Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/AST/Interp/Disasm.cpp
35291 views
1
//===--- Disasm.cpp - Disassembler for bytecode functions -------*- C++ -*-===//
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
// Dump method for Function which disassembles the bytecode.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "Boolean.h"
14
#include "Context.h"
15
#include "EvaluationResult.h"
16
#include "Floating.h"
17
#include "Function.h"
18
#include "FunctionPointer.h"
19
#include "Integral.h"
20
#include "IntegralAP.h"
21
#include "InterpFrame.h"
22
#include "MemberPointer.h"
23
#include "Opcode.h"
24
#include "PrimType.h"
25
#include "Program.h"
26
#include "clang/AST/ASTDumperUtils.h"
27
#include "clang/AST/DeclCXX.h"
28
#include "clang/AST/ExprCXX.h"
29
#include "llvm/Support/Compiler.h"
30
#include "llvm/Support/Format.h"
31
32
using namespace clang;
33
using namespace clang::interp;
34
35
template <typename T> inline T ReadArg(Program &P, CodePtr &OpPC) {
36
if constexpr (std::is_pointer_v<T>) {
37
uint32_t ID = OpPC.read<uint32_t>();
38
return reinterpret_cast<T>(P.getNativePointer(ID));
39
} else {
40
return OpPC.read<T>();
41
}
42
}
43
44
template <> inline Floating ReadArg<Floating>(Program &P, CodePtr &OpPC) {
45
Floating F = Floating::deserialize(*OpPC);
46
OpPC += align(F.bytesToSerialize());
47
return F;
48
}
49
50
template <>
51
inline IntegralAP<false> ReadArg<IntegralAP<false>>(Program &P, CodePtr &OpPC) {
52
IntegralAP<false> I = IntegralAP<false>::deserialize(*OpPC);
53
OpPC += align(I.bytesToSerialize());
54
return I;
55
}
56
57
template <>
58
inline IntegralAP<true> ReadArg<IntegralAP<true>>(Program &P, CodePtr &OpPC) {
59
IntegralAP<true> I = IntegralAP<true>::deserialize(*OpPC);
60
OpPC += align(I.bytesToSerialize());
61
return I;
62
}
63
64
LLVM_DUMP_METHOD void Function::dump() const { dump(llvm::errs()); }
65
66
LLVM_DUMP_METHOD void Function::dump(llvm::raw_ostream &OS) const {
67
{
68
ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_GREEN, true});
69
OS << getName() << " " << (const void *)this << "\n";
70
}
71
OS << "frame size: " << getFrameSize() << "\n";
72
OS << "arg size: " << getArgSize() << "\n";
73
OS << "rvo: " << hasRVO() << "\n";
74
OS << "this arg: " << hasThisPointer() << "\n";
75
76
auto PrintName = [&OS](const char *Name) {
77
OS << Name;
78
long N = 30 - strlen(Name);
79
if (N > 0)
80
OS.indent(N);
81
};
82
83
for (CodePtr Start = getCodeBegin(), PC = Start; PC != getCodeEnd();) {
84
size_t Addr = PC - Start;
85
auto Op = PC.read<Opcode>();
86
OS << llvm::format("%8d", Addr) << " ";
87
switch (Op) {
88
#define GET_DISASM
89
#include "Opcodes.inc"
90
#undef GET_DISASM
91
}
92
}
93
}
94
95
LLVM_DUMP_METHOD void Program::dump() const { dump(llvm::errs()); }
96
97
static const char *primTypeToString(PrimType T) {
98
switch (T) {
99
case PT_Sint8:
100
return "Sint8";
101
case PT_Uint8:
102
return "Uint8";
103
case PT_Sint16:
104
return "Sint16";
105
case PT_Uint16:
106
return "Uint16";
107
case PT_Sint32:
108
return "Sint32";
109
case PT_Uint32:
110
return "Uint32";
111
case PT_Sint64:
112
return "Sint64";
113
case PT_Uint64:
114
return "Uint64";
115
case PT_IntAP:
116
return "IntAP";
117
case PT_IntAPS:
118
return "IntAPS";
119
case PT_Bool:
120
return "Bool";
121
case PT_Float:
122
return "Float";
123
case PT_Ptr:
124
return "Ptr";
125
case PT_FnPtr:
126
return "FnPtr";
127
case PT_MemberPtr:
128
return "MemberPtr";
129
}
130
llvm_unreachable("Unhandled PrimType");
131
}
132
133
LLVM_DUMP_METHOD void Program::dump(llvm::raw_ostream &OS) const {
134
{
135
ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_RED, true});
136
OS << "\n:: Program\n";
137
}
138
139
{
140
ColorScope SC(OS, true, {llvm::raw_ostream::WHITE, true});
141
OS << "Total memory : " << Allocator.getTotalMemory() << " bytes\n";
142
OS << "Global Variables: " << Globals.size() << "\n";
143
}
144
unsigned GI = 0;
145
for (const Global *G : Globals) {
146
const Descriptor *Desc = G->block()->getDescriptor();
147
Pointer GP = getPtrGlobal(GI);
148
149
OS << GI << ": " << (const void *)G->block() << " ";
150
{
151
ColorScope SC(OS, true,
152
GP.isInitialized()
153
? TerminalColor{llvm::raw_ostream::GREEN, false}
154
: TerminalColor{llvm::raw_ostream::RED, false});
155
OS << (GP.isInitialized() ? "initialized " : "uninitialized ");
156
}
157
Desc->dump(OS);
158
159
if (GP.isInitialized() && Desc->IsTemporary) {
160
if (const auto *MTE =
161
dyn_cast_if_present<MaterializeTemporaryExpr>(Desc->asExpr());
162
MTE && MTE->getLifetimeExtendedTemporaryDecl()) {
163
if (const APValue *V =
164
MTE->getLifetimeExtendedTemporaryDecl()->getValue()) {
165
OS << " (global temporary value: ";
166
{
167
ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_MAGENTA, true});
168
std::string VStr;
169
llvm::raw_string_ostream SS(VStr);
170
V->dump(SS, Ctx.getASTContext());
171
172
for (unsigned I = 0; I != VStr.size(); ++I) {
173
if (VStr[I] == '\n')
174
VStr[I] = ' ';
175
}
176
VStr.pop_back(); // Remove the newline (or now space) at the end.
177
OS << VStr;
178
}
179
OS << ')';
180
}
181
}
182
}
183
184
OS << "\n";
185
if (GP.isInitialized() && Desc->isPrimitive() && !Desc->isDummy()) {
186
OS << " ";
187
{
188
ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_CYAN, false});
189
OS << primTypeToString(Desc->getPrimType()) << " ";
190
}
191
TYPE_SWITCH(Desc->getPrimType(), { GP.deref<T>().print(OS); });
192
OS << "\n";
193
}
194
++GI;
195
}
196
197
{
198
ColorScope SC(OS, true, {llvm::raw_ostream::WHITE, true});
199
OS << "Functions: " << Funcs.size() << "\n";
200
}
201
for (const auto &Func : Funcs) {
202
Func.second->dump();
203
}
204
for (const auto &Anon : AnonFuncs) {
205
Anon->dump();
206
}
207
}
208
209
LLVM_DUMP_METHOD void Descriptor::dump() const {
210
dump(llvm::errs());
211
llvm::errs() << '\n';
212
}
213
214
LLVM_DUMP_METHOD void Descriptor::dump(llvm::raw_ostream &OS) const {
215
// Source
216
{
217
ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});
218
if (const auto *ND = dyn_cast_if_present<NamedDecl>(asDecl()))
219
ND->printQualifiedName(OS);
220
else if (asExpr())
221
OS << "Expr " << (const void *)asExpr();
222
}
223
224
// Print a few interesting bits about the descriptor.
225
if (isPrimitiveArray())
226
OS << " primitive-array";
227
else if (isCompositeArray())
228
OS << " composite-array";
229
else if (isRecord())
230
OS << " record";
231
else if (isPrimitive())
232
OS << " primitive";
233
234
if (isZeroSizeArray())
235
OS << " zero-size-array";
236
else if (isUnknownSizeArray())
237
OS << " unknown-size-array";
238
239
if (isDummy())
240
OS << " dummy";
241
}
242
243
LLVM_DUMP_METHOD void InlineDescriptor::dump(llvm::raw_ostream &OS) const {
244
{
245
ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});
246
OS << "InlineDescriptor " << (const void *)this << "\n";
247
}
248
OS << "Offset: " << Offset << "\n";
249
OS << "IsConst: " << IsConst << "\n";
250
OS << "IsInitialized: " << IsInitialized << "\n";
251
OS << "IsBase: " << IsBase << "\n";
252
OS << "IsActive: " << IsActive << "\n";
253
OS << "IsFieldMutable: " << IsFieldMutable << "\n";
254
OS << "Desc: ";
255
if (Desc)
256
Desc->dump(OS);
257
else
258
OS << "nullptr";
259
OS << "\n";
260
}
261
262
LLVM_DUMP_METHOD void InterpFrame::dump(llvm::raw_ostream &OS,
263
unsigned Indent) const {
264
unsigned Spaces = Indent * 2;
265
{
266
ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});
267
OS.indent(Spaces);
268
if (getCallee())
269
describe(OS);
270
else
271
OS << "Frame (Depth: " << getDepth() << ")";
272
OS << "\n";
273
}
274
OS.indent(Spaces) << "Function: " << getFunction();
275
if (const Function *F = getFunction()) {
276
OS << " (" << F->getName() << ")";
277
}
278
OS << "\n";
279
OS.indent(Spaces) << "This: " << getThis() << "\n";
280
OS.indent(Spaces) << "RVO: " << getRVOPtr() << "\n";
281
282
while (const InterpFrame *F = this->Caller) {
283
F->dump(OS, Indent + 1);
284
F = F->Caller;
285
}
286
}
287
288
LLVM_DUMP_METHOD void Record::dump(llvm::raw_ostream &OS, unsigned Indentation,
289
unsigned Offset) const {
290
unsigned Indent = Indentation * 2;
291
OS.indent(Indent);
292
{
293
ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});
294
OS << getName() << "\n";
295
}
296
297
unsigned I = 0;
298
for (const Record::Base &B : bases()) {
299
OS.indent(Indent) << "- Base " << I << ". Offset " << (Offset + B.Offset)
300
<< "\n";
301
B.R->dump(OS, Indentation + 1, Offset + B.Offset);
302
++I;
303
}
304
305
I = 0;
306
for (const Record::Field &F : fields()) {
307
OS.indent(Indent) << "- Field " << I << ": ";
308
{
309
ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_RED, true});
310
OS << F.Decl->getName();
311
}
312
OS << ". Offset " << (Offset + F.Offset) << "\n";
313
++I;
314
}
315
316
I = 0;
317
for (const Record::Base &B : virtual_bases()) {
318
OS.indent(Indent) << "- Virtual Base " << I << ". Offset "
319
<< (Offset + B.Offset) << "\n";
320
B.R->dump(OS, Indentation + 1, Offset + B.Offset);
321
++I;
322
}
323
}
324
325
LLVM_DUMP_METHOD void Block::dump(llvm::raw_ostream &OS) const {
326
{
327
ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_BLUE, true});
328
OS << "Block " << (const void *)this;
329
}
330
OS << " (";
331
Desc->dump(OS);
332
OS << ")\n";
333
unsigned NPointers = 0;
334
for (const Pointer *P = Pointers; P; P = P->Next) {
335
++NPointers;
336
}
337
OS << " Pointers: " << NPointers << "\n";
338
OS << " Dead: " << IsDead << "\n";
339
OS << " Static: " << IsStatic << "\n";
340
OS << " Extern: " << IsExtern << "\n";
341
OS << " Initialized: " << IsInitialized << "\n";
342
}
343
344
LLVM_DUMP_METHOD void EvaluationResult::dump() const {
345
assert(Ctx);
346
auto &OS = llvm::errs();
347
const ASTContext &ASTCtx = Ctx->getASTContext();
348
349
switch (Kind) {
350
case Empty:
351
OS << "Empty\n";
352
break;
353
case RValue:
354
OS << "RValue: ";
355
std::get<APValue>(Value).dump(OS, ASTCtx);
356
break;
357
case LValue: {
358
assert(Source);
359
QualType SourceType;
360
if (const auto *D = Source.dyn_cast<const Decl *>()) {
361
if (const auto *VD = dyn_cast<ValueDecl>(D))
362
SourceType = VD->getType();
363
} else if (const auto *E = Source.dyn_cast<const Expr *>()) {
364
SourceType = E->getType();
365
}
366
367
OS << "LValue: ";
368
if (const auto *P = std::get_if<Pointer>(&Value))
369
P->toAPValue(ASTCtx).printPretty(OS, ASTCtx, SourceType);
370
else if (const auto *FP = std::get_if<FunctionPointer>(&Value)) // Nope
371
FP->toAPValue(ASTCtx).printPretty(OS, ASTCtx, SourceType);
372
OS << "\n";
373
break;
374
}
375
case Invalid:
376
OS << "Invalid\n";
377
break;
378
case Valid:
379
OS << "Valid\n";
380
break;
381
}
382
}
383
384