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