Path: blob/main/contrib/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFExpressionPrinter.cpp
213799 views
//===-- DWARFExpression.cpp -----------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/DebugInfo/DWARF/DWARFExpressionPrinter.h"9#include "llvm/ADT/SmallString.h"10#include "llvm/DebugInfo/DWARF/DWARFUnit.h"11#include "llvm/DebugInfo/DWARF/LowLevel/DWARFExpression.h"12#include "llvm/Support/Format.h"13#include <cassert>14#include <cstdint>1516using namespace llvm;17using namespace dwarf;1819namespace llvm {2021typedef DWARFExpression::Operation Op;22typedef Op::Description Desc;2324static void prettyPrintBaseTypeRef(DWARFUnit *U, raw_ostream &OS,25DIDumpOptions DumpOpts,26ArrayRef<uint64_t> Operands,27unsigned Operand) {28assert(Operand < Operands.size() && "operand out of bounds");29if (!U) {30OS << format(" <base_type ref: 0x%" PRIx64 ">", Operands[Operand]);31return;32}33auto Die = U->getDIEForOffset(U->getOffset() + Operands[Operand]);34if (Die && Die.getTag() == dwarf::DW_TAG_base_type) {35OS << " (";36if (DumpOpts.Verbose)37OS << format("0x%08" PRIx64 " -> ", Operands[Operand]);38OS << format("0x%08" PRIx64 ")", U->getOffset() + Operands[Operand]);39if (auto Name = dwarf::toString(Die.find(dwarf::DW_AT_name)))40OS << " \"" << *Name << "\"";41} else {42OS << format(" <invalid base_type ref: 0x%" PRIx64 ">", Operands[Operand]);43}44}4546static bool printOp(const DWARFExpression::Operation *Op, raw_ostream &OS,47DIDumpOptions DumpOpts, const DWARFExpression *Expr,48DWARFUnit *U) {49if (Op->isError()) {50OS << "<decoding error>";51return false;52}5354StringRef Name = OperationEncodingString(Op->getCode());55assert(!Name.empty() && "DW_OP has no name!");56OS << Name;5758if ((Op->getCode() >= DW_OP_breg0 && Op->getCode() <= DW_OP_breg31) ||59(Op->getCode() >= DW_OP_reg0 && Op->getCode() <= DW_OP_reg31) ||60Op->getCode() == DW_OP_bregx || Op->getCode() == DW_OP_regx ||61Op->getCode() == DW_OP_regval_type)62if (prettyPrintRegisterOp(U, OS, DumpOpts, Op->getCode(),63Op->getRawOperands()))64return true;6566for (unsigned Operand = 0; Operand < Op->getDescription().Op.size();67++Operand) {68unsigned Size = Op->getDescription().Op[Operand];69unsigned Signed = Size & DWARFExpression::Operation::SignBit;7071if (Size == DWARFExpression::Operation::SizeSubOpLEB) {72StringRef SubName =73SubOperationEncodingString(Op->getCode(), Op->getRawOperand(Operand));74assert(!SubName.empty() && "DW_OP SubOp has no name!");75OS << " " << SubName;76} else if (Size == DWARFExpression::Operation::BaseTypeRef && U) {77// For DW_OP_convert the operand may be 0 to indicate that conversion to78// the generic type should be done. The same holds for DW_OP_reinterpret,79// which is currently not supported.80if (Op->getCode() == DW_OP_convert && Op->getRawOperand(Operand) == 0)81OS << " 0x0";82else83prettyPrintBaseTypeRef(U, OS, DumpOpts, Op->getRawOperands(), Operand);84} else if (Size == DWARFExpression::Operation::WasmLocationArg) {85assert(Operand == 1);86switch (Op->getRawOperand(0)) {87case 0:88case 1:89case 2:90case 3: // global as uint3291case 4:92OS << format(" 0x%" PRIx64, Op->getRawOperand(Operand));93break;94default:95assert(false);96}97} else if (Size == DWARFExpression::Operation::SizeBlock) {98uint64_t Offset = Op->getRawOperand(Operand);99for (unsigned i = 0; i < Op->getRawOperand(Operand - 1); ++i)100OS << format(" 0x%02x",101static_cast<uint8_t>(Expr->getData()[Offset++]));102} else {103if (Signed)104OS << format(" %+" PRId64, (int64_t)Op->getRawOperand(Operand));105else if (Op->getCode() != DW_OP_entry_value &&106Op->getCode() != DW_OP_GNU_entry_value)107OS << format(" 0x%" PRIx64, Op->getRawOperand(Operand));108}109}110return true;111}112113void printDwarfExpression(const DWARFExpression *E, raw_ostream &OS,114DIDumpOptions DumpOpts, DWARFUnit *U, bool IsEH) {115uint32_t EntryValExprSize = 0;116uint64_t EntryValStartOffset = 0;117if (E->getData().empty())118OS << "<empty>";119120for (auto &Op : *E) {121DumpOpts.IsEH = IsEH;122if (!printOp(&Op, OS, DumpOpts, E, U)) {123uint64_t FailOffset = Op.getEndOffset();124while (FailOffset < E->getData().size())125OS << format(" %02x", static_cast<uint8_t>(E->getData()[FailOffset++]));126return;127}128129if (Op.getCode() == DW_OP_entry_value ||130Op.getCode() == DW_OP_GNU_entry_value) {131OS << "(";132EntryValExprSize = Op.getRawOperand(0);133EntryValStartOffset = Op.getEndOffset();134continue;135}136137if (EntryValExprSize) {138EntryValExprSize -= Op.getEndOffset() - EntryValStartOffset;139if (EntryValExprSize == 0)140OS << ")";141}142143if (Op.getEndOffset() < E->getData().size())144OS << ", ";145}146}147148/// A user-facing string representation of a DWARF expression. This might be an149/// Address expression, in which case it will be implicitly dereferenced, or a150/// Value expression.151struct PrintedExpr {152enum ExprKind {153Address,154Value,155};156ExprKind Kind;157SmallString<16> String;158159PrintedExpr(ExprKind K = Address) : Kind(K) {}160};161162static bool printCompactDWARFExpr(163raw_ostream &OS, DWARFExpression::iterator I,164const DWARFExpression::iterator E,165std::function<StringRef(uint64_t RegNum, bool IsEH)> GetNameForDWARFReg =166nullptr) {167SmallVector<PrintedExpr, 4> Stack;168169while (I != E) {170const DWARFExpression::Operation &Op = *I;171uint8_t Opcode = Op.getCode();172switch (Opcode) {173case dwarf::DW_OP_regx: {174// DW_OP_regx: A register, with the register num given as an operand.175// Printed as the plain register name.176uint64_t DwarfRegNum = Op.getRawOperand(0);177auto RegName = GetNameForDWARFReg(DwarfRegNum, false);178if (RegName.empty())179return false;180raw_svector_ostream S(Stack.emplace_back(PrintedExpr::Value).String);181S << RegName;182break;183}184case dwarf::DW_OP_bregx: {185int DwarfRegNum = Op.getRawOperand(0);186int64_t Offset = Op.getRawOperand(1);187auto RegName = GetNameForDWARFReg(DwarfRegNum, false);188if (RegName.empty())189return false;190raw_svector_ostream S(Stack.emplace_back().String);191S << RegName;192if (Offset)193S << format("%+" PRId64, Offset);194break;195}196case dwarf::DW_OP_entry_value:197case dwarf::DW_OP_GNU_entry_value: {198// DW_OP_entry_value contains a sub-expression which must be rendered199// separately.200uint64_t SubExprLength = Op.getRawOperand(0);201DWARFExpression::iterator SubExprEnd = I.skipBytes(SubExprLength);202++I;203raw_svector_ostream S(Stack.emplace_back().String);204S << "entry(";205printCompactDWARFExpr(S, I, SubExprEnd, GetNameForDWARFReg);206S << ")";207I = SubExprEnd;208continue;209}210case dwarf::DW_OP_stack_value: {211// The top stack entry should be treated as the actual value of tne212// variable, rather than the address of the variable in memory.213assert(!Stack.empty());214Stack.back().Kind = PrintedExpr::Value;215break;216}217case dwarf::DW_OP_nop: {218break;219}220case dwarf::DW_OP_LLVM_user: {221assert(Op.getSubCode() == dwarf::DW_OP_LLVM_nop);222break;223}224default:225if (Opcode >= dwarf::DW_OP_reg0 && Opcode <= dwarf::DW_OP_reg31) {226// DW_OP_reg<N>: A register, with the register num implied by the227// opcode. Printed as the plain register name.228uint64_t DwarfRegNum = Opcode - dwarf::DW_OP_reg0;229auto RegName = GetNameForDWARFReg(DwarfRegNum, false);230if (RegName.empty())231return false;232raw_svector_ostream S(Stack.emplace_back(PrintedExpr::Value).String);233S << RegName;234} else if (Opcode >= dwarf::DW_OP_breg0 &&235Opcode <= dwarf::DW_OP_breg31) {236int DwarfRegNum = Opcode - dwarf::DW_OP_breg0;237int64_t Offset = Op.getRawOperand(0);238auto RegName = GetNameForDWARFReg(DwarfRegNum, false);239if (RegName.empty())240return false;241raw_svector_ostream S(Stack.emplace_back().String);242S << RegName;243if (Offset)244S << format("%+" PRId64, Offset);245} else {246// If we hit an unknown operand, we don't know its effect on the stack,247// so bail out on the whole expression.248OS << "<unknown op " << dwarf::OperationEncodingString(Opcode) << " ("249<< (int)Opcode << ")>";250return false;251}252break;253}254++I;255}256257if (Stack.size() != 1) {258OS << "<stack of size " << Stack.size() << ", expected 1>";259return false;260}261262if (Stack.front().Kind == PrintedExpr::Address)263OS << "[" << Stack.front().String << "]";264else265OS << Stack.front().String;266267return true;268}269270bool printDwarfExpressionCompact(271const DWARFExpression *E, raw_ostream &OS,272std::function<StringRef(uint64_t RegNum, bool IsEH)> GetNameForDWARFReg) {273return printCompactDWARFExpr(OS, E->begin(), E->end(), GetNameForDWARFReg);274}275276bool prettyPrintRegisterOp(DWARFUnit *U, raw_ostream &OS,277DIDumpOptions DumpOpts, uint8_t Opcode,278ArrayRef<uint64_t> Operands) {279if (!DumpOpts.GetNameForDWARFReg)280return false;281282uint64_t DwarfRegNum;283unsigned OpNum = 0;284285if (Opcode == DW_OP_bregx || Opcode == DW_OP_regx ||286Opcode == DW_OP_regval_type)287DwarfRegNum = Operands[OpNum++];288else if (Opcode >= DW_OP_breg0 && Opcode < DW_OP_bregx)289DwarfRegNum = Opcode - DW_OP_breg0;290else291DwarfRegNum = Opcode - DW_OP_reg0;292293auto RegName = DumpOpts.GetNameForDWARFReg(DwarfRegNum, DumpOpts.IsEH);294if (!RegName.empty()) {295if ((Opcode >= DW_OP_breg0 && Opcode <= DW_OP_breg31) ||296Opcode == DW_OP_bregx)297OS << ' ' << RegName << format("%+" PRId64, Operands[OpNum]);298else299OS << ' ' << RegName.data();300301if (Opcode == DW_OP_regval_type)302prettyPrintBaseTypeRef(U, OS, DumpOpts, Operands, 1);303return true;304}305306return false;307}308309} // namespace llvm310311312