diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-01-19 10:01:25 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-01-19 10:01:25 +0000 |
commit | d8e91e46262bc44006913e6796843909f1ac7bcd (patch) | |
tree | 7d0c143d9b38190e0fa0180805389da22cd834c5 /lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp | |
parent | b7eb8e35e481a74962664b63dfb09483b200209a (diff) |
Notes
Diffstat (limited to 'lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp')
-rw-r--r-- | lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp | 104 |
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"); } |