xref: /freebsd/contrib/llvm-project/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp (revision 9c68ef1455f882f5d737dcaa10f67250495902dc)
1  //==- WebAssemblyDisassembler.cpp - Disassembler for WebAssembly -*- C++ -*-==//
2  //
3  // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4  // See https://llvm.org/LICENSE.txt for license information.
5  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6  //
7  //===----------------------------------------------------------------------===//
8  ///
9  /// \file
10  /// This file is part of the WebAssembly Disassembler.
11  ///
12  /// It contains code to translate the data produced by the decoder into
13  /// MCInsts.
14  ///
15  //===----------------------------------------------------------------------===//
16  
17  #include "MCTargetDesc/WebAssemblyInstPrinter.h"
18  #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
19  #include "TargetInfo/WebAssemblyTargetInfo.h"
20  #include "llvm/MC/MCContext.h"
21  #include "llvm/MC/MCDisassembler/MCDisassembler.h"
22  #include "llvm/MC/MCFixedLenDisassembler.h"
23  #include "llvm/MC/MCInst.h"
24  #include "llvm/MC/MCInstrInfo.h"
25  #include "llvm/MC/MCSubtargetInfo.h"
26  #include "llvm/MC/MCSymbol.h"
27  #include "llvm/Support/Endian.h"
28  #include "llvm/Support/LEB128.h"
29  #include "llvm/Support/TargetRegistry.h"
30  
31  using namespace llvm;
32  
33  #define DEBUG_TYPE "wasm-disassembler"
34  
35  using DecodeStatus = MCDisassembler::DecodeStatus;
36  
37  #include "WebAssemblyGenDisassemblerTables.inc"
38  
39  namespace {
40  static constexpr int WebAssemblyInstructionTableSize = 256;
41  
42  class WebAssemblyDisassembler final : public MCDisassembler {
43    std::unique_ptr<const MCInstrInfo> MCII;
44  
45    DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
46                                ArrayRef<uint8_t> Bytes, uint64_t Address,
47                                raw_ostream &VStream,
48                                raw_ostream &CStream) const override;
49    DecodeStatus onSymbolStart(StringRef Name, uint64_t &Size,
50                               ArrayRef<uint8_t> Bytes, uint64_t Address,
51                               raw_ostream &VStream,
52                               raw_ostream &CStream) const override;
53  
54  public:
55    WebAssemblyDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx,
56                            std::unique_ptr<const MCInstrInfo> MCII)
57        : MCDisassembler(STI, Ctx), MCII(std::move(MCII)) {}
58  };
59  } // end anonymous namespace
60  
61  static MCDisassembler *createWebAssemblyDisassembler(const Target &T,
62                                                       const MCSubtargetInfo &STI,
63                                                       MCContext &Ctx) {
64    std::unique_ptr<const MCInstrInfo> MCII(T.createMCInstrInfo());
65    return new WebAssemblyDisassembler(STI, Ctx, std::move(MCII));
66  }
67  
68  extern "C" void LLVMInitializeWebAssemblyDisassembler() {
69    // Register the disassembler for each target.
70    TargetRegistry::RegisterMCDisassembler(getTheWebAssemblyTarget32(),
71                                           createWebAssemblyDisassembler);
72    TargetRegistry::RegisterMCDisassembler(getTheWebAssemblyTarget64(),
73                                           createWebAssemblyDisassembler);
74  }
75  
76  static int nextByte(ArrayRef<uint8_t> Bytes, uint64_t &Size) {
77    if (Size >= Bytes.size())
78      return -1;
79    auto V = Bytes[Size];
80    Size++;
81    return V;
82  }
83  
84  static bool nextLEB(int64_t &Val, ArrayRef<uint8_t> Bytes, uint64_t &Size,
85                      bool Signed) {
86    unsigned N = 0;
87    const char *Error = nullptr;
88    Val = Signed ? decodeSLEB128(Bytes.data() + Size, &N,
89                                 Bytes.data() + Bytes.size(), &Error)
90                 : static_cast<int64_t>(decodeULEB128(Bytes.data() + Size, &N,
91                                                      Bytes.data() + Bytes.size(),
92                                                      &Error));
93    if (Error)
94      return false;
95    Size += N;
96    return true;
97  }
98  
99  static bool parseLEBImmediate(MCInst &MI, uint64_t &Size,
100                                ArrayRef<uint8_t> Bytes, bool Signed) {
101    int64_t Val;
102    if (!nextLEB(Val, Bytes, Size, Signed))
103      return false;
104    MI.addOperand(MCOperand::createImm(Val));
105    return true;
106  }
107  
108  template <typename T>
109  bool parseImmediate(MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes) {
110    if (Size + sizeof(T) > Bytes.size())
111      return false;
112    T Val = support::endian::read<T, support::endianness::little, 1>(
113        Bytes.data() + Size);
114    Size += sizeof(T);
115    if (std::is_floating_point<T>::value) {
116      MI.addOperand(MCOperand::createFPImm(static_cast<double>(Val)));
117    } else {
118      MI.addOperand(MCOperand::createImm(static_cast<int64_t>(Val)));
119    }
120    return true;
121  }
122  
123  MCDisassembler::DecodeStatus WebAssemblyDisassembler::onSymbolStart(
124      StringRef Name, uint64_t &Size, ArrayRef<uint8_t> Bytes, uint64_t Address,
125      raw_ostream &VStream, raw_ostream &CStream) const {
126    Size = 0;
127    if (Address == 0) {
128      // Start of a code section: we're parsing only the function count.
129      int64_t FunctionCount;
130      if (!nextLEB(FunctionCount, Bytes, Size, false))
131        return MCDisassembler::Fail;
132      outs() << "        # " << FunctionCount << " functions in section.";
133    } else {
134      // Parse the start of a single function.
135      int64_t BodySize, LocalEntryCount;
136      if (!nextLEB(BodySize, Bytes, Size, false) ||
137          !nextLEB(LocalEntryCount, Bytes, Size, false))
138        return MCDisassembler::Fail;
139      if (LocalEntryCount) {
140        outs() << "        .local ";
141        for (int64_t I = 0; I < LocalEntryCount; I++) {
142          int64_t Count, Type;
143          if (!nextLEB(Count, Bytes, Size, false) ||
144              !nextLEB(Type, Bytes, Size, false))
145            return MCDisassembler::Fail;
146          for (int64_t J = 0; J < Count; J++) {
147            if (I || J)
148              outs() << ", ";
149            outs() << WebAssembly::anyTypeToString(Type);
150          }
151        }
152      }
153    }
154    outs() << "\n";
155    return MCDisassembler::Success;
156  }
157  
158  MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
159      MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes, uint64_t /*Address*/,
160      raw_ostream & /*OS*/, raw_ostream &CS) const {
161    CommentStream = &CS;
162    Size = 0;
163    int Opc = nextByte(Bytes, Size);
164    if (Opc < 0)
165      return MCDisassembler::Fail;
166    const auto *WasmInst = &InstructionTable0[Opc];
167    // If this is a prefix byte, indirect to another table.
168    if (WasmInst->ET == ET_Prefix) {
169      WasmInst = nullptr;
170      // Linear search, so far only 2 entries.
171      for (auto PT = PrefixTable; PT->Table; PT++) {
172        if (PT->Prefix == Opc) {
173          WasmInst = PT->Table;
174          break;
175        }
176      }
177      if (!WasmInst)
178        return MCDisassembler::Fail;
179      int64_t PrefixedOpc;
180      if (!nextLEB(PrefixedOpc, Bytes, Size, false))
181        return MCDisassembler::Fail;
182      if (PrefixedOpc < 0 || PrefixedOpc >= WebAssemblyInstructionTableSize)
183        return MCDisassembler::Fail;
184      WasmInst += PrefixedOpc;
185    }
186    if (WasmInst->ET == ET_Unused)
187      return MCDisassembler::Fail;
188    // At this point we must have a valid instruction to decode.
189    assert(WasmInst->ET == ET_Instruction);
190    MI.setOpcode(WasmInst->Opcode);
191    // Parse any operands.
192    for (uint8_t OPI = 0; OPI < WasmInst->NumOperands; OPI++) {
193      auto OT = OperandTable[WasmInst->OperandStart + OPI];
194      switch (OT) {
195      // ULEB operands:
196      case WebAssembly::OPERAND_BASIC_BLOCK:
197      case WebAssembly::OPERAND_LOCAL:
198      case WebAssembly::OPERAND_GLOBAL:
199      case WebAssembly::OPERAND_FUNCTION32:
200      case WebAssembly::OPERAND_OFFSET32:
201      case WebAssembly::OPERAND_P2ALIGN:
202      case WebAssembly::OPERAND_TYPEINDEX:
203      case WebAssembly::OPERAND_EVENT:
204      case MCOI::OPERAND_IMMEDIATE: {
205        if (!parseLEBImmediate(MI, Size, Bytes, false))
206          return MCDisassembler::Fail;
207        break;
208      }
209      // SLEB operands:
210      case WebAssembly::OPERAND_I32IMM:
211      case WebAssembly::OPERAND_I64IMM: {
212        if (!parseLEBImmediate(MI, Size, Bytes, true))
213          return MCDisassembler::Fail;
214        break;
215      }
216      // block_type operands (uint8_t).
217      case WebAssembly::OPERAND_SIGNATURE: {
218        if (!parseImmediate<uint8_t>(MI, Size, Bytes))
219          return MCDisassembler::Fail;
220        break;
221      }
222      // FP operands.
223      case WebAssembly::OPERAND_F32IMM: {
224        if (!parseImmediate<float>(MI, Size, Bytes))
225          return MCDisassembler::Fail;
226        break;
227      }
228      case WebAssembly::OPERAND_F64IMM: {
229        if (!parseImmediate<double>(MI, Size, Bytes))
230          return MCDisassembler::Fail;
231        break;
232      }
233      // Vector lane operands (not LEB encoded).
234      case WebAssembly::OPERAND_VEC_I8IMM: {
235        if (!parseImmediate<uint8_t>(MI, Size, Bytes))
236          return MCDisassembler::Fail;
237        break;
238      }
239      case WebAssembly::OPERAND_VEC_I16IMM: {
240        if (!parseImmediate<uint16_t>(MI, Size, Bytes))
241          return MCDisassembler::Fail;
242        break;
243      }
244      case WebAssembly::OPERAND_VEC_I32IMM: {
245        if (!parseImmediate<uint32_t>(MI, Size, Bytes))
246          return MCDisassembler::Fail;
247        break;
248      }
249      case WebAssembly::OPERAND_VEC_I64IMM: {
250        if (!parseImmediate<uint64_t>(MI, Size, Bytes))
251          return MCDisassembler::Fail;
252        break;
253      }
254      case WebAssembly::OPERAND_BRLIST: {
255        int64_t TargetTableLen;
256        if (!nextLEB(TargetTableLen, Bytes, Size, false))
257          return MCDisassembler::Fail;
258        for (int64_t I = 0; I < TargetTableLen; I++) {
259          if (!parseLEBImmediate(MI, Size, Bytes, false))
260            return MCDisassembler::Fail;
261        }
262        // Default case.
263        if (!parseLEBImmediate(MI, Size, Bytes, false))
264          return MCDisassembler::Fail;
265        break;
266      }
267      case MCOI::OPERAND_REGISTER:
268        // The tablegen header currently does not have any register operands since
269        // we use only the stack (_S) instructions.
270        // If you hit this that probably means a bad instruction definition in
271        // tablegen.
272        llvm_unreachable("Register operand in WebAssemblyDisassembler");
273      default:
274        llvm_unreachable("Unknown operand type in WebAssemblyDisassembler");
275      }
276    }
277    return MCDisassembler::Success;
278  }
279