omjavaid updated this revision to Diff 357101.
omjavaid edited the summary of this revision.
omjavaid added a comment.

This adds pointer signing before we set watchpoint on the tagged_ptr. LLDB 
should be able to successfully set a watchpoint on a signed pointer. We can hit 
the watchpoint on tagged + signed pointer using variable but need to 
authenticate before increment using tagged pointer.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D101361/new/

https://reviews.llvm.org/D101361

Files:
  lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
  lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
  lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp
  lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.h
  lldb/source/Target/Target.cpp
  lldb/test/API/commands/watchpoints/watch_tagged_addr/Makefile
  lldb/test/API/commands/watchpoints/watch_tagged_addr/TestWatchTaggedAddress.py
  lldb/test/API/commands/watchpoints/watch_tagged_addr/main.c

Index: lldb/test/API/commands/watchpoints/watch_tagged_addr/main.c
===================================================================
--- /dev/null
+++ lldb/test/API/commands/watchpoints/watch_tagged_addr/main.c
@@ -0,0 +1,26 @@
+#include <stdint.h>
+
+uint32_t global_var = 0; // Watchpoint variable declaration.
+
+int main(int argc, char **argv) {
+  int dummy = 0;
+  // Move address of global variable into tagged_ptr after tagging
+  // Simple tagging scheme where 62nd bit of tagged address is set
+  uint32_t *tagged_ptr = (uint32_t *)((uint64_t)&global_var | (1ULL << 62));
+
+  __asm__ __volatile__("pacdza %0" : "=r"(tagged_ptr) : "r"(tagged_ptr));
+
+  ++dummy; // Set break point at this line.
+
+  // Increment global_var
+  ++global_var;
+
+  ++dummy;
+
+  __asm__ __volatile__("autdza %0" : "=r"(tagged_ptr) : "r"(tagged_ptr));
+
+  // Increment global_var using tagged_ptr
+  ++*tagged_ptr;
+
+  return 0;
+}
Index: lldb/test/API/commands/watchpoints/watch_tagged_addr/TestWatchTaggedAddress.py
===================================================================
--- /dev/null
+++ lldb/test/API/commands/watchpoints/watch_tagged_addr/TestWatchTaggedAddress.py
@@ -0,0 +1,135 @@
+"""
+Test LLDB can set and hit watchpoints on tagged addresses
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+class TestWatchTaggedAddresses(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+    NO_DEBUG_INFO_TESTCASE = True
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+
+        # Set source filename.
+        self.source = 'main.c'
+
+        # Invoke the default build rule.
+        self.build()
+
+        # Get the path of the executable
+        exe = self.getBuildArtifact("a.out")
+
+        # Create a target by the debugger.
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+
+    @skipIf(archs=no_match(["aarch64"]))
+    @skipIf(oslist=no_match(['linux']))
+    def test_watch_hit_tagged_ptr_access(self):
+        """
+        Test that LLDB hits watchpoint installed on an untagged address with
+        memory access by a tagged pointer.
+        """
+        if not self.isAArch64PAuth():
+            self.skipTest('Target must support pointer authentication.')
+
+        # Add a breakpoint to set a watchpoint when stopped on the breakpoint.
+        lldbutil.run_break_set_by_symbol(self, 'main')
+
+        # Run the program.
+        self.runCmd("run", RUN_SUCCEEDED)
+
+        # We should be stopped due to the breakpoint.
+        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+                    substrs=['stopped',
+                             'stop reason = breakpoint'])
+
+        # Set the watchpoint variable declaration line number.
+        self.decl = line_number(self.source,
+                                '// Watchpoint variable declaration.')
+
+        # Now let's set a watchpoint on 'global_var'.
+        self.expect(
+            "watchpoint set variable global_var",
+            WATCHPOINT_CREATED,
+            substrs=[
+                'Watchpoint created',
+                'size = 4',
+                'type = w',
+                '%s:%d' %
+                (self.source,
+                 self.decl)])
+
+        self.verify_watch_hits()
+
+    @skipIf(archs=no_match(["aarch64"]))
+    @skipIf(oslist=no_match(['linux']))
+    def test_watch_set_on_tagged_ptr(self):
+        """Test that LLDB can install and hit watchpoint on a tagged address"""
+
+        if not self.isAArch64PAuth():
+            self.skipTest('Target must support pointer authentication.')
+
+        # Find the line number to break inside main().
+        self.line = line_number(self.source, '// Set break point at this line.')
+
+        # Add a breakpoint to set a watchpoint when stopped on the breakpoint.
+        lldbutil.run_break_set_by_file_and_line(
+            self, None, self.line, num_expected_locations=1)
+
+        # Run the program.
+        self.runCmd("run", RUN_SUCCEEDED)
+
+        # We should be stopped due to the breakpoint.
+        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+                    substrs=['stopped',
+                             'stop reason = breakpoint'])
+
+        # Now let's set a expression watchpoint on 'tagged_ptr'.
+        self.expect(
+            "watchpoint set expression -s 4 -- tagged_ptr",
+            WATCHPOINT_CREATED,
+            substrs=[
+                'Watchpoint created',
+                'size = 4',
+                'type = w'])
+
+        self.verify_watch_hits()
+
+    def verify_watch_hits(self):
+        # Use the '-v' option to do verbose listing of the watchpoint.
+        # The hit count should be 0 initially.
+        self.expect("watchpoint list -v",
+                    substrs=['Number of supported hardware watchpoints:',
+                             'hit_count = 0'])
+
+        self.runCmd("process continue")
+
+        # We should be stopped again due to the watchpoint (read_write type).
+        # The stop reason of the thread should be watchpoint.
+        self.expect("thread backtrace", STOPPED_DUE_TO_WATCHPOINT,
+                    substrs=['stop reason = watchpoint'])
+
+        self.runCmd("process continue")
+
+        # We should be stopped again due to the watchpoint (read_write type).
+        # The stop reason of the thread should be watchpoint.
+        self.expect("thread backtrace", STOPPED_DUE_TO_WATCHPOINT,
+                    substrs=['stop reason = watchpoint'])
+
+        self.runCmd("process continue")
+
+        # There should be no more watchpoint hit and the process status should
+        # be 'exited'.
+        self.expect("process status",
+                    substrs=['exited'])
+
+        # Use the '-v' option to do verbose listing of the watchpoint.
+        # The hit count should now be 2.
+        self.expect("watchpoint list -v",
+                    substrs=['hit_count = 2'])
Index: lldb/test/API/commands/watchpoints/watch_tagged_addr/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/commands/watchpoints/watch_tagged_addr/Makefile
@@ -0,0 +1,5 @@
+C_SOURCES := main.c
+
+CFLAGS_EXTRAS := -march=armv8.3-a
+
+include Makefile.rules
Index: lldb/source/Target/Target.cpp
===================================================================
--- lldb/source/Target/Target.cpp
+++ lldb/source/Target/Target.cpp
@@ -41,6 +41,7 @@
 #include "lldb/Symbol/Function.h"
 #include "lldb/Symbol/ObjectFile.h"
 #include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/ABI.h"
 #include "lldb/Target/Language.h"
 #include "lldb/Target/LanguageRuntime.h"
 #include "lldb/Target/Process.h"
@@ -823,6 +824,11 @@
   // Grab the list mutex while doing operations.
   const bool notify = false; // Don't notify about all the state changes we do
                              // on creating the watchpoint.
+
+  // Mask off ignored bits from watchpoint address.
+  if (ABISP abi = m_process_sp->GetABI())
+    addr = abi->FixDataAddress(addr);
+
   std::unique_lock<std::recursive_mutex> lock;
   this->GetWatchpointList().GetListMutex(lock);
   WatchpointSP matched_sp = m_watchpoint_list.FindByAddress(addr);
Index: lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.h
===================================================================
--- lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.h
+++ lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.h
@@ -72,6 +72,9 @@
 
   virtual llvm::Error ReadHardwareDebugInfo() = 0;
   virtual llvm::Error WriteHardwareDebugRegs(DREGType hwbType) = 0;
+  virtual lldb::addr_t FixWatchpointHitAddress(lldb::addr_t hit_addr) {
+    return hit_addr;
+  }
 };
 
 } // namespace lldb_private
Index: lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp
===================================================================
--- lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp
+++ lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp
@@ -421,6 +421,9 @@
   if (error)
     return Status(std::move(error));
 
+  // Mask off ignored bits from watchpoint trap address.
+  trap_addr = FixWatchpointHitAddress(trap_addr);
+
   uint32_t watch_size;
   lldb::addr_t watch_addr;
 
Index: lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
===================================================================
--- lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
+++ lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
@@ -76,6 +76,8 @@
 
   size_t GetFPRSize() override { return sizeof(m_fpr); }
 
+  lldb::addr_t FixWatchpointHitAddress(lldb::addr_t hit_addr) override;
+
 private:
   bool m_gpr_is_valid;
   bool m_fpu_is_valid;
Index: lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
===================================================================
--- lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
+++ lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
@@ -892,4 +892,19 @@
                                  "Unknown AArch64 memory tag type %d", type);
 }
 
+lldb::addr_t NativeRegisterContextLinux_arm64::FixWatchpointHitAddress(
+    lldb::addr_t hit_addr) {
+  // Linux configures user-space virtual addresses with top byte ignored.
+  // We set default value of mask such that top byte is masked out.
+  lldb::addr_t mask = ~((1ULL << 56) - 1);
+
+  // Try to read pointer authentication data_mask register and calculate a
+  // consolidated data address mask after ignoring the top byte.
+  if (ReadPAuthMask().Success())
+    mask |= m_pac_mask.data_mask;
+
+  return hit_addr & ~mask;
+  ;
+}
+
 #endif // defined (__arm64__) || defined (__aarch64__)
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to