[Lldb-commits] [lldb] r153228 - in /lldb/trunk/tools/debugserver/source/MacOSX/arm: DNBArchImpl.cpp DNBArchImpl.h
Johnny Chen
johnny.chen at apple.com
Wed Mar 21 17:08:14 PDT 2012
Author: johnny
Date: Wed Mar 21 19:08:13 2012
New Revision: 153228
URL: http://llvm.org/viewvc/llvm-project?rev=153228&view=rev
Log:
WIP snapshot of hardware watchpoints for arm. A simple watchpoint has triggered.
However, the debugserver cannot get past the instruction which triggered the watchpoint.
So a workaround is in place for the time being which disables the triggered watchpoint
before resuming.
Lots of commented out printf's remain in the source which needs to be cleaned up.
WIP rdar://problem/9667960
Modified:
lldb/trunk/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp
lldb/trunk/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h
Modified: lldb/trunk/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp?rev=153228&r1=153227&r2=153228&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp (original)
+++ lldb/trunk/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp Wed Mar 21 19:08:13 2012
@@ -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 @@
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 @@
}
}
- // 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 @@
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 @@
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 @@
}
}
}
+ //printf("g_num_supported_hw_watchpoints=%u\n", g_num_supported_hw_watchpoints);
return g_num_supported_hw_watchpoints;
}
@@ -2333,6 +2365,7 @@
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 @@
// 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 @@
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 @@
}
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 @@
{
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 @@
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 @@
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 @@
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 @@
{
// 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);
}
//----------------------------------------------------------------------
Modified: lldb/trunk/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h?rev=153228&r1=153227&r2=153228&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h (original)
+++ lldb/trunk/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h Wed Mar 21 19:08:13 2012
@@ -35,7 +35,9 @@
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 @@
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 @@
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;
};
More information about the lldb-commits
mailing list