diff options
Diffstat (limited to 'llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp')
-rw-r--r-- | llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp | 231 |
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 |