Path: blob/main/contrib/llvm-project/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
35326 views
//==- WebAssemblyDisassembler.cpp - Disassembler for WebAssembly -*- 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/// \file9/// This file is part of the WebAssembly Disassembler.10///11/// It contains code to translate the data produced by the decoder into12/// MCInsts.13///14//===----------------------------------------------------------------------===//1516#include "MCTargetDesc/WebAssemblyMCTypeUtilities.h"17#include "TargetInfo/WebAssemblyTargetInfo.h"18#include "llvm/BinaryFormat/Wasm.h"19#include "llvm/MC/MCContext.h"20#include "llvm/MC/MCDecoderOps.h"21#include "llvm/MC/MCDisassembler/MCDisassembler.h"22#include "llvm/MC/MCInst.h"23#include "llvm/MC/MCInstrInfo.h"24#include "llvm/MC/MCSubtargetInfo.h"25#include "llvm/MC/MCSymbol.h"26#include "llvm/MC/MCSymbolWasm.h"27#include "llvm/MC/TargetRegistry.h"28#include "llvm/Support/Casting.h"29#include "llvm/Support/Endian.h"30#include "llvm/Support/LEB128.h"3132using namespace llvm;3334#define DEBUG_TYPE "wasm-disassembler"3536using DecodeStatus = MCDisassembler::DecodeStatus;3738#include "WebAssemblyGenDisassemblerTables.inc"3940namespace {41static constexpr int WebAssemblyInstructionTableSize = 256;4243class WebAssemblyDisassembler final : public MCDisassembler {44std::unique_ptr<const MCInstrInfo> MCII;4546DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,47ArrayRef<uint8_t> Bytes, uint64_t Address,48raw_ostream &CStream) const override;4950Expected<bool> onSymbolStart(SymbolInfoTy &Symbol, uint64_t &Size,51ArrayRef<uint8_t> Bytes,52uint64_t Address) const override;5354public:55WebAssemblyDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx,56std::unique_ptr<const MCInstrInfo> MCII)57: MCDisassembler(STI, Ctx), MCII(std::move(MCII)) {}58};59} // end anonymous namespace6061static MCDisassembler *createWebAssemblyDisassembler(const Target &T,62const MCSubtargetInfo &STI,63MCContext &Ctx) {64std::unique_ptr<const MCInstrInfo> MCII(T.createMCInstrInfo());65return new WebAssemblyDisassembler(STI, Ctx, std::move(MCII));66}6768extern "C" LLVM_EXTERNAL_VISIBILITY void69LLVMInitializeWebAssemblyDisassembler() {70// Register the disassembler for each target.71TargetRegistry::RegisterMCDisassembler(getTheWebAssemblyTarget32(),72createWebAssemblyDisassembler);73TargetRegistry::RegisterMCDisassembler(getTheWebAssemblyTarget64(),74createWebAssemblyDisassembler);75}7677static int nextByte(ArrayRef<uint8_t> Bytes, uint64_t &Size) {78if (Size >= Bytes.size())79return -1;80auto V = Bytes[Size];81Size++;82return V;83}8485static bool nextLEB(int64_t &Val, ArrayRef<uint8_t> Bytes, uint64_t &Size,86bool Signed) {87unsigned N = 0;88const char *Error = nullptr;89Val = Signed ? decodeSLEB128(Bytes.data() + Size, &N,90Bytes.data() + Bytes.size(), &Error)91: static_cast<int64_t>(decodeULEB128(Bytes.data() + Size, &N,92Bytes.data() + Bytes.size(),93&Error));94if (Error)95return false;96Size += N;97return true;98}99100static bool parseLEBImmediate(MCInst &MI, uint64_t &Size,101ArrayRef<uint8_t> Bytes, bool Signed) {102int64_t Val;103if (!nextLEB(Val, Bytes, Size, Signed))104return false;105MI.addOperand(MCOperand::createImm(Val));106return true;107}108109template <typename T>110bool parseImmediate(MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes) {111if (Size + sizeof(T) > Bytes.size())112return false;113T Val =114support::endian::read<T, llvm::endianness::little>(Bytes.data() + Size);115Size += sizeof(T);116if (std::is_floating_point<T>::value) {117MI.addOperand(118MCOperand::createDFPImm(bit_cast<uint64_t>(static_cast<double>(Val))));119} else {120MI.addOperand(MCOperand::createImm(static_cast<int64_t>(Val)));121}122return true;123}124125Expected<bool> WebAssemblyDisassembler::onSymbolStart(SymbolInfoTy &Symbol,126uint64_t &Size,127ArrayRef<uint8_t> Bytes,128uint64_t Address) const {129Size = 0;130if (Symbol.Type == wasm::WASM_SYMBOL_TYPE_SECTION) {131// Start of a code section: we're parsing only the function count.132int64_t FunctionCount;133if (!nextLEB(FunctionCount, Bytes, Size, false))134return false;135outs() << " # " << FunctionCount << " functions in section.";136} else {137// Parse the start of a single function.138int64_t BodySize, LocalEntryCount;139if (!nextLEB(BodySize, Bytes, Size, false) ||140!nextLEB(LocalEntryCount, Bytes, Size, false))141return false;142if (LocalEntryCount) {143outs() << " .local ";144for (int64_t I = 0; I < LocalEntryCount; I++) {145int64_t Count, Type;146if (!nextLEB(Count, Bytes, Size, false) ||147!nextLEB(Type, Bytes, Size, false))148return false;149for (int64_t J = 0; J < Count; J++) {150if (I || J)151outs() << ", ";152outs() << WebAssembly::anyTypeToString(Type);153}154}155}156}157outs() << "\n";158return true;159}160161MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(162MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes, uint64_t /*Address*/,163raw_ostream &CS) const {164CommentStream = &CS;165Size = 0;166int Opc = nextByte(Bytes, Size);167if (Opc < 0)168return MCDisassembler::Fail;169const auto *WasmInst = &InstructionTable0[Opc];170// If this is a prefix byte, indirect to another table.171if (WasmInst->ET == ET_Prefix) {172WasmInst = nullptr;173// Linear search, so far only 2 entries.174for (auto PT = PrefixTable; PT->Table; PT++) {175if (PT->Prefix == Opc) {176WasmInst = PT->Table;177break;178}179}180if (!WasmInst)181return MCDisassembler::Fail;182int64_t PrefixedOpc;183if (!nextLEB(PrefixedOpc, Bytes, Size, false))184return MCDisassembler::Fail;185if (PrefixedOpc < 0 || PrefixedOpc >= WebAssemblyInstructionTableSize)186return MCDisassembler::Fail;187WasmInst += PrefixedOpc;188}189if (WasmInst->ET == ET_Unused)190return MCDisassembler::Fail;191// At this point we must have a valid instruction to decode.192assert(WasmInst->ET == ET_Instruction);193MI.setOpcode(WasmInst->Opcode);194// Parse any operands.195for (uint8_t OPI = 0; OPI < WasmInst->NumOperands; OPI++) {196auto OT = OperandTable[WasmInst->OperandStart + OPI];197switch (OT) {198// ULEB operands:199case WebAssembly::OPERAND_BASIC_BLOCK:200case WebAssembly::OPERAND_LOCAL:201case WebAssembly::OPERAND_GLOBAL:202case WebAssembly::OPERAND_FUNCTION32:203case WebAssembly::OPERAND_TABLE:204case WebAssembly::OPERAND_OFFSET32:205case WebAssembly::OPERAND_OFFSET64:206case WebAssembly::OPERAND_P2ALIGN:207case WebAssembly::OPERAND_TYPEINDEX:208case WebAssembly::OPERAND_TAG:209case MCOI::OPERAND_IMMEDIATE: {210if (!parseLEBImmediate(MI, Size, Bytes, false))211return MCDisassembler::Fail;212break;213}214// SLEB operands:215case WebAssembly::OPERAND_I32IMM:216case WebAssembly::OPERAND_I64IMM: {217if (!parseLEBImmediate(MI, Size, Bytes, true))218return MCDisassembler::Fail;219break;220}221// block_type operands:222case WebAssembly::OPERAND_SIGNATURE: {223int64_t Val;224uint64_t PrevSize = Size;225if (!nextLEB(Val, Bytes, Size, true))226return MCDisassembler::Fail;227if (Val < 0) {228// Negative values are single septet value types or empty types229if (Size != PrevSize + 1) {230MI.addOperand(231MCOperand::createImm(int64_t(WebAssembly::BlockType::Invalid)));232} else {233MI.addOperand(MCOperand::createImm(Val & 0x7f));234}235} else {236// We don't have access to the signature, so create a symbol without one237MCSymbol *Sym = getContext().createTempSymbol("typeindex", true);238auto *WasmSym = cast<MCSymbolWasm>(Sym);239WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);240const MCExpr *Expr = MCSymbolRefExpr::create(241WasmSym, MCSymbolRefExpr::VK_WASM_TYPEINDEX, getContext());242MI.addOperand(MCOperand::createExpr(Expr));243}244break;245}246// FP operands.247case WebAssembly::OPERAND_F32IMM: {248if (!parseImmediate<float>(MI, Size, Bytes))249return MCDisassembler::Fail;250break;251}252case WebAssembly::OPERAND_F64IMM: {253if (!parseImmediate<double>(MI, Size, Bytes))254return MCDisassembler::Fail;255break;256}257// Vector lane operands (not LEB encoded).258case WebAssembly::OPERAND_VEC_I8IMM: {259if (!parseImmediate<uint8_t>(MI, Size, Bytes))260return MCDisassembler::Fail;261break;262}263case WebAssembly::OPERAND_VEC_I16IMM: {264if (!parseImmediate<uint16_t>(MI, Size, Bytes))265return MCDisassembler::Fail;266break;267}268case WebAssembly::OPERAND_VEC_I32IMM: {269if (!parseImmediate<uint32_t>(MI, Size, Bytes))270return MCDisassembler::Fail;271break;272}273case WebAssembly::OPERAND_VEC_I64IMM: {274if (!parseImmediate<uint64_t>(MI, Size, Bytes))275return MCDisassembler::Fail;276break;277}278case WebAssembly::OPERAND_BRLIST: {279int64_t TargetTableLen;280if (!nextLEB(TargetTableLen, Bytes, Size, false))281return MCDisassembler::Fail;282for (int64_t I = 0; I < TargetTableLen; I++) {283if (!parseLEBImmediate(MI, Size, Bytes, false))284return MCDisassembler::Fail;285}286// Default case.287if (!parseLEBImmediate(MI, Size, Bytes, false))288return MCDisassembler::Fail;289break;290}291case MCOI::OPERAND_REGISTER:292// The tablegen header currently does not have any register operands since293// we use only the stack (_S) instructions.294// If you hit this that probably means a bad instruction definition in295// tablegen.296llvm_unreachable("Register operand in WebAssemblyDisassembler");297default:298llvm_unreachable("Unknown operand type in WebAssemblyDisassembler");299}300}301return MCDisassembler::Success;302}303304305