Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -739,6 +739,40 @@ if (!m_reg_info_sp) return false; + // In addition to SVE vector length configuration we will use this function + // to configure no of address bits being used by the process for addressing. + // Default value will be set to 52 which is maximum possible AArch64 virtual + // address width. + // Code below tries to detect pointer authentication feature for the current + // process. If PAC is enabled, address bits in use are configured based on + // PAC code/data mask. + if (!GetThread().GetProcess()->GetAddressBitsInUse()) { + uint32_t address_bits_in_use = 52; + const RegisterInfo *reg_info = m_reg_info_sp->GetRegisterInfo("code_mask"); + if (reg_info) { + uint64_t fail_value = LLDB_INVALID_ADDRESS; + uint32_t reg_num = reg_info->kinds[eRegisterKindLLDB]; + uint64_t cmask_reg_value = ReadRegisterAsUnsigned(reg_num, fail_value); + if ((cmask_reg_value != fail_value) && + (cmask_reg_value & ((uint64_t)1 << 48))) + address_bits_in_use = 48; + else { + const RegisterInfo *reg_info = + m_reg_info_sp->GetRegisterInfo("data_mask"); + if (reg_info) { + fail_value = LLDB_INVALID_ADDRESS; + reg_num = reg_info->kinds[eRegisterKindLLDB]; + uint64_t dmask_reg_value = + ReadRegisterAsUnsigned(reg_num, fail_value); + if ((dmask_reg_value != fail_value) && + (dmask_reg_value & ((uint64_t)1 << 48))) + address_bits_in_use = 48; + } + } + } + GetThread().GetProcess()->SetAddressBitsInUse(address_bits_in_use); + } + const RegisterInfo *reg_info = m_reg_info_sp->GetRegisterInfo("vg"); if (!reg_info) return false; Index: lldb/test/API/functionalities/unwind/aarch64_unwind_pac/Makefile =================================================================== --- /dev/null +++ lldb/test/API/functionalities/unwind/aarch64_unwind_pac/Makefile @@ -0,0 +1,5 @@ +C_SOURCES := main.c + +CFLAGS ?= -g -Os -march=armv8.5-a -mbranch-protection=pac-ret+leaf + +include Makefile.rules Index: lldb/test/API/functionalities/unwind/aarch64_unwind_pac/TestAArch64UnwindPAC.py =================================================================== --- /dev/null +++ lldb/test/API/functionalities/unwind/aarch64_unwind_pac/TestAArch64UnwindPAC.py @@ -0,0 +1,42 @@ +""" +Test that we can backtrace correctly when AArch64 PAC is enabled +""" + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class AArch64UnwindPAC(TestBase): + mydir = TestBase.compute_mydir(__file__) + + @skipIf(archs=no_match(["aarch64"])) + @skipIf(oslist=no_match(['linux'])) + def test(self): + """Test that we can backtrace correctly when AArch64 PAC is enabled""" + self.build() + + self.line = line_number('main.c', '// Frame func_c') + + exe = self.getBuildArtifact("a.out") + self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) + + lldbutil.run_break_set_by_file_and_line( + self, "main.c", self.line, num_expected_locations=1) + self.runCmd("run", RUN_SUCCEEDED) + self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT, + substrs=["stop reason = breakpoint 1."]) + + target = self.dbg.GetSelectedTarget() + process = target.GetProcess() + thread = process.GetThreadAtIndex(0) + + backtrace = ["func_c", "func_b", "func_a", "main"] + self.assertEqual(thread.GetNumFrames(), len(backtrace)) + for i in range(len(backtrace)): + frame = thread.GetFrameAtIndex(i) + self.assertTrue(frame) + self.assertEqual(frame.GetFunctionName(), backtrace[i]) + self.assertEqual(frame.GetLineEntry().GetLine(), + line_number("main.c", "Frame " + backtrace[i])) Index: lldb/test/API/functionalities/unwind/aarch64_unwind_pac/main.c =================================================================== --- /dev/null +++ lldb/test/API/functionalities/unwind/aarch64_unwind_pac/main.c @@ -0,0 +1,30 @@ +#include + +static void func_a (void) __attribute__((noinline)); +static void func_b (void) __attribute__((noinline)); +static void func_c (void) __attribute__((noinline)); + +static void +func_c (void) +{ + exit (0); // Frame func_c +} + +static void +func_b (void) +{ + func_c (); // Frame func_b +} + +static void +func_a (void) +{ + func_b (); // Frame func_a +} + +int +main (int argc, char *argv[]) +{ + func_a (); // Frame main + return 0; +}