Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFExpressionPrinter.cpp
213799 views
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
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
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
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
160
PrintedExpr(ExprKind K = Address) : Kind(K) {}
161
};
162
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
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
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
312