* Update Capstone and add m68k ColdFire support * Fix test 'core regs linux m68k' * Add M68K ColdFire integration coverage * Update Capstone v6 to version 6.0.0-Alpha9 * Refactor CPU mode detection to use case-insensitive string comparison * Update Capstone next revision to 3df6ff0
1493 lines
39 KiB
C
1493 lines
39 KiB
C
// SPDX-FileCopyrightText: 2015-2018 pancake <pancake@nopcode.org>
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
|
|
#include <rz_asm.h>
|
|
#include <rz_lib.h>
|
|
#include <capstone/capstone.h>
|
|
|
|
#ifdef CAPSTONE_M68K_H
|
|
#define CAPSTONE_HAS_M68K 1
|
|
#else
|
|
#define CAPSTONE_HAS_M68K 0
|
|
#ifdef _MSC_VER
|
|
#pragma message("Cannot find capstone-m68k support")
|
|
#else
|
|
#warning Cannot find capstone-m68k support
|
|
#endif
|
|
#endif
|
|
|
|
#if CAPSTONE_HAS_M68K
|
|
#include <capstone/m68k.h>
|
|
#include "m68k/m68k_cs.h"
|
|
// http://www.mrc.uidaho.edu/mrc/people/jff/digital/M68Kir.html
|
|
|
|
#define OPERAND(x) insn->detail->m68k.operands[x]
|
|
#define REG(x) cs_reg_name(*handle, insn->detail->m68k.operands[x].reg)
|
|
#define IMM(x) insn->detail->m68k.operands[x].imm
|
|
#define MEMBASE(x) cs_reg_name(*handle, insn->detail->m68k.operands[x].mem.base)
|
|
#define MEMINDEX(x) insn->detail->m68k.operands[x].mem.index
|
|
#define MEMDISP(x) insn->detail->m68k.operands[x].mem.disp
|
|
|
|
static inline ut64 make_64bits_address(ut64 address) {
|
|
return UT32_MAX & address;
|
|
}
|
|
|
|
static inline ut64 m68k_mem_operand_absolute_address(const cs_m68k_op *operand) {
|
|
if (!operand || operand->type != M68K_OP_MEM) {
|
|
return 0;
|
|
}
|
|
#ifdef RZ_CAPSTONE_HAS_M68K_COLDFIRE
|
|
return operand->mem.address;
|
|
#else
|
|
if (operand->imm) {
|
|
return operand->imm;
|
|
}
|
|
return (ut64)(st64)(operand->mem.disp + operand->mem.in_disp + operand->mem.out_disp);
|
|
#endif
|
|
}
|
|
|
|
static inline bool m68k_mem_operand_is_absolute(const cs_m68k_op *operand) {
|
|
if (!operand || operand->type != M68K_OP_MEM) {
|
|
return false;
|
|
}
|
|
switch (operand->address_mode) {
|
|
case M68K_AM_ABSOLUTE_DATA_SHORT:
|
|
case M68K_AM_ABSOLUTE_DATA_LONG:
|
|
return true;
|
|
default:
|
|
break;
|
|
}
|
|
return operand->mem.base_reg == M68K_REG_INVALID &&
|
|
operand->mem.index_reg == M68K_REG_INVALID &&
|
|
operand->mem.in_base_reg == M68K_REG_INVALID;
|
|
}
|
|
|
|
static inline void handle_branch_instruction(RzAnalysisOp *op, ut64 addr, cs_m68k *m68k, ut32 type, int index) {
|
|
if (m68k->operands[index].type == M68K_OP_BR_DISP) {
|
|
op->type = type;
|
|
// TODO: disp_size is ignored
|
|
op->jump = make_64bits_address(addr + m68k->operands[index].br_disp.disp + 2);
|
|
op->fail = make_64bits_address(addr + op->size);
|
|
}
|
|
}
|
|
|
|
static inline void handle_jump_instruction(RzAnalysisOp *op, ut64 addr, cs_m68k *m68k, ut32 type) {
|
|
if (!m68k || m68k->op_count < 1) {
|
|
op->type = type;
|
|
return;
|
|
}
|
|
|
|
const cs_m68k_op *operand = &m68k->operands[0];
|
|
// Handle PC relative mode jump
|
|
if (operand->address_mode == M68K_AM_PCI_DISP) {
|
|
op->type = type;
|
|
op->jump = make_64bits_address(addr + operand->mem.disp + 2);
|
|
} else if (operand->type == M68K_OP_IMM) {
|
|
op->type = type;
|
|
op->jump = make_64bits_address(operand->imm);
|
|
} else if (m68k_mem_operand_is_absolute(operand)) {
|
|
op->type = type;
|
|
op->jump = make_64bits_address(m68k_mem_operand_absolute_address(operand));
|
|
} else {
|
|
op->type = (type == RZ_ANALYSIS_OP_TYPE_CALL) ? RZ_ANALYSIS_OP_TYPE_ICALL : RZ_ANALYSIS_OP_TYPE_IJMP;
|
|
}
|
|
|
|
op->fail = make_64bits_address(addr + op->size);
|
|
}
|
|
|
|
static RzStructuredData *mk68_opex(csh handle, cs_insn *insn) {
|
|
if (!insn->detail) {
|
|
return NULL;
|
|
}
|
|
|
|
RzStructuredData *root = rz_structured_data_new_map();
|
|
if (!root) {
|
|
return NULL;
|
|
}
|
|
|
|
RzStructuredData *opex = rz_structured_data_map_add_map(root, "opex");
|
|
if (!opex) {
|
|
rz_structured_data_free(root);
|
|
return NULL;
|
|
}
|
|
|
|
RzStructuredData *operands = rz_structured_data_map_add_array(opex, "operands");
|
|
cs_m68k *x = &insn->detail->m68k;
|
|
for (st32 i = 0; i < x->op_count; i++) {
|
|
cs_m68k_op *op = &x->operands[i];
|
|
RzStructuredData *operand = rz_structured_data_array_add_map(operands);
|
|
#ifdef RZ_CAPSTONE_HAS_M68K_COLDFIRE
|
|
if (op->flags != M68K_OP_FLAG_NONE) {
|
|
rz_structured_data_map_add_unsigned(operand, "flags", op->flags, false);
|
|
}
|
|
#endif
|
|
switch (op->type) {
|
|
case M68K_OP_REG:
|
|
rz_structured_data_map_add_string(operand, "type", "reg");
|
|
rz_structured_data_map_add_string(operand, "value", cs_reg_name(handle, op->reg));
|
|
break;
|
|
case M68K_OP_REG_PAIR:
|
|
rz_structured_data_map_add_string(operand, "type", "reg_pair");
|
|
rz_structured_data_map_add_string(operand, "reg_0", cs_reg_name(handle, op->reg_pair.reg_0));
|
|
rz_structured_data_map_add_string(operand, "reg_1", cs_reg_name(handle, op->reg_pair.reg_1));
|
|
break;
|
|
case M68K_OP_IMM:
|
|
rz_structured_data_map_add_string(operand, "type", "imm");
|
|
rz_structured_data_map_add_signed(operand, "value", (st64)op->imm);
|
|
break;
|
|
case M68K_OP_FP_SINGLE:
|
|
rz_structured_data_map_add_string(operand, "type", "fp_single");
|
|
rz_structured_data_map_add_double(operand, "value", op->simm);
|
|
break;
|
|
case M68K_OP_FP_DOUBLE:
|
|
rz_structured_data_map_add_string(operand, "type", "fp_double");
|
|
rz_structured_data_map_add_double(operand, "value", op->dimm);
|
|
break;
|
|
case M68K_OP_REG_BITS:
|
|
rz_structured_data_map_add_string(operand, "type", "reg_bits");
|
|
rz_structured_data_map_add_unsigned(operand, "value", op->register_bits, true);
|
|
break;
|
|
case M68K_OP_BR_DISP:
|
|
rz_structured_data_map_add_string(operand, "type", "br_disp");
|
|
rz_structured_data_map_add_signed(operand, "disp", op->br_disp.disp);
|
|
rz_structured_data_map_add_unsigned(operand, "disp_size", op->br_disp.disp_size, false);
|
|
break;
|
|
#ifdef RZ_CAPSTONE_HAS_M68K_COLDFIRE
|
|
case M68K_OP_SHIFT:
|
|
rz_structured_data_map_add_string(operand, "type", "shift");
|
|
break;
|
|
#endif
|
|
case M68K_OP_MEM:
|
|
rz_structured_data_map_add_string(operand, "type", "mem");
|
|
rz_structured_data_map_add_unsigned(operand, "address_mode", op->address_mode, false);
|
|
if (op->mem.base_reg != M68K_REG_INVALID) {
|
|
rz_structured_data_map_add_string(operand, "base_reg", cs_reg_name(handle, op->mem.base_reg));
|
|
}
|
|
#ifdef RZ_CAPSTONE_HAS_M68K_COLDFIRE
|
|
if (m68k_mem_operand_is_absolute(op)) {
|
|
rz_structured_data_map_add_unsigned(operand, "address", op->mem.address, false);
|
|
}
|
|
#endif
|
|
if (op->mem.index_reg != M68K_REG_INVALID) {
|
|
rz_structured_data_map_add_string(operand, "index_reg", cs_reg_name(handle, op->mem.index_reg));
|
|
}
|
|
if (op->mem.in_base_reg != M68K_REG_INVALID) {
|
|
rz_structured_data_map_add_string(operand, "in_base_reg", cs_reg_name(handle, op->mem.in_base_reg));
|
|
}
|
|
rz_structured_data_map_add_signed(operand, "in_disp", op->mem.in_disp);
|
|
rz_structured_data_map_add_signed(operand, "out_disp", op->mem.out_disp);
|
|
rz_structured_data_map_add_signed(operand, "disp", op->mem.disp);
|
|
rz_structured_data_map_add_signed(operand, "scale", op->mem.scale);
|
|
rz_structured_data_map_add_signed(operand, "bitfield", op->mem.bitfield);
|
|
rz_structured_data_map_add_signed(operand, "width", op->mem.width);
|
|
rz_structured_data_map_add_signed(operand, "offset", op->mem.offset);
|
|
rz_structured_data_map_add_signed(operand, "index_size", op->mem.index_size);
|
|
#ifdef RZ_CAPSTONE_HAS_M68K_COLDFIRE
|
|
rz_structured_data_map_add_signed(operand, "in_disp_size", op->mem.in_disp_size);
|
|
rz_structured_data_map_add_signed(operand, "out_disp_size", op->mem.out_disp_size);
|
|
rz_structured_data_map_add_signed(operand, "disp_size", op->mem.disp_size);
|
|
#endif
|
|
break;
|
|
default:
|
|
rz_structured_data_map_add_string(operand, "type", "invalid");
|
|
break;
|
|
}
|
|
}
|
|
|
|
return root;
|
|
}
|
|
|
|
static inline int m68k_op_memref(const cs_m68k *m68k) {
|
|
if (!m68k) {
|
|
return 0;
|
|
}
|
|
switch (m68k->op_size.type) {
|
|
case M68K_SIZE_TYPE_CPU:
|
|
switch (m68k->op_size.cpu_size) {
|
|
case M68K_CPU_SIZE_BYTE:
|
|
return 1;
|
|
case M68K_CPU_SIZE_WORD:
|
|
return 2;
|
|
case M68K_CPU_SIZE_LONG:
|
|
return 4;
|
|
default:
|
|
return 0;
|
|
}
|
|
case M68K_SIZE_TYPE_FPU:
|
|
switch (m68k->op_size.fpu_size) {
|
|
case M68K_FPU_SIZE_SINGLE:
|
|
return 4;
|
|
case M68K_FPU_SIZE_DOUBLE:
|
|
return 8;
|
|
case M68K_FPU_SIZE_EXTENDED:
|
|
return 12;
|
|
default:
|
|
return 0;
|
|
}
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static inline RzRegItem *m68k_reg_get(RzAnalysis *a, csh handle, m68k_reg reg) {
|
|
if (!a || reg == M68K_REG_INVALID) {
|
|
return NULL;
|
|
}
|
|
const char *name = cs_reg_name(handle, reg);
|
|
return RZ_STR_ISNOTEMPTY(name) ? rz_reg_get(a->reg, name, RZ_REG_TYPE_ANY) : NULL;
|
|
}
|
|
|
|
static RzAnalysisValue *m68k_value_from_operand(RzAnalysis *a, csh handle, const cs_m68k_op *operand, int memref, RzAnalysisValueAccess access) {
|
|
if (!operand) {
|
|
return NULL;
|
|
}
|
|
|
|
RzAnalysisValue *value = rz_analysis_value_new();
|
|
if (!value) {
|
|
return NULL;
|
|
}
|
|
value->access = access;
|
|
|
|
switch (operand->type) {
|
|
case M68K_OP_REG:
|
|
value->type = RZ_ANALYSIS_VAL_REG;
|
|
value->reg = m68k_reg_get(a, handle, operand->reg);
|
|
if (!value->reg) {
|
|
rz_analysis_value_free(value);
|
|
return NULL;
|
|
}
|
|
break;
|
|
case M68K_OP_IMM:
|
|
value->type = RZ_ANALYSIS_VAL_IMM;
|
|
value->imm = (st64)operand->imm;
|
|
break;
|
|
case M68K_OP_BR_DISP:
|
|
value->type = RZ_ANALYSIS_VAL_IMM;
|
|
value->imm = operand->br_disp.disp;
|
|
break;
|
|
case M68K_OP_MEM:
|
|
value->type = RZ_ANALYSIS_VAL_MEM;
|
|
value->memref = memref;
|
|
value->reg = m68k_reg_get(a, handle, operand->mem.base_reg);
|
|
if (!value->reg) {
|
|
value->reg = m68k_reg_get(a, handle, operand->mem.in_base_reg);
|
|
}
|
|
value->regdelta = m68k_reg_get(a, handle, operand->mem.index_reg);
|
|
value->mul = operand->mem.scale;
|
|
value->delta = operand->mem.disp + operand->mem.in_disp + operand->mem.out_disp;
|
|
if (m68k_mem_operand_is_absolute(operand)) {
|
|
value->absolute = true;
|
|
value->base = m68k_mem_operand_absolute_address(operand);
|
|
value->delta = 0;
|
|
} else if (!value->reg && !value->regdelta && value->delta) {
|
|
value->absolute = true;
|
|
value->base = (ut64)value->delta;
|
|
value->delta = 0;
|
|
}
|
|
break;
|
|
case M68K_OP_REG_PAIR:
|
|
value->type = RZ_ANALYSIS_VAL_REG;
|
|
value->reg = m68k_reg_get(a, handle, operand->reg_pair.reg_0);
|
|
if (!value->reg) {
|
|
rz_analysis_value_free(value);
|
|
return NULL;
|
|
}
|
|
break;
|
|
default:
|
|
rz_analysis_value_free(value);
|
|
return NULL;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
static inline void m68k_note_memref(RzAnalysisOp *op, RzAnalysisValue *value) {
|
|
if (value && value->type == RZ_ANALYSIS_VAL_MEM && value->memref > 0) {
|
|
op->refptr = value->memref;
|
|
}
|
|
}
|
|
|
|
static bool m68k_add_src_value(RzAnalysisOp *op, RzAnalysisValue *value) {
|
|
if (!value) {
|
|
return false;
|
|
}
|
|
for (size_t i = 0; i < RZ_ARRAY_SIZE(op->src); i++) {
|
|
if (!op->src[i]) {
|
|
op->src[i] = value;
|
|
m68k_note_memref(op, value);
|
|
return true;
|
|
}
|
|
}
|
|
rz_analysis_value_free(value);
|
|
return false;
|
|
}
|
|
|
|
static void m68k_set_dst_value(RzAnalysisOp *op, RzAnalysisValue *value) {
|
|
if (!value) {
|
|
return;
|
|
}
|
|
if (op->dst) {
|
|
rz_analysis_value_free(op->dst);
|
|
}
|
|
op->dst = value;
|
|
m68k_note_memref(op, value);
|
|
}
|
|
|
|
static void m68k_add_src_operand(RzAnalysis *a, RzAnalysisOp *op, csh handle, const cs_m68k *m68k, int operand_index) {
|
|
if (!m68k || operand_index < 0 || operand_index >= m68k->op_count) {
|
|
return;
|
|
}
|
|
RzAnalysisValue *value = m68k_value_from_operand(a, handle, &m68k->operands[operand_index], m68k_op_memref(m68k), RZ_ANALYSIS_ACC_R);
|
|
m68k_add_src_value(op, value);
|
|
}
|
|
|
|
static void m68k_set_dst_operand(RzAnalysis *a, RzAnalysisOp *op, csh handle, const cs_m68k *m68k, int operand_index, RzAnalysisValueAccess access) {
|
|
if (!m68k || operand_index < 0 || operand_index >= m68k->op_count) {
|
|
return;
|
|
}
|
|
RzAnalysisValue *value = m68k_value_from_operand(a, handle, &m68k->operands[operand_index], m68k_op_memref(m68k), access);
|
|
m68k_set_dst_value(op, value);
|
|
}
|
|
|
|
static void m68k_fill_srcs_before_dst(RzAnalysis *a, RzAnalysisOp *op, csh handle, const cs_m68k *m68k, bool dst_is_read) {
|
|
if (!m68k || m68k->op_count < 1) {
|
|
return;
|
|
}
|
|
|
|
int dst_index = m68k->op_count - 1;
|
|
for (int i = 0; i < dst_index; i++) {
|
|
m68k_add_src_operand(a, op, handle, m68k, i);
|
|
}
|
|
m68k_set_dst_operand(a, op, handle, m68k, dst_index, dst_is_read ? (RZ_ANALYSIS_ACC_R | RZ_ANALYSIS_ACC_W) : RZ_ANALYSIS_ACC_W);
|
|
}
|
|
|
|
static void m68k_fill_all_srcs(RzAnalysis *a, RzAnalysisOp *op, csh handle, const cs_m68k *m68k) {
|
|
if (!m68k) {
|
|
return;
|
|
}
|
|
for (int i = 0; i < m68k->op_count; i++) {
|
|
m68k_add_src_operand(a, op, handle, m68k, i);
|
|
}
|
|
}
|
|
|
|
static void m68k_fill_unary_rw(RzAnalysis *a, RzAnalysisOp *op, csh handle, const cs_m68k *m68k) {
|
|
if (!m68k || m68k->op_count < 1) {
|
|
return;
|
|
}
|
|
m68k_set_dst_operand(a, op, handle, m68k, 0, RZ_ANALYSIS_ACC_R | RZ_ANALYSIS_ACC_W);
|
|
if (op->dst) {
|
|
RzAnalysisValue *src = rz_analysis_value_copy(op->dst);
|
|
if (src) {
|
|
src->access = RZ_ANALYSIS_ACC_R;
|
|
m68k_add_src_value(op, src);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void m68k_fill_clear(RzAnalysis *a, RzAnalysisOp *op, csh handle, const cs_m68k *m68k) {
|
|
if (!m68k || m68k->op_count < 1) {
|
|
return;
|
|
}
|
|
m68k_set_dst_operand(a, op, handle, m68k, 0, RZ_ANALYSIS_ACC_W);
|
|
RzAnalysisValue *src = rz_analysis_value_new();
|
|
if (src) {
|
|
src->type = RZ_ANALYSIS_VAL_IMM;
|
|
src->access = RZ_ANALYSIS_ACC_R;
|
|
src->imm = 0;
|
|
m68k_add_src_value(op, src);
|
|
}
|
|
}
|
|
|
|
static void m68k_fill_indirect_target(RzAnalysis *a, RzAnalysisOp *op, csh handle, const cs_m68k *m68k) {
|
|
if (!m68k || m68k->op_count < 1) {
|
|
return;
|
|
}
|
|
m68k_add_src_operand(a, op, handle, m68k, 0);
|
|
}
|
|
|
|
static void m68k_fill_fpu_unknown(RzAnalysis *a, RzAnalysisOp *op, csh handle, const cs_m68k *m68k) {
|
|
if (!m68k || m68k->op_count < 1) {
|
|
return;
|
|
}
|
|
if (m68k->op_count == 1) {
|
|
m68k_fill_unary_rw(a, op, handle, m68k);
|
|
} else {
|
|
m68k_fill_srcs_before_dst(a, op, handle, m68k, false);
|
|
}
|
|
}
|
|
|
|
static void m68k_set_move_type(RzAnalysisOp *op, const cs_m68k *m68k) {
|
|
if (!m68k || m68k->op_count < 2) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
return;
|
|
}
|
|
const cs_m68k_op *src = &m68k->operands[0];
|
|
const cs_m68k_op *dst = &m68k->operands[m68k->op_count - 1];
|
|
if (dst->type == M68K_OP_MEM) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_STORE;
|
|
} else if (src->type == M68K_OP_MEM) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_LOAD;
|
|
} else {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
}
|
|
}
|
|
|
|
static RZ_UNUSED void m68k_set_cast_type(RzAnalysisOp *op, const cs_m68k *m68k) {
|
|
if (!m68k || m68k->op_count < 2) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CAST;
|
|
return;
|
|
}
|
|
const cs_m68k_op *src = &m68k->operands[0];
|
|
const cs_m68k_op *dst = &m68k->operands[m68k->op_count - 1];
|
|
if (dst->type == M68K_OP_MEM) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_STORE;
|
|
} else if (src->type == M68K_OP_MEM) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_LOAD;
|
|
} else {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CAST;
|
|
}
|
|
}
|
|
|
|
static void m68k_set_opdir(RzAnalysisOp *op) {
|
|
switch (op->type & RZ_ANALYSIS_OP_TYPE_MASK) {
|
|
case RZ_ANALYSIS_OP_TYPE_LOAD:
|
|
op->direction = RZ_ANALYSIS_OP_DIR_READ;
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_STORE:
|
|
op->direction = RZ_ANALYSIS_OP_DIR_WRITE;
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_LEA:
|
|
op->direction = RZ_ANALYSIS_OP_DIR_REF;
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_JMP:
|
|
case RZ_ANALYSIS_OP_TYPE_CJMP:
|
|
case RZ_ANALYSIS_OP_TYPE_UJMP:
|
|
case RZ_ANALYSIS_OP_TYPE_CALL:
|
|
case RZ_ANALYSIS_OP_TYPE_UCALL:
|
|
op->direction = RZ_ANALYSIS_OP_DIR_EXEC;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void m68k_handle_fpu_instruction(RzAnalysisOp *op, ut64 addr, cs_m68k *m68k, unsigned int insn_id) {
|
|
op->family = RZ_ANALYSIS_OP_FAMILY_FPU;
|
|
switch (insn_id) {
|
|
case M68K_INS_FMOVE:
|
|
case M68K_INS_FSMOVE:
|
|
case M68K_INS_FDMOVE:
|
|
case M68K_INS_FMOVECR:
|
|
case M68K_INS_FMOVEM:
|
|
m68k_set_move_type(op, m68k);
|
|
break;
|
|
case M68K_INS_FADD:
|
|
case M68K_INS_FSADD:
|
|
case M68K_INS_FDADD:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
|
|
break;
|
|
case M68K_INS_FSUB:
|
|
case M68K_INS_FSSUB:
|
|
case M68K_INS_FDSUB:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SUB;
|
|
break;
|
|
case M68K_INS_FMUL:
|
|
case M68K_INS_FSMUL:
|
|
case M68K_INS_FDMUL:
|
|
case M68K_INS_FSGLMUL:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MUL;
|
|
break;
|
|
case M68K_INS_FDIV:
|
|
case M68K_INS_FSDIV:
|
|
case M68K_INS_FDDIV:
|
|
case M68K_INS_FSGLDIV:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_DIV;
|
|
break;
|
|
case M68K_INS_FMOD:
|
|
case M68K_INS_FREM:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOD;
|
|
break;
|
|
case M68K_INS_FCMP:
|
|
case M68K_INS_FTST:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CMP;
|
|
break;
|
|
case M68K_INS_FABS:
|
|
case M68K_INS_FSABS:
|
|
case M68K_INS_FDABS:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ABS;
|
|
break;
|
|
case M68K_INS_FNEG:
|
|
case M68K_INS_FSNEG:
|
|
case M68K_INS_FDNEG:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SUB;
|
|
break;
|
|
case M68K_INS_FINT:
|
|
case M68K_INS_FINTRZ:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CAST;
|
|
break;
|
|
case M68K_INS_FNOP:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_NOP;
|
|
break;
|
|
case M68K_INS_FSAVE:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_STORE;
|
|
break;
|
|
case M68K_INS_FRESTORE:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_LOAD;
|
|
break;
|
|
case M68K_INS_FSF:
|
|
case M68K_INS_FSBEQ:
|
|
case M68K_INS_FSOGT:
|
|
case M68K_INS_FSOGE:
|
|
case M68K_INS_FSOLT:
|
|
case M68K_INS_FSOLE:
|
|
case M68K_INS_FSOGL:
|
|
case M68K_INS_FSOR:
|
|
case M68K_INS_FSUN:
|
|
case M68K_INS_FSUEQ:
|
|
case M68K_INS_FSUGT:
|
|
case M68K_INS_FSUGE:
|
|
case M68K_INS_FSULT:
|
|
case M68K_INS_FSULE:
|
|
case M68K_INS_FSNE:
|
|
case M68K_INS_FST:
|
|
case M68K_INS_FSSF:
|
|
case M68K_INS_FSSEQ:
|
|
case M68K_INS_FSGT:
|
|
case M68K_INS_FSGE:
|
|
case M68K_INS_FSLT:
|
|
case M68K_INS_FSLE:
|
|
case M68K_INS_FSGL:
|
|
case M68K_INS_FSGLE:
|
|
case M68K_INS_FSNGLE:
|
|
case M68K_INS_FSNGL:
|
|
case M68K_INS_FSNLE:
|
|
case M68K_INS_FSNLT:
|
|
case M68K_INS_FSNGE:
|
|
case M68K_INS_FSNGT:
|
|
case M68K_INS_FSSNE:
|
|
case M68K_INS_FSST:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
break;
|
|
case M68K_INS_FTRAPF:
|
|
case M68K_INS_FTRAPEQ:
|
|
case M68K_INS_FTRAPOGT:
|
|
case M68K_INS_FTRAPOGE:
|
|
case M68K_INS_FTRAPOLT:
|
|
case M68K_INS_FTRAPOLE:
|
|
case M68K_INS_FTRAPOGL:
|
|
case M68K_INS_FTRAPOR:
|
|
case M68K_INS_FTRAPUN:
|
|
case M68K_INS_FTRAPUEQ:
|
|
case M68K_INS_FTRAPUGT:
|
|
case M68K_INS_FTRAPUGE:
|
|
case M68K_INS_FTRAPULT:
|
|
case M68K_INS_FTRAPULE:
|
|
case M68K_INS_FTRAPNE:
|
|
case M68K_INS_FTRAPT:
|
|
case M68K_INS_FTRAPSF:
|
|
case M68K_INS_FTRAPSEQ:
|
|
case M68K_INS_FTRAPGT:
|
|
case M68K_INS_FTRAPGE:
|
|
case M68K_INS_FTRAPLT:
|
|
case M68K_INS_FTRAPLE:
|
|
case M68K_INS_FTRAPGL:
|
|
case M68K_INS_FTRAPGLE:
|
|
case M68K_INS_FTRAPNGLE:
|
|
case M68K_INS_FTRAPNGL:
|
|
case M68K_INS_FTRAPNLE:
|
|
case M68K_INS_FTRAPNLT:
|
|
case M68K_INS_FTRAPNGE:
|
|
case M68K_INS_FTRAPNGT:
|
|
case M68K_INS_FTRAPSNE:
|
|
case M68K_INS_FTRAPST:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_TRAP;
|
|
break;
|
|
case M68K_INS_FBF:
|
|
case M68K_INS_FBEQ:
|
|
case M68K_INS_FBOGT:
|
|
case M68K_INS_FBOGE:
|
|
case M68K_INS_FBOLT:
|
|
case M68K_INS_FBOLE:
|
|
case M68K_INS_FBOGL:
|
|
case M68K_INS_FBOR:
|
|
case M68K_INS_FBUN:
|
|
case M68K_INS_FBUEQ:
|
|
case M68K_INS_FBUGT:
|
|
case M68K_INS_FBUGE:
|
|
case M68K_INS_FBULT:
|
|
case M68K_INS_FBULE:
|
|
case M68K_INS_FBNE:
|
|
case M68K_INS_FBT:
|
|
case M68K_INS_FBSF:
|
|
case M68K_INS_FBSEQ:
|
|
case M68K_INS_FBGT:
|
|
case M68K_INS_FBGE:
|
|
case M68K_INS_FBLT:
|
|
case M68K_INS_FBLE:
|
|
case M68K_INS_FBGL:
|
|
case M68K_INS_FBGLE:
|
|
case M68K_INS_FBNGLE:
|
|
case M68K_INS_FBNGL:
|
|
case M68K_INS_FBNLE:
|
|
case M68K_INS_FBNLT:
|
|
case M68K_INS_FBNGE:
|
|
case M68K_INS_FBNGT:
|
|
case M68K_INS_FBSNE:
|
|
case M68K_INS_FBST:
|
|
handle_branch_instruction(op, addr, m68k, RZ_ANALYSIS_OP_TYPE_CJMP, 0);
|
|
break;
|
|
case M68K_INS_FDBF:
|
|
case M68K_INS_FDBEQ:
|
|
case M68K_INS_FDBOGT:
|
|
case M68K_INS_FDBOGE:
|
|
case M68K_INS_FDBOLT:
|
|
case M68K_INS_FDBOLE:
|
|
case M68K_INS_FDBOGL:
|
|
case M68K_INS_FDBOR:
|
|
case M68K_INS_FDBUN:
|
|
case M68K_INS_FDBUEQ:
|
|
case M68K_INS_FDBUGT:
|
|
case M68K_INS_FDBUGE:
|
|
case M68K_INS_FDBULT:
|
|
case M68K_INS_FDBULE:
|
|
case M68K_INS_FDBNE:
|
|
case M68K_INS_FDBT:
|
|
case M68K_INS_FDBSF:
|
|
case M68K_INS_FDBSEQ:
|
|
case M68K_INS_FDBGT:
|
|
case M68K_INS_FDBGE:
|
|
case M68K_INS_FDBLT:
|
|
case M68K_INS_FDBLE:
|
|
case M68K_INS_FDBGL:
|
|
case M68K_INS_FDBGLE:
|
|
case M68K_INS_FDBNGLE:
|
|
case M68K_INS_FDBNGL:
|
|
case M68K_INS_FDBNLE:
|
|
case M68K_INS_FDBNLT:
|
|
case M68K_INS_FDBNGE:
|
|
case M68K_INS_FDBNGT:
|
|
case M68K_INS_FDBSNE:
|
|
case M68K_INS_FDBST:
|
|
handle_branch_instruction(op, addr, m68k, RZ_ANALYSIS_OP_TYPE_CJMP, 1);
|
|
break;
|
|
default:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_UNK;
|
|
break;
|
|
}
|
|
}
|
|
|
|
typedef struct {
|
|
csh handle;
|
|
int omode;
|
|
int obits;
|
|
} M68KContext;
|
|
|
|
static bool m68k_init(void **user) {
|
|
M68KContext *ctx = RZ_NEW0(M68KContext);
|
|
rz_return_val_if_fail(ctx, false);
|
|
ctx->handle = 0;
|
|
ctx->omode = -1;
|
|
ctx->obits = 32;
|
|
*user = ctx;
|
|
return true;
|
|
}
|
|
|
|
static void op_fillval(RzAnalysis *a, RzAnalysisOp *op, csh handle, cs_insn *insn) {
|
|
cs_m68k *m68k = &insn->detail->m68k;
|
|
switch (insn->id) {
|
|
case M68K_INS_CLR:
|
|
m68k_fill_clear(a, op, handle, m68k);
|
|
return;
|
|
case M68K_INS_NEG:
|
|
case M68K_INS_NEGX:
|
|
case M68K_INS_NOT:
|
|
case M68K_INS_SWAP:
|
|
case M68K_INS_EXT:
|
|
case M68K_INS_EXTB:
|
|
m68k_fill_unary_rw(a, op, handle, m68k);
|
|
return;
|
|
#ifdef RZ_CAPSTONE_HAS_M68K_COLDFIRE
|
|
case M68K_INS_BITREV:
|
|
case M68K_INS_BYTEREV:
|
|
case M68K_INS_FF1:
|
|
case M68K_INS_SATS:
|
|
m68k_fill_unary_rw(a, op, handle, m68k);
|
|
return;
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (op->type & RZ_ANALYSIS_OP_TYPE_MASK) {
|
|
case RZ_ANALYSIS_OP_TYPE_LOAD:
|
|
case RZ_ANALYSIS_OP_TYPE_MOV:
|
|
case RZ_ANALYSIS_OP_TYPE_STORE:
|
|
case RZ_ANALYSIS_OP_TYPE_CAST:
|
|
m68k_fill_srcs_before_dst(a, op, handle, m68k, false);
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_LEA:
|
|
if (m68k->op_count > 1) {
|
|
m68k_add_src_operand(a, op, handle, m68k, 0);
|
|
m68k_set_dst_operand(a, op, handle, m68k, m68k->op_count - 1, RZ_ANALYSIS_ACC_W);
|
|
} else {
|
|
m68k_fill_all_srcs(a, op, handle, m68k);
|
|
}
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_ADD:
|
|
case RZ_ANALYSIS_OP_TYPE_SUB:
|
|
case RZ_ANALYSIS_OP_TYPE_MUL:
|
|
case RZ_ANALYSIS_OP_TYPE_DIV:
|
|
case RZ_ANALYSIS_OP_TYPE_MOD:
|
|
case RZ_ANALYSIS_OP_TYPE_SHL:
|
|
case RZ_ANALYSIS_OP_TYPE_SHR:
|
|
case RZ_ANALYSIS_OP_TYPE_SAR:
|
|
case RZ_ANALYSIS_OP_TYPE_SAL:
|
|
case RZ_ANALYSIS_OP_TYPE_OR:
|
|
case RZ_ANALYSIS_OP_TYPE_AND:
|
|
case RZ_ANALYSIS_OP_TYPE_XOR:
|
|
case RZ_ANALYSIS_OP_TYPE_XCHG:
|
|
case RZ_ANALYSIS_OP_TYPE_ROR:
|
|
case RZ_ANALYSIS_OP_TYPE_ROL:
|
|
case RZ_ANALYSIS_OP_TYPE_ABS:
|
|
case RZ_ANALYSIS_OP_TYPE_BCNT:
|
|
case RZ_ANALYSIS_OP_TYPE_REV:
|
|
m68k_fill_srcs_before_dst(a, op, handle, m68k, true);
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_CMP:
|
|
m68k_fill_all_srcs(a, op, handle, m68k);
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_UJMP:
|
|
case RZ_ANALYSIS_OP_TYPE_UCALL:
|
|
m68k_fill_indirect_target(a, op, handle, m68k);
|
|
break;
|
|
default:
|
|
if (op->family == RZ_ANALYSIS_OP_FAMILY_FPU &&
|
|
(op->type & RZ_ANALYSIS_OP_TYPE_MASK) == RZ_ANALYSIS_OP_TYPE_UNK) {
|
|
m68k_fill_fpu_unknown(a, op, handle, m68k);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int m68k_analyze_op(RzAnalysis *a, RzAnalysisOp *op, ut64 addr, const ut8 *buf, int len, RzAnalysisOpMask mask) {
|
|
M68KContext *ctx = (M68KContext *)a->plugin_data;
|
|
int n, ret, opsize = -1;
|
|
cs_insn *insn;
|
|
cs_m68k *m68k;
|
|
cs_detail *detail;
|
|
|
|
cs_mode mode = rz_m68k_cs_mode(rz_analysis_get_cpu(a));
|
|
|
|
if (mode != ctx->omode || a->bits != ctx->obits) {
|
|
cs_close(&ctx->handle);
|
|
ctx->handle = 0;
|
|
ctx->omode = -1;
|
|
ctx->obits = a->bits;
|
|
}
|
|
op->size = 4;
|
|
if (ctx->handle == 0) {
|
|
ret = cs_open(CS_ARCH_M68K, mode, &ctx->handle);
|
|
if (ret != CS_ERR_OK) {
|
|
goto fin;
|
|
}
|
|
ctx->omode = mode;
|
|
cs_option(ctx->handle, CS_OPT_DETAIL, CS_OPT_ON);
|
|
}
|
|
n = cs_disasm(ctx->handle, (ut8 *)buf, len, addr, 1, &insn);
|
|
if (n < 1 || insn->size < 1) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ILL;
|
|
op->size = 2;
|
|
opsize = -1;
|
|
goto beach;
|
|
}
|
|
if (!memcmp(buf, "\xff\xff", RZ_MIN(len, 2))) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ILL;
|
|
op->size = 2;
|
|
opsize = -1;
|
|
goto beach;
|
|
}
|
|
detail = insn->detail;
|
|
m68k = &detail->m68k;
|
|
op->id = insn->id;
|
|
opsize = op->size = insn->size;
|
|
if (mask & RZ_ANALYSIS_OP_MASK_OPEX) {
|
|
op->opex = mk68_opex(ctx->handle, insn);
|
|
}
|
|
switch (insn->id) {
|
|
case M68K_INS_INVALID:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ILL;
|
|
break;
|
|
case M68K_INS_ADD:
|
|
case M68K_INS_ADDA:
|
|
case M68K_INS_ADDI:
|
|
case M68K_INS_ADDQ:
|
|
case M68K_INS_ADDX:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
|
|
break;
|
|
case M68K_INS_AND:
|
|
case M68K_INS_ANDI:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_AND;
|
|
break;
|
|
case M68K_INS_ASL:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SHL;
|
|
break;
|
|
case M68K_INS_ASR:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SHR;
|
|
break;
|
|
case M68K_INS_ABCD:
|
|
break;
|
|
case M68K_INS_BHS:
|
|
case M68K_INS_BLO:
|
|
case M68K_INS_BHI:
|
|
case M68K_INS_BLS:
|
|
case M68K_INS_BCC:
|
|
case M68K_INS_BCS:
|
|
case M68K_INS_BNE:
|
|
case M68K_INS_BEQ:
|
|
case M68K_INS_BVC:
|
|
case M68K_INS_BVS:
|
|
case M68K_INS_BPL:
|
|
case M68K_INS_BMI:
|
|
case M68K_INS_BGE:
|
|
case M68K_INS_BLT:
|
|
case M68K_INS_BGT:
|
|
case M68K_INS_BLE:
|
|
handle_branch_instruction(op, addr, m68k, RZ_ANALYSIS_OP_TYPE_CJMP, 0);
|
|
break;
|
|
case M68K_INS_BRA:
|
|
handle_branch_instruction(op, addr, m68k, RZ_ANALYSIS_OP_TYPE_JMP, 0);
|
|
break;
|
|
case M68K_INS_BSR:
|
|
handle_branch_instruction(op, addr, m68k, RZ_ANALYSIS_OP_TYPE_CALL, 0);
|
|
break;
|
|
case M68K_INS_BCHG:
|
|
case M68K_INS_BCLR:
|
|
case M68K_INS_BSET:
|
|
case M68K_INS_BTST:
|
|
case M68K_INS_BFCHG:
|
|
case M68K_INS_BFCLR:
|
|
case M68K_INS_BFEXTS:
|
|
case M68K_INS_BFEXTU:
|
|
case M68K_INS_BFFFO:
|
|
case M68K_INS_BFINS:
|
|
case M68K_INS_BFSET:
|
|
case M68K_INS_BFTST:
|
|
case M68K_INS_BKPT:
|
|
case M68K_INS_CALLM:
|
|
case M68K_INS_CAS:
|
|
case M68K_INS_CAS2:
|
|
case M68K_INS_CHK:
|
|
case M68K_INS_CHK2:
|
|
// TODO:
|
|
break;
|
|
case M68K_INS_CLR:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
break;
|
|
case M68K_INS_CMP:
|
|
case M68K_INS_CMPA:
|
|
case M68K_INS_CMPI:
|
|
case M68K_INS_CMPM:
|
|
case M68K_INS_CMP2:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CMP;
|
|
break;
|
|
case M68K_INS_CINVL:
|
|
case M68K_INS_CINVP:
|
|
case M68K_INS_CINVA:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ILL;
|
|
break;
|
|
case M68K_INS_CPUSHL:
|
|
case M68K_INS_CPUSHP:
|
|
case M68K_INS_CPUSHA:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SYNC;
|
|
break;
|
|
case M68K_INS_DBT:
|
|
case M68K_INS_DBF:
|
|
case M68K_INS_DBHI:
|
|
case M68K_INS_DBLS:
|
|
case M68K_INS_DBCC:
|
|
case M68K_INS_DBCS:
|
|
case M68K_INS_DBNE:
|
|
case M68K_INS_DBEQ:
|
|
case M68K_INS_DBVC:
|
|
case M68K_INS_DBVS:
|
|
case M68K_INS_DBPL:
|
|
case M68K_INS_DBMI:
|
|
case M68K_INS_DBGE:
|
|
case M68K_INS_DBLT:
|
|
case M68K_INS_DBGT:
|
|
case M68K_INS_DBLE:
|
|
case M68K_INS_DBRA:
|
|
handle_branch_instruction(op, addr, m68k, RZ_ANALYSIS_OP_TYPE_CJMP, 1);
|
|
break;
|
|
case M68K_INS_DIVS:
|
|
case M68K_INS_DIVSL:
|
|
case M68K_INS_DIVU:
|
|
case M68K_INS_DIVUL:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_DIV;
|
|
break;
|
|
case M68K_INS_EOR:
|
|
case M68K_INS_EORI:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_XOR;
|
|
break;
|
|
case M68K_INS_EXG:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_XCHG;
|
|
break;
|
|
case M68K_INS_EXT:
|
|
case M68K_INS_EXTB:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CAST;
|
|
break;
|
|
case M68K_INS_FABS:
|
|
case M68K_INS_FSABS:
|
|
case M68K_INS_FDABS:
|
|
case M68K_INS_FACOS:
|
|
case M68K_INS_FADD:
|
|
case M68K_INS_FSADD:
|
|
case M68K_INS_FDADD:
|
|
case M68K_INS_FASIN:
|
|
case M68K_INS_FATAN:
|
|
case M68K_INS_FATANH:
|
|
case M68K_INS_FBF:
|
|
case M68K_INS_FBEQ:
|
|
case M68K_INS_FBOGT:
|
|
case M68K_INS_FBOGE:
|
|
case M68K_INS_FBOLT:
|
|
case M68K_INS_FBOLE:
|
|
case M68K_INS_FBOGL:
|
|
case M68K_INS_FBOR:
|
|
case M68K_INS_FBUN:
|
|
case M68K_INS_FBUEQ:
|
|
case M68K_INS_FBUGT:
|
|
case M68K_INS_FBUGE:
|
|
case M68K_INS_FBULT:
|
|
case M68K_INS_FBULE:
|
|
case M68K_INS_FBNE:
|
|
case M68K_INS_FBT:
|
|
case M68K_INS_FBSF:
|
|
case M68K_INS_FBSEQ:
|
|
case M68K_INS_FBGT:
|
|
case M68K_INS_FBGE:
|
|
case M68K_INS_FBLT:
|
|
case M68K_INS_FBLE:
|
|
case M68K_INS_FBGL:
|
|
case M68K_INS_FBGLE:
|
|
case M68K_INS_FBNGLE:
|
|
case M68K_INS_FBNGL:
|
|
case M68K_INS_FBNLE:
|
|
case M68K_INS_FBNLT:
|
|
case M68K_INS_FBNGE:
|
|
case M68K_INS_FBNGT:
|
|
case M68K_INS_FBSNE:
|
|
case M68K_INS_FBST:
|
|
case M68K_INS_FCMP:
|
|
case M68K_INS_FCOS:
|
|
case M68K_INS_FCOSH:
|
|
case M68K_INS_FDBF:
|
|
case M68K_INS_FDBEQ:
|
|
case M68K_INS_FDBOGT:
|
|
case M68K_INS_FDBOGE:
|
|
case M68K_INS_FDBOLT:
|
|
case M68K_INS_FDBOLE:
|
|
case M68K_INS_FDBOGL:
|
|
case M68K_INS_FDBOR:
|
|
case M68K_INS_FDBUN:
|
|
case M68K_INS_FDBUEQ:
|
|
case M68K_INS_FDBUGT:
|
|
case M68K_INS_FDBUGE:
|
|
case M68K_INS_FDBULT:
|
|
case M68K_INS_FDBULE:
|
|
case M68K_INS_FDBNE:
|
|
case M68K_INS_FDBT:
|
|
case M68K_INS_FDBSF:
|
|
case M68K_INS_FDBSEQ:
|
|
case M68K_INS_FDBGT:
|
|
case M68K_INS_FDBGE:
|
|
case M68K_INS_FDBLT:
|
|
case M68K_INS_FDBLE:
|
|
case M68K_INS_FDBGL:
|
|
case M68K_INS_FDBGLE:
|
|
case M68K_INS_FDBNGLE:
|
|
case M68K_INS_FDBNGL:
|
|
case M68K_INS_FDBNLE:
|
|
case M68K_INS_FDBNLT:
|
|
case M68K_INS_FDBNGE:
|
|
case M68K_INS_FDBNGT:
|
|
case M68K_INS_FDBSNE:
|
|
case M68K_INS_FDBST:
|
|
case M68K_INS_FDIV:
|
|
case M68K_INS_FSDIV:
|
|
case M68K_INS_FDDIV:
|
|
case M68K_INS_FETOX:
|
|
case M68K_INS_FETOXM1:
|
|
case M68K_INS_FGETEXP:
|
|
case M68K_INS_FGETMAN:
|
|
case M68K_INS_FINT:
|
|
case M68K_INS_FINTRZ:
|
|
case M68K_INS_FLOG10:
|
|
case M68K_INS_FLOG2:
|
|
case M68K_INS_FLOGN:
|
|
case M68K_INS_FLOGNP1:
|
|
case M68K_INS_FMOD:
|
|
case M68K_INS_FMOVE:
|
|
case M68K_INS_FSMOVE:
|
|
case M68K_INS_FDMOVE:
|
|
case M68K_INS_FMOVECR:
|
|
case M68K_INS_FMOVEM:
|
|
case M68K_INS_FMUL:
|
|
case M68K_INS_FSMUL:
|
|
case M68K_INS_FDMUL:
|
|
case M68K_INS_FNEG:
|
|
case M68K_INS_FSNEG:
|
|
case M68K_INS_FDNEG:
|
|
case M68K_INS_FNOP:
|
|
case M68K_INS_FREM:
|
|
case M68K_INS_FRESTORE:
|
|
case M68K_INS_FSAVE:
|
|
case M68K_INS_FSCALE:
|
|
case M68K_INS_FSGLDIV:
|
|
case M68K_INS_FSGLMUL:
|
|
case M68K_INS_FSIN:
|
|
case M68K_INS_FSINCOS:
|
|
case M68K_INS_FSINH:
|
|
case M68K_INS_FSQRT:
|
|
case M68K_INS_FSSQRT:
|
|
case M68K_INS_FDSQRT:
|
|
case M68K_INS_FSF:
|
|
case M68K_INS_FSBEQ:
|
|
case M68K_INS_FSOGT:
|
|
case M68K_INS_FSOGE:
|
|
case M68K_INS_FSOLT:
|
|
case M68K_INS_FSOLE:
|
|
case M68K_INS_FSOGL:
|
|
case M68K_INS_FSOR:
|
|
case M68K_INS_FSUN:
|
|
case M68K_INS_FSUEQ:
|
|
case M68K_INS_FSUGT:
|
|
case M68K_INS_FSUGE:
|
|
case M68K_INS_FSULT:
|
|
case M68K_INS_FSULE:
|
|
case M68K_INS_FSNE:
|
|
case M68K_INS_FST:
|
|
case M68K_INS_FSSF:
|
|
case M68K_INS_FSSEQ:
|
|
case M68K_INS_FSGT:
|
|
case M68K_INS_FSGE:
|
|
case M68K_INS_FSLT:
|
|
case M68K_INS_FSLE:
|
|
case M68K_INS_FSGL:
|
|
case M68K_INS_FSGLE:
|
|
case M68K_INS_FSNGLE:
|
|
case M68K_INS_FSNGL:
|
|
case M68K_INS_FSNLE:
|
|
case M68K_INS_FSNLT:
|
|
case M68K_INS_FSNGE:
|
|
case M68K_INS_FSNGT:
|
|
case M68K_INS_FSSNE:
|
|
case M68K_INS_FSST:
|
|
case M68K_INS_FSUB:
|
|
case M68K_INS_FSSUB:
|
|
case M68K_INS_FDSUB:
|
|
case M68K_INS_FTAN:
|
|
case M68K_INS_FTANH:
|
|
case M68K_INS_FTENTOX:
|
|
case M68K_INS_FTRAPF:
|
|
case M68K_INS_FTRAPEQ:
|
|
case M68K_INS_FTRAPOGT:
|
|
case M68K_INS_FTRAPOGE:
|
|
case M68K_INS_FTRAPOLT:
|
|
case M68K_INS_FTRAPOLE:
|
|
case M68K_INS_FTRAPOGL:
|
|
case M68K_INS_FTRAPOR:
|
|
case M68K_INS_FTRAPUN:
|
|
case M68K_INS_FTRAPUEQ:
|
|
case M68K_INS_FTRAPUGT:
|
|
case M68K_INS_FTRAPUGE:
|
|
case M68K_INS_FTRAPULT:
|
|
case M68K_INS_FTRAPULE:
|
|
case M68K_INS_FTRAPNE:
|
|
case M68K_INS_FTRAPT:
|
|
case M68K_INS_FTRAPSF:
|
|
case M68K_INS_FTRAPSEQ:
|
|
case M68K_INS_FTRAPGT:
|
|
case M68K_INS_FTRAPGE:
|
|
case M68K_INS_FTRAPLT:
|
|
case M68K_INS_FTRAPLE:
|
|
case M68K_INS_FTRAPGL:
|
|
case M68K_INS_FTRAPGLE:
|
|
case M68K_INS_FTRAPNGLE:
|
|
case M68K_INS_FTRAPNGL:
|
|
case M68K_INS_FTRAPNLE:
|
|
case M68K_INS_FTRAPNLT:
|
|
case M68K_INS_FTRAPNGE:
|
|
case M68K_INS_FTRAPNGT:
|
|
case M68K_INS_FTRAPSNE:
|
|
case M68K_INS_FTRAPST:
|
|
case M68K_INS_FTST:
|
|
case M68K_INS_FTWOTOX:
|
|
m68k_handle_fpu_instruction(op, addr, m68k, insn->id);
|
|
break;
|
|
case M68K_INS_HALT:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_NOP;
|
|
break;
|
|
case M68K_INS_ILLEGAL:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ILL;
|
|
break;
|
|
case M68K_INS_JMP:
|
|
handle_jump_instruction(op, addr, m68k, RZ_ANALYSIS_OP_TYPE_JMP);
|
|
break;
|
|
case M68K_INS_JSR:
|
|
handle_jump_instruction(op, addr, m68k, RZ_ANALYSIS_OP_TYPE_CALL);
|
|
break;
|
|
case M68K_INS_LPSTOP:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_NOP;
|
|
break;
|
|
case M68K_INS_LSL:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SHL;
|
|
break;
|
|
case M68K_INS_LINK:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_PUSH;
|
|
op->stackop = RZ_ANALYSIS_STACK_INC;
|
|
op->stackptr = -(st16)IMM(1);
|
|
break;
|
|
case M68K_INS_LSR:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SHR;
|
|
break;
|
|
case M68K_INS_PEA:
|
|
case M68K_INS_LEA:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_LEA;
|
|
break;
|
|
case M68K_INS_MOVE:
|
|
case M68K_INS_MOVEA:
|
|
case M68K_INS_MOVEC:
|
|
case M68K_INS_MOVEM:
|
|
case M68K_INS_MOVEP:
|
|
case M68K_INS_MOVEQ:
|
|
case M68K_INS_MOVES:
|
|
case M68K_INS_MOVE16:
|
|
m68k_set_move_type(op, m68k);
|
|
break;
|
|
#ifdef RZ_CAPSTONE_HAS_M68K_COLDFIRE
|
|
case M68K_INS_MOV3Q:
|
|
case M68K_INS_MOVCLR:
|
|
m68k_set_move_type(op, m68k);
|
|
break;
|
|
case M68K_INS_MVS:
|
|
op->sign = true;
|
|
m68k_set_cast_type(op, m68k);
|
|
break;
|
|
case M68K_INS_MVZ:
|
|
op->sign = false;
|
|
m68k_set_cast_type(op, m68k);
|
|
break;
|
|
case M68K_INS_MAC:
|
|
case M68K_INS_MSAC:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MUL;
|
|
break;
|
|
case M68K_INS_SATS:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CAST;
|
|
break;
|
|
case M68K_INS_BITREV:
|
|
case M68K_INS_BYTEREV:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_REV;
|
|
break;
|
|
case M68K_INS_FF1:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_BCNT;
|
|
break;
|
|
case M68K_INS_INTOUCH:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SYNC;
|
|
break;
|
|
case M68K_INS_STRLDSR:
|
|
case M68K_INS_WDDATA:
|
|
case M68K_INS_WDEBUG:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
break;
|
|
case M68K_INS_TBLS:
|
|
case M68K_INS_TBLU:
|
|
case M68K_INS_TBLSN:
|
|
case M68K_INS_TBLUN:
|
|
m68k_set_move_type(op, m68k);
|
|
break;
|
|
case M68K_INS_BGND:
|
|
case M68K_INS_TPF:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_TRAP;
|
|
break;
|
|
case M68K_INS_CP0BCBUSY:
|
|
case M68K_INS_CP1BCBUSY:
|
|
handle_branch_instruction(op, addr, m68k, RZ_ANALYSIS_OP_TYPE_CJMP, 0);
|
|
break;
|
|
case M68K_INS_CP0LD:
|
|
case M68K_INS_CP1LD:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_LOAD;
|
|
break;
|
|
case M68K_INS_CP0ST:
|
|
case M68K_INS_CP1ST:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_STORE;
|
|
break;
|
|
case M68K_INS_CP0NOP:
|
|
case M68K_INS_CP1NOP:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_NOP;
|
|
break;
|
|
#endif
|
|
case M68K_INS_MULS:
|
|
case M68K_INS_MULU:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MUL;
|
|
break;
|
|
case M68K_INS_NBCD:
|
|
case M68K_INS_NEG:
|
|
case M68K_INS_NEGX:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SUB;
|
|
break;
|
|
case M68K_INS_NOP:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_NOP;
|
|
break;
|
|
case M68K_INS_NOT:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_NOT;
|
|
break;
|
|
case M68K_INS_OR:
|
|
case M68K_INS_ORI:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_OR;
|
|
break;
|
|
case M68K_INS_PACK:
|
|
case M68K_INS_PFLUSH:
|
|
case M68K_INS_PFLUSHA:
|
|
case M68K_INS_PFLUSHAN:
|
|
case M68K_INS_PFLUSHN:
|
|
case M68K_INS_PLOADR:
|
|
case M68K_INS_PLOADW:
|
|
case M68K_INS_PLPAR:
|
|
case M68K_INS_PLPAW:
|
|
case M68K_INS_PMOVE:
|
|
case M68K_INS_PMOVEFD:
|
|
case M68K_INS_PTESTR:
|
|
case M68K_INS_PTESTW:
|
|
case M68K_INS_PULSE:
|
|
case M68K_INS_RESET:
|
|
break;
|
|
case M68K_INS_REMS:
|
|
case M68K_INS_REMU:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOD;
|
|
break;
|
|
case M68K_INS_ROL:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ROL;
|
|
break;
|
|
case M68K_INS_ROR:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ROR;
|
|
break;
|
|
case M68K_INS_ROXL:
|
|
case M68K_INS_ROXR:
|
|
break;
|
|
case M68K_INS_RTD:
|
|
case M68K_INS_RTE:
|
|
case M68K_INS_RTM:
|
|
case M68K_INS_RTR:
|
|
case M68K_INS_RTS:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_RET;
|
|
break;
|
|
case M68K_INS_SBCD:
|
|
case M68K_INS_ST:
|
|
case M68K_INS_SF:
|
|
case M68K_INS_SHI:
|
|
case M68K_INS_SLS:
|
|
case M68K_INS_SCC:
|
|
case M68K_INS_SHS:
|
|
case M68K_INS_SCS:
|
|
case M68K_INS_SLO:
|
|
case M68K_INS_SNE:
|
|
case M68K_INS_SEQ:
|
|
case M68K_INS_SVC:
|
|
case M68K_INS_SVS:
|
|
case M68K_INS_SPL:
|
|
case M68K_INS_SMI:
|
|
case M68K_INS_SGE:
|
|
case M68K_INS_SLT:
|
|
case M68K_INS_SGT:
|
|
case M68K_INS_SLE:
|
|
case M68K_INS_STOP:
|
|
break;
|
|
case M68K_INS_SUB:
|
|
case M68K_INS_SUBA:
|
|
case M68K_INS_SUBI:
|
|
case M68K_INS_SUBQ:
|
|
case M68K_INS_SUBX:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SUB;
|
|
break;
|
|
case M68K_INS_SWAP:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
break;
|
|
case M68K_INS_TAS:
|
|
break;
|
|
case M68K_INS_TRAP:
|
|
case M68K_INS_TRAPV:
|
|
case M68K_INS_TRAPT:
|
|
case M68K_INS_TRAPF:
|
|
case M68K_INS_TRAPHI:
|
|
case M68K_INS_TRAPLS:
|
|
case M68K_INS_TRAPCC:
|
|
case M68K_INS_TRAPHS:
|
|
case M68K_INS_TRAPCS:
|
|
case M68K_INS_TRAPLO:
|
|
case M68K_INS_TRAPNE:
|
|
case M68K_INS_TRAPEQ:
|
|
case M68K_INS_TRAPVC:
|
|
case M68K_INS_TRAPVS:
|
|
case M68K_INS_TRAPPL:
|
|
case M68K_INS_TRAPMI:
|
|
case M68K_INS_TRAPGE:
|
|
case M68K_INS_TRAPLT:
|
|
case M68K_INS_TRAPGT:
|
|
case M68K_INS_TRAPLE:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_TRAP;
|
|
break;
|
|
case M68K_INS_TST:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CMP;
|
|
break;
|
|
case M68K_INS_UNPK: // unpack BCD
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
break;
|
|
case M68K_INS_UNLK:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_POP;
|
|
// reset stackframe
|
|
op->stackop = RZ_ANALYSIS_STACK_SET;
|
|
op->stackptr = 0;
|
|
break;
|
|
}
|
|
m68k_set_opdir(op);
|
|
if (mask & RZ_ANALYSIS_OP_MASK_VAL) {
|
|
op_fillval(a, op, ctx->handle, insn);
|
|
}
|
|
beach:
|
|
cs_free(insn, n);
|
|
// cs_close (&handle);
|
|
fin:
|
|
return opsize;
|
|
}
|
|
|
|
static char *m68k_get_reg_profile(RzAnalysis *analysis) {
|
|
// The GPR offsets follow Linux/m68k struct user_regs_struct, which is also
|
|
// the ELF core PRSTATUS regset layout.
|
|
// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/m68k/include/asm/user.h
|
|
const char *p =
|
|
"=PC pc\n"
|
|
"=SP a7\n"
|
|
"=BP a6\n"
|
|
"=A0 a0\n"
|
|
"=A1 a1\n"
|
|
"=A2 a2\n"
|
|
"=A3 a3\n"
|
|
"gpr d0 .32 56 0\n"
|
|
"gpr d1 .32 0 0\n"
|
|
"gpr d2 .32 4 0\n"
|
|
"gpr d3 .32 8 0\n"
|
|
"gpr d4 .32 12 0\n"
|
|
"gpr d5 .32 16 0\n"
|
|
"gpr d6 .32 20 0\n"
|
|
"gpr d7 .32 24 0\n"
|
|
"gpr a0 .32 28 0\n"
|
|
"gpr a1 .32 32 0\n"
|
|
"gpr a2 .32 36 0\n"
|
|
"gpr a3 .32 40 0\n"
|
|
"gpr a4 .32 44 0\n"
|
|
"gpr a5 .32 48 0\n"
|
|
"gpr a6 .32 52 0\n"
|
|
"gpr a7 .32 60 0\n"
|
|
"gpr pc .32 72 0\n"
|
|
"gpr ccr .8 71 0\n" // subset of the SR, available from any mode
|
|
"gpr fp0 .32 80 0\n" // FPU register 0, 96bits to write and read max
|
|
"gpr fp1 .32 84 0\n" // FPU register 1, 96bits to write and read max
|
|
"gpr fp2 .32 88 0\n" // FPU register 2, 96bits to write and read max
|
|
"gpr fp3 .32 92 0\n" // FPU register 3, 96bits to write and read max
|
|
"gpr fp4 .32 96 0\n" // FPU register 4, 96bits to write and read max
|
|
"gpr fp5 .32 100 0\n" // FPU register 5, 96bits to write and read max
|
|
"gpr fp6 .32 104 0\n" // FPU register 6, 96bits to write and read max
|
|
"gpr fp7 .32 108 0\n" // FPU register 7, 96bits to write and read max
|
|
"gpr fpcr .32 112 0\n"
|
|
"gpr fpsr .32 116 0\n"
|
|
"gpr fpiar .32 120 0\n"
|
|
"gpr sr .16 70 0\n" // only available for read and write access during supervisor mode
|
|
"gpr sfc .32 124 0\n" // source function code register
|
|
"gpr dfc .32 128 0\n" // destination function code register
|
|
"gpr usp .32 60 0\n" // user stack point this is an shadow register of A7 user mode, SR bit 0xD is 0
|
|
"gpr vbr .32 132 0\n" // vector base register, this is a Address pointer
|
|
"gpr cacr .32 136 0\n" // cache control register, implementation specific
|
|
"gpr caar .32 140 0\n" // cache address register, 68020, 68EC020, 68030 and 68EC030 only.
|
|
"gpr msp .32 144 0\n" // master stack pointer, this is an shadow register of A7 supervisor mode, SR bits 0xD && 0xC are set
|
|
"gpr isp .32 148 0\n" // interrupt stack pointer, this is an shadow register of A7 supervisor mode, SR bit 0xD is set, 0xC is not.
|
|
"gpr tc .32 152 0\n"
|
|
"gpr itt0 .32 156 0\n" // in 68EC040 this is IACR0
|
|
"gpr itt1 .32 160 0\n" // in 68EC040 this is IACR1
|
|
"gpr dtt0 .32 164 0\n" // in 68EC040 this is DACR0
|
|
"gpr dtt1 .32 168 0\n" // in 68EC040 this is DACR1
|
|
"gpr mmusr .32 172 0\n"
|
|
"gpr urp .32 176 0\n"
|
|
"gpr srp .32 180 0\n"
|
|
"gpr tt0 .32 184 0\n"
|
|
"gpr tt1 .32 188 0\n"
|
|
"gpr crp .32 192 0\n"
|
|
"gpr acc .32 196 0\n"
|
|
"gpr acc0 .32 200 0\n"
|
|
"gpr acc1 .32 204 0\n"
|
|
"gpr acc2 .32 208 0\n"
|
|
"gpr acc3 .32 212 0\n"
|
|
"gpr accext01 .32 216 0\n"
|
|
"gpr accext23 .32 220 0\n"
|
|
"gpr macsr .32 224 0\n"
|
|
"gpr mask .32 228 0\n";
|
|
return rz_str_dup(p);
|
|
}
|
|
|
|
static bool m68k_fini(void *user) {
|
|
M68KContext *ctx = (M68KContext *)user;
|
|
if (ctx) {
|
|
cs_close(&ctx->handle);
|
|
free(ctx);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static int m68k_archinfo(RzAnalysis *a, RzAnalysisInfoType query) {
|
|
switch (query) {
|
|
case RZ_ANALYSIS_ARCHINFO_MIN_OP_SIZE:
|
|
return 2;
|
|
case RZ_ANALYSIS_ARCHINFO_MAX_OP_SIZE:
|
|
return M68K_LONGEST_INSTRUCTION;
|
|
case RZ_ANALYSIS_ARCHINFO_TEXT_ALIGN:
|
|
return 2;
|
|
case RZ_ANALYSIS_ARCHINFO_DATA_ALIGN:
|
|
return 1;
|
|
case RZ_ANALYSIS_ARCHINFO_CAN_USE_POINTERS:
|
|
return true;
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
RzAnalysisPlugin rz_analysis_plugin_m68k_cs = {
|
|
.name = "m68k",
|
|
.desc = "Capstone M68K analyzer",
|
|
.license = "BSD",
|
|
.esil = false,
|
|
.arch = "m68k",
|
|
.get_reg_profile = &m68k_get_reg_profile,
|
|
.bits = 32,
|
|
.op = &m68k_analyze_op,
|
|
.init = m68k_init,
|
|
.fini = m68k_fini,
|
|
.archinfo = m68k_archinfo,
|
|
};
|
|
|
|
#else
|
|
RzAnalysisPlugin rz_analysis_plugin_m68k_cs = {
|
|
.name = "m68k (unsupported)",
|
|
.desc = "Capstone M68K analyzer (unsupported)",
|
|
.license = "BSD",
|
|
.arch = "m68k",
|
|
.bits = 32,
|
|
};
|
|
#endif
|
|
|
|
#ifndef RZ_PLUGIN_INCORE
|
|
RZ_API RzLibStruct rizin_plugin = {
|
|
.type = RZ_LIB_TYPE_ANALYSIS,
|
|
.data = &rz_analysis_plugin_m68k_cs,
|
|
.version = RZ_VERSION
|
|
};
|
|
#endif
|