radare2/libr/print/format.c
pancake 1e6806aa84 * Add R_INLINE in config.h
* Add R_API directive in r_types
* Huge refactoring for r_print
  - C code format
  - formatted memory structures also working (not finished)
  - unix, dos and w32 timestamps
  - Added p->interrupt to break loong loops (should we think in a limit?)
  - print formats that need processing returns the number of bytes processed
    - if they return 0 is because they failed
  - Much more simplified code than the one in r1
  - Use p->printf instead of r_cons_printf (aim to independize from r_cons)
  - Some basic support for color output
2009-03-12 00:42:32 +00:00

258 lines
5.8 KiB
C

/* radare - LGPL - Copyright 2007-2009 pancake<nopcode.org> */
#include "r_cons.h"
#include "r_util.h"
#include "r_print.h"
static void print_mem_help()
{
printf(
"Usage: pm [times][format] [arg0 arg1]\n"
"Example: pm 10xiz pointer length string\n"
"Example: pm {array_size}b @ array_base\n"
" e - temporally swap endian\n"
//" D - double (8 bytes)\n"
" f - float value\n"
" b - one byte \n"
" B - show 10 first bytes of buffer\n"
" d - %%d integer value (4 bytes)\n"
" w - word (16 bit hexa)\n"
" q - quadword (8 bytes)\n"
" p - pointer reference\n"
" x - 0x%%08x hexadecimal value\n"
" X - 0x%%08x hexadecimal value and flag (fd @ addr)\n"
" z - \\0 terminated string\n"
" Z - \\0 terminated wide string\n"
" s - pointer to string\n"
" t - unix timestamp string\n"
" * - next char is pointer\n"
" . - skip 1 byte\n");
}
/* TODO: needs refactoring */
void r_print_format(struct r_print_t *p, u64 seek, const u8* buf, int len, const char *fmt)
{
unsigned char buffer[256];
int endian = 0;
int i,j,idx;
int times, otimes;
char tmp, last;
char *args, *bracket;
int nargs = 0;
const char *arg = fmt;
const char *argend = arg+strlen(fmt);
u64 addr = 0;
char namefmt[8];
i = j = 0;
while(*arg && *arg==' ') arg = arg +1;
/* get times */
otimes = times = atoi(arg);
if (times > 0)
while((*arg>='0'&&*arg<='9')) arg = arg +1;
bracket = strchr(arg,'{');
if (bracket) {
char *end = strchr(arg,'}');
if (end == NULL) {
fprintf(stderr, "No end bracket. Try pm {ecx}b @ esi\n");
return;
}
*end='\0';
times = r_num_math(NULL, bracket+1);
arg = end + 1;
}
if (arg[0]=='\0') {
print_mem_help();
return;
}
/* get args */
args = strchr(arg, ' ');
if (args) {
int l, 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 l = strlen(r_str_word_get0(args+1, i));
if (l>maxl) maxl = l;
}
l++;
sprintf(namefmt, "%%%ds : ", maxl);
}
/* go format */
i = 0;
if (times==0) otimes=times=1;
for(;times;times--) { // repeat N times
const char * orig = arg;
if (otimes>1)
p->printf("0x%08llx [%d] {\n", seek+i, otimes-times);
for(idx=0;arg<argend && idx<len;idx++, arg=arg+1) {
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);
tmp = *arg;
feed_me_again:
if (tmp == 0 && last != '*')
break;
/* skip chars */
switch(tmp) {
case '*':
if (i<=0) break;
tmp = last;
arg = arg - 1;
idx--;
goto feed_me_again;
case 'e': // tmp swap endian
idx--;
endian ^=1;
continue;
case '.': // skip char
i++;
idx--;
continue;
case '?': // help
print_mem_help();
idx--;
i=len; // exit
continue;
}
if (idx<nargs) {
p->printf(namefmt, r_str_word_get0(args, idx));
}
/* 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;
u64 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': {
double doub;
memcpy(&doub, buf+i, sizeof(double));
p->printf("%e = ", doub);
p->printf("(double)");
i+=8;
}
break;
case 'q':
p->printf("0x%08x = ", seek+i);
p->printf("(qword)");
i+=8;
break;
case 'b':
p->printf("0x%08x = ", seek+i);
p->printf("%d ; 0x%02x ; '%c' ",
buf[i], buf[i], IS_PRINTABLE(buf[i])?buf[i]:0);
i++;
break;
case 'B':
memset(buffer, '\0', 255);
if (p->read_at)
p->read_at((u64)addr, buffer, 248, p->user);
else {
printf("(cannot read memory)\n");
break;
}
p->printf("0x%08x = ", seek+i);
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 'd':
p->printf("0x%08x = ", seek+i);
p->printf("%d", addr);
i+=4;
break;
case 'x':
p->printf("0x%08x = ", seek+i);
p->printf("0x%08x ", addr);
i+=4;
break;
case 'X': {
u32 addr32 = (u32)addr;
//char buf[128];
p->printf("0x%08x = ", seek+i);
p->printf("0x%08llx ", addr32);
//if (string_flag_offset(buf, (u64)addr32, -1))
// p->printf("; %s", buf);
i+=4;
} break;
case 'w':
case '1': // word (16 bits)
p->printf("0x%08x = ", seek+i);
if (endian)
addr = (*(buf+i))<<8 | (*(buf+i+1));
else addr = (*(buf+i+1))<<8 | (*(buf+i));
p->printf("0x%04x ", addr);
break;
case 'z': // zero terminated string
p->printf("0x%08x = ", seek+i);
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%08x = ", seek+i);
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%08x = ", seek+i);
memset(buffer, '\0', 255);
if (p->read_at)
p->read_at((u64)addr, buffer, 248, p->user);
else {
printf("(cannot read memory)\n");
break;
}
p->printf("0x%08x -> 0x%08x ", seek+i, addr);
p->printf("%s ", buffer);
i+=4;
break;
default:
/* ignore unknown chars */
break;
}
p->printf("\n");
last = tmp;
}
if (otimes>1)
p->printf("}\n");
arg = orig;
idx = 0;
}
// free((void *)&args);
}