clang 19.0.0git
Disasm.cpp
Go to the documentation of this file.
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 "Floating.h"
15#include "Function.h"
16#include "FunctionPointer.h"
17#include "Integral.h"
18#include "IntegralAP.h"
19#include "InterpFrame.h"
20#include "Opcode.h"
21#include "PrimType.h"
22#include "Program.h"
24#include "clang/AST/DeclCXX.h"
25#include "llvm/Support/Compiler.h"
26#include "llvm/Support/Format.h"
27
28using namespace clang;
29using namespace clang::interp;
30
31template <typename T> inline T ReadArg(Program &P, CodePtr &OpPC) {
32 if constexpr (std::is_pointer_v<T>) {
33 uint32_t ID = OpPC.read<uint32_t>();
34 return reinterpret_cast<T>(P.getNativePointer(ID));
35 } else {
36 return OpPC.read<T>();
37 }
38}
39
40template <> inline Floating ReadArg<Floating>(Program &P, CodePtr &OpPC) {
42 OpPC += align(F.bytesToSerialize());
43 return F;
44}
45
46template <>
47inline IntegralAP<false> ReadArg<IntegralAP<false>>(Program &P, CodePtr &OpPC) {
49 OpPC += align(I.bytesToSerialize());
50 return I;
51}
52
53template <>
54inline IntegralAP<true> ReadArg<IntegralAP<true>>(Program &P, CodePtr &OpPC) {
56 OpPC += align(I.bytesToSerialize());
57 return I;
58}
59
60LLVM_DUMP_METHOD void Function::dump() const { dump(llvm::errs()); }
61
62LLVM_DUMP_METHOD void Function::dump(llvm::raw_ostream &OS) const {
63 {
64 ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_GREEN, true});
65 OS << getName() << " " << (const void *)this << "\n";
66 }
67 OS << "frame size: " << getFrameSize() << "\n";
68 OS << "arg size: " << getArgSize() << "\n";
69 OS << "rvo: " << hasRVO() << "\n";
70 OS << "this arg: " << hasThisPointer() << "\n";
71
72 auto PrintName = [&OS](const char *Name) {
73 OS << Name;
74 long N = 30 - strlen(Name);
75 if (N > 0)
76 OS.indent(N);
77 };
78
79 for (CodePtr Start = getCodeBegin(), PC = Start; PC != getCodeEnd();) {
80 size_t Addr = PC - Start;
81 auto Op = PC.read<Opcode>();
82 OS << llvm::format("%8d", Addr) << " ";
83 switch (Op) {
84#define GET_DISASM
85#include "Opcodes.inc"
86#undef GET_DISASM
87 }
88 }
89}
90
91LLVM_DUMP_METHOD void Program::dump() const { dump(llvm::errs()); }
92
93static const char *primTypeToString(PrimType T) {
94 switch (T) {
95 case PT_Sint8:
96 return "Sint8";
97 case PT_Uint8:
98 return "Uint8";
99 case PT_Sint16:
100 return "Sint16";
101 case PT_Uint16:
102 return "Uint16";
103 case PT_Sint32:
104 return "Sint32";
105 case PT_Uint32:
106 return "Uint32";
107 case PT_Sint64:
108 return "Sint64";
109 case PT_Uint64:
110 return "Uint64";
111 case PT_IntAP:
112 return "IntAP";
113 case PT_IntAPS:
114 return "IntAPS";
115 case PT_Bool:
116 return "Bool";
117 case PT_Float:
118 return "Float";
119 case PT_Ptr:
120 return "Ptr";
121 case PT_FnPtr:
122 return "FnPtr";
123 }
124 llvm_unreachable("Unhandled PrimType");
125}
126
127LLVM_DUMP_METHOD void Program::dump(llvm::raw_ostream &OS) const {
128 {
129 ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_RED, true});
130 OS << "\n:: Program\n";
131 }
132
133 {
134 ColorScope SC(OS, true, {llvm::raw_ostream::WHITE, true});
135 OS << "Total memory : " << Allocator.getTotalMemory() << " bytes\n";
136 OS << "Global Variables: " << Globals.size() << "\n";
137 }
138 unsigned GI = 0;
139 for (const Global *G : Globals) {
140 const Descriptor *Desc = G->block()->getDescriptor();
141 Pointer GP = getPtrGlobal(GI);
142
143 OS << GI << ": " << (const void *)G->block() << " ";
144 {
145 ColorScope SC(OS, true,
146 GP.isInitialized()
147 ? TerminalColor{llvm::raw_ostream::GREEN, false}
148 : TerminalColor{llvm::raw_ostream::RED, false});
149 OS << (GP.isInitialized() ? "initialized " : "uninitialized ");
150 }
151 Desc->dump(OS);
152 OS << "\n";
153 if (Desc->isPrimitive() && !Desc->isDummy()) {
154 OS << " ";
155 {
156 ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_CYAN, false});
157 OS << primTypeToString(Desc->getPrimType()) << " ";
158 }
159 TYPE_SWITCH(Desc->getPrimType(), { GP.deref<T>().print(OS); });
160 OS << "\n";
161 }
162 ++GI;
163 }
164
165 {
166 ColorScope SC(OS, true, {llvm::raw_ostream::WHITE, true});
167 OS << "Functions: " << Funcs.size() << "\n";
168 }
169 for (const auto &Func : Funcs) {
170 Func.second->dump();
171 }
172 for (const auto &Anon : AnonFuncs) {
173 Anon->dump();
174 }
175}
176
177LLVM_DUMP_METHOD void Descriptor::dump() const {
178 dump(llvm::errs());
179 llvm::errs() << '\n';
180}
181
182LLVM_DUMP_METHOD void Descriptor::dump(llvm::raw_ostream &OS) const {
183 // Source
184 {
185 ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});
186 if (const auto *ND = dyn_cast_if_present<NamedDecl>(asDecl()))
187 ND->printQualifiedName(OS);
188 else if (asExpr())
189 OS << "expr (TODO)";
190 }
191
192 // Print a few interesting bits about the descriptor.
193 if (isPrimitiveArray())
194 OS << " primitive-array";
195 else if (isCompositeArray())
196 OS << " composite-array";
197 else if (isRecord())
198 OS << " record";
199 else if (isPrimitive())
200 OS << " primitive";
201
202 if (isZeroSizeArray())
203 OS << " zero-size-arrary";
204 else if (isUnknownSizeArray())
205 OS << " unknown-size-array";
206
207 if (isDummy())
208 OS << " dummy";
209}
210
211LLVM_DUMP_METHOD void InterpFrame::dump(llvm::raw_ostream &OS,
212 unsigned Indent) const {
213 unsigned Spaces = Indent * 2;
214 {
215 ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});
216 OS.indent(Spaces);
217 if (getCallee())
218 describe(OS);
219 else
220 OS << "Frame (Depth: " << getDepth() << ")";
221 OS << "\n";
222 }
223 OS.indent(Spaces) << "Function: " << getFunction();
224 if (const Function *F = getFunction()) {
225 OS << " (" << F->getName() << ")";
226 }
227 OS << "\n";
228 OS.indent(Spaces) << "This: " << getThis() << "\n";
229 OS.indent(Spaces) << "RVO: " << getRVOPtr() << "\n";
230
231 while (const InterpFrame *F = this->Caller) {
232 F->dump(OS, Indent + 1);
233 F = F->Caller;
234 }
235}
236
237LLVM_DUMP_METHOD void Record::dump(llvm::raw_ostream &OS, unsigned Indentation,
238 unsigned Offset) const {
239 unsigned Indent = Indentation * 2;
240 OS.indent(Indent);
241 {
242 ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});
243 OS << getName() << "\n";
244 }
245
246 unsigned I = 0;
247 for (const Record::Base &B : bases()) {
248 OS.indent(Indent) << "- Base " << I << ". Offset " << (Offset + B.Offset)
249 << "\n";
250 B.R->dump(OS, Indentation + 1, Offset + B.Offset);
251 ++I;
252 }
253
254 // FIXME: Virtual bases.
255
256 I = 0;
257 for (const Record::Field &F : fields()) {
258 OS.indent(Indent) << "- Field " << I << ": ";
259 {
260 ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_RED, true});
261 OS << F.Decl->getName();
262 }
263 OS << ". Offset " << (Offset + F.Offset) << "\n";
264 ++I;
265 }
266}
267
268LLVM_DUMP_METHOD void Block::dump(llvm::raw_ostream &OS) const {
269 {
270 ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_BLUE, true});
271 OS << "Block " << (const void *)this << "\n";
272 }
273 unsigned NPointers = 0;
274 for (const Pointer *P = Pointers; P; P = P->Next) {
275 ++NPointers;
276 }
277 OS << " Pointers: " << NPointers << "\n";
278 OS << " Dead: " << IsDead << "\n";
279 OS << " Static: " << IsStatic << "\n";
280 OS << " Extern: " << IsExtern << "\n";
281 OS << " Initialized: " << IsInitialized << "\n";
282}
StringRef P
static void dump(llvm::raw_ostream &OS, StringRef FunctionName, ArrayRef< CounterExpression > Expressions, ArrayRef< CounterMappingRegion > Regions)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
static const char * primTypeToString(PrimType T)
Definition: Disasm.cpp:93
Floating ReadArg< Floating >(Program &P, CodePtr &OpPC)
Definition: Disasm.cpp:40
T ReadArg(Program &P, CodePtr &OpPC)
Definition: Disasm.cpp:31
#define TYPE_SWITCH(Expr, B)
Definition: PrimType.h:117
static std::string getName(const CallEvent &Call)
bool IsExtern
Flag indicating if the block is an extern.
Definition: InterpBlock.h:150
bool IsInitialized
Flag indicating if the block contents have been initialized via invokeCtor.
Definition: InterpBlock.h:156
bool IsStatic
Flag indicating if the block has static storage duration.
Definition: InterpBlock.h:148
Pointer * Pointers
Start of the chain of pointers.
Definition: InterpBlock.h:144
void dump() const
Definition: InterpBlock.h:121
bool IsDead
Flag indicating if the pointer is dead.
Definition: InterpBlock.h:153
Pointer into the code segment.
Definition: Source.h:30
std::enable_if_t<!std::is_pointer< T >::value, T > read()
Reads data and advances the pointer.
Definition: Source.h:55
static Floating deserialize(const std::byte *Buff)
Definition: Floating.h:153
size_t bytesToSerialize() const
Definition: Floating.h:139
Bytecode function.
Definition: Function.h:77
static IntegralAP< Signed > deserialize(const std::byte *Buff)
Definition: IntegralAP.h:281
size_t bytesToSerialize() const
Definition: IntegralAP.h:267
Frame storing local variables.
Definition: InterpFrame.h:28
InterpFrame * Caller
The frame of the previous function.
Definition: InterpFrame.h:31
const Pointer & getThis() const
Returns the 'this' pointer.
Definition: InterpFrame.h:104
const Function * getFunction() const
Returns the current function.
Definition: InterpFrame.h:66
unsigned getDepth() const
Definition: InterpFrame.h:124
const Pointer & getRVOPtr() const
Returns the RVO pointer, if the Function has one.
Definition: InterpFrame.h:107
const FunctionDecl * getCallee() const override
Returns the caller.
void describe(llvm::raw_ostream &OS) const override
Describes the frame with arguments for diagnostic purposes.
A pointer to a memory block, live or dead.
Definition: Pointer.h:80
bool isInitialized() const
Checks if an object was initialized.
Definition: Pointer.cpp:216
The program contains and links the bytecode for all functions.
Definition: Program.h:39
Pointer getPtrGlobal(unsigned Idx) const
Returns a pointer to a global.
Definition: Program.cpp:105
void dump() const
Dumps the disassembled bytecode to llvm::errs().
Definition: Disasm.cpp:91
const std::string getName() const
Returns the name of the underlying declaration.
Definition: Record.cpp:31
llvm::iterator_range< const_base_iter > bases() const
Definition: Record.h:85
llvm::iterator_range< const_field_iter > fields() const
Definition: Record.h:77
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
Definition: PrimType.h:99
PrimType
Enumeration of the primitive types of the VM.
Definition: PrimType.h:32
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T
Describes a memory block created by an allocation site.
Definition: Descriptor.h:88
bool isPrimitive() const
Checks if the descriptor is of a primitive.
Definition: Descriptor.h:222
bool isCompositeArray() const
Checks if the descriptor is of an array of composites.
Definition: Descriptor.h:215
const Decl * asDecl() const
Definition: Descriptor.h:169
bool isDummy() const
Checks if this is a dummy descriptor.
Definition: Descriptor.h:229
bool isUnknownSizeArray() const
Checks if the descriptor is of an array of unknown size.
Definition: Descriptor.h:219
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
Definition: Descriptor.h:213
bool isZeroSizeArray() const
Checks if the descriptor is of an array of zero size.
Definition: Descriptor.h:217
PrimType getPrimType() const
Definition: Descriptor.h:195
bool isRecord() const
Checks if the descriptor is of a record.
Definition: Descriptor.h:227
const Expr * asExpr() const
Definition: Descriptor.h:170