From 10472cfbd84fe7f612b7ba1113a61bd7eb4780ba Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Wed, 7 Sep 2022 16:30:54 +0800 Subject: [PATCH 1/4] Move ESIL and analysis APIs to the corresponding places --- librz/core/canalysis.c | 139 +++++++++++ librz/core/cesil.c | 328 ++++++++++++++++++++++++ librz/core/cmd/cmd_analysis.c | 455 ---------------------------------- librz/core/meson.build | 1 + 4 files changed, 468 insertions(+), 455 deletions(-) create mode 100644 librz/core/cesil.c diff --git a/librz/core/canalysis.c b/librz/core/canalysis.c index 65afdc519f2..05b9ad6aa37 100644 --- a/librz/core/canalysis.c +++ b/librz/core/canalysis.c @@ -6191,3 +6191,142 @@ RZ_API RZ_OWN RzCoreAnalysisName *rz_core_analysis_name(RZ_NONNULL RzCore *core, return p; } + +static void _analysis_calls(RzCore *core, ut64 addr, ut64 addr_end, bool imports_only) { + RzAnalysisOp op; + int depth = rz_config_get_i(core->config, "analysis.depth"); + const int addrbytes = core->io->addrbytes; + const int bsz = 4096; + int bufi = 0; + int bufi_max = bsz - 16; + if (addr_end - addr > UT32_MAX) { + return; + } + ut8 *buf = malloc(bsz); + ut8 *block0 = calloc(1, bsz); + ut8 *block1 = malloc(bsz); + if (!buf || !block0 || !block1) { + RZ_LOG_ERROR("core: cannot allocate buf or block\n"); + free(buf); + free(block0); + free(block1); + return; + } + memset(block1, -1, bsz); + int minop = rz_analysis_archinfo(core->analysis, RZ_ANALYSIS_ARCHINFO_MIN_OP_SIZE); + if (minop < 1) { + minop = 1; + } + int setBits = rz_config_get_i(core->config, "asm.bits"); + rz_cons_break_push(NULL, NULL); + while (addr < addr_end && !rz_cons_is_breaked()) { + // TODO: too many ioreads here + if (bufi > bufi_max) { + bufi = 0; + } + if (!bufi) { + (void)rz_io_read_at(core->io, addr, buf, bsz); + } + if (!memcmp(buf, block0, bsz) || !memcmp(buf, block1, bsz)) { + // eprintf ("Error: skipping uninitialized block \n"); + addr += bsz; + continue; + } + RzAnalysisHint *hint = rz_analysis_hint_get(core->analysis, addr); + if (hint && hint->bits) { + setBits = hint->bits; + } + rz_analysis_hint_free(hint); + if (setBits != core->rasm->bits) { + rz_config_set_i(core->config, "asm.bits", setBits); + } + if (rz_analysis_op(core->analysis, &op, addr, buf + bufi, bsz - bufi, 0) > 0) { + if (op.size < 1) { + op.size = minop; + } + if (op.type == RZ_ANALYSIS_OP_TYPE_CALL) { + bool isValidCall = true; + if (imports_only) { + RzFlagItem *f = rz_flag_get_i(core->flags, op.jump); + if (!f || !strstr(f->name, "imp.")) { + isValidCall = false; + } + } + RzBinReloc *rel = rz_core_getreloc(core, addr, op.size); + if (rel && (rel->import || rel->symbol)) { + isValidCall = false; + } + if (isValidCall) { + ut8 buf[4]; + rz_io_read_at(core->io, op.jump, buf, 4); + isValidCall = memcmp(buf, "\x00\x00\x00\x00", 4); + } + if (isValidCall) { + // add xref here + rz_analysis_xrefs_set(core->analysis, addr, op.jump, RZ_ANALYSIS_XREF_TYPE_CALL); + if (rz_io_is_valid_offset(core->io, op.jump, 1)) { + rz_core_analysis_fcn(core, op.jump, addr, RZ_ANALYSIS_XREF_TYPE_CALL, depth); + } + } + } + } else { + op.size = minop; + } + if ((int)op.size < 1) { + op.size = minop; + } + addr += op.size; + bufi += addrbytes * op.size; + rz_analysis_op_fini(&op); + } + rz_cons_break_pop(); + free(buf); + free(block0); + free(block1); +} + +/* + * \brief Performs analysis on each call sight, creates new functions whenever necessary. + * \param core RzCore instance + * \param imports_only if true it analyses calls only of imported functions, otherwise - every flag + */ +RZ_API void rz_core_analysis_calls(RZ_NONNULL RzCore *core, bool imports_only) { + rz_return_if_fail(core); + + RzList *ranges = NULL; + RzIOMap *r; + ut64 addr; + RzBinFile *binfile = rz_bin_cur(core->bin); + addr = core->offset; + if (binfile) { + ranges = rz_core_get_boundaries_prot(core, RZ_PERM_X, NULL, "analysis"); + } + rz_cons_break_push(NULL, NULL); + if (!binfile || rz_list_length(ranges) < 1) { + RzListIter *iter; + RzIOMap *map; + rz_list_free(ranges); + ranges = rz_core_get_boundaries_prot(core, 0, NULL, "analysis"); + if (ranges) { + rz_list_foreach (ranges, iter, map) { + ut64 addr = map->itv.addr; + _analysis_calls(core, addr, rz_itv_end(map->itv), imports_only); + } + } + } else { + RzListIter *iter; + if (binfile) { + rz_list_foreach (ranges, iter, r) { + addr = r->itv.addr; + // this normally will happen on fuzzed binaries, dunno if with huge + // binaries as well + if (rz_cons_is_breaked()) { + break; + } + _analysis_calls(core, addr, rz_itv_end(r->itv), imports_only); + } + } + } + rz_cons_break_pop(); + rz_list_free(ranges); +} diff --git a/librz/core/cesil.c b/librz/core/cesil.c new file mode 100644 index 00000000000..3b67e41e7ec --- /dev/null +++ b/librz/core/cesil.c @@ -0,0 +1,328 @@ +// SPDX-FileCopyrightText: 2009-2021 pancake +// SPDX-FileCopyrightText: 2009-2021 maijin +// SPDX-License-Identifier: LGPL-3.0-only + +#include + +#include "../core_private.h" + +static ut64 initializeEsil(RzCore *core) { + int romem = rz_config_get_i(core->config, "esil.romem"); + int stats = rz_config_get_i(core->config, "esil.stats"); + int iotrap = rz_config_get_i(core->config, "esil.iotrap"); + int exectrap = rz_config_get_i(core->config, "esil.exectrap"); + int stacksize = rz_config_get_i(core->config, "esil.stack.depth"); + int noNULL = rz_config_get_i(core->config, "esil.noNULL"); + unsigned int addrsize = rz_config_get_i(core->config, "esil.addr.size"); + if (!(core->analysis->esil = rz_analysis_esil_new(stacksize, iotrap, addrsize))) { + return UT64_MAX; + } + ut64 addr; + RzAnalysisEsil *esil = core->analysis->esil; + esil->verbose = rz_config_get_i(core->config, "esil.verbose"); + esil->cmd = rz_core_esil_cmd; + rz_analysis_esil_setup(esil, core->analysis, romem, stats, noNULL); // setup io + { + const char *cmd_esil_step = rz_config_get(core->config, "cmd.esil.step"); + if (cmd_esil_step && *cmd_esil_step) { + esil->cmd_step = strdup(cmd_esil_step); + } + const char *cmd_esil_step_out = rz_config_get(core->config, "cmd.esil.stepout"); + if (cmd_esil_step_out && *cmd_esil_step_out) { + esil->cmd_step_out = strdup(cmd_esil_step_out); + } + { + const char *s = rz_config_get(core->config, "cmd.esil.intr"); + if (s) { + char *my = strdup(s); + if (my) { + rz_config_set(core->config, "cmd.esil.intr", my); + free(my); + } + } + } + } + esil->exectrap = exectrap; + RzList *entries = rz_bin_get_entries(core->bin); + RzBinAddr *entry = NULL; + RzBinInfo *info = NULL; + if (entries && !rz_list_empty(entries)) { + entry = (RzBinAddr *)rz_list_pop_head(entries); + info = rz_bin_get_info(core->bin); + addr = info->has_va ? entry->vaddr : entry->paddr; + rz_list_push(entries, entry); + } else { + addr = core->offset; + } + // set memory read only + return addr; +} + +RZ_API int rz_core_esil_step(RzCore *core, ut64 until_addr, const char *until_expr, ut64 *prev_addr, bool stepOver) { +#define return_tail(x) \ + { \ + tail_return_value = x; \ + goto tail_return; \ + } + int tail_return_value = 0; + int ret; + ut8 code[32]; + RzAnalysisOp op = { 0 }; + RzAnalysisEsil *esil = core->analysis->esil; + const char *name = rz_reg_get_name(core->analysis->reg, RZ_REG_NAME_PC); + ut64 addr = 0; + bool breakoninvalid = rz_config_get_i(core->config, "esil.breakoninvalid"); + int esiltimeout = rz_config_get_i(core->config, "esil.timeout"); + ut64 startTime; + + if (esiltimeout > 0) { + startTime = rz_time_now_mono(); + } + rz_cons_break_push(NULL, NULL); +repeat: + if (rz_cons_is_breaked()) { + RZ_LOG_WARN("core: esil: emulation interrupted at 0x%08" PFMT64x "\n", addr); + return_tail(0); + } + // Break if we have exceeded esil.timeout + if (esiltimeout > 0) { + ut64 elapsedTime = rz_time_now_mono() - startTime; + elapsedTime >>= 20; + if (elapsedTime >= esiltimeout) { + RZ_LOG_WARN("core: esil: timeout exceeded.\n"); + return_tail(0); + } + } + if (!esil) { + addr = initializeEsil(core); + esil = core->analysis->esil; + if (!esil) { + return_tail(0); + } + } else { + esil->trap = 0; + addr = rz_reg_getv(core->analysis->reg, name); + // eprintf ("PC=0x%"PFMT64x"\n", (ut64)addr); + } + if (prev_addr) { + *prev_addr = addr; + } + if (esil->exectrap) { + if (!rz_io_is_valid_offset(core->io, addr, RZ_PERM_X)) { + esil->trap = RZ_ANALYSIS_TRAP_EXEC_ERR; + esil->trap_code = addr; + RZ_LOG_ERROR("core: esil: Trap, trying to execute on non-executable memory\n"); + return_tail(1); + } + } + rz_asm_set_pc(core->rasm, addr); + + (void)rz_io_read_at_mapped(core->io, addr, code, sizeof(code)); + // TODO: sometimes this is dupe + ret = rz_analysis_op(core->analysis, &op, addr, code, sizeof(code), RZ_ANALYSIS_OP_MASK_ESIL | RZ_ANALYSIS_OP_MASK_HINT); + // if type is JMP then we execute the next N instructions + // update the esil pointer because RzAnalysis.op() can change it + esil = core->analysis->esil; + if (op.size < 1 || ret < 1) { + if (esil->cmd && esil->cmd_trap) { + esil->cmd(esil, esil->cmd_trap, addr, RZ_ANALYSIS_TRAP_INVALID); + } + if (breakoninvalid) { + RZ_LOG_ERROR("core: esil: Stopped execution in an invalid instruction (see e??esil.breakoninvalid)\n"); + return_tail(0); + } + op.size = 1; // avoid inverted stepping + } + if (stepOver) { + switch (op.type) { + case RZ_ANALYSIS_OP_TYPE_SWI: + case RZ_ANALYSIS_OP_TYPE_UCALL: + case RZ_ANALYSIS_OP_TYPE_CALL: + case RZ_ANALYSIS_OP_TYPE_JMP: + case RZ_ANALYSIS_OP_TYPE_RCALL: + case RZ_ANALYSIS_OP_TYPE_RJMP: + case RZ_ANALYSIS_OP_TYPE_CJMP: + case RZ_ANALYSIS_OP_TYPE_RET: + case RZ_ANALYSIS_OP_TYPE_CRET: + case RZ_ANALYSIS_OP_TYPE_UJMP: + if (addr == until_addr) { + return_tail(0); + } else { + rz_reg_setv(core->analysis->reg, "PC", op.addr + op.size); + } + return 1; + } + } + rz_reg_setv(core->analysis->reg, name, addr + op.size); + if (ret) { + rz_analysis_esil_set_pc(esil, addr); + const char *e = RZ_STRBUF_SAFEGET(&op.esil); + if (core->dbg->trace->enabled) { + RzReg *reg = core->dbg->reg; + core->dbg->reg = core->analysis->reg; + rz_debug_trace_op(core->dbg, &op); + core->dbg->reg = reg; + } else if (RZ_STR_ISNOTEMPTY(e)) { + rz_analysis_esil_parse(esil, e); + if (core->analysis->cur && core->analysis->cur->esil_post_loop) { + core->analysis->cur->esil_post_loop(esil, &op); + } + rz_analysis_esil_stack_free(esil); + } + bool isNextFall = false; + if (op.type == RZ_ANALYSIS_OP_TYPE_CJMP) { + ut64 pc = rz_reg_getv(core->analysis->reg, name); + if (pc == addr + op.size) { + // do not opdelay here + isNextFall = true; + } + } + // only support 1 slot for now + if (op.delay && !isNextFall) { + ut8 code2[32]; + ut64 naddr = addr + op.size; + RzAnalysisOp op2 = { 0 }; + // emulate only 1 instruction + rz_analysis_esil_set_pc(esil, naddr); + (void)rz_io_read_at(core->io, naddr, code2, sizeof(code2)); + // TODO: sometimes this is dupe + ret = rz_analysis_op(core->analysis, &op2, naddr, code2, sizeof(code2), RZ_ANALYSIS_OP_MASK_ESIL | RZ_ANALYSIS_OP_MASK_HINT); + if (ret > 0) { + switch (op2.type) { + case RZ_ANALYSIS_OP_TYPE_CJMP: + case RZ_ANALYSIS_OP_TYPE_JMP: + case RZ_ANALYSIS_OP_TYPE_CRET: + case RZ_ANALYSIS_OP_TYPE_RET: + // branches are illegal in a delay slot + esil->trap = RZ_ANALYSIS_TRAP_EXEC_ERR; + esil->trap_code = addr; + RZ_LOG_WARN("core: ESIL: Trap, trying to execute a branch in a delay slot\n"); + return_tail(1); + break; + } + const char *e = RZ_STRBUF_SAFEGET(&op2.esil); + if (RZ_STR_ISNOTEMPTY(e)) { + rz_analysis_esil_parse(esil, e); + } + } else { + RZ_LOG_ERROR("core: Invalid instruction at 0x%08" PFMT64x "\n", naddr); + } + rz_analysis_op_fini(&op2); + } + tail_return_value = 1; + } + // esil->verbose ? + // eprintf ("REPE 0x%llx %s => 0x%llx\n", addr, RZ_STRBUF_SAFEGET (&op.esil), rz_reg_getv (core->analysis->reg, "PC")); + + ut64 pc = rz_reg_getv(core->analysis->reg, name); + if (core->analysis->pcalign > 0) { + pc -= (pc % core->analysis->pcalign); + rz_reg_setv(core->analysis->reg, name, pc); + } + + st64 follow = (st64)rz_config_get_i(core->config, "dbg.follow"); + if (follow > 0) { + ut64 pc = rz_reg_getv(core->analysis->reg, name); + if ((pc < core->offset) || (pc > (core->offset + follow))) { + rz_core_seek_to_register(core, "PC", false); + } + } + // check breakpoints + if (rz_bp_get_at(core->dbg->bp, pc)) { + rz_cons_printf("[ESIL] hit breakpoint at 0x%" PFMT64x "\n", pc); + return_tail(0); + } + // check addr + if (until_addr != UT64_MAX) { + if (pc == until_addr) { + return_tail(0); + } + goto repeat; + } + // check esil + if (esil && esil->trap) { + if (core->analysis->esil->verbose) { + RZ_LOG_WARN("core: TRAP\n"); + } + return_tail(0); + } + if (until_expr) { + if (rz_analysis_esil_condition(core->analysis->esil, until_expr)) { + if (core->analysis->esil->verbose) { + RZ_LOG_WARN("core: ESIL BREAK!\n"); + } + return_tail(0); + } + goto repeat; + } +tail_return: + rz_analysis_op_fini(&op); + rz_cons_break_pop(); + return tail_return_value; +} + +RZ_API int rz_core_esil_step_back(RzCore *core) { + rz_return_val_if_fail(core->analysis->esil && core->analysis->esil->trace, -1); + RzAnalysisEsil *esil = core->analysis->esil; + if (esil->trace->idx > 0) { + rz_analysis_esil_trace_restore(esil, esil->trace->idx - 1); + rz_core_reg_update_flags(core); + return 1; + } + return 0; +} + +RZ_API bool rz_core_esil_continue_back(RZ_NONNULL RzCore *core) { + rz_return_val_if_fail(core->analysis->esil && core->analysis->esil->trace, false); + RzAnalysisEsil *esil = core->analysis->esil; + if (esil->trace->idx == 0) { + return true; + } + + RzRegItem *ripc = rz_reg_get(esil->analysis->reg, "PC", -1); + RzVector *vreg = ht_up_find(esil->trace->registers, ripc->offset | (ripc->arena << 16), NULL); + if (!vreg) { + RZ_LOG_ERROR("failed to find PC change vector\n"); + return false; + } + + // Search for the nearest breakpoint in the tracepoints before the current position + bool bp_found = false; + int idx = 0; + RzAnalysisEsilRegChange *reg; + rz_vector_foreach_prev(vreg, reg) { + if (reg->idx >= esil->trace->idx) { + continue; + } + bp_found = rz_bp_get_in(core->dbg->bp, reg->data, RZ_PERM_X) != NULL; + if (bp_found) { + idx = reg->idx; + RZ_LOG_WARN("core: hit breakpoint at: 0x%" PFMT64x " idx: %d\n", reg->data, reg->idx); + break; + } + } + + // Return to the nearest breakpoint or jump back to the first index if a breakpoint wasn't found + rz_analysis_esil_trace_restore(esil, idx); + + rz_core_reg_update_flags(core); + + return true; +} + +RZ_API bool rz_core_esil_dumpstack(RzAnalysisEsil *esil) { + rz_return_val_if_fail(esil, false); + int i; + if (esil->trap) { + rz_cons_printf("ESIL TRAP type %d code 0x%08x %s\n", + esil->trap, esil->trap_code, + rz_analysis_esil_trapstr(esil->trap)); + } + if (esil->stackptr < 1) { + return false; + } + for (i = esil->stackptr - 1; i >= 0; i--) { + rz_cons_printf("%s\n", esil->stack[i]); + } + return true; +} diff --git a/librz/core/cmd/cmd_analysis.c b/librz/core/cmd/cmd_analysis.c index dd7e3e1a895..640e63a6050 100644 --- a/librz/core/cmd/cmd_analysis.c +++ b/librz/core/cmd/cmd_analysis.c @@ -753,310 +753,6 @@ static char *ut64join(RzList *list) { return s; } -static ut64 initializeEsil(RzCore *core) { - int romem = rz_config_get_i(core->config, "esil.romem"); - int stats = rz_config_get_i(core->config, "esil.stats"); - int iotrap = rz_config_get_i(core->config, "esil.iotrap"); - int exectrap = rz_config_get_i(core->config, "esil.exectrap"); - int stacksize = rz_config_get_i(core->config, "esil.stack.depth"); - int noNULL = rz_config_get_i(core->config, "esil.noNULL"); - unsigned int addrsize = rz_config_get_i(core->config, "esil.addr.size"); - if (!(core->analysis->esil = rz_analysis_esil_new(stacksize, iotrap, addrsize))) { - return UT64_MAX; - } - ut64 addr; - RzAnalysisEsil *esil = core->analysis->esil; - esil->verbose = rz_config_get_i(core->config, "esil.verbose"); - esil->cmd = rz_core_esil_cmd; - rz_analysis_esil_setup(esil, core->analysis, romem, stats, noNULL); // setup io - { - const char *cmd_esil_step = rz_config_get(core->config, "cmd.esil.step"); - if (cmd_esil_step && *cmd_esil_step) { - esil->cmd_step = strdup(cmd_esil_step); - } - const char *cmd_esil_step_out = rz_config_get(core->config, "cmd.esil.stepout"); - if (cmd_esil_step_out && *cmd_esil_step_out) { - esil->cmd_step_out = strdup(cmd_esil_step_out); - } - { - const char *s = rz_config_get(core->config, "cmd.esil.intr"); - if (s) { - char *my = strdup(s); - if (my) { - rz_config_set(core->config, "cmd.esil.intr", my); - free(my); - } - } - } - } - esil->exectrap = exectrap; - RzList *entries = rz_bin_get_entries(core->bin); - RzBinAddr *entry = NULL; - RzBinInfo *info = NULL; - if (entries && !rz_list_empty(entries)) { - entry = (RzBinAddr *)rz_list_pop_head(entries); - info = rz_bin_get_info(core->bin); - addr = info->has_va ? entry->vaddr : entry->paddr; - rz_list_push(entries, entry); - } else { - addr = core->offset; - } - // set memory read only - return addr; -} - -RZ_API int rz_core_esil_step(RzCore *core, ut64 until_addr, const char *until_expr, ut64 *prev_addr, bool stepOver) { -#define return_tail(x) \ - { \ - tail_return_value = x; \ - goto tail_return; \ - } - int tail_return_value = 0; - int ret; - ut8 code[32]; - RzAnalysisOp op = { 0 }; - RzAnalysisEsil *esil = core->analysis->esil; - const char *name = rz_reg_get_name(core->analysis->reg, RZ_REG_NAME_PC); - ut64 addr = 0; - bool breakoninvalid = rz_config_get_i(core->config, "esil.breakoninvalid"); - int esiltimeout = rz_config_get_i(core->config, "esil.timeout"); - ut64 startTime; - - if (esiltimeout > 0) { - startTime = rz_time_now_mono(); - } - rz_cons_break_push(NULL, NULL); -repeat: - if (rz_cons_is_breaked()) { - RZ_LOG_WARN("core: esil: emulation interrupted at 0x%08" PFMT64x "\n", addr); - return_tail(0); - } - // Break if we have exceeded esil.timeout - if (esiltimeout > 0) { - ut64 elapsedTime = rz_time_now_mono() - startTime; - elapsedTime >>= 20; - if (elapsedTime >= esiltimeout) { - RZ_LOG_WARN("core: esil: timeout exceeded.\n"); - return_tail(0); - } - } - if (!esil) { - addr = initializeEsil(core); - esil = core->analysis->esil; - if (!esil) { - return_tail(0); - } - } else { - esil->trap = 0; - addr = rz_reg_getv(core->analysis->reg, name); - // eprintf ("PC=0x%"PFMT64x"\n", (ut64)addr); - } - if (prev_addr) { - *prev_addr = addr; - } - if (esil->exectrap) { - if (!rz_io_is_valid_offset(core->io, addr, RZ_PERM_X)) { - esil->trap = RZ_ANALYSIS_TRAP_EXEC_ERR; - esil->trap_code = addr; - RZ_LOG_ERROR("core: esil: Trap, trying to execute on non-executable memory\n"); - return_tail(1); - } - } - rz_asm_set_pc(core->rasm, addr); - - (void)rz_io_read_at_mapped(core->io, addr, code, sizeof(code)); - // TODO: sometimes this is dupe - ret = rz_analysis_op(core->analysis, &op, addr, code, sizeof(code), RZ_ANALYSIS_OP_MASK_ESIL | RZ_ANALYSIS_OP_MASK_HINT); - // if type is JMP then we execute the next N instructions - // update the esil pointer because RzAnalysis.op() can change it - esil = core->analysis->esil; - if (op.size < 1 || ret < 1) { - if (esil->cmd && esil->cmd_trap) { - esil->cmd(esil, esil->cmd_trap, addr, RZ_ANALYSIS_TRAP_INVALID); - } - if (breakoninvalid) { - RZ_LOG_ERROR("core: esil: Stopped execution in an invalid instruction (see e??esil.breakoninvalid)\n"); - return_tail(0); - } - op.size = 1; // avoid inverted stepping - } - if (stepOver) { - switch (op.type) { - case RZ_ANALYSIS_OP_TYPE_SWI: - case RZ_ANALYSIS_OP_TYPE_UCALL: - case RZ_ANALYSIS_OP_TYPE_CALL: - case RZ_ANALYSIS_OP_TYPE_JMP: - case RZ_ANALYSIS_OP_TYPE_RCALL: - case RZ_ANALYSIS_OP_TYPE_RJMP: - case RZ_ANALYSIS_OP_TYPE_CJMP: - case RZ_ANALYSIS_OP_TYPE_RET: - case RZ_ANALYSIS_OP_TYPE_CRET: - case RZ_ANALYSIS_OP_TYPE_UJMP: - if (addr == until_addr) { - return_tail(0); - } else { - rz_reg_setv(core->analysis->reg, "PC", op.addr + op.size); - } - return 1; - } - } - rz_reg_setv(core->analysis->reg, name, addr + op.size); - if (ret) { - rz_analysis_esil_set_pc(esil, addr); - const char *e = RZ_STRBUF_SAFEGET(&op.esil); - if (core->dbg->trace->enabled) { - RzReg *reg = core->dbg->reg; - core->dbg->reg = core->analysis->reg; - rz_debug_trace_op(core->dbg, &op); - core->dbg->reg = reg; - } else if (RZ_STR_ISNOTEMPTY(e)) { - rz_analysis_esil_parse(esil, e); - if (core->analysis->cur && core->analysis->cur->esil_post_loop) { - core->analysis->cur->esil_post_loop(esil, &op); - } - rz_analysis_esil_stack_free(esil); - } - bool isNextFall = false; - if (op.type == RZ_ANALYSIS_OP_TYPE_CJMP) { - ut64 pc = rz_reg_getv(core->analysis->reg, name); - if (pc == addr + op.size) { - // do not opdelay here - isNextFall = true; - } - } - // only support 1 slot for now - if (op.delay && !isNextFall) { - ut8 code2[32]; - ut64 naddr = addr + op.size; - RzAnalysisOp op2 = { 0 }; - // emulate only 1 instruction - rz_analysis_esil_set_pc(esil, naddr); - (void)rz_io_read_at(core->io, naddr, code2, sizeof(code2)); - // TODO: sometimes this is dupe - ret = rz_analysis_op(core->analysis, &op2, naddr, code2, sizeof(code2), RZ_ANALYSIS_OP_MASK_ESIL | RZ_ANALYSIS_OP_MASK_HINT); - if (ret > 0) { - switch (op2.type) { - case RZ_ANALYSIS_OP_TYPE_CJMP: - case RZ_ANALYSIS_OP_TYPE_JMP: - case RZ_ANALYSIS_OP_TYPE_CRET: - case RZ_ANALYSIS_OP_TYPE_RET: - // branches are illegal in a delay slot - esil->trap = RZ_ANALYSIS_TRAP_EXEC_ERR; - esil->trap_code = addr; - RZ_LOG_WARN("core: ESIL: Trap, trying to execute a branch in a delay slot\n"); - return_tail(1); - break; - } - const char *e = RZ_STRBUF_SAFEGET(&op2.esil); - if (RZ_STR_ISNOTEMPTY(e)) { - rz_analysis_esil_parse(esil, e); - } - } else { - RZ_LOG_ERROR("core: Invalid instruction at 0x%08" PFMT64x "\n", naddr); - } - rz_analysis_op_fini(&op2); - } - tail_return_value = 1; - } - // esil->verbose ? - // eprintf ("REPE 0x%llx %s => 0x%llx\n", addr, RZ_STRBUF_SAFEGET (&op.esil), rz_reg_getv (core->analysis->reg, "PC")); - - ut64 pc = rz_reg_getv(core->analysis->reg, name); - if (core->analysis->pcalign > 0) { - pc -= (pc % core->analysis->pcalign); - rz_reg_setv(core->analysis->reg, name, pc); - } - - st64 follow = (st64)rz_config_get_i(core->config, "dbg.follow"); - if (follow > 0) { - ut64 pc = rz_reg_getv(core->analysis->reg, name); - if ((pc < core->offset) || (pc > (core->offset + follow))) { - rz_core_seek_to_register(core, "PC", false); - } - } - // check breakpoints - if (rz_bp_get_at(core->dbg->bp, pc)) { - rz_cons_printf("[ESIL] hit breakpoint at 0x%" PFMT64x "\n", pc); - return_tail(0); - } - // check addr - if (until_addr != UT64_MAX) { - if (pc == until_addr) { - return_tail(0); - } - goto repeat; - } - // check esil - if (esil && esil->trap) { - if (core->analysis->esil->verbose) { - RZ_LOG_WARN("core: TRAP\n"); - } - return_tail(0); - } - if (until_expr) { - if (rz_analysis_esil_condition(core->analysis->esil, until_expr)) { - if (core->analysis->esil->verbose) { - RZ_LOG_WARN("core: ESIL BREAK!\n"); - } - return_tail(0); - } - goto repeat; - } -tail_return: - rz_analysis_op_fini(&op); - rz_cons_break_pop(); - return tail_return_value; -} - -RZ_API int rz_core_esil_step_back(RzCore *core) { - rz_return_val_if_fail(core->analysis->esil && core->analysis->esil->trace, -1); - RzAnalysisEsil *esil = core->analysis->esil; - if (esil->trace->idx > 0) { - rz_analysis_esil_trace_restore(esil, esil->trace->idx - 1); - rz_core_reg_update_flags(core); - return 1; - } - return 0; -} - -RZ_API bool rz_core_esil_continue_back(RZ_NONNULL RzCore *core) { - rz_return_val_if_fail(core->analysis->esil && core->analysis->esil->trace, false); - RzAnalysisEsil *esil = core->analysis->esil; - if (esil->trace->idx == 0) { - return true; - } - - RzRegItem *ripc = rz_reg_get(esil->analysis->reg, "PC", -1); - RzVector *vreg = ht_up_find(esil->trace->registers, ripc->offset | (ripc->arena << 16), NULL); - if (!vreg) { - RZ_LOG_ERROR("failed to find PC change vector\n"); - return false; - } - - // Search for the nearest breakpoint in the tracepoints before the current position - bool bp_found = false; - int idx = 0; - RzAnalysisEsilRegChange *reg; - rz_vector_foreach_prev(vreg, reg) { - if (reg->idx >= esil->trace->idx) { - continue; - } - bp_found = rz_bp_get_in(core->dbg->bp, reg->data, RZ_PERM_X) != NULL; - if (bp_found) { - idx = reg->idx; - RZ_LOG_WARN("core: hit breakpoint at: 0x%" PFMT64x " idx: %d\n", reg->data, reg->idx); - break; - } - } - - // Return to the nearest breakpoint or jump back to the first index if a breakpoint wasn't found - rz_analysis_esil_trace_restore(esil, idx); - - rz_core_reg_update_flags(core); - - return true; -} - static void cmd_address_info(RzCore *core, const ut64 addr, RzCmdStateOutput *state) { ut64 type; PJ *pj; @@ -1727,23 +1423,6 @@ static void rz_analysis_aefa(RzCore *core, const char *arg) { rz_core_cmd0(core, "arA"); } -RZ_API bool rz_core_esil_dumpstack(RzAnalysisEsil *esil) { - rz_return_val_if_fail(esil, false); - int i; - if (esil->trap) { - rz_cons_printf("ESIL TRAP type %d code 0x%08x %s\n", - esil->trap, esil->trap_code, - rz_analysis_esil_trapstr(esil->trap)); - } - if (esil->stackptr < 1) { - return false; - } - for (i = esil->stackptr - 1; i >= 0; i--) { - rz_cons_printf("%s\n", esil->stack[i]); - } - return true; -} - static void __analysis_esil_function(RzCore *core, ut64 addr) { RzListIter *iter; RzAnalysisBlock *bb; @@ -2127,140 +1806,6 @@ static bool print_cmd_analysis_after_traps_print(RZ_NONNULL RzCore *core, ut64 n return true; } -static void _analysis_calls(RzCore *core, ut64 addr, ut64 addr_end, bool importsOnly) { - RzAnalysisOp op; - int depth = rz_config_get_i(core->config, "analysis.depth"); - const int addrbytes = core->io->addrbytes; - const int bsz = 4096; - int bufi = 0; - int bufi_max = bsz - 16; - if (addr_end - addr > UT32_MAX) { - return; - } - ut8 *buf = malloc(bsz); - ut8 *block0 = calloc(1, bsz); - ut8 *block1 = malloc(bsz); - if (!buf || !block0 || !block1) { - RZ_LOG_ERROR("core: cannot allocate buf or block\n"); - free(buf); - free(block0); - free(block1); - return; - } - memset(block1, -1, bsz); - int minop = rz_analysis_archinfo(core->analysis, RZ_ANALYSIS_ARCHINFO_MIN_OP_SIZE); - if (minop < 1) { - minop = 1; - } - int setBits = rz_config_get_i(core->config, "asm.bits"); - rz_cons_break_push(NULL, NULL); - while (addr < addr_end && !rz_cons_is_breaked()) { - // TODO: too many ioreads here - if (bufi > bufi_max) { - bufi = 0; - } - if (!bufi) { - (void)rz_io_read_at(core->io, addr, buf, bsz); - } - if (!memcmp(buf, block0, bsz) || !memcmp(buf, block1, bsz)) { - // eprintf ("Error: skipping uninitialized block \n"); - addr += bsz; - continue; - } - RzAnalysisHint *hint = rz_analysis_hint_get(core->analysis, addr); - if (hint && hint->bits) { - setBits = hint->bits; - } - rz_analysis_hint_free(hint); - if (setBits != core->rasm->bits) { - rz_config_set_i(core->config, "asm.bits", setBits); - } - if (rz_analysis_op(core->analysis, &op, addr, buf + bufi, bsz - bufi, 0) > 0) { - if (op.size < 1) { - op.size = minop; - } - if (op.type == RZ_ANALYSIS_OP_TYPE_CALL) { - bool isValidCall = true; - if (importsOnly) { - RzFlagItem *f = rz_flag_get_i(core->flags, op.jump); - if (!f || !strstr(f->name, "imp.")) { - isValidCall = false; - } - } - RzBinReloc *rel = rz_core_getreloc(core, addr, op.size); - if (rel && (rel->import || rel->symbol)) { - isValidCall = false; - } - if (isValidCall) { - ut8 buf[4]; - rz_io_read_at(core->io, op.jump, buf, 4); - isValidCall = memcmp(buf, "\x00\x00\x00\x00", 4); - } - if (isValidCall) { - // add xref here - rz_analysis_xrefs_set(core->analysis, addr, op.jump, RZ_ANALYSIS_XREF_TYPE_CALL); - if (rz_io_is_valid_offset(core->io, op.jump, 1)) { - rz_core_analysis_fcn(core, op.jump, addr, RZ_ANALYSIS_XREF_TYPE_CALL, depth); - } - } - } - } else { - op.size = minop; - } - if ((int)op.size < 1) { - op.size = minop; - } - addr += op.size; - bufi += addrbytes * op.size; - rz_analysis_op_fini(&op); - } - rz_cons_break_pop(); - free(buf); - free(block0); - free(block1); -} - -RZ_API void rz_core_analysis_calls(RZ_NONNULL RzCore *core, bool imports_only) { - rz_return_if_fail(core); - - RzList *ranges = NULL; - RzIOMap *r; - ut64 addr; - RzBinFile *binfile = rz_bin_cur(core->bin); - addr = core->offset; - if (binfile) { - ranges = rz_core_get_boundaries_prot(core, RZ_PERM_X, NULL, "analysis"); - } - rz_cons_break_push(NULL, NULL); - if (!binfile || rz_list_length(ranges) < 1) { - RzListIter *iter; - RzIOMap *map; - rz_list_free(ranges); - ranges = rz_core_get_boundaries_prot(core, 0, NULL, "analysis"); - if (ranges) { - rz_list_foreach (ranges, iter, map) { - ut64 addr = map->itv.addr; - _analysis_calls(core, addr, rz_itv_end(map->itv), imports_only); - } - } - } else { - RzListIter *iter; - if (binfile) { - rz_list_foreach (ranges, iter, r) { - addr = r->itv.addr; - // this normally will happen on fuzzed binaries, dunno if with huge - // binaries as well - if (rz_cons_is_breaked()) { - break; - } - _analysis_calls(core, addr, rz_itv_end(r->itv), imports_only); - } - } - } - rz_cons_break_pop(); - rz_list_free(ranges); -} - RZ_IPI RzCmdStatus rz_analysis_syscall_show_handler(RzCore *core, int argc, const char **argv) { st64 n = argc > 1 ? rz_num_math(core->num, argv[1]) : -1; char *sysc = rz_core_syscall_as_string(core, n, core->offset); diff --git a/librz/core/meson.build b/librz/core/meson.build index 4823756faff..6412d795ac6 100644 --- a/librz/core/meson.build +++ b/librz/core/meson.build @@ -25,6 +25,7 @@ rz_core_sources = [ 'cconfig.c', 'cdebug.c', 'cdwarf.c', + 'cesil.c', 'cfile.c', 'cflag.c', 'chash.c', From 3703eaea44f9bd680d8f9f5d7b1806f773e88d2a Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Wed, 7 Sep 2022 17:28:15 +0800 Subject: [PATCH 2/4] Move RzDebug APIs to the cdebug.c --- librz/core/cdebug.c | 41 ++++++++++++++++++++++++++++++++++++ librz/core/cmd/cmd_debug.c | 43 +------------------------------------- librz/core/core_private.h | 1 + librz/include/rz_core.h | 1 - 4 files changed, 43 insertions(+), 43 deletions(-) diff --git a/librz/core/cdebug.c b/librz/core/cdebug.c index 8dd6b636ac6..027ec009161 100644 --- a/librz/core/cdebug.c +++ b/librz/core/cdebug.c @@ -951,3 +951,44 @@ RZ_API RZ_OWN RzList /**/ *rz_core_debug_backtraces(RzCore *core) rz_list_free(list); return bts; } + +/** + * \brief Seek to `PC` if needed + * \param core The RzCore instance + */ +RZ_API void rz_core_dbg_follow_seek_register(RzCore *core) { + ut64 follow = rz_config_get_i(core->config, "dbg.follow"); + if (follow <= 0) { + return; + } + ut64 pc = rz_debug_reg_get(core->dbg, "PC"); + if ((pc < core->offset) || (pc > (core->offset + follow))) { + rz_core_seek_to_register(core, "PC", false); + } + rz_core_debug_sync_bits(core); +} + +static void foreach_reg_set_or_clear(RzCore *core, bool set) { + RzReg *reg = rz_core_reg_default(core); + const RzList *regs = rz_reg_get_list(reg, RZ_REG_TYPE_GPR); + RzListIter *it; + RzRegItem *reg_item; + rz_list_foreach (regs, it, reg_item) { + if (set) { + const ut64 value = rz_reg_get_value(reg, reg_item); + rz_flag_set(core->flags, reg_item->name, value, reg_item->size / 8); + } else { + rz_flag_unset_name(core->flags, reg_item->name); + } + } +} + +RZ_API void rz_core_debug_set_register_flags(RzCore *core) { + rz_flag_space_push(core->flags, RZ_FLAGS_FS_REGISTERS); + foreach_reg_set_or_clear(core, true); + rz_flag_space_pop(core->flags); +} + +RZ_API void rz_core_debug_clear_register_flags(RzCore *core) { + foreach_reg_set_or_clear(core, false); +} diff --git a/librz/core/cmd/cmd_debug.c b/librz/core/cmd/cmd_debug.c index d60a54e95cd..b4587189d19 100644 --- a/librz/core/cmd/cmd_debug.c +++ b/librz/core/cmd/cmd_debug.c @@ -467,22 +467,6 @@ static bool step_until_inst(RzCore *core, const char *instr, bool regex) { return true; } -/** - * \brief Seek to `PC` if needed - * \param core The RzCore instance - */ -RZ_API void rz_core_dbg_follow_seek_register(RzCore *core) { - ut64 follow = rz_config_get_i(core->config, "dbg.follow"); - if (follow <= 0) { - return; - } - ut64 pc = rz_debug_reg_get(core->dbg, "PC"); - if ((pc < core->offset) || (pc > (core->offset + follow))) { - rz_core_seek_to_register(core, "PC", false); - } - rz_core_debug_sync_bits(core); -} - static bool step_until_optype(RzCore *core, RzList *optypes_list) { RzAnalysisOp op; ut8 buf[32]; @@ -1427,31 +1411,6 @@ RZ_IPI int rz_cmd_debug_heap_jemalloc(void *data, const char *input) { return RZ_CMD_STATUS_ERROR; } -static void foreach_reg_set_or_clear(RzCore *core, bool set) { - RzReg *reg = rz_core_reg_default(core); - const RzList *regs = rz_reg_get_list(reg, RZ_REG_TYPE_GPR); - RzListIter *it; - RzRegItem *reg_item; - rz_list_foreach (regs, it, reg_item) { - if (set) { - const ut64 value = rz_reg_get_value(reg, reg_item); - rz_flag_set(core->flags, reg_item->name, value, reg_item->size / 8); - } else { - rz_flag_unset_name(core->flags, reg_item->name); - } - } -} - -RZ_API void rz_core_debug_set_register_flags(RzCore *core) { - rz_flag_space_push(core->flags, RZ_FLAGS_FS_REGISTERS); - foreach_reg_set_or_clear(core, true); - rz_flag_space_pop(core->flags); -} - -RZ_API void rz_core_debug_clear_register_flags(RzCore *core) { - foreach_reg_set_or_clear(core, false); -} - static void backtrace_vars(RzCore *core, RzList *frames) { RzDebugFrame *f; RzListIter *iter; @@ -3619,7 +3578,7 @@ static bool cmd_regs_sync(RzCore *core, RzRegisterType type, bool write) { #undef CMD_REGS_REG_PATH #undef CMD_REGS_SYNC -RZ_API void rz_core_debug_ri(RzCore *core) { +RZ_IPI void rz_core_debug_ri(RzCore *core) { const RzList *list = rz_reg_get_list(core->dbg->reg, RZ_REG_TYPE_GPR); rz_regs_show_valgroup(core, core->dbg->reg, cmd_regs_sync, list); } diff --git a/librz/core/core_private.h b/librz/core/core_private.h index 17e85db130a..cb39f0f1882 100644 --- a/librz/core/core_private.h +++ b/librz/core/core_private.h @@ -134,6 +134,7 @@ RZ_IPI void rz_core_debug_continue(RzCore *core); RZ_IPI void rz_core_debug_attach(RzCore *core, int pid); RZ_IPI void rz_core_debug_print_status(RzCore *core); RZ_IPI void rz_core_debug_bp_add(RzCore *core, ut64 addr, const char *arg_perm, bool hwbp, bool watch); +RZ_IPI void rz_core_debug_ri(RzCore *core); /* cfile.c */ RZ_IPI RzCoreIOMapInfo *rz_core_io_map_info_new(RzCoreFile *cf, int perm_orig); diff --git a/librz/include/rz_core.h b/librz/include/rz_core.h index 15d74d53d32..6a00611be2c 100644 --- a/librz/include/rz_core.h +++ b/librz/include/rz_core.h @@ -566,7 +566,6 @@ RZ_API bool rz_core_debug_continue_until(RzCore *core, ut64 addr, ut64 to); RZ_API void rz_core_debug_bp_add_noreturn_func(RzCore *core); RZ_API void rz_core_debug_breakpoint_toggle(RZ_NONNULL RzCore *core, ut64 addr); -RZ_API void rz_core_debug_ri(RzCore *core); RZ_API void rz_core_debug_set_register_flags(RzCore *core); RZ_API void rz_core_debug_clear_register_flags(RzCore *core); From da9cc83a9c5564a8cf4ccac7ad38a4b7ec00747e Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Wed, 7 Sep 2022 18:17:50 +0800 Subject: [PATCH 3/4] Move rz_core_file_*() API to the cfile.c --- librz/core/cfile.c | 48 +++++++++++++++++++++++++++++++++++++++ librz/core/cmd/cmd_open.c | 48 --------------------------------------- librz/include/rz_core.h | 1 + 3 files changed, 49 insertions(+), 48 deletions(-) diff --git a/librz/core/cfile.c b/librz/core/cfile.c index 63585f84286..7c16beb4d68 100644 --- a/librz/core/cfile.c +++ b/librz/core/cfile.c @@ -1664,6 +1664,54 @@ RZ_API void rz_core_io_file_reopen(RZ_NONNULL RzCore *core, int fd, int perms) { } } +static bool reopen_in_malloc_cb(void *user, void *data, ut32 id) { + RzIO *io = (RzIO *)user; + RzIODesc *desc = (RzIODesc *)data; + + if (rz_io_desc_is_blockdevice(desc) || rz_io_desc_is_dbg(desc)) { + return true; + } + + if (strstr(desc->uri, "://")) { + return true; + } + + ut64 size = rz_io_desc_size(desc); + + char *uri = rz_str_newf("malloc://%" PFMT64u, size); + if (!uri) { + return false; + } + + ut8 *buf = malloc(size); + // if malloc fails, we can just abort the loop by returning false + if (!buf) { + free(uri); + return false; + } + + RzIODesc *ndesc = rz_io_open_nomap(io, uri, RZ_PERM_RW, 0); + free(uri); + if (!ndesc) { + free(buf); + return false; + } + + rz_io_desc_read_at(desc, 0LL, buf, (int)size); // that cast o_O + rz_io_desc_write_at(ndesc, 0LL, buf, (int)size); + free(buf); + rz_io_desc_exchange(io, desc->fd, ndesc->fd); + + rz_io_desc_close(desc); + return true; +} + +RZ_API void rz_core_file_reopen_in_malloc(RzCore *core) { + if (core && core->io && core->io->files) { + rz_id_storage_foreach(core->io->files, reopen_in_malloc_cb, core->io); + } +} + /* --------------------------------------------------------------------------------- */ RZ_IPI RzCoreIOMapInfo *rz_core_io_map_info_new(RzCoreFile *cf, int perm_orig) { diff --git a/librz/core/cmd/cmd_open.c b/librz/core/cmd/cmd_open.c index 790c3f924cf..a3c55957a70 100644 --- a/librz/core/cmd/cmd_open.c +++ b/librz/core/cmd/cmd_open.c @@ -29,54 +29,6 @@ static bool core_bin_reload(RzCore *r, const char *file, ut64 baseaddr) { return true; } -static bool reopen_in_malloc_cb(void *user, void *data, ut32 id) { - RzIO *io = (RzIO *)user; - RzIODesc *desc = (RzIODesc *)data; - - if (rz_io_desc_is_blockdevice(desc) || rz_io_desc_is_dbg(desc)) { - return true; - } - - if (strstr(desc->uri, "://")) { - return true; - } - - ut64 size = rz_io_desc_size(desc); - - char *uri = rz_str_newf("malloc://%" PFMT64u, size); - if (!uri) { - return false; - } - - ut8 *buf = malloc(size); - // if malloc fails, we can just abort the loop by returning false - if (!buf) { - free(uri); - return false; - } - - RzIODesc *ndesc = rz_io_open_nomap(io, uri, RZ_PERM_RW, 0); - free(uri); - if (!ndesc) { - free(buf); - return false; - } - - rz_io_desc_read_at(desc, 0LL, buf, (int)size); // that cast o_O - rz_io_desc_write_at(ndesc, 0LL, buf, (int)size); - free(buf); - rz_io_desc_exchange(io, desc->fd, ndesc->fd); - - rz_io_desc_close(desc); - return true; -} - -RZ_API void rz_core_file_reopen_in_malloc(RzCore *core) { - if (core && core->io && core->io->files) { - rz_id_storage_foreach(core->io->files, reopen_in_malloc_cb, core->io); - } -} - static bool init_desc_list_visual_cb(void *user, void *data, ut32 id) { struct open_list_ascii_data_t *u = (struct open_list_ascii_data_t *)user; RzIODesc *desc = (RzIODesc *)data; diff --git a/librz/include/rz_core.h b/librz/include/rz_core.h index 6a00611be2c..fe3199fe957 100644 --- a/librz/include/rz_core.h +++ b/librz/include/rz_core.h @@ -510,6 +510,7 @@ RZ_API RZ_OWN RzPVector /**/ *rz_core_analysis_bytes(RZ_NONNU RZ_API int rz_core_search_cb(RzCore *core, ut64 from, ut64 to, RzCoreSearchCallback cb); RZ_API bool rz_core_serve(RzCore *core, RzIODesc *fd); RZ_API bool rz_core_file_reopen(RzCore *core, const char *args, int perm, int binload); +RZ_API void rz_core_file_reopen_in_malloc(RzCore *core); RZ_API void rz_core_file_reopen_debug(RzCore *core, const char *args); RZ_API void rz_core_file_reopen_remote_debug(RzCore *core, const char *uri, ut64 addr); RZ_API bool rz_core_file_resize(RzCore *core, ut64 newsize); From c2fb1506fde5558c0534e89dcd8f6da27bf5d6ee Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Wed, 7 Sep 2022 18:18:09 +0800 Subject: [PATCH 4/4] Move rz_core_project_*() API to the project.c --- librz/core/cmd/cmd_project.c | 17 ----------------- librz/core/project.c | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/librz/core/cmd/cmd_project.c b/librz/core/cmd/cmd_project.c index a0da26dff3d..c7695bbf8c4 100644 --- a/librz/core/cmd/cmd_project.c +++ b/librz/core/cmd/cmd_project.c @@ -3,23 +3,6 @@ #include -RZ_API bool rz_core_project_load_for_cli(RzCore *core, const char *file, bool load_bin_io) { - RzSerializeResultInfo *res = rz_serialize_result_info_new(); - RzProjectErr err = rz_project_load_file(core, file, load_bin_io, res); - if (err != RZ_PROJECT_ERR_SUCCESS) { - RZ_LOG_ERROR("core: Failed to load project: %s\n", rz_project_err_message(err)); - } else if (!rz_list_empty(res)) { - rz_cons_printf("Detailed project load info:\n"); - } - RzListIter *it; - char *s; - rz_list_foreach (res, it, s) { - rz_cons_printf(" %s\n", s); - } - rz_serialize_result_info_free(res); - return err == RZ_PROJECT_ERR_SUCCESS; -} - RZ_IPI RzCmdStatus rz_project_save_handler(RzCore *core, int argc, const char **argv) { const char *file; if (argc == 1) { diff --git a/librz/core/project.c b/librz/core/project.c index eaf4067caee..8bf37f0f8d5 100644 --- a/librz/core/project.c +++ b/librz/core/project.c @@ -175,3 +175,20 @@ RZ_API RzProjectErr rz_project_load_file(RzCore *core, const char *file, bool lo sdb_free(prj); return ret; } + +RZ_API bool rz_core_project_load_for_cli(RzCore *core, const char *file, bool load_bin_io) { + RzSerializeResultInfo *res = rz_serialize_result_info_new(); + RzProjectErr err = rz_project_load_file(core, file, load_bin_io, res); + if (err != RZ_PROJECT_ERR_SUCCESS) { + RZ_LOG_ERROR("core: Failed to load project: %s\n", rz_project_err_message(err)); + } else if (!rz_list_empty(res)) { + rz_cons_printf("Detailed project load info:\n"); + } + RzListIter *it; + char *s; + rz_list_foreach (res, it, s) { + rz_cons_printf(" %s\n", s); + } + rz_serialize_result_info_free(res); + return err == RZ_PROJECT_ERR_SUCCESS; +}