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