Building libfoo.a twice (quickly) confuses the cache in ObjectContainerBSDArchive (which works only with second granularity), and causes the second test to fail due to accessing wrong parts of the file. I'm also making this a NO_DEBUG_INFO_TESTCASE as the debug info distinction is not particularly relevant for this test. Technically, this would be enough as the collision is between two debug info variants of the same test case, but SHARED_BUILD_TESTCASE=False seems like a more principled fix.
178 lines
6.5 KiB
Python
178 lines
6.5 KiB
Python
"""Test the SBDModule APIs."""
|
|
|
|
import lldb
|
|
from lldbsuite.test.decorators import *
|
|
from lldbsuite.test.lldbtest import *
|
|
from lldbsuite.test import lldbutil
|
|
|
|
import os, signal, subprocess
|
|
|
|
|
|
class SBModuleAPICase(TestBase):
|
|
NO_DEBUG_INFO_TESTCASE = True
|
|
|
|
# Shared build causes collisions in the ObjectArchive file cache
|
|
SHARED_BUILD_TESTCASE = False
|
|
|
|
def setUp(self):
|
|
TestBase.setUp(self)
|
|
self.background_pid = None
|
|
|
|
def tearDown(self):
|
|
TestBase.tearDown(self)
|
|
if self.background_pid:
|
|
os.kill(self.background_pid, signal.SIGKILL)
|
|
|
|
@skipIfRemote
|
|
def test_GetObjectName(self):
|
|
"""Test the SBModule::GetObjectName() method"""
|
|
self.build()
|
|
exe = self.getBuildArtifact("a.out")
|
|
libfoo_path = self.getBuildArtifact("libfoo.a")
|
|
target_exe = self.dbg.CreateTarget(exe)
|
|
self.assertTrue(target_exe.IsValid(), "Target for a.out is valid")
|
|
|
|
# Test that the executable module has no object name (usually the first module in the target)
|
|
exe_module = target_exe.GetModuleAtIndex(0)
|
|
self.assertTrue(exe_module.IsValid(), "Executable module is valid")
|
|
self.assertIsNone(
|
|
exe_module.GetObjectName(), "a.out should have no object name"
|
|
)
|
|
|
|
# check archive member names
|
|
module_specs = lldb.SBModuleSpecList.GetModuleSpecifications(libfoo_path)
|
|
self.assertGreater(
|
|
module_specs.GetSize(), 0, "Archive should have at least one module spec"
|
|
)
|
|
self.assertEqual(
|
|
module_specs[0].GetObjectName(),
|
|
module_specs.GetSpecAtIndex(0).GetObjectName(),
|
|
"subscript [0] matches GetSpecAtIndex(0)",
|
|
)
|
|
self.assertEqual(
|
|
module_specs[-1].GetObjectName(),
|
|
module_specs.GetSpecAtIndex(module_specs.GetSize() - 1).GetObjectName(),
|
|
"subscript [-1] matches last item",
|
|
)
|
|
found = set()
|
|
expected = {"a.o", "b.o"}
|
|
for i in range(module_specs.GetSize()):
|
|
spec = module_specs.GetSpecAtIndex(i)
|
|
obj_name = spec.GetObjectName()
|
|
self.assertIsInstance(obj_name, str)
|
|
self.assertIn(obj_name, expected, f"Unexpected object name: {obj_name}")
|
|
# create a module from the arhive using the sepc
|
|
module = lldb.SBModule(spec)
|
|
self.assertTrue(module.IsValid(), "Module is valid")
|
|
self.assertTrue(module.IsValid(), f"Module for {obj_name} is valid")
|
|
self.assertEqual(
|
|
module.GetObjectName(), obj_name, f"Object name for {obj_name} matches"
|
|
)
|
|
found.add(obj_name)
|
|
|
|
self.assertEqual(found, expected, "Did not find all expected archive members")
|
|
|
|
@skipUnlessDarwin
|
|
@skipIfRemote
|
|
def test_module_is_file_backed(self):
|
|
"""Test the SBModule::IsFileBacked() method"""
|
|
self.build()
|
|
target, _, _, _ = lldbutil.run_to_source_breakpoint(
|
|
self, "// break here", lldb.SBFileSpec("main.c")
|
|
)
|
|
|
|
self.assertGreater(target.GetNumModules(), 0)
|
|
main_module = target.GetModuleAtIndex(0)
|
|
self.assertEqual(main_module.GetFileSpec().GetFilename(), "a.out")
|
|
self.assertTrue(
|
|
main_module.IsFileBacked(), "The module should be backed by a file on disk"
|
|
)
|
|
|
|
self.dbg.DeleteTarget(target)
|
|
self.assertEqual(self.dbg.GetNumTargets(), 0)
|
|
|
|
exe = self.getBuildArtifact("a.out")
|
|
background_process = subprocess.Popen([exe])
|
|
self.assertTrue(background_process, "process is not valid")
|
|
self.background_pid = background_process.pid
|
|
os.unlink(exe)
|
|
|
|
target = self.dbg.CreateTarget("")
|
|
self.assertEqual(self.dbg.GetNumTargets(), 1)
|
|
error = lldb.SBError()
|
|
process = target.AttachToProcessWithID(
|
|
self.dbg.GetListener(), self.background_pid, error
|
|
)
|
|
self.assertTrue(error.Success() and process, PROCESS_IS_VALID)
|
|
main_module = target.FindModule(lldb.SBFileSpec("a.out"))
|
|
self.assertIsNotNone(main_module)
|
|
self.assertFalse(
|
|
main_module.IsFileBacked(),
|
|
"The module should not be backed by a file on disk.",
|
|
)
|
|
|
|
error = process.Destroy()
|
|
self.assertSuccess(
|
|
error, "couldn't destroy process %s" % background_process.pid
|
|
)
|
|
|
|
@skipIfRemote
|
|
def test_module_spec_list_indexing(self):
|
|
"""Test that SBModuleSpecList supports Pythonic indexing."""
|
|
self.build()
|
|
libfoo_path = self.getBuildArtifact("libfoo.a")
|
|
specs = lldb.SBModuleSpecList.GetModuleSpecifications(libfoo_path)
|
|
count = specs.GetSize()
|
|
self.assertGreater(count, 0, "Archive should have at least one module spec")
|
|
|
|
# Integer indexing: positive indices
|
|
for i in range(count):
|
|
self.assertEqual(
|
|
str(specs[i]),
|
|
str(specs.GetSpecAtIndex(i)),
|
|
"specs[%d] should match GetSpecAtIndex(%d)" % (i, i),
|
|
)
|
|
|
|
# Integer indexing: negative indices
|
|
self.assertEqual(
|
|
str(specs[-1]),
|
|
str(specs.GetSpecAtIndex(count - 1)),
|
|
"specs[-1] should match last element",
|
|
)
|
|
self.assertEqual(
|
|
str(specs[-count]),
|
|
str(specs.GetSpecAtIndex(0)),
|
|
"specs[-count] should match first element",
|
|
)
|
|
|
|
# Integer indexing: out of bounds raises IndexError
|
|
self.assertRaises(IndexError, lambda: specs[count])
|
|
self.assertRaises(IndexError, lambda: specs[-count - 1])
|
|
|
|
# Unsupported key type raises TypeError
|
|
self.assertRaises(TypeError, lambda: specs[1.5])
|
|
|
|
# String indexing: lookup by file basename
|
|
spec0 = specs.GetSpecAtIndex(0)
|
|
basename = spec0.GetFileSpec().GetFilename()
|
|
if basename:
|
|
found = specs[basename]
|
|
self.assertIsNotNone(found, "Should find spec by basename '%s'" % basename)
|
|
self.assertEqual(
|
|
found.GetFileSpec().GetFilename(),
|
|
basename,
|
|
"Found spec basename should match",
|
|
)
|
|
|
|
# String indexing: lookup by partial path (endswith matching)
|
|
fullpath = str(spec0.GetFileSpec())
|
|
if fullpath:
|
|
found = specs[fullpath]
|
|
self.assertIsNotNone(found, "Should find spec by full path '%s'" % fullpath)
|
|
|
|
# String indexing: missing basename returns None
|
|
self.assertIsNone(
|
|
specs["nonexistent_file.xyz"],
|
|
"Lookup of nonexistent basename should return None",
|
|
)
|