rizin/librz/core/cmd_open.c

1612 lines
42 KiB
C

// SPDX-FileCopyrightText: 2009-2021 pancake <pancake@nopcode.org>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_bin.h>
#include <rz_debug.h>
static const char *help_msg_o[] = {
"Usage: o", "[com- ] [file] ([offset])", "",
"o", " [file] 0x4000 rwx", "map file at 0x4000",
"o", " [file]", "open [file] file in read-only",
"o", "", "list opened files",
"o", "-1", "close file descriptor 1",
"o*", "", "list opened files in rizin commands",
"o+", " [file]", "open file in read-write mode",
"o-", "!*", "close all opened files",
"o--", "", "close all files, analysis, binfiles, flags, same as !rizin --",
"o.", "", "show current filename (or o.q/oq to get the fd)",
"oC", " [len]", "open a malloc://[len] copying the bytes from current offset",
"o=", "", "list opened files (ascii-art bars)",
"oL", "", "list all IO plugins registered",
"oa", "[-] [A] [B] [filename]", "Specify arch and bits for given file",
"ob", "[?] [lbdos] [...]", "list opened binary files backed by fd",
"oc", " [file]", "open core file, like relaunching rizin",
"of", " [file]", "open file and map it at addr 0 as read-only",
"oi", "[-|idx]", "alias for o, but using index instead of fd",
"oj", "[?] ", "list opened files in JSON format",
"om", "[?]", "create, list, remove IO maps",
"on", " [file] 0x4000", "map raw file at 0x4000 (no rz_bin involved)",
"oo", "[?+bcdnm]", "reopen current file (see oo?) (reload in rw or debugger)",
"op", "[r|n|p|fd]", "select priorized file by fd (see ob), opn/opp/opr = next/previous/rotate",
"oq", "", "list all open files",
"ox", " fd fdx", "exchange the descs of fd and fdx and keep the mapping",
NULL
};
static const char *help_msg_o_[] = {
"Usage: o-", "[#!*]", "",
"o-*", "", "close all opened files",
"o-!", "", "close all files except the current one",
"o-3", "", "close fd=3",
NULL
};
static const char *help_msg_op[] = {
"Usage:", "op[rnp] [fd]", "",
"opr", "", "open next file rotating",
"opn", "", "open next file",
"opp", "", "open previous file",
"op", " [fd]", "open priorizing fd",
NULL
};
static const char *help_msg_o_star[] = {
"Usage:", "o* [> files.rz]", "",
"o*", "", "list opened files in rizin commands", NULL
};
static const char *help_msg_oa[] = {
"Usage:", "oba [addr] ([filename])", " # load bininfo and update flags",
"oba", " [addr]", "Open bin info from the given address",
"oba", " [addr] [baddr]", "Open file and load bin info at given address",
"oba", " [addr] [/abs/filename]", "Open file and load bin info at given address",
NULL
};
static const char *help_msg_ob[] = {
"Usage:", "ob", " # List open binary files backed by fd",
"ob", " [bfid]", "Switch to open given objid",
"ob", "", "List opened binary files and objid",
"ob*", "", "List opened binary files and objid (rizin commands)",
"ob-", "*", "Delete all binfiles",
"ob-", "[objid]", "Delete binfile by binobjid",
"ob.", " ([addr])", "Show bfid at current address",
"ob=", "", "Show ascii art table having the list of open files",
"obL", "", "Same as iL or Li",
"oba", " [addr] [baddr]", "Open file and load bin info at given address",
"oba", " [addr] [filename]", "Open file and load bin info at given address",
"oba", " [addr]", "Open bin info from the given address",
"obf", " ([file])", "Load bininfo for current file (useful for rizin -n)",
"obj", "", "List opened binary files and objid (JSON format)",
"obn", " [name]", "Select binfile by name",
"obo", " [fd]", "Switch to open binfile by fd number",
"obr", " [baddr]", "Rebase current bin object",
NULL
};
static const char *help_msg_oj[] = {
"Usage:", "oj [~{}]", " # Use ~{} to indent the JSON",
"oj", "", "list opened files in JSON format", NULL
};
static const char *help_msg_om[] = {
"Usage:", "om[-] [arg]", " # map opened files",
"om", " [fd]", "list all defined IO maps for a specific fd",
"om", " fd vaddr [size] [paddr] [rwx] [name]", "create new io map",
"om", "", "list all defined IO maps",
"om*", "", "list all maps in rizin commands format",
"om-", "mapid", "remove the map with corresponding id",
"om-*", "", "remove all maps",
"om-..", "", "hud view of all the maps to select the one to remove",
"om.", "", "show map, that is mapped to current offset",
"om=", "", "list all maps in ascii art",
"oma", " [fd]", "create a map covering all VA for given fd",
"omb", " mapid addr", "relocate map with corresponding id",
"omb.", " addr", "relocate current map",
"omf", " [mapid] rwx", "change flags/perms for current/given map",
"omfg", "[+-]rwx", "change flags/perms for all maps (global)",
"omj", "", "list all maps in json format",
"omm", " [fd]", "create default map for given fd. (omm `oq`)",
"omn", " mapaddr [name]", "set/delete name for map which spans mapaddr",
"omn.", "([-|name])", "show/set/delete name for current map",
"omni", " mapid [name]", "set/delete name for map with mapid",
"omo", " fd", "map the given fd with lowest priority",
"omp", " mapid", "prioritize map with corresponding id",
"ompb", " [fd]", "prioritize maps of the bin associated with the binid",
"ompd", " mapid", "deprioritize map with corresponding id",
"ompf", " [fd]", "prioritize map by fd",
"omq", "", "list all maps and their fds",
"omqq", "", "list all maps addresses (See $MM to get the size)",
"omr", " mapid newsize", "resize map with corresponding id",
"omt", " [query]", "list maps using table api",
NULL
};
static const char *help_msg_oo[] = {
"Usage:", "oo[-] [arg]", " # map opened files",
"oo", "", "reopen current file",
"oo+", "", "reopen in read-write",
"oob", " [baddr]", "reopen loading rbin info (change base address?)",
"ooc", "", "reopen core with current file",
"ood", "", "reopen in debug mode",
"oom", "", "reopen in malloc://",
"oon", "", "reopen without loading rbin info",
"oon+", "", "reopen in read-write mode without loading rbin info",
"oonn", "", "reopen without loading rbin info, but with header flags",
"oonn+", "", "reopen in read-write mode without loading rbin info, but with",
NULL
};
static const char *help_msg_oo_plus[] = {
"Usage:", "oo+", " # reopen in read-write",
NULL
};
static const char *help_msg_oob[] = {
"Usage:", "oob", " # reopen loading rbin info",
NULL
};
static const char *help_msg_ood[] = {
"Usage:", "ood", " # Debug (re)open commands",
"ood", " [args]", " # reopen in debug mode (with args)",
"oodf", " [file]", " # reopen in debug mode using the given file",
"oodr", " [rz-run]", " # same as dor ..;ood",
NULL
};
static const char *help_msg_oon[] = {
"Usage:", "oon[+]", " # reopen without loading rbin info",
"oon", "", "reopen without loading rbin info",
"oon+", "", "reopen in read-write mode without loading rbin info",
NULL
};
static const char *help_msg_oonn[] = {
"Usage:", "oonn", " # reopen without loading rbin info, but with header flags",
"oonn", "", "reopen without loading rbin info, but with header flags",
"oonn+", "", "reopen in read-write mode without loading rbin info, but with",
NULL
};
// HONOR bin.at
static void cmd_open_bin(RzCore *core, const char *input) {
const char *value = NULL;
ut32 binfile_num = -1;
switch (input[1]) {
case 'L': // "obL"
rz_core_cmd0(core, "iL");
break;
case '\0': // "ob"
case 'q': // "obj"
case 'j': // "obj"
case '*': // "ob*"
rz_core_bin_list(core, input[1]);
if (input[1] == 'j') {
rz_cons_newline();
}
break;
case '.': // "ob."
{
const char *arg = rz_str_trim_head_ro(input + 2);
ut64 at = core->offset;
if (*arg) {
at = rz_num_math(core->num, arg);
if (at == 0 && *arg != '0') {
at = core->offset;
}
}
RzBinFile *bf = rz_bin_file_at(core->bin, at);
if (bf) {
rz_cons_printf("%d\n", bf->id);
}
} break;
case 'a': // "oba"
if ('?' == input[2]) {
rz_core_cmd_help(core, help_msg_oa);
break;
}
if (input[2] && input[3]) {
char *arg = strdup(input + 3);
char *filename = strchr(arg, ' ');
if (filename && *filename && (filename[1] == '/' || filename[1] == '.')) {
int saved_fd = rz_io_fd_get_current(core->io);
RzIODesc *desc = rz_io_open(core->io, filename + 1, RZ_PERM_R, 0);
if (desc) {
*filename = 0;
ut64 addr = rz_num_math(core->num, arg);
RzBinOptions opt;
rz_bin_options_init(&opt, desc->fd, addr, 0, core->bin->rawstr);
rz_bin_open_io(core->bin, &opt);
rz_io_desc_close(desc);
rz_core_cmd0(core, ".is*");
rz_io_use_fd(core->io, saved_fd);
} else {
eprintf("Cannot open %s\n", filename + 1);
}
} else if (filename && *filename) {
ut64 baddr = rz_num_math(core->num, filename);
ut64 addr = rz_num_math(core->num, input + 2); // mapaddr
int fd = rz_io_fd_get_current(core->io);
RzIODesc *desc = rz_io_desc_get(core->io, fd);
if (desc) {
RzBinOptions opt;
opt.baseaddr = baddr;
opt.loadaddr = addr;
opt.sz = 1024 * 1024 * 1;
rz_bin_options_init(&opt, desc->fd, baddr, addr, core->bin->rawstr);
rz_bin_open_io(core->bin, &opt);
rz_core_cmd0(core, ".is*");
} else {
eprintf("No file to load bin from?\n");
}
} else {
ut64 addr = rz_num_math(core->num, input + 2);
int fd = rz_io_fd_get_current(core->io);
RzIODesc *desc = rz_io_desc_get(core->io, fd);
if (desc) {
RzBinOptions opt;
opt.baseaddr = addr;
opt.loadaddr = addr;
opt.sz = 1024 * 1024 * 1;
rz_bin_options_init(&opt, desc->fd, addr, addr, core->bin->rawstr);
rz_bin_open_io(core->bin, &opt);
rz_core_cmd0(core, ".is*");
} else {
eprintf("No file to load bin from?\n");
}
}
free(arg);
} else {
RzList *ofiles = rz_id_storage_list(core->io->files);
RzIODesc *desc;
RzListIter *iter;
RzList *files = rz_list_newf(NULL);
rz_list_foreach (ofiles, iter, desc) {
rz_list_append(files, (void *)(size_t)desc->fd);
}
void *_fd;
rz_list_foreach (files, iter, _fd) {
int fd = (size_t)_fd;
RzBinOptions opt;
rz_bin_options_init(&opt, fd, core->offset, 0, core->bin->rawstr);
rz_bin_open_io(core->bin, &opt);
rz_core_cmd0(core, ".ies*");
break;
}
rz_list_free(files);
}
break;
case ' ': // "ob "
{
ut32 id;
int n;
const char *tmp;
char *v;
v = input[2] ? strdup(input + 2) : NULL;
if (!v) {
eprintf("Invalid arguments");
break;
}
n = rz_str_word_set0(v);
if (n < 1 || n > 2) {
eprintf("Usage: ob [file|objid]\n");
free(v);
break;
}
tmp = rz_str_word_get0(v, 0);
id = *v && rz_is_valid_input_num_value(core->num, tmp)
? rz_get_input_num_value(core->num, tmp)
: UT32_MAX;
if (n != 2) {
binfile_num = id;
}
rz_core_bin_raise(core, binfile_num);
free(v);
break;
}
case 'r': // "obr"
rz_core_bin_rebase(core, rz_num_math(core->num, input + 3));
rz_core_cmd0(core, ".is*");
break;
case 'f':
if (input[2] == ' ') {
rz_core_cmdf(core, "oba 0 %s", input + 3);
} else {
rz_core_bin_load(core, NULL, UT64_MAX);
}
break;
case 'o': // "obo"
if (input[2] == ' ') {
ut32 fd = rz_num_math(core->num, input + 3);
RzBinFile *bf = rz_bin_file_find_by_fd(core->bin, fd);
if (!bf || !rz_core_bin_raise(core, bf->id)) {
eprintf("Invalid RzBinFile.id number.\n");
}
} else {
eprintf("Usage: obb [bfid]\n");
}
break;
case '-': // "ob-"
if (input[2] == '*') {
rz_bin_file_delete_all(core->bin);
} else {
ut32 id;
value = rz_str_trim_head_ro(input + 2);
if (!value) {
eprintf("Invalid argument\n");
break;
}
id = (*value && rz_is_valid_input_num_value(core->num, value)) ? rz_get_input_num_value(core->num, value) : UT32_MAX;
RzBinFile *bf = rz_bin_file_find_by_id(core->bin, id);
if (!bf) {
eprintf("Invalid binid\n");
break;
}
if (!rz_core_bin_delete(core, bf->id)) {
eprintf("Cannot find an RzBinFile associated with that id.\n");
}
}
break;
case '=': // "ob="
{
RzListIter *iter;
RzList *list = rz_list_newf((RzListFree)rz_listinfo_free);
RzBinFile *bf = NULL;
RzBin *bin = core->bin;
if (!bin) {
return;
}
rz_list_foreach (bin->binfiles, iter, bf) {
char temp[4];
RzInterval inter = (RzInterval){ bf->o->baddr, bf->o->size };
RzListInfo *info = rz_listinfo_new(bf->file, inter, inter, -1, sdb_itoa(bf->fd, temp, 10));
if (!info) {
break;
}
rz_list_append(list, info);
}
RzTable *table = rz_core_table(core);
rz_table_visual_list(table, list, core->offset, core->blocksize,
rz_cons_get_size(NULL), rz_config_get_i(core->config, "scr.color"));
char *table_text = rz_table_tostring(table);
rz_cons_printf("\n%s\n", table_text);
rz_free(table_text);
rz_table_free(table);
rz_list_free(list);
} break;
case '?': // "ob?"
rz_core_cmd_help(core, help_msg_ob);
break;
}
}
// TODO: discuss the output format
static void map_list(RzIO *io, int mode, RzPrint *print, int fd) {
if (!io || !print || !print->cb_printf) {
return;
}
PJ *pj = NULL;
if (mode == 'j') {
pj = pj_new();
if (!pj) {
return;
}
pj_a(pj);
}
char *om_cmds = NULL;
void **it;
rz_pvector_foreach_prev(&io->maps, it) { //this must be prev (LIFO)
RzIOMap *map = *it;
if (fd >= 0 && map->fd != fd) {
continue;
}
switch (mode) {
case 'q':
if (fd == -2) {
print->cb_printf("0x%08" PFMT64x "\n", rz_io_map_get_from(map));
} else {
print->cb_printf("%d %d\n", map->fd, map->id);
}
break;
case 'j':
pj_o(pj);
pj_ki(pj, "map", map->id);
pj_ki(pj, "fd", map->fd);
pj_kn(pj, "delta", map->delta);
pj_kn(pj, "from", rz_io_map_get_from(map));
pj_kn(pj, "to", rz_itv_end(map->itv));
pj_ks(pj, "perm", rz_str_rwx_i(map->perm));
pj_ks(pj, "name", rz_str_get(map->name));
pj_end(pj);
break;
case 1:
case '*':
case 'r': {
// Need FIFO order here
char *om_cmd = rz_str_newf("om %d 0x%08" PFMT64x " 0x%08" PFMT64x " 0x%08" PFMT64x " %s%s%s\n",
map->fd, rz_io_map_get_from(map), map->itv.size, map->delta, rz_str_rwx_i(map->perm),
map->name ? " " : "", rz_str_get(map->name));
if (om_cmd) {
om_cmds = rz_str_prepend(om_cmds, om_cmd);
free(om_cmd);
}
break;
}
default:
print->cb_printf("%2d fd: %i +0x%08" PFMT64x " 0x%08" PFMT64x
" - 0x%08" PFMT64x " %s %s\n",
map->id, map->fd,
map->delta, rz_io_map_get_from(map), rz_io_map_get_to(map),
rz_str_rwx_i(map->perm), rz_str_get(map->name));
break;
}
}
if (om_cmds) {
print->cb_printf("%s", om_cmds);
free(om_cmds);
}
if (mode == 'j') {
pj_end(pj);
print->cb_printf("%s\n", pj_string(pj));
pj_free(pj);
}
}
static void cmd_omfg(RzCore *core, const char *input) {
input = rz_str_trim_head_ro(input);
if (input) {
int perm = *input
? (*input == '+' || *input == '-')
? rz_str_rwx(input + 1)
: rz_str_rwx(input)
: 7;
void **it;
switch (*input) {
case '+':
rz_pvector_foreach (&core->io->maps, it) {
RzIOMap *map = *it;
map->perm |= perm;
}
break;
case '-':
rz_pvector_foreach (&core->io->maps, it) {
RzIOMap *map = *it;
map->perm &= ~perm;
}
break;
default:
rz_pvector_foreach (&core->io->maps, it) {
RzIOMap *map = *it;
map->perm = perm;
}
break;
}
}
}
static void cmd_omf(RzCore *core, const char *input) {
char *arg = strdup(rz_str_trim_head_ro(input));
if (!arg) {
return;
}
char *sp = strchr(arg, ' ');
if (sp) {
// change perms of Nth map
*sp++ = 0;
int id = rz_num_math(core->num, arg);
int perm = (*sp) ? rz_str_rwx(sp) : RZ_PERM_RWX;
void **it;
rz_pvector_foreach (&core->io->maps, it) {
RzIOMap *map = *it;
if (map->id == id) {
map->perm = perm;
break;
}
}
} else {
// change perms of current map
int perm = (arg && *arg) ? rz_str_rwx(arg) : RZ_PERM_RWX;
void **it;
rz_pvector_foreach (&core->io->maps, it) {
RzIOMap *map = *it;
if (rz_itv_contain(map->itv, core->offset)) {
map->perm = perm;
}
}
}
free(arg);
}
static void rz_core_cmd_omt(RzCore *core, const char *arg) {
RzTable *t = rz_table_new();
rz_table_set_columnsf(t, "nnnnnnnss", "id", "fd", "pa", "pa_end", "size", "va", "va_end", "perm", "name", NULL);
void **it;
rz_pvector_foreach (&core->io->maps, it) {
RzIOMap *m = *it;
ut64 va = rz_itv_begin(m->itv);
ut64 va_end = rz_itv_end(m->itv);
ut64 pa = m->delta;
ut64 pa_size = rz_itv_size(m->itv);
ut64 pa_end = pa + pa_size;
const char *name = m->name ? m->name : "";
rz_table_add_rowf(t, "ddxxxxxss", m->id, m->fd, pa, pa_end, pa_size, va, va_end, rz_str_rwx_i(m->perm), name);
}
if (rz_table_query(t, arg)) {
char *ts = rz_table_tofancystring(t);
rz_cons_printf("%s", ts);
free(ts);
}
rz_table_free(t);
}
static void cmd_open_map(RzCore *core, const char *input) {
ut64 fd = 0LL;
ut32 id = 0;
ut64 addr = 0;
char *s = NULL, *p = NULL, *q = NULL;
ut64 new;
RzIOMap *map = NULL;
const char *P;
PJ *pj;
switch (input[1]) {
case '.': // "om."
map = rz_io_map_get(core->io, core->offset);
if (map) {
if (input[2] == 'j') { // "om.j"
pj = pj_new();
if (!pj) {
return;
}
pj_o(pj);
pj_ki(pj, "map", map->id);
pj_ki(pj, "fd", map->fd);
pj_kn(pj, "delta", map->delta);
pj_kn(pj, "from", rz_io_map_get_from(map));
pj_kn(pj, "to", rz_itv_end(map->itv));
pj_ks(pj, "perm", rz_str_rwx_i(map->perm));
pj_ks(pj, "name", rz_str_get(map->name));
pj_end(pj);
core->print->cb_printf("%s\n", pj_string(pj));
pj_free(pj);
} else {
core->print->cb_printf("%2d fd: %i +0x%08" PFMT64x " 0x%08" PFMT64x
" - 0x%08" PFMT64x " %s %s\n",
map->id, map->fd,
map->delta, rz_io_map_get_from(map), rz_io_map_get_to(map),
rz_str_rwx_i(map->perm), rz_str_get(map->name));
}
}
break;
case 'r': // "omr"
if (input[2] != ' ') {
break;
}
P = strchr(input + 3, ' ');
if (P) {
id = (ut32)rz_num_math(core->num, input + 3); //mapid
new = rz_num_math(core->num, P + 1);
rz_io_map_resize(core->io, id, new);
}
break;
case 'b': // "omb"
if (input[2] == '.') {
RzIOMap *map = rz_io_map_get(core->io, core->offset);
if (map) {
ut64 dst = rz_num_math(core->num, input + 3);
rz_io_map_remap(core->io, map->id, dst);
}
} else {
if (input[2] != ' ') {
break;
}
P = strchr(input + 3, ' ');
if (P) {
id = (ut32)rz_num_math(core->num, input + 3); //mapid
new = rz_num_math(core->num, P + 1);
rz_io_map_remap(core->io, id, new);
}
}
break;
case 'o': // "omo"
if (input[2] == ' ') {
rz_core_cmdf(core, "om %s 0x%08" PFMT64x " $s r omo", input + 2, core->offset);
} else {
rz_core_cmd0(core, "om `oq.` $B $s r");
}
rz_core_cmd0(core, "ompd `omq.`");
break;
case 'p':
switch (input[2]) {
case 'd': // "ompf"
id = rz_num_math(core->num, input + 3); //mapid
if (rz_io_map_exists_for_id(core->io, id)) {
rz_io_map_depriorize(core->io, id);
} else {
eprintf("Cannot find any map with mapid %d\n", id);
}
break;
case 'f': // "ompf"
fd = rz_num_math(core->num, input + 3);
if (!rz_io_map_priorize_for_fd(core->io, (int)fd)) {
eprintf("Cannot prioritize any map for fd %d\n", (int)fd);
}
break;
case 'b': // "ompb"
id = (ut32)rz_num_math(core->num, input + 4);
if (!rz_bin_file_set_cur_by_id(core->bin, id)) {
eprintf("Cannot prioritize bin with fd %d\n", id);
}
break;
case ' ': // "omp"
id = rz_num_math(core->num, input + 3); //mapid
if (rz_io_map_exists_for_id(core->io, id)) {
rz_io_map_priorize(core->io, id);
rz_core_block_read(core);
} else {
eprintf("Cannot find any map with mapid %d\n", id);
}
break;
}
break;
case 't': // "omt"
rz_core_cmd_omt(core, input + 2);
break;
case ' ': // "om"
s = strdup(input + 2);
if (!s) {
break;
}
if (strchr(s, ' ')) {
int fd = 0, rwx = 0;
ut64 size = 0, vaddr = 0, paddr = 0;
const char *name = NULL;
bool rwx_arg = false;
RzIODesc *desc = NULL;
int words = rz_str_word_set0(s);
switch (words) {
case 6:
name = rz_str_word_get0(s, 5);
case 5:
//TODO: this needs some love because it is not optimal.
rwx = rz_str_rwx(rz_str_word_get0(s, 4));
rwx_arg = true;
case 4:
paddr = rz_num_math(core->num, rz_str_word_get0(s, 3));
case 3:
size = rz_num_math(core->num, rz_str_word_get0(s, 2));
case 2:
vaddr = rz_num_math(core->num, rz_str_word_get0(s, 1));
case 1:
fd = rz_num_math(core->num, rz_str_word_get0(s, 0));
}
if (fd < 3) {
eprintf("wrong fd, it must be greater than 3\n");
break;
}
desc = rz_io_desc_get(core->io, fd);
if (desc) {
if (!size) {
size = rz_io_fd_size(core->io, fd);
}
map = rz_io_map_add(core->io, fd, rwx_arg ? rwx : desc->perm, paddr, vaddr, size);
rz_io_map_set_name(map, name);
}
} else {
int fd = rz_io_fd_get_current(core->io);
if (rz_io_desc_get(core->io, fd)) {
map_list(core->io, 0, core->print, fd);
} else {
eprintf("Invalid fd %d\n", (int)fd);
}
}
RZ_FREE(s);
break;
case 'n': // "omn"
if (input[2] == '.') { // "omn."
RzIOMap *map = rz_io_map_get(core->io, core->offset);
if (map) {
switch (input[3]) {
case '-':
rz_io_map_del_name(map);
break;
case 0:
rz_cons_printf("%s\n", map->name);
break;
default:
rz_io_map_set_name(map, rz_str_trim_head_ro(input + 3));
break;
}
}
} else {
bool use_id = (input[2] == 'i') ? true : false;
s = strdup(use_id ? &input[3] : &input[2]);
if (!s) {
break;
}
p = s;
while (*s == ' ') {
s++;
}
if (*s == '\0') {
s = p;
break;
}
if (!(q = strchr(s, ' '))) {
if (use_id) {
id = (ut32)rz_num_math(core->num, s);
map = rz_io_map_resolve(core->io, id);
} else {
addr = rz_num_math(core->num, s);
map = rz_io_map_get(core->io, addr);
}
rz_io_map_del_name(map);
s = p;
break;
}
*q = '\0';
q++;
if (use_id) {
id = (ut32)rz_num_math(core->num, s);
map = rz_io_map_resolve(core->io, id);
} else {
addr = rz_num_math(core->num, s);
map = rz_io_map_get(core->io, addr);
}
if (*q) {
rz_io_map_set_name(map, q);
} else {
rz_io_map_del_name(map);
}
s = p;
}
break;
case 'a': // "oma"
{
ut32 fd = input[2] ? rz_num_math(core->num, input + 2) : rz_io_fd_get_current(core->io);
RzIODesc *desc = rz_io_desc_get(core->io, fd);
if (desc) {
map = rz_io_map_add(core->io, fd, desc->perm, 0, 0, UT64_MAX);
rz_io_map_set_name(map, desc->name);
} else {
eprintf("Usage: omm [fd]\n");
}
} break;
case 'm': // "omm"
{
ut32 fd = input[2] ? rz_num_math(core->num, input + 2) : rz_io_fd_get_current(core->io);
RzIODesc *desc = rz_io_desc_get(core->io, fd);
if (desc) {
ut64 size = rz_io_desc_size(desc);
map = rz_io_map_add(core->io, fd, desc->perm, 0, 0, size);
rz_io_map_set_name(map, desc->name);
} else {
eprintf("Usage: omm [fd]\n");
}
} break;
case '-': // "om-"
if (!strcmp(input + 2, "..")) {
rz_core_cmd0(core, "om-`om~...`~[0]");
} else if (input[2] == '*') {
rz_io_map_reset(core->io);
} else {
rz_io_map_del(core->io, rz_num_math(core->num, input + 2));
}
break;
case 'f': // "omf"
switch (input[2]) {
case 'g': // "omfg"
cmd_omfg(core, input + 3);
break;
case ' ': // "omf"
cmd_omf(core, input + 3);
break;
default:
rz_core_cmd_help(core, help_msg_om);
break;
}
break;
case '\0': // "om"
case 'j': // "omj"
case '*': // "om*"
case 'q': // "omq"
if (input[1] && input[2] == '.') {
map = rz_io_map_get(core->io, core->offset);
if (map) {
core->print->cb_printf("%i\n", map->id);
}
} else {
if (input[1] && input[2] == 'q') { // "omqq"
map_list(core->io, input[1], core->print, -2);
} else {
map_list(core->io, input[1], core->print, -1);
}
}
break;
case '=': // "om="
{
RzList *list = rz_list_newf((RzListFree)rz_listinfo_free);
if (!list) {
return;
}
void **it;
rz_pvector_foreach_prev(&core->io->maps, it) {
RzIOMap *map = *it;
char temp[32];
snprintf(temp, sizeof(temp), "%d", map->fd);
RzListInfo *info = rz_listinfo_new(map->name, map->itv, map->itv, map->perm, temp);
if (!info) {
break;
}
rz_list_append(list, info);
}
RzTable *table = rz_core_table(core);
rz_table_visual_list(table, list, core->offset, core->blocksize,
rz_cons_get_size(NULL), rz_config_get_i(core->config, "scr.color"));
char *tablestr = rz_table_tostring(table);
rz_cons_printf("\n%s\n", tablestr);
rz_table_free(table);
rz_list_free(list);
free(tablestr);
} break;
default:
case '?':
rz_core_cmd_help(core, help_msg_om);
break;
}
RZ_FREE(s);
rz_core_block_read(core);
}
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 int fdsz = 0;
static bool init_desc_list_visual_cb(void *user, void *data, ut32 id) {
RzIODesc *desc = (RzIODesc *)data;
ut64 sz = rz_io_desc_size(desc);
if (sz > fdsz) {
fdsz = sz;
}
return true;
}
static bool desc_list_visual_cb(void *user, void *data, ut32 id) {
RzPrint *p = (RzPrint *)user;
RzIODesc *desc = (RzIODesc *)data;
ut64 sz = rz_io_desc_size(desc);
rz_cons_printf("%2d %c %s 0x%08" PFMT64x " ", desc->fd,
(desc->io && (desc->io->desc == desc)) ? '*' : '-', rz_str_rwx_i(desc->perm), sz);
int flags = p->flags;
p->flags &= ~RZ_PRINT_FLAGS_HEADER;
rz_print_progressbar(p, sz * 100 / fdsz, rz_cons_get_size(NULL) - 40);
p->flags = flags;
rz_cons_printf(" %s\n", desc->uri);
#if 0
RzIOMap *map;
SdbListIter *iter;
if (desc->io && desc->io->va && desc->io->maps) {
ls_foreach_prev (desc->io->maps, iter, map) {
if (map->fd == desc->fd) {
p->cb_printf(" +0x%"PFMT64x" 0x%"PFMT64x
" - 0x%"PFMT64x" : %s : %s : %s\n", map->delta,
map->from, map->to, rz_str_rwx_i(map->flags), "",
rz_str_get(map));
}
}
}
#endif
return true;
}
static bool desc_list_quiet2_cb(void *user, void *data, ut32 id) {
RzPrint *p = (RzPrint *)user;
RzIODesc *desc = (RzIODesc *)data;
p->cb_printf("%d\n", desc->fd);
return false;
}
static bool desc_list_quiet_cb(void *user, void *data, ut32 id) {
RzPrint *p = (RzPrint *)user;
RzIODesc *desc = (RzIODesc *)data;
p->cb_printf("%d\n", desc->fd);
return true;
}
static bool desc_list_cb(void *user, void *data, ut32 id) {
RzPrint *p = (RzPrint *)user;
RzIODesc *desc = (RzIODesc *)data;
p->cb_printf("%2d %c %s 0x%08" PFMT64x " %s\n", desc->fd,
(desc->io && (desc->io->desc == desc)) ? '*' : '-',
rz_str_rwx_i(desc->perm), rz_io_desc_size(desc), desc->uri);
return true;
}
static bool desc_list_json_cb(void *user, void *data, ut32 id) {
PJ *pj = (PJ *)user;
RzIODesc *desc = (RzIODesc *)data;
// TODO: from is always 0? See librz/core/file.c:945
ut64 from = 0LL;
pj_o(pj);
pj_kb(pj, "raised", desc->io && (desc->io->desc == desc));
pj_kN(pj, "fd", desc->fd);
pj_ks(pj, "uri", desc->uri);
pj_kn(pj, "from", from);
pj_kb(pj, "writable", desc->perm & RZ_PERM_W);
pj_kN(pj, "size", rz_io_desc_size(desc));
pj_end(pj);
return true;
}
static bool cmd_op(RzCore *core, char mode, int fd) {
int cur_fd = rz_io_fd_get_current(core->io);
int next_fd = cur_fd;
switch (mode) {
case 0:
next_fd = fd;
break;
case 'n':
next_fd = rz_io_fd_get_next(core->io, cur_fd);
break;
case 'p':
next_fd = rz_io_fd_get_prev(core->io, cur_fd);
break;
case 'r':
next_fd = rz_io_fd_get_next(core->io, cur_fd);
if (next_fd == -1) {
next_fd = rz_io_fd_get_lowest(core->io);
}
break;
}
if (next_fd >= 0 && next_fd != cur_fd && rz_io_use_fd(core->io, next_fd)) {
RzBinFile *bf = rz_bin_file_find_by_fd(core->bin, next_fd);
if (bf && rz_core_bin_raise(core, bf->id)) {
rz_core_block_read(core);
return true;
}
eprintf("Invalid RzBinFile.id number.\n");
}
return false;
}
RZ_IPI int rz_cmd_open(void *data, const char *input) {
RzCore *core = (RzCore *)data;
int perms = RZ_PERM_R;
ut64 baddr = rz_config_get_i(core->config, "bin.baddr");
ut64 addr = 0LL;
int argc, fd = -1;
RzCoreFile *file;
RzIODesc *desc;
bool write = false;
const char *ptr = NULL;
char **argv = NULL;
switch (*input) {
case 'a':
switch (input[1]) {
case '*': // "oa*"
{
RzListIter *iter;
RzBinFile *bf = NULL;
rz_list_foreach (core->bin->binfiles, iter, bf) {
if (bf && bf->o && bf->o->info) {
eprintf("oa %s %d %s\n", bf->o->info->arch, bf->o->info->bits, bf->file);
}
}
return 1;
}
case '?': // "oa?"
case ' ': // "oa "
{
int i;
char *ptr = strdup(input + 2);
const char *arch = NULL;
ut16 bits = 0;
const char *filename = NULL;
i = rz_str_word_set0(ptr);
if (i < 2) {
eprintf("Missing argument\n");
free(ptr);
return 0;
}
if (i == 3) {
filename = rz_str_word_get0(ptr, 2);
}
bits = rz_num_math(core->num, rz_str_word_get0(ptr, 1));
arch = rz_str_word_get0(ptr, 0);
rz_core_bin_set_arch_bits(core, filename, arch, bits);
RzBinFile *file = rz_bin_file_find_by_name(core->bin, filename);
if (!file) {
eprintf("Cannot find file %s\n", filename);
free(ptr);
return 0;
}
if (file->o && file->o->info) {
file->o->info->arch = strdup(arch);
file->o->info->bits = bits;
rz_core_bin_apply_all_info(core, file);
}
free(ptr);
return 1;
} break;
default:
eprintf("Usage: oa[-][arch] [bits] [filename]\n");
return 0;
}
case 'n': // "on"
if (input[1] == '*') {
rz_core_file_list(core, 'n');
return 0;
}
if (input[1] == '+') { // "on+"
write = true;
perms |= RZ_PERM_W;
if (input[2] != ' ') {
eprintf("Usage: on+ file [addr] [rwx]\n");
return 0;
}
ptr = input + 3;
} else if (input[1] == ' ') {
ptr = input + 2;
} else {
eprintf("Usage: on file [addr] [rwx]\n");
return 0;
}
argv = rz_str_argv(ptr, &argc);
if (!argc) {
eprintf("Usage: on%s file [addr] [rwx]\n", write ? "+" : "");
rz_str_argv_free(argv);
return 0;
}
ptr = argv[0];
if (argc == 2) {
if (rz_num_is_valid_input(core->num, argv[1])) {
addr = rz_num_math(core->num, argv[1]);
} else {
perms = rz_str_rwx(argv[1]);
}
}
if (argc == 3) {
addr = rz_num_math(core->num, argv[1]);
perms = rz_str_rwx(argv[2]);
}
if (!strcmp(ptr, "-")) {
ptr = "malloc://512";
}
if ((desc = rz_io_open_at(core->io, ptr, perms, 0644, addr))) {
fd = desc->fd;
}
if (fd == -1) {
eprintf("Cannot open file '%s'\n", ptr);
}
rz_str_argv_free(argv);
core->num->value = fd;
rz_core_block_read(core);
return 0;
#if 1
// XXX projects use the of command, but i think we should deprecate it... keeping it for now
case 'f': // "of"
ptr = rz_str_trim_head_ro(input + 2);
argv = rz_str_argv(ptr, &argc);
if (argc == 0) {
eprintf("Usage: of [filename] (rwx)\n");
rz_str_argv_free(argv);
return 0;
} else if (argc == 2) {
perms = rz_str_rwx(argv[1]);
}
fd = rz_io_fd_open(core->io, argv[0], perms, 0);
core->num->value = fd;
rz_str_argv_free(argv);
return 0;
#else
{
if ((input[1] == 's') && (input[2] == ' ')) {
silence = true;
input++;
}
addr = 0; // honor bin.baddr ?
const char *argv0 = rz_str_trim_head_ro(input + 2);
if ((file = rz_core_file_open(core, argv0, perms, addr))) {
fd = file->fd;
if (!silence) {
eprintf("%d\n", fd);
}
rz_core_bin_load(core, argv0, baddr);
} else {
eprintf("cannot open file %s\n", argv0);
}
rz_str_argv_free(argv);
}
rz_core_block_read(core);
return 0;
break;
#endif
case 'p': // "op"
/* handle prioritize */
if (input[1]) {
switch (input[1]) {
case 'r': // "opr" - open next file + rotate if not found
case 'n': // "opn" - open next file
case 'p': // "opp" - open previous file
if (!cmd_op(core, input[1], -1)) {
eprintf("Cannot find file\n");
}
break;
case ' ': {
int fd = rz_num_math(core->num, input + 1);
if (fd >= 0 || input[1] == '0') {
cmd_op(core, 0, fd);
} else {
eprintf("Invalid fd number\n");
}
} break;
default:
rz_core_cmd_help(core, help_msg_op);
break;
}
} else {
if (core->io && core->io->desc) {
rz_cons_printf("%d\n", core->io->desc->fd);
}
}
return 0;
break;
case '+': // "o+"
perms |= RZ_PERM_W;
/* fallthrough */
case ' ': // "o" "o "
ptr = input + 1;
argv = rz_str_argv(ptr, &argc);
if (argc == 0) {
eprintf("Usage: o (uri://)[/path/to/file] (addr)\n");
rz_str_argv_free(argv);
return 0;
}
if (argv) {
// Unescape spaces from the path
rz_str_path_unescape(argv[0]);
if (argc == 2) {
if (rz_num_is_valid_input(core->num, argv[1])) {
addr = rz_num_math(core->num, argv[1]);
} else {
perms = rz_str_rwx(argv[1]);
}
}
if (argc == 3) {
addr = rz_num_math(core->num, argv[1]);
perms = rz_str_rwx(argv[2]);
}
}
{
const char *argv0 = argv ? argv[0] : ptr;
if ((file = rz_core_file_open(core, argv0, perms, addr))) {
fd = file->fd;
core->num->value = fd;
if (addr == 0) { // if no baddr defined, use the one provided by the file
addr = UT64_MAX;
}
rz_core_bin_load(core, argv0, addr);
if (*input == '+') { // "o+"
RzIODesc *desc = rz_io_desc_get(core->io, fd);
if (desc && (desc->perm & RZ_PERM_W)) {
void **it;
rz_pvector_foreach_prev(&core->io->maps, it) {
RzIOMap *map = *it;
if (map->fd == fd) {
map->perm |= RZ_PERM_WX;
}
}
} else {
eprintf("Error: %s is not writable\n", argv0);
}
}
} else {
eprintf("cannot open file %s\n", argv0);
}
rz_str_argv_free(argv);
}
rz_core_block_read(core);
return 0;
}
switch (*input) {
case '=': // "o="
fdsz = 0;
rz_id_storage_foreach(core->io->files, init_desc_list_visual_cb, core->print);
rz_id_storage_foreach(core->io->files, desc_list_visual_cb, core->print);
break;
case 'q': // "oq"
if (input[1] == '.') {
rz_id_storage_foreach(core->io->files, desc_list_quiet2_cb, core->print);
} else {
rz_id_storage_foreach(core->io->files, desc_list_quiet_cb, core->print);
}
break;
case '\0': // "o"
rz_id_storage_foreach(core->io->files, desc_list_cb, core->print);
break;
case '*': // "o*"
if ('?' == input[1]) {
rz_core_cmd_help(core, help_msg_o_star);
break;
}
rz_core_file_list(core, (int)(*input));
break;
case 'j': // "oj"
if ('?' == input[1]) {
rz_core_cmd_help(core, help_msg_oj);
break;
}
PJ *pj = pj_new();
pj_a(pj);
rz_id_storage_foreach(core->io->files, desc_list_json_cb, pj);
pj_end(pj);
core->print->cb_printf("%s\n", pj_string(pj));
pj_free(pj);
break;
case 'L': // "oL"
if (input[1] == ' ') {
if (rz_lib_open(core->lib, input + 2) == -1) {
eprintf("Oops\n");
}
} else {
if ('j' == input[1]) {
rz_io_plugin_list_json(core->io);
} else {
rz_io_plugin_list(core->io);
}
}
break;
case 'i': // "oi"
switch (input[1]) {
case ' ': // "oi "
{
RzListIter *iter = NULL;
RzCoreFile *f;
int nth = rz_num_math(core->num, input + 2);
int count = 0;
rz_list_foreach (core->files, iter, f) {
if (count == nth) {
rz_io_use_fd(core->io, f->fd);
break;
}
count++;
}
} break;
case '-': // "oi-"
{
RzListIter *iter = NULL;
RzCoreFile *f;
int nth = rz_num_math(core->num, input + 2);
int count = 0;
rz_list_foreach (core->files, iter, f) {
if (count == nth) {
rz_core_file_close_fd(core, f->fd);
break;
}
count++;
}
} break;
case 'j': // "oij"
case '*': // "oi*"
case 0: // "oi"
rz_core_file_list(core, input[1]);
break;
}
break;
case 'u': { // "ou"
RzListIter *iter = NULL;
RzCoreFile *f;
core->switch_file_view = 0;
int num = atoi(input + 2);
rz_list_foreach (core->files, iter, f) {
if (f->fd == num) {
core->file = f;
}
}
rz_io_use_fd(core->io, num);
RzBinFile *bf = rz_bin_file_find_by_fd(core->bin, num);
if (bf) {
rz_core_bin_raise(core, bf->id);
rz_core_block_read(core);
}
break;
}
case 'b': // "ob"
cmd_open_bin(core, input);
break;
case '-': // "o-"
switch (input[1]) {
case '!': // "o-!"
rz_core_file_close_all_but(core);
break;
case '*': // "o-*"
rz_core_file_close_fd(core, -1);
rz_io_close_all(core->io);
rz_bin_file_delete_all(core->bin);
if (core->files) {
rz_list_purge(core->files);
}
break;
case '-': // "o--"
eprintf("All core files, io, analysis and flags info purged.\n");
rz_core_file_close_fd(core, -1);
rz_io_close_all(core->io);
rz_bin_file_delete_all(core->bin);
// TODO: Move to a-- ?
rz_analysis_purge(core->analysis);
// TODO: Move to f-- ?
rz_flag_unset_all(core->flags);
// TODO: rbin?
break;
default: {
int fd = (int)rz_num_math(core->num, input + 1);
if (!rz_core_file_close_fd(core, fd)) {
eprintf("Unable to find file descriptor %d\n", fd);
}
} break;
case 0:
case '?':
rz_core_cmd_help(core, help_msg_o_);
}
break;
case '.': // "o."
if (input[1] == 'q') { // "o.q" // same as oq
RzIOMap *map = rz_io_map_get(core->io, core->offset);
if (map) {
rz_cons_printf("%d\n", map->fd);
}
} else {
RzIOMap *map = rz_io_map_get(core->io, core->offset);
if (map) {
RzIODesc *desc = rz_io_desc_get(core->io, map->fd);
if (desc) {
rz_cons_printf("%s\n", desc->uri);
}
}
}
break;
case 'C': // "oC"
{
int len = rz_num_math(core->num, input + 1);
if (len < 1) {
len = core->blocksize;
}
char *uri = rz_str_newf("malloc://%d", len);
ut8 *data = calloc(len, 1);
rz_io_read_at(core->io, core->offset, data, len);
if ((file = rz_core_file_open(core, uri, RZ_PERM_RWX, 0))) {
fd = file->fd;
core->num->value = fd;
rz_core_bin_load(core, uri, 0);
RzIODesc *desc = rz_io_desc_get(core->io, fd);
if (desc) {
// TODO: why rz_io_desc_write() fails?
rz_io_desc_write_at(desc, 0, data, len);
}
} else {
eprintf("Cannot %s\n", uri);
}
free(uri);
free(data);
} break;
case 'm': // "om"
cmd_open_map(core, input);
break;
case 'o': // "oo"
switch (input[1]) {
case 'm': // "oom"
rz_core_file_reopen_in_malloc(core);
break;
case 'd': // "ood" : reopen in debugger
if (input[2] == 'r') { // "oodr"
rz_core_cmdf(core, "dor %s", input + 3);
rz_core_file_reopen_debug(core, "");
} else if (input[2] == 'f') { // "oodf"
char **argv = NULL;
int addr = 0;
argv = rz_str_argv(input + 3, &argc);
if (argc == 0) {
eprintf("Usage: oodf (uri://)[/path/to/file] (addr)\n");
rz_str_argv_free(argv);
return 0;
}
if (argc == 2) {
if (rz_num_is_valid_input(core->num, argv[1])) {
addr = rz_num_math(core->num, argv[1]);
}
}
rz_core_file_reopen_remote_debug(core, argv[0], addr);
rz_str_argv_free(argv);
} else if ('?' == input[2]) {
rz_core_cmd_help(core, help_msg_ood);
} else {
rz_core_file_reopen_debug(core, input + 2);
}
break;
case 'c': // "oob" : reopen with bin info
rz_core_cmd0(core, "oc `o.`");
break;
case 'b': // "oob" : reopen with bin info
if ('?' == input[2]) {
rz_core_cmd_help(core, help_msg_oob);
} else {
rz_core_file_reopen(core, input + 2, 0, 2);
}
break;
case 'n': // "oon"
switch (input[2]) {
case 0: // "oon"
rz_core_file_reopen(core, NULL, 0, 0);
break;
case '+': // "oon+"
rz_core_file_reopen(core, NULL, RZ_PERM_RW, 0);
break;
case 'n': // "oonn"
if ('?' == input[3] || !core->file) {
rz_core_cmd_help(core, help_msg_oonn);
break;
}
RzIODesc *desc = rz_io_desc_get(core->io, core->file->fd);
if (desc) {
perms = core->io->desc->perm;
if (input[3] == '+') {
perms |= RZ_PERM_RW;
}
char *fname = strdup(desc->name);
if (fname) {
rz_core_bin_load_structs(core, fname);
rz_core_file_reopen(core, fname, perms, 0);
free(fname);
}
break;
}
break;
case '?':
default:
rz_core_cmd_help(core, help_msg_oon);
break;
}
break;
case '+': // "oo+"
if ('?' == input[2]) {
rz_core_cmd_help(core, help_msg_oo_plus);
} else if (core && core->io && core->io->desc) {
int fd;
int perms = RZ_PERM_RW;
if ((ptr = strrchr(input, ' ')) && ptr[1]) {
fd = (int)rz_num_math(core->num, ptr + 1);
} else {
fd = core->io->desc->fd;
perms |= core->io->desc->perm;
}
rz_core_io_file_reopen(core, fd, perms);
}
break;
case '\0': // "oo"
if (core && core->io && core->io->desc) {
int fd;
if ((ptr = strrchr(input, ' ')) && ptr[1]) {
fd = (int)rz_num_math(core->num, ptr + 1);
} else {
fd = core->io->desc->fd;
}
rz_core_io_file_open(core, fd);
}
break;
case '?':
default:
rz_core_cmd_help(core, help_msg_oo);
break;
}
break;
case 'c': // "oc"
if (input[1] == '?') {
eprintf("Usage: oc [file]\n");
} else if (input[1] && input[2]) {
if (core->tasks.current_task != core->tasks.main_task) {
eprintf("This command can only be executed on the main task!\n");
return 0;
}
// memleak? loses all settings
// if load fails does not fallbacks to previous file
rz_core_task_sync_end(&core->tasks);
rz_core_fini(core);
rz_core_init(core);
rz_core_task_sync_begin(&core->tasks);
if (!rz_core_file_open(core, input + 2, RZ_PERM_R, 0)) {
eprintf("Cannot open file\n");
}
(void)rz_core_bin_load(core, NULL, baddr);
} else {
eprintf("Missing argument\n");
}
break;
case 'x': // "ox"
if (input[1] && input[1] != '?') {
int fd, fdx;
fd = fdx = -1;
char *ptr, *inp = strdup(input);
if ((ptr = strrchr(inp, ' '))) {
fdx = (int)rz_num_math(core->num, ptr + 1);
*ptr = '\0';
if ((ptr = strchr(inp, ' '))) {
fd = rz_num_math(core->num, ptr + 1);
}
}
free(inp);
if ((fdx == -1) || (fd == -1) || (fdx == fd)) {
break;
}
rz_io_desc_exchange(core->io, fd, fdx);
rz_core_block_read(core);
} else {
eprintf("Usage: ox [fd] [fdx] - exchange two file descriptors\n");
}
break;
case '?': // "o?"
default:
rz_core_cmd_help(core, help_msg_o);
break;
}
return 0;
}