Skip to content

Commit 9e0a5be

Browse files
zhytyTom Yang
andauthored
[lldb][split-dwarf] Add --errors-only argument separate-debug-info list (#71000)
Often, we only care about the split-dwarf files that have failed to load. This can be useful when diagnosing binaries with many separate debug info files where only some have errors. ``` (lldb) help image dump separate-debug-info List the separate debug info symbol files for one or more target modules. Syntax: target modules dump separate-debug-info <cmd-options> [<filename> [<filename> [...]]] Command Options Usage: target modules dump separate-debug-info [-ej] [<filename> [<filename> [...]]] -e ( --errors-only ) Filter to show only debug info files with errors. -j ( --json ) Output the details in JSON format. This command takes options and free-form arguments. If your arguments resemble option specifiers (i.e., they start with a - or --), you must use ' -- ' between the end of the command options and the beginning of the arguments. 'image' is an abbreviation for 'target modules' ``` I updated the following tests ``` # on Linux bin/lldb-dotest -p TestDumpDwo # on Mac bin/lldb-dotest -p TestDumpOso ``` This change applies to both the table and JSON outputs. --------- Co-authored-by: Tom Yang <[email protected]>
1 parent deedf55 commit 9e0a5be

File tree

9 files changed

+60
-26
lines changed

9 files changed

+60
-26
lines changed

lldb/include/lldb/Symbol/SymbolFile.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,12 @@ class SymbolFile : public PluginInterface {
445445
/// contains the keys "type", "symfile", and "separate-debug-info-files".
446446
/// "type" can be used to assume the structure of each object in
447447
/// "separate-debug-info-files".
448-
virtual bool GetSeparateDebugInfo(StructuredData::Dictionary &d) {
448+
/// \param errors_only
449+
/// If true, then only return separate debug info files that encountered
450+
/// errors during loading. If false, then return all expected separate
451+
/// debug info files, regardless of whether they were successfully loaded.
452+
virtual bool GetSeparateDebugInfo(StructuredData::Dictionary &d,
453+
bool errors_only) {
449454
return false;
450455
};
451456

lldb/source/Commands/CommandObjectTarget.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1452,11 +1452,11 @@ static bool DumpModuleSymbolFile(Stream &strm, Module *module) {
14521452
}
14531453

14541454
static bool GetSeparateDebugInfoList(StructuredData::Array &list,
1455-
Module *module) {
1455+
Module *module, bool errors_only) {
14561456
if (module) {
14571457
if (SymbolFile *symbol_file = module->GetSymbolFile(/*can_create=*/true)) {
14581458
StructuredData::Dictionary d;
1459-
if (symbol_file->GetSeparateDebugInfo(d)) {
1459+
if (symbol_file->GetSeparateDebugInfo(d, errors_only)) {
14601460
list.AddItem(
14611461
std::make_shared<StructuredData::Dictionary>(std::move(d)));
14621462
return true;
@@ -2561,7 +2561,10 @@ class CommandObjectTargetModulesDumpSeparateDebugInfoFiles
25612561
m_json.SetCurrentValue(true);
25622562
m_json.SetOptionWasSet();
25632563
break;
2564-
2564+
case 'e':
2565+
m_errors_only.SetCurrentValue(true);
2566+
m_errors_only.SetOptionWasSet();
2567+
break;
25652568
default:
25662569
llvm_unreachable("Unimplemented option");
25672570
}
@@ -2570,13 +2573,15 @@ class CommandObjectTargetModulesDumpSeparateDebugInfoFiles
25702573

25712574
void OptionParsingStarting(ExecutionContext *execution_context) override {
25722575
m_json.Clear();
2576+
m_errors_only.Clear();
25732577
}
25742578

25752579
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
25762580
return llvm::ArrayRef(g_target_modules_dump_separate_debug_info_options);
25772581
}
25782582

25792583
OptionValueBoolean m_json = false;
2584+
OptionValueBoolean m_errors_only = false;
25802585
};
25812586

25822587
protected:
@@ -2607,7 +2612,8 @@ class CommandObjectTargetModulesDumpSeparateDebugInfoFiles
26072612
break;
26082613

26092614
if (GetSeparateDebugInfoList(separate_debug_info_lists_by_module,
2610-
module_sp.get()))
2615+
module_sp.get(),
2616+
bool(m_options.m_errors_only)))
26112617
num_dumped++;
26122618
}
26132619
} else {
@@ -2628,7 +2634,7 @@ class CommandObjectTargetModulesDumpSeparateDebugInfoFiles
26282634
break;
26292635
Module *module = module_list.GetModulePointerAtIndex(i);
26302636
if (GetSeparateDebugInfoList(separate_debug_info_lists_by_module,
2631-
module))
2637+
module, bool(m_options.m_errors_only)))
26322638
num_dumped++;
26332639
}
26342640
} else
@@ -2639,11 +2645,13 @@ class CommandObjectTargetModulesDumpSeparateDebugInfoFiles
26392645

26402646
if (num_dumped > 0) {
26412647
Stream &strm = result.GetOutputStream();
2648+
// Display the debug info files in some format.
26422649
if (m_options.m_json) {
2650+
// JSON format
26432651
separate_debug_info_lists_by_module.Dump(strm,
26442652
/*pretty_print=*/true);
26452653
} else {
2646-
// List the debug info files in human readable form.
2654+
// Human-readable table format
26472655
separate_debug_info_lists_by_module.ForEach(
26482656
[&result, &strm](StructuredData::Object *obj) {
26492657
if (!obj) {

lldb/source/Commands/Options.td

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ let Command = "target modules dump symtab" in {
1010

1111
let Command = "target modules dump separate debug info" in {
1212
def tm_json : Option<"json", "j">, Group<1>,
13-
Desc<"Output the details in JSON format.">;
13+
Desc<"Output the details in JSON format.">;
14+
def tm_errors_only : Option<"errors-only", "e">, Group<1>,
15+
Desc<"Filter to show only debug info files with errors.">;
1416
}
1517

1618
let Command = "help" in {

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4243,7 +4243,8 @@ void SymbolFileDWARF::DumpClangAST(Stream &s) {
42434243
clang->Dump(s.AsRawOstream());
42444244
}
42454245

4246-
bool SymbolFileDWARF::GetSeparateDebugInfo(StructuredData::Dictionary &d) {
4246+
bool SymbolFileDWARF::GetSeparateDebugInfo(StructuredData::Dictionary &d,
4247+
bool errors_only) {
42474248
StructuredData::Array separate_debug_info_files;
42484249
DWARFDebugInfo &info = DebugInfo();
42494250
const size_t num_cus = info.GetNumUnits();
@@ -4296,7 +4297,8 @@ bool SymbolFileDWARF::GetSeparateDebugInfo(StructuredData::Dictionary &d) {
42964297
dwarf_cu->GetDwoError().AsCString("unknown"));
42974298
}
42984299
dwo_data->AddBooleanItem("loaded", dwo_symfile != nullptr);
4299-
separate_debug_info_files.AddItem(dwo_data);
4300+
if (!errors_only || dwo_data->HasKey("error"))
4301+
separate_debug_info_files.AddItem(dwo_data);
43004302
}
43014303

43024304
d.AddStringItem("type", "dwo");

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,8 @@ class SymbolFileDWARF : public SymbolFileCommon {
268268
void DumpClangAST(Stream &s) override;
269269

270270
/// List separate dwo files.
271-
bool GetSeparateDebugInfo(StructuredData::Dictionary &d) override;
271+
bool GetSeparateDebugInfo(StructuredData::Dictionary &d,
272+
bool errors_only) override;
272273

273274
DWARFContext &GetDWARFContext() { return m_context; }
274275

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,7 +1278,7 @@ void SymbolFileDWARFDebugMap::DumpClangAST(Stream &s) {
12781278
}
12791279

12801280
bool SymbolFileDWARFDebugMap::GetSeparateDebugInfo(
1281-
lldb_private::StructuredData::Dictionary &d) {
1281+
lldb_private::StructuredData::Dictionary &d, bool errors_only) {
12821282
StructuredData::Array separate_debug_info_files;
12831283
const uint32_t cu_count = GetNumCompileUnits();
12841284
for (uint32_t cu_idx = 0; cu_idx < cu_count; ++cu_idx) {
@@ -1302,7 +1302,8 @@ bool SymbolFileDWARFDebugMap::GetSeparateDebugInfo(
13021302
oso_data->AddStringItem("error", info.oso_load_error.AsCString());
13031303
}
13041304
oso_data->AddBooleanItem("loaded", loaded_successfully);
1305-
separate_debug_info_files.AddItem(oso_data);
1305+
if (!errors_only || oso_data->HasKey("error"))
1306+
separate_debug_info_files.AddItem(oso_data);
13061307
}
13071308

13081309
d.AddStringItem("type", "oso");

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,8 @@ class SymbolFileDWARFDebugMap : public SymbolFileCommon {
136136
void DumpClangAST(Stream &s) override;
137137

138138
/// List separate oso files.
139-
bool GetSeparateDebugInfo(StructuredData::Dictionary &d) override;
139+
bool GetSeparateDebugInfo(StructuredData::Dictionary &d,
140+
bool errors_only) override;
140141

141142
// PluginInterface protocol
142143
llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }

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

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
class TestDumpDWO(lldbtest.TestBase):
1313
NO_DEBUG_INFO_TESTCASE = True
1414

15-
def get_dwos_from_json(self):
15+
def get_dwos_from_json_output(self):
1616
"""Returns a dictionary of `symfile` -> {`dwo_name` -> dwo_info object}."""
1717
result = {}
1818
output = json.loads(self.res.GetOutput())
@@ -42,7 +42,7 @@ def test_dwos_loaded_json_output(self):
4242
self.runCmd("target modules dump separate-debug-info --json")
4343

4444
# Check the output
45-
output = self.get_dwos_from_json()
45+
output = self.get_dwos_from_json_output()
4646
self.assertTrue(output[exe]["main.dwo"]["loaded"])
4747
self.assertTrue(output[exe]["foo.dwo"]["loaded"])
4848

@@ -55,21 +55,27 @@ def test_dwos_not_loaded_json_output(self):
5555
main_dwo = self.getBuildArtifact("main.dwo")
5656
foo_dwo = self.getBuildArtifact("foo.dwo")
5757

58-
# REMOVE the dwo files
58+
# REMOVE one of the dwo files
5959
os.unlink(main_dwo)
60-
os.unlink(foo_dwo)
6160

6261
target = self.dbg.CreateTarget(exe)
6362
self.assertTrue(target, lldbtest.VALID_TARGET)
6463

6564
self.runCmd("target modules dump separate-debug-info --json")
6665

6766
# Check the output
68-
output = self.get_dwos_from_json()
67+
output = self.get_dwos_from_json_output()
68+
self.assertFalse(output[exe]["main.dwo"]["loaded"])
69+
self.assertIn("error", output[exe]["main.dwo"])
70+
self.assertTrue(output[exe]["foo.dwo"]["loaded"])
71+
self.assertNotIn("error", output[exe]["foo.dwo"])
72+
73+
# Check with --errors-only
74+
self.runCmd("target modules dump separate-debug-info --json --errors-only")
75+
output = self.get_dwos_from_json_output()
6976
self.assertFalse(output[exe]["main.dwo"]["loaded"])
70-
self.assertFalse(output[exe]["foo.dwo"]["loaded"])
7177
self.assertIn("error", output[exe]["main.dwo"])
72-
self.assertIn("error", output[exe]["foo.dwo"])
78+
self.assertNotIn("foo.dwo", output[exe])
7379

7480
@skipIfRemote
7581
@skipIfDarwin

lldb/test/API/commands/target/dump-separate-debug-info/oso/TestDumpOso.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
class TestDumpOso(lldbtest.TestBase):
1313
NO_DEBUG_INFO_TESTCASE = True
1414

15-
def get_osos_from_json(self):
15+
def get_osos_from_json_output(self):
1616
"""Returns a dictionary of `symfile` -> {`OSO_PATH` -> oso_info object}."""
1717
result = {}
1818
output = json.loads(self.res.GetOutput())
@@ -41,7 +41,7 @@ def test_shows_oso_loaded_json_output(self):
4141
self.runCmd("target modules dump separate-debug-info --json")
4242

4343
# Check the output
44-
osos = self.get_osos_from_json()
44+
osos = self.get_osos_from_json_output()
4545
self.assertTrue(osos[exe][main_o]["loaded"])
4646
self.assertTrue(osos[exe][foo_o]["loaded"])
4747

@@ -55,17 +55,25 @@ def test_shows_oso_not_loaded_json_output(self):
5555

5656
# REMOVE the o files
5757
os.unlink(main_o)
58-
os.unlink(foo_o)
5958

6059
target = self.dbg.CreateTarget(exe)
6160
self.assertTrue(target, lldbtest.VALID_TARGET)
6261

6362
self.runCmd("target modules dump separate-debug-info --json")
6463

6564
# Check the output
66-
osos = self.get_osos_from_json()
65+
osos = self.get_osos_from_json_output()
6766
self.assertFalse(osos[exe][main_o]["loaded"])
68-
self.assertFalse(osos[exe][foo_o]["loaded"])
67+
self.assertIn("error", osos[exe][main_o])
68+
self.assertTrue(osos[exe][foo_o]["loaded"])
69+
self.assertNotIn("error", osos[exe][foo_o])
70+
71+
# Check with --errors-only
72+
self.runCmd("target modules dump separate-debug-info --json --errors-only")
73+
output = self.get_osos_from_json_output()
74+
self.assertFalse(output[exe][main_o]["loaded"])
75+
self.assertIn("error", output[exe][main_o])
76+
self.assertNotIn(foo_o, output[exe])
6977

7078
@skipIfRemote
7179
@skipUnlessDarwin

0 commit comments

Comments
 (0)