diff --git a/librz/core/canalysis.c b/librz/core/canalysis.c index f9c8befae15..b07c3555432 100644 --- a/librz/core/canalysis.c +++ b/librz/core/canalysis.c @@ -364,11 +364,16 @@ static ut64 __opaddr(RzAnalysisBlock *b, ut64 addr) { return UT64_MAX; } -static void bb_info_print(RzCore *core, RzAnalysisFunction *fcn, RzAnalysisBlock *bb, +static RZ_OWN char *bb_info_to_string(RzCore *core, RzAnalysisFunction *fcn, RzAnalysisBlock *bb, ut64 addr, RzOutputMode mode, PJ *pj, RzTable *t) { RzDebugTracepoint *tp = NULL; + RzStrBuf *buf = rz_strbuf_new(""); + if (!buf) { + return NULL; + } int outputs = (bb->jump != UT64_MAX) + (bb->fail != UT64_MAX); int inputs = 0; + char *table_str = NULL; void **iter; RzAnalysisBlock *bb2; @@ -386,26 +391,26 @@ static void bb_info_print(RzCore *core, RzAnalysisFunction *fcn, RzAnalysisBlock switch (mode) { case RZ_OUTPUT_MODE_STANDARD: tp = rz_debug_trace_get(core->dbg, bb->addr); - rz_cons_printf("0x%08" PFMT64x " 0x%08" PFMT64x " %02X:%04X %" PFMT64d, + rz_strbuf_appendf(buf, "0x%08" PFMT64x " 0x%08" PFMT64x " %02X:%04X %" PFMT64d, bb->addr, bb->addr + bb->size, tp ? tp->times : 0, tp ? tp->count : 0, bb->size); if (bb->jump != UT64_MAX) { - rz_cons_printf(" j 0x%08" PFMT64x, bb->jump); + rz_strbuf_appendf(buf, " j 0x%08" PFMT64x, bb->jump); } if (bb->fail != UT64_MAX) { - rz_cons_printf(" f 0x%08" PFMT64x, bb->fail); + rz_strbuf_appendf(buf, " f 0x%08" PFMT64x, bb->fail); } if (bb->switch_op) { RzAnalysisCaseOp *cop; RzListIter *iter; RzList *unique_cases = rz_list_uniq(bb->switch_op->cases, casecmp, NULL); rz_list_foreach (unique_cases, iter, cop) { - rz_cons_printf(" s 0x%08" PFMT64x, cop->addr); + rz_strbuf_appendf(buf, " s 0x%08" PFMT64x, cop->addr); } rz_list_free(unique_cases); } - rz_cons_newline(); + rz_strbuf_append(buf, "\n"); break; case RZ_OUTPUT_MODE_JSON: { pj_o(pj); @@ -446,26 +451,31 @@ static void bb_info_print(RzCore *core, RzAnalysisFunction *fcn, RzAnalysisBlock pj_ki(pj, "ninstr", bb->ninstr); pj_kb(pj, "traced", bb->traced); pj_end(pj); + char *json_str = rz_str_dup(pj_string(pj)); + pj_free(pj); + rz_strbuf_append(buf, json_str); break; } case RZ_OUTPUT_MODE_TABLE: - rz_table_add_rowf(t, "xdxx", bb->addr, bb->size, bb->jump, bb->fail); + table_str = rz_table_tostring(t); + rz_strbuf_append(buf, table_str); + RZ_FREE(table_str); break; case RZ_OUTPUT_MODE_RIZIN: - rz_cons_printf("f bb.%05" PFMT64x " @ 0x%08" PFMT64x "\n", bb->addr & 0xFFFFF, bb->addr); + rz_strbuf_appendf(buf, "f bb.%05" PFMT64x " @ 0x%08" PFMT64x "\n", bb->addr & 0xFFFFF, bb->addr); break; case RZ_OUTPUT_MODE_QUIET: - rz_cons_printf("0x%08" PFMT64x "\n", bb->addr); + rz_strbuf_appendf(buf, "0x%08" PFMT64x "\n", bb->addr); break; case RZ_OUTPUT_MODE_LONG: { if (bb->jump != UT64_MAX) { - rz_cons_printf("jump: 0x%08" PFMT64x "\n", bb->jump); + rz_strbuf_appendf(buf, "jump: 0x%08" PFMT64x "\n", bb->jump); } if (bb->fail != UT64_MAX) { - rz_cons_printf("fail: 0x%08" PFMT64x "\n", bb->fail); + rz_strbuf_appendf(buf, "fail: 0x%08" PFMT64x "\n", bb->fail); } - rz_cons_printf("opaddr: 0x%08" PFMT64x "\n", opaddr); - rz_cons_printf("addr: 0x%08" PFMT64x "\nsize: %" PFMT64d "\ninputs: %d\noutputs: %d\nninstr: %d\ntraced: %s\n", + rz_strbuf_appendf(buf, "opaddr: 0x%08" PFMT64x "\n", opaddr); + rz_strbuf_appendf(buf, "addr: 0x%08" PFMT64x "\nsize: %" PFMT64d "\ninputs: %d\noutputs: %d\nninstr: %d\ntraced: %s\n", bb->addr, bb->size, inputs, outputs, bb->ninstr, rz_str_bool(bb->traced)); break; } @@ -473,6 +483,8 @@ static void bb_info_print(RzCore *core, RzAnalysisFunction *fcn, RzAnalysisBlock rz_warn_if_reached(); break; } + + return rz_strbuf_drain(buf); } static int bb_cmp(const void *a, const void *b, void *user) { @@ -481,30 +493,41 @@ static int bb_cmp(const void *a, const void *b, void *user) { return ba->addr - bb->addr; } -RZ_IPI void rz_core_analysis_bbs_info_print(RzCore *core, RzAnalysisFunction *fcn, RzCmdStateOutput *state) { - rz_return_if_fail(core && fcn && state); +RZ_IPI RZ_OWN char *rz_core_analysis_bbs_as_string(RzCore *core, RzAnalysisFunction *fcn, RzCmdStateOutput *state) { + rz_return_val_if_fail(core && fcn && state, NULL); void **iter; RzAnalysisBlock *bb; + RzStrBuf *buf = rz_strbuf_new(""); + if (!buf) { + return NULL; + } rz_cmd_state_output_array_start(state); rz_cmd_state_output_set_columnsf(state, "xdxx", "addr", "size", "jump", "fail"); if (state->mode == RZ_OUTPUT_MODE_RIZIN) { - rz_cons_printf("fs blocks\n"); + rz_strbuf_append(buf, "fs blocks\n"); } rz_pvector_sort(fcn->bbs, bb_cmp, NULL); rz_pvector_foreach (fcn->bbs, iter) { bb = (RzAnalysisBlock *)*iter; - bb_info_print(core, fcn, bb, bb->addr, state->mode, state->d.pj, state->d.t); + char *bb_info = bb_info_to_string(core, fcn, bb, bb->addr, state->mode, state->d.pj, state->d.t); + rz_strbuf_append(buf, bb_info); + RZ_FREE(bb_info); } rz_cmd_state_output_array_end(state); + return rz_strbuf_drain(buf); } RZ_IPI void rz_core_analysis_bb_info_print(RzCore *core, RzAnalysisBlock *bb, ut64 addr, RzCmdStateOutput *state) { rz_return_if_fail(core && bb && state); rz_cmd_state_output_set_columnsf(state, "xdxx", "addr", "size", "jump", "fail"); RzAnalysisFunction *fcn = rz_list_first(bb->fcns); - bb_info_print(core, fcn, bb, addr, state->mode, state->d.pj, state->d.t); + char *bb_info = bb_info_to_string(core, fcn, bb, addr, state->mode, state->d.pj, state->d.t); + if (bb_info) { + rz_cons_printf("%s", bb_info); + RZ_FREE(bb_info); + } } /*this only autoname those function that start with fcn.* or sym.func.* */ diff --git a/librz/core/cmd/cmd_analysis.c b/librz/core/cmd/cmd_analysis.c index 285f94c7eb2..9235226ccf8 100644 --- a/librz/core/cmd/cmd_analysis.c +++ b/librz/core/cmd/cmd_analysis.c @@ -2095,7 +2095,11 @@ RZ_IPI RzCmdStatus rz_analysis_function_blocks_list_handler(RzCore *core, int ar if (!fcn) { return RZ_CMD_STATUS_ERROR; } - rz_core_analysis_bbs_info_print(core, fcn, state); + char *info = rz_core_analysis_bbs_as_string(core, fcn, state); + if (info) { + rz_cons_println(info); + RZ_FREE(info); + } return RZ_CMD_STATUS_OK; } diff --git a/librz/core/core.c b/librz/core/core.c index 780753403f8..45fc773a926 100644 --- a/librz/core/core.c +++ b/librz/core/core.c @@ -2445,4 +2445,4 @@ RZ_API RzCmdStatus rz_core_core_plugins_print(RzCore *core, RzCmdStateOutput *st } rz_cmd_state_output_array_end(state); return RZ_CMD_STATUS_OK; -} +} \ No newline at end of file diff --git a/librz/core/core_private.h b/librz/core/core_private.h index 023435cf60d..c6d15fd86e7 100644 --- a/librz/core/core_private.h +++ b/librz/core/core_private.h @@ -42,7 +42,7 @@ RZ_IPI bool rz_core_analysis_function_set_signature(RzCore *core, RzAnalysisFunc RZ_IPI void rz_core_analysis_function_signature_editor(RzCore *core, ut64 addr); RZ_IPI void rz_core_analysis_bbs_asciiart(RzCore *core, RzAnalysisFunction *fcn); RZ_IPI void rz_core_analysis_fcn_returns(RzCore *core, RzAnalysisFunction *fcn); -RZ_IPI void rz_core_analysis_bbs_info_print(RzCore *core, RzAnalysisFunction *fcn, RzCmdStateOutput *state); +RZ_IPI RZ_OWN char *rz_core_analysis_bbs_as_string(RzCore *core, RzAnalysisFunction *fcn, RzCmdStateOutput *state); RZ_IPI void rz_core_analysis_bb_info_print(RzCore *core, RzAnalysisBlock *bb, ut64 addr, RzCmdStateOutput *state); RZ_IPI void rz_core_analysis_function_until(RzCore *core, ut64 addr_end); RZ_IPI void rz_core_analysis_value_pointers(RzCore *core, RzOutputMode mode); diff --git a/librz/core/tui/visual.c b/librz/core/tui/visual.c index 7424163c7fa..99da3ee088a 100644 --- a/librz/core/tui/visual.c +++ b/librz/core/tui/visual.c @@ -1901,6 +1901,73 @@ static bool insert_mode_enabled(RzCore *core) { return true; } +static char *function_basic_blocks_string(RZ_NONNULL RzCore *core, RZ_NONNULL RzAnalysisFunction *fcn) { + rz_return_val_if_fail(core && fcn, NULL); + RzCmdStateOutput state; + state.mode = RZ_OUTPUT_MODE_STANDARD; + char *fcn_info = rz_core_analysis_bbs_as_string(core, fcn, &state); + return fcn_info; +} + +/** + * \brief Seeks to any basic block of the current function. + * + * \param core The RzCore instance. + */ +static void view_and_seek_to_bb(RZ_NONNULL RzCore *core) { + rz_return_if_fail(core); + RzAnalysisFunction *fcn = rz_analysis_get_fcn_in(core->analysis, core->offset, 0); + if (!fcn) { + return; + } + char *bbs_string = function_basic_blocks_string(core, fcn); + char *output = rz_str_filter_apply(bbs_string, ""); + RZ_FREE(bbs_string); + if (!output) { + return; + } + rz_cons_println(output); + rz_cons_flush(); + char *input = rz_cons_input("Seek to address: "); + if (RZ_STR_ISEMPTY(input)) { + return; + } + ut64 addr = strtoull(input, NULL, 16); + RZ_FREE(input); + RZ_FREE(output); + RzAnalysisBlock *bb; + void **iter; + rz_pvector_foreach (fcn->bbs, iter) { + bb = *iter; + if (bb->addr <= addr && addr < bb->addr + bb->size) { + rz_core_seek(core, addr, true); + break; + } + } +} + +/** + * \brief Displays the available themes and sets the chosen theme. + * + * \param core The RzCore instance. + */ +static void view_and_set_theme(RZ_NONNULL RzCore *core) { + rz_return_if_fail(core); + RzList *themes = rz_core_theme_list(core); + char *themes_str = rz_str_list_join(themes, "\n"); + themes_str = rz_str_append(themes_str, "\n"); + rz_list_free(themes); + rz_cons_println(themes_str); + rz_cons_flush(); + RZ_FREE(themes_str); + char *input = rz_cons_input("Choose A Theme: "); + if (RZ_STR_ISEMPTY(input)) { + return; + } + rz_core_theme_load(core, input); + RZ_FREE(input); +} + RZ_IPI void rz_core_visual_browse(RzCore *core, const char *input) { const char *browsemsg = "Browse stuff:\n" @@ -1981,13 +2048,13 @@ RZ_IPI void rz_core_visual_browse(RzCore *core, const char *input) { rz_core_visual_comments(core); break; case 'T': // "vbT" - rz_core_cmd0(core, "eco $(eco~...)"); + view_and_set_theme(core); break; case 'p': rz_debug_switch_to_first_thread(core->dbg); break; case 'b': - rz_core_cmd0(core, "s $(afb~...)"); + view_and_seek_to_bb(core); break; case 'i': // XXX ii shows index first and iiq shows no offset :( diff --git a/librz/include/rz_util/rz_str.h b/librz/include/rz_util/rz_str.h index 5133aed15ff..a30c0b88a20 100644 --- a/librz/include/rz_util/rz_str.h +++ b/librz/include/rz_util/rz_str.h @@ -89,6 +89,7 @@ RZ_API size_t rz_str_utf8_charsize(const char *str); RZ_API size_t rz_str_utf8_charsize_prev(const char *str, int prev_len); RZ_API size_t rz_str_utf8_charsize_last(const char *str); RZ_API void rz_str_filter_zeroline(char *str, int len); +RZ_API RZ_OWN char *rz_str_filter_apply(RZ_NONNULL const char *str, const char *filter); RZ_API size_t rz_str_utf8_codepoint(const char *s, size_t left); RZ_API bool rz_str_char_fullwidth(const char *s, size_t left); RZ_API int rz_str_write(int fd, const char *b); diff --git a/librz/util/str.c b/librz/util/str.c index 7a7b3c0f08e..9fd1c8fa5eb 100644 --- a/librz/util/str.c +++ b/librz/util/str.c @@ -2418,6 +2418,12 @@ RZ_API size_t rz_str_utf8_charsize_last(const char *str) { return rz_str_utf8_charsize_prev(str + len, len); } +/** + * \brief Filters out non-printable characters and newlines from the given string. + * + * \param str The string to be filtered. This string is modified in-place. + * \param len The maximum length of the string to consider for filtering. + */ RZ_API void rz_str_filter_zeroline(char *str, int len) { int i; for (i = 0; i < len && str[i]; i++) { @@ -4300,3 +4306,31 @@ RZ_API const char *rz_str_indent(int indent) { } return indent_tbl[indent]; } + +/** + * \brief Filters the given string based on the provided filter. + * + * \param str The string to be filtered. + * \param filter The filter string to be used for filtering the str. + * \return char* The filtered string. The caller is responsible for freeing this string. + */ +RZ_API RZ_OWN char *rz_str_filter_apply(RZ_NONNULL const char *str, const char *filter) { + rz_return_val_if_fail(str, NULL); + char *filtered_str = NULL; + char *str_copy = rz_str_dup(str); + RzList *lines = rz_str_split_list(str_copy, "\n", 0); + RzListIter *iter; + char *line; + rz_list_foreach (lines, iter, line) { + if (strstr(line, filter)) { + if (filtered_str) { + filtered_str = rz_str_append(filtered_str, "\n"); + } else { + filtered_str = rz_str_dup(""); + } + filtered_str = rz_str_append(filtered_str, line); + } + } + RZ_FREE(str_copy); + return filtered_str; +} \ No newline at end of file