xref: /llvm-project/lldb/test/API/functionalities/unwind/aarch64_unwind_pac/TestAArch64UnwindPAC.py (revision 9c2468821ec51defd09c246fea4a47886fff8c01)
1"""
2Test that we can backtrace correctly when AArch64 PAC is enabled
3"""
4
5import lldb
6from lldbsuite.test.decorators import *
7from lldbsuite.test.lldbtest import *
8from lldbsuite.test import lldbutil
9
10
11class AArch64UnwindPAC(TestBase):
12    @skipIf(archs=no_match(["aarch64"]))
13    @skipIf(oslist=no_match(["linux"]))
14    def test(self):
15        """Test that we can backtrace correctly when AArch64 PAC is enabled"""
16        if not self.isAArch64PAuth():
17            self.skipTest("Target must support Pointer Authentication.")
18
19        self.build()
20
21        self.line = line_number("main.c", "// Frame func_c")
22
23        exe = self.getBuildArtifact("a.out")
24        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
25
26        lldbutil.run_break_set_by_file_and_line(
27            self, "main.c", self.line, num_expected_locations=1
28        )
29        self.runCmd("run", RUN_SUCCEEDED)
30        self.expect(
31            "thread backtrace",
32            STOPPED_DUE_TO_BREAKPOINT,
33            substrs=["stop reason = breakpoint 1."],
34        )
35
36        target = self.dbg.GetSelectedTarget()
37        process = target.GetProcess()
38        thread = process.GetThreadAtIndex(0)
39
40        backtrace = [
41            "func_c",
42            "func_b",
43            "func_a",
44            "main",
45        ]
46
47        libc_backtrace = [
48            "__libc_start_main",
49            "_start",
50        ]
51
52        self.assertGreaterEqual(
53            thread.GetNumFrames(), len(backtrace) + len(libc_backtrace)
54        )
55
56        # Strictly check frames that are in the test program's source.
57        for frame_idx, frame in enumerate(thread.frames[: len(backtrace)]):
58            self.assertTrue(frame)
59            self.assertEqual(frame.GetFunctionName(), backtrace[frame_idx])
60            self.assertEqual(
61                frame.GetLineEntry().GetLine(),
62                line_number("main.c", "Frame " + backtrace[frame_idx]),
63            )
64
65        # After the program comes some libc frames. The number varies by
66        # system, so ensure we have at least these two in this order,
67        # skipping frames in between.
68        start_idx = frame_idx + 1
69        for frame_idx, frame in enumerate(thread.frames[start_idx:], start=start_idx):
70            self.assertTrue(frame)
71            if libc_backtrace[0] == frame.GetFunctionName():
72                libc_backtrace.pop(0)
73
74        self.assertFalse(libc_backtrace, "Did not find expected libc frames.")
75