Skip to content

Commit 65cdc87

Browse files
committed
Add defer-load-all-debug-info option to dumping separate_debug-info
The target modules dump separate separate-debug-info option automatically loads up all DWO files, even if deferred loading is enabled through debug_names. This adds the option to get the debug info without loading it up, if it hasn't been loaded yet, so that the correct DWO files will show up for each modules as "loaded" or not "loaded", which could be more informational to the user.
1 parent 52040b4 commit 65cdc87

File tree

10 files changed

+137
-38
lines changed

10 files changed

+137
-38
lines changed

lldb/include/lldb/Symbol/SymbolFile.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -467,8 +467,11 @@ class SymbolFile : public PluginInterface {
467467
/// If true, then only return separate debug info files that encountered
468468
/// errors during loading. If false, then return all expected separate
469469
/// debug info files, regardless of whether they were successfully loaded.
470+
/// \param load_all_debug_info
471+
/// If true, force loading any symbol files if they are not yet loaded.
470472
virtual bool GetSeparateDebugInfo(StructuredData::Dictionary &d,
471-
bool errors_only) {
473+
bool errors_only,
474+
bool load_all_debug_info = false) {
472475
return false;
473476
};
474477

lldb/include/lldb/Symbol/SymbolFileOnDemand.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,9 +223,10 @@ class SymbolFileOnDemand : public lldb_private::SymbolFile {
223223
return m_sym_file_impl->SetDebugInfoHadFrameVariableErrors();
224224
}
225225

226-
bool GetSeparateDebugInfo(StructuredData::Dictionary &d,
227-
bool errors_only) override {
228-
return m_sym_file_impl->GetSeparateDebugInfo(d, errors_only);
226+
bool GetSeparateDebugInfo(StructuredData::Dictionary &d, bool errors_only,
227+
bool load_all_debug_info = false) override {
228+
return m_sym_file_impl->GetSeparateDebugInfo(d, errors_only,
229+
load_all_debug_info);
229230
}
230231

231232
lldb::TypeSP MakeType(lldb::user_id_t uid, ConstString name,

lldb/source/Commands/CommandObjectTarget.cpp

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1412,11 +1412,13 @@ static bool DumpModuleSymbolFile(Stream &strm, Module *module) {
14121412
}
14131413

14141414
static bool GetSeparateDebugInfoList(StructuredData::Array &list,
1415-
Module *module, bool errors_only) {
1415+
Module *module, bool errors_only,
1416+
bool load_all_debug_info) {
14161417
if (module) {
14171418
if (SymbolFile *symbol_file = module->GetSymbolFile(/*can_create=*/true)) {
14181419
StructuredData::Dictionary d;
1419-
if (symbol_file->GetSeparateDebugInfo(d, errors_only)) {
1420+
if (symbol_file->GetSeparateDebugInfo(d, errors_only,
1421+
load_all_debug_info)) {
14201422
list.AddItem(
14211423
std::make_shared<StructuredData::Dictionary>(std::move(d)));
14221424
return true;
@@ -2030,7 +2032,8 @@ class CommandObjectTargetModulesDumpSymtab
20302032
}
20312033
if (INTERRUPT_REQUESTED(GetDebugger(),
20322034
"Interrupted in dump all symtabs with {0} "
2033-
"of {1} dumped.", num_dumped, num_modules))
2035+
"of {1} dumped.",
2036+
num_dumped, num_modules))
20342037
break;
20352038

20362039
num_dumped++;
@@ -2058,9 +2061,10 @@ class CommandObjectTargetModulesDumpSymtab
20582061
result.GetOutputStream().EOL();
20592062
result.GetOutputStream().EOL();
20602063
}
2061-
if (INTERRUPT_REQUESTED(GetDebugger(),
2062-
"Interrupted in dump symtab list with {0} of {1} dumped.",
2063-
num_dumped, num_matches))
2064+
if (INTERRUPT_REQUESTED(
2065+
GetDebugger(),
2066+
"Interrupted in dump symtab list with {0} of {1} dumped.",
2067+
num_dumped, num_matches))
20642068
break;
20652069

20662070
num_dumped++;
@@ -2121,9 +2125,10 @@ class CommandObjectTargetModulesDumpSections
21212125
result.GetOutputStream().Format("Dumping sections for {0} modules.\n",
21222126
num_modules);
21232127
for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) {
2124-
if (INTERRUPT_REQUESTED(GetDebugger(),
2125-
"Interrupted in dump all sections with {0} of {1} dumped",
2126-
image_idx, num_modules))
2128+
if (INTERRUPT_REQUESTED(
2129+
GetDebugger(),
2130+
"Interrupted in dump all sections with {0} of {1} dumped",
2131+
image_idx, num_modules))
21272132
break;
21282133

21292134
num_dumped++;
@@ -2142,9 +2147,10 @@ class CommandObjectTargetModulesDumpSections
21422147
FindModulesByName(&target, arg_cstr, module_list, true);
21432148
if (num_matches > 0) {
21442149
for (size_t i = 0; i < num_matches; ++i) {
2145-
if (INTERRUPT_REQUESTED(GetDebugger(),
2146-
"Interrupted in dump section list with {0} of {1} dumped.",
2147-
i, num_matches))
2150+
if (INTERRUPT_REQUESTED(
2151+
GetDebugger(),
2152+
"Interrupted in dump section list with {0} of {1} dumped.",
2153+
i, num_matches))
21482154
break;
21492155

21502156
Module *module = module_list.GetModulePointerAtIndex(i);
@@ -2295,9 +2301,10 @@ class CommandObjectTargetModulesDumpClangAST
22952301
}
22962302

22972303
for (size_t i = 0; i < num_matches; ++i) {
2298-
if (INTERRUPT_REQUESTED(GetDebugger(),
2299-
"Interrupted in dump clang ast list with {0} of {1} dumped.",
2300-
i, num_matches))
2304+
if (INTERRUPT_REQUESTED(
2305+
GetDebugger(),
2306+
"Interrupted in dump clang ast list with {0} of {1} dumped.", i,
2307+
num_matches))
23012308
break;
23022309

23032310
Module *m = module_list.GetModulePointerAtIndex(i);
@@ -2346,9 +2353,10 @@ class CommandObjectTargetModulesDumpSymfile
23462353
result.GetOutputStream().Format(
23472354
"Dumping debug symbols for {0} modules.\n", num_modules);
23482355
for (ModuleSP module_sp : target_modules.ModulesNoLocking()) {
2349-
if (INTERRUPT_REQUESTED(GetDebugger(), "Interrupted in dumping all "
2356+
if (INTERRUPT_REQUESTED(GetDebugger(),
2357+
"Interrupted in dumping all "
23502358
"debug symbols with {0} of {1} modules dumped",
2351-
num_dumped, num_modules))
2359+
num_dumped, num_modules))
23522360
break;
23532361

23542362
if (DumpModuleSymbolFile(result.GetOutputStream(), module_sp.get()))
@@ -2365,9 +2373,10 @@ class CommandObjectTargetModulesDumpSymfile
23652373
FindModulesByName(&target, arg_cstr, module_list, true);
23662374
if (num_matches > 0) {
23672375
for (size_t i = 0; i < num_matches; ++i) {
2368-
if (INTERRUPT_REQUESTED(GetDebugger(), "Interrupted dumping {0} "
2369-
"of {1} requested modules",
2370-
i, num_matches))
2376+
if (INTERRUPT_REQUESTED(GetDebugger(),
2377+
"Interrupted dumping {0} "
2378+
"of {1} requested modules",
2379+
i, num_matches))
23712380
break;
23722381
Module *module = module_list.GetModulePointerAtIndex(i);
23732382
if (module) {
@@ -2436,8 +2445,8 @@ class CommandObjectTargetModulesDumpLineTable
24362445
for (ModuleSP module_sp : target_modules.ModulesNoLocking()) {
24372446
if (INTERRUPT_REQUESTED(GetDebugger(),
24382447
"Interrupted in dump all line tables with "
2439-
"{0} of {1} dumped", num_dumped,
2440-
num_modules))
2448+
"{0} of {1} dumped",
2449+
num_dumped, num_modules))
24412450
break;
24422451

24432452
if (DumpCompileUnitLineTable(
@@ -2522,6 +2531,10 @@ class CommandObjectTargetModulesDumpSeparateDebugInfoFiles
25222531
const int short_option = m_getopt_table[option_idx].val;
25232532

25242533
switch (short_option) {
2534+
case 'd':
2535+
m_load_all_debug_info.SetCurrentValue(false);
2536+
m_load_all_debug_info.SetOptionWasSet();
2537+
break;
25252538
case 'j':
25262539
m_json.SetCurrentValue(true);
25272540
m_json.SetOptionWasSet();
@@ -2539,6 +2552,7 @@ class CommandObjectTargetModulesDumpSeparateDebugInfoFiles
25392552
void OptionParsingStarting(ExecutionContext *execution_context) override {
25402553
m_json.Clear();
25412554
m_errors_only.Clear();
2555+
m_load_all_debug_info.Clear();
25422556
}
25432557

25442558
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
@@ -2547,6 +2561,7 @@ class CommandObjectTargetModulesDumpSeparateDebugInfoFiles
25472561

25482562
OptionValueBoolean m_json = false;
25492563
OptionValueBoolean m_errors_only = false;
2564+
OptionValueBoolean m_load_all_debug_info = true;
25502565
};
25512566

25522567
protected:
@@ -2578,7 +2593,8 @@ class CommandObjectTargetModulesDumpSeparateDebugInfoFiles
25782593

25792594
if (GetSeparateDebugInfoList(separate_debug_info_lists_by_module,
25802595
module_sp.get(),
2581-
bool(m_options.m_errors_only)))
2596+
bool(m_options.m_errors_only),
2597+
bool(m_options.m_load_all_debug_info)))
25822598
num_dumped++;
25832599
}
25842600
} else {
@@ -2599,7 +2615,8 @@ class CommandObjectTargetModulesDumpSeparateDebugInfoFiles
25992615
break;
26002616
Module *module = module_list.GetModulePointerAtIndex(i);
26012617
if (GetSeparateDebugInfoList(separate_debug_info_lists_by_module,
2602-
module, bool(m_options.m_errors_only)))
2618+
module, bool(m_options.m_errors_only),
2619+
bool(m_options.m_load_all_debug_info)))
26032620
num_dumped++;
26042621
}
26052622
} else

lldb/source/Commands/Options.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ let Command = "target modules dump separate debug info" in {
1313
Desc<"Output the details in JSON format.">;
1414
def tm_errors_only : Option<"errors-only", "e">, Group<1>,
1515
Desc<"Filter to show only debug info files with errors.">;
16+
def tm_defer_load_all_debug_info : Option<"defer-load-all-debug-info", "d">,
17+
Group<1>,
18+
Desc<"Load all debug info files.">;
1619
}
1720

1821
let Command = "help" in {

lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4139,7 +4139,8 @@ void SymbolFileDWARF::DumpClangAST(Stream &s, llvm::StringRef filter) {
41394139
}
41404140

41414141
bool SymbolFileDWARF::GetSeparateDebugInfo(StructuredData::Dictionary &d,
4142-
bool errors_only) {
4142+
bool errors_only,
4143+
bool load_all_debug_info) {
41434144
StructuredData::Array separate_debug_info_files;
41444145
DWARFDebugInfo &info = DebugInfo();
41454146
const size_t num_cus = info.GetNumUnits();
@@ -4182,7 +4183,7 @@ bool SymbolFileDWARF::GetSeparateDebugInfo(StructuredData::Dictionary &d,
41824183

41834184
// If we have a DWO symbol file, that means we were able to successfully
41844185
// load it.
4185-
SymbolFile *dwo_symfile = dwarf_cu->GetDwoSymbolFile();
4186+
SymbolFile *dwo_symfile = dwarf_cu->GetDwoSymbolFile(load_all_debug_info);
41864187
if (dwo_symfile) {
41874188
dwo_data->AddStringItem(
41884189
"resolved_dwo_path",

lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,8 +279,8 @@ class SymbolFileDWARF : public SymbolFileCommon {
279279
void DumpClangAST(Stream &s, llvm::StringRef filter) override;
280280

281281
/// List separate dwo files.
282-
bool GetSeparateDebugInfo(StructuredData::Dictionary &d,
283-
bool errors_only) override;
282+
bool GetSeparateDebugInfo(StructuredData::Dictionary &d, bool errors_only,
283+
bool load_all_debug_info = false) override;
284284

285285
// Gets a pair of loaded and total dwo file counts.
286286
// For split-dwarf files, this reports the counts for successfully loaded DWO

lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1278,7 +1278,8 @@ void SymbolFileDWARFDebugMap::DumpClangAST(Stream &s, llvm::StringRef filter) {
12781278
}
12791279

12801280
bool SymbolFileDWARFDebugMap::GetSeparateDebugInfo(
1281-
lldb_private::StructuredData::Dictionary &d, bool errors_only) {
1281+
lldb_private::StructuredData::Dictionary &d, bool errors_only,
1282+
bool load_all_debug_info) {
12821283
StructuredData::Array separate_debug_info_files;
12831284
const uint32_t cu_count = GetNumCompileUnits();
12841285
for (uint32_t cu_idx = 0; cu_idx < cu_count; ++cu_idx) {

lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,8 @@ class SymbolFileDWARFDebugMap : public SymbolFileCommon {
132132
void DumpClangAST(Stream &s, llvm::StringRef filter) override;
133133

134134
/// List separate oso files.
135-
bool GetSeparateDebugInfo(StructuredData::Dictionary &d,
136-
bool errors_only) override;
135+
bool GetSeparateDebugInfo(StructuredData::Dictionary &d, bool errors_only,
136+
bool load_all_debug_info = false) override;
137137

138138
// PluginInterface protocol
139139
llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
include Makefile.rules
22

33
a.out:
4-
$(CC) -target x86_64-pc-linux-elf -g -gsplit-dwarf -o $@ $(SRCDIR)/main.c $(SRCDIR)/foo.c
4+
$(CC) $(CFLAGS) -target x86_64-pc-linux-elf -g -gsplit-dwarf -o $@ $(SRCDIR)/main.c $(SRCDIR)/foo.c

lldb/test/API/commands/target/dump-separate-debug-info/dwo/TestDumpDwo.py

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ def get_dwos_from_json_output(self):
2424
result[symfile_entry["symfile"]] = dwo_dict
2525
return result
2626

27-
def build_and_skip_if_error(self):
27+
def build_and_skip_if_error(self, debug_info=None):
2828
try:
29-
self.build()
29+
self.build(debug_info=debug_info)
3030
except BuildError as e:
3131
self.skipTest(f"Skipping test due to build exception: {e}")
3232

@@ -148,3 +148,76 @@ def test_dwos_loaded_symbols_on_demand(self):
148148
output = self.get_dwos_from_json_output()
149149
self.assertTrue(output[exe]["a.out-main.dwo"]["loaded"])
150150
self.assertTrue(output[exe]["a.out-foo.dwo"]["loaded"])
151+
152+
def test_dwos_loaded_symbols_on_demand_defer_load_all(self):
153+
self.build_and_skip_if_error()
154+
exe = self.getBuildArtifact("a.out")
155+
main_dwo = self.getBuildArtifact("a.out-main.dwo")
156+
foo_dwo = self.getBuildArtifact("a.out-foo.dwo")
157+
158+
# Make sure dwo files exist
159+
self.assertTrue(os.path.exists(main_dwo), f'Make sure "{main_dwo}" file exists')
160+
self.assertTrue(os.path.exists(foo_dwo), f'Make sure "{foo_dwo}" file exists')
161+
162+
# Load symbols on-demand
163+
self.runCmd("settings set symbols.load-on-demand true")
164+
165+
target = self.dbg.CreateTarget(exe)
166+
self.assertTrue(target, lldbtest.VALID_TARGET)
167+
168+
self.runCmd(
169+
"target modules dump separate-debug-info --json --defer-load-all-debug-info"
170+
)
171+
172+
# Check the output
173+
output = self.get_dwos_from_json_output()
174+
self.assertFalse(output[exe]["a.out-main.dwo"]["loaded"])
175+
self.assertFalse(output[exe]["a.out-foo.dwo"]["loaded"])
176+
177+
# Set a breakpoint in main(). All DWO files should be loaded now
178+
self.runCmd("b main")
179+
self.runCmd(
180+
"target modules dump separate-debug-info --json --defer-load-all-debug-info"
181+
)
182+
output = self.get_dwos_from_json_output()
183+
self.assertTrue(output[exe]["a.out-main.dwo"]["loaded"])
184+
self.assertTrue(output[exe]["a.out-foo.dwo"]["loaded"])
185+
186+
def test_dwos_defer_loaded_json_with_debug_names(self):
187+
"""
188+
Test that DWO files are lazily loaded, and target module dump gives the expected output.
189+
"""
190+
# Build with split DWARF, debug_names, and gpubnames
191+
self.build_and_skip_if_error(debug_info=["debug_names"])
192+
exe = self.getBuildArtifact("a.out")
193+
194+
main_dwo = self.getBuildArtifact("a.out-main.dwo")
195+
foo_dwo = self.getBuildArtifact("a.out-foo.dwo")
196+
197+
# Make sure dwo files exist
198+
self.assertTrue(os.path.exists(main_dwo), f'Make sure "{main_dwo}" file exists')
199+
self.assertTrue(os.path.exists(foo_dwo), f'Make sure "{foo_dwo}" file exists')
200+
201+
target = self.dbg.CreateTarget(exe)
202+
self.assertTrue(target, lldbtest.VALID_TARGET)
203+
204+
self.runCmd("target modules dump separate-debug-info --j --d")
205+
206+
# Check the output
207+
output = self.get_dwos_from_json_output()
208+
self.assertFalse(output[exe]["a.out-main.dwo"]["loaded"])
209+
self.assertFalse(output[exe]["a.out-foo.dwo"]["loaded"])
210+
211+
# Set a breakpoint in main(). a.out-main.dwo should be loaded now
212+
self.runCmd("b main")
213+
self.runCmd("target modules dump separate-debug-info --j --d")
214+
output = self.get_dwos_from_json_output()
215+
self.assertTrue(output[exe]["a.out-main.dwo"]["loaded"])
216+
self.assertFalse(output[exe]["a.out-foo.dwo"]["loaded"])
217+
218+
# Set a breakpoint in foo(). a.out-foo.dwo should be loaded now
219+
self.runCmd("b foo")
220+
self.runCmd("target modules dump separate-debug-info --j --d")
221+
output = self.get_dwos_from_json_output()
222+
self.assertTrue(output[exe]["a.out-main.dwo"]["loaded"])
223+
self.assertTrue(output[exe]["a.out-foo.dwo"]["loaded"])

0 commit comments

Comments
 (0)