Skip to content

Commit 172aa72

Browse files
royitaqiIanWood1
authored andcommitted
[lldb] Avoid force loading symbols in statistics collection (llvm#136236)
Currently, `DebuggerStats::ReportStatistics()` calls `Module::GetSymtab(/*can_create=*/false)`, but then the latter calls `SymbolFile::GetSymtab()`. This will load symbols if haven't yet. See stacktrace below. The problem is that `DebuggerStats::ReportStatistics` should be read-only. This is especially important because it reports stats for symtab parsing/indexing time, which could be affected by the reporting itself if it's not read-only. This patch fixes this problem by adding an optional parameter `SymbolFile::GetSymtab(bool can_create = true)` and receive the `false` value passed down from `Module::GetSymtab(/*can_create=*/false)` when the call was initiated from `DebuggerStats::ReportStatistics()`.
1 parent 3f61953 commit 172aa72

File tree

9 files changed

+111
-13
lines changed

9 files changed

+111
-13
lines changed

lldb/include/lldb/Symbol/ObjectFile.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ class ObjectFile : public std::enable_shared_from_this<ObjectFile>,
319319
///
320320
/// \return
321321
/// The symbol table for this object file.
322-
Symtab *GetSymtab();
322+
Symtab *GetSymtab(bool can_create = true);
323323

324324
/// Parse the symbol table into the provides symbol table object.
325325
///

lldb/include/lldb/Symbol/SymbolFile.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ class SymbolFile : public PluginInterface {
144144
virtual uint32_t GetNumCompileUnits() = 0;
145145
virtual lldb::CompUnitSP GetCompileUnitAtIndex(uint32_t idx) = 0;
146146

147-
virtual Symtab *GetSymtab() = 0;
147+
virtual Symtab *GetSymtab(bool can_create = true) = 0;
148148

149149
virtual lldb::LanguageType ParseLanguage(CompileUnit &comp_unit) = 0;
150150
/// Return the Xcode SDK comp_unit was compiled against.
@@ -533,7 +533,7 @@ class SymbolFileCommon : public SymbolFile {
533533
return m_abilities;
534534
}
535535

536-
Symtab *GetSymtab() override;
536+
Symtab *GetSymtab(bool can_create = true) override;
537537

538538
ObjectFile *GetObjectFile() override { return m_objfile_sp.get(); }
539539
const ObjectFile *GetObjectFile() const override {

lldb/include/lldb/Symbol/SymbolFileOnDemand.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,9 @@ class SymbolFileOnDemand : public lldb_private::SymbolFile {
186186

187187
uint32_t GetAbilities() override;
188188

189-
Symtab *GetSymtab() override { return m_sym_file_impl->GetSymtab(); }
189+
Symtab *GetSymtab(bool can_create = true) override {
190+
return m_sym_file_impl->GetSymtab(can_create);
191+
}
190192

191193
ObjectFile *GetObjectFile() override {
192194
return m_sym_file_impl->GetObjectFile();

lldb/source/Core/Module.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -997,7 +997,7 @@ SymbolFile *Module::GetSymbolFile(bool can_create, Stream *feedback_strm) {
997997

998998
Symtab *Module::GetSymtab(bool can_create) {
999999
if (SymbolFile *symbols = GetSymbolFile(can_create))
1000-
return symbols->GetSymtab();
1000+
return symbols->GetSymtab(can_create);
10011001
return nullptr;
10021002
}
10031003

lldb/source/Symbol/ObjectFile.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -734,10 +734,9 @@ void llvm::format_provider<ObjectFile::Strata>::format(
734734
}
735735
}
736736

737-
738-
Symtab *ObjectFile::GetSymtab() {
737+
Symtab *ObjectFile::GetSymtab(bool can_create) {
739738
ModuleSP module_sp(GetModule());
740-
if (module_sp) {
739+
if (module_sp && can_create) {
741740
// We can't take the module lock in ObjectFile::GetSymtab() or we can
742741
// deadlock in DWARF indexing when any file asks for the symbol table from
743742
// an object file. This currently happens in the preloading of symbols in

lldb/source/Symbol/SymbolFile.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,10 +152,10 @@ void SymbolFile::AssertModuleLock() {
152152

153153
SymbolFile::RegisterInfoResolver::~RegisterInfoResolver() = default;
154154

155-
Symtab *SymbolFileCommon::GetSymtab() {
155+
Symtab *SymbolFileCommon::GetSymtab(bool can_create) {
156156
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
157157
// Fetch the symtab from the main object file.
158-
auto *symtab = GetMainObjectFile()->GetSymtab();
158+
auto *symtab = GetMainObjectFile()->GetSymtab(can_create);
159159
if (m_symtab != symtab) {
160160
m_symtab = symtab;
161161

lldb/test/API/commands/statistics/basic/TestStats.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,29 @@ def test_default_no_run(self):
209209
)
210210
self.assertGreater(module_stats["symbolsLoaded"], 0)
211211

212+
def test_default_no_run_no_preload_symbols(self):
213+
"""Test "statistics dump" without running the target and without
214+
preloading symbols.
215+
216+
Checks that symbol count are zero.
217+
"""
218+
# Make sure symbols will not be preloaded.
219+
self.runCmd("settings set target.preload-symbols false")
220+
221+
# Build and load the target
222+
self.build()
223+
target = self.createTestTarget()
224+
225+
# Get statistics
226+
debug_stats = self.get_stats()
227+
228+
# No symbols should be loaded
229+
self.assertEqual(debug_stats["totalSymbolsLoaded"], 0)
230+
231+
# No symbols should be loaded in each module
232+
for module_stats in debug_stats["modules"]:
233+
self.assertEqual(module_stats["symbolsLoaded"], 0)
234+
212235
def test_default_with_run(self):
213236
"""Test "statistics dump" when running the target to a breakpoint.
214237

lldb/unittests/Symbol/LineTableTest.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class FakeSymbolFile : public SymbolFile {
5858
uint32_t CalculateAbilities() override { return UINT32_MAX; }
5959
uint32_t GetNumCompileUnits() override { return 1; }
6060
CompUnitSP GetCompileUnitAtIndex(uint32_t) override { return m_cu_sp; }
61-
Symtab *GetSymtab() override { return nullptr; }
61+
Symtab *GetSymtab(bool can_create = true) override { return nullptr; }
6262
LanguageType ParseLanguage(CompileUnit &) override { return eLanguageTypeC; }
6363
size_t ParseFunctions(CompileUnit &) override { return 0; }
6464
bool ParseLineTable(CompileUnit &) override { return true; }

lldb/unittests/Symbol/SymtabTest.cpp

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,7 @@ TEST_F(SymtabTest, TestDecodeCStringMaps) {
721721
ASSERT_NE(symbol, nullptr);
722722
}
723723

724-
TEST_F(SymtabTest, TestSymtabCreatedOnDemand) {
724+
TEST_F(SymtabTest, TestSymbolFileCreatedOnDemand) {
725725
auto ExpectedFile = TestFile::fromYaml(R"(
726726
--- !ELF
727727
FileHeader:
@@ -749,7 +749,7 @@ TEST_F(SymtabTest, TestSymtabCreatedOnDemand) {
749749
ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
750750
auto module_sp = std::make_shared<Module>(ExpectedFile->moduleSpec());
751751

752-
// The symbol table should not be loaded by default.
752+
// The symbol file should not be created by default.
753753
Symtab *module_symtab = module_sp->GetSymtab(/*can_create=*/false);
754754
ASSERT_EQ(module_symtab, nullptr);
755755

@@ -761,3 +761,77 @@ TEST_F(SymtabTest, TestSymtabCreatedOnDemand) {
761761
Symtab *cached_module_symtab = module_sp->GetSymtab(/*can_create=*/false);
762762
ASSERT_EQ(module_symtab, cached_module_symtab);
763763
}
764+
765+
TEST_F(SymtabTest, TestSymbolTableCreatedOnDemand) {
766+
const char *yamldata = R"(
767+
--- !ELF
768+
FileHeader:
769+
Class: ELFCLASS64
770+
Data: ELFDATA2LSB
771+
Type: ET_EXEC
772+
Machine: EM_386
773+
DWARF:
774+
debug_abbrev:
775+
- Table:
776+
- Code: 0x00000001
777+
Tag: DW_TAG_compile_unit
778+
Children: DW_CHILDREN_no
779+
Attributes:
780+
- Attribute: DW_AT_addr_base
781+
Form: DW_FORM_sec_offset
782+
debug_info:
783+
- Version: 5
784+
AddrSize: 4
785+
UnitType: DW_UT_compile
786+
Entries:
787+
- AbbrCode: 0x00000001
788+
Values:
789+
- Value: 0x8 # Offset of the first Address past the header
790+
- AbbrCode: 0x0
791+
debug_addr:
792+
- Version: 5
793+
AddressSize: 4
794+
Entries:
795+
- Address: 0x1234
796+
- Address: 0x5678
797+
debug_line:
798+
- Length: 42
799+
Version: 2
800+
PrologueLength: 36
801+
MinInstLength: 1
802+
DefaultIsStmt: 1
803+
LineBase: 251
804+
LineRange: 14
805+
OpcodeBase: 13
806+
StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]
807+
IncludeDirs:
808+
- '/tmp'
809+
Files:
810+
- Name: main.cpp
811+
DirIdx: 1
812+
ModTime: 0
813+
Length: 0
814+
)";
815+
llvm::Expected<TestFile> file = TestFile::fromYaml(yamldata);
816+
EXPECT_THAT_EXPECTED(file, llvm::Succeeded());
817+
auto module_sp = std::make_shared<Module>(file->moduleSpec());
818+
819+
SymbolFile *symbol_file = module_sp->GetSymbolFile();
820+
// At this point, the symbol table is not created. This is because the above
821+
// yaml data contains the necessary sections in order for
822+
// SymbolFileDWARF::CalculateAbilities() to identify all abilities, saving it
823+
// from calling SymbolFileDWARFDebugMap::CalculateAbilities(), which
824+
// eventually loads the symbol table, which we don't want.
825+
826+
// The symbol table should not be created if asked not to.
827+
Symtab *symtab = symbol_file->GetSymtab(/*can_create=*/false);
828+
ASSERT_EQ(symtab, nullptr);
829+
830+
// But it should be created on demand.
831+
symtab = symbol_file->GetSymtab(/*can_create=*/true);
832+
ASSERT_NE(symtab, nullptr);
833+
834+
// And we should be able to get it again once it has been created.
835+
Symtab *cached_symtab = symbol_file->GetSymtab(/*can_create=*/false);
836+
ASSERT_EQ(symtab, cached_symtab);
837+
}

0 commit comments

Comments
 (0)