1 //==- 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
11 /// This file is part of the WebAssembly Disassembler.
12 ///
13 /// It contains code to translate the data produced by the decoder into
14 /// MCInsts.
15 ///
16 //===----------------------------------------------------------------------===//
17
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"
29
30 using namespace llvm;
31
32 #define DEBUG_TYPE "wasm-disassembler"
33
34 using DecodeStatus = MCDisassembler::DecodeStatus;
35
36 #include "WebAssemblyGenDisassemblerTables.inc"
37
38 namespace {
39 static constexpr int WebAssemblyInstructionTableSize = 256;
40
41 class 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
49 public:
WebAssemblyDisassembler(const MCSubtargetInfo & STI,MCContext & Ctx,std::unique_ptr<const MCInstrInfo> MCII)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
createWebAssemblyDisassembler(const Target & T,const MCSubtargetInfo & STI,MCContext & Ctx)56 static 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
LLVMInitializeWebAssemblyDisassembler()63 extern "C" void LLVMInitializeWebAssemblyDisassembler() {
64 // Register the disassembler for each target.
65 TargetRegistry::RegisterMCDisassembler(getTheWebAssemblyTarget32(),
66 createWebAssemblyDisassembler);
67 TargetRegistry::RegisterMCDisassembler(getTheWebAssemblyTarget64(),
68 createWebAssemblyDisassembler);
69 }
70
nextByte(ArrayRef<uint8_t> Bytes,uint64_t & Size)71 static int nextByte(ArrayRef<uint8_t> Bytes, uint64_t &Size) {
72 if (Size >= Bytes.size())
73 return -1;
74 auto V = Bytes[Size];
75 Size++;
76 return V;
77 }
78
nextLEB(int64_t & Val,ArrayRef<uint8_t> Bytes,uint64_t & Size,bool Signed=false)79 static bool nextLEB(int64_t &Val, ArrayRef<uint8_t> Bytes, uint64_t &Size,
80 bool Signed = false) {
81 unsigned N = 0;
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(),
87 &Error));
88 if (Error)
89 return false;
90 Size += N;
91 return true;
92 }
93
parseLEBImmediate(MCInst & MI,uint64_t & Size,ArrayRef<uint8_t> Bytes,bool Signed)94 static 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;
99 MI.addOperand(MCOperand::createImm(Val));
100 return true;
101 }
102
103 template <typename T>
parseImmediate(MCInst & MI,uint64_t & Size,ArrayRef<uint8_t> Bytes)104 bool parseImmediate(MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes) {
105 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);
111 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 }
116 return true;
117 }
118
getInstruction(MCInst & MI,uint64_t & Size,ArrayRef<uint8_t> Bytes,uint64_t,raw_ostream &,raw_ostream & CS) const119 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 {
122 CommentStream = &CS;
123 Size = 0;
124 int Opc = nextByte(Bytes, Size);
125 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;
140 int64_t PrefixedOpc;
141 if (!nextLEB(PrefixedOpc, Bytes, Size))
142 return MCDisassembler::Fail;
143 if (PrefixedOpc < 0 || PrefixedOpc >= WebAssemblyInstructionTableSize)
144 return MCDisassembler::Fail;
145 WasmInst += PrefixedOpc;
146 }
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];
155 switch (OT) {
156 // ULEB operands:
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;
167 break;
168 }
169 // SLEB operands:
170 case WebAssembly::OPERAND_I32IMM:
171 case WebAssembly::OPERAND_I64IMM: {
172 if (!parseLEBImmediate(MI, Size, Bytes, true))
173 return MCDisassembler::Fail;
174 break;
175 }
176 // block_type operands (uint8_t).
177 case WebAssembly::OPERAND_SIGNATURE: {
178 if (!parseImmediate<uint8_t>(MI, Size, Bytes))
179 return MCDisassembler::Fail;
180 break;
181 }
182 // FP operands.
183 case WebAssembly::OPERAND_F32IMM: {
184 if (!parseImmediate<float>(MI, Size, Bytes))
185 return MCDisassembler::Fail;
186 break;
187 }
188 case WebAssembly::OPERAND_F64IMM: {
189 if (!parseImmediate<double>(MI, Size, Bytes))
190 return MCDisassembler::Fail;
191 break;
192 }
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;
197 break;
198 }
199 case WebAssembly::OPERAND_VEC_I16IMM: {
200 if (!parseImmediate<uint16_t>(MI, Size, Bytes))
201 return MCDisassembler::Fail;
202 break;
203 }
204 case WebAssembly::OPERAND_VEC_I32IMM: {
205 if (!parseImmediate<uint32_t>(MI, Size, Bytes))
206 return MCDisassembler::Fail;
207 break;
208 }
209 case WebAssembly::OPERAND_VEC_I64IMM: {
210 if (!parseImmediate<uint64_t>(MI, Size, Bytes))
211 return MCDisassembler::Fail;
212 break;
213 }
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;
221 }
222 // Default case.
223 if (!parseLEBImmediate(MI, Size, Bytes, false))
224 return MCDisassembler::Fail;
225 break;
226 }
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
231 // tablegen.
232 llvm_unreachable("Register operand in WebAssemblyDisassembler");
233 default:
234 llvm_unreachable("Unknown operand type in WebAssemblyDisassembler");
235 }
236 }
237 return MCDisassembler::Success;
238 }
239