diff --git a/include/vm_debug.h b/include/vm_debug.h new file mode 100644 index 0000000..9d97e85 --- /dev/null +++ b/include/vm_debug.h @@ -0,0 +1,60 @@ +#ifndef _VM_DEBUG_H_ +#define _VM_DEBUG_H_ + +typedef struct { + /* + * Most commands that need an argument will simply use addr1, but a + * few have more than one address--hence addr2. + */ + int addr1; + int addr2; + + /* + * If we have a thing we want to work with, but want to leave what + * that is up to the helper func, then you can write it into the + * target. + * + * If a command uses target, followed by an address, that address + * will be in addr1. + */ + char target[256]; +} vm_debug_args; + +typedef void (*vm_debug_func)(vm_debug_args *); + +typedef struct { + /* + * The name field is the full name of the command; each command also + * has an abbreviated form (either is acceptable as input), which is + * defined in the abbrev field. + */ + char *name; + char *abbrev; + + /* + * The number of arguments we expect to see + */ + int nargs; + + /* + * The function that will do something with the command's input + */ + vm_debug_func handler; + + /* + * What do our arguments look like? + */ + char *argdesc; + + /* + * What do we do? + */ + char *desc; +} vm_debug_cmd; + +#define DEBUG_CMD(x) \ + void vm_debug_cmd_##x (vm_debug_args *args) + +extern DEBUG_CMD(help); + +#endif diff --git a/sources.cmake b/sources.cmake index da87f99..c239605 100644 --- a/sources.cmake +++ b/sources.cmake @@ -25,6 +25,7 @@ set(erc_sources option.c vm_area.c vm_bitfont.c + vm_debug.c vm_di.c vm_event.c vm_reflect.c diff --git a/src/vm_debug.c b/src/vm_debug.c new file mode 100644 index 0000000..45afd7a --- /dev/null +++ b/src/vm_debug.c @@ -0,0 +1,27 @@ +/* + * vm_debug.c + */ + +#include + +#include "vm_debug.h" +#include "vm_di.h" + +vm_debug_cmd cmdtable[] = { + { "help", "h", 0, vm_debug_cmd_help, "", + "Print out this list of commands", }, +}; + +#define CMDTABLE_SIZE (sizeof(cmdtable) / sizeof(vm_debug_cmd)) + +DEBUG_CMD(help) +{ + FILE *stream = (FILE *)vm_di_get(VM_OUTPUT); + vm_debug_cmd *cmd; + + for (int i = 0; i < CMDTABLE_SIZE; i++) { + cmd = &cmdtable[i]; + fprintf(stream, "%-15s%-5s%-15s%s\n", cmd->name, cmd->abbrev, + cmd->argdesc, cmd->desc); + } +} diff --git a/tests/vm_debug.c b/tests/vm_debug.c new file mode 100644 index 0000000..9b4be2f --- /dev/null +++ b/tests/vm_debug.c @@ -0,0 +1,47 @@ +#include + +#include +#include +#include "vm_debug.h" +#include "vm_di.h" + +static char buf[BUFSIZ]; +static FILE *stream = NULL; +static vm_debug_args args; + +static void +setup() +{ + // Don't worry...we don't care about /dev/null, because we'll hijack + // the output with setvbuf below + stream = fopen("/dev/null", "w"); + if (stream == NULL) { + perror("Could not open /dev/null for stream testing"); + exit(1); + } + + vm_di_set(VM_OUTPUT, stream); + + // Writing to stream will now write to buf + setvbuf(stream, buf, _IOFBF, BUFSIZ); +} + +static void +teardown() +{ + memset(buf, 0, BUFSIZ); + fclose(stream); +} + +TestSuite(vm_debug, .init = setup, .fini = teardown); + +/* + * I dunno what we'll end up printing! It'll change as we add commands, + * so we just test if we print _something_. + */ +Test(vm_debug, cmd_help) +{ + vm_debug_cmd_help(&args); + cr_assert_neq(strlen(buf), 0); + printf("%s", buf); +}