improve disassembly and add info about more commands

This commit is contained in:
2026-06-02 21:42:01 +10:00
parent cd4023d6e5
commit 0986dae5df
2 changed files with 163 additions and 111 deletions

View File

@@ -2,6 +2,7 @@ struct Foo {
int x
init(int x) {
breakpoint
self.x = x
}
@@ -14,7 +15,5 @@ func main() -> int {
Foo foo = new Foo(123)
foo.x = 50
breakpoint
return foo.test()
}

View File

@@ -11,13 +11,26 @@
#include <inttypes.h>
static inline int64_t max(int64_t a, int64_t b) {
return a > b ? a : b;
}
static inline int64_t min(int64_t a, int64_t b) {
return a < b ? a : b;
}
ResultType(voidPtr, charptr) disassembleHandler(CometDebugger* dbgr, int argc, char** argv) {
Range range;
if (argc < 1) {
return Error(voidPtr, charptr, "command needs 1 arg");
range = (Range){
.start = max(dbgr->vm->currentFrame->ip - 5, 0),
.end = min(dbgr->vm->currentFrame->ip + 4, dbgr->vm->numInstructions-1)
};
} else {
range = parseRange(argv[0]);
}
Range range = parseRange(argv[0]);
if (range.start < 0) {
return Error(voidPtr, charptr, "can't start disassembly at negative address!");
@@ -30,30 +43,103 @@ ResultType(voidPtr, charptr) disassembleHandler(CometDebugger* dbgr, int argc, c
}
for (size_t i = range.start; i <= range.end; i++) {
if (i < dbgr->vm->currentFrame->ip) {
printf(ESC_DIM " ");
} else if (i == dbgr->vm->currentFrame->ip) {
printf(ESC_BOLD ESC_BRIGHT_GREEN_FG " -> ");
} else {
printf(" ");
}
// some instructions have a special colour to make it easier to spot loops
switch (dbgr->vm->instructions[i].opcode) {
case INST_JMP:
case INST_JMP_IF_FALSE:
case INST_CALL:
case INST_CALL_METHOD:
case INST_RET:
printf(ESC_BOLD ESC_CYAN_FG);
break;
default:
break;
}
if (i >= dbgr->vm->numInstructions) {
printf("0x%04lx ??? (outside bytecode)\n", i);
printf("0x%04lx ??? <invalid address>\n" ESC_RESET, i);
break;
}
printf("%s\n", cometInstructionToCStr(dbgr->vm, dbgr->vm->instructions[i], i));
printf("%s\n" ESC_RESET, cometInstructionToCStr(dbgr->vm, dbgr->vm->instructions[i], i));
}
return Success(voidPtr, charptr, NULL);
}
ResultType(voidPtr, charptr) helpHandler(CometDebugger* dbgr, int argc, char** argv);
int tokenize(char* line, char** argv, int maxArgs) {
int argc = 0;
while (*line) {
// skip whitespace
while (*line == ' ' || *line == '\t' || *line == '\n')
line++;
if (*line == '\0')
break;
if (argc >= maxArgs)
break;
argv[argc++] = line;
// find end of token
while (*line &&
*line != ' ' &&
*line != '\t' &&
*line != '\n') {
line++;
}
// terminate token
if (*line) {
*line = '\0';
line++;
}
}
return argc;
}
static const char* helpAliases[] = {"h", NULL};
static const char* disassembleAliases[] = {"d", NULL};
static const char* breakAliases[] = {"b", NULL};
static const char* unbreakAliases[] = {"ubreak", "u", "ub", NULL};
static const char* stackAliases[] = {"st", NULL};
static const char* localAliases[] = {"l", NULL};
static const char* structsAliases[] = {"ls", NULL};
static const char* stepAliases[] = {"s", NULL};
static const char* continueAliases[] = {"c", "cont", NULL};
ResultType(voidPtr, charptr) helpHandler(CometDebugger* dbgr, int argc, char** argv);
const CometDebugCommand DBGR_COMMANDS[] = {
{"help", helpHandler, "display a list of all commnads", "h | h <command>", helpAliases},
{"disassemble", disassembleHandler, "disassemble a line", "d <line> | d <start>:<end>", disassembleAliases},
{"help", helpHandler, "display a list of all commnads or get help about a specific command", "h | h <command>", helpAliases},
{"disassemble", disassembleHandler, "disassemble a line or range of lines", "d | d <line> | d <start>:<end>", disassembleAliases},
{"break", NULL, "set a breakpoint", "b <address> | b <functionName>", breakAliases},
{"unbreak", NULL, "delete a breakpoint", "ub <breakpointId>", unbreakAliases},
{"stack", NULL, "display the current state of the stack", "st | st <index>", stackAliases},
{"local", NULL, "print all variables or get the value of a variable", "l | l <name>", localAliases},
{"structs", NULL, "print all structs or display info about a struct", "ls | ls <name>", structsAliases},
{"step", NULL, "execute next instruction", "s | s <numInstructions>", stepAliases},
{"continue", NULL, "continue execution", "c", continueAliases},
};
const CometDebugCommand* getCommandByName(char* cmdName) {
@@ -82,6 +168,74 @@ const CometDebugCommand* getCommandByName(char* cmdName) {
return NULL;
}
ResultType(voidPtr, charptr) parseCommand(CometDebugger* dbgr, char* line) {
int maxArgs = 16;
char* argv[maxArgs];
int argc = tokenize(line, argv, maxArgs);
if (argc == 0)
return Success(voidPtr, charptr, NULL);
const CometDebugCommand* cmd = getCommandByName(argv[0]);
if (cmd == NULL) {
Estr errMsg = CREATE_ESTR("dbgr: no such command: \"");
APPEND_ESTR(errMsg, argv[0]);
APPEND_ESTR(errMsg, "\"");
fprintf(stderr, "%s\n", errMsg.str);
DESTROY_ESTR(errMsg);
return Success(voidPtr, charptr, NULL);
}
ResultType(voidPtr, charptr) cmdResult = cmd->handler(dbgr, argc - 1, &argv[1]);
if (cmdResult.error) {
fprintf(stderr, "%s: %s\n", cmd->name, cmdResult.as.error);
}
return Success(voidPtr, charptr, NULL);
}
void debuggerLoop(CometDebugger* dbgr) {
bool looping = true;
while (looping) {
char* userInput = NULL;
size_t size = 0;
ssize_t charsRead;
printf("dbgr > ");
charsRead = getline(&userInput, &size, stdin);
if (charsRead == -1) {
fprintf(stderr, "getline: failed to read input!");
return;
}
ResultType(voidPtr, charptr) commandResult = parseCommand(dbgr, userInput);
printf("\n");
if (commandResult.error)
break;
}
}
void startDebugger(CometVM* vm) {
CometDebugger* newDbgr = malloc(sizeof(CometDebugger));
newDbgr->vm = vm;
printf(ESC_BOLD ESC_CYAN_FG "\nBREAKPOINT - COMET DEBUGGER" ESC_RESET "\n");
printf(ESC_BOLD "VM State:\n" ESC_RESET);
printf(" - IP: 0x%016lx\n", vm->currentFrame->ip);
printf(" - Current Inst: %s\n", cometInstructionToCStr(vm, vm->instructions[vm->currentFrame->ip], vm->currentFrame->ip));
printf(" - SP: 0x%08x\n", vm->currentFrame->sp);
printf(" - Stack: %s\n\n", stackAsString(*vm->currentStack, *vm->currentSp));
debuggerLoop(newDbgr);
free(newDbgr);
}
void printAliases(CometDebugCommand cmd) {
size_t aliasIdx = 0;
while (true) {
@@ -110,6 +264,7 @@ ResultType(voidPtr, charptr) helpHandler(CometDebugger* dbgr, int argc, char** a
}
printf(ESC_BOLD ESC_CYAN_FG "\\\\\\ %s ///\n\n" ESC_RESET, cmd->name);
printf(ESC_BOLD ESC_YELLOW_FG "Description:" ESC_RESET " %s\n", cmd->help);
printf(ESC_BOLD ESC_YELLOW_FG "Usage:" ESC_RESET " %s\n", cmd->usage);
printf(ESC_BOLD ESC_YELLOW_FG "Aliases: " ESC_RESET);
printAliases(*cmd);
@@ -481,93 +636,6 @@ char* cometInstructionToCStr(CometVM* vm, CometSerializedInst inst, uint64_t ins
return buffer;
}
int tokenize(char* line, char** argv, int maxArgs) {
int argc = 0;
while (*line) {
// skip whitespace
while (*line == ' ' || *line == '\t' || *line == '\n')
line++;
if (*line == '\0')
break;
if (argc >= maxArgs)
break;
argv[argc++] = line;
// find end of token
while (*line &&
*line != ' ' &&
*line != '\t' &&
*line != '\n') {
line++;
}
// terminate token
if (*line) {
*line = '\0';
line++;
}
}
return argc;
}
ResultType(voidPtr, charptr) parseCommand(CometDebugger* dbgr, char* line) {
int maxArgs = 16;
char* argv[maxArgs];
int argc = tokenize(line, argv, maxArgs);
if (argc == 0)
return Success(voidPtr, charptr, NULL);
const CometDebugCommand* cmd = getCommandByName(argv[0]);
if (cmd == NULL) {
Estr errMsg = CREATE_ESTR("dbgr: no such command: \"");
APPEND_ESTR(errMsg, argv[0]);
APPEND_ESTR(errMsg, "\"");
fprintf(stderr, "%s\n", errMsg.str);
DESTROY_ESTR(errMsg);
return Success(voidPtr, charptr, NULL);
}
ResultType(voidPtr, charptr) cmdResult = cmd->handler(dbgr, argc - 1, &argv[1]);
if (cmdResult.error) {
fprintf(stderr, "%s: %s\n", cmd->name, cmdResult.as.error);
}
return Success(voidPtr, charptr, NULL);
}
void debuggerLoop(CometDebugger* dbgr) {
bool looping = true;
while (looping) {
char* userInput = NULL;
size_t size = 0;
ssize_t charsRead;
printf("dbgr > ");
charsRead = getline(&userInput, &size, stdin);
if (charsRead == -1) {
fprintf(stderr, "getline: failed to read input!");
return;
}
ResultType(voidPtr, charptr) commandResult = parseCommand(dbgr, userInput);
printf("\n");
if (commandResult.error)
break;
}
}
char* stackAsString(int64_t* stack, uint32_t sp) {
Estr stackString = CREATE_ESTR("[");
@@ -597,19 +665,4 @@ char* stackTrace(CometVM* vm) {
}
return stackTraceStr.str;
}
void startDebugger(CometVM* vm) {
CometDebugger* newDbgr = malloc(sizeof(CometDebugger));
newDbgr->vm = vm;
printf(ESC_BOLD ESC_CYAN_FG "\nBREAKPOINT - COMET DEBUGGER" ESC_RESET "\n");
printf(ESC_BOLD "VM State:\n" ESC_RESET);
printf(" - IP: 0x%016lx\n", vm->currentFrame->ip);
printf(" - Current Inst: %s\n", cometInstructionToCStr(vm, vm->instructions[vm->currentFrame->ip], vm->currentFrame->ip));
printf(" - SP: 0x%08x\n", vm->currentFrame->sp);
printf(" - Stack: %s\n\n", stackAsString(*vm->currentStack, *vm->currentSp));
debuggerLoop(newDbgr);
free(newDbgr);
}