// SPDX-FileCopyrightText: 2008-2011 pancake // 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); } }