From 893d902412f04aa48f609a15cd69d93944d125d9 Mon Sep 17 00:00:00 2001 From: Jared Date: Fri, 23 Feb 2024 04:56:01 -0500 Subject: [PATCH 1/4] Test --- do_you_see_this | 1 + 1 file changed, 1 insertion(+) create mode 100644 do_you_see_this diff --git a/do_you_see_this b/do_you_see_this new file mode 100644 index 00000000000..ce013625030 --- /dev/null +++ b/do_you_see_this @@ -0,0 +1 @@ +hello From df494edccda54f2e373c5ce5a9c8b1319ac8f968 Mon Sep 17 00:00:00 2001 From: Jared Date: Tue, 27 Feb 2024 19:44:50 -0500 Subject: [PATCH 2/4] Fixes #2247 - Improve try/catch analysis [WIP] Your checklist for this pull request - [x] I've read the guidelines for contributing to this repository - [x] I made sure to follow the project's coding style - [ ] I've documented or updated the documentation of every function and struct this PR changes. If not so I've explained why. - [ ] I've added tests that prove my fix is effective or that my feature works (if possible) - [ ] I've updated the rizin book with the relevant information (if needed) Detailed description Bin - Load exception information by default Analysis - Make analyzing exception scopes the default - Analyze all exception sources as functions - Do not hack basic blocks flow to add try/catch information Graph - Add an edge pointing to the catch block for each basic block inside the try scope - Add configuration graph.trycatch to control if graphing the exception blocks is enabled Problems 8ff06e9 Is basically copy-pasted logic from block.c This can make graphs a lot noisier Cutter will have to implement its own version of the logic if it wants to copy rizin in showing the connection between the blocks and its catch blocks I didn't add tests yet Test plan Open bins\pe\microsoft_seh_tests\x64\xcpt4.exe for example Optional: idp to load debug info for binary aaa Optional: .iw to show try catch scopes as flags s main Enter visual graph mode, make sure all edges, lines are painted correctly, and that there area now new edges pointing each basic block to its catch block if it is inside a try scope Open file from #2247 aaa s main Enter visual graph mode, make sure issue is fixed Closing issues Closes #2247 --- librz/analysis/analysis.c | 8 ++ librz/analysis/fcn.c | 43 +++-------- librz/core/agraph.c | 95 +++++++++++++++++++---- librz/core/canalysis.c | 23 ++++++ librz/core/cbin.c | 51 ++++++++++-- librz/core/cconfig.c | 3 +- librz/include/rz_agraph.h | 4 + librz/include/rz_analysis.h | 3 + librz/include/rz_core.h | 5 +- librz/include/rz_util/rz_rbtree.h | 6 ++ librz/util/rbtree.c | 124 ++++++++++++++++++++++++++++++ 11 files changed, 310 insertions(+), 55 deletions(-) diff --git a/librz/analysis/analysis.c b/librz/analysis/analysis.c index 4b80a007adb..ec185b50fcc 100644 --- a/librz/analysis/analysis.c +++ b/librz/analysis/analysis.c @@ -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); @@ -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); @@ -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; } diff --git a/librz/analysis/fcn.c b/librz/analysis/fcn.c index d60b836888a..50cf1c1812e 100644 --- a/librz/analysis/fcn.c +++ b/librz/analysis/fcn.c @@ -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) { @@ -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; diff --git a/librz/core/agraph.c b/librz/core/agraph.c index 6f047253b9e..e6f07d88948 100644 --- a/librz/core/agraph.c +++ b/librz/core/agraph.c @@ -714,6 +714,10 @@ static void create_dummy_nodes(RzAGraph *g) { 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); @@ -1754,6 +1758,9 @@ static void fix_back_edge_dummy_nodes(RzAGraph *g, RzANode *from, RzANode *to) { } 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; @@ -1768,6 +1775,9 @@ static int get_edge_number(const RzAGraph *g, RzANode *src, RzANode *dst, bool o ? 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; @@ -2346,6 +2356,7 @@ static int get_bbnodes(RzAGraph *g, RzCore *core, RzAnalysisFunction *fcn) { 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; @@ -2384,6 +2395,9 @@ static int get_bbnodes(RzAGraph *g, RzCore *core, RzAnalysisFunction *fcn) { 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); } @@ -2395,6 +2409,15 @@ static int get_bbnodes(RzAGraph *g, RzCore *core, RzAnalysisFunction *fcn) { 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; @@ -2406,6 +2429,28 @@ static int get_bbnodes(RzAGraph *g, RzCore *core, RzAnalysisFunction *fcn) { 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); + if (v) { + v->is_unconditional_jmp = true; + rz_agraph_add_edge(g, u, v); + } + } free(title); if (bb->jump != UT64_MAX) { title = get_title(bb->jump); @@ -2430,7 +2475,7 @@ static int get_bbnodes(RzAGraph *g, RzCore *core, RzAnalysisFunction *fcn) { } } } - + rz_list_free(exception_scopes); delete_dup_edges(g); ret = true; @@ -2861,6 +2906,14 @@ static int first_x_cmp(const void *_a, const void *_b, void *user) { 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; @@ -2869,12 +2922,20 @@ static void agraph_print_edges(RzAGraph *g) { 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(); @@ -2938,6 +2999,14 @@ static void agraph_print_edges(RzAGraph *g) { 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; @@ -2945,21 +3014,14 @@ static void agraph_print_edges(RzAGraph *g) { 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) { @@ -3783,6 +3845,9 @@ RZ_API RzANode *rz_agraph_add_node(const RzAGraph *g, const char *title, const c 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; } diff --git a/librz/core/canalysis.c b/librz/core/canalysis.c index 38ab14f3279..690003711a5 100644 --- a/librz/core/canalysis.c +++ b/librz/core/canalysis.c @@ -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 @@ -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" rz_core_seek(core, curseek, true); rz_core_notify_done(core, "%s", notify); diff --git a/librz/core/cbin.c b/librz/core/cbin.c index e9142cc0aa7..ecb9f44d154 100644 --- a/librz/core/cbin.c +++ b/librz/core/cbin.c @@ -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" @@ -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; } @@ -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); diff --git a/librz/core/cconfig.c b/librz/core/cconfig.c index f3a5ff4a4aa..3a89185dfa8 100644 --- a/librz/core/cconfig.c +++ b/librz/core/cconfig.c @@ -3051,7 +3051,7 @@ RZ_API int rz_core_config_init(RzCore *core) { SETCB("analysis.jmp.mid", "true", &cb_analysis_jmpmid, "Continue analysis after jump to middle of instruction (x86 only)"); SETCB("analysis.refstr", "false", &cb_analysis_searchstringrefs, "Search string references in data references"); - SETCB("analysis.trycatch", "false", &cb_analysis_trycatch, "Honor try.X.Y.{from,to,catch} flags"); + SETCB("analysis.trycatch", "true", &cb_analysis_trycatch, "Honor try.X.Y.{from,to,catch} flags"); SETCB("analysis.bb.maxsize", "512K", &cb_analysis_bb_max_size, "Maximum basic block size"); SETCB("analysis.pushret", "false", &cb_analysis_pushret, "Analyze push+ret as jmp"); @@ -3565,6 +3565,7 @@ RZ_API int rz_core_config_init(RzCore *core) { SETBPREF("graph.trace", "false", "Fold all non-traced basic blocks"); SETBPREF("graph.dummy", "true", "Create dummy nodes in the graph for better layout (20% slower)"); SETBPREF("graph.few", "false", "Show few basic blocks in the graph"); + SETBPREF("graph.trycatch", "true", "Draw exception handling related basic blocks in the function graph"); SETBPREF("graph.comments", "true", "Show disasm comments in graph"); SETBPREF("graph.cmtright", "false", "Show comments at right"); SETCB("graph.gv.format", "gif", &cb_graphformat, "Graph image extension when using 'w' format (png, jpg, pdf, ps, svg, json)"); diff --git a/librz/include/rz_agraph.h b/librz/include/rz_agraph.h index 59770363569..de10b50a898 100644 --- a/librz/include/rz_agraph.h +++ b/librz/include/rz_agraph.h @@ -26,6 +26,10 @@ typedef struct rz_ascii_node_t { ut32 shortcut_w; bool is_mini; ut64 offset; + bool is_unconditional_jmp; + ut64 address; + ut64 jump; + ut64 fail; } RzANode; typedef struct rz_core_graph_hits_t { diff --git a/librz/include/rz_analysis.h b/librz/include/rz_analysis.h index ad31d32d5f7..aac52c0343b 100644 --- a/librz/include/rz_analysis.h +++ b/librz/include/rz_analysis.h @@ -532,6 +532,9 @@ typedef struct rz_analysis_t { HtPP *ht_global_var; // global variables RBTree global_var_tree; // global variables by address. must not overlap RzHash *hash; + RBItvTree /**/ exception_scopes_tree; + // TODO (Jared): Find out the meanings of these. And why they're here (i.e., could they go somewhere else) + HtUP /* *>*/ *exception_scopes_ht; RzAnalysisDebugInfo *debug_info; ///< store all debug info parsed from DWARF, etc.. ut64 cmpval; ///< last compare value for jump table. ut64 lea_jmptbl_ip; ///< jump table x86 lea ip diff --git a/librz/include/rz_core.h b/librz/include/rz_core.h index 4c3a83de930..a8536a7ef4b 100644 --- a/librz/include/rz_core.h +++ b/librz/include/rz_core.h @@ -899,6 +899,8 @@ RZ_API void rz_core_bin_export_info(RzCore *core, int mode); RZ_API bool rz_core_binfiles_print(RzCore *core, RzCmdStateOutput *state); RZ_API bool rz_core_binfiles_delete(RzCore *core, RzBinFile *bf); RZ_API RZ_OWN HtPP *rz_core_bin_create_digests(RzCore *core, ut64 paddr, ut64 size, RzList /**/ *digests); +RZ_API bool rz_core_bin_apply_trycatch(RzCore *core, RzBinFile *binfile); +// RZ_API bool RZ_API void rz_core_bin_print_source_line_sample(RzCore *core, const RzBinSourceLineSample *s, RzCmdStateOutput *state); RZ_API void rz_core_bin_print_source_line_info(RzCore *core, const RzBinSourceLineInfo *li, RzCmdStateOutput *state); @@ -973,7 +975,8 @@ RZ_API RZ_OWN RzList /**/ *rz_heap_windows_heap_list(RzCore #define RZ_CORE_BIN_ACC_TRYCATCH 0x20000000 #define RZ_CORE_BIN_ACC_SECTIONS_MAPPING 0x40000000 #define RZ_CORE_BIN_ACC_MAPS 0x80000000 -#define RZ_CORE_BIN_ACC_ALL 0x80504FFF +// TODO (Jared): OR together all the above stuff +#define RZ_CORE_BIN_ACC_ALL 0xA0504FFF #define RZ_CORE_PRJ_FLAGS 0x0001 #define RZ_CORE_PRJ_EVAL 0x0002 diff --git a/librz/include/rz_util/rz_rbtree.h b/librz/include/rz_util/rz_rbtree.h index 499b27139db..376882d1215 100644 --- a/librz/include/rz_util/rz_rbtree.h +++ b/librz/include/rz_util/rz_rbtree.h @@ -6,6 +6,7 @@ #include #include "rz_list.h" +#include #ifdef __cplusplus extern "C" { @@ -55,6 +56,7 @@ typedef struct rz_containing_rb_tree_t { RContRBFree free; } RContRBTree; +typedef RBTree RBItvTree; // Routines for augmented red-black trees. The user should provide an aggregation (monoid sum) callback `sum` // to calculate extra information such as size, sum, ... RZ_API bool rz_rbtree_aug_delete(RBNode **root, void *data, RBComparator cmp, void *cmp_user, RBNodeFree freefn, void *free_user, RBNodeSum sum); @@ -118,6 +120,10 @@ RZ_API void *rz_rbtree_cont_find(RContRBTree *tree, void *data, RContRBCmp cmp, RZ_API void rz_rbtree_cont_free(RContRBTree *tree); +RZ_API bool rz_rbtree_itv_insert(RBItvTree *itv_tree, RzInterval itv, RZ_BORROW void *user); +RZ_API RZ_OWN RzList *rz_rbtree_itv_all_intersect(RBItvTree itv_tree, RzInterval itv); +RZ_API void rz_rbtree_itv_free(RBItvTree *itv_tree); + #ifdef __cplusplus } #endif diff --git a/librz/util/rbtree.c b/librz/util/rbtree.c index 2974f764aa8..c875bf3b91c 100644 --- a/librz/util/rbtree.c +++ b/librz/util/rbtree.c @@ -474,3 +474,127 @@ RZ_API void rz_rbtree_cont_free(RContRBTree *tree) { } free(tree); } + +typedef struct { + RBNode _rb; + RzInterval itv; + ut64 _max_end; + void *user; +} RzItvTreeNode; + +typedef void (*RzItvTreeCb)(void *node_user, void *user); + +#define unwrap(rbnode) ((rbnode) ? container_of(rbnode, RzItvTreeNode, _rb) : NULL) + +static void itv_max_end(RBNode *node) { + RzItvTreeNode *n = container_of(node, RzItvTreeNode, _rb); + n->_max_end = rz_itv_end(n->itv); + int i; + for (i = 0; i < 2; i++) { + if (node->child[i]) { + ut64 end = unwrap(node->child[i])->_max_end; + if (end > n->_max_end) { + n->_max_end = end; + } + } + } +} + +static int itv_cmp_start(const void *incoming, const RBNode *in_tree, void *user) { + const ut64 incoming_start = *(ut64 *)incoming; + const RzItvTreeNode *in_tree_itv = container_of(in_tree, const RzItvTreeNode, _rb); + const ut64 in_tree_start = rz_itv_begin(in_tree_itv->itv); + if (incoming_start < in_tree_start) { + return -1; + } + if (incoming_start > in_tree_start) { + return 1; + } + return 0; +} + +/* + * * \brief Convenience function to insert new node with interval \p itv into a rbtree + * * \param itv_tree Pointer to RBItvTree to insert new node to + * * \param itv Interval to use when inserting the node + * * \param user Borrowed user pointer, must live as long as \p itv_tree + * * \return true if successfull + * * + * * Note: Do not use this function on a RBTree with nodes that were inserted with + * * non-itv version of the rbtree functions. + * */ +RZ_API bool rz_rbtree_itv_insert(RBItvTree *itv_tree, RzInterval itv, RZ_BORROW void *user) { + RzItvTreeNode *node = RZ_NEW0(RzItvTreeNode); + if (!node) { + return false; + } + node->itv = itv; + node->user = user; + ut64 begin = rz_itv_begin(itv); + bool ret = rz_rbtree_aug_insert(itv_tree, user, &node->_rb, itv_cmp_start, &begin, itv_max_end); + if (!ret) { + free(node); + } + return ret; +} + +static void all_intersect(RzItvTreeNode *node, RzInterval itv, RzItvTreeCb cb, void *user) { + const ut64 end = rz_itv_end(itv); + while (node && end <= rz_itv_begin(node->itv)) { + // less than the current node, but might still be contained further down + node = unwrap(node->_rb.child[0]); + } + if (!node) { + return; + } + const ut64 begin = rz_itv_begin(itv); + if (begin >= node->_max_end) { + return; + } + if (begin < rz_itv_end(node->itv)) { + cb(node->user, user); + } + // This can be done more efficiently by building the stack manually + all_intersect(unwrap(node->_rb.child[0]), itv, cb, user); + all_intersect(unwrap(node->_rb.child[1]), itv, cb, user); +} + +static void add_to_list(void *node_user, void *user) { + RzList *l = user; + rz_list_append(l, node_user); +} + +/* + * \brief Returns list with all nodes that intersect with interval \p itv + * \param itv_tree RBItvTree to search for intersecting nodes + * \param itv Interval to use when searching for intersecting nodes + * \return RzList * with intersecting nodes + * + * Note: Do not use this function on a RBTree with nodes that were inserted with + * non-itv version of the rbtree functions. + */ +RZ_API RzList *rz_rbtree_itv_all_intersect(RBItvTree itv_tree, RzInterval itv) { + if (!itv_tree) { + return NULL; + } + RzList *l = rz_list_new(); + all_intersect(unwrap(itv_tree->child[0]), itv, add_to_list, l); + all_intersect(unwrap(itv_tree->child[1]), itv, add_to_list, l); + return l; +} + +static void free_itv_rb(RBNode *node, void *user) { + free(container_of(node, RzItvTreeNode, _rb)); +} + +/* + * * \brief Frees \p itv_tree + * * \param itv_tree Pointer to RBItvTree to free + * * + * * Note: Do not use this function on a RBTree with nodes that were inserted with + * * non-itv version of the rbtree functions. + * */ +RZ_API void rz_rbtree_itv_free(RBItvTree *itv_tree) { + rz_rbtree_free(*itv_tree, free_itv_rb, NULL); + *itv_tree = NULL; +} From 8b7943bc315a28fab2c7a8c0a55f41ed053c708b Mon Sep 17 00:00:00 2001 From: Jared Date: Sun, 3 Mar 2024 18:52:15 -0500 Subject: [PATCH 3/4] Fixing Errors --- librz/analysis/analysis.c | 3 +- librz/core/agraph.c | 2 +- librz/core/cbin.c | 3 +- librz/include/rz_analysis.h | 5 +- librz/include/rz_util/rz_rbtree.h | 5 -- librz/util/rbtree.c | 124 ------------------------------ 6 files changed, 8 insertions(+), 134 deletions(-) diff --git a/librz/analysis/analysis.c b/librz/analysis/analysis.c index ec185b50fcc..a77e7dcfb20 100644 --- a/librz/analysis/analysis.c +++ b/librz/analysis/analysis.c @@ -198,7 +198,8 @@ RZ_API RzAnalysis *rz_analysis_free(RzAnalysis *a) { rz_list_free(a->plugins); rz_analysis_debug_info_free(a->debug_info); // TODO (Jared): Implement - rz_rbtree_itv_free(&a->exception_scopes_tree); + // free a->exception_scopes_tree + // rz_rbtree_itv_free(&a->exception_scopes_tree); ht_up_free(a->exception_scopes_ht); free(a); return NULL; diff --git a/librz/core/agraph.c b/librz/core/agraph.c index e6f07d88948..dd1a25bebf7 100644 --- a/librz/core/agraph.c +++ b/librz/core/agraph.c @@ -2415,7 +2415,7 @@ static int get_bbnodes(RzAGraph *g, RzCore *core, RzAnalysisFunction *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); + exception_scopes = rz_interval_tree_all_intersect(fcn->analysis->exception_scopes_tree, itv); } rz_list_foreach (fcn->bbs, iter, bb) { diff --git a/librz/core/cbin.c b/librz/core/cbin.c index ecb9f44d154..f213174a9c3 100644 --- a/librz/core/cbin.c +++ b/librz/core/cbin.c @@ -1671,6 +1671,7 @@ RZ_API bool rz_core_bin_apply_resources(RzCore *core, RzBinFile *binfile) { return true; } +// TODO: (Jared) Analyze this function closely RZ_API bool rz_core_bin_apply_trycatch(RzCore *core, RzBinFile *binfile) { rz_return_val_if_fail(core && binfile, false); RzListIter *it; @@ -1698,7 +1699,7 @@ RZ_API bool rz_core_bin_apply_trycatch(RzCore *core, RzBinFile *binfile) { return false; } RzInterval itv = { tc->from, tc->to - tc->from - 1 }; - if (!rz_rbtree_itv_insert(&core->analysis->exception_scopes_tree, itv, tc)) { + if (!rz_interval_tree_insert(&core->analysis->exception_scopes_tree, itv, tc)) { return false; } } diff --git a/librz/include/rz_analysis.h b/librz/include/rz_analysis.h index aac52c0343b..ea89d8c72a3 100644 --- a/librz/include/rz_analysis.h +++ b/librz/include/rz_analysis.h @@ -532,8 +532,9 @@ typedef struct rz_analysis_t { HtPP *ht_global_var; // global variables RBTree global_var_tree; // global variables by address. must not overlap RzHash *hash; - RBItvTree /**/ exception_scopes_tree; - // TODO (Jared): Find out the meanings of these. And why they're here (i.e., could they go somewhere else) + // TODO: (Jared) Find out the meanings of this. And why they're here (i.e., could they go somewhere else) + RzIntervalTree /**/ exception_scopes_tree; + // TODO: (Jared) Find out the meanings of this. And why they're here (i.e., could they go somewhere else) HtUP /* *>*/ *exception_scopes_ht; RzAnalysisDebugInfo *debug_info; ///< store all debug info parsed from DWARF, etc.. ut64 cmpval; ///< last compare value for jump table. diff --git a/librz/include/rz_util/rz_rbtree.h b/librz/include/rz_util/rz_rbtree.h index 376882d1215..e3d8e360d15 100644 --- a/librz/include/rz_util/rz_rbtree.h +++ b/librz/include/rz_util/rz_rbtree.h @@ -56,7 +56,6 @@ typedef struct rz_containing_rb_tree_t { RContRBFree free; } RContRBTree; -typedef RBTree RBItvTree; // Routines for augmented red-black trees. The user should provide an aggregation (monoid sum) callback `sum` // to calculate extra information such as size, sum, ... RZ_API bool rz_rbtree_aug_delete(RBNode **root, void *data, RBComparator cmp, void *cmp_user, RBNodeFree freefn, void *free_user, RBNodeSum sum); @@ -120,10 +119,6 @@ RZ_API void *rz_rbtree_cont_find(RContRBTree *tree, void *data, RContRBCmp cmp, RZ_API void rz_rbtree_cont_free(RContRBTree *tree); -RZ_API bool rz_rbtree_itv_insert(RBItvTree *itv_tree, RzInterval itv, RZ_BORROW void *user); -RZ_API RZ_OWN RzList *rz_rbtree_itv_all_intersect(RBItvTree itv_tree, RzInterval itv); -RZ_API void rz_rbtree_itv_free(RBItvTree *itv_tree); - #ifdef __cplusplus } #endif diff --git a/librz/util/rbtree.c b/librz/util/rbtree.c index c875bf3b91c..2974f764aa8 100644 --- a/librz/util/rbtree.c +++ b/librz/util/rbtree.c @@ -474,127 +474,3 @@ RZ_API void rz_rbtree_cont_free(RContRBTree *tree) { } free(tree); } - -typedef struct { - RBNode _rb; - RzInterval itv; - ut64 _max_end; - void *user; -} RzItvTreeNode; - -typedef void (*RzItvTreeCb)(void *node_user, void *user); - -#define unwrap(rbnode) ((rbnode) ? container_of(rbnode, RzItvTreeNode, _rb) : NULL) - -static void itv_max_end(RBNode *node) { - RzItvTreeNode *n = container_of(node, RzItvTreeNode, _rb); - n->_max_end = rz_itv_end(n->itv); - int i; - for (i = 0; i < 2; i++) { - if (node->child[i]) { - ut64 end = unwrap(node->child[i])->_max_end; - if (end > n->_max_end) { - n->_max_end = end; - } - } - } -} - -static int itv_cmp_start(const void *incoming, const RBNode *in_tree, void *user) { - const ut64 incoming_start = *(ut64 *)incoming; - const RzItvTreeNode *in_tree_itv = container_of(in_tree, const RzItvTreeNode, _rb); - const ut64 in_tree_start = rz_itv_begin(in_tree_itv->itv); - if (incoming_start < in_tree_start) { - return -1; - } - if (incoming_start > in_tree_start) { - return 1; - } - return 0; -} - -/* - * * \brief Convenience function to insert new node with interval \p itv into a rbtree - * * \param itv_tree Pointer to RBItvTree to insert new node to - * * \param itv Interval to use when inserting the node - * * \param user Borrowed user pointer, must live as long as \p itv_tree - * * \return true if successfull - * * - * * Note: Do not use this function on a RBTree with nodes that were inserted with - * * non-itv version of the rbtree functions. - * */ -RZ_API bool rz_rbtree_itv_insert(RBItvTree *itv_tree, RzInterval itv, RZ_BORROW void *user) { - RzItvTreeNode *node = RZ_NEW0(RzItvTreeNode); - if (!node) { - return false; - } - node->itv = itv; - node->user = user; - ut64 begin = rz_itv_begin(itv); - bool ret = rz_rbtree_aug_insert(itv_tree, user, &node->_rb, itv_cmp_start, &begin, itv_max_end); - if (!ret) { - free(node); - } - return ret; -} - -static void all_intersect(RzItvTreeNode *node, RzInterval itv, RzItvTreeCb cb, void *user) { - const ut64 end = rz_itv_end(itv); - while (node && end <= rz_itv_begin(node->itv)) { - // less than the current node, but might still be contained further down - node = unwrap(node->_rb.child[0]); - } - if (!node) { - return; - } - const ut64 begin = rz_itv_begin(itv); - if (begin >= node->_max_end) { - return; - } - if (begin < rz_itv_end(node->itv)) { - cb(node->user, user); - } - // This can be done more efficiently by building the stack manually - all_intersect(unwrap(node->_rb.child[0]), itv, cb, user); - all_intersect(unwrap(node->_rb.child[1]), itv, cb, user); -} - -static void add_to_list(void *node_user, void *user) { - RzList *l = user; - rz_list_append(l, node_user); -} - -/* - * \brief Returns list with all nodes that intersect with interval \p itv - * \param itv_tree RBItvTree to search for intersecting nodes - * \param itv Interval to use when searching for intersecting nodes - * \return RzList * with intersecting nodes - * - * Note: Do not use this function on a RBTree with nodes that were inserted with - * non-itv version of the rbtree functions. - */ -RZ_API RzList *rz_rbtree_itv_all_intersect(RBItvTree itv_tree, RzInterval itv) { - if (!itv_tree) { - return NULL; - } - RzList *l = rz_list_new(); - all_intersect(unwrap(itv_tree->child[0]), itv, add_to_list, l); - all_intersect(unwrap(itv_tree->child[1]), itv, add_to_list, l); - return l; -} - -static void free_itv_rb(RBNode *node, void *user) { - free(container_of(node, RzItvTreeNode, _rb)); -} - -/* - * * \brief Frees \p itv_tree - * * \param itv_tree Pointer to RBItvTree to free - * * - * * Note: Do not use this function on a RBTree with nodes that were inserted with - * * non-itv version of the rbtree functions. - * */ -RZ_API void rz_rbtree_itv_free(RBItvTree *itv_tree) { - rz_rbtree_free(*itv_tree, free_itv_rb, NULL); - *itv_tree = NULL; -} From 976d00579f320a24c206ca49a938b03b8604abbe Mon Sep 17 00:00:00 2001 From: Jared Date: Tue, 2 Apr 2024 23:36:09 -0400 Subject: [PATCH 4/4] Progress towards SEH parsing --- librz/bin/p/bin_pe64.c | 1 + librz/core/cbin.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/librz/bin/p/bin_pe64.c b/librz/bin/p/bin_pe64.c index 40aa2336d3a..61417c08036 100644 --- a/librz/bin/p/bin_pe64.c +++ b/librz/bin/p/bin_pe64.c @@ -434,6 +434,7 @@ static bool read_pe64_scope_record(RzBuffer *buf, ut64 base, PE64_SCOPE_RECORD * rz_buf_read_ble32_offset(buf, &offset, &record->JumpTarget, big_endian); } +// TODO: (Jared) Analyze this closely static RzPVector /**/ *trycatch(RzBinFile *bf) { ut64 baseAddr = bf->o->opts.baseaddr; ut64 offset; diff --git a/librz/core/cbin.c b/librz/core/cbin.c index f213174a9c3..7b5f793b2e6 100644 --- a/librz/core/cbin.c +++ b/librz/core/cbin.c @@ -1674,7 +1674,7 @@ RZ_API bool rz_core_bin_apply_resources(RzCore *core, RzBinFile *binfile) { // TODO: (Jared) Analyze this function closely RZ_API bool rz_core_bin_apply_trycatch(RzCore *core, RzBinFile *binfile) { rz_return_val_if_fail(core && binfile, false); - RzListIter *it; + void **it; RzPVector *vec = rz_bin_file_get_trycatch(binfile); RzBinTrycatch *trycatch = NULL; rz_pvector_foreach (vec, it) {