199451b44SJordan Rupprecht""" 299451b44SJordan RupprechtTest Debugger APIs. 399451b44SJordan Rupprecht""" 499451b44SJordan Rupprecht 599451b44SJordan Rupprechtimport lldb 699451b44SJordan Rupprecht 799451b44SJordan Rupprechtfrom lldbsuite.test.decorators import * 899451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import * 999451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil 1099451b44SJordan Rupprecht 1199451b44SJordan Rupprecht 1299451b44SJordan Rupprechtclass DebuggerAPITestCase(TestBase): 1399451b44SJordan Rupprecht NO_DEBUG_INFO_TESTCASE = True 1499451b44SJordan Rupprecht 1599451b44SJordan Rupprecht def test_debugger_api_boundary_condition(self): 1699451b44SJordan Rupprecht """Exercise SBDebugger APIs with boundary conditions.""" 1799451b44SJordan Rupprecht self.dbg.HandleCommand(None) 1899451b44SJordan Rupprecht self.dbg.SetDefaultArchitecture(None) 1999451b44SJordan Rupprecht self.dbg.GetScriptingLanguage(None) 2099451b44SJordan Rupprecht self.dbg.CreateTarget(None) 2199451b44SJordan Rupprecht self.dbg.CreateTarget(None, None, None, True, lldb.SBError()) 2299451b44SJordan Rupprecht self.dbg.CreateTargetWithFileAndTargetTriple(None, None) 2399451b44SJordan Rupprecht self.dbg.CreateTargetWithFileAndArch(None, None) 2499451b44SJordan Rupprecht self.dbg.FindTargetWithFileAndArch(None, None) 2599451b44SJordan Rupprecht self.dbg.SetInternalVariable(None, None, None) 2699451b44SJordan Rupprecht self.dbg.GetInternalVariableValue(None, None) 2799451b44SJordan Rupprecht # FIXME (filcab): We must first allow for the swig bindings to know if 2899451b44SJordan Rupprecht # a Python callback is set. (Check python-typemaps.swig) 2999451b44SJordan Rupprecht # self.dbg.SetLoggingCallback(None) 3099451b44SJordan Rupprecht self.dbg.SetPrompt(None) 3199451b44SJordan Rupprecht self.dbg.SetCurrentPlatform(None) 3299451b44SJordan Rupprecht self.dbg.SetCurrentPlatformSDKRoot(None) 3399451b44SJordan Rupprecht 3499451b44SJordan Rupprecht fresh_dbg = lldb.SBDebugger() 3580fcecb1SJonas Devlieghere self.assertEqual(len(fresh_dbg), 0) 3699451b44SJordan Rupprecht 3799451b44SJordan Rupprecht def test_debugger_delete_invalid_target(self): 3899451b44SJordan Rupprecht """SBDebugger.DeleteTarget() should not crash LLDB given and invalid target.""" 3999451b44SJordan Rupprecht target = lldb.SBTarget() 4099451b44SJordan Rupprecht self.assertFalse(target.IsValid()) 4199451b44SJordan Rupprecht self.dbg.DeleteTarget(target) 4236de94cfSTatyana Krasnukha 4336de94cfSTatyana Krasnukha def test_debugger_internal_variables(self): 4436de94cfSTatyana Krasnukha """Ensure that SBDebugger reachs the same instance of properties 4536de94cfSTatyana Krasnukha regardless CommandInterpreter's context initialization""" 4636de94cfSTatyana Krasnukha self.build() 4736de94cfSTatyana Krasnukha exe = self.getBuildArtifact("a.out") 4836de94cfSTatyana Krasnukha 4936de94cfSTatyana Krasnukha # Create a target by the debugger. 5036de94cfSTatyana Krasnukha target = self.dbg.CreateTarget(exe) 5136de94cfSTatyana Krasnukha self.assertTrue(target, VALID_TARGET) 5236de94cfSTatyana Krasnukha 5336de94cfSTatyana Krasnukha property_name = "target.process.memory-cache-line-size" 5436de94cfSTatyana Krasnukha 5536de94cfSTatyana Krasnukha def get_cache_line_size(): 5636de94cfSTatyana Krasnukha value_list = lldb.SBStringList() 572238dcc3SJonas Devlieghere value_list = self.dbg.GetInternalVariableValue( 582238dcc3SJonas Devlieghere property_name, self.dbg.GetInstanceName() 592238dcc3SJonas Devlieghere ) 6036de94cfSTatyana Krasnukha 6136de94cfSTatyana Krasnukha self.assertEqual(value_list.GetSize(), 1) 6236de94cfSTatyana Krasnukha try: 6336de94cfSTatyana Krasnukha return int(value_list.GetStringAtIndex(0)) 6436de94cfSTatyana Krasnukha except ValueError as error: 6536de94cfSTatyana Krasnukha self.fail("Value is not a number: " + error) 6636de94cfSTatyana Krasnukha 6736de94cfSTatyana Krasnukha # Get global property value while there are no processes. 6836de94cfSTatyana Krasnukha global_cache_line_size = get_cache_line_size() 6936de94cfSTatyana Krasnukha 7036de94cfSTatyana Krasnukha # Run a process via SB interface. CommandInterpreter's execution context 7136de94cfSTatyana Krasnukha # remains empty. 7236de94cfSTatyana Krasnukha error = lldb.SBError() 7336de94cfSTatyana Krasnukha launch_info = lldb.SBLaunchInfo(None) 7436de94cfSTatyana Krasnukha launch_info.SetLaunchFlags(lldb.eLaunchFlagStopAtEntry) 7536de94cfSTatyana Krasnukha process = target.Launch(launch_info, error) 7636de94cfSTatyana Krasnukha self.assertTrue(process, PROCESS_IS_VALID) 7736de94cfSTatyana Krasnukha 7836de94cfSTatyana Krasnukha # This should change the value of a process's local property. 7936de94cfSTatyana Krasnukha new_cache_line_size = global_cache_line_size + 512 802238dcc3SJonas Devlieghere error = self.dbg.SetInternalVariable( 812238dcc3SJonas Devlieghere property_name, str(new_cache_line_size), self.dbg.GetInstanceName() 822238dcc3SJonas Devlieghere ) 832238dcc3SJonas Devlieghere self.assertSuccess(error, property_name + " value was changed successfully") 8436de94cfSTatyana Krasnukha 8536de94cfSTatyana Krasnukha # Check that it was set actually. 8636de94cfSTatyana Krasnukha self.assertEqual(get_cache_line_size(), new_cache_line_size) 8736de94cfSTatyana Krasnukha 8836de94cfSTatyana Krasnukha # Run any command to initialize CommandInterpreter's execution context. 8936de94cfSTatyana Krasnukha self.runCmd("target list") 9036de94cfSTatyana Krasnukha 9136de94cfSTatyana Krasnukha # Test the local property again, is it set to new_cache_line_size? 9236de94cfSTatyana Krasnukha self.assertEqual(get_cache_line_size(), new_cache_line_size) 93af921006SPavel Labath 94*77369a7fSDmitry Vasilyev @expectedFailureAll( 95*77369a7fSDmitry Vasilyev remote=True, 96*77369a7fSDmitry Vasilyev bugnumber="github.com/llvm/llvm-project/issues/92419", 97*77369a7fSDmitry Vasilyev ) 98af921006SPavel Labath def test_CreateTarget_platform(self): 99af921006SPavel Labath exe = self.getBuildArtifact("a.out") 100af921006SPavel Labath self.yaml2obj("elf.yaml", exe) 101af921006SPavel Labath error = lldb.SBError() 1022238dcc3SJonas Devlieghere target1 = self.dbg.CreateTarget(exe, None, "remote-linux", False, error) 103af921006SPavel Labath self.assertSuccess(error) 104af921006SPavel Labath platform1 = target1.GetPlatform() 105af921006SPavel Labath platform1.SetWorkingDirectory("/foo/bar") 106af921006SPavel Labath 107af921006SPavel Labath # Reuse a platform if it matches the currently selected one... 1082238dcc3SJonas Devlieghere target2 = self.dbg.CreateTarget(exe, None, "remote-linux", False, error) 109af921006SPavel Labath self.assertSuccess(error) 110af921006SPavel Labath platform2 = target2.GetPlatform() 1112238dcc3SJonas Devlieghere self.assertTrue( 1122238dcc3SJonas Devlieghere platform2.GetWorkingDirectory().endswith("bar"), 1132238dcc3SJonas Devlieghere platform2.GetWorkingDirectory(), 1142238dcc3SJonas Devlieghere ) 115af921006SPavel Labath 116af921006SPavel Labath # ... but create a new one if it doesn't. 117af921006SPavel Labath self.dbg.SetSelectedPlatform(lldb.SBPlatform("remote-windows")) 1182238dcc3SJonas Devlieghere target3 = self.dbg.CreateTarget(exe, None, "remote-linux", False, error) 119af921006SPavel Labath self.assertSuccess(error) 120af921006SPavel Labath platform3 = target3.GetPlatform() 121af921006SPavel Labath self.assertIsNone(platform3.GetWorkingDirectory()) 122af921006SPavel Labath 123af921006SPavel Labath def test_CreateTarget_arch(self): 124af921006SPavel Labath exe = self.getBuildArtifact("a.out") 1252238dcc3SJonas Devlieghere if lldbplatformutil.getHostPlatform() == "linux": 126af921006SPavel Labath self.yaml2obj("macho.yaml", exe) 127af921006SPavel Labath arch = "x86_64-apple-macosx" 1287d70b1a4SPavel Labath expected_platform = "remote-macosx" 129af921006SPavel Labath else: 130af921006SPavel Labath self.yaml2obj("elf.yaml", exe) 131af921006SPavel Labath arch = "x86_64-pc-linux" 1327d70b1a4SPavel Labath expected_platform = "remote-linux" 133af921006SPavel Labath 134af921006SPavel Labath fbsd = lldb.SBPlatform("remote-freebsd") 135af921006SPavel Labath self.dbg.SetSelectedPlatform(fbsd) 136af921006SPavel Labath 137af921006SPavel Labath error = lldb.SBError() 138af921006SPavel Labath target1 = self.dbg.CreateTarget(exe, arch, None, False, error) 139af921006SPavel Labath self.assertSuccess(error) 140af921006SPavel Labath platform1 = target1.GetPlatform() 1417d70b1a4SPavel Labath self.assertEqual(platform1.GetName(), expected_platform) 142af921006SPavel Labath platform1.SetWorkingDirectory("/foo/bar") 143af921006SPavel Labath 144af921006SPavel Labath # Reuse a platform even if it is not currently selected. 145af921006SPavel Labath self.dbg.SetSelectedPlatform(fbsd) 146af921006SPavel Labath target2 = self.dbg.CreateTarget(exe, arch, None, False, error) 147af921006SPavel Labath self.assertSuccess(error) 148af921006SPavel Labath platform2 = target2.GetPlatform() 1497d70b1a4SPavel Labath self.assertEqual(platform2.GetName(), expected_platform) 1502238dcc3SJonas Devlieghere self.assertTrue( 1512238dcc3SJonas Devlieghere platform2.GetWorkingDirectory().endswith("bar"), 1522238dcc3SJonas Devlieghere platform2.GetWorkingDirectory(), 1532238dcc3SJonas Devlieghere ) 154b461398fSJeffrey Tan 155b461398fSJeffrey Tan def test_SetDestroyCallback(self): 156b461398fSJeffrey Tan destroy_dbg_id = None 1572238dcc3SJonas Devlieghere 158b461398fSJeffrey Tan def foo(dbg_id): 159b461398fSJeffrey Tan # Need nonlocal to modify closure variable. 160b461398fSJeffrey Tan nonlocal destroy_dbg_id 161b461398fSJeffrey Tan destroy_dbg_id = dbg_id 162b461398fSJeffrey Tan 163b461398fSJeffrey Tan self.dbg.SetDestroyCallback(foo) 164b461398fSJeffrey Tan 165b461398fSJeffrey Tan original_dbg_id = self.dbg.GetID() 166b461398fSJeffrey Tan self.dbg.Destroy(self.dbg) 167b461398fSJeffrey Tan self.assertEqual(destroy_dbg_id, original_dbg_id) 1689f627750Sroyitaqi 1699f627750Sroyitaqi def test_AddDestroyCallback(self): 1709f627750Sroyitaqi original_dbg_id = self.dbg.GetID() 1719f627750Sroyitaqi called = [] 1729f627750Sroyitaqi 1739f627750Sroyitaqi def foo(dbg_id): 1749f627750Sroyitaqi # Need nonlocal to modify closure variable. 1759f627750Sroyitaqi nonlocal called 1769f627750Sroyitaqi called += [('foo', dbg_id)] 1779f627750Sroyitaqi 1789f627750Sroyitaqi def bar(dbg_id): 1799f627750Sroyitaqi # Need nonlocal to modify closure variable. 1809f627750Sroyitaqi nonlocal called 1819f627750Sroyitaqi called += [('bar', dbg_id)] 1829f627750Sroyitaqi 1839f627750Sroyitaqi token_foo = self.dbg.AddDestroyCallback(foo) 1849f627750Sroyitaqi token_bar = self.dbg.AddDestroyCallback(bar) 1859f627750Sroyitaqi self.dbg.Destroy(self.dbg) 1869f627750Sroyitaqi 1879f627750Sroyitaqi # Should call both `foo()` and `bar()`. 1889f627750Sroyitaqi self.assertEqual(called, [ 1899f627750Sroyitaqi ('foo', original_dbg_id), 1909f627750Sroyitaqi ('bar', original_dbg_id), 1919f627750Sroyitaqi ]) 1929f627750Sroyitaqi 1939f627750Sroyitaqi def test_RemoveDestroyCallback(self): 1949f627750Sroyitaqi original_dbg_id = self.dbg.GetID() 1959f627750Sroyitaqi called = [] 1969f627750Sroyitaqi 1979f627750Sroyitaqi def foo(dbg_id): 1989f627750Sroyitaqi # Need nonlocal to modify closure variable. 1999f627750Sroyitaqi nonlocal called 2009f627750Sroyitaqi called += [('foo', dbg_id)] 2019f627750Sroyitaqi 2029f627750Sroyitaqi def bar(dbg_id): 2039f627750Sroyitaqi # Need nonlocal to modify closure variable. 2049f627750Sroyitaqi nonlocal called 2059f627750Sroyitaqi called += [('bar', dbg_id)] 2069f627750Sroyitaqi 2079f627750Sroyitaqi token_foo = self.dbg.AddDestroyCallback(foo) 2089f627750Sroyitaqi token_bar = self.dbg.AddDestroyCallback(bar) 2099f627750Sroyitaqi ret = self.dbg.RemoveDestroyCallback(token_foo) 2109f627750Sroyitaqi self.dbg.Destroy(self.dbg) 2119f627750Sroyitaqi 2129f627750Sroyitaqi # `Remove` should be successful 2139f627750Sroyitaqi self.assertTrue(ret) 2149f627750Sroyitaqi # Should only call `bar()` 2159f627750Sroyitaqi self.assertEqual(called, [('bar', original_dbg_id)]) 2169f627750Sroyitaqi 2179f627750Sroyitaqi def test_RemoveDestroyCallback_invalid_token(self): 2189f627750Sroyitaqi original_dbg_id = self.dbg.GetID() 2199f627750Sroyitaqi magic_token_that_should_not_exist = 32413 2209f627750Sroyitaqi called = [] 2219f627750Sroyitaqi 2229f627750Sroyitaqi def foo(dbg_id): 2239f627750Sroyitaqi # Need nonlocal to modify closure variable. 2249f627750Sroyitaqi nonlocal called 2259f627750Sroyitaqi called += [('foo', dbg_id)] 2269f627750Sroyitaqi 2279f627750Sroyitaqi token_foo = self.dbg.AddDestroyCallback(foo) 2289f627750Sroyitaqi ret = self.dbg.RemoveDestroyCallback(magic_token_that_should_not_exist) 2299f627750Sroyitaqi self.dbg.Destroy(self.dbg) 2309f627750Sroyitaqi 2319f627750Sroyitaqi # `Remove` should be unsuccessful 2329f627750Sroyitaqi self.assertFalse(ret) 2339f627750Sroyitaqi # Should call `foo()` 2349f627750Sroyitaqi self.assertEqual(called, [('foo', original_dbg_id)]) 2359f627750Sroyitaqi 2369f627750Sroyitaqi def test_HandleDestroyCallback(self): 2379f627750Sroyitaqi """ 2389f627750Sroyitaqi Validates: 2399f627750Sroyitaqi 1. AddDestroyCallback and RemoveDestroyCallback work during debugger destroy. 2409f627750Sroyitaqi 2. HandleDestroyCallback invokes all callbacks in FIFO order. 2419f627750Sroyitaqi """ 2429f627750Sroyitaqi original_dbg_id = self.dbg.GetID() 2439f627750Sroyitaqi events = [] 2449f627750Sroyitaqi bar_token = None 2459f627750Sroyitaqi 2469f627750Sroyitaqi def foo(dbg_id): 2479f627750Sroyitaqi # Need nonlocal to modify closure variable. 2489f627750Sroyitaqi nonlocal events 2499f627750Sroyitaqi events.append(('foo called', dbg_id)) 2509f627750Sroyitaqi 2519f627750Sroyitaqi def bar(dbg_id): 2529f627750Sroyitaqi # Need nonlocal to modify closure variable. 2539f627750Sroyitaqi nonlocal events 2549f627750Sroyitaqi events.append(('bar called', dbg_id)) 2559f627750Sroyitaqi 2569f627750Sroyitaqi def add_foo(dbg_id): 2579f627750Sroyitaqi # Need nonlocal to modify closure variable. 2589f627750Sroyitaqi nonlocal events 2599f627750Sroyitaqi events.append(('add_foo called', dbg_id)) 2609f627750Sroyitaqi events.append(('foo token', self.dbg.AddDestroyCallback(foo))) 2619f627750Sroyitaqi 2629f627750Sroyitaqi def remove_bar(dbg_id): 2639f627750Sroyitaqi # Need nonlocal to modify closure variable. 2649f627750Sroyitaqi nonlocal events 2659f627750Sroyitaqi events.append(('remove_bar called', dbg_id)) 2669f627750Sroyitaqi events.append(('remove bar ret', self.dbg.RemoveDestroyCallback(bar_token))) 2679f627750Sroyitaqi 2689f627750Sroyitaqi # Setup 2699f627750Sroyitaqi events.append(('add_foo token', self.dbg.AddDestroyCallback(add_foo))) 2709f627750Sroyitaqi bar_token = self.dbg.AddDestroyCallback(bar) 2719f627750Sroyitaqi events.append(('bar token', bar_token)) 2729f627750Sroyitaqi events.append(('remove_bar token', self.dbg.AddDestroyCallback(remove_bar))) 2739f627750Sroyitaqi # Destroy 2749f627750Sroyitaqi self.dbg.Destroy(self.dbg) 2759f627750Sroyitaqi 2769f627750Sroyitaqi self.assertEqual(events, [ 2779f627750Sroyitaqi # Setup 2789f627750Sroyitaqi ('add_foo token', 0), # add_foo should be added 2799f627750Sroyitaqi ('bar token', 1), # bar should be added 2809f627750Sroyitaqi ('remove_bar token', 2), # remove_bar should be added 2819f627750Sroyitaqi # Destroy 2829f627750Sroyitaqi ('add_foo called', original_dbg_id), # add_foo should be called 2839f627750Sroyitaqi ('foo token', 3), # foo should be added 2849f627750Sroyitaqi ('bar called', original_dbg_id), # bar should be called 2859f627750Sroyitaqi ('remove_bar called', original_dbg_id), # remove_bar should be called 2869f627750Sroyitaqi ('remove bar ret', False), # remove_bar should fail, because it's already invoked and removed 2879f627750Sroyitaqi ('foo called', original_dbg_id), # foo should be called 2889f627750Sroyitaqi ]) 289