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