r_anal_esil_dfg_lemon_const_folder

This commit is contained in:
condret 2020-08-11 13:06:39 +02:00
parent fbdc4f16dd
commit 87dd695d2b
2 changed files with 163 additions and 47 deletions

View File

@ -17,6 +17,11 @@ typedef struct r_anal_esil_dfg_filter_t {
Sdb *results;
} RAnalEsilDFGFilter;
typedef struct r_anal_esil_dfg_const_reducer_t {
RAnalEsilDFGFilter filter;
RContRBTree *const_result_gnodes;
} RAnalEsilDFGConstReducer;
// TODO: simple const propagation - use node->type of srcs to propagate consts of pushed vars
R_API RAnalEsilDFGNode *r_anal_esil_dfg_node_new(RAnalEsilDFG *edf, const char *c) {
@ -26,14 +31,14 @@ R_API RAnalEsilDFGNode *r_anal_esil_dfg_node_new(RAnalEsilDFG *edf, const char *
return ret;
}
static void _dfg_node_free (RAnalEsilDFGNode *free_me) {
static void _dfg_node_free(RAnalEsilDFGNode *free_me) {
if (free_me) {
r_strbuf_free (free_me->content);
free (free_me);
}
}
static int _rv_del_alloc_cmp (void *incoming, void *in, void *user) {
static int _rv_del_alloc_cmp(void *incoming, void *in, void *user) {
EsilDFGRegVar *rv_incoming = (EsilDFGRegVar *)incoming;
EsilDFGRegVar *rv_in = (EsilDFGRegVar *)in;
RAnalEsilDFG *dfg = (RAnalEsilDFG *)user;
@ -173,13 +178,13 @@ static int _rv_del_alloc_cmp (void *incoming, void *in, void *user) {
return -1;
}
static int _rv_ins_cmp (void *incoming, void *in, void *user) {
static int _rv_ins_cmp(void *incoming, void *in, void *user) {
EsilDFGRegVar *rv_incoming = (EsilDFGRegVar *)incoming;
EsilDFGRegVar *rv_in = (EsilDFGRegVar *)in;
return rv_incoming->from - rv_in->from;
}
static bool _edf_reg_set (RAnalEsilDFG *dfg, const char *reg, RGraphNode *node) {
static bool _edf_reg_set(RAnalEsilDFG *dfg, const char *reg, RGraphNode *node) {
r_return_val_if_fail (dfg && !dfg->malloc_failed && reg, false);
const ut32 _reg_strlen = 4 + strlen (reg);
char *_reg = R_NEWS0 (char, _reg_strlen + 1);
@ -229,7 +234,7 @@ static bool _edf_reg_set (RAnalEsilDFG *dfg, const char *reg, RGraphNode *node)
return true;
}
static int _rv_find_cmp (void *incoming, void *in, void *user) {
static int _rv_find_cmp(void *incoming, void *in, void *user) {
EsilDFGRegVar *rv_incoming = (EsilDFGRegVar *)incoming;
EsilDFGRegVar *rv_in = (EsilDFGRegVar *)in;
@ -352,7 +357,6 @@ static RGraphNode *_edf_origin_reg_get(RAnalEsilDFG *dfg, const char *reg) {
return origin_reg_node;
}
static RGraphNode *_edf_reg_get(RAnalEsilDFG *dfg, const char *reg) {
r_return_val_if_fail (dfg && reg, NULL);
const ut32 _reg_strlen = 4 + strlen (reg);
@ -422,7 +426,7 @@ static RGraphNode *_edf_reg_get(RAnalEsilDFG *dfg, const char *reg) {
}
reg_node = NULL; // is this needed?
if (dfg->malloc_failed) {
while (!r_queue_is_empty(dfg->todo)) {
while (!r_queue_is_empty (dfg->todo)) {
free (r_queue_dequeue (dfg->todo));
goto beach;
}
@ -433,8 +437,7 @@ static RGraphNode *_edf_reg_get(RAnalEsilDFG *dfg, const char *reg) {
case 1:
reg_node = r_queue_dequeue (parts);
break;
default:
{
default: {
RAnalEsilDFGNode *_reg_node = r_anal_esil_dfg_node_new (dfg, "merge to ");
if (!_reg_node) {
while (!r_queue_is_empty (dfg->todo)) {
@ -456,7 +459,7 @@ static RGraphNode *_edf_reg_get(RAnalEsilDFG *dfg, const char *reg) {
}
}
do {
r_graph_add_edge (dfg->flow, r_queue_dequeue(parts), reg_node);
r_graph_add_edge (dfg->flow, r_queue_dequeue (parts), reg_node);
} while (!r_queue_is_empty (parts));
break;
}
@ -465,8 +468,7 @@ beach:
return reg_node;
}
static bool _edf_var_set (RAnalEsilDFG *dfg, const char *var, RGraphNode *node) {
static bool _edf_var_set(RAnalEsilDFG *dfg, const char *var, RGraphNode *node) {
r_return_val_if_fail (dfg && var, false);
const ut32 _var_strlen = 4 + strlen (var);
char *_var = R_NEWS0 (char, _var_strlen + 1);
@ -480,8 +482,7 @@ static bool _edf_var_set (RAnalEsilDFG *dfg, const char *var, RGraphNode *node)
return ret;
}
static RGraphNode *_edf_var_get (RAnalEsilDFG *dfg, const char *var) {
static RGraphNode *_edf_var_get(RAnalEsilDFG *dfg, const char *var) {
r_return_val_if_fail (dfg && var, NULL);
const ut32 _var_strlen = 4 + strlen (var);
char *_var = R_NEWS0 (char, _var_strlen + 1);
@ -712,7 +713,7 @@ static bool edf_consume_1_push_1(RAnalEsil *esil) {
src_node = _edf_var_get (edf, src);
// cannot fail, bc src cannot be NULL
RAnalEsilDFGNode *ec_node = (RAnalEsilDFGNode *)src_node->data;
const_result = (eop->type == R_ANAL_ESIL_OP_TYPE_MATH) & !!(ec_node->type & R_ANAL_ESIL_DFG_BLOCK_CONST);
const_result = (eop_type == R_ANAL_ESIL_OP_TYPE_MATH) & !!(ec_node->type & R_ANAL_ESIL_DFG_BLOCK_CONST);
}
free (src);
@ -765,7 +766,7 @@ static bool edf_consume_2_set_mem(RAnalEsil *esil) {
if (!dst_node) {
dst_node = _edf_var_get (edf, dst);
}
//probably dead code
//probably dead code
if (!dst_node) {
if (dst_type == R_ANAL_ESIL_PARM_REG) {
RGraphNode *n_reg = r_graph_add_node (edf->flow, r_anal_esil_dfg_node_new (edf, dst));
@ -911,9 +912,9 @@ R_API RAnalEsilDFG *r_anal_esil_dfg_new(RReg *regs) {
return NULL;
}
// this is not exactly necessary
// could use RReg-API directly in the dfg gen,
// but sdb as transition table is probably faster
// this is not exactly necessary
// could use RReg-API directly in the dfg gen,
// but sdb as transition table is probably faster
RRegItem *ri;
RListIter *ator;
r_list_foreach (regs->allregs, ator, ri) {
@ -1013,9 +1014,16 @@ static int _dfg_node_filter_insert_cmp(void *incoming, void *in, void *user) {
return incoming_node->idx - in_node->idx;
}
static void _dfg_rev_dfs_cb(RGraphNode *n, RGraphVisitor *vi) {
static int _dfg_gnode_reducer_insert_cmp(void *incoming, void *in, void *user) {
RGraphNode *incoming_gnode = (RGraphNode *)incoming;
RGraphNode *in_gnode = (RGraphNode *)in;
RAnalEsilDFGNode *incoming_node = (RAnalEsilDFGNode *)incoming_gnode->data;
RAnalEsilDFGNode *in_node = (RAnalEsilDFGNode *)in_gnode->data;
return in_node->idx - incoming_node->idx;
}
static void _dfg_filter_rev_dfs(RGraphNode *n, RAnalEsilDFGFilter *filter) {
RAnalEsilDFGNode *node = (RAnalEsilDFGNode *)n->data;
RAnalEsilDFGFilter *filter = (RAnalEsilDFGFilter *)vi->data;
switch (node->type) {
case R_ANAL_ESIL_DFG_BLOCK_CONST:
case R_ANAL_ESIL_DFG_BLOCK_VAR:
@ -1025,7 +1033,7 @@ static void _dfg_rev_dfs_cb(RGraphNode *n, RGraphVisitor *vi) {
r_rbtree_cont_insert (filter->tree, node, _dfg_node_filter_insert_cmp, NULL);
break;
case R_ANAL_ESIL_DFG_BLOCK_RESULT: // outnode must be result generator here
{
case R_ANAL_ESIL_DFG_BLOCK_RESULT | R_ANAL_ESIL_DFG_BLOCK_CONST: {
RGraphNode *previous = (RGraphNode *)r_list_get_top (n->in_nodes);
if (previous) {
sdb_ptr_set (filter->results, r_strbuf_get (node->content), previous, 0);
@ -1034,6 +1042,21 @@ static void _dfg_rev_dfs_cb(RGraphNode *n, RGraphVisitor *vi) {
}
}
static void _dfg_filter_rev_dfs_cb(RGraphNode *n, RGraphVisitor *vi) {
_dfg_filter_rev_dfs (n, (RAnalEsilDFGFilter *)vi->data);
}
static void _dfg_const_reducer_rev_dfs_cb(RGraphNode *n, RGraphVisitor *vi) {
RAnalEsilDFGConstReducer *reducer = (RAnalEsilDFGConstReducer *)vi->data;
RAnalEsilDFGNode *enode = (RAnalEsilDFGNode *)n->data;
_dfg_filter_rev_dfs (n, &reducer->filter);
r_queue_enqueue (reducer->filter.dfg->todo, n);
if (enode->type == (R_ANAL_ESIL_DFG_BLOCK_CONST | R_ANAL_ESIL_DFG_BLOCK_RESULT)) {
// n can only exist in the tree, if it is a const-result
r_rbtree_cont_delete (reducer->const_result_gnodes, n, _dfg_gnode_reducer_insert_cmp, NULL);
}
}
static char *condrets_strtok(char *str, const char tok) {
if (!str) {
return NULL;
@ -1075,6 +1098,98 @@ static RStrBuf *get_resolved_expr(RAnalEsilDFGFilter *filter, RAnalEsilDFGNode *
return res;
}
R_API void r_anal_esil_dfg_fold_const(RAnal *anal, RAnalEsilDFG *dfg) {
// sorted RContRBTree for graph-nodes that contain edf-nodes with const-result as type
RAnalEsilDFGConstReducer reducer = { { dfg, NULL, NULL }, r_rbtree_cont_new () };
RListIter *iter;
RGraphNode *gnode;
r_list_foreach (dfg->flow->nodes, iter, gnode) {
RAnalEsilDFGNode *enode = (RAnalEsilDFGNode *)gnode->data;
// insert const-result-nodes into the tree
// sort key is enode->idx
if (enode->type == (R_ANAL_ESIL_DFG_BLOCK_CONST | R_ANAL_ESIL_DFG_BLOCK_RESULT)) {
r_rbtree_cont_insert (reducer.const_result_gnodes, gnode, _dfg_gnode_reducer_insert_cmp, NULL);
}
}
RAnalEsil *esil = r_anal_esil_new (4096, 0, 1);
r_anal_esil_setup (esil, anal, 1, 0, 0);
RGraphVisitor vi = { _dfg_const_reducer_rev_dfs_cb, NULL, NULL, NULL, NULL, &reducer };
while ((gnode = (RGraphNode *)r_rbtree_cont_first (reducer.const_result_gnodes))) {
// filter, remove gnodes from const-result-tree
// during rdfs, run in esil, replace subtree with
// const-nodes and fix str-reference if outnode exists
// filter
reducer.filter.tree = r_rbtree_cont_new ();
reducer.filter.results = sdb_new0 (); // I guess this can be done better
r_graph_dfs_node_reverse (dfg->flow, gnode, &vi);
// ok, so gnode here cannot contain a generative node, only const-results
// get_resolved_expr expects a generative node
// the predecessor of a const-result node is always a generative node
RGraphNode *previous_gnode = (RGraphNode *)r_list_get_top (gnode->in_nodes);
// it can never be NULL
RAnalEsilDFGNode *enode = (RAnalEsilDFGNode *)previous_gnode->data;
RStrBuf *filtered = get_resolved_expr (&reducer.filter, enode);
{
char *sanitized = r_str_replace (r_str_replace (strdup (r_strbuf_get (filtered)), ",,", ",", 1), ",,", ",", 1);
r_strbuf_set (filtered, (sanitized[0] == ',') ? &sanitized[1] : sanitized);
free (sanitized);
}
r_rbtree_cont_free (reducer.filter.tree);
sdb_free (reducer.filter.results);
// running filtered const-expression in esil
r_anal_esil_parse (esil, r_strbuf_get (filtered));
char *reduced_const = r_anal_esil_pop (esil);
r_strbuf_free (filtered);
// this part needs some explanation:
// in _dfg_const_reducer_rev_dfs_cb all nodes that are traversed during
// reverse dfs are enqueued in dfg->todo. reverse dfs in this context
// ALWAYS starts with a const-result-node. Result-nodes ALWAYS have a
// generative node as predecessor, which represent to operation.
// An operation in esil, with the exception of $z and some custom operations,
// have at least one operand, which is represented by at least one node in the dfg.
// As a consequence of this, we can safely dequeue 2 nodes from the dfg->todo
// without any checks and reuse them
gnode = (RGraphNode *)r_queue_dequeue (dfg->todo);
enode = (RAnalEsilDFGNode *)gnode->data;
RGraphNode *next_gnode = (RGraphNode *)r_list_get_top (gnode->out_nodes);
if (next_gnode) {
// Cannot assume that there is another operation
// Fix string reference
RAnalEsilDFGNode *next_enode = (RAnalEsilDFGNode *)next_gnode->data;
char *fixed = r_str_replace (strdup (r_strbuf_get (next_enode->content)),
r_strbuf_get (enode->content), reduced_const, 0);
r_strbuf_set (next_enode->content, fixed);
free (fixed);
}
// replace subtree with const-nodes
r_strbuf_setf (enode->content, "%s:const_%d", reduced_const, enode->idx);
gnode = (RGraphNode *)r_queue_dequeue (dfg->todo);
enode = (RAnalEsilDFGNode *)gnode->data;
r_strbuf_set (enode->content, reduced_const);
free (reduced_const);
while (!r_queue_is_empty (dfg->todo)) {
gnode = (RGraphNode *)r_queue_dequeue (dfg->todo);
enode = (RAnalEsilDFGNode *)gnode->data;
_dfg_node_free (enode);
r_graph_del_node (dfg->flow, gnode);
}
}
r_anal_esil_free (esil);
r_rbtree_cont_free (reducer.const_result_gnodes);
}
R_API RStrBuf *r_anal_esil_dfg_filter(RAnalEsilDFG *dfg, const char *reg) {
if (!dfg || !reg) {
return NULL;
@ -1087,7 +1202,7 @@ R_API RStrBuf *r_anal_esil_dfg_filter(RAnalEsilDFG *dfg, const char *reg) {
// allocate stuff
RAnalEsilDFGFilter filter = { dfg, r_rbtree_cont_new (), sdb_new0 () };
RStrBuf *filtered = r_strbuf_new ("");
RGraphVisitor vi = { _dfg_rev_dfs_cb, NULL, NULL, NULL, NULL, &filter };
RGraphVisitor vi = { _dfg_filter_rev_dfs_cb, NULL, NULL, NULL, NULL, &filter };
// dfs the graph starting at node of esp-register
r_graph_dfs_node_reverse (dfg->flow, resolve_me, &vi);

View File

@ -1260,13 +1260,13 @@ typedef struct r_anal_esil_cfg_t {
RGraph *g;
} RAnalEsilCFG;
typedef enum {
enum {
R_ANAL_ESIL_DFG_BLOCK_CONST = 1,
R_ANAL_ESIL_DFG_BLOCK_VAR = 2,
R_ANAL_ESIL_DFG_BLOCK_PTR = 4,
R_ANAL_ESIL_DFG_BLOCK_RESULT = 8,
R_ANAL_ESIL_DFG_BLOCK_GENERATIVE = 16,
} RAnalEsilDFGBlockType;
}; //RAnalEsilDFGBlockType
typedef struct r_anal_esil_dfg_t {
ut32 idx;
@ -1284,7 +1284,7 @@ typedef struct r_anal_esil_dfg_node_t {
// add more info here
ut32 idx;
RStrBuf *content;
RAnalEsilDFGBlockType type;
ut32 /*RAnalEsilDFGBlockType*/ type;
} RAnalEsilDFGNode;
typedef int (*RAnalCmdExt)(/* Rcore */RAnal *anal, const char* input);
@ -2120,10 +2120,11 @@ R_API RAnalEsilCFG *r_anal_esil_cfg_op(RAnalEsilCFG *cfg, RAnal *anal, RAnalOp *
R_API void r_anal_esil_cfg_merge_blocks(RAnalEsilCFG *cfg);
R_API void r_anal_esil_cfg_free(RAnalEsilCFG *cfg);
R_API RAnalEsilDFGNode *r_anal_esil_dfg_node_new (RAnalEsilDFG *edf, const char *c);
R_API RAnalEsilDFGNode *r_anal_esil_dfg_node_new(RAnalEsilDFG *edf, const char *c);
R_API RAnalEsilDFG *r_anal_esil_dfg_new(RReg *regs);
R_API void r_anal_esil_dfg_free(RAnalEsilDFG *dfg);
R_API RAnalEsilDFG *r_anal_esil_dfg_expr(RAnal *anal, RAnalEsilDFG *dfg, const char *expr);
R_API void r_anal_esil_dfg_fold_const(RAnal *anal, RAnalEsilDFG *dfg);
R_API RStrBuf *r_anal_esil_dfg_filter(RAnalEsilDFG *dfg, const char *reg);
R_API RStrBuf *r_anal_esil_dfg_filter_expr(RAnal *anal, const char *expr, const char *reg);
R_API RList *r_anal_types_from_fcn(RAnal *anal, RAnalFunction *fcn);