[Lldb-commits] [lldb] r296119 - Hardware breakpoints for Linux on Arm/AArch64 targets

Omair Javaid via lldb-commits lldb-commits at lists.llvm.org
Fri Feb 24 05:27:32 PST 2017


Author: omjavaid
Date: Fri Feb 24 07:27:31 2017
New Revision: 296119

URL: http://llvm.org/viewvc/llvm-project?rev=296119&view=rev
Log:
Hardware breakpoints for Linux on Arm/AArch64 targets

Please look at below differential link for upstream discussion.

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


Added:
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/hardware_breakpoints/
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/hardware_breakpoints/hardware_breakpoint_on_multiple_threads/
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/hardware_breakpoints/hardware_breakpoint_on_multiple_threads/Makefile
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/hardware_breakpoints/hardware_breakpoint_on_multiple_threads/TestHWBreakMultiThread.py
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/hardware_breakpoints/hardware_breakpoint_on_multiple_threads/main.cpp
Modified:
    lldb/trunk/include/lldb/Host/common/NativeBreakpointList.h
    lldb/trunk/include/lldb/Host/common/NativeProcessProtocol.h
    lldb/trunk/include/lldb/Host/common/NativeRegisterContext.h
    lldb/trunk/include/lldb/Host/common/NativeThreadProtocol.h
    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/TestLldbGdbServer.py
    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
    lldb/trunk/source/Host/common/NativeProcessProtocol.cpp
    lldb/trunk/source/Host/common/NativeRegisterContext.cpp
    lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
    lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h
    lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp
    lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h
    lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
    lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
    lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp
    lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp

Modified: lldb/trunk/include/lldb/Host/common/NativeBreakpointList.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Host/common/NativeBreakpointList.h?rev=296119&r1=296118&r2=296119&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Host/common/NativeBreakpointList.h (original)
+++ lldb/trunk/include/lldb/Host/common/NativeBreakpointList.h Fri Feb 24 07:27:31 2017
@@ -19,6 +19,14 @@
 #include <mutex>
 
 namespace lldb_private {
+
+struct HardwareBreakpoint {
+  lldb::addr_t m_addr;
+  size_t m_size;
+};
+
+using HardwareBreakpointMap = std::map<lldb::addr_t, HardwareBreakpoint>;
+
 class NativeBreakpointList {
 public:
   typedef std::function<Error(lldb::addr_t addr, size_t size_hint,

Modified: lldb/trunk/include/lldb/Host/common/NativeProcessProtocol.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Host/common/NativeProcessProtocol.h?rev=296119&r1=296118&r2=296119&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Host/common/NativeProcessProtocol.h (original)
+++ lldb/trunk/include/lldb/Host/common/NativeProcessProtocol.h Fri Feb 24 07:27:31 2017
@@ -107,18 +107,28 @@ public:
   virtual Error SetBreakpoint(lldb::addr_t addr, uint32_t size,
                               bool hardware) = 0;
 
-  virtual Error RemoveBreakpoint(lldb::addr_t addr);
+  virtual Error RemoveBreakpoint(lldb::addr_t addr, bool hardware = false);
 
   virtual Error EnableBreakpoint(lldb::addr_t addr);
 
   virtual Error DisableBreakpoint(lldb::addr_t addr);
 
   //----------------------------------------------------------------------
+  // Hardware Breakpoint functions
+  //----------------------------------------------------------------------
+  virtual const HardwareBreakpointMap &GetHardwareBreakpointMap() const;
+
+  virtual Error SetHardwareBreakpoint(lldb::addr_t addr, size_t size);
+
+  virtual Error RemoveHardwareBreakpoint(lldb::addr_t addr);
+
+  //----------------------------------------------------------------------
   // Watchpoint functions
   //----------------------------------------------------------------------
   virtual const NativeWatchpointList::WatchpointMap &GetWatchpointMap() const;
 
-  virtual uint32_t GetMaxWatchpoints() const;
+  virtual llvm::Optional<std::pair<uint32_t, uint32_t>>
+  GetHardwareDebugSupportInfo() const;
 
   virtual Error SetWatchpoint(lldb::addr_t addr, size_t size,
                               uint32_t watch_flags, bool hardware);
@@ -313,6 +323,7 @@ protected:
   std::vector<NativeDelegate *> m_delegates;
   NativeBreakpointList m_breakpoint_list;
   NativeWatchpointList m_watchpoint_list;
+  HardwareBreakpointMap m_hw_breakpoints_map;
   int m_terminal_fd;
   uint32_t m_stop_id;
 

Modified: lldb/trunk/include/lldb/Host/common/NativeRegisterContext.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Host/common/NativeRegisterContext.h?rev=296119&r1=296118&r2=296119&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Host/common/NativeRegisterContext.h (original)
+++ lldb/trunk/include/lldb/Host/common/NativeRegisterContext.h Fri Feb 24 07:27:31 2017
@@ -75,6 +75,11 @@ public:
 
   virtual bool ClearHardwareBreakpoint(uint32_t hw_idx);
 
+  virtual Error ClearAllHardwareBreakpoints();
+
+  virtual Error GetHardwareBreakHitIndex(uint32_t &bp_index,
+                                         lldb::addr_t trap_addr);
+
   virtual uint32_t NumSupportedHardwareWatchpoints();
 
   virtual uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size,

Modified: lldb/trunk/include/lldb/Host/common/NativeThreadProtocol.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Host/common/NativeThreadProtocol.h?rev=296119&r1=296118&r2=296119&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Host/common/NativeThreadProtocol.h (original)
+++ lldb/trunk/include/lldb/Host/common/NativeThreadProtocol.h Fri Feb 24 07:27:31 2017
@@ -56,6 +56,13 @@ public:
 
   virtual Error RemoveWatchpoint(lldb::addr_t addr) = 0;
 
+  // ---------------------------------------------------------------------
+  // Thread-specific Hardware Breakpoint routines
+  // ---------------------------------------------------------------------
+  virtual Error SetHardwareBreakpoint(lldb::addr_t addr, size_t size) = 0;
+
+  virtual Error RemoveHardwareBreakpoint(lldb::addr_t addr) = 0;
+
 protected:
   NativeProcessProtocolWP m_process_wp;
   lldb::tid_t m_tid;

Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/hardware_breakpoints/hardware_breakpoint_on_multiple_threads/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/hardware_breakpoints/hardware_breakpoint_on_multiple_threads/Makefile?rev=296119&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/hardware_breakpoints/hardware_breakpoint_on_multiple_threads/Makefile (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/hardware_breakpoints/hardware_breakpoint_on_multiple_threads/Makefile Fri Feb 24 07:27:31 2017
@@ -0,0 +1,6 @@
+LEVEL = ../../../../make
+
+ENABLE_THREADS := YES
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules

Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/hardware_breakpoints/hardware_breakpoint_on_multiple_threads/TestHWBreakMultiThread.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/hardware_breakpoints/hardware_breakpoint_on_multiple_threads/TestHWBreakMultiThread.py?rev=296119&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/hardware_breakpoints/hardware_breakpoint_on_multiple_threads/TestHWBreakMultiThread.py (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/hardware_breakpoints/hardware_breakpoint_on_multiple_threads/TestHWBreakMultiThread.py Fri Feb 24 07:27:31 2017
@@ -0,0 +1,114 @@
+"""
+Test hardware breakpoints for multiple threads.
+"""
+
+from __future__ import print_function
+
+
+import os
+import time
+import re
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+# Hardware breakpoints are supported only by platforms mentioned in oslist.
+ at skipUnlessPlatform(oslist=['linux'])
+class HardwareBreakpointMultiThreadTestCase(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    # LLDB supports hardware breakpoints for arm and aarch64 architectures.
+    @skipIf(archs=no_match(['arm', 'aarch64']))
+    @expectedFailureAndroid
+    def test_hw_break_set_delete_multi_thread(self):
+        self.build()
+        self.setTearDownCleanup() 
+        self.break_multi_thread('delete')
+
+    # LLDB supports hardware breakpoints for arm and aarch64 architectures.
+    @skipIf(archs=no_match(['arm', 'aarch64']))
+    @expectedFailureAndroid
+    def test_hw_break_set_disable_multi_thread(self):
+        self.build()
+        self.setTearDownCleanup() 
+        self.break_multi_thread('disable')
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+        # Our simple source filename.
+        self.source = 'main.cpp'
+        # Find the line number to break inside main().
+        self.first_stop = line_number(
+            self.source, 'Starting thread creation with hardware breakpoint set')
+
+    def break_multi_thread(self, removal_type):
+        """Test that lldb hardware breakpoints work for multiple threads."""
+        self.runCmd(
+            "file %s" %
+            os.path.join(
+                os.getcwd(),
+                'a.out'),
+            CURRENT_EXECUTABLE_SET)
+
+        # Stop in main before creating any threads.
+        lldbutil.run_break_set_by_file_and_line(
+            self, None, self.first_stop, num_expected_locations=1)
+
+        # Run the program.
+        self.runCmd("run", RUN_SUCCEEDED)
+
+        # We should be stopped again due to the breakpoint.
+        # The stop reason of the thread should be breakpoint.
+        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+                    substrs=['stopped',
+                             'stop reason = breakpoint'])
+
+        # Now set a hardware breakpoint in thread function.
+        self.expect("breakpoint set -b hw_break_function --hardware",
+            substrs=[
+                'Breakpoint',
+                'hw_break_function',
+                'address = 0x'])
+
+        # We should stop in hw_break_function function for 4 threads.
+        count = 0
+
+        while count < 2 :
+         
+            self.runCmd("process continue")
+
+            # We should be stopped in hw_break_function
+            # The stop reason of the thread should be breakpoint.
+            self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+                substrs=[
+                    'stop reason = breakpoint',
+                    'hw_break_function'])
+
+            # Continue the loop and test that we are stopped 4 times.
+            count += 1
+
+        if removal_type == 'delete':
+            self.runCmd("settings set auto-confirm true")
+
+            # Now 'breakpoint delete' should just work fine without confirmation
+            # prompt from the command interpreter.
+            self.expect("breakpoint delete",
+                        startstr="All breakpoints removed")
+
+            # Restore the original setting of auto-confirm.
+            self.runCmd("settings clear auto-confirm")
+
+        elif removal_type == 'disable':
+            self.expect("breakpoint disable",
+                        startstr="All breakpoints disabled.")
+
+        # Continue. Program should exit without stopping anywhere.
+        self.runCmd("process continue")
+
+        # Process should have stopped and exited with status = 0
+        self.expect("process status", PROCESS_STOPPED,
+                    patterns=['Process .* exited with status = 0'])

Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/hardware_breakpoints/hardware_breakpoint_on_multiple_threads/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/hardware_breakpoints/hardware_breakpoint_on_multiple_threads/main.cpp?rev=296119&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/hardware_breakpoints/hardware_breakpoint_on_multiple_threads/main.cpp (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/hardware_breakpoints/hardware_breakpoint_on_multiple_threads/main.cpp Fri Feb 24 07:27:31 2017
@@ -0,0 +1,51 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <chrono>
+#include <cstdio>
+#include <mutex>
+#include <random>
+#include <thread>
+
+#define NUM_OF_THREADS 4
+
+std::mutex hw_break_mutex;
+
+void
+hw_break_function (uint32_t thread_index) {
+  printf ("%s called by Thread #%u...\n", __FUNCTION__, thread_index);
+}
+
+
+void
+thread_func (uint32_t thread_index) {
+  printf ("%s (thread index = %u) starting...\n", __FUNCTION__, thread_index);
+
+  hw_break_mutex.lock();
+  
+  hw_break_function(thread_index); // Call hw_break_function
+
+  hw_break_mutex.unlock();
+}
+
+
+int main (int argc, char const *argv[])
+{
+  std::thread threads[NUM_OF_THREADS]; 
+
+  printf ("Starting thread creation with hardware breakpoint set...\n");
+
+  for (auto &thread : threads)
+    thread = std::thread{thread_func, std::distance(threads, &thread)};
+
+  for (auto &thread : threads)
+    thread.join();
+
+  return 0;
+}

Modified: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/TestLldbGdbServer.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/TestLldbGdbServer.py?rev=296119&r1=296118&r2=296119&view=diff
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/TestLldbGdbServer.py (original)
+++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/TestLldbGdbServer.py Fri Feb 24 07:27:31 2017
@@ -1082,7 +1082,7 @@ class LldbGdbServerTestCase(gdbremote_te
         self.set_inferior_startup_launch()
         self.qMemoryRegionInfo_reports_heap_address_as_readable_writeable()
 
-    def software_breakpoint_set_and_remove_work(self):
+    def breakpoint_set_and_remove_work(self, want_hardware=False):
         # Start up the inferior.
         procs = self.prep_debug_monitor_and_inferior(
             inferior_args=[
@@ -1126,15 +1126,27 @@ class LldbGdbServerTestCase(gdbremote_te
         self.assertIsNotNone(context.get("function_address"))
         function_address = int(context.get("function_address"), 16)
 
+        # Get current target architecture
+        target_arch = self.getArchitecture()
+
         # Set the breakpoint.
-        if self.getArchitecture() == "arm":
+        if (target_arch == "arm") or (target_arch == "aarch64"):
             # TODO: Handle case when setting breakpoint in thumb code
             BREAKPOINT_KIND = 4
         else:
             BREAKPOINT_KIND = 1
+
+        # Set default packet type to Z0 (software breakpoint)
+        z_packet_type = 0       
+
+        # If hardware breakpoint is requested set packet type to Z1
+        if want_hardware == True:
+            z_packet_type = 1
+
         self.reset_test_sequence()
         self.add_set_breakpoint_packets(
             function_address,
+            z_packet_type,
             do_continue=True,
             breakpoint_kind=BREAKPOINT_KIND)
 
@@ -1182,13 +1194,15 @@ class LldbGdbServerTestCase(gdbremote_te
         # Verify that a breakpoint remove and continue gets us the expected
         # output.
         self.reset_test_sequence()
+
+        # Add breakpoint remove packets
+        self.add_remove_breakpoint_packets(
+            function_address,
+            z_packet_type,
+            breakpoint_kind=BREAKPOINT_KIND)
+
         self.test_sequence.add_log_lines(
             [
-                # Remove the breakpoint.
-                "read packet: $z0,{0:x},{1}#00".format(
-                    function_address, BREAKPOINT_KIND),
-                # Verify the stub could unset it.
-                "send packet: $OK#00",
                 # Continue running.
                 "read packet: $c#63",
                 # We should now receive the output from the call.
@@ -1209,7 +1223,7 @@ class LldbGdbServerTestCase(gdbremote_te
         else:
             self.build()
         self.set_inferior_startup_launch()
-        self.software_breakpoint_set_and_remove_work()
+        self.breakpoint_set_and_remove_work(want_hardware=False)
 
     @llgs_test
     @expectedFlakeyLinux("llvm.org/pr25652")
@@ -1221,7 +1235,35 @@ class LldbGdbServerTestCase(gdbremote_te
         else:
             self.build()
         self.set_inferior_startup_launch()
-        self.software_breakpoint_set_and_remove_work()
+        self.breakpoint_set_and_remove_work(want_hardware=False)
+
+    @debugserver_test
+    @skipUnlessPlatform(oslist=['linux'])
+    @expectedFailureAndroid
+    @skipIf(archs=no_match(['arm', 'aarch64']))
+    def test_hardware_breakpoint_set_and_remove_work_debugserver(self):
+        self.init_debugserver_test()
+        if self.getArchitecture() == "arm":
+            # TODO: Handle case when setting breakpoint in thumb code
+            self.build(dictionary={'CFLAGS_EXTRAS': '-marm'})
+        else:
+            self.build()
+        self.set_inferior_startup_launch()
+        self.breakpoint_set_and_remove_work(want_hardware=True)
+
+    @llgs_test
+    @skipUnlessPlatform(oslist=['linux'])
+    @expectedFailureAndroid
+    @skipIf(archs=no_match(['arm', 'aarch64']))
+    def test_hardware_breakpoint_set_and_remove_work_llgs(self):
+        self.init_llgs_test()
+        if self.getArchitecture() == "arm":
+            # TODO: Handle case when setting breakpoint in thumb code
+            self.build(dictionary={'CFLAGS_EXTRAS': '-marm'})
+        else:
+            self.build()
+        self.set_inferior_startup_launch()
+        self.breakpoint_set_and_remove_work(want_hardware=True)
 
     def qSupported_returns_known_stub_features(self):
         # Start up the stub and start/prep the inferior.

Modified: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py?rev=296119&r1=296118&r2=296119&view=diff
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py (original)
+++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py Fri Feb 24 07:27:31 2017
@@ -883,12 +883,13 @@ class GdbRemoteTestCaseBase(TestBase):
     def add_set_breakpoint_packets(
             self,
             address,
+            z_packet_type=0,
             do_continue=True,
             breakpoint_kind=1):
         self.test_sequence.add_log_lines(
             [  # Set the breakpoint.
-                "read packet: $Z0,{0:x},{1}#00".format(
-                    address, breakpoint_kind),
+                "read packet: $Z{2},{0:x},{1}#00".format(
+                    address, breakpoint_kind, z_packet_type),
                 # Verify the stub could set it.
                 "send packet: $OK#00",
             ], True)
@@ -904,11 +905,15 @@ class GdbRemoteTestCaseBase(TestBase):
                                  2: "stop_thread_id"}},
                 ], True)
 
-    def add_remove_breakpoint_packets(self, address, breakpoint_kind=1):
+    def add_remove_breakpoint_packets(
+            self,
+            address,
+            z_packet_type=0,
+            breakpoint_kind=1):
         self.test_sequence.add_log_lines(
             [  # Remove the breakpoint.
-                "read packet: $z0,{0:x},{1}#00".format(
-                    address, breakpoint_kind),
+                "read packet: $z{2},{0:x},{1}#00".format(
+                    address, breakpoint_kind, z_packet_type),
                 # Verify the stub could unset it.
                 "send packet: $OK#00",
             ], True)

Modified: lldb/trunk/source/Host/common/NativeProcessProtocol.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/NativeProcessProtocol.cpp?rev=296119&r1=296118&r2=296119&view=diff
==============================================================================
--- lldb/trunk/source/Host/common/NativeProcessProtocol.cpp (original)
+++ lldb/trunk/source/Host/common/NativeProcessProtocol.cpp Fri Feb 24 07:27:31 2017
@@ -145,11 +145,8 @@ NativeProcessProtocol::GetWatchpointMap(
   return m_watchpoint_list.GetWatchpointMap();
 }
 
-uint32_t NativeProcessProtocol::GetMaxWatchpoints() const {
-  // This default implementation will return the number of
-  // *hardware* breakpoints available.  MacOSX and other OS
-  // implementations that support software breakpoints will want to
-  // override this correctly for their implementation.
+llvm::Optional<std::pair<uint32_t, uint32_t>>
+NativeProcessProtocol::GetHardwareDebugSupportInfo() const {
   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
 
   // get any thread
@@ -160,7 +157,7 @@ uint32_t NativeProcessProtocol::GetMaxWa
       log->Warning("NativeProcessProtocol::%s (): failed to find a thread to "
                    "grab a NativeRegisterContext!",
                    __FUNCTION__);
-    return 0;
+    return llvm::None;
   }
 
   NativeRegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
@@ -169,10 +166,11 @@ uint32_t NativeProcessProtocol::GetMaxWa
       log->Warning("NativeProcessProtocol::%s (): failed to get a "
                    "RegisterContextNativeProcess from the first thread!",
                    __FUNCTION__);
-    return 0;
+    return llvm::None;
   }
 
-  return reg_ctx_sp->NumSupportedHardwareWatchpoints();
+  return std::make_pair(reg_ctx_sp->NumSupportedHardwareBreakpoints(),
+                        reg_ctx_sp->NumSupportedHardwareWatchpoints());
 }
 
 Error NativeProcessProtocol::SetWatchpoint(lldb::addr_t addr, size_t size,
@@ -269,6 +267,92 @@ Error NativeProcessProtocol::RemoveWatch
   return overall_error.Fail() ? overall_error : error;
 }
 
+const HardwareBreakpointMap &
+NativeProcessProtocol::GetHardwareBreakpointMap() const {
+  return m_hw_breakpoints_map;
+}
+
+Error NativeProcessProtocol::SetHardwareBreakpoint(lldb::addr_t addr,
+                                                   size_t size) {
+  // This default implementation assumes setting a hardware breakpoint for
+  // this process will require setting same hardware breakpoint for each
+  // of its existing threads. New thread will do the same once created.
+  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+  // Update the thread list
+  UpdateThreads();
+
+  // Exit here if target does not have required hardware breakpoint capability.
+  auto hw_debug_cap = GetHardwareDebugSupportInfo();
+
+  if (hw_debug_cap == llvm::None || hw_debug_cap->first == 0 ||
+      hw_debug_cap->first <= m_hw_breakpoints_map.size())
+    return Error("Target does not have required no of hardware breakpoints");
+
+  // Vector below stores all thread pointer for which we have we successfully
+  // set this hardware breakpoint. If any of the current process threads fails
+  // to set this hardware breakpoint then roll back and remove this breakpoint
+  // for all the threads that had already set it successfully.
+  std::vector<NativeThreadProtocolSP> breakpoint_established_threads;
+
+  // Request to set a hardware breakpoint for each of current process threads.
+  std::lock_guard<std::recursive_mutex> guard(m_threads_mutex);
+  for (auto thread_sp : m_threads) {
+    assert(thread_sp && "thread list should not have a NULL thread!");
+    if (!thread_sp)
+      continue;
+
+    Error thread_error = thread_sp->SetHardwareBreakpoint(addr, size);
+    if (thread_error.Success()) {
+      // Remember that we set this breakpoint successfully in
+      // case we need to clear it later.
+      breakpoint_established_threads.push_back(thread_sp);
+    } else {
+      // Unset the breakpoint for each thread we successfully
+      // set so that we get back to a consistent state of "not
+      // set" for this hardware breakpoint.
+      for (auto rollback_thread_sp : breakpoint_established_threads) {
+        Error remove_error = rollback_thread_sp->RemoveHardwareBreakpoint(addr);
+        if (remove_error.Fail() && log) {
+          log->Warning("NativeProcessProtocol::%s (): RemoveHardwareBreakpoint"
+                       " failed for pid=%" PRIu64 ", tid=%" PRIu64 ": %s",
+                       __FUNCTION__, GetID(), rollback_thread_sp->GetID(),
+                       remove_error.AsCString());
+        }
+      }
+
+      return thread_error;
+    }
+  }
+
+  // Register new hardware breakpoint into hardware breakpoints map of current
+  // process.
+  m_hw_breakpoints_map[addr] = {addr, size};
+
+  return Error();
+}
+
+Error NativeProcessProtocol::RemoveHardwareBreakpoint(lldb::addr_t addr) {
+  // Update the thread list
+  UpdateThreads();
+
+  Error error;
+
+  std::lock_guard<std::recursive_mutex> guard(m_threads_mutex);
+  for (auto thread_sp : m_threads) {
+    assert(thread_sp && "thread list should not have a NULL thread!");
+    if (!thread_sp)
+      continue;
+
+    error = thread_sp->RemoveHardwareBreakpoint(addr);
+  }
+
+  // Also remove from hardware breakpoint map of current process.
+  m_hw_breakpoints_map.erase(addr);
+
+  return error;
+}
+
 bool NativeProcessProtocol::RegisterNativeDelegate(
     NativeDelegate &native_delegate) {
   std::lock_guard<std::recursive_mutex> guard(m_delegates_mutex);
@@ -345,8 +429,12 @@ Error NativeProcessProtocol::SetSoftware
       });
 }
 
-Error NativeProcessProtocol::RemoveBreakpoint(lldb::addr_t addr) {
-  return m_breakpoint_list.DecRef(addr);
+Error NativeProcessProtocol::RemoveBreakpoint(lldb::addr_t addr,
+                                              bool hardware) {
+  if (hardware)
+    return RemoveHardwareBreakpoint(addr);
+  else
+    return m_breakpoint_list.DecRef(addr);
 }
 
 Error NativeProcessProtocol::EnableBreakpoint(lldb::addr_t addr) {

Modified: lldb/trunk/source/Host/common/NativeRegisterContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/NativeRegisterContext.cpp?rev=296119&r1=296118&r2=296119&view=diff
==============================================================================
--- lldb/trunk/source/Host/common/NativeRegisterContext.cpp (original)
+++ lldb/trunk/source/Host/common/NativeRegisterContext.cpp Fri Feb 24 07:27:31 2017
@@ -246,10 +246,20 @@ uint32_t NativeRegisterContext::SetHardw
   return LLDB_INVALID_INDEX32;
 }
 
+Error NativeRegisterContext::ClearAllHardwareBreakpoints() {
+  return Error("not implemented");
+}
+
 bool NativeRegisterContext::ClearHardwareBreakpoint(uint32_t hw_idx) {
   return false;
 }
 
+Error NativeRegisterContext::GetHardwareBreakHitIndex(uint32_t &bp_index,
+                                                      lldb::addr_t trap_addr) {
+  bp_index = LLDB_INVALID_INDEX32;
+  return Error("not implemented");
+}
+
 uint32_t NativeRegisterContext::NumSupportedHardwareWatchpoints() { return 0; }
 
 uint32_t NativeRegisterContext::SetHardwareWatchpoint(lldb::addr_t addr,

Modified: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp?rev=296119&r1=296118&r2=296119&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp Fri Feb 24 07:27:31 2017
@@ -870,6 +870,19 @@ void NativeProcessLinux::MonitorSIGTRAP(
       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::GetSoftwareBre
 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) {

Modified: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h?rev=296119&r1=296118&r2=296119&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h Fri Feb 24 07:27:31 2017
@@ -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,

Modified: lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp?rev=296119&r1=296118&r2=296119&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp Fri Feb 24 07:27:31 2017
@@ -130,6 +130,7 @@ NativeRegisterContextLinux_arm::NativeRe
   ::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::IsF
   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::SetHardw
 
   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;
-
-    // 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;
+  // 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;
 
-      return LLDB_INVALID_INDEX32;
-    }
-  } else
-    m_hbr_regs[bp_index].refcount++;
+  // 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;
+
+    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::Cle
   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;
-
-    m_hbr_regs[hw_idx].control &= ~1;
-    m_hbr_regs[hw_idx].address = 0;
-    m_hbr_regs[hw_idx].refcount = 0;
-
-    // PTRACE call to clear corresponding hardware breakpoint register.
-    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;
+  // 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, hw_idx);
+
+  if (error.Fail()) {
+    m_hbr_regs[hw_idx].control = tempControl;
+    m_hbr_regs[hw_idx].address = tempAddr;
+
+    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__);
 
-      return false;
+  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::Wr
         (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(),

Modified: lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h?rev=296119&r1=296118&r2=296119&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h Fri Feb 24 07:27:31 2017
@@ -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,

Modified: lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp?rev=296119&r1=296118&r2=296119&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp Fri Feb 24 07:27:31 2017
@@ -153,6 +153,7 @@ NativeRegisterContextLinux_arm64::Native
   ::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::I
   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::SetHar
   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;
-
-    // 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;
+  // 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);
+
+  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::C
   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;
-
-    m_hbr_regs[hw_idx].control &= ~1;
-    m_hbr_regs[hw_idx].address = 0;
-    m_hbr_regs[hw_idx].refcount = 0;
-
-    // PTRACE call to clear corresponding hardware breakpoint register.
-    WriteHardwareDebugRegs(eDREGTypeBREAK);
-
-    if (error.Fail()) {
-      m_hbr_regs[hw_idx].control = tempControl;
-      m_hbr_regs[hw_idx].address = tempAddr;
-      m_hbr_regs[hw_idx].refcount = tempRefCount;
+  // 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));
+
+  if (log)
+    log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
 
-      return false;
+  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();
     }
+  }
+
+  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;
 
-    return true;
+  // 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() {

Modified: lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h?rev=296119&r1=296118&r2=296119&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h Fri Feb 24 07:27:31 2017
@@ -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,

Modified: lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp?rev=296119&r1=296118&r2=296119&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp Fri Feb 24 07:27:31 2017
@@ -190,6 +190,38 @@ Error NativeThreadLinux::RemoveWatchpoin
   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
     }
   }
 
+  // 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)

Modified: lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h?rev=296119&r1=296118&r2=296119&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h Fri Feb 24 07:27:31 2017
@@ -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;
 };
 

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp?rev=296119&r1=296118&r2=296119&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp Fri Feb 24 07:27:31 2017
@@ -2534,12 +2534,14 @@ GDBRemoteCommunicationServerLLGS::Handle
         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
 
   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
   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());
 }
 




More information about the lldb-commits mailing list