radare2/libr/debug/p/bfvm.c
2014-01-21 15:40:10 +01:00

308 lines
6.7 KiB
C

/*
* Copyright (C) 2008-2011 -- pancake <@nopcode.org>
* NOTE: This file has been ported from r1 and relicensed to LGPL
*/
#include "bfvm.h"
static ut8 bfvm_op(BfvmCPU *c) {
// XXX: this is slow :(
ut8 buf[4] = {0};
if (c && c->iob.read_at && !c->iob.read_at (c->iob.io, c->eip, buf, 4))
return 0xff;
return buf[0];
}
R_API int bfvm_in_trap(BfvmCPU *c) {
switch (bfvm_op (c)) {
case 0x00:
case 0xcc:
case 0xff:
return 1;
}
return 0;
}
R_API void bfvm_reset(BfvmCPU *c) {
memset (c->mem, '\0', c->size);
memset (c->input_buf, '\0', c->input_size);
memset (c->screen_buf, '\0', c->screen_size);
c->base = BFVM_DATA_ADDR;
c->input = BFVM_INPUT_ADDR;
c->input_idx = 0;
c->screen = BFVM_SCREEN_ADDR;
c->screen_idx = 0;
c->eip = 0; // TODO look forward nops
c->ptr = 0;
c->esp = c->base;
}
R_API int bfvm_init(BfvmCPU *c, ut32 size, int circular) {
memset (c, '\0', sizeof (BfvmCPU));
/* data */
c->mem = (ut8 *)malloc (size);
if (c->mem == NULL)
return 0;
memset (c->mem, '\0', size);
/* setup */
c->circular = circular;
c->size = size;
// TODO: use RBuffer or so here.. this is spagueti
/* screen */
c->screen = BFVM_SCREEN_ADDR;
c->screen_size = BFVM_SCREEN_SIZE;
c->screen_buf = (ut8*)malloc (c->screen_size);
memset (c->screen_buf, '\0', c->screen_size);
/* input */
c->input_size = BFVM_INPUT_SIZE;
c->input_buf = (ut8*)malloc (c->input_size);
bfvm_reset (c);
return 1;
}
R_API BfvmCPU *bfvm_new(RIOBind *iob) {
BfvmCPU *c = R_NEW0 (BfvmCPU);
bfvm_init (c, 4096, 1);
memcpy (&c->iob, iob, sizeof (c->iob));
return c;
}
R_API BfvmCPU *bfvm_free(BfvmCPU *c) {
free (c->mem);
c->mem = 0;
free (c->screen_buf);
c->screen_buf = 0;
free (c);
return NULL;
}
R_API ut8 *bfvm_get_ptr_at(BfvmCPU *c, ut64 at) {
if (at >= c->base) at -= c->base;
//if (at<0) at = c->circular? c->size-2: 0;
else if (at >= c->size) at = c->circular? 0: c->size-1;
//if (at<0) return c->mem;
return c->mem+at;
}
R_API ut8 *bfvm_get_ptr(BfvmCPU *c) {
//return bfvm_cpu.mem;
return bfvm_get_ptr_at (c, c->ptr);
}
R_API ut8 bfvm_get(BfvmCPU *c) {
ut8 *ptr = bfvm_get_ptr (c);
return ptr? *ptr: 0;
}
R_API void bfvm_inc(BfvmCPU *c) {
ut8 *mem = bfvm_get_ptr (c);
if (mem != NULL)
mem[0]++;
}
R_API void bfvm_dec(BfvmCPU *c) {
ut8 *mem = bfvm_get_ptr (c);
if (mem != NULL)
mem[0]--;
}
R_API int bfvm_reg_set(BfvmCPU *c, const char *str) {
char *ptr = strchr (str, ' ');
if (ptr == NULL)
return 0;
if (strstr (str, "eip"))
c->eip = r_num_math (NULL, ptr+1);
else if (strstr (str, "esp"))
c->esp = r_num_math (NULL, ptr+1);
else if (strstr (str, "ptr"))
c->ptr = r_num_math (NULL, ptr+1);
return 1;
}
/* screen and input */
R_API void bfvm_peek(BfvmCPU *c) {
int idx = c->input_idx;
ut8 *ptr = bfvm_get_ptr (c);
if (idx >= c->input_size)
idx = 0;
if (ptr) {
*ptr = c->input_buf[idx];
c->input_idx = idx+1;
}
}
R_API void bfvm_poke(BfvmCPU *c) {
int idx = c->screen_idx;
c->screen_buf[idx] = bfvm_get (c);
c->screen_idx = idx+1;
}
R_API int bfvm_trace_op(BfvmCPU *c, ut8 op) {
ut8 g;
switch (op) {
case '\0':
eprintf (" ; trap (%02x)\n", op);
case '.':
case ',':
case '+':
case '-':
case '>':
case '<':
eprintf ("%c", op);
break;
case '[':
case ']':
g = bfvm_get (c);
eprintf ("%c ; [ptr] = %d\n", op, g);
if (g!= 0)
eprintf ("[");
break;
}
return 0;
}
#define T if (c->trace)
/* debug */
R_API int bfvm_step(BfvmCPU *c, int over) {
ut8 op2, op = bfvm_op (c);
do {
T bfvm_trace_op (c, op);
switch (op) {
case '\0':
/* trap */
return 1;
case '.':
bfvm_get_ptr (c);
bfvm_poke (c);
break;
case ',':
bfvm_peek (c);
/* TODO read */
break;
case '+':
bfvm_inc (c);
break;
case '-':
bfvm_dec (c);
break;
case '>':
c->ptr++;
break;
case '<':
c->ptr--;
break;
case '[':
break;
case ']':
if (bfvm_get (c) != 0) {
do {
/* control underflow */
if (c->eip < (c->eip-1)) {
c->eip = 0;
break;
}
c->eip--;
} while (bfvm_op (c)!='[');
}
break;
default:
break;
}
c->eip++;
op2 = bfvm_op (c);
} while (over && op == op2);
return 0;
}
R_API int bfvm_contsc(BfvmCPU *c) {
c->breaked = 0;
while (!c->breaked) {
bfvm_step (c, 0);
if (bfvm_in_trap (c)) {
eprintf ("Trap instruction at 0x%08"PFMT64x"\n", c->eip);
break;
}
switch (bfvm_op (c)) {
case ',':
eprintf("contsc: read from input trap\n");
c->breaked = 1;
continue;
case '.':
eprintf ("contsc: print to screen trap\n");
c->breaked = 1;
continue;
}
}
return 0;
}
R_API int bfvm_cont(BfvmCPU *c, ut64 until) {
c->breaked = 0;
while (!c->breaked && c->eip != until) {
bfvm_step (c, 0);
if (bfvm_in_trap (c)) {
eprintf ("Trap instruction at 0x%"PFMT64x"\n", c->eip);
break;
}
}
return 0;
}
R_API int bfvm_trace(BfvmCPU *c, ut64 until) {
c->trace=1;
bfvm_cont (c, until);
c->trace=0;
return 0;
}
R_API void bfvm_show_regs(BfvmCPU *c, int rad) {
if (rad) {
eprintf ("fs regs\n");
eprintf ("f eip @ 0x%08"PFMT64x"\n", (ut64)c->eip);
eprintf ("f esp @ 0x%08"PFMT64x"\n", (ut64)c->esp);
eprintf ("f ptr @ 0x%08"PFMT64x"\n", (ut64)c->ptr+c->base);
eprintf ("fs *\n");
} else {
ut8 ch = bfvm_get (c);
eprintf (" eip 0x%08"PFMT64x" esp 0x%08"PFMT64x"\n",
(ut64)c->eip, (ut64)c->esp);
eprintf (" ptr 0x%08x [ptr] %d = 0x%02x '%c'\n",
(ut32)c->ptr, ch, ch, IS_PRINTABLE (ch)? ch:' ');
}
}
R_API void bfvm_maps(BfvmCPU *c, int rad) {
if (rad) {
eprintf ("fs sections\n");
eprintf ("e cmd.vprompt=px@screen\n");
eprintf ("f section_code @ 0x%08"PFMT64x"\n", (ut64)BFVM_CODE_ADDR);
eprintf ("f section_code_end @ 0x%08"PFMT64x"\n", (ut64)BFVM_CODE_ADDR+BFVM_CODE_SIZE);
eprintf ("f section_data @ 0x%08"PFMT64x"\n", (ut64)c->base);
eprintf ("f section_data_end @ 0x%08"PFMT64x"\n", (ut64)c->base+c->size);
eprintf ("f screen @ 0x%08"PFMT64x"\n", (ut64)c->screen);
eprintf ("f section_screen @ 0x%08"PFMT64x"\n", (ut64)c->screen);
eprintf ("f section_screen_end @ 0x%08"PFMT64x"\n", (ut64)c->screen+c->screen_size);
eprintf ("f input @ 0x%08"PFMT64x"\n", (ut64)c->input);
eprintf ("f section_input @ 0x%08"PFMT64x"\n", (ut64)c->input);
eprintf ("f section_input_end @ 0x%08"PFMT64x"\n", (ut64)c->input+c->input_size);
eprintf ("fs *\n");
} else {
eprintf ("0x%08"PFMT64x" - 0x%08"PFMT64x" rwxu 0x%08"PFMT64x" .code\n",
(ut64)0, (ut64)c->size, (ut64)c->size);
eprintf ("0x%08"PFMT64x" - 0x%08"PFMT64x" rw-- 0x%08"PFMT64x" .data\n",
(ut64)c->base, (ut64)(c->base+c->size), (ut64)c->size);
eprintf ("0x%08"PFMT64x" - 0x%08"PFMT64x" rw-- 0x%08"PFMT64x" .screen\n",
(ut64)c->screen, (ut64)(c->screen+c->screen_size), (ut64)c->screen_size);
eprintf ("0x%08"PFMT64x" - 0x%08"PFMT64x" rw-- 0x%08"PFMT64x" .input\n",
(ut64)c->input, (ut64)(c->input+c->input_size), (ut64)c->input_size);
}
}