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 77 78 # Make sure on arm targets we dont mismatch PC value on the basis of thumb bit. 79 # Frame PC will not have thumb bit set in case of a thumb 80 # instruction as PC. 81 pc_value_int = int(pc_value.GetValue(), 0) 82 if self.getArchitecture() in ["arm", "armv7", "armv7k"]: 83 pc_value_int &= ~1 84 self.assertEqual( 85 pc_value_int, 86 frame.GetPC(), 87 "PC gotten as a value should equal frame's GetPC", 88 ) 89 sp_value = gpr_reg_set.GetChildMemberWithName("sp") 90 self.assertTrue(sp_value, "We should have a valid Stack Pointer.") 91 self.assertEqual( 92 int(sp_value.GetValue(), 0), 93 frame.GetSP(), 94 "SP gotten as a value should equal frame's GetSP", 95 ) 96 # Test that the "register" property's flat list matches the list from 97 # the "registers" property that returns register sets: 98 register_regs = set() 99 flattened_regs = set() 100 for reg_set in frame.registers: 101 for reg in reg_set: 102 flattened_regs.add(reg.name) 103 for reg in frame.register: 104 register_regs.add(reg.name) 105 self.assertEqual(register_regs, flattened_regs, "register matches registers") 106 107 print("---", file=session) 108 process.Continue() 109 110 # At this point, the inferior process should have exited. 111 self.assertEqual(process.GetState(), lldb.eStateExited, PROCESS_EXITED) 112 113 # Expect to find 'a' on the call stacks two times. 114 self.assertEqual(callsOfA, 2, "Expect to find 'a' on the call stacks two times") 115 # By design, the 'a' call frame has the following arg vals: 116 # o a((int)val=1, (char)ch='A') 117 # o a((int)val=3, (char)ch='A') 118 if self.TraceOn(): 119 print("Full stack traces when stopped on the breakpoint 'c':") 120 print(session.getvalue()) 121 self.expect( 122 session.getvalue(), 123 "Argument values displayed correctly", 124 exe=False, 125 substrs=["a((int)val=1, (char)ch='A')", "a((int)val=3, (char)ch='A')"], 126 ) 127 128 def test_frame_api_boundary_condition(self): 129 """Exercise SBFrame APIs with boundary condition inputs.""" 130 self.build() 131 exe = self.getBuildArtifact("a.out") 132 133 # Create a target by the debugger. 134 target = self.dbg.CreateTarget(exe) 135 self.assertTrue(target, VALID_TARGET) 136 137 # Now create a breakpoint on main.c by name 'c'. 138 breakpoint = target.BreakpointCreateByName("c", "a.out") 139 self.trace("breakpoint:", breakpoint) 140 self.assertTrue( 141 breakpoint and breakpoint.GetNumLocations() == 1, VALID_BREAKPOINT 142 ) 143 144 # Now launch the process, and do not stop at the entry point. 145 process = target.LaunchSimple(None, None, self.get_process_working_directory()) 146 147 process = target.GetProcess() 148 self.assertState(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED) 149 150 thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint) 151 self.assertIsNotNone(thread) 152 frame = thread.GetFrameAtIndex(0) 153 if self.TraceOn(): 154 print("frame:", frame) 155 156 # Boundary condition testings. 157 val1 = frame.FindVariable(None, True) 158 val2 = frame.FindVariable(None, False) 159 val3 = frame.FindValue(None, lldb.eValueTypeVariableGlobal) 160 if self.TraceOn(): 161 print("val1:", val1) 162 print("val2:", val2) 163 164 frame.EvaluateExpression(None) 165 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( 179 breakpoint and breakpoint.GetNumLocations() == 1, VALID_BREAKPOINT 180 ) 181 182 # Now launch the process, and do not stop at the entry point. 183 process = target.LaunchSimple(None, None, self.get_process_working_directory()) 184 185 process = target.GetProcess() 186 self.assertState(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED) 187 188 thread = lldbutil.get_stopped_thread(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