radare2/libr/util/p_format.c
2014-04-28 11:53:22 +02:00

432 lines
10 KiB
C

/* radare - LGPL - Copyright 2007-2013 - pancake */
#if 0
# TEST DAT PTR SHIT
e asm.bits=32
wv 0x10
wv 0x10 @ 4
w hello @ 0x10
pf ss
pf *x*x
pf *z*z
#endif
#include "r_cons.h"
#include "r_util.h"
#include "r_print.h"
static int nullprintf(const char *fmt, ...) { return 0; }
static void print_format_help(RPrint *p) {
p->printf (
"Usage: pf[.key[.field[=value]]|[ val]]|[times][format] [arg0 arg1 ...]\n"
"Examples:\n"
" pf 10xiz pointer length string\n"
" pf {array_size}b @ array_base\n"
" pf. # list all formats\n"
" pf.obj xxdz prev next size name\n"
" pf.obj # run stored format\n"
" pf.obj.name # show string inside object\n"
" pf.obj.size=33 # set new size\n"
"Format chars:\n"
" e - temporally swap endian\n"
//" D - double (8 bytes)\n"
" f - float value (4 bytes)\n"
" c - char (signed byte)\n"
" b - byte (unsigned)\n"
" B - show 10 first bytes of buffer\n" // B must be for binary ??
" i - %%i integer value (4 bytes)\n"
" w - word (2 bytes unsigned short in hex)\n"
" q - quadword (8 bytes)\n"
" p - pointer reference (2, 4 or 8 bytes)\n"
" d - 0x%%08x hexadecimal value (4 bytes)\n"
" D - disassemble one opcode\n"
" x - 0x%%08x hexadecimal value and flag (fd @ addr)\n"
" z - \\0 terminated string\n"
" Z - \\0 terminated wide string\n"
" s - 32bit pointer to string (4 bytes)\n"
" S - 64bit pointer to string (8 bytes)\n"
//" t - unix timestamp string\n"
" * - next char is pointer (honors asm.bits)\n"
" + - toggle show flags for each offset\n"
" : - skip 4 bytes\n"
" . - skip 1 byte\n");
}
/* TODO: needs refactoring */
R_API int r_print_format(RPrint *p, ut64 seek, const ut8* b, int len, const char *fmt, int elem, const char *setval) {
int nargs, i, j, nexti, idx, times, otimes, endian, isptr = 0;
int (*realprintf)(const char *str, ...);
int (*oldprintf)(const char *str, ...);
const char *argend = fmt+strlen (fmt);
ut64 addr = 0, addr64 = 0, seeki = 0;;
char *args = NULL, *bracket, tmp, last = 0;
const char *arg = fmt;
int viewflags = 0;
char namefmt[8];
ut8 *buf, buffer[256];
nexti = nargs = endian = i = j = 0;
if (len<1) return 0;
buf = malloc (len);
if (!buf) return 0;
memcpy (buf, b, len);
endian = p->big_endian;
oldprintf = NULL;
realprintf = p->printf;
while (*arg && iswhitechar (*arg)) arg++;
/* get times */
otimes = times = atoi (arg);
if (times > 0)
while ((*arg>='0'&&*arg<='9')) arg++;
bracket = strchr (arg,'{');
if (bracket) {
char *end = strchr (arg,'}');
if (end == NULL) {
eprintf ("No end bracket. Try pm {ecx}b @ esi\n");
goto beach;
}
*end='\0';
times = r_num_math (NULL, bracket+1);
arg = end + 1;
}
if (*arg=='\0') {
print_format_help (p);
goto beach;
}
/* get args */
args = strchr (arg, ' ');
if (args) {
int l=0, maxl = 0;
argend = args;
args = strdup (args+1);
nargs = r_str_word_set0 (args+1);
if (nargs == 0)
R_FREE (args);
for (i=0; i<nargs; i++) {
int len = strlen (r_str_word_get0 (args+1, i));
if (len>maxl) maxl = len;
}
l++;
snprintf (namefmt, sizeof (namefmt), "%%%ds : ", maxl);
}
/* go format */
i = 0;
if (!times) otimes = times = 1;
for (; times; times--) { // repeat N times
const char * orig = arg;
if (otimes>1)
p->printf ("0x%08"PFMT64x" [%d] {\n", seek+i, otimes-times);
idx = 0;
arg = orig;
for (idx=0; i<len && arg<argend && *arg; idx++, arg++) {
seeki = seek+i;
addr = 0LL;
if (endian)
addr = (*(buf+i))<<24 | (*(buf+i+1))<<16 | *(buf+i+2)<<8 | *(buf+i+3);
else addr = (*(buf+i+3))<<24 | (*(buf+i+2))<<16 | *(buf+i+1)<<8 | *(buf+i);
if (endian)
addr64 = (ut64)(*(buf+i))<<56 | (ut64)(*(buf+i+1))<<48
| (ut64)*(buf+i+2)<<40 | (ut64)(*(buf+i+3))<<32
| (*(buf+i+4))<<24 | (*(buf+i+5))<<16 | *(buf+i+6)<<8 | *(buf+i+7);
else addr64 = ((ut64)(*(buf+i+7)))<<56 | (ut64)(*(buf+i+6))<<48
| (ut64)(*(buf+i+5))<<40 | (ut64)(*(buf+i+4))<<32
| (*(buf+i+3))<<24 | (*(buf+i+2))<<16 | *(buf+i+1)<<8 | *(buf+i);
tmp = *arg;
feed_me_again:
switch (isptr) {
case 1:
nexti = i + (p->bits/8);
i = 0;
tmp = *arg;
memset (buf, '\0', len);
p->printf ("(*0x%"PFMT64x") ", addr);
if (p->iob.read_at) {
p->iob.read_at (p->iob.io, (ut64)addr, buf, len-4);
} else {
eprintf ("(cannot read memory)\n");
break;
}
isptr = 2;
break;
case 2:
// restore state after pointer seek
i = nexti;
seeki = seek+i;
memcpy (buf, b, len);
isptr = 0;
arg--;
idx--;
continue;
}
if (tmp == 0 && last != '*')
break;
/* skip chars */
switch (tmp) {
case '*':
isptr = 1;
if (i<=0 || !arg[1]) break;
arg++;
tmp = *arg; //last;
// arg--;
// idx--;
goto feed_me_again;
case '+':
idx--;
viewflags = !viewflags;
continue;
case 'e': // tmp swap endian
idx--;
endian ^= 1;
continue;
case ':': // skip char
i+=4;
idx-=4;
continue;
case '.': // skip char
i++;
idx--;
continue;
case 'p':
tmp = (p->bits==64)?'q': 'x';
//tmp = (sizeof (void*)==8)? 'q': 'x';
break;
case '?': // help
print_format_help (p);
idx--;
i = len; // exit
continue;
}
if (otimes>1)
p->printf (" ");
#define MUSTSET (setval && elem == idx)
#define MUSTSEE (elem == -1 || elem == idx)
if (MUSTSEE) {
if (!(MUSTSET)) {
if (oldprintf)
p->printf = oldprintf;
if (idx<nargs)
p->printf (namefmt, r_str_word_get0 (args, idx));
}
} else {
if (!oldprintf)
oldprintf = p->printf;
p->printf = nullprintf;
}
/* cmt chars */
switch (tmp) {
#if 0
case 'n': // enable newline
j ^= 1;
continue;
#endif
#if 0
case 't':
/* unix timestamp */
D cons_printf("0x%08x = ", config.seek+i);
{
/* dirty hack */
int oldfmt = last_print_format;
ut64 old = config.seek;
radare_seek(config.seek+i, SEEK_SET);
radare_read(0);
print_data(config.seek+i, "8", buf+i, 4, FMT_TIME_UNIX);
last_print_format=oldfmt;
radare_seek(old, SEEK_SET);
}
break;
#endif
case 'e':
if (MUSTSET) {
realprintf ("?e pf e not yet supported\n");
} else {
double doub;
memcpy (&doub, buf+i, sizeof (double));
p->printf ("0x%08"PFMT64x" = (double) ", seeki);
p->printf ("%e", doub);
i += 8;
}
break;
case 'q':
if (MUSTSET) {
realprintf ("wv8 %s @ 0x%08"PFMT64x"\n", setval, seeki);
} else {
p->printf ("0x%08"PFMT64x" = ", seeki);
p->printf ("(qword) ");
p->printf ("0x%08"PFMT64x" ", addr64);
}
i += 8;
break;
case 'b':
if (MUSTSET) {
realprintf ("w %s @ 0x%08"PFMT64x"\n", setval, seeki);
} else {
p->printf ("0x%08"PFMT64x" = ", seeki);
p->printf ("%d ; 0x%02x ; '%c' ",
buf[i], buf[i], IS_PRINTABLE (buf[i])?buf[i]:0);
}
i++;
break;
case 'c':
if (MUSTSET) {
realprintf ("?e pf c not yet implemented\n");
} else {
p->printf ("0x%08"PFMT64x" = ", seeki);
p->printf ("%d ; %d ; '%c' ",
buf[i], (char)buf[i],
IS_PRINTABLE (buf[i])?buf[i]:0);
}
i++;
break;
case 'B':
if (MUSTSET) {
realprintf ("?e pf B not yet implemented\n");
} else {
memset (buffer, '\0', 255);
if (!p->iob.read_at) {
printf ("(cannot read memory)\n");
break;
} else p->iob.read_at (p->iob.io, (ut64)addr, buffer, 248);
p->printf ("0x%08"PFMT64x" = ", seeki);
for (j=0; j<10; j++) p->printf ("%02x ", buf[j]);
p->printf (" ... (");
for (j=0; j<10; j++)
if (IS_PRINTABLE (buf[j]))
p->printf ("%c", buf[j]);
p->printf (")");
}
i += 4;
break;
case 'f':
if (MUSTSET) {
realprintf ("wv4 %s @ 0x%08"PFMT64x"\n", setval, seeki);
} else {
p->printf ("0x%08"PFMT64x" = %f", seeki,
(float)(addr));
}
i += 4;
break;
case 'i':
case 'd': // TODO: support unsigned int?
if (MUSTSET) {
realprintf ("wv4 %s @ 0x%08"PFMT64x"\n", setval, seeki);
} else {
p->printf ("0x%08"PFMT64x" = ", seeki);
p->printf ("%"PFMT64d" ", addr);
}
i += 4;
break;
case 'D':
if (p->disasm && p->user)
i += p->disasm (p->user, seeki);
break;
case 'x':
if (MUSTSET) {
realprintf ("wv4 %s @ 0x%08"PFMT64x"\n", setval, seeki);
} else {
ut32 addr32 = (ut32)addr;
p->printf ("0x%08"PFMT64x" = ", seeki);
p->printf ("0x%08"PFMT64x" ", addr32);
}
//if (string_flag_offset(buf, (ut64)addr32, -1))
// p->printf("; %s", buf);
i += 4;
break;
case 'w':
case '1': // word (16 bits)
if (MUSTSET) {
realprintf ("wv2 %s @ 0x%08"PFMT64x"\n", setval, seeki);
} else {
p->printf ("0x%08x = ", seeki);
if (endian)
addr = (*(buf+i))<<8 | (*(buf+i+1));
else addr = (*(buf+i+1))<<8 | (*(buf+i));
p->printf ("0x%04x ", addr);
}
i+=2;
break;
case 'z': // zero terminated string
if (MUSTSET) {
realprintf ("?e pf z not yet supported\n");
} else {
p->printf ("0x%08"PFMT64x" = ", seeki);
for (; buf[i]&&i<len; i++) {
if (IS_PRINTABLE (buf[i]))
p->printf ("%c", buf[i]);
else p->printf (".");
}
}
break;
case 'Z': // zero terminated wide string
p->printf ("0x%08"PFMT64x" = ", seeki);
for (; buf[i] && i<len; i+=2) {
if (IS_PRINTABLE (buf[i]))
p->printf ("%c", buf[i]);
else p->printf (".");
}
p->printf (" ");
break;
case 's':
p->printf ("0x%08"PFMT64x" = ", seeki);
memset (buffer, '\0', 255);
if (p->iob.read_at) {
p->iob.read_at (p->iob.io, (ut64)addr,
buffer, sizeof (buffer)-8);
} else {
printf ("(cannot read memory)\n");
break;
}
p->printf ("0x%08"PFMT64x" -> 0x%08"PFMT64x" ",
seeki, addr);
p->printf ("%s ", buffer);
i += 4;
break;
case 'S':
p->printf ("0x%08"PFMT64x" = ", seeki);
memset (buffer, '\0', 255);
if (p->iob.read_at) {
p->iob.read_at (p->iob.io, addr64,
buffer, sizeof (buffer)-8);
} else {
printf ("(cannot read memory)\n");
break;
}
p->printf ("0x%08"PFMT64x" -> 0x%08"PFMT64x" ",
seeki, addr);
p->printf ("%s ", buffer);
i += 8;
break;
default:
/* ignore unknown chars */
break;
}
if (viewflags && p->offname) {
const char *s = p->offname (p->user, seeki);
if (s) p->printf ("@(%s)", s);
s = p->offname (p->user, addr);
if (s) p->printf ("*(%s)", s);
}
if (tmp != 'D')
p->printf ("\n");
last = tmp;
}
if (otimes>1)
p->printf ("}\n");
arg = orig;
idx = 0;
}
if (oldprintf)
p->printf = oldprintf;
beach:
free (buf);
if (args) {
free (args);
}
return i;
}