Report only loaded debug info in statistics dump (#81706)

Currently running `statistics dump` will trigger lldb to load debug info
that's not yet loaded (eg. dwo files). Resulted in a delay in the
command return, which, can be interrupting.

This patch also added a new option `--load-all-debug-info` asking
statistics to dump all possible debug info, which will force loading all
debug info available if not yet loaded.
This commit is contained in:
Wanyi
2024-02-17 14:38:18 -05:00
committed by GitHub
parent 27f2908fbc
commit 21ddd7ff2b
24 changed files with 346 additions and 21 deletions

View File

@@ -6,3 +6,9 @@
) lldb::SBStatisticsOptions::SetSummaryOnly;
%feature("docstring", "Gets whether the statistics only dump a summary."
) lldb::SBStatisticsOptions::GetSummaryOnly;
%feature("docstring", "
Sets whether the statistics will force loading all possible debug info."
) lldb::SBStatisticsOptions::SetReportAllAvailableDebugInfo;
%feature("docstring", "
Gets whether the statistics will force loading all possible debug info."
) lldb::SBStatisticsOptions::GetReportAllAvailableDebugInfo;

View File

@@ -25,6 +25,14 @@ public:
void SetSummaryOnly(bool b);
bool GetSummaryOnly();
/// If set to true, the debugger will load all debug info that is available
/// and report statistics on the total amount. If this is set to false, then
/// only report statistics on the currently loaded debug information.
/// This can avoid loading debug info from separate files just so it can
/// report the total size which can slow down statistics reporting.
void SetReportAllAvailableDebugInfo(bool b);
bool GetReportAllAvailableDebugInfo();
protected:
friend class SBTarget;
const lldb_private::StatisticsOptions &ref() const;

View File

@@ -381,7 +381,8 @@ public:
/// Metrics gathering functions
/// Return the size in bytes of all debug information in the symbol file.
/// Return the size in bytes of all loaded debug information or total possible
/// debug info in the symbol file.
///
/// If the debug information is contained in sections of an ObjectFile, then
/// this call should add the size of all sections that contain debug
@@ -391,7 +392,14 @@ public:
/// entire file should be returned. The default implementation of this
/// function will iterate over all sections in a module and add up their
/// debug info only section byte sizes.
virtual uint64_t GetDebugInfoSize() = 0;
///
/// \param load_all_debug_info
/// If true, force loading any symbol files if they are not yet loaded and
/// add to the total size. Default to false.
///
/// \returns
/// Total currently loaded debug info size in bytes
virtual uint64_t GetDebugInfoSize(bool load_all_debug_info = false) = 0;
/// Return the time taken to parse the debug information.
///
@@ -534,7 +542,7 @@ public:
void Dump(Stream &s) override;
uint64_t GetDebugInfoSize() override;
uint64_t GetDebugInfoSize(bool load_all_debug_info = false) override;
bool GetDebugInfoIndexWasLoadedFromCache() const override {
return m_index_was_loaded_from_cache;

View File

@@ -178,7 +178,7 @@ public:
void PreloadSymbols() override;
uint64_t GetDebugInfoSize() override;
uint64_t GetDebugInfoSize(bool load_all_debug_info = false) override;
lldb_private::StatsDuration::Duration GetDebugInfoParseTime() override;
lldb_private::StatsDuration::Duration GetDebugInfoIndexTime() override;

View File

@@ -132,6 +132,7 @@ struct ConstStringStats {
struct StatisticsOptions {
bool summary_only = false;
bool load_all_debug_info = false;
};
/// A class that represents statistics for a since lldb_private::Target.

View File

@@ -44,6 +44,14 @@ void SBStatisticsOptions::SetSummaryOnly(bool b) {
bool SBStatisticsOptions::GetSummaryOnly() { return m_opaque_up->summary_only; }
void SBStatisticsOptions::SetReportAllAvailableDebugInfo(bool b) {
m_opaque_up->load_all_debug_info = b;
}
bool SBStatisticsOptions::GetReportAllAvailableDebugInfo() {
return m_opaque_up->load_all_debug_info;
}
const lldb_private::StatisticsOptions &SBStatisticsOptions::ref() const {
return *m_opaque_up;
}

View File

@@ -78,6 +78,9 @@ class CommandObjectStatsDump : public CommandObjectParsed {
case 's':
m_stats_options.summary_only = true;
break;
case 'f':
m_stats_options.load_all_debug_info = true;
break;
default:
llvm_unreachable("Unimplemented option");
}

View File

@@ -1419,6 +1419,10 @@ let Command = "statistics dump" in {
def statistics_dump_all: Option<"all-targets", "a">, Group<1>,
Desc<"Include statistics for all targets.">;
def statistics_dump_summary: Option<"summary", "s">, Group<1>,
Desc<"Dump only high-level summary statistics."
Desc<"Dump only high-level summary statistics. "
"Exclude targets, modules, breakpoints etc... details.">;
def statistics_dump_force: Option<"load-all-debug-info", "f">, Group<1>,
Desc<"Dump the total possible debug info statistics. "
"Force loading all the debug information if not yet loaded, and collect "
"statistics with those.">;
}

View File

@@ -918,7 +918,7 @@ void SymbolFileBreakpad::ParseUnwindData() {
m_unwind_data->win.Sort();
}
uint64_t SymbolFileBreakpad::GetDebugInfoSize() {
uint64_t SymbolFileBreakpad::GetDebugInfoSize(bool load_all_debug_info) {
// Breakpad files are all debug info.
return m_objfile_sp->GetByteSize();
}

View File

@@ -141,7 +141,7 @@ public:
llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
uint64_t GetDebugInfoSize() override;
uint64_t GetDebugInfoSize(bool load_all_debug_info = false) override;
private:
// A class representing a position in the breakpad file. Useful for

View File

@@ -896,8 +896,9 @@ void DWARFUnit::ComputeAbsolutePath() {
m_file_spec->MakeAbsolute(GetCompilationDirectory());
}
SymbolFileDWARFDwo *DWARFUnit::GetDwoSymbolFile() {
ExtractUnitDIEIfNeeded();
SymbolFileDWARFDwo *DWARFUnit::GetDwoSymbolFile(bool load_all_debug_info) {
if (load_all_debug_info)
ExtractUnitDIEIfNeeded();
if (m_dwo)
return &llvm::cast<SymbolFileDWARFDwo>(m_dwo->GetSymbolFileDWARF());
return nullptr;

View File

@@ -241,7 +241,7 @@ public:
FileSpec GetFile(size_t file_idx);
FileSpec::Style GetPathStyle();
SymbolFileDWARFDwo *GetDwoSymbolFile();
SymbolFileDWARFDwo *GetDwoSymbolFile(bool load_all_debug_info = false);
die_iterator_range dies() {
ExtractDIEsIfNeeded();

View File

@@ -2672,7 +2672,7 @@ static bool UpdateCompilerContextForSimpleTemplateNames(TypeQuery &match) {
return any_context_updated;
}
uint64_t SymbolFileDWARF::GetDebugInfoSize() {
uint64_t SymbolFileDWARF::GetDebugInfoSize(bool load_all_debug_info) {
DWARFDebugInfo &info = DebugInfo();
uint32_t num_comp_units = info.GetNumUnits();
@@ -2687,7 +2687,7 @@ uint64_t SymbolFileDWARF::GetDebugInfoSize() {
if (cu == nullptr)
continue;
SymbolFileDWARFDwo *dwo = cu->GetDwoSymbolFile();
SymbolFileDWARFDwo *dwo = cu->GetDwoSymbolFile(load_all_debug_info);
if (dwo)
debug_info_size += dwo->GetDebugInfoSize();
}

View File

@@ -186,7 +186,7 @@ public:
GetMangledNamesForFunction(const std::string &scope_qualified_name,
std::vector<ConstString> &mangled_names) override;
uint64_t GetDebugInfoSize() override;
uint64_t GetDebugInfoSize(bool load_all_debug_info = false) override;
void FindTypes(const lldb_private::TypeQuery &match,
lldb_private::TypeResults &results) override;

View File

@@ -85,7 +85,7 @@ lldb::offset_t SymbolFileDWARFDwo::GetVendorDWARFOpcodeSize(
return GetBaseSymbolFile().GetVendorDWARFOpcodeSize(data, data_offset, op);
}
uint64_t SymbolFileDWARFDwo::GetDebugInfoSize() {
uint64_t SymbolFileDWARFDwo::GetDebugInfoSize(bool load_all_debug_info) {
// Directly get debug info from current dwo object file's section list
// instead of asking SymbolFileCommon::GetDebugInfo() which parses from
// owning module which is wrong.

View File

@@ -47,7 +47,7 @@ public:
const lldb::offset_t data_offset,
const uint8_t op) const override;
uint64_t GetDebugInfoSize() override;
uint64_t GetDebugInfoSize(bool load_all_debug_info = false) override;
bool ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes,
lldb::offset_t &offset,

View File

@@ -2156,7 +2156,7 @@ SymbolFileNativePDB::GetTypeSystemForLanguage(lldb::LanguageType language) {
return type_system_or_err;
}
uint64_t SymbolFileNativePDB::GetDebugInfoSize() {
uint64_t SymbolFileNativePDB::GetDebugInfoSize(bool load_all_debug_info) {
// PDB files are a separate file that contains all debug info.
return m_index->pdb().getFileSize();
}

View File

@@ -77,7 +77,7 @@ public:
void InitializeObject() override;
uint64_t GetDebugInfoSize() override;
uint64_t GetDebugInfoSize(bool load_all_debug_info = false) override;
// Compile Unit function calls

View File

@@ -227,7 +227,7 @@ SymbolFileCommon::GetTypeSystemForLanguage(lldb::LanguageType language) {
return type_system_or_err;
}
uint64_t SymbolFileCommon::GetDebugInfoSize() {
uint64_t SymbolFileCommon::GetDebugInfoSize(bool load_all_debug_info) {
if (!m_objfile_sp)
return 0;
ModuleSP module_sp(m_objfile_sp->GetModule());

View File

@@ -535,11 +535,11 @@ void SymbolFileOnDemand::PreloadSymbols() {
return m_sym_file_impl->PreloadSymbols();
}
uint64_t SymbolFileOnDemand::GetDebugInfoSize() {
uint64_t SymbolFileOnDemand::GetDebugInfoSize(bool load_all_debug_info) {
// Always return the real debug info size.
LLDB_LOG(GetLog(), "[{0}] {1} is not skipped", GetSymbolFileName(),
__FUNCTION__);
return m_sym_file_impl->GetDebugInfoSize();
return m_sym_file_impl->GetDebugInfoSize(load_all_debug_info);
}
StatsDuration::Duration SymbolFileOnDemand::GetDebugInfoParseTime() {

View File

@@ -224,6 +224,7 @@ llvm::json::Value DebuggerStats::ReportStatistics(
const lldb_private::StatisticsOptions &options) {
const bool summary_only = options.summary_only;
const bool load_all_debug_info = options.load_all_debug_info;
json::Array json_targets;
json::Array json_modules;
@@ -280,7 +281,8 @@ llvm::json::Value DebuggerStats::ReportStatistics(
++debug_index_saved;
module_stat.debug_index_time = sym_file->GetDebugInfoIndexTime().count();
module_stat.debug_parse_time = sym_file->GetDebugInfoParseTime().count();
module_stat.debug_info_size = sym_file->GetDebugInfoSize();
module_stat.debug_info_size =
sym_file->GetDebugInfoSize(load_all_debug_info);
module_stat.symtab_stripped = module->GetObjectFile()->IsStripped();
if (module_stat.symtab_stripped)
++num_stripped_modules;

View File

@@ -117,3 +117,38 @@ class TestStatsAPI(TestBase):
self.assertNotIn("bt", command_stats)
# Verify bt's regex command is not duplicatedly captured.
self.assertNotIn("_regexp-bt", command_stats)
def test_command_stats_force(self):
"""
Test reporting all pssible debug info stats by force loading all debug
info. For example, dwo files
"""
src_dir = self.getSourceDir()
dwo_yaml_path = os.path.join(src_dir, "main.dwo.yaml")
obj_yaml_path = os.path.join(src_dir, "main.o.yaml")
dwo_path = self.getBuildArtifact("main.dwo")
obj_path = self.getBuildArtifact("main.o")
self.yaml2obj(dwo_yaml_path, dwo_path)
self.yaml2obj(obj_yaml_path, obj_path)
# We need the current working directory to be set to the build directory
os.chdir(self.getBuildDir())
# Create a target with the object file we just created from YAML
target = self.dbg.CreateTarget(obj_path)
self.assertTrue(target, VALID_TARGET)
# Get statistics
stats_options = lldb.SBStatisticsOptions()
stats = target.GetStatistics(stats_options)
stream = lldb.SBStream()
stats.GetAsJSON(stream)
debug_stats = json.loads(stream.GetData())
self.assertEqual(debug_stats["totalDebugInfoByteSize"], 188)
# Get statistics with force loading
stats_options.SetReportAllAvailableDebugInfo(True)
stats_force = target.GetStatistics(stats_options)
stream_force = lldb.SBStream()
stats_force.GetAsJSON(stream_force)
debug_stats_force = json.loads(stream_force.GetData())
self.assertEqual(debug_stats_force["totalDebugInfoByteSize"], 435)

View File

@@ -0,0 +1,37 @@
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_REL
Machine: EM_X86_64
SectionHeaderStringTable: .strtab
Sections:
- Name: .debug_str.dwo
Type: SHT_PROGBITS
Flags: [ SHF_EXCLUDE, SHF_MERGE, SHF_STRINGS ]
AddressAlign: 0x1
EntSize: 0x1
Content: 5F5A33666F6F7600666F6F006D61696E00696E7400636C616E672076657273696F6E2031372E302E36202843656E744F532031372E302E362D342E656C3929006D61696E2E637070006D61696E2E64776F00
- Name: .debug_str_offsets.dwo
Type: SHT_PROGBITS
Flags: [ SHF_EXCLUDE ]
AddressAlign: 0x1
Content: 00000000080000000C00000011000000150000004000000049000000
- Name: .debug_info.dwo
Type: SHT_PROGBITS
Flags: [ SHF_EXCLUDE ]
AddressAlign: 0x1
Content: 3500000004000000000008010421000506939F5FCB7816797B02000600000001560001010103011C0000000156020105340000000403050400
- Name: .debug_abbrev.dwo
Type: SHT_PROGBITS
Flags: [ SHF_EXCLUDE ]
AddressAlign: 0x1
Content: 01110125823E130503823EB042823EB142070000022E0011813E120640186E823E03823E3A0B3B0B3F190000032E0011813E1206401803823E3A0B3B0B49133F19000004240003823E3E0B0B0B000000
- Type: SectionHeaderTable
Sections:
- Name: .strtab
- Name: .debug_str.dwo
- Name: .debug_str_offsets.dwo
- Name: .debug_info.dwo
- Name: .debug_abbrev.dwo
...

View File

@@ -0,0 +1,212 @@
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_REL
Machine: EM_X86_64
SectionHeaderStringTable: .strtab
Sections:
- Name: .text
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
AddressAlign: 0x10
Content: 554889E55DC3662E0F1F840000000000554889E54883EC10C745FC00000000E80000000031C04883C4105DC3
- Name: .debug_abbrev
Type: SHT_PROGBITS
AddressAlign: 0x1
Content: 01110010171B0EB44219B0420EB1420711011206B34217000000
- Name: .debug_info
Type: SHT_PROGBITS
AddressAlign: 0x1
Content: 2C0000000400000000000801000000000000000000000000939F5FCB7816797B00000000000000002C00000000000000
- Name: .debug_addr
Type: SHT_PROGBITS
AddressAlign: 0x1
Content: '00000000000000000000000000000000'
- Name: .debug_gnu_pubnames
Type: SHT_PROGBITS
AddressAlign: 0x1
Content: 21000000020000000000300000001900000030666F6F0025000000306D61696E0000000000
- Name: .debug_gnu_pubtypes
Type: SHT_PROGBITS
AddressAlign: 0x1
Content: '17000000020000000000300000003400000090696E740000000000'
- Name: .comment
Type: SHT_PROGBITS
Flags: [ SHF_MERGE, SHF_STRINGS ]
AddressAlign: 0x1
EntSize: 0x1
Content: 00636C616E672076657273696F6E2031372E302E36202843656E744F532031372E302E362D342E656C392900
- Name: .note.GNU-stack
Type: SHT_PROGBITS
AddressAlign: 0x1
- Name: .eh_frame
Type: SHT_X86_64_UNWIND
Flags: [ SHF_ALLOC ]
AddressAlign: 0x8
Content: 1400000000000000017A5200017810011B0C0708900100001C0000001C000000000000000600000000410E108602430D06410C07080000001C0000003C000000000000001C00000000410E108602430D06570C0708000000
- Name: .debug_line
Type: SHT_PROGBITS
AddressAlign: 0x1
Content: 47000000040020000000010101FB0E0D000101010100000001000001006D61696E2E637070000000000000090200000000000000000105050A0B4B0500BD05050AE559060B2E0206000101
- Name: .rela.text
Type: SHT_RELA
Flags: [ SHF_INFO_LINK ]
Link: .symtab
AddressAlign: 0x8
Info: .text
Relocations:
- Offset: 0x20
Symbol: _Z3foov
Type: R_X86_64_PLT32
Addend: -4
- Name: .rela.debug_info
Type: SHT_RELA
Flags: [ SHF_INFO_LINK ]
Link: .symtab
AddressAlign: 0x8
Info: .debug_info
Relocations:
- Offset: 0x6
Symbol: .debug_abbrev
Type: R_X86_64_32
- Offset: 0xC
Symbol: .debug_line
Type: R_X86_64_32
- Offset: 0x10
Symbol: .debug_str
Type: R_X86_64_32
- Offset: 0x14
Symbol: .debug_str
Type: R_X86_64_32
Addend: 14
- Offset: 0x20
Symbol: .text
Type: R_X86_64_64
- Offset: 0x2C
Symbol: .debug_addr
Type: R_X86_64_32
- Name: .rela.debug_addr
Type: SHT_RELA
Flags: [ SHF_INFO_LINK ]
Link: .symtab
AddressAlign: 0x8
Info: .debug_addr
Relocations:
- Symbol: .text
Type: R_X86_64_64
- Offset: 0x8
Symbol: .text
Type: R_X86_64_64
Addend: 16
- Name: .rela.debug_gnu_pubnames
Type: SHT_RELA
Flags: [ SHF_INFO_LINK ]
Link: .symtab
AddressAlign: 0x8
Info: .debug_gnu_pubnames
Relocations:
- Offset: 0x6
Symbol: .debug_info
Type: R_X86_64_32
- Name: .rela.debug_gnu_pubtypes
Type: SHT_RELA
Flags: [ SHF_INFO_LINK ]
Link: .symtab
AddressAlign: 0x8
Info: .debug_gnu_pubtypes
Relocations:
- Offset: 0x6
Symbol: .debug_info
Type: R_X86_64_32
- Name: .rela.eh_frame
Type: SHT_RELA
Flags: [ SHF_INFO_LINK ]
Link: .symtab
AddressAlign: 0x8
Info: .eh_frame
Relocations:
- Offset: 0x20
Symbol: .text
Type: R_X86_64_PC32
- Offset: 0x40
Symbol: .text
Type: R_X86_64_PC32
Addend: 16
- Name: .rela.debug_line
Type: SHT_RELA
Flags: [ SHF_INFO_LINK ]
Link: .symtab
AddressAlign: 0x8
Info: .debug_line
Relocations:
- Offset: 0x2D
Symbol: .text
Type: R_X86_64_64
- Name: .llvm_addrsig
Type: SHT_LLVM_ADDRSIG
Flags: [ SHF_EXCLUDE ]
Link: .symtab
AddressAlign: 0x1
Symbols: [ _Z3foov ]
- Type: SectionHeaderTable
Sections:
- Name: .strtab
- Name: .text
- Name: .rela.text
- Name: .debug_abbrev
- Name: .debug_info
- Name: .rela.debug_info
- Name: .debug_str
- Name: .debug_addr
- Name: .rela.debug_addr
- Name: .debug_gnu_pubnames
- Name: .rela.debug_gnu_pubnames
- Name: .debug_gnu_pubtypes
- Name: .rela.debug_gnu_pubtypes
- Name: .comment
- Name: .note.GNU-stack
- Name: .eh_frame
- Name: .rela.eh_frame
- Name: .debug_line
- Name: .rela.debug_line
- Name: .llvm_addrsig
- Name: .symtab
Symbols:
- Name: main.cpp
Type: STT_FILE
Index: SHN_ABS
- Name: .text
Type: STT_SECTION
Section: .text
- Name: .debug_abbrev
Type: STT_SECTION
Section: .debug_abbrev
- Name: .debug_info
Type: STT_SECTION
Section: .debug_info
- Name: .debug_str
Type: STT_SECTION
Section: .debug_str
- Name: .debug_addr
Type: STT_SECTION
Section: .debug_addr
- Name: .debug_line
Type: STT_SECTION
Section: .debug_line
- Name: _Z3foov
Type: STT_FUNC
Section: .text
Binding: STB_GLOBAL
Size: 0x6
- Name: main
Type: STT_FUNC
Section: .text
Binding: STB_GLOBAL
Value: 0x10
Size: 0x1C
DWARF:
debug_str:
- '/tmp/test_dwo'
- main.dwo
...