[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