https://github.com/qxy11 updated https://github.com/llvm/llvm-project/pull/144424
>From 57483ee0f44f8bbed325268e7d1d40b1a0403aa1 Mon Sep 17 00:00:00 2001 From: Janet Yang <qx...@meta.com> Date: Mon, 16 Jun 2025 11:06:24 -0700 Subject: [PATCH 1/6] Add counter for number of DWO files loaded in statistics --- lldb/include/lldb/Symbol/SymbolFile.h | 5 +++ .../Python/lldbsuite/test/builders/builder.py | 25 ++++++++++----- .../Python/lldbsuite/test/make/Makefile.rules | 4 +++ .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 1 + .../SymbolFile/DWARF/SymbolFileDWARF.h | 9 ++++++ .../SymbolFile/DWARF/SymbolFileDWARFDwo.cpp | 2 +- lldb/source/Target/Statistics.cpp | 5 +++ .../commands/statistics/basic/TestStats.py | 31 +++++++++++++++++++ .../API/commands/statistics/basic/baz.cpp | 12 +++++++ .../API/commands/statistics/basic/third.cpp | 7 +++++ 10 files changed, 93 insertions(+), 8 deletions(-) create mode 100644 lldb/test/API/commands/statistics/basic/baz.cpp create mode 100644 lldb/test/API/commands/statistics/basic/third.cpp diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h index 75c7f230ddf3d..42fbc2508889a 100644 --- a/lldb/include/lldb/Symbol/SymbolFile.h +++ b/lldb/include/lldb/Symbol/SymbolFile.h @@ -425,6 +425,11 @@ class SymbolFile : public PluginInterface { /// Reset the statistics for the symbol file. virtual void ResetStatistics() {} + /// Get the number of loaded DWO files for this symbol file. + /// This is used for statistics gathering and will return 0 for most + /// symbol file implementations except DWARF symbol files. + virtual uint32_t GetLoadedDwoFileCount() const { return 0; } + /// Get the additional modules that this symbol file uses to parse debug info. /// /// Some debug info is stored in stand alone object files that are represented diff --git a/lldb/packages/Python/lldbsuite/test/builders/builder.py b/lldb/packages/Python/lldbsuite/test/builders/builder.py index de05732469448..572abf590345c 100644 --- a/lldb/packages/Python/lldbsuite/test/builders/builder.py +++ b/lldb/packages/Python/lldbsuite/test/builders/builder.py @@ -247,13 +247,24 @@ def getLLDBObjRoot(self): def _getDebugInfoArgs(self, debug_info): if debug_info is None: return [] - if debug_info == "dwarf": - return ["MAKE_DSYM=NO"] - if debug_info == "dwo": - return ["MAKE_DSYM=NO", "MAKE_DWO=YES"] - if debug_info == "gmodules": - return ["MAKE_DSYM=NO", "MAKE_GMODULES=YES"] - return None + + debug_options = debug_info if isinstance(debug_info, list) else [debug_info] + option_flags = { + "dwarf": {"MAKE_DSYM": "NO"}, + "dwo": {"MAKE_DSYM": "NO", "MAKE_DWO": "YES"}, + "gmodules": {"MAKE_DSYM": "NO", "MAKE_GMODULES": "YES"}, + "debug_names": {"MAKE_DEBUG_NAMES": "YES"}, + } + + # Collect all flags, with later options overriding earlier ones + flags = {} + + for option in debug_options: + if not option or option not in option_flags: + return None # Invalid options + flags.update(option_flags[option]) + + return [f"{key}={value}" for key, value in flags.items()] def getBuildCommand( self, diff --git a/lldb/packages/Python/lldbsuite/test/make/Makefile.rules b/lldb/packages/Python/lldbsuite/test/make/Makefile.rules index 06959f226066a..58833e1b0cc78 100644 --- a/lldb/packages/Python/lldbsuite/test/make/Makefile.rules +++ b/lldb/packages/Python/lldbsuite/test/make/Makefile.rules @@ -276,6 +276,10 @@ ifeq "$(MAKE_DWO)" "YES" CFLAGS += -gsplit-dwarf endif +ifeq "$(MAKE_DEBUG_NAMES)" "YES" + CFLAGS += -gpubnames +endif + ifeq "$(USE_PRIVATE_MODULE_CACHE)" "YES" THE_CLANG_MODULE_CACHE_DIR := $(BUILDDIR)/private-module-cache else diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 71f204c03a42a..acd9d2230c201 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -4358,6 +4358,7 @@ StatsDuration::Duration SymbolFileDWARF::GetDebugInfoIndexTime() { void SymbolFileDWARF::ResetStatistics() { m_parse_time.reset(); + m_loaded_dwo_file_count = 0; if (m_index) return m_index->ResetStatistics(); } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index d2d30d7decb16..d695961bbfc1d 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -315,6 +315,11 @@ class SymbolFileDWARF : public SymbolFileCommon { void ResetStatistics() override; + /// Get the number of loaded DWO files for this symbol file + uint32_t GetLoadedDwoFileCount() const override { + return m_loaded_dwo_file_count; + } + virtual lldb::offset_t GetVendorDWARFOpcodeSize(const DataExtractor &data, const lldb::offset_t data_offset, @@ -497,6 +502,8 @@ class SymbolFileDWARF : public SymbolFileCommon { void InitializeFirstCodeAddress(); + void IncrementLoadedDwoFileCount() { m_loaded_dwo_file_count++; } + void GetCompileOptions(std::unordered_map<lldb::CompUnitSP, Args> &args) override; @@ -550,6 +557,8 @@ class SymbolFileDWARF : public SymbolFileCommon { /// valid value that can be used in DIERef objects which will contain /// an index that identifies the .DWO or .o file. std::optional<uint64_t> m_file_index; + /// Count of loaded DWO files for this symbol file + uint32_t m_loaded_dwo_file_count = 0; }; } // namespace dwarf } // namespace lldb_private::plugin diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp index c1829abe72933..1f0e847da2905 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp @@ -31,7 +31,7 @@ SymbolFileDWARFDwo::SymbolFileDWARFDwo(SymbolFileDWARF &base_symbol_file, /*update_module_section_list*/ false)), m_base_symbol_file(base_symbol_file) { SetFileIndex(id); - + m_base_symbol_file.IncrementLoadedDwoFileCount(); // Parsing of the dwarf unit index is not thread-safe, so we need to prime it // to enable subsequent concurrent lookups. m_context.GetAsLLVM().getCUIndex(); diff --git a/lldb/source/Target/Statistics.cpp b/lldb/source/Target/Statistics.cpp index 6ec8f8963baf9..b30d7f755f2fc 100644 --- a/lldb/source/Target/Statistics.cpp +++ b/lldb/source/Target/Statistics.cpp @@ -322,6 +322,7 @@ llvm::json::Value DebuggerStats::ReportStatistics( uint32_t num_modules_with_incomplete_types = 0; uint32_t num_stripped_modules = 0; uint32_t symtab_symbol_count = 0; + uint32_t total_loaded_dwo_file_count = 0; for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) { Module *module = target != nullptr ? target->GetImages().GetModuleAtIndex(image_idx).get() @@ -353,6 +354,9 @@ llvm::json::Value DebuggerStats::ReportStatistics( for (const auto &symbol_module : symbol_modules.Modules()) module_stat.symfile_modules.push_back((intptr_t)symbol_module.get()); } + // Add DWO file count from this symbol file (will be 0 for non-DWARF + // symbol files) + total_loaded_dwo_file_count += sym_file->GetLoadedDwoFileCount(); module_stat.debug_info_index_loaded_from_cache = sym_file->GetDebugInfoIndexWasLoadedFromCache(); if (module_stat.debug_info_index_loaded_from_cache) @@ -427,6 +431,7 @@ llvm::json::Value DebuggerStats::ReportStatistics( {"totalDebugInfoEnabled", num_debug_info_enabled_modules}, {"totalSymbolTableStripped", num_stripped_modules}, {"totalSymbolTableSymbolCount", symtab_symbol_count}, + {"totalLoadedDwoFileCount", total_loaded_dwo_file_count}, }; if (include_targets) { diff --git a/lldb/test/API/commands/statistics/basic/TestStats.py b/lldb/test/API/commands/statistics/basic/TestStats.py index 83132b40d85db..de4dafaf0a77d 100644 --- a/lldb/test/API/commands/statistics/basic/TestStats.py +++ b/lldb/test/API/commands/statistics/basic/TestStats.py @@ -177,6 +177,7 @@ def test_default_no_run(self): "totalDebugInfoIndexLoadedFromCache", "totalDebugInfoIndexSavedToCache", "totalDebugInfoParseTime", + "totalLoadedDwoFileCount", ] self.verify_keys(debug_stats, '"debug_stats"', debug_stat_keys, None) if self.getPlatform() != "windows": @@ -287,6 +288,7 @@ def test_default_with_run(self): "totalDebugInfoIndexLoadedFromCache", "totalDebugInfoIndexSavedToCache", "totalDebugInfoParseTime", + "totalLoadedDwoFileCount", ] self.verify_keys(debug_stats, '"debug_stats"', debug_stat_keys, None) stats = debug_stats["targets"][0] @@ -325,6 +327,7 @@ def test_memory(self): "totalDebugInfoIndexLoadedFromCache", "totalDebugInfoIndexSavedToCache", "totalDebugInfoByteSize", + "totalLoadedDwoFileCount", ] self.verify_keys(debug_stats, '"debug_stats"', debug_stat_keys, None) @@ -377,6 +380,7 @@ def test_modules(self): "totalDebugInfoIndexLoadedFromCache", "totalDebugInfoIndexSavedToCache", "totalDebugInfoByteSize", + "totalLoadedDwoFileCount", ] self.verify_keys(debug_stats, '"debug_stats"', debug_stat_keys, None) stats = debug_stats["targets"][0] @@ -485,6 +489,7 @@ def test_breakpoints(self): "totalDebugInfoIndexLoadedFromCache", "totalDebugInfoIndexSavedToCache", "totalDebugInfoByteSize", + "totalLoadedDwoFileCount", ] self.verify_keys(debug_stats, '"debug_stats"', debug_stat_keys, None) target_stats = debug_stats["targets"][0] @@ -512,6 +517,32 @@ def test_breakpoints(self): self.verify_keys( breakpoint, 'target_stats["breakpoints"]', bp_keys_exist, None ) + + def test_loaded_dwo_file_count(self): + """ + Test "statistics dump" and the loaded dwo file count. + Builds a binary w/ separate .dwo files and debug_names, and then + verifies the loaded dwo file count is the expected count after running + various commands + """ + da = {"CXX_SOURCES": "third.cpp baz.cpp", "EXE": self.getBuildArtifact("a.out")} + self.build(dictionary=da, debug_info=["dwo", "debug_names"]) + self.addTearDownCleanup(dictionary=da) + exe = self.getBuildArtifact("a.out") + target = self.createTestTarget(file_path=exe) + debug_stats = self.get_stats() + + self.assertIn("totalLoadedDwoFileCount", debug_stats) + self.assertEqual(debug_stats["totalLoadedDwoFileCount"], 0) + + self.runCmd("b main") + debug_stats_after_main = self.get_stats() + self.assertEqual(debug_stats_after_main["totalLoadedDwoFileCount"], 1) + + self.runCmd("type lookup Baz") + debug_stats_after_type_lookup = self.get_stats() + self.assertEqual(debug_stats_after_type_lookup["totalLoadedDwoFileCount"], 2) + @skipUnlessDarwin @no_debug_info_test diff --git a/lldb/test/API/commands/statistics/basic/baz.cpp b/lldb/test/API/commands/statistics/basic/baz.cpp new file mode 100644 index 0000000000000..536758b17d839 --- /dev/null +++ b/lldb/test/API/commands/statistics/basic/baz.cpp @@ -0,0 +1,12 @@ +// Helper that the lldb command `statistics dump` works in split-dwarf mode. + +struct Baz { + int x; + bool y; +}; + +void baz() { + Baz b; + b.x = 1; + b.y = true; +} diff --git a/lldb/test/API/commands/statistics/basic/third.cpp b/lldb/test/API/commands/statistics/basic/third.cpp new file mode 100644 index 0000000000000..3943b9c2faafe --- /dev/null +++ b/lldb/test/API/commands/statistics/basic/third.cpp @@ -0,0 +1,7 @@ +// Test that the lldb command `statistics dump` works. + +void baz(); +int main(void) { + baz(); + return 0; +} >From 3292b8965ab59bf4e42767d350868898a96cd66b Mon Sep 17 00:00:00 2001 From: Janet Yang <qx...@meta.com> Date: Tue, 17 Jun 2025 08:09:19 -0700 Subject: [PATCH 2/6] Use GetSeparateDebugInfo and add totalLoadedDwoFileCount Address comments to use `GetSeparateDebugInfo` instead of adding a new Symbol File function. Also add a totalLoadedDwoFileCount to statistics dump and add some unit tests for expected behavior in the DWP case and non-split-dwarf cases. --- lldb/include/lldb/Symbol/SymbolFile.h | 11 ++- lldb/include/lldb/Symbol/SymbolFileOnDemand.h | 7 +- .../Python/lldbsuite/test/builders/builder.py | 1 + .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 6 +- .../SymbolFile/DWARF/SymbolFileDWARF.h | 13 +-- .../DWARF/SymbolFileDWARFDebugMap.cpp | 3 +- .../DWARF/SymbolFileDWARFDebugMap.h | 4 +- .../SymbolFile/DWARF/SymbolFileDWARFDwo.cpp | 2 +- lldb/source/Target/Statistics.cpp | 29 ++++++- .../commands/statistics/basic/TestStats.py | 82 +++++++++++++++++-- 10 files changed, 121 insertions(+), 37 deletions(-) diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h index 42fbc2508889a..55af626a6ed96 100644 --- a/lldb/include/lldb/Symbol/SymbolFile.h +++ b/lldb/include/lldb/Symbol/SymbolFile.h @@ -425,11 +425,6 @@ class SymbolFile : public PluginInterface { /// Reset the statistics for the symbol file. virtual void ResetStatistics() {} - /// Get the number of loaded DWO files for this symbol file. - /// This is used for statistics gathering and will return 0 for most - /// symbol file implementations except DWARF symbol files. - virtual uint32_t GetLoadedDwoFileCount() const { return 0; } - /// Get the additional modules that this symbol file uses to parse debug info. /// /// Some debug info is stored in stand alone object files that are represented @@ -472,8 +467,12 @@ 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 and + /// add its info to the debug info files. Default to true. virtual bool GetSeparateDebugInfo(StructuredData::Dictionary &d, - bool errors_only) { + bool errors_only, + bool load_all_debug_info = true) { return false; }; diff --git a/lldb/include/lldb/Symbol/SymbolFileOnDemand.h b/lldb/include/lldb/Symbol/SymbolFileOnDemand.h index ba4a7f09afeaa..137e29e1e7a8d 100644 --- a/lldb/include/lldb/Symbol/SymbolFileOnDemand.h +++ b/lldb/include/lldb/Symbol/SymbolFileOnDemand.h @@ -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 = true) override { + return m_sym_file_impl->GetSeparateDebugInfo(d, errors_only, + load_all_debug_info); } lldb::TypeSP MakeType(lldb::user_id_t uid, ConstString name, diff --git a/lldb/packages/Python/lldbsuite/test/builders/builder.py b/lldb/packages/Python/lldbsuite/test/builders/builder.py index 572abf590345c..efb1ba568e3e6 100644 --- a/lldb/packages/Python/lldbsuite/test/builders/builder.py +++ b/lldb/packages/Python/lldbsuite/test/builders/builder.py @@ -254,6 +254,7 @@ def _getDebugInfoArgs(self, debug_info): "dwo": {"MAKE_DSYM": "NO", "MAKE_DWO": "YES"}, "gmodules": {"MAKE_DSYM": "NO", "MAKE_GMODULES": "YES"}, "debug_names": {"MAKE_DEBUG_NAMES": "YES"}, + "dwp": {"MAKE_DSYM": "NO", "MAKE_DWP": "YES"}, } # Collect all flags, with later options overriding earlier ones diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index acd9d2230c201..7aee91d541e37 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -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", @@ -4358,7 +4359,6 @@ StatsDuration::Duration SymbolFileDWARF::GetDebugInfoIndexTime() { void SymbolFileDWARF::ResetStatistics() { m_parse_time.reset(); - m_loaded_dwo_file_count = 0; if (m_index) return m_index->ResetStatistics(); } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index d695961bbfc1d..5f0275be91c34 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -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 = true) override; DWARFContext &GetDWARFContext() { return m_context; } @@ -315,11 +315,6 @@ class SymbolFileDWARF : public SymbolFileCommon { void ResetStatistics() override; - /// Get the number of loaded DWO files for this symbol file - uint32_t GetLoadedDwoFileCount() const override { - return m_loaded_dwo_file_count; - } - virtual lldb::offset_t GetVendorDWARFOpcodeSize(const DataExtractor &data, const lldb::offset_t data_offset, @@ -502,8 +497,6 @@ class SymbolFileDWARF : public SymbolFileCommon { void InitializeFirstCodeAddress(); - void IncrementLoadedDwoFileCount() { m_loaded_dwo_file_count++; } - void GetCompileOptions(std::unordered_map<lldb::CompUnitSP, Args> &args) override; @@ -557,8 +550,6 @@ class SymbolFileDWARF : public SymbolFileCommon { /// valid value that can be used in DIERef objects which will contain /// an index that identifies the .DWO or .o file. std::optional<uint64_t> m_file_index; - /// Count of loaded DWO files for this symbol file - uint32_t m_loaded_dwo_file_count = 0; }; } // namespace dwarf } // namespace lldb_private::plugin diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp index f3a940b2ee396..dd94f0b36f2b2 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -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) { diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h index 35cbdbbb1692f..64c0e415f8bce 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -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 = true) override; // PluginInterface protocol llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp index 1f0e847da2905..c1829abe72933 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp @@ -31,7 +31,7 @@ SymbolFileDWARFDwo::SymbolFileDWARFDwo(SymbolFileDWARF &base_symbol_file, /*update_module_section_list*/ false)), m_base_symbol_file(base_symbol_file) { SetFileIndex(id); - m_base_symbol_file.IncrementLoadedDwoFileCount(); + // Parsing of the dwarf unit index is not thread-safe, so we need to prime it // to enable subsequent concurrent lookups. m_context.GetAsLLVM().getCUIndex(); diff --git a/lldb/source/Target/Statistics.cpp b/lldb/source/Target/Statistics.cpp index b30d7f755f2fc..5e0680794dbb0 100644 --- a/lldb/source/Target/Statistics.cpp +++ b/lldb/source/Target/Statistics.cpp @@ -323,6 +323,7 @@ llvm::json::Value DebuggerStats::ReportStatistics( uint32_t num_stripped_modules = 0; uint32_t symtab_symbol_count = 0; uint32_t total_loaded_dwo_file_count = 0; + uint32_t total_dwo_file_count = 0; for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) { Module *module = target != nullptr ? target->GetImages().GetModuleAtIndex(image_idx).get() @@ -354,9 +355,30 @@ llvm::json::Value DebuggerStats::ReportStatistics( for (const auto &symbol_module : symbol_modules.Modules()) module_stat.symfile_modules.push_back((intptr_t)symbol_module.get()); } - // Add DWO file count from this symbol file (will be 0 for non-DWARF - // symbol files) - total_loaded_dwo_file_count += sym_file->GetLoadedDwoFileCount(); + // Count DWO files from this symbol file using GetSeparateDebugInfo + StructuredData::Dictionary separate_debug_info; + if (sym_file->GetSeparateDebugInfo(separate_debug_info, + /*errors_only=*/false, + /*load_all_debug_info*/ false)) { + llvm::StringRef type; + if (separate_debug_info.GetValueForKeyAsString("type", type) && + type == "dwo") { + StructuredData::Array *files; + if (separate_debug_info.GetValueForKeyAsArray( + "separate-debug-info-files", files)) { + files->ForEach([&](StructuredData::Object *obj) { + if (auto dict = obj->GetAsDictionary()) { + total_dwo_file_count++; + + bool loaded = false; + if (dict->GetValueForKeyAsBoolean("loaded", loaded) && loaded) + total_loaded_dwo_file_count++; + } + return true; + }); + } + } + } module_stat.debug_info_index_loaded_from_cache = sym_file->GetDebugInfoIndexWasLoadedFromCache(); if (module_stat.debug_info_index_loaded_from_cache) @@ -432,6 +454,7 @@ llvm::json::Value DebuggerStats::ReportStatistics( {"totalSymbolTableStripped", num_stripped_modules}, {"totalSymbolTableSymbolCount", symtab_symbol_count}, {"totalLoadedDwoFileCount", total_loaded_dwo_file_count}, + {"totalDwoFileCount", total_dwo_file_count}, }; if (include_targets) { diff --git a/lldb/test/API/commands/statistics/basic/TestStats.py b/lldb/test/API/commands/statistics/basic/TestStats.py index de4dafaf0a77d..1c891a5f78728 100644 --- a/lldb/test/API/commands/statistics/basic/TestStats.py +++ b/lldb/test/API/commands/statistics/basic/TestStats.py @@ -177,6 +177,7 @@ def test_default_no_run(self): "totalDebugInfoIndexLoadedFromCache", "totalDebugInfoIndexSavedToCache", "totalDebugInfoParseTime", + "totalDwoFileCount", "totalLoadedDwoFileCount", ] self.verify_keys(debug_stats, '"debug_stats"', debug_stat_keys, None) @@ -288,6 +289,7 @@ def test_default_with_run(self): "totalDebugInfoIndexLoadedFromCache", "totalDebugInfoIndexSavedToCache", "totalDebugInfoParseTime", + "totalDwoFileCount", "totalLoadedDwoFileCount", ] self.verify_keys(debug_stats, '"debug_stats"', debug_stat_keys, None) @@ -327,6 +329,7 @@ def test_memory(self): "totalDebugInfoIndexLoadedFromCache", "totalDebugInfoIndexSavedToCache", "totalDebugInfoByteSize", + "totalDwoFileCount", "totalLoadedDwoFileCount", ] self.verify_keys(debug_stats, '"debug_stats"', debug_stat_keys, None) @@ -380,6 +383,7 @@ def test_modules(self): "totalDebugInfoIndexLoadedFromCache", "totalDebugInfoIndexSavedToCache", "totalDebugInfoByteSize", + "totalDwoFileCount", "totalLoadedDwoFileCount", ] self.verify_keys(debug_stats, '"debug_stats"', debug_stat_keys, None) @@ -489,6 +493,7 @@ def test_breakpoints(self): "totalDebugInfoIndexLoadedFromCache", "totalDebugInfoIndexSavedToCache", "totalDebugInfoByteSize", + "totalDwoFileCount", "totalLoadedDwoFileCount", ] self.verify_keys(debug_stats, '"debug_stats"', debug_stat_keys, None) @@ -517,14 +522,35 @@ def test_breakpoints(self): self.verify_keys( breakpoint, 'target_stats["breakpoints"]', bp_keys_exist, None ) - - def test_loaded_dwo_file_count(self): + def test_non_split_dwarf_has_no_dwo_files(self): """ - Test "statistics dump" and the loaded dwo file count. + Test "statistics dump" and the dwo file count. + Builds a binary without split-dwarf mode, and then + verifies the dwo file count is zero after running "statistics dump" + """ + da = {"CXX_SOURCES": "third.cpp baz.cpp", "EXE": self.getBuildArtifact("a.out")} + self.build(dictionary=da, debug_info=["debug_names"]) + self.addTearDownCleanup(dictionary=da) + exe = self.getBuildArtifact("a.out") + target = self.createTestTarget(file_path=exe) + debug_stats = self.get_stats() + self.assertIn("totalDwoFileCount", debug_stats) + self.assertIn("totalLoadedDwoFileCount", debug_stats) + + # Verify that the dwo file count is zero + self.assertEqual(debug_stats["totalDwoFileCount"], 0) + self.assertEqual(debug_stats["totalLoadedDwoFileCount"], 0) + + def test_split_dwarf_dwo_file_count(self): + """ + Test "statistics dump" and the dwo file count. Builds a binary w/ separate .dwo files and debug_names, and then verifies the loaded dwo file count is the expected count after running various commands """ + # Build with split DWARF: -gsplit-dwarf creates separate .dwo files, + # -gpubnames enables accelerator tables for faster symbol lookup + # Expected output: third.dwo (contains main) and baz.dwo (contains Baz struct/function) da = {"CXX_SOURCES": "third.cpp baz.cpp", "EXE": self.getBuildArtifact("a.out")} self.build(dictionary=da, debug_info=["dwo", "debug_names"]) self.addTearDownCleanup(dictionary=da) @@ -532,16 +558,58 @@ def test_loaded_dwo_file_count(self): target = self.createTestTarget(file_path=exe) debug_stats = self.get_stats() + # Initially: 2 DWO files available but none loaded yet self.assertIn("totalLoadedDwoFileCount", debug_stats) + self.assertIn("totalDwoFileCount", debug_stats) self.assertEqual(debug_stats["totalLoadedDwoFileCount"], 0) + self.assertEqual(debug_stats["totalDwoFileCount"], 2) + # Setting breakpoint in main triggers loading of third.dwo (contains main function) self.runCmd("b main") - debug_stats_after_main = self.get_stats() - self.assertEqual(debug_stats_after_main["totalLoadedDwoFileCount"], 1) + debug_stats = self.get_stats() + self.assertEqual(debug_stats["totalLoadedDwoFileCount"], 1) + self.assertEqual(debug_stats["totalDwoFileCount"], 2) + # Type lookup forces loading of baz.dwo (contains struct Baz definition) self.runCmd("type lookup Baz") - debug_stats_after_type_lookup = self.get_stats() - self.assertEqual(debug_stats_after_type_lookup["totalLoadedDwoFileCount"], 2) + debug_stats = self.get_stats() + self.assertEqual(debug_stats["totalLoadedDwoFileCount"], 2) + self.assertEqual(debug_stats["totalDwoFileCount"], 2) + + def test_dwp_dwo_file_count(self): + """ + Test "statistics dump" and the loaded dwo file count. + Builds a binary w/ a separate .dwp file and debug_names, and then + verifies the loaded dwo file count is the expected count after running + various commands. + + We expect the DWO file counters to reflect the number of compile units + loaded from the DWP file (each representing what was originally a separate DWO file) + """ + da = {"CXX_SOURCES": "third.cpp baz.cpp", "EXE": self.getBuildArtifact("a.out")} + self.build(dictionary=da, debug_info=["dwp", "debug_names"]) + self.addTearDownCleanup(dictionary=da) + exe = self.getBuildArtifact("a.out") + target = self.createTestTarget(file_path=exe) + debug_stats = self.get_stats() + + # Initially: 2 DWO files available but none loaded yet + self.assertIn("totalLoadedDwoFileCount", debug_stats) + self.assertIn("totalDwoFileCount", debug_stats) + self.assertEqual(debug_stats["totalLoadedDwoFileCount"], 0) + self.assertEqual(debug_stats["totalDwoFileCount"], 2) + + # Setting breakpoint in main triggers parsing of the CU within a.dwp corresponding to third.dwo (contains main function) + self.runCmd("b main") + debug_stats = self.get_stats() + self.assertEqual(debug_stats["totalLoadedDwoFileCount"], 1) + self.assertEqual(debug_stats["totalDwoFileCount"], 2) + + # Type lookup forces parsing of the CU within a.dwp corresponding to baz.dwo (contains struct Baz definition) + self.runCmd("type lookup Baz") + debug_stats = self.get_stats() + self.assertEqual(debug_stats["totalDwoFileCount"], 2) + self.assertEqual(debug_stats["totalLoadedDwoFileCount"], 2) @skipUnlessDarwin >From a90294dd182c9a118b86684315b81e66be0f0bcb Mon Sep 17 00:00:00 2001 From: Janet Yang <qx...@meta.com> Date: Tue, 17 Jun 2025 12:46:52 -0700 Subject: [PATCH 3/6] Put file counting logic in UpdateDwoFileCounts and add test_debug_names_eager_loads_dwo_files Adds an extra unit test and refactors some logic into a helper function. Also added additional comments in code and tests to clarify purpose of debug_names usage and how it prevents the eager loading of DWO files --- lldb/source/Target/Statistics.cpp | 57 +++++++++++-------- .../commands/statistics/basic/TestStats.py | 30 +++++++++- 2 files changed, 60 insertions(+), 27 deletions(-) diff --git a/lldb/source/Target/Statistics.cpp b/lldb/source/Target/Statistics.cpp index 5e0680794dbb0..e4975c6cedb6e 100644 --- a/lldb/source/Target/Statistics.cpp +++ b/lldb/source/Target/Statistics.cpp @@ -33,6 +33,37 @@ static void EmplaceSafeString(llvm::json::Object &obj, llvm::StringRef key, obj.try_emplace(key, llvm::json::fixUTF8(str)); } +static void UpdateDwoFileCounts(SymbolFile *sym_file, + uint32_t &total_dwo_file_count, + uint32_t &total_loaded_dwo_file_count) { + // Count DWO files from this symbol file using GetSeparateDebugInfo + // For DWP files, this increments counts for both total and successfully + // loaded DWO CUs. For non split-dwarf files, these counts should not change + StructuredData::Dictionary separate_debug_info; + if (sym_file->GetSeparateDebugInfo(separate_debug_info, + /*errors_only=*/false, + /*load_all_debug_info*/ false)) { + llvm::StringRef type; + if (separate_debug_info.GetValueForKeyAsString("type", type) && + type == "dwo") { + StructuredData::Array *files; + if (separate_debug_info.GetValueForKeyAsArray("separate-debug-info-files", + files)) { + files->ForEach([&](StructuredData::Object *obj) { + if (auto dict = obj->GetAsDictionary()) { + total_dwo_file_count++; + + bool loaded = false; + if (dict->GetValueForKeyAsBoolean("loaded", loaded) && loaded) + total_loaded_dwo_file_count++; + } + return true; + }); + } + } + } +} + json::Value StatsSuccessFail::ToJSON() const { return json::Object{{"successes", successes}, {"failures", failures}}; } @@ -355,30 +386,8 @@ llvm::json::Value DebuggerStats::ReportStatistics( for (const auto &symbol_module : symbol_modules.Modules()) module_stat.symfile_modules.push_back((intptr_t)symbol_module.get()); } - // Count DWO files from this symbol file using GetSeparateDebugInfo - StructuredData::Dictionary separate_debug_info; - if (sym_file->GetSeparateDebugInfo(separate_debug_info, - /*errors_only=*/false, - /*load_all_debug_info*/ false)) { - llvm::StringRef type; - if (separate_debug_info.GetValueForKeyAsString("type", type) && - type == "dwo") { - StructuredData::Array *files; - if (separate_debug_info.GetValueForKeyAsArray( - "separate-debug-info-files", files)) { - files->ForEach([&](StructuredData::Object *obj) { - if (auto dict = obj->GetAsDictionary()) { - total_dwo_file_count++; - - bool loaded = false; - if (dict->GetValueForKeyAsBoolean("loaded", loaded) && loaded) - total_loaded_dwo_file_count++; - } - return true; - }); - } - } - } + UpdateDwoFileCounts(sym_file, total_dwo_file_count, + total_loaded_dwo_file_count); module_stat.debug_info_index_loaded_from_cache = sym_file->GetDebugInfoIndexWasLoadedFromCache(); if (module_stat.debug_info_index_loaded_from_cache) diff --git a/lldb/test/API/commands/statistics/basic/TestStats.py b/lldb/test/API/commands/statistics/basic/TestStats.py index 1c891a5f78728..685d7fe9ab711 100644 --- a/lldb/test/API/commands/statistics/basic/TestStats.py +++ b/lldb/test/API/commands/statistics/basic/TestStats.py @@ -540,6 +540,29 @@ def test_non_split_dwarf_has_no_dwo_files(self): # Verify that the dwo file count is zero self.assertEqual(debug_stats["totalDwoFileCount"], 0) self.assertEqual(debug_stats["totalLoadedDwoFileCount"], 0) + + def test_debug_names_eager_loads_dwo_files(self): + """ + Test the eager loading behavior of DWO files when debug_names is absent by + building a split-dwarf binary without debug_names and then running "statistics dump". + DWO file loading behavior: + - With debug_names: DebugNamesDWARFIndex allows for lazy loading. + DWO files are loaded on-demand when symbols are actually looked up + - Without debug_names: ManualDWARFIndex uses eager loading. + All DWO files are loaded upfront during the first symbol lookup to build a manual index. + """ + da = {"CXX_SOURCES": "third.cpp baz.cpp", "EXE": self.getBuildArtifact("a.out")} + self.build(dictionary=da, debug_info=["dwo"]) + self.addTearDownCleanup(dictionary=da) + exe = self.getBuildArtifact("a.out") + target = self.createTestTarget(file_path=exe) + debug_stats = self.get_stats() + self.assertIn("totalDwoFileCount", debug_stats) + self.assertIn("totalLoadedDwoFileCount", debug_stats) + + # Verify that all DWO files are loaded + self.assertEqual(debug_stats["totalDwoFileCount"], 2) + self.assertEqual(debug_stats["totalLoadedDwoFileCount"], 2) def test_split_dwarf_dwo_file_count(self): """ @@ -548,10 +571,11 @@ def test_split_dwarf_dwo_file_count(self): verifies the loaded dwo file count is the expected count after running various commands """ - # Build with split DWARF: -gsplit-dwarf creates separate .dwo files, - # -gpubnames enables accelerator tables for faster symbol lookup - # Expected output: third.dwo (contains main) and baz.dwo (contains Baz struct/function) da = {"CXX_SOURCES": "third.cpp baz.cpp", "EXE": self.getBuildArtifact("a.out")} + # -gsplit-dwarf creates separate .dwo files, + # -gpubnames enables the debug_names accelerator tables for faster symbol lookup + # and lazy loading of DWO files + # Expected output: third.dwo (contains main) and baz.dwo (contains Baz struct/function) self.build(dictionary=da, debug_info=["dwo", "debug_names"]) self.addTearDownCleanup(dictionary=da) exe = self.getBuildArtifact("a.out") >From 9b966482264b1c0188d474b013d1db7236da1448 Mon Sep 17 00:00:00 2001 From: Janet Yang <qx...@meta.com> Date: Tue, 17 Jun 2025 17:23:19 -0700 Subject: [PATCH 4/6] Add dwo_file_count and loaded_dwo_file_count to ModuleStats --- lldb/include/lldb/Target/Statistics.h | 2 ++ lldb/source/Target/Statistics.cpp | 12 ++++++---- .../commands/statistics/basic/TestStats.py | 23 +++++++++++++++---- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/lldb/include/lldb/Target/Statistics.h b/lldb/include/lldb/Target/Statistics.h index 2d0d25cd3c753..42f03798c219e 100644 --- a/lldb/include/lldb/Target/Statistics.h +++ b/lldb/include/lldb/Target/Statistics.h @@ -153,6 +153,8 @@ struct ModuleStats { bool symtab_stripped = false; bool debug_info_had_variable_errors = false; bool debug_info_had_incomplete_types = false; + uint32_t dwo_file_count = 0; + uint32_t loaded_dwo_file_count = 0; }; struct ConstStringStats { diff --git a/lldb/source/Target/Statistics.cpp b/lldb/source/Target/Statistics.cpp index e4975c6cedb6e..db14d7e706877 100644 --- a/lldb/source/Target/Statistics.cpp +++ b/lldb/source/Target/Statistics.cpp @@ -42,7 +42,7 @@ static void UpdateDwoFileCounts(SymbolFile *sym_file, StructuredData::Dictionary separate_debug_info; if (sym_file->GetSeparateDebugInfo(separate_debug_info, /*errors_only=*/false, - /*load_all_debug_info*/ false)) { + /*load_all_debug_info=*/false)) { llvm::StringRef type; if (separate_debug_info.GetValueForKeyAsString("type", type) && type == "dwo") { @@ -104,6 +104,8 @@ json::Value ModuleStats::ToJSON() const { debug_info_had_incomplete_types); module.try_emplace("symbolTableStripped", symtab_stripped); module.try_emplace("symbolTableSymbolCount", symtab_symbol_count); + module.try_emplace("dwoFileCount", dwo_file_count); + module.try_emplace("loadedDwoFileCount", loaded_dwo_file_count); if (!symbol_locator_time.map.empty()) { json::Object obj; @@ -117,7 +119,7 @@ json::Value ModuleStats::ToJSON() const { if (!symfile_modules.empty()) { json::Array symfile_ids; - for (const auto symfile_id: symfile_modules) + for (const auto symfile_id : symfile_modules) symfile_ids.emplace_back(symfile_id); module.try_emplace("symbolFileModuleIdentifiers", std::move(symfile_ids)); } @@ -386,8 +388,10 @@ llvm::json::Value DebuggerStats::ReportStatistics( for (const auto &symbol_module : symbol_modules.Modules()) module_stat.symfile_modules.push_back((intptr_t)symbol_module.get()); } - UpdateDwoFileCounts(sym_file, total_dwo_file_count, - total_loaded_dwo_file_count); + UpdateDwoFileCounts(sym_file, module_stat.dwo_file_count, + module_stat.loaded_dwo_file_count); + total_dwo_file_count += module_stat.dwo_file_count; + total_loaded_dwo_file_count += module_stat.loaded_dwo_file_count; module_stat.debug_info_index_loaded_from_cache = sym_file->GetDebugInfoIndexWasLoadedFromCache(); if (module_stat.debug_info_index_loaded_from_cache) diff --git a/lldb/test/API/commands/statistics/basic/TestStats.py b/lldb/test/API/commands/statistics/basic/TestStats.py index 685d7fe9ab711..5281bde4c6479 100644 --- a/lldb/test/API/commands/statistics/basic/TestStats.py +++ b/lldb/test/API/commands/statistics/basic/TestStats.py @@ -405,6 +405,8 @@ def test_modules(self): "symbolTableLoadedFromCache", "symbolTableParseTime", "symbolTableSavedToCache", + "dwoFileCount", + "loadedDwoFileCount", "triple", "uuid", ] @@ -541,7 +543,7 @@ def test_non_split_dwarf_has_no_dwo_files(self): self.assertEqual(debug_stats["totalDwoFileCount"], 0) self.assertEqual(debug_stats["totalLoadedDwoFileCount"], 0) - def test_debug_names_eager_loads_dwo_files(self): + def test_no_debug_names_eager_loads_dwo_files(self): """ Test the eager loading behavior of DWO files when debug_names is absent by building a split-dwarf binary without debug_names and then running "statistics dump". @@ -582,23 +584,36 @@ def test_split_dwarf_dwo_file_count(self): target = self.createTestTarget(file_path=exe) debug_stats = self.get_stats() - # Initially: 2 DWO files available but none loaded yet + # 1) 2 DWO files available but none loaded yet + self.assertEqual(len(debug_stats["modules"]), 1) self.assertIn("totalLoadedDwoFileCount", debug_stats) self.assertIn("totalDwoFileCount", debug_stats) self.assertEqual(debug_stats["totalLoadedDwoFileCount"], 0) self.assertEqual(debug_stats["totalDwoFileCount"], 2) - # Setting breakpoint in main triggers loading of third.dwo (contains main function) + # Since there's only one module, module stats should have the same counts as total counts + self.assertIn("dwoFileCount", debug_stats["modules"][0]) + self.assertIn("loadedDwoFileCount", debug_stats["modules"][0]) + self.assertEqual(debug_stats["modules"][0]["loadedDwoFileCount"], 0) + self.assertEqual(debug_stats["modules"][0]["dwoFileCount"], 2) + + # 2) Setting breakpoint in main triggers loading of third.dwo (contains main function) self.runCmd("b main") debug_stats = self.get_stats() self.assertEqual(debug_stats["totalLoadedDwoFileCount"], 1) self.assertEqual(debug_stats["totalDwoFileCount"], 2) + + self.assertEqual(debug_stats["modules"][0]["loadedDwoFileCount"], 1) + self.assertEqual(debug_stats["modules"][0]["dwoFileCount"], 2) - # Type lookup forces loading of baz.dwo (contains struct Baz definition) + # 3) Type lookup forces loading of baz.dwo (contains struct Baz definition) self.runCmd("type lookup Baz") debug_stats = self.get_stats() self.assertEqual(debug_stats["totalLoadedDwoFileCount"], 2) self.assertEqual(debug_stats["totalDwoFileCount"], 2) + + self.assertEqual(debug_stats["modules"][0]["loadedDwoFileCount"], 2) + self.assertEqual(debug_stats["modules"][0]["dwoFileCount"], 2) def test_dwp_dwo_file_count(self): """ >From d3e89b75a3a3be0d48482b8394224143f69c6aee Mon Sep 17 00:00:00 2001 From: Janet Yang <qx...@meta.com> Date: Wed, 18 Jun 2025 11:16:42 -0700 Subject: [PATCH 5/6] Add a separate GetDwoFileCounts instead of using GetSeparateDebugInfo --- lldb/include/lldb/Symbol/SymbolFile.h | 14 +++++--- lldb/include/lldb/Symbol/SymbolFileOnDemand.h | 7 ++-- .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 34 ++++++++++++++++-- .../SymbolFile/DWARF/SymbolFileDWARF.h | 9 +++-- .../DWARF/SymbolFileDWARFDebugMap.cpp | 3 +- .../DWARF/SymbolFileDWARFDebugMap.h | 4 +-- lldb/source/Target/Statistics.cpp | 35 ++----------------- 7 files changed, 55 insertions(+), 51 deletions(-) diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h index 55af626a6ed96..b0b608d0a5e79 100644 --- a/lldb/include/lldb/Symbol/SymbolFile.h +++ b/lldb/include/lldb/Symbol/SymbolFile.h @@ -467,15 +467,19 @@ 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 and - /// add its info to the debug info files. Default to true. virtual bool GetSeparateDebugInfo(StructuredData::Dictionary &d, - bool errors_only, - bool load_all_debug_info = true) { + bool errors_only) { return false; }; + /// Get number of loaded/parsed DWO files. This is emitted in "statistics + /// dump" + /// + /// \returns + /// A pair containing (loaded_dwo_count, total_dwo_count). If this + /// symbol file doesn't support DWO files, both counts will be 0. + virtual std::pair<uint32_t, uint32_t> GetDwoFileCounts() { return {0, 0}; } + virtual lldb::TypeSP MakeType(lldb::user_id_t uid, ConstString name, std::optional<uint64_t> byte_size, SymbolContextScope *context, diff --git a/lldb/include/lldb/Symbol/SymbolFileOnDemand.h b/lldb/include/lldb/Symbol/SymbolFileOnDemand.h index 137e29e1e7a8d..ba4a7f09afeaa 100644 --- a/lldb/include/lldb/Symbol/SymbolFileOnDemand.h +++ b/lldb/include/lldb/Symbol/SymbolFileOnDemand.h @@ -223,10 +223,9 @@ class SymbolFileOnDemand : public lldb_private::SymbolFile { return m_sym_file_impl->SetDebugInfoHadFrameVariableErrors(); } - bool GetSeparateDebugInfo(StructuredData::Dictionary &d, bool errors_only, - bool load_all_debug_info = true) override { - return m_sym_file_impl->GetSeparateDebugInfo(d, errors_only, - load_all_debug_info); + bool GetSeparateDebugInfo(StructuredData::Dictionary &d, + bool errors_only) override { + return m_sym_file_impl->GetSeparateDebugInfo(d, errors_only); } lldb::TypeSP MakeType(lldb::user_id_t uid, ConstString name, diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 7aee91d541e37..c83779c40a05b 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -4139,8 +4139,7 @@ void SymbolFileDWARF::DumpClangAST(Stream &s, llvm::StringRef filter) { } bool SymbolFileDWARF::GetSeparateDebugInfo(StructuredData::Dictionary &d, - bool errors_only, - bool load_all_debug_info) { + bool errors_only) { StructuredData::Array separate_debug_info_files; DWARFDebugInfo &info = DebugInfo(); const size_t num_cus = info.GetNumUnits(); @@ -4183,7 +4182,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(load_all_debug_info); + SymbolFile *dwo_symfile = dwarf_cu->GetDwoSymbolFile(); if (dwo_symfile) { dwo_data->AddStringItem( "resolved_dwo_path", @@ -4421,3 +4420,32 @@ void SymbolFileDWARF::GetCompileOptions( args.insert({comp_unit, Args(flags)}); } } + +std::pair<uint32_t, uint32_t> SymbolFileDWARF::GetDwoFileCounts() { + uint32_t total_dwo_count = 0; + uint32_t loaded_dwo_count = 0; + + DWARFDebugInfo &info = DebugInfo(); + const size_t num_cus = info.GetNumUnits(); + for (size_t cu_idx = 0; cu_idx < num_cus; cu_idx++) { + DWARFUnit *dwarf_cu = info.GetUnitAtIndex(cu_idx); + if (dwarf_cu == nullptr) + continue; + + // Check if this is a DWO unit by checking if it has a DWO ID. + if (!dwarf_cu->GetDWOId().has_value()) + continue; + + total_dwo_count++; + + // If we have a DWO symbol file, that means we were able to successfully + // load it. + SymbolFile *dwo_symfile = + dwarf_cu->GetDwoSymbolFile(/*load_all_debug_info=*/false); + if (dwo_symfile) { + loaded_dwo_count++; + } + } + + return {loaded_dwo_count, total_dwo_count}; +} diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index 5f0275be91c34..942e0b5990fa4 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -279,8 +279,13 @@ class SymbolFileDWARF : public SymbolFileCommon { void DumpClangAST(Stream &s, llvm::StringRef filter) override; /// List separate dwo files. - bool GetSeparateDebugInfo(StructuredData::Dictionary &d, bool errors_only, - bool load_all_debug_info = true) override; + bool GetSeparateDebugInfo(StructuredData::Dictionary &d, + bool errors_only) override; + + // Gets a pair of loaded and total dwo file counts. + // For DWP files, this reports the counts for successfully loaded DWO CUs + // and total DWO CUs. For non-split-dwarf files, this reports 0 for both. + std::pair<uint32_t, uint32_t> GetDwoFileCounts() override; DWARFContext &GetDWARFContext() { return m_context; } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp index dd94f0b36f2b2..f3a940b2ee396 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -1278,8 +1278,7 @@ void SymbolFileDWARFDebugMap::DumpClangAST(Stream &s, llvm::StringRef filter) { } bool SymbolFileDWARFDebugMap::GetSeparateDebugInfo( - lldb_private::StructuredData::Dictionary &d, bool errors_only, - bool load_all_debug_info) { + lldb_private::StructuredData::Dictionary &d, bool errors_only) { StructuredData::Array separate_debug_info_files; const uint32_t cu_count = GetNumCompileUnits(); for (uint32_t cu_idx = 0; cu_idx < cu_count; ++cu_idx) { diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h index 64c0e415f8bce..35cbdbbb1692f 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -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, - bool load_all_debug_info = true) override; + bool GetSeparateDebugInfo(StructuredData::Dictionary &d, + bool errors_only) override; // PluginInterface protocol llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } diff --git a/lldb/source/Target/Statistics.cpp b/lldb/source/Target/Statistics.cpp index db14d7e706877..909f335687b21 100644 --- a/lldb/source/Target/Statistics.cpp +++ b/lldb/source/Target/Statistics.cpp @@ -33,37 +33,6 @@ static void EmplaceSafeString(llvm::json::Object &obj, llvm::StringRef key, obj.try_emplace(key, llvm::json::fixUTF8(str)); } -static void UpdateDwoFileCounts(SymbolFile *sym_file, - uint32_t &total_dwo_file_count, - uint32_t &total_loaded_dwo_file_count) { - // Count DWO files from this symbol file using GetSeparateDebugInfo - // For DWP files, this increments counts for both total and successfully - // loaded DWO CUs. For non split-dwarf files, these counts should not change - StructuredData::Dictionary separate_debug_info; - if (sym_file->GetSeparateDebugInfo(separate_debug_info, - /*errors_only=*/false, - /*load_all_debug_info=*/false)) { - llvm::StringRef type; - if (separate_debug_info.GetValueForKeyAsString("type", type) && - type == "dwo") { - StructuredData::Array *files; - if (separate_debug_info.GetValueForKeyAsArray("separate-debug-info-files", - files)) { - files->ForEach([&](StructuredData::Object *obj) { - if (auto dict = obj->GetAsDictionary()) { - total_dwo_file_count++; - - bool loaded = false; - if (dict->GetValueForKeyAsBoolean("loaded", loaded) && loaded) - total_loaded_dwo_file_count++; - } - return true; - }); - } - } - } -} - json::Value StatsSuccessFail::ToJSON() const { return json::Object{{"successes", successes}, {"failures", failures}}; } @@ -388,8 +357,8 @@ llvm::json::Value DebuggerStats::ReportStatistics( for (const auto &symbol_module : symbol_modules.Modules()) module_stat.symfile_modules.push_back((intptr_t)symbol_module.get()); } - UpdateDwoFileCounts(sym_file, module_stat.dwo_file_count, - module_stat.loaded_dwo_file_count); + std::tie(module_stat.loaded_dwo_file_count, module_stat.dwo_file_count) = + sym_file->GetDwoFileCounts(); total_dwo_file_count += module_stat.dwo_file_count; total_loaded_dwo_file_count += module_stat.loaded_dwo_file_count; module_stat.debug_info_index_loaded_from_cache = >From ef1c1316b8d20520b0cc549fb256eeecba648605 Mon Sep 17 00:00:00 2001 From: Janet Yang <qx...@meta.com> Date: Wed, 18 Jun 2025 16:14:35 -0700 Subject: [PATCH 6/6] Fix a typo in the comments --- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index 942e0b5990fa4..8335f11712872 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -283,8 +283,8 @@ class SymbolFileDWARF : public SymbolFileCommon { bool errors_only) override; // Gets a pair of loaded and total dwo file counts. - // For DWP files, this reports the counts for successfully loaded DWO CUs - // and total DWO CUs. For non-split-dwarf files, this reports 0 for both. + // For split-dwarf files, this reports the counts for successfully loaded DWO + // CUs and total DWO CUs. For non-split-dwarf files, this reports 0 for both. std::pair<uint32_t, uint32_t> GetDwoFileCounts() override; DWARFContext &GetDWARFContext() { return m_context; } _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits