mirror of
https://github.com/radareorg/radare2.git
synced 2024-11-24 05:40:10 +00:00
499 lines
16 KiB
C
499 lines
16 KiB
C
/* radare - Apache 2.0 - Copyright 2013 - Adam Pridgen <dso@rice.edu || adam.pridgen@thecoverofnight.com> */
|
|
|
|
#include <r_anal.h>
|
|
#include <r_anal_ex.h>
|
|
#include <r_util.h>
|
|
#include <r_list.h>
|
|
#include <r_io.h>
|
|
#include <config.h>
|
|
|
|
#ifdef IFDBG
|
|
#undef IFDBG
|
|
#endif
|
|
|
|
#define DO_THE_DBG 0
|
|
#define IFDBG if(DO_THE_DBG)
|
|
#define IFINT if(0)
|
|
|
|
|
|
static void r_anal_ex_perform_pre_anal(RAnal *anal, RAnalState *state, ut64 addr);
|
|
static void r_anal_ex_perform_pre_anal_op_cb(RAnal *anal, RAnalState *state, ut64 addr);
|
|
static void r_anal_ex_perform_pre_anal_bb_cb(RAnal *anal, RAnalState *state, ut64 addr);
|
|
//static void r_anal_ex_perform_pre_anal_fn_cb(RAnal *anal, RAnalState *state, ut64 addr);
|
|
|
|
static void r_anal_ex_perform_post_anal(RAnal *anal, RAnalState *state, ut64 addr);
|
|
static void r_anal_ex_perform_post_anal_op_cb(RAnal *anal, RAnalState *state, ut64 addr);
|
|
static void r_anal_ex_perform_post_anal_bb_cb(RAnal *anal, RAnalState *state, ut64 addr);
|
|
//static void r_anal_ex_perform_post_anal_fn_cb(RAnal *anal, RAnalState *state, ut64 addr);
|
|
|
|
static void r_anal_ex_perform_revisit_bb_cb(RAnal *anal, RAnalState *state, ut64 addr);
|
|
|
|
ut64 extract_load_store_op(ut64 ranal2_op_type);
|
|
ut64 extract_unknown_op(ut64 ranal2_op_type);
|
|
|
|
static void r_anal_ex_perform_pre_anal(RAnal *anal, RAnalState *state, ut64 addr) {
|
|
if (anal && anal->cur && anal->cur->pre_anal) {
|
|
anal->cur->pre_anal (anal, state, addr);
|
|
}
|
|
}
|
|
|
|
static void r_anal_ex_perform_pre_anal_op_cb(RAnal *anal, RAnalState *state, ut64 addr) {
|
|
if (anal && anal->cur && anal->cur->pre_anal_op_cb) {
|
|
anal->cur->pre_anal_op_cb (anal, state, addr);
|
|
}
|
|
}
|
|
|
|
static void r_anal_ex_perform_pre_anal_bb_cb(RAnal *anal, RAnalState *state, ut64 addr) {
|
|
if (anal && anal->cur && anal->cur->pre_anal_bb_cb) {
|
|
anal->cur->pre_anal_bb_cb (anal, state, addr);
|
|
}
|
|
}
|
|
|
|
/*static void r_anal_ex_perform_pre_anal_fn_cb(RAnal *anal, RAnalState *state, ut64 addr) {
|
|
if (anal->cur && anal->cur->pre_anal_fn_cb) {
|
|
anal->cur->pre_anal_fn_cb (anal, state, addr);
|
|
}
|
|
}*/
|
|
|
|
static void r_anal_ex_perform_post_anal_op_cb(RAnal *anal, RAnalState *state, ut64 addr) {
|
|
if (anal && anal->use_ex && anal->cur && anal->cur->post_anal_op_cb) {
|
|
anal->cur->post_anal_op_cb (anal, state, addr);
|
|
}
|
|
}
|
|
|
|
static void r_anal_ex_perform_post_anal_bb_cb(RAnal *anal, RAnalState *state, ut64 addr) {
|
|
if (anal && anal->use_ex && anal->cur && anal->cur->post_anal_bb_cb) {
|
|
anal->cur->post_anal_bb_cb (anal, state, addr);
|
|
}
|
|
}
|
|
|
|
/*static void r_anal_ex_perform_post_anal_fn_cb(RAnal *anal, RAnalState *state, ut64 addr) {
|
|
if (anal->cur && anal->cur->post_anal_fn_cb) {
|
|
anal->cur->post_anal_fn_cb (anal, state, addr);
|
|
}
|
|
}*/
|
|
|
|
static void r_anal_ex_perform_post_anal(RAnal *anal, RAnalState *state, ut64 addr) {
|
|
if (anal && anal->cur && anal->cur->post_anal) {
|
|
anal->cur->post_anal (anal, state, addr);
|
|
}
|
|
}
|
|
|
|
static void r_anal_ex_perform_revisit_bb_cb(RAnal *anal, RAnalState *state, ut64 addr) {
|
|
if (anal && anal->use_ex && anal->cur && anal->cur->revisit_bb_anal) {
|
|
anal->cur->revisit_bb_anal (anal, state, addr);
|
|
}
|
|
}
|
|
|
|
R_API int r_anal_ex_bb_address_comparator(RAnalBlock *a, RAnalBlock *b){
|
|
if (a->addr == b->addr) {
|
|
return 0;
|
|
}
|
|
if (a->addr < b->addr) {
|
|
return -1;
|
|
}
|
|
// a->addr > b->addr
|
|
return 1;
|
|
}
|
|
|
|
R_API int r_anal_ex_bb_head_comparator(RAnalBlock *a, RAnalBlock *b){
|
|
if (a->head == b->head) {
|
|
return 0;
|
|
}
|
|
if (a->head < b->head) {
|
|
return -1;
|
|
}
|
|
// a->head > b->head
|
|
return 1;
|
|
}
|
|
|
|
R_API void r_anal_ex_clone_op_switch_to_bb (RAnalBlock *bb, RAnalOp *op) {
|
|
RListIter *iter;
|
|
RAnalCaseOp *caseop = NULL;
|
|
|
|
if (bb && op && op->switch_op) {
|
|
bb->switch_op = r_anal_switch_op_new (op->switch_op->addr,
|
|
op->switch_op->min_val,
|
|
op->switch_op->max_val);
|
|
r_list_foreach (op->switch_op->cases, iter, caseop) {
|
|
r_anal_switch_op_add_case (bb->switch_op, caseop->addr,
|
|
caseop->value, caseop->jump);
|
|
}
|
|
}
|
|
}
|
|
|
|
R_API RAnalOp * r_anal_ex_get_op(RAnal *anal, RAnalState *state, ut64 addr, RAnalOpMask mask) {
|
|
RAnalOp *current_op = state->current_op;
|
|
const ut8 * data;
|
|
// current_op set in a prior stage
|
|
if (current_op) {
|
|
return current_op;
|
|
}
|
|
if (!anal || !anal->cur || (!anal->cur->op_from_buffer && !anal->cur->op)) {
|
|
return NULL;
|
|
}
|
|
if (!r_anal_state_addr_is_valid(state, addr) ||
|
|
(anal->cur && (!anal->cur->op && !anal->cur->op_from_buffer))) {
|
|
state->done = 1;
|
|
return NULL;
|
|
}
|
|
data = r_anal_state_get_buf_by_addr(state, addr);
|
|
if (anal->cur->op_from_buffer) {
|
|
current_op = anal->cur->op_from_buffer (anal, addr, data, r_anal_state_get_len (state, addr));
|
|
} else {
|
|
current_op = r_anal_op_new();
|
|
anal->cur->op (anal, current_op, addr, data, r_anal_state_get_len (state, addr), mask);
|
|
}
|
|
state->current_op = current_op;
|
|
return current_op;
|
|
}
|
|
|
|
R_API RAnalBlock * r_anal_ex_get_bb(RAnal *anal, RAnalState *state, ut64 addr) {
|
|
RAnalBlock *current_bb = state->current_bb;
|
|
RAnalOp *op = state->current_op;
|
|
// current_bb set before in a pre-analysis stage.
|
|
if (current_bb) {
|
|
return current_bb;
|
|
}
|
|
if (r_anal_state_addr_is_valid (state, addr) && !op) {
|
|
op = r_anal_ex_get_op (anal, state, addr, R_ANAL_OP_MASK_ALL);
|
|
}
|
|
if (!op || !r_anal_state_addr_is_valid (state, addr)) {
|
|
return NULL;
|
|
}
|
|
current_bb = r_anal_bb_new ();
|
|
if (!current_bb) {
|
|
return NULL;
|
|
}
|
|
r_anal_ex_op_to_bb (anal, state, current_bb, op);
|
|
if (r_anal_op_is_eob (op)) {
|
|
current_bb->type |= R_ANAL_BB_TYPE_LAST;
|
|
}
|
|
if (!current_bb->op_bytes) {
|
|
current_bb->op_sz = state->current_op->size;
|
|
current_bb->op_bytes = malloc (current_bb->op_sz);
|
|
if (current_bb->op_bytes) {
|
|
int buf_len = r_anal_state_get_len (state, addr);
|
|
if (current_bb->op_sz > buf_len) {
|
|
r_anal_bb_free (current_bb);
|
|
return NULL;
|
|
}
|
|
memcpy (current_bb->op_bytes,
|
|
r_anal_state_get_buf_by_addr (state, addr),
|
|
current_bb->op_sz);
|
|
}
|
|
}
|
|
state->current_bb = current_bb;
|
|
// this can be overridden in a post_bb_anal_cb
|
|
state->next_addr = addr + current_bb->op_sz;
|
|
current_bb->op_sz = state->current_op->size;
|
|
return current_bb;
|
|
}
|
|
|
|
R_API void r_anal_ex_update_bb_cfg_head_tail( RAnalBlock *start, RAnalBlock * head, RAnalBlock * tail ) {
|
|
RAnalBlock *bb = start;
|
|
|
|
if (bb) {
|
|
bb->head = head;
|
|
bb->tail = tail;
|
|
}
|
|
|
|
if (bb && bb->next){
|
|
bb->head = head;
|
|
bb->tail = tail;
|
|
do {
|
|
bb->next->prev = bb;
|
|
bb = bb->next;
|
|
bb->head = head;
|
|
bb->tail = tail;
|
|
} while (bb->next && !(bb->type & R_ANAL_BB_TYPE_TAIL));
|
|
}
|
|
}
|
|
|
|
R_API RList* r_anal_ex_perform_analysis(RAnal *anal, RAnalState *state, ut64 addr) {
|
|
if (anal && anal->cur && anal->cur->analysis_algorithm) {
|
|
return anal->cur->analysis_algorithm (anal, state, addr);
|
|
}
|
|
return r_anal_ex_analysis_driver (anal, state, addr);
|
|
}
|
|
|
|
R_API RList* r_anal_ex_analysis_driver(RAnal *anal, RAnalState *state, ut64 addr ) {
|
|
ut64 consumed_iter = 0;
|
|
ut64 bytes_consumed = 0, len = r_anal_state_get_len (state, addr);
|
|
RAnalBlock *pcurrent_bb = state->current_bb,
|
|
*pcurrent_head = state->current_bb_head, *past_bb = NULL;
|
|
RAnalOp *pcurrent_op = state->current_op;
|
|
ut64 backup_addr = state->current_addr;
|
|
state->current_addr = addr;
|
|
RList *bb_list = r_anal_bb_list_new ();
|
|
bb_list->free = NULL; // avoid dblfree
|
|
|
|
if (state->done) {
|
|
return bb_list;
|
|
}
|
|
state->current_bb_head = NULL;
|
|
state->current_bb = NULL;
|
|
state->current_op = NULL;
|
|
|
|
r_anal_ex_perform_pre_anal (anal, state, state->current_addr);
|
|
while (!state->done && bytes_consumed < len) {
|
|
state->current_bb = r_anal_state_search_bb (state, state->current_addr);
|
|
// check state for bb
|
|
if (state->current_bb) {
|
|
// TODO something special should happen here.
|
|
r_anal_ex_perform_revisit_bb_cb (anal, state, state->current_addr);
|
|
consumed_iter += state->current_bb->op_sz;
|
|
bytes_consumed += state->current_bb->op_sz;
|
|
if (state->done) {
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
r_anal_ex_perform_pre_anal_op_cb (anal, state, state->current_addr);
|
|
if (state->done) {
|
|
break;
|
|
}
|
|
r_anal_ex_get_op (anal, state, state->current_addr, R_ANAL_OP_MASK_ALL);
|
|
r_anal_ex_perform_post_anal_op_cb (anal, state, state->current_addr);
|
|
if (state->done) {
|
|
break;
|
|
}
|
|
r_anal_ex_perform_pre_anal_bb_cb (anal, state, state->current_addr);
|
|
if (state->done) {
|
|
break;
|
|
}
|
|
if (!r_anal_ex_get_bb (anal, state, state->current_addr)) {
|
|
break;
|
|
}
|
|
if (!state->current_bb_head) {
|
|
state->current_bb_head = state->current_bb;
|
|
if (state->current_bb_head) {
|
|
state->current_bb_head->type |= R_ANAL_BB_TYPE_HEAD;
|
|
}
|
|
}
|
|
if (past_bb) {
|
|
past_bb->next = state->current_bb;
|
|
state->current_bb->prev = past_bb;
|
|
}
|
|
past_bb = state->current_bb;
|
|
//state->current_bb is shared in two list and one ht!!!
|
|
//source of UAF this should be rewritten to avoid such errors
|
|
r_anal_state_insert_bb (state, state->current_bb);
|
|
r_list_append (bb_list, state->current_bb);
|
|
r_anal_ex_perform_post_anal_bb_cb (anal, state, state->current_addr);
|
|
if (state->done) {
|
|
break;
|
|
}
|
|
if (state->current_bb) {
|
|
bytes_consumed += state->current_bb->op_sz;
|
|
consumed_iter += state->current_bb->op_sz;
|
|
}
|
|
state->current_addr = state->next_addr;
|
|
r_anal_op_free (state->current_op);
|
|
state->current_op = NULL;
|
|
state->current_bb = NULL;
|
|
if (!consumed_iter) {
|
|
eprintf ("No bytes consumed, bailing!\n");
|
|
break;
|
|
}
|
|
consumed_iter = 0;
|
|
}
|
|
r_anal_op_free (state->current_op);
|
|
r_anal_ex_perform_post_anal (anal, state, addr);
|
|
state->current_op = pcurrent_op;
|
|
state->current_bb = pcurrent_bb;
|
|
state->current_bb_head = pcurrent_head;
|
|
state->current_addr = backup_addr;
|
|
return bb_list;
|
|
}
|
|
|
|
R_API void r_anal_ex_op_to_bb(RAnal *anal, RAnalState *state, RAnalBlock *bb, RAnalOp *op) {
|
|
//ut64 cnd_jmp = (R_ANAL_EX_COND_OP | R_ANAL_EX_CODEOP_JMP);
|
|
bb->addr = op->addr;
|
|
bb->size = op->size;
|
|
bb->type2 = op->type2;
|
|
bb->type = r_anal_ex_map_anal_ex_to_anal_bb_type ( op->type2 );
|
|
bb->fail = op->fail;
|
|
bb->jump = op->jump;
|
|
|
|
bb->conditional = R_ANAL_EX_COND_OP & op->type2 ? R_ANAL_OP_TYPE_COND : 0;
|
|
if (r_anal_op_is_eob (op)) {
|
|
bb->type |= R_ANAL_BB_TYPE_LAST;
|
|
}
|
|
r_anal_ex_clone_op_switch_to_bb (bb, op);
|
|
}
|
|
|
|
R_API ut64 r_anal_ex_map_anal_ex_to_anal_bb_type (ut64 ranal2_op_type) {
|
|
ut64 bb_type = 0;
|
|
ut64 conditional = (R_ANAL_EX_COND_OP & ranal2_op_type)?
|
|
R_ANAL_OP_TYPE_COND : 0;
|
|
ut64 code_op_val = ranal2_op_type & (R_ANAL_EX_CODE_OP | 0x1FF);
|
|
|
|
if (conditional) {
|
|
bb_type |= R_ANAL_BB_TYPE_COND;
|
|
}
|
|
if (ranal2_op_type & R_ANAL_EX_LOAD_OP) {
|
|
bb_type |= R_ANAL_BB_TYPE_LD;
|
|
}
|
|
if (ranal2_op_type & R_ANAL_EX_BIN_OP) {
|
|
bb_type |= R_ANAL_BB_TYPE_BINOP;
|
|
}
|
|
if (ranal2_op_type & R_ANAL_EX_LOAD_OP) {
|
|
bb_type |= R_ANAL_BB_TYPE_LD;
|
|
}
|
|
if (ranal2_op_type & R_ANAL_EX_STORE_OP) {
|
|
bb_type |= R_ANAL_BB_TYPE_ST;
|
|
}
|
|
/* mark bb with a comparison */
|
|
if (ranal2_op_type & R_ANAL_EX_BINOP_CMP) {
|
|
bb_type |= R_ANAL_BB_TYPE_CMP;
|
|
}
|
|
|
|
/* change in control flow here */
|
|
if (code_op_val & R_ANAL_EX_CODEOP_JMP) {
|
|
bb_type |= R_ANAL_BB_TYPE_JMP;
|
|
bb_type |= R_ANAL_BB_TYPE_TAIL;
|
|
} else if (code_op_val & R_ANAL_EX_CODEOP_CALL) {
|
|
bb_type |= R_ANAL_BB_TYPE_CALL;
|
|
bb_type |= R_ANAL_BB_TYPE_TAIL;
|
|
} else if ( code_op_val & R_ANAL_EX_CODEOP_SWITCH) {
|
|
bb_type |= R_ANAL_BB_TYPE_SWITCH;
|
|
bb_type |= R_ANAL_BB_TYPE_TAIL;
|
|
} else if (code_op_val & R_ANAL_EX_CODEOP_LEAVE ||
|
|
code_op_val & R_ANAL_EX_CODEOP_RET ) {
|
|
bb_type |= R_ANAL_BB_TYPE_RET;
|
|
bb_type |= R_ANAL_BB_TYPE_LAST;
|
|
bb_type |= R_ANAL_BB_TYPE_TAIL;
|
|
}
|
|
|
|
if (ranal2_op_type & R_ANAL_EX_UNK_OP && code_op_val & R_ANAL_EX_CODEOP_JMP) {
|
|
bb_type |= R_ANAL_BB_TYPE_FOOT;
|
|
}
|
|
|
|
if (conditional && code_op_val & R_ANAL_EX_CODEOP_JMP) {
|
|
bb_type |= R_ANAL_BB_TYPE_BODY;
|
|
}
|
|
|
|
return bb_type;
|
|
}
|
|
|
|
R_API int r_anal_ex_is_op_type_eop(ut64 x) {
|
|
ut8 result = (x & R_ANAL_EX_CODE_OP) ? 1 : 0;
|
|
return result &&
|
|
( (x & R_ANAL_EX_CODEOP_LEAVE) == R_ANAL_EX_CODEOP_LEAVE ||
|
|
(x & R_ANAL_EX_CODEOP_RET) == R_ANAL_EX_CODEOP_RET ||
|
|
(x & R_ANAL_EX_CODEOP_JMP) == R_ANAL_EX_CODEOP_JMP ||
|
|
(x & R_ANAL_EX_CODEOP_SWITCH) == R_ANAL_EX_CODEOP_SWITCH);
|
|
}
|
|
|
|
static ut64 extract_code_op(ut64 ranal2_op_type) {
|
|
ut64 conditional = R_ANAL_EX_COND_OP & ranal2_op_type ? R_ANAL_OP_TYPE_COND : 0;
|
|
ut64 code_op_val = ranal2_op_type & (R_ANAL_EX_CODE_OP | 0x1FF);
|
|
switch (code_op_val) {
|
|
case R_ANAL_EX_CODEOP_CALL: return conditional | R_ANAL_OP_TYPE_CALL;
|
|
case R_ANAL_EX_CODEOP_JMP: return conditional | R_ANAL_OP_TYPE_JMP;
|
|
case R_ANAL_EX_CODEOP_RET: return conditional | R_ANAL_OP_TYPE_RET;
|
|
case R_ANAL_EX_CODEOP_LEAVE: return R_ANAL_OP_TYPE_LEAVE;
|
|
case R_ANAL_EX_CODEOP_SWI: return R_ANAL_OP_TYPE_SWI;
|
|
case R_ANAL_EX_CODEOP_TRAP: return R_ANAL_OP_TYPE_TRAP;
|
|
case R_ANAL_EX_CODEOP_SWITCH: return R_ANAL_OP_TYPE_SWITCH;
|
|
}
|
|
return R_ANAL_OP_TYPE_UNK;
|
|
}
|
|
|
|
ut64 extract_load_store_op(ut64 ranal2_op_type) {
|
|
if ( (ranal2_op_type & R_ANAL_EX_LDST_OP_PUSH) == R_ANAL_EX_LDST_OP_PUSH) {
|
|
return R_ANAL_OP_TYPE_PUSH;
|
|
}
|
|
if ( (ranal2_op_type & R_ANAL_EX_LDST_OP_POP) == R_ANAL_EX_LDST_OP_POP) {
|
|
return R_ANAL_OP_TYPE_POP;
|
|
}
|
|
if ( (ranal2_op_type & R_ANAL_EX_LDST_OP_MOV) == R_ANAL_EX_LDST_OP_MOV) {
|
|
return R_ANAL_OP_TYPE_MOV;
|
|
}
|
|
if ( (ranal2_op_type & R_ANAL_EX_LDST_OP_EFF_ADDR) == R_ANAL_EX_LDST_OP_EFF_ADDR) {
|
|
return R_ANAL_OP_TYPE_LEA;
|
|
}
|
|
return R_ANAL_OP_TYPE_UNK;
|
|
}
|
|
|
|
ut64 extract_unknown_op(ut64 ranal2_op_type) {
|
|
if ((ranal2_op_type & R_ANAL_EX_CODEOP_JMP) == R_ANAL_EX_CODEOP_JMP) {
|
|
return R_ANAL_OP_TYPE_UJMP;
|
|
}
|
|
if ((ranal2_op_type & R_ANAL_EX_CODEOP_CALL) == R_ANAL_EX_CODEOP_CALL) {
|
|
return R_ANAL_OP_TYPE_UCALL;
|
|
}
|
|
if ((ranal2_op_type & R_ANAL_EX_LDST_OP_PUSH) == R_ANAL_EX_LDST_OP_PUSH) {
|
|
return R_ANAL_OP_TYPE_UPUSH;
|
|
}
|
|
return R_ANAL_OP_TYPE_UNK;
|
|
}
|
|
|
|
ut64 extract_bin_op(ut64 ranal2_op_type) {
|
|
ut64 bin_op_val = ranal2_op_type & (R_ANAL_EX_BIN_OP | 0x80000);
|
|
switch (bin_op_val) {
|
|
case R_ANAL_EX_BINOP_XCHG:return R_ANAL_OP_TYPE_XCHG;
|
|
case R_ANAL_EX_BINOP_CMP: return R_ANAL_OP_TYPE_CMP;
|
|
case R_ANAL_EX_BINOP_ADD: return R_ANAL_OP_TYPE_ADD;
|
|
case R_ANAL_EX_BINOP_SUB: return R_ANAL_OP_TYPE_SUB;
|
|
case R_ANAL_EX_BINOP_MUL: return R_ANAL_OP_TYPE_MUL;
|
|
case R_ANAL_EX_BINOP_DIV: return R_ANAL_OP_TYPE_DIV;
|
|
case R_ANAL_EX_BINOP_SHR: return R_ANAL_OP_TYPE_SHR;
|
|
case R_ANAL_EX_BINOP_SHL: return R_ANAL_OP_TYPE_SHL;
|
|
case R_ANAL_EX_BINOP_SAL: return R_ANAL_OP_TYPE_SAL;
|
|
case R_ANAL_EX_BINOP_SAR: return R_ANAL_OP_TYPE_SAR;
|
|
case R_ANAL_EX_BINOP_OR : return R_ANAL_OP_TYPE_OR;
|
|
case R_ANAL_EX_BINOP_AND: return R_ANAL_OP_TYPE_AND;
|
|
case R_ANAL_EX_BINOP_XOR: return R_ANAL_OP_TYPE_XOR;
|
|
case R_ANAL_EX_BINOP_NOT: return R_ANAL_OP_TYPE_NOT;
|
|
case R_ANAL_EX_BINOP_MOD: return R_ANAL_OP_TYPE_MOD;
|
|
case R_ANAL_EX_BINOP_ROR: return R_ANAL_OP_TYPE_ROR;
|
|
case R_ANAL_EX_BINOP_ROL: return R_ANAL_OP_TYPE_ROL;
|
|
default: break;
|
|
}
|
|
return R_ANAL_OP_TYPE_UNK;
|
|
}
|
|
|
|
|
|
R_API ut64 r_anal_ex_map_anal_ex_to_anal_op_type (ut64 t) {
|
|
ut64 t2 = extract_bin_op(t);
|
|
if (t2 != R_ANAL_OP_TYPE_UNK) {
|
|
return t2;
|
|
}
|
|
switch (t) {
|
|
case R_ANAL_EX_NULL_OP: return R_ANAL_OP_TYPE_NULL;
|
|
case R_ANAL_EX_NOP: return R_ANAL_OP_TYPE_NOP;
|
|
case R_ANAL_EX_BINOP_ADD: return R_ANAL_OP_TYPE_ADD;
|
|
case R_ANAL_EX_BINOP_AND: return R_ANAL_OP_TYPE_AND;
|
|
case R_ANAL_EX_BINOP_MUL: return R_ANAL_OP_TYPE_MUL;
|
|
case R_ANAL_EX_BINOP_XOR: return R_ANAL_OP_TYPE_XOR;
|
|
case R_ANAL_EX_BINOP_XCHG: return R_ANAL_OP_TYPE_MOV;
|
|
case R_ANAL_EX_OBJOP_NEW: return R_ANAL_OP_TYPE_UCALL;
|
|
case R_ANAL_EX_OBJOP_SIZE: return R_ANAL_OP_TYPE_UCALL;
|
|
case R_ANAL_EX_ILL_OP: return R_ANAL_OP_TYPE_ILL;
|
|
default:
|
|
if (t & R_ANAL_EX_UNK_OP) {
|
|
return extract_unknown_op (t);
|
|
}
|
|
if (t & R_ANAL_EX_CODE_OP) {
|
|
return extract_code_op (t);
|
|
}
|
|
if (t & R_ANAL_EX_REP_OP) {
|
|
ut64 ret = r_anal_ex_map_anal_ex_to_anal_op_type (t & ~R_ANAL_EX_REP_OP);
|
|
return R_ANAL_OP_TYPE_REP | ret;
|
|
}
|
|
if (t & (R_ANAL_EX_LOAD_OP | R_ANAL_EX_STORE_OP)) {
|
|
return extract_load_store_op(t);
|
|
}
|
|
if (t & R_ANAL_EX_BIN_OP) {
|
|
return extract_bin_op (t);
|
|
}
|
|
break;
|
|
}
|
|
if (R_ANAL_EX_OBJOP_CAST & t) {
|
|
return R_ANAL_OP_TYPE_MOV;
|
|
}
|
|
return R_ANAL_OP_TYPE_UNK;
|
|
}
|