diff options
Diffstat (limited to 'llvm/tools/dsymutil/DwarfLinker.cpp')
| -rw-r--r-- | llvm/tools/dsymutil/DwarfLinker.cpp | 188 |
1 files changed, 160 insertions, 28 deletions
diff --git a/llvm/tools/dsymutil/DwarfLinker.cpp b/llvm/tools/dsymutil/DwarfLinker.cpp index 70a8b7c82e9..87f465dd83d 100644 --- a/llvm/tools/dsymutil/DwarfLinker.cpp +++ b/llvm/tools/dsymutil/DwarfLinker.cpp @@ -100,6 +100,24 @@ namespace dsymutil { namespace { +/// Retrieve the section named \a SecName in \a Obj. +/// +/// To accommodate for platform discrepancies, the name passed should be +/// (for example) 'debug_info' to match either '__debug_info' or '.debug_info'. +/// This function will strip the initial platform-specific characters. +static Optional<object::SectionRef> +getSectionByName(const object::ObjectFile &Obj, StringRef SecName) { + for (const object::SectionRef &Section : Obj.sections()) { + StringRef SectionName; + Section.getName(SectionName); + SectionName = SectionName.substr(SectionName.find_first_not_of("._")); + if (SectionName != SecName) + continue; + return Section; + } + return None; +} + template <typename KeyT, typename ValT> using HalfOpenIntervalMap = IntervalMap<KeyT, ValT, IntervalMapImpl::NodeSizer<KeyT, ValT>::LeafSize, @@ -491,12 +509,48 @@ private: std::string ClangModuleName; }; +/// Check if the DIE at \p Idx is in the scope of a function. +static bool inFunctionScope(CompileUnit &U, unsigned Idx) { + while (Idx) { + if (U.getOrigUnit().getDIEAtIndex(Idx).getTag() == dwarf::DW_TAG_subprogram) + return true; + Idx = U.getInfo(Idx).ParentIdx; + } + return false; +} + } // end anonymous namespace void CompileUnit::markEverythingAsKept() { - for (auto &I : Info) - // Mark everything that wasn't explicity marked for pruning. + unsigned Idx = 0; + + setHasInterestingContent(); + + for (auto &I : Info) { + // Mark everything that wasn't explicit marked for pruning. I.Keep = !I.Prune; + auto DIE = OrigUnit.getDIEAtIndex(Idx++); + + // Try to guess which DIEs must go to the accelerator tables. We do that + // just for variables, because functions will be handled depending on + // whether they carry a DW_AT_low_pc attribute or not. + if (DIE.getTag() != dwarf::DW_TAG_variable && + DIE.getTag() != dwarf::DW_TAG_constant) + continue; + + Optional<DWARFFormValue> Value; + if (!(Value = DIE.find(dwarf::DW_AT_location))) { + if ((Value = DIE.find(dwarf::DW_AT_const_value)) && + !inFunctionScope(*this, I.ParentIdx)) + I.InDebugMap = true; + continue; + } + if (auto Block = Value->getAsBlock()) { + if (Block->size() > OrigUnit.getAddressByteSize() && + (*Block)[0] == dwarf::DW_OP_addr) + I.InDebugMap = true; + } + } } uint64_t CompileUnit::computeNextUnitOffset() { @@ -668,6 +722,9 @@ public: std::vector<DWARFDebugLine::Row> &Rows, unsigned AdddressSize); + /// Copy over the debug sections that are not modified when updating. + void copyInvariantDebugSection(const object::ObjectFile &Obj, LinkOptions &); + uint32_t getLineSectionSize() const { return LineSectionSize; } /// Emit the .debug_pubnames contribution for \p Unit. @@ -1200,6 +1257,32 @@ void DwarfStreamer::emitLineTableForUnit(MCDwarfLineTableParams Params, MS->EmitLabel(LineEndSym); } +static void emitSectionContents(const object::ObjectFile &Obj, + StringRef SecName, MCStreamer *MS) { + StringRef Contents; + if (auto Sec = getSectionByName(Obj, SecName)) + if (!Sec->getContents(Contents)) + MS->EmitBytes(Contents); +} + +void DwarfStreamer::copyInvariantDebugSection(const object::ObjectFile &Obj, + LinkOptions &Options) { + MS->SwitchSection(MC->getObjectFileInfo()->getDwarfLineSection()); + emitSectionContents(Obj, "debug_line", MS); + + MS->SwitchSection(MC->getObjectFileInfo()->getDwarfLocSection()); + emitSectionContents(Obj, "debug_loc", MS); + + MS->SwitchSection(MC->getObjectFileInfo()->getDwarfRangesSection()); + emitSectionContents(Obj, "debug_ranges", MS); + + MS->SwitchSection(MC->getObjectFileInfo()->getDwarfFrameSection()); + emitSectionContents(Obj, "debug_frame", MS); + + MS->SwitchSection(MC->getObjectFileInfo()->getDwarfARangesSection()); + emitSectionContents(Obj, "debug_aranges", MS); +} + /// Emit the pubnames or pubtypes section contribution for \p /// Unit into \p Sec. The data is provided in \p Names. void DwarfStreamer::emitPubSectionForUnit( @@ -1529,8 +1612,8 @@ private: /// it to \p Die. /// \returns the size of the new attribute. unsigned cloneStringAttribute(DIE &Die, AttributeSpec AttrSpec, - const DWARFFormValue &Val, - const DWARFUnit &U); + const DWARFFormValue &Val, const DWARFUnit &U, + AttributesInfo &Info); /// Clone an attribute referencing another DIE and add /// it to \p Die. @@ -2621,12 +2704,18 @@ void DwarfLinker::AssignAbbrev(DIEAbbrev &Abbrev) { unsigned DwarfLinker::DIECloner::cloneStringAttribute(DIE &Die, AttributeSpec AttrSpec, const DWARFFormValue &Val, - const DWARFUnit &U) { + const DWARFUnit &U, + AttributesInfo &Info) { // Switch everything to out of line strings. const char *String = *Val.getAsCString(); - unsigned Offset = Linker.StringPool.getStringOffset(String); + auto StringEntry = Linker.StringPool.getEntry(String); + 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(Offset)); + DIEInteger(StringEntry.getOffset())); return 4; } @@ -2749,6 +2838,14 @@ unsigned DwarfLinker::DIECloner::cloneAddressAttribute( const CompileUnit &Unit, AttributesInfo &Info) { uint64_t Addr = *Val.getAsAddress(); + if (LLVM_UNLIKELY(Linker.Options.Update)) { + if (AttrSpec.Attr == dwarf::DW_AT_low_pc) + Info.HasLowPc = true; + Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr), + dwarf::Form(AttrSpec.Form), DIEInteger(Addr)); + return Unit.getOrigUnit().getAddressByteSize(); + } + if (AttrSpec.Attr == dwarf::DW_AT_low_pc) { if (Die.getTag() == dwarf::DW_TAG_inlined_subroutine || Die.getTag() == dwarf::DW_TAG_lexical_block) @@ -2789,6 +2886,26 @@ unsigned DwarfLinker::DIECloner::cloneScalarAttribute( AttributeSpec AttrSpec, const DWARFFormValue &Val, unsigned AttrSize, AttributesInfo &Info) { uint64_t Value; + + if (LLVM_UNLIKELY(Linker.Options.Update)) { + if (auto OptionalValue = Val.getAsUnsignedConstant()) + Value = *OptionalValue; + else if (auto OptionalValue = Val.getAsSignedConstant()) + Value = *OptionalValue; + else if (auto OptionalValue = Val.getAsSectionOffset()) + Value = *OptionalValue; + else { + Linker.reportWarning( + "Unsupported scalar attribute form. Dropping attribute.", &InputDIE); + return 0; + } + if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value) + Info.IsDeclaration = true; + Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr), + dwarf::Form(AttrSpec.Form), DIEInteger(Value)); + return AttrSize; + } + if (AttrSpec.Attr == dwarf::DW_AT_high_pc && Die.getTag() == dwarf::DW_TAG_compile_unit) { if (Unit.getLowPc() == -1ULL) @@ -2839,7 +2956,7 @@ unsigned DwarfLinker::DIECloner::cloneAttribute( switch (AttrSpec.Form) { case dwarf::DW_FORM_strp: case dwarf::DW_FORM_string: - return cloneStringAttribute(Die, AttrSpec, Val, U); + return cloneStringAttribute(Die, AttrSpec, Val, U, Info); case dwarf::DW_FORM_ref_addr: case dwarf::DW_FORM_ref1: case dwarf::DW_FORM_ref2: @@ -3108,13 +3225,14 @@ DIE *DwarfLinker::DIECloner::cloneDIE( if (Abbrev->getTag() == dwarf::DW_TAG_subprogram) { Flags |= TF_InFunctionScope; - if (!Info.InDebugMap) + if (!Info.InDebugMap && LLVM_LIKELY(!Options.Update)) Flags |= TF_SkipPC; } bool Copied = false; for (const auto &AttrSpec : Abbrev->attributes()) { - if (shouldSkipAttribute(AttrSpec, Die->getTag(), Info.InDebugMap, + if (LLVM_LIKELY(!Options.Update) && + shouldSkipAttribute(AttrSpec, Die->getTag(), Info.InDebugMap, Flags & TF_SkipPC, Flags & TF_InFunctionScope)) { DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset, U.getFormParams()); @@ -3827,13 +3945,18 @@ void DwarfLinker::DIECloner::cloneAllCompileUnits(DWARFContext &DwarfContext) { Linker.OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset(); if (Linker.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. - Linker.patchLineTableForUnit(*CurrentUnit, DwarfContext); - Linker.emitAcceleratorEntriesForUnit(*CurrentUnit); - Linker.patchRangesForUnit(*CurrentUnit, DwarfContext); - Linker.Streamer->emitLocationsForUnit(*CurrentUnit, DwarfContext); + + if (LLVM_LIKELY(!Linker.Options.Update)) { + // 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.emitAcceleratorEntriesForUnit(*CurrentUnit); + Linker.patchRangesForUnit(*CurrentUnit, DwarfContext); + Linker.Streamer->emitLocationsForUnit(*CurrentUnit, DwarfContext); + } else { + Linker.emitAcceleratorEntriesForUnit(*CurrentUnit); + } } if (Linker.Options.NoOutput) @@ -3841,7 +3964,8 @@ void DwarfLinker::DIECloner::cloneAllCompileUnits(DWARFContext &DwarfContext) { // Emit all the compile unit's debug information. for (auto &CurrentUnit : CompileUnits) { - Linker.generateUnitRanges(*CurrentUnit); + if (LLVM_LIKELY(!Linker.Options.Update)) + Linker.generateUnitRanges(*CurrentUnit); CurrentUnit->fixupForwardReferences(); Linker.Streamer->emitCompileUnitHeader(*CurrentUnit); if (!CurrentUnit->getOutputUnitDIE()) @@ -3900,7 +4024,8 @@ bool DwarfLinker::link(const DebugMap &Map) { // Look for relocations that correspond to debug map entries. RelocationManager RelocMgr(*this); - if (!RelocMgr.findValidRelocsInDebugInfo(*ErrOrObj, *Obj)) { + if (LLVM_LIKELY(!Options.Update) && + !RelocMgr.findValidRelocsInDebugInfo(*ErrOrObj, *Obj)) { if (Options.Verbose) outs() << "No valid relocations found. Skipping.\n"; continue; @@ -3921,9 +4046,10 @@ bool DwarfLinker::link(const DebugMap &Map) { CUDie.dump(outs(), 0, DumpOpts); } - if (!registerModuleReference(CUDie, *CU, ModuleMap)) { - Units.push_back(llvm::make_unique<CompileUnit>(*CU, UnitID++, - !Options.NoODR, "")); + if (!CUDie || LLVM_UNLIKELY(Options.Update) || + !registerModuleReference(CUDie, *CU, ModuleMap)) { + Units.push_back(llvm::make_unique<CompileUnit>( + *CU, UnitID++, !Options.NoODR && !Options.Update, "")); maybeUpdateMaxDwarfVersion(CU->getVersion()); } } @@ -3935,21 +4061,27 @@ bool DwarfLinker::link(const DebugMap &Map) { // Then mark all the DIEs that need to be present in the linked // output and collect some information about them. Note that this - // loop can not be merged with the previous one becaue cross-cu + // loop can not be merged with the previous one because cross-CU // references require the ParentIdx to be setup for every CU in // the object file before calling this. - for (auto &CurrentUnit : Units) - lookForDIEsToKeep(RelocMgr, CurrentUnit->getOrigUnit().getUnitDIE(), *Obj, - *CurrentUnit, 0); + if (LLVM_UNLIKELY(Options.Update)) { + for (auto &CurrentUnit : Units) + CurrentUnit->markEverythingAsKept(); + Streamer->copyInvariantDebugSection(*ErrOrObj, Options); + } else { + for (auto &CurrentUnit : Units) + 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. RelocMgr.resetValidRelocs(); - if (RelocMgr.hasValidRelocs()) + if (RelocMgr.hasValidRelocs() || LLVM_UNLIKELY(Options.Update)) DIECloner(*this, RelocMgr, DIEAlloc, Units, Options) .cloneAllCompileUnits(*DwarfContext); - if (!Options.NoOutput && !Units.empty()) + if (!Options.NoOutput && !Units.empty() && LLVM_LIKELY(!Options.Update)) patchFrameInfoForObject(*Obj, *DwarfContext, Units[0]->getOrigUnit().getAddressByteSize()); |

