Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Try Catch Improvement #4305

Draft
wants to merge 5 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions do_you_see_this
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
hello
8 changes: 8 additions & 0 deletions librz/analysis/analysis.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ static void global_kv_free(HtPPKv *kv) {
rz_analysis_var_global_free(kv->value);
}

static void exception_scope_kv_free(HtUPKv *kv) {
rz_list_free(kv->value);
}

RZ_API RzAnalysis *rz_analysis_new(void) {
int i;
RzAnalysis *analysis = RZ_NEW0(RzAnalysis);
Expand Down Expand Up @@ -102,6 +106,7 @@ RZ_API RzAnalysis *rz_analysis_new(void) {
analysis->cpp_abi = RZ_ANALYSIS_CPP_ABI_ITANIUM;
analysis->opt.depth = 32;
analysis->opt.noncode = false; // do not analyze data by default
analysis->exception_scopes_ht = ht_up_new(NULL, exception_scope_kv_free, NULL);
rz_spaces_init(&analysis->meta_spaces, "CS");
rz_event_hook(analysis->meta_spaces.event, RZ_SPACE_EVENT_UNSET, meta_unset_for, NULL);
rz_event_hook(analysis->meta_spaces.event, RZ_SPACE_EVENT_COUNT, meta_count_for, NULL);
Expand Down Expand Up @@ -192,6 +197,9 @@ RZ_API RzAnalysis *rz_analysis_free(RzAnalysis *a) {
ht_pp_free(a->ht_global_var);
rz_list_free(a->plugins);
rz_analysis_debug_info_free(a->debug_info);
// TODO (Jared): Implement
rz_rbtree_itv_free(&a->exception_scopes_tree);
ht_up_free(a->exception_scopes_ht);
free(a);
return NULL;
}
Expand Down
43 changes: 12 additions & 31 deletions librz/analysis/fcn.c
Original file line number Diff line number Diff line change
Expand Up @@ -773,37 +773,6 @@ static RzAnalysisBBEndCause run_basic_block_analysis(RzAnalysisTaskItem *item, R
rz_analysis_block_set_size(bb, newbbsize);
fcn->ninstr++;
}
if (analysis->opt.trycatch) {
const char *name = analysis->coreb.getName(analysis->coreb.core, at);
if (name) {
if (rz_str_startswith(name, "try.") && rz_str_endswith(name, ".from")) {
char *handle = strdup(name);
// handle = rz_str_replace (handle, ".from", ".to", 0);
ut64 from_addr = analysis->coreb.numGet(analysis->coreb.core, handle);
handle = rz_str_replace(handle, ".from", ".catch", 0);
ut64 handle_addr = analysis->coreb.numGet(analysis->coreb.core, handle);
handle = rz_str_replace(handle, ".catch", ".filter", 0);
ut64 filter_addr = analysis->coreb.numGet(analysis->coreb.core, handle);
if (filter_addr) {
rz_analysis_xrefs_set(analysis, op.addr, filter_addr, RZ_ANALYSIS_XREF_TYPE_CALL);
}
bb->jump = at + oplen;
if (from_addr != bb->addr) {
bb->fail = handle_addr;
ret = analyze_function_locally(analysis, fcn, handle_addr);
if (bb->size == 0) {
rz_analysis_function_remove_block(fcn, bb);
}
rz_analysis_block_update_hash(bb);
rz_analysis_block_unref(bb);
bb = fcn_append_basic_block(analysis, fcn, bb->jump);
if (!bb) {
gotoBeach(RZ_ANALYSIS_RET_ERROR);
}
}
}
}
}
idx += oplen;
delay.un_idx = idx;
if (analysis->opt.delay && op.delay > 0 && !delay.pending) {
Expand Down Expand Up @@ -1633,6 +1602,18 @@ RZ_API int rz_analysis_fcn(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 a
RzVector tasks;
rz_vector_init(&tasks, sizeof(RzAnalysisTaskItem), NULL, NULL);
rz_analysis_task_item_new(analysis, &tasks, fcn, NULL, addr, 0);
if (analysis->opt.trycatch) {
RzBinTrycatch *tc;
RzListIter *it;
RzList *scopes = ht_up_find(analysis->exception_scopes_ht, fcn->addr, NULL);
rz_list_foreach (scopes, it, tc) {
if (tc->filter) {
rz_analysis_xrefs_set(analysis, tc->from, tc->filter, RZ_ANALYSIS_XREF_TYPE_CALL);
}
// TODO (Jared): Fix Function
rz_analysis_task_item_new(analysis, &tasks, fcn, NULL, tc->handler, fcn->stack);
}
}
int ret = rz_analysis_run_tasks(&tasks);
rz_vector_fini(&tasks);
return ret;
Expand Down
95 changes: 80 additions & 15 deletions librz/core/agraph.c
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,10 @@
dummy->layer = from->layer + i;
dummy->is_reversed = is_reversed(g, e);
dummy->w = 1;
dummy->is_unconditional_jmp = to->is_unconditional_jmp;
dummy->address = to->address;
dummy->jump = to->jump;
dummy->fail = to->fail;
rz_agraph_add_edge_at(g, prev, dummy, nth);
rz_list_append(g->dummy_nodes, dummy);

Expand Down Expand Up @@ -1754,6 +1758,9 @@
}

static int get_edge_number(const RzAGraph *g, RzANode *src, RzANode *dst, bool outgoing) {
if (g->is_callgraph) {
return 0;
}
RzListIter *itn;
RzGraphNode *gv;
int cur_nth = 0;
Expand All @@ -1768,6 +1775,9 @@
? rz_graph_get_neighbours(g->graph, src->gnode)
: rz_graph_innodes(g->graph, dst->gnode);
const int exit_edges = rz_list_length(neighbours);
if (exit_edges == 1) {
return -1;
}
rz_list_foreach (neighbours, itn, gv) {
if (!(v = gv->data)) {
break;
Expand Down Expand Up @@ -2346,6 +2356,7 @@
RzListIter *iter;
bool emu = rz_config_get_i(core->config, "asm.emu");
bool few = rz_config_get_i(core->config, "graph.few");
bool trycatch = rz_config_get_i(core->config, "graph.trycatch");
int ret = false;
ut64 saved_gp = core->analysis->gp;
ut8 *saved_arena = NULL;
Expand Down Expand Up @@ -2384,6 +2395,9 @@
char *title = get_title(bb->addr);

RzANode *node = rz_agraph_add_node(g, title, body);
node->address = bb->addr;
node->jump = bb->jump;
node->fail = bb->fail;
if (shortcuts) {
rz_core_agraph_add_shortcut(core, g, node, bb->addr, title);
}
Expand All @@ -2395,6 +2409,15 @@
core->keep_asmqjmps = true;
}

RzList *exception_scopes = NULL;
if (trycatch) {
// RzInterval itv = { rz_analysis_function_min_addr(fcn),
RzInterval itv = { rz_analysis_function_min_addr(fcn),
rz_analysis_function_max_addr(fcn) - rz_analysis_function_min_addr(fcn) };
// TODO (Jared): Implement exception_scopes_tree
exception_scopes = rz_rbtree_itv_all_intersect(fcn->analysis->exception_scopes_tree, itv);
}

rz_list_foreach (fcn->bbs, iter, bb) {
if (bb->addr == UT64_MAX) {
continue;
Expand All @@ -2406,7 +2429,29 @@
char *title = get_title(bb->addr);
RzANode *u = rz_agraph_get_node(g, title);
RzANode *v;

RzListIter *it;
RzBinTrycatch *tc;
rz_list_foreach (exception_scopes, it, tc) {
if (bb->addr == tc->handler) {
continue;
}
if (!rz_itv_overlap2((RzInterval){ bb->addr, bb->size }, tc->from, tc->to - 1)) {
continue;
}
RzAnalysisBlock *catch_bb = rz_analysis_get_block_at(bb->analysis, tc->handler);
if (!catch_bb || catch_bb->addr == bb->jump || catch_bb->addr == bb->fail) {
continue;
}
title = get_title(catch_bb->addr);
v = rz_agraph_get_node(g, title);
free(title);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
free(title);
RZ_FREE(title);

Use RZ_FREE when a pointer is reused.
RZ_FREE will invoke free and also set the freed pointer to NULL.

if (v) {
v->is_unconditional_jmp = true;
rz_agraph_add_edge(g, u, v);
}
}
free(title);

Check failure

Code scanning / CodeQL

Potential double free Critical

Memory pointed to by 'title' may already have been freed by
call to free
.
if (bb->jump != UT64_MAX) {
title = get_title(bb->jump);
v = rz_agraph_get_node(g, title);
Expand All @@ -2430,7 +2475,7 @@
}
}
}

rz_list_free(exception_scopes);
delete_dup_edges(g);
ret = true;

Expand Down Expand Up @@ -2861,6 +2906,14 @@
return 0;
}

static inline bool is_true_edge(RzANode *src, RzANode *dst) {
return src->jump != UT64_MAX && src->jump == dst->address;
}

static inline bool is_false_edge(RzANode *src, RzANode *dst) {
return src->fail != UT64_MAX && src->fail == dst->address;
}

static void agraph_print_edges(RzAGraph *g) {
if (!g->edgemode) {
return;
Expand All @@ -2869,12 +2922,20 @@
agraph_print_edges_simple(g);
return;
}

int out_nth, in_nth, bendpoint;
RzListIter *itn, *itm, *ito;
RzCanvasLineStyle style = { 0 };
const RzList *nodes = rz_graph_get_nodes(g->graph);
RzGraphNode *ga;
RzANode *a;
// RzANode *real_parent = a;
// if (a->is_dummy) {
// real_parent = (RzANode *)(((RzGraphNode *)rz_list_first(ga->in_nodes))->data);
// while (real_parent && real_parent->is_dummy) {
// real_parent = (RzANode *)(((RzGraphNode *)rz_list_first((real_parent->gnode)->in_nodes))->data);
// }
// }

RzList *lyr = rz_list_new();
RzList *bckedges = rz_list_new();
Expand Down Expand Up @@ -2938,28 +2999,29 @@
rz_list_sort(neighbours, first_x_cmp, NULL);
}

RzANode *real_parent = a;
if (a->is_dummy) {
real_parent = (RzANode *)(((RzGraphNode *)rz_list_first(ga->in_nodes))->data);
while (real_parent && real_parent->is_dummy) {
real_parent = (RzANode *)(((RzGraphNode *)rz_list_first((real_parent->gnode)->in_nodes))->data);
}
}

rz_list_foreach (neighbours, itn, gb) {
if (!(b = gb->data)) {
break;
}
out_nth = get_edge_number(g, a, b, true);
in_nth = get_edge_number(g, a, b, false);

bool parent_many = false;
if (a->is_dummy) {
RzANode *in = (RzANode *)(((RzGraphNode *)rz_list_first(ga->in_nodes))->data);
while (in && in->is_dummy) {
in = (RzANode *)(((RzGraphNode *)rz_list_first((in->gnode)->in_nodes))->data);
}
if (in && in->gnode) {
parent_many = rz_list_length(in->gnode->out_nodes) > 2;
} else {
parent_many = false;
}
}

style.dot_style = DOT_STYLE_NORMAL;
if (many || parent_many || g->is_il) {
if (is_true_edge(real_parent, b) && out_nth != -1) {
style.color = LINE_TRUE;
style.dot_style = DOT_STYLE_CONDITIONAL;
} else if (is_false_edge(real_parent, b)) {
style.color = LINE_FALSE;
style.dot_style = DOT_STYLE_CONDITIONAL;
} else if (many || b->is_unconditional_jmp) {
style.color = LINE_UNCJMP;
} else {
switch (out_nth) {
Expand Down Expand Up @@ -3783,6 +3845,9 @@
rz_strf(buf, "agraph.nodes.%s.body", res->title);
sdb_set_owned(g->db, buf, s, 0);
}
res->address = UT64_MAX;
res->jump = UT64_MAX;
res->fail = UT64_MAX;
return res;
}

Expand Down
23 changes: 23 additions & 0 deletions librz/core/canalysis.c
Original file line number Diff line number Diff line change
Expand Up @@ -1487,10 +1487,24 @@ static bool is_skippable_addr(RzCore *core, ut64 addr) {
if (fcn->addr == addr) {
return true;
}
if (ht_up_find(core->analysis->exception_scopes_ht, addr, NULL)) {
return false;
}
const RzList *flags = rz_flag_get_list(core->flags, addr);
return !(flags && rz_list_find(flags, fcn, find_sym_flag, NULL));
}

static bool analyze_exception_source(void *user, const ut64 key, const void *value) {
RzCore *core = user;
const RzList *scopes = value;
RzListIter *it;
RzBinTrycatch *trycatch;
rz_list_foreach (scopes, it, trycatch) {
rz_core_analysis_fcn(core, trycatch->source, UT64_MAX, RZ_ANALYSIS_XREF_TYPE_NULL, core->analysis->opt.depth);
}
return true;
}

// XXX: This function takes sometimes forever
/* analyze a RzAnalysisFunction at the address 'at'.
* If the function has been already analyzed, it adds a
Expand Down Expand Up @@ -4003,8 +4017,17 @@ RZ_API bool rz_core_analysis_everything(RzCore *core, bool experimental, char *d
return false;
}

if (core->analysis->exception_scopes_ht->count) {
notify = "Analyze exception sources as functions";
rz_core_notify_begin(core, "%s", notify);
ht_up_foreach(core->analysis->exception_scopes_ht, analyze_exception_source, core);
rz_core_notify_done(core, "%s", notify);
rz_core_task_yield(&core->tasks);
}

notify = "Analyze function calls";
rz_core_notify_begin(core, "%s", notify);
rz_core_analysis_calls(core, false); // "aac"
(void)rz_core_analysis_calls(core, false); // "aac"
Comment on lines +4030 to 4031
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

rz_core_seek(core, curseek, true);
rz_core_notify_done(core, "%s", notify);
Expand Down
51 changes: 44 additions & 7 deletions librz/core/cbin.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@

#define LOAD_BSS_MALLOC 0

#define IS_MODE_SET(mode) ((mode)&RZ_MODE_SET)
#define IS_MODE_SIMPLE(mode) ((mode)&RZ_MODE_SIMPLE)
#define IS_MODE_SIMPLEST(mode) ((mode)&RZ_MODE_SIMPLEST)
#define IS_MODE_JSON(mode) ((mode)&RZ_MODE_JSON)
#define IS_MODE_RZCMD(mode) ((mode)&RZ_MODE_RIZINCMD)
#define IS_MODE_EQUAL(mode) ((mode)&RZ_MODE_EQUAL)
#define IS_MODE_SET(mode) ((mode) & RZ_MODE_SET)
#define IS_MODE_SIMPLE(mode) ((mode) & RZ_MODE_SIMPLE)
#define IS_MODE_SIMPLEST(mode) ((mode) & RZ_MODE_SIMPLEST)
#define IS_MODE_JSON(mode) ((mode) & RZ_MODE_JSON)
#define IS_MODE_RZCMD(mode) ((mode) & RZ_MODE_RIZINCMD)
#define IS_MODE_EQUAL(mode) ((mode) & RZ_MODE_EQUAL)
#define IS_MODE_NORMAL(mode) (!(mode))
#define IS_MODE_CLASSDUMP(mode) ((mode)&RZ_MODE_CLASSDUMP)
#define IS_MODE_CLASSDUMP(mode) ((mode) & RZ_MODE_CLASSDUMP)

// dup from cmd_info
#define PAIR_WIDTH "9"
Expand Down Expand Up @@ -279,6 +279,9 @@ RZ_API bool rz_core_bin_apply_info(RzCore *r, RzBinFile *binfile, ut32 mask) {
if (mask & RZ_CORE_BIN_ACC_RESOURCES) {
rz_core_bin_apply_resources(r, binfile);
}
if (mask & RZ_CORE_BIN_ACC_TRYCATCH) {
rz_core_bin_apply_trycatch(r, binfile);
}

return true;
}
Expand Down Expand Up @@ -1668,6 +1671,40 @@ RZ_API bool rz_core_bin_apply_resources(RzCore *core, RzBinFile *binfile) {
return true;
}

RZ_API bool rz_core_bin_apply_trycatch(RzCore *core, RzBinFile *binfile) {
rz_return_val_if_fail(core && binfile, false);
RzListIter *it;
RzPVector *vec = rz_bin_file_get_trycatch(binfile);
RzBinTrycatch *trycatch = NULL;
rz_pvector_foreach (vec, it) {
RzList *scopes = ht_up_find(core->analysis->exception_scopes_ht, trycatch->source, NULL);
if (!scopes) {
scopes = rz_list_newf(free);
if (!scopes) {
return false;
}
if (!ht_up_insert(core->analysis->exception_scopes_ht, trycatch->source, scopes)) {
rz_list_free(scopes);
return false;
}
}
RzBinTrycatch *tc = RZ_NEW(RzBinTrycatch);
if (!tc) {
return false;
}
*tc = *trycatch;
if (!rz_list_append(scopes, tc)) {
free(tc);
return false;
}
RzInterval itv = { tc->from, tc->to - tc->from - 1 };
if (!rz_rbtree_itv_insert(&core->analysis->exception_scopes_tree, itv, tc)) {
return false;
}
}
return true;
}

static void digests_ht_free(HtPPKv *kv) {
free(kv->key);
free(kv->value);
Expand Down
Loading
Loading