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