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 @@ -574,16 +569,16 @@ uint32_t MangledNameOffset = 0; /// Value of AT_low_pc in the input DIE - uint64_t OrigLowPc = std::numeric_limits::max(); + Optional OrigLowPc; /// Value of AT_high_pc in the input DIE - uint64_t OrigHighPc = 0; + Optional OrigHighPc; /// Value of DW_AT_call_return_pc in the input DIE - uint64_t OrigCallReturnPc = 0; + Optional OrigCallReturnPc; /// Value of DW_AT_call_pc in the input DIE - uint64_t OrigCallPc = 0; + Optional OrigCallPc; /// Offset to apply to PC addresses inside a function. int64_t PCOffset = 0; 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,36 @@ 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; + +inline bool +IntervalContainsAddress(const FunctionIntervals::const_iterator &Interval, + const object::SectionedAddress &Address) { + assert(Interval.start().SectionIndex == Interval.stop().SectionIndex); + + if (Interval.start().SectionIndex != Address.SectionIndex) + return false; + + return Interval.start().Address <= Address.Address && + Interval.stop().Address > Address.Address; +} // FIXME: Delete this structure. struct PatchLocation { @@ -127,9 +151,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 +197,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 +290,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 +311,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/DebugInfo/DWARF/DWARFDie.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h @@ -201,7 +201,7 @@ /// /// \param LowPC the low PC that might be needed to calculate the high PC. /// \returns an optional address value for the attribute. - Optional getHighPC(uint64_t LowPC) const; + Optional getHighPC(object::SectionedAddress LowPC) const; /// Retrieves DW_AT_low_pc and DW_AT_high_pc from CU. /// Returns true if both attributes are present. 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 @@ -152,12 +152,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; @@ -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,36 +1031,34 @@ // relocated because it happens to match the low_pc of the // enclosing subprogram. To prevent issues with that, always use // the low_pc from the input DIE if relocations have been applied. - Addr = (Info.OrigLowPc != std::numeric_limits::max() - ? Info.OrigLowPc - : Addr) + - Info.PCOffset; + Addr = (Info.OrigLowPc ? *Info.OrigLowPc : Addr) + Info.PCOffset; else if (Die.getTag() == dwarf::DW_TAG_compile_unit) { - Addr = Unit.getLowPc(); - if (Addr == std::numeric_limits::max()) + if (Optional LowPc = Unit.getLowPc()) + Addr = *LowPc; + 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 (Optional HighPc = Unit.getHighPc()) + Addr = *HighPc; else return 0; } else // If we have a high_pc recorded for the input DIE, use // it. Otherwise (when no relocations where applied) just use the // one we just decoded. - Addr = (Info.OrigHighPc ? Info.OrigHighPc : Addr) + Info.PCOffset; + Addr = (Info.OrigHighPc ? *Info.OrigHighPc : Addr) + Info.PCOffset; } else if (AttrSpec.Attr == dwarf::DW_AT_call_return_pc) { // Relocate a return PC address within a call site entry. if (Die.getTag() == dwarf::DW_TAG_call_site) - Addr = (Info.OrigCallReturnPc ? Info.OrigCallReturnPc : Addr) + + Addr = (Info.OrigCallReturnPc ? *Info.OrigCallReturnPc : Addr) + Info.PCOffset; } else if (AttrSpec.Attr == dwarf::DW_AT_call_pc) { // Relocate the address of a branch instruction within a call site entry. if (Die.getTag() == dwarf::DW_TAG_call_site) - Addr = (Info.OrigCallPc ? Info.OrigCallPc : Addr) + Info.PCOffset; + Addr = (Info.OrigCallPc ? *Info.OrigCallPc : Addr) + Info.PCOffset; } Die.addValue(DIEAlloc, static_cast(AttrSpec.Attr), @@ -1095,10 +1094,11 @@ if (AttrSpec.Attr == dwarf::DW_AT_high_pc && Die.getTag() == dwarf::DW_TAG_compile_unit) { - if (Unit.getLowPc() == -1ULL) + if (Unit.getLowPc() && Unit.getHighPc()) + // Dwarf >= 4 high_pc is an size, not an address. + Value = *Unit.getHighPc() - *Unit.getLowPc(); + 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) @@ -1317,15 +1317,13 @@ // file might be start address of another function which got moved // independently by the linker). The computation of the actual // high_pc value is done in cloneAddressAttribute(). - AttrInfo.OrigHighPc = - dwarf::toAddress(InputDIE.find(dwarf::DW_AT_high_pc), 0); + AttrInfo.OrigHighPc = dwarf::toAddress(InputDIE.find(dwarf::DW_AT_high_pc)); // Also store the low_pc. It might get relocated in an // inline_subprogram that happens at the beginning of its // inlining function. - AttrInfo.OrigLowPc = dwarf::toAddress(InputDIE.find(dwarf::DW_AT_low_pc), - std::numeric_limits::max()); + AttrInfo.OrigLowPc = dwarf::toAddress(InputDIE.find(dwarf::DW_AT_low_pc)); AttrInfo.OrigCallReturnPc = - dwarf::toAddress(InputDIE.find(dwarf::DW_AT_call_return_pc), 0); + dwarf::toAddress(InputDIE.find(dwarf::DW_AT_call_return_pc)); } // Reset the Offset to 0 as we will be working on the local copy of @@ -1472,13 +1470,15 @@ 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); + Optional OrigLowPc = + dwarf::toAddress(OrigUnitDie.find(dwarf::DW_AT_low_pc)); // 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 && Unit.getLowPc()) + UnitPcOffset = int64_t(*OrigLowPc) - *Unit.getLowPc(); + else + OrigLowPc = 0; for (const auto &RangeAttribute : Unit.getRangesAttributes()) { uint64_t Offset = RangeAttribute.get(); @@ -1492,19 +1492,20 @@ if (!Entries.empty()) { const DWARFDebugRangeList::RangeListEntry &First = Entries.front(); + object::SectionedAddress RangeListEntryStartAddress = { + First.StartAddress + *OrigLowPc, First.SectionIndex}; 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) { + !IntervalContainsAddress(CurrRange, RangeListEntryStartAddress)) { + CurrRange = FunctionRanges.find(RangeListEntryStartAddress); + if (CurrRange == InvalidRange || CurrRange == FunctionRanges.end() || + !IntervalContainsAddress(CurrRange, RangeListEntryStartAddress)) { reportWarning("no mapping for range.", File); continue; } } } - TheDwarfEmitter->emitRangesEntries(UnitPcOffset, OrigLowPc, CurrRange, + TheDwarfEmitter->emitRangesEntries(UnitPcOffset, *OrigLowPc, CurrRange, Entries, AddressSize); } } @@ -1623,17 +1624,17 @@ // 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 || + !IntervalContainsAddress(CurrRange, Row.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() + ? CurrRange.stop().Address + CurrRange.value() : -1ULL; - CurrRange = FunctionRanges.find(Row.Address.Address); + CurrRange = FunctionRanges.find(Row.Address); bool CurrRangeValid = - CurrRange != InvalidRange && CurrRange.start() <= Row.Address.Address; + CurrRange != InvalidRange && CurrRange.start() <= Row.Address; if (!CurrRangeValid) { CurrRange = InvalidRange; if (StopAddress != -1ULL) { @@ -1643,11 +1644,11 @@ // 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 <= Row.Address && Range->second.HighPC >= Row.Address.Address) { StopAddress = Row.Address.Address + Range->second.Offset; } @@ -1806,10 +1807,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; 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,29 @@ } } -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) { + assert(FuncLowPc.SectionIndex == FuncHighPc.SectionIndex); + // 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) + this->LowPc = std::min(*LowPc, FuncLowPc.Address + PcOffset); + else + this->LowPc = FuncLowPc.Address + PcOffset; + if (HighPc) + this->HighPc = std::max(*HighPc, FuncHighPc.Address + PcOffset); + else + this->HighPc = FuncHighPc.Address + PcOffset; } void CompileUnit::noteRangeAttribute(const DIE &Die, PatchLocation Attr) { diff --git a/llvm/lib/DWARFLinker/DWARFStreamer.cpp b/llvm/lib/DWARFLinker/DWARFStreamer.cpp --- a/llvm/lib/DWARFLinker/DWARFStreamer.cpp +++ b/llvm/lib/DWARFLinker/DWARFStreamer.cpp @@ -300,8 +300,8 @@ continue; // All range entries should lie in the function range. - if (!(Range.StartAddress + OrigLowPc >= FuncRange.start() && - Range.EndAddress + OrigLowPc <= FuncRange.stop())) + if (!(IntervalContainsAddress( + FuncRange, {Range.StartAddress + OrigLowPc, Range.SectionIndex}))) warn("inconsistent range data.", "emitting debug_ranges"); MS->emitIntValue(Range.StartAddress + PcOffset, AddressSize); MS->emitIntValue(Range.EndAddress + PcOffset, AddressSize); @@ -329,8 +329,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. @@ -381,7 +381,7 @@ MS->SwitchSection(MC->getObjectFileInfo()->getDwarfRangesSection()); // Offset each range by the right amount. - int64_t PcOffset = -Unit.getLowPc(); + int64_t PcOffset = Unit.getLowPc() ? -*Unit.getLowPc() : 0; // Emit coalesced ranges. for (auto Range = Ranges.begin(), End = Ranges.end(); Range != End; ++Range) { MS->emitIntValue(Range->first + PcOffset, AddressSize); @@ -418,9 +418,13 @@ DWARFUnit &OrigUnit = Unit.getOrigUnit(); 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 (auto OrigLowPc = + dwarf::toAddress(OrigUnitDie.find(dwarf::DW_AT_low_pc))) { + if (Unit.getLowPc()) + UnitPcOffset = int64_t(*OrigLowPc) - *Unit.getLowPc(); + else + UnitPcOffset = int64_t(*OrigLowPc); + } SmallVector Buffer; for (const auto &Attr : Attributes) { uint64_t Offset = Attr.first.get(); diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -414,15 +414,16 @@ return toSectionOffset(find(DW_AT_loclists_base)); } -Optional DWARFDie::getHighPC(uint64_t LowPC) const { +Optional DWARFDie::getHighPC(object::SectionedAddress LowPC) const { if (auto FormValue = find(DW_AT_high_pc)) { - if (auto Address = FormValue->getAsAddress()) { + if (auto Address = FormValue->getAsSectionedAddress()) { // High PC is an address. - return Address; + if (Address->SectionIndex == LowPC.SectionIndex) + return Address->Address; } if (auto Offset = FormValue->getAsUnsignedConstant()) { // High PC is an offset from LowPC. - return LowPC + *Offset; + return LowPC.Address + *Offset; } } return None; @@ -434,7 +435,7 @@ auto LowPcAddr = toSectionedAddress(F); if (!LowPcAddr) return false; - if (auto HighPcAddr = getHighPC(LowPcAddr->Address)) { + if (auto HighPcAddr = getHighPC(*LowPcAddr)) { LowPC = LowPcAddr->Address; HighPC = *HighPcAddr; SectionIndex = LowPcAddr->SectionIndex; 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/unittests/DebugInfo/DWARF/CMakeLists.txt b/llvm/unittests/DebugInfo/DWARF/CMakeLists.txt --- a/llvm/unittests/DebugInfo/DWARF/CMakeLists.txt +++ b/llvm/unittests/DebugInfo/DWARF/CMakeLists.txt @@ -3,6 +3,7 @@ AsmPrinter BinaryFormat DebugInfoDWARF + DWARFLinker MC Object ObjectYAML @@ -21,6 +22,7 @@ DWARFDieTest.cpp DWARFFormValueTest.cpp DWARFLocationExpressionTest.cpp + DWARFLinkerCompileUnit.cpp ) target_link_libraries(DebugInfoDWARFTests PRIVATE LLVMTestingSupport) diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp --- a/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp +++ b/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp @@ -906,7 +906,8 @@ EXPECT_FALSE((bool)OptU64); OptU64 = toUnsigned(SubprogramDieNoPC.find(DW_AT_high_pc)); EXPECT_FALSE((bool)OptU64); - OptU64 = SubprogramDieNoPC.getHighPC(ActualLowPC); + OptU64 = SubprogramDieNoPC.getHighPC( + {ActualLowPC, object::SectionedAddress::UndefSection}); EXPECT_FALSE((bool)OptU64); EXPECT_FALSE(SubprogramDieNoPC.getLowAndHighPC(LowPC, HighPC, SectionIndex)); @@ -923,7 +924,8 @@ EXPECT_FALSE((bool)OptU64); OptU64 = toUnsigned(SubprogramDieLowPC.find(DW_AT_high_pc)); EXPECT_FALSE((bool)OptU64); - OptU64 = SubprogramDieLowPC.getHighPC(ActualLowPC); + OptU64 = SubprogramDieLowPC.getHighPC( + {ActualLowPC, object::SectionedAddress::UndefSection}); EXPECT_FALSE((bool)OptU64); EXPECT_FALSE(SubprogramDieLowPC.getLowAndHighPC(LowPC, HighPC, SectionIndex)); @@ -955,7 +957,8 @@ EXPECT_FALSE((bool)OptU64); } - OptU64 = SubprogramDieLowHighPC.getHighPC(ActualLowPC); + OptU64 = SubprogramDieLowHighPC.getHighPC( + {ActualLowPC, object::SectionedAddress::UndefSection}); EXPECT_TRUE((bool)OptU64); EXPECT_EQ(OptU64.getValue(), ActualHighPC); diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFLinkerCompileUnit.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFLinkerCompileUnit.cpp new file mode 100644 --- /dev/null +++ b/llvm/unittests/DebugInfo/DWARF/DWARFLinkerCompileUnit.cpp @@ -0,0 +1,165 @@ +//===- llvm/unittest/DebugInfo/DWARFLinkerCompileUnit.cpp -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/ObjectYAML/DWARFEmitter.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace llvm::dwarf; +using object::SectionedAddress; + +namespace { + +TEST(DWARFLinkerCompileUnit, sectionedAddressRanges) { + const char *yamldata = "debug_abbrev:\n" + " - Code: 0x00000001\n" + " Tag: DW_TAG_compile_unit\n" + " Children: DW_CHILDREN_yes\n" + " Attributes:\n" + "debug_info:\n" + " - Length:\n" + " TotalLength: 0\n" + " Version: 4\n" + " AbbrOffset: 0\n" + " AddrSize: 8\n" + " Entries:\n" + " - AbbrCode: 0x00000001\n" + " Values:\n" + " - AbbrCode: 0x00000000\n" + " Values:\n"; + + auto ErrOrSections = DWARFYAML::EmitDebugSections(StringRef(yamldata), true); + ASSERT_TRUE((bool)ErrOrSections); + std::unique_ptr DwarfContext = + DWARFContext::create(*ErrOrSections, 8); + + // Verify the number of compile units is correct. + uint32_t NumCUs = DwarfContext->getNumCompileUnits(); + EXPECT_EQ(NumCUs, 1u); + DWARFCompileUnit *U = cast(DwarfContext->getUnitAtIndex(0)); + + // Check the compile unit DIE is valid. + auto DieDG = U->getUnitDIE(false); + EXPECT_TRUE(DieDG.isValid()); + + // Create DWARFLinker compile unit. + CompileUnit CU(*U, 1, false, ""); + + // Check for adding zero address range from undefined section. + CU.addFunctionRange({0x10, object::SectionedAddress::UndefSection}, + {0x10, object::SectionedAddress::UndefSection}, 0x4000); + EXPECT_TRUE(CU.getFunctionRanges().empty()); + + EXPECT_TRUE(*CU.getLowPc() == 0x4010); + EXPECT_TRUE(*CU.getHighPc() == 0x4010); + + // Check for adding zero address range from first section. + CU.addFunctionRange({0x10, 1}, {0x10, 1}, 0x4500); + EXPECT_TRUE(CU.getFunctionRanges().empty()); + + EXPECT_TRUE(*CU.getLowPc() == 0x4010); + EXPECT_TRUE(*CU.getHighPc() == 0x4510); + + // Check for adding valid address range from undefined section. + CU.addFunctionRange({0x10, object::SectionedAddress::UndefSection}, + {0x20, object::SectionedAddress::UndefSection}, 0x4000); + EXPECT_TRUE(!CU.getFunctionRanges().empty()); + EXPECT_TRUE(CU.getFunctionRanges().find( + {0x10, object::SectionedAddress::UndefSection}) != + CU.getFunctionRanges().end()); + EXPECT_TRUE(CU.getFunctionRanges().lookup( + {0x10, object::SectionedAddress::UndefSection}) == 0x4000); + + // Check for adding second valid address range from undefined section. + CU.addFunctionRange({0x20, object::SectionedAddress::UndefSection}, + {0x40, object::SectionedAddress::UndefSection}, 0x5000); + EXPECT_TRUE(!CU.getFunctionRanges().empty()); + EXPECT_TRUE(CU.getFunctionRanges().find( + {0x20, object::SectionedAddress::UndefSection}) != + CU.getFunctionRanges().end()); + EXPECT_TRUE(CU.getFunctionRanges().lookup( + {0x20, object::SectionedAddress::UndefSection}) == 0x5000); + EXPECT_TRUE(CU.getFunctionRanges().lookup( + {0x19, object::SectionedAddress::UndefSection}) == 0x4000); + + // Check for adding third valid address range from undefined section. + CU.addFunctionRange({0x100, object::SectionedAddress::UndefSection}, + {0x200, object::SectionedAddress::UndefSection}, 0x6000); + EXPECT_TRUE(!CU.getFunctionRanges().empty()); + EXPECT_TRUE(CU.getFunctionRanges().find( + {0x100, object::SectionedAddress::UndefSection}) != + CU.getFunctionRanges().end()); + + // Check that function ranges does not contain values which were not put there + // previously. + EXPECT_TRUE(CU.getFunctionRanges().lookup( + {0x5, object::SectionedAddress::UndefSection}, -1LL) == -1LL); + EXPECT_TRUE(CU.getFunctionRanges().lookup( + {0x100, object::SectionedAddress::UndefSection}) == 0x6000); + + // Check compile unit low/high pc values. + EXPECT_TRUE(*CU.getLowPc() == 0x4010); + EXPECT_TRUE(*CU.getHighPc() == 0x6200); + + // Check for adding valid address range from first section. + CU.addFunctionRange({0x10, 1}, {0x20, 1}, 0x1000); + EXPECT_TRUE(!CU.getFunctionRanges().empty()); + EXPECT_TRUE(CU.getFunctionRanges().find({0x10, 1}) != + CU.getFunctionRanges().end()); + EXPECT_TRUE(CU.getFunctionRanges().lookup({0x10, 1}) == 0x1000); + + // Check for adding second valid address range from first section. + CU.addFunctionRange({0x20, 1}, {0x40, 1}, 0x2000); + EXPECT_TRUE(!CU.getFunctionRanges().empty()); + EXPECT_TRUE(CU.getFunctionRanges().find({0x20, 1}) != + CU.getFunctionRanges().end()); + EXPECT_TRUE(CU.getFunctionRanges().lookup({0x20, 1}) == 0x2000); + EXPECT_TRUE(CU.getFunctionRanges().lookup({0x19, 1}) == 0x1000); + + // Check for adding valid address range from second section. + CU.addFunctionRange({0x10, 2}, {0x20, 2}, 0x3000); + EXPECT_TRUE(!CU.getFunctionRanges().empty()); + EXPECT_TRUE(CU.getFunctionRanges().find({0x10, 2}) != + CU.getFunctionRanges().end()); + EXPECT_TRUE(CU.getFunctionRanges().lookup({0x10, 2}) == 0x3000); + + // Check that function ranges does not contain values which were not put there + // previously. + EXPECT_TRUE(CU.getFunctionRanges().lookup({0x10, 3}, -1LL) == -1LL); + EXPECT_TRUE(CU.getFunctionRanges().lookup({UINT64_MAX, 2}, -1LL) == -1LL); + + EXPECT_TRUE(*CU.getLowPc() == 0x1010); + EXPECT_TRUE(*CU.getHighPc() == 0x6200); + + // Check for adding valid address range from four section. + CU.addFunctionRange({0x0, 4}, {0x200, 4}, 0x8000); + EXPECT_TRUE(!CU.getFunctionRanges().empty()); + EXPECT_TRUE(CU.getFunctionRanges().find({0x10, 4}) != + CU.getFunctionRanges().end()); + EXPECT_TRUE(CU.getFunctionRanges().lookup({0x10, 4}) == 0x8000); + + EXPECT_TRUE(*CU.getLowPc() == 0x1010); + EXPECT_TRUE(*CU.getHighPc() == 0x8200); + + // Check adding labels. + CU.addLabelLowPc({0x10, object::SectionedAddress::UndefSection}, 0x4000); + EXPECT_TRUE(CU.hasLabelAt({0x10, object::SectionedAddress::UndefSection})); + EXPECT_TRUE(!CU.hasLabelAt({0x0, object::SectionedAddress::UndefSection})); + + CU.addLabelLowPc({0x10, 1}, 0x4000); + EXPECT_TRUE(CU.hasLabelAt({0x10, 1})); + EXPECT_TRUE(!CU.hasLabelAt({0x0, 1})); + + EXPECT_TRUE(!CU.hasLabelAt({0x10, 2})); +} + +} // end anonymous namespace