[NFC] Refactor symbol table parsing.

Symbol table parsing has evolved over the years and many plug-ins contained duplicate code in the ObjectFile::GetSymtab() that used to be pure virtual. With this change, the "Symbtab *ObjectFile::GetSymtab()" is no longer virtual and will end up calling a new "void ObjectFile::ParseSymtab(Symtab &symtab)" pure virtual function to actually do the parsing. This helps centralize the code for parsing the symbol table and allows the ObjectFile base class to do all of the common work, like taking the necessary locks and creating the symbol table object itself. Plug-ins now just need to parse when they are asked to parse as the ParseSymtab function will only get called once.

This is a retry of the original patch https://reviews.llvm.org/D113965 which was reverted. There was a deadlock in the Manual DWARF indexing code during symbol preloading where the module was asked on the main thread to preload its symbols, and this would in turn cause the DWARF manual indexing to use a thread pool to index all of the compile units, and if there were relocations on the debug information sections, these threads could ask the ObjectFile to load section contents, which could cause a call to ObjectFileELF::RelocateSection() which would ask for the symbol table from the module and it would deadlock. We can't lock the module in ObjectFile::GetSymtab(), so the solution I am using is to use a llvm::once_flag to create the symbol table object once and then lock the Symtab object. Since all APIs on the symbol table use this lock, this will prevent anyone from using the symbol table before it is parsed and finalized and will avoid the deadlock I mentioned. ObjectFileELF::GetSymtab() was never locking the module lock before and would put off creating the symbol table until somewhere inside ObjectFileELF::GetSymtab(). Now we create it one time inside of the ObjectFile::GetSymtab() and immediately lock it which should be safe enough. This avoids the deadlocks and still provides safety.

Differential Revision: https://reviews.llvm.org/D114288
This commit is contained in:
Greg Clayton 2021-11-17 21:18:24 -08:00
parent 80cdf0db67
commit 7e6df41f65
22 changed files with 355 additions and 375 deletions

View File

@ -19,6 +19,7 @@
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/UUID.h"
#include "lldb/lldb-private.h"
#include "llvm/Support/Threading.h"
#include "llvm/Support/VersionTuple.h"
namespace lldb_private {
@ -322,12 +323,26 @@ public:
/// Gets the symbol table for the currently selected architecture (and
/// object for archives).
///
/// Symbol table parsing can be deferred by ObjectFile instances until this
/// accessor is called the first time.
/// This function will manage when ParseSymtab(...) is called to actually do
/// the symbol table parsing in each plug-in. This function will take care of
/// taking all the necessary locks and finalizing the symbol table when the
/// symbol table does get parsed.
///
/// \return
/// The symbol table for this object file.
virtual Symtab *GetSymtab() = 0;
Symtab *GetSymtab();
/// Parse the symbol table into the provides symbol table object.
///
/// Symbol table parsing will be done once when this function is called by
/// each object file plugin. All of the necessary locks will already be
/// acquired before this function is called and the symbol table object to
/// populate is supplied as an argument and doesn't need to be created by
/// each plug-in.
///
/// \param
/// The symbol table to populate.
virtual void ParseSymtab(Symtab &symtab) = 0;
/// Perform relocations on the section if necessary.
///
@ -708,7 +723,12 @@ protected:
const lldb::addr_t m_memory_addr;
std::unique_ptr<lldb_private::SectionList> m_sections_up;
std::unique_ptr<lldb_private::Symtab> m_symtab_up;
uint32_t m_synthetic_symbol_idx;
/// We need a llvm::once_flag that we can use to avoid locking the module
/// lock and deadlocking LLDB. See comments in ObjectFile::GetSymtab() for
/// the full details. We also need to be able to clear the symbol table, so we
/// need to use a std::unique_ptr to a llvm::once_flag so if we clear the
/// symbol table, we can have a new once flag to use when it is created again.
std::unique_ptr<llvm::once_flag> m_symtab_once_up;
/// Sets the architecture for a module. At present the architecture can
/// only be set if it is invalid. It is not allowed to switch from one

View File

@ -119,20 +119,13 @@ public:
lldb::addr_t file_addr, std::function<bool(Symbol *)> const &callback);
void FindFunctionSymbols(ConstString name, uint32_t name_type_mask,
SymbolContextList &sc_list);
void CalculateSymbolSizes();
void SortSymbolIndexesByValue(std::vector<uint32_t> &indexes,
bool remove_duplicates) const;
static void DumpSymbolHeader(Stream *s);
void Finalize() {
// Shrink to fit the symbols so we don't waste memory
if (m_symbols.capacity() > m_symbols.size()) {
collection new_symbols(m_symbols.begin(), m_symbols.end());
m_symbols.swap(new_symbols);
}
}
void Finalize();
void AppendSymbolNamesToMap(const IndexCollection &indexes,
bool add_demangled, bool add_mangled,

View File

@ -1379,12 +1379,15 @@ void Module::PreloadSymbols() {
if (!sym_file)
return;
// Prime the symbol file first, since it adds symbols to the symbol table.
sym_file->PreloadSymbols();
// Now we can prime the symbol table.
// Load the object file symbol table and any symbols from the SymbolFile that
// get appended using SymbolFile::AddSymbols(...).
if (Symtab *symtab = sym_file->GetSymtab())
symtab->PreloadSymbols();
// Now let the symbol file preload its data and the symbol table will be
// available without needing to take the module lock.
sym_file->PreloadSymbols();
}
void Module::SetSymbolFileFileSpec(const FileSpec &file) {

View File

@ -116,9 +116,10 @@ bool ObjectFileBreakpad::ParseHeader() {
return true;
}
Symtab *ObjectFileBreakpad::GetSymtab() {
// TODO
return nullptr;
void ObjectFileBreakpad::ParseSymtab(Symtab &symtab) {
// Nothing to do for breakpad files, all information is parsed as debug info
// which means "lldb_private::Function" objects are used, or symbols are added
// by the SymbolFileBreakpad::AddSymbols(...) function in the symbol file.
}
void ObjectFileBreakpad::CreateSections(SectionList &unified_section_list) {

View File

@ -71,7 +71,7 @@ public:
return AddressClass::eInvalid;
}
Symtab *GetSymtab() override;
void ParseSymtab(lldb_private::Symtab &symtab) override;
bool IsStripped() override { return false; }

View File

@ -2687,28 +2687,27 @@ unsigned ObjectFileELF::RelocateDebugSections(const ELFSectionHeader *rel_hdr,
return 0;
}
Symtab *ObjectFileELF::GetSymtab() {
void ObjectFileELF::ParseSymtab(Symtab &lldb_symtab) {
ModuleSP module_sp(GetModule());
if (!module_sp)
return nullptr;
return;
Progress progress(
llvm::formatv("Parsing symbol table for {0}",
m_file.GetFilename().AsCString("<Unknown>")));
ElapsedTime elapsed(module_sp->GetSymtabParseTime());
// We always want to use the main object file so we (hopefully) only have one
// cached copy of our symtab, dynamic sections, etc.
ObjectFile *module_obj_file = module_sp->GetObjectFile();
if (module_obj_file && module_obj_file != this)
return module_obj_file->GetSymtab();
return module_obj_file->ParseSymtab(lldb_symtab);
if (m_symtab_up == nullptr) {
Progress progress(
llvm::formatv("Parsing symbol table for {0}",
m_file.GetFilename().AsCString("<Unknown>")));
ElapsedTime elapsed(module_sp->GetSymtabParseTime());
SectionList *section_list = module_sp->GetSectionList();
if (!section_list)
return nullptr;
return;
uint64_t symbol_id = 0;
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
// Sharable objects and dynamic executables usually have 2 distinct symbol
// tables, one named ".symtab", and the other ".dynsym". The dynsym is a
@ -2717,10 +2716,8 @@ Symtab *ObjectFileELF::GetSymtab() {
// while the reverse is not necessarily true.
Section *symtab =
section_list->FindSectionByType(eSectionTypeELFSymbolTable, true).get();
if (symtab) {
m_symtab_up = std::make_unique<Symtab>(symtab->GetObjectFile());
symbol_id += ParseSymbolTable(m_symtab_up.get(), symbol_id, symtab);
}
if (symtab)
symbol_id += ParseSymbolTable(&lldb_symtab, symbol_id, symtab);
// The symtab section is non-allocable and can be stripped, while the
// .dynsym section which should always be always be there. To support the
@ -2733,11 +2730,8 @@ Symtab *ObjectFileELF::GetSymtab() {
Section *dynsym =
section_list->FindSectionByType(eSectionTypeELFDynamicSymbols, true)
.get();
if (dynsym) {
if (!m_symtab_up)
m_symtab_up = std::make_unique<Symtab>(dynsym->GetObjectFile());
symbol_id += ParseSymbolTable(m_symtab_up.get(), symbol_id, dynsym);
}
if (dynsym)
symbol_id += ParseSymbolTable(&lldb_symtab, symbol_id, dynsym);
}
// DT_JMPREL
@ -2759,29 +2753,16 @@ Symtab *ObjectFileELF::GetSymtab() {
user_id_t reloc_id = reloc_section->GetID();
const ELFSectionHeaderInfo *reloc_header =
GetSectionHeaderByIndex(reloc_id);
if (reloc_header) {
if (m_symtab_up == nullptr)
m_symtab_up =
std::make_unique<Symtab>(reloc_section->GetObjectFile());
ParseTrampolineSymbols(m_symtab_up.get(), symbol_id, reloc_header,
reloc_id);
}
if (reloc_header)
ParseTrampolineSymbols(&lldb_symtab, symbol_id, reloc_header, reloc_id);
}
}
if (DWARFCallFrameInfo *eh_frame =
GetModule()->GetUnwindTable().GetEHFrameInfo()) {
if (m_symtab_up == nullptr)
m_symtab_up = std::make_unique<Symtab>(this);
ParseUnwindSymbols(m_symtab_up.get(), eh_frame);
ParseUnwindSymbols(&lldb_symtab, eh_frame);
}
// If we still don't have any symtab then create an empty instance to avoid
// do the section lookup next time.
if (m_symtab_up == nullptr)
m_symtab_up = std::make_unique<Symtab>(this);
// In the event that there's no symbol entry for the entry point we'll
// artificially create one. We delegate to the symtab object the figuring
// out of the proper size, this will usually make it span til the next
@ -2795,9 +2776,9 @@ Symtab *ObjectFileELF::GetSymtab() {
bool is_valid_entry_point =
entry_point_addr.IsValid() && entry_point_addr.IsSectionOffset();
addr_t entry_point_file_addr = entry_point_addr.GetFileAddress();
if (is_valid_entry_point && !m_symtab_up->FindSymbolContainingFileAddress(
if (is_valid_entry_point && !lldb_symtab.FindSymbolContainingFileAddress(
entry_point_file_addr)) {
uint64_t symbol_id = m_symtab_up->GetNumSymbols();
uint64_t symbol_id = lldb_symtab.GetNumSymbols();
// Don't set the name for any synthetic symbols, the Symbol
// object will generate one if needed when the name is accessed
// via accessors.
@ -2828,14 +2809,9 @@ Symtab *ObjectFileELF::GetSymtab() {
} else {
m_address_class_map[entry_point_file_addr] = AddressClass::eCode;
}
m_symtab_up->AddSymbol(symbol);
lldb_symtab.AddSymbol(symbol);
}
}
m_symtab_up->CalculateSymbolSizes();
}
return m_symtab_up.get();
}
void ObjectFileELF::RelocateSection(lldb_private::Section *section)

View File

@ -110,7 +110,7 @@ public:
lldb_private::AddressClass GetAddressClass(lldb::addr_t file_addr) override;
lldb_private::Symtab *GetSymtab() override;
void ParseSymtab(lldb_private::Symtab &symtab) override;
bool IsStripped() override;
@ -278,8 +278,9 @@ private:
/// number of dynamic symbols parsed.
size_t ParseDynamicSymbols();
/// Populates m_symtab_up will all non-dynamic linker symbols. This method
/// will parse the symbols only once. Returns the number of symbols parsed.
/// Populates the symbol table with all non-dynamic linker symbols. This
/// method will parse the symbols only once. Returns the number of symbols
/// parsed.
unsigned ParseSymbolTable(lldb_private::Symtab *symbol_table,
lldb::user_id_t start_id,
lldb_private::Section *symtab);

View File

@ -106,23 +106,10 @@ uint32_t ObjectFileJIT::GetAddressByteSize() const {
return m_data.GetAddressByteSize();
}
Symtab *ObjectFileJIT::GetSymtab() {
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
if (m_symtab_up == nullptr) {
ElapsedTime elapsed(module_sp->GetSymtabParseTime());
m_symtab_up = std::make_unique<Symtab>(this);
std::lock_guard<std::recursive_mutex> symtab_guard(
m_symtab_up->GetMutex());
void ObjectFileJIT::ParseSymtab(Symtab &symtab) {
ObjectFileJITDelegateSP delegate_sp(m_delegate_wp.lock());
if (delegate_sp)
delegate_sp->PopulateSymtab(this, *m_symtab_up);
// TODO: get symbols from delegate
m_symtab_up->Finalize();
}
}
return m_symtab_up.get();
delegate_sp->PopulateSymtab(this, symtab);
}
bool ObjectFileJIT::IsStripped() {

View File

@ -67,7 +67,7 @@ public:
uint32_t GetAddressByteSize() const override;
lldb_private::Symtab *GetSymtab() override;
void ParseSymtab(lldb_private::Symtab &symtab) override;
bool IsStripped() override;

View File

@ -1311,22 +1311,6 @@ AddressClass ObjectFileMachO::GetAddressClass(lldb::addr_t file_addr) {
return AddressClass::eUnknown;
}
Symtab *ObjectFileMachO::GetSymtab() {
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
if (m_symtab_up == nullptr) {
ElapsedTime elapsed(module_sp->GetSymtabParseTime());
m_symtab_up = std::make_unique<Symtab>(this);
std::lock_guard<std::recursive_mutex> symtab_guard(
m_symtab_up->GetMutex());
ParseSymtab();
m_symtab_up->Finalize();
}
}
return m_symtab_up.get();
}
bool ObjectFileMachO::IsStripped() {
if (m_dysymtab.cmd == 0) {
ModuleSP module_sp(GetModule());
@ -2233,12 +2217,12 @@ ParseNList(DataExtractor &nlist_data, lldb::offset_t &nlist_data_offset,
enum { DebugSymbols = true, NonDebugSymbols = false };
size_t ObjectFileMachO::ParseSymtab() {
void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
LLDB_SCOPED_TIMERF("ObjectFileMachO::ParseSymtab () module = %s",
m_file.GetFilename().AsCString(""));
ModuleSP module_sp(GetModule());
if (!module_sp)
return 0;
return;
Progress progress(llvm::formatv("Parsing symbol table for {0}",
m_file.GetFilename().AsCString("<Unknown>")));
@ -2288,7 +2272,7 @@ size_t ObjectFileMachO::ParseSymtab() {
// Read in the rest of the symtab load command
if (m_data.GetU32(&offset, &symtab_load_command.symoff, 4) ==
nullptr) // fill in symoff, nsyms, stroff, strsize fields
return 0;
return;
break;
case LC_DYLD_INFO:
@ -2347,12 +2331,11 @@ size_t ObjectFileMachO::ParseSymtab() {
}
if (!symtab_load_command.cmd)
return 0;
return;
Symtab *symtab = m_symtab_up.get();
SectionList *section_list = GetSectionList();
if (section_list == nullptr)
return 0;
return;
const uint32_t addr_byte_size = m_data.GetAddressByteSize();
const ByteOrder byte_order = m_data.GetByteOrder();
@ -2881,10 +2864,10 @@ size_t ObjectFileMachO::ParseSymtab() {
// The normal nlist code cannot correctly size the Symbols
// array, we need to allocate it here.
sym = symtab->Resize(
sym = symtab.Resize(
symtab_load_command.nsyms + m_dysymtab.nindirectsyms +
unmapped_local_symbols_found - m_dysymtab.nlocalsym);
num_syms = symtab->GetNumSymbols();
num_syms = symtab.GetNumSymbols();
nlist_data_offset =
local_symbols_info.nlistOffset +
@ -3016,7 +2999,7 @@ size_t ObjectFileMachO::ParseSymtab() {
// original
// STAB entry so we don't have
// to hunt for it later
symtab->SymbolAtIndex(N_FUN_indexes.back())
symtab.SymbolAtIndex(N_FUN_indexes.back())
->SetByteSize(nlist.n_value);
N_FUN_indexes.pop_back();
// We don't really need the end function STAB as
@ -3096,7 +3079,7 @@ size_t ObjectFileMachO::ParseSymtab() {
// index of this N_SO so that we can always skip
// the entire N_SO if we need to navigate more
// quickly at the source level when parsing STABS
symbol_ptr = symtab->SymbolAtIndex(N_SO_index);
symbol_ptr = symtab.SymbolAtIndex(N_SO_index);
symbol_ptr->SetByteSize(sym_idx);
symbol_ptr->SetSizeIsSibling(true);
}
@ -3203,7 +3186,7 @@ size_t ObjectFileMachO::ParseSymtab() {
// quickly at the source level when parsing STABS
if (!N_INCL_indexes.empty()) {
symbol_ptr =
symtab->SymbolAtIndex(N_INCL_indexes.back());
symtab.SymbolAtIndex(N_INCL_indexes.back());
symbol_ptr->SetByteSize(sym_idx + 1);
symbol_ptr->SetSizeIsSibling(true);
N_INCL_indexes.pop_back();
@ -3268,7 +3251,7 @@ size_t ObjectFileMachO::ParseSymtab() {
nlist.n_value);
if (!N_BRAC_indexes.empty()) {
symbol_ptr =
symtab->SymbolAtIndex(N_BRAC_indexes.back());
symtab.SymbolAtIndex(N_BRAC_indexes.back());
symbol_ptr->SetByteSize(sym_idx + 1);
symbol_ptr->SetSizeIsSibling(true);
N_BRAC_indexes.pop_back();
@ -3306,7 +3289,7 @@ size_t ObjectFileMachO::ParseSymtab() {
// parsing STABS
if (!N_COMM_indexes.empty()) {
symbol_ptr =
symtab->SymbolAtIndex(N_COMM_indexes.back());
symtab.SymbolAtIndex(N_COMM_indexes.back());
symbol_ptr->SetByteSize(sym_idx + 1);
symbol_ptr->SetSizeIsSibling(true);
N_COMM_indexes.pop_back();
@ -3806,8 +3789,8 @@ size_t ObjectFileMachO::ParseSymtab() {
// symbols, create it now.
if (sym == nullptr) {
sym =
symtab->Resize(symtab_load_command.nsyms + m_dysymtab.nindirectsyms);
num_syms = symtab->GetNumSymbols();
symtab.Resize(symtab_load_command.nsyms + m_dysymtab.nindirectsyms);
num_syms = symtab.GetNumSymbols();
}
if (unmapped_local_symbols_found) {
@ -3941,7 +3924,7 @@ size_t ObjectFileMachO::ParseSymtab() {
if (!N_FUN_indexes.empty()) {
// Copy the size of the function into the original STAB entry
// so we don't have to hunt for it later
symtab->SymbolAtIndex(N_FUN_indexes.back())
symtab.SymbolAtIndex(N_FUN_indexes.back())
->SetByteSize(nlist.n_value);
N_FUN_indexes.pop_back();
// We don't really need the end function STAB as it contains
@ -4015,7 +3998,7 @@ size_t ObjectFileMachO::ParseSymtab() {
// N_SO so that we can always skip the entire N_SO if we need
// to navigate more quickly at the source level when parsing
// STABS
symbol_ptr = symtab->SymbolAtIndex(N_SO_index);
symbol_ptr = symtab.SymbolAtIndex(N_SO_index);
symbol_ptr->SetByteSize(sym_idx);
symbol_ptr->SetSizeIsSibling(true);
}
@ -4109,7 +4092,7 @@ size_t ObjectFileMachO::ParseSymtab() {
// N_EINCL so that we can always skip the entire symbol if we need
// to navigate more quickly at the source level when parsing STABS
if (!N_INCL_indexes.empty()) {
symbol_ptr = symtab->SymbolAtIndex(N_INCL_indexes.back());
symbol_ptr = symtab.SymbolAtIndex(N_INCL_indexes.back());
symbol_ptr->SetByteSize(sym_idx + 1);
symbol_ptr->SetSizeIsSibling(true);
N_INCL_indexes.pop_back();
@ -4168,7 +4151,7 @@ size_t ObjectFileMachO::ParseSymtab() {
// quickly at the source level when parsing STABS
symbol_section = section_info.GetSection(nlist.n_sect, nlist.n_value);
if (!N_BRAC_indexes.empty()) {
symbol_ptr = symtab->SymbolAtIndex(N_BRAC_indexes.back());
symbol_ptr = symtab.SymbolAtIndex(N_BRAC_indexes.back());
symbol_ptr->SetByteSize(sym_idx + 1);
symbol_ptr->SetSizeIsSibling(true);
N_BRAC_indexes.pop_back();
@ -4202,7 +4185,7 @@ size_t ObjectFileMachO::ParseSymtab() {
// we need to navigate more quickly at the source level when
// parsing STABS
if (!N_COMM_indexes.empty()) {
symbol_ptr = symtab->SymbolAtIndex(N_COMM_indexes.back());
symbol_ptr = symtab.SymbolAtIndex(N_COMM_indexes.back());
symbol_ptr->SetByteSize(sym_idx + 1);
symbol_ptr->SetSizeIsSibling(true);
N_COMM_indexes.pop_back();
@ -4658,7 +4641,7 @@ size_t ObjectFileMachO::ParseSymtab() {
if (num_syms < sym_idx + trie_symbol_table_augment_count) {
num_syms = sym_idx + trie_symbol_table_augment_count;
sym = symtab->Resize(num_syms);
sym = symtab.Resize(num_syms);
}
uint32_t synthetic_sym_id = symtab_load_command.nsyms;
@ -4707,7 +4690,7 @@ size_t ObjectFileMachO::ParseSymtab() {
if (num_synthetic_function_symbols > 0) {
if (num_syms < sym_idx + num_synthetic_function_symbols) {
num_syms = sym_idx + num_synthetic_function_symbols;
sym = symtab->Resize(num_syms);
sym = symtab.Resize(num_syms);
}
for (i = 0; i < function_starts_count; ++i) {
const FunctionStarts::Entry *func_start_entry =
@ -4762,7 +4745,7 @@ size_t ObjectFileMachO::ParseSymtab() {
// symbols.
if (sym_idx < num_syms) {
num_syms = sym_idx;
sym = symtab->Resize(num_syms);
sym = symtab.Resize(num_syms);
}
// Now synthesize indirect symbols
@ -4807,11 +4790,11 @@ size_t ObjectFileMachO::ParseSymtab() {
if (index_pos != end_index_pos) {
// We have a remapping from the original nlist index to a
// current symbol index, so just look this up by index
stub_symbol = symtab->SymbolAtIndex(index_pos->second);
stub_symbol = symtab.SymbolAtIndex(index_pos->second);
} else {
// We need to lookup a symbol using the original nlist symbol
// index since this index is coming from the S_SYMBOL_STUBS
stub_symbol = symtab->FindSymbolByID(stub_sym_id);
stub_symbol = symtab.FindSymbolByID(stub_sym_id);
}
if (stub_symbol) {
@ -4834,7 +4817,7 @@ size_t ObjectFileMachO::ParseSymtab() {
// Make a synthetic symbol to describe the trampoline stub
Mangled stub_symbol_mangled_name(stub_symbol->GetMangled());
if (sym_idx >= num_syms) {
sym = symtab->Resize(++num_syms);
sym = symtab.Resize(++num_syms);
stub_symbol = nullptr; // this pointer no longer valid
}
sym[sym_idx].SetID(synthetic_sym_id++);
@ -4873,7 +4856,7 @@ size_t ObjectFileMachO::ParseSymtab() {
indirect_symbol_names.end()) {
// Make a synthetic symbol to describe re-exported symbol.
if (sym_idx >= num_syms)
sym = symtab->Resize(++num_syms);
sym = symtab.Resize(++num_syms);
sym[sym_idx].SetID(synthetic_sym_id++);
sym[sym_idx].GetMangled() = Mangled(e.entry.name);
sym[sym_idx].SetType(eSymbolTypeReExported);
@ -4888,18 +4871,6 @@ size_t ObjectFileMachO::ParseSymtab() {
}
}
}
// StreamFile s(stdout, false);
// s.Printf ("Symbol table before CalculateSymbolSizes():\n");
// symtab->Dump(&s, NULL, eSortOrderNone);
// Set symbol byte sizes correctly since mach-o nlist entries don't have
// sizes
symtab->CalculateSymbolSizes();
// s.Printf ("Symbol table after CalculateSymbolSizes():\n");
// symtab->Dump(&s, NULL, eSortOrderNone);
return symtab->GetNumSymbols();
}
void ObjectFileMachO::Dump(Stream *s) {

View File

@ -92,7 +92,7 @@ public:
lldb_private::AddressClass GetAddressClass(lldb::addr_t file_addr) override;
lldb_private::Symtab *GetSymtab() override;
void ParseSymtab(lldb_private::Symtab &symtab) override;
bool IsStripped() override;

View File

@ -68,7 +68,7 @@ public:
bool IsExecutable() const override { return false; }
Symtab *GetSymtab() override { return nullptr; }
void ParseSymtab(lldb_private::Symtab &symtab) override {}
bool IsStripped() override { return false; }

View File

@ -589,19 +589,9 @@ llvm::StringRef ObjectFilePECOFF::GetSectionName(const section_header_t &sect) {
return hdr_name;
}
// GetNListSymtab
Symtab *ObjectFilePECOFF::GetSymtab() {
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
if (m_symtab_up == nullptr) {
ElapsedTime elapsed(module_sp->GetSymtabParseTime());
void ObjectFilePECOFF::ParseSymtab(Symtab &symtab) {
SectionList *sect_list = GetSectionList();
m_symtab_up = std::make_unique<Symtab>(this);
std::lock_guard<std::recursive_mutex> guard(m_symtab_up->GetMutex());
const uint32_t num_syms = m_coff_header.nsyms;
if (m_file && num_syms > 0 && m_coff_header.symoff > 0) {
const uint32_t symbol_size = 18;
const size_t symbol_data_size = num_syms * symbol_size;
@ -616,7 +606,7 @@ Symtab *ObjectFilePECOFF::GetSymtab() {
offset = 0;
std::string symbol_name;
Symbol *symbols = m_symtab_up->Resize(num_syms);
Symbol *symbols = symtab.Resize(num_syms);
for (uint32_t i = 0; i < num_syms; ++i) {
coff_symbol_t symbol;
const uint32_t symbol_offset = offset;
@ -691,7 +681,7 @@ Symtab *ObjectFilePECOFF::GetSymtab() {
lldb::offset_t name_ordinal_offset =
export_table.address_of_name_ordinals - data_start;
Symbol *symbols = m_symtab_up->Resize(export_table.number_of_names);
Symbol *symbols = symtab.Resize(export_table.number_of_names);
std::string symbol_name;
@ -718,10 +708,6 @@ Symtab *ObjectFilePECOFF::GetSymtab() {
symbols[i].SetDebug(true);
}
}
m_symtab_up->CalculateSymbolSizes();
}
}
return m_symtab_up.get();
}
std::unique_ptr<CallFrameInfo> ObjectFilePECOFF::CreateCallFrameInfo() {

View File

@ -107,7 +107,7 @@ public:
// virtual lldb_private::AddressClass
// GetAddressClass (lldb::addr_t file_addr);
lldb_private::Symtab *GetSymtab() override;
void ParseSymtab(lldb_private::Symtab &symtab) override;
bool IsStripped() override;

View File

@ -246,7 +246,7 @@ bool ObjectFileWasm::ParseHeader() {
return true;
}
Symtab *ObjectFileWasm::GetSymtab() { return nullptr; }
void ObjectFileWasm::ParseSymtab(Symtab &symtab) {}
static SectionType GetSectionTypeFromName(llvm::StringRef Name) {
if (Name.consume_front(".debug_") || Name.consume_front(".zdebug_")) {

View File

@ -78,7 +78,7 @@ public:
return AddressClass::eInvalid;
}
Symtab *GetSymtab() override;
void ParseSymtab(lldb_private::Symtab &symtab) override;
bool IsStripped() override { return !!GetExternalDebugInfoFileSpec(); }

View File

@ -73,7 +73,7 @@ public:
bool IsExecutable() const override { return false; }
ArchSpec GetArchitecture() override { return m_arch; }
UUID GetUUID() override { return m_uuid; }
Symtab *GetSymtab() override { return m_symtab_up.get(); }
void ParseSymtab(lldb_private::Symtab &symtab) override {}
bool IsStripped() override { return true; }
ByteOrder GetByteOrder() const override { return m_arch.GetByteOrder(); }

View File

@ -500,7 +500,7 @@ void SymbolFileBreakpad::AddSymbols(Symtab &symtab) {
for (Symbol &symbol : symbols)
symtab.AddSymbol(std::move(symbol));
symtab.CalculateSymbolSizes();
symtab.Finalize();
}
llvm::Expected<lldb::addr_t>
@ -927,4 +927,3 @@ uint64_t SymbolFileBreakpad::GetDebugInfoSize() {
// Breakpad files are all debug info.
return m_objfile_sp->GetByteSize();
}

View File

@ -2067,6 +2067,13 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(
}
void SymbolFileDWARF::PreloadSymbols() {
// Get the symbol table for the symbol file prior to taking the module lock
// so that it is available without needing to take the module lock. The DWARF
// indexing might end up needing to relocate items when DWARF sections are
// loaded as they might end up getting the section contents which can call
// ObjectFileELF::RelocateSection() which in turn will ask for the symbol
// table and can cause deadlocks.
GetSymtab();
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
m_index->Preload();
}

View File

@ -1421,7 +1421,6 @@ void SymbolFilePDB::AddSymbols(lldb_private::Symtab &symtab) {
));
}
symtab.CalculateSymbolSizes();
symtab.Finalize();
}

View File

@ -244,7 +244,7 @@ ObjectFile::ObjectFile(const lldb::ModuleSP &module_sp,
m_type(eTypeInvalid), m_strata(eStrataInvalid),
m_file_offset(file_offset), m_length(length), m_data(), m_process_wp(),
m_memory_addr(LLDB_INVALID_ADDRESS), m_sections_up(), m_symtab_up(),
m_synthetic_symbol_idx(0) {
m_symtab_once_up(new llvm::once_flag()) {
if (file_spec_ptr)
m_file = *file_spec_ptr;
if (data_sp)
@ -265,7 +265,7 @@ ObjectFile::ObjectFile(const lldb::ModuleSP &module_sp,
: ModuleChild(module_sp), m_file(), m_type(eTypeInvalid),
m_strata(eStrataInvalid), m_file_offset(0), m_length(0), m_data(),
m_process_wp(process_sp), m_memory_addr(header_addr), m_sections_up(),
m_symtab_up(), m_synthetic_symbol_idx(0) {
m_symtab_up(), m_symtab_once_up(new llvm::once_flag()) {
if (header_data_sp)
m_data.SetData(header_data_sp, 0, header_data_sp->GetByteSize());
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT));
@ -571,11 +571,13 @@ bool ObjectFile::SplitArchivePathWithObject(llvm::StringRef path_with_object,
void ObjectFile::ClearSymtab() {
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT));
LLDB_LOGF(log, "%p ObjectFile::ClearSymtab () symtab = %p",
static_cast<void *>(this),
static_cast<void *>(m_symtab_up.get()));
// Since we need to clear the symbol table, we need a new llvm::once_flag
// instance so we can safely create another symbol table
m_symtab_once_up.reset(new llvm::once_flag());
m_symtab_up.reset();
}
}
@ -715,3 +717,33 @@ void llvm::format_provider<ObjectFile::Strata>::format(
break;
}
}
Symtab *ObjectFile::GetSymtab() {
ModuleSP module_sp(GetModule());
if (module_sp) {
// We can't take the module lock in ObjectFile::GetSymtab() or we can
// deadlock in DWARF indexing when any file asks for the symbol table from
// an object file. This currently happens in the preloading of symbols in
// SymbolFileDWARF::PreloadSymbols() because the main thread will take the
// module lock, and then threads will be spun up to index the DWARF and
// any of those threads might end up trying to relocate items in the DWARF
// sections which causes ObjectFile::GetSectionData(...) to relocate section
// data which requires the symbol table.
//
// So to work around this, we create the symbol table one time using
// llvm::once_flag, lock it, and then set the unique pointer. Any other
// thread that gets ahold of the symbol table before parsing is done, will
// not be able to access the symbol table contents since all APIs in Symtab
// are protected by a mutex in the Symtab object itself.
llvm::call_once(*m_symtab_once_up, [&]() {
ElapsedTime elapsed(module_sp->GetSymtabParseTime());
Symtab *symtab = new Symtab(this);
std::lock_guard<std::recursive_mutex> symtab_guard(symtab->GetMutex());
m_symtab_up.reset(symtab);
ParseSymtab(*m_symtab_up);
m_symtab_up->Finalize();
});
}
return m_symtab_up.get();
}

View File

@ -997,10 +997,15 @@ void Symtab::InitAddressIndexes() {
}
}
void Symtab::CalculateSymbolSizes() {
void Symtab::Finalize() {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
// Size computation happens inside InitAddressIndexes.
// Calculate the size of symbols inside InitAddressIndexes.
InitAddressIndexes();
// Shrink to fit the symbols so we don't waste memory
if (m_symbols.capacity() > m_symbols.size()) {
collection new_symbols(m_symbols.begin(), m_symbols.end());
m_symbols.swap(new_symbols);
}
}
Symbol *Symtab::FindSymbolAtFileAddress(addr_t file_addr) {