949 lines
26 KiB
C
949 lines
26 KiB
C
// SPDX-FileCopyrightText: 2009-2021 pancake <pancake@nopcode.org>
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
|
|
#include <stddef.h>
|
|
#include <rz_cons.h>
|
|
#include <rz_core.h>
|
|
#include "../core_private.h"
|
|
|
|
static bool listFlag(RzFlagItem *flag, void *user) {
|
|
rz_list_append(user, flag);
|
|
return true;
|
|
}
|
|
|
|
static size_t countMatching(const char *a, const char *b) {
|
|
size_t matches = 0;
|
|
for (; *a && *b; a++, b++) {
|
|
if (*a != *b) {
|
|
break;
|
|
}
|
|
matches++;
|
|
}
|
|
return matches;
|
|
}
|
|
|
|
static const char *__isOnlySon(RzCore *core, RzList /*<RzFlagItem *>*/ *flags, const char *kw) {
|
|
RzListIter *iter;
|
|
RzFlagItem *f;
|
|
|
|
size_t count = 0;
|
|
char *fname = NULL;
|
|
rz_list_foreach (flags, iter, f) {
|
|
if (!strncmp(f->name, kw, strlen(kw))) {
|
|
count++;
|
|
if (count > 1) {
|
|
return NULL;
|
|
}
|
|
fname = f->name;
|
|
}
|
|
}
|
|
return fname;
|
|
}
|
|
|
|
static RzList /*<char *>*/ *__childrenFlagsOf(RzCore *core, RzList /*<RzFlagItem *>*/ *flags, const char *prefix) {
|
|
RzList *list = rz_list_newf(free);
|
|
RzListIter *iter, *iter2;
|
|
RzFlagItem *f, *f2;
|
|
char *fn;
|
|
|
|
const size_t prefix_len = strlen(prefix);
|
|
rz_list_foreach (flags, iter, f) {
|
|
if (prefix_len > 0 && strncmp(f->name, prefix, prefix_len)) {
|
|
continue;
|
|
}
|
|
if (prefix_len > strlen(f->name)) {
|
|
continue;
|
|
}
|
|
if (rz_cons_is_breaked()) {
|
|
break;
|
|
}
|
|
const char *name = f->name;
|
|
int name_len = strlen(name);
|
|
rz_list_foreach (flags, iter2, f2) {
|
|
if (prefix_len > strlen(f2->name)) {
|
|
continue;
|
|
}
|
|
if (prefix_len > 0 && strncmp(f2->name, prefix, prefix_len)) {
|
|
continue;
|
|
}
|
|
int matching = countMatching(name, f2->name);
|
|
if (matching < prefix_len || matching == name_len) {
|
|
continue;
|
|
}
|
|
if (matching > name_len) {
|
|
break;
|
|
}
|
|
if (matching < name_len) {
|
|
name_len = matching;
|
|
}
|
|
}
|
|
char *kw = rz_str_ndup(name, name_len + 1);
|
|
const int kw_len = strlen(kw);
|
|
const char *only = __isOnlySon(core, flags, kw);
|
|
if (only) {
|
|
free(kw);
|
|
kw = strdup(only);
|
|
} else {
|
|
const char *fname = NULL;
|
|
size_t fname_len = 0;
|
|
rz_list_foreach (flags, iter2, f2) {
|
|
if (strncmp(f2->name, kw, kw_len)) {
|
|
continue;
|
|
}
|
|
if (fname) {
|
|
int matching = countMatching(fname, f2->name);
|
|
if (fname_len) {
|
|
if (matching < fname_len) {
|
|
fname_len = matching;
|
|
}
|
|
} else {
|
|
fname_len = matching;
|
|
}
|
|
} else {
|
|
fname = f2->name;
|
|
}
|
|
}
|
|
if (fname_len > 0) {
|
|
free(kw);
|
|
kw = rz_str_ndup(fname, fname_len);
|
|
}
|
|
}
|
|
|
|
bool found = false;
|
|
rz_list_foreach (list, iter2, fn) {
|
|
if (!strcmp(fn, kw)) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (found) {
|
|
free(kw);
|
|
} else {
|
|
if (strcmp(prefix, kw)) {
|
|
rz_list_append(list, kw);
|
|
} else {
|
|
free(kw);
|
|
}
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
static void __printRecursive(RzCore *core, RzList /*<RzFlagItem *>*/ *flags, const char *name, RzOutputMode mode, int depth) {
|
|
char *fn;
|
|
RzListIter *iter;
|
|
if (mode == RZ_OUTPUT_MODE_RIZIN && RZ_STR_ISEMPTY(name)) {
|
|
rz_cons_printf("agn root\n");
|
|
}
|
|
if (rz_flag_get(core->flags, name)) {
|
|
return;
|
|
}
|
|
RzList *children = __childrenFlagsOf(core, flags, name);
|
|
const int name_len = strlen(name);
|
|
rz_list_foreach (children, iter, fn) {
|
|
if (!strcmp(fn, name)) {
|
|
continue;
|
|
}
|
|
if (mode == RZ_OUTPUT_MODE_RIZIN) {
|
|
rz_cons_printf("agn %s %s\n", fn, fn + name_len);
|
|
rz_cons_printf("age %s %s\n", RZ_STR_ISNOTEMPTY(name) ? name : "root", fn);
|
|
} else {
|
|
char *pad = rz_str_pad(' ', name_len);
|
|
rz_cons_printf("%s %s\n", pad, fn + name_len);
|
|
free(pad);
|
|
}
|
|
// rz_cons_printf (".fg %s\n", fn);
|
|
__printRecursive(core, flags, fn, mode, depth + 1);
|
|
}
|
|
rz_list_free(children);
|
|
}
|
|
|
|
typedef struct {
|
|
RzAnalysisFunction *fcn;
|
|
RzCmdStateOutput *state;
|
|
} PrintFcnLabelsCtx;
|
|
|
|
static bool print_function_labels_cb(void *user, const ut64 addr, const void *v) {
|
|
const PrintFcnLabelsCtx *ctx = user;
|
|
const char *name = v;
|
|
switch (ctx->state->mode) {
|
|
case RZ_OUTPUT_MODE_JSON:
|
|
pj_o(ctx->state->d.pj);
|
|
pj_kn(ctx->state->d.pj, name, addr);
|
|
pj_end(ctx->state->d.pj);
|
|
break;
|
|
case RZ_OUTPUT_MODE_QUIET:
|
|
rz_cons_printf("%s\n", name);
|
|
break;
|
|
case RZ_OUTPUT_MODE_STANDARD:
|
|
rz_cons_printf("0x%08" PFMT64x " %s [%s + %" PFMT64d "]\n",
|
|
addr,
|
|
name, ctx->fcn->name,
|
|
addr - ctx->fcn->addr);
|
|
break;
|
|
default:
|
|
rz_warn_if_reached();
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool flag_set_comment(RzFlagItem *item, const char *comment) {
|
|
if (!strncmp(comment, "base64:", 7)) {
|
|
const char *b64str = comment + 7;
|
|
char *dec = (char *)rz_base64_decode_dyn(b64str, -1);
|
|
if (!dec) {
|
|
RZ_LOG_ERROR("Failed to decode base64-encoded string: \"%s\"\n", b64str);
|
|
return false;
|
|
}
|
|
rz_flag_item_set_comment(item, dec);
|
|
free(dec);
|
|
} else {
|
|
rz_flag_item_set_comment(item, comment);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_add_handler(RzCore *core, int argc, const char **argv) {
|
|
RzFlagItem *item;
|
|
bool addFlag = true;
|
|
ut64 size = argc > 2 ? rz_num_math(core->num, argv[2]) : 1;
|
|
if ((item = rz_flag_get_at(core->flags, core->offset, false))) {
|
|
RZ_LOG_ERROR("Cannot create flag \"%s\" at 0x%" PFMT64x
|
|
" because there is already \"%s\" flag\n",
|
|
argv[1],
|
|
core->offset, item->name);
|
|
addFlag = false;
|
|
}
|
|
if (addFlag) {
|
|
item = rz_flag_set(core->flags, argv[1], core->offset, size);
|
|
}
|
|
if (!item) {
|
|
RZ_LOG_ERROR("Cannot create flag \"%s\" at 0x%" PFMT64x "\n", argv[1], core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
if (argc > 3) {
|
|
return bool2status(flag_set_comment(item, argv[3]));
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_append_handler(RzCore *core, int argc, const char **argv) {
|
|
ut64 size = argc > 2 ? rz_num_math(core->num, argv[2]) : 1;
|
|
RzFlagItem *item = rz_flag_set(core->flags, argv[1], core->offset, size);
|
|
if (!item) {
|
|
RZ_LOG_ERROR("Cannot create flag \"%s\" at 0x%" PFMT64x "\n", argv[1], core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
if (argc > 3) {
|
|
return bool2status(flag_set_comment(item, argv[3]));
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_local_add_handler(RzCore *core, int argc, const char **argv) {
|
|
RzAnalysisFunction *fcn = rz_analysis_get_fcn_in(core->analysis, core->offset, 0);
|
|
if (!fcn) {
|
|
RZ_LOG_ERROR("Cannot find function at 0x%" PFMT64x " offset\n", core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_analysis_function_set_label(fcn, argv[1], core->offset);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_local_remove_handler(RzCore *core, int argc, const char **argv) {
|
|
RzAnalysisFunction *fcn = rz_analysis_get_fcn_in(core->analysis, core->offset, 0);
|
|
if (!fcn) {
|
|
RZ_LOG_ERROR("Cannot find function at 0x%" PFMT64x " offset\n", core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_analysis_function_delete_label(fcn, argv[1]);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_local_list_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
RzAnalysisFunction *fcn = rz_analysis_get_fcn_in(core->analysis, core->offset, 0);
|
|
if (!fcn) {
|
|
RZ_LOG_ERROR("Cannot find function at 0x%" PFMT64x " offset\n", core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_cmd_state_output_array_start(state);
|
|
PrintFcnLabelsCtx ctx = { fcn, state };
|
|
ht_up_foreach(fcn->labels, print_function_labels_cb, &ctx);
|
|
rz_cmd_state_output_array_end(state);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_local_list_all_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
RzAnalysisFunction *fcn;
|
|
RzListIter *it;
|
|
rz_cmd_state_output_array_start(state);
|
|
rz_list_foreach (core->analysis->fcns, it, fcn) {
|
|
if (!fcn->labels->count) {
|
|
continue;
|
|
}
|
|
if (state->mode == RZ_OUTPUT_MODE_JSON) {
|
|
pj_k(state->d.pj, fcn->name);
|
|
}
|
|
PrintFcnLabelsCtx ctx = { fcn, state };
|
|
ht_up_foreach(fcn->labels, print_function_labels_cb, &ctx);
|
|
if (state->mode == RZ_OUTPUT_MODE_JSON) {
|
|
pj_end(state->d.pj);
|
|
}
|
|
}
|
|
rz_cmd_state_output_array_end(state);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_graph_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
RzList *flags = rz_list_newf(NULL);
|
|
rz_flag_foreach_space(core->flags, rz_flag_space_cur(core->flags), listFlag, flags);
|
|
if (!argv[1]) {
|
|
__printRecursive(core, flags, "", state->mode, 0);
|
|
} else {
|
|
__printRecursive(core, flags, argv[1], state->mode, 0);
|
|
}
|
|
rz_list_free(flags);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_relocate_handler(RzCore *core, int argc, const char **argv) {
|
|
ut64 mask = 0xffff;
|
|
if (argc > 3) {
|
|
mask = rz_num_math(core->num, argv[3]);
|
|
}
|
|
ut64 from = rz_num_math(core->num, argv[1]);
|
|
ut64 to = rz_num_math(core->num, argv[2]);
|
|
int ret = rz_flag_relocate(core->flags, from, mask, to);
|
|
RZ_LOG_INFO("Relocated %d flags\n", ret);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
static int cmpflag(const void *_a, const void *_b, void *user) {
|
|
const RzFlagItem *flag1 = _a, *flag2 = _b;
|
|
return (flag1->offset - flag2->offset);
|
|
}
|
|
|
|
RZ_IPI void rz_core_flag_describe(RzCore *core, ut64 addr, bool strict_offset, RzCmdStateOutput *state) {
|
|
RzFlagItem *f = rz_flag_get_at(core->flags, addr, !strict_offset);
|
|
if (!f) {
|
|
return;
|
|
}
|
|
PJ *pj = state->d.pj;
|
|
rz_cmd_state_output_set_columnsf(state, "ssXXds", "name", "realname",
|
|
"vaddr", "paddr", "size", "comment");
|
|
switch (state->mode) {
|
|
case RZ_OUTPUT_MODE_JSON:
|
|
pj_o(pj);
|
|
pj_kn(pj, "offset", f->offset);
|
|
pj_ks(pj, "name", f->name);
|
|
// Print flag's real name if defined
|
|
if (f->realname) {
|
|
pj_ks(pj, "realname", f->realname);
|
|
}
|
|
pj_end(pj);
|
|
break;
|
|
case RZ_OUTPUT_MODE_TABLE: {
|
|
// Print realname if exists and asm.flags.real is enabled
|
|
const char *name = core->flags->realnames && f->realname ? f->realname : f->name;
|
|
ut64 paddr = rz_io_v2p(core->io, addr);
|
|
if (f->offset != addr) {
|
|
char *descr_name = rz_str_newf("%s + %d", name, (int)(addr - f->offset));
|
|
rz_table_add_rowf(state->d.t, "ssXXds", f->name, descr_name,
|
|
addr, paddr, f->size, f->comment);
|
|
free(descr_name);
|
|
} else {
|
|
rz_table_add_rowf(state->d.t, "ssXXds", f->name, name, addr,
|
|
paddr, f->size, f->comment);
|
|
}
|
|
break;
|
|
}
|
|
case RZ_OUTPUT_MODE_STANDARD: {
|
|
// Print realname if exists and asm.flags.real is enabled
|
|
const char *name = core->flags->realnames && f->realname ? f->realname : f->name;
|
|
if (f->offset != addr) {
|
|
rz_cons_printf("%s + %d\n", name, (int)(addr - f->offset));
|
|
} else {
|
|
rz_cons_println(name);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
rz_warn_if_reached();
|
|
break;
|
|
}
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_describe_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
rz_core_flag_describe(core, core->offset, false, state);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_describe_at_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
const RzList *flags = rz_flag_get_list(core->flags, core->offset);
|
|
if (!flags) {
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
PJ *pj = state->d.pj;
|
|
rz_cmd_state_output_array_start(state);
|
|
rz_cmd_state_output_set_columnsf(state, "ssXXds", "name", "realname",
|
|
"vaddr", "paddr", "size", "comment");
|
|
RzFlagItem *flag;
|
|
RzListIter *iter;
|
|
// Sometimes an address has multiple flags assigned to, show them all
|
|
rz_list_foreach (flags, iter, flag) {
|
|
if (!flag) {
|
|
continue;
|
|
}
|
|
switch (state->mode) {
|
|
case RZ_OUTPUT_MODE_JSON:
|
|
pj_o(pj);
|
|
pj_ks(pj, "name", flag->name);
|
|
if (flag->realname) {
|
|
pj_ks(pj, "realname", flag->realname);
|
|
}
|
|
pj_end(pj);
|
|
break;
|
|
case RZ_OUTPUT_MODE_TABLE: {
|
|
// Print realname if exists and asm.flags.real is enabled
|
|
const char *name = core->flags->realnames && flag->realname ? flag->realname : flag->name;
|
|
ut64 paddr = rz_io_v2p(core->io, flag->offset);
|
|
rz_table_add_rowf(state->d.t, "ssXXds", flag->name, name,
|
|
flag->offset, paddr, flag->size, flag->comment);
|
|
break;
|
|
}
|
|
case RZ_OUTPUT_MODE_STANDARD: {
|
|
// Print realname if exists and asm.flags.real is enabled
|
|
if (core->flags->realnames && flag->realname) {
|
|
rz_cons_println(flag->realname);
|
|
} else {
|
|
rz_cons_println(flag->name);
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
rz_warn_if_reached();
|
|
break;
|
|
}
|
|
}
|
|
rz_cmd_state_output_array_end(state);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_describe_closest_handler(RzCore *core, int argc, const char **argv) {
|
|
RzList *temp = rz_flag_all_list(core->flags, true);
|
|
if (!temp) {
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
ut64 loff = 0;
|
|
ut64 uoff = 0;
|
|
ut64 curseek = core->offset;
|
|
char *lmatch = NULL, *umatch = NULL;
|
|
RzFlagItem *flag;
|
|
RzListIter *iter;
|
|
rz_list_sort(temp, &cmpflag, NULL);
|
|
rz_list_foreach (temp, iter, flag) {
|
|
if (strstr(flag->name, argv[1]) != NULL) {
|
|
if (flag->offset < core->offset) {
|
|
loff = flag->offset;
|
|
lmatch = flag->name;
|
|
continue;
|
|
}
|
|
uoff = flag->offset;
|
|
umatch = flag->name;
|
|
break;
|
|
}
|
|
}
|
|
char *match = (curseek - loff) < (uoff - curseek) ? lmatch : umatch;
|
|
if (match) {
|
|
if (*match) {
|
|
rz_cons_println(match);
|
|
}
|
|
}
|
|
rz_list_free(temp);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
static void flag_zone_list(RzFlag *f, RzCmdStateOutput *state) {
|
|
if (!f->zones) {
|
|
return;
|
|
}
|
|
RzListIter *iter;
|
|
RzFlagZoneItem *zi;
|
|
PJ *pj = state->d.pj;
|
|
rz_cmd_state_output_array_start(state);
|
|
rz_list_foreach (f->zones, iter, zi) {
|
|
switch (state->mode) {
|
|
case RZ_OUTPUT_MODE_JSON:
|
|
pj_o(pj);
|
|
pj_ks(pj, "name", zi->name);
|
|
pj_ki(pj, "from", zi->from);
|
|
pj_ki(pj, "to", zi->to);
|
|
pj_end(pj);
|
|
break;
|
|
case RZ_OUTPUT_MODE_STANDARD:
|
|
rz_cons_printf("0x08%" PFMT64x " 0x%08" PFMT64x " %s\n",
|
|
zi->from, zi->to, zi->name);
|
|
break;
|
|
default:
|
|
rz_warn_if_reached();
|
|
break;
|
|
}
|
|
}
|
|
rz_cmd_state_output_array_end(state);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_zone_add_handler(RzCore *core, int argc, const char **argv) {
|
|
rz_flag_zone_add(core->flags, argv[1], core->offset);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_zone_remove_handler(RzCore *core, int argc, const char **argv) {
|
|
rz_flag_zone_del(core->flags, argv[1]);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_zone_remove_all_handler(RzCore *core, int argc, const char **argv) {
|
|
rz_flag_zone_reset(core->flags);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_zone_around_handler(RzCore *core, int argc, const char **argv) {
|
|
const char *a = NULL, *b = NULL;
|
|
rz_flag_zone_around(core->flags, core->offset, &a, &b);
|
|
rz_cons_printf("%s %s\n", a ? a : "~", b ? b : "~");
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_zone_list_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
flag_zone_list(core->flags, state);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
struct flagbar_t {
|
|
RzCore *core;
|
|
int cols;
|
|
};
|
|
|
|
static bool flagbar_foreach(RzFlagItem *fi, void *user) {
|
|
struct flagbar_t *u = (struct flagbar_t *)user;
|
|
ut64 min = 0, max = rz_io_size(u->core->io);
|
|
RzIOMap *m = rz_io_map_get(u->core->io, fi->offset);
|
|
if (m) {
|
|
min = m->itv.addr;
|
|
max = m->itv.addr + m->itv.size;
|
|
}
|
|
rz_cons_printf("0x%08" PFMT64x " ", fi->offset);
|
|
RzBarOptions opts = {
|
|
.unicode = false,
|
|
.thinline = false,
|
|
.legend = true,
|
|
.offset = false,
|
|
.offpos = 0,
|
|
.cursor = false,
|
|
.curpos = 0,
|
|
.color = false
|
|
};
|
|
RzStrBuf *strbuf = rz_rangebar(&opts, fi->offset, fi->offset + fi->size, min, max, u->cols);
|
|
if (!strbuf) {
|
|
RZ_LOG_ERROR("Cannot generate rangebar\n");
|
|
} else {
|
|
rz_cons_print(rz_strbuf_drain(strbuf));
|
|
}
|
|
rz_cons_printf(" %s\n", fi->name);
|
|
return true;
|
|
}
|
|
|
|
static void flagbars(RzCore *core, const char *glob) {
|
|
int cols = rz_cons_get_size(NULL);
|
|
cols -= 80;
|
|
if (cols < 0) {
|
|
cols += 80;
|
|
}
|
|
|
|
struct flagbar_t u = { .core = core, .cols = cols };
|
|
rz_flag_foreach_space_glob(core->flags, glob, rz_flag_space_cur(core->flags), flagbar_foreach, &u);
|
|
}
|
|
|
|
struct flag_to_flag_t {
|
|
ut64 next;
|
|
ut64 offset;
|
|
};
|
|
|
|
static bool flag_to_flag_foreach(RzFlagItem *fi, void *user) {
|
|
struct flag_to_flag_t *u = (struct flag_to_flag_t *)user;
|
|
if (fi->offset < u->next && fi->offset > u->offset) {
|
|
u->next = fi->offset;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static int flag_to_flag(RzCore *core, const char *glob) {
|
|
rz_return_val_if_fail(glob, 0);
|
|
glob = rz_str_trim_head_ro(glob);
|
|
struct flag_to_flag_t u = { .next = UT64_MAX, .offset = core->offset };
|
|
rz_flag_foreach_glob(core->flags, glob, flag_to_flag_foreach, &u);
|
|
if (u.next != UT64_MAX && u.next > core->offset) {
|
|
return u.next - core->offset;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_tag_add_handler(RzCore *core, int argc, const char **argv) {
|
|
rz_flag_tags_set(core->flags, argv[1], argv[2]);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
static void flag_tag_print(RzCore *core, const char *tag, RzCmdStateOutput *state) {
|
|
PJ *pj = state->d.pj;
|
|
switch (state->mode) {
|
|
case RZ_OUTPUT_MODE_JSON: {
|
|
pj_k(pj, tag);
|
|
pj_a(pj);
|
|
RzList *flags = rz_flag_tags_get(core->flags, tag);
|
|
if (!flags) {
|
|
pj_end(pj);
|
|
break;
|
|
}
|
|
RzListIter *iter;
|
|
RzFlagItem *flag;
|
|
rz_list_foreach (flags, iter, flag) {
|
|
pj_s(pj, flag->name);
|
|
}
|
|
pj_end(pj);
|
|
rz_list_free(flags);
|
|
break;
|
|
}
|
|
case RZ_OUTPUT_MODE_LONG: {
|
|
rz_cons_printf("%s:\n", tag);
|
|
RzList *flags = rz_flag_tags_get(core->flags, tag);
|
|
if (!flags) {
|
|
break;
|
|
}
|
|
RzListIter *iter;
|
|
RzFlagItem *flag;
|
|
rz_list_foreach (flags, iter, flag) {
|
|
rz_cons_printf("0x%08" PFMT64x " %s\n", flag->offset, flag->name);
|
|
}
|
|
rz_list_free(flags);
|
|
break;
|
|
}
|
|
case RZ_OUTPUT_MODE_STANDARD:
|
|
rz_cons_printf("%s\n", tag);
|
|
break;
|
|
default:
|
|
rz_warn_if_reached();
|
|
break;
|
|
}
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_tag_list_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
RzList *list = rz_flag_tags_list(core->flags);
|
|
if (!list) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
RzListIter *iter;
|
|
const char *tag;
|
|
rz_cmd_state_output_array_start(state);
|
|
rz_list_foreach (list, iter, tag) {
|
|
flag_tag_print(core, tag, state);
|
|
}
|
|
rz_list_free(list);
|
|
rz_cmd_state_output_array_end(state);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_tag_search_handler(RzCore *core, int argc, const char **argv) {
|
|
RzList *flags = rz_flag_tags_get(core->flags, argv[1]);
|
|
if (!flags) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
RzListIter *iter;
|
|
RzFlagItem *flag;
|
|
rz_list_foreach (flags, iter, flag) {
|
|
rz_cons_printf("0x%08" PFMT64x " %s\n", flag->offset, flag->name);
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
struct rename_flag_t {
|
|
RzCore *core;
|
|
const char *pfx;
|
|
int count;
|
|
};
|
|
|
|
static bool rename_flag_ordinal(RzFlagItem *fi, void *user) {
|
|
struct rename_flag_t *u = (struct rename_flag_t *)user;
|
|
char *newName = rz_str_newf("%s%d", u->pfx, u->count++);
|
|
if (!newName) {
|
|
return false;
|
|
}
|
|
rz_flag_rename(u->core->flags, fi, newName);
|
|
free(newName);
|
|
return true;
|
|
}
|
|
|
|
static void flag_ordinals(RzCore *core, const char *glob) {
|
|
char *pfx = strdup(glob);
|
|
char *p = strchr(pfx, '*');
|
|
if (p) {
|
|
*p = 0;
|
|
}
|
|
struct rename_flag_t u = { .core = core, .pfx = pfx, .count = 0 };
|
|
rz_flag_foreach_glob(core->flags, glob, rename_flag_ordinal, &u);
|
|
free(pfx);
|
|
}
|
|
|
|
static void print_space_stack(RzFlag *f, int ordinal, const char *name, bool selected, RzCmdStateOutput *state) {
|
|
switch (state->mode) {
|
|
case RZ_OUTPUT_MODE_JSON: {
|
|
char *ename = rz_str_escape(name);
|
|
if (!ename) {
|
|
return;
|
|
}
|
|
pj_o(state->d.pj);
|
|
pj_ki(state->d.pj, "ordinal", ordinal);
|
|
pj_ks(state->d.pj, "name", ename);
|
|
pj_kb(state->d.pj, "selected", selected);
|
|
pj_end(state->d.pj);
|
|
free(ename);
|
|
break;
|
|
}
|
|
default:
|
|
rz_cons_printf("%-2d %s%s\n", ordinal, name, selected ? " (selected)" : "");
|
|
break;
|
|
}
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_space_add_handler(RzCore *core, int argc, const char **argv) {
|
|
return bool2status(rz_flag_space_set(core->flags, argv[1]));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_space_list_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
rz_core_spaces_print(core, &core->flags->spaces, state);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_space_move_handler(RzCore *core, int argc, const char **argv) {
|
|
RzFlagItem *f = rz_flag_get_i(core->flags, core->offset);
|
|
if (!f) {
|
|
RZ_LOG_ERROR("Cannot find any flag at 0x%" PFMT64x ".\n", core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
f->space = rz_flag_space_cur(core->flags);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_space_remove_handler(RzCore *core, int argc, const char **argv) {
|
|
const RzSpace *sp = rz_flag_space_cur(core->flags);
|
|
if (!sp) {
|
|
RZ_LOG_ERROR("No flag space currently selected.\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
return bool2status(rz_flag_space_unset(core->flags, sp->name));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_space_remove_all_handler(RzCore *core, int argc, const char **argv) {
|
|
return bool2status(rz_flag_space_unset(core->flags, NULL));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_space_rename_handler(RzCore *core, int argc, const char **argv) {
|
|
return bool2status(rz_flag_space_rename(core->flags, NULL, argv[1]));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_space_stack_push_handler(RzCore *core, int argc, const char **argv) {
|
|
return bool2status(rz_flag_space_push(core->flags, argv[1]));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_space_stack_pop_handler(RzCore *core, int argc, const char **argv) {
|
|
return bool2status(rz_flag_space_pop(core->flags));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_space_stack_list_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
RzListIter *iter;
|
|
char *space;
|
|
int i = 0;
|
|
rz_list_foreach (core->flags->spaces.spacestack, iter, space) {
|
|
print_space_stack(core->flags, i++, space, false, state);
|
|
}
|
|
const char *cur_name = rz_flag_space_cur_name(core->flags);
|
|
print_space_stack(core->flags, i++, cur_name, true, state);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_remove_handler(RzCore *core, int argc, const char **argv) {
|
|
if (argc < 2) {
|
|
return bool2status(rz_flag_unset_all_off(core->flags, core->offset));
|
|
}
|
|
if (rz_flag_unset_glob(core->flags, argv[1]) < 0) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_remove_all_handler(RzCore *core, int argc, const char **argv) {
|
|
rz_flag_unset_all(core->flags);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_alias_handler(RzCore *core, int argc, const char **argv) {
|
|
RzFlagItem *fi = rz_flag_get(core->flags, argv[1]);
|
|
if (!fi) {
|
|
fi = rz_flag_set(core->flags, argv[1], core->offset, 1);
|
|
}
|
|
if (!fi) {
|
|
RZ_LOG_ERROR("Cannot find flag '%s'\n", argv[1]);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_flag_item_set_alias(fi, argv[2]);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_exists_handler(RzCore *core, int argc, const char **argv) {
|
|
RzFlagItem *item = rz_flag_get(core->flags, argv[1]);
|
|
if (!item) {
|
|
RZ_LOG_ERROR("Cannot find flag '%s'\n", argv[1]);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
RZ_LOG_DEBUG("Find flag '%s' at 0x%" PFMT64x "\n", argv[1], item->offset);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_distance_handler(RzCore *core, int argc, const char **argv) {
|
|
rz_cons_printf("%d\n", flag_to_flag(core, argv[1]));
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_move_handler(RzCore *core, int argc, const char **argv) {
|
|
ut64 address = rz_num_math(core->num, argv[1]);
|
|
return bool2status(rz_flag_move(core->flags, core->offset, address));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_length_handler(RzCore *core, int argc, const char **argv) {
|
|
RzFlagItem *item = rz_flag_get_i(core->flags, core->offset);
|
|
if (!item) {
|
|
RZ_LOG_ERROR("Cannot find flag at 0x%" PFMT64x " offset\n", core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
if (argc < 2) {
|
|
rz_cons_printf("0x%08" PFMT64x "\n", item->size);
|
|
} else {
|
|
item->size = rz_num_math(core->num, argv[1]);
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_realname_handler(RzCore *core, int argc, const char **argv) {
|
|
RzFlagItem *item = argc > 1 ? rz_flag_get(core->flags, argv[1])
|
|
: rz_flag_get_i(core->flags, core->offset);
|
|
if (!item) {
|
|
RZ_LOG_ERROR("Cannot find flag\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
if (argc < 3) {
|
|
rz_cons_printf("%s\n", item->realname);
|
|
} else {
|
|
rz_flag_item_set_realname(item, argv[2]);
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_list_ascii_handler(RzCore *core, int argc, const char **argv) {
|
|
if (argc > 1) {
|
|
flagbars(core, argv[1]);
|
|
} else {
|
|
flagbars(core, NULL);
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_color_handler(RzCore *core, int argc, const char **argv) {
|
|
RzFlagItem *fi = rz_flag_get(core->flags, argv[1]);
|
|
if (!fi) {
|
|
RZ_LOG_ERROR("Cannot find the flag '%s'\n", argv[1]);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
const char *ret = rz_flag_item_set_color(fi, argv[2]);
|
|
if (ret) {
|
|
rz_cons_println(ret);
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_comment_handler(RzCore *core, int argc, const char **argv) {
|
|
RzFlagItem *item;
|
|
if (argc > 2) {
|
|
item = rz_flag_get(core->flags, argv[1]);
|
|
if (!item) {
|
|
RZ_LOG_ERROR("Cannot find flag with name '%s'\n", argv[1]);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
return bool2status(flag_set_comment(item, argv[2]));
|
|
} else {
|
|
item = rz_flag_get_i(core->flags, rz_num_math(core->num, argv[1]));
|
|
if (item && item->comment) {
|
|
rz_cons_println(item->comment);
|
|
} else {
|
|
RZ_LOG_ERROR("Cannot find the flag\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_ordinals_handler(RzCore *core, int argc, const char **argv) {
|
|
flag_ordinals(core, argv[1]);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_rename_handler(RzCore *core, int argc, const char **argv) {
|
|
RzFlagItem *item = rz_flag_get(core->flags, argv[1]);
|
|
if (!item && !strncmp(argv[1], "fcn.", 4)) {
|
|
item = rz_flag_get(core->flags, argv[1] + 4);
|
|
}
|
|
if (!item) {
|
|
RZ_LOG_ERROR("Cannot find matching flag\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
if (!rz_flag_rename(core->flags, item, argv[2])) {
|
|
RZ_LOG_ERROR("Invalid new flag name\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_hexdump_handler(RzCore *core, int argc, const char **argv) {
|
|
char cmd[128];
|
|
ut64 address = rz_num_math(core->num, argv[1]);
|
|
RzFlagItem *item = rz_flag_get_i(core->flags, address);
|
|
if (!item) {
|
|
RZ_LOG_ERROR("Cannot find flag '%s'\n", argv[1]);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_cons_printf("0x%08" PFMT64x "\n", item->offset);
|
|
// FIXME: Use the API directly instead of calling the command
|
|
snprintf(cmd, sizeof(cmd), "px@%" PFMT64d ":%" PFMT64d, item->offset, item->size);
|
|
rz_core_cmd0(core, cmd);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_range_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
if (argc > 1) {
|
|
ut64 size = rz_num_math(core->num, argv[1]);
|
|
rz_core_flag_range_print(core->flags, state, core->offset, core->offset + size);
|
|
} else {
|
|
rz_core_flag_range_print(core->flags, state, core->offset, core->offset + core->blocksize);
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_list_at_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
rz_core_flag_range_print(core->flags, state, core->offset, core->offset + 1);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_flag_list_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
rz_core_flag_print(core->flags, state);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|