1"""Test that lldb steps correctly after the inferior has crashed while in a recursive routine.""" 2 3 4import lldb 5from lldbsuite.test.decorators import * 6from lldbsuite.test.lldbtest import * 7from lldbsuite.test import lldbplatformutil 8from lldbsuite.test import lldbutil 9 10 11class CrashingRecursiveInferiorStepTestCase(TestBase): 12 def test_recursive_inferior_crashing_step(self): 13 """Test that stepping after a crash behaves correctly.""" 14 self.build() 15 self.recursive_inferior_crashing_step() 16 17 @skipIfTargetAndroid() # debuggerd interferes with this test on Android 18 @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24778") 19 @expectedFailureNetBSD 20 def test_recursive_inferior_crashing_step_after_break(self): 21 """Test that lldb functions correctly after stepping through a crash.""" 22 self.build() 23 self.recursive_inferior_crashing_step_after_break() 24 25 # Inferior exits after stepping after a segfault. This is working as 26 # intended IMHO. 27 @skipIf(oslist=["freebsd", "linux", "netbsd"]) 28 def test_recursive_inferior_crashing_expr_step_and_expr(self): 29 """Test that lldb expressions work before and after stepping after a crash.""" 30 self.build() 31 self.recursive_inferior_crashing_expr_step_expr() 32 33 def set_breakpoint(self, line): 34 lldbutil.run_break_set_by_file_and_line( 35 self, "main.c", line, num_expected_locations=1, loc_exact=True 36 ) 37 38 def check_stop_reason(self): 39 # We should have one crashing thread 40 self.assertEqual( 41 len( 42 lldbutil.get_crashed_threads( 43 self, self.dbg.GetSelectedTarget().GetProcess() 44 ) 45 ), 46 1, 47 STOPPED_DUE_TO_EXC_BAD_ACCESS, 48 ) 49 50 def setUp(self): 51 # Call super's setUp(). 52 TestBase.setUp(self) 53 # Find the line number of the crash. 54 self.line = line_number("main.c", "// Crash here.") 55 56 def recursive_inferior_crashing_step(self): 57 """Test that lldb functions correctly after stepping through a crash.""" 58 exe = self.getBuildArtifact("a.out") 59 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 60 61 self.set_breakpoint(self.line) 62 self.runCmd("run", RUN_SUCCEEDED) 63 64 self.expect( 65 "thread list", 66 STOPPED_DUE_TO_BREAKPOINT, 67 substrs=["main.c:%d" % self.line, "stop reason = breakpoint"], 68 ) 69 70 self.runCmd("next") 71 self.check_stop_reason() 72 73 # The lldb expression interpreter should be able to read from addresses 74 # of the inferior after a crash. 75 self.expect("expression i", substrs=["(int) $0 ="]) 76 77 # lldb should be able to read from registers from the inferior after 78 # crashing. 79 lldbplatformutil.check_first_register_readable(self) 80 81 # And it should report the correct line number. 82 self.expect("thread backtrace all", substrs=["main.c:%d" % self.line]) 83 84 def recursive_inferior_crashing_step_after_break(self): 85 """Test that lldb behaves correctly when stepping after a crash.""" 86 exe = self.getBuildArtifact("a.out") 87 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 88 89 self.runCmd("run", RUN_SUCCEEDED) 90 self.check_stop_reason() 91 92 expected_state = "exited" # Provide the exit code. 93 if self.platformIsDarwin(): 94 # TODO: Determine why 'next' and 'continue' have no effect after a 95 # crash. 96 expected_state = "stopped" 97 98 self.expect("next", substrs=["Process", expected_state]) 99 100 if expected_state == "exited": 101 self.expect("thread list", error=True, substrs=["Process must be launched"]) 102 else: 103 self.check_stop_reason() 104 105 def recursive_inferior_crashing_expr_step_expr(self): 106 """Test that lldb expressions work before and after stepping after a crash.""" 107 exe = self.getBuildArtifact("a.out") 108 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 109 110 self.runCmd("run", RUN_SUCCEEDED) 111 self.check_stop_reason() 112 113 # The lldb expression interpreter should be able to read from addresses 114 # of the inferior after a crash. 115 self.expect("expression null", startstr="(char *) $0 = 0x0") 116 117 self.runCmd("next") 118 119 # The lldb expression interpreter should be able to read from addresses 120 # of the inferior after a step. 121 self.expect("expression null", startstr="(char *) $1 = 0x0") 122 123 self.check_stop_reason() 124