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
17 using namespace llvm;
18 using namespace dwarf;
19
20 namespace llvm {
21
22 typedef DWARFExpression::Operation Op;
23 typedef Op::Description Desc;
24
prettyPrintBaseTypeRef(DWARFUnit * U,raw_ostream & OS,DIDumpOptions DumpOpts,ArrayRef<uint64_t> Operands,unsigned Operand)25 static 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(" <base_type ref: 0x%" PRIx64 ">", Operands[Operand]);
32 return;
33 }
34 auto Die = U->getDIEForOffset(U->getOffset() + Operands[Operand]);
35 if (Die && Die.getTag() == dwarf::DW_TAG_base_type) {
36 OS << " (";
37 if (DumpOpts.Verbose)
38 OS << format("0x%08" PRIx64 " -> ", Operands[Operand]);
39 OS << format("0x%08" PRIx64 ")", U->getOffset() + Operands[Operand]);
40 if (auto Name = dwarf::toString(Die.find(dwarf::DW_AT_name)))
41 OS << " \"" << *Name << "\"";
42 } else {
43 OS << format(" <invalid base_type ref: 0x%" PRIx64 ">", Operands[Operand]);
44 }
45 }
46
printOp(const DWARFExpression::Operation * Op,raw_ostream & OS,DIDumpOptions DumpOpts,const DWARFExpression * Expr,DWARFUnit * U)47 static 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(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, Op->getCode(),
64 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(Op->getCode(), Op->getRawOperand(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(Operand) == 0)
82 OS << " 0x0";
83 else
84 prettyPrintBaseTypeRef(U, OS, DumpOpts, Op->getRawOperands(), Operand);
85 } else if (Size == DWARFExpression::Operation::WasmLocationArg) {
86 assert(Operand == 1);
87 switch (Op->getRawOperand(0)) {
88 case 0:
89 case 1:
90 case 2:
91 case 3: // global as uint32
92 case 4:
93 OS << format(" 0x%" PRIx64, Op->getRawOperand(Operand));
94 break;
95 default:
96 assert(false);
97 }
98 } else if (Size == DWARFExpression::Operation::SizeBlock) {
99 uint64_t Offset = Op->getRawOperand(Operand);
100 for (unsigned i = 0; i < Op->getRawOperand(Operand - 1); ++i)
101 OS << format(" 0x%02x",
102 static_cast<uint8_t>(Expr->getData()[Offset++]));
103 } else {
104 if (Signed)
105 OS << format(" %+" PRId64, (int64_t)Op->getRawOperand(Operand));
106 else if (Op->getCode() != DW_OP_entry_value &&
107 Op->getCode() != DW_OP_GNU_entry_value)
108 OS << format(" 0x%" PRIx64, Op->getRawOperand(Operand));
109 }
110 }
111 return true;
112 }
113
printDwarfExpression(const DWARFExpression * E,raw_ostream & OS,DIDumpOptions DumpOpts,DWARFUnit * U,bool IsEH)114 void 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, OS, DumpOpts, E, U)) {
124 uint64_t FailOffset = Op.getEndOffset();
125 while (FailOffset < E->getData().size())
126 OS << format(" %02x", 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(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.
152 struct PrintedExpr {
153 enum ExprKind {
154 Address,
155 Value,
156 };
157 ExprKind Kind;
158 SmallString<16> String;
159
PrintedExprllvm::PrintedExpr160 PrintedExpr(ExprKind K = Address) : Kind(K) {}
161 };
162
printCompactDWARFExpr(raw_ostream & OS,DWARFExpression::iterator I,const DWARFExpression::iterator E,std::function<StringRef (uint64_t RegNum,bool IsEH)> GetNameForDWARFReg=nullptr)163 static 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(0);
178 auto RegName = GetNameForDWARFReg(DwarfRegNum, false);
179 if (RegName.empty())
180 return false;
181 raw_svector_ostream S(Stack.emplace_back(PrintedExpr::Value).String);
182 S << RegName;
183 break;
184 }
185 case dwarf::DW_OP_bregx: {
186 int DwarfRegNum = Op.getRawOperand(0);
187 int64_t Offset = Op.getRawOperand(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("%+" PRId64, 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(0);
202 DWARFExpression::iterator SubExprEnd = I.skipBytes(SubExprLength);
203 ++I;
204 raw_svector_ostream S(Stack.emplace_back().String);
205 S << "entry(";
206 printCompactDWARFExpr(S, I, 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(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(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("%+" PRId64, 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(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
printDwarfExpressionCompact(const DWARFExpression * E,raw_ostream & OS,std::function<StringRef (uint64_t RegNum,bool IsEH)> GetNameForDWARFReg)271 bool printDwarfExpressionCompact(
272 const DWARFExpression *E, raw_ostream &OS,
273 std::function<StringRef(uint64_t RegNum, bool IsEH)> GetNameForDWARFReg) {
274 return printCompactDWARFExpr(OS, E->begin(), E->end(), GetNameForDWARFReg);
275 }
276
prettyPrintRegisterOp(DWARFUnit * U,raw_ostream & OS,DIDumpOptions DumpOpts,uint8_t Opcode,ArrayRef<uint64_t> Operands)277 bool 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("%+" PRId64, Operands[OpNum]);
299 else
300 OS << ' ' << RegName.data();
301
302 if (Opcode == DW_OP_regval_type)
303 prettyPrintBaseTypeRef(U, OS, DumpOpts, Operands, 1);
304 return true;
305 }
306
307 return false;
308 }
309
310 } // namespace llvm
311