1 //===-- NativeRegisterContextDBReg.cpp ------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "NativeRegisterContextDBReg.h"
11 #include "lldb/Utility/LLDBLog.h"
12 #include "lldb/Utility/Log.h"
13 #include "lldb/Utility/RegisterValue.h"
15 using namespace lldb_private
;
17 uint32_t NativeRegisterContextDBReg::NumSupportedHardwareBreakpoints() {
18 Log
*log
= GetLog(LLDBLog::Breakpoints
);
20 // Read hardware breakpoint and watchpoint information.
21 llvm::Error error
= ReadHardwareDebugInfo();
24 LLDB_LOG_ERROR(log
, std::move(error
),
25 "failed to read debug registers: {0}");
29 LLDB_LOG(log
, "{0}", m_max_hbp_supported
);
30 return m_max_hbp_supported
;
33 uint32_t NativeRegisterContextDBReg::SetHardwareBreakpoint(lldb::addr_t addr
,
35 Log
*log
= GetLog(LLDBLog::Breakpoints
);
36 LLDB_LOG(log
, "addr: {0:x}, size: {1:x}", addr
, size
);
38 // Read hardware breakpoint and watchpoint information.
39 llvm::Error error
= ReadHardwareDebugInfo();
42 log
, std::move(error
),
43 "unable to set breakpoint: failed to read debug registers: {0}");
44 return LLDB_INVALID_INDEX32
;
47 uint32_t control_value
= 0, bp_index
= 0;
49 if (!ValidateBreakpoint(size
, addr
))
50 return LLDB_INVALID_INDEX32
;
52 control_value
= MakeBreakControlValue(size
);
54 // Iterate over stored breakpoints and find a free bp_index
55 bp_index
= LLDB_INVALID_INDEX32
;
56 for (uint32_t i
= 0; i
< m_max_hbp_supported
; i
++) {
57 if (!BreakpointIsEnabled(i
))
58 bp_index
= i
; // Mark last free slot
59 else if (m_hbp_regs
[i
].address
== addr
)
60 return LLDB_INVALID_INDEX32
; // We do not support duplicate breakpoints.
63 if (bp_index
== LLDB_INVALID_INDEX32
)
64 return LLDB_INVALID_INDEX32
;
66 // Update breakpoint in local cache
67 m_hbp_regs
[bp_index
].real_addr
= addr
;
68 m_hbp_regs
[bp_index
].address
= addr
;
69 m_hbp_regs
[bp_index
].control
= control_value
;
71 // PTRACE call to set corresponding hardware breakpoint register.
72 error
= WriteHardwareDebugRegs(eDREGTypeBREAK
);
75 m_hbp_regs
[bp_index
].address
= 0;
76 m_hbp_regs
[bp_index
].control
&= ~m_hw_dbg_enable_bit
;
79 log
, std::move(error
),
80 "unable to set breakpoint: failed to write debug registers: {0}");
81 return LLDB_INVALID_INDEX32
;
87 bool NativeRegisterContextDBReg::ClearHardwareBreakpoint(uint32_t hw_idx
) {
88 Log
*log
= GetLog(LLDBLog::Breakpoints
);
89 LLDB_LOG(log
, "hw_idx: {0}", hw_idx
);
91 // Read hardware breakpoint and watchpoint information.
92 llvm::Error error
= ReadHardwareDebugInfo();
95 log
, std::move(error
),
96 "unable to clear breakpoint: failed to read debug registers: {0}");
100 if (hw_idx
>= m_max_hbp_supported
)
103 // Create a backup we can revert to in case of failure.
104 lldb::addr_t tempAddr
= m_hbp_regs
[hw_idx
].address
;
105 uint32_t tempControl
= m_hbp_regs
[hw_idx
].control
;
107 m_hbp_regs
[hw_idx
].control
&= ~m_hw_dbg_enable_bit
;
108 m_hbp_regs
[hw_idx
].address
= 0;
110 // PTRACE call to clear corresponding hardware breakpoint register.
111 error
= WriteHardwareDebugRegs(eDREGTypeBREAK
);
114 m_hbp_regs
[hw_idx
].control
= tempControl
;
115 m_hbp_regs
[hw_idx
].address
= tempAddr
;
118 log
, std::move(error
),
119 "unable to clear breakpoint: failed to write debug registers: {0}");
127 NativeRegisterContextDBReg::GetHardwareBreakHitIndex(uint32_t &bp_index
,
128 lldb::addr_t trap_addr
) {
129 Log
*log
= GetLog(LLDBLog::Breakpoints
);
131 LLDB_LOGF(log
, "NativeRegisterContextDBReg::%s()", __FUNCTION__
);
133 lldb::addr_t break_addr
;
135 for (bp_index
= 0; bp_index
< m_max_hbp_supported
; ++bp_index
) {
136 break_addr
= m_hbp_regs
[bp_index
].address
;
138 if (BreakpointIsEnabled(bp_index
) && trap_addr
== break_addr
) {
139 m_hbp_regs
[bp_index
].hit_addr
= trap_addr
;
144 bp_index
= LLDB_INVALID_INDEX32
;
148 Status
NativeRegisterContextDBReg::ClearAllHardwareBreakpoints() {
149 Log
*log
= GetLog(LLDBLog::Breakpoints
);
151 LLDB_LOGF(log
, "NativeRegisterContextDBReg::%s()", __FUNCTION__
);
153 // Read hardware breakpoint and watchpoint information.
154 llvm::Error error
= ReadHardwareDebugInfo();
156 return Status::FromError(std::move(error
));
158 for (uint32_t i
= 0; i
< m_max_hbp_supported
; i
++) {
159 if (!BreakpointIsEnabled(i
))
161 // Create a backup we can revert to in case of failure.
162 lldb::addr_t tempAddr
= m_hbp_regs
[i
].address
;
163 uint32_t tempControl
= m_hbp_regs
[i
].control
;
165 // Clear watchpoints in local cache
166 m_hbp_regs
[i
].control
&= ~m_hw_dbg_enable_bit
;
167 m_hbp_regs
[i
].address
= 0;
169 // Ptrace call to update hardware debug registers
170 error
= WriteHardwareDebugRegs(eDREGTypeBREAK
);
173 m_hbp_regs
[i
].control
= tempControl
;
174 m_hbp_regs
[i
].address
= tempAddr
;
176 return Status::FromError(std::move(error
));
183 bool NativeRegisterContextDBReg::BreakpointIsEnabled(uint32_t bp_index
) {
184 return ((m_hbp_regs
[bp_index
].control
& m_hw_dbg_enable_bit
) != 0);
187 uint32_t NativeRegisterContextDBReg::NumSupportedHardwareWatchpoints() {
188 Log
*log
= GetLog(LLDBLog::Watchpoints
);
189 llvm::Error error
= ReadHardwareDebugInfo();
191 LLDB_LOG_ERROR(log
, std::move(error
),
192 "failed to read debug registers: {0}");
196 return m_max_hwp_supported
;
199 uint32_t NativeRegisterContextDBReg::SetHardwareWatchpoint(
200 lldb::addr_t addr
, size_t size
, uint32_t watch_flags
) {
201 Log
*log
= GetLog(LLDBLog::Watchpoints
);
202 LLDB_LOG(log
, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr
, size
,
205 // Read hardware breakpoint and watchpoint information.
206 llvm::Error error
= ReadHardwareDebugInfo();
209 log
, std::move(error
),
210 "unable to set watchpoint: failed to read debug registers: {0}");
211 return LLDB_INVALID_INDEX32
;
214 uint32_t control_value
= 0, wp_index
= 0;
215 lldb::addr_t real_addr
= addr
;
216 WatchpointDetails details
{size
, addr
};
218 auto adjusted
= AdjustWatchpoint(details
);
219 if (adjusted
== std::nullopt
)
220 return LLDB_INVALID_INDEX32
;
221 size
= adjusted
->size
;
222 addr
= adjusted
->addr
;
224 // Check if we are setting watchpoint other than read/write/access Also
225 // update watchpoint flag to match AArch64/LoongArch write-read bit
227 switch (watch_flags
) {
228 case lldb::eWatchpointKindWrite
:
231 case lldb::eWatchpointKindRead
:
234 case (lldb::eWatchpointKindRead
| lldb::eWatchpointKindWrite
):
237 return LLDB_INVALID_INDEX32
;
240 control_value
= MakeWatchControlValue(size
, watch_flags
);
242 // Iterate over stored watchpoints and find a free wp_index
243 wp_index
= LLDB_INVALID_INDEX32
;
244 for (uint32_t i
= 0; i
< m_max_hwp_supported
; i
++) {
245 if (!WatchpointIsEnabled(i
))
246 wp_index
= i
; // Mark last free slot
247 else if (m_hwp_regs
[i
].address
== addr
) {
248 return LLDB_INVALID_INDEX32
; // We do not support duplicate watchpoints.
252 if (wp_index
== LLDB_INVALID_INDEX32
)
253 return LLDB_INVALID_INDEX32
;
255 // Update watchpoint in local cache
256 m_hwp_regs
[wp_index
].real_addr
= real_addr
;
257 m_hwp_regs
[wp_index
].address
= addr
;
258 m_hwp_regs
[wp_index
].control
= control_value
;
260 // PTRACE call to set corresponding watchpoint register.
261 error
= WriteHardwareDebugRegs(eDREGTypeWATCH
);
264 m_hwp_regs
[wp_index
].address
= 0;
265 m_hwp_regs
[wp_index
].control
&= ~m_hw_dbg_enable_bit
;
268 log
, std::move(error
),
269 "unable to set watchpoint: failed to write debug registers: {0}");
270 return LLDB_INVALID_INDEX32
;
276 bool NativeRegisterContextDBReg::ClearHardwareWatchpoint(uint32_t wp_index
) {
277 Log
*log
= GetLog(LLDBLog::Watchpoints
);
278 LLDB_LOG(log
, "wp_index: {0}", wp_index
);
280 // Read hardware breakpoint and watchpoint information.
281 llvm::Error error
= ReadHardwareDebugInfo();
284 log
, std::move(error
),
285 "unable to set watchpoint: failed to read debug registers: {0}");
286 return LLDB_INVALID_INDEX32
;
289 if (wp_index
>= m_max_hwp_supported
)
292 // Create a backup we can revert to in case of failure.
293 lldb::addr_t tempAddr
= m_hwp_regs
[wp_index
].address
;
294 uint32_t tempControl
= m_hwp_regs
[wp_index
].control
;
296 // Update watchpoint in local cache
297 m_hwp_regs
[wp_index
].control
&= ~m_hw_dbg_enable_bit
;
298 m_hwp_regs
[wp_index
].address
= 0;
300 // Ptrace call to update hardware debug registers
301 error
= WriteHardwareDebugRegs(eDREGTypeWATCH
);
304 m_hwp_regs
[wp_index
].control
= tempControl
;
305 m_hwp_regs
[wp_index
].address
= tempAddr
;
308 log
, std::move(error
),
309 "unable to clear watchpoint: failed to read debug registers: {0}");
316 Status
NativeRegisterContextDBReg::ClearAllHardwareWatchpoints() {
317 // Read hardware breakpoint and watchpoint information.
318 llvm::Error error
= ReadHardwareDebugInfo();
320 return Status::FromError(std::move(error
));
322 for (uint32_t i
= 0; i
< m_max_hwp_supported
; i
++) {
323 if (!WatchpointIsEnabled(i
))
325 // Create a backup we can revert to in case of failure.
326 lldb::addr_t tempAddr
= m_hwp_regs
[i
].address
;
327 uint32_t tempControl
= m_hwp_regs
[i
].control
;
329 // Clear watchpoints in local cache
330 m_hwp_regs
[i
].control
= 0;
331 m_hwp_regs
[i
].address
= 0;
333 // Ptrace call to update hardware debug registers
334 error
= WriteHardwareDebugRegs(eDREGTypeWATCH
);
337 m_hwp_regs
[i
].control
= tempControl
;
338 m_hwp_regs
[i
].address
= tempAddr
;
340 return Status::FromError(std::move(error
));
348 NativeRegisterContextDBReg::GetWatchpointHitIndex(uint32_t &wp_index
,
349 lldb::addr_t trap_addr
) {
350 Log
*log
= GetLog(LLDBLog::Watchpoints
);
351 LLDB_LOG(log
, "wp_index: {0}, trap_addr: {1:x}", wp_index
, trap_addr
);
353 // Read hardware breakpoint and watchpoint information.
354 llvm::Error error
= ReadHardwareDebugInfo();
356 return Status::FromError(std::move(error
));
358 // AArch64 need mask off ignored bits from watchpoint trap address.
359 trap_addr
= FixWatchpointHitAddress(trap_addr
);
362 lldb::addr_t watch_addr
;
364 for (wp_index
= 0; wp_index
< m_max_hwp_supported
; ++wp_index
) {
365 watch_size
= GetWatchpointSize(wp_index
);
366 watch_addr
= m_hwp_regs
[wp_index
].address
;
368 if (WatchpointIsEnabled(wp_index
) && trap_addr
>= watch_addr
&&
369 trap_addr
< watch_addr
+ watch_size
) {
370 m_hwp_regs
[wp_index
].hit_addr
= trap_addr
;
375 wp_index
= LLDB_INVALID_INDEX32
;
379 bool NativeRegisterContextDBReg::WatchpointIsEnabled(uint32_t wp_index
) {
380 Log
*log
= GetLog(LLDBLog::Watchpoints
);
381 LLDB_LOG(log
, "wp_index: {0}", wp_index
);
382 return ((m_hwp_regs
[wp_index
].control
& m_hw_dbg_enable_bit
) != 0);
386 NativeRegisterContextDBReg::GetWatchpointAddress(uint32_t wp_index
) {
387 Log
*log
= GetLog(LLDBLog::Watchpoints
);
388 LLDB_LOG(log
, "wp_index: {0}", wp_index
);
390 if (wp_index
>= m_max_hwp_supported
)
391 return LLDB_INVALID_ADDRESS
;
393 if (WatchpointIsEnabled(wp_index
))
394 return m_hwp_regs
[wp_index
].real_addr
;
395 return LLDB_INVALID_ADDRESS
;
399 NativeRegisterContextDBReg::GetWatchpointHitAddress(uint32_t wp_index
) {
400 Log
*log
= GetLog(LLDBLog::Watchpoints
);
401 LLDB_LOG(log
, "wp_index: {0}", wp_index
);
403 if (wp_index
>= m_max_hwp_supported
)
404 return LLDB_INVALID_ADDRESS
;
406 if (WatchpointIsEnabled(wp_index
))
407 return m_hwp_regs
[wp_index
].hit_addr
;
408 return LLDB_INVALID_ADDRESS
;