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