diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -2626,8 +2626,14 @@ } lldb::addr_t Target::GetBreakableLoadAddress(lldb::addr_t addr) { - auto arch_plugin = GetArchitecturePlugin(); - return arch_plugin ? arch_plugin->GetBreakableLoadAddress(addr, *this) : addr; + lldb::ABISP abi_plugin = m_process_sp ? m_process_sp->GetABI() : nullptr; + if (abi_plugin) + addr = abi_plugin->FixCodeAddress(addr); + + if (auto arch_plugin = GetArchitecturePlugin()) + addr = arch_plugin->GetBreakableLoadAddress(addr, *this); + + return addr; } SourceManager &Target::GetSourceManager() { diff --git a/lldb/test/API/linux/aarch64/tagged_code_break/Makefile b/lldb/test/API/linux/aarch64/tagged_code_break/Makefile new file mode 100644 --- /dev/null +++ b/lldb/test/API/linux/aarch64/tagged_code_break/Makefile @@ -0,0 +1,5 @@ +C_SOURCES := main.c + +CFLAGS_EXTRAS := -march=armv8.3-a + +include Makefile.rules diff --git a/lldb/test/API/linux/aarch64/tagged_code_break/TestAArch64LinuxTaggedCodeBreak.py b/lldb/test/API/linux/aarch64/tagged_code_break/TestAArch64LinuxTaggedCodeBreak.py new file mode 100644 --- /dev/null +++ b/lldb/test/API/linux/aarch64/tagged_code_break/TestAArch64LinuxTaggedCodeBreak.py @@ -0,0 +1,57 @@ +""" +Test that "breakpoint set -a" uses the ABI plugin to remove non-address bits +before attempting to set a breakpoint. +""" + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class AArch64LinuxTaggedCodeBreak(TestBase): + + NO_DEBUG_INFO_TESTCASE = True + + def do_tagged_break(self, hardware): + if not self.isAArch64PAuth(): + self.skipTest('Target must support pointer authentication.') + + 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', '// Set break point at this line.'), + num_expected_locations=1) + + self.runCmd("run", 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']) + + cmd = "breakpoint set -a fnptr" + # LLDB only has the option to force hardware break, not software. + # It prefers sofware break when it can and this will be one of those cases. + if hardware: + cmd += " --hardware" + self.expect(cmd) + + self.runCmd("continue") + self.assertEqual(self.process().GetState(), lldb.eStateStopped) + self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, + substrs=['stopped', '`foo at main.c', 'stop reason = breakpoint']) + + # AArch64 Linux always enables the top byte ignore feature + @skipUnlessArch("aarch64") + @skipUnlessPlatform(["linux"]) + def test_software_break(self): + self.do_tagged_break(False) + + @skipUnlessArch("aarch64") + @skipUnlessPlatform(["linux"]) + def test_hardware_break(self): + self.do_tagged_break(True) \ No newline at end of file diff --git a/lldb/test/API/linux/aarch64/tagged_code_break/main.c b/lldb/test/API/linux/aarch64/tagged_code_break/main.c new file mode 100644 --- /dev/null +++ b/lldb/test/API/linux/aarch64/tagged_code_break/main.c @@ -0,0 +1,18 @@ +#include + +void foo(void) {} +typedef void (*FooPtr)(void); + +int main() { + FooPtr fnptr = foo; + // Set top byte. + fnptr = (FooPtr)((uintptr_t)fnptr | (uintptr_t)0xff << 56); + // Then apply a PAuth signature to it. + __asm__ __volatile__("pacdza %0" : "=r"(fnptr) : "r"(fnptr)); + // fnptr is now: + // <8 bit top byte tag> + + foo(); // Set break point at this line. + + return 0; +}