2017-04-12 01:11:35 +00:00
|
|
|
/* radare - LGPL - Copyright 2010-2017 - nibble, alvaro, pancake */
|
2010-03-12 02:05:20 +00:00
|
|
|
|
|
|
|
#include <r_anal.h>
|
|
|
|
#include <r_util.h>
|
|
|
|
#include <r_list.h>
|
2015-06-12 00:11:07 +00:00
|
|
|
|
2017-08-09 17:21:53 +00:00
|
|
|
#define VARPREFIX "local"
|
|
|
|
#define ARGPREFIX "arg"
|
|
|
|
|
2016-08-21 01:07:19 +00:00
|
|
|
#define USE_SDB_CACHE 0
|
2017-03-09 22:46:02 +00:00
|
|
|
#define SDB_KEY_BB "bb.0x%"PFMT64x ".0x%"PFMT64x
|
2015-10-18 19:38:06 +00:00
|
|
|
// XXX must be configurable by the user
|
|
|
|
#define FCN_DEPTH 512
|
2014-09-20 07:43:31 +00:00
|
|
|
|
2016-08-21 09:39:37 +00:00
|
|
|
/* speedup analysis by removing some function overlapping checks */
|
|
|
|
#define JAYRO_04 0
|
2016-08-01 16:41:07 +00:00
|
|
|
|
2015-11-09 10:18:34 +00:00
|
|
|
// 16 KB is the maximum size for a basic block
|
|
|
|
#define MAXBBSIZE 16 * 1024
|
2016-09-05 18:42:04 +00:00
|
|
|
#define MAX_FLG_NAME_SIZE 64
|
2015-11-09 10:18:34 +00:00
|
|
|
|
2016-08-01 16:41:07 +00:00
|
|
|
#define FIX_JMP_FWD 0
|
2015-08-18 00:44:59 +00:00
|
|
|
#define JMP_IS_EOB 1
|
2016-08-01 16:41:07 +00:00
|
|
|
#define JMP_IS_EOB_RANGE 64
|
2014-09-21 23:39:24 +00:00
|
|
|
#define CALL_IS_EOB 0
|
2014-09-20 07:43:31 +00:00
|
|
|
|
2014-09-20 08:26:31 +00:00
|
|
|
// 64KB max size
|
2015-07-09 00:13:55 +00:00
|
|
|
// 256KB max function size
|
2017-03-09 22:46:02 +00:00
|
|
|
#define MAX_FCN_SIZE (1024 * 256)
|
2014-09-20 08:26:31 +00:00
|
|
|
|
2015-11-20 08:33:48 +00:00
|
|
|
#define MAX_JMPTBL_SIZE 1000
|
|
|
|
#define MAX_JMPTBL_JMP 10000
|
|
|
|
|
2014-03-31 01:05:48 +00:00
|
|
|
#define DB a->sdb_fcns
|
2017-09-01 23:57:13 +00:00
|
|
|
#define EXISTS(x, ...) snprintf (key, sizeof (key) - 1, x, ## __VA_ARGS__), sdb_exists (DB, key)
|
2017-05-09 12:25:57 +00:00
|
|
|
#define SETKEY(x, ...) snprintf (key, sizeof (key) - 1, x, ## __VA_ARGS__);
|
2011-02-05 01:55:50 +00:00
|
|
|
|
2017-03-09 22:46:02 +00:00
|
|
|
#define VERBOSE_DELAY if (0)
|
2014-06-07 09:59:27 +00:00
|
|
|
|
2016-08-22 16:32:18 +00:00
|
|
|
#if USE_SDB_CACHE
|
2016-08-21 01:07:19 +00:00
|
|
|
static Sdb *HB = NULL;
|
2016-08-22 16:32:18 +00:00
|
|
|
#endif
|
2016-08-21 01:07:19 +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";
|
2016-07-25 18:15:50 +00:00
|
|
|
case R_ANAL_FCN_TYPE_INT: return "int"; // interrupt
|
2014-04-27 00:48:42 +00:00
|
|
|
case R_ANAL_FCN_TYPE_ROOT: return "root";
|
|
|
|
}
|
|
|
|
return "unk";
|
|
|
|
}
|
|
|
|
|
2017-03-09 22:46:02 +00:00
|
|
|
static int cmpaddr(const void *_a, const void *_b) {
|
2016-08-21 01:07:19 +00:00
|
|
|
const RAnalBlock *a = _a, *b = _b;
|
2017-03-26 22:37:18 +00:00
|
|
|
return (a->addr - b->addr);
|
2016-08-21 01:07:19 +00:00
|
|
|
}
|
|
|
|
|
2017-09-04 00:56:54 +00:00
|
|
|
R_API void r_anal_fcn_update_tinyrange_bbs(RAnalFunction *fcn) {
|
2016-08-21 01:07:19 +00:00
|
|
|
RAnalBlock *bb;
|
|
|
|
RListIter *iter;
|
|
|
|
r_list_sort (fcn->bbs, &cmpaddr);
|
|
|
|
r_tinyrange_fini (&fcn->bbr);
|
|
|
|
r_list_foreach (fcn->bbs, iter, bb) {
|
|
|
|
r_tinyrange_add (&fcn->bbr, bb->addr, bb->addr + bb->size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-24 23:12:06 +00:00
|
|
|
R_API int r_anal_fcn_resize(RAnalFunction *fcn, int newsize) {
|
2015-09-06 22:30:48 +00:00
|
|
|
ut64 eof; /* end of function */
|
|
|
|
RAnalBlock *bb;
|
|
|
|
RListIter *iter, *iter2;
|
2016-08-01 16:41:07 +00:00
|
|
|
if (!fcn || newsize < 1) {
|
2015-09-14 09:31:54 +00:00
|
|
|
return false;
|
2016-08-01 16:41:07 +00:00
|
|
|
}
|
2016-05-15 12:37:22 +00:00
|
|
|
r_anal_fcn_set_size (fcn, newsize);
|
|
|
|
eof = fcn->addr + r_anal_fcn_size (fcn);
|
2015-09-06 22:30:48 +00:00
|
|
|
r_list_foreach_safe (fcn->bbs, iter, iter2, bb) {
|
|
|
|
if (bb->addr >= eof) {
|
|
|
|
// already called by r_list_delete r_anal_bb_free (bb);
|
|
|
|
r_list_delete (fcn->bbs, iter);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (bb->addr + bb->size >= eof) {
|
|
|
|
bb->size = eof - bb->addr;
|
|
|
|
}
|
|
|
|
if (bb->jump != UT64_MAX && bb->jump >= eof) {
|
|
|
|
bb->jump = UT64_MAX;
|
|
|
|
}
|
|
|
|
if (bb->fail != UT64_MAX && bb->fail >= eof) {
|
|
|
|
bb->fail = UT64_MAX;
|
|
|
|
}
|
|
|
|
}
|
2017-09-04 00:56:54 +00:00
|
|
|
r_anal_fcn_update_tinyrange_bbs (fcn);
|
2015-09-14 09:31:54 +00:00
|
|
|
return true;
|
2014-09-02 00:41:40 +00:00
|
|
|
}
|
|
|
|
|
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);
|
2016-10-24 23:12:06 +00:00
|
|
|
if (!fcn) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-07-19 02:54:22 +00:00
|
|
|
/* Function return type */
|
|
|
|
fcn->rets = 0;
|
2016-05-15 12:37:22 +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 */
|
2016-07-27 11:50:14 +00:00
|
|
|
fcn->cc = NULL;
|
2012-07-19 02:54:22 +00:00
|
|
|
/* Function attributes: weak/noreturn/format/etc */
|
2015-07-09 01:53:10 +00:00
|
|
|
fcn->addr = UT64_MAX;
|
2014-09-22 22:40:35 +00:00
|
|
|
#if FCN_OLD
|
2011-09-14 00:07:06 +00:00
|
|
|
fcn->refs = r_anal_ref_list_new ();
|
|
|
|
fcn->xrefs = r_anal_ref_list_new ();
|
2014-09-22 22:40:35 +00:00
|
|
|
#endif
|
2016-09-09 17:28:47 +00:00
|
|
|
fcn->fcn_locs = NULL;
|
2011-09-14 00:07:06 +00:00
|
|
|
fcn->bbs = r_anal_bb_list_new ();
|
|
|
|
fcn->fingerprint = NULL;
|
|
|
|
fcn->diff = r_anal_diff_new ();
|
2016-08-20 22:53:39 +00:00
|
|
|
r_tinyrange_init (&fcn->bbr);
|
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 ();
|
2016-08-01 16:41:07 +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;
|
2016-10-24 23:12:06 +00:00
|
|
|
if (!_fcn) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-15 12:37:22 +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);
|
2016-08-20 22:53:39 +00:00
|
|
|
r_tinyrange_fini (&fcn->bbr);
|
2014-09-22 22:40:35 +00:00
|
|
|
#if FCN_OLD
|
2011-02-18 09:08:24 +00:00
|
|
|
r_list_free (fcn->refs);
|
|
|
|
r_list_free (fcn->xrefs);
|
2014-09-22 22:40:35 +00:00
|
|
|
#endif
|
2017-03-09 22:46:02 +00:00
|
|
|
// all functions are freed in anal->fcns
|
2016-09-09 17:28:47 +00:00
|
|
|
fcn->fcn_locs = NULL;
|
2015-03-10 20:00:12 +00:00
|
|
|
if (fcn->bbs) {
|
2017-03-09 22:46:02 +00:00
|
|
|
fcn->bbs->free = (RListFree) r_anal_bb_free;
|
2015-03-10 20:00:12 +00:00
|
|
|
r_list_free (fcn->bbs);
|
|
|
|
fcn->bbs = NULL;
|
|
|
|
}
|
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);
|
|
|
|
}
|
|
|
|
|
2016-12-12 22:02:11 +00:00
|
|
|
static bool refExists(RList *refs, RAnalRef *ref) {
|
|
|
|
RAnalRef *r;
|
|
|
|
RListIter *iter;
|
|
|
|
r_list_foreach (refs, iter, r) {
|
|
|
|
if (r->at == ref->at && ref->addr == r->addr) {
|
|
|
|
r->type = ref->type;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-10-24 23:12:06 +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;
|
2016-08-01 16:41:07 +00:00
|
|
|
if (!fcn || !a) {
|
2015-09-14 09:31:54 +00:00
|
|
|
return false;
|
2016-08-01 16:41:07 +00:00
|
|
|
}
|
|
|
|
if (!a->iob.is_valid_offset (a->iob.io, addr, 0)) {
|
2015-09-14 09:31:54 +00:00
|
|
|
return false;
|
2016-08-01 16:41:07 +00:00
|
|
|
}
|
2014-09-21 23:39:24 +00:00
|
|
|
ref = r_anal_ref_new ();
|
2016-08-01 16:41:07 +00:00
|
|
|
if (!ref) {
|
2015-09-14 09:31:54 +00:00
|
|
|
return false;
|
2016-08-01 16:41:07 +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
|
2016-12-12 22:02:11 +00:00
|
|
|
if (refExists (fcn->refs, ref)) {
|
|
|
|
r_anal_ref_free (ref);
|
|
|
|
} else {
|
|
|
|
r_list_append (fcn->refs, ref);
|
|
|
|
}
|
2014-03-31 01:05:48 +00:00
|
|
|
#endif
|
|
|
|
#if FCN_SDB
|
2017-03-09 22:46:02 +00:00
|
|
|
sdb_add (DB, sdb_fmt (0, "fcn.0x%08"PFMT64x ".name", fcn->addr), fcn->name, 0);
|
2014-09-21 23:39:24 +00:00
|
|
|
// encode the name in base64 ?
|
|
|
|
sdb_num_add (DB, sdb_fmt (0, "fcn.name.%s", fcn->name), fcn->addr, 0);
|
2017-03-09 22:46:02 +00:00
|
|
|
sdb_array_add_num (DB, sdb_fmt (0, "fcn.0x%08"PFMT64x ".xrefs", fcn->addr), at, 0);
|
2014-03-31 01:05:48 +00:00
|
|
|
#endif
|
2015-09-14 09:31:54 +00:00
|
|
|
return true;
|
2011-09-28 00:48:03 +00:00
|
|
|
}
|
|
|
|
|
2016-10-24 23:12:06 +00:00
|
|
|
R_API int r_anal_fcn_xref_del(RAnal *a, RAnalFunction *fcn, ut64 at, ut64 addr, int type) {
|
2014-03-31 01:05:48 +00:00
|
|
|
#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) {
|
2017-03-09 22:46:02 +00:00
|
|
|
if ((type != -1 || type == ref->type) &&
|
|
|
|
(at == 0LL || at == ref->at) &&
|
|
|
|
(addr == 0LL || addr == ref->addr)) {
|
|
|
|
r_list_delete (fcn->xrefs, iter);
|
|
|
|
return true;
|
2011-09-28 00:48:03 +00:00
|
|
|
}
|
|
|
|
}
|
2014-03-31 01:05:48 +00:00
|
|
|
#endif
|
|
|
|
#if FCN_SDB
|
2015-11-09 04:07:53 +00:00
|
|
|
// TODO
|
2017-03-09 22:46:02 +00:00
|
|
|
// sdb_array_delete_num (DB, key, at, 0);
|
2014-03-31 01:05:48 +00:00
|
|
|
#endif
|
2015-09-14 09:31:54 +00:00
|
|
|
return false;
|
2011-09-28 00:48:03 +00:00
|
|
|
}
|
|
|
|
|
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) {
|
2014-10-09 16:43:57 +00:00
|
|
|
ut64 eaddr = bb->addr + bb->size;
|
2016-05-15 00:33:03 +00:00
|
|
|
if (bb->addr >= eaddr && addr == bb->addr) {
|
2016-08-01 16:41:07 +00:00
|
|
|
return bb;
|
2014-10-09 16:43:57 +00:00
|
|
|
}
|
|
|
|
if ((addr >= bb->addr) && (addr < eaddr)) {
|
2013-10-08 02:58:51 +00:00
|
|
|
return bb;
|
2014-10-09 16:43:57 +00:00
|
|
|
}
|
2013-10-08 02:58:51 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-03-09 22:46:02 +00:00
|
|
|
static RAnalBlock *appendBasicBlock(RAnal *anal, RAnalFunction *fcn, ut64 addr) {
|
2016-04-21 19:19:01 +00:00
|
|
|
RAnalBlock *bb = r_anal_bb_new ();
|
2016-08-01 16:41:07 +00:00
|
|
|
if (!bb) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2014-09-21 23:39:24 +00:00
|
|
|
bb->addr = addr;
|
|
|
|
bb->size = 0;
|
|
|
|
bb->jump = UT64_MAX;
|
|
|
|
bb->fail = UT64_MAX;
|
|
|
|
bb->type = 0; // TODO
|
2016-08-21 01:07:19 +00:00
|
|
|
r_anal_fcn_bbadd (fcn, bb);
|
2015-03-16 01:52:26 +00:00
|
|
|
if (anal->cb.on_fcn_bb_new) {
|
|
|
|
anal->cb.on_fcn_bb_new (anal, anal->user, fcn, bb);
|
|
|
|
}
|
2014-09-21 23:39:24 +00:00
|
|
|
return bb;
|
|
|
|
}
|
2015-07-31 10:40:04 +00:00
|
|
|
|
2015-09-07 16:12:08 +00:00
|
|
|
#define FITFCNSZ() {\
|
2017-03-09 22:46:02 +00:00
|
|
|
st64 n = bb->addr + bb->size - fcn->addr;\
|
|
|
|
if (n >= 0 && r_anal_fcn_size (fcn) < n) { r_anal_fcn_set_size (fcn, n); } }\
|
|
|
|
if (r_anal_fcn_size (fcn) > MAX_FCN_SIZE) {\
|
|
|
|
/* eprintf ("Function too big at 0x%"PFMT64x" + %d\n", bb->addr, fcn->size); */\
|
|
|
|
r_anal_fcn_set_size (fcn, 0);\
|
2014-09-20 08:26:31 +00:00
|
|
|
return R_ANAL_RET_ERROR; }
|
2014-09-21 23:39:24 +00:00
|
|
|
|
2017-08-09 17:21:53 +00:00
|
|
|
// ETOOSLOW
|
2016-06-27 21:26:13 +00:00
|
|
|
static char *get_varname(RAnal *a, RAnalFunction *fcn, char type, const char *pfx, int idx) {
|
2016-06-08 16:13:36 +00:00
|
|
|
char *varname = r_str_newf ("%s_%xh", pfx, idx);
|
|
|
|
int i = 2;
|
|
|
|
while (1) {
|
2016-08-08 22:17:42 +00:00
|
|
|
RAnalVar *v = r_anal_var_get_byname (a, fcn, varname);
|
2016-06-08 16:13:36 +00:00
|
|
|
if (!v) {
|
2016-08-08 22:17:42 +00:00
|
|
|
v = r_anal_var_get_byname (a, fcn, varname);
|
2016-06-08 16:13:36 +00:00
|
|
|
}
|
|
|
|
if (!v) {
|
2016-08-08 22:17:42 +00:00
|
|
|
v = r_anal_var_get_byname (a, fcn, varname);
|
2016-06-08 16:13:36 +00:00
|
|
|
}
|
2016-10-24 23:12:06 +00:00
|
|
|
if (!v) {
|
|
|
|
break;
|
|
|
|
}
|
2016-06-08 16:13:36 +00:00
|
|
|
if (v->kind == type && R_ABS (v->delta) == idx) {
|
2016-06-27 21:26:13 +00:00
|
|
|
r_anal_var_free (v);
|
2016-06-08 16:13:36 +00:00
|
|
|
break;
|
|
|
|
}
|
2016-06-20 13:22:09 +00:00
|
|
|
r_anal_var_free (v);
|
2017-08-09 17:21:53 +00:00
|
|
|
free (varname);
|
2016-06-08 16:13:36 +00:00
|
|
|
varname = r_str_newf ("%s_%xh_%d", pfx, idx, i);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
return varname;
|
2015-03-16 01:52:26 +00:00
|
|
|
}
|
|
|
|
|
2015-11-20 14:35:47 +00:00
|
|
|
static int fcn_recurse(RAnal *anal, RAnalFunction *fcn, ut64 addr, ut8 *buf, ut64 len, int depth);
|
2017-03-09 22:46:02 +00:00
|
|
|
#define recurseAt(x) {\
|
|
|
|
ut8 *bbuf = malloc (MAXBBSIZE);\
|
|
|
|
anal->iob.read_at (anal->iob.io, x, bbuf, MAXBBSIZE);\
|
|
|
|
ret = fcn_recurse (anal, fcn, x, bbuf, MAXBBSIZE, depth - 1);\
|
2017-09-04 00:56:54 +00:00
|
|
|
r_anal_fcn_update_tinyrange_bbs (fcn);\
|
2017-03-09 22:46:02 +00:00
|
|
|
free (bbuf);\
|
2015-11-20 14:35:47 +00:00
|
|
|
}
|
|
|
|
|
2015-11-25 11:21:46 +00:00
|
|
|
static int try_walkthrough_jmptbl(RAnal *anal, RAnalFunction *fcn, int depth, ut64 ip, ut64 ptr, int ret0) {
|
|
|
|
int ret = ret0;
|
2015-12-14 12:51:55 +00:00
|
|
|
ut8 *jmptbl = malloc (MAX_JMPTBL_SIZE);
|
2016-08-01 16:41:07 +00:00
|
|
|
ut64 jmpptr, offs, sz = anal->bits >> 3;
|
|
|
|
if (!jmptbl) {
|
|
|
|
return 0;
|
|
|
|
}
|
2015-11-20 14:35:47 +00:00
|
|
|
anal->iob.read_at (anal->iob.io, ptr, jmptbl, MAX_JMPTBL_SIZE);
|
2016-04-26 09:09:15 +00:00
|
|
|
for (offs = 0; offs + sz - 1 < MAX_JMPTBL_SIZE; offs += sz) {
|
|
|
|
switch (sz) {
|
2017-01-31 09:00:24 +00:00
|
|
|
case 1:
|
|
|
|
jmpptr = r_read_le8 (jmptbl + offs);
|
2016-10-24 23:12:06 +00:00
|
|
|
break;
|
2017-01-31 09:00:24 +00:00
|
|
|
case 2:
|
|
|
|
jmpptr = r_read_le16 (jmptbl + offs);
|
2016-10-24 23:12:06 +00:00
|
|
|
break;
|
2017-01-31 09:00:24 +00:00
|
|
|
case 4:
|
|
|
|
jmpptr = r_read_le32 (jmptbl + offs);
|
2016-10-24 23:12:06 +00:00
|
|
|
break;
|
2017-01-31 09:00:24 +00:00
|
|
|
case 8:
|
|
|
|
jmpptr = r_read_le32 (jmptbl + offs);
|
2016-10-24 23:12:06 +00:00
|
|
|
break; // XXX
|
2017-01-31 09:00:24 +00:00
|
|
|
default:
|
|
|
|
jmpptr = r_read_le64 (jmptbl + offs);
|
2016-10-24 23:12:06 +00:00
|
|
|
break;
|
2016-04-26 09:09:15 +00:00
|
|
|
}
|
2016-05-30 13:30:55 +00:00
|
|
|
if (!anal->iob.is_valid_offset (anal->iob.io, jmpptr, 0)) {
|
2017-03-09 22:46:02 +00:00
|
|
|
jmpptr = ptr + (st32) jmpptr;
|
2016-05-30 13:30:55 +00:00
|
|
|
if (!anal->iob.is_valid_offset (anal->iob.io, jmpptr, 0)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2015-11-20 14:35:47 +00:00
|
|
|
if (anal->limit) {
|
2016-05-15 00:33:03 +00:00
|
|
|
if (jmpptr < anal->limit->from || jmpptr > anal->limit->to) {
|
2015-11-20 14:35:47 +00:00
|
|
|
break;
|
2016-05-15 00:33:03 +00:00
|
|
|
}
|
2015-11-20 14:35:47 +00:00
|
|
|
}
|
2016-05-30 02:18:48 +00:00
|
|
|
// if (jmpptr < ip - MAX_JMPTBL_JMP || jmpptr > ip + MAX_JMPTBL_JMP) { break; }
|
2015-11-20 14:35:47 +00:00
|
|
|
recurseAt (jmpptr);
|
|
|
|
}
|
2015-12-14 11:07:26 +00:00
|
|
|
free (jmptbl);
|
2015-11-20 14:35:47 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-12-14 12:51:55 +00:00
|
|
|
static ut64 search_reg_val(RAnal *anal, ut8 *buf, ut64 len, ut64 addr, char *regsz) {
|
2015-11-20 14:35:47 +00:00
|
|
|
ut64 offs, oplen;
|
2017-03-09 22:46:02 +00:00
|
|
|
RAnalOp op = {
|
|
|
|
0
|
|
|
|
};
|
2015-11-20 14:35:47 +00:00
|
|
|
ut64 ret = UT64_MAX;
|
2017-09-04 19:41:09 +00:00
|
|
|
const int addrbytes = anal->iob.io ? anal->iob.io->addrbytes : 1;
|
|
|
|
for (offs = 0; offs < len; offs += addrbytes * oplen) {
|
2015-11-26 13:32:07 +00:00
|
|
|
r_anal_op_fini (&op);
|
2015-11-20 14:35:47 +00:00
|
|
|
if ((oplen = r_anal_op (anal, &op, addr + offs, buf + offs, len - offs)) < 1) {
|
|
|
|
break;
|
|
|
|
}
|
2017-03-09 22:46:02 +00:00
|
|
|
if (op.dst && op.dst->reg && op.dst->reg->name && !strcmp (op.dst->reg->name, regsz)) {
|
|
|
|
if (op.src[0]) {
|
|
|
|
ret = op.src[0]->delta;
|
|
|
|
}
|
2015-11-20 14:35:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-03-09 22:46:02 +00:00
|
|
|
#define gotoBeach(x) ret = x; goto beach;
|
2015-06-30 10:36:13 +00:00
|
|
|
#define gotoBeachRet() goto beach;
|
2016-04-21 19:19:01 +00:00
|
|
|
|
2016-11-06 00:40:51 +00:00
|
|
|
static void extract_arg(RAnal *anal, RAnalFunction *fcn, RAnalOp *op, const char *reg, const char *sign, char type) {
|
2017-08-09 17:21:53 +00:00
|
|
|
char sigstr[16] = {0};
|
2016-05-04 20:20:58 +00:00
|
|
|
st64 ptr;
|
2017-08-09 17:21:53 +00:00
|
|
|
char *addr;
|
|
|
|
if (!anal || !fcn || !op) {
|
2016-10-24 23:12:06 +00:00
|
|
|
return;
|
|
|
|
}
|
2017-08-09 17:21:53 +00:00
|
|
|
// snprintf (sigstr, sizeof (sigstr), ",%s,%s", reg, sign);
|
|
|
|
snprintf (sigstr, sizeof (sigstr), ",%s,%s", reg, sign);
|
|
|
|
const char *op_esil = r_strbuf_get (&op->esil);
|
2016-05-04 20:20:58 +00:00
|
|
|
if (!op_esil) {
|
|
|
|
return;
|
|
|
|
}
|
2017-08-09 17:21:53 +00:00
|
|
|
char *esil_buf = strdup (op_esil);
|
2016-05-04 20:20:58 +00:00
|
|
|
if (!esil_buf) {
|
|
|
|
return;
|
|
|
|
}
|
2017-08-09 17:21:53 +00:00
|
|
|
char *ptr_end = strstr (esil_buf, sigstr);
|
2016-05-04 20:20:58 +00:00
|
|
|
if (!ptr_end) {
|
2016-04-21 19:19:01 +00:00
|
|
|
free (esil_buf);
|
2016-05-04 20:20:58 +00:00
|
|
|
return;
|
2016-04-21 19:19:01 +00:00
|
|
|
}
|
2017-08-09 17:21:53 +00:00
|
|
|
#if 1
|
2016-05-04 20:20:58 +00:00
|
|
|
*ptr_end = 0;
|
|
|
|
addr = ptr_end;
|
2017-08-09 17:21:53 +00:00
|
|
|
while ((addr[0] != '0' || addr[1] != 'x') && addr >= esil_buf + 1 && *addr != ',') {
|
2016-05-04 20:20:58 +00:00
|
|
|
addr--;
|
|
|
|
}
|
|
|
|
if (strncmp (addr, "0x", 2)) {
|
|
|
|
free (esil_buf);
|
|
|
|
return;
|
|
|
|
}
|
2017-03-09 22:46:02 +00:00
|
|
|
ptr = (st64) r_num_get (NULL, addr);
|
2017-08-09 17:21:53 +00:00
|
|
|
#else
|
|
|
|
ptr = -op->ptr;
|
|
|
|
if (ptr%4) {
|
|
|
|
free (esil_buf);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
2017-03-09 22:46:02 +00:00
|
|
|
if (*sign == '+') {
|
2017-08-09 17:21:53 +00:00
|
|
|
const char *pfx = (ptr < fcn->maxstack && type == 's')? VARPREFIX: ARGPREFIX;
|
|
|
|
char *varname = get_varname (anal, fcn, type, pfx, R_ABS (ptr));
|
2016-05-04 20:20:58 +00:00
|
|
|
r_anal_var_add (anal, fcn->addr, 1, ptr, type, NULL, anal->bits / 8, varname);
|
|
|
|
r_anal_var_access (anal, fcn->addr, type, 1, ptr, 0, op->addr);
|
2017-08-09 17:21:53 +00:00
|
|
|
free (varname);
|
2016-05-04 20:20:58 +00:00
|
|
|
} else {
|
2017-08-09 17:21:53 +00:00
|
|
|
char *varname = get_varname (anal, fcn, type, VARPREFIX, R_ABS (ptr));
|
2016-06-05 22:33:42 +00:00
|
|
|
r_anal_var_add (anal, fcn->addr, 1, -ptr, type, NULL, anal->bits / 8, varname);
|
2017-03-09 22:46:02 +00:00
|
|
|
r_anal_var_access (anal, fcn->addr, type, 1, -ptr, 1, op->addr);
|
2017-08-09 17:21:53 +00:00
|
|
|
free (varname);
|
2016-05-04 20:20:58 +00:00
|
|
|
}
|
|
|
|
free (esil_buf);
|
|
|
|
}
|
2016-05-15 00:33:03 +00:00
|
|
|
|
2017-08-09 17:21:53 +00:00
|
|
|
R_API void r_anal_fcn_fill_args(RAnal *anal, RAnalFunction *fcn, RAnalOp *op) {
|
|
|
|
if (!anal || !fcn || !op) {
|
|
|
|
return;
|
2017-02-02 12:08:08 +00:00
|
|
|
}
|
2017-08-09 17:21:53 +00:00
|
|
|
const char *BP = anal->reg->name[R_REG_NAME_BP];
|
|
|
|
const char *SP = anal->reg->name[R_REG_NAME_SP];
|
|
|
|
extract_arg (anal, fcn, op, BP, "+", 'b');
|
|
|
|
extract_arg (anal, fcn, op, BP, "-", 'b');
|
|
|
|
extract_arg (anal, fcn, op, SP, "+", 's');
|
2016-05-04 20:20:58 +00:00
|
|
|
}
|
2016-05-15 00:33:03 +00:00
|
|
|
|
2017-02-02 12:08:08 +00:00
|
|
|
static bool isInvalidMemory(const ut8 *buf, int len) {
|
2016-05-16 21:07:13 +00:00
|
|
|
// can be wrong
|
2017-02-02 12:08:08 +00:00
|
|
|
return !memcmp (buf, "\xff\xff\xff\xff", R_MIN (len, 4));
|
2016-05-16 21:07:13 +00:00
|
|
|
// return buf[0]==buf[1] && buf[0]==0xff && buf[2]==0xff && buf[3] == 0xff;
|
|
|
|
}
|
|
|
|
|
2017-05-23 21:55:22 +00:00
|
|
|
static bool is_delta_pointer_table(RAnal *anal, ut64 addr, ut64 ptr) {
|
2016-05-30 02:18:48 +00:00
|
|
|
int i;
|
|
|
|
ut64 dst;
|
2017-05-23 21:55:22 +00:00
|
|
|
st32 jmptbl[64] = {
|
2017-03-09 22:46:02 +00:00
|
|
|
0
|
|
|
|
};
|
2017-05-23 21:55:22 +00:00
|
|
|
/* check if current instruction is followed by an ujmp */
|
|
|
|
ut8 buf[64];
|
|
|
|
anal->iob.read_at (anal->iob.io, addr, (ut8 *) buf, 64);
|
|
|
|
RAnalOp aop = {0};
|
|
|
|
bool isValid = false;
|
|
|
|
for (i = 0; i + 8 < 64; i++) {
|
|
|
|
int len = r_anal_op (anal, &aop, addr + i, buf + i, 64 - i);
|
|
|
|
if (len < 1) {
|
|
|
|
len = 1;
|
|
|
|
}
|
|
|
|
if (aop.type == R_ANAL_OP_TYPE_UJMP || aop.type == R_ANAL_OP_TYPE_RJMP) {
|
|
|
|
isValid = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
i += len - 1;
|
|
|
|
}
|
|
|
|
if (!isValid) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check if jump table contains valid deltas */
|
|
|
|
anal->iob.read_at (anal->iob.io, ptr, (ut8 *) &jmptbl, 64);
|
2016-05-30 02:18:48 +00:00
|
|
|
// XXX this is not endian safe
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
dst = ptr + jmptbl[0];
|
|
|
|
if (!anal->iob.is_valid_offset (anal->iob.io, dst, 0)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-09-05 18:42:04 +00:00
|
|
|
static bool regs_exist(RAnalValue *src, RAnalValue *dst) {
|
|
|
|
return src && dst && src->reg && dst->reg && src->reg->name && dst->reg->name;
|
|
|
|
}
|
|
|
|
|
2017-03-09 22:46:02 +00:00
|
|
|
// 0 if not skipped; 1 if skipped; 2 if skipped before
|
2016-09-05 18:42:04 +00:00
|
|
|
static int skip_hp(RAnal *anal, RAnalFunction *fcn, RAnalOp *op, RAnalBlock *bb, ut64 addr,
|
2017-03-09 22:46:02 +00:00
|
|
|
char *tmp_buf, int oplen, int un_idx, int *idx) {
|
|
|
|
// this step is required in order to prevent infinite recursion in some cases
|
2016-09-05 18:42:04 +00:00
|
|
|
if ((addr + un_idx - oplen) == fcn->addr) {
|
|
|
|
if (!anal->flb.exist_at (anal->flb.f, "skip", 4, op->addr)) {
|
2016-09-18 20:11:35 +00:00
|
|
|
snprintf (tmp_buf + 5, MAX_FLG_NAME_SIZE - 6, "%"PFMT64u, op->addr);
|
2016-09-05 18:42:04 +00:00
|
|
|
anal->flb.set (anal->flb.f, tmp_buf, op->addr, oplen);
|
|
|
|
fcn->addr += oplen;
|
|
|
|
bb->size -= oplen;
|
|
|
|
bb->addr += oplen;
|
|
|
|
*idx = un_idx;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-12-29 02:34:16 +00:00
|
|
|
R_API int r_anal_case(RAnal *anal, RAnalFunction *fcn, ut64 addr_bbsw, ut64 addr, ut8 *buf, ut64 len, int reftype) {
|
2017-03-09 22:46:02 +00:00
|
|
|
RAnalOp op = {
|
|
|
|
0
|
|
|
|
};
|
2016-12-29 02:34:16 +00:00
|
|
|
int oplen, idx = 0;
|
|
|
|
while (idx < len) {
|
|
|
|
if ((len - idx) < 5) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
r_anal_op_fini (&op);
|
|
|
|
if ((oplen = r_anal_op (anal, &op, addr + idx, buf + idx, len - idx)) < 1) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
switch (op.type) {
|
|
|
|
case R_ANAL_OP_TYPE_TRAP:
|
|
|
|
case R_ANAL_OP_TYPE_RET:
|
|
|
|
case R_ANAL_OP_TYPE_JMP:
|
|
|
|
// eprintf ("CASE AT 0x%llx size %d\n", addr, idx + oplen);
|
2017-05-23 21:55:22 +00:00
|
|
|
anal->cmdtail = r_str_appendf (anal->cmdtail, "afb+ 0x%"PFMT64x " 0x%"PFMT64x " %d\n",
|
2017-03-09 22:46:02 +00:00
|
|
|
fcn->addr, addr, idx + oplen);
|
2017-05-23 21:55:22 +00:00
|
|
|
anal->cmdtail = r_str_appendf (anal->cmdtail, "afbe 0x%"PFMT64x " 0x%"PFMT64x "\n",
|
2017-03-09 22:46:02 +00:00
|
|
|
addr_bbsw, addr);
|
2016-12-29 02:34:16 +00:00
|
|
|
return idx + oplen;
|
|
|
|
}
|
|
|
|
idx += oplen;
|
|
|
|
}
|
|
|
|
return idx;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int walk_switch(RAnal *anal, RAnalFunction *fcn, ut64 from, ut64 at) {
|
|
|
|
ut8 buf[1024];
|
|
|
|
int i;
|
2017-03-09 22:46:02 +00:00
|
|
|
eprintf ("WALK SWITCH TABLE INTO (0x%"PFMT64x ") %"PFMT64x "\n", from, at);
|
2016-12-29 02:34:16 +00:00
|
|
|
for (i = 0; i < 10; i++) {
|
|
|
|
anal->iob.read_at (anal->iob.io, at, buf, sizeof (buf));
|
|
|
|
int sz = r_anal_case (anal, fcn, from, at, buf, sizeof (buf), 0);
|
|
|
|
if (sz < 1) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
at += sz;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-10-08 12:20:21 +00:00
|
|
|
static int fcn_recurse(RAnal *anal, RAnalFunction *fcn, ut64 addr, ut8 *buf, ut64 len, int depth) {
|
2017-09-04 19:41:09 +00:00
|
|
|
const int continue_after_jump = anal->opt.afterjmp;
|
|
|
|
const int noncode = anal->opt.noncode;
|
|
|
|
const int addrbytes = anal->iob.io ? anal->iob.io->addrbytes : 1;
|
2014-09-21 23:39:24 +00:00
|
|
|
RAnalBlock *bb = NULL;
|
|
|
|
RAnalBlock *bbg = NULL;
|
2016-09-05 18:42:04 +00:00
|
|
|
int ret = R_ANAL_RET_END, skip_ret = 0;
|
2013-10-08 02:58:51 +00:00
|
|
|
int overlapped = 0;
|
2010-03-12 02:05:20 +00:00
|
|
|
char *varname;
|
2017-03-09 22:46:02 +00:00
|
|
|
RAnalOp op = {
|
|
|
|
0
|
|
|
|
};
|
2010-03-12 02:05:20 +00:00
|
|
|
int oplen, idx = 0;
|
2014-09-21 23:39:24 +00:00
|
|
|
struct {
|
|
|
|
int cnt;
|
|
|
|
int idx;
|
|
|
|
int after;
|
|
|
|
int pending;
|
|
|
|
int adjust;
|
|
|
|
int un_idx; // delay.un_idx
|
2017-03-09 22:46:02 +00:00
|
|
|
} delay = {
|
|
|
|
0
|
|
|
|
};
|
2016-09-05 18:42:04 +00:00
|
|
|
char tmp_buf[MAX_FLG_NAME_SIZE + 5] = "skip";
|
2016-05-15 00:33:03 +00:00
|
|
|
|
2015-09-07 16:12:08 +00:00
|
|
|
if (anal->sleep) {
|
2014-11-02 01:01:09 +00:00
|
|
|
r_sys_usleep (anal->sleep);
|
2015-09-07 16:12:08 +00:00
|
|
|
}
|
2014-09-21 23:39:24 +00:00
|
|
|
|
2016-08-01 16:41:07 +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
|
|
|
}
|
2015-01-29 22:27:18 +00:00
|
|
|
|
2017-02-02 12:08:08 +00:00
|
|
|
if (!noncode && anal->cur && anal->cur->is_valid_offset && !anal->cur->is_valid_offset (anal, addr, 0)) {
|
2016-10-11 12:28:46 +00:00
|
|
|
return R_ANAL_RET_END;
|
|
|
|
}
|
|
|
|
|
2015-07-09 18:11:15 +00:00
|
|
|
// check if address is readable //:
|
|
|
|
if (!anal->iob.is_valid_offset (anal->iob.io, addr, 0)) {
|
2016-02-20 23:46:32 +00:00
|
|
|
if (addr != UT64_MAX && !anal->iob.io->va) {
|
2017-03-09 22:46:02 +00:00
|
|
|
eprintf ("Invalid address 0x%"PFMT64x ". Try with io.va=true\n", addr);
|
2016-02-20 23:46:32 +00:00
|
|
|
}
|
2015-07-09 01:53:10 +00:00
|
|
|
return R_ANAL_RET_ERROR; // MUST BE TOO DEEP
|
2015-07-09 18:11:15 +00:00
|
|
|
}
|
|
|
|
|
2014-10-09 16:43:57 +00:00
|
|
|
if (r_anal_get_fcn_at (anal, addr, 0)) {
|
|
|
|
return R_ANAL_RET_ERROR; // MUST BE NOT FOUND
|
|
|
|
}
|
2015-01-29 22:27:18 +00:00
|
|
|
bb = bbget (fcn, addr);
|
|
|
|
if (bb) {
|
2015-03-16 01:52:26 +00:00
|
|
|
r_anal_fcn_split_bb (anal, fcn, bb, addr);
|
2016-08-01 16:41:07 +00:00
|
|
|
if (anal->opt.recont) {
|
2015-02-23 14:39:54 +00:00
|
|
|
return R_ANAL_RET_END;
|
2016-08-01 16:41:07 +00:00
|
|
|
}
|
2014-10-09 16:43:57 +00:00
|
|
|
return R_ANAL_RET_ERROR; // MUST BE NOT DUP
|
2014-05-26 08:37:18 +00:00
|
|
|
}
|
2014-09-21 23:39:24 +00:00
|
|
|
|
2015-03-16 01:52:26 +00:00
|
|
|
bb = appendBasicBlock (anal, fcn, addr);
|
2012-02-15 10:11:25 +00:00
|
|
|
|
2017-05-23 21:55:22 +00:00
|
|
|
VERBOSE_ANAL eprintf ("Append bb at 0x%08"PFMT64x" (fcn 0x%08"PFMT64x ")\n", addr, fcn->addr);
|
2014-06-07 09:59:27 +00:00
|
|
|
|
2016-04-14 12:27:44 +00:00
|
|
|
bool last_is_push = false;
|
|
|
|
ut64 last_push_addr = UT64_MAX;
|
2017-08-05 10:20:17 +00:00
|
|
|
if (anal->limit && addr + idx < anal->limit->from) {
|
|
|
|
return R_ANAL_RET_END;
|
|
|
|
}
|
|
|
|
while (addrbytes * idx < len) {
|
|
|
|
if (anal->limit && anal->limit->to <= addr + idx) {
|
|
|
|
break;
|
2014-11-03 03:05:19 +00:00
|
|
|
}
|
2014-09-12 02:57:39 +00:00
|
|
|
repeat:
|
2017-08-05 10:20:17 +00:00
|
|
|
if ((len - addrbytes * idx) < 5) {
|
2015-04-27 22:35:11 +00:00
|
|
|
break;
|
|
|
|
}
|
2011-11-13 23:21:25 +00:00
|
|
|
r_anal_op_fini (&op);
|
2017-08-05 10:20:17 +00:00
|
|
|
if (isInvalidMemory (buf + addrbytes * idx, len - addrbytes * idx)) {
|
2017-03-09 22:46:02 +00:00
|
|
|
FITFCNSZ ();
|
2017-05-23 21:55:22 +00:00
|
|
|
VERBOSE_ANAL eprintf ("FFFF opcode at 0x%08"PFMT64x "\n", addr + idx);
|
2012-02-15 10:11:25 +00:00
|
|
|
return R_ANAL_RET_ERROR;
|
2013-10-16 23:04:05 +00:00
|
|
|
}
|
2014-06-07 09:59:27 +00:00
|
|
|
// check if opcode is in another basic block
|
|
|
|
// in that case we break
|
2017-08-05 10:20:17 +00:00
|
|
|
if ((oplen = r_anal_op (anal, &op, addr + idx, buf + addrbytes * idx, len - addrbytes * idx)) < 1) {
|
2017-05-23 21:55:22 +00:00
|
|
|
VERBOSE_ANAL eprintf ("Unknown opcode at 0x%08"PFMT64x "\n", addr + idx);
|
2016-10-24 23:12:06 +00:00
|
|
|
if (!idx) {
|
2014-09-21 23:39:24 +00:00
|
|
|
gotoBeach (R_ANAL_RET_END);
|
2014-06-07 09:59:27 +00:00
|
|
|
} else {
|
2014-08-05 03:37:48 +00:00
|
|
|
break; // unspecified behaviour
|
2014-06-07 09:59:27 +00:00
|
|
|
}
|
2013-10-08 02:58:51 +00:00
|
|
|
}
|
2016-08-01 16:41:07 +00:00
|
|
|
if (idx > 0 && !overlapped) {
|
2016-10-24 23:12:06 +00:00
|
|
|
bbg = bbget (fcn, addr + idx);
|
2013-10-08 02:58:51 +00:00
|
|
|
if (bbg && bbg != bb) {
|
2016-08-01 16:41:07 +00:00
|
|
|
bb->jump = addr + idx;
|
2013-10-08 02:58:51 +00:00
|
|
|
overlapped = 1;
|
2017-03-09 22:46:02 +00:00
|
|
|
VERBOSE_ANAL eprintf("Overlapped at 0x%08"PFMT64x "\n", addr + idx);
|
|
|
|
// return R_ANAL_RET_END;
|
2013-10-08 02:58:51 +00:00
|
|
|
}
|
2010-03-12 02:05:20 +00:00
|
|
|
}
|
2013-10-08 02:58:51 +00:00
|
|
|
if (!overlapped) {
|
2016-06-17 00:49:41 +00:00
|
|
|
r_anal_bb_set_offset (bb, bb->ninstr++, addr + idx - bb->addr);
|
2013-10-08 02:58:51 +00:00
|
|
|
bb->size += oplen;
|
|
|
|
fcn->ninstr++;
|
2017-03-09 22:46:02 +00:00
|
|
|
// FITFCNSZ(); // defer this, in case this instruction is a branch delay entry
|
|
|
|
// fcn->size += oplen; /// XXX. must be the sum of all the bblocks
|
2013-10-08 02:58:51 +00:00
|
|
|
}
|
2016-02-10 23:18:09 +00:00
|
|
|
idx += oplen;
|
|
|
|
delay.un_idx = idx;
|
2016-12-05 17:46:45 +00:00
|
|
|
if (op.delay > 0 && !delay.pending) {
|
2014-06-07 09:59:27 +00:00
|
|
|
// Handle first pass through a branch delay jump:
|
|
|
|
// Come back and handle the current instruction later.
|
2014-09-21 23:39:24 +00:00
|
|
|
// Save the location of it in `delay.idx`
|
2014-06-07 09:59:27 +00:00
|
|
|
// note, we have still increased size of basic block
|
|
|
|
// (and function)
|
2017-03-09 22:46:02 +00:00
|
|
|
VERBOSE_DELAY eprintf("Enter branch delay at 0x%08"PFMT64x ". bb->sz=%d\n", addr + idx - oplen, bb->size);
|
2014-09-21 23:39:24 +00:00
|
|
|
delay.idx = idx - oplen;
|
|
|
|
delay.cnt = op.delay;
|
|
|
|
delay.pending = 1; // we need this in case the actual idx is zero...
|
|
|
|
delay.adjust = !overlapped; // adjustment is required later to avoid double count
|
2014-06-07 09:59:27 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-09-21 23:39:24 +00:00
|
|
|
if (delay.cnt > 0) {
|
2015-07-31 10:40:04 +00:00
|
|
|
// if we had passed a branch delay instruction, keep
|
|
|
|
// track of how many still to process.
|
2014-09-21 23:39:24 +00:00
|
|
|
delay.cnt--;
|
2016-10-24 23:12:06 +00:00
|
|
|
if (!delay.cnt) {
|
2017-03-09 22:46:02 +00:00
|
|
|
VERBOSE_DELAY eprintf("Last branch delayed opcode at 0x%08"PFMT64x ". bb->sz=%d\n", addr + idx - oplen, bb->size);
|
2014-09-21 23:39:24 +00:00
|
|
|
delay.after = idx;
|
|
|
|
idx = delay.idx;
|
2014-06-07 09:59:27 +00:00
|
|
|
// At this point, we are still looking at the
|
|
|
|
// last instruction in the branch delay group.
|
|
|
|
// Next time, we will again be looking
|
|
|
|
// at the original instruction that entered
|
|
|
|
// the branch delay.
|
2014-05-10 16:04:34 +00:00
|
|
|
}
|
2014-09-21 23:39:24 +00:00
|
|
|
} else if (op.delay > 0 && delay.pending) {
|
2017-03-09 22:46:02 +00:00
|
|
|
VERBOSE_DELAY eprintf("Revisit branch delay jump at 0x%08"PFMT64x ". bb->sz=%d\n", addr + idx - oplen, bb->size);
|
2014-06-07 09:59:27 +00:00
|
|
|
// This is the second pass of the branch delaying opcode
|
|
|
|
// But we also already counted this instruction in the
|
|
|
|
// size of the current basic block, so we need to fix that
|
2014-09-21 23:39:24 +00:00
|
|
|
if (delay.adjust) {
|
2014-06-07 09:59:27 +00:00
|
|
|
bb->size -= oplen;
|
|
|
|
fcn->ninstr--;
|
2017-03-09 22:46:02 +00:00
|
|
|
VERBOSE_DELAY eprintf("Correct for branch delay @ %08"PFMT64x " bb.addr=%08"PFMT64x " corrected.bb=%d f.uncorr=%d\n",
|
|
|
|
addr + idx - oplen, bb->addr, bb->size, r_anal_fcn_size (fcn));
|
|
|
|
FITFCNSZ ();
|
2014-05-10 16:04:34 +00:00
|
|
|
}
|
2014-06-07 09:59:27 +00:00
|
|
|
// Next time, we go to the opcode after the delay count
|
2014-09-21 23:39:24 +00:00
|
|
|
// Take care not to use this below, use delay.un_idx instead ...
|
|
|
|
idx = delay.after;
|
|
|
|
delay.pending = delay.after = delay.idx = delay.adjust = 0;
|
2014-05-10 16:04:34 +00:00
|
|
|
}
|
2014-06-07 09:59:27 +00:00
|
|
|
// Note: if we got two branch delay instructions in a row due to an
|
|
|
|
// compiler bug or junk or something it wont get treated as a delay
|
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:
|
2017-03-08 07:44:34 +00:00
|
|
|
if (R_ABS (op.stackptr) < 8096) {
|
|
|
|
fcn->stack += op.stackptr;
|
2017-03-09 12:23:41 +00:00
|
|
|
if (fcn->stack > fcn->maxstack) {
|
2017-02-09 23:02:18 +00:00
|
|
|
fcn->maxstack = fcn->stack;
|
|
|
|
}
|
2016-05-16 01:46:23 +00:00
|
|
|
}
|
2017-02-20 13:20:44 +00:00
|
|
|
bb->stackptr += op.stackptr;
|
2017-01-31 09:00:24 +00:00
|
|
|
break;
|
|
|
|
case R_ANAL_STACK_RESET:
|
|
|
|
bb->stackptr = 0;
|
2010-05-19 00:39:01 +00:00
|
|
|
break;
|
2017-03-09 12:23:41 +00:00
|
|
|
// TODO: use fcn->maxstack to know our stackframe
|
2010-05-14 21:04:10 +00:00
|
|
|
case R_ANAL_STACK_SET:
|
2017-03-09 22:46:02 +00:00
|
|
|
if ((int) op.ptr > 0) {
|
|
|
|
varname = get_varname (anal, fcn, 'b', ARGPREFIX, R_ABS (op.ptr));
|
2010-03-12 02:05:20 +00:00
|
|
|
} else {
|
2017-03-09 22:46:02 +00:00
|
|
|
varname = get_varname (anal, fcn, 'b', VARPREFIX, R_ABS (op.ptr));
|
2010-03-12 02:05:20 +00:00
|
|
|
}
|
2016-08-01 16:41:07 +00:00
|
|
|
r_anal_var_add (anal, fcn->addr, 1, op.ptr, 'b', NULL, anal->bits / 8, varname);
|
2016-07-01 14:15:29 +00:00
|
|
|
r_anal_var_access (anal, fcn->addr, 'b', 1, op.ptr, 1, op.addr);
|
2010-03-12 02:05:20 +00:00
|
|
|
free (varname);
|
|
|
|
break;
|
2017-03-09 12:23:41 +00:00
|
|
|
// TODO: use fcn->maxstack to know our stackframe
|
2010-05-14 21:04:10 +00:00
|
|
|
case R_ANAL_STACK_GET:
|
2017-03-09 22:46:02 +00:00
|
|
|
if (((int) op.ptr) > 0) {
|
|
|
|
varname = get_varname (anal, fcn, 'b', ARGPREFIX, R_ABS (op.ptr));
|
2010-03-12 02:05:20 +00:00
|
|
|
} else {
|
2017-03-09 22:46:02 +00:00
|
|
|
varname = get_varname (anal, fcn, 'b', VARPREFIX, R_ABS (op.ptr));
|
2010-03-12 02:05:20 +00:00
|
|
|
}
|
2017-03-09 22:46:02 +00:00
|
|
|
r_anal_var_add (anal, fcn->addr, 1, op.ptr, 'b', NULL, anal->bits / 8, varname);
|
2016-07-01 14:15:29 +00:00
|
|
|
r_anal_var_access (anal, fcn->addr, 'b', 1, op.ptr, 0, op.addr);
|
2010-03-12 02:05:20 +00:00
|
|
|
free (varname);
|
|
|
|
break;
|
|
|
|
}
|
2015-11-24 13:49:44 +00:00
|
|
|
|
2015-11-26 09:15:17 +00:00
|
|
|
if (op.ptr && op.ptr != UT64_MAX && op.ptr != UT32_MAX) {
|
2015-07-31 10:40:04 +00:00
|
|
|
// swapped parameters wtf
|
2015-11-25 11:14:40 +00:00
|
|
|
r_anal_fcn_xref_add (anal, fcn, op.addr, op.ptr, R_ANAL_REF_TYPE_DATA);
|
2013-07-19 01:35:45 +00:00
|
|
|
}
|
2015-11-20 14:35:47 +00:00
|
|
|
|
2016-09-18 21:02:49 +00:00
|
|
|
switch (op.type & R_ANAL_OP_TYPE_MASK) {
|
2016-09-05 18:42:04 +00:00
|
|
|
case R_ANAL_OP_TYPE_MOV:
|
2017-03-09 22:46:02 +00:00
|
|
|
// skip mov reg,reg
|
|
|
|
if (anal->opt.hpskip && regs_exist (op.src[0], op.dst)
|
|
|
|
&& !strcmp (op.src[0]->reg->name, op.dst->reg->name)) {
|
2016-09-05 18:42:04 +00:00
|
|
|
skip_ret = skip_hp (anal, fcn, &op, bb, addr, tmp_buf, oplen, delay.un_idx, &idx);
|
|
|
|
if (skip_ret == 1) {
|
|
|
|
goto repeat;
|
|
|
|
}
|
|
|
|
if (skip_ret == 2) {
|
|
|
|
return R_ANAL_RET_END;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2016-05-30 02:18:48 +00:00
|
|
|
case R_ANAL_OP_TYPE_LEA:
|
2017-03-09 22:46:02 +00:00
|
|
|
// skip lea reg,[reg]
|
|
|
|
if (anal->opt.hpskip && regs_exist (op.src[0], op.dst)
|
|
|
|
&& !strcmp (op.src[0]->reg->name, op.dst->reg->name)) {
|
2016-09-05 18:42:04 +00:00
|
|
|
skip_ret = skip_hp (anal, fcn, &op, bb, addr, tmp_buf, oplen, delay.un_idx, &idx);
|
|
|
|
if (skip_ret == 1) {
|
|
|
|
goto repeat;
|
|
|
|
}
|
|
|
|
if (skip_ret == 2) {
|
|
|
|
return R_ANAL_RET_END;
|
|
|
|
}
|
|
|
|
}
|
2016-05-30 02:18:48 +00:00
|
|
|
if (anal->opt.jmptbl) {
|
2017-05-23 21:55:22 +00:00
|
|
|
if (is_delta_pointer_table (anal, op.addr, op.ptr)) {
|
2017-08-25 22:37:38 +00:00
|
|
|
char *str = r_str_newf ("pxt. 0x%08" PFMT64x" @ 0x%08"PFMT64x "\n", op.addr, op.ptr);
|
2017-08-30 21:04:40 +00:00
|
|
|
if (!anal->cmdtail) {
|
2017-08-25 22:37:38 +00:00
|
|
|
anal->cmdtail = r_str_appendf (anal->cmdtail, str);
|
|
|
|
}
|
2017-08-30 21:04:40 +00:00
|
|
|
if (anal->cmdtail && !strstr (anal->cmdtail, str)) {
|
|
|
|
anal->cmdtail = r_str_appendf (anal->cmdtail, str);
|
|
|
|
}
|
2017-08-25 22:37:38 +00:00
|
|
|
free (str);
|
2017-03-09 22:46:02 +00:00
|
|
|
// jmptbl_addr = op.ptr;
|
|
|
|
// jmptbl_size = -1;
|
|
|
|
// ret = try_walkthrough_jmptbl (anal, fcn, depth, op.addr, op.ptr, 4);
|
2016-05-30 02:18:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2015-01-10 02:21:27 +00:00
|
|
|
case R_ANAL_OP_TYPE_ILL:
|
2016-09-05 18:42:04 +00:00
|
|
|
if (anal->opt.nopskip && len > 3 && !memcmp (buf, "\x00\x00\x00\x00", 4)) {
|
2017-01-23 22:13:51 +00:00
|
|
|
if ((addr + delay.un_idx - oplen) == fcn->addr) {
|
2015-01-10 02:21:27 +00:00
|
|
|
fcn->addr += oplen;
|
|
|
|
bb->size -= oplen;
|
|
|
|
bb->addr += oplen;
|
|
|
|
idx = delay.un_idx;
|
|
|
|
goto repeat;
|
|
|
|
} else {
|
|
|
|
// sa
|
|
|
|
bb->size -= oplen;
|
|
|
|
op.type = R_ANAL_OP_TYPE_RET;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
FITFCNSZ ();
|
|
|
|
r_anal_op_fini (&op);
|
|
|
|
gotoBeach (R_ANAL_RET_END);
|
|
|
|
break;
|
2014-12-22 22:36:21 +00:00
|
|
|
case R_ANAL_OP_TYPE_TRAP:
|
2016-08-01 16:41:07 +00:00
|
|
|
if (anal->opt.nopskip && buf[0] == 0xcc) {
|
|
|
|
if ((addr + delay.un_idx - oplen) == fcn->addr) {
|
2014-12-22 22:36:21 +00:00
|
|
|
fcn->addr += oplen;
|
|
|
|
bb->size -= oplen;
|
|
|
|
bb->addr += oplen;
|
|
|
|
idx = delay.un_idx;
|
|
|
|
goto repeat;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
FITFCNSZ ();
|
|
|
|
r_anal_op_fini (&op);
|
|
|
|
return R_ANAL_RET_END;
|
2014-04-07 11:49:09 +00:00
|
|
|
case R_ANAL_OP_TYPE_NOP:
|
2015-09-06 22:30:48 +00:00
|
|
|
if (anal->opt.nopskip) {
|
2016-09-05 18:42:04 +00:00
|
|
|
if (!strcmp (anal->cur->arch, "mips")) {
|
2017-03-09 22:46:02 +00:00
|
|
|
// Looks like this flags check is useful only for mips
|
2016-09-05 18:42:04 +00:00
|
|
|
// do not skip nops if there's a flag at starting address
|
2016-12-01 09:48:00 +00:00
|
|
|
RFlagItem *fi = anal->flb.get_at (anal->flb.f, addr, false);
|
2016-09-05 18:42:04 +00:00
|
|
|
if (!fi || strncmp (fi->name, "sym.", 4)) {
|
|
|
|
if ((addr + delay.un_idx - oplen) == fcn->addr) {
|
|
|
|
fcn->addr += oplen;
|
|
|
|
bb->size -= oplen;
|
|
|
|
bb->addr += oplen;
|
|
|
|
idx = delay.un_idx;
|
|
|
|
goto repeat;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2017-06-06 23:53:59 +00:00
|
|
|
RFlagItem *fi = anal->flb.get_at (anal->flb.f, fcn->addr? fcn->addr: addr, false);
|
2017-01-23 22:19:02 +00:00
|
|
|
if (fi) {
|
2017-01-23 22:13:51 +00:00
|
|
|
break;
|
|
|
|
}
|
2016-09-05 18:42:04 +00:00
|
|
|
skip_ret = skip_hp (anal, fcn, &op, bb, addr, tmp_buf, oplen, delay.un_idx, &idx);
|
|
|
|
if (skip_ret == 1) {
|
2016-02-16 02:47:15 +00:00
|
|
|
goto repeat;
|
|
|
|
}
|
2016-09-05 18:42:04 +00:00
|
|
|
if (skip_ret == 2) {
|
|
|
|
return R_ANAL_RET_END;
|
|
|
|
}
|
2014-09-14 09:52:30 +00:00
|
|
|
}
|
2014-04-07 11:49:09 +00:00
|
|
|
}
|
|
|
|
break;
|
2010-06-13 22:57:40 +00:00
|
|
|
case R_ANAL_OP_TYPE_JMP:
|
2017-04-12 01:11:35 +00:00
|
|
|
{
|
|
|
|
RFlagItem *fi = anal->flb.get_at (anal->flb.f, op.jump, false);
|
|
|
|
if (fi && strstr (fi->name, "imp.")) {
|
|
|
|
FITFCNSZ ();
|
|
|
|
r_anal_op_fini (&op);
|
|
|
|
return R_ANAL_RET_END;
|
|
|
|
}
|
|
|
|
}
|
2016-09-18 20:20:46 +00:00
|
|
|
if (op.jump == UT64_MAX) {
|
|
|
|
FITFCNSZ ();
|
|
|
|
r_anal_op_fini (&op);
|
|
|
|
return R_ANAL_RET_END;
|
|
|
|
}
|
2016-05-15 00:33:03 +00:00
|
|
|
if (anal->opt.jmpref) {
|
2015-11-24 12:01:26 +00:00
|
|
|
(void) r_anal_fcn_xref_add (anal, fcn, op.addr, op.jump, R_ANAL_REF_TYPE_CODE);
|
2016-05-15 00:33:03 +00:00
|
|
|
}
|
2016-12-01 09:48:00 +00:00
|
|
|
if (!anal->opt.jmpabove && (op.jump < fcn->addr)) {
|
|
|
|
FITFCNSZ ();
|
|
|
|
r_anal_op_fini (&op);
|
|
|
|
return R_ANAL_RET_END;
|
|
|
|
}
|
|
|
|
if (r_anal_noreturn_at (anal, op.jump)) {
|
2015-11-12 12:47:44 +00:00
|
|
|
FITFCNSZ ();
|
|
|
|
r_anal_op_fini (&op);
|
|
|
|
return R_ANAL_RET_END;
|
|
|
|
}
|
2016-04-01 17:39:31 +00:00
|
|
|
{
|
|
|
|
bool must_eob = anal->opt.eobjmp;
|
|
|
|
if (!must_eob) {
|
2017-08-23 20:28:49 +00:00
|
|
|
RIOSection *s = anal->iob.sect_vget (anal->iob.io, addr);
|
2017-08-24 00:00:33 +00:00
|
|
|
if (s) {
|
2017-08-24 00:10:20 +00:00
|
|
|
must_eob = (op.jump < s->vaddr || op.jump >= s->vaddr + s->vsize);
|
2017-08-24 00:00:33 +00:00
|
|
|
}
|
2016-04-01 17:39:31 +00:00
|
|
|
}
|
|
|
|
if (must_eob) {
|
2017-03-09 22:46:02 +00:00
|
|
|
FITFCNSZ ();
|
2016-04-01 17:39:31 +00:00
|
|
|
op.jump = UT64_MAX;
|
|
|
|
recurseAt (op.jump);
|
|
|
|
recurseAt (op.fail);
|
|
|
|
gotoBeachRet ();
|
|
|
|
return R_ANAL_RET_END;
|
|
|
|
}
|
2015-08-18 00:44:59 +00:00
|
|
|
}
|
2015-09-06 22:30:48 +00:00
|
|
|
if (anal->opt.bbsplit) {
|
2016-08-01 16:41:07 +00:00
|
|
|
#if FIX_JMP_FWD
|
|
|
|
bb->jump = op.jump;
|
|
|
|
bb->fail = UT64_MAX;
|
2017-03-09 22:46:02 +00:00
|
|
|
FITFCNSZ ();
|
2016-08-01 16:41:07 +00:00
|
|
|
return R_ANAL_RET_END;
|
|
|
|
#else
|
2015-07-31 10:40:04 +00:00
|
|
|
if (!overlapped) {
|
|
|
|
bb->jump = op.jump;
|
|
|
|
bb->fail = UT64_MAX;
|
|
|
|
}
|
2014-12-22 22:36:21 +00:00
|
|
|
recurseAt (op.jump);
|
2017-03-09 22:46:02 +00:00
|
|
|
FITFCNSZ ();
|
2015-07-31 10:40:04 +00:00
|
|
|
gotoBeachRet ();
|
2016-08-01 16:41:07 +00:00
|
|
|
#endif
|
2014-12-22 22:36:21 +00:00
|
|
|
} else {
|
2015-07-31 10:40:04 +00:00
|
|
|
if (continue_after_jump) {
|
|
|
|
recurseAt (op.jump);
|
|
|
|
recurseAt (op.fail);
|
2014-12-22 22:36:21 +00:00
|
|
|
} else {
|
2015-07-31 10:40:04 +00:00
|
|
|
// This code seems to break #1519
|
2015-09-06 22:30:48 +00:00
|
|
|
if (anal->opt.eobjmp) {
|
2015-07-31 10:40:04 +00:00
|
|
|
#if JMP_IS_EOB
|
2014-12-22 22:36:21 +00:00
|
|
|
if (!overlapped) {
|
|
|
|
bb->jump = op.jump;
|
|
|
|
bb->fail = UT64_MAX;
|
|
|
|
}
|
2017-03-09 22:46:02 +00:00
|
|
|
FITFCNSZ ();
|
2014-12-22 22:36:21 +00:00
|
|
|
return R_ANAL_RET_END;
|
2015-07-31 10:40:04 +00:00
|
|
|
#else
|
|
|
|
// hardcoded jmp size // must be checked at the end wtf?
|
|
|
|
// always fitfcnsz and retend
|
2016-08-01 16:41:07 +00:00
|
|
|
if (r_anal_fcn_is_in_offset (fcn, op.jump)) {
|
2015-07-31 10:40:04 +00:00
|
|
|
/* jump inside the same function */
|
2017-03-09 22:46:02 +00:00
|
|
|
FITFCNSZ ();
|
2015-07-31 10:40:04 +00:00
|
|
|
return R_ANAL_RET_END;
|
2016-10-24 23:12:06 +00:00
|
|
|
#if JMP_IS_EOB_RANGE > 0
|
2015-07-31 10:40:04 +00:00
|
|
|
} else {
|
2016-08-01 16:41:07 +00:00
|
|
|
if (op.jump < addr - JMP_IS_EOB_RANGE && op.jump < addr) {
|
2015-07-31 10:40:04 +00:00
|
|
|
gotoBeach (R_ANAL_RET_END);
|
|
|
|
}
|
2016-08-01 16:41:07 +00:00
|
|
|
if (op.jump > addr + JMP_IS_EOB_RANGE) {
|
2015-07-31 10:40:04 +00:00
|
|
|
gotoBeach (R_ANAL_RET_END);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
/* if not eobjmp. a jump will break the function if jumps before the beginning of the function */
|
|
|
|
if (op.jump < fcn->addr) {
|
|
|
|
if (!overlapped) {
|
|
|
|
bb->jump = op.jump;
|
|
|
|
bb->fail = UT64_MAX;
|
|
|
|
}
|
2017-03-09 22:46:02 +00:00
|
|
|
FITFCNSZ ();
|
2015-07-31 10:40:04 +00:00
|
|
|
return R_ANAL_RET_END;
|
|
|
|
}
|
2014-12-22 22:36:21 +00:00
|
|
|
}
|
2014-11-25 01:07:01 +00:00
|
|
|
}
|
|
|
|
}
|
2013-10-25 00:06:00 +00:00
|
|
|
break;
|
2010-08-02 10:42:59 +00:00
|
|
|
case R_ANAL_OP_TYPE_CJMP:
|
2015-09-06 22:30:48 +00:00
|
|
|
if (anal->opt.cjmpref) {
|
|
|
|
(void) r_anal_fcn_xref_add (anal, fcn,
|
|
|
|
op.addr, op.jump, R_ANAL_REF_TYPE_CODE);
|
|
|
|
}
|
2013-10-08 02:58:51 +00:00
|
|
|
if (!overlapped) {
|
|
|
|
bb->jump = op.jump;
|
|
|
|
bb->fail = op.fail;
|
|
|
|
}
|
2015-05-13 23:17:35 +00:00
|
|
|
if (continue_after_jump) {
|
|
|
|
recurseAt (op.jump);
|
|
|
|
recurseAt (op.fail);
|
|
|
|
} else {
|
|
|
|
// This code seems to break #1519
|
2015-09-06 22:30:48 +00:00
|
|
|
if (anal->opt.eobjmp) {
|
2015-05-13 23:17:35 +00:00
|
|
|
#if JMP_IS_EOB
|
|
|
|
if (!overlapped) {
|
|
|
|
bb->jump = op.jump;
|
|
|
|
bb->fail = UT64_MAX;
|
|
|
|
}
|
2017-03-09 22:46:02 +00:00
|
|
|
FITFCNSZ ();
|
2015-07-31 10:40:04 +00:00
|
|
|
recurseAt (op.jump);
|
|
|
|
recurseAt (op.fail);
|
2015-05-13 23:17:35 +00:00
|
|
|
return R_ANAL_RET_END;
|
|
|
|
#else
|
|
|
|
// hardcoded jmp size // must be checked at the end wtf?
|
|
|
|
// always fitfcnsz and retend
|
2016-08-01 16:41:07 +00:00
|
|
|
if (op.jump > fcn->addr + JMP_IS_EOB_RANGE) {
|
2015-07-31 10:40:04 +00:00
|
|
|
recurseAt (op.fail);
|
2015-05-13 23:17:35 +00:00
|
|
|
/* jump inside the same function */
|
2017-03-09 22:46:02 +00:00
|
|
|
FITFCNSZ ();
|
2015-05-13 23:17:35 +00:00
|
|
|
return R_ANAL_RET_END;
|
2016-08-01 16:41:07 +00:00
|
|
|
#if JMP_IS_EOB_RANGE > 0
|
2015-05-13 23:17:35 +00:00
|
|
|
} else {
|
2017-03-09 22:46:02 +00:00
|
|
|
if (op.jump < addr - JMP_IS_EOB_RANGE && op.jump < addr) {
|
2015-05-13 23:17:35 +00:00
|
|
|
gotoBeach (R_ANAL_RET_END);
|
|
|
|
}
|
2016-12-29 02:34:16 +00:00
|
|
|
if (op.jump > addr + JMP_IS_EOB_RANGE) {
|
2015-05-13 23:17:35 +00:00
|
|
|
gotoBeach (R_ANAL_RET_END);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
2015-07-31 10:40:04 +00:00
|
|
|
recurseAt (op.jump);
|
|
|
|
recurseAt (op.fail);
|
2015-05-13 23:17:35 +00:00
|
|
|
} else {
|
|
|
|
/* if not eobjmp. a jump will break the function if jumps before the beginning of the function */
|
2015-07-31 10:40:04 +00:00
|
|
|
recurseAt (op.jump);
|
|
|
|
recurseAt (op.fail);
|
2015-05-13 23:17:35 +00:00
|
|
|
if (op.jump < fcn->addr) {
|
|
|
|
if (!overlapped) {
|
|
|
|
bb->jump = op.jump;
|
|
|
|
bb->fail = UT64_MAX;
|
|
|
|
}
|
2017-03-09 22:46:02 +00:00
|
|
|
FITFCNSZ ();
|
2015-05-13 23:17:35 +00:00
|
|
|
return R_ANAL_RET_END;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-09-21 23:39:24 +00:00
|
|
|
|
|
|
|
// XXX breaks mips analysis too !op.delay
|
|
|
|
// this will be all x86, arm (at least)
|
|
|
|
// without which the analysis is really slow,
|
|
|
|
// presumably because each opcode would get revisited
|
|
|
|
// (and already covered by a bb) many times
|
2016-08-01 16:41:07 +00:00
|
|
|
gotoBeachRet ();
|
2015-07-31 10:40:04 +00:00
|
|
|
// For some reason, branch delayed code (MIPS) needs to continue
|
2013-09-11 22:41:01 +00:00
|
|
|
break;
|
2016-06-19 10:26:58 +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:
|
2016-06-19 10:26:58 +00:00
|
|
|
/* call [dst] */
|
|
|
|
if (op.ptr != UT64_MAX && r_anal_noreturn_at (anal, op.ptr)) {
|
|
|
|
FITFCNSZ ();
|
|
|
|
r_anal_op_fini (&op);
|
|
|
|
return R_ANAL_RET_END;
|
|
|
|
}
|
2016-09-26 21:13:49 +00:00
|
|
|
// XXX: this is TYPE_MCALL or indirect-call
|
2017-03-09 22:46:02 +00:00
|
|
|
(void) r_anal_fcn_xref_add (anal, fcn, op.addr, op.ptr, R_ANAL_REF_TYPE_CALL);
|
2016-06-19 10:26:58 +00:00
|
|
|
break;
|
2014-09-22 19:59:30 +00:00
|
|
|
case R_ANAL_OP_TYPE_CCALL:
|
2010-03-12 02:05:20 +00:00
|
|
|
case R_ANAL_OP_TYPE_CALL:
|
2016-06-19 10:26:58 +00:00
|
|
|
/* call dst */
|
2015-11-12 12:47:44 +00:00
|
|
|
if (r_anal_noreturn_at (anal, op.jump)) {
|
|
|
|
FITFCNSZ ();
|
|
|
|
r_anal_op_fini (&op);
|
|
|
|
return R_ANAL_RET_END;
|
|
|
|
}
|
2017-03-09 22:46:02 +00:00
|
|
|
(void) r_anal_fcn_xref_add (anal, fcn, op.addr, op.jump, R_ANAL_REF_TYPE_CALL);
|
2014-09-21 23:39:24 +00:00
|
|
|
#if CALL_IS_EOB
|
|
|
|
recurseAt (op.jump);
|
|
|
|
recurseAt (op.fail);
|
|
|
|
gotoBeach (R_ANAL_RET_NEW);
|
2014-05-26 08:37:18 +00:00
|
|
|
#endif
|
2010-03-12 02:05:20 +00:00
|
|
|
break;
|
2016-05-29 22:38:35 +00:00
|
|
|
case R_ANAL_OP_TYPE_MJMP:
|
2012-02-15 21:09:23 +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:
|
2015-11-20 08:33:48 +00:00
|
|
|
// switch statement
|
2015-11-20 14:35:47 +00:00
|
|
|
if (anal->opt.jmptbl) {
|
2015-12-10 13:23:37 +00:00
|
|
|
if (fcn->refs->tail) {
|
|
|
|
RAnalRef *last_ref = fcn->refs->tail->data;
|
|
|
|
last_ref->type = R_ANAL_REF_TYPE_NULL;
|
|
|
|
}
|
2017-03-09 22:46:02 +00:00
|
|
|
if (op.ptr != UT64_MAX) { // direct jump
|
2015-12-14 10:18:26 +00:00
|
|
|
ret = try_walkthrough_jmptbl (anal, fcn, depth, addr + idx, op.ptr, ret);
|
2015-11-20 14:35:47 +00:00
|
|
|
|
2017-03-09 22:46:02 +00:00
|
|
|
} else { // indirect jump: table pointer is unknown
|
2015-12-14 17:37:32 +00:00
|
|
|
if (op.src[0] && op.src[0]->reg) {
|
2016-04-02 21:58:52 +00:00
|
|
|
ut64 ptr = search_reg_val (anal, buf, idx, addr, op.src[0]->reg->name);
|
2016-05-30 02:18:48 +00:00
|
|
|
if (ptr && ptr != UT64_MAX) {
|
2015-12-14 10:18:26 +00:00
|
|
|
ret = try_walkthrough_jmptbl (anal, fcn, depth, addr + idx, ptr, ret);
|
2016-05-30 02:18:48 +00:00
|
|
|
}
|
2015-11-20 08:33:48 +00:00
|
|
|
}
|
|
|
|
}
|
2016-12-29 02:34:16 +00:00
|
|
|
walk_switch (anal, fcn, op.addr, op.addr + op.size);
|
2015-12-14 17:37:32 +00:00
|
|
|
}
|
2016-12-29 02:34:16 +00:00
|
|
|
if (anal->cur) {
|
2016-11-16 16:42:23 +00:00
|
|
|
/* if UJMP is in .plt section just skip it */
|
2017-08-28 14:44:20 +00:00
|
|
|
RBinSection *s = anal->binb.get_vsect_at (anal->binb.bin, addr);
|
2017-09-13 08:52:55 +00:00
|
|
|
if (s && s->name[0]) {
|
2016-08-07 08:17:05 +00:00
|
|
|
bool in_plt = strstr (s->name, ".plt") != NULL;
|
2017-01-23 22:13:51 +00:00
|
|
|
if (!in_plt && strstr (s->name, "_stubs") != NULL) {
|
|
|
|
/* for mach0 */
|
|
|
|
in_plt = true;
|
|
|
|
}
|
2016-11-16 16:42:23 +00:00
|
|
|
if (anal->cur->arch && strstr (anal->cur->arch, "arm")) {
|
2016-05-09 21:08:25 +00:00
|
|
|
if (anal->bits == 64) {
|
2017-03-09 22:46:02 +00:00
|
|
|
if (!in_plt) {
|
|
|
|
goto river;
|
|
|
|
}
|
2016-05-09 21:08:25 +00:00
|
|
|
}
|
2016-04-02 21:58:52 +00:00
|
|
|
} else {
|
2017-05-08 01:51:36 +00:00
|
|
|
if (in_plt && !strstr (s->name, "_stubs")) {
|
2016-12-29 02:34:16 +00:00
|
|
|
goto river;
|
|
|
|
}
|
2016-04-02 21:58:52 +00:00
|
|
|
}
|
2015-12-14 10:18:26 +00:00
|
|
|
}
|
|
|
|
}
|
2016-04-01 10:24:19 +00:00
|
|
|
FITFCNSZ ();
|
|
|
|
r_anal_op_fini (&op);
|
|
|
|
return R_ANAL_RET_END;
|
2016-04-02 21:58:52 +00:00
|
|
|
river:
|
2016-04-01 10:24:19 +00:00
|
|
|
break;
|
2017-03-09 22:46:02 +00:00
|
|
|
/* fallthru */
|
2016-04-14 12:27:44 +00:00
|
|
|
case R_ANAL_OP_TYPE_PUSH:
|
|
|
|
last_is_push = true;
|
|
|
|
last_push_addr = op.val;
|
2016-10-04 19:03:11 +00:00
|
|
|
if (anal->iob.is_valid_offset (anal->iob.io, op.val, 1)) {
|
2017-03-09 22:46:02 +00:00
|
|
|
(void) r_anal_fcn_xref_add (anal, fcn, op.addr, op.val, R_ANAL_REF_TYPE_DATA);
|
2016-10-04 19:03:11 +00:00
|
|
|
}
|
2016-04-14 12:27:44 +00:00
|
|
|
break;
|
2010-03-12 02:05:20 +00:00
|
|
|
case R_ANAL_OP_TYPE_RET:
|
2016-07-25 18:15:50 +00:00
|
|
|
if (op.family == R_ANAL_OP_FAMILY_PRIV) {
|
|
|
|
fcn->type = R_ANAL_FCN_TYPE_INT;
|
|
|
|
}
|
2016-04-14 12:27:44 +00:00
|
|
|
if (last_is_push && anal->opt.pushret) {
|
|
|
|
op.type = R_ANAL_OP_TYPE_JMP;
|
|
|
|
op.jump = last_push_addr;
|
|
|
|
bb->jump = op.jump;
|
|
|
|
recurseAt (op.jump);
|
2016-07-25 18:15:50 +00:00
|
|
|
gotoBeachRet ();
|
2016-04-14 12:27:44 +00:00
|
|
|
} else {
|
2016-10-24 23:12:06 +00:00
|
|
|
if (!op.cond) {
|
2017-03-09 22:46:02 +00:00
|
|
|
VERBOSE_ANAL eprintf("RET 0x%08"PFMT64x ". %d %d %d\n",
|
|
|
|
addr + delay.un_idx - oplen, overlapped,
|
|
|
|
bb->size, r_anal_fcn_size (fcn));
|
2016-04-14 12:27:44 +00:00
|
|
|
FITFCNSZ ();
|
|
|
|
r_anal_op_fini (&op);
|
|
|
|
return R_ANAL_RET_END;
|
|
|
|
}
|
2016-03-31 21:38:25 +00:00
|
|
|
}
|
|
|
|
break;
|
2010-03-12 02:05:20 +00:00
|
|
|
}
|
2016-07-25 18:15:50 +00:00
|
|
|
if (op.type != R_ANAL_OP_TYPE_PUSH) {
|
2016-04-14 12:27:44 +00:00
|
|
|
last_is_push = false;
|
2016-07-25 18:15:50 +00:00
|
|
|
}
|
2010-03-12 02:05:20 +00:00
|
|
|
}
|
2014-09-21 23:39:24 +00:00
|
|
|
beach:
|
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;
|
|
|
|
}
|
|
|
|
|
2015-12-08 09:54:57 +00:00
|
|
|
static int check_preludes(ut8 *buf, ut16 bufsz) {
|
2016-08-01 16:41:07 +00:00
|
|
|
if (bufsz < 10) {
|
|
|
|
return false;
|
|
|
|
}
|
2017-03-09 22:46:02 +00:00
|
|
|
if (!memcmp (buf, (const ut8 *) "\x55\x89\xe5", 3)) {
|
2015-11-26 13:32:07 +00:00
|
|
|
return true;
|
2017-03-09 22:46:02 +00:00
|
|
|
} else if (!memcmp (buf, (const ut8 *) "\x55\x8b\xec", 3)) {
|
2015-11-26 13:32:07 +00:00
|
|
|
return true;
|
2017-03-09 22:46:02 +00:00
|
|
|
} else if (!memcmp (buf, (const ut8 *) "\x8b\xff", 2)) {
|
2015-11-26 13:32:07 +00:00
|
|
|
return true;
|
2017-03-09 22:46:02 +00:00
|
|
|
} else if (!memcmp (buf, (const ut8 *) "\x55\x48\x89\xe5", 4)) {
|
2015-11-26 13:32:07 +00:00
|
|
|
return true;
|
2017-03-09 22:46:02 +00:00
|
|
|
} else if (!memcmp (buf, (const ut8 *) "\x55\x48\x8b\xec", 4)) {
|
2015-11-26 13:32:07 +00:00
|
|
|
return true;
|
2016-08-01 16:41:07 +00:00
|
|
|
}
|
2015-11-26 13:32:07 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-05-15 00:33:03 +00:00
|
|
|
R_API bool r_anal_check_fcn(RAnal *anal, ut8 *buf, ut16 bufsz, ut64 addr, ut64 low, ut64 high) {
|
2017-03-09 22:46:02 +00:00
|
|
|
RAnalOp op = {
|
|
|
|
0
|
|
|
|
};
|
2015-12-04 11:49:30 +00:00
|
|
|
int i, oplen, opcnt = 0, pushcnt = 0, movcnt = 0, brcnt = 0;
|
2016-08-01 16:41:07 +00:00
|
|
|
if (check_preludes (buf, bufsz)) {
|
|
|
|
return true;
|
|
|
|
}
|
2015-11-26 13:32:07 +00:00
|
|
|
for (i = 0; i < bufsz && opcnt < 10; i += oplen, opcnt++) {
|
|
|
|
r_anal_op_fini (&op);
|
2016-08-01 16:41:07 +00:00
|
|
|
if ((oplen = r_anal_op (anal, &op, addr + i, buf + i, bufsz - i)) < 1) {
|
2015-11-26 13:32:07 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
switch (op.type) {
|
|
|
|
case R_ANAL_OP_TYPE_PUSH:
|
|
|
|
case R_ANAL_OP_TYPE_UPUSH:
|
|
|
|
pushcnt++;
|
|
|
|
break;
|
|
|
|
case R_ANAL_OP_TYPE_MOV:
|
|
|
|
case R_ANAL_OP_TYPE_CMOV:
|
|
|
|
movcnt++;
|
|
|
|
break;
|
|
|
|
case R_ANAL_OP_TYPE_JMP:
|
|
|
|
case R_ANAL_OP_TYPE_CJMP:
|
|
|
|
case R_ANAL_OP_TYPE_CALL:
|
2016-05-15 00:33:03 +00:00
|
|
|
if (op.jump < low || op.jump >= high) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-12-04 11:49:30 +00:00
|
|
|
brcnt++;
|
2015-11-26 13:32:07 +00:00
|
|
|
break;
|
|
|
|
case R_ANAL_OP_TYPE_UNK:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2015-12-04 11:49:30 +00:00
|
|
|
return (pushcnt + movcnt + brcnt > 5);
|
2015-11-26 13:32:07 +00:00
|
|
|
}
|
|
|
|
|
2017-03-09 22:46:02 +00:00
|
|
|
static void fcnfit(RAnal *a, RAnalFunction *f) {
|
2014-09-02 00:41:40 +00:00
|
|
|
// find next function
|
|
|
|
RAnalFunction *next = r_anal_fcn_next (a, f->addr);
|
|
|
|
if (next) {
|
2017-03-09 22:46:02 +00:00
|
|
|
if ((f->addr + r_anal_fcn_size (f)) > next->addr) {
|
2014-09-02 00:41:40 +00:00
|
|
|
r_anal_fcn_resize (f, (next->addr - f->addr));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-09 22:46:02 +00:00
|
|
|
R_API void r_anal_fcn_fit_overlaps(RAnal *anal, RAnalFunction *fcn) {
|
2014-09-02 00:41:40 +00:00
|
|
|
if (fcn) {
|
|
|
|
fcnfit (anal, fcn);
|
|
|
|
} else {
|
|
|
|
RAnalFunction *f;
|
|
|
|
RListIter *iter;
|
|
|
|
r_list_foreach (anal->fcns, iter, f) {
|
|
|
|
fcnfit (anal, f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-09 15:02:45 +00:00
|
|
|
R_API void r_anal_trim_jmprefs(RAnalFunction *fcn) {
|
2015-12-02 15:17:12 +00:00
|
|
|
RAnalRef *ref;
|
|
|
|
RListIter *iter;
|
2015-12-05 18:56:56 +00:00
|
|
|
RListIter *tmp;
|
|
|
|
r_list_foreach_safe (fcn->refs, iter, tmp, ref) {
|
2016-05-14 14:37:24 +00:00
|
|
|
if (ref->type == R_ANAL_REF_TYPE_CODE && r_anal_fcn_is_in_offset (fcn, ref->addr)) {
|
2016-08-01 16:41:07 +00:00
|
|
|
r_list_delete (fcn->refs, iter);
|
2015-12-02 15:17:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-07-25 18:15:50 +00:00
|
|
|
|
2013-10-08 02:58:51 +00:00
|
|
|
R_API int r_anal_fcn(RAnal *anal, RAnalFunction *fcn, ut64 addr, ut8 *buf, ut64 len, int reftype) {
|
2015-12-02 15:17:12 +00:00
|
|
|
int ret;
|
2016-05-15 12:37:22 +00:00
|
|
|
r_anal_fcn_set_size (fcn, 0);
|
2016-08-01 16:41:07 +00:00
|
|
|
/* defines fcn. or loc. prefix */
|
2016-07-25 18:15:50 +00:00
|
|
|
fcn->type = (reftype == R_ANAL_REF_TYPE_CODE)
|
2017-03-09 22:46:02 +00:00
|
|
|
? R_ANAL_FCN_TYPE_LOC
|
2016-07-25 18:15:50 +00:00
|
|
|
: R_ANAL_FCN_TYPE_FCN;
|
|
|
|
if (fcn->addr == UT64_MAX) {
|
|
|
|
fcn->addr = addr;
|
|
|
|
}
|
2014-09-22 13:00:41 +00:00
|
|
|
if (anal->cur && anal->cur->fcn) {
|
|
|
|
int result = anal->cur->fcn (anal, fcn, addr, buf, len, reftype);
|
2016-08-01 16:41:07 +00:00
|
|
|
if (anal->cur->custom_fn_anal) {
|
|
|
|
return result;
|
|
|
|
}
|
2014-01-02 05:09:46 +00:00
|
|
|
}
|
2016-05-16 01:46:23 +00:00
|
|
|
fcn->maxstack = 0;
|
2015-12-02 15:17:12 +00:00
|
|
|
ret = fcn_recurse (anal, fcn, addr, buf, len, FCN_DEPTH);
|
2017-03-09 22:46:02 +00:00
|
|
|
// update tinyrange for the function
|
2017-09-04 00:56:54 +00:00
|
|
|
r_anal_fcn_update_tinyrange_bbs (fcn);
|
2015-12-02 15:17:12 +00:00
|
|
|
|
2017-03-09 22:46:02 +00:00
|
|
|
if (ret == R_ANAL_RET_END && r_anal_fcn_size (fcn)) { // cfg analysis completed
|
2015-12-02 15:17:12 +00:00
|
|
|
RListIter *iter;
|
|
|
|
RAnalBlock *bb;
|
|
|
|
ut64 endaddr = fcn->addr;
|
|
|
|
ut64 overlapped = -1;
|
|
|
|
RAnalFunction *fcn1 = NULL;
|
|
|
|
|
|
|
|
// set function size as length of continuous sequence of bbs
|
|
|
|
r_list_sort (fcn->bbs, &cmpaddr);
|
|
|
|
r_list_foreach (fcn->bbs, iter, bb) {
|
2015-12-11 11:37:25 +00:00
|
|
|
if (endaddr == bb->addr) {
|
|
|
|
endaddr += bb->size;
|
|
|
|
} else if (endaddr < bb->addr &&
|
2017-03-09 22:46:02 +00:00
|
|
|
bb->addr - endaddr <
|
|
|
|
anal->opt.bbs_alignment &&
|
|
|
|
!(bb->addr &
|
|
|
|
(anal->opt.bbs_alignment - 1))) {
|
2015-12-11 11:37:25 +00:00
|
|
|
endaddr = bb->addr + bb->size;
|
2016-08-20 22:53:39 +00:00
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
2015-12-02 15:17:12 +00:00
|
|
|
}
|
2016-08-21 10:10:44 +00:00
|
|
|
#if !JAYRO_04
|
2016-02-03 11:53:35 +00:00
|
|
|
r_anal_fcn_resize (fcn, endaddr - fcn->addr);
|
2015-12-02 15:17:12 +00:00
|
|
|
|
|
|
|
// resize function if overlaps
|
|
|
|
r_list_foreach (anal->fcns, iter, fcn1) {
|
2016-08-01 16:41:07 +00:00
|
|
|
if (fcn1->addr >= (fcn->addr) && fcn1->addr < (fcn->addr + r_anal_fcn_size (fcn))) {
|
|
|
|
if (overlapped > fcn1->addr) {
|
|
|
|
overlapped = fcn1->addr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (overlapped != -1) {
|
|
|
|
r_anal_fcn_resize (fcn, overlapped - fcn->addr);
|
2015-12-02 15:17:12 +00:00
|
|
|
}
|
2016-08-21 09:39:37 +00:00
|
|
|
#endif
|
2016-02-03 11:53:35 +00:00
|
|
|
r_anal_trim_jmprefs (fcn);
|
2015-12-02 15:17:12 +00:00
|
|
|
}
|
|
|
|
return ret;
|
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) {
|
2017-03-09 22:46:02 +00:00
|
|
|
// RAnalFunction *f = r_anal_get_fcn_in (anal, fcn->addr, R_ANAL_FCN_TYPE_ROOT);
|
2016-10-05 14:01:01 +00:00
|
|
|
RAnalFunction *f = r_anal_get_fcn_at (anal, fcn->addr, R_ANAL_FCN_TYPE_ROOT);
|
2016-08-01 16:41:07 +00:00
|
|
|
if (f) {
|
|
|
|
return 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
|
2015-07-31 10:40:04 +00:00
|
|
|
/* TODO: sdbization */
|
2014-03-02 21:16:54 +00:00
|
|
|
r_list_append (anal->fcns, fcn);
|
2015-03-16 01:52:26 +00:00
|
|
|
if (anal->cb.on_fcn_new) {
|
|
|
|
anal->cb.on_fcn_new (anal, anal->user, fcn);
|
|
|
|
}
|
2015-09-14 09:31:54 +00:00
|
|
|
return true;
|
2011-09-14 01:47:30 +00:00
|
|
|
}
|
|
|
|
|
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-09-20 08:26:31 +00:00
|
|
|
RAnalFunction *fcn;
|
2015-07-31 10:40:04 +00:00
|
|
|
|
2017-02-09 23:02:18 +00:00
|
|
|
#if 0
|
2016-08-01 16:41:07 +00:00
|
|
|
if (size < 1) {
|
|
|
|
return false;
|
|
|
|
}
|
2017-02-09 23:02:18 +00:00
|
|
|
#endif
|
2014-09-26 13:40:17 +00:00
|
|
|
fcn = r_anal_get_fcn_in (a, addr, R_ANAL_FCN_TYPE_ROOT);
|
2016-08-21 01:07:19 +00:00
|
|
|
if (!fcn) {
|
2016-08-01 16:41:07 +00:00
|
|
|
if (!(fcn = r_anal_fcn_new ())) {
|
2015-09-14 09:31:54 +00:00
|
|
|
return false;
|
2016-08-01 16:41:07 +00:00
|
|
|
}
|
2010-05-24 11:57:49 +00:00
|
|
|
append = 1;
|
|
|
|
}
|
2010-04-07 11:43:50 +00:00
|
|
|
fcn->addr = addr;
|
2017-05-04 12:51:05 +00:00
|
|
|
fcn->cc = r_str_const (r_anal_cc_default (a));
|
2016-06-09 21:34:07 +00:00
|
|
|
fcn->bits = a->bits;
|
2016-05-15 12:37:22 +00:00
|
|
|
r_anal_fcn_set_size (fcn, size);
|
2010-05-24 11:57:49 +00:00
|
|
|
free (fcn->name);
|
2015-10-31 19:51:47 +00:00
|
|
|
if (!name) {
|
2014-11-24 22:34:53 +00:00
|
|
|
fcn->name = r_str_newf ("fcn.%08"PFMT64x, fcn->addr);
|
|
|
|
} else {
|
|
|
|
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);
|
2016-05-23 23:47:09 +00:00
|
|
|
if (diff->name) {
|
2010-12-05 07:46:56 +00:00
|
|
|
fcn->diff->name = strdup (diff->name);
|
2016-05-23 23:47:09 +00:00
|
|
|
}
|
2010-12-05 07:46:56 +00:00
|
|
|
}
|
2014-03-31 01:05:48 +00:00
|
|
|
#if FCN_SDB
|
2014-09-22 22:40:35 +00:00
|
|
|
sdb_set (DB, sdb_fmt (0, "fcn.0x%08"PFMT64x, addr), "TODO", 0); // TODO: add more info here
|
2014-03-31 01:05:48 +00:00
|
|
|
#endif
|
2015-09-14 09:31:54 +00:00
|
|
|
return append? r_anal_fcn_insert (a, fcn): 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-09-26 13:40:17 +00:00
|
|
|
RAnalFunction *fcn, *f = r_anal_get_fcn_in (anal, addr,
|
2014-03-02 21:16:54 +00:00
|
|
|
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
|
2016-08-01 16:41:07 +00:00
|
|
|
if (!f) {
|
|
|
|
return false;
|
|
|
|
}
|
2012-10-30 09:08:06 +00:00
|
|
|
r_list_foreach_safe (anal->fcns, iter, iter2, fcn) {
|
2016-08-01 16:41:07 +00:00
|
|
|
if (fcn->type != R_ANAL_FCN_TYPE_LOC) {
|
2012-10-30 09:08:06 +00:00
|
|
|
continue;
|
2016-08-01 16:41:07 +00:00
|
|
|
}
|
2017-10-09 11:25:25 +00:00
|
|
|
if (r_anal_fcn_in (fcn, addr)) {
|
2012-10-30 09:08:06 +00:00
|
|
|
r_list_delete (anal->fcns, iter);
|
2016-08-01 16:41:07 +00:00
|
|
|
}
|
2012-09-28 00:20:52 +00:00
|
|
|
}
|
|
|
|
r_anal_fcn_del (anal, addr);
|
2015-09-14 09:31:54 +00:00
|
|
|
return true;
|
2012-09-28 00:20:52 +00:00
|
|
|
}
|
|
|
|
|
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);
|
2016-08-01 16:41:07 +00:00
|
|
|
if (!(a->fcns = r_anal_fcn_list_new ())) {
|
2015-09-14 09:31:54 +00:00
|
|
|
return false;
|
2016-08-01 16:41:07 +00:00
|
|
|
}
|
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);
|
2016-10-24 23:12:06 +00:00
|
|
|
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) {
|
2017-10-09 11:25:25 +00:00
|
|
|
if (r_anal_fcn_in (fcni, addr)) {
|
2015-03-16 01:52:26 +00:00
|
|
|
if (a->cb.on_fcn_delete) {
|
|
|
|
a->cb.on_fcn_delete (a, a->user, fcni);
|
|
|
|
}
|
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
|
|
|
}
|
2015-09-14 09:31:54 +00:00
|
|
|
return true;
|
2010-04-07 11:43:50 +00:00
|
|
|
}
|
2010-05-19 00:39:01 +00:00
|
|
|
|
2014-09-26 15:25:19 +00:00
|
|
|
R_API RAnalFunction *r_anal_get_fcn_in(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
|
2017-03-09 22:46:02 +00:00
|
|
|
// if (root) return r_listrange_find_root (anal->fcnstore, addr);
|
2014-09-26 13:40:17 +00:00
|
|
|
return r_listrange_find_in_range (anal->fcnstore, addr);
|
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) {
|
2017-03-09 22:46:02 +00:00
|
|
|
if (addr == fcn->addr) {
|
2011-11-15 22:40:28 +00:00
|
|
|
return fcn;
|
2017-03-09 22:46:02 +00:00
|
|
|
}
|
2011-11-15 22:40:28 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-07-03 01:35:26 +00:00
|
|
|
r_list_foreach (anal->fcns, iter, fcn) {
|
2016-01-17 19:18:17 +00:00
|
|
|
if (!type || (fcn && fcn->type & type)) {
|
2016-05-14 14:37:24 +00:00
|
|
|
if (fcn->addr == addr || (!ret && r_anal_fcn_is_in_offset (fcn, addr))) {
|
2012-07-17 08:00:23 +00:00
|
|
|
ret = fcn;
|
2016-12-19 22:40:09 +00:00
|
|
|
break;
|
2016-05-14 14:37:24 +00:00
|
|
|
}
|
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
|
|
|
|
2016-08-21 01:07:19 +00:00
|
|
|
R_API bool r_anal_fcn_in(RAnalFunction *fcn, ut64 addr) {
|
2016-11-06 00:40:51 +00:00
|
|
|
return fcn? r_tinyrange_in (&fcn->bbr, addr): false;
|
2016-08-21 09:39:37 +00:00
|
|
|
}
|
|
|
|
|
2016-06-10 13:31:38 +00:00
|
|
|
R_API RAnalFunction *r_anal_get_fcn_in_bounds(RAnal *anal, ut64 addr, int type) {
|
|
|
|
#if USE_NEW_FCN_STORE
|
|
|
|
#warning TODO: r_anal_get_fcn_in_bounds
|
|
|
|
// TODO: type is ignored here? wtf.. we need more work on fcnstore
|
2017-03-09 22:46:02 +00:00
|
|
|
// if (root) return r_listrange_find_root (anal->fcnstore, addr);
|
2016-06-10 13:31:38 +00:00
|
|
|
return r_listrange_find_in_range (anal->fcnstore, addr);
|
|
|
|
#else
|
|
|
|
RAnalFunction *fcn, *ret = NULL;
|
|
|
|
RListIter *iter;
|
|
|
|
if (type == R_ANAL_FCN_TYPE_ROOT) {
|
|
|
|
r_list_foreach (anal->fcns, iter, fcn) {
|
2016-08-01 16:41:07 +00:00
|
|
|
if (addr == fcn->addr) {
|
2016-06-10 13:31:38 +00:00
|
|
|
return fcn;
|
2016-08-01 16:41:07 +00:00
|
|
|
}
|
2016-06-10 13:31:38 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
r_list_foreach (anal->fcns, iter, fcn) {
|
|
|
|
if (!type || (fcn && fcn->type & type)) {
|
2016-08-21 01:07:19 +00:00
|
|
|
if (r_anal_fcn_in (fcn, addr)) {
|
2016-08-20 22:53:39 +00:00
|
|
|
return fcn;
|
|
|
|
}
|
2016-06-10 13:31:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
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) {
|
2016-05-14 14:37:24 +00:00
|
|
|
if (!strcmp (name, fcn->name)) {
|
2013-06-25 21:44:21 +00:00
|
|
|
return fcn;
|
2016-05-14 14:37:24 +00:00
|
|
|
}
|
2013-06-25 21:44:21 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-07-19 02:54:22 +00:00
|
|
|
/* rename RAnalFunctionBB.add() */
|
2015-03-16 01:52:26 +00:00
|
|
|
R_API int r_anal_fcn_add_bb(RAnal *anal, 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;
|
2016-08-01 16:41:07 +00:00
|
|
|
bool mid = false;
|
2011-02-11 10:22:43 +00:00
|
|
|
|
|
|
|
r_list_foreach (fcn->bbs, iter, bbi) {
|
|
|
|
if (addr == bbi->addr) {
|
|
|
|
bb = bbi;
|
2016-08-01 16:41:07 +00:00
|
|
|
mid = false;
|
2011-02-11 10:22:43 +00:00
|
|
|
break;
|
2017-02-15 21:26:03 +00:00
|
|
|
} else if ((addr > bbi->addr) && (addr < bbi->addr + bbi->size)) {
|
2016-08-01 16:41:07 +00:00
|
|
|
mid = true;
|
2015-07-31 10:40:04 +00:00
|
|
|
}
|
2011-02-11 10:22:43 +00:00
|
|
|
}
|
2014-12-14 00:49:04 +00:00
|
|
|
if (mid) {
|
2017-03-09 22:46:02 +00:00
|
|
|
// eprintf ("Basic Block overlaps another one that should be shrinked\n");
|
2014-12-14 00:49:04 +00:00
|
|
|
if (bbi) {
|
|
|
|
/* shrink overlapped basic block */
|
|
|
|
bbi->size = addr - (bbi->addr);
|
2017-09-04 00:56:54 +00:00
|
|
|
r_anal_fcn_update_tinyrange_bbs (fcn);
|
2014-12-14 00:49:04 +00:00
|
|
|
}
|
|
|
|
}
|
2016-09-19 12:44:47 +00:00
|
|
|
if (!bb) {
|
2015-03-16 01:52:26 +00:00
|
|
|
bb = appendBasicBlock (anal, fcn, addr);
|
2014-12-14 00:49:04 +00:00
|
|
|
if (!bb) {
|
|
|
|
eprintf ("appendBasicBlock failed\n");
|
2015-09-14 09:31:54 +00:00
|
|
|
return false;
|
2014-12-14 00:49:04 +00:00
|
|
|
}
|
2011-02-11 10:22:43 +00:00
|
|
|
}
|
|
|
|
bb->addr = addr;
|
|
|
|
bb->size = size;
|
|
|
|
bb->jump = jump;
|
|
|
|
bb->fail = fail;
|
|
|
|
bb->type = type;
|
|
|
|
if (diff) {
|
2016-08-22 16:32:18 +00:00
|
|
|
if (!bb->diff) {
|
|
|
|
bb->diff = r_anal_diff_new ();
|
|
|
|
}
|
|
|
|
if (bb->diff) {
|
|
|
|
bb->diff->type = diff->type;
|
|
|
|
bb->diff->addr = diff->addr;
|
|
|
|
if (diff->name) {
|
|
|
|
R_FREE (bb->diff->name);
|
|
|
|
bb->diff->name = strdup (diff->name);
|
|
|
|
}
|
2016-05-23 23:47:09 +00:00
|
|
|
}
|
2011-02-11 10:22:43 +00:00
|
|
|
}
|
2017-09-04 00:56:54 +00:00
|
|
|
r_anal_fcn_update_tinyrange_bbs (fcn);
|
2015-09-14 09:31:54 +00:00
|
|
|
return true;
|
2011-02-11 10:22:43 +00:00
|
|
|
}
|
|
|
|
|
2011-09-14 00:07:06 +00:00
|
|
|
// TODO: rename fcn_bb_split()
|
2015-01-29 22:27:18 +00:00
|
|
|
// bb seems to be ignored
|
2015-03-16 01:52:26 +00:00
|
|
|
R_API int r_anal_fcn_split_bb(RAnal *anal, RAnalFunction *fcn, RAnalBlock *bb, ut64 addr) {
|
2011-02-11 10:22:43 +00:00
|
|
|
RAnalBlock *bbi;
|
|
|
|
RListIter *iter;
|
2016-08-01 16:41:07 +00:00
|
|
|
if (addr == UT64_MAX) {
|
2015-01-29 22:27:18 +00:00
|
|
|
return 0;
|
2016-08-01 16:41:07 +00:00
|
|
|
}
|
2011-09-01 23:42:09 +00:00
|
|
|
r_list_foreach (fcn->bbs, iter, bbi) {
|
2016-10-24 23:12:06 +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) {
|
2016-02-10 23:18:09 +00:00
|
|
|
int new_bbi_instr, i;
|
2015-03-16 01:52:26 +00:00
|
|
|
bb = appendBasicBlock (anal, fcn, addr);
|
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;
|
|
|
|
bbi->size = addr - bbi->addr;
|
|
|
|
bbi->jump = addr;
|
|
|
|
bbi->fail = -1;
|
2015-09-14 09:31:54 +00:00
|
|
|
bbi->conditional = false;
|
2016-02-10 23:18:09 +00:00
|
|
|
if (bbi->type & R_ANAL_BB_TYPE_HEAD) {
|
|
|
|
bb->type = bbi->type ^ R_ANAL_BB_TYPE_HEAD;
|
2011-02-11 10:22:43 +00:00
|
|
|
bbi->type = R_ANAL_BB_TYPE_HEAD;
|
|
|
|
} else {
|
|
|
|
bb->type = bbi->type;
|
|
|
|
bbi->type = R_ANAL_BB_TYPE_BODY;
|
|
|
|
}
|
2016-02-10 23:18:09 +00:00
|
|
|
// recalculate offset of instructions in both bb and bbi
|
|
|
|
i = 0;
|
2016-08-01 16:41:07 +00:00
|
|
|
while (i < bbi->ninstr && r_anal_bb_offset_inst (bbi, i) < bbi->size) {
|
|
|
|
i++;
|
|
|
|
}
|
2016-02-10 23:18:09 +00:00
|
|
|
new_bbi_instr = i;
|
|
|
|
if (bb->addr - bbi->addr == r_anal_bb_offset_inst (bbi, i)) {
|
|
|
|
bb->ninstr = 0;
|
|
|
|
while (i < bbi->ninstr) {
|
|
|
|
ut16 off_op = r_anal_bb_offset_inst (bbi, i);
|
2016-10-24 23:12:06 +00:00
|
|
|
if (off_op >= bbi->size + bb->size) {
|
|
|
|
break;
|
|
|
|
}
|
2016-02-10 23:18:09 +00:00
|
|
|
r_anal_bb_set_offset (bb, bb->ninstr, off_op - bbi->size);
|
|
|
|
bb->ninstr++;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bbi->ninstr = new_bbi_instr;
|
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()
|
2014-09-21 23:39:24 +00:00
|
|
|
R_API int r_anal_fcn_bb_overlaps(RAnalFunction *fcn, RAnalBlock *bb) {
|
2011-02-11 10:22:43 +00:00
|
|
|
RAnalBlock *bbi;
|
2011-11-15 22:40:28 +00:00
|
|
|
RListIter *iter;
|
2016-08-01 16:41:07 +00:00
|
|
|
r_list_foreach (fcn->bbs, iter, bbi) {
|
2017-03-09 22:46:02 +00:00
|
|
|
if (bb->addr + bb->size > bbi->addr && bb->addr + bb->size <= bbi->addr + bbi->size) {
|
2011-02-11 10:22:43 +00:00
|
|
|
bb->size = bbi->addr - bb->addr;
|
|
|
|
bb->jump = bbi->addr;
|
|
|
|
bb->fail = -1;
|
2015-09-14 09:31:54 +00:00
|
|
|
bb->conditional = 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;
|
2017-03-09 22:46:02 +00:00
|
|
|
bbi->type = bbi->type ^ R_ANAL_BB_TYPE_HEAD;
|
2016-08-01 16:41:07 +00:00
|
|
|
} else {
|
|
|
|
bb->type = R_ANAL_BB_TYPE_BODY;
|
|
|
|
}
|
2011-02-11 10:22:43 +00:00
|
|
|
r_list_append (fcn->bbs, bb);
|
|
|
|
return R_ANAL_RET_END;
|
|
|
|
}
|
2016-08-01 16:41:07 +00:00
|
|
|
}
|
2011-02-11 10:22:43 +00:00
|
|
|
return R_ANAL_RET_NEW;
|
|
|
|
}
|
|
|
|
|
2012-07-19 02:54:22 +00:00
|
|
|
R_API int r_anal_fcn_cc(RAnalFunction *fcn) {
|
2014-06-18 23:11:53 +00:00
|
|
|
/*
|
2017-03-09 22:46:02 +00:00
|
|
|
CC = E - N + 2P
|
|
|
|
E = the number of edges of the graph.
|
|
|
|
N = the number of nodes of the graph.
|
|
|
|
P = the number of connected components (exit nodes).
|
|
|
|
*/
|
2014-06-18 23:11:53 +00:00
|
|
|
int E = 0, N = 0, P = 0;
|
2011-02-11 10:22:43 +00:00
|
|
|
RListIter *iter;
|
2014-06-18 23:11:53 +00:00
|
|
|
RAnalBlock *bb;
|
2011-02-11 10:22:43 +00:00
|
|
|
|
2014-06-18 23:11:53 +00:00
|
|
|
r_list_foreach (fcn->bbs, iter, bb) {
|
|
|
|
N++; // nodes
|
|
|
|
if (bb->jump == UT64_MAX) {
|
|
|
|
P++; // exit nodes
|
|
|
|
} else {
|
|
|
|
E++; // edges
|
2017-01-10 00:30:24 +00:00
|
|
|
if (bb->fail != UT64_MAX) {
|
2014-06-18 23:11:53 +00:00
|
|
|
E++;
|
2017-01-10 00:30:24 +00:00
|
|
|
}
|
2014-06-18 23:11:53 +00:00
|
|
|
}
|
2011-02-11 10:22:43 +00:00
|
|
|
}
|
2016-11-07 01:55:27 +00:00
|
|
|
return E - N + 2; // (2 * P);
|
2011-02-11 10:22:43 +00:00
|
|
|
}
|
|
|
|
|
2017-03-09 22:46:02 +00:00
|
|
|
R_API char *r_anal_fcn_to_string(RAnal *a, RAnalFunction *fs) {
|
2014-09-21 23:39:24 +00:00
|
|
|
return NULL;
|
2010-08-10 10:34:10 +00:00
|
|
|
}
|
|
|
|
|
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) {
|
2016-10-24 23:12:06 +00:00
|
|
|
int length = 0;
|
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");
|
2015-09-14 09:31:54 +00:00
|
|
|
return false;
|
2010-08-12 10:19:25 +00:00
|
|
|
}
|
2016-10-24 23:12:06 +00:00
|
|
|
length = strlen (sig) + 10;
|
2012-07-22 08:00:35 +00:00
|
|
|
/* Add 'function' keyword */
|
2016-10-24 23:12:06 +00:00
|
|
|
char *str = calloc (1, length);
|
2016-05-19 11:56:57 +00:00
|
|
|
if (!str) {
|
2016-05-23 23:12:22 +00:00
|
|
|
eprintf ("Cannot allocate %d bytes\n", length);
|
2016-05-19 11:56:57 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
strcpy (str, "function ");
|
|
|
|
strcat (str, sig);
|
2012-07-22 08:00:35 +00:00
|
|
|
|
2015-07-31 10:40:04 +00:00
|
|
|
/* TODO: improve arguments parsing */
|
|
|
|
/* TODO: implement parser */
|
|
|
|
/* TODO: simplify this complex api usage */
|
2012-07-22 08:00:35 +00:00
|
|
|
|
2014-05-02 23:50:28 +00:00
|
|
|
free (str);
|
2015-09-14 09:31:54 +00:00
|
|
|
return true;
|
2010-07-12 19:37:40 +00:00
|
|
|
}
|
2011-11-12 03:51:45 +00:00
|
|
|
|
2014-09-26 13:40:17 +00:00
|
|
|
R_API RAnalFunction *r_anal_get_fcn_at(RAnal *anal, ut64 addr, int type) {
|
|
|
|
#if USE_NEW_FCN_STORE
|
|
|
|
// TODO: type is ignored here? wtf.. we need more work on fcnstore
|
2017-03-09 22:46:02 +00:00
|
|
|
// if (root) return r_listrange_find_root (anal->fcnstore, addr);
|
2014-09-26 13:40:17 +00:00
|
|
|
return r_listrange_find_root (anal->fcnstore, addr);
|
|
|
|
#else
|
|
|
|
RAnalFunction *fcn, *ret = NULL;
|
2011-11-12 03:51:45 +00:00
|
|
|
RListIter *iter;
|
2014-09-26 13:40:17 +00:00
|
|
|
if (type == R_ANAL_FCN_TYPE_ROOT) {
|
|
|
|
r_list_foreach (anal->fcns, iter, fcn) {
|
2016-08-01 16:41:07 +00:00
|
|
|
if (addr == fcn->addr) {
|
2014-09-26 13:40:17 +00:00
|
|
|
return fcn;
|
2016-08-01 16:41:07 +00:00
|
|
|
}
|
2014-09-26 13:40:17 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
r_list_foreach (anal->fcns, iter, fcn) {
|
|
|
|
if (!type || (fcn->type & type)) {
|
2016-08-01 16:41:07 +00:00
|
|
|
if (addr == fcn->addr) {
|
2014-09-26 13:40:17 +00:00
|
|
|
ret = fcn;
|
2016-08-01 16:41:07 +00:00
|
|
|
}
|
2014-09-26 13:40:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
2014-09-22 22:40:35 +00:00
|
|
|
#endif
|
2011-11-12 03:51:45 +00:00
|
|
|
}
|
2012-06-05 15:50:12 +00:00
|
|
|
|
2014-09-02 00:41:40 +00:00
|
|
|
R_API RAnalFunction *r_anal_fcn_next(RAnal *anal, ut64 addr) {
|
|
|
|
RAnalFunction *fcni;
|
|
|
|
RListIter *iter;
|
|
|
|
RAnalFunction *closer = NULL;
|
|
|
|
r_list_foreach (anal->fcns, iter, fcni) {
|
2017-03-09 22:46:02 +00:00
|
|
|
// if (fcni->addr == addr)
|
|
|
|
if (fcni->addr > addr && (!closer || fcni->addr < closer->addr)) {
|
2014-09-02 00:41:40 +00:00
|
|
|
closer = fcni;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return closer;
|
|
|
|
}
|
|
|
|
|
2012-06-05 15:50:12 +00:00
|
|
|
/* getters */
|
2014-09-22 22:40:35 +00:00
|
|
|
#if FCN_OLD
|
2017-03-09 22:46:02 +00:00
|
|
|
R_API RList *r_anal_fcn_get_refs(RAnalFunction *fcn) {
|
|
|
|
return fcn->refs;
|
|
|
|
}
|
|
|
|
R_API RList *r_anal_fcn_get_xrefs(RAnalFunction *fcn) {
|
|
|
|
return fcn->xrefs;
|
|
|
|
}
|
2014-09-22 22:40:35 +00:00
|
|
|
#endif
|
2014-12-11 15:43:33 +00:00
|
|
|
|
2017-03-09 22:46:02 +00:00
|
|
|
R_API RList *r_anal_fcn_get_bbs(RAnalFunction *anal) {
|
2014-12-11 15:43:33 +00:00
|
|
|
// avoid received to free this thing
|
2017-03-09 22:46:02 +00:00
|
|
|
// anal->bbs->rc++;
|
2014-12-11 15:43:33 +00:00
|
|
|
anal->bbs->free = NULL;
|
|
|
|
return anal->bbs;
|
|
|
|
}
|
2012-06-14 00:18:15 +00:00
|
|
|
|
2016-08-21 09:39:37 +00:00
|
|
|
R_API int r_anal_fcn_is_in_offset(RAnalFunction *fcn, ut64 addr) {
|
2016-08-21 01:07:19 +00:00
|
|
|
if (r_list_empty (fcn->bbs)) {
|
2016-11-13 00:40:44 +00:00
|
|
|
// r_anal_fcn_size (fcn);
|
|
|
|
return addr >= fcn->addr && addr < fcn->addr + fcn->_size;
|
2016-08-21 01:07:19 +00:00
|
|
|
}
|
|
|
|
if (r_anal_fcn_in (fcn, addr)) {
|
2016-08-20 22:53:39 +00:00
|
|
|
return true;
|
|
|
|
}
|
2016-05-14 14:37:24 +00:00
|
|
|
return false;
|
2012-06-14 00:18:15 +00:00
|
|
|
}
|
2012-11-20 02:59:00 +00:00
|
|
|
|
2017-03-09 22:46:02 +00:00
|
|
|
R_API int r_anal_fcn_count(RAnal *anal, ut64 from, ut64 to) {
|
2012-11-20 02:59:00 +00:00
|
|
|
int n = 0;
|
|
|
|
RAnalFunction *fcni;
|
|
|
|
RListIter *iter;
|
2016-05-14 14:37:24 +00:00
|
|
|
r_list_foreach (anal->fcns, iter, fcni) {
|
|
|
|
if (fcni->addr >= from && fcni->addr < to) {
|
2016-12-19 15:44:51 +00:00
|
|
|
n++;
|
2016-05-14 14:37:24 +00:00
|
|
|
}
|
|
|
|
}
|
2012-11-20 02:59:00 +00:00
|
|
|
return n;
|
|
|
|
}
|
2016-02-23 17:30:32 +00:00
|
|
|
|
|
|
|
/* return the basic block in fcn found at the given address.
|
|
|
|
* NULL is returned if such basic block doesn't exist. */
|
|
|
|
R_API RAnalBlock *r_anal_fcn_bbget(RAnalFunction *fcn, ut64 addr) {
|
2017-05-05 10:48:52 +00:00
|
|
|
if (!fcn || addr == UT64_MAX) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2016-08-21 01:07:19 +00:00
|
|
|
#if USE_SDB_CACHE
|
2016-11-13 00:40:44 +00:00
|
|
|
return sdb_ptr_get (HB, sdb_fmt (0, SDB_KEY_BB, fcn->addr, addr), NULL);
|
2016-08-21 01:07:19 +00:00
|
|
|
#else
|
2016-02-23 17:30:32 +00:00
|
|
|
RListIter *iter;
|
|
|
|
RAnalBlock *bb;
|
|
|
|
r_list_foreach (fcn->bbs, iter, bb) {
|
2016-08-21 01:07:19 +00:00
|
|
|
if (bb->addr == addr) {
|
|
|
|
return bb;
|
|
|
|
}
|
2016-02-23 17:30:32 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
2016-08-21 01:07:19 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API bool r_anal_fcn_bbadd(RAnalFunction *fcn, RAnalBlock *bb) {
|
|
|
|
#if USE_SDB_CACHE
|
|
|
|
return sdb_ptr_set (HB, sdb_fmt (0, SDB_KEY_BB, fcn->addr, bb->addr), bb, NULL);
|
|
|
|
#endif
|
|
|
|
r_list_append (fcn->bbs, bb);
|
2016-08-21 09:39:37 +00:00
|
|
|
return true;
|
2016-02-23 17:30:32 +00:00
|
|
|
}
|
2016-03-28 22:39:50 +00:00
|
|
|
|
2016-05-15 12:37:22 +00:00
|
|
|
/* directly set the size of the function */
|
|
|
|
R_API void r_anal_fcn_set_size(RAnalFunction *fcn, ut32 size) {
|
2016-08-01 16:41:07 +00:00
|
|
|
if (fcn) {
|
|
|
|
fcn->_size = size;
|
|
|
|
}
|
2016-05-15 12:37:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* returns the size of the function.
|
|
|
|
* IMPORTANT: this will change, one day, because it doesn't have much sense */
|
|
|
|
R_API ut32 r_anal_fcn_size(const RAnalFunction *fcn) {
|
2017-03-09 22:46:02 +00:00
|
|
|
return fcn? fcn->_size: 0;
|
2016-05-15 12:37:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* return the "real" size of the function, that is the sum of the size of the
|
|
|
|
* basicblocks this function is composed of.
|
|
|
|
* IMPORTANT: this will become, one day, the only size of a function */
|
|
|
|
R_API ut32 r_anal_fcn_realsize(const RAnalFunction *fcn) {
|
2016-09-09 17:28:47 +00:00
|
|
|
RListIter *iter, *fiter;
|
2016-03-28 22:39:50 +00:00
|
|
|
RAnalBlock *bb;
|
2016-09-09 17:28:47 +00:00
|
|
|
RAnalFunction *f;
|
2016-05-15 12:37:22 +00:00
|
|
|
ut32 sz = 0;
|
2016-03-28 22:39:50 +00:00
|
|
|
r_list_foreach (fcn->bbs, iter, bb) {
|
|
|
|
sz += bb->size;
|
|
|
|
}
|
2016-09-09 17:28:47 +00:00
|
|
|
r_list_foreach (fcn->fcn_locs, fiter, f) {
|
|
|
|
r_list_foreach (f->bbs, iter, bb) {
|
|
|
|
sz += bb->size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return sz;
|
|
|
|
}
|
|
|
|
|
2017-03-09 22:46:02 +00:00
|
|
|
// continious function size without loc.*
|
2016-09-09 17:28:47 +00:00
|
|
|
R_API ut32 r_anal_fcn_contsize(const RAnalFunction *fcn) {
|
2016-09-14 14:42:23 +00:00
|
|
|
RListIter *iter;
|
2016-09-09 17:28:47 +00:00
|
|
|
RAnalBlock *bb;
|
|
|
|
ut32 sz = 0;
|
|
|
|
r_list_foreach (fcn->bbs, iter, bb) {
|
|
|
|
/* TODO: this if is an ugly hack and should be removed when r2 will be
|
2017-03-09 22:46:02 +00:00
|
|
|
* able to handle BBs that comes before the function emtry point.
|
|
|
|
* Another way to remove this is to throw away BBs before the function
|
|
|
|
* entry point at the analysis time in the r_anal_fcn. */
|
2016-09-14 14:42:23 +00:00
|
|
|
if (bb->addr >= fcn->addr) {
|
2016-09-09 17:28:47 +00:00
|
|
|
sz += bb->size;
|
|
|
|
}
|
|
|
|
}
|
2016-03-28 22:39:50 +00:00
|
|
|
return sz;
|
|
|
|
}
|
2017-01-13 22:08:37 +00:00
|
|
|
|
|
|
|
// compute the cyclomatic cost
|
|
|
|
R_API ut32 r_anal_fcn_cost(RAnal *anal, RAnalFunction *fcn) {
|
|
|
|
RListIter *iter;
|
|
|
|
RAnalBlock *bb;
|
|
|
|
ut32 totalCycles = 0;
|
|
|
|
if (!fcn) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
r_list_foreach (fcn->bbs, iter, bb) {
|
|
|
|
RAnalOp op;
|
|
|
|
ut64 at, end = bb->addr + bb->size;
|
|
|
|
ut8 *buf = malloc (bb->size);
|
2017-03-09 22:46:02 +00:00
|
|
|
anal->iob.read_at (anal->iob.io, bb->addr, (ut8 *) buf, bb->size);
|
2017-01-13 22:08:37 +00:00
|
|
|
int idx = 0;
|
2017-03-09 22:46:02 +00:00
|
|
|
for (at = bb->addr; at < end;) {
|
2017-01-13 22:08:37 +00:00
|
|
|
memset (&op, 0, sizeof (op));
|
2017-03-09 22:46:02 +00:00
|
|
|
(void) r_anal_op (anal, &op, at, buf + idx, bb->size - idx);
|
2017-01-13 22:08:37 +00:00
|
|
|
if (op.size < 1) {
|
|
|
|
op.size = 1;
|
|
|
|
}
|
|
|
|
idx += op.size;
|
|
|
|
at += op.size;
|
|
|
|
totalCycles += op.cycles;
|
|
|
|
}
|
|
|
|
free (buf);
|
|
|
|
}
|
|
|
|
return totalCycles;
|
|
|
|
}
|
2017-03-18 07:46:35 +00:00
|
|
|
|
|
|
|
R_API int r_anal_fcn_count_edges(RAnalFunction *fcn, int *ebbs) {
|
|
|
|
RListIter *iter;
|
|
|
|
RAnalBlock *bb;
|
|
|
|
int edges = 0;
|
|
|
|
if (ebbs) {
|
|
|
|
*ebbs = 0;
|
|
|
|
}
|
|
|
|
r_list_foreach (fcn->bbs, iter, bb) {
|
|
|
|
if (ebbs && bb->jump == UT64_MAX && bb->fail == UT64_MAX) {
|
|
|
|
*ebbs = *ebbs + 1;
|
|
|
|
} else {
|
|
|
|
if (bb->jump != UT64_MAX) {
|
|
|
|
edges ++;
|
|
|
|
}
|
|
|
|
if (bb->fail != UT64_MAX) {
|
|
|
|
edges ++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return edges;
|
|
|
|
}
|