xref: /llvm-project/lldb/test/API/python_api/frame/TestFrames.py (revision 56f9cfe30c4488aade888905bb6280ecb952a613)
1"""
2Use lldb Python SBFrame API to get the argument values of the call stacks.
3And other SBFrame API tests.
4"""
5
6from __future__ import print_function
7
8import io
9
10import lldb
11from lldbsuite.test.decorators import *
12from lldbsuite.test.lldbtest import *
13from lldbsuite.test import lldbutil
14
15
16class FrameAPITestCase(TestBase):
17
18    def test_get_arg_vals_for_call_stack(self):
19        """Exercise SBFrame.GetVariables() API to get argument vals."""
20        self.build()
21        exe = self.getBuildArtifact("a.out")
22
23        # Create a target by the debugger.
24        target = self.dbg.CreateTarget(exe)
25        self.assertTrue(target, VALID_TARGET)
26
27        # Now create a breakpoint on main.c by name 'c'.
28        breakpoint = target.BreakpointCreateByName('c', 'a.out')
29        self.trace("breakpoint:", breakpoint)
30        self.assertTrue(breakpoint and
31                        breakpoint.GetNumLocations() == 1,
32                        VALID_BREAKPOINT)
33
34        # Now launch the process, and do not stop at the entry point.
35        process = target.LaunchSimple(
36            None, None, self.get_process_working_directory())
37
38        process = target.GetProcess()
39        self.assertState(process.GetState(), lldb.eStateStopped,
40                         PROCESS_STOPPED)
41
42        # Keeps track of the number of times 'a' is called where it is within a
43        # depth of 3 of the 'c' leaf function.
44        callsOfA = 0
45
46        session = io.StringIO()
47        while process.GetState() == lldb.eStateStopped:
48            thread = lldbutil.get_stopped_thread(
49                process, lldb.eStopReasonBreakpoint)
50            self.assertIsNotNone(thread)
51            # Inspect at most 3 frames.
52            numFrames = min(3, thread.GetNumFrames())
53            for i in range(numFrames):
54                frame = thread.GetFrameAtIndex(i)
55                if self.TraceOn():
56                    print("frame:", frame)
57
58                name = frame.GetFunction().GetName()
59                if name == 'a':
60                    callsOfA = callsOfA + 1
61
62                # We'll inspect only the arguments for the current frame:
63                #
64                # arguments     => True
65                # locals        => False
66                # statics       => False
67                # in_scope_only => True
68                valList = frame.GetVariables(True, False, False, True)
69                argList = []
70                for val in valList:
71                    argList.append("(%s)%s=%s" % (val.GetTypeName(),
72                                                  val.GetName(),
73                                                  val.GetValue()))
74                print("%s(%s)" % (name, ", ".join(argList)), file=session)
75
76                # Also check the generic pc & stack pointer.  We can't test their absolute values,
77                # but they should be valid.  Uses get_GPRs() from the lldbutil
78                # module.
79                gpr_reg_set = lldbutil.get_GPRs(frame)
80                pc_value = gpr_reg_set.GetChildMemberWithName("pc")
81                self.assertTrue(pc_value, "We should have a valid PC.")
82                pc_value_int = int(pc_value.GetValue(), 0)
83                # Make sure on arm targets we dont mismatch PC value on the basis of thumb bit.
84                # Frame PC will not have thumb bit set in case of a thumb
85                # instruction as PC.
86                if self.getArchitecture() in ['arm', 'armv7', 'armv7k']:
87                    pc_value_int &= ~1
88                self.assertEqual(
89                    pc_value_int, frame.GetPC(),
90                    "PC gotten as a value should equal frame's GetPC")
91                sp_value = gpr_reg_set.GetChildMemberWithName("sp")
92                self.assertTrue(
93                    sp_value, "We should have a valid Stack Pointer.")
94                self.assertEqual(
95                    int(sp_value.GetValue(), 0), frame.GetSP(),
96                    "SP gotten as a value should equal frame's GetSP")
97
98            print("---", file=session)
99            process.Continue()
100
101        # At this point, the inferior process should have exited.
102        self.assertEqual(
103            process.GetState(), lldb.eStateExited,
104            PROCESS_EXITED)
105
106        # Expect to find 'a' on the call stacks two times.
107        self.assertEqual(callsOfA, 2,
108                        "Expect to find 'a' on the call stacks two times")
109        # By design, the 'a' call frame has the following arg vals:
110        #     o a((int)val=1, (char)ch='A')
111        #     o a((int)val=3, (char)ch='A')
112        if self.TraceOn():
113            print("Full stack traces when stopped on the breakpoint 'c':")
114            print(session.getvalue())
115        self.expect(session.getvalue(), "Argument values displayed correctly",
116                    exe=False,
117                    substrs=["a((int)val=1, (char)ch='A')",
118                             "a((int)val=3, (char)ch='A')"])
119
120    def test_frame_api_boundary_condition(self):
121        """Exercise SBFrame APIs with boundary condition inputs."""
122        self.build()
123        exe = self.getBuildArtifact("a.out")
124
125        # Create a target by the debugger.
126        target = self.dbg.CreateTarget(exe)
127        self.assertTrue(target, VALID_TARGET)
128
129        # Now create a breakpoint on main.c by name 'c'.
130        breakpoint = target.BreakpointCreateByName('c', 'a.out')
131        self.trace("breakpoint:", breakpoint)
132        self.assertTrue(breakpoint and
133                        breakpoint.GetNumLocations() == 1,
134                        VALID_BREAKPOINT)
135
136        # Now launch the process, and do not stop at the entry point.
137        process = target.LaunchSimple(
138            None, None, self.get_process_working_directory())
139
140        process = target.GetProcess()
141        self.assertState(process.GetState(), lldb.eStateStopped,
142                         PROCESS_STOPPED)
143
144        thread = lldbutil.get_stopped_thread(
145            process, lldb.eStopReasonBreakpoint)
146        self.assertIsNotNone(thread)
147        frame = thread.GetFrameAtIndex(0)
148        if self.TraceOn():
149            print("frame:", frame)
150
151        # Boundary condition testings.
152        val1 = frame.FindVariable(None, True)
153        val2 = frame.FindVariable(None, False)
154        val3 = frame.FindValue(None, lldb.eValueTypeVariableGlobal)
155        if self.TraceOn():
156            print("val1:", val1)
157            print("val2:", val2)
158
159        frame.EvaluateExpression(None)
160
161    def test_frame_api_IsEqual(self):
162        """Exercise SBFrame API IsEqual."""
163        self.build()
164        exe = self.getBuildArtifact("a.out")
165
166        # Create a target by the debugger.
167        target = self.dbg.CreateTarget(exe)
168        self.assertTrue(target, VALID_TARGET)
169
170        # Now create a breakpoint on main.c by name 'c'.
171        breakpoint = target.BreakpointCreateByName('c', 'a.out')
172        self.trace("breakpoint:", breakpoint)
173        self.assertTrue(breakpoint and
174                        breakpoint.GetNumLocations() == 1,
175                        VALID_BREAKPOINT)
176
177        # Now launch the process, and do not stop at the entry point.
178        process = target.LaunchSimple(
179            None, None, self.get_process_working_directory())
180
181        process = target.GetProcess()
182        self.assertState(process.GetState(), lldb.eStateStopped,
183                         PROCESS_STOPPED)
184
185        thread = lldbutil.get_stopped_thread(
186            process, lldb.eStopReasonBreakpoint)
187        self.assertIsNotNone(thread)
188
189        frameEntered = thread.GetFrameAtIndex(0)
190        if self.TraceOn():
191            print(frameEntered)
192            lldbutil.print_stacktrace(thread)
193        self.assertTrue(frameEntered)
194
195        # Doing two step overs while still inside c().
196        thread.StepOver()
197        thread.StepOver()
198        self.assertTrue(thread)
199        frameNow = thread.GetFrameAtIndex(0)
200        if self.TraceOn():
201            print(frameNow)
202            lldbutil.print_stacktrace(thread)
203        self.assertTrue(frameNow)
204
205        # The latest two frames are considered equal.
206        self.assertTrue(frameEntered.IsEqual(frameNow))
207
208        # Now let's step out of frame c().
209        thread.StepOutOfFrame(frameNow)
210        frameOutOfC = thread.GetFrameAtIndex(0)
211        if self.TraceOn():
212            print(frameOutOfC)
213            lldbutil.print_stacktrace(thread)
214        self.assertTrue(frameOutOfC)
215
216        # The latest two frames should not be equal.
217        self.assertFalse(frameOutOfC.IsEqual(frameNow))
218