diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h @@ -25,6 +25,7 @@ #include "llvm/TargetParser/Host.h" #include #include +#include namespace llvm { @@ -45,69 +46,86 @@ /// This data structure is the top level entity that deals with dwarf debug /// information parsing. The actual data is supplied through DWARFObj. class DWARFContext : public DIContext { - DWARFUnitVector NormalUnits; - std::optional> NormalTypeUnits; - std::unique_ptr CUIndex; - std::unique_ptr GdbIndex; - std::unique_ptr TUIndex; - std::unique_ptr Abbrev; - std::unique_ptr Loc; - std::unique_ptr Aranges; - std::unique_ptr Line; - std::unique_ptr DebugFrame; - std::unique_ptr EHFrame; - std::unique_ptr Macro; - std::unique_ptr Macinfo; - std::unique_ptr Names; - std::unique_ptr AppleNames; - std::unique_ptr AppleTypes; - std::unique_ptr AppleNamespaces; - std::unique_ptr AppleObjC; - - DWARFUnitVector DWOUnits; - std::optional> DWOTypeUnits; - std::unique_ptr AbbrevDWO; - std::unique_ptr MacinfoDWO; - std::unique_ptr MacroDWO; +public: + /// DWARFContextState + /// This structure contains all member variables for DWARFContext that need + /// to be protected in multi-threaded environments. Threading support can be + /// enabled by setting the ThreadSafe to true when constructing a + /// DWARFContext to allow DWARRContext to be able to be used in a + /// multi-threaded environment, or not enabled to allow for maximum + /// performance in single threaded environments. + class DWARFContextState { + protected: + /// Helper enum to distinguish between macro[.dwo] and macinfo[.dwo] + /// section. + enum MacroSecType { + MacinfoSection, + MacinfoDwoSection, + MacroSection, + MacroDwoSection + }; + + DWARFContext &D; + public: + DWARFContextState(DWARFContext &DC) : D(DC) {} + virtual ~DWARFContextState() = default; + virtual DWARFUnitVector &getNormalUnits() = 0; + virtual DWARFUnitVector &getDWOUnits(bool Lazy = false) = 0; + virtual const DWARFDebugAbbrev *getDebugAbbrevDWO() = 0; + virtual const DWARFUnitIndex &getCUIndex() = 0; + virtual const DWARFUnitIndex &getTUIndex() = 0; + virtual DWARFGdbIndex &getGdbIndex() = 0; + virtual const DWARFDebugAbbrev *getDebugAbbrev() = 0; + virtual const DWARFDebugLoc *getDebugLoc() = 0; + virtual const DWARFDebugAranges *getDebugAranges() = 0; + virtual Expected + getLineTableForUnit(DWARFUnit *U, + function_ref RecoverableErrHandler) = 0; + virtual void clearLineTableForUnit(DWARFUnit *U) = 0; + virtual Expected getDebugFrame() = 0; + virtual Expected getEHFrame() = 0; + virtual const DWARFDebugMacro *getDebugMacinfo() = 0; + virtual const DWARFDebugMacro *getDebugMacinfoDWO() = 0; + virtual const DWARFDebugMacro *getDebugMacro() = 0; + virtual const DWARFDebugMacro *getDebugMacroDWO() = 0; + virtual const DWARFDebugNames &getDebugNames() = 0; + virtual const AppleAcceleratorTable &getAppleNames() = 0; + virtual const AppleAcceleratorTable &getAppleTypes() = 0; + virtual const AppleAcceleratorTable &getAppleNamespaces() = 0; + virtual const AppleAcceleratorTable &getAppleObjC() = 0; + virtual std::shared_ptr + getDWOContext(StringRef AbsolutePath) = 0; + virtual const DenseMap & + getTypeUnitMap(bool IsDWO) = 0; + + /// Parse a macro[.dwo] or macinfo[.dwo] section. + std::unique_ptr + parseMacroOrMacinfo(MacroSecType SectionType); + + }; + friend class DWARFContextState; + +private: + /// All important state for a DWARFContext that needs to be threadsafe needs + /// to go into DWARFContextState. + std::unique_ptr State; /// The maximum DWARF version of all units. unsigned MaxVersion = 0; - struct DWOFile { - object::OwningBinary File; - std::unique_ptr Context; - }; - StringMap> DWOFiles; - std::weak_ptr DWP; - bool CheckedForDWP = false; - std::string DWPName; std::function RecoverableErrorHandler = WithColor::defaultErrorHandler; std::function WarningHandler = WithColor::defaultWarningHandler; - /// Read compile units from the debug_info section (if necessary) - /// and type units from the debug_types sections (if necessary) - /// and store them in NormalUnits. - void parseNormalUnits(); - /// Read compile units from the debug_info.dwo section (if necessary) /// and type units from the debug_types.dwo section (if necessary) /// and store them in DWOUnits. /// If \p Lazy is true, set up to parse but don't actually parse them. enum { EagerParse = false, LazyParse = true }; - void parseDWOUnits(bool Lazy = false); + DWARFUnitVector &getDWOUnits(bool Lazy = false); std::unique_ptr DObj; - /// Helper enum to distinguish between macro[.dwo] and macinfo[.dwo] - /// section. - enum MacroSecType { - MacinfoSection, - MacinfoDwoSection, - MacroSection, - MacroDwoSection - }; - // When set parses debug_info.dwo/debug_abbrev.dwo manually and populates CU // Index, and TU Index for DWARF5. bool ParseCUTUIndexManually = false; @@ -118,7 +136,8 @@ std::function RecoverableErrorHandler = WithColor::defaultErrorHandler, std::function WarningHandler = - WithColor::defaultWarningHandler); + WithColor::defaultWarningHandler, + bool ThreadSafe = false); ~DWARFContext() override; DWARFContext(DWARFContext &) = delete; @@ -147,20 +166,19 @@ /// Get units from .debug_info in this context. unit_iterator_range info_section_units() { - parseNormalUnits(); + DWARFUnitVector &NormalUnits = State->getNormalUnits(); return unit_iterator_range(NormalUnits.begin(), NormalUnits.begin() + NormalUnits.getNumInfoUnits()); } const DWARFUnitVector &getNormalUnitsVector() { - parseNormalUnits(); - return NormalUnits; + return State->getNormalUnits(); } /// Get units from .debug_types in this context. unit_iterator_range types_section_units() { - parseNormalUnits(); + DWARFUnitVector &NormalUnits = State->getNormalUnits(); return unit_iterator_range( NormalUnits.begin() + NormalUnits.getNumInfoUnits(), NormalUnits.end()); } @@ -175,25 +193,24 @@ /// Get all normal compile/type units in this context. unit_iterator_range normal_units() { - parseNormalUnits(); + DWARFUnitVector &NormalUnits = State->getNormalUnits(); return unit_iterator_range(NormalUnits.begin(), NormalUnits.end()); } /// Get units from .debug_info..dwo in the DWO context. unit_iterator_range dwo_info_section_units() { - parseDWOUnits(); + DWARFUnitVector &DWOUnits = State->getDWOUnits(); return unit_iterator_range(DWOUnits.begin(), DWOUnits.begin() + DWOUnits.getNumInfoUnits()); } const DWARFUnitVector &getDWOUnitsVector() { - parseDWOUnits(); - return DWOUnits; + return State->getDWOUnits(); } /// Get units from .debug_types.dwo in the DWO context. unit_iterator_range dwo_types_section_units() { - parseDWOUnits(); + DWARFUnitVector &DWOUnits = State->getDWOUnits(); return unit_iterator_range(DWOUnits.begin() + DWOUnits.getNumInfoUnits(), DWOUnits.end()); } @@ -209,44 +226,38 @@ /// Get all units in the DWO context. unit_iterator_range dwo_units() { - parseDWOUnits(); + DWARFUnitVector &DWOUnits = State->getDWOUnits(); return unit_iterator_range(DWOUnits.begin(), DWOUnits.end()); } /// Get the number of compile units in this context. unsigned getNumCompileUnits() { - parseNormalUnits(); - return NormalUnits.getNumInfoUnits(); + return State->getNormalUnits().getNumInfoUnits(); } /// Get the number of type units in this context. unsigned getNumTypeUnits() { - parseNormalUnits(); - return NormalUnits.getNumTypesUnits(); + return State->getNormalUnits().getNumTypesUnits(); } /// Get the number of compile units in the DWO context. unsigned getNumDWOCompileUnits() { - parseDWOUnits(); - return DWOUnits.getNumInfoUnits(); + return State->getDWOUnits().getNumInfoUnits(); } /// Get the number of type units in the DWO context. unsigned getNumDWOTypeUnits() { - parseDWOUnits(); - return DWOUnits.getNumTypesUnits(); + return State->getDWOUnits().getNumTypesUnits(); } /// Get the unit at the specified index. DWARFUnit *getUnitAtIndex(unsigned index) { - parseNormalUnits(); - return NormalUnits[index].get(); + return State->getNormalUnits()[index].get(); } /// Get the unit at the specified index for the DWO units. DWARFUnit *getDWOUnitAtIndex(unsigned index) { - parseDWOUnits(); - return DWOUnits[index].get(); + return State->getDWOUnits()[index].get(); } DWARFCompileUnit *getDWOCompileUnitForHash(uint64_t Hash); @@ -424,7 +435,8 @@ std::function RecoverableErrorHandler = WithColor::defaultErrorHandler, std::function WarningHandler = - WithColor::defaultWarningHandler); + WithColor::defaultWarningHandler, + bool ThreadSafe = false); static std::unique_ptr create(const StringMap> &Sections, @@ -432,7 +444,8 @@ std::function RecoverableErrorHandler = WithColor::defaultErrorHandler, std::function WarningHandler = - WithColor::defaultWarningHandler); + WithColor::defaultWarningHandler, + bool ThreadSafe = false); /// Get address size from CUs. /// TODO: refactor compile_units() to make this const. @@ -466,10 +479,6 @@ void setParseCUTUIndexManually(bool PCUTU) { ParseCUTUIndexManually = PCUTU; } private: - /// Parse a macro[.dwo] or macinfo[.dwo] section. - std::unique_ptr - parseMacroOrMacinfo(MacroSecType SectionType); - void addLocalsForDie(DWARFCompileUnit *CU, DWARFDie Subprogram, DWARFDie Die, std::vector &Result); }; diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -70,13 +70,675 @@ using FileLineInfoKind = DILineInfoSpecifier::FileLineInfoKind; using FunctionNameKind = DILineInfoSpecifier::FunctionNameKind; + +void fixupIndexV4(DWARFContext &C, DWARFUnitIndex &Index) { + using EntryType = DWARFUnitIndex::Entry::SectionContribution; + using EntryMap = DenseMap; + EntryMap Map; + const auto &DObj = C.getDWARFObj(); + if (DObj.getCUIndexSection().empty()) + return; + + uint64_t Offset = 0; + uint32_t TruncOffset = 0; + DObj.forEachInfoDWOSections([&](const DWARFSection &S) { + if (!(C.getParseCUTUIndexManually() || + S.Data.size() >= std::numeric_limits::max())) + return; + + DWARFDataExtractor Data(DObj, S, C.isLittleEndian(), 0); + while (Data.isValidOffset(Offset)) { + DWARFUnitHeader Header; + if (!Header.extract(C, Data, &Offset, DWARFSectionKind::DW_SECT_INFO)) { + logAllUnhandledErrors( + createError("Failed to parse CU header in DWP file"), errs()); + Map.clear(); + break; + } + + auto Iter = Map.insert({TruncOffset, + {Header.getOffset(), Header.getNextUnitOffset() - + Header.getOffset()}}); + if (!Iter.second) { + logAllUnhandledErrors( + createError("Collision occured between for truncated offset 0x" + + Twine::utohexstr(TruncOffset)), + errs()); + Map.clear(); + return; + } + + Offset = Header.getNextUnitOffset(); + TruncOffset = Offset; + } + }); + + if (Map.empty()) + return; + + for (DWARFUnitIndex::Entry &E : Index.getMutableRows()) { + if (!E.isValid()) + continue; + DWARFUnitIndex::Entry::SectionContribution &CUOff = E.getContribution(); + auto Iter = Map.find(CUOff.getOffset()); + if (Iter == Map.end()) { + logAllUnhandledErrors(createError("Could not find CU offset 0x" + + Twine::utohexstr(CUOff.getOffset()) + + " in the Map"), + errs()); + break; + } + CUOff.setOffset(Iter->second.getOffset()); + if (CUOff.getOffset() != Iter->second.getOffset()) + logAllUnhandledErrors(createError("Length of CU in CU index doesn't " + "match calculated length at offset 0x" + + Twine::utohexstr(CUOff.getOffset())), + errs()); + } +} + +void fixupIndexV5(DWARFContext &C, DWARFUnitIndex &Index) { + DenseMap Map; + + const auto &DObj = C.getDWARFObj(); + DObj.forEachInfoDWOSections([&](const DWARFSection &S) { + if (!(C.getParseCUTUIndexManually() || + S.Data.size() >= std::numeric_limits::max())) + return; + DWARFDataExtractor Data(DObj, S, C.isLittleEndian(), 0); + uint64_t Offset = 0; + while (Data.isValidOffset(Offset)) { + DWARFUnitHeader Header; + if (!Header.extract(C, Data, &Offset, DWARFSectionKind::DW_SECT_INFO)) { + logAllUnhandledErrors( + createError("Failed to parse unit header in DWP file"), errs()); + break; + } + bool CU = Header.getUnitType() == DW_UT_split_compile; + uint64_t Sig = CU ? *Header.getDWOId() : Header.getTypeHash(); + Map[Sig] = Header.getOffset(); + Offset = Header.getNextUnitOffset(); + } + }); + if (Map.empty()) + return; + for (DWARFUnitIndex::Entry &E : Index.getMutableRows()) { + if (!E.isValid()) + continue; + DWARFUnitIndex::Entry::SectionContribution &CUOff = E.getContribution(); + auto Iter = Map.find(E.getSignature()); + if (Iter == Map.end()) { + logAllUnhandledErrors( + createError("Could not find unit with signature 0x" + + Twine::utohexstr(E.getSignature()) + " in the Map"), + errs()); + break; + } + CUOff.setOffset(Iter->second); + } +} + +void fixupIndex(DWARFContext &C, DWARFUnitIndex &Index) { + if (Index.getVersion() < 5) + fixupIndexV4(C, Index); + else + fixupIndexV5(C, Index); +} + +template +static T &getAccelTable(std::unique_ptr &Cache, const DWARFObject &Obj, + const DWARFSection &Section, StringRef StringSection, + bool IsLittleEndian) { + if (Cache) + return *Cache; + DWARFDataExtractor AccelSection(Obj, Section, IsLittleEndian, 0); + DataExtractor StrData(StringSection, IsLittleEndian, 0); + Cache.reset(new T(AccelSection, StrData)); + if (Error E = Cache->extract()) + llvm::consumeError(std::move(E)); + return *Cache; +} + + +std::unique_ptr +DWARFContext::DWARFContextState::parseMacroOrMacinfo(MacroSecType SectionType) { + auto Macro = std::make_unique(); + auto ParseAndDump = [&](DWARFDataExtractor &Data, bool IsMacro) { + if (Error Err = IsMacro ? Macro->parseMacro(SectionType == MacroSection + ? D.compile_units() + : D.dwo_compile_units(), + SectionType == MacroSection + ? D.getStringExtractor() + : D.getStringDWOExtractor(), + Data) + : Macro->parseMacinfo(Data)) { + D.getRecoverableErrorHandler()(std::move(Err)); + Macro = nullptr; + } + }; + const DWARFObject &DObj = D.getDWARFObj(); + switch (SectionType) { + case MacinfoSection: { + DWARFDataExtractor Data(DObj.getMacinfoSection(), D.isLittleEndian(), 0); + ParseAndDump(Data, /*IsMacro=*/false); + break; + } + case MacinfoDwoSection: { + DWARFDataExtractor Data(DObj.getMacinfoDWOSection(), D.isLittleEndian(), 0); + ParseAndDump(Data, /*IsMacro=*/false); + break; + } + case MacroSection: { + DWARFDataExtractor Data(DObj, DObj.getMacroSection(), D.isLittleEndian(), + 0); + ParseAndDump(Data, /*IsMacro=*/true); + break; + } + case MacroDwoSection: { + DWARFDataExtractor Data(DObj.getMacroDWOSection(), D.isLittleEndian(), 0); + ParseAndDump(Data, /*IsMacro=*/true); + break; + } + } + return Macro; +} + +class ThreadUnsafeDWARFContextState : public DWARFContext::DWARFContextState { + + DWARFUnitVector NormalUnits; + std::optional> NormalTypeUnits; + std::unique_ptr CUIndex; + std::unique_ptr GdbIndex; + std::unique_ptr TUIndex; + std::unique_ptr Abbrev; + std::unique_ptr Loc; + std::unique_ptr Aranges; + std::unique_ptr Line; + std::unique_ptr DebugFrame; + std::unique_ptr EHFrame; + std::unique_ptr Macro; + std::unique_ptr Macinfo; + std::unique_ptr Names; + std::unique_ptr AppleNames; + std::unique_ptr AppleTypes; + std::unique_ptr AppleNamespaces; + std::unique_ptr AppleObjC; + DWARFUnitVector DWOUnits; + std::optional> DWOTypeUnits; + std::unique_ptr AbbrevDWO; + std::unique_ptr MacinfoDWO; + std::unique_ptr MacroDWO; + struct DWOFile { + object::OwningBinary File; + std::unique_ptr Context; + }; + StringMap> DWOFiles; + std::weak_ptr DWP; + bool CheckedForDWP = false; + std::string DWPName; + +public: + ThreadUnsafeDWARFContextState(DWARFContext &DC, std::string &DWP) : + DWARFContext::DWARFContextState(DC), + DWPName(std::move(DWP)) {} + + DWARFUnitVector &getNormalUnits() override { + if (NormalUnits.empty()) { + const DWARFObject &DObj = D.getDWARFObj(); + DObj.forEachInfoSections([&](const DWARFSection &S) { + NormalUnits.addUnitsForSection(D, S, DW_SECT_INFO); + }); + NormalUnits.finishedInfoUnits(); + DObj.forEachTypesSections([&](const DWARFSection &S) { + NormalUnits.addUnitsForSection(D, S, DW_SECT_EXT_TYPES); + }); + } + return NormalUnits; + } + + DWARFUnitVector &getDWOUnits(bool Lazy) override { + if (DWOUnits.empty()) { + const DWARFObject &DObj = D.getDWARFObj(); + + DObj.forEachInfoDWOSections([&](const DWARFSection &S) { + DWOUnits.addUnitsForDWOSection(D, S, DW_SECT_INFO, Lazy); + }); + DWOUnits.finishedInfoUnits(); + DObj.forEachTypesDWOSections([&](const DWARFSection &S) { + DWOUnits.addUnitsForDWOSection(D, S, DW_SECT_EXT_TYPES, Lazy); + }); + } + return DWOUnits; + } + + const DWARFDebugAbbrev *getDebugAbbrevDWO() override { + if (AbbrevDWO) + return AbbrevDWO.get(); + const DWARFObject &DObj = D.getDWARFObj(); + DataExtractor abbrData(DObj.getAbbrevDWOSection(), D.isLittleEndian(), 0); + AbbrevDWO = std::make_unique(abbrData); + return AbbrevDWO.get(); + } + + const DWARFUnitIndex &getCUIndex() override { + if (CUIndex) + return *CUIndex; + + DataExtractor Data(D.getDWARFObj().getCUIndexSection(), + D.isLittleEndian(), 0); + CUIndex = std::make_unique(DW_SECT_INFO); + if (CUIndex->parse(Data)) + fixupIndex(D, *CUIndex); + return *CUIndex; + } + const DWARFUnitIndex &getTUIndex() override { + if (TUIndex) + return *TUIndex; + + DataExtractor Data(D.getDWARFObj().getTUIndexSection(), + D.isLittleEndian(), 0); + TUIndex = std::make_unique(DW_SECT_EXT_TYPES); + bool isParseSuccessful = TUIndex->parse(Data); + // If we are parsing TU-index and for .debug_types section we don't need + // to do anything. + if (isParseSuccessful && TUIndex->getVersion() != 2) + fixupIndex(D, *TUIndex); + return *TUIndex; + } + + DWARFGdbIndex &getGdbIndex() override { + if (GdbIndex) + return *GdbIndex; + + DataExtractor Data(D.getDWARFObj().getGdbIndexSection(), true /*LE*/, 0); + GdbIndex = std::make_unique(); + GdbIndex->parse(Data); + return *GdbIndex; + } + + const DWARFDebugAbbrev *getDebugAbbrev() override { + if (Abbrev) + return Abbrev.get(); + + DataExtractor Data(D.getDWARFObj().getAbbrevSection(), + D.isLittleEndian(), 0); + Abbrev = std::make_unique(Data); + return Abbrev.get(); + } + + const DWARFDebugLoc *getDebugLoc() override { + if (Loc) + return Loc.get(); + + const DWARFObject &DObj = D.getDWARFObj(); + // Assume all units have the same address byte size. + auto Data = + D.getNumCompileUnits() + ? DWARFDataExtractor(DObj, DObj.getLocSection(), D.isLittleEndian(), + D.getUnitAtIndex(0)->getAddressByteSize()) + : DWARFDataExtractor("", D.isLittleEndian(), 0); + Loc.reset(new DWARFDebugLoc(std::move(Data))); + return Loc.get(); + } + + const DWARFDebugAranges *getDebugAranges() override { + if (Aranges) + return Aranges.get(); + + Aranges.reset(new DWARFDebugAranges()); + Aranges->generate(&D); + return Aranges.get(); + } + + Expected + getLineTableForUnit(DWARFUnit *U, function_ref RecoverableErrorHandler) override { + if (!Line) + Line.reset(new DWARFDebugLine); + + auto UnitDIE = U->getUnitDIE(); + if (!UnitDIE) + return nullptr; + + auto Offset = toSectionOffset(UnitDIE.find(DW_AT_stmt_list)); + if (!Offset) + return nullptr; // No line table for this compile unit. + + uint64_t stmtOffset = *Offset + U->getLineTableOffset(); + // See if the line table is cached. + if (const DWARFLineTable *lt = Line->getLineTable(stmtOffset)) + return lt; + + // Make sure the offset is good before we try to parse. + if (stmtOffset >= U->getLineSection().Data.size()) + return nullptr; + + // We have to parse it first. + DWARFDataExtractor Data(U->getContext().getDWARFObj(), U->getLineSection(), + U->isLittleEndian(), U->getAddressByteSize()); + return Line->getOrParseLineTable(Data, stmtOffset, U->getContext(), U, + RecoverableErrorHandler); + + } + + void clearLineTableForUnit(DWARFUnit *U) override { + if (!Line) + return; + + auto UnitDIE = U->getUnitDIE(); + if (!UnitDIE) + return; + + auto Offset = toSectionOffset(UnitDIE.find(DW_AT_stmt_list)); + if (!Offset) + return; + + uint64_t stmtOffset = *Offset + U->getLineTableOffset(); + Line->clearLineTable(stmtOffset); + } + + Expected getDebugFrame() override { + if (DebugFrame) + return DebugFrame.get(); + const DWARFObject &DObj = D.getDWARFObj(); + const DWARFSection &DS = DObj.getFrameSection(); + + // There's a "bug" in the DWARFv3 standard with respect to the target address + // size within debug frame sections. While DWARF is supposed to be independent + // of its container, FDEs have fields with size being "target address size", + // which isn't specified in DWARF in general. It's only specified for CUs, but + // .eh_frame can appear without a .debug_info section. Follow the example of + // other tools (libdwarf) and extract this from the container (ObjectFile + // provides this information). This problem is fixed in DWARFv4 + // See this dwarf-discuss discussion for more details: + // http://lists.dwarfstd.org/htdig.cgi/dwarf-discuss-dwarfstd.org/2011-December/001173.html + DWARFDataExtractor Data(DObj, DS, D.isLittleEndian(), + DObj.getAddressSize()); + auto DF = + std::make_unique(D.getArch(), /*IsEH=*/false, + DS.Address); + if (Error E = DF->parse(Data)) + return std::move(E); + + DebugFrame.swap(DF); + return DebugFrame.get(); + } + + Expected getEHFrame() override { + if (EHFrame) + return EHFrame.get(); + const DWARFObject &DObj = D.getDWARFObj(); + + const DWARFSection &DS = DObj.getEHFrameSection(); + DWARFDataExtractor Data(DObj, DS, D.isLittleEndian(), + DObj.getAddressSize()); + auto DF = + std::make_unique(D.getArch(), /*IsEH=*/true, + DS.Address); + if (Error E = DF->parse(Data)) + return std::move(E); + EHFrame.swap(DF); + return EHFrame.get(); + } + + const DWARFDebugMacro *getDebugMacinfo() override { + if (!Macinfo) + Macinfo = parseMacroOrMacinfo(MacinfoSection); + return Macinfo.get(); + } + const DWARFDebugMacro *getDebugMacinfoDWO() override { + if (!MacinfoDWO) + MacinfoDWO = parseMacroOrMacinfo(MacinfoDwoSection); + return MacinfoDWO.get(); + } + const DWARFDebugMacro *getDebugMacro() override { + if (!Macro) + Macro = parseMacroOrMacinfo(MacroSection); + return Macro.get(); + } + const DWARFDebugMacro *getDebugMacroDWO() override { + if (!MacroDWO) + MacroDWO = parseMacroOrMacinfo(MacroDwoSection); + return MacroDWO.get(); + } + const DWARFDebugNames &getDebugNames() override { + const DWARFObject &DObj = D.getDWARFObj(); + return getAccelTable(Names, DObj, DObj.getNamesSection(), + DObj.getStrSection(), D.isLittleEndian()); + } + const AppleAcceleratorTable &getAppleNames() override { + const DWARFObject &DObj = D.getDWARFObj(); + return getAccelTable(AppleNames, DObj, DObj.getAppleNamesSection(), + DObj.getStrSection(), D.isLittleEndian()); + + } + const AppleAcceleratorTable &getAppleTypes() override { + const DWARFObject &DObj = D.getDWARFObj(); + return getAccelTable(AppleTypes, DObj, DObj.getAppleTypesSection(), + DObj.getStrSection(), D.isLittleEndian()); + + } + const AppleAcceleratorTable &getAppleNamespaces() override { + const DWARFObject &DObj = D.getDWARFObj(); + return getAccelTable(AppleNamespaces, DObj, + DObj.getAppleNamespacesSection(), + DObj.getStrSection(), D.isLittleEndian()); + + } + const AppleAcceleratorTable &getAppleObjC() override { + const DWARFObject &DObj = D.getDWARFObj(); + return getAccelTable(AppleObjC, DObj, DObj.getAppleObjCSection(), + DObj.getStrSection(), D.isLittleEndian()); + } + + std::shared_ptr + getDWOContext(StringRef AbsolutePath) override { + if (auto S = DWP.lock()) { + DWARFContext *Ctxt = S->Context.get(); + return std::shared_ptr(std::move(S), Ctxt); + } + + std::weak_ptr *Entry = &DWOFiles[AbsolutePath]; + + if (auto S = Entry->lock()) { + DWARFContext *Ctxt = S->Context.get(); + return std::shared_ptr(std::move(S), Ctxt); + } + + const DWARFObject &DObj = D.getDWARFObj(); + + Expected> Obj = [&] { + if (!CheckedForDWP) { + SmallString<128> DWPName; + auto Obj = object::ObjectFile::createObjectFile( + this->DWPName.empty() + ? (DObj.getFileName() + ".dwp").toStringRef(DWPName) + : StringRef(this->DWPName)); + if (Obj) { + Entry = &DWP; + return Obj; + } else { + CheckedForDWP = true; + // TODO: Should this error be handled (maybe in a high verbosity mode) + // before falling back to .dwo files? + consumeError(Obj.takeError()); + } + } + + return object::ObjectFile::createObjectFile(AbsolutePath); + }(); + + if (!Obj) { + // TODO: Actually report errors helpfully. + consumeError(Obj.takeError()); + return nullptr; + } + + auto S = std::make_shared(); + S->File = std::move(Obj.get()); + S->Context = DWARFContext::create(*S->File.getBinary(), + DWARFContext::ProcessDebugRelocations::Ignore); + *Entry = S; + auto *Ctxt = S->Context.get(); + return std::shared_ptr(std::move(S), Ctxt); + } + + const DenseMap &getNormalTypeUnitMap() { + if (!NormalTypeUnits) { + NormalTypeUnits.emplace(); + for (const auto &U :D.normal_units()) { + if (DWARFTypeUnit *TU = dyn_cast(U.get())) + (*NormalTypeUnits)[TU->getTypeHash()] = TU; + } + } + return *NormalTypeUnits; + } + + const DenseMap &getDWOTypeUnitMap() { + if (!DWOTypeUnits) { + DWOTypeUnits.emplace(); + for (const auto &U :D.dwo_units()) { + if (DWARFTypeUnit *TU = dyn_cast(U.get())) + (*DWOTypeUnits)[TU->getTypeHash()] = TU; + } + } + return *DWOTypeUnits; + } + + const DenseMap & + getTypeUnitMap(bool IsDWO) override { + if (IsDWO) + return getDWOTypeUnitMap(); + else + return getNormalTypeUnitMap(); + } + + +}; + +class ThreadSafeState : public ThreadUnsafeDWARFContextState { + std::recursive_mutex Mutex; + +public: + ThreadSafeState(DWARFContext &DC, std::string &DWP) : + ThreadUnsafeDWARFContextState(DC, DWP) {} + + DWARFUnitVector &getNormalUnits() override { + std::unique_lock LockGuard(Mutex); + return ThreadUnsafeDWARFContextState::getNormalUnits(); + } + DWARFUnitVector &getDWOUnits(bool Lazy) override { + std::unique_lock LockGuard(Mutex); + return ThreadUnsafeDWARFContextState::getDWOUnits(Lazy); + } + const DWARFUnitIndex &getCUIndex() override { + std::unique_lock LockGuard(Mutex); + return ThreadUnsafeDWARFContextState::getCUIndex(); + } + const DWARFDebugAbbrev *getDebugAbbrevDWO() override { + std::unique_lock LockGuard(Mutex); + return ThreadUnsafeDWARFContextState::getDebugAbbrevDWO(); + } + + const DWARFUnitIndex &getTUIndex() override { + std::unique_lock LockGuard(Mutex); + return ThreadUnsafeDWARFContextState::getTUIndex(); + } + DWARFGdbIndex &getGdbIndex() override { + std::unique_lock LockGuard(Mutex); + return ThreadUnsafeDWARFContextState::getGdbIndex(); + } + const DWARFDebugAbbrev *getDebugAbbrev() override { + std::unique_lock LockGuard(Mutex); + return ThreadUnsafeDWARFContextState::getDebugAbbrev(); + } + const DWARFDebugLoc *getDebugLoc() override { + std::unique_lock LockGuard(Mutex); + return ThreadUnsafeDWARFContextState::getDebugLoc(); + } + const DWARFDebugAranges *getDebugAranges() override { + std::unique_lock LockGuard(Mutex); + return ThreadUnsafeDWARFContextState::getDebugAranges(); + } + Expected + getLineTableForUnit(DWARFUnit *U, function_ref RecoverableErrorHandler) override { + std::unique_lock LockGuard(Mutex); + return ThreadUnsafeDWARFContextState::getLineTableForUnit(U, RecoverableErrorHandler); + } + void clearLineTableForUnit(DWARFUnit *U) override { + std::unique_lock LockGuard(Mutex); + return ThreadUnsafeDWARFContextState::clearLineTableForUnit(U); + } + Expected getDebugFrame() override { + std::unique_lock LockGuard(Mutex); + return ThreadUnsafeDWARFContextState::getDebugFrame(); + } + Expected getEHFrame() override { + std::unique_lock LockGuard(Mutex); + return ThreadUnsafeDWARFContextState::getEHFrame(); + } + const DWARFDebugMacro *getDebugMacinfo() override { + std::unique_lock LockGuard(Mutex); + return ThreadUnsafeDWARFContextState::getDebugMacinfo(); + } + const DWARFDebugMacro *getDebugMacinfoDWO() override { + std::unique_lock LockGuard(Mutex); + return ThreadUnsafeDWARFContextState::getDebugMacinfoDWO(); + } + const DWARFDebugMacro *getDebugMacro() override { + std::unique_lock LockGuard(Mutex); + return ThreadUnsafeDWARFContextState::getDebugMacro(); + } + const DWARFDebugMacro *getDebugMacroDWO() override { + std::unique_lock LockGuard(Mutex); + return ThreadUnsafeDWARFContextState::getDebugMacroDWO(); + } + const DWARFDebugNames &getDebugNames() override { + std::unique_lock LockGuard(Mutex); + return ThreadUnsafeDWARFContextState::getDebugNames(); + } + const AppleAcceleratorTable &getAppleNames() override { + std::unique_lock LockGuard(Mutex); + return ThreadUnsafeDWARFContextState::getAppleNames(); + } + const AppleAcceleratorTable &getAppleTypes() override { + std::unique_lock LockGuard(Mutex); + return ThreadUnsafeDWARFContextState::getAppleTypes(); + } + const AppleAcceleratorTable &getAppleNamespaces() override { + std::unique_lock LockGuard(Mutex); + return ThreadUnsafeDWARFContextState::getAppleNamespaces(); + } + const AppleAcceleratorTable &getAppleObjC() override { + std::unique_lock LockGuard(Mutex); + return ThreadUnsafeDWARFContextState::getAppleObjC(); + } + std::shared_ptr + getDWOContext(StringRef AbsolutePath) override { + std::unique_lock LockGuard(Mutex); + return ThreadUnsafeDWARFContextState::getDWOContext(AbsolutePath); + } + const DenseMap & + getTypeUnitMap(bool IsDWO) override { + std::unique_lock LockGuard(Mutex); + return ThreadUnsafeDWARFContextState::getTypeUnitMap(IsDWO); + } +}; + + + DWARFContext::DWARFContext(std::unique_ptr DObj, std::string DWPName, std::function RecoverableErrorHandler, - std::function WarningHandler) - : DIContext(CK_DWARF), DWPName(std::move(DWPName)), + std::function WarningHandler, + bool ThreadSafe) + : DIContext(CK_DWARF), RecoverableErrorHandler(RecoverableErrorHandler), - WarningHandler(WarningHandler), DObj(std::move(DObj)) {} + WarningHandler(WarningHandler), DObj(std::move(DObj)) { + if (ThreadSafe) + State.reset(new ThreadUnsafeDWARFContextState(*this, DWPName)); + else + State.reset(new ThreadSafeState(*this, DWPName)); + } DWARFContext::~DWARFContext() = default; @@ -266,47 +928,6 @@ } } -std::unique_ptr -DWARFContext::parseMacroOrMacinfo(MacroSecType SectionType) { - auto Macro = std::make_unique(); - auto ParseAndDump = [&](DWARFDataExtractor &Data, bool IsMacro) { - if (Error Err = IsMacro ? Macro->parseMacro(SectionType == MacroSection - ? compile_units() - : dwo_compile_units(), - SectionType == MacroSection - ? getStringExtractor() - : getStringDWOExtractor(), - Data) - : Macro->parseMacinfo(Data)) { - RecoverableErrorHandler(std::move(Err)); - Macro = nullptr; - } - }; - switch (SectionType) { - case MacinfoSection: { - DWARFDataExtractor Data(DObj->getMacinfoSection(), isLittleEndian(), 0); - ParseAndDump(Data, /*IsMacro=*/false); - break; - } - case MacinfoDwoSection: { - DWARFDataExtractor Data(DObj->getMacinfoDWOSection(), isLittleEndian(), 0); - ParseAndDump(Data, /*IsMacro=*/false); - break; - } - case MacroSection: { - DWARFDataExtractor Data(*DObj, DObj->getMacroSection(), isLittleEndian(), - 0); - ParseAndDump(Data, /*IsMacro=*/true); - break; - } - case MacroDwoSection: { - DWARFDataExtractor Data(DObj->getMacroDWOSection(), isLittleEndian(), 0); - ParseAndDump(Data, /*IsMacro=*/true); - break; - } - } - return Macro; -} static void dumpLoclistsSection(raw_ostream &OS, DIDumpOptions DumpOpts, DWARFDataExtractor Data, const DWARFObject &Obj, @@ -700,34 +1321,22 @@ DWARFTypeUnit *DWARFContext::getTypeUnitForHash(uint16_t Version, uint64_t Hash, bool IsDWO) { - parseDWOUnits(LazyParse); - + DWARFUnitVector &DWOUnits = State->getDWOUnits(); if (const auto &TUI = getTUIndex()) { if (const auto *R = TUI.getFromHash(Hash)) return dyn_cast_or_null( DWOUnits.getUnitForIndexEntry(*R)); return nullptr; } - - struct UnitContainers { - const DWARFUnitVector &Units; - std::optional> ⤅ - }; - UnitContainers Units = IsDWO ? UnitContainers{DWOUnits, DWOTypeUnits} - : UnitContainers{NormalUnits, NormalTypeUnits}; - if (!Units.Map) { - Units.Map.emplace(); - for (const auto &U : IsDWO ? dwo_units() : normal_units()) { - if (DWARFTypeUnit *TU = dyn_cast(U.get())) - (*Units.Map)[TU->getTypeHash()] = TU; - } - } - - return (*Units.Map)[Hash]; + const DenseMap &Map = State->getTypeUnitMap(IsDWO); + auto Iter = Map.find(Hash); + if (Iter != Map.end()) + return Iter->second; + return nullptr; } DWARFCompileUnit *DWARFContext::getDWOCompileUnitForHash(uint64_t Hash) { - parseDWOUnits(LazyParse); + DWARFUnitVector &DWOUnits = State->getDWOUnits(LazyParse); if (const auto &CUI = getCUIndex()) { if (const auto *R = CUI.getFromHash(Hash)) @@ -757,8 +1366,7 @@ } DWARFDie DWARFContext::getDIEForOffset(uint64_t Offset) { - parseNormalUnits(); - if (auto *CU = NormalUnits.getUnitForOffset(Offset)) + if (auto *CU = State->getNormalUnits().getUnitForOffset(Offset)) return CU->getDIEForOffset(Offset); return DWARFDie(); } @@ -782,302 +1390,77 @@ return Success; } -void fixupIndexV4(const DWARFObject &DObj, DWARFContext &C, - DWARFUnitIndex &Index) { - using EntryType = DWARFUnitIndex::Entry::SectionContribution; - using EntryMap = DenseMap; - EntryMap Map; - if (DObj.getCUIndexSection().empty()) - return; - - uint64_t Offset = 0; - uint32_t TruncOffset = 0; - DObj.forEachInfoDWOSections([&](const DWARFSection &S) { - if (!(C.getParseCUTUIndexManually() || - S.Data.size() >= std::numeric_limits::max())) - return; - - DWARFDataExtractor Data(DObj, S, C.isLittleEndian(), 0); - while (Data.isValidOffset(Offset)) { - DWARFUnitHeader Header; - if (!Header.extract(C, Data, &Offset, DWARFSectionKind::DW_SECT_INFO)) { - logAllUnhandledErrors( - createError("Failed to parse CU header in DWP file"), errs()); - Map.clear(); - break; - } - - auto Iter = Map.insert({TruncOffset, - {Header.getOffset(), Header.getNextUnitOffset() - - Header.getOffset()}}); - if (!Iter.second) { - logAllUnhandledErrors( - createError("Collision occured between for truncated offset 0x" + - Twine::utohexstr(TruncOffset)), - errs()); - Map.clear(); - return; - } - - Offset = Header.getNextUnitOffset(); - TruncOffset = Offset; - } - }); - - if (Map.empty()) - return; - - for (DWARFUnitIndex::Entry &E : Index.getMutableRows()) { - if (!E.isValid()) - continue; - DWARFUnitIndex::Entry::SectionContribution &CUOff = E.getContribution(); - auto Iter = Map.find(CUOff.getOffset()); - if (Iter == Map.end()) { - logAllUnhandledErrors(createError("Could not find CU offset 0x" + - Twine::utohexstr(CUOff.getOffset()) + - " in the Map"), - errs()); - break; - } - CUOff.setOffset(Iter->second.getOffset()); - if (CUOff.getOffset() != Iter->second.getOffset()) - logAllUnhandledErrors(createError("Length of CU in CU index doesn't " - "match calculated length at offset 0x" + - Twine::utohexstr(CUOff.getOffset())), - errs()); - } -} - -void fixupIndexV5(const DWARFObject &DObj, DWARFContext &C, - DWARFUnitIndex &Index) { - DenseMap Map; - - DObj.forEachInfoDWOSections([&](const DWARFSection &S) { - if (!(C.getParseCUTUIndexManually() || - S.Data.size() >= std::numeric_limits::max())) - return; - DWARFDataExtractor Data(DObj, S, C.isLittleEndian(), 0); - uint64_t Offset = 0; - while (Data.isValidOffset(Offset)) { - DWARFUnitHeader Header; - if (!Header.extract(C, Data, &Offset, DWARFSectionKind::DW_SECT_INFO)) { - logAllUnhandledErrors( - createError("Failed to parse unit header in DWP file"), errs()); - break; - } - bool CU = Header.getUnitType() == DW_UT_split_compile; - uint64_t Sig = CU ? *Header.getDWOId() : Header.getTypeHash(); - Map[Sig] = Header.getOffset(); - Offset = Header.getNextUnitOffset(); - } - }); - if (Map.empty()) - return; - for (DWARFUnitIndex::Entry &E : Index.getMutableRows()) { - if (!E.isValid()) - continue; - DWARFUnitIndex::Entry::SectionContribution &CUOff = E.getContribution(); - auto Iter = Map.find(E.getSignature()); - if (Iter == Map.end()) { - logAllUnhandledErrors( - createError("Could not find unit with signature 0x" + - Twine::utohexstr(E.getSignature()) + " in the Map"), - errs()); - break; - } - CUOff.setOffset(Iter->second); - } -} - -void fixupIndex(const DWARFObject &DObj, DWARFContext &C, - DWARFUnitIndex &Index) { - if (Index.getVersion() < 5) - fixupIndexV4(DObj, C, Index); - else - fixupIndexV5(DObj, C, Index); -} - const DWARFUnitIndex &DWARFContext::getCUIndex() { - if (CUIndex) - return *CUIndex; - - DataExtractor CUIndexData(DObj->getCUIndexSection(), isLittleEndian(), 0); - CUIndex = std::make_unique(DW_SECT_INFO); - bool IsParseSuccessful = CUIndex->parse(CUIndexData); - if (IsParseSuccessful) - fixupIndex(*DObj, *this, *CUIndex); - return *CUIndex; + return State->getCUIndex(); } const DWARFUnitIndex &DWARFContext::getTUIndex() { - if (TUIndex) - return *TUIndex; - - DataExtractor TUIndexData(DObj->getTUIndexSection(), isLittleEndian(), 0); - TUIndex = std::make_unique(DW_SECT_EXT_TYPES); - bool isParseSuccessful = TUIndex->parse(TUIndexData); - // If we are parsing TU-index and for .debug_types section we don't need - // to do anything. - if (isParseSuccessful && TUIndex->getVersion() != 2) - fixupIndex(*DObj, *this, *TUIndex); - return *TUIndex; + return State->getTUIndex(); } DWARFGdbIndex &DWARFContext::getGdbIndex() { - if (GdbIndex) - return *GdbIndex; - - DataExtractor GdbIndexData(DObj->getGdbIndexSection(), true /*LE*/, 0); - GdbIndex = std::make_unique(); - GdbIndex->parse(GdbIndexData); - return *GdbIndex; + return State->getGdbIndex(); } const DWARFDebugAbbrev *DWARFContext::getDebugAbbrev() { - if (Abbrev) - return Abbrev.get(); - - DataExtractor abbrData(DObj->getAbbrevSection(), isLittleEndian(), 0); - Abbrev = std::make_unique(abbrData); - return Abbrev.get(); + return State->getDebugAbbrev(); } const DWARFDebugAbbrev *DWARFContext::getDebugAbbrevDWO() { - if (AbbrevDWO) - return AbbrevDWO.get(); - - DataExtractor abbrData(DObj->getAbbrevDWOSection(), isLittleEndian(), 0); - AbbrevDWO = std::make_unique(abbrData); - return AbbrevDWO.get(); + return State->getDebugAbbrevDWO(); } const DWARFDebugLoc *DWARFContext::getDebugLoc() { - if (Loc) - return Loc.get(); - - // Assume all units have the same address byte size. - auto LocData = - getNumCompileUnits() - ? DWARFDataExtractor(*DObj, DObj->getLocSection(), isLittleEndian(), - getUnitAtIndex(0)->getAddressByteSize()) - : DWARFDataExtractor("", isLittleEndian(), 0); - Loc.reset(new DWARFDebugLoc(std::move(LocData))); - return Loc.get(); + return State->getDebugLoc(); } const DWARFDebugAranges *DWARFContext::getDebugAranges() { - if (Aranges) - return Aranges.get(); - - Aranges.reset(new DWARFDebugAranges()); - Aranges->generate(this); - return Aranges.get(); + return State->getDebugAranges(); } Expected DWARFContext::getDebugFrame() { - if (DebugFrame) - return DebugFrame.get(); - - const DWARFSection &DS = DObj->getFrameSection(); - - // There's a "bug" in the DWARFv3 standard with respect to the target address - // size within debug frame sections. While DWARF is supposed to be independent - // of its container, FDEs have fields with size being "target address size", - // which isn't specified in DWARF in general. It's only specified for CUs, but - // .eh_frame can appear without a .debug_info section. Follow the example of - // other tools (libdwarf) and extract this from the container (ObjectFile - // provides this information). This problem is fixed in DWARFv4 - // See this dwarf-discuss discussion for more details: - // http://lists.dwarfstd.org/htdig.cgi/dwarf-discuss-dwarfstd.org/2011-December/001173.html - DWARFDataExtractor DebugFrameData(*DObj, DS, isLittleEndian(), - DObj->getAddressSize()); - auto DF = - std::make_unique(getArch(), /*IsEH=*/false, DS.Address); - if (Error E = DF->parse(DebugFrameData)) - return std::move(E); - - DebugFrame.swap(DF); - return DebugFrame.get(); + return State->getDebugFrame(); } Expected DWARFContext::getEHFrame() { - if (EHFrame) - return EHFrame.get(); - - const DWARFSection &DS = DObj->getEHFrameSection(); - DWARFDataExtractor DebugFrameData(*DObj, DS, isLittleEndian(), - DObj->getAddressSize()); - - auto DF = - std::make_unique(getArch(), /*IsEH=*/true, DS.Address); - if (Error E = DF->parse(DebugFrameData)) - return std::move(E); - DebugFrame.swap(DF); - return DebugFrame.get(); + return State->getEHFrame(); } const DWARFDebugMacro *DWARFContext::getDebugMacro() { - if (!Macro) - Macro = parseMacroOrMacinfo(MacroSection); - return Macro.get(); + return State->getDebugMacro(); } const DWARFDebugMacro *DWARFContext::getDebugMacroDWO() { - if (!MacroDWO) - MacroDWO = parseMacroOrMacinfo(MacroDwoSection); - return MacroDWO.get(); + return State->getDebugMacroDWO(); } const DWARFDebugMacro *DWARFContext::getDebugMacinfo() { - if (!Macinfo) - Macinfo = parseMacroOrMacinfo(MacinfoSection); - return Macinfo.get(); + return State->getDebugMacinfo(); } const DWARFDebugMacro *DWARFContext::getDebugMacinfoDWO() { - if (!MacinfoDWO) - MacinfoDWO = parseMacroOrMacinfo(MacinfoDwoSection); - return MacinfoDWO.get(); + return State->getDebugMacinfoDWO(); } -template -static T &getAccelTable(std::unique_ptr &Cache, const DWARFObject &Obj, - const DWARFSection &Section, StringRef StringSection, - bool IsLittleEndian) { - if (Cache) - return *Cache; - DWARFDataExtractor AccelSection(Obj, Section, IsLittleEndian, 0); - DataExtractor StrData(StringSection, IsLittleEndian, 0); - Cache.reset(new T(AccelSection, StrData)); - if (Error E = Cache->extract()) - llvm::consumeError(std::move(E)); - return *Cache; -} const DWARFDebugNames &DWARFContext::getDebugNames() { - return getAccelTable(Names, *DObj, DObj->getNamesSection(), - DObj->getStrSection(), isLittleEndian()); + return State->getDebugNames(); } const AppleAcceleratorTable &DWARFContext::getAppleNames() { - return getAccelTable(AppleNames, *DObj, DObj->getAppleNamesSection(), - DObj->getStrSection(), isLittleEndian()); + return State->getAppleNames(); } const AppleAcceleratorTable &DWARFContext::getAppleTypes() { - return getAccelTable(AppleTypes, *DObj, DObj->getAppleTypesSection(), - DObj->getStrSection(), isLittleEndian()); + return State->getAppleTypes(); } const AppleAcceleratorTable &DWARFContext::getAppleNamespaces() { - return getAccelTable(AppleNamespaces, *DObj, - DObj->getAppleNamespacesSection(), - DObj->getStrSection(), isLittleEndian()); + return State->getAppleNamespaces(); } const AppleAcceleratorTable &DWARFContext::getAppleObjC() { - return getAccelTable(AppleObjC, *DObj, DObj->getAppleObjCSection(), - DObj->getStrSection(), isLittleEndian()); + return State->getAppleObjC(); } const DWARFDebugLine::LineTable * @@ -1093,77 +1476,20 @@ Expected DWARFContext::getLineTableForUnit( DWARFUnit *U, function_ref RecoverableErrorHandler) { - if (!Line) - Line.reset(new DWARFDebugLine); - - auto UnitDIE = U->getUnitDIE(); - if (!UnitDIE) - return nullptr; - - auto Offset = toSectionOffset(UnitDIE.find(DW_AT_stmt_list)); - if (!Offset) - return nullptr; // No line table for this compile unit. - - uint64_t stmtOffset = *Offset + U->getLineTableOffset(); - // See if the line table is cached. - if (const DWARFLineTable *lt = Line->getLineTable(stmtOffset)) - return lt; - - // Make sure the offset is good before we try to parse. - if (stmtOffset >= U->getLineSection().Data.size()) - return nullptr; - - // We have to parse it first. - DWARFDataExtractor lineData(*DObj, U->getLineSection(), isLittleEndian(), - U->getAddressByteSize()); - return Line->getOrParseLineTable(lineData, stmtOffset, *this, U, - RecoverableErrorHandler); + return State->getLineTableForUnit(U, RecoverableErrorHandler); } void DWARFContext::clearLineTableForUnit(DWARFUnit *U) { - if (!Line) - return; - - auto UnitDIE = U->getUnitDIE(); - if (!UnitDIE) - return; - - auto Offset = toSectionOffset(UnitDIE.find(DW_AT_stmt_list)); - if (!Offset) - return; - - uint64_t stmtOffset = *Offset + U->getLineTableOffset(); - Line->clearLineTable(stmtOffset); + return State->clearLineTableForUnit(U); } -void DWARFContext::parseNormalUnits() { - if (!NormalUnits.empty()) - return; - DObj->forEachInfoSections([&](const DWARFSection &S) { - NormalUnits.addUnitsForSection(*this, S, DW_SECT_INFO); - }); - NormalUnits.finishedInfoUnits(); - DObj->forEachTypesSections([&](const DWARFSection &S) { - NormalUnits.addUnitsForSection(*this, S, DW_SECT_EXT_TYPES); - }); -} - -void DWARFContext::parseDWOUnits(bool Lazy) { - if (!DWOUnits.empty()) - return; - DObj->forEachInfoDWOSections([&](const DWARFSection &S) { - DWOUnits.addUnitsForDWOSection(*this, S, DW_SECT_INFO, Lazy); - }); - DWOUnits.finishedInfoUnits(); - DObj->forEachTypesDWOSections([&](const DWARFSection &S) { - DWOUnits.addUnitsForDWOSection(*this, S, DW_SECT_EXT_TYPES, Lazy); - }); +DWARFUnitVector &DWARFContext::getDWOUnits(bool Lazy) { + return State->getDWOUnits(Lazy); } DWARFCompileUnit *DWARFContext::getCompileUnitForOffset(uint64_t Offset) { - parseNormalUnits(); return dyn_cast_or_null( - NormalUnits.getUnitForOffset(Offset)); + State->getNormalUnits().getUnitForOffset(Offset)); } DWARFCompileUnit *DWARFContext::getCompileUnitForCodeAddress(uint64_t Address) { @@ -1519,52 +1845,7 @@ std::shared_ptr DWARFContext::getDWOContext(StringRef AbsolutePath) { - if (auto S = DWP.lock()) { - DWARFContext *Ctxt = S->Context.get(); - return std::shared_ptr(std::move(S), Ctxt); - } - - std::weak_ptr *Entry = &DWOFiles[AbsolutePath]; - - if (auto S = Entry->lock()) { - DWARFContext *Ctxt = S->Context.get(); - return std::shared_ptr(std::move(S), Ctxt); - } - - Expected> Obj = [&] { - if (!CheckedForDWP) { - SmallString<128> DWPName; - auto Obj = object::ObjectFile::createObjectFile( - this->DWPName.empty() - ? (DObj->getFileName() + ".dwp").toStringRef(DWPName) - : StringRef(this->DWPName)); - if (Obj) { - Entry = &DWP; - return Obj; - } else { - CheckedForDWP = true; - // TODO: Should this error be handled (maybe in a high verbosity mode) - // before falling back to .dwo files? - consumeError(Obj.takeError()); - } - } - - return object::ObjectFile::createObjectFile(AbsolutePath); - }(); - - if (!Obj) { - // TODO: Actually report errors helpfully. - consumeError(Obj.takeError()); - return nullptr; - } - - auto S = std::make_shared(); - S->File = std::move(Obj.get()); - S->Context = DWARFContext::create(*S->File.getBinary(), - ProcessDebugRelocations::Ignore); - *Entry = S; - auto *Ctxt = S->Context.get(); - return std::shared_ptr(std::move(S), Ctxt); + return State->getDWOContext(AbsolutePath); } static Error createError(const Twine &Reason, llvm::Error E) { @@ -2115,23 +2396,27 @@ ProcessDebugRelocations RelocAction, const LoadedObjectInfo *L, std::string DWPName, std::function RecoverableErrorHandler, - std::function WarningHandler) { + std::function WarningHandler, + bool ThreadSafe) { auto DObj = std::make_unique( Obj, L, RecoverableErrorHandler, WarningHandler, RelocAction); - return std::make_unique(std::move(DObj), std::move(DWPName), + return std::make_unique(std::move(DObj), + std::move(DWPName), RecoverableErrorHandler, - WarningHandler); + WarningHandler, + ThreadSafe); } std::unique_ptr DWARFContext::create(const StringMap> &Sections, uint8_t AddrSize, bool isLittleEndian, std::function RecoverableErrorHandler, - std::function WarningHandler) { + std::function WarningHandler, + bool ThreadSafe) { auto DObj = std::make_unique(Sections, AddrSize, isLittleEndian); return std::make_unique( - std::move(DObj), "", RecoverableErrorHandler, WarningHandler); + std::move(DObj), "", RecoverableErrorHandler, WarningHandler, ThreadSafe); } uint8_t DWARFContext::getCUAddrSize() { diff --git a/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp b/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp --- a/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp +++ b/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp @@ -337,7 +337,14 @@ } // Make sure there is DWARF to convert first. - std::unique_ptr DICtx = DWARFContext::create(Obj); + std::unique_ptr DICtx = DWARFContext::create( + Obj, + /*RelocAction=*/DWARFContext::ProcessDebugRelocations::Process, + nullptr, + /*DWPName=*/"", + /*RecoverableErrorHandler=*/WithColor::defaultErrorHandler, + /*WarningHandler=*/WithColor::defaultWarningHandler, + /*ThreadSafe*/true); if (!DICtx) return createStringError(std::errc::invalid_argument, "unable to create DWARF context");