blob: 54403a562741ce22d2cf2861bbfc34600ef40a10 [file] [log] [blame]
Dan Gohman1a427282016-01-12 03:32:29 +00001//==- WebAssemblyDisassembler.cpp - Disassembler for WebAssembly -*- C++ -*-==//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file
Adrian Prantl5f8f34e42018-05-01 15:54:18 +000011/// This file is part of the WebAssembly Disassembler.
Dan Gohman1a427282016-01-12 03:32:29 +000012///
13/// It contains code to translate the data produced by the decoder into
14/// MCInsts.
15///
16//===----------------------------------------------------------------------===//
17
Dan Gohman1a427282016-01-12 03:32:29 +000018#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
19#include "llvm/MC/MCContext.h"
Benjamin Kramerc50b8902016-01-26 18:21:38 +000020#include "llvm/MC/MCDisassembler/MCDisassembler.h"
Sam Clegg16c16822018-05-10 22:16:44 +000021#include "llvm/MC/MCFixedLenDisassembler.h"
Dan Gohman1a427282016-01-12 03:32:29 +000022#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"
Sam Clegg16c16822018-05-10 22:16:44 +000027#include "llvm/Support/LEB128.h"
Dan Gohman1a427282016-01-12 03:32:29 +000028#include "llvm/Support/TargetRegistry.h"
Sam Clegg16c16822018-05-10 22:16:44 +000029
Dan Gohman1a427282016-01-12 03:32:29 +000030using namespace llvm;
31
32#define DEBUG_TYPE "wasm-disassembler"
33
Sam Clegg16c16822018-05-10 22:16:44 +000034using DecodeStatus = MCDisassembler::DecodeStatus;
35
36#include "WebAssemblyGenDisassemblerTables.inc"
37
Dan Gohman1a427282016-01-12 03:32:29 +000038namespace {
39class WebAssemblyDisassembler final : public MCDisassembler {
40 std::unique_ptr<const MCInstrInfo> MCII;
41
42 DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
43 ArrayRef<uint8_t> Bytes, uint64_t Address,
44 raw_ostream &VStream,
45 raw_ostream &CStream) const override;
46
47public:
48 WebAssemblyDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx,
49 std::unique_ptr<const MCInstrInfo> MCII)
50 : MCDisassembler(STI, Ctx), MCII(std::move(MCII)) {}
51};
52} // end anonymous namespace
53
54static MCDisassembler *createWebAssemblyDisassembler(const Target &T,
55 const MCSubtargetInfo &STI,
56 MCContext &Ctx) {
57 std::unique_ptr<const MCInstrInfo> MCII(T.createMCInstrInfo());
58 return new WebAssemblyDisassembler(STI, Ctx, std::move(MCII));
59}
60
61extern "C" void LLVMInitializeWebAssemblyDisassembler() {
62 // Register the disassembler for each target.
Mehdi Aminif42454b2016-10-09 23:00:34 +000063 TargetRegistry::RegisterMCDisassembler(getTheWebAssemblyTarget32(),
Dan Gohman1a427282016-01-12 03:32:29 +000064 createWebAssemblyDisassembler);
Mehdi Aminif42454b2016-10-09 23:00:34 +000065 TargetRegistry::RegisterMCDisassembler(getTheWebAssemblyTarget64(),
Dan Gohman1a427282016-01-12 03:32:29 +000066 createWebAssemblyDisassembler);
67}
68
Sam Clegg16c16822018-05-10 22:16:44 +000069static int nextByte(ArrayRef<uint8_t> Bytes, uint64_t &Size) {
70 if (Size >= Bytes.size())
71 return -1;
72 auto V = Bytes[Size];
73 Size++;
74 return V;
75}
76
77static bool parseLEBImmediate(MCInst &MI, uint64_t &Size,
78 ArrayRef<uint8_t> Bytes, bool Signed) {
79 unsigned N = 0;
80 const char *Error = nullptr;
81 auto Val = Signed ? decodeSLEB128(Bytes.data() + Size, &N,
82 Bytes.data() + Bytes.size(), &Error)
83 : static_cast<int64_t>(
84 decodeULEB128(Bytes.data() + Size, &N,
85 Bytes.data() + Bytes.size(), &Error));
86 if (Error)
87 return false;
88 Size += N;
89 MI.addOperand(MCOperand::createImm(Val));
90 return true;
91}
92
93template <typename T>
Thomas Lively22442922018-08-21 21:03:18 +000094bool parseImmediate(MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes) {
Sam Clegg16c16822018-05-10 22:16:44 +000095 if (Size + sizeof(T) > Bytes.size())
96 return false;
97 T Val;
98 memcpy(&Val, Bytes.data() + Size, sizeof(T));
99 support::endian::byte_swap<T, support::endianness::little>(Val);
100 Size += sizeof(T);
Thomas Lively22442922018-08-21 21:03:18 +0000101 if (std::is_floating_point<T>::value) {
102 MI.addOperand(MCOperand::createFPImm(static_cast<double>(Val)));
103 } else {
104 MI.addOperand(MCOperand::createImm(static_cast<int64_t>(Val)));
105 }
Sam Clegg16c16822018-05-10 22:16:44 +0000106 return true;
107}
108
Dan Gohman1a427282016-01-12 03:32:29 +0000109MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
110 MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes, uint64_t /*Address*/,
Sam Clegg16c16822018-05-10 22:16:44 +0000111 raw_ostream & /*OS*/, raw_ostream &CS) const {
112 CommentStream = &CS;
113 Size = 0;
114 auto Opc = nextByte(Bytes, Size);
115 if (Opc < 0)
116 return MCDisassembler::Fail;
117 const auto *WasmInst = &InstructionTable0[Opc];
118 // If this is a prefix byte, indirect to another table.
119 if (WasmInst->ET == ET_Prefix) {
120 WasmInst = nullptr;
121 // Linear search, so far only 2 entries.
122 for (auto PT = PrefixTable; PT->Table; PT++) {
123 if (PT->Prefix == Opc) {
124 WasmInst = PT->Table;
125 break;
126 }
127 }
128 if (!WasmInst)
129 return MCDisassembler::Fail;
130 Opc = nextByte(Bytes, Size);
131 if (Opc < 0)
132 return MCDisassembler::Fail;
133 WasmInst += Opc;
134 }
135 if (WasmInst->ET == ET_Unused)
136 return MCDisassembler::Fail;
137 // At this point we must have a valid instruction to decode.
138 assert(WasmInst->ET == ET_Instruction);
139 MI.setOpcode(WasmInst->Opcode);
140 // Parse any operands.
141 for (uint8_t OPI = 0; OPI < WasmInst->NumOperands; OPI++) {
Wouter van Oortmerssena733d082018-08-30 15:40:53 +0000142 switch (OperandTable[WasmInst->OperandStart + OPI]) {
Sam Clegg16c16822018-05-10 22:16:44 +0000143 // ULEB operands:
144 case WebAssembly::OPERAND_BASIC_BLOCK:
145 case WebAssembly::OPERAND_LOCAL:
146 case WebAssembly::OPERAND_GLOBAL:
147 case WebAssembly::OPERAND_FUNCTION32:
148 case WebAssembly::OPERAND_OFFSET32:
149 case WebAssembly::OPERAND_P2ALIGN:
150 case WebAssembly::OPERAND_TYPEINDEX:
151 case MCOI::OPERAND_IMMEDIATE: {
152 if (!parseLEBImmediate(MI, Size, Bytes, false))
153 return MCDisassembler::Fail;
154 break;
155 }
156 // SLEB operands:
157 case WebAssembly::OPERAND_I32IMM:
158 case WebAssembly::OPERAND_I64IMM:
159 case WebAssembly::OPERAND_SIGNATURE: {
160 if (!parseLEBImmediate(MI, Size, Bytes, true))
161 return MCDisassembler::Fail;
162 break;
163 }
164 // FP operands.
165 case WebAssembly::OPERAND_F32IMM: {
Thomas Lively22442922018-08-21 21:03:18 +0000166 if (!parseImmediate<float>(MI, Size, Bytes))
Sam Clegg16c16822018-05-10 22:16:44 +0000167 return MCDisassembler::Fail;
168 break;
169 }
170 case WebAssembly::OPERAND_F64IMM: {
Thomas Lively22442922018-08-21 21:03:18 +0000171 if (!parseImmediate<double>(MI, Size, Bytes))
172 return MCDisassembler::Fail;
173 break;
174 }
175 // Vector lane operands (not LEB encoded).
176 case WebAssembly::OPERAND_VEC_I8IMM: {
177 if (!parseImmediate<uint8_t>(MI, Size, Bytes))
178 return MCDisassembler::Fail;
179 break;
180 }
181 case WebAssembly::OPERAND_VEC_I16IMM: {
182 if (!parseImmediate<uint16_t>(MI, Size, Bytes))
183 return MCDisassembler::Fail;
184 break;
185 }
186 case WebAssembly::OPERAND_VEC_I32IMM: {
187 if (!parseImmediate<uint32_t>(MI, Size, Bytes))
188 return MCDisassembler::Fail;
189 break;
190 }
191 case WebAssembly::OPERAND_VEC_I64IMM: {
192 if (!parseImmediate<uint64_t>(MI, Size, Bytes))
Sam Clegg16c16822018-05-10 22:16:44 +0000193 return MCDisassembler::Fail;
194 break;
195 }
Wouter van Oortmerssena733d082018-08-30 15:40:53 +0000196 case MCOI::OPERAND_REGISTER:
197 // The tablegen header currently does not have any register operands since
198 // we use only the stack (_S) instructions.
199 // If you hit this that probably means a bad instruction definition in
200 // tablegen.
201 llvm_unreachable("Register operand in WebAssemblyDisassembler");
Sam Clegg16c16822018-05-10 22:16:44 +0000202 default:
203 llvm_unreachable("Unknown operand type in WebAssemblyDisassembler");
204 }
205 }
206 return MCDisassembler::Success;
Dan Gohman1a427282016-01-12 03:32:29 +0000207}