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