[llvm] 788e6ff - [DWARFLinker][DWARFv5] Add support for .debug_line_str table.
Alexey Lapshin via llvm-commits
llvm-commits at lists.llvm.org
Tue May 16 08:00:33 PDT 2023
Author: Alexey Lapshin
Date: 2023-05-16T16:56:14+02:00
New Revision: 788e6ff4e5e6414c6707e91e95829f1d7c76b1aa
URL: https://github.com/llvm/llvm-project/commit/788e6ff4e5e6414c6707e91e95829f1d7c76b1aa
DIFF: https://github.com/llvm/llvm-project/commit/788e6ff4e5e6414c6707e91e95829f1d7c76b1aa.diff
LOG: [DWARFLinker][DWARFv5] Add support for .debug_line_str table.
This patch adds support for DWARFv5 .debug_line_str table.
It replaces code generating line table. Instead of copying original
table and patching certain places this patch implements full line table
generation.
Differential Revision: https://reviews.llvm.org/D150554
Added:
llvm/test/tools/dsymutil/Inputs/dwarf5-linetable.o
llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-line-str.test
Modified:
llvm/include/llvm/DWARFLinker/DWARFLinker.h
llvm/include/llvm/DWARFLinker/DWARFStreamer.h
llvm/lib/DWARFLinker/DWARFLinker.cpp
llvm/lib/DWARFLinker/DWARFStreamer.cpp
llvm/test/tools/dsymutil/X86/dwarf5-linetable.test
Removed:
llvm/test/tools/dsymutil/Inputs/dwarf5.o
################################################################################
diff --git a/llvm/include/llvm/DWARFLinker/DWARFLinker.h b/llvm/include/llvm/DWARFLinker/DWARFLinker.h
index a090ea43f1d33..4d519479fab6e 100644
--- a/llvm/include/llvm/DWARFLinker/DWARFLinker.h
+++ b/llvm/include/llvm/DWARFLinker/DWARFLinker.h
@@ -25,7 +25,6 @@ class DWARFExpression;
class DWARFUnit;
class DataExtractor;
class DeclContextTree;
-struct MCDwarfLineTableParams;
template <typename T> class SmallVectorImpl;
enum class DwarfLinkerClient { Dsymutil, LLD, General };
@@ -100,9 +99,12 @@ class DwarfEmitter {
emitAbbrevs(const std::vector<std::unique_ptr<DIEAbbrev>> &Abbrevs,
unsigned DwarfVersion) = 0;
- /// Emit the string table described by \p Pool.
+ /// Emit the string table described by \p Pool into .debug_str table.
virtual void emitStrings(const NonRelocatableStringpool &Pool) = 0;
+ /// Emit the string table described by \p Pool into .debug_line_str table.
+ virtual void emitLineStrings(const NonRelocatableStringpool &Pool) = 0;
+
/// Emit DWARF debug names.
virtual void
emitDebugNames(AccelTable<DWARF5AccelTableStaticData> &Table) = 0;
@@ -154,16 +156,11 @@ class DwarfEmitter {
emitDwarfDebugArangesTable(const CompileUnit &Unit,
const AddressRanges &LinkedRanges) = 0;
- /// Copy the .debug_line over to the updated binary while unobfuscating the
- /// file names and directories.
- virtual void translateLineTable(DataExtractor LineData, uint64_t Offset) = 0;
-
- /// Emit the line table described in \p Rows into the .debug_line section.
- virtual void emitLineTableForUnit(MCDwarfLineTableParams Params,
- StringRef PrologueBytes,
- unsigned MinInstLength,
- std::vector<DWARFDebugLine::Row> &Rows,
- unsigned AdddressSize) = 0;
+ /// Emit specified \p LineTable into .debug_line table.
+ virtual void emitLineTableForUnit(const DWARFDebugLine::LineTable &LineTable,
+ const CompileUnit &Unit,
+ OffsetsStringPool &DebugStrPool,
+ OffsetsStringPool &DebugLineStrPool) = 0;
/// Emit the .debug_pubnames contribution for \p Unit.
virtual void emitPubNamesForUnit(const CompileUnit &Unit) = 0;
@@ -559,7 +556,8 @@ class DWARFLinker {
/// Clone specified Clang module unit \p Unit.
Error cloneModuleUnit(LinkContext &Context, RefModuleUnit &Unit,
DeclContextTree &ODRContexts,
- OffsetsStringPool &OffsetsStringPool,
+ OffsetsStringPool &DebugStrPool,
+ OffsetsStringPool &DebugLineStrPool,
unsigned Indent = 0);
/// Mark the passed DIE as well as all the ones it depends on as kept.
@@ -605,6 +603,8 @@ class DWARFLinker {
DWARFLinker &Linker;
DwarfEmitter *Emitter;
DWARFFile &ObjFile;
+ OffsetsStringPool &DebugStrPool;
+ OffsetsStringPool &DebugLineStrPool;
/// Allocator used for all the DIEValue objects.
BumpPtrAllocator &DIEAlloc;
@@ -621,8 +621,10 @@ class DWARFLinker {
DIECloner(DWARFLinker &Linker, DwarfEmitter *Emitter, DWARFFile &ObjFile,
BumpPtrAllocator &DIEAlloc,
std::vector<std::unique_ptr<CompileUnit>> &CompileUnits,
- bool Update)
+ bool Update, OffsetsStringPool &DebugStrPool,
+ OffsetsStringPool &DebugLineStrPool)
: Linker(Linker), Emitter(Emitter), ObjFile(ObjFile),
+ DebugStrPool(DebugStrPool), DebugLineStrPool(DebugLineStrPool),
DIEAlloc(DIEAlloc), CompileUnits(CompileUnits), Update(Update) {}
/// Recursively clone \p InputDIE into an tree of DIE objects
@@ -637,17 +639,14 @@ class DWARFLinker {
/// \param Die the output DIE to use, pass NULL to create one.
/// \returns the root of the cloned tree or null if nothing was selected.
DIE *cloneDIE(const DWARFDie &InputDIE, const DWARFFile &File,
- CompileUnit &U, OffsetsStringPool &StringPool,
- int64_t PCOffset, uint32_t OutOffset, unsigned Flags,
- bool IsLittleEndian, DIE *Die = nullptr);
+ CompileUnit &U, int64_t PCOffset, uint32_t OutOffset,
+ unsigned Flags, bool IsLittleEndian, DIE *Die = nullptr);
/// Construct the output DIE tree by cloning the DIEs we
/// chose to keep above. If there are no valid relocs, then there's
/// nothing to clone/emit.
uint64_t cloneAllCompileUnits(DWARFContext &DwarfContext,
- const DWARFFile &File,
- OffsetsStringPool &StringPool,
- bool IsLittleEndian);
+ const DWARFFile &File, bool IsLittleEndian);
private:
using AttributeSpec = DWARFAbbreviationDeclaration::AttributeSpec;
@@ -680,7 +679,6 @@ class DWARFLinker {
/// Helper for cloneDIE.
unsigned cloneAttribute(DIE &Die, const DWARFDie &InputDIE,
const DWARFFile &File, CompileUnit &U,
- OffsetsStringPool &StringPool,
const DWARFFormValue &Val,
const AttributeSpec AttrSpec, unsigned AttrSize,
AttributesInfo &AttrInfo, bool IsLittleEndian);
@@ -690,7 +688,6 @@ class DWARFLinker {
/// \returns the size of the new attribute.
unsigned cloneStringAttribute(DIE &Die, AttributeSpec AttrSpec,
const DWARFFormValue &Val, const DWARFUnit &U,
- OffsetsStringPool &StringPool,
AttributesInfo &Info);
/// Clone an attribute referencing another DIE and add
@@ -750,6 +747,11 @@ class DWARFLinker {
OffsetsStringPool &StringPool, bool SkipPubSection);
void rememberUnitForMacroOffset(CompileUnit &Unit);
+
+ /// Clone and emit the line table for the specified \p Unit.
+ /// Translate directories and file names if necessary.
+ /// Relocate address ranges.
+ void generateLineTableForUnit(CompileUnit &Unit);
};
/// Assign an abbreviation number to \p Abbrev
@@ -767,12 +769,6 @@ class DWARFLinker {
void generateUnitLocations(CompileUnit &Unit, const DWARFFile &File,
ExpressionHandlerRef ExprHandler) const;
- /// Extract the line tables from the original dwarf, extract the relevant
- /// parts according to the linked function ranges and emit the result in the
- /// .debug_line section.
- void patchLineTableForUnit(CompileUnit &Unit, DWARFContext &OrigDwarf,
- const DWARFFile &File);
-
/// Emit the accelerator entries for \p Unit.
void emitAcceleratorEntriesForUnit(CompileUnit &Unit);
diff --git a/llvm/include/llvm/DWARFLinker/DWARFStreamer.h b/llvm/include/llvm/DWARFLinker/DWARFStreamer.h
index c96dd4007c23f..f7dbdd2196a61 100644
--- a/llvm/include/llvm/DWARFLinker/DWARFStreamer.h
+++ b/llvm/include/llvm/DWARFLinker/DWARFStreamer.h
@@ -82,9 +82,12 @@ class DwarfStreamer : public DwarfEmitter {
/// Emit contents of section SecName From Obj.
void emitSectionContents(StringRef SecData, StringRef SecName) override;
- /// Emit the string table described by \p Pool.
+ /// Emit the string table described by \p Pool into .debug_str table.
void emitStrings(const NonRelocatableStringpool &Pool) override;
+ /// Emit the string table described by \p Pool into .debug_line_str table.
+ void emitLineStrings(const NonRelocatableStringpool &Pool) override;
+
/// Emit the swift_ast section stored in \p Buffer.
void emitSwiftAST(StringRef Buffer);
@@ -128,15 +131,11 @@ class DwarfStreamer : public DwarfEmitter {
return RngListsSectionSize;
}
- /// Emit the line table described in \p Rows into the debug_line section.
- void emitLineTableForUnit(MCDwarfLineTableParams Params,
- StringRef PrologueBytes, unsigned MinInstLength,
- std::vector<DWARFDebugLine::Row> &Rows,
- unsigned AdddressSize) override;
-
- /// Copy the debug_line over to the updated binary while unobfuscating the
- /// file names and directories.
- void translateLineTable(DataExtractor LineData, uint64_t Offset) override;
+ /// Emit .debug_line table entry for specified \p LineTable
+ void emitLineTableForUnit(const DWARFDebugLine::LineTable &LineTable,
+ const CompileUnit &Unit,
+ OffsetsStringPool &DebugStrPool,
+ OffsetsStringPool &DebugLineStrPool) override;
uint64_t getLineSectionSize() const override { return LineSectionSize; }
@@ -231,6 +230,32 @@ class DwarfStreamer : public DwarfEmitter {
const DWARFLocationExpressionsVector &LinkedLocationExpression,
PatchLocation Patch);
+ /// \defgroup Line table emission
+ /// @{
+ void emitLineTablePrologue(const DWARFDebugLine::Prologue &P,
+ OffsetsStringPool &DebugStrPool,
+ OffsetsStringPool &DebugLineStrPool);
+ void emitLineTableString(const DWARFDebugLine::Prologue &P,
+ const DWARFFormValue &String,
+ OffsetsStringPool &DebugStrPool,
+ OffsetsStringPool &DebugLineStrPool);
+ void emitLineTableProloguePayload(const DWARFDebugLine::Prologue &P,
+ OffsetsStringPool &DebugStrPool,
+ OffsetsStringPool &DebugLineStrPool);
+ void emitLineTablePrologueV2IncludeAndFileTable(
+ const DWARFDebugLine::Prologue &P, OffsetsStringPool &DebugStrPool,
+ OffsetsStringPool &DebugLineStrPool);
+ void emitLineTablePrologueV5IncludeAndFileTable(
+ const DWARFDebugLine::Prologue &P, OffsetsStringPool &DebugStrPool,
+ OffsetsStringPool &DebugLineStrPool);
+ void emitLineTableRows(const DWARFDebugLine::LineTable &LineTable,
+ MCSymbol *LineEndSym, unsigned AddressByteSize);
+ void emitIntOffset(uint64_t Offset, dwarf::DwarfFormat Format,
+ uint64_t &SectionSize);
+ void emitLabelDifference(const MCSymbol *Hi, const MCSymbol *Lo,
+ dwarf::DwarfFormat Format, uint64_t &SectionSize);
+ /// @}
+
/// \defgroup MCObjects MC layer objects constructed by the streamer
/// @{
std::unique_ptr<MCRegisterInfo> MRI;
diff --git a/llvm/lib/DWARFLinker/DWARFLinker.cpp b/llvm/lib/DWARFLinker/DWARFLinker.cpp
index 3c6495a12a9bb..3307f5384158f 100644
--- a/llvm/lib/DWARFLinker/DWARFLinker.cpp
+++ b/llvm/lib/DWARFLinker/DWARFLinker.cpp
@@ -948,24 +948,33 @@ void DWARFLinker::assignAbbrev(DIEAbbrev &Abbrev) {
}
}
-unsigned DWARFLinker::DIECloner::cloneStringAttribute(
- DIE &Die, AttributeSpec AttrSpec, const DWARFFormValue &Val,
- const DWARFUnit &, OffsetsStringPool &StringPool, AttributesInfo &Info) {
+unsigned DWARFLinker::DIECloner::cloneStringAttribute(DIE &Die,
+ AttributeSpec AttrSpec,
+ const DWARFFormValue &Val,
+ const DWARFUnit &,
+ AttributesInfo &Info) {
std::optional<const char *> String = dwarf::toString(Val);
if (!String)
return 0;
- // Switch everything to out of line strings.
- auto StringEntry = StringPool.getEntry(*String);
+ DwarfStringPoolEntryRef StringEntry;
+ if (AttrSpec.Form == dwarf::DW_FORM_line_strp) {
+ StringEntry = DebugLineStrPool.getEntry(*String);
+ } else {
+ StringEntry = DebugStrPool.getEntry(*String);
+
+ // Update attributes info.
+ 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;
- // Update attributes info.
- 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;
+ // Switch everything to out of line strings.
+ AttrSpec.Form = dwarf::DW_FORM_strp;
+ }
- Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr), dwarf::DW_FORM_strp,
+ Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr), AttrSpec.Form,
DIEInteger(StringEntry.getOffset()));
return 4;
@@ -1373,20 +1382,20 @@ unsigned DWARFLinker::DIECloner::cloneScalarAttribute(
/// \returns the size of the cloned attribute.
unsigned DWARFLinker::DIECloner::cloneAttribute(
DIE &Die, const DWARFDie &InputDIE, const DWARFFile &File,
- CompileUnit &Unit, OffsetsStringPool &StringPool, const DWARFFormValue &Val,
- const AttributeSpec AttrSpec, unsigned AttrSize, AttributesInfo &Info,
- bool IsLittleEndian) {
+ CompileUnit &Unit, const DWARFFormValue &Val, const AttributeSpec AttrSpec,
+ unsigned AttrSize, AttributesInfo &Info, bool IsLittleEndian) {
const DWARFUnit &U = Unit.getOrigUnit();
switch (AttrSpec.Form) {
case dwarf::DW_FORM_strp:
+ case dwarf::DW_FORM_line_strp:
case dwarf::DW_FORM_string:
case dwarf::DW_FORM_strx:
case dwarf::DW_FORM_strx1:
case dwarf::DW_FORM_strx2:
case dwarf::DW_FORM_strx3:
case dwarf::DW_FORM_strx4:
- return cloneStringAttribute(Die, AttrSpec, Val, U, StringPool, Info);
+ return cloneStringAttribute(Die, AttrSpec, Val, U, Info);
case dwarf::DW_FORM_ref_addr:
case dwarf::DW_FORM_ref1:
case dwarf::DW_FORM_ref2:
@@ -1524,7 +1533,6 @@ static bool shouldSkipAttribute(
DIE *DWARFLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE,
const DWARFFile &File, CompileUnit &Unit,
- OffsetsStringPool &StringPool,
int64_t PCOffset, uint32_t OutOffset,
unsigned Flags, bool IsLittleEndian,
DIE *Die) {
@@ -1614,8 +1622,8 @@ DIE *DWARFLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE,
Val.extractValue(Data, &Offset, U.getFormParams(), &U);
AttrSize = Offset - AttrSize;
- OutOffset += cloneAttribute(*Die, InputDIE, File, Unit, StringPool, Val,
- AttrSpec, AttrSize, AttrInfo, IsLittleEndian);
+ OutOffset += cloneAttribute(*Die, InputDIE, File, Unit, Val, AttrSpec,
+ AttrSize, AttrInfo, IsLittleEndian);
}
// Look for accelerator entries.
@@ -1625,7 +1633,7 @@ DIE *DWARFLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE,
// accelerator tables too. For now stick with dsymutil's behavior.
if ((Info.InDebugMap || AttrInfo.HasLowPc || AttrInfo.HasRanges) &&
Tag != dwarf::DW_TAG_compile_unit &&
- getDIENames(InputDIE, AttrInfo, StringPool,
+ getDIENames(InputDIE, AttrInfo, DebugStrPool,
Tag != dwarf::DW_TAG_inlined_subroutine)) {
if (AttrInfo.MangledName && AttrInfo.MangledName != AttrInfo.Name)
Unit.addNameAccelerator(Die, AttrInfo.MangledName,
@@ -1638,17 +1646,17 @@ DIE *DWARFLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE,
Tag == dwarf::DW_TAG_inlined_subroutine);
}
if (AttrInfo.Name && isObjCSelector(AttrInfo.Name.getString()))
- addObjCAccelerator(Unit, Die, AttrInfo.Name, StringPool,
+ addObjCAccelerator(Unit, Die, AttrInfo.Name, DebugStrPool,
/* SkipPubSection =*/true);
} else if (Tag == dwarf::DW_TAG_namespace) {
if (!AttrInfo.Name)
- AttrInfo.Name = StringPool.getEntry("(anonymous namespace)");
+ AttrInfo.Name = DebugStrPool.getEntry("(anonymous namespace)");
Unit.addNamespaceAccelerator(Die, AttrInfo.Name);
} else if (Tag == dwarf::DW_TAG_imported_declaration && AttrInfo.Name) {
Unit.addNamespaceAccelerator(Die, AttrInfo.Name);
} else if (isTypeTag(Tag) && !AttrInfo.IsDeclaration &&
- getDIENames(InputDIE, AttrInfo, StringPool) && AttrInfo.Name &&
+ getDIENames(InputDIE, AttrInfo, DebugStrPool) && AttrInfo.Name &&
AttrInfo.Name.getString()[0]) {
uint32_t Hash = hashFullyQualifiedName(InputDIE, Unit, File);
uint64_t RuntimeLang =
@@ -1691,8 +1699,8 @@ DIE *DWARFLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE,
// Recursively clone children.
for (auto Child : InputDIE.children()) {
- if (DIE *Clone = cloneDIE(Child, File, Unit, StringPool, PCOffset,
- OutOffset, Flags, IsLittleEndian)) {
+ if (DIE *Clone = cloneDIE(Child, File, Unit, PCOffset, OutOffset, Flags,
+ IsLittleEndian)) {
Die->addChild(Clone);
OutOffset = Clone->getOffset() + Clone->getSize();
}
@@ -1850,7 +1858,7 @@ static void insertLineSequence(std::vector<DWARFDebugLine::Row> &Seq,
// FIXME: this only removes the unneeded end_sequence if the
// sequences have been inserted in order. Using a global sort like
- // described in patchLineTableForUnit() and delaying the end_sequene
+ // described in generateLineTableForUnit() and delaying the end_sequene
// elimination to emitLineTableForUnit() we can get rid of all of them.
if (InsertPoint != Rows.end() && InsertPoint->Address == Front &&
InsertPoint->EndSequence) {
@@ -1873,142 +1881,6 @@ static void patchStmtList(DIE &Die, DIEInteger Offset) {
llvm_unreachable("Didn't find DW_AT_stmt_list in cloned DIE!");
}
-/// Extract the line table for \p Unit from \p OrigDwarf, and
-/// recreate a relocated version of these for the address ranges that
-/// are present in the binary.
-void DWARFLinker::patchLineTableForUnit(CompileUnit &Unit,
- DWARFContext &OrigDwarf,
- const DWARFFile &File) {
- DWARFDie CUDie = Unit.getOrigUnit().getUnitDIE();
- auto StmtList = dwarf::toSectionOffset(CUDie.find(dwarf::DW_AT_stmt_list));
- if (!StmtList)
- return;
-
- // Update the cloned DW_AT_stmt_list with the correct debug_line offset.
- if (auto *OutputDIE = Unit.getOutputUnitDIE())
- patchStmtList(*OutputDIE,
- DIEInteger(TheDwarfEmitter->getLineSectionSize()));
-
- RangesTy &Ranges = File.Addresses->getValidAddressRanges();
-
- // Parse the original line info for the unit.
- DWARFDebugLine::LineTable LineTable;
- uint64_t StmtOffset = *StmtList;
- DWARFDataExtractor LineExtractor(
- OrigDwarf.getDWARFObj(), OrigDwarf.getDWARFObj().getLineSection(),
- OrigDwarf.isLittleEndian(), Unit.getOrigUnit().getAddressByteSize());
- if (needToTranslateStrings())
- return TheDwarfEmitter->translateLineTable(LineExtractor, StmtOffset);
-
- if (Error Err =
- LineTable.parse(LineExtractor, &StmtOffset, OrigDwarf,
- &Unit.getOrigUnit(), OrigDwarf.getWarningHandler()))
- OrigDwarf.getWarningHandler()(std::move(Err));
-
- // This vector is the output line table.
- std::vector<DWARFDebugLine::Row> NewRows;
- NewRows.reserve(LineTable.Rows.size());
-
- // Current sequence of rows being extracted, before being inserted
- // in NewRows.
- std::vector<DWARFDebugLine::Row> Seq;
- const auto &FunctionRanges = Unit.getFunctionRanges();
- std::optional<AddressRangeValuePair> CurrRange;
-
- // FIXME: This logic is meant to generate exactly the same output as
- // Darwin's classic dsymutil. There is a nicer way to implement this
- // by simply putting all the relocated line info in NewRows and simply
- // sorting NewRows before passing it to emitLineTableForUnit. This
- // should be correct as sequences for a function should stay
- // together in the sorted output. There are a few corner cases that
- // look suspicious though, and that required to implement the logic
- // this way. Revisit that once initial validation is finished.
-
- // Iterate over the object file line info and extract the sequences
- // that correspond to linked functions.
- for (auto &Row : LineTable.Rows) {
- // Check whether we stepped out of the range. The range is
- // half-open, but consider accept the end address of the range if
- // 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 || !CurrRange->Range.contains(Row.Address.Address) ||
- (Row.Address.Address == CurrRange->Range.end() && !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 ? CurrRange->Range.end() + CurrRange->Value : -1ULL;
- CurrRange = FunctionRanges.getRangeThatContains(Row.Address.Address);
- if (!CurrRange) {
- if (StopAddress != -1ULL) {
- // 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.
- if (std::optional<AddressRangeValuePair> Range =
- Ranges.getRangeThatContains(Row.Address.Address))
- StopAddress = Row.Address.Address + (*Range).Value;
- }
- }
- if (StopAddress != -1ULL && !Seq.empty()) {
- // Insert end sequence row with the computed end address, but
- // the same line as the previous one.
- auto NextLine = Seq.back();
- NextLine.Address.Address = StopAddress;
- NextLine.EndSequence = 1;
- NextLine.PrologueEnd = 0;
- NextLine.BasicBlock = 0;
- NextLine.EpilogueBegin = 0;
- Seq.push_back(NextLine);
- insertLineSequence(Seq, NewRows);
- }
-
- if (!CurrRange)
- continue;
- }
-
- // Ignore empty sequences.
- if (Row.EndSequence && Seq.empty())
- continue;
-
- // Relocate row address and add it to the current sequence.
- Row.Address.Address += CurrRange->Value;
- Seq.emplace_back(Row);
-
- if (Row.EndSequence)
- insertLineSequence(Seq, NewRows);
- }
-
- // Finished extracting, now emit the line tables.
- // FIXME: LLVM hard-codes its prologue values. We just copy the
- // prologue over and that works because we act as both producer and
- // consumer. It would be nicer to have a real configurable line
- // table emitter.
- if (LineTable.Prologue.getVersion() < 2 ||
- LineTable.Prologue.getVersion() > 5 ||
- LineTable.Prologue.DefaultIsStmt != DWARF2_LINE_DEFAULT_IS_STMT ||
- LineTable.Prologue.OpcodeBase > 13)
- reportWarning("line table parameters mismatch. Cannot emit.", File);
- else {
- uint32_t PrologueEnd = *StmtList + 10 + LineTable.Prologue.PrologueLength;
- // DWARF v5 has an extra 2 bytes of information before the header_length
- // field.
- if (LineTable.Prologue.getVersion() == 5)
- PrologueEnd += 2;
- StringRef LineData = OrigDwarf.getDWARFObj().getLineSection().Data;
- MCDwarfLineTableParams Params;
- Params.DWARF2LineOpcodeBase = LineTable.Prologue.OpcodeBase;
- Params.DWARF2LineBase = LineTable.Prologue.LineBase;
- Params.DWARF2LineRange = LineTable.Prologue.LineRange;
- TheDwarfEmitter->emitLineTableForUnit(
- Params, LineData.slice(*StmtList + 4, PrologueEnd),
- LineTable.Prologue.MinInstLength, NewRows,
- Unit.getOrigUnit().getAddressByteSize());
- }
-}
-
void DWARFLinker::DIECloner::rememberUnitForMacroOffset(CompileUnit &Unit) {
DWARFUnit &OrigUnit = Unit.getOrigUnit();
DWARFDie OrigUnitDie = OrigUnit.getUnitDIE();
@@ -2026,6 +1898,123 @@ void DWARFLinker::DIECloner::rememberUnitForMacroOffset(CompileUnit &Unit) {
}
}
+void DWARFLinker::DIECloner::generateLineTableForUnit(CompileUnit &Unit) {
+ if (LLVM_UNLIKELY(Linker.Options.NoOutput))
+ return;
+
+ // Check whether DW_AT_stmt_list attribute is presented.
+ DWARFDie CUDie = Unit.getOrigUnit().getUnitDIE();
+ auto StmtList = dwarf::toSectionOffset(CUDie.find(dwarf::DW_AT_stmt_list));
+ if (!StmtList)
+ return;
+
+ // Update the cloned DW_AT_stmt_list with the correct debug_line offset.
+ if (auto *OutputDIE = Unit.getOutputUnitDIE())
+ patchStmtList(*OutputDIE, DIEInteger(Emitter->getLineSectionSize()));
+
+ if (const DWARFDebugLine::LineTable *LT =
+ ObjFile.Dwarf->getLineTableForUnit(&Unit.getOrigUnit())) {
+
+ DWARFDebugLine::LineTable LineTable;
+
+ // Set Line Table header.
+ LineTable.Prologue = LT->Prologue;
+
+ // Set Line Table Rows.
+ if (Linker.Options.Update) {
+ LineTable.Rows = LT->Rows;
+
+ LineTable.Sequences = LT->Sequences;
+ } else {
+ RangesTy &Ranges = ObjFile.Addresses->getValidAddressRanges();
+
+ // This vector is the output line table.
+ std::vector<DWARFDebugLine::Row> NewRows;
+ NewRows.reserve(LT->Rows.size());
+
+ // Current sequence of rows being extracted, before being inserted
+ // in NewRows.
+ std::vector<DWARFDebugLine::Row> Seq;
+
+ const auto &FunctionRanges = Unit.getFunctionRanges();
+ std::optional<AddressRangeValuePair> CurrRange;
+
+ // FIXME: This logic is meant to generate exactly the same output as
+ // Darwin's classic dsymutil. There is a nicer way to implement this
+ // by simply putting all the relocated line info in NewRows and simply
+ // sorting NewRows before passing it to emitLineTableForUnit. This
+ // should be correct as sequences for a function should stay
+ // together in the sorted output. There are a few corner cases that
+ // look suspicious though, and that required to implement the logic
+ // this way. Revisit that once initial validation is finished.
+
+ // Iterate over the object file line info and extract the sequences
+ // that correspond to linked functions.
+ for (DWARFDebugLine::Row Row : LT->Rows) {
+ // Check whether we stepped out of the range. The range is
+ // half-open, but consider accept the end address of the range if
+ // 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 || !CurrRange->Range.contains(Row.Address.Address) ||
+ (Row.Address.Address == CurrRange->Range.end() &&
+ !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 ? CurrRange->Range.end() + CurrRange->Value : -1ULL;
+ CurrRange = FunctionRanges.getRangeThatContains(Row.Address.Address);
+ if (!CurrRange) {
+ if (StopAddress != -1ULL) {
+ // 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.
+ if (std::optional<AddressRangeValuePair> Range =
+ Ranges.getRangeThatContains(Row.Address.Address))
+ StopAddress = Row.Address.Address + (*Range).Value;
+ }
+ }
+ if (StopAddress != -1ULL && !Seq.empty()) {
+ // Insert end sequence row with the computed end address, but
+ // the same line as the previous one.
+ auto NextLine = Seq.back();
+ NextLine.Address.Address = StopAddress;
+ NextLine.EndSequence = 1;
+ NextLine.PrologueEnd = 0;
+ NextLine.BasicBlock = 0;
+ NextLine.EpilogueBegin = 0;
+ Seq.push_back(NextLine);
+ insertLineSequence(Seq, NewRows);
+ }
+
+ if (!CurrRange)
+ continue;
+ }
+
+ // Ignore empty sequences.
+ if (Row.EndSequence && Seq.empty())
+ continue;
+
+ // Relocate row address and add it to the current sequence.
+ Row.Address.Address += CurrRange->Value;
+ Seq.emplace_back(Row);
+
+ if (Row.EndSequence)
+ insertLineSequence(Seq, NewRows);
+ }
+
+ LineTable.Rows = std::move(NewRows);
+ }
+
+ Emitter->emitLineTableForUnit(LineTable, Unit, DebugStrPool,
+ DebugLineStrPool);
+ } else
+ Linker.reportWarning("Cann't load line table.", ObjFile);
+}
+
void DWARFLinker::emitAcceleratorEntriesForUnit(CompileUnit &Unit) {
for (DwarfLinkerAccelTableKind AccelTableKind : Options.AccelTables) {
switch (AccelTableKind) {
@@ -2372,8 +2361,7 @@ Error DWARFLinker::loadClangModule(objFileLoader Loader, const DWARFDie &CUDie,
}
uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits(
- DWARFContext &DwarfContext, const DWARFFile &File,
- OffsetsStringPool &StringPool, bool IsLittleEndian) {
+ DWARFContext &DwarfContext, const DWARFFile &File, bool IsLittleEndian) {
uint64_t OutputDebugInfoSize =
Linker.Options.NoOutput ? 0 : Emitter->getDebugInfoSectionSize();
const uint64_t StartOutputDebugInfoSize = OutputDebugInfoSize;
@@ -2392,9 +2380,8 @@ uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits(
// already has a DIE inside of it.
CurrentUnit->createOutputDIE();
rememberUnitForMacroOffset(*CurrentUnit);
- cloneDIE(InputDIE, File, *CurrentUnit, StringPool, 0 /* PC offset */,
- UnitHeaderSize, 0, IsLittleEndian,
- CurrentUnit->getOutputUnitDIE());
+ cloneDIE(InputDIE, File, *CurrentUnit, 0 /* PC offset */, UnitHeaderSize,
+ 0, IsLittleEndian, CurrentUnit->getOutputUnitDIE());
}
OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset(DwarfVersion);
@@ -2402,9 +2389,7 @@ uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits(
if (!Linker.Options.NoOutput) {
assert(Emitter);
- if (LLVM_LIKELY(!Linker.Options.Update) ||
- Linker.needToTranslateStrings())
- Linker.patchLineTableForUnit(*CurrentUnit, DwarfContext, File);
+ generateLineTableForUnit(*CurrentUnit);
Linker.emitAcceleratorEntriesForUnit(*CurrentUnit);
@@ -2430,7 +2415,7 @@ uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits(
if (!Linker.Options.NoOutput) {
assert(Emitter);
// Emit macro tables.
- Emitter->emitMacroTables(File.Dwarf, UnitMacroMap, StringPool);
+ Emitter->emitMacroTables(File.Dwarf, UnitMacroMap, DebugStrPool);
// Emit all the compile unit's debug information.
for (auto &CurrentUnit : CompileUnits) {
@@ -2517,9 +2502,6 @@ bool DWARFLinker::emitPaperTrailWarnings(const DWARFFile &File,
}
void DWARFLinker::copyInvariantDebugSection(DWARFContext &Dwarf) {
- if (!needToTranslateStrings())
- TheDwarfEmitter->emitSectionContents(
- Dwarf.getDWARFObj().getLineSection().Data, "debug_line");
TheDwarfEmitter->emitSectionContents(Dwarf.getDWARFObj().getLocSection().Data,
"debug_loc");
TheDwarfEmitter->emitSectionContents(
@@ -2569,7 +2551,8 @@ Error DWARFLinker::link() {
// This Dwarf string pool which is used for emission. It must be used
// serially as the order of calling getStringOffset matters for
// reproducibility.
- OffsetsStringPool OffsetsStringPool(StringsTranslator, true);
+ OffsetsStringPool DebugStrPool(StringsTranslator, true);
+ OffsetsStringPool DebugLineStrPool(StringsTranslator, false);
// ODR Contexts for the optimize.
DeclContextTree ODRContexts;
@@ -2582,7 +2565,7 @@ Error DWARFLinker::link() {
outs() << "OBJECT FILE: " << OptContext.File.FileName << "\n";
}
- if (emitPaperTrailWarnings(OptContext.File, OffsetsStringPool))
+ if (emitPaperTrailWarnings(OptContext.File, DebugStrPool))
continue;
if (!OptContext.File.Dwarf)
@@ -2635,8 +2618,8 @@ Error DWARFLinker::link() {
}
for (auto &CU : OptContext.ModuleUnits) {
- if (Error Err =
- cloneModuleUnit(OptContext, CU, ODRContexts, OffsetsStringPool))
+ if (Error Err = cloneModuleUnit(OptContext, CU, ODRContexts, DebugStrPool,
+ DebugLineStrPool))
reportWarning(toString(std::move(Err)), CU.File);
}
}
@@ -2733,9 +2716,9 @@ Error DWARFLinker::link() {
getDebugInfoSize(*OptContext.File.Dwarf);
SizeByObject[OptContext.File.FileName].Output =
DIECloner(*this, TheDwarfEmitter, OptContext.File, DIEAlloc,
- OptContext.CompileUnits, Options.Update)
+ OptContext.CompileUnits, Options.Update, DebugStrPool,
+ DebugLineStrPool)
.cloneAllCompileUnits(*OptContext.File.Dwarf, OptContext.File,
- OffsetsStringPool,
OptContext.File.Dwarf->isLittleEndian());
}
if (!Options.NoOutput && !OptContext.CompileUnits.empty() &&
@@ -2753,7 +2736,8 @@ Error DWARFLinker::link() {
// Emit everything that's global.
if (!Options.NoOutput) {
TheDwarfEmitter->emitAbbrevs(Abbreviations, Options.TargetDWARFVersion);
- TheDwarfEmitter->emitStrings(OffsetsStringPool);
+ TheDwarfEmitter->emitStrings(DebugStrPool);
+ TheDwarfEmitter->emitLineStrings(DebugLineStrPool);
for (DwarfLinkerAccelTableKind TableKind : Options.AccelTables) {
switch (TableKind) {
case DwarfLinkerAccelTableKind::Apple:
@@ -2867,7 +2851,8 @@ Error DWARFLinker::link() {
Error DWARFLinker::cloneModuleUnit(LinkContext &Context, RefModuleUnit &Unit,
DeclContextTree &ODRContexts,
- OffsetsStringPool &OffsetsStringPool,
+ OffsetsStringPool &DebugStrPool,
+ OffsetsStringPool &DebugLineStrPool,
unsigned Indent) {
assert(Unit.Unit.get() != nullptr);
@@ -2894,8 +2879,8 @@ Error DWARFLinker::cloneModuleUnit(LinkContext &Context, RefModuleUnit &Unit,
CompileUnits.emplace_back(std::move(Unit.Unit));
assert(TheDwarfEmitter);
DIECloner(*this, TheDwarfEmitter, Unit.File, DIEAlloc, CompileUnits,
- Options.Update)
- .cloneAllCompileUnits(*Unit.File.Dwarf, Unit.File, OffsetsStringPool,
+ Options.Update, DebugStrPool, DebugLineStrPool)
+ .cloneAllCompileUnits(*Unit.File.Dwarf, Unit.File,
Unit.File.Dwarf->isLittleEndian());
return Error::success();
}
diff --git a/llvm/lib/DWARFLinker/DWARFStreamer.cpp b/llvm/lib/DWARFLinker/DWARFStreamer.cpp
index 249f145c41644..ebc765ed2b9fd 100644
--- a/llvm/lib/DWARFLinker/DWARFStreamer.cpp
+++ b/llvm/lib/DWARFLinker/DWARFStreamer.cpp
@@ -240,16 +240,18 @@ void DwarfStreamer::emitStrings(const NonRelocatableStringpool &Pool) {
// Emit a null terminator.
Asm->emitInt8(0);
}
+}
-#if 0
- if (DwarfVersion >= 5) {
- // Emit an empty string offset section.
- Asm->OutStreamer->switchSection(MOFI->getDwarfStrOffSection());
- Asm->emitDwarfUnitLength(4, "Length of String Offsets Set");
- Asm->emitInt16(DwarfVersion);
- Asm->emitInt16(0);
+/// Emit the debug_line_str section stored in \p Pool.
+void DwarfStreamer::emitLineStrings(const NonRelocatableStringpool &Pool) {
+ Asm->OutStreamer->switchSection(MOFI->getDwarfLineStrSection());
+ std::vector<DwarfStringPoolEntryRef> Entries = Pool.getEntriesForEmission();
+ for (auto Entry : Entries) {
+ // Emit the string itself.
+ Asm->OutStreamer->emitBytes(Entry.getString());
+ // Emit a null terminator.
+ Asm->emitInt8(0);
}
-#endif
}
void DwarfStreamer::emitDebugNames(
@@ -631,27 +633,225 @@ void DwarfStreamer::emitDwarfDebugLocListsTableFragment(
LocListsSectionSize += 1;
}
-void DwarfStreamer::emitLineTableForUnit(MCDwarfLineTableParams Params,
- StringRef PrologueBytes,
- unsigned MinInstLength,
- std::vector<DWARFDebugLine::Row> &Rows,
- unsigned PointerSize) {
+void DwarfStreamer::emitLineTableForUnit(
+ const DWARFDebugLine::LineTable &LineTable, const CompileUnit &Unit,
+ OffsetsStringPool &DebugStrPool, OffsetsStringPool &DebugLineStrPool) {
// Switch to the section where the table will be emitted into.
MS->switchSection(MC->getObjectFileInfo()->getDwarfLineSection());
+
MCSymbol *LineStartSym = MC->createTempSymbol();
MCSymbol *LineEndSym = MC->createTempSymbol();
- // The first 4 bytes is the total length of the information for this
- // compilation unit (not including these 4 bytes for the length).
- Asm->emitLabelDifference(LineEndSym, LineStartSym, 4);
+ // unit_length.
+ if (LineTable.Prologue.FormParams.Format == dwarf::DwarfFormat::DWARF64) {
+ MS->emitInt32(dwarf::DW_LENGTH_DWARF64);
+ LineSectionSize += 4;
+ }
+ emitLabelDifference(LineEndSym, LineStartSym,
+ LineTable.Prologue.FormParams.Format, LineSectionSize);
Asm->OutStreamer->emitLabel(LineStartSym);
- // Copy Prologue.
- MS->emitBytes(PrologueBytes);
- LineSectionSize += PrologueBytes.size() + 4;
+
+ // Emit prologue.
+ emitLineTablePrologue(LineTable.Prologue, DebugStrPool, DebugLineStrPool);
+
+ // Emit rows.
+ emitLineTableRows(LineTable, LineEndSym,
+ Unit.getOrigUnit().getAddressByteSize());
+}
+
+void DwarfStreamer::emitLineTablePrologue(const DWARFDebugLine::Prologue &P,
+ OffsetsStringPool &DebugStrPool,
+ OffsetsStringPool &DebugLineStrPool) {
+ MCSymbol *PrologueStartSym = MC->createTempSymbol();
+ MCSymbol *PrologueEndSym = MC->createTempSymbol();
+
+ // version (uhalf).
+ MS->emitInt16(P.getVersion());
+ LineSectionSize += 2;
+ if (P.getVersion() == 5) {
+ // address_size (ubyte).
+ MS->emitInt8(P.getAddressSize());
+ LineSectionSize += 1;
+
+ // segment_selector_size (ubyte).
+ MS->emitInt8(P.SegSelectorSize);
+ LineSectionSize += 1;
+ }
+
+ // header_length.
+ emitLabelDifference(PrologueEndSym, PrologueStartSym, P.FormParams.Format,
+ LineSectionSize);
+
+ Asm->OutStreamer->emitLabel(PrologueStartSym);
+ emitLineTableProloguePayload(P, DebugStrPool, DebugLineStrPool);
+ Asm->OutStreamer->emitLabel(PrologueEndSym);
+}
+
+void DwarfStreamer::emitLineTablePrologueV2IncludeAndFileTable(
+ const DWARFDebugLine::Prologue &P, OffsetsStringPool &DebugStrPool,
+ OffsetsStringPool &DebugLineStrPool) {
+ // include_directories (sequence of path names).
+ for (const DWARFFormValue &Include : P.IncludeDirectories)
+ emitLineTableString(P, Include, DebugStrPool, DebugLineStrPool);
+ // The last entry is followed by a single null byte.
+ MS->emitInt8(0);
+ LineSectionSize += 1;
+
+ // file_names (sequence of file entries).
+ for (const DWARFDebugLine::FileNameEntry &File : P.FileNames) {
+ // A null-terminated string containing the full or relative path name of a
+ // source file.
+ emitLineTableString(P, File.Name, DebugStrPool, DebugLineStrPool);
+ // An unsigned LEB128 number representing the directory index of a directory
+ // in the include_directories section.
+ LineSectionSize += MS->emitULEB128IntValue(File.DirIdx);
+ // An unsigned LEB128 number representing the (implementation-defined) time
+ // of last modification for the file, or 0 if not available.
+ LineSectionSize += MS->emitULEB128IntValue(File.ModTime);
+ // An unsigned LEB128 number representing the length in bytes of the file,
+ // or 0 if not available.
+ LineSectionSize += MS->emitULEB128IntValue(File.Length);
+ }
+ // The last entry is followed by a single null byte.
+ MS->emitInt8(0);
+ LineSectionSize += 1;
+}
+
+void DwarfStreamer::emitLineTablePrologueV5IncludeAndFileTable(
+ const DWARFDebugLine::Prologue &P, OffsetsStringPool &DebugStrPool,
+ OffsetsStringPool &DebugLineStrPool) {
+ if (P.IncludeDirectories.empty()) {
+ // directory_entry_format_count(ubyte).
+ MS->emitInt8(0);
+ LineSectionSize += 1;
+ } else {
+ // directory_entry_format_count(ubyte).
+ MS->emitInt8(1);
+ LineSectionSize += 1;
+
+ // directory_entry_format (sequence of ULEB128 pairs).
+ LineSectionSize += MS->emitULEB128IntValue(dwarf::DW_LNCT_path);
+ LineSectionSize +=
+ MS->emitULEB128IntValue(P.IncludeDirectories[0].getForm());
+ }
+
+ // directories_count (ULEB128).
+ LineSectionSize += MS->emitULEB128IntValue(P.IncludeDirectories.size());
+ // directories (sequence of directory names).
+ for (auto Include : P.IncludeDirectories)
+ emitLineTableString(P, Include, DebugStrPool, DebugLineStrPool);
+
+ if (P.FileNames.empty()) {
+ // file_name_entry_format_count (ubyte).
+ MS->emitInt8(0);
+ LineSectionSize += 1;
+ } else {
+ // file_name_entry_format_count (ubyte).
+ MS->emitInt8(2);
+ LineSectionSize += 1;
+
+ // file_name_entry_format (sequence of ULEB128 pairs).
+ LineSectionSize += MS->emitULEB128IntValue(dwarf::DW_LNCT_path);
+ LineSectionSize += MS->emitULEB128IntValue(P.FileNames[0].Name.getForm());
+
+ LineSectionSize += MS->emitULEB128IntValue(dwarf::DW_LNCT_directory_index);
+ LineSectionSize += MS->emitULEB128IntValue(dwarf::DW_FORM_data1);
+ }
+
+ // file_names_count (ULEB128).
+ LineSectionSize += MS->emitULEB128IntValue(P.FileNames.size());
+
+ // file_names (sequence of file name entries).
+ for (auto File : P.FileNames) {
+ emitLineTableString(P, File.Name, DebugStrPool, DebugLineStrPool);
+ MS->emitInt8(File.DirIdx);
+ LineSectionSize += 1;
+ }
+}
+
+void DwarfStreamer::emitLineTableString(const DWARFDebugLine::Prologue &P,
+ const DWARFFormValue &String,
+ OffsetsStringPool &DebugStrPool,
+ OffsetsStringPool &DebugLineStrPool) {
+ std::optional<const char *> StringVal = dwarf::toString(String);
+ if (!StringVal) {
+ warn("Cann't read string from line table.");
+ return;
+ }
+
+ switch (String.getForm()) {
+ case dwarf::DW_FORM_string: {
+ StringRef TranslatedString =
+ (Translator) ? Translator(*StringVal) : *StringVal;
+ Asm->OutStreamer->emitBytes(TranslatedString.data());
+ Asm->emitInt8(0);
+ LineSectionSize += TranslatedString.size() + 1;
+ } break;
+ case dwarf::DW_FORM_strp:
+ case dwarf::DW_FORM_line_strp: {
+ DwarfStringPoolEntryRef StringRef =
+ String.getForm() == dwarf::DW_FORM_strp
+ ? DebugStrPool.getEntry(*StringVal)
+ : DebugLineStrPool.getEntry(*StringVal);
+
+ emitIntOffset(StringRef.getOffset(), P.FormParams.Format, LineSectionSize);
+ } break;
+ default:
+ warn("Unsupported string form inside line table.");
+ break;
+ };
+}
+
+void DwarfStreamer::emitLineTableProloguePayload(
+ const DWARFDebugLine::Prologue &P, OffsetsStringPool &DebugStrPool,
+ OffsetsStringPool &DebugLineStrPool) {
+ // minimum_instruction_length (ubyte).
+ MS->emitInt8(P.MinInstLength);
+ LineSectionSize += 1;
+ if (P.FormParams.Version >= 4) {
+ // maximum_operations_per_instruction (ubyte).
+ MS->emitInt8(P.MaxOpsPerInst);
+ LineSectionSize += 1;
+ }
+ // default_is_stmt (ubyte).
+ MS->emitInt8(P.DefaultIsStmt);
+ LineSectionSize += 1;
+ // line_base (sbyte).
+ MS->emitInt8(P.LineBase);
+ LineSectionSize += 1;
+ // line_range (ubyte).
+ MS->emitInt8(P.LineRange);
+ LineSectionSize += 1;
+ // opcode_base (ubyte).
+ MS->emitInt8(P.OpcodeBase);
+ LineSectionSize += 1;
+
+ // standard_opcode_lengths (array of ubyte).
+ for (auto Length : P.StandardOpcodeLengths) {
+ MS->emitInt8(Length);
+ LineSectionSize += 1;
+ }
+
+ if (P.FormParams.Version < 5)
+ emitLineTablePrologueV2IncludeAndFileTable(P, DebugStrPool,
+ DebugLineStrPool);
+ else
+ emitLineTablePrologueV5IncludeAndFileTable(P, DebugStrPool,
+ DebugLineStrPool);
+}
+
+void DwarfStreamer::emitLineTableRows(
+ const DWARFDebugLine::LineTable &LineTable, MCSymbol *LineEndSym,
+ unsigned AddressByteSize) {
+
+ MCDwarfLineTableParams Params;
+ Params.DWARF2LineOpcodeBase = LineTable.Prologue.OpcodeBase;
+ Params.DWARF2LineBase = LineTable.Prologue.LineBase;
+ Params.DWARF2LineRange = LineTable.Prologue.LineRange;
SmallString<128> EncodingBuffer;
- if (Rows.empty()) {
+ if (LineTable.Rows.empty()) {
// We only have the dummy entry, dsymutil emits an entry with a 0
// address in that case.
MCDwarfLineAddr::encode(*MC, Params, std::numeric_limits<int64_t>::max(), 0,
@@ -672,17 +872,19 @@ void DwarfStreamer::emitLineTableForUnit(MCDwarfLineTableParams Params,
unsigned RowsSinceLastSequence = 0;
- for (DWARFDebugLine::Row &Row : Rows) {
+ for (const DWARFDebugLine::Row &Row : LineTable.Rows) {
int64_t AddressDelta;
if (Address == -1ULL) {
MS->emitIntValue(dwarf::DW_LNS_extended_op, 1);
- MS->emitULEB128IntValue(PointerSize + 1);
+ MS->emitULEB128IntValue(AddressByteSize + 1);
MS->emitIntValue(dwarf::DW_LNE_set_address, 1);
- MS->emitIntValue(Row.Address.Address, PointerSize);
- LineSectionSize += 2 + PointerSize + getULEB128Size(PointerSize + 1);
+ MS->emitIntValue(Row.Address.Address, AddressByteSize);
+ LineSectionSize +=
+ 2 + AddressByteSize + getULEB128Size(AddressByteSize + 1);
AddressDelta = 0;
} else {
- AddressDelta = (Row.Address.Address - Address) / MinInstLength;
+ AddressDelta =
+ (Row.Address.Address - Address) / LineTable.Prologue.MinInstLength;
}
// FIXME: code copied and transformed from MCDwarf.cpp::EmitDwarfLineTable.
@@ -734,7 +936,8 @@ void DwarfStreamer::emitLineTableForUnit(MCDwarfLineTableParams Params,
int64_t LineDelta = int64_t(Row.Line) - LastLine;
if (!Row.EndSequence) {
- MCDwarfLineAddr::encode(*MC, Params, LineDelta, AddressDelta, EncodingBuffer);
+ MCDwarfLineAddr::encode(*MC, Params, LineDelta, AddressDelta,
+ EncodingBuffer);
MS->emitBytes(EncodingBuffer);
LineSectionSize += EncodingBuffer.size();
EncodingBuffer.resize(0);
@@ -774,86 +977,19 @@ void DwarfStreamer::emitLineTableForUnit(MCDwarfLineTableParams Params,
MS->emitLabel(LineEndSym);
}
-/// Copy the debug_line over to the updated binary while unobfuscating the file
-/// names and directories.
-void DwarfStreamer::translateLineTable(DataExtractor Data, uint64_t Offset) {
- MS->switchSection(MC->getObjectFileInfo()->getDwarfLineSection());
- StringRef Contents = Data.getData();
-
- // We have to deconstruct the line table header, because it contains to
- // length fields that will need to be updated when we change the length of
- // the files and directories in there.
- unsigned UnitLength = Data.getU32(&Offset);
- uint64_t UnitEnd = Offset + UnitLength;
- MCSymbol *BeginLabel = MC->createTempSymbol();
- MCSymbol *EndLabel = MC->createTempSymbol();
- unsigned Version = Data.getU16(&Offset);
-
- if (Version > 5) {
- warn("Unsupported line table version: dropping contents and not "
- "unobfsucating line table.");
- return;
- }
-
- Asm->emitLabelDifference(EndLabel, BeginLabel, 4);
- Asm->OutStreamer->emitLabel(BeginLabel);
- Asm->emitInt16(Version);
- LineSectionSize += 6;
-
- MCSymbol *HeaderBeginLabel = MC->createTempSymbol();
- MCSymbol *HeaderEndLabel = MC->createTempSymbol();
- Asm->emitLabelDifference(HeaderEndLabel, HeaderBeginLabel, 4);
- Asm->OutStreamer->emitLabel(HeaderBeginLabel);
- Offset += 4;
- LineSectionSize += 4;
-
- uint64_t AfterHeaderLengthOffset = Offset;
- // Skip to the directories.
- Offset += (Version >= 4) ? 5 : 4;
- unsigned OpcodeBase = Data.getU8(&Offset);
- Offset += OpcodeBase - 1;
- Asm->OutStreamer->emitBytes(Contents.slice(AfterHeaderLengthOffset, Offset));
- LineSectionSize += Offset - AfterHeaderLengthOffset;
-
- // Offset points to the first directory.
- while (const char *Dir = Data.getCStr(&Offset)) {
- if (Dir[0] == 0)
- break;
-
- StringRef Translated = Translator(Dir);
- Asm->OutStreamer->emitBytes(Translated);
- Asm->emitInt8(0);
- LineSectionSize += Translated.size() + 1;
- }
- Asm->emitInt8(0);
- LineSectionSize += 1;
-
- while (const char *File = Data.getCStr(&Offset)) {
- if (File[0] == 0)
- break;
-
- StringRef Translated = Translator(File);
- Asm->OutStreamer->emitBytes(Translated);
- Asm->emitInt8(0);
- LineSectionSize += Translated.size() + 1;
-
- uint64_t OffsetBeforeLEBs = Offset;
- Asm->emitULEB128(Data.getULEB128(&Offset));
- Asm->emitULEB128(Data.getULEB128(&Offset));
- Asm->emitULEB128(Data.getULEB128(&Offset));
- LineSectionSize += Offset - OffsetBeforeLEBs;
- }
- Asm->emitInt8(0);
- LineSectionSize += 1;
-
- Asm->OutStreamer->emitLabel(HeaderEndLabel);
-
- // Copy the actual line table program over.
- Asm->OutStreamer->emitBytes(Contents.slice(Offset, UnitEnd));
- LineSectionSize += UnitEnd - Offset;
+void DwarfStreamer::emitIntOffset(uint64_t Offset, dwarf::DwarfFormat Format,
+ uint64_t &SectionSize) {
+ uint8_t Size = dwarf::getDwarfOffsetByteSize(Format);
+ MS->emitIntValue(Offset, Size);
+ SectionSize += Size;
+}
- Asm->OutStreamer->emitLabel(EndLabel);
- Offset = UnitEnd;
+void DwarfStreamer::emitLabelDifference(const MCSymbol *Hi, const MCSymbol *Lo,
+ dwarf::DwarfFormat Format,
+ uint64_t &SectionSize) {
+ uint8_t Size = dwarf::getDwarfOffsetByteSize(Format);
+ Asm->emitLabelDifference(Hi, Lo, Size);
+ SectionSize += Size;
}
/// Emit the pubnames or pubtypes section contribution for \p
diff --git a/llvm/test/tools/dsymutil/Inputs/dwarf5-linetable.o b/llvm/test/tools/dsymutil/Inputs/dwarf5-linetable.o
new file mode 100644
index 0000000000000..c4d504083e69e
Binary files /dev/null and b/llvm/test/tools/dsymutil/Inputs/dwarf5-linetable.o
diff er
diff --git a/llvm/test/tools/dsymutil/Inputs/dwarf5.o b/llvm/test/tools/dsymutil/Inputs/dwarf5.o
deleted file mode 100644
index a9767f6d93762..0000000000000
Binary files a/llvm/test/tools/dsymutil/Inputs/dwarf5.o and /dev/null
diff er
diff --git a/llvm/test/tools/dsymutil/X86/dwarf5-linetable.test b/llvm/test/tools/dsymutil/X86/dwarf5-linetable.test
index c4ee8bd4e1d1d..008e133ec6301 100644
--- a/llvm/test/tools/dsymutil/X86/dwarf5-linetable.test
+++ b/llvm/test/tools/dsymutil/X86/dwarf5-linetable.test
@@ -1,16 +1,16 @@
-# RUN: dsymutil -f -oso-prepend-path=%p/../Inputs/ -y %s -o - | llvm-dwarfdump -debug-line - | FileCheck %s
+# RUN: dsymutil -f -oso-prepend-path=%p/../Inputs/ -y %s -o - | llvm-dwarfdump -debug-line -debug-line-str --verbose - | FileCheck %s
# Source:
# int main() {
# return 0;
# }
# Compile with:
-# clang -gdwarf-5 dwarf5.c -c -o dwarf5.o
+# clang -gdwarf-5 dwarf5-linetable.c -c -o dwarf5-linetable.o
---
triple: 'x86_64-apple-darwin'
objects:
- - filename: dwarf5.o
+ - filename: dwarf5-linetable.o
timestamp: 1513021112
symbols:
- { sym: _main, objAddr: 0x0000000000000000, binAddr: 0x0000000100000FA0, size: 0x0000000F }
@@ -21,3 +21,9 @@ objects:
# CHECK: Line table prologue:
# CHECK: total_length:
# CHECK: version: 5
+# CHECK: include_directories[ 0] = .debug_line_str[0x00000000] = "/Users/buildslave/avl_test/test-line-str"
+# CHECK: file_names[ 0]:
+# CHECK: name: .debug_line_str[0x00000029] = "dwarf5-linetable.c"
+# CHECK: .debug_line_str contents:
+# CHECK: "/Users/buildslave/avl_test/test-line-str"
+# CHECK: "dwarf5-linetable.c"
diff --git a/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-line-str.test b/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-line-str.test
new file mode 100644
index 0000000000000..8f2957350484e
--- /dev/null
+++ b/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-line-str.test
@@ -0,0 +1,129 @@
+## Test that DWARFv5 DW_FORM_line_strp and corresponding .debug_line_str
+## table are correctly recognized and copied into the result.
+
+# RUN: yaml2obj %s -o %t.o
+
+# RUN: llvm-dwarfutil %t.o %t1
+# RUN: llvm-dwarfdump -verify %t1 | FileCheck %s --check-prefix VERIFY-CHECK
+# RUN: llvm-dwarfdump -a --verbose %t1 | FileCheck %s
+#
+# RUN: llvm-dwarfutil --no-garbage-collection %t.o %t1
+# RUN: llvm-dwarfdump -verify %t1 | FileCheck %s --check-prefix VERIFY-CHECK
+# RUN: llvm-dwarfdump -a --verbose %t1 | FileCheck %s
+#
+# RUN: llvm-dwarfutil --no-garbage-collection --build-accelerator=DWARF %t.o %t1
+# RUN: llvm-dwarfdump -verify %t1 | FileCheck %s --check-prefix VERIFY-CHECK
+# RUN: llvm-dwarfdump -a --verbose %t1 | FileCheck %s
+
+#VERIFY-CHECK: No errors.
+
+#CHECK: .debug_info
+#CHECK: DW_TAG_compile_unit
+#CHECK: DW_TAG_subprogram
+#CHECK: DW_AT_name [DW_FORM_line_strp] ( .debug_line_str[0x00000000] = "foo1")
+#CHECK: .debug_line
+#CHECK: include_directories[ 0] = .debug_line_str[0x00000000] = "foo1"
+#CHECK: include_directories[ 1] = .debug_line_str[0x00000000] = "foo1"
+#CHECK: file_names[ 0]:
+#CHECK: name: .debug_line_str[0x00000000] = "foo1"
+#CHECK: file_names[ 1]:
+#CHECK: name: .debug_line_str[0x00000000] = "foo1"
+#CHECK: .debug_line_str
+#CHECK: "foo1"
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ Address: 0x1130
+ Size: 0x60
+ - Name: .debug_line_str
+ Type: SHT_PROGBITS
+ Flags: [ ]
+ Content: "666f6f3100"
+ - Name: .debug_line
+ Type: SHT_PROGBITS
+ Flags: [ ]
+ Content: "2a00000005000801220000000102030405050102030401011f02000000000000000001011f020000000000000000"
+DWARF:
+ debug_abbrev:
+ - Table:
+ - Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_producer
+ Form: DW_FORM_string
+ - Attribute: DW_AT_language
+ Form: DW_FORM_data2
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_low_pc
+ Form: DW_FORM_addrx
+ - Attribute: DW_AT_high_pc
+ Form: DW_FORM_data8
+ - Attribute: DW_AT_addr_base
+ Form: DW_FORM_sec_offset
+ - Attribute: DW_AT_stmt_list
+ Form: DW_FORM_sec_offset
+ - Tag: DW_TAG_subprogram
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_line_strp
+ - Attribute: DW_AT_low_pc
+ Form: DW_FORM_addrx
+ - Attribute: DW_AT_high_pc
+ Form: DW_FORM_data8
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref4
+ - Tag: DW_TAG_base_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_variable
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_const_value
+ Form: DW_FORM_implicit_const
+ Value: 33
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref4
+ debug_info:
+ - Version: 5
+ UnitType: DW_UT_compile
+ Entries:
+ - AbbrCode: 1
+ Values:
+ - CStr: by_hand
+ - Value: 0x04
+ - CStr: CU1
+ - Value: 0x0
+ - Value: 0x10
+ - Value: 0x8
+ - Value: 0x0
+ - AbbrCode: 2
+ Values:
+ - Value: 0x0
+ - Value: 0x0
+ - Value: 0x10
+ - Value: 0x3f
+ - AbbrCode: 0
+ - AbbrCode: 3
+ Values:
+ - CStr: int
+ - AbbrCode: 0
+ debug_addr:
+ - Version: 5
+ AddressSize: 0x08
+ Entries:
+ - Address: 0x1130
+...
More information about the llvm-commits
mailing list