Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.cpp
213845 views
1
//===-- NativeRegisterContextDBReg.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
9
#include "NativeRegisterContextDBReg.h"
10
11
#include "lldb/Utility/LLDBLog.h"
12
#include "lldb/Utility/Log.h"
13
#include "lldb/Utility/RegisterValue.h"
14
15
using namespace lldb_private;
16
17
uint32_t NativeRegisterContextDBReg::NumSupportedHardwareBreakpoints() {
18
Log *log = GetLog(LLDBLog::Breakpoints);
19
20
// Read hardware breakpoint and watchpoint information.
21
llvm::Error error = ReadHardwareDebugInfo();
22
23
if (error) {
24
LLDB_LOG_ERROR(log, std::move(error),
25
"failed to read debug registers: {0}");
26
return 0;
27
}
28
29
LLDB_LOG(log, "{0}", m_max_hbp_supported);
30
return m_max_hbp_supported;
31
}
32
33
uint32_t NativeRegisterContextDBReg::SetHardwareBreakpoint(lldb::addr_t addr,
34
size_t size) {
35
Log *log = GetLog(LLDBLog::Breakpoints);
36
LLDB_LOG(log, "addr: {0:x}, size: {1:x}", addr, size);
37
38
// Read hardware breakpoint and watchpoint information.
39
llvm::Error error = ReadHardwareDebugInfo();
40
if (error) {
41
LLDB_LOG_ERROR(
42
log, std::move(error),
43
"unable to set breakpoint: failed to read debug registers: {0}");
44
return LLDB_INVALID_INDEX32;
45
}
46
47
uint32_t control_value = 0, bp_index = 0;
48
49
if (!ValidateBreakpoint(size, addr))
50
return LLDB_INVALID_INDEX32;
51
52
control_value = MakeBreakControlValue(size);
53
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.
61
}
62
63
if (bp_index == LLDB_INVALID_INDEX32)
64
return LLDB_INVALID_INDEX32;
65
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;
70
71
// PTRACE call to set corresponding hardware breakpoint register.
72
error = WriteHardwareDebugRegs(eDREGTypeBREAK);
73
74
if (error) {
75
m_hbp_regs[bp_index].address = 0;
76
m_hbp_regs[bp_index].control &= ~m_hw_dbg_enable_bit;
77
78
LLDB_LOG_ERROR(
79
log, std::move(error),
80
"unable to set breakpoint: failed to write debug registers: {0}");
81
return LLDB_INVALID_INDEX32;
82
}
83
84
return bp_index;
85
}
86
87
bool NativeRegisterContextDBReg::ClearHardwareBreakpoint(uint32_t hw_idx) {
88
Log *log = GetLog(LLDBLog::Breakpoints);
89
LLDB_LOG(log, "hw_idx: {0}", hw_idx);
90
91
// Read hardware breakpoint and watchpoint information.
92
llvm::Error error = ReadHardwareDebugInfo();
93
if (error) {
94
LLDB_LOG_ERROR(
95
log, std::move(error),
96
"unable to clear breakpoint: failed to read debug registers: {0}");
97
return false;
98
}
99
100
if (hw_idx >= m_max_hbp_supported)
101
return false;
102
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;
106
107
m_hbp_regs[hw_idx].control &= ~m_hw_dbg_enable_bit;
108
m_hbp_regs[hw_idx].address = 0;
109
110
// PTRACE call to clear corresponding hardware breakpoint register.
111
error = WriteHardwareDebugRegs(eDREGTypeBREAK);
112
113
if (error) {
114
m_hbp_regs[hw_idx].control = tempControl;
115
m_hbp_regs[hw_idx].address = tempAddr;
116
117
LLDB_LOG_ERROR(
118
log, std::move(error),
119
"unable to clear breakpoint: failed to write debug registers: {0}");
120
return false;
121
}
122
123
return true;
124
}
125
126
Status
127
NativeRegisterContextDBReg::GetHardwareBreakHitIndex(uint32_t &bp_index,
128
lldb::addr_t trap_addr) {
129
Log *log = GetLog(LLDBLog::Breakpoints);
130
131
LLDB_LOGF(log, "NativeRegisterContextDBReg::%s()", __FUNCTION__);
132
133
lldb::addr_t break_addr;
134
135
for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) {
136
break_addr = m_hbp_regs[bp_index].address;
137
138
if (BreakpointIsEnabled(bp_index) && trap_addr == break_addr) {
139
m_hbp_regs[bp_index].hit_addr = trap_addr;
140
return Status();
141
}
142
}
143
144
bp_index = LLDB_INVALID_INDEX32;
145
return Status();
146
}
147
148
Status NativeRegisterContextDBReg::ClearAllHardwareBreakpoints() {
149
Log *log = GetLog(LLDBLog::Breakpoints);
150
151
LLDB_LOGF(log, "NativeRegisterContextDBReg::%s()", __FUNCTION__);
152
153
// Read hardware breakpoint and watchpoint information.
154
llvm::Error error = ReadHardwareDebugInfo();
155
if (error)
156
return Status::FromError(std::move(error));
157
158
for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
159
if (!BreakpointIsEnabled(i))
160
continue;
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;
164
165
// Clear watchpoints in local cache
166
m_hbp_regs[i].control &= ~m_hw_dbg_enable_bit;
167
m_hbp_regs[i].address = 0;
168
169
// Ptrace call to update hardware debug registers
170
error = WriteHardwareDebugRegs(eDREGTypeBREAK);
171
172
if (error) {
173
m_hbp_regs[i].control = tempControl;
174
m_hbp_regs[i].address = tempAddr;
175
176
return Status::FromError(std::move(error));
177
}
178
}
179
180
return Status();
181
}
182
183
bool NativeRegisterContextDBReg::BreakpointIsEnabled(uint32_t bp_index) {
184
return ((m_hbp_regs[bp_index].control & m_hw_dbg_enable_bit) != 0);
185
}
186
187
uint32_t NativeRegisterContextDBReg::NumSupportedHardwareWatchpoints() {
188
Log *log = GetLog(LLDBLog::Watchpoints);
189
llvm::Error error = ReadHardwareDebugInfo();
190
if (error) {
191
LLDB_LOG_ERROR(log, std::move(error),
192
"failed to read debug registers: {0}");
193
return 0;
194
}
195
196
return m_max_hwp_supported;
197
}
198
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,
203
watch_flags);
204
205
// Read hardware breakpoint and watchpoint information.
206
llvm::Error error = ReadHardwareDebugInfo();
207
if (error) {
208
LLDB_LOG_ERROR(
209
log, std::move(error),
210
"unable to set watchpoint: failed to read debug registers: {0}");
211
return LLDB_INVALID_INDEX32;
212
}
213
214
uint32_t control_value = 0, wp_index = 0;
215
lldb::addr_t real_addr = addr;
216
WatchpointDetails details{size, addr};
217
218
auto adjusted = AdjustWatchpoint(details);
219
if (adjusted == std::nullopt)
220
return LLDB_INVALID_INDEX32;
221
size = adjusted->size;
222
addr = adjusted->addr;
223
224
// Check if we are setting watchpoint other than read/write/access Also
225
// update watchpoint flag to match AArch64/LoongArch write-read bit
226
// configuration.
227
switch (watch_flags) {
228
case lldb::eWatchpointKindWrite:
229
watch_flags = 2;
230
break;
231
case lldb::eWatchpointKindRead:
232
watch_flags = 1;
233
break;
234
case (lldb::eWatchpointKindRead | lldb::eWatchpointKindWrite):
235
break;
236
default:
237
return LLDB_INVALID_INDEX32;
238
}
239
240
control_value = MakeWatchControlValue(size, watch_flags);
241
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.
249
}
250
}
251
252
if (wp_index == LLDB_INVALID_INDEX32)
253
return LLDB_INVALID_INDEX32;
254
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;
259
260
// PTRACE call to set corresponding watchpoint register.
261
error = WriteHardwareDebugRegs(eDREGTypeWATCH);
262
263
if (error) {
264
m_hwp_regs[wp_index].address = 0;
265
m_hwp_regs[wp_index].control &= ~m_hw_dbg_enable_bit;
266
267
LLDB_LOG_ERROR(
268
log, std::move(error),
269
"unable to set watchpoint: failed to write debug registers: {0}");
270
return LLDB_INVALID_INDEX32;
271
}
272
273
return wp_index;
274
}
275
276
bool NativeRegisterContextDBReg::ClearHardwareWatchpoint(uint32_t wp_index) {
277
Log *log = GetLog(LLDBLog::Watchpoints);
278
LLDB_LOG(log, "wp_index: {0}", wp_index);
279
280
// Read hardware breakpoint and watchpoint information.
281
llvm::Error error = ReadHardwareDebugInfo();
282
if (error) {
283
LLDB_LOG_ERROR(
284
log, std::move(error),
285
"unable to set watchpoint: failed to read debug registers: {0}");
286
return false;
287
}
288
289
if (wp_index >= m_max_hwp_supported)
290
return false;
291
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;
295
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;
299
300
// Ptrace call to update hardware debug registers
301
error = WriteHardwareDebugRegs(eDREGTypeWATCH);
302
303
if (error) {
304
m_hwp_regs[wp_index].control = tempControl;
305
m_hwp_regs[wp_index].address = tempAddr;
306
307
LLDB_LOG_ERROR(
308
log, std::move(error),
309
"unable to clear watchpoint: failed to read debug registers: {0}");
310
return false;
311
}
312
313
return true;
314
}
315
316
Status NativeRegisterContextDBReg::ClearAllHardwareWatchpoints() {
317
// Read hardware breakpoint and watchpoint information.
318
llvm::Error error = ReadHardwareDebugInfo();
319
if (error)
320
return Status::FromError(std::move(error));
321
322
for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
323
if (!WatchpointIsEnabled(i))
324
continue;
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;
328
329
// Clear watchpoints in local cache
330
m_hwp_regs[i].control = 0;
331
m_hwp_regs[i].address = 0;
332
333
// Ptrace call to update hardware debug registers
334
error = WriteHardwareDebugRegs(eDREGTypeWATCH);
335
336
if (error) {
337
m_hwp_regs[i].control = tempControl;
338
m_hwp_regs[i].address = tempAddr;
339
340
return Status::FromError(std::move(error));
341
}
342
}
343
344
return Status();
345
}
346
347
Status
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);
352
353
// Read hardware breakpoint and watchpoint information.
354
llvm::Error error = ReadHardwareDebugInfo();
355
if (error)
356
return Status::FromError(std::move(error));
357
358
// AArch64 need mask off ignored bits from watchpoint trap address.
359
trap_addr = FixWatchpointHitAddress(trap_addr);
360
361
uint32_t watch_size;
362
lldb::addr_t watch_addr;
363
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;
367
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;
371
return Status();
372
}
373
}
374
375
wp_index = LLDB_INVALID_INDEX32;
376
return Status();
377
}
378
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);
383
}
384
385
lldb::addr_t
386
NativeRegisterContextDBReg::GetWatchpointAddress(uint32_t wp_index) {
387
Log *log = GetLog(LLDBLog::Watchpoints);
388
LLDB_LOG(log, "wp_index: {0}", wp_index);
389
390
if (wp_index >= m_max_hwp_supported)
391
return LLDB_INVALID_ADDRESS;
392
393
if (WatchpointIsEnabled(wp_index))
394
return m_hwp_regs[wp_index].real_addr;
395
return LLDB_INVALID_ADDRESS;
396
}
397
398
lldb::addr_t
399
NativeRegisterContextDBReg::GetWatchpointHitAddress(uint32_t wp_index) {
400
Log *log = GetLog(LLDBLog::Watchpoints);
401
LLDB_LOG(log, "wp_index: {0}", wp_index);
402
403
if (wp_index >= m_max_hwp_supported)
404
return LLDB_INVALID_ADDRESS;
405
406
if (WatchpointIsEnabled(wp_index))
407
return m_hwp_regs[wp_index].hit_addr;
408
return LLDB_INVALID_ADDRESS;
409
}
410
411