Path: blob/main/contrib/llvm-project/clang/lib/AST/ByteCode/Disasm.cpp
213799 views
//===--- Disasm.cpp - Disassembler for bytecode functions -------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Dump method for Function which disassembles the bytecode.9//10//===----------------------------------------------------------------------===//1112#include "Boolean.h"13#include "Context.h"14#include "EvaluationResult.h"15#include "FixedPoint.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"3031using namespace clang;32using namespace clang::interp;3334template <typename T>35inline static std::string printArg(Program &P, CodePtr &OpPC) {36if constexpr (std::is_pointer_v<T>) {37uint32_t ID = OpPC.read<uint32_t>();38std::string Result;39llvm::raw_string_ostream SS(Result);40SS << reinterpret_cast<T>(P.getNativePointer(ID));41return Result;42} else {43std::string Result;44llvm::raw_string_ostream SS(Result);45auto Arg = OpPC.read<T>();46SS << Arg;47return Result;48}49}5051template <> inline std::string printArg<Floating>(Program &P, CodePtr &OpPC) {52auto Sem = Floating::deserializeSemantics(*OpPC);5354unsigned BitWidth = llvm::APFloatBase::semanticsSizeInBits(55llvm::APFloatBase::EnumToSemantics(Sem));56auto Memory =57std::make_unique<uint64_t[]>(llvm::APInt::getNumWords(BitWidth));58Floating Result(Memory.get(), Sem);59Floating::deserialize(*OpPC, &Result);6061OpPC += align(Result.bytesToSerialize());6263std::string S;64llvm::raw_string_ostream SS(S);65SS << std::move(Result);66return S;67}6869template <>70inline std::string printArg<IntegralAP<false>>(Program &P, CodePtr &OpPC) {71using T = IntegralAP<false>;72uint32_t BitWidth = T::deserializeSize(*OpPC);73auto Memory =74std::make_unique<uint64_t[]>(llvm::APInt::getNumWords(BitWidth));7576T Result(Memory.get(), BitWidth);77T::deserialize(*OpPC, &Result);7879OpPC += align(Result.bytesToSerialize());8081std::string Str;82llvm::raw_string_ostream SS(Str);83SS << std::move(Result);84return Str;85}8687template <>88inline std::string printArg<IntegralAP<true>>(Program &P, CodePtr &OpPC) {89using T = IntegralAP<true>;90uint32_t BitWidth = T::deserializeSize(*OpPC);91auto Memory =92std::make_unique<uint64_t[]>(llvm::APInt::getNumWords(BitWidth));9394T Result(Memory.get(), BitWidth);95T::deserialize(*OpPC, &Result);9697OpPC += align(Result.bytesToSerialize());9899std::string Str;100llvm::raw_string_ostream SS(Str);101SS << std::move(Result);102return Str;103}104105template <> inline std::string printArg<FixedPoint>(Program &P, CodePtr &OpPC) {106auto F = FixedPoint::deserialize(*OpPC);107OpPC += align(F.bytesToSerialize());108109std::string Result;110llvm::raw_string_ostream SS(Result);111SS << std::move(F);112return Result;113}114115static bool isJumpOpcode(Opcode Op) {116return Op == OP_Jmp || Op == OP_Jf || Op == OP_Jt;117}118119static size_t getNumDisplayWidth(size_t N) {120unsigned L = 1u, M = 10u;121while (M <= N && ++L != std::numeric_limits<size_t>::digits10 + 1)122M *= 10u;123124return L;125}126127LLVM_DUMP_METHOD void Function::dump() const { dump(llvm::errs()); }128129LLVM_DUMP_METHOD void Function::dump(llvm::raw_ostream &OS) const {130{131ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_GREEN, true});132OS << getName() << " " << (const void *)this << "\n";133}134OS << "frame size: " << getFrameSize() << "\n";135OS << "arg size: " << getArgSize() << "\n";136OS << "rvo: " << hasRVO() << "\n";137OS << "this arg: " << hasThisPointer() << "\n";138139struct OpText {140size_t Addr;141std::string Op;142bool IsJump;143llvm::SmallVector<std::string> Args;144};145146auto PrintName = [](const char *Name) -> std::string {147return std::string(Name);148};149150llvm::SmallVector<OpText> Code;151size_t LongestAddr = 0;152size_t LongestOp = 0;153154for (CodePtr Start = getCodeBegin(), PC = Start; PC != getCodeEnd();) {155size_t Addr = PC - Start;156OpText Text;157auto Op = PC.read<Opcode>();158Text.Addr = Addr;159Text.IsJump = isJumpOpcode(Op);160switch (Op) {161#define GET_DISASM162#include "Opcodes.inc"163#undef GET_DISASM164}165Code.push_back(Text);166LongestOp = std::max(Text.Op.size(), LongestOp);167LongestAddr = std::max(getNumDisplayWidth(Addr), LongestAddr);168}169170// Record jumps and their targets.171struct JmpData {172size_t From;173size_t To;174};175llvm::SmallVector<JmpData> Jumps;176for (auto &Text : Code) {177if (Text.IsJump)178Jumps.push_back({Text.Addr, Text.Addr + std::stoi(Text.Args[0]) +179align(sizeof(Opcode)) +180align(sizeof(int32_t))});181}182183llvm::SmallVector<std::string> Text;184Text.reserve(Code.size());185size_t LongestLine = 0;186// Print code to a string, one at a time.187for (auto C : Code) {188std::string Line;189llvm::raw_string_ostream LS(Line);190LS << C.Addr;191LS.indent(LongestAddr - getNumDisplayWidth(C.Addr) + 4);192LS << C.Op;193LS.indent(LongestOp - C.Op.size() + 4);194for (auto &Arg : C.Args) {195LS << Arg << ' ';196}197Text.push_back(Line);198LongestLine = std::max(Line.size(), LongestLine);199}200201assert(Code.size() == Text.size());202203auto spaces = [](unsigned N) -> std::string {204std::string S;205for (unsigned I = 0; I != N; ++I)206S += ' ';207return S;208};209210// Now, draw the jump lines.211for (auto &J : Jumps) {212if (J.To > J.From) {213bool FoundStart = false;214for (size_t LineIndex = 0; LineIndex != Text.size(); ++LineIndex) {215Text[LineIndex] += spaces(LongestLine - Text[LineIndex].size());216217if (Code[LineIndex].Addr == J.From) {218Text[LineIndex] += " --+";219FoundStart = true;220} else if (Code[LineIndex].Addr == J.To) {221Text[LineIndex] += " <-+";222break;223} else if (FoundStart) {224Text[LineIndex] += " |";225}226}227LongestLine += 5;228} else {229bool FoundStart = false;230for (ssize_t LineIndex = Text.size() - 1; LineIndex >= 0; --LineIndex) {231Text[LineIndex] += spaces(LongestLine - Text[LineIndex].size());232if (Code[LineIndex].Addr == J.From) {233Text[LineIndex] += " --+";234FoundStart = true;235} else if (Code[LineIndex].Addr == J.To) {236Text[LineIndex] += " <-+";237break;238} else if (FoundStart) {239Text[LineIndex] += " |";240}241}242LongestLine += 5;243}244}245246for (auto &Line : Text)247OS << Line << '\n';248}249250LLVM_DUMP_METHOD void Program::dump() const { dump(llvm::errs()); }251252static const char *primTypeToString(PrimType T) {253switch (T) {254case PT_Sint8:255return "Sint8";256case PT_Uint8:257return "Uint8";258case PT_Sint16:259return "Sint16";260case PT_Uint16:261return "Uint16";262case PT_Sint32:263return "Sint32";264case PT_Uint32:265return "Uint32";266case PT_Sint64:267return "Sint64";268case PT_Uint64:269return "Uint64";270case PT_IntAP:271return "IntAP";272case PT_IntAPS:273return "IntAPS";274case PT_Bool:275return "Bool";276case PT_Float:277return "Float";278case PT_Ptr:279return "Ptr";280case PT_MemberPtr:281return "MemberPtr";282case PT_FixedPoint:283return "FixedPoint";284}285llvm_unreachable("Unhandled PrimType");286}287288LLVM_DUMP_METHOD void Program::dump(llvm::raw_ostream &OS) const {289{290ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_RED, true});291OS << "\n:: Program\n";292}293294{295ColorScope SC(OS, true, {llvm::raw_ostream::WHITE, true});296OS << "Total memory : " << Allocator.getTotalMemory() << " bytes\n";297OS << "Global Variables: " << Globals.size() << "\n";298}299unsigned GI = 0;300for (const Global *G : Globals) {301const Descriptor *Desc = G->block()->getDescriptor();302Pointer GP = getPtrGlobal(GI);303304OS << GI << ": " << (const void *)G->block() << " ";305{306ColorScope SC(OS, true,307GP.isInitialized()308? TerminalColor{llvm::raw_ostream::GREEN, false}309: TerminalColor{llvm::raw_ostream::RED, false});310OS << (GP.isInitialized() ? "initialized " : "uninitialized ");311}312Desc->dump(OS);313314if (GP.isInitialized() && Desc->IsTemporary) {315if (const auto *MTE =316dyn_cast_if_present<MaterializeTemporaryExpr>(Desc->asExpr());317MTE && MTE->getLifetimeExtendedTemporaryDecl()) {318if (const APValue *V =319MTE->getLifetimeExtendedTemporaryDecl()->getValue()) {320OS << " (global temporary value: ";321{322ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_MAGENTA, true});323std::string VStr;324llvm::raw_string_ostream SS(VStr);325V->dump(SS, Ctx.getASTContext());326327for (unsigned I = 0; I != VStr.size(); ++I) {328if (VStr[I] == '\n')329VStr[I] = ' ';330}331VStr.pop_back(); // Remove the newline (or now space) at the end.332OS << VStr;333}334OS << ')';335}336}337}338339OS << "\n";340if (GP.isInitialized() && Desc->isPrimitive() && !Desc->isDummy()) {341OS << " ";342{343ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_CYAN, false});344OS << primTypeToString(Desc->getPrimType()) << " ";345}346TYPE_SWITCH(Desc->getPrimType(), { GP.deref<T>().print(OS); });347OS << "\n";348}349++GI;350}351352{353ColorScope SC(OS, true, {llvm::raw_ostream::WHITE, true});354OS << "Functions: " << Funcs.size() << "\n";355}356for (const auto &Func : Funcs) {357Func.second->dump();358}359for (const auto &Anon : AnonFuncs) {360Anon->dump();361}362}363364LLVM_DUMP_METHOD void Descriptor::dump() const {365dump(llvm::errs());366llvm::errs() << '\n';367}368369LLVM_DUMP_METHOD void Descriptor::dump(llvm::raw_ostream &OS) const {370// Source371{372ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});373if (const auto *ND = dyn_cast_if_present<NamedDecl>(asDecl()))374ND->printQualifiedName(OS);375else if (asExpr())376OS << "Expr " << (const void *)asExpr();377}378379// Print a few interesting bits about the descriptor.380if (isPrimitiveArray())381OS << " primitive-array";382else if (isCompositeArray())383OS << " composite-array";384else if (isUnion())385OS << " union";386else if (isRecord())387OS << " record";388else if (isPrimitive())389OS << " primitive " << primTypeToString(getPrimType());390391if (isZeroSizeArray())392OS << " zero-size-array";393else if (isUnknownSizeArray())394OS << " unknown-size-array";395396if (isDummy())397OS << " dummy";398if (IsConstexprUnknown)399OS << " constexpr-unknown";400}401402/// Dump descriptor, including all valid offsets.403LLVM_DUMP_METHOD void Descriptor::dumpFull(unsigned Offset,404unsigned Indent) const {405unsigned Spaces = Indent * 2;406llvm::raw_ostream &OS = llvm::errs();407OS.indent(Spaces);408dump(OS);409OS << '\n';410OS.indent(Spaces) << "Metadata: " << getMetadataSize() << " bytes\n";411OS.indent(Spaces) << "Size: " << getSize() << " bytes\n";412OS.indent(Spaces) << "AllocSize: " << getAllocSize() << " bytes\n";413Offset += getMetadataSize();414if (isCompositeArray()) {415OS.indent(Spaces) << "Elements: " << getNumElems() << '\n';416unsigned FO = Offset;417for (unsigned I = 0; I != getNumElems(); ++I) {418FO += sizeof(InlineDescriptor);419assert(ElemDesc->getMetadataSize() == 0);420OS.indent(Spaces) << "Element " << I << " offset: " << FO << '\n';421ElemDesc->dumpFull(FO, Indent + 1);422423FO += ElemDesc->getAllocSize();424}425} else if (isRecord()) {426ElemRecord->dump(OS, Indent + 1, Offset);427} else if (isPrimitive()) {428} else {429}430431OS << '\n';432}433434LLVM_DUMP_METHOD void InlineDescriptor::dump(llvm::raw_ostream &OS) const {435{436ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});437OS << "InlineDescriptor " << (const void *)this << "\n";438}439OS << "Offset: " << Offset << "\n";440OS << "IsConst: " << IsConst << "\n";441OS << "IsInitialized: " << IsInitialized << "\n";442OS << "IsBase: " << IsBase << "\n";443OS << "IsActive: " << IsActive << "\n";444OS << "InUnion: " << InUnion << "\n";445OS << "IsFieldMutable: " << IsFieldMutable << "\n";446OS << "IsArrayElement: " << IsArrayElement << "\n";447OS << "Desc: ";448if (Desc)449Desc->dump(OS);450else451OS << "nullptr";452OS << "\n";453}454455LLVM_DUMP_METHOD void InterpFrame::dump(llvm::raw_ostream &OS,456unsigned Indent) const {457unsigned Spaces = Indent * 2;458{459ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});460OS.indent(Spaces);461if (getCallee())462describe(OS);463else464OS << "Frame (Depth: " << getDepth() << ")";465OS << "\n";466}467OS.indent(Spaces) << "Function: " << getFunction();468if (const Function *F = getFunction()) {469OS << " (" << F->getName() << ")";470}471OS << "\n";472OS.indent(Spaces) << "This: " << getThis() << "\n";473OS.indent(Spaces) << "RVO: " << getRVOPtr() << "\n";474OS.indent(Spaces) << "Depth: " << Depth << "\n";475OS.indent(Spaces) << "ArgSize: " << ArgSize << "\n";476OS.indent(Spaces) << "Args: " << (void *)Args << "\n";477OS.indent(Spaces) << "FrameOffset: " << FrameOffset << "\n";478OS.indent(Spaces) << "FrameSize: " << (Func ? Func->getFrameSize() : 0)479<< "\n";480481for (const InterpFrame *F = this->Caller; F; F = F->Caller) {482F->dump(OS, Indent + 1);483}484}485486LLVM_DUMP_METHOD void Record::dump(llvm::raw_ostream &OS, unsigned Indentation,487unsigned Offset) const {488unsigned Indent = Indentation * 2;489OS.indent(Indent);490{491ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});492OS << getName() << "\n";493}494495unsigned I = 0;496for (const Record::Base &B : bases()) {497OS.indent(Indent) << "- Base " << I << ". Offset " << (Offset + B.Offset)498<< "\n";499B.R->dump(OS, Indentation + 1, Offset + B.Offset);500++I;501}502503I = 0;504for (const Record::Field &F : fields()) {505OS.indent(Indent) << "- Field " << I << ": ";506{507ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_RED, true});508OS << F.Decl->getName();509}510OS << ". Offset " << (Offset + F.Offset) << "\n";511++I;512}513514I = 0;515for (const Record::Base &B : virtual_bases()) {516OS.indent(Indent) << "- Virtual Base " << I << ". Offset "517<< (Offset + B.Offset) << "\n";518B.R->dump(OS, Indentation + 1, Offset + B.Offset);519++I;520}521}522523LLVM_DUMP_METHOD void Block::dump(llvm::raw_ostream &OS) const {524{525ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_BLUE, true});526OS << "Block " << (const void *)this;527}528OS << " (";529Desc->dump(OS);530OS << ")\n";531unsigned NPointers = 0;532for (const Pointer *P = Pointers; P; P = P->Next) {533++NPointers;534}535OS << " EvalID: " << EvalID << '\n';536OS << " DeclID: ";537if (DeclID)538OS << *DeclID << '\n';539else540OS << "-\n";541OS << " Pointers: " << NPointers << "\n";542OS << " Dead: " << IsDead << "\n";543OS << " Static: " << IsStatic << "\n";544OS << " Extern: " << IsExtern << "\n";545OS << " Initialized: " << IsInitialized << "\n";546OS << " Weak: " << IsWeak << "\n";547OS << " Dynamic: " << IsDynamic << "\n";548}549550LLVM_DUMP_METHOD void EvaluationResult::dump() const {551assert(Ctx);552auto &OS = llvm::errs();553const ASTContext &ASTCtx = Ctx->getASTContext();554555switch (Kind) {556case Empty:557OS << "Empty\n";558break;559case RValue:560OS << "RValue: ";561std::get<APValue>(Value).dump(OS, ASTCtx);562break;563case LValue: {564assert(Source);565QualType SourceType;566if (const auto *D = dyn_cast<const Decl *>(Source)) {567if (const auto *VD = dyn_cast<ValueDecl>(D))568SourceType = VD->getType();569} else if (const auto *E = dyn_cast<const Expr *>(Source)) {570SourceType = E->getType();571}572573OS << "LValue: ";574if (const auto *P = std::get_if<Pointer>(&Value))575P->toAPValue(ASTCtx).printPretty(OS, ASTCtx, SourceType);576else if (const auto *FP = std::get_if<FunctionPointer>(&Value)) // Nope577FP->toAPValue(ASTCtx).printPretty(OS, ASTCtx, SourceType);578OS << "\n";579break;580}581case Invalid:582OS << "Invalid\n";583break;584case Valid:585OS << "Valid\n";586break;587}588}589590591