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 @add_test_categories(['pyapi']) 20 def test_get_arg_vals_for_call_stack(self): 21 """Exercise SBFrame.GetVariables() API to get argument vals.""" 22 self.build() 23 exe = self.getBuildArtifact("a.out") 24 25 # Create a target by the debugger. 26 target = self.dbg.CreateTarget(exe) 27 self.assertTrue(target, VALID_TARGET) 28 29 # Now create a breakpoint on main.c by name 'c'. 30 breakpoint = target.BreakpointCreateByName('c', 'a.out') 31 #print("breakpoint:", breakpoint) 32 self.assertTrue(breakpoint and 33 breakpoint.GetNumLocations() == 1, 34 VALID_BREAKPOINT) 35 36 # Now launch the process, and do not stop at the entry point. 37 process = target.LaunchSimple( 38 None, None, self.get_process_working_directory()) 39 40 process = target.GetProcess() 41 self.assertTrue(process.GetState() == lldb.eStateStopped, 42 PROCESS_STOPPED) 43 44 # Keeps track of the number of times 'a' is called where it is within a 45 # depth of 3 of the 'c' leaf function. 46 callsOfA = 0 47 48 from six import StringIO as SixStringIO 49 session = SixStringIO() 50 while process.GetState() == lldb.eStateStopped: 51 thread = lldbutil.get_stopped_thread( 52 process, lldb.eStopReasonBreakpoint) 53 self.assertIsNotNone(thread) 54 # Inspect at most 3 frames. 55 numFrames = min(3, thread.GetNumFrames()) 56 for i in range(numFrames): 57 frame = thread.GetFrameAtIndex(i) 58 if self.TraceOn(): 59 print("frame:", frame) 60 61 name = frame.GetFunction().GetName() 62 if name == 'a': 63 callsOfA = callsOfA + 1 64 65 # We'll inspect only the arguments for the current frame: 66 # 67 # arguments => True 68 # locals => False 69 # statics => False 70 # in_scope_only => True 71 valList = frame.GetVariables(True, False, False, True) 72 argList = [] 73 for val in valList: 74 argList.append("(%s)%s=%s" % (val.GetTypeName(), 75 val.GetName(), 76 val.GetValue())) 77 print("%s(%s)" % (name, ", ".join(argList)), file=session) 78 79 # Also check the generic pc & stack pointer. We can't test their absolute values, 80 # but they should be valid. Uses get_GPRs() from the lldbutil 81 # module. 82 gpr_reg_set = lldbutil.get_GPRs(frame) 83 pc_value = gpr_reg_set.GetChildMemberWithName("pc") 84 self.assertTrue(pc_value, "We should have a valid PC.") 85 pc_value_int = int(pc_value.GetValue(), 0) 86 # Make sure on arm targets we dont mismatch PC value on the basis of thumb bit. 87 # Frame PC will not have thumb bit set in case of a thumb 88 # instruction as PC. 89 if self.getArchitecture() in ['arm', 'armv7', 'armv7k']: 90 pc_value_int &= ~1 91 self.assertTrue( 92 pc_value_int == frame.GetPC(), 93 "PC gotten as a value should equal frame's GetPC") 94 sp_value = gpr_reg_set.GetChildMemberWithName("sp") 95 self.assertTrue( 96 sp_value, "We should have a valid Stack Pointer.") 97 self.assertTrue(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.assertTrue( 105 process.GetState() == lldb.eStateExited, 106 PROCESS_EXITED) 107 108 # Expect to find 'a' on the call stacks two times. 109 self.assertTrue(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 @add_test_categories(['pyapi']) 123 def test_frame_api_boundary_condition(self): 124 """Exercise SBFrame APIs with boundary condition inputs.""" 125 self.build() 126 exe = self.getBuildArtifact("a.out") 127 128 # Create a target by the debugger. 129 target = self.dbg.CreateTarget(exe) 130 self.assertTrue(target, VALID_TARGET) 131 132 # Now create a breakpoint on main.c by name 'c'. 133 breakpoint = target.BreakpointCreateByName('c', 'a.out') 134 #print("breakpoint:", breakpoint) 135 self.assertTrue(breakpoint and 136 breakpoint.GetNumLocations() == 1, 137 VALID_BREAKPOINT) 138 139 # Now launch the process, and do not stop at the entry point. 140 process = target.LaunchSimple( 141 None, None, self.get_process_working_directory()) 142 143 process = target.GetProcess() 144 self.assertTrue(process.GetState() == lldb.eStateStopped, 145 PROCESS_STOPPED) 146 147 thread = lldbutil.get_stopped_thread( 148 process, lldb.eStopReasonBreakpoint) 149 self.assertIsNotNone(thread) 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 @add_test_categories(['pyapi']) 165 def test_frame_api_IsEqual(self): 166 """Exercise SBFrame API IsEqual.""" 167 self.build() 168 exe = self.getBuildArtifact("a.out") 169 170 # Create a target by the debugger. 171 target = self.dbg.CreateTarget(exe) 172 self.assertTrue(target, VALID_TARGET) 173 174 # Now create a breakpoint on main.c by name 'c'. 175 breakpoint = target.BreakpointCreateByName('c', 'a.out') 176 #print("breakpoint:", breakpoint) 177 self.assertTrue(breakpoint and 178 breakpoint.GetNumLocations() == 1, 179 VALID_BREAKPOINT) 180 181 # Now launch the process, and do not stop at the entry point. 182 process = target.LaunchSimple( 183 None, None, self.get_process_working_directory()) 184 185 process = target.GetProcess() 186 self.assertTrue(process.GetState() == lldb.eStateStopped, 187 PROCESS_STOPPED) 188 189 thread = lldbutil.get_stopped_thread( 190 process, lldb.eStopReasonBreakpoint) 191 self.assertIsNotNone(thread) 192 193 frameEntered = thread.GetFrameAtIndex(0) 194 if self.TraceOn(): 195 print(frameEntered) 196 lldbutil.print_stacktrace(thread) 197 self.assertTrue(frameEntered) 198 199 # Doing two step overs while still inside c(). 200 thread.StepOver() 201 thread.StepOver() 202 self.assertTrue(thread) 203 frameNow = thread.GetFrameAtIndex(0) 204 if self.TraceOn(): 205 print(frameNow) 206 lldbutil.print_stacktrace(thread) 207 self.assertTrue(frameNow) 208 209 # The latest two frames are considered equal. 210 self.assertTrue(frameEntered.IsEqual(frameNow)) 211 212 # Now let's step out of frame c(). 213 thread.StepOutOfFrame(frameNow) 214 frameOutOfC = thread.GetFrameAtIndex(0) 215 if self.TraceOn(): 216 print(frameOutOfC) 217 lldbutil.print_stacktrace(thread) 218 self.assertTrue(frameOutOfC) 219 220 # The latest two frames should not be equal. 221 self.assertFalse(frameOutOfC.IsEqual(frameNow)) 222