Start working on debugger
This commit is contained in:
@@ -129,7 +129,8 @@ endif
|
|||||||
|
|
||||||
|
|
||||||
cli_sources = files(
|
cli_sources = files(
|
||||||
'src/cli/main.c'
|
'src/cli/main.c',
|
||||||
|
'src/cli/debugger.c'
|
||||||
)
|
)
|
||||||
|
|
||||||
incdir = include_directories('include')
|
incdir = include_directories('include')
|
||||||
|
|||||||
140
src/cli/debugger.c
Normal file
140
src/cli/debugger.c
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
#include "../../include/ground.h"
|
||||||
|
#include "../linenoise/linenoise.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
typedef struct DebugCommand {
|
||||||
|
char* command;
|
||||||
|
struct {
|
||||||
|
char* at[32];
|
||||||
|
GroundSize count;
|
||||||
|
} args;
|
||||||
|
} DebugCommand;
|
||||||
|
|
||||||
|
static inline DebugCommand parseCommand(char* input) {
|
||||||
|
DebugCommand debugCommand;
|
||||||
|
// split by spaces
|
||||||
|
const char* delim = " ";
|
||||||
|
debugCommand.command = strtok(input, delim);
|
||||||
|
for (GroundSize i = 0; i < 32; i++) {
|
||||||
|
char* buf = strtok(NULL, delim);
|
||||||
|
if (buf == NULL) {
|
||||||
|
debugCommand.args.count = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
debugCommand.args.at[i] = buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
return debugCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct Debugger {
|
||||||
|
|
||||||
|
GroundSize currentInst;
|
||||||
|
|
||||||
|
} Debugger;
|
||||||
|
|
||||||
|
enum DebuggerStatus {
|
||||||
|
DBG_DONE, DBG_CONTINUE, DBG_WAIT, DBG_STEP
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline enum DebuggerStatus runCommand(char* input, GroundBytecode* bytecode, Debugger* debugger) {
|
||||||
|
DebugCommand cmd = parseCommand(input);
|
||||||
|
if (strcmp(cmd.command, "help") == 0) {
|
||||||
|
printf(
|
||||||
|
"Commands: \n" \
|
||||||
|
" help - Show this help message\n" \
|
||||||
|
" continue - Run the program until next breakpoint, error, or otherwise termination\n" \
|
||||||
|
" step - Run one instruction\n" \
|
||||||
|
" break [idx] - Sets a breakpoint on the specified index\n" \
|
||||||
|
" exit - Stop debugging and exit\n\n" \
|
||||||
|
|
||||||
|
" dump - Dump current state of VM\n" \
|
||||||
|
" view [slot] - Prints the variable in the current slot\n" \
|
||||||
|
" set [slot] [value] - Sets the current slot to the specified value\n" \
|
||||||
|
" copy [slot] [slot] - Copies a value from the second slot to the first\n" \
|
||||||
|
);
|
||||||
|
return DBG_CONTINUE;
|
||||||
|
}
|
||||||
|
if (strcmp(cmd.command, "continue") == 0) {
|
||||||
|
return DBG_CONTINUE;
|
||||||
|
}
|
||||||
|
if (strcmp(cmd.command, "step") == 0) {
|
||||||
|
return DBG_STEP;
|
||||||
|
}
|
||||||
|
if (strcmp(cmd.command, "break") == 0) {
|
||||||
|
return DBG_WAIT;
|
||||||
|
}
|
||||||
|
if (strcmp(cmd.command, "exit") == 0) {
|
||||||
|
return DBG_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(cmd.command, "dump") == 0) {
|
||||||
|
printf("%s", Ground.Stringify.Bytecode(bytecode));
|
||||||
|
return DBG_WAIT;
|
||||||
|
}
|
||||||
|
if (strcmp(cmd.command, "view") == 0) {
|
||||||
|
return DBG_WAIT;
|
||||||
|
}
|
||||||
|
if (strcmp(cmd.command, "set") == 0) {
|
||||||
|
return DBG_WAIT;
|
||||||
|
}
|
||||||
|
if (strcmp(cmd.command, "copy") == 0) {
|
||||||
|
return DBG_WAIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Unknown command %s\n", cmd.command);
|
||||||
|
return DBG_WAIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void runInstruction(GroundBytecodeProgram* program, GroundBytecodeHeap* heap) {
|
||||||
|
GroundSize i = 0;
|
||||||
|
while (i < program->len) {
|
||||||
|
struct GroundExecutionResult status = Ground.Bytecode.Instruction.execute(&program->at[i], heap);
|
||||||
|
if (Ground.Flags.error) {
|
||||||
|
fprintf(stderr, "Errors while debugging: \n");
|
||||||
|
Ground.Log.printErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (status.type) {
|
||||||
|
|
||||||
|
case _GER_CONTINUE: i++; break;
|
||||||
|
case _GER_RETURN: return;
|
||||||
|
case _GER_JUMP: i = status.as.line; break;
|
||||||
|
case _GER_END: exit(status.as.end);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void runDebugger(GroundBytecode* bytecode) {
|
||||||
|
printf("Ground Debugger\n");
|
||||||
|
printf("Type 'help' for a list of commands\n");
|
||||||
|
printf("Type 'start' to begin debugging\n");
|
||||||
|
printf("Type 'exit' to exit\n");
|
||||||
|
|
||||||
|
Debugger debugger;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
char* input = linenoise("> ");
|
||||||
|
if (input == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (runCommand(input, bytecode, &debugger)) {
|
||||||
|
case DBG_DONE: {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case DBG_CONTINUE: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DBG_WAIT: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DBG_STEP: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
#include "../../include/ground.h"
|
#include "../../include/ground.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
void runDebugger(GroundBytecode* bytecode);
|
||||||
|
|
||||||
enum ArgsAction {
|
enum ArgsAction {
|
||||||
ARGS_HELP, ARGS_EXECUTE, ARGS_DEBUG, ARGS_ASSEMBLE, ARGS_DISASSEMBLE
|
ARGS_HELP, ARGS_EXECUTE, ARGS_DEBUG, ARGS_ASSEMBLE, ARGS_DISASSEMBLE
|
||||||
};
|
};
|
||||||
@@ -73,7 +75,20 @@ int main(int argc, char** argv) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ARGS_DEBUG: {
|
case ARGS_DEBUG: {
|
||||||
fprintf(stderr, "Not yet implemented");
|
if (args.inputFile == NULL) {
|
||||||
|
fprintf(stderr, "Please specify a bytecode file\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
GroundBytecode bc = Ground.Bytecode.load(args.inputFile);
|
||||||
|
if (Ground.Flags.error) {
|
||||||
|
fprintf(stderr, "Failed to load bytecode, printing errors...\n");
|
||||||
|
Ground.Log.printErrors();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
runDebugger(&bc);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ARGS_ASSEMBLE: {
|
case ARGS_ASSEMBLE: {
|
||||||
|
|||||||
Reference in New Issue
Block a user