[lldb/Breakpoint] Recogize hardware breakpoints as such
authorJonas Devlieghere <jonas@devlieghere.com>
Sat, 25 Jan 2020 02:49:44 +0000 (18:49 -0800)
committerJonas Devlieghere <jonas@devlieghere.com>
Sat, 25 Jan 2020 03:24:25 +0000 (19:24 -0800)
Recognize hardware breakpoints as breakpoints instead of just mach
exceptions. The mach exception is the same for watch and breakpoints, so
we have to try each to figure out which is which.

Differential revision: https://reviews.llvm.org/D73401

lldb/include/lldb/Breakpoint/BreakpointSite.h
lldb/include/lldb/Breakpoint/StoppointLocation.h
lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/hardware_breakpoints/hardware_breakpoint_on_multiple_threads/TestHWBreakMultiThread.py
lldb/source/Breakpoint/BreakpointSite.cpp
lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp

index 5c9f79a..eef2e29 100644 (file)
@@ -61,6 +61,8 @@ public:
   /// Sets the trap opcode
   bool SetTrapOpcode(const uint8_t *trap_opcode, uint32_t trap_opcode_size);
 
+  void SetHardwareIndex(uint32_t index) override;
+
   /// Gets the original instruction bytes that were overwritten by the trap
   uint8_t *GetSavedOpcodeBytes();
 
index 3926f45..3c22813 100644 (file)
@@ -48,7 +48,7 @@ public:
 
   virtual void Dump(Stream *stream) const {}
 
-  void SetHardwareIndex(uint32_t index) { m_hardware_index = index; }
+  virtual void SetHardwareIndex(uint32_t index) { m_hardware_index = index; }
 
   lldb::break_id_t GetID() const { return m_loc_id; }
 
index 16c63b9..0ea8e04 100644 (file)
@@ -21,7 +21,7 @@ class HardwareBreakpointMultiThreadTestCase(TestBase):
     def test_hw_break_set_delete_multi_thread_linux(self):
         self.build()
         self.setTearDownCleanup()
-        self.break_multi_thread('delete', 'breakpoint')
+        self.break_multi_thread('delete')
 
     # LLDB on linux supports hardware breakpoints for arm and aarch64
     # architectures.
@@ -30,7 +30,7 @@ class HardwareBreakpointMultiThreadTestCase(TestBase):
     def test_hw_break_set_disable_multi_thread_linux(self):
         self.build()
         self.setTearDownCleanup()
-        self.break_multi_thread('disable', 'breakpoint')
+        self.break_multi_thread('disable')
 
     # LLDB on darwin supports hardware breakpoints for arm, aarch64, x86_64 and
     # i386 architectures.
@@ -39,7 +39,7 @@ class HardwareBreakpointMultiThreadTestCase(TestBase):
     def test_hw_break_set_delete_multi_thread_macos(self):
         self.build()
         self.setTearDownCleanup()
-        self.break_multi_thread('delete', 'EXC_BREAKPOINT')
+        self.break_multi_thread('delete')
 
     # LLDB on darwin supports hardware breakpoints for arm, aarch64, x86_64 and
     # i386 architectures.
@@ -48,7 +48,7 @@ class HardwareBreakpointMultiThreadTestCase(TestBase):
     def test_hw_break_set_disable_multi_thread_macos(self):
         self.build()
         self.setTearDownCleanup()
-        self.break_multi_thread('disable', 'EXC_BREAKPOINT')
+        self.break_multi_thread('disable')
 
 
     def setUp(self):
@@ -60,7 +60,7 @@ class HardwareBreakpointMultiThreadTestCase(TestBase):
         self.first_stop = line_number(
             self.source, 'Starting thread creation with hardware breakpoint set')
 
-    def break_multi_thread(self, removal_type, stop_reason):
+    def break_multi_thread(self, removal_type):
         """Test that lldb hardware breakpoints work for multiple threads."""
         self.runCmd("file " + self.getBuildArtifact("a.out"),
                     CURRENT_EXECUTABLE_SET)
@@ -95,7 +95,7 @@ class HardwareBreakpointMultiThreadTestCase(TestBase):
             # The stop reason of the thread should be breakpoint.
             self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
                 substrs=[
-                    'stop reason = {}'.format(stop_reason),
+                    'stop reason = breakpoint',
                     'hw_break_function'])
 
             # Continue the loop and test that we are stopped 4 times.
index 7ffbe28..a33fd0a 100644 (file)
@@ -156,6 +156,13 @@ void BreakpointSite::BumpHitCounts() {
   }
 }
 
+void BreakpointSite::SetHardwareIndex(uint32_t index) {
+  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
+  for (BreakpointLocationSP loc_sp : m_owners.BreakpointLocations()) {
+    loc_sp->SetHardwareIndex(index);
+  }
+}
+
 bool BreakpointSite::IntersectsRange(lldb::addr_t addr, size_t size,
                                      lldb::addr_t *intersect_addr,
                                      size_t *intersect_size,
index c619416..7331fc1 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "StopInfoMachException.h"
 
+#include "lldb/lldb-forward.h"
 
 #if defined(__APPLE__)
 // Needed for the EXC_RESOURCE interpretation macros
@@ -293,6 +294,44 @@ const char *StopInfoMachException::GetDescription() {
   return m_description.c_str();
 }
 
+static StopInfoSP GetStopInfoForHardwareBP(Thread &thread, Target *target,
+                                           uint32_t exc_data_count,
+                                           uint64_t exc_sub_code,
+                                           uint64_t exc_sub_sub_code) {
+  // Try hardware watchpoint.
+  if (target) {
+    // The exc_sub_code indicates the data break address.
+    lldb::WatchpointSP wp_sp =
+        target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code);
+    if (wp_sp && wp_sp->IsEnabled()) {
+      // Debugserver may piggyback the hardware index of the fired watchpoint
+      // in the exception data. Set the hardware index if that's the case.
+      if (exc_data_count >= 3)
+        wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
+      return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID());
+    }
+  }
+
+  // Try hardware breakpoint.
+  ProcessSP process_sp(thread.GetProcess());
+  if (process_sp) {
+    // The exc_sub_code indicates the data break address.
+    lldb::BreakpointSiteSP bp_sp =
+        process_sp->GetBreakpointSiteList().FindByAddress(
+            (lldb::addr_t)exc_sub_code);
+    if (bp_sp && bp_sp->IsEnabled()) {
+      // Debugserver may piggyback the hardware index of the fired breakpoint
+      // in the exception data. Set the hardware index if that's the case.
+      if (exc_data_count >= 3)
+        bp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
+      return StopInfo::CreateStopReasonWithBreakpointSiteID(thread,
+                                                            bp_sp->GetID());
+    }
+  }
+
+  return nullptr;
+}
+
 StopInfoSP StopInfoMachException::CreateStopReasonWithMachException(
     Thread &thread, uint32_t exc_type, uint32_t exc_data_count,
     uint64_t exc_code, uint64_t exc_sub_code, uint64_t exc_sub_sub_code,
@@ -350,22 +389,10 @@ StopInfoSP StopInfoMachException::CreateStopReasonWithMachException(
           is_actual_breakpoint = true;
           is_trace_if_actual_breakpoint_missing = true;
         } else {
-
-          // It's a watchpoint, then.
-          // The exc_sub_code indicates the data break address.
-          lldb::WatchpointSP wp_sp;
-          if (target)
-            wp_sp = target->GetWatchpointList().FindByAddress(
-                (lldb::addr_t)exc_sub_code);
-          if (wp_sp && wp_sp->IsEnabled()) {
-            // Debugserver may piggyback the hardware index of the fired
-            // watchpoint in the exception data. Set the hardware index if
-            // that's the case.
-            if (exc_data_count >= 3)
-              wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
-            return StopInfo::CreateStopReasonWithWatchpointID(thread,
-                                                              wp_sp->GetID());
-          }
+          if (StopInfoSP stop_info =
+                  GetStopInfoForHardwareBP(thread, target, exc_data_count,
+                                           exc_sub_code, exc_sub_sub_code))
+            return stop_info;
         }
       } else if (exc_code == 2 || // EXC_I386_BPT
                  exc_code == 3)   // EXC_I386_BPTFLT