xref: /llvm-project/lldb/test/API/linux/aarch64/unwind_signal/TestUnwindSignal.py (revision 9c2468821ec51defd09c246fea4a47886fff8c01)
1"""Test that we can unwind out of a signal handler.
2   Which for AArch64 Linux requires a specific unwind plan."""
3
4
5import lldb
6from lldbsuite.test.decorators import *
7from lldbsuite.test.lldbtest import *
8from lldbsuite.test import lldbutil
9
10
11class UnwindSignalTestCase(TestBase):
12    NO_DEBUG_INFO_TESTCASE = True
13
14    @skipUnlessArch("aarch64")
15    @skipUnlessPlatform(["linux"])
16    def test_unwind_signal(self):
17        """Inferior calls sigill() and handles the resultant SIGILL.
18        Stopped at a breakpoint in the handler, check that we can unwind
19        back to sigill() and get the expected register contents there."""
20        self.build()
21        exe = self.getBuildArtifact("a.out")
22
23        target = self.dbg.CreateTarget(exe)
24        self.assertTrue(target, VALID_TARGET)
25
26        process = target.LaunchSimple(None, None, self.get_process_working_directory())
27        self.assertTrue(process, PROCESS_IS_VALID)
28        self.assertState(process.GetState(), lldb.eStateStopped)
29        signo = process.GetUnixSignals().GetSignalNumberFromName("SIGILL")
30
31        thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonSignal)
32        self.assertTrue(
33            thread and thread.IsValid(), "Thread should be stopped due to a signal"
34        )
35        self.assertGreaterEqual(
36            thread.GetStopReasonDataCount(), 1, "There should be data in the event."
37        )
38        self.assertEqual(
39            thread.GetStopReasonDataAtIndex(0),
40            signo,
41            "The stop signal should be SIGILL",
42        )
43
44        # Continue to breakpoint in sigill handler
45        bkpt = target.FindBreakpointByID(
46            lldbutil.run_break_set_by_source_regexp(self, "Set a breakpoint here")
47        )
48        threads = lldbutil.continue_to_breakpoint(process, bkpt)
49        self.assertEqual(len(threads), 1, "Expected single thread")
50        thread = threads[0]
51
52        # Expect breakpoint in 'handler'
53        frame = thread.GetFrameAtIndex(0)
54        self.assertEqual(frame.GetDisplayFunctionName(), "handler", "Unexpected break?")
55
56        # Expect that unwinding should find 'sigill'
57        found_caller = False
58        for frame in thread.get_thread_frames():
59            if frame.GetDisplayFunctionName() == "sigill":
60                # We should have ascending values in the x registers
61                regs = frame.GetRegisters().GetValueAtIndex(0)
62                err = lldb.SBError()
63
64                for i in range(31):
65                    name = "x{}".format(i)
66                    value = regs.GetChildMemberWithName(name).GetValueAsUnsigned(err)
67                    self.assertSuccess(err, "Failed to get register {}".format(name))
68                    self.assertEqual(
69                        value, i, "Unexpected value for register {}".format(name)
70                    )
71
72                found_caller = True
73                break
74
75        self.assertTrue(
76            found_caller, "Unwinding did not find func that caused the SIGILL"
77        )
78
79        # Continue until we exit.
80        process.Continue()
81        self.assertState(process.GetState(), lldb.eStateExited)
82        self.assertEqual(process.GetExitStatus(), 0)
83