mirror of
https://github.com/radareorg/radare2.git
synced 2025-04-03 18:11:38 +00:00
r_anal_esil_dfg_lemon_const_folder
This commit is contained in:
parent
fbdc4f16dd
commit
87dd695d2b
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user