/// \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<ValidReloc> 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<char> Data, uint32_t BaseOffset,
+ bool isLittleEndian);
};
- /// \brief The valid relocations for the current DebugMapObject.
- /// This vector is sorted by relocation offset.
- std::vector<ValidReloc> 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);
/// \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);
/// 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> CompileUnit,
+ DWARFContextInMemory &DwarfContext);
+
+
+
typedef DWARFAbbreviationDeclaration::AttributeSpec AttributeSpec;
/// \brief Information gathered and exchanged between the various
const DWARFFormValue &Val, unsigned AttrSize,
AttributesInfo &Info);
- /// \brief Helper for cloneDIE.
- bool applyValidRelocs(MutableArrayRef<char> Data, uint32_t BaseOffset,
- bool isLittleEndian);
-
/// \brief Assign an abbreviation number to \p Abbrev
void AssignAbbrev(DIEAbbrev &Abbrev);
LinkOptions Options;
BinaryHolder BinHolder;
std::unique_ptr<DwarfStreamer> Streamer;
+ uint64_t OutputDebugInfoSize;
/// The units of the current debug map object.
std::vector<CompileUnit> Units;
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
void DwarfLinker::endDebugObject() {
Units.clear();
- ValidRelocs.clear();
Ranges.clear();
for (auto I = DIEBlocks.begin(), E = DIEBlocks.end(); I != E; ++I)
/// \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);
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;
if (Sym != Obj.symbol_end()) {
ErrorOr<StringRef> 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))
/// \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<object::MachOObjectFile>(&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;
/// 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;
/// 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())
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),
/// \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.
// 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;
/// \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();
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)
/// \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:
/// 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) {
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;
}
continue;
unsigned ODRFlag = UseODR ? TF_ODR : 0;
- lookForDIEsToKeep(*RefDIE, DMO, *ReferencedCU,
+ lookForDIEsToKeep(RelocMgr, *RefDIE, DMO, *ReferencedCU,
TF_Keep | TF_DependencyWalk | ODRFlag);
}
}
/// 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);
// 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
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.
/// monotonic \p BaseOffset values.
///
/// \returns wether any reloc has been applied.
-bool DwarfLinker::applyValidRelocs(MutableArrayRef<char> Data,
- uint32_t BaseOffset, bool isLittleEndian) {
+bool DwarfLinker::RelocationManager::
+applyValidRelocs(MutableArrayRef<char> Data, uint32_t BaseOffset,
+ bool isLittleEndian) {
assert((NextValidReloc == 0 ||
BaseOffset > ValidRelocs[NextValidReloc - 1].Offset) &&
"BaseOffset should only be increasing.");
/// 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();
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
// 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();
}
return ErrOrObj;
}
+void DwarfLinker::cloneCompileUnit(RelocationManager &RelocMgr,
+ MutableArrayRef<CompileUnit> 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()) {
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;
// 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());