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