LLVM  8.0.1
WebAssemblyDisassembler.cpp
Go to the documentation of this file.
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 
19 #include "llvm/MC/MCContext.h"
22 #include "llvm/MC/MCInst.h"
23 #include "llvm/MC/MCInstrInfo.h"
25 #include "llvm/MC/MCSymbol.h"
26 #include "llvm/Support/Endian.h"
27 #include "llvm/Support/LEB128.h"
29 
30 using namespace llvm;
31 
32 #define DEBUG_TYPE "wasm-disassembler"
33 
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:
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 
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 
64  // Register the disassembler for each target.
69 }
70 
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 
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 
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;
100  return true;
101 }
102 
103 template <typename T>
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 
119 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:
165  if (!parseLEBImmediate(MI, Size, Bytes, false))
166  return MCDisassembler::Fail;
167  break;
168  }
169  // SLEB operands:
172  if (!parseLEBImmediate(MI, Size, Bytes, true))
173  return MCDisassembler::Fail;
174  break;
175  }
176  // block_type operands (uint8_t).
178  if (!parseImmediate<uint8_t>(MI, Size, Bytes))
179  return MCDisassembler::Fail;
180  break;
181  }
182  // FP operands.
184  if (!parseImmediate<float>(MI, Size, Bytes))
185  return MCDisassembler::Fail;
186  break;
187  }
189  if (!parseImmediate<double>(MI, Size, Bytes))
190  return MCDisassembler::Fail;
191  break;
192  }
193  // Vector lane operands (not LEB encoded).
195  if (!parseImmediate<uint8_t>(MI, Size, Bytes))
196  return MCDisassembler::Fail;
197  break;
198  }
200  if (!parseImmediate<uint16_t>(MI, Size, Bytes))
201  return MCDisassembler::Fail;
202  break;
203  }
205  if (!parseImmediate<uint32_t>(MI, Size, Bytes))
206  return MCDisassembler::Fail;
207  break;
208  }
210  if (!parseImmediate<uint64_t>(MI, Size, Bytes))
211  return MCDisassembler::Fail;
212  break;
213  }
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  }
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  }
238 }
32-bit floating-point immediates.
This class represents lattice values for constants.
Definition: AllocatorList.h:24
void LLVMInitializeWebAssemblyDisassembler()
DecodeStatus
Ternary decode status.
Superclass for all disassemblers.
32-bit unsigned memory offsets.
MCInstrInfo * createMCInstrInfo() const
createMCInstrInfo - Create a MCInstrInfo implementation.
Basic block label in a branch construct.
static void RegisterMCDisassembler(Target &T, Target::MCDisassemblerCtorTy Fn)
RegisterMCDisassembler - Register a MCDisassembler implementation for the given target.
A list of branch targets for br_list.
signature immediate for block/loop.
int64_t decodeSLEB128(const uint8_t *p, unsigned *n=nullptr, const uint8_t *end=nullptr, const char **error=nullptr)
Utility function to decode a SLEB128 value.
Definition: LEB128.h:162
Context object for machine code objects.
Definition: MCContext.h:63
#define T
static int nextByte(ArrayRef< uint8_t > Bytes, uint64_t &Size)
Instances of this class represent a single low-level machine instruction.
Definition: MCInst.h:161
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:149
This file provides WebAssembly-specific target descriptions.
uint64_t decodeULEB128(const uint8_t *p, unsigned *n=nullptr, const uint8_t *end=nullptr, const char **error=nullptr)
Utility function to decode a ULEB128 value.
Definition: LEB128.h:129
type signature immediate for call_indirect.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
const T * data() const
Definition: ArrayRef.h:146
void setOpcode(unsigned Op)
Definition: MCInst.h:173
static MCOperand createFPImm(double Val)
Definition: MCInst.h:130
Target - Wrapper for Target specific information.
64-bit floating-point immediates.
32-bit unsigned function indices.
static MCDisassembler * createWebAssemblyDisassembler(const Target &T, const MCSubtargetInfo &STI, MCContext &Ctx)
p2align immediate for load and store address alignment.
#define I(x, y, z)
Definition: MD5.cpp:58
#define N
Generic base class for all target subtargets.
static bool parseLEBImmediate(MCInst &MI, uint64_t &Size, ArrayRef< uint8_t > Bytes, bool Signed)
uint32_t Size
Definition: Profile.cpp:47
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Lightweight error class with error context and mandatory checking.
Definition: Error.h:158
This class implements an extremely fast bulk output stream that can only output to a stream...
Definition: raw_ostream.h:46
IRTranslator LLVM IR MI
void addOperand(const MCOperand &Op)
Definition: MCInst.h:186
Target & getTheWebAssemblyTarget32()
Target & getTheWebAssemblyTarget64()
static bool nextLEB(int64_t &Val, ArrayRef< uint8_t > Bytes, uint64_t &Size, bool Signed=false)
static MCOperand createImm(int64_t Val)
Definition: MCInst.h:123
bool parseImmediate(MCInst &MI, uint64_t &Size, ArrayRef< uint8_t > Bytes)