mirror of
https://github.com/radareorg/radare2.git
synced 2024-12-11 23:16:05 +00:00
3272 lines
93 KiB
C
3272 lines
93 KiB
C
/* radare - LGPL - Copyright 2009-2015 - pancake */
|
|
|
|
#define R_CORE_MAX_DISASM (1024*1024*1)
|
|
|
|
static char get_string_type (const ut8 *buf, ut64 len){
|
|
ut64 needle = 0;
|
|
int rc, i;
|
|
char str_type = 0;
|
|
|
|
if (!buf)
|
|
return '?';
|
|
|
|
while (needle < len){
|
|
rc = r_utf8_decode (buf+needle, len-needle, NULL);
|
|
if (!rc){
|
|
needle++;
|
|
continue;
|
|
}
|
|
if (needle+rc+2 < len &&
|
|
buf[needle+rc+0] == 0x00 &&
|
|
buf[needle+rc+1] == 0x00 &&
|
|
buf[needle+rc+2] == 0x00)
|
|
str_type = 'w';
|
|
else
|
|
str_type = 'a';
|
|
for (rc = i = 0; needle < len ; i+= rc){
|
|
RRune r;
|
|
if (str_type == 'w'){
|
|
if (needle+1 < len){
|
|
r = buf[needle+1] << 8 | buf[needle];
|
|
rc = 2;
|
|
} else {
|
|
break;
|
|
}
|
|
} else {
|
|
rc = r_utf8_decode (buf+needle, len-needle, &r);
|
|
if(rc > 1) str_type = 'u';
|
|
}
|
|
/*Invalid sequence detected*/
|
|
if (!rc){
|
|
needle++;
|
|
break;
|
|
}
|
|
needle += rc;
|
|
}
|
|
}
|
|
return str_type;
|
|
}
|
|
|
|
static void cmd_print_eq_dict(RCore *core, int bsz) {
|
|
int i;
|
|
int min = 0;
|
|
int max = 0;
|
|
int dict = 0;
|
|
int range = 0;
|
|
ut8 buf[0xff+1];
|
|
|
|
for (i=0; i<0xff; i++) {
|
|
buf[i] = 0;
|
|
}
|
|
for (i=0; i<bsz; i++) {
|
|
buf[core->block[i]] = 1;
|
|
}
|
|
for (i=0; i<0xff; i++) {
|
|
if (buf[i]) {
|
|
if (min == 0)
|
|
min = i;
|
|
max = i;
|
|
dict++;
|
|
}
|
|
}
|
|
range = max - min;
|
|
r_cons_printf ("min: %d 0x%x\n", min, min);
|
|
r_cons_printf ("max: %d 0x%x\n", max, max);
|
|
r_cons_printf ("dict: %d 0x%x\n", dict, dict);
|
|
r_cons_printf ("range: %d 0x%x\n", range, range);
|
|
}
|
|
|
|
static void set_asm_configs(RCore *core, char *arch, ut32 bits, int segoff){
|
|
r_config_set (core->config, "asm.arch", arch);
|
|
r_config_set_i (core->config, "asm.bits", bits);
|
|
// XXX - this needs to be done here, because
|
|
// if arch == x86 and bits == 16, segoff automatically changes
|
|
r_config_set_i (core->config, "asm.segoff", segoff);
|
|
}
|
|
|
|
static void cmd_pDj (RCore *core, const char *arg) {
|
|
int bsize = r_num_math (core->num, arg);
|
|
if (bsize < 0) bsize = -bsize;
|
|
if (bsize <= core->blocksize) {
|
|
r_core_print_disasm_json (core, core->offset, core->block,
|
|
bsize, 0);
|
|
} else {
|
|
ut8 *buf = malloc (bsize);
|
|
if (buf) {
|
|
r_io_read_at (core->io, core->offset, buf, bsize);
|
|
r_core_print_disasm_json (core, core->offset, buf,
|
|
bsize, 0);
|
|
free (buf);
|
|
} else eprintf ("cannot allocate %d bytes\n", bsize);
|
|
}
|
|
r_cons_newline ();
|
|
}
|
|
|
|
static void cmd_pdj (RCore *core, const char *arg) {
|
|
int nblines = r_num_math(core->num, arg);
|
|
ut8 buf[256];
|
|
r_core_print_disasm_json (core, core->offset, buf, sizeof(buf), nblines);
|
|
r_cons_newline ();
|
|
}
|
|
|
|
static int process_input(RCore *core, const char *input, ut64* blocksize, char **asm_arch, ut32 *bits) {
|
|
// input: start of the input string e.g. after the command symbols have been consumed
|
|
// size: blocksize if present, otherwise -1
|
|
// asm_arch: asm_arch to interpret as if present and valid, otherwise NULL;
|
|
// bits: bits to use if present, otherwise -1
|
|
|
|
int result = false;
|
|
char *input_one = NULL, *input_two = NULL, *input_three = NULL;
|
|
char *str_clone = NULL,
|
|
*ptr_str_clone = NULL,
|
|
*trimmed_clone = NULL;
|
|
|
|
if (input == NULL || blocksize == NULL || asm_arch == NULL || bits == NULL) {
|
|
return false;
|
|
}
|
|
|
|
str_clone = strdup (input);
|
|
trimmed_clone = r_str_trim_head_tail (str_clone);
|
|
|
|
input_one = trimmed_clone;
|
|
|
|
ptr_str_clone = strchr (trimmed_clone, ' ');
|
|
// terminate input_one
|
|
if (ptr_str_clone) {
|
|
*ptr_str_clone = '\0';
|
|
input_two = (++ptr_str_clone);
|
|
ptr_str_clone = strchr (input_two, ' ');
|
|
}
|
|
|
|
// terminate input_two
|
|
if (ptr_str_clone && input_two) {
|
|
*ptr_str_clone = '\0';
|
|
input_three = (++ptr_str_clone);
|
|
ptr_str_clone = strchr (input_three, ' ');
|
|
}
|
|
|
|
// terminate input_three
|
|
if (ptr_str_clone && input_three) {
|
|
*ptr_str_clone = '\0';
|
|
ptr_str_clone = strchr (input_three, ' ');
|
|
}
|
|
|
|
// command formats
|
|
// <size> <arch> <bits>
|
|
// <size> <arch>
|
|
// <size> <bits>
|
|
// <arch> <bits>
|
|
// <arch>
|
|
|
|
// initialize
|
|
*asm_arch = NULL;
|
|
*blocksize = *bits = -1;
|
|
|
|
if (input_one && input_two && input_three) {
|
|
// <size> <arch> <bits>
|
|
*blocksize = r_num_is_valid_input (core->num, input_one) ? r_num_get_input_value (core->num, input_one): 0;
|
|
*asm_arch = r_asm_is_valid (core->assembler, input_two) ? strdup (input_two) : NULL;
|
|
*bits = r_num_get_input_value (core->num, input_three);
|
|
result = true;
|
|
|
|
} else if (input_one && input_two) {
|
|
|
|
*blocksize = r_num_is_valid_input (core->num, input_one) ? r_num_get_input_value (core->num, input_one): 0;
|
|
|
|
if (!r_num_is_valid_input (core->num, input_one) ) {
|
|
// input_one can only be one other thing
|
|
*asm_arch = r_asm_is_valid (core->assembler, input_one) ? strdup (input_one) : NULL;
|
|
*bits = r_num_is_valid_input (core->num, input_two) ? r_num_get_input_value (core->num, input_two): -1;
|
|
} else {
|
|
if (r_str_contains_macro (input_two) ){
|
|
r_str_truncate_cmd (input_two);
|
|
}
|
|
*bits = r_num_is_valid_input (core->num, input_two) ? r_num_get_input_value (core->num, input_two): -1;
|
|
*asm_arch = r_asm_is_valid (core->assembler, input_two) ? strdup (input_two) : NULL;
|
|
}
|
|
|
|
result = true;
|
|
} else if (input_one) {
|
|
*blocksize = r_num_is_valid_input (core->num, input_one) ? r_num_get_input_value (core->num, input_one): 0;
|
|
if (!r_num_is_valid_input (core->num, input_one) ) {
|
|
// input_one can only be one other thing
|
|
if (r_str_contains_macro (input_one))
|
|
r_str_truncate_cmd (input_one);
|
|
*asm_arch = r_asm_is_valid (core->assembler, input_one) ? strdup (input_one) : NULL;
|
|
}
|
|
result = true;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/* This function is not necessary anymore, but it's kept for discussion */
|
|
static int process_input_pade(RCore *core, const char *input, char** hex, char **asm_arch, ut32 *bits) {
|
|
// input: start of the input string e.g. after the command symbols have been consumed
|
|
// size: hex if present, otherwise -1
|
|
// asm_arch: asm_arch to interpret as if present and valid, otherwise NULL;
|
|
// bits: bits to use if present, otherwise -1
|
|
|
|
int result = false;
|
|
char *input_one = NULL, *input_two = NULL, *input_three = NULL;
|
|
char *str_clone = NULL,
|
|
*trimmed_clone = NULL;
|
|
|
|
if (input == NULL || hex == NULL || asm_arch == NULL || bits == NULL) {
|
|
return false;
|
|
}
|
|
|
|
str_clone = strdup (input);
|
|
trimmed_clone = r_str_trim_head_tail (str_clone);
|
|
|
|
input_one = trimmed_clone;
|
|
|
|
#if 0
|
|
char *ptr_str_clone = NULL;
|
|
ptr_str_clone = strchr (trimmed_clone, ' ');
|
|
// terminate input_one
|
|
if (ptr_str_clone) {
|
|
*ptr_str_clone = '\0';
|
|
input_two = (++ptr_str_clone);
|
|
ptr_str_clone = strchr (input_two, ' ');
|
|
}
|
|
|
|
// terminate input_two
|
|
if (ptr_str_clone && input_two) {
|
|
*ptr_str_clone = '\0';
|
|
input_three = (++ptr_str_clone);
|
|
ptr_str_clone = strchr (input_three, ' ');
|
|
}
|
|
|
|
// terminate input_three
|
|
if (ptr_str_clone && input_three) {
|
|
*ptr_str_clone = '\0';
|
|
ptr_str_clone = strchr (input_three, ' ');
|
|
}
|
|
#endif
|
|
|
|
// command formats
|
|
// <hex> <arch> <bits>
|
|
// <hex> <arch>
|
|
// <hex> <bits>
|
|
// <hex>
|
|
|
|
// initialize
|
|
*hex = *asm_arch = NULL;
|
|
*bits = -1;
|
|
|
|
if (input_one && input_two && input_three) {
|
|
// <size> <arch> <bits>
|
|
*hex = input_one;
|
|
*asm_arch = r_asm_is_valid (core->assembler, input_two) ? strdup (input_two) : NULL;
|
|
*bits = r_num_get_input_value (core->num, input_three);
|
|
result = true;
|
|
|
|
} else if (input_one && input_two) {
|
|
*hex = input_one;
|
|
if (r_str_contains_macro (input_two) ){
|
|
r_str_truncate_cmd (input_two);
|
|
}
|
|
*bits = r_num_is_valid_input (core->num, input_two) ? r_num_get_input_value (core->num, input_two): -1;
|
|
*asm_arch = r_asm_is_valid (core->assembler, input_two) ? strdup (input_two) : NULL;
|
|
result = true;
|
|
} else if (input_one) {
|
|
*hex = input_one;
|
|
result = true;
|
|
} else {
|
|
free (input_one);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static void print_format_help(RCore *core) {
|
|
const char* help_msg[] = {
|
|
"pf:", "pf[.k[.f[=v]]|[ v]]|[n]|[0][ [sz] fmt] [a0 a1 ...]", "",
|
|
"Commands:","","",
|
|
"pf", "?", "Show this help",
|
|
"pf", "??", "Format characters",
|
|
"pf", "???", "pf usage examples",
|
|
"pf", " xsi foo bar cow", "format named hex str and int (see `pf??`)",
|
|
"pf.", "", "List all formats",
|
|
"pf?", "fmt_name", "Show format of that stored one",
|
|
"pfs", " fmt_name", "Print the size of the format in bytes",
|
|
"pfo", "", "List all format files",
|
|
"pfo", " elf32", "Load the elf32 format definition file",
|
|
"pf.", "fmt_name", "Run stored format",
|
|
"pf.", "fmt_name.field_name", "Show specific field inside format",
|
|
"pf.", "fmt_name.size=33", "Set new value for the size field in obj",
|
|
"pfj.", "fmt_name", "Print format in JSON",
|
|
"pfv.", "fmt_name", "Print the value(s) only. Useful for one-liners",
|
|
"pf*.", "fmt_name", "Display flag commands",
|
|
"pfd.", "fmt_name", "Display graphviz commands",
|
|
NULL};
|
|
r_core_cmd_help (core, help_msg);
|
|
}
|
|
|
|
static void print_format_help_help(RCore *core) {
|
|
const char* help_msg[] = {
|
|
"pf:", "pf[.k[.f[=v]]|[ v]]|[n]|[0][ [sz] fmt] [a0 a1 ...]", "",
|
|
"Format:", "", "",
|
|
" ", "b", "byte (unsigned)",
|
|
" ", "B", "resolve enum bitfield (see t?)",
|
|
" ", "c", "char (signed byte)",
|
|
" ", "d", "0x%%08x hexadecimal value (4 bytes)",
|
|
" ", "D", "disassemble one opcode",
|
|
" ", "e", "temporally swap endian",
|
|
" ", "E", "resolve enum name (see t?)",
|
|
" ", "f", "float value (4 bytes)",
|
|
" ", "i", "%%i integer value (4 bytes)",
|
|
" ", "o", "0x%%08o octal value (4 byte)",
|
|
" ", "p", "pointer reference (2, 4 or 8 bytes)",
|
|
" ", "q", "quadword (8 bytes)",
|
|
" ", "r", "CPU register `pf r (eax)plop`",
|
|
" ", "s", "32bit pointer to string (4 bytes)",
|
|
" ", "S", "64bit pointer to string (8 bytes)",
|
|
" ", "t", "UNIX timestamp (4 bytes)",
|
|
" ", "T", "show Ten first bytes of buffer",
|
|
" ", "u", "uleb128 (variable length)",
|
|
" ", "w", "word (2 bytes unsigned short in hex)",
|
|
" ", "x", "0x%%08x hex value and flag (fd @ addr)",
|
|
" ", "X", "show formatted hexpairs",
|
|
" ", "z", "\\0 terminated string",
|
|
" ", "Z", "\\0 terminated wide string",
|
|
" ", "?", "data structure `pf ? (struct_name)example_name`",
|
|
" ", "*", "next char is pointer (honors asm.bits)",
|
|
" ", "+", "toggle show flags for each offset",
|
|
" ", ":", "skip 4 bytes",
|
|
" ", ".", "skip 1 byte",
|
|
NULL};
|
|
r_core_cmd_help (core, help_msg);
|
|
}
|
|
|
|
static void print_format_help_help_help(RCore *core) {
|
|
const char* help_msg[] = {
|
|
"pf:", "pf[.k[.f[=v]]|[ v]]|[n]|[0][ [sz] fmt] [a0 a1 ...]", "",
|
|
"Examples:","","",
|
|
"pf", " B (BitFldType)arg_name`", "bitfield type",
|
|
"pf", " E (EnumType)arg_name`", "enum type",
|
|
"pf.", "obj xxdz prev next size name", "Define the obj format as xxdz",
|
|
"pf", " obj=xxdz prev next size name", "Same as above",
|
|
"pf", " iwq foo bar troll", "Print the iwq format with foo, bar, troll as the respective names for the fields",
|
|
"pf", " 0iwq foo bar troll", "Same as above, but considered as a union (all fields at offset 0)",
|
|
"pf.", "plop ? (troll)mystruct", "Use structure troll previously defined",
|
|
"pf", " 10xiz pointer length string", "Print a size 10 array of the xiz struct with its field names",
|
|
"pf", " {integer}bifc", "Print integer times the following format (bifc)",
|
|
"pf", " [4]w[7]i", "Print an array of 4 words and then an array of 7 integers",
|
|
NULL};
|
|
r_core_cmd_help (core, help_msg);
|
|
}
|
|
|
|
static void print_format_help_help_help_help(RCore *core) {
|
|
const char* help_msg[] = {
|
|
" STAHP IT!!!", "", "",
|
|
NULL};
|
|
r_core_cmd_help (core, help_msg);
|
|
}
|
|
|
|
static void cmd_print_format (RCore *core, const char *_input, int len) {
|
|
char *input;
|
|
int mode = R_PRINT_MUSTSEE;
|
|
switch (_input[1]) {
|
|
case '*':
|
|
_input++;
|
|
mode = R_PRINT_SEEFLAGS;
|
|
break;
|
|
case 'd':
|
|
_input++;
|
|
mode = R_PRINT_DOT;
|
|
break;
|
|
case 'j':
|
|
_input++;
|
|
mode = R_PRINT_JSON;
|
|
break;
|
|
case 'v':
|
|
_input++;
|
|
mode = R_PRINT_VALUE | R_PRINT_MUSTSEE;
|
|
break;
|
|
case 's':
|
|
{
|
|
const char *val = NULL;
|
|
_input+=2;
|
|
if (*_input == '.') {
|
|
_input++;
|
|
val = r_strht_get (core->print->formats, _input);
|
|
if (val != NULL)
|
|
r_cons_printf ("%d bytes\n", r_print_format_struct_size (val, core->print, mode));
|
|
else {
|
|
eprintf ("Struct %s not defined\nUsage: pfs.struct_name | pfs format\n", _input);
|
|
}
|
|
} else if (*_input == ' ') {
|
|
while (*_input == ' ' && *_input != '\0') _input++;
|
|
if (_input != '\0')
|
|
r_cons_printf ("%d bytes\n", r_print_format_struct_size (_input, core->print, mode));
|
|
else {
|
|
eprintf ("Struct %s not defined\nUsage: pfs.struct_name | pfs format\n", _input);
|
|
}
|
|
} else {
|
|
eprintf ("Usage: pfs.struct_name | pfs format\n");
|
|
}
|
|
}
|
|
return;
|
|
case '?':
|
|
_input+=2;
|
|
if (*_input) {
|
|
if (*_input == '?') {
|
|
_input++;
|
|
if (_input && *_input == '?') {
|
|
_input++;
|
|
if (_input && *_input == '?') {
|
|
print_format_help_help_help_help (core);
|
|
} else {
|
|
print_format_help_help_help (core);
|
|
}
|
|
} else {
|
|
print_format_help_help (core);
|
|
}
|
|
} else {
|
|
RListIter *iter;
|
|
RStrHT *sht = core->print->formats;
|
|
int *i;
|
|
r_list_foreach (sht->ls, iter, i) {
|
|
int idx = ((int)(size_t)i)-1;
|
|
const char *key = r_strpool_get (sht->sp, idx);
|
|
if (!strcmp (_input, key)) {
|
|
const char *val = r_strht_get (core->print->formats, key);
|
|
r_cons_printf ("%s\n", val);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
print_format_help (core);
|
|
}
|
|
return;
|
|
}
|
|
|
|
input = strdup (_input);
|
|
// "pfo" // open formatted thing
|
|
if (input[1]=='o') { // "pfo"
|
|
if (input[2] == '?') {
|
|
eprintf ("|Usage: pfo [format-file]\n"
|
|
" ~/.config/radare2/format\n"
|
|
" "R2_DATDIR"/radare2/"R2_VERSION"/format/\n");
|
|
} else if (input[2] == ' ') {
|
|
char *home, path[512];
|
|
snprintf (path, sizeof (path), ".config/radare2/format/%s", input+3);
|
|
home = r_str_home (path);
|
|
snprintf (path, sizeof (path), R2_DATDIR"/radare2/"
|
|
R2_VERSION"/format/%s", input+3);
|
|
if (!r_core_cmd_file (core, home))
|
|
if (!r_core_cmd_file (core, path))
|
|
if (!r_core_cmd_file (core, input+3))
|
|
eprintf ("ecf: cannot open colorscheme profile (%s)\n", path);
|
|
free (home);
|
|
} else {
|
|
RList *files;
|
|
RListIter *iter;
|
|
const char *fn;
|
|
char *home = r_str_home (".config/radare2/format/");
|
|
if (home) {
|
|
files = r_sys_dir (home);
|
|
r_list_foreach (files, iter, fn) {
|
|
if (*fn && *fn != '.')
|
|
r_cons_printf ("%s\n", fn);
|
|
}
|
|
r_list_free (files);
|
|
free (home);
|
|
}
|
|
files = r_sys_dir (R2_DATDIR"/radare2/"R2_VERSION"/format/");
|
|
r_list_foreach (files, iter, fn) {
|
|
if (*fn && *fn != '.')
|
|
r_cons_printf ("%s\n", fn);
|
|
}
|
|
r_list_free (files);
|
|
}
|
|
free (input);
|
|
return;
|
|
}
|
|
/* syntax aliasing bridge for 'pf foo=xxd' -> 'pf.foo xxd' */
|
|
if (input[1]==' ') {
|
|
char *eq = strchr (input+2, '=');
|
|
if (eq) {
|
|
input[1] = '.';
|
|
*eq = ' ';
|
|
}
|
|
}
|
|
|
|
int listFormats = 0;
|
|
if (input[1]=='.')
|
|
listFormats = 1;
|
|
if (!strcmp (input, "*") && mode == R_PRINT_SEEFLAGS)
|
|
listFormats = 1;
|
|
|
|
core->print->reg = core->dbg->reg;
|
|
core->print->get_register = r_reg_get;
|
|
core->print->get_register_value = r_reg_get_value;
|
|
|
|
int o_blocksize = core->blocksize;
|
|
|
|
if (listFormats) {
|
|
core->print->num = core->num;
|
|
/* print all stored format */
|
|
if (input[1]==0 || input[2]=='\0') {
|
|
RListIter *iter;
|
|
RStrHT *sht = core->print->formats;
|
|
int *i;
|
|
r_list_foreach (sht->ls, iter, i) {
|
|
int idx = ((int)(size_t)i)-1;
|
|
const char *key = r_strpool_get (sht->sp, idx);
|
|
const char *val = r_strht_get (core->print->formats, key);
|
|
r_cons_printf ("pf.%s %s\n", key, val);
|
|
}
|
|
/* delete a format */
|
|
} else if (input[1] && input[2]=='-') {
|
|
if (input[2] && input[3]) r_strht_del (core->print->formats, input+3);
|
|
else r_strht_clear (core->print->formats);
|
|
} else {
|
|
char *name = strdup (input+(input[1]?2:1));
|
|
char *space = strchr (name, ' ');
|
|
char *eq = strchr (name, '=');
|
|
char *dot = strchr (name, '.');
|
|
|
|
if (eq && !dot) {
|
|
*eq = ' ';
|
|
space = eq;
|
|
eq = NULL;
|
|
}
|
|
|
|
/* store a new format */
|
|
if (space && (eq == NULL || space < eq)) {
|
|
char *fields = NULL;
|
|
*space++ = 0;
|
|
fields = strchr (space, ' ');
|
|
if (strchr (name, '.') != NULL || (fields != NULL && strchr(fields, '.') != NULL))
|
|
eprintf ("Struct or fields name can not contain dot symbol (.)\n");
|
|
else
|
|
r_strht_set (core->print->formats, name, space);
|
|
free (name);
|
|
free (input);
|
|
return;
|
|
}
|
|
|
|
if (strchr (name, '.') == NULL && r_strht_get (core->print->formats, name) == NULL) {
|
|
eprintf ("Cannot find '%s' format.\n", name);
|
|
free (name);
|
|
free (input);
|
|
return;
|
|
}
|
|
|
|
/* Load format from name into fmt to get the size */
|
|
/* This make sure the whole structure will be printed */
|
|
const char *fmt = NULL;
|
|
fmt = r_strht_get (core->print->formats, name);
|
|
if (fmt != NULL) {
|
|
int size = r_print_format_struct_size (fmt, core->print, mode)+10;
|
|
if (size > core->blocksize)
|
|
r_core_block_size (core, size);
|
|
}
|
|
/* display a format */
|
|
if (dot) {
|
|
*dot++ = 0;
|
|
eq = strchr (dot, '=');
|
|
if (eq) { // Write mode (pf.field=value)
|
|
*eq++ = 0;
|
|
mode = R_PRINT_MUSTSET;
|
|
r_print_format (core->print, core->offset,
|
|
core->block, core->blocksize, name, mode, eq, dot);
|
|
} else {
|
|
r_print_format (core->print, core->offset,
|
|
core->block, core->blocksize, name, mode, NULL, dot);
|
|
}
|
|
} else {
|
|
r_print_format (core->print, core->offset,
|
|
core->block, core->blocksize, name, mode, NULL, NULL);
|
|
}
|
|
free (name);
|
|
}
|
|
} else {
|
|
/* This make sure the structure will be printed entirely */
|
|
char *fmt = input+1;
|
|
int size = 0;
|
|
while (*fmt && iswhitechar (*fmt)) fmt++;
|
|
size = r_print_format_struct_size (fmt, core->print, mode)+10;
|
|
if (size > core->blocksize)
|
|
r_core_block_size (core, size);
|
|
r_print_format (core->print, core->offset,
|
|
core->block, core->blocksize, fmt, mode, NULL, NULL);
|
|
}
|
|
free (input);
|
|
r_core_block_size (core, o_blocksize);
|
|
}
|
|
|
|
// > 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); }
|
|
static void annotated_hexdump(RCore *core, const char *str, int len) {
|
|
const int usecolor = r_config_get_i (core->config, "scr.color");
|
|
int nb_cols = r_config_get_i (core->config, "hex.cols");
|
|
int flagsz = r_config_get_i (core->config, "hex.flagsz");
|
|
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;
|
|
char *comment;
|
|
int i, j, low, max, here, rows;
|
|
boolt marks = false, setcolor = true, hascolor = false;
|
|
ut8 ch;
|
|
const char **colors = (const char **)&core->cons->pal.list;
|
|
#if 0
|
|
const char *colors[] = {
|
|
Color_WHITE, /*Color_GREEN,*/ Color_YELLOW, Color_RED,
|
|
Color_CYAN, Color_MAGENTA, Color_GRAY, Color_BLUE
|
|
};
|
|
#endif
|
|
// const char* colors[] = Colors_PLAIN;
|
|
const int col = core->print->col;
|
|
RFlagItem *flag, *current_flag = NULL;
|
|
char** note;
|
|
int html = r_config_get_i (core->config, "scr.html");
|
|
int nb_cons_cols;
|
|
|
|
// Adjust the number of columns
|
|
if (nb_cols < 1)
|
|
nb_cols = 16;
|
|
nb_cols -= (nb_cols % 2); //nb_cols should be even
|
|
|
|
nb_cons_cols = 12 + nb_cols * 2 + (nb_cols/2);
|
|
nb_cons_cols += 17;
|
|
rows = len/nb_cols;
|
|
|
|
chars = calloc (nb_cols * 20, sizeof(char));
|
|
if (!chars)
|
|
return;
|
|
note = calloc (nb_cols, sizeof(char*));
|
|
if (!note) {
|
|
free (chars);
|
|
return;
|
|
}
|
|
bytes = calloc (nb_cons_cols*20, sizeof(char));
|
|
if (!bytes) {
|
|
free (chars);
|
|
free (note);
|
|
return;
|
|
}
|
|
#if 1
|
|
int addrpadlen = strlen (sdb_fmt (0, "%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 - ");
|
|
#endif
|
|
j = strlen (bytes);
|
|
for (i=0; i<nb_cols; i+=2) {
|
|
sprintf (bytes+j, " %X %X ", (i&0xf), (i+1)&0xf);
|
|
j += 5;
|
|
}
|
|
sprintf (bytes+j+i, " ");
|
|
j++;
|
|
for (i=0; i<nb_cols; i++)
|
|
sprintf (bytes+j+i, "%0X", i%17);
|
|
if (usecolor) r_cons_strcat (Color_GREEN);
|
|
r_cons_strcat (bytes);
|
|
if (usecolor) r_cons_strcat (Color_RESET);
|
|
r_cons_newline ();
|
|
|
|
//hexdump
|
|
for (i=0; i<rows; i++) {
|
|
bytes[0] = '\0';
|
|
chars[0] = '\0';
|
|
ebytes = bytes;
|
|
echars = chars;
|
|
hascolor = false;
|
|
|
|
if (usecolor) append (ebytes, core->cons->pal.offset);
|
|
ebytes += sprintf (ebytes, "0x%08"PFMT64x, addr);
|
|
if (usecolor) append (ebytes, Color_RESET);
|
|
append (ebytes, (col==1)?" |":" ");
|
|
|
|
for (j=0; j<nb_cols; j++) {
|
|
setcolor = true;
|
|
free (note[j]);
|
|
note[j] = NULL;
|
|
|
|
// collect comments
|
|
comment = r_meta_get_string (core->anal, R_META_TYPE_COMMENT, addr+j);
|
|
if (comment) {
|
|
comment = r_str_prefix (comment, ";");
|
|
note[j] = comment;
|
|
marks = true;
|
|
}
|
|
|
|
// collect flags
|
|
flag = r_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;
|
|
}
|
|
note[j] = r_str_prefix (strdup (flag->name), "/");
|
|
marks = true;
|
|
color_idx++;
|
|
color_idx %= R_CONS_PALETTE_LIST_SIZE;
|
|
current_flag = flag;
|
|
} 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 (setcolor && !hascolor) {
|
|
hascolor = true;
|
|
if (usecolor) {
|
|
if (current_flag && current_flag->color) {
|
|
char *ansicolor = r_cons_pal_parse (current_flag->color);
|
|
append (ebytes, ansicolor);
|
|
append (echars, ansicolor);
|
|
free (ansicolor);
|
|
} else { // Use "random" colours
|
|
append (ebytes, colors[color_idx]);
|
|
append (echars, colors[color_idx]);
|
|
}
|
|
} else {
|
|
if (html) {
|
|
append (ebytes, "[");
|
|
} else {
|
|
append (ebytes, Color_INVERT);
|
|
}
|
|
}
|
|
}
|
|
here = R_MIN ((i * nb_cols) + j, core->blocksize);
|
|
ch = buf[here];
|
|
if (core->print->ocur!=-1) {
|
|
low = R_MIN (core->print->cur, core->print->ocur);
|
|
max = R_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) {
|
|
append (ebytes, "[");
|
|
append (echars, "[");
|
|
} else {
|
|
append (echars, Color_INVERT);
|
|
append (ebytes, Color_INVERT);
|
|
}
|
|
}
|
|
} else {
|
|
if (here >= low && here <max) {
|
|
if (html) {
|
|
append (ebytes, "[");
|
|
append (echars, "[");
|
|
} else {
|
|
append (ebytes, Color_INVERT);
|
|
append (echars, Color_INVERT);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
sprintf (ebytes, "%02x", ch);
|
|
ebytes += strlen (ebytes);
|
|
sprintf (echars, "%c", IS_PRINTABLE (ch)?ch:'.');
|
|
echars++;
|
|
if (core->print->cur_enabled && max == here) {
|
|
if (!html) {
|
|
append (ebytes, Color_RESET);
|
|
append (echars, Color_RESET);
|
|
}
|
|
hascolor = false;
|
|
}
|
|
|
|
if (j < (nb_cols-1) && (j%2))
|
|
append (ebytes, " ");
|
|
|
|
if (fend != UT64_MAX && fend == addr+j+1) {
|
|
if (!html) {
|
|
append (ebytes, Color_RESET);
|
|
append (echars, Color_RESET);
|
|
}
|
|
fend = UT64_MAX;
|
|
hascolor = false;
|
|
}
|
|
|
|
}
|
|
if (!html) {
|
|
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 = R_MIN (notej_len, nb_cons_cols-off);
|
|
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] != ' ');
|
|
R_FREE (note[j]);
|
|
}
|
|
}
|
|
out[out_sz-1] = 0;
|
|
if (hasline) {
|
|
r_cons_strcat (addrpad);
|
|
r_cons_strcat (out);
|
|
r_cons_newline ();
|
|
}
|
|
marks = false;
|
|
free (out);
|
|
}
|
|
r_cons_strcat (bytes);
|
|
r_cons_strcat (chars);
|
|
r_cons_newline ();
|
|
addr += nb_cols;
|
|
}
|
|
free (note);
|
|
free (bytes);
|
|
free (chars);
|
|
}
|
|
|
|
R_API void r_core_print_examine(RCore *core, const char *str) {
|
|
char cmd[128], *p;
|
|
ut64 addr = core->offset;
|
|
int size = (core->anal->bits/4);
|
|
int count = atoi (str);
|
|
int i, n;
|
|
if (count<1) count = 1;
|
|
// skipsapces
|
|
while (*str>='0' && *str<='9') str++;
|
|
|
|
// "px/" alone isn't a full command.
|
|
if (!str[0]) return;
|
|
#if 0
|
|
Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).
|
|
#endif
|
|
switch (str[1]) {
|
|
case 'b': size = 1; break;
|
|
case 'h': size = 2; break;
|
|
case 'd': size = 4; break;
|
|
case 'w': size = 4; break;
|
|
case 'g': size = 8; break;
|
|
}
|
|
if ((p=strchr (str, ' ')))
|
|
addr = r_num_math (core->num, p+1);
|
|
switch (*str) {
|
|
case '?':
|
|
eprintf (
|
|
"Format is x/[num][format][size]\n"
|
|
"Num specifies the number of format elements to display\n"
|
|
"Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal),\n"
|
|
" t(binary), f(float), a(address), i(instruction), c(char) and s(string),\n"
|
|
" T(OSType), A(floating point values in hex).\n"
|
|
"Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).\n"
|
|
);
|
|
break;
|
|
case 's':
|
|
r_core_cmdf (core, "psb %d @ 0x%"PFMT64x, count*size, addr);
|
|
break;
|
|
case 'o':
|
|
r_core_cmdf (core, "pxo %d @ 0x%"PFMT64x, count*size, addr);
|
|
break;
|
|
case 'f':
|
|
case 'A': // XXX (float in hex wtf)
|
|
n = 3;
|
|
snprintf (cmd, sizeof (cmd), "pxo %d @ 0x%"PFMT64x,
|
|
count*size, addr);
|
|
strcpy (cmd, "pf ");
|
|
for (i=0;i<count && n<sizeof (cmd);i++)
|
|
cmd[n++] = 'f';
|
|
cmd[n] = 0;
|
|
r_core_cmd0 (core, cmd);
|
|
break;
|
|
case 'x':
|
|
r_core_cmdf (core, "px %d @ 0x%"PFMT64x, count, addr);
|
|
break;
|
|
case 'a':
|
|
case 'd':
|
|
r_core_cmdf (core, "pxw %d @ 0x%"PFMT64x, count*size, addr);
|
|
break;
|
|
case 'i':
|
|
r_core_cmdf (core, "pid %d @ 0x%"PFMT64x, count, addr);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int printzoomcallback(void *user, int mode, ut64 addr, ut8 *bufz, ut64 size) {
|
|
RCore *core = (RCore *) user;
|
|
int j, ret = 0;
|
|
RListIter *iter;
|
|
RFlagItem *flag;
|
|
|
|
switch (mode) {
|
|
case 'p':
|
|
for (j=0; j<size; j++)
|
|
if (IS_PRINTABLE (bufz[j]))
|
|
ret++;
|
|
break;
|
|
case 'f':
|
|
r_list_foreach (core->flags->flags, iter, flag)
|
|
if (flag->offset <= addr && addr < flag->offset+flag->size)
|
|
ret++;
|
|
break;
|
|
case 's':
|
|
j = r_flag_space_get (core->flags, "strings");
|
|
r_list_foreach (core->flags->flags, iter, flag) {
|
|
if (flag->space == j && ((addr <= flag->offset
|
|
&& flag->offset < addr+size)
|
|
|| (addr <= flag->offset+flag->size
|
|
&& flag->offset+flag->size < addr+size)))
|
|
ret++;
|
|
}
|
|
break;
|
|
case '0': // 0x00
|
|
for (j=0; j<size; j++)
|
|
if (bufz[j] == 0)
|
|
ret++;
|
|
break;
|
|
case 'F': // 0xFF
|
|
for (j=0; j<size; j++)
|
|
if (bufz[j] == 0xff)
|
|
ret++;
|
|
break;
|
|
case 'e': // entropy
|
|
ret = (ut8) (r_hash_entropy_fraction (bufz, size)*255);
|
|
break;
|
|
case 'h': // head
|
|
default:
|
|
ret = *bufz;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
R_API void r_core_print_cmp(RCore *core, ut64 from, ut64 to) {
|
|
long int delta = 0;
|
|
int col = core->cons->columns>123;
|
|
ut8 *b = malloc (core->blocksize);
|
|
ut64 addr = core->offset;
|
|
memset (b, 0xff, core->blocksize);
|
|
delta = addr - from;
|
|
r_core_read_at (core, to+delta, b, core->blocksize);
|
|
r_print_hexdiff (core->print, core->offset, core->block,
|
|
to+delta, b, core->blocksize, col);
|
|
free (b);
|
|
}
|
|
|
|
static int pdi(RCore *core, int nb_opcodes, int nb_bytes, int fmt) {
|
|
int show_offset = r_config_get_i (core->config, "asm.offset");
|
|
int show_bytes = r_config_get_i (core->config, "asm.bytes");
|
|
int decode = r_config_get_i (core->config, "asm.decode");
|
|
int filter = r_config_get_i (core->config, "asm.filter");
|
|
int show_color = r_config_get_i (core->config, "scr.color");
|
|
int esil = r_config_get_i (core->config, "asm.esil");
|
|
int flags = r_config_get_i (core->config, "asm.flags");
|
|
int i=0, j, ret, err = 0;
|
|
ut64 old_offset = core->offset;
|
|
RAsmOp asmop;
|
|
#define PAL(x) (core->cons && core->cons->pal.x)? core->cons->pal.x
|
|
const char *color_reg = PAL(reg): Color_YELLOW;
|
|
const char *color_num = PAL(num): Color_CYAN;
|
|
|
|
if (fmt=='e') {
|
|
show_bytes = 0;
|
|
decode = 1;
|
|
}
|
|
if (!nb_opcodes && !nb_bytes) return 0;
|
|
|
|
if (!nb_opcodes) {
|
|
nb_opcodes = 0xffff;
|
|
if (nb_bytes < 0) {
|
|
// Backward disasm `nb_bytes` bytes
|
|
nb_bytes = -nb_bytes;
|
|
core->offset -= nb_bytes;
|
|
r_core_read_at (core, core->offset, core->block, nb_bytes);
|
|
}
|
|
} else if (!nb_bytes) {
|
|
if (nb_opcodes < 0) {
|
|
/* Backward disassembly of `ilen` opcodes
|
|
* - We compute the new starting offset
|
|
* - Read at the new offset */
|
|
nb_opcodes = -nb_opcodes;
|
|
r_core_asm_bwdis_len (core, &nb_bytes, &core->offset, nb_opcodes);
|
|
r_core_read_at (core, core->offset, core->block, nb_bytes);
|
|
} else {
|
|
// workaround for the `for` loop below
|
|
nb_bytes = core->blocksize;
|
|
}
|
|
}
|
|
|
|
// XXX - is there a better way to reset a the analysis counter so that
|
|
// when code is disassembled, it can actually find the correct offsets
|
|
if (core->anal && core->anal->cur && core->anal->cur->reset_counter ) {
|
|
core->anal->cur->reset_counter (core->anal, core->offset);
|
|
}
|
|
|
|
int len = (nb_opcodes + nb_bytes) * 5;
|
|
if (core->fixedblock) {
|
|
len = core->blocksize;
|
|
} else {
|
|
if (len > core->blocksize) {
|
|
r_core_block_size (core, len);
|
|
r_core_block_read (core, 0);
|
|
}
|
|
}
|
|
r_cons_break (NULL, NULL);
|
|
#define isTheEnd (nb_opcodes? nb_bytes? (j<nb_opcodes && i<nb_bytes) : j<nb_opcodes: i<nb_bytes)
|
|
for (i=j=0; isTheEnd; j++) {
|
|
RFlagItem *item;
|
|
if (r_cons_singleton ()->breaked) {
|
|
err = 1;
|
|
break;
|
|
}
|
|
r_asm_set_pc (core->assembler, core->offset+i);
|
|
ret = r_asm_disassemble (core->assembler, &asmop, core->block+i,
|
|
core->blocksize-i);
|
|
if (flags) {
|
|
if (fmt != 'e') { // pie
|
|
item = r_flag_get_i (core->flags, core->offset+i);
|
|
if (item) {
|
|
if (show_offset)
|
|
r_cons_printf ("0x%08"PFMT64x" ", core->offset+i);
|
|
r_cons_printf (" %s:\n", item->name);
|
|
}
|
|
} // do not show flags in pie
|
|
}
|
|
if (show_offset) {
|
|
const int show_offseg = 0;
|
|
ut64 at = core->offset + i;
|
|
r_print_offset (core->print, at, 0, show_offseg, 0);
|
|
}
|
|
// r_cons_printf ("0x%08"PFMT64x" ", core->offset+i);
|
|
if (ret<1) {
|
|
err = 1;
|
|
ret = asmop.size;
|
|
if (ret<1) ret = 1;
|
|
if (show_bytes)
|
|
r_cons_printf ("%14s%02x ", "", core->block[i]);
|
|
r_cons_printf ("%s\n", "invalid"); //???");
|
|
} else {
|
|
if (show_bytes)
|
|
r_cons_printf ("%16s ", asmop.buf_hex);
|
|
ret = asmop.size;
|
|
if (decode || esil) {
|
|
RAnalOp analop = {0};
|
|
char *tmpopstr, *opstr = NULL;
|
|
r_anal_op (core->anal, &analop, core->offset+i,
|
|
core->block+i, core->blocksize-i);
|
|
tmpopstr = r_anal_op_to_string (core->anal, &analop);
|
|
if (fmt == 'e') { // pie
|
|
char *esil = (R_STRBUF_SAFEGET (&analop.esil));
|
|
r_cons_printf ("%s\n", esil);
|
|
} else {
|
|
if (decode) {
|
|
opstr = (tmpopstr)? tmpopstr: (asmop.buf_asm);
|
|
} else if (esil) {
|
|
opstr = (R_STRBUF_SAFEGET (&analop.esil));
|
|
}
|
|
r_cons_printf ("%s\n", opstr);
|
|
}
|
|
} else {
|
|
if (filter) {
|
|
char opstr[128] = {0};
|
|
if (show_color) {
|
|
RAnalOp aop = {0};
|
|
char *asm_str = r_print_colorize_opcode (asmop.buf_asm, color_reg, color_num);
|
|
r_anal_op (core->anal, &aop, core->offset+i,
|
|
core->block+i, core->blocksize-i);
|
|
r_parse_filter (core->parser, core->flags,
|
|
asm_str, opstr, sizeof (opstr)-1);
|
|
r_cons_printf ("%s%s"Color_RESET"\n", r_print_color_op_type (core->print, aop.type), opstr);
|
|
} else {
|
|
r_parse_filter (core->parser, core->flags,
|
|
asmop.buf_asm, opstr, sizeof (opstr)-1);
|
|
r_cons_printf ("%s\n", opstr);
|
|
}
|
|
} else {
|
|
if (show_color) {
|
|
RAnalOp aop;
|
|
r_anal_op (core->anal, &aop, core->offset+i,
|
|
core->block+i, core->blocksize-i);
|
|
r_cons_printf ("%s%s"Color_RESET"\n",
|
|
r_print_color_op_type (core->print, aop.type),
|
|
asmop.buf_asm);
|
|
} else {
|
|
r_cons_printf ("%s\n", asmop.buf_asm);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
i += ret;
|
|
#if 0
|
|
if ((nb_bytes && (nb_bytes <= i)) || (i >= core->blocksize))
|
|
break;
|
|
#endif
|
|
}
|
|
r_cons_break_end ();
|
|
core->offset = old_offset;
|
|
return err;
|
|
}
|
|
|
|
static void cmd_print_pwn(const RCore* core) {
|
|
r_cons_printf ("easter egg license has expired\n");
|
|
}
|
|
|
|
static int cmd_print_pxA(RCore *core, int len, const char *data) {
|
|
RConsPalette *pal = &core->cons->pal;
|
|
int show_offset = true;
|
|
int cols = r_config_get_i (core->config, "hex.cols");
|
|
int show_color = r_config_get_i (core->config, "scr.color");
|
|
int onechar = r_config_get_i (core->config, "hex.onechar");
|
|
int show_cursor = core->print->cur_enabled;
|
|
int bgcolor_in_heap = false;
|
|
char buf[2];
|
|
char *bgcolor, *fgcolor, *text;
|
|
ut64 i, c, oi;
|
|
RAnalOp op;
|
|
|
|
if (len < 0 || len > core->blocksize) {
|
|
eprintf ("Invalid length\n");
|
|
return 0;
|
|
}
|
|
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;
|
|
r_cons_printf (" %d\n", i-oi);
|
|
oi = i;
|
|
}
|
|
if (show_offset) {
|
|
r_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;
|
|
if (!r_anal_op (core->anal, &op, core->offset+i, core->block+i, len-i)) {
|
|
op.type = 0;
|
|
bgcolor = Color_BGRED;
|
|
op.size = 1;
|
|
}
|
|
switch (op.type) {
|
|
case R_ANAL_OP_TYPE_LEA:
|
|
case R_ANAL_OP_TYPE_MOV:
|
|
case R_ANAL_OP_TYPE_CAST:
|
|
case R_ANAL_OP_TYPE_LENGTH:
|
|
case R_ANAL_OP_TYPE_CMOV:
|
|
text = "mv";
|
|
bgcolor = pal->mov;
|
|
fgcolor = Color_YELLOW;
|
|
break;
|
|
case R_ANAL_OP_TYPE_PUSH:
|
|
case R_ANAL_OP_TYPE_UPUSH:
|
|
bgcolor = pal->push;
|
|
fgcolor = Color_WHITE;
|
|
text = "->";
|
|
break;
|
|
case R_ANAL_OP_TYPE_IO:
|
|
bgcolor = pal->swi;
|
|
fgcolor = Color_WHITE;
|
|
text = "io";
|
|
break;
|
|
case R_ANAL_OP_TYPE_TRAP:
|
|
case R_ANAL_OP_TYPE_SWI:
|
|
case R_ANAL_OP_TYPE_NEW:
|
|
//bgcolor = Color_BGRED;
|
|
bgcolor = pal->trap; //r_cons_swap_ground (pal->trap);
|
|
fgcolor = Color_WHITE;
|
|
text = "$$";
|
|
break;
|
|
case R_ANAL_OP_TYPE_POP:
|
|
text = "<-";
|
|
bgcolor = r_cons_swap_ground (pal->pop);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_WHITE;
|
|
break;
|
|
case R_ANAL_OP_TYPE_NOP:
|
|
fgcolor = Color_WHITE;
|
|
bgcolor = r_cons_swap_ground (pal->nop);
|
|
bgcolor_in_heap = true;
|
|
text = "..";
|
|
break;
|
|
case R_ANAL_OP_TYPE_MUL:
|
|
fgcolor = Color_BLACK;
|
|
bgcolor = r_cons_swap_ground (pal->math);
|
|
bgcolor_in_heap = true;
|
|
text = "_*";
|
|
break;
|
|
case R_ANAL_OP_TYPE_DIV:
|
|
bgcolor = r_cons_swap_ground (pal->math);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_BLACK;
|
|
text = "_/";
|
|
break;
|
|
case R_ANAL_OP_TYPE_AND:
|
|
bgcolor = r_cons_swap_ground (pal->bin);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_BLACK;
|
|
text = "_&";
|
|
break;
|
|
case R_ANAL_OP_TYPE_XOR:
|
|
bgcolor = r_cons_swap_ground (pal->bin);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_BLACK;
|
|
text = "_^";
|
|
break;
|
|
case R_ANAL_OP_TYPE_OR:
|
|
bgcolor = r_cons_swap_ground (pal->bin);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_BLACK;
|
|
text = "_|";
|
|
break;
|
|
case R_ANAL_OP_TYPE_SHR:
|
|
bgcolor = r_cons_swap_ground (pal->bin);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_BLACK;
|
|
text = ">>";
|
|
break;
|
|
case R_ANAL_OP_TYPE_SHL:
|
|
bgcolor = r_cons_swap_ground (pal->bin);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_BLACK;
|
|
text = "<<";
|
|
break;
|
|
case R_ANAL_OP_TYPE_SUB:
|
|
bgcolor = r_cons_swap_ground (pal->math);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_WHITE;
|
|
text = "--";
|
|
break;
|
|
case R_ANAL_OP_TYPE_ADD:
|
|
bgcolor = r_cons_swap_ground (pal->math);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_WHITE;
|
|
text = "++";
|
|
break;
|
|
case R_ANAL_OP_TYPE_JMP:
|
|
case R_ANAL_OP_TYPE_UJMP:
|
|
bgcolor = r_cons_swap_ground (pal->jmp);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_BLACK;
|
|
text = "_J";
|
|
break;
|
|
case R_ANAL_OP_TYPE_CJMP:
|
|
case R_ANAL_OP_TYPE_UCJMP:
|
|
bgcolor = r_cons_swap_ground (pal->cjmp);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_BLACK;
|
|
text = "cJ";
|
|
break;
|
|
case R_ANAL_OP_TYPE_CALL:
|
|
case R_ANAL_OP_TYPE_UCALL:
|
|
case R_ANAL_OP_TYPE_UCCALL:
|
|
bgcolor = r_cons_swap_ground (pal->call);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_WHITE;
|
|
text = "_C";
|
|
break;
|
|
case R_ANAL_OP_TYPE_ACMP:
|
|
case R_ANAL_OP_TYPE_CMP:
|
|
bgcolor = r_cons_swap_ground (pal->cmp);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_BLACK;
|
|
text = "==";
|
|
break;
|
|
case R_ANAL_OP_TYPE_RET:
|
|
bgcolor = r_cons_swap_ground (pal->ret);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_WHITE;
|
|
text = "_R";
|
|
break;
|
|
case -1:
|
|
case R_ANAL_OP_TYPE_ILL:
|
|
case R_ANAL_OP_TYPE_UNK:
|
|
bgcolor = r_cons_swap_ground (pal->invalid);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_WHITE;
|
|
text = "XX";
|
|
break;
|
|
#if 0
|
|
default:
|
|
color = Color_BGCYAN;
|
|
fgcolor = Color_BLACK;
|
|
break;
|
|
#endif
|
|
}
|
|
int opsz = R_MAX (op.size, 1);
|
|
if (show_cursor) {
|
|
if (core->print->cur >=i && core->print->cur < i+opsz)
|
|
r_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 = " ";
|
|
r_cons_printf ("%s%s%s\x1b[0m", bgcolor, fgcolor, text);
|
|
} else {
|
|
r_cons_printf ("%s", text? text: " ");
|
|
}
|
|
if (show_cursor) {
|
|
if (core->print->cur >=i && core->print->cur < i+opsz)
|
|
r_cons_invert (0, 1);
|
|
}
|
|
i += opsz;
|
|
}
|
|
if (bgcolor_in_heap) free (bgcolor);
|
|
|
|
return true;
|
|
}
|
|
|
|
static void printraw (RCore *core, int len, int mode) {
|
|
int obsz = core->blocksize;
|
|
int restore_obsz = 0;
|
|
if (len != obsz) {
|
|
if (!r_core_block_size (core, len))
|
|
len = core->blocksize;
|
|
else restore_obsz = 1;
|
|
}
|
|
r_print_raw (core->print, core->offset, core->block, len, mode);
|
|
if (restore_obsz) {
|
|
(void)r_core_block_size (core, obsz);
|
|
}
|
|
core->cons->newline = true;
|
|
}
|
|
static void cmd_print_pv(RCore *core, const char *input) {
|
|
const char *stack[] = { "ret", "arg0", "arg1", "arg2", "arg3", "arg4", NULL };
|
|
int i, n = core->assembler->bits / 8;
|
|
int type = 'v';
|
|
// variables can be
|
|
switch (input[0]) {
|
|
case 'z':
|
|
type = 'z';
|
|
if (input[1]) {
|
|
input++;
|
|
} else {
|
|
r_core_cmdf (core, "ps");
|
|
break;
|
|
}
|
|
/* fallthrough */
|
|
case ' ':
|
|
for (i=0;stack[i]; i++) {
|
|
if (!strcmp (input+1, stack[i])) {
|
|
if (type == 'z') {
|
|
r_core_cmdf (core, "ps @ [`drn sp`+%d]", n * i);
|
|
} else {
|
|
r_core_cmdf (core, "?v [`drn sp`+%d]", n * i);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case '?':
|
|
eprintf ("Usage: pv[z] [ret arg#]\n");
|
|
break;
|
|
default:
|
|
r_core_cmd0 (core, "?v [$$]");
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int cmd_print(void *data, const char *input) {
|
|
RCore *core = (RCore *)data;
|
|
int mode, w, p, i, l, len, total[10];
|
|
int ret = 0;
|
|
ut64 off, from, to, at, ate, piece;
|
|
ut32 tbs = core->blocksize;
|
|
ut8 *ptr = core->block;
|
|
RCoreAnalStats *as;
|
|
ut64 n, nbsz, obsz, fsz;
|
|
ut64 tmpseek = UT64_MAX;
|
|
|
|
off = UT64_MAX;
|
|
l = len = core->blocksize;
|
|
if (input[0] && input[1]) {
|
|
const char *p = strchr (input, ' ');
|
|
if (p) {
|
|
l = (int) r_num_math (core->num, p+1);
|
|
/* except disasm and memoryfmt (pd, pm) */
|
|
if (input[0] != 'd' && input[0] != 'D' && input[0] != 'm' && input[0]!='a' && input[0]!='f') {
|
|
int n = (st32) l; //r_num_math (core->num, input+1);
|
|
if (l<0) {
|
|
off = core->offset + n;
|
|
len = l = - n;
|
|
tmpseek = core->offset;
|
|
} else if (l>0) {
|
|
len = l;
|
|
if (l>tbs) {
|
|
if (input[0] == 'x' && input[1] == 'l') {
|
|
l *= core->print->cols;
|
|
}
|
|
if (!r_core_block_size (core, l)) {
|
|
eprintf ("This block size is too big. Did you mean 'p%c @ %s' instead?\n",
|
|
*input, input+2);
|
|
goto beach;
|
|
}
|
|
l = core->blocksize;
|
|
} else {
|
|
l = len;
|
|
}
|
|
}
|
|
}
|
|
}// else l = 0;
|
|
} else l = len;
|
|
|
|
if (len > core->blocksize)
|
|
len = core->blocksize;
|
|
|
|
if (input[0] != 'd' && input[0] != 'm' && input[0]!='a' && input[0] != 'f') {
|
|
n = core->blocksize_max;
|
|
i = (int)n;
|
|
if (i != n) i = 0;
|
|
if (i && l > i) {
|
|
eprintf ("This block size is too big (%d<%d). Did you mean 'p%c @ %s' instead?\n",
|
|
i, l, *input, input+2);
|
|
goto beach;
|
|
}
|
|
}
|
|
if (input[0] == 'x' || input[0] == 'D'){
|
|
if (l > 0 && tmpseek == UT64_MAX){
|
|
if (!r_core_block_size (core, l)){
|
|
eprintf ("This block size is too big. Did you mean 'p%c @ %s' instead?\n",
|
|
*input, input+2);
|
|
goto beach;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (input[0] && input[0]!='z' && input[1] == 'f') {
|
|
RAnalFunction *f = r_anal_get_fcn_in (core->anal, core->offset,
|
|
R_ANAL_FCN_TYPE_FCN|R_ANAL_FCN_TYPE_SYM);
|
|
if (f) {
|
|
len = f->size;
|
|
} else {
|
|
eprintf ("Cannot find function at 0x%08"PFMT64x"\n", core->offset);
|
|
goto beach;
|
|
}
|
|
}
|
|
ptr = core->block;
|
|
core->num->value = len;
|
|
if (len>core->blocksize)
|
|
len = core->blocksize;
|
|
|
|
if (off != UT64_MAX) {
|
|
r_core_seek (core, off, SEEK_SET);
|
|
}
|
|
switch (*input) {
|
|
case 'w': // "pw"
|
|
if (input[1]=='n') {
|
|
cmd_print_pwn (core);
|
|
} else if (input[1]=='d') {
|
|
if (!r_sandbox_enable (0)) {
|
|
char *cwd = r_sys_getdir ();
|
|
if (cwd) {
|
|
eprintf ("%s\n", cwd);
|
|
free (cwd);
|
|
}
|
|
}
|
|
} else {
|
|
r_cons_printf("| pwd display current working directory\n");
|
|
}
|
|
break;
|
|
case 'v': // "pv"
|
|
cmd_print_pv (core, input+1);
|
|
break;
|
|
case '-': // "p-"
|
|
mode = input[1];
|
|
w = len? len: core->print->cols * 4;
|
|
if (mode == 'j') r_cons_strcat ("{");
|
|
off = core->offset;
|
|
for (i=0; i<10; i++)
|
|
total[i] = 0;
|
|
r_list_free (r_core_get_boundaries (core, "file", &from, &to));
|
|
piece = R_MAX((to - from) / w, 1);
|
|
as = r_core_anal_get_stats (core, from, to, piece);
|
|
if (!as && mode !='?') return 0;
|
|
//eprintf ("RANGE = %llx %llx\n", from, to);
|
|
switch (mode) {
|
|
case '?':{
|
|
const char* help_msg[] = {
|
|
"Usage:", "p%%[jh] [pieces]", "bar|json|histogram blocks",
|
|
"p-", "", "show ascii-art bar of metadata in file boundaries",
|
|
"p-j", "", "show json format",
|
|
"p-h", "", "show histogram analysis of metadata per block",
|
|
NULL};
|
|
r_core_cmd_help (core, help_msg);
|
|
}
|
|
return 0;
|
|
case 'j': //pvj
|
|
r_cons_printf (
|
|
"\"from\":%"PFMT64d","
|
|
"\"to\":%"PFMT64d","
|
|
"\"blocksize\":%d,"
|
|
"\"blocks\":[", from, to, piece);
|
|
break;
|
|
case 'h': //pvh
|
|
r_cons_printf (".-------------.---------------------------------.\n");
|
|
r_cons_printf ("| offset | flags funcs cmts imps syms str |\n");
|
|
r_cons_printf ("|-------------)---------------------------------|\n");
|
|
break;
|
|
default:
|
|
r_cons_printf ("0x%"PFMT64x" [", from);
|
|
}
|
|
|
|
len = 0;
|
|
for (i=0; i<w; i++) {
|
|
at = from + (piece*i);
|
|
ate = at + piece;
|
|
p = (at-from)/piece;
|
|
switch (mode) {
|
|
case 'j':
|
|
r_cons_printf ("%s{",len?",":"");
|
|
if ((as->block[p].flags)
|
|
|| (as->block[p].functions)
|
|
|| (as->block[p].comments)
|
|
|| (as->block[p].imports)
|
|
|| (as->block[p].symbols)
|
|
|| (as->block[p].strings))
|
|
r_cons_printf ("\"offset\":%"PFMT64d",", at), l++;
|
|
// TODO: simplify with macro
|
|
l = 0;
|
|
if (as->block[p].flags) r_cons_printf ("%s\"flags\":%d", l?",":"", as->block[p].flags), l++;
|
|
if (as->block[p].functions) r_cons_printf ("%s\"functions\":%d", l?",":"", as->block[p].functions), l++;
|
|
if (as->block[p].comments) r_cons_printf ("%s\"comments\":%d", l?",":"", as->block[p].comments), l++;
|
|
if (as->block[p].imports) r_cons_printf ("%s\"imports\":%d", l?",":"", as->block[p].imports), l++;
|
|
if (as->block[p].symbols) r_cons_printf ("%s\"symbols\":%d", l?",":"", as->block[p].symbols), l++;
|
|
if (as->block[p].strings) r_cons_printf ("%s\"strings\":%d", l?",":"", as->block[p].strings), l++;
|
|
r_cons_strcat ("}");
|
|
len++;
|
|
break;
|
|
case 'h':
|
|
total[0] += as->block[p].flags;
|
|
total[1] += as->block[p].functions;
|
|
total[2] += as->block[p].comments;
|
|
total[3] += as->block[p].imports;
|
|
total[4] += as->block[p].symbols;
|
|
total[5] += as->block[p].strings;
|
|
if ((as->block[p].flags)
|
|
|| (as->block[p].functions)
|
|
|| (as->block[p].comments)
|
|
|| (as->block[p].imports)
|
|
|| (as->block[p].symbols)
|
|
|| (as->block[p].strings))
|
|
r_cons_printf ("| 0x%09"PFMT64x" | %4d %4d %4d %4d %4d %4d |\n", at,
|
|
as->block[p].flags,
|
|
as->block[p].functions,
|
|
as->block[p].comments,
|
|
as->block[p].imports,
|
|
as->block[p].symbols,
|
|
as->block[p].strings);
|
|
break;
|
|
default:
|
|
if (off>=at && off<ate) {
|
|
r_cons_memcat ("^", 1);
|
|
} else {
|
|
if (as->block[p].strings>0)
|
|
r_cons_memcat ("z", 1);
|
|
else if (as->block[p].imports>0)
|
|
r_cons_memcat ("i", 1);
|
|
else if (as->block[p].symbols>0)
|
|
r_cons_memcat ("s", 1);
|
|
else if (as->block[p].functions>0)
|
|
r_cons_memcat ("F", 1);
|
|
else if (as->block[p].flags>0)
|
|
r_cons_memcat ("f", 1);
|
|
else if (as->block[p].comments>0)
|
|
r_cons_memcat ("c", 1);
|
|
else r_cons_memcat (".", 1);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
switch (mode) {
|
|
case 'j':
|
|
r_cons_strcat ("]}\n");
|
|
break;
|
|
case 'h':
|
|
//r_cons_printf (" total | flags funcs cmts imps syms str |\n");
|
|
r_cons_printf ("|-------------)---------------------------------|\n");
|
|
r_cons_printf ("| total | %4d %4d %4d %4d %4d %4d |\n",
|
|
total[0], total[1], total[2], total[3], total[4], total[5]);
|
|
r_cons_printf ("`-------------'---------------------------------'\n");
|
|
break;
|
|
default:
|
|
r_cons_printf ("] 0x%"PFMT64x"\n", to);
|
|
}
|
|
r_core_anal_stats_free (as);
|
|
break;
|
|
case '=': //p=
|
|
{
|
|
char *spc, input1 = 'b';
|
|
ut64 stblk = 0;
|
|
nbsz = core->blocksize;
|
|
fsz = 0;
|
|
if (input[0]) {
|
|
if (input[1] && input[1] != ' ')
|
|
input1 = input[1];
|
|
spc = strchr (input, ' ');
|
|
if (spc) {
|
|
nbsz = r_num_get (core->num, spc+1);
|
|
if (nbsz<1)
|
|
nbsz = core->blocksize;
|
|
|
|
spc = strchr (spc+1, ' ');
|
|
if (spc) {
|
|
fsz = r_num_get (core->num, spc+1);
|
|
|
|
spc = strchr (spc+1, ' ');
|
|
if (spc) {
|
|
stblk = r_num_get (core->num, spc+1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (fsz<1)
|
|
fsz = (core->file && core->io)? r_io_desc_size (core->io, core->file->desc): 0;
|
|
if (nbsz) {
|
|
obsz = core->blocksize;
|
|
switch (input1) {
|
|
case 'p':
|
|
case 'e':
|
|
if (fsz==UT64_MAX) {
|
|
eprintf ("Cannot determine file size\n");
|
|
goto beach;
|
|
}
|
|
nbsz = fsz / nbsz;
|
|
break;
|
|
}
|
|
r_core_block_size (core, nbsz);
|
|
} else {
|
|
obsz = nbsz = core->blocksize;
|
|
}
|
|
switch (input1) {
|
|
case '?':{ // bars
|
|
const char* help_msg[] = {
|
|
"Usage:", "p=[bep?] [num-of-blocks] ([len]) ([block-offset]) ", "show entropy/printable chars/chars bars",
|
|
"p=", "", "print bytes of current block in bars",
|
|
"p=", "b", "same as above",
|
|
"p=", "d", "print different bytes from block",
|
|
"p=", "e", "print entropy for each filesize/blocksize",
|
|
"p=", "p", "print number of printable bytes for each filesize/blocksize",
|
|
NULL};
|
|
r_core_cmd_help (core, help_msg);
|
|
}
|
|
break;
|
|
case 'd':
|
|
cmd_print_eq_dict (core, nbsz); //core->blocksize);
|
|
break;
|
|
case 'e': // entropy
|
|
{
|
|
ut8 *p;
|
|
int psz, i = 0;
|
|
if (nbsz<1) nbsz=1;
|
|
psz = fsz / nbsz;
|
|
if (!psz) psz = 1;
|
|
ptr = malloc (psz);
|
|
if (!ptr) {
|
|
eprintf ("Error: failed to malloc memory");
|
|
goto beach;
|
|
}
|
|
//eprintf ("block = %d * %d\n", (int)nbsz, psz);
|
|
p = malloc (core->blocksize);
|
|
if (!p) {
|
|
R_FREE (ptr);
|
|
eprintf ("Error: failed to malloc memory");
|
|
goto beach;
|
|
}
|
|
for (i=stblk; i<(psz+stblk); i++) {
|
|
r_core_read_at (core, i*nbsz, p, nbsz);
|
|
ptr[i-stblk] = (ut8) (256 * r_hash_entropy_fraction (p, core->blocksize));
|
|
}
|
|
free (p);
|
|
r_print_fill (core->print, ptr, psz);
|
|
break;
|
|
case 'p': // printable chars
|
|
{
|
|
ut8 *p;
|
|
int psz, i = 0, j, k;
|
|
if (nbsz<1) nbsz=1;
|
|
psz = fsz / nbsz;
|
|
if (!psz) psz = 1;
|
|
ptr = malloc (psz);
|
|
if (!ptr) {
|
|
eprintf ("Error: failed to malloc memory");
|
|
goto beach;
|
|
}
|
|
//eprintf ("block = %d * %d\n", (int)nbsz, (int)psz);
|
|
p = malloc (core->blocksize);
|
|
if (!p) {
|
|
eprintf ("Error: failed to malloc memory");
|
|
R_FREE (ptr);
|
|
goto beach;
|
|
}
|
|
for (i=stblk; i<(psz+stblk); i++) {
|
|
r_core_read_at (core, i*nbsz, p, nbsz);
|
|
for (j=k=0; j<nbsz; j++) {
|
|
if (IS_PRINTABLE (p[j]))
|
|
k++;
|
|
}
|
|
ptr[i-stblk] = 256 * k / nbsz;
|
|
}
|
|
free (p);
|
|
r_print_fill (core->print, ptr, psz);
|
|
}
|
|
break;
|
|
case 'b': // bytes
|
|
case '\0':
|
|
r_print_fill (core->print, core->block, core->blocksize);
|
|
break;
|
|
}
|
|
if (ptr && ptr != core->block)
|
|
free (ptr);
|
|
ptr = NULL;
|
|
}
|
|
if (nbsz)
|
|
r_core_block_size (core, obsz);
|
|
}
|
|
break;
|
|
case 'A': // "pA"
|
|
{
|
|
ut64 from = r_config_get_i (core->config, "search.from");
|
|
ut64 to = r_config_get_i (core->config, "search.to");
|
|
int count = r_config_get_i (core->config, "search.count");
|
|
|
|
int want = r_num_math (core->num, input+1);
|
|
if (input[1]=='?') {
|
|
r_core_cmd0 (core, "/A?");
|
|
} else {
|
|
r_config_set_i (core->config, "search.count", want);
|
|
r_config_set_i (core->config, "search.from", core->offset);
|
|
r_config_set_i (core->config, "search.to", core->offset+core->blocksize);
|
|
r_core_cmd0 (core, "/A");
|
|
r_config_set_i (core->config, "search.count", count);
|
|
r_config_set_i (core->config, "search.from", from);
|
|
r_config_set_i (core->config, "search.to", to);
|
|
}
|
|
}
|
|
break;
|
|
case 'a': // "pa"
|
|
{
|
|
ut32 new_bits = -1;
|
|
int segoff, old_bits, pos = 0;
|
|
ut8 settings_changed = false;
|
|
char *new_arch = NULL, *old_arch = NULL, *hex = NULL;
|
|
old_arch = strdup (r_config_get (core->config, "asm.arch"));
|
|
old_bits = r_config_get_i (core->config, "asm.bits");
|
|
segoff = r_config_get_i (core->config, "asm.segoff");
|
|
if (input[1] != ' ') {
|
|
if (input[0])
|
|
for (pos = 1; pos < R_BIN_SIZEOF_STRINGS && input[pos]; pos++)
|
|
if (input[pos] == ' ') break;
|
|
|
|
if (!process_input_pade (core, input+pos, &hex, &new_arch, &new_bits)) {
|
|
// XXX - print help message
|
|
//return false;
|
|
}
|
|
|
|
if (new_arch == NULL) new_arch = strdup (old_arch);
|
|
if (new_bits == -1) new_bits = old_bits;
|
|
|
|
if (strcmp (new_arch, old_arch) != 0 || new_bits != old_bits){
|
|
set_asm_configs (core, new_arch, new_bits, segoff);
|
|
settings_changed = true;
|
|
}
|
|
}
|
|
if (input[1]=='e') { // "pae"
|
|
if (input[2]=='?') {
|
|
r_cons_printf ("|Usage: pae [hex] assemble esil from hexpairs\n");
|
|
} else {
|
|
int ret, bufsz;
|
|
RAnalOp aop = {0};
|
|
const char *str;
|
|
// char *buf = strdup (input+2);
|
|
bufsz = r_hex_str2bin (hex, (ut8*)hex);
|
|
ret = r_anal_op (core->anal, &aop, core->offset,
|
|
(const ut8*)hex, bufsz);
|
|
if (ret>0) {
|
|
str = R_STRBUF_SAFEGET (&aop.esil);
|
|
r_cons_printf ("%s\n", str);
|
|
}
|
|
r_anal_op_fini (&aop);
|
|
}
|
|
} else if (input[1] == 'D') {
|
|
if (input[2]=='?') {
|
|
r_cons_printf ("|Usage: paD [asm] disasm like in pdi\n");
|
|
} else {
|
|
r_core_cmdf (core, "pdi@x:%s", input+2);
|
|
}
|
|
} else if (input[1]=='d') { // "pad"
|
|
if (input[2]=='?') {
|
|
r_cons_printf ("|Usage: pad [asm] disasm\n");
|
|
} else {
|
|
RAsmCode *c;
|
|
r_asm_set_pc (core->assembler, core->offset);
|
|
c = r_asm_mdisassemble_hexstr (core->assembler, hex);
|
|
if (c) {
|
|
r_cons_puts (c->buf_asm);
|
|
r_asm_code_free (c);
|
|
} else eprintf ("Invalid hexstr\n");
|
|
}
|
|
} else if (input[1]=='?') {
|
|
r_cons_printf("|Usage: pa[ed] [hex|asm] assemble (pa) disasm (pad)"
|
|
" esil (pae) from hexpairs\n");
|
|
} else {
|
|
RAsmCode *acode;
|
|
r_asm_set_pc (core->assembler, core->offset);
|
|
acode = r_asm_massemble (core->assembler, input+1);
|
|
if (acode && *acode->buf_hex) {
|
|
r_cons_printf ("%s\n", acode->buf_hex);
|
|
r_asm_code_free (acode);
|
|
}
|
|
}
|
|
if (settings_changed)
|
|
set_asm_configs (core, old_arch, old_bits, segoff);
|
|
free (old_arch);
|
|
free (new_arch);
|
|
}
|
|
break;
|
|
case 'b': { // "pb"
|
|
if (input[1]=='?') {
|
|
r_cons_printf("|Usage: p[bB] [len] ([skip]) ; see also pB and pxb\n");
|
|
} else {
|
|
int from, to;
|
|
const int size = len*8;
|
|
char *spc, *buf = malloc (size+1);
|
|
spc = strchr (input, ' ');
|
|
if (spc) {
|
|
len = r_num_math (core->num, spc+1);
|
|
if (len<1)
|
|
len = 1;
|
|
spc = strchr (spc+1, ' ');
|
|
if (spc) {
|
|
from = r_num_math (core->num, spc+1);
|
|
} else {
|
|
from = 0;
|
|
}
|
|
to = from+len;
|
|
} else {
|
|
from = 0;
|
|
to = size;
|
|
}
|
|
if (buf) {
|
|
int buf_len;
|
|
r_str_bits (buf, core->block, size, NULL);
|
|
buf_len = strlen (buf);
|
|
if (from>=buf_len) {
|
|
from = buf_len;
|
|
}
|
|
if (to<buf_len) {
|
|
buf[to] = 0;
|
|
}
|
|
r_cons_printf ("%s\n", buf+from);
|
|
free (buf);
|
|
} else eprintf ("ERROR: Cannot malloc %d bytes\n", size);
|
|
}
|
|
}
|
|
break;
|
|
case 'B': { // "pB"
|
|
if (input[1]=='?') {
|
|
r_cons_printf ("|Usage: p[bB] [len] bitstream of N bytes\n");
|
|
} else {
|
|
const int size = len*8;
|
|
char *buf = malloc (size+1);
|
|
if (buf) {
|
|
r_str_bits (buf, core->block, size, NULL);
|
|
r_cons_printf ("%s\n", buf);
|
|
free (buf);
|
|
} else eprintf ("ERROR: Cannot malloc %d bytes\n", size);
|
|
} }
|
|
break;
|
|
case 'I': // "pI"
|
|
switch (input[1]) {
|
|
case 'j': // "pIj" is the same as pDj
|
|
if (input[2]) {
|
|
cmd_pDj (core, input+2);
|
|
} else {
|
|
cmd_pDj (core, sdb_fmt(0, "%d", core->blocksize));
|
|
}
|
|
break;
|
|
case 'f': // "pIf"
|
|
{
|
|
const RAnalFunction *f = r_anal_get_fcn_in (core->anal, core->offset,
|
|
R_ANAL_FCN_TYPE_FCN|R_ANAL_FCN_TYPE_SYM);
|
|
if (f) {
|
|
r_core_print_disasm_instructions (core,
|
|
f->size, 0);
|
|
break;
|
|
}
|
|
}
|
|
case 'd': // "pId" is the same as pDi
|
|
pdi (core, 0, l, 0);
|
|
break;
|
|
case '?': // "pi?"
|
|
r_cons_printf("|Usage: p[iI][df] [len] print N instructions/bytes"
|
|
"(f=func) (see pi? and pdi)\n");
|
|
break;
|
|
default:
|
|
r_core_print_disasm_instructions (core, l, 0);
|
|
}
|
|
break;
|
|
case 'i': // "pi"
|
|
switch (input[1]) {
|
|
case '?':
|
|
r_cons_printf ("|Usage: pi[defj] [num]\n");
|
|
break;
|
|
case 'a': // "pia" is like "pda", but with "pi" output
|
|
{
|
|
RAsmOp asmop;
|
|
char str[128];
|
|
char* buf_asm;
|
|
ut8 *buf = core->block;
|
|
int colors_on = r_config_get_i (core->config, "scr.color");
|
|
if (l<1) l = len;
|
|
if (l>core->blocksize) {
|
|
buf = malloc (l+1);
|
|
r_core_read_at (core, core->offset, buf, l);
|
|
}
|
|
r_cons_break (NULL, NULL);
|
|
for (i=0; i<l; i++) {
|
|
ut64 addr = core->offset+i;
|
|
r_asm_set_pc (core->assembler, addr);
|
|
if (r_cons_singleton ()->breaked)
|
|
break;
|
|
if (r_asm_disassemble (core->assembler, &asmop, buf+i, l-i) < 1) {
|
|
r_cons_printf ("???\n");
|
|
} else {
|
|
r_parse_filter (core->parser, core->flags, asmop.buf_asm,
|
|
str, sizeof (str));
|
|
if (colors_on) {
|
|
RAnalOp aop;
|
|
r_anal_op (core->anal, &aop, addr, buf+i, l-i);
|
|
buf_asm = r_print_colorize_opcode (str,
|
|
core->cons->pal.reg, core->cons->pal.num);
|
|
r_cons_printf ("%s%s\n",
|
|
r_print_color_op_type (core->print, aop.type),
|
|
buf_asm);
|
|
free (buf_asm);
|
|
} else {
|
|
r_cons_printf ("%s\n", asmop.buf_asm);
|
|
}
|
|
}
|
|
}
|
|
r_cons_break_end ();
|
|
if (buf != core->block)
|
|
free (buf);
|
|
}
|
|
break;
|
|
case 'j': //pij is the same as pdj
|
|
cmd_pdj (core, input+2);
|
|
break;
|
|
case 'd': //pid is the same as pdi
|
|
pdi (core, l, 0, 0);
|
|
break;
|
|
case 'e':
|
|
pdi (core, l, 0, 'e');
|
|
break;
|
|
case 'f': // "pif"
|
|
{
|
|
RAnalFunction *f = r_anal_get_fcn_in (core->anal, core->offset,
|
|
R_ANAL_FCN_TYPE_FCN|R_ANAL_FCN_TYPE_SYM);
|
|
if (f) {
|
|
ut32 bsz = core->blocksize;
|
|
r_core_block_size (core, f->size);
|
|
r_core_print_disasm_instructions (core, 0, 0);
|
|
r_core_block_size (core, bsz);
|
|
} else {
|
|
r_core_print_disasm_instructions (core,
|
|
core->blocksize, l);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
r_core_print_disasm_instructions (core, 0, l);
|
|
break;
|
|
}
|
|
goto beach;
|
|
case 'D': // "pD"
|
|
case 'd': // "pd"
|
|
{
|
|
ut64 current_offset = core->offset;
|
|
ut32 new_bits = -1;
|
|
ut64 use_blocksize = core->blocksize;
|
|
int segoff, old_bits, pos = 0;
|
|
ut8 settings_changed = false, bw_disassemble = false;
|
|
char *new_arch = NULL, *old_arch = NULL;
|
|
ut32 pd_result = false, processed_cmd = false;
|
|
old_arch = strdup (r_config_get (core->config, "asm.arch"));
|
|
segoff = r_config_get_i (core->config, "asm.segoff");
|
|
old_bits = r_config_get_i (core->config, "asm.bits");
|
|
|
|
// XXX - this is necessay b/c radare will automatically
|
|
// swap flags if arch is x86 and bits == 16 see: __setsegoff in config.c
|
|
|
|
// get to the space
|
|
if (input[0])
|
|
for (pos = 1; pos < R_BIN_SIZEOF_STRINGS && input[pos]; pos++)
|
|
if (input[pos] == ' ') break;
|
|
|
|
if (!process_input (core, input+pos, &use_blocksize, &new_arch, &new_bits)) {
|
|
// XXX - print help message
|
|
//return false;
|
|
}
|
|
if (!use_blocksize)
|
|
use_blocksize = core->blocksize;
|
|
|
|
if (core->blocksize_max < use_blocksize && (int)use_blocksize < -core->blocksize_max) {
|
|
eprintf ("This block size is too big (%"PFMT64d"<%"PFMT64d"). Did you mean 'p%c @ 0x%08"PFMT64x"' instead?\n",
|
|
(ut64)core->blocksize_max, (ut64)use_blocksize, input[0], (ut64) use_blocksize);
|
|
free (old_arch);
|
|
free (new_arch);
|
|
goto beach;
|
|
} else if (core->blocksize_max < use_blocksize && (int)use_blocksize > -core->blocksize_max) {
|
|
bw_disassemble = true;
|
|
use_blocksize = -use_blocksize;
|
|
}
|
|
l = use_blocksize;
|
|
|
|
if (new_arch == NULL) new_arch = strdup (old_arch);
|
|
if (new_bits == -1) new_bits = old_bits;
|
|
|
|
if (strcmp (new_arch, old_arch) != 0 || new_bits != old_bits){
|
|
set_asm_configs (core, new_arch, new_bits, segoff);
|
|
settings_changed = true;
|
|
}
|
|
|
|
switch (input[1]) {
|
|
case 'c': // "pdc" // "pDc"
|
|
r_core_pseudo_code (core, input+2);
|
|
pd_result = 0;
|
|
processed_cmd = true;
|
|
break;
|
|
case 'i': // "pdi" // "pDi"
|
|
processed_cmd = true;
|
|
if (*input == 'D')
|
|
pdi (core, 0, l, 0);
|
|
else
|
|
pdi (core, l, 0, 0);
|
|
pd_result = 0;
|
|
break;
|
|
case 'a': // "pda"
|
|
processed_cmd = true;
|
|
{
|
|
RAsmOp asmop;
|
|
int ret, err = 0;
|
|
ut8 *buf = core->block;
|
|
if (l<1) l = len;
|
|
if (l>core->blocksize) {
|
|
buf = malloc (l+1);
|
|
r_core_read_at (core, core->offset, buf, l);
|
|
}
|
|
r_cons_break (NULL, NULL);
|
|
for (i=0; i<l; i++) {
|
|
r_asm_set_pc (core->assembler, core->offset+i);
|
|
if (r_cons_singleton ()->breaked)
|
|
break;
|
|
ret = r_asm_disassemble (core->assembler, &asmop,
|
|
buf+i, l-i);
|
|
if (ret<1) {
|
|
ret = err = 1;
|
|
//r_cons_printf ("???\n");
|
|
r_cons_printf ("0x%08"PFMT64x" ???\n", core->offset+i);
|
|
} else r_cons_printf ("0x%08"PFMT64x" %16s %s\n",
|
|
core->offset+i, asmop.buf_hex, asmop.buf_asm);
|
|
}
|
|
r_cons_break_end ();
|
|
if (buf != core->block)
|
|
free (buf);
|
|
pd_result = true;
|
|
}
|
|
break;
|
|
case 'r': // "pdr"
|
|
processed_cmd = true;
|
|
{
|
|
RAnalFunction *f = r_anal_get_fcn_in (core->anal, core->offset,
|
|
R_ANAL_FCN_TYPE_FCN|R_ANAL_FCN_TYPE_SYM);
|
|
if (f) {
|
|
RListIter *iter;
|
|
RAnalBlock *b;
|
|
// XXX: hack must be reviewed/fixed in code analysis
|
|
if (r_list_length (f->bbs) == 1) {
|
|
b = r_list_get_top (f->bbs);
|
|
if (b->size > f->size) b->size = f->size;
|
|
}
|
|
// TODO: sort by addr
|
|
//r_list_sort (f->bbs, &r_anal_ex_bb_address_comparator);
|
|
r_list_foreach (f->bbs, iter, b) {
|
|
r_core_cmdf (core, "pD %"PFMT64d" @0x%"PFMT64x, b->size, b->addr);
|
|
/*switch (control_type) {
|
|
case R_ANAL_OP_TYPE_CALL:
|
|
break;
|
|
case R_ANAL_OP_TYPE_JMP:
|
|
break;
|
|
case R_ANAL_OP_TYPE_CJMP:
|
|
break;
|
|
case R_ANAL_OP_TYPE_SWITCH:
|
|
}*/
|
|
if (b->jump != UT64_MAX)
|
|
r_cons_printf ("-[true]-> 0x%08"PFMT64x"\n", b->jump);
|
|
if (b->fail != UT64_MAX)
|
|
r_cons_printf ("-[false]-> 0x%08"PFMT64x"\n", b->fail);
|
|
r_cons_printf ("--\n");
|
|
}
|
|
} else {
|
|
eprintf ("Cannot find function at 0x%08"PFMT64x"\n", core->offset);
|
|
core->num->value = -1;
|
|
}
|
|
pd_result = true;
|
|
}
|
|
break;
|
|
case 'b': // "pdb"
|
|
processed_cmd = true;
|
|
{
|
|
RAnalBlock *b = r_anal_bb_from_offset (core->anal, core->offset);
|
|
if (b) {
|
|
ut8 *block = malloc (b->size+1);
|
|
if (block) {
|
|
r_core_read_at (core, b->addr, block, b->size);
|
|
core->num->value = r_core_print_disasm (
|
|
core->print, core, b->addr, block,
|
|
b->size, 9999, 0, 2);
|
|
free (block);
|
|
pd_result = 0;
|
|
}
|
|
} else {
|
|
eprintf ("Cannot find function at 0x%08"PFMT64x"\n", core->offset);
|
|
core->num->value = -1;
|
|
}
|
|
}
|
|
break;
|
|
case 'f': // "pdf"
|
|
processed_cmd = true;
|
|
{
|
|
ut32 bsz = core->blocksize;
|
|
RAnalFunction *f = r_anal_get_fcn_in (core->anal, core->offset,
|
|
R_ANAL_FCN_TYPE_FCN|R_ANAL_FCN_TYPE_SYM);
|
|
if (f && input[2] == 'j') { // "pdfj"
|
|
ut8 *buf;
|
|
r_cons_printf ("{");
|
|
r_cons_printf ("\"name\":\"%s\"", f->name);
|
|
r_cons_printf (",\"size\":%d", f->size);
|
|
r_cons_printf (",\"addr\":%"PFMT64d, f->addr);
|
|
r_cons_printf (",\"ops\":");
|
|
// instructions are all outputted as a json list
|
|
buf = malloc (f->size);
|
|
if (buf) {
|
|
r_io_read_at (core->io, f->addr, buf, f->size);
|
|
r_core_print_disasm_json (core, f->addr, buf, f->size, 0);
|
|
r_cons_newline ();
|
|
free (buf);
|
|
} else eprintf ("cannot allocate %d bytes\n", f->size);
|
|
r_cons_printf ("}");
|
|
pd_result = 0;
|
|
} else if (f) {
|
|
r_core_cmdf (core, "pD %d @ 0x%08llx", f->size, f->addr);
|
|
pd_result = 0;
|
|
} else {
|
|
eprintf ("Cannot find function at 0x%08"PFMT64x"\n", core->offset);
|
|
processed_cmd = true;
|
|
core->num->value = -1;
|
|
}
|
|
if (bsz != core->blocksize)
|
|
r_core_block_size (core, bsz);
|
|
}
|
|
l = 0;
|
|
break;
|
|
case 'l': //pdl
|
|
processed_cmd = true;
|
|
{
|
|
RAsmOp asmop;
|
|
int j, ret;
|
|
const ut8 *buf = core->block;
|
|
if (l==0) l= len;
|
|
r_cons_break (NULL, NULL);
|
|
for (i=j=0; i<core->blocksize && j<l; i+=ret,j++ ) {
|
|
ret = r_asm_disassemble (core->assembler, &asmop, buf+i, len-i);
|
|
if (r_cons_singleton ()->breaked) break;
|
|
r_cons_printf ("%d\n", ret);
|
|
if (ret<1) ret = 1;
|
|
}
|
|
r_cons_break_end ();
|
|
pd_result = 0;
|
|
}
|
|
break;
|
|
case 'j': //pdj
|
|
processed_cmd = true;
|
|
if (*input == 'D'){
|
|
cmd_pDj (core, input+2);
|
|
} else cmd_pdj (core, input+2);
|
|
r_cons_newline ();
|
|
pd_result = 0;
|
|
break;
|
|
case 0:
|
|
/* "pd" -> will disassemble blocksize/4 instructions */
|
|
if (*input=='d') {
|
|
l/=4;
|
|
}
|
|
break;
|
|
case '?': // "pd?"
|
|
processed_cmd = true;
|
|
const char* help_msg[] = {
|
|
"Usage:", "p[dD][ajbrfils] [sz] [arch] [bits]", " # Print Disassembly",
|
|
"NOTE: ", "len", "parameter can be negative",
|
|
"NOTE: ", "", "Pressing ENTER on empty command will repeat last pd command and also seek to end of disassembled range.",
|
|
"pd", " N", "disassemble N instructions",
|
|
"pd", " -N", "disassemble N instructions backward",
|
|
"pD", " N", "disassemble N bytes",
|
|
"pda", "", "disassemble all possible opcodes (byte per byte)",
|
|
"pdb", "", "disassemble basic block",
|
|
"pdc", "", "pseudo disassembler output in C-link syntax",
|
|
"pdj", "", "disassemble to json",
|
|
"pdr", "", "recursive disassemble across the function graph",
|
|
"pdf", "", "disassemble function",
|
|
"pdi", "", "like 'pi', with offset and bytes",
|
|
"pdl", "", "show instruction sizes",
|
|
"pds", "", "disassemble with back sweep (greedy disassembly backwards)",
|
|
"pdt", "", "disassemble the debugger traces (see atd)",
|
|
NULL};
|
|
r_core_cmd_help (core, help_msg);
|
|
pd_result = 0;
|
|
}
|
|
if (!processed_cmd) {
|
|
ut64 addr = core->offset;
|
|
ut8 *block = NULL;
|
|
|
|
if (bw_disassemble) {
|
|
block = malloc (core->blocksize);
|
|
if (l<0)
|
|
l = -l;
|
|
if (block) {
|
|
if (*input == 'D'){ //pD
|
|
r_core_read_at (core, addr-l, block, l); //core->blocksize);
|
|
core->num->value = r_core_print_disasm (core->print,
|
|
core, addr-l, block, l, l, 0, 1);
|
|
} else { //pd
|
|
const int bs = core->blocksize;
|
|
int instr_len;
|
|
r_core_asm_bwdis_len (core, &instr_len, &addr, l);
|
|
ut32 prevaddr = core->offset;
|
|
r_core_seek(core, prevaddr - instr_len, true);
|
|
block = realloc (block, R_MAX(instr_len, bs));
|
|
memcpy (block, core->block, bs);
|
|
r_core_read_at (core, addr+bs, block+bs, instr_len-bs); //core->blocksize);
|
|
core->num->value = r_core_print_disasm (core->print,
|
|
core, addr, block, instr_len, l, 0, 1);
|
|
r_core_seek(core, prevaddr, true);
|
|
}
|
|
}
|
|
} else {
|
|
const int bs = core->blocksize;
|
|
// XXX: issue with small blocks
|
|
if (*input == 'D' && l>0) {
|
|
if (l>R_CORE_MAX_DISASM) { // pD
|
|
eprintf ("Block size too big\n");
|
|
return 1;
|
|
}
|
|
block = malloc (l);
|
|
if (block) {
|
|
if (l>core->blocksize) {
|
|
r_core_read_at (core, addr, block, l); //core->blocksize);
|
|
} else {
|
|
memcpy (block, core->block, l);
|
|
}
|
|
core->num->value = r_core_print_disasm (core->print,
|
|
core, addr, block, l, l, 0, 1);
|
|
} else {
|
|
eprintf ("Cannot allocate %d bytes\n", l);
|
|
}
|
|
} else {
|
|
block = malloc (R_MAX(l*10, bs));
|
|
memcpy (block, core->block, bs);
|
|
r_core_read_at (core, addr+bs, block+bs, (l*10)-bs); //core->blocksize);
|
|
core->num->value = r_core_print_disasm (core->print,
|
|
core, addr, block, l*10, l, 0, 0);
|
|
}
|
|
}
|
|
free (block);
|
|
}
|
|
core->offset = current_offset;
|
|
// change back asm setting is they were changed
|
|
if (settings_changed)
|
|
set_asm_configs (core, old_arch, old_bits, segoff);
|
|
|
|
free (old_arch);
|
|
free (new_arch);
|
|
|
|
if (processed_cmd) {
|
|
ret = pd_result;
|
|
goto beach;
|
|
}
|
|
}
|
|
break;
|
|
case 's': //ps
|
|
switch (input[1]) {
|
|
case '?':{
|
|
const char* help_msg[] = {
|
|
"Usage:", "ps[zpw] [N]", "Print String",
|
|
"ps", "", "print string",
|
|
"psi", "", "print string inside curseek",
|
|
"psb", "", "print strings in current block",
|
|
"psx", "", "show string with scaped chars",
|
|
"psz", "", "print zero terminated string",
|
|
"psp", "", "print pascal string",
|
|
"psu", "", "print utf16 unicode (json)",
|
|
"psw", "", "print wide string",
|
|
"psj", "", "print string in JSON format",
|
|
NULL};
|
|
r_core_cmd_help (core, help_msg);
|
|
}
|
|
break;
|
|
case 'j':
|
|
{
|
|
char *str, *type;
|
|
ut64 vaddr;
|
|
RIOSection *section;
|
|
|
|
if (input[2] == ' ' && input[3]){
|
|
len = r_num_math (core->num, input+3);
|
|
len = R_MIN (len, core->blocksize);
|
|
}
|
|
/* try to get the section that contains the
|
|
* string, by considering current offset as
|
|
* paddr and if it isn't, trying to consider it
|
|
* as vaddr. */
|
|
vaddr = r_io_section_maddr_to_vaddr (core->io, core->offset);
|
|
section = core->io->section;
|
|
if (vaddr == UT64_MAX) {
|
|
section = r_io_section_vget (core->io, core->offset);
|
|
if (section) {
|
|
vaddr = core->offset;
|
|
}
|
|
}
|
|
|
|
r_cons_printf ("{\"string\":");
|
|
str = r_str_utf16_encode ((const char*)core->block, len);
|
|
r_cons_printf ("\"%s\"", str);
|
|
r_cons_printf (",\"offset\":%"PFMT64d, core->offset);
|
|
r_cons_printf (",\"section\":\"%s\"", vaddr == UT64_MAX ? "unknown" : section->name);
|
|
r_cons_printf (",\"length\":%d", len);
|
|
switch (get_string_type (core->block, len)){
|
|
case 'w' : type = "wide" ; break;
|
|
case 'a' : type = "ascii"; break;
|
|
case 'u' : type = "utf" ; break;
|
|
default : type = "unkown" ; break;
|
|
}
|
|
r_cons_printf (",\"type\":\"%s\"}", type);
|
|
r_cons_newline ();
|
|
free (str);
|
|
}
|
|
break;
|
|
case 'i': //psi
|
|
{
|
|
ut8 *buf = malloc (1024);
|
|
int delta = 512;
|
|
ut8 *p, *e, *b;
|
|
if (!buf) return 0;
|
|
if (core->offset<delta)
|
|
delta = core->offset;
|
|
p = buf+delta;
|
|
r_core_read_at (core, core->offset-delta, buf, 1024);
|
|
for (b = p; b>buf; b--) {
|
|
if (!IS_PRINTABLE (*b)) {
|
|
b++;
|
|
break;
|
|
}
|
|
}
|
|
for (e = p; e<(buf+1024); e++) {
|
|
if (!IS_PRINTABLE (*b)) {
|
|
*e = 0;
|
|
e--;
|
|
break;
|
|
}
|
|
}
|
|
r_cons_strcat ((const char *)b);
|
|
r_cons_newline ();
|
|
//r_print_string (core->print, core->offset, b,
|
|
// (size_t)(e-b), 0);
|
|
free (buf);
|
|
}
|
|
break;
|
|
case 'x': // "psx"
|
|
r_print_string (core->print, core->offset, core->block, len, 0);
|
|
break;
|
|
case 'b': // "psb"
|
|
{
|
|
char *s = malloc (core->blocksize+1);
|
|
int i, j, hasnl = 0;;
|
|
if (s) {
|
|
memset (s, 0, core->blocksize);
|
|
// TODO: filter more chars?
|
|
for (i=j=0;i<core->blocksize; i++) {
|
|
char ch = (char)core->block[i];
|
|
if (!ch) {
|
|
if (!hasnl) {
|
|
s[j] = 0;
|
|
if (*s) r_cons_printf ("%s\n", s);
|
|
j = 0;
|
|
s[0] = 0;
|
|
}
|
|
hasnl = 1;
|
|
continue;
|
|
}
|
|
hasnl = 0;
|
|
if (IS_PRINTABLE (ch))
|
|
s[j++] = ch;
|
|
}
|
|
s[j] = 0;
|
|
r_cons_printf ("%s", s); // TODO: missing newline?
|
|
free (s);
|
|
}
|
|
}
|
|
break;
|
|
case 'z': //psz
|
|
{
|
|
char *s = malloc (core->blocksize+1);
|
|
int i, j;
|
|
if (s) {
|
|
memset (s, 0, core->blocksize);
|
|
// TODO: filter more chars?
|
|
for (i=j=0;i<core->blocksize; i++) {
|
|
char ch = (char)core->block[i];
|
|
if (!ch) break;
|
|
if (IS_PRINTABLE (ch))
|
|
s[j++] = ch;
|
|
}
|
|
r_cons_printf ("%s\n", s);
|
|
free (s);
|
|
}
|
|
}
|
|
break;
|
|
case 'p': //psp
|
|
{
|
|
int mylen = core->block[0];
|
|
// TODO: add support for 2-4 byte length pascal strings
|
|
if (mylen < core->blocksize) {
|
|
r_print_string (core->print, core->offset,
|
|
core->block+1, mylen, R_PRINT_STRING_ZEROEND);
|
|
core->num->value = mylen;
|
|
} else core->num->value = 0; // error
|
|
}
|
|
break;
|
|
case 'w': //psw
|
|
r_print_string (core->print, core->offset, core->block, len,
|
|
R_PRINT_STRING_WIDE | R_PRINT_STRING_ZEROEND);
|
|
break;
|
|
case ' ':
|
|
len = r_num_math (core->num, input+2);
|
|
r_print_string (core->print, core->offset, core->block, len, 0);
|
|
break;
|
|
case 'u':
|
|
{
|
|
char *str = r_str_utf16_encode (
|
|
(const char*)core->block, len);
|
|
r_cons_printf ("%s\n", str);
|
|
free (str);
|
|
}
|
|
break;
|
|
default:
|
|
r_print_string (core->print, core->offset, core->block,
|
|
len, R_PRINT_STRING_ZEROEND);
|
|
break;
|
|
}
|
|
break;
|
|
case 'm': //pm
|
|
if (input[1]=='?') {
|
|
r_cons_printf ("|Usage: pm [file|directory]\n"
|
|
"| r_magic will use given file/dir as reference\n"
|
|
"| output of those magic can contain expressions like:\n"
|
|
"| foo@0x40 # use 'foo' magic file on address 0x40\n"
|
|
"| @0x40 # use current magic file on address 0x40\n"
|
|
"| \\n # append newline\n"
|
|
"| e dir.magic # defaults to "R_MAGIC_PATH"\n"
|
|
"| /m # search for magic signatures\n"
|
|
);
|
|
} else r_core_magic (core, input+1, true);
|
|
break;
|
|
case 'u': //pu
|
|
if (input[1]=='?') {
|
|
r_cons_printf ("|Usage: pu[w] [len] print N url"
|
|
"encoded bytes (w=wide)\n");
|
|
} else {
|
|
r_print_string (core->print, core->offset, core->block, len,
|
|
R_PRINT_STRING_URLENCODE |
|
|
((input[1]=='w')?R_PRINT_STRING_WIDE:0));
|
|
}
|
|
break;
|
|
case 'c': //pc
|
|
r_print_code (core->print, core->offset, core->block, len, input[1]);
|
|
break;
|
|
case 'r': // "pr"
|
|
switch (input[1]) {
|
|
case '?':
|
|
r_cons_printf ("|Usage: pr[glx] [size]\n"
|
|
"| prl: print raw with lines offsets\n"
|
|
"| prx: printable chars with real offset (hyew)\n"
|
|
"| prg: print raw GUNZIPped block\n");
|
|
break;
|
|
case 'g': // "prg" // gunzip
|
|
switch (input[2]) {
|
|
case '?':
|
|
r_cons_printf ("|Usage: prg[io]\n"
|
|
"| prg: print gunzipped data of current block\n"
|
|
"| prgi: show consumed bytes when inflating\n"
|
|
"| prgo: show output bytes after inflating\n");
|
|
break;
|
|
case 'i':
|
|
{
|
|
int sz, outlen = 0;
|
|
int inConsumed = 0;
|
|
ut8 *in, *out;
|
|
in = core->block;
|
|
sz = core->blocksize;
|
|
out = r_inflate (in, sz, &inConsumed, &outlen);
|
|
r_cons_printf ("%d\n", inConsumed);
|
|
free (out);
|
|
}
|
|
break;
|
|
case 'o':
|
|
{
|
|
int sz, outlen = 0;
|
|
ut8 *in, *out;
|
|
in = core->block;
|
|
sz = core->blocksize;
|
|
out = r_inflate (in, sz, NULL, &outlen);
|
|
r_cons_printf ("%d\n", outlen);
|
|
free (out);
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
int sz, outlen = 0;
|
|
ut8 *in, *out;
|
|
in = core->block;
|
|
sz = core->blocksize;
|
|
out = r_inflate (in, sz, NULL, &outlen);
|
|
if (out) {
|
|
r_cons_memcat ((const char*)out, outlen);
|
|
}
|
|
free (out);
|
|
}
|
|
}
|
|
break;
|
|
/* TODO: compact */
|
|
case 'l': // "prl"
|
|
printraw (core, len, 1);
|
|
break;
|
|
case 'x': // "prx"
|
|
printraw (core, len, 2);
|
|
break;
|
|
default:
|
|
printraw (core, len, 0);
|
|
break;
|
|
}
|
|
break;
|
|
case '3': // "p3" [file]
|
|
if (input[1]=='?') {
|
|
eprintf ("Usage: p3 [file] - print 3D stereogram image of current block\n");
|
|
} else
|
|
if (input[1]==' ') {
|
|
char *data = r_file_slurp (input+2, NULL);
|
|
char *res = r_print_stereogram (data, 78, 20);
|
|
r_print_stereogram_print (core->print, res);
|
|
//if (data) eprintf ("%s\n", data);
|
|
free (res);
|
|
free (data);
|
|
} else {
|
|
char *res = r_print_stereogram_bytes (core->block, core->blocksize);
|
|
r_print_stereogram_print (core->print, res);
|
|
free (res);
|
|
}
|
|
break;
|
|
case 'x': // "px"
|
|
{
|
|
int show_offset = r_config_get_i (core->config, "asm.offset");
|
|
if (show_offset) {
|
|
core->print->flags |= R_PRINT_FLAGS_HEADER;
|
|
core->print->flags |= R_PRINT_FLAGS_OFFSET;
|
|
} else {
|
|
core->print->flags &= ~R_PRINT_FLAGS_OFFSET;
|
|
core->print->flags &= ~R_PRINT_FLAGS_HEADER;
|
|
}
|
|
}
|
|
switch (input[1]) {
|
|
case '/':
|
|
r_core_print_examine (core, input+2);
|
|
break;
|
|
case '?':{
|
|
const char* help_msg[] = {
|
|
"Usage:", "px[afoswqWqQ][f]", " # Print heXadecimal",
|
|
"px", "", "show hexdump",
|
|
"px/", "", "same as x/ in gdb (help x)",
|
|
"pxa", "", "show annotated hexdump",
|
|
"pxA", "", "show op analysis color map",
|
|
"pxb", "", "dump bits in hexdump form",
|
|
"pxd", "", "decimal (base 10) dump",
|
|
"pxe", "", "emoji hexdump! :)",
|
|
"pxf", "", "show hexdump of current function",
|
|
"pxh", "", "show hexadecimal half-words dump (16bit)",
|
|
"pxH", "", "same as above, but one per line",
|
|
"pxl", "", "display N lines (rows) of hexdump",
|
|
"pxo", "", "show octal dump",
|
|
"pxq", "", "show hexadecimal quad-words dump (64bit)",
|
|
"pxQ", "", "same as above, but one per line",
|
|
"pxr", "[j]", "show words with references to flags and code",
|
|
"pxs", "", "show hexadecimal in sparse mode",
|
|
"pxw", "", "show hexadecimal words dump (32bit)",
|
|
"pxW", "", "same as above, but one per line",
|
|
NULL};
|
|
r_core_cmd_help (core, help_msg);
|
|
}
|
|
break;
|
|
case 'a': // "pxa"
|
|
if (len%16)
|
|
len += 16-(len%16);
|
|
annotated_hexdump (core, input+2, len);
|
|
break;
|
|
case 'A': // "pxA"
|
|
if (input[2]=='?') {
|
|
eprintf ("Usage: pxA [len] # f.ex: pxA 4K\n"
|
|
" mv move,lea,li\n"
|
|
" -> push\n"
|
|
" <- pop\n"
|
|
" io in/out ops\n"
|
|
" $$ int/swi/trap/new\n"
|
|
" .. nop\n"
|
|
" +-*/ math ops\n"
|
|
" |&^ bin ops\n"
|
|
" <<>> shift ops\n"
|
|
" _J jump\n"
|
|
" cJ conditional jump\n"
|
|
" _C call\n"
|
|
" == cmp/test\n"
|
|
" XX invalid\n");
|
|
} else {
|
|
cmd_print_pxA (core, len, input+1);
|
|
}
|
|
break;
|
|
case 'b': // "pxb"
|
|
{
|
|
ut32 n;
|
|
int i, c;
|
|
char buf[32];
|
|
#define P(x) (IS_PRINTABLE(x)?x:'.')
|
|
#define SPLIT_BITS(x) memmove (x + 5, x + 4, 5); x[4]=0
|
|
for (i = c = 0; i < len; i++,c++) {
|
|
if (c == 0) r_print_offset (core->print,
|
|
core->offset+i, 0, 0, 0);
|
|
r_str_bits (buf, core->block+i, 8, NULL);
|
|
SPLIT_BITS (buf);
|
|
r_cons_printf ("%s.%s ", buf, buf+5);
|
|
if (c==3) {
|
|
const ut8 *b = core->block + i-3;
|
|
#define K(x) (b[3-x]<<(8*x))
|
|
n = K (0) | K (1) | K (2) | K (3);
|
|
r_cons_printf ("0x%08x %c%c%c%c\n",
|
|
n, P (b[0]), P (b[1]), P (b[2]),
|
|
P (b[3]));
|
|
c = -1;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 'o': // "pxo"
|
|
r_print_hexdump (core->print, core->offset,
|
|
core->block, len, 8, 1);
|
|
break;
|
|
case 'd': // "pxd"
|
|
r_print_hexdump (core->print, core->offset,
|
|
core->block, len, 10, 4);
|
|
break;
|
|
case 'w': // "pxw
|
|
r_print_hexdump (core->print, core->offset, core->block,
|
|
len, 32, 4);
|
|
break;
|
|
case 'W': // "pxW"
|
|
len = len - (len%4);
|
|
for (i=0; i<len; i+=4) {
|
|
const char *a, *b;
|
|
char *fn;
|
|
RPrint *p = core->print;
|
|
RFlagItem *f;
|
|
ut32 *v = (ut32*)((ut8*)core->block+i);
|
|
r_mem_copyendian ((ut8*)v, (ut8*)v, 4,
|
|
!core->print->big_endian);
|
|
|
|
if (p && p->colorfor) {
|
|
a = p->colorfor (p->user, *v);
|
|
if (a && *a) {
|
|
b = Color_RESET;
|
|
} else {
|
|
a = b = "";
|
|
}
|
|
} else {
|
|
a = b = "";
|
|
}
|
|
f = r_flag_get_at (core->flags, *v);
|
|
fn = NULL;
|
|
if (f) {
|
|
st64 delta = (*v - f->offset);
|
|
if (delta >= 0 && delta < 8192) {
|
|
if (*v == f->offset) {
|
|
fn = strdup (f->name);
|
|
} else {
|
|
fn = r_str_newf ("%s+%d",
|
|
f->name, *v-f->offset);
|
|
}
|
|
}
|
|
}
|
|
r_cons_printf ("0x%08"PFMT64x" %s0x%08"PFMT64x"%s %s\n",
|
|
(ut64)core->offset+i, a, (ut64)*v, b, fn? fn: "");
|
|
free (fn);
|
|
}
|
|
break;
|
|
case 'r': // "pxr"
|
|
if (input[2] == 'j') {
|
|
int base = core->anal->bits;
|
|
r_cons_printf ("[");
|
|
const char *comma = "";
|
|
const ut8 *buf = core->block;
|
|
int withref = 0;
|
|
for (i=0; i< core->blocksize; i+= (base/4)) {
|
|
ut64 addr = core->offset + i;
|
|
ut64 *foo = (ut64*)(buf+i);
|
|
ut64 val = *foo;
|
|
if (base==32) val &= UT32_MAX;
|
|
r_cons_printf ("%s{\"addr\":%"PFMT64d",\
|
|
\"value\":%"PFMT64d,
|
|
comma, addr, val);
|
|
comma = ",";
|
|
// XXX: this only works in little endian
|
|
withref = 0;
|
|
if (core->print->hasrefs) {
|
|
const char *rstr = core->print->hasrefs (core->print->user, val);
|
|
if (rstr && *rstr) {
|
|
char *ns; //r_str_ansi_chop (ns, -1, 0);
|
|
ns = r_str_escape (rstr);
|
|
r_cons_printf (",\"ref\":\"%s\"}", *ns==' '?ns+1:ns);
|
|
free (ns);
|
|
withref = 1;
|
|
}
|
|
}
|
|
if (!withref) r_cons_printf ("}");
|
|
}
|
|
r_cons_printf ("]\n");
|
|
} else {
|
|
const int ocols = core->print->cols;
|
|
int bitsize = core->assembler->bits;
|
|
/* Thumb is 16bit arm but handles 32bit data */
|
|
if (bitsize == 16) bitsize = 32;
|
|
core->print->cols = 1;
|
|
core->print->flags |= R_PRINT_FLAGS_REFS;
|
|
r_print_hexdump (core->print, core->offset,
|
|
core->block, len,
|
|
bitsize, bitsize/8);
|
|
core->print->flags &= ~R_PRINT_FLAGS_REFS;
|
|
core->print->cols = ocols;
|
|
}
|
|
break;
|
|
case 'h':
|
|
r_print_hexdump (core->print, core->offset,
|
|
core->block, len, 32, 2);
|
|
break;
|
|
case 'H':
|
|
len = len - (len % 2);
|
|
for (i = 0; i < len; i += 2) {
|
|
const char *a, *b;
|
|
char *fn;
|
|
RPrint *p = core->print;
|
|
RFlagItem *f;
|
|
ut64 v;
|
|
r_mem_copyendian ((ut8*)&v,
|
|
(const ut8*)(ut64*)(core->block+i), 2,
|
|
!core->assembler->big_endian);
|
|
if (p && p->colorfor) {
|
|
a = p->colorfor (p->user, v);
|
|
if (a && *a) { b = Color_RESET; } else { a = b = ""; }
|
|
} else { a = b = ""; }
|
|
f = r_flag_get_at (core->flags, v);
|
|
fn = NULL;
|
|
if (f) {
|
|
st64 delta = (v - f->offset);
|
|
if (delta>=0 && delta<8192) {
|
|
if (v == f->offset) {
|
|
fn = strdup (f->name);
|
|
} else fn = r_str_newf ("%s+%d", f->name, v-f->offset);
|
|
}
|
|
}
|
|
r_cons_printf ("0x%08"PFMT64x" %s0x%04"PFMT64x"%s %s\n",
|
|
(ut64)core->offset+i, a, v, b, fn? fn: "");
|
|
free (fn);
|
|
}
|
|
break;
|
|
case 'q':
|
|
r_print_hexdump (core->print, core->offset, core->block, len, 64, 8);
|
|
break;
|
|
case 'Q':
|
|
// TODO. show if flag name, or inside function
|
|
len = len - (len % 8);
|
|
for (i = 0; i < len; i += 8) {
|
|
const char *a, *b;
|
|
char *fn;
|
|
RPrint *p = core->print;
|
|
RFlagItem *f;
|
|
ut64 v;
|
|
r_mem_copyendian ((ut8*)&v,
|
|
(const ut8*)(ut64*)(core->block+i), 8,
|
|
!core->assembler->big_endian);
|
|
if (p && p->colorfor) {
|
|
a = p->colorfor (p->user, v);
|
|
if (a && *a) { b = Color_RESET; } else { a = b = ""; }
|
|
} else { a = b = ""; }
|
|
f = r_flag_get_at (core->flags, v);
|
|
fn = NULL;
|
|
if (f) {
|
|
st64 delta = (v - f->offset);
|
|
if (delta>=0 && delta<8192) {
|
|
if (v == f->offset) {
|
|
fn = strdup (f->name);
|
|
} else fn = r_str_newf ("%s+%d", f->name, v-f->offset);
|
|
}
|
|
}
|
|
r_cons_printf ("0x%08"PFMT64x" %s0x%016"PFMT64x"%s %s\n",
|
|
(ut64)core->offset+i, a, v, b, fn? fn: "");
|
|
free (fn);
|
|
}
|
|
break;
|
|
case 's':
|
|
core->print->flags |= R_PRINT_FLAGS_SPARSE;
|
|
r_print_hexdump (core->print, core->offset,
|
|
core->block, len, 16, 1);
|
|
core->print->flags &= (((ut32)-1) & (~R_PRINT_FLAGS_SPARSE));
|
|
break;
|
|
case 'e':
|
|
{
|
|
int j;
|
|
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'};
|
|
for (i=0; i<len; i+=16) {
|
|
r_print_addr (core->print, core->offset+i);
|
|
for (j=i; j<i+16; j+=1) {
|
|
ut8 *p = (ut8*)core->block+j;
|
|
if (j<len)
|
|
r_cons_printf ("\xf0\x9f%c%c ", emoji[*p*2], emoji[*p*2+1]);
|
|
else
|
|
r_cons_printf (" ");
|
|
}
|
|
r_cons_printf (" ");
|
|
for (j=i; j<len && j<i+16; j+=1) {
|
|
ut8 *p = (ut8*)core->block+j;
|
|
r_print_byte (core->print, "%c", j, *p);
|
|
}
|
|
r_cons_printf ("\n");
|
|
}
|
|
}
|
|
break;
|
|
case 'l':
|
|
len = core->print->cols*len;
|
|
default: {
|
|
int restore_block_size = 0;
|
|
ut64 from = r_config_get_i (core->config, "diff.from");
|
|
ut64 to = r_config_get_i (core->config, "diff.to");
|
|
ut64 obsz = core->blocksize;
|
|
if (from == to && from == 0) {
|
|
if (len != obsz) {
|
|
if (!r_core_block_size (core, len)) {
|
|
len = obsz;
|
|
} else {
|
|
restore_block_size = 1;
|
|
}
|
|
}
|
|
r_print_hexdump (core->print, core->offset,
|
|
core->block, len, 16, 1);
|
|
} else {
|
|
r_core_print_cmp (core, from, to);
|
|
}
|
|
if (restore_block_size) {
|
|
(void)r_core_block_size (core, obsz);
|
|
}
|
|
core->num->value = len;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case '2':
|
|
if (input[1] == '?')
|
|
r_cons_printf ("|Usage: p2 [number of bytes representing tiles]\n"
|
|
"NOTE: Only full tiles will be printed\n");
|
|
else r_print_2bpp_tiles (core->print, core->block, len/16);
|
|
break;
|
|
case '6':
|
|
{
|
|
int malen = (core->blocksize*4)+1;
|
|
ut8 *buf = malloc (malen);
|
|
if (!buf) break;
|
|
memset (buf, 0, malen);
|
|
switch (input[1]) {
|
|
case 'd':
|
|
if (input[2] == '?')
|
|
r_cons_printf ("|Usage: p6d [len] base 64 decode\n");
|
|
else if (r_base64_decode (buf, (const char *)core->block, len))
|
|
r_cons_printf ("%s\n", buf);
|
|
else eprintf ("r_base64_decode: invalid stream\n");
|
|
break;
|
|
case 'e':
|
|
if (input[2] == '?') {
|
|
r_cons_printf ("|Usage: p6e [len] base 64 encode\n");
|
|
break;
|
|
} else {
|
|
len = len > core->blocksize ? core->blocksize : len;
|
|
r_base64_encode ((char *)buf, core->block, len);
|
|
r_cons_printf ("%s\n", buf);
|
|
}
|
|
break;
|
|
case '?':
|
|
default:
|
|
r_cons_printf ("|Usage: p6[ed] [len] base 64 encode/decode\n");
|
|
break;
|
|
}
|
|
free (buf);
|
|
}
|
|
break;
|
|
case '8':
|
|
if (input[1] == '?') {
|
|
r_cons_printf("|Usage: p8[j] [len] 8bit hexpair list of bytes (see pcj)\n");
|
|
} else if (input[1] == 'j') {
|
|
r_core_cmdf (core, "pcj %s", input+2);
|
|
} else r_print_bytes (core->print, core->block, len, "%02x");
|
|
break;
|
|
case 'f':
|
|
cmd_print_format (core, input, len);
|
|
break;
|
|
case 'k':
|
|
if (input[1] == '?') {
|
|
r_cons_printf ("|Usage: pk [len] print key in randomart\n");
|
|
} else {
|
|
len = len > core->blocksize ? core->blocksize : len;
|
|
char *s = r_print_randomart (core->block, len, core->offset);
|
|
r_cons_printf ("%s\n", s);
|
|
free (s);
|
|
}
|
|
break;
|
|
case 'K':
|
|
if (input[1] == '?') {
|
|
r_cons_printf ("|Usage: pK [len] print key in randomart mosaic\n");
|
|
} else {
|
|
len = len > core->blocksize ? core->blocksize : len;
|
|
int w, h;
|
|
RConsCanvas *c;
|
|
w = r_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 = r_cons_canvas_new (w, rows*11);
|
|
for (i = 0; i<rows; i++) {
|
|
for (j = 0; j<cols; j++) {
|
|
r_cons_canvas_gotoxy (c, j*20, i*11);
|
|
core->offset += len;
|
|
r_core_read_at (core, core->offset, core->block, len);
|
|
s = r_print_randomart (core->block, len, core->offset);
|
|
r_cons_canvas_write (c, s);
|
|
free (s);
|
|
}
|
|
}
|
|
r_cons_canvas_print (c);
|
|
r_cons_canvas_free (c);
|
|
r_core_read_at (core, offset0, core->block, len);
|
|
core->offset = offset0;
|
|
r_cons_printf("\n");
|
|
}
|
|
break;
|
|
case 'n': // easter
|
|
eprintf ("easter egg license has expired\n");
|
|
break;
|
|
case 't':
|
|
switch (input[1]) {
|
|
case ' ':
|
|
case '\0':
|
|
//len must be multiple of 4 since r_mem_copyendian move data in fours - sizeof(ut32)
|
|
if (len < sizeof (ut32)) eprintf ("You should change the block size: b %d\n", (int)sizeof (ut32));
|
|
if (len % sizeof (ut32) != 0) len = len - (len % sizeof (ut32));
|
|
for (l=0; l<len; l+=sizeof (ut32))
|
|
r_print_date_unix (core->print, core->block+l, sizeof (ut32));
|
|
break;
|
|
case 'd':
|
|
//len must be multiple of 4 since r_print_date_dos read buf+3
|
|
//if block size is 1 or 5 for example it reads beyond the buffer
|
|
if (len < sizeof (ut32)) eprintf ("You should change the block size: b %d\n", (int)sizeof (ut32));
|
|
if (len % sizeof (ut32) != 0) len = len - (len % sizeof (ut32));
|
|
for (l=0; l<len; l+=sizeof (ut32))
|
|
r_print_date_dos (core->print, core->block+l, sizeof (ut32));
|
|
break;
|
|
case 'n':
|
|
core->print->big_endian = !core->print->big_endian;
|
|
if (len < sizeof (ut64)) eprintf ("You should change the block size: b %d\n", (int)sizeof (ut64));
|
|
if (len % sizeof (ut64) != 0) len = len - (len % sizeof (ut64));
|
|
for (l=0; l<len; l+=sizeof (ut64))
|
|
r_print_date_w32 (core->print, core->block+l, sizeof (ut64));
|
|
core->print->big_endian = !core->print->big_endian;
|
|
break;
|
|
case '?':{
|
|
const char* help_msg[] = {
|
|
"Usage: pt", "[dn]", "print timestamps",
|
|
"pt", "", "print unix time (32 bit `cfg.bigendian`)",
|
|
"ptd","", "print dos time (32 bit `cfg.bigendian`)",
|
|
"ptn","", "print ntfs time (64 bit `cfg.bigendian`)",
|
|
NULL};
|
|
r_core_cmd_help (core, help_msg);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case 'z':
|
|
if (input[1]=='?') {
|
|
const char *help_msg[] = {
|
|
"Usage: pz [len]", "", "print zoomed blocks (filesize/N)",
|
|
"e ","zoom.maxsz","max size of block",
|
|
"e ","zoom.from","start address",
|
|
"e ","zoom.to","end address",
|
|
"e ","zoom.byte","specify how to calculate each byte",
|
|
"pzp","","number of printable chars",
|
|
"pzf","","count of flags in block",
|
|
"pzs","","strings in range",
|
|
"pz0","","number of bytes with value '0'",
|
|
"pzF","","number of bytes with value 0xFF",
|
|
"pze","","calculate entropy and expand to 0-255 range",
|
|
"pzh","","head (first byte value); This is the default mode",
|
|
//"WARNING: On big files, use 'zoom.byte=h' or restrict ranges\n");
|
|
NULL};
|
|
r_core_cmd_help (core, help_msg);
|
|
} else {
|
|
char *oldzoom = NULL;
|
|
ut64 maxsize = r_config_get_i (core->config, "zoom.maxsz");
|
|
ut64 from, to;
|
|
int oldva = core->io->va;
|
|
int do_zoom = 1;
|
|
|
|
core->io->va = 0;
|
|
from = 0;
|
|
to = r_io_size (core->io);
|
|
from = r_config_get_i (core->config, "zoom.from");
|
|
to = r_config_get_i (core->config, "zoom.to");
|
|
if (input[1] && input[1] != ' ') {
|
|
oldzoom = strdup (r_config_get (core->config, "zoom.byte"));
|
|
if (!r_config_set (core->config, "zoom.byte", input+1)) {
|
|
eprintf ("Invalid zoom.byte mode (%s)\n", input+1);
|
|
R_FREE (oldzoom);
|
|
do_zoom = 0;
|
|
}
|
|
}
|
|
if (do_zoom) {
|
|
r_print_zoom (core->print, core, printzoomcallback,
|
|
from, to, core->blocksize, (int)maxsize);
|
|
}
|
|
if (oldzoom) {
|
|
r_config_set (core->config, "zoom.byte", oldzoom);
|
|
R_FREE (oldzoom);
|
|
}
|
|
if (oldva)
|
|
core->io->va = oldva;
|
|
}
|
|
break;
|
|
default: {
|
|
const char* help_msg[] = {
|
|
"Usage:", "p[=68abcdDfiImrstuxz] [arg|len]", "",
|
|
"p=","[bep?] [blks] [len] [blk]","show entropy/printable chars/chars bars",
|
|
"p2"," [len]","8x8 2bpp-tiles",
|
|
"p3"," [file]","print stereogram (3D)",
|
|
"p6","[de] [len]", "base64 decode/encode",
|
|
"p8","[j] [len]","8bit hexpair list of bytes",
|
|
"pa","[edD] [arg]", "pa:assemble pa[dD]:disasm or pae: esil from hexpairs",
|
|
"pA","[n_ops]", "show n_ops address and type",
|
|
"p","[b|B|xb] [len] ([skip])", "bindump N bits skipping M",
|
|
"p","[bB] [len]","bitstream of N bytes",
|
|
"pc","[p] [len]","output C (or python) format",
|
|
"p","[dD][ajbrfils] [sz] [a] [b]","disassemble N opcodes/bytes for Arch/Bits (see pd?)",
|
|
"pf","[?|.nam] [fmt]","print formatted data (pf.name, pf.name $<expr>) ",
|
|
"p","[iI][df] [len]", "print N ops/bytes (f=func) (see pi? and pdi)",
|
|
"pm"," [magic]","print libmagic data (see pm? and /m?)",
|
|
"pr","[glx] [len]","print N raw bytes (in lines or hexblocks, 'g'unzip)",
|
|
"p","[kK] [len]","print key in randomart (K is for mosaic)",
|
|
"ps","[pwz] [len]","print pascal/wide/zero-terminated strings",
|
|
"pt","[dn?] [len]","print different timestamps",
|
|
"pu","[w] [len]","print N url encoded bytes (w=wide)",
|
|
"pv","[jh] [mode]","show variable/pointer/value in memory",
|
|
"p-","[jh] [mode]","bar|json|histogram blocks (mode: e?search.in)",
|
|
"p","[xX][owq] [len]","hexdump of N bytes (o=octal, w=32bit, q=64bit)",
|
|
"pz"," [len]","print zoom view (see pz? for help)",
|
|
"pwd","","display current working directory",
|
|
NULL
|
|
};
|
|
r_core_cmd_help (core, help_msg);
|
|
}
|
|
break;
|
|
}
|
|
beach:
|
|
if (tbs != core->blocksize)
|
|
r_core_block_size (core, tbs);
|
|
if (tmpseek != UT64_MAX) {
|
|
r_core_seek (core, tmpseek, SEEK_SET);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int cmd_hexdump(void *data, const char *input) {
|
|
return cmd_print (data, input-1);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
// TODO : move to r_util? .. depends on r_cons...
|
|
R_API void r_print_offset(RPrint *p, ut64 off, int invert, int offseg, int delta) {
|
|
int show_color = p->flags & R_PRINT_FLAGS_COLOR;
|
|
if (show_color) {
|
|
const char *k = r_cons_singleton ()->pal.offset; // TODO etooslow. must cache
|
|
if (invert)
|
|
r_cons_invert (true, true);
|
|
if (offseg) {
|
|
ut32 s, a;
|
|
a = off & 0xffff;
|
|
s = (off-a)>>4;
|
|
r_cons_printf ("%s%04x:%04x"Color_RESET,
|
|
k, s&0xFFFF, a&0xFFFF);
|
|
} else {
|
|
int sz = lenof (off, 0);
|
|
int sz2 = lenof (delta, 1);
|
|
const char *pad = r_str_pad (' ', sz-sz2);
|
|
if (delta>0) {
|
|
r_cons_printf ("%s+0x%x"Color_RESET, pad, delta);
|
|
} else r_cons_printf ("%s0x%08"PFMT64x""Color_RESET, k, off);
|
|
}
|
|
r_cons_puts (" ");
|
|
} else {
|
|
if (offseg) {
|
|
ut32 s, a;
|
|
a = off & 0xffff;
|
|
s = (off-a)>>4;
|
|
r_cons_printf ("%04x:%04x", s&0xFFFF, a&0xFFFF);
|
|
} else {
|
|
int sz = lenof (off, 0);
|
|
int sz2 = lenof (delta, 1);
|
|
const char *pad = r_str_pad (' ', sz-5-sz2-3);
|
|
if (delta>0) {
|
|
r_cons_printf ("%s+0x%x"Color_RESET, pad, delta);
|
|
} else r_cons_printf ("0x%08"PFMT64x" ", off);
|
|
}
|
|
}
|
|
}
|