[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
This commit is contained in:
Alexey Lapshin
2023-03-21 18:55:57 +01:00
parent d225e6f40c
commit bd0dd27bb5
13 changed files with 439 additions and 101 deletions

View File

@@ -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 <map>
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<int64_t>
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<int64_t> 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<uint8_t> &OutputBuffer);
SmallVectorImpl<uint8_t> &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<void(SmallVectorImpl<uint8_t> &,
SmallVectorImpl<uint8_t> &)>;
using ExpressionHandlerRef =
function_ref<void(SmallVectorImpl<uint8_t> &, SmallVectorImpl<uint8_t> &,
int64_t AddrRelocAdjustment)>;
/// Compute and emit debug locations (.debug_loc, .debug_loclists)
/// for \p Unit, patch the attributes referencing it.

View File

@@ -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<PatchLocation>;
using LocListAttributesTy = SmallVector<std::pair<PatchLocation, int64_t>>;
using LocListAttributesTy = SmallVector<PatchLocation>;
/// 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*

View File

@@ -11,6 +11,7 @@
#include "llvm/ADT/AddressRanges.h"
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
#include <cstdint>
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<int64_t>
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

View File

@@ -419,6 +419,94 @@ void DWARFLinker::cleanupAuxiliarryData(LinkContext &Context) {
DIEAlloc.Reset();
}
std::optional<int64_t>
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<uint32_t> 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<DWARFFormValue> 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<ArrayRef<uint8_t>> 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<int64_t> 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<uint64_t> 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<int64_t> 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<int64_t> 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<uint8_t> &OutputBuffer) {
CompileUnit &Unit, SmallVectorImpl<uint8_t> &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<uint8_t> ULEBbytes(ULEB, ULEBsize);
OutputBuffer.append(ULEBbytes.begin(), ULEBbytes.end());
} else if (!Linker.Options.Update && Op.getCode() == dwarf::DW_OP_addrx) {
if (std::optional<object::SectionedAddress> 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<uint8_t> AddressBytes(
reinterpret_cast<const uint8_t *>(&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<object::SectionedAddress> 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<uint8_t> 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<uint8_t> AddressBytes(
reinterpret_cast<const uint8_t *>(&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<DWARFLocationExpressionsVector> 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<uint8_t> &SrcBytes,
SmallVectorImpl<uint8_t> &OutBytes) {
SmallVectorImpl<uint8_t> &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);
}

View File

@@ -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,

View File

@@ -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] =

Binary file not shown.

View File

@@ -0,0 +1,47 @@
## This test checks that DW_OP_addrx expression operand
## is correctly recognized and converted into the DW_OP_addr
## operand or just preserved in case --update.
## cat dwarf5-dw-op-addrx.c
## $ clang -gdwarf-5 dwarf5-dw-op-addrx.c -c -O2 -o dwarf5-dw-op-addrx.o
#RUN: dsymutil -oso-prepend-path %p/../Inputs -y %s -o %t.dSYM
#RUN: llvm-dwarfdump --verify %t.dSYM | FileCheck %s
#RUN: llvm-dwarfdump -a --verbose %t.dSYM | FileCheck %s --check-prefix DWARF-CHECK
#RUN: dsymutil --update -oso-prepend-path %p/../Inputs -y %s -o %t.dSYM
#RUN: llvm-dwarfdump --verify %t.dSYM | FileCheck %s
#RUN: llvm-dwarfdump -a --verbose %t.dSYM | FileCheck %s --check-prefix UPD-DWARF-CHECK
#CHECK: No errors.
#DWARF-CHECK: DW_TAG_compile_unit
#DWARF-CHECK: DW_AT_name {{.*}}"dwarf5-dw-op-addrx.c"
#DWARF-CHECK: DW_AT_low_pc {{.*}}0x0000000100000fb0
#DWARF-CHECK: DW_TAG_variable
#DWARF-CHECK: DW_AT_name {{.*}}"arr"
#DWARF-CHECK: DW_AT_location {{.*}}(DW_OP_addr 0x100002000)
#DWARF-CHECK-NOT: .debug_addr
#UPD-DWARF-CHECK: DW_TAG_compile_unit
#UPD-DWARF-CHECK: DW_AT_name {{.*}}"dwarf5-dw-op-addrx.c"
#UPD-DWARF-CHECK: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000001) address = 0x0000000000000000)
#UPD-DWARF-CHECK: DW_AT_high_pc [DW_FORM_data4] (0x00000008)
#UPD-DWARF-CHECK: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000008)
#UPD-DWARF-CHECK: DW_TAG_variable
#UPD-DWARF-CHECK: DW_AT_name {{.*}}"arr"
#UPD-DWARF-CHECK: DW_AT_location [DW_FORM_exprloc] (DW_OP_addrx 0x0)
#UPD-DWARF-CHECK: .debug_addr contents:
#UPD-DWARF-CHECK: 0x00000000: Address table header: length = 0x00000014, format = DWARF32, version = 0x0005, addr_size = 0x08, seg_size = 0x00
#UPD-DWARF-CHECK: 0x0000000000000000
#UPD-DWARF-CHECK: 0x0000000000000000
---
triple: 'x86_64-apple-darwin'
objects:
- filename: 'dwarf5-dw-op-addrx.o'
timestamp: 1676048242
symbols:
- { sym: _main, objAddr: 0x0000000000000000, binAddr: 0x0000000100000FB0, size: 0x00000008 }
- { sym: _arr, binAddr: 0x0000000100002000, size: 0x00000000 }

View File

@@ -34,12 +34,12 @@ OBJ: DW_AT_location (DW_OP_breg2 RCX+0, DW_OP_constu 0x
OBJ: DW_AT_name ("b")
OBJ: DW_AT_type (0x000000af "_Bool")
DSYM: 0x0000008d: DW_TAG_base_type
DSYM: 0x000000ae: DW_TAG_base_type
DSYM: DW_AT_name ("DW_ATE_unsigned_1")
DSYM: DW_AT_encoding (DW_ATE_unsigned)
DSYM: DW_AT_byte_size (0x01)
DSYM: 0x000000b4: DW_TAG_formal_parameter
DSYM: DW_AT_location (DW_OP_breg2 RCX+0, DW_OP_constu 0xff, DW_OP_and, DW_OP_convert (0x0000008d) "DW_ATE_unsigned_1", DW_OP_convert (0x00000094) "DW_ATE_unsigned_8", DW_OP_stack_value)
DSYM: 0x000000d5: DW_TAG_formal_parameter
DSYM: DW_AT_location (DW_OP_breg2 RCX+0, DW_OP_constu 0xff, DW_OP_and, DW_OP_convert (0x000000ae) "DW_ATE_unsigned_1", DW_OP_convert (0x000000b5) "DW_ATE_unsigned_8", DW_OP_stack_value)
DSYM: DW_AT_name ("b")
DSYM: DW_AT_type (0x000000d2 "_Bool")
DSYM: DW_AT_type (0x000000f3 "_Bool")

View File

@@ -1,6 +1,11 @@
## Test that DWARFv5 DW_FORM_addrx is correctly recognized
## and converted into the DW_FORM_addr in --garbage-collection
## case or correctly preserved in --no-garbage-collection case.
## Test that DWARFv5 address attributes and address expression operands
## are handled correctly, specifically:
## 1. DW_FORM_addrx is correctly recognized and converted into the DW_FORM_addr
## in --garbage-collection case or correctly preserved in --no-garbage-collection case.
## 2. DW_OP_addrx is correctly recognized and converted into the DW_OP_addr
## in --garbage-collection case or correctly preserved in --no-garbage-collection case.
## 3. DW_OP_constx is correctly recognized and converted into the DW_OP_const[*]u
## in --garbage-collection case or correctly preserved in --no-garbage-collection case.
# RUN: yaml2obj %s -o %t.o
@@ -46,6 +51,18 @@
#DWARF-CHECK: DW_AT_name [DW_FORM_strp] {{.*}} "foo6"
#DWARF-CHECK: DW_AT_low_pc [DW_FORM_addr] (0x0000000000001180)
#DWARF-CHECK: DW_AT_high_pc [DW_FORM_data8] (0x0000000000000010)
#DWARF-CHECK: DW_TAG_variable
#DWARF-CHECK: DW_AT_name [DW_FORM_strp] {{.*}} "var1"
#DWARF-CHECK: DW_AT_location [DW_FORM_exprloc] (DW_OP_addr 0x2000)
#DWARF-CHECK: DW_TAG_variable
#DWARF-CHECK: DW_AT_name [DW_FORM_strp] {{.*}} "var2"
#DWARF-CHECK: DW_AT_location [DW_FORM_exprloc] (DW_OP_addr 0x2000)
#DWARF-CHECK: DW_TAG_variable
#DWARF-CHECK: DW_AT_name [DW_FORM_strp] {{.*}} "var3"
#DWARF-CHECK: DW_AT_location [DW_FORM_exprloc] (DW_OP_const8u 0x2000, DW_OP_form_tls_address)
#DWARF-CHECK: DW_TAG_variable
#DWARF-CHECK: DW_AT_name [DW_FORM_strp] {{.*}} "var4"
#DWARF-CHECK: DW_AT_location [DW_FORM_exprloc] (DW_OP_const8u 0x2000, DW_OP_form_tls_address)
#DWARF-CHECK=NOT: .debug_addr contents:
#UPD-DWARF-CHECK: DW_TAG_compile_unit
@@ -76,8 +93,20 @@
#UPD-DWARF-CHECK: DW_AT_name {{.*}}"foo6"
#UPD-DWARF-CHECK: DW_AT_low_pc [DW_FORM_addrx4] (indexed (00000005) address = 0x0000000000001180)
#UPD-DWARF-CHECK: DW_AT_high_pc [DW_FORM_data8] (0x0000000000000010)
#UPD-DWARF-CHECK: DW_TAG_variable
#UPD-DWARF-CHECK: DW_AT_name {{.*}}"var1"
#UPD-DWARF-CHECK: DW_AT_location [DW_FORM_exprloc] (DW_OP_addrx 0x6)
#UPD-DWARF-CHECK: DW_TAG_variable
#UPD-DWARF-CHECK: DW_AT_name {{.*}}"var2"
#UPD-DWARF-CHECK: DW_AT_location [DW_FORM_exprloc] (DW_OP_addr 0x2000)
#UPD-DWARF-CHECK: DW_TAG_variable
#UPD-DWARF-CHECK: DW_AT_name {{.*}}"var3"
#UPD-DWARF-CHECK: DW_AT_location [DW_FORM_exprloc] (DW_OP_constx 0x6, DW_OP_form_tls_address)
#UPD-DWARF-CHECK: DW_TAG_variable
#UPD-DWARF-CHECK: DW_AT_name {{.*}}"var4"
#UPD-DWARF-CHECK: DW_AT_location [DW_FORM_exprloc] (DW_OP_const8u 0x2000, DW_OP_form_tls_address)
#UPD-DWARF-CHECK: .debug_addr contents:
#UPD-DWARF-CHECK: 0x00000000: Address table header: length = 0x00000034, format = DWARF32, version = 0x0005, addr_size = 0x08, seg_size = 0x00
#UPD-DWARF-CHECK: 0x00000000: Address table header: length = 0x0000003c, format = DWARF32, version = 0x0005, addr_size = 0x08, seg_size = 0x00
#UPD-DWARF-CHECK: Addrs: [
#UPD-DWARF-CHECK: 0x0000000000001130
#UPD-DWARF-CHECK: 0x0000000000001140
@@ -85,6 +114,7 @@
#UPD-DWARF-CHECK: 0x0000000000001160
#UPD-DWARF-CHECK: 0x0000000000001170
#UPD-DWARF-CHECK: 0x0000000000001180
#UPD-DWARF-CHECK: 0x0000000000002000
#UPD-DWARF-CHECK: ]
--- !ELF
@@ -98,7 +128,7 @@ Sections:
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
Address: 0x1130
Size: 0x60
Size: 0x1000
DWARF:
debug_abbrev:
- Table:
@@ -166,6 +196,15 @@ DWARF:
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_type
Form: DW_FORM_ref4
- Attribute: DW_AT_location
Form: DW_FORM_exprloc
debug_info:
- Version: 5
UnitType: DW_UT_compile
@@ -223,6 +262,50 @@ DWARF:
- AbbrCode: 6
Values:
- CStr: int
- AbbrCode: 7
Values:
- CStr: var1
- Value: 0xa4
- BlockData:
- 0xa1
- 0x6
- AbbrCode: 7
Values:
- CStr: var2
- Value: 0xa4
- BlockData:
- 0x03
- 0x00
- 0x20
- 0x00
- 0x00
- 0x00
- 0x00
- 0x00
- 0x00
- AbbrCode: 7
Values:
- CStr: var3
- Value: 0xa4
- BlockData:
- 0xa2
- 0x6
- 0x9b
- AbbrCode: 7
Values:
- CStr: var4
- Value: 0xa4
- BlockData:
- 0x0e
- 0x00
- 0x20
- 0x00
- 0x00
- 0x00
- 0x00
- 0x00
- 0x00
- 0x9b
- AbbrCode: 0
debug_addr:
- Version: 5
@@ -234,4 +317,5 @@ DWARF:
- Address: 0x1160
- Address: 0x1170
- Address: 0x1180
- Address: 0x2000
...

View File

@@ -40,6 +40,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 "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/DebugInfo/DWARF/DWARFSection.h"
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
@@ -985,23 +986,27 @@ getAttributeOffsets(const DWARFAbbreviationDeclaration *Abbrev, unsigned Idx,
}
std::optional<int64_t>
DwarfLinkerForBinary::AddressManager::getVariableRelocAdjustment(
const DWARFDie &DIE) {
const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
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;
}
std::optional<uint32_t> 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());
// FIXME: Support relocations debug_addr.
return hasValidRelocationAt(ValidDebugInfoRelocs, LocationOffset,
LocationEndOffset);
return std::nullopt;
}
std::optional<int64_t>

View File

@@ -177,8 +177,9 @@ private:
hasValidRelocationAt(const std::vector<ValidReloc> &Relocs,
uint64_t StartOffset, uint64_t EndOffset);
std::optional<int64_t>
getVariableRelocAdjustment(const DWARFDie &DIE) override;
std::optional<int64_t> getExprOpAddressRelocAdjustment(
DWARFUnit &U, const DWARFExpression::Operation &Op,
uint64_t StartOffset, uint64_t EndOffset) override;
std::optional<int64_t>
getSubprogramRelocAdjustment(const DWARFDie &DIE) override;

View File

@@ -88,38 +88,33 @@ public:
return std::nullopt;
}
std::optional<int64_t>
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<DWARFLocationExpressionsVector> 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<int64_t> 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<object::SectionedAddress> 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;