From 4e92945241300a7bc2cf9ef0135a236332fc36b0 Mon Sep 17 00:00:00 2001 From: condret Date: Sun, 25 Sep 2022 03:19:52 +0200 Subject: [PATCH] Instantiate RArch in anal ##arch --- libr/anal/anal.c | 2 + libr/arch/aconfig.c | 2 +- libr/arch/arch.c | 128 ++++++++++++++++++++++++++++++++++++++---- libr/core/cconfig.c | 42 ++++++++++++++ libr/include/r_anal.h | 1 + libr/include/r_arch.h | 4 ++ 6 files changed, 167 insertions(+), 12 deletions(-) diff --git a/libr/anal/anal.c b/libr/anal/anal.c index 8caed74ecb..a83157dbf1 100644 --- a/libr/anal/anal.c +++ b/libr/anal/anal.c @@ -94,6 +94,7 @@ R_API RAnal *r_anal_new(void) { anal->ht_addr_fun = ht_up_new0 (); anal->ht_name_fun = ht_pp_new0 (); anal->config = r_arch_config_new (); + anal->arch = r_arch_new (); anal->esil_goto_limit = R_ANAL_ESIL_GOTO_LIMIT; anal->opt.nopskip = true; // skip nops in code analysis anal->opt.hpskip = false; // skip `mov reg,reg` and `lea reg,[reg]` @@ -169,6 +170,7 @@ R_API void r_anal_free(RAnal *a) { r_th_lock_free (a->lock); r_interval_tree_fini (&a->meta); r_unref (a->config); + r_arch_free (a->arch); free (a->zign_path); r_list_free (a->plugins); r_rbtree_free (a->bb_tree, __block_free_rb, NULL); diff --git a/libr/arch/aconfig.c b/libr/arch/aconfig.c index cb0634d797..6cdea70809 100644 --- a/libr/arch/aconfig.c +++ b/libr/arch/aconfig.c @@ -48,7 +48,7 @@ R_API RArchConfig *r_arch_config_new(void) { // ac->free = (void (*)(void*))my_ac_free; ac->syntax = R_ARCH_SYNTAX_INTEL; r_ref_init (ac, &_ac_free); - ac->big_endian = false; + ac->endian = R_SYS_ENDIAN_NONE; r_ref (ac); return (RArchConfig *)ac; } diff --git a/libr/arch/arch.c b/libr/arch/arch.c index f763dbd946..ef4ece9035 100644 --- a/libr/arch/arch.c +++ b/libr/arch/arch.c @@ -40,7 +40,7 @@ R_API RArch *r_arch_new(void) { return a; } -static char *_find_bestmatch(RList *plugins, RArchConfig *cfg) { +static ut32 _rate_compat(RArchPlugin *p, RArchConfig *cfg) { ut32 bits; switch (cfg->bits) { case 64: @@ -67,21 +67,26 @@ static char *_find_bestmatch(RList *plugins, RArchConfig *cfg) { default: bits = UT32_MAX; } + ut32 score = 0; + if (!strcmp (p->arch, cfg->arch)) { + score = 50; + } + if (p->bits & bits) { + score += (!!score) * 30; + } + if (p->endian & cfg->endian) { + score += (!!score) * 20; + } + return score; +} + +static char *_find_bestmatch(RList *plugins, RArchConfig *cfg) { ut8 best_score = 0; char *name = NULL; RListIter *iter; RArchPlugin *p; r_list_foreach (plugins, iter, p) { - ut32 score = 0; - if (!strcmp (p->arch, cfg->arch)) { - score = 50; - } - if (p->bits & bits) { - score += (!!score) * 30; - } - if (p->endian & cfg->endian) { - score += (!!score) * 20; - } + const ut32 score = _rate_compat (p, cfg); if (score > best_score) { best_score = score; name = p->name; @@ -112,6 +117,104 @@ R_API bool r_arch_use(RArch *arch, RArchConfig *config) { return true; } +R_API bool r_arch_set_bits(RArch *arch, ut32 bits) { + r_return_val_if_fail (arch && bits, false); + if (!arch->cfg) { + arch->cfg = r_arch_config_new (); + if (!arch->cfg) { + return false; + } + arch->cfg->bits = bits; + if (!r_arch_use (arch, arch->cfg)) { + r_unref (arch->cfg); + arch->cfg = NULL; + return false; + } + } + if (arch->autoselect) { + if (arch->current) { + const ut32 score = _rate_compat (arch->current->p, arch->cfg); + arch->cfg->bits = bits; + if (!score || score > _rate_compat (arch->current->p, arch->cfg)) { + return r_arch_use (arch, arch->cfg); + } + return true; + } + arch->cfg->bits = bits; + return r_arch_use (arch, arch->cfg); + } + arch->cfg->bits = bits; + return true; +} + +R_API bool r_arch_set_endian(RArch *arch, ut32 endian) { + r_return_val_if_fail (arch, false); + if (!arch->cfg) { + arch->cfg = r_arch_config_new (); + if (!arch->cfg) { + return false; + } + arch->cfg->endian = endian; + if (!r_arch_use (arch, arch->cfg)) { + r_unref (arch->cfg); + arch->cfg = NULL; + return false; + } + } + if (arch->autoselect) { + if (arch->current) { + const ut32 score = _rate_compat (arch->current->p, arch->cfg); + arch->cfg->endian = endian; + if (!score || score > _rate_compat (arch->current->p, arch->cfg)) { + return r_arch_use (arch, arch->cfg); + } + return true; + } + arch->cfg->endian = endian; + return r_arch_use (arch, arch->cfg); + } + arch->cfg->bits = endian; + return true; +} + +R_API bool r_arch_set_arch(RArch *arch, char *archname) { + r_return_val_if_fail (arch && archname, false); + char *_arch = strdup (archname); + if (!_arch) { + return false; + } + if (!arch->cfg) { + arch->cfg = r_arch_config_new (); + if (!arch->cfg) { + free (_arch); + return false; + } + arch->cfg->arch = _arch; + if (!r_arch_use (arch, arch->cfg)) { + r_unref (arch->cfg); + arch->cfg = NULL; + return false; + } + } + if (arch->autoselect) { + if (arch->current) { + const ut32 score = _rate_compat (arch->current->p, arch->cfg); + free (arch->cfg->arch); + arch->cfg->arch = _arch; + if (!score || score > _rate_compat (arch->current->p, arch->cfg)) { + return r_arch_use (arch, arch->cfg); + } + return true; + } + free (arch->cfg->arch); + arch->cfg->arch = _arch; + return r_arch_use (arch, arch->cfg); + } + free (arch->cfg->arch); + arch->cfg->arch = _arch; + return true; +} + R_API bool r_arch_add(RArch *a, RArchPlugin *ap) { r_return_val_if_fail (a && ap->name && ap->arch, false); return !!r_list_append (a->plugins, ap); @@ -149,5 +252,8 @@ R_API void r_arch_free(RArch *a) { r_return_if_fail (a); ht_pp_free (a->decoders); r_list_free (a->plugins); + if (a->cfg) { + r_unref (a->cfg); + } free (a); } diff --git a/libr/core/cconfig.c b/libr/core/cconfig.c index eb039cda9f..9e266f46e6 100644 --- a/libr/core/cconfig.c +++ b/libr/core/cconfig.c @@ -493,6 +493,44 @@ static bool cb_analarch(void *user, void *data) { return false; } +static void update_archdecoder_options(RCore *core, RConfigNode *node) { + r_return_if_fail (core && core->anal && core->anal->arch && node); + r_config_node_purge_options (node); + RListIter *it; + RArchPlugin *p; + r_list_foreach (core->anal->arch->plugins, it, p) { + if (p->name) { + SETOPTIONS (node, p->name, NULL); + } + } +} + +static bool cb_archdecoder(void *user, void *data) { + RCore *core = (RCore*) user; + r_return_val_if_fail (core && core->anal && core->anal->arch, false); + RConfigNode *node = (RConfigNode*) data; + if (*node->value == '?') { + update_archdecoder_options (core, node); + print_node_options (node); + return false; + } + if (*node->value) { + if (r_arch_use_decoder (core->anal->arch, node->value)) { + return true; + } + R_LOG_ERROR ("arch.decoder: cannot find '%s'", node->value); + } + return false; +} + +static bool cb_archautoselect(void *user, void *data) { + RCore *core = (RCore*) user; + r_return_val_if_fail (core && core->anal && core->anal->arch, false); + RConfigNode *node = (RConfigNode*) data; + core->anal->arch->autoselect = node->i_value; + return true; +} + #if 0 static bool cb_analcpu(void *user, void *data) { RCore *core = (RCore *) user; @@ -3395,6 +3433,10 @@ R_API int r_core_config_init(RCore *core) { SETCB ("anal.recont", "false", &cb_analrecont, "end block after splitting a basic block instead of error"); // testing SETCB ("anal.jmp.indir", "false", &cb_analijmp, "follow the indirect jumps in function analysis"); // testing SETI ("anal.ptrdepth", 3, "maximum number of nested pointers to follow in analysis"); + n = NODECB ("arch.decoder", "null", &cb_archdecoder); + SETDESC (n, "select the instruction decoder to use"); + update_archdecoder_options (core, n); + SETCB ("arch.autoselect", "false", &cb_archautoselect, "automagically select matching decoder on arch related config changes (has no effect atm)"); SETICB ("asm.lines.maxref", 0, &cb_analmaxrefs, "maximum number of reflines to be analyzed and displayed in asm.lines with pd"); SETCB ("anal.jmp.tbl", "true", &cb_anal_jmptbl, "analyze jump tables in switch statements"); diff --git a/libr/include/r_anal.h b/libr/include/r_anal.h index dd501b160f..e9f79622a1 100644 --- a/libr/include/r_anal.h +++ b/libr/include/r_anal.h @@ -626,6 +626,7 @@ typedef struct r_anal_t { struct r_anal_esil_t *esil; struct r_anal_plugin_t *cur; struct r_anal_esil_plugin_t *esil_cur; // ??? + RArch *arch; RAnalRange *limit; // anal.from, anal.to RList *plugins; // anal plugins RList *esil_plugins; diff --git a/libr/include/r_arch.h b/libr/include/r_arch.h index e0ec4c2155..f588d5065e 100644 --- a/libr/include/r_arch.h +++ b/libr/include/r_arch.h @@ -334,6 +334,7 @@ typedef struct r_arch_t { RArchDecoder *current; //currently used decoder HtPP *decoders; //as decoders instantiated plugins RArchConfig *cfg; //config + bool autoselect; } RArch; typedef struct r_arch_plugin_t { @@ -372,6 +373,9 @@ R_API bool r_arch_set_reg_profile(RArch *arch, const char *dname, struct r_reg_t // arch.c R_API RArch *r_arch_new(void); R_API bool r_arch_use(RArch *arch, RArchConfig *config); +R_API bool r_arch_set_bits(RArch *arch, ut32 bits); +R_API bool r_arch_set_endian(RArch *arch, ut32 endian); +R_API bool r_arch_set_arch(RArch *arch, char *archname); R_API bool r_arch_add(RArch *arch, RArchPlugin *ap); R_API bool r_arch_del(RArch *arch, const char *name); R_API void r_arch_free(RArch *arch);