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/LLDBLog.h"
12 #include "lldb/Utility/Log.h"
14 
15 using namespace lldb_private;
16 
17 // E (bit 0), used to enable breakpoint/watchpoint
18 constexpr uint32_t g_enable_bit = 1;
19 // PAC (bits 2:1): 0b10
20 constexpr uint32_t g_pac_bits = (2 << 1);
21 
22 // Returns appropriate control register bits for the specified size
23 static 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 
35  if (error) {
36  LLDB_LOG_ERROR(log, std::move(error),
37  "failed to read debug registers: {0}");
38  return 0;
39  }
40 
41  return m_max_hbp_supported;
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.
52  if (error) {
54  log, std::move(error),
55  "unable to set breakpoint: failed to read debug registers: {0}");
56  return LLDB_INVALID_INDEX32;
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)
83  return 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}");
100  return LLDB_INVALID_INDEX32;
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.
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.
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 
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.
229  if (error) {
231  log, std::move(error),
232  "unable to set watchpoint: failed to read debug registers: {0}");
233  return LLDB_INVALID_INDEX32;
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:
251  return LLDB_INVALID_INDEX32;
252  }
253 
254  // Check if size has a valid hardware watchpoint length.
255  if (size != 1 && size != 2 && size != 4 && size != 8)
256  return LLDB_INVALID_INDEX32;
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)
265  return LLDB_INVALID_INDEX32;
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)
291  return 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}");
308  return LLDB_INVALID_INDEX32;
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.
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.
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 
386 uint32_t
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.
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)
452  return LLDB_INVALID_ADDRESS;
453 
454  if (WatchpointIsEnabled(wp_index))
455  return m_hwp_regs[wp_index].real_addr;
456  return LLDB_INVALID_ADDRESS;
457 }
458 
462  LLDB_LOG(log, "wp_index: {0}", wp_index);
463 
464  if (wp_index >= m_max_hwp_supported)
465  return LLDB_INVALID_ADDRESS;
466 
467  if (WatchpointIsEnabled(wp_index))
468  return m_hwp_regs[wp_index].hit_addr;
469  return LLDB_INVALID_ADDRESS;
470 }
lldb_private::NativeRegisterContextDBReg_arm64::BreakpointIsEnabled
bool BreakpointIsEnabled(uint32_t bp_index)
Definition: NativeRegisterContextDBReg_arm64.cpp:202
LLDB_LOGF
#define LLDB_LOGF(log,...)
Definition: Log.h:343
lldb_private::NativeRegisterContextDBReg_arm64::m_hwp_regs
std::array< struct DREG, 16 > m_hwp_regs
Definition: NativeRegisterContextDBReg_arm64.h:68
lldb_private::NativeRegisterContextDBReg_arm64::NumSupportedHardwareWatchpoints
uint32_t NumSupportedHardwareWatchpoints() override
Definition: NativeRegisterContextDBReg_arm64.cpp:209
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:405
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:221
g_enable_bit
constexpr uint32_t g_enable_bit
Definition: NativeRegisterContextDBReg_arm64.cpp:18
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:415
lldb_private::NativeRegisterContextDBReg_arm64::ClearAllHardwareBreakpoints
Status ClearAllHardwareBreakpoints() override
Definition: NativeRegisterContextDBReg_arm64.cpp:167
Log.h
lldb_private::NativeRegisterContextDBReg_arm64::GetHardwareBreakHitIndex
Status GetHardwareBreakHitIndex(uint32_t &bp_index, lldb::addr_t trap_addr) override
Definition: NativeRegisterContextDBReg_arm64.cpp:146
lldb_private::NativeRegisterContextDBReg_arm64::ClearAllHardwareWatchpoints
Status ClearAllHardwareWatchpoints() override
Definition: NativeRegisterContextDBReg_arm64.cpp:355
lldb_private::LLDBLog::Watchpoints
@ Watchpoints
lldb_private::NativeRegisterContextDBReg_arm64::GetWatchpointHitAddress
lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override
Definition: NativeRegisterContextDBReg_arm64.cpp:460
lldb_private::NativeRegisterContextDBReg_arm64::eDREGTypeWATCH
@ eDREGTypeWATCH
Definition: NativeRegisterContextDBReg_arm64.h:55
lldb_private::LLDBLog::Breakpoints
@ Breakpoints
lldb_private::NativeRegisterContextDBReg_arm64::ClearHardwareBreakpoint
bool ClearHardwareBreakpoint(uint32_t hw_idx) override
Definition: NativeRegisterContextDBReg_arm64.cpp:106
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:447
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
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:387
GetSizeBits
static constexpr uint64_t GetSizeBits(int size)
Definition: NativeRegisterContextDBReg_arm64.cpp:23
LLDB_INVALID_ADDRESS
#define LLDB_INVALID_ADDRESS
Definition: lldb-defines.h:74
LLDB_LOG
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition: Log.h:336
g_pac_bits
constexpr uint32_t g_pac_bits
Definition: NativeRegisterContextDBReg_arm64.cpp:20
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
Error
llvm::Error Error
Definition: UdtRecordCompleter.cpp:30
LLDB_INVALID_INDEX32
#define LLDB_INVALID_INDEX32
Definition: lldb-defines.h:75
lldb_private::NativeRegisterContextDBReg_arm64::ClearHardwareWatchpoint
bool ClearHardwareWatchpoint(uint32_t hw_index) override
Definition: NativeRegisterContextDBReg_arm64.cpp:314
lldb_private::Log
Definition: Log.h:115
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:32
lldb_private::GetLog
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition: Log.h:308
LLDB_LOG_ERROR
#define LLDB_LOG_ERROR(log, error,...)
Definition: Log.h:359
lldb_private::NativeRegisterContextDBReg_arm64::SetHardwareBreakpoint
uint32_t SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override
Definition: NativeRegisterContextDBReg_arm64.cpp:45
LLDBLog.h