[llvm-branch-commits] [llvm] f1d5cbb - [dsymutil] Add preliminary support for DWARF 5.
Jonas Devlieghere via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Jan 12 22:00:18 PST 2021
Author: Jonas Devlieghere
Date: 2021-01-12T21:55:41-08:00
New Revision: f1d5cbbdee5526bc86eac0a5652b115d9bc158e5
URL: https://github.com/llvm/llvm-project/commit/f1d5cbbdee5526bc86eac0a5652b115d9bc158e5
DIFF: https://github.com/llvm/llvm-project/commit/f1d5cbbdee5526bc86eac0a5652b115d9bc158e5.diff
LOG: [dsymutil] Add preliminary support for DWARF 5.
Currently dsymutil will silently fail when processing binaries with
Dwarf 5 debug info. This patch adds rudimentary support for Dwarf 5 in
dsymutil.
- Recognize relocations in the debug_addr section.
- Recognize (a subset of) Dwarf 5 form values.
- Emits valid Dwarf 5 compile unit header chains.
To simplify things (and avoid having to emit indexed sections) I decided
to emit the relocated addresses directly in the debug info section.
- DW_FORM_strx gets relocated and rewritten to DW_FORM_strp
- DW_FORM_addrx gets relocated and rewritten to DW_FORM_addr
Obviously there's a lot of work left, but this should be a step in the
right direction.
rdar://62345491
Differential revision: https://reviews.llvm.org/D94323
Added:
llvm/test/tools/dsymutil/Inputs/private/tmp/dwarf5/dwarf5.o
llvm/test/tools/dsymutil/Inputs/private/tmp/dwarf5/dwarf5.out
llvm/test/tools/dsymutil/X86/dwarf5.test
Modified:
llvm/include/llvm/DWARFLinker/DWARFLinker.h
llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h
llvm/include/llvm/DWARFLinker/DWARFStreamer.h
llvm/lib/DWARFLinker/DWARFLinker.cpp
llvm/lib/DWARFLinker/DWARFLinkerCompileUnit.cpp
llvm/lib/DWARFLinker/DWARFStreamer.cpp
llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
llvm/tools/dsymutil/DwarfLinkerForBinary.h
Removed:
################################################################################
diff --git a/llvm/include/llvm/DWARFLinker/DWARFLinker.h b/llvm/include/llvm/DWARFLinker/DWARFLinker.h
index 97faad6b6180..7281966fc608 100644
--- a/llvm/include/llvm/DWARFLinker/DWARFLinker.h
+++ b/llvm/include/llvm/DWARFLinker/DWARFLinker.h
@@ -85,6 +85,9 @@ class AddressesMap {
virtual bool applyValidRelocs(MutableArrayRef<char> Data, uint64_t BaseOffset,
bool IsLittleEndian) = 0;
+ /// Relocate the given address offset if a valid relocation exists.
+ virtual llvm::Expected<uint64_t> relocateIndexedAddr(uint64_t Offset) = 0;
+
/// Returns all valid functions address ranges(i.e., those ranges
/// which points to sections with code).
virtual RangesTy &getValidAddressRanges() = 0;
@@ -183,7 +186,8 @@ class DwarfEmitter {
///
/// As a side effect, this also switches the current Dwarf version
/// of the MC layer to the one of U.getOrigUnit().
- virtual void emitCompileUnitHeader(CompileUnit &Unit) = 0;
+ virtual void emitCompileUnitHeader(CompileUnit &Unit,
+ unsigned DwarfVersion) = 0;
/// Recursively emit the DIE tree rooted at \p Die.
virtual void emitDIE(DIE &Die) = 0;
diff --git a/llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h b/llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h
index 549a0ce4e4b7..a6310bcb5df1 100644
--- a/llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h
+++ b/llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h
@@ -159,7 +159,7 @@ class CompileUnit {
/// Compute the end offset for this unit. Must be called after the CU's DIEs
/// have been cloned. \returns the next unit offset (which is also the
/// current debug_info section size).
- uint64_t computeNextUnitOffset();
+ uint64_t computeNextUnitOffset(uint16_t DwarfVersion);
/// Keep track of a forward reference to DIE \p Die in \p RefUnit by \p
/// Attr. The attribute should be fixed up later to point to the absolute
diff --git a/llvm/include/llvm/DWARFLinker/DWARFStreamer.h b/llvm/include/llvm/DWARFLinker/DWARFStreamer.h
index de58f5dedf24..7b0851159252 100644
--- a/llvm/include/llvm/DWARFLinker/DWARFStreamer.h
+++ b/llvm/include/llvm/DWARFLinker/DWARFStreamer.h
@@ -64,7 +64,7 @@ class DwarfStreamer : public DwarfEmitter {
///
/// As a side effect, this also switches the current Dwarf version
/// of the MC layer to the one of U.getOrigUnit().
- void emitCompileUnitHeader(CompileUnit &Unit) override;
+ void emitCompileUnitHeader(CompileUnit &Unit, unsigned DwarfVersion) override;
/// Recursively emit the DIE tree rooted at \p Die.
void emitDIE(DIE &Die) override;
diff --git a/llvm/lib/DWARFLinker/DWARFLinker.cpp b/llvm/lib/DWARFLinker/DWARFLinker.cpp
index 1595b31cb4f9..a09cbf9c95ea 100644
--- a/llvm/lib/DWARFLinker/DWARFLinker.cpp
+++ b/llvm/lib/DWARFLinker/DWARFLinker.cpp
@@ -419,7 +419,6 @@ void DWARFLinker::cleanupAuxiliarryData(LinkContext &Context) {
DIEAlloc.Reset();
}
-
/// Check if a variable describing DIE should be kept.
/// \returns updated TraversalFlags.
unsigned DWARFLinker::shouldKeepVariableDIE(AddressesMap &RelocMgr,
@@ -845,9 +844,12 @@ void DWARFLinker::assignAbbrev(DIEAbbrev &Abbrev) {
unsigned DWARFLinker::DIECloner::cloneStringAttribute(
DIE &Die, AttributeSpec AttrSpec, const DWARFFormValue &Val,
const DWARFUnit &U, OffsetsStringPool &StringPool, AttributesInfo &Info) {
+ Optional<const char *> String = Val.getAsCString();
+ if (!String)
+ return 0;
+
// Switch everything to out of line strings.
- const char *String = *Val.getAsCString();
- auto StringEntry = StringPool.getEntry(String);
+ auto StringEntry = StringPool.getEntry(*String);
// Update attributes info.
if (AttrSpec.Attr == dwarf::DW_AT_name)
@@ -1056,6 +1058,7 @@ unsigned DWARFLinker::DIECloner::cloneBlockAttribute(
unsigned DWARFLinker::DIECloner::cloneAddressAttribute(
DIE &Die, AttributeSpec AttrSpec, const DWARFFormValue &Val,
const CompileUnit &Unit, AttributesInfo &Info) {
+ dwarf::Form Form = AttrSpec.Form;
uint64_t Addr = *Val.getAsAddress();
if (LLVM_UNLIKELY(Linker.Options.Update)) {
@@ -1105,8 +1108,19 @@ unsigned DWARFLinker::DIECloner::cloneAddressAttribute(
Addr = (Info.OrigCallPc ? Info.OrigCallPc : Addr) + Info.PCOffset;
}
+ // If this is an indexed address emit the relocated address.
+ if (Form == dwarf::DW_FORM_addrx) {
+ if (llvm::Expected<uint64_t> RelocAddr =
+ ObjFile.Addresses->relocateIndexedAddr(Addr)) {
+ Addr = *RelocAddr;
+ Form = dwarf::DW_FORM_addr;
+ } else {
+ Linker.reportWarning(toString(RelocAddr.takeError()), ObjFile);
+ }
+ }
+
Die.addValue(DIEAlloc, static_cast<dwarf::Attribute>(AttrSpec.Attr),
- static_cast<dwarf::Form>(AttrSpec.Form), DIEInteger(Addr));
+ static_cast<dwarf::Form>(Form), DIEInteger(Addr));
return Unit.getOrigUnit().getAddressByteSize();
}
@@ -1188,6 +1202,11 @@ unsigned DWARFLinker::DIECloner::cloneAttribute(
switch (AttrSpec.Form) {
case dwarf::DW_FORM_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);
case dwarf::DW_FORM_ref_addr:
case dwarf::DW_FORM_ref1:
@@ -1204,6 +1223,7 @@ unsigned DWARFLinker::DIECloner::cloneAttribute(
return cloneBlockAttribute(Die, File, Unit, AttrSpec, Val, AttrSize,
IsLittleEndian);
case dwarf::DW_FORM_addr:
+ case dwarf::DW_FORM_addrx:
return cloneAddressAttribute(Die, AttrSpec, Val, Unit, Info);
case dwarf::DW_FORM_data1:
case dwarf::DW_FORM_data2:
@@ -1284,6 +1304,9 @@ shouldSkipAttribute(DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,
case dwarf::DW_AT_high_pc:
case dwarf::DW_AT_ranges:
return SkipPC;
+ case dwarf::DW_AT_str_offsets_base:
+ // FIXME: Use the string offset table with Dwarf 5.
+ return true;
case dwarf::DW_AT_location:
case dwarf::DW_AT_frame_base:
// FIXME: for some reason dsymutil-classic keeps the location attributes
@@ -2127,10 +2150,12 @@ uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits(
const uint64_t StartOutputDebugInfoSize = OutputDebugInfoSize;
for (auto &CurrentUnit : CompileUnits) {
+ const uint16_t DwarfVersion = CurrentUnit->getOrigUnit().getVersion();
+ const uint32_t UnitHeaderSize = DwarfVersion >= 5 ? 12 : 11;
auto InputDIE = CurrentUnit->getOrigUnit().getUnitDIE();
CurrentUnit->setStartOffset(OutputDebugInfoSize);
if (!InputDIE) {
- OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset();
+ OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset(DwarfVersion);
continue;
}
if (CurrentUnit->getInfo(0).Keep) {
@@ -2138,11 +2163,11 @@ uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits(
// already has a DIE inside of it.
CurrentUnit->createOutputDIE();
cloneDIE(InputDIE, File, *CurrentUnit, StringPool, 0 /* PC offset */,
- 11 /* Unit Header size */, 0, IsLittleEndian,
+ UnitHeaderSize, 0, IsLittleEndian,
CurrentUnit->getOutputUnitDIE());
}
- OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset();
+ OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset(DwarfVersion);
if (!Linker.Options.NoOutput) {
assert(Emitter);
@@ -2183,12 +2208,14 @@ uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits(
if (!CurrentUnit->getOutputUnitDIE())
continue;
+ unsigned DwarfVersion = CurrentUnit->getOrigUnit().getVersion();
+
assert(Emitter->getDebugInfoSectionSize() ==
CurrentUnit->getStartOffset());
- Emitter->emitCompileUnitHeader(*CurrentUnit);
+ Emitter->emitCompileUnitHeader(*CurrentUnit, DwarfVersion);
Emitter->emitDIE(*CurrentUnit->getOutputUnitDIE());
assert(Emitter->getDebugInfoSectionSize() ==
- CurrentUnit->computeNextUnitOffset());
+ CurrentUnit->computeNextUnitOffset(DwarfVersion));
}
}
diff --git a/llvm/lib/DWARFLinker/DWARFLinkerCompileUnit.cpp b/llvm/lib/DWARFLinker/DWARFLinkerCompileUnit.cpp
index f59a9023c690..925ab3d295c2 100644
--- a/llvm/lib/DWARFLinker/DWARFLinkerCompileUnit.cpp
+++ b/llvm/lib/DWARFLinker/DWARFLinkerCompileUnit.cpp
@@ -36,7 +36,7 @@ StringRef CompileUnit::getSysRoot() {
}
return SysRoot;
}
-
+
void CompileUnit::markEverythingAsKept() {
unsigned Idx = 0;
@@ -69,10 +69,10 @@ void CompileUnit::markEverythingAsKept() {
}
}
-uint64_t CompileUnit::computeNextUnitOffset() {
+uint64_t CompileUnit::computeNextUnitOffset(uint16_t DwarfVersion) {
NextUnitOffset = StartOffset;
if (NewUnit) {
- NextUnitOffset += 11 /* Header size */;
+ NextUnitOffset += (DwarfVersion >= 5) ? 12 : 11; // Header size
NextUnitOffset += NewUnit->getUnitDie().getSize();
}
return NextUnitOffset;
diff --git a/llvm/lib/DWARFLinker/DWARFStreamer.cpp b/llvm/lib/DWARFLinker/DWARFStreamer.cpp
index e900335f24b3..c0043ae39efe 100644
--- a/llvm/lib/DWARFLinker/DWARFStreamer.cpp
+++ b/llvm/lib/DWARFLinker/DWARFStreamer.cpp
@@ -121,16 +121,23 @@ void DwarfStreamer::switchToDebugInfoSection(unsigned DwarfVersion) {
/// Emit the compilation unit header for \p Unit in the debug_info section.
///
-/// A Dwarf section header is encoded as:
+/// A Dwarf 4 section header is encoded as:
/// uint32_t Unit length (omitting this field)
/// uint16_t Version
/// uint32_t Abbreviation table offset
/// uint8_t Address size
-///
/// Leading to a total of 11 bytes.
-void DwarfStreamer::emitCompileUnitHeader(CompileUnit &Unit) {
- unsigned Version = Unit.getOrigUnit().getVersion();
- switchToDebugInfoSection(Version);
+///
+/// A Dwarf 5 section header is encoded as:
+/// uint32_t Unit length (omitting this field)
+/// uint16_t Version
+/// uint8_t Unit type
+/// uint8_t Address size
+/// uint32_t Abbreviation table offset
+/// Leading to a total of 12 bytes.
+void DwarfStreamer::emitCompileUnitHeader(CompileUnit &Unit,
+ unsigned DwarfVersion) {
+ switchToDebugInfoSection(DwarfVersion);
/// The start of the unit within its section.
Unit.setLabelBegin(Asm->createTempSymbol("cu_begin"));
@@ -140,13 +147,22 @@ void DwarfStreamer::emitCompileUnitHeader(CompileUnit &Unit) {
// been computed in CompileUnit::computeOffsets(). Subtract 4 to that size to
// account for the length field.
Asm->emitInt32(Unit.getNextUnitOffset() - Unit.getStartOffset() - 4);
- Asm->emitInt16(Version);
-
- // We share one abbreviations table across all units so it's always at the
- // start of the section.
- Asm->emitInt32(0);
- Asm->emitInt8(Unit.getOrigUnit().getAddressByteSize());
- DebugInfoSectionSize += 11;
+ Asm->emitInt16(DwarfVersion);
+
+ if (DwarfVersion >= 5) {
+ Asm->emitInt8(dwarf::DW_UT_compile);
+ Asm->emitInt8(Unit.getOrigUnit().getAddressByteSize());
+ // We share one abbreviations table across all units so it's always at the
+ // start of the section.
+ Asm->emitInt32(0);
+ DebugInfoSectionSize += 12;
+ } else {
+ // We share one abbreviations table across all units so it's always at the
+ // start of the section.
+ Asm->emitInt32(0);
+ Asm->emitInt8(Unit.getOrigUnit().getAddressByteSize());
+ DebugInfoSectionSize += 11;
+ }
// Remember this CU.
EmittedUnits.push_back({Unit.getUniqueID(), Unit.getLabelBegin()});
@@ -211,6 +227,16 @@ 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);
+ }
+#endif
}
void DwarfStreamer::emitDebugNames(
diff --git a/llvm/test/tools/dsymutil/Inputs/private/tmp/dwarf5/dwarf5.o b/llvm/test/tools/dsymutil/Inputs/private/tmp/dwarf5/dwarf5.o
new file mode 100644
index 000000000000..1f47f6a225de
Binary files /dev/null and b/llvm/test/tools/dsymutil/Inputs/private/tmp/dwarf5/dwarf5.o
diff er
diff --git a/llvm/test/tools/dsymutil/Inputs/private/tmp/dwarf5/dwarf5.out b/llvm/test/tools/dsymutil/Inputs/private/tmp/dwarf5/dwarf5.out
new file mode 100755
index 000000000000..420395f0d15b
Binary files /dev/null and b/llvm/test/tools/dsymutil/Inputs/private/tmp/dwarf5/dwarf5.out
diff er
diff --git a/llvm/test/tools/dsymutil/X86/dwarf5.test b/llvm/test/tools/dsymutil/X86/dwarf5.test
new file mode 100644
index 000000000000..9d1ad3c4fdf4
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/dwarf5.test
@@ -0,0 +1,59 @@
+Test DWARF5 support in dsymutil. Currently this still generates an empty dSYM.
+
+$ cat dwarf5.c
+__attribute__ ((optnone))
+int foo() {
+ volatile i;
+ return i;
+}
+
+int main(int argc, char** argv) {
+ return foo();
+}
+
+$ clang -gdwarf-5 dwarf5.c -c -o dwarf5.o
+$ clang dwarf5.o -o dwarf5.out
+
+RUN: dsymutil -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/dwarf5/dwarf5.out -o %t.dSYM 2>&1 | FileCheck %s --allow-empty
+RUN: llvm-dwarfdump --verify %t.dSYM 2>&1 | FileCheck %s
+CHECK-NOT: error:
+
+RUN: llvm-dwarfdump %t.dSYM | FileCheck %s --check-prefix DWARF
+DWARF: DW_TAG_compile_unit
+DWARF: DW_AT_producer ("clang version 12.0.0
+DWARF: DW_AT_language (DW_LANG_C99)
+DWARF: DW_AT_name ("dwarf5.c")
+DWARF: DW_AT_LLVM_sysroot ("/")
+DWARF: DW_AT_stmt_list (0x00000000)
+DWARF: DW_AT_comp_dir ("/private/tmp/dwarf5")
+DWARF: DW_AT_low_pc (0x0000000100003f80)
+DWARF: DW_AT_high_pc (0x0000000100003fb1)
+DWARF: DW_AT_addr_base (0x00000008)
+DWARF: DW_TAG_subprogram
+DWARF: DW_AT_name ("foo")
+DWARF: DW_AT_decl_file (0x00)
+DWARF: DW_AT_decl_line (2)
+DWARF: DW_AT_type (0x0000006c "int")
+DWARF: DW_AT_external (true)
+DWARF: DW_TAG_variable
+DWARF: DW_AT_name ("i")
+DWARF: DW_AT_decl_file (0x00)
+DWARF: DW_AT_decl_line (3)
+DWARF: DW_AT_type (0x00000073 "volatile int")
+DWARF: DW_TAG_subprogram
+DWARF: DW_AT_name ("main")
+DWARF: DW_AT_decl_file (0x00)
+DWARF: DW_AT_decl_line (7)
+DWARF: DW_AT_prototyped (true)
+DWARF: DW_AT_type (0x0000006c "int")
+DWARF: DW_AT_external (true)
+DWARF: DW_TAG_formal_parameter
+DWARF: DW_AT_name ("argc")
+DWARF: DW_AT_decl_file (0x00)
+DWARF: DW_AT_decl_line (7)
+DWARF: DW_AT_type (0x0000006c "int")
+DWARF: DW_TAG_formal_parameter
+DWARF: DW_AT_name ("argv")
+DWARF: DW_AT_decl_file (0x00)
+DWARF: DW_AT_decl_line (7)
+DWARF: DW_AT_type (0x00000078 "char**")
diff --git a/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp b/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
index bd9529c4cd0f..29408e7c4946 100644
--- a/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
+++ b/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
@@ -489,7 +489,7 @@ static bool isMachOPairedReloc(uint64_t RelocType, uint64_t Arch) {
/// ValidRelocs array.
void DwarfLinkerForBinary::AddressManager::findValidRelocsMachO(
const object::SectionRef &Section, const object::MachOObjectFile &Obj,
- const DebugMapObject &DMO) {
+ const DebugMapObject &DMO, std::vector<ValidReloc> &ValidRelocs) {
Expected<StringRef> ContentsOrErr = Section.getContents();
if (!ContentsOrErr) {
consumeError(ContentsOrErr.takeError());
@@ -511,7 +511,8 @@ void DwarfLinkerForBinary::AddressManager::findValidRelocsMachO(
if (isMachOPairedReloc(Obj.getAnyRelocationType(MachOReloc),
Obj.getArch())) {
SkipNext = true;
- Linker.reportWarning("unsupported relocation in debug_info section.",
+ Linker.reportWarning("unsupported relocation in " + *Section.getName() +
+ " section.",
DMO.getObjectFilename());
continue;
}
@@ -519,7 +520,8 @@ void DwarfLinkerForBinary::AddressManager::findValidRelocsMachO(
unsigned RelocSize = 1 << Obj.getAnyRelocationLength(MachOReloc);
uint64_t Offset64 = Reloc.getOffset();
if ((RelocSize != 4 && RelocSize != 8)) {
- Linker.reportWarning("unsupported relocation in debug_info section.",
+ Linker.reportWarning("unsupported relocation in " + *Section.getName() +
+ " section.",
DMO.getObjectFilename());
continue;
}
@@ -564,33 +566,33 @@ void DwarfLinkerForBinary::AddressManager::findValidRelocsMachO(
/// appropriate handler depending on the object file format.
bool DwarfLinkerForBinary::AddressManager::findValidRelocs(
const object::SectionRef &Section, const object::ObjectFile &Obj,
- const DebugMapObject &DMO) {
+ const DebugMapObject &DMO, std::vector<ValidReloc> &Relocs) {
// Dispatch to the right handler depending on the file type.
if (auto *MachOObj = dyn_cast<object::MachOObjectFile>(&Obj))
- findValidRelocsMachO(Section, *MachOObj, DMO);
+ findValidRelocsMachO(Section, *MachOObj, DMO, Relocs);
else
Linker.reportWarning(Twine("unsupported object file type: ") +
Obj.getFileName(),
DMO.getObjectFilename());
- if (ValidRelocs.empty())
+ if (Relocs.empty())
return false;
// Sort the relocations by offset. We will walk the DIEs linearly in
// the file, this allows us to just keep an index in the relocation
// array that we advance during our walk, rather than resorting to
// some associative container. See DwarfLinkerForBinary::NextValidReloc.
- llvm::sort(ValidRelocs);
+ llvm::sort(Relocs);
return true;
}
-/// Look for relocations in the debug_info section that match
-/// entries in the debug map. These relocations will drive the Dwarf
-/// link by indicating which DIEs refer to symbols present in the
-/// linked binary.
+/// Look for relocations in the debug_info and debug_addr section that match
+/// entries in the debug map. These relocations will drive the Dwarf link by
+/// indicating which DIEs refer to symbols present in the linked binary.
/// \returns whether there are any valid relocations in the debug info.
-bool DwarfLinkerForBinary::AddressManager::findValidRelocsInDebugInfo(
+bool DwarfLinkerForBinary::AddressManager::findValidRelocsInDebugSections(
const object::ObjectFile &Obj, const DebugMapObject &DMO) {
// Find the debug_info section.
+ bool FoundValidRelocs = false;
for (const object::SectionRef &Section : Obj.sections()) {
StringRef SectionName;
if (Expected<StringRef> NameOrErr = Section.getName())
@@ -599,39 +601,44 @@ bool DwarfLinkerForBinary::AddressManager::findValidRelocsInDebugInfo(
consumeError(NameOrErr.takeError());
SectionName = SectionName.substr(SectionName.find_first_not_of("._"));
- if (SectionName != "debug_info")
- continue;
- return findValidRelocs(Section, Obj, DMO);
+ if (SectionName == "debug_info")
+ FoundValidRelocs |=
+ findValidRelocs(Section, Obj, DMO, ValidDebugInfoRelocs);
+ if (SectionName == "debug_addr")
+ FoundValidRelocs |=
+ findValidRelocs(Section, Obj, DMO, ValidDebugAddrRelocs);
}
- return false;
+ return FoundValidRelocs;
}
-/// Checks that there is a relocation against an actual debug
-/// map entry between \p StartOffset and \p NextOffset.
-///
-/// This function must be called with offsets in strictly ascending
-/// order because it never looks back at relocations it already 'went past'.
-/// \returns true and sets Info.InDebugMap if it is the case.
-bool DwarfLinkerForBinary::AddressManager::hasValidRelocationAt(
+bool DwarfLinkerForBinary::AddressManager::hasValidDebugAddrRelocationAt(
+ uint64_t Offset) {
+ auto It = std::lower_bound(ValidDebugAddrRelocs.begin(),
+ ValidDebugAddrRelocs.end(), Offset);
+ return It != ValidDebugAddrRelocs.end();
+}
+
+bool DwarfLinkerForBinary::AddressManager::hasValidDebugInfoRelocationAt(
uint64_t StartOffset, uint64_t EndOffset, CompileUnit::DIEInfo &Info) {
assert(NextValidReloc == 0 ||
- StartOffset > ValidRelocs[NextValidReloc - 1].Offset);
- if (NextValidReloc >= ValidRelocs.size())
+ StartOffset > ValidDebugInfoRelocs[NextValidReloc - 1].Offset);
+ if (NextValidReloc >= ValidDebugInfoRelocs.size())
return false;
- uint64_t RelocOffset = ValidRelocs[NextValidReloc].Offset;
+ uint64_t RelocOffset = ValidDebugInfoRelocs[NextValidReloc].Offset;
// We might need to skip some relocs that we didn't consider. For
// example the high_pc of a discarded DIE might contain a reloc that
// is in the list because it actually corresponds to the start of a
// function that is in the debug map.
- while (RelocOffset < StartOffset && NextValidReloc < ValidRelocs.size() - 1)
- RelocOffset = ValidRelocs[++NextValidReloc].Offset;
+ while (RelocOffset < StartOffset &&
+ NextValidReloc < ValidDebugInfoRelocs.size() - 1)
+ RelocOffset = ValidDebugInfoRelocs[++NextValidReloc].Offset;
if (RelocOffset < StartOffset || RelocOffset >= EndOffset)
return false;
- const auto &ValidReloc = ValidRelocs[NextValidReloc++];
+ const auto &ValidReloc = ValidDebugInfoRelocs[NextValidReloc++];
const auto &Mapping = ValidReloc.Mapping->getValue();
const uint64_t BinaryAddress = Mapping.BinaryAddress;
const uint64_t ObjectAddress = Mapping.ObjectAddress
@@ -673,7 +680,6 @@ getAttributeOffsets(const DWARFAbbreviationDeclaration *Abbrev, unsigned Idx,
bool DwarfLinkerForBinary::AddressManager::hasLiveMemoryLocation(
const DWARFDie &DIE, CompileUnit::DIEInfo &MyInfo) {
-
const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
Optional<uint32_t> LocationIdx =
@@ -686,7 +692,9 @@ bool DwarfLinkerForBinary::AddressManager::hasLiveMemoryLocation(
std::tie(LocationOffset, LocationEndOffset) =
getAttributeOffsets(Abbrev, *LocationIdx, Offset, *DIE.getDwarfUnit());
- return hasValidRelocationAt(LocationOffset, LocationEndOffset, MyInfo);
+ // FIXME: Support relocations debug_addr.
+ return hasValidDebugInfoRelocationAt(LocationOffset, LocationEndOffset,
+ MyInfo);
}
bool DwarfLinkerForBinary::AddressManager::hasLiveAddressRange(
@@ -697,12 +705,22 @@ bool DwarfLinkerForBinary::AddressManager::hasLiveAddressRange(
if (!LowPcIdx)
return false;
- uint64_t Offset = DIE.getOffset() + getULEB128Size(Abbrev->getCode());
- uint64_t LowPcOffset, LowPcEndOffset;
- std::tie(LowPcOffset, LowPcEndOffset) =
- getAttributeOffsets(Abbrev, *LowPcIdx, Offset, *DIE.getDwarfUnit());
+ dwarf::Form Form = Abbrev->getFormByIndex(*LowPcIdx);
- return hasValidRelocationAt(LowPcOffset, LowPcEndOffset, MyInfo);
+ if (Form == dwarf::DW_FORM_addr) {
+ uint64_t Offset = DIE.getOffset() + getULEB128Size(Abbrev->getCode());
+ uint64_t LowPcOffset, LowPcEndOffset;
+ std::tie(LowPcOffset, LowPcEndOffset) =
+ getAttributeOffsets(Abbrev, *LowPcIdx, Offset, *DIE.getDwarfUnit());
+ return hasValidDebugInfoRelocationAt(LowPcOffset, LowPcEndOffset, MyInfo);
+ }
+
+ if (Form == dwarf::DW_FORM_addrx) {
+ Optional<DWARFFormValue> AddrValue = DIE.find(dwarf::DW_AT_low_pc);
+ return hasValidDebugAddrRelocationAt(*AddrValue->getAsAddress());
+ }
+
+ return false;
}
/// Apply the valid relocations found by findValidRelocs() to
/// the buffer \p Data, taking into account that Data is at \p BaseOffset
@@ -716,22 +734,22 @@ bool DwarfLinkerForBinary::AddressManager::applyValidRelocs(
MutableArrayRef<char> Data, uint64_t BaseOffset, bool IsLittleEndian) {
assert(areRelocationsResolved());
assert((NextValidReloc == 0 ||
- BaseOffset > ValidRelocs[NextValidReloc - 1].Offset) &&
+ BaseOffset > ValidDebugInfoRelocs[NextValidReloc - 1].Offset) &&
"BaseOffset should only be increasing.");
- if (NextValidReloc >= ValidRelocs.size())
+ if (NextValidReloc >= ValidDebugInfoRelocs.size())
return false;
// Skip relocs that haven't been applied.
- while (NextValidReloc < ValidRelocs.size() &&
- ValidRelocs[NextValidReloc].Offset < BaseOffset)
+ while (NextValidReloc < ValidDebugInfoRelocs.size() &&
+ ValidDebugInfoRelocs[NextValidReloc].Offset < BaseOffset)
++NextValidReloc;
bool Applied = false;
uint64_t EndOffset = BaseOffset + Data.size();
- while (NextValidReloc < ValidRelocs.size() &&
- ValidRelocs[NextValidReloc].Offset >= BaseOffset &&
- ValidRelocs[NextValidReloc].Offset < EndOffset) {
- const auto &ValidReloc = ValidRelocs[NextValidReloc++];
+ while (NextValidReloc < ValidDebugInfoRelocs.size() &&
+ ValidDebugInfoRelocs[NextValidReloc].Offset >= BaseOffset &&
+ ValidDebugInfoRelocs[NextValidReloc].Offset < EndOffset) {
+ const auto &ValidReloc = ValidDebugInfoRelocs[NextValidReloc++];
assert(ValidReloc.Offset - BaseOffset < Data.size());
assert(ValidReloc.Offset - BaseOffset + ValidReloc.Size <= Data.size());
char Buf[8];
@@ -749,6 +767,17 @@ bool DwarfLinkerForBinary::AddressManager::applyValidRelocs(
return Applied;
}
+llvm::Expected<uint64_t>
+DwarfLinkerForBinary::AddressManager::relocateIndexedAddr(uint64_t Offset) {
+ auto It = std::lower_bound(ValidDebugAddrRelocs.begin(),
+ ValidDebugAddrRelocs.end(), Offset);
+ if (It == ValidDebugAddrRelocs.end())
+ return createStringError(
+ std::make_error_code(std::errc::invalid_argument),
+ "no relocation for offset %llu in debug_addr section", Offset);
+ return It->Mapping->getValue().BinaryAddress + It->Addend;
+}
+
bool linkDwarf(raw_fd_ostream &OutFile, BinaryHolder &BinHolder,
const DebugMap &DM, LinkOptions Options) {
DwarfLinkerForBinary Linker(OutFile, BinHolder, std::move(Options));
diff --git a/llvm/tools/dsymutil/DwarfLinkerForBinary.h b/llvm/tools/dsymutil/DwarfLinkerForBinary.h
index ec157e38ccf9..c6c07d689f6f 100644
--- a/llvm/tools/dsymutil/DwarfLinkerForBinary.h
+++ b/llvm/tools/dsymutil/DwarfLinkerForBinary.h
@@ -70,13 +70,17 @@ class DwarfLinkerForBinary {
bool operator<(const ValidReloc &RHS) const {
return Offset < RHS.Offset;
}
+ bool operator<(uint64_t RHS) const { return Offset < RHS; }
};
const DwarfLinkerForBinary &Linker;
/// The valid relocations for the current DebugMapObject.
/// This vector is sorted by relocation offset.
- std::vector<ValidReloc> ValidRelocs;
+ /// {
+ std::vector<ValidReloc> ValidDebugInfoRelocs;
+ std::vector<ValidReloc> ValidDebugAddrRelocs;
+ /// }
/// Index into ValidRelocs of the next relocation to consider. As we walk
/// the DIEs in acsending file offset and as ValidRelocs is sorted by file
@@ -90,7 +94,7 @@ class DwarfLinkerForBinary {
AddressManager(DwarfLinkerForBinary &Linker, const object::ObjectFile &Obj,
const DebugMapObject &DMO)
: Linker(Linker) {
- findValidRelocsInDebugInfo(Obj, DMO);
+ findValidRelocsInDebugSections(Obj, DMO);
// Iterate over the debug map entries and put all the ones that are
// functions (because they have a size) into the Ranges map. This map is
@@ -124,27 +128,39 @@ class DwarfLinkerForBinary {
bool hasValidRelocs(bool ResetRelocsPtr = true) override {
if (ResetRelocsPtr)
NextValidReloc = 0;
- return !ValidRelocs.empty();
+ return !ValidDebugInfoRelocs.empty() || !ValidDebugAddrRelocs.empty();
}
/// \defgroup FindValidRelocations Translate debug map into a list
/// of relevant relocations
///
/// @{
- bool findValidRelocsInDebugInfo(const object::ObjectFile &Obj,
- const DebugMapObject &DMO);
+ bool findValidRelocsInDebugSections(const object::ObjectFile &Obj,
+ const DebugMapObject &DMO);
bool findValidRelocs(const object::SectionRef &Section,
const object::ObjectFile &Obj,
- const DebugMapObject &DMO);
+ const DebugMapObject &DMO,
+ std::vector<ValidReloc> &ValidRelocs);
void findValidRelocsMachO(const object::SectionRef &Section,
const object::MachOObjectFile &Obj,
- const DebugMapObject &DMO);
+ const DebugMapObject &DMO,
+ std::vector<ValidReloc> &ValidRelocs);
/// @}
- bool hasValidRelocationAt(uint64_t StartOffset, uint64_t EndOffset,
- CompileUnit::DIEInfo &Info);
+ /// Checks that there is a relocation in the debug_addr section against a
+ /// debug map entry between \p StartOffset and \p NextOffset.
+ ///
+ /// This function must be called with offsets in strictly ascending order
+ /// because it never looks back at relocations it already 'went past'.
+ /// \returns true and sets Info.InDebugMap if it is the case.
+ bool hasValidDebugInfoRelocationAt(uint64_t StartOffset, uint64_t EndOffset,
+ CompileUnit::DIEInfo &Info);
+
+ /// Checks that there is a relocation in the debug_addr section against a
+ /// debug map entry at the given offset.
+ bool hasValidDebugAddrRelocationAt(uint64_t Offset);
bool hasLiveMemoryLocation(const DWARFDie &DIE,
CompileUnit::DIEInfo &Info) override;
@@ -154,11 +170,14 @@ class DwarfLinkerForBinary {
bool applyValidRelocs(MutableArrayRef<char> Data, uint64_t BaseOffset,
bool IsLittleEndian) override;
+ llvm::Expected<uint64_t> relocateIndexedAddr(uint64_t Offset) override;
+
RangesTy &getValidAddressRanges() override { return AddressRanges; }
void clear() override {
AddressRanges.clear();
- ValidRelocs.clear();
+ ValidDebugInfoRelocs.clear();
+ ValidDebugAddrRelocs.clear();
NextValidReloc = 0;
}
};
More information about the llvm-branch-commits
mailing list