[Lldb-commits] [lldb] [lldb] Add count for errors of DWO files in statistics and combine DWO file count functions (PR #155023)
Ziyi Wang via lldb-commits
lldb-commits at lists.llvm.org
Thu Aug 28 17:02:38 PDT 2025
https://github.com/zw3917 updated https://github.com/llvm/llvm-project/pull/155023
>From d978cb5b17b7a8450226825a8fd85f2054166059 Mon Sep 17 00:00:00 2001
From: Ziyi Wang <zw3917 at nyu.edu>
Date: Fri, 22 Aug 2025 09:17:25 -0700
Subject: [PATCH 1/4] [lldb] Add count for errors of DWO files in statistics
---
lldb/include/lldb/Symbol/SymbolFile.h | 4 +
lldb/include/lldb/Target/Statistics.h | 1 +
.../SymbolFile/DWARF/SymbolFileDWARF.cpp | 18 +++
.../SymbolFile/DWARF/SymbolFileDWARF.h | 3 +
lldb/source/Target/Statistics.cpp | 5 +
.../commands/statistics/basic/TestStats.py | 115 ++++++++++++++++++
.../statistics/basic/dwo_error_foo.cpp | 10 ++
.../statistics/basic/dwo_error_main.cpp | 5 +
8 files changed, 161 insertions(+)
create mode 100644 lldb/test/API/commands/statistics/basic/dwo_error_foo.cpp
create mode 100644 lldb/test/API/commands/statistics/basic/dwo_error_main.cpp
diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h
index bbc615d9fdc38..7f590fc2e7e64 100644
--- a/lldb/include/lldb/Symbol/SymbolFile.h
+++ b/lldb/include/lldb/Symbol/SymbolFile.h
@@ -496,6 +496,10 @@ class SymbolFile : public PluginInterface {
/// symbol file doesn't support DWO files, both counts will be 0.
virtual std::pair<uint32_t, uint32_t> GetDwoFileCounts() { return {0, 0}; }
+ /// Calculates the count of dwo load error, return the number of dwo file with
+ /// errors, 0 by default.
+ virtual uint32_t CountDwoLoadErrors() { return 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/Target/Statistics.h b/lldb/include/lldb/Target/Statistics.h
index 55dff8861a9ab..6dd09cac890b8 100644
--- a/lldb/include/lldb/Target/Statistics.h
+++ b/lldb/include/lldb/Target/Statistics.h
@@ -155,6 +155,7 @@ struct ModuleStats {
bool debug_info_had_incomplete_types = false;
uint32_t dwo_file_count = 0;
uint32_t loaded_dwo_file_count = 0;
+ uint32_t dwo_load_error_count = 0;
};
struct ConstStringStats {
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 9958af26379b9..51ad43894d982 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -4529,3 +4529,21 @@ std::pair<uint32_t, uint32_t> SymbolFileDWARF::GetDwoFileCounts() {
return {loaded_dwo_count, total_dwo_count};
}
+
+uint32_t SymbolFileDWARF::CountDwoLoadErrors() {
+ uint32_t dwo_load_error_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 unit has dwo error (False by default).
+ const Status &dwo_error = dwarf_cu->GetDwoError();
+ if (dwo_error.Fail())
+ dwo_load_error_count++;
+ }
+ return dwo_load_error_count;
+}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index d7db8a3c0869f..349ea9ef8224b 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -288,6 +288,9 @@ class SymbolFileDWARF : public SymbolFileCommon {
// CUs and total DWO CUs. For non-split-dwarf files, this reports 0 for both.
std::pair<uint32_t, uint32_t> GetDwoFileCounts() override;
+ /// Count the number of dwo load errors happened.
+ uint32_t CountDwoLoadErrors() override;
+
DWARFContext &GetDWARFContext() { return m_context; }
const std::shared_ptr<SymbolFileDWARFDwo> &GetDwpSymbolFile();
diff --git a/lldb/source/Target/Statistics.cpp b/lldb/source/Target/Statistics.cpp
index 909f335687b21..20ade32f488ea 100644
--- a/lldb/source/Target/Statistics.cpp
+++ b/lldb/source/Target/Statistics.cpp
@@ -75,6 +75,7 @@ json::Value ModuleStats::ToJSON() const {
module.try_emplace("symbolTableSymbolCount", symtab_symbol_count);
module.try_emplace("dwoFileCount", dwo_file_count);
module.try_emplace("loadedDwoFileCount", loaded_dwo_file_count);
+ module.try_emplace("dwoLoadErrorCount", dwo_load_error_count);
if (!symbol_locator_time.map.empty()) {
json::Object obj;
@@ -326,6 +327,7 @@ llvm::json::Value DebuggerStats::ReportStatistics(
uint32_t symtab_symbol_count = 0;
uint32_t total_loaded_dwo_file_count = 0;
uint32_t total_dwo_file_count = 0;
+ uint32_t total_dwo_load_error_count = 0;
for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) {
Module *module = target != nullptr
? target->GetImages().GetModuleAtIndex(image_idx).get()
@@ -361,6 +363,8 @@ llvm::json::Value DebuggerStats::ReportStatistics(
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.dwo_load_error_count += current_dwo_errors;
+ total_dwo_load_error_count += current_dwo_errors;
module_stat.debug_info_index_loaded_from_cache =
sym_file->GetDebugInfoIndexWasLoadedFromCache();
if (module_stat.debug_info_index_loaded_from_cache)
@@ -437,6 +441,7 @@ llvm::json::Value DebuggerStats::ReportStatistics(
{"totalSymbolTableSymbolCount", symtab_symbol_count},
{"totalLoadedDwoFileCount", total_loaded_dwo_file_count},
{"totalDwoFileCount", total_dwo_file_count},
+ {"totalDwoLoadErrorCount", total_dwo_load_error_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 e9ee8b8661e5a..7a2dc213ce6fd 100644
--- a/lldb/test/API/commands/statistics/basic/TestStats.py
+++ b/lldb/test/API/commands/statistics/basic/TestStats.py
@@ -1,6 +1,8 @@
+import glob
import json
import os
import re
+import shutil
import lldb
from lldbsuite.test.decorators import *
@@ -179,6 +181,7 @@ def test_default_no_run(self):
"totalDebugInfoParseTime",
"totalDwoFileCount",
"totalLoadedDwoFileCount",
+ "totalDwoLoadErrorCount",
]
self.verify_keys(debug_stats, '"debug_stats"', debug_stat_keys, None)
if self.getPlatform() != "windows":
@@ -291,6 +294,7 @@ def test_default_with_run(self):
"totalDebugInfoParseTime",
"totalDwoFileCount",
"totalLoadedDwoFileCount",
+ "totalDwoLoadErrorCount",
]
self.verify_keys(debug_stats, '"debug_stats"', debug_stat_keys, None)
stats = debug_stats["targets"][0]
@@ -331,6 +335,7 @@ def test_memory(self):
"totalDebugInfoByteSize",
"totalDwoFileCount",
"totalLoadedDwoFileCount",
+ "totalDwoLoadErrorCount",
]
self.verify_keys(debug_stats, '"debug_stats"', debug_stat_keys, None)
@@ -385,6 +390,7 @@ def test_modules(self):
"totalDebugInfoByteSize",
"totalDwoFileCount",
"totalLoadedDwoFileCount",
+ "totalDwoLoadErrorCount",
]
self.verify_keys(debug_stats, '"debug_stats"', debug_stat_keys, None)
stats = debug_stats["targets"][0]
@@ -407,6 +413,7 @@ def test_modules(self):
"symbolTableSavedToCache",
"dwoFileCount",
"loadedDwoFileCount",
+ "dwoLoadErrorCount",
"triple",
"uuid",
]
@@ -497,6 +504,7 @@ def test_breakpoints(self):
"totalDebugInfoByteSize",
"totalDwoFileCount",
"totalLoadedDwoFileCount",
+ "totalDwoLoadErrorCount",
]
self.verify_keys(debug_stats, '"debug_stats"', debug_stat_keys, None)
target_stats = debug_stats["targets"][0]
@@ -655,6 +663,113 @@ def test_dwp_dwo_file_count(self):
self.assertEqual(debug_stats["totalDwoFileCount"], 2)
self.assertEqual(debug_stats["totalLoadedDwoFileCount"], 2)
+ @add_test_categories(["dwo"])
+ def test_dwo_missing_error_stats(self):
+ """
+ Test that DWO missing errors are reported correctly in statistics.
+ This test:
+ 1) Builds a program with split DWARF (.dwo files)
+ 2) Delete all two .dwo files
+ 3) Verify that 2 DWO load errors are reported in statistics
+ """
+ da = {
+ "CXX_SOURCES": "dwo_error_main.cpp dwo_error_foo.cpp",
+ "EXE": self.getBuildArtifact("a.out"),
+ }
+ # -gsplit-dwarf creates separate .dwo files,
+ # Expected output: dwo_error_main.dwo (contains main) and dwo_error_foo.dwo (contains foo struct/function)
+ self.build(dictionary=da, debug_info="dwo")
+ self.addTearDownCleanup(dictionary=da)
+ exe = self.getBuildArtifact("a.out")
+
+ # Remove the two .dwo files to trigger a DWO load error
+ dwo_files = glob.glob(self.getBuildArtifact("*.dwo"))
+ for dwo_file in dwo_files:
+ os.rename(dwo_file, dwo_file + ".bak")
+
+ target = self.createTestTarget(file_path=exe)
+ debug_stats = self.get_stats()
+
+ # Check DWO load error statistics are reported
+ self.assertIn("totalDwoLoadErrorCount", debug_stats)
+ self.assertEqual(debug_stats["totalDwoLoadErrorCount"], 2)
+
+ # Since there's only one module, module stats should have the same count as total count
+ self.assertIn("dwoLoadErrorCount", debug_stats["modules"][0])
+ self.assertEqual(debug_stats["modules"][0]["dwoLoadErrorCount"], 2)
+
+ # Restore the original .dwo file
+ for dwo_file in dwo_files:
+ os.rename(dwo_file + ".bak", dwo_file)
+
+ @add_test_categories(["dwo"])
+ def test_dwo_id_mismatch_error_stats(self):
+ """
+ Test that DWO ID mismatch errors are reported correctly in statistics.
+ This test:
+ 1) Builds a program with split DWARF (.dwo files)
+ 2) Change one of the source file content and rebuild
+ 3) Replace the new .dwo file with the original one to create a DWO ID mismatch
+ 4) Verifies that a DWO load error is reported in statistics
+ 5) Restores the original source file
+ """
+ da = {
+ "CXX_SOURCES": "dwo_error_main.cpp dwo_error_foo.cpp",
+ "EXE": self.getBuildArtifact("a.out"),
+ }
+ # -gsplit-dwarf creates separate .dwo files,
+ # Expected output: dwo_error_main.dwo (contains main) and dwo_error_foo.dwo (contains foo struct/function)
+ self.build(dictionary=da, debug_info="dwo")
+ self.addTearDownCleanup(dictionary=da)
+ exe = self.getBuildArtifact("a.out")
+
+ # Find and make a backup of the original .dwo file
+ dwo_files = glob.glob(self.getBuildArtifact("*.dwo"))
+
+ original_dwo_file = dwo_files[1]
+ original_dwo_backup = original_dwo_file + ".bak"
+ shutil.copy2(original_dwo_file, original_dwo_backup)
+
+ target = self.createTestTarget(file_path=exe)
+ initial_stats = self.get_stats()
+ self.assertIn("totalDwoLoadErrorCount", initial_stats)
+ self.assertEqual(initial_stats["totalDwoLoadErrorCount"], 0)
+ self.dbg.DeleteTarget(target)
+
+ # Get the original file size before modification
+ source_file_path = self.getSourcePath("dwo_error_foo.cpp")
+ original_size = os.path.getsize(source_file_path)
+
+ try:
+ # Modify the source code and rebuild
+ with open(source_file_path, "a") as f:
+ f.write("\n void additional_foo(){}\n")
+
+ # Rebuild and replace the new .dwo file with the original one
+ self.build(dictionary=da, debug_info="dwo")
+ shutil.copy2(original_dwo_backup, original_dwo_file)
+
+ # Create a new target and run to a breakpoint to force DWO file loading
+ target = self.createTestTarget(file_path=exe)
+ debug_stats = self.get_stats()
+
+ # Check that DWO load error statistics are reported
+ self.assertIn("totalDwoLoadErrorCount", debug_stats)
+ self.assertEqual(debug_stats["totalDwoLoadErrorCount"], 1)
+
+ # Since there's only one module, module stats should have the same count as total count
+ self.assertIn("dwoLoadErrorCount", debug_stats["modules"][0])
+ self.assertEqual(debug_stats["modules"][0]["dwoLoadErrorCount"], 1)
+
+ finally:
+ # Remove the appended content
+ with open(source_file_path, "a") as f:
+ f.truncate(original_size)
+
+ # Restore the original .dwo file
+ if os.path.exists(original_dwo_backup):
+ os.unlink(original_dwo_backup)
+
@skipUnlessDarwin
@no_debug_info_test
def test_dsym_binary_has_symfile_in_stats(self):
diff --git a/lldb/test/API/commands/statistics/basic/dwo_error_foo.cpp b/lldb/test/API/commands/statistics/basic/dwo_error_foo.cpp
new file mode 100644
index 0000000000000..41618bdcee958
--- /dev/null
+++ b/lldb/test/API/commands/statistics/basic/dwo_error_foo.cpp
@@ -0,0 +1,10 @@
+struct foo {
+ int x;
+ bool y;
+};
+
+void dwo_error_foo() {
+ foo f;
+ f.x = 1;
+ f.y = true;
+}
diff --git a/lldb/test/API/commands/statistics/basic/dwo_error_main.cpp b/lldb/test/API/commands/statistics/basic/dwo_error_main.cpp
new file mode 100644
index 0000000000000..4f09bd74e1fd6
--- /dev/null
+++ b/lldb/test/API/commands/statistics/basic/dwo_error_main.cpp
@@ -0,0 +1,5 @@
+void dwo_error_foo();
+int main() {
+ dwo_error_foo();
+ return 0;
+}
>From 698bc9ea4b70ecb3981380615579a296ac064999 Mon Sep 17 00:00:00 2001
From: Ziyi Wang <zw3917 at nyu.edu>
Date: Sun, 24 Aug 2025 16:24:54 -0700
Subject: [PATCH 2/4] Combine DWO counting statistics into a single DWOStats
struct
---
lldb/include/lldb/Symbol/SymbolFile.h | 24 +++++++-----
lldb/include/lldb/Target/Statistics.h | 2 +-
.../SymbolFile/DWARF/SymbolFileDWARF.cpp | 37 ++++++-------------
.../SymbolFile/DWARF/SymbolFileDWARF.h | 12 +++---
lldb/source/Target/Statistics.cpp | 21 ++++++-----
.../commands/statistics/basic/TestStats.py | 24 ++++++------
6 files changed, 56 insertions(+), 64 deletions(-)
diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h
index 7f590fc2e7e64..49e3573292595 100644
--- a/lldb/include/lldb/Symbol/SymbolFile.h
+++ b/lldb/include/lldb/Symbol/SymbolFile.h
@@ -488,17 +488,23 @@ class SymbolFile : public PluginInterface {
return false;
};
- /// Get number of loaded/parsed DWO files. This is emitted in "statistics
- /// dump"
+ /// Holds statistics about DWO (Debug With Object) files.
+ struct DWOStats {
+ uint32_t loaded_dwo_file_count = 0;
+ uint32_t dwo_file_count = 0;
+ uint32_t dwo_error_count = 0;
+ };
+
+ /// Retrieves statistics about DWO files associated with this symbol file.
+ /// This function returns a DWOStats struct containing:
+ /// - The number of successfully loaded/parsed DWO files.
+ /// - The total number of DWO files encountered.
+ /// - The number of DWO CUs that failed to load due to errors.
+ /// If this symbol file does not support DWO files, all counts will be zero.
///
/// \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}; }
-
- /// Calculates the count of dwo load error, return the number of dwo file with
- /// errors, 0 by default.
- virtual uint32_t CountDwoLoadErrors() { return 0; }
+ /// A DWOStats struct with loaded, total, and error counts for DWO files.
+ virtual DWOStats GetDwoStats() { return {}; }
virtual lldb::TypeSP
MakeType(lldb::user_id_t uid, ConstString name,
diff --git a/lldb/include/lldb/Target/Statistics.h b/lldb/include/lldb/Target/Statistics.h
index 6dd09cac890b8..1cd78b195a7c9 100644
--- a/lldb/include/lldb/Target/Statistics.h
+++ b/lldb/include/lldb/Target/Statistics.h
@@ -155,7 +155,7 @@ struct ModuleStats {
bool debug_info_had_incomplete_types = false;
uint32_t dwo_file_count = 0;
uint32_t loaded_dwo_file_count = 0;
- uint32_t dwo_load_error_count = 0;
+ uint32_t dwo_error_count = 0;
};
struct ConstStringStats {
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 5c95200abd1bd..e41dfdf190697 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -90,7 +90,7 @@
#include <cctype>
#include <cstring>
-//#define ENABLE_DEBUG_PRINTF // COMMENT OUT THIS LINE PRIOR TO CHECKIN
+// #define ENABLE_DEBUG_PRINTF // COMMENT OUT THIS LINE PRIOR TO CHECKIN
#ifdef ENABLE_DEBUG_PRINTF
#include <cstdio>
@@ -1716,7 +1716,7 @@ SymbolFileDWARF *SymbolFileDWARF::GetDIERefSymbolFile(const DIERef &die_ref) {
return this;
if (file_index) {
- // We have a SymbolFileDWARFDebugMap, so let it find the right file
+ // We have a SymbolFileDWARFDebugMap, so let it find the right file
if (SymbolFileDWARFDebugMap *debug_map = GetDebugMapSymfile())
return debug_map->GetSymbolFileByOSOIndex(*file_index);
@@ -1725,7 +1725,8 @@ SymbolFileDWARF *SymbolFileDWARF::GetDIERefSymbolFile(const DIERef &die_ref) {
return GetDwpSymbolFile().get(); // DWP case
// Handle the .dwo file case correctly
- return DebugInfo().GetUnitAtIndex(*die_ref.file_index())
+ return DebugInfo()
+ .GetUnitAtIndex(*die_ref.file_index())
->GetDwoSymbolFile(); // DWO case
}
return this;
@@ -4502,9 +4503,8 @@ void SymbolFileDWARF::GetCompileOptions(
}
}
-std::pair<uint32_t, uint32_t> SymbolFileDWARF::GetDwoFileCounts() {
- uint32_t total_dwo_count = 0;
- uint32_t loaded_dwo_count = 0;
+SymbolFile::DWOStats SymbolFileDWARF::GetDwoStats() {
+ SymbolFile::DWOStats stats;
DWARFDebugInfo &info = DebugInfo();
const size_t num_cus = info.GetNumUnits();
@@ -4517,34 +4517,21 @@ std::pair<uint32_t, uint32_t> SymbolFileDWARF::GetDwoFileCounts() {
if (!dwarf_cu->GetDWOId().has_value())
continue;
- total_dwo_count++;
+ stats.dwo_file_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++;
+ stats.loaded_dwo_file_count++;
}
- }
-
- return {loaded_dwo_count, total_dwo_count};
-}
-
-uint32_t SymbolFileDWARF::CountDwoLoadErrors() {
- uint32_t dwo_load_error_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 unit has dwo error (False by default).
+ // Check if this unit has a DWO load error, false by default.
const Status &dwo_error = dwarf_cu->GetDwoError();
if (dwo_error.Fail())
- dwo_load_error_count++;
+ stats.dwo_error_count++;
}
- return dwo_load_error_count;
+
+ return stats;
}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index 349ea9ef8224b..8b8cb5859e8a0 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -283,13 +283,11 @@ class SymbolFileDWARF : public SymbolFileCommon {
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
- // CUs and total DWO CUs. For non-split-dwarf files, this reports 0 for both.
- std::pair<uint32_t, uint32_t> GetDwoFileCounts() override;
-
- /// Count the number of dwo load errors happened.
- uint32_t CountDwoLoadErrors() override;
+ /// Gets statistics about dwo files associated with this symbol file.
+ /// For split-dwarf files, this reports the counts for successfully loaded DWO
+ /// CUs, total DWO CUs, and the number of DWO CUs with loading errors.
+ /// For non-split-dwarf files, this reports 0 for all.
+ DWOStats GetDwoStats() override;
DWARFContext &GetDWARFContext() { return m_context; }
diff --git a/lldb/source/Target/Statistics.cpp b/lldb/source/Target/Statistics.cpp
index 0f9eb5a785163..0dab6aa0b7861 100644
--- a/lldb/source/Target/Statistics.cpp
+++ b/lldb/source/Target/Statistics.cpp
@@ -75,7 +75,7 @@ json::Value ModuleStats::ToJSON() const {
module.try_emplace("symbolTableSymbolCount", symtab_symbol_count);
module.try_emplace("dwoFileCount", dwo_file_count);
module.try_emplace("loadedDwoFileCount", loaded_dwo_file_count);
- module.try_emplace("dwoLoadErrorCount", dwo_load_error_count);
+ module.try_emplace("dwoErrorCount", dwo_error_count);
if (!symbol_locator_time.map.empty()) {
json::Object obj;
@@ -327,7 +327,7 @@ llvm::json::Value DebuggerStats::ReportStatistics(
uint32_t symtab_symbol_count = 0;
uint32_t total_loaded_dwo_file_count = 0;
uint32_t total_dwo_file_count = 0;
- uint32_t total_dwo_load_error_count = 0;
+ uint32_t total_dwo_error_count = 0;
for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) {
Module *module = target != nullptr
? target->GetImages().GetModuleAtIndex(image_idx).get()
@@ -359,13 +359,14 @@ llvm::json::Value DebuggerStats::ReportStatistics(
for (const auto &symbol_module : symbol_modules.Modules())
module_stat.symfile_modules.push_back((intptr_t)symbol_module.get());
}
- 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;
- uint32_t current_dwo_errors = sym_file->CountDwoLoadErrors();
- module_stat.dwo_load_error_count += current_dwo_errors;
- total_dwo_load_error_count += current_dwo_errors;
+ SymbolFile::DWOStats current_dwo_stats = sym_file->GetDwoStats();
+ module_stat.loaded_dwo_file_count +=
+ current_dwo_stats.loaded_dwo_file_count;
+ module_stat.dwo_file_count += current_dwo_stats.dwo_file_count;
+ module_stat.dwo_error_count += current_dwo_stats.dwo_error_count;
+ total_dwo_file_count += current_dwo_stats.dwo_file_count;
+ total_loaded_dwo_file_count += current_dwo_stats.loaded_dwo_file_count;
+ total_dwo_error_count += current_dwo_stats.dwo_error_count;
module_stat.debug_info_index_loaded_from_cache =
sym_file->GetDebugInfoIndexWasLoadedFromCache();
if (module_stat.debug_info_index_loaded_from_cache)
@@ -442,7 +443,7 @@ llvm::json::Value DebuggerStats::ReportStatistics(
{"totalSymbolTableSymbolCount", symtab_symbol_count},
{"totalLoadedDwoFileCount", total_loaded_dwo_file_count},
{"totalDwoFileCount", total_dwo_file_count},
- {"totalDwoLoadErrorCount", total_dwo_load_error_count},
+ {"totalDwoErrorCount", total_dwo_error_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 7a2dc213ce6fd..d41877eaf8996 100644
--- a/lldb/test/API/commands/statistics/basic/TestStats.py
+++ b/lldb/test/API/commands/statistics/basic/TestStats.py
@@ -670,7 +670,7 @@ def test_dwo_missing_error_stats(self):
This test:
1) Builds a program with split DWARF (.dwo files)
2) Delete all two .dwo files
- 3) Verify that 2 DWO load errors are reported in statistics
+ 3) Verify that 2 DWO errors are reported in statistics
"""
da = {
"CXX_SOURCES": "dwo_error_main.cpp dwo_error_foo.cpp",
@@ -691,12 +691,12 @@ def test_dwo_missing_error_stats(self):
debug_stats = self.get_stats()
# Check DWO load error statistics are reported
- self.assertIn("totalDwoLoadErrorCount", debug_stats)
- self.assertEqual(debug_stats["totalDwoLoadErrorCount"], 2)
+ self.assertIn("totalDwoErrorCount", debug_stats)
+ self.assertEqual(debug_stats["totalDwoErrorCount"], 2)
# Since there's only one module, module stats should have the same count as total count
- self.assertIn("dwoLoadErrorCount", debug_stats["modules"][0])
- self.assertEqual(debug_stats["modules"][0]["dwoLoadErrorCount"], 2)
+ self.assertIn("dwoErrorCount", debug_stats["modules"][0])
+ self.assertEqual(debug_stats["modules"][0]["dwoErrorCount"], 2)
# Restore the original .dwo file
for dwo_file in dwo_files:
@@ -710,7 +710,7 @@ def test_dwo_id_mismatch_error_stats(self):
1) Builds a program with split DWARF (.dwo files)
2) Change one of the source file content and rebuild
3) Replace the new .dwo file with the original one to create a DWO ID mismatch
- 4) Verifies that a DWO load error is reported in statistics
+ 4) Verifies that a DWO error is reported in statistics
5) Restores the original source file
"""
da = {
@@ -732,8 +732,8 @@ def test_dwo_id_mismatch_error_stats(self):
target = self.createTestTarget(file_path=exe)
initial_stats = self.get_stats()
- self.assertIn("totalDwoLoadErrorCount", initial_stats)
- self.assertEqual(initial_stats["totalDwoLoadErrorCount"], 0)
+ self.assertIn("totalDwoErrorCount", initial_stats)
+ self.assertEqual(initial_stats["totalDwoErrorCount"], 0)
self.dbg.DeleteTarget(target)
# Get the original file size before modification
@@ -754,12 +754,12 @@ def test_dwo_id_mismatch_error_stats(self):
debug_stats = self.get_stats()
# Check that DWO load error statistics are reported
- self.assertIn("totalDwoLoadErrorCount", debug_stats)
- self.assertEqual(debug_stats["totalDwoLoadErrorCount"], 1)
+ self.assertIn("totalDwoErrorCount", debug_stats)
+ self.assertEqual(debug_stats["totalDwoErrorCount"], 1)
# Since there's only one module, module stats should have the same count as total count
- self.assertIn("dwoLoadErrorCount", debug_stats["modules"][0])
- self.assertEqual(debug_stats["modules"][0]["dwoLoadErrorCount"], 1)
+ self.assertIn("dwoErrorCount", debug_stats["modules"][0])
+ self.assertEqual(debug_stats["modules"][0]["dwoErrorCount"], 1)
finally:
# Remove the appended content
>From 3881633f1bb7a1af20d15d26f4539dd5b0ab1c90 Mon Sep 17 00:00:00 2001
From: Ziyi Wang <zw3917 at nyu.edu>
Date: Thu, 28 Aug 2025 13:29:23 -0700
Subject: [PATCH 3/4] Reuse DWOStats in Statistics
---
lldb/include/lldb/Symbol/SymbolFile.h | 46 +++++++++++++++------------
lldb/include/lldb/Target/Statistics.h | 5 ++-
lldb/source/Target/Statistics.cpp | 25 ++++++---------
3 files changed, 37 insertions(+), 39 deletions(-)
diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h
index 49e3573292595..671a2483783bf 100644
--- a/lldb/include/lldb/Symbol/SymbolFile.h
+++ b/lldb/include/lldb/Symbol/SymbolFile.h
@@ -493,6 +493,12 @@ class SymbolFile : public PluginInterface {
uint32_t loaded_dwo_file_count = 0;
uint32_t dwo_file_count = 0;
uint32_t dwo_error_count = 0;
+
+ DWOStats operator+(const DWOStats &rhs) const {
+ return DWOStats{loaded_dwo_file_count + rhs.loaded_dwo_file_count,
+ dwo_file_count + rhs.dwo_file_count,
+ dwo_error_count + rhs.dwo_error_count};
+ }
};
/// Retrieves statistics about DWO files associated with this symbol file.
@@ -506,14 +512,15 @@ class SymbolFile : public PluginInterface {
/// A DWOStats struct with loaded, total, and error counts for DWO files.
virtual DWOStats GetDwoStats() { return {}; }
- virtual lldb::TypeSP
- MakeType(lldb::user_id_t uid, ConstString name,
- std::optional<uint64_t> byte_size, SymbolContextScope *context,
- lldb::user_id_t encoding_uid,
- Type::EncodingDataType encoding_uid_type, const Declaration &decl,
- const CompilerType &compiler_qual_type,
- Type::ResolveState compiler_type_resolve_state,
- uint32_t opaque_payload = 0) = 0;
+ virtual lldb::TypeSP MakeType(lldb::user_id_t uid, ConstString name,
+ std::optional<uint64_t> byte_size,
+ SymbolContextScope *context,
+ lldb::user_id_t encoding_uid,
+ Type::EncodingDataType encoding_uid_type,
+ const Declaration &decl,
+ const CompilerType &compiler_qual_type,
+ Type::ResolveState compiler_type_resolve_state,
+ uint32_t opaque_payload = 0) = 0;
virtual lldb::TypeSP CopyType(const lldb::TypeSP &other_type) = 0;
@@ -607,7 +614,7 @@ class SymbolFileCommon : public SymbolFile {
return m_debug_info_had_variable_errors;
}
void SetDebugInfoHadFrameVariableErrors() override {
- m_debug_info_had_variable_errors = true;
+ m_debug_info_had_variable_errors = true;
}
/// This function is used to create types that belong to a SymbolFile. The
@@ -622,21 +629,20 @@ class SymbolFileCommon : public SymbolFile {
const CompilerType &compiler_qual_type,
Type::ResolveState compiler_type_resolve_state,
uint32_t opaque_payload = 0) override {
- lldb::TypeSP type_sp (new Type(
- uid, this, name, byte_size, context, encoding_uid,
- encoding_uid_type, decl, compiler_qual_type,
- compiler_type_resolve_state, opaque_payload));
- m_type_list.Insert(type_sp);
- return type_sp;
+ lldb::TypeSP type_sp(new Type(
+ uid, this, name, byte_size, context, encoding_uid, encoding_uid_type,
+ decl, compiler_qual_type, compiler_type_resolve_state, opaque_payload));
+ m_type_list.Insert(type_sp);
+ return type_sp;
}
lldb::TypeSP CopyType(const lldb::TypeSP &other_type) override {
- // Make sure the real symbol file matches when copying types.
- if (GetBackingSymbolFile() != other_type->GetSymbolFile())
+ // Make sure the real symbol file matches when copying types.
+ if (GetBackingSymbolFile() != other_type->GetSymbolFile())
return lldb::TypeSP();
- lldb::TypeSP type_sp(new Type(*other_type));
- m_type_list.Insert(type_sp);
- return type_sp;
+ lldb::TypeSP type_sp(new Type(*other_type));
+ m_type_list.Insert(type_sp);
+ return type_sp;
}
protected:
diff --git a/lldb/include/lldb/Target/Statistics.h b/lldb/include/lldb/Target/Statistics.h
index 1cd78b195a7c9..bf00dd3eb146d 100644
--- a/lldb/include/lldb/Target/Statistics.h
+++ b/lldb/include/lldb/Target/Statistics.h
@@ -10,6 +10,7 @@
#define LLDB_TARGET_STATISTICS_H
#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/RealpathPrefixes.h"
#include "lldb/Utility/Stream.h"
@@ -153,9 +154,7 @@ 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;
- uint32_t dwo_error_count = 0;
+ SymbolFile::DWOStats dwo_stats;
};
struct ConstStringStats {
diff --git a/lldb/source/Target/Statistics.cpp b/lldb/source/Target/Statistics.cpp
index 0dab6aa0b7861..b0e2257705b5e 100644
--- a/lldb/source/Target/Statistics.cpp
+++ b/lldb/source/Target/Statistics.cpp
@@ -73,9 +73,9 @@ 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);
- module.try_emplace("dwoErrorCount", dwo_error_count);
+ module.try_emplace("dwoFileCount", dwo_stats.dwo_file_count);
+ module.try_emplace("loadedDwoFileCount", dwo_stats.loaded_dwo_file_count);
+ module.try_emplace("dwoErrorCount", dwo_stats.dwo_error_count);
if (!symbol_locator_time.map.empty()) {
json::Object obj;
@@ -325,9 +325,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;
- uint32_t total_dwo_file_count = 0;
- uint32_t total_dwo_error_count = 0;
+ SymbolFile::DWOStats total_dwo_stats;
for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) {
Module *module = target != nullptr
? target->GetImages().GetModuleAtIndex(image_idx).get()
@@ -360,13 +358,8 @@ llvm::json::Value DebuggerStats::ReportStatistics(
module_stat.symfile_modules.push_back((intptr_t)symbol_module.get());
}
SymbolFile::DWOStats current_dwo_stats = sym_file->GetDwoStats();
- module_stat.loaded_dwo_file_count +=
- current_dwo_stats.loaded_dwo_file_count;
- module_stat.dwo_file_count += current_dwo_stats.dwo_file_count;
- module_stat.dwo_error_count += current_dwo_stats.dwo_error_count;
- total_dwo_file_count += current_dwo_stats.dwo_file_count;
- total_loaded_dwo_file_count += current_dwo_stats.loaded_dwo_file_count;
- total_dwo_error_count += current_dwo_stats.dwo_error_count;
+ module_stat.dwo_stats += current_dwo_stats;
+ total_dwo_stats += current_dwo_stats;
module_stat.debug_info_index_loaded_from_cache =
sym_file->GetDebugInfoIndexWasLoadedFromCache();
if (module_stat.debug_info_index_loaded_from_cache)
@@ -441,9 +434,9 @@ 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},
- {"totalDwoFileCount", total_dwo_file_count},
- {"totalDwoErrorCount", total_dwo_error_count},
+ {"totalLoadedDwoFileCount", total_dwo_stats.loaded_dwo_file_count},
+ {"totalDwoFileCount", total_dwo_stats.dwo_file_count},
+ {"totalDwoErrorCount", total_dwo_stats.dwo_error_count},
};
if (include_targets) {
>From ec5dabd0a75ab86264b31dc40d049ac776dc6906 Mon Sep 17 00:00:00 2001
From: Ziyi Wang <zw3917 at nyu.edu>
Date: Thu, 28 Aug 2025 16:35:19 -0700
Subject: [PATCH 4/4] [lldb]Reuse DWOStats in statistics
---
lldb/include/lldb/Symbol/SymbolFile.h | 13 -------------
lldb/include/lldb/Target/Statistics.h | 15 ++++++++++++++-
.../Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp | 4 ++--
lldb/source/Target/Statistics.cpp | 8 ++++----
4 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h
index 671a2483783bf..68c6563e7f314 100644
--- a/lldb/include/lldb/Symbol/SymbolFile.h
+++ b/lldb/include/lldb/Symbol/SymbolFile.h
@@ -488,19 +488,6 @@ class SymbolFile : public PluginInterface {
return false;
};
- /// Holds statistics about DWO (Debug With Object) files.
- struct DWOStats {
- uint32_t loaded_dwo_file_count = 0;
- uint32_t dwo_file_count = 0;
- uint32_t dwo_error_count = 0;
-
- DWOStats operator+(const DWOStats &rhs) const {
- return DWOStats{loaded_dwo_file_count + rhs.loaded_dwo_file_count,
- dwo_file_count + rhs.dwo_file_count,
- dwo_error_count + rhs.dwo_error_count};
- }
- };
-
/// Retrieves statistics about DWO files associated with this symbol file.
/// This function returns a DWOStats struct containing:
/// - The number of successfully loaded/parsed DWO files.
diff --git a/lldb/include/lldb/Target/Statistics.h b/lldb/include/lldb/Target/Statistics.h
index bf00dd3eb146d..fac825229ec36 100644
--- a/lldb/include/lldb/Target/Statistics.h
+++ b/lldb/include/lldb/Target/Statistics.h
@@ -124,6 +124,19 @@ struct StatsSuccessFail {
uint32_t failures = 0;
};
+/// Holds statistics about DWO (Debug With Object) files.
+struct DWOStats {
+ uint32_t loaded_dwo_file_count = 0;
+ uint32_t dwo_file_count = 0;
+ uint32_t dwo_error_count = 0;
+
+ DWOStats operator+(const DWOStats &rhs) const {
+ return DWOStats{loaded_dwo_file_count + rhs.loaded_dwo_file_count,
+ dwo_file_count + rhs.dwo_file_count,
+ dwo_error_count + rhs.dwo_error_count};
+ }
+};
+
/// A class that represents statistics for a since lldb_private::Module.
struct ModuleStats {
llvm::json::Value ToJSON() const;
@@ -154,7 +167,7 @@ struct ModuleStats {
bool symtab_stripped = false;
bool debug_info_had_variable_errors = false;
bool debug_info_had_incomplete_types = false;
- SymbolFile::DWOStats dwo_stats;
+ DWOStats dwo_stats;
};
struct ConstStringStats {
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index e41dfdf190697..6f395b5a98afe 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -4503,8 +4503,8 @@ void SymbolFileDWARF::GetCompileOptions(
}
}
-SymbolFile::DWOStats SymbolFileDWARF::GetDwoStats() {
- SymbolFile::DWOStats stats;
+DWOStats SymbolFileDWARF::GetDwoStats() {
+ DWOStats stats;
DWARFDebugInfo &info = DebugInfo();
const size_t num_cus = info.GetNumUnits();
diff --git a/lldb/source/Target/Statistics.cpp b/lldb/source/Target/Statistics.cpp
index b0e2257705b5e..3c16df5440f25 100644
--- a/lldb/source/Target/Statistics.cpp
+++ b/lldb/source/Target/Statistics.cpp
@@ -325,7 +325,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;
- SymbolFile::DWOStats total_dwo_stats;
+ DWOStats total_dwo_stats;
for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) {
Module *module = target != nullptr
? target->GetImages().GetModuleAtIndex(image_idx).get()
@@ -357,9 +357,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());
}
- SymbolFile::DWOStats current_dwo_stats = sym_file->GetDwoStats();
- module_stat.dwo_stats += current_dwo_stats;
- total_dwo_stats += current_dwo_stats;
+ DWOStats current_dwo_stats = sym_file->GetDwoStats();
+ module_stat.dwo_stats = module_stat.dwo_stats + current_dwo_stats;
+ total_dwo_stats = total_dwo_stats + current_dwo_stats;
module_stat.debug_info_index_loaded_from_cache =
sym_file->GetDebugInfoIndexWasLoadedFromCache();
if (module_stat.debug_info_index_loaded_from_cache)
More information about the lldb-commits
mailing list