xref: /llvm-project/lldb/test/API/debuginfod/Normal/TestDebuginfod.py (revision e77ac42bccb8c26bbf4b74d8e92eb09e7fa1b218)
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