mirror of
https://github.com/radareorg/radare2.git
synced 2024-10-08 02:53:29 +00:00
anal/xrefs: single, global xrefs API
* several bugfixes * Fix xrefs/refs confusion with asm.cmt.refs * Also check if xref source is valid offset * Fix ax* to show type of ref * anal/xrefs: pass the right hashtable to mylistrefs * r_anal_refs_get should use anal->refs, not anal->xrefs * anal/fcn: add xref also when there's a CALL to a noreturn function * projects: use radare2 output of ax command to save/restore xrefs * core/cmd_anal: when analyzing calls, we should use REF_TYPE_CALL * core/canal: use xrefs API, because the list is a just a copy * core/canal: rename "loc." entries to "fcn." when a CALL is found * sort xrefs to make results consistent * core/canal: avoid recomputing function every time during `aan` * anal: move fcn_refs/xrefs functions to the xrefs.c file * core/canal.c: avoid iterating fcn xrefs list * anal/xrefs: compute fcn xrefs by analyzing fcn addresses * remove other unused functions * anal/xrefs: remove fcn_xrefs_add and fcn_xrefs_deln * anal/xrefs: remove old fcn->refs/xrefs * anal/xrefs: directly store RAnalRef objects in the hash table * libr: prevent memory leaks when using refs/xrefs * anal/xrefs: merge anal/ref and anal/xref and clean API Big xrefs/refs refactoring that provides a more uniform and simple API. It avoids changes to refs/xrefs except through the API and it keeps all xrefs/refs info in one single place, to improve consistency. Thanks to: Riccardo Schirone <sirmy15@gmail.com> pancake <pancake@nopcode.org> rene <rlaemmert@gmail.com>
This commit is contained in:
parent
cbe9a12be2
commit
b703dfbf17
@ -27,7 +27,7 @@ plugins: ${LIBSO} ${LIBAR}
|
||||
include ${STATIC_ANAL_PLUGINS}
|
||||
|
||||
STATIC_OBJS=$(addprefix $(LTOP)/anal/p/,$(STATIC_OBJ))
|
||||
OBJLIBS=meta.o reflines.o ref.o op.o fcn.o bb.o var.o
|
||||
OBJLIBS=meta.o reflines.o op.o fcn.o bb.o var.o
|
||||
OBJLIBS+=cond.o value.o cc.o diff.o types.o
|
||||
OBJLIBS+=hint.o anal.o data.o xrefs.o esil.o sign.o
|
||||
OBJLIBS+=anal_ex.o switch.o state.o cycles.o
|
||||
|
@ -78,14 +78,9 @@ R_API RAnal *r_anal_new() {
|
||||
anal->sdb_fcns = sdb_ns (anal->sdb, "fcns", 1);
|
||||
anal->sdb_meta = sdb_ns (anal->sdb, "meta", 1);
|
||||
anal->sdb_hints = sdb_ns (anal->sdb, "hints", 1);
|
||||
anal->sdb_xrefs = sdb_ns (anal->sdb, "xrefs", 1);
|
||||
anal->sdb_types = sdb_ns (anal->sdb, "types", 1);
|
||||
anal->sdb_cc = sdb_ns (anal->sdb, "cc", 1);
|
||||
anal->sdb_zigns = sdb_ns (anal->sdb, "zigns", 1);
|
||||
#if USE_DICT
|
||||
anal->dict_refs = dict_new (100, dict_free);
|
||||
anal->dict_xrefs = dict_new (100, dict_free);
|
||||
#endif
|
||||
anal->zign_path = strdup ("");
|
||||
anal->cb_printf = (PrintfCallback) printf;
|
||||
(void)r_anal_pin_init (anal);
|
||||
@ -141,6 +136,8 @@ R_API RAnal *r_anal_free(RAnal *a) {
|
||||
r_reg_free (a->reg);
|
||||
r_anal_op_free (a->queued);
|
||||
r_list_free (a->bits_ranges);
|
||||
ht_free (a->dict_refs);
|
||||
ht_free (a->dict_xrefs);
|
||||
a->sdb = NULL;
|
||||
sdb_ns_free (a->sdb);
|
||||
if (a->esil) {
|
||||
@ -364,13 +361,6 @@ R_API RList* r_anal_get_fcns (RAnal *anal) {
|
||||
return anal->fcns;
|
||||
}
|
||||
|
||||
R_API bool r_anal_project_save(RAnal *anal, const char *prjfile) {
|
||||
if (prjfile && *prjfile) {
|
||||
return r_anal_xrefs_save (anal, prjfile);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
R_API RAnalOp *r_anal_op_hexstr(RAnal *anal, ut64 addr, const char *str) {
|
||||
int len;
|
||||
ut8 *buf;
|
||||
@ -412,7 +402,6 @@ R_API int r_anal_purge (RAnal *anal) {
|
||||
sdb_reset (anal->sdb_fcns);
|
||||
sdb_reset (anal->sdb_meta);
|
||||
sdb_reset (anal->sdb_hints);
|
||||
sdb_reset (anal->sdb_xrefs);
|
||||
sdb_reset (anal->sdb_types);
|
||||
sdb_reset (anal->sdb_zigns);
|
||||
r_list_free (anal->fcns);
|
||||
|
@ -144,7 +144,7 @@ R_API int r_anal_bb(RAnal *anal, RAnalBlock *bb, ut64 addr, ut8 *buf, ut64 len,
|
||||
ut8 b[8];
|
||||
ut64 ptr = idx+addr+src->delta;
|
||||
anal->iob.read_at (anal->iob.io, ptr, b, memref);
|
||||
r_anal_ref_add (anal, ptr, addr+idx-op->size, 'd');
|
||||
r_anal_xrefs_set (anal, addr+idx-op->size, ptr, R_ANAL_REF_TYPE_DATA);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
111
libr/anal/fcn.c
111
libr/anal/fcn.c
@ -293,10 +293,6 @@ R_API RAnalFunction *r_anal_fcn_new() {
|
||||
fcn->cc = NULL;
|
||||
/* Function attributes: weak/noreturn/format/etc */
|
||||
fcn->addr = UT64_MAX;
|
||||
#if FCN_OLD
|
||||
fcn->refs = r_anal_ref_list_new ();
|
||||
fcn->xrefs = r_anal_ref_list_new ();
|
||||
#endif
|
||||
fcn->fcn_locs = NULL;
|
||||
fcn->bbs = r_anal_bb_list_new ();
|
||||
fcn->fingerprint = NULL;
|
||||
@ -323,10 +319,6 @@ R_API void r_anal_fcn_free(void *_fcn) {
|
||||
free (fcn->name);
|
||||
free (fcn->attr);
|
||||
r_tinyrange_fini (&fcn->bbr);
|
||||
#if FCN_OLD
|
||||
r_list_free (fcn->refs);
|
||||
r_list_free (fcn->xrefs);
|
||||
#endif
|
||||
// all functions are freed in anal->fcns
|
||||
fcn->fcn_locs = NULL;
|
||||
if (fcn->bbs) {
|
||||
@ -352,64 +344,6 @@ static bool refExists(RList *refs, RAnalRef *ref) {
|
||||
return false;
|
||||
}
|
||||
|
||||
R_API int r_anal_fcn_xref_add(RAnal *a, RAnalFunction *fcn, ut64 at, ut64 addr, int type) {
|
||||
RAnalRef *ref;
|
||||
if (!fcn || !a) {
|
||||
return false;
|
||||
}
|
||||
if (!a->iob.is_valid_offset (a->iob.io, addr, 0)) {
|
||||
return false;
|
||||
}
|
||||
ref = r_anal_ref_new ();
|
||||
if (!ref) {
|
||||
return false;
|
||||
}
|
||||
// set global reference
|
||||
// r_cons_printf ("C 0x%llx 0x%llx\n", at, addr);
|
||||
r_anal_xrefs_set (a, type, at, addr);
|
||||
// set per-function reference
|
||||
#if FCN_OLD
|
||||
// TOO OLD we shouldnt be storing this.. or we do?
|
||||
ref->at = at; // from
|
||||
ref->addr = addr; // to
|
||||
ref->type = type;
|
||||
// TODO: ensure we are not dupping xrefs
|
||||
if (refExists (fcn->refs, ref)) {
|
||||
r_anal_ref_free (ref);
|
||||
} else {
|
||||
r_list_append (fcn->refs, ref);
|
||||
}
|
||||
#endif
|
||||
#if FCN_SDB
|
||||
sdb_add (DB, sdb_fmt ("fcn.0x%08"PFMT64x ".name", fcn->addr), fcn->name, 0);
|
||||
// encode the name in base64 ?
|
||||
sdb_num_add (DB, sdb_fmt ("fcn.name.%s", fcn->name), fcn->addr, 0);
|
||||
sdb_array_add_num (DB, sdb_fmt ("fcn.0x%08"PFMT64x ".xrefs", fcn->addr), at, 0);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
R_API int r_anal_fcn_xref_del(RAnal *a, RAnalFunction *fcn, ut64 at, ut64 addr, int type) {
|
||||
#if FCN_OLD
|
||||
RAnalRef *ref;
|
||||
RListIter *iter;
|
||||
/* No need for _safe loop coz we return immediately after the delete. */
|
||||
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 true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if FCN_SDB
|
||||
// TODO
|
||||
// sdb_array_delete_num (DB, key, at, 0);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
static RAnalBlock *bbget(RAnalFunction *fcn, ut64 addr) {
|
||||
RListIter *iter;
|
||||
RAnalBlock *bb;
|
||||
@ -1150,7 +1084,7 @@ repeat:
|
||||
|
||||
if (op.ptr && op.ptr != UT64_MAX && op.ptr != UT32_MAX) {
|
||||
// swapped parameters wtf
|
||||
r_anal_fcn_xref_add (anal, fcn, op.addr, op.ptr, R_ANAL_REF_TYPE_DATA);
|
||||
r_anal_xrefs_set (anal, op.addr, op.ptr, R_ANAL_REF_TYPE_DATA);
|
||||
}
|
||||
|
||||
switch (op.type & R_ANAL_OP_TYPE_MASK) {
|
||||
@ -1289,7 +1223,7 @@ repeat:
|
||||
return R_ANAL_RET_END;
|
||||
}
|
||||
if (anal->opt.jmpref) {
|
||||
(void) r_anal_fcn_xref_add (anal, fcn, op.addr, op.jump, R_ANAL_REF_TYPE_CODE);
|
||||
(void) r_anal_xrefs_set (anal, op.addr, op.jump, R_ANAL_REF_TYPE_CODE);
|
||||
}
|
||||
if (!anal->opt.jmpabove && (op.jump < fcn->addr)) {
|
||||
FITFCNSZ ();
|
||||
@ -1384,8 +1318,7 @@ repeat:
|
||||
break;
|
||||
case R_ANAL_OP_TYPE_CJMP:
|
||||
if (anal->opt.cjmpref) {
|
||||
(void) r_anal_fcn_xref_add (anal, fcn,
|
||||
op.addr, op.jump, R_ANAL_REF_TYPE_CODE);
|
||||
(void) r_anal_xrefs_set (anal, op.addr, op.jump, R_ANAL_REF_TYPE_CODE);
|
||||
}
|
||||
if (!overlapped) {
|
||||
bb->jump = op.jump;
|
||||
@ -1455,23 +1388,25 @@ repeat:
|
||||
case R_ANAL_OP_TYPE_ICALL:
|
||||
case R_ANAL_OP_TYPE_IRCALL:
|
||||
/* call [dst] */
|
||||
// XXX: this is TYPE_MCALL or indirect-call
|
||||
(void) r_anal_xrefs_set (anal, op.addr, op.ptr, R_ANAL_REF_TYPE_CALL);
|
||||
|
||||
if (op.ptr != UT64_MAX && r_anal_noreturn_at (anal, op.ptr)) {
|
||||
FITFCNSZ ();
|
||||
r_anal_op_fini (&op);
|
||||
return R_ANAL_RET_END;
|
||||
}
|
||||
// XXX: this is TYPE_MCALL or indirect-call
|
||||
(void) r_anal_fcn_xref_add (anal, fcn, op.addr, op.ptr, R_ANAL_REF_TYPE_CALL);
|
||||
break;
|
||||
case R_ANAL_OP_TYPE_CCALL:
|
||||
case R_ANAL_OP_TYPE_CALL:
|
||||
/* call dst */
|
||||
(void) r_anal_xrefs_set (anal, op.addr, op.jump, R_ANAL_REF_TYPE_CALL);
|
||||
|
||||
if (r_anal_noreturn_at (anal, op.jump)) {
|
||||
FITFCNSZ ();
|
||||
r_anal_op_fini (&op);
|
||||
return R_ANAL_RET_END;
|
||||
}
|
||||
(void) r_anal_fcn_xref_add (anal, fcn, op.addr, op.jump, R_ANAL_REF_TYPE_CALL);
|
||||
#if CALL_IS_EOB
|
||||
recurseAt (op.jump);
|
||||
recurseAt (op.fail);
|
||||
@ -1491,13 +1426,6 @@ repeat:
|
||||
}
|
||||
// switch statement
|
||||
if (anal->opt.jmptbl) {
|
||||
if (fcn->refs->tail) {
|
||||
RAnalRef *last_ref = fcn->refs->tail->data;
|
||||
last_ref->type = R_ANAL_REF_TYPE_NULL;
|
||||
// TODO: walk switch? try_walkthrough_jmptbl?
|
||||
// Why is this a jmp table and what does it look like
|
||||
// walk_switch (anal, fcn, op.addr, op.addr + op.size);
|
||||
}
|
||||
// op.ireg since rip relative addressing produces way too many false positives otherwise
|
||||
// op.ireg is 0 for rip relative, "rax", etc otherwise
|
||||
if (op.ptr != UT64_MAX && op.ireg) { // direct jump
|
||||
@ -1554,7 +1482,7 @@ analopfinish:
|
||||
last_is_push = true;
|
||||
last_push_addr = op.val;
|
||||
if (anal->iob.is_valid_offset (anal->iob.io, op.val, 1)) {
|
||||
(void) r_anal_fcn_xref_add (anal, fcn, op.addr, op.val, R_ANAL_REF_TYPE_DATA);
|
||||
(void) r_anal_xrefs_set (anal, op.addr, op.val, R_ANAL_REF_TYPE_DATA);
|
||||
}
|
||||
break;
|
||||
case R_ANAL_OP_TYPE_RET:
|
||||
@ -1666,15 +1594,18 @@ R_API void r_anal_fcn_fit_overlaps(RAnal *anal, RAnalFunction *fcn) {
|
||||
}
|
||||
}
|
||||
|
||||
R_API void r_anal_trim_jmprefs(RAnalFunction *fcn) {
|
||||
R_API void r_anal_trim_jmprefs(RAnal *anal, RAnalFunction *fcn) {
|
||||
RAnalRef *ref;
|
||||
RList *refs = r_anal_fcn_get_refs (anal, fcn);
|
||||
RListIter *iter;
|
||||
RListIter *tmp;
|
||||
r_list_foreach_safe (fcn->refs, iter, tmp, ref) {
|
||||
|
||||
r_list_foreach (refs, iter, ref) {
|
||||
if (ref->type == R_ANAL_REF_TYPE_CODE && r_anal_fcn_is_in_offset (fcn, ref->addr)) {
|
||||
r_list_delete (fcn->refs, iter);
|
||||
r_anal_xrefs_deln (anal, ref->at, ref->addr, ref->type);
|
||||
}
|
||||
}
|
||||
r_list_free (refs);
|
||||
}
|
||||
|
||||
R_API int r_anal_fcn(RAnal *anal, RAnalFunction *fcn, ut64 addr, ut8 *buf, ut64 len, int reftype) {
|
||||
@ -1718,7 +1649,7 @@ R_API int r_anal_fcn(RAnal *anal, RAnalFunction *fcn, ut64 addr, ut8 *buf, ut64
|
||||
// fcn is not yet in anal => pass NULL
|
||||
r_anal_fcn_resize (NULL, fcn, endaddr - fcn->addr);
|
||||
#endif
|
||||
r_anal_trim_jmprefs (fcn);
|
||||
r_anal_trim_jmprefs (anal, fcn);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@ -2319,13 +2250,3 @@ R_API int r_anal_fcn_count_edges(RAnalFunction *fcn, int *ebbs) {
|
||||
}
|
||||
return edges;
|
||||
}
|
||||
|
||||
R_API RList *r_anal_fcn_get_refs(RAnal *anal, RAnalFunction *fcn) {
|
||||
RList *ret = (fcn) ? r_list_clone (fcn->refs) : NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
R_API RList *r_anal_fcn_get_xrefs(RAnal *anal, RAnalFunction *fcn) {
|
||||
RList *ret = (fcn) ? r_list_clone (fcn->xrefs) : NULL;
|
||||
return ret;
|
||||
}
|
||||
|
@ -593,7 +593,7 @@ static int module_match_buffer(const RAnal *anal, const RFlirtModule *module,
|
||||
}
|
||||
r_anal_fcn_resize (anal, next_module_function, flirt_fcn_size);
|
||||
next_module_function_size = r_anal_fcn_size (next_module_function);
|
||||
r_anal_trim_jmprefs (next_module_function);
|
||||
r_anal_trim_jmprefs ((RAnal *)anal, next_module_function);
|
||||
}
|
||||
|
||||
|
||||
|
@ -66,7 +66,6 @@ files = [
|
||||
'p/anal_xtensa.c',
|
||||
'p/anal_z80.c',
|
||||
'pin.c',
|
||||
'ref.c',
|
||||
'reflines.c',
|
||||
'rtti.c',
|
||||
'rtti_msvc.c',
|
||||
|
@ -223,7 +223,7 @@ static int handle_bb_cf_recursive_descent (RAnal *anal, RAnalState *state) {
|
||||
switch (control_type) {
|
||||
case R_ANAL_OP_TYPE_CALL:
|
||||
IFDBG eprintf (" - Handling a call @ 0x%04"PFMT64x".\n", addr);
|
||||
r_anal_fcn_xref_add (anal, state->current_fcn, bb->addr, bb->jump, R_ANAL_REF_TYPE_CALL);
|
||||
r_anal_xrefs_set (anal, bb->addr, bb->jump, R_ANAL_REF_TYPE_CALL);
|
||||
result = R_ANAL_RET_ERROR;
|
||||
break;
|
||||
case R_ANAL_OP_TYPE_JMP:
|
||||
@ -406,7 +406,7 @@ static int handle_bb_cf_linear_sweep (RAnal *anal, RAnalState *state) {
|
||||
switch (control_type) {
|
||||
case R_ANAL_OP_TYPE_CALL:
|
||||
IFDBG eprintf (" - Handling a call @ 0x%04"PFMT64x"\n", addr);
|
||||
r_anal_fcn_xref_add (anal, state->current_fcn, bb->addr, bb->jump, R_ANAL_REF_TYPE_CALL);
|
||||
r_anal_xrefs_set (anal, bb->addr, bb->jump, R_ANAL_REF_TYPE_CALL);
|
||||
result = R_ANAL_RET_ERROR;
|
||||
break;
|
||||
case R_ANAL_OP_TYPE_JMP:
|
||||
|
@ -1,72 +0,0 @@
|
||||
/* radare - LGPL - Copyright 2010-2018 - nibble, pancake */
|
||||
|
||||
#include <r_anal.h>
|
||||
#include <r_util.h>
|
||||
#include <r_list.h>
|
||||
|
||||
// This file contains the reversed api for querying xrefs.c which
|
||||
// is implemented on top of sdb. Anyway, the sdbization is not
|
||||
// complete because there's still r_anal_ref_new() which doesnt
|
||||
// serializes with sdb_native
|
||||
|
||||
R_API RAnalRef *r_anal_ref_new() {
|
||||
RAnalRef *ref = R_NEW0 (RAnalRef);
|
||||
if (ref) {
|
||||
ref->addr = -1;
|
||||
ref->at = -1;
|
||||
ref->type = R_ANAL_REF_TYPE_CODE;
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
R_API RList *r_anal_ref_list_new() {
|
||||
RList *list = r_list_new ();
|
||||
if (!list) return NULL;
|
||||
list->free = &r_anal_ref_free;
|
||||
return list;
|
||||
}
|
||||
|
||||
R_API void r_anal_ref_free(void *ref) {
|
||||
free (ref);
|
||||
}
|
||||
|
||||
R_API int r_anal_ref_add(RAnal *anal, ut64 addr, ut64 at, int type) {
|
||||
r_anal_xrefs_set (anal, type, at, addr);
|
||||
return true;
|
||||
}
|
||||
|
||||
R_API const char *r_anal_ref_to_string(int type) {
|
||||
switch (type) {
|
||||
case R_ANAL_REF_TYPE_NULL: return "null";
|
||||
case R_ANAL_REF_TYPE_CODE: return "code";
|
||||
case R_ANAL_REF_TYPE_CALL: return "call";
|
||||
case R_ANAL_REF_TYPE_DATA: return "data";
|
||||
case R_ANAL_REF_TYPE_STRING: return "strg";
|
||||
}
|
||||
return "unk";
|
||||
}
|
||||
|
||||
R_API int r_anal_ref_del(RAnal *anal, ut64 from, ut64 to) {
|
||||
#if USE_MHT
|
||||
// TODO Must delete from mht_refs too
|
||||
mht *m = anal->mht_xrefs;
|
||||
mhtkv *kv = mht_getr (m, from);
|
||||
if (kv) {
|
||||
mht *ht = kv->u;
|
||||
if (ht) {
|
||||
mht_del (ht, to);
|
||||
}
|
||||
}
|
||||
#else
|
||||
r_anal_xrefs_deln (anal, R_ANAL_REF_TYPE_NULL, from, to);
|
||||
r_anal_xrefs_deln (anal, R_ANAL_REF_TYPE_CODE, from, to);
|
||||
r_anal_xrefs_deln (anal, R_ANAL_REF_TYPE_CALL, from, to);
|
||||
r_anal_xrefs_deln (anal, R_ANAL_REF_TYPE_DATA, from, to);
|
||||
r_anal_xrefs_deln (anal, R_ANAL_REF_TYPE_STRING, from, to);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
R_API RList *r_anal_xref_get(RAnal *anal, ut64 addr) {
|
||||
return r_anal_xrefs_get (anal, addr);
|
||||
}
|
@ -146,6 +146,7 @@ static int vtable_is_addr_vtable_start(RVTableContext *context, ut64 curAddress)
|
||||
r_anal_op_fini (&analop);
|
||||
}
|
||||
}
|
||||
r_list_free (xrefs);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -198,9 +199,12 @@ R_API RList *r_anal_vtable_search(RVTableContext *context) {
|
||||
startAddress += context->word_size;
|
||||
|
||||
// a ref means the vtable has ended
|
||||
if (!r_list_empty (r_anal_xrefs_get (context->anal, startAddress))) {
|
||||
RList *ll = r_anal_xrefs_get (context->anal, startAddress);
|
||||
if (!r_list_empty (ll)) {
|
||||
r_list_free (ll);
|
||||
break;
|
||||
}
|
||||
r_list_free (ll);
|
||||
}
|
||||
vtable->method_count = noOfMethods;
|
||||
r_list_append (vtables, vtable);
|
||||
|
@ -1,10 +1,7 @@
|
||||
/* radare - LGPL - Copyright 2009-2017 - pancake, nibble */
|
||||
/* radare - LGPL - Copyright 2009-2018 - pancake, nibble, defragger, ret2libc */
|
||||
|
||||
#include <r_anal.h>
|
||||
#include <r_cons.h>
|
||||
#include <sdb.h>
|
||||
|
||||
#define DB anal->sdb_xrefs
|
||||
|
||||
#if 0
|
||||
DICT
|
||||
@ -24,284 +21,160 @@ xrefs
|
||||
20: call 10
|
||||
#endif
|
||||
|
||||
// XXX: is it possible to have multiple type for the same (from, to) pair?
|
||||
// if it is, things need to be adjusted
|
||||
|
||||
#define u64_to_key(x) (sdb_fmt ("%"PFMT64x, (x)))
|
||||
|
||||
#define ht_find_u64(_ht,_key,_found) (ht_find ((_ht), u64_to_key (_key), (_found)))
|
||||
#define ht_insert_u64(_ht,_key,_value) (ht_insert ((_ht), u64_to_key (_key), _value))
|
||||
#define ht_update_u64(_ht,_key,_value) (ht_update ((_ht), u64_to_key (_key), _value))
|
||||
#define ht_delete_u64(_ht,_key) (ht_delete ((_ht), u64_to_key (_key)))
|
||||
|
||||
R_API RAnalRef *r_anal_ref_new() {
|
||||
RAnalRef *ref = R_NEW0 (RAnalRef);
|
||||
if (ref) {
|
||||
ref->addr = -1;
|
||||
ref->at = -1;
|
||||
ref->type = R_ANAL_REF_TYPE_CODE;
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
R_API RList *r_anal_ref_list_new() {
|
||||
return r_list_newf (r_anal_ref_free);
|
||||
}
|
||||
|
||||
R_API void r_anal_ref_free(void *ref) {
|
||||
free (ref);
|
||||
}
|
||||
void xrefs_ht_free(HtKv *kv) {
|
||||
free (kv->key);
|
||||
ht_free (kv->value);
|
||||
free (kv);
|
||||
}
|
||||
|
||||
void xrefs_ref_free(HtKv *kv) {
|
||||
free (kv->key);
|
||||
r_anal_ref_free (kv->value);
|
||||
free (kv);
|
||||
}
|
||||
|
||||
static const char *analref_toString(RAnalRefType type) {
|
||||
switch (type) {
|
||||
case R_ANAL_REF_TYPE_NULL:
|
||||
/* do nothing */
|
||||
break;
|
||||
case R_ANAL_REF_TYPE_CODE:
|
||||
return "code.jmp";
|
||||
return "code jmp";
|
||||
case R_ANAL_REF_TYPE_CALL:
|
||||
return "code.call";
|
||||
return "code call";
|
||||
case R_ANAL_REF_TYPE_DATA:
|
||||
return "data.mem";
|
||||
return "data mem";
|
||||
case R_ANAL_REF_TYPE_STRING:
|
||||
return "data.string";
|
||||
return "data string";
|
||||
}
|
||||
return "unk";
|
||||
}
|
||||
|
||||
static void XREFKEY(char * const key, const size_t key_len,
|
||||
char const * const kind, const RAnalRefType type, const ut64 addr) {
|
||||
char const * _sdb_type = analref_toString (type);
|
||||
snprintf (key, key_len, "%s.%s.0x%"PFMT64x, kind, _sdb_type, addr);
|
||||
static bool appendRef(RList *list, const char *k, RAnalRef *ref) {
|
||||
RAnalRef *cloned = r_anal_ref_new ();
|
||||
if (!cloned) {
|
||||
return false;
|
||||
}
|
||||
cloned->addr = ref->addr;
|
||||
cloned->at = ref->at;
|
||||
cloned->type = ref->type;
|
||||
r_list_append (list, cloned);
|
||||
return true;
|
||||
}
|
||||
|
||||
R_API bool r_anal_xrefs_save(RAnal *anal, const char *prjDir) {
|
||||
#if USE_DICT
|
||||
anal->sdb_xrefs = sdb_new0 ();
|
||||
#endif
|
||||
char *xrefs_path = r_str_newf ("%s" R_SYS_DIR "xrefs.sdb", prjDir);
|
||||
sdb_file (anal->sdb_xrefs, xrefs_path);
|
||||
free (xrefs_path);
|
||||
return sdb_sync (anal->sdb_xrefs);
|
||||
static bool mylistrefs_cb(RList *list, const char *k, SdbHash *ht) {
|
||||
ht_foreach (ht, (HtForeachCallback)appendRef, list);
|
||||
return true;
|
||||
}
|
||||
|
||||
#if USE_DICT
|
||||
static void appendRef(RList *list, dicti k, dicti v, void *u) {
|
||||
static void listxrefs(SdbHash *m, ut64 addr, RList *list) {
|
||||
if (addr == UT64_MAX) {
|
||||
ht_foreach (m, (HtForeachCallback)mylistrefs_cb, list);
|
||||
} else {
|
||||
bool found;
|
||||
SdbHash *d = ht_find_u64 (m, addr, &found);
|
||||
if (!found) {
|
||||
return;
|
||||
}
|
||||
|
||||
ht_foreach (d, (HtForeachCallback)appendRef, list);
|
||||
}
|
||||
}
|
||||
|
||||
static void setxref(SdbHash *m, ut64 from, ut64 to, int type) {
|
||||
bool found;
|
||||
SdbHash *ht = ht_find_u64 (m, from, &found);
|
||||
|
||||
if (!found) {
|
||||
ht = ht_new (NULL, xrefs_ref_free, NULL);
|
||||
if (!ht) {
|
||||
return;
|
||||
}
|
||||
|
||||
ht_insert_u64 (m, from, ht);
|
||||
}
|
||||
|
||||
RAnalRef *ref = r_anal_ref_new ();
|
||||
if (ref) {
|
||||
#if 0
|
||||
eprintf ("%s 0x%08llx -> 0x%08llx (0x%llx)\n",
|
||||
kv->u, kv->k, kv->v, addr);
|
||||
#endif
|
||||
ref->at = k;
|
||||
ref->addr = v;
|
||||
ref->type = u;
|
||||
r_list_append (list, ref);
|
||||
}
|
||||
ref->at = from;
|
||||
ref->addr = to;
|
||||
ref->type = type;
|
||||
|
||||
ht_update_u64 (ht, to, ref);
|
||||
}
|
||||
|
||||
static void mylistrefs(dict *m, ut64 addr, RList *list) {
|
||||
int i, j;
|
||||
for (i = 0; i < m->size; i++) {
|
||||
dictkv *kv = m->table[i];
|
||||
if (!kv) {
|
||||
continue;
|
||||
}
|
||||
while (kv->k != MHTNO) {
|
||||
if (addr == UT64_MAX || addr == kv->k) {
|
||||
appendRef (list, kv->k, kv->v, kv->u);
|
||||
}
|
||||
kv++;
|
||||
}
|
||||
// set a reference from FROM to TO and a cross-reference(xref) from TO to FROM.
|
||||
R_API int r_anal_xrefs_set(RAnal *anal, ut64 from, ut64 to, const RAnalRefType type) {
|
||||
if (!anal) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void listrefs(dict *m, ut64 addr, RList *list) {
|
||||
int i;
|
||||
if (addr == UT64_MAX) {
|
||||
for (i = 0; i < m->size; i++) {
|
||||
dictkv *kv = m->table[i];
|
||||
if (kv) {
|
||||
dict *ht = kv->u;
|
||||
while (kv->k != MHTNO) {
|
||||
mylistrefs (ht, UT64_MAX, list);
|
||||
kv++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dict *d = dict_getu (m, addr);
|
||||
if (!d) {
|
||||
return;
|
||||
}
|
||||
mylistrefs (d, addr, list);
|
||||
for (i = 0; i < m->size; i++) {
|
||||
dictkv *kv = m->table[i];
|
||||
if (kv) {
|
||||
while (kv->k != MHTNO) {
|
||||
if (kv->k == addr) {
|
||||
appendRef (list, kv->k, kv->v, kv->u);
|
||||
}
|
||||
// mylistrefs (ht, UT64_MAX, list);
|
||||
kv++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void listxrefs(dict *m, ut64 addr, RList *list) {
|
||||
int i;
|
||||
if (addr == UT64_MAX) {
|
||||
for (i = 0; i < m->size; i++) {
|
||||
dictkv *kv = m->table[i];
|
||||
if (kv) {
|
||||
dict *ht = kv->u;
|
||||
while (kv->k != MHTNO) {
|
||||
mylistrefs (ht, UT64_MAX, list);
|
||||
kv++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dict *d = dict_getu (m, addr);
|
||||
if (!d) {
|
||||
return;
|
||||
}
|
||||
mylistrefs (d, addr, list);
|
||||
}
|
||||
}
|
||||
|
||||
// [from=[from:to,],]
|
||||
// 10->20
|
||||
static void setref(dict *m, ut64 from, ut64 to, int type) {
|
||||
dict_set (m, from, to, r_anal_xrefs_type_tostring (type));
|
||||
}
|
||||
|
||||
static void setxref(dict *m, ut64 from, ut64 to, int type) {
|
||||
dictkv *kv = dict_getr (m, from);
|
||||
dict *d = NULL;
|
||||
if (kv) {
|
||||
d = kv->u;
|
||||
} else {
|
||||
d = R_NEW0 (dict);
|
||||
if (d) {
|
||||
dict_init (d, 9, dict_free);
|
||||
dict_set (m, from, to, d);
|
||||
}
|
||||
}
|
||||
if (d) {
|
||||
dict_set (d, from, to, r_anal_xrefs_type_tostring (type));
|
||||
}
|
||||
}
|
||||
|
||||
static void delref(dict *m, ut64 from, ut64 to, int type) {
|
||||
dict_del (m, to);
|
||||
#if 0
|
||||
dictkv *kv = dict_getr (m, from);
|
||||
if (kv) {
|
||||
dict *ht = kv->u;
|
||||
if (ht) {
|
||||
dict_del (ht, to);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
R_API int r_anal_xrefs_set (RAnal *anal, const RAnalRefType type, ut64 from, ut64 to) {
|
||||
char key[33];
|
||||
if (!anal || !DB) {
|
||||
if (!anal->iob.is_valid_offset (anal->iob.io, from, 0)) {
|
||||
return false;
|
||||
}
|
||||
if (!anal->iob.is_valid_offset (anal->iob.io, to, 0)) {
|
||||
return false;
|
||||
}
|
||||
// unknown refs should not be stored. seems wrong
|
||||
#if 0
|
||||
if (type == R_ANAL_REF_TYPE_NULL) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
#if USE_DICT
|
||||
setxref (anal->dict_xrefs, to, from, type);
|
||||
setref (anal->dict_refs, from, to, type);
|
||||
// setref (anal->dict_refs, from, to, type);
|
||||
// setref (anal->dict_xrefs, from, to, type);
|
||||
// setref (anal->dict_refs, to, from, type);
|
||||
// eprintf ("set %llx %llx %p\n", from , to, dict_getr(anal->dict_refs, from));
|
||||
// dict_getu(m, from, checkType, "ref");
|
||||
#else
|
||||
XREFKEY (key, sizeof (key), "ref", type, from);
|
||||
sdb_array_add_num (DB, key, to, 0);
|
||||
|
||||
XREFKEY (key, sizeof (key), "xref", type, to);
|
||||
sdb_array_add_num (DB, key, from, 0);
|
||||
#endif
|
||||
setxref (anal->dict_refs, from, to, type);
|
||||
return true;
|
||||
}
|
||||
|
||||
R_API int r_anal_xrefs_deln (RAnal *anal, const RAnalRefType type, ut64 from, ut64 to) {
|
||||
char key[33];
|
||||
if (!anal || !DB) {
|
||||
R_API int r_anal_xrefs_deln(RAnal *anal, ut64 from, ut64 to, const RAnalRefType type) {
|
||||
if (!anal) {
|
||||
return false;
|
||||
}
|
||||
#if USE_DICT
|
||||
delref (anal->dict_refs, from, to, type);
|
||||
delref (anal->dict_xrefs, to, from, type);
|
||||
#else
|
||||
XREFKEY (key, sizeof (key), "ref", type, from);
|
||||
sdb_array_remove_num (DB, key, to, 0);
|
||||
XREFKEY (key, sizeof (key), "xref", type, to);
|
||||
sdb_array_remove_num (DB, key, from, 0);
|
||||
#endif
|
||||
ht_delete_u64 (anal->dict_refs, from);
|
||||
ht_delete_u64 (anal->dict_xrefs, to);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int _type = -1;
|
||||
static RList *_list = NULL;
|
||||
static char *_kpfx = NULL;
|
||||
R_API int r_anal_xref_del(RAnal *anal, ut64 from, ut64 to) {
|
||||
bool res = false;
|
||||
res |= r_anal_xrefs_deln (anal, from, to, R_ANAL_REF_TYPE_NULL);
|
||||
res |= r_anal_xrefs_deln (anal, from, to, R_ANAL_REF_TYPE_CODE);
|
||||
res |= r_anal_xrefs_deln (anal, from, to, R_ANAL_REF_TYPE_CALL);
|
||||
res |= r_anal_xrefs_deln (anal, from, to, R_ANAL_REF_TYPE_DATA);
|
||||
res |= r_anal_xrefs_deln (anal, from, to, R_ANAL_REF_TYPE_STRING);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int xrefs_list_cb_any(RAnal *anal, const char *k, const char *v) {
|
||||
//ut64 dst, src = r_num_get (NULL, v);
|
||||
if (!strncmp (_kpfx, k, strlen (_kpfx))) {
|
||||
RAnalRef *ref = r_anal_ref_new ();
|
||||
if (ref) {
|
||||
ref->addr = r_num_get (NULL, k + strlen (_kpfx) + 1);
|
||||
ref->at = r_num_get (NULL, v); // XXX
|
||||
ref->type = _type;
|
||||
r_list_append (_list, ref);
|
||||
}
|
||||
}
|
||||
R_API int r_anal_xrefs_from(RAnal *anal, RList *list, const char *kind, const RAnalRefType type, ut64 addr) {
|
||||
listxrefs (anal->dict_refs, addr, list);
|
||||
return true;
|
||||
}
|
||||
|
||||
#if USE_DICT
|
||||
R_API int r_anal_xrefs_from (RAnal *anal, RList *list, const char *kind, const RAnalRefType type, ut64 addr) {
|
||||
listrefs (anal->dict_refs, addr, list);
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
R_API int r_anal_xrefs_from (RAnal *anal, RList *list, const char *kind, const RAnalRefType type, ut64 addr) {
|
||||
char *next, *s, *str, *ptr, key[256];
|
||||
RAnalRef *ref = NULL;
|
||||
if (addr == UT64_MAX) {
|
||||
_type = type;
|
||||
_list = list;
|
||||
_kpfx = r_str_newf ("xref.%s", analref_toString (type));
|
||||
sdb_foreach (DB, (SdbForeachCallback)xrefs_list_cb_any, anal);
|
||||
free (_kpfx);
|
||||
return true;
|
||||
}
|
||||
XREFKEY(key, sizeof (key), kind, type, addr);
|
||||
str = sdb_get (DB, key, 0);
|
||||
if (!str) {
|
||||
return false;
|
||||
}
|
||||
for (next = ptr = str; next; ptr = next) {
|
||||
s = sdb_anext (ptr, &next);
|
||||
if (!(ref = r_anal_ref_new ())) {
|
||||
return false;
|
||||
}
|
||||
ref->addr = r_num_get (NULL, s);
|
||||
ref->at = addr;
|
||||
ref->type = type;
|
||||
r_list_append (list, ref);
|
||||
}
|
||||
free (str);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
R_API RList *r_anal_xrefs_get (RAnal *anal, ut64 to) {
|
||||
RList *list = r_list_newf (r_anal_ref_free);
|
||||
R_API RList *r_anal_xrefs_get(RAnal *anal, ut64 to) {
|
||||
RList *list = r_anal_ref_list_new ();
|
||||
if (!list) {
|
||||
return NULL;
|
||||
}
|
||||
#if USE_DICT
|
||||
// listrefs (anal->dict_refs, to, list);
|
||||
// XXX, one or the other?
|
||||
listxrefs (anal->dict_xrefs, to, list);
|
||||
// listrefs (anal->dict_xrefs, to, list);
|
||||
#else
|
||||
r_anal_xrefs_from (anal, list, "xref", R_ANAL_REF_TYPE_NULL, to);
|
||||
r_anal_xrefs_from (anal, list, "xref", R_ANAL_REF_TYPE_CODE, to);
|
||||
r_anal_xrefs_from (anal, list, "xref", R_ANAL_REF_TYPE_CALL, to);
|
||||
r_anal_xrefs_from (anal, list, "xref", R_ANAL_REF_TYPE_DATA, to);
|
||||
r_anal_xrefs_from (anal, list, "xref", R_ANAL_REF_TYPE_STRING, to);
|
||||
#endif
|
||||
if (r_list_empty (list)) {
|
||||
r_list_free (list);
|
||||
list = NULL;
|
||||
@ -309,22 +182,12 @@ R_API RList *r_anal_xrefs_get (RAnal *anal, ut64 to) {
|
||||
return list;
|
||||
}
|
||||
|
||||
R_API RList *r_anal_refs_get (RAnal *anal, ut64 from) {
|
||||
RList *list = r_list_newf (r_anal_ref_free);
|
||||
R_API RList *r_anal_refs_get(RAnal *anal, ut64 from) {
|
||||
RList *list = r_anal_ref_list_new ();
|
||||
if (!list) {
|
||||
return NULL;
|
||||
}
|
||||
#if USE_DICT
|
||||
// listrefs (anal->dict_refs, from, list);
|
||||
listxrefs (anal->dict_xrefs, from, list);
|
||||
// eprintf ("refs_get from %llx %d\n", from, r_list_length (list));
|
||||
#else
|
||||
r_anal_xrefs_from (anal, list, "ref", R_ANAL_REF_TYPE_NULL, from);
|
||||
r_anal_xrefs_from (anal, list, "ref", R_ANAL_REF_TYPE_CODE, from);
|
||||
r_anal_xrefs_from (anal, list, "ref", R_ANAL_REF_TYPE_CALL, from);
|
||||
r_anal_xrefs_from (anal, list, "ref", R_ANAL_REF_TYPE_DATA, from);
|
||||
r_anal_xrefs_from (anal, list, "ref", R_ANAL_REF_TYPE_STRING, from);
|
||||
#endif
|
||||
listxrefs (anal->dict_refs, from, list);
|
||||
if (r_list_empty (list)) {
|
||||
r_list_free (list);
|
||||
list = NULL;
|
||||
@ -332,21 +195,12 @@ R_API RList *r_anal_refs_get (RAnal *anal, ut64 from) {
|
||||
return list;
|
||||
}
|
||||
|
||||
R_API RList *r_anal_xrefs_get_from (RAnal *anal, ut64 to) {
|
||||
RList *list = r_list_newf (NULL);
|
||||
R_API RList *r_anal_xrefs_get_from(RAnal *anal, ut64 to) {
|
||||
RList *list = r_anal_ref_list_new ();
|
||||
if (!list) {
|
||||
return NULL;
|
||||
}
|
||||
#if USE_DICT
|
||||
listxrefs (anal->dict_xrefs, to, list);
|
||||
//listrefs (anal->dict_refs, to, list);
|
||||
#else
|
||||
r_anal_xrefs_from (anal, list, "ref", R_ANAL_REF_TYPE_NULL, to);
|
||||
r_anal_xrefs_from (anal, list, "ref", R_ANAL_REF_TYPE_CODE, to);
|
||||
r_anal_xrefs_from (anal, list, "ref", R_ANAL_REF_TYPE_CALL, to);
|
||||
r_anal_xrefs_from (anal, list, "ref", R_ANAL_REF_TYPE_DATA, to);
|
||||
r_anal_xrefs_from (anal, list, "ref", R_ANAL_REF_TYPE_STRING, to);
|
||||
#endif
|
||||
listxrefs (anal->dict_refs, to, list);
|
||||
if (r_list_empty (list)) {
|
||||
r_list_free (list);
|
||||
list = NULL;
|
||||
@ -354,174 +208,63 @@ R_API RList *r_anal_xrefs_get_from (RAnal *anal, ut64 to) {
|
||||
return list;
|
||||
}
|
||||
|
||||
R_API bool r_anal_xrefs_init(RAnal *anal) {
|
||||
sdb_reset (DB);
|
||||
if (DB) {
|
||||
sdb_array_set (DB, "types", -1, "code.jmp,code.call,data.mem,data.string", 0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int xrefs_list_cb_rad(RAnal *anal, const char *k, const char *v) {
|
||||
ut64 dst, src = r_num_get (NULL, v);
|
||||
if (!strncmp (k, "ref.", 4)) {
|
||||
const char *p = r_str_rchr (k, NULL, '.');
|
||||
if (p) {
|
||||
dst = r_num_get (NULL, p + 1);
|
||||
anal->cb_printf ("ax 0x%"PFMT64x" 0x%"PFMT64x"\n", src, dst);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int xrefs_list_cb_quiet(RAnal *anal, const char *k, const char *v) {
|
||||
ut64 dst, src = r_num_get (NULL, v);
|
||||
if (!strncmp (k, "ref.", 4)) {
|
||||
const char *p = r_str_rchr (k, NULL, '.');
|
||||
if (p) {
|
||||
dst = r_num_get (NULL, p + 1);
|
||||
char * type = strchr (k, '.');
|
||||
if (type) {
|
||||
type = strdup (type + 1);
|
||||
char *t = strchr (type, '.');
|
||||
if (t) {
|
||||
*t = ' ';
|
||||
}
|
||||
char *T = (char *)r_str_rchr (type, NULL, '.');
|
||||
if (T) {
|
||||
T = (char *)r_str_rchr (T, NULL, '.');
|
||||
if (T) {
|
||||
*T = 0;
|
||||
anal->cb_printf ("0x%08"PFMT64x" -> 0x%08"PFMT64x" %s\n", src, dst, type);
|
||||
}
|
||||
} else {
|
||||
if (t) {
|
||||
*t = 0;
|
||||
}
|
||||
}
|
||||
anal->cb_printf ("0x%08"PFMT64x" -> 0x%08"PFMT64x" %s\n", src, dst, type);
|
||||
free (type);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int xrefs_list_cb_normal(RAnal *anal, const char *k, const char *v) {
|
||||
ut64 dst, src = r_num_get (NULL, v);
|
||||
if (!strncmp (k, "ref.", 4)) {
|
||||
const char *p = r_str_rchr (k, NULL, '.');
|
||||
if (p) {
|
||||
dst = r_num_get (NULL, p + 1);
|
||||
char * type = strchr (k, '.');
|
||||
if (type) {
|
||||
type = strdup (type + 1);
|
||||
char *ot = strchr (type, '.');
|
||||
if (ot) {
|
||||
*ot = ' ';
|
||||
}
|
||||
char *t = (char *)r_str_rchr (type, NULL, '.');
|
||||
if (t) {
|
||||
t = (char *)r_str_rchr (t, NULL, '.');
|
||||
if (t) {
|
||||
*t = 0;
|
||||
}
|
||||
} else {
|
||||
if (ot) {
|
||||
*ot = 0;
|
||||
}
|
||||
}
|
||||
{
|
||||
char *name = anal->coreb.getNameDelta (anal->coreb.core, src);
|
||||
r_str_replace_char (name, ' ', 0);
|
||||
anal->cb_printf ("%40s", name? name: "");
|
||||
free (name);
|
||||
anal->cb_printf (" 0x%"PFMT64x" -> %9s -> 0x%"PFMT64x, src, type, dst);
|
||||
name = anal->coreb.getNameDelta (anal->coreb.core, dst);
|
||||
r_str_replace_char (name, ' ', 0);
|
||||
if (name && *name) {
|
||||
anal->cb_printf (" %s\n", name);
|
||||
} else {
|
||||
anal->cb_printf ("\n");
|
||||
}
|
||||
free (name);
|
||||
}
|
||||
free (type);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool xrefs_list_cb_json(RAnal *anal, bool is_first, const char *k, const char *v) {
|
||||
ut64 dst, src = r_num_get (NULL, v);
|
||||
if (strlen (k) > 8) {
|
||||
const char *p = r_str_rchr (k, NULL, '.');
|
||||
if (p) {
|
||||
if (is_first) {
|
||||
is_first = false;
|
||||
} else {
|
||||
anal->cb_printf (",");
|
||||
}
|
||||
dst = r_num_get (NULL, p + 1);
|
||||
sscanf (p + 1, "0x%"PFMT64x, &dst);
|
||||
anal->cb_printf ("\"%"PFMT64d"\":%"PFMT64d, src, dst);
|
||||
}
|
||||
}
|
||||
return is_first;
|
||||
}
|
||||
|
||||
static int xrefs_list_cb_plain(RAnal *anal, const char *k, const char *v) {
|
||||
anal->cb_printf ("%s=%s\n", k, v);
|
||||
return 1;
|
||||
}
|
||||
|
||||
R_API void r_anal_xrefs_list(RAnal *anal, int rad) {
|
||||
#if USE_DICT
|
||||
bool is_first = true;
|
||||
RListIter *iter;
|
||||
RAnalRef *ref;
|
||||
RList *list = r_list_new();
|
||||
RList *list = r_anal_ref_list_new();
|
||||
listxrefs (anal->dict_xrefs, UT64_MAX, list);
|
||||
if (rad == 'j') {
|
||||
anal->cb_printf ("{");
|
||||
}
|
||||
r_list_foreach (list, iter, ref) {
|
||||
int type = ref->type? ref->type: ' ';
|
||||
r_cons_printf ("%c 0x%08llx -> 0x%08llx\n", type, ref->at, ref->addr);
|
||||
int t = ref->type ? ref->type: ' ';
|
||||
switch (rad) {
|
||||
case '*':
|
||||
anal->cb_printf ("ax%c 0x%"PFMT64x" 0x%"PFMT64x"\n",
|
||||
t, ref->at, ref->addr);
|
||||
break;
|
||||
case '\0':
|
||||
{
|
||||
char *name = anal->coreb.getNameDelta (anal->coreb.core, ref->at);
|
||||
r_str_replace_char (name, ' ', 0);
|
||||
anal->cb_printf ("%40s", name? name: "");
|
||||
free (name);
|
||||
anal->cb_printf (" 0x%"PFMT64x" -> %9s -> 0x%"PFMT64x, ref->at, analref_toString (t), ref->addr);
|
||||
name = anal->coreb.getNameDelta (anal->coreb.core, ref->addr);
|
||||
r_str_replace_char (name, ' ', 0);
|
||||
if (name && *name) {
|
||||
anal->cb_printf (" %s\n", name);
|
||||
} else {
|
||||
anal->cb_printf ("\n");
|
||||
}
|
||||
free (name);
|
||||
}
|
||||
break;
|
||||
case 'q':
|
||||
anal->cb_printf ("0x%08"PFMT64x" -> 0x%08"PFMT64x" %s\n", ref->at, ref->addr, analref_toString (t));
|
||||
break;
|
||||
case 'j':
|
||||
{
|
||||
if (is_first) {
|
||||
is_first = false;
|
||||
} else {
|
||||
anal->cb_printf (",");
|
||||
}
|
||||
anal->cb_printf ("\"%"PFMT64d"\":%"PFMT64d, ref->at, ref->addr);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rad == 'j') {
|
||||
anal->cb_printf ("}\n");
|
||||
}
|
||||
r_list_free (list);
|
||||
#else
|
||||
switch (rad) {
|
||||
case 1:
|
||||
case '*':
|
||||
sdb_foreach (DB, (SdbForeachCallback)xrefs_list_cb_rad, anal);
|
||||
break;
|
||||
case '\0':
|
||||
sdb_foreach (DB, (SdbForeachCallback)xrefs_list_cb_normal, anal);
|
||||
break;
|
||||
case 'q':
|
||||
sdb_foreach (DB, (SdbForeachCallback)xrefs_list_cb_quiet, anal);
|
||||
break;
|
||||
case 'j':
|
||||
{
|
||||
anal->cb_printf ("{");
|
||||
bool is_first = true;
|
||||
SdbListIter *sdb_iter;
|
||||
SdbKv *kv;
|
||||
SdbList *sdb_list = sdb_foreach_match (DB, "^ref.", false);
|
||||
ls_foreach (sdb_list, sdb_iter, kv) {
|
||||
is_first = xrefs_list_cb_json (anal, is_first, kv->key, kv->value);
|
||||
}
|
||||
ls_free (sdb_list);
|
||||
anal->cb_printf ("}\n");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
sdb_foreach (DB, (SdbForeachCallback)xrefs_list_cb_plain, anal);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
R_API const char *r_anal_xrefs_type_tostring (char type) {
|
||||
R_API const char *r_anal_xrefs_type_tostring(RAnalRefType type) {
|
||||
switch (type) {
|
||||
case R_ANAL_REF_TYPE_CODE:
|
||||
return "JMP";
|
||||
@ -537,20 +280,98 @@ R_API const char *r_anal_xrefs_type_tostring (char type) {
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
RAnal *anal;
|
||||
int count;
|
||||
} CountState;
|
||||
|
||||
static int countcb(CountState *cs, const char *k, const char *v) {
|
||||
if (!strncmp (k, "ref.", 4)) {
|
||||
cs->count ++;
|
||||
R_API RAnalRefType r_anal_xrefs_type(char ch) {
|
||||
switch (ch) {
|
||||
case R_ANAL_REF_TYPE_CODE:
|
||||
case R_ANAL_REF_TYPE_CALL:
|
||||
case R_ANAL_REF_TYPE_DATA:
|
||||
case R_ANAL_REF_TYPE_STRING:
|
||||
case R_ANAL_REF_TYPE_NULL:
|
||||
return (RAnalRefType)ch;
|
||||
default:
|
||||
return R_ANAL_REF_TYPE_NULL;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
R_API bool r_anal_xrefs_init(RAnal *anal) {
|
||||
SdbHash *tmp;
|
||||
|
||||
ht_free (anal->dict_refs);
|
||||
anal->dict_refs = NULL;
|
||||
ht_free (anal->dict_xrefs);
|
||||
anal->dict_xrefs = NULL;
|
||||
|
||||
tmp = ht_new (NULL, xrefs_ht_free, NULL);
|
||||
if (!tmp) {
|
||||
return false;
|
||||
}
|
||||
anal->dict_refs = tmp;
|
||||
|
||||
tmp = ht_new (NULL, xrefs_ht_free, NULL);
|
||||
if (!tmp) {
|
||||
ht_free (anal->dict_refs);
|
||||
anal->dict_refs = NULL;
|
||||
return false;
|
||||
}
|
||||
anal->dict_xrefs = tmp;
|
||||
return true;
|
||||
}
|
||||
|
||||
R_API int r_anal_xrefs_count(RAnal *anal) {
|
||||
CountState cs = { anal, 0 };
|
||||
sdb_foreach (DB, (SdbForeachCallback)countcb, &cs);
|
||||
return cs.count;
|
||||
return anal->dict_xrefs->count;
|
||||
}
|
||||
|
||||
static int ref_cmp(const RAnalRef *a, const RAnalRef *b) {
|
||||
if (a->at < b->at) {
|
||||
return -1;
|
||||
}
|
||||
if (a->at > b->at) {
|
||||
return 1;
|
||||
}
|
||||
if (a->addr < b->addr) {
|
||||
return -1;
|
||||
}
|
||||
if (a->addr > b->addr) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static RList *fcn_get_refs(RAnalFunction *fcn, SdbHash *ht) {
|
||||
RListIter *iter;
|
||||
RAnalBlock *bb;
|
||||
RList *list = r_anal_ref_list_new ();
|
||||
if (!list) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r_list_foreach (fcn->bbs, iter, bb) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < bb->ninstr; ++i) {
|
||||
ut64 at = bb->addr + r_anal_bb_offset_inst (bb, i);
|
||||
listxrefs (ht, at, list);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
R_API RList *r_anal_fcn_get_refs(RAnal *anal, RAnalFunction *fcn) {
|
||||
return fcn_get_refs (fcn, anal->dict_refs);
|
||||
}
|
||||
|
||||
R_API RList *r_anal_fcn_get_xrefs(RAnal *anal, RAnalFunction *fcn) {
|
||||
return fcn_get_refs (fcn, anal->dict_xrefs);
|
||||
}
|
||||
|
||||
R_API RList *r_anal_fcn_get_refs_sorted(RAnal *anal, RAnalFunction *fcn) {
|
||||
RList *l = r_anal_fcn_get_refs (anal, fcn);
|
||||
r_list_sort (l, (RListComparator)ref_cmp);
|
||||
return l;
|
||||
}
|
||||
|
||||
R_API RList *r_anal_fcn_get_xrefs_sorted(RAnal *anal, RAnalFunction *fcn) {
|
||||
RList *l = r_anal_fcn_get_xrefs (anal, fcn);
|
||||
r_list_sort (l, (RListComparator)ref_cmp);
|
||||
return l;
|
||||
}
|
||||
|
@ -318,12 +318,92 @@ R_API ut64 r_core_anal_address(RCore *core, ut64 addr) {
|
||||
return types;
|
||||
}
|
||||
|
||||
static bool blacklisted_word(char* name) {
|
||||
const char * list[] = {
|
||||
"__stack_chk_guard", "__stderrp", "__stdinp", "__stdoutp", "_DefaultRuneLocale"
|
||||
};
|
||||
int i;
|
||||
for (i = 0; i < sizeof (list) / sizeof (list[0]); i++) {
|
||||
if (strstr (name, list[i])) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static char *anal_fcn_autoname(RCore *core, RAnalFunction *fcn, int dump) {
|
||||
int use_getopt = 0;
|
||||
int use_isatty = 0;
|
||||
char *do_call = NULL;
|
||||
RAnalRef *ref;
|
||||
RListIter *iter;
|
||||
RList *refs = r_anal_fcn_get_refs_sorted (core->anal, fcn);
|
||||
r_list_foreach (refs, iter, ref) {
|
||||
RFlagItem *f = r_flag_get_i (core->flags, ref->addr);
|
||||
if (f) {
|
||||
if (dump) {
|
||||
r_cons_printf ("0x%08"PFMT64x" 0x%08"PFMT64x" %s\n", ref->at, ref->addr, f->name);
|
||||
}
|
||||
if (blacklisted_word (f->name)) {
|
||||
break;
|
||||
}
|
||||
if (strstr (f->name, ".isatty")) {
|
||||
use_isatty = 1;
|
||||
}
|
||||
if (strstr (f->name, ".getopt")) {
|
||||
use_getopt = 1;
|
||||
}
|
||||
if (!strncmp (f->name, "method.", 7)) {
|
||||
free (do_call);
|
||||
do_call = strdup (f->name + 7);
|
||||
break;
|
||||
}
|
||||
if (!strncmp (f->name, "str.", 4)) {
|
||||
free (do_call);
|
||||
do_call = strdup (f->name + 4);
|
||||
break;
|
||||
}
|
||||
if (!strncmp (f->name, "sym.imp.", 8)) {
|
||||
free (do_call);
|
||||
do_call = strdup (f->name + 8);
|
||||
break;
|
||||
}
|
||||
if (!strncmp (f->name, "reloc.", 6)) {
|
||||
free (do_call);
|
||||
do_call = strdup (f->name + 6);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
r_list_free (refs);
|
||||
// TODO: append counter if name already exists
|
||||
if (use_getopt) {
|
||||
RFlagItem *item = r_flag_get (core->flags, "main");
|
||||
free (do_call);
|
||||
// if referenced from entrypoint. this should be main
|
||||
if (item && item->offset == fcn->addr) {
|
||||
return strdup ("main"); // main?
|
||||
}
|
||||
return strdup ("parse_args"); // main?
|
||||
}
|
||||
if (use_isatty) {
|
||||
char *ret = r_str_newf ("sub.setup_tty_%s_%x", do_call, fcn->addr & 0xfff);
|
||||
free (do_call);
|
||||
return ret;
|
||||
}
|
||||
if (do_call) {
|
||||
char *ret = r_str_newf ("sub.%s_%x", do_call, fcn->addr & 0xfff);
|
||||
free (do_call);
|
||||
return ret;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*this only autoname those function that start with fcn.* or sym.func.* */
|
||||
R_API void r_core_anal_autoname_all_fcns(RCore *core) {
|
||||
RListIter *it;
|
||||
RAnalFunction *fcn;
|
||||
|
||||
r_list_foreach (core->anal->fcns, it, fcn) {
|
||||
char *name = r_core_anal_fcn_autoname (core, fcn->addr, 0);
|
||||
char *name = anal_fcn_autoname (core, fcn, 0);
|
||||
if (name && (!strncmp (fcn->name, "fcn.", 4) || \
|
||||
!strncmp (fcn->name, "sym.func.", 9))) {
|
||||
r_flag_rename (core->flags, r_flag_get (core->flags, fcn->name), name);
|
||||
@ -335,86 +415,12 @@ R_API void r_core_anal_autoname_all_fcns(RCore *core) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool blacklisted_word(char* name) {
|
||||
const char * list[] = {
|
||||
"__stack_chk_guard", "__stderrp", "__stdinp", "__stdoutp", "_DefaultRuneLocale"
|
||||
};
|
||||
int i;
|
||||
for (i = 0; i < sizeof (list) / sizeof (list[0]); i++) {
|
||||
if (strstr (name, list[i])) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* suggest a name for the function at the address 'addr'.
|
||||
* If dump is true, every strings associated with the function is printed */
|
||||
R_API char *r_core_anal_fcn_autoname(RCore *core, ut64 addr, int dump) {
|
||||
int use_getopt = 0;
|
||||
int use_isatty = 0;
|
||||
char *do_call = NULL;
|
||||
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, addr, 0);
|
||||
if (fcn) {
|
||||
RAnalRef *ref;
|
||||
RListIter *iter;
|
||||
RList *refs = r_anal_fcn_get_refs (core->anal, fcn);
|
||||
r_list_foreach (refs, iter, ref) {
|
||||
RFlagItem *f = r_flag_get_i (core->flags, ref->addr);
|
||||
if (f) {
|
||||
if (dump) {
|
||||
r_cons_printf ("0x%08"PFMT64x" 0x%08"PFMT64x" %s\n", ref->at, ref->addr, f->name);
|
||||
}
|
||||
if (blacklisted_word (f->name)) {
|
||||
break;
|
||||
}
|
||||
if (strstr (f->name, ".isatty")) {
|
||||
use_isatty = 1;
|
||||
}
|
||||
if (strstr (f->name, ".getopt")) {
|
||||
use_getopt = 1;
|
||||
}
|
||||
if (!strncmp (f->name, "method.", 7)) {
|
||||
free (do_call);
|
||||
do_call = strdup (f->name + 7);
|
||||
break;
|
||||
}
|
||||
if (!strncmp (f->name, "str.", 4)) {
|
||||
free (do_call);
|
||||
do_call = strdup (f->name + 4);
|
||||
break;
|
||||
}
|
||||
if (!strncmp (f->name, "sym.imp.", 8)) {
|
||||
free (do_call);
|
||||
do_call = strdup (f->name + 8);
|
||||
break;
|
||||
}
|
||||
if (!strncmp (f->name, "reloc.", 6)) {
|
||||
free (do_call);
|
||||
do_call = strdup (f->name + 6);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
r_list_free (refs);
|
||||
// TODO: append counter if name already exists
|
||||
if (use_getopt) {
|
||||
RFlagItem *item = r_flag_get (core->flags, "main");
|
||||
free (do_call);
|
||||
// if referenced from entrypoint. this should be main
|
||||
if (item && item->offset == addr) {
|
||||
return strdup ("main"); // main?
|
||||
}
|
||||
return strdup ("parse_args"); // main?
|
||||
}
|
||||
if (use_isatty) {
|
||||
char *ret = r_str_newf ("sub.setup_tty_%s_%x", do_call, addr & 0xfff);
|
||||
free (do_call);
|
||||
return ret;
|
||||
}
|
||||
if (do_call) {
|
||||
char *ret = r_str_newf ("sub.%s_%x", do_call, addr & 0xfff);
|
||||
free (do_call);
|
||||
return ret;
|
||||
}
|
||||
return anal_fcn_autoname (core, fcn, dump);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -437,7 +443,7 @@ static void r_anal_set_stringrefs(RCore *core, RAnalFunction *fcn) {
|
||||
r_list_foreach (refs, iter, ref) {
|
||||
if (ref->type == R_ANAL_REF_TYPE_DATA &&
|
||||
r_bin_is_string (core->bin, ref->addr)) {
|
||||
ref->type = R_ANAL_REF_TYPE_STRING;
|
||||
r_anal_xrefs_set (core->anal, ref->at, ref->addr, R_ANAL_REF_TYPE_STRING);
|
||||
}
|
||||
}
|
||||
r_list_free (refs);
|
||||
@ -509,34 +515,55 @@ static int r_anal_try_get_fcn(RCore *core, RAnalRef *ref, int fcndepth, int refd
|
||||
}
|
||||
|
||||
static int r_anal_analyze_fcn_refs(RCore *core, RAnalFunction *fcn, int depth) {
|
||||
RListIter *iter, *tmp;
|
||||
RListIter *iter;
|
||||
RAnalRef *ref;
|
||||
RList *refs = r_anal_fcn_get_refs (core->anal, fcn);
|
||||
|
||||
r_list_foreach_safe (refs, iter, tmp, ref) {
|
||||
if (ref->addr != UT64_MAX) {
|
||||
switch (ref->type) {
|
||||
case 'd':
|
||||
if (core->anal->opt.followdatarefs) {
|
||||
r_anal_try_get_fcn (core, ref, depth, 2);
|
||||
}
|
||||
break;
|
||||
case R_ANAL_REF_TYPE_CODE:
|
||||
case R_ANAL_REF_TYPE_CALL:
|
||||
r_core_anal_fcn (core, ref->addr, ref->at, ref->type, depth-1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// TODO: fix memleak here, fcn not freed even though it is
|
||||
// added in core->anal->fcns which is freed in r_anal_free()
|
||||
r_list_foreach (refs, iter, ref) {
|
||||
if (ref->addr == UT64_MAX) {
|
||||
continue;
|
||||
}
|
||||
switch (ref->type) {
|
||||
case 'd':
|
||||
if (core->anal->opt.followdatarefs) {
|
||||
r_anal_try_get_fcn (core, ref, depth, 2);
|
||||
}
|
||||
break;
|
||||
case R_ANAL_REF_TYPE_CODE:
|
||||
case R_ANAL_REF_TYPE_CALL:
|
||||
r_core_anal_fcn (core, ref->addr, ref->at, ref->type, depth-1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// TODO: fix memleak here, fcn not freed even though it is
|
||||
// added in core->anal->fcns which is freed in r_anal_free()
|
||||
}
|
||||
|
||||
r_list_free (refs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void function_rename(RFlag *flags, RAnalFunction *fcn) {
|
||||
const char *locname = "loc.";
|
||||
const size_t locsize = strlen (locname);
|
||||
char *fcnname = fcn->name;
|
||||
|
||||
if (strncmp (fcn->name, locname, locsize) == 0) {
|
||||
const char *fcnpfx, *restofname;
|
||||
RFlagItem *f;
|
||||
|
||||
fcn->type = R_ANAL_FCN_TYPE_FCN;
|
||||
fcnpfx = r_anal_fcn_type_tostring (fcn->type);
|
||||
restofname = fcn->name + locsize;
|
||||
fcn->name = r_str_newf ("%s.%s", fcnpfx, restofname);
|
||||
|
||||
f = r_flag_get_i (flags, fcn->addr);
|
||||
r_flag_rename (flags, f, fcn->name);
|
||||
|
||||
free (fcnname);
|
||||
}
|
||||
}
|
||||
|
||||
static int core_anal_fcn(RCore *core, ut64 at, ut64 from, int reftype, int depth) {
|
||||
if (depth < 0) {
|
||||
// printf ("Too deep for 0x%08"PFMT64x"\n", at);
|
||||
@ -581,7 +608,6 @@ static int core_anal_fcn(RCore *core, ut64 at, ut64 from, int reftype, int depth
|
||||
}
|
||||
do {
|
||||
RFlagItem *f;
|
||||
RAnalRef *ref;
|
||||
int delta = r_anal_fcn_size (fcn);
|
||||
// XXX hack slow check io error
|
||||
if (core->io->va) {
|
||||
@ -690,13 +716,6 @@ static int core_anal_fcn(RCore *core, ut64 at, ut64 from, int reftype, int depth
|
||||
|
||||
/* New function: Add initial xref */
|
||||
if (from != UT64_MAX) {
|
||||
// We shuold not use fcn->xrefs .. because that should be only via api (on top of sdb)
|
||||
// the concepts of refs and xrefs are a bit twisted in the old implementation
|
||||
ref = r_anal_ref_new ();
|
||||
if (!ref) {
|
||||
eprintf ("Error: new (xref)\n");
|
||||
goto error;
|
||||
}
|
||||
if (fcn->type == R_ANAL_FCN_TYPE_LOC) {
|
||||
RAnalFunction *f = r_anal_get_fcn_in (core->anal, from, -1);
|
||||
if (f) {
|
||||
@ -707,11 +726,7 @@ static int core_anal_fcn(RCore *core, ut64 at, ut64 from, int reftype, int depth
|
||||
r_list_sort (f->fcn_locs, &cmpfcn);
|
||||
}
|
||||
}
|
||||
ref->addr = from;
|
||||
ref->at = fcn->addr;
|
||||
ref->type = reftype;
|
||||
// XXX this is creating dupped entries in the refs list with invalid reftypes, wtf?
|
||||
r_anal_xrefs_set (core->anal, reftype, from, fcn->addr);
|
||||
r_anal_xrefs_set (core->anal, from, fcn->addr, reftype);
|
||||
}
|
||||
// XXX: this is wrong. See CID 1134565
|
||||
r_anal_fcn_insert (core->anal, fcn);
|
||||
@ -1468,7 +1483,6 @@ R_API int r_core_anal_fcn(RCore *core, ut64 at, ut64 from, int reftype, int dept
|
||||
bool use_esil = r_config_get_i (core->config, "anal.esil");
|
||||
RAnalFunction *fcn;
|
||||
RListIter *iter;
|
||||
RList *xrefs = NULL;
|
||||
|
||||
//update bits based on the core->offset otherwise we could have the
|
||||
//last value set and blow everything up
|
||||
@ -1514,36 +1528,26 @@ R_API int r_core_anal_fcn(RCore *core, ut64 at, ut64 from, int reftype, int dept
|
||||
fcn = r_anal_get_fcn_in (core->anal, at, 0);
|
||||
if (fcn) {
|
||||
if (fcn->addr == at) {
|
||||
// if the function was already analyzed as a "loc.",
|
||||
// convert it to function and rename it to "fcn.",
|
||||
// because we found a call to this address
|
||||
if (reftype == R_ANAL_REF_TYPE_CALL && fcn->type == R_ANAL_FCN_TYPE_LOC) {
|
||||
function_rename (core->flags, fcn);
|
||||
}
|
||||
|
||||
return 0; // already analyzed function
|
||||
}
|
||||
if (r_anal_fcn_is_in_offset (fcn, from)) { // inner function
|
||||
RAnalRef *ref;
|
||||
|
||||
// XXX: use r_anal-xrefs api and sdb
|
||||
// If the xref is new, add it
|
||||
// avoid dupes
|
||||
xrefs = r_anal_fcn_get_xrefs (core->anal, fcn);
|
||||
r_list_foreach (xrefs, iter, ref) {
|
||||
if (from == ref->addr) {
|
||||
r_list_free (xrefs);
|
||||
return true;
|
||||
}
|
||||
RList *l = r_anal_xrefs_get (core->anal, from);
|
||||
if (l && !r_list_empty (l)) {
|
||||
r_list_free (l);
|
||||
return true;
|
||||
}
|
||||
r_list_free (xrefs);
|
||||
r_list_free (l);
|
||||
|
||||
// we should analyze and add code ref otherwise aaa != aac
|
||||
if (from != UT64_MAX) {
|
||||
// We shuold not use fcn->xrefs .. because that should be only via api (on top of sdb)
|
||||
// the concepts of refs and xrefs are a bit twisted in the old implementation
|
||||
ref = r_anal_ref_new ();
|
||||
if (ref) {
|
||||
ref->addr = from;
|
||||
ref->at = fcn->addr;
|
||||
ref->type = reftype;
|
||||
// XXX this is creating dupped entries in the refs list with invalid reftypes, wtf?
|
||||
r_anal_xrefs_set (core->anal, reftype, from, fcn->addr);
|
||||
} else {
|
||||
eprintf ("Error: new (xref)\n");
|
||||
}
|
||||
r_anal_xrefs_set (core->anal, from, fcn->addr, reftype);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -1581,7 +1585,7 @@ R_API void r_core_anal_codexrefs(RCore *core, ut64 addr, int fmt) {
|
||||
const char *me = fcn->name;
|
||||
RListIter *iter;
|
||||
RAnalRef *ref;
|
||||
RList *refs = r_anal_fcn_get_refs (core->anal, fcn);
|
||||
RList *refs = r_anal_fcn_get_refs_sorted (core->anal, fcn);
|
||||
r_cons_printf ("e graph.layout=1\n");
|
||||
r_cons_printf ("ag-\n");
|
||||
r_cons_printf ("agn %s\n", me);
|
||||
@ -1599,6 +1603,7 @@ R_API void r_core_anal_codexrefs(RCore *core, ut64 addr, int fmt) {
|
||||
r_cons_printf ("agn %s\n", src);
|
||||
r_cons_printf ("age %s %s\n", src, me);
|
||||
}
|
||||
r_list_free (list);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1653,7 +1658,7 @@ repeat:
|
||||
if (addr != UT64_MAX && addr != fcni->addr) {
|
||||
continue;
|
||||
}
|
||||
RList *refs = r_anal_fcn_get_refs (core->anal, fcni);
|
||||
RList *refs = r_anal_fcn_get_refs_sorted (core->anal, fcni);
|
||||
if (!fmt) {
|
||||
r_cons_printf ("0x%08"PFMT64x"\n", fcni->addr);
|
||||
} else if (fmt == 1 && isGML) {
|
||||
@ -1783,7 +1788,7 @@ repeat:
|
||||
}
|
||||
} else if (fmt == 2) {
|
||||
if (fr) {
|
||||
RList *refs1 = r_anal_fcn_get_refs (core->anal, fr);
|
||||
RList *refs1 = r_anal_fcn_get_refs_sorted (core->anal, fr);
|
||||
if (!hideempty || (hideempty && r_list_length (refs1) > 0)) {
|
||||
if (usenames) {
|
||||
r_cons_printf ("%s\"%s\"", first2?",":"", fr->name);
|
||||
@ -1896,10 +1901,10 @@ static int fcnlist_gather_metadata(RAnal *anal, RList *fcns) {
|
||||
numcallrefs++;
|
||||
}
|
||||
}
|
||||
r_list_free (refs);
|
||||
fcn->meta.numcallrefs = numcallrefs;
|
||||
xrefs = r_anal_xrefs_get (anal, fcn->addr);
|
||||
fcn->meta.numrefs = xrefs? xrefs->length: 0;
|
||||
r_list_free (refs);
|
||||
r_list_free (xrefs);
|
||||
|
||||
// Determine the bounds of the functions address space
|
||||
@ -2070,7 +2075,7 @@ static int fcn_print_json(RCore *core, RAnalFunction *fcn) {
|
||||
fcn->diff->type == R_ANAL_DIFF_TYPE_UNMATCH?"UNMATCH":"NEW");
|
||||
}
|
||||
int outdegree = 0;
|
||||
refs = r_anal_fcn_get_refs (core->anal, fcn);
|
||||
refs = r_anal_fcn_get_refs_sorted (core->anal, fcn);
|
||||
if (!r_list_empty (refs)) {
|
||||
r_cons_printf (",\"callrefs\":[");
|
||||
r_list_foreach (refs, iter, refi) {
|
||||
@ -2102,7 +2107,7 @@ static int fcn_print_json(RCore *core, RAnalFunction *fcn) {
|
||||
r_list_free (refs);
|
||||
|
||||
int indegree = 0;
|
||||
xrefs = r_anal_fcn_get_xrefs (core->anal, fcn);
|
||||
xrefs = r_anal_fcn_get_xrefs_sorted (core->anal, fcn);
|
||||
if (!r_list_empty (xrefs)) {
|
||||
first = true;
|
||||
r_cons_printf (",\"codexrefs\":[");
|
||||
@ -2206,7 +2211,7 @@ static int fcn_print_detail(RCore *core, RAnalFunction *fcn) {
|
||||
/* Show references */
|
||||
RListIter *refiter;
|
||||
RAnalRef *refi;
|
||||
RList *refs = r_anal_fcn_get_refs (core->anal, fcn);
|
||||
RList *refs = r_anal_fcn_get_refs_sorted (core->anal, fcn);
|
||||
r_list_foreach (refs, refiter, refi) {
|
||||
switch (refi->type) {
|
||||
case R_ANAL_REF_TYPE_CALL:
|
||||
@ -2220,9 +2225,9 @@ static int fcn_print_detail(RCore *core, RAnalFunction *fcn) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
r_list_free (refs);
|
||||
/*Saving Function stack frame*/
|
||||
r_cons_printf ("afS %"PFMT64d" @ 0x%"PFMT64x"\n", fcn->maxstack, fcn->addr);
|
||||
r_list_free (refs);
|
||||
free (name);
|
||||
return 0;
|
||||
}
|
||||
@ -2253,7 +2258,7 @@ static int fcn_print_legacy(RCore *core, RAnalFunction *fcn) {
|
||||
r_cons_printf ("\nend-bbs: %d", ebbs);
|
||||
r_cons_printf ("\ncall-refs: ");
|
||||
int outdegree = 0;
|
||||
refs = r_anal_fcn_get_refs (core->anal, fcn);
|
||||
refs = r_anal_fcn_get_refs_sorted (core->anal, fcn);
|
||||
r_list_foreach (refs, iter, refi) {
|
||||
if (refi->type == R_ANAL_REF_TYPE_CALL) {
|
||||
outdegree++;
|
||||
@ -2273,7 +2278,7 @@ static int fcn_print_legacy(RCore *core, RAnalFunction *fcn) {
|
||||
|
||||
int indegree = 0;
|
||||
r_cons_printf ("\ncode-xrefs: ");
|
||||
xrefs = r_anal_fcn_get_xrefs (core->anal, fcn);
|
||||
xrefs = r_anal_fcn_get_xrefs_sorted (core->anal, fcn);
|
||||
r_list_foreach (xrefs, iter, refi) {
|
||||
if (refi->type == R_ANAL_REF_TYPE_CODE || refi->type == R_ANAL_REF_TYPE_CALL) {
|
||||
indegree++;
|
||||
@ -2289,6 +2294,7 @@ static int fcn_print_legacy(RCore *core, RAnalFunction *fcn) {
|
||||
r_cons_printf ("0x%08"PFMT64x" ", refi->addr);
|
||||
}
|
||||
}
|
||||
r_list_free (xrefs);
|
||||
|
||||
if (fcn->type == R_ANAL_FCN_TYPE_FCN || fcn->type == R_ANAL_FCN_TYPE_SYM) {
|
||||
int args_count = r_anal_var_count (core->anal, fcn, 'b', 1);
|
||||
@ -2312,7 +2318,6 @@ static int fcn_print_legacy(RCore *core, RAnalFunction *fcn) {
|
||||
r_cons_printf ("function: %s", fcn->diff->name);
|
||||
}
|
||||
}
|
||||
r_list_free (xrefs);
|
||||
free (name);
|
||||
return 0;
|
||||
}
|
||||
@ -2618,8 +2623,8 @@ static int core_anal_followptr(RCore *core, int type, ut64 at, ut64 ptr, ut64 re
|
||||
return false;
|
||||
}
|
||||
if (ref == UT64_MAX || ptr == ref) {
|
||||
const int t = code? type? type: 'c': 'd';
|
||||
r_anal_ref_add (core->anal, ptr, at, t);
|
||||
const RAnalRefType t = code? type? type: R_ANAL_REF_TYPE_CODE: R_ANAL_REF_TYPE_DATA;
|
||||
r_anal_xrefs_set (core->anal, at, ptr, t);
|
||||
return true;
|
||||
}
|
||||
if (depth < 1) {
|
||||
@ -2961,7 +2966,7 @@ R_API int r_core_anal_search_xrefs(RCore *core, ut64 from, ut64 to, int rad) {
|
||||
}
|
||||
// Add to SDB
|
||||
if (xref_to) {
|
||||
r_anal_xrefs_set (core->anal, type, at, xref_to);
|
||||
r_anal_xrefs_set (core->anal, at, xref_to, type);
|
||||
}
|
||||
} else if (rad == 'j') {
|
||||
// Output JSON
|
||||
@ -3575,7 +3580,7 @@ static int esilbreak_mem_read(RAnalEsil *esil, ut64 addr, ut8 *buf, int len) {
|
||||
bool validRef = false;
|
||||
if (trace && myvalid (mycore->io, refptr)) {
|
||||
if (ntarget == UT64_MAX || ntarget == refptr) {
|
||||
r_anal_ref_add (mycore->anal, refptr, esil->address, 'd');
|
||||
r_anal_xrefs_set (mycore->anal, esil->address, refptr, R_ANAL_REF_TYPE_DATA);
|
||||
str[0] = 0;
|
||||
if (r_io_read_at (mycore->io, refptr, str, sizeof (str)) < 1) {
|
||||
eprintf ("Invalid read\n");
|
||||
@ -3590,7 +3595,7 @@ static int esilbreak_mem_read(RAnalEsil *esil, ut64 addr, ut8 *buf, int len) {
|
||||
|
||||
/** resolve ptr */
|
||||
if (ntarget == UT64_MAX || ntarget == addr || (ntarget == UT64_MAX && !validRef)) {
|
||||
r_anal_ref_add (mycore->anal, addr, esil->address, 'd');
|
||||
r_anal_xrefs_set (mycore->anal, esil->address, addr, R_ANAL_REF_TYPE_DATA);
|
||||
}
|
||||
}
|
||||
return 0; // fallback
|
||||
@ -3929,15 +3934,15 @@ R_API void r_core_anal_esil(RCore *core, const char *str, const char *target) {
|
||||
// arm64
|
||||
if (core->anal->cur && arch == R2_ARCH_ARM64) {
|
||||
if (CHECKREF (ESIL->cur)) {
|
||||
r_anal_ref_add (core->anal, ESIL->cur, cur, 's');
|
||||
r_anal_xrefs_set (core->anal, cur, ESIL->cur, R_ANAL_REF_TYPE_STRING);
|
||||
}
|
||||
} else if ((target && op.ptr == ntarget) || !target) {
|
||||
// if (core->anal->cur && strcmp (core->anal->cur->arch, "arm")) {
|
||||
if (CHECKREF (ESIL->cur)) {
|
||||
if (op.ptr && r_io_is_valid_offset (core->io, op.ptr, !core->anal->opt.noncode)) {
|
||||
r_anal_ref_add (core->anal, op.ptr, cur,'s');
|
||||
r_anal_xrefs_set (core->anal, cur, op.ptr, R_ANAL_REF_TYPE_STRING);
|
||||
} else {
|
||||
r_anal_ref_add (core->anal, ESIL->cur, cur, 's');
|
||||
r_anal_xrefs_set (core->anal, cur, ESIL->cur, R_ANAL_REF_TYPE_STRING);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3952,7 +3957,7 @@ R_API void r_core_anal_esil(RCore *core, const char *str, const char *target) {
|
||||
ut64 dst = ESIL->cur;
|
||||
if ((target && dst == ntarget) || !target) {
|
||||
if (CHECKREF (dst)) {
|
||||
r_anal_ref_add (core->anal, dst, cur, 'd');
|
||||
r_anal_xrefs_set (core->anal, cur, dst, R_ANAL_REF_TYPE_DATA);
|
||||
}
|
||||
}
|
||||
// if (cfg_anal_strings) {
|
||||
@ -3974,7 +3979,7 @@ R_API void r_core_anal_esil(RCore *core, const char *str, const char *target) {
|
||||
RFlagItem *f;
|
||||
char *str;
|
||||
if (CHECKREF (dst) || CHECKREF (cur)) {
|
||||
r_anal_ref_add (core->anal, dst, cur, 'd');
|
||||
r_anal_xrefs_set (core->anal, cur, dst, R_ANAL_REF_TYPE_DATA);
|
||||
if (cfg_anal_strings) {
|
||||
add_string_ref (core, dst);
|
||||
}
|
||||
@ -3999,7 +4004,7 @@ R_API void r_core_anal_esil(RCore *core, const char *str, const char *target) {
|
||||
ut64 dst = esilbreak_last_read;
|
||||
if (dst != UT64_MAX && CHECKREF (dst)) {
|
||||
if (myvalid (mycore->io, dst)) {
|
||||
r_anal_ref_add (core->anal, dst, cur, 'd');
|
||||
r_anal_xrefs_set (core->anal, cur, dst, R_ANAL_REF_TYPE_DATA);
|
||||
if (cfg_anal_strings) {
|
||||
add_string_ref (core, dst);
|
||||
}
|
||||
@ -4008,7 +4013,7 @@ R_API void r_core_anal_esil(RCore *core, const char *str, const char *target) {
|
||||
dst = esilbreak_last_data;
|
||||
if (dst != UT64_MAX && CHECKREF (dst)) {
|
||||
if (myvalid (mycore->io, dst)) {
|
||||
r_anal_ref_add (core->anal, dst, cur, 'd');
|
||||
r_anal_xrefs_set (core->anal, cur, dst, R_ANAL_REF_TYPE_DATA);
|
||||
if (cfg_anal_strings) {
|
||||
add_string_ref (core, dst);
|
||||
}
|
||||
@ -4021,7 +4026,7 @@ R_API void r_core_anal_esil(RCore *core, const char *str, const char *target) {
|
||||
ut64 dst = op.jump;
|
||||
if (CHECKREF (dst)) {
|
||||
if (myvalid (core->io, dst)) {
|
||||
r_anal_ref_add (core->anal, dst, cur, 'c');
|
||||
r_anal_xrefs_set (core->anal, cur, dst, R_ANAL_REF_TYPE_CODE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4031,7 +4036,7 @@ R_API void r_core_anal_esil(RCore *core, const char *str, const char *target) {
|
||||
ut64 dst = op.jump;
|
||||
if (CHECKREF (dst)) {
|
||||
if (myvalid (core->io, dst)) {
|
||||
r_anal_ref_add (core->anal, dst, cur, 'C');
|
||||
r_anal_xrefs_set (core->anal, cur, dst, R_ANAL_REF_TYPE_CALL);
|
||||
}
|
||||
ESIL->old = cur + op.size;
|
||||
getpcfromstack (core, ESIL);
|
||||
@ -4055,7 +4060,7 @@ R_API void r_core_anal_esil(RCore *core, const char *str, const char *target) {
|
||||
(op.type & R_ANAL_OP_TYPE_MASK) == R_ANAL_OP_TYPE_UCALL
|
||||
? R_ANAL_REF_TYPE_CALL
|
||||
: R_ANAL_REF_TYPE_CODE;
|
||||
r_anal_ref_add (core->anal, dst, cur, ref);
|
||||
r_anal_xrefs_set (core->anal, cur, dst, ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -560,7 +560,8 @@ static const char *help_msg_ax[] = {
|
||||
"Usage:", "ax[?d-l*]", " # see also 'afx?'",
|
||||
"ax", "", "list refs",
|
||||
"ax", " addr [at]", "add code ref pointing to addr (from curseek)",
|
||||
"ax-", " [at]", "clean all refs (or refs from addr)",
|
||||
"ax-", " [at]", "clean all refs/refs from addr",
|
||||
"ax-*", "", "clean all refs/refs",
|
||||
"axc", " addr [at]", "add code jmp ref // unused?",
|
||||
"axC", " addr [at]", "add code call ref",
|
||||
"axg", " [addr]", "show xrefs graph to reach current function",
|
||||
@ -571,7 +572,6 @@ static const char *help_msg_ax[] = {
|
||||
"axF", " [flg-glob]", "find data/code references of flags",
|
||||
"axt", " [addr]", "find data/code references to this address",
|
||||
"axf", " [addr]", "find data/code references from this address",
|
||||
"axk", " [query]", "perform sdb query",
|
||||
"ax*", "", "output radare commands",
|
||||
NULL
|
||||
};
|
||||
@ -2571,7 +2571,7 @@ static int cmd_anal_fcn(RCore *core, const char *input) {
|
||||
if (fcn) {
|
||||
RAnalRef *ref;
|
||||
RListIter *iter;
|
||||
RList *refs = r_anal_fcn_get_refs (core->anal, fcn);
|
||||
RList *refs = r_anal_fcn_get_refs_sorted (core->anal, fcn);
|
||||
r_list_foreach (refs, iter, ref) {
|
||||
if (input[2] == 'j') {
|
||||
r_cons_printf ("{\"type\":\"%c\",\"from\":%"PFMT64d",\"to\":%"PFMT64d"}%s",
|
||||
@ -2602,10 +2602,11 @@ static int cmd_anal_fcn(RCore *core, const char *input) {
|
||||
ut64 a, b;
|
||||
char *mi = strdup (input);
|
||||
if (mi && mi[3] == ' ' && (p = strchr (mi + 4, ' '))) {
|
||||
RAnalRefType reftype = r_anal_xrefs_type (input[2]);
|
||||
*p = 0;
|
||||
a = r_num_math (core->num, mi + 3);
|
||||
b = r_num_math (core->num, p + 1);
|
||||
r_anal_xrefs_set (core->anal, input[2], a, b);
|
||||
r_anal_xrefs_set (core->anal, a, b, reftype);
|
||||
} else {
|
||||
r_core_cmd_help (core, help_msg_afx);
|
||||
}
|
||||
@ -2621,7 +2622,7 @@ static int cmd_anal_fcn(RCore *core, const char *input) {
|
||||
*p = 0;
|
||||
a = r_num_math (core->num, mi);
|
||||
b = r_num_math (core->num, p + 1);
|
||||
r_anal_xrefs_deln (core->anal, -1, a, b);
|
||||
r_anal_xrefs_deln (core->anal, a, b, -1);
|
||||
} else {
|
||||
eprintf ("Usage: afx- [src] [dst]\n");
|
||||
}
|
||||
@ -2687,7 +2688,7 @@ static int cmd_anal_fcn(RCore *core, const char *input) {
|
||||
if (fcn) {
|
||||
RAnalRef *ref;
|
||||
RListIter *iter;
|
||||
RList *refs = r_anal_fcn_get_refs (core->anal, fcn);
|
||||
RList *refs = r_anal_fcn_get_refs_sorted (core->anal, fcn);
|
||||
r_list_foreach (refs, iter, ref) {
|
||||
if (ref->addr == UT64_MAX) {
|
||||
//eprintf ("Warning: ignore 0x%08"PFMT64x" call 0x%08"PFMT64x"\n", ref->at, ref->addr);
|
||||
@ -2707,7 +2708,7 @@ static int cmd_anal_fcn(RCore *core, const char *input) {
|
||||
if (f) {
|
||||
RListIter *iter;
|
||||
RAnalRef *ref;
|
||||
RList *refs1 = r_anal_fcn_get_refs (core->anal, f);
|
||||
RList *refs1 = r_anal_fcn_get_refs_sorted (core->anal, f);
|
||||
r_list_foreach (refs1, iter, ref) {
|
||||
if (!r_io_is_valid_offset (core->io, ref->addr, !core->anal->opt.noncode)) {
|
||||
continue;
|
||||
@ -4748,14 +4749,14 @@ static void _anal_calls(RCore *core, ut64 addr, ut64 addr_end) {
|
||||
if (!anal_is_bad_call (core, from, to, addr, buf, bufi)) {
|
||||
fcn = r_anal_get_fcn_in (core->anal, op.jump, R_ANAL_FCN_TYPE_ROOT);
|
||||
if (!fcn) {
|
||||
r_core_anal_fcn (core, op.jump, addr, R_ANAL_REF_TYPE_NULL, depth);
|
||||
r_core_anal_fcn (core, op.jump, addr, R_ANAL_REF_TYPE_CALL, depth);
|
||||
}
|
||||
}
|
||||
#else
|
||||
// add xref here
|
||||
r_anal_xrefs_set (core->anal, R_ANAL_REF_TYPE_CALL, addr, op.jump);
|
||||
r_anal_xrefs_set (core->anal, addr, op.jump, R_ANAL_REF_TYPE_CALL);
|
||||
if (r_io_is_valid_offset (core->io, op.jump, 1)) {
|
||||
r_core_anal_fcn (core, op.jump, addr, R_ANAL_REF_TYPE_NULL, depth);
|
||||
r_core_anal_fcn (core, op.jump, addr, R_ANAL_REF_TYPE_CALL, depth);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -5086,7 +5087,7 @@ static bool cmd_anal_refs(RCore *core, const char *input) {
|
||||
RAnalRef *ref;
|
||||
char *cp_inp = strdup (input + 1);
|
||||
char *ptr = r_str_trim_head (cp_inp);
|
||||
if (!strcmp (ptr, "*")) {
|
||||
if (!strcmp (ptr, "*")) { // "ax-*"
|
||||
r_anal_xrefs_init (core->anal);
|
||||
} else {
|
||||
int n = r_str_word_set0 (ptr);
|
||||
@ -5106,14 +5107,14 @@ static bool cmd_anal_refs(RCore *core, const char *input) {
|
||||
if (list) {
|
||||
r_list_foreach (list, iter, ref) {
|
||||
if (from != UT64_MAX && from == ref->addr) {
|
||||
r_anal_ref_del (core->anal, ref->addr, ref->at);
|
||||
r_anal_xref_del (core->anal, ref->addr, ref->at);
|
||||
}
|
||||
if (from == UT64_MAX) {
|
||||
r_anal_ref_del (core->anal, ref->addr, ref->at);
|
||||
r_anal_xref_del (core->anal, ref->addr, ref->at);
|
||||
}
|
||||
}
|
||||
r_list_free (list);
|
||||
}
|
||||
r_list_free (list);
|
||||
}
|
||||
free (cp_inp);
|
||||
} break;
|
||||
@ -5128,15 +5129,6 @@ static bool cmd_anal_refs(RCore *core, const char *input) {
|
||||
sdb_free (db);
|
||||
}
|
||||
break;
|
||||
case 'k': // "axk"
|
||||
if (input[1] == '?') {
|
||||
eprintf ("Usage: axk [query]\n");
|
||||
} else if (input[1] == ' ') {
|
||||
sdb_query (core->anal->sdb_xrefs, input + 2);
|
||||
} else {
|
||||
r_core_anal_ref_list (core, 'k');
|
||||
}
|
||||
break;
|
||||
case '\0': // "ax"
|
||||
case 'j': // "axj"
|
||||
case 'q': // "axq"
|
||||
@ -5183,7 +5175,7 @@ static bool cmd_anal_refs(RCore *core, const char *input) {
|
||||
r_parse_filter (core->parser, core->flags,
|
||||
asmop.buf_asm, str, sizeof (str), core->print->big_endian);
|
||||
|
||||
r_cons_printf ("{\"from\":%" PFMT64u ",\"type\":\"%s\",\"opcode\":\"%s\"", ref->addr, r_anal_ref_to_string (ref->type), str);
|
||||
r_cons_printf ("{\"from\":%" PFMT64u ",\"type\":\"%s\",\"opcode\":\"%s\"", ref->addr, r_anal_xrefs_type_tostring (ref->type), str);
|
||||
if (fcn) {
|
||||
r_cons_printf (",\"fcn_addr\":%"PFMT64d",\"fcn_name\":\"%s\"", fcn->addr, fcn->name);
|
||||
}
|
||||
@ -5256,17 +5248,17 @@ static bool cmd_anal_refs(RCore *core, const char *input) {
|
||||
? r_str_newf ("%s; %s", fcn ? fcn->name : "(nofunc)", strtok (comment, "\n"))
|
||||
: r_str_newf ("%s", fcn ? fcn->name : "(nofunc)");
|
||||
r_cons_printf ("%s 0x%" PFMT64x " [%s] %s\n",
|
||||
buf_fcn, ref->addr, r_anal_ref_to_string (ref->type), buf_asm);
|
||||
buf_fcn, ref->addr, r_anal_xrefs_type_tostring (ref->type), buf_asm);
|
||||
free (buf_asm);
|
||||
free (buf_fcn);
|
||||
}
|
||||
}
|
||||
r_list_free (list);
|
||||
} else {
|
||||
if (input[1] == 'j') { // "axtj"
|
||||
r_cons_print ("[]\n");
|
||||
}
|
||||
}
|
||||
r_list_free (list);
|
||||
} break;
|
||||
case 'f': { // "axf"
|
||||
ut8 buf[12];
|
||||
@ -5286,7 +5278,7 @@ static bool cmd_anal_refs(RCore *core, const char *input) {
|
||||
list = list_ = r_anal_xrefs_get_from (core->anal, addr);
|
||||
if (!list) {
|
||||
RAnalFunction * fcn = r_anal_get_fcn_in (core->anal, addr, 0);
|
||||
list = r_anal_fcn_get_refs (core->anal, fcn);
|
||||
list = r_anal_fcn_get_refs_sorted (core->anal, fcn);
|
||||
}
|
||||
} else {
|
||||
list = r_anal_refs_get (core->anal, addr);
|
||||
@ -5304,7 +5296,7 @@ static bool cmd_anal_refs(RCore *core, const char *input) {
|
||||
r_asm_set_pc (core->assembler, ref->at);
|
||||
r_asm_disassemble (core->assembler, &asmop, buf, 12);
|
||||
r_cons_printf ("{\"from\":%" PFMT64d ",\"to\":%" PFMT64d ",\"type\":\"%s\",\"opcode\":\"%s\"}%s",
|
||||
ref->at, ref->addr, r_anal_ref_to_string (ref->type), asmop.buf_asm, iter->n? ",": "");
|
||||
ref->at, ref->addr, r_anal_xrefs_type_tostring (ref->type), asmop.buf_asm, iter->n? ",": "");
|
||||
}
|
||||
r_cons_print ("]\n");
|
||||
} else if (input[1] == '*') { // axf*
|
||||
@ -5342,13 +5334,12 @@ static bool cmd_anal_refs(RCore *core, const char *input) {
|
||||
free (buf_asm);
|
||||
}
|
||||
}
|
||||
r_list_free (list_);
|
||||
r_list_free (list);
|
||||
} else {
|
||||
if (input[1] == 'j') { // axfj
|
||||
r_cons_print ("[]\n");
|
||||
}
|
||||
}
|
||||
r_list_free (list);
|
||||
} break;
|
||||
case 'F':
|
||||
find_refs (core, input + 1);
|
||||
@ -5362,6 +5353,7 @@ static bool cmd_anal_refs(RCore *core, const char *input) {
|
||||
int n = r_str_word_set0 (ptr);
|
||||
ut64 at = core->offset;
|
||||
ut64 addr = UT64_MAX;
|
||||
RAnalRefType reftype = r_anal_xrefs_type (input[0]);
|
||||
switch (n) {
|
||||
case 2: // get at
|
||||
at = r_num_math (core->num, r_str_word_get0 (ptr, 1));
|
||||
@ -5373,7 +5365,7 @@ static bool cmd_anal_refs(RCore *core, const char *input) {
|
||||
free (ptr);
|
||||
return false;
|
||||
}
|
||||
r_anal_xrefs_set (core->anal, input[0], at, addr);
|
||||
r_anal_xrefs_set (core->anal, at, addr, reftype);
|
||||
free (ptr);
|
||||
}
|
||||
break;
|
||||
@ -6042,9 +6034,9 @@ static int compute_calls(RCore *core) {
|
||||
xrefs = r_anal_fcn_get_xrefs (core->anal, fcn);
|
||||
if (xrefs) {
|
||||
cov += r_list_length (xrefs);
|
||||
r_list_free (xrefs);
|
||||
xrefs = NULL;
|
||||
}
|
||||
r_list_free (xrefs);
|
||||
}
|
||||
return cov;
|
||||
}
|
||||
@ -6143,7 +6135,7 @@ void _CbInRangeAav(RCore *core, ut64 from, ut64 to, int vsize, bool asterisk, in
|
||||
r_cons_printf ("f+ aav.0x%08"PFMT64x "= 0x%08"PFMT64x, to, to);
|
||||
} else {
|
||||
#if 1
|
||||
r_anal_ref_add (core->anal, to, from, ' ');
|
||||
r_anal_xrefs_set (core->anal, from, to, R_ANAL_REF_TYPE_NULL);
|
||||
r_meta_add (core->anal, 'd', from, from + vsize, NULL);
|
||||
if (!r_flag_get_at (core->flags, to, false)) {
|
||||
char *name = r_str_newf ("aav.0x%08"PFMT64x, to);
|
||||
|
@ -1834,7 +1834,7 @@ static void do_ref_search(RCore *core, ut64 addr,ut64 from, ut64 to, struct sear
|
||||
: r_str_newf ("%s", fcn ? fcn->name : "(nofunc)");
|
||||
if (from <= ref->addr && to >= ref->addr) {
|
||||
r_cons_printf ("%s 0x%" PFMT64x " [%s] %s\n",
|
||||
buf_fcn, ref->addr, r_anal_ref_to_string (ref->type), str);
|
||||
buf_fcn, ref->addr, r_anal_xrefs_type_tostring (ref->type), str);
|
||||
if (*param->cmd_hit) {
|
||||
ut64 here = core->offset;
|
||||
r_core_seek (core, ref->addr, true);
|
||||
|
@ -327,15 +327,14 @@ static ut64 getref (RCore *core, int n, char t, int type) {
|
||||
}
|
||||
#if FCN_OLD
|
||||
if (t == 'r') {
|
||||
list = r_anal_fcn_get_refs (core->anal, fcn);
|
||||
list = r_anal_fcn_get_refs_sorted (core->anal, fcn);
|
||||
} else {
|
||||
list = r_anal_fcn_get_xrefs (core->anal, fcn);
|
||||
list = r_anal_fcn_get_xrefs_sorted (core->anal, fcn);
|
||||
}
|
||||
r_list_foreach (list, iter, r) {
|
||||
if (r->type == type) {
|
||||
if (i == n) {
|
||||
ut64 addr = r->addr;
|
||||
r_list_free (list);
|
||||
return addr;
|
||||
}
|
||||
i++;
|
||||
|
@ -1084,7 +1084,6 @@ static void ds_pre_xrefs(RDisasmState *ds, bool no_fcnlines) {
|
||||
}
|
||||
|
||||
static void ds_show_refs(RDisasmState *ds) {
|
||||
RList *list;
|
||||
RAnalRef *ref;
|
||||
RListIter *iter;
|
||||
RFlagItem *flagi, *flagat;
|
||||
@ -1092,7 +1091,8 @@ static void ds_show_refs(RDisasmState *ds) {
|
||||
if (!ds->show_cmtrefs) {
|
||||
return;
|
||||
}
|
||||
list = r_anal_xrefs_get_from (ds->core->anal, ds->at);
|
||||
RList *list = r_anal_xrefs_get_from (ds->core->anal, ds->at);
|
||||
|
||||
r_list_foreach (list, iter, ref) {
|
||||
char *cmt = r_meta_get_string (ds->core->anal, R_META_TYPE_COMMENT, ref->addr);
|
||||
flagi = r_flag_get_i (ds->core->flags, ref->addr);
|
||||
@ -1127,6 +1127,7 @@ static void ds_show_refs(RDisasmState *ds) {
|
||||
}
|
||||
ds_print_color_reset (ds);
|
||||
}
|
||||
r_list_free (list);
|
||||
}
|
||||
|
||||
static void ds_show_xrefs(RDisasmState *ds) {
|
||||
@ -1141,7 +1142,7 @@ static void ds_show_xrefs(RDisasmState *ds) {
|
||||
return;
|
||||
}
|
||||
/* show xrefs */
|
||||
RList *xrefs = r_anal_xref_get (core->anal, ds->at);
|
||||
RList *xrefs = r_anal_xrefs_get (core->anal, ds->at);
|
||||
if (!xrefs) {
|
||||
return;
|
||||
}
|
||||
@ -2636,7 +2637,7 @@ static void ds_instruction_mov_lea(RDisasmState *ds, int idx) {
|
||||
dst->reg->name, ptr, off, item?item->name: "");
|
||||
if (ds->asm_anal) {
|
||||
if (r_io_is_valid_offset (core->io, off, 0)) {
|
||||
r_anal_ref_add (core->anal, ds->addr, off, 'd');
|
||||
r_anal_xrefs_set (core->anal, off, ds->addr, R_ANAL_REF_TYPE_DATA);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2668,7 +2669,7 @@ static void ds_instruction_mov_lea(RDisasmState *ds, int idx) {
|
||||
dst->reg->name, ptr, off, item?item->name: s);
|
||||
if (ds->asm_anal) {
|
||||
if (r_io_is_valid_offset (core->io, off, 0)) {
|
||||
r_anal_ref_add (core->anal, ds->addr, ptr, 'd');
|
||||
r_anal_xrefs_set (core->anal, ptr, ds->addr, R_ANAL_REF_TYPE_DATA);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5246,7 +5247,7 @@ R_API int r_core_print_disasm_json(RCore *core, ut64 addr, ut8 *buf, int nb_byte
|
||||
{
|
||||
RAnalRef *ref;
|
||||
RListIter *iter;
|
||||
RList *xrefs = r_anal_xref_get (core->anal, at);
|
||||
RList *xrefs = r_anal_xrefs_get (core->anal, at);
|
||||
if (xrefs && !r_list_empty (xrefs)) {
|
||||
r_cons_printf (",\"xrefs\":[");
|
||||
r_list_foreach (xrefs, iter, ref) {
|
||||
|
@ -186,14 +186,6 @@ R_API int r_core_project_delete(RCore *core, const char *prjfile) {
|
||||
eprintf ("rm %s\n", path);
|
||||
}
|
||||
|
||||
//rm xrefs.sdb file
|
||||
char *xrefs_sdb = r_str_newf ("%s%s%s", prjDir, R_SYS_DIR, "xrefs.sdb");
|
||||
if (r_file_exists (xrefs_sdb)) {
|
||||
r_file_rm (xrefs_sdb);
|
||||
eprintf ("rm %s\n", xrefs_sdb);
|
||||
}
|
||||
free (xrefs_sdb);
|
||||
|
||||
//rm notes.txt file
|
||||
char *notes_txt = r_str_newf ("%s%s%s", prjDir, R_SYS_DIR, "notes.txt");
|
||||
if (r_file_exists (notes_txt)) {
|
||||
@ -810,8 +802,6 @@ R_API bool r_core_project_save(RCore *core, const char *prjName) {
|
||||
}
|
||||
projectInit (core);
|
||||
|
||||
r_anal_project_save (core->anal, prjDir);
|
||||
|
||||
Sdb *rop_db = sdb_ns (core->sdb, "rop", false);
|
||||
if (rop_db) {
|
||||
/* set filepath for all the rop sub-dbs */
|
||||
@ -829,12 +819,12 @@ R_API bool r_core_project_save(RCore *core, const char *prjName) {
|
||||
}
|
||||
r_config_set (core->config, "prj.name", prjName);
|
||||
if (r_config_get_i (core->config, "prj.simple")) {
|
||||
if (!simpleProjectSaveScript (core, scriptPath, R_CORE_PRJ_ALL ^ R_CORE_PRJ_XREFS)) {
|
||||
if (!simpleProjectSaveScript (core, scriptPath, R_CORE_PRJ_ALL)) {
|
||||
eprintf ("Cannot open '%s' for writing\n", prjName);
|
||||
ret = false;
|
||||
}
|
||||
} else {
|
||||
if (!projectSaveScript (core, scriptPath, R_CORE_PRJ_ALL ^ R_CORE_PRJ_XREFS)) {
|
||||
if (!projectSaveScript (core, scriptPath, R_CORE_PRJ_ALL)) {
|
||||
eprintf ("Cannot open '%s' for writing\n", prjName);
|
||||
ret = false;
|
||||
}
|
||||
@ -909,62 +899,11 @@ R_API char *r_core_project_notes_file(RCore *core, const char *prjName) {
|
||||
return notes_txt;
|
||||
}
|
||||
|
||||
#define DB core->anal->sdb_xrefs
|
||||
|
||||
static bool projectLoadXrefs(RCore *core, const char *prjName) {
|
||||
char *path, *db;
|
||||
|
||||
if (!prjName || !*prjName) {
|
||||
return false;
|
||||
}
|
||||
const char *prjdir = r_config_get (core->config, "dir.projects");
|
||||
|
||||
if (prjName[0] == R_SYS_DIR[0]) {
|
||||
db = r_str_newf ("%s", prjName);
|
||||
if (!db) {
|
||||
return false;
|
||||
}
|
||||
path = strdup (db);
|
||||
} else {
|
||||
db = r_str_newf ("%s" R_SYS_DIR "%s", prjdir, prjName);
|
||||
if (!db) {
|
||||
return false;
|
||||
}
|
||||
path = r_file_abspath (db);
|
||||
}
|
||||
|
||||
if (!path) {
|
||||
free (db);
|
||||
return false;
|
||||
}
|
||||
if (!r_file_is_directory (db)) {
|
||||
db = r_str_append (db, ".d");
|
||||
}
|
||||
|
||||
if (!sdb_ns_unset (core->anal->sdb, NULL, DB)) {
|
||||
sdb_free (DB);
|
||||
}
|
||||
const char *xrefs_path = r_file_fexists ("%s" R_SYS_DIR "xrefs.sdb", path)
|
||||
? "xrefs.sdb": "xrefs";
|
||||
DB = sdb_new (path, xrefs_path, 0);
|
||||
if (!DB) {
|
||||
free (db);
|
||||
free (path);
|
||||
return false;
|
||||
}
|
||||
sdb_ns_set (core->anal->sdb, "xrefs", DB);
|
||||
free (path);
|
||||
|
||||
free (db);
|
||||
return true;
|
||||
}
|
||||
|
||||
R_API bool r_core_project_load(RCore *core, const char *prjName, const char *rcpath) {
|
||||
const bool cfg_fortunes = r_config_get_i (core->config, "cfg.fortunes");
|
||||
const bool scr_interactive = r_config_get_i (core->config, "scr.interactive");
|
||||
const bool scr_prompt = r_config_get_i (core->config, "scr.prompt");
|
||||
(void) projectLoadRop (core, prjName);
|
||||
(void) projectLoadXrefs (core, prjName);
|
||||
bool ret = r_core_cmd_file (core, rcpath);
|
||||
r_config_set_i (core->config, "cfg.fortunes", cfg_fortunes);
|
||||
r_config_set_i (core->config, "scr.interactive", scr_interactive);
|
||||
|
@ -1013,7 +1013,7 @@ repeat:
|
||||
}
|
||||
r_cons_printf (" %d [%s] 0x%08"PFMT64x " %s %cREF (%s)\n",
|
||||
idx, cstr, refi->addr,
|
||||
r_anal_ref_to_string (refi->type),
|
||||
r_anal_xrefs_type_tostring (refi->type),
|
||||
xref ? 'X':' ', name);
|
||||
free (name);
|
||||
if (idx == skip) {
|
||||
|
@ -3,7 +3,7 @@
|
||||
#ifndef R2_ANAL_H
|
||||
#define R2_ANAL_H
|
||||
|
||||
#define USE_DICT 0
|
||||
#define USE_DICT 1
|
||||
|
||||
/* use sdb function storage */
|
||||
#define FCN_SDB 1
|
||||
@ -296,10 +296,6 @@ typedef struct r_anal_type_function_t {
|
||||
RList *fcn_locs; //sorted list of a function *.loc refs
|
||||
//RList *locals; // list of local labels -> moved to anal->sdb_fcns
|
||||
RList *bbs;
|
||||
#if FCN_OLD
|
||||
RList *refs;
|
||||
RList *xrefs;
|
||||
#endif
|
||||
RAnalFcnMeta meta;
|
||||
RRangeTiny bbr;
|
||||
RBNode rb;
|
||||
@ -654,14 +650,13 @@ typedef struct r_anal_t {
|
||||
struct r_anal_plugin_t *cur;
|
||||
RAnalRange *limit;
|
||||
RList *plugins;
|
||||
Sdb *sdb_xrefs;
|
||||
Sdb *sdb_types;
|
||||
Sdb *sdb_meta; // TODO: Future r_meta api
|
||||
Sdb *sdb_zigns;
|
||||
|
||||
#if USE_DICT
|
||||
dict *dict_refs;
|
||||
dict *dict_xrefs;
|
||||
SdbHash *dict_refs;
|
||||
SdbHash *dict_xrefs;
|
||||
#endif
|
||||
bool recursive_noreturn;
|
||||
RSpaces meta_spaces;
|
||||
@ -867,7 +862,7 @@ typedef enum {
|
||||
} RAnalRefType;
|
||||
|
||||
typedef struct r_anal_ref_t {
|
||||
int type;
|
||||
RAnalRefType type;
|
||||
ut64 addr;
|
||||
ut64 at;
|
||||
} RAnalRef;
|
||||
@ -1381,6 +1376,7 @@ R_API int r_anal_fcn_add_bb(RAnal *anal, RAnalFunction *fcn,
|
||||
R_API bool r_anal_check_fcn(RAnal *anal, ut8 *buf, ut16 bufsz, ut64 addr, ut64 low, ut64 high);
|
||||
R_API void r_anal_fcn_update_tinyrange_bbs(RAnalFunction *fcn);
|
||||
|
||||
|
||||
/* locals */
|
||||
#if 0
|
||||
R_API int r_anal_fcn_local_add(RAnal *anal, RAnalFunction *fcn, int index, const char *name, const char *type);
|
||||
@ -1415,7 +1411,7 @@ R_API int r_anal_fcn_split_bb(RAnal *anal, RAnalFunction *fcn, RAnalBlock *bb, u
|
||||
R_API int r_anal_fcn_bb_overlaps(RAnalFunction *fcn, RAnalBlock *bb);
|
||||
R_API RAnalVar *r_anal_fcn_get_var(RAnalFunction *fs, int num, int dir);
|
||||
R_API void r_anal_fcn_fit_overlaps (RAnal *anal, RAnalFunction *fcn);
|
||||
R_API void r_anal_trim_jmprefs(RAnalFunction *fcn);
|
||||
R_API void r_anal_trim_jmprefs(RAnal *anal, RAnalFunction *fcn);
|
||||
R_API RAnalFunction *r_anal_fcn_next(RAnal *anal, ut64 addr);
|
||||
R_API char *r_anal_fcn_to_string(RAnal *a, RAnalFunction* fs);
|
||||
R_API int r_anal_str_to_fcn(RAnal *a, RAnalFunction *f, const char *_str);
|
||||
@ -1424,38 +1420,29 @@ R_API RAnalBlock *r_anal_fcn_bbget(RAnalFunction *fcn, ut64 addr);
|
||||
R_API bool r_anal_fcn_bbadd(RAnalFunction *fcn, RAnalBlock *bb);
|
||||
R_API int r_anal_fcn_resize (const RAnal *anal, RAnalFunction *fcn, int newsize);
|
||||
|
||||
#if 0
|
||||
#define r_anal_fcn_get_refs(x) x->refs
|
||||
#define r_anal_fcn_get_xrefs(x) x->xrefs
|
||||
#define r_anal_fcn_get_vars(x) x->vars
|
||||
#define r_anal_fcn_get_bbs(x) x->bbs
|
||||
#else
|
||||
R_API int r_anal_xrefs_count(RAnal *anal);
|
||||
R_API const char *r_anal_xrefs_type_tostring (char type);
|
||||
R_API RList *r_anal_xrefs_get (RAnal *anal, ut64 to);
|
||||
R_API RList *r_anal_refs_get (RAnal *anal, ut64 to);
|
||||
R_API RList *r_anal_xrefs_get_from (RAnal *anal, ut64 from);
|
||||
R_API void r_anal_xrefs_list(RAnal *anal, int rad);
|
||||
R_API RList *r_anal_fcn_get_refs(RAnal *anal, RAnalFunction *fcn);
|
||||
R_API RList *r_anal_fcn_get_xrefs(RAnal *anal, RAnalFunction *fcn);
|
||||
R_API int r_anal_xrefs_from (RAnal *anal, RList *list, const char *kind, const RAnalRefType type, ut64 addr);
|
||||
R_API int r_anal_xrefs_set (RAnal *anal, const RAnalRefType type, ut64 from, ut64 to);
|
||||
R_API int r_anal_xrefs_deln (RAnal *anal, const RAnalRefType type, ut64 from, ut64 to);
|
||||
R_API bool r_anal_xrefs_save(RAnal *anal, const char *prjfile);
|
||||
R_API RList* r_anal_fcn_get_vars (RAnalFunction *anal);
|
||||
R_API RList* r_anal_fcn_get_bbs (RAnalFunction *anal);
|
||||
R_API RList* r_anal_get_fcns (RAnal *anal);
|
||||
#endif
|
||||
|
||||
/* ref.c */
|
||||
typedef bool (* RAnalRefCmp)(RAnalRef *ref, void *data);
|
||||
R_API RAnalRef *r_anal_ref_new(void);
|
||||
R_API RList *r_anal_ref_list_new(void);
|
||||
R_API void r_anal_ref_free(void *ref);
|
||||
R_API const char *r_anal_ref_to_string(int type);
|
||||
R_API int r_anal_ref_add(RAnal *anal, ut64 addr, ut64 at, int type);
|
||||
R_API int r_anal_ref_del(RAnal *anal, ut64 at, ut64 addr);
|
||||
R_API RList *r_anal_xref_get(RAnal *anal, ut64 addr);
|
||||
R_API RList *r_anal_ref_get(RAnal *anal, ut64 addr);
|
||||
R_API int r_anal_xrefs_count(RAnal *anal);
|
||||
R_API const char *r_anal_xrefs_type_tostring(RAnalRefType type);
|
||||
R_API RAnalRefType r_anal_xrefs_type(char ch);
|
||||
R_API RList *r_anal_xrefs_get(RAnal *anal, ut64 to);
|
||||
R_API RList *r_anal_refs_get(RAnal *anal, ut64 to);
|
||||
R_API RList *r_anal_xrefs_get_from(RAnal *anal, ut64 from);
|
||||
R_API void r_anal_xrefs_list(RAnal *anal, int rad);
|
||||
R_API RList *r_anal_fcn_get_refs(RAnal *anal, RAnalFunction *fcn);
|
||||
R_API RList *r_anal_fcn_get_xrefs(RAnal *anal, RAnalFunction *fcn);
|
||||
R_API RList *r_anal_fcn_get_refs_sorted(RAnal *anal, RAnalFunction *fcn);
|
||||
R_API RList *r_anal_fcn_get_xrefs_sorted(RAnal *anal, RAnalFunction *fcn);
|
||||
R_API int r_anal_xrefs_from(RAnal *anal, RList *list, const char *kind, const RAnalRefType type, ut64 addr);
|
||||
R_API int r_anal_xrefs_set(RAnal *anal, ut64 from, ut64 to, const RAnalRefType type);
|
||||
R_API int r_anal_xrefs_deln(RAnal *anal, ut64 from, ut64 to, const RAnalRefType type);
|
||||
R_API int r_anal_xref_del(RAnal *anal, ut64 at, ut64 addr);
|
||||
|
||||
R_API RList* r_anal_fcn_get_vars (RAnalFunction *anal);
|
||||
R_API RList* r_anal_fcn_get_bbs (RAnalFunction *anal);
|
||||
R_API RList* r_anal_get_fcns (RAnal *anal);
|
||||
|
||||
/* var.c */
|
||||
R_API void r_anal_var_access_clear (RAnal *a, ut64 var_addr, int scope, int index);
|
||||
@ -1484,7 +1471,6 @@ R_API RAnalVarAccess *r_anal_var_access_get(RAnal *anal, RAnalVar *var, ut64 fro
|
||||
R_API RAnalVar *r_anal_var_get_byname (RAnal *anal, RAnalFunction *fcn, const char* name);
|
||||
|
||||
/* project */
|
||||
R_API bool r_anal_project_save(RAnal *anal, const char *prjfile);
|
||||
R_API bool r_anal_xrefs_init (RAnal *anal);
|
||||
|
||||
#define R_ANAL_THRESHOLDFCN 0.7F
|
||||
@ -1584,9 +1570,6 @@ R_API RAnalMetaItem *r_meta_item_new(int type);
|
||||
R_API bool r_meta_deserialize_val(RAnalMetaItem *it, int type, ut64 from, const char *v);
|
||||
R_API void r_meta_print(RAnal *a, RAnalMetaItem *d, int rad, bool show_full);
|
||||
|
||||
R_API int r_anal_fcn_xref_add (RAnal *anal, RAnalFunction *fcn, ut64 at, ut64 addr, int type);
|
||||
R_API int r_anal_fcn_xref_del (RAnal *anal, RAnalFunction *fcn, ut64 at, ut64 addr, int type);
|
||||
|
||||
/* hints */
|
||||
|
||||
R_API void r_anal_build_range_on_hints (RAnal *a);
|
||||
|
Loading…
Reference in New Issue
Block a user