diff --git a/libr/anal/anal.c b/libr/anal/anal.c index 3bb92f8225..2998420361 100644 --- a/libr/anal/anal.c +++ b/libr/anal/anal.c @@ -75,6 +75,7 @@ R_API RAnal *r_anal_new() { RAnal *anal = R_NEW0 (RAnal); if (!anal) return NULL; anal->os = strdup (R_SYS_OS); + anal->noreturn = r_list_newf ((RListFree)&r_anal_noreturn_free); anal->reflines = anal->reflines2 = NULL; anal->esil_goto_limit = R_ANAL_ESIL_GOTO_LIMIT; anal->limit = NULL; @@ -132,6 +133,7 @@ R_API RAnal *r_anal_free(RAnal *a) { /* TODO: Free anals here */ R_FREE (a->cpu); r_list_free (a->plugins); + r_list_free (a->noreturn); a->fcns->free = r_anal_fcn_free; r_list_free (a->fcns); r_space_fini (&a->meta_spaces); @@ -404,3 +406,93 @@ R_API int r_anal_archinfo(RAnal *anal, int query) { } return -1; } + +R_API void r_anal_noreturn_free(RAnalNoreturn *nr) { + free (nr->name); + free (nr); +} + +R_API void r_anal_noreturn_list(RAnal *anal, int mode) { + RListIter *iter; + RAnalNoreturn *nr; + r_list_foreach (anal->noreturn, iter, nr) { + switch (mode) { + case 1: + case '*': + case 'r': + if (nr->name) anal->cb_printf ("ann %s\n", nr->name); + else anal->cb_printf ("0x%08"PFMT64x"\n", nr->addr); + break; + default: + if (nr->name) anal->cb_printf ("%s\n", nr->name); + else anal->cb_printf ("0x%08"PFMT64x"\n", nr->addr); + break; + } + } +} + +R_API bool r_anal_noreturn_add(RAnal *anal, const char *name, ut64 addr) { + RAnalNoreturn *nr = R_NEW0(RAnalNoreturn); + if (!nr) return false; + if (name && *name) nr->name = strdup (name); + nr->addr = addr; + if (!nr->name && !nr->addr) { + free (nr); + return false; + } + r_list_append (anal->noreturn, nr); + return true; +} + +R_API int r_anal_noreturn_drop(RAnal *anal, const char *expr) { + bool ret = false; + if (!strcmp (expr, "*")) { + if (!r_list_empty (anal->noreturn)) { + r_list_free (anal->noreturn); + anal->noreturn = r_list_newf ((RListFree)&r_anal_noreturn_free); + ret = true; + } + } else { + RListIter *iter, *iter2; + RAnalNoreturn *nr; + if (!strncmp (expr, "0x", 2)) { + ut64 n = r_num_math (NULL, expr); + r_list_foreach_safe (anal->noreturn, iter, iter2, nr) { + if (nr->addr == n) { + r_list_delete (anal->noreturn, iter); + ret = true; + } + } + } else { + r_list_foreach_safe (anal->noreturn, iter, iter2, nr) { + if (r_str_glob (nr->name, expr)) { + r_list_delete (anal->noreturn, iter); + ret = true; + } + } + } + } + return ret; +} + +R_API bool r_anal_noreturn_at(RAnal *anal, ut64 addr) { + RListIter *iter; + RAnalNoreturn *nr; + RAnalFunction *f = r_anal_get_fcn_at (anal, addr, 0); + RFlagItem *fi = anal->flb.get_at (anal->flb.f, addr); + r_list_foreach (anal->noreturn, iter, nr) { + if (nr->name) { + RFlagItem *fi2 = anal->flb.get (anal->flb.f, nr->name); + if (fi2 && fi2->offset == addr) + return true; + if (f && !strcmp (f->name, nr->name)) + return true; + if (fi && fi->name && !strcmp (fi->name, nr->name)) + return true; + } else { + if (addr == nr->addr) + return true; + } + } + return false; +} diff --git a/libr/anal/fcn.c b/libr/anal/fcn.c index ce0044dfcb..c6a04ff21c 100644 --- a/libr/anal/fcn.c +++ b/libr/anal/fcn.c @@ -448,6 +448,11 @@ repeat: } break; case R_ANAL_OP_TYPE_JMP: + if (r_anal_noreturn_at (anal, op.jump)) { + FITFCNSZ (); + r_anal_op_fini (&op); + return R_ANAL_RET_END; + } if (anal->opt.eobjmp) { FITFCNSZ(); op.jump = UT64_MAX; @@ -583,6 +588,11 @@ repeat: break; case R_ANAL_OP_TYPE_CCALL: case R_ANAL_OP_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); diff --git a/libr/core/cmd_anal.c b/libr/core/cmd_anal.c index 939de7aa2a..0b9607ba47 100644 --- a/libr/core/cmd_anal.c +++ b/libr/core/cmd_anal.c @@ -1991,6 +1991,52 @@ static void cmd_anal_esil(RCore *core, const char *input) { } } +static void cmd_anal_noreturn(RCore *core, const char *input) { + const char* help_msg[] = { + "Usage:", "an [-][0xaddr|symname]", " manage no-return marks", + "an[a]", " 0x3000", "stop function analysis if call/jmp to this address", + "an[n]", " sym.imp.exit", "same as above but for flag/fcn names", + "an", "-*", "remove all no-return references", + "an", "", "list them all", + "ao*", "", "display opcode in r commands", + NULL}; + switch (input[0]) { + case '-': + r_anal_noreturn_drop (core->anal, input+1); + break; + case ' ': + if (input[1] == '0' && input[2] == 'x') { + r_anal_noreturn_add (core->anal, NULL, + r_num_math (core->num, input+1)); + } else { + r_anal_noreturn_add (core->anal, input+1, + r_num_math (core->num, input+1)); + } + break; + case 'a': + if (input[1] == ' ') { + r_anal_noreturn_add (core->anal, NULL, + r_num_math (core->num, input+1)); + } else r_core_cmd_help (core, help_msg); + break; + case 'n': + if (input[1] == ' ') { + } else r_core_cmd_help (core, help_msg); + break; + case '*': + case 'r': + r_anal_noreturn_list (core->anal, 1); + break; + case 0: + r_anal_noreturn_list (core->anal, 0); + break; + default: + case '?': + r_core_cmd_help (core, help_msg); + break; + } +} + static void cmd_anal_opcode(RCore *core, const char *input) { int l, len = core->blocksize; ut32 tbs = core->blocksize; @@ -3099,6 +3145,7 @@ static int cmd_anal(void *data, const char *input) { "ah", "[?lba-]", "analysis hints (force opcode size, ...)", "ai", " [addr]", "address information (show perms, stack, heap, ...)", "ao", "[e?] [len]", "analyze Opcodes (or emulate it)", + "an", "[an-] [...]", "manage no-return addresses/symbols/functions", "ar", "", "like 'dr' but for the esil vm. (registers)", "ax", "[?ld-*]", "manage refs/xrefs (see also afx?)", "as", " [num]", "analyze syscall using dbg.reg", @@ -3123,6 +3170,7 @@ static int cmd_anal(void *data, const char *input) { case 'r': cmd_anal_reg (core, input+1); break; // "ar" case 'e': cmd_anal_esil (core, input+1); break; // "ae" case 'o': cmd_anal_opcode (core, input+1); break; + case 'n': cmd_anal_noreturn (core, input+1); break; // "an" case 'F': r_core_anal_fcn (core, core->offset, UT64_MAX, R_ANAL_REF_TYPE_NULL, 1); break; diff --git a/libr/flags/flags.c b/libr/flags/flags.c index b81a38f0c1..0123b9c712 100644 --- a/libr/flags/flags.c +++ b/libr/flags/flags.c @@ -622,6 +622,7 @@ R_API const char *r_flag_color(RFlag *f, RFlagItem *it, const char *color) { R_API int r_flag_bind (RFlag *f, RFlagBind *fb) { fb->f = f; fb->get = r_flag_get; + fb->get_at = r_flag_get_at; fb->set = r_flag_set; fb->set_fs = r_flag_space_set; return 0; diff --git a/libr/include/r_anal.h b/libr/include/r_anal.h index 0c4caacff0..08cfb60a43 100644 --- a/libr/include/r_anal.h +++ b/libr/include/r_anal.h @@ -634,6 +634,7 @@ typedef struct r_anal_t { RAnalOptions opt; RList *reflines; RList *reflines2; + RList *noreturn; } RAnal; typedef struct r_anal_hint_t { @@ -927,7 +928,13 @@ typedef struct r_anal_reil { char pc[8]; } RAnalReil; -#define ESIL_INTERNAL_PREFIX '$' //must be a char +typedef struct r_anal_noreturn_t { + char *name; + ut64 addr; +} RAnalNoreturn; + +// must be a char +#define ESIL_INTERNAL_PREFIX '$' #define ESIL struct r_anal_esil_t typedef struct r_anal_esil_callbacks_t { @@ -1476,6 +1483,12 @@ R_API void r_anal_unset_limits(RAnal *anal); /* ESIL to REIL */ R_API int r_anal_esil_to_reil_setup (RAnalEsil *esil, RAnal *anal, int romem, int stats); +/* no-return stuff */ +R_API void r_anal_noreturn_list(RAnal *anal, int mode); +R_API void r_anal_noreturn_free(RAnalNoreturn *nr); +R_API bool r_anal_noreturn_add(RAnal *anal, const char *name, ut64 addr); +R_API int r_anal_noreturn_drop(RAnal *anal, const char *expr); + /* plugin pointers */ extern RAnalPlugin r_anal_plugin_null; extern RAnalPlugin r_anal_plugin_csr; diff --git a/libr/include/r_flags.h b/libr/include/r_flags.h index 77ce89d9bd..dab8fd31a1 100644 --- a/libr/include/r_flags.h +++ b/libr/include/r_flags.h @@ -60,6 +60,7 @@ typedef struct r_flag_t { #include // compile time line, no linkage needed typedef RFlagItem* (*RFlagGet)(RFlag *f, const char *name); +typedef RFlagItem* (*RFlagGetAt)(RFlag *f, ut64 addr); typedef RFlagItem* (*RFlagSet)(RFlag *f, const char *name, ut64 addr, ut32 size, int dup); typedef int (*RFlagSetSpace)(RFlag *f, const char *name); @@ -67,6 +68,7 @@ typedef struct r_flag_bind_t { int init; RFlag *f; RFlagGet get; + RFlagGetAt get_at; RFlagSet set; RFlagSetSpace set_fs; } RFlagBind;