Skip to content

Defer loading all DWOs by default when dumping separate_debug-info #146166

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion lldb/include/lldb/Symbol/SymbolFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -467,8 +467,11 @@ class SymbolFile : public PluginInterface {
/// 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;
};

Expand Down
7 changes: 4 additions & 3 deletions lldb/include/lldb/Symbol/SymbolFileOnDemand.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,9 +223,10 @@ class SymbolFileOnDemand : public lldb_private::SymbolFile {
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,
Expand Down
18 changes: 14 additions & 4 deletions lldb/source/Commands/CommandObjectTarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -2522,6 +2524,10 @@ class CommandObjectTargetModulesDumpSeparateDebugInfoFiles
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();
Expand All @@ -2539,6 +2545,7 @@ class CommandObjectTargetModulesDumpSeparateDebugInfoFiles
void OptionParsingStarting(ExecutionContext *execution_context) override {
m_json.Clear();
m_errors_only.Clear();
m_load_all_debug_info.Clear();
}

llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
Expand All @@ -2547,6 +2554,7 @@ class CommandObjectTargetModulesDumpSeparateDebugInfoFiles

OptionValueBoolean m_json = false;
OptionValueBoolean m_errors_only = false;
OptionValueBoolean m_load_all_debug_info = false;
};

protected:
Expand Down Expand Up @@ -2578,7 +2586,8 @@ class CommandObjectTargetModulesDumpSeparateDebugInfoFiles

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 {
Expand All @@ -2599,7 +2608,8 @@ class CommandObjectTargetModulesDumpSeparateDebugInfoFiles
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
Expand Down
3 changes: 3 additions & 0 deletions lldb/source/Commands/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
5 changes: 3 additions & 2 deletions lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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",
Expand Down
4 changes: 2 additions & 2 deletions lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,8 @@ class SymbolFileDWARF : public SymbolFileCommon {
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ class SymbolFileDWARFDebugMap : public SymbolFileCommon {
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(); }
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ def get_dwos_from_json_output(self):
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}")

Expand Down Expand Up @@ -145,6 +145,75 @@ def test_dwos_loaded_symbols_on_demand(self):
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