Index: include/llvm/CodeGen/AsmPrinter.h =================================================================== --- include/llvm/CodeGen/AsmPrinter.h +++ include/llvm/CodeGen/AsmPrinter.h @@ -460,6 +460,8 @@ void EmitLabelDifference(const MCSymbol *Hi, const MCSymbol *Lo, unsigned Size) const; + void EmitULEB128LabelDifference(const MCSymbol *Hi, const MCSymbol *Lo) const; + /// Emit something like ".long Label+Offset" where the size in bytes of the /// directive is specified by Size and Label specifies the label. This /// implicitly uses .set if it is available. Index: include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h +++ include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h @@ -11,6 +11,7 @@ #define LLVM_DEBUGINFO_DWARF_DWARFDEBUGLOC_H #include "llvm/ADT/SmallVector.h" +#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" #include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" #include @@ -56,8 +57,9 @@ class DWARFDebugLocDWO { struct Entry { - uint64_t Start; - uint32_t Length; + dwarf::LocationListEntry Kind; + uint64_t First; + uint32_t Second; SmallVector Loc; }; Index: include/llvm/MC/MCObjectStreamer.h =================================================================== --- include/llvm/MC/MCObjectStreamer.h +++ include/llvm/MC/MCObjectStreamer.h @@ -167,6 +167,8 @@ /// \pre Offset of \c Hi is greater than the offset \c Lo. void emitAbsoluteSymbolDiff(const MCSymbol *Hi, const MCSymbol *Lo, unsigned Size) override; + void emitULEB128AbsoluteSymbolDiff(const MCSymbol *Hi, + const MCSymbol *Lo) override; bool mayHaveInstructions(MCSection &Sec) const override; }; Index: include/llvm/MC/MCStreamer.h =================================================================== --- include/llvm/MC/MCStreamer.h +++ include/llvm/MC/MCStreamer.h @@ -780,6 +780,9 @@ virtual void emitAbsoluteSymbolDiff(const MCSymbol *Hi, const MCSymbol *Lo, unsigned Size); + virtual void emitULEB128AbsoluteSymbolDiff(const MCSymbol *Hi, + const MCSymbol *Lo); + virtual MCSymbol *getDwarfLineTableSymbol(unsigned CUID); virtual void EmitCFISections(bool EH, bool Debug); void EmitCFIStartProc(bool IsSimple); Index: lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1837,6 +1837,11 @@ OutStreamer->emitAbsoluteSymbolDiff(Hi, Lo, Size); } +void AsmPrinter::EmitULEB128LabelDifference(const MCSymbol *Hi, + const MCSymbol *Lo) const { + OutStreamer->emitULEB128AbsoluteSymbolDiff(Hi, Lo); +} + /// EmitLabelPlusOffset - Emit something like ".long Label+Offset" /// where the size in bytes of the directive is specified by Size and Label /// specifies the label. This implicitly uses .set if it is available. Index: lib/CodeGen/AsmPrinter/DwarfDebug.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.h +++ lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -297,6 +297,8 @@ // Identify a debugger for "tuning" the debug info. DebuggerKind DebuggerTuning; + DenseMap FirstAddresses; + /// \defgroup DebuggerTuning Predicates to tune DWARF for a given debugger. /// /// Returns whether we are "tuning" for a given debugger. Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -1226,6 +1226,8 @@ if (SP->getUnit()->getEmissionKind() == DICompileUnit::NoDebug) return; + const MCSymbol *BeginSym = Asm->getFunctionBegin(); + FirstAddresses.insert(std::make_pair(&BeginSym->getSection(), BeginSym)); DwarfCompileUnit &CU = getOrCreateDwarfCompileUnit(SP->getUnit()); // Set DwarfDwarfCompileUnitID in MCContext to the Compile Unit this function @@ -1654,23 +1656,74 @@ } } +template +static void emitBasedRanges(const DwarfCompileUnit &CU, const Range &R, + StartGetter getStart, BaseFilter shouldUseBase, + BaseEmitter emitBase, EntryEmitter emitEntry, + BaselessEntryEmitter emitBaselessEntry) { + // Gather all the ranges that apply to the same section so they can + // share a base address entry. + MapVector> MV; + for (const auto &SR : R) + MV[&getStart(SR)->getSection()].push_back(&SR); + + auto *CUBase = CU.getBaseAddress(); + bool BaseIsSet = false; + for (const auto &P : MV) { + auto Base = CUBase; + if (!Base && shouldUseBase(P.second)) { + BaseIsSet = true; + Base = getStart(*P.second.front()); + emitBase(Base); + } else if (BaseIsSet) { + BaseIsSet = false; + emitBase(nullptr); + } + + for (const auto *RS : P.second) + Base ? emitEntry(Base, *RS) : emitBaselessEntry(*RS); + } +} + void DwarfDebug::emitDebugLocDWO() { Asm->OutStreamer->SwitchSection( Asm->getObjFileLowering().getDwarfLocDWOSection()); for (const auto &List : DebugLocs.getLists()) { Asm->OutStreamer->EmitLabel(List.Label); - for (const auto &Entry : DebugLocs.getEntries(List)) { - // Just always use start_length for now - at least that's one address - // rather than two. We could get fancier and try to, say, reuse an - // address we know we've emitted elsewhere (the start of the function? - // The start of the CU or CU subrange that encloses this range?) - Asm->EmitInt8(dwarf::DW_LLE_startx_length); - unsigned idx = AddrPool.getIndex(Entry.BeginSym); - Asm->EmitULEB128(idx); - Asm->EmitLabelDifference(Entry.EndSym, Entry.BeginSym, 4); - - emitDebugLocEntryLocation(Entry); - } + emitBasedRanges(*List.CU, DebugLocs.getEntries(List), + [&](const DebugLocStream::Entry &E) { + return FirstAddresses[&E.BeginSym->getSection()]; + }, + [](const std::vector &v) { + return true; + }, + [&](const MCSymbol *Base) { + Asm->EmitInt8(dwarf::DW_LLE_base_addressx); + unsigned idx = AddrPool.getIndex(Base); + Asm->EmitULEB128(idx); + }, + [&](const MCSymbol *Base, const DebugLocStream::Entry &E) { + Asm->EmitInt8(dwarf::DW_LLE_offset_pair); + auto &Context = Asm->OutStreamer->getContext(); + Asm->OutStreamer->EmitULEB128Value( + MCBinaryExpr::createSub( + MCSymbolRefExpr::create(E.BeginSym, Context), + MCSymbolRefExpr::create(Base, Context), Context)); + Asm->OutStreamer->EmitULEB128Value( + MCBinaryExpr::createSub( + MCSymbolRefExpr::create(E.EndSym, Context), + MCSymbolRefExpr::create(Base, Context), Context)); + emitDebugLocEntryLocation(E); + }, + [&](const DebugLocStream::Entry &E) { + Asm->EmitInt8(dwarf::DW_LLE_startx_length); + unsigned idx = AddrPool.getIndex(E.BeginSym); + Asm->EmitULEB128(idx); + Asm->EmitLabelDifference(E.EndSym, E.BeginSym, 4); + emitDebugLocEntryLocation(E); + }); Asm->EmitInt8(dwarf::DW_LLE_end_of_list); } } @@ -1861,52 +1914,28 @@ // Emit our symbol so we can find the beginning of the range. Asm->OutStreamer->EmitLabel(List.getSym()); - // Gather all the ranges that apply to the same section so they can share - // a base address entry. - MapVector> MV; - for (const RangeSpan &Range : List.getRanges()) { - MV[&Range.getStart()->getSection()].push_back(&Range); - } - - auto *CUBase = TheCU->getBaseAddress(); - bool BaseIsSet = false; - for (const auto &P : MV) { - // Don't bother with a base address entry if there's only one range in - // this section in this range list - for example ranges for a CU will - // usually consist of single regions from each of many sections - // (-ffunction-sections, or just C++ inline functions) except under LTO - // or optnone where there may be holes in a single CU's section - // contrubutions. - auto *Base = CUBase; - if (!Base && P.second.size() > 1 && - UseDwarfRangesBaseAddressSpecifier) { - BaseIsSet = true; - // FIXME/use care: This may not be a useful base address if it's not - // the lowest address/range in this object. - Base = P.second.front()->getStart(); - Asm->OutStreamer->EmitIntValue(-1, Size); - Asm->OutStreamer->EmitSymbolValue(Base, Size); - } else if (BaseIsSet) { - BaseIsSet = false; - Asm->OutStreamer->EmitIntValue(-1, Size); - Asm->OutStreamer->EmitIntValue(0, Size); - } - - for (const auto *RS : P.second) { - const MCSymbol *Begin = RS->getStart(); - const MCSymbol *End = RS->getEnd(); - assert(Begin && "Range without a begin symbol?"); - assert(End && "Range without an end symbol?"); - if (Base) { - Asm->EmitLabelDifference(Begin, Base, Size); - Asm->EmitLabelDifference(End, Base, Size); - } else { - Asm->OutStreamer->EmitSymbolValue(Begin, Size); - Asm->OutStreamer->EmitSymbolValue(End, Size); - } - } - } - + emitBasedRanges(*TheCU, List.getRanges(), + [](const RangeSpan &R) { return R.getStart(); }, + [](const std::vector &V) { + return V.size() > 1 && + UseDwarfRangesBaseAddressSpecifier; + }, + [&](const MCSymbol *Base) { + Asm->OutStreamer->EmitIntValue(-1, Size); + if (Base) { + Asm->OutStreamer->EmitSymbolValue(Base, Size); + } else { + Asm->OutStreamer->EmitIntValue(0, Size); + } + }, + [&](const MCSymbol *Base, const RangeSpan &RS) { + Asm->EmitLabelDifference(RS.getStart(), Base, Size); + Asm->EmitLabelDifference(RS.getEnd(), Base, Size); + }, + [&](const RangeSpan &RS) { + Asm->OutStreamer->EmitSymbolValue(RS.getStart(), Size); + Asm->OutStreamer->EmitSymbolValue(RS.getEnd(), Size); + }); // And terminate the list with two 0 values. Asm->OutStreamer->EmitIntValue(0, Size); Asm->OutStreamer->EmitIntValue(0, Size); Index: lib/DebugInfo/DWARF/DWARFDebugLoc.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFDebugLoc.cpp +++ lib/DebugInfo/DWARF/DWARFDebugLoc.cpp @@ -82,16 +82,23 @@ while ((Kind = static_cast( data.getU8(&Offset))) != dwarf::DW_LLE_end_of_list) { - if (Kind != dwarf::DW_LLE_startx_length) { + if (Kind != dwarf::DW_LLE_startx_length && + Kind != dwarf::DW_LLE_offset_pair && + Kind != dwarf::DW_LLE_base_addressx) { errs() << "error: dumping support for LLE of kind " << (int)Kind << " not implemented\n"; return; } - Entry E; + Loc.Entries.emplace_back(); + Entry &E = Loc.Entries.back(); - E.Start = data.getULEB128(&Offset); - E.Length = data.getU32(&Offset); + E.Kind = Kind; + E.First = data.getULEB128(&Offset); + if (Kind == dwarf::DW_LLE_base_addressx) + continue; + E.Second = Kind == dwarf::DW_LLE_offset_pair ? data.getULEB128(&Offset) + : data.getU32(&Offset); unsigned Bytes = data.getU16(&Offset); // A single location description describing the location of the object... @@ -99,8 +106,6 @@ Offset += Bytes; E.Loc.resize(str.size()); std::copy(str.begin(), str.end(), E.Loc.begin()); - - Loc.Entries.push_back(std::move(E)); } } } @@ -112,9 +117,18 @@ for (const Entry &E : L.Entries) { if (&E != L.Entries.begin()) OS.indent(Indent); - OS << "Beginning address index: " << E.Start << '\n'; - OS.indent(Indent) << " Length: " << E.Length << '\n'; - OS.indent(Indent) << " Location description: "; + if (E.Kind == dwarf::DW_LLE_base_addressx) { + OS << " Base address index: " << E.First << "\n\n"; + continue; + } + OS << (E.Kind == dwarf::DW_LLE_offset_pair ? " Starting offset: " + : "Starting address index: ") + << E.First << '\n'; + OS.indent(Indent) << (E.Kind == dwarf::DW_LLE_offset_pair + ? " Ending offset: " + : " Length: ") + << E.Second << '\n'; + OS.indent(Indent) << " Location description: "; for (unsigned char Loc : E.Loc) OS << format("%2.2x ", Loc); OS << "\n\n"; Index: lib/MC/MCObjectStreamer.cpp =================================================================== --- lib/MC/MCObjectStreamer.cpp +++ lib/MC/MCObjectStreamer.cpp @@ -56,6 +56,18 @@ PendingLabels.clear(); } +void MCObjectStreamer::emitULEB128AbsoluteSymbolDiff(const MCSymbol *Hi, + const MCSymbol *Lo) { + // If not assigned to the same (valid) fragment, fallback. + if (!Hi->getFragment() || Hi->getFragment() != Lo->getFragment() || + Hi->isVariable() || Lo->isVariable()) { + MCStreamer::emitULEB128AbsoluteSymbolDiff(Hi, Lo); + return; + } + + EmitULEB128IntValue(Hi->getOffset() - Lo->getOffset()); +} + void MCObjectStreamer::emitAbsoluteSymbolDiff(const MCSymbol *Hi, const MCSymbol *Lo, unsigned Size) { Index: lib/MC/MCStreamer.cpp =================================================================== --- lib/MC/MCStreamer.cpp +++ lib/MC/MCStreamer.cpp @@ -791,6 +791,24 @@ visitUsedExpr(*Inst.getOperand(i).getExpr()); } +void MCStreamer::emitULEB128AbsoluteSymbolDiff(const MCSymbol *Hi, + const MCSymbol *Lo) { + const MCExpr *Diff = + MCBinaryExpr::createSub(MCSymbolRefExpr::create(Hi, Context), + MCSymbolRefExpr::create(Lo, Context), Context); + + const MCAsmInfo *MAI = Context.getAsmInfo(); + if (!MAI->doesSetDirectiveSuppressReloc()) { + EmitULEB128Value(Diff); + return; + } + + // Otherwise, emit with .set (aka assignment). + MCSymbol *SetLabel = Context.createTempSymbol("set", true); + EmitAssignment(SetLabel, Diff); + EmitULEB128Value(MCSymbolRefExpr::create(SetLabel, getContext())); +} + void MCStreamer::emitAbsoluteSymbolDiff(const MCSymbol *Hi, const MCSymbol *Lo, unsigned Size) { // Get the Hi-Lo expression.