LLDB  mainline
NativeRegisterContextDBReg_x86.cpp
Go to the documentation of this file.
1 //===-- NativeRegisterContextDBReg_x86.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 
15 
16 using namespace lldb_private;
17 
18 // Returns mask/value for status bit of wp_index in DR6
19 static inline uint64_t GetStatusBit(uint32_t wp_index) {
20  // DR6: ...BBBB
21  // 3210 <- status bits for bp./wp. i; 1 if hit
22  return 1 << wp_index;
23 }
24 
25 // Returns mask/value for global enable bit of wp_index in DR7
26 static inline uint64_t GetEnableBit(uint32_t wp_index) {
27  // DR7: ...GLGLGLGL
28  // 33221100 <- global/local enable for bp./wp.; 1 if enabled
29  // we use global bits because NetBSD kernel does not preserve local
30  // bits reliably; Linux seems fine with either
31  return 1 << (2 * wp_index + 1);
32 }
33 
34 // Returns mask for both enable bits of wp_index in DR7
35 static inline uint64_t GetBothEnableBitMask(uint32_t wp_index) {
36  // DR7: ...GLGLGLGL
37  // 33221100 <- global/local enable for bp./wp.; 1 if enabled
38  return 3 << (2 * wp_index + 1);
39 }
40 
41 // Returns value for type bits of wp_index in DR7
42 static inline uint64_t GetWatchTypeBits(uint32_t watch_flags,
43  uint32_t wp_index) {
44  // DR7:
45  // bit: 3322222222221111...
46  // 1098765432109876...
47  // val: SSTTSSTTSSTTSSTT...
48  // wp.: 3333222211110000...
49  //
50  // where T - type is 01 for write, 11 for r/w
51  return watch_flags << (16 + 4 * wp_index);
52 }
53 
54 // Returns value for size bits of wp_index in DR7
55 static inline uint64_t GetWatchSizeBits(uint32_t size, uint32_t wp_index) {
56  // DR7:
57  // bit: 3322222222221111...
58  // 1098765432109876...
59  // val: SSTTSSTTSSTTSSTT...
60  // wp.: 3333222211110000...
61  //
62  // where S - size is:
63  // 00 for 1 byte
64  // 01 for 2 bytes
65  // 10 for 8 bytes
66  // 11 for 4 bytes
67  return (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index);
68 }
69 
70 // Returns bitmask for all bits controlling wp_index in DR7
71 static inline uint64_t GetWatchControlBitmask(uint32_t wp_index) {
72  // DR7:
73  // bit: 33222222222211111111110000000000
74  // 10987654321098765432109876543210
75  // val: SSTTSSTTSSTTSSTTxxxxxxGLGLGLGLGL
76  // wp.: 3333222211110000xxxxxxEE33221100
77  return GetBothEnableBitMask(wp_index) | (0xF << (16 + 4 * wp_index));
78 }
79 
80 // Bit mask for control bits regarding all watchpoints.
81 static constexpr uint64_t watchpoint_all_control_bit_mask = 0xFFFF00FF;
82 
83 const RegisterInfo *NativeRegisterContextDBReg_x86::GetDR(int num) const {
84  assert(num >= 0 && num <= 7);
85  switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
86  case llvm::Triple::x86:
88  case llvm::Triple::x86_64:
90  default:
91  llvm_unreachable("Unhandled target architecture.");
92  }
93 }
94 
96  bool &is_hit) {
97  if (wp_index >= NumSupportedHardwareWatchpoints())
98  return Status("Watchpoint index out of range");
99 
100  RegisterValue dr6;
101  Status error = ReadRegister(GetDR(6), dr6);
102  if (error.Fail())
103  is_hit = false;
104  else
105  is_hit = dr6.GetAsUInt64() & GetStatusBit(wp_index);
106 
107  return error;
108 }
109 
110 Status
112  lldb::addr_t trap_addr) {
114  for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) {
115  bool is_hit;
116  Status error = IsWatchpointHit(wp_index, is_hit);
117  if (error.Fail()) {
118  wp_index = LLDB_INVALID_INDEX32;
119  return error;
120  } else if (is_hit) {
121  return error;
122  }
123  }
124  wp_index = LLDB_INVALID_INDEX32;
125  return Status();
126 }
127 
129  bool &is_vacant) {
130  if (wp_index >= NumSupportedHardwareWatchpoints())
131  return Status("Watchpoint index out of range");
132 
133  RegisterValue dr7;
134  Status error = ReadRegister(GetDR(7), dr7);
135  if (error.Fail())
136  is_vacant = false;
137  else
138  is_vacant = !(dr7.GetAsUInt64() & GetEnableBit(wp_index));
139 
140  return error;
141 }
142 
144  lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) {
145 
146  if (wp_index >= NumSupportedHardwareWatchpoints())
147  return Status("Watchpoint index out of range");
148 
149  // Read only watchpoints aren't supported on x86_64. Fall back to read/write
150  // waitchpoints instead.
151  // TODO: Add logic to detect when a write happens and ignore that watchpoint
152  // hit.
153  if (watch_flags == 2)
154  watch_flags = 3;
155 
156  if (watch_flags != 1 && watch_flags != 3)
157  return Status("Invalid read/write bits for watchpoint");
158  if (size != 1 && size != 2 && size != 4 && size != 8)
159  return Status("Invalid size for watchpoint");
160 
161  bool is_vacant;
162  Status error = IsWatchpointVacant(wp_index, is_vacant);
163  if (error.Fail())
164  return error;
165  if (!is_vacant)
166  return Status("Watchpoint index not vacant");
167 
168  RegisterValue dr7, drN;
169  error = ReadRegister(GetDR(7), dr7);
170  if (error.Fail())
171  return error;
172  error = ReadRegister(GetDR(wp_index), drN);
173  if (error.Fail())
174  return error;
175 
176  uint64_t control_bits = dr7.GetAsUInt64() & ~GetWatchControlBitmask(wp_index);
177  control_bits |= GetEnableBit(wp_index) |
178  GetWatchTypeBits(watch_flags, wp_index) |
179  GetWatchSizeBits(size, wp_index);
180 
181  // Clear dr6 if address or bits changed (i.e. we're not reenabling the same
182  // watchpoint). This can not be done when clearing watchpoints since
183  // the gdb-remote protocol repeatedly clears and readds watchpoints on all
184  // program threads, effectively clearing pending events on NetBSD.
185  // NB: enable bits in dr7 are always 0 here since we're (re)adding it
186  if (drN.GetAsUInt64() != addr ||
187  (dr7.GetAsUInt64() & GetWatchControlBitmask(wp_index)) !=
188  (GetWatchTypeBits(watch_flags, wp_index) |
189  GetWatchSizeBits(size, wp_index))) {
190  ClearWatchpointHit(wp_index);
191 
192  // We skip update to drN if neither address nor mode changed.
193  error = WriteRegister(GetDR(wp_index), RegisterValue(addr));
194  if (error.Fail())
195  return error;
196  }
197 
198  error = WriteRegister(GetDR(7), RegisterValue(control_bits));
199  if (error.Fail())
200  return error;
201 
202  return error;
203 }
204 
206  uint32_t wp_index) {
207  if (wp_index >= NumSupportedHardwareWatchpoints())
208  return false;
209 
210  RegisterValue dr7;
211  Status error = ReadRegister(GetDR(7), dr7);
212  if (error.Fail())
213  return false;
214 
215  return WriteRegister(GetDR(7), RegisterValue(dr7.GetAsUInt64() &
216  ~GetBothEnableBitMask(wp_index)))
217  .Success();
218 }
219 
221  if (wp_index >= NumSupportedHardwareWatchpoints())
222  return Status("Watchpoint index out of range");
223 
224  RegisterValue dr6;
225  Status error = ReadRegister(GetDR(6), dr6);
226  if (error.Fail())
227  return error;
228 
229  return WriteRegister(
230  GetDR(6), RegisterValue(dr6.GetAsUInt64() & ~GetStatusBit(wp_index)));
231 }
232 
234  RegisterValue dr7;
235  Status error = ReadRegister(GetDR(7), dr7);
236  if (error.Fail())
237  return error;
238  return WriteRegister(
239  GetDR(7),
241 }
242 
244  lldb::addr_t addr, size_t size, uint32_t watch_flags) {
246  const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
247  for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index) {
248  bool is_vacant;
249  Status error = IsWatchpointVacant(wp_index, is_vacant);
250  if (is_vacant) {
251  error = SetHardwareWatchpointWithIndex(addr, size, watch_flags, wp_index);
252  if (error.Success())
253  return wp_index;
254  }
255  if (error.Fail() && log) {
256  LLDB_LOGF(log, "NativeRegisterContextDBReg_x86::%s Error: %s",
257  __FUNCTION__, error.AsCString());
258  }
259  }
260  return LLDB_INVALID_INDEX32;
261 }
262 
265  if (wp_index >= NumSupportedHardwareWatchpoints())
266  return LLDB_INVALID_ADDRESS;
267  RegisterValue drN;
268  if (ReadRegister(GetDR(wp_index), drN).Fail())
269  return LLDB_INVALID_ADDRESS;
270  return drN.GetAsUInt64();
271 }
272 
274  // Available debug address registers: dr0, dr1, dr2, dr3
275  return 4;
276 }
GetWatchTypeBits
static uint64_t GetWatchTypeBits(uint32_t watch_flags, uint32_t wp_index)
Definition: NativeRegisterContextDBReg_x86.cpp:42
lldb_private::lldb_dr0_i386
@ lldb_dr0_i386
Definition: lldb-x86-register-enums.h:117
lldb_private::NativeRegisterContextDBReg_x86::GetWatchpointAddress
lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override
Definition: NativeRegisterContextDBReg_x86.cpp:264
lldb_private::lldb_dr0_x86_64
@ lldb_dr0_x86_64
Definition: lldb-x86-register-enums.h:303
lldb_private::NativeRegisterContext::ReadRegister
virtual Status ReadRegister(const RegisterInfo *reg_info, RegisterValue &reg_value)=0
lldb_private::RegisterValue
Definition: RegisterValue.h:28
LLDB_LOGF
#define LLDB_LOGF(log,...)
Definition: Log.h:249
LIBLLDB_LOG_WATCHPOINTS
#define LIBLLDB_LOG_WATCHPOINTS
Definition: Logging.h:20
RegisterValue.h
arm64_dwarf::x2
@ x2
Definition: ARM64_DWARF_Registers.h:19
lldb::addr_t
uint64_t addr_t
Definition: lldb-types.h:83
GetBothEnableBitMask
static uint64_t GetBothEnableBitMask(uint32_t wp_index)
Definition: NativeRegisterContextDBReg_x86.cpp:35
lldb_private::RegisterValue::GetAsUInt64
uint64_t GetAsUInt64(uint64_t fail_value=UINT64_MAX, bool *success_ptr=nullptr) const
Definition: RegisterValue.cpp:563
GetStatusBit
static uint64_t GetStatusBit(uint32_t wp_index)
Definition: NativeRegisterContextDBReg_x86.cpp:19
error
static llvm::raw_ostream & error(Stream &strm)
Definition: CommandReturnObject.cpp:17
lldb_private::Status::Success
bool Success() const
Test for success condition.
Definition: Status.cpp:288
lldb_private::NativeRegisterContextDBReg_x86::SetHardwareWatchpoint
uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags) override
Definition: NativeRegisterContextDBReg_x86.cpp:243
lldb_private::NativeRegisterContextRegisterInfo::GetRegisterInfoInterface
const RegisterInfoInterface & GetRegisterInfoInterface() const
Definition: NativeRegisterContextRegisterInfo.cpp:40
Log.h
lldb_private::NativeRegisterContextDBReg_x86::SetHardwareWatchpointWithIndex
Status SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index)
Definition: NativeRegisterContextDBReg_x86.cpp:143
lldb_private::GetLogIfAllCategoriesSet
Log * GetLogIfAllCategoriesSet(uint32_t mask)
Definition: Logging.cpp:58
lldb_private::NativeRegisterContextDBReg_x86::IsWatchpointHit
Status IsWatchpointHit(uint32_t wp_index, bool &is_hit) override
Definition: NativeRegisterContextDBReg_x86.cpp:95
GetEnableBit
static uint64_t GetEnableBit(uint32_t wp_index)
Definition: NativeRegisterContextDBReg_x86.cpp:26
lldb_private::Status
Definition: Status.h:44
lldb_private::NativeRegisterContextDBReg_x86::IsWatchpointVacant
Status IsWatchpointVacant(uint32_t wp_index, bool &is_vacant) override
Definition: NativeRegisterContextDBReg_x86.cpp:128
uint32_t
lldb_private::NativeRegisterContextDBReg_x86::ClearWatchpointHit
Status ClearWatchpointHit(uint32_t wp_index) override
Definition: NativeRegisterContextDBReg_x86.cpp:220
lldb-x86-register-enums.h
LLDB_INVALID_ADDRESS
#define LLDB_INVALID_ADDRESS
Definition: lldb-defines.h:86
lldb_private::NativeRegisterContextDBReg_x86::GetWatchpointHitIndex
Status GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) override
Definition: NativeRegisterContextDBReg_x86.cpp:111
lldb_private::NativeRegisterContextDBReg_x86::ClearAllHardwareWatchpoints
Status ClearAllHardwareWatchpoints() override
Definition: NativeRegisterContextDBReg_x86.cpp:233
lldb_private::NativeRegisterContextDBReg_x86::NumSupportedHardwareWatchpoints
uint32_t NumSupportedHardwareWatchpoints() override
Definition: NativeRegisterContextDBReg_x86.cpp:273
watchpoint_all_control_bit_mask
static constexpr uint64_t watchpoint_all_control_bit_mask
Definition: NativeRegisterContextDBReg_x86.cpp:81
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
lldb_private::NativeRegisterContextDBReg_x86::ClearHardwareWatchpoint
bool ClearHardwareWatchpoint(uint32_t wp_index) override
Definition: NativeRegisterContextDBReg_x86.cpp:205
GetWatchSizeBits
static uint64_t GetWatchSizeBits(uint32_t size, uint32_t wp_index)
Definition: NativeRegisterContextDBReg_x86.cpp:55
LLDB_INVALID_INDEX32
#define LLDB_INVALID_INDEX32
Definition: lldb-defines.h:87
lldb_private::Log
Definition: Log.h:49
lldb_private::NativeRegisterContext::WriteRegister
virtual Status WriteRegister(const RegisterInfo *reg_info, const RegisterValue &reg_value)=0
GetWatchControlBitmask
static uint64_t GetWatchControlBitmask(uint32_t wp_index)
Definition: NativeRegisterContextDBReg_x86.cpp:71
lldb_private::NativeRegisterContextRegisterInfo::GetRegisterInfoAtIndex
const RegisterInfo * GetRegisterInfoAtIndex(uint32_t reg_index) const override
Definition: NativeRegisterContextRegisterInfo.cpp:31
lldb_private::NativeRegisterContextDBReg_x86::GetDR
const RegisterInfo * GetDR(int num) const
Definition: NativeRegisterContextDBReg_x86.cpp:83
NativeRegisterContextDBReg_x86.h