diff --git a/llvm/include/llvm/DWARFLinker/DWARFLinker.h b/llvm/include/llvm/DWARFLinker/DWARFLinker.h --- a/llvm/include/llvm/DWARFLinker/DWARFLinker.h +++ b/llvm/include/llvm/DWARFLinker/DWARFLinker.h @@ -31,21 +31,16 @@ /// Partial address range. Besides an offset, only the /// HighPC is stored. The structure is stored in a map where the LowPC is the /// key. -struct ObjFileAddressRange { +struct AddressHighPC { /// Function HighPC. - uint64_t HighPC; + uint64_t HighPC = 0; /// Offset to apply to the linked address. /// should be 0 for not-linked object file. - int64_t Offset; - - ObjFileAddressRange(uint64_t EndPC, int64_t Offset) - : HighPC(EndPC), Offset(Offset) {} - - ObjFileAddressRange() : HighPC(0), Offset(0) {} + int64_t Offset = 0; }; -/// Map LowPC to ObjFileAddressRange. -using RangesTy = std::map; +/// Map LowPC to AddressHighPC. +using RangesTy = std::map; /// AddressesMap represents information about valid addresses used /// by debug information. Valid addresses are those which points to diff --git a/llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h b/llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h --- a/llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h +++ b/llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h @@ -18,12 +18,24 @@ class DeclContext; +template <> struct DenseMapInfo { + static object::SectionedAddress getEmptyKey(); + + static object::SectionedAddress getTombstoneKey(); + + static unsigned getHashValue(const object::SectionedAddress &val); + + static bool isEqual(const object::SectionedAddress &lhs, + const object::SectionedAddress &rhs); +}; + template using HalfOpenIntervalMap = IntervalMap::LeafSize, IntervalMapHalfOpenInfo>; -using FunctionIntervals = HalfOpenIntervalMap; +using FunctionIntervals = + HalfOpenIntervalMap; // FIXME: Delete this structure. struct PatchLocation { @@ -77,9 +89,16 @@ }; CompileUnit(DWARFUnit &OrigUnit, unsigned ID, bool CanUseODR, - StringRef ClangModuleName) + StringRef ClangModuleName, bool IsLinkedBinary) : OrigUnit(OrigUnit), ID(ID), Ranges(RangeAlloc), ClangModuleName(ClangModuleName) { + + if (IsLinkedBinary) { + LowPc = {std::numeric_limits::max(), + object::SectionedAddress::UndefSection}; + HighPc = {0, object::SectionedAddress::UndefSection}; + } + Info.resize(OrigUnit.getNumDIEs()); auto CUDie = OrigUnit.getUnitDIE(false); @@ -127,9 +146,11 @@ uint64_t getNextUnitOffset() const { return NextUnitOffset; } void setStartOffset(uint64_t DebugInfoSize) { StartOffset = DebugInfoSize; } - uint64_t getLowPc() const { return LowPc; } - uint64_t getHighPc() const { return HighPc; } - bool hasLabelAt(uint64_t Addr) const { return Labels.count(Addr); } + Optional getLowPc() const { return LowPc; } + Optional getHighPc() const { return HighPc; } + bool hasLabelAt(object::SectionedAddress Addr) const { + return Labels.count(Addr); + } Optional getUnitRangesAttribute() const { return UnitRangeAttribute; @@ -171,11 +192,12 @@ /// Add the low_pc of a label that is relocated by applying /// offset \p PCOffset. - void addLabelLowPc(uint64_t LabelLowPc, int64_t PcOffset); + void addLabelLowPc(object::SectionedAddress LabelLowPc, int64_t PcOffset); /// Add a function range [\p LowPC, \p HighPC) that is relocated by applying /// offset \p PCOffset. - void addFunctionRange(uint64_t LowPC, uint64_t HighPC, int64_t PCOffset); + void addFunctionRange(object::SectionedAddress LowPC, + object::SectionedAddress HighPC, int64_t PCOffset); /// Keep track of a DW_AT_range attribute that we will need to patch up later. void noteRangeAttribute(const DIE &Die, PatchLocation Attr); @@ -263,8 +285,8 @@ uint64_t StartOffset; uint64_t NextUnitOffset; - uint64_t LowPc = std::numeric_limits::max(); - uint64_t HighPc = 0; + Optional LowPc; + Optional HighPc; /// A list of attributes to fixup with the absolute offset of /// a DIE in the debug_info section. @@ -284,7 +306,7 @@ FunctionIntervals Ranges; /// The DW_AT_low_pc of each DW_TAG_label. - SmallDenseMap Labels; + SmallDenseMap Labels; /// DW_AT_ranges attributes to patch after we have gathered /// all the unit's function addresses. diff --git a/llvm/include/llvm/Object/ObjectFile.h b/llvm/include/llvm/Object/ObjectFile.h --- a/llvm/include/llvm/Object/ObjectFile.h +++ b/llvm/include/llvm/Object/ObjectFile.h @@ -149,12 +149,24 @@ std::tie(RHS.SectionIndex, RHS.Address); } +inline bool operator<=(const SectionedAddress &LHS, + const SectionedAddress &RHS) { + return std::tie(LHS.SectionIndex, LHS.Address) <= + std::tie(RHS.SectionIndex, RHS.Address); +} + inline bool operator==(const SectionedAddress &LHS, const SectionedAddress &RHS) { return std::tie(LHS.SectionIndex, LHS.Address) == std::tie(RHS.SectionIndex, RHS.Address); } +inline bool operator!=(const SectionedAddress &LHS, + const SectionedAddress &RHS) { + return std::tie(LHS.SectionIndex, LHS.Address) != + std::tie(RHS.SectionIndex, RHS.Address); +} + raw_ostream &operator<<(raw_ostream &OS, const SectionedAddress &Addr); /// This is a value type class that represents a single symbol in the list of diff --git a/llvm/lib/DWARFLinker/DWARFLinker.cpp b/llvm/lib/DWARFLinker/DWARFLinker.cpp --- a/llvm/lib/DWARFLinker/DWARFLinker.cpp +++ b/llvm/lib/DWARFLinker/DWARFLinker.cpp @@ -418,7 +418,7 @@ std::tie(LowPcOffset, LowPcEndOffset) = getAttributeOffsets(Abbrev, *LowPcIdx, Offset, OrigUnit); - auto LowPc = dwarf::toAddress(DIE.find(dwarf::DW_AT_low_pc)); + auto LowPc = dwarf::toSectionedAddress(DIE.find(dwarf::DW_AT_low_pc)); assert(LowPc.hasValue() && "low_pc attribute is not an address."); if (!LowPc || !RelocMgr.hasValidRelocationAt(LowPcOffset, LowPcEndOffset, MyInfo)) @@ -440,7 +440,7 @@ // generation bugs aside, this is really wrong in the case of labels, where // a label marking the end of a function will have a PC == CU's high_pc. if (dwarf::toAddress(OrigUnit.getUnitDIE().find(dwarf::DW_AT_high_pc)) - .getValueOr(UINT64_MAX) <= LowPc) + .getValueOr(UINT64_MAX) <= LowPc->Address) return Flags; Unit.addLabelLowPc(*LowPc, MyInfo.AddrAdjust); return Flags | TF_Keep; @@ -448,7 +448,7 @@ Flags |= TF_Keep; - Optional HighPc = DIE.getHighPC(*LowPc); + Optional HighPc = DIE.getHighPC(LowPc->Address); if (!HighPc) { reportWarning("Function without high_pc. Range will be discarded.\n", File, &DIE); @@ -456,8 +456,9 @@ } // Replace the debug map range with a more accurate one. - Ranges[*LowPc] = ObjFileAddressRange(*HighPc, MyInfo.AddrAdjust); - Unit.addFunctionRange(*LowPc, *HighPc, MyInfo.AddrAdjust); + Ranges[*LowPc] = {*HighPc, MyInfo.AddrAdjust}; + Unit.addFunctionRange(*LowPc, {*HighPc, LowPc->SectionIndex}, + MyInfo.AddrAdjust); return Flags; } @@ -1030,15 +1031,18 @@ : Addr) + Info.PCOffset; else if (Die.getTag() == dwarf::DW_TAG_compile_unit) { - Addr = Unit.getLowPc(); - if (Addr == std::numeric_limits::max()) + const auto &pc = Unit.getLowPc(); + + if (pc && pc->Address != std::numeric_limits::max()) + Addr = pc->Address; + else return 0; } Info.HasLowPc = true; } else if (AttrSpec.Attr == dwarf::DW_AT_high_pc) { if (Die.getTag() == dwarf::DW_TAG_compile_unit) { - if (uint64_t HighPc = Unit.getHighPc()) - Addr = HighPc; + if (const auto &pc = Unit.getHighPc()) + Addr = pc->Address; else return 0; } else @@ -1086,10 +1090,15 @@ if (AttrSpec.Attr == dwarf::DW_AT_high_pc && Die.getTag() == dwarf::DW_TAG_compile_unit) { - if (Unit.getLowPc() == -1ULL) + const auto &lowPc = Unit.getLowPc(); + const auto &highPc = Unit.getHighPc(); + + if (lowPc && highPc && + lowPc->Address != std::numeric_limits::max()) + // Dwarf >= 4 high_pc is an size, not an address. + Value = highPc->Address - lowPc->Address; + else return 0; - // Dwarf >= 4 high_pc is an size, not an address. - Value = Unit.getHighPc() - Unit.getLowPc(); } else if (AttrSpec.Form == dwarf::DW_FORM_sec_offset) Value = *Val.getAsSectionOffset(); else if (AttrSpec.Form == dwarf::DW_FORM_sdata) @@ -1463,13 +1472,14 @@ auto InvalidRange = FunctionRanges.end(), CurrRange = InvalidRange; DWARFUnit &OrigUnit = Unit.getOrigUnit(); auto OrigUnitDie = OrigUnit.getUnitDIE(false); - uint64_t OrigLowPc = - dwarf::toAddress(OrigUnitDie.find(dwarf::DW_AT_low_pc), -1ULL); + uint64_t OrigLowPc = dwarf::toAddress(OrigUnitDie.find(dwarf::DW_AT_low_pc), + std::numeric_limits::max()); // Ranges addresses are based on the unit's low_pc. Compute the // offset we need to apply to adapt to the new unit's low_pc. int64_t UnitPcOffset = 0; - if (OrigLowPc != -1ULL) - UnitPcOffset = int64_t(OrigLowPc) - Unit.getLowPc(); + if (OrigLowPc != std::numeric_limits::max()) + if (const auto &unitLowPc = Unit.getLowPc()) + UnitPcOffset = int64_t(OrigLowPc) - unitLowPc->Address; for (const auto &RangeAttribute : Unit.getRangesAttributes()) { uint64_t Offset = RangeAttribute.get(); @@ -1484,11 +1494,13 @@ const DWARFDebugRangeList::RangeListEntry &First = Entries.front(); if (CurrRange == InvalidRange || - First.StartAddress + OrigLowPc < CurrRange.start() || - First.StartAddress + OrigLowPc >= CurrRange.stop()) { - CurrRange = FunctionRanges.find(First.StartAddress + OrigLowPc); - if (CurrRange == InvalidRange || - CurrRange.start() > First.StartAddress + OrigLowPc) { + First.StartAddress + OrigLowPc < CurrRange.start().Address || + First.StartAddress + OrigLowPc >= CurrRange.stop().Address) { + CurrRange = FunctionRanges.find( + {First.StartAddress + OrigLowPc, First.SectionIndex}); + if (CurrRange == InvalidRange || CurrRange == FunctionRanges.end() || + CurrRange.start().SectionIndex != First.SectionIndex || + CurrRange.start().Address > First.StartAddress + OrigLowPc) { reportWarning("no mapping for range.", File); continue; } @@ -1614,37 +1626,43 @@ // it is marked as end_sequence in the input (because in that // case, the relocation offset is accurate and that entry won't // serve as the start of another function). - if (CurrRange == InvalidRange || Row.Address.Address < CurrRange.start() || - Row.Address.Address > CurrRange.stop() || - (Row.Address.Address == CurrRange.stop() && !Row.EndSequence)) { + if (CurrRange == InvalidRange || + Row.Address.SectionIndex != CurrRange.start().SectionIndex || + Row.Address.Address < CurrRange.start().Address || + Row.Address.Address > CurrRange.stop().Address || + (Row.Address.Address == CurrRange.stop().Address && !Row.EndSequence)) { // We just stepped out of a known range. Insert a end_sequence // corresponding to the end of the range. uint64_t StopAddress = CurrRange != InvalidRange - ? CurrRange.stop() + CurrRange.value() - : -1ULL; - CurrRange = FunctionRanges.find(Row.Address.Address); + ? CurrRange.stop().Address + CurrRange.value() + : std::numeric_limits::max(); + CurrRange = FunctionRanges.find(Row.Address); bool CurrRangeValid = - CurrRange != InvalidRange && CurrRange.start() <= Row.Address.Address; + CurrRange != InvalidRange && + CurrRange.start().SectionIndex == Row.Address.SectionIndex && + CurrRange.start().Address <= Row.Address.Address; if (!CurrRangeValid) { CurrRange = InvalidRange; - if (StopAddress != -1ULL) { + if (StopAddress != std::numeric_limits::max()) { // Try harder by looking in the Address ranges map. // There are corner cases where this finds a // valid entry. It's unclear if this is right or wrong, but // for now do as dsymutil. // FIXME: Understand exactly what cases this addresses and // potentially remove it along with the Ranges map. - auto Range = Ranges.lower_bound(Row.Address.Address); + auto Range = Ranges.lower_bound(Row.Address); if (Range != Ranges.begin() && Range != Ranges.end()) --Range; - if (Range != Ranges.end() && Range->first <= Row.Address.Address && + if (Range != Ranges.end() && + Range->first.SectionIndex == Row.Address.SectionIndex && + Range->first.Address <= Row.Address.Address && Range->second.HighPC >= Row.Address.Address) { StopAddress = Row.Address.Address + Range->second.Offset; } } } - if (StopAddress != -1ULL && !Seq.empty()) { + if (StopAddress != std::numeric_limits::max() && !Seq.empty()) { // Insert end sequence row with the computed end address, but // the same line as the previous one. auto NextLine = Seq.back(); @@ -1797,10 +1815,11 @@ // the function entry point, thus we can't just lookup the address // in the debug map. Use the AddressInfo's range map to see if the FDE // describes something that we can relocate. - auto Range = Ranges.upper_bound(Loc); + auto Range = + Ranges.upper_bound({Loc, object::SectionedAddress::UndefSection}); if (Range != Ranges.begin()) --Range; - if (Range == Ranges.end() || Range->first > Loc || + if (Range == Ranges.end() || Range->first.Address > Loc || Range->second.HighPC <= Loc) { // The +4 is to account for the size of the InitialLength field itself. InputOffset = EntryOffset + InitialLength + 4; @@ -2021,8 +2040,9 @@ } // Add this module. - Unit = std::make_unique(*CU, UnitID++, !Options.NoODR, - ModuleName); + Unit = std::make_unique( + *CU, UnitID++, !Options.NoODR, ModuleName, + ErrOrObj->Addresses->areRelocationsResolved()); Unit->setHasInterestingContent(); analyzeContextInfo(CUDie, 0, *Unit, &ODRContexts.getRoot(), UniquingStringPool, ODRContexts, ModulesEndOffset, @@ -2354,7 +2374,8 @@ UniquingStringPool, ODRContexts, ModulesEndOffset, UnitID, Quiet)) { Context.CompileUnits.push_back(std::make_unique( - *CU, UnitID++, !Options.NoODR && !Options.Update, "")); + *CU, UnitID++, !Options.NoODR && !Options.Update, "", + Context.File.Addresses->areRelocationsResolved())); } } diff --git a/llvm/lib/DWARFLinker/DWARFLinkerCompileUnit.cpp b/llvm/lib/DWARFLinker/DWARFLinkerCompileUnit.cpp --- a/llvm/lib/DWARFLinker/DWARFLinkerCompileUnit.cpp +++ b/llvm/lib/DWARFLinker/DWARFLinkerCompileUnit.cpp @@ -11,6 +11,27 @@ namespace llvm { +object::SectionedAddress DenseMapInfo::getEmptyKey() { + return {object::SectionedAddress::UndefSection, + object::SectionedAddress::UndefSection - 1}; +} + +object::SectionedAddress +DenseMapInfo::getTombstoneKey() { + return {object::SectionedAddress::UndefSection, + object::SectionedAddress::UndefSection - 2}; +} + +unsigned DenseMapInfo::getHashValue( + const object::SectionedAddress &val) { + return llvm::hash_value(std::make_pair(val.Address, val.SectionIndex)); +} + +bool DenseMapInfo::isEqual( + const object::SectionedAddress &lhs, const object::SectionedAddress &rhs) { + return lhs == rhs; +} + /// Check if the DIE at \p Idx is in the scope of a function. static bool inFunctionScope(CompileUnit &U, unsigned Idx) { while (Idx) { @@ -99,19 +120,25 @@ } } -void CompileUnit::addLabelLowPc(uint64_t LabelLowPc, int64_t PcOffset) { +void CompileUnit::addLabelLowPc(object::SectionedAddress LabelLowPc, + int64_t PcOffset) { Labels.insert({LabelLowPc, PcOffset}); } -void CompileUnit::addFunctionRange(uint64_t FuncLowPc, uint64_t FuncHighPc, +void CompileUnit::addFunctionRange(object::SectionedAddress FuncLowPc, + object::SectionedAddress FuncHighPc, int64_t PcOffset) { // Don't add empty ranges to the interval map. They are a problem because // the interval map expects half open intervals. This is safe because they // are empty anyway. if (FuncHighPc != FuncLowPc) Ranges.insert(FuncLowPc, FuncHighPc, PcOffset); - this->LowPc = std::min(LowPc, FuncLowPc + PcOffset); - this->HighPc = std::max(HighPc, FuncHighPc + PcOffset); + if (LowPc) + *LowPc = std::min(*LowPc, + {FuncLowPc.Address + PcOffset, FuncLowPc.SectionIndex}); + if (HighPc) + *HighPc = std::max( + *HighPc, {FuncHighPc.Address + PcOffset, FuncHighPc.SectionIndex}); } void CompileUnit::noteRangeAttribute(const DIE &Die, PatchLocation Attr) { diff --git a/llvm/tools/dsymutil/DwarfLinkerForBinary.h b/llvm/tools/dsymutil/DwarfLinkerForBinary.h --- a/llvm/tools/dsymutil/DwarfLinkerForBinary.h +++ b/llvm/tools/dsymutil/DwarfLinkerForBinary.h @@ -112,9 +112,10 @@ for (const auto &Entry : DMO.symbols()) { const auto &Mapping = Entry.getValue(); if (Mapping.Size && Mapping.ObjectAddress) - AddressRanges[*Mapping.ObjectAddress] = ObjFileAddressRange( + AddressRanges[{*Mapping.ObjectAddress, + object::SectionedAddress::UndefSection}] = { *Mapping.ObjectAddress + Mapping.Size, - int64_t(Mapping.BinaryAddress) - *Mapping.ObjectAddress); + int64_t(Mapping.BinaryAddress - *Mapping.ObjectAddress)}; } } virtual ~AddressManager() override { clear(); } diff --git a/llvm/tools/dsymutil/DwarfStreamer.cpp b/llvm/tools/dsymutil/DwarfStreamer.cpp --- a/llvm/tools/dsymutil/DwarfStreamer.cpp +++ b/llvm/tools/dsymutil/DwarfStreamer.cpp @@ -302,8 +302,9 @@ continue; // All range entries should lie in the function range. - if (!(Range.StartAddress + OrigLowPc >= FuncRange.start() && - Range.EndAddress + OrigLowPc <= FuncRange.stop())) + if (!(Range.SectionIndex == FuncRange.start().SectionIndex && + Range.StartAddress + OrigLowPc >= FuncRange.start().Address && + Range.EndAddress + OrigLowPc <= FuncRange.stop().Address)) warn("inconsistent range data.", "emitting debug_ranges"); MS->emitIntValue(Range.StartAddress + PcOffset, AddressSize); MS->emitIntValue(Range.EndAddress + PcOffset, AddressSize); @@ -331,8 +332,8 @@ const auto &FunctionRanges = Unit.getFunctionRanges(); for (auto Range = FunctionRanges.begin(), End = FunctionRanges.end(); Range != End; ++Range) - Ranges.push_back(std::make_pair(Range.start() + Range.value(), - Range.stop() + Range.value())); + Ranges.push_back(std::make_pair(Range.start().Address + Range.value(), + Range.stop().Address + Range.value())); // The object addresses where sorted, but again, the linked // addresses might end up in a different order. @@ -383,7 +384,9 @@ MS->SwitchSection(MC->getObjectFileInfo()->getDwarfRangesSection()); // Offset each range by the right amount. - int64_t PcOffset = -Unit.getLowPc(); + int64_t PcOffset = 0; + if (const auto &lowPc = Unit.getLowPc()) + PcOffset = -lowPc->Address; // Emit coalesced ranges. for (auto Range = Ranges.begin(), End = Ranges.end(); Range != End; ++Range) { MS->emitIntValue(Range->first + PcOffset, AddressSize); @@ -421,8 +424,8 @@ auto OrigUnitDie = OrigUnit.getUnitDIE(false); int64_t UnitPcOffset = 0; if (auto OrigLowPc = dwarf::toAddress(OrigUnitDie.find(dwarf::DW_AT_low_pc))) - UnitPcOffset = int64_t(*OrigLowPc) - Unit.getLowPc(); - + if (const auto &pc = Unit.getLowPc()) + UnitPcOffset = int64_t(*OrigLowPc) - pc->Address; SmallVector Buffer; for (const auto &Attr : Attributes) { uint64_t Offset = Attr.first.get();