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