brintos

brintos / llvm-project-archived public Read only

0
0
Text · 16.8 KiB · 44b1183 Raw
444 lines · python
1"""2Test Debugger APIs.3"""4 5import lldb6 7from lldbsuite.test.decorators import *8from lldbsuite.test.lldbtest import *9from lldbsuite.test import lldbutil10 11 12class DebuggerAPITestCase(TestBase):13    NO_DEBUG_INFO_TESTCASE = True14 15    def test_debugger_api_boundary_condition(self):16        """Exercise SBDebugger APIs with boundary conditions."""17        self.dbg.HandleCommand(None)18        self.dbg.SetDefaultArchitecture(None)19        self.dbg.GetScriptingLanguage(None)20        self.dbg.CreateTarget(None)21        self.dbg.CreateTarget(None, None, None, True, lldb.SBError())22        self.dbg.CreateTargetWithFileAndTargetTriple(None, None)23        self.dbg.CreateTargetWithFileAndArch(None, None)24        self.dbg.FindTargetWithFileAndArch(None, None)25        self.dbg.SetInternalVariable(None, None, None)26        self.dbg.GetInternalVariableValue(None, None)27        # FIXME (filcab): We must first allow for the swig bindings to know if28        # a Python callback is set. (Check python-typemaps.swig)29        # self.dbg.SetLoggingCallback(None)30        self.dbg.SetPrompt(None)31        self.dbg.SetCurrentPlatform(None)32        self.dbg.SetCurrentPlatformSDKRoot(None)33 34        fresh_dbg = lldb.SBDebugger()35        self.assertEqual(len(fresh_dbg), 0)36 37    def test_debugger_delete_invalid_target(self):38        """SBDebugger.DeleteTarget() should not crash LLDB given and invalid target."""39        target = lldb.SBTarget()40        self.assertFalse(target.IsValid())41        self.dbg.DeleteTarget(target)42 43    def test_debugger_internal_variables(self):44        """Ensure that SBDebugger reachs the same instance of properties45        regardless CommandInterpreter's context initialization"""46        self.build()47        exe = self.getBuildArtifact("a.out")48 49        # Create a target by the debugger.50        target = self.dbg.CreateTarget(exe)51        self.assertTrue(target, VALID_TARGET)52 53        property_name = "target.process.memory-cache-line-size"54 55        def get_cache_line_size():56            value_list = lldb.SBStringList()57            value_list = self.dbg.GetInternalVariableValue(58                property_name, self.dbg.GetInstanceName()59            )60 61            self.assertEqual(value_list.GetSize(), 1)62            try:63                return int(value_list.GetStringAtIndex(0))64            except ValueError as error:65                self.fail("Value is not a number: " + error)66 67        # Get global property value while there are no processes.68        global_cache_line_size = get_cache_line_size()69 70        # Run a process via SB interface. CommandInterpreter's execution context71        # remains empty.72        error = lldb.SBError()73        launch_info = lldb.SBLaunchInfo(None)74        launch_info.SetLaunchFlags(lldb.eLaunchFlagStopAtEntry)75        process = target.Launch(launch_info, error)76        self.assertTrue(process, PROCESS_IS_VALID)77 78        # This should change the value of a process's local property.79        new_cache_line_size = global_cache_line_size + 51280        error = self.dbg.SetInternalVariable(81            property_name, str(new_cache_line_size), self.dbg.GetInstanceName()82        )83        self.assertSuccess(error, property_name + " value was changed successfully")84 85        # Check that it was set actually.86        self.assertEqual(get_cache_line_size(), new_cache_line_size)87 88        # Run any command to initialize CommandInterpreter's execution context.89        self.runCmd("target list")90 91        # Test the local property again, is it set to new_cache_line_size?92        self.assertEqual(get_cache_line_size(), new_cache_line_size)93 94    @expectedFailureAll(95        remote=True,96        bugnumber="github.com/llvm/llvm-project/issues/92419",97    )98    def test_CreateTarget_platform(self):99        exe = self.getBuildArtifact("a.out")100        self.yaml2obj("elf.yaml", exe)101        error = lldb.SBError()102        target1 = self.dbg.CreateTarget(exe, None, "remote-linux", False, error)103        self.assertSuccess(error)104        platform1 = target1.GetPlatform()105        platform1.SetWorkingDirectory("/foo/bar")106 107        # Reuse a platform if it matches the currently selected one...108        target2 = self.dbg.CreateTarget(exe, None, "remote-linux", False, error)109        self.assertSuccess(error)110        platform2 = target2.GetPlatform()111        self.assertTrue(112            platform2.GetWorkingDirectory().endswith("bar"),113            platform2.GetWorkingDirectory(),114        )115 116        # ... but create a new one if it doesn't.117        self.dbg.SetSelectedPlatform(lldb.SBPlatform("remote-windows"))118        target3 = self.dbg.CreateTarget(exe, None, "remote-linux", False, error)119        self.assertSuccess(error)120        platform3 = target3.GetPlatform()121        self.assertIsNone(platform3.GetWorkingDirectory())122 123    def test_CreateTarget_arch(self):124        exe = self.getBuildArtifact("a.out")125        if lldbplatformutil.getHostPlatform() == "linux":126            self.yaml2obj("macho.yaml", exe)127            arch = "x86_64-apple-macosx"128            expected_platform = "remote-macosx"129        else:130            self.yaml2obj("elf.yaml", exe)131            arch = "x86_64-pc-linux"132            expected_platform = "remote-linux"133 134        fbsd = lldb.SBPlatform("remote-freebsd")135        self.dbg.SetSelectedPlatform(fbsd)136 137        error = lldb.SBError()138        target1 = self.dbg.CreateTarget(exe, arch, None, False, error)139        self.assertSuccess(error)140        platform1 = target1.GetPlatform()141        self.assertEqual(platform1.GetName(), expected_platform)142        platform1.SetWorkingDirectory("/foo/bar")143 144        # Reuse a platform even if it is not currently selected.145        self.dbg.SetSelectedPlatform(fbsd)146        target2 = self.dbg.CreateTarget(exe, arch, None, False, error)147        self.assertSuccess(error)148        platform2 = target2.GetPlatform()149        self.assertEqual(platform2.GetName(), expected_platform)150        self.assertTrue(151            platform2.GetWorkingDirectory().endswith("bar"),152            platform2.GetWorkingDirectory(),153        )154 155    def test_SetDestroyCallback(self):156        destroy_dbg_id = None157 158        def foo(dbg_id):159            # Need nonlocal to modify closure variable.160            nonlocal destroy_dbg_id161            destroy_dbg_id = dbg_id162 163        self.dbg.SetDestroyCallback(foo)164 165        original_dbg_id = self.dbg.GetID()166        self.dbg.Destroy(self.dbg)167        self.assertEqual(destroy_dbg_id, original_dbg_id)168 169    def test_AddDestroyCallback(self):170        original_dbg_id = self.dbg.GetID()171        called = []172 173        def foo(dbg_id):174            # Need nonlocal to modify closure variable.175            nonlocal called176            called += [('foo', dbg_id)]177 178        def bar(dbg_id):179            # Need nonlocal to modify closure variable.180            nonlocal called181            called += [('bar', dbg_id)]182 183        token_foo = self.dbg.AddDestroyCallback(foo)184        token_bar = self.dbg.AddDestroyCallback(bar)185        self.dbg.Destroy(self.dbg)186 187        # Should call both `foo()` and `bar()`.188        self.assertEqual(called, [189            ('foo', original_dbg_id),190            ('bar', original_dbg_id),191        ])192 193    def test_RemoveDestroyCallback(self):194        original_dbg_id = self.dbg.GetID()195        called = []196 197        def foo(dbg_id):198            # Need nonlocal to modify closure variable.199            nonlocal called200            called += [('foo', dbg_id)]201 202        def bar(dbg_id):203            # Need nonlocal to modify closure variable.204            nonlocal called205            called += [('bar', dbg_id)]206 207        token_foo = self.dbg.AddDestroyCallback(foo)208        token_bar = self.dbg.AddDestroyCallback(bar)209        ret = self.dbg.RemoveDestroyCallback(token_foo)210        self.dbg.Destroy(self.dbg)211 212        # `Remove` should be successful213        self.assertTrue(ret)214        # Should only call `bar()`215        self.assertEqual(called, [('bar', original_dbg_id)])216 217    def test_RemoveDestroyCallback_invalid_token(self):218        original_dbg_id = self.dbg.GetID()219        magic_token_that_should_not_exist = 32413220        called = []221 222        def foo(dbg_id):223            # Need nonlocal to modify closure variable.224            nonlocal called225            called += [('foo', dbg_id)]226 227        token_foo = self.dbg.AddDestroyCallback(foo)228        ret = self.dbg.RemoveDestroyCallback(magic_token_that_should_not_exist)229        self.dbg.Destroy(self.dbg)230 231        # `Remove` should be unsuccessful232        self.assertFalse(ret)233        # Should call `foo()`234        self.assertEqual(called, [('foo', original_dbg_id)])235 236    def test_HandleDestroyCallback(self):237        """238        Validates:239        1. AddDestroyCallback and RemoveDestroyCallback work during debugger destroy.240        2. HandleDestroyCallback invokes all callbacks in FIFO order.241        """242        original_dbg_id = self.dbg.GetID()243        events = []244        bar_token = None245 246        def foo(dbg_id):247            # Need nonlocal to modify closure variable.248            nonlocal events249            events.append(('foo called', dbg_id))250 251        def bar(dbg_id):252            # Need nonlocal to modify closure variable.253            nonlocal events254            events.append(('bar called', dbg_id))255 256        def add_foo(dbg_id):257            # Need nonlocal to modify closure variable.258            nonlocal events259            events.append(('add_foo called', dbg_id))260            events.append(('foo token', self.dbg.AddDestroyCallback(foo)))261 262        def remove_bar(dbg_id):263            # Need nonlocal to modify closure variable.264            nonlocal events265            events.append(('remove_bar called', dbg_id))266            events.append(('remove bar ret', self.dbg.RemoveDestroyCallback(bar_token)))267 268        # Setup269        events.append(('add_foo token', self.dbg.AddDestroyCallback(add_foo)))270        bar_token = self.dbg.AddDestroyCallback(bar)271        events.append(('bar token', bar_token))272        events.append(('remove_bar token', self.dbg.AddDestroyCallback(remove_bar)))273        # Destroy274        self.dbg.Destroy(self.dbg)275 276        self.assertEqual(events, [277            # Setup278            ('add_foo token', 0), # add_foo should be added279            ('bar token', 1), # bar should be added280            ('remove_bar token', 2), # remove_bar should be added281            # Destroy282            ('add_foo called', original_dbg_id), # add_foo should be called283            ('foo token', 3), # foo should be added284            ('bar called', original_dbg_id), # bar should be called285            ('remove_bar called', original_dbg_id), # remove_bar should be called286            ('remove bar ret', False), # remove_bar should fail, because it's already invoked and removed287            ('foo called', original_dbg_id), # foo should be called288        ])289 290    def test_version(self):291        instance_str = self.dbg.GetVersionString()292        class_str = lldb.SBDebugger.GetVersionString()293        property_str = lldb.SBDebugger.version294 295        self.assertEqual(instance_str, class_str)296        self.assertEqual(class_str, property_str)297 298    def test_find_target_with_unique_id(self):299        """Test SBDebugger.FindTargetByGloballyUniqueID() functionality."""300 301        # Test with invalid ID - should return invalid target302        invalid_target = self.dbg.FindTargetByGloballyUniqueID(999999)303        self.assertFalse(invalid_target.IsValid())304 305        # Test with ID 0 - should return invalid target306        zero_target = self.dbg.FindTargetByGloballyUniqueID(0)307        self.assertFalse(zero_target.IsValid())308 309        # Build a real executable and create target with it310        self.build()311        exe = self.getBuildArtifact("a.out")312        target = self.dbg.CreateTarget(exe)313        self.assertTrue(target.IsValid())314 315        # Find the target using its unique ID316        unique_id = target.GetGloballyUniqueID()317        self.assertNotEqual(unique_id, lldb.LLDB_INVALID_GLOBALLY_UNIQUE_TARGET_ID)318        found_target = self.dbg.FindTargetByGloballyUniqueID(unique_id)319        self.assertTrue(found_target.IsValid())320        self.assertEqual(321            self.dbg.GetIndexOfTarget(target), self.dbg.GetIndexOfTarget(found_target)322        )323        self.assertEqual(found_target.GetGloballyUniqueID(), unique_id)324 325    def test_target_unique_id_uniqueness(self):326        """Test that Target.GetGloballyUniqueID() returns unique values across multiple targets."""327 328        # Create multiple targets and verify they all have unique IDs329        self.build()330        exe = self.getBuildArtifact("a.out")331        targets = []332        unique_ids = set()333 334        for i in range(10):335            target = self.dbg.CreateTarget(exe)336            self.assertTrue(target.IsValid())337 338            unique_id = target.GetGloballyUniqueID()339            self.assertNotEqual(unique_id, 0)340 341            # Verify this ID hasn't been used before342            self.assertNotIn(343                unique_id, unique_ids, f"Duplicate unique ID found: {unique_id}"344            )345 346            unique_ids.add(unique_id)347            targets.append(target)348 349        # Verify all targets can still be found by their IDs350        for target in targets:351            unique_id = target.GetGloballyUniqueID()352            found = self.dbg.FindTargetByGloballyUniqueID(unique_id)353            self.assertTrue(found.IsValid())354            self.assertEqual(found.GetGloballyUniqueID(), unique_id)355 356    def test_target_unique_id_uniqueness_after_deletion(self):357        """Test finding targets have unique ID after target deletion."""358        # Create two targets359        self.build()360        exe = self.getBuildArtifact("a.out")361        target1 = self.dbg.CreateTarget(exe)362        target2 = self.dbg.CreateTarget(exe)363        self.assertTrue(target1.IsValid())364        self.assertTrue(target2.IsValid())365 366        unique_id1 = target1.GetGloballyUniqueID()367        unique_id2 = target2.GetGloballyUniqueID()368        self.assertNotEqual(unique_id1, 0)369        self.assertNotEqual(unique_id2, 0)370        self.assertNotEqual(unique_id1, unique_id2)371 372        # Verify we can find them initially373        found_target1 = self.dbg.FindTargetByGloballyUniqueID(unique_id1)374        found_target2 = self.dbg.FindTargetByGloballyUniqueID(unique_id2)375        self.assertTrue(found_target1.IsValid())376        self.assertTrue(found_target2.IsValid())377        target2_index = self.dbg.GetIndexOfTarget(target2)378 379        # Delete target 2380        deleted = self.dbg.DeleteTarget(target2)381        self.assertTrue(deleted)382 383        # Try to find the deleted target - should not be found384        not_found_target = self.dbg.FindTargetByGloballyUniqueID(unique_id2)385        self.assertFalse(not_found_target.IsValid())386 387        # Create a new target388        target3 = self.dbg.CreateTarget(exe)389        self.assertTrue(target3.IsValid())390        # Target list index of target3 should be the same as target2's391        # since it was deleted, but it should have a distinct unique ID392        target3_index = self.dbg.GetIndexOfTarget(target3)393        unique_id3 = target3.GetGloballyUniqueID()394        self.assertEqual(target3_index, target2_index)395        self.assertNotEqual(unique_id3, unique_id2)396        self.assertNotEqual(unique_id3, unique_id1)397        # Make sure we can find the new target398        found_target3 = self.dbg.FindTargetByGloballyUniqueID(399            target3.GetGloballyUniqueID()400        )401        self.assertTrue(found_target3.IsValid())402 403    def test_target_globally_unique_id_across_debuggers(self):404        """Test that target IDs are globally unique across multiple debuggers."""405        self.build()406        exe = self.getBuildArtifact("a.out")407 408        # Create two debuggers with targets each409        debugger1 = lldb.SBDebugger.Create()410        debugger2 = lldb.SBDebugger.Create()411        self.addTearDownHook(lambda: lldb.SBDebugger.Destroy(debugger1))412        self.addTearDownHook(lambda: lldb.SBDebugger.Destroy(debugger2))413 414        # Create 2 targets per debugger415        targets_d1 = [debugger1.CreateTarget(exe), debugger1.CreateTarget(exe)]416        targets_d2 = [debugger2.CreateTarget(exe), debugger2.CreateTarget(exe)]417        targets = targets_d1 + targets_d2418 419        # Get all IDs and verify they're unique420        ids = [target.GetGloballyUniqueID() for target in targets]421        self.assertEqual(422            len(set(ids)), len(ids), f"IDs should be globally unique: {ids}"423        )424        self.assertTrue(425            all(uid != lldb.LLDB_INVALID_GLOBALLY_UNIQUE_TARGET_ID for uid in ids),426            "All IDs should be valid",427        )428 429        # Verify targets can be found by their IDs in respective debuggers430        for debugger, target_pair in [431            (debugger1, targets[:2]),432            (debugger2, targets[2:]),433        ]:434            for target in target_pair:435                found = debugger.FindTargetByGloballyUniqueID(436                    target.GetGloballyUniqueID()437                )438                self.assertTrue(439                    found.IsValid(), "Target should be found by its unique ID"440                )441                self.assertEqual(442                    found.GetGloballyUniqueID(), target.GetGloballyUniqueID()443                )444