Skip to content

Commit c51ad48

Browse files
committedOct 27, 2017
Add specific ppc64le hardware watchpoint handler
Summary: Add hardware watchpoint funcionality for ppc64le Reviewers: clayborg, zturner Reviewed By: clayborg Subscribers: eugene, clayborg, zturner, lbianc, gut, nemanjai, alexandreyy, kbarton, lldb-commits Differential Revision: https://reviews.llvm.org/D38897 Patch by Ana Julia Caetano <ana.caetano@eldorado.org.br> llvm-svn: 316772
1 parent 5e3808a commit c51ad48

File tree

4 files changed

+320
-12
lines changed

4 files changed

+320
-12
lines changed
 

‎lldb/include/lldb/lldb-enumerations.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -934,8 +934,8 @@ enum ExpressionEvaluationPhase {
934934
// Indicates what types of events cause the watchpoint to fire.
935935
// Used by Native*Protocol-related classes.
936936
//----------------------------------------------------------------------
937-
FLAGS_ENUM(WatchpointKind){eWatchpointKindRead = (1u << 0),
938-
eWatchpointKindWrite = (1u << 1)};
937+
FLAGS_ENUM(WatchpointKind){eWatchpointKindWrite = (1u << 0),
938+
eWatchpointKindRead = (1u << 1)};
939939

940940
enum GdbSignal {
941941
eGdbSignalBadAccess = 0x91,

‎lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.cpp

+260
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ NativeRegisterContextLinux_ppc64le::NativeRegisterContextLinux_ppc64le(
8585
}
8686

8787
::memset(&m_gpr_ppc64le, 0, sizeof(m_gpr_ppc64le));
88+
::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs));
8889
}
8990

9091
uint32_t NativeRegisterContextLinux_ppc64le::GetRegisterSetCount() const {
@@ -242,4 +243,263 @@ Status NativeRegisterContextLinux_ppc64le::DoWriteGPR(
242243
&regset, buf, buf_size);
243244
}
244245

246+
uint32_t NativeRegisterContextLinux_ppc64le::NumSupportedHardwareWatchpoints() {
247+
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
248+
249+
// Read hardware breakpoint and watchpoint information.
250+
Status error = ReadHardwareDebugInfo();
251+
252+
if (error.Fail())
253+
return 0;
254+
255+
LLDB_LOG(log, "{0}", m_max_hwp_supported);
256+
return m_max_hwp_supported;
257+
}
258+
259+
uint32_t NativeRegisterContextLinux_ppc64le::SetHardwareWatchpoint(
260+
lldb::addr_t addr, size_t size, uint32_t watch_flags) {
261+
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
262+
LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size,
263+
watch_flags);
264+
265+
// Read hardware breakpoint and watchpoint information.
266+
Status error = ReadHardwareDebugInfo();
267+
268+
if (error.Fail())
269+
return LLDB_INVALID_INDEX32;
270+
271+
uint32_t control_value = 0, wp_index = 0;
272+
lldb::addr_t real_addr = addr;
273+
uint32_t rw_mode = 0;
274+
275+
// Check if we are setting watchpoint other than read/write/access
276+
// Update watchpoint flag to match ppc64le write-read bit configuration.
277+
switch (watch_flags) {
278+
case eWatchpointKindWrite:
279+
rw_mode = PPC_BREAKPOINT_TRIGGER_WRITE;
280+
watch_flags = 2;
281+
break;
282+
case eWatchpointKindRead:
283+
rw_mode = PPC_BREAKPOINT_TRIGGER_READ;
284+
watch_flags = 1;
285+
break;
286+
case (eWatchpointKindRead | eWatchpointKindWrite):
287+
rw_mode = PPC_BREAKPOINT_TRIGGER_RW;
288+
break;
289+
default:
290+
return LLDB_INVALID_INDEX32;
291+
}
292+
293+
// Check if size has a valid hardware watchpoint length.
294+
if (size != 1 && size != 2 && size != 4 && size != 8)
295+
return LLDB_INVALID_INDEX32;
296+
297+
// Check 8-byte alignment for hardware watchpoint target address.
298+
// Below is a hack to recalculate address and size in order to
299+
// make sure we can watch non 8-byte alligned addresses as well.
300+
if (addr & 0x07) {
301+
302+
addr_t begin = llvm::alignDown(addr, 8);
303+
addr_t end = llvm::alignTo(addr + size, 8);
304+
size = llvm::PowerOf2Ceil(end - begin);
305+
306+
addr = addr & (~0x07);
307+
}
308+
309+
// Setup control value
310+
control_value = watch_flags << 3;
311+
control_value |= ((1 << size) - 1) << 5;
312+
control_value |= (2 << 1) | 1;
313+
314+
// Iterate over stored watchpoints and find a free wp_index
315+
wp_index = LLDB_INVALID_INDEX32;
316+
for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
317+
if ((m_hwp_regs[i].control & 1) == 0) {
318+
wp_index = i; // Mark last free slot
319+
} else if (m_hwp_regs[i].address == addr) {
320+
return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints.
321+
}
322+
}
323+
324+
if (wp_index == LLDB_INVALID_INDEX32)
325+
return LLDB_INVALID_INDEX32;
326+
327+
// Update watchpoint in local cache
328+
m_hwp_regs[wp_index].real_addr = real_addr;
329+
m_hwp_regs[wp_index].address = addr;
330+
m_hwp_regs[wp_index].control = control_value;
331+
m_hwp_regs[wp_index].mode = rw_mode;
332+
333+
// PTRACE call to set corresponding watchpoint register.
334+
error = WriteHardwareDebugRegs();
335+
336+
if (error.Fail()) {
337+
m_hwp_regs[wp_index].address = 0;
338+
m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros<uint32_t>(1);
339+
340+
return LLDB_INVALID_INDEX32;
341+
}
342+
343+
return wp_index;
344+
}
345+
346+
bool NativeRegisterContextLinux_ppc64le::ClearHardwareWatchpoint(
347+
uint32_t wp_index) {
348+
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
349+
LLDB_LOG(log, "wp_index: {0}", wp_index);
350+
351+
// Read hardware breakpoint and watchpoint information.
352+
Status error = ReadHardwareDebugInfo();
353+
354+
if (error.Fail())
355+
return false;
356+
357+
if (wp_index >= m_max_hwp_supported)
358+
return false;
359+
360+
// Create a backup we can revert to in case of failure.
361+
lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
362+
uint32_t tempControl = m_hwp_regs[wp_index].control;
363+
long *tempSlot = reinterpret_cast<long *>(m_hwp_regs[wp_index].slot);
364+
365+
// Update watchpoint in local cache
366+
m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros<uint32_t>(1);
367+
m_hwp_regs[wp_index].address = 0;
368+
m_hwp_regs[wp_index].slot = 0;
369+
m_hwp_regs[wp_index].mode = 0;
370+
371+
// Ptrace call to update hardware debug registers
372+
error = NativeProcessLinux::PtraceWrapper(PPC_PTRACE_DELHWDEBUG,
373+
m_thread.GetID(), 0, tempSlot);
374+
375+
if (error.Fail()) {
376+
m_hwp_regs[wp_index].control = tempControl;
377+
m_hwp_regs[wp_index].address = tempAddr;
378+
m_hwp_regs[wp_index].slot = reinterpret_cast<long>(tempSlot);
379+
380+
return false;
381+
}
382+
383+
return true;
384+
}
385+
386+
uint32_t
387+
NativeRegisterContextLinux_ppc64le::GetWatchpointSize(uint32_t wp_index) {
388+
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
389+
LLDB_LOG(log, "wp_index: {0}", wp_index);
390+
391+
unsigned control = (m_hwp_regs[wp_index].control >> 5) & 0xff;
392+
assert(llvm::isPowerOf2_32(control + 1));
393+
return llvm::countPopulation(control);
394+
}
395+
396+
bool NativeRegisterContextLinux_ppc64le::WatchpointIsEnabled(
397+
uint32_t wp_index) {
398+
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
399+
LLDB_LOG(log, "wp_index: {0}", wp_index);
400+
401+
return !!((m_hwp_regs[wp_index].control & 0x1) == 0x1);
402+
}
403+
404+
Status NativeRegisterContextLinux_ppc64le::GetWatchpointHitIndex(
405+
uint32_t &wp_index, lldb::addr_t trap_addr) {
406+
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
407+
LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr);
408+
409+
uint32_t watch_size;
410+
lldb::addr_t watch_addr;
411+
412+
for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {
413+
watch_size = GetWatchpointSize(wp_index);
414+
watch_addr = m_hwp_regs[wp_index].address;
415+
416+
if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr &&
417+
trap_addr <= watch_addr + watch_size) {
418+
m_hwp_regs[wp_index].hit_addr = trap_addr;
419+
return Status();
420+
}
421+
}
422+
423+
wp_index = LLDB_INVALID_INDEX32;
424+
return Status();
425+
}
426+
427+
lldb::addr_t
428+
NativeRegisterContextLinux_ppc64le::GetWatchpointAddress(uint32_t wp_index) {
429+
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
430+
LLDB_LOG(log, "wp_index: {0}", wp_index);
431+
432+
if (wp_index >= m_max_hwp_supported)
433+
return LLDB_INVALID_ADDRESS;
434+
435+
if (WatchpointIsEnabled(wp_index))
436+
return m_hwp_regs[wp_index].real_addr;
437+
else
438+
return LLDB_INVALID_ADDRESS;
439+
}
440+
441+
lldb::addr_t
442+
NativeRegisterContextLinux_ppc64le::GetWatchpointHitAddress(uint32_t wp_index) {
443+
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
444+
LLDB_LOG(log, "wp_index: {0}", wp_index);
445+
446+
if (wp_index >= m_max_hwp_supported)
447+
return LLDB_INVALID_ADDRESS;
448+
449+
if (WatchpointIsEnabled(wp_index))
450+
return m_hwp_regs[wp_index].hit_addr;
451+
452+
return LLDB_INVALID_ADDRESS;
453+
}
454+
455+
Status NativeRegisterContextLinux_ppc64le::ReadHardwareDebugInfo() {
456+
if (!m_refresh_hwdebug_info) {
457+
return Status();
458+
}
459+
460+
::pid_t tid = m_thread.GetID();
461+
462+
struct ppc_debug_info hwdebug_info;
463+
Status error;
464+
465+
error = NativeProcessLinux::PtraceWrapper(
466+
PPC_PTRACE_GETHWDBGINFO, tid, 0, &hwdebug_info, sizeof(hwdebug_info));
467+
468+
if (error.Fail())
469+
return error;
470+
471+
m_max_hwp_supported = hwdebug_info.num_data_bps;
472+
m_max_hbp_supported = hwdebug_info.num_instruction_bps;
473+
m_refresh_hwdebug_info = false;
474+
475+
return error;
476+
}
477+
478+
Status NativeRegisterContextLinux_ppc64le::WriteHardwareDebugRegs() {
479+
struct ppc_hw_breakpoint reg_state;
480+
Status error;
481+
long ret;
482+
483+
for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
484+
reg_state.addr = m_hwp_regs[i].address;
485+
reg_state.trigger_type = m_hwp_regs[i].mode;
486+
reg_state.version = 1;
487+
reg_state.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
488+
reg_state.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
489+
reg_state.addr2 = 0;
490+
reg_state.condition_value = 0;
491+
492+
error = NativeProcessLinux::PtraceWrapper(PPC_PTRACE_SETHWDEBUG,
493+
m_thread.GetID(), 0, &reg_state,
494+
sizeof(reg_state), &ret);
495+
496+
if (error.Fail())
497+
return error;
498+
499+
m_hwp_regs[i].slot = ret;
500+
}
501+
502+
return error;
503+
}
504+
245505
#endif // defined(__powerpc64__)

‎lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.h

+46-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//===-- NativeRegisterContextLinux_ppc64le.h ---------------------*- C++ -*-===//
1+
//===-- NativeRegisterContextLinux_ppc64le.h --------------------*- C++ -*-===//
22
//
33
// The LLVM Compiler Infrastructure
44
//
@@ -49,6 +49,28 @@ class NativeRegisterContextLinux_ppc64le : public NativeRegisterContextLinux {
4949

5050
Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
5151

52+
//------------------------------------------------------------------
53+
// Hardware watchpoint mangement functions
54+
//------------------------------------------------------------------
55+
56+
uint32_t NumSupportedHardwareWatchpoints() override;
57+
58+
uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
59+
uint32_t watch_flags) override;
60+
61+
bool ClearHardwareWatchpoint(uint32_t hw_index) override;
62+
63+
Status GetWatchpointHitIndex(uint32_t &wp_index,
64+
lldb::addr_t trap_addr) override;
65+
66+
lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override;
67+
68+
lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override;
69+
70+
uint32_t GetWatchpointSize(uint32_t wp_index);
71+
72+
bool WatchpointIsEnabled(uint32_t wp_index);
73+
5274
protected:
5375
Status DoReadGPR(void *buf, size_t buf_size) override;
5476

@@ -60,6 +82,29 @@ class NativeRegisterContextLinux_ppc64le : public NativeRegisterContextLinux {
6082
GPR m_gpr_ppc64le; // 64-bit general purpose registers.
6183

6284
bool IsGPR(unsigned reg) const;
85+
86+
Status ReadHardwareDebugInfo();
87+
88+
Status WriteHardwareDebugRegs();
89+
90+
// Debug register info for hardware watchpoints management.
91+
struct DREG {
92+
lldb::addr_t address; // Breakpoint/watchpoint address value.
93+
lldb::addr_t hit_addr; // Address at which last watchpoint trigger
94+
// exception occurred.
95+
lldb::addr_t real_addr; // Address value that should cause target to stop.
96+
uint32_t control; // Breakpoint/watchpoint control value.
97+
uint32_t refcount; // Serves as enable/disable and reference counter.
98+
long slot; // Saves the value returned from PTRACE_SETHWDEBUG.
99+
int mode; // Defines if watchpoint is read/write/access.
100+
};
101+
102+
std::array<DREG, 4> m_hwp_regs;
103+
104+
// 16 is just a maximum value, query hardware for actual watchpoint count
105+
uint32_t m_max_hwp_supported = 16;
106+
uint32_t m_max_hbp_supported = 16;
107+
bool m_refresh_hwdebug_info = true;
63108
};
64109

65110
} // namespace process_linux

‎lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp

+12-9
Original file line numberDiff line numberDiff line change
@@ -1601,21 +1601,24 @@ GDBRemoteCommunicationClient::GetWatchpointsTriggerAfterInstruction(
16011601
// and we only want to override this behavior if we have explicitly
16021602
// received a qHostInfo telling us otherwise
16031603
if (m_qHostInfo_is_valid != eLazyBoolYes) {
1604-
// On targets like MIPS, watchpoint exceptions are always generated
1605-
// before the instruction is executed. The connected target may not
1606-
// support qHostInfo or qWatchpointSupportInfo packets.
1604+
// On targets like MIPS and ppc64le, watchpoint exceptions are always
1605+
// generated before the instruction is executed. The connected target
1606+
// may not support qHostInfo or qWatchpointSupportInfo packets.
16071607
if (atype == llvm::Triple::mips || atype == llvm::Triple::mipsel ||
1608-
atype == llvm::Triple::mips64 || atype == llvm::Triple::mips64el)
1608+
atype == llvm::Triple::mips64 || atype == llvm::Triple::mips64el ||
1609+
atype == llvm::Triple::ppc64le)
16091610
after = false;
16101611
else
16111612
after = true;
16121613
} else {
1613-
// For MIPS, set m_watchpoints_trigger_after_instruction to eLazyBoolNo
1614-
// if it is not calculated before.
1615-
if (m_watchpoints_trigger_after_instruction == eLazyBoolCalculate &&
1616-
(atype == llvm::Triple::mips || atype == llvm::Triple::mipsel ||
1617-
atype == llvm::Triple::mips64 || atype == llvm::Triple::mips64el))
1614+
// For MIPS and ppc64le, set m_watchpoints_trigger_after_instruction to
1615+
// eLazyBoolNo if it is not calculated before.
1616+
if ((m_watchpoints_trigger_after_instruction == eLazyBoolCalculate &&
1617+
(atype == llvm::Triple::mips || atype == llvm::Triple::mipsel ||
1618+
atype == llvm::Triple::mips64 || atype == llvm::Triple::mips64el)) ||
1619+
atype == llvm::Triple::ppc64le) {
16181620
m_watchpoints_trigger_after_instruction = eLazyBoolNo;
1621+
}
16191622
16201623
after = (m_watchpoints_trigger_after_instruction != eLazyBoolNo);
16211624
}

0 commit comments

Comments
 (0)
Please sign in to comment.