rizin/librz/core/cmd/cmd_print.c

6870 lines
212 KiB
C

// SPDX-FileCopyrightText: 2009-2021 pancake <pancake@nopcode.org>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_asm.h>
#include <rz_cmd.h>
#include <rz_core.h>
#include <rz_config.h>
#include <rz_util.h>
#include <rz_type.h>
#include <rz_types.h>
#include "../core_private.h"
#define PF_USAGE_STR "pf[.k[.f[=v]]|[v]]|[n]|[0|cnt][fmt] [a0 a1 ...]"
static const ut32 colormap[256] = {
0x000000,
0x560000,
0x640000,
0x750000,
0x870000,
0x9b0000,
0xb00000,
0xc60000,
0xdd0000,
0xf50000,
0xff0f0f,
0xff2828,
0xff4343,
0xff5e5e,
0xff7979,
0xfe9595,
0x4c1600,
0x561900,
0x641e00,
0x752300,
0x872800,
0x9b2e00,
0xb03400,
0xc63b00,
0xdd4200,
0xf54900,
0xff570f,
0xff6928,
0xff7b43,
0xff8e5e,
0xffa179,
0xfeb595,
0x4c3900,
0x564000,
0x644b00,
0x755700,
0x876500,
0x9b7400,
0xb08400,
0xc69400,
0xdda600,
0xf5b800,
0xffc30f,
0xffc928,
0xffd043,
0xffd65e,
0xffdd79,
0xfee495,
0x4c4c00,
0x565600,
0x646400,
0x757500,
0x878700,
0x9b9b00,
0xb0b000,
0xc6c600,
0xdddd00,
0xf5f500,
0xffff0f,
0xffff28,
0xffff43,
0xffff5e,
0xffff79,
0xfffe95,
0x324c00,
0x395600,
0x426400,
0x4e7500,
0x5a8700,
0x679b00,
0x75b000,
0x84c600,
0x93dd00,
0xa3f500,
0xafff0f,
0xb7ff28,
0xc0ff43,
0xc9ff5e,
0xd2ff79,
0xdbfe95,
0x1f4c00,
0x235600,
0x296400,
0x307500,
0x388700,
0x409b00,
0x49b000,
0x52c600,
0x5cdd00,
0x66f500,
0x73ff0f,
0x82ff28,
0x91ff43,
0xa1ff5e,
0xb1ff79,
0xc1fe95,
0x004c00,
0x005600,
0x006400,
0x007500,
0x008700,
0x009b00,
0x00b000,
0x00c600,
0x00dd00,
0x00f500,
0x0fff0f,
0x28ff28,
0x43ff43,
0x5eff5e,
0x79ff79,
0x95fe95,
0x004c19,
0x00561c,
0x006421,
0x007527,
0x00872d,
0x009b33,
0x00b03a,
0x00c642,
0x00dd49,
0x00f551,
0x0fff5f,
0x28ff70,
0x43ff81,
0x5eff93,
0x79ffa6,
0x95feb8,
0x004c4c,
0x005656,
0x006464,
0x007575,
0x008787,
0x009b9b,
0x00b0b0,
0x00c6c6,
0x00dddd,
0x00f5f5,
0x0ffffe,
0x28fffe,
0x43fffe,
0x5efffe,
0x79ffff,
0x95fffe,
0x00394c,
0x004056,
0x004b64,
0x005775,
0x006587,
0x00749b,
0x0084b0,
0x0094c6,
0x00a6dd,
0x00b8f5,
0x0fc3ff,
0x28c9ff,
0x43d0ff,
0x5ed6ff,
0x79ddff,
0x95e4fe,
0x00264c,
0x002b56,
0x003264,
0x003a75,
0x004387,
0x004d9b,
0x0058b0,
0x0063c6,
0x006edd,
0x007af5,
0x0f87ff,
0x2893ff,
0x43a1ff,
0x5eaeff,
0x79bcff,
0x95cafe,
0x00134c,
0x001556,
0x001964,
0x001d75,
0x002187,
0x00269b,
0x002cb0,
0x0031c6,
0x0037dd,
0x003df5,
0x0f4bff,
0x285eff,
0x4372ff,
0x5e86ff,
0x799aff,
0x95b0fe,
0x19004c,
0x1c0056,
0x210064,
0x270075,
0x2d0087,
0x33009b,
0x3a00b0,
0x4200c6,
0x4900dd,
0x5100f5,
0x5f0fff,
0x7028ff,
0x8143ff,
0x935eff,
0xa679ff,
0xb895fe,
0x33004c,
0x390056,
0x420064,
0x4e0075,
0x5a0087,
0x67009b,
0x7500b0,
0x8400c6,
0x9300dd,
0xa300f5,
0xaf0fff,
0xb728ff,
0xc043ff,
0xc95eff,
0xd279ff,
0xdb95fe,
0x4c004c,
0x560056,
0x640064,
0x750075,
0x870087,
0x9b009b,
0xb000b0,
0xc600c6,
0xdd00dd,
0xf500f5,
0xfe0fff,
0xfe28ff,
0xfe43ff,
0xfe5eff,
0xfe79ff,
0xfe95fe,
0x4c0032,
0x560039,
0x640042,
0x75004e,
0x87005a,
0x9b0067,
0xb00075,
0xc60084,
0xdd0093,
0xf500a3,
0xff0faf,
0xff28b7,
0xff43c0,
0xff5ec9,
0xff79d2,
0xffffff,
};
static inline char *get_section_name(RzCore *core, ut64 offset) {
char *csection = rz_core_get_section_name(core, offset);
if (RZ_STR_ISEMPTY(csection)) {
free(csection);
return rz_str_dup("unknown");
}
rz_str_trim(csection);
if (RZ_STR_ISEMPTY(csection)) {
free(csection);
return rz_str_dup("unknown");
}
return csection;
}
static void colordump(RzCore *core, const ut8 *block, int len) {
const char *chars = " .,:;!O@#";
bool square = rz_config_get_i(core->config, "scr.square");
int i, j;
char ch, ch2, *color;
int cols = rz_config_get_i(core->config, "hex.cols");
bool show_color = rz_config_get_i(core->config, "scr.color");
bool show_flags = rz_config_get_i(core->config, "asm.flags");
bool show_section = rz_config_get_i(core->config, "hex.section");
bool show_offset = rz_config_get_i(core->config, "hex.offset");
bool show_cursor = core->print->cur_enabled;
bool show_unalloc = core->print->flags & RZ_PRINT_FLAGS_UNALLOC;
if (cols < 1 || cols > 0xfffff) {
cols = 32;
}
for (i = 0; i < len; i += cols) {
if (show_section) {
char *name = get_section_name(core, core->offset + i);
rz_cons_printf("%20s ", name ? name : "");
free(name);
}
if (show_offset) {
rz_print_addr(core->print, core->offset + i);
}
for (j = i; j < i + cols; j++) {
if (j >= len) {
break;
}
if (show_color) {
ut32 color_val = colormap[block[j]];
// Brightness weights are based on
// https://twitter.com/DanHollick/status/1417895189239123968
// (normalized to red). I'm aware that max
// brightness is greater than 255 * 3.
int brightness = ((color_val & 0xff0000) >> 16) + 2 * ((color_val & 0xff00) >> 8) + (color_val & 0xff) / 3;
char *str = rz_str_newf("rgb:%s rgb:%06x",
brightness <= 0x7f * 3 ? "fff" : "000", color_val);
color = rz_cons_pal_parse(str, NULL);
free(str);
if (show_cursor && core->print->cur == j) {
ch = '_';
} else {
ch = ' ';
}
} else {
color = rz_str_dup("");
if (show_cursor && core->print->cur == j) {
ch = '_';
} else {
const int idx = ((float)block[j] / 255) * (strlen(chars) - 1);
ch = chars[idx];
}
}
if (show_unalloc &&
!core->print->iob.is_valid_offset(core->print->iob.io, core->offset + j, false)) {
ch = core->print->io_unalloc_ch;
if (show_color) {
free(color);
color = rz_str_dup(Color_RESET);
if (ch == ' ') {
ch = '.';
}
} else {
ch = strchr(chars, ch) ? '?' : ch;
}
}
if (square) {
if (show_flags) {
RzFlagItem *fi = rz_flag_get_i(core->flags, core->offset + j);
if (fi) {
if (fi->name[1]) {
ch = fi->name[0];
ch2 = fi->name[1];
} else {
ch = ' ';
ch2 = fi->name[0];
}
} else {
ch2 = ch;
}
} else {
ch2 = ch;
}
rz_cons_printf("%s%c%c", color, ch, ch2);
} else {
rz_cons_printf("%s%c", color, ch);
}
free(color);
}
if (show_color) {
rz_cons_printf(Color_RESET);
}
rz_cons_newline();
}
}
static void findMethodBounds(RzList /*<RzBinSymbol *>*/ *methods, ut64 *min, ut64 *max) {
RzBinSymbol *sym;
RzListIter *iter;
ut64 at_min = UT64_MAX;
ut64 at_max = 0LL;
rz_list_foreach (methods, iter, sym) {
if (sym->vaddr) {
if (sym->vaddr < at_min) {
at_min = sym->vaddr;
}
if (sym->vaddr + sym->size > at_max) {
at_max = sym->vaddr + sym->size;
}
}
}
*min = at_min;
*max = at_max;
}
static ut64 findClassBounds(RzCore *core, int *len) {
ut64 min = 0, max = 0;
void **iter;
RzBinClass *c;
RzBinObject *bin_obj = rz_bin_cur_object(core->bin);
const RzPVector *cs = rz_bin_object_get_classes(bin_obj);
if (cs) {
rz_pvector_foreach (cs, iter) {
c = *iter;
if (!c || !c->name || !c->name[0]) {
continue;
}
findMethodBounds(c->methods, &min, &max);
if (len) {
*len = (max - min);
}
return min;
}
}
return 0;
}
RZ_IPI RzCmdStatus rz_cmd_print_timestamp_unix_handler(RzCore *core, int argc, const char **argv) {
char *date = NULL;
const ut8 *block = core->block;
ut32 len = core->blocksize;
bool big_endian = rz_config_get_b(core->config, "cfg.bigendian");
int timezone = (int)rz_config_get_i(core->config, "time.zone");
if (len < sizeof(ut32)) {
RZ_LOG_ERROR("The block size is less than 4.\n");
return RZ_CMD_STATUS_ERROR;
}
for (ut64 i = 0; i < len; i += sizeof(ut32)) {
ut32 dt = rz_read_ble32(block + i, big_endian);
// add timezone
dt += timezone * (60 * 60);
date = rz_time_date_unix_to_string(dt);
rz_cons_printf("%s\n", date);
free(date);
}
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_print_timestamp_current_handler(RzCore *core, int argc, const char **argv) {
char *now = rz_time_date_now_to_string();
rz_cons_printf("%s\n", now);
free(now);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_print_timestamp_dos_handler(RzCore *core, int argc, const char **argv) {
char *date = NULL;
const ut8 *block = core->block;
ut32 len = core->blocksize;
if (len < sizeof(ut32)) {
RZ_LOG_ERROR("The block size is less than 4.\n");
return RZ_CMD_STATUS_ERROR;
}
for (ut64 i = 0; i < len; i += sizeof(ut32)) {
ut32 dt = rz_read_le32(block + i);
date = rz_time_date_dos_to_string(dt);
rz_cons_printf("%s\n", date);
free(date);
}
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_print_timestamp_hfs_handler(RzCore *core, int argc, const char **argv) {
char *date = NULL;
const ut8 *block = core->block;
ut32 len = core->blocksize;
bool big_endian = rz_config_get_b(core->config, "cfg.bigendian");
int timezone = (int)rz_config_get_i(core->config, "time.zone");
if (len < sizeof(ut32)) {
RZ_LOG_ERROR("The block size is less than 4.\n");
return RZ_CMD_STATUS_ERROR;
}
for (ut64 i = 0; i < len; i += sizeof(ut32)) {
ut32 dt = rz_read_ble32(block + i, big_endian);
// add timezone
dt += timezone * (60 * 60);
date = rz_time_date_hfs_to_string(dt);
rz_cons_printf("%s\n", date);
free(date);
}
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_print_timestamp_ntfs_handler(RzCore *core, int argc, const char **argv) {
char *date = NULL;
const ut8 *block = core->block;
ut32 len = core->blocksize;
bool big_endian = rz_config_get_b(core->config, "cfg.bigendian");
if (len < sizeof(ut64)) {
RZ_LOG_ERROR("The block size is less than 8.\n");
return RZ_CMD_STATUS_ERROR;
}
for (ut64 i = 0; i < len; i += sizeof(ut64)) {
ut64 dt = rz_read_ble64(block + i, big_endian);
date = rz_time_date_w32_to_string(dt);
rz_cons_printf("%s\n", date);
free(date);
}
return RZ_CMD_STATUS_OK;
}
// > pxa
/* In this function, most of the buffers have 4 times
* the required length. This is because we supports colours,
* that are 4 chars long. */
#define append(x, y) \
{ \
strcat(x, y); \
x += strlen(y); \
}
#define Pal(x, y) (x->cons && x->cons->context->pal.y) ? x->cons->context->pal.y
static void annotated_hexdump(RzCore *core, int len) {
if (!len) {
return;
}
const int usecolor = rz_config_get_i(core->config, "scr.color");
int nb_cols = rz_config_get_i(core->config, "hex.cols");
core->print->use_comments = rz_config_get_i(core->config, "hex.comments");
int flagsz = rz_config_get_i(core->config, "hex.flagsz");
bool showSection = rz_config_get_i(core->config, "hex.section");
const ut8 *buf = core->block;
ut64 addr = core->offset;
int color_idx = 0;
char *bytes, *chars;
char *ebytes, *echars; // They'll walk over the vars above
ut64 fend = UT64_MAX;
int i, j, low, max, here, rows;
bool marks = false, setcolor = true, hascolor = false;
ut8 ch = 0;
char tmpbuf[20] = { 0 };
char *colors[10] = { NULL };
for (i = 0; i < 10; i++) {
colors[i] = rz_cons_rainbow_get(i, 10, false);
}
const int col = core->print->col;
RzFlagItem *flag, *current_flag = NULL;
char **note;
int html = rz_config_get_i(core->config, "scr.html");
int nb_cons_cols;
bool compact = false;
if (core->print) {
compact = core->print->flags & RZ_PRINT_FLAGS_COMPACT;
}
char *format = compact ? " %X %X" : " %X %X ";
int step = compact ? 4 : 5;
// Adjust the number of columns
if (nb_cols < 1) {
nb_cols = 16;
}
nb_cols -= (nb_cols % 2); // nb_cols should be even
if (nb_cols < 1) {
return;
}
nb_cons_cols = 12 + nb_cols * 2 + (nb_cols / 2);
nb_cons_cols += 17;
rows = len / nb_cols;
chars = calloc(nb_cols * 40, sizeof(char));
if (!chars)
goto err_chars;
note = calloc(nb_cols, sizeof(char *));
if (!note)
goto err_note;
bytes = calloc(nb_cons_cols * 40, sizeof(char));
if (!bytes)
goto err_bytes;
int addrpadlen = strlen(rz_strf(tmpbuf, "%08" PFMT64x, addr)) - 8;
char addrpad[32];
if (addrpadlen > 0) {
memset(addrpad, ' ', addrpadlen);
addrpad[addrpadlen] = 0;
// Compute, then show the legend
strcpy(bytes, addrpad);
} else {
*addrpad = 0;
addrpadlen = 0;
}
strcpy(bytes + addrpadlen, "- offset - ");
j = strlen(bytes);
for (i = 0; i < nb_cols; i += 2) {
sprintf(bytes + j, format, (i & 0xf), (i + 1) & 0xf);
j += step;
}
j--;
strcpy(bytes + j, " ");
j += 2;
for (i = 0; i < nb_cols; i++) {
sprintf(bytes + j + i, "%0X", i % 17);
}
if (usecolor) {
const char *color_title = Pal(core, offset)
: Color_MAGENTA;
rz_cons_strcat(color_title);
rz_cons_strcat(bytes);
rz_cons_strcat(Color_RESET);
} else {
rz_cons_strcat(bytes);
}
rz_cons_newline();
// hexdump
for (i = 0; i < rows; i++) {
bytes[0] = '\0';
chars[0] = '\0';
ebytes = bytes;
echars = chars;
hascolor = false;
ut64 ea = addr;
if (core->print->pava) {
ut64 va = rz_io_p2v(core->io, addr);
if (va != UT64_MAX) {
ea = va;
}
}
if (usecolor) {
append(ebytes, core->cons->context->pal.offset);
}
if (showSection) {
char *name = get_section_name(core, ea);
char *s = rz_str_newf("%20s ", name);
append(ebytes, s);
free(s);
free(name);
}
ebytes += sprintf(ebytes, "0x%08" PFMT64x, ea);
if (usecolor) {
append(ebytes, Color_RESET);
}
append(ebytes, (col == 1) ? " |" : " ");
bool hadflag = false;
for (j = 0; j < nb_cols; j++) {
setcolor = true;
RZ_FREE(note[j]);
// TODO: in pava mode we should read addr or ea? // imho ea. but wat about hdrs and such
RzIntervalNode *meta_node = rz_meta_get_in(core->analysis, ea + j, RZ_META_TYPE_FORMAT);
RzAnalysisMetaItem *meta = meta_node ? meta_node->data : NULL;
if (meta && meta->type == RZ_META_TYPE_FORMAT && meta_node->start == addr + j) {
rz_cons_printf(".format %s ; size=", meta->str);
// TODO: Convert to the API
rz_core_cmdf(core, "pfs %s", meta->str);
char *r = rz_core_print_format(core, meta->str, RZ_PRINT_MUSTSEE, meta_node->start);
rz_cons_print(r);
free(r);
if (usecolor) {
append(ebytes, Color_INVERT);
append(echars, Color_INVERT);
}
hadflag = true;
}
if (meta) {
meta = NULL;
}
// collect comments
const char *comment = rz_meta_get_string(core->analysis, RZ_META_TYPE_COMMENT, addr + j);
if (comment) {
note[j] = rz_str_newf(";%s", comment);
marks = true;
}
// collect flags
flag = rz_flag_get_i(core->flags, addr + j);
if (flag) { // Beginning of a flag
if (flagsz) {
fend = addr + flagsz; // core->blocksize;
} else {
fend = addr + j + flag->size;
}
free(note[j]);
note[j] = rz_str_prepend(rz_str_dup(flag->name), "/");
marks = true;
color_idx++;
color_idx %= 10;
current_flag = flag;
if (showSection) {
rz_cons_printf("%20s ", "");
}
if (flag->offset == addr + j) {
if (usecolor) {
append(ebytes, Color_INVERT);
append(echars, Color_INVERT);
}
hadflag = true;
}
} else {
// Are we past the current flag?
if (current_flag && addr + j > (current_flag->offset + current_flag->size)) {
setcolor = false;
current_flag = NULL;
}
// Turn colour off if we're at the end of the current flag
if (fend == UT64_MAX || fend <= addr + j) {
setcolor = false;
}
}
if (usecolor) {
if (!setcolor) {
const char *bytecolor = rz_print_byte_color(core->print, ch);
if (bytecolor) {
append(ebytes, bytecolor);
append(echars, bytecolor);
hascolor = true;
}
} else if (!hascolor) {
hascolor = true;
if (current_flag && current_flag->color) {
char *ansicolor = rz_cons_pal_parse(current_flag->color, NULL);
if (ansicolor) {
append(ebytes, ansicolor);
append(echars, ansicolor);
free(ansicolor);
}
} else { // Use "random" colours
append(ebytes, colors[color_idx]);
append(echars, colors[color_idx]);
}
}
}
here = RZ_MIN((i * nb_cols) + j, core->blocksize);
ch = buf[here];
if (core->print->ocur != -1) {
low = RZ_MIN(core->print->cur, core->print->ocur);
max = RZ_MAX(core->print->cur, core->print->ocur);
} else {
low = max = core->print->cur;
}
if (core->print->cur_enabled) {
if (low == max) {
if (low == here) {
if (html || !usecolor) {
append(ebytes, "[");
append(echars, "[");
} else {
append(echars, Color_INVERT);
append(ebytes, Color_INVERT);
}
}
} else {
if (here >= low && here < max) {
if (html || !usecolor) {
append(ebytes, "[");
append(echars, "[");
} else {
if (usecolor) {
append(ebytes, Color_INVERT);
append(echars, Color_INVERT);
}
}
}
}
}
if (!ebytes) { // this check is just to silence the compiler
goto err_ebytes;
}
sprintf(ebytes, "%02x", ch);
// rz_print_byte (core->print, "%02x ", j, ch);
ebytes += strlen(ebytes);
if (hadflag) {
if (usecolor) {
append(ebytes, Color_INVERT_RESET);
append(echars, Color_INVERT_RESET);
}
hadflag = false;
}
sprintf(echars, "%c", IS_PRINTABLE(ch) ? ch : '.');
echars++;
if (core->print->cur_enabled && max == here) {
if (!html && usecolor) {
append(ebytes, Color_RESET);
append(echars, Color_RESET);
}
hascolor = false;
}
if (j < (nb_cols - 1) && (j % 2) && !compact) {
append(ebytes, " ");
}
if (fend != UT64_MAX && fend == addr + j + 1) {
if (!html && usecolor) {
append(ebytes, Color_RESET);
append(echars, Color_RESET);
}
fend = UT64_MAX;
hascolor = false;
}
}
if (!html && usecolor) {
append(ebytes, Color_RESET);
append(echars, Color_RESET);
}
append(ebytes, (col == 1) ? "| " : (col == 2) ? " |"
: " ");
if (col == 2) {
append(echars, "|");
}
if (marks) { // show comments and flags
int hasline = 0;
int out_sz = nb_cons_cols + 20;
char *out = calloc(out_sz, sizeof(char));
memset(out, ' ', nb_cons_cols - 1);
for (j = 0; j < nb_cols; j++) {
if (note[j]) {
int off = (j * 3) - (j / 2) + 13;
int notej_len = strlen(note[j]);
int sz = RZ_MIN(notej_len, nb_cons_cols - off);
if (compact) {
off -= (j / 2);
} else {
if (j % 2) {
off--;
}
}
memcpy(out + off, note[j], sz);
if (sz < notej_len) {
out[off + sz - 2] = '.';
out[off + sz - 1] = '.';
}
hasline = (out[off] != ' ');
RZ_FREE(note[j]);
}
}
out[out_sz - 1] = 0;
if (hasline) {
rz_cons_strcat(addrpad);
rz_cons_strcat(out);
rz_cons_newline();
}
marks = false;
free(out);
}
rz_cons_strcat(bytes);
rz_cons_strcat(chars);
if (core->print->use_comments) {
for (j = 0; j < nb_cols; j++) {
const char *comment = core->print->get_comments(core->print->user, addr + j);
if (comment) {
rz_cons_printf(" ; %s", comment);
}
}
}
rz_cons_newline();
addr += nb_cols;
}
err_ebytes:
free(bytes);
err_bytes:
free(note);
err_note:
free(chars);
err_chars:
for (i = 0; i < RZ_ARRAY_SIZE(colors); i++) {
free(colors[i]);
}
}
static bool cmd_print_pxA(RzCore *core, int len, RzOutputMode mode) {
if (!len) {
return false;
}
RzConsPrintablePalette *pal = &core->cons->context->pal;
int show_offset = true;
int cols = rz_config_get_i(core->config, "hex.cols");
int show_color = rz_config_get_i(core->config, "scr.color");
int onechar = rz_config_get_i(core->config, "hex.onechar");
bool hex_offset = rz_config_get_i(core->config, "hex.offset");
int bgcolor_in_heap = false;
bool show_cursor = core->print->cur_enabled;
char buf[2];
char *bgcolor, *fgcolor, *text;
ut64 i, c, oi;
RzAnalysisOp op = { 0 };
ut8 *data;
int datalen;
switch (mode) {
case RZ_OUTPUT_MODE_LONG:
datalen = cols * 8 * core->cons->rows;
data = malloc(datalen);
rz_io_read_at_mapped(core->io, core->offset, data, datalen);
len = datalen;
break;
case RZ_OUTPUT_MODE_STANDARD:
data = core->block;
datalen = core->blocksize;
break;
default:
rz_warn_if_reached();
return false;
}
if (len < 1) {
len = datalen;
}
if (len < 0 || len > datalen) {
RZ_LOG_ERROR("core: Invalid length\n");
return false;
}
if (onechar) {
cols *= 4;
} else {
cols *= 2;
}
if (show_offset) {
char offstr[128];
snprintf(offstr, sizeof(offstr),
"0x%08" PFMT64x " ", core->offset);
if (strlen(offstr) > 12) {
cols -= ((strlen(offstr) - 12) * 2);
}
}
for (oi = i = c = 0; i < len; c++) {
if (i && (cols != 0) && !(c % cols)) {
show_offset = true;
rz_cons_printf(" %" PFMT64u "\n", i - oi);
oi = i;
}
if (show_offset && hex_offset) {
rz_cons_printf("0x%08" PFMT64x " ", core->offset + i);
show_offset = false;
}
if (bgcolor_in_heap) {
free(bgcolor);
bgcolor_in_heap = false;
}
bgcolor = Color_BGBLACK;
fgcolor = Color_WHITE;
text = NULL;
rz_analysis_op_init(&op);
if (rz_analysis_op(core->analysis, &op, core->offset + i, data + i, len - i, RZ_ANALYSIS_OP_MASK_BASIC) <= 0) {
op.type = 0;
bgcolor = Color_BGRED;
op.size = 1;
}
switch (op.type) {
case RZ_ANALYSIS_OP_TYPE_LEA:
case RZ_ANALYSIS_OP_TYPE_MOV:
case RZ_ANALYSIS_OP_TYPE_CAST:
case RZ_ANALYSIS_OP_TYPE_LENGTH:
case RZ_ANALYSIS_OP_TYPE_CMOV:
text = "mv";
bgcolor = pal->mov;
fgcolor = Color_YELLOW;
break;
case RZ_ANALYSIS_OP_TYPE_PUSH:
case RZ_ANALYSIS_OP_TYPE_UPUSH:
case RZ_ANALYSIS_OP_TYPE_RPUSH:
bgcolor = pal->push;
fgcolor = Color_WHITE;
text = "->";
break;
case RZ_ANALYSIS_OP_TYPE_IO:
bgcolor = pal->swi;
fgcolor = Color_WHITE;
text = "io";
break;
case RZ_ANALYSIS_OP_TYPE_TRAP:
case RZ_ANALYSIS_OP_TYPE_SWI:
case RZ_ANALYSIS_OP_TYPE_NEW:
// bgcolor = Color_BGRED;
bgcolor = pal->trap; // rz_cons_swap_ground (pal->trap);
fgcolor = Color_WHITE;
text = "$$";
break;
case RZ_ANALYSIS_OP_TYPE_POP:
text = "<-";
bgcolor = rz_cons_swap_ground(pal->pop);
bgcolor_in_heap = true;
fgcolor = Color_WHITE;
break;
case RZ_ANALYSIS_OP_TYPE_NOP:
fgcolor = Color_WHITE;
bgcolor = rz_cons_swap_ground(pal->nop);
bgcolor_in_heap = true;
text = "..";
break;
case RZ_ANALYSIS_OP_TYPE_MUL:
fgcolor = Color_BLACK;
bgcolor = rz_cons_swap_ground(pal->math);
bgcolor_in_heap = true;
text = "_*";
break;
case RZ_ANALYSIS_OP_TYPE_DIV:
bgcolor = rz_cons_swap_ground(pal->math);
bgcolor_in_heap = true;
fgcolor = Color_BLACK;
text = "_/";
break;
case RZ_ANALYSIS_OP_TYPE_AND:
bgcolor = rz_cons_swap_ground(pal->bin);
bgcolor_in_heap = true;
fgcolor = Color_BLACK;
text = "_&";
break;
case RZ_ANALYSIS_OP_TYPE_XOR:
bgcolor = rz_cons_swap_ground(pal->bin);
bgcolor_in_heap = true;
fgcolor = Color_BLACK;
text = "_^";
break;
case RZ_ANALYSIS_OP_TYPE_OR:
bgcolor = rz_cons_swap_ground(pal->bin);
bgcolor_in_heap = true;
fgcolor = Color_BLACK;
text = "_|";
break;
case RZ_ANALYSIS_OP_TYPE_SHR:
bgcolor = rz_cons_swap_ground(pal->bin);
bgcolor_in_heap = true;
fgcolor = Color_BLACK;
text = ">>";
break;
case RZ_ANALYSIS_OP_TYPE_SHL:
bgcolor = rz_cons_swap_ground(pal->bin);
bgcolor_in_heap = true;
fgcolor = Color_BLACK;
text = "<<";
break;
case RZ_ANALYSIS_OP_TYPE_SUB:
bgcolor = rz_cons_swap_ground(pal->math);
bgcolor_in_heap = true;
fgcolor = Color_WHITE;
text = "--";
break;
case RZ_ANALYSIS_OP_TYPE_ADD:
bgcolor = rz_cons_swap_ground(pal->math);
bgcolor_in_heap = true;
fgcolor = Color_WHITE;
text = "++";
break;
case RZ_ANALYSIS_OP_TYPE_JMP:
case RZ_ANALYSIS_OP_TYPE_UJMP:
case RZ_ANALYSIS_OP_TYPE_IJMP:
case RZ_ANALYSIS_OP_TYPE_RJMP:
case RZ_ANALYSIS_OP_TYPE_IRJMP:
case RZ_ANALYSIS_OP_TYPE_MJMP:
bgcolor = rz_cons_swap_ground(pal->jmp);
bgcolor_in_heap = true;
fgcolor = Color_BLACK;
text = "_J";
break;
case RZ_ANALYSIS_OP_TYPE_CJMP:
case RZ_ANALYSIS_OP_TYPE_UCJMP:
bgcolor = rz_cons_swap_ground(pal->cjmp);
bgcolor_in_heap = true;
fgcolor = Color_BLACK;
text = "cJ";
break;
case RZ_ANALYSIS_OP_TYPE_CALL:
case RZ_ANALYSIS_OP_TYPE_UCALL:
case RZ_ANALYSIS_OP_TYPE_ICALL:
case RZ_ANALYSIS_OP_TYPE_RCALL:
case RZ_ANALYSIS_OP_TYPE_IRCALL:
case RZ_ANALYSIS_OP_TYPE_UCCALL:
bgcolor = rz_cons_swap_ground(pal->call);
bgcolor_in_heap = true;
fgcolor = Color_WHITE;
text = "_C";
break;
case RZ_ANALYSIS_OP_TYPE_ACMP:
case RZ_ANALYSIS_OP_TYPE_CMP:
bgcolor = rz_cons_swap_ground(pal->cmp);
bgcolor_in_heap = true;
fgcolor = Color_BLACK;
text = "==";
break;
case RZ_ANALYSIS_OP_TYPE_RET:
bgcolor = rz_cons_swap_ground(pal->ret);
bgcolor_in_heap = true;
fgcolor = Color_WHITE;
text = "_R";
break;
case -1:
case RZ_ANALYSIS_OP_TYPE_ILL:
case RZ_ANALYSIS_OP_TYPE_UNK:
bgcolor = rz_cons_swap_ground(pal->invalid);
bgcolor_in_heap = true;
fgcolor = Color_WHITE;
text = "XX";
break;
}
int opsz = RZ_MAX(op.size, 1);
if (show_cursor) {
if (core->print->cur >= i && core->print->cur < i + opsz) {
rz_cons_invert(1, 1);
}
}
if (onechar) {
if (text) {
if (text[0] == '_' || text[0] == '.') {
buf[0] = text[1];
} else {
buf[0] = text[0];
}
} else {
buf[0] = '.';
}
buf[1] = 0;
text = buf;
}
if (show_color) {
if (!text) {
text = " ";
}
rz_cons_printf("%s%s%s\x1b[0m", bgcolor, fgcolor, text);
} else {
if (text) {
rz_cons_print(text);
} else {
rz_cons_print(" ");
}
}
if (show_cursor) {
if (core->print->cur >= i && core->print->cur < i + opsz) {
rz_cons_invert(0, 1);
}
}
i += opsz;
rz_analysis_op_fini(&op);
}
rz_cons_printf(" %" PFMT64d "\n", i - oi);
if (bgcolor_in_heap) {
free(bgcolor);
}
if (data != core->block) {
free(data);
}
return true;
}
/* Uses data from clipboard if value is NULL */
static bool print_operation_transform(RzCore *core, RzCoreWriteOp op, RZ_NULLABLE const char *val) {
ut8 *hex = NULL;
size_t hexlen = 0, buflen = 0;
if (val) {
hex = RZ_NEWS(ut8, (strlen(val) + 1) / 2);
if (!hex) {
return false;
}
hexlen = rz_hex_str2bin(val, hex);
}
ut8 *buf = rz_core_transform_op(core, core->offset, op, hex, hexlen, &buflen);
free(hex);
rz_core_print_hexdump(core, core->offset, buf, buflen, 16, 1, 1);
free(buf);
return true;
}
static void handle_entropy(RzCore *core, const char *name, const ut8 *block, int len) {
RzHashSize digest_size = 0;
ut8 *digest = rz_hash_cfg_calculate_small_block(core->hash, name, block, len, &digest_size);
if (!digest) {
return;
}
double entropy = rz_read_be_double(digest);
rz_cons_printf("%f\n", entropy);
free(digest);
}
static void handle_temperature(RzCore *core, const char *name, const ut8 *block, int len) {
RzHashSize digest_size = 0;
ut8 *digest = rz_hash_cfg_calculate_small_block(core->hash, name, block, len, &digest_size);
if (!digest) {
return;
}
double temperature = rz_read_be_double(digest);
rz_cons_printf("%f\n", temperature);
free(digest);
}
static void handle_ssdeep(RzCore *core, const char *name, const ut8 *block, int len) {
RzHashSize digest_size = 0;
char *digest = (char *)rz_hash_cfg_calculate_small_block(core->hash, name, block, len, &digest_size);
if (!digest) {
return;
}
rz_cons_printf("%s\n", digest);
free(digest);
}
static inline void hexprint(const ut8 *data, int len) {
if (!data || len < 1) {
return;
}
for (int i = 0; i < len; i++) {
rz_cons_printf("%02x", data[i]);
}
rz_cons_newline();
}
static void handle_hash_cfg(RzCore *core, const char *name, const ut8 *block, int len) {
RzHashSize digest_size = 0;
ut8 *digest = rz_hash_cfg_calculate_small_block(core->hash, name, block, len, &digest_size);
hexprint(digest, digest_size);
free(digest);
}
RZ_IPI RzCmdStatus rz_cmd_print_hash_cfg_handler(RzCore *core, int argc, const char **argv) {
const RzHashPlugin *plugin = rz_hash_plugin_by_name(core->hash, argv[1]);
if (!plugin) {
RZ_LOG_ERROR("algorithm '%s' does not exists\n", argv[1]);
return RZ_CMD_STATUS_ERROR;
}
if (!strncmp(plugin->name, "entropy", strlen("entropy"))) {
handle_entropy(core, plugin->name, core->block, core->blocksize);
} else if (!strncmp(plugin->name, "temperature", strlen("temperature"))) {
handle_temperature(core, plugin->name, core->block, core->blocksize);
} else if (!strcmp(plugin->name, "ssdeep")) {
handle_ssdeep(core, plugin->name, core->block, core->blocksize);
} else {
handle_hash_cfg(core, plugin->name, core->block, core->blocksize);
}
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_print_hash_cfg_algo_list_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
return rz_core_hash_plugins_print(core->hash, state);
}
RZ_IPI RzCmdStatus rz_cmd_print_magic_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
RzList *hits = rz_core_search_magic(core, NULL, argc > 1 ? argv[1] : NULL);
if (!hits) {
RZ_LOG_ERROR("Searching for magics failed.\n");
return RZ_CMD_STATUS_ERROR;
}
RzListIter *it;
RzSearchHit *hit;
if (mode == RZ_OUTPUT_MODE_JSON) {
PJ *pj = pj_new();
pj_a(pj);
rz_list_foreach (hits, it, hit) {
char *detail = rz_search_hit_detail_as_string(hit);
pj_o(pj);
pj_kn(pj, "address", hit->address);
pj_ks(pj, "magic", rz_str_get(detail));
pj_end(pj);
free(detail);
}
pj_end(pj);
rz_cons_println(pj_string(pj));
pj_free(pj);
} else {
rz_list_foreach (hits, it, hit) {
char *detail = rz_search_hit_detail_as_string(hit);
rz_cons_printf("0x%08" PFMT64x " %s\n", hit->address, rz_str_get(detail));
free(detail);
}
}
rz_list_free(hits);
return RZ_CMD_STATUS_OK;
}
static int bbcmp(RzAnalysisBlock *a, RzAnalysisBlock *b, void *user) {
return a->addr - b->addr;
}
/* TODO: integrate this into rz_analysis */
static void _pointer_table(RzCore *core, ut64 origin, ut64 offset, const ut8 *buf, int len, int step, RzOutputMode mode) {
if (step < 1) {
step = 4;
}
if (!rz_io_is_valid_offset(core->io, origin, 0) ||
!rz_io_is_valid_offset(core->io, offset, 0)) {
return;
}
for (size_t i = 0; (i + sizeof(st32)) <= len; i += step) {
st32 delta = rz_read_le32(buf + i);
ut64 addr = offset + delta;
if (!rz_io_is_valid_offset(core->io, addr, 0)) {
// Lets check for jmptbl with not relative addresses
// Like: jmp dword [eax*4 + jmptbl.0x5435345]
if (!rz_io_is_valid_offset(core->io, delta, 0)) {
break;
}
addr = delta;
}
rz_cons_printf("0x%08" PFMT64x " -> 0x%08" PFMT64x "\n", offset + i, addr);
}
}
static void pr_bb(RzCore *core, RzAnalysisFunction *fcn, RzAnalysisBlock *b, bool emu, ut64 saved_gp, ut8 *saved_arena, char p_type, bool fromHere) {
bool show_flags = rz_config_get_i(core->config, "asm.flags");
const bool orig_bb_middle = rz_config_get_b(core->config, "asm.bb.middle");
RzReg *rreg = rz_analysis_get_reg(core->analysis);
rz_analysis_set_gp(core->analysis, saved_gp);
if (fromHere) {
if (b->addr < core->offset) {
core->cons->null = true;
} else {
core->cons->null = false;
}
}
if (emu) {
if (b->parent_reg_arena) {
ut64 gp;
rz_reg_arena_poke(rreg, b->parent_reg_arena);
RZ_FREE(b->parent_reg_arena);
gp = rz_reg_getv(rreg, "gp");
if (gp) {
rz_analysis_set_gp(core->analysis, gp);
}
} else {
rz_reg_arena_poke(rreg, saved_arena);
}
}
rz_config_set_b(core->config, "asm.bb.middle", false);
p_type == 'D'
? rz_core_cmdf(core, "pD %" PFMT64u " @ 0x%" PFMT64x, b->size, b->addr)
: rz_core_cmdf(core, "pI %" PFMT64u " @ 0x%" PFMT64x, b->size, b->addr);
rz_config_set_b(core->config, "asm.bb.middle", orig_bb_middle);
if (b->jump != UT64_MAX) {
if (b->jump > b->addr) {
RzAnalysisBlock *jumpbb = rz_analysis_get_block_at(b->analysis, b->jump);
if (jumpbb && rz_list_contains(jumpbb->fcns, fcn)) {
ut8 *last_disasm_reg = rz_analysis_get_last_disasm_reg(core->analysis);
if (emu && last_disasm_reg && !jumpbb->parent_reg_arena) {
jumpbb->parent_reg_arena = rz_reg_arena_dup(rreg, last_disasm_reg);
}
}
}
if (p_type == 'D' && show_flags) {
rz_cons_printf("| ----------- true: 0x%08" PFMT64x, b->jump);
}
}
if (b->fail != UT64_MAX) {
if (b->fail > b->addr) {
RzAnalysisBlock *failbb = rz_analysis_get_block_at(b->analysis, b->fail);
if (failbb && rz_list_contains(failbb->fcns, fcn)) {
ut8 *last_disasm_reg = rz_analysis_get_last_disasm_reg(core->analysis);
if (emu && last_disasm_reg && !failbb->parent_reg_arena) {
failbb->parent_reg_arena = rz_reg_arena_dup(rreg, last_disasm_reg);
}
}
}
if (p_type == 'D' && show_flags) {
rz_cons_printf(" false: 0x%08" PFMT64x, b->fail);
}
}
if (p_type == 'D' && show_flags) {
rz_cons_newline();
}
}
static void handle_default_disasm_print_mode(const RzCore *core, const ut64 addr, const bool ret_val,
const char *m_intr, RzStrBuf *buf) {
const bool show_color = rz_config_get_i(core->config, "scr.color");
if (show_color) {
const char *offsetColor = rz_cons_singleton()->context->pal.offset;
if (!ret_val) {
rz_cons_printf("%s0x%08" PFMT64x Color_RESET " %10s %s\n",
offsetColor, addr, "", m_intr);
} else {
rz_strbuf_appendf(buf, "%s0x%08" PFMT64x Color_RESET " %10s %s\n",
offsetColor, addr, "", m_intr);
}
} else {
if (!ret_val) {
rz_cons_printf("0x%08" PFMT64x " %10s %s\n", addr, "", m_intr);
} else {
rz_strbuf_appendf(buf, "0x%08" PFMT64x " %10s %s\n", addr, "", m_intr);
}
}
}
static void disasm_print_ret(const RzCore *core, const RzOutputMode mode, const char *m_intr, const ut64 addr,
const bool ret_val, RzStrBuf *buf) {
if (!buf && ret_val) {
return;
}
switch (mode) {
case RZ_OUTPUT_MODE_QUIET:
if (!ret_val) {
rz_cons_printf("%s\n", m_intr);
} else {
rz_strbuf_append(buf, m_intr);
}
break;
default:
handle_default_disasm_print_mode(core, addr, ret_val, m_intr, buf);
break;
}
}
/**
* \brief Disassemble from \p addr until \p limit no of instructions and
* prints or returns the disassembled string in \p buf
*
* \param core Pointer to the RzCore
* \param addr Address to start disassembling
* \param limit Maximum number of instructions to disassemble
* \param mode The mode in which data has to be printed/crafted
* \param ret_val If true, the disassembled string is stored in \p buf. Otherwise it is streamed to stdout
* \param buf Pointer to the RzStrBuf to store the disassembled string
*
* \return True if there are no errors during disassembling and crafting the response. False otherwise.
*/
RZ_API bool rz_core_disasm_until_ret(RZ_NONNULL RzCore *core, ut64 addr, const int limit,
const RzOutputMode mode, const bool ret_val, RZ_NULLABLE RZ_OUT RzStrBuf *buf) {
rz_return_val_if_fail(core, false);
if (!buf && ret_val) {
return false;
}
for (int i = 0; i < limit; i++) {
RzAnalysisOp *op = rz_core_analysis_op(core, addr, RZ_ANALYSIS_OP_MASK_BASIC | RZ_ANALYSIS_OP_MASK_DISASM);
if (!op) {
RZ_LOG_ERROR("Cannot get op at 0x%08" PFMT64x "\n", addr);
rz_analysis_op_free(op);
break;
}
const char *mnem = op->mnemonic;
disasm_print_ret(core, mode, mnem, addr, ret_val, buf);
switch (op->type & RZ_ANALYSIS_OP_MASK_WILDCARD) {
case RZ_ANALYSIS_OP_TYPE_RET:
case RZ_ANALYSIS_OP_TYPE_UJMP:
rz_analysis_op_free(op);
goto beach;
break;
default:
break;
}
if (op->type == RZ_ANALYSIS_OP_TYPE_JMP) {
addr = op->jump;
} else {
addr += op->size;
}
if (ret_val) {
rz_strbuf_append(buf, "\n");
}
rz_analysis_op_free(op);
}
beach:
return true;
}
static void func_walk_blocks(RzCore *core, RzAnalysisFunction *f, bool fromHere, RzCmdStateOutput *state) {
const bool orig_bb_middle = rz_config_get_b(core->config, "asm.bb.middle");
rz_config_set_b(core->config, "asm.bb.middle", false);
rz_pvector_sort(f->bbs, (RzPVectorComparator)bbcmp, NULL);
RzAnalysisBlock *b;
void **iter;
if (state->mode == RZ_OUTPUT_MODE_JSON) {
rz_cmd_state_output_array_start(state);
rz_pvector_foreach (f->bbs, iter) {
b = (RzAnalysisBlock *)*iter;
if (fromHere) {
if (b->addr < core->offset) {
core->cons->null = true;
} else {
core->cons->null = false;
}
}
ut8 *buf = malloc(b->size);
if (!buf) {
RZ_LOG_ERROR("core: cannot allocate %" PFMT64u " byte(s)\n", b->size);
return;
}
rz_io_read_at_mapped(core->io, b->addr, buf, b->size);
rz_core_print_disasm_json(core, b->addr, buf, b->size, 0, state->d.pj);
free(buf);
}
rz_cmd_state_output_array_end(state);
} else {
RzReg *rreg = rz_analysis_get_reg(core->analysis);
bool asm_lines = rz_config_get_i(core->config, "asm.lines.bb");
bool emu = rz_config_get_i(core->config, "asm.emu");
ut64 saved_gp = 0;
ut8 *saved_arena = NULL;
if (emu) {
saved_gp = rz_analysis_get_gp(core->analysis);
saved_arena = rz_reg_arena_peek(rreg);
}
rz_config_set_i(core->config, "asm.lines.bb", 0);
rz_pvector_foreach (f->bbs, iter) {
b = (RzAnalysisBlock *)*iter;
pr_bb(core, f, b, emu, saved_gp, saved_arena, 'I', fromHere);
}
if (emu) {
rz_analysis_set_gp(core->analysis, saved_gp);
if (saved_arena) {
rz_reg_arena_poke(rreg, saved_arena);
RZ_FREE(saved_arena);
}
}
rz_config_set_i(core->config, "asm.lines.bb", asm_lines);
}
rz_config_set_b(core->config, "asm.bb.middle", orig_bb_middle);
}
static inline char cmd_pxb_p(char input) {
return IS_PRINTABLE(input) ? input : '.';
}
static inline ut32 cmd_pxb_k(const ut8 *buffer, int x) {
return ((ut32)buffer[3 - x]) << (8 * x);
}
static void print_json_string(RzCore *core, const ut8 *block, ut32 len, RzStrEnc encoding, bool stop_at_nil, bool stop_at_unprintable) {
char *section = get_section_name(core, core->offset);
if (!section) {
return;
}
ut32 dlength = 0;
RzStrStringifyOpt opt = { 0 };
opt.buffer = block;
opt.length = len;
opt.encoding = encoding;
opt.json = true;
opt.stop_at_nil = stop_at_nil;
opt.stop_at_unprintable = stop_at_unprintable;
char *dstring = rz_str_stringify_raw_buffer(&opt, &dlength);
if (!dstring) {
free(section);
return;
}
PJ *pj = pj_new();
if (!pj) {
free(section);
free(dstring);
return;
}
const char *enc_name = rz_str_enc_as_string(encoding);
pj_o(pj);
pj_k(pj, "string");
pj_raw(pj, "\"");
pj_raw(pj, dstring);
pj_raw(pj, "\"");
pj_kn(pj, "offset", core->offset);
pj_ks(pj, "section", section);
pj_kn(pj, "length", dlength);
pj_ks(pj, "type", enc_name);
pj_end(pj);
rz_cons_println(pj_string(pj));
pj_free(pj);
free(section);
free(dstring);
}
static char *__op_refs(RzCore *core, RzAnalysisOp *op, int n) {
RzStrBuf *sb = rz_strbuf_new("");
if (n) {
// RzList *list = rz_analysis_xrefs_get_from (core->analysis, op->addr);
RzList *list = rz_analysis_xrefs_get_to(core->analysis, op->addr);
RzAnalysisXRef *xref;
RzListIter *iter;
rz_list_foreach (list, iter, xref) {
rz_strbuf_appendf(sb, "0x%08" PFMT64x " ", xref->to);
}
rz_list_free(list);
} else {
if (op->jump != UT64_MAX) {
rz_strbuf_appendf(sb, "0x%08" PFMT64x " ", op->jump);
}
if (op->fail != UT64_MAX) {
rz_strbuf_appendf(sb, "0x%08" PFMT64x " ", op->fail);
}
if (op->ptr != UT64_MAX) {
if (rz_io_is_valid_offset(core->io, op->ptr, false)) {
rz_strbuf_appendf(sb, "0x%08" PFMT64x " ", op->ptr);
}
}
}
char *res = rz_strbuf_drain(sb);
rz_str_trim(res);
return res;
}
static inline char *__refs(RzCore *core, ut64 x) {
if (!core->print->hasrefs) {
return NULL;
}
char *refs = core->print->hasrefs(core->print->user, x, RZ_OUTPUT_MODE_STANDARD);
if (RZ_STR_ISNOTEMPTY(refs)) {
rz_str_trim(refs);
} else {
RZ_FREE(refs);
}
return refs;
}
static bool cmd_pxr(RzCore *core, ut64 at, int len, RzCmdStateOutput *state, int wordsize, const char *query) {
if (!len) {
return true;
}
RzStrBuf *sb = rz_strbuf_new(NULL);
if (!sb) {
return false;
}
const ut8 *buf = core->block;
bool be = rz_asm_is_big_endian_set(core->rasm);
int end = RZ_MIN(core->blocksize, len);
int bitsize = wordsize * 8;
RzOutputMode mode = state->mode;
if (mode == RZ_OUTPUT_MODE_TABLE) {
RzTable *t = state->d.t;
rz_table_add_column(t, RZ_TABLE_COLUMN_TYPE_NUMBER, "addr");
rz_table_add_column(t, RZ_TABLE_COLUMN_TYPE_NUMBER, "value");
rz_table_add_column(t, RZ_TABLE_COLUMN_TYPE_STRING, "refs");
for (ut64 i = 0; i + wordsize < end; i += wordsize) {
ut64 addr = at + i;
ut64 val = rz_read_ble(buf + i, be, bitsize);
char *refs = __refs(core, val);
rz_table_add_rowf(t, "xxs", addr, val, refs);
RZ_FREE(refs);
}
rz_table_query(t, query);
} else if (mode == RZ_OUTPUT_MODE_JSON) {
PJ *pj = state->d.pj;
const int hex_depth = (int)rz_config_get_i(core->config, "hex.depth");
pj_a(pj);
for (ut64 i = 0; i + wordsize < end; i += wordsize) {
ut64 addr = at + i;
ut64 val = rz_read_ble(buf + i, be, bitsize);
pj_o(pj);
pj_kn(pj, "addr", addr);
pj_kn(pj, "value", val);
char *refs = __refs(core, val);
if (refs) {
char *refstr = rz_str_escape(refs);
pj_ks(pj, "refstr", rz_str_trim_head_ro(refstr));
free(refstr);
pj_k(pj, "ref");
free(rz_core_analysis_hasrefs_to_depth(core, val, pj, hex_depth));
}
pj_end(pj);
}
pj_end(pj);
} else if (mode == RZ_OUTPUT_MODE_QUIET) {
for (ut64 i = 0; i + wordsize < end; i += wordsize) {
ut64 val = rz_read_ble(buf + i, be, bitsize);
char *refs = __refs(core, val);
rz_strbuf_appendf(sb, "%s\n", refs);
}
} else if (mode == RZ_OUTPUT_MODE_STANDARD) {
char *hexdump_str = rz_core_print_hexdump_refs(core, core->offset, len, wordsize);
rz_strbuf_append(sb, hexdump_str);
free(hexdump_str);
} else {
rz_warn_if_reached();
rz_strbuf_free(sb);
return false;
}
if (mode == RZ_OUTPUT_MODE_STANDARD || mode == RZ_OUTPUT_MODE_QUIET) {
char *res = rz_strbuf_drain(sb);
rz_cons_print(res);
free(res);
} else {
rz_strbuf_free(sb);
}
return true;
}
static void core_print_2bpp_row(const ut8 *buf, bool useColor) {
const char *symbols = "#=-.";
for (ut32 i = 0, c = 0; i < 8; i++) {
if (buf[1] & ((1 << 7) >> i)) {
c = 2;
}
if (buf[0] & ((1 << 7) >> i)) {
c++;
}
if (useColor) {
char *color = "";
switch (c) {
case 0:
color = Color_BGWHITE;
break;
case 1:
color = Color_BGRED;
break;
case 2:
color = Color_BGBLUE;
break;
case 3:
color = Color_BGBLACK;
break;
}
rz_cons_printf("%s ", color);
} else {
const char ch = symbols[c % 4];
rz_cons_printf("%c%c", ch, ch);
}
c = 0;
}
}
static void core_print_2bpp_tiles(RzCore *core, ut32 tiles) {
const ut8 *buf = core->block;
bool useColor = rz_config_get_i(core->config, "scr.color") > 0;
for (ut32 i = 0; i < 8; i++) {
for (ut32 r = 0; r < tiles; r++) {
core_print_2bpp_row(buf + 2 * i + r * 16, useColor);
}
if (useColor) {
rz_cons_printf(Color_RESET "\n");
} else {
rz_cons_printf("\n");
}
}
}
static void core_print_raw_buffer(RzStrStringifyOpt *opt) {
char *str = rz_str_stringify_raw_buffer(opt, NULL);
if (str) {
rz_cons_strcat(str);
free(str);
}
}
static RzCmdStatus core_print_string_in_block(RzCore *core, bool stop_at_nil, bool stop_at_unprintable, ut32 offset, RzOutputMode mode, RzStrEnc str_encoding) {
const ut8 *buffer = core->block + offset;
const ut32 length = core->blocksize - offset;
RzStrEnc encoding = str_encoding == RZ_STRING_ENC_SETTINGS ? core->bin->str_search_cfg.string_encoding : str_encoding;
RzStrStringifyOpt opt = { 0 };
if (encoding == RZ_STRING_ENC_GUESS) {
encoding = rz_str_guess_encoding_from_buffer(buffer, length);
}
switch (mode) {
case RZ_OUTPUT_MODE_STANDARD:
opt.buffer = buffer;
opt.length = length;
opt.encoding = encoding;
opt.stop_at_nil = stop_at_nil;
opt.stop_at_unprintable = stop_at_unprintable;
opt.user_unprintable = core->bin->str_search_cfg.user_unprintable;
core_print_raw_buffer(&opt);
break;
case RZ_OUTPUT_MODE_JSON:
print_json_string(core, buffer, length, encoding, stop_at_nil, stop_at_unprintable);
break;
default:
RZ_LOG_ERROR("core: unsupported output mode\n");
return RZ_CMD_STATUS_ERROR;
}
return RZ_CMD_STATUS_OK;
}
// "ps"
RZ_IPI RzCmdStatus rz_print_string_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
bool stop_at_nil = !strcmp(argv[2], "null");
bool stop_at_unprintable = !strcmp(argv[2], "unprintable");
RzStrEnc enc = rz_str_enc_string_as_type(argv[1]);
return core_print_string_in_block(core, stop_at_nil, stop_at_unprintable, 0, mode, enc);
}
// "ps+"
RZ_IPI RzCmdStatus rz_print_string_as_libcpp_string_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
ut32 bitness = (ut32)rz_config_get_i(core->config, "asm.bits");
bool big_endian = rz_config_get_b(core->config, "cfg.bigendian");
switch (bitness) {
case 32:
/* fall-thru */
case 64:
break;
default:
RZ_LOG_ERROR("core: %u bits are not supported by %s\n", bitness, argv[0]);
return RZ_CMD_STATUS_ERROR;
}
ut32 min_size = (bitness / 8) * 3;
if (core->blocksize < 2 || core->blocksize < min_size) {
RZ_LOG_ERROR("core: the block size is too small to read string (expected at least %u but got %u bytes).\n", core->blocksize, min_size);
return RZ_CMD_STATUS_ERROR;
}
RzCmdStatus status = RZ_CMD_STATUS_ERROR;
if (*core->block & 0x1) { // "long" string
const ut8 *ptr = core->block + (bitness / 8) * 2;
ut64 old_offset = core->offset;
ut64 new_offset = rz_read_ble(ptr, big_endian, bitness);
rz_core_seek(core, new_offset, SEEK_SET);
rz_core_block_read(core);
status = core_print_string_in_block(core, true, false, 0, mode, RZ_STRING_ENC_SETTINGS);
rz_core_seek(core, old_offset, SEEK_SET);
rz_core_block_read(core);
} else {
status = core_print_string_in_block(core, true, false, 1, mode, RZ_STRING_ENC_SETTINGS);
}
return status;
}
// "psb"
RZ_IPI RzCmdStatus rz_print_strings_current_block_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
RzListIter *it = NULL;
RzDetectedString *detected = NULL;
RzBin *bin = core->bin;
RzUtilStrScanOptions scan_opt = {
.max_str_length = core->blocksize,
.min_str_length = bin->str_search_cfg.min_length,
.prefer_big_endian = false,
.check_ascii_freq = bin->str_search_cfg.check_ascii_freq,
};
RzList *found = rz_list_newf((RzListFree)rz_detected_string_free);
if (!found) {
RZ_LOG_ERROR("core: failed to allocate RzList\n");
return RZ_CMD_STATUS_ERROR;
}
if (rz_scan_strings_raw(core->block, found, &scan_opt, 0, core->blocksize, RZ_STRING_ENC_GUESS) < 0) {
rz_list_free(found);
return RZ_CMD_STATUS_ERROR;
}
rz_list_foreach (found, it, detected) {
ut64 address = core->offset + detected->addr;
if (mode != RZ_OUTPUT_MODE_QUIET) {
rz_print_offset(core->print, address, 0, 0, 0, 0, NULL);
}
RzStrEscOptions eopts = { 0 };
eopts.keep_printable = true;
char *escaped = rz_str_escape_utf8(detected->string, &eopts);
rz_cons_printf("%s", escaped);
free(escaped);
rz_cons_newline();
}
rz_list_free(found);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_first_string_current_block_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
RzDetectedString *detected = NULL;
RzBin *bin = core->bin;
RzUtilStrScanOptions scan_opt = {
.max_str_length = core->blocksize,
.min_str_length = bin->str_search_cfg.min_length,
.prefer_big_endian = false,
.check_ascii_freq = bin->str_search_cfg.check_ascii_freq,
};
RzList *found = rz_list_newf((RzListFree)rz_detected_string_free);
if (!found) {
RZ_LOG_ERROR("core: failed to allocate RzList\n");
return RZ_CMD_STATUS_ERROR;
}
if (rz_scan_strings_raw(core->block, found, &scan_opt, 0, core->blocksize, RZ_STRING_ENC_GUESS) < 0) {
rz_list_free(found);
return RZ_CMD_STATUS_ERROR;
}
detected = rz_list_first_val(found);
if (detected) {
rz_cons_memcat(detected->string, detected->size);
rz_cons_newline();
}
rz_list_free(found);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_pascal_string_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
RzStrStringifyOpt opt = { 0 };
bool big_endian = rz_config_get_b(core->config, "cfg.bigendian");
ut64 string_len = 0;
ut32 offset = 0;
if (!strcmp(argv[1], "8")) {
string_len = (ut64)core->block[0];
offset = 1;
} else if (!strcmp(argv[1], "16")) {
string_len = rz_read_ble16(core->block, big_endian);
offset = 2;
} else if (!strcmp(argv[1], "32")) {
string_len = rz_read_ble32(core->block, big_endian);
offset = 4;
} else {
string_len = rz_read_ble64(core->block, big_endian);
offset = 8;
}
if (string_len < 1) {
RZ_LOG_ERROR("core: string length is zero\n");
return RZ_CMD_STATUS_ERROR;
}
if ((string_len + offset) > core->blocksize) {
RZ_LOG_ERROR("core: string length exceeds block size\n");
return RZ_CMD_STATUS_ERROR;
}
switch (mode) {
case RZ_OUTPUT_MODE_STANDARD:
opt.buffer = core->block + offset;
opt.length = string_len;
opt.encoding = RZ_STRING_ENC_8BIT;
opt.stop_at_nil = true;
opt.stop_at_unprintable = true;
core_print_raw_buffer(&opt);
break;
case RZ_OUTPUT_MODE_JSON:
print_json_string(core, core->block + offset, string_len, RZ_STRING_ENC_8BIT, true, true);
break;
default:
RZ_LOG_ERROR("core: unsupported output mode\n");
return RZ_CMD_STATUS_ERROR;
}
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_string_wrap_width_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
int h, w = rz_cons_get_size(&h);
int colwidth = rz_config_get_i(core->config, "hex.cols") * 2;
int width = (colwidth == 32) ? w : colwidth; // w;
ut64 blocksize = core->blocksize;
ut64 len = (h * w) / 3;
rz_core_block_size(core, len);
RzStrStringifyOpt opt = { 0 };
opt.buffer = core->block;
opt.length = len;
opt.encoding = RZ_STRING_ENC_8BIT;
opt.wrap_at = width;
core_print_raw_buffer(&opt);
rz_core_block_size(core, blocksize);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_string_escaped_newlines_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
RzStrStringifyOpt opt = { 0 };
opt.buffer = core->block;
opt.length = core->blocksize;
opt.encoding = RZ_STRING_ENC_8BIT;
opt.escape_nl = true;
core_print_raw_buffer(&opt);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_string_c_cpp_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
char *str = rz_core_print_string_c_cpp(core);
if (!str) {
return RZ_CMD_STATUS_ERROR;
}
rz_cons_println(str);
free(str);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_hex_of_assembly_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
char *buf = rz_core_hex_of_assembly(core, argv[1]);
if (!buf) {
return RZ_CMD_STATUS_ERROR;
}
rz_cons_println(buf);
free(buf);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_esil_of_assembly_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
char *buf = rz_core_esil_of_assembly(core, argv[1]);
if (!buf) {
return RZ_CMD_STATUS_ERROR;
}
rz_cons_print(buf);
free(buf);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_assembly_of_hex_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
ut8 *hex = calloc(1, strlen(argv[1]) + 1);
if (!hex) {
RZ_LOG_ERROR("Fail to allocate memory\n");
return RZ_CMD_STATUS_ERROR;
}
int len = rz_hex_str2bin(argv[1], hex);
if (len < 1) {
RZ_LOG_ERROR("rz_hex_str2bin: invalid hexstr\n");
free(hex);
return RZ_CMD_STATUS_ERROR;
}
char *buf = rz_core_assembly_of_hex(core, hex, len);
free(hex);
if (!buf) {
return RZ_CMD_STATUS_ERROR;
}
rz_cons_print(buf);
free(buf);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_assembly_of_hex_alias_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
return rz_assembly_of_hex_handler(core, argc, argv, mode);
}
RZ_IPI RzCmdStatus rz_print_instructions_handler(RzCore *core, int argc, const char **argv) {
if (argc <= 1) {
RZ_LOG_ERROR("Invalid arguments\n");
return RZ_CMD_STATUS_ERROR;
}
ut64 len = rz_num_math(core->num, argv[1]);
if (len == 0) {
RZ_LOG_ERROR("The argument cannot be zero\n");
return RZ_CMD_STATUS_ERROR;
}
rz_core_print_disasm_instructions(core, len, 0);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_instructions_function_handler(RzCore *core, int argc, const char **argv) {
const RzAnalysisFunction *f = rz_analysis_get_fcn_in(core->analysis, core->offset,
RZ_ANALYSIS_FCN_TYPE_FCN | RZ_ANALYSIS_FCN_TYPE_SYM);
if (!f) {
RZ_LOG_ERROR("Cannot find function at 0x%08" PFMT64x "\n", core->offset);
return RZ_CMD_STATUS_ERROR;
}
ut64 fcn_size = rz_analysis_function_linear_size((RzAnalysisFunction *)f);
if (fcn_size == 0) {
RZ_LOG_ERROR("The function size is zero\n");
return RZ_CMD_STATUS_ERROR;
}
rz_core_print_disasm_instructions(core, fcn_size, 0);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_esil_of_hex_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
ut8 *hex = calloc(1, strlen(argv[1]) + 1);
if (!hex) {
RZ_LOG_ERROR("Fail to allocate memory\n");
return RZ_CMD_STATUS_ERROR;
}
int len = rz_hex_str2bin(argv[1], hex);
if (len < 1) {
RZ_LOG_ERROR("rz_hex_str2bin: invalid hexstr\n");
free(hex);
return RZ_CMD_STATUS_ERROR;
}
char *buf = rz_core_esil_of_hex(core, hex, len);
if (!buf) {
// rz_core_esil_of_hex outputs the error message
free(hex);
return RZ_CMD_STATUS_ERROR;
}
rz_cons_print(buf);
free(buf);
free(hex);
return RZ_CMD_STATUS_OK;
}
static int lenof(ut64 off, int two) {
char buf[64];
buf[0] = 0;
if (two) {
snprintf(buf, sizeof(buf), "+0x%" PFMT64x, off);
} else {
snprintf(buf, sizeof(buf), "0x%08" PFMT64x, off);
}
return strlen(buf);
}
RZ_API void rz_print_offset_sg(RzPrint *p, ut64 off, int invert, int offseg, int seggrn, int offdec, int delta, const char *label) {
char space[32] = {
0
};
const char *reset = p->resetbg ? Color_RESET : Color_RESET_NOBG;
bool show_color = p->flags & RZ_PRINT_FLAGS_COLOR;
if (show_color) {
const char *k = rz_cons_singleton()->context->pal.offset; // TODO etooslow. must cache
const char *inv = invert ? RZ_CONS_INVERT(true, true) : "";
if (offseg) {
ut32 s, a;
a = off & 0xffff;
s = ((off - a) >> seggrn) & 0xffff;
if (offdec) {
snprintf(space, sizeof(space), "%d:%d", s, a);
rz_cons_printf("%s%s%9s%s", k, inv, space, reset);
} else {
rz_cons_printf("%s%s%04x:%04x%s", k, inv, s, a, reset);
}
} else {
int sz = lenof(off, 0);
int sz2 = lenof(delta, 1);
if (delta > 0 || label) {
if (label) {
const int label_padding = 10;
if (delta > 0) {
char *pad = rz_str_pad(' ', sz - sz2 + label_padding);
if (offdec) {
rz_cons_printf("%s%s%s%s+%d%s", k, inv, label, reset, delta, pad);
} else {
rz_cons_printf("%s%s%s%s+0x%x%s", k, inv, label, reset, delta, pad);
}
free(pad);
} else {
char *pad = rz_str_pad(' ', sz + label_padding);
rz_cons_printf("%s%s%s%s%s", k, inv, label, reset, pad);
free(pad);
}
} else {
char *pad = rz_str_pad(' ', sz - sz2);
if (offdec) {
rz_cons_printf("%s+%d%s", pad, delta, reset);
} else {
rz_cons_printf("%s+0x%x%s", pad, delta, reset);
}
free(pad);
}
} else {
if (offdec) {
snprintf(space, sizeof(space), "%" PFMT64u, off);
rz_cons_printf("%s%s%10s%s", k, inv, space, reset);
} else {
if (p->wide_offsets) {
rz_cons_printf("%s%s0x%016" PFMT64x "%s", k, inv, off, reset);
} else {
rz_cons_printf("%s%s0x%08" PFMT64x "%s", k, inv, off, reset);
}
}
}
}
rz_cons_print(" ");
} else {
if (offseg) {
ut32 s, a;
a = off & 0xffff;
s = (off - a) >> seggrn;
if (offdec) {
snprintf(space, sizeof(space), "%d:%d", s & 0xffff, a & 0xffff);
rz_cons_printf("%9s%s", space, reset);
} else {
rz_cons_printf("%04x:%04x", s & 0xFFFF, a & 0xFFFF);
}
} else {
int sz = lenof(off, 0);
int sz2 = lenof(delta, 1);
if (delta > 0) {
char *pad = rz_str_pad(' ', sz - 5 - sz2 - 3);
if (offdec) {
rz_cons_printf("%s+%d%s", pad, delta, reset);
} else {
rz_cons_printf("%s+0x%x%s", pad, delta, reset);
}
free(pad);
} else {
if (offdec) {
snprintf(space, sizeof(space), "%" PFMT64u, off);
rz_cons_printf("%10s", space);
} else {
rz_cons_printf("0x%08" PFMT64x " ", off);
}
}
}
}
}
// TODO : move to rz_util? .. depends on rz_cons...
// XXX: dupe of rz_print_addr
RZ_API void rz_print_offset(RzPrint *p, ut64 off, int invert, int offseg, int offdec, int delta, const char *label) {
rz_print_offset_sg(p, off, invert, offseg, 4, offdec, delta, label);
}
RZ_IPI RzCmdStatus rz_print_utf8_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
return core_print_string_in_block(core, true, false, 0, mode, RZ_STRING_ENC_UTF8);
}
RZ_IPI RzCmdStatus rz_print_utf16le_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
return core_print_string_in_block(core, true, false, 0, mode, RZ_STRING_ENC_UTF16LE);
}
RZ_IPI RzCmdStatus rz_print_utf32le_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
return core_print_string_in_block(core, true, false, 0, mode, RZ_STRING_ENC_UTF32LE);
}
RZ_IPI RzCmdStatus rz_print_utf16be_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
return core_print_string_in_block(core, true, false, 0, mode, RZ_STRING_ENC_UTF16BE);
}
RZ_IPI RzCmdStatus rz_print_utf32be_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
return core_print_string_in_block(core, true, false, 0, mode, RZ_STRING_ENC_UTF32BE);
}
RZ_IPI RzCmdStatus rz_print_hexdump_annotated_handler(RzCore *core, int argc, const char **argv) {
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
if (len % 16) {
len += 16 - (len % 16);
}
annotated_hexdump(core, len);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_op_analysis_color_map_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
return bool2status(cmd_print_pxA(core, len, state->mode));
}
void print_cursor(RzPrint *p, int cur, int len, int set) {
if (rz_print_have_cursor(p, cur, len)) {
rz_cons_printf("%s", RZ_CONS_INVERT(set, 1));
}
}
RZ_IPI RzCmdStatus rz_print_hexdump_bits_handler(RzCore *core, int argc, const char **argv) {
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
if (!len) {
return RZ_CMD_STATUS_OK;
}
char buf[32];
for (int i = 0, c = 0; i < len; i++, c++) {
if (c == 0) {
ut64 ea = core->offset + i;
if (core->print->pava) {
ut64 va = rz_io_p2v(core->io, ea);
if (va != UT64_MAX) {
ea = va;
}
}
char *string = rz_print_section_str(core->print, ea);
rz_cons_print(string);
free(string);
rz_print_offset(core->print, ea, 0, 0, 0, 0, NULL);
}
rz_str_bits(buf, core->block + i, 8, NULL);
// split bits
memmove(buf + 5, buf + 4, 5);
buf[4] = 0;
print_cursor(core->print, i, 1, 1);
rz_cons_printf("%s.%s ", buf, buf + 5);
print_cursor(core->print, i, 1, 0);
if (c == 3) {
const ut8 *b = core->block + i - 3;
ut32 (*k)(const ut8 *, int) = cmd_pxb_k;
char (*p)(char) = cmd_pxb_p;
ut32 n = k(b, 0) | k(b, 1) | k(b, 2) | k(b, 3);
rz_cons_printf("0x%08x %c%c%c%c\n",
n, p(b[0]), p(b[1]), p(b[2]), p(b[3]));
c = -1;
}
}
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_hexdump_comments_handler(RzCore *core, int argc, const char **argv) {
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
return bool2status(rz_core_print_hexdump_or_hexdiff(core, RZ_OUTPUT_MODE_STANDARD, core->offset, len, true));
}
RZ_IPI RzCmdStatus rz_print_hexdump_signed_integer_common_handler(RzCore *core, int argc, const char **argv,
RzCmdStateOutput *state, ut8 n) {
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
return bool2status(rz_core_print_dump(core, state->mode, core->offset, n, len, RZ_CORE_PRINT_FORMAT_TYPE_INTEGER));
}
RZ_IPI RzCmdStatus rz_print_hexdump_signed_integer_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
return rz_print_hexdump_signed_integer_common_handler(core, argc, argv, state, 1);
}
RZ_IPI RzCmdStatus rz_print_hexdump_signed_integer2_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
return rz_print_hexdump_signed_integer_common_handler(core, argc, argv, state, 2);
}
RZ_IPI RzCmdStatus rz_print_hexdump_signed_integer4_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
return rz_print_hexdump_signed_integer_common_handler(core, argc, argv, state, 4);
}
RZ_IPI RzCmdStatus rz_print_hexdump_signed_integer8_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
return rz_print_hexdump_signed_integer_common_handler(core, argc, argv, state, 8);
}
RZ_IPI RzCmdStatus rz_print_hexdump_emoji_handler(RzCore *core, int argc, const char **argv) {
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
if (!len) {
return RZ_CMD_STATUS_OK;
}
static const char emoji[] = {
'\x8c', '\x80', '\x8c', '\x82', '\x8c', '\x85', '\x8c', '\x88',
'\x8c', '\x99', '\x8c', '\x9e', '\x8c', '\x9f', '\x8c', '\xa0',
'\x8c', '\xb0', '\x8c', '\xb1', '\x8c', '\xb2', '\x8c', '\xb3',
'\x8c', '\xb4', '\x8c', '\xb5', '\x8c', '\xb7', '\x8c', '\xb8',
'\x8c', '\xb9', '\x8c', '\xba', '\x8c', '\xbb', '\x8c', '\xbc',
'\x8c', '\xbd', '\x8c', '\xbe', '\x8c', '\xbf', '\x8d', '\x80',
'\x8d', '\x81', '\x8d', '\x82', '\x8d', '\x83', '\x8d', '\x84',
'\x8d', '\x85', '\x8d', '\x86', '\x8d', '\x87', '\x8d', '\x88',
'\x8d', '\x89', '\x8d', '\x8a', '\x8d', '\x8b', '\x8d', '\x8c',
'\x8d', '\x8d', '\x8d', '\x8e', '\x8d', '\x8f', '\x8d', '\x90',
'\x8d', '\x91', '\x8d', '\x92', '\x8d', '\x93', '\x8d', '\x94',
'\x8d', '\x95', '\x8d', '\x96', '\x8d', '\x97', '\x8d', '\x98',
'\x8d', '\x9c', '\x8d', '\x9d', '\x8d', '\x9e', '\x8d', '\x9f',
'\x8d', '\xa0', '\x8d', '\xa1', '\x8d', '\xa2', '\x8d', '\xa3',
'\x8d', '\xa4', '\x8d', '\xa5', '\x8d', '\xa6', '\x8d', '\xa7',
'\x8d', '\xa8', '\x8d', '\xa9', '\x8d', '\xaa', '\x8d', '\xab',
'\x8d', '\xac', '\x8d', '\xad', '\x8d', '\xae', '\x8d', '\xaf',
'\x8d', '\xb0', '\x8d', '\xb1', '\x8d', '\xb2', '\x8d', '\xb3',
'\x8d', '\xb4', '\x8d', '\xb5', '\x8d', '\xb6', '\x8d', '\xb7',
'\x8d', '\xb8', '\x8d', '\xb9', '\x8d', '\xba', '\x8d', '\xbb',
'\x8d', '\xbc', '\x8e', '\x80', '\x8e', '\x81', '\x8e', '\x82',
'\x8e', '\x83', '\x8e', '\x84', '\x8e', '\x85', '\x8e', '\x88',
'\x8e', '\x89', '\x8e', '\x8a', '\x8e', '\x8b', '\x8e', '\x8c',
'\x8e', '\x8d', '\x8e', '\x8e', '\x8e', '\x8f', '\x8e', '\x92',
'\x8e', '\x93', '\x8e', '\xa0', '\x8e', '\xa1', '\x8e', '\xa2',
'\x8e', '\xa3', '\x8e', '\xa4', '\x8e', '\xa5', '\x8e', '\xa6',
'\x8e', '\xa7', '\x8e', '\xa8', '\x8e', '\xa9', '\x8e', '\xaa',
'\x8e', '\xab', '\x8e', '\xac', '\x8e', '\xad', '\x8e', '\xae',
'\x8e', '\xaf', '\x8e', '\xb0', '\x8e', '\xb1', '\x8e', '\xb2',
'\x8e', '\xb3', '\x8e', '\xb4', '\x8e', '\xb5', '\x8e', '\xb7',
'\x8e', '\xb8', '\x8e', '\xb9', '\x8e', '\xba', '\x8e', '\xbb',
'\x8e', '\xbd', '\x8e', '\xbe', '\x8e', '\xbf', '\x8f', '\x80',
'\x8f', '\x81', '\x8f', '\x82', '\x8f', '\x83', '\x8f', '\x84',
'\x8f', '\x86', '\x8f', '\x87', '\x8f', '\x88', '\x8f', '\x89',
'\x8f', '\x8a', '\x90', '\x80', '\x90', '\x81', '\x90', '\x82',
'\x90', '\x83', '\x90', '\x84', '\x90', '\x85', '\x90', '\x86',
'\x90', '\x87', '\x90', '\x88', '\x90', '\x89', '\x90', '\x8a',
'\x90', '\x8b', '\x90', '\x8c', '\x90', '\x8d', '\x90', '\x8e',
'\x90', '\x8f', '\x90', '\x90', '\x90', '\x91', '\x90', '\x92',
'\x90', '\x93', '\x90', '\x94', '\x90', '\x95', '\x90', '\x96',
'\x90', '\x97', '\x90', '\x98', '\x90', '\x99', '\x90', '\x9a',
'\x90', '\x9b', '\x90', '\x9c', '\x90', '\x9d', '\x90', '\x9e',
'\x90', '\x9f', '\x90', '\xa0', '\x90', '\xa1', '\x90', '\xa2',
'\x90', '\xa3', '\x90', '\xa4', '\x90', '\xa5', '\x90', '\xa6',
'\x90', '\xa7', '\x90', '\xa8', '\x90', '\xa9', '\x90', '\xaa',
'\x90', '\xab', '\x90', '\xac', '\x90', '\xad', '\x90', '\xae',
'\x90', '\xaf', '\x90', '\xb0', '\x90', '\xb1', '\x90', '\xb2',
'\x90', '\xb3', '\x90', '\xb4', '\x90', '\xb5', '\x90', '\xb6',
'\x90', '\xb7', '\x90', '\xb8', '\x90', '\xb9', '\x90', '\xba',
'\x90', '\xbb', '\x90', '\xbc', '\x90', '\xbd', '\x90', '\xbe',
'\x91', '\x80', '\x91', '\x82', '\x91', '\x83', '\x91', '\x84',
'\x91', '\x85', '\x91', '\x86', '\x91', '\x87', '\x91', '\x88',
'\x91', '\x89', '\x91', '\x8a', '\x91', '\x8b', '\x91', '\x8c',
'\x91', '\x8d', '\x91', '\x8e', '\x91', '\x8f', '\x91', '\x90',
'\x91', '\x91', '\x91', '\x92', '\x91', '\x93', '\x91', '\x94',
'\x91', '\x95', '\x91', '\x96', '\x91', '\x97', '\x91', '\x98',
'\x91', '\x99', '\x91', '\x9a', '\x91', '\x9b', '\x91', '\x9c',
'\x91', '\x9d', '\x91', '\x9e', '\x91', '\x9f', '\x91', '\xa0',
'\x91', '\xa1', '\x91', '\xa2', '\x91', '\xa3', '\x91', '\xa4',
'\x91', '\xa5', '\x91', '\xa6', '\x91', '\xa7', '\x91', '\xa8',
'\x91', '\xa9', '\x91', '\xaa', '\x91', '\xae', '\x91', '\xaf',
'\x91', '\xba', '\x91', '\xbb', '\x91', '\xbc', '\x91', '\xbd',
'\x91', '\xbe', '\x91', '\xbf', '\x92', '\x80', '\x92', '\x81',
'\x92', '\x82', '\x92', '\x83', '\x92', '\x84', '\x92', '\x85'
};
int cols = core->print->cols;
if (cols < 1) {
cols = 1;
}
for (int i = 0; i < len; i += cols) {
rz_print_addr(core->print, core->offset + i);
for (int j = i; j < i + cols; j += 1) {
ut8 *p = (ut8 *)core->block + j;
if (j < len) {
rz_cons_printf("\xf0\x9f%c%c ", emoji[*p * 2], emoji[*p * 2 + 1]);
} else {
rz_cons_print(" ");
}
}
rz_cons_print(" ");
for (int j = i; j < len && j < i + cols; j += 1) {
ut8 *p = (ut8 *)core->block + j;
rz_print_byte(core->print, "%c", j, *p);
}
rz_cons_newline();
}
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_hexdump_function_handler(RzCore *core, int argc, const char **argv) {
RzAnalysisFunction *function = rz_analysis_get_fcn_in(core->analysis, core->offset, RZ_ANALYSIS_FCN_TYPE_ROOT);
if (!function) {
function = rz_analysis_get_fcn_in(core->analysis, core->offset, 0);
}
if (!function) {
RZ_LOG_ERROR("Cannot find function at 0x%08" PFMT64x "\n", core->offset);
return RZ_CMD_STATUS_ERROR;
}
// Disable printing header for RzPrint
int old_flags = core->print->flags;
core->print->flags &= ~RZ_PRINT_FLAGS_HEADER;
RzAnalysisBlock *b;
void **iter;
rz_pvector_foreach (function->bbs, iter) {
b = (RzAnalysisBlock *)*iter;
ut8 *buf = malloc(b->size);
if (!buf) {
RZ_LOG_ERROR("core: cannot allocate %" PFMT64u " byte(s)\n", b->size);
core->print->flags = old_flags;
return RZ_CMD_STATUS_ERROR;
}
rz_io_read_at_mapped(core->io, b->addr, buf, b->size);
rz_core_print_hexdump(core, b->addr, buf, b->size, 0, 16, 0);
free(buf);
}
core->print->flags = old_flags;
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_hexdump_hexii_handler(RzCore *core, int argc, const char **argv) {
core->print->show_offset = rz_config_get_i(core->config, "hex.offset");
rz_print_hexii(core->print, core->offset, core->block,
(int)core->blocksize, rz_config_get_i(core->config, "hex.cols"));
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_hexword_references_common_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state, int wordsize) {
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
const char *query = argc > 2 ? argv[2] : NULL;
switch (wordsize) {
case 1:
case 2:
case 4:
case 8:
cmd_pxr(core, core->offset, len, state, wordsize, query);
break;
default:
rz_warn_if_reached();
return RZ_CMD_STATUS_ERROR;
}
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_hexword_references_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
int wordsize = rz_analysis_get_address_bits(core->analysis) / 8;
return rz_print_hexword_references_common_handler(core, argc, argv, state, wordsize);
}
RZ_IPI RzCmdStatus rz_print_hexword_references_1_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
return rz_print_hexword_references_common_handler(core, argc, argv, state, 1);
}
RZ_IPI RzCmdStatus rz_print_hexword_references_2_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
return rz_print_hexword_references_common_handler(core, argc, argv, state, 2);
}
RZ_IPI RzCmdStatus rz_print_hexword_references_4_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
return rz_print_hexword_references_common_handler(core, argc, argv, state, 4);
}
RZ_IPI RzCmdStatus rz_print_hexword_references_8_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
return rz_print_hexword_references_common_handler(core, argc, argv, state, 8);
}
RZ_IPI RzCmdStatus rz_print_hexdump_sparse_handler(RzCore *core, int argc, const char **argv) {
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
if (!len) {
return RZ_CMD_STATUS_OK;
}
core->print->flags |= RZ_PRINT_FLAGS_SPARSE;
rz_core_print_hexdump(core, core->offset, core->block, len, 16, 1, 1);
core->print->flags &= (int)(((ut32)-1) & (~RZ_PRINT_FLAGS_SPARSE));
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_delta_pointer_table_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
if (!len) {
return RZ_CMD_STATUS_OK;
}
ut64 origin = argc > 2 ? rz_num_math(core->num, argv[2]) : core->offset;
// _pointer_table does rz_core_cmd with @, so it modifies core->block
// and this results in an UAF access when iterating over the jmptable
// so we do a new allocation to avoid that issue
ut8 *block = calloc(len, 1);
if (!block) {
return RZ_CMD_STATUS_ERROR;
}
memcpy(block, core->block, len);
_pointer_table(core, origin, core->offset, block, len, 4, state->mode);
free(block);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_hexdump_hexless_bytes_handler(RzCore *core, int argc, const char **argv) {
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
core->print->flags |= RZ_PRINT_FLAGS_NONHEX;
rz_core_print_hexdump(core, core->offset,
core->block, len, 8, 1, 1);
core->print->flags &= ~RZ_PRINT_FLAGS_NONHEX;
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_hexdump_hexless_words_handler(RzCore *core, int argc, const char **argv) {
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
if (!len) {
return RZ_CMD_STATUS_OK;
}
ut8 *buf = calloc(len, 4);
if (!buf) {
return RZ_CMD_STATUS_ERROR;
}
rz_io_read_at_mapped(core->io, core->offset, buf, len * 4);
core->print->flags |= RZ_PRINT_FLAGS_NONHEX;
rz_core_print_hexdump(core, core->offset, buf, len * 4, 8, 1, 1);
core->print->flags &= ~RZ_PRINT_FLAGS_NONHEX;
free(buf);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_hexdump_hexpair_bytes_handler(RzCore *core, int argc, const char **argv) {
int len = (int)rz_str_nlen((const char *)core->block, core->blocksize);
if (!len) {
return RZ_CMD_STATUS_OK;
}
rz_print_bytes(core->print, core->block, len, "%02x");
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_hexdump_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
return bool2status(rz_core_print_hexdump_or_hexdiff(core, state->mode, core->offset, len, false));
}
RZ_IPI RzCmdStatus rz_print_hexdump_n_lines_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
return bool2status(rz_core_print_hexdump_or_hexdiff(core, state->mode, core->offset, core->print->cols * len, false));
}
RZ_IPI RzCmdStatus rz_print_hexdump_hex_common_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state, ut8 n) {
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
return bool2status(rz_core_print_dump(core, state->mode, core->offset, n, len, RZ_CORE_PRINT_FORMAT_TYPE_HEXADECIMAL));
}
RZ_IPI RzCmdStatus rz_print_hexdump_hex2_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
return rz_print_hexdump_hex_common_handler(core, argc, argv, state, 2);
}
RZ_IPI RzCmdStatus rz_print_hexdump_hex4_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
return rz_print_hexdump_hex_common_handler(core, argc, argv, state, 4);
}
RZ_IPI RzCmdStatus rz_print_hexdump_hex8_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
return rz_print_hexdump_hex_common_handler(core, argc, argv, state, 8);
}
RZ_IPI RzCmdStatus rz_print_hexdump_hexl_common_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state, ut8 n) {
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
bool hex_offset = rz_config_get_b(core->config, "hex.offset");
bool quiet = state->mode == RZ_OUTPUT_MODE_QUIET || state->mode == RZ_OUTPUT_MODE_QUIETEST;
return bool2status(rz_core_print_hexdump_byline(core, !quiet && hex_offset, core->offset, len, n));
}
RZ_IPI RzCmdStatus rz_print_hexdump_hex2l_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
return rz_print_hexdump_hexl_common_handler(core, argc, argv, state, 2);
}
RZ_IPI RzCmdStatus rz_print_hexdump_hex4l_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
return rz_print_hexdump_hexl_common_handler(core, argc, argv, state, 4);
}
RZ_IPI RzCmdStatus rz_print_hexdump_hex8l_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
return rz_print_hexdump_hexl_common_handler(core, argc, argv, state, 8);
}
RZ_IPI RzCmdStatus rz_print_hexdump_oct_handler(RzCore *core, int argc, const char **argv) {
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
return bool2status(rz_core_print_dump(core, RZ_OUTPUT_MODE_STANDARD, core->offset, 1, len, RZ_CORE_PRINT_FORMAT_TYPE_OCTAL));
}
#define CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(name, type) \
RZ_IPI RzCmdStatus name(RzCore *core, int argc, const char **argv) { \
const int size = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize; \
if (size > core->blocksize_max) { \
RZ_LOG_ERROR("Size exceeds max size (%u)\n", core->blocksize_max); \
return RZ_CMD_STATUS_ERROR; \
} \
if (size <= 0) { \
RZ_LOG_ERROR("Size must be greater than 0\n"); \
return RZ_CMD_STATUS_ERROR; \
} \
char *code = rz_lang_byte_array(core->block, size, type); \
if (RZ_STR_ISNOTEMPTY(code)) { \
rz_cons_println(code); \
} \
RzCmdStatus result = code ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR; \
free(code); \
return result; \
}
#define CMD_PRINT_BYTE_ARRAY_HANDLER_ENDIAN(name, type) \
RZ_IPI RzCmdStatus name(RzCore *core, int argc, const char **argv) { \
bool big_endian = rz_config_get_b(core->config, "cfg.bigendian"); \
char *code = rz_lang_byte_array(core->block, core->blocksize, big_endian ? type##_BE : type##_LE); \
if (RZ_STR_ISNOTEMPTY(code)) { \
rz_cons_println(code); \
} \
RzCmdStatus result = code ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR; \
free(code); \
return result; \
}
CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(rz_cmd_print_byte_array_rizin_handler, RZ_LANG_BYTE_ARRAY_RIZIN);
CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(rz_cmd_print_byte_array_asm_handler, RZ_LANG_BYTE_ARRAY_ASM);
CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(rz_cmd_print_byte_array_bash_handler, RZ_LANG_BYTE_ARRAY_BASH);
CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(rz_cmd_print_byte_array_c_cpp_bytes_handler, RZ_LANG_BYTE_ARRAY_C_CPP_BYTES);
CMD_PRINT_BYTE_ARRAY_HANDLER_ENDIAN(rz_cmd_print_byte_array_c_cpp_half_word_handler, RZ_LANG_BYTE_ARRAY_C_CPP_HALFWORDS);
CMD_PRINT_BYTE_ARRAY_HANDLER_ENDIAN(rz_cmd_print_byte_array_c_cpp_word_handler, RZ_LANG_BYTE_ARRAY_C_CPP_WORDS);
CMD_PRINT_BYTE_ARRAY_HANDLER_ENDIAN(rz_cmd_print_byte_array_c_cpp_double_word_handler, RZ_LANG_BYTE_ARRAY_C_CPP_DOUBLEWORDS);
CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(rz_cmd_print_byte_array_golang_handler, RZ_LANG_BYTE_ARRAY_GOLANG);
CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(rz_cmd_print_byte_array_java_handler, RZ_LANG_BYTE_ARRAY_JAVA);
CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(rz_cmd_print_byte_array_json_handler, RZ_LANG_BYTE_ARRAY_JSON);
CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(rz_cmd_print_byte_array_kotlin_handler, RZ_LANG_BYTE_ARRAY_KOTLIN);
CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(rz_cmd_print_byte_array_nodejs_handler, RZ_LANG_BYTE_ARRAY_NODEJS);
CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(rz_cmd_print_byte_array_objc_handler, RZ_LANG_BYTE_ARRAY_OBJECTIVE_C);
CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(rz_cmd_print_byte_array_python_handler, RZ_LANG_BYTE_ARRAY_PYTHON);
CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(rz_cmd_print_byte_array_rust_handler, RZ_LANG_BYTE_ARRAY_RUST);
CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(rz_cmd_print_byte_array_swift_handler, RZ_LANG_BYTE_ARRAY_SWIFT);
CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(rz_cmd_print_byte_array_yara_handler, RZ_LANG_BYTE_ARRAY_YARA);
#undef CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL
#undef CMD_PRINT_BYTE_ARRAY_HANDLER_ENDIAN
RZ_IPI RzCmdStatus rz_cmd_print_byte_array_with_inst_handler(RzCore *core, int argc, const char **argv) {
rz_core_block_read(core);
const int size = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
if (size > core->blocksize_max) {
RZ_LOG_ERROR("Size exceeds max size (%u)\n", core->blocksize_max);
return RZ_CMD_STATUS_ERROR;
}
if (size <= 0) {
RZ_LOG_ERROR("Size must be greater 0\n");
return RZ_CMD_STATUS_ERROR;
}
char *code = rz_core_print_bytes_with_inst(core, core->block, core->offset, size);
if (!code) {
return RZ_CMD_STATUS_ERROR;
}
rz_cons_println(code);
free(code);
return RZ_CMD_STATUS_OK;
}
static void disassembly_as_table(RzTable *t, RzCore *core, ut64 addr, int n_instrs, int n_bytes) {
ut8 buffer[256];
rz_table_set_columnsf(t, "snssssss", "name", "addr", "bytes", "disasm", "comment", "esil", "refs", "xrefs");
const int minopsz = 1;
const int options = RZ_ANALYSIS_OP_MASK_BASIC | RZ_ANALYSIS_OP_MASK_HINT | RZ_ANALYSIS_OP_MASK_DISASM | RZ_ANALYSIS_OP_MASK_ESIL;
ut64 offset = addr;
ut64 inc = 0;
for (int i = 0, j = 0; rz_disasm_check_end(n_instrs, i, n_bytes, j); i++, offset += inc, j += inc) {
RzAnalysisOp *op = rz_core_analysis_op(core, offset, options);
if (!op || op->size < 1) {
i += minopsz;
inc = minopsz;
continue;
}
const char *comment = rz_meta_get_string(core->analysis, RZ_META_TYPE_COMMENT, offset);
if (!comment) {
comment = "";
}
rz_io_read_at_mapped(core->io, offset, buffer, RZ_MIN(op->size, sizeof(buffer)));
char *bytes = rz_hex_bin2strdup(buffer, op->size);
RzFlagItem *flag = rz_flag_get_i(core->flags, offset);
char *function_name = flag ? flag->name : "";
const char *esil = RZ_STRBUF_SAFEGET(&op->esil);
char *refs = __op_refs(core, op, 0);
char *xrefs = __op_refs(core, op, 1);
rz_table_add_rowf(t, "sXssssss", function_name, offset, bytes, op->mnemonic, comment, esil, refs, xrefs);
free(bytes);
free(xrefs);
free(refs);
inc = op->size;
rz_analysis_op_free(op);
}
}
static bool core_disassembly(RzCore *core, int n_bytes, int n_instrs, RzCmdStateOutput *state, bool cbytes) {
ut64 offset = rz_core_backward_offset(core, core->offset, &n_instrs, &n_bytes);
if (n_bytes == 0) {
int max_op_size = rz_analysis_archinfo(core->analysis, RZ_ANALYSIS_ARCHINFO_MAX_OP_SIZE);
if (max_op_size < 1) {
// Just assume some random default value.
max_op_size = 1;
}
n_bytes = max_op_size * n_instrs;
}
RZ_LOG_VERBOSE("disassembly at: 0x%" PFMT64x " "
"blocksize: %" PFMT32d " "
"n_bytes: %" PFMT32d " "
"n_instrs: %" PFMT32d "\n",
core->offset, core->blocksize, n_bytes, n_instrs);
RzCoreDisasmOptions disasm_options = {
.cbytes = cbytes,
};
ut8 *buf = RZ_NEWS0(ut8, n_bytes + 1);
if (!buf) {
RZ_LOG_ERROR("Failed to allocate memory\n");
return false;
}
bool ret = true;
if (!rz_io_read_at_mapped(core->io, offset, buf, n_bytes + 1)) {
// Even with an error, keep on disassembling as at least some data may be read successfully
RZ_LOG_WARN("Failed to read chunk of size 0x%" PFMT64x " at 0x%" PFMT64x " from io.\n", (ut64)(n_bytes + 1), offset);
ret = false;
}
switch (state->mode) {
case RZ_OUTPUT_MODE_STANDARD:
rz_core_print_disasm(core, offset, buf, n_bytes,
n_bytes > 0 && !n_instrs ? n_bytes : n_instrs, state, &disasm_options);
break;
case RZ_OUTPUT_MODE_TABLE:
disassembly_as_table(state->d.t, core, offset, n_instrs, n_bytes);
break;
case RZ_OUTPUT_MODE_JSON:
rz_cmd_state_output_array_start(state);
rz_core_print_disasm_json(core, offset, buf, n_bytes, n_instrs, state->d.pj);
rz_cmd_state_output_array_end(state);
break;
case RZ_OUTPUT_MODE_QUIET:
rz_core_disasm_pdi(core, n_instrs, n_bytes, 0);
break;
default:
rz_warn_if_reached();
break;
}
free(buf);
return ret;
}
RZ_IPI RzCmdStatus rz_cmd_disassembly_n_bytes_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
ut64 n_bytes = argc > 1 ? (ut64)rz_num_math(core->num, argv[1]) : core->blocksize;
if (n_bytes == 0) {
RZ_LOG_ERROR("The argument cannot be zero\n");
return RZ_CMD_STATUS_ERROR;
}
return bool2status(core_disassembly(core, n_bytes, 0, state, true));
}
RZ_IPI RzCmdStatus rz_cmd_disassembly_n_instructions_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
int n_instrs = 0;
if (argc <= 1) {
// when no arg, we always use the rows number of the terminal
// no args must be always positive, if is not we use 16
n_instrs = rz_num_get(core->num, "$r");
if (n_instrs < 1) {
n_instrs = 16;
}
} else {
n_instrs = (int)rz_num_math(core->num, argv[1]);
if (n_instrs == 0) {
RZ_LOG_ERROR("The argument cannot be zero\n");
return RZ_CMD_STATUS_ERROR;
}
}
return bool2status(core_disassembly(core, argc > 1 ? (int)core->blocksize : 0, n_instrs, state, false));
}
RZ_IPI RzCmdStatus rz_cmd_disassembly_all_possible_opcodes_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
ut64 n_bytes = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
ut8 *buffer = RZ_NEWS0(ut8, n_bytes);
RzPVector *vec = NULL;
RzCmdStatus res = RZ_CMD_STATUS_OK;
if (!buffer) {
goto fail;
}
if (!rz_io_read_at_mapped(core->io, core->offset, buffer, n_bytes)) {
goto fail;
}
vec = rz_core_disasm_all_possible_opcodes(core, buffer, core->offset, n_bytes);
if (!vec) {
goto fail;
}
bool color = rz_config_get_i(core->config, "scr.color") > 0;
void **p;
rz_cmd_state_output_array_start(state);
rz_cons_break_push(NULL, NULL);
rz_pvector_foreach (vec, p) {
RzCoreDisasmOp *op = *p;
switch (state->mode) {
case RZ_OUTPUT_MODE_STANDARD:
rz_cons_printf("0x%08" PFMT64x " %20s %s\n", op->offset, op->hex, color ? op->assembly_colored : op->assembly);
break;
case RZ_OUTPUT_MODE_JSON:
pj_o(state->d.pj);
pj_kn(state->d.pj, "addr", op->offset);
pj_ks(state->d.pj, "bytes", op->hex);
pj_ks(state->d.pj, "inst", op->assembly);
pj_end(state->d.pj);
break;
case RZ_OUTPUT_MODE_QUIET:
rz_cons_printf("%s\n", color ? op->assembly_colored : op->assembly);
break;
default:
rz_warn_if_reached();
break;
}
}
rz_cons_break_pop();
rz_cmd_state_output_array_end(state);
ret:
free(buffer);
rz_pvector_free(vec);
return res;
fail:
res = RZ_CMD_STATUS_ERROR;
goto ret;
}
RZ_IPI RzCmdStatus rz_cmd_disassembly_all_possible_opcodes_treeview_handler(RzCore *core, int argc, const char **argv) {
#define TREEVIEW_N_BYTES 28
ut8 buffer[TREEVIEW_N_BYTES];
RzPVector *vec = NULL;
RzCmdStatus res = RZ_CMD_STATUS_OK;
if (!rz_io_read_at_mapped(core->io, core->offset, buffer, TREEVIEW_N_BYTES)) {
goto fail;
}
vec = rz_core_disasm_all_possible_opcodes(core, buffer, core->offset, TREEVIEW_N_BYTES);
if (!vec) {
goto fail;
}
bool color = rz_config_get_i(core->config, "scr.color") > 0;
void **p;
int position = 0;
rz_pvector_foreach (vec, p) {
RzCoreDisasmOp *op = *p;
if (op->size < 1) {
continue;
}
int padding = position * 2;
int space = 60 - padding;
if ((position + op->size) >= 30) {
ut32 last = (30 - position) * 2;
op->hex[last - 1] = '.';
op->hex[last] = 0;
}
rz_cons_printf("0x%08" PFMT64x " %*s%*s %s\n", op->offset, padding, "", -space, op->hex, color ? op->assembly_colored : op->assembly);
position++;
}
ret:
rz_pvector_free(vec);
return res;
fail:
res = RZ_CMD_STATUS_ERROR;
goto ret;
}
RZ_IPI RzCmdStatus rz_cmd_disassembly_basic_block_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
RzAnalysisBlock *b = rz_analysis_find_most_relevant_block_in(core->analysis, core->offset);
core->num->value = 0;
if (!b) {
RZ_LOG_ERROR("Cannot find function at 0x%08" PFMT64x "\n", core->offset);
return RZ_CMD_STATUS_ERROR;
}
ut8 *block = malloc(b->size + 1);
if (!block) {
RZ_LOG_ERROR("Cannot allocate buffer\n");
return RZ_CMD_STATUS_ERROR;
}
rz_io_read_at_mapped(core->io, b->addr, block, b->size);
RzCoreDisasmOptions disasm_options = {
.cbytes = 2,
};
rz_cmd_state_output_array_start(state);
switch (state->mode) {
case RZ_OUTPUT_MODE_STANDARD:
core->num->value = rz_core_print_disasm(core, b->addr, block, b->size, 9999, state, &disasm_options);
break;
case RZ_OUTPUT_MODE_JSON:
core->num->value = 1;
rz_core_print_disasm_json(core, b->addr, block, b->size, 0, state->d.pj);
break;
default:
rz_warn_if_reached();
break;
}
rz_cmd_state_output_array_end(state);
free(block);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_disassembly_basic_block_as_text_json_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
RzAnalysisBlock *b = rz_analysis_find_most_relevant_block_in(core->analysis, core->offset);
core->num->value = 0;
if (!b) {
RZ_LOG_ERROR("Cannot find function at 0x%08" PFMT64x "\n", core->offset);
return RZ_CMD_STATUS_ERROR;
}
ut8 *block = malloc(b->size + 1);
if (!block) {
RZ_LOG_ERROR("Cannot allocate buffer\n");
return RZ_CMD_STATUS_ERROR;
}
rz_io_read_at_mapped(core->io, b->addr, block, b->size);
RzCoreDisasmOptions disasm_options = {
.cbytes = 2,
};
core->num->value = rz_core_print_disasm(core, b->addr, block, b->size, 9999, state, &disasm_options);
free(block);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_comments_in_n_instructions_handler(RzCore *core, int argc, const char **argv) {
st64 parsed = argc > 1 ? (st64)rz_num_math(core->num, argv[1]) : core->blocksize;
if (parsed > ST16_MAX || parsed < ST16_MIN) {
RZ_LOG_ERROR("the number of instructions is too big (%d < n_instrs < %d).\n", ST16_MAX, ST16_MIN);
return RZ_CMD_STATUS_ERROR;
}
int n_instrs = parsed;
if (rz_core_disasm_pdi(core, n_instrs, 0, 'C') < 0) {
return RZ_CMD_STATUS_ERROR;
}
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_disassembly_n_instructions_with_flow_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
st64 parsed = argc > 1 ? (st64)rz_num_math(core->num, argv[1]) : (core->blocksize / 4);
if (parsed > ST16_MAX || parsed < ST16_MIN) {
RZ_LOG_ERROR("the number of instructions is too big (%d < n_instrs < %d).\n", ST16_MAX, ST16_MIN);
return RZ_CMD_STATUS_ERROR;
}
int n_instrs = parsed;
// this command is going to be removed when esil will be removed.
rz_core_disasm_pde(core, n_instrs, state);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_disassembly_function_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
core->num->value = 0;
ut32 old_blocksize = core->blocksize;
RzAnalysisFunction *function = rz_analysis_get_fcn_in(core->analysis, core->offset, RZ_ANALYSIS_FCN_TYPE_ROOT);
if (!function) {
function = rz_analysis_get_fcn_in(core->analysis, core->offset, 0);
}
if (!function) {
RZ_LOG_ERROR("Cannot find function at 0x%08" PFMT64x "\n", core->offset);
return RZ_CMD_STATUS_ERROR;
}
if (state->mode == RZ_OUTPUT_MODE_JSON) {
bool ret = rz_core_print_function_disasm_json(core, function, state->d.pj);
rz_core_block_size(core, old_blocksize);
return ret ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR;
}
ut64 linear_size = rz_analysis_function_linear_size(function);
ut64 max_real_size = rz_analysis_function_realsize(function) + 4096;
if (max_real_size < linear_size) {
RZ_LOG_ERROR("Linear size differs too much from the bbsum, please use pdr instead.\n");
return RZ_CMD_STATUS_ERROR;
}
ut64 start = function->addr; // For pdf, start disassembling at the entrypoint
ut64 end = rz_analysis_function_max_addr(function);
if (end <= start) {
RZ_LOG_ERROR("Cannot print function because the end offset is less or equal to the start offset\n");
return RZ_CMD_STATUS_ERROR;
}
ut64 size = end - start;
ut8 *bytes = malloc(size);
if (!bytes) {
RZ_LOG_ERROR("Cannot allocate buffer\n");
return RZ_CMD_STATUS_ERROR;
}
(void)rz_io_read_at_mapped(core->io, start, bytes, size);
RzCoreDisasmOptions disasm_options = {
.cbytes = 1,
.function = function,
};
core->num->value = rz_core_print_disasm(core, start, bytes, size, size, state, &disasm_options);
free(bytes);
rz_core_block_size(core, old_blocksize);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_current_block_json_handler(RzCore *core, int argc, const char **argv) {
rz_return_val_if_fail(core, RZ_CMD_STATUS_ERROR);
bool enable_color = rz_config_get_i(core->config, "escr.color") != 0;
char *res = rz_print_json_indent((const char *)core->block, enable_color, " ", NULL);
if (RZ_STR_ISEMPTY(res)) {
free(res);
RZ_LOG_ERROR("Couldn't find a JSON string.\n");
return RZ_CMD_STATUS_ERROR;
} else {
rz_cons_printf("%s\n", res);
}
free(res);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_function_rzil_handler(RzCore *core, int argc, const char **argv) {
RzAnalysisFunction *f = rz_analysis_first_function_in(core->analysis, core->offset);
if (!f) {
goto exit;
}
RzIterator *ops = rz_core_analysis_op_function_iter(core, f, RZ_ANALYSIS_OP_MASK_IL);
if (!ops) {
goto exit;
}
rz_core_il_cons_print(core, ops, false, false);
rz_iterator_free(ops);
return RZ_CMD_STATUS_OK;
exit:
return RZ_CMD_STATUS_ERROR;
}
RZ_IPI RzCmdStatus rz_print_function_rzil_enriched_handler(RzCore *core, int argc, const char **argv) {
if (!rz_config_get_b(core->config, "scr.utf8")) {
RZ_LOG_ERROR("Config variable 'scr.utf8' is not set\n");
goto exit;
}
RzAnalysisFunction *f = rz_analysis_first_function_in(core->analysis, core->offset);
if (!f) {
goto exit;
}
RzIterator *ops = rz_core_analysis_op_function_iter(core, f, RZ_ANALYSIS_OP_MASK_IL);
if (!ops) {
goto exit;
}
rz_core_il_cons_print(core, ops, false, true);
rz_iterator_free(ops);
return RZ_CMD_STATUS_OK;
exit:
return RZ_CMD_STATUS_ERROR;
}
RZ_IPI RzCmdStatus rz_cmd_disassembly_function_summary_handler(RzCore *core, int argc, const char **argv) {
ut32 old_blocksize = core->blocksize;
RzAnalysisFunction *function = rz_analysis_get_fcn_in(core->analysis, core->offset, RZ_ANALYSIS_FCN_TYPE_FCN | RZ_ANALYSIS_FCN_TYPE_SYM);
if (!function) {
RZ_LOG_ERROR("cannot find function at 0x%08" PFMT64x "\n", core->offset);
return RZ_CMD_STATUS_ERROR;
}
ut32 rs = rz_analysis_function_realsize(function);
ut32 fs = rz_analysis_function_linear_size(function);
rz_core_block_size(core, RZ_MAX(rs, fs));
char *string = rz_core_print_disasm_strings(core, RZ_CORE_DISASM_STRINGS_MODE_INST, 0, function);
rz_core_block_size(core, old_blocksize);
if (!string) {
RZ_LOG_ERROR("failed summarize %" PFMT64x "\n", core->offset);
return RZ_CMD_STATUS_ERROR;
}
rz_cons_print(string);
free(string);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_disassembly_n_instrs_as_text_json_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
ut32 old_blocksize = core->blocksize;
ut64 old_offset = core->offset;
core->num->value = 0;
st64 parsed = argc > 1 ? (st64)rz_num_math(core->num, argv[1]) : 0;
if (parsed > ST16_MAX || parsed < ST16_MIN) {
RZ_LOG_ERROR("the number of instructions is too big (%d < n_instrs < %d).\n", ST16_MAX, ST16_MIN);
return RZ_CMD_STATUS_ERROR;
}
int n_instrs = parsed;
if (n_instrs < 0) {
ut64 new_offset = old_offset;
if (!rz_core_prevop_addr(core, old_offset, -n_instrs, &new_offset)) {
new_offset = rz_core_prevop_addr_force(core, old_offset, -n_instrs);
}
ut32 new_blocksize = new_offset - old_blocksize;
if (new_blocksize > old_blocksize) {
rz_core_block_size(core, new_blocksize);
}
rz_core_seek(core, new_offset, true);
} else {
rz_core_block_read(core);
}
state->mode = RZ_OUTPUT_MODE_JSON;
if (rz_cons_singleton()->is_html) {
rz_cons_singleton()->is_html = false;
rz_cons_singleton()->was_html = true;
}
RzCoreDisasmOptions disasm_options = {
.cbytes = 1,
};
core->num->value = rz_core_print_disasm(core, core->offset, core->block, core->blocksize, RZ_ABS(n_instrs), state, &disasm_options);
if (n_instrs < 0) {
rz_core_block_size(core, old_blocksize);
rz_core_seek(core, old_offset, true);
}
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_disassembly_all_methods_class_handler(RzCore *core, int argc, const char **argv) {
ut32 old_blocksize = core->blocksize;
ut64 old_offset = core->offset;
int len = 0;
ut64 at = findClassBounds(core, &len);
if (!at) {
RZ_LOG_ERROR("Cannot find class at 0x%" PFMT64x ".\n", core->offset);
return RZ_CMD_STATUS_ERROR;
}
rz_core_seek(core, at, true);
// TODO: remove this and use C api.
// on success returns 0 else negative
int ret = rz_core_cmdf(core, "pD %d", len);
rz_core_block_size(core, old_blocksize);
rz_core_seek(core, old_offset, true);
return ret >= 0 ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR;
}
RZ_IPI RzCmdStatus rz_cmd_sizes_of_n_instructions_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
ut32 old_blocksize = core->blocksize;
ut64 old_offset = core->offset;
st64 ret = 0;
st64 parsed = argc > 1 ? (st64)rz_num_math(core->num, argv[1]) : (core->blocksize / 4);
if (parsed > ST16_MAX || parsed < ST16_MIN) {
RZ_LOG_ERROR("the number of instructions is too big (%d < n_instrs < %d).\n", ST16_MAX, ST16_MIN);
return RZ_CMD_STATUS_ERROR;
}
int n_instrs = parsed;
if (n_instrs < 0) {
ut64 new_offset = old_offset;
if (!rz_core_prevop_addr(core, old_offset, -n_instrs, &new_offset)) {
new_offset = rz_core_prevop_addr_force(core, old_offset, -n_instrs);
}
ut32 new_blocksize = new_offset - old_blocksize;
if (new_blocksize > old_blocksize) {
rz_core_block_size(core, new_blocksize);
}
rz_core_seek(core, new_offset, true);
} else {
rz_core_block_read(core);
}
rz_cmd_state_output_array_start(state);
rz_cons_break_push(NULL, NULL);
for (ut32 i = 0, j = 0; i < core->blocksize && j < RZ_ABS(n_instrs); i += ret, j++) {
RzAsmOp asm_op = { 0 };
ret = rz_asm_disassemble(core->rasm, &asm_op, core->block + i, core->blocksize - i);
rz_asm_op_fini(&asm_op);
if (rz_cons_is_breaked()) {
break;
}
// be sure to return 0 when it fails to disassemble the
// instruction to uniform the output across all disassemblers.
int op_size = ret < 1 ? 0 : ret;
switch (state->mode) {
case RZ_OUTPUT_MODE_STANDARD:
rz_cons_printf("%d\n", op_size);
break;
case RZ_OUTPUT_MODE_JSON:
pj_N(state->d.pj, op_size);
break;
default:
rz_warn_if_reached();
return RZ_CMD_STATUS_ERROR;
}
if (ret < 1) {
ret = 1;
}
}
rz_cons_break_pop();
rz_cmd_state_output_array_end(state);
if (n_instrs < 0) {
rz_core_block_size(core, old_blocksize);
rz_core_seek(core, old_offset, true);
}
return RZ_CMD_STATUS_OK;
}
static void disassemble_till_return_is_found(RzCore *core, ut64 offset, ut64 limit, RzCmdStateOutput *state) {
bool src_color = rz_config_get_i(core->config, "scr.color") > 0;
const char *off_color = src_color ? rz_cons_singleton()->context->pal.b0x00 : "";
const char *ret_color = src_color ? rz_cons_singleton()->context->pal.jmp : "";
const char *end_color = src_color ? Color_RESET : "";
for (ut64 i = 0; i < limit; i++) {
RzAnalysisOp *op = rz_core_analysis_op(core, offset, RZ_ANALYSIS_OP_MASK_BASIC | RZ_ANALYSIS_OP_MASK_DISASM);
if (!op) {
return;
}
switch (state->mode) {
case RZ_OUTPUT_MODE_QUIET:
rz_cons_printf("%s%s%s\n", ret_color, op->mnemonic, end_color);
break;
case RZ_OUTPUT_MODE_STANDARD:
rz_cons_printf("%s0x%08" PFMT64x "%s %-11s%s\n", off_color, core->offset + i, ret_color, op->mnemonic, end_color);
break;
case RZ_OUTPUT_MODE_JSON:
pj_o(state->d.pj);
pj_ks(state->d.pj, "mnemonic", op->mnemonic);
pj_kn(state->d.pj, "address", core->offset + i);
pj_end(state->d.pj);
break;
default:
rz_warn_if_reached();
break;
}
if (!(op->type & (RZ_ANALYSIS_OP_TYPE_RET | RZ_ANALYSIS_OP_TYPE_UJMP))) {
rz_analysis_op_free(op);
return;
}
if (op->type == RZ_ANALYSIS_OP_TYPE_JMP) {
offset = op->jump;
} else {
offset += op->size;
}
rz_analysis_op_free(op);
}
}
RZ_IPI RzCmdStatus rz_cmd_disassemble_ropchain_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
ut64 limit = argc > 1 ? rz_num_math(core->num, argv[1]) : 1024;
if (limit > 1024) {
RZ_LOG_ERROR("the limit value exceeds the max value (1024).\n");
return RZ_CMD_STATUS_ERROR;
}
ut64 asm_bits = rz_asm_get_bits(core->rasm);
bool big_endian = rz_config_get_b(core->config, "cfg.bigendian");
bool src_color = rz_config_get_i(core->config, "scr.color") > 0;
const char *off_color = src_color ? rz_cons_singleton()->context->pal.offset : "";
const char *num_color = src_color ? rz_cons_singleton()->context->pal.num : "";
const char *end_color = src_color ? Color_RESET : "";
if (asm_bits < 64) {
asm_bits = 32;
}
ut32 asm_bytes = asm_bits / 8;
if (core->blocksize < asm_bytes) {
RZ_LOG_ERROR("block size is not enough big to host a word (needs to be >= %u bytes).\n", asm_bytes);
return RZ_CMD_STATUS_ERROR;
}
ut8 *bytes = RZ_NEWS0(ut8, core->blocksize);
if (!bytes) {
RZ_LOG_ERROR("cannot allocate buffer.\n");
return RZ_CMD_STATUS_ERROR;
}
(void)rz_io_read_at_mapped(core->io, core->offset, bytes, core->blocksize);
rz_cmd_state_output_array_start(state);
for (ut32 i = 0; i < core->blocksize - asm_bytes; i += asm_bytes) {
ut64 number = rz_read_ble(bytes + i, big_endian, asm_bits);
switch (state->mode) {
case RZ_OUTPUT_MODE_QUIET:
rz_cons_printf("%s0x%08" PFMT64x "%s %s0x%08" PFMT64x "%s\n", off_color, core->offset + i, end_color, num_color, number, end_color);
disassemble_till_return_is_found(core, core->offset + i, limit, state);
break;
case RZ_OUTPUT_MODE_STANDARD:
rz_cons_printf("[%s0x%08" PFMT64x "%s] %s0x%08" PFMT64x "%s\n", off_color, core->offset + i, end_color, num_color, number, end_color);
disassemble_till_return_is_found(core, core->offset + i, limit, state);
break;
case RZ_OUTPUT_MODE_JSON:
pj_o(state->d.pj);
pj_kn(state->d.pj, "address", core->offset + i);
pj_kn(state->d.pj, "bits", asm_bits);
pj_kn(state->d.pj, "word", number);
pj_ka(state->d.pj, "opcodes");
disassemble_till_return_is_found(core, core->offset + i, limit, state);
pj_end(state->d.pj);
pj_end(state->d.pj);
break;
default:
rz_warn_if_reached();
return RZ_CMD_STATUS_ERROR;
}
}
rz_cmd_state_output_array_end(state);
return RZ_CMD_STATUS_OK;
}
static bool core_walk_function_blocks(RzCore *core, RzAnalysisFunction *f, RzCmdStateOutput *state, char type_print, bool fromHere) {
void **iter;
RzAnalysisBlock *b = NULL;
const bool orig_bb_middle = rz_config_get_b(core->config, "asm.bb.middle");
rz_config_set_b(core->config, "asm.bb.middle", false);
if (rz_pvector_len(f->bbs) >= 1) {
ut32 fcn_size = rz_analysis_function_realsize(f);
b = rz_pvector_tail(f->bbs);
if (b->size > fcn_size) {
b->size = fcn_size;
}
}
rz_pvector_sort(f->bbs, (RzPVectorComparator)bbcmp, NULL);
if (state->mode == RZ_OUTPUT_MODE_JSON) {
rz_pvector_foreach (f->bbs, iter) {
b = (RzAnalysisBlock *)*iter;
ut8 *buf = malloc(b->size);
if (!buf) {
RZ_LOG_ERROR("cannot allocate %" PFMT64u " byte(s)\n", b->size);
return false;
}
(void)rz_io_read_at_mapped(core->io, b->addr, buf, b->size);
rz_core_print_disasm_json(core, b->addr, buf, b->size, 0, state->d.pj);
free(buf);
}
} else {
RzReg *rreg = rz_analysis_get_reg(core->analysis);
bool asm_lines = rz_config_get_i(core->config, "asm.lines.bb");
bool emu = rz_config_get_i(core->config, "asm.emu");
ut64 saved_gp = 0;
ut8 *saved_arena = NULL;
if (emu) {
saved_gp = rz_analysis_get_gp(core->analysis);
saved_arena = rz_reg_arena_peek(rreg);
}
rz_config_set_i(core->config, "asm.lines.bb", 0);
rz_pvector_foreach (f->bbs, iter) {
b = (RzAnalysisBlock *)*iter;
pr_bb(core, f, b, emu, saved_gp, saved_arena, type_print, fromHere);
}
if (emu) {
rz_analysis_set_gp(core->analysis, saved_gp);
if (saved_arena) {
rz_reg_arena_poke(rreg, saved_arena);
RZ_FREE(saved_arena);
}
}
rz_config_set_i(core->config, "asm.lines.bb", asm_lines);
}
rz_config_set_b(core->config, "asm.bb.middle", orig_bb_middle);
return true;
}
RZ_IPI RzCmdStatus rz_cmd_disassemble_recursively_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
RzAnalysisFunction *function = rz_analysis_get_fcn_in(core->analysis, core->offset, 0);
// RZ_ANALYSIS_FCN_TYPE_FCN|RZ_ANALYSIS_FCN_TYPE_SYM);
if (!function) {
RZ_LOG_ERROR("Cannot find function at 0x%08" PFMT64x "\n", core->offset);
return RZ_CMD_STATUS_ERROR;
}
rz_cmd_state_output_array_start(state);
bool ret = core_walk_function_blocks(core, function, state, 'D', false);
rz_cmd_state_output_array_end(state);
return ret ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR;
}
RZ_IPI RzCmdStatus rz_cmd_disassemble_recursively_from_current_block_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
RzAnalysisFunction *function = rz_analysis_get_fcn_in(core->analysis, core->offset, 0);
// RZ_ANALYSIS_FCN_TYPE_FCN|RZ_ANALYSIS_FCN_TYPE_SYM);
if (!function) {
RZ_LOG_ERROR("Cannot find function at 0x%08" PFMT64x "\n", core->offset);
return RZ_CMD_STATUS_ERROR;
}
rz_cmd_state_output_array_start(state);
bool ret = core_walk_function_blocks(core, function, state, 'D', true);
rz_cmd_state_output_array_end(state);
return ret ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR;
}
RZ_IPI RzCmdStatus rz_cmd_disassemble_recursively_no_function_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
ut64 old_offset = core->offset;
RzAnalysisOp aop = { 0 };
ut32 aop_type;
ut64 aop_jump;
int aop_size;
rz_cmd_state_output_array_start(state);
for (ut64 count = core->blocksize, offset = core->offset; count > 0; count--) {
rz_core_seek(core, offset, true);
rz_analysis_op_init(&aop);
int ret = rz_analysis_op(core->analysis, &aop, offset, core->block, core->blocksize, RZ_ANALYSIS_OP_MASK_BASIC);
if (ret > 0) {
aop_type = aop.type;
aop_jump = aop.jump;
aop_size = aop.size;
}
rz_analysis_op_fini(&aop);
if (ret < 1 || aop_size < 1) {
offset++;
continue;
}
core_disassembly(core, core->blocksize, 1, state, false);
switch (aop_type) {
case RZ_ANALYSIS_OP_TYPE_JMP:
offset = aop_jump;
continue;
case RZ_ANALYSIS_OP_TYPE_UCJMP:
break;
case RZ_ANALYSIS_OP_TYPE_RET:
count = 1; // stop disassembling when hitting RET
break;
default:
break;
}
offset += aop_size;
}
rz_cmd_state_output_array_end(state);
rz_core_seek(core, old_offset, true);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_disassemble_summarize_n_bytes_handler(RzCore *core, int argc, const char **argv) {
if (argc <= 1) {
RZ_LOG_ERROR("Invalid argument.\n");
return RZ_CMD_STATUS_ERROR;
}
ut64 n_bytes = rz_num_math(core->num, argv[1]);
// small patch to reuse rz_core_print_disasm_strings which
// needs to be rewritten entirely
char *string = rz_core_print_disasm_strings(core, argc > 1 ? RZ_CORE_DISASM_STRINGS_MODE_BYTES : RZ_CORE_DISASM_STRINGS_MODE_INST, n_bytes, NULL);
if (!string) {
RZ_LOG_ERROR("failed summarize bytes %" PFMT64x "\n", core->offset);
return RZ_CMD_STATUS_ERROR;
}
rz_cons_print(string);
free(string);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_disassemble_summarize_function_handler(RzCore *core, int argc, const char **argv) {
char *string = rz_core_print_disasm_strings(core, RZ_CORE_DISASM_STRINGS_MODE_FUNCTION, 0, NULL);
if (!string) {
RZ_LOG_ERROR("failed summarize function %" PFMT64x "\n", core->offset);
return RZ_CMD_STATUS_ERROR;
}
rz_cons_print(string);
free(string);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_disassemble_summarize_block_handler(RzCore *core, int argc, const char **argv) {
// small patch to reuse rz_core_print_disasm_strings which
// needs to be rewritten entirely
char *string = rz_core_print_disasm_strings(core, RZ_CORE_DISASM_STRINGS_MODE_BLOCK, 0, NULL);
if (!string) {
RZ_LOG_ERROR("failed summarize block %" PFMT64x "\n", core->offset);
return RZ_CMD_STATUS_ERROR;
}
rz_cons_print(string);
free(string);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_base64_encode_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
char *buf = rz_base64_encode_dyn((const unsigned char *)core->block, core->blocksize);
if (!buf) {
RZ_LOG_ERROR("rz_base64_encode_dyn: error\n");
return RZ_CMD_STATUS_ERROR;
}
rz_cons_println((const char *)buf);
free(buf);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_base64_decode_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
ut8 *buf = rz_base64_decode_dyn((const char *)core->block, core->blocksize);
if (!buf) {
RZ_LOG_ERROR("rz_base64_decode_dyn: error\n");
return RZ_CMD_STATUS_ERROR;
}
rz_cons_println((const char *)buf);
free(buf);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_bitstream_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
ut64 old_offset = core->offset;
st32 len = (st32)rz_num_math(core->num, argv[1]);
st32 skip = (st32)rz_num_math(core->num, argv[2]);
if (len < 0 || (!len && !skip)) {
RZ_LOG_ERROR("`len` should be a positive number\n");
return RZ_CMD_STATUS_ERROR;
} else if (skip < 0) {
RZ_LOG_ERROR("`skip` should be a positive number\n");
return RZ_CMD_STATUS_ERROR;
}
// `pb len skip` means skip <skip> bits then print <len> bits
const size_t skip_n_chars = skip & 7;
const size_t max_n_bits = ((size_t)core->blocksize) << 3;
const size_t buf_len = ((size_t)len) + (skip_n_chars ? 8 : 0);
if (buf_len > max_n_bits) {
RZ_LOG_ERROR("cannot print %" PFMT32d " bits when current block size is %" PFMTSZu " bits\n", len, max_n_bits);
return RZ_CMD_STATUS_ERROR;
}
char *buf = RZ_NEWS0(char, buf_len + 1);
if (!buf) {
RZ_LOG_ERROR("Fail to allocate memory\n");
return RZ_CMD_STATUS_ERROR;
}
if (skip > 7) {
const size_t n_bytes = (skip >> 3);
rz_core_seek(core, old_offset + n_bytes, true);
}
rz_str_bits(buf, core->block, buf_len, NULL);
if (skip_n_chars) {
// we always show `len` bits, just shifted.
// so we trim the last chars.
buf[buf_len - (8 - skip_n_chars)] = 0;
}
rz_cons_println(buf + skip_n_chars);
free(buf);
if (skip > 7) {
rz_core_seek(core, old_offset, true);
}
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_byte_bitstream_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
ut64 start = core->offset;
int len = (int)rz_num_math(core->num, argv[1]);
if (len < 0) {
start = core->offset + len;
len *= -1;
}
ut8 *bit_buf = RZ_NEWS0(ut8, len);
char *str_buf = RZ_NEWS0(char, len * 8 + 1);
if (!bit_buf || !str_buf) {
RZ_LOG_ERROR("Fail to allocate memory\n");
free(bit_buf);
free(str_buf);
return RZ_CMD_STATUS_ERROR;
}
rz_io_read_at_mapped(core->io, start, bit_buf, len);
rz_str_bits(str_buf, (const ut8 *)bit_buf, len * 8, NULL);
rz_cons_println(str_buf);
free(bit_buf);
free(str_buf);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_print_asn1_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
RzASN1Object *asn1 = rz_asn1_object_parse(core->block, core->blocksize);
if (!asn1) {
RZ_LOG_ERROR("core: Malformed object: did you supply enough data?\ntry to change the block size (see b? or @!<size>)\n");
return RZ_CMD_STATUS_ERROR;
}
char *res = rz_asn1_to_string(asn1);
rz_asn1_object_free(asn1);
if (!res) {
return RZ_CMD_STATUS_ERROR;
}
rz_cons_printf("%s", res);
free(res);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_print_asn1_structure_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
RzASN1Object *asn1 = rz_asn1_object_parse(core->block, core->blocksize);
if (!asn1) {
RZ_LOG_ERROR("core: Malformed object: did you supply enough data?\ntry to change the block size (see b? or @!<size>)\n");
return RZ_CMD_STATUS_ERROR;
}
RzStructuredData *sd = rz_asn1_to_structure(asn1, state->mode == RZ_OUTPUT_MODE_QUIET);
rz_asn1_object_free(asn1);
if (!sd) {
RZ_LOG_ERROR("core: failed to create RzStructuredData from ASN1 data.\n");
return RZ_CMD_STATUS_ERROR;
}
switch (state->mode) {
case RZ_OUTPUT_MODE_JSON:
rz_structured_data_to_pj(sd, state->d.pj);
break;
default: {
char *res = rz_structured_data_to_yaml(sd);
if (res) {
rz_cons_println(res);
free(res);
}
break;
}
}
rz_structured_data_free(sd);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_print_protobuf_standard_handler(RzCore *core, int argc, const char **argv) {
char *s = rz_protobuf_decode(core->block, core->blocksize, false);
if (!s) {
RZ_LOG_ERROR("core: Malformed object: did you supply enough data?\ntry to change the block size (see b? or @!<size>)\n");
return RZ_CMD_STATUS_ERROR;
}
rz_cons_printf("%s", s);
free(s);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_print_protobuf_verbose_handler(RzCore *core, int argc, const char **argv) {
char *s = rz_protobuf_decode(core->block, core->blocksize, true);
if (!s) {
RZ_LOG_ERROR("core: Malformed object: did you supply enough data?\ntry to change the block size (see b? or @!<size>)\n");
return RZ_CMD_STATUS_ERROR;
}
rz_cons_printf("%s", s);
free(s);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_print_pkcs7_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
RzCMS *cms = rz_pkcs7_cms_parse(core->block, core->blocksize);
if (!cms) {
RZ_LOG_ERROR("core: Malformed object: did you supply enough data?\ntry to change the block size (see b? or @!<size>)\n");
return RZ_CMD_STATUS_ERROR;
}
RzStructuredData *sd = rz_pkcs7_cms_to_structure(cms);
rz_pkcs7_cms_free(cms);
if (!sd) {
RZ_LOG_ERROR("core: failed to create RzStructuredData from CMS data.\n");
return RZ_CMD_STATUS_ERROR;
}
switch (state->mode) {
case RZ_OUTPUT_MODE_JSON:
rz_structured_data_to_pj(sd, state->d.pj);
break;
default: {
char *res = rz_structured_data_to_yaml(sd);
if (res) {
rz_cons_println(res);
free(res);
}
break;
}
}
rz_structured_data_free(sd);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_print_x509_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
RzX509Certificate *x509 = rz_x509_certificate_parse2(core->block, core->blocksize);
if (!x509) {
RZ_LOG_ERROR("core: Malformed object: did you supply enough data?\ntry to change the block size (see b? or @!<size>)\n");
return RZ_CMD_STATUS_ERROR;
}
RzStructuredData *sd = rz_x509_certificate_to_structure(x509);
rz_x509_certificate_free(x509);
if (!sd) {
RZ_LOG_ERROR("core: failed to create RzStructuredData from x509 data.\n");
return RZ_CMD_STATUS_ERROR;
}
switch (state->mode) {
case RZ_OUTPUT_MODE_JSON:
rz_structured_data_to_pj(sd, state->d.pj);
break;
default: {
char *res = rz_structured_data_to_yaml(sd);
if (res) {
rz_cons_println(res);
free(res);
}
break;
}
}
rz_structured_data_free(sd);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_print_pkcs8_pkey_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
RzPrivateKeyInfo *pki = rz_pkcs8_private_key_info_parse(core->block, core->blocksize);
if (!pki) {
RZ_LOG_ERROR("core: Malformed object: did you supply enough data?\ntry to change the block size (see b? or @!<size>)\n");
return RZ_CMD_STATUS_ERROR;
}
RzStructuredData *sd = rz_pkcs8_private_key_info_to_structure(pki);
rz_pkcs8_private_key_info_free(pki);
if (!sd) {
RZ_LOG_ERROR("core: failed to create RzStructuredData from PrivateKeyInfo data.\n");
return RZ_CMD_STATUS_ERROR;
}
switch (state->mode) {
case RZ_OUTPUT_MODE_JSON:
rz_structured_data_to_pj(sd, state->d.pj);
break;
default: {
char *res = rz_structured_data_to_yaml(sd);
if (res) {
rz_cons_println(res);
free(res);
}
break;
}
}
rz_structured_data_free(sd);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_print_axml_handler(RzCore *core, int argc, const char **argv) {
char *s = rz_axml_decode(core->block, core->blocksize);
if (!s) {
RZ_LOG_ERROR("core: Malformed object: did you supply enough data?\ntry to change the block size (see b? or @!<size>)\n");
return RZ_CMD_STATUS_ERROR;
}
rz_cons_printf("%s", s);
free(s);
return RZ_CMD_STATUS_OK;
}
typedef struct {
ut64 size;
ut64 repeat;
bool useBytes;
} PrintValueOptions;
static void print_value_single(RzCore *core, PrintValueOptions *opts, ut64 address, ut64 value, RzCmdStateOutput *state) {
switch (state->mode) {
case RZ_OUTPUT_MODE_STANDARD:
switch (opts->size) {
case 1:
rz_cons_printf("0x%02" PFMT64x "\n", value);
break;
case 2:
rz_cons_printf("0x%04" PFMT64x "\n", value);
break;
case 4:
rz_cons_printf("0x%08" PFMT64x "\n", value);
break;
case 8:
rz_cons_printf("0x%016" PFMT64x "\n", value);
break;
default:
rz_warn_if_reached();
break;
}
break;
case RZ_OUTPUT_MODE_JSON: {
// TODO: Use API instead of the command
char *str = rz_core_cmd_str(core, "ps");
rz_str_trim(str);
char *p = str;
if (p) {
while (*p) {
if (*p == '\\' && p[1] == 'x') {
memmove(p, p + 4, strlen(p + 4) + 1);
}
p++;
}
}
pj_o(state->d.pj);
pj_k(state->d.pj, "value");
switch (opts->size) {
case 1:
case 2:
pj_i(state->d.pj, value);
break;
case 4:
case 8:
pj_n(state->d.pj, value);
break;
default:
rz_warn_if_reached();
break;
}
pj_ks(state->d.pj, "string", str);
free(str);
pj_end(state->d.pj);
break;
}
default:
rz_warn_if_reached();
break;
}
}
static bool print_value(RzCore *core, PrintValueOptions *opts, RzCmdStateOutput *state) {
ut64 old_at = core->offset;
ut8 *block = core->block;
int blocksize = core->blocksize;
ut8 *block_end = core->block + blocksize;
bool big_endian = rz_config_get_b(core->config, "cfg.bigendian");
if (block + 8 >= block_end) {
RZ_LOG_ERROR("core: block is truncated.\n");
return false;
}
ut64 repeat = opts->repeat;
if (opts->useBytes && opts->size > 0 && repeat > 0) {
repeat /= opts->size;
}
ut64 at = old_at;
rz_cmd_state_output_array_start(state);
do {
rz_core_seek(core, at, false);
ut64 v = 0;
switch (opts->size) {
case 1:
v = rz_read_ble8(block);
block += opts->size;
break;
case 2:
v = rz_read_ble16(block, big_endian);
block += opts->size;
break;
case 4:
v = rz_read_ble32(block, big_endian);
block += opts->size;
break;
case 8:
v = rz_read_ble64(block, big_endian);
block += opts->size;
break;
case 0:
v = rz_read_ble64(block, big_endian);
opts->size = rz_asm_get_bits(core->rasm) / 8;
switch (opts->size) {
case 1: v &= UT8_MAX; break;
case 2: v &= UT16_MAX; break;
case 4: v &= UT32_MAX; break;
case 8: v &= UT64_MAX; break;
default: break;
}
block += opts->size;
break;
}
print_value_single(core, opts, at, v, state);
repeat--;
at += opts->size;
} while (repeat > 0);
rz_cmd_state_output_array_end(state);
rz_core_seek(core, old_at, false);
return true;
}
static RzCmdStatus print_value_size(RzCore *core, RzCmdStateOutput *state, int argc, const char **argv, ut64 size) {
int repeat = argc > 1 ? rz_num_math(NULL, argv[1]) : 1;
if (repeat <= 0) {
return RZ_CMD_STATUS_ERROR;
}
PrintValueOptions opts = {
.size = size,
.repeat = repeat,
.useBytes = false
};
return bool2status(print_value(core, &opts, state));
}
RZ_IPI RzCmdStatus rz_print_value_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
return print_value_size(core, state, argc, argv, 0);
}
RZ_IPI RzCmdStatus rz_print_value1_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
return print_value_size(core, state, argc, argv, 1);
}
RZ_IPI RzCmdStatus rz_print_value2_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
return print_value_size(core, state, argc, argv, 2);
}
RZ_IPI RzCmdStatus rz_print_value4_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
return print_value_size(core, state, argc, argv, 4);
}
RZ_IPI RzCmdStatus rz_print_value8_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
return print_value_size(core, state, argc, argv, 8);
}
RZ_IPI RzCmdStatus rz_print_url_encode_handler(RzCore *core, int argc, const char **argv) {
ut64 len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
RzStrStringifyOpt opt = { 0 };
opt.buffer = core->block;
opt.length = len;
opt.encoding = RZ_STRING_ENC_8BIT;
opt.urlencode = true;
core_print_raw_buffer(&opt);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_url_encode_wide_handler(RzCore *core, int argc, const char **argv) {
ut64 len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
RzStrStringifyOpt opt = { 0 };
opt.buffer = core->block;
opt.length = len;
opt.encoding = RZ_STRING_ENC_UTF16LE;
opt.urlencode = true;
core_print_raw_buffer(&opt);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_url_encode_zero_handler(RzCore *core, int argc, const char **argv) {
ut64 len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
RzStrStringifyOpt opt = { 0 };
opt.buffer = core->block;
opt.length = len;
opt.stop_at_nil = true;
opt.stop_at_unprintable = true;
opt.encoding = RZ_STRING_ENC_8BIT;
opt.urlencode = true;
core_print_raw_buffer(&opt);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_pattern0_handler(RzCore *core, int argc, const char **argv) {
st64 len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
if (len < 1) {
RZ_LOG_ERROR("Invalid pattern length\n");
return RZ_CMD_STATUS_ERROR;
}
for (st64 i = 0; i < len; i++) {
rz_cons_print("00");
}
rz_cons_newline();
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_pattern1_handler(RzCore *core, int argc, const char **argv) {
st8 len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
if (len < 1) {
RZ_LOG_ERROR("Invalid pattern length\n");
return RZ_CMD_STATUS_ERROR;
}
ut8 min = (core->offset & 0xff);
for (ut8 i = 0; i < len; i++) {
rz_cons_printf("%02x", i + min);
}
rz_cons_newline();
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_pattern2_handler(RzCore *core, int argc, const char **argv) {
st16 len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
if (len < 1) {
RZ_LOG_ERROR("Invalid pattern length\n");
return RZ_CMD_STATUS_ERROR;
}
// TODO: honor cfg.bigendian
ut16 min = (core->offset & 0xffff);
for (ut16 i = 0; i < len; i++) {
rz_cons_printf("%04x", i + min);
}
rz_cons_newline();
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_pattern4_handler(RzCore *core, int argc, const char **argv) {
st32 len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
if (len < 1) {
RZ_LOG_ERROR("Invalid pattern length\n");
return RZ_CMD_STATUS_ERROR;
}
// TODO: honor cfg.bigendian
ut32 min = (core->offset & UT32_MAX);
for (ut32 i = 0; i < len; i++) {
rz_cons_printf("%08" PFMT32x, i + min);
}
rz_cons_newline();
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_pattern8_handler(RzCore *core, int argc, const char **argv) {
st64 len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
if (len < 1) {
RZ_LOG_ERROR("Invalid pattern length\n");
return RZ_CMD_STATUS_ERROR;
}
// TODO: honor cfg.bigendian
ut64 min = (core->offset);
for (ut64 i = 0; i < len; i++) {
rz_cons_printf("%016" PFMT64x, i + min);
}
rz_cons_newline();
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_pattern_latin_alphabet_handler(RzCore *core, int argc, const char **argv) {
st64 len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
if (len < 1) {
RZ_LOG_ERROR("Invalid pattern length\n");
return RZ_CMD_STATUS_ERROR;
}
size_t bs = 4;
ut8 *buf = calloc(bs, 1);
if (!buf) {
RZ_LOG_ERROR("Cannot allocate buffer\n");
return RZ_CMD_STATUS_ERROR;
}
for (st64 i = 0; i < len; i++) {
incAlphaBuffer(buf, bs);
for (st64 j = 0; j < bs; j++) {
rz_cons_printf("%c", buf[j] ? buf[j] : 'A');
}
rz_cons_printf(" ");
}
rz_cons_newline();
free(buf);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_pattern_debrujin_handler(RzCore *core, int argc, const char **argv) {
st64 len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
if (len < 1) {
RZ_LOG_ERROR("Invalid pattern length\n");
return RZ_CMD_STATUS_ERROR;
}
ut8 *buf = (ut8 *)rz_debruijn_pattern(len, 0, NULL);
if (!buf) {
RZ_LOG_ERROR("Cannot generate De Brujin pattern\n");
return RZ_CMD_STATUS_ERROR;
}
for (st64 i = 0; i < len; i++) {
rz_cons_printf("%02x", buf[i]);
}
rz_cons_newline();
free(buf);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_pattern_debrujin_find_handler(RzCore *core, int argc, const char **argv) {
ut64 value = rz_num_math(core->num, argv[1]);
bool big_endian = rz_config_get_b(core->config, "cfg.bigendian");
int offset = rz_debruijn_offset(0, NULL, value, big_endian);
if (offset < 0) {
RZ_LOG_ERROR("Could not find value %" PFMT64x " in Debrujn sequence.\n", value);
return RZ_CMD_STATUS_ERROR;
}
rz_cons_printf("%d\n", offset);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_pattern_oxff_handler(RzCore *core, int argc, const char **argv) {
st64 len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
if (len < 1) {
RZ_LOG_ERROR("Invalid pattern length\n");
return RZ_CMD_STATUS_ERROR;
}
for (st64 i = 0; i < len; i++) {
rz_cons_print("ff");
}
rz_cons_newline();
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_pattern_num_handler(RzCore *core, int argc, const char **argv) {
st64 len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
if (len < 1) {
RZ_LOG_ERROR("Invalid pattern length\n");
return RZ_CMD_STATUS_ERROR;
}
size_t bs = 4;
ut8 *buf = calloc(bs, 1);
if (!buf) {
RZ_LOG_ERROR("Cannot allocate buffer\n");
return RZ_CMD_STATUS_ERROR;
}
for (st64 i = 0; i < len; i++) {
incDigitBuffer(buf, bs);
for (st64 j = 0; j < bs; j++) {
rz_cons_printf("%c", buf[j] ? buf[j] : '0');
}
rz_cons_printf(" ");
}
rz_cons_newline();
free(buf);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_operation_2swap_handler(RzCore *core, int argc, const char **argv) {
return bool2status(print_operation_transform(core, RZ_CORE_WRITE_OP_BYTESWAP2, NULL));
}
RZ_IPI RzCmdStatus rz_print_operation_4swap_handler(RzCore *core, int argc, const char **argv) {
return bool2status(print_operation_transform(core, RZ_CORE_WRITE_OP_BYTESWAP4, NULL));
}
RZ_IPI RzCmdStatus rz_print_operation_8swap_handler(RzCore *core, int argc, const char **argv) {
return bool2status(print_operation_transform(core, RZ_CORE_WRITE_OP_BYTESWAP8, NULL));
}
RZ_IPI RzCmdStatus rz_print_operation_add_handler(RzCore *core, int argc, const char **argv) {
return bool2status(print_operation_transform(core, RZ_CORE_WRITE_OP_ADD, argv[1]));
}
RZ_IPI RzCmdStatus rz_print_operation_and_handler(RzCore *core, int argc, const char **argv) {
return bool2status(print_operation_transform(core, RZ_CORE_WRITE_OP_AND, argv[1]));
}
RZ_IPI RzCmdStatus rz_print_operation_div_handler(RzCore *core, int argc, const char **argv) {
return bool2status(print_operation_transform(core, RZ_CORE_WRITE_OP_DIV, argv[1]));
}
RZ_IPI RzCmdStatus rz_print_operation_shl_handler(RzCore *core, int argc, const char **argv) {
return bool2status(print_operation_transform(core, RZ_CORE_WRITE_OP_SHIFT_LEFT, argv[1]));
}
RZ_IPI RzCmdStatus rz_print_operation_mul_handler(RzCore *core, int argc, const char **argv) {
return bool2status(print_operation_transform(core, RZ_CORE_WRITE_OP_MUL, argv[1]));
}
RZ_IPI RzCmdStatus rz_print_operation_or_handler(RzCore *core, int argc, const char **argv) {
return bool2status(print_operation_transform(core, RZ_CORE_WRITE_OP_OR, argv[1]));
}
RZ_IPI RzCmdStatus rz_print_operation_shr_handler(RzCore *core, int argc, const char **argv) {
return bool2status(print_operation_transform(core, RZ_CORE_WRITE_OP_SHIFT_RIGHT, argv[1]));
}
RZ_IPI RzCmdStatus rz_print_operation_sub_handler(RzCore *core, int argc, const char **argv) {
return bool2status(print_operation_transform(core, RZ_CORE_WRITE_OP_SUB, argv[1]));
}
RZ_IPI RzCmdStatus rz_print_operation_xor_handler(RzCore *core, int argc, const char **argv) {
return bool2status(print_operation_transform(core, RZ_CORE_WRITE_OP_XOR, argv[1]));
}
RZ_IPI RzCmdStatus rz_print_key_randomart_handler(RzCore *core, int argc, const char **argv) {
ut64 len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
if (len == 0) {
return RZ_CMD_STATUS_ERROR;
}
len = len > core->blocksize ? core->blocksize : len;
char *s = rz_hash_cfg_randomart(core->block, len, core->offset);
rz_cons_println(s);
free(s);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_key_mosaic_handler(RzCore *core, int argc, const char **argv) {
ut64 len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
if (len == 0) {
return RZ_CMD_STATUS_ERROR;
}
len = len > core->blocksize ? core->blocksize : len;
int w, h;
RzConsCanvas *c;
w = rz_cons_get_size(&h);
ut64 offset0 = core->offset;
int cols = (w / 20);
int rows = (h / 12);
int i, j;
char *s;
if (rows < 1) {
rows = 1;
}
c = rz_cons_canvas_new(w, rows * 11);
for (i = 0; i < rows; i++) {
for (j = 0; j < cols; j++) {
rz_cons_canvas_gotoxy(c, j * 20, i * 11);
core->offset += len;
rz_io_read_at_mapped(core->io, core->offset, core->block, len);
s = rz_hash_cfg_randomart(core->block, len, core->offset);
rz_cons_canvas_write(c, s);
free(s);
}
}
rz_cons_canvas_print(c);
rz_cons_canvas_free(c);
rz_io_read_at_mapped(core->io, offset0, core->block, len);
core->offset = offset0;
rz_cons_printf("\n");
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_instr_handler(RzCore *core, int argc, const char **argv) {
if (argc <= 1) {
RZ_LOG_ERROR("Invalid arguments\n");
return RZ_CMD_STATUS_ERROR;
}
ut64 N = rz_num_math(core->num, argv[1]);
if (N == 0) {
RZ_LOG_ERROR("The argument cannot be zero\n");
return RZ_CMD_STATUS_ERROR;
}
rz_core_print_disasm_instructions(core, 0, N);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_instr_opcodes_handler(RzCore *core, int argc, const char **argv) {
ut64 N = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
if (N == 0) {
return RZ_CMD_STATUS_ERROR;
}
rz_core_print_disasm_all(core, core->offset, N, N);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_instr_block_handler(RzCore *core, int argc, const char **argv) {
RzAnalysisBlock *b = rz_analysis_find_most_relevant_block_in(core->analysis, core->offset);
if (!b) {
RZ_LOG_ERROR("core: Cannot find function at 0x%08" PFMT64x "\n", core->offset);
core->num->value = 0;
return RZ_CMD_STATUS_ERROR;
}
rz_core_print_disasm_instructions(core, b->size - (core->offset - b->addr), 0);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_instr_esil_handler(RzCore *core, int argc, const char **argv) {
ut64 N = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
if (N == 0) {
return RZ_CMD_STATUS_ERROR;
}
rz_core_disasm_pdi(core, N, 0, 'e');
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_instr_function_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
if (state->mode == RZ_OUTPUT_MODE_JSON) {
return rz_cmd_disassembly_function_handler(core, argc, argv, state);
}
RzAnalysisFunction *f = rz_analysis_get_fcn_in(core->analysis, core->offset,
RZ_ANALYSIS_FCN_TYPE_FCN | RZ_ANALYSIS_FCN_TYPE_SYM);
if (!f) {
return RZ_CMD_STATUS_ERROR;
}
ut32 bsz = core->blocksize;
// int fsz = rz_analysis_function_realsize (f);
int fsz = rz_analysis_function_linear_size(f); // we want max-min here
rz_core_block_size(core, fsz);
rz_core_print_disasm_instructions(core, fsz, 0);
rz_core_block_size(core, bsz);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_calls_function_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
RzListIter *iter;
RzAnalysisXRef *xrefi;
RzList *refs = NULL;
rz_cmd_state_output_array_start(state);
// get function in current offset
RzAnalysisFunction *f = rz_analysis_get_fcn_in(core->analysis, core->offset,
RZ_ANALYSIS_FCN_TYPE_FCN | RZ_ANALYSIS_FCN_TYPE_SYM);
if (!f) {
rz_cmd_state_output_array_end(state);
return RZ_CMD_STATUS_ERROR;
}
// get all the calls of the function
refs = rz_core_analysis_fcn_get_calls(core, f);
if (rz_list_empty(refs)) {
rz_cmd_state_output_array_end(state);
rz_list_free(refs);
return RZ_CMD_STATUS_OK;
}
// store current configurations
RzConfigHold *hc = rz_config_hold_new(core->config);
rz_config_hold_var(hc, "asm.offset", NULL);
rz_config_hold_var(hc, "asm.comments", NULL);
rz_config_hold_var(hc, "asm.tabs", NULL);
rz_config_hold_var(hc, "asm.bytes", NULL);
rz_config_hold_var(hc, "emu.str", NULL);
// temporarily replace configurations
rz_config_set_i(core->config, "asm.offset", false);
rz_config_set_i(core->config, "asm.comments", false);
rz_config_set_i(core->config, "asm.tabs", 0);
rz_config_set_i(core->config, "asm.bytes", false);
rz_config_set_i(core->config, "emu.str", false);
// iterate over all call references
rz_list_foreach (refs, iter, xrefi) {
if (state->mode == RZ_OUTPUT_MODE_JSON) {
RzAnalysisFunction *f = rz_analysis_get_fcn_in(core->analysis, xrefi->to,
RZ_ANALYSIS_FCN_TYPE_FCN | RZ_ANALYSIS_FCN_TYPE_SYM);
char *dst = rz_str_newf((f ? f->name : "0x%08" PFMT64x), xrefi->to);
char *dst2 = NULL;
RzAnalysisOp *op = rz_core_analysis_op(core, xrefi->to, RZ_ANALYSIS_OP_MASK_BASIC);
RzBinReloc *rel = rz_core_getreloc(core, xrefi->to, op->size);
if (rel) {
if (rel && rel->import && rel->import->name) {
dst2 = rel->import->name;
} else if (rel && rel->symbol && rel->symbol->name) {
dst2 = rel->symbol->name;
}
} else {
dst2 = dst;
}
pj_o(state->d.pj);
pj_ks(state->d.pj, "dest", dst2);
pj_kn(state->d.pj, "addr", xrefi->to);
pj_kn(state->d.pj, "at", xrefi->from);
pj_end(state->d.pj);
rz_analysis_op_free(op);
free(dst);
} else {
ut64 off = core->offset;
rz_core_seek(core, xrefi->from, true);
core_disassembly(core, 1, 1, state, false);
rz_core_seek(core, off, true);
}
}
rz_list_free(refs);
// restore saved configuration
rz_config_hold_restore(hc);
rz_config_hold_free(hc);
rz_cmd_state_output_array_end(state);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_instr_recursive_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
RzAnalysisFunction *f = rz_analysis_get_fcn_in(core->analysis, core->offset,
RZ_ANALYSIS_FCN_TYPE_FCN | RZ_ANALYSIS_FCN_TYPE_SYM);
if (!f) {
RZ_LOG_ERROR("core: Cannot find function at 0x%08" PFMT64x "\n", core->offset);
core->num->value = 0;
return RZ_CMD_STATUS_ERROR;
}
func_walk_blocks(core, f, false, state);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_instr_recursive_at_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
RzAnalysisFunction *f = rz_analysis_get_fcn_in(core->analysis, core->offset,
RZ_ANALYSIS_FCN_TYPE_FCN | RZ_ANALYSIS_FCN_TYPE_SYM);
if (!f) {
RZ_LOG_ERROR("core: Cannot find function at 0x%08" PFMT64x "\n", core->offset);
core->num->value = 0;
return RZ_CMD_STATUS_ERROR;
}
func_walk_blocks(core, f, true, state);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_instr_until_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
const ut64 limit = argc > 1 ? rz_num_math(core->num, argv[1]) : 1024;
if (!rz_core_disasm_until_ret(core, core->offset, limit, state->mode, false, NULL)) {
return RZ_CMD_STATUS_ERROR;
}
return RZ_CMD_STATUS_OK;
}
typedef struct rz_core_analysis_stats_range_t {
RzCoreAnalysisStats *as;
ut64 from;
ut64 to;
ut64 piece;
} RzCoreAnalysisStatsRange;
static RzCoreAnalysisStatsRange *analysis_stats_range(RzCore *core, int width) {
int cols = rz_config_get_i(core->config, "hex.cols");
int w = RZ_MAX(cols, width);
ut64 from = UT64_MAX;
ut64 to = 0;
RzList *list = rz_core_get_boundaries_select(core, "search.from", "search.to", "search.in");
if (rz_list_empty(list)) {
RZ_LOG_ERROR("No range to calculate stats for.\n");
rz_list_free(list);
return NULL;
}
RzCoreAnalysisStatsRange *srange = RZ_NEW0(RzCoreAnalysisStatsRange);
if (!srange) {
rz_list_free(list);
return NULL;
}
RzListIter *iter;
RzIOMap *map;
rz_list_foreach (list, iter, map) {
ut64 f = rz_itv_begin(map->itv);
ut64 t = rz_itv_end(map->itv);
if (f < from) {
from = f;
}
if (t > to) {
to = t;
}
}
rz_list_free(list);
srange->from = from;
srange->to = to;
ut64 piece = RZ_MAX((to - from) / w, 1);
if (piece * w != to - from) {
// add 1 to compute `piece = ceil((to - from) / w)` instead
piece++;
}
srange->piece = piece;
srange->as = rz_core_analysis_get_stats(core, from, to - 1, piece);
return srange;
}
static void analysis_stats_range_free(RzCoreAnalysisStatsRange *srange) {
if (!srange) {
return;
}
rz_core_analysis_stats_free(srange->as);
free(srange);
}
static void analysis_stats_standard_info(RzCore *core, RzCoreAnalysisStatsRange *srange, RzCoreAnalysisStatsItem *sitem, ut64 blockidx, bool use_color) {
ut64 at = rz_core_analysis_stats_get_block_from(srange->as, blockidx);
ut64 ate = rz_core_analysis_stats_get_block_to(srange->as, blockidx) + 1;
if (core->offset >= at && core->offset < ate) {
rz_cons_memcat("^", 1);
} else {
RzIOMap *s = rz_io_map_get(core->io, at);
if (use_color) {
if (s) {
if (s->perm & RZ_PERM_X) {
rz_cons_print(rz_cons_singleton()->context->pal.graph_ujump);
} else {
rz_cons_print(rz_cons_singleton()->context->pal.graph_true);
}
} else {
rz_cons_print(rz_cons_singleton()->context->pal.graph_false);
}
}
if (sitem->strings > 0) {
rz_cons_memcat("z", 1);
} else if (sitem->signatures) {
rz_cons_memcat("S", 1);
} else if (sitem->imports > 0) {
rz_cons_memcat("i", 1);
} else if (sitem->symbols > 0) {
rz_cons_memcat("s", 1);
} else if (sitem->functions > 0) {
rz_cons_memcat("F", 1);
} else if (sitem->comments > 0) {
rz_cons_memcat("c", 1);
} else if (sitem->flags > 0) {
rz_cons_memcat(".", 1);
} else if (sitem->in_functions > 0) {
rz_cons_memcat("f", 1);
} else {
rz_cons_memcat("_", 1);
}
}
if (use_color) {
rz_cons_print(Color_RESET);
}
}
static void analysis_stats_json_info(RzCore *core, RzCoreAnalysisStats *as, RzCoreAnalysisStatsItem *sitem, ut64 blockidx, RzCmdStateOutput *state) {
ut64 at = rz_core_analysis_stats_get_block_from(as, blockidx);
ut64 ate = rz_core_analysis_stats_get_block_to(as, blockidx) + 1;
pj_o(state->d.pj);
if ((sitem->flags) || (sitem->functions) || (sitem->comments) || (sitem->symbols) || (sitem->perm) || (sitem->strings) || (sitem->signatures) || (sitem->imports)) {
pj_kn(state->d.pj, "offset", at);
pj_kn(state->d.pj, "size", ate - at);
}
if (sitem->flags) {
pj_ki(state->d.pj, "flags", sitem->flags);
}
if (sitem->functions) {
pj_ki(state->d.pj, "functions", sitem->functions);
}
if (sitem->in_functions) {
pj_ki(state->d.pj, "in_functions", sitem->in_functions);
}
if (sitem->comments) {
pj_ki(state->d.pj, "comments", sitem->comments);
}
if (sitem->symbols) {
pj_ki(state->d.pj, "symbols", sitem->symbols);
}
if (sitem->strings) {
pj_ki(state->d.pj, "strings", sitem->strings);
}
if (sitem->signatures) {
pj_ki(state->d.pj, "signatures", sitem->signatures);
}
if (sitem->imports) {
pj_ki(state->d.pj, "imports", sitem->imports);
}
if (sitem->perm) {
pj_ks(state->d.pj, "perm", rz_str_rwx_i(sitem->perm));
}
pj_end(state->d.pj);
}
static void analysis_stats_table_info(RzCore *core, RzCoreAnalysisStats *as, RzCoreAnalysisStatsItem *sitem, ut64 blockidx, RzCmdStateOutput *state) {
ut64 at = rz_core_analysis_stats_get_block_from(as, blockidx);
if ((sitem->flags) || (sitem->functions) || (sitem->comments) || (sitem->symbols) || (sitem->strings) || (sitem->signatures) || (sitem->imports)) {
rz_table_add_rowf(state->d.t, "xddddddd", at, sitem->flags,
sitem->functions, sitem->comments, sitem->symbols, sitem->strings, sitem->signatures, sitem->imports);
}
}
static void analysis_stats_entropy_info(RzCore *core, RzCoreAnalysisStats *as, ut64 blockidx, bool use_color) {
ut64 at = rz_core_analysis_stats_get_block_from(as, blockidx);
ut64 ate = rz_core_analysis_stats_get_block_to(as, blockidx) + 1;
ut8 *blockptr = malloc(ate - at);
if (!blockptr) {
return;
}
if (rz_io_read_at_mapped(core->io, at, blockptr, (ate - at))) {
ut8 entropy = (ut8)(rz_hash_entropy_fraction(blockptr, (ate - at)) * 255);
entropy = 9 * entropy / 200; // normalize entropy from 0 to 9
if (use_color) {
const char *color =
(entropy > 6) ? Color_BGRED : (entropy > 3) ? Color_BGGREEN
: Color_BGBLUE;
rz_cons_printf("%s%d" Color_RESET, color, entropy);
} else {
rz_cons_printf("%d", entropy);
}
}
free(blockptr);
if (use_color) {
rz_cons_print(Color_RESET);
}
}
RZ_IPI RzCmdStatus rz_print_minus_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
int width = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)(core->print->cols * 2.7);
RzCoreAnalysisStatsRange *srange = analysis_stats_range(core, width);
if (!srange) {
RZ_LOG_ERROR("Cannot find valid range for calculating the analysis information\n");
return RZ_CMD_STATUS_ERROR;
}
bool use_color = rz_config_get_i(core->config, "scr.color");
switch (state->mode) {
case RZ_OUTPUT_MODE_JSON:
pj_o(state->d.pj);
pj_kn(state->d.pj, "from", srange->from);
pj_kn(state->d.pj, "to", srange->to);
pj_ki(state->d.pj, "blocksize", srange->piece);
pj_ka(state->d.pj, "blocks");
for (size_t i = 0; i < rz_vector_len(&srange->as->blocks); i++) {
RzCoreAnalysisStatsItem *sitem = rz_vector_index_ptr(&srange->as->blocks, i);
analysis_stats_json_info(core, srange->as, sitem, i, state);
}
pj_end(state->d.pj);
pj_end(state->d.pj);
break;
case RZ_OUTPUT_MODE_STANDARD:
rz_cons_printf("0x%08" PFMT64x " [", srange->from);
for (size_t i = 0; i < rz_vector_len(&srange->as->blocks); i++) {
RzCoreAnalysisStatsItem *sitem = rz_vector_index_ptr(&srange->as->blocks, i);
analysis_stats_standard_info(core, srange, sitem, i, use_color);
}
rz_cons_printf("] 0x%08" PFMT64x "\n", srange->to);
break;
default:
rz_warn_if_reached();
break;
}
analysis_stats_range_free(srange);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_minus_entropy_handler(RzCore *core, int argc, const char **argv) {
int width = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)(core->print->cols * 2.7);
RzCoreAnalysisStatsRange *srange = analysis_stats_range(core, width);
if (!srange) {
RZ_LOG_ERROR("Cannot find valid range for calculating the analysis information\n");
return RZ_CMD_STATUS_ERROR;
}
bool use_color = rz_config_get_i(core->config, "scr.color");
rz_cons_printf("0x%08" PFMT64x " [", srange->from);
for (size_t i = 0; i < rz_vector_len(&srange->as->blocks); i++) {
analysis_stats_entropy_info(core, srange->as, i, use_color);
}
rz_cons_printf("] 0x%08" PFMT64x "\n", srange->to);
analysis_stats_range_free(srange);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_minus_table_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
int width = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)(core->print->cols * 2.7);
RzCoreAnalysisStatsRange *srange = analysis_stats_range(core, width);
if (!srange) {
RZ_LOG_ERROR("Cannot find valid range for calculating the analysis information\n");
return RZ_CMD_STATUS_ERROR;
}
rz_cmd_state_output_array_start(state);
rz_cmd_state_output_set_columnsf(state, "xddddddd", "offset", "flags", "funcs", "cmts", "syms", "str", "sigs", "imps");
state->d.t->showSum = true;
state->d.t->showFancy = true;
for (size_t i = 0; i < rz_vector_len(&srange->as->blocks); i++) {
RzCoreAnalysisStatsItem *sitem = rz_vector_index_ptr(&srange->as->blocks, i);
analysis_stats_table_info(core, srange->as, sitem, i, state);
}
rz_cmd_state_output_array_end(state);
analysis_stats_range_free(srange);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_columns_disassembly_handler(RzCore *core, int argc, const char **argv) {
int h, w = rz_cons_get_size(&h);
int colwidth = rz_config_get_i(core->config, "hex.cols") * 2.5;
if (colwidth < 1) {
colwidth = 16;
}
int i, columns = w / colwidth;
int user_rows = argc > 1 ? rz_num_math(core->num, argv[1]) : -1;
int rows = user_rows > 0 ? user_rows : h - 2;
RzConfigHold *ch = rz_config_hold_new(core->config);
rz_config_hold_var(ch, "asm.offset", "asm.bytes", NULL);
if (rz_config_get_i(core->config, "asm.minicols")) {
rz_config_set_b(core->config, "asm.offset", false);
}
rz_config_set_b(core->config, "asm.bytes", false);
RzConsCanvas *c = rz_cons_canvas_new(w, rows);
ut64 osek = core->offset;
int pos_i = 0;
c->color = rz_config_get_i(core->config, "scr.color");
for (i = 0; i < columns; i++) {
(void)rz_cons_canvas_gotoxy(c, i * (w / columns), 0);
// TODO: Use the API directly
char *cmd = rz_str_newf("pdq %d @i:%d", rows, pos_i);
char *dis = rz_core_cmd_str(core, cmd);
if (dis) {
RzList *dis_lines = rz_str_split_duplist_n(dis, "\n", 0, false);
ut32 n_lines = rz_list_length(dis_lines);
rz_list_free(dis_lines);
// If the output contains more lines than expected, do not move
// forward the whole chunk as some data will be hidden.
if (n_lines > rows) {
pos_i -= (n_lines - rows - 1);
}
rz_cons_canvas_write(c, dis);
}
free(cmd);
free(dis);
pos_i += rows;
}
rz_core_seek(core, osek, true);
rz_cons_canvas_print(c);
rz_cons_canvas_free(c);
rz_cons_printf("\n");
rz_config_hold_restore(ch);
rz_config_hold_free(ch);
return RZ_CMD_STATUS_OK;
}
static void print_stack(RzCore *core) {
RzCmdStateOutput so;
ut64 sp_addr = rz_core_reg_getv_by_role_or_name(core, "SP");
if (rz_config_get_b(core->config, "dbg.slow")) {
rz_cmd_state_output_init(&so, RZ_OUTPUT_MODE_STANDARD, core);
int wordsize = rz_analysis_get_address_bits(core->analysis) / 8;
cmd_pxr(core, sp_addr, 128, &so, wordsize, NULL);
rz_cmd_state_output_print(&so);
rz_cmd_state_output_fini(&so);
} else if (rz_config_get_b(core->config, "stack.bytes")) {
char *string = rz_core_print_hexdump_or_hexdiff_str(core, RZ_OUTPUT_MODE_STANDARD, sp_addr, 128, false);
if (!string) {
RZ_LOG_ERROR("fail to print hexdump at 0x%" PFMT64x "\n", sp_addr);
return; // TODO: free stuff
}
rz_cons_print(string);
} else if (rz_asm_is_bits(core->rasm, 64)) {
rz_core_print_dump(core, RZ_OUTPUT_MODE_STANDARD, sp_addr, 8, 128, RZ_CORE_PRINT_FORMAT_TYPE_HEXADECIMAL);
} else if (rz_asm_is_bits(core->rasm, 32)) {
rz_core_print_dump(core, RZ_OUTPUT_MODE_STANDARD, sp_addr, 4, 128, RZ_CORE_PRINT_FORMAT_TYPE_HEXADECIMAL);
}
rz_cmd_state_output_init(&so, RZ_OUTPUT_MODE_STANDARD, core);
core_disassembly(core, core->blocksize, 0, &so, false);
rz_cmd_state_output_fini(&so);
}
RZ_IPI RzCmdStatus rz_print_columns_debug_handler(RzCore *core, int argc, const char **argv) {
if (!rz_config_get_b(core->config, "cfg.debug")) {
RZ_LOG_ERROR("Command works only in debug mode\n");
return RZ_CMD_STATUS_ERROR;
}
int h, w = rz_cons_get_size(&h);
int rows = h - 2;
int obsz = core->blocksize;
int user_rows = argc > 1 ? rz_num_math(core->num, argv[1]) : -1;
if (user_rows > 0) {
rows = user_rows;
}
bool asm_minicols = rz_config_get_i(core->config, "asm.minicols");
char *o_ao = rz_str_dup(rz_config_get(core->config, "asm.offset"));
char *o_ab = rz_str_dup(rz_config_get(core->config, "asm.bytes"));
if (asm_minicols) {
// Set asm.offset and asm.bytes configs to false to avoid printing them
rz_config_set_b(core->config, "asm.offset", false);
rz_config_set_b(core->config, "asm.bytes", false);
}
rz_config_set_b(core->config, "asm.bytes", false);
RzConsCanvas *c = rz_cons_canvas_new(w, rows);
ut64 osek = core->offset;
c->color = rz_config_get_i(core->config, "scr.color");
rz_core_block_size(core, rows * 32);
// Left column
RzCmdStateOutput so;
(void)rz_cons_canvas_gotoxy(c, 0, 0);
rz_cons_push();
rz_debug_regs_args_handler(core, 0, NULL, RZ_OUTPUT_MODE_STANDARD);
rz_cons_print("\nbacktrace:\n");
rz_cmd_state_output_init(&so, RZ_OUTPUT_MODE_STANDARD, core);
rz_cmd_debug_display_bt_handler(core, 0, NULL, &so);
rz_cmd_state_output_print(&so);
rz_cmd_state_output_fini(&so);
rz_cons_canvas_write(c, rz_cons_get_buffer());
rz_cons_pop();
// Right column
(void)rz_cons_canvas_gotoxy(c, RZ_MAX(w / 3, 28), 0);
rz_cons_push();
print_stack(core);
rz_cons_canvas_write(c, rz_cons_get_buffer());
rz_cons_pop();
rz_core_block_size(core, obsz);
rz_core_seek(core, osek, true);
rz_cons_canvas_print(c);
rz_cons_canvas_free(c);
if (asm_minicols) {
rz_config_set(core->config, "asm.offset", o_ao);
rz_config_set(core->config, "asm.bytes", o_ab);
}
rz_config_set(core->config, "asm.bytes", o_ab);
free(o_ao);
free(o_ab);
rz_cons_printf("\n");
return RZ_CMD_STATUS_OK;
}
static bool print_hexdump_columns(RzCore *core, int user_rows, bool has_header, const char *xcmd) {
int h, w = rz_cons_get_size(&h);
int hex_cols = rz_config_get_i(core->config, "hex.cols");
int colwidth = hex_cols * 5;
int i, columns = w / (colwidth * 0.9);
int rows = user_rows > 0 ? user_rows : h - 2;
RzConfigHold *ch = rz_config_hold_new(core->config);
rz_config_hold_var(ch, "hex.cols", NULL);
rz_config_set_i(core->config, "hex.cols", colwidth / 5);
// Add one more line for the hexdump header
int canvas_rows = rows + (has_header ? 1 : 0);
RzConsCanvas *c = rz_cons_canvas_new(w, canvas_rows);
if (!c) {
RZ_LOG_ERROR("core: Couldn't allocate a canvas with %d rows\n", rows);
rz_config_set_i(core->config, "hex.cols", hex_cols);
return false;
}
ut64 tsek = core->offset;
c->color = rz_config_get_i(core->config, "scr.color");
int bsize = hex_cols * rows;
if (!strcmp(xcmd, "pxAl")) {
bsize *= 12;
}
for (i = 0; i < columns; i++) {
(void)rz_cons_canvas_gotoxy(c, i * (w / columns), 0);
char *cmd = rz_str_newf("%s %d @ %" PFMT64u, xcmd, bsize, tsek);
char *dis = rz_core_cmd_str(core, cmd);
if (dis) {
RzList *dis_lines = rz_str_split_duplist_n(dis, "\n", 0, false);
// Count the lines do not contain actual data and handle them for
// the next column
RzListIter *it;
char *line;
int i = 0, diff_lines = 0;
rz_list_foreach (dis_lines, it, line) {
if (line[0] == ' ' && i < canvas_rows) {
diff_lines++;
}
i++;
}
rz_list_free(dis_lines);
if (!UT64_MUL_OVFCHK(diff_lines, hex_cols)) {
tsek -= diff_lines * hex_cols;
}
rz_cons_canvas_write(c, dis);
free(dis);
}
free(cmd);
tsek += bsize;
}
rz_cons_canvas_print(c);
rz_cons_canvas_free(c);
rz_cons_printf("\n");
rz_config_hold_restore(ch);
rz_config_hold_free(ch);
return true;
}
RZ_IPI RzCmdStatus rz_print_columns_hex_annotated_handler(RzCore *core, int argc, const char **argv) {
int user_rows = argc > 1 ? rz_num_math(core->num, argv[1]) : -1;
return bool2status(print_hexdump_columns(core, user_rows, true, "pxa"));
}
RZ_IPI RzCmdStatus rz_print_columns_hex_op_colored_handler(RzCore *core, int argc, const char **argv) {
int user_rows = argc > 1 ? rz_num_math(core->num, argv[1]) : -1;
return bool2status(print_hexdump_columns(core, user_rows, false, "pxAl"));
}
RZ_IPI RzCmdStatus rz_print_columns_hex_handler(RzCore *core, int argc, const char **argv) {
int user_rows = argc > 1 ? rz_num_math(core->num, argv[1]) : -1;
return bool2status(print_hexdump_columns(core, user_rows, true, "px"));
}
RZ_IPI RzCmdStatus rz_print_columns_hex_words_handler(RzCore *core, int argc, const char **argv) {
int user_rows = argc > 1 ? rz_num_math(core->num, argv[1]) : -1;
return bool2status(print_hexdump_columns(core, user_rows, false, "pxw"));
}
RZ_IPI RzCmdStatus rz_print_equal_d_handler(RzCore *core, int argc, const char **argv) {
int min = -1, max = 0, dict = 0, range = 0;
bool histogram[256] = { 0 };
const ut8 *block = core->block;
ut32 bsz = core->blocksize;
for (size_t i = 0; i < bsz; i++) {
histogram[block[i]] = true;
}
for (size_t i = 0; i < 256; i++) {
if (histogram[i]) {
if (min == -1) {
min = i;
}
max = i;
dict++;
}
}
range = max - min;
rz_cons_printf("min: %d 0x%x\n", min, min);
rz_cons_printf("max: %d 0x%x\n", max, max);
rz_cons_printf("unique (count): %d 0x%x\n", dict, dict);
rz_cons_printf("range (max-min): %d 0x%x\n", range, range);
rz_cons_printf("size (of block): %d 0x%x\n", bsz, bsz);
return RZ_CMD_STATUS_OK;
}
typedef struct core_block_range_t {
ut64 from;
ut64 to;
ut64 totalsize;
int nblocks;
st64 blocksize;
int skipblocks;
} CoreBlockRange;
static CoreBlockRange *calculate_blocks_range(RzCore *core, ut64 from, ut64 to, ut64 totalsize, int nblocks, int skipblocks) {
if (nblocks == 0) {
return NULL;
}
CoreBlockRange *brange = RZ_NEW0(CoreBlockRange);
if (!brange) {
return NULL;
}
if (totalsize == UT64_MAX) {
if (rz_config_get_b(core->config, "cfg.debug")) {
RzDebugMap *map = rz_debug_map_get(core->dbg, core->offset);
if (map) {
brange->totalsize = map->addr_end - map->addr;
brange->from = map->addr;
}
} else {
if (core->file && core->io) {
brange->totalsize = rz_io_fd_size(core->io, core->file->fd);
if ((st64)brange->totalsize < 1) {
brange->totalsize = UT64_MAX;
}
}
if (brange->totalsize == UT64_MAX) {
RZ_LOG_ERROR("core: Cannot determine file size\n");
free(brange);
return NULL;
}
}
} else {
brange->totalsize = totalsize;
}
st64 blocksize = core->blocksize;
// If we are not in the debug mode - use only current mapped ranges
if (!rz_config_get_b(core->config, "cfg.debug")) {
RzList *boundaries = rz_core_get_boundaries_select(core, "zoom.from", "zoom.to", "zoom.in");
if (!boundaries) {
free(brange);
return NULL;
}
RzIOMap *map = rz_list_first_val(boundaries);
if (map) {
brange->from = map->itv.addr;
RzIOMap *m;
RzListIter *iter;
rz_list_foreach (boundaries, iter, m) {
brange->to = rz_itv_end(m->itv);
}
brange->totalsize = brange->to - brange->from;
} else {
brange->from = core->offset;
}
rz_list_free(boundaries);
}
if (nblocks < 1) {
brange->nblocks = brange->totalsize / blocksize;
} else {
blocksize = brange->totalsize / nblocks;
brange->nblocks = nblocks;
}
if (skipblocks > 0) {
brange->skipblocks = skipblocks;
}
brange->blocksize = blocksize;
return brange;
}
typedef enum {
HISTOGRAM_ANALYSIS_BASIC_BLOCKS,
HISTOGRAM_ANALYSIS_INVALID_INSTRUCTIONS,
HISTOGRAM_ANALYSIS_CALL_INSTRUCTIONS,
HISTOGRAM_ANALYSIS_JUMP_INSTRUCTIONS,
HISTOGRAM_ANALYSIS_PRIV_INSTRUCTIONS,
} CoreAnalysisHistogramType;
static inline void data_array_increment_element(ut8 *data, int i) {
if (data[i] < 0xff) {
data[i]++;
}
}
static bool if_aop_match_hist_type(RzAnalysisOp *op, CoreAnalysisHistogramType t) {
switch (t) {
case HISTOGRAM_ANALYSIS_BASIC_BLOCKS:
/* We do not need to check the op type in this case */
return false;
case HISTOGRAM_ANALYSIS_CALL_INSTRUCTIONS: {
switch (op->type) {
case RZ_ANALYSIS_OP_TYPE_RCALL:
case RZ_ANALYSIS_OP_TYPE_UCALL:
case RZ_ANALYSIS_OP_TYPE_CALL:
return true;
}
break;
}
case HISTOGRAM_ANALYSIS_PRIV_INSTRUCTIONS: {
if (op->family == RZ_ANALYSIS_OP_FAMILY_PRIV) {
return true;
}
switch (op->type) {
case RZ_ANALYSIS_OP_TYPE_SWI:
return true;
}
break;
}
case HISTOGRAM_ANALYSIS_INVALID_INSTRUCTIONS: {
switch (op->type) {
case RZ_ANALYSIS_OP_TYPE_TRAP:
case RZ_ANALYSIS_OP_TYPE_ILL:
return true;
}
break;
}
case HISTOGRAM_ANALYSIS_JUMP_INSTRUCTIONS: {
switch (op->type) {
case RZ_ANALYSIS_OP_TYPE_JMP:
// case RZ_ANALYSIS_OP_TYPE_RJMP:
// case RZ_ANALYSIS_OP_TYPE_UJMP:
case RZ_ANALYSIS_OP_TYPE_CJMP:
return true;
default:
break;
}
break;
}
}
return false;
}
// Counts all analysis metainformation units per block
static ut8 *analysis_stats_histogram_data(RzCore *core, CoreBlockRange *brange) {
ut8 *data = calloc(1, brange->nblocks);
if (!data) {
RZ_LOG_ERROR("core: Failed to allocate memory\n");
return NULL;
}
// FIXME: Should we just use the value from brange instead?
ut64 to = brange->from + (brange->blocksize * brange->nblocks) - 1;
if (to < brange->from) {
free(data);
return NULL;
}
RzCoreAnalysisStats *as = rz_core_analysis_get_stats(core, brange->from, to, brange->blocksize);
if (!as) {
free(data);
return NULL;
}
for (size_t i = 0; i < RZ_MIN(brange->nblocks, rz_vector_len(&as->blocks)); i++) {
int value = 0;
RzCoreAnalysisStatsItem *block = rz_vector_index_ptr(&as->blocks, i);
value += block->functions;
value += block->in_functions;
value += block->comments;
value += block->symbols;
value += block->flags;
value += block->strings;
value += block->blocks;
data[i] = RZ_MIN(255, value);
}
rz_core_analysis_stats_free(as);
return data;
}
static ut8 *analysis_histogram_data(RzCore *core, CoreBlockRange *brange, CoreAnalysisHistogramType hist_type) {
size_t j, i = 0;
ut8 *data = calloc(1, brange->nblocks);
if (!data) {
RZ_LOG_ERROR("core: Failed to allocate memory\n");
return NULL;
}
for (i = 0; i < brange->nblocks; i++) {
if (rz_cons_is_breaked()) {
break;
}
ut64 off = brange->from + (i + brange->skipblocks) * brange->blocksize;
for (j = 0; j < brange->blocksize; j++) {
if (hist_type == HISTOGRAM_ANALYSIS_BASIC_BLOCKS) {
RzAnalysisFunction *fcn = rz_analysis_get_fcn_in(core->analysis, off + j, 0);
if (fcn) {
data[i] = rz_pvector_len(fcn->bbs);
}
continue;
}
RzAnalysisOp *op = rz_core_analysis_op(core, off + j, RZ_ANALYSIS_OP_MASK_BASIC);
if (op) {
if (op->size < 1) {
// do nothing
if (hist_type == HISTOGRAM_ANALYSIS_INVALID_INSTRUCTIONS) {
data_array_increment_element(data, i);
}
} else {
if (if_aop_match_hist_type(op, hist_type)) {
data_array_increment_element(data, i);
}
}
if (op->size > 0) {
j += op->size - 1;
}
rz_analysis_op_free(op);
} else {
if (hist_type == HISTOGRAM_ANALYSIS_INVALID_INSTRUCTIONS) {
data_array_increment_element(data, i);
}
}
}
}
return data;
}
// Build an RzHistogramOptions filled from config-driven defaults.
static RzHistogramOptions default_histogram_opts(RzConfig *config, RzConsPrintablePalette *pal, ut64 offset) {
return (RzHistogramOptions){
.unicode = rz_config_get_b(config, "scr.utf8"),
.thinline = !rz_config_get_b(config, "scr.hist.block"),
.ruler = rz_config_get_b(config, "scr.hist.ruler"),
.legend = false,
.offset = rz_config_get_b(config, "hex.offset"),
.cursor = false,
.color = rz_config_get_i(config, "scr.color"),
.offpos = offset,
.curpos = 0,
.pal = pal,
};
}
static bool print_histogram(RzCore *core, RZ_NONNULL RzHistogramOptions *opts, const ut8 *data, int width, int step, bool vertical) {
bool hex_offset = rz_config_get_i(core->config, "hex.offset");
core->print->num = core->num;
if (hex_offset) {
// TODO: Currently this option doesn't affect horizontal histograms
core->print->flags |= RZ_PRINT_FLAGS_OFFSET;
} else {
core->print->flags &= ~RZ_PRINT_FLAGS_OFFSET;
}
// Compute the histogram screen size from configuration, clamped to the
// current terminal dimensions so it never overflows the screen.
int term_rows = 0;
int term_cols = rz_cons_get_size(&term_rows);
if (term_cols <= 0) {
term_cols = 80;
}
if (term_rows <= 0) {
term_rows = 24;
}
ut64 cfg_w = rz_config_get_i(core->config, "scr.hist.width");
ut64 cfg_h = rz_config_get_i(core->config, "scr.hist.height");
// Reserve a few columns/rows so the chart doesn't touch the terminal
// edge: the Y-axis ruler gutter (up to ~6 cols for " 0.00|"), the
// right-aligned X-axis end label (which would otherwise wrap when it
// lands on the very last column), the 2 X-axis ruler lines and the
// prompt that comes back on the next line.
int avail_cols = term_cols > 10 ? term_cols - 8 : term_cols;
int avail_rows = term_rows > 6 ? term_rows - 4 : term_rows;
ut32 hist_cols = (cfg_w > 0) ? (ut32)RZ_MIN((int)cfg_w, avail_cols) : 78;
ut32 hist_rows = (cfg_h > 0) ? (ut32)RZ_MIN((int)cfg_h, avail_rows) : 14;
if (cfg_w > 0 && hist_cols < 4) {
hist_cols = 4;
}
if (cfg_h > 0 && hist_rows < 2) {
hist_rows = 2;
}
if (opts->cols == 0) {
opts->cols = hist_cols;
}
if (opts->blocksize == 0 && step > 0) {
opts->blocksize = (ut64)step;
}
RzStrBuf *strbuf = vertical
? rz_histogram_vertical(opts, data, width, step)
: rz_histogram_horizontal(opts, data, width, hist_rows);
if (!strbuf) {
return false;
}
char *histogram = rz_strbuf_drain(strbuf);
rz_cons_print(histogram);
free(histogram);
return true;
}
static void showcursor(RzCore *core, int x) {
if (!x) {
int wheel = rz_config_get_i(core->config, "scr.wheel");
if (wheel) {
rz_cons_enable_mouse(true);
}
} else {
rz_cons_enable_mouse(false);
}
rz_cons_show_cursor(x);
}
// Re-read the config-driven opts fields so `:` `e scr.hist.minimap=...` (and
// scr.hist.block / scr.utf8 / hex.offset / scr.color) take effect on the next
// redraw. Scenario-specific fields (value_max, data_f, ...) are preserved.
static void refresh_visual_opts_from_config(RzCore *core, RzHistogramOptions *opts) {
if (!opts) {
return;
}
opts->unicode = rz_config_get_b(core->config, "scr.utf8");
opts->thinline = !rz_config_get_b(core->config, "scr.hist.block");
opts->minimap = rz_config_get_b(core->config, "scr.hist.minimap");
opts->offset = rz_config_get_b(core->config, "hex.offset");
opts->color = rz_config_get_i(core->config, "scr.color");
}
static RZ_OWN RzHistogramOptions *default_visual_opts(RzCore *core, ut64 offset) {
RzHistogramOptions *opts = rz_histogram_options_new();
if (!opts) {
return NULL;
}
opts->legend = false;
opts->ruler = true;
opts->offpos = offset;
opts->cursor = false;
opts->curpos = 0;
opts->pal = &core->cons->context->pal;
refresh_visual_opts_from_config(core, opts);
return opts;
}
static const char *help_msg_visual_hist[] = {
"?", "", "show this help",
"hl", "", "move cursor left / right one bar",
"+/-", "", "zoom in / out",
":cmd", "", "run a rizin command",
"q", "", "back to Visual mode (or Q / Space)",
NULL
};
static RzCmdStatus print_visual_bytes(RzCore *core, RZ_OWN RZ_NONNULL RzHistogramOptions *opts, RZ_NONNULL const ut8 *data, RZ_NONNULL CoreBlockRange *brange) {
if (!rz_cons_is_interactive()) {
RZ_LOG_ERROR("core: visual mode requires scr.interactive=true.\n");
rz_histogram_options_free(opts);
return RZ_CMD_STATUS_ERROR;
}
RzConsCanvas *can;
bool exit_histogram = false, is_error = false;
RzConfigHold *hc = rz_config_hold_new(core->config);
if (!hc) {
rz_histogram_options_free(opts);
return RZ_CMD_STATUS_ERROR;
}
rz_config_hold_var(hc, "asm.pseudo", "asm.esil", "asm.cmt.right", NULL);
int h, w = rz_cons_get_size(&h);
can = rz_cons_canvas_new(w, h);
if (!can) {
w = 80;
h = 25;
can = rz_cons_canvas_new(w, h);
if (!can) {
RZ_LOG_ERROR("core: cannot create RzCons.canvas context. Invalid screen "
"size? See scr.columns + scr.rows\n");
rz_config_hold_restore(hc);
rz_config_hold_free(hc);
rz_histogram_options_free(opts);
return RZ_CMD_STATUS_ERROR;
}
}
can->color = rz_config_get_i(core->config, "scr.color");
RzHistogramInteractive *hist = rz_histogram_interactive_new(can, opts);
if (!hist) {
rz_config_hold_restore(hc);
rz_config_hold_free(hc);
rz_cons_canvas_free(can);
rz_histogram_options_free(opts);
return RZ_CMD_STATUS_ERROR;
}
hist->size = brange->nblocks;
hist->blocksize = brange->blocksize;
int okey, key;
while (!exit_histogram && !is_error && !rz_cons_is_breaked()) {
// Re-read scr.hist.minimap / scr.hist.block / scr.utf8 / scr.color /
// hex.offset from config every iteration so that `:` + `e ...` <Enter>
// from inside the visual histogram takes effect on the next redraw.
refresh_visual_opts_from_config(core, hist->opts);
can->color = rz_config_get_i(core->config, "scr.color");
showcursor(core, false);
w = rz_cons_get_size(&h);
if (!rz_cons_canvas_resize(hist->can, w, h)) {
rz_histogram_options_free(hist->opts);
rz_config_hold_restore(hc);
rz_config_hold_free(hc);
rz_cons_canvas_free(can);
return RZ_CMD_STATUS_ERROR;
}
hist->w = w;
hist->h = h;
// Pre-fetch up to 32 bytes at the cursor for the hex preview panel;
// zero-initialised so a short or failed read simply shows zero bytes.
ut8 cursor_bytes_buf[32] = { 0 };
ut64 cursor_off = brange->from + (ut64)hist->barnumber * brange->blocksize;
rz_io_read_at_mapped(core->io, cursor_off, cursor_bytes_buf, sizeof(cursor_bytes_buf));
hist->cursor_bytes = cursor_bytes_buf;
hist->cursor_bytes_len = sizeof(cursor_bytes_buf);
RzStrBuf *str = rz_histogram_interactive_horizontal(hist, data);
hist->cursor_bytes = NULL;
hist->cursor_bytes_len = 0;
rz_cons_canvas_write(hist->can, str->ptr);
rz_strbuf_free(str);
rz_cons_canvas_print_region(hist->can);
rz_cons_newline();
rz_cons_visual_flush();
okey = rz_cons_readchar();
key = rz_cons_arrow_to_hjkl(okey);
switch (key) {
case '?': {
rz_cons_clear00();
RzStrBuf *help = rz_strbuf_new(NULL);
if (help) {
rz_core_visual_append_help(help, "Visual histogram keybindings", help_msg_visual_hist);
rz_cons_less_str(rz_strbuf_get(help), "?");
rz_strbuf_free(help);
}
break;
}
case ':':
rz_core_visual_prompt_input(core);
break;
case 'h':
hist->barnumber = (hist->barnumber > 0) ? (hist->barnumber - 1) : (brange->nblocks - 1);
break;
case 'l':
hist->barnumber = (hist->barnumber == brange->nblocks - 1) ? (0) : (hist->barnumber + 1);
break;
case '+':
rz_histogram_interactive_zoom_in(hist);
break;
case '-':
rz_histogram_interactive_zoom_out(hist);
break;
case 'q':
case 'Q':
case ' ':
exit_histogram = true;
break;
default:
break;
}
rz_cons_clear00();
}
rz_cons_break_pop();
core->cons->event_resize = NULL;
core->cons->event_data = NULL;
core->keep_asmqjmps = false;
rz_config_hold_restore(hc);
rz_config_hold_free(hc);
rz_histogram_interactive_free(hist);
rz_cons_show_cursor(true);
rz_cons_enable_mouse(false);
return RZ_CMD_STATUS_OK;
}
static CoreBlockRange *parse_args_calculate_range(RzCore *core, int argc, const char **argv) {
int nblocks = argc > 1 ? rz_num_math(core->num, argv[1]) : -1;
ut64 totalsize = argc > 2 ? rz_num_math(core->num, argv[2]) : UT64_MAX;
int skipblocks = argc > 3 ? rz_num_math(core->num, argv[3]) : -1;
CoreBlockRange *brange = calculate_blocks_range(core, 0, 0, totalsize, nblocks, skipblocks);
if (!brange) {
RZ_LOG_ERROR("Cannot calculate blocks range\n");
}
return brange;
}
static RzCmdStatus print_histogram_bytes(RzCore *core, int argc, const char **argv, bool vertical, bool isinteractive) {
CoreBlockRange *brange = parse_args_calculate_range(core, argc, argv);
if (!brange) {
return RZ_CMD_STATUS_ERROR;
}
ut8 *data = calloc(1, brange->nblocks);
// Sample one byte at the start of each block (not nblocks contiguous bytes
// from core->offset, which for blocksize > 1 rendered only the file's first
// bytes; #4431). Byte-by-byte keeps huge/sparse files cheap.
for (size_t i = 0; i < brange->nblocks; i++) {
ut64 off = brange->from + (ut64)i * brange->blocksize;
if (!rz_io_read_at_mapped(core->io, off, &data[i], 1)) {
// Render an unreadable block as a zero sample.
data[i] = 0;
}
}
if (isinteractive) {
RzHistogramOptions *opts = default_visual_opts(core, brange->from);
if (!opts) {
free(brange);
free(data);
return RZ_CMD_STATUS_ERROR;
}
opts->value_max = 255;
if (print_visual_bytes(core, opts, data, brange) != RZ_CMD_STATUS_OK) {
RZ_LOG_ERROR("Cannot generate interactive histogram\n");
free(brange);
free(data);
return RZ_CMD_STATUS_ERROR;
}
} else {
RzHistogramOptions opts = default_histogram_opts(core->config, &core->cons->context->pal, brange->from);
opts.value_max = 255;
if (!print_histogram(core, &opts, data, brange->nblocks, brange->blocksize, vertical)) {
RZ_LOG_ERROR("Cannot generate %s histogram\n", vertical ? "vertical" : "horizontal");
free(brange);
free(data);
return RZ_CMD_STATUS_ERROR;
}
}
free(brange);
free(data);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_equal_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_bytes(core, argc, argv, true, false);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_bytes(core, argc, argv, false, false);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_visual_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_bytes(core, argc, argv, false, true);
}
typedef double (*RzBlockMetricFn)(const ut8 *data, ut64 len);
/**
* \brief Configuration for the generic per-block scalar histogram (p= / p==).
*/
typedef struct {
RzBlockMetricFn fn; ///< Per-block metric (e.g. rz_hash_entropy, rz_hash_chisquare).
double range_min; ///< Lower bound of the display range (ignored when autoscale is set).
double range_max; ///< Upper bound of the display range (ignored when autoscale is set).
bool autoscale; ///< Derive the upper bound from the largest value currently in view.
int precision; ///< Number of decimals shown on the ruler labels.
} RzBlockMetricSpec;
// Generic per-block histogram for a scalar byte statistic (entropy, chi-square, index
// of coincidence, min-entropy, serial correlation, ...). The per-block value and its
// display range come from spec: bounded metrics use the fixed [range_min, range_max];
// unbounded ones (autoscale) rescale to the largest value currently in view so the
// bars stay meaningful regardless of block size.
static RzCmdStatus print_histogram_metric(RzCore *core, int argc, const char **argv, bool vertical, bool isinteractive, const RzBlockMetricSpec *spec) {
CoreBlockRange *brange = parse_args_calculate_range(core, argc, argv);
if (!brange) {
return RZ_CMD_STATUS_ERROR;
}
ut8 *data = calloc(1, brange->nblocks);
// fp metric values feed the static horizontal ruler via opts->data_f; the
// ut8 copy keeps the visual / vertical paths working.
double *fdata = RZ_NEWS0(double, brange->nblocks);
ut8 *tmp = malloc(brange->blocksize);
if (!tmp || !fdata || !data) {
RZ_LOG_ERROR("core: failed to malloc memory\n");
free(tmp);
free(fdata);
free(data);
free(brange);
return RZ_CMD_STATUS_ERROR;
}
for (size_t i = 0; i < brange->nblocks; i++) {
ut64 off = brange->from + (brange->blocksize * (i + brange->skipblocks));
rz_io_read_at_mapped(core->io, off, tmp, brange->blocksize);
fdata[i] = spec->fn(tmp, brange->blocksize);
}
free(tmp);
double vmin = spec->range_min;
double vmax = spec->range_max;
if (spec->autoscale) {
vmin = 0.0;
vmax = 0.0;
for (size_t i = 0; i < brange->nblocks; i++) {
if (fdata[i] > vmax) {
vmax = fdata[i];
}
}
if (vmax <= 0.0) {
vmax = 1.0;
}
}
double span = vmax - vmin;
if (span <= 0.0) {
span = 1.0;
}
for (size_t i = 0; i < brange->nblocks; i++) {
double q = (fdata[i] - vmin) / span;
if (q < 0.0) {
q = 0.0;
} else if (q > 1.0) {
q = 1.0;
}
data[i] = (ut8)(255 * q);
}
// Integer ruler bounds, computed without libm: floor(vmin) and ceil(vmax).
int imin = (int)vmin;
if ((double)imin > vmin) {
imin--;
}
int imax = (int)vmax;
if ((double)imax < vmax) {
imax++;
}
RzCmdStatus res = RZ_CMD_STATUS_OK;
if (isinteractive) {
RzHistogramOptions *opts = default_visual_opts(core, brange->from);
if (!opts) {
free(brange);
free(fdata);
free(data);
return RZ_CMD_STATUS_ERROR;
}
opts->value_max = 8;
opts->value_precision = 1;
opts->data_f = fdata; // visual fp path uses Shannon directly
if (print_visual_bytes(core, opts, data, brange) != RZ_CMD_STATUS_OK) {
RZ_LOG_ERROR("Cannot generate interactive histogram\n");
res = RZ_CMD_STATUS_ERROR;
}
} else {
RzHistogramOptions opts = default_histogram_opts(core->config, &core->cons->context->pal, brange->from);
opts.value_min = imin;
opts.value_max = imax;
opts.value_precision = spec->precision;
// The static horizontal path can show full-precision fp values.
if (!vertical) {
opts.data_f = fdata;
}
if (!print_histogram(core, &opts, data, brange->nblocks, brange->blocksize, vertical)) {
RZ_LOG_ERROR("Cannot generate %s histogram\n", vertical ? "vertical" : "horizontal");
res = RZ_CMD_STATUS_ERROR;
}
}
free(data);
free(fdata);
free(brange);
return res;
}
static RzCmdStatus print_histogram_entropy(RzCore *core, int argc, const char **argv, bool vertical, bool isinteractive) {
// Shannon entropy in bits-per-byte (0..8 for ut8 data).
static const RzBlockMetricSpec spec = { rz_hash_entropy, 0.0, 8.0, false, 1 };
return print_histogram_metric(core, argc, argv, vertical, isinteractive, &spec);
}
static bool print_rising_and_falling_entropy_table(RzCore *core, RzCmdStateOutput *state, CoreBlockRange *brange, ut8 *tmp, double fallingthreshold, double risingthreshold) {
bool resetFlag = 1;
st8 lastEdge = 0;
RzTable *t = state->d.t;
rz_table_add_column(t, RZ_TABLE_COLUMN_TYPE_NUMBER, "addr");
rz_table_add_column(t, RZ_TABLE_COLUMN_TYPE_NUMBER, "index");
rz_table_add_column(t, RZ_TABLE_COLUMN_TYPE_STRING, "edge_type");
rz_table_add_column(t, RZ_TABLE_COLUMN_TYPE_NUMBER, "entropy_value");
for (int i = 0; i < brange->nblocks; i++) {
ut64 off = brange->from + (brange->blocksize * (i));
if (!rz_io_read_at_mapped(core->io, off, tmp, brange->blocksize))
return false;
double data = rz_hash_entropy_fraction(tmp, brange->blocksize);
// reseting flag if goes above falling threshold and below rising threshold
if (resetFlag == 0 && lastEdge == 0 && data > fallingthreshold) {
resetFlag = 1;
} else if (resetFlag == 0 && lastEdge == 1 && data < risingthreshold) {
resetFlag = 1;
}
// if reset flag is true
// than if entopy goes above threshold printing rising entropy edge
// and if entropy goes below threshold printing falling entropy edge
if (resetFlag == 1 && data >= risingthreshold) {
// rising edge print
resetFlag = 0;
lastEdge = 1;
rz_table_add_rowf(t, "xnsf", off, i, "rising entropy edge", data);
} else if (resetFlag == 1 && data <= fallingthreshold) {
// falling edge print
resetFlag = 0;
lastEdge = 0;
rz_table_add_rowf(t, "xnsf", off, i, "falling entropy edge", data);
}
}
return true;
}
static bool print_rising_and_falling_entropy_JSON(RzCore *core, RzCmdStateOutput *state, CoreBlockRange *brange, ut8 *tmp, double fallingthreshold, double risingthreshold) {
bool resetFlag = 1;
st8 lastEdge = 0;
PJ *pj = state->d.pj;
pj_a(pj);
for (int i = 0; i < brange->nblocks; i++) {
ut64 off = brange->from + (brange->blocksize * (i));
if (!rz_io_read_at_mapped(core->io, off, tmp, brange->blocksize))
return false;
double data = rz_hash_entropy_fraction(tmp, brange->blocksize);
// reseting flag if goes above falling threshold and below rising threshold
if (resetFlag == 0 && lastEdge == 0 && data > fallingthreshold) {
resetFlag = 1;
} else if (resetFlag == 0 && lastEdge == 1 && data < risingthreshold) {
resetFlag = 1;
}
// if reset flag is true
// than if entopy goes above threshold printing rising entropy edge
// and if entropy goes below threshold printing falling entropy edge
if (resetFlag == 1 && data >= risingthreshold) {
// rising edge print
resetFlag = 0;
lastEdge = 1;
pj_o(pj);
pj_kn(pj, "addr", off);
pj_kn(pj, "index", i);
pj_ks(pj, "edge_type", "rising entropy edge");
pj_kd(pj, "entropy_value", data);
pj_end(pj);
} else if (resetFlag == 1 && data <= fallingthreshold) {
// falling edge print
resetFlag = 0;
lastEdge = 0;
pj_o(pj);
pj_kn(pj, "addr", off);
pj_kn(pj, "index", i);
pj_ks(pj, "edge_type", "falling entropy edge");
pj_kd(pj, "entropy_value", data);
pj_end(pj);
}
}
pj_end(pj);
return true;
}
static bool print_rising_and_falling_entropy_quiet(RzCore *core, CoreBlockRange *brange, ut8 *tmp, double fallingthreshold, double risingthreshold) {
RzStrBuf *buf = rz_strbuf_new("");
if (!buf) {
RZ_LOG_ERROR("core: failed to malloc memory\n");
return false;
}
bool resetFlag = 1;
st8 lastEdge = 0;
for (int i = 0; i < brange->nblocks; i++) {
ut64 off = brange->from + (brange->blocksize * (i));
if (!rz_io_read_at_mapped(core->io, off, tmp, brange->blocksize)) {
rz_strbuf_free(buf);
return false;
}
double data = rz_hash_entropy_fraction(tmp, brange->blocksize);
// reseting flag if goes above falling threshold and below rising threshold
if (resetFlag == 0 && lastEdge == 0 && data > fallingthreshold) {
resetFlag = 1;
} else if (resetFlag == 0 && lastEdge == 1 && data < risingthreshold) {
resetFlag = 1;
}
// if reset flag is true
// than if entopy goes above threshold printing rising entropy edge
// and if entropy goes below threshold printing falling entropy edge
if (resetFlag == 1 && data >= risingthreshold) {
// rising edge print
resetFlag = 0;
lastEdge = 1;
rz_strbuf_appendf(buf, "0x%08" PFMT64x "\n", off);
} else if (resetFlag == 1 && data <= fallingthreshold) {
// falling edge print
resetFlag = 0;
lastEdge = 0;
rz_strbuf_appendf(buf, "0x%08" PFMT64x "\n", off);
}
}
char *res = rz_strbuf_drain(buf);
rz_cons_print(res);
free(res);
return true;
}
static bool print_rising_and_falling_entropy_standard(RzCore *core, CoreBlockRange *brange, ut8 *tmp, double fallingthreshold, double risingthreshold) {
RzStrBuf *buf = rz_strbuf_new("");
if (!buf) {
RZ_LOG_ERROR("core: failed to malloc memory\n");
return false;
}
bool resetFlag = 1;
st8 lastEdge = 0;
for (int i = 0; i < brange->nblocks; i++) {
ut64 off = brange->from + (brange->blocksize * (i));
if (!rz_io_read_at_mapped(core->io, off, tmp, brange->blocksize)) {
rz_strbuf_free(buf);
return false;
}
double data = rz_hash_entropy_fraction(tmp, brange->blocksize);
// reseting flag if goes above falling threshold and below rising threshold
if (resetFlag == 0 && lastEdge == 0 && data > fallingthreshold) {
resetFlag = 1;
} else if (resetFlag == 0 && lastEdge == 1 && data < risingthreshold) {
resetFlag = 1;
}
// if reset flag is true
// than if entopy goes above threshold printing rising entropy edge
// and if entropy goes below threshold printing falling entropy edge
if (resetFlag == 1 && data >= risingthreshold) {
// rising edge print
resetFlag = 0;
lastEdge = 1;
rz_strbuf_appendf(buf, "0x%08" PFMT64x " Rising entropy edge\n", off);
} else if (resetFlag == 1 && data <= fallingthreshold) {
// falling edge print
resetFlag = 0;
lastEdge = 0;
rz_strbuf_appendf(buf, "0x%08" PFMT64x " Falling entropy edge\n", off);
}
}
char *res = rz_strbuf_drain(buf);
rz_cons_print(res);
free(res);
return true;
}
static bool print_rising_and_falling_entropy_long(RzCore *core, CoreBlockRange *brange, ut8 *tmp, double fallingthreshold, double risingthreshold) {
RzStrBuf *buf = rz_strbuf_new("");
if (!buf) {
RZ_LOG_ERROR("core: failed to malloc memory\n");
return false;
}
bool resetFlag = 1;
st8 lastEdge = 0;
for (int i = 0; i < brange->nblocks; i++) {
ut64 off = brange->from + (brange->blocksize * (i));
if (!rz_io_read_at_mapped(core->io, off, tmp, brange->blocksize)) {
rz_strbuf_free(buf);
return false;
}
double data = rz_hash_entropy_fraction(tmp, brange->blocksize);
// reseting flag if goes above falling threshold and below rising threshold
if (resetFlag == 0 && lastEdge == 0 && data > fallingthreshold) {
resetFlag = 1;
} else if (resetFlag == 0 && lastEdge == 1 && data < risingthreshold) {
resetFlag = 1;
}
// if reset flag is true
// than if entopy goes above threshold printing rising entropy edge
// and if entropy goes below threshold printing falling entropy edge
if (resetFlag == 1 && data >= risingthreshold) {
// rising edge print
resetFlag = 0;
lastEdge = 1;
rz_strbuf_appendf(buf, "0x%08" PFMT64x " ", off);
rz_strbuf_appendf(buf, "%03x Rising entropy edge (%8lf)\n", i, data);
} else if (resetFlag == 1 && data <= fallingthreshold) {
// falling edge print
resetFlag = 0;
lastEdge = 0;
rz_strbuf_appendf(buf, "0x%08" PFMT64x " ", off);
rz_strbuf_appendf(buf, "%03x Falling entropy edge (%8lf)\n", i, data);
}
}
char *res = rz_strbuf_drain(buf);
rz_cons_print(res);
free(res);
return true;
}
static RzCmdStatus print_rising_and_falling_entropy(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
double risingthreshold = 0.95;
double fallingthreshold = 0.85;
if (argc >= 3) {
risingthreshold = rz_num_get_float(core->num, argv[1]);
fallingthreshold = rz_num_get_float(core->num, argv[2]);
}
if (fallingthreshold > risingthreshold) {
RZ_LOG_ERROR("falling threshold is greater than rising threshold\n");
return RZ_CMD_STATUS_ERROR;
}
if (risingthreshold > 1) {
RZ_LOG_ERROR("threshold can't be greater than 1\n");
return RZ_CMD_STATUS_ERROR;
}
int nblocks = -1;
ut64 totalsize = UT64_MAX;
int skipblocks = -1;
CoreBlockRange *brange = calculate_blocks_range(core, 0, 0, totalsize, nblocks, skipblocks);
if (!brange) {
RZ_LOG_ERROR("Cannot calculate blocks range\n");
return RZ_CMD_STATUS_ERROR;
}
ut8 *tmp = malloc(brange->blocksize);
if (!tmp) {
RZ_LOG_ERROR("core: failed to malloc memory\n");
free(brange);
return RZ_CMD_STATUS_ERROR;
}
switch (state->mode) {
case RZ_OUTPUT_MODE_TABLE:
if (!print_rising_and_falling_entropy_table(core, state, brange, tmp, fallingthreshold, risingthreshold)) {
free(tmp);
free(brange);
return RZ_CMD_STATUS_ERROR;
}
break;
case RZ_OUTPUT_MODE_JSON:
if (!print_rising_and_falling_entropy_JSON(core, state, brange, tmp, fallingthreshold, risingthreshold)) {
free(tmp);
free(brange);
return RZ_CMD_STATUS_ERROR;
}
break;
case RZ_OUTPUT_MODE_QUIET:
if (!print_rising_and_falling_entropy_quiet(core, brange, tmp, fallingthreshold, risingthreshold)) {
free(tmp);
free(brange);
return RZ_CMD_STATUS_ERROR;
}
break;
case RZ_OUTPUT_MODE_STANDARD:
if (!print_rising_and_falling_entropy_standard(core, brange, tmp, fallingthreshold, risingthreshold)) {
free(tmp);
free(brange);
return RZ_CMD_STATUS_ERROR;
}
break;
case RZ_OUTPUT_MODE_LONG:
if (!print_rising_and_falling_entropy_long(core, brange, tmp, fallingthreshold, risingthreshold)) {
free(tmp);
free(brange);
return RZ_CMD_STATUS_ERROR;
}
break;
default:
rz_warn_if_reached();
free(tmp);
free(brange);
return RZ_CMD_STATUS_ERROR;
}
free(tmp);
free(brange);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_equal_entropy_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_entropy(core, argc, argv, true, false);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_entropy_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_entropy(core, argc, argv, false, false);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_entropy_visual_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_entropy(core, argc, argv, false, true);
}
static const RzBlockMetricSpec metric_chisquare = { rz_hash_chisquare, 0.0, 0.0, true, 1 };
RZ_IPI RzCmdStatus rz_print_equal_chisquare_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_metric(core, argc, argv, true, false, &metric_chisquare);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_chisquare_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_metric(core, argc, argv, false, false, &metric_chisquare);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_chisquare_visual_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_metric(core, argc, argv, false, true, &metric_chisquare);
}
static const RzBlockMetricSpec metric_ioc = { rz_hash_ioc, 0.0, 1.0, false, 4 };
RZ_IPI RzCmdStatus rz_print_equal_ioc_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_metric(core, argc, argv, true, false, &metric_ioc);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_ioc_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_metric(core, argc, argv, false, false, &metric_ioc);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_ioc_visual_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_metric(core, argc, argv, false, true, &metric_ioc);
}
static const RzBlockMetricSpec metric_minentropy = { rz_hash_min_entropy, 0.0, 8.0, false, 2 };
RZ_IPI RzCmdStatus rz_print_equal_minentropy_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_metric(core, argc, argv, true, false, &metric_minentropy);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_minentropy_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_metric(core, argc, argv, false, false, &metric_minentropy);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_minentropy_visual_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_metric(core, argc, argv, false, true, &metric_minentropy);
}
static const RzBlockMetricSpec metric_serialcorr = { rz_hash_serial_correlation, -1.0, 1.0, false, 2 };
RZ_IPI RzCmdStatus rz_print_equal_serialcorr_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_metric(core, argc, argv, true, false, &metric_serialcorr);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_serialcorr_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_metric(core, argc, argv, false, false, &metric_serialcorr);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_serialcorr_visual_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_metric(core, argc, argv, false, true, &metric_serialcorr);
}
RZ_IPI RzCmdStatus rz_print_rising_and_falling_entropy_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
return print_rising_and_falling_entropy(core, argc, argv, state);
}
static RzCmdStatus print_histogram_marks(RzCore *core, int argc, const char **argv, bool vertical, bool isinteractive) {
CoreBlockRange *brange = parse_args_calculate_range(core, argc, argv);
if (!brange) {
return RZ_CMD_STATUS_ERROR;
}
ut8 *data = calloc(1, brange->nblocks);
ut8 *tmp = malloc(brange->blocksize);
if (!tmp) {
free(data);
free(brange);
RZ_LOG_ERROR("core: failed to malloc memory\n");
return RZ_CMD_STATUS_ERROR;
}
for (size_t i = 0; i < brange->nblocks; i++) {
ut64 off = brange->from + (brange->blocksize * (i + brange->skipblocks));
for (size_t j = 0; j < brange->blocksize; j++) {
if (rz_flag_get_at(core->flags, off + j, false)) {
data_array_increment_element(data, i);
}
}
}
free(tmp);
if (isinteractive) {
RzHistogramOptions *opts = default_visual_opts(core, brange->from);
if (!opts) {
free(brange);
free(data);
return RZ_CMD_STATUS_ERROR;
}
if (print_visual_bytes(core, opts, data, brange) != RZ_CMD_STATUS_OK) {
RZ_LOG_ERROR("Cannot generate interactive histogram\n");
free(brange);
free(data);
return RZ_CMD_STATUS_ERROR;
}
} else {
RzHistogramOptions opts = default_histogram_opts(core->config, &core->cons->context->pal, brange->from);
opts.value_max = 255;
if (!print_histogram(core, &opts, data, brange->nblocks, brange->blocksize, vertical)) {
RZ_LOG_ERROR("Cannot generate %s histogram\n", vertical ? "vertical" : "horizontal");
free(data);
free(brange);
return RZ_CMD_STATUS_ERROR;
}
}
free(data);
free(brange);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_equal_m_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_marks(core, argc, argv, true, false);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_m_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_marks(core, argc, argv, false, false);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_m_visual_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_marks(core, argc, argv, false, true);
}
static RzCmdStatus print_histogram_0x00(RzCore *core, int argc, const char **argv, bool vertical, bool isinteractive) {
CoreBlockRange *brange = parse_args_calculate_range(core, argc, argv);
if (!brange) {
return RZ_CMD_STATUS_ERROR;
}
ut8 *data = calloc(1, brange->nblocks);
ut8 *tmp = malloc(brange->blocksize);
if (!tmp) {
free(data);
free(brange);
RZ_LOG_ERROR("core: failed to malloc memory\n");
return RZ_CMD_STATUS_ERROR;
}
for (size_t i = 0; i < brange->nblocks; i++) {
int k = 0;
ut64 off = brange->from + (brange->blocksize * (i + brange->skipblocks));
rz_io_read_at_mapped(core->io, off, tmp, brange->blocksize);
for (size_t j = k = 0; j < brange->blocksize; j++) {
if (!tmp[j]) {
k++;
}
}
data[i] = 256 * k / brange->blocksize;
}
free(tmp);
if (isinteractive) {
RzHistogramOptions *opts = default_visual_opts(core, brange->from);
if (!opts) {
free(brange);
free(data);
return RZ_CMD_STATUS_ERROR;
}
if (print_visual_bytes(core, opts, data, brange) != RZ_CMD_STATUS_OK) {
RZ_LOG_ERROR("Cannot generate interactive histogram\n");
free(brange);
free(data);
return RZ_CMD_STATUS_ERROR;
}
} else {
RzHistogramOptions opts = default_histogram_opts(core->config, &core->cons->context->pal, brange->from);
opts.value_max = 100;
opts.value_unit = "%";
if (!print_histogram(core, &opts, data, brange->nblocks, brange->blocksize, vertical)) {
RZ_LOG_ERROR("Cannot generate %s histogram\n", vertical ? "vertical" : "horizontal");
free(data);
free(brange);
return RZ_CMD_STATUS_ERROR;
}
}
free(data);
free(brange);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_equal_0x00_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_0x00(core, argc, argv, true, false);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_0x00_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_0x00(core, argc, argv, false, false);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_0x00_visual_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_0x00(core, argc, argv, false, true);
}
static RzCmdStatus print_histogram_0xff(RzCore *core, int argc, const char **argv, bool vertical, bool isinteractive) {
CoreBlockRange *brange = parse_args_calculate_range(core, argc, argv);
if (!brange) {
return RZ_CMD_STATUS_ERROR;
}
ut8 *data = calloc(1, brange->nblocks);
ut8 *tmp = malloc(brange->blocksize);
if (!tmp) {
free(data);
free(brange);
RZ_LOG_ERROR("core: failed to malloc memory\n");
return RZ_CMD_STATUS_ERROR;
}
for (size_t i = 0; i < brange->nblocks; i++) {
int k = 0;
ut64 off = brange->from + (brange->blocksize * (i + brange->skipblocks));
rz_io_read_at_mapped(core->io, off, tmp, brange->blocksize);
for (size_t j = k = 0; j < brange->blocksize; j++) {
if (tmp[j] == 0xff) {
k++;
}
}
data[i] = 256 * k / brange->blocksize;
}
free(tmp);
if (isinteractive) {
RzHistogramOptions *opts = default_visual_opts(core, brange->from);
if (!opts) {
free(brange);
free(data);
return RZ_CMD_STATUS_ERROR;
}
if (print_visual_bytes(core, opts, data, brange) != RZ_CMD_STATUS_OK) {
RZ_LOG_ERROR("Cannot generate interactive histogram\n");
free(brange);
free(data);
return RZ_CMD_STATUS_ERROR;
}
} else {
RzHistogramOptions opts = default_histogram_opts(core->config, &core->cons->context->pal, brange->from);
opts.value_max = 100;
opts.value_unit = "%";
if (!print_histogram(core, &opts, data, brange->nblocks, brange->blocksize, vertical)) {
RZ_LOG_ERROR("Cannot generate %s histogram\n", vertical ? "vertical" : "horizontal");
free(data);
free(brange);
return RZ_CMD_STATUS_ERROR;
}
}
free(data);
free(brange);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_equal_0xff_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_0xff(core, argc, argv, true, false);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_0xff_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_0xff(core, argc, argv, false, false);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_0xff_visual_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_0xff(core, argc, argv, false, true);
}
static RzCmdStatus print_histogram_printable(RzCore *core, int argc, const char **argv, bool vertical, bool isinteractive) {
CoreBlockRange *brange = parse_args_calculate_range(core, argc, argv);
if (!brange) {
return RZ_CMD_STATUS_ERROR;
}
ut8 *data = calloc(1, brange->nblocks);
ut8 *tmp = malloc(brange->blocksize);
if (!tmp) {
free(data);
free(brange);
RZ_LOG_ERROR("core: failed to malloc memory\n");
return RZ_CMD_STATUS_ERROR;
}
for (size_t i = 0; i < brange->nblocks; i++) {
int k = 0;
ut64 off = brange->from + (brange->blocksize * (i + brange->skipblocks));
rz_io_read_at_mapped(core->io, off, tmp, brange->blocksize);
for (size_t j = k = 0; j < brange->blocksize; j++) {
if (IS_PRINTABLE(tmp[j])) {
k++;
}
}
data[i] = 256 * k / brange->blocksize;
}
free(tmp);
if (isinteractive) {
RzHistogramOptions *opts = default_visual_opts(core, brange->from);
if (!opts) {
free(brange);
free(data);
return RZ_CMD_STATUS_ERROR;
}
if (print_visual_bytes(core, opts, data, brange) != RZ_CMD_STATUS_OK) {
RZ_LOG_ERROR("Cannot generate interactive histogram\n");
free(brange);
free(data);
return RZ_CMD_STATUS_ERROR;
}
} else {
RzHistogramOptions opts = default_histogram_opts(core->config, &core->cons->context->pal, brange->from);
opts.value_max = 100;
opts.value_unit = "%";
if (!print_histogram(core, &opts, data, brange->nblocks, brange->blocksize, vertical)) {
RZ_LOG_ERROR("Cannot generate %s histogram\n", vertical ? "vertical" : "horizontal");
free(data);
free(brange);
return RZ_CMD_STATUS_ERROR;
}
}
free(data);
free(brange);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_equal_printable_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_printable(core, argc, argv, true, false);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_printable_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_printable(core, argc, argv, false, false);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_printable_visual_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_printable(core, argc, argv, false, true);
}
static RzCmdStatus print_histogram_z(RzCore *core, int argc, const char **argv, bool vertical, bool isinteractive) {
CoreBlockRange *brange = parse_args_calculate_range(core, argc, argv);
if (!brange) {
return RZ_CMD_STATUS_ERROR;
}
ut8 *data = calloc(1, brange->nblocks);
ut8 *tmp = malloc(brange->blocksize);
if (!tmp) {
free(data);
free(brange);
RZ_LOG_ERROR("core: failed to malloc memory\n");
return RZ_CMD_STATUS_ERROR;
}
size_t len = 0;
for (size_t i = 0; i < brange->nblocks; i++) {
int k = 0;
ut64 off = brange->from + (brange->blocksize * (i + brange->skipblocks));
rz_io_read_at_mapped(core->io, off, tmp, brange->blocksize);
for (size_t j = k = 0; j < brange->blocksize; j++) {
if (IS_PRINTABLE(tmp[j])) {
if ((j + 1) < brange->blocksize && tmp[j + 1] == 0) {
k++;
j++;
}
if (len++ > 8) {
k++;
}
} else {
len = 0;
}
}
data[i] = 256 * k / brange->blocksize;
}
free(tmp);
if (isinteractive) {
RzHistogramOptions *opts = default_visual_opts(core, brange->from);
if (!opts) {
free(brange);
free(data);
return RZ_CMD_STATUS_ERROR;
}
if (print_visual_bytes(core, opts, data, brange) != RZ_CMD_STATUS_OK) {
RZ_LOG_ERROR("Cannot generate interactive histogram\n");
free(brange);
free(data);
return RZ_CMD_STATUS_ERROR;
}
} else {
RzHistogramOptions opts = default_histogram_opts(core->config, &core->cons->context->pal, brange->from);
opts.value_max = 100;
opts.value_unit = "%";
if (!print_histogram(core, &opts, data, brange->nblocks, brange->blocksize, vertical)) {
free(data);
free(brange);
RZ_LOG_ERROR("Cannot generate %s histogram\n", vertical ? "vertical" : "horizontal");
return RZ_CMD_STATUS_ERROR;
}
}
free(data);
free(brange);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_equal_z_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_z(core, argc, argv, true, false);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_z_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_z(core, argc, argv, false, false);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_z_visual_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_z(core, argc, argv, false, true);
}
static RzCmdStatus print_histogram_stats(RzCore *core, int argc, const char **argv, bool vertical, bool isinteractive) {
CoreBlockRange *brange = parse_args_calculate_range(core, argc, argv);
if (!brange) {
return RZ_CMD_STATUS_ERROR;
}
ut8 *data = analysis_stats_histogram_data(core, brange);
if (!data) {
free(brange);
RZ_LOG_ERROR("core: failed to access analysis stats");
return RZ_CMD_STATUS_ERROR;
}
if (isinteractive) {
RzHistogramOptions *opts = default_visual_opts(core, brange->from);
if (!opts) {
free(brange);
free(data);
return RZ_CMD_STATUS_ERROR;
}
if (print_visual_bytes(core, opts, data, brange) != RZ_CMD_STATUS_OK) {
RZ_LOG_ERROR("Cannot generate interactive histogram\n");
free(brange);
free(data);
return RZ_CMD_STATUS_ERROR;
}
} else {
RzHistogramOptions opts = default_histogram_opts(core->config, &core->cons->context->pal, brange->from);
opts.value_max = 255;
if (!print_histogram(core, &opts, data, brange->nblocks, brange->blocksize, vertical)) {
RZ_LOG_ERROR("Cannot generate %s histogram\n", vertical ? "vertical" : "horizontal");
free(data);
free(brange);
return RZ_CMD_STATUS_ERROR;
}
}
free(data);
free(brange);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_equal_stats_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_stats(core, argc, argv, true, false);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_stats_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_stats(core, argc, argv, false, false);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_stats_visual_handler(RzCore *core, int argc, const char **argv) {
return print_histogram_stats(core, argc, argv, false, true);
}
static RzCmdStatus analysis_hist_handler(RzCore *core, int argc, const char **argv, CoreAnalysisHistogramType hist_type, bool vertical, bool isinteractive) {
CoreBlockRange *brange = parse_args_calculate_range(core, argc, argv);
if (!brange) {
return RZ_CMD_STATUS_ERROR;
}
ut8 *data = analysis_histogram_data(core, brange, hist_type);
if (!data) {
free(brange);
RZ_LOG_ERROR("core: failed to access analyzed instructions for specified range");
return RZ_CMD_STATUS_ERROR;
}
if (isinteractive) {
RzHistogramOptions *opts = default_visual_opts(core, brange->from);
if (!opts) {
free(brange);
free(data);
return RZ_CMD_STATUS_ERROR;
}
if (print_visual_bytes(core, opts, data, brange) != RZ_CMD_STATUS_OK) {
RZ_LOG_ERROR("Cannot generate interactive histogram\n");
free(brange);
free(data);
return RZ_CMD_STATUS_ERROR;
}
} else {
RzHistogramOptions opts = default_histogram_opts(core->config, &core->cons->context->pal, brange->from);
opts.value_max = 255;
if (!print_histogram(core, &opts, data, brange->nblocks, brange->blocksize, vertical)) {
RZ_LOG_ERROR("Cannot generate %s histogram\n", vertical ? "vertical" : "horizontal");
free(data);
free(brange);
return RZ_CMD_STATUS_ERROR;
}
}
free(data);
free(brange);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_print_equal_bbs_handler(RzCore *core, int argc, const char **argv) {
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_BASIC_BLOCKS, true, false);
}
RZ_IPI RzCmdStatus rz_print_equal_call_handler(RzCore *core, int argc, const char **argv) {
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_CALL_INSTRUCTIONS, true, false);
}
RZ_IPI RzCmdStatus rz_print_equal_jump_handler(RzCore *core, int argc, const char **argv) {
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_JUMP_INSTRUCTIONS, true, false);
}
RZ_IPI RzCmdStatus rz_print_equal_priv_handler(RzCore *core, int argc, const char **argv) {
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_PRIV_INSTRUCTIONS, true, false);
}
RZ_IPI RzCmdStatus rz_print_equal_invalid_handler(RzCore *core, int argc, const char **argv) {
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_INVALID_INSTRUCTIONS, true, false);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_bbs_handler(RzCore *core, int argc, const char **argv) {
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_BASIC_BLOCKS, false, false);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_call_handler(RzCore *core, int argc, const char **argv) {
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_CALL_INSTRUCTIONS, false, false);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_jump_handler(RzCore *core, int argc, const char **argv) {
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_JUMP_INSTRUCTIONS, false, false);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_priv_handler(RzCore *core, int argc, const char **argv) {
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_PRIV_INSTRUCTIONS, false, false);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_invalid_handler(RzCore *core, int argc, const char **argv) {
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_INVALID_INSTRUCTIONS, false, false);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_bbs_visual_handler(RzCore *core, int argc, const char **argv) {
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_BASIC_BLOCKS, false, true);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_call_visual_handler(RzCore *core, int argc, const char **argv) {
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_CALL_INSTRUCTIONS, false, true);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_jump_visual_handler(RzCore *core, int argc, const char **argv) {
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_JUMP_INSTRUCTIONS, false, true);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_priv_visual_handler(RzCore *core, int argc, const char **argv) {
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_PRIV_INSTRUCTIONS, false, true);
}
RZ_IPI RzCmdStatus rz_print_equal_equal_invalid_visual_handler(RzCore *core, int argc, const char **argv) {
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_INVALID_INSTRUCTIONS, false, true);
}
RZ_IPI RzCmdStatus rz_print_equal_two_handler(RzCore *core, int argc, const char **argv) {
short *word = (short *)core->block;
size_t i, words = core->blocksize / 2;
int step = rz_num_math(core->num, argv[1]);
ut64 oldword = 0;
for (i = 0; i < words; i++) {
ut64 word64 = word[i] + ST16_MAX;
rz_cons_printf("0x%08" PFMT64x " %8d ", core->offset + (i * 2), word[i]);
RzBarOptions baropts = {
.unicode = rz_config_get_b(core->config, "scr.utf8"),
.thinline = !rz_config_get_b(core->config, "scr.hist.block"),
.legend = false,
.offset = rz_config_get_b(core->config, "hex.offset"),
.offpos = 0,
.cursor = false,
.curpos = 0,
.color = rz_config_get_i(core->config, "scr.color")
};
RzStrBuf *strbuf = rz_progressbar(&baropts, word64 * 100 / UT16_MAX, 60);
if (!strbuf) {
RZ_LOG_ERROR("Cannot generate vertical histogram\n");
} else {
char *bar = rz_strbuf_drain(strbuf);
rz_cons_print(bar);
free(bar);
}
rz_cons_printf(" %" PFMT64d, word64 - oldword);
oldword = word64;
rz_cons_newline();
i += step;
}
return RZ_CMD_STATUS_OK;
}
static void printraw(RzCore *core, int len, bool stop_at_null) {
ut8 *data = malloc(len);
if (!data) {
return;
}
if (rz_io_read_at_mapped(core->io, core->offset, data, len)) {
if (stop_at_null) {
len = rz_str_nlen((const char *)data, len);
}
rz_print_raw(core->print, core->offset, data, len);
}
free(data);
core->cons->newline = core->cmd_in_backticks ? false : true;
}
RZ_IPI RzCmdStatus rz_cmd_print_raw_handler(RzCore *core, int argc, const char **argv) {
int len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
if (len < 0) {
return RZ_CMD_STATUS_ERROR;
}
printraw(core, len, false);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_print_raw_colors_handler(RzCore *core, int argc, const char **argv) {
int len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
if (len < 0) {
return RZ_CMD_STATUS_ERROR;
}
colordump(core, core->block, len);
return RZ_CMD_STATUS_OK;
}
static bool gunzip_and_print_block(RzCore *core, bool verbose) {
int outlen = 0;
int inConsumed = 0;
ut8 *out;
out = rz_inflate(core->block, core->blocksize, &inConsumed, &outlen);
if (!out) {
return false;
}
if (verbose) {
rz_cons_printf("consumed: %d produced: %d\n", inConsumed, outlen);
}
rz_cons_memcat((const char *)out, outlen);
free(out);
return true;
}
RZ_IPI RzCmdStatus rz_cmd_print_raw_gunzip_handler(RzCore *core, int argc, const char **argv) {
return bool2status(gunzip_and_print_block(core, false));
}
RZ_IPI RzCmdStatus rz_cmd_print_raw_gunzip_verbose_handler(RzCore *core, int argc, const char **argv) {
return bool2status(gunzip_and_print_block(core, true));
}
RZ_IPI RzCmdStatus rz_cmd_print_raw_printable_handler(RzCore *core, int argc, const char **argv) {
int a = rz_config_get_i(core->config, "hex.bytes");
rz_config_set_i(core->config, "hex.bytes", false);
// TODO: Use the API instead of commands
rz_core_cmd0(core, "pxx");
rz_config_set_i(core->config, "hex.bytes", a);
return RZ_CMD_STATUS_OK;
}
static RzCmdStatus print_format(RzCore *core, const char *fmt, int mode, RzCmdStateOutput *state) {
rz_return_val_if_fail(fmt, RZ_CMD_STATUS_ERROR);
if (state) {
switch (state->mode) {
case RZ_OUTPUT_MODE_JSON:
mode = RZ_PRINT_JSON;
break;
case RZ_OUTPUT_MODE_QUIET:
mode |= RZ_PRINT_QUIET | RZ_PRINT_MUSTSEE;
break;
default:
break;
}
// Temporary workaround until `librz/type/format.c` is rewritten properly
if (state->mode != RZ_OUTPUT_MODE_JSON) {
rz_cmd_state_output_array_start(state);
}
}
char *format = rz_core_print_format(core, fmt, mode, core->offset);
if (!format) {
return RZ_CMD_STATUS_ERROR;
}
if (state) {
// Temporary workaround until `librz/type/format.c` is rewritten properly
if (state->mode != RZ_OUTPUT_MODE_JSON) {
rz_cmd_state_output_array_end(state);
}
}
rz_cons_print(format);
free(format);
return RZ_CMD_STATUS_OK;
}
static RzCmdStatus print_format_write(RzCore *core, const char *fmt, const char *value) {
rz_return_val_if_fail(fmt, RZ_CMD_STATUS_ERROR);
char *format = rz_core_print_format_write(core, fmt, value, core->offset);
if (!format) {
return RZ_CMD_STATUS_ERROR;
}
rz_cons_print(format);
free(format);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_print_raw_string_handler(RzCore *core, int argc, const char **argv) {
int len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
if (len < 0) {
return RZ_CMD_STATUS_ERROR;
}
printraw(core, len, true);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_print_format_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
int mode = RZ_PRINT_MUSTSEE;
return print_format(core, argv[1], mode, state);
}
RZ_IPI RzCmdStatus rz_cmd_print_format_delete_handler(RzCore *core, int argc, const char **argv) {
RzTypeDB *typedb = rz_analysis_get_type_db(core->analysis);
rz_type_db_format_delete(typedb, argv[1]);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_print_format_delete_all_handler(RzCore *core, int argc, const char **argv) {
RzTypeDB *typedb = rz_analysis_get_type_db(core->analysis);
rz_type_db_format_purge(typedb);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_print_format_apply_handler(RzCore *core, int argc, const char **argv) {
if (argc < 2) {
return RZ_CMD_STATUS_WRONG_ARGS;
}
const char *typename = argv[1];
ut64 addr = argc > 2 ? rz_num_math(core->num, argv[2]) : core->offset;
RzTypeDB *typedb = rz_analysis_get_type_db(core->analysis);
const char *fmt = rz_type_db_format_get(typedb, typename);
if (RZ_STR_ISEMPTY(fmt)) {
RZ_LOG_ERROR("Format with \"%s\" name not found\n", typename);
return RZ_CMD_STATUS_ERROR;
}
ut64 old_offset = core->offset;
rz_core_seek(core, addr, true);
RzCmdStatus status = print_format(core, fmt, RZ_PRINT_MUSTSEE, NULL);
rz_core_seek(core, old_offset, true);
return status;
}
RZ_IPI RzCmdStatus rz_cmd_print_format_named_dot_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
int mode = RZ_PRINT_MUSTSEE;
/* pf. is the "show data using a NAMED format" command. The leading
* dot is the marker. If the argument doesn't resolve to a registered
* format (and isn't a sub-field reference like `name.field`), bail
* out with a clear error instead of falling through to raw-format
* parsing, which would emit a string of "unknown specifier" warnings
* that obscure the real problem. */
if (argc < 2) {
return print_format(core, "", mode, state);
}
RzTypeDB *typedb = rz_analysis_get_type_db(core->analysis);
const char *arg = argv[1];
const char *dot = strchr(arg, '.');
size_t name_len = dot ? (size_t)(dot - arg) : strlen(arg);
char *name = rz_str_ndup(arg, name_len);
if (!name) {
return RZ_CMD_STATUS_ERROR;
}
const char *fmt = rz_type_db_format_get(typedb, name);
if (RZ_STR_ISEMPTY(fmt)) {
RZ_LOG_ERROR("pf.: no registered format named '%s'. "
"Run `pfn` to list known formats, or `pfo` to load a "
"format definition file (e.g. `pfo elf64` then "
"`pf. elf_header`).\n",
name);
free(name);
return RZ_CMD_STATUS_ERROR;
}
free(name);
return print_format(core, arg, mode, state);
}
static int compare_type_formats(const RzTypeFormat *a, const RzTypeFormat *b, RZ_UNUSED void *user) {
return strcmp(a->name, b->name);
}
RZ_IPI RzCmdStatus rz_cmd_print_format_named_handler(RzCore *core, int argc, const char **argv) {
RzTypeDB *typedb = rz_analysis_get_type_db(core->analysis);
if (argc < 2) {
// List all named formats
RzListIter *iter;
RzTypeFormat *fmt = NULL;
RzList *formats = rz_type_db_format_all(typedb);
rz_list_sort(formats, (RzListComparator)compare_type_formats, NULL);
rz_list_foreach (formats, iter, fmt) {
rz_cons_printf("%s \"%s\"\n", fmt->name, fmt->body);
}
rz_list_free(formats);
return RZ_CMD_STATUS_OK;
} else if (argc < 3) {
// Show the format string for a named format
const char *fmt = rz_type_db_format_get(typedb, argv[1]);
if (RZ_STR_ISEMPTY(fmt)) {
RZ_LOG_ERROR("Format with \"%s\" name not found\n", argv[1]);
return RZ_CMD_STATUS_ERROR;
}
rz_cons_printf("%s\n", fmt);
return RZ_CMD_STATUS_OK;
}
rz_type_db_format_set(typedb, argv[1], argv[2]);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_print_format_c_handler(RzCore *core, int argc, const char **argv) {
int mode = RZ_PRINT_STRUCT;
return print_format(core, argv[1], mode, NULL);
}
RZ_IPI RzCmdStatus rz_cmd_print_format_dot_handler(RzCore *core, int argc, const char **argv) {
int mode = RZ_PRINT_DOT;
return print_format(core, argv[1], mode, NULL);
}
RZ_IPI RzCmdStatus rz_cmd_print_format_file_handler(RzCore *core, int argc, const char **argv) {
if (argc < 2) {
RzList *files;
RzListIter *iter;
const char *fn;
/* De-duplicate file names that appear in both the home FDF dir
* and the system FDF dir (common when the same file is
* installed in both locations). */
HtSU *seen = ht_su_new(HT_STR_DUP);
char *home = rz_path_home_prefix(RZ_SDB_FORMAT);
if (home) {
files = rz_sys_dir(home);
rz_list_foreach (files, iter, fn) {
if (*fn && *fn != '.' && (!seen || !ht_su_find(seen, fn, NULL))) {
rz_cons_println(fn);
if (seen) {
ht_su_insert(seen, fn, 1);
}
}
}
rz_list_free(files);
free(home);
}
char *path = rz_path_system(core->sys_path, RZ_SDB_FORMAT);
if (path) {
files = rz_sys_dir(path);
rz_list_foreach (files, iter, fn) {
if (*fn && *fn != '.' && (!seen || !ht_su_find(seen, fn, NULL))) {
rz_cons_println(fn);
if (seen) {
ht_su_insert(seen, fn, 1);
}
}
}
rz_list_free(files);
free(path);
}
ht_su_free(seen);
return RZ_CMD_STATUS_OK;
}
char *home_formats = rz_path_home_prefix(RZ_SDB_FORMAT);
char *home = rz_file_path_join(home_formats, argv[1]);
free(home_formats);
char *system_formats = rz_path_system(core->sys_path, RZ_SDB_FORMAT);
char *path = rz_file_path_join(system_formats, argv[1]);
free(system_formats);
if (rz_str_endswith(argv[1], ".h")) {
char *error_msg = NULL;
const char *dir = rz_config_get(core->config, "dir.types");
RzTypeDB *typedb = rz_analysis_get_type_db(core->analysis);
int result = rz_type_parse_file(typedb, path, dir, &error_msg);
if (!result) {
// TODO: Use the API here
rz_core_cmd0(core, ".ts*");
} else {
RZ_LOG_ERROR("core: Parse error: %s\n", error_msg);
free(error_msg);
}
} else {
if (!rz_core_cmd_file(core, home) && !rz_core_cmd_file(core, path)) {
if (!rz_core_cmd_file(core, argv[1])) {
RZ_LOG_ERROR("core: pfo: cannot open format file at '%s'\n", path);
}
}
}
free(home);
free(path);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_print_format_size_handler(RzCore *core, int argc, const char **argv) {
RzTypeDB *typedb = rz_analysis_get_type_db(core->analysis);
const char *format = rz_type_db_format_get(typedb, argv[1]);
if (!format) {
RZ_LOG_ERROR("Format \"%s\" could not be found\n", argv[1]);
return RZ_CMD_STATUS_ERROR;
}
int fmtsz = rz_type_format_struct_size(typedb, format, RZ_PRINT_MUSTSEE, 0);
rz_cons_printf("%d\n", fmtsz);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_print_format_value_handler(RzCore *core, int argc, const char **argv) {
int mode = RZ_PRINT_VALUE | RZ_PRINT_MUSTSEE;
return print_format(core, argv[1], mode, NULL);
}
RZ_IPI RzCmdStatus rz_cmd_print_format_write_handler(RzCore *core, int argc, const char **argv) {
return print_format_write(core, argv[1], argv[2]);
}
RZ_IPI RzCmdStatus rz_cmd_print_2bpp_tiles_handler(RzCore *core, int argc, const char **argv) {
size_t len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
if (len == 0) {
return RZ_CMD_STATUS_OK;
}
core_print_2bpp_tiles(core, len / 16);
return RZ_CMD_STATUS_OK;
}
static RzCmdStatus print_8bit_hexpair(RzCore *core, ut64 addr, size_t len) {
ut8 *buf = malloc(len);
if (!buf) {
RZ_LOG_ERROR("core: cannot allocate %zu byte(s)\n", len);
return RZ_CMD_STATUS_ERROR;
}
rz_io_read_at_mapped(core->io, addr, buf, len);
rz_print_bytes(core->print, buf, len, "%02x");
free(buf);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_print_8bit_hexpair_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
size_t len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
if (len == 0) {
return RZ_CMD_STATUS_OK;
}
if (state->mode == RZ_OUTPUT_MODE_STANDARD) {
return print_8bit_hexpair(core, core->offset, len);
}
char *code = rz_lang_byte_array(core->block, len, RZ_LANG_BYTE_ARRAY_JSON);
if (RZ_STR_ISEMPTY(code)) {
free(code);
return RZ_CMD_STATUS_ERROR;
}
rz_cons_print(code);
free(code);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_print_8bit_hexpair_function_handler(RzCore *core, int argc, const char **argv) {
RzAnalysisFunction *f = rz_analysis_first_function_in(core->analysis, core->offset);
if (!f) {
RZ_LOG_ERROR("Cannot find function at 0x%08" PFMT64x "\n", core->offset);
return RZ_CMD_STATUS_ERROR;
}
size_t len = rz_analysis_function_linear_size(f);
ut64 addr = rz_analysis_function_min_addr(f);
return print_8bit_hexpair(core, addr, len);
}
// "x"
RZ_IPI RzCmdStatus rz_print_hexdump_alias_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
return rz_print_hexdump_handler(core, argc, argv, state);
}
// "xc"
RZ_IPI RzCmdStatus rz_print_hexdump_comments_alias_handler(RzCore *core, int argc, const char **argv) {
return rz_print_hexdump_comments_handler(core, argc, argv);
}
static size_t format_width_to_num(size_t arch_bits, const char *width) {
rz_return_val_if_fail(width, 0);
switch (width[0]) {
default:
rz_warn_if_reached();
return 0;
case 'b': // # Byte = 1 bytes
return 1;
case 'h': // # Half word = 2 bytes
return 2;
case 'w': // # Word = 4 bytes
return 4;
case 'd': // # Double word = 8 bytes
return 8;
case 'a': // # Architecture width
return arch_bits > 0 ? arch_bits / 8 : 1;
}
}
// "pxF"
RZ_IPI RzCmdStatus rz_print_hexdump_format_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
ut64 num = rz_num_math(core->num, argv[1]);
if (!num) {
return RZ_CMD_STATUS_OK;
}
const char *format = argv[2];
size_t width = format_width_to_num(rz_asm_get_bits(core->rasm), argv[3]);
switch (format[0]) {
default:
RZ_LOG_ERROR("Invalid format: '%s'.\n", format);
return RZ_CMD_STATUS_ERROR;
case 'x':
return bool2status(rz_core_print_dump(core, state->mode, core->offset, width, num * width, RZ_CORE_PRINT_FORMAT_TYPE_HEXADECIMAL));
case 'o':
// Parameter n must be 1 here. Don't ask me why :( The rabbit whole is deep and defuse.
return bool2status(rz_core_print_dump(core, state->mode, core->offset, 1, num * width, RZ_CORE_PRINT_FORMAT_TYPE_OCTAL));
case 'd':
return bool2status(rz_core_print_dump(core, state->mode, core->offset, width, num * width, RZ_CORE_PRINT_FORMAT_TYPE_INTEGER));
case 'f': {
char *format = RZ_NEWS0(char, num + 1);
for (size_t i = 0; i < num; ++i) {
format[i] = 'f';
}
RzCmdStatus status = print_format(core, format, RZ_PRINT_MUSTSEE, state);
free(format);
return status;
}
case 's': {
size_t block_size_bak = core->blocksize;
size_t new_block_size = num * width;
if (!rz_core_block_size(core, new_block_size)) {
RZ_LOG_ERROR("Failed to set block size to %" PFMTSZu " bytes.\n", new_block_size);
return RZ_CMD_STATUS_ERROR;
}
const char *psb = "psb";
RzCmdStatus status = rz_print_strings_current_block_handler(core, 1, &psb, state->mode);
if (!rz_core_block_size(core, block_size_bak)) {
RZ_LOG_ERROR("Failed to reset block size to %" PFMTSZu " bytes.\n", block_size_bak);
return RZ_CMD_STATUS_ERROR;
}
return status;
}
}
return RZ_CMD_STATUS_ERROR;
}