mirror of
https://github.com/radareorg/radare2.git
synced 2024-12-13 16:18:33 +00:00
910 lines
23 KiB
C
910 lines
23 KiB
C
/* radare - LGPL - Copyright 2009-2022 - pancake */
|
|
|
|
#include "r_types.h"
|
|
#include "r_config.h"
|
|
#include "r_cons.h"
|
|
#include "r_core.h"
|
|
#include "r_debug.h"
|
|
#include "r_io.h"
|
|
|
|
static void __core_cmd_search_backward_prelude(RCore *core, bool doseek, bool forward);
|
|
|
|
static const char *help_msg_s[] = {
|
|
"Usage: s", "", " # Help for the seek commands. See ?$? to see all variables",
|
|
"s", "", "print current address",
|
|
"s", " addr", "seek to address",
|
|
"s.", "[?]hexoff", "seek honoring a base from core->offset",
|
|
"s:", "pad", "print current address with N padded zeros (defaults to 8)",
|
|
"s-", "", "undo seek",
|
|
"s-*", "", "reset undo seek history",
|
|
"s-", " n", "seek n bytes backward",
|
|
"s--", "[n]", "seek blocksize bytes backward (/=n)",
|
|
"s+", "", "redo seek",
|
|
"s+", " n", "seek n bytes forward",
|
|
"s++", "[n]", "seek blocksize bytes forward (/=n)",
|
|
"s[j*=!]", "", "list undo seek history (JSON, =list, *r2, !=names, s==)",
|
|
"s/", " DATA", "search for next occurrence of 'DATA'",
|
|
"s/x", " 9091", "search for next occurrence of \\x90\\x91",
|
|
"sa", " [[+-]a] [asz]", "seek asz (or bsize) aligned to addr",
|
|
"sb", "", "seek aligned to bb start",
|
|
"sC", "[?] string", "seek to comment matching given string",
|
|
"sf", "", "seek to next function (f->addr+f->size)",
|
|
"sf", " function", "seek to address of specified function",
|
|
"sf.", "", "seek to the beginning of current function",
|
|
"sg/sG", "", "seek begin (sg) or end (sG) of section or file",
|
|
"sh", "", "open a basic shell (aims to support basic posix syntax)",
|
|
"sl", "[?] [+-]line", "seek to line",
|
|
"sn/sp", " ([nkey])", "seek to next/prev location, as specified by scr.nkey",
|
|
"snp", "", "seek to next function prelude",
|
|
"spp", "", "seek to prev function prelude",
|
|
"so", " [N]", "seek to N next opcode(s)",
|
|
"sr", " pc", "seek to register",
|
|
"ss", "[?]", "seek silently (without adding an entry to the seek history)",
|
|
// "sp [page] seek page N (page = block)",
|
|
NULL
|
|
};
|
|
|
|
static const char *help_msg_sdot[] = {
|
|
"Usage:", "s.", "Seek here or there (near seeks)",
|
|
"s.", "", "seek here, same as 's $$'",
|
|
"s..", "32a8", "seek to the same address but replacing the lower nibbles",
|
|
NULL
|
|
};
|
|
|
|
static const char *help_msg_sh[] = {
|
|
"Usage:", "sh", "r2's posix shell compatible subset",
|
|
"sh", "", "enters a posix shell subset repl (requires scr.interactive)",
|
|
"sh", " [cmd]", "run the given line and update $?",
|
|
NULL
|
|
};
|
|
|
|
static const char *help_msg_sC[] = {
|
|
"Usage:", "sC", "Comment grep",
|
|
"sC", "*", "list all comments",
|
|
"sC", " str", "seek to the first comment matching 'str'",
|
|
NULL
|
|
};
|
|
|
|
static const char *help_msg_sn[] = {
|
|
"Usage:", "sn[p]", "",
|
|
"sn", " [line]", "seek to next address",
|
|
"snp", "", "seek to next prelude",
|
|
NULL
|
|
};
|
|
|
|
static const char *help_msg_sp[] = {
|
|
"Usage:", "sp[p]", "",
|
|
"sp", " [line]", "seek to previous address",
|
|
"spp", "", "seek to previous prelude",
|
|
NULL
|
|
};
|
|
|
|
static const char *help_msg_sl[] = {
|
|
"Usage:", "sl+ or sl- or slc", "",
|
|
"sl", " [line]", "seek to absolute line",
|
|
"sl", "[+-][line]", "seek to relative line",
|
|
"slc", "", "clear line cache",
|
|
"sll", "", "show total number of lines",
|
|
"sleep", " [seconds]", "sleep for an specific amount of time (support decimal values)",
|
|
NULL
|
|
};
|
|
|
|
static const char *help_msg_ss[] = {
|
|
"Usage: ss", "", " # Seek silently (not recorded in the seek history)",
|
|
"s?", "", "works with all s subcommands",
|
|
NULL
|
|
};
|
|
|
|
static void __init_seek_line(RCore *core) {
|
|
ut64 from, to;
|
|
|
|
r_config_bump (core->config, "lines.to");
|
|
from = r_config_get_i (core->config, "lines.from");
|
|
const char *to_str = r_config_get (core->config, "lines.to");
|
|
to = r_num_math (core->num, (to_str && *to_str) ? to_str : "$s");
|
|
if (r_core_lines_initcache (core, from, to) == -1) {
|
|
R_LOG_ERROR ("lines.from and lines.to are not defined");
|
|
}
|
|
}
|
|
|
|
static void printPadded(RCore *core, int pad) {
|
|
if (pad < 1) {
|
|
pad = 8;
|
|
}
|
|
char *fmt = r_str_newf ("0x%%0%d" PFMT64x, pad);
|
|
char *off = r_str_newf (fmt, core->offset);
|
|
r_cons_printf ("%s\n", off);
|
|
free (off);
|
|
free (fmt);
|
|
}
|
|
|
|
static void __get_current_line(RCore *core) {
|
|
if (core->print->lines_cache_sz > 0) {
|
|
int curr = r_util_lines_getline (core->print->lines_cache, core->print->lines_cache_sz, core->offset);
|
|
r_cons_printf ("%d\n", curr);
|
|
}
|
|
}
|
|
|
|
static void __seek_line_absolute(RCore *core, int numline) {
|
|
if (numline < 1 || numline > core->print->lines_cache_sz - 1) {
|
|
R_LOG_ERROR ("Line must be between 1 and %d", core->print->lines_cache_sz - 1);
|
|
} else {
|
|
r_core_seek (core, core->print->lines_cache[numline - 1], true);
|
|
}
|
|
}
|
|
|
|
static void __seek_line_relative(RCore *core, int numlines) {
|
|
int curr = r_util_lines_getline (core->print->lines_cache, core->print->lines_cache_sz, core->offset);
|
|
if (numlines > 0 && curr + numlines >= core->print->lines_cache_sz - 1) {
|
|
R_LOG_ERROR ("Line must be < %d", core->print->lines_cache_sz - 1);
|
|
} else if (numlines < 0 && curr + numlines < 1) {
|
|
R_LOG_ERROR ("Line must be > 1");
|
|
} else {
|
|
r_core_seek (core, core->print->lines_cache[curr + numlines - 1], true);
|
|
}
|
|
}
|
|
|
|
static void __clean_lines_cache(RCore *core) {
|
|
core->print->lines_cache_sz = -1;
|
|
R_FREE (core->print->lines_cache);
|
|
}
|
|
|
|
R_API int r_core_lines_currline(RCore *core) { // make priv8 again
|
|
int imin = 0;
|
|
int imax = core->print->lines_cache_sz;
|
|
int imid = 0;
|
|
|
|
while (imin <= imax) {
|
|
imid = imin + ((imax - imin) / 2);
|
|
if (core->print->lines_cache[imid] == core->offset) {
|
|
return imid;
|
|
} else if (core->print->lines_cache[imid] < core->offset) {
|
|
imin = imid + 1;
|
|
} else {
|
|
imax = imid - 1;
|
|
}
|
|
}
|
|
return imin;
|
|
}
|
|
|
|
R_API int r_core_lines_initcache(RCore *core, ut64 start_addr, ut64 end_addr) {
|
|
int i, bsz = core->blocksize;
|
|
ut64 off = start_addr;
|
|
ut64 baddr;
|
|
if (start_addr == UT64_MAX || end_addr == UT64_MAX) {
|
|
return -1;
|
|
}
|
|
|
|
free (core->print->lines_cache);
|
|
core->print->lines_cache = R_NEWS0 (ut64, bsz);
|
|
if (!core->print->lines_cache) {
|
|
return -1;
|
|
}
|
|
|
|
baddr = r_config_get_i (core->config, "bin.baddr");
|
|
|
|
int line_count = start_addr? 0: 1;
|
|
core->print->lines_cache[0] = start_addr? 0: baddr;
|
|
char *buf = malloc (bsz);
|
|
if (!buf) {
|
|
return -1;
|
|
}
|
|
r_cons_break_push (NULL, NULL);
|
|
while (off < end_addr) {
|
|
if (r_cons_is_breaked ()) {
|
|
break;
|
|
}
|
|
r_io_read_at (core->io, off, (ut8 *) buf, bsz);
|
|
for (i = 0; i < bsz; i++) {
|
|
if (buf[i] != '\n') {
|
|
continue;
|
|
}
|
|
if ((line_count + 1) >= bsz) {
|
|
break;
|
|
}
|
|
core->print->lines_cache[line_count] = start_addr? off + i + 1: off + i + 1 + baddr;
|
|
line_count++;
|
|
if (line_count % bsz == 0) {
|
|
ut64 *tmp = realloc (core->print->lines_cache,
|
|
(line_count + bsz) * sizeof (ut64));
|
|
if (tmp) {
|
|
core->print->lines_cache = tmp;
|
|
} else {
|
|
R_FREE (core->print->lines_cache);
|
|
goto beach;
|
|
}
|
|
}
|
|
}
|
|
off += bsz;
|
|
}
|
|
free (buf);
|
|
r_cons_break_pop ();
|
|
return line_count;
|
|
beach:
|
|
free (buf);
|
|
r_cons_break_pop ();
|
|
return -1;
|
|
}
|
|
|
|
static void seek_to_register(RCore *core, const char *input, bool is_silent) {
|
|
if (r_config_get_b (core->config, "cfg.debug")) {
|
|
ut64 off = r_debug_reg_get (core->dbg, input);
|
|
if (!is_silent) {
|
|
r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print));
|
|
}
|
|
r_core_seek (core, off, true);
|
|
} else {
|
|
RReg *orig = core->dbg->reg;
|
|
core->dbg->reg = core->anal->reg;
|
|
ut64 off = r_debug_reg_get (core->dbg, input);
|
|
core->dbg->reg = orig;
|
|
if (!is_silent) {
|
|
r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print));
|
|
}
|
|
r_core_seek (core, off, true);
|
|
}
|
|
}
|
|
|
|
static int cmd_sort(void *data, const char *input) { // "sort"
|
|
RCore *core = (RCore *)data;
|
|
const char *arg = strchr (input, ' ');
|
|
if (arg) {
|
|
arg = r_str_trim_head_ro (arg + 1);
|
|
}
|
|
switch (*input) {
|
|
case '?': // "sort?"
|
|
eprintf ("Usage: sort # sort the contents of the file\n");
|
|
break;
|
|
default: // "ls"
|
|
if (!arg) {
|
|
arg = "";
|
|
}
|
|
if (r_fs_check (core->fs, arg)) {
|
|
r_core_cmdf (core, "md %s", arg);
|
|
} else {
|
|
char *res = r_syscmd_sort (arg);
|
|
if (res) {
|
|
r_cons_print (res);
|
|
free (res);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_seek_opcode_backward(RCore *core, int numinstr) {
|
|
int i, val = 0;
|
|
// N previous instructions
|
|
ut64 addr = core->offset;
|
|
int ret = 0;
|
|
if (r_core_prevop_addr (core, core->offset, numinstr, &addr)) {
|
|
ret = core->offset - addr;
|
|
} else {
|
|
#if 0
|
|
// core_asm_bwdis_len is buggy as hell we should kill it. seems like prevop_addr
|
|
// works as expected, because is the one used from visual
|
|
ret = r_core_asm_bwdis_len (core, &instr_len, &addr, numinstr);
|
|
#endif
|
|
addr = core->offset;
|
|
const int mininstrsize = r_anal_archinfo (core->anal, R_ANAL_ARCHINFO_MIN_OP_SIZE);
|
|
for (i = 0; i < numinstr; i++) {
|
|
ut64 prev_addr = r_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;
|
|
}
|
|
RAsmOp op = {0};
|
|
r_core_seek (core, prev_addr, true);
|
|
r_asm_disassemble (core->rasm, &op, core->block, 32);
|
|
if (op.size < mininstrsize) {
|
|
op.size = mininstrsize;
|
|
}
|
|
val += op.size;
|
|
addr = prev_addr;
|
|
r_asm_op_fini (&op);
|
|
}
|
|
}
|
|
r_core_seek (core, addr, true);
|
|
val += ret;
|
|
return val;
|
|
}
|
|
|
|
static int cmd_seek_opcode_forward(RCore *core, int n) {
|
|
// N forward instructions
|
|
int i, ret, val = 0;
|
|
for (val = i = 0; i < n; i++) {
|
|
RAnalOp op;
|
|
ret = r_anal_op (core->anal, &op, core->offset, core->block,
|
|
core->blocksize, R_ANAL_OP_MASK_BASIC);
|
|
if (ret < 1) {
|
|
ret = 1;
|
|
}
|
|
r_core_seek_delta (core, ret);
|
|
r_anal_op_fini (&op);
|
|
val += ret;
|
|
}
|
|
return val;
|
|
}
|
|
|
|
static void cmd_seek_opcode(RCore *core, const char *input) {
|
|
if (input[0] == '?') {
|
|
eprintf ("Usage: so [-][n]\n");
|
|
return;
|
|
}
|
|
if (!strcmp (input, "-")) {
|
|
input = "-1";
|
|
}
|
|
int n = r_num_math (core->num, input);
|
|
if (n == 0) {
|
|
n = 1;
|
|
}
|
|
int val = (n < 0)
|
|
? cmd_seek_opcode_backward (core, -n)
|
|
: cmd_seek_opcode_forward (core, n);
|
|
r_core_return_value (core, val);
|
|
}
|
|
|
|
static int cmd_seek(void *data, const char *input) {
|
|
RCore *core = (RCore *) data;
|
|
char *cmd, *p;
|
|
ut64 off = core->offset;
|
|
|
|
if (!*input) {
|
|
r_cons_printf ("0x%"PFMT64x "\n", core->offset);
|
|
return 0;
|
|
}
|
|
char *ptr;
|
|
if ((ptr = strstr (input, "+."))) {
|
|
char *dup = strdup (input);
|
|
dup[ptr - input] = '\x00';
|
|
off = r_num_math (core->num, dup + 1);
|
|
core->offset = off;
|
|
free (dup);
|
|
}
|
|
const char *inputnum = strchr (input, ' ');
|
|
if (r_str_cmp (input, "ort", 3)) { // hack to handle Invalid Argument for sort
|
|
const char *u_num = inputnum? inputnum + 1: input + 1;
|
|
off = r_num_math (core->num, u_num);
|
|
if (*u_num == '-') {
|
|
off = -(st64)off;
|
|
}
|
|
}
|
|
#if 1
|
|
// int sign = 1;
|
|
if (input[0] == ' ') {
|
|
switch (input[1]) {
|
|
case '-':
|
|
// sign = -1;
|
|
/* pass thru */
|
|
case '+':
|
|
input++;
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
bool silent = false;
|
|
if (*input == 's') {
|
|
silent = true;
|
|
input++;
|
|
if (*input == '?') {
|
|
r_core_cmd_help (core, help_msg_ss);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
switch (*input) {
|
|
case 'r': // "sr"
|
|
if (input[1] && input[2]) {
|
|
seek_to_register (core, input + 2, silent);
|
|
} else {
|
|
eprintf ("Usage: 'sr PC' seek to program counter register\n");
|
|
}
|
|
break;
|
|
case 'C': // "sC"
|
|
if (input[1] == '*') { // "sC*"
|
|
r_core_cmd0 (core, "C*~^\"CC");
|
|
} else if (input[1] == ' ') {
|
|
RIntervalTreeIter it;
|
|
RAnalMetaItem *meta;
|
|
bool seeked = false;
|
|
r_interval_tree_foreach (&core->anal->meta, it, meta) {
|
|
if (meta->type == R_META_TYPE_COMMENT && !strcmp (meta->str, input + 2)) {
|
|
if (!silent) {
|
|
r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print));
|
|
}
|
|
r_core_seek (core, off, true);
|
|
r_core_block_read (core);
|
|
seeked = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!seeked) {
|
|
R_LOG_ERROR ("No matching comment");
|
|
}
|
|
} else {
|
|
r_core_cmd_help (core, help_msg_sC);
|
|
}
|
|
break;
|
|
case '0': // "s0"
|
|
case '1': // "s1"
|
|
case '2': // "s2"
|
|
case '3': // "s3"
|
|
case '4': // "s4"
|
|
case '5': // "s5"
|
|
case '6': // "s6"
|
|
case '7': // "s7"
|
|
case '8': // "s8"
|
|
case '9': // "s9"
|
|
case ' ': // "s "
|
|
{
|
|
ut64 addr = r_num_math (core->num, r_str_trim_head_ro (input));
|
|
if (core->num->nc.errors) { // TODO expose an api for this char *r_num_failed();
|
|
if (r_cons_singleton ()->context->is_interactive) {
|
|
R_LOG_ERROR ("Cannot seek to unknown address '%s'", core->num->nc.calc_buf);
|
|
}
|
|
break;
|
|
}
|
|
if (!silent) {
|
|
r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print));
|
|
}
|
|
r_core_seek (core, addr, true);
|
|
r_core_block_read (core);
|
|
}
|
|
break;
|
|
case '/': // "s/"
|
|
{
|
|
const char *pfx = r_config_get (core->config, "search.prefix");
|
|
const ut64 saved_from = r_config_get_i (core->config, "search.from");
|
|
const ut64 saved_maxhits = r_config_get_i (core->config, "search.maxhits");
|
|
// kwidx cfg var is ignored
|
|
int kwidx = core->search->n_kws; // (int)r_config_get_i (core->config, "search.kwidx")-1;
|
|
if (kwidx < 0) {
|
|
kwidx = 0;
|
|
}
|
|
switch (input[1]) {
|
|
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':
|
|
r_config_set_i (core->config, "search.from", core->offset + 1);
|
|
r_config_set_i (core->config, "search.maxhits", 1);
|
|
r_core_cmdf (core, "s+1; %s; s-1; s %s%d_0; f-%s%d_0",
|
|
input, pfx, kwidx, pfx, kwidx);
|
|
r_config_set_i (core->config, "search.from", saved_from);
|
|
r_config_set_i (core->config, "search.maxhits", saved_maxhits);
|
|
break;
|
|
case '?':
|
|
eprintf ("Usage: s/.. arg.\n");
|
|
r_cons_printf ("/?\n");
|
|
break;
|
|
default:
|
|
R_LOG_ERROR ("unknown search subcommand");
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case '.': // "s." "s.."
|
|
if (input[1] == '?') {
|
|
r_core_cmd_help (core, help_msg_sdot);
|
|
} else if (input[1]) {
|
|
for (input++; *input == '.'; input++) {
|
|
;
|
|
}
|
|
r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print));
|
|
r_core_seek_base (core, input);
|
|
} else {
|
|
// just re-read the current block
|
|
r_core_seek (core, core->offset, true);
|
|
r_core_block_read (core);
|
|
}
|
|
break;
|
|
case 'j': // "sj"
|
|
{
|
|
RList /*<ut64 *>*/ *addrs = r_list_newf (free);
|
|
RList /*<char *>*/ *names = r_list_newf (free);
|
|
RList *list = r_io_sundo_list (core->io, '!');
|
|
ut64 lsz = 0;
|
|
ut64 i;
|
|
RListIter *iter;
|
|
RIOUndos *undo;
|
|
if (list) {
|
|
r_list_foreach (list, iter, undo) {
|
|
char *name = NULL;
|
|
|
|
RFlagItem *f = r_flag_get_at (core->flags, undo->off, true);
|
|
if (f) {
|
|
if (f->offset != undo->off) {
|
|
name = r_str_newf ("%s+%d", f->name,
|
|
(int)(undo->off- f->offset));
|
|
} else {
|
|
name = strdup (f->name);
|
|
}
|
|
}
|
|
if (!name) {
|
|
name = strdup ("");
|
|
}
|
|
ut64 *val = malloc (sizeof (ut64));
|
|
if (!val) {
|
|
free (name);
|
|
break;
|
|
}
|
|
*val = undo->off;
|
|
r_list_append (addrs, val);
|
|
r_list_append (names, strdup (name));
|
|
lsz++;
|
|
free (name);
|
|
}
|
|
r_list_free (list);
|
|
}
|
|
PJ *pj = pj_new ();
|
|
pj_a (pj);
|
|
for (i = 0; i < lsz; i++) {
|
|
ut64 *addr = r_list_get_n (addrs, i);
|
|
const char *name = r_list_get_n (names, i);
|
|
pj_o (pj);
|
|
pj_kn (pj, "offset", *addr);
|
|
if (name && *name) {
|
|
pj_ks (pj, "name", name);
|
|
}
|
|
if (core->io->undo.undos == i) {
|
|
pj_kb (pj, "current", true);
|
|
}
|
|
pj_end (pj);
|
|
}
|
|
pj_end (pj);
|
|
char *s = pj_drain (pj);
|
|
r_cons_printf ("%s\n", s);
|
|
free (s);
|
|
r_list_free (addrs);
|
|
r_list_free (names);
|
|
}
|
|
break;
|
|
case '*': // "s*"
|
|
case '=': // "s="
|
|
case '!': // "s!"
|
|
{
|
|
char mode = input[0];
|
|
if (input[1] == '=') {
|
|
mode = 0;
|
|
} else if (input[1] == '*') {
|
|
mode = 'r';
|
|
}
|
|
RList *list = r_io_sundo_list (core->io, mode);
|
|
if (list) {
|
|
RListIter *iter;
|
|
RIOUndos *undo;
|
|
r_list_foreach (list, iter, undo) {
|
|
char *name = NULL;
|
|
|
|
RFlagItem *f = r_flag_get_at (core->flags, undo->off, true);
|
|
if (f) {
|
|
if (f->offset != undo->off) {
|
|
name = r_str_newf ("%s + %d\n", f->name,
|
|
(int)(undo->off - f->offset));
|
|
} else {
|
|
name = strdup (f->name);
|
|
}
|
|
}
|
|
if (mode) {
|
|
r_cons_printf ("0x%"PFMT64x" %s\n", undo->off, r_str_get (name));
|
|
} else {
|
|
if (!name) {
|
|
name = r_str_newf ("0x%"PFMT64x, undo->off);
|
|
}
|
|
r_cons_printf ("%s%s", name, iter->n? " > ":"");
|
|
}
|
|
free (name);
|
|
}
|
|
r_list_free (list);
|
|
if (!mode) {
|
|
r_cons_newline ();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case '+': // "s+"
|
|
if (input[1] != '\0') {
|
|
int delta = off;
|
|
if (input[1] == '+') {
|
|
delta = core->blocksize;
|
|
int mult = r_num_math (core->num, input + 2);
|
|
if (mult > 0) {
|
|
delta /= mult;
|
|
}
|
|
}
|
|
// int delta = (input[1] == '+')? core->blocksize: off;
|
|
if (!silent) {
|
|
r_io_sundo_push (core->io, core->offset,
|
|
r_print_get_cursor (core->print));
|
|
}
|
|
r_core_seek_delta (core, delta);
|
|
r_core_block_read (core);
|
|
} else {
|
|
RIOUndos *undo = r_io_sundo_redo (core->io);
|
|
if (undo) {
|
|
r_core_seek (core, undo->off, false);
|
|
r_core_block_read (core);
|
|
}
|
|
}
|
|
break;
|
|
case '-': // "s-"
|
|
switch (input[1]) {
|
|
case '*': // "s-*"
|
|
r_io_sundo_reset (core->io);
|
|
break;
|
|
case 0: // "s-"
|
|
{
|
|
RIOUndos *undo = r_io_sundo (core->io, core->offset);
|
|
if (undo) {
|
|
r_core_seek (core, undo->off, false);
|
|
r_core_block_read (core);
|
|
}
|
|
}
|
|
break;
|
|
case '-': // "s--"
|
|
default:
|
|
{
|
|
st64 delta = -(st64)off;
|
|
if (input[1] == '-') {
|
|
delta = -(st64)core->blocksize;
|
|
int mult = r_num_math (core->num, input + 2);
|
|
if (mult > 0) {
|
|
delta /= mult;
|
|
}
|
|
}
|
|
if (!silent) {
|
|
r_io_sundo_push (core->io, core->offset,
|
|
r_print_get_cursor (core->print));
|
|
}
|
|
r_core_seek_delta (core, delta);
|
|
r_core_block_read (core);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case 'n': // "sn"
|
|
if (input[1] == '?') {
|
|
r_core_cmd_help (core, help_msg_sn);
|
|
} else if (input[1] == 'p') { // "snp" - seek next prelude
|
|
__core_cmd_search_backward_prelude (core, true, true);
|
|
} else {
|
|
if (!silent) {
|
|
r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print));
|
|
}
|
|
const char *nkey = (input[1] == ' ')
|
|
? input + 2
|
|
: r_config_get (core->config, "scr.nkey");
|
|
r_core_seek_next (core, nkey);
|
|
}
|
|
break;
|
|
case 'p': // "sp"
|
|
if (input[1] == '?') {
|
|
r_core_cmd_help (core, help_msg_sp);
|
|
} else if (input[1] == 'p') { // "spp" - seek previous prelude
|
|
__core_cmd_search_backward_prelude (core, true, false);
|
|
} else {
|
|
if (!silent) {
|
|
r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print));
|
|
}
|
|
const char *nkey = (input[1] == ' ')
|
|
? input + 2
|
|
: r_config_get (core->config, "scr.nkey");
|
|
r_core_seek_previous (core, nkey);
|
|
}
|
|
break;
|
|
case 'a': // "sa"
|
|
off = core->blocksize;
|
|
if (input[1] && input[2]) {
|
|
cmd = strdup (input);
|
|
p = strchr (cmd + 2, ' ');
|
|
if (p) {
|
|
off = r_num_math (core->num, p + 1);
|
|
*p = '\0';
|
|
}
|
|
cmd[0] = 's';
|
|
// perform real seek if provided
|
|
r_cmd_call (core->rcmd, cmd);
|
|
free (cmd);
|
|
}
|
|
if (!silent) {
|
|
r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print));
|
|
}
|
|
r_core_seek_align (core, off, 0);
|
|
break;
|
|
case 'b': // "sb"
|
|
if (off == 0) {
|
|
off = core->offset;
|
|
}
|
|
if (!silent) {
|
|
r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print));
|
|
}
|
|
r_core_anal_bb_seek (core, off);
|
|
break;
|
|
case 'f': { // "sf"
|
|
RAnalFunction *fcn;
|
|
switch (input[1]) {
|
|
case '\0': // "sf"
|
|
fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
|
|
if (fcn) {
|
|
r_core_seek (core, r_anal_function_max_addr (fcn), true);
|
|
}
|
|
break;
|
|
case ' ': // "sf "
|
|
fcn = r_anal_get_function_byname (core->anal, input + 2);
|
|
if (fcn) {
|
|
r_core_seek (core, fcn->addr, true);
|
|
}
|
|
break;
|
|
case '.': // "sf."
|
|
fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
|
|
if (fcn) {
|
|
r_core_seek (core, fcn->addr, true);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case 'o': // "so"
|
|
switch (input[1]) {
|
|
case 'r':
|
|
if (input[2] == 't') {
|
|
cmd_sort (core, input);
|
|
} else {
|
|
return -1;
|
|
}
|
|
break;
|
|
case ' ':
|
|
case '\0':
|
|
case '+':
|
|
case '-':
|
|
cmd_seek_opcode (core, input + 1);
|
|
break;
|
|
default:
|
|
return -1; // invalid command
|
|
}
|
|
break;
|
|
case 'g': // "sg"
|
|
{
|
|
RIOMap *map = r_io_map_get_at (core->io, core->offset);
|
|
if (map) {
|
|
r_core_seek (core, r_io_map_begin (map), true);
|
|
} else {
|
|
r_core_seek (core, 0, true);
|
|
}
|
|
}
|
|
break;
|
|
case 'G': // "sG"
|
|
{
|
|
if (!core->io->desc) {
|
|
break;
|
|
}
|
|
RIOMap *map = r_io_map_get_at (core->io, core->offset);
|
|
// XXX: this +2 is a hack. must fix gap between sections
|
|
if (map) {
|
|
r_core_seek (core, r_io_map_end (map) + 2, true);
|
|
} else {
|
|
r_core_seek (core, r_io_fd_size (core->io, core->io->desc->fd), true);
|
|
}
|
|
}
|
|
break;
|
|
case 'h': // "sh"
|
|
if (input[1] == '?') {
|
|
r_core_cmd_help (core, help_msg_sh);
|
|
} else {
|
|
char *arg = r_str_trim_dup (input + 1);
|
|
if (R_STR_ISNOTEMPTY (arg)) {
|
|
int rc = r_sys_tem (arg);
|
|
r_core_return_value (core, (rc > 0)? rc: 1);
|
|
} else {
|
|
if (r_config_get_b (core->config, "scr.interactive")) {
|
|
// open shell
|
|
r_line_set_prompt ("sh> ");
|
|
for (;;) {
|
|
const char *line = r_line_readline ();
|
|
if (!line || !strcmp (line, "exit")) {
|
|
break;
|
|
}
|
|
int rc = r_sys_tem (line);
|
|
r_core_return_value (core, (rc > 0)? rc: 1);
|
|
}
|
|
} else {
|
|
R_LOG_WARN ("enable scr.interactive to use this new shell prompt");
|
|
}
|
|
}
|
|
free (arg);
|
|
}
|
|
break;
|
|
case 'l': // "sl"
|
|
{
|
|
int sl_arg = r_num_math (core->num, input + 1);
|
|
switch (input[1]) {
|
|
case 'e': // "sleep"
|
|
{
|
|
const char *arg = strchr (input, ' ');
|
|
if (arg) {
|
|
arg++;
|
|
void *bed = r_cons_sleep_begin ();
|
|
if (strchr (arg, '.')) {
|
|
double d = 0;
|
|
sscanf (arg, "%lf", &d);
|
|
r_sys_usleep ((int)(d * 1000000));
|
|
} else {
|
|
r_sys_sleep (atoi (arg));
|
|
}
|
|
r_cons_sleep_end (bed);
|
|
} else {
|
|
eprintf ("Usage: sleep [seconds]\n");
|
|
}
|
|
}
|
|
break;
|
|
case '\0': // "sl"
|
|
if (!core->print->lines_cache) {
|
|
__init_seek_line (core);
|
|
}
|
|
__get_current_line (core);
|
|
break;
|
|
case ' ': // "sl "
|
|
if (!core->print->lines_cache) {
|
|
__init_seek_line (core);
|
|
}
|
|
__seek_line_absolute (core, sl_arg);
|
|
break;
|
|
case '+': // "sl+"
|
|
case '-': // "sl-"
|
|
if (!core->print->lines_cache) {
|
|
__init_seek_line (core);
|
|
}
|
|
__seek_line_relative (core, sl_arg);
|
|
break;
|
|
case 'c': // "slc"
|
|
__clean_lines_cache (core);
|
|
break;
|
|
case 'l': // "sll"
|
|
if (!core->print->lines_cache) {
|
|
__init_seek_line (core);
|
|
}
|
|
r_cons_printf ("%d\n", core->print->lines_cache_sz - 1);
|
|
break;
|
|
case '?': // "sl?"
|
|
r_core_cmd_help (core, help_msg_sl);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case ':': // "s:"
|
|
printPadded (core, atoi (input + 1));
|
|
break;
|
|
case '?': // "s?"
|
|
r_core_cmd_help (core, help_msg_s);
|
|
break;
|
|
default:
|
|
{
|
|
ut64 n = r_num_math (core->num, input);
|
|
if (n) {
|
|
if (!silent) {
|
|
r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print));
|
|
}
|
|
r_core_seek (core, n, true);
|
|
r_core_block_read (core);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|