1*1a427287SDan Gohman //==- WebAssemblyDisassembler.cpp - Disassembler for WebAssembly -*- C++ -*-==// 2*1a427287SDan Gohman // 3*1a427287SDan Gohman // The LLVM Compiler Infrastructure 4*1a427287SDan Gohman // 5*1a427287SDan Gohman // This file is distributed under the University of Illinois Open Source 6*1a427287SDan Gohman // License. See LICENSE.TXT for details. 7*1a427287SDan Gohman // 8*1a427287SDan Gohman //===----------------------------------------------------------------------===// 9*1a427287SDan Gohman /// 10*1a427287SDan Gohman /// \file 11*1a427287SDan Gohman /// \brief This file is part of the WebAssembly Disassembler. 12*1a427287SDan Gohman /// 13*1a427287SDan Gohman /// It contains code to translate the data produced by the decoder into 14*1a427287SDan Gohman /// MCInsts. 15*1a427287SDan Gohman /// 16*1a427287SDan Gohman //===----------------------------------------------------------------------===// 17*1a427287SDan Gohman 18*1a427287SDan Gohman #include "WebAssembly.h" 19*1a427287SDan Gohman #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 20*1a427287SDan Gohman #include "llvm/MC/MCContext.h" 21*1a427287SDan Gohman #include "llvm/MC/MCDisassembler.h" 22*1a427287SDan Gohman #include "llvm/MC/MCInst.h" 23*1a427287SDan Gohman #include "llvm/MC/MCInstrInfo.h" 24*1a427287SDan Gohman #include "llvm/MC/MCSubtargetInfo.h" 25*1a427287SDan Gohman #include "llvm/MC/MCSymbol.h" 26*1a427287SDan Gohman #include "llvm/Support/Endian.h" 27*1a427287SDan Gohman #include "llvm/Support/TargetRegistry.h" 28*1a427287SDan Gohman using namespace llvm; 29*1a427287SDan Gohman 30*1a427287SDan Gohman #define DEBUG_TYPE "wasm-disassembler" 31*1a427287SDan Gohman 32*1a427287SDan Gohman namespace { 33*1a427287SDan Gohman class WebAssemblyDisassembler final : public MCDisassembler { 34*1a427287SDan Gohman std::unique_ptr<const MCInstrInfo> MCII; 35*1a427287SDan Gohman 36*1a427287SDan Gohman DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size, 37*1a427287SDan Gohman ArrayRef<uint8_t> Bytes, uint64_t Address, 38*1a427287SDan Gohman raw_ostream &VStream, 39*1a427287SDan Gohman raw_ostream &CStream) const override; 40*1a427287SDan Gohman 41*1a427287SDan Gohman public: 42*1a427287SDan Gohman WebAssemblyDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx, 43*1a427287SDan Gohman std::unique_ptr<const MCInstrInfo> MCII) 44*1a427287SDan Gohman : MCDisassembler(STI, Ctx), MCII(std::move(MCII)) {} 45*1a427287SDan Gohman }; 46*1a427287SDan Gohman } // end anonymous namespace 47*1a427287SDan Gohman 48*1a427287SDan Gohman static MCDisassembler *createWebAssemblyDisassembler(const Target &T, 49*1a427287SDan Gohman const MCSubtargetInfo &STI, 50*1a427287SDan Gohman MCContext &Ctx) { 51*1a427287SDan Gohman std::unique_ptr<const MCInstrInfo> MCII(T.createMCInstrInfo()); 52*1a427287SDan Gohman return new WebAssemblyDisassembler(STI, Ctx, std::move(MCII)); 53*1a427287SDan Gohman } 54*1a427287SDan Gohman 55*1a427287SDan Gohman extern "C" void LLVMInitializeWebAssemblyDisassembler() { 56*1a427287SDan Gohman // Register the disassembler for each target. 57*1a427287SDan Gohman TargetRegistry::RegisterMCDisassembler(TheWebAssemblyTarget32, 58*1a427287SDan Gohman createWebAssemblyDisassembler); 59*1a427287SDan Gohman TargetRegistry::RegisterMCDisassembler(TheWebAssemblyTarget64, 60*1a427287SDan Gohman createWebAssemblyDisassembler); 61*1a427287SDan Gohman } 62*1a427287SDan Gohman 63*1a427287SDan Gohman MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction( 64*1a427287SDan Gohman MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes, uint64_t /*Address*/, 65*1a427287SDan Gohman raw_ostream &OS, raw_ostream &CS) const { 66*1a427287SDan Gohman Size = 0; 67*1a427287SDan Gohman uint64_t Pos = 0; 68*1a427287SDan Gohman 69*1a427287SDan Gohman // Read the opcode. 70*1a427287SDan Gohman if (Pos + sizeof(uint64_t) > Bytes.size()) 71*1a427287SDan Gohman return MCDisassembler::Fail; 72*1a427287SDan Gohman uint64_t Opcode = support::endian::read64le(Bytes.data() + Pos); 73*1a427287SDan Gohman Pos += sizeof(uint64_t); 74*1a427287SDan Gohman 75*1a427287SDan Gohman if (Opcode >= WebAssembly::INSTRUCTION_LIST_END) 76*1a427287SDan Gohman return MCDisassembler::Fail; 77*1a427287SDan Gohman 78*1a427287SDan Gohman MI.setOpcode(Opcode); 79*1a427287SDan Gohman const MCInstrDesc &Desc = MCII->get(Opcode); 80*1a427287SDan Gohman unsigned NumFixedOperands = Desc.NumOperands; 81*1a427287SDan Gohman 82*1a427287SDan Gohman // If it's variadic, read the number of extra operands. 83*1a427287SDan Gohman unsigned NumExtraOperands = 0; 84*1a427287SDan Gohman if (Desc.isVariadic()) { 85*1a427287SDan Gohman if (Pos + sizeof(uint64_t) > Bytes.size()) 86*1a427287SDan Gohman return MCDisassembler::Fail; 87*1a427287SDan Gohman NumExtraOperands = support::endian::read64le(Bytes.data() + Pos); 88*1a427287SDan Gohman Pos += sizeof(uint64_t); 89*1a427287SDan Gohman } 90*1a427287SDan Gohman 91*1a427287SDan Gohman // Read the fixed operands. These are described by the MCInstrDesc. 92*1a427287SDan Gohman for (unsigned i = 0; i < NumFixedOperands; ++i) { 93*1a427287SDan Gohman const MCOperandInfo &Info = Desc.OpInfo[i]; 94*1a427287SDan Gohman switch (Info.OperandType) { 95*1a427287SDan Gohman case MCOI::OPERAND_IMMEDIATE: 96*1a427287SDan Gohman case WebAssembly::OPERAND_BASIC_BLOCK: { 97*1a427287SDan Gohman if (Pos + sizeof(uint64_t) > Bytes.size()) 98*1a427287SDan Gohman return MCDisassembler::Fail; 99*1a427287SDan Gohman uint64_t Imm = support::endian::read64le(Bytes.data() + Pos); 100*1a427287SDan Gohman Pos += sizeof(uint64_t); 101*1a427287SDan Gohman MI.addOperand(MCOperand::createImm(Imm)); 102*1a427287SDan Gohman break; 103*1a427287SDan Gohman } 104*1a427287SDan Gohman case MCOI::OPERAND_REGISTER: { 105*1a427287SDan Gohman if (Pos + sizeof(uint64_t) > Bytes.size()) 106*1a427287SDan Gohman return MCDisassembler::Fail; 107*1a427287SDan Gohman uint64_t Reg = support::endian::read64le(Bytes.data() + Pos); 108*1a427287SDan Gohman Pos += sizeof(uint64_t); 109*1a427287SDan Gohman MI.addOperand(MCOperand::createReg(Reg)); 110*1a427287SDan Gohman break; 111*1a427287SDan Gohman } 112*1a427287SDan Gohman case WebAssembly::OPERAND_FPIMM: { 113*1a427287SDan Gohman // TODO: MC converts all floating point immediate operands to double. 114*1a427287SDan Gohman // This is fine for numeric values, but may cause NaNs to change bits. 115*1a427287SDan Gohman if (Pos + sizeof(uint64_t) > Bytes.size()) 116*1a427287SDan Gohman return MCDisassembler::Fail; 117*1a427287SDan Gohman uint64_t Bits = support::endian::read64le(Bytes.data() + Pos); 118*1a427287SDan Gohman Pos += sizeof(uint64_t); 119*1a427287SDan Gohman double Imm; 120*1a427287SDan Gohman memcpy(&Imm, &Bits, sizeof(Imm)); 121*1a427287SDan Gohman MI.addOperand(MCOperand::createFPImm(Imm)); 122*1a427287SDan Gohman break; 123*1a427287SDan Gohman } 124*1a427287SDan Gohman default: 125*1a427287SDan Gohman llvm_unreachable("unimplemented operand kind"); 126*1a427287SDan Gohman } 127*1a427287SDan Gohman } 128*1a427287SDan Gohman 129*1a427287SDan Gohman // Read the extra operands. 130*1a427287SDan Gohman assert(NumExtraOperands == 0 || Desc.isVariadic()); 131*1a427287SDan Gohman for (unsigned i = 0; i < NumExtraOperands; ++i) { 132*1a427287SDan Gohman if (Pos + sizeof(uint64_t) > Bytes.size()) 133*1a427287SDan Gohman return MCDisassembler::Fail; 134*1a427287SDan Gohman if (Desc.TSFlags & WebAssemblyII::VariableOpIsImmediate) { 135*1a427287SDan Gohman // Decode extra immediate operands. 136*1a427287SDan Gohman uint64_t Imm = support::endian::read64le(Bytes.data() + Pos); 137*1a427287SDan Gohman MI.addOperand(MCOperand::createImm(Imm)); 138*1a427287SDan Gohman } else { 139*1a427287SDan Gohman // Decode extra register operands. 140*1a427287SDan Gohman uint64_t Reg = support::endian::read64le(Bytes.data() + Pos); 141*1a427287SDan Gohman MI.addOperand(MCOperand::createReg(Reg)); 142*1a427287SDan Gohman } 143*1a427287SDan Gohman Pos += sizeof(uint64_t); 144*1a427287SDan Gohman } 145*1a427287SDan Gohman 146*1a427287SDan Gohman Size = Pos; 147*1a427287SDan Gohman return MCDisassembler::Success; 148*1a427287SDan Gohman } 149