brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.5 KiB · a230d07 Raw
333 lines · python
1"""2Use lldb Python API to test dynamic values in C++3"""4 5 6import lldb7from lldbsuite.test.decorators import *8from lldbsuite.test.lldbtest import *9from lldbsuite.test import lldbutil10 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_line46        )47        self.assertTrue(do_something_bpt, VALID_BREAKPOINT)48 49        first_call_bpt = target.BreakpointCreateByLocation(50            "pass-to-base.cpp", self.main_first_call_line51        )52        self.assertTrue(first_call_bpt, VALID_BREAKPOINT)53 54        second_call_bpt = target.BreakpointCreateByLocation(55            "pass-to-base.cpp", self.main_second_call_line56        )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 them71        # with the dynamic values we get in doSomething:72 73        use_dynamic = lldb.eDynamicCanRunTarget74        no_dynamic = lldb.eNoDynamicValues75 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 from100        # 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_loc104        )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_loc110        )111 112        # Get "this" using FindValue, make sure that works too:113        this_static = frame.FindValue(114            "this", lldb.eValueTypeVariableArgument, no_dynamic115        )116        this_dynamic = frame.FindValue(117            "this", lldb.eValueTypeVariableArgument, use_dynamic118        )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's127        # 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=[r"\(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", True151        )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", True158        )159        self.assertFalse(anotherA_m_b_value_static)160 161        # Okay, now continue again, and when we hit the second breakpoint in162        # main163 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_location202    ):203        # Get "this" as its static value204        self.assertTrue(this_static)205        this_static_loc = int(this_static.GetValue(), 16)206 207        # Get "this" as its dynamic value208 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 one219 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.eDynamicCanRunTarget225        no_dynamic = lldb.eNoDynamicValues226 227        this_dynamic_m_b_value = this_dynamic.GetChildMemberWithName(228            "m_b_value", use_dynamic229        )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 version236 237        this_static_m_b_value = this_static.GetChildMemberWithName(238            "m_b_value", no_dynamic239        )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 child243        # element:244 245        contained_auto_ptr = this_dynamic.GetChildMemberWithName(246            "m_client_A", use_dynamic247        )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_dynamic253            )254        self.assertTrue(contained_b)255 256        contained_b_static = contained_auto_ptr.GetChildMemberWithName(257            "_M_ptr", no_dynamic258        )259        if not contained_b_static:260            contained_b_static = contained_auto_ptr.GetChildMemberWithName(261                "__ptr_", no_dynamic262            )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 270    @no_debug_info_test271    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24663")272    def test_from_forward_decl(self):273        """Test fetching C++ dynamic values forward-declared types. It's274        imperative that this is a separate test so that we don't end up parsing275        a definition of A from somewhere else."""276        self.build()277        lldbutil.run_to_name_breakpoint(self, "take_A")278        self.expect(279            "frame var -d run-target --ptr-depth=1 --show-types a",280            substrs=["(B *) a", "m_b_value = 10"],281        )282 283    @no_debug_info_test284    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24663")285    @expectedFailureAll(archs=["arm$"]) # Minidump saving not implemented286    def test_from_core_file(self):287        """Test fetching C++ dynamic values from core files. Specifically, test288        that we can determine the dynamic type of the value if the core file289        does not contain the type vtable."""290        self.build()291        lldbutil.run_to_name_breakpoint(self, "take_A")292 293        # Get the address of our object and its vtable294        a = self.frame().FindVariable("a")295        self.assertSuccess(a.GetError())296        vtable = a.GetVTable()297        self.assertSuccess(vtable.GetError())298        a = a.GetValueAsAddress()299        vtable = vtable.GetValueAsAddress()300 301        # Create a core file which will only contain the memory region302        # containing `a`. The object is on the stack, so this will automatically303        # include the stack of the main thread.304        core = self.getBuildArtifact("a.dmp")305        options = lldb.SBSaveCoreOptions()306        options.SetPluginName("minidump")307        options.SetStyle(lldb.eSaveCoreCustomOnly)308        options.SetOutputFile(lldb.SBFileSpec(core))309        region = lldb.SBMemoryRegionInfo()310        self.assertSuccess(self.process().GetMemoryRegionInfo(a, region))311        self.assertSuccess(options.AddMemoryRegionToSave(region))312 313        # Save the core file and load it.314        self.assertSuccess(self.process().SaveCore(options))315        self.process().Kill()316        error = lldb.SBError()317        self.target().LoadCore(core, error)318        self.assertSuccess(error)319 320        # Sanity check -- the process should be able to read the object but not321        # its vtable..322        self.process().ReadPointerFromMemory(a, error)323        self.assertSuccess(error)324        self.process().ReadPointerFromMemory(vtable, error)325        self.assertTrue(error.Fail())326 327        # .. but we should still be able to see the dynamic type by reading the328        # vtable from the executable file.329        self.expect(330            "frame var -d run-target --ptr-depth=1 --show-types a",331            substrs=["(B *) a", "m_b_value = 10"],332        )333