"""
Test Debugger APIs.
"""
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
class DebuggerAPITestCase(TestBase):
NO_DEBUG_INFO_TESTCASE = True
def test_debugger_api_boundary_condition(self):
"""Exercise SBDebugger APIs with boundary conditions."""
self.dbg.HandleCommand(None)
self.dbg.SetDefaultArchitecture(None)
self.dbg.GetScriptingLanguage(None)
self.dbg.CreateTarget(None)
self.dbg.CreateTarget(None, None, None, True, lldb.SBError())
self.dbg.CreateTargetWithFileAndTargetTriple(None, None)
self.dbg.CreateTargetWithFileAndArch(None, None)
self.dbg.FindTargetWithFileAndArch(None, None)
self.dbg.SetInternalVariable(None, None, None)
self.dbg.GetInternalVariableValue(None, None)
self.dbg.SetPrompt(None)
self.dbg.SetCurrentPlatform(None)
self.dbg.SetCurrentPlatformSDKRoot(None)
fresh_dbg = lldb.SBDebugger()
self.assertEqual(len(fresh_dbg), 0)
def test_debugger_delete_invalid_target(self):
"""SBDebugger.DeleteTarget() should not crash LLDB given and invalid target."""
target = lldb.SBTarget()
self.assertFalse(target.IsValid())
self.dbg.DeleteTarget(target)
def test_debugger_internal_variables(self):
"""Ensure that SBDebugger reachs the same instance of properties
regardless CommandInterpreter's context initialization"""
self.build()
exe = self.getBuildArtifact("a.out")
target = self.dbg.CreateTarget(exe)
self.assertTrue(target, VALID_TARGET)
property_name = "target.process.memory-cache-line-size"
def get_cache_line_size():
value_list = lldb.SBStringList()
value_list = self.dbg.GetInternalVariableValue(
property_name, self.dbg.GetInstanceName()
)
self.assertEqual(value_list.GetSize(), 1)
try:
return int(value_list.GetStringAtIndex(0))
except ValueError as error:
self.fail("Value is not a number: " + error)
global_cache_line_size = get_cache_line_size()
error = lldb.SBError()
launch_info = lldb.SBLaunchInfo(None)
launch_info.SetLaunchFlags(lldb.eLaunchFlagStopAtEntry)
process = target.Launch(launch_info, error)
self.assertTrue(process, PROCESS_IS_VALID)
new_cache_line_size = global_cache_line_size + 512
error = self.dbg.SetInternalVariable(
property_name, str(new_cache_line_size), self.dbg.GetInstanceName()
)
self.assertSuccess(error, property_name + " value was changed successfully")
self.assertEqual(get_cache_line_size(), new_cache_line_size)
self.runCmd("target list")
self.assertEqual(get_cache_line_size(), new_cache_line_size)
@expectedFailureAll(
remote=True,
bugnumber="github.com/llvm/llvm-project/issues/92419",
)
def test_CreateTarget_platform(self):
exe = self.getBuildArtifact("a.out")
self.yaml2obj("elf.yaml", exe)
error = lldb.SBError()
target1 = self.dbg.CreateTarget(exe, None, "remote-linux", False, error)
self.assertSuccess(error)
platform1 = target1.GetPlatform()
platform1.SetWorkingDirectory("/foo/bar")
target2 = self.dbg.CreateTarget(exe, None, "remote-linux", False, error)
self.assertSuccess(error)
platform2 = target2.GetPlatform()
self.assertTrue(
platform2.GetWorkingDirectory().endswith("bar"),
platform2.GetWorkingDirectory(),
)
self.dbg.SetSelectedPlatform(lldb.SBPlatform("remote-windows"))
target3 = self.dbg.CreateTarget(exe, None, "remote-linux", False, error)
self.assertSuccess(error)
platform3 = target3.GetPlatform()
self.assertIsNone(platform3.GetWorkingDirectory())
def test_CreateTarget_arch(self):
exe = self.getBuildArtifact("a.out")
if lldbplatformutil.getHostPlatform() == "linux":
self.yaml2obj("macho.yaml", exe)
arch = "x86_64-apple-macosx"
expected_platform = "remote-macosx"
else:
self.yaml2obj("elf.yaml", exe)
arch = "x86_64-pc-linux"
expected_platform = "remote-linux"
fbsd = lldb.SBPlatform("remote-freebsd")
self.dbg.SetSelectedPlatform(fbsd)
error = lldb.SBError()
target1 = self.dbg.CreateTarget(exe, arch, None, False, error)
self.assertSuccess(error)
platform1 = target1.GetPlatform()
self.assertEqual(platform1.GetName(), expected_platform)
platform1.SetWorkingDirectory("/foo/bar")
self.dbg.SetSelectedPlatform(fbsd)
target2 = self.dbg.CreateTarget(exe, arch, None, False, error)
self.assertSuccess(error)
platform2 = target2.GetPlatform()
self.assertEqual(platform2.GetName(), expected_platform)
self.assertTrue(
platform2.GetWorkingDirectory().endswith("bar"),
platform2.GetWorkingDirectory(),
)
def test_SetDestroyCallback(self):
destroy_dbg_id = None
def foo(dbg_id):
nonlocal destroy_dbg_id
destroy_dbg_id = dbg_id
self.dbg.SetDestroyCallback(foo)
original_dbg_id = self.dbg.GetID()
self.dbg.Destroy(self.dbg)
self.assertEqual(destroy_dbg_id, original_dbg_id)
def test_AddDestroyCallback(self):
original_dbg_id = self.dbg.GetID()
called = []
def foo(dbg_id):
nonlocal called
called += [('foo', dbg_id)]
def bar(dbg_id):
nonlocal called
called += [('bar', dbg_id)]
token_foo = self.dbg.AddDestroyCallback(foo)
token_bar = self.dbg.AddDestroyCallback(bar)
self.dbg.Destroy(self.dbg)
self.assertEqual(called, [
('foo', original_dbg_id),
('bar', original_dbg_id),
])
def test_RemoveDestroyCallback(self):
original_dbg_id = self.dbg.GetID()
called = []
def foo(dbg_id):
nonlocal called
called += [('foo', dbg_id)]
def bar(dbg_id):
nonlocal called
called += [('bar', dbg_id)]
token_foo = self.dbg.AddDestroyCallback(foo)
token_bar = self.dbg.AddDestroyCallback(bar)
ret = self.dbg.RemoveDestroyCallback(token_foo)
self.dbg.Destroy(self.dbg)
self.assertTrue(ret)
self.assertEqual(called, [('bar', original_dbg_id)])
def test_RemoveDestroyCallback_invalid_token(self):
original_dbg_id = self.dbg.GetID()
magic_token_that_should_not_exist = 32413
called = []
def foo(dbg_id):
nonlocal called
called += [('foo', dbg_id)]
token_foo = self.dbg.AddDestroyCallback(foo)
ret = self.dbg.RemoveDestroyCallback(magic_token_that_should_not_exist)
self.dbg.Destroy(self.dbg)
self.assertFalse(ret)
self.assertEqual(called, [('foo', original_dbg_id)])
def test_HandleDestroyCallback(self):
"""
Validates:
1. AddDestroyCallback and RemoveDestroyCallback work during debugger destroy.
2. HandleDestroyCallback invokes all callbacks in FIFO order.
"""
original_dbg_id = self.dbg.GetID()
events = []
bar_token = None
def foo(dbg_id):
nonlocal events
events.append(('foo called', dbg_id))
def bar(dbg_id):
nonlocal events
events.append(('bar called', dbg_id))
def add_foo(dbg_id):
nonlocal events
events.append(('add_foo called', dbg_id))
events.append(('foo token', self.dbg.AddDestroyCallback(foo)))
def remove_bar(dbg_id):
nonlocal events
events.append(('remove_bar called', dbg_id))
events.append(('remove bar ret', self.dbg.RemoveDestroyCallback(bar_token)))
events.append(('add_foo token', self.dbg.AddDestroyCallback(add_foo)))
bar_token = self.dbg.AddDestroyCallback(bar)
events.append(('bar token', bar_token))
events.append(('remove_bar token', self.dbg.AddDestroyCallback(remove_bar)))
self.dbg.Destroy(self.dbg)
self.assertEqual(events, [
('add_foo token', 0),
('bar token', 1),
('remove_bar token', 2),
('add_foo called', original_dbg_id),
('foo token', 3),
('bar called', original_dbg_id),
('remove_bar called', original_dbg_id),
('remove bar ret', False),
('foo called', original_dbg_id),
])