Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/AST/ByteCode/Disasm.cpp
213799 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 "FixedPoint.h"
17
#include "Floating.h"
18
#include "Function.h"
19
#include "FunctionPointer.h"
20
#include "Integral.h"
21
#include "IntegralAP.h"
22
#include "InterpFrame.h"
23
#include "MemberPointer.h"
24
#include "Opcode.h"
25
#include "PrimType.h"
26
#include "Program.h"
27
#include "clang/AST/ASTDumperUtils.h"
28
#include "clang/AST/DeclCXX.h"
29
#include "clang/AST/ExprCXX.h"
30
#include "llvm/Support/Compiler.h"
31
32
using namespace clang;
33
using namespace clang::interp;
34
35
template <typename T>
36
inline static std::string printArg(Program &P, CodePtr &OpPC) {
37
if constexpr (std::is_pointer_v<T>) {
38
uint32_t ID = OpPC.read<uint32_t>();
39
std::string Result;
40
llvm::raw_string_ostream SS(Result);
41
SS << reinterpret_cast<T>(P.getNativePointer(ID));
42
return Result;
43
} else {
44
std::string Result;
45
llvm::raw_string_ostream SS(Result);
46
auto Arg = OpPC.read<T>();
47
SS << Arg;
48
return Result;
49
}
50
}
51
52
template <> inline std::string printArg<Floating>(Program &P, CodePtr &OpPC) {
53
auto Sem = Floating::deserializeSemantics(*OpPC);
54
55
unsigned BitWidth = llvm::APFloatBase::semanticsSizeInBits(
56
llvm::APFloatBase::EnumToSemantics(Sem));
57
auto Memory =
58
std::make_unique<uint64_t[]>(llvm::APInt::getNumWords(BitWidth));
59
Floating Result(Memory.get(), Sem);
60
Floating::deserialize(*OpPC, &Result);
61
62
OpPC += align(Result.bytesToSerialize());
63
64
std::string S;
65
llvm::raw_string_ostream SS(S);
66
SS << std::move(Result);
67
return S;
68
}
69
70
template <>
71
inline std::string printArg<IntegralAP<false>>(Program &P, CodePtr &OpPC) {
72
using T = IntegralAP<false>;
73
uint32_t BitWidth = T::deserializeSize(*OpPC);
74
auto Memory =
75
std::make_unique<uint64_t[]>(llvm::APInt::getNumWords(BitWidth));
76
77
T Result(Memory.get(), BitWidth);
78
T::deserialize(*OpPC, &Result);
79
80
OpPC += align(Result.bytesToSerialize());
81
82
std::string Str;
83
llvm::raw_string_ostream SS(Str);
84
SS << std::move(Result);
85
return Str;
86
}
87
88
template <>
89
inline std::string printArg<IntegralAP<true>>(Program &P, CodePtr &OpPC) {
90
using T = IntegralAP<true>;
91
uint32_t BitWidth = T::deserializeSize(*OpPC);
92
auto Memory =
93
std::make_unique<uint64_t[]>(llvm::APInt::getNumWords(BitWidth));
94
95
T Result(Memory.get(), BitWidth);
96
T::deserialize(*OpPC, &Result);
97
98
OpPC += align(Result.bytesToSerialize());
99
100
std::string Str;
101
llvm::raw_string_ostream SS(Str);
102
SS << std::move(Result);
103
return Str;
104
}
105
106
template <> inline std::string printArg<FixedPoint>(Program &P, CodePtr &OpPC) {
107
auto F = FixedPoint::deserialize(*OpPC);
108
OpPC += align(F.bytesToSerialize());
109
110
std::string Result;
111
llvm::raw_string_ostream SS(Result);
112
SS << std::move(F);
113
return Result;
114
}
115
116
static bool isJumpOpcode(Opcode Op) {
117
return Op == OP_Jmp || Op == OP_Jf || Op == OP_Jt;
118
}
119
120
static size_t getNumDisplayWidth(size_t N) {
121
unsigned L = 1u, M = 10u;
122
while (M <= N && ++L != std::numeric_limits<size_t>::digits10 + 1)
123
M *= 10u;
124
125
return L;
126
}
127
128
LLVM_DUMP_METHOD void Function::dump() const { dump(llvm::errs()); }
129
130
LLVM_DUMP_METHOD void Function::dump(llvm::raw_ostream &OS) const {
131
{
132
ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_GREEN, true});
133
OS << getName() << " " << (const void *)this << "\n";
134
}
135
OS << "frame size: " << getFrameSize() << "\n";
136
OS << "arg size: " << getArgSize() << "\n";
137
OS << "rvo: " << hasRVO() << "\n";
138
OS << "this arg: " << hasThisPointer() << "\n";
139
140
struct OpText {
141
size_t Addr;
142
std::string Op;
143
bool IsJump;
144
llvm::SmallVector<std::string> Args;
145
};
146
147
auto PrintName = [](const char *Name) -> std::string {
148
return std::string(Name);
149
};
150
151
llvm::SmallVector<OpText> Code;
152
size_t LongestAddr = 0;
153
size_t LongestOp = 0;
154
155
for (CodePtr Start = getCodeBegin(), PC = Start; PC != getCodeEnd();) {
156
size_t Addr = PC - Start;
157
OpText Text;
158
auto Op = PC.read<Opcode>();
159
Text.Addr = Addr;
160
Text.IsJump = isJumpOpcode(Op);
161
switch (Op) {
162
#define GET_DISASM
163
#include "Opcodes.inc"
164
#undef GET_DISASM
165
}
166
Code.push_back(Text);
167
LongestOp = std::max(Text.Op.size(), LongestOp);
168
LongestAddr = std::max(getNumDisplayWidth(Addr), LongestAddr);
169
}
170
171
// Record jumps and their targets.
172
struct JmpData {
173
size_t From;
174
size_t To;
175
};
176
llvm::SmallVector<JmpData> Jumps;
177
for (auto &Text : Code) {
178
if (Text.IsJump)
179
Jumps.push_back({Text.Addr, Text.Addr + std::stoi(Text.Args[0]) +
180
align(sizeof(Opcode)) +
181
align(sizeof(int32_t))});
182
}
183
184
llvm::SmallVector<std::string> Text;
185
Text.reserve(Code.size());
186
size_t LongestLine = 0;
187
// Print code to a string, one at a time.
188
for (auto C : Code) {
189
std::string Line;
190
llvm::raw_string_ostream LS(Line);
191
LS << C.Addr;
192
LS.indent(LongestAddr - getNumDisplayWidth(C.Addr) + 4);
193
LS << C.Op;
194
LS.indent(LongestOp - C.Op.size() + 4);
195
for (auto &Arg : C.Args) {
196
LS << Arg << ' ';
197
}
198
Text.push_back(Line);
199
LongestLine = std::max(Line.size(), LongestLine);
200
}
201
202
assert(Code.size() == Text.size());
203
204
auto spaces = [](unsigned N) -> std::string {
205
std::string S;
206
for (unsigned I = 0; I != N; ++I)
207
S += ' ';
208
return S;
209
};
210
211
// Now, draw the jump lines.
212
for (auto &J : Jumps) {
213
if (J.To > J.From) {
214
bool FoundStart = false;
215
for (size_t LineIndex = 0; LineIndex != Text.size(); ++LineIndex) {
216
Text[LineIndex] += spaces(LongestLine - Text[LineIndex].size());
217
218
if (Code[LineIndex].Addr == J.From) {
219
Text[LineIndex] += " --+";
220
FoundStart = true;
221
} else if (Code[LineIndex].Addr == J.To) {
222
Text[LineIndex] += " <-+";
223
break;
224
} else if (FoundStart) {
225
Text[LineIndex] += " |";
226
}
227
}
228
LongestLine += 5;
229
} else {
230
bool FoundStart = false;
231
for (ssize_t LineIndex = Text.size() - 1; LineIndex >= 0; --LineIndex) {
232
Text[LineIndex] += spaces(LongestLine - Text[LineIndex].size());
233
if (Code[LineIndex].Addr == J.From) {
234
Text[LineIndex] += " --+";
235
FoundStart = true;
236
} else if (Code[LineIndex].Addr == J.To) {
237
Text[LineIndex] += " <-+";
238
break;
239
} else if (FoundStart) {
240
Text[LineIndex] += " |";
241
}
242
}
243
LongestLine += 5;
244
}
245
}
246
247
for (auto &Line : Text)
248
OS << Line << '\n';
249
}
250
251
LLVM_DUMP_METHOD void Program::dump() const { dump(llvm::errs()); }
252
253
static const char *primTypeToString(PrimType T) {
254
switch (T) {
255
case PT_Sint8:
256
return "Sint8";
257
case PT_Uint8:
258
return "Uint8";
259
case PT_Sint16:
260
return "Sint16";
261
case PT_Uint16:
262
return "Uint16";
263
case PT_Sint32:
264
return "Sint32";
265
case PT_Uint32:
266
return "Uint32";
267
case PT_Sint64:
268
return "Sint64";
269
case PT_Uint64:
270
return "Uint64";
271
case PT_IntAP:
272
return "IntAP";
273
case PT_IntAPS:
274
return "IntAPS";
275
case PT_Bool:
276
return "Bool";
277
case PT_Float:
278
return "Float";
279
case PT_Ptr:
280
return "Ptr";
281
case PT_MemberPtr:
282
return "MemberPtr";
283
case PT_FixedPoint:
284
return "FixedPoint";
285
}
286
llvm_unreachable("Unhandled PrimType");
287
}
288
289
LLVM_DUMP_METHOD void Program::dump(llvm::raw_ostream &OS) const {
290
{
291
ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_RED, true});
292
OS << "\n:: Program\n";
293
}
294
295
{
296
ColorScope SC(OS, true, {llvm::raw_ostream::WHITE, true});
297
OS << "Total memory : " << Allocator.getTotalMemory() << " bytes\n";
298
OS << "Global Variables: " << Globals.size() << "\n";
299
}
300
unsigned GI = 0;
301
for (const Global *G : Globals) {
302
const Descriptor *Desc = G->block()->getDescriptor();
303
Pointer GP = getPtrGlobal(GI);
304
305
OS << GI << ": " << (const void *)G->block() << " ";
306
{
307
ColorScope SC(OS, true,
308
GP.isInitialized()
309
? TerminalColor{llvm::raw_ostream::GREEN, false}
310
: TerminalColor{llvm::raw_ostream::RED, false});
311
OS << (GP.isInitialized() ? "initialized " : "uninitialized ");
312
}
313
Desc->dump(OS);
314
315
if (GP.isInitialized() && Desc->IsTemporary) {
316
if (const auto *MTE =
317
dyn_cast_if_present<MaterializeTemporaryExpr>(Desc->asExpr());
318
MTE && MTE->getLifetimeExtendedTemporaryDecl()) {
319
if (const APValue *V =
320
MTE->getLifetimeExtendedTemporaryDecl()->getValue()) {
321
OS << " (global temporary value: ";
322
{
323
ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_MAGENTA, true});
324
std::string VStr;
325
llvm::raw_string_ostream SS(VStr);
326
V->dump(SS, Ctx.getASTContext());
327
328
for (unsigned I = 0; I != VStr.size(); ++I) {
329
if (VStr[I] == '\n')
330
VStr[I] = ' ';
331
}
332
VStr.pop_back(); // Remove the newline (or now space) at the end.
333
OS << VStr;
334
}
335
OS << ')';
336
}
337
}
338
}
339
340
OS << "\n";
341
if (GP.isInitialized() && Desc->isPrimitive() && !Desc->isDummy()) {
342
OS << " ";
343
{
344
ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_CYAN, false});
345
OS << primTypeToString(Desc->getPrimType()) << " ";
346
}
347
TYPE_SWITCH(Desc->getPrimType(), { GP.deref<T>().print(OS); });
348
OS << "\n";
349
}
350
++GI;
351
}
352
353
{
354
ColorScope SC(OS, true, {llvm::raw_ostream::WHITE, true});
355
OS << "Functions: " << Funcs.size() << "\n";
356
}
357
for (const auto &Func : Funcs) {
358
Func.second->dump();
359
}
360
for (const auto &Anon : AnonFuncs) {
361
Anon->dump();
362
}
363
}
364
365
LLVM_DUMP_METHOD void Descriptor::dump() const {
366
dump(llvm::errs());
367
llvm::errs() << '\n';
368
}
369
370
LLVM_DUMP_METHOD void Descriptor::dump(llvm::raw_ostream &OS) const {
371
// Source
372
{
373
ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});
374
if (const auto *ND = dyn_cast_if_present<NamedDecl>(asDecl()))
375
ND->printQualifiedName(OS);
376
else if (asExpr())
377
OS << "Expr " << (const void *)asExpr();
378
}
379
380
// Print a few interesting bits about the descriptor.
381
if (isPrimitiveArray())
382
OS << " primitive-array";
383
else if (isCompositeArray())
384
OS << " composite-array";
385
else if (isUnion())
386
OS << " union";
387
else if (isRecord())
388
OS << " record";
389
else if (isPrimitive())
390
OS << " primitive " << primTypeToString(getPrimType());
391
392
if (isZeroSizeArray())
393
OS << " zero-size-array";
394
else if (isUnknownSizeArray())
395
OS << " unknown-size-array";
396
397
if (isDummy())
398
OS << " dummy";
399
if (IsConstexprUnknown)
400
OS << " constexpr-unknown";
401
}
402
403
/// Dump descriptor, including all valid offsets.
404
LLVM_DUMP_METHOD void Descriptor::dumpFull(unsigned Offset,
405
unsigned Indent) const {
406
unsigned Spaces = Indent * 2;
407
llvm::raw_ostream &OS = llvm::errs();
408
OS.indent(Spaces);
409
dump(OS);
410
OS << '\n';
411
OS.indent(Spaces) << "Metadata: " << getMetadataSize() << " bytes\n";
412
OS.indent(Spaces) << "Size: " << getSize() << " bytes\n";
413
OS.indent(Spaces) << "AllocSize: " << getAllocSize() << " bytes\n";
414
Offset += getMetadataSize();
415
if (isCompositeArray()) {
416
OS.indent(Spaces) << "Elements: " << getNumElems() << '\n';
417
unsigned FO = Offset;
418
for (unsigned I = 0; I != getNumElems(); ++I) {
419
FO += sizeof(InlineDescriptor);
420
assert(ElemDesc->getMetadataSize() == 0);
421
OS.indent(Spaces) << "Element " << I << " offset: " << FO << '\n';
422
ElemDesc->dumpFull(FO, Indent + 1);
423
424
FO += ElemDesc->getAllocSize();
425
}
426
} else if (isRecord()) {
427
ElemRecord->dump(OS, Indent + 1, Offset);
428
} else if (isPrimitive()) {
429
} else {
430
}
431
432
OS << '\n';
433
}
434
435
LLVM_DUMP_METHOD void InlineDescriptor::dump(llvm::raw_ostream &OS) const {
436
{
437
ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});
438
OS << "InlineDescriptor " << (const void *)this << "\n";
439
}
440
OS << "Offset: " << Offset << "\n";
441
OS << "IsConst: " << IsConst << "\n";
442
OS << "IsInitialized: " << IsInitialized << "\n";
443
OS << "IsBase: " << IsBase << "\n";
444
OS << "IsActive: " << IsActive << "\n";
445
OS << "InUnion: " << InUnion << "\n";
446
OS << "IsFieldMutable: " << IsFieldMutable << "\n";
447
OS << "IsArrayElement: " << IsArrayElement << "\n";
448
OS << "Desc: ";
449
if (Desc)
450
Desc->dump(OS);
451
else
452
OS << "nullptr";
453
OS << "\n";
454
}
455
456
LLVM_DUMP_METHOD void InterpFrame::dump(llvm::raw_ostream &OS,
457
unsigned Indent) const {
458
unsigned Spaces = Indent * 2;
459
{
460
ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});
461
OS.indent(Spaces);
462
if (getCallee())
463
describe(OS);
464
else
465
OS << "Frame (Depth: " << getDepth() << ")";
466
OS << "\n";
467
}
468
OS.indent(Spaces) << "Function: " << getFunction();
469
if (const Function *F = getFunction()) {
470
OS << " (" << F->getName() << ")";
471
}
472
OS << "\n";
473
OS.indent(Spaces) << "This: " << getThis() << "\n";
474
OS.indent(Spaces) << "RVO: " << getRVOPtr() << "\n";
475
OS.indent(Spaces) << "Depth: " << Depth << "\n";
476
OS.indent(Spaces) << "ArgSize: " << ArgSize << "\n";
477
OS.indent(Spaces) << "Args: " << (void *)Args << "\n";
478
OS.indent(Spaces) << "FrameOffset: " << FrameOffset << "\n";
479
OS.indent(Spaces) << "FrameSize: " << (Func ? Func->getFrameSize() : 0)
480
<< "\n";
481
482
for (const InterpFrame *F = this->Caller; F; F = F->Caller) {
483
F->dump(OS, Indent + 1);
484
}
485
}
486
487
LLVM_DUMP_METHOD void Record::dump(llvm::raw_ostream &OS, unsigned Indentation,
488
unsigned Offset) const {
489
unsigned Indent = Indentation * 2;
490
OS.indent(Indent);
491
{
492
ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});
493
OS << getName() << "\n";
494
}
495
496
unsigned I = 0;
497
for (const Record::Base &B : bases()) {
498
OS.indent(Indent) << "- Base " << I << ". Offset " << (Offset + B.Offset)
499
<< "\n";
500
B.R->dump(OS, Indentation + 1, Offset + B.Offset);
501
++I;
502
}
503
504
I = 0;
505
for (const Record::Field &F : fields()) {
506
OS.indent(Indent) << "- Field " << I << ": ";
507
{
508
ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_RED, true});
509
OS << F.Decl->getName();
510
}
511
OS << ". Offset " << (Offset + F.Offset) << "\n";
512
++I;
513
}
514
515
I = 0;
516
for (const Record::Base &B : virtual_bases()) {
517
OS.indent(Indent) << "- Virtual Base " << I << ". Offset "
518
<< (Offset + B.Offset) << "\n";
519
B.R->dump(OS, Indentation + 1, Offset + B.Offset);
520
++I;
521
}
522
}
523
524
LLVM_DUMP_METHOD void Block::dump(llvm::raw_ostream &OS) const {
525
{
526
ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_BLUE, true});
527
OS << "Block " << (const void *)this;
528
}
529
OS << " (";
530
Desc->dump(OS);
531
OS << ")\n";
532
unsigned NPointers = 0;
533
for (const Pointer *P = Pointers; P; P = P->Next) {
534
++NPointers;
535
}
536
OS << " EvalID: " << EvalID << '\n';
537
OS << " DeclID: ";
538
if (DeclID)
539
OS << *DeclID << '\n';
540
else
541
OS << "-\n";
542
OS << " Pointers: " << NPointers << "\n";
543
OS << " Dead: " << IsDead << "\n";
544
OS << " Static: " << IsStatic << "\n";
545
OS << " Extern: " << IsExtern << "\n";
546
OS << " Initialized: " << IsInitialized << "\n";
547
OS << " Weak: " << IsWeak << "\n";
548
OS << " Dynamic: " << IsDynamic << "\n";
549
}
550
551
LLVM_DUMP_METHOD void EvaluationResult::dump() const {
552
assert(Ctx);
553
auto &OS = llvm::errs();
554
const ASTContext &ASTCtx = Ctx->getASTContext();
555
556
switch (Kind) {
557
case Empty:
558
OS << "Empty\n";
559
break;
560
case RValue:
561
OS << "RValue: ";
562
std::get<APValue>(Value).dump(OS, ASTCtx);
563
break;
564
case LValue: {
565
assert(Source);
566
QualType SourceType;
567
if (const auto *D = dyn_cast<const Decl *>(Source)) {
568
if (const auto *VD = dyn_cast<ValueDecl>(D))
569
SourceType = VD->getType();
570
} else if (const auto *E = dyn_cast<const Expr *>(Source)) {
571
SourceType = E->getType();
572
}
573
574
OS << "LValue: ";
575
if (const auto *P = std::get_if<Pointer>(&Value))
576
P->toAPValue(ASTCtx).printPretty(OS, ASTCtx, SourceType);
577
else if (const auto *FP = std::get_if<FunctionPointer>(&Value)) // Nope
578
FP->toAPValue(ASTCtx).printPretty(OS, ASTCtx, SourceType);
579
OS << "\n";
580
break;
581
}
582
case Invalid:
583
OS << "Invalid\n";
584
break;
585
case Valid:
586
OS << "Valid\n";
587
break;
588
}
589
}
590
591