blob: 4ab290399ba720ae12c28412d1b5a8a0d69768b6 [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
Thomas Lively2faf0792018-11-09 01:57:00 +000069static uint8_t nextByte(ArrayRef<uint8_t> Bytes, uint64_t &Size) {
Sam Clegg16c16822018-05-10 22:16:44 +000070 if (Size >= Bytes.size())
71 return -1;
72 auto V = Bytes[Size];
73 Size++;
74 return V;
75}
76
Thomas Lively2faf0792018-11-09 01:57:00 +000077static bool nextLEB(int64_t &Val, ArrayRef<uint8_t> Bytes, uint64_t &Size,
78 bool Signed = false) {
Sam Clegg16c16822018-05-10 22:16:44 +000079 unsigned N = 0;
80 const char *Error = nullptr;
Thomas Lively2faf0792018-11-09 01:57:00 +000081 Val = Signed ? decodeSLEB128(Bytes.data() + Size, &N,
82 Bytes.data() + Bytes.size(), &Error)
83 : static_cast<int64_t>(decodeULEB128(Bytes.data() + Size, &N,
84 Bytes.data() + Bytes.size(),
85 &Error));
Sam Clegg16c16822018-05-10 22:16:44 +000086 if (Error)
87 return false;
88 Size += N;
Thomas Lively2faf0792018-11-09 01:57:00 +000089 return true;
90}
91
92static bool parseLEBImmediate(MCInst &MI, uint64_t &Size,
93 ArrayRef<uint8_t> Bytes, bool Signed) {
94 int64_t Val;
95 if (!nextLEB(Val, Bytes, Size, Signed))
96 return false;
Sam Clegg16c16822018-05-10 22:16:44 +000097 MI.addOperand(MCOperand::createImm(Val));
98 return true;
99}
100
101template <typename T>
Thomas Lively22442922018-08-21 21:03:18 +0000102bool parseImmediate(MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes) {
Sam Clegg16c16822018-05-10 22:16:44 +0000103 if (Size + sizeof(T) > Bytes.size())
104 return false;
105 T Val;
106 memcpy(&Val, Bytes.data() + Size, sizeof(T));
107 support::endian::byte_swap<T, support::endianness::little>(Val);
108 Size += sizeof(T);
Thomas Lively22442922018-08-21 21:03:18 +0000109 if (std::is_floating_point<T>::value) {
110 MI.addOperand(MCOperand::createFPImm(static_cast<double>(Val)));
111 } else {
112 MI.addOperand(MCOperand::createImm(static_cast<int64_t>(Val)));
113 }
Sam Clegg16c16822018-05-10 22:16:44 +0000114 return true;
115}
116
Dan Gohman1a427282016-01-12 03:32:29 +0000117MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
118 MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes, uint64_t /*Address*/,
Sam Clegg16c16822018-05-10 22:16:44 +0000119 raw_ostream & /*OS*/, raw_ostream &CS) const {
120 CommentStream = &CS;
121 Size = 0;
122 auto Opc = nextByte(Bytes, Size);
123 if (Opc < 0)
124 return MCDisassembler::Fail;
125 const auto *WasmInst = &InstructionTable0[Opc];
126 // If this is a prefix byte, indirect to another table.
127 if (WasmInst->ET == ET_Prefix) {
128 WasmInst = nullptr;
129 // Linear search, so far only 2 entries.
130 for (auto PT = PrefixTable; PT->Table; PT++) {
131 if (PT->Prefix == Opc) {
132 WasmInst = PT->Table;
133 break;
134 }
135 }
136 if (!WasmInst)
137 return MCDisassembler::Fail;
Thomas Lively2faf0792018-11-09 01:57:00 +0000138 int64_t PrefixedOpc;
139 if (!nextLEB(PrefixedOpc, Bytes, Size))
Sam Clegg16c16822018-05-10 22:16:44 +0000140 return MCDisassembler::Fail;
Thomas Lively2faf0792018-11-09 01:57:00 +0000141 if (PrefixedOpc < 0 || PrefixedOpc >= WebAssemblyInstructionTableSize)
142 return MCDisassembler::Fail;
143 WasmInst += PrefixedOpc;
Sam Clegg16c16822018-05-10 22:16:44 +0000144 }
145 if (WasmInst->ET == ET_Unused)
146 return MCDisassembler::Fail;
147 // At this point we must have a valid instruction to decode.
148 assert(WasmInst->ET == ET_Instruction);
149 MI.setOpcode(WasmInst->Opcode);
150 // Parse any operands.
151 for (uint8_t OPI = 0; OPI < WasmInst->NumOperands; OPI++) {
Wouter van Oortmerssena733d082018-08-30 15:40:53 +0000152 switch (OperandTable[WasmInst->OperandStart + OPI]) {
Sam Clegg16c16822018-05-10 22:16:44 +0000153 // ULEB operands:
154 case WebAssembly::OPERAND_BASIC_BLOCK:
155 case WebAssembly::OPERAND_LOCAL:
156 case WebAssembly::OPERAND_GLOBAL:
157 case WebAssembly::OPERAND_FUNCTION32:
158 case WebAssembly::OPERAND_OFFSET32:
159 case WebAssembly::OPERAND_P2ALIGN:
160 case WebAssembly::OPERAND_TYPEINDEX:
161 case MCOI::OPERAND_IMMEDIATE: {
162 if (!parseLEBImmediate(MI, Size, Bytes, false))
163 return MCDisassembler::Fail;
164 break;
165 }
166 // SLEB operands:
167 case WebAssembly::OPERAND_I32IMM:
168 case WebAssembly::OPERAND_I64IMM:
169 case WebAssembly::OPERAND_SIGNATURE: {
170 if (!parseLEBImmediate(MI, Size, Bytes, true))
171 return MCDisassembler::Fail;
172 break;
173 }
174 // FP operands.
175 case WebAssembly::OPERAND_F32IMM: {
Thomas Lively22442922018-08-21 21:03:18 +0000176 if (!parseImmediate<float>(MI, Size, Bytes))
Sam Clegg16c16822018-05-10 22:16:44 +0000177 return MCDisassembler::Fail;
178 break;
179 }
180 case WebAssembly::OPERAND_F64IMM: {
Thomas Lively22442922018-08-21 21:03:18 +0000181 if (!parseImmediate<double>(MI, Size, Bytes))
182 return MCDisassembler::Fail;
183 break;
184 }
185 // Vector lane operands (not LEB encoded).
186 case WebAssembly::OPERAND_VEC_I8IMM: {
187 if (!parseImmediate<uint8_t>(MI, Size, Bytes))
188 return MCDisassembler::Fail;
189 break;
190 }
191 case WebAssembly::OPERAND_VEC_I16IMM: {
192 if (!parseImmediate<uint16_t>(MI, Size, Bytes))
193 return MCDisassembler::Fail;
194 break;
195 }
196 case WebAssembly::OPERAND_VEC_I32IMM: {
197 if (!parseImmediate<uint32_t>(MI, Size, Bytes))
198 return MCDisassembler::Fail;
199 break;
200 }
201 case WebAssembly::OPERAND_VEC_I64IMM: {
202 if (!parseImmediate<uint64_t>(MI, Size, Bytes))
Sam Clegg16c16822018-05-10 22:16:44 +0000203 return MCDisassembler::Fail;
204 break;
205 }
Wouter van Oortmerssena733d082018-08-30 15:40:53 +0000206 case MCOI::OPERAND_REGISTER:
207 // The tablegen header currently does not have any register operands since
208 // we use only the stack (_S) instructions.
209 // If you hit this that probably means a bad instruction definition in
210 // tablegen.
211 llvm_unreachable("Register operand in WebAssemblyDisassembler");
Sam Clegg16c16822018-05-10 22:16:44 +0000212 default:
213 llvm_unreachable("Unknown operand type in WebAssemblyDisassembler");
214 }
215 }
216 return MCDisassembler::Success;
Dan Gohman1a427282016-01-12 03:32:29 +0000217}