1""" 2Use lldb Python API to test dynamic values in C++ 3""" 4 5 6import lldb 7from lldbsuite.test.decorators import * 8from lldbsuite.test.lldbtest import * 9from lldbsuite.test import lldbutil 10 11 12class DynamicValueTestCase(TestBase): 13 def setUp(self): 14 # Call super's setUp(). 15 TestBase.setUp(self) 16 17 # Find the line number to break for main.c. 18 19 self.do_something_line = line_number( 20 "pass-to-base.cpp", "// Break here in doSomething." 21 ) 22 self.main_first_call_line = line_number( 23 "pass-to-base.cpp", 24 "// Break here and get real addresses of myB and otherB.", 25 ) 26 self.main_second_call_line = line_number( 27 "pass-to-base.cpp", "// Break here and get real address of reallyA." 28 ) 29 30 @add_test_categories(["pyapi"]) 31 @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24663") 32 def test_get_dynamic_vals(self): 33 """Test fetching C++ dynamic values from pointers & references.""" 34 self.build() 35 exe = self.getBuildArtifact("a.out") 36 37 # Create a target from the debugger. 38 39 target = self.dbg.CreateTarget(exe) 40 self.assertTrue(target, VALID_TARGET) 41 42 # Set up our breakpoints: 43 44 do_something_bpt = target.BreakpointCreateByLocation( 45 "pass-to-base.cpp", self.do_something_line 46 ) 47 self.assertTrue(do_something_bpt, VALID_BREAKPOINT) 48 49 first_call_bpt = target.BreakpointCreateByLocation( 50 "pass-to-base.cpp", self.main_first_call_line 51 ) 52 self.assertTrue(first_call_bpt, VALID_BREAKPOINT) 53 54 second_call_bpt = target.BreakpointCreateByLocation( 55 "pass-to-base.cpp", self.main_second_call_line 56 ) 57 self.assertTrue(second_call_bpt, VALID_BREAKPOINT) 58 59 # Now launch the process, and do not stop at the entry point. 60 process = target.LaunchSimple(None, None, self.get_process_working_directory()) 61 62 self.assertState(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED) 63 64 threads = lldbutil.get_threads_stopped_at_breakpoint(process, first_call_bpt) 65 self.assertEqual(len(threads), 1) 66 thread = threads[0] 67 68 frame = thread.GetFrameAtIndex(0) 69 70 # Now find the dynamic addresses of myB and otherB so we can compare them 71 # with the dynamic values we get in doSomething: 72 73 use_dynamic = lldb.eDynamicCanRunTarget 74 no_dynamic = lldb.eNoDynamicValues 75 76 myB = frame.FindVariable("myB", no_dynamic) 77 self.assertTrue(myB) 78 myB_loc = int(myB.GetLocation(), 16) 79 80 otherB = frame.FindVariable("otherB", no_dynamic) 81 self.assertTrue(otherB) 82 otherB_loc = int(otherB.GetLocation(), 16) 83 84 # Okay now run to doSomething: 85 86 threads = lldbutil.continue_to_breakpoint(process, do_something_bpt) 87 self.assertEqual(len(threads), 1) 88 thread = threads[0] 89 90 frame = thread.GetFrameAtIndex(0) 91 92 # Get "this" using FindVariable: 93 94 this_static = frame.FindVariable("this", no_dynamic) 95 this_dynamic = frame.FindVariable("this", use_dynamic) 96 self.examine_value_object_of_this_ptr(this_static, this_dynamic, myB_loc) 97 98 # Now make sure that the "GetDynamicValue" works: 99 # This doesn't work currently because we can't get dynamic values from 100 # ConstResult objects. 101 fetched_dynamic_value = this_static.GetDynamicValue(use_dynamic) 102 self.examine_value_object_of_this_ptr( 103 this_static, fetched_dynamic_value, myB_loc 104 ) 105 106 # And conversely that the GetDynamicValue() interface also works: 107 fetched_static_value = this_dynamic.GetStaticValue() 108 self.examine_value_object_of_this_ptr( 109 fetched_static_value, this_dynamic, myB_loc 110 ) 111 112 # Get "this" using FindValue, make sure that works too: 113 this_static = frame.FindValue( 114 "this", lldb.eValueTypeVariableArgument, no_dynamic 115 ) 116 this_dynamic = frame.FindValue( 117 "this", lldb.eValueTypeVariableArgument, use_dynamic 118 ) 119 self.examine_value_object_of_this_ptr(this_static, this_dynamic, myB_loc) 120 121 # Get "this" using the EvaluateExpression: 122 this_static = frame.EvaluateExpression("this", False) 123 this_dynamic = frame.EvaluateExpression("this", True) 124 self.examine_value_object_of_this_ptr(this_static, this_dynamic, myB_loc) 125 126 # The "frame var" code uses another path to get into children, so let's 127 # make sure that works as well: 128 129 self.expect( 130 "frame var -d run-target --ptr-depth=2 --show-types anotherA.m_client_A", 131 "frame var finds its way into a child member", 132 patterns=["\(B \*\)"], 133 ) 134 135 # Now make sure we also get it right for a reference as well: 136 137 anotherA_static = frame.FindVariable("anotherA", False) 138 self.assertTrue(anotherA_static) 139 anotherA_static_addr = int(anotherA_static.GetValue(), 16) 140 141 anotherA_dynamic = frame.FindVariable("anotherA", True) 142 self.assertTrue(anotherA_dynamic) 143 anotherA_dynamic_addr = int(anotherA_dynamic.GetValue(), 16) 144 anotherA_dynamic_typename = anotherA_dynamic.GetTypeName() 145 self.assertNotEqual(anotherA_dynamic_typename.find("B"), -1) 146 147 self.assertLess(anotherA_dynamic_addr, anotherA_static_addr) 148 149 anotherA_m_b_value_dynamic = anotherA_dynamic.GetChildMemberWithName( 150 "m_b_value", True 151 ) 152 self.assertTrue(anotherA_m_b_value_dynamic) 153 anotherA_m_b_val = int(anotherA_m_b_value_dynamic.GetValue(), 10) 154 self.assertEqual(anotherA_m_b_val, 300) 155 156 anotherA_m_b_value_static = anotherA_static.GetChildMemberWithName( 157 "m_b_value", True 158 ) 159 self.assertFalse(anotherA_m_b_value_static) 160 161 # Okay, now continue again, and when we hit the second breakpoint in 162 # main 163 164 threads = lldbutil.continue_to_breakpoint(process, second_call_bpt) 165 self.assertEqual(len(threads), 1) 166 thread = threads[0] 167 168 frame = thread.GetFrameAtIndex(0) 169 reallyA_value = frame.FindVariable("reallyA", False) 170 self.assertTrue(reallyA_value) 171 reallyA_loc = int(reallyA_value.GetLocation(), 16) 172 173 # Continue to doSomething again, and make sure we get the right value for anotherA, 174 # which this time around is just an "A". 175 176 threads = lldbutil.continue_to_breakpoint(process, do_something_bpt) 177 self.assertEqual(len(threads), 1) 178 thread = threads[0] 179 180 frame = thread.GetFrameAtIndex(0) 181 anotherA_value = frame.FindVariable("anotherA", True) 182 self.assertTrue(anotherA_value) 183 anotherA_loc = int(anotherA_value.GetValue(), 16) 184 self.assertEqual(anotherA_loc, reallyA_loc) 185 self.assertEqual(anotherA_value.GetTypeName().find("B"), -1) 186 187 # Finally do the same with a B in an anonymous namespace. 188 threads = lldbutil.continue_to_breakpoint(process, do_something_bpt) 189 self.assertEqual(len(threads), 1) 190 thread = threads[0] 191 192 frame = thread.GetFrameAtIndex(0) 193 anotherA_value = frame.FindVariable("anotherA", use_dynamic) 194 self.assertTrue(anotherA_value) 195 self.assertIn("B", anotherA_value.GetTypeName()) 196 anon_b_value = anotherA_value.GetChildMemberWithName("m_anon_b_value") 197 self.assertTrue(anon_b_value) 198 self.assertEqual(anon_b_value.GetValueAsSigned(), 47) 199 200 def examine_value_object_of_this_ptr( 201 self, this_static, this_dynamic, dynamic_location 202 ): 203 # Get "this" as its static value 204 self.assertTrue(this_static) 205 this_static_loc = int(this_static.GetValue(), 16) 206 207 # Get "this" as its dynamic value 208 209 self.assertTrue(this_dynamic) 210 this_dynamic_typename = this_dynamic.GetTypeName() 211 self.assertNotEqual(this_dynamic_typename.find("B"), -1) 212 this_dynamic_loc = int(this_dynamic.GetValue(), 16) 213 214 # Make sure we got the right address for "this" 215 216 self.assertEqual(this_dynamic_loc, dynamic_location) 217 218 # And that the static address is greater than the dynamic one 219 220 self.assertGreater(this_static_loc, this_dynamic_loc) 221 222 # Now read m_b_value which is only in the dynamic value: 223 224 use_dynamic = lldb.eDynamicCanRunTarget 225 no_dynamic = lldb.eNoDynamicValues 226 227 this_dynamic_m_b_value = this_dynamic.GetChildMemberWithName( 228 "m_b_value", use_dynamic 229 ) 230 self.assertTrue(this_dynamic_m_b_value) 231 232 m_b_value = int(this_dynamic_m_b_value.GetValue(), 0) 233 self.assertEqual(m_b_value, 10) 234 235 # Make sure it is not in the static version 236 237 this_static_m_b_value = this_static.GetChildMemberWithName( 238 "m_b_value", no_dynamic 239 ) 240 self.assertFalse(this_static_m_b_value) 241 242 # Okay, now let's make sure that we can get the dynamic type of a child 243 # element: 244 245 contained_auto_ptr = this_dynamic.GetChildMemberWithName( 246 "m_client_A", use_dynamic 247 ) 248 self.assertTrue(contained_auto_ptr) 249 contained_b = contained_auto_ptr.GetChildMemberWithName("_M_ptr", use_dynamic) 250 if not contained_b: 251 contained_b = contained_auto_ptr.GetChildMemberWithName( 252 "__ptr_", use_dynamic 253 ) 254 self.assertTrue(contained_b) 255 256 contained_b_static = contained_auto_ptr.GetChildMemberWithName( 257 "_M_ptr", no_dynamic 258 ) 259 if not contained_b_static: 260 contained_b_static = contained_auto_ptr.GetChildMemberWithName( 261 "__ptr_", no_dynamic 262 ) 263 self.assertTrue(contained_b_static) 264 265 contained_b_addr = int(contained_b.GetValue(), 16) 266 contained_b_static_addr = int(contained_b_static.GetValue(), 16) 267 268 self.assertLess(contained_b_addr, contained_b_static_addr) 269