Index: llvm/include/llvm/DWARFLinker/DWARFLinker.h =================================================================== --- llvm/include/llvm/DWARFLinker/DWARFLinker.h +++ llvm/include/llvm/DWARFLinker/DWARFLinker.h @@ -85,6 +85,9 @@ virtual bool applyValidRelocs(MutableArrayRef Data, uint64_t BaseOffset, bool IsLittleEndian) = 0; + /// Relocate the given address offset if a valid relocation exists. + virtual 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 @@ /// /// 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; Index: llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h =================================================================== --- llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h +++ llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h @@ -159,7 +159,7 @@ /// 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 Index: llvm/include/llvm/DWARFLinker/DWARFStreamer.h =================================================================== --- llvm/include/llvm/DWARFLinker/DWARFStreamer.h +++ llvm/include/llvm/DWARFLinker/DWARFStreamer.h @@ -64,7 +64,7 @@ /// /// 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; Index: llvm/lib/DWARFLinker/DWARFLinker.cpp =================================================================== --- llvm/lib/DWARFLinker/DWARFLinker.cpp +++ llvm/lib/DWARFLinker/DWARFLinker.cpp @@ -419,7 +419,6 @@ DIEAlloc.Reset(); } - /// Check if a variable describing DIE should be kept. /// \returns updated TraversalFlags. unsigned DWARFLinker::shouldKeepVariableDIE(AddressesMap &RelocMgr, @@ -845,9 +844,12 @@ unsigned DWARFLinker::DIECloner::cloneStringAttribute( DIE &Die, AttributeSpec AttrSpec, const DWARFFormValue &Val, const DWARFUnit &U, OffsetsStringPool &StringPool, AttributesInfo &Info) { + Optional 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::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,14 @@ Addr = (Info.OrigCallPc ? Info.OrigCallPc : Addr) + Info.PCOffset; } + // If this is an indexed address emit the relocated address. + if (Form == dwarf::DW_FORM_addrx) { + Addr = ObjFile.Addresses->relocateIndexedAddr(Addr); + Form = dwarf::DW_FORM_addr; + } + Die.addValue(DIEAlloc, static_cast(AttrSpec.Attr), - static_cast(AttrSpec.Form), DIEInteger(Addr)); + static_cast(Form), DIEInteger(Addr)); return Unit.getOrigUnit().getAddressByteSize(); } @@ -1188,6 +1197,11 @@ 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 +1218,7 @@ 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 +1299,9 @@ 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 +2145,12 @@ 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 +2158,11 @@ // 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 +2203,14 @@ 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)); } } Index: llvm/lib/DWARFLinker/DWARFLinkerCompileUnit.cpp =================================================================== --- llvm/lib/DWARFLinker/DWARFLinkerCompileUnit.cpp +++ llvm/lib/DWARFLinker/DWARFLinkerCompileUnit.cpp @@ -36,7 +36,7 @@ } return SysRoot; } - + void CompileUnit::markEverythingAsKept() { unsigned Idx = 0; @@ -69,10 +69,10 @@ } } -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; Index: llvm/lib/DWARFLinker/DWARFStreamer.cpp =================================================================== --- llvm/lib/DWARFLinker/DWARFStreamer.cpp +++ llvm/lib/DWARFLinker/DWARFStreamer.cpp @@ -121,16 +121,23 @@ /// 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 @@ // 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 @@ // 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( Index: llvm/test/tools/dsymutil/X86/dwarf5.test =================================================================== --- /dev/null +++ llvm/test/tools/dsymutil/X86/dwarf5.test @@ -0,0 +1,60 @@ +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: dwarfdump --verify %t.dSYM 2>&1 | FileCheck %s +CHECK-NOT: warning: +CHECK-NOT: error: + +RUN: 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**") Index: llvm/tools/dsymutil/DwarfLinkerForBinary.h =================================================================== --- llvm/tools/dsymutil/DwarfLinkerForBinary.h +++ llvm/tools/dsymutil/DwarfLinkerForBinary.h @@ -70,13 +70,17 @@ 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 ValidRelocs; + /// { + std::vector ValidDebugInfoRelocs; + std::vector 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 @@ 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 @@ 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 &ValidRelocs); void findValidRelocsMachO(const object::SectionRef &Section, const object::MachOObjectFile &Obj, - const DebugMapObject &DMO); + const DebugMapObject &DMO, + std::vector &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. + 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. + /// + /// 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 hasValidDebugAddrRelocationAt(uint64_t Offset); bool hasLiveMemoryLocation(const DWARFDie &DIE, CompileUnit::DIEInfo &Info) override; @@ -154,11 +170,14 @@ bool applyValidRelocs(MutableArrayRef Data, uint64_t BaseOffset, bool IsLittleEndian) override; + 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; } }; Index: llvm/tools/dsymutil/DwarfLinkerForBinary.cpp =================================================================== --- llvm/tools/dsymutil/DwarfLinkerForBinary.cpp +++ llvm/tools/dsymutil/DwarfLinkerForBinary.cpp @@ -488,7 +488,7 @@ /// ValidRelocs array. void DwarfLinkerForBinary::AddressManager::findValidRelocsMachO( const object::SectionRef &Section, const object::MachOObjectFile &Obj, - const DebugMapObject &DMO) { + const DebugMapObject &DMO, std::vector &ValidRelocs) { Expected ContentsOrErr = Section.getContents(); if (!ContentsOrErr) { consumeError(ContentsOrErr.takeError()); @@ -510,7 +510,8 @@ 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; } @@ -518,7 +519,8 @@ 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; } @@ -563,33 +565,33 @@ /// 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 &Relocs) { // Dispatch to the right handler depending on the file type. if (auto *MachOObj = dyn_cast(&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 NameOrErr = Section.getName()) @@ -598,39 +600,44 @@ 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 @@ -672,7 +679,6 @@ bool DwarfLinkerForBinary::AddressManager::hasLiveMemoryLocation( const DWARFDie &DIE, CompileUnit::DIEInfo &MyInfo) { - const auto *Abbrev = DIE.getAbbreviationDeclarationPtr(); Optional LocationIdx = @@ -685,7 +691,9 @@ 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( @@ -696,12 +704,22 @@ 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 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 @@ -715,22 +733,22 @@ MutableArrayRef 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]; @@ -748,6 +766,15 @@ return Applied; } +uint64_t +DwarfLinkerForBinary::AddressManager::relocateIndexedAddr(uint64_t Offset) { + auto It = std::lower_bound(ValidDebugAddrRelocs.begin(), + ValidDebugAddrRelocs.end(), Offset); + if (It == ValidDebugAddrRelocs.end()) + return Offset; + return It->Mapping->getValue().BinaryAddress; +} + bool linkDwarf(raw_fd_ostream &OutFile, BinaryHolder &BinHolder, const DebugMap &DM, LinkOptions Options) { DwarfLinkerForBinary Linker(OutFile, BinHolder, std::move(Options));