1"""Test that lldb steps correctly after the inferior has crashed while in a recursive routine."""
2
3
4import lldb
5from lldbsuite.test.decorators import *
6from lldbsuite.test.lldbtest import *
7from lldbsuite.test import lldbplatformutil
8from lldbsuite.test import lldbutil
9
10
11class CrashingRecursiveInferiorStepTestCase(TestBase):
12
13    mydir = TestBase.compute_mydir(__file__)
14
15    def test_recursive_inferior_crashing_step(self):
16        """Test that stepping after a crash behaves correctly."""
17        self.build()
18        self.recursive_inferior_crashing_step()
19
20    @skipIfTargetAndroid()  # debuggerd interferes with this test on Android
21    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24778")
22    @expectedFailureNetBSD
23    def test_recursive_inferior_crashing_step_after_break(self):
24        """Test that lldb functions correctly after stepping through a crash."""
25        self.build()
26        self.recursive_inferior_crashing_step_after_break()
27
28    # Inferior exits after stepping after a segfault. This is working as
29    # intended IMHO.
30    @skipIf(oslist=["freebsd", "linux", "netbsd"])
31    def test_recursive_inferior_crashing_expr_step_and_expr(self):
32        """Test that lldb expressions work before and after stepping after a crash."""
33        self.build()
34        self.recursive_inferior_crashing_expr_step_expr()
35
36    def set_breakpoint(self, line):
37        lldbutil.run_break_set_by_file_and_line(
38            self, "main.c", line, num_expected_locations=1, loc_exact=True)
39
40    def check_stop_reason(self):
41        # We should have one crashing thread
42        self.assertEqual(
43            len(
44                lldbutil.get_crashed_threads(
45                    self,
46                    self.dbg.GetSelectedTarget().GetProcess())), 1,
47            STOPPED_DUE_TO_EXC_BAD_ACCESS)
48
49    def setUp(self):
50        # Call super's setUp().
51        TestBase.setUp(self)
52        # Find the line number of the crash.
53        self.line = line_number('main.c', '// Crash here.')
54
55    def recursive_inferior_crashing_step(self):
56        """Test that lldb functions correctly after stepping through a crash."""
57        exe = self.getBuildArtifact("a.out")
58        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
59
60        self.set_breakpoint(self.line)
61        self.runCmd("run", RUN_SUCCEEDED)
62
63        self.expect(
64            "thread list",
65            STOPPED_DUE_TO_BREAKPOINT,
66            substrs=['main.c:%d' % self.line, 'stop reason = breakpoint'])
67
68        self.runCmd("next")
69        self.check_stop_reason()
70
71        # The lldb expression interpreter should be able to read from addresses
72        # of the inferior after a crash.
73        self.expect("p i", substrs=['(int) $0 ='])
74
75        # lldb should be able to read from registers from the inferior after
76        # crashing.
77        lldbplatformutil.check_first_register_readable(self)
78
79        # And it should report the correct line number.
80        self.expect("thread backtrace all", substrs=['main.c:%d' % self.line])
81
82    def recursive_inferior_crashing_step_after_break(self):
83        """Test that lldb behaves correctly when stepping after a crash."""
84        exe = self.getBuildArtifact("a.out")
85        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
86
87        self.runCmd("run", RUN_SUCCEEDED)
88        self.check_stop_reason()
89
90        expected_state = 'exited'  # Provide the exit code.
91        if self.platformIsDarwin():
92            # TODO: Determine why 'next' and 'continue' have no effect after a
93            # crash.
94            expected_state = 'stopped'
95
96        self.expect("next", substrs=['Process', expected_state])
97
98        if expected_state == 'exited':
99            self.expect(
100                "thread list",
101                error=True,
102                substrs=['Process must be launched'])
103        else:
104            self.check_stop_reason()
105
106    def recursive_inferior_crashing_expr_step_expr(self):
107        """Test that lldb expressions work before and after stepping after a crash."""
108        exe = self.getBuildArtifact("a.out")
109        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
110
111        self.runCmd("run", RUN_SUCCEEDED)
112        self.check_stop_reason()
113
114        # The lldb expression interpreter should be able to read from addresses
115        # of the inferior after a crash.
116        self.expect("p null", startstr='(char *) $0 = 0x0')
117
118        self.runCmd("next")
119
120        # The lldb expression interpreter should be able to read from addresses
121        # of the inferior after a step.
122        self.expect("p null", startstr='(char *) $1 = 0x0')
123
124        self.check_stop_reason()
125