11a427287SDan Gohman //==- WebAssemblyDisassembler.cpp - Disassembler for WebAssembly -*- C++ -*-==// 21a427287SDan Gohman // 31a427287SDan Gohman // The LLVM Compiler Infrastructure 41a427287SDan Gohman // 51a427287SDan Gohman // This file is distributed under the University of Illinois Open Source 61a427287SDan Gohman // License. See LICENSE.TXT for details. 71a427287SDan Gohman // 81a427287SDan Gohman //===----------------------------------------------------------------------===// 91a427287SDan Gohman /// 101a427287SDan Gohman /// \file 111a427287SDan Gohman /// \brief This file is part of the WebAssembly Disassembler. 121a427287SDan Gohman /// 131a427287SDan Gohman /// It contains code to translate the data produced by the decoder into 141a427287SDan Gohman /// MCInsts. 151a427287SDan Gohman /// 161a427287SDan Gohman //===----------------------------------------------------------------------===// 171a427287SDan Gohman 181a427287SDan Gohman #include "WebAssembly.h" 191a427287SDan Gohman #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 201a427287SDan Gohman #include "llvm/MC/MCContext.h" 21c50b8907SBenjamin Kramer #include "llvm/MC/MCDisassembler/MCDisassembler.h" 221a427287SDan Gohman #include "llvm/MC/MCInst.h" 231a427287SDan Gohman #include "llvm/MC/MCInstrInfo.h" 241a427287SDan Gohman #include "llvm/MC/MCSubtargetInfo.h" 251a427287SDan Gohman #include "llvm/MC/MCSymbol.h" 261a427287SDan Gohman #include "llvm/Support/Endian.h" 271a427287SDan Gohman #include "llvm/Support/TargetRegistry.h" 281a427287SDan Gohman using namespace llvm; 291a427287SDan Gohman 301a427287SDan Gohman #define DEBUG_TYPE "wasm-disassembler" 311a427287SDan Gohman 321a427287SDan Gohman namespace { 331a427287SDan Gohman class WebAssemblyDisassembler final : public MCDisassembler { 341a427287SDan Gohman std::unique_ptr<const MCInstrInfo> MCII; 351a427287SDan Gohman 361a427287SDan Gohman DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size, 371a427287SDan Gohman ArrayRef<uint8_t> Bytes, uint64_t Address, 381a427287SDan Gohman raw_ostream &VStream, 391a427287SDan Gohman raw_ostream &CStream) const override; 401a427287SDan Gohman 411a427287SDan Gohman public: 421a427287SDan Gohman WebAssemblyDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx, 431a427287SDan Gohman std::unique_ptr<const MCInstrInfo> MCII) 441a427287SDan Gohman : MCDisassembler(STI, Ctx), MCII(std::move(MCII)) {} 451a427287SDan Gohman }; 461a427287SDan Gohman } // end anonymous namespace 471a427287SDan Gohman 481a427287SDan Gohman static MCDisassembler *createWebAssemblyDisassembler(const Target &T, 491a427287SDan Gohman const MCSubtargetInfo &STI, 501a427287SDan Gohman MCContext &Ctx) { 511a427287SDan Gohman std::unique_ptr<const MCInstrInfo> MCII(T.createMCInstrInfo()); 521a427287SDan Gohman return new WebAssemblyDisassembler(STI, Ctx, std::move(MCII)); 531a427287SDan Gohman } 541a427287SDan Gohman 551a427287SDan Gohman extern "C" void LLVMInitializeWebAssemblyDisassembler() { 561a427287SDan Gohman // Register the disassembler for each target. 57*f42454b9SMehdi Amini TargetRegistry::RegisterMCDisassembler(getTheWebAssemblyTarget32(), 581a427287SDan Gohman createWebAssemblyDisassembler); 59*f42454b9SMehdi Amini TargetRegistry::RegisterMCDisassembler(getTheWebAssemblyTarget64(), 601a427287SDan Gohman createWebAssemblyDisassembler); 611a427287SDan Gohman } 621a427287SDan Gohman 631a427287SDan Gohman MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction( 641a427287SDan Gohman MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes, uint64_t /*Address*/, 651a427287SDan Gohman raw_ostream &OS, raw_ostream &CS) const { 661a427287SDan Gohman Size = 0; 671a427287SDan Gohman uint64_t Pos = 0; 681a427287SDan Gohman 691a427287SDan Gohman // Read the opcode. 701a427287SDan Gohman if (Pos + sizeof(uint64_t) > Bytes.size()) 711a427287SDan Gohman return MCDisassembler::Fail; 721a427287SDan Gohman uint64_t Opcode = support::endian::read64le(Bytes.data() + Pos); 731a427287SDan Gohman Pos += sizeof(uint64_t); 741a427287SDan Gohman 751a427287SDan Gohman if (Opcode >= WebAssembly::INSTRUCTION_LIST_END) 761a427287SDan Gohman return MCDisassembler::Fail; 771a427287SDan Gohman 781a427287SDan Gohman MI.setOpcode(Opcode); 791a427287SDan Gohman const MCInstrDesc &Desc = MCII->get(Opcode); 801a427287SDan Gohman unsigned NumFixedOperands = Desc.NumOperands; 811a427287SDan Gohman 821a427287SDan Gohman // If it's variadic, read the number of extra operands. 831a427287SDan Gohman unsigned NumExtraOperands = 0; 841a427287SDan Gohman if (Desc.isVariadic()) { 851a427287SDan Gohman if (Pos + sizeof(uint64_t) > Bytes.size()) 861a427287SDan Gohman return MCDisassembler::Fail; 871a427287SDan Gohman NumExtraOperands = support::endian::read64le(Bytes.data() + Pos); 881a427287SDan Gohman Pos += sizeof(uint64_t); 891a427287SDan Gohman } 901a427287SDan Gohman 911a427287SDan Gohman // Read the fixed operands. These are described by the MCInstrDesc. 921a427287SDan Gohman for (unsigned i = 0; i < NumFixedOperands; ++i) { 931a427287SDan Gohman const MCOperandInfo &Info = Desc.OpInfo[i]; 941a427287SDan Gohman switch (Info.OperandType) { 951a427287SDan Gohman case MCOI::OPERAND_IMMEDIATE: 96bb372243SDan Gohman case WebAssembly::OPERAND_P2ALIGN: 971a427287SDan Gohman case WebAssembly::OPERAND_BASIC_BLOCK: { 981a427287SDan Gohman if (Pos + sizeof(uint64_t) > Bytes.size()) 991a427287SDan Gohman return MCDisassembler::Fail; 1001a427287SDan Gohman uint64_t Imm = support::endian::read64le(Bytes.data() + Pos); 1011a427287SDan Gohman Pos += sizeof(uint64_t); 1021a427287SDan Gohman MI.addOperand(MCOperand::createImm(Imm)); 1031a427287SDan Gohman break; 1041a427287SDan Gohman } 1051a427287SDan Gohman case MCOI::OPERAND_REGISTER: { 1061a427287SDan Gohman if (Pos + sizeof(uint64_t) > Bytes.size()) 1071a427287SDan Gohman return MCDisassembler::Fail; 1081a427287SDan Gohman uint64_t Reg = support::endian::read64le(Bytes.data() + Pos); 1091a427287SDan Gohman Pos += sizeof(uint64_t); 1101a427287SDan Gohman MI.addOperand(MCOperand::createReg(Reg)); 1111a427287SDan Gohman break; 1121a427287SDan Gohman } 1134b8e8becSDan Gohman case WebAssembly::OPERAND_F32IMM: 1144b8e8becSDan Gohman case WebAssembly::OPERAND_F64IMM: { 1151a427287SDan Gohman // TODO: MC converts all floating point immediate operands to double. 1161a427287SDan Gohman // This is fine for numeric values, but may cause NaNs to change bits. 1171a427287SDan Gohman if (Pos + sizeof(uint64_t) > Bytes.size()) 1181a427287SDan Gohman return MCDisassembler::Fail; 1191a427287SDan Gohman uint64_t Bits = support::endian::read64le(Bytes.data() + Pos); 1201a427287SDan Gohman Pos += sizeof(uint64_t); 1211a427287SDan Gohman double Imm; 1221a427287SDan Gohman memcpy(&Imm, &Bits, sizeof(Imm)); 1231a427287SDan Gohman MI.addOperand(MCOperand::createFPImm(Imm)); 1241a427287SDan Gohman break; 1251a427287SDan Gohman } 1261a427287SDan Gohman default: 1271a427287SDan Gohman llvm_unreachable("unimplemented operand kind"); 1281a427287SDan Gohman } 1291a427287SDan Gohman } 1301a427287SDan Gohman 1311a427287SDan Gohman // Read the extra operands. 1321a427287SDan Gohman assert(NumExtraOperands == 0 || Desc.isVariadic()); 1331a427287SDan Gohman for (unsigned i = 0; i < NumExtraOperands; ++i) { 1341a427287SDan Gohman if (Pos + sizeof(uint64_t) > Bytes.size()) 1351a427287SDan Gohman return MCDisassembler::Fail; 1361a427287SDan Gohman if (Desc.TSFlags & WebAssemblyII::VariableOpIsImmediate) { 1371a427287SDan Gohman // Decode extra immediate operands. 1381a427287SDan Gohman uint64_t Imm = support::endian::read64le(Bytes.data() + Pos); 1391a427287SDan Gohman MI.addOperand(MCOperand::createImm(Imm)); 1401a427287SDan Gohman } else { 1411a427287SDan Gohman // Decode extra register operands. 1421a427287SDan Gohman uint64_t Reg = support::endian::read64le(Bytes.data() + Pos); 1431a427287SDan Gohman MI.addOperand(MCOperand::createReg(Reg)); 1441a427287SDan Gohman } 1451a427287SDan Gohman Pos += sizeof(uint64_t); 1461a427287SDan Gohman } 1471a427287SDan Gohman 1481a427287SDan Gohman Size = Pos; 1491a427287SDan Gohman return MCDisassembler::Success; 1501a427287SDan Gohman } 151