1"""Test that lldb functions correctly after the inferior has crashed while in a recursive routine."""
2
3import os, time
4import unittest2
5import lldb, lldbutil
6from lldbtest import *
7
8class 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
238if __name__ == '__main__':
239    import atexit
240    lldb.SBDebugger.Initialize()
241    atexit.register(lambda: lldb.SBDebugger.Terminate())
242    unittest2.main()
243