Files
clang-p2996/lldb/test/API/debuginfod/Normal/TestDebuginfod.py
Kevin Frei b9496a74eb [lldb] DebugInfoD tests & fixes (but with dwp testing disabled) (#98344)
This is all the tests and fixes I've had percolating since my first
attempt at this in January. After 6 months of trying, I've given up on
adding the ability to test DWP files in LLDB API tests. I've left both
the tests (disabled) and the changes to Makefile.rules in place, in the
hopes that someone who can configure the build bots will be able to
enable the tests once a non-borked dwp tool is widely available.

Other than disabling the DWP tests, this continues to be the same diff
that I've tried to land and
[not](https://github.com/llvm/llvm-project/pull/90622)
[revert](https://github.com/llvm/llvm-project/pull/87676)
[five](https://github.com/llvm/llvm-project/pull/86812)
[times](https://github.com/llvm/llvm-project/pull/85693)
[before](https://github.com/llvm/llvm-project/pull/96802). There are a
couple of fixes that the testing exposed, and I've abandoned the DWP
tests because I want to get those fixes finally upstreamed, as without
them DebugInfoD is less useful.
2024-07-10 09:28:22 -07:00

187 lines
6.6 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
"""
class DebugInfodTests(TestBase):
# No need to try every flavor of debug inf.
NO_DEBUG_INFO_TESTCASE = True
@skipUnlessPlatform(["linux", "freebsd"])
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)
@skipUnlessPlatform(["linux", "freebsd"])
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)
@skipIfCurlSupportMissing
@skipUnlessPlatform(["linux", "freebsd"])
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)
@skipIfCurlSupportMissing
@skipUnlessPlatform(["linux", "freebsd"])
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)
@skipIfCurlSupportMissing
@skipUnlessPlatform(["linux", "freebsd"])
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:
spec = lldb.SBModuleSpec()
spec.SetFileSpec(lldb.SBFileSpec(self.getBuildArtifact(filename)))
module = lldb.SBModule(spec)
uuid = module.GetUUIDString().replace("-", "").lower()
# Don't want lldb's fake 32 bit CRC's for this one
return uuid if len(uuid) > 8 else None
except:
return None