Provide a mechanism to do some pre-loading of symbols up front.

Loading a shared library can require a large amount of work; rather than do that serially for each library,
this patch will allow parallelization of the symbols and debug info name indexes.

From scott.smith@purestorage.com

https://reviews.llvm.org/D32598

llvm-svn: 301609
This commit is contained in:
Jim Ingham 2017-04-28 00:51:06 +00:00
parent b242e93541
commit 7fca8c0757
11 changed files with 78 additions and 4 deletions

View File

@ -614,6 +614,8 @@ public:
const FileSpec &GetSymbolFileFileSpec() const { return m_symfile_spec; } const FileSpec &GetSymbolFileFileSpec() const { return m_symfile_spec; }
void PreloadSymbols();
void SetSymbolFileFileSpec(const FileSpec &file); void SetSymbolFileFileSpec(const FileSpec &file);
const llvm::sys::TimePoint<> &GetModificationTime() const { const llvm::sys::TimePoint<> &GetModificationTime() const {

View File

@ -180,6 +180,8 @@ public:
uint32_t type_mask, uint32_t type_mask,
lldb_private::TypeList &type_list) = 0; lldb_private::TypeList &type_list) = 0;
virtual void PreloadSymbols();
virtual lldb_private::TypeSystem * virtual lldb_private::TypeSystem *
GetTypeSystemForLanguage(lldb::LanguageType language); GetTypeSystemForLanguage(lldb::LanguageType language);

View File

@ -40,6 +40,7 @@ public:
Symtab(ObjectFile *objfile); Symtab(ObjectFile *objfile);
~Symtab(); ~Symtab();
void PreloadSymbols();
void Reserve(size_t count); void Reserve(size_t count);
Symbol *Resize(size_t count); Symbol *Resize(size_t count);
uint32_t AddSymbol(const Symbol &symbol); uint32_t AddSymbol(const Symbol &symbol);

View File

@ -82,6 +82,10 @@ public:
bool SetPreferDynamicValue(lldb::DynamicValueType d); bool SetPreferDynamicValue(lldb::DynamicValueType d);
bool GetPreloadSymbols() const;
void SetPreloadSymbols(bool b);
bool GetDisableASLR() const; bool GetDisableASLR() const;
void SetDisableASLR(bool b); void SetDisableASLR(bool b);

View File

@ -13,14 +13,13 @@ class SharedLibTestCase(TestBase):
mydir = TestBase.compute_mydir(__file__) mydir = TestBase.compute_mydir(__file__)
def test_expr(self): def common_test_expr(self, preload_symbols):
"""Test that types work when defined in a shared library and forward-declared in the main executable"""
if "clang" in self.getCompiler() and "3.4" in self.getCompilerVersion(): if "clang" in self.getCompiler() and "3.4" in self.getCompilerVersion():
self.skipTest( self.skipTest(
"llvm.org/pr16214 -- clang emits partial DWARF for structures referenced via typedef") "llvm.org/pr16214 -- clang emits partial DWARF for structures referenced via typedef")
self.build() self.build()
self.common_setup() self.common_setup(preload_symbols)
# This should display correctly. # This should display correctly.
self.expect( self.expect(
@ -31,6 +30,18 @@ class SharedLibTestCase(TestBase):
"(sub_foo)", "(sub_foo)",
"other_element = 3"]) "other_element = 3"])
self.expect(
"expression GetMeASubFoo(my_foo_ptr)",
startstr="(sub_foo *) $")
def test_expr(self):
"""Test that types work when defined in a shared library and forward-declared in the main executable"""
self.common_test_expr(True)
def test_expr_no_preload(self):
"""Test that types work when defined in a shared library and forward-declared in the main executable, but with preloading disabled"""
self.common_test_expr(False)
@unittest2.expectedFailure("rdar://problem/10704639") @unittest2.expectedFailure("rdar://problem/10704639")
def test_frame_variable(self): def test_frame_variable(self):
"""Test that types work when defined in a shared library and forward-declared in the main executable""" """Test that types work when defined in a shared library and forward-declared in the main executable"""
@ -54,7 +65,7 @@ class SharedLibTestCase(TestBase):
self.line = line_number(self.source, '// Set breakpoint 0 here.') self.line = line_number(self.source, '// Set breakpoint 0 here.')
self.shlib_names = ["foo"] self.shlib_names = ["foo"]
def common_setup(self): def common_setup(self, preload_symbols = True):
# Run in synchronous mode # Run in synchronous mode
self.dbg.SetAsync(False) self.dbg.SetAsync(False)
@ -62,6 +73,8 @@ class SharedLibTestCase(TestBase):
target = self.dbg.CreateTarget("a.out") target = self.dbg.CreateTarget("a.out")
self.assertTrue(target, VALID_TARGET) self.assertTrue(target, VALID_TARGET)
self.runCmd("settings set target.preload-symbols " + str(preload_symbols).lower())
# Break inside the foo function which takes a bar_ptr argument. # Break inside the foo function which takes a bar_ptr argument.
lldbutil.run_break_set_by_file_and_line( lldbutil.run_break_set_by_file_and_line(
self, self.source, self.line, num_expected_locations=1, loc_exact=True) self, self.source, self.line, num_expected_locations=1, loc_exact=True)

View File

@ -1432,6 +1432,22 @@ size_t Module::FindSymbolsMatchingRegExAndType(const RegularExpression &regex,
return sc_list.GetSize() - initial_size; return sc_list.GetSize() - initial_size;
} }
void Module::PreloadSymbols() {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
SymbolVendor * sym_vendor = GetSymbolVendor();
if (!sym_vendor) {
return;
}
// Prime the symbol file first, since it adds symbols to the symbol table.
if (SymbolFile *symbol_file = sym_vendor->GetSymbolFile()) {
symbol_file->PreloadSymbols();
}
// Now we can prime the symbol table.
if (Symtab * symtab = sym_vendor->GetSymtab()) {
symtab->PreloadSymbols();
}
}
void Module::SetSymbolFileFileSpec(const FileSpec &file) { void Module::SetSymbolFileFileSpec(const FileSpec &file) {
if (!file.Exists()) if (!file.Exists())
return; return;

View File

@ -1917,6 +1917,12 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const FileSpec &file_spec,
return sc_list.GetSize() - prev_size; return sc_list.GetSize() - prev_size;
} }
void SymbolFileDWARF::PreloadSymbols() {
std::lock_guard<std::recursive_mutex> guard(
GetObjectFile()->GetModule()->GetMutex());
Index();
}
void SymbolFileDWARF::Index() { void SymbolFileDWARF::Index() {
if (m_indexed) if (m_indexed)
return; return;

View File

@ -226,6 +226,8 @@ public:
const lldb_private::ConstString &name, const lldb_private::ConstString &name,
const lldb_private::CompilerDeclContext *parent_decl_ctx) override; const lldb_private::CompilerDeclContext *parent_decl_ctx) override;
void PreloadSymbols() override;
//------------------------------------------------------------------ //------------------------------------------------------------------
// PluginInterface protocol // PluginInterface protocol
//------------------------------------------------------------------ //------------------------------------------------------------------

View File

@ -21,6 +21,10 @@
using namespace lldb_private; using namespace lldb_private;
void SymbolFile::PreloadSymbols() {
// No-op for most implementations.
}
SymbolFile *SymbolFile::FindPlugin(ObjectFile *obj_file) { SymbolFile *SymbolFile::FindPlugin(ObjectFile *obj_file) {
std::unique_ptr<SymbolFile> best_symfile_ap; std::unique_ptr<SymbolFile> best_symfile_ap;
if (obj_file != nullptr) { if (obj_file != nullptr) {

View File

@ -427,6 +427,11 @@ void Symtab::InitNameIndexes() {
} }
} }
void Symtab::PreloadSymbols() {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
InitNameIndexes();
}
void Symtab::AppendSymbolNamesToMap(const IndexCollection &indexes, void Symtab::AppendSymbolNamesToMap(const IndexCollection &indexes,
bool add_demangled, bool add_mangled, bool add_demangled, bool add_mangled,
NameToIndexMap &name_to_index_map) const { NameToIndexMap &name_to_index_map) const {

View File

@ -1870,6 +1870,11 @@ ModuleSP Target::GetSharedModule(const ModuleSpec &module_spec,
} }
} }
// Preload symbols outside of any lock, so hopefully we can do this for
// each library in parallel.
if (GetPreloadSymbols())
module_sp->PreloadSymbols();
if (old_module_sp && if (old_module_sp &&
m_images.GetIndexForModule(old_module_sp.get()) != m_images.GetIndexForModule(old_module_sp.get()) !=
LLDB_INVALID_INDEX32) { LLDB_INVALID_INDEX32) {
@ -3277,6 +3282,8 @@ static PropertyDefinition g_properties[] = {
{"detach-on-error", OptionValue::eTypeBoolean, false, true, nullptr, {"detach-on-error", OptionValue::eTypeBoolean, false, true, nullptr,
nullptr, "debugserver will detach (rather than killing) a process if it " nullptr, "debugserver will detach (rather than killing) a process if it "
"loses connection with lldb."}, "loses connection with lldb."},
{"preload-symbols", OptionValue::eTypeBoolean, false, true, nullptr, nullptr,
"Enable loading of symbol tables before they are needed."},
{"disable-aslr", OptionValue::eTypeBoolean, false, true, nullptr, nullptr, {"disable-aslr", OptionValue::eTypeBoolean, false, true, nullptr, nullptr,
"Disable Address Space Layout Randomization (ASLR)"}, "Disable Address Space Layout Randomization (ASLR)"},
{"disable-stdio", OptionValue::eTypeBoolean, false, false, nullptr, nullptr, {"disable-stdio", OptionValue::eTypeBoolean, false, false, nullptr, nullptr,
@ -3379,6 +3386,7 @@ enum {
ePropertyOutputPath, ePropertyOutputPath,
ePropertyErrorPath, ePropertyErrorPath,
ePropertyDetachOnError, ePropertyDetachOnError,
ePropertyPreloadSymbols,
ePropertyDisableASLR, ePropertyDisableASLR,
ePropertyDisableSTDIO, ePropertyDisableSTDIO,
ePropertyInlineStrategy, ePropertyInlineStrategy,
@ -3641,6 +3649,17 @@ bool TargetProperties::SetPreferDynamicValue(lldb::DynamicValueType d) {
return m_collection_sp->SetPropertyAtIndexAsEnumeration(nullptr, idx, d); return m_collection_sp->SetPropertyAtIndexAsEnumeration(nullptr, idx, d);
} }
bool TargetProperties::GetPreloadSymbols() const {
const uint32_t idx = ePropertyPreloadSymbols;
return m_collection_sp->GetPropertyAtIndexAsBoolean(
nullptr, idx, g_properties[idx].default_uint_value != 0);
}
void TargetProperties::SetPreloadSymbols(bool b) {
const uint32_t idx = ePropertyPreloadSymbols;
m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b);
}
bool TargetProperties::GetDisableASLR() const { bool TargetProperties::GetDisableASLR() const {
const uint32_t idx = ePropertyDisableASLR; const uint32_t idx = ePropertyDisableASLR;
return m_collection_sp->GetPropertyAtIndexAsBoolean( return m_collection_sp->GetPropertyAtIndexAsBoolean(