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