1 //==- WebAssemblyDisassembler.cpp - Disassembler for WebAssembly -*- C++ -*-==//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 /// This file is part of the WebAssembly Disassembler.
13 /// It contains code to translate the data produced by the decoder into
16 //===----------------------------------------------------------------------===//
18 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
19 #include "llvm/MC/MCContext.h"
20 #include "llvm/MC/MCDisassembler/MCDisassembler.h"
21 #include "llvm/MC/MCFixedLenDisassembler.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/Support/Endian.h"
27 #include "llvm/Support/LEB128.h"
28 #include "llvm/Support/TargetRegistry.h"
32 #define DEBUG_TYPE "wasm-disassembler"
34 using DecodeStatus = MCDisassembler::DecodeStatus;
36 #include "WebAssemblyGenDisassemblerTables.inc"
39 static constexpr int WebAssemblyInstructionTableSize = 256;
41 class WebAssemblyDisassembler final : public MCDisassembler {
42 std::unique_ptr<const MCInstrInfo> MCII;
44 DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
45 ArrayRef<uint8_t> Bytes, uint64_t Address,
47 raw_ostream &CStream) const override;
50 WebAssemblyDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx,
51 std::unique_ptr<const MCInstrInfo> MCII)
52 : MCDisassembler(STI, Ctx), MCII(std::move(MCII)) {}
54 } // end anonymous namespace
56 static MCDisassembler *createWebAssemblyDisassembler(const Target &T,
57 const MCSubtargetInfo &STI,
59 std::unique_ptr<const MCInstrInfo> MCII(T.createMCInstrInfo());
60 return new WebAssemblyDisassembler(STI, Ctx, std::move(MCII));
63 extern "C" void LLVMInitializeWebAssemblyDisassembler() {
64 // Register the disassembler for each target.
65 TargetRegistry::RegisterMCDisassembler(getTheWebAssemblyTarget32(),
66 createWebAssemblyDisassembler);
67 TargetRegistry::RegisterMCDisassembler(getTheWebAssemblyTarget64(),
68 createWebAssemblyDisassembler);
71 static int nextByte(ArrayRef<uint8_t> Bytes, uint64_t &Size) {
72 if (Size >= Bytes.size())
79 static bool nextLEB(int64_t &Val, ArrayRef<uint8_t> Bytes, uint64_t &Size,
80 bool Signed = false) {
82 const char *Error = nullptr;
83 Val = Signed ? decodeSLEB128(Bytes.data() + Size, &N,
84 Bytes.data() + Bytes.size(), &Error)
85 : static_cast<int64_t>(decodeULEB128(Bytes.data() + Size, &N,
86 Bytes.data() + Bytes.size(),
94 static bool parseLEBImmediate(MCInst &MI, uint64_t &Size,
95 ArrayRef<uint8_t> Bytes, bool Signed) {
97 if (!nextLEB(Val, Bytes, Size, Signed))
99 MI.addOperand(MCOperand::createImm(Val));
103 template <typename T>
104 bool parseImmediate(MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes) {
105 if (Size + sizeof(T) > Bytes.size())
108 memcpy(&Val, Bytes.data() + Size, sizeof(T));
109 support::endian::byte_swap<T, support::endianness::little>(Val);
111 if (std::is_floating_point<T>::value) {
112 MI.addOperand(MCOperand::createFPImm(static_cast<double>(Val)));
114 MI.addOperand(MCOperand::createImm(static_cast<int64_t>(Val)));
119 MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
120 MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes, uint64_t /*Address*/,
121 raw_ostream & /*OS*/, raw_ostream &CS) const {
124 int Opc = nextByte(Bytes, Size);
126 return MCDisassembler::Fail;
127 const auto *WasmInst = &InstructionTable0[Opc];
128 // If this is a prefix byte, indirect to another table.
129 if (WasmInst->ET == ET_Prefix) {
131 // Linear search, so far only 2 entries.
132 for (auto PT = PrefixTable; PT->Table; PT++) {
133 if (PT->Prefix == Opc) {
134 WasmInst = PT->Table;
139 return MCDisassembler::Fail;
141 if (!nextLEB(PrefixedOpc, Bytes, Size))
142 return MCDisassembler::Fail;
143 if (PrefixedOpc < 0 || PrefixedOpc >= WebAssemblyInstructionTableSize)
144 return MCDisassembler::Fail;
145 WasmInst += PrefixedOpc;
147 if (WasmInst->ET == ET_Unused)
148 return MCDisassembler::Fail;
149 // At this point we must have a valid instruction to decode.
150 assert(WasmInst->ET == ET_Instruction);
151 MI.setOpcode(WasmInst->Opcode);
152 // Parse any operands.
153 for (uint8_t OPI = 0; OPI < WasmInst->NumOperands; OPI++) {
154 auto OT = OperandTable[WasmInst->OperandStart + OPI];
157 case WebAssembly::OPERAND_BASIC_BLOCK:
158 case WebAssembly::OPERAND_LOCAL:
159 case WebAssembly::OPERAND_GLOBAL:
160 case WebAssembly::OPERAND_FUNCTION32:
161 case WebAssembly::OPERAND_OFFSET32:
162 case WebAssembly::OPERAND_P2ALIGN:
163 case WebAssembly::OPERAND_TYPEINDEX:
164 case MCOI::OPERAND_IMMEDIATE: {
165 if (!parseLEBImmediate(MI, Size, Bytes, false))
166 return MCDisassembler::Fail;
170 case WebAssembly::OPERAND_I32IMM:
171 case WebAssembly::OPERAND_I64IMM: {
172 if (!parseLEBImmediate(MI, Size, Bytes, true))
173 return MCDisassembler::Fail;
176 // block_type operands (uint8_t).
177 case WebAssembly::OPERAND_SIGNATURE: {
178 if (!parseImmediate<uint8_t>(MI, Size, Bytes))
179 return MCDisassembler::Fail;
183 case WebAssembly::OPERAND_F32IMM: {
184 if (!parseImmediate<float>(MI, Size, Bytes))
185 return MCDisassembler::Fail;
188 case WebAssembly::OPERAND_F64IMM: {
189 if (!parseImmediate<double>(MI, Size, Bytes))
190 return MCDisassembler::Fail;
193 // Vector lane operands (not LEB encoded).
194 case WebAssembly::OPERAND_VEC_I8IMM: {
195 if (!parseImmediate<uint8_t>(MI, Size, Bytes))
196 return MCDisassembler::Fail;
199 case WebAssembly::OPERAND_VEC_I16IMM: {
200 if (!parseImmediate<uint16_t>(MI, Size, Bytes))
201 return MCDisassembler::Fail;
204 case WebAssembly::OPERAND_VEC_I32IMM: {
205 if (!parseImmediate<uint32_t>(MI, Size, Bytes))
206 return MCDisassembler::Fail;
209 case WebAssembly::OPERAND_VEC_I64IMM: {
210 if (!parseImmediate<uint64_t>(MI, Size, Bytes))
211 return MCDisassembler::Fail;
214 case WebAssembly::OPERAND_BRLIST: {
215 int64_t TargetTableLen;
216 if (!nextLEB(TargetTableLen, Bytes, Size, false))
217 return MCDisassembler::Fail;
218 for (int64_t I = 0; I < TargetTableLen; I++) {
219 if (!parseLEBImmediate(MI, Size, Bytes, false))
220 return MCDisassembler::Fail;
223 if (!parseLEBImmediate(MI, Size, Bytes, false))
224 return MCDisassembler::Fail;
227 case MCOI::OPERAND_REGISTER:
228 // The tablegen header currently does not have any register operands since
229 // we use only the stack (_S) instructions.
230 // If you hit this that probably means a bad instruction definition in
232 llvm_unreachable("Register operand in WebAssemblyDisassembler");
234 llvm_unreachable("Unknown operand type in WebAssemblyDisassembler");
237 return MCDisassembler::Success;