From da228d11cfc865b06442bd66b192caeb6e5ff556 Mon Sep 17 00:00:00 2001 From: Rot127 <45763064+Rot127@users.noreply.github.com> Date: Sun, 21 Jun 2026 05:02:40 +0000 Subject: [PATCH] Add all call and other xrefs to the abl output (#6269) * Ensure call targets are only added once for each block. * Fix abl printing correct xrefs --- librz/arch/analysis.c | 12 + librz/arch/block.c | 1 + librz/core/cmd/cmd_analysis.c | 121 ++++--- librz/include/rz_analysis.h | 1 + test/db/cmd/cmd_ab | 596 +++++++++++++++++++++------------- 5 files changed, 450 insertions(+), 281 deletions(-) diff --git a/librz/arch/analysis.c b/librz/arch/analysis.c index e77d77057e..2494b32c59 100644 --- a/librz/arch/analysis.c +++ b/librz/arch/analysis.c @@ -974,6 +974,18 @@ RZ_API bool rz_analysis_op_is_eob(const RzAnalysisOp *op) { } } +/** + * \brief Returns true if the \p op is a call. + */ +RZ_API bool rz_analysis_op_is_call(RZ_NONNULL const RzAnalysisOp *op) { + rz_return_val_if_fail(op, false); + if ((op->type & RZ_ANALYSIS_OP_TYPE_CALL) == RZ_ANALYSIS_OP_TYPE_CALL || + (op->type & RZ_ANALYSIS_OP_TYPE_UCALL) == RZ_ANALYSIS_OP_TYPE_UCALL) { + return true; + } + return false; +} + RZ_API void rz_analysis_purge(RzAnalysis *analysis) { rz_analysis_hint_clear(analysis); rz_interval_tree_fini(&analysis->meta); diff --git a/librz/arch/block.c b/librz/arch/block.c index 1c42df949d..0a330d98b5 100644 --- a/librz/arch/block.c +++ b/librz/arch/block.c @@ -1056,6 +1056,7 @@ RZ_API bool rz_analysis_block_set_op_offset(RzAnalysisBlock *block, size_t i, ut if (!tmp_op_pos) { return false; } + memset(tmp_op_pos + block->op_pos_size, 0, (new_pos_size - block->op_pos_size) * sizeof(ut16)); block->op_pos_size = new_pos_size; block->op_pos = tmp_op_pos; } diff --git a/librz/core/cmd/cmd_analysis.c b/librz/core/cmd/cmd_analysis.c index 701c170ec3..ef35ce27ee 100644 --- a/librz/core/cmd/cmd_analysis.c +++ b/librz/core/cmd/cmd_analysis.c @@ -13,8 +13,6 @@ #define MAX_SCAN_SIZE 0x7ffffff -HEAPTYPE(ut64); - static const char *help_detail_ae[] = { "Examples:", "ESIL", " examples and documentation", "=", "", "assign updating internal flags", @@ -612,12 +610,11 @@ static char *fcnjoin(RzList /**/ *list) { return s; } -static char *ut64join(RzList /**/ *list) { +static char *ut64join(RzVector /**/ *addrs) { ut64 *n; - RzListIter *iter; RzStrBuf buf; rz_strbuf_init(&buf); - rz_list_foreach (list, iter, n) { + rz_vector_foreach (addrs, n) { rz_strbuf_appendf(&buf, " 0x%08" PFMT64x, *n); } char *s = rz_str_dup(rz_strbuf_get(&buf)); @@ -5662,31 +5659,40 @@ RZ_IPI RzCmdStatus rz_analysis_all_esil_functions_handler(RzCore *core, int argc return RZ_CMD_STATUS_OK; } -static RzList /**/ *get_xrefs(RzAnalysisBlock *block) { +static int cmp(const ut64 *a, const ut64 *b, void *user) { + return *a - *b; +} + +static RzVector /**/ *get_xrefs(RzAnalysisBlock *block) { RzListIter *iter; RzAnalysisXRef *xref; - RzList *list = NULL; + RzVector *set = rz_vector_new(sizeof(ut64), NULL, NULL); + if (!set) { + return NULL; + } size_t i; for (i = 0; i < block->ninstr; i++) { ut64 ia = block->addr + block->op_pos[i]; RzList *xrefs = rz_analysis_xrefs_get_to(block->analysis, ia); rz_list_foreach (xrefs, iter, xref) { - if (!list) { - list = rz_list_newf(free); + if (!rz_vector_contains(set, &xref->from)) { + rz_vector_push(set, &xref->from); } - rz_list_push(list, ut64_new(xref->from)); } rz_list_free(xrefs); } - return list; + return set; } -static RzList /**/ *get_calls(RzCore *core, RzAnalysisBlock *block) { +static RZ_OWN RzVector /**/ *get_calls(RzCore *core, RzAnalysisBlock *block) { ut8 *data = malloc(block->size); if (!data) { return NULL; } - RzList *list = NULL; + RzVector *set = rz_vector_new(sizeof(ut64), NULL, NULL); + if (!set) { + return NULL; + } RzAnalysisOp op = { 0 }; rz_io_read_at_mapped(core->io, block->addr, data, block->size); for (size_t i = 0; i < block->size; i++) { @@ -5695,19 +5701,36 @@ static RzList /**/ *get_calls(RzCore *core, RzAnalysisBlock *block) { if (ret < 1) { continue; } - if (op.type == RZ_ANALYSIS_OP_TYPE_CALL) { - if (!list) { - list = rz_list_newf(free); + if (rz_analysis_op_is_call(&op)) { + if (op.jump != UT64_MAX) { + if (!rz_vector_contains(set, &op.jump)) { + rz_vector_push(set, &op.jump); + } + } else { + // No statically known call target. + // Check if a previous analysis found any xrefs from it. + RzList *xrefs = rz_analysis_xrefs_get_from(block->analysis, op.addr); + RzAnalysisXRef *xref; + RzListIter *iter; + rz_list_foreach (xrefs, iter, xref) { + if (xref->type != RZ_ANALYSIS_XREF_TYPE_CALL) { + continue; + } + if (!rz_vector_contains(set, &xref->to)) { + rz_vector_push(set, &xref->to); + } + } + rz_list_free(xrefs); } - rz_list_push(list, ut64_new(op.jump)); } rz_analysis_op_fini(&op); if (op.size > 0) { i += op.size - 1; } } + rz_vector_sort(set, (RzVectorComparator)cmp, false, NULL); free(data); - return list; + return set; } RZ_IPI RzCmdStatus rz_analysis_basic_block_info_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { @@ -5732,8 +5755,11 @@ RZ_IPI RzCmdStatus rz_analysis_basic_block_list_handler(RzCore *core, int argc, RzAnalysisBlock *block; RBTree *bb_tree = rz_analysis_get_bb_tree(core->analysis); rz_rbtree_foreach ((*bb_tree), iter, block, RzAnalysisBlock, _rb) { - RzList *xrefs = get_xrefs(block); - RzList *calls = get_calls(core, block); + RzVector *sorted_xrefs = get_xrefs(block); + RzVector *sorted_calls = get_calls(core, block); + rz_return_val_if_fail(sorted_xrefs && sorted_calls, RZ_CMD_STATUS_ERROR); + + ut64 *addr; switch (state->mode) { case RZ_OUTPUT_MODE_JSON: pj_o(pj); @@ -5747,24 +5773,19 @@ RZ_IPI RzCmdStatus rz_analysis_basic_block_list_handler(RzCore *core, int argc, if (block->fail != UT64_MAX) { pj_kn(pj, "fail", block->fail); } - if (xrefs) { - pj_ka(pj, "xrefs"); - RzListIter *iter2; - ut64 *addr; - rz_list_foreach (xrefs, iter2, addr) { - pj_n(pj, *addr); - } - pj_end(pj); + + pj_ka(pj, "xrefs"); + rz_vector_foreach (sorted_xrefs, addr) { + pj_n(pj, *addr); } - if (calls) { - pj_ka(pj, "calls"); - RzListIter *iter2; - ut64 *addr; - rz_list_foreach (calls, iter2, addr) { - pj_n(pj, *addr); - } - pj_end(pj); + pj_end(pj); + + pj_ka(pj, "calls"); + rz_vector_foreach (sorted_calls, addr) { + pj_n(pj, *addr); } + pj_end(pj); + pj_ka(pj, "fcns"); RzListIter *iter2; RzAnalysisFunction *fcn; @@ -5777,8 +5798,8 @@ RZ_IPI RzCmdStatus rz_analysis_basic_block_list_handler(RzCore *core, int argc, case RZ_OUTPUT_MODE_TABLE: { char *jump = block->jump != UT64_MAX ? rz_str_newf("0x%08" PFMT64x, block->jump) : rz_str_dup(""); char *fail = block->fail != UT64_MAX ? rz_str_newf("0x%08" PFMT64x, block->fail) : rz_str_dup(""); - char *call = ut64join(calls); - char *xref = ut64join(calls); + char *call = ut64join(sorted_calls); + char *xref = ut64join(sorted_xrefs); char *fcns = fcnjoin(block->fcns); rz_table_add_rowf(table, "xnddsssss", block->addr, @@ -5807,21 +5828,13 @@ RZ_IPI RzCmdStatus rz_analysis_basic_block_list_handler(RzCore *core, int argc, if (block->fail != UT64_MAX) { rz_cons_printf(" .f 0x%08" PFMT64x, block->fail); } - if (xrefs) { - RzListIter *iter2; - rz_cons_printf(" .x"); - ut64 *addr; - rz_list_foreach (xrefs, iter2, addr) { - rz_cons_printf(" 0x%08" PFMT64x, *addr); - } + rz_vector_foreach (sorted_xrefs, addr) { + rz_cons_printf(" 0x%08" PFMT64x, *addr); } - if (calls) { - rz_cons_printf(" .c"); - RzListIter *iter2; - ut64 *addr; - rz_list_foreach (calls, iter2, addr) { - rz_cons_printf(" 0x%08" PFMT64x, *addr); - } + + rz_cons_printf(" .c"); + rz_vector_foreach (sorted_calls, addr) { + rz_cons_printf(" 0x%08" PFMT64x, *addr); } if (block->fcns) { RzListIter *iter2; @@ -5837,8 +5850,8 @@ RZ_IPI RzCmdStatus rz_analysis_basic_block_list_handler(RzCore *core, int argc, status = RZ_CMD_STATUS_WRONG_ARGS; iter.len = 0; } - rz_list_free(xrefs); - rz_list_free(calls); + rz_vector_free(sorted_xrefs); + rz_vector_free(sorted_calls); } rz_cmd_state_output_array_end(state); return status; diff --git a/librz/include/rz_analysis.h b/librz/include/rz_analysis.h index e1b0219805..30fa0d125a 100644 --- a/librz/include/rz_analysis.h +++ b/librz/include/rz_analysis.h @@ -1461,6 +1461,7 @@ RZ_API void rz_analysis_op_init(RzAnalysisOp *op); RZ_API bool rz_analysis_op_fini(RzAnalysisOp *op); RZ_API int rz_analysis_op_reg_delta(RzAnalysis *analysis, ut64 addr, const char *name); RZ_API bool rz_analysis_op_is_eob(const RzAnalysisOp *op); +RZ_API bool rz_analysis_op_is_call(RZ_NONNULL const RzAnalysisOp *op); RZ_API RzList /**/ *rz_analysis_op_list_new(void); RZ_API int rz_analysis_op(RZ_NONNULL RzAnalysis *analysis, RZ_OUT RzAnalysisOp *op, ut64 addr, const ut8 *data, ut64 len, RzAnalysisOpMask mask); RZ_API RzAnalysisOp *rz_analysis_op_hexstr(RzAnalysis *analysis, ut64 addr, const char *hexstr); diff --git a/test/db/cmd/cmd_ab b/test/db/cmd/cmd_ab index 35ffcf30d0..965dd148c2 100644 --- a/test/db/cmd/cmd_ab +++ b/test/db/cmd/cmd_ab @@ -23,51 +23,51 @@ inputs: 0 outputs: 2 ninstr: 14 traced: false -.-------------------------------------------------------------------------------------------------. -| addr | size | jump | calls | -)-------------------------------------------------------------------------------------------------( -| 0x1000011e8 | 41 | 0x100001216 | | -| 0x100001216 | 28 | 0x100001290 | 0x10000456a 0x100004510 | -| 0x100001232 | 27 | 0x10000125c | 0x1000044e0 | -| 0x10000124d | 5 | 0x10000125c | | -| 0x10000125c | 26 | 0x100001284 | 0x10000450a | -| 0x100001276 | 8 | 0x100001284 | | -| 0x100001290 | 24 | 0x1000012b6 | 0x1000044e0 | -| 0x1000012b6 | 9 | 0x1000012c6 | 0x1000044f2 | -| 0x1000012e7 | 26 | 0x100001682 | 0x1000044e6 | -| 0x100001370 | 34 | 0x1000012e7 | 0x10000448c | -| 0x10000141a | 37 | 0x1000012e7 | 0x10000448c | -| 0x10000144b | 27 | 0x1000012e7 | 0x10000448c | -| 0x100001492 | 23 | 0x1000014d0 | 0x10000448c | -| 0x1000015c9 | 27 | 0x1000012e3 | 0x10000448c | -| 0x100001682 | 9 | 0x1000012dc | | -| 0x10000168b | 31 | 0x1000017a6 | 0x1000044e0 | -| 0x1000016aa | 14 | 0x1000016cd | 0x100004510 | -| 0x1000016b8 | 21 | 0x1000017a6 | 0x1000044e0 | -| 0x1000016cd | 36 | 0x1000017a6 | 0x1000044e0 0x1000045a6 | -| 0x1000016f1 | 119 | 0x10000177f | 0x1000045ac 0x1000045ac 0x1000045ac 0x1000045ac 0x1000045ac | -| 0x10000177f | 10 | 0x1000017a6 | | -| 0x100001789 | 12 | 0x1000017a6 | | -| 0x100001795 | 5 | 0x1000017a6 | | -| 0x1000017a6 | 9 | 0x1000017b4 | | -| 0x1000017fe | 119 | 0x1000018c2 | | -| 0x100001875 | 9 | 0x10000188b | | -| 0x1000018c2 | 9 | 0x1000018dd | | -| 0x1000018cb | 6 | 0x1000018ef | | -| 0x1000018dd | 6 | 0x10000191c | | -| 0x1000018ef | 9 | 0x100001949 | | -| 0x1000018f8 | 9 | 0x10000195b | | -| 0x100001901 | 9 | 0x10000196d | | -| 0x10000190a | 9 | 0x10000197f | | -| 0x10000191c | 9 | 0x100001952 | | -| 0x100001925 | 9 | 0x100001964 | | -| 0x10000192e | 9 | 0x100001976 | | -| 0x100001937 | 9 | 0x100001988 | | -| 0x10000198f | 19 | 0x1000019ab | | -| 0x1000019ab | 9 | 0x1000019c6 | | -| 0x1000019b4 | 9 | 0x1000019cf | | -| 0x1000019d6 | 12 | 0x1000019f0 | | -`-------------------------------------------------------------------------------------------------' +.-------------------------------------------------------------. +| addr | size | jump | calls | +)-------------------------------------------------------------( +| 0x1000011e8 | 41 | 0x100001216 | | +| 0x100001216 | 28 | 0x100001290 | 0x100004510 0x10000456a | +| 0x100001232 | 27 | 0x10000125c | 0x1000044e0 | +| 0x10000124d | 5 | 0x10000125c | | +| 0x10000125c | 26 | 0x100001284 | 0x10000450a | +| 0x100001276 | 8 | 0x100001284 | | +| 0x100001290 | 24 | 0x1000012b6 | 0x1000044e0 | +| 0x1000012b6 | 9 | 0x1000012c6 | 0x1000044f2 | +| 0x1000012e7 | 26 | 0x100001682 | 0x1000044e6 | +| 0x100001370 | 34 | 0x1000012e7 | 0x10000448c | +| 0x10000141a | 37 | 0x1000012e7 | 0x10000448c | +| 0x10000144b | 27 | 0x1000012e7 | 0x10000448c | +| 0x100001492 | 23 | 0x1000014d0 | 0x10000448c | +| 0x1000015c9 | 27 | 0x1000012e3 | 0x10000448c | +| 0x100001682 | 9 | 0x1000012dc | | +| 0x10000168b | 31 | 0x1000017a6 | 0x1000044e0 | +| 0x1000016aa | 14 | 0x1000016cd | 0x100004510 | +| 0x1000016b8 | 21 | 0x1000017a6 | 0x1000044e0 | +| 0x1000016cd | 36 | 0x1000017a6 | 0x1000044e0 0x1000045a6 | +| 0x1000016f1 | 119 | 0x10000177f | 0x1000045ac | +| 0x10000177f | 10 | 0x1000017a6 | | +| 0x100001789 | 12 | 0x1000017a6 | | +| 0x100001795 | 5 | 0x1000017a6 | | +| 0x1000017a6 | 9 | 0x1000017b4 | | +| 0x1000017fe | 119 | 0x1000018c2 | | +| 0x100001875 | 9 | 0x10000188b | | +| 0x1000018c2 | 9 | 0x1000018dd | | +| 0x1000018cb | 6 | 0x1000018ef | | +| 0x1000018dd | 6 | 0x10000191c | | +| 0x1000018ef | 9 | 0x100001949 | | +| 0x1000018f8 | 9 | 0x10000195b | | +| 0x100001901 | 9 | 0x10000196d | | +| 0x10000190a | 9 | 0x10000197f | | +| 0x10000191c | 9 | 0x100001952 | | +| 0x100001925 | 9 | 0x100001964 | | +| 0x10000192e | 9 | 0x100001976 | | +| 0x100001937 | 9 | 0x100001988 | | +| 0x10000198f | 19 | 0x1000019ab | | +| 0x1000019ab | 9 | 0x1000019c6 | | +| 0x1000019b4 | 9 | 0x1000019cf | | +| 0x1000019d6 | 12 | 0x1000019f0 | | +`-------------------------------------------------------------' 116 1 794 @@ -82,188 +82,330 @@ aa ablt:addr/cols/xrefs:xrefs/str/0x:fancy EOF EXPECT=<