187 lines · python
1import os2import shutil3import tempfile4 5import lldb6from lldbsuite.test.decorators import *7import lldbsuite.test.lldbutil as lldbutil8from lldbsuite.test.lldbtest import *9 10 11"""12Test support for the DebugInfoD network symbol acquisition protocol.13This one is for simple / no split-dwarf scenarios.14 15For no-split-dwarf scenarios, there are 2 variations:161 - A stripped binary with it's corresponding unstripped binary:172 - A stripped binary with a corresponding --only-keep-debug symbols file18"""19 20 21class DebugInfodTests(TestBase):22 # No need to try every flavor of debug inf.23 NO_DEBUG_INFO_TESTCASE = True24 25 @skipUnlessPlatform(["linux", "freebsd"])26 def test_normal_no_symbols(self):27 """28 Validate behavior with no symbols or symbol locator.29 ('baseline negative' behavior)30 """31 test_root = self.config_test(["a.out"])32 self.try_breakpoint(False)33 34 @skipUnlessPlatform(["linux", "freebsd"])35 def test_normal_default(self):36 """37 Validate behavior with symbols, but no symbol locator.38 ('baseline positive' behavior)39 """40 test_root = self.config_test(["a.out", "a.out.debug"])41 self.try_breakpoint(True)42 43 @skipIfCurlSupportMissing44 @skipUnlessPlatform(["linux", "freebsd"])45 def test_debuginfod_symbols(self):46 """47 Test behavior with the full binary available from Debuginfod as48 'debuginfo' from the plug-in.49 """50 test_root = self.config_test(["a.out"], "a.out.unstripped")51 self.try_breakpoint(True)52 53 @skipIfCurlSupportMissing54 @skipUnlessPlatform(["linux", "freebsd"])55 def test_debuginfod_executable(self):56 """57 Test behavior with the full binary available from Debuginfod as58 'executable' from the plug-in.59 """60 test_root = self.config_test(["a.out"], None, "a.out.unstripped")61 self.try_breakpoint(True)62 63 @skipIfCurlSupportMissing64 @skipUnlessPlatform(["linux", "freebsd"])65 def test_debuginfod_okd_symbols(self):66 """67 Test behavior with the 'only-keep-debug' symbols available from Debuginfod.68 """69 test_root = self.config_test(["a.out"], "a.out.debug")70 self.try_breakpoint(True)71 72 def try_breakpoint(self, should_have_loc):73 """74 This function creates a target from self.aout, sets a function-name75 breakpoint, and checks to see if we have a file/line location,76 as a way to validate that the symbols have been loaded.77 should_have_loc specifies if we're testing that symbols have or78 haven't been loaded.79 """80 target = self.dbg.CreateTarget(self.aout)81 self.assertTrue(target and target.IsValid(), "Target is valid")82 83 bp = target.BreakpointCreateByName("func")84 self.assertTrue(bp and bp.IsValid(), "Breakpoint is valid")85 self.assertEqual(bp.GetNumLocations(), 1)86 87 loc = bp.GetLocationAtIndex(0)88 self.assertTrue(loc and loc.IsValid(), "Location is valid")89 addr = loc.GetAddress()90 self.assertTrue(addr and addr.IsValid(), "Loc address is valid")91 line_entry = addr.GetLineEntry()92 self.assertEqual(93 should_have_loc,94 line_entry != None and line_entry.IsValid(),95 "Loc line entry is valid",96 )97 if should_have_loc:98 self.assertEqual(line_entry.GetLine(), 4)99 self.assertEqual(100 line_entry.GetFileSpec().GetFilename(),101 self.main_source_file.GetFilename(),102 )103 self.dbg.DeleteTarget(target)104 shutil.rmtree(self.tmp_dir)105 106 def config_test(self, local_files, debuginfo=None, executable=None):107 """108 Set up a test with local_files[] copied to a different location109 so that we control which files are, or are not, found in the file system.110 Also, create a stand-alone file-system 'hosted' debuginfod server with the111 provided debuginfo and executable files (if they exist)112 113 Make the filesystem look like:114 115 /tmp/<tmpdir>/test/[local_files]116 117 /tmp/<tmpdir>/cache (for lldb to use as a temp cache)118 119 /tmp/<tmpdir>/buildid/<uuid>/executable -> <executable>120 /tmp/<tmpdir>/buildid/<uuid>/debuginfo -> <debuginfo>121 Returns the /tmp/<tmpdir> path122 """123 124 self.build()125 126 uuid = self.getUUID("a.out")127 if not uuid:128 self.fail("Could not get UUID for a.out")129 return130 self.main_source_file = lldb.SBFileSpec("main.c")131 self.tmp_dir = tempfile.mkdtemp()132 test_dir = os.path.join(self.tmp_dir, "test")133 os.makedirs(test_dir)134 135 self.aout = ""136 # Copy the files used by the test:137 for f in local_files:138 shutil.copy(self.getBuildArtifact(f), test_dir)139 # The first item is the binary to be used for the test140 if self.aout == "":141 self.aout = os.path.join(test_dir, f)142 143 use_debuginfod = debuginfo != None or executable != None144 145 # Populated the 'file://... mocked' Debuginfod server:146 if use_debuginfod:147 os.makedirs(os.path.join(self.tmp_dir, "cache"))148 uuid_dir = os.path.join(self.tmp_dir, "buildid", uuid)149 os.makedirs(uuid_dir)150 if debuginfo:151 shutil.copy(152 self.getBuildArtifact(debuginfo),153 os.path.join(uuid_dir, "debuginfo"),154 )155 if executable:156 shutil.copy(157 self.getBuildArtifact(executable),158 os.path.join(uuid_dir, "executable"),159 )160 161 # Configure LLDB for the test:162 self.runCmd(163 "settings set symbols.enable-external-lookup %s"164 % str(use_debuginfod).lower()165 )166 self.runCmd("settings clear plugin.symbol-locator.debuginfod.server-urls")167 if use_debuginfod:168 self.runCmd(169 "settings set plugin.symbol-locator.debuginfod.cache-path %s/cache"170 % self.tmp_dir171 )172 self.runCmd(173 "settings insert-before plugin.symbol-locator.debuginfod.server-urls 0 file://%s"174 % self.tmp_dir175 )176 177 def getUUID(self, filename):178 try:179 spec = lldb.SBModuleSpec()180 spec.SetFileSpec(lldb.SBFileSpec(self.getBuildArtifact(filename)))181 module = lldb.SBModule(spec)182 uuid = module.GetUUIDString().replace("-", "").lower()183 # Don't want lldb's fake 32 bit CRC's for this one184 return uuid if len(uuid) > 8 else None185 except:186 return None187