From bd0dd27bb5be0fbf60c1b2a4ce15188812388574 Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Tue, 21 Mar 2023 18:55:57 +0100 Subject: [PATCH] [DWARFLinker][DWARFv5] Add handling of DW_OP_addrx and DW_OP_constx expression operands. This patch adds handling of DW_OP_addrx and DW_OP_constx expression operands. In --update case these operands are preserved as is. Otherwise they are converted into the DW_OP_addr and DW_OP_const[*]u correspondingly. Differential Revision: https://reviews.llvm.org/D147066 --- llvm/include/llvm/DWARFLinker/DWARFLinker.h | 34 ++-- .../llvm/DWARFLinker/DWARFLinkerCompileUnit.h | 21 ++- .../llvm/DWARFLinkerParallel/AddressesMap.h | 13 +- llvm/lib/DWARFLinker/DWARFLinker.cpp | 181 +++++++++++++++++++-- llvm/lib/DWARFLinker/DWARFLinkerCompileUnit.cpp | 44 ++++- llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp | 3 +- .../tools/dsymutil/Inputs/dwarf5-dw-op-addrx.o | Bin 0 -> 1856 bytes .../tools/dsymutil/X86/dwarf5-dw-op-addrx.test | 47 ++++++ .../test/tools/dsymutil/X86/op-convert-offset.test | 8 +- .../{dwarf5-addrx.test => dwarf5-addresses.test} | 94 ++++++++++- llvm/tools/dsymutil/DwarfLinkerForBinary.cpp | 37 +++-- llvm/tools/dsymutil/DwarfLinkerForBinary.h | 5 +- llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp | 53 +++--- 13 files changed, 439 insertions(+), 101 deletions(-) create mode 100644 llvm/test/tools/dsymutil/Inputs/dwarf5-dw-op-addrx.o create mode 100644 llvm/test/tools/dsymutil/X86/dwarf5-dw-op-addrx.test rename llvm/test/tools/llvm-dwarfutil/ELF/X86/{dwarf5-addrx.test => dwarf5-addresses.test} (71%) diff --git a/llvm/include/llvm/DWARFLinker/DWARFLinker.h b/llvm/include/llvm/DWARFLinker/DWARFLinker.h index 4d51947..d94e31d5 100644 --- a/llvm/include/llvm/DWARFLinker/DWARFLinker.h +++ b/llvm/include/llvm/DWARFLinker/DWARFLinker.h @@ -17,6 +17,7 @@ #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" #include "llvm/DebugInfo/DWARF/DWARFDie.h" +#include "llvm/DebugInfo/DWARF/DWARFExpression.h" #include namespace llvm { @@ -48,14 +49,16 @@ public: /// section. virtual bool hasValidRelocs() = 0; - /// Checks that the specified variable \p DIE references the live code - /// section and returns the relocation adjustment value (to get the linked - /// address this value might be added to the source variable address). - /// Allowed kinds of input DIE: DW_TAG_variable, DW_TAG_constant. + /// Checks that the specified DWARF expression operand \p Op references live + /// code section and returns the relocation adjustment value (to get the + /// linked address this value might be added to the source expression operand + /// address). /// \returns relocation adjustment value or std::nullopt if there is no /// corresponding live address. virtual std::optional - getVariableRelocAdjustment(const DWARFDie &DIE) = 0; + getExprOpAddressRelocAdjustment(DWARFUnit &U, + const DWARFExpression::Operation &Op, + uint64_t StartOffset, uint64_t EndOffset) = 0; /// Checks that the specified subprogram \p DIE references the live code /// section and returns the relocation adjustment value (to get the linked @@ -572,6 +575,12 @@ private: CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo, unsigned Flags); + /// This function checks whether variable has DWARF expression containing + /// operation referencing live address(f.e. DW_OP_addr, DW_OP_addrx...). + /// \returns relocation adjustment value if live address is referenced. + std::optional getVariableRelocAdjustment(AddressesMap &RelocMgr, + const DWARFDie &DIE); + /// Check if a variable describing DIE should be kept. /// \returns updated TraversalFlags. unsigned shouldKeepVariableDIE(AddressesMap &RelocMgr, const DWARFDie &DIE, @@ -703,14 +712,16 @@ private: /// Clone a DWARF expression that may be referencing another DIE. void cloneExpression(DataExtractor &Data, DWARFExpression Expression, const DWARFFile &File, CompileUnit &Unit, - SmallVectorImpl &OutputBuffer); + SmallVectorImpl &OutputBuffer, + int64_t AddrRelocAdjustment); /// Clone an attribute referencing another DIE and add /// it to \p Die. /// \returns the size of the new attribute. - unsigned cloneBlockAttribute(DIE &Die, const DWARFFile &File, - CompileUnit &Unit, AttributeSpec AttrSpec, - const DWARFFormValue &Val, unsigned AttrSize, + unsigned cloneBlockAttribute(DIE &Die, const DWARFDie &InputDIE, + const DWARFFile &File, CompileUnit &Unit, + AttributeSpec AttrSpec, + const DWARFFormValue &Val, bool IsLittleEndian); /// Clone an attribute referencing another DIE and add @@ -761,8 +772,9 @@ private: /// .debug_rnglists) for \p Unit, patch the attributes referencing it. void generateUnitRanges(CompileUnit &Unit, const DWARFFile &File) const; - using ExpressionHandlerRef = function_ref &, - SmallVectorImpl &)>; + using ExpressionHandlerRef = + function_ref &, SmallVectorImpl &, + int64_t AddrRelocAdjustment)>; /// Compute and emit debug locations (.debug_loc, .debug_loclists) /// for \p Unit, patch the attributes referencing it. diff --git a/llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h b/llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h index cfbd134..3736033 100644 --- a/llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h +++ b/llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h @@ -23,12 +23,22 @@ class DeclContext; /// linked address. using RangesTy = AddressRangesMap; -// FIXME: Delete this structure. +// This structure keeps patch for the attribute and, optionally, +// the value of relocation which should be applied. Currently, +// only location attribute needs to have relocation: either to the +// function ranges if location attribute is of type 'loclist', +// either to the operand of DW_OP_addr/DW_OP_addrx if location attribute +// is of type 'exprloc'. +// ASSUMPTION: Location attributes of 'loclist' type containing 'exprloc' +// with address expression operands are not supported yet. struct PatchLocation { DIE::value_iterator I; + int64_t RelocAdjustment = 0; PatchLocation() = default; PatchLocation(DIE::value_iterator I) : I(I) {} + PatchLocation(DIE::value_iterator I, int64_t Reloc) + : I(I), RelocAdjustment(Reloc) {} void set(uint64_t New) const { assert(I); @@ -44,7 +54,7 @@ struct PatchLocation { }; using RngListAttributesTy = SmallVector; -using LocListAttributesTy = SmallVector>; +using LocListAttributesTy = SmallVector; /// Stores all information relating to a compile unit, be it in its original /// instance in the object file to its brand new cloned and generated DIE tree. @@ -191,7 +201,7 @@ public: /// Keep track of a location attribute pointing to a location list in the /// debug_loc section. - void noteLocationAttribute(PatchLocation Attr, int64_t PcOffset); + void noteLocationAttribute(PatchLocation Attr); /// Add a name accelerator entry for \a Die with \a Name. void addNamespaceAccelerator(const DIE *Die, DwarfStringPoolEntryRef Name); @@ -286,9 +296,10 @@ private: /// @} /// Location attributes that need to be transferred from the - /// original debug_loc section to the liked one. They are stored + /// original debug_loc section to the linked one. They are stored /// along with the PC offset that is to be applied to their - /// function's address. + /// function's address or to be applied to address operands of + /// location expression. LocListAttributesTy LocationAttributes; /// Accelerator entries for the unit, both for the pub* diff --git a/llvm/include/llvm/DWARFLinkerParallel/AddressesMap.h b/llvm/include/llvm/DWARFLinkerParallel/AddressesMap.h index eadd712..5386f9c 100644 --- a/llvm/include/llvm/DWARFLinkerParallel/AddressesMap.h +++ b/llvm/include/llvm/DWARFLinkerParallel/AddressesMap.h @@ -11,6 +11,7 @@ #include "llvm/ADT/AddressRanges.h" #include "llvm/DebugInfo/DWARF/DWARFDie.h" +#include "llvm/DebugInfo/DWARF/DWARFExpression.h" #include namespace llvm { @@ -32,14 +33,16 @@ public: /// section. virtual bool hasValidRelocs() = 0; - /// Checks that the specified variable \p DIE references the live code - /// section and returns the relocation adjustment value (to get the linked - /// address this value might be added to the source variable address). - /// Allowed kinds of input DIE: DW_TAG_variable, DW_TAG_constant. + /// Checks that the specified DWARF expression operand \p Op references live + /// code section and returns the relocation adjustment value (to get the + /// linked address this value might be added to the source expression operand + /// address). /// \returns relocation adjustment value or std::nullopt if there is no /// corresponding live address. virtual std::optional - getVariableRelocAdjustment(const DWARFDie &DIE) = 0; + getExprOpAddressRelocAdjustment(DWARFUnit &U, + const DWARFExpression::Operation &Op, + uint64_t StartOffset, uint64_t EndOffset) = 0; /// Checks that the specified subprogram \p DIE references the live code /// section and returns the relocation adjustment value (to get the linked diff --git a/llvm/lib/DWARFLinker/DWARFLinker.cpp b/llvm/lib/DWARFLinker/DWARFLinker.cpp index 3307f53..93c03a1 100644 --- a/llvm/lib/DWARFLinker/DWARFLinker.cpp +++ b/llvm/lib/DWARFLinker/DWARFLinker.cpp @@ -419,6 +419,94 @@ void DWARFLinker::cleanupAuxiliarryData(LinkContext &Context) { DIEAlloc.Reset(); } +std::optional +DWARFLinker::getVariableRelocAdjustment(AddressesMap &RelocMgr, + const DWARFDie &DIE) { + assert((DIE.getTag() == dwarf::DW_TAG_variable || + DIE.getTag() == dwarf::DW_TAG_constant) && + "Wrong type of input die"); + + const auto *Abbrev = DIE.getAbbreviationDeclarationPtr(); + + // Check if DIE has DW_AT_location attribute. + DWARFUnit *U = DIE.getDwarfUnit(); + std::optional LocationIdx = + Abbrev->findAttributeIndex(dwarf::DW_AT_location); + if (!LocationIdx) + return std::nullopt; + + // Get offset to the DW_AT_location attribute. + uint64_t AttrOffset = + Abbrev->getAttributeOffsetFromIndex(*LocationIdx, DIE.getOffset(), *U); + + // Get value of the DW_AT_location attribute. + std::optional LocationValue = + Abbrev->getAttributeValueFromOffset(*LocationIdx, AttrOffset, *U); + if (!LocationValue) + return std::nullopt; + + // Check that DW_AT_location attribute is of 'exprloc' class. + // Handling value of location expressions for attributes of 'loclist' + // class is not implemented yet. + std::optional> Expr = LocationValue->getAsBlock(); + if (!Expr) + return std::nullopt; + + // Parse 'exprloc' expression. + DataExtractor Data(toStringRef(*Expr), U->getContext().isLittleEndian(), + U->getAddressByteSize()); + DWARFExpression Expression(Data, U->getAddressByteSize(), + U->getFormParams().Format); + + uint64_t CurExprOffset = 0; + for (DWARFExpression::iterator It = Expression.begin(); + It != Expression.end(); ++It) { + DWARFExpression::iterator NextIt = It; + ++NextIt; + + const DWARFExpression::Operation &Op = *It; + switch (Op.getCode()) { + case dwarf::DW_OP_const4u: + case dwarf::DW_OP_const8u: + case dwarf::DW_OP_const4s: + case dwarf::DW_OP_const8s: + if (NextIt == Expression.end() || + NextIt->getCode() != dwarf::DW_OP_form_tls_address) + break; + [[fallthrough]]; + case dwarf::DW_OP_addr: { + // Check relocation for the address. + if (std::optional RelocAdjustment = + RelocMgr.getExprOpAddressRelocAdjustment( + *U, Op, AttrOffset + CurExprOffset, + AttrOffset + Op.getEndOffset())) + return *RelocAdjustment; + } break; + case dwarf::DW_OP_constx: + case dwarf::DW_OP_addrx: { + if (std::optional AddrOffsetSectionBase = + DIE.getDwarfUnit()->getAddrOffsetSectionBase()) { + uint64_t StartOffset = *AddrOffsetSectionBase + Op.getRawOperand(0); + uint64_t EndOffset = + StartOffset + DIE.getDwarfUnit()->getAddressByteSize(); + + // Check relocation for the address. + if (std::optional RelocAdjustment = + RelocMgr.getExprOpAddressRelocAdjustment(*U, Op, StartOffset, + EndOffset)) + return *RelocAdjustment; + } + } break; + default: { + // Nothing to do. + } break; + } + CurExprOffset = Op.getEndOffset(); + } + + return std::nullopt; +} + /// Check if a variable describing DIE should be kept. /// \returns updated TraversalFlags. unsigned DWARFLinker::shouldKeepVariableDIE(AddressesMap &RelocMgr, @@ -440,7 +528,7 @@ unsigned DWARFLinker::shouldKeepVariableDIE(AddressesMap &RelocMgr, // However, we don't want a static variable in a function to force us to keep // the enclosing function, unless requested explicitly. std::optional RelocAdjustment = - RelocMgr.getVariableRelocAdjustment(DIE); + getVariableRelocAdjustment(RelocMgr, DIE); if (RelocAdjustment) { MyInfo.AddrAdjust = *RelocAdjustment; @@ -1053,9 +1141,12 @@ unsigned DWARFLinker::DIECloner::cloneDieReferenceAttribute( void DWARFLinker::DIECloner::cloneExpression( DataExtractor &Data, DWARFExpression Expression, const DWARFFile &File, - CompileUnit &Unit, SmallVectorImpl &OutputBuffer) { + CompileUnit &Unit, SmallVectorImpl &OutputBuffer, + int64_t AddrRelocAdjustment) { using Encoding = DWARFExpression::Operation::Encoding; + uint8_t OrigAddressByteSize = Unit.getOrigUnit().getAddressByteSize(); + uint64_t OpOffset = 0; for (auto &Op : Expression) { auto Description = Op.getDescription(); @@ -1107,6 +1198,55 @@ void DWARFLinker::DIECloner::cloneExpression( assert(RealSize == ULEBsize && "padding failed"); ArrayRef ULEBbytes(ULEB, ULEBsize); OutputBuffer.append(ULEBbytes.begin(), ULEBbytes.end()); + } else if (!Linker.Options.Update && Op.getCode() == dwarf::DW_OP_addrx) { + if (std::optional SA = + Unit.getOrigUnit().getAddrOffsetSectionItem( + Op.getRawOperand(0))) { + // DWARFLinker does not use addrx forms since it generates relocated + // addresses. Replace DW_OP_addrx with DW_OP_addr here. + // Argument of DW_OP_addrx should be relocated here as it is not + // processed by applyValidRelocs. + OutputBuffer.push_back(dwarf::DW_OP_addr); + uint64_t LinkedAddress = SA->Address + AddrRelocAdjustment; + ArrayRef AddressBytes( + reinterpret_cast(&LinkedAddress), + OrigAddressByteSize); + OutputBuffer.append(AddressBytes.begin(), AddressBytes.end()); + } else + Linker.reportWarning("cannot read DW_OP_addrx operand.", File); + } else if (!Linker.Options.Update && Op.getCode() == dwarf::DW_OP_constx) { + if (std::optional SA = + Unit.getOrigUnit().getAddrOffsetSectionItem( + Op.getRawOperand(0))) { + // DWARFLinker does not use constx forms since it generates relocated + // addresses. Replace DW_OP_constx with DW_OP_const[*]u here. + // Argument of DW_OP_constx should be relocated here as it is not + // processed by applyValidRelocs. + std::optional OutOperandKind; + switch (OrigAddressByteSize) { + case 4: + OutOperandKind = dwarf::DW_OP_const4u; + break; + case 8: + OutOperandKind = dwarf::DW_OP_const8u; + break; + default: + Linker.reportWarning( + formatv(("unsupported address size: {0}."), OrigAddressByteSize), + File); + break; + } + + if (OutOperandKind) { + OutputBuffer.push_back(*OutOperandKind); + uint64_t LinkedAddress = SA->Address + AddrRelocAdjustment; + ArrayRef AddressBytes( + reinterpret_cast(&LinkedAddress), + OrigAddressByteSize); + OutputBuffer.append(AddressBytes.begin(), AddressBytes.end()); + } + } else + Linker.reportWarning("cannot read DW_OP_constx operand.", File); } else { // Copy over everything else unmodified. StringRef Bytes = Data.getData().slice(OpOffset, Op.getEndOffset()); @@ -1117,8 +1257,9 @@ void DWARFLinker::DIECloner::cloneExpression( } unsigned DWARFLinker::DIECloner::cloneBlockAttribute( - DIE &Die, const DWARFFile &File, CompileUnit &Unit, AttributeSpec AttrSpec, - const DWARFFormValue &Val, unsigned AttrSize, bool IsLittleEndian) { + DIE &Die, const DWARFDie &InputDIE, const DWARFFile &File, + CompileUnit &Unit, AttributeSpec AttrSpec, const DWARFFormValue &Val, + bool IsLittleEndian) { DIEValueList *Attr; DIEValue Value; DIELoc *Loc = nullptr; @@ -1152,7 +1293,8 @@ unsigned DWARFLinker::DIECloner::cloneBlockAttribute( IsLittleEndian, OrigUnit.getAddressByteSize()); DWARFExpression Expr(Data, OrigUnit.getAddressByteSize(), OrigUnit.getFormParams().Format); - cloneExpression(Data, Expr, File, Unit, Buffer); + cloneExpression(Data, Expr, File, Unit, Buffer, + Unit.getInfo(InputDIE).AddrAdjust); Bytes = Buffer; } for (auto Byte : Bytes) @@ -1168,7 +1310,7 @@ unsigned DWARFLinker::DIECloner::cloneBlockAttribute( Block->setSize(Bytes.size()); Die.addValue(DIEAlloc, Value); - return AttrSize; + return getULEB128Size(Bytes.size()) + Bytes.size(); } unsigned DWARFLinker::DIECloner::cloneAddressAttribute( @@ -1355,7 +1497,7 @@ unsigned DWARFLinker::DIECloner::cloneScalarAttribute( return 0; } - PatchLocation Patch = + DIE::value_iterator Patch = Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr), dwarf::Form(AttrSpec.Form), DIEInteger(Value)); if (AttrSpec.Attr == dwarf::DW_AT_ranges || @@ -1366,7 +1508,11 @@ unsigned DWARFLinker::DIECloner::cloneScalarAttribute( dwarf::doesFormBelongToClass(AttrSpec.Form, DWARFFormValue::FC_SectionOffset, Unit.getOrigUnit().getVersion())) { - Unit.noteLocationAttribute(Patch, Info.PCOffset); + + CompileUnit::DIEInfo &LocationDieInfo = Unit.getInfo(InputDIE); + Unit.noteLocationAttribute({Patch, LocationDieInfo.InDebugMap + ? LocationDieInfo.AddrAdjust + : Info.PCOffset}); } else if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value) Info.IsDeclaration = true; @@ -1408,7 +1554,7 @@ unsigned DWARFLinker::DIECloner::cloneAttribute( case dwarf::DW_FORM_block2: case dwarf::DW_FORM_block4: case dwarf::DW_FORM_exprloc: - return cloneBlockAttribute(Die, File, Unit, AttrSpec, Val, AttrSize, + return cloneBlockAttribute(Die, InputDIE, File, Unit, AttrSpec, Val, IsLittleEndian); case dwarf::DW_FORM_addr: case dwarf::DW_FORM_addrx: @@ -1803,7 +1949,7 @@ void DWARFLinker::generateUnitLocations( // Get location expressions vector corresponding to the current attribute // from the source DWARF. Expected OriginalLocations = - Unit.getOrigUnit().findLoclistFromOffset((CurLocAttr.first).get()); + Unit.getOrigUnit().findLoclistFromOffset(CurLocAttr.get()); if (!OriginalLocations) { llvm::consumeError(OriginalLocations.takeError()); @@ -1813,26 +1959,26 @@ void DWARFLinker::generateUnitLocations( DWARFLocationExpressionsVector LinkedLocationExpressions; for (DWARFLocationExpression &CurExpression : *OriginalLocations) { - DWARFLocationExpression LinkedExpression; if (CurExpression.Range) { // Relocate address range. LinkedExpression.Range = { - CurExpression.Range->LowPC + CurLocAttr.second, - CurExpression.Range->HighPC + CurLocAttr.second}; + CurExpression.Range->LowPC + CurLocAttr.RelocAdjustment, + CurExpression.Range->HighPC + CurLocAttr.RelocAdjustment}; } // Clone expression. LinkedExpression.Expr.reserve(CurExpression.Expr.size()); - ExprHandler(CurExpression.Expr, LinkedExpression.Expr); + ExprHandler(CurExpression.Expr, LinkedExpression.Expr, + CurLocAttr.RelocAdjustment); LinkedLocationExpressions.push_back(LinkedExpression); } // Emit locations list table fragment corresponding to the CurLocAttr. TheDwarfEmitter->emitDwarfDebugLocListFragment( - Unit, LinkedLocationExpressions, CurLocAttr.first); + Unit, LinkedLocationExpressions, CurLocAttr); } // Emit locations list table footer. @@ -2399,14 +2545,15 @@ uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits( Linker.generateUnitRanges(*CurrentUnit, File); auto ProcessExpr = [&](SmallVectorImpl &SrcBytes, - SmallVectorImpl &OutBytes) { + SmallVectorImpl &OutBytes, + int64_t RelocAdjustment) { DWARFUnit &OrigUnit = CurrentUnit->getOrigUnit(); DataExtractor Data(SrcBytes, IsLittleEndian, OrigUnit.getAddressByteSize()); cloneExpression(Data, DWARFExpression(Data, OrigUnit.getAddressByteSize(), OrigUnit.getFormParams().Format), - File, *CurrentUnit, OutBytes); + File, *CurrentUnit, OutBytes, RelocAdjustment); }; Linker.generateUnitLocations(*CurrentUnit, File, ProcessExpr); } diff --git a/llvm/lib/DWARFLinker/DWARFLinkerCompileUnit.cpp b/llvm/lib/DWARFLinker/DWARFLinkerCompileUnit.cpp index 870a841..4aa6f33 100644 --- a/llvm/lib/DWARFLinker/DWARFLinkerCompileUnit.cpp +++ b/llvm/lib/DWARFLinker/DWARFLinkerCompileUnit.cpp @@ -8,6 +8,8 @@ #include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h" #include "llvm/DWARFLinker/DWARFLinkerDeclContext.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFExpression.h" #include "llvm/Support/FormatVariadic.h" namespace llvm { @@ -63,6 +65,7 @@ void CompileUnit::markEverythingAsKept() { // Mark everything that wasn't explicit marked for pruning. I.Keep = !I.Prune; auto DIE = OrigUnit.getDIEAtIndex(Idx++); + DWARFUnit *U = DIE.getDwarfUnit(); // Try to guess which DIEs must go to the accelerator tables. We do that // just for variables, because functions will be handled depending on @@ -78,10 +81,39 @@ void CompileUnit::markEverythingAsKept() { I.InDebugMap = true; continue; } - if (auto Block = Value->getAsBlock()) { - if (Block->size() > OrigUnit.getAddressByteSize() && - (*Block)[0] == dwarf::DW_OP_addr) - I.InDebugMap = true; + + if (auto ExprLockBlock = Value->getAsBlock()) { + // Parse 'exprloc' expression. + DataExtractor Data(toStringRef(*ExprLockBlock), + U->getContext().isLittleEndian(), + U->getAddressByteSize()); + DWARFExpression Expression(Data, U->getAddressByteSize(), + U->getFormParams().Format); + + for (DWARFExpression::iterator It = Expression.begin(); + (It != Expression.end()) && !I.InDebugMap; ++It) { + DWARFExpression::iterator NextIt = It; + ++NextIt; + + switch (It->getCode()) { + case dwarf::DW_OP_const4u: + case dwarf::DW_OP_const8u: + case dwarf::DW_OP_const4s: + case dwarf::DW_OP_const8s: + if (NextIt == Expression.end() || + NextIt->getCode() != dwarf::DW_OP_form_tls_address) + break; + [[fallthrough]]; + case dwarf::DW_OP_constx: + case dwarf::DW_OP_addr: + case dwarf::DW_OP_addrx: + I.InDebugMap = true; + break; + default: + // Nothing to do. + break; + } + } } } } @@ -143,8 +175,8 @@ void CompileUnit::noteRangeAttribute(const DIE &Die, PatchLocation Attr) { RangeAttributes.emplace_back(Attr); } -void CompileUnit::noteLocationAttribute(PatchLocation Attr, int64_t PcOffset) { - LocationAttributes.emplace_back(Attr, PcOffset); +void CompileUnit::noteLocationAttribute(PatchLocation Attr) { + LocationAttributes.emplace_back(Attr); } void CompileUnit::addNamespaceAccelerator(const DIE *Die, diff --git a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp index 3adc6c7..109731e 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp @@ -94,11 +94,12 @@ static DescVector getDescriptions() { Descriptions[DW_OP_WASM_location] = Desc(Op::Dwarf4, Op::SizeLEB, Op::WasmLocationArg); Descriptions[DW_OP_GNU_push_tls_address] = Desc(Op::Dwarf3); - Descriptions[DW_OP_addrx] = Desc(Op::Dwarf4, Op::SizeLEB); Descriptions[DW_OP_GNU_addr_index] = Desc(Op::Dwarf4, Op::SizeLEB); Descriptions[DW_OP_GNU_const_index] = Desc(Op::Dwarf4, Op::SizeLEB); Descriptions[DW_OP_GNU_entry_value] = Desc(Op::Dwarf4, Op::SizeLEB); + Descriptions[DW_OP_addrx] = Desc(Op::Dwarf5, Op::SizeLEB); + Descriptions[DW_OP_constx] = Desc(Op::Dwarf5, Op::SizeLEB); Descriptions[DW_OP_convert] = Desc(Op::Dwarf5, Op::BaseTypeRef); Descriptions[DW_OP_entry_value] = Desc(Op::Dwarf5, Op::SizeLEB); Descriptions[DW_OP_regval_type] = diff --git a/llvm/test/tools/dsymutil/Inputs/dwarf5-dw-op-addrx.o b/llvm/test/tools/dsymutil/Inputs/dwarf5-dw-op-addrx.o new file mode 100644 index 0000000000000000000000000000000000000000..fb2a6d3242ec5b9e49fac277fba58145b21f6aad GIT binary patch literal 1856 zcma)6K~EDw6rS1bwn(8AO9BllC80?*wxtDwVgfW$LyZTlfIwo#ZM%gg?Y7yL(%?a( ziGuN<2M^vfp1pYTU<}51_9v(Z5--M!2O|mk-s~*26_UQ>?R)dyn{VFCd^?~2{Md64 zLS+IUP#frZ{P;jYyr6F}d4xQd%)}zj0kOt_Nl={_1YxYA)hecMj_2Zwa|dI~YZDIQ z2}m?0LFu&bF-ihj|ZCZh6T}Jx0A#Vhp7@}#|ZxjM})_hyt?U?6+MHugaKF}Wp+W{8; z(^=4Z!MT>!$6N8|XSQ}C+c!TBL9w`Mg8xt)6bW1gt${uUeF_>YmGYV|omcf0UsW^8 zxuWiiL_))%5nq5ugOSMa2#%wn=!MfHv#uK1bHU7duviKr>1v@g3D1{dYB;r)%V)}Y zwW@{HY91b*awRP4wVGOhg@|exB)zH{z|&YV8Czo46U%Wnw=^4Pj1<(IPI7vM&~EDY zdlcDk^tyZd{on3*yZevZ%e`=PqeS*6Jd@sW=S8Ok2P#vV@BsY=Ny0M*hp7xf!GzNZ zt{q*ca{^pPh#yg(1Ybg>mqZ>1$2I|< z08wmqYFFAE4qiwX>_oZ-3B{qn8`Xmz;i%yKFCrt@e~`y{D0Cx9Xw6OC9gemqP=)t- z0@Sznm&-nK%;kO{UFx)GiSH1uJBApP?z%eB2sVK;z*m&%fYha&qGzCr{QUlIaQFSI z`_b2rc0QcFcN@Atw$Evg;%dJl*#M;VOFon%u#g*jf_uT -DwarfLinkerForBinary::AddressManager::getVariableRelocAdjustment( - const DWARFDie &DIE) { - const auto *Abbrev = DIE.getAbbreviationDeclarationPtr(); - - std::optional LocationIdx = - Abbrev->findAttributeIndex(dwarf::DW_AT_location); - if (!LocationIdx) - return std::nullopt; - - uint64_t Offset = DIE.getOffset() + getULEB128Size(Abbrev->getCode()); - uint64_t LocationOffset, LocationEndOffset; - std::tie(LocationOffset, LocationEndOffset) = - getAttributeOffsets(Abbrev, *LocationIdx, Offset, *DIE.getDwarfUnit()); +DwarfLinkerForBinary::AddressManager::getExprOpAddressRelocAdjustment( + DWARFUnit &U, const DWARFExpression::Operation &Op, uint64_t StartOffset, + uint64_t EndOffset) { + switch (Op.getCode()) { + default: { + assert(false && "Specified operation does not have address operand"); + } break; + case dwarf::DW_OP_const4u: + case dwarf::DW_OP_const8u: + case dwarf::DW_OP_const4s: + case dwarf::DW_OP_const8s: + case dwarf::DW_OP_addr: { + return hasValidRelocationAt(ValidDebugInfoRelocs, StartOffset, EndOffset); + } break; + case dwarf::DW_OP_constx: + case dwarf::DW_OP_addrx: { + return hasValidRelocationAt(ValidDebugAddrRelocs, StartOffset, EndOffset); + } break; + } - // FIXME: Support relocations debug_addr. - return hasValidRelocationAt(ValidDebugInfoRelocs, LocationOffset, - LocationEndOffset); + return std::nullopt; } std::optional diff --git a/llvm/tools/dsymutil/DwarfLinkerForBinary.h b/llvm/tools/dsymutil/DwarfLinkerForBinary.h index ec54265..8b967f9 100644 --- a/llvm/tools/dsymutil/DwarfLinkerForBinary.h +++ b/llvm/tools/dsymutil/DwarfLinkerForBinary.h @@ -177,8 +177,9 @@ private: hasValidRelocationAt(const std::vector &Relocs, uint64_t StartOffset, uint64_t EndOffset); - std::optional - getVariableRelocAdjustment(const DWARFDie &DIE) override; + std::optional getExprOpAddressRelocAdjustment( + DWARFUnit &U, const DWARFExpression::Operation &Op, + uint64_t StartOffset, uint64_t EndOffset) override; std::optional getSubprogramRelocAdjustment(const DWARFDie &DIE) override; diff --git a/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp b/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp index 534a56a..b36c57a 100644 --- a/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp +++ b/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp @@ -88,38 +88,33 @@ public: return std::nullopt; } - std::optional - getVariableRelocAdjustment(const DWARFDie &DIE) override { - assert((DIE.getTag() == dwarf::DW_TAG_variable || - DIE.getTag() == dwarf::DW_TAG_constant) && - "Wrong type of input die"); - - if (Expected Loc = - DIE.getLocations(dwarf::DW_AT_location)) { - DWARFUnit *U = DIE.getDwarfUnit(); - for (const auto &Entry : *Loc) { - DataExtractor Data(toStringRef(Entry.Expr), - U->getContext().isLittleEndian(), 0); - DWARFExpression Expression(Data, U->getAddressByteSize(), - U->getFormParams().Format); - bool HasLiveAddresses = - any_of(Expression, [&](const DWARFExpression::Operation &Op) { - // TODO: add handling of dwarf::DW_OP_addrx - return !Op.isError() && - (Op.getCode() == dwarf::DW_OP_addr && - !isDeadAddress(Op.getRawOperand(0), U->getVersion(), - Opts.Tombstone, - DIE.getDwarfUnit()->getAddressByteSize())); - }); - - if (HasLiveAddresses) + std::optional getExprOpAddressRelocAdjustment( + DWARFUnit &U, const DWARFExpression::Operation &Op, uint64_t StartOffset, + uint64_t EndOffset) override { + switch (Op.getCode()) { + default: { + assert(false && "Specified operation does not have address operand"); + } break; + case dwarf::DW_OP_const4u: + case dwarf::DW_OP_const8u: + case dwarf::DW_OP_const4s: + case dwarf::DW_OP_const8s: + case dwarf::DW_OP_addr: { + if (!isDeadAddress(Op.getRawOperand(0), U.getVersion(), Opts.Tombstone, + U.getAddressByteSize())) + // Relocation value for the linked binary is 0. + return 0; + } break; + case dwarf::DW_OP_constx: + case dwarf::DW_OP_addrx: { + if (std::optional Address = + U.getAddrOffsetSectionItem(Op.getRawOperand(0))) { + if (!isDeadAddress(Address->Address, U.getVersion(), Opts.Tombstone, + U.getAddressByteSize())) // Relocation value for the linked binary is 0. return 0; } - } else { - // FIXME: missing DW_AT_location is OK here, but other errors should be - // reported to the user. - consumeError(Loc.takeError()); + } break; } return std::nullopt; -- 2.7.4