brintos

brintos / llvm-project-archived public Read only

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