summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Process
diff options
context:
space:
mode:
authorOmair Javaid <omair.javaid@linaro.org>2017-02-24 13:27:31 +0000
committerOmair Javaid <omair.javaid@linaro.org>2017-02-24 13:27:31 +0000
commitd5ffbad275c8800fcd4e0c1d5efe813352d5977e (patch)
treebd9128ea1c1057a32bfd04c9e480c2597ebed628 /lldb/source/Plugins/Process
parentd224c08efcccd1f9db912c30774ffbab5c3be063 (diff)
downloadbcm5719-llvm-d5ffbad275c8800fcd4e0c1d5efe813352d5977e.tar.gz
bcm5719-llvm-d5ffbad275c8800fcd4e0c1d5efe813352d5977e.zip
Hardware breakpoints for Linux on Arm/AArch64 targets
Please look at below differential link for upstream discussion. Differential revision: https://reviews.llvm.org/D29669 llvm-svn: 296119
Diffstat (limited to 'lldb/source/Plugins/Process')
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp22
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeProcessLinux.h2
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp191
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h7
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp152
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h7
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp44
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeThreadLinux.h5
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp14
9 files changed, 330 insertions, 114 deletions
diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
index 1ff8893192f..05276294f0e 100644
--- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -870,6 +870,19 @@ void NativeProcessLinux::MonitorSIGTRAP(const siginfo_t &info,
break;
}
+ // If a breakpoint was hit, report it
+ uint32_t bp_index;
+ error = thread.GetRegisterContext()->GetHardwareBreakHitIndex(
+ bp_index, (uintptr_t)info.si_addr);
+ if (error.Fail())
+ LLDB_LOG(log, "received error while checking for hardware "
+ "breakpoint hits, pid = {0}, error = {1}",
+ thread.GetID(), error);
+ if (bp_index != LLDB_INVALID_INDEX32) {
+ MonitorBreakpoint(thread);
+ break;
+ }
+
// Otherwise, report step over
MonitorTrace(thread);
break;
@@ -1726,11 +1739,18 @@ Error NativeProcessLinux::GetSoftwareBreakpointPCOffset(
Error NativeProcessLinux::SetBreakpoint(lldb::addr_t addr, uint32_t size,
bool hardware) {
if (hardware)
- return Error("NativeProcessLinux does not support hardware breakpoints");
+ return SetHardwareBreakpoint(addr, size);
else
return SetSoftwareBreakpoint(addr, size);
}
+Error NativeProcessLinux::RemoveBreakpoint(lldb::addr_t addr, bool hardware) {
+ if (hardware)
+ return RemoveHardwareBreakpoint(addr);
+ else
+ return NativeProcessProtocol::RemoveBreakpoint(addr);
+}
+
Error NativeProcessLinux::GetSoftwareBreakpointTrapOpcode(
size_t trap_opcode_size_hint, size_t &actual_opcode_size,
const uint8_t *&trap_opcode_bytes) {
diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
index 5f51a6bc138..685a2ca239e 100644
--- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
+++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
@@ -86,6 +86,8 @@ public:
Error SetBreakpoint(lldb::addr_t addr, uint32_t size, bool hardware) override;
+ Error RemoveBreakpoint(lldb::addr_t addr, bool hardware = false) override;
+
void DoStopIDBumped(uint32_t newBumpId) override;
Error GetLoadedModuleFileSpec(const char *module_path,
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp
index 2b1dece8fea..f39abdd3248 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp
@@ -130,6 +130,7 @@ NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm(
::memset(&m_fpr, 0, sizeof(m_fpr));
::memset(&m_gpr_arm, 0, sizeof(m_gpr_arm));
::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs));
+ ::memset(&m_hbr_regs, 0, sizeof(m_hbr_regs));
// 16 is just a maximum value, query hardware for actual watchpoint count
m_max_hwp_supported = 16;
@@ -354,10 +355,28 @@ bool NativeRegisterContextLinux_arm::IsFPR(unsigned reg) const {
return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr);
}
+uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareBreakpoints() {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
+
+ if (log)
+ log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
+
+ Error error;
+
+ // Read hardware breakpoint and watchpoint information.
+ error = ReadHardwareDebugInfo();
+
+ if (error.Fail())
+ return 0;
+
+ LLDB_LOG(log, "{0}", m_max_hbp_supported);
+ return m_max_hbp_supported;
+}
+
uint32_t
NativeRegisterContextLinux_arm::SetHardwareBreakpoint(lldb::addr_t addr,
size_t size) {
- Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
LLDB_LOG(log, "addr: {0:x}, size: {1:x}", addr, size);
// Read hardware breakpoint and watchpoint information.
@@ -368,71 +387,58 @@ NativeRegisterContextLinux_arm::SetHardwareBreakpoint(lldb::addr_t addr,
uint32_t control_value = 0, bp_index = 0;
- // Check if size has a valid hardware breakpoint length.
- // Thumb instructions are 2-bytes but we have no way here to determine
- // if target address is a thumb or arm instruction.
- // TODO: Add support for setting thumb mode hardware breakpoints
- if (size != 4 && size != 2)
+ // Setup address and control values.
+ // Use size to get a hint of arm vs thumb modes.
+ switch (size) {
+ case 2:
+ control_value = (0x3 << 5) | 7;
+ addr &= ~1;
+ break;
+ case 4:
+ control_value = (0xfu << 5) | 7;
+ addr &= ~3;
+ break;
+ default:
return LLDB_INVALID_INDEX32;
+ }
- // Setup control value
- // Make the byte_mask into a valid Byte Address Select mask
- control_value = 0xfu << 5;
-
- // Enable this breakpoint and make it stop in privileged or user mode;
- control_value |= 7;
-
- // Make sure bits 1:0 are clear in our address
- // This should be different once we support thumb here.
- addr &= ~((lldb::addr_t)3);
-
- // Iterate over stored hardware breakpoints
- // Find a free bp_index or update reference count if duplicate.
+ // Iterate over stored breakpoints and find a free bp_index
bp_index = LLDB_INVALID_INDEX32;
-
for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
if ((m_hbr_regs[i].control & 1) == 0) {
bp_index = i; // Mark last free slot
- } else if (m_hbr_regs[i].address == addr &&
- m_hbr_regs[i].control == control_value) {
- bp_index = i; // Mark duplicate index
- break; // Stop searching here
+ } else if (m_hbr_regs[i].address == addr) {
+ return LLDB_INVALID_INDEX32; // We do not support duplicate breakpoints.
}
}
if (bp_index == LLDB_INVALID_INDEX32)
return LLDB_INVALID_INDEX32;
- // Add new or update existing breakpoint
- if ((m_hbr_regs[bp_index].control & 1) == 0) {
- m_hbr_regs[bp_index].address = addr;
- m_hbr_regs[bp_index].control = control_value;
- m_hbr_regs[bp_index].refcount = 1;
+ // Update breakpoint in local cache
+ m_hbr_regs[bp_index].real_addr = addr;
+ m_hbr_regs[bp_index].address = addr;
+ m_hbr_regs[bp_index].control = control_value;
- // PTRACE call to set corresponding hardware breakpoint register.
- error = WriteHardwareDebugRegs(eDREGTypeBREAK, bp_index);
+ // PTRACE call to set corresponding hardware breakpoint register.
+ error = WriteHardwareDebugRegs(eDREGTypeBREAK, bp_index);
- if (error.Fail()) {
- m_hbr_regs[bp_index].address = 0;
- m_hbr_regs[bp_index].control &= ~1;
- m_hbr_regs[bp_index].refcount = 0;
+ if (error.Fail()) {
+ m_hbr_regs[bp_index].address = 0;
+ m_hbr_regs[bp_index].control &= ~1;
- return LLDB_INVALID_INDEX32;
- }
- } else
- m_hbr_regs[bp_index].refcount++;
+ return LLDB_INVALID_INDEX32;
+ }
return bp_index;
}
bool NativeRegisterContextLinux_arm::ClearHardwareBreakpoint(uint32_t hw_idx) {
- Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
LLDB_LOG(log, "hw_idx: {0}", hw_idx);
- Error error;
-
// Read hardware breakpoint and watchpoint information.
- error = ReadHardwareDebugInfo();
+ Error error = ReadHardwareDebugInfo();
if (error.Fail())
return false;
@@ -440,35 +446,88 @@ bool NativeRegisterContextLinux_arm::ClearHardwareBreakpoint(uint32_t hw_idx) {
if (hw_idx >= m_max_hbp_supported)
return false;
- // Update reference count if multiple references.
- if (m_hbr_regs[hw_idx].refcount > 1) {
- m_hbr_regs[hw_idx].refcount--;
- return true;
- } else if (m_hbr_regs[hw_idx].refcount == 1) {
- // Create a backup we can revert to in case of failure.
- lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address;
- uint32_t tempControl = m_hbr_regs[hw_idx].control;
- uint32_t tempRefCount = m_hbr_regs[hw_idx].refcount;
+ // Create a backup we can revert to in case of failure.
+ lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address;
+ uint32_t tempControl = m_hbr_regs[hw_idx].control;
- m_hbr_regs[hw_idx].control &= ~1;
- m_hbr_regs[hw_idx].address = 0;
- m_hbr_regs[hw_idx].refcount = 0;
+ m_hbr_regs[hw_idx].control &= ~1;
+ m_hbr_regs[hw_idx].address = 0;
- // PTRACE call to clear corresponding hardware breakpoint register.
- WriteHardwareDebugRegs(eDREGTypeBREAK, hw_idx);
+ // PTRACE call to clear corresponding hardware breakpoint register.
+ error = WriteHardwareDebugRegs(eDREGTypeBREAK, hw_idx);
- if (error.Fail()) {
- m_hbr_regs[hw_idx].control = tempControl;
- m_hbr_regs[hw_idx].address = tempAddr;
- m_hbr_regs[hw_idx].refcount = tempRefCount;
+ if (error.Fail()) {
+ m_hbr_regs[hw_idx].control = tempControl;
+ m_hbr_regs[hw_idx].address = tempAddr;
- return false;
+ return false;
+ }
+
+ return true;
+}
+
+Error NativeRegisterContextLinux_arm::GetHardwareBreakHitIndex(
+ uint32_t &bp_index, lldb::addr_t trap_addr) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
+
+ if (log)
+ log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
+
+ lldb::addr_t break_addr;
+
+ for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) {
+ break_addr = m_hbr_regs[bp_index].address;
+
+ if ((m_hbr_regs[bp_index].control & 0x1) && (trap_addr == break_addr)) {
+ m_hbr_regs[bp_index].hit_addr = trap_addr;
+ return Error();
}
+ }
- return true;
+ bp_index = LLDB_INVALID_INDEX32;
+ return Error();
+}
+
+Error NativeRegisterContextLinux_arm::ClearAllHardwareBreakpoints() {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
+
+ if (log)
+ log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
+
+ Error error;
+
+ // Read hardware breakpoint and watchpoint information.
+ error = ReadHardwareDebugInfo();
+
+ if (error.Fail())
+ return error;
+
+ lldb::addr_t tempAddr = 0;
+ uint32_t tempControl = 0;
+
+ for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
+ if (m_hbr_regs[i].control & 0x01) {
+ // Create a backup we can revert to in case of failure.
+ tempAddr = m_hbr_regs[i].address;
+ tempControl = m_hbr_regs[i].control;
+
+ // Clear breakpoints in local cache
+ m_hbr_regs[i].control &= ~1;
+ m_hbr_regs[i].address = 0;
+
+ // Ptrace call to update hardware debug registers
+ error = WriteHardwareDebugRegs(eDREGTypeBREAK, i);
+
+ if (error.Fail()) {
+ m_hbr_regs[i].control = tempControl;
+ m_hbr_regs[i].address = tempAddr;
+
+ return error;
+ }
+ }
}
- return false;
+ return Error();
}
uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareWatchpoints() {
@@ -784,8 +843,8 @@ Error NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(int hwbType,
(PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 2), ctrl_buf,
sizeof(unsigned int));
} else {
- addr_buf = &m_hwp_regs[hwb_index].address;
- ctrl_buf = &m_hwp_regs[hwb_index].control;
+ addr_buf = &m_hbr_regs[hwb_index].address;
+ ctrl_buf = &m_hbr_regs[hwb_index].control;
error = NativeProcessLinux::PtraceWrapper(
PTRACE_SETHBPREGS, m_thread.GetID(),
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h
index f979811216d..824ac88ad9e 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h
@@ -46,10 +46,17 @@ public:
// Hardware breakpoints/watchpoint mangement functions
//------------------------------------------------------------------
+ uint32_t NumSupportedHardwareBreakpoints() override;
+
uint32_t SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override;
bool ClearHardwareBreakpoint(uint32_t hw_idx) override;
+ Error ClearAllHardwareBreakpoints() override;
+
+ Error GetHardwareBreakHitIndex(uint32_t &bp_index,
+ lldb::addr_t trap_addr) override;
+
uint32_t NumSupportedHardwareWatchpoints() override;
uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
index 16e5784b09f..a1327954b21 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
@@ -153,6 +153,7 @@ NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64(
::memset(&m_fpr, 0, sizeof(m_fpr));
::memset(&m_gpr_arm64, 0, sizeof(m_gpr_arm64));
::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs));
+ ::memset(&m_hbr_regs, 0, sizeof(m_hbr_regs));
// 16 is just a maximum value, query hardware for actual watchpoint count
m_max_hwp_supported = 16;
@@ -360,10 +361,27 @@ bool NativeRegisterContextLinux_arm64::IsFPR(unsigned reg) const {
return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr);
}
+uint32_t NativeRegisterContextLinux_arm64::NumSupportedHardwareBreakpoints() {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
+
+ if (log)
+ log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
+
+ Error error;
+
+ // Read hardware breakpoint and watchpoint information.
+ error = ReadHardwareDebugInfo();
+
+ if (error.Fail())
+ return 0;
+
+ return m_max_hbp_supported;
+}
+
uint32_t
NativeRegisterContextLinux_arm64::SetHardwareBreakpoint(lldb::addr_t addr,
size_t size) {
- Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
LLDB_LOG(log, "addr: {0:x}, size: {1:x}", addr, size);
// Read hardware breakpoint and watchpoint information.
@@ -388,47 +406,40 @@ NativeRegisterContextLinux_arm64::SetHardwareBreakpoint(lldb::addr_t addr,
control_value |= ((1 << size) - 1) << 5;
control_value |= (2 << 1) | 1;
- // Iterate over stored hardware breakpoints
- // Find a free bp_index or update reference count if duplicate.
+ // Iterate over stored breakpoints and find a free bp_index
bp_index = LLDB_INVALID_INDEX32;
for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
if ((m_hbr_regs[i].control & 1) == 0) {
bp_index = i; // Mark last free slot
- } else if (m_hbr_regs[i].address == addr &&
- m_hbr_regs[i].control == control_value) {
- bp_index = i; // Mark duplicate index
- break; // Stop searching here
+ } else if (m_hbr_regs[i].address == addr) {
+ return LLDB_INVALID_INDEX32; // We do not support duplicate breakpoints.
}
}
if (bp_index == LLDB_INVALID_INDEX32)
return LLDB_INVALID_INDEX32;
- // Add new or update existing breakpoint
- if ((m_hbr_regs[bp_index].control & 1) == 0) {
- m_hbr_regs[bp_index].address = addr;
- m_hbr_regs[bp_index].control = control_value;
- m_hbr_regs[bp_index].refcount = 1;
+ // Update breakpoint in local cache
+ m_hbr_regs[bp_index].real_addr = addr;
+ m_hbr_regs[bp_index].address = addr;
+ m_hbr_regs[bp_index].control = control_value;
- // PTRACE call to set corresponding hardware breakpoint register.
- error = WriteHardwareDebugRegs(eDREGTypeBREAK);
+ // PTRACE call to set corresponding hardware breakpoint register.
+ error = WriteHardwareDebugRegs(eDREGTypeBREAK);
- if (error.Fail()) {
- m_hbr_regs[bp_index].address = 0;
- m_hbr_regs[bp_index].control &= ~1;
- m_hbr_regs[bp_index].refcount = 0;
+ if (error.Fail()) {
+ m_hbr_regs[bp_index].address = 0;
+ m_hbr_regs[bp_index].control &= ~1;
- return LLDB_INVALID_INDEX32;
- }
- } else
- m_hbr_regs[bp_index].refcount++;
+ return LLDB_INVALID_INDEX32;
+ }
return bp_index;
}
bool NativeRegisterContextLinux_arm64::ClearHardwareBreakpoint(
uint32_t hw_idx) {
- Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
LLDB_LOG(log, "hw_idx: {0}", hw_idx);
// Read hardware breakpoint and watchpoint information.
@@ -440,35 +451,88 @@ bool NativeRegisterContextLinux_arm64::ClearHardwareBreakpoint(
if (hw_idx >= m_max_hbp_supported)
return false;
- // Update reference count if multiple references.
- if (m_hbr_regs[hw_idx].refcount > 1) {
- m_hbr_regs[hw_idx].refcount--;
- return true;
- } else if (m_hbr_regs[hw_idx].refcount == 1) {
- // Create a backup we can revert to in case of failure.
- lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address;
- uint32_t tempControl = m_hbr_regs[hw_idx].control;
- uint32_t tempRefCount = m_hbr_regs[hw_idx].refcount;
+ // Create a backup we can revert to in case of failure.
+ lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address;
+ uint32_t tempControl = m_hbr_regs[hw_idx].control;
+
+ m_hbr_regs[hw_idx].control &= ~1;
+ m_hbr_regs[hw_idx].address = 0;
+
+ // PTRACE call to clear corresponding hardware breakpoint register.
+ error = WriteHardwareDebugRegs(eDREGTypeBREAK);
+
+ if (error.Fail()) {
+ m_hbr_regs[hw_idx].control = tempControl;
+ m_hbr_regs[hw_idx].address = tempAddr;
+
+ return false;
+ }
+
+ return true;
+}
+
+Error NativeRegisterContextLinux_arm64::GetHardwareBreakHitIndex(
+ uint32_t &bp_index, lldb::addr_t trap_addr) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
- m_hbr_regs[hw_idx].control &= ~1;
- m_hbr_regs[hw_idx].address = 0;
- m_hbr_regs[hw_idx].refcount = 0;
+ if (log)
+ log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
- // PTRACE call to clear corresponding hardware breakpoint register.
- WriteHardwareDebugRegs(eDREGTypeBREAK);
+ lldb::addr_t break_addr;
- if (error.Fail()) {
- m_hbr_regs[hw_idx].control = tempControl;
- m_hbr_regs[hw_idx].address = tempAddr;
- m_hbr_regs[hw_idx].refcount = tempRefCount;
+ for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) {
+ break_addr = m_hbr_regs[bp_index].address;
- return false;
+ if ((m_hbr_regs[bp_index].control & 0x1) && (trap_addr == break_addr)) {
+ m_hbr_regs[bp_index].hit_addr = trap_addr;
+ return Error();
}
+ }
- return true;
+ bp_index = LLDB_INVALID_INDEX32;
+ return Error();
+}
+
+Error NativeRegisterContextLinux_arm64::ClearAllHardwareBreakpoints() {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
+
+ if (log)
+ log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
+
+ Error error;
+
+ // Read hardware breakpoint and watchpoint information.
+ error = ReadHardwareDebugInfo();
+
+ if (error.Fail())
+ return error;
+
+ lldb::addr_t tempAddr = 0;
+ uint32_t tempControl = 0;
+
+ for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
+ if (m_hbr_regs[i].control & 0x01) {
+ // Create a backup we can revert to in case of failure.
+ tempAddr = m_hbr_regs[i].address;
+ tempControl = m_hbr_regs[i].control;
+
+ // Clear watchpoints in local cache
+ m_hbr_regs[i].control &= ~1;
+ m_hbr_regs[i].address = 0;
+
+ // Ptrace call to update hardware debug registers
+ error = WriteHardwareDebugRegs(eDREGTypeBREAK);
+
+ if (error.Fail()) {
+ m_hbr_regs[i].control = tempControl;
+ m_hbr_regs[i].address = tempAddr;
+
+ return error;
+ }
+ }
}
- return false;
+ return Error();
}
uint32_t NativeRegisterContextLinux_arm64::NumSupportedHardwareWatchpoints() {
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
index c46c375acfe..4ffbd97ee33 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
@@ -46,10 +46,17 @@ public:
// Hardware breakpoints/watchpoint mangement functions
//------------------------------------------------------------------
+ uint32_t NumSupportedHardwareBreakpoints() override;
+
uint32_t SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override;
bool ClearHardwareBreakpoint(uint32_t hw_idx) override;
+ Error ClearAllHardwareBreakpoints() override;
+
+ Error GetHardwareBreakHitIndex(uint32_t &bp_index,
+ lldb::addr_t trap_addr) override;
+
uint32_t NumSupportedHardwareWatchpoints() override;
uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
diff --git a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
index a50ea7e3d0a..d46a3da3a59 100644
--- a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
@@ -190,6 +190,38 @@ Error NativeThreadLinux::RemoveWatchpoint(lldb::addr_t addr) {
return Error("Clearing hardware watchpoint failed.");
}
+Error NativeThreadLinux::SetHardwareBreakpoint(lldb::addr_t addr, size_t size) {
+ if (m_state == eStateLaunching)
+ return Error();
+
+ Error error = RemoveHardwareBreakpoint(addr);
+ if (error.Fail())
+ return error;
+
+ NativeRegisterContextSP reg_ctx = GetRegisterContext();
+ uint32_t bp_index = reg_ctx->SetHardwareBreakpoint(addr, size);
+
+ if (bp_index == LLDB_INVALID_INDEX32)
+ return Error("Setting hardware breakpoint failed.");
+
+ m_hw_break_index_map.insert({addr, bp_index});
+ return Error();
+}
+
+Error NativeThreadLinux::RemoveHardwareBreakpoint(lldb::addr_t addr) {
+ auto bp = m_hw_break_index_map.find(addr);
+ if (bp == m_hw_break_index_map.end())
+ return Error();
+
+ uint32_t bp_index = bp->second;
+ if (GetRegisterContext()->ClearHardwareBreakpoint(bp_index)) {
+ m_hw_break_index_map.erase(bp);
+ return Error();
+ }
+
+ return Error("Clearing hardware breakpoint failed.");
+}
+
Error NativeThreadLinux::Resume(uint32_t signo) {
const StateType new_state = StateType::eStateRunning;
MaybeLogStateChange(new_state);
@@ -211,6 +243,18 @@ Error NativeThreadLinux::Resume(uint32_t signo) {
}
}
+ // Set all active hardware breakpoint on all threads.
+ if (m_hw_break_index_map.empty()) {
+ NativeProcessLinux &process = GetProcess();
+
+ const auto &hw_breakpoint_map = process.GetHardwareBreakpointMap();
+ GetRegisterContext()->ClearAllHardwareBreakpoints();
+ for (const auto &pair : hw_breakpoint_map) {
+ const auto &bp = pair.second;
+ SetHardwareBreakpoint(bp.m_addr, bp.m_size);
+ }
+ }
+
intptr_t data = 0;
if (signo != LLDB_INVALID_SIGNAL_NUMBER)
diff --git a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
index cc03a1fbb62..42697497c0a 100644
--- a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
+++ b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
@@ -46,6 +46,10 @@ public:
Error RemoveWatchpoint(lldb::addr_t addr) override;
+ Error SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override;
+
+ Error RemoveHardwareBreakpoint(lldb::addr_t addr) override;
+
private:
// ---------------------------------------------------------------------
// Interface for friend classes
@@ -102,6 +106,7 @@ private:
std::string m_stop_description;
using WatchpointIndexMap = std::map<lldb::addr_t, uint32_t>;
WatchpointIndexMap m_watchpoint_index_map;
+ WatchpointIndexMap m_hw_break_index_map;
std::unique_ptr<SingleStepWorkaround> m_step_workaround;
};
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
index 0beabc60ddc..74cecfe0e40 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -2534,12 +2534,14 @@ GDBRemoteCommunicationServerLLGS::Handle_z(StringExtractorGDBRemote &packet) {
packet, "Too short z packet, missing software/hardware specifier");
bool want_breakpoint = true;
+ bool want_hardware = false;
const GDBStoppointType stoppoint_type =
GDBStoppointType(packet.GetS32(eStoppointInvalid));
switch (stoppoint_type) {
case eBreakpointHardware:
want_breakpoint = true;
+ want_hardware = true;
break;
case eBreakpointSoftware:
want_breakpoint = true;
@@ -2582,7 +2584,8 @@ GDBRemoteCommunicationServerLLGS::Handle_z(StringExtractorGDBRemote &packet) {
if (want_breakpoint) {
// Try to clear the breakpoint.
- const Error error = m_debugged_process_sp->RemoveBreakpoint(addr);
+ const Error error =
+ m_debugged_process_sp->RemoveBreakpoint(addr, want_hardware);
if (error.Success())
return SendOKResponse();
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
@@ -3040,9 +3043,14 @@ GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo(
if (packet.GetChar() != ':')
return SendErrorResponse(67);
- uint32_t num = m_debugged_process_sp->GetMaxWatchpoints();
+ auto hw_debug_cap = m_debugged_process_sp->GetHardwareDebugSupportInfo();
+
StreamGDBRemote response;
- response.Printf("num:%d;", num);
+ if (hw_debug_cap == llvm::None)
+ response.Printf("num:0;");
+ else
+ response.Printf("num:%d;", hw_debug_cap->second);
+
return SendPacketNoLock(response.GetString());
}
OpenPOWER on IntegriCloud