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 mydir = TestBase.compute_mydir(__file__) 14 15 @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24778") 16 def test_recursive_inferior_crashing_step(self): 17 """Test that stepping after a crash behaves correctly.""" 18 self.build() 19 self.recursive_inferior_crashing_step() 20 21 @skipIfTargetAndroid() # debuggerd interferes with this test on Android 22 @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24778") 23 def test_recursive_inferior_crashing_step_after_break(self): 24 """Test that lldb functions correctly after stepping through a crash.""" 25 self.build() 26 self.recursive_inferior_crashing_step_after_break() 27 28 # Inferior exits after stepping after a segfault. This is working as 29 # intended IMHO. 30 @skipIfLinux 31 @skipIfFreeBSD 32 @expectedFailureNetBSD 33 def test_recursive_inferior_crashing_expr_step_and_expr(self): 34 """Test that lldb expressions work before and after stepping after a crash.""" 35 self.build() 36 self.recursive_inferior_crashing_expr_step_expr() 37 38 def set_breakpoint(self, line): 39 lldbutil.run_break_set_by_file_and_line( 40 self, "main.c", line, num_expected_locations=1, loc_exact=True) 41 42 def check_stop_reason(self): 43 # We should have one crashing thread 44 self.assertEqual( 45 len( 46 lldbutil.get_crashed_threads( 47 self, 48 self.dbg.GetSelectedTarget().GetProcess())), 1, 49 STOPPED_DUE_TO_EXC_BAD_ACCESS) 50 51 def setUp(self): 52 # Call super's setUp(). 53 TestBase.setUp(self) 54 # Find the line number of the crash. 55 self.line = line_number('main.c', '// Crash here.') 56 57 def recursive_inferior_crashing_step(self): 58 """Test that lldb functions correctly after stepping through a crash.""" 59 exe = self.getBuildArtifact("a.out") 60 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 61 62 self.set_breakpoint(self.line) 63 self.runCmd("run", RUN_SUCCEEDED) 64 65 self.expect( 66 "thread list", 67 STOPPED_DUE_TO_BREAKPOINT, 68 substrs=['main.c:%d' % self.line, 'stop reason = breakpoint']) 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("p 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( 102 "thread list", 103 error=True, 104 substrs=['Process must be launched']) 105 else: 106 self.check_stop_reason() 107 108 def recursive_inferior_crashing_expr_step_expr(self): 109 """Test that lldb expressions work before and after stepping after a crash.""" 110 exe = self.getBuildArtifact("a.out") 111 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 112 113 self.runCmd("run", RUN_SUCCEEDED) 114 self.check_stop_reason() 115 116 # The lldb expression interpreter should be able to read from addresses 117 # of the inferior after a crash. 118 self.expect("p null", startstr='(char *) $0 = 0x0') 119 120 self.runCmd("next") 121 122 # The lldb expression interpreter should be able to read from addresses 123 # of the inferior after a step. 124 self.expect("p null", startstr='(char *) $1 = 0x0') 125 126 self.check_stop_reason() 127