1"""
2Use lldb Python SBFrame API to get the argument values of the call stacks.
3And other SBFrame API tests.
4"""
5
6import os, time
7import re
8import unittest2
9import lldb, lldbutil
10from lldbtest import *
11
12class FrameAPITestCase(TestBase):
13
14    mydir = os.path.join("python_api", "frame")
15
16    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
17    @python_api_test
18    @dsym_test
19    def test_get_arg_vals_for_call_stack_with_dsym(self):
20        """Exercise SBFrame.GetVariables() API to get argument vals."""
21        self.buildDsym()
22        self.do_get_arg_vals()
23
24    @python_api_test
25    @dwarf_test
26    def test_get_arg_vals_for_call_stack_with_dwarf(self):
27        """Exercise SBFrame.GetVariables() API to get argument vals."""
28        self.buildDwarf()
29        self.do_get_arg_vals()
30
31    @python_api_test
32    def test_frame_api_boundary_condition(self):
33        """Exercise SBFrame APIs with boundary condition inputs."""
34        self.buildDefault()
35        self.frame_api_boundary_condition()
36
37    @python_api_test
38    def test_frame_api_IsEqual(self):
39        """Exercise SBFrame API IsEqual."""
40        self.buildDefault()
41        self.frame_api_IsEqual()
42
43    def do_get_arg_vals(self):
44        """Get argument vals for the call stack when stopped on a breakpoint."""
45        exe = os.path.join(os.getcwd(), "a.out")
46
47        # Create a target by the debugger.
48        target = self.dbg.CreateTarget(exe)
49        self.assertTrue(target, VALID_TARGET)
50
51        # Now create a breakpoint on main.c by name 'c'.
52        breakpoint = target.BreakpointCreateByName('c', 'a.out')
53        #print "breakpoint:", breakpoint
54        self.assertTrue(breakpoint and
55                        breakpoint.GetNumLocations() == 1,
56                        VALID_BREAKPOINT)
57
58        # Now launch the process, and do not stop at the entry point.
59        process = target.LaunchSimple(None, None, os.getcwd())
60
61        process = target.GetProcess()
62        self.assertTrue(process.GetState() == lldb.eStateStopped,
63                        PROCESS_STOPPED)
64
65        # Keeps track of the number of times 'a' is called where it is within a
66        # depth of 3 of the 'c' leaf function.
67        callsOfA = 0
68
69        import StringIO
70        session = StringIO.StringIO()
71        while process.GetState() == lldb.eStateStopped:
72            thread = process.GetThreadAtIndex(0)
73            # Inspect at most 3 frames.
74            numFrames = min(3, thread.GetNumFrames())
75            for i in range(numFrames):
76                frame = thread.GetFrameAtIndex(i)
77                if self.TraceOn():
78                    print "frame:", frame
79
80                name = frame.GetFunction().GetName()
81                if name == 'a':
82                    callsOfA = callsOfA + 1
83
84                # We'll inspect only the arguments for the current frame:
85                #
86                # arguments     => True
87                # locals        => False
88                # statics       => False
89                # in_scope_only => True
90                valList = frame.GetVariables(True, False, False, True)
91                argList = []
92                for val in valList:
93                    argList.append("(%s)%s=%s" % (val.GetTypeName(),
94                                                  val.GetName(),
95                                                  val.GetValue()))
96                print >> session, "%s(%s)" % (name, ", ".join(argList))
97
98                # Also check the generic pc & stack pointer.  We can't test their absolute values,
99                # but they should be valid.  Uses get_GPRs() from the lldbutil module.
100                gpr_reg_set = lldbutil.get_GPRs(frame)
101                pc_value = gpr_reg_set.GetChildMemberWithName("pc")
102                self.assertTrue (pc_value, "We should have a valid PC.")
103                self.assertTrue (int(pc_value.GetValue(), 0) == frame.GetPC(), "PC gotten as a value should equal frame's GetPC")
104                sp_value = gpr_reg_set.GetChildMemberWithName("sp")
105                self.assertTrue (sp_value, "We should have a valid Stack Pointer.")
106                self.assertTrue (int(sp_value.GetValue(), 0) == frame.GetSP(), "SP gotten as a value should equal frame's GetSP")
107
108            print >> session, "---"
109            process.Continue()
110
111        # At this point, the inferior process should have exited.
112        self.assertTrue(process.GetState() == lldb.eStateExited, PROCESS_EXITED)
113
114        # Expect to find 'a' on the call stacks two times.
115        self.assertTrue(callsOfA == 2,
116                        "Expect to find 'a' on the call stacks two times")
117        # By design, the 'a' call frame has the following arg vals:
118        #     o a((int)val=1, (char)ch='A')
119        #     o a((int)val=3, (char)ch='A')
120        if self.TraceOn():
121            print "Full stack traces when stopped on the breakpoint 'c':"
122            print session.getvalue()
123        self.expect(session.getvalue(), "Argugment values displayed correctly",
124                    exe=False,
125            substrs = ["a((int)val=1, (char)ch='A')",
126                       "a((int)val=3, (char)ch='A')"])
127
128    def frame_api_boundary_condition(self):
129        exe = os.path.join(os.getcwd(), "a.out")
130
131        # Create a target by the debugger.
132        target = self.dbg.CreateTarget(exe)
133        self.assertTrue(target, VALID_TARGET)
134
135        # Now create a breakpoint on main.c by name 'c'.
136        breakpoint = target.BreakpointCreateByName('c', 'a.out')
137        #print "breakpoint:", breakpoint
138        self.assertTrue(breakpoint and
139                        breakpoint.GetNumLocations() == 1,
140                        VALID_BREAKPOINT)
141
142        # Now launch the process, and do not stop at the entry point.
143        process = target.LaunchSimple(None, None, os.getcwd())
144
145        process = target.GetProcess()
146        self.assertTrue(process.GetState() == lldb.eStateStopped,
147                        PROCESS_STOPPED)
148
149        thread = process.GetThreadAtIndex(0)
150        frame = thread.GetFrameAtIndex(0)
151        if self.TraceOn():
152            print "frame:", frame
153
154        # Boundary condition testings.
155        val1 = frame.FindVariable(None, True)
156        val2 = frame.FindVariable(None, False)
157        val3 = frame.FindValue(None, lldb.eValueTypeVariableGlobal)
158        if self.TraceOn():
159            print "val1:", val1
160            print "val2:", val2
161
162        frame.EvaluateExpression(None)
163
164    def frame_api_IsEqual(self):
165        """Exercise SBFrame API IsEqual."""
166        exe = os.path.join(os.getcwd(), "a.out")
167
168        # Create a target by the debugger.
169        target = self.dbg.CreateTarget(exe)
170        self.assertTrue(target, VALID_TARGET)
171
172        # Now create a breakpoint on main.c by name 'c'.
173        breakpoint = target.BreakpointCreateByName('c', 'a.out')
174        #print "breakpoint:", breakpoint
175        self.assertTrue(breakpoint and
176                        breakpoint.GetNumLocations() == 1,
177                        VALID_BREAKPOINT)
178
179        # Now launch the process, and do not stop at the entry point.
180        process = target.LaunchSimple(None, None, os.getcwd())
181
182        process = target.GetProcess()
183        self.assertTrue(process.GetState() == lldb.eStateStopped,
184                        PROCESS_STOPPED)
185
186        thread = process.GetThreadAtIndex(0)
187        self.assertTrue(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
219
220if __name__ == '__main__':
221    import atexit
222    lldb.SBDebugger.Initialize()
223    atexit.register(lambda: lldb.SBDebugger.Terminate())
224    unittest2.main()
225