267 lines
7.1 KiB
C++
267 lines
7.1 KiB
C++
//===--- Disasm.cpp - Disassembler for bytecode functions -------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Dump method for Function which disassembles the bytecode.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "Boolean.h"
|
|
#include "Floating.h"
|
|
#include "Function.h"
|
|
#include "FunctionPointer.h"
|
|
#include "Integral.h"
|
|
#include "IntegralAP.h"
|
|
#include "InterpFrame.h"
|
|
#include "Opcode.h"
|
|
#include "PrimType.h"
|
|
#include "Program.h"
|
|
#include "clang/AST/ASTDumperUtils.h"
|
|
#include "clang/AST/DeclCXX.h"
|
|
#include "llvm/Support/Compiler.h"
|
|
#include "llvm/Support/Format.h"
|
|
|
|
using namespace clang;
|
|
using namespace clang::interp;
|
|
|
|
template <typename T> inline T ReadArg(Program &P, CodePtr &OpPC) {
|
|
if constexpr (std::is_pointer_v<T>) {
|
|
uint32_t ID = OpPC.read<uint32_t>();
|
|
return reinterpret_cast<T>(P.getNativePointer(ID));
|
|
} else {
|
|
return OpPC.read<T>();
|
|
}
|
|
}
|
|
|
|
template <> inline Floating ReadArg<Floating>(Program &P, CodePtr &OpPC) {
|
|
Floating F = Floating::deserialize(*OpPC);
|
|
OpPC += align(F.bytesToSerialize());
|
|
return F;
|
|
}
|
|
|
|
template <>
|
|
inline IntegralAP<false> ReadArg<IntegralAP<false>>(Program &P, CodePtr &OpPC) {
|
|
IntegralAP<false> I = IntegralAP<false>::deserialize(*OpPC);
|
|
OpPC += align(I.bytesToSerialize());
|
|
return I;
|
|
}
|
|
|
|
template <>
|
|
inline IntegralAP<true> ReadArg<IntegralAP<true>>(Program &P, CodePtr &OpPC) {
|
|
IntegralAP<true> I = IntegralAP<true>::deserialize(*OpPC);
|
|
OpPC += align(I.bytesToSerialize());
|
|
return I;
|
|
}
|
|
|
|
LLVM_DUMP_METHOD void Function::dump() const { dump(llvm::errs()); }
|
|
|
|
LLVM_DUMP_METHOD void Function::dump(llvm::raw_ostream &OS) const {
|
|
{
|
|
ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_GREEN, true});
|
|
OS << getName() << " " << (const void *)this << "\n";
|
|
}
|
|
OS << "frame size: " << getFrameSize() << "\n";
|
|
OS << "arg size: " << getArgSize() << "\n";
|
|
OS << "rvo: " << hasRVO() << "\n";
|
|
OS << "this arg: " << hasThisPointer() << "\n";
|
|
|
|
auto PrintName = [&OS](const char *Name) {
|
|
OS << Name;
|
|
long N = 30 - strlen(Name);
|
|
if (N > 0)
|
|
OS.indent(N);
|
|
};
|
|
|
|
for (CodePtr Start = getCodeBegin(), PC = Start; PC != getCodeEnd();) {
|
|
size_t Addr = PC - Start;
|
|
auto Op = PC.read<Opcode>();
|
|
OS << llvm::format("%8d", Addr) << " ";
|
|
switch (Op) {
|
|
#define GET_DISASM
|
|
#include "Opcodes.inc"
|
|
#undef GET_DISASM
|
|
}
|
|
}
|
|
}
|
|
|
|
LLVM_DUMP_METHOD void Program::dump() const { dump(llvm::errs()); }
|
|
|
|
static const char *primTypeToString(PrimType T) {
|
|
switch (T) {
|
|
case PT_Sint8:
|
|
return "Sint8";
|
|
case PT_Uint8:
|
|
return "Uint8";
|
|
case PT_Sint16:
|
|
return "Sint16";
|
|
case PT_Uint16:
|
|
return "Uint16";
|
|
case PT_Sint32:
|
|
return "Sint32";
|
|
case PT_Uint32:
|
|
return "Uint32";
|
|
case PT_Sint64:
|
|
return "Sint64";
|
|
case PT_Uint64:
|
|
return "Uint64";
|
|
case PT_IntAP:
|
|
return "IntAP";
|
|
case PT_IntAPS:
|
|
return "IntAPS";
|
|
case PT_Bool:
|
|
return "Bool";
|
|
case PT_Float:
|
|
return "Float";
|
|
case PT_Ptr:
|
|
return "Ptr";
|
|
case PT_FnPtr:
|
|
return "FnPtr";
|
|
}
|
|
llvm_unreachable("Unhandled PrimType");
|
|
}
|
|
|
|
LLVM_DUMP_METHOD void Program::dump(llvm::raw_ostream &OS) const {
|
|
{
|
|
ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_RED, true});
|
|
OS << "\n:: Program\n";
|
|
}
|
|
|
|
{
|
|
ColorScope SC(OS, true, {llvm::raw_ostream::WHITE, true});
|
|
OS << "Total memory : " << Allocator.getTotalMemory() << " bytes\n";
|
|
OS << "Global Variables: " << Globals.size() << "\n";
|
|
}
|
|
unsigned GI = 0;
|
|
for (const Global *G : Globals) {
|
|
const Descriptor *Desc = G->block()->getDescriptor();
|
|
Pointer GP = getPtrGlobal(GI);
|
|
|
|
OS << GI << ": " << (void *)G->block() << " ";
|
|
{
|
|
ColorScope SC(OS, true,
|
|
GP.isInitialized()
|
|
? TerminalColor{llvm::raw_ostream::GREEN, false}
|
|
: TerminalColor{llvm::raw_ostream::RED, false});
|
|
OS << (GP.isInitialized() ? "initialized " : "uninitialized ");
|
|
}
|
|
Desc->dump(OS);
|
|
OS << "\n";
|
|
if (Desc->isPrimitive() && !Desc->isDummy()) {
|
|
OS << " ";
|
|
{
|
|
ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_CYAN, false});
|
|
OS << primTypeToString(Desc->getPrimType()) << " ";
|
|
}
|
|
TYPE_SWITCH(Desc->getPrimType(), { GP.deref<T>().print(OS); });
|
|
OS << "\n";
|
|
}
|
|
++GI;
|
|
}
|
|
|
|
{
|
|
ColorScope SC(OS, true, {llvm::raw_ostream::WHITE, true});
|
|
OS << "Functions: " << Funcs.size() << "\n";
|
|
}
|
|
for (const auto &Func : Funcs) {
|
|
Func.second->dump();
|
|
}
|
|
for (const auto &Anon : AnonFuncs) {
|
|
Anon->dump();
|
|
}
|
|
}
|
|
|
|
LLVM_DUMP_METHOD void Descriptor::dump() const {
|
|
dump(llvm::errs());
|
|
llvm::errs() << '\n';
|
|
}
|
|
|
|
LLVM_DUMP_METHOD void Descriptor::dump(llvm::raw_ostream &OS) const {
|
|
// Source
|
|
{
|
|
ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});
|
|
if (const auto *ND = dyn_cast_if_present<NamedDecl>(asDecl()))
|
|
ND->printQualifiedName(OS);
|
|
else if (asExpr())
|
|
OS << "expr (TODO)";
|
|
}
|
|
|
|
// Print a few interesting bits about the descriptor.
|
|
if (isPrimitiveArray())
|
|
OS << " primitive-array";
|
|
else if (isCompositeArray())
|
|
OS << " composite-array";
|
|
else if (isRecord())
|
|
OS << " record";
|
|
else if (isPrimitive())
|
|
OS << " primitive";
|
|
|
|
if (isZeroSizeArray())
|
|
OS << " zero-size-arrary";
|
|
else if (isUnknownSizeArray())
|
|
OS << " unknown-size-array";
|
|
|
|
if (isDummy())
|
|
OS << " dummy";
|
|
}
|
|
|
|
LLVM_DUMP_METHOD void InterpFrame::dump(llvm::raw_ostream &OS,
|
|
unsigned Indent) const {
|
|
unsigned Spaces = Indent * 2;
|
|
{
|
|
ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});
|
|
OS.indent(Spaces);
|
|
if (getCallee())
|
|
describe(OS);
|
|
else
|
|
OS << "Frame (Depth: " << getDepth() << ")";
|
|
OS << "\n";
|
|
}
|
|
OS.indent(Spaces) << "Function: " << getFunction();
|
|
if (const Function *F = getFunction()) {
|
|
OS << " (" << F->getName() << ")";
|
|
}
|
|
OS << "\n";
|
|
OS.indent(Spaces) << "This: " << getThis() << "\n";
|
|
OS.indent(Spaces) << "RVO: " << getRVOPtr() << "\n";
|
|
|
|
while (const InterpFrame *F = this->Caller) {
|
|
F->dump(OS, Indent + 1);
|
|
F = F->Caller;
|
|
}
|
|
}
|
|
|
|
LLVM_DUMP_METHOD void Record::dump(llvm::raw_ostream &OS, unsigned Indentation,
|
|
unsigned Offset) const {
|
|
unsigned Indent = Indentation * 2;
|
|
OS.indent(Indent);
|
|
{
|
|
ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});
|
|
OS << getName() << "\n";
|
|
}
|
|
|
|
unsigned I = 0;
|
|
for (const Record::Base &B : bases()) {
|
|
OS.indent(Indent) << "- Base " << I << ". Offset " << (Offset + B.Offset)
|
|
<< "\n";
|
|
B.R->dump(OS, Indentation + 1, Offset + B.Offset);
|
|
++I;
|
|
}
|
|
|
|
// FIXME: Virtual bases.
|
|
|
|
I = 0;
|
|
for (const Record::Field &F : fields()) {
|
|
OS.indent(Indent) << "- Field " << I << ": ";
|
|
{
|
|
ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_RED, true});
|
|
OS << F.Decl->getName();
|
|
}
|
|
OS << ". Offset " << (Offset + F.Offset) << "\n";
|
|
++I;
|
|
}
|
|
}
|