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 self.trace("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.assertEqual(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.assertEqual( 98 int(sp_value.GetValue(), 0), frame.GetSP(), 99 "SP gotten as a value should equal frame's GetSP") 100 101 print("---", file=session) 102 process.Continue() 103 104 # At this point, the inferior process should have exited. 105 self.assertTrue( 106 process.GetState() == lldb.eStateExited, 107 PROCESS_EXITED) 108 109 # Expect to find 'a' on the call stacks two times. 110 self.assertEqual(callsOfA, 2, 111 "Expect to find 'a' on the call stacks two times") 112 # By design, the 'a' call frame has the following arg vals: 113 # o a((int)val=1, (char)ch='A') 114 # o a((int)val=3, (char)ch='A') 115 if self.TraceOn(): 116 print("Full stack traces when stopped on the breakpoint 'c':") 117 print(session.getvalue()) 118 self.expect(session.getvalue(), "Argument values displayed correctly", 119 exe=False, 120 substrs=["a((int)val=1, (char)ch='A')", 121 "a((int)val=3, (char)ch='A')"]) 122 123 @add_test_categories(['pyapi']) 124 def test_frame_api_boundary_condition(self): 125 """Exercise SBFrame APIs with boundary condition inputs.""" 126 self.build() 127 exe = self.getBuildArtifact("a.out") 128 129 # Create a target by the debugger. 130 target = self.dbg.CreateTarget(exe) 131 self.assertTrue(target, VALID_TARGET) 132 133 # Now create a breakpoint on main.c by name 'c'. 134 breakpoint = target.BreakpointCreateByName('c', 'a.out') 135 self.trace("breakpoint:", breakpoint) 136 self.assertTrue(breakpoint and 137 breakpoint.GetNumLocations() == 1, 138 VALID_BREAKPOINT) 139 140 # Now launch the process, and do not stop at the entry point. 141 process = target.LaunchSimple( 142 None, None, self.get_process_working_directory()) 143 144 process = target.GetProcess() 145 self.assertEqual(process.GetState(), lldb.eStateStopped, 146 PROCESS_STOPPED) 147 148 thread = lldbutil.get_stopped_thread( 149 process, lldb.eStopReasonBreakpoint) 150 self.assertIsNotNone(thread) 151 frame = thread.GetFrameAtIndex(0) 152 if self.TraceOn(): 153 print("frame:", frame) 154 155 # Boundary condition testings. 156 val1 = frame.FindVariable(None, True) 157 val2 = frame.FindVariable(None, False) 158 val3 = frame.FindValue(None, lldb.eValueTypeVariableGlobal) 159 if self.TraceOn(): 160 print("val1:", val1) 161 print("val2:", val2) 162 163 frame.EvaluateExpression(None) 164 165 @add_test_categories(['pyapi']) 166 def test_frame_api_IsEqual(self): 167 """Exercise SBFrame API IsEqual.""" 168 self.build() 169 exe = self.getBuildArtifact("a.out") 170 171 # Create a target by the debugger. 172 target = self.dbg.CreateTarget(exe) 173 self.assertTrue(target, VALID_TARGET) 174 175 # Now create a breakpoint on main.c by name 'c'. 176 breakpoint = target.BreakpointCreateByName('c', 'a.out') 177 self.trace("breakpoint:", breakpoint) 178 self.assertTrue(breakpoint and 179 breakpoint.GetNumLocations() == 1, 180 VALID_BREAKPOINT) 181 182 # Now launch the process, and do not stop at the entry point. 183 process = target.LaunchSimple( 184 None, None, self.get_process_working_directory()) 185 186 process = target.GetProcess() 187 self.assertEqual(process.GetState(), lldb.eStateStopped, 188 PROCESS_STOPPED) 189 190 thread = lldbutil.get_stopped_thread( 191 process, lldb.eStopReasonBreakpoint) 192 self.assertIsNotNone(thread) 193 194 frameEntered = thread.GetFrameAtIndex(0) 195 if self.TraceOn(): 196 print(frameEntered) 197 lldbutil.print_stacktrace(thread) 198 self.assertTrue(frameEntered) 199 200 # Doing two step overs while still inside c(). 201 thread.StepOver() 202 thread.StepOver() 203 self.assertTrue(thread) 204 frameNow = thread.GetFrameAtIndex(0) 205 if self.TraceOn(): 206 print(frameNow) 207 lldbutil.print_stacktrace(thread) 208 self.assertTrue(frameNow) 209 210 # The latest two frames are considered equal. 211 self.assertTrue(frameEntered.IsEqual(frameNow)) 212 213 # Now let's step out of frame c(). 214 thread.StepOutOfFrame(frameNow) 215 frameOutOfC = thread.GetFrameAtIndex(0) 216 if self.TraceOn(): 217 print(frameOutOfC) 218 lldbutil.print_stacktrace(thread) 219 self.assertTrue(frameOutOfC) 220 221 # The latest two frames should not be equal. 222 self.assertFalse(frameOutOfC.IsEqual(frameNow)) 223