2020-06-14 14:08:32 +00:00
|
|
|
/* radare - LGPL - Copyright 2010-2020 - pancake, nibble */
|
2010-03-12 02:05:20 +00:00
|
|
|
|
|
|
|
#include <r_anal.h>
|
|
|
|
#include <r_util.h>
|
|
|
|
#include <r_list.h>
|
|
|
|
|
2020-06-14 14:08:32 +00:00
|
|
|
R_API RAnalOp *r_anal_op_new(void) {
|
2019-03-06 13:04:22 +00:00
|
|
|
RAnalOp *op = R_NEW (RAnalOp);
|
|
|
|
r_anal_op_init (op);
|
2011-02-24 13:06:49 +00:00
|
|
|
return op;
|
2010-03-12 02:05:20 +00:00
|
|
|
}
|
|
|
|
|
2020-06-14 14:08:32 +00:00
|
|
|
R_API RList *r_anal_op_list_new(void) {
|
2010-03-12 02:05:20 +00:00
|
|
|
RList *list = r_list_new ();
|
2017-08-09 17:21:53 +00:00
|
|
|
if (list) {
|
|
|
|
list->free = &r_anal_op_free;
|
2016-06-17 12:26:24 +00:00
|
|
|
}
|
2010-03-12 02:05:20 +00:00
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2019-03-06 13:04:22 +00:00
|
|
|
R_API void r_anal_op_init(RAnalOp *op) {
|
|
|
|
if (op) {
|
|
|
|
memset (op, 0, sizeof (*op));
|
|
|
|
op->addr = UT64_MAX;
|
|
|
|
op->jump = UT64_MAX;
|
|
|
|
op->fail = UT64_MAX;
|
|
|
|
op->ptr = UT64_MAX;
|
2019-05-27 22:59:39 +00:00
|
|
|
op->refptr = 0;
|
2019-03-06 13:04:22 +00:00
|
|
|
op->val = UT64_MAX;
|
2019-08-19 15:30:56 +00:00
|
|
|
op->disp = UT64_MAX;
|
2019-03-06 13:04:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-24 10:32:45 +00:00
|
|
|
R_API bool r_anal_op_fini(RAnalOp *op) {
|
2016-05-29 22:38:35 +00:00
|
|
|
if (!op) {
|
2016-05-24 10:32:45 +00:00
|
|
|
return false;
|
|
|
|
}
|
2013-12-01 22:33:07 +00:00
|
|
|
r_anal_value_free (op->src[0]);
|
|
|
|
r_anal_value_free (op->src[1]);
|
|
|
|
r_anal_value_free (op->src[2]);
|
2016-10-26 21:40:17 +00:00
|
|
|
op->src[0] = NULL;
|
|
|
|
op->src[1] = NULL;
|
|
|
|
op->src[2] = NULL;
|
2013-12-01 22:33:07 +00:00
|
|
|
r_anal_value_free (op->dst);
|
2016-10-26 21:40:17 +00:00
|
|
|
op->dst = NULL;
|
2017-03-10 19:05:28 +00:00
|
|
|
r_strbuf_fini (&op->opex);
|
2016-04-03 22:52:45 +00:00
|
|
|
r_strbuf_fini (&op->esil);
|
2014-03-26 13:47:30 +00:00
|
|
|
r_anal_switch_op_free (op->switch_op);
|
2018-02-04 11:42:42 +00:00
|
|
|
op->switch_op = NULL;
|
2016-04-03 22:36:18 +00:00
|
|
|
R_FREE (op->mnemonic);
|
2016-05-24 10:32:45 +00:00
|
|
|
return true;
|
2011-11-13 23:21:25 +00:00
|
|
|
}
|
|
|
|
|
2011-02-24 13:06:49 +00:00
|
|
|
R_API void r_anal_op_free(void *_op) {
|
2016-08-24 20:02:38 +00:00
|
|
|
if (!_op) {
|
|
|
|
return;
|
|
|
|
}
|
2011-11-13 23:21:25 +00:00
|
|
|
r_anal_op_fini (_op);
|
2016-04-03 22:36:18 +00:00
|
|
|
memset (_op, 0, sizeof (RAnalOp));
|
2011-11-13 23:21:25 +00:00
|
|
|
free (_op);
|
2010-03-12 02:05:20 +00:00
|
|
|
}
|
|
|
|
|
2018-08-22 23:32:20 +00:00
|
|
|
static int defaultCycles(RAnalOp *op) {
|
|
|
|
switch (op->type) {
|
|
|
|
case R_ANAL_OP_TYPE_PUSH:
|
|
|
|
case R_ANAL_OP_TYPE_POP:
|
|
|
|
case R_ANAL_OP_TYPE_STORE:
|
|
|
|
case R_ANAL_OP_TYPE_LOAD:
|
|
|
|
return 2;
|
|
|
|
case R_ANAL_OP_TYPE_LEA:
|
|
|
|
case R_ANAL_OP_TYPE_MOV:
|
|
|
|
case R_ANAL_OP_TYPE_NOP:
|
|
|
|
return 1;
|
|
|
|
case R_ANAL_OP_TYPE_TRAP:
|
|
|
|
case R_ANAL_OP_TYPE_SWI:
|
|
|
|
return 4;
|
|
|
|
case R_ANAL_OP_TYPE_SYNC:
|
|
|
|
return 4;
|
|
|
|
case R_ANAL_OP_TYPE_RET:
|
|
|
|
case R_ANAL_OP_TYPE_JMP:
|
|
|
|
case R_ANAL_OP_TYPE_RJMP:
|
|
|
|
case R_ANAL_OP_TYPE_CALL:
|
|
|
|
return 4;
|
|
|
|
default:
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-15 18:39:24 +00:00
|
|
|
R_API int r_anal_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int len, RAnalOpMask mask) {
|
2019-03-06 13:04:22 +00:00
|
|
|
r_anal_op_init (op);
|
2018-11-22 15:24:04 +00:00
|
|
|
r_return_val_if_fail (anal && op && len > 0, -1);
|
2018-03-15 11:31:01 +00:00
|
|
|
|
2019-01-16 15:22:45 +00:00
|
|
|
int ret = R_MIN (2, len);
|
2016-11-03 15:22:56 +00:00
|
|
|
if (len > 0 && anal->cur && anal->cur->op) {
|
2017-02-07 22:51:44 +00:00
|
|
|
//use core binding to set asm.bits correctly based on the addr
|
|
|
|
//this is because of the hassle of arm/thumb
|
2017-02-08 21:18:56 +00:00
|
|
|
if (anal && anal->coreb.archbits) {
|
|
|
|
anal->coreb.archbits (anal->coreb.core, addr);
|
|
|
|
}
|
2019-12-11 17:57:32 +00:00
|
|
|
if (anal->pcalign && addr % anal->pcalign) {
|
|
|
|
op->type = R_ANAL_OP_TYPE_ILL;
|
|
|
|
op->addr = addr;
|
|
|
|
// eprintf ("Unaligned instruction for %d bits at 0x%"PFMT64x"\n", anal->bits, addr);
|
|
|
|
op->size = 1;
|
|
|
|
return -1;
|
|
|
|
}
|
2019-03-15 18:39:24 +00:00
|
|
|
ret = anal->cur->op (anal, op, addr, data, len, mask);
|
2017-08-09 17:21:53 +00:00
|
|
|
if (ret < 1) {
|
|
|
|
op->type = R_ANAL_OP_TYPE_ILL;
|
|
|
|
}
|
2014-11-06 15:01:00 +00:00
|
|
|
op->addr = addr;
|
2016-11-23 10:31:24 +00:00
|
|
|
/* consider at least 1 byte to be part of the opcode */
|
|
|
|
if (op->nopcode < 1) {
|
|
|
|
op->nopcode = 1;
|
|
|
|
}
|
2019-01-16 15:22:45 +00:00
|
|
|
} else if (!memcmp (data, "\xff\xff\xff\xff", R_MIN (4, len))) {
|
2017-08-09 17:21:53 +00:00
|
|
|
op->type = R_ANAL_OP_TYPE_ILL;
|
2019-01-16 15:22:45 +00:00
|
|
|
} else {
|
|
|
|
op->type = R_ANAL_OP_TYPE_MOV;
|
|
|
|
if (op->cycles == 0) {
|
|
|
|
op->cycles = defaultCycles (op);
|
|
|
|
}
|
2017-08-09 17:21:53 +00:00
|
|
|
}
|
2019-10-13 20:47:39 +00:00
|
|
|
if (!op->mnemonic && (mask & R_ANAL_OP_MASK_DISASM)) {
|
2019-11-06 11:18:49 +00:00
|
|
|
if (anal->verbose) {
|
|
|
|
eprintf ("Warning: unhandled R_ANAL_OP_MASK_DISASM in r_anal_op\n");
|
|
|
|
}
|
2019-10-13 20:47:39 +00:00
|
|
|
}
|
2019-01-16 15:22:45 +00:00
|
|
|
if (mask & R_ANAL_OP_MASK_HINT) {
|
|
|
|
RAnalHint *hint = r_anal_hint_get (anal, addr);
|
|
|
|
if (hint) {
|
|
|
|
r_anal_op_hint (op, hint);
|
|
|
|
r_anal_hint_free (hint);
|
|
|
|
}
|
2018-08-22 23:32:20 +00:00
|
|
|
}
|
2019-01-16 15:22:45 +00:00
|
|
|
return ret;
|
2010-03-12 02:05:20 +00:00
|
|
|
}
|
2010-06-21 09:55:48 +00:00
|
|
|
|
2017-02-07 22:51:44 +00:00
|
|
|
R_API RAnalOp *r_anal_op_copy(RAnalOp *op) {
|
2016-05-24 10:32:45 +00:00
|
|
|
RAnalOp *nop = R_NEW0 (RAnalOp);
|
2017-02-07 22:51:44 +00:00
|
|
|
if (!nop) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2014-03-26 13:47:30 +00:00
|
|
|
*nop = *op;
|
2015-07-21 04:06:00 +00:00
|
|
|
if (op->mnemonic) {
|
|
|
|
nop->mnemonic = strdup (op->mnemonic);
|
|
|
|
if (!nop->mnemonic) {
|
|
|
|
free (nop);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
nop->mnemonic = NULL;
|
2015-06-17 10:36:08 +00:00
|
|
|
}
|
2011-03-28 08:24:01 +00:00
|
|
|
nop->src[0] = r_anal_value_copy (op->src[0]);
|
|
|
|
nop->src[1] = r_anal_value_copy (op->src[1]);
|
|
|
|
nop->src[2] = r_anal_value_copy (op->src[2]);
|
|
|
|
nop->dst = r_anal_value_copy (op->dst);
|
2013-12-10 02:35:59 +00:00
|
|
|
r_strbuf_init (&nop->esil);
|
2019-10-03 23:27:50 +00:00
|
|
|
r_strbuf_copy (&nop->esil, &op->esil);
|
2011-03-28 08:24:01 +00:00
|
|
|
return nop;
|
|
|
|
}
|
|
|
|
|
2018-05-29 04:51:31 +00:00
|
|
|
R_API bool r_anal_op_nonlinear(int t) {
|
2018-07-14 17:47:34 +00:00
|
|
|
t &= R_ANAL_OP_TYPE_MASK;
|
2018-05-29 04:51:31 +00:00
|
|
|
switch (t) {
|
|
|
|
//call
|
|
|
|
case R_ANAL_OP_TYPE_CALL:
|
|
|
|
case R_ANAL_OP_TYPE_RCALL:
|
|
|
|
case R_ANAL_OP_TYPE_ICALL:
|
|
|
|
case R_ANAL_OP_TYPE_UCALL:
|
|
|
|
case R_ANAL_OP_TYPE_IRCALL:
|
|
|
|
case R_ANAL_OP_TYPE_UCCALL:
|
|
|
|
// jmp
|
|
|
|
case R_ANAL_OP_TYPE_JMP:
|
|
|
|
case R_ANAL_OP_TYPE_MJMP:
|
|
|
|
case R_ANAL_OP_TYPE_UJMP:
|
|
|
|
case R_ANAL_OP_TYPE_CJMP:
|
|
|
|
case R_ANAL_OP_TYPE_UCJMP:
|
|
|
|
case R_ANAL_OP_TYPE_RJMP:
|
|
|
|
case R_ANAL_OP_TYPE_IJMP:
|
|
|
|
case R_ANAL_OP_TYPE_IRJMP:
|
|
|
|
// trap| ill| unk
|
|
|
|
case R_ANAL_OP_TYPE_TRAP:
|
|
|
|
case R_ANAL_OP_TYPE_ILL:
|
|
|
|
case R_ANAL_OP_TYPE_UNK:
|
2018-07-09 06:22:22 +00:00
|
|
|
case R_ANAL_OP_TYPE_SWI:
|
2018-08-19 21:05:54 +00:00
|
|
|
case R_ANAL_OP_TYPE_RET:
|
2018-05-29 04:51:31 +00:00
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-05 19:43:32 +00:00
|
|
|
R_API bool r_anal_op_ismemref(int t) {
|
2018-07-14 17:47:34 +00:00
|
|
|
t &= R_ANAL_OP_TYPE_MASK;
|
2018-06-05 19:43:32 +00:00
|
|
|
switch (t) {
|
|
|
|
case R_ANAL_OP_TYPE_LOAD:
|
|
|
|
case R_ANAL_OP_TYPE_MOV:
|
|
|
|
case R_ANAL_OP_TYPE_STORE:
|
|
|
|
case R_ANAL_OP_TYPE_LEA:
|
|
|
|
case R_ANAL_OP_TYPE_CMP:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-16 23:26:39 +00:00
|
|
|
static struct optype {
|
|
|
|
int type;
|
|
|
|
const char *name;
|
|
|
|
} optypes[] = {
|
|
|
|
{ R_ANAL_OP_TYPE_IO, "io" },
|
|
|
|
{ R_ANAL_OP_TYPE_ACMP, "acmp" },
|
|
|
|
{ R_ANAL_OP_TYPE_ADD, "add" },
|
|
|
|
{ R_ANAL_OP_TYPE_SYNC, "sync" },
|
|
|
|
{ R_ANAL_OP_TYPE_AND, "and" },
|
|
|
|
{ R_ANAL_OP_TYPE_CALL, "call" },
|
|
|
|
{ R_ANAL_OP_TYPE_CCALL, "ccall" },
|
|
|
|
{ R_ANAL_OP_TYPE_CJMP, "cjmp" },
|
|
|
|
{ R_ANAL_OP_TYPE_MJMP, "mjmp" },
|
|
|
|
{ R_ANAL_OP_TYPE_CMP, "cmp" },
|
|
|
|
{ R_ANAL_OP_TYPE_IO, "cret" },
|
|
|
|
{ R_ANAL_OP_TYPE_ILL, "ill" },
|
|
|
|
{ R_ANAL_OP_TYPE_JMP, "jmp" },
|
|
|
|
{ R_ANAL_OP_TYPE_LEA, "lea" },
|
|
|
|
{ R_ANAL_OP_TYPE_LEAVE, "leave" },
|
|
|
|
{ R_ANAL_OP_TYPE_LOAD, "load" },
|
|
|
|
{ R_ANAL_OP_TYPE_NEW, "new" },
|
|
|
|
{ R_ANAL_OP_TYPE_MOD, "mod" },
|
|
|
|
{ R_ANAL_OP_TYPE_CMOV, "cmov" },
|
|
|
|
{ R_ANAL_OP_TYPE_MOV, "mov" },
|
2019-05-27 22:59:39 +00:00
|
|
|
{ R_ANAL_OP_TYPE_CAST, "cast" },
|
2019-01-16 23:26:39 +00:00
|
|
|
{ R_ANAL_OP_TYPE_MUL, "mul" },
|
2019-01-21 10:12:21 +00:00
|
|
|
{ R_ANAL_OP_TYPE_DIV, "div" },
|
2019-01-16 23:26:39 +00:00
|
|
|
{ R_ANAL_OP_TYPE_NOP, "nop" },
|
|
|
|
{ R_ANAL_OP_TYPE_NOT, "not" },
|
|
|
|
{ R_ANAL_OP_TYPE_NULL , "null" },
|
|
|
|
{ R_ANAL_OP_TYPE_OR , "or" },
|
|
|
|
{ R_ANAL_OP_TYPE_POP , "pop" },
|
|
|
|
{ R_ANAL_OP_TYPE_PUSH , "push" },
|
|
|
|
{ R_ANAL_OP_TYPE_REP , "rep" },
|
|
|
|
{ R_ANAL_OP_TYPE_RET , "ret" },
|
|
|
|
{ R_ANAL_OP_TYPE_ROL , "rol" },
|
|
|
|
{ R_ANAL_OP_TYPE_ROR , "ror" },
|
|
|
|
{ R_ANAL_OP_TYPE_SAL , "sal" },
|
|
|
|
{ R_ANAL_OP_TYPE_SAR , "sar" },
|
|
|
|
{ R_ANAL_OP_TYPE_SHL , "shl" },
|
|
|
|
{ R_ANAL_OP_TYPE_SHR , "shr" },
|
|
|
|
{ R_ANAL_OP_TYPE_STORE , "store" },
|
|
|
|
{ R_ANAL_OP_TYPE_SUB , "sub" },
|
|
|
|
{ R_ANAL_OP_TYPE_SWI , "swi" },
|
|
|
|
{ R_ANAL_OP_TYPE_CSWI , "cswi" },
|
|
|
|
{ R_ANAL_OP_TYPE_SWITCH, "switch" },
|
|
|
|
{ R_ANAL_OP_TYPE_TRAP , "trap" },
|
|
|
|
{ R_ANAL_OP_TYPE_UCALL , "ucall" },
|
2019-09-23 10:40:24 +00:00
|
|
|
{ R_ANAL_OP_TYPE_RCALL , "rcall" }, // needs to be changed
|
2019-01-16 23:26:39 +00:00
|
|
|
{ R_ANAL_OP_TYPE_ICALL , "ucall" }, // needs to be changed
|
|
|
|
{ R_ANAL_OP_TYPE_IRCALL, "ucall" }, // needs to be changed
|
|
|
|
{ R_ANAL_OP_TYPE_UCCALL, "uccall" },
|
|
|
|
{ R_ANAL_OP_TYPE_UCJMP , "ucjmp" },
|
|
|
|
{ R_ANAL_OP_TYPE_UJMP , "ujmp" },
|
2019-09-23 10:40:24 +00:00
|
|
|
{ R_ANAL_OP_TYPE_RJMP , "rjmp" }, // needs to be changed
|
2019-01-16 23:26:39 +00:00
|
|
|
{ R_ANAL_OP_TYPE_IJMP , "ujmp" }, // needs to be changed
|
|
|
|
{ R_ANAL_OP_TYPE_IRJMP , "ujmp" }, // needs to be changed
|
|
|
|
{ R_ANAL_OP_TYPE_UNK , "unk" },
|
|
|
|
{ R_ANAL_OP_TYPE_UPUSH , "upush" },
|
2019-05-15 10:04:41 +00:00
|
|
|
{ R_ANAL_OP_TYPE_RPUSH , "rpush" },
|
2019-01-16 23:26:39 +00:00
|
|
|
{ R_ANAL_OP_TYPE_XCHG , "xchg" },
|
|
|
|
{ R_ANAL_OP_TYPE_XOR , "xor" },
|
|
|
|
{ R_ANAL_OP_TYPE_CASE , "case" },
|
|
|
|
{ R_ANAL_OP_TYPE_CPL , "cpl" },
|
|
|
|
{ R_ANAL_OP_TYPE_CRYPTO, "crypto" },
|
|
|
|
{0,NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
R_API int r_anal_optype_from_string(const char *type) {
|
|
|
|
int i;
|
|
|
|
for (i = 0; optypes[i].name;i++) {
|
|
|
|
if (!strcmp (optypes[i].name, type)) {
|
|
|
|
return optypes[i].type;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-03-03 23:46:59 +00:00
|
|
|
R_API const char *r_anal_optype_to_string(int t) {
|
2020-01-14 11:36:36 +00:00
|
|
|
bool once = true;
|
|
|
|
repeat:
|
2019-01-16 23:26:39 +00:00
|
|
|
// TODO: delete
|
2012-11-08 08:49:27 +00:00
|
|
|
switch (t) {
|
2015-03-03 23:46:59 +00:00
|
|
|
case R_ANAL_OP_TYPE_IO : return "io";
|
2015-01-15 00:31:21 +00:00
|
|
|
case R_ANAL_OP_TYPE_ACMP : return "acmp";
|
|
|
|
case R_ANAL_OP_TYPE_ADD : return "add";
|
2018-01-08 10:21:48 +00:00
|
|
|
case R_ANAL_OP_TYPE_SYNC : return "sync";
|
2015-01-15 00:31:21 +00:00
|
|
|
case R_ANAL_OP_TYPE_AND : return "and";
|
2012-11-08 08:49:27 +00:00
|
|
|
case R_ANAL_OP_TYPE_CALL : return "call";
|
2014-02-25 23:03:42 +00:00
|
|
|
case R_ANAL_OP_TYPE_CCALL : return "ccall";
|
2015-01-15 00:31:21 +00:00
|
|
|
case R_ANAL_OP_TYPE_CJMP : return "cjmp";
|
2016-05-29 22:38:35 +00:00
|
|
|
case R_ANAL_OP_TYPE_MJMP : return "mjmp";
|
2015-01-15 00:31:21 +00:00
|
|
|
case R_ANAL_OP_TYPE_CMP : return "cmp";
|
2014-02-25 23:03:42 +00:00
|
|
|
case R_ANAL_OP_TYPE_CRET : return "cret";
|
2015-01-15 00:31:21 +00:00
|
|
|
case R_ANAL_OP_TYPE_DIV : return "div";
|
2012-11-08 08:49:27 +00:00
|
|
|
case R_ANAL_OP_TYPE_ILL : return "ill";
|
2015-01-15 00:31:21 +00:00
|
|
|
case R_ANAL_OP_TYPE_JMP : return "jmp";
|
|
|
|
case R_ANAL_OP_TYPE_LEA : return "lea";
|
|
|
|
case R_ANAL_OP_TYPE_LEAVE : return "leave";
|
|
|
|
case R_ANAL_OP_TYPE_LOAD : return "load";
|
2016-12-14 23:14:33 +00:00
|
|
|
case R_ANAL_OP_TYPE_NEW : return "new";
|
2015-01-15 00:31:21 +00:00
|
|
|
case R_ANAL_OP_TYPE_MOD : return "mod";
|
2015-10-18 20:14:06 +00:00
|
|
|
case R_ANAL_OP_TYPE_CMOV : return "cmov";
|
2012-11-08 08:49:27 +00:00
|
|
|
case R_ANAL_OP_TYPE_MOV : return "mov";
|
2019-05-27 22:59:39 +00:00
|
|
|
case R_ANAL_OP_TYPE_CAST : return "cast";
|
2012-11-08 08:49:27 +00:00
|
|
|
case R_ANAL_OP_TYPE_MUL : return "mul";
|
2015-01-15 00:31:21 +00:00
|
|
|
case R_ANAL_OP_TYPE_NOP : return "nop";
|
|
|
|
case R_ANAL_OP_TYPE_NOT : return "not";
|
|
|
|
case R_ANAL_OP_TYPE_NULL : return "null";
|
|
|
|
case R_ANAL_OP_TYPE_OR : return "or";
|
|
|
|
case R_ANAL_OP_TYPE_POP : return "pop";
|
|
|
|
case R_ANAL_OP_TYPE_PUSH : return "push";
|
2020-01-14 11:36:36 +00:00
|
|
|
case R_ANAL_OP_TYPE_RPUSH : return "rpush";
|
2015-01-15 00:31:21 +00:00
|
|
|
case R_ANAL_OP_TYPE_REP : return "rep";
|
|
|
|
case R_ANAL_OP_TYPE_RET : return "ret";
|
|
|
|
case R_ANAL_OP_TYPE_ROL : return "rol";
|
|
|
|
case R_ANAL_OP_TYPE_ROR : return "ror";
|
|
|
|
case R_ANAL_OP_TYPE_SAL : return "sal";
|
2014-10-15 23:51:48 +00:00
|
|
|
case R_ANAL_OP_TYPE_SAR : return "sar";
|
2012-11-08 08:49:27 +00:00
|
|
|
case R_ANAL_OP_TYPE_SHL : return "shl";
|
2015-01-15 00:31:21 +00:00
|
|
|
case R_ANAL_OP_TYPE_SHR : return "shr";
|
2012-11-08 08:49:27 +00:00
|
|
|
case R_ANAL_OP_TYPE_STORE : return "store";
|
2015-01-15 00:31:21 +00:00
|
|
|
case R_ANAL_OP_TYPE_SUB : return "sub";
|
|
|
|
case R_ANAL_OP_TYPE_SWI : return "swi";
|
2018-10-27 09:28:16 +00:00
|
|
|
case R_ANAL_OP_TYPE_CSWI : return "cswi";
|
2015-03-08 21:09:59 +00:00
|
|
|
case R_ANAL_OP_TYPE_SWITCH: return "switch";
|
2015-01-15 00:31:21 +00:00
|
|
|
case R_ANAL_OP_TYPE_TRAP : return "trap";
|
|
|
|
case R_ANAL_OP_TYPE_UCALL : return "ucall";
|
2019-09-23 10:40:24 +00:00
|
|
|
case R_ANAL_OP_TYPE_RCALL : return "rcall"; // needs to be changed
|
2016-09-22 11:42:06 +00:00
|
|
|
case R_ANAL_OP_TYPE_ICALL : return "ucall"; // needs to be changed
|
|
|
|
case R_ANAL_OP_TYPE_IRCALL: return "ucall"; // needs to be changed
|
2015-01-15 00:31:21 +00:00
|
|
|
case R_ANAL_OP_TYPE_UCCALL: return "uccall";
|
|
|
|
case R_ANAL_OP_TYPE_UCJMP : return "ucjmp";
|
|
|
|
case R_ANAL_OP_TYPE_UJMP : return "ujmp";
|
2019-09-23 10:40:24 +00:00
|
|
|
case R_ANAL_OP_TYPE_RJMP : return "rjmp"; // needs to be changed
|
2016-09-22 11:42:06 +00:00
|
|
|
case R_ANAL_OP_TYPE_IJMP : return "ujmp"; // needs to be changed
|
|
|
|
case R_ANAL_OP_TYPE_IRJMP : return "ujmp"; // needs to be changed
|
2015-01-15 00:31:21 +00:00
|
|
|
case R_ANAL_OP_TYPE_UNK : return "unk";
|
|
|
|
case R_ANAL_OP_TYPE_UPUSH : return "upush";
|
|
|
|
case R_ANAL_OP_TYPE_XCHG : return "xchg";
|
|
|
|
case R_ANAL_OP_TYPE_XOR : return "xor";
|
2015-03-08 21:09:59 +00:00
|
|
|
case R_ANAL_OP_TYPE_CASE : return "case";
|
2015-10-15 00:22:27 +00:00
|
|
|
case R_ANAL_OP_TYPE_CPL : return "cpl";
|
2015-10-15 18:02:36 +00:00
|
|
|
case R_ANAL_OP_TYPE_CRYPTO: return "crypto";
|
2012-11-08 08:49:27 +00:00
|
|
|
}
|
2020-01-14 11:36:36 +00:00
|
|
|
if (once) {
|
|
|
|
once = false;
|
|
|
|
t &= R_ANAL_OP_TYPE_MASK; // ignore the modifier bits... we don't want this!
|
|
|
|
goto repeat;
|
|
|
|
}
|
2012-11-08 08:49:27 +00:00
|
|
|
return "undefined";
|
|
|
|
}
|
|
|
|
|
2013-06-09 01:25:32 +00:00
|
|
|
R_API const char *r_anal_op_to_esil_string(RAnal *anal, RAnalOp *op) {
|
2013-12-10 02:35:59 +00:00
|
|
|
return r_strbuf_get (&op->esil);
|
2013-06-09 01:25:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: use esil here?
|
2011-02-24 13:06:49 +00:00
|
|
|
R_API char *r_anal_op_to_string(RAnal *anal, RAnalOp *op) {
|
2016-06-17 12:26:24 +00:00
|
|
|
RAnalBlock *bb;
|
2012-07-19 02:54:22 +00:00
|
|
|
RAnalFunction *f;
|
2017-08-09 17:21:53 +00:00
|
|
|
char *cstr, ret[128];
|
2010-06-21 09:55:48 +00:00
|
|
|
char *r0 = r_anal_value_to_string (op->dst);
|
|
|
|
char *a0 = r_anal_value_to_string (op->src[0]);
|
|
|
|
char *a1 = r_anal_value_to_string (op->src[1]);
|
2018-09-13 08:17:26 +00:00
|
|
|
if (!r0) {
|
|
|
|
r0 = strdup ("?");
|
|
|
|
}
|
|
|
|
if (!a0) {
|
|
|
|
a0 = strdup ("?");
|
|
|
|
}
|
|
|
|
if (!a1) {
|
|
|
|
a1 = strdup ("?");
|
|
|
|
}
|
2010-06-21 09:55:48 +00:00
|
|
|
|
|
|
|
switch (op->type) {
|
|
|
|
case R_ANAL_OP_TYPE_MOV:
|
2011-08-18 15:03:45 +00:00
|
|
|
snprintf (ret, sizeof (ret), "%s = %s", r0, a0);
|
2010-06-21 09:55:48 +00:00
|
|
|
break;
|
|
|
|
case R_ANAL_OP_TYPE_CJMP:
|
2016-06-17 12:26:24 +00:00
|
|
|
if ((bb = r_anal_bb_from_offset (anal, op->addr))) {
|
2011-02-28 12:07:41 +00:00
|
|
|
cstr = r_anal_cond_to_string (bb->cond);
|
2011-08-18 15:03:45 +00:00
|
|
|
snprintf (ret, sizeof (ret), "if (%s) goto 0x%"PFMT64x, cstr, op->jump);
|
2011-02-28 12:07:41 +00:00
|
|
|
free (cstr);
|
2016-06-17 12:26:24 +00:00
|
|
|
} else {
|
|
|
|
snprintf (ret, sizeof (ret), "if (%s) goto 0x%"PFMT64x, "?", op->jump);
|
2011-02-28 12:07:41 +00:00
|
|
|
}
|
2010-06-21 09:55:48 +00:00
|
|
|
break;
|
|
|
|
case R_ANAL_OP_TYPE_JMP:
|
2011-08-18 15:03:45 +00:00
|
|
|
snprintf (ret, sizeof (ret), "goto 0x%"PFMT64x, op->jump);
|
2010-06-21 09:55:48 +00:00
|
|
|
break;
|
2011-03-01 18:16:29 +00:00
|
|
|
case R_ANAL_OP_TYPE_UJMP:
|
2016-09-22 11:42:06 +00:00
|
|
|
case R_ANAL_OP_TYPE_RJMP:
|
|
|
|
case R_ANAL_OP_TYPE_IJMP:
|
|
|
|
case R_ANAL_OP_TYPE_IRJMP:
|
2011-08-18 15:03:45 +00:00
|
|
|
snprintf (ret, sizeof (ret), "goto %s", r0);
|
2011-03-01 18:16:29 +00:00
|
|
|
break;
|
2011-02-27 02:39:27 +00:00
|
|
|
case R_ANAL_OP_TYPE_PUSH:
|
|
|
|
case R_ANAL_OP_TYPE_UPUSH:
|
2019-05-15 10:04:41 +00:00
|
|
|
case R_ANAL_OP_TYPE_RPUSH:
|
2011-08-18 15:03:45 +00:00
|
|
|
snprintf (ret, sizeof (ret), "push %s", a0);
|
2011-02-27 02:39:27 +00:00
|
|
|
break;
|
|
|
|
case R_ANAL_OP_TYPE_POP:
|
2011-08-18 15:03:45 +00:00
|
|
|
snprintf (ret, sizeof (ret), "pop %s", r0);
|
2011-02-27 02:39:27 +00:00
|
|
|
break;
|
2011-02-28 16:27:08 +00:00
|
|
|
case R_ANAL_OP_TYPE_UCALL:
|
2016-09-22 11:42:06 +00:00
|
|
|
case R_ANAL_OP_TYPE_RCALL:
|
|
|
|
case R_ANAL_OP_TYPE_ICALL:
|
|
|
|
case R_ANAL_OP_TYPE_IRCALL:
|
2011-08-18 15:03:45 +00:00
|
|
|
snprintf (ret, sizeof (ret), "%s()", r0);
|
2011-02-28 16:27:08 +00:00
|
|
|
break;
|
2010-06-21 09:55:48 +00:00
|
|
|
case R_ANAL_OP_TYPE_CALL:
|
2014-09-26 13:40:17 +00:00
|
|
|
f = r_anal_get_fcn_in (anal, op->jump, R_ANAL_FCN_TYPE_NULL);
|
2017-08-09 17:21:53 +00:00
|
|
|
if (f) {
|
|
|
|
snprintf (ret, sizeof (ret), "%s()", f->name);
|
|
|
|
} else {
|
|
|
|
snprintf (ret, sizeof (ret), "0x%"PFMT64x"()", op->jump);
|
|
|
|
}
|
2010-06-21 09:55:48 +00:00
|
|
|
break;
|
2014-02-25 23:03:42 +00:00
|
|
|
case R_ANAL_OP_TYPE_CCALL:
|
2014-09-26 13:40:17 +00:00
|
|
|
f = r_anal_get_fcn_in (anal, op->jump, R_ANAL_FCN_TYPE_NULL);
|
2016-06-17 12:26:24 +00:00
|
|
|
if ((bb = r_anal_bb_from_offset (anal, op->addr))) {
|
2014-02-25 23:03:42 +00:00
|
|
|
cstr = r_anal_cond_to_string (bb->cond);
|
2018-09-13 08:17:26 +00:00
|
|
|
if (f) {
|
|
|
|
snprintf (ret, sizeof (ret), "if (%s) %s()", cstr, f->name);
|
|
|
|
} else {
|
|
|
|
snprintf (ret, sizeof (ret), "if (%s) 0x%" PFMT64x "()", cstr, op->jump);
|
|
|
|
}
|
2014-02-25 23:03:42 +00:00
|
|
|
free (cstr);
|
|
|
|
} else {
|
2018-09-13 08:17:26 +00:00
|
|
|
if (f) {
|
|
|
|
snprintf (ret, sizeof (ret), "if (unk) %s()", f->name);
|
|
|
|
} else {
|
|
|
|
snprintf (ret, sizeof (ret), "if (unk) 0x%" PFMT64x "()", op->jump);
|
|
|
|
}
|
2014-02-25 23:03:42 +00:00
|
|
|
}
|
|
|
|
break;
|
2011-02-27 15:17:05 +00:00
|
|
|
case R_ANAL_OP_TYPE_ADD:
|
2016-06-17 12:26:24 +00:00
|
|
|
if (!a1 || !strcmp (a0, a1)) {
|
2011-08-18 15:03:45 +00:00
|
|
|
snprintf (ret, sizeof (ret), "%s += %s", r0, a0);
|
2016-06-17 12:26:24 +00:00
|
|
|
} else {
|
|
|
|
snprintf (ret, sizeof (ret), "%s = %s + %s", r0, a0, a1);
|
|
|
|
}
|
2011-02-27 15:17:05 +00:00
|
|
|
break;
|
2010-06-21 09:55:48 +00:00
|
|
|
case R_ANAL_OP_TYPE_SUB:
|
2016-06-17 12:26:24 +00:00
|
|
|
if (!a1 || !strcmp (a0, a1)) {
|
2011-08-18 15:03:45 +00:00
|
|
|
snprintf (ret, sizeof (ret), "%s -= %s", r0, a0);
|
2016-06-17 12:26:24 +00:00
|
|
|
} else {
|
|
|
|
snprintf (ret, sizeof (ret), "%s = %s - %s", r0, a0, a1);
|
|
|
|
}
|
2010-06-21 09:55:48 +00:00
|
|
|
break;
|
2011-02-27 15:17:05 +00:00
|
|
|
case R_ANAL_OP_TYPE_MUL:
|
2016-06-17 12:26:24 +00:00
|
|
|
if (!a1 || !strcmp (a0, a1)) {
|
2011-08-18 15:03:45 +00:00
|
|
|
snprintf (ret, sizeof (ret), "%s *= %s", r0, a0);
|
2016-06-17 12:26:24 +00:00
|
|
|
} else {
|
|
|
|
snprintf (ret, sizeof (ret), "%s = %s * %s", r0, a0, a1);
|
|
|
|
}
|
2011-02-27 15:17:05 +00:00
|
|
|
break;
|
|
|
|
case R_ANAL_OP_TYPE_DIV:
|
2016-06-17 12:26:24 +00:00
|
|
|
if (!a1 || !strcmp (a0, a1)) {
|
2011-08-18 15:03:45 +00:00
|
|
|
snprintf (ret, sizeof (ret), "%s /= %s", r0, a0);
|
2018-09-13 08:17:26 +00:00
|
|
|
} else {
|
|
|
|
snprintf (ret, sizeof (ret), "%s = %s / %s", r0, a0, a1);
|
|
|
|
}
|
2011-02-27 15:17:05 +00:00
|
|
|
break;
|
|
|
|
case R_ANAL_OP_TYPE_AND:
|
2016-06-17 12:26:24 +00:00
|
|
|
if (!a1 || !strcmp (a0, a1)) {
|
2011-08-18 15:03:45 +00:00
|
|
|
snprintf (ret, sizeof (ret), "%s &= %s", r0, a0);
|
2018-09-13 08:17:26 +00:00
|
|
|
} else {
|
|
|
|
snprintf (ret, sizeof (ret), "%s = %s & %s", r0, a0, a1);
|
|
|
|
}
|
2011-02-27 15:17:05 +00:00
|
|
|
break;
|
|
|
|
case R_ANAL_OP_TYPE_OR:
|
2016-06-17 12:26:24 +00:00
|
|
|
if (!a1 || !strcmp (a0, a1)) {
|
2011-08-18 15:03:45 +00:00
|
|
|
snprintf (ret, sizeof (ret), "%s |= %s", r0, a0);
|
2018-09-13 08:17:26 +00:00
|
|
|
} else {
|
|
|
|
snprintf (ret, sizeof (ret), "%s = %s | %s", r0, a0, a1);
|
|
|
|
}
|
2011-02-27 15:17:05 +00:00
|
|
|
break;
|
|
|
|
case R_ANAL_OP_TYPE_XOR:
|
2016-06-17 12:26:24 +00:00
|
|
|
if (!a1 || !strcmp (a0, a1)) {
|
2011-08-18 15:03:45 +00:00
|
|
|
snprintf (ret, sizeof (ret), "%s ^= %s", r0, a0);
|
2018-09-13 08:17:26 +00:00
|
|
|
} else {
|
|
|
|
snprintf (ret, sizeof (ret), "%s = %s ^ %s", r0, a0, a1);
|
|
|
|
}
|
2011-02-27 15:17:05 +00:00
|
|
|
break;
|
2011-03-01 18:16:29 +00:00
|
|
|
case R_ANAL_OP_TYPE_LEA:
|
2011-08-18 15:03:45 +00:00
|
|
|
snprintf (ret, sizeof (ret), "%s -> %s", r0, a0);
|
2011-03-01 18:16:29 +00:00
|
|
|
break;
|
2011-02-28 12:07:41 +00:00
|
|
|
case R_ANAL_OP_TYPE_CMP:
|
2011-08-18 15:03:45 +00:00
|
|
|
memcpy (ret, ";", 2);
|
2011-02-28 12:07:41 +00:00
|
|
|
break;
|
2011-02-27 15:17:05 +00:00
|
|
|
case R_ANAL_OP_TYPE_NOP:
|
2011-07-06 07:40:23 +00:00
|
|
|
memcpy (ret, "nop", 4);
|
2011-02-27 15:17:05 +00:00
|
|
|
break;
|
2011-02-28 12:07:41 +00:00
|
|
|
case R_ANAL_OP_TYPE_RET:
|
2011-07-06 07:40:23 +00:00
|
|
|
memcpy (ret, "ret", 4);
|
2011-02-28 12:07:41 +00:00
|
|
|
break;
|
2014-02-25 23:03:42 +00:00
|
|
|
case R_ANAL_OP_TYPE_CRET:
|
2016-06-17 12:26:24 +00:00
|
|
|
if ((bb = r_anal_bb_from_offset (anal, op->addr))) {
|
2014-02-25 23:03:42 +00:00
|
|
|
cstr = r_anal_cond_to_string (bb->cond);
|
|
|
|
snprintf (ret, sizeof (ret), "if (%s) ret", cstr);
|
|
|
|
free (cstr);
|
2016-06-17 12:26:24 +00:00
|
|
|
} else {
|
|
|
|
strcpy (ret, "if (unk) ret");
|
2014-02-25 23:03:42 +00:00
|
|
|
}
|
|
|
|
break;
|
2011-03-01 18:16:29 +00:00
|
|
|
case R_ANAL_OP_TYPE_LEAVE:
|
2011-07-06 07:40:23 +00:00
|
|
|
memcpy (ret, "leave", 6);
|
2011-03-01 18:16:29 +00:00
|
|
|
break;
|
2014-01-02 05:09:46 +00:00
|
|
|
case R_ANAL_OP_TYPE_MOD:
|
2016-06-17 12:26:24 +00:00
|
|
|
if (!a1 || !strcmp (a0, a1)) {
|
2014-03-18 01:21:52 +00:00
|
|
|
snprintf (ret, sizeof (ret), "%s %%= %s", r0, a0);
|
2016-06-17 12:26:24 +00:00
|
|
|
} else {
|
|
|
|
snprintf (ret, sizeof (ret), "%s = %s %% %s", r0, a0, a1);
|
|
|
|
}
|
2014-01-02 05:09:46 +00:00
|
|
|
break;
|
|
|
|
case R_ANAL_OP_TYPE_XCHG:
|
2016-06-17 12:26:24 +00:00
|
|
|
if (!a1 || !strcmp (a0, a1)) {
|
2014-01-02 05:09:46 +00:00
|
|
|
snprintf (ret, sizeof (ret), "tmp = %s; %s = %s; %s = tmp", r0, r0, a0, a0);
|
2016-06-17 12:26:24 +00:00
|
|
|
} else {
|
|
|
|
snprintf (ret, sizeof (ret), "%s = %s ^ %s", r0, a0, a1);
|
|
|
|
}
|
2014-01-02 05:09:46 +00:00
|
|
|
break;
|
|
|
|
case R_ANAL_OP_TYPE_ROL:
|
|
|
|
case R_ANAL_OP_TYPE_ROR:
|
|
|
|
case R_ANAL_OP_TYPE_SWITCH:
|
2014-08-11 02:52:53 +00:00
|
|
|
case R_ANAL_OP_TYPE_CASE:
|
2014-01-02 05:09:46 +00:00
|
|
|
eprintf ("Command not implemented.\n");
|
2014-01-04 04:03:24 +00:00
|
|
|
free (r0);
|
|
|
|
free (a0);
|
|
|
|
free (a1);
|
|
|
|
return NULL;
|
2010-06-21 09:55:48 +00:00
|
|
|
default:
|
2011-08-18 15:03:45 +00:00
|
|
|
free (r0);
|
|
|
|
free (a0);
|
|
|
|
free (a1);
|
|
|
|
return NULL;
|
2010-06-21 09:55:48 +00:00
|
|
|
}
|
|
|
|
free (r0);
|
|
|
|
free (a0);
|
|
|
|
free (a1);
|
2011-08-18 15:03:45 +00:00
|
|
|
return strdup (ret);
|
2010-06-21 09:55:48 +00:00
|
|
|
}
|
2014-09-22 11:45:36 +00:00
|
|
|
|
2016-06-15 23:43:41 +00:00
|
|
|
R_API const char *r_anal_stackop_tostring(int s) {
|
2014-09-22 11:45:36 +00:00
|
|
|
switch (s) {
|
|
|
|
case R_ANAL_STACK_NULL:
|
|
|
|
return "null";
|
|
|
|
case R_ANAL_STACK_NOP:
|
|
|
|
return "nop";
|
|
|
|
case R_ANAL_STACK_INC:
|
|
|
|
return "inc";
|
|
|
|
case R_ANAL_STACK_GET:
|
|
|
|
return "get";
|
|
|
|
case R_ANAL_STACK_SET:
|
|
|
|
return "set";
|
2016-05-11 10:59:32 +00:00
|
|
|
case R_ANAL_STACK_RESET:
|
|
|
|
return "reset";
|
2014-09-22 11:45:36 +00:00
|
|
|
}
|
|
|
|
return "unk";
|
|
|
|
}
|
2014-12-01 23:36:42 +00:00
|
|
|
|
2016-06-15 23:43:41 +00:00
|
|
|
R_API const char *r_anal_op_family_to_string(int n) {
|
2014-12-01 23:36:42 +00:00
|
|
|
switch (n) {
|
2015-10-03 11:52:52 +00:00
|
|
|
case R_ANAL_OP_FAMILY_UNKNOWN: return "unk";
|
2014-12-01 23:36:42 +00:00
|
|
|
case R_ANAL_OP_FAMILY_CPU: return "cpu";
|
2019-04-12 11:12:10 +00:00
|
|
|
case R_ANAL_OP_FAMILY_PAC: return "pac";
|
2014-12-01 23:36:42 +00:00
|
|
|
case R_ANAL_OP_FAMILY_FPU: return "fpu";
|
|
|
|
case R_ANAL_OP_FAMILY_MMX: return "mmx";
|
2017-05-21 22:56:24 +00:00
|
|
|
case R_ANAL_OP_FAMILY_SSE: return "sse";
|
2014-12-01 23:36:42 +00:00
|
|
|
case R_ANAL_OP_FAMILY_PRIV: return "priv";
|
2018-08-06 08:38:02 +00:00
|
|
|
case R_ANAL_OP_FAMILY_THREAD: return "thrd";
|
|
|
|
case R_ANAL_OP_FAMILY_CRYPTO: return "crpt";
|
|
|
|
case R_ANAL_OP_FAMILY_IO: return "io";
|
2016-06-15 23:43:41 +00:00
|
|
|
case R_ANAL_OP_FAMILY_VIRT: return "virt";
|
2014-12-01 23:36:42 +00:00
|
|
|
}
|
2018-08-11 14:39:18 +00:00
|
|
|
return NULL;
|
2014-12-01 23:36:42 +00:00
|
|
|
}
|
2016-06-15 23:43:41 +00:00
|
|
|
|
|
|
|
R_API int r_anal_op_family_from_string(const char *f) {
|
2018-12-20 10:48:19 +00:00
|
|
|
struct op_family {
|
|
|
|
const char *name;
|
|
|
|
int id;
|
|
|
|
};
|
|
|
|
static const struct op_family of[] = {
|
|
|
|
{"cpu", R_ANAL_OP_FAMILY_CPU},
|
|
|
|
{"fpu", R_ANAL_OP_FAMILY_FPU},
|
|
|
|
{"mmx", R_ANAL_OP_FAMILY_MMX},
|
|
|
|
{"sse", R_ANAL_OP_FAMILY_SSE},
|
|
|
|
{"priv", R_ANAL_OP_FAMILY_PRIV},
|
|
|
|
{"virt", R_ANAL_OP_FAMILY_VIRT},
|
|
|
|
{"crpt", R_ANAL_OP_FAMILY_CRYPTO},
|
|
|
|
{"io", R_ANAL_OP_FAMILY_IO},
|
2019-04-12 11:12:10 +00:00
|
|
|
{"pac", R_ANAL_OP_FAMILY_PAC},
|
2018-12-20 10:48:19 +00:00
|
|
|
{"thread", R_ANAL_OP_FAMILY_THREAD},
|
|
|
|
};
|
|
|
|
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < sizeof (of) / sizeof (of[0]); i ++) {
|
|
|
|
if (!strcmp (f, of[i].name)) {
|
|
|
|
return of[i].id;
|
|
|
|
}
|
2018-09-13 08:17:26 +00:00
|
|
|
}
|
2016-06-15 23:43:41 +00:00
|
|
|
return R_ANAL_OP_FAMILY_UNKNOWN;
|
|
|
|
}
|
2016-12-12 13:47:42 +00:00
|
|
|
|
|
|
|
/* apply hint to op, return the number of hints applied */
|
|
|
|
R_API int r_anal_op_hint(RAnalOp *op, RAnalHint *hint) {
|
|
|
|
int changes = 0;
|
|
|
|
if (hint) {
|
2019-07-07 16:51:21 +00:00
|
|
|
if (hint->val != UT64_MAX) {
|
|
|
|
op->val = hint->val;
|
|
|
|
changes++;
|
|
|
|
}
|
2019-01-16 23:26:39 +00:00
|
|
|
if (hint->type > 0) {
|
|
|
|
op->type = hint->type;
|
2016-12-12 13:47:42 +00:00
|
|
|
changes++;
|
2019-01-16 23:26:39 +00:00
|
|
|
}
|
|
|
|
if (hint->jump != UT64_MAX) {
|
2016-12-12 13:47:42 +00:00
|
|
|
op->jump = hint->jump;
|
2019-01-16 23:26:39 +00:00
|
|
|
changes++;
|
2016-12-12 13:47:42 +00:00
|
|
|
}
|
|
|
|
if (hint->fail != UT64_MAX) {
|
|
|
|
op->fail = hint->fail;
|
2019-01-16 23:26:39 +00:00
|
|
|
changes++;
|
2016-12-12 13:47:42 +00:00
|
|
|
}
|
|
|
|
if (hint->opcode) {
|
|
|
|
/* XXX: this is not correct */
|
|
|
|
free (op->mnemonic);
|
|
|
|
op->mnemonic = strdup (hint->opcode);
|
2019-01-16 23:26:39 +00:00
|
|
|
changes++;
|
2016-12-12 13:47:42 +00:00
|
|
|
}
|
|
|
|
if (hint->esil) {
|
|
|
|
r_strbuf_set (&op->esil, hint->esil);
|
2019-01-16 23:26:39 +00:00
|
|
|
changes++;
|
2016-12-12 13:47:42 +00:00
|
|
|
}
|
|
|
|
if (hint->size) {
|
|
|
|
op->size = hint->size;
|
2019-01-16 23:26:39 +00:00
|
|
|
changes++;
|
2016-12-12 13:47:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return changes;
|
|
|
|
}
|
2019-03-16 09:20:20 +00:00
|
|
|
|
|
|
|
// returns the '33' in 'rax + 33'
|
|
|
|
// returns value for the given register name in specific address / range
|
|
|
|
// imho this should not iterate, should be just a helper to get that value
|
|
|
|
R_API int r_anal_op_reg_delta(RAnal *anal, ut64 addr, const char *name) {
|
|
|
|
ut8 buf[32];
|
|
|
|
anal->iob.read_at (anal->iob.io, addr, buf, sizeof (buf));
|
|
|
|
RAnalOp op = { 0 };
|
|
|
|
if (r_anal_op (anal, &op, addr, buf, sizeof (buf), R_ANAL_OP_MASK_ALL) > 0) {
|
|
|
|
if (op.dst && op.dst->reg && op.dst->reg->name && (!name || !strcmp (op.dst->reg->name, name))) {
|
|
|
|
if (op.src[0]) {
|
|
|
|
return op.src[0]->delta;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|