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