2014-04-27 00:48:42 +00:00
|
|
|
/* radare - LGPL - Copyright 2010-2014 - nibble, pancake */
|
2010-03-12 02:05:20 +00:00
|
|
|
|
|
|
|
#include <r_anal.h>
|
|
|
|
#include <r_util.h>
|
|
|
|
#include <r_list.h>
|
|
|
|
|
2013-10-08 12:20:21 +00:00
|
|
|
#define FCN_DEPTH 32
|
2014-03-31 01:05:48 +00:00
|
|
|
#define DB a->sdb_fcns
|
2014-03-31 02:42:55 +00:00
|
|
|
#define EXISTS(x,y...) snprintf (key, sizeof(key)-1,x,##y),sdb_exists(DB,key)
|
|
|
|
#define SETKEY(x,y...) snprintf (key, sizeof (key)-1, x,##y);
|
2011-02-05 01:55:50 +00:00
|
|
|
|
2014-04-27 00:48:42 +00:00
|
|
|
R_API const char *r_anal_fcn_type_tostring(int type) {
|
|
|
|
switch (type) {
|
|
|
|
case R_ANAL_FCN_TYPE_NULL: return "null";
|
|
|
|
case R_ANAL_FCN_TYPE_FCN: return "fcn";
|
|
|
|
case R_ANAL_FCN_TYPE_LOC: return "loc";
|
|
|
|
case R_ANAL_FCN_TYPE_SYM: return "sym";
|
|
|
|
case R_ANAL_FCN_TYPE_IMP: return "imp";
|
|
|
|
case R_ANAL_FCN_TYPE_ROOT: return "root";
|
|
|
|
}
|
|
|
|
return "unk";
|
|
|
|
}
|
|
|
|
|
2012-07-19 02:54:22 +00:00
|
|
|
R_API RAnalFunction *r_anal_fcn_new() {
|
2013-02-12 01:42:34 +00:00
|
|
|
RAnalFunction *fcn = R_NEW0 (RAnalFunction);
|
2011-09-14 00:07:06 +00:00
|
|
|
if (!fcn) return NULL;
|
2012-07-19 02:54:22 +00:00
|
|
|
fcn->name = NULL;
|
|
|
|
fcn->dsc = NULL;
|
|
|
|
/* Function return type */
|
|
|
|
fcn->rets = 0;
|
2013-10-19 22:25:37 +00:00
|
|
|
fcn->size = 0;
|
2012-07-19 02:54:22 +00:00
|
|
|
/* Function qualifier: static/volatile/inline/naked/virtual */
|
|
|
|
fcn->fmod = R_ANAL_FQUALIFIER_NONE;
|
|
|
|
/* Function calling convention: cdecl/stdcall/fastcall/etc */
|
|
|
|
fcn->call = R_ANAL_CC_TYPE_NONE;
|
|
|
|
/* Function attributes: weak/noreturn/format/etc */
|
|
|
|
fcn->attr = NULL;
|
2011-09-14 00:07:06 +00:00
|
|
|
fcn->addr = -1;
|
2013-05-24 00:53:15 +00:00
|
|
|
fcn->bits = 0;
|
2014-04-04 01:42:22 +00:00
|
|
|
//fcn->vars = r_anal_var_list_new ();
|
2011-09-14 00:07:06 +00:00
|
|
|
fcn->refs = r_anal_ref_list_new ();
|
|
|
|
fcn->xrefs = r_anal_ref_list_new ();
|
|
|
|
fcn->bbs = r_anal_bb_list_new ();
|
|
|
|
fcn->fingerprint = NULL;
|
|
|
|
fcn->diff = r_anal_diff_new ();
|
2012-07-19 02:54:22 +00:00
|
|
|
fcn->args = NULL;
|
2012-08-28 02:56:59 +00:00
|
|
|
fcn->locs = NULL;
|
2014-03-31 01:05:48 +00:00
|
|
|
//fcn->locals = NULL;
|
2010-05-20 15:40:58 +00:00
|
|
|
return fcn;
|
2010-03-12 02:05:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
R_API RList *r_anal_fcn_list_new() {
|
|
|
|
RList *list = r_list_new ();
|
2011-09-14 00:07:06 +00:00
|
|
|
if (!list) return NULL;
|
2010-03-12 02:05:20 +00:00
|
|
|
list->free = &r_anal_fcn_free;
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2010-12-04 14:24:39 +00:00
|
|
|
R_API void r_anal_fcn_free(void *_fcn) {
|
2012-07-19 02:54:22 +00:00
|
|
|
RAnalFunction *fcn = _fcn;
|
2011-02-18 09:08:24 +00:00
|
|
|
if (!_fcn) return;
|
2012-09-28 00:20:52 +00:00
|
|
|
fcn->size = 0;
|
2011-02-18 09:08:24 +00:00
|
|
|
free (fcn->name);
|
2012-07-19 02:54:22 +00:00
|
|
|
free (fcn->attr);
|
2011-02-18 09:08:24 +00:00
|
|
|
r_list_free (fcn->refs);
|
|
|
|
r_list_free (fcn->xrefs);
|
|
|
|
r_list_free (fcn->vars);
|
2012-08-28 02:56:59 +00:00
|
|
|
r_list_free (fcn->locs);
|
2014-03-02 21:16:54 +00:00
|
|
|
#if 0
|
2014-05-03 12:19:23 +00:00
|
|
|
// XXX: some shared basic blocks make it crash.
|
2014-03-02 21:16:54 +00:00
|
|
|
// TODO: fix it with sdb
|
2011-02-18 09:08:24 +00:00
|
|
|
r_list_free (fcn->bbs);
|
2014-03-31 01:05:48 +00:00
|
|
|
//r_list_free (fcn->locals);
|
2014-03-02 21:16:54 +00:00
|
|
|
#endif
|
2011-02-18 09:08:24 +00:00
|
|
|
free (fcn->fingerprint);
|
|
|
|
r_anal_diff_free (fcn->diff);
|
2012-07-19 02:54:22 +00:00
|
|
|
free (fcn->args);
|
2010-03-12 02:05:20 +00:00
|
|
|
free (fcn);
|
|
|
|
}
|
|
|
|
|
2014-03-31 01:05:48 +00:00
|
|
|
R_API int r_anal_fcn_xref_add (RAnal *a, RAnalFunction *fcn, ut64 at, ut64 addr, int type) {
|
2011-09-28 00:48:03 +00:00
|
|
|
RAnalRef *ref;
|
2014-03-31 01:05:48 +00:00
|
|
|
if (!fcn || !a|| !(ref = r_anal_ref_new ()))
|
2011-09-28 00:48:03 +00:00
|
|
|
return R_FALSE;
|
2014-05-25 01:28:54 +00:00
|
|
|
// TODO: check if valid memory
|
2014-05-26 10:27:22 +00:00
|
|
|
if (addr < 0xff) {
|
|
|
|
free (ref);
|
2014-05-25 01:28:54 +00:00
|
|
|
return R_FALSE; // invalid reference
|
2014-05-26 10:27:22 +00:00
|
|
|
}
|
2014-03-31 02:42:55 +00:00
|
|
|
// set global reference
|
2014-05-05 15:31:10 +00:00
|
|
|
r_anal_xrefs_set (a, type, at, addr);
|
2014-03-31 02:42:55 +00:00
|
|
|
// set per-function reference
|
2014-03-31 01:05:48 +00:00
|
|
|
#if FCN_OLD
|
2013-06-25 21:44:21 +00:00
|
|
|
ref->at = at; // from
|
2013-02-13 16:54:20 +00:00
|
|
|
ref->addr = addr; // to
|
2012-08-31 09:45:06 +00:00
|
|
|
ref->type = type;
|
2011-09-28 00:48:03 +00:00
|
|
|
// TODO: ensure we are not dupping xrefs
|
|
|
|
r_list_append (fcn->refs, ref);
|
2014-03-31 01:05:48 +00:00
|
|
|
#endif
|
|
|
|
#if FCN_SDB
|
2014-05-12 09:04:46 +00:00
|
|
|
char key[1024];
|
2014-03-31 02:42:55 +00:00
|
|
|
SETKEY ("fcn.0x%08"PFMT64x".xrefs", fcn->addr);
|
2014-03-31 01:05:48 +00:00
|
|
|
sdb_array_add_num (DB, key, at, 0);
|
|
|
|
#endif
|
2011-09-28 00:48:03 +00:00
|
|
|
return R_TRUE;
|
|
|
|
}
|
|
|
|
|
2014-03-31 01:05:48 +00:00
|
|
|
R_API int r_anal_fcn_xref_del (RAnal *a, RAnalFunction *fcn, ut64 at, ut64 addr, int type) {
|
|
|
|
#if FCN_OLD
|
2011-09-28 00:48:03 +00:00
|
|
|
RAnalRef *ref;
|
|
|
|
RListIter *iter;
|
2013-02-12 01:42:34 +00:00
|
|
|
/* No need for _safe loop coz we return immediately after the delete. */
|
2011-09-28 00:48:03 +00:00
|
|
|
r_list_foreach (fcn->xrefs, iter, ref) {
|
|
|
|
if ((type != -1 || type == ref->type) &&
|
|
|
|
(at == 0LL || at == ref->at) &&
|
|
|
|
(addr == 0LL || addr == ref->addr)) {
|
|
|
|
r_list_delete (fcn->xrefs, iter);
|
|
|
|
return R_TRUE;
|
|
|
|
}
|
|
|
|
}
|
2014-03-31 01:05:48 +00:00
|
|
|
#endif
|
|
|
|
#if FCN_SDB
|
|
|
|
//sdb_array_delete_num (DB, key, at, 0);
|
|
|
|
#endif
|
2011-09-28 00:48:03 +00:00
|
|
|
return R_FALSE;
|
|
|
|
}
|
|
|
|
|
2013-10-08 02:58:51 +00:00
|
|
|
static RAnalBlock *bbget(RAnalFunction *fcn, ut64 addr) {
|
|
|
|
RListIter *iter;
|
|
|
|
RAnalBlock *bb;
|
|
|
|
r_list_foreach (fcn->bbs, iter, bb) {
|
|
|
|
if (bb->addr == addr)
|
|
|
|
return bb;
|
|
|
|
if (addr >= bb->addr && (addr < bb->addr+bb->size))
|
|
|
|
return bb;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-10-08 12:20:21 +00:00
|
|
|
#if 0
|
2013-10-08 02:58:51 +00:00
|
|
|
static int bbsum(RAnalFunction *fcn) {
|
|
|
|
RListIter *iter;
|
|
|
|
RAnalBlock *bb;
|
|
|
|
ut32 size = 0;
|
|
|
|
r_list_foreach (fcn->bbs, iter, bb) {
|
|
|
|
size += bb->size;
|
|
|
|
}
|
|
|
|
return size;
|
|
|
|
}
|
2013-10-08 12:20:21 +00:00
|
|
|
#endif
|
2013-10-08 02:58:51 +00:00
|
|
|
|
2013-10-16 23:04:05 +00:00
|
|
|
#define FITFCNSZ() {st64 n=bb->addr+bb->size-fcn->addr; \
|
|
|
|
if(n<0) { fcn->addr += n; fcn->size = -n; } else \
|
|
|
|
if(fcn->size<n)fcn->size=n; }
|
2013-10-08 12:20:21 +00:00
|
|
|
static int fcn_recurse(RAnal *anal, RAnalFunction *fcn, ut64 addr, ut8 *buf, ut64 len, int depth) {
|
2013-10-19 22:25:37 +00:00
|
|
|
int ret = R_ANAL_RET_END;
|
2013-10-08 02:58:51 +00:00
|
|
|
ut8 bbuf[8096];
|
|
|
|
int overlapped = 0;
|
2010-03-12 02:05:20 +00:00
|
|
|
char *varname;
|
2013-10-08 02:58:51 +00:00
|
|
|
RAnalOp op = {0};
|
2010-03-12 02:05:20 +00:00
|
|
|
int oplen, idx = 0;
|
2014-05-15 20:49:01 +00:00
|
|
|
int delay_cnt = 0, delay_idx = 0, delay_next = 0, delay_done = 0;
|
2014-06-02 12:54:31 +00:00
|
|
|
int delay_fin = 0;
|
2013-10-08 02:58:51 +00:00
|
|
|
// add basic block
|
|
|
|
RAnalBlock *bb = NULL;
|
|
|
|
RAnalBlock *bbg = NULL;
|
2014-05-26 08:37:18 +00:00
|
|
|
if (depth<1) {
|
2013-10-08 12:20:21 +00:00
|
|
|
return R_ANAL_RET_ERROR; // MUST BE TOO DEEP
|
2014-05-26 08:37:18 +00:00
|
|
|
}
|
|
|
|
if (bbget (fcn, addr)) {
|
2013-10-08 02:58:51 +00:00
|
|
|
return R_ANAL_RET_ERROR; // MUST BE DUP
|
2014-05-26 08:37:18 +00:00
|
|
|
}
|
2013-10-25 08:42:46 +00:00
|
|
|
bb = r_anal_bb_new();
|
2013-10-08 02:58:51 +00:00
|
|
|
bb->addr = addr;
|
|
|
|
bb->size = 0;
|
|
|
|
bb->jump = UT64_MAX;
|
|
|
|
bb->fail = UT64_MAX;
|
|
|
|
bb->type = 0; // TODO
|
|
|
|
r_list_append (fcn->bbs, bb);
|
2012-02-15 10:11:25 +00:00
|
|
|
|
2010-03-12 02:05:20 +00:00
|
|
|
while (idx < len) {
|
2011-11-13 23:21:25 +00:00
|
|
|
r_anal_op_fini (&op);
|
2013-10-16 23:04:05 +00:00
|
|
|
if (buf[idx]==buf[idx+1] && buf[idx]==0xff && buf[idx+2]==0xff) {
|
|
|
|
FITFCNSZ();
|
2012-02-15 10:11:25 +00:00
|
|
|
return R_ANAL_RET_ERROR;
|
2013-10-16 23:04:05 +00:00
|
|
|
}
|
2013-10-08 02:58:51 +00:00
|
|
|
// check if opcode is in another basic block
|
|
|
|
// in that case we break
|
2012-02-15 10:11:25 +00:00
|
|
|
if ((oplen = r_anal_op (anal, &op, addr+idx, buf+idx, len-idx)) < 1) {
|
2010-08-25 00:27:42 +00:00
|
|
|
if (idx == 0) {
|
2012-08-31 09:45:06 +00:00
|
|
|
VERBOSE_ANAL eprintf ("Unknown opcode at 0x%08"PFMT64x"\n", addr+idx);
|
2011-11-13 23:21:25 +00:00
|
|
|
r_anal_op_fini (&op);
|
2013-10-16 23:04:05 +00:00
|
|
|
FITFCNSZ();
|
2010-11-25 23:44:47 +00:00
|
|
|
return R_ANAL_RET_END;
|
2013-10-08 02:58:51 +00:00
|
|
|
} else break; // unspecified behaviour
|
|
|
|
}
|
|
|
|
if (idx>0 && !overlapped) {
|
|
|
|
bbg = bbget (fcn, addr+idx);
|
|
|
|
if (bbg && bbg != bb) {
|
|
|
|
bb->jump = addr+idx;
|
|
|
|
overlapped = 1;
|
|
|
|
//return R_ANAL_RET_END;
|
|
|
|
}
|
2010-03-12 02:05:20 +00:00
|
|
|
}
|
|
|
|
idx += oplen;
|
2013-10-08 02:58:51 +00:00
|
|
|
if (!overlapped) {
|
|
|
|
bb->size += oplen;
|
|
|
|
fcn->ninstr++;
|
2013-10-19 22:25:37 +00:00
|
|
|
FITFCNSZ();
|
2013-10-16 23:04:05 +00:00
|
|
|
// fcn->size += oplen; /// XXX. must be the sum of all the bblocks
|
2013-10-08 02:58:51 +00:00
|
|
|
}
|
2014-05-10 16:04:34 +00:00
|
|
|
if (delay_cnt>0) {
|
|
|
|
if (op.delay>0) {
|
|
|
|
return R_ANAL_RET_ERROR;
|
|
|
|
}
|
|
|
|
delay_cnt--;
|
|
|
|
if (delay_cnt==0) {
|
2014-05-11 00:19:03 +00:00
|
|
|
delay_next = idx;
|
2014-05-10 16:04:34 +00:00
|
|
|
idx = delay_idx;
|
|
|
|
delay_done = 1;
|
2014-05-11 00:19:03 +00:00
|
|
|
//break;
|
2014-06-02 12:54:31 +00:00
|
|
|
|
|
|
|
// At this point, we are looking at the last instruction in the branch delay group.
|
2014-05-10 16:04:34 +00:00
|
|
|
}
|
|
|
|
}
|
2014-06-02 12:54:31 +00:00
|
|
|
delay_fin = 0;
|
2014-05-10 16:04:34 +00:00
|
|
|
if (op.delay>0) {
|
|
|
|
if (!delay_done) {
|
|
|
|
delay_idx = idx - oplen;
|
|
|
|
delay_cnt = op.delay;
|
2014-05-11 00:19:03 +00:00
|
|
|
continue;
|
2014-05-10 16:04:34 +00:00
|
|
|
} else {
|
2014-05-11 00:19:03 +00:00
|
|
|
idx = delay_next;
|
2014-05-15 20:47:20 +00:00
|
|
|
delay_idx = delay_cnt = delay_done = 0;
|
2014-06-02 12:54:31 +00:00
|
|
|
// If delay_done is 1, then it means
|
|
|
|
// this is the second time we are looking at op.*
|
|
|
|
// and op* is for addr+delay_idx, _not_ addr+delay_next
|
|
|
|
// Which means the switch statement below will have the
|
|
|
|
// wrong value for idx due to `idx = delay_next` above,
|
|
|
|
// so beware...
|
|
|
|
// additionally, if the starting opcode in the
|
|
|
|
// branch delay group is actually a function return
|
|
|
|
// we need to take care to avoid over-stating the
|
|
|
|
// size of the function because we double-counted
|
|
|
|
// (idx += oplen, etc) above
|
|
|
|
delay_fin = 1;
|
2014-05-10 16:04:34 +00:00
|
|
|
}
|
|
|
|
}
|
2010-12-03 12:52:11 +00:00
|
|
|
/* TODO: Parse fastargs (R_ANAL_VAR_ARGREG) */
|
2011-02-24 13:06:49 +00:00
|
|
|
switch (op.stackop) {
|
2013-04-23 01:38:39 +00:00
|
|
|
case R_ANAL_STACK_INC:
|
2013-06-09 01:25:32 +00:00
|
|
|
fcn->stack += op.val;
|
2010-05-19 00:39:01 +00:00
|
|
|
break;
|
2012-08-31 09:45:06 +00:00
|
|
|
// TODO: use fcn->stack to know our stackframe
|
2010-05-14 21:04:10 +00:00
|
|
|
case R_ANAL_STACK_SET:
|
2013-06-09 01:25:32 +00:00
|
|
|
if (op.ptr > 0) {
|
2013-12-03 23:20:52 +00:00
|
|
|
varname = r_str_newf ("arg_%x", op.ptr);
|
2014-05-12 09:04:46 +00:00
|
|
|
r_anal_var_add (anal, fcn->addr, op.addr, op.ptr,
|
2012-07-22 08:00:35 +00:00
|
|
|
R_ANAL_VAR_SCOPE_ARG|R_ANAL_VAR_DIR_IN, NULL, varname, 1);
|
2010-03-12 02:05:20 +00:00
|
|
|
} else {
|
2013-12-03 23:20:52 +00:00
|
|
|
varname = r_str_newf ("local_%x", -op.ptr);
|
2014-05-12 09:04:46 +00:00
|
|
|
r_anal_var_add (anal, fcn->addr, op.addr, -op.ptr,
|
2012-07-22 08:00:35 +00:00
|
|
|
R_ANAL_VAR_SCOPE_LOCAL|R_ANAL_VAR_DIR_NONE, NULL, varname, 1);
|
2010-03-12 02:05:20 +00:00
|
|
|
}
|
|
|
|
free (varname);
|
|
|
|
break;
|
2012-08-31 09:45:06 +00:00
|
|
|
// TODO: use fcn->stack to know our stackframe
|
2010-05-14 21:04:10 +00:00
|
|
|
case R_ANAL_STACK_GET:
|
2013-06-09 01:25:32 +00:00
|
|
|
if (op.ptr > 0) {
|
2013-12-03 23:20:52 +00:00
|
|
|
varname = r_str_newf ("arg_%x", op.ptr);
|
2014-05-26 08:37:18 +00:00
|
|
|
r_anal_var_add (anal, fcn, op.addr, op.ptr, 'a', NULL, varname, 0);
|
|
|
|
//R_ANAL_VAR_SCOPE_ARG|R_ANAL_VAR_DIR_IN, NULL, varname, 0);
|
2010-03-12 02:05:20 +00:00
|
|
|
} else {
|
2013-12-03 23:20:52 +00:00
|
|
|
varname = r_str_newf ("local_%x", -op.ptr);
|
2014-05-26 08:37:18 +00:00
|
|
|
r_anal_var_add (anal, fcn, op.addr, -op.ptr, 'v', NULL, varname, 0);
|
|
|
|
//R_ANAL_VAR_SCOPE_LOCAL|R_ANAL_VAR_DIR_NONE, NULL, varname, 0);
|
2010-03-12 02:05:20 +00:00
|
|
|
}
|
|
|
|
free (varname);
|
|
|
|
break;
|
|
|
|
}
|
2014-01-23 01:31:51 +00:00
|
|
|
if (op.ptr && op.ptr != UT64_MAX && op.ptr != UT32_MAX) {
|
2013-10-12 00:19:01 +00:00
|
|
|
// swapped parameters wtf //
|
2014-01-19 23:14:00 +00:00
|
|
|
//if (!r_anal_fcn_xref_add (anal, fcn, op.ptr, op.addr, 'd')) {
|
|
|
|
if (!r_anal_fcn_xref_add (anal, fcn, op.addr, op.ptr, 'd')) {
|
2014-05-26 08:37:18 +00:00
|
|
|
#if 0
|
2013-07-19 01:35:45 +00:00
|
|
|
r_anal_op_fini (&op);
|
2014-01-19 23:14:00 +00:00
|
|
|
FITFCNSZ ();
|
2013-07-19 01:35:45 +00:00
|
|
|
return R_ANAL_RET_ERROR;
|
2014-05-26 08:37:18 +00:00
|
|
|
#endif
|
2013-07-19 01:35:45 +00:00
|
|
|
}
|
|
|
|
}
|
2011-02-24 13:06:49 +00:00
|
|
|
switch (op.type) {
|
2014-04-07 11:49:09 +00:00
|
|
|
case R_ANAL_OP_TYPE_NOP:
|
|
|
|
if ((addr+idx-oplen) == fcn->addr) {
|
|
|
|
fcn->addr = bb->addr = addr + idx;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
2010-06-13 22:57:40 +00:00
|
|
|
case R_ANAL_OP_TYPE_JMP:
|
2013-06-26 08:11:51 +00:00
|
|
|
if (!r_anal_fcn_xref_add (anal, fcn, op.addr, op.jump,
|
|
|
|
R_ANAL_REF_TYPE_CODE)) {
|
2014-05-26 08:37:18 +00:00
|
|
|
#if 0
|
2013-10-19 22:25:37 +00:00
|
|
|
FITFCNSZ();
|
2013-06-26 08:11:51 +00:00
|
|
|
r_anal_op_fini (&op);
|
|
|
|
return R_ANAL_RET_ERROR;
|
2013-10-08 02:58:51 +00:00
|
|
|
#endif
|
2014-05-26 08:37:18 +00:00
|
|
|
}
|
2013-10-08 02:58:51 +00:00
|
|
|
if (!overlapped) {
|
|
|
|
bb->jump = op.jump;
|
|
|
|
bb->fail = UT64_MAX;
|
|
|
|
}
|
|
|
|
// hardcoded jmp size // must be checked at the end wtf?
|
2013-10-16 23:04:05 +00:00
|
|
|
if (op.jump>fcn->addr && op.jump<(fcn->addr+fcn->size)) {
|
|
|
|
/* jump inside the same function */
|
2013-10-19 22:25:37 +00:00
|
|
|
FITFCNSZ();
|
|
|
|
return R_ANAL_RET_END;
|
2013-10-16 23:04:05 +00:00
|
|
|
} else {
|
|
|
|
if (op.jump < addr-512 && op.jump<addr) {
|
|
|
|
FITFCNSZ();
|
|
|
|
return R_ANAL_RET_END;
|
|
|
|
}
|
|
|
|
if (op.jump > addr+512) {
|
|
|
|
FITFCNSZ();
|
2014-05-03 12:19:23 +00:00
|
|
|
return R_ANAL_RET_END;
|
2013-10-16 23:04:05 +00:00
|
|
|
}
|
|
|
|
}
|
2013-10-25 00:06:00 +00:00
|
|
|
break;
|
2013-10-08 02:58:51 +00:00
|
|
|
//
|
2013-10-25 00:06:00 +00:00
|
|
|
//FITFCNSZ();
|
|
|
|
//return R_ANAL_RET_END;
|
2014-05-03 12:19:23 +00:00
|
|
|
/// DO not follow jmps.. this is probably a bug ...
|
2013-10-19 22:25:37 +00:00
|
|
|
#if 0
|
2013-10-08 12:20:21 +00:00
|
|
|
anal->iob.read_at (anal->iob.io, op.jump, bbuf, sizeof (bbuf));
|
2013-10-16 23:04:05 +00:00
|
|
|
FITFCNSZ();
|
2013-10-08 12:20:21 +00:00
|
|
|
return fcn_recurse (anal, fcn, op.jump, bbuf, sizeof (bbuf), depth-1);
|
2013-10-19 22:25:37 +00:00
|
|
|
#endif
|
2010-08-02 10:42:59 +00:00
|
|
|
case R_ANAL_OP_TYPE_CJMP:
|
2014-05-05 15:31:10 +00:00
|
|
|
if (!r_anal_fcn_xref_add (anal, fcn, op.addr, op.jump,
|
|
|
|
R_ANAL_REF_TYPE_CODE)) {
|
2014-05-26 08:37:18 +00:00
|
|
|
FITFCNSZ();
|
|
|
|
/// XXX. fcn_xref_add returning false shouldnt result in fcn chop
|
|
|
|
#if 0
|
|
|
|
r_anal_op_fini (&op);
|
|
|
|
eprintf ("ERR CJMP JAJAJWAT\n");
|
|
|
|
return R_ANAL_RET_ERROR;
|
|
|
|
#endif
|
2014-05-05 15:31:10 +00:00
|
|
|
}
|
|
|
|
|
2013-10-08 02:58:51 +00:00
|
|
|
if (!overlapped) {
|
|
|
|
bb->jump = op.jump;
|
|
|
|
bb->fail = op.fail;
|
|
|
|
}
|
|
|
|
anal->iob.read_at (anal->iob.io, op.jump, bbuf, sizeof (bbuf));
|
2013-10-16 23:04:05 +00:00
|
|
|
FITFCNSZ();
|
2013-10-08 12:20:21 +00:00
|
|
|
fcn_recurse (anal, fcn, op.jump, bbuf, sizeof (bbuf), depth-1);
|
2013-10-08 02:58:51 +00:00
|
|
|
anal->iob.read_at (anal->iob.io, op.fail, bbuf, sizeof (bbuf));
|
2013-10-16 23:04:05 +00:00
|
|
|
FITFCNSZ();
|
2013-10-08 12:20:21 +00:00
|
|
|
return fcn_recurse (anal, fcn, op.fail, bbuf, sizeof (bbuf), depth-1);
|
2012-08-31 09:45:06 +00:00
|
|
|
#if 0
|
|
|
|
// do not add xrefs for cjmps?
|
|
|
|
r_anal_op_fini (&op);
|
|
|
|
#endif
|
2013-09-11 22:41:01 +00:00
|
|
|
break;
|
2010-03-12 02:05:20 +00:00
|
|
|
case R_ANAL_OP_TYPE_CALL:
|
2011-09-28 00:48:03 +00:00
|
|
|
if (!r_anal_fcn_xref_add (anal, fcn, op.addr, op.jump,
|
|
|
|
op.type == R_ANAL_OP_TYPE_CALL?
|
2011-11-13 23:21:25 +00:00
|
|
|
R_ANAL_REF_TYPE_CALL : R_ANAL_REF_TYPE_CODE)) {
|
2013-10-08 02:58:51 +00:00
|
|
|
//fcn->size = bbsum (fcn);
|
2014-04-07 11:49:09 +00:00
|
|
|
FITFCNSZ ();
|
2014-05-26 08:37:18 +00:00
|
|
|
#if 0
|
|
|
|
r_anal_op_fini (&op);
|
2010-03-12 02:05:20 +00:00
|
|
|
return R_ANAL_RET_ERROR;
|
2014-05-26 08:37:18 +00:00
|
|
|
#endif
|
2011-11-13 23:21:25 +00:00
|
|
|
}
|
2010-03-12 02:05:20 +00:00
|
|
|
break;
|
2014-04-07 11:49:09 +00:00
|
|
|
//case R_ANAL_OP_TYPE_HLT:
|
2012-02-15 21:09:23 +00:00
|
|
|
case R_ANAL_OP_TYPE_TRAP:
|
|
|
|
case R_ANAL_OP_TYPE_UJMP:
|
2010-03-12 02:05:20 +00:00
|
|
|
case R_ANAL_OP_TYPE_RET:
|
2014-06-02 12:54:31 +00:00
|
|
|
if (delay_fin) {
|
|
|
|
// Don't double count the first instruction in
|
|
|
|
// the branch delay group when we pass back
|
|
|
|
// through the loop, _if_ this is a return of some kind
|
|
|
|
idx -= oplen;
|
|
|
|
bb->size -= oplen;
|
|
|
|
fcn->size -= oplen;
|
|
|
|
fcn->ninstr--;
|
|
|
|
}
|
2013-10-16 23:04:05 +00:00
|
|
|
FITFCNSZ();
|
2013-10-19 22:25:37 +00:00
|
|
|
r_anal_op_fini (&op);
|
2013-10-08 02:58:51 +00:00
|
|
|
//fcn->size = bbsum (fcn);
|
2010-03-12 02:05:20 +00:00
|
|
|
return R_ANAL_RET_END;
|
|
|
|
}
|
|
|
|
}
|
2011-11-13 23:21:25 +00:00
|
|
|
r_anal_op_fini (&op);
|
2013-10-19 22:25:37 +00:00
|
|
|
FITFCNSZ ();
|
2013-10-08 02:58:51 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API int r_anal_fcn(RAnal *anal, RAnalFunction *fcn, ut64 addr, ut8 *buf, ut64 len, int reftype) {
|
2013-10-19 22:25:37 +00:00
|
|
|
fcn->size = 0;
|
2013-10-08 02:58:51 +00:00
|
|
|
fcn->type = (reftype==R_ANAL_REF_TYPE_CODE)?
|
2014-01-02 05:09:46 +00:00
|
|
|
R_ANAL_FCN_TYPE_LOC: R_ANAL_FCN_TYPE_FCN;
|
2014-05-03 12:19:23 +00:00
|
|
|
|
2014-01-02 05:09:46 +00:00
|
|
|
if (fcn->addr == UT64_MAX) fcn->addr = addr;
|
|
|
|
|
|
|
|
if (anal->cur && anal->cur->fcn){
|
|
|
|
int result = anal->cur->fcn(anal, fcn, addr, buf, len, reftype);
|
|
|
|
if (anal->cur->custom_fn_anal) return result;
|
|
|
|
}
|
2014-05-03 12:19:23 +00:00
|
|
|
|
2013-10-08 02:58:51 +00:00
|
|
|
//if (len>16)
|
|
|
|
// len -= 16; // XXX: hack to avoid buffer overflow by reading >64 bytes..
|
2013-10-08 12:20:21 +00:00
|
|
|
return fcn_recurse (anal, fcn, addr, buf, len, FCN_DEPTH);
|
2010-03-12 02:05:20 +00:00
|
|
|
}
|
2010-04-07 11:43:50 +00:00
|
|
|
|
2012-07-19 02:54:22 +00:00
|
|
|
// TODO: need to implement r_anal_fcn_remove(RAnal *anal, RAnalFunction *fcn);
|
|
|
|
R_API int r_anal_fcn_insert(RAnal *anal, RAnalFunction *fcn) {
|
2014-03-02 21:16:54 +00:00
|
|
|
RAnalFunction *f = r_anal_fcn_find (anal, fcn->addr,
|
|
|
|
R_ANAL_FCN_TYPE_ROOT);
|
2013-10-19 22:25:37 +00:00
|
|
|
if (f) return R_FALSE;
|
2011-09-14 01:47:30 +00:00
|
|
|
#if USE_NEW_FCN_STORE
|
|
|
|
r_listrange_add (anal->fcnstore, fcn);
|
2011-09-20 07:44:17 +00:00
|
|
|
// HUH? store it here .. for backweird compatibility
|
2014-04-10 17:17:24 +00:00
|
|
|
#endif
|
|
|
|
#if ANAL_FCN_SDB
|
|
|
|
#if 0
|
2014-05-03 12:19:23 +00:00
|
|
|
// override bits, size,
|
2014-04-10 17:17:24 +00:00
|
|
|
fcn.<offset>=name,size,type
|
2014-04-11 23:13:34 +00:00
|
|
|
fcn.<offset>.bbs
|
2014-04-10 17:17:24 +00:00
|
|
|
fcn.name.<name>=<offset>
|
|
|
|
#endif
|
2014-04-11 23:13:34 +00:00
|
|
|
sdb_set (DB, "fcn.0x080", "", 0);
|
2011-09-14 01:47:30 +00:00
|
|
|
#endif
|
2014-03-02 21:16:54 +00:00
|
|
|
r_list_append (anal->fcns, fcn);
|
2011-09-14 01:47:30 +00:00
|
|
|
return R_TRUE;
|
|
|
|
}
|
|
|
|
|
2014-03-31 01:05:48 +00:00
|
|
|
R_API int r_anal_fcn_add(RAnal *a, ut64 addr, ut64 size, const char *name, int type, RAnalDiff *diff) {
|
2010-05-24 23:31:52 +00:00
|
|
|
int append = 0;
|
2014-03-31 01:05:48 +00:00
|
|
|
RAnalFunction *fcn = r_anal_fcn_find (a, addr, R_ANAL_FCN_TYPE_ROOT);
|
2010-05-24 11:57:49 +00:00
|
|
|
if (fcn == NULL) {
|
|
|
|
if (!(fcn = r_anal_fcn_new ()))
|
|
|
|
return R_FALSE;
|
|
|
|
append = 1;
|
|
|
|
}
|
2010-04-07 11:43:50 +00:00
|
|
|
fcn->addr = addr;
|
|
|
|
fcn->size = size;
|
2010-05-24 11:57:49 +00:00
|
|
|
free (fcn->name);
|
2010-04-07 11:43:50 +00:00
|
|
|
fcn->name = strdup (name);
|
2010-11-23 16:15:33 +00:00
|
|
|
fcn->type = type;
|
2010-12-05 07:46:56 +00:00
|
|
|
if (diff) {
|
|
|
|
fcn->diff->type = diff->type;
|
|
|
|
fcn->diff->addr = diff->addr;
|
|
|
|
R_FREE (fcn->diff->name);
|
|
|
|
if (diff->name)
|
|
|
|
fcn->diff->name = strdup (diff->name);
|
|
|
|
}
|
2014-03-31 01:05:48 +00:00
|
|
|
#if FCN_SDB
|
|
|
|
char key[128];
|
|
|
|
SETKEY ("fcn.0x%08"PFMT64x, addr);
|
|
|
|
sdb_set (DB, key, "TODO", 0); // TODO: add more info here
|
|
|
|
#endif
|
|
|
|
return append? r_anal_fcn_insert (a, fcn): R_TRUE;
|
2010-04-07 11:43:50 +00:00
|
|
|
}
|
|
|
|
|
2012-09-28 00:20:52 +00:00
|
|
|
R_API int r_anal_fcn_del_locs(RAnal *anal, ut64 addr) {
|
|
|
|
RListIter *iter, *iter2;
|
2014-03-02 21:16:54 +00:00
|
|
|
RAnalFunction *fcn, *f = r_anal_fcn_find (anal, addr,
|
|
|
|
R_ANAL_FCN_TYPE_ROOT);
|
2012-09-28 00:20:52 +00:00
|
|
|
#if USE_NEW_FCN_STORE
|
|
|
|
#warning TODO: r_anal_fcn_del_locs not implemented for newstore
|
|
|
|
#endif
|
2012-10-30 09:08:06 +00:00
|
|
|
if (!f) return R_FALSE;
|
|
|
|
r_list_foreach_safe (anal->fcns, iter, iter2, fcn) {
|
|
|
|
if (fcn->type != R_ANAL_FCN_TYPE_LOC)
|
|
|
|
continue;
|
|
|
|
if (fcn->addr >= f->addr && fcn->addr < (f->addr+f->size))
|
|
|
|
r_list_delete (anal->fcns, iter);
|
2012-09-28 00:20:52 +00:00
|
|
|
}
|
|
|
|
r_anal_fcn_del (anal, addr);
|
|
|
|
return R_TRUE;
|
|
|
|
}
|
|
|
|
|
2014-03-31 02:42:55 +00:00
|
|
|
R_API int r_anal_fcn_del(RAnal *a, ut64 addr) {
|
2012-10-30 09:08:06 +00:00
|
|
|
if (addr == UT64_MAX) {
|
2011-09-14 01:47:30 +00:00
|
|
|
#if USE_NEW_FCN_STORE
|
2014-03-31 02:42:55 +00:00
|
|
|
r_listrange_free (a->fcnstore);
|
|
|
|
a->fcnstore = r_listrange_new ();
|
2011-09-14 01:47:30 +00:00
|
|
|
#else
|
2014-03-31 02:42:55 +00:00
|
|
|
r_list_free (a->fcns);
|
|
|
|
if (!(a->fcns = r_anal_fcn_list_new ()))
|
2010-04-07 11:43:50 +00:00
|
|
|
return R_FALSE;
|
2011-09-14 01:47:30 +00:00
|
|
|
#endif
|
2011-09-14 00:07:06 +00:00
|
|
|
} else {
|
|
|
|
#if USE_NEW_FCN_STORE
|
|
|
|
// XXX: must only get the function if starting at 0?
|
2014-03-31 02:42:55 +00:00
|
|
|
RAnalFunction *f = r_listrange_find_in_range (a->fcnstore, addr);
|
|
|
|
if (f) r_listrange_del (a->fcnstore, f);
|
2011-09-14 00:07:06 +00:00
|
|
|
#else
|
2012-07-19 02:54:22 +00:00
|
|
|
RAnalFunction *fcni;
|
2012-02-14 17:10:52 +00:00
|
|
|
RListIter *iter, *iter_tmp;
|
2014-03-31 02:42:55 +00:00
|
|
|
r_list_foreach_safe (a->fcns, iter, iter_tmp, fcni) {
|
2011-09-14 00:07:06 +00:00
|
|
|
if (addr >= fcni->addr && addr < fcni->addr+fcni->size) {
|
2014-03-31 02:42:55 +00:00
|
|
|
r_list_delete (a->fcns, iter);
|
2011-09-14 00:07:06 +00:00
|
|
|
}
|
2011-04-29 11:55:27 +00:00
|
|
|
}
|
2011-09-14 00:07:06 +00:00
|
|
|
#endif
|
2011-04-29 11:55:27 +00:00
|
|
|
}
|
2010-04-07 11:43:50 +00:00
|
|
|
return R_TRUE;
|
|
|
|
}
|
2010-05-19 00:39:01 +00:00
|
|
|
|
2012-07-19 02:54:22 +00:00
|
|
|
R_API RAnalFunction *r_anal_fcn_find(RAnal *anal, ut64 addr, int type) {
|
2011-09-14 00:07:06 +00:00
|
|
|
#if USE_NEW_FCN_STORE
|
|
|
|
// TODO: type is ignored here? wtf.. we need more work on fcnstore
|
2013-02-12 01:42:34 +00:00
|
|
|
//if (root) return r_listrange_find_root (anal->fcnstore, addr);
|
2013-05-21 23:49:18 +00:00
|
|
|
RAnalFunction *f = r_listrange_find_in_range (anal->fcnstore, addr);
|
|
|
|
return (f->addr == addr)? f: NULL;
|
2011-09-14 00:07:06 +00:00
|
|
|
#else
|
2012-07-19 02:54:22 +00:00
|
|
|
RAnalFunction *fcn, *ret = NULL;
|
2010-07-03 01:35:26 +00:00
|
|
|
RListIter *iter;
|
2011-11-15 22:40:28 +00:00
|
|
|
if (type == R_ANAL_FCN_TYPE_ROOT) {
|
|
|
|
r_list_foreach (anal->fcns, iter, fcn) {
|
|
|
|
if (addr == fcn->addr)
|
|
|
|
return fcn;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-07-03 01:35:26 +00:00
|
|
|
r_list_foreach (anal->fcns, iter, fcn) {
|
2011-11-15 22:40:28 +00:00
|
|
|
if (!type || (fcn->type & type)) {
|
2014-05-03 12:19:23 +00:00
|
|
|
if (addr == fcn->addr || (ret == NULL &&
|
2013-10-16 23:04:05 +00:00
|
|
|
((addr > fcn->addr) && (addr < fcn->addr+fcn->size))))
|
2012-07-17 08:00:23 +00:00
|
|
|
ret = fcn;
|
2011-09-14 00:07:06 +00:00
|
|
|
}
|
2010-07-03 01:35:26 +00:00
|
|
|
}
|
2010-11-23 18:55:31 +00:00
|
|
|
return ret;
|
2011-09-14 00:07:06 +00:00
|
|
|
#endif
|
2010-07-03 01:35:26 +00:00
|
|
|
}
|
2010-07-12 19:37:40 +00:00
|
|
|
|
2013-06-25 21:44:21 +00:00
|
|
|
R_API RAnalFunction *r_anal_fcn_find_name(RAnal *anal, const char *name) {
|
|
|
|
RAnalFunction *fcn = NULL;
|
|
|
|
RListIter *iter;
|
|
|
|
r_list_foreach (anal->fcns, iter, fcn) {
|
2013-10-16 23:04:05 +00:00
|
|
|
if (!strcmp (name, fcn->name))
|
2013-06-25 21:44:21 +00:00
|
|
|
return fcn;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-07-19 02:54:22 +00:00
|
|
|
/* rename RAnalFunctionBB.add() */
|
|
|
|
R_API int r_anal_fcn_add_bb(RAnalFunction *fcn, ut64 addr, ut64 size, ut64 jump, ut64 fail, int type, RAnalDiff *diff) {
|
2011-02-11 10:22:43 +00:00
|
|
|
RAnalBlock *bb = NULL, *bbi;
|
|
|
|
RListIter *iter;
|
|
|
|
int append = 0, mid = 0;
|
|
|
|
|
|
|
|
r_list_foreach (fcn->bbs, iter, bbi) {
|
|
|
|
if (addr == bbi->addr) {
|
|
|
|
bb = bbi;
|
|
|
|
mid = 0;
|
|
|
|
break;
|
2011-09-14 00:07:06 +00:00
|
|
|
} else
|
|
|
|
if (addr > bbi->addr && addr < bbi->addr+bbi->size)
|
2011-02-11 10:22:43 +00:00
|
|
|
mid = 1;
|
|
|
|
}
|
|
|
|
if (mid)
|
|
|
|
return R_FALSE;
|
|
|
|
if (bb == NULL) {
|
|
|
|
if (!(bb = r_anal_bb_new ()))
|
|
|
|
return R_FALSE;
|
|
|
|
append = 1;
|
|
|
|
}
|
|
|
|
bb->addr = addr;
|
|
|
|
bb->size = size;
|
|
|
|
bb->jump = jump;
|
|
|
|
bb->fail = fail;
|
|
|
|
bb->type = type;
|
|
|
|
if (diff) {
|
|
|
|
bb->diff->type = diff->type;
|
|
|
|
bb->diff->addr = diff->addr;
|
|
|
|
R_FREE (bb->diff->name);
|
|
|
|
if (diff->name)
|
|
|
|
bb->diff->name = strdup (diff->name);
|
|
|
|
}
|
|
|
|
if (append) r_list_append (fcn->bbs, bb);
|
|
|
|
return R_TRUE;
|
|
|
|
}
|
|
|
|
|
2011-09-14 00:07:06 +00:00
|
|
|
// TODO: rename fcn_bb_split()
|
2012-07-19 02:54:22 +00:00
|
|
|
R_API int r_anal_fcn_split_bb(RAnalFunction *fcn, RAnalBlock *bb, ut64 addr) {
|
2011-02-11 10:22:43 +00:00
|
|
|
RAnalBlock *bbi;
|
2011-11-15 22:40:28 +00:00
|
|
|
#if R_ANAL_BB_HAS_OPS
|
2011-02-24 13:06:49 +00:00
|
|
|
RAnalOp *opi;
|
2011-11-15 22:40:28 +00:00
|
|
|
#endif
|
2011-02-11 10:22:43 +00:00
|
|
|
RListIter *iter;
|
|
|
|
|
2011-09-01 23:42:09 +00:00
|
|
|
r_list_foreach (fcn->bbs, iter, bbi) {
|
2011-02-11 10:22:43 +00:00
|
|
|
if (addr == bbi->addr)
|
|
|
|
return R_ANAL_RET_DUP;
|
2011-09-01 23:42:09 +00:00
|
|
|
if (addr > bbi->addr && addr < bbi->addr + bbi->size) {
|
2011-02-11 10:22:43 +00:00
|
|
|
r_list_append (fcn->bbs, bb);
|
2013-10-24 11:59:19 +00:00
|
|
|
bb->addr = addr+bbi->size;
|
2011-02-11 10:22:43 +00:00
|
|
|
bb->size = bbi->addr + bbi->size - addr;
|
|
|
|
bb->jump = bbi->jump;
|
|
|
|
bb->fail = bbi->fail;
|
|
|
|
bb->conditional = bbi->conditional;
|
2012-08-31 09:45:06 +00:00
|
|
|
|
2011-02-11 10:22:43 +00:00
|
|
|
bbi->size = addr - bbi->addr;
|
|
|
|
bbi->jump = addr;
|
|
|
|
bbi->fail = -1;
|
|
|
|
bbi->conditional = R_FALSE;
|
|
|
|
if (bbi->type&R_ANAL_BB_TYPE_HEAD) {
|
|
|
|
bb->type = bbi->type^R_ANAL_BB_TYPE_HEAD;
|
|
|
|
bbi->type = R_ANAL_BB_TYPE_HEAD;
|
|
|
|
} else {
|
|
|
|
bb->type = bbi->type;
|
|
|
|
bbi->type = R_ANAL_BB_TYPE_BODY;
|
|
|
|
}
|
2011-11-15 13:30:52 +00:00
|
|
|
#if R_ANAL_BB_HAS_OPS
|
2011-11-13 23:21:25 +00:00
|
|
|
if (bbi->ops) {
|
2012-02-14 17:19:16 +00:00
|
|
|
r_list_foreach (bbi->ops, iter, opi) {
|
2011-11-13 23:21:25 +00:00
|
|
|
if (opi->addr >= addr) {
|
2012-02-14 17:19:16 +00:00
|
|
|
/* Remove opi from bbi->ops without free()ing it. */
|
2011-11-13 23:21:25 +00:00
|
|
|
r_list_split (bbi->ops, opi);
|
|
|
|
bbi->ninstr--;
|
|
|
|
r_list_append (bb->ops, opi);
|
|
|
|
bb->ninstr++;
|
|
|
|
}
|
2011-02-11 10:22:43 +00:00
|
|
|
}
|
|
|
|
}
|
2011-11-15 13:30:52 +00:00
|
|
|
#endif
|
2011-02-11 10:22:43 +00:00
|
|
|
return R_ANAL_RET_END;
|
|
|
|
}
|
2011-09-01 23:42:09 +00:00
|
|
|
}
|
2011-02-11 10:22:43 +00:00
|
|
|
return R_ANAL_RET_NEW;
|
|
|
|
}
|
|
|
|
|
2011-09-14 00:07:06 +00:00
|
|
|
// TODO: rename fcn_bb_overlap()
|
2012-07-19 02:54:22 +00:00
|
|
|
R_API int r_anal_fcn_overlap_bb(RAnalFunction *fcn, RAnalBlock *bb) {
|
2011-02-11 10:22:43 +00:00
|
|
|
RAnalBlock *bbi;
|
2011-11-15 22:40:28 +00:00
|
|
|
RListIter *iter;
|
|
|
|
#if R_ANAL_BB_HAS_OPS
|
2012-02-14 17:10:52 +00:00
|
|
|
RListIter *iter_tmp;
|
2011-02-24 13:06:49 +00:00
|
|
|
RAnalOp *opi;
|
2011-11-15 22:40:28 +00:00
|
|
|
#endif
|
2011-02-11 10:22:43 +00:00
|
|
|
|
|
|
|
r_list_foreach (fcn->bbs, iter, bbi)
|
|
|
|
if (bb->addr+bb->size > bbi->addr && bb->addr+bb->size <= bbi->addr+bbi->size) {
|
|
|
|
bb->size = bbi->addr - bb->addr;
|
|
|
|
bb->jump = bbi->addr;
|
|
|
|
bb->fail = -1;
|
|
|
|
bb->conditional = R_FALSE;
|
2011-09-04 18:25:32 +00:00
|
|
|
if (bbi->type & R_ANAL_BB_TYPE_HEAD) {
|
2011-02-11 10:22:43 +00:00
|
|
|
bb->type = R_ANAL_BB_TYPE_HEAD;
|
|
|
|
bbi->type = bbi->type^R_ANAL_BB_TYPE_HEAD;
|
|
|
|
} else bb->type = R_ANAL_BB_TYPE_BODY;
|
2011-11-15 13:30:52 +00:00
|
|
|
#if R_ANAL_BB_HAS_OPS
|
2012-02-14 17:10:52 +00:00
|
|
|
/* We can reuse iter because we return before the outer loop. */
|
|
|
|
r_list_foreach_safe (bb->ops, iter, iter_tmp, opi) {
|
2011-04-03 00:43:15 +00:00
|
|
|
if (opi->addr >= bbi->addr) {
|
|
|
|
// eprintf ("Must delete opi %p\n", iter);
|
|
|
|
r_list_delete (bb->ops, iter);
|
|
|
|
}
|
|
|
|
}
|
2011-11-15 13:30:52 +00:00
|
|
|
#endif
|
2014-05-02 16:29:00 +00:00
|
|
|
//r_list_delete_data (bb->ops, opi);
|
2011-02-11 10:22:43 +00:00
|
|
|
r_list_append (fcn->bbs, bb);
|
|
|
|
return R_ANAL_RET_END;
|
|
|
|
}
|
|
|
|
return R_ANAL_RET_NEW;
|
|
|
|
}
|
|
|
|
|
2012-07-19 02:54:22 +00:00
|
|
|
R_API int r_anal_fcn_cc(RAnalFunction *fcn) {
|
2011-02-11 10:22:43 +00:00
|
|
|
struct r_anal_bb_t *bbi;
|
|
|
|
RListIter *iter;
|
|
|
|
int ret = 0, retbb;
|
|
|
|
|
|
|
|
r_list_foreach (fcn->bbs, iter, bbi) {
|
2011-09-14 00:07:06 +00:00
|
|
|
retbb = ((bbi->type & R_ANAL_BB_TYPE_LAST))? 1: 0;
|
2011-02-11 10:22:43 +00:00
|
|
|
ret += bbi->conditional + retbb;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-07-19 02:54:22 +00:00
|
|
|
R_API RAnalVar *r_anal_fcn_get_var(RAnalFunction *fs, int num, int type) {
|
2010-07-12 19:37:40 +00:00
|
|
|
RAnalVar *var;
|
|
|
|
RListIter *iter;
|
|
|
|
int count = 0;
|
2010-07-21 23:14:13 +00:00
|
|
|
// vars are sorted by delta in r_anal_var_add()
|
2010-07-12 19:37:40 +00:00
|
|
|
r_list_foreach (fs->vars, iter, var) {
|
2012-07-19 02:54:22 +00:00
|
|
|
//if (type & var->type) /* What we need to use here? */
|
2010-07-12 19:37:40 +00:00
|
|
|
if (count++ == num)
|
|
|
|
return var;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-07-19 02:54:22 +00:00
|
|
|
R_API char *r_anal_fcn_to_string(RAnal *a, RAnalFunction* fs) {
|
2010-07-12 19:37:40 +00:00
|
|
|
int i;
|
|
|
|
char *sign;
|
2011-09-01 23:42:09 +00:00
|
|
|
RAnalVar *arg, *ret;
|
2011-02-07 16:43:50 +00:00
|
|
|
if (fs->type != R_ANAL_FCN_TYPE_FCN || fs->type != R_ANAL_FCN_TYPE_SYM)
|
2010-11-23 18:55:31 +00:00
|
|
|
return NULL;
|
2012-07-22 08:00:35 +00:00
|
|
|
ret = r_anal_fcn_get_var (fs, 0, R_ANAL_VAR_SCOPE_RET);
|
2014-05-02 23:50:28 +00:00
|
|
|
sign = ret ? r_str_newf ("%s %s (", ret->name, fs->name):
|
2011-09-01 23:42:09 +00:00
|
|
|
r_str_newf ("void %s (", fs->name);
|
2012-07-19 02:54:22 +00:00
|
|
|
/* FIXME: Use RAnalType instead */
|
2014-05-02 23:50:28 +00:00
|
|
|
for (i = 0; ; i++) {
|
2010-12-03 12:52:11 +00:00
|
|
|
if (!(arg = r_anal_fcn_get_var (fs, i,
|
2012-07-22 08:00:35 +00:00
|
|
|
R_ANAL_VAR_SCOPE_ARG|R_ANAL_VAR_SCOPE_ARGREG)))
|
2010-08-10 10:34:10 +00:00
|
|
|
break;
|
2013-09-01 23:20:12 +00:00
|
|
|
#if 0
|
|
|
|
// TODO: implement array support using sdb
|
2012-07-19 02:54:22 +00:00
|
|
|
if (arg->type->type == R_ANAL_TYPE_ARRAY)
|
2011-09-14 00:07:06 +00:00
|
|
|
sign = r_str_concatf (sign, i?", %s %s:%02x[%d]":"%s %s:%02x[%d]",
|
2012-07-22 08:00:35 +00:00
|
|
|
arg->type, arg->name, arg->delta, arg->type->custom.a->count);
|
2014-05-02 23:50:28 +00:00
|
|
|
else
|
2013-09-01 23:20:12 +00:00
|
|
|
#endif
|
2013-09-14 12:04:08 +00:00
|
|
|
sign = r_str_concatf (sign, i?", %s %s:%02x":"%s %s:%02x",
|
|
|
|
arg->type, arg->name, arg->delta);
|
2010-07-12 19:37:40 +00:00
|
|
|
}
|
2010-08-10 10:34:10 +00:00
|
|
|
return (sign = r_str_concatf (sign, ");"));
|
|
|
|
}
|
|
|
|
|
2011-02-18 09:08:24 +00:00
|
|
|
// TODO: This function is not fully implemented
|
2011-09-14 00:07:06 +00:00
|
|
|
/* set function signature from string */
|
2012-07-22 08:00:35 +00:00
|
|
|
R_API int r_anal_str_to_fcn(RAnal *a, RAnalFunction *f, const char *sig) {
|
2012-10-03 23:20:00 +00:00
|
|
|
char *str; //*p, *q, *r
|
2011-02-18 09:08:24 +00:00
|
|
|
|
2011-09-14 00:07:06 +00:00
|
|
|
if (!a || !f || !sig) {
|
2012-07-22 08:00:35 +00:00
|
|
|
eprintf ("r_anal_str_to_fcn: No function received\n");
|
2010-08-12 10:19:25 +00:00
|
|
|
return R_FALSE;
|
|
|
|
}
|
2012-07-22 08:00:35 +00:00
|
|
|
|
|
|
|
/* Add 'function' keyword */
|
|
|
|
str = malloc(strlen(sig) + 10);
|
|
|
|
strcpy(str, "function ");
|
|
|
|
strcat(str, sig);
|
|
|
|
|
|
|
|
/* TODO: Improve arguments parsing */
|
|
|
|
/*
|
2013-09-14 12:04:08 +00:00
|
|
|
RAnalType *t;
|
2013-08-11 12:23:51 +00:00
|
|
|
t = r_anal_str_to_type(a, str);
|
2011-09-14 00:07:06 +00:00
|
|
|
str = strdup (sig);
|
2012-07-22 08:00:35 +00:00
|
|
|
|
|
|
|
// TODO : implement parser
|
2014-05-02 14:54:27 +00:00
|
|
|
//r_list_purge (fs->vars);
|
2010-08-10 10:34:10 +00:00
|
|
|
//set: fs->vars = r_list_new ();
|
|
|
|
//set: fs->name
|
2011-09-14 00:07:06 +00:00
|
|
|
eprintf ("ORIG=(%s)\n", sig);
|
2010-08-12 10:19:25 +00:00
|
|
|
p = strchr (str, '(');
|
|
|
|
if (!p) goto parsefail;
|
|
|
|
*p = 0;
|
|
|
|
q = strrchr (str, ' ');
|
|
|
|
if (!q) goto parsefail;
|
|
|
|
*q = 0;
|
|
|
|
printf ("RET=(%s)\n", str);
|
|
|
|
printf ("NAME=(%s)\n", q+1);
|
2012-07-22 08:00:35 +00:00
|
|
|
// set function name
|
2010-08-12 10:19:25 +00:00
|
|
|
free (f->name);
|
|
|
|
f->name = strdup (q+1);
|
2012-07-22 08:00:35 +00:00
|
|
|
// set return value
|
2010-08-12 10:19:25 +00:00
|
|
|
// TODO: simplify this complex api usage
|
2010-12-03 12:52:11 +00:00
|
|
|
r_anal_var_add (a, f, 0LL, 0,
|
2012-07-22 08:00:35 +00:00
|
|
|
R_ANAL_VAR_SCOPE_RET|R_ANAL_VAR_DIR_OUT, t, "ret", 1);
|
2010-08-12 10:19:25 +00:00
|
|
|
|
2012-07-22 08:00:35 +00:00
|
|
|
// parse arguments
|
2010-12-03 12:52:11 +00:00
|
|
|
for (i=arg=0,p++;;p=q+1,i++) {
|
2010-08-12 10:19:25 +00:00
|
|
|
q = strchr (p, ',');
|
|
|
|
if (!q) {
|
|
|
|
q = strchr (p, ')');
|
|
|
|
if (!q) break;
|
|
|
|
}
|
|
|
|
*q = 0;
|
|
|
|
p = r_str_chop (p);
|
|
|
|
r = strrchr (p, ' ');
|
|
|
|
if (!r) goto parsefail;
|
|
|
|
*r = 0;
|
|
|
|
r = r_str_chop (r+1);
|
|
|
|
printf ("VAR %d=(%s)(%s)\n", arg, p, r);
|
|
|
|
// TODO : increment arg by var size
|
2012-07-22 08:00:35 +00:00
|
|
|
if ((var = r_anal_fcn_get_var (f, i, R_ANAL_VAR_SCOPE_ARG|R_ANAL_VAR_SCOPE_ARGREG))) {
|
|
|
|
free (var->name); var->name = strdup(r);
|
|
|
|
// FIXME: add cparse function
|
|
|
|
free (var->type); var->type = r_anal_str_to_type(p);
|
|
|
|
} else r_anal_var_add (a, f, 0LL, arg, R_ANAL_VAR_SCOPE_ARG|R_ANAL_VAR_DIR_IN, p, r, 0);
|
2010-08-12 10:19:25 +00:00
|
|
|
arg++;
|
|
|
|
}
|
2010-10-27 22:55:07 +00:00
|
|
|
// r_anal_fcn_set_var (fs, 0, R_ANAL_VAR_DIR_OUT, );
|
2012-07-22 08:00:35 +00:00
|
|
|
*/
|
2014-05-02 23:50:28 +00:00
|
|
|
free (str);
|
2010-08-12 10:19:25 +00:00
|
|
|
return R_TRUE;
|
|
|
|
|
2012-07-22 08:00:35 +00:00
|
|
|
//parsefail:
|
|
|
|
//free (str);
|
|
|
|
//eprintf ("Function string parse fail\n");
|
|
|
|
//return R_FALSE;
|
2010-07-12 19:37:40 +00:00
|
|
|
}
|
2011-11-12 03:51:45 +00:00
|
|
|
|
2012-07-19 02:54:22 +00:00
|
|
|
R_API RAnalFunction *r_anal_get_fcn_at(RAnal *anal, ut64 addr) {
|
|
|
|
RAnalFunction *fcni;
|
2011-11-12 03:51:45 +00:00
|
|
|
RListIter *iter;
|
|
|
|
//eprintf ("DEPRECATED: get-at\n");
|
|
|
|
r_list_foreach (anal->fcns, iter, fcni)
|
|
|
|
//if (fcni->addr == addr)
|
|
|
|
if (addr >= fcni->addr && addr < (fcni->addr+fcni->size))
|
|
|
|
return fcni;
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-06-05 15:50:12 +00:00
|
|
|
|
|
|
|
/* getters */
|
2012-07-19 02:54:22 +00:00
|
|
|
R_API RList* r_anal_fcn_get_refs (RAnalFunction *anal) { return anal->refs; }
|
|
|
|
R_API RList* r_anal_fcn_get_xrefs (RAnalFunction *anal) { return anal->xrefs; }
|
|
|
|
R_API RList* r_anal_fcn_get_vars (RAnalFunction *anal) { return anal->vars; }
|
|
|
|
R_API RList* r_anal_fcn_get_bbs (RAnalFunction *anal) { return anal->bbs; }
|
2012-06-14 00:18:15 +00:00
|
|
|
|
2012-07-19 02:54:22 +00:00
|
|
|
R_API int r_anal_fcn_is_in_offset (RAnalFunction *fcn, ut64 addr) {
|
2012-06-14 00:18:15 +00:00
|
|
|
return (addr >= fcn->addr && addr < (fcn->addr+fcn->size));
|
|
|
|
}
|
2012-11-20 02:59:00 +00:00
|
|
|
|
|
|
|
R_API int r_anal_fcn_count (RAnal *anal, ut64 from, ut64 to) {
|
|
|
|
int n = 0;
|
|
|
|
RAnalFunction *fcni;
|
|
|
|
RListIter *iter;
|
|
|
|
r_list_foreach (anal->fcns, iter, fcni)
|
|
|
|
if (fcni->addr >= from && fcni->addr < to)
|
|
|
|
return n++;
|
|
|
|
return n;
|
|
|
|
}
|