From: Adrian Prantl Date: Fri, 11 Sep 2015 23:45:30 +0000 (+0000) Subject: dsymutil: Factor out the relocation handling into a RelocationManager (NFC) X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=0a0a960468ba6a903356bf78fe8b51d7a0817691;p=oota-llvm.git dsymutil: Factor out the relocation handling into a RelocationManager (NFC) git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@247490 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/tools/dsymutil/DwarfLinker.cpp b/tools/dsymutil/DwarfLinker.cpp index 619bbf923ea..f48fcb805a3 100644 --- a/tools/dsymutil/DwarfLinker.cpp +++ b/tools/dsymutil/DwarfLinker.cpp @@ -1103,52 +1103,74 @@ private: /// \brief Called at the end of a debug object link. void endDebugObject(); - /// \defgroup FindValidRelocations Translate debug map into a list - /// of relevant relocations - /// - /// @{ - struct ValidReloc { - uint32_t Offset; - uint32_t Size; - uint64_t Addend; - const DebugMapObject::DebugMapEntry *Mapping; - - ValidReloc(uint32_t Offset, uint32_t Size, uint64_t Addend, - const DebugMapObject::DebugMapEntry *Mapping) - : Offset(Offset), Size(Size), Addend(Addend), Mapping(Mapping) {} - - bool operator<(const ValidReloc &RHS) const { return Offset < RHS.Offset; } + /// Keeps track of relocations. + class RelocationManager { + struct ValidReloc { + uint32_t Offset; + uint32_t Size; + uint64_t Addend; + const DebugMapObject::DebugMapEntry *Mapping; + + ValidReloc(uint32_t Offset, uint32_t Size, uint64_t Addend, + const DebugMapObject::DebugMapEntry *Mapping) + : Offset(Offset), Size(Size), Addend(Addend), Mapping(Mapping) {} + + bool operator<(const ValidReloc &RHS) const { + return Offset < RHS.Offset; + } + }; + + DwarfLinker &Linker; + + /// \brief The valid relocations for the current DebugMapObject. + /// This vector is sorted by relocation offset. + std::vector ValidRelocs; + + /// \brief Index into ValidRelocs of the next relocation to + /// consider. As we walk the DIEs in acsending file offset and as + /// ValidRelocs is sorted by file offset, keeping this index + /// uptodate is all we have to do to have a cheap lookup during the + /// root DIE selection and during DIE cloning. + unsigned NextValidReloc; + + public: + RelocationManager(DwarfLinker &Linker) + : Linker(Linker), NextValidReloc(0) {} + + bool hasValidRelocs() const { return !ValidRelocs.empty(); } + /// \brief Reset the NextValidReloc counter. + void resetValidRelocs() { NextValidReloc = 0; } + + /// \defgroup FindValidRelocations Translate debug map into a list + /// of relevant relocations + /// + /// @{ + bool findValidRelocsInDebugInfo(const object::ObjectFile &Obj, + const DebugMapObject &DMO); + + bool findValidRelocs(const object::SectionRef &Section, + const object::ObjectFile &Obj, + const DebugMapObject &DMO); + + void findValidRelocsMachO(const object::SectionRef &Section, + const object::MachOObjectFile &Obj, + const DebugMapObject &DMO); + /// @} + + bool hasValidRelocation(uint32_t StartOffset, uint32_t EndOffset, + CompileUnit::DIEInfo &Info); + + bool applyValidRelocs(MutableArrayRef Data, uint32_t BaseOffset, + bool isLittleEndian); }; - /// \brief The valid relocations for the current DebugMapObject. - /// This vector is sorted by relocation offset. - std::vector ValidRelocs; - - /// \brief Index into ValidRelocs of the next relocation to - /// consider. As we walk the DIEs in acsending file offset and as - /// ValidRelocs is sorted by file offset, keeping this index - /// uptodate is all we have to do to have a cheap lookup during the - /// root DIE selection and during DIE cloning. - unsigned NextValidReloc; - - bool findValidRelocsInDebugInfo(const object::ObjectFile &Obj, - const DebugMapObject &DMO); - - bool findValidRelocs(const object::SectionRef &Section, - const object::ObjectFile &Obj, - const DebugMapObject &DMO); - - void findValidRelocsMachO(const object::SectionRef &Section, - const object::MachOObjectFile &Obj, - const DebugMapObject &DMO); - /// @} - /// \defgroup FindRootDIEs Find DIEs corresponding to debug map entries. /// /// @{ /// \brief Recursively walk the \p DIE tree and look for DIEs to /// keep. Store that information in \p CU's DIEInfo. - void lookForDIEsToKeep(const DWARFDebugInfoEntryMinimal &DIE, + void lookForDIEsToKeep(RelocationManager &RelocMgr, + const DWARFDebugInfoEntryMinimal &DIE, const DebugMapObject &DMO, CompileUnit &CU, unsigned Flags); @@ -1164,20 +1186,24 @@ private: /// \brief Mark the passed DIE as well as all the ones it depends on /// as kept. - void keepDIEAndDenpendencies(const DWARFDebugInfoEntryMinimal &DIE, + void keepDIEAndDenpendencies(RelocationManager &RelocMgr, + const DWARFDebugInfoEntryMinimal &DIE, CompileUnit::DIEInfo &MyInfo, const DebugMapObject &DMO, CompileUnit &CU, bool UseODR); - unsigned shouldKeepDIE(const DWARFDebugInfoEntryMinimal &DIE, + unsigned shouldKeepDIE(RelocationManager &RelocMgr, + const DWARFDebugInfoEntryMinimal &DIE, CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo, unsigned Flags); - unsigned shouldKeepVariableDIE(const DWARFDebugInfoEntryMinimal &DIE, + unsigned shouldKeepVariableDIE(RelocationManager &RelocMgr, + const DWARFDebugInfoEntryMinimal &DIE, CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo, unsigned Flags); - unsigned shouldKeepSubprogramDIE(const DWARFDebugInfoEntryMinimal &DIE, + unsigned shouldKeepSubprogramDIE(RelocationManager &RelocMgr, + const DWARFDebugInfoEntryMinimal &DIE, CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo, unsigned Flags); @@ -1200,9 +1226,19 @@ private: /// applied to the entry point of the function to get the linked address. /// /// \returns the root of the cloned tree. - DIE *cloneDIE(const DWARFDebugInfoEntryMinimal &InputDIE, CompileUnit &U, + DIE *cloneDIE(RelocationManager &RelocMgr, + const DWARFDebugInfoEntryMinimal &InputDIE, CompileUnit &U, int64_t PCOffset, uint32_t OutOffset, unsigned Flags); + /// 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 cloneCompileUnit(RelocationManager &RelocMgr, + MutableArrayRef CompileUnit, + DWARFContextInMemory &DwarfContext); + + + typedef DWARFAbbreviationDeclaration::AttributeSpec AttributeSpec; /// \brief Information gathered and exchanged between the various @@ -1257,10 +1293,6 @@ private: const DWARFFormValue &Val, unsigned AttrSize, AttributesInfo &Info); - /// \brief Helper for cloneDIE. - bool applyValidRelocs(MutableArrayRef Data, uint32_t BaseOffset, - bool isLittleEndian); - /// \brief Assign an abbreviation number to \p Abbrev void AssignAbbrev(DIEAbbrev &Abbrev); @@ -1334,6 +1366,7 @@ private: LinkOptions Options; BinaryHolder BinHolder; std::unique_ptr Streamer; + uint64_t OutputDebugInfoSize; /// The units of the current debug map object. std::vector Units; @@ -1701,7 +1734,6 @@ static unsigned getRefAddrSize(const DWARFUnit &U) { void DwarfLinker::startDebugObject(DWARFContext &Dwarf, DebugMapObject &Obj) { Units.reserve(Dwarf.getNumCompileUnits()); - NextValidReloc = 0; // 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 @@ -1727,7 +1759,6 @@ void DwarfLinker::startDebugObject(DWARFContext &Dwarf, DebugMapObject &Obj) { void DwarfLinker::endDebugObject() { Units.clear(); - ValidRelocs.clear(); Ranges.clear(); for (auto I = DIEBlocks.begin(), E = DIEBlocks.end(); I != E; ++I) @@ -1743,9 +1774,10 @@ void DwarfLinker::endDebugObject() { /// \brief Iterate over the relocations of the given \p Section and /// store the ones that correspond to debug map entries into the /// ValidRelocs array. -void DwarfLinker::findValidRelocsMachO(const object::SectionRef &Section, - const object::MachOObjectFile &Obj, - const DebugMapObject &DMO) { +void DwarfLinker::RelocationManager:: +findValidRelocsMachO(const object::SectionRef &Section, + const object::MachOObjectFile &Obj, + const DebugMapObject &DMO) { StringRef Contents; Section.getContents(Contents); DataExtractor Data(Contents, Obj.isLittleEndian(), 0); @@ -1756,7 +1788,7 @@ void DwarfLinker::findValidRelocsMachO(const object::SectionRef &Section, unsigned RelocSize = 1 << Obj.getAnyRelocationLength(MachOReloc); uint64_t Offset64 = Reloc.getOffset(); if ((RelocSize != 4 && RelocSize != 8)) { - reportWarning(" unsupported relocation in debug_info section."); + Linker.reportWarning(" unsupported relocation in debug_info section."); continue; } uint32_t Offset = Offset64; @@ -1767,7 +1799,7 @@ void DwarfLinker::findValidRelocsMachO(const object::SectionRef &Section, if (Sym != Obj.symbol_end()) { ErrorOr SymbolName = Sym->getName(); if (!SymbolName) { - reportWarning("error getting relocation symbol name."); + Linker.reportWarning("error getting relocation symbol name."); continue; } if (const auto *Mapping = DMO.lookupSymbol(*SymbolName)) @@ -1783,14 +1815,15 @@ void DwarfLinker::findValidRelocsMachO(const object::SectionRef &Section, /// \brief Dispatch the valid relocation finding logic to the /// appropriate handler depending on the object file format. -bool DwarfLinker::findValidRelocs(const object::SectionRef &Section, - const object::ObjectFile &Obj, - const DebugMapObject &DMO) { +bool DwarfLinker::RelocationManager::findValidRelocs( + const object::SectionRef &Section, const object::ObjectFile &Obj, + const DebugMapObject &DMO) { // Dispatch to the right handler depending on the file type. if (auto *MachOObj = dyn_cast(&Obj)) findValidRelocsMachO(Section, *MachOObj, DMO); else - reportWarning(Twine("unsupported object file type: ") + Obj.getFileName()); + Linker.reportWarning(Twine("unsupported object file type: ") + + Obj.getFileName()); if (ValidRelocs.empty()) return false; @@ -1808,8 +1841,9 @@ bool DwarfLinker::findValidRelocs(const object::SectionRef &Section, /// link by indicating which DIEs refer to symbols present in the /// linked binary. /// \returns wether there are any valid relocations in the debug info. -bool DwarfLinker::findValidRelocsInDebugInfo(const object::ObjectFile &Obj, - const DebugMapObject &DMO) { +bool DwarfLinker::RelocationManager:: +findValidRelocsInDebugInfo(const object::ObjectFile &Obj, + const DebugMapObject &DMO) { // Find the debug_info section. for (const object::SectionRef &Section : Obj.sections()) { StringRef SectionName; @@ -1828,8 +1862,9 @@ bool DwarfLinker::findValidRelocsInDebugInfo(const object::ObjectFile &Obj, /// This function must be called with offsets in strictly ascending /// order because it never looks back at relocations it already 'went past'. /// \returns true and sets Info.InDebugMap if it is the case. -bool DwarfLinker::hasValidRelocation(uint32_t StartOffset, uint32_t EndOffset, - CompileUnit::DIEInfo &Info) { +bool DwarfLinker::RelocationManager:: +hasValidRelocation(uint32_t StartOffset, uint32_t EndOffset, + CompileUnit::DIEInfo &Info) { assert(NextValidReloc == 0 || StartOffset > ValidRelocs[NextValidReloc - 1].Offset); if (NextValidReloc >= ValidRelocs.size()) @@ -1849,7 +1884,7 @@ bool DwarfLinker::hasValidRelocation(uint32_t StartOffset, uint32_t EndOffset, const auto &ValidReloc = ValidRelocs[NextValidReloc++]; const auto &Mapping = ValidReloc.Mapping->getValue(); - if (Options.Verbose) + if (Linker.Options.Verbose) outs() << "Found valid debug map entry: " << ValidReloc.Mapping->getKey() << " " << format("\t%016" PRIx64 " => %016" PRIx64, uint64_t(Mapping.ObjectAddress), @@ -1882,9 +1917,11 @@ getAttributeOffsets(const DWARFAbbreviationDeclaration *Abbrev, unsigned Idx, /// \brief Check if a variable describing DIE should be kept. /// \returns updated TraversalFlags. -unsigned DwarfLinker::shouldKeepVariableDIE( - const DWARFDebugInfoEntryMinimal &DIE, CompileUnit &Unit, - CompileUnit::DIEInfo &MyInfo, unsigned Flags) { +unsigned DwarfLinker::shouldKeepVariableDIE(RelocationManager &RelocMgr, + const DWARFDebugInfoEntryMinimal &DIE, + CompileUnit &Unit, + CompileUnit::DIEInfo &MyInfo, + unsigned Flags) { const auto *Abbrev = DIE.getAbbreviationDeclarationPtr(); // Global variables with constant value can always be kept. @@ -1909,7 +1946,7 @@ unsigned DwarfLinker::shouldKeepVariableDIE( // always check in the variable has a valid relocation, so that the // DIEInfo is filled. However, we don't want a static variable in a // function to force us to keep the enclosing function. - if (!hasValidRelocation(LocationOffset, LocationEndOffset, MyInfo) || + if (!RelocMgr.hasValidRelocation(LocationOffset, LocationEndOffset, MyInfo) || (Flags & TF_InFunctionScope)) return Flags; @@ -1922,6 +1959,7 @@ unsigned DwarfLinker::shouldKeepVariableDIE( /// \brief Check if a function describing DIE should be kept. /// \returns updated TraversalFlags. unsigned DwarfLinker::shouldKeepSubprogramDIE( + RelocationManager &RelocMgr, const DWARFDebugInfoEntryMinimal &DIE, CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo, unsigned Flags) { const auto *Abbrev = DIE.getAbbreviationDeclarationPtr(); @@ -1942,7 +1980,7 @@ unsigned DwarfLinker::shouldKeepSubprogramDIE( DIE.getAttributeValueAsAddress(&OrigUnit, dwarf::DW_AT_low_pc, -1ULL); assert(LowPc != -1ULL && "low_pc attribute is not an address."); if (LowPc == -1ULL || - !hasValidRelocation(LowPcOffset, LowPcEndOffset, MyInfo)) + !RelocMgr.hasValidRelocation(LowPcOffset, LowPcEndOffset, MyInfo)) return Flags; if (Options.Verbose) @@ -1973,16 +2011,17 @@ unsigned DwarfLinker::shouldKeepSubprogramDIE( /// \brief Check if a DIE should be kept. /// \returns updated TraversalFlags. -unsigned DwarfLinker::shouldKeepDIE(const DWARFDebugInfoEntryMinimal &DIE, +unsigned DwarfLinker::shouldKeepDIE(RelocationManager &RelocMgr, + const DWARFDebugInfoEntryMinimal &DIE, CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo, unsigned Flags) { switch (DIE.getTag()) { case dwarf::DW_TAG_constant: case dwarf::DW_TAG_variable: - return shouldKeepVariableDIE(DIE, Unit, MyInfo, Flags); + return shouldKeepVariableDIE(RelocMgr, DIE, Unit, MyInfo, Flags); case dwarf::DW_TAG_subprogram: - return shouldKeepSubprogramDIE(DIE, Unit, MyInfo, Flags); + return shouldKeepSubprogramDIE(RelocMgr, DIE, Unit, MyInfo, Flags); case dwarf::DW_TAG_module: case dwarf::DW_TAG_imported_module: case dwarf::DW_TAG_imported_declaration: @@ -2002,7 +2041,8 @@ unsigned DwarfLinker::shouldKeepDIE(const DWARFDebugInfoEntryMinimal &DIE, /// back to lookForDIEsToKeep while adding TF_DependencyWalk to the /// TraversalFlags to inform it that it's not doing the primary DIE /// tree walk. -void DwarfLinker::keepDIEAndDenpendencies(const DWARFDebugInfoEntryMinimal &Die, +void DwarfLinker::keepDIEAndDenpendencies(RelocationManager &RelocMgr, + const DWARFDebugInfoEntryMinimal &Die, CompileUnit::DIEInfo &MyInfo, const DebugMapObject &DMO, CompileUnit &CU, bool UseODR) { @@ -2013,7 +2053,7 @@ void DwarfLinker::keepDIEAndDenpendencies(const DWARFDebugInfoEntryMinimal &Die, unsigned AncestorIdx = MyInfo.ParentIdx; while (!CU.getInfo(AncestorIdx).Keep) { unsigned ODRFlag = UseODR ? TF_ODR : 0; - lookForDIEsToKeep(*Unit.getDIEAtIndex(AncestorIdx), DMO, CU, + lookForDIEsToKeep(RelocMgr, *Unit.getDIEAtIndex(AncestorIdx), DMO, CU, TF_ParentWalk | TF_Keep | TF_DependencyWalk | ODRFlag); AncestorIdx = CU.getInfo(AncestorIdx).ParentIdx; } @@ -2053,7 +2093,7 @@ void DwarfLinker::keepDIEAndDenpendencies(const DWARFDebugInfoEntryMinimal &Die, continue; unsigned ODRFlag = UseODR ? TF_ODR : 0; - lookForDIEsToKeep(*RefDIE, DMO, *ReferencedCU, + lookForDIEsToKeep(RelocMgr, *RefDIE, DMO, *ReferencedCU, TF_Keep | TF_DependencyWalk | ODRFlag); } } @@ -2071,7 +2111,8 @@ void DwarfLinker::keepDIEAndDenpendencies(const DWARFDebugInfoEntryMinimal &Die, /// also called, but during these dependency walks the file order is /// not respected. The TF_DependencyWalk flag tells us which kind of /// traversal we are currently doing. -void DwarfLinker::lookForDIEsToKeep(const DWARFDebugInfoEntryMinimal &Die, +void DwarfLinker::lookForDIEsToKeep(RelocationManager &RelocMgr, + const DWARFDebugInfoEntryMinimal &Die, const DebugMapObject &DMO, CompileUnit &CU, unsigned Flags) { unsigned Idx = CU.getOrigUnit().getDIEIndex(&Die); @@ -2087,12 +2128,12 @@ void DwarfLinker::lookForDIEsToKeep(const DWARFDebugInfoEntryMinimal &Die, // We must not call shouldKeepDIE while called from keepDIEAndDenpendencies, // because it would screw up the relocation finding logic. if (!(Flags & TF_DependencyWalk)) - Flags = shouldKeepDIE(Die, CU, MyInfo, Flags); + Flags = shouldKeepDIE(RelocMgr, Die, 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(); - keepDIEAndDenpendencies(Die, MyInfo, DMO, CU, UseOdr); + keepDIEAndDenpendencies(RelocMgr, 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 @@ -2108,7 +2149,7 @@ void DwarfLinker::lookForDIEsToKeep(const DWARFDebugInfoEntryMinimal &Die, for (auto *Child = Die.getFirstChild(); Child && !Child->isNULL(); Child = Child->getSibling()) - lookForDIEsToKeep(*Child, DMO, CU, Flags); + lookForDIEsToKeep(RelocMgr, *Child, DMO, CU, Flags); } /// \brief Assign an abbreviation numer to \p Abbrev. @@ -2412,8 +2453,9 @@ unsigned DwarfLinker::cloneAttribute(DIE &Die, /// monotonic \p BaseOffset values. /// /// \returns wether any reloc has been applied. -bool DwarfLinker::applyValidRelocs(MutableArrayRef Data, - uint32_t BaseOffset, bool isLittleEndian) { +bool DwarfLinker::RelocationManager:: +applyValidRelocs(MutableArrayRef Data, uint32_t BaseOffset, + bool isLittleEndian) { assert((NextValidReloc == 0 || BaseOffset > ValidRelocs[NextValidReloc - 1].Offset) && "BaseOffset should only be increasing."); @@ -2512,7 +2554,8 @@ shouldSkipAttribute(DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, /// lie in the linked compile unit. /// /// \returns the cloned DIE object or null if nothing was selected. -DIE *DwarfLinker::cloneDIE(const DWARFDebugInfoEntryMinimal &InputDIE, +DIE *DwarfLinker::cloneDIE(RelocationManager &RelocMgr, + const DWARFDebugInfoEntryMinimal &InputDIE, CompileUnit &Unit, int64_t PCOffset, uint32_t OutOffset, unsigned Flags) { DWARFUnit &U = Unit.getOrigUnit(); @@ -2551,7 +2594,7 @@ DIE *DwarfLinker::cloneDIE(const DWARFDebugInfoEntryMinimal &InputDIE, SmallString<40> DIECopy(Data.getData().substr(Offset, NextOffset - Offset)); Data = DataExtractor(DIECopy, Data.isLittleEndian(), Data.getAddressSize()); // Modify the copy with relocated addresses. - if (applyValidRelocs(DIECopy, Offset, Data.isLittleEndian())) { + if (RelocMgr.applyValidRelocs(DIECopy, Offset, Data.isLittleEndian())) { // If we applied relocations, we store the value of high_pc that was // potentially stored in the input DIE. If high_pc is an address // (Dwarf version == 2), then it might have been relocated to a @@ -2652,7 +2695,8 @@ DIE *DwarfLinker::cloneDIE(const DWARFDebugInfoEntryMinimal &InputDIE, // Recursively clone children. for (auto *Child = InputDIE.getFirstChild(); Child && !Child->isNULL(); Child = Child->getSibling()) { - if (DIE *Clone = cloneDIE(*Child, Unit, PCOffset, OutOffset, Flags)) { + if (DIE *Clone = + cloneDIE(RelocMgr, *Child, Unit, PCOffset, OutOffset, Flags)) { Die->addChild(Clone); OutOffset = Clone->getOffset() + Clone->getSize(); } @@ -3020,13 +3064,53 @@ DwarfLinker::loadObject(BinaryHolder &BinaryHolder, DebugMapObject &Obj, return ErrOrObj; } +void DwarfLinker::cloneCompileUnit(RelocationManager &RelocMgr, + MutableArrayRef CompileUnits, + DWARFContextInMemory &DwarfContext) { + if (!Streamer) + return; + + for (auto &CurrentUnit : CompileUnits) { + const auto *InputDIE = CurrentUnit.getOrigUnit().getUnitDIE(); + CurrentUnit.setStartOffset(OutputDebugInfoSize); + DIE *OutputDIE = cloneDIE(RelocMgr, *InputDIE, CurrentUnit, + 0 /* PC offset */, 11 /* Unit Header size */, 0); + CurrentUnit.setOutputUnitDIE(OutputDIE); + OutputDebugInfoSize = CurrentUnit.computeNextUnitOffset(); + if (Options.NoOutput) + continue; + // 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. + patchLineTableForUnit(CurrentUnit, DwarfContext); + if (!OutputDIE) + continue; + patchRangesForUnit(CurrentUnit, DwarfContext); + Streamer->emitLocationsForUnit(CurrentUnit, DwarfContext); + emitAcceleratorEntriesForUnit(CurrentUnit); + } + + if (Options.NoOutput) + return; + + // Emit all the compile unit's debug information. + for (auto &CurrentUnit : CompileUnits) { + generateUnitRanges(CurrentUnit); + CurrentUnit.fixupForwardReferences(); + Streamer->emitCompileUnitHeader(CurrentUnit); + if (!CurrentUnit.getOutputUnitDIE()) + continue; + Streamer->emitDIE(*CurrentUnit.getOutputUnitDIE()); + } +} + bool DwarfLinker::link(const DebugMap &Map) { if (!createStreamer(Map.getTriple(), OutputFilename)) return false; // Size of the DIEs (and headers) generated for the linked output. - uint64_t OutputDebugInfoSize = 0; + OutputDebugInfoSize = 0; // A unique ID that identifies each compile unit. unsigned UnitID = 0; for (const auto &Obj : Map.objects()) { @@ -3039,7 +3123,8 @@ bool DwarfLinker::link(const DebugMap &Map) { continue; // Look for relocations that correspond to debug map entries. - if (!findValidRelocsInDebugInfo(*ErrOrObj, *Obj)) { + RelocationManager RelocMgr(*this); + if (!RelocMgr.findValidRelocsInDebugInfo(*ErrOrObj, *Obj)) { if (Options.Verbose) outs() << "No valid relocations found. Skipping.\n"; continue; @@ -3068,50 +3153,16 @@ bool DwarfLinker::link(const DebugMap &Map) { // references require the ParentIdx to be setup for every CU in // the object file before calling this. for (auto &CurrentUnit : Units) - lookForDIEsToKeep(*CurrentUnit.getOrigUnit().getUnitDIE(), *Obj, + lookForDIEsToKeep(RelocMgr, *CurrentUnit.getOrigUnit().getUnitDIE(), *Obj, 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. - NextValidReloc = 0; - - // 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. - if (!ValidRelocs.empty()) - for (auto &CurrentUnit : Units) { - const auto *InputDIE = CurrentUnit.getOrigUnit().getUnitDIE(); - CurrentUnit.setStartOffset(OutputDebugInfoSize); - DIE *OutputDIE = cloneDIE(*InputDIE, CurrentUnit, 0 /* PCOffset */, - 11 /* Unit Header size */, /* Flags =*/0); - CurrentUnit.setOutputUnitDIE(OutputDIE); - OutputDebugInfoSize = CurrentUnit.computeNextUnitOffset(); - if (Options.NoOutput) - continue; - // 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. - patchLineTableForUnit(CurrentUnit, DwarfContext); - if (!OutputDIE) - continue; - patchRangesForUnit(CurrentUnit, DwarfContext); - Streamer->emitLocationsForUnit(CurrentUnit, DwarfContext); - emitAcceleratorEntriesForUnit(CurrentUnit); - } - - // Emit all the compile unit's debug information. - if (!ValidRelocs.empty() && !Options.NoOutput) - for (auto &CurrentUnit : Units) { - generateUnitRanges(CurrentUnit); - CurrentUnit.fixupForwardReferences(); - Streamer->emitCompileUnitHeader(CurrentUnit); - if (!CurrentUnit.getOutputUnitDIE()) - continue; - Streamer->emitDIE(*CurrentUnit.getOutputUnitDIE()); - } - - if (!ValidRelocs.empty() && !Options.NoOutput && !Units.empty()) + RelocMgr.resetValidRelocs(); + if (RelocMgr.hasValidRelocs()) + cloneCompileUnit(RelocMgr, Units, DwarfContext); + if (!Options.NoOutput && !Units.empty()) patchFrameInfoForObject(*Obj, DwarfContext, Units[0].getOrigUnit().getAddressByteSize());