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