DavidSpickett created this revision.
Herald added subscribers: danielkiss, kristof.beyls.
DavidSpickett requested review of this revision.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

In the latest Linux kernels synchronous tag faults
include the tag bits in their address.

Programs must enable the tagged address ABI to
receive these signals and are also opting into the
presence of these tag bits.
(asynchronous faults have no address)

Add logical and allocation tags to the description
of synchronous tag faults.

Process 1626 stopped

- thread #1, name = 'a.out', stop reason = signal SIGSEGV: sync tag check fault 
(fault address: 0x900fffff7ff9010 logical tag: 0x9 allocation tag: 0x0)

This extends the existing description and will
show as much as it can on the rare occasion something
fails.

This change supports AArch64 MTE only but other
architectures could be added by extending the
switch at the start of AnnotateSyncTagCheckFault.
The rest of the function is generic code.

Tests have been added for synchronous and asynchronous
MTE faults.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D105178

Files:
  lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
  lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
  lldb/test/API/linux/aarch64/mte_tag_faults/Makefile
  
lldb/test/API/linux/aarch64/mte_tag_faults/TestAArch64LinuxMTEMemoryTagFaults.py
  lldb/test/API/linux/aarch64/mte_tag_faults/main.c

Index: lldb/test/API/linux/aarch64/mte_tag_faults/main.c
===================================================================
--- /dev/null
+++ lldb/test/API/linux/aarch64/mte_tag_faults/main.c
@@ -0,0 +1,49 @@
+#include <arm_acle.h>
+#include <asm/hwcap.h>
+#include <asm/mman.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/auxv.h>
+#include <sys/mman.h>
+#include <sys/prctl.h>
+#include <unistd.h>
+
+int main(int argc, char const *argv[]) {
+  // We assume that the test runner has checked we're on an MTE system
+
+  // Only expect to get the fault type
+  if (argc != 2)
+    return 1;
+
+  // Tagged address ABI also enables MTE faults
+  // Allow tags 9 and 10 to be generated
+  unsigned long prctl_arg2 =
+      PR_TAGGED_ADDR_ENABLE | ((3 << 9) << PR_MTE_TAG_SHIFT);
+  if (!strcmp(argv[1], "sync"))
+    prctl_arg2 |= PR_MTE_TCF_SYNC;
+  else if (!strcmp(argv[1], "async"))
+    prctl_arg2 |= PR_MTE_TCF_ASYNC;
+  else
+    return 1;
+
+  if (prctl(PR_SET_TAGGED_ADDR_CTRL, prctl_arg2, 0, 0, 0))
+    return 1;
+
+  char *buf = mmap(0, sysconf(_SC_PAGESIZE), PROT_MTE | PROT_READ | PROT_WRITE,
+                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  if (buf == MAP_FAILED)
+    return 1;
+
+  // Tag ptr with 10
+  char *tagged_buf = __arm_mte_create_random_tag(buf, 1 << 9);
+  // Set first allocation tag to 10
+  __arm_mte_set_tag(tagged_buf);
+  // Retag the pointer with 9
+  tagged_buf = __arm_mte_create_random_tag(buf, 1 << 10);
+
+  // Breakpoint here
+  // Faults, 9 != 10
+  *(tagged_buf) = '?';
+
+  return 0;
+}
Index: lldb/test/API/linux/aarch64/mte_tag_faults/TestAArch64LinuxMTEMemoryTagFaults.py
===================================================================
--- /dev/null
+++ lldb/test/API/linux/aarch64/mte_tag_faults/TestAArch64LinuxMTEMemoryTagFaults.py
@@ -0,0 +1,59 @@
+"""
+Test reporting of MTE tag access faults.
+"""
+
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class AArch64LinuxMTEMemoryTagFaultsTestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    NO_DEBUG_INFO_TESTCASE = True
+
+    def setup_mte_test(self, fault_type):
+        if not self.isAArch64MTE():
+            self.skipTest('Target must support MTE.')
+
+        self.build()
+        self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
+
+        lldbutil.run_break_set_by_file_and_line(self, "main.c",
+            line_number('main.c', '// Breakpoint here'),
+            num_expected_locations=1)
+
+        self.runCmd("run {}".format(fault_type), RUN_SUCCEEDED)
+
+        if self.process().GetState() == lldb.eStateExited:
+            self.fail("Test program failed to run.")
+
+        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+            substrs=['stopped',
+                     'stop reason = breakpoint'])
+
+    @skipUnlessArch("aarch64")
+    @skipUnlessPlatform(["linux"])
+    @skipUnlessAArch64MTELinuxCompiler
+    def test_mte_tag_fault_sync(self):
+        self.setup_mte_test("sync")
+        # The logical tag should be included in the fault address
+        # and we know what the bottom byte should be.
+        self.expect("continue",
+                patterns=[
+                "\* thread #1, name = 'a.out', stop reason = signal SIGSEGV: "
+                "sync tag check fault \(fault address: 0x9[0-9A-Fa-f]+00\ "
+                "logical tag: 0x9 allocation tag: 0xa\)"])
+
+    @skipUnlessArch("aarch64")
+    @skipUnlessPlatform(["linux"])
+    @skipUnlessAArch64MTELinuxCompiler
+    def test_mte_tag_fault_async(self):
+        self.setup_mte_test("async")
+        self.expect("continue",
+                substrs=[
+                    "* thread #1, name = 'a.out', stop reason = "
+                    "signal SIGSEGV: async tag check fault"])
Index: lldb/test/API/linux/aarch64/mte_tag_faults/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/linux/aarch64/mte_tag_faults/Makefile
@@ -0,0 +1,4 @@
+C_SOURCES := main.c
+CFLAGS_EXTRAS := -march=armv8.5-a+memtag
+
+include Makefile.rules
Index: lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
===================================================================
--- lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
+++ lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
@@ -102,6 +102,11 @@
 
   void SetStopped();
 
+  /// Extend m_stop_description with logical and allocation tag values.
+  /// If there is an error along the way just add the information we were able
+  /// to get.
+  void AnnotateSyncTagCheckFault(const siginfo_t *info);
+
   // Member Variables
   lldb::StateType m_state;
   ThreadStopInfo m_stop_info;
Index: lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
===================================================================
--- lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
+++ lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
@@ -26,6 +26,7 @@
 #include "llvm/ADT/SmallString.h"
 
 #include "Plugins/Process/POSIX/CrashReason.h"
+#include "Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h"
 
 #include <sys/syscall.h>
 // Try to define a macro to encapsulate the tgkill syscall
@@ -299,11 +300,66 @@
               ? CrashReason::eInvalidAddress
               : GetCrashReason(*info);
       m_stop_description = GetCrashReasonString(reason, *info);
+
+      if (reason == CrashReason::eSyncTagCheckFault) {
+        AnnotateSyncTagCheckFault(info);
+      }
+
       break;
     }
   }
 }
 
+void NativeThreadLinux::AnnotateSyncTagCheckFault(const siginfo_t *info) {
+  int32_t allocation_tag_type = 0;
+  switch (GetProcess().GetArchitecture().GetMachine()) {
+  // aarch64_32 deliberately not here because there's no 32 bit MTE
+  case llvm::Triple::aarch64:
+  case llvm::Triple::aarch64_be:
+    allocation_tag_type = MemoryTagManagerAArch64MTE::eMTE_allocation;
+    break;
+  default:
+    return;
+  }
+
+  auto details =
+      GetRegisterContext().GetMemoryTaggingDetails(allocation_tag_type);
+  if (!details) {
+    llvm::consumeError(details.takeError());
+    return;
+  }
+
+  // We assume that the stop description is currently:
+  // signal SIGSEGV: sync tag check fault (fault address: <addr>)
+  // Remove the closing )
+  m_stop_description.pop_back();
+
+  std::stringstream ss;
+  lldb::addr_t fault_addr = reinterpret_cast<uintptr_t>(info->si_addr);
+  std::unique_ptr<MemoryTagManager> manager(std::move(details->manager));
+
+  ss << " logical tag: 0x" << std::hex << manager->GetLogicalTag(fault_addr);
+
+  std::vector<uint8_t> allocation_tag_data;
+  Status status = GetProcess().ReadMemoryTags(allocation_tag_type, fault_addr,
+                                              manager->GetGranuleSize(),
+                                              allocation_tag_data);
+
+  if (status.Success()) {
+    llvm::Expected<std::vector<lldb::addr_t>> allocation_tag =
+        manager->UnpackTagsData(allocation_tag_data, 1);
+    if (allocation_tag) {
+      ss << " allocation tag: 0x" << std::hex << allocation_tag->front() << ")";
+    } else {
+      llvm::consumeError(allocation_tag.takeError());
+      ss << ")";
+    }
+  } else
+    ss << ")";
+
+  m_stop_description += ss.str();
+}
+
 bool NativeThreadLinux::IsStopped(int *signo) {
   if (!StateIsStoppedState(m_state, false))
     return false;
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to