Line data Source code
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 : class 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 :
47 : public:
48 : WebAssemblyDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx,
49 : std::unique_ptr<const MCInstrInfo> MCII)
50 4 : : MCDisassembler(STI, Ctx), MCII(std::move(MCII)) {}
51 : };
52 : } // end anonymous namespace
53 :
54 2 : static MCDisassembler *createWebAssemblyDisassembler(const Target &T,
55 : const MCSubtargetInfo &STI,
56 : MCContext &Ctx) {
57 2 : std::unique_ptr<const MCInstrInfo> MCII(T.createMCInstrInfo());
58 2 : return new WebAssemblyDisassembler(STI, Ctx, std::move(MCII));
59 : }
60 :
61 10844 : extern "C" void LLVMInitializeWebAssemblyDisassembler() {
62 : // Register the disassembler for each target.
63 10844 : TargetRegistry::RegisterMCDisassembler(getTheWebAssemblyTarget32(),
64 : createWebAssemblyDisassembler);
65 10844 : TargetRegistry::RegisterMCDisassembler(getTheWebAssemblyTarget64(),
66 : createWebAssemblyDisassembler);
67 10844 : }
68 :
69 : static int nextByte(ArrayRef<uint8_t> Bytes, uint64_t &Size) {
70 3 : if (Size >= Bytes.size())
71 : return -1;
72 16 : auto V = Bytes[Size];
73 16 : Size++;
74 13 : return V;
75 : }
76 :
77 10 : static bool parseLEBImmediate(MCInst &MI, uint64_t &Size,
78 : ArrayRef<uint8_t> Bytes, bool Signed) {
79 10 : unsigned N = 0;
80 10 : const char *Error = nullptr;
81 17 : auto Val = Signed ? decodeSLEB128(Bytes.data() + Size, &N,
82 : Bytes.data() + Bytes.size(), &Error)
83 : : static_cast<int64_t>(
84 7 : decodeULEB128(Bytes.data() + Size, &N,
85 : Bytes.data() + Bytes.size(), &Error));
86 10 : if (Error)
87 : return false;
88 10 : Size += N;
89 10 : MI.addOperand(MCOperand::createImm(Val));
90 10 : return true;
91 : }
92 :
93 : template <typename T>
94 : bool parseImmediate(MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes) {
95 32 : if (Size + sizeof(T) > Bytes.size())
96 : return false;
97 : T Val;
98 32 : memcpy(&Val, Bytes.data() + Size, sizeof(T));
99 : support::endian::byte_swap<T, support::endianness::little>(Val);
100 32 : Size += sizeof(T);
101 : if (std::is_floating_point<T>::value) {
102 0 : MI.addOperand(MCOperand::createFPImm(static_cast<double>(Val)));
103 : } else {
104 32 : MI.addOperand(MCOperand::createImm(static_cast<int64_t>(Val)));
105 : }
106 : return true;
107 : }
108 :
109 13 : MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
110 : MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes, uint64_t /*Address*/,
111 : raw_ostream & /*OS*/, raw_ostream &CS) const {
112 13 : CommentStream = &CS;
113 13 : Size = 0;
114 : auto Opc = nextByte(Bytes, Size);
115 : if (Opc < 0)
116 : return MCDisassembler::Fail;
117 13 : const auto *WasmInst = &InstructionTable0[Opc];
118 : // If this is a prefix byte, indirect to another table.
119 13 : if (WasmInst->ET == ET_Prefix) {
120 : WasmInst = nullptr;
121 : // Linear search, so far only 2 entries.
122 5 : for (auto PT = PrefixTable; PT->Table; PT++) {
123 5 : if (PT->Prefix == Opc) {
124 : WasmInst = PT->Table;
125 : break;
126 : }
127 : }
128 3 : if (!WasmInst)
129 : return MCDisassembler::Fail;
130 : Opc = nextByte(Bytes, Size);
131 : if (Opc < 0)
132 : return MCDisassembler::Fail;
133 3 : WasmInst += Opc;
134 : }
135 13 : 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 13 : MI.setOpcode(WasmInst->Opcode);
140 : // Parse any operands.
141 55 : for (uint8_t OPI = 0; OPI < WasmInst->NumOperands; OPI++) {
142 42 : switch (OperandTable[WasmInst->OperandStart + OPI]) {
143 : // ULEB operands:
144 7 : 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 7 : if (!parseLEBImmediate(MI, Size, Bytes, false))
153 : return MCDisassembler::Fail;
154 : break;
155 : }
156 : // SLEB operands:
157 3 : case WebAssembly::OPERAND_I32IMM:
158 : case WebAssembly::OPERAND_I64IMM:
159 : case WebAssembly::OPERAND_SIGNATURE: {
160 3 : if (!parseLEBImmediate(MI, Size, Bytes, true))
161 : return MCDisassembler::Fail;
162 : break;
163 : }
164 : // FP operands.
165 0 : case WebAssembly::OPERAND_F32IMM: {
166 : if (!parseImmediate<float>(MI, Size, Bytes))
167 : return MCDisassembler::Fail;
168 : break;
169 : }
170 0 : case WebAssembly::OPERAND_F64IMM: {
171 : if (!parseImmediate<double>(MI, Size, Bytes))
172 : return MCDisassembler::Fail;
173 : break;
174 : }
175 : // Vector lane operands (not LEB encoded).
176 32 : case WebAssembly::OPERAND_VEC_I8IMM: {
177 : if (!parseImmediate<uint8_t>(MI, Size, Bytes))
178 : return MCDisassembler::Fail;
179 : break;
180 : }
181 0 : case WebAssembly::OPERAND_VEC_I16IMM: {
182 : if (!parseImmediate<uint16_t>(MI, Size, Bytes))
183 : return MCDisassembler::Fail;
184 : break;
185 : }
186 0 : case WebAssembly::OPERAND_VEC_I32IMM: {
187 : if (!parseImmediate<uint32_t>(MI, Size, Bytes))
188 : return MCDisassembler::Fail;
189 : break;
190 : }
191 0 : case WebAssembly::OPERAND_VEC_I64IMM: {
192 : if (!parseImmediate<uint64_t>(MI, Size, Bytes))
193 : return MCDisassembler::Fail;
194 : break;
195 : }
196 : 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");
202 0 : default:
203 0 : llvm_unreachable("Unknown operand type in WebAssemblyDisassembler");
204 : }
205 : }
206 : return MCDisassembler::Success;
207 : }
|