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