Home | History | Annotate | Download | only in recursive-inferior
      1 """Test that lldb functions correctly after the inferior has crashed while in a recursive routine."""
      2 
      3 import os, time
      4 import unittest2
      5 import lldb, lldbutil
      6 from lldbtest import *
      7 
      8 class CrashingRecursiveInferiorTestCase(TestBase):
      9 
     10     mydir = os.path.join("functionalities", "inferior-crashing", "recursive-inferior")
     11 
     12     @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
     13     def test_recursive_inferior_crashing_dsym(self):
     14         """Test that lldb reliably catches the inferior crashing (command)."""
     15         self.buildDsym()
     16         self.recursive_inferior_crashing()
     17 
     18     @expectedFailureLinux('llvm.org/pr15415', ['gcc', 'clang']) # partial backtrace with -fomit-frame-pointer with tool-chains that support this option
     19     def test_recursive_inferior_crashing_dwarf(self):
     20         """Test that lldb reliably catches the inferior crashing (command)."""
     21         self.buildDwarf()
     22         self.recursive_inferior_crashing()
     23 
     24     @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
     25     def test_recursive_inferior_crashing_registers_dsym(self):
     26         """Test that lldb reliably reads registers from the inferior after crashing (command)."""
     27         self.buildDsym()
     28         self.recursive_inferior_crashing_registers()
     29 
     30     def test_recursive_inferior_crashing_register_dwarf(self):
     31         """Test that lldb reliably reads registers from the inferior after crashing (command)."""
     32         self.buildDwarf()
     33         self.recursive_inferior_crashing_registers()
     34 
     35     @python_api_test
     36     def test_recursive_inferior_crashing_python(self):
     37         """Test that lldb reliably catches the inferior crashing (Python API)."""
     38         self.buildDefault()
     39         self.recursive_inferior_crashing_python()
     40 
     41     @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
     42     def test_recursive_inferior_crashing_expr_dsym(self):
     43         """Test that the lldb expression interpreter can read from the inferior after crashing (command)."""
     44         self.buildDsym()
     45         self.recursive_inferior_crashing_expr()
     46 
     47     def test_recursive_inferior_crashing_expr_dwarf(self):
     48         """Test that the lldb expression interpreter can read from the inferior after crashing (command)."""
     49         self.buildDwarf()
     50         self.recursive_inferior_crashing_expr()
     51 
     52     @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
     53     def test_recursive_inferior_crashing_step_dsym(self):
     54         """Test that lldb functions correctly after stepping through a crash."""
     55         self.buildDsym()
     56         self.recursive_inferior_crashing_step()
     57 
     58     def test_recursive_inferior_crashing_step_dwarf(self):
     59         """Test that stepping after a crash behaves correctly."""
     60         self.buildDwarf()
     61         self.recursive_inferior_crashing_step()
     62 
     63     @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
     64     def test_recursive_inferior_crashing_step_after_break_dsym(self):
     65         """Test that stepping after a crash behaves correctly."""
     66         self.buildDsym()
     67         self.recursive_inferior_crashing_step_after_break()
     68 
     69     def test_recursive_inferior_crashing_step_after_break_dwarf(self):
     70         """Test that lldb functions correctly after stepping through a crash."""
     71         self.buildDwarf()
     72         self.recursive_inferior_crashing_step_after_break()
     73 
     74     @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
     75     def test_recursive_inferior_crashing_expr_step_and_expr_dsym(self):
     76         """Test that lldb expressions work before and after stepping after a crash."""
     77         self.buildDsym()
     78         self.recursive_inferior_crashing_expr_step_expr()
     79 
     80     @expectedFailureLinux # due to llvm.org/pr15415 with -fomit-frame-pointer, and pr15989 with ebp/rbp
     81     def test_recursive_inferior_crashing_expr_step_and_expr_dwarf(self):
     82         """Test that lldb expressions work before and after stepping after a crash."""
     83         self.buildDwarf()
     84         self.recursive_inferior_crashing_expr_step_expr()
     85 
     86     def set_breakpoint(self, line):
     87         lldbutil.run_break_set_by_file_and_line (self, "main.c", line, num_expected_locations=1, loc_exact=True)
     88 
     89     def check_stop_reason(self):
     90         if sys.platform.startswith("darwin"):
     91             stop_reason = 'stop reason = EXC_BAD_ACCESS'
     92         else:
     93             stop_reason = 'stop reason = invalid address'
     94 
     95         # The stop reason of the thread should be a bad access exception.
     96         self.expect("thread list", STOPPED_DUE_TO_EXC_BAD_ACCESS,
     97             substrs = ['stopped',
     98                        stop_reason])
     99 
    100         return stop_reason
    101 
    102     def setUp(self):
    103         # Call super's setUp().
    104         TestBase.setUp(self)
    105         # Find the line number of the crash.
    106         self.line = line_number('main.c', '// Crash here.')
    107 
    108     def recursive_inferior_crashing(self):
    109         """Inferior crashes upon launching; lldb should catch the event and stop."""
    110         exe = os.path.join(os.getcwd(), "a.out")
    111         self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
    112 
    113         self.runCmd("run", RUN_SUCCEEDED)
    114         stop_reason = self.check_stop_reason()
    115 
    116         # And it should report a backtrace that includes main and the crash site.
    117         self.expect("thread backtrace all",
    118             substrs = [stop_reason, 'main', 'argc', 'argv', 'recursive_function'])
    119 
    120         # And it should report the correct line number.
    121         self.expect("thread backtrace all",
    122             substrs = [stop_reason,
    123                        'main.c:%d' % self.line])
    124 
    125     def recursive_inferior_crashing_python(self):
    126         """Inferior crashes upon launching; lldb should catch the event and stop."""
    127         exe = os.path.join(os.getcwd(), "a.out")
    128 
    129         target = self.dbg.CreateTarget(exe)
    130         self.assertTrue(target, VALID_TARGET)
    131 
    132         # Now launch the process, and do not stop at entry point.
    133         # Both argv and envp are null.
    134         process = target.LaunchSimple(None, None, os.getcwd())
    135 
    136         if process.GetState() != lldb.eStateStopped:
    137             self.fail("Process should be in the 'stopped' state, "
    138                       "instead the actual state is: '%s'" %
    139                       lldbutil.state_type_to_str(process.GetState()))
    140 
    141         thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonException)
    142         if not thread:
    143             self.fail("Fail to stop the thread upon bad access exception")
    144 
    145         if self.TraceOn():
    146             lldbutil.print_stacktrace(thread)
    147 
    148     def recursive_inferior_crashing_registers(self):
    149         """Test that lldb can read registers after crashing."""
    150         exe = os.path.join(os.getcwd(), "a.out")
    151         self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
    152 
    153         self.runCmd("run", RUN_SUCCEEDED)
    154         self.check_stop_reason()
    155 
    156         # lldb should be able to read from registers from the inferior after crashing.
    157         self.expect("register read eax",
    158             substrs = ['eax = 0x'])
    159 
    160     def recursive_inferior_crashing_expr(self):
    161         """Test that the lldb expression interpreter can read symbols after crashing."""
    162         exe = os.path.join(os.getcwd(), "a.out")
    163         self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
    164 
    165         self.runCmd("run", RUN_SUCCEEDED)
    166         self.check_stop_reason()
    167 
    168         # The lldb expression interpreter should be able to read from addresses of the inferior after a crash.
    169         self.expect("p i",
    170             startstr = '(int) $0 =')
    171 
    172     def recursive_inferior_crashing_step(self):
    173         """Test that lldb functions correctly after stepping through a crash."""
    174         exe = os.path.join(os.getcwd(), "a.out")
    175         self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
    176 
    177         self.set_breakpoint(self.line)
    178         self.runCmd("run", RUN_SUCCEEDED)
    179 
    180         self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
    181             substrs = ['main.c:%d' % self.line,
    182                        'stop reason = breakpoint'])
    183 
    184         self.runCmd("next")
    185         stop_reason = self.check_stop_reason()
    186 
    187         # The lldb expression interpreter should be able to read from addresses of the inferior after a crash.
    188         self.expect("p i",
    189             substrs = ['(int) $0 ='])
    190 
    191         # lldb should be able to read from registers from the inferior after crashing.
    192         self.expect("register read eax",
    193             substrs = ['eax = 0x'])
    194 
    195         # And it should report the correct line number.
    196         self.expect("thread backtrace all",
    197             substrs = [stop_reason,
    198                        'main.c:%d' % self.line])
    199 
    200     def recursive_inferior_crashing_step_after_break(self):
    201         """Test that lldb behaves correctly when stepping after a crash."""
    202         exe = os.path.join(os.getcwd(), "a.out")
    203         self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
    204 
    205         self.runCmd("run", RUN_SUCCEEDED)
    206         self.check_stop_reason()
    207 
    208         expected_state = 'exited' # Provide the exit code.
    209         if sys.platform.startswith("darwin"):
    210             expected_state = 'stopped' # TODO: Determine why 'next' and 'continue' have no effect after a crash.
    211 
    212         self.expect("next",
    213             substrs = ['Process', expected_state])
    214 
    215         self.expect("thread list", error=True, 
    216             substrs = ['Process must be launched'])
    217 
    218     def recursive_inferior_crashing_expr_step_expr(self):
    219         """Test that lldb expressions work before and after stepping after a crash."""
    220         exe = os.path.join(os.getcwd(), "a.out")
    221         self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
    222 
    223         self.runCmd("run", RUN_SUCCEEDED)
    224         self.check_stop_reason()
    225 
    226         # The lldb expression interpreter should be able to read from addresses of the inferior after a crash.
    227         self.expect("p null",
    228             startstr = '(char *) $0 = 0x0')
    229 
    230         self.runCmd("next")
    231 
    232         # The lldb expression interpreter should be able to read from addresses of the inferior after a step.
    233         self.expect("p null",
    234             startstr = '(char *) $1 = 0x0')
    235 
    236         self.check_stop_reason()
    237 
    238 if __name__ == '__main__':
    239     import atexit
    240     lldb.SBDebugger.Initialize()
    241     atexit.register(lambda: lldb.SBDebugger.Terminate())
    242     unittest2.main()
    243