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 @@ -121,13 +121,10 @@ virtual void emitAppleTypes(AccelTable &Table) = 0; - /// Emit .debug_ranges for \p FuncRange by translating the - /// original \p Entries. - virtual void emitRangesEntries( - int64_t UnitPcOffset, uint64_t OrigLowPc, - std::optional> FuncRange, - const std::vector &Entries, - unsigned AddressSize) = 0; + /// Emit piece of .debug_ranges for \p Ranges. + virtual void + emitDwarfDebugRangesTableFragment(const CompileUnit &Unit, + const AddressRanges &LinkedRanges) = 0; /// Emit .debug_aranges entries for \p Unit and if \p DoRangesSection is true, /// also emit the .debug_ranges entries for the DW_TAG_compile_unit's 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 @@ -139,7 +139,7 @@ uint64_t getNextUnitOffset() const { return NextUnitOffset; } void setStartOffset(uint64_t DebugInfoSize) { StartOffset = DebugInfoSize; } - uint64_t getLowPc() const { return LowPc; } + std::optional getLowPc() const { return LowPc; } uint64_t getHighPc() const { return HighPc; } bool hasLabelAt(uint64_t Addr) const { return Labels.count(Addr); } @@ -257,7 +257,7 @@ uint64_t StartOffset; uint64_t NextUnitOffset; - uint64_t LowPc = std::numeric_limits::max(); + std::optional LowPc; uint64_t HighPc = 0; /// A list of attributes to fixup with the absolute offset of diff --git a/llvm/include/llvm/DWARFLinker/DWARFStreamer.h b/llvm/include/llvm/DWARFLinker/DWARFStreamer.h --- a/llvm/include/llvm/DWARFLinker/DWARFStreamer.h +++ b/llvm/include/llvm/DWARFLinker/DWARFStreamer.h @@ -93,13 +93,10 @@ llvm::binaryformat::Swift5ReflectionSectionKind ReflSectionKind, StringRef Buffer, uint32_t Alignment, uint32_t Size); - /// Emit debug_ranges for \p FuncRange by translating the - /// original \p Entries. - void emitRangesEntries( - int64_t UnitPcOffset, uint64_t OrigLowPc, - std::optional> FuncRange, - const std::vector &Entries, - unsigned AddressSize) override; + /// Emit piece of .debug_ranges for \p Ranges. + virtual void + emitDwarfDebugRangesTableFragment(const CompileUnit &Unit, + const AddressRanges &LinkedRanges) override; /// Emit debug_aranges entries for \p Unit and if \p DoRangesSection is true, /// also emit the debug_ranges entries for the DW_TAG_compile_unit's @@ -192,6 +189,8 @@ void emitMacroTableImpl(const DWARFDebugMacro *MacroTable, const Offset2UnitMap &UnitMacroMap, OffsetsStringPool &StringPool, uint64_t &OutOffset); + void emitDwarfDebugArangesTable(const CompileUnit &Unit, + const AddressRanges &LinkedRanges); /// \defgroup MCObjects MC layer objects constructed by the streamer /// @{ 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 @@ -1198,8 +1198,9 @@ : Addr) + Info.PCOffset; } else if (Die.getTag() == dwarf::DW_TAG_compile_unit) { - Addr = Unit.getLowPc(); - if (Addr == std::numeric_limits::max()) + if (std::optional LowPC = Unit.getLowPc()) + Addr = *LowPC; + else return 0; } Info.HasLowPc = true; @@ -1276,10 +1277,11 @@ if (AttrSpec.Attr == dwarf::DW_AT_high_pc && Die.getTag() == dwarf::DW_TAG_compile_unit) { - if (Unit.getLowPc() == -1ULL) + std::optional LowPC = Unit.getLowPc(); + if (!LowPC) return 0; // Dwarf >= 4 high_pc is an size, not an address. - Value = Unit.getHighPc() - Unit.getLowPc(); + Value = Unit.getHighPc() - *LowPC; } else if (AttrSpec.Form == dwarf::DW_FORM_sec_offset) Value = *Val.getAsSectionOffset(); else if (AttrSpec.Form == dwarf::DW_FORM_sdata) @@ -1657,16 +1659,11 @@ DWARFDataExtractor RangeExtractor(OrigDwarf.getDWARFObj(), OrigDwarf.getDWARFObj().getRangesSection(), OrigDwarf.isLittleEndian(), AddressSize); - std::optional> CurrRange; + std::optional> CachedRange; DWARFUnit &OrigUnit = Unit.getOrigUnit(); auto OrigUnitDie = OrigUnit.getUnitDIE(false); - uint64_t OrigLowPc = - dwarf::toAddress(OrigUnitDie.find(dwarf::DW_AT_low_pc), -1ULL); - // 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(); + uint64_t UnitBaseAddress = + dwarf::toAddress(OrigUnitDie.find(dwarf::DW_AT_low_pc), 0); for (const auto &RangeAttribute : Unit.getRangesAttributes()) { uint64_t Offset = RangeAttribute.get(); @@ -1677,22 +1674,36 @@ RangeList.clear(); } const auto &Entries = RangeList.getEntries(); + + uint64_t BaseAddress = UnitBaseAddress; + AddressRanges LinkedRanges; + if (!Entries.empty()) { - const DWARFDebugRangeList::RangeListEntry &First = Entries.front(); - - if (!CurrRange || - !CurrRange->first.contains(First.StartAddress + OrigLowPc)) { - CurrRange = FunctionRanges.getRangeValueThatContains( - First.StartAddress + OrigLowPc); - if (!CurrRange) { - reportWarning("no mapping for range.", File); + for (const auto &Range : Entries) { + if (Range.isBaseAddressSelectionEntry( + Unit.getOrigUnit().getAddressByteSize())) { + BaseAddress = Range.EndAddress; continue; } + + if (!CachedRange || + !CachedRange->first.contains(Range.StartAddress + BaseAddress)) + CachedRange = FunctionRanges.getRangeValueThatContains( + Range.StartAddress + BaseAddress); + + // All range entries should lie in the function range. + if (!CachedRange) { + reportWarning("inconsistent range data.", File); + continue; + } + + LinkedRanges.insert( + {Range.StartAddress + BaseAddress + CachedRange->second, + Range.EndAddress + BaseAddress + CachedRange->second}); } } - TheDwarfEmitter->emitRangesEntries(UnitPcOffset, OrigLowPc, CurrRange, - Entries, AddressSize); + TheDwarfEmitter->emitDwarfDebugRangesTableFragment(Unit, LinkedRanges); } } 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 @@ -127,7 +127,10 @@ void CompileUnit::addFunctionRange(uint64_t FuncLowPc, uint64_t FuncHighPc, int64_t PcOffset) { Ranges.insert({FuncLowPc, FuncHighPc}, PcOffset); - this->LowPc = std::min(LowPc, FuncLowPc + PcOffset); + if (LowPc) + LowPc = std::min(*LowPc, FuncLowPc + PcOffset); + else + LowPc = FuncLowPc + PcOffset; this->HighPc = std::max(HighPc, FuncHighPc + PcOffset); } 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 @@ -320,42 +320,74 @@ MS->emitBytes(Buffer); } -/// Emit the debug_range section contents for \p FuncRange by -/// translating the original \p Entries. The debug_range section -/// format is totally trivial, consisting just of pairs of address -/// sized addresses describing the ranges. -void DwarfStreamer::emitRangesEntries( - int64_t UnitPcOffset, uint64_t OrigLowPc, - std::optional> FuncRange, - const std::vector &Entries, - unsigned AddressSize) { +void DwarfStreamer::emitDwarfDebugArangesTable( + const CompileUnit &Unit, const AddressRanges &LinkedRanges) { + unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize(); + + // Make .debug_aranges to be current section. + MS->switchSection(MC->getObjectFileInfo()->getDwarfARangesSection()); + + // Emit Header. + MCSymbol *BeginLabel = Asm->createTempSymbol("Barange"); + MCSymbol *EndLabel = Asm->createTempSymbol("Earange"); + + unsigned HeaderSize = + sizeof(int32_t) + // Size of contents (w/o this field + sizeof(int16_t) + // DWARF ARange version number + sizeof(int32_t) + // Offset of CU in the .debug_info section + sizeof(int8_t) + // Pointer Size (in bytes) + sizeof(int8_t); // Segment Size (in bytes) + + unsigned TupleSize = AddressSize * 2; + unsigned Padding = offsetToAlignment(HeaderSize, Align(TupleSize)); + + Asm->emitLabelDifference(EndLabel, BeginLabel, 4); // Arange length + Asm->OutStreamer->emitLabel(BeginLabel); + Asm->emitInt16(dwarf::DW_ARANGES_VERSION); // Version number + Asm->emitInt32(Unit.getStartOffset()); // Corresponding unit's offset + Asm->emitInt8(AddressSize); // Address size + Asm->emitInt8(0); // Segment size + + Asm->OutStreamer->emitFill(Padding, 0x0); + + // Emit linked ranges. + for (const AddressRange &Range : LinkedRanges) { + MS->emitIntValue(Range.start(), AddressSize); + MS->emitIntValue(Range.end() - Range.start(), AddressSize); + } + + // Emit terminator. + Asm->OutStreamer->emitIntValue(0, AddressSize); + Asm->OutStreamer->emitIntValue(0, AddressSize); + Asm->OutStreamer->emitLabel(EndLabel); +} + +void DwarfStreamer::emitDwarfDebugRangesTableFragment( + const CompileUnit &Unit, const AddressRanges &LinkedRanges) { + unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize(); + + // Make .debug_ranges to be current section. MS->switchSection(MC->getObjectFileInfo()->getDwarfRangesSection()); - // Offset each range by the right amount. - int64_t PcOffset = - (Entries.empty() || !FuncRange) ? 0 : FuncRange->second + UnitPcOffset; - for (const auto &Range : Entries) { - if (Range.isBaseAddressSelectionEntry(AddressSize)) { - warn("unsupported base address selection operation", - "emitting debug_ranges"); - break; - } - // Do not emit empty ranges. - if (Range.StartAddress == Range.EndAddress) - continue; + // Emit ranges. + uint64_t BaseAddress = 0; + if (std::optional LowPC = Unit.getLowPc()) + BaseAddress = *LowPC; + + for (const AddressRange &Range : LinkedRanges) { + MS->emitIntValue(Range.start() - BaseAddress, AddressSize); + MS->emitIntValue(Range.end() - BaseAddress, AddressSize); - // All range entries should lie in the function range. - if (!FuncRange->first.contains(Range.StartAddress + OrigLowPc)) - warn("inconsistent range data.", "emitting debug_ranges"); - MS->emitIntValue(Range.StartAddress + PcOffset, AddressSize); - MS->emitIntValue(Range.EndAddress + PcOffset, AddressSize); - RangesSectionSize += 2 * AddressSize; + RangesSectionSize += AddressSize; + RangesSectionSize += AddressSize; } // Add the terminator entry. MS->emitIntValue(0, AddressSize); MS->emitIntValue(0, AddressSize); - RangesSectionSize += 2 * AddressSize; + + RangesSectionSize += AddressSize; + RangesSectionSize += AddressSize; } /// Emit the debug_aranges contribution of a unit and @@ -365,82 +397,21 @@ /// Just aggregate all the ranges gathered inside that unit. void DwarfStreamer::emitUnitRangesEntries(CompileUnit &Unit, bool DoDebugRanges) { - unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize(); - // Gather the ranges in a vector, so that we can simplify them. The - // IntervalMap will have coalesced the non-linked ranges, but here - // we want to coalesce the linked addresses. - std::vector> Ranges; const RangesTy &FunctionRanges = Unit.getFunctionRanges(); - for (size_t Idx = 0; Idx < FunctionRanges.size(); Idx++) { - std::pair CurRange = FunctionRanges[Idx]; - Ranges.push_back(std::make_pair(CurRange.first.start() + CurRange.second, - CurRange.first.end() + CurRange.second)); - } + // Linked addresses might end up in a different order. + // Build linked address ranges. + AddressRanges LinkedRanges; + for (size_t Idx = 0; Idx < FunctionRanges.size(); Idx++) + LinkedRanges.insert( + {FunctionRanges[Idx].first.start() + FunctionRanges[Idx].second, + FunctionRanges[Idx].first.end() + FunctionRanges[Idx].second}); - // The object addresses where sorted, but again, the linked - // addresses might end up in a different order. - llvm::sort(Ranges); - - if (!Ranges.empty()) { - MS->switchSection(MC->getObjectFileInfo()->getDwarfARangesSection()); - - MCSymbol *BeginLabel = Asm->createTempSymbol("Barange"); - MCSymbol *EndLabel = Asm->createTempSymbol("Earange"); - - unsigned HeaderSize = - sizeof(int32_t) + // Size of contents (w/o this field - sizeof(int16_t) + // DWARF ARange version number - sizeof(int32_t) + // Offset of CU in the .debug_info section - sizeof(int8_t) + // Pointer Size (in bytes) - sizeof(int8_t); // Segment Size (in bytes) - - unsigned TupleSize = AddressSize * 2; - unsigned Padding = offsetToAlignment(HeaderSize, Align(TupleSize)); - - Asm->emitLabelDifference(EndLabel, BeginLabel, 4); // Arange length - Asm->OutStreamer->emitLabel(BeginLabel); - Asm->emitInt16(dwarf::DW_ARANGES_VERSION); // Version number - Asm->emitInt32(Unit.getStartOffset()); // Corresponding unit's offset - Asm->emitInt8(AddressSize); // Address size - Asm->emitInt8(0); // Segment size - - Asm->OutStreamer->emitFill(Padding, 0x0); - - for (auto Range = Ranges.begin(), End = Ranges.end(); Range != End; - ++Range) { - uint64_t RangeStart = Range->first; - MS->emitIntValue(RangeStart, AddressSize); - while ((Range + 1) != End && Range->second == (Range + 1)->first) - ++Range; - MS->emitIntValue(Range->second - RangeStart, AddressSize); - } - - // Emit terminator - Asm->OutStreamer->emitIntValue(0, AddressSize); - Asm->OutStreamer->emitIntValue(0, AddressSize); - Asm->OutStreamer->emitLabel(EndLabel); - } + if (!FunctionRanges.empty()) + emitDwarfDebugArangesTable(Unit, LinkedRanges); - if (!DoDebugRanges) - return; - - MS->switchSection(MC->getObjectFileInfo()->getDwarfRangesSection()); - // Offset each range by the right amount. - int64_t PcOffset = -Unit.getLowPc(); - // Emit coalesced ranges. - for (auto Range = Ranges.begin(), End = Ranges.end(); Range != End; ++Range) { - MS->emitIntValue(Range->first + PcOffset, AddressSize); - while (Range + 1 != End && Range->second == (Range + 1)->first) - ++Range; - MS->emitIntValue(Range->second + PcOffset, AddressSize); - RangesSectionSize += 2 * AddressSize; - } - - // Add the terminator entry. - MS->emitIntValue(0, AddressSize); - MS->emitIntValue(0, AddressSize); - RangesSectionSize += 2 * AddressSize; + if (DoDebugRanges) + emitDwarfDebugRangesTableFragment(Unit, LinkedRanges); } /// Emit location lists for \p Unit and update attributes to point to the new @@ -464,8 +435,11 @@ 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))) { + assert(Unit.getLowPc()); + UnitPcOffset = int64_t(*OrigLowPc) - *Unit.getLowPc(); + } SmallVector Buffer; for (const auto &Attr : Attributes) {