1//===-- DWARFExpression.cpp -----------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/DebugInfo/DWARF/DWARFExpressionPrinter.h"
10#include "llvm/ADT/SmallString.h"
11#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
12#include "llvm/DebugInfo/DWARF/LowLevel/DWARFExpression.h"
13#include "llvm/Support/Format.h"
14#include <cassert>
15#include <cstdint>
16
17using namespace llvm;
18using namespace dwarf;
19
20namespace llvm {
21
22typedef DWARFExpression::Operation Op;
23typedef Op::Description Desc;
24
25static void prettyPrintBaseTypeRef(DWARFUnit *U, raw_ostream &OS,
26 DIDumpOptions DumpOpts,
27 ArrayRef<uint64_t> Operands,
28 unsigned Operand) {
29 assert(Operand < Operands.size() && "operand out of bounds");
30 if (!U) {
31 OS << format(Fmt: " <base_type ref: 0x%" PRIx64 ">", Vals: Operands[Operand]);
32 return;
33 }
34 auto Die = U->getDIEForOffset(Offset: U->getOffset() + Operands[Operand]);
35 if (Die && Die.getTag() == dwarf::DW_TAG_base_type) {
36 OS << " (";
37 if (DumpOpts.Verbose)
38 OS << format(Fmt: "0x%08" PRIx64 " -> ", Vals: Operands[Operand]);
39 OS << format(Fmt: "0x%08" PRIx64 ")", Vals: U->getOffset() + Operands[Operand]);
40 if (auto Name = dwarf::toString(V: Die.find(Attr: dwarf::DW_AT_name)))
41 OS << " \"" << *Name << "\"";
42 } else {
43 OS << format(Fmt: " <invalid base_type ref: 0x%" PRIx64 ">", Vals: Operands[Operand]);
44 }
45}
46
47static bool printOp(const DWARFExpression::Operation *Op, raw_ostream &OS,
48 DIDumpOptions DumpOpts, const DWARFExpression *Expr,
49 DWARFUnit *U) {
50 if (Op->isError()) {
51 OS << "<decoding error>";
52 return false;
53 }
54
55 StringRef Name = OperationEncodingString(Encoding: Op->getCode());
56 assert(!Name.empty() && "DW_OP has no name!");
57 OS << Name;
58
59 if ((Op->getCode() >= DW_OP_breg0 && Op->getCode() <= DW_OP_breg31) ||
60 (Op->getCode() >= DW_OP_reg0 && Op->getCode() <= DW_OP_reg31) ||
61 Op->getCode() == DW_OP_bregx || Op->getCode() == DW_OP_regx ||
62 Op->getCode() == DW_OP_regval_type)
63 if (prettyPrintRegisterOp(U, OS, DumpOpts, Opcode: Op->getCode(),
64 Operands: Op->getRawOperands()))
65 return true;
66
67 for (unsigned Operand = 0; Operand < Op->getDescription().Op.size();
68 ++Operand) {
69 unsigned Size = Op->getDescription().Op[Operand];
70 unsigned Signed = Size & DWARFExpression::Operation::SignBit;
71
72 if (Size == DWARFExpression::Operation::SizeSubOpLEB) {
73 StringRef SubName =
74 SubOperationEncodingString(OpEncoding: Op->getCode(), SubOpEncoding: Op->getRawOperand(Idx: Operand));
75 assert(!SubName.empty() && "DW_OP SubOp has no name!");
76 OS << " " << SubName;
77 } else if (Size == DWARFExpression::Operation::BaseTypeRef && U) {
78 // For DW_OP_convert the operand may be 0 to indicate that conversion to
79 // the generic type should be done. The same holds for DW_OP_reinterpret,
80 // which is currently not supported.
81 if (Op->getCode() == DW_OP_convert && Op->getRawOperand(Idx: Operand) == 0)
82 OS << " 0x0";
83 else
84 prettyPrintBaseTypeRef(U, OS, DumpOpts, Operands: Op->getRawOperands(), Operand);
85 } else if (Size == DWARFExpression::Operation::WasmLocationArg) {
86 assert(Operand == 1);
87 switch (Op->getRawOperand(Idx: 0)) {
88 case 0:
89 case 1:
90 case 2:
91 case 3: // global as uint32
92 case 4:
93 OS << format(Fmt: " 0x%" PRIx64, Vals: Op->getRawOperand(Idx: Operand));
94 break;
95 default:
96 assert(false);
97 }
98 } else if (Size == DWARFExpression::Operation::SizeBlock) {
99 uint64_t Offset = Op->getRawOperand(Idx: Operand);
100 for (unsigned i = 0; i < Op->getRawOperand(Idx: Operand - 1); ++i)
101 OS << format(Fmt: " 0x%02x",
102 Vals: static_cast<uint8_t>(Expr->getData()[Offset++]));
103 } else {
104 if (Signed)
105 OS << format(Fmt: " %+" PRId64, Vals: (int64_t)Op->getRawOperand(Idx: Operand));
106 else if (Op->getCode() != DW_OP_entry_value &&
107 Op->getCode() != DW_OP_GNU_entry_value)
108 OS << format(Fmt: " 0x%" PRIx64, Vals: Op->getRawOperand(Idx: Operand));
109 }
110 }
111 return true;
112}
113
114void printDwarfExpression(const DWARFExpression *E, raw_ostream &OS,
115 DIDumpOptions DumpOpts, DWARFUnit *U, bool IsEH) {
116 uint32_t EntryValExprSize = 0;
117 uint64_t EntryValStartOffset = 0;
118 if (E->getData().empty())
119 OS << "<empty>";
120
121 for (auto &Op : *E) {
122 DumpOpts.IsEH = IsEH;
123 if (!printOp(Op: &Op, OS, DumpOpts, Expr: E, U)) {
124 uint64_t FailOffset = Op.getEndOffset();
125 while (FailOffset < E->getData().size())
126 OS << format(Fmt: " %02x", Vals: static_cast<uint8_t>(E->getData()[FailOffset++]));
127 return;
128 }
129
130 if (Op.getCode() == DW_OP_entry_value ||
131 Op.getCode() == DW_OP_GNU_entry_value) {
132 OS << "(";
133 EntryValExprSize = Op.getRawOperand(Idx: 0);
134 EntryValStartOffset = Op.getEndOffset();
135 continue;
136 }
137
138 if (EntryValExprSize) {
139 EntryValExprSize -= Op.getEndOffset() - EntryValStartOffset;
140 if (EntryValExprSize == 0)
141 OS << ")";
142 }
143
144 if (Op.getEndOffset() < E->getData().size())
145 OS << ", ";
146 }
147}
148
149/// A user-facing string representation of a DWARF expression. This might be an
150/// Address expression, in which case it will be implicitly dereferenced, or a
151/// Value expression.
152struct PrintedExpr {
153 enum ExprKind {
154 Address,
155 Value,
156 };
157 ExprKind Kind;
158 SmallString<16> String;
159
160 PrintedExpr(ExprKind K = Address) : Kind(K) {}
161};
162
163static bool printCompactDWARFExpr(
164 raw_ostream &OS, DWARFExpression::iterator I,
165 const DWARFExpression::iterator E,
166 std::function<StringRef(uint64_t RegNum, bool IsEH)> GetNameForDWARFReg =
167 nullptr) {
168 SmallVector<PrintedExpr, 4> Stack;
169
170 while (I != E) {
171 const DWARFExpression::Operation &Op = *I;
172 uint8_t Opcode = Op.getCode();
173 switch (Opcode) {
174 case dwarf::DW_OP_regx: {
175 // DW_OP_regx: A register, with the register num given as an operand.
176 // Printed as the plain register name.
177 uint64_t DwarfRegNum = Op.getRawOperand(Idx: 0);
178 auto RegName = GetNameForDWARFReg(DwarfRegNum, false);
179 if (RegName.empty())
180 return false;
181 raw_svector_ostream S(Stack.emplace_back(Args: PrintedExpr::Value).String);
182 S << RegName;
183 break;
184 }
185 case dwarf::DW_OP_bregx: {
186 int DwarfRegNum = Op.getRawOperand(Idx: 0);
187 int64_t Offset = Op.getRawOperand(Idx: 1);
188 auto RegName = GetNameForDWARFReg(DwarfRegNum, false);
189 if (RegName.empty())
190 return false;
191 raw_svector_ostream S(Stack.emplace_back().String);
192 S << RegName;
193 if (Offset)
194 S << format(Fmt: "%+" PRId64, Vals: Offset);
195 break;
196 }
197 case dwarf::DW_OP_entry_value:
198 case dwarf::DW_OP_GNU_entry_value: {
199 // DW_OP_entry_value contains a sub-expression which must be rendered
200 // separately.
201 uint64_t SubExprLength = Op.getRawOperand(Idx: 0);
202 DWARFExpression::iterator SubExprEnd = I.skipBytes(Add: SubExprLength);
203 ++I;
204 raw_svector_ostream S(Stack.emplace_back().String);
205 S << "entry(";
206 printCompactDWARFExpr(OS&: S, I, E: SubExprEnd, GetNameForDWARFReg);
207 S << ")";
208 I = SubExprEnd;
209 continue;
210 }
211 case dwarf::DW_OP_stack_value: {
212 // The top stack entry should be treated as the actual value of tne
213 // variable, rather than the address of the variable in memory.
214 assert(!Stack.empty());
215 Stack.back().Kind = PrintedExpr::Value;
216 break;
217 }
218 case dwarf::DW_OP_nop: {
219 break;
220 }
221 case dwarf::DW_OP_LLVM_user: {
222 assert(Op.getSubCode() == dwarf::DW_OP_LLVM_nop);
223 break;
224 }
225 default:
226 if (Opcode >= dwarf::DW_OP_reg0 && Opcode <= dwarf::DW_OP_reg31) {
227 // DW_OP_reg<N>: A register, with the register num implied by the
228 // opcode. Printed as the plain register name.
229 uint64_t DwarfRegNum = Opcode - dwarf::DW_OP_reg0;
230 auto RegName = GetNameForDWARFReg(DwarfRegNum, false);
231 if (RegName.empty())
232 return false;
233 raw_svector_ostream S(Stack.emplace_back(Args: PrintedExpr::Value).String);
234 S << RegName;
235 } else if (Opcode >= dwarf::DW_OP_breg0 &&
236 Opcode <= dwarf::DW_OP_breg31) {
237 int DwarfRegNum = Opcode - dwarf::DW_OP_breg0;
238 int64_t Offset = Op.getRawOperand(Idx: 0);
239 auto RegName = GetNameForDWARFReg(DwarfRegNum, false);
240 if (RegName.empty())
241 return false;
242 raw_svector_ostream S(Stack.emplace_back().String);
243 S << RegName;
244 if (Offset)
245 S << format(Fmt: "%+" PRId64, Vals: Offset);
246 } else {
247 // If we hit an unknown operand, we don't know its effect on the stack,
248 // so bail out on the whole expression.
249 OS << "<unknown op " << dwarf::OperationEncodingString(Encoding: Opcode) << " ("
250 << (int)Opcode << ")>";
251 return false;
252 }
253 break;
254 }
255 ++I;
256 }
257
258 if (Stack.size() != 1) {
259 OS << "<stack of size " << Stack.size() << ", expected 1>";
260 return false;
261 }
262
263 if (Stack.front().Kind == PrintedExpr::Address)
264 OS << "[" << Stack.front().String << "]";
265 else
266 OS << Stack.front().String;
267
268 return true;
269}
270
271bool printDwarfExpressionCompact(
272 const DWARFExpression *E, raw_ostream &OS,
273 std::function<StringRef(uint64_t RegNum, bool IsEH)> GetNameForDWARFReg) {
274 return printCompactDWARFExpr(OS, I: E->begin(), E: E->end(), GetNameForDWARFReg);
275}
276
277bool prettyPrintRegisterOp(DWARFUnit *U, raw_ostream &OS,
278 DIDumpOptions DumpOpts, uint8_t Opcode,
279 ArrayRef<uint64_t> Operands) {
280 if (!DumpOpts.GetNameForDWARFReg)
281 return false;
282
283 uint64_t DwarfRegNum;
284 unsigned OpNum = 0;
285
286 if (Opcode == DW_OP_bregx || Opcode == DW_OP_regx ||
287 Opcode == DW_OP_regval_type)
288 DwarfRegNum = Operands[OpNum++];
289 else if (Opcode >= DW_OP_breg0 && Opcode < DW_OP_bregx)
290 DwarfRegNum = Opcode - DW_OP_breg0;
291 else
292 DwarfRegNum = Opcode - DW_OP_reg0;
293
294 auto RegName = DumpOpts.GetNameForDWARFReg(DwarfRegNum, DumpOpts.IsEH);
295 if (!RegName.empty()) {
296 if ((Opcode >= DW_OP_breg0 && Opcode <= DW_OP_breg31) ||
297 Opcode == DW_OP_bregx)
298 OS << ' ' << RegName << format(Fmt: "%+" PRId64, Vals: Operands[OpNum]);
299 else
300 OS << ' ' << RegName.data();
301
302 if (Opcode == DW_OP_regval_type)
303 prettyPrintBaseTypeRef(U, OS, DumpOpts, Operands, Operand: 1);
304 return true;
305 }
306
307 return false;
308}
309
310} // namespace llvm
311