rizin/librz/core/cmd/cmd_seek.c

369 lines
11 KiB
C

// SPDX-FileCopyrightText: 2009-2020 pancake <pancake@nopcode.org>
// SPDX-License-Identifier: LGPL-3.0-only
#include "rz_types.h"
#include "rz_config.h"
#include "rz_cons.h"
#include "rz_core.h"
#include "rz_debug.h"
#include "rz_io.h"
static void printPadded(RzCore *core, int pad) {
if (pad < 1) {
pad = 8;
}
char *fmt = rz_str_newf("0x%%0%d" PFMT64x, pad);
char *off = rz_str_newf(fmt, core->offset);
rz_cons_printf("%s\n", off);
free(off);
free(fmt);
}
RZ_IPI bool rz_core_seek_to_register(RzCore *core, const char *regname, bool is_silent) {
ut64 off = rz_core_reg_getv_by_role_or_name(core, regname);
return rz_core_seek_opt(core, off, true, !is_silent);
}
RZ_IPI int rz_core_seek_opcode_backward(RzCore *core, int numinstr, bool silent) {
int i, val = 0;
// N previous instructions
ut64 addr = core->offset;
int ret = 0;
if (rz_core_prevop_addr(core, core->offset, numinstr, &addr)) {
ret = core->offset - addr;
} else {
#if 0
// core_asm_bwdis_len is really buggy and we should remove it. seems like prevop_addr
// works as expected, because is the one used from visual
ret = rz_core_asm_bwdis_len (core, &instr_len, &addr, numinstr);
#endif
addr = core->offset;
const int mininstrsize = rz_analysis_archinfo(core->analysis, RZ_ANALYSIS_ARCHINFO_MIN_OP_SIZE);
for (i = 0; i < numinstr; i++) {
ut64 prev_addr = rz_core_prevop_addr_force(core, addr, 1);
if (prev_addr == UT64_MAX) {
prev_addr = addr - mininstrsize;
}
if (prev_addr == UT64_MAX || prev_addr >= core->offset) {
break;
}
RzAsmOp op = { 0 };
rz_core_seek(core, prev_addr, true);
rz_asm_disassemble(core->rasm, &op, core->block, 32);
if (op.size < mininstrsize) {
op.size = mininstrsize;
}
val += op.size;
addr = prev_addr;
}
}
rz_core_seek_opt(core, addr, true, !silent);
val += ret;
return val;
}
RZ_IPI int rz_core_seek_opcode_forward(RzCore *core, int n, bool silent) {
// N forward instructions
int i, ret, val = 0;
if (!silent) {
rz_core_seek_mark(core);
}
for (val = i = 0; i < n; i++) {
RzAnalysisOp op;
ret = rz_analysis_op(core->analysis, &op, core->offset, core->block,
core->blocksize, RZ_ANALYSIS_OP_MASK_BASIC);
if (ret < 1) {
ret = 1;
}
rz_core_seek_delta(core, ret, false);
rz_analysis_op_fini(&op);
val += ret;
}
rz_core_seek_save(core);
return val;
}
RZ_IPI int rz_core_seek_opcode(RzCore *core, int n, bool silent) {
int val = (n < 0)
? rz_core_seek_opcode_backward(core, -n, silent)
: rz_core_seek_opcode_forward(core, n, silent);
core->num->value = val;
return val;
}
static void cmd_seek_opcode(RzCore *core, const char *input, bool silent) {
if (input[0] == '?') {
RZ_LOG_ERROR("core: Usage: so [-][n]\n");
return;
}
if (!strcmp(input, "-")) {
input = "-1";
}
int n = rz_num_math(core->num, input);
if (n == 0) {
n = 1;
}
rz_core_seek_opcode(core, n, silent);
}
RZ_IPI int rz_seek_search(void *data, const char *input) {
RzCore *core = (RzCore *)data;
const char *pfx = rz_config_get(core->config, "search.prefix");
const ut64 saved_from = rz_config_get_i(core->config, "search.from");
const ut64 saved_maxhits = rz_config_get_i(core->config, "search.maxhits");
int kwidx = core->search->n_kws; // (int)rz_config_get_i (core->config, "search.kwidx")-1;
if (kwidx < 0) {
kwidx = 0;
}
switch (input[0]) {
case ' ':
case 'v':
case 'V':
case 'w':
case 'W':
case 'z':
case 'm':
case 'c':
case 'A':
case 'e':
case 'E':
case 'i':
case 'R':
case 'r':
case '/':
case 'x':
rz_config_set_i(core->config, "search.from", core->offset + 1);
rz_config_set_i(core->config, "search.maxhits", 1);
rz_core_cmdf(core, "sd 1@e:cfg.seek.silent=true; /%s; sd -1@e:cfg.seek.silent=true; s %s%d_0; f- %s%d_0",
input, pfx, kwidx, pfx, kwidx);
rz_config_set_i(core->config, "search.from", saved_from);
rz_config_set_i(core->config, "search.maxhits", saved_maxhits);
break;
case '?':
RZ_LOG_ERROR("core: Usage: s/.. arg.\n");
rz_cons_printf("/?\n");
break;
default:
RZ_LOG_ERROR("core: unknown search method\n");
break;
}
return 0;
}
static RzCmdStatus bool2cmdstatus(bool res) {
return res ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR;
}
RZ_IPI RzCmdStatus rz_seek_handler(RzCore *core, int argc, const char **argv) {
if (argc == 1) {
rz_cons_printf("0x%" PFMT64x "\n", core->offset);
return RZ_CMD_STATUS_OK;
}
rz_core_seek_mark(core);
// NOTE: hack to make it work with local function labels
char *ptr;
if ((ptr = strstr(argv[1], "+.")) != NULL) {
char *dup = strdup(argv[1]);
dup[ptr - argv[1]] = '\x00';
core->offset = rz_num_math(core->num, dup);
;
free(dup);
}
ut64 addr = rz_num_math(core->num, argv[1]);
if (core->num->nc.errors) {
RZ_LOG_ERROR("Cannot seek to unknown address '%s'\n", core->num->nc.calc_buf);
return RZ_CMD_STATUS_ERROR;
}
return bool2cmdstatus(rz_core_seek_and_save(core, addr, true));
}
RZ_IPI RzCmdStatus rz_seek_delta_handler(RzCore *core, int argc, const char **argv) {
st64 delta = strtoll(argv[1], NULL, 0);
return bool2cmdstatus(rz_core_seek_delta(core, delta, true));
}
RZ_IPI RzCmdStatus rz_seek_padded_handler(RzCore *core, int argc, const char **argv) {
int n = argc > 1 ? atoi(argv[1]) : 0;
printPadded(core, n);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_seek_base_handler(RzCore *core, int argc, const char **argv) {
return bool2cmdstatus(rz_core_seek_base(core, argv[1], true));
}
RZ_IPI RzCmdStatus rz_seek_blocksize_backward_handler(RzCore *core, int argc, const char **argv) {
int n = 1;
if (argc == 2) {
n = rz_num_math(core->num, argv[1]);
}
int delta = -core->blocksize / n;
return bool2cmdstatus(rz_core_seek_delta(core, delta, true));
}
RZ_IPI RzCmdStatus rz_seek_blocksize_forward_handler(RzCore *core, int argc, const char **argv) {
int n = 1;
if (argc == 2) {
n = rz_num_math(core->num, argv[1]);
}
int delta = core->blocksize / n;
return bool2cmdstatus(rz_core_seek_delta(core, delta, true));
}
RZ_IPI RzCmdStatus rz_seek_redo_handler(RzCore *core, int argc, const char **argv) {
return bool2cmdstatus(rz_core_seek_redo(core));
}
RZ_IPI RzCmdStatus rz_seek_undo_handler(RzCore *core, int argc, const char **argv) {
return bool2cmdstatus(rz_core_seek_undo(core));
}
RZ_IPI RzCmdStatus rz_seek_undo_reset_handler(RzCore *core, int argc, const char **argv) {
rz_core_seek_reset(core);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_seek_history_list_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
RzList *list = rz_core_seek_list(core);
RzListIter *iter;
RzCoreSeekItem *undo;
PJ *pj = state->d.pj;
rz_cmd_state_output_array_start(state);
bool current_met = false;
rz_list_foreach (list, iter, undo) {
RzFlagItem *f = rz_flag_get_at(core->flags, undo->offset, true);
const char *comment;
char *name = NULL;
if (f) {
if (f->offset != undo->offset) {
name = rz_str_newf("%s+%" PFMT64d, f->name, undo->offset - f->offset);
} else {
name = strdup(f->name);
}
}
current_met |= undo->is_current;
switch (state->mode) {
case RZ_OUTPUT_MODE_JSON:
pj_o(pj);
pj_kn(pj, "offset", undo->offset);
pj_kn(pj, "cursor", undo->cursor);
if (name) {
pj_ks(pj, "name", name);
}
pj_kb(pj, "current", undo->is_current);
pj_end(pj);
break;
case RZ_OUTPUT_MODE_STANDARD:
comment = "";
if (undo->is_current) {
comment = " # current seek";
} else if (current_met) {
comment = " # redo";
}
rz_cons_printf("0x%" PFMT64x " %s%s\n", undo->offset, name ? name : "", comment);
break;
case RZ_OUTPUT_MODE_RIZIN:
if (undo->is_current) {
rz_cons_printf("# Current seek @ 0x%" PFMT64x "\n", undo->offset);
} else if (current_met) {
rz_cons_printf("f redo_%d @ 0x%" PFMT64x "\n", RZ_ABS(undo->idx - 1), undo->offset);
} else {
rz_cons_printf("f undo_%d @ 0x%" PFMT64x "\n", RZ_ABS(undo->idx + 1), undo->offset);
}
break;
default:
rz_warn_if_reached();
break;
}
free(name);
}
rz_cmd_state_output_array_end(state);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_seek_asz_handler(RzCore *core, int argc, const char **argv) {
ut64 align = rz_num_math(NULL, argv[1]);
ut64 addr = core->offset;
rz_core_seek_mark(core);
if (argc > 2) {
addr = rz_num_math(core->num, argv[2]);
rz_core_seek(core, addr, false);
}
return bool2cmdstatus(rz_core_seek_align(core, align, true));
}
RZ_IPI RzCmdStatus rz_seek_basicblock_handler(RzCore *core, int argc, const char **argv) {
return bool2cmdstatus(rz_core_seek_analysis_bb(core, core->offset, true));
}
RZ_IPI RzCmdStatus rz_seek_function_handler(RzCore *core, int argc, const char **argv) {
RzAnalysisFunction *fcn = NULL;
ut64 addr;
if (argc == 1) {
fcn = rz_analysis_get_fcn_in(core->analysis, core->offset, 0);
if (!fcn) {
return RZ_CMD_STATUS_ERROR;
}
addr = rz_analysis_function_max_addr(fcn);
} else {
fcn = rz_analysis_get_function_byname(core->analysis, argv[1]);
if (!fcn) {
return RZ_CMD_STATUS_ERROR;
}
addr = fcn->addr;
}
return bool2cmdstatus(rz_core_seek_and_save(core, addr, true));
}
RZ_IPI RzCmdStatus rz_seek_function_current_handler(RzCore *core, int argc, const char **argv) {
RzAnalysisFunction *fcn = rz_analysis_get_fcn_in(core->analysis, core->offset, 0);
if (!fcn) {
return RZ_CMD_STATUS_ERROR;
}
return bool2cmdstatus(rz_core_seek_and_save(core, fcn->addr, true));
}
RZ_IPI RzCmdStatus rz_seek_begin_handler(RzCore *core, int argc, const char **argv) {
RzIOMap *map = rz_io_map_get(core->io, core->offset);
ut64 addr = map ? map->itv.addr : 0;
return bool2cmdstatus(rz_core_seek_and_save(core, addr, true));
}
RZ_IPI RzCmdStatus rz_seek_end_handler(RzCore *core, int argc, const char **argv) {
RzIOMap *map = rz_io_map_get(core->io, core->offset);
// XXX: this +2 is a hack. must fix gap between sections
ut64 addr = map ? map->itv.addr + map->itv.size + 2 : rz_io_fd_size(core->io, core->file->fd);
return bool2cmdstatus(rz_core_seek_and_save(core, addr, true));
}
RZ_IPI RzCmdStatus rz_seek_next_handler(RzCore *core, int argc, const char **argv) {
const char *nkey;
if (argc == 1) {
nkey = rz_config_get(core->config, "scr.nkey");
} else {
nkey = argv[1];
}
return bool2cmdstatus(rz_core_seek_next(core, nkey, true));
}
RZ_IPI RzCmdStatus rz_seek_prev_handler(RzCore *core, int argc, const char **argv) {
const char *nkey;
if (argc == 1) {
nkey = rz_config_get(core->config, "scr.nkey");
} else {
nkey = argv[1];
}
return bool2cmdstatus(rz_core_seek_prev(core, nkey, true));
}
RZ_IPI RzCmdStatus rz_seek_opcode_handler(RzCore *core, int argc, const char **argv) {
cmd_seek_opcode(core, argc > 1 ? argv[1] : "", false);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_seek_register_handler(RzCore *core, int argc, const char **argv) {
return bool2cmdstatus(rz_core_seek_to_register(core, argv[1], false));
}