Index: source/Plugins/SymbolFile/DWARF/DWARFUnit.h =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -13,6 +13,7 @@ #include "DWARFDIE.h" #include "DWARFDebugInfoEntry.h" #include "lldb/lldb-enumerations.h" +#include "llvm/Support/RWMutex.h" class DWARFUnit; class DWARFCompileUnit; @@ -196,6 +197,12 @@ // If this is a dwo compile unit this is the offset of the base compile unit // in the main object file dw_offset_t m_base_obj_offset = DW_INVALID_OFFSET; + mutable llvm::sys::RWMutex m_extractdies_mutex; + // It gets increased by ExtractDIEsIfNeeded(false) and decreased by ClearDIEs. + // BuildAddressRangeTable and SymbolFileDWARF::Index can populate m_die_array + // only temporarily while other functions calling only + // ExtractDIEsIfNeeded(false) will keep m_die_array populated forever. + uint32_t m_extractdies_count = 0; static void IndexPrivate(DWARFUnit *dwarf_cu, const lldb::LanguageType cu_language, @@ -215,6 +222,7 @@ // if needed. const DWARFDebugInfoEntry *GetUnitDIEPtrOnly() { ExtractDIEsIfNeeded(true); + // m_extractdies_mutex is not required as m_first_die is never cleared. if (!m_first_die) return NULL; return &m_first_die; @@ -223,6 +231,8 @@ // Get all DWARF debug informration entries. Parse all DIEs if needed. const DWARFDebugInfoEntry *DIEPtr() { ExtractDIEsIfNeeded(false); + // m_extractdies_mutex is not required as ExtractDIEsIfNeeded(false) has not + // been matched by ClearDIEs. if (m_die_array.empty()) return NULL; return &m_die_array[0]; Index: source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -41,9 +41,24 @@ // Parses a compile unit and indexes its DIEs if it hasn't already been done. //---------------------------------------------------------------------- size_t DWARFUnit::ExtractDIEsIfNeeded(bool cu_die_only) { - const size_t initial_die_array_size = m_die_array_size(); - if ((cu_die_only && initial_die_array_size > 0) || initial_die_array_size > 1) - return 0; // Already parsed + size_t initial_die_array_size; + auto already_parsed = [cu_die_only, &initial_die_array_size, this]() -> bool { + initial_die_array_size = m_die_array_size(); + return (cu_die_only && initial_die_array_size > 0) + || initial_die_array_size > 1; + }; + { + llvm::sys::ScopedReader lock(m_extractdies_mutex); + if (already_parsed()) + return 0; + } + llvm::sys::ScopedWriter lock(m_extractdies_mutex); + if (already_parsed()) + return 0; + // Protect against use count overflow. + if (!cu_die_only && m_extractdies_count + < std::numeric_limits::max()) + ++m_extractdies_count; static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); Timer scoped_timer( @@ -213,6 +228,7 @@ return m_first_die ? 1 : 0; } +// m_extractdies_mutex must be already held as read/write. void DWARFUnit::AddUnitDIE(DWARFDebugInfoEntry &die) { assert(m_die_array.empty() && "Compile unit DIE already added"); assert(!m_first_die); @@ -265,11 +281,14 @@ DWARFDIECollection &dies, uint32_t depth) const { size_t old_size = dies.Size(); - DWARFDebugInfoEntry::const_iterator pos; - DWARFDebugInfoEntry::const_iterator end = m_die_array.end(); - for (pos = m_die_array.begin(); pos != end; ++pos) { - if (pos->Tag() == tag) - dies.Append(DWARFDIE(this, &(*pos))); + { + llvm::sys::ScopedReader lock(m_extractdies_mutex); + DWARFDebugInfoEntry::const_iterator pos; + DWARFDebugInfoEntry::const_iterator end = m_die_array.end(); + for (pos = m_die_array.begin(); pos != end; ++pos) { + if (pos->Tag() == tag) + dies.Append(DWARFDIE(this, &(*pos))); + } } // Return the number of DIEs added to the collection @@ -310,9 +329,18 @@ m_base_obj_offset = base_obj_offset; } +// It may be called only after: ExtractDIEsIfNeeded(false) > 1 void DWARFUnit::ClearDIEs(bool keep_compile_unit_die) { - m_die_array.clear(); - m_die_array.shrink_to_fit(); + { + llvm::sys::ScopedWriter lock(m_extractdies_mutex); + lldbassert(m_die_array.size() > 1); + lldbassert(m_extractdies_count > 0); + if (--m_extractdies_count > 0) + return; + + m_die_array.clear(); + m_die_array.shrink_to_fit(); + } if (m_dwo_symbol_file) m_dwo_symbol_file->GetCompileUnit()->ClearDIEs(keep_compile_unit_die); @@ -434,7 +462,10 @@ void DWARFUnit::SetBaseAddress(dw_addr_t base_addr) { m_base_addr = base_addr; } -bool DWARFUnit::HasDIEsParsed() const { return m_die_array.size() > 1; } +bool DWARFUnit::HasDIEsParsed() const { + llvm::sys::ScopedReader lock(m_extractdies_mutex); + return m_die_array.size() > 1; +} //---------------------------------------------------------------------- // Compare function DWARFDebugAranges::Range structures @@ -459,6 +490,8 @@ if (ContainsDIEOffset(die_offset)) { ExtractDIEsIfNeeded(false); + // m_extractdies_mutex is not required as ExtractDIEsIfNeeded(false) has + // not been matched by ClearDIEs. DWARFDebugInfoEntry::const_iterator end = m_die_array.cend(); DWARFDebugInfoEntry::const_iterator pos = lower_bound(m_die_array.cbegin(), end, die_offset, CompareDIEOffset);