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 
28 using namespace clang;
29 using namespace clang::interp;
30 
31 template <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 
40 template <> inline Floating ReadArg<Floating>(Program &P, CodePtr &OpPC) {
42  OpPC += align(F.bytesToSerialize());
43  return F;
44 }
45 
46 template <>
47 inline IntegralAP<false> ReadArg<IntegralAP<false>>(Program &P, CodePtr &OpPC) {
49  OpPC += align(I.bytesToSerialize());
50  return I;
51 }
52 
53 template <>
54 inline IntegralAP<true> ReadArg<IntegralAP<true>>(Program &P, CodePtr &OpPC) {
56  OpPC += align(I.bytesToSerialize());
57  return I;
58 }
59 
60 LLVM_DUMP_METHOD void Function::dump() const { dump(llvm::errs()); }
61 
62 LLVM_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 
91 LLVM_DUMP_METHOD void Program::dump() const { dump(llvm::errs()); }
92 
93 static 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 
127 LLVM_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 
177 LLVM_DUMP_METHOD void Descriptor::dump() const {
178  dump(llvm::errs());
179  llvm::errs() << '\n';
180 }
181 
182 LLVM_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-array";
204  else if (isUnknownSizeArray())
205  OS << " unknown-size-array";
206 
207  if (isDummy())
208  OS << " dummy";
209 }
210 
211 LLVM_DUMP_METHOD void InlineDescriptor::dump(llvm::raw_ostream &OS) const {
212  {
213  ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});
214  OS << "InlineDescriptor " << (const void *)this << "\n";
215  }
216  OS << "Offset: " << Offset << "\n";
217  OS << "IsConst: " << IsConst << "\n";
218  OS << "IsInitialized: " << IsInitialized << "\n";
219  OS << "IsBase: " << IsBase << "\n";
220  OS << "IsActive: " << IsActive << "\n";
221  OS << "IsFieldMutable: " << IsFieldMutable << "\n";
222  OS << "Desc: ";
223  if (Desc)
224  Desc->dump(OS);
225  else
226  OS << "nullptr";
227  OS << "\n";
228 }
229 
230 LLVM_DUMP_METHOD void InterpFrame::dump(llvm::raw_ostream &OS,
231  unsigned Indent) const {
232  unsigned Spaces = Indent * 2;
233  {
234  ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});
235  OS.indent(Spaces);
236  if (getCallee())
237  describe(OS);
238  else
239  OS << "Frame (Depth: " << getDepth() << ")";
240  OS << "\n";
241  }
242  OS.indent(Spaces) << "Function: " << getFunction();
243  if (const Function *F = getFunction()) {
244  OS << " (" << F->getName() << ")";
245  }
246  OS << "\n";
247  OS.indent(Spaces) << "This: " << getThis() << "\n";
248  OS.indent(Spaces) << "RVO: " << getRVOPtr() << "\n";
249 
250  while (const InterpFrame *F = this->Caller) {
251  F->dump(OS, Indent + 1);
252  F = F->Caller;
253  }
254 }
255 
256 LLVM_DUMP_METHOD void Record::dump(llvm::raw_ostream &OS, unsigned Indentation,
257  unsigned Offset) const {
258  unsigned Indent = Indentation * 2;
259  OS.indent(Indent);
260  {
261  ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});
262  OS << getName() << "\n";
263  }
264 
265  unsigned I = 0;
266  for (const Record::Base &B : bases()) {
267  OS.indent(Indent) << "- Base " << I << ". Offset " << (Offset + B.Offset)
268  << "\n";
269  B.R->dump(OS, Indentation + 1, Offset + B.Offset);
270  ++I;
271  }
272 
273  I = 0;
274  for (const Record::Field &F : fields()) {
275  OS.indent(Indent) << "- Field " << I << ": ";
276  {
277  ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_RED, true});
278  OS << F.Decl->getName();
279  }
280  OS << ". Offset " << (Offset + F.Offset) << "\n";
281  ++I;
282  }
283 
284  I = 0;
285  for (const Record::Base &B : virtual_bases()) {
286  OS.indent(Indent) << "- Virtual Base " << I << ". Offset "
287  << (Offset + B.Offset) << "\n";
288  B.R->dump(OS, Indentation + 1, Offset + B.Offset);
289  ++I;
290  }
291 }
292 
293 LLVM_DUMP_METHOD void Block::dump(llvm::raw_ostream &OS) const {
294  {
295  ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_BLUE, true});
296  OS << "Block " << (const void *)this << "\n";
297  }
298  unsigned NPointers = 0;
299  for (const Pointer *P = Pointers; P; P = P->Next) {
300  ++NPointers;
301  }
302  OS << " Pointers: " << NPointers << "\n";
303  OS << " Dead: " << IsDead << "\n";
304  OS << " Static: " << IsStatic << "\n";
305  OS << " Extern: " << IsExtern << "\n";
306  OS << " Initialized: " << IsInitialized << "\n";
307 }
StringRef P
static char ID
Definition: Arena.cpp:183
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
static const char * primTypeToString(PrimType T)
Definition: Disasm.cpp:93
unsigned Offset
Definition: Format.cpp:2978
#define TYPE_SWITCH(Expr, B)
Definition: PrimType.h:117
bool IsExtern
Flag indicating if the block is an extern.
Definition: InterpBlock.h:154
bool IsInitialized
Flag indicating if the block contents have been initialized via invokeCtor.
Definition: InterpBlock.h:160
bool IsStatic
Flag indicating if the block has static storage duration.
Definition: InterpBlock.h:152
Pointer * Pointers
Start of the chain of pointers.
Definition: InterpBlock.h:148
void dump() const
Definition: InterpBlock.h:125
bool IsDead
Flag indicating if the pointer is dead.
Definition: InterpBlock.h:157
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
CodePtr getCodeBegin() const
Returns a pointer to the start of the code.
Definition: Function.h:87
CodePtr getCodeEnd() const
Returns a pointer to the end of the code.
Definition: Function.h:89
const std::string getName() const
Returns the name of the function decl this code was generated for.
Definition: Function.h:96
unsigned getFrameSize() const
Returns the size of the function's local stack.
Definition: Function.h:82
bool hasThisPointer() const
Definition: Function.h:171
void dump() const
Dumps the disassembled bytecode to llvm::errs().
Definition: Disasm.cpp:60
unsigned getArgSize() const
Returns the size of the argument stack.
Definition: Function.h:84
bool hasRVO() const
Checks if the first argument is a RVO pointer.
Definition: Function.h:110
static IntegralAP< Signed > deserialize(const std::byte *Buff)
Definition: IntegralAP.h:284
size_t bytesToSerialize() const
Definition: IntegralAP.h:270
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
unsigned getDepth() const
Definition: InterpFrame.h:124
const FunctionDecl * getCallee() const override
Returns the caller.
const Function * getFunction() const
Returns the current function.
Definition: InterpFrame.h:66
const Pointer & getRVOPtr() const
Returns the RVO pointer, if the Function has one.
Definition: InterpFrame.h:107
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:220
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
llvm::iterator_range< const_virtual_iter > virtual_bases() const
Definition: Record.h:96
void dump() const
Definition: Record.h:105
Floating ReadArg< Floating >(InterpState &S, CodePtr &OpPC)
Definition: Interp.h:2425
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
Definition: PrimType.h:99
T ReadArg(InterpState &S, CodePtr &OpPC)
Definition: Interp.h:2416
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
raw_ostream & Indent(raw_ostream &Out, const unsigned int Space, bool IsDot)
Definition: JsonSupport.h:21
Describes a memory block created by an allocation site.
Definition: Descriptor.h:91
bool isPrimitive() const
Checks if the descriptor is of a primitive.
Definition: Descriptor.h:225
const Expr * asExpr() const
Definition: Descriptor.h:173
bool isCompositeArray() const
Checks if the descriptor is of an array of composites.
Definition: Descriptor.h:218
const Decl * asDecl() const
Definition: Descriptor.h:172
bool isDummy() const
Checks if this is a dummy descriptor.
Definition: Descriptor.h:232
bool isUnknownSizeArray() const
Checks if the descriptor is of an array of unknown size.
Definition: Descriptor.h:222
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
Definition: Descriptor.h:216
bool isZeroSizeArray() const
Checks if the descriptor is of an array of zero size.
Definition: Descriptor.h:220
PrimType getPrimType() const
Definition: Descriptor.h:198
bool isRecord() const
Checks if the descriptor is of a record.
Definition: Descriptor.h:230
unsigned IsActive
Flag indicating if the field is the active member of a union.
Definition: Descriptor.h:75
unsigned IsBase
Flag indicating if the field is an embedded base class.
Definition: Descriptor.h:72
const Descriptor * Desc
Definition: Descriptor.h:80
unsigned Offset
Offset inside the structure/array.
Definition: Descriptor.h:58
unsigned IsInitialized
For primitive fields, it indicates if the field was initialized.
Definition: Descriptor.h:69
unsigned IsConst
Flag indicating if the storage is constant or not.
Definition: Descriptor.h:63
unsigned IsFieldMutable
Flag indicating if the field is mutable (if in a record).
Definition: Descriptor.h:78