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