129 lines · python
1"""Test that lldb backtraces a frameless function that faults correctly."""2 3import lldbsuite.test.lldbutil as lldbutil4from lldbsuite.test.lldbtest import *5from lldbsuite.test.decorators import *6import shutil7import os8 9 10class TestUnwindFramelessFaulted(TestBase):11 NO_DEBUG_INFO_TESTCASE = True12 13 @skipIf(oslist=no_match([lldbplatformutil.getDarwinOSTriples()]))14 @skipIf(archs=no_match(["aarch64", "arm64", "arm64e"]))15 16 # The static linker in Xcode 15.0-15.2 on macOS 14 will mislink17 # the eh_frame addresses; ld-classic in those tools is one workaround.18 # This issue was fixed in Xcode 15.3, but it's not straightforward19 # to test for the linker version or Xcode version so tie this to20 # macOS 15 which uses Xcode 16 and does not have the issues.21 @skipIf(macos_version=["<", "15.0"])22 23 def test_frameless_faulted_unwind(self):24 self.build()25 26 (target, process, thread, bp) = lldbutil.run_to_name_breakpoint(27 self, "main", only_one_thread=False28 )29 30 # The test program will have a backtrace like this at its deepest:31 #32 # * frame #0: 0x0000000102adc468 a.out`break_to_debugger + 433 # frame #1: 0x0000000102adc458 a.out`trap + 1634 # frame #2: 0x0000000102adc440 a.out`to_be_interrupted + 2035 # frame #3: 0x0000000102adc418 a.out`main at main.c:4:736 # frame #4: 0x0000000193b7eb4c dyld`start + 600037 38 correct_frames = ["break_to_debugger", "trap", "to_be_interrupted", "main"]39 40 # Keep track of when main has branch & linked, instruction step until we're41 # back in main()42 main_has_bl_ed = False43 44 # Instruction step through the binary until we are in a function not45 # listed in correct_frames.46 frame = thread.GetFrameAtIndex(0)47 step_count = 048 max_step_count = 20049 while (50 process.GetState() == lldb.eStateStopped51 and frame.name in correct_frames52 and step_count < max_step_count53 ):54 starting_index = 055 if self.TraceOn():56 self.runCmd("bt")57 58 # Find which index into correct_frames the current stack frame is59 for idx, name in enumerate(correct_frames):60 if frame.name == name:61 starting_index = idx62 63 # Test that all frames after the current frame listed in64 # correct_frames appears in the backtrace.65 frame_idx = 066 for expected_frame in correct_frames[starting_index:]:67 self.assertEqual(thread.GetFrameAtIndex(frame_idx).name, expected_frame)68 frame_idx = frame_idx + 169 70 # When we're at our deepest level, test that register passing of71 # x0 and x20 follow the by-hand UnwindPlan rules.72 # In this test program, we can get x0 in the middle of the stack73 # and we CAN'T get x20. The opposites of the normal AArch64 SysV74 # ABI.75 if frame.name == "break_to_debugger":76 tbi_frame = thread.GetFrameAtIndex(2)77 self.assertEqual(tbi_frame.name, "to_be_interrupted")78 # The original argument to to_be_interrupted(), 1079 # Normally can't get x0 mid-stack, but UnwindPlans have80 # special rules to make this possible.81 x0_reg = tbi_frame.register["x0"]82 self.assertTrue(x0_reg.IsValid())83 self.assertEqual(x0_reg.GetValueAsUnsigned(), 10)84 # The incremented return value from to_be_interrupted(), 1185 x24_reg = tbi_frame.register["x24"]86 self.assertTrue(x24_reg.IsValid())87 self.assertEqual(x24_reg.GetValueAsUnsigned(), 11)88 # x20 can normally be fetched mid-stack, but the UnwindPlan89 # has a rule saying it can't be fetched.90 x20_reg = tbi_frame.register["x20"]91 self.assertTrue(x20_reg.error.fail)92 93 trap_frame = thread.GetFrameAtIndex(1)94 self.assertEqual(trap_frame.name, "trap")95 # Confirm that we can fetch x0 from trap() which96 # is normally not possible w/ SysV AbI, but special97 # UnwindPlans in use.98 x0_reg = trap_frame.register["x0"]99 self.assertTrue(x0_reg.IsValid())100 self.assertEqual(x0_reg.GetValueAsUnsigned(), 10)101 x1_reg = trap_frame.register["x1"]102 self.assertTrue(x1_reg.error.fail)103 104 main_frame = thread.GetFrameAtIndex(3)105 self.assertEqual(main_frame.name, "main")106 # x20 can normally be fetched mid-stack, but the UnwindPlan107 # has a rule saying it can't be fetched.108 x20_reg = main_frame.register["x20"]109 self.assertTrue(x20_reg.error.fail)110 # x21 can be fetched mid-stack.111 x21_reg = main_frame.register["x21"]112 self.assertTrue(x21_reg.error.success)113 114 # manually move past the BRK instruction in115 # break_to_debugger(). lldb-server doesn't116 # advance past the builtin_debugtrap() BRK117 # instruction.118 if (119 thread.GetStopReason() == lldb.eStopReasonException120 and frame.name == "break_to_debugger"121 ):122 frame.SetPC(frame.GetPC() + 4)123 124 if self.TraceOn():125 print("StepInstruction")126 thread.StepInstruction(False)127 frame = thread.GetFrameAtIndex(0)128 step_count = step_count + 1129