[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