Defer loading all DWOs by default when dumping separate_debug-info (#146166)
### Summary Currently `target modules dump separate separate-debug-info` automatically loads up all DWO files, even if deferred loading is enabled through debug_names. Then, as expected all DWO files (assuming there is no error loading it), get marked as "loaded". This change adds the option `--force-load-all-debug-info` or `-f` for short to force loading all debug_info up, if it hasn't been loaded yet. Otherwise, it will change default behavior to not load all debug info so that the correct DWO files will show up for each modules as "loaded" or not "loaded", which could be helpful in cases where we want to know which particular DWO files were loaded. ### Testing #### Unit Tests Added additional unit tests `test_dwos_load_json_with_debug_names_default` and `test_dwos_load_json_with_debug_names_force_load_all` to test both default behavior and loading with the new flag `--force-load-all-debug-info`, and changed expected behavior in `test_dwos_loaded_symbols_on_demand`. ``` bin/lldb-dotest -p TestDumpDwo ~/llvm-project/lldb/test/API/commands/target/dump-separate-debug-info/dwo ``` #### Manual Testing Compiled a simple binary w/ `--gsplit-dwarf --gpubnames` and loaded it up: ``` (lldb) target create "./a.out" Current executable set to '/home/qxy11/hello-world/a.out' (x86_64). (lldb) help target modules 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 [-efj] [<filename> [<filename> [...]]] -e ( --errors-only ) Filter to show only debug info files with errors. -f ( --force-load-all-debug-info ) Load all debug info files. -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. (lldb) target modules dump separate-debug-info --j [ { "separate-debug-info-files": [ { ... "dwo_name": "main.dwo", "loaded": false }, { ... "dwo_name": "foo.dwo", "loaded": false }, { ... "dwo_name": "bar.dwo", "loaded": false } ], } ] (lldb) b main Breakpoint 1: where = a.out`main + 15 at main.cc:3:12, address = 0x00000000000011ff (lldb) target modules dump separate-debug-info --j [ { "separate-debug-info-files": [ { ... "dwo_name": "main.dwo", "loaded": true, "resolved_dwo_path": "/home/qxy11/hello-world/main.dwo" }, { ... "dwo_name": "foo.dwo", "loaded": false }, { ... "dwo_name": "bar.dwo", "loaded": false } ], } ] (lldb) b foo Breakpoint 2: where = a.out`foo(int) + 11 at foo.cc:12:11, address = 0x000000000000121b (lldb) target modules dump separate-debug-info --j [ { "separate-debug-info-files": [ { ... "dwo_name": "main.dwo", "loaded": true, "resolved_dwo_path": "/home/qxy11/hello-world/main.dwo" }, { ... "dwo_name": "foo.dwo", "loaded": true, "resolved_dwo_path": "/home/qxy11/hello-world/foo.dwo" }, { ... "dwo_name": "bar.dwo", "loaded": false } ], } ] (lldb) b bar Breakpoint 3: where = a.out`bar(int) + 11 at bar.cc:10:9, address = 0x000000000000126b (lldb) target modules dump separate-debug-info --j [ { "separate-debug-info-files": [ { ... "dwo_name": "main.dwo", "loaded": true, "resolved_dwo_path": "/home/qxy11/hello-world/main.dwo" }, { ... "dwo_name": "foo.dwo", "loaded": true, "resolved_dwo_path": "/home/qxy11/hello-world/foo.dwo" }, { ... "dwo_name": "bar.dwo", "loaded": true, "resolved_dwo_path": "/home/qxy11/hello-world/bar.dwo" } ], } ] ```
This commit is contained in:
parent
6512ca7ddb
commit
7bd06c41a3
@ -467,8 +467,11 @@ public:
|
||||
/// If true, then only return separate debug info files that encountered
|
||||
/// errors during loading. If false, then return all expected separate
|
||||
/// debug info files, regardless of whether they were successfully loaded.
|
||||
/// \param load_all_debug_info
|
||||
/// If true, force loading any symbol files if they are not yet loaded.
|
||||
virtual bool GetSeparateDebugInfo(StructuredData::Dictionary &d,
|
||||
bool errors_only) {
|
||||
bool errors_only,
|
||||
bool load_all_debug_info = false) {
|
||||
return false;
|
||||
};
|
||||
|
||||
|
@ -223,9 +223,10 @@ public:
|
||||
return m_sym_file_impl->SetDebugInfoHadFrameVariableErrors();
|
||||
}
|
||||
|
||||
bool GetSeparateDebugInfo(StructuredData::Dictionary &d,
|
||||
bool errors_only) override {
|
||||
return m_sym_file_impl->GetSeparateDebugInfo(d, errors_only);
|
||||
bool GetSeparateDebugInfo(StructuredData::Dictionary &d, bool errors_only,
|
||||
bool load_all_debug_info = false) override {
|
||||
return m_sym_file_impl->GetSeparateDebugInfo(d, errors_only,
|
||||
load_all_debug_info);
|
||||
}
|
||||
|
||||
lldb::TypeSP MakeType(lldb::user_id_t uid, ConstString name,
|
||||
|
@ -1412,11 +1412,13 @@ static bool DumpModuleSymbolFile(Stream &strm, Module *module) {
|
||||
}
|
||||
|
||||
static bool GetSeparateDebugInfoList(StructuredData::Array &list,
|
||||
Module *module, bool errors_only) {
|
||||
Module *module, bool errors_only,
|
||||
bool load_all_debug_info) {
|
||||
if (module) {
|
||||
if (SymbolFile *symbol_file = module->GetSymbolFile(/*can_create=*/true)) {
|
||||
StructuredData::Dictionary d;
|
||||
if (symbol_file->GetSeparateDebugInfo(d, errors_only)) {
|
||||
if (symbol_file->GetSeparateDebugInfo(d, errors_only,
|
||||
load_all_debug_info)) {
|
||||
list.AddItem(
|
||||
std::make_shared<StructuredData::Dictionary>(std::move(d)));
|
||||
return true;
|
||||
@ -2522,6 +2524,10 @@ public:
|
||||
const int short_option = m_getopt_table[option_idx].val;
|
||||
|
||||
switch (short_option) {
|
||||
case 'f':
|
||||
m_load_all_debug_info.SetCurrentValue(true);
|
||||
m_load_all_debug_info.SetOptionWasSet();
|
||||
break;
|
||||
case 'j':
|
||||
m_json.SetCurrentValue(true);
|
||||
m_json.SetOptionWasSet();
|
||||
@ -2539,6 +2545,7 @@ public:
|
||||
void OptionParsingStarting(ExecutionContext *execution_context) override {
|
||||
m_json.Clear();
|
||||
m_errors_only.Clear();
|
||||
m_load_all_debug_info.Clear();
|
||||
}
|
||||
|
||||
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
|
||||
@ -2547,6 +2554,7 @@ public:
|
||||
|
||||
OptionValueBoolean m_json = false;
|
||||
OptionValueBoolean m_errors_only = false;
|
||||
OptionValueBoolean m_load_all_debug_info = false;
|
||||
};
|
||||
|
||||
protected:
|
||||
@ -2578,7 +2586,8 @@ protected:
|
||||
|
||||
if (GetSeparateDebugInfoList(separate_debug_info_lists_by_module,
|
||||
module_sp.get(),
|
||||
bool(m_options.m_errors_only)))
|
||||
bool(m_options.m_errors_only),
|
||||
bool(m_options.m_load_all_debug_info)))
|
||||
num_dumped++;
|
||||
}
|
||||
} else {
|
||||
@ -2599,7 +2608,8 @@ protected:
|
||||
break;
|
||||
Module *module = module_list.GetModulePointerAtIndex(i);
|
||||
if (GetSeparateDebugInfoList(separate_debug_info_lists_by_module,
|
||||
module, bool(m_options.m_errors_only)))
|
||||
module, bool(m_options.m_errors_only),
|
||||
bool(m_options.m_load_all_debug_info)))
|
||||
num_dumped++;
|
||||
}
|
||||
} else
|
||||
|
@ -13,6 +13,9 @@ let Command = "target modules dump separate debug info" in {
|
||||
Desc<"Output the details in JSON format.">;
|
||||
def tm_errors_only : Option<"errors-only", "e">, Group<1>,
|
||||
Desc<"Filter to show only debug info files with errors.">;
|
||||
def tm_force_load_all_debug_info : Option<"force-load-all-debug-info", "f">,
|
||||
Group<1>,
|
||||
Desc<"Load all debug info files.">;
|
||||
}
|
||||
|
||||
let Command = "help" in {
|
||||
|
@ -4139,7 +4139,8 @@ void SymbolFileDWARF::DumpClangAST(Stream &s, llvm::StringRef filter) {
|
||||
}
|
||||
|
||||
bool SymbolFileDWARF::GetSeparateDebugInfo(StructuredData::Dictionary &d,
|
||||
bool errors_only) {
|
||||
bool errors_only,
|
||||
bool load_all_debug_info) {
|
||||
StructuredData::Array separate_debug_info_files;
|
||||
DWARFDebugInfo &info = DebugInfo();
|
||||
const size_t num_cus = info.GetNumUnits();
|
||||
@ -4182,7 +4183,7 @@ bool SymbolFileDWARF::GetSeparateDebugInfo(StructuredData::Dictionary &d,
|
||||
|
||||
// If we have a DWO symbol file, that means we were able to successfully
|
||||
// load it.
|
||||
SymbolFile *dwo_symfile = dwarf_cu->GetDwoSymbolFile();
|
||||
SymbolFile *dwo_symfile = dwarf_cu->GetDwoSymbolFile(load_all_debug_info);
|
||||
if (dwo_symfile) {
|
||||
dwo_data->AddStringItem(
|
||||
"resolved_dwo_path",
|
||||
|
@ -279,8 +279,8 @@ public:
|
||||
void DumpClangAST(Stream &s, llvm::StringRef filter) override;
|
||||
|
||||
/// List separate dwo files.
|
||||
bool GetSeparateDebugInfo(StructuredData::Dictionary &d,
|
||||
bool errors_only) override;
|
||||
bool GetSeparateDebugInfo(StructuredData::Dictionary &d, bool errors_only,
|
||||
bool load_all_debug_info = false) override;
|
||||
|
||||
// Gets a pair of loaded and total dwo file counts.
|
||||
// For split-dwarf files, this reports the counts for successfully loaded DWO
|
||||
|
@ -1278,7 +1278,8 @@ void SymbolFileDWARFDebugMap::DumpClangAST(Stream &s, llvm::StringRef filter) {
|
||||
}
|
||||
|
||||
bool SymbolFileDWARFDebugMap::GetSeparateDebugInfo(
|
||||
lldb_private::StructuredData::Dictionary &d, bool errors_only) {
|
||||
lldb_private::StructuredData::Dictionary &d, bool errors_only,
|
||||
bool load_all_debug_info) {
|
||||
StructuredData::Array separate_debug_info_files;
|
||||
const uint32_t cu_count = GetNumCompileUnits();
|
||||
for (uint32_t cu_idx = 0; cu_idx < cu_count; ++cu_idx) {
|
||||
|
@ -132,8 +132,8 @@ public:
|
||||
void DumpClangAST(Stream &s, llvm::StringRef filter) override;
|
||||
|
||||
/// List separate oso files.
|
||||
bool GetSeparateDebugInfo(StructuredData::Dictionary &d,
|
||||
bool errors_only) override;
|
||||
bool GetSeparateDebugInfo(StructuredData::Dictionary &d, bool errors_only,
|
||||
bool load_all_debug_info = false) override;
|
||||
|
||||
// PluginInterface protocol
|
||||
llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
|
||||
|
@ -1,4 +1,4 @@
|
||||
include Makefile.rules
|
||||
|
||||
a.out:
|
||||
$(CC) -target x86_64-pc-linux-elf -g -gsplit-dwarf -o $@ $(SRCDIR)/main.c $(SRCDIR)/foo.c
|
||||
$(CC) $(CFLAGS) -target x86_64-pc-linux-elf -g -gsplit-dwarf -o $@ $(SRCDIR)/main.c $(SRCDIR)/foo.c
|
||||
|
@ -24,9 +24,9 @@ class TestDumpDWO(lldbtest.TestBase):
|
||||
result[symfile_entry["symfile"]] = dwo_dict
|
||||
return result
|
||||
|
||||
def build_and_skip_if_error(self):
|
||||
def build_and_skip_if_error(self, debug_info=None):
|
||||
try:
|
||||
self.build()
|
||||
self.build(debug_info=debug_info)
|
||||
except BuildError as e:
|
||||
self.skipTest(f"Skipping test due to build exception: {e}")
|
||||
|
||||
@ -145,6 +145,75 @@ class TestDumpDWO(lldbtest.TestBase):
|
||||
self.runCmd("target modules dump separate-debug-info --json")
|
||||
|
||||
# Check the output
|
||||
output = self.get_dwos_from_json_output()
|
||||
self.assertFalse(output[exe]["a.out-main.dwo"]["loaded"])
|
||||
self.assertFalse(output[exe]["a.out-foo.dwo"]["loaded"])
|
||||
# Set a breakpoint in main(). All DWO files should be loaded now
|
||||
self.runCmd("b main")
|
||||
self.runCmd("target modules dump separate-debug-info --json")
|
||||
output = self.get_dwos_from_json_output()
|
||||
self.assertTrue(output[exe]["a.out-main.dwo"]["loaded"])
|
||||
self.assertTrue(output[exe]["a.out-foo.dwo"]["loaded"])
|
||||
|
||||
def test_dwos_load_json_with_debug_names_default(self):
|
||||
"""
|
||||
Test that DWO files are lazily loaded, and target module dump gives the expected output.
|
||||
"""
|
||||
# Build with split DWARF, debug_names, and gpubnames
|
||||
self.build_and_skip_if_error(debug_info=["debug_names"])
|
||||
exe = self.getBuildArtifact("a.out")
|
||||
|
||||
main_dwo = self.getBuildArtifact("a.out-main.dwo")
|
||||
foo_dwo = self.getBuildArtifact("a.out-foo.dwo")
|
||||
|
||||
# Make sure dwo files exist
|
||||
self.assertTrue(os.path.exists(main_dwo), f'Make sure "{main_dwo}" file exists')
|
||||
self.assertTrue(os.path.exists(foo_dwo), f'Make sure "{foo_dwo}" file exists')
|
||||
|
||||
target = self.dbg.CreateTarget(exe)
|
||||
self.assertTrue(target, lldbtest.VALID_TARGET)
|
||||
|
||||
self.runCmd("target modules dump separate-debug-info --j")
|
||||
|
||||
# Check the output
|
||||
output = self.get_dwos_from_json_output()
|
||||
self.assertFalse(output[exe]["a.out-main.dwo"]["loaded"])
|
||||
self.assertFalse(output[exe]["a.out-foo.dwo"]["loaded"])
|
||||
|
||||
# Set a breakpoint in main(). a.out-main.dwo should be loaded now
|
||||
self.runCmd("b main")
|
||||
self.runCmd("target modules dump separate-debug-info --j")
|
||||
output = self.get_dwos_from_json_output()
|
||||
self.assertTrue(output[exe]["a.out-main.dwo"]["loaded"])
|
||||
self.assertFalse(output[exe]["a.out-foo.dwo"]["loaded"])
|
||||
|
||||
# Set a breakpoint in foo(). a.out-foo.dwo should be loaded now
|
||||
self.runCmd("b foo")
|
||||
self.runCmd("target modules dump separate-debug-info --j")
|
||||
output = self.get_dwos_from_json_output()
|
||||
self.assertTrue(output[exe]["a.out-main.dwo"]["loaded"])
|
||||
self.assertTrue(output[exe]["a.out-foo.dwo"]["loaded"])
|
||||
|
||||
def test_dwos_load_json_with_debug_names_force_load_all(self):
|
||||
"""
|
||||
Test that DWO files are lazily loaded, and target module dump gives the expected output.
|
||||
"""
|
||||
# Build with split DWARF, debug_names, and gpubnames
|
||||
self.build_and_skip_if_error(debug_info=["debug_names"])
|
||||
exe = self.getBuildArtifact("a.out")
|
||||
|
||||
main_dwo = self.getBuildArtifact("a.out-main.dwo")
|
||||
foo_dwo = self.getBuildArtifact("a.out-foo.dwo")
|
||||
|
||||
# Make sure dwo files exist
|
||||
self.assertTrue(os.path.exists(main_dwo), f'Make sure "{main_dwo}" file exists')
|
||||
self.assertTrue(os.path.exists(foo_dwo), f'Make sure "{foo_dwo}" file exists')
|
||||
|
||||
target = self.dbg.CreateTarget(exe)
|
||||
self.assertTrue(target, lldbtest.VALID_TARGET)
|
||||
|
||||
self.runCmd("target modules dump separate-debug-info --j --f")
|
||||
|
||||
output = self.get_dwos_from_json_output()
|
||||
self.assertTrue(output[exe]["a.out-main.dwo"]["loaded"])
|
||||
self.assertTrue(output[exe]["a.out-foo.dwo"]["loaded"])
|
||||
|
Loading…
x
Reference in New Issue
Block a user