forked from OSchip/llvm-project
[DebugInfo] Fix handling DW_OP_call_ref in DWARF64 units.
DW_OP_call_ref is the only operation that has an operand which depends on the DWARF format. The patch fixes handling that operation in DWARF64 units. Differential Revision: https://reviews.llvm.org/D79501
This commit is contained in:
parent
050c9dd43a
commit
989ae9e848
|
@ -12,6 +12,8 @@
|
||||||
#include "llvm/ADT/ArrayRef.h"
|
#include "llvm/ADT/ArrayRef.h"
|
||||||
#include "llvm/ADT/iterator.h"
|
#include "llvm/ADT/iterator.h"
|
||||||
#include "llvm/ADT/iterator_range.h"
|
#include "llvm/ADT/iterator_range.h"
|
||||||
|
#include "llvm/ADT/Optional.h"
|
||||||
|
#include "llvm/BinaryFormat/Dwarf.h"
|
||||||
#include "llvm/Support/DataExtractor.h"
|
#include "llvm/Support/DataExtractor.h"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
@ -88,7 +90,8 @@ public:
|
||||||
uint64_t getRawOperand(unsigned Idx) { return Operands[Idx]; }
|
uint64_t getRawOperand(unsigned Idx) { return Operands[Idx]; }
|
||||||
uint64_t getOperandEndOffset(unsigned Idx) { return OperandEndOffsets[Idx]; }
|
uint64_t getOperandEndOffset(unsigned Idx) { return OperandEndOffsets[Idx]; }
|
||||||
uint64_t getEndOffset() { return EndOffset; }
|
uint64_t getEndOffset() { return EndOffset; }
|
||||||
bool extract(DataExtractor Data, uint8_t AddressSize, uint64_t Offset);
|
bool extract(DataExtractor Data, uint8_t AddressSize, uint64_t Offset,
|
||||||
|
Optional<dwarf::DwarfFormat> Format);
|
||||||
bool isError() { return Error; }
|
bool isError() { return Error; }
|
||||||
bool print(raw_ostream &OS, const DWARFExpression *Expr,
|
bool print(raw_ostream &OS, const DWARFExpression *Expr,
|
||||||
const MCRegisterInfo *RegInfo, DWARFUnit *U, bool isEH);
|
const MCRegisterInfo *RegInfo, DWARFUnit *U, bool isEH);
|
||||||
|
@ -107,7 +110,7 @@ public:
|
||||||
: Expr(Expr), Offset(Offset) {
|
: Expr(Expr), Offset(Offset) {
|
||||||
Op.Error =
|
Op.Error =
|
||||||
Offset >= Expr->Data.getData().size() ||
|
Offset >= Expr->Data.getData().size() ||
|
||||||
!Op.extract(Expr->Data, Expr->AddressSize, Offset);
|
!Op.extract(Expr->Data, Expr->AddressSize, Offset, Expr->Format);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -115,7 +118,7 @@ public:
|
||||||
Offset = Op.isError() ? Expr->Data.getData().size() : Op.EndOffset;
|
Offset = Op.isError() ? Expr->Data.getData().size() : Op.EndOffset;
|
||||||
Op.Error =
|
Op.Error =
|
||||||
Offset >= Expr->Data.getData().size() ||
|
Offset >= Expr->Data.getData().size() ||
|
||||||
!Op.extract(Expr->Data, Expr->AddressSize, Offset);
|
!Op.extract(Expr->Data, Expr->AddressSize, Offset, Expr->Format);
|
||||||
return Op;
|
return Op;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,8 +130,9 @@ public:
|
||||||
friend bool operator==(const iterator &, const iterator &);
|
friend bool operator==(const iterator &, const iterator &);
|
||||||
};
|
};
|
||||||
|
|
||||||
DWARFExpression(DataExtractor Data, uint8_t AddressSize)
|
DWARFExpression(DataExtractor Data, uint8_t AddressSize,
|
||||||
: Data(Data), AddressSize(AddressSize) {
|
Optional<dwarf::DwarfFormat> Format = None)
|
||||||
|
: Data(Data), AddressSize(AddressSize), Format(Format) {
|
||||||
assert(AddressSize == 8 || AddressSize == 4 || AddressSize == 2);
|
assert(AddressSize == 8 || AddressSize == 4 || AddressSize == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,6 +147,7 @@ public:
|
||||||
private:
|
private:
|
||||||
DataExtractor Data;
|
DataExtractor Data;
|
||||||
uint8_t AddressSize;
|
uint8_t AddressSize;
|
||||||
|
Optional<dwarf::DwarfFormat> Format;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool operator==(const DWARFExpression::iterator &LHS,
|
inline bool operator==(const DWARFExpression::iterator &LHS,
|
||||||
|
|
|
@ -2337,7 +2337,7 @@ void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer,
|
||||||
DWARFDataExtractor Data(StringRef(DebugLocs.getBytes(Entry).data(),
|
DWARFDataExtractor Data(StringRef(DebugLocs.getBytes(Entry).data(),
|
||||||
DebugLocs.getBytes(Entry).size()),
|
DebugLocs.getBytes(Entry).size()),
|
||||||
Asm->getDataLayout().isLittleEndian(), PtrSize);
|
Asm->getDataLayout().isLittleEndian(), PtrSize);
|
||||||
DWARFExpression Expr(Data, PtrSize);
|
DWARFExpression Expr(Data, PtrSize, Asm->OutContext.getDwarfFormat());
|
||||||
|
|
||||||
using Encoding = DWARFExpression::Operation::Encoding;
|
using Encoding = DWARFExpression::Operation::Encoding;
|
||||||
uint64_t Offset = 0;
|
uint64_t Offset = 0;
|
||||||
|
|
|
@ -1008,7 +1008,8 @@ unsigned DWARFLinker::DIECloner::cloneBlockAttribute(
|
||||||
DWARFUnit &OrigUnit = Unit.getOrigUnit();
|
DWARFUnit &OrigUnit = Unit.getOrigUnit();
|
||||||
DataExtractor Data(StringRef((const char *)Bytes.data(), Bytes.size()),
|
DataExtractor Data(StringRef((const char *)Bytes.data(), Bytes.size()),
|
||||||
IsLittleEndian, OrigUnit.getAddressByteSize());
|
IsLittleEndian, OrigUnit.getAddressByteSize());
|
||||||
DWARFExpression Expr(Data, OrigUnit.getAddressByteSize());
|
DWARFExpression Expr(Data, OrigUnit.getAddressByteSize(),
|
||||||
|
OrigUnit.getFormParams().Format);
|
||||||
cloneExpression(Data, Expr, File, Unit, Buffer);
|
cloneExpression(Data, Expr, File, Unit, Buffer);
|
||||||
Bytes = Buffer;
|
Bytes = Buffer;
|
||||||
}
|
}
|
||||||
|
@ -2134,7 +2135,8 @@ uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits(
|
||||||
DataExtractor Data(Bytes, IsLittleEndian,
|
DataExtractor Data(Bytes, IsLittleEndian,
|
||||||
OrigUnit.getAddressByteSize());
|
OrigUnit.getAddressByteSize());
|
||||||
cloneExpression(Data,
|
cloneExpression(Data,
|
||||||
DWARFExpression(Data, OrigUnit.getAddressByteSize()),
|
DWARFExpression(Data, OrigUnit.getAddressByteSize(),
|
||||||
|
OrigUnit.getFormParams().Format),
|
||||||
File, *CurrentUnit, Buffer);
|
File, *CurrentUnit, Buffer);
|
||||||
};
|
};
|
||||||
Emitter->emitLocationsForUnit(*CurrentUnit, DwarfContext, ProcessExpr);
|
Emitter->emitLocationsForUnit(*CurrentUnit, DwarfContext, ProcessExpr);
|
||||||
|
|
|
@ -130,6 +130,9 @@ Error CFIProgram::parse(DWARFDataExtractor Data, uint64_t *Offset,
|
||||||
DataExtractor Extractor(
|
DataExtractor Extractor(
|
||||||
Data.getData().slice(*Offset, *Offset + ExprLength),
|
Data.getData().slice(*Offset, *Offset + ExprLength),
|
||||||
Data.isLittleEndian(), Data.getAddressSize());
|
Data.isLittleEndian(), Data.getAddressSize());
|
||||||
|
// Note. We do not pass the DWARF format to DWARFExpression, because
|
||||||
|
// DW_OP_call_ref, the only operation which depends on the format, is
|
||||||
|
// prohibited in call frame instructions, see sec. 6.4.2 in DWARFv5.
|
||||||
Instructions.back().Expression =
|
Instructions.back().Expression =
|
||||||
DWARFExpression(Extractor, Data.getAddressSize());
|
DWARFExpression(Extractor, Data.getAddressSize());
|
||||||
*Offset += ExprLength;
|
*Offset += ExprLength;
|
||||||
|
@ -143,6 +146,9 @@ Error CFIProgram::parse(DWARFDataExtractor Data, uint64_t *Offset,
|
||||||
DataExtractor Extractor(
|
DataExtractor Extractor(
|
||||||
Data.getData().slice(*Offset, *Offset + BlockLength),
|
Data.getData().slice(*Offset, *Offset + BlockLength),
|
||||||
Data.isLittleEndian(), Data.getAddressSize());
|
Data.isLittleEndian(), Data.getAddressSize());
|
||||||
|
// Note. We do not pass the DWARF format to DWARFExpression, because
|
||||||
|
// DW_OP_call_ref, the only operation which depends on the format, is
|
||||||
|
// prohibited in call frame instructions, see sec. 6.4.2 in DWARFv5.
|
||||||
Instructions.back().Expression =
|
Instructions.back().Expression =
|
||||||
DWARFExpression(Extractor, Data.getAddressSize());
|
DWARFExpression(Extractor, Data.getAddressSize());
|
||||||
*Offset += BlockLength;
|
*Offset += BlockLength;
|
||||||
|
|
|
@ -110,6 +110,10 @@ static void dumpExpression(raw_ostream &OS, ArrayRef<uint8_t> Data,
|
||||||
bool IsLittleEndian, unsigned AddressSize,
|
bool IsLittleEndian, unsigned AddressSize,
|
||||||
const MCRegisterInfo *MRI, DWARFUnit *U) {
|
const MCRegisterInfo *MRI, DWARFUnit *U) {
|
||||||
DWARFDataExtractor Extractor(Data, IsLittleEndian, AddressSize);
|
DWARFDataExtractor Extractor(Data, IsLittleEndian, AddressSize);
|
||||||
|
// Note. We do not pass any format to DWARFExpression, even if the
|
||||||
|
// corresponding unit is known. For now, there is only one operation,
|
||||||
|
// DW_OP_call_ref, which depends on the format; it is rarely used, and
|
||||||
|
// is unexpected in location tables.
|
||||||
DWARFExpression(Extractor, AddressSize).print(OS, MRI, U);
|
DWARFExpression(Extractor, AddressSize).print(OS, MRI, U);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,8 @@ static void dumpLocation(raw_ostream &OS, DWARFFormValue &FormValue,
|
||||||
ArrayRef<uint8_t> Expr = *FormValue.getAsBlock();
|
ArrayRef<uint8_t> Expr = *FormValue.getAsBlock();
|
||||||
DataExtractor Data(StringRef((const char *)Expr.data(), Expr.size()),
|
DataExtractor Data(StringRef((const char *)Expr.data(), Expr.size()),
|
||||||
Ctx.isLittleEndian(), 0);
|
Ctx.isLittleEndian(), 0);
|
||||||
DWARFExpression(Data, U->getAddressByteSize()).print(OS, MRI, U);
|
DWARFExpression(Data, U->getAddressByteSize(), U->getFormParams().Format)
|
||||||
|
.print(OS, MRI, U);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
|
#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
|
||||||
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
|
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
|
||||||
#include "llvm/BinaryFormat/Dwarf.h"
|
|
||||||
#include "llvm/MC/MCRegisterInfo.h"
|
#include "llvm/MC/MCRegisterInfo.h"
|
||||||
#include "llvm/Support/Format.h"
|
#include "llvm/Support/Format.h"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
@ -119,7 +118,8 @@ static DWARFExpression::Operation::Description getOpDesc(unsigned OpCode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DWARFExpression::Operation::extract(DataExtractor Data,
|
bool DWARFExpression::Operation::extract(DataExtractor Data,
|
||||||
uint8_t AddressSize, uint64_t Offset) {
|
uint8_t AddressSize, uint64_t Offset,
|
||||||
|
Optional<DwarfFormat> Format) {
|
||||||
Opcode = Data.getU8(&Offset);
|
Opcode = Data.getU8(&Offset);
|
||||||
|
|
||||||
Desc = getOpDesc(Opcode);
|
Desc = getOpDesc(Opcode);
|
||||||
|
@ -158,8 +158,10 @@ bool DWARFExpression::Operation::extract(DataExtractor Data,
|
||||||
Operands[Operand] = Data.getUnsigned(&Offset, AddressSize);
|
Operands[Operand] = Data.getUnsigned(&Offset, AddressSize);
|
||||||
break;
|
break;
|
||||||
case Operation::SizeRefAddr:
|
case Operation::SizeRefAddr:
|
||||||
// TODO: Add support for 64-bit DWARF format.
|
if (!Format)
|
||||||
Operands[Operand] = Data.getU32(&Offset);
|
return false;
|
||||||
|
Operands[Operand] =
|
||||||
|
Data.getUnsigned(&Offset, dwarf::getDwarfOffsetByteSize(*Format));
|
||||||
break;
|
break;
|
||||||
case Operation::SizeLEB:
|
case Operation::SizeLEB:
|
||||||
if (Signed)
|
if (Signed)
|
||||||
|
|
|
@ -486,7 +486,8 @@ unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die,
|
||||||
DWARFUnit *U = Die.getDwarfUnit();
|
DWARFUnit *U = Die.getDwarfUnit();
|
||||||
for (const auto &Entry : *Loc) {
|
for (const auto &Entry : *Loc) {
|
||||||
DataExtractor Data(toStringRef(Entry.Expr), DCtx.isLittleEndian(), 0);
|
DataExtractor Data(toStringRef(Entry.Expr), DCtx.isLittleEndian(), 0);
|
||||||
DWARFExpression Expression(Data, U->getAddressByteSize());
|
DWARFExpression Expression(Data, U->getAddressByteSize(),
|
||||||
|
U->getFormParams().Format);
|
||||||
bool Error = any_of(Expression, [](DWARFExpression::Operation &Op) {
|
bool Error = any_of(Expression, [](DWARFExpression::Operation &Op) {
|
||||||
return Op.isError();
|
return Op.isError();
|
||||||
});
|
});
|
||||||
|
@ -1294,7 +1295,8 @@ static bool isVariableIndexable(const DWARFDie &Die, DWARFContext &DCtx) {
|
||||||
for (const auto &Entry : *Loc) {
|
for (const auto &Entry : *Loc) {
|
||||||
DataExtractor Data(toStringRef(Entry.Expr), DCtx.isLittleEndian(),
|
DataExtractor Data(toStringRef(Entry.Expr), DCtx.isLittleEndian(),
|
||||||
U->getAddressByteSize());
|
U->getAddressByteSize());
|
||||||
DWARFExpression Expression(Data, U->getAddressByteSize());
|
DWARFExpression Expression(Data, U->getAddressByteSize(),
|
||||||
|
U->getFormParams().Format);
|
||||||
bool IsInteresting = any_of(Expression, [](DWARFExpression::Operation &Op) {
|
bool IsInteresting = any_of(Expression, [](DWARFExpression::Operation &Op) {
|
||||||
return !Op.isError() && (Op.getCode() == DW_OP_addr ||
|
return !Op.isError() && (Op.getCode() == DW_OP_addr ||
|
||||||
Op.getCode() == DW_OP_form_tls_address ||
|
Op.getCode() == DW_OP_form_tls_address ||
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
# RUN: llvm-mc -triple x86_64 %s -filetype=obj -o %t.o
|
||||||
|
# RUN: llvm-dwarfdump -debug-info %t.o | FileCheck %s
|
||||||
|
# RUN: llvm-dwarfdump -verify %t.o | FileCheck %s --check-prefix=VERIFY
|
||||||
|
|
||||||
|
# CHECK: DW_TAG_variable
|
||||||
|
# CHECK-NEXT: DW_AT_location (DW_OP_call_ref 0x1100223344)
|
||||||
|
|
||||||
|
# VERIFY-NOT: error: DIE contains invalid DWARF expression:
|
||||||
|
# VERIFY: No errors.
|
||||||
|
|
||||||
|
.section .debug_abbrev,"",@progbits
|
||||||
|
.uleb128 1 # Abbreviation Code
|
||||||
|
.uleb128 17 # DW_TAG_compile_unit
|
||||||
|
.byte 1 # DW_CHILDREN_yes
|
||||||
|
.byte 0 # EOM(1)
|
||||||
|
.byte 0 # EOM(2)
|
||||||
|
.uleb128 5 # Abbreviation Code
|
||||||
|
.uleb128 52 # DW_TAG_variable
|
||||||
|
.byte 0 # DW_CHILDREN_no
|
||||||
|
.uleb128 2 # DW_AT_location
|
||||||
|
.uleb128 24 # DW_FORM_exprloc
|
||||||
|
.byte 0 # EOM(1)
|
||||||
|
.byte 0 # EOM(2)
|
||||||
|
.byte 0 # EOM(3)
|
||||||
|
|
||||||
|
.section .debug_info,"",@progbits
|
||||||
|
.long 0xffffffff # DWARF64 mark
|
||||||
|
.quad .Lcu_end-.Lcu_start # Length of Unit
|
||||||
|
.Lcu_start:
|
||||||
|
.short 5 # DWARF version number
|
||||||
|
.byte 1 # DW_UT_compile
|
||||||
|
.byte 8 # Address Size
|
||||||
|
.quad .debug_abbrev # Offset Into Abbrev. Section
|
||||||
|
.uleb128 1 # Abbrev [1] DW_TAG_compile_unit
|
||||||
|
.uleb128 5 # Abbrev [5] DW_TAG_variable
|
||||||
|
.byte .Lloc_end-.Lloc_begin # DW_AT_location
|
||||||
|
.Lloc_begin:
|
||||||
|
.byte 154 # DW_OP_call_ref
|
||||||
|
.quad 0x1100223344 # Offset
|
||||||
|
.Lloc_end:
|
||||||
|
.byte 0 # End Of Children Mark
|
||||||
|
.Lcu_end:
|
|
@ -0,0 +1,29 @@
|
||||||
|
# RUN: llvm-mc -triple x86_64 %s -filetype=obj -o - | \
|
||||||
|
# RUN: llvm-dwarfdump -debug-loc - | \
|
||||||
|
# RUN: FileCheck %s
|
||||||
|
|
||||||
|
# This checks that we do not try to interpret DW_OP_call_ref if it is
|
||||||
|
# encountered in a location table.
|
||||||
|
|
||||||
|
# CHECK: .debug_loc contents:
|
||||||
|
# CHECK-NEXT: 0x00000000:
|
||||||
|
# CHECK-NEXT: (0x0000000000000000, 0x0000000000000015): <decoding error> 9a ff 00 00 00
|
||||||
|
|
||||||
|
.section .debug_loc, "", @progbits
|
||||||
|
.quad 0 # Beginning address offset
|
||||||
|
.quad 0x15 # Ending address offset
|
||||||
|
.short .LDescrEnd-.LDescrBegin # Location description length
|
||||||
|
.LDescrBegin:
|
||||||
|
.byte 0x9a # DW_OP_call_ref
|
||||||
|
.long 0xff
|
||||||
|
.LDescrEnd:
|
||||||
|
.quad 0, 0 # EOL entry
|
||||||
|
|
||||||
|
# A dummy CU to provide the parser of .debug_loc with the address size.
|
||||||
|
.section .debug_info,"",@progbits
|
||||||
|
.long .LCUEnd-.LCUBegin # Length of Unit
|
||||||
|
.LCUBegin:
|
||||||
|
.short 4 # DWARF version number
|
||||||
|
.long 0 # Offset Into Abbrev. Section
|
||||||
|
.byte 8 # Address Size
|
||||||
|
.LCUEnd:
|
|
@ -248,7 +248,8 @@ static void collectStatsForDie(DWARFDie Die, std::string FnPrefix,
|
||||||
DWARFUnit *U = Die.getDwarfUnit();
|
DWARFUnit *U = Die.getDwarfUnit();
|
||||||
DataExtractor Data(toStringRef(D),
|
DataExtractor Data(toStringRef(D),
|
||||||
Die.getDwarfUnit()->getContext().isLittleEndian(), 0);
|
Die.getDwarfUnit()->getContext().isLittleEndian(), 0);
|
||||||
DWARFExpression Expression(Data, U->getAddressByteSize());
|
DWARFExpression Expression(Data, U->getAddressByteSize(),
|
||||||
|
U->getFormParams().Format);
|
||||||
// Consider the expression containing the DW_OP_entry_value as
|
// Consider the expression containing the DW_OP_entry_value as
|
||||||
// an entry value.
|
// an entry value.
|
||||||
return llvm::any_of(Expression, [](DWARFExpression::Operation &Op) {
|
return llvm::any_of(Expression, [](DWARFExpression::Operation &Op) {
|
||||||
|
|
Loading…
Reference in New Issue