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 115f8f34e4SAdrian Prantl /// 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 "MCTargetDesc/WebAssemblyMCTargetDesc.h" 191a427287SDan Gohman #include "llvm/MC/MCContext.h" 20c50b8907SBenjamin Kramer #include "llvm/MC/MCDisassembler/MCDisassembler.h" 2116c16827SSam Clegg #include "llvm/MC/MCFixedLenDisassembler.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" 2716c16827SSam Clegg #include "llvm/Support/LEB128.h" 281a427287SDan Gohman #include "llvm/Support/TargetRegistry.h" 2916c16827SSam Clegg 301a427287SDan Gohman using namespace llvm; 311a427287SDan Gohman 321a427287SDan Gohman #define DEBUG_TYPE "wasm-disassembler" 331a427287SDan Gohman 3416c16827SSam Clegg using DecodeStatus = MCDisassembler::DecodeStatus; 3516c16827SSam Clegg 3616c16827SSam Clegg #include "WebAssemblyGenDisassemblerTables.inc" 3716c16827SSam Clegg 381a427287SDan Gohman namespace { 391a427287SDan Gohman class WebAssemblyDisassembler final : public MCDisassembler { 401a427287SDan Gohman std::unique_ptr<const MCInstrInfo> MCII; 411a427287SDan Gohman 421a427287SDan Gohman DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size, 431a427287SDan Gohman ArrayRef<uint8_t> Bytes, uint64_t Address, 441a427287SDan Gohman raw_ostream &VStream, 451a427287SDan Gohman raw_ostream &CStream) const override; 461a427287SDan Gohman 471a427287SDan Gohman public: 481a427287SDan Gohman WebAssemblyDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx, 491a427287SDan Gohman std::unique_ptr<const MCInstrInfo> MCII) 501a427287SDan Gohman : MCDisassembler(STI, Ctx), MCII(std::move(MCII)) {} 511a427287SDan Gohman }; 521a427287SDan Gohman } // end anonymous namespace 531a427287SDan Gohman 541a427287SDan Gohman static MCDisassembler *createWebAssemblyDisassembler(const Target &T, 551a427287SDan Gohman const MCSubtargetInfo &STI, 561a427287SDan Gohman MCContext &Ctx) { 571a427287SDan Gohman std::unique_ptr<const MCInstrInfo> MCII(T.createMCInstrInfo()); 581a427287SDan Gohman return new WebAssemblyDisassembler(STI, Ctx, std::move(MCII)); 591a427287SDan Gohman } 601a427287SDan Gohman 611a427287SDan Gohman extern "C" void LLVMInitializeWebAssemblyDisassembler() { 621a427287SDan Gohman // Register the disassembler for each target. 63f42454b9SMehdi Amini TargetRegistry::RegisterMCDisassembler(getTheWebAssemblyTarget32(), 641a427287SDan Gohman createWebAssemblyDisassembler); 65f42454b9SMehdi Amini TargetRegistry::RegisterMCDisassembler(getTheWebAssemblyTarget64(), 661a427287SDan Gohman createWebAssemblyDisassembler); 671a427287SDan Gohman } 681a427287SDan Gohman 69*2faf0794SThomas Lively static uint8_t nextByte(ArrayRef<uint8_t> Bytes, uint64_t &Size) { 7016c16827SSam Clegg if (Size >= Bytes.size()) 7116c16827SSam Clegg return -1; 7216c16827SSam Clegg auto V = Bytes[Size]; 7316c16827SSam Clegg Size++; 7416c16827SSam Clegg return V; 7516c16827SSam Clegg } 7616c16827SSam Clegg 77*2faf0794SThomas Lively static bool nextLEB(int64_t &Val, ArrayRef<uint8_t> Bytes, uint64_t &Size, 78*2faf0794SThomas Lively bool Signed = false) { 7916c16827SSam Clegg unsigned N = 0; 8016c16827SSam Clegg const char *Error = nullptr; 81*2faf0794SThomas Lively Val = Signed ? decodeSLEB128(Bytes.data() + Size, &N, 8216c16827SSam Clegg Bytes.data() + Bytes.size(), &Error) 83*2faf0794SThomas Lively : static_cast<int64_t>(decodeULEB128(Bytes.data() + Size, &N, 84*2faf0794SThomas Lively Bytes.data() + Bytes.size(), 85*2faf0794SThomas Lively &Error)); 8616c16827SSam Clegg if (Error) 8716c16827SSam Clegg return false; 8816c16827SSam Clegg Size += N; 89*2faf0794SThomas Lively return true; 90*2faf0794SThomas Lively } 91*2faf0794SThomas Lively 92*2faf0794SThomas Lively static bool parseLEBImmediate(MCInst &MI, uint64_t &Size, 93*2faf0794SThomas Lively ArrayRef<uint8_t> Bytes, bool Signed) { 94*2faf0794SThomas Lively int64_t Val; 95*2faf0794SThomas Lively if (!nextLEB(Val, Bytes, Size, Signed)) 96*2faf0794SThomas Lively return false; 9716c16827SSam Clegg MI.addOperand(MCOperand::createImm(Val)); 9816c16827SSam Clegg return true; 9916c16827SSam Clegg } 10016c16827SSam Clegg 10116c16827SSam Clegg template <typename T> 10222442924SThomas Lively bool parseImmediate(MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes) { 10316c16827SSam Clegg if (Size + sizeof(T) > Bytes.size()) 10416c16827SSam Clegg return false; 10516c16827SSam Clegg T Val; 10616c16827SSam Clegg memcpy(&Val, Bytes.data() + Size, sizeof(T)); 10716c16827SSam Clegg support::endian::byte_swap<T, support::endianness::little>(Val); 10816c16827SSam Clegg Size += sizeof(T); 10922442924SThomas Lively if (std::is_floating_point<T>::value) { 11016c16827SSam Clegg MI.addOperand(MCOperand::createFPImm(static_cast<double>(Val))); 11122442924SThomas Lively } else { 11222442924SThomas Lively MI.addOperand(MCOperand::createImm(static_cast<int64_t>(Val))); 11322442924SThomas Lively } 11416c16827SSam Clegg return true; 11516c16827SSam Clegg } 11616c16827SSam Clegg 1171a427287SDan Gohman MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction( 1181a427287SDan Gohman MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes, uint64_t /*Address*/, 11916c16827SSam Clegg raw_ostream & /*OS*/, raw_ostream &CS) const { 12016c16827SSam Clegg CommentStream = &CS; 12116c16827SSam Clegg Size = 0; 12216c16827SSam Clegg auto Opc = nextByte(Bytes, Size); 12316c16827SSam Clegg if (Opc < 0) 1241a427287SDan Gohman return MCDisassembler::Fail; 12516c16827SSam Clegg const auto *WasmInst = &InstructionTable0[Opc]; 12616c16827SSam Clegg // If this is a prefix byte, indirect to another table. 12716c16827SSam Clegg if (WasmInst->ET == ET_Prefix) { 12816c16827SSam Clegg WasmInst = nullptr; 12916c16827SSam Clegg // Linear search, so far only 2 entries. 13016c16827SSam Clegg for (auto PT = PrefixTable; PT->Table; PT++) { 13116c16827SSam Clegg if (PT->Prefix == Opc) { 13216c16827SSam Clegg WasmInst = PT->Table; 13316c16827SSam Clegg break; 13416c16827SSam Clegg } 13516c16827SSam Clegg } 13616c16827SSam Clegg if (!WasmInst) 13716c16827SSam Clegg return MCDisassembler::Fail; 138*2faf0794SThomas Lively int64_t PrefixedOpc; 139*2faf0794SThomas Lively if (!nextLEB(PrefixedOpc, Bytes, Size)) 14016c16827SSam Clegg return MCDisassembler::Fail; 141*2faf0794SThomas Lively if (PrefixedOpc < 0 || PrefixedOpc >= WebAssemblyInstructionTableSize) 142*2faf0794SThomas Lively return MCDisassembler::Fail; 143*2faf0794SThomas Lively WasmInst += PrefixedOpc; 14416c16827SSam Clegg } 14516c16827SSam Clegg if (WasmInst->ET == ET_Unused) 14616c16827SSam Clegg return MCDisassembler::Fail; 14716c16827SSam Clegg // At this point we must have a valid instruction to decode. 14816c16827SSam Clegg assert(WasmInst->ET == ET_Instruction); 14916c16827SSam Clegg MI.setOpcode(WasmInst->Opcode); 15016c16827SSam Clegg // Parse any operands. 15116c16827SSam Clegg for (uint8_t OPI = 0; OPI < WasmInst->NumOperands; OPI++) { 152a733d08dSWouter van Oortmerssen switch (OperandTable[WasmInst->OperandStart + OPI]) { 15316c16827SSam Clegg // ULEB operands: 15416c16827SSam Clegg case WebAssembly::OPERAND_BASIC_BLOCK: 15516c16827SSam Clegg case WebAssembly::OPERAND_LOCAL: 15616c16827SSam Clegg case WebAssembly::OPERAND_GLOBAL: 15716c16827SSam Clegg case WebAssembly::OPERAND_FUNCTION32: 15816c16827SSam Clegg case WebAssembly::OPERAND_OFFSET32: 15916c16827SSam Clegg case WebAssembly::OPERAND_P2ALIGN: 16016c16827SSam Clegg case WebAssembly::OPERAND_TYPEINDEX: 16116c16827SSam Clegg case MCOI::OPERAND_IMMEDIATE: { 16216c16827SSam Clegg if (!parseLEBImmediate(MI, Size, Bytes, false)) 16316c16827SSam Clegg return MCDisassembler::Fail; 16416c16827SSam Clegg break; 16516c16827SSam Clegg } 16616c16827SSam Clegg // SLEB operands: 16716c16827SSam Clegg case WebAssembly::OPERAND_I32IMM: 16816c16827SSam Clegg case WebAssembly::OPERAND_I64IMM: 16916c16827SSam Clegg case WebAssembly::OPERAND_SIGNATURE: { 17016c16827SSam Clegg if (!parseLEBImmediate(MI, Size, Bytes, true)) 17116c16827SSam Clegg return MCDisassembler::Fail; 17216c16827SSam Clegg break; 17316c16827SSam Clegg } 17416c16827SSam Clegg // FP operands. 17516c16827SSam Clegg case WebAssembly::OPERAND_F32IMM: { 17622442924SThomas Lively if (!parseImmediate<float>(MI, Size, Bytes)) 17716c16827SSam Clegg return MCDisassembler::Fail; 17816c16827SSam Clegg break; 17916c16827SSam Clegg } 18016c16827SSam Clegg case WebAssembly::OPERAND_F64IMM: { 18122442924SThomas Lively if (!parseImmediate<double>(MI, Size, Bytes)) 18222442924SThomas Lively return MCDisassembler::Fail; 18322442924SThomas Lively break; 18422442924SThomas Lively } 18522442924SThomas Lively // Vector lane operands (not LEB encoded). 18622442924SThomas Lively case WebAssembly::OPERAND_VEC_I8IMM: { 18722442924SThomas Lively if (!parseImmediate<uint8_t>(MI, Size, Bytes)) 18822442924SThomas Lively return MCDisassembler::Fail; 18922442924SThomas Lively break; 19022442924SThomas Lively } 19122442924SThomas Lively case WebAssembly::OPERAND_VEC_I16IMM: { 19222442924SThomas Lively if (!parseImmediate<uint16_t>(MI, Size, Bytes)) 19322442924SThomas Lively return MCDisassembler::Fail; 19422442924SThomas Lively break; 19522442924SThomas Lively } 19622442924SThomas Lively case WebAssembly::OPERAND_VEC_I32IMM: { 19722442924SThomas Lively if (!parseImmediate<uint32_t>(MI, Size, Bytes)) 19822442924SThomas Lively return MCDisassembler::Fail; 19922442924SThomas Lively break; 20022442924SThomas Lively } 20122442924SThomas Lively case WebAssembly::OPERAND_VEC_I64IMM: { 20222442924SThomas Lively if (!parseImmediate<uint64_t>(MI, Size, Bytes)) 20316c16827SSam Clegg return MCDisassembler::Fail; 20416c16827SSam Clegg break; 20516c16827SSam Clegg } 206a733d08dSWouter van Oortmerssen case MCOI::OPERAND_REGISTER: 207a733d08dSWouter van Oortmerssen // The tablegen header currently does not have any register operands since 208a733d08dSWouter van Oortmerssen // we use only the stack (_S) instructions. 209a733d08dSWouter van Oortmerssen // If you hit this that probably means a bad instruction definition in 210a733d08dSWouter van Oortmerssen // tablegen. 211a733d08dSWouter van Oortmerssen llvm_unreachable("Register operand in WebAssemblyDisassembler"); 21216c16827SSam Clegg default: 21316c16827SSam Clegg llvm_unreachable("Unknown operand type in WebAssemblyDisassembler"); 21416c16827SSam Clegg } 21516c16827SSam Clegg } 21616c16827SSam Clegg return MCDisassembler::Success; 2171a427287SDan Gohman } 218