1"""Test that lldb steps correctly after the inferior has crashed.""" 2 3 4import lldb 5from lldbsuite.test import lldbutil 6from lldbsuite.test import lldbplatformutil 7from lldbsuite.test.decorators import * 8from lldbsuite.test.lldbtest import * 9 10 11class CrashingInferiorStepTestCase(TestBase): 12 @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24778") 13 @expectedFailureNetBSD 14 def test_inferior_crashing(self): 15 """Test that lldb reliably catches the inferior crashing (command).""" 16 self.build() 17 self.inferior_crashing() 18 19 def test_inferior_crashing_register(self): 20 """Test that lldb reliably reads registers from the inferior after crashing (command).""" 21 self.build() 22 self.inferior_crashing_registers() 23 24 @add_test_categories(["pyapi"]) 25 def test_inferior_crashing_python(self): 26 """Test that lldb reliably catches the inferior crashing (Python API).""" 27 self.build() 28 self.inferior_crashing_python() 29 30 def test_inferior_crashing_expr(self): 31 """Test that the lldb expression interpreter can read from the inferior after crashing (command).""" 32 self.build() 33 self.inferior_crashing_expr() 34 35 def test_inferior_crashing_step(self): 36 """Test that stepping after a crash behaves correctly.""" 37 self.build() 38 self.inferior_crashing_step() 39 40 @skipIfTargetAndroid() # debuggerd interferes with this test on Android 41 @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24778") 42 def test_inferior_crashing_step_after_break(self): 43 """Test that lldb functions correctly after stepping through a crash.""" 44 self.build() 45 self.inferior_crashing_step_after_break() 46 47 # Inferior exits after stepping after a segfault. This is working as 48 # intended IMHO. 49 @skipIf(oslist=["freebsd", "linux", "netbsd"]) 50 def test_inferior_crashing_expr_step_and_expr(self): 51 """Test that lldb expressions work before and after stepping after a crash.""" 52 self.build() 53 self.inferior_crashing_expr_step_expr() 54 55 def set_breakpoint(self, line): 56 lldbutil.run_break_set_by_file_and_line( 57 self, "main.c", line, num_expected_locations=1, loc_exact=True 58 ) 59 60 def check_stop_reason(self): 61 # We should have one crashing thread 62 self.assertEqual( 63 len( 64 lldbutil.get_crashed_threads( 65 self, self.dbg.GetSelectedTarget().GetProcess() 66 ) 67 ), 68 1, 69 STOPPED_DUE_TO_EXC_BAD_ACCESS, 70 ) 71 72 def get_api_stop_reason(self): 73 return lldb.eStopReasonException 74 75 def setUp(self): 76 # Call super's setUp(). 77 TestBase.setUp(self) 78 # Find the line number of the crash. 79 self.line = line_number("main.c", "// Crash here.") 80 81 def inferior_crashing(self): 82 """Inferior crashes upon launching; lldb should catch the event and stop.""" 83 exe = self.getBuildArtifact("a.out") 84 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 85 86 self.runCmd("run", RUN_SUCCEEDED) 87 # The exact stop reason depends on the platform 88 if self.platformIsDarwin(): 89 stop_reason = "stop reason = EXC_BAD_ACCESS" 90 elif self.getPlatform() == "linux" or self.getPlatform() == "freebsd": 91 stop_reason = "stop reason = signal SIGSEGV" 92 else: 93 stop_reason = "stop reason = invalid address" 94 self.expect( 95 "thread list", 96 STOPPED_DUE_TO_EXC_BAD_ACCESS, 97 substrs=["stopped", stop_reason], 98 ) 99 100 # And it should report the correct line number. 101 self.expect( 102 "thread backtrace all", substrs=[stop_reason, "main.c:%d" % self.line] 103 ) 104 105 def inferior_crashing_python(self): 106 """Inferior crashes upon launching; lldb should catch the event and stop.""" 107 exe = self.getBuildArtifact("a.out") 108 109 target = self.dbg.CreateTarget(exe) 110 self.assertTrue(target, VALID_TARGET) 111 112 # Now launch the process, and do not stop at entry point. 113 # Both argv and envp are null. 114 process = target.LaunchSimple(None, None, self.get_process_working_directory()) 115 116 if process.GetState() != lldb.eStateStopped: 117 self.fail( 118 "Process should be in the 'stopped' state, " 119 "instead the actual state is: '%s'" 120 % lldbutil.state_type_to_str(process.GetState()) 121 ) 122 123 threads = lldbutil.get_crashed_threads(self, process) 124 self.assertEqual( 125 len(threads), 1, "Failed to stop the thread upon bad access exception" 126 ) 127 128 if self.TraceOn(): 129 lldbutil.print_stacktrace(threads[0]) 130 131 def inferior_crashing_registers(self): 132 """Test that lldb can read registers after crashing.""" 133 exe = self.getBuildArtifact("a.out") 134 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 135 136 self.runCmd("run", RUN_SUCCEEDED) 137 self.check_stop_reason() 138 139 # lldb should be able to read from registers from the inferior after 140 # crashing. 141 lldbplatformutil.check_first_register_readable(self) 142 143 def inferior_crashing_expr(self): 144 """Test that the lldb expression interpreter can read symbols after crashing.""" 145 exe = self.getBuildArtifact("a.out") 146 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 147 148 self.runCmd("run", RUN_SUCCEEDED) 149 self.check_stop_reason() 150 151 # The lldb expression interpreter should be able to read from addresses 152 # of the inferior after a crash. 153 self.expect("expression argc", startstr="(int) $0 = 1") 154 155 self.expect("expression hello_world", substrs=["Hello"]) 156 157 def inferior_crashing_step(self): 158 """Test that lldb functions correctly after stepping through a crash.""" 159 exe = self.getBuildArtifact("a.out") 160 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 161 162 self.set_breakpoint(self.line) 163 self.runCmd("run", RUN_SUCCEEDED) 164 165 self.expect( 166 "thread list", 167 STOPPED_DUE_TO_BREAKPOINT, 168 substrs=["main.c:%d" % self.line, "stop reason = breakpoint"], 169 ) 170 171 self.runCmd("next") 172 self.check_stop_reason() 173 174 # The lldb expression interpreter should be able to read from addresses 175 # of the inferior after a crash. 176 self.expect("expression argv[0]", substrs=["a.out"]) 177 self.expect("expression null_ptr", substrs=["= 0x0"]) 178 179 # lldb should be able to read from registers from the inferior after 180 # crashing. 181 lldbplatformutil.check_first_register_readable(self) 182 183 # And it should report the correct line number. 184 self.expect("thread backtrace all", substrs=["main.c:%d" % self.line]) 185 186 @expectedFailureNetBSD 187 def inferior_crashing_step_after_break(self): 188 """Test that lldb behaves correctly when stepping after a crash.""" 189 exe = self.getBuildArtifact("a.out") 190 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 191 192 self.runCmd("run", RUN_SUCCEEDED) 193 self.check_stop_reason() 194 195 expected_state = "exited" # Provide the exit code. 196 if self.platformIsDarwin(): 197 # TODO: Determine why 'next' and 'continue' have no effect after a 198 # crash. 199 expected_state = "stopped" 200 201 self.expect("next", substrs=["Process", expected_state]) 202 203 if expected_state == "exited": 204 self.expect("thread list", error=True, substrs=["Process must be launched"]) 205 else: 206 self.check_stop_reason() 207 208 def inferior_crashing_expr_step_expr(self): 209 """Test that lldb expressions work before and after stepping after a crash.""" 210 exe = self.getBuildArtifact("a.out") 211 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 212 213 self.runCmd("run", RUN_SUCCEEDED) 214 self.check_stop_reason() 215 216 # The lldb expression interpreter should be able to read from addresses 217 # of the inferior after a crash. 218 self.expect("expression argv[0]", substrs=["a.out"]) 219 220 self.runCmd("next") 221 self.check_stop_reason() 222 223 # The lldb expression interpreter should be able to read from addresses 224 # of the inferior after a crash. 225 self.expect("expression argv[0]", substrs=["a.out"]) 226