This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rGd510b5f199d6: [lldb][AArch64] Annotate synchronous tag
faults (authored by DavidSpickett).
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D105178/new/
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,59 @@
+#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>
+
+// Set bits 59-56 to tag, removing any existing tag
+static char *set_tag(char *ptr, size_t tag) {
+ return (char *)(((size_t)ptr & ~((size_t)0xf << 56)) | (tag << 56));
+}
+
+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;
+
+ unsigned long prctl_arg2 = 0;
+ 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;
+
+ // Set fault type
+ if (prctl(PR_SET_TAGGED_ADDR_CTRL, prctl_arg2, 0, 0, 0))
+ return 1;
+
+ // Allocate some memory with tagging enabled that we
+ // can read/write if we use correct tags.
+ 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;
+
+ // Our pointer will have tag 9
+ char *tagged_buf = set_tag(buf, 9);
+ // Set allocation tags for the first 2 granules
+ __arm_mte_set_tag(set_tag(tagged_buf, 9));
+ __arm_mte_set_tag(set_tag(tagged_buf + 16, 10));
+
+ // Confirm that we can write when tags match
+ *tagged_buf = ' ';
+
+ // Breakpoint here
+ // Faults because tag 9 in the ptr != allocation tag of 10.
+ // + 16 puts us in the second granule and +1 makes the fault address
+ // misaligned relative to the granule size. This misalignment must
+ // be accounted for by lldb-server.
+ *(tagged_buf + 16 + 1) = '?';
+
+ 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,62 @@
+"""
+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.
+ # It will be 0x10 (to be in the 2nd granule), +1 to be 0x11.
+ # Which tests that lldb-server handles fault addresses that
+ # are not granule aligned.
+ self.expect("continue",
+ patterns=[
+ "\* thread #1, name = 'a.out', stop reason = signal SIGSEGV: "
+ "sync tag check fault \(fault address: 0x9[0-9A-Fa-f]+11\ "
+ "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,69 @@
? 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;
+ // The fault address may not be granule aligned. ReadMemoryTags will granule
+ // align any range you give it, potentially making it larger.
+ // To prevent this set len to 1. This always results in a range that is at
+ // most 1 granule in size and includes fault_addr.
+ Status status = GetProcess().ReadMemoryTags(allocation_tag_type, fault_addr,
+ 1, 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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits