blob: 369954b88c991c0a42b5acca9f22df48546b051c [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 {
Fangrui Song49550662018-11-09 18:32:20 +000039static constexpr int WebAssemblyInstructionTableSize = 256;
40
Dan Gohman1a427282016-01-12 03:32:29 +000041class WebAssemblyDisassembler final : public MCDisassembler {
42 std::unique_ptr<const MCInstrInfo> MCII;
43
44 DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
45 ArrayRef<uint8_t> Bytes, uint64_t Address,
46 raw_ostream &VStream,
47 raw_ostream &CStream) const override;
48
49public:
50 WebAssemblyDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx,
51 std::unique_ptr<const MCInstrInfo> MCII)
52 : MCDisassembler(STI, Ctx), MCII(std::move(MCII)) {}
53};
54} // end anonymous namespace
55
56static MCDisassembler *createWebAssemblyDisassembler(const Target &T,
57 const MCSubtargetInfo &STI,
58 MCContext &Ctx) {
59 std::unique_ptr<const MCInstrInfo> MCII(T.createMCInstrInfo());
60 return new WebAssemblyDisassembler(STI, Ctx, std::move(MCII));
61}
62
63extern "C" void LLVMInitializeWebAssemblyDisassembler() {
64 // Register the disassembler for each target.
Mehdi Aminif42454b2016-10-09 23:00:34 +000065 TargetRegistry::RegisterMCDisassembler(getTheWebAssemblyTarget32(),
Dan Gohman1a427282016-01-12 03:32:29 +000066 createWebAssemblyDisassembler);
Mehdi Aminif42454b2016-10-09 23:00:34 +000067 TargetRegistry::RegisterMCDisassembler(getTheWebAssemblyTarget64(),
Dan Gohman1a427282016-01-12 03:32:29 +000068 createWebAssemblyDisassembler);
69}
70
Thomas Livelyfc3163b2018-11-15 18:56:49 +000071static int nextByte(ArrayRef<uint8_t> Bytes, uint64_t &Size) {
Sam Clegg16c16822018-05-10 22:16:44 +000072 if (Size >= Bytes.size())
73 return -1;
74 auto V = Bytes[Size];
75 Size++;
76 return V;
77}
78
Thomas Lively2faf0792018-11-09 01:57:00 +000079static bool nextLEB(int64_t &Val, ArrayRef<uint8_t> Bytes, uint64_t &Size,
80 bool Signed = false) {
Sam Clegg16c16822018-05-10 22:16:44 +000081 unsigned N = 0;
82 const char *Error = nullptr;
Thomas Lively2faf0792018-11-09 01:57:00 +000083 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(),
87 &Error));
Sam Clegg16c16822018-05-10 22:16:44 +000088 if (Error)
89 return false;
90 Size += N;
Thomas Lively2faf0792018-11-09 01:57:00 +000091 return true;
92}
93
94static bool parseLEBImmediate(MCInst &MI, uint64_t &Size,
95 ArrayRef<uint8_t> Bytes, bool Signed) {
96 int64_t Val;
97 if (!nextLEB(Val, Bytes, Size, Signed))
98 return false;
Sam Clegg16c16822018-05-10 22:16:44 +000099 MI.addOperand(MCOperand::createImm(Val));
100 return true;
101}
102
103template <typename T>
Thomas Lively22442922018-08-21 21:03:18 +0000104bool parseImmediate(MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes) {
Sam Clegg16c16822018-05-10 22:16:44 +0000105 if (Size + sizeof(T) > Bytes.size())
106 return false;
107 T Val;
108 memcpy(&Val, Bytes.data() + Size, sizeof(T));
109 support::endian::byte_swap<T, support::endianness::little>(Val);
110 Size += sizeof(T);
Thomas Lively22442922018-08-21 21:03:18 +0000111 if (std::is_floating_point<T>::value) {
112 MI.addOperand(MCOperand::createFPImm(static_cast<double>(Val)));
113 } else {
114 MI.addOperand(MCOperand::createImm(static_cast<int64_t>(Val)));
115 }
Sam Clegg16c16822018-05-10 22:16:44 +0000116 return true;
117}
118
Dan Gohman1a427282016-01-12 03:32:29 +0000119MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
120 MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes, uint64_t /*Address*/,
Sam Clegg16c16822018-05-10 22:16:44 +0000121 raw_ostream & /*OS*/, raw_ostream &CS) const {
122 CommentStream = &CS;
123 Size = 0;
Thomas Livelyfc3163b2018-11-15 18:56:49 +0000124 int Opc = nextByte(Bytes, Size);
Sam Clegg16c16822018-05-10 22:16:44 +0000125 if (Opc < 0)
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) {
130 WasmInst = nullptr;
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;
135 break;
136 }
137 }
138 if (!WasmInst)
139 return MCDisassembler::Fail;
Thomas Lively2faf0792018-11-09 01:57:00 +0000140 int64_t PrefixedOpc;
141 if (!nextLEB(PrefixedOpc, Bytes, Size))
Sam Clegg16c16822018-05-10 22:16:44 +0000142 return MCDisassembler::Fail;
Thomas Lively2faf0792018-11-09 01:57:00 +0000143 if (PrefixedOpc < 0 || PrefixedOpc >= WebAssemblyInstructionTableSize)
144 return MCDisassembler::Fail;
145 WasmInst += PrefixedOpc;
Sam Clegg16c16822018-05-10 22:16:44 +0000146 }
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++) {
Wouter van Oortmerssena733d082018-08-30 15:40:53 +0000154 switch (OperandTable[WasmInst->OperandStart + OPI]) {
Sam Clegg16c16822018-05-10 22:16:44 +0000155 // ULEB operands:
156 case WebAssembly::OPERAND_BASIC_BLOCK:
157 case WebAssembly::OPERAND_LOCAL:
158 case WebAssembly::OPERAND_GLOBAL:
159 case WebAssembly::OPERAND_FUNCTION32:
160 case WebAssembly::OPERAND_OFFSET32:
161 case WebAssembly::OPERAND_P2ALIGN:
162 case WebAssembly::OPERAND_TYPEINDEX:
163 case MCOI::OPERAND_IMMEDIATE: {
164 if (!parseLEBImmediate(MI, Size, Bytes, false))
165 return MCDisassembler::Fail;
166 break;
167 }
168 // SLEB operands:
169 case WebAssembly::OPERAND_I32IMM:
Wouter van Oortmerssenad72f682019-01-02 23:23:51 +0000170 case WebAssembly::OPERAND_I64IMM: {
Sam Clegg16c16822018-05-10 22:16:44 +0000171 if (!parseLEBImmediate(MI, Size, Bytes, true))
172 return MCDisassembler::Fail;
173 break;
174 }
Wouter van Oortmerssenad72f682019-01-02 23:23:51 +0000175 // block_type operands (uint8_t).
176 case WebAssembly::OPERAND_SIGNATURE: {
177 if (!parseImmediate<uint8_t>(MI, Size, Bytes))
178 return MCDisassembler::Fail;
179 break;
180 }
Sam Clegg16c16822018-05-10 22:16:44 +0000181 // FP operands.
182 case WebAssembly::OPERAND_F32IMM: {
Thomas Lively22442922018-08-21 21:03:18 +0000183 if (!parseImmediate<float>(MI, Size, Bytes))
Sam Clegg16c16822018-05-10 22:16:44 +0000184 return MCDisassembler::Fail;
185 break;
186 }
187 case WebAssembly::OPERAND_F64IMM: {
Thomas Lively22442922018-08-21 21:03:18 +0000188 if (!parseImmediate<double>(MI, Size, Bytes))
189 return MCDisassembler::Fail;
190 break;
191 }
192 // Vector lane operands (not LEB encoded).
193 case WebAssembly::OPERAND_VEC_I8IMM: {
194 if (!parseImmediate<uint8_t>(MI, Size, Bytes))
195 return MCDisassembler::Fail;
196 break;
197 }
198 case WebAssembly::OPERAND_VEC_I16IMM: {
199 if (!parseImmediate<uint16_t>(MI, Size, Bytes))
200 return MCDisassembler::Fail;
201 break;
202 }
203 case WebAssembly::OPERAND_VEC_I32IMM: {
204 if (!parseImmediate<uint32_t>(MI, Size, Bytes))
205 return MCDisassembler::Fail;
206 break;
207 }
208 case WebAssembly::OPERAND_VEC_I64IMM: {
209 if (!parseImmediate<uint64_t>(MI, Size, Bytes))
Sam Clegg16c16822018-05-10 22:16:44 +0000210 return MCDisassembler::Fail;
211 break;
212 }
Wouter van Oortmerssena733d082018-08-30 15:40:53 +0000213 case MCOI::OPERAND_REGISTER:
214 // The tablegen header currently does not have any register operands since
215 // we use only the stack (_S) instructions.
216 // If you hit this that probably means a bad instruction definition in
217 // tablegen.
218 llvm_unreachable("Register operand in WebAssemblyDisassembler");
Sam Clegg16c16822018-05-10 22:16:44 +0000219 default:
220 llvm_unreachable("Unknown operand type in WebAssemblyDisassembler");
221 }
222 }
223 return MCDisassembler::Success;
Dan Gohman1a427282016-01-12 03:32:29 +0000224}