LLDB mainline
NativeRegisterContextDBReg_arm64.cpp
Go to the documentation of this file.
1//===-- NativeRegisterContextDBReg_arm64.cpp ------------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
10
12#include "lldb/Utility/Log.h"
14
15using namespace lldb_private;
16
17// E (bit 0), used to enable breakpoint/watchpoint
18constexpr uint32_t g_enable_bit = 1;
19// PAC (bits 2:1): 0b10
20constexpr uint32_t g_pac_bits = (2 << 1);
21
22// Returns appropriate control register bits for the specified size
23static constexpr inline uint64_t GetSizeBits(int size) {
24 // BAS (bits 12:5) hold a bit-mask of addresses to watch
25 // e.g. 0b00000001 means 1 byte at address
26 // 0b00000011 means 2 bytes (addr..addr+1)
27 // ...
28 // 0b11111111 means 8 bytes (addr..addr+7)
29 return ((1 << size) - 1) << 5;
30}
31
34 llvm::Error error = ReadHardwareDebugInfo();
35 if (error) {
36 LLDB_LOG_ERROR(log, std::move(error),
37 "failed to read debug registers: {0}");
38 return 0;
39 }
40
42}
43
46 size_t size) {
48 LLDB_LOG(log, "addr: {0:x}, size: {1:x}", addr, size);
49
50 // Read hardware breakpoint and watchpoint information.
51 llvm::Error error = ReadHardwareDebugInfo();
52 if (error) {
54 log, std::move(error),
55 "unable to set breakpoint: failed to read debug registers: {0}");
57 }
58
59 uint32_t control_value = 0, bp_index = 0;
60
61 // Check if size has a valid hardware breakpoint length.
62 if (size != 4)
63 return LLDB_INVALID_INDEX32; // Invalid size for a AArch64 hardware
64 // breakpoint
65
66 // Check 4-byte alignment for hardware breakpoint target address.
67 if (addr & 0x03)
68 return LLDB_INVALID_INDEX32; // Invalid address, should be 4-byte aligned.
69
70 // Setup control value
71 control_value = g_enable_bit | g_pac_bits | GetSizeBits(size);
72
73 // Iterate over stored breakpoints and find a free bp_index
74 bp_index = LLDB_INVALID_INDEX32;
75 for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
76 if (!BreakpointIsEnabled(i))
77 bp_index = i; // Mark last free slot
78 else if (m_hbp_regs[i].address == addr)
79 return LLDB_INVALID_INDEX32; // We do not support duplicate breakpoints.
80 }
81
82 if (bp_index == LLDB_INVALID_INDEX32)
84
85 // Update breakpoint in local cache
86 m_hbp_regs[bp_index].real_addr = addr;
87 m_hbp_regs[bp_index].address = addr;
88 m_hbp_regs[bp_index].control = control_value;
89
90 // PTRACE call to set corresponding hardware breakpoint register.
92
93 if (error) {
94 m_hbp_regs[bp_index].address = 0;
95 m_hbp_regs[bp_index].control &= ~1;
96
98 log, std::move(error),
99 "unable to set breakpoint: failed to write debug registers: {0}");
101 }
102
103 return bp_index;
104}
105
107 uint32_t hw_idx) {
109 LLDB_LOG(log, "hw_idx: {0}", hw_idx);
110
111 // Read hardware breakpoint and watchpoint information.
112 llvm::Error error = ReadHardwareDebugInfo();
113 if (error) {
115 log, std::move(error),
116 "unable to clear breakpoint: failed to read debug registers: {0}");
117 return false;
118 }
119
120 if (hw_idx >= m_max_hbp_supported)
121 return false;
122
123 // Create a backup we can revert to in case of failure.
124 lldb::addr_t tempAddr = m_hbp_regs[hw_idx].address;
125 uint32_t tempControl = m_hbp_regs[hw_idx].control;
126
127 m_hbp_regs[hw_idx].control &= ~g_enable_bit;
128 m_hbp_regs[hw_idx].address = 0;
129
130 // PTRACE call to clear corresponding hardware breakpoint register.
132
133 if (error) {
134 m_hbp_regs[hw_idx].control = tempControl;
135 m_hbp_regs[hw_idx].address = tempAddr;
136
138 log, std::move(error),
139 "unable to clear breakpoint: failed to write debug registers: {0}");
140 return false;
141 }
142
143 return true;
144}
145
147 uint32_t &bp_index, lldb::addr_t trap_addr) {
149
150 LLDB_LOGF(log, "NativeRegisterContextDBReg_arm64::%s()", __FUNCTION__);
151
152 lldb::addr_t break_addr;
153
154 for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) {
155 break_addr = m_hbp_regs[bp_index].address;
156
157 if (BreakpointIsEnabled(bp_index) && trap_addr == break_addr) {
158 m_hbp_regs[bp_index].hit_addr = trap_addr;
159 return Status();
160 }
161 }
162
163 bp_index = LLDB_INVALID_INDEX32;
164 return Status();
165}
166
169
170 LLDB_LOGF(log, "NativeRegisterContextDBReg_arm64::%s()", __FUNCTION__);
171
172 // Read hardware breakpoint and watchpoint information.
173 llvm::Error error = ReadHardwareDebugInfo();
174 if (error)
175 return Status(std::move(error));
176
177 for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
178 if (BreakpointIsEnabled(i)) {
179 // Create a backup we can revert to in case of failure.
180 lldb::addr_t tempAddr = m_hbp_regs[i].address;
181 uint32_t tempControl = m_hbp_regs[i].control;
182
183 // Clear watchpoints in local cache
184 m_hbp_regs[i].control &= ~g_enable_bit;
185 m_hbp_regs[i].address = 0;
186
187 // Ptrace call to update hardware debug registers
189
190 if (error) {
191 m_hbp_regs[i].control = tempControl;
192 m_hbp_regs[i].address = tempAddr;
193
194 return Status(std::move(error));
195 }
196 }
197 }
198
199 return Status();
200}
201
203 if ((m_hbp_regs[bp_index].control & g_enable_bit) != 0)
204 return true;
205 else
206 return false;
207}
208
211 llvm::Error error = ReadHardwareDebugInfo();
212 if (error) {
213 LLDB_LOG_ERROR(log, std::move(error),
214 "failed to read debug registers: {0}");
215 return 0;
216 }
217
218 return m_max_hwp_supported;
219}
220
222 lldb::addr_t addr, size_t size, uint32_t watch_flags) {
224 LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size,
225 watch_flags);
226
227 // Read hardware breakpoint and watchpoint information.
228 llvm::Error error = ReadHardwareDebugInfo();
229 if (error) {
231 log, std::move(error),
232 "unable to set watchpoint: failed to read debug registers: {0}");
234 }
235
236 uint32_t control_value = 0, wp_index = 0;
237 lldb::addr_t real_addr = addr;
238
239 // Check if we are setting watchpoint other than read/write/access Also
240 // update watchpoint flag to match AArch64 write-read bit configuration.
241 switch (watch_flags) {
242 case 1:
243 watch_flags = 2;
244 break;
245 case 2:
246 watch_flags = 1;
247 break;
248 case 3:
249 break;
250 default:
252 }
253
254 // Check if size has a valid hardware watchpoint length.
255 if (size != 1 && size != 2 && size != 4 && size != 8)
257
258 // Check 8-byte alignment for hardware watchpoint target address. Below is a
259 // hack to recalculate address and size in order to make sure we can watch
260 // non 8-byte aligned addresses as well.
261 if (addr & 0x07) {
262 uint8_t watch_mask = (addr & 0x07) + size;
263
264 if (watch_mask > 0x08)
266 else if (watch_mask <= 0x02)
267 size = 2;
268 else if (watch_mask <= 0x04)
269 size = 4;
270 else
271 size = 8;
272
273 addr = addr & (~0x07);
274 }
275
276 // Setup control value
277 control_value = g_enable_bit | g_pac_bits | GetSizeBits(size);
278 control_value |= watch_flags << 3;
279
280 // Iterate over stored watchpoints and find a free wp_index
281 wp_index = LLDB_INVALID_INDEX32;
282 for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
283 if (!WatchpointIsEnabled(i))
284 wp_index = i; // Mark last free slot
285 else if (m_hwp_regs[i].address == addr) {
286 return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints.
287 }
288 }
289
290 if (wp_index == LLDB_INVALID_INDEX32)
292
293 // Update watchpoint in local cache
294 m_hwp_regs[wp_index].real_addr = real_addr;
295 m_hwp_regs[wp_index].address = addr;
296 m_hwp_regs[wp_index].control = control_value;
297
298 // PTRACE call to set corresponding watchpoint register.
300
301 if (error) {
302 m_hwp_regs[wp_index].address = 0;
303 m_hwp_regs[wp_index].control &= ~g_enable_bit;
304
306 log, std::move(error),
307 "unable to set watchpoint: failed to write debug registers: {0}");
309 }
310
311 return wp_index;
312}
313
315 uint32_t wp_index) {
317 LLDB_LOG(log, "wp_index: {0}", wp_index);
318
319 // Read hardware breakpoint and watchpoint information.
320 llvm::Error error = ReadHardwareDebugInfo();
321 if (error) {
323 log, std::move(error),
324 "unable to clear watchpoint: failed to read debug registers: {0}");
325 return false;
326 }
327
328 if (wp_index >= m_max_hwp_supported)
329 return false;
330
331 // Create a backup we can revert to in case of failure.
332 lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
333 uint32_t tempControl = m_hwp_regs[wp_index].control;
334
335 // Update watchpoint in local cache
336 m_hwp_regs[wp_index].control &= ~g_enable_bit;
337 m_hwp_regs[wp_index].address = 0;
338
339 // Ptrace call to update hardware debug registers
341
342 if (error) {
343 m_hwp_regs[wp_index].control = tempControl;
344 m_hwp_regs[wp_index].address = tempAddr;
345
347 log, std::move(error),
348 "unable to clear watchpoint: failed to write debug registers: {0}");
349 return false;
350 }
351
352 return true;
353}
354
356 // Read hardware breakpoint and watchpoint information.
357 llvm::Error error = ReadHardwareDebugInfo();
358 if (error)
359 return Status(std::move(error));
360
361 for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
362 if (WatchpointIsEnabled(i)) {
363 // Create a backup we can revert to in case of failure.
364 lldb::addr_t tempAddr = m_hwp_regs[i].address;
365 uint32_t tempControl = m_hwp_regs[i].control;
366
367 // Clear watchpoints in local cache
368 m_hwp_regs[i].control &= ~g_enable_bit;
369 m_hwp_regs[i].address = 0;
370
371 // Ptrace call to update hardware debug registers
373
374 if (error) {
375 m_hwp_regs[i].control = tempControl;
376 m_hwp_regs[i].address = tempAddr;
377
378 return Status(std::move(error));
379 }
380 }
381 }
382
383 return Status();
384}
385
389 LLDB_LOG(log, "wp_index: {0}", wp_index);
390
391 switch ((m_hwp_regs[wp_index].control >> 5) & 0xff) {
392 case 0x01:
393 return 1;
394 case 0x03:
395 return 2;
396 case 0x0f:
397 return 4;
398 case 0xff:
399 return 8;
400 default:
401 return 0;
402 }
403}
404
407 LLDB_LOG(log, "wp_index: {0}", wp_index);
408
409 if ((m_hwp_regs[wp_index].control & g_enable_bit) != 0)
410 return true;
411 else
412 return false;
413}
414
416 uint32_t &wp_index, lldb::addr_t trap_addr) {
418 LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr);
419
420 // Read hardware breakpoint and watchpoint information.
421 llvm::Error error = ReadHardwareDebugInfo();
422 if (error)
423 return Status(std::move(error));
424
425 // Mask off ignored bits from watchpoint trap address.
426 trap_addr = FixWatchpointHitAddress(trap_addr);
427
428 uint32_t watch_size;
429 lldb::addr_t watch_addr;
430
431 for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {
432 watch_size = GetWatchpointSize(wp_index);
433 watch_addr = m_hwp_regs[wp_index].address;
434
435 if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr &&
436 trap_addr < watch_addr + watch_size) {
437 m_hwp_regs[wp_index].hit_addr = trap_addr;
438 return Status();
439 }
440 }
441
442 wp_index = LLDB_INVALID_INDEX32;
443 return Status();
444}
445
449 LLDB_LOG(log, "wp_index: {0}", wp_index);
450
451 if (wp_index >= m_max_hwp_supported)
453
454 if (WatchpointIsEnabled(wp_index))
455 return m_hwp_regs[wp_index].real_addr;
457}
458
462 LLDB_LOG(log, "wp_index: {0}", wp_index);
463
464 if (wp_index >= m_max_hwp_supported)
466
467 if (WatchpointIsEnabled(wp_index))
468 return m_hwp_regs[wp_index].hit_addr;
470}
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition: Log.h:337
#define LLDB_LOGF(log,...)
Definition: Log.h:344
#define LLDB_LOG_ERROR(log, error,...)
Definition: Log.h:360
constexpr uint32_t g_pac_bits
static constexpr uint64_t GetSizeBits(int size)
constexpr uint32_t g_enable_bit
Status GetHardwareBreakHitIndex(uint32_t &bp_index, lldb::addr_t trap_addr) override
lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override
Status GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) override
uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags) override
virtual llvm::Error WriteHardwareDebugRegs(DREGType hwbType)=0
virtual lldb::addr_t FixWatchpointHitAddress(lldb::addr_t hit_addr)
uint32_t SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override
lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override
An error handling class.
Definition: Status.h:44
#define LLDB_INVALID_INDEX32
Definition: lldb-defines.h:75
#define LLDB_INVALID_ADDRESS
Definition: lldb-defines.h:74
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition: Log.h:309
uint64_t addr_t
Definition: lldb-types.h:83