xref: /llvm-project/lldb/test/API/functionalities/exec/TestExec.py (revision 2238dcc39358353cac21df75c3c3286ab20b8f53)
1"""
2Test some lldb command abbreviations.
3"""
4
5import lldb
6from lldbsuite.test.decorators import *
7from lldbsuite.test.lldbtest import *
8from lldbsuite.test import lldbutil
9
10
11class ExecTestCase(TestBase):
12    NO_DEBUG_INFO_TESTCASE = True
13
14    @expectedFailureAll(
15        archs=["i386"], oslist=no_match(["freebsd"]), bugnumber="rdar://28656532"
16    )
17    @expectedFailureAll(
18        oslist=["ios", "tvos", "watchos", "bridgeos"],
19        bugnumber="rdar://problem/34559552",
20    )  # this exec test has problems on ios systems
21    @expectedFailureNetBSD
22    @skipIfAsan  # rdar://problem/43756823
23    @skipIfWindows
24    def test_hitting_exec(self):
25        self.do_test(False)
26
27    @expectedFailureAll(
28        archs=["i386"], oslist=no_match(["freebsd"]), bugnumber="rdar://28656532"
29    )
30    @expectedFailureAll(
31        oslist=["ios", "tvos", "watchos", "bridgeos"],
32        bugnumber="rdar://problem/34559552",
33    )  # this exec test has problems on ios systems
34    @expectedFailureNetBSD
35    @skipIfAsan  # rdar://problem/43756823
36    @skipIfWindows
37    def test_skipping_exec(self):
38        self.do_test(True)
39
40    def do_test(self, skip_exec):
41        self.build()
42        exe = self.getBuildArtifact("a.out")
43        secondprog = self.getBuildArtifact("secondprog")
44
45        # Create the target
46        target = self.dbg.CreateTarget(exe)
47
48        # Create any breakpoints we need
49        breakpoint1 = target.BreakpointCreateBySourceRegex(
50            "Set breakpoint 1 here", lldb.SBFileSpec("main.c", False)
51        )
52        self.assertTrue(breakpoint1, VALID_BREAKPOINT)
53        breakpoint2 = target.BreakpointCreateBySourceRegex(
54            "Set breakpoint 2 here", lldb.SBFileSpec("secondprog.cpp", False)
55        )
56        self.assertTrue(breakpoint2, VALID_BREAKPOINT)
57
58        # Launch the process
59        process = target.LaunchSimple(None, None, self.get_process_working_directory())
60        self.assertTrue(process, PROCESS_IS_VALID)
61
62        if self.TraceOn():
63            self.runCmd("settings show target.process.stop-on-exec", check=False)
64        if skip_exec:
65            self.dbg.HandleCommand("settings set target.process.stop-on-exec false")
66
67            def cleanup():
68                self.runCmd(
69                    "settings set target.process.stop-on-exec false", check=False
70                )
71
72            # Execute the cleanup function during test case tear down.
73            self.addTearDownHook(cleanup)
74
75        # The stop reason of the thread should be breakpoint.
76        self.assertState(
77            process.GetState(), lldb.eStateStopped, STOPPED_DUE_TO_BREAKPOINT
78        )
79
80        threads = lldbutil.get_threads_stopped_at_breakpoint(process, breakpoint1)
81        self.assertEqual(len(threads), 1)
82
83        # We had a deadlock tearing down the TypeSystemMap on exec, but only if some
84        # expression had been evaluated.  So make sure we do that here so the teardown
85        # is not trivial.
86
87        thread = threads[0]
88        value = thread.frames[0].EvaluateExpression("1 + 2")
89        self.assertTrue(value.IsValid(), "Expression evaluated successfully")
90        int_value = value.GetValueAsSigned()
91        self.assertEqual(int_value, 3, "Expression got the right result.")
92
93        # Run and we should stop due to exec
94        process.Continue()
95
96        if not skip_exec:
97            self.assertNotEqual(
98                process.GetState(), lldb.eStateExited, "Process should not have exited!"
99            )
100            self.assertState(
101                process.GetState(),
102                lldb.eStateStopped,
103                "Process should be stopped at __dyld_start",
104            )
105
106            threads = lldbutil.get_stopped_threads(process, lldb.eStopReasonExec)
107            self.assertEqual(len(threads), 1, "We got a thread stopped for exec.")
108
109            # Run and we should stop at breakpoint in main after exec
110            process.Continue()
111
112        self.assertState(process.GetState(), lldb.eStateStopped)
113        for t in process.threads:
114            if t.stop_reason != lldb.eStopReasonNone:
115                self.assertStopReason(
116                    t.stop_reason, lldb.eStopReasonBreakpoint, "Unexpected stop reason"
117                )
118                if self.TraceOn():
119                    print(t)
120                    if t.stop_reason != lldb.eStopReasonBreakpoint:
121                        self.runCmd("bt")
122
123        threads = lldbutil.get_threads_stopped_at_breakpoint(process, breakpoint2)
124        self.assertEqual(len(threads), 1, "Stopped at breakpoint in exec'ed process.")
125
126    @expectedFailureAll(
127        archs=["i386"], oslist=no_match(["freebsd"]), bugnumber="rdar://28656532"
128    )
129    @expectedFailureAll(
130        oslist=["ios", "tvos", "watchos", "bridgeos"],
131        bugnumber="rdar://problem/34559552",
132    )  # this exec test has problems on ios systems
133    @expectedFailureNetBSD
134    @skipIfAsan  # rdar://problem/43756823
135    @skipIfWindows
136    def test_correct_thread_plan_state_before_exec(self):
137        """
138        In this test we make sure that the Thread* cache in the ThreadPlans
139        is cleared correctly when performing exec
140        """
141
142        self.build()
143        exe = self.getBuildArtifact("a.out")
144        target = self.dbg.CreateTarget(exe)
145
146        (target, process, thread, breakpoint1) = lldbutil.run_to_source_breakpoint(
147            self, "Set breakpoint 1 here", lldb.SBFileSpec("main.c", False)
148        )
149
150        # The stop reason of the thread should be breakpoint.
151        self.assertState(
152            process.GetState(), lldb.eStateStopped, STOPPED_DUE_TO_BREAKPOINT
153        )
154
155        threads = lldbutil.get_threads_stopped_at_breakpoint(process, breakpoint1)
156        self.assertEqual(len(threads), 1)
157
158        # We perform an instruction step, which effectively sets the cache of the base
159        # thread plan, which should be cleared when a new thread list appears.
160        #
161        # Continuing after this instruction step will trigger a call to
162        # ThreadPlan::ShouldReportRun, which sets the ThreadPlan's Thread cache to
163        # the old Thread* value. In Process::UpdateThreadList we are clearing this
164        # cache in preparation for the new ThreadList.
165        #
166        # Not doing this stepping will cause LLDB to first execute a private single step
167        # past the current breakpoint, which eventually avoids the call to ShouldReportRun,
168        # thus not setting the cache to its invalid value.
169        thread.StepInstruction(False)
170
171        # Run and we should stop due to exec
172        breakpoint2 = target.BreakpointCreateBySourceRegex(
173            "Set breakpoint 2 here", lldb.SBFileSpec("secondprog.cpp", False)
174        )
175
176        process.Continue()
177
178        self.assertNotEqual(
179            process.GetState(), lldb.eStateExited, "Process should not have exited!"
180        )
181        self.assertState(
182            process.GetState(),
183            lldb.eStateStopped,
184            "Process should be stopped at __dyld_start",
185        )
186
187        threads = lldbutil.get_stopped_threads(process, lldb.eStopReasonExec)
188        self.assertEqual(len(threads), 1, "We got a thread stopped for exec.")
189
190        # Run and we should stop at breakpoint in main after exec
191        process.Continue()
192
193        threads = lldbutil.get_threads_stopped_at_breakpoint(process, breakpoint2)
194        self.assertEqual(len(threads), 1, "Stopped at breakpoint in exec'ed process.")
195