[llvm] 576f3f0 - Make DWARFContext more thread safe.
Greg Clayton via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 1 14:11:42 PDT 2023
Author: Greg Clayton
Date: 2023-09-01T14:11:27-07:00
New Revision: 576f3f0cc930dc9aee157b76dd80319dfe7d51b9
URL: https://github.com/llvm/llvm-project/commit/576f3f0cc930dc9aee157b76dd80319dfe7d51b9
DIFF: https://github.com/llvm/llvm-project/commit/576f3f0cc930dc9aee157b76dd80319dfe7d51b9.diff
LOG: Make DWARFContext more thread safe.
llvm-gsymutil uses a DWARFContext from multiple threads as it parses each compile unit. As it finds issues it might end up dumping a DIE to an output stream which can cause accesses to the DWARFContext from multiple threads. In llvm-gsymutil it can end up dumping a DIE from multiple threads into thread specific stream which was causing DWARFContext::getTUIndex() to be called and can crash the process.
This fix puts a recursive mutex into the DWARFContext class and makes most APIs threadsafe for access. Many of the methods in DWARFContext will check if a member variable has been filled in yet, and parse what is needed and populate a member variagle with the results. Now a mutex protects these functions.
Differential Revision: https://reviews.llvm.org/D157459
Added:
Modified:
llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h
llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h
index 27720ac746ee2fd..4bd8394e6b4ec82 100644
--- 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 <cstdint>
#include <memory>
+#include <mutex>
namespace llvm {
@@ -45,69 +46,86 @@ class DWARFUnitIndex;
/// 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<DenseMap<uint64_t, DWARFTypeUnit *>> NormalTypeUnits;
- std::unique_ptr<DWARFUnitIndex> CUIndex;
- std::unique_ptr<DWARFGdbIndex> GdbIndex;
- std::unique_ptr<DWARFUnitIndex> TUIndex;
- std::unique_ptr<DWARFDebugAbbrev> Abbrev;
- std::unique_ptr<DWARFDebugLoc> Loc;
- std::unique_ptr<DWARFDebugAranges> Aranges;
- std::unique_ptr<DWARFDebugLine> Line;
- std::unique_ptr<DWARFDebugFrame> DebugFrame;
- std::unique_ptr<DWARFDebugFrame> EHFrame;
- std::unique_ptr<DWARFDebugMacro> Macro;
- std::unique_ptr<DWARFDebugMacro> Macinfo;
- std::unique_ptr<DWARFDebugNames> Names;
- std::unique_ptr<AppleAcceleratorTable> AppleNames;
- std::unique_ptr<AppleAcceleratorTable> AppleTypes;
- std::unique_ptr<AppleAcceleratorTable> AppleNamespaces;
- std::unique_ptr<AppleAcceleratorTable> AppleObjC;
-
- DWARFUnitVector DWOUnits;
- std::optional<DenseMap<uint64_t, DWARFTypeUnit *>> DWOTypeUnits;
- std::unique_ptr<DWARFDebugAbbrev> AbbrevDWO;
- std::unique_ptr<DWARFDebugMacro> MacinfoDWO;
- std::unique_ptr<DWARFDebugMacro> 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<const DWARFDebugLine::LineTable *>
+ getLineTableForUnit(DWARFUnit *U,
+ function_ref<void(Error)> RecoverableErrHandler) = 0;
+ virtual void clearLineTableForUnit(DWARFUnit *U) = 0;
+ virtual Expected<const DWARFDebugFrame *> getDebugFrame() = 0;
+ virtual Expected<const DWARFDebugFrame *> 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<DWARFContext>
+ getDWOContext(StringRef AbsolutePath) = 0;
+ virtual const DenseMap<uint64_t, DWARFTypeUnit *> &
+ getTypeUnitMap(bool IsDWO) = 0;
+
+ /// Parse a macro[.dwo] or macinfo[.dwo] section.
+ std::unique_ptr<DWARFDebugMacro>
+ 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<DWARFContextState> State;
/// The maximum DWARF version of all units.
unsigned MaxVersion = 0;
- struct DWOFile {
- object::OwningBinary<object::ObjectFile> File;
- std::unique_ptr<DWARFContext> Context;
- };
- StringMap<std::weak_ptr<DWOFile>> DWOFiles;
- std::weak_ptr<DWOFile> DWP;
- bool CheckedForDWP = false;
- std::string DWPName;
std::function<void(Error)> RecoverableErrorHandler =
WithColor::defaultErrorHandler;
std::function<void(Error)> 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<const DWARFObject> 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 @@ class DWARFContext : public DIContext {
std::function<void(Error)> RecoverableErrorHandler =
WithColor::defaultErrorHandler,
std::function<void(Error)> WarningHandler =
- WithColor::defaultWarningHandler);
+ WithColor::defaultWarningHandler,
+ bool ThreadSafe = false);
~DWARFContext() override;
DWARFContext(DWARFContext &) = delete;
@@ -147,20 +166,19 @@ class DWARFContext : public DIContext {
/// 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 @@ class DWARFContext : public DIContext {
/// 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 @@ class DWARFContext : public DIContext {
/// 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 @@ class DWARFContext : public DIContext {
std::function<void(Error)> RecoverableErrorHandler =
WithColor::defaultErrorHandler,
std::function<void(Error)> WarningHandler =
- WithColor::defaultWarningHandler);
+ WithColor::defaultWarningHandler,
+ bool ThreadSafe = false);
static std::unique_ptr<DWARFContext>
create(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections,
@@ -432,7 +444,8 @@ class DWARFContext : public DIContext {
std::function<void(Error)> RecoverableErrorHandler =
WithColor::defaultErrorHandler,
std::function<void(Error)> 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 @@ class DWARFContext : public DIContext {
void setParseCUTUIndexManually(bool PCUTU) { ParseCUTUIndexManually = PCUTU; }
private:
- /// Parse a macro[.dwo] or macinfo[.dwo] section.
- std::unique_ptr<DWARFDebugMacro>
- parseMacroOrMacinfo(MacroSecType SectionType);
-
void addLocalsForDie(DWARFCompileUnit *CU, DWARFDie Subprogram, DWARFDie Die,
std::vector<DILocal> &Result);
};
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
index 9830e8c600bd098..a45ed0e56553d4e 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
@@ -70,13 +70,675 @@ using DWARFLineTable = DWARFDebugLine::LineTable;
using FileLineInfoKind = DILineInfoSpecifier::FileLineInfoKind;
using FunctionNameKind = DILineInfoSpecifier::FunctionNameKind;
+
+void fixupIndexV4(DWARFContext &C, DWARFUnitIndex &Index) {
+ using EntryType = DWARFUnitIndex::Entry::SectionContribution;
+ using EntryMap = DenseMap<uint32_t, EntryType>;
+ 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<uint32_t>::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<uint64_t, uint64_t> Map;
+
+ const auto &DObj = C.getDWARFObj();
+ DObj.forEachInfoDWOSections([&](const DWARFSection &S) {
+ if (!(C.getParseCUTUIndexManually() ||
+ S.Data.size() >= std::numeric_limits<uint32_t>::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 <typename T>
+static T &getAccelTable(std::unique_ptr<T> &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<DWARFDebugMacro>
+DWARFContext::DWARFContextState::parseMacroOrMacinfo(MacroSecType SectionType) {
+ auto Macro = std::make_unique<DWARFDebugMacro>();
+ 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<DenseMap<uint64_t, DWARFTypeUnit *>> NormalTypeUnits;
+ std::unique_ptr<DWARFUnitIndex> CUIndex;
+ std::unique_ptr<DWARFGdbIndex> GdbIndex;
+ std::unique_ptr<DWARFUnitIndex> TUIndex;
+ std::unique_ptr<DWARFDebugAbbrev> Abbrev;
+ std::unique_ptr<DWARFDebugLoc> Loc;
+ std::unique_ptr<DWARFDebugAranges> Aranges;
+ std::unique_ptr<DWARFDebugLine> Line;
+ std::unique_ptr<DWARFDebugFrame> DebugFrame;
+ std::unique_ptr<DWARFDebugFrame> EHFrame;
+ std::unique_ptr<DWARFDebugMacro> Macro;
+ std::unique_ptr<DWARFDebugMacro> Macinfo;
+ std::unique_ptr<DWARFDebugNames> Names;
+ std::unique_ptr<AppleAcceleratorTable> AppleNames;
+ std::unique_ptr<AppleAcceleratorTable> AppleTypes;
+ std::unique_ptr<AppleAcceleratorTable> AppleNamespaces;
+ std::unique_ptr<AppleAcceleratorTable> AppleObjC;
+ DWARFUnitVector DWOUnits;
+ std::optional<DenseMap<uint64_t, DWARFTypeUnit *>> DWOTypeUnits;
+ std::unique_ptr<DWARFDebugAbbrev> AbbrevDWO;
+ std::unique_ptr<DWARFDebugMacro> MacinfoDWO;
+ std::unique_ptr<DWARFDebugMacro> MacroDWO;
+ struct DWOFile {
+ object::OwningBinary<object::ObjectFile> File;
+ std::unique_ptr<DWARFContext> Context;
+ };
+ StringMap<std::weak_ptr<DWOFile>> DWOFiles;
+ std::weak_ptr<DWOFile> 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<DWARFDebugAbbrev>(abbrData);
+ return AbbrevDWO.get();
+ }
+
+ const DWARFUnitIndex &getCUIndex() override {
+ if (CUIndex)
+ return *CUIndex;
+
+ DataExtractor Data(D.getDWARFObj().getCUIndexSection(),
+ D.isLittleEndian(), 0);
+ CUIndex = std::make_unique<DWARFUnitIndex>(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<DWARFUnitIndex>(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<DWARFGdbIndex>();
+ 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<DWARFDebugAbbrev>(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<const DWARFDebugLine::LineTable *>
+ getLineTableForUnit(DWARFUnit *U, function_ref<void(Error)> 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<const DWARFDebugFrame *> 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<DWARFDebugFrame>(D.getArch(), /*IsEH=*/false,
+ DS.Address);
+ if (Error E = DF->parse(Data))
+ return std::move(E);
+
+ DebugFrame.swap(DF);
+ return DebugFrame.get();
+ }
+
+ Expected<const DWARFDebugFrame *> 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<DWARFDebugFrame>(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<DWARFContext>
+ getDWOContext(StringRef AbsolutePath) override {
+ if (auto S = DWP.lock()) {
+ DWARFContext *Ctxt = S->Context.get();
+ return std::shared_ptr<DWARFContext>(std::move(S), Ctxt);
+ }
+
+ std::weak_ptr<DWOFile> *Entry = &DWOFiles[AbsolutePath];
+
+ if (auto S = Entry->lock()) {
+ DWARFContext *Ctxt = S->Context.get();
+ return std::shared_ptr<DWARFContext>(std::move(S), Ctxt);
+ }
+
+ const DWARFObject &DObj = D.getDWARFObj();
+
+ Expected<OwningBinary<ObjectFile>> 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<DWOFile>();
+ 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<DWARFContext>(std::move(S), Ctxt);
+ }
+
+ const DenseMap<uint64_t, DWARFTypeUnit *> &getNormalTypeUnitMap() {
+ if (!NormalTypeUnits) {
+ NormalTypeUnits.emplace();
+ for (const auto &U :D.normal_units()) {
+ if (DWARFTypeUnit *TU = dyn_cast<DWARFTypeUnit>(U.get()))
+ (*NormalTypeUnits)[TU->getTypeHash()] = TU;
+ }
+ }
+ return *NormalTypeUnits;
+ }
+
+ const DenseMap<uint64_t, DWARFTypeUnit *> &getDWOTypeUnitMap() {
+ if (!DWOTypeUnits) {
+ DWOTypeUnits.emplace();
+ for (const auto &U :D.dwo_units()) {
+ if (DWARFTypeUnit *TU = dyn_cast<DWARFTypeUnit>(U.get()))
+ (*DWOTypeUnits)[TU->getTypeHash()] = TU;
+ }
+ }
+ return *DWOTypeUnits;
+ }
+
+ const DenseMap<uint64_t, DWARFTypeUnit *> &
+ 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<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getNormalUnits();
+ }
+ DWARFUnitVector &getDWOUnits(bool Lazy) override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getDWOUnits(Lazy);
+ }
+ const DWARFUnitIndex &getCUIndex() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getCUIndex();
+ }
+ const DWARFDebugAbbrev *getDebugAbbrevDWO() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getDebugAbbrevDWO();
+ }
+
+ const DWARFUnitIndex &getTUIndex() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getTUIndex();
+ }
+ DWARFGdbIndex &getGdbIndex() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getGdbIndex();
+ }
+ const DWARFDebugAbbrev *getDebugAbbrev() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getDebugAbbrev();
+ }
+ const DWARFDebugLoc *getDebugLoc() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getDebugLoc();
+ }
+ const DWARFDebugAranges *getDebugAranges() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getDebugAranges();
+ }
+ Expected<const DWARFDebugLine::LineTable *>
+ getLineTableForUnit(DWARFUnit *U, function_ref<void(Error)> RecoverableErrorHandler) override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getLineTableForUnit(U, RecoverableErrorHandler);
+ }
+ void clearLineTableForUnit(DWARFUnit *U) override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::clearLineTableForUnit(U);
+ }
+ Expected<const DWARFDebugFrame *> getDebugFrame() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getDebugFrame();
+ }
+ Expected<const DWARFDebugFrame *> getEHFrame() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getEHFrame();
+ }
+ const DWARFDebugMacro *getDebugMacinfo() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getDebugMacinfo();
+ }
+ const DWARFDebugMacro *getDebugMacinfoDWO() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getDebugMacinfoDWO();
+ }
+ const DWARFDebugMacro *getDebugMacro() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getDebugMacro();
+ }
+ const DWARFDebugMacro *getDebugMacroDWO() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getDebugMacroDWO();
+ }
+ const DWARFDebugNames &getDebugNames() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getDebugNames();
+ }
+ const AppleAcceleratorTable &getAppleNames() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getAppleNames();
+ }
+ const AppleAcceleratorTable &getAppleTypes() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getAppleTypes();
+ }
+ const AppleAcceleratorTable &getAppleNamespaces() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getAppleNamespaces();
+ }
+ const AppleAcceleratorTable &getAppleObjC() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getAppleObjC();
+ }
+ std::shared_ptr<DWARFContext>
+ getDWOContext(StringRef AbsolutePath) override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getDWOContext(AbsolutePath);
+ }
+ const DenseMap<uint64_t, DWARFTypeUnit *> &
+ getTypeUnitMap(bool IsDWO) override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getTypeUnitMap(IsDWO);
+ }
+};
+
+
+
DWARFContext::DWARFContext(std::unique_ptr<const DWARFObject> DObj,
std::string DWPName,
std::function<void(Error)> RecoverableErrorHandler,
- std::function<void(Error)> WarningHandler)
- : DIContext(CK_DWARF), DWPName(std::move(DWPName)),
+ std::function<void(Error)> 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 @@ static void dumpRnglistsSection(
}
}
-std::unique_ptr<DWARFDebugMacro>
-DWARFContext::parseMacroOrMacinfo(MacroSecType SectionType) {
- auto Macro = std::make_unique<DWARFDebugMacro>();
- 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 @@ void DWARFContext::dump(
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<DWARFTypeUnit>(
DWOUnits.getUnitForIndexEntry(*R));
return nullptr;
}
-
- struct UnitContainers {
- const DWARFUnitVector &Units;
- std::optional<DenseMap<uint64_t, DWARFTypeUnit *>> ⤅
- };
- 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<DWARFTypeUnit>(U.get()))
- (*Units.Map)[TU->getTypeHash()] = TU;
- }
- }
-
- return (*Units.Map)[Hash];
+ const DenseMap<uint64_t, DWARFTypeUnit *> &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 @@ DWARFCompileUnit *DWARFContext::getDWOCompileUnitForHash(uint64_t Hash) {
}
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 @@ bool DWARFContext::verify(raw_ostream &OS, DIDumpOptions DumpOpts) {
return Success;
}
-void fixupIndexV4(const DWARFObject &DObj, DWARFContext &C,
- DWARFUnitIndex &Index) {
- using EntryType = DWARFUnitIndex::Entry::SectionContribution;
- using EntryMap = DenseMap<uint32_t, EntryType>;
- 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<uint32_t>::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<uint64_t, uint64_t> Map;
-
- DObj.forEachInfoDWOSections([&](const DWARFSection &S) {
- if (!(C.getParseCUTUIndexManually() ||
- S.Data.size() >= std::numeric_limits<uint32_t>::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<DWARFUnitIndex>(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<DWARFUnitIndex>(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<DWARFGdbIndex>();
- 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<DWARFDebugAbbrev>(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<DWARFDebugAbbrev>(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<const DWARFDebugFrame *> 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<DWARFDebugFrame>(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<const DWARFDebugFrame *> DWARFContext::getEHFrame() {
- if (EHFrame)
- return EHFrame.get();
-
- const DWARFSection &DS = DObj->getEHFrameSection();
- DWARFDataExtractor DebugFrameData(*DObj, DS, isLittleEndian(),
- DObj->getAddressSize());
-
- auto DF =
- std::make_unique<DWARFDebugFrame>(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 <typename T>
-static T &getAccelTable(std::unique_ptr<T> &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 @@ DWARFContext::getLineTableForUnit(DWARFUnit *U) {
Expected<const DWARFDebugLine::LineTable *> DWARFContext::getLineTableForUnit(
DWARFUnit *U, function_ref<void(Error)> 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<DWARFCompileUnit>(
- NormalUnits.getUnitForOffset(Offset));
+ State->getNormalUnits().getUnitForOffset(Offset));
}
DWARFCompileUnit *DWARFContext::getCompileUnitForCodeAddress(uint64_t Address) {
@@ -1519,52 +1845,7 @@ DWARFContext::getInliningInfoForAddress(object::SectionedAddress Address,
std::shared_ptr<DWARFContext>
DWARFContext::getDWOContext(StringRef AbsolutePath) {
- if (auto S = DWP.lock()) {
- DWARFContext *Ctxt = S->Context.get();
- return std::shared_ptr<DWARFContext>(std::move(S), Ctxt);
- }
-
- std::weak_ptr<DWOFile> *Entry = &DWOFiles[AbsolutePath];
-
- if (auto S = Entry->lock()) {
- DWARFContext *Ctxt = S->Context.get();
- return std::shared_ptr<DWARFContext>(std::move(S), Ctxt);
- }
-
- Expected<OwningBinary<ObjectFile>> 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<DWOFile>();
- 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<DWARFContext>(std::move(S), Ctxt);
+ return State->getDWOContext(AbsolutePath);
}
static Error createError(const Twine &Reason, llvm::Error E) {
@@ -2115,23 +2396,27 @@ DWARFContext::create(const object::ObjectFile &Obj,
ProcessDebugRelocations RelocAction,
const LoadedObjectInfo *L, std::string DWPName,
std::function<void(Error)> RecoverableErrorHandler,
- std::function<void(Error)> WarningHandler) {
+ std::function<void(Error)> WarningHandler,
+ bool ThreadSafe) {
auto DObj = std::make_unique<DWARFObjInMemory>(
Obj, L, RecoverableErrorHandler, WarningHandler, RelocAction);
- return std::make_unique<DWARFContext>(std::move(DObj), std::move(DWPName),
+ return std::make_unique<DWARFContext>(std::move(DObj),
+ std::move(DWPName),
RecoverableErrorHandler,
- WarningHandler);
+ WarningHandler,
+ ThreadSafe);
}
std::unique_ptr<DWARFContext>
DWARFContext::create(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections,
uint8_t AddrSize, bool isLittleEndian,
std::function<void(Error)> RecoverableErrorHandler,
- std::function<void(Error)> WarningHandler) {
+ std::function<void(Error)> WarningHandler,
+ bool ThreadSafe) {
auto DObj =
std::make_unique<DWARFObjInMemory>(Sections, AddrSize, isLittleEndian);
return std::make_unique<DWARFContext>(
- 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
index a0cac8b7dbc3bb7..5680c8c5a449eda 100644
--- a/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
+++ b/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
@@ -337,7 +337,14 @@ static llvm::Error handleObjectFile(ObjectFile &Obj,
}
// Make sure there is DWARF to convert first.
- std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(Obj);
+ std::unique_ptr<DWARFContext> 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");
More information about the llvm-commits
mailing list