diff options
-rw-r--r-- | llvm/tools/dsymutil/DebugMap.h | 2 | ||||
-rw-r--r-- | llvm/tools/dsymutil/DwarfLinker.cpp | 555 |
2 files changed, 338 insertions, 219 deletions
diff --git a/llvm/tools/dsymutil/DebugMap.h b/llvm/tools/dsymutil/DebugMap.h index b30385fefba..2173ba6d4c2 100644 --- a/llvm/tools/dsymutil/DebugMap.h +++ b/llvm/tools/dsymutil/DebugMap.h @@ -102,6 +102,8 @@ public: const_iterator end() const { return Objects.end(); } + unsigned getNumberOfObjects() const { return Objects.size(); } + /// This function adds an DebugMapObject to the list owned by this /// debug map. DebugMapObject & diff --git a/llvm/tools/dsymutil/DwarfLinker.cpp b/llvm/tools/dsymutil/DwarfLinker.cpp index 04b5210a1c8..cfab4af3c32 100644 --- a/llvm/tools/dsymutil/DwarfLinker.cpp +++ b/llvm/tools/dsymutil/DwarfLinker.cpp @@ -101,6 +101,20 @@ namespace dsymutil { namespace { +/// Helper for making strong types. +template <typename T, typename S> class StrongType : public T { +public: + template <typename... Args> + explicit StrongType(Args... A) : T(std::forward<Args>(A)...) {} +}; + +/// It's very easy to introduce bugs by passing the wrong string pool. By using +/// strong types the interface enforces that the right kind of pool is used. +struct UniqueTag {}; +struct OffsetsTag {}; +using UniquingStringPool = StrongType<NonRelocatableStringpool, UniqueTag>; +using OffsetsStringPool = StrongType<NonRelocatableStringpool, OffsetsTag>; + /// Small helper that resolves and caches file paths. This helps reduce the /// number of calls to realpath which is expensive. We assume the input are /// files, and cache the realpath of their parent. This way we can quickly @@ -282,7 +296,7 @@ public: /// dsymutil-classic functionality. PointerIntPair<DeclContext *, 1> getChildDeclContext(DeclContext &Context, const DWARFDie &DIE, - CompileUnit &Unit, NonRelocatableStringpool &StringPool, + CompileUnit &Unit, UniquingStringPool &StringPool, bool InClangModule); DeclContext &getRoot() { return Root; } @@ -1426,6 +1440,25 @@ void DwarfStreamer::emitFDE(uint32_t CIEOffset, uint32_t AddrSize, namespace { +/// Partial address range for debug map objects. Besides an offset, only the +/// HighPC is stored. The structure is stored in a map where the LowPC is the +/// key. +struct DebugMapObjectRange { + /// Function HighPC. + uint64_t HighPC; + /// Offset to apply to the linked address. + int64_t Offset; + + DebugMapObjectRange(uint64_t EndPC, int64_t Offset) + : HighPC(EndPC), Offset(Offset) {} + + DebugMapObjectRange() : HighPC(0), Offset(0) {} +}; + +/// Map LowPC to DebugMapObjectRange. +using RangesTy = std::map<uint64_t, DebugMapObjectRange>; +using UnitListTy = std::vector<std::unique_ptr<CompileUnit>>; + /// The core of the Dwarf linking logic. /// /// The link of the dwarf information from the object files will be @@ -1443,20 +1476,15 @@ namespace { class DwarfLinker { public: DwarfLinker(raw_fd_ostream &OutFile, const LinkOptions &Options) - : OutFile(OutFile), Options(Options), BinHolder(Options.Verbose) {} + : OutFile(OutFile), Options(Options) {} /// Link the contents of the DebugMap. bool link(const DebugMap &); - void reportWarning(const Twine &Warning, const DWARFDie *DIE = nullptr) const; + void reportWarning(const Twine &Warning, const DebugMapObject &DMO, + const DWARFDie *DIE = nullptr) const; private: - /// Called at the start of a debug object link. - void startDebugObject(DWARFContext &, DebugMapObject &); - - /// Called at the end of a debug object link. - void endDebugObject(); - /// Remembers the newest DWARF version we've seen in a unit. void maybeUpdateMaxDwarfVersion(unsigned Version) { if (MaxDwarfVersion < Version) @@ -1480,7 +1508,7 @@ private: } }; - DwarfLinker &Linker; + const DwarfLinker &Linker; /// The valid relocations for the current DebugMapObject. /// This vector is sorted by relocation offset. @@ -1523,6 +1551,37 @@ private: bool isLittleEndian); }; + /// Keeps track of data associated with one object during linking. + struct LinkContext { + DebugMapObject &DMO; + BinaryHolder BinaryHolder; + const object::ObjectFile *ObjectFile; + RelocationManager RelocMgr; + std::unique_ptr<DWARFContext> DwarfContext; + RangesTy Ranges; + UnitListTy CompileUnits; + + LinkContext(const DebugMap &Map, DwarfLinker &Linker, DebugMapObject &DMO, + bool Verbose = false) + : DMO(DMO), BinaryHolder(Verbose), RelocMgr(Linker) { + auto ErrOrObj = Linker.loadObject(BinaryHolder, DMO, Map); + ObjectFile = ErrOrObj ? &*ErrOrObj : nullptr; + DwarfContext = ObjectFile ? DWARFContext::create(*ObjectFile) : nullptr; + } + + /// Clear compile units and ranges. + void Clear() { + CompileUnits.clear(); + Ranges.clear(); + } + }; + + /// Called at the start of a debug object link. + void startDebugObject(LinkContext &Context); + + /// Called at the end of a debug object link. + void endDebugObject(LinkContext &Context); + /// \defgroup FindRootDIEs Find DIEs corresponding to debug map entries. /// /// @{ @@ -1530,7 +1589,8 @@ private: /// keep. Store that information in \p CU's DIEInfo. /// /// The return value indicates whether the DIE is incomplete. - bool lookForDIEsToKeep(RelocationManager &RelocMgr, const DWARFDie &DIE, + bool lookForDIEsToKeep(RelocationManager &RelocMgr, RangesTy &Ranges, + UnitListTy &Units, const DWARFDie &DIE, const DebugMapObject &DMO, CompileUnit &CU, unsigned Flags); @@ -1541,14 +1601,23 @@ private: /// pointing to the module, and a DW_AT_gnu_dwo_id with the module /// hash. bool registerModuleReference(const DWARFDie &CUDie, const DWARFUnit &Unit, - DebugMap &ModuleMap, unsigned Indent = 0); + DebugMap &ModuleMap, const DebugMapObject &DMO, + RangesTy &Ranges, + OffsetsStringPool &OffsetsStringPool, + UniquingStringPool &UniquingStringPoolStringPool, + DeclContextTree &ODRContexts, unsigned &UnitID, + unsigned Indent = 0); /// Recursively add the debug info in this clang module .pcm /// file (and all the modules imported by it in a bottom-up fashion) /// to Units. Error loadClangModule(StringRef Filename, StringRef ModulePath, StringRef ModuleName, uint64_t DwoId, - DebugMap &ModuleMap, unsigned Indent = 0); + DebugMap &ModuleMap, const DebugMapObject &DMO, + RangesTy &Ranges, OffsetsStringPool &OffsetsStringPool, + UniquingStringPool &UniquingStringPool, + DeclContextTree &ODRContexts, unsigned &UnitID, + unsigned Indent = 0); /// Flags passed to DwarfLinker::lookForDIEsToKeep enum TravesalFlags { @@ -1561,12 +1630,14 @@ private: }; /// Mark the passed DIE as well as all the ones it depends on as kept. - void keepDIEAndDependencies(RelocationManager &RelocMgr, const DWARFDie &DIE, + void keepDIEAndDependencies(RelocationManager &RelocMgr, RangesTy &Ranges, + UnitListTy &Units, const DWARFDie &DIE, CompileUnit::DIEInfo &MyInfo, const DebugMapObject &DMO, CompileUnit &CU, bool UseODR); - unsigned shouldKeepDIE(RelocationManager &RelocMgr, const DWARFDie &DIE, + unsigned shouldKeepDIE(RelocationManager &RelocMgr, RangesTy &Ranges, + const DWARFDie &DIE, const DebugMapObject &DMO, CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo, unsigned Flags); @@ -1575,7 +1646,8 @@ private: CompileUnit::DIEInfo &MyInfo, unsigned Flags); unsigned shouldKeepSubprogramDIE(RelocationManager &RelocMgr, - const DWARFDie &DIE, CompileUnit &Unit, + RangesTy &Ranges, const DWARFDie &DIE, + const DebugMapObject &DMO, CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo, unsigned Flags); @@ -1616,13 +1688,17 @@ private: /// applied to the entry point of the function to get the linked address. /// \param Die the output DIE to use, pass NULL to create one. /// \returns the root of the cloned tree or null if nothing was selected. - DIE *cloneDIE(const DWARFDie &InputDIE, CompileUnit &U, int64_t PCOffset, - uint32_t OutOffset, unsigned Flags, DIE *Die = nullptr); + DIE *cloneDIE(const DWARFDie &InputDIE, const DebugMapObject &DMO, + CompileUnit &U, OffsetsStringPool &StringPool, + int64_t PCOffset, uint32_t OutOffset, unsigned Flags, + DIE *Die = nullptr); /// Construct the output DIE tree by cloning the DIEs we /// chose to keep above. If there are no valid relocs, then there's /// nothing to clone/emit. - void cloneAllCompileUnits(DWARFContext &DwarfContext); + void cloneAllCompileUnits(DWARFContext &DwarfContext, + const DebugMapObject &DMO, RangesTy &Ranges, + OffsetsStringPool &StringPool); private: using AttributeSpec = DWARFAbbreviationDeclaration::AttributeSpec; @@ -1659,7 +1735,9 @@ private: }; /// Helper for cloneDIE. - unsigned cloneAttribute(DIE &Die, const DWARFDie &InputDIE, CompileUnit &U, + unsigned cloneAttribute(DIE &Die, const DWARFDie &InputDIE, + const DebugMapObject &DMO, CompileUnit &U, + OffsetsStringPool &StringPool, const DWARFFormValue &Val, const AttributeSpec AttrSpec, unsigned AttrSize, AttributesInfo &AttrInfo); @@ -1669,6 +1747,7 @@ private: /// \returns the size of the new attribute. unsigned cloneStringAttribute(DIE &Die, AttributeSpec AttrSpec, const DWARFFormValue &Val, const DWARFUnit &U, + OffsetsStringPool &StringPool, AttributesInfo &Info); /// Clone an attribute referencing another DIE and add @@ -1678,6 +1757,7 @@ private: AttributeSpec AttrSpec, unsigned AttrSize, const DWARFFormValue &Val, + const DebugMapObject &DMO, CompileUnit &Unit); /// Clone an attribute referencing another DIE and add @@ -1697,7 +1777,8 @@ private: /// Clone a scalar attribute and add it to \p Die. /// \returns the size of the new attribute. unsigned cloneScalarAttribute(DIE &Die, const DWARFDie &InputDIE, - CompileUnit &U, AttributeSpec AttrSpec, + const DebugMapObject &DMO, CompileUnit &U, + AttributeSpec AttrSpec, const DWARFFormValue &Val, unsigned AttrSize, AttributesInfo &Info); @@ -1706,17 +1787,19 @@ private: /// already there. /// \returns is a name was found. bool getDIENames(const DWARFDie &Die, AttributesInfo &Info, - bool StripTemplate = false); + OffsetsStringPool &StringPool, bool StripTemplate = false); /// Create a copy of abbreviation Abbrev. void copyAbbrev(const DWARFAbbreviationDeclaration &Abbrev, bool hasODR); uint32_t hashFullyQualifiedName(DWARFDie DIE, CompileUnit &U, + const DebugMapObject &DMO, int RecurseDepth = 0); /// Helper for cloneDIE. void addObjCAccelerator(CompileUnit &Unit, const DIE *Die, - DwarfStringPoolEntryRef Name, bool SkipPubSection); + DwarfStringPoolEntryRef Name, + OffsetsStringPool &StringPool, bool SkipPubSection); }; /// Assign an abbreviation number to \p Abbrev @@ -1724,7 +1807,8 @@ private: /// Compute and emit debug_ranges section for \p Unit, and /// patch the attributes referencing it. - void patchRangesForUnit(const CompileUnit &Unit, DWARFContext &Dwarf) const; + void patchRangesForUnit(const CompileUnit &Unit, DWARFContext &Dwarf, + const DebugMapObject &DMO) const; /// Generate and emit the DW_AT_ranges attribute for a compile_unit if it had /// one. @@ -1733,14 +1817,15 @@ private: /// Extract the line tables from the original dwarf, extract the relevant /// parts according to the linked function ranges and emit the result in the /// debug_line section. - void patchLineTableForUnit(CompileUnit &Unit, DWARFContext &OrigDwarf); + void patchLineTableForUnit(CompileUnit &Unit, DWARFContext &OrigDwarf, + RangesTy &Ranges, const DebugMapObject &DMO); /// Emit the accelerator entries for \p Unit. void emitAcceleratorEntriesForUnit(CompileUnit &Unit); /// Patch the frame info for an object file and emit it. - void patchFrameInfoForObject(const DebugMapObject &, DWARFContext &, - unsigned AddressSize); + void patchFrameInfoForObject(const DebugMapObject &, RangesTy &Ranges, + DWARFContext &, unsigned AddressSize); /// FoldingSet that uniques the abbreviations. FoldingSet<DIEAbbrev> AbbreviationsSet; @@ -1760,9 +1845,6 @@ private: BumpPtrAllocator DIEAlloc; /// @} - /// ODR Contexts for that link. - DeclContextTree ODRContexts; - /// \defgroup Helpers Various helper methods. /// /// @{ @@ -1770,42 +1852,19 @@ private: /// Attempt to load a debug object from disk. ErrorOr<const object::ObjectFile &> loadObject(BinaryHolder &BinaryHolder, - DebugMapObject &Obj, + const DebugMapObject &Obj, const DebugMap &Map); /// @} raw_fd_ostream &OutFile; LinkOptions Options; - BinaryHolder BinHolder; std::unique_ptr<DwarfStreamer> Streamer; uint64_t OutputDebugInfoSize; - - /// A unique ID that identifies each compile unit. - unsigned UnitID; - unsigned MaxDwarfVersion = 0; - /// The units of the current debug map object. - std::vector<std::unique_ptr<CompileUnit>> Units; - - /// The debug map object currently under consideration. - DebugMapObject *CurrentDebugObject; - - /// The Dwarf string pool. - NonRelocatableStringpool StringPool; - - /// This map is keyed by the entry PC of functions in that - /// debug object and the associated value is a pair storing the - /// corresponding end PC and the offset to apply to get the linked - /// address. - /// - /// See startDebugObject() for a more complete description of its use. - std::map<uint64_t, std::pair<uint64_t, int64_t>> Ranges; - - /// The CIEs that have been emitted in the output - /// section. The actual CIE data serves a the key to this StringMap, - /// this takes care of comparing the semantics of CIEs defined in - /// different object files. + /// The CIEs that have been emitted in the output section. The actual CIE + /// data serves a the key to this StringMap, this takes care of comparing the + /// semantics of CIEs defined in different object files. StringMap<uint32_t> EmittedCIEs; /// Offset of the last CIE that has been emitted in the output @@ -1844,7 +1903,7 @@ getUnitForOffset(std::vector<std::unique_ptr<CompileUnit>> &Units, /// The resulting DIE might be in another CompileUnit which is stored into \p /// ReferencedCU. \returns null if resolving fails for any reason. static DWARFDie -resolveDIEReference(const DwarfLinker &Linker, +resolveDIEReference(const DwarfLinker &Linker, const DebugMapObject &DMO, std::vector<std::unique_ptr<CompileUnit>> &Units, const DWARFFormValue &RefValue, const DWARFUnit &Unit, const DWARFDie &DIE, CompileUnit *&RefCU) { @@ -1859,7 +1918,7 @@ resolveDIEReference(const DwarfLinker &Linker, return RefDie; } - Linker.reportWarning("could not find referenced DIE", &DIE); + Linker.reportWarning("could not find referenced DIE", DMO, &DIE); return DWARFDie(); } @@ -1908,7 +1967,7 @@ bool DeclContext::setLastSeenDIE(CompileUnit &U, const DWARFDie &Die) { PointerIntPair<DeclContext *, 1> DeclContextTree::getChildDeclContext( DeclContext &Context, const DWARFDie &DIE, CompileUnit &U, - NonRelocatableStringpool &StringPool, bool InClangModule) { + UniquingStringPool &StringPool, bool InClangModule) { unsigned Tag = DIE.getTag(); // FIXME: dsymutil-classic compat: We should bail out here if we @@ -2074,6 +2133,7 @@ PointerIntPair<DeclContext *, 1> DeclContextTree::getChildDeclContext( bool DwarfLinker::DIECloner::getDIENames(const DWARFDie &Die, AttributesInfo &Info, + OffsetsStringPool &StringPool, bool StripTemplate) { // This function will be called on DIEs having low_pcs and // ranges. As getting the name might be more expansive, filter out @@ -2085,17 +2145,17 @@ bool DwarfLinker::DIECloner::getDIENames(const DWARFDie &Die, // short name. if (!Info.MangledName) if (const char *MangledName = Die.getName(DINameKind::LinkageName)) - Info.MangledName = Linker.StringPool.getEntry(MangledName); + Info.MangledName = StringPool.getEntry(MangledName); if (!Info.Name) if (const char *Name = Die.getName(DINameKind::ShortName)) - Info.Name = Linker.StringPool.getEntry(Name); + Info.Name = StringPool.getEntry(Name); if (StripTemplate && Info.Name && Info.MangledName != Info.Name) { // FIXME: dsymutil compatibility. This is wrong for operator< auto Split = Info.Name.getString().split('<'); if (!Split.second.empty()) - Info.NameWithoutTemplate = Linker.StringPool.getEntry(Split.first); + Info.NameWithoutTemplate = StringPool.getEntry(Split.first); } return Info.Name || Info.MangledName; @@ -2103,11 +2163,9 @@ bool DwarfLinker::DIECloner::getDIENames(const DWARFDie &Die, /// Report a warning to the user, optionally including information about a /// specific \p DIE related to the warning. -void DwarfLinker::reportWarning(const Twine &Warning, +void DwarfLinker::reportWarning(const Twine &Warning, const DebugMapObject &DMO, const DWARFDie *DIE) const { - StringRef Context = "<debug map>"; - if (CurrentDebugObject) - Context = CurrentDebugObject->getObjectFilename(); + StringRef Context = DMO.getObjectFilename(); warn(Warning, Context); if (!Options.Verbose || !DIE) @@ -2138,7 +2196,7 @@ bool DwarfLinker::createStreamer(const Triple &TheTriple, /// (i.e., forward declarations that are children of a DW_TAG_module). static bool analyzeContextInfo(const DWARFDie &DIE, unsigned ParentIdx, CompileUnit &CU, DeclContext *CurrentDeclContext, - NonRelocatableStringpool &StringPool, + UniquingStringPool &StringPool, DeclContextTree &Contexts, bool InImportedModule = false) { unsigned MyIdx = CU.getOrigUnit().getDIEIndex(DIE); @@ -2210,34 +2268,35 @@ static bool dieNeedsChildrenToBeMeaningful(uint32_t Tag) { llvm_unreachable("Invalid Tag"); } -void DwarfLinker::startDebugObject(DWARFContext &Dwarf, DebugMapObject &Obj) { +void DwarfLinker::startDebugObject(LinkContext &Context) { // Iterate over the debug map entries and put all the ones that are - // functions (because they have a size) into the Ranges map. This - // map is very similar to the FunctionRanges that are stored in each - // unit, with 2 notable differences: - // - obviously this one is global, while the other ones are per-unit. - // - this one contains not only the functions described in the DIE - // tree, but also the ones that are only in the debug map. - // The latter information is required to reproduce dsymutil's logic - // while linking line tables. The cases where this information - // matters look like bugs that need to be investigated, but for now - // we need to reproduce dsymutil's behavior. + // functions (because they have a size) into the Ranges map. This map is + // very similar to the FunctionRanges that are stored in each unit, with 2 + // notable differences: + // + // 1. Obviously this one is global, while the other ones are per-unit. + // + // 2. This one contains not only the functions described in the DIE + // tree, but also the ones that are only in the debug map. + // + // The latter information is required to reproduce dsymutil's logic while + // linking line tables. The cases where this information matters look like + // bugs that need to be investigated, but for now we need to reproduce + // dsymutil's behavior. // FIXME: Once we understood exactly if that information is needed, // maybe totally remove this (or try to use it to do a real // -gline-tables-only on Darwin. - for (const auto &Entry : Obj.symbols()) { + for (const auto &Entry : Context.DMO.symbols()) { const auto &Mapping = Entry.getValue(); if (Mapping.Size && Mapping.ObjectAddress) - Ranges[*Mapping.ObjectAddress] = std::make_pair( + Context.Ranges[*Mapping.ObjectAddress] = DebugMapObjectRange( *Mapping.ObjectAddress + Mapping.Size, int64_t(Mapping.BinaryAddress) - *Mapping.ObjectAddress); } } -void DwarfLinker::endDebugObject() { - Units.clear(); - Ranges.clear(); - +void DwarfLinker::endDebugObject(LinkContext &Context) { + Context.Clear(); for (auto I = DIEBlocks.begin(), E = DIEBlocks.end(); I != E; ++I) (*I)->~DIEBlock(); for (auto I = DIELocs.begin(), E = DIELocs.end(); I != E; ++I) @@ -2291,14 +2350,16 @@ void DwarfLinker::RelocationManager::findValidRelocsMachO( if (isMachOPairedReloc(Obj.getAnyRelocationType(MachOReloc), Obj.getArch())) { SkipNext = true; - Linker.reportWarning(" unsupported relocation in debug_info section."); + Linker.reportWarning("unsupported relocation in debug_info section.", + DMO); continue; } unsigned RelocSize = 1 << Obj.getAnyRelocationLength(MachOReloc); uint64_t Offset64 = Reloc.getOffset(); if ((RelocSize != 4 && RelocSize != 8)) { - Linker.reportWarning(" unsupported relocation in debug_info section."); + Linker.reportWarning("unsupported relocation in debug_info section.", + DMO); continue; } uint32_t Offset = Offset64; @@ -2323,7 +2384,7 @@ void DwarfLinker::RelocationManager::findValidRelocsMachO( Expected<StringRef> SymbolName = Sym->getName(); if (!SymbolName) { consumeError(SymbolName.takeError()); - Linker.reportWarning("error getting relocation symbol name."); + Linker.reportWarning("error getting relocation symbol name.", DMO); continue; } if (const auto *Mapping = DMO.lookupSymbol(*SymbolName)) @@ -2346,8 +2407,8 @@ bool DwarfLinker::RelocationManager::findValidRelocs( if (auto *MachOObj = dyn_cast<object::MachOObjectFile>(&Obj)) findValidRelocsMachO(Section, *MachOObj, DMO); else - Linker.reportWarning(Twine("unsupported object file type: ") + - Obj.getFileName()); + Linker.reportWarning( + Twine("unsupported object file type: ") + Obj.getFileName(), DMO); if (ValidRelocs.empty()) return false; @@ -2491,11 +2552,10 @@ unsigned DwarfLinker::shouldKeepVariableDIE(RelocationManager &RelocMgr, /// Check if a function describing DIE should be kept. /// \returns updated TraversalFlags. -unsigned DwarfLinker::shouldKeepSubprogramDIE(RelocationManager &RelocMgr, - const DWARFDie &DIE, - CompileUnit &Unit, - CompileUnit::DIEInfo &MyInfo, - unsigned Flags) { +unsigned DwarfLinker::shouldKeepSubprogramDIE( + RelocationManager &RelocMgr, RangesTy &Ranges, const DWARFDie &DIE, + const DebugMapObject &DMO, CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo, + unsigned Flags) { const auto *Abbrev = DIE.getAbbreviationDeclarationPtr(); Flags |= TF_InFunctionScope; @@ -2541,12 +2601,13 @@ unsigned DwarfLinker::shouldKeepSubprogramDIE(RelocationManager &RelocMgr, Optional<uint64_t> HighPc = DIE.getHighPC(*LowPc); if (!HighPc) { - reportWarning("Function without high_pc. Range will be discarded.\n", &DIE); + reportWarning("Function without high_pc. Range will be discarded.\n", DMO, + &DIE); return Flags; } // Replace the debug map range with a more accurate one. - Ranges[*LowPc] = std::make_pair(*HighPc, MyInfo.AddrAdjust); + Ranges[*LowPc] = DebugMapObjectRange(*HighPc, MyInfo.AddrAdjust); Unit.addFunctionRange(*LowPc, *HighPc, MyInfo.AddrAdjust); return Flags; } @@ -2554,7 +2615,9 @@ unsigned DwarfLinker::shouldKeepSubprogramDIE(RelocationManager &RelocMgr, /// Check if a DIE should be kept. /// \returns updated TraversalFlags. unsigned DwarfLinker::shouldKeepDIE(RelocationManager &RelocMgr, - const DWARFDie &DIE, CompileUnit &Unit, + RangesTy &Ranges, const DWARFDie &DIE, + const DebugMapObject &DMO, + CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo, unsigned Flags) { switch (DIE.getTag()) { @@ -2563,7 +2626,8 @@ unsigned DwarfLinker::shouldKeepDIE(RelocationManager &RelocMgr, return shouldKeepVariableDIE(RelocMgr, DIE, Unit, MyInfo, Flags); case dwarf::DW_TAG_subprogram: case dwarf::DW_TAG_label: - return shouldKeepSubprogramDIE(RelocMgr, DIE, Unit, MyInfo, Flags); + return shouldKeepSubprogramDIE(RelocMgr, Ranges, DIE, DMO, Unit, MyInfo, + Flags); case dwarf::DW_TAG_imported_module: case dwarf::DW_TAG_imported_declaration: case dwarf::DW_TAG_imported_unit: @@ -2585,6 +2649,7 @@ unsigned DwarfLinker::shouldKeepDIE(RelocationManager &RelocMgr, /// TraversalFlags to inform it that it's not doing the primary DIE /// tree walk. void DwarfLinker::keepDIEAndDependencies(RelocationManager &RelocMgr, + RangesTy &Ranges, UnitListTy &Units, const DWARFDie &Die, CompileUnit::DIEInfo &MyInfo, const DebugMapObject &DMO, @@ -2601,7 +2666,8 @@ void DwarfLinker::keepDIEAndDependencies(RelocationManager &RelocMgr, unsigned AncestorIdx = MyInfo.ParentIdx; while (!CU.getInfo(AncestorIdx).Keep) { unsigned ODRFlag = UseODR ? TF_ODR : 0; - lookForDIEsToKeep(RelocMgr, Unit.getDIEAtIndex(AncestorIdx), DMO, CU, + lookForDIEsToKeep(RelocMgr, Ranges, Units, Unit.getDIEAtIndex(AncestorIdx), + DMO, CU, TF_ParentWalk | TF_Keep | TF_DependencyWalk | ODRFlag); AncestorIdx = CU.getInfo(AncestorIdx).ParentIdx; } @@ -2625,8 +2691,8 @@ void DwarfLinker::keepDIEAndDependencies(RelocationManager &RelocMgr, Val.extractValue(Data, &Offset, Unit.getFormParams(), &Unit); CompileUnit *ReferencedCU; - if (auto RefDie = - resolveDIEReference(*this, Units, Val, Unit, Die, ReferencedCU)) { + if (auto RefDie = resolveDIEReference(*this, DMO, Units, Val, Unit, Die, + ReferencedCU)) { uint32_t RefIdx = ReferencedCU->getOrigUnit().getDIEIndex(RefDie); CompileUnit::DIEInfo &Info = ReferencedCU->getInfo(RefIdx); bool IsModuleRef = Info.Ctxt && Info.Ctxt->getCanonicalDIEOffset() && @@ -2651,7 +2717,7 @@ void DwarfLinker::keepDIEAndDependencies(RelocationManager &RelocMgr, Info.Prune = false; unsigned ODRFlag = UseODR ? TF_ODR : 0; - lookForDIEsToKeep(RelocMgr, RefDie, DMO, *ReferencedCU, + lookForDIEsToKeep(RelocMgr, Ranges, Units, RefDie, DMO, *ReferencedCU, TF_Keep | TF_DependencyWalk | ODRFlag); // The incomplete property is propagated if the current DIE is complete @@ -2682,6 +2748,7 @@ void DwarfLinker::keepDIEAndDependencies(RelocationManager &RelocMgr, /// /// The return value indicates whether the DIE is incomplete. bool DwarfLinker::lookForDIEsToKeep(RelocationManager &RelocMgr, + RangesTy &Ranges, UnitListTy &Units, const DWARFDie &Die, const DebugMapObject &DMO, CompileUnit &CU, unsigned Flags) { @@ -2700,12 +2767,13 @@ bool DwarfLinker::lookForDIEsToKeep(RelocationManager &RelocMgr, // We must not call shouldKeepDIE while called from keepDIEAndDependencies, // because it would screw up the relocation finding logic. if (!(Flags & TF_DependencyWalk)) - Flags = shouldKeepDIE(RelocMgr, Die, CU, MyInfo, Flags); + Flags = shouldKeepDIE(RelocMgr, Ranges, Die, DMO, CU, MyInfo, Flags); // If it is a newly kept DIE mark it as well as all its dependencies as kept. if (!AlreadyKept && (Flags & TF_Keep)) { bool UseOdr = (Flags & TF_DependencyWalk) ? (Flags & TF_ODR) : CU.hasODR(); - keepDIEAndDependencies(RelocMgr, Die, MyInfo, DMO, CU, UseOdr); + keepDIEAndDependencies(RelocMgr, Ranges, Units, Die, MyInfo, DMO, CU, + UseOdr); } // The TF_ParentWalk flag tells us that we are currently walking up // the parent chain of a required DIE, and we don't want to mark all @@ -2721,7 +2789,8 @@ bool DwarfLinker::lookForDIEsToKeep(RelocationManager &RelocMgr, bool Incomplete = false; for (auto Child : Die.children()) { - Incomplete |= lookForDIEsToKeep(RelocMgr, Child, DMO, CU, Flags); + Incomplete |= + lookForDIEsToKeep(RelocMgr, Ranges, Units, Child, DMO, CU, Flags); // If any of the members are incomplete we propagate the incompleteness. if (!MyInfo.Incomplete && Incomplete && @@ -2762,27 +2831,30 @@ void DwarfLinker::AssignAbbrev(DIEAbbrev &Abbrev) { } } -unsigned DwarfLinker::DIECloner::cloneStringAttribute(DIE &Die, - AttributeSpec AttrSpec, - const DWARFFormValue &Val, - const DWARFUnit &U, - AttributesInfo &Info) { +unsigned DwarfLinker::DIECloner::cloneStringAttribute( + DIE &Die, AttributeSpec AttrSpec, const DWARFFormValue &Val, + const DWARFUnit &U, OffsetsStringPool &StringPool, AttributesInfo &Info) { // Switch everything to out of line strings. const char *String = *Val.getAsCString(); - auto StringEntry = Linker.StringPool.getEntry(String); + auto StringEntry = StringPool.getEntry(String); + + // Update attributes info. if (AttrSpec.Attr == dwarf::DW_AT_name) Info.Name = StringEntry; else if (AttrSpec.Attr == dwarf::DW_AT_MIPS_linkage_name || AttrSpec.Attr == dwarf::DW_AT_linkage_name) Info.MangledName = StringEntry; + Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr), dwarf::DW_FORM_strp, DIEInteger(StringEntry.getOffset())); + return 4; } unsigned DwarfLinker::DIECloner::cloneDieReferenceAttribute( DIE &Die, const DWARFDie &InputDIE, AttributeSpec AttrSpec, - unsigned AttrSize, const DWARFFormValue &Val, CompileUnit &Unit) { + unsigned AttrSize, const DWARFFormValue &Val, const DebugMapObject &DMO, + CompileUnit &Unit) { const DWARFUnit &U = Unit.getOrigUnit(); uint32_t Ref = *Val.getAsReference(); DIE *NewRefDie = nullptr; @@ -2790,7 +2862,7 @@ unsigned DwarfLinker::DIECloner::cloneDieReferenceAttribute( DeclContext *Ctxt = nullptr; DWARFDie RefDie = - resolveDIEReference(Linker, CompileUnits, Val, U, InputDIE, RefUnit); + resolveDIEReference(Linker, DMO, CompileUnits, Val, U, InputDIE, RefUnit); // If the referenced DIE is not found, drop the attribute. if (!RefDie || AttrSpec.Attr == dwarf::DW_AT_sibling) @@ -2942,9 +3014,9 @@ unsigned DwarfLinker::DIECloner::cloneAddressAttribute( } unsigned DwarfLinker::DIECloner::cloneScalarAttribute( - DIE &Die, const DWARFDie &InputDIE, CompileUnit &Unit, - AttributeSpec AttrSpec, const DWARFFormValue &Val, unsigned AttrSize, - AttributesInfo &Info) { + DIE &Die, const DWARFDie &InputDIE, const DebugMapObject &DMO, + CompileUnit &Unit, AttributeSpec AttrSpec, const DWARFFormValue &Val, + unsigned AttrSize, AttributesInfo &Info) { uint64_t Value; if (LLVM_UNLIKELY(Linker.Options.Update)) { @@ -2956,7 +3028,8 @@ unsigned DwarfLinker::DIECloner::cloneScalarAttribute( Value = *OptionalValue; else { Linker.reportWarning( - "Unsupported scalar attribute form. Dropping attribute.", &InputDIE); + "Unsupported scalar attribute form. Dropping attribute.", DMO, + &InputDIE); return 0; } if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value) @@ -2980,7 +3053,8 @@ unsigned DwarfLinker::DIECloner::cloneScalarAttribute( Value = *OptionalValue; else { Linker.reportWarning( - "Unsupported scalar attribute form. Dropping attribute.", &InputDIE); + "Unsupported scalar attribute form. Dropping attribute.", DMO, + &InputDIE); return 0; } PatchLocation Patch = @@ -3007,22 +3081,22 @@ unsigned DwarfLinker::DIECloner::cloneScalarAttribute( /// value \p Val, and add it to \p Die. /// \returns the size of the cloned attribute. unsigned DwarfLinker::DIECloner::cloneAttribute( - DIE &Die, const DWARFDie &InputDIE, CompileUnit &Unit, - const DWARFFormValue &Val, const AttributeSpec AttrSpec, unsigned AttrSize, - AttributesInfo &Info) { + DIE &Die, const DWARFDie &InputDIE, const DebugMapObject &DMO, + CompileUnit &Unit, OffsetsStringPool &StringPool, const DWARFFormValue &Val, + const AttributeSpec AttrSpec, unsigned AttrSize, AttributesInfo &Info) { const DWARFUnit &U = Unit.getOrigUnit(); switch (AttrSpec.Form) { case dwarf::DW_FORM_strp: case dwarf::DW_FORM_string: - return cloneStringAttribute(Die, AttrSpec, Val, U, Info); + return cloneStringAttribute(Die, AttrSpec, Val, U, StringPool, Info); case dwarf::DW_FORM_ref_addr: case dwarf::DW_FORM_ref1: case dwarf::DW_FORM_ref2: case dwarf::DW_FORM_ref4: case dwarf::DW_FORM_ref8: return cloneDieReferenceAttribute(Die, InputDIE, AttrSpec, AttrSize, Val, - Unit); + DMO, Unit); case dwarf::DW_FORM_block: case dwarf::DW_FORM_block1: case dwarf::DW_FORM_block2: @@ -3040,11 +3114,12 @@ unsigned DwarfLinker::DIECloner::cloneAttribute( case dwarf::DW_FORM_sec_offset: case dwarf::DW_FORM_flag: case dwarf::DW_FORM_flag_present: - return cloneScalarAttribute(Die, InputDIE, Unit, AttrSpec, Val, AttrSize, - Info); + return cloneScalarAttribute(Die, InputDIE, DMO, Unit, AttrSpec, Val, + AttrSize, Info); default: Linker.reportWarning( - "Unsupported attribute form in cloneAttribute. Dropping.", &InputDIE); + "Unsupported attribute form in cloneAttribute. Dropping.", DMO, + &InputDIE); } return 0; @@ -3136,6 +3211,7 @@ static bool isObjCSelector(StringRef Name) { void DwarfLinker::DIECloner::addObjCAccelerator(CompileUnit &Unit, const DIE *Die, DwarfStringPoolEntryRef Name, + OffsetsStringPool &StringPool, bool SkipPubSection) { assert(isObjCSelector(Name.getString()) && "not an objc selector"); // Objective C method or class function. @@ -3150,28 +3226,25 @@ void DwarfLinker::DIECloner::addObjCAccelerator(CompileUnit &Unit, return; StringRef Selector(SelectorStart.data(), SelectorStart.size() - 1); - Unit.addNameAccelerator(Die, Linker.StringPool.getEntry(Selector), - SkipPubSection); + Unit.addNameAccelerator(Die, StringPool.getEntry(Selector), SkipPubSection); // Add an entry for the class name that points to this // method/class function. StringRef ClassName(ClassNameStart.data(), FirstSpace); - Unit.addObjCAccelerator(Die, Linker.StringPool.getEntry(ClassName), - SkipPubSection); + Unit.addObjCAccelerator(Die, StringPool.getEntry(ClassName), SkipPubSection); if (ClassName[ClassName.size() - 1] == ')') { size_t OpenParens = ClassName.find('('); if (OpenParens != StringRef::npos) { StringRef ClassNameNoCategory(ClassName.data(), OpenParens); - Unit.addObjCAccelerator( - Die, Linker.StringPool.getEntry(ClassNameNoCategory), SkipPubSection); + Unit.addObjCAccelerator(Die, StringPool.getEntry(ClassNameNoCategory), + SkipPubSection); std::string MethodNameNoCategory(Name.getString().data(), OpenParens + 2); // FIXME: The missing space here may be a bug, but // dsymutil-classic also does it this way. MethodNameNoCategory.append(SelectorStart); - Unit.addNameAccelerator(Die, - Linker.StringPool.getEntry(MethodNameNoCategory), + Unit.addNameAccelerator(Die, StringPool.getEntry(MethodNameNoCategory), SkipPubSection); } } @@ -3202,9 +3275,11 @@ shouldSkipAttribute(DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, } DIE *DwarfLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE, - CompileUnit &Unit, int64_t PCOffset, - uint32_t OutOffset, unsigned Flags, - DIE *Die) { + const DebugMapObject &DMO, + CompileUnit &Unit, + OffsetsStringPool &StringPool, + int64_t PCOffset, uint32_t OutOffset, + unsigned Flags, DIE *Die) { DWARFUnit &U = Unit.getOrigUnit(); unsigned Idx = U.getDIEIndex(InputDIE); CompileUnit::DIEInfo &Info = Unit.getInfo(Idx); @@ -3309,8 +3384,8 @@ DIE *DwarfLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE, Val.extractValue(Data, &Offset, U.getFormParams(), &U); AttrSize = Offset - AttrSize; - OutOffset += - cloneAttribute(*Die, InputDIE, Unit, Val, AttrSpec, AttrSize, AttrInfo); + OutOffset += cloneAttribute(*Die, InputDIE, DMO, Unit, StringPool, Val, + AttrSpec, AttrSize, AttrInfo); } // Look for accelerator entries. @@ -3320,7 +3395,7 @@ DIE *DwarfLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE, // accelerator tables too. For now stick with dsymutil's behavior. if ((Info.InDebugMap || AttrInfo.HasLowPc || AttrInfo.HasRanges) && Tag != dwarf::DW_TAG_compile_unit && - getDIENames(InputDIE, AttrInfo, + getDIENames(InputDIE, AttrInfo, StringPool, Tag != dwarf::DW_TAG_inlined_subroutine)) { if (AttrInfo.MangledName && AttrInfo.MangledName != AttrInfo.Name) Unit.addNameAccelerator(Die, AttrInfo.MangledName, @@ -3333,16 +3408,17 @@ DIE *DwarfLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE, Tag == dwarf::DW_TAG_inlined_subroutine); } if (AttrInfo.Name && isObjCSelector(AttrInfo.Name.getString())) - addObjCAccelerator(Unit, Die, AttrInfo.Name, /* SkipPubSection =*/true); + addObjCAccelerator(Unit, Die, AttrInfo.Name, StringPool, + /* SkipPubSection =*/true); } else if (Tag == dwarf::DW_TAG_namespace) { if (!AttrInfo.Name) - AttrInfo.Name = Linker.StringPool.getEntry("(anonymous namespace)"); + AttrInfo.Name = StringPool.getEntry("(anonymous namespace)"); Unit.addNamespaceAccelerator(Die, AttrInfo.Name); } else if (isTypeTag(Tag) && !AttrInfo.IsDeclaration && - getDIENames(InputDIE, AttrInfo) && AttrInfo.Name && + getDIENames(InputDIE, AttrInfo, StringPool) && AttrInfo.Name && AttrInfo.Name.getString()[0]) { - uint32_t Hash = hashFullyQualifiedName(InputDIE, Unit); + uint32_t Hash = hashFullyQualifiedName(InputDIE, Unit, DMO); uint64_t RuntimeLang = dwarf::toUnsigned(InputDIE.find(dwarf::DW_AT_APPLE_runtime_class)) .getValueOr(0); @@ -3383,7 +3459,8 @@ DIE *DwarfLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE, // Recursively clone children. for (auto Child : InputDIE.children()) { - if (DIE *Clone = cloneDIE(Child, Unit, PCOffset, OutOffset, Flags)) { + if (DIE *Clone = cloneDIE(Child, DMO, Unit, StringPool, PCOffset, OutOffset, + Flags)) { Die->addChild(Clone); OutOffset = Clone->getOffset() + Clone->getSize(); } @@ -3400,7 +3477,8 @@ DIE *DwarfLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE, /// and emit them in the output file. Update the relevant attributes /// to point at the new entries. void DwarfLinker::patchRangesForUnit(const CompileUnit &Unit, - DWARFContext &OrigDwarf) const { + DWARFContext &OrigDwarf, + const DebugMapObject &DMO) const { DWARFDebugRangeList RangeList; const auto &FunctionRanges = Unit.getFunctionRanges(); unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize(); @@ -3432,7 +3510,7 @@ void DwarfLinker::patchRangesForUnit(const CompileUnit &Unit, CurrRange = FunctionRanges.find(First.StartAddress + OrigLowPc); if (CurrRange == InvalidRange || CurrRange.start() > First.StartAddress + OrigLowPc) { - reportWarning("no mapping for range."); + reportWarning("no mapping for range.", DMO); continue; } } @@ -3504,7 +3582,9 @@ static void patchStmtList(DIE &Die, DIEInteger Offset) { /// recreate a relocated version of these for the address ranges that /// are present in the binary. void DwarfLinker::patchLineTableForUnit(CompileUnit &Unit, - DWARFContext &OrigDwarf) { + DWARFContext &OrigDwarf, + RangesTy &Ranges, + const DebugMapObject &DMO) { DWARFDie CUDie = Unit.getOrigUnit().getUnitDIE(); auto StmtList = dwarf::toSectionOffset(CUDie.find(dwarf::DW_AT_stmt_list)); if (!StmtList) @@ -3574,8 +3654,8 @@ void DwarfLinker::patchLineTableForUnit(CompileUnit &Unit, --Range; if (Range != Ranges.end() && Range->first <= Row.Address && - Range->second.first >= Row.Address) { - StopAddress = Row.Address + Range->second.second; + Range->second.HighPC >= Row.Address) { + StopAddress = Row.Address + Range->second.Offset; } } } @@ -3617,7 +3697,7 @@ void DwarfLinker::patchLineTableForUnit(CompileUnit &Unit, LineTable.Prologue.getVersion() > 5 || LineTable.Prologue.DefaultIsStmt != DWARF2_LINE_DEFAULT_IS_STMT || LineTable.Prologue.OpcodeBase > 13) - reportWarning("line table parameters mismatch. Cannot emit."); + reportWarning("line table parameters mismatch. Cannot emit.", DMO); else { uint32_t PrologueEnd = *StmtList + 10 + LineTable.Prologue.PrologueLength; // DWARF v5 has an extra 2 bytes of information before the header_length @@ -3672,6 +3752,7 @@ void DwarfLinker::emitAcceleratorEntriesForUnit(CompileUnit &Unit) { /// be considered as black boxes and moved as is. The only thing to do /// is to patch the addresses in the headers. void DwarfLinker::patchFrameInfoForObject(const DebugMapObject &DMO, + RangesTy &Ranges, DWARFContext &OrigDwarf, unsigned AddrSize) { StringRef FrameData = OrigDwarf.getDWARFObj().getDebugFrameSection(); @@ -3689,7 +3770,7 @@ void DwarfLinker::patchFrameInfoForObject(const DebugMapObject &DMO, uint32_t EntryOffset = InputOffset; uint32_t InitialLength = Data.getU32(&InputOffset); if (InitialLength == 0xFFFFFFFF) - return reportWarning("Dwarf64 bits no supported"); + return reportWarning("Dwarf64 bits no supported", DMO); uint32_t CIEId = Data.getU32(&InputOffset); if (CIEId == 0xFFFFFFFF) { @@ -3711,7 +3792,7 @@ void DwarfLinker::patchFrameInfoForObject(const DebugMapObject &DMO, if (Range != Ranges.begin()) --Range; if (Range == Ranges.end() || Range->first > Loc || - Range->second.first <= Loc) { + Range->second.HighPC <= Loc) { // The +4 is to account for the size of the InitialLength field itself. InputOffset = EntryOffset + InitialLength + 4; continue; @@ -3721,7 +3802,7 @@ void DwarfLinker::patchFrameInfoForObject(const DebugMapObject &DMO, // Have we already emitted a corresponding CIE? StringRef CIEData = LocalCIES[CIEId]; if (CIEData.empty()) - return reportWarning("Inconsistent debug_frame content. Dropping."); + return reportWarning("Inconsistent debug_frame content. Dropping.", DMO); // Look if we already emitted a CIE that corresponds to the // referenced one (the CIE data is the key of that lookup). @@ -3744,7 +3825,7 @@ void DwarfLinker::patchFrameInfoForObject(const DebugMapObject &DMO, // fields that will get reconstructed by emitFDE(). unsigned FDERemainingBytes = InitialLength - (4 + AddrSize); Streamer->emitFDE(IteratorInserted.first->getValue(), AddrSize, - Loc + Range->second.second, + Loc + Range->second.Offset, FrameData.substr(InputOffset, FDERemainingBytes)); InputOffset += FDERemainingBytes; } @@ -3765,9 +3846,8 @@ void DwarfLinker::DIECloner::copyAbbrev( Linker.AssignAbbrev(Copy); } -uint32_t DwarfLinker::DIECloner::hashFullyQualifiedName(DWARFDie DIE, - CompileUnit &U, - int RecurseDepth) { +uint32_t DwarfLinker::DIECloner::hashFullyQualifiedName( + DWARFDie DIE, CompileUnit &U, const DebugMapObject &DMO, int RecurseDepth) { const char *Name = nullptr; DWARFUnit *OrigUnit = &U.getOrigUnit(); CompileUnit *CU = &U; @@ -3785,7 +3865,7 @@ uint32_t DwarfLinker::DIECloner::hashFullyQualifiedName(DWARFDie DIE, break; CompileUnit *RefCU; - if (auto RefDIE = resolveDIEReference(Linker, CompileUnits, *Ref, + if (auto RefDIE = resolveDIEReference(Linker, DMO, CompileUnits, *Ref, U.getOrigUnit(), DIE, RefCU)) { CU = RefCU; OrigUnit = &RefCU->getOrigUnit(); @@ -3804,9 +3884,10 @@ uint32_t DwarfLinker::DIECloner::hashFullyQualifiedName(DWARFDie DIE, return djbHash(Name ? Name : "", djbHash(RecurseDepth ? "" : "::")); DWARFDie Die = OrigUnit->getDIEAtIndex(CU->getInfo(Idx).ParentIdx); - return djbHash((Name ? Name : ""), - djbHash((Name ? "::" : ""), - hashFullyQualifiedName(Die, *CU, ++RecurseDepth))); + return djbHash( + (Name ? Name : ""), + djbHash((Name ? "::" : ""), + hashFullyQualifiedName(Die, *CU, DMO, ++RecurseDepth))); } static uint64_t getDwoId(const DWARFDie &CUDie, const DWARFUnit &Unit) { @@ -3817,10 +3898,11 @@ static uint64_t getDwoId(const DWARFDie &CUDie, const DWARFUnit &Unit) { return 0; } -bool DwarfLinker::registerModuleReference(const DWARFDie &CUDie, - const DWARFUnit &Unit, - DebugMap &ModuleMap, - unsigned Indent) { +bool DwarfLinker::registerModuleReference( + const DWARFDie &CUDie, const DWARFUnit &Unit, DebugMap &ModuleMap, + const DebugMapObject &DMO, RangesTy &Ranges, OffsetsStringPool &StringPool, + UniquingStringPool &UniquingStringPool, DeclContextTree &ODRContexts, + unsigned &UnitID, unsigned Indent) { std::string PCMfile = dwarf::toString( CUDie.find({dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}), ""); if (PCMfile.empty()) @@ -3832,7 +3914,7 @@ bool DwarfLinker::registerModuleReference(const DWARFDie &CUDie, std::string Name = dwarf::toString(CUDie.find(dwarf::DW_AT_name), ""); if (Name.empty()) { - reportWarning("Anonymous module skeleton CU for " + PCMfile); + reportWarning("Anonymous module skeleton CU for " + PCMfile, DMO); return true; } @@ -3849,7 +3931,8 @@ bool DwarfLinker::registerModuleReference(const DWARFDie &CUDie, if (Options.Verbose && (Cached->second != DwoId)) reportWarning(Twine("hash mismatch: this object file was built against a " "different version of the module ") + - PCMfile); + PCMfile, + DMO); if (Options.Verbose) outs() << " [cached].\n"; return true; @@ -3860,8 +3943,9 @@ bool DwarfLinker::registerModuleReference(const DWARFDie &CUDie, // Cyclic dependencies are disallowed by Clang, but we still // shouldn't run into an infinite loop, so mark it as processed now. ClangModules.insert({PCMfile, DwoId}); - if (Error E = loadClangModule(PCMfile, PCMpath, Name, DwoId, ModuleMap, - Indent + 2)) { + if (Error E = loadClangModule(PCMfile, PCMpath, Name, DwoId, ModuleMap, DMO, + Ranges, StringPool, UniquingStringPool, + ODRContexts, UnitID, Indent + 2)) { consumeError(std::move(E)); return false; } @@ -3869,23 +3953,28 @@ bool DwarfLinker::registerModuleReference(const DWARFDie &CUDie, } ErrorOr<const object::ObjectFile &> -DwarfLinker::loadObject(BinaryHolder &BinaryHolder, DebugMapObject &Obj, +DwarfLinker::loadObject(BinaryHolder &BinaryHolder, const DebugMapObject &Obj, const DebugMap &Map) { auto ErrOrObjs = BinaryHolder.GetObjectFiles(Obj.getObjectFilename(), Obj.getTimestamp()); if (std::error_code EC = ErrOrObjs.getError()) { - reportWarning(Twine(Obj.getObjectFilename()) + ": " + EC.message()); + reportWarning(Twine(Obj.getObjectFilename()) + ": " + EC.message(), Obj); return EC; } auto ErrOrObj = BinaryHolder.Get(Map.getTriple()); if (std::error_code EC = ErrOrObj.getError()) - reportWarning(Twine(Obj.getObjectFilename()) + ": " + EC.message()); + reportWarning(Twine(Obj.getObjectFilename()) + ": " + EC.message(), Obj); return ErrOrObj; } Error DwarfLinker::loadClangModule(StringRef Filename, StringRef ModulePath, StringRef ModuleName, uint64_t DwoId, - DebugMap &ModuleMap, unsigned Indent) { + DebugMap &ModuleMap, + const DebugMapObject &DMO, RangesTy &Ranges, + OffsetsStringPool &StringPool, + UniquingStringPool &UniquingStringPool, + DeclContextTree &ODRContexts, + unsigned &UnitID, unsigned Indent) { SmallString<80> Path(Options.PrependPath); if (sys::path::is_relative(Filename)) sys::path::append(Path, ModulePath, Filename); @@ -3897,7 +3986,7 @@ Error DwarfLinker::loadClangModule(StringRef Filename, StringRef ModulePath, auto ErrOrObj = loadObject(ObjHolder, Obj, ModuleMap); if (!ErrOrObj) { // Try and emit more helpful warnings by applying some heuristics. - StringRef ObjFile = CurrentDebugObject->getObjectFilename(); + StringRef ObjFile = DMO.getObjectFilename(); bool isClangModule = sys::path::extension(Filename).equals(".pcm"); bool isArchive = ObjFile.endswith(")"); if (isClangModule) { @@ -3941,7 +4030,9 @@ Error DwarfLinker::loadClangModule(StringRef Filename, StringRef ModulePath, // Recursively get all modules imported by this one. auto CUDie = CU->getUnitDIE(false); - if (!registerModuleReference(CUDie, *CU, ModuleMap, Indent)) { + if (!registerModuleReference(CUDie, *CU, ModuleMap, DMO, Ranges, StringPool, + UniquingStringPool, ODRContexts, UnitID, + Indent)) { if (Unit) { std::string Err = (Filename + @@ -3959,7 +4050,8 @@ Error DwarfLinker::loadClangModule(StringRef Filename, StringRef ModulePath, reportWarning( Twine("hash mismatch: this object file was built against a " "different version of the module ") + - Filename); + Filename, + DMO); // Update the cache entry with the DwoId of the module loaded from disk. ClangModules[Filename] = PCMDwoId; } @@ -3968,8 +4060,8 @@ Error DwarfLinker::loadClangModule(StringRef Filename, StringRef ModulePath, Unit = llvm::make_unique<CompileUnit>(*CU, UnitID++, !Options.NoODR, ModuleName); Unit->setHasInterestingContent(); - analyzeContextInfo(CUDie, 0, *Unit, &ODRContexts.getRoot(), StringPool, - ODRContexts); + analyzeContextInfo(CUDie, 0, *Unit, &ODRContexts.getRoot(), + UniquingStringPool, ODRContexts); // Keep everything. Unit->markEverythingAsKept(); } @@ -3984,11 +4076,13 @@ Error DwarfLinker::loadClangModule(StringRef Filename, StringRef ModulePath, std::vector<std::unique_ptr<CompileUnit>> CompileUnits; CompileUnits.push_back(std::move(Unit)); DIECloner(*this, RelocMgr, DIEAlloc, CompileUnits, Options) - .cloneAllCompileUnits(*DwarfContext); + .cloneAllCompileUnits(*DwarfContext, DMO, Ranges, StringPool); return Error::success(); } -void DwarfLinker::DIECloner::cloneAllCompileUnits(DWARFContext &DwarfContext) { +void DwarfLinker::DIECloner::cloneAllCompileUnits( + DWARFContext &DwarfContext, const DebugMapObject &DMO, RangesTy &Ranges, + OffsetsStringPool &StringPool) { if (!Linker.Streamer) return; @@ -3999,7 +4093,7 @@ void DwarfLinker::DIECloner::cloneAllCompileUnits(DWARFContext &DwarfContext) { // Clone the InputDIE into your Unit DIE in our compile unit since it // already has a DIE inside of it. CurrentUnit->createOutputDIE(); - cloneDIE(InputDIE, *CurrentUnit, 0 /* PC offset */, + cloneDIE(InputDIE, DMO, *CurrentUnit, StringPool, 0 /* PC offset */, 11 /* Unit Header size */, 0, CurrentUnit->getOutputUnitDIE()); } Linker.OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset(); @@ -4010,9 +4104,9 @@ void DwarfLinker::DIECloner::cloneAllCompileUnits(DWARFContext &DwarfContext) { // FIXME: for compatibility with the classic dsymutil, we emit an empty // line table for the unit, even if the unit doesn't actually exist in // the DIE tree. - Linker.patchLineTableForUnit(*CurrentUnit, DwarfContext); + Linker.patchLineTableForUnit(*CurrentUnit, DwarfContext, Ranges, DMO); Linker.emitAcceleratorEntriesForUnit(*CurrentUnit); - Linker.patchRangesForUnit(*CurrentUnit, DwarfContext); + Linker.patchRangesForUnit(*CurrentUnit, DwarfContext, DMO); Linker.Streamer->emitLocationsForUnit(*CurrentUnit, DwarfContext); } else { Linker.emitAcceleratorEntriesForUnit(*CurrentUnit); @@ -4041,19 +4135,31 @@ bool DwarfLinker::link(const DebugMap &Map) { // Size of the DIEs (and headers) generated for the linked output. OutputDebugInfoSize = 0; // A unique ID that identifies each compile unit. - UnitID = 0; + unsigned UnitID = 0; DebugMap ModuleMap(Map.getTriple(), Map.getBinaryPath()); + // This Dwarf string pool which is only used for uniquing. This one should + // never be used for offsets as its not thread-safe or predictable. + UniquingStringPool UniquingStringPool; + + // This Dwarf string pool which is used for emission. It must be used + // serially as the order of calling getStringOffset matters for + // reproducibility. + OffsetsStringPool OffsetsStringPool; + + // ODR Contexts for the link. + DeclContextTree ODRContexts; + for (const auto &Obj : Map.objects()) { - CurrentDebugObject = Obj.get(); + LinkContext LinkContext(Map, *this, *Obj.get(), Options.Verbose); if (Options.Verbose) outs() << "DEBUG MAP OBJECT: " << Obj->getObjectFilename() << "\n"; // N_AST objects (swiftmodule files) should get dumped directly into the // appropriate DWARF section. - if (Obj->getType() == MachO::N_AST) { - StringRef File = Obj->getObjectFilename(); + if (LinkContext.DMO.getType() == MachO::N_AST) { + StringRef File = LinkContext.DMO.getObjectFilename(); auto ErrorOrMem = MemoryBuffer::getFile(File); if (!ErrorOrMem) { errs() << "Warning: Could not open " << File << "\n"; @@ -4064,12 +4170,14 @@ bool DwarfLinker::link(const DebugMap &Map) { warn(Err.message()); continue; } - if (!Options.NoTimestamp && Stat.getLastModificationTime() != - sys::TimePoint<>(Obj->getTimestamp())) { + if (!Options.NoTimestamp && + Stat.getLastModificationTime() != + sys::TimePoint<>(LinkContext.DMO.getTimestamp())) { // Not using the helper here as we can easily stream TimePoint<>. warn_ostream() << "Timestamp mismatch for " << File << ": " << Stat.getLastModificationTime() << " and " - << sys::TimePoint<>(Obj->getTimestamp()) << "\n"; + << sys::TimePoint<>(LinkContext.DMO.getTimestamp()) + << "\n"; continue; } @@ -4079,25 +4187,26 @@ bool DwarfLinker::link(const DebugMap &Map) { continue; } - auto ErrOrObj = loadObject(BinHolder, *Obj, Map); - if (!ErrOrObj) + if (!LinkContext.ObjectFile) continue; // Look for relocations that correspond to debug map entries. - RelocationManager RelocMgr(*this); if (LLVM_LIKELY(!Options.Update) && - !RelocMgr.findValidRelocsInDebugInfo(*ErrOrObj, *Obj)) { + !LinkContext.RelocMgr.findValidRelocsInDebugInfo( + *LinkContext.ObjectFile, LinkContext.DMO)) { if (Options.Verbose) - outs() << "No valid relocations found. Skipping.\n"; + warn("No valid relocations found: skipping\n"); continue; } // Setup access to the debug info. - auto DwarfContext = DWARFContext::create(*ErrOrObj); - startDebugObject(*DwarfContext, *Obj); + if (!LinkContext.DwarfContext) + continue; // In a first phase, just read in the debug info and load all clang modules. - for (const auto &CU : DwarfContext->compile_units()) { + LinkContext.CompileUnits.reserve( + LinkContext.DwarfContext->getNumCompileUnits()); + for (const auto &CU : LinkContext.DwarfContext->compile_units()) { auto CUDie = CU->getUnitDIE(false); if (Options.Verbose) { outs() << "Input compilation unit:"; @@ -4108,18 +4217,20 @@ bool DwarfLinker::link(const DebugMap &Map) { } if (!CUDie || LLVM_UNLIKELY(Options.Update) || - !registerModuleReference(CUDie, *CU, ModuleMap)) { - Units.push_back(llvm::make_unique<CompileUnit>( + !registerModuleReference(CUDie, *CU, ModuleMap, LinkContext.DMO, + LinkContext.Ranges, OffsetsStringPool, + UniquingStringPool, ODRContexts, UnitID)) { + LinkContext.CompileUnits.push_back(llvm::make_unique<CompileUnit>( *CU, UnitID++, !Options.NoODR && !Options.Update, "")); maybeUpdateMaxDwarfVersion(CU->getVersion()); } } // Now build the DIE parent links that we will use during the next phase. - for (auto &CurrentUnit : Units) + for (auto &CurrentUnit : LinkContext.CompileUnits) analyzeContextInfo(CurrentUnit->getOrigUnit().getUnitDIE(), 0, - *CurrentUnit, &ODRContexts.getRoot(), StringPool, - ODRContexts); + *CurrentUnit, &ODRContexts.getRoot(), + UniquingStringPool, ODRContexts); // Then mark all the DIEs that need to be present in the linked // output and collect some information about them. Note that this @@ -4127,34 +4238,40 @@ bool DwarfLinker::link(const DebugMap &Map) { // references require the ParentIdx to be setup for every CU in // the object file before calling this. if (LLVM_UNLIKELY(Options.Update)) { - for (auto &CurrentUnit : Units) + for (auto &CurrentUnit : LinkContext.CompileUnits) CurrentUnit->markEverythingAsKept(); - Streamer->copyInvariantDebugSection(*ErrOrObj, Options); + Streamer->copyInvariantDebugSection(*LinkContext.ObjectFile, Options); } else { - for (auto &CurrentUnit : Units) - lookForDIEsToKeep(RelocMgr, CurrentUnit->getOrigUnit().getUnitDIE(), - *Obj, *CurrentUnit, 0); + for (auto &CurrentUnit : LinkContext.CompileUnits) + lookForDIEsToKeep(LinkContext.RelocMgr, LinkContext.Ranges, + LinkContext.CompileUnits, + CurrentUnit->getOrigUnit().getUnitDIE(), + LinkContext.DMO, *CurrentUnit, 0); } // The calls to applyValidRelocs inside cloneDIE will walk the // reloc array again (in the same way findValidRelocsInDebugInfo() // did). We need to reset the NextValidReloc index to the beginning. - RelocMgr.resetValidRelocs(); - if (RelocMgr.hasValidRelocs() || LLVM_UNLIKELY(Options.Update)) - DIECloner(*this, RelocMgr, DIEAlloc, Units, Options) - .cloneAllCompileUnits(*DwarfContext); - if (!Options.NoOutput && !Units.empty() && LLVM_LIKELY(!Options.Update)) - patchFrameInfoForObject(*Obj, *DwarfContext, - Units[0]->getOrigUnit().getAddressByteSize()); + LinkContext.RelocMgr.resetValidRelocs(); + if (LinkContext.RelocMgr.hasValidRelocs() || LLVM_UNLIKELY(Options.Update)) + DIECloner(*this, LinkContext.RelocMgr, DIEAlloc, LinkContext.CompileUnits, + Options) + .cloneAllCompileUnits(*LinkContext.DwarfContext, LinkContext.DMO, + LinkContext.Ranges, OffsetsStringPool); + if (!Options.NoOutput && !LinkContext.CompileUnits.empty() && + LLVM_LIKELY(!Options.Update)) + patchFrameInfoForObject( + LinkContext.DMO, LinkContext.Ranges, *LinkContext.DwarfContext, + LinkContext.CompileUnits[0]->getOrigUnit().getAddressByteSize()); // Clean-up before starting working on the next object. - endDebugObject(); + endDebugObject(LinkContext); } // Emit everything that's global. if (!Options.NoOutput) { Streamer->emitAbbrevs(Abbreviations, MaxDwarfVersion); - Streamer->emitStrings(StringPool); + Streamer->emitStrings(OffsetsStringPool); Streamer->emitAppleNames(AppleNames); Streamer->emitAppleNamespaces(AppleNamespaces); Streamer->emitAppleTypes(AppleTypes); |