[Lldb-commits] [lldb] [lldb] Avoid force loading symbol files in statistics collection (PR #129593)
David Peixotto via lldb-commits
lldb-commits at lists.llvm.org
Fri Mar 7 16:05:26 PST 2025
https://github.com/dmpots updated https://github.com/llvm/llvm-project/pull/129593
>From bca07d666683152df179f7784d0003262fa54834 Mon Sep 17 00:00:00 2001
From: David Peixotto <peix at meta.com>
Date: Wed, 26 Feb 2025 13:55:35 -0800
Subject: [PATCH 1/5] Avoid force loading symbol files in statistics collection
This commit modifies the `DebuggerStats::ReportStatistics` implementation
to avoid loading symbol files for unloaded symbols. We collect stats
on debugger shutdown and without this change it can cause the debugger
to hang for a long while on shutdown if they symbols were not previously
loaded (e.g. `settings set target.preload-symbols false`).
The implementation is done by adding an optional parameter to
`Module::GetSymtab` to control if the corresponding symbol file will
be loaded in the same way that can control it for `Module::GetSymbolFile`.
---
lldb/include/lldb/Core/Module.h | 6 +++-
lldb/source/Core/Module.cpp | 4 +--
lldb/source/Target/Statistics.cpp | 4 +--
.../Commands/command-statistics-dump.test | 31 +++++++++++++++++++
4 files changed, 40 insertions(+), 5 deletions(-)
create mode 100644 lldb/test/Shell/Commands/command-statistics-dump.test
diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h
index 90e0f4b6a3aac..9aa05ed3eb074 100644
--- a/lldb/include/lldb/Core/Module.h
+++ b/lldb/include/lldb/Core/Module.h
@@ -608,7 +608,11 @@ class Module : public std::enable_shared_from_this<Module>,
virtual SymbolFile *GetSymbolFile(bool can_create = true,
Stream *feedback_strm = nullptr);
- Symtab *GetSymtab();
+ /// Get the module's symbol table
+ ///
+ /// If the symbol table has already been loaded, this function returns it.
+ /// Otherwise, it will only be loaded when can_create is true.
+ Symtab *GetSymtab(bool can_create = true);
/// Get a reference to the UUID value contained in this object.
///
diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp
index 33668c5d20dde..d70f292abaea4 100644
--- a/lldb/source/Core/Module.cpp
+++ b/lldb/source/Core/Module.cpp
@@ -1022,8 +1022,8 @@ SymbolFile *Module::GetSymbolFile(bool can_create, Stream *feedback_strm) {
return m_symfile_up ? m_symfile_up->GetSymbolFile() : nullptr;
}
-Symtab *Module::GetSymtab() {
- if (SymbolFile *symbols = GetSymbolFile())
+Symtab *Module::GetSymtab(bool can_create) {
+ if (SymbolFile *symbols = GetSymbolFile(can_create))
return symbols->GetSymtab();
return nullptr;
}
diff --git a/lldb/source/Target/Statistics.cpp b/lldb/source/Target/Statistics.cpp
index 8173d20457e21..b5d2e7bda1edf 100644
--- a/lldb/source/Target/Statistics.cpp
+++ b/lldb/source/Target/Statistics.cpp
@@ -316,7 +316,7 @@ llvm::json::Value DebuggerStats::ReportStatistics(
ModuleStats module_stat;
module_stat.symtab_parse_time = module->GetSymtabParseTime().get().count();
module_stat.symtab_index_time = module->GetSymtabIndexTime().get().count();
- Symtab *symtab = module->GetSymtab();
+ Symtab *symtab = module->GetSymtab(/*can_create=*/false);
if (symtab) {
module_stat.symtab_loaded_from_cache = symtab->GetWasLoadedFromCache();
if (module_stat.symtab_loaded_from_cache)
@@ -325,7 +325,7 @@ llvm::json::Value DebuggerStats::ReportStatistics(
if (module_stat.symtab_saved_to_cache)
++symtabs_saved;
}
- SymbolFile *sym_file = module->GetSymbolFile();
+ SymbolFile *sym_file = module->GetSymbolFile(/*can_create=*/false);
if (sym_file) {
if (!summary_only) {
if (sym_file->GetObjectFile() != module->GetObjectFile())
diff --git a/lldb/test/Shell/Commands/command-statistics-dump.test b/lldb/test/Shell/Commands/command-statistics-dump.test
new file mode 100644
index 0000000000000..d490a0c374057
--- /dev/null
+++ b/lldb/test/Shell/Commands/command-statistics-dump.test
@@ -0,0 +1,31 @@
+# RUN: %clang_host -g %S/Inputs/main.c -o %t-main.exe
+
+# When we enable symbol preload and dump stats there should be a non-zero
+# time for parsing symbol tables for the main module.
+# RUN: %lldb %t-main.exe \
+# RUN: -O "settings set plugin.jit-loader.gdb.enable off" \
+# RUN: -O "settings set target.preload-symbols true" \
+# RUN: -o "statistics dump" \
+# RUN: -o "q" \
+# RUN: | FileCheck %s -check-prefixes=CHECK,PRELOAD_TRUE
+
+# Find the module stats for the main executable and make sure
+# we are looking at the symbol parse time for that module.
+# CHECK: "modules": [
+# CHECK: {
+# CHECK: "path": {{.*}}-main.exe
+# CHECK-NOT: }
+
+# PRELOAD_TRUE: "symbolTableParseTime":
+# PRELOAD_TRUE-SAME: {{[1-9]+}}
+
+# When we disable symbol preload and dump stats the symbol table
+# for main should not be parsed and have a time of 0.
+# RUN: %lldb %t-main.exe \
+# RUN: -O "settings set plugin.jit-loader.gdb.enable off" \
+# RUN: -O "settings set target.preload-symbols false" \
+# RUN: -o "statistics dump" \
+# RUN: -o "q" \
+# RUN: | FileCheck %s -check-prefixes=CHECK,PRELOAD_FALSE
+
+# PRELOAD_FALSE: "symbolTableParseTime": 0,
>From 2a6475487ef7cc885d72b36436c8b2cff9775644 Mon Sep 17 00:00:00 2001
From: David Peixotto <peix at meta.com>
Date: Tue, 4 Mar 2025 15:03:25 -0800
Subject: [PATCH 2/5] Add unit test for new GetSymtab overload
Add a unit test to show that symbol tables are only
created on demand.
---
lldb/unittests/Symbol/SymtabTest.cpp | 41 +++++++++++++++++++++++++++-
1 file changed, 40 insertions(+), 1 deletion(-)
diff --git a/lldb/unittests/Symbol/SymtabTest.cpp b/lldb/unittests/Symbol/SymtabTest.cpp
index 7b8892e5b5c0f..76743c96cc502 100644
--- a/lldb/unittests/Symbol/SymtabTest.cpp
+++ b/lldb/unittests/Symbol/SymtabTest.cpp
@@ -6,8 +6,10 @@
//
//===----------------------------------------------------------------------===//
+#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
#include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h"
#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
+#include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h"
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "TestingSupport/SubsystemRAII.h"
#include "TestingSupport/TestUtilities.h"
@@ -31,7 +33,7 @@ using namespace lldb_private::plugin::dwarf;
class SymtabTest : public testing::Test {
SubsystemRAII<FileSystem, HostInfo, ObjectFileMachO, SymbolFileDWARF,
- TypeSystemClang>
+ ObjectFileELF, SymbolFileSymtab, TypeSystemClang>
subsystem;
};
@@ -718,3 +720,40 @@ TEST_F(SymtabTest, TestDecodeCStringMaps) {
Symtab::eVisibilityAny);
ASSERT_NE(symbol, nullptr);
}
+
+TEST_F(SymtabTest, TestSymtabCreatedOnDemand) {
+ auto ExpectedFile = TestFile::fromYaml(R"(
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_X86_64
+ Entry: 0x0000000000400180
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ Address: 0x0000000000400180
+ AddressAlign: 0x0000000000000010
+ Content: 554889E58B042500106000890425041060005DC3
+Symbols:
+ - Name: _start
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000400180
+ Size: 0x0000000000000014
+ Binding: STB_GLOBAL
+...
+)");
+ ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
+ auto module_sp = std::make_shared<Module>(ExpectedFile->moduleSpec());
+
+ // The symbol table should not be loaded by default.
+ Symtab *module_symtab = module_sp->GetSymtab(/*can_create=*/false);
+ ASSERT_EQ(module_symtab, nullptr);
+
+ // But it should be created on demand.
+ module_symtab = module_sp->GetSymtab(/*can_create=*/true);
+ ASSERT_NE(module_symtab, nullptr);
+}
>From 86b8e935e69b94d434cc0819bc4481fe4b4aff56 Mon Sep 17 00:00:00 2001
From: David Peixotto <peix at meta.com>
Date: Tue, 4 Mar 2025 17:42:13 -0800
Subject: [PATCH 3/5] Create target without loading dependents
---
lldb/test/Shell/Commands/command-statistics-dump.test | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/lldb/test/Shell/Commands/command-statistics-dump.test b/lldb/test/Shell/Commands/command-statistics-dump.test
index d490a0c374057..b4e1252d01bbb 100644
--- a/lldb/test/Shell/Commands/command-statistics-dump.test
+++ b/lldb/test/Shell/Commands/command-statistics-dump.test
@@ -2,9 +2,9 @@
# When we enable symbol preload and dump stats there should be a non-zero
# time for parsing symbol tables for the main module.
-# RUN: %lldb %t-main.exe \
-# RUN: -O "settings set plugin.jit-loader.gdb.enable off" \
+# RUN: %lldb -O "settings set plugin.jit-loader.gdb.enable off" \
# RUN: -O "settings set target.preload-symbols true" \
+# RUN: -o 'target create --no-dependents "%t-main.exe"' \
# RUN: -o "statistics dump" \
# RUN: -o "q" \
# RUN: | FileCheck %s -check-prefixes=CHECK,PRELOAD_TRUE
@@ -21,9 +21,9 @@
# When we disable symbol preload and dump stats the symbol table
# for main should not be parsed and have a time of 0.
-# RUN: %lldb %t-main.exe \
-# RUN: -O "settings set plugin.jit-loader.gdb.enable off" \
+# RUN: %lldb -O "settings set plugin.jit-loader.gdb.enable off" \
# RUN: -O "settings set target.preload-symbols false" \
+# RUN: -o 'target create --no-dependents "%t-main.exe"' \
# RUN: -o "statistics dump" \
# RUN: -o "q" \
# RUN: | FileCheck %s -check-prefixes=CHECK,PRELOAD_FALSE
>From b63d34a58b6f0abfc48fa1d963a3247985330357 Mon Sep 17 00:00:00 2001
From: David Peixotto <peix at meta.com>
Date: Wed, 5 Mar 2025 12:38:48 -0800
Subject: [PATCH 4/5] Add comment explaning assumption around symbol loading
---
lldb/test/Shell/Commands/command-statistics-dump.test | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/lldb/test/Shell/Commands/command-statistics-dump.test b/lldb/test/Shell/Commands/command-statistics-dump.test
index b4e1252d01bbb..bad7de0ecf61f 100644
--- a/lldb/test/Shell/Commands/command-statistics-dump.test
+++ b/lldb/test/Shell/Commands/command-statistics-dump.test
@@ -1,3 +1,12 @@
+# This test validates that statistics generation does not force loading
+# symbol tables. In order to avoid other sources of symbol loading we
+# create the target without loading dependents and do not actually
+# run it. Running the target is a problem because there are various
+# instrumentation plugins (e.g. ASAN) that are always enabled and force
+# symbol loading. If you see this test start to fail we may have added
+# a new source of symbol loading unexpectedly.
+
+# Build a simple test executable.
# RUN: %clang_host -g %S/Inputs/main.c -o %t-main.exe
# When we enable symbol preload and dump stats there should be a non-zero
>From 44dea6aca131b6b2868f99613d54c9c5797ce1a0 Mon Sep 17 00:00:00 2001
From: David Peixotto <peix at meta.com>
Date: Fri, 7 Mar 2025 16:04:04 -0800
Subject: [PATCH 5/5] Extend unit test to show that we cache the symbol table
Once it has been created then passing `can_create=false` should
have no effect.
---
lldb/unittests/Symbol/SymtabTest.cpp | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/lldb/unittests/Symbol/SymtabTest.cpp b/lldb/unittests/Symbol/SymtabTest.cpp
index 76743c96cc502..e431c31e1eac1 100644
--- a/lldb/unittests/Symbol/SymtabTest.cpp
+++ b/lldb/unittests/Symbol/SymtabTest.cpp
@@ -756,4 +756,8 @@ TEST_F(SymtabTest, TestSymtabCreatedOnDemand) {
// But it should be created on demand.
module_symtab = module_sp->GetSymtab(/*can_create=*/true);
ASSERT_NE(module_symtab, nullptr);
+
+ // And we should be able to get it again once it has been created.
+ Symtab *cached_module_symtab = module_sp->GetSymtab(/*can_create=*/false);
+ ASSERT_EQ(module_symtab, cached_module_symtab);
}
More information about the lldb-commits
mailing list