diff options
| author | Kevin Frei <kevinfrei@users.noreply.github.com> | 2024-04-04 11:43:55 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-04-04 11:43:55 -0700 |
| commit | d6713ad80d6907210c629f22babaf12177fa329c (patch) | |
| tree | 3cff209208b638b7611e23e6e3f8a233d055bbdb /lldb/test/API/debuginfod/Normal | |
| parent | 8004ce236795d48063c636d1ce4818ebcb526b21 (diff) | |
Debuginfod Testing & fixes: 3rd times the charm? (#87676)
I believe I've got the tests properly configured to only run on Linux
x86(_64), as I don't have a Linux AArch64/Arm device to diagnose what's
going wrong with the tests (I suspect there's some issue with generating
`.note.gnu.build-id` sections...)
The actual code fixes have now been reviewed 3 times:
https://github.com/llvm/llvm-project/pull/79181 (moved shell tests to
API tests), https://github.com/llvm/llvm-project/pull/85693 (Changed
some of the testing infra), and
https://github.com/llvm/llvm-project/pull/86812 (didn't get the tests
configured quite right). The Debuginfod integration for symbol
acquisition in LLDB now works with the `executable` and `debuginfo`
Debuginfod network requests working properly for normal, `objcopy
--only-keep-debug` stripped, split-dwarf, and `objcopy
--only-keep-debug` stripped *plus* split-dwarf symbols/binaries.
The reasons for the multiple attempts have been tests on platforms I
don't have access to (Linux AArch64/Arm + MacOS x86_64). I believe I've
got the tests properly disabled for everything except for Linux x86(_64)
now. I've built & tested on MacOS AArch64 and Linux x86_64.
---------
Co-authored-by: Kevin Frei <freik@meta.com>
Diffstat (limited to 'lldb/test/API/debuginfod/Normal')
| -rw-r--r-- | lldb/test/API/debuginfod/Normal/Makefile | 19 | ||||
| -rw-r--r-- | lldb/test/API/debuginfod/Normal/TestDebuginfod.py | 183 | ||||
| -rw-r--r-- | lldb/test/API/debuginfod/Normal/main.c | 7 |
3 files changed, 209 insertions, 0 deletions
diff --git a/lldb/test/API/debuginfod/Normal/Makefile b/lldb/test/API/debuginfod/Normal/Makefile new file mode 100644 index 000000000000..54bd7adae241 --- /dev/null +++ b/lldb/test/API/debuginfod/Normal/Makefile @@ -0,0 +1,19 @@ +C_SOURCES := main.c + +# For normal (non DWP) Debuginfod tests, we need: + +# * The full binary: a.out.unstripped +# Produced by Makefile.rules with SAVE_FULL_DEBUG_BINARY set to YES and +# SPLIT_DEBUG_SYMBOLS set to YES + +# * The stripped binary (a.out) +# Produced by Makefile.rules with SPLIT_DEBUG_SYMBOLS set to YES + +# * The 'only-keep-debug' binary (a.out.debug) +# Produced below + +SPLIT_DEBUG_SYMBOLS := YES +SAVE_FULL_DEBUG_BINARY := YES +GEN_GNU_BUILD_ID := YES + +include Makefile.rules diff --git a/lldb/test/API/debuginfod/Normal/TestDebuginfod.py b/lldb/test/API/debuginfod/Normal/TestDebuginfod.py new file mode 100644 index 000000000000..f1be1e705ee0 --- /dev/null +++ b/lldb/test/API/debuginfod/Normal/TestDebuginfod.py @@ -0,0 +1,183 @@ +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 +class DebugInfodTests(TestBase): + # No need to try every flavor of debug inf. + NO_DEBUG_INFO_TESTCASE = True + + @skipIf(oslist=no_match(["linux"]), archs=no_match(["i386", "x86_64"])) + 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) + + @skipIf(oslist=no_match(["linux"]), archs=no_match(["i386", "x86_64"])) + 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) + + @skipIf(oslist=no_match(["linux"]), archs=no_match(["i386", "x86_64"])) + 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) + + @skipIf(oslist=no_match(["linux"]), archs=no_match(["i386", "x86_64"])) + 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) + + @skipIf(oslist=no_match(["linux"]), archs=no_match(["i386", "x86_64"])) + 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 diff --git a/lldb/test/API/debuginfod/Normal/main.c b/lldb/test/API/debuginfod/Normal/main.c new file mode 100644 index 000000000000..4c7184609b45 --- /dev/null +++ b/lldb/test/API/debuginfod/Normal/main.c @@ -0,0 +1,7 @@ +// This is a dump little pair of test files + +int func(int argc, const char *argv[]) { + return (argc + 1) * (argv[argc][0] + 2); +} + +int main(int argc, const char *argv[]) { return func(0, argv); } |
