summaryrefslogtreecommitdiff
path: root/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-01-19 10:01:25 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-01-19 10:01:25 +0000
commitd8e91e46262bc44006913e6796843909f1ac7bcd (patch)
tree7d0c143d9b38190e0fa0180805389da22cd834c5 /lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
parentb7eb8e35e481a74962664b63dfb09483b200209a (diff)
Notes
Diffstat (limited to 'lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp')
-rw-r--r--lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp104
1 files changed, 78 insertions, 26 deletions
diff --git a/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp b/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
index 2f0960271e30..6acc9b20eed2 100644
--- a/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
+++ b/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
@@ -16,7 +16,6 @@
//===----------------------------------------------------------------------===//
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
-#include "WebAssembly.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDisassembler/MCDisassembler.h"
#include "llvm/MC/MCFixedLenDisassembler.h"
@@ -37,6 +36,8 @@ using DecodeStatus = MCDisassembler::DecodeStatus;
#include "WebAssemblyGenDisassemblerTables.inc"
namespace {
+static constexpr int WebAssemblyInstructionTableSize = 256;
+
class WebAssemblyDisassembler final : public MCDisassembler {
std::unique_ptr<const MCInstrInfo> MCII;
@@ -75,31 +76,43 @@ static int nextByte(ArrayRef<uint8_t> Bytes, uint64_t &Size) {
return V;
}
-static bool parseLEBImmediate(MCInst &MI, uint64_t &Size,
- ArrayRef<uint8_t> Bytes, bool Signed) {
+static bool nextLEB(int64_t &Val, ArrayRef<uint8_t> Bytes, uint64_t &Size,
+ bool Signed = false) {
unsigned N = 0;
const char *Error = nullptr;
- auto Val = Signed ? decodeSLEB128(Bytes.data() + Size, &N,
- Bytes.data() + Bytes.size(), &Error)
- : static_cast<int64_t>(
- decodeULEB128(Bytes.data() + Size, &N,
- Bytes.data() + Bytes.size(), &Error));
+ Val = Signed ? decodeSLEB128(Bytes.data() + Size, &N,
+ Bytes.data() + Bytes.size(), &Error)
+ : static_cast<int64_t>(decodeULEB128(Bytes.data() + Size, &N,
+ Bytes.data() + Bytes.size(),
+ &Error));
if (Error)
return false;
Size += N;
+ return true;
+}
+
+static bool parseLEBImmediate(MCInst &MI, uint64_t &Size,
+ ArrayRef<uint8_t> Bytes, bool Signed) {
+ int64_t Val;
+ if (!nextLEB(Val, Bytes, Size, Signed))
+ return false;
MI.addOperand(MCOperand::createImm(Val));
return true;
}
template <typename T>
-bool parseFPImmediate(MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes) {
+bool parseImmediate(MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes) {
if (Size + sizeof(T) > Bytes.size())
return false;
T Val;
memcpy(&Val, Bytes.data() + Size, sizeof(T));
support::endian::byte_swap<T, support::endianness::little>(Val);
Size += sizeof(T);
- MI.addOperand(MCOperand::createFPImm(static_cast<double>(Val)));
+ if (std::is_floating_point<T>::value) {
+ MI.addOperand(MCOperand::createFPImm(static_cast<double>(Val)));
+ } else {
+ MI.addOperand(MCOperand::createImm(static_cast<int64_t>(Val)));
+ }
return true;
}
@@ -108,7 +121,7 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
raw_ostream & /*OS*/, raw_ostream &CS) const {
CommentStream = &CS;
Size = 0;
- auto Opc = nextByte(Bytes, Size);
+ int Opc = nextByte(Bytes, Size);
if (Opc < 0)
return MCDisassembler::Fail;
const auto *WasmInst = &InstructionTable0[Opc];
@@ -124,10 +137,12 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
}
if (!WasmInst)
return MCDisassembler::Fail;
- Opc = nextByte(Bytes, Size);
- if (Opc < 0)
+ int64_t PrefixedOpc;
+ if (!nextLEB(PrefixedOpc, Bytes, Size))
return MCDisassembler::Fail;
- WasmInst += Opc;
+ if (PrefixedOpc < 0 || PrefixedOpc >= WebAssemblyInstructionTableSize)
+ return MCDisassembler::Fail;
+ WasmInst += PrefixedOpc;
}
if (WasmInst->ET == ET_Unused)
return MCDisassembler::Fail;
@@ -136,7 +151,8 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
MI.setOpcode(WasmInst->Opcode);
// Parse any operands.
for (uint8_t OPI = 0; OPI < WasmInst->NumOperands; OPI++) {
- switch (WasmInst->Operands[OPI]) {
+ auto OT = OperandTable[WasmInst->OperandStart + OPI];
+ switch (OT) {
// ULEB operands:
case WebAssembly::OPERAND_BASIC_BLOCK:
case WebAssembly::OPERAND_LOCAL:
@@ -152,32 +168,68 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
}
// SLEB operands:
case WebAssembly::OPERAND_I32IMM:
- case WebAssembly::OPERAND_I64IMM:
- case WebAssembly::OPERAND_SIGNATURE: {
+ case WebAssembly::OPERAND_I64IMM: {
if (!parseLEBImmediate(MI, Size, Bytes, true))
return MCDisassembler::Fail;
break;
}
+ // block_type operands (uint8_t).
+ case WebAssembly::OPERAND_SIGNATURE: {
+ if (!parseImmediate<uint8_t>(MI, Size, Bytes))
+ return MCDisassembler::Fail;
+ break;
+ }
// FP operands.
case WebAssembly::OPERAND_F32IMM: {
- if (!parseFPImmediate<float>(MI, Size, Bytes))
+ if (!parseImmediate<float>(MI, Size, Bytes))
return MCDisassembler::Fail;
break;
}
case WebAssembly::OPERAND_F64IMM: {
- if (!parseFPImmediate<double>(MI, Size, Bytes))
+ if (!parseImmediate<double>(MI, Size, Bytes))
return MCDisassembler::Fail;
break;
}
- case MCOI::OPERAND_REGISTER: {
- // These are NOT actually in the instruction stream, but MC is going to
- // expect operands to be present for them!
- // FIXME: can MC re-generate register assignments or do we have to
- // do this? Since this function decodes a single instruction, we don't
- // have the proper context for tracking an operand stack here.
- MI.addOperand(MCOperand::createReg(0));
+ // Vector lane operands (not LEB encoded).
+ case WebAssembly::OPERAND_VEC_I8IMM: {
+ if (!parseImmediate<uint8_t>(MI, Size, Bytes))
+ return MCDisassembler::Fail;
+ break;
+ }
+ case WebAssembly::OPERAND_VEC_I16IMM: {
+ if (!parseImmediate<uint16_t>(MI, Size, Bytes))
+ return MCDisassembler::Fail;
+ break;
+ }
+ case WebAssembly::OPERAND_VEC_I32IMM: {
+ if (!parseImmediate<uint32_t>(MI, Size, Bytes))
+ return MCDisassembler::Fail;
+ break;
+ }
+ case WebAssembly::OPERAND_VEC_I64IMM: {
+ if (!parseImmediate<uint64_t>(MI, Size, Bytes))
+ return MCDisassembler::Fail;
+ break;
+ }
+ case WebAssembly::OPERAND_BRLIST: {
+ int64_t TargetTableLen;
+ if (!nextLEB(TargetTableLen, Bytes, Size, false))
+ return MCDisassembler::Fail;
+ for (int64_t I = 0; I < TargetTableLen; I++) {
+ if (!parseLEBImmediate(MI, Size, Bytes, false))
+ return MCDisassembler::Fail;
+ }
+ // Default case.
+ if (!parseLEBImmediate(MI, Size, Bytes, false))
+ return MCDisassembler::Fail;
break;
}
+ case MCOI::OPERAND_REGISTER:
+ // The tablegen header currently does not have any register operands since
+ // we use only the stack (_S) instructions.
+ // If you hit this that probably means a bad instruction definition in
+ // tablegen.
+ llvm_unreachable("Register operand in WebAssemblyDisassembler");
default:
llvm_unreachable("Unknown operand type in WebAssemblyDisassembler");
}