1444ed5c5SDimitry Andric //==- WebAssemblyDisassembler.cpp - Disassembler for WebAssembly -*- C++ -*-==// 2444ed5c5SDimitry Andric // 3444ed5c5SDimitry Andric // The LLVM Compiler Infrastructure 4444ed5c5SDimitry Andric // 5444ed5c5SDimitry Andric // This file is distributed under the University of Illinois Open Source 6444ed5c5SDimitry Andric // License. See LICENSE.TXT for details. 7444ed5c5SDimitry Andric // 8444ed5c5SDimitry Andric //===----------------------------------------------------------------------===// 9444ed5c5SDimitry Andric /// 10444ed5c5SDimitry Andric /// \file 11444ed5c5SDimitry Andric /// \brief This file is part of the WebAssembly Disassembler. 12444ed5c5SDimitry Andric /// 13444ed5c5SDimitry Andric /// It contains code to translate the data produced by the decoder into 14444ed5c5SDimitry Andric /// MCInsts. 15444ed5c5SDimitry Andric /// 16444ed5c5SDimitry Andric //===----------------------------------------------------------------------===// 17444ed5c5SDimitry Andric 18444ed5c5SDimitry Andric #include "WebAssembly.h" 19444ed5c5SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 20444ed5c5SDimitry Andric #include "llvm/MC/MCContext.h" 213ca95b02SDimitry Andric #include "llvm/MC/MCDisassembler/MCDisassembler.h" 22444ed5c5SDimitry Andric #include "llvm/MC/MCInst.h" 23444ed5c5SDimitry Andric #include "llvm/MC/MCInstrInfo.h" 24444ed5c5SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h" 25444ed5c5SDimitry Andric #include "llvm/MC/MCSymbol.h" 26444ed5c5SDimitry Andric #include "llvm/Support/Endian.h" 27444ed5c5SDimitry Andric #include "llvm/Support/TargetRegistry.h" 28444ed5c5SDimitry Andric using namespace llvm; 29444ed5c5SDimitry Andric 30444ed5c5SDimitry Andric #define DEBUG_TYPE "wasm-disassembler" 31444ed5c5SDimitry Andric 32444ed5c5SDimitry Andric namespace { 33444ed5c5SDimitry Andric class WebAssemblyDisassembler final : public MCDisassembler { 34444ed5c5SDimitry Andric std::unique_ptr<const MCInstrInfo> MCII; 35444ed5c5SDimitry Andric 36444ed5c5SDimitry Andric DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size, 37444ed5c5SDimitry Andric ArrayRef<uint8_t> Bytes, uint64_t Address, 38444ed5c5SDimitry Andric raw_ostream &VStream, 39444ed5c5SDimitry Andric raw_ostream &CStream) const override; 40444ed5c5SDimitry Andric 41444ed5c5SDimitry Andric public: 42444ed5c5SDimitry Andric WebAssemblyDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx, 43444ed5c5SDimitry Andric std::unique_ptr<const MCInstrInfo> MCII) 44444ed5c5SDimitry Andric : MCDisassembler(STI, Ctx), MCII(std::move(MCII)) {} 45444ed5c5SDimitry Andric }; 46444ed5c5SDimitry Andric } // end anonymous namespace 47444ed5c5SDimitry Andric 48444ed5c5SDimitry Andric static MCDisassembler *createWebAssemblyDisassembler(const Target &T, 49444ed5c5SDimitry Andric const MCSubtargetInfo &STI, 50444ed5c5SDimitry Andric MCContext &Ctx) { 51444ed5c5SDimitry Andric std::unique_ptr<const MCInstrInfo> MCII(T.createMCInstrInfo()); 52444ed5c5SDimitry Andric return new WebAssemblyDisassembler(STI, Ctx, std::move(MCII)); 53444ed5c5SDimitry Andric } 54444ed5c5SDimitry Andric 55444ed5c5SDimitry Andric extern "C" void LLVMInitializeWebAssemblyDisassembler() { 56444ed5c5SDimitry Andric // Register the disassembler for each target. 57444ed5c5SDimitry Andric TargetRegistry::RegisterMCDisassembler(TheWebAssemblyTarget32, 58444ed5c5SDimitry Andric createWebAssemblyDisassembler); 59444ed5c5SDimitry Andric TargetRegistry::RegisterMCDisassembler(TheWebAssemblyTarget64, 60444ed5c5SDimitry Andric createWebAssemblyDisassembler); 61444ed5c5SDimitry Andric } 62444ed5c5SDimitry Andric 63444ed5c5SDimitry Andric MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction( 64444ed5c5SDimitry Andric MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes, uint64_t /*Address*/, 65444ed5c5SDimitry Andric raw_ostream &OS, raw_ostream &CS) const { 66444ed5c5SDimitry Andric Size = 0; 67444ed5c5SDimitry Andric uint64_t Pos = 0; 68444ed5c5SDimitry Andric 69444ed5c5SDimitry Andric // Read the opcode. 70444ed5c5SDimitry Andric if (Pos + sizeof(uint64_t) > Bytes.size()) 71444ed5c5SDimitry Andric return MCDisassembler::Fail; 72444ed5c5SDimitry Andric uint64_t Opcode = support::endian::read64le(Bytes.data() + Pos); 73444ed5c5SDimitry Andric Pos += sizeof(uint64_t); 74444ed5c5SDimitry Andric 75444ed5c5SDimitry Andric if (Opcode >= WebAssembly::INSTRUCTION_LIST_END) 76444ed5c5SDimitry Andric return MCDisassembler::Fail; 77444ed5c5SDimitry Andric 78444ed5c5SDimitry Andric MI.setOpcode(Opcode); 79444ed5c5SDimitry Andric const MCInstrDesc &Desc = MCII->get(Opcode); 80444ed5c5SDimitry Andric unsigned NumFixedOperands = Desc.NumOperands; 81444ed5c5SDimitry Andric 82444ed5c5SDimitry Andric // If it's variadic, read the number of extra operands. 83444ed5c5SDimitry Andric unsigned NumExtraOperands = 0; 84444ed5c5SDimitry Andric if (Desc.isVariadic()) { 85444ed5c5SDimitry Andric if (Pos + sizeof(uint64_t) > Bytes.size()) 86444ed5c5SDimitry Andric return MCDisassembler::Fail; 87444ed5c5SDimitry Andric NumExtraOperands = support::endian::read64le(Bytes.data() + Pos); 88444ed5c5SDimitry Andric Pos += sizeof(uint64_t); 89444ed5c5SDimitry Andric } 90444ed5c5SDimitry Andric 91444ed5c5SDimitry Andric // Read the fixed operands. These are described by the MCInstrDesc. 92444ed5c5SDimitry Andric for (unsigned i = 0; i < NumFixedOperands; ++i) { 93444ed5c5SDimitry Andric const MCOperandInfo &Info = Desc.OpInfo[i]; 94444ed5c5SDimitry Andric switch (Info.OperandType) { 95444ed5c5SDimitry Andric case MCOI::OPERAND_IMMEDIATE: 963ca95b02SDimitry Andric case WebAssembly::OPERAND_P2ALIGN: 97444ed5c5SDimitry Andric case WebAssembly::OPERAND_BASIC_BLOCK: { 98444ed5c5SDimitry Andric if (Pos + sizeof(uint64_t) > Bytes.size()) 99444ed5c5SDimitry Andric return MCDisassembler::Fail; 100444ed5c5SDimitry Andric uint64_t Imm = support::endian::read64le(Bytes.data() + Pos); 101444ed5c5SDimitry Andric Pos += sizeof(uint64_t); 102444ed5c5SDimitry Andric MI.addOperand(MCOperand::createImm(Imm)); 103444ed5c5SDimitry Andric break; 104444ed5c5SDimitry Andric } 105444ed5c5SDimitry Andric case MCOI::OPERAND_REGISTER: { 106444ed5c5SDimitry Andric if (Pos + sizeof(uint64_t) > Bytes.size()) 107444ed5c5SDimitry Andric return MCDisassembler::Fail; 108444ed5c5SDimitry Andric uint64_t Reg = support::endian::read64le(Bytes.data() + Pos); 109444ed5c5SDimitry Andric Pos += sizeof(uint64_t); 110444ed5c5SDimitry Andric MI.addOperand(MCOperand::createReg(Reg)); 111444ed5c5SDimitry Andric break; 112444ed5c5SDimitry Andric } 1133ca95b02SDimitry Andric case WebAssembly::OPERAND_FP32IMM: 1143ca95b02SDimitry Andric case WebAssembly::OPERAND_FP64IMM: { 115444ed5c5SDimitry Andric // TODO: MC converts all floating point immediate operands to double. 116444ed5c5SDimitry Andric // This is fine for numeric values, but may cause NaNs to change bits. 117444ed5c5SDimitry Andric if (Pos + sizeof(uint64_t) > Bytes.size()) 118444ed5c5SDimitry Andric return MCDisassembler::Fail; 119444ed5c5SDimitry Andric uint64_t Bits = support::endian::read64le(Bytes.data() + Pos); 120444ed5c5SDimitry Andric Pos += sizeof(uint64_t); 121444ed5c5SDimitry Andric double Imm; 122444ed5c5SDimitry Andric memcpy(&Imm, &Bits, sizeof(Imm)); 123444ed5c5SDimitry Andric MI.addOperand(MCOperand::createFPImm(Imm)); 124444ed5c5SDimitry Andric break; 125444ed5c5SDimitry Andric } 126444ed5c5SDimitry Andric default: 127444ed5c5SDimitry Andric llvm_unreachable("unimplemented operand kind"); 128444ed5c5SDimitry Andric } 129444ed5c5SDimitry Andric } 130444ed5c5SDimitry Andric 131444ed5c5SDimitry Andric // Read the extra operands. 132444ed5c5SDimitry Andric assert(NumExtraOperands == 0 || Desc.isVariadic()); 133444ed5c5SDimitry Andric for (unsigned i = 0; i < NumExtraOperands; ++i) { 134444ed5c5SDimitry Andric if (Pos + sizeof(uint64_t) > Bytes.size()) 135444ed5c5SDimitry Andric return MCDisassembler::Fail; 136444ed5c5SDimitry Andric if (Desc.TSFlags & WebAssemblyII::VariableOpIsImmediate) { 137444ed5c5SDimitry Andric // Decode extra immediate operands. 138444ed5c5SDimitry Andric uint64_t Imm = support::endian::read64le(Bytes.data() + Pos); 139444ed5c5SDimitry Andric MI.addOperand(MCOperand::createImm(Imm)); 140444ed5c5SDimitry Andric } else { 141444ed5c5SDimitry Andric // Decode extra register operands. 142444ed5c5SDimitry Andric uint64_t Reg = support::endian::read64le(Bytes.data() + Pos); 143444ed5c5SDimitry Andric MI.addOperand(MCOperand::createReg(Reg)); 144444ed5c5SDimitry Andric } 145444ed5c5SDimitry Andric Pos += sizeof(uint64_t); 146444ed5c5SDimitry Andric } 147444ed5c5SDimitry Andric 148444ed5c5SDimitry Andric Size = Pos; 149444ed5c5SDimitry Andric return MCDisassembler::Success; 150444ed5c5SDimitry Andric } 151