rizin/librz/debug/p/bfvm.c
2022-03-24 08:27:18 +08:00

315 lines
6.8 KiB
C

// SPDX-FileCopyrightText: 2008-2011 pancake <pancake@nopcode.org>
// SPDX-License-Identifier: LGPL-3.0-only
#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];
}
RZ_API int bfvm_in_trap(BfvmCPU *c) {
switch (bfvm_op(c)) {
case 0x00:
case 0xcc:
case 0xff:
return 1;
}
return 0;
}
RZ_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;
}
RZ_API int bfvm_init(BfvmCPU *c, ut32 size, int circular) {
memset(c, '\0', sizeof(BfvmCPU));
/* data */
c->mem = (ut8 *)malloc(size);
if (!c->mem) {
return 0;
}
memset(c->mem, '\0', size);
/* setup */
c->circular = circular;
c->size = size;
// TODO: use RzBuffer 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;
}
RZ_API BfvmCPU *bfvm_new(RzIOBind *iob) {
BfvmCPU *c = RZ_NEW0(BfvmCPU);
bfvm_init(c, 4096, 1);
memcpy(&c->iob, iob, sizeof(c->iob));
return c;
}
RZ_API BfvmCPU *bfvm_free(BfvmCPU *c) {
free(c->mem);
c->mem = 0;
free(c->screen_buf);
c->screen_buf = 0;
free(c);
return NULL;
}
RZ_API ut8 *bfvm_get_ptr_at(BfvmCPU *c, ut64 at) {
if (at >= c->base) {
at -= c->base;
} else if (at >= c->size) {
at = c->circular ? 0 : c->size - 1;
}
return c->mem + at;
}
RZ_API ut8 *bfvm_get_ptr(BfvmCPU *c) {
// return bfvm_cpu.mem;
return bfvm_get_ptr_at(c, c->ptr);
}
RZ_API ut8 bfvm_get(BfvmCPU *c) {
ut8 *ptr = bfvm_get_ptr(c);
return ptr ? *ptr : 0;
}
RZ_API void bfvm_inc(BfvmCPU *c) {
ut8 *mem = bfvm_get_ptr(c);
if (mem != NULL) {
mem[0]++;
}
}
RZ_API void bfvm_dec(BfvmCPU *c) {
ut8 *mem = bfvm_get_ptr(c);
if (mem != NULL) {
mem[0]--;
}
}
RZ_API int bfvm_reg_set(BfvmCPU *c, const char *str) {
char *ptr = strchr(str, ' ');
if (!ptr) {
return 0;
}
if (strstr(str, "eip")) {
c->eip = rz_num_math(NULL, ptr + 1);
} else if (strstr(str, "esp")) {
c->esp = rz_num_math(NULL, ptr + 1);
} else if (strstr(str, "ptr")) {
c->ptr = rz_num_math(NULL, ptr + 1);
}
return 1;
}
/* screen and input */
RZ_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;
}
}
RZ_API void bfvm_poke(BfvmCPU *c) {
int idx = c->screen_idx;
c->screen_buf[idx] = bfvm_get(c);
c->screen_idx = idx + 1;
}
RZ_API int bfvm_trace_op(BfvmCPU *c, ut8 op) {
ut8 g;
switch (op) {
case '\0':
eprintf(" ; trap (%02x)\n", op);
// fallthrough
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 */
RZ_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;
}
RZ_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;
}
RZ_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;
}
RZ_API int bfvm_trace(BfvmCPU *c, ut64 until) {
c->trace = 1;
bfvm_cont(c, until);
c->trace = 0;
return 0;
}
RZ_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 : ' ');
}
}
RZ_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);
}
}