199451b44SJordan Rupprecht"""
299451b44SJordan RupprechtUse lldb Python SBFrame API to get the argument values of the call stacks.
399451b44SJordan RupprechtAnd other SBFrame API tests.
499451b44SJordan Rupprecht"""
599451b44SJordan Rupprecht
699451b44SJordan Rupprechtfrom __future__ import print_function
799451b44SJordan Rupprecht
899451b44SJordan Rupprecht
999451b44SJordan Rupprechtimport lldb
1099451b44SJordan Rupprechtfrom lldbsuite.test.decorators import *
1199451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import *
1299451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil
1399451b44SJordan Rupprecht
1499451b44SJordan Rupprecht
1599451b44SJordan Rupprechtclass FrameAPITestCase(TestBase):
1699451b44SJordan Rupprecht
1799451b44SJordan Rupprecht    mydir = TestBase.compute_mydir(__file__)
1899451b44SJordan Rupprecht
1999451b44SJordan Rupprecht    @add_test_categories(['pyapi'])
2099451b44SJordan Rupprecht    def test_get_arg_vals_for_call_stack(self):
2199451b44SJordan Rupprecht        """Exercise SBFrame.GetVariables() API to get argument vals."""
2299451b44SJordan Rupprecht        self.build()
2399451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
2499451b44SJordan Rupprecht
2599451b44SJordan Rupprecht        # Create a target by the debugger.
2699451b44SJordan Rupprecht        target = self.dbg.CreateTarget(exe)
2799451b44SJordan Rupprecht        self.assertTrue(target, VALID_TARGET)
2899451b44SJordan Rupprecht
2999451b44SJordan Rupprecht        # Now create a breakpoint on main.c by name 'c'.
3099451b44SJordan Rupprecht        breakpoint = target.BreakpointCreateByName('c', 'a.out')
31*b321b429SJonas Devlieghere        self.trace("breakpoint:", breakpoint)
3299451b44SJordan Rupprecht        self.assertTrue(breakpoint and
3399451b44SJordan Rupprecht                        breakpoint.GetNumLocations() == 1,
3499451b44SJordan Rupprecht                        VALID_BREAKPOINT)
3599451b44SJordan Rupprecht
3699451b44SJordan Rupprecht        # Now launch the process, and do not stop at the entry point.
3799451b44SJordan Rupprecht        process = target.LaunchSimple(
3899451b44SJordan Rupprecht            None, None, self.get_process_working_directory())
3999451b44SJordan Rupprecht
4099451b44SJordan Rupprecht        process = target.GetProcess()
4199451b44SJordan Rupprecht        self.assertTrue(process.GetState() == lldb.eStateStopped,
4299451b44SJordan Rupprecht                        PROCESS_STOPPED)
4399451b44SJordan Rupprecht
4499451b44SJordan Rupprecht        # Keeps track of the number of times 'a' is called where it is within a
4599451b44SJordan Rupprecht        # depth of 3 of the 'c' leaf function.
4699451b44SJordan Rupprecht        callsOfA = 0
4799451b44SJordan Rupprecht
4899451b44SJordan Rupprecht        from six import StringIO as SixStringIO
4999451b44SJordan Rupprecht        session = SixStringIO()
5099451b44SJordan Rupprecht        while process.GetState() == lldb.eStateStopped:
5199451b44SJordan Rupprecht            thread = lldbutil.get_stopped_thread(
5299451b44SJordan Rupprecht                process, lldb.eStopReasonBreakpoint)
5399451b44SJordan Rupprecht            self.assertIsNotNone(thread)
5499451b44SJordan Rupprecht            # Inspect at most 3 frames.
5599451b44SJordan Rupprecht            numFrames = min(3, thread.GetNumFrames())
5699451b44SJordan Rupprecht            for i in range(numFrames):
5799451b44SJordan Rupprecht                frame = thread.GetFrameAtIndex(i)
5899451b44SJordan Rupprecht                if self.TraceOn():
5999451b44SJordan Rupprecht                    print("frame:", frame)
6099451b44SJordan Rupprecht
6199451b44SJordan Rupprecht                name = frame.GetFunction().GetName()
6299451b44SJordan Rupprecht                if name == 'a':
6399451b44SJordan Rupprecht                    callsOfA = callsOfA + 1
6499451b44SJordan Rupprecht
6599451b44SJordan Rupprecht                # We'll inspect only the arguments for the current frame:
6699451b44SJordan Rupprecht                #
6799451b44SJordan Rupprecht                # arguments     => True
6899451b44SJordan Rupprecht                # locals        => False
6999451b44SJordan Rupprecht                # statics       => False
7099451b44SJordan Rupprecht                # in_scope_only => True
7199451b44SJordan Rupprecht                valList = frame.GetVariables(True, False, False, True)
7299451b44SJordan Rupprecht                argList = []
7399451b44SJordan Rupprecht                for val in valList:
7499451b44SJordan Rupprecht                    argList.append("(%s)%s=%s" % (val.GetTypeName(),
7599451b44SJordan Rupprecht                                                  val.GetName(),
7699451b44SJordan Rupprecht                                                  val.GetValue()))
7799451b44SJordan Rupprecht                print("%s(%s)" % (name, ", ".join(argList)), file=session)
7899451b44SJordan Rupprecht
7999451b44SJordan Rupprecht                # Also check the generic pc & stack pointer.  We can't test their absolute values,
8099451b44SJordan Rupprecht                # but they should be valid.  Uses get_GPRs() from the lldbutil
8199451b44SJordan Rupprecht                # module.
8299451b44SJordan Rupprecht                gpr_reg_set = lldbutil.get_GPRs(frame)
8399451b44SJordan Rupprecht                pc_value = gpr_reg_set.GetChildMemberWithName("pc")
8499451b44SJordan Rupprecht                self.assertTrue(pc_value, "We should have a valid PC.")
8599451b44SJordan Rupprecht                pc_value_int = int(pc_value.GetValue(), 0)
8699451b44SJordan Rupprecht                # Make sure on arm targets we dont mismatch PC value on the basis of thumb bit.
8799451b44SJordan Rupprecht                # Frame PC will not have thumb bit set in case of a thumb
8899451b44SJordan Rupprecht                # instruction as PC.
8999451b44SJordan Rupprecht                if self.getArchitecture() in ['arm', 'armv7', 'armv7k']:
9099451b44SJordan Rupprecht                    pc_value_int &= ~1
9199451b44SJordan Rupprecht                self.assertTrue(
9299451b44SJordan Rupprecht                    pc_value_int == frame.GetPC(),
9399451b44SJordan Rupprecht                    "PC gotten as a value should equal frame's GetPC")
9499451b44SJordan Rupprecht                sp_value = gpr_reg_set.GetChildMemberWithName("sp")
9599451b44SJordan Rupprecht                self.assertTrue(
9699451b44SJordan Rupprecht                    sp_value, "We should have a valid Stack Pointer.")
9799451b44SJordan Rupprecht                self.assertTrue(int(sp_value.GetValue(), 0) == frame.GetSP(
9899451b44SJordan Rupprecht                ), "SP gotten as a value should equal frame's GetSP")
9999451b44SJordan Rupprecht
10099451b44SJordan Rupprecht            print("---", file=session)
10199451b44SJordan Rupprecht            process.Continue()
10299451b44SJordan Rupprecht
10399451b44SJordan Rupprecht        # At this point, the inferior process should have exited.
10499451b44SJordan Rupprecht        self.assertTrue(
10599451b44SJordan Rupprecht            process.GetState() == lldb.eStateExited,
10699451b44SJordan Rupprecht            PROCESS_EXITED)
10799451b44SJordan Rupprecht
10899451b44SJordan Rupprecht        # Expect to find 'a' on the call stacks two times.
10999451b44SJordan Rupprecht        self.assertTrue(callsOfA == 2,
11099451b44SJordan Rupprecht                        "Expect to find 'a' on the call stacks two times")
11199451b44SJordan Rupprecht        # By design, the 'a' call frame has the following arg vals:
11299451b44SJordan Rupprecht        #     o a((int)val=1, (char)ch='A')
11399451b44SJordan Rupprecht        #     o a((int)val=3, (char)ch='A')
11499451b44SJordan Rupprecht        if self.TraceOn():
11599451b44SJordan Rupprecht            print("Full stack traces when stopped on the breakpoint 'c':")
11699451b44SJordan Rupprecht            print(session.getvalue())
117e9264b74SKazuaki Ishizaki        self.expect(session.getvalue(), "Argument values displayed correctly",
11899451b44SJordan Rupprecht                    exe=False,
11999451b44SJordan Rupprecht                    substrs=["a((int)val=1, (char)ch='A')",
12099451b44SJordan Rupprecht                             "a((int)val=3, (char)ch='A')"])
12199451b44SJordan Rupprecht
12299451b44SJordan Rupprecht    @add_test_categories(['pyapi'])
12399451b44SJordan Rupprecht    def test_frame_api_boundary_condition(self):
12499451b44SJordan Rupprecht        """Exercise SBFrame APIs with boundary condition inputs."""
12599451b44SJordan Rupprecht        self.build()
12699451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
12799451b44SJordan Rupprecht
12899451b44SJordan Rupprecht        # Create a target by the debugger.
12999451b44SJordan Rupprecht        target = self.dbg.CreateTarget(exe)
13099451b44SJordan Rupprecht        self.assertTrue(target, VALID_TARGET)
13199451b44SJordan Rupprecht
13299451b44SJordan Rupprecht        # Now create a breakpoint on main.c by name 'c'.
13399451b44SJordan Rupprecht        breakpoint = target.BreakpointCreateByName('c', 'a.out')
134*b321b429SJonas Devlieghere        self.trace("breakpoint:", breakpoint)
13599451b44SJordan Rupprecht        self.assertTrue(breakpoint and
13699451b44SJordan Rupprecht                        breakpoint.GetNumLocations() == 1,
13799451b44SJordan Rupprecht                        VALID_BREAKPOINT)
13899451b44SJordan Rupprecht
13999451b44SJordan Rupprecht        # Now launch the process, and do not stop at the entry point.
14099451b44SJordan Rupprecht        process = target.LaunchSimple(
14199451b44SJordan Rupprecht            None, None, self.get_process_working_directory())
14299451b44SJordan Rupprecht
14399451b44SJordan Rupprecht        process = target.GetProcess()
14499451b44SJordan Rupprecht        self.assertTrue(process.GetState() == lldb.eStateStopped,
14599451b44SJordan Rupprecht                        PROCESS_STOPPED)
14699451b44SJordan Rupprecht
14799451b44SJordan Rupprecht        thread = lldbutil.get_stopped_thread(
14899451b44SJordan Rupprecht            process, lldb.eStopReasonBreakpoint)
14999451b44SJordan Rupprecht        self.assertIsNotNone(thread)
15099451b44SJordan Rupprecht        frame = thread.GetFrameAtIndex(0)
15199451b44SJordan Rupprecht        if self.TraceOn():
15299451b44SJordan Rupprecht            print("frame:", frame)
15399451b44SJordan Rupprecht
15499451b44SJordan Rupprecht        # Boundary condition testings.
15599451b44SJordan Rupprecht        val1 = frame.FindVariable(None, True)
15699451b44SJordan Rupprecht        val2 = frame.FindVariable(None, False)
15799451b44SJordan Rupprecht        val3 = frame.FindValue(None, lldb.eValueTypeVariableGlobal)
15899451b44SJordan Rupprecht        if self.TraceOn():
15999451b44SJordan Rupprecht            print("val1:", val1)
16099451b44SJordan Rupprecht            print("val2:", val2)
16199451b44SJordan Rupprecht
16299451b44SJordan Rupprecht        frame.EvaluateExpression(None)
16399451b44SJordan Rupprecht
16499451b44SJordan Rupprecht    @add_test_categories(['pyapi'])
16599451b44SJordan Rupprecht    def test_frame_api_IsEqual(self):
16699451b44SJordan Rupprecht        """Exercise SBFrame API IsEqual."""
16799451b44SJordan Rupprecht        self.build()
16899451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
16999451b44SJordan Rupprecht
17099451b44SJordan Rupprecht        # Create a target by the debugger.
17199451b44SJordan Rupprecht        target = self.dbg.CreateTarget(exe)
17299451b44SJordan Rupprecht        self.assertTrue(target, VALID_TARGET)
17399451b44SJordan Rupprecht
17499451b44SJordan Rupprecht        # Now create a breakpoint on main.c by name 'c'.
17599451b44SJordan Rupprecht        breakpoint = target.BreakpointCreateByName('c', 'a.out')
176*b321b429SJonas Devlieghere        self.trace("breakpoint:", breakpoint)
17799451b44SJordan Rupprecht        self.assertTrue(breakpoint and
17899451b44SJordan Rupprecht                        breakpoint.GetNumLocations() == 1,
17999451b44SJordan Rupprecht                        VALID_BREAKPOINT)
18099451b44SJordan Rupprecht
18199451b44SJordan Rupprecht        # Now launch the process, and do not stop at the entry point.
18299451b44SJordan Rupprecht        process = target.LaunchSimple(
18399451b44SJordan Rupprecht            None, None, self.get_process_working_directory())
18499451b44SJordan Rupprecht
18599451b44SJordan Rupprecht        process = target.GetProcess()
18699451b44SJordan Rupprecht        self.assertTrue(process.GetState() == lldb.eStateStopped,
18799451b44SJordan Rupprecht                        PROCESS_STOPPED)
18899451b44SJordan Rupprecht
18999451b44SJordan Rupprecht        thread = lldbutil.get_stopped_thread(
19099451b44SJordan Rupprecht            process, lldb.eStopReasonBreakpoint)
19199451b44SJordan Rupprecht        self.assertIsNotNone(thread)
19299451b44SJordan Rupprecht
19399451b44SJordan Rupprecht        frameEntered = thread.GetFrameAtIndex(0)
19499451b44SJordan Rupprecht        if self.TraceOn():
19599451b44SJordan Rupprecht            print(frameEntered)
19699451b44SJordan Rupprecht            lldbutil.print_stacktrace(thread)
19799451b44SJordan Rupprecht        self.assertTrue(frameEntered)
19899451b44SJordan Rupprecht
19999451b44SJordan Rupprecht        # Doing two step overs while still inside c().
20099451b44SJordan Rupprecht        thread.StepOver()
20199451b44SJordan Rupprecht        thread.StepOver()
20299451b44SJordan Rupprecht        self.assertTrue(thread)
20399451b44SJordan Rupprecht        frameNow = thread.GetFrameAtIndex(0)
20499451b44SJordan Rupprecht        if self.TraceOn():
20599451b44SJordan Rupprecht            print(frameNow)
20699451b44SJordan Rupprecht            lldbutil.print_stacktrace(thread)
20799451b44SJordan Rupprecht        self.assertTrue(frameNow)
20899451b44SJordan Rupprecht
20999451b44SJordan Rupprecht        # The latest two frames are considered equal.
21099451b44SJordan Rupprecht        self.assertTrue(frameEntered.IsEqual(frameNow))
21199451b44SJordan Rupprecht
21299451b44SJordan Rupprecht        # Now let's step out of frame c().
21399451b44SJordan Rupprecht        thread.StepOutOfFrame(frameNow)
21499451b44SJordan Rupprecht        frameOutOfC = thread.GetFrameAtIndex(0)
21599451b44SJordan Rupprecht        if self.TraceOn():
21699451b44SJordan Rupprecht            print(frameOutOfC)
21799451b44SJordan Rupprecht            lldbutil.print_stacktrace(thread)
21899451b44SJordan Rupprecht        self.assertTrue(frameOutOfC)
21999451b44SJordan Rupprecht
22099451b44SJordan Rupprecht        # The latest two frames should not be equal.
22199451b44SJordan Rupprecht        self.assertFalse(frameOutOfC.IsEqual(frameNow))
222