The previous diff (and it's subsequent fix) were reverted as the tests didn't work properly on the AArch64 & ARM LLDB buildbots. I made a couple more minor changes to tests (from @clayborg's feedback) and disabled them for non Linux-x86(_64) builds, as I don't have the ability do anything about an ARM64 Linux failure. If I had to guess, I'd say the toolchain on the buildbots isn't respecting the `-Wl,--build-id` flag. Maybe, one day, when I have a Linux AArch64 system I'll dig in to it. From the reverted PR: I've migrated the tests in my https://github.com/llvm/llvm-project/pull/79181 from shell to API (at @JDevlieghere's suggestion) and addressed a couple issues that were exposed during testing. The tests first test the "normal" situation (no DebugInfoD involvement, just normal debug files sitting around), then the "no debug info" situation (to make sure the test is seeing failure properly), then it tests to validate that when DebugInfoD returns the symbols, things work properly. This is duplicated for DWP/split-dwarf scenarios. --------- Co-authored-by: Kevin Frei <freik@meta.com>
180 lines
6.4 KiB
Python
180 lines
6.4 KiB
Python
import os
|
|
import shutil
|
|
import tempfile
|
|
|
|
import lldb
|
|
from lldbsuite.test.decorators import *
|
|
import lldbsuite.test.lldbutil as lldbutil
|
|
from lldbsuite.test.lldbtest import *
|
|
|
|
|
|
"""
|
|
Test support for the DebugInfoD network symbol acquisition protocol.
|
|
This one is for simple / no split-dwarf scenarios.
|
|
|
|
For no-split-dwarf scenarios, there are 2 variations:
|
|
1 - A stripped binary with it's corresponding unstripped binary:
|
|
2 - A stripped binary with a corresponding --only-keep-debug symbols file
|
|
"""
|
|
|
|
|
|
# It looks like Linux-AArch64 doesn't support build-id's on the LLDB builtbots
|
|
@skipIf(oslist=no_match(["linux"]), archs=no_match(["i386", "x86_64"]))
|
|
class DebugInfodTests(TestBase):
|
|
# No need to try every flavor of debug inf.
|
|
NO_DEBUG_INFO_TESTCASE = True
|
|
|
|
def test_normal_no_symbols(self):
|
|
"""
|
|
Validate behavior with no symbols or symbol locator.
|
|
('baseline negative' behavior)
|
|
"""
|
|
test_root = self.config_test(["a.out"])
|
|
self.try_breakpoint(False)
|
|
|
|
def test_normal_default(self):
|
|
"""
|
|
Validate behavior with symbols, but no symbol locator.
|
|
('baseline positive' behavior)
|
|
"""
|
|
test_root = self.config_test(["a.out", "a.out.debug"])
|
|
self.try_breakpoint(True)
|
|
|
|
def test_debuginfod_symbols(self):
|
|
"""
|
|
Test behavior with the full binary available from Debuginfod as
|
|
'debuginfo' from the plug-in.
|
|
"""
|
|
test_root = self.config_test(["a.out"], "a.out.unstripped")
|
|
self.try_breakpoint(True)
|
|
|
|
def test_debuginfod_executable(self):
|
|
"""
|
|
Test behavior with the full binary available from Debuginfod as
|
|
'executable' from the plug-in.
|
|
"""
|
|
test_root = self.config_test(["a.out"], None, "a.out.unstripped")
|
|
self.try_breakpoint(True)
|
|
|
|
def test_debuginfod_okd_symbols(self):
|
|
"""
|
|
Test behavior with the 'only-keep-debug' symbols available from Debuginfod.
|
|
"""
|
|
test_root = self.config_test(["a.out"], "a.out.debug")
|
|
self.try_breakpoint(True)
|
|
|
|
def try_breakpoint(self, should_have_loc):
|
|
"""
|
|
This function creates a target from self.aout, sets a function-name
|
|
breakpoint, and checks to see if we have a file/line location,
|
|
as a way to validate that the symbols have been loaded.
|
|
should_have_loc specifies if we're testing that symbols have or
|
|
haven't been loaded.
|
|
"""
|
|
target = self.dbg.CreateTarget(self.aout)
|
|
self.assertTrue(target and target.IsValid(), "Target is valid")
|
|
|
|
bp = target.BreakpointCreateByName("func")
|
|
self.assertTrue(bp and bp.IsValid(), "Breakpoint is valid")
|
|
self.assertEqual(bp.GetNumLocations(), 1)
|
|
|
|
loc = bp.GetLocationAtIndex(0)
|
|
self.assertTrue(loc and loc.IsValid(), "Location is valid")
|
|
addr = loc.GetAddress()
|
|
self.assertTrue(addr and addr.IsValid(), "Loc address is valid")
|
|
line_entry = addr.GetLineEntry()
|
|
self.assertEqual(
|
|
should_have_loc,
|
|
line_entry != None and line_entry.IsValid(),
|
|
"Loc line entry is valid",
|
|
)
|
|
if should_have_loc:
|
|
self.assertEqual(line_entry.GetLine(), 4)
|
|
self.assertEqual(
|
|
line_entry.GetFileSpec().GetFilename(),
|
|
self.main_source_file.GetFilename(),
|
|
)
|
|
self.dbg.DeleteTarget(target)
|
|
shutil.rmtree(self.tmp_dir)
|
|
|
|
def config_test(self, local_files, debuginfo=None, executable=None):
|
|
"""
|
|
Set up a test with local_files[] copied to a different location
|
|
so that we control which files are, or are not, found in the file system.
|
|
Also, create a stand-alone file-system 'hosted' debuginfod server with the
|
|
provided debuginfo and executable files (if they exist)
|
|
|
|
Make the filesystem look like:
|
|
|
|
/tmp/<tmpdir>/test/[local_files]
|
|
|
|
/tmp/<tmpdir>/cache (for lldb to use as a temp cache)
|
|
|
|
/tmp/<tmpdir>/buildid/<uuid>/executable -> <executable>
|
|
/tmp/<tmpdir>/buildid/<uuid>/debuginfo -> <debuginfo>
|
|
Returns the /tmp/<tmpdir> path
|
|
"""
|
|
|
|
self.build()
|
|
|
|
uuid = self.getUUID("a.out")
|
|
if not uuid:
|
|
self.fail("Could not get UUID for a.out")
|
|
return
|
|
self.main_source_file = lldb.SBFileSpec("main.c")
|
|
self.tmp_dir = tempfile.mkdtemp()
|
|
test_dir = os.path.join(self.tmp_dir, "test")
|
|
os.makedirs(test_dir)
|
|
|
|
self.aout = ""
|
|
# Copy the files used by the test:
|
|
for f in local_files:
|
|
shutil.copy(self.getBuildArtifact(f), test_dir)
|
|
# The first item is the binary to be used for the test
|
|
if self.aout == "":
|
|
self.aout = os.path.join(test_dir, f)
|
|
|
|
use_debuginfod = debuginfo != None or executable != None
|
|
|
|
# Populated the 'file://... mocked' Debuginfod server:
|
|
if use_debuginfod:
|
|
os.makedirs(os.path.join(self.tmp_dir, "cache"))
|
|
uuid_dir = os.path.join(self.tmp_dir, "buildid", uuid)
|
|
os.makedirs(uuid_dir)
|
|
if debuginfo:
|
|
shutil.copy(
|
|
self.getBuildArtifact(debuginfo),
|
|
os.path.join(uuid_dir, "debuginfo"),
|
|
)
|
|
if executable:
|
|
shutil.copy(
|
|
self.getBuildArtifact(executable),
|
|
os.path.join(uuid_dir, "executable"),
|
|
)
|
|
|
|
# Configure LLDB for the test:
|
|
self.runCmd(
|
|
"settings set symbols.enable-external-lookup %s"
|
|
% str(use_debuginfod).lower()
|
|
)
|
|
self.runCmd("settings clear plugin.symbol-locator.debuginfod.server-urls")
|
|
if use_debuginfod:
|
|
self.runCmd(
|
|
"settings set plugin.symbol-locator.debuginfod.cache-path %s/cache"
|
|
% self.tmp_dir
|
|
)
|
|
self.runCmd(
|
|
"settings insert-before plugin.symbol-locator.debuginfod.server-urls 0 file://%s"
|
|
% self.tmp_dir
|
|
)
|
|
|
|
def getUUID(self, filename):
|
|
try:
|
|
target = self.dbg.CreateTarget(self.getBuildArtifact(filename))
|
|
module = target.GetModuleAtIndex(0)
|
|
uuid = module.GetUUIDString().replace("-", "").lower()
|
|
self.dbg.DeleteTarget(target)
|
|
return uuid if len(uuid) == 40 else None
|
|
except:
|
|
return None
|