aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp')
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp231
1 files changed, 192 insertions, 39 deletions
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
index 7d817d8a9925..de5e11e084f4 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
@@ -8,7 +8,6 @@
#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
-#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/Support/Format.h"
#include <cassert>
@@ -94,7 +93,7 @@ static DescVector getDescriptions() {
Desc(Op::Dwarf3, Op::SizeLEB, Op::SizeBlock);
Descriptions[DW_OP_stack_value] = Desc(Op::Dwarf3);
Descriptions[DW_OP_WASM_location] =
- Desc(Op::Dwarf4, Op::SizeLEB, Op::SignedSizeLEB);
+ 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);
@@ -103,6 +102,8 @@ static DescVector getDescriptions() {
Descriptions[DW_OP_convert] = Desc(Op::Dwarf5, Op::BaseTypeRef);
Descriptions[DW_OP_entry_value] = Desc(Op::Dwarf5, Op::SizeLEB);
+ Descriptions[DW_OP_regval_type] =
+ Desc(Op::Dwarf5, Op::SizeLEB, Op::BaseTypeRef);
return Descriptions;
}
@@ -116,19 +117,15 @@ static DWARFExpression::Operation::Description getOpDesc(unsigned OpCode) {
return Descriptions[OpCode];
}
-static uint8_t getRefAddrSize(uint8_t AddrSize, uint16_t Version) {
- return (Version == 2) ? AddrSize : 4;
-}
-
-bool DWARFExpression::Operation::extract(DataExtractor Data, uint16_t Version,
- uint8_t AddressSize, uint64_t Offset) {
+bool DWARFExpression::Operation::extract(DataExtractor Data,
+ uint8_t AddressSize, uint64_t Offset,
+ Optional<DwarfFormat> Format) {
+ EndOffset = Offset;
Opcode = Data.getU8(&Offset);
Desc = getOpDesc(Opcode);
- if (Desc.Version == Operation::DwarfNA) {
- EndOffset = Offset;
+ if (Desc.Version == Operation::DwarfNA)
return false;
- }
for (unsigned Operand = 0; Operand < 2; ++Operand) {
unsigned Size = Desc.Op[Operand];
@@ -157,24 +154,13 @@ bool DWARFExpression::Operation::extract(DataExtractor Data, uint16_t Version,
Operands[Operand] = Data.getU64(&Offset);
break;
case Operation::SizeAddr:
- if (AddressSize == 8) {
- Operands[Operand] = Data.getU64(&Offset);
- } else if (AddressSize == 4) {
- Operands[Operand] = Data.getU32(&Offset);
- } else {
- assert(AddressSize == 2);
- Operands[Operand] = Data.getU16(&Offset);
- }
+ Operands[Operand] = Data.getUnsigned(&Offset, AddressSize);
break;
case Operation::SizeRefAddr:
- if (getRefAddrSize(AddressSize, Version) == 8) {
- Operands[Operand] = Data.getU64(&Offset);
- } else if (getRefAddrSize(AddressSize, Version) == 4) {
- Operands[Operand] = Data.getU32(&Offset);
- } else {
- assert(getRefAddrSize(AddressSize, Version) == 2);
- Operands[Operand] = Data.getU16(&Offset);
- }
+ if (!Format)
+ return false;
+ Operands[Operand] =
+ Data.getUnsigned(&Offset, dwarf::getDwarfOffsetByteSize(*Format));
break;
case Operation::SizeLEB:
if (Signed)
@@ -185,6 +171,19 @@ bool DWARFExpression::Operation::extract(DataExtractor Data, uint16_t Version,
case Operation::BaseTypeRef:
Operands[Operand] = Data.getULEB128(&Offset);
break;
+ case Operation::WasmLocationArg:
+ assert(Operand == 1);
+ switch (Operands[0]) {
+ case 0: case 1: case 2:
+ Operands[Operand] = Data.getULEB128(&Offset);
+ break;
+ case 3: // global as uint32
+ Operands[Operand] = Data.getU32(&Offset);
+ break;
+ default:
+ return false; // Unknown Wasm location
+ }
+ break;
case Operation::SizeBlock:
// We need a size, so this cannot be the first operand
if (Operand == 0)
@@ -204,7 +203,21 @@ bool DWARFExpression::Operation::extract(DataExtractor Data, uint16_t Version,
return true;
}
-static bool prettyPrintRegisterOp(raw_ostream &OS, uint8_t Opcode,
+static void prettyPrintBaseTypeRef(DWARFUnit *U, raw_ostream &OS,
+ uint64_t Operands[2], unsigned Operand) {
+ assert(Operand < 2 && "operand out of bounds");
+ auto Die = U->getDIEForOffset(U->getOffset() + Operands[Operand]);
+ if (Die && Die.getTag() == dwarf::DW_TAG_base_type) {
+ OS << format(" (0x%08" PRIx64 ")", U->getOffset() + Operands[Operand]);
+ if (auto Name = Die.find(dwarf::DW_AT_name))
+ OS << " \"" << Name->getAsCString() << "\"";
+ } else {
+ OS << format(" <invalid base_type ref: 0x%" PRIx64 ">",
+ Operands[Operand]);
+ }
+}
+
+static bool prettyPrintRegisterOp(DWARFUnit *U, raw_ostream &OS, uint8_t Opcode,
uint64_t Operands[2],
const MCRegisterInfo *MRI, bool isEH) {
if (!MRI)
@@ -213,7 +226,8 @@ static bool prettyPrintRegisterOp(raw_ostream &OS, uint8_t Opcode,
uint64_t DwarfRegNum;
unsigned OpNum = 0;
- if (Opcode == DW_OP_bregx || Opcode == DW_OP_regx)
+ if (Opcode == DW_OP_bregx || Opcode == DW_OP_regx ||
+ Opcode == DW_OP_regval_type)
DwarfRegNum = Operands[OpNum++];
else if (Opcode >= DW_OP_breg0 && Opcode < DW_OP_bregx)
DwarfRegNum = Opcode - DW_OP_breg0;
@@ -227,6 +241,9 @@ static bool prettyPrintRegisterOp(raw_ostream &OS, uint8_t Opcode,
OS << format(" %s%+" PRId64, RegName, Operands[OpNum]);
else
OS << ' ' << RegName;
+
+ if (Opcode == DW_OP_regval_type)
+ prettyPrintBaseTypeRef(U, OS, Operands, 1);
return true;
}
}
@@ -250,8 +267,9 @@ bool DWARFExpression::Operation::print(raw_ostream &OS,
if ((Opcode >= DW_OP_breg0 && Opcode <= DW_OP_breg31) ||
(Opcode >= DW_OP_reg0 && Opcode <= DW_OP_reg31) ||
- Opcode == DW_OP_bregx || Opcode == DW_OP_regx)
- if (prettyPrintRegisterOp(OS, Opcode, Operands, RegInfo, isEH))
+ Opcode == DW_OP_bregx || Opcode == DW_OP_regx ||
+ Opcode == DW_OP_regval_type)
+ if (prettyPrintRegisterOp(U, OS, Opcode, Operands, RegInfo, isEH))
return true;
for (unsigned Operand = 0; Operand < 2; ++Operand) {
@@ -262,14 +280,21 @@ bool DWARFExpression::Operation::print(raw_ostream &OS,
break;
if (Size == Operation::BaseTypeRef && U) {
- auto Die = U->getDIEForOffset(U->getOffset() + Operands[Operand]);
- if (Die && Die.getTag() == dwarf::DW_TAG_base_type) {
- OS << format(" (0x%08" PRIx64 ")", U->getOffset() + Operands[Operand]);
- if (auto Name = Die.find(dwarf::DW_AT_name))
- OS << " \"" << Name->getAsCString() << "\"";
- } else {
- OS << format(" <invalid base_type ref: 0x%" PRIx64 ">",
- Operands[Operand]);
+ // For DW_OP_convert the operand may be 0 to indicate that conversion to
+ // the generic type should be done. The same holds for DW_OP_reinterpret,
+ // which is currently not supported.
+ if (Opcode == DW_OP_convert && Operands[Operand] == 0)
+ OS << " 0x0";
+ else
+ prettyPrintBaseTypeRef(U, OS, Operands, Operand);
+ } else if (Size == Operation::WasmLocationArg) {
+ assert(Operand == 1);
+ switch (Operands[0]) {
+ case 0: case 1: case 2:
+ case 3: // global as uint32
+ OS << format(" 0x%" PRIx64, Operands[Operand]);
+ break;
+ default: assert(false);
}
} else if (Size == Operation::SizeBlock) {
uint64_t Offset = Operands[Operand];
@@ -324,6 +349,12 @@ bool DWARFExpression::Operation::verify(DWARFUnit *U) {
break;
if (Size == Operation::BaseTypeRef) {
+ // For DW_OP_convert the operand may be 0 to indicate that conversion to
+ // the generic type should be done, so don't look up a base type in that
+ // case. The same holds for DW_OP_reinterpret, which is currently not
+ // supported.
+ if (Opcode == DW_OP_convert && Operands[Operand] == 0)
+ continue;
auto Die = U->getDIEForOffset(U->getOffset() + Operands[Operand]);
if (!Die || Die.getTag() != dwarf::DW_TAG_base_type) {
Error = true;
@@ -343,4 +374,126 @@ bool DWARFExpression::verify(DWARFUnit *U) {
return true;
}
+/// A user-facing string representation of a DWARF expression. This might be an
+/// Address expression, in which case it will be implicitly dereferenced, or a
+/// Value expression.
+struct PrintedExpr {
+ enum ExprKind {
+ Address,
+ Value,
+ };
+ ExprKind Kind;
+ SmallString<16> String;
+
+ PrintedExpr(ExprKind K = Address) : Kind(K) {}
+};
+
+static bool printCompactDWARFExpr(raw_ostream &OS, DWARFExpression::iterator I,
+ const DWARFExpression::iterator E,
+ const MCRegisterInfo &MRI) {
+ SmallVector<PrintedExpr, 4> Stack;
+
+ while (I != E) {
+ DWARFExpression::Operation &Op = *I;
+ uint8_t Opcode = Op.getCode();
+ switch (Opcode) {
+ case dwarf::DW_OP_regx: {
+ // DW_OP_regx: A register, with the register num given as an operand.
+ // Printed as the plain register name.
+ uint64_t DwarfRegNum = Op.getRawOperand(0);
+ Optional<unsigned> LLVMRegNum = MRI.getLLVMRegNum(DwarfRegNum, false);
+ if (!LLVMRegNum) {
+ OS << "<unknown register " << DwarfRegNum << ">";
+ return false;
+ }
+ raw_svector_ostream S(Stack.emplace_back(PrintedExpr::Value).String);
+ S << MRI.getName(*LLVMRegNum);
+ break;
+ }
+ case dwarf::DW_OP_bregx: {
+ int DwarfRegNum = Op.getRawOperand(0);
+ int64_t Offset = Op.getRawOperand(1);
+ Optional<unsigned> LLVMRegNum = MRI.getLLVMRegNum(DwarfRegNum, false);
+ if (!LLVMRegNum) {
+ OS << "<unknown register " << DwarfRegNum << ">";
+ return false;
+ }
+ raw_svector_ostream S(Stack.emplace_back().String);
+ S << MRI.getName(*LLVMRegNum);
+ if (Offset)
+ S << format("%+" PRId64, Offset);
+ break;
+ }
+ case dwarf::DW_OP_entry_value:
+ case dwarf::DW_OP_GNU_entry_value: {
+ // DW_OP_entry_value contains a sub-expression which must be rendered
+ // separately.
+ uint64_t SubExprLength = Op.getRawOperand(0);
+ DWARFExpression::iterator SubExprEnd = I.skipBytes(SubExprLength);
+ ++I;
+ raw_svector_ostream S(Stack.emplace_back().String);
+ S << "entry(";
+ printCompactDWARFExpr(S, I, SubExprEnd, MRI);
+ S << ")";
+ I = SubExprEnd;
+ continue;
+ }
+ case dwarf::DW_OP_stack_value: {
+ // The top stack entry should be treated as the actual value of tne
+ // variable, rather than the address of the variable in memory.
+ assert(!Stack.empty());
+ Stack.back().Kind = PrintedExpr::Value;
+ break;
+ }
+ default:
+ if (Opcode >= dwarf::DW_OP_reg0 && Opcode <= dwarf::DW_OP_reg31) {
+ // DW_OP_reg<N>: A register, with the register num implied by the
+ // opcode. Printed as the plain register name.
+ uint64_t DwarfRegNum = Opcode - dwarf::DW_OP_reg0;
+ Optional<unsigned> LLVMRegNum = MRI.getLLVMRegNum(DwarfRegNum, false);
+ if (!LLVMRegNum) {
+ OS << "<unknown register " << DwarfRegNum << ">";
+ return false;
+ }
+ raw_svector_ostream S(Stack.emplace_back(PrintedExpr::Value).String);
+ S << MRI.getName(*LLVMRegNum);
+ } else if (Opcode >= dwarf::DW_OP_breg0 &&
+ Opcode <= dwarf::DW_OP_breg31) {
+ int DwarfRegNum = Opcode - dwarf::DW_OP_breg0;
+ int64_t Offset = Op.getRawOperand(0);
+ Optional<unsigned> LLVMRegNum = MRI.getLLVMRegNum(DwarfRegNum, false);
+ if (!LLVMRegNum) {
+ OS << "<unknown register " << DwarfRegNum << ">";
+ return false;
+ }
+ raw_svector_ostream S(Stack.emplace_back().String);
+ S << MRI.getName(*LLVMRegNum);
+ if (Offset)
+ S << format("%+" PRId64, Offset);
+ } else {
+ // If we hit an unknown operand, we don't know its effect on the stack,
+ // so bail out on the whole expression.
+ OS << "<unknown op " << dwarf::OperationEncodingString(Opcode) << " ("
+ << (int)Opcode << ")>";
+ return false;
+ }
+ break;
+ }
+ ++I;
+ }
+
+ assert(Stack.size() == 1 && "expected one value on stack");
+
+ if (Stack.front().Kind == PrintedExpr::Address)
+ OS << "[" << Stack.front().String << "]";
+ else
+ OS << Stack.front().String;
+
+ return true;
+}
+
+bool DWARFExpression::printCompact(raw_ostream &OS, const MCRegisterInfo &MRI) {
+ return printCompactDWARFExpr(OS, begin(), end(), MRI);
+}
+
} // namespace llvm