xref: /llvm-project/lldb/test/API/commands/target/dump-separate-debug-info/dwo/TestDumpDwo.py (revision 69a5869da4906f61caf59ff021559ca7d974c5f9)
1"""
2Test 'target modules dump separate-debug-info' for dwo files.
3"""
4
5import json
6import os
7
8from lldbsuite.test import lldbtest, lldbutil
9from lldbsuite.test.decorators import *
10from lldbsuite.test_event.build_exception import BuildError
11
12
13class TestDumpDWO(lldbtest.TestBase):
14    NO_DEBUG_INFO_TESTCASE = True
15
16    def get_dwos_from_json_output(self):
17        """Returns a dictionary of `symfile` -> {`dwo_name` -> dwo_info object}."""
18        result = {}
19        output = json.loads(self.res.GetOutput())
20        for symfile_entry in output:
21            dwo_dict = {}
22            for dwo_entry in symfile_entry["separate-debug-info-files"]:
23                dwo_dict[dwo_entry["dwo_name"]] = dwo_entry
24            result[symfile_entry["symfile"]] = dwo_dict
25        return result
26
27    def build_and_skip_if_error(self):
28        try:
29            self.build()
30        except BuildError as e:
31            self.skipTest(f"Skipping test due to build exception: {e}")
32
33    def test_dwos_loaded_json_output(self):
34        self.build_and_skip_if_error()
35        exe = self.getBuildArtifact("a.out")
36        main_dwo = self.getBuildArtifact("a.out-main.dwo")
37        foo_dwo = self.getBuildArtifact("a.out-foo.dwo")
38
39        # Make sure dwo files exist
40        self.assertTrue(os.path.exists(main_dwo), f'Make sure "{main_dwo}" file exists')
41        self.assertTrue(os.path.exists(foo_dwo), f'Make sure "{foo_dwo}" file exists')
42
43        target = self.dbg.CreateTarget(exe)
44        self.assertTrue(target, lldbtest.VALID_TARGET)
45
46        self.runCmd("target modules dump separate-debug-info --json")
47
48        # Check the output
49        output = self.get_dwos_from_json_output()
50        self.assertTrue(output[exe]["a.out-main.dwo"]["loaded"])
51        self.assertTrue(output[exe]["a.out-foo.dwo"]["loaded"])
52
53    def test_dwos_not_loaded_json_output(self):
54        self.build_and_skip_if_error()
55        exe = self.getBuildArtifact("a.out")
56        main_dwo = self.getBuildArtifact("a.out-main.dwo")
57        foo_dwo = self.getBuildArtifact("a.out-foo.dwo")
58
59        # REMOVE one of the dwo files
60        os.unlink(main_dwo)
61
62        target = self.dbg.CreateTarget(exe)
63        self.assertTrue(target, lldbtest.VALID_TARGET)
64
65        self.runCmd("target modules dump separate-debug-info --json")
66
67        # Check the output
68        output = self.get_dwos_from_json_output()
69        self.assertFalse(output[exe]["a.out-main.dwo"]["loaded"])
70        self.assertIn("error", output[exe]["a.out-main.dwo"])
71        self.assertTrue(output[exe]["a.out-foo.dwo"]["loaded"])
72        self.assertNotIn("error", output[exe]["a.out-foo.dwo"])
73
74        # Check with --errors-only
75        self.runCmd("target modules dump separate-debug-info --json --errors-only")
76        output = self.get_dwos_from_json_output()
77        self.assertFalse(output[exe]["a.out-main.dwo"]["loaded"])
78        self.assertIn("error", output[exe]["a.out-main.dwo"])
79        self.assertNotIn("a.out-foo.dwo", output[exe])
80
81    def test_dwos_loaded_table_output(self):
82        self.build_and_skip_if_error()
83        exe = self.getBuildArtifact("a.out")
84        main_dwo = self.getBuildArtifact("a.out-main.dwo")
85        foo_dwo = self.getBuildArtifact("a.out-foo.dwo")
86
87        # Make sure dwo files exist
88        self.assertTrue(os.path.exists(main_dwo), f'Make sure "{main_dwo}" file exists')
89        self.assertTrue(os.path.exists(foo_dwo), f'Make sure "{foo_dwo}" file exists')
90
91        target = self.dbg.CreateTarget(exe)
92        self.assertTrue(target, lldbtest.VALID_TARGET)
93
94        self.expect(
95            "target modules dump separate-debug-info",
96            patterns=[
97                "Symbol file: .*?a\.out",
98                'Type: "dwo"',
99                "Dwo ID\s+Err\s+Dwo Path",
100                "0x[a-zA-Z0-9]{16}\s+.*main\.dwo",
101                "0x[a-zA-Z0-9]{16}\s+.*foo\.dwo",
102            ],
103        )
104
105    def test_dwos_not_loaded_table_output(self):
106        self.build_and_skip_if_error()
107        exe = self.getBuildArtifact("a.out")
108        main_dwo = self.getBuildArtifact("a.out-main.dwo")
109        foo_dwo = self.getBuildArtifact("a.out-foo.dwo")
110
111        # REMOVE the dwo files
112        os.unlink(main_dwo)
113        os.unlink(foo_dwo)
114
115        target = self.dbg.CreateTarget(exe)
116        self.assertTrue(target, lldbtest.VALID_TARGET)
117
118        self.expect(
119            "target modules dump separate-debug-info",
120            patterns=[
121                "Symbol file: .*?a\.out",
122                'Type: "dwo"',
123                "Dwo ID\s+Err\s+Dwo Path",
124                "0x[a-zA-Z0-9]{16}\s+E\s+.*main\.dwo",
125                "0x[a-zA-Z0-9]{16}\s+E\s+.*foo\.dwo",
126            ],
127        )
128
129    def test_dwos_loaded_symbols_on_demand(self):
130        self.build_and_skip_if_error()
131        exe = self.getBuildArtifact("a.out")
132        main_dwo = self.getBuildArtifact("a.out-main.dwo")
133        foo_dwo = self.getBuildArtifact("a.out-foo.dwo")
134
135        # Make sure dwo files exist
136        self.assertTrue(os.path.exists(main_dwo), f'Make sure "{main_dwo}" file exists')
137        self.assertTrue(os.path.exists(foo_dwo), f'Make sure "{foo_dwo}" file exists')
138
139        # Load symbols on-demand
140        self.runCmd("settings set symbols.load-on-demand true")
141
142        target = self.dbg.CreateTarget(exe)
143        self.assertTrue(target, lldbtest.VALID_TARGET)
144
145        self.runCmd("target modules dump separate-debug-info --json")
146
147        # Check the output
148        output = self.get_dwos_from_json_output()
149        self.assertTrue(output[exe]["a.out-main.dwo"]["loaded"])
150        self.assertTrue(output[exe]["a.out-foo.dwo"]["loaded"])
151