mirror of
https://github.com/capstone-engine/capstone.git
synced 2024-11-23 13:39:46 +00:00
936dca0e2d
* Constify registerinfo.py output Remove two conditionals separating identical bits of code. Add "const" markup to MCRegisterDesc and MCRegisterClass. Signed-off-by: Richard Henderson <rth@twiddle.net> * Constify instrinfo-arch.py output In this case, do not actively strip const. Signed-off-by: Richard Henderson <rth@twiddle.net> * Constify the AArch64 backend Signed-off-by: Richard Henderson <rth@twiddle.net> * Constify the EVM backend Signed-off-by: Richard Henderson <rth@twiddle.net> * Constify M680X backend Signed-off-by: Richard Henderson <rth@twiddle.net> * Constify M68K backend Signed-off-by: Richard Henderson <rth@twiddle.net> * Constify the Mips backend The Mips backend has not been regenerated from LLVM recently, and there are more fixups required than I'd like. Just apply the fixes to the tables by hand for now. Signed-off-by: Richard Henderson <rth@twiddle.net> * Constify the Sparc backend Signed-off-by: Richard Henderson <rth@twiddle.net> * Constify the TMS320C64x backend Signed-off-by: Richard Henderson <rth@twiddle.net> * Constify the X86 backend Signed-off-by: Richard Henderson <rth@twiddle.net> * Constify the XCore backend Signed-off-by: Richard Henderson <rth@twiddle.net> * Constify systemregister.py output Signed-off-by: Richard Henderson <rth@twiddle.net> * Constify the ARM backend Signed-off-by: Richard Henderson <rth@twiddle.net> * Constify the PowerPC backend Signed-off-by: Richard Henderson <rth@twiddle.net> * Constify the MOS65XX backend Signed-off-by: Richard Henderson <rth@twiddle.net> * Constify the SystemZ backend The mapping of system register to indexes is easy to generate read-only. Since we know the indexes are between 0 and 31, use uint8_t instead of unsigned. Signed-off-by: Richard Henderson <rth@twiddle.net> * Constify the WASM backend Signed-off-by: Richard Henderson <rth@twiddle.net> * Constify cs.c Signed-off-by: Richard Henderson <rth@twiddle.net> * Constify the BPF backend Signed-off-by: Richard Henderson <rth@twiddle.net>
1010 lines
23 KiB
C
1010 lines
23 KiB
C
/* Capstone Disassembly Engine */
|
|
/* By Spike, xwings 2019 */
|
|
|
|
#include <string.h>
|
|
#include <stddef.h> // offsetof macro
|
|
// alternatively #include "../../utils.h" like everyone else
|
|
|
|
#include "WASMDisassembler.h"
|
|
#include "WASMMapping.h"
|
|
#include "../../cs_priv.h"
|
|
|
|
static const short opcodes[256] = {
|
|
WASM_INS_UNREACHABLE,
|
|
WASM_INS_NOP,
|
|
WASM_INS_BLOCK,
|
|
WASM_INS_LOOP,
|
|
WASM_INS_IF,
|
|
WASM_INS_ELSE,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
WASM_INS_END,
|
|
WASM_INS_BR,
|
|
WASM_INS_BR_IF,
|
|
WASM_INS_BR_TABLE,
|
|
WASM_INS_RETURN,
|
|
WASM_INS_CALL,
|
|
WASM_INS_CALL_INDIRECT,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
WASM_INS_DROP,
|
|
WASM_INS_SELECT,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
WASM_INS_GET_LOCAL,
|
|
WASM_INS_SET_LOCAL,
|
|
WASM_INS_TEE_LOCAL,
|
|
WASM_INS_GET_GLOBAL,
|
|
WASM_INS_SET_GLOBAL,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
WASM_INS_I32_LOAD,
|
|
WASM_INS_I64_LOAD,
|
|
WASM_INS_F32_LOAD,
|
|
WASM_INS_F64_LOAD,
|
|
WASM_INS_I32_LOAD8_S,
|
|
WASM_INS_I32_LOAD8_U,
|
|
WASM_INS_I32_LOAD16_S,
|
|
WASM_INS_I32_LOAD16_U,
|
|
WASM_INS_I64_LOAD8_S,
|
|
WASM_INS_I64_LOAD8_U,
|
|
WASM_INS_I64_LOAD16_S,
|
|
WASM_INS_I64_LOAD16_U,
|
|
WASM_INS_I64_LOAD32_S,
|
|
WASM_INS_I64_LOAD32_U,
|
|
WASM_INS_I32_STORE,
|
|
WASM_INS_I64_STORE,
|
|
WASM_INS_F32_STORE,
|
|
WASM_INS_F64_STORE,
|
|
WASM_INS_I32_STORE8,
|
|
WASM_INS_I32_STORE16,
|
|
WASM_INS_I64_STORE8,
|
|
WASM_INS_I64_STORE16,
|
|
WASM_INS_I64_STORE32,
|
|
WASM_INS_CURRENT_MEMORY,
|
|
WASM_INS_GROW_MEMORY,
|
|
WASM_INS_I32_CONST,
|
|
WASM_INS_I64_CONST,
|
|
WASM_INS_F32_CONST,
|
|
WASM_INS_F64_CONST,
|
|
WASM_INS_I32_EQZ,
|
|
WASM_INS_I32_EQ,
|
|
WASM_INS_I32_NE,
|
|
WASM_INS_I32_LT_S,
|
|
WASM_INS_I32_LT_U,
|
|
WASM_INS_I32_GT_S,
|
|
WASM_INS_I32_GT_U,
|
|
WASM_INS_I32_LE_S,
|
|
WASM_INS_I32_LE_U,
|
|
WASM_INS_I32_GE_S,
|
|
WASM_INS_I32_GE_U,
|
|
WASM_INS_I64_EQZ,
|
|
WASM_INS_I64_EQ,
|
|
WASM_INS_I64_NE,
|
|
WASM_INS_I64_LT_S,
|
|
WASM_INS_I64_LT_U,
|
|
WASN_INS_I64_GT_S,
|
|
WASM_INS_I64_GT_U,
|
|
WASM_INS_I64_LE_S,
|
|
WASM_INS_I64_LE_U,
|
|
WASM_INS_I64_GE_S,
|
|
WASM_INS_I64_GE_U,
|
|
WASM_INS_F32_EQ,
|
|
WASM_INS_F32_NE,
|
|
WASM_INS_F32_LT,
|
|
WASM_INS_F32_GT,
|
|
WASM_INS_F32_LE,
|
|
WASM_INS_F32_GE,
|
|
WASM_INS_F64_EQ,
|
|
WASM_INS_F64_NE,
|
|
WASM_INS_F64_LT,
|
|
WASM_INS_F64_GT,
|
|
WASM_INS_F64_LE,
|
|
WASM_INS_F64_GE,
|
|
WASM_INS_I32_CLZ,
|
|
WASM_INS_I32_CTZ,
|
|
WASM_INS_I32_POPCNT,
|
|
WASM_INS_I32_ADD,
|
|
WASM_INS_I32_SUB,
|
|
WASM_INS_I32_MUL,
|
|
WASM_INS_I32_DIV_S,
|
|
WASM_INS_I32_DIV_U,
|
|
WASM_INS_I32_REM_S,
|
|
WASM_INS_I32_REM_U,
|
|
WASM_INS_I32_AND,
|
|
WASM_INS_I32_OR,
|
|
WASM_INS_I32_XOR,
|
|
WASM_INS_I32_SHL,
|
|
WASM_INS_I32_SHR_S,
|
|
WASM_INS_I32_SHR_U,
|
|
WASM_INS_I32_ROTL,
|
|
WASM_INS_I32_ROTR,
|
|
WASM_INS_I64_CLZ,
|
|
WASM_INS_I64_CTZ,
|
|
WASM_INS_I64_POPCNT,
|
|
WASM_INS_I64_ADD,
|
|
WASM_INS_I64_SUB,
|
|
WASM_INS_I64_MUL,
|
|
WASM_INS_I64_DIV_S,
|
|
WASM_INS_I64_DIV_U,
|
|
WASM_INS_I64_REM_S,
|
|
WASM_INS_I64_REM_U,
|
|
WASM_INS_I64_AND,
|
|
WASM_INS_I64_OR,
|
|
WASM_INS_I64_XOR,
|
|
WASM_INS_I64_SHL,
|
|
WASM_INS_I64_SHR_S,
|
|
WASM_INS_I64_SHR_U,
|
|
WASM_INS_I64_ROTL,
|
|
WASM_INS_I64_ROTR,
|
|
WASM_INS_F32_ABS,
|
|
WASM_INS_F32_NEG,
|
|
WASM_INS_F32_CEIL,
|
|
WASM_INS_F32_FLOOR,
|
|
WASM_INS_F32_TRUNC,
|
|
WASM_INS_F32_NEAREST,
|
|
WASM_INS_F32_SQRT,
|
|
WASM_INS_F32_ADD,
|
|
WASM_INS_F32_SUB,
|
|
WASM_INS_F32_MUL,
|
|
WASM_INS_F32_DIV,
|
|
WASM_INS_F32_MIN,
|
|
WASM_INS_F32_MAX,
|
|
WASM_INS_F32_COPYSIGN,
|
|
WASM_INS_F64_ABS,
|
|
WASM_INS_F64_NEG,
|
|
WASM_INS_F64_CEIL,
|
|
WASM_INS_F64_FLOOR,
|
|
WASM_INS_F64_TRUNC,
|
|
WASM_INS_F64_NEAREST,
|
|
WASM_INS_F64_SQRT,
|
|
WASM_INS_F64_ADD,
|
|
WASM_INS_F64_SUB,
|
|
WASM_INS_F64_MUL,
|
|
WASM_INS_F64_DIV,
|
|
WASM_INS_F64_MIN,
|
|
WASM_INS_F64_MAX,
|
|
WASM_INS_F64_COPYSIGN,
|
|
WASM_INS_I32_WARP_I64,
|
|
WASP_INS_I32_TRUNC_S_F32,
|
|
WASM_INS_I32_TRUNC_U_F32,
|
|
WASM_INS_I32_TRUNC_S_F64,
|
|
WASM_INS_I32_TRUNC_U_F64,
|
|
WASM_INS_I64_EXTEND_S_I32,
|
|
WASM_INS_I64_EXTEND_U_I32,
|
|
WASM_INS_I64_TRUNC_S_F32,
|
|
WASM_INS_I64_TRUNC_U_F32,
|
|
WASM_INS_I64_TRUNC_S_F64,
|
|
WASM_INS_I64_TRUNC_U_F64,
|
|
WASM_INS_F32_CONVERT_S_I32,
|
|
WASM_INS_F32_CONVERT_U_I32,
|
|
WASM_INS_F32_CONVERT_S_I64,
|
|
WASM_INS_F32_CONVERT_U_I64,
|
|
WASM_INS_F32_DEMOTE_F64,
|
|
WASM_INS_F64_CONVERT_S_I32,
|
|
WASM_INS_F64_CONVERT_U_I32,
|
|
WASM_INS_F64_CONVERT_S_I64,
|
|
WASM_INS_F64_CONVERT_U_I64,
|
|
WASM_INS_F64_PROMOTE_F32,
|
|
WASM_INS_I32_REINTERPRET_F32,
|
|
WASM_INS_I64_REINTERPRET_F64,
|
|
WASM_INS_F32_REINTERPRET_I32,
|
|
WASM_INS_F64_REINTERPRET_I64,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
};
|
|
|
|
// input | code: code pointer start from varuint32
|
|
// | code_len: real code len count from varint
|
|
// | leng: return value, means length of varint. -1 means error
|
|
// return | varint
|
|
static uint32_t get_varuint32(const uint8_t *code, size_t code_len, size_t *leng)
|
|
{
|
|
uint32_t data = 0;
|
|
int i;
|
|
|
|
for(i = 0;; i++) {
|
|
if (code_len < i + 1) {
|
|
*leng = -1;
|
|
return 0;
|
|
}
|
|
|
|
|
|
if (i > 4 || (i == 4 && (code[i] & 0x7f) > 0x0f)) {
|
|
*leng = -1;
|
|
return 0;
|
|
}
|
|
|
|
data = data + (((uint32_t) code[i] & 0x7f) << (i * 7));
|
|
if (code[i] >> 7 == 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
*leng = i + 1;
|
|
|
|
return data;
|
|
}
|
|
|
|
// input | code : code pointer start from varuint64
|
|
// | code_len : real code len count from varint
|
|
// | leng: return value, means length of varint. -1 means error
|
|
// return | varint
|
|
static uint64_t get_varuint64(const uint8_t *code, size_t code_len, size_t *leng)
|
|
{
|
|
uint64_t data;
|
|
int i;
|
|
|
|
data = 0;
|
|
for(i = 0;; i++){
|
|
if (code_len < i + 1) {
|
|
*leng = -1;
|
|
return 0;
|
|
}
|
|
|
|
if (i > 9 || (i == 9 && (code[i] & 0x7f) > 0x01)) {
|
|
*leng = -1;
|
|
return 0;
|
|
}
|
|
|
|
data = data + (((uint64_t) code[i] & 0x7f) << (i * 7));
|
|
if (code[i] >> 7 == 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
*leng = i + 1;
|
|
|
|
return data;
|
|
}
|
|
|
|
// input | code : code pointer start from uint32
|
|
// | dest : the pointer where we store the uint32
|
|
// return | None
|
|
static void get_uint32(const uint8_t *code, uint32_t *dest)
|
|
{
|
|
memcpy(dest, code, 4);
|
|
}
|
|
|
|
// input | code : code pointer start from uint32
|
|
// | dest : the pointer where we store the uint64
|
|
// return | None
|
|
static void get_uint64(const uint8_t *code, uint64_t *dest)
|
|
{
|
|
memcpy(dest, code, 8);
|
|
}
|
|
|
|
// input | code : code pointer start from varint7
|
|
// | code_len : start from the code pointer to the end, how long is it
|
|
// | leng : length of the param , -1 means error
|
|
// return | data of varint7
|
|
static int8_t get_varint7(const uint8_t *code, size_t code_len, size_t *leng)
|
|
{
|
|
int8_t data;
|
|
|
|
if (code_len < 1) {
|
|
*leng = -1;
|
|
return -1;
|
|
}
|
|
|
|
*leng = 1;
|
|
|
|
if (code[0] == 0x40) {
|
|
return -1;
|
|
}
|
|
|
|
data = code[0] & 0x7f;
|
|
|
|
return data;
|
|
}
|
|
|
|
// input | code : code pointer start from varuint32
|
|
// | code_len : start from the code pointer to the end, how long is it
|
|
// | param_size : pointer of the param size
|
|
// | MI : Mcinst handler in this round of disasm
|
|
// return | true/false if the function successfully finished
|
|
static bool read_varuint32(const uint8_t *code, size_t code_len, uint16_t *param_size, MCInst *MI)
|
|
{
|
|
size_t len = 0;
|
|
uint32_t data;
|
|
|
|
data = get_varuint32(code, code_len, &len);
|
|
if (len == -1) {
|
|
return false;
|
|
}
|
|
|
|
if (MI->flat_insn->detail) {
|
|
MI->flat_insn->detail->wasm.op_count = 1;
|
|
MI->flat_insn->detail->wasm.operands[0].type = WASM_OP_VARUINT32;
|
|
MI->flat_insn->detail->wasm.operands[0].size= len;
|
|
MI->flat_insn->detail->wasm.operands[0].varuint32= data;
|
|
}
|
|
|
|
MI->wasm_data.size = len;
|
|
MI->wasm_data.type = WASM_OP_VARUINT32;
|
|
MI->wasm_data.uint32 = data;
|
|
*param_size = len;
|
|
|
|
return true;
|
|
}
|
|
|
|
// input | code : code pointer start from varuint64
|
|
// | code_len : start from the code pointer to the end, how long is it
|
|
// | param_size : pointer of the param size
|
|
// | MI : Mcinst handler in this round of disasm
|
|
// return | true/false if the function successfully finished
|
|
static bool read_varuint64(const uint8_t *code, size_t code_len, uint16_t *param_size, MCInst *MI)
|
|
{
|
|
size_t len = 0;
|
|
uint64_t data;
|
|
|
|
data = get_varuint64(code, code_len, &len);
|
|
if (len == -1) {
|
|
return false;
|
|
}
|
|
|
|
if (MI->flat_insn->detail) {
|
|
MI->flat_insn->detail->wasm.op_count = 1;
|
|
MI->flat_insn->detail->wasm.operands[0].type = WASM_OP_VARUINT64;
|
|
MI->flat_insn->detail->wasm.operands[0].size = len;
|
|
MI->flat_insn->detail->wasm.operands[0].varuint64 = data;
|
|
}
|
|
|
|
MI->wasm_data.size = len;
|
|
MI->wasm_data.type = WASM_OP_VARUINT64;
|
|
MI->wasm_data.uint64 = data;
|
|
*param_size = len;
|
|
|
|
return true;
|
|
}
|
|
|
|
// input | code : code pointer start from memoryimmediate
|
|
// | code_len : start from the code pointer to the end, how long is it
|
|
// | param_size : pointer of the param size (sum of two params)
|
|
// | MI : Mcinst handler in this round of disasm
|
|
// return | true/false if the function successfully finished
|
|
static bool read_memoryimmediate(const uint8_t *code, size_t code_len, uint16_t *param_size, MCInst *MI)
|
|
{
|
|
size_t tmp, len = 0;
|
|
uint32_t data[2];
|
|
|
|
if (MI->flat_insn->detail) {
|
|
MI->flat_insn->detail->wasm.op_count = 2;
|
|
}
|
|
|
|
data[0] = get_varuint32(code, code_len, &tmp);
|
|
if (tmp == -1) {
|
|
return false;
|
|
}
|
|
|
|
if (MI->flat_insn->detail) {
|
|
MI->flat_insn->detail->wasm.operands[0].type = WASM_OP_VARUINT32;
|
|
MI->flat_insn->detail->wasm.operands[0].size = tmp;
|
|
MI->flat_insn->detail->wasm.operands[0].varuint32 = data[0];
|
|
}
|
|
|
|
len = tmp;
|
|
data[1] = get_varuint32(&code[len], code_len - len, &tmp);
|
|
if (len == -1) {
|
|
return false;
|
|
}
|
|
|
|
if (MI->flat_insn->detail) {
|
|
MI->flat_insn->detail->wasm.operands[1].type = WASM_OP_VARUINT32;
|
|
MI->flat_insn->detail->wasm.operands[1].size = tmp;
|
|
MI->flat_insn->detail->wasm.operands[1].varuint32 = data[1];
|
|
}
|
|
|
|
len += tmp;
|
|
MI->wasm_data.size = len;
|
|
MI->wasm_data.type = WASM_OP_IMM;
|
|
MI->wasm_data.immediate[0] = data[0];
|
|
MI->wasm_data.immediate[1] = data[1];
|
|
*param_size = len;
|
|
|
|
return true;
|
|
}
|
|
|
|
// input | code : code pointer start from uint32
|
|
// | code_len : start from the code pointer to the end, how long is it
|
|
// | param_size : pointer of the param size
|
|
// | MI : Mcinst handler in this round of disasm
|
|
// return | true/false if the function successfully finished
|
|
static bool read_uint32(const uint8_t *code, size_t code_len, uint16_t *param_size, MCInst *MI)
|
|
{
|
|
if (code_len < 4) {
|
|
return false;
|
|
}
|
|
|
|
get_uint32(code, &(MI->wasm_data.uint32));
|
|
|
|
if (MI->flat_insn->detail) {
|
|
MI->flat_insn->detail->wasm.op_count = 1;
|
|
MI->flat_insn->detail->wasm.operands[0].type = WASM_OP_UINT32;
|
|
MI->flat_insn->detail->wasm.operands[0].size = 4;
|
|
get_uint32(code, &(MI->flat_insn->detail->wasm.operands[0].uint32));
|
|
}
|
|
|
|
MI->wasm_data.size = 4;
|
|
MI->wasm_data.type = WASM_OP_UINT32;
|
|
*param_size = 4;
|
|
|
|
return true;
|
|
}
|
|
|
|
// input | code : code pointer start from uint64
|
|
// | code_len : start from the code pointer to the end, how long is it
|
|
// | param_size : pointer of the param size
|
|
// | MI : Mcinst handler in this round of disasm
|
|
// return | true/false if the function successfully finished
|
|
static bool read_uint64(const uint8_t *code, size_t code_len, uint16_t *param_size, MCInst *MI)
|
|
{
|
|
if (code_len < 8) {
|
|
return false;
|
|
}
|
|
|
|
get_uint64(code, &(MI->wasm_data.uint64));
|
|
|
|
if (MI->flat_insn->detail) {
|
|
MI->flat_insn->detail->wasm.op_count = 1;
|
|
MI->flat_insn->detail->wasm.operands[0].type = WASM_OP_UINT64;
|
|
MI->flat_insn->detail->wasm.operands[0].size = 8;
|
|
get_uint64(code, &(MI->flat_insn->detail->wasm.operands[0].uint64));
|
|
}
|
|
|
|
MI->wasm_data.size = 8;
|
|
MI->wasm_data.type = WASM_OP_UINT64;
|
|
*param_size = 8;
|
|
|
|
return true;
|
|
}
|
|
|
|
// input | code : code pointer start from brtable
|
|
// | code_len : start from the code pointer to the end, how long is it
|
|
// | param_size : pointer of the param size (sum of all param)
|
|
// | MI : Mcinst handler in this round of disasm
|
|
// return | true/false if the function successfully finished
|
|
static bool read_brtable(const uint8_t *code, size_t code_len, uint16_t *param_size, MCInst *MI)
|
|
{
|
|
uint32_t length, default_target;
|
|
int tmp_len = 0, i;
|
|
size_t var_len;
|
|
|
|
// read length
|
|
length = get_varuint32(code, code_len, &var_len);
|
|
if (var_len == -1) {
|
|
return false;
|
|
}
|
|
|
|
tmp_len += var_len;
|
|
MI->wasm_data.brtable.length = length;
|
|
if (length >= UINT32_MAX - tmp_len) {
|
|
// integer overflow check
|
|
return false;
|
|
}
|
|
if (code_len < tmp_len + length) {
|
|
// safety check that we have minimum enough data to read
|
|
return false;
|
|
}
|
|
// base address + 1 byte opcode + tmp_len for number of cases = start of targets
|
|
MI->wasm_data.brtable.address = MI->address + 1 + tmp_len;
|
|
|
|
if (MI->flat_insn->detail) {
|
|
MI->flat_insn->detail->wasm.op_count = 1;
|
|
MI->flat_insn->detail->wasm.operands[0].type = WASM_OP_BRTABLE;
|
|
MI->flat_insn->detail->wasm.operands[0].brtable.length = MI->wasm_data.brtable.length;
|
|
MI->flat_insn->detail->wasm.operands[0].brtable.address = MI->wasm_data.brtable.address;
|
|
}
|
|
|
|
// read data
|
|
for(i = 0; i < length; i++){
|
|
if (code_len < tmp_len) {
|
|
return false;
|
|
}
|
|
|
|
get_varuint32(code + tmp_len, code_len - tmp_len, &var_len);
|
|
if (var_len == -1) {
|
|
return false;
|
|
}
|
|
|
|
tmp_len += var_len;
|
|
}
|
|
|
|
// read default target
|
|
default_target = get_varuint32(code + tmp_len, code_len - tmp_len, &var_len);
|
|
if (var_len == -1) {
|
|
return false;
|
|
}
|
|
|
|
MI->wasm_data.brtable.default_target = default_target;
|
|
MI->wasm_data.type = WASM_OP_BRTABLE;
|
|
*param_size = tmp_len + var_len;
|
|
|
|
if (MI->flat_insn->detail) {
|
|
MI->flat_insn->detail->wasm.operands[0].size = *param_size;
|
|
MI->flat_insn->detail->wasm.operands[0].brtable.default_target = MI->wasm_data.brtable.default_target;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// input | code : code pointer start from varint7
|
|
// | code_len : start from the code pointer to the end, how long is it
|
|
// | param_size : pointer of the param size
|
|
// | MI : Mcinst handler in this round of disasm
|
|
// return | true/false if the function successfully finished
|
|
static bool read_varint7(const uint8_t *code, size_t code_len, uint16_t *param_size, MCInst *MI)
|
|
{
|
|
size_t len = 0;
|
|
|
|
MI->wasm_data.type = WASM_OP_INT7;
|
|
MI->wasm_data.int7 = get_varint7(code, code_len, &len);
|
|
if (len == -1) {
|
|
return false;
|
|
}
|
|
|
|
if (MI->flat_insn->detail) {
|
|
MI->flat_insn->detail->wasm.op_count = 1;
|
|
MI->flat_insn->detail->wasm.operands[0].type = WASM_OP_INT7;
|
|
MI->flat_insn->detail->wasm.operands[0].size = 1;
|
|
MI->flat_insn->detail->wasm.operands[0].int7 = MI->wasm_data.int7;
|
|
}
|
|
|
|
*param_size = len;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool WASM_getInstruction(csh ud, const uint8_t *code, size_t code_len,
|
|
MCInst *MI, uint16_t *size, uint64_t address, void *inst_info)
|
|
{
|
|
unsigned char opcode;
|
|
uint16_t param_size;
|
|
|
|
if (code_len == 0)
|
|
return false;
|
|
|
|
opcode = code[0];
|
|
if (opcodes[opcode] == -1) {
|
|
// invalid opcode
|
|
return false;
|
|
}
|
|
|
|
// valid opcode
|
|
MI->address = address;
|
|
MI->OpcodePub = MI->Opcode = opcode;
|
|
|
|
if (MI->flat_insn->detail) {
|
|
memset(MI->flat_insn->detail, 0, offsetof(cs_detail, wasm)+sizeof(cs_wasm));
|
|
WASM_get_insn_id((cs_struct *)ud, MI->flat_insn, opcode);
|
|
}
|
|
|
|
// setup groups
|
|
switch(opcode) {
|
|
default:
|
|
return false;
|
|
|
|
case WASM_INS_I32_CONST:
|
|
if (code_len == 1 || !read_varuint32(&code[1], code_len - 1, ¶m_size, MI)) {
|
|
return false;
|
|
}
|
|
|
|
if (MI->flat_insn->detail) {
|
|
MI->flat_insn->detail->wasm.op_count = 1;
|
|
MI->flat_insn->detail->groups[MI->flat_insn->detail->groups_count] = WASM_GRP_NUMBERIC;
|
|
MI->flat_insn->detail->groups_count++;
|
|
}
|
|
|
|
*size = param_size + 1;
|
|
|
|
break;
|
|
|
|
case WASM_INS_I64_CONST:
|
|
if (code_len == 1 || !read_varuint64(&code[1], code_len - 1, ¶m_size, MI)) {
|
|
return false;
|
|
}
|
|
|
|
if (MI->flat_insn->detail) {
|
|
MI->flat_insn->detail->wasm.op_count = 1;
|
|
MI->flat_insn->detail->groups[MI->flat_insn->detail->groups_count] = WASM_GRP_NUMBERIC;
|
|
MI->flat_insn->detail->groups_count++;
|
|
}
|
|
|
|
*size = param_size + 1;
|
|
|
|
break;
|
|
|
|
case WASM_INS_F32_CONST:
|
|
if (code_len == 1 || !read_uint32(&code[1], code_len - 1, ¶m_size, MI)) {
|
|
return false;
|
|
}
|
|
|
|
if (MI->flat_insn->detail) {
|
|
MI->flat_insn->detail->wasm.op_count = 1;
|
|
MI->flat_insn->detail->groups[MI->flat_insn->detail->groups_count] = WASM_GRP_NUMBERIC;
|
|
MI->flat_insn->detail->groups_count++;
|
|
}
|
|
|
|
*size = param_size + 1;
|
|
|
|
break;
|
|
|
|
case WASM_INS_F64_CONST:
|
|
if (code_len == 1 || !read_uint64(&code[1], code_len - 1, ¶m_size, MI)) {
|
|
return false;
|
|
}
|
|
|
|
if (MI->flat_insn->detail) {
|
|
MI->flat_insn->detail->wasm.op_count = 1;
|
|
MI->flat_insn->detail->groups[MI->flat_insn->detail->groups_count] = WASM_GRP_NUMBERIC;
|
|
MI->flat_insn->detail->groups_count++;
|
|
}
|
|
|
|
*size = param_size + 1;
|
|
|
|
break;
|
|
|
|
case WASM_INS_I32_EQZ:
|
|
case WASM_INS_I32_EQ:
|
|
case WASM_INS_I32_NE:
|
|
case WASM_INS_I32_LT_S:
|
|
case WASM_INS_I32_LT_U:
|
|
case WASM_INS_I32_GT_S:
|
|
case WASM_INS_I32_GT_U:
|
|
case WASM_INS_I32_LE_S:
|
|
case WASM_INS_I32_LE_U:
|
|
case WASM_INS_I32_GE_S:
|
|
case WASM_INS_I32_GE_U:
|
|
case WASM_INS_I64_EQZ:
|
|
case WASM_INS_I64_EQ:
|
|
case WASM_INS_I64_NE:
|
|
case WASM_INS_I64_LT_S:
|
|
case WASM_INS_I64_LT_U:
|
|
case WASN_INS_I64_GT_S:
|
|
case WASM_INS_I64_GT_U:
|
|
case WASM_INS_I64_LE_S:
|
|
case WASM_INS_I64_LE_U:
|
|
case WASM_INS_I64_GE_S:
|
|
case WASM_INS_I64_GE_U:
|
|
case WASM_INS_F32_EQ:
|
|
case WASM_INS_F32_NE:
|
|
case WASM_INS_F32_LT:
|
|
case WASM_INS_F32_GT:
|
|
case WASM_INS_F32_LE:
|
|
case WASM_INS_F32_GE:
|
|
case WASM_INS_F64_EQ:
|
|
case WASM_INS_F64_NE:
|
|
case WASM_INS_F64_LT:
|
|
case WASM_INS_F64_GT:
|
|
case WASM_INS_F64_LE:
|
|
case WASM_INS_F64_GE:
|
|
case WASM_INS_I32_CLZ:
|
|
case WASM_INS_I32_CTZ:
|
|
case WASM_INS_I32_POPCNT:
|
|
case WASM_INS_I32_ADD:
|
|
case WASM_INS_I32_SUB:
|
|
case WASM_INS_I32_MUL:
|
|
case WASM_INS_I32_DIV_S:
|
|
case WASM_INS_I32_DIV_U:
|
|
case WASM_INS_I32_REM_S:
|
|
case WASM_INS_I32_REM_U:
|
|
case WASM_INS_I32_AND:
|
|
case WASM_INS_I32_OR:
|
|
case WASM_INS_I32_XOR:
|
|
case WASM_INS_I32_SHL:
|
|
case WASM_INS_I32_SHR_S:
|
|
case WASM_INS_I32_SHR_U:
|
|
case WASM_INS_I32_ROTL:
|
|
case WASM_INS_I32_ROTR:
|
|
case WASM_INS_I64_CLZ:
|
|
case WASM_INS_I64_CTZ:
|
|
case WASM_INS_I64_POPCNT:
|
|
case WASM_INS_I64_ADD:
|
|
case WASM_INS_I64_SUB:
|
|
case WASM_INS_I64_MUL:
|
|
case WASM_INS_I64_DIV_S:
|
|
case WASM_INS_I64_DIV_U:
|
|
case WASM_INS_I64_REM_S:
|
|
case WASM_INS_I64_REM_U:
|
|
case WASM_INS_I64_AND:
|
|
case WASM_INS_I64_OR:
|
|
case WASM_INS_I64_XOR:
|
|
case WASM_INS_I64_SHL:
|
|
case WASM_INS_I64_SHR_S:
|
|
case WASM_INS_I64_SHR_U:
|
|
case WASM_INS_I64_ROTL:
|
|
case WASM_INS_I64_ROTR:
|
|
case WASM_INS_F32_ABS:
|
|
case WASM_INS_F32_NEG:
|
|
case WASM_INS_F32_CEIL:
|
|
case WASM_INS_F32_FLOOR:
|
|
case WASM_INS_F32_TRUNC:
|
|
case WASM_INS_F32_NEAREST:
|
|
case WASM_INS_F32_SQRT:
|
|
case WASM_INS_F32_ADD:
|
|
case WASM_INS_F32_SUB:
|
|
case WASM_INS_F32_MUL:
|
|
case WASM_INS_F32_DIV:
|
|
case WASM_INS_F32_MIN:
|
|
case WASM_INS_F32_MAX:
|
|
case WASM_INS_F32_COPYSIGN:
|
|
case WASM_INS_F64_ABS:
|
|
case WASM_INS_F64_NEG:
|
|
case WASM_INS_F64_CEIL:
|
|
case WASM_INS_F64_FLOOR:
|
|
case WASM_INS_F64_TRUNC:
|
|
case WASM_INS_F64_NEAREST:
|
|
case WASM_INS_F64_SQRT:
|
|
case WASM_INS_F64_ADD:
|
|
case WASM_INS_F64_SUB:
|
|
case WASM_INS_F64_MUL:
|
|
case WASM_INS_F64_DIV:
|
|
case WASM_INS_F64_MIN:
|
|
case WASM_INS_F64_MAX:
|
|
case WASM_INS_F64_COPYSIGN:
|
|
case WASM_INS_I32_WARP_I64:
|
|
case WASP_INS_I32_TRUNC_S_F32:
|
|
case WASM_INS_I32_TRUNC_U_F32:
|
|
case WASM_INS_I32_TRUNC_S_F64:
|
|
case WASM_INS_I32_TRUNC_U_F64:
|
|
case WASM_INS_I64_EXTEND_S_I32:
|
|
case WASM_INS_I64_EXTEND_U_I32:
|
|
case WASM_INS_I64_TRUNC_S_F32:
|
|
case WASM_INS_I64_TRUNC_U_F32:
|
|
case WASM_INS_I64_TRUNC_S_F64:
|
|
case WASM_INS_I64_TRUNC_U_F64:
|
|
case WASM_INS_F32_CONVERT_S_I32:
|
|
case WASM_INS_F32_CONVERT_U_I32:
|
|
case WASM_INS_F32_CONVERT_S_I64:
|
|
case WASM_INS_F32_CONVERT_U_I64:
|
|
case WASM_INS_F32_DEMOTE_F64:
|
|
case WASM_INS_F64_CONVERT_S_I32:
|
|
case WASM_INS_F64_CONVERT_U_I32:
|
|
case WASM_INS_F64_CONVERT_S_I64:
|
|
case WASM_INS_F64_CONVERT_U_I64:
|
|
case WASM_INS_F64_PROMOTE_F32:
|
|
case WASM_INS_I32_REINTERPRET_F32:
|
|
case WASM_INS_I64_REINTERPRET_F64:
|
|
case WASM_INS_F32_REINTERPRET_I32:
|
|
case WASM_INS_F64_REINTERPRET_I64:
|
|
MI->wasm_data.type = WASM_OP_NONE;
|
|
|
|
if (MI->flat_insn->detail) {
|
|
MI->flat_insn->detail->wasm.op_count = 0;
|
|
MI->flat_insn->detail->groups[MI->flat_insn->detail->groups_count] = WASM_GRP_NUMBERIC;
|
|
MI->flat_insn->detail->groups_count++;
|
|
}
|
|
|
|
*size = 1;
|
|
|
|
break;
|
|
|
|
case WASM_INS_DROP:
|
|
case WASM_INS_SELECT:
|
|
MI->wasm_data.type = WASM_OP_NONE;
|
|
|
|
if (MI->flat_insn->detail) {
|
|
MI->flat_insn->detail->wasm.op_count = 0;
|
|
MI->flat_insn->detail->groups[MI->flat_insn->detail->groups_count] = WASM_GRP_PARAMETRIC;
|
|
MI->flat_insn->detail->groups_count++;
|
|
}
|
|
|
|
*size = 1;
|
|
|
|
break;
|
|
|
|
case WASM_INS_GET_LOCAL:
|
|
case WASM_INS_SET_LOCAL:
|
|
case WASM_INS_TEE_LOCAL:
|
|
case WASM_INS_GET_GLOBAL:
|
|
case WASM_INS_SET_GLOBAL:
|
|
if (code_len == 1 || !read_varuint32(&code[1], code_len - 1, ¶m_size, MI)) {
|
|
return false;
|
|
}
|
|
|
|
if (MI->flat_insn->detail) {
|
|
MI->flat_insn->detail->wasm.op_count = 1;
|
|
MI->flat_insn->detail->groups[MI->flat_insn->detail->groups_count] = WASM_GRP_VARIABLE;
|
|
MI->flat_insn->detail->groups_count++;
|
|
}
|
|
|
|
*size = param_size + 1;
|
|
|
|
break;
|
|
|
|
case WASM_INS_I32_LOAD:
|
|
case WASM_INS_I64_LOAD:
|
|
case WASM_INS_F32_LOAD:
|
|
case WASM_INS_F64_LOAD:
|
|
case WASM_INS_I32_LOAD8_S:
|
|
case WASM_INS_I32_LOAD8_U:
|
|
case WASM_INS_I32_LOAD16_S:
|
|
case WASM_INS_I32_LOAD16_U:
|
|
case WASM_INS_I64_LOAD8_S:
|
|
case WASM_INS_I64_LOAD8_U:
|
|
case WASM_INS_I64_LOAD16_S:
|
|
case WASM_INS_I64_LOAD16_U:
|
|
case WASM_INS_I64_LOAD32_S:
|
|
case WASM_INS_I64_LOAD32_U:
|
|
case WASM_INS_I32_STORE:
|
|
case WASM_INS_I64_STORE:
|
|
case WASM_INS_F32_STORE:
|
|
case WASM_INS_F64_STORE:
|
|
case WASM_INS_I32_STORE8:
|
|
case WASM_INS_I32_STORE16:
|
|
case WASM_INS_I64_STORE8:
|
|
case WASM_INS_I64_STORE16:
|
|
case WASM_INS_I64_STORE32:
|
|
if (code_len == 1 || !read_memoryimmediate(&code[1], code_len - 1, ¶m_size, MI)) {
|
|
return false;
|
|
}
|
|
|
|
if (MI->flat_insn->detail) {
|
|
MI->flat_insn->detail->wasm.op_count = 2;
|
|
MI->flat_insn->detail->groups[MI->flat_insn->detail->groups_count] = WASM_GRP_MEMORY;
|
|
MI->flat_insn->detail->groups_count++;
|
|
}
|
|
|
|
*size = param_size + 1;
|
|
|
|
break;
|
|
|
|
case WASM_INS_CURRENT_MEMORY:
|
|
case WASM_INS_GROW_MEMORY:
|
|
MI->wasm_data.type = WASM_OP_NONE;
|
|
|
|
if (MI->flat_insn->detail) {
|
|
MI->flat_insn->detail->wasm.op_count = 0;
|
|
MI->flat_insn->detail->groups[MI->flat_insn->detail->groups_count] = WASM_GRP_MEMORY;
|
|
MI->flat_insn->detail->groups_count++;
|
|
}
|
|
|
|
*size = 1;
|
|
|
|
break;
|
|
|
|
case WASM_INS_UNREACHABLE:
|
|
case WASM_INS_NOP:
|
|
case WASM_INS_ELSE:
|
|
case WASM_INS_END:
|
|
case WASM_INS_RETURN:
|
|
MI->wasm_data.type = WASM_OP_NONE;
|
|
|
|
if (MI->flat_insn->detail) {
|
|
MI->flat_insn->detail->wasm.op_count = 0;
|
|
MI->flat_insn->detail->groups[MI->flat_insn->detail->groups_count] = WASM_GRP_CONTROL;
|
|
MI->flat_insn->detail->groups_count++;
|
|
}
|
|
|
|
*size = 1;
|
|
|
|
break;
|
|
|
|
case WASM_INS_BLOCK:
|
|
case WASM_INS_LOOP:
|
|
case WASM_INS_IF:
|
|
if (code_len == 1 || !read_varint7(&code[1], code_len - 1, ¶m_size, MI)) {
|
|
return false;
|
|
}
|
|
|
|
if (MI->flat_insn->detail) {
|
|
MI->flat_insn->detail->wasm.op_count = 1;
|
|
MI->flat_insn->detail->groups[MI->flat_insn->detail->groups_count] = WASM_GRP_CONTROL;
|
|
MI->flat_insn->detail->groups_count++;
|
|
}
|
|
|
|
*size = param_size + 1;
|
|
|
|
break;
|
|
|
|
case WASM_INS_BR:
|
|
case WASM_INS_BR_IF:
|
|
case WASM_INS_CALL:
|
|
case WASM_INS_CALL_INDIRECT:
|
|
if (code_len == 1 || !read_varuint32(&code[1], code_len - 1, ¶m_size, MI)) {
|
|
return false;
|
|
}
|
|
|
|
if (MI->flat_insn->detail) {
|
|
MI->flat_insn->detail->wasm.op_count = 1;
|
|
MI->flat_insn->detail->groups[MI->flat_insn->detail->groups_count] = WASM_GRP_CONTROL;
|
|
MI->flat_insn->detail->groups_count++;
|
|
}
|
|
|
|
*size = param_size + 1;
|
|
|
|
break;
|
|
|
|
case WASM_INS_BR_TABLE:
|
|
if (code_len == 1 || !read_brtable(&code[1], code_len - 1, ¶m_size, MI)) {
|
|
return false;
|
|
}
|
|
|
|
if (MI->flat_insn->detail) {
|
|
MI->flat_insn->detail->wasm.op_count = 1;
|
|
MI->flat_insn->detail->groups[MI->flat_insn->detail->groups_count] = WASM_GRP_CONTROL;
|
|
MI->flat_insn->detail->groups_count++;
|
|
}
|
|
|
|
*size = param_size + 1;
|
|
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|