mirror of
https://github.com/llvm/llvm-project.git
synced 2025-05-03 22:36:06 +00:00

Recently we have disabled this test for Windows host and Linux target. Now we faced the same issue #92419 in case of Linux x86_64 host and Linux Aarch64 target.
289 lines
11 KiB
Python
289 lines
11 KiB
Python
"""
|
|
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)
|
|
# FIXME (filcab): We must first allow for the swig bindings to know if
|
|
# a Python callback is set. (Check python-typemaps.swig)
|
|
# self.dbg.SetLoggingCallback(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")
|
|
|
|
# Create a target by the debugger.
|
|
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)
|
|
|
|
# Get global property value while there are no processes.
|
|
global_cache_line_size = get_cache_line_size()
|
|
|
|
# Run a process via SB interface. CommandInterpreter's execution context
|
|
# remains empty.
|
|
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)
|
|
|
|
# This should change the value of a process's local property.
|
|
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")
|
|
|
|
# Check that it was set actually.
|
|
self.assertEqual(get_cache_line_size(), new_cache_line_size)
|
|
|
|
# Run any command to initialize CommandInterpreter's execution context.
|
|
self.runCmd("target list")
|
|
|
|
# Test the local property again, is it set to new_cache_line_size?
|
|
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")
|
|
|
|
# Reuse a platform if it matches the currently selected one...
|
|
target2 = self.dbg.CreateTarget(exe, None, "remote-linux", False, error)
|
|
self.assertSuccess(error)
|
|
platform2 = target2.GetPlatform()
|
|
self.assertTrue(
|
|
platform2.GetWorkingDirectory().endswith("bar"),
|
|
platform2.GetWorkingDirectory(),
|
|
)
|
|
|
|
# ... but create a new one if it doesn't.
|
|
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")
|
|
|
|
# Reuse a platform even if it is not currently selected.
|
|
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):
|
|
# Need nonlocal to modify closure variable.
|
|
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):
|
|
# Need nonlocal to modify closure variable.
|
|
nonlocal called
|
|
called += [('foo', dbg_id)]
|
|
|
|
def bar(dbg_id):
|
|
# Need nonlocal to modify closure variable.
|
|
nonlocal called
|
|
called += [('bar', dbg_id)]
|
|
|
|
token_foo = self.dbg.AddDestroyCallback(foo)
|
|
token_bar = self.dbg.AddDestroyCallback(bar)
|
|
self.dbg.Destroy(self.dbg)
|
|
|
|
# Should call both `foo()` and `bar()`.
|
|
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):
|
|
# Need nonlocal to modify closure variable.
|
|
nonlocal called
|
|
called += [('foo', dbg_id)]
|
|
|
|
def bar(dbg_id):
|
|
# Need nonlocal to modify closure variable.
|
|
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)
|
|
|
|
# `Remove` should be successful
|
|
self.assertTrue(ret)
|
|
# Should only call `bar()`
|
|
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):
|
|
# Need nonlocal to modify closure variable.
|
|
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)
|
|
|
|
# `Remove` should be unsuccessful
|
|
self.assertFalse(ret)
|
|
# Should call `foo()`
|
|
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):
|
|
# Need nonlocal to modify closure variable.
|
|
nonlocal events
|
|
events.append(('foo called', dbg_id))
|
|
|
|
def bar(dbg_id):
|
|
# Need nonlocal to modify closure variable.
|
|
nonlocal events
|
|
events.append(('bar called', dbg_id))
|
|
|
|
def add_foo(dbg_id):
|
|
# Need nonlocal to modify closure variable.
|
|
nonlocal events
|
|
events.append(('add_foo called', dbg_id))
|
|
events.append(('foo token', self.dbg.AddDestroyCallback(foo)))
|
|
|
|
def remove_bar(dbg_id):
|
|
# Need nonlocal to modify closure variable.
|
|
nonlocal events
|
|
events.append(('remove_bar called', dbg_id))
|
|
events.append(('remove bar ret', self.dbg.RemoveDestroyCallback(bar_token)))
|
|
|
|
# Setup
|
|
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)))
|
|
# Destroy
|
|
self.dbg.Destroy(self.dbg)
|
|
|
|
self.assertEqual(events, [
|
|
# Setup
|
|
('add_foo token', 0), # add_foo should be added
|
|
('bar token', 1), # bar should be added
|
|
('remove_bar token', 2), # remove_bar should be added
|
|
# Destroy
|
|
('add_foo called', original_dbg_id), # add_foo should be called
|
|
('foo token', 3), # foo should be added
|
|
('bar called', original_dbg_id), # bar should be called
|
|
('remove_bar called', original_dbg_id), # remove_bar should be called
|
|
('remove bar ret', False), # remove_bar should fail, because it's already invoked and removed
|
|
('foo called', original_dbg_id), # foo should be called
|
|
])
|