summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp160
-rw-r--r--lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h7
2 files changed, 140 insertions, 27 deletions
diff --git a/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp b/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp
index 55d0e0c4884..deb7bd65a28 100644
--- a/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp
+++ b/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp
@@ -58,7 +58,9 @@
// Definitions for the Debug Status and Control Register fields:
// [5:2] => Method of debug entry
-#define WATCHPOINT_OCCURRED ((uint32_t)(2u))
+//#define WATCHPOINT_OCCURRED ((uint32_t)(2u))
+// I'm seeing this, instead.
+#define WATCHPOINT_OCCURRED ((uint32_t)(10u))
//#define DNB_ARCH_MACH_ARM_DEBUG_SW_STEP 1
@@ -269,10 +271,16 @@ static void
DumpDBGState(const DNBArchMachARM::DBG& dbg)
{
uint32_t i = 0;
- for (i=0; i<16; i++)
+ for (i=0; i<16; i++) {
DNBLogThreadedIf(LOG_STEP, "BVR%-2u/BCR%-2u = { 0x%8.8x, 0x%8.8x } WVR%-2u/WCR%-2u = { 0x%8.8x, 0x%8.8x }",
i, i, dbg.__bvr[i], dbg.__bcr[i],
i, i, dbg.__wvr[i], dbg.__wcr[i]);
+ /*
+ printf("BVR%-2u/BCR%-2u = { 0x%8.8x, 0x%8.8x } WVR%-2u/WCR%-2u = { 0x%8.8x, 0x%8.8x }\n",
+ i, i, dbg.__bvr[i], dbg.__bcr[i],
+ i, i, dbg.__wvr[i], dbg.__wcr[i]);
+ */
+ }
}
kern_return_t
@@ -357,11 +365,18 @@ DNBArchMachARM::ThreadWillResume()
}
}
- // Reset the method of debug entry field of the DSCR, if necessary, before we resume.
- if (HasWatchpointOccurred())
+ // Disable the triggered watchpoint temporarily because we resume.
+ if (this->m_watchpoint_did_occur)
{
- ClearWatchpointOccurred();
- DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::ThreadWillResume() ClearWatchpointOccurred() called");
+ if (this->m_watchpoint_hw_index >= 0) {
+ DisableHardwareWatchpoint(this->m_watchpoint_hw_index);
+ DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::ThreadWillResume() DisableHardwareWatchpoint(%d) called",
+ this->m_watchpoint_hw_index);
+ /*
+ printf("DNBArchMachARM::ThreadWillResume() DisableHardwareWatchpoint(%d) called",
+ this->m_watchpoint_hw_index);
+ */
+ }
}
}
@@ -471,25 +486,41 @@ DNBArchMachARM::ThreadDidStop()
bool
DNBArchMachARM::NotifyException(MachException::Data& exc)
{
+ //printf("exc.ex_type=%d\n", exc.exc_type);
switch (exc.exc_type)
{
default:
break;
case EXC_BREAKPOINT:
- if (exc.exc_data.size() >= 2 && exc.exc_data[0] == 1)
+ /*
+ for (size_t i = 0; i < exc.exc_data.size(); ++i)
+ printf("exc.exc_data[%lu]=%llu\n", i, exc.exc_data[i]);
+ */
+ if (exc.exc_data.size() == 2 && exc.exc_data[0] == EXC_ARM_DA_DEBUG)
{
- // exc_code = EXC_ARM_WATCHPOINT
+ // exc_code = EXC_ARM_DA_DEBUG
//
// Check whether this corresponds to a watchpoint hit event.
- // If yes, set the exc_sub_code to the data break address.
+ // If yes, retrieve the exc_sub_code as the data break address.
if (!HasWatchpointOccurred())
break;
- nub_addr_t addr = 0;
+ //printf("Info -- hardware watchpoint was hit!\n");
+ this->m_watchpoint_did_occur = true;
+ this->m_watchpoint_hw_index = -1;
+
+ // The data break address is passed as exc_data[1].
+ nub_addr_t addr = exc.exc_data[1];
+ //printf("exc.exc_data[1]=0x%x\n", addr);
+ // Find the hardware index with the side effect of possibly massaging the
+ // addr to return the starting address as seen from the debugger side.
uint32_t hw_index = GetHardwareWatchpointHit(addr);
if (hw_index != INVALID_NUB_HW_INDEX)
{
+ this->m_watchpoint_hw_index = hw_index;
+ //printf("Setting exc.exc_data[1] to %u\n", addr);
exc.exc_data[1] = addr;
// Piggyback the hw_index in the exc.data.
+ //printf("Setting exc.exc_data[2] to %u\n", hw_index);
exc.exc_data.push_back(hw_index);
}
@@ -680,7 +711,7 @@ static inline uint32_t bits(uint32_t value, uint32_t msbit, uint32_t lsbit)
assert(msbit >= lsbit);
uint32_t shift_left = sizeof(value) * 8 - 1 - msbit;
value <<= shift_left; // shift anything above the msbit off of the unsigned edge
- value >>= shift_left + lsbit; // shift it back again down to the lsbit (including undoing any shift from above)
+ value >>= (shift_left + lsbit); // shift it back again down to the lsbit (including undoing any shift from above)
return value; // return our result
}
@@ -2225,6 +2256,7 @@ DNBArchMachARM::NumSupportedHardwareWatchpoints()
}
}
}
+ //printf("g_num_supported_hw_watchpoints=%u\n", g_num_supported_hw_watchpoints);
return g_num_supported_hw_watchpoints;
}
@@ -2333,6 +2365,7 @@ DNBArchMachARM::DisableHardwareBreakpoint (uint32_t hw_index)
uint32_t
DNBArchMachARM::EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool read, bool write)
{
+ //printf("DNBArchMachARM::EnableHardwareWatchpoint(addr = 0x%8.8llx, size = %zu, read = %u, write = %u)\n", (uint64_t)addr, size, read, write);
DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::EnableHardwareWatchpoint(addr = 0x%8.8llx, size = %zu, read = %u, write = %u)", (uint64_t)addr, size, read, write);
const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
@@ -2393,6 +2426,9 @@ DNBArchMachARM::EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool
// See if we found an available hw watchpoint slot above
if (i < num_hw_watchpoints)
{
+ //printf("Found an available watchpoint slot: %u\nBefore setting WRP...\n", i);
+ //DumpDBGState(m_state.dbg);
+
// Make the byte_mask into a valid Byte Address Select mask
uint32_t byte_address_select = byte_mask << 5;
// Make sure bits 1:0 are clear in our address
@@ -2404,6 +2440,9 @@ DNBArchMachARM::EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool
WCR_ENABLE; // Enable this watchpoint;
kret = SetDBGState();
+ //printf("After setting WRP for slot: %u ...\n", i);
+ //DumpDBGState(m_state.dbg);
+
DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::EnableHardwareWatchpoint() SetDBGState() => 0x%8.8x.", kret);
if (kret == KERN_SUCCESS)
@@ -2418,6 +2457,33 @@ DNBArchMachARM::EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool
}
bool
+DNBArchMachARM::EnableHardwareWatchpoint (uint32_t hw_index)
+{
+ kern_return_t kret = GetDBGState(false);
+
+ const uint32_t num_hw_points = NumSupportedHardwareWatchpoints();
+ if (kret == KERN_SUCCESS)
+ {
+ if (hw_index < num_hw_points)
+ {
+ m_state.dbg.__wcr[hw_index] &= ~((nub_addr_t)0x1);
+ DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::EnableHardwareWatchpoint( %u ) - WVR%u = 0x%8.8x WCR%u = 0x%8.8x",
+ hw_index,
+ hw_index,
+ m_state.dbg.__wvr[hw_index],
+ hw_index,
+ m_state.dbg.__wcr[hw_index]);
+
+ kret = SetDBGState();
+
+ if (kret == KERN_SUCCESS)
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
DNBArchMachARM::DisableHardwareWatchpoint (uint32_t hw_index)
{
kern_return_t kret = GetDBGState(false);
@@ -2427,7 +2493,7 @@ DNBArchMachARM::DisableHardwareWatchpoint (uint32_t hw_index)
{
if (hw_index < num_hw_points)
{
- m_state.dbg.__wcr[hw_index] = 0;
+ m_state.dbg.__wcr[hw_index] &= ~((nub_addr_t)0x1);
DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::DisableHardwareWatchpoint( %u ) - WVR%u = 0x%8.8x WCR%u = 0x%8.8x",
hw_index,
hw_index,
@@ -2458,28 +2524,68 @@ DNBArchMachARM::HardwareWatchpointStateChanged ()
Valid_Global_Debug_State = true;
}
-// Iterate through the debug registers; return the index of the first hit.
+// Returns -1 if the trailing bit patterns are not one of:
+// { 0b???1, 0b??10, 0b?100, 0b1000 }.
+static inline
+int32_t
+LowestBitSet(uint32_t val)
+{
+ //printf("LowestBitSet(): val=0x%x)\n", val);
+ /*
+ for (unsigned i = 0; i < 4; ++i)
+ printf("bit %u = %u\n", i, bit(val, i));
+ */
+ for (unsigned i = 0; i < 4; ++i) {
+ if (bit(val, i)) {
+ //printf("LowestBitSet() returning %d\n", i);
+ return i;
+ }
+ }
+ return -1;
+}
+
+// Iterate through the debug registers; return the index of the first watchpoint whose address matches.
+// As a side effect, the starting address as understood by the debugger is returned which could be
+// different from 'addr' passed as an in/out argument.
uint32_t
DNBArchMachARM::GetHardwareWatchpointHit(nub_addr_t &addr)
{
// Read the debug state
kern_return_t kret = GetDBGState(true);
+ //printf("GetHardwareWatchpointHit: dumping the debug state....\n");
+ //DumpDBGState(m_state.dbg);
DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::GetHardwareWatchpointHit() GetDBGState() => 0x%8.8x.", kret);
+ DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::GetHardwareWatchpointHit() addr = 0x%llx", (uint64_t)addr);
+
+ // This is the watchpoint value to match against, i.e., word address.
+ nub_addr_t wp_val = addr & ~((nub_addr_t)3);
if (kret == KERN_SUCCESS)
{
DBG &debug_state = m_state.dbg;
uint32_t i, num = NumSupportedHardwareWatchpoints();
for (i = 0; i < num; ++i)
{
- // FIXME: IsWatchpointHit() currently returns the first enabled watchpoint,
- // instead of finding the watchpoint that actually triggered.
- if (IsWatchpointHit(debug_state, i))
- {
- addr = GetWatchAddress(debug_state, i);
- DNBLogThreadedIf(LOG_WATCHPOINTS,
- "DNBArchMachARM::GetHardwareWatchpointHit() found => %u (addr = 0x%llx).",
- i,
- (uint64_t)addr);
+ nub_addr_t wp_addr = GetWatchAddress(debug_state, i);
+ /*
+ printf("DNBArchMachARM::GetHardwareWatchpointHit() slot: %u (addr = 0x%llx).\n",
+ i, (uint64_t)wp_addr);
+ */
+ DNBLogThreadedIf(LOG_WATCHPOINTS,
+ "DNBArchMachARM::GetHardwareWatchpointHit() slot: %u (addr = 0x%llx).",
+ i, (uint64_t)wp_addr);
+ if (wp_val == wp_addr) {
+ uint32_t byte_mask = bits(debug_state.__wcr[i], 8, 5);
+
+ // Sanity check the byte_mask, first.
+ if (LowestBitSet(byte_mask) < 0)
+ continue;
+
+ // Compute the starting address (from the point of view of the debugger).
+ addr = wp_addr + LowestBitSet(byte_mask);
+ /*
+ printf("DNBArchMachARM::GetHardwareWatchpointHit() found => %u (wp_addr = 0x%llx, addr = 0x%llx).\n",
+ i, (uint64_t)wp_addr, (uint64_t)addr);
+ */
return i;
}
}
@@ -2495,14 +2601,15 @@ DNBArchMachARM::GetHardwareWatchpointHit(nub_addr_t &addr)
void
DNBArchMachARM::ClearWatchpointOccurred()
{
- // See also IsWatchpointHit().
uint32_t register_DBGDSCR;
asm("mrc p14, 0, %0, c0, c1, 0" : "=r" (register_DBGDSCR));
+ //printf("ClearWatchpointOccurred: register_DBGDSCR: 0x%x, bits(5, 2): 0x%x\n", register_DBGDSCR, bits(register_DBGDSCR, 5, 2));
if (bits(register_DBGDSCR, 5, 2) == WATCHPOINT_OCCURRED)
{
uint32_t mask = ~(0xF << 2);
register_DBGDSCR &= mask;
asm("mcr p14, 0, %0, c0, c1, 0" : "=r" (register_DBGDSCR));
+ //printf("ClearWatchpointOccurred: cleared bits(5,2) of register_DBGDSCR\n");
}
return;
}
@@ -2515,9 +2622,9 @@ DNBArchMachARM::ClearWatchpointOccurred()
bool
DNBArchMachARM::HasWatchpointOccurred()
{
- // See also IsWatchpointHit().
uint32_t register_DBGDSCR;
asm("mrc p14, 0, %0, c0, c1, 0" : "=r" (register_DBGDSCR));
+ //printf("HasWatchpointOccurred: register_DBGDSCR: 0x%x, bits(5, 2): 0x%x\n", register_DBGDSCR, bits(register_DBGDSCR, 5, 2));
return (bits(register_DBGDSCR, 5, 2) == WATCHPOINT_OCCURRED);
}
@@ -2539,8 +2646,9 @@ DNBArchMachARM::GetWatchAddress(const DBG &debug_state, uint32_t hw_index)
{
// Watchpoint Value Registers, bitfield definitions
// Bits Description
- // [31:2] Watchpoint address
- return bits(debug_state.__wvr[hw_index], 31, 2);
+ // [31:2] Watchpoint value (word address, i.e., 4-byte aligned)
+ // [1:0] RAZ/SBZP
+ return bits(debug_state.__wvr[hw_index], 31, 0);
}
//----------------------------------------------------------------------
diff --git a/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h b/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h
index d0f9ea75b64..4e1eeec6f72 100644
--- a/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h
+++ b/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h
@@ -35,7 +35,9 @@ public:
m_sw_single_step_next_pc(INVALID_NUB_ADDRESS),
m_sw_single_step_break_id(INVALID_NUB_BREAK_ID),
m_sw_single_step_itblock_break_count(0),
- m_last_decode_pc(INVALID_NUB_ADDRESS)
+ m_last_decode_pc(INVALID_NUB_ADDRESS),
+ m_watchpoint_hw_index(-1),
+ m_watchpoint_did_occur(false)
{
memset(&m_dbg_save, 0, sizeof(m_dbg_save));
#if defined (USE_ARM_DISASSEMBLER_FRAMEWORK)
@@ -78,6 +80,7 @@ public:
virtual uint32_t EnableHardwareBreakpoint (nub_addr_t addr, nub_size_t size);
virtual uint32_t EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool read, bool write);
virtual bool DisableHardwareBreakpoint (uint32_t hw_break_index);
+ virtual bool EnableHardwareWatchpoint (uint32_t hw_break_index);
virtual bool DisableHardwareWatchpoint (uint32_t hw_break_index);
virtual bool StepNotComplete ();
virtual void HardwareWatchpointStateChanged ();
@@ -258,6 +261,8 @@ protected:
arm_decoded_instruction_t m_last_decode_arm;
#endif
nub_addr_t m_last_decode_pc;
+ int32_t m_watchpoint_hw_index;
+ bool m_watchpoint_did_occur;
};
OpenPOWER on IntegriCloud