1"""Test that lldb functions correctly after the inferior has asserted.""" 2 3from __future__ import print_function 4 5 6import lldb 7from lldbsuite.test import lldbutil 8from lldbsuite.test import lldbplatformutil 9from lldbsuite.test.decorators import * 10from lldbsuite.test.lldbtest import * 11 12 13class AssertingInferiorTestCase(TestBase): 14 15 mydir = TestBase.compute_mydir(__file__) 16 17 @expectedFailureAll( 18 oslist=["windows"], 19 bugnumber="llvm.org/pr21793: need to implement support for detecting assertion / abort on Windows") 20 @expectedFailureAll( 21 oslist=["linux"], 22 archs=["arm"], 23 bugnumber="llvm.org/pr25338") 24 @expectedFailureAll(bugnumber="llvm.org/pr26592", triple='^mips') 25 def test_inferior_asserting(self): 26 """Test that lldb reliably catches the inferior asserting (command).""" 27 self.build() 28 self.inferior_asserting() 29 30 @expectedFailureAll( 31 oslist=["windows"], 32 bugnumber="llvm.org/pr21793: need to implement support for detecting assertion / abort on Windows") 33 @expectedFailureAndroid( 34 api_levels=list( 35 range( 36 16 + 37 1))) # b.android.com/179836 38 def test_inferior_asserting_register(self): 39 """Test that lldb reliably reads registers from the inferior after asserting (command).""" 40 self.build() 41 self.inferior_asserting_registers() 42 43 @expectedFailureAll( 44 oslist=["windows"], 45 bugnumber="llvm.org/pr21793: need to implement support for detecting assertion / abort on Windows") 46 @expectedFailureAll( 47 oslist=["linux"], 48 archs=["arm"], 49 triple=no_match(".*-android"), 50 bugnumber="llvm.org/pr25338") 51 @expectedFailureAll(bugnumber="llvm.org/pr26592", triple='^mips') 52 def test_inferior_asserting_disassemble(self): 53 """Test that lldb reliably disassembles frames after asserting (command).""" 54 self.build() 55 self.inferior_asserting_disassemble() 56 57 @add_test_categories(['pyapi']) 58 @expectedFailureAll( 59 oslist=["windows"], 60 bugnumber="llvm.org/pr21793: need to implement support for detecting assertion / abort on Windows") 61 def test_inferior_asserting_python(self): 62 """Test that lldb reliably catches the inferior asserting (Python API).""" 63 self.build() 64 self.inferior_asserting_python() 65 66 @expectedFailureAll( 67 oslist=["windows"], 68 bugnumber="llvm.org/pr21793: need to implement support for detecting assertion / abort on Windows") 69 @expectedFailureAll( 70 oslist=["linux"], 71 archs=["arm"], 72 triple=no_match(".*-android"), 73 bugnumber="llvm.org/pr25338") 74 @expectedFailureAll(bugnumber="llvm.org/pr26592", triple='^mips') 75 def test_inferior_asserting_expr(self): 76 """Test that the lldb expression interpreter can read from the inferior after asserting (command).""" 77 self.build() 78 self.inferior_asserting_expr() 79 80 @expectedFailureAll( 81 oslist=["windows"], 82 bugnumber="llvm.org/pr21793: need to implement support for detecting assertion / abort on Windows") 83 @expectedFailureAll( 84 oslist=["linux"], 85 archs=["arm"], 86 triple=no_match(".*-android"), 87 bugnumber="llvm.org/pr25338") 88 @expectedFailureAll(bugnumber="llvm.org/pr26592", triple='^mips') 89 def test_inferior_asserting_step(self): 90 """Test that lldb functions correctly after stepping through a call to assert().""" 91 self.build() 92 self.inferior_asserting_step() 93 94 def set_breakpoint(self, line): 95 lldbutil.run_break_set_by_file_and_line( 96 self, "main.c", line, num_expected_locations=1, loc_exact=True) 97 98 def check_stop_reason(self): 99 matched = lldbplatformutil.match_android_device( 100 self.getArchitecture(), valid_api_levels=list(range(1, 16 + 1))) 101 if matched: 102 # On android until API-16 the abort() call ended in a sigsegv 103 # instead of in a sigabrt 104 stop_reason = 'signal SIGSEGV' 105 else: 106 stop_reason = 'signal SIGABRT' 107 108 target = self.dbg.GetTargetAtIndex(0) 109 process = target.GetProcess() 110 thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonSignal) 111 112 pattern = "stop reason = (" + stop_reason + "|hit program assert)" 113 114 # The stop reason of the thread should be an abort signal or exception. 115 self.expect("thread list", STOPPED_DUE_TO_ASSERT, 116 patterns=[pattern], 117 substrs=['stopped']) 118 119 return pattern 120 121 def setUp(self): 122 # Call super's setUp(). 123 TestBase.setUp(self) 124 # Find the line number of the call to assert. 125 self.line = line_number('main.c', '// Assert here.') 126 127 def inferior_asserting(self): 128 """Inferior asserts upon launching; lldb should catch the event and stop.""" 129 exe = self.getBuildArtifact("a.out") 130 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 131 132 self.runCmd("run", RUN_SUCCEEDED) 133 stop_reason = self.check_stop_reason() 134 135 # And it should report a backtrace that includes the assert site. 136 self.expect("thread backtrace all", 137 patterns=[stop_reason], 138 substrs=['main', 'argc', 'argv']) 139 140 # And it should report the correct line number. 141 self.expect("thread backtrace all", 142 patterns=[stop_reason], 143 substrs=['main.c:%d' % self.line]) 144 145 def inferior_asserting_python(self): 146 """Inferior asserts upon launching; lldb should catch the event and stop.""" 147 exe = self.getBuildArtifact("a.out") 148 149 target = self.dbg.CreateTarget(exe) 150 self.assertTrue(target, VALID_TARGET) 151 152 # Now launch the process, and do not stop at entry point. 153 # Both argv and envp are null. 154 process = target.LaunchSimple( 155 None, None, self.get_process_working_directory()) 156 157 if process.GetState() != lldb.eStateStopped: 158 self.fail("Process should be in the 'stopped' state, " 159 "instead the actual state is: '%s'" % 160 lldbutil.state_type_to_str(process.GetState())) 161 162 thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonSignal) 163 if not thread: 164 self.fail("Fail to stop the thread upon assert") 165 166 if self.TraceOn(): 167 lldbutil.print_stacktrace(thread) 168 169 def inferior_asserting_registers(self): 170 """Test that lldb can read registers after asserting.""" 171 exe = self.getBuildArtifact("a.out") 172 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 173 174 self.runCmd("run", RUN_SUCCEEDED) 175 self.check_stop_reason() 176 177 # change current frame to frame 0, since recognizer might have selected 178 # different frame. 179 self.runCmd("frame select 0", RUN_SUCCEEDED) 180 181 # lldb should be able to read from registers from the inferior after 182 # asserting. 183 lldbplatformutil.check_first_register_readable(self) 184 185 def inferior_asserting_disassemble(self): 186 """Test that lldb can disassemble frames after asserting.""" 187 exe = self.getBuildArtifact("a.out") 188 189 # Create a target by the debugger. 190 target = self.dbg.CreateTarget(exe) 191 self.assertTrue(target, VALID_TARGET) 192 193 # Launch the process, and do not stop at the entry point. 194 target.LaunchSimple(None, None, self.get_process_working_directory()) 195 self.check_stop_reason() 196 197 process = target.GetProcess() 198 self.assertTrue(process.IsValid(), "current process is valid") 199 200 thread = process.GetThreadAtIndex(0) 201 self.assertTrue(thread.IsValid(), "current thread is valid") 202 203 lastframeID = thread.GetFrameAtIndex( 204 thread.GetNumFrames() - 1).GetFrameID() 205 206 isi386Arch = False 207 if "i386" in self.getArchitecture(): 208 isi386Arch = True 209 210 # lldb should be able to disassemble frames from the inferior after 211 # asserting. 212 for frame in thread: 213 self.assertTrue(frame.IsValid(), "current frame is valid") 214 215 self.runCmd("frame select " + 216 str(frame.GetFrameID()), RUN_SUCCEEDED) 217 218 # Don't expect the function name to be in the disassembly as the assert 219 # function might be a no-return function where the PC is past the end 220 # of the function and in the next function. We also can't back the PC up 221 # because we don't know how much to back it up by on targets with opcodes 222 # that have differing sizes 223 pc_backup_offset = 1 224 if frame.GetFrameID() == 0: 225 pc_backup_offset = 0 226 if isi386Arch: 227 if lastframeID == frame.GetFrameID(): 228 pc_backup_offset = 0 229 self.expect( 230 "disassemble -a %s" % 231 (frame.GetPC() - 232 pc_backup_offset), 233 substrs=['<+0>: ']) 234 235 def check_expr_in_main(self, thread): 236 depth = thread.GetNumFrames() 237 for i in range(depth): 238 frame = thread.GetFrameAtIndex(i) 239 self.assertTrue(frame.IsValid(), "current frame is valid") 240 if self.TraceOn(): 241 print( 242 "Checking if function %s is main" % 243 frame.GetFunctionName()) 244 245 if 'main' == frame.GetFunctionName(): 246 frame_id = frame.GetFrameID() 247 self.runCmd("frame select " + str(frame_id), RUN_SUCCEEDED) 248 self.expect("p argc", substrs=['(int)', ' = 1']) 249 self.expect("p hello_world", substrs=['Hello']) 250 self.expect("p argv[0]", substrs=['a.out']) 251 self.expect("p null_ptr", substrs=['= 0x0']) 252 return True 253 return False 254 255 def inferior_asserting_expr(self): 256 """Test that the lldb expression interpreter can read symbols after asserting.""" 257 exe = self.getBuildArtifact("a.out") 258 259 # Create a target by the debugger. 260 target = self.dbg.CreateTarget(exe) 261 self.assertTrue(target, VALID_TARGET) 262 263 # Launch the process, and do not stop at the entry point. 264 target.LaunchSimple(None, None, self.get_process_working_directory()) 265 self.check_stop_reason() 266 267 process = target.GetProcess() 268 self.assertTrue(process.IsValid(), "current process is valid") 269 270 thread = process.GetThreadAtIndex(0) 271 self.assertTrue(thread.IsValid(), "current thread is valid") 272 273 # The lldb expression interpreter should be able to read from addresses 274 # of the inferior after a call to assert(). 275 self.assertTrue( 276 self.check_expr_in_main(thread), 277 "cannot find 'main' in the backtrace") 278 279 def inferior_asserting_step(self): 280 """Test that lldb functions correctly after stepping through a call to assert().""" 281 exe = self.getBuildArtifact("a.out") 282 283 # Create a target by the debugger. 284 target = self.dbg.CreateTarget(exe) 285 self.assertTrue(target, VALID_TARGET) 286 287 # Launch the process, and do not stop at the entry point. 288 self.set_breakpoint(self.line) 289 target.LaunchSimple(None, None, self.get_process_working_directory()) 290 291 self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, 292 substrs=['main.c:%d' % self.line, 293 'stop reason = breakpoint']) 294 295 self.runCmd("next") 296 stop_reason = self.check_stop_reason() 297 298 # lldb should be able to read from registers from the inferior after 299 # asserting. 300 if "x86_64" in self.getArchitecture(): 301 self.expect("register read rbp", substrs=['rbp = 0x']) 302 if "i386" in self.getArchitecture(): 303 self.expect("register read ebp", substrs=['ebp = 0x']) 304 305 process = target.GetProcess() 306 self.assertTrue(process.IsValid(), "current process is valid") 307 308 thread = process.GetThreadAtIndex(0) 309 self.assertTrue(thread.IsValid(), "current thread is valid") 310 311 # The lldb expression interpreter should be able to read from addresses 312 # of the inferior after a call to assert(). 313 self.assertTrue( 314 self.check_expr_in_main(thread), 315 "cannot find 'main' in the backtrace") 316 317 # And it should report the correct line number. 318 self.expect("thread backtrace all", 319 patterns=[stop_reason], 320 substrs=['main.c:%d' % self.line]) 321