mirror of https://github.com/mgba-emu/mgba.git
Debugger: Add support for additional platforms in CLI
This commit is contained in:
parent
8ec961d2e8
commit
a8731d280f
|
@ -8,95 +8,71 @@
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct DebugVector {
|
|
||||||
struct DebugVector* next;
|
|
||||||
enum DVType {
|
|
||||||
DV_ERROR_TYPE,
|
|
||||||
DV_INT_TYPE,
|
|
||||||
DV_CHAR_TYPE
|
|
||||||
} type;
|
|
||||||
union {
|
|
||||||
int32_t intValue;
|
|
||||||
char* charValue;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char* ERROR_MISSING_ARGS = "Arguments missing";
|
static const char* ERROR_MISSING_ARGS = "Arguments missing";
|
||||||
|
|
||||||
static struct CLIDebugger* _activeDebugger;
|
static struct CLIDebugger* _activeDebugger;
|
||||||
|
|
||||||
typedef void (*DebuggerCommand)(struct CLIDebugger*, struct DebugVector*);
|
static void _breakInto(struct CLIDebugger*, struct CLIDebugVector*);
|
||||||
typedef struct DebugVector* (*DVParser)(struct CLIDebugger* debugger, const char* string, size_t length);
|
static void _continue(struct CLIDebugger*, struct CLIDebugVector*);
|
||||||
|
static void _disassemble(struct CLIDebugger*, struct CLIDebugVector*);
|
||||||
static struct DebugVector* _DVParse(struct CLIDebugger* debugger, const char* string, size_t length);
|
static void _disassembleArm(struct CLIDebugger*, struct CLIDebugVector*);
|
||||||
static struct DebugVector* _DVStringParse(struct CLIDebugger* debugger, const char* string, size_t length);
|
static void _disassembleThumb(struct CLIDebugger*, struct CLIDebugVector*);
|
||||||
|
static void _next(struct CLIDebugger*, struct CLIDebugVector*);
|
||||||
static void _breakInto(struct CLIDebugger*, struct DebugVector*);
|
static void _print(struct CLIDebugger*, struct CLIDebugVector*);
|
||||||
static void _continue(struct CLIDebugger*, struct DebugVector*);
|
static void _printBin(struct CLIDebugger*, struct CLIDebugVector*);
|
||||||
static void _disassemble(struct CLIDebugger*, struct DebugVector*);
|
static void _printHex(struct CLIDebugger*, struct CLIDebugVector*);
|
||||||
static void _disassembleArm(struct CLIDebugger*, struct DebugVector*);
|
static void _printStatus(struct CLIDebugger*, struct CLIDebugVector*);
|
||||||
static void _disassembleThumb(struct CLIDebugger*, struct DebugVector*);
|
static void _printHelp(struct CLIDebugger*, struct CLIDebugVector*);
|
||||||
static void _next(struct CLIDebugger*, struct DebugVector*);
|
static void _quit(struct CLIDebugger*, struct CLIDebugVector*);
|
||||||
static void _print(struct CLIDebugger*, struct DebugVector*);
|
static void _readByte(struct CLIDebugger*, struct CLIDebugVector*);
|
||||||
static void _printBin(struct CLIDebugger*, struct DebugVector*);
|
static void _reset(struct CLIDebugger*, struct CLIDebugVector*);
|
||||||
static void _printHex(struct CLIDebugger*, struct DebugVector*);
|
static void _readHalfword(struct CLIDebugger*, struct CLIDebugVector*);
|
||||||
static void _printStatus(struct CLIDebugger*, struct DebugVector*);
|
static void _readWord(struct CLIDebugger*, struct CLIDebugVector*);
|
||||||
static void _printHelp(struct CLIDebugger*, struct DebugVector*);
|
static void _setBreakpoint(struct CLIDebugger*, struct CLIDebugVector*);
|
||||||
static void _quit(struct CLIDebugger*, struct DebugVector*);
|
static void _clearBreakpoint(struct CLIDebugger*, struct CLIDebugVector*);
|
||||||
static void _readByte(struct CLIDebugger*, struct DebugVector*);
|
static void _setWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
|
||||||
static void _reset(struct CLIDebugger*, struct DebugVector*);
|
|
||||||
static void _readHalfword(struct CLIDebugger*, struct DebugVector*);
|
|
||||||
static void _readWord(struct CLIDebugger*, struct DebugVector*);
|
|
||||||
static void _setBreakpoint(struct CLIDebugger*, struct DebugVector*);
|
|
||||||
static void _clearBreakpoint(struct CLIDebugger*, struct DebugVector*);
|
|
||||||
static void _setWatchpoint(struct CLIDebugger*, struct DebugVector*);
|
|
||||||
|
|
||||||
static void _breakIntoDefault(int signal);
|
static void _breakIntoDefault(int signal);
|
||||||
static void _disassembleMode(struct CLIDebugger*, struct DebugVector*, enum ExecutionMode mode);
|
static void _disassembleMode(struct CLIDebugger*, struct CLIDebugVector*, enum ExecutionMode mode);
|
||||||
static void _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode);
|
static void _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode);
|
||||||
|
|
||||||
static struct {
|
static struct CLIDebuggerCommandSummary _debuggerCommands[] = {
|
||||||
const char* name;
|
{ "b", _setBreakpoint, CLIDVParse, "Set a breakpoint" },
|
||||||
DebuggerCommand command;
|
{ "break", _setBreakpoint, CLIDVParse, "Set a breakpoint" },
|
||||||
DVParser parser;
|
|
||||||
const char* summary;
|
|
||||||
} _debuggerCommands[] = {
|
|
||||||
{ "b", _setBreakpoint, _DVParse, "Set a breakpoint" },
|
|
||||||
{ "break", _setBreakpoint, _DVParse, "Set a breakpoint" },
|
|
||||||
{ "c", _continue, 0, "Continue execution" },
|
{ "c", _continue, 0, "Continue execution" },
|
||||||
{ "continue", _continue, 0, "Continue execution" },
|
{ "continue", _continue, 0, "Continue execution" },
|
||||||
{ "d", _clearBreakpoint, _DVParse, "Delete a breakpoint" },
|
{ "d", _clearBreakpoint, CLIDVParse, "Delete a breakpoint" },
|
||||||
{ "delete", _clearBreakpoint, _DVParse, "Delete a breakpoint" },
|
{ "delete", _clearBreakpoint, CLIDVParse, "Delete a breakpoint" },
|
||||||
{ "dis", _disassemble, _DVParse, "Disassemble instructions" },
|
{ "dis", _disassemble, CLIDVParse, "Disassemble instructions" },
|
||||||
{ "dis/a", _disassembleArm, _DVParse, "Disassemble instructions as ARM" },
|
{ "dis/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" },
|
||||||
{ "dis/t", _disassembleThumb, _DVParse, "Disassemble instructions as Thumb" },
|
{ "dis/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" },
|
||||||
{ "disasm", _disassemble, _DVParse, "Disassemble instructions" },
|
{ "disasm", _disassemble, CLIDVParse, "Disassemble instructions" },
|
||||||
{ "disasm/a", _disassembleArm, _DVParse, "Disassemble instructions as ARM" },
|
{ "disasm/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" },
|
||||||
{ "disasm/t", _disassembleThumb, _DVParse, "Disassemble instructions as Thumb" },
|
{ "disasm/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" },
|
||||||
{ "disassemble", _disassemble, _DVParse, "Disassemble instructions" },
|
{ "disassemble", _disassemble, CLIDVParse, "Disassemble instructions" },
|
||||||
{ "disassemble/a", _disassembleArm, _DVParse, "Disassemble instructions as ARM" },
|
{ "disassemble/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" },
|
||||||
{ "disassemble/t", _disassembleThumb, _DVParse, "Disassemble instructions as Thumb" },
|
{ "disassemble/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" },
|
||||||
{ "h", _printHelp, _DVStringParse, "Print help" },
|
{ "h", _printHelp, CLIDVStringParse, "Print help" },
|
||||||
{ "help", _printHelp, _DVStringParse, "Print help" },
|
{ "help", _printHelp, CLIDVStringParse, "Print help" },
|
||||||
{ "i", _printStatus, 0, "Print the current status" },
|
{ "i", _printStatus, 0, "Print the current status" },
|
||||||
{ "info", _printStatus, 0, "Print the current status" },
|
{ "info", _printStatus, 0, "Print the current status" },
|
||||||
{ "n", _next, 0, "Execute next instruction" },
|
{ "n", _next, 0, "Execute next instruction" },
|
||||||
{ "next", _next, 0, "Execute next instruction" },
|
{ "next", _next, 0, "Execute next instruction" },
|
||||||
{ "p", _print, _DVParse, "Print a value" },
|
{ "p", _print, CLIDVParse, "Print a value" },
|
||||||
{ "p/t", _printBin, _DVParse, "Print a value as binary" },
|
{ "p/t", _printBin, CLIDVParse, "Print a value as binary" },
|
||||||
{ "p/x", _printHex, _DVParse, "Print a value as hexadecimal" },
|
{ "p/x", _printHex, CLIDVParse, "Print a value as hexadecimal" },
|
||||||
{ "print", _print, _DVParse, "Print a value" },
|
{ "print", _print, CLIDVParse, "Print a value" },
|
||||||
{ "print/t", _printBin, _DVParse, "Print a value as binary" },
|
{ "print/t", _printBin, CLIDVParse, "Print a value as binary" },
|
||||||
{ "print/x", _printHex, _DVParse, "Print a value as hexadecimal" },
|
{ "print/x", _printHex, CLIDVParse, "Print a value as hexadecimal" },
|
||||||
{ "q", _quit, 0, "Quit the emulator" },
|
{ "q", _quit, 0, "Quit the emulator" },
|
||||||
{ "quit", _quit, 0, "Quit the emulator" },
|
{ "quit", _quit, 0, "Quit the emulator" },
|
||||||
{ "rb", _readByte, _DVParse, "Read a byte from a specified offset" },
|
{ "rb", _readByte, CLIDVParse, "Read a byte from a specified offset" },
|
||||||
{ "reset", _reset, 0, "Reset the emulation" },
|
{ "reset", _reset, 0, "Reset the emulation" },
|
||||||
{ "rh", _readHalfword, _DVParse, "Read a halfword from a specified offset" },
|
{ "rh", _readHalfword, CLIDVParse, "Read a halfword from a specified offset" },
|
||||||
{ "rw", _readWord, _DVParse, "Read a word from a specified offset" },
|
{ "rw", _readWord, CLIDVParse, "Read a word from a specified offset" },
|
||||||
{ "status", _printStatus, 0, "Print the current status" },
|
{ "status", _printStatus, 0, "Print the current status" },
|
||||||
{ "w", _setWatchpoint, _DVParse, "Set a watchpoint" },
|
{ "w", _setWatchpoint, CLIDVParse, "Set a watchpoint" },
|
||||||
{ "watch", _setWatchpoint, _DVParse, "Set a watchpoint" },
|
{ "watch", _setWatchpoint, CLIDVParse, "Set a watchpoint" },
|
||||||
{ "x", _breakInto, 0, "Break into attached debugger (for developers)" },
|
{ "x", _breakInto, 0, "Break into attached debugger (for developers)" },
|
||||||
{ 0, 0, 0, 0 }
|
{ 0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
@ -117,7 +93,7 @@ static void _handleDeath(int sig) {
|
||||||
printf("No debugger attached!\n");
|
printf("No debugger attached!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _breakInto(struct CLIDebugger* debugger, struct DebugVector* dv) {
|
static void _breakInto(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||||
UNUSED(debugger);
|
UNUSED(debugger);
|
||||||
UNUSED(dv);
|
UNUSED(dv);
|
||||||
struct sigaction sa, osa;
|
struct sigaction sa, osa;
|
||||||
|
@ -134,30 +110,30 @@ static void _breakInto(struct CLIDebugger* debugger, struct DebugVector* dv) {
|
||||||
sigaction(SIGTRAP, &osa, 0);
|
sigaction(SIGTRAP, &osa, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _continue(struct CLIDebugger* debugger, struct DebugVector* dv) {
|
static void _continue(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||||
UNUSED(dv);
|
UNUSED(dv);
|
||||||
debugger->d.state = DEBUGGER_RUNNING;
|
debugger->d.state = DEBUGGER_RUNNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _next(struct CLIDebugger* debugger, struct DebugVector* dv) {
|
static void _next(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||||
UNUSED(dv);
|
UNUSED(dv);
|
||||||
ARMRun(debugger->d.cpu);
|
ARMRun(debugger->d.cpu);
|
||||||
_printStatus(debugger, 0);
|
_printStatus(debugger, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _disassemble(struct CLIDebugger* debugger, struct DebugVector* dv) {
|
static void _disassemble(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||||
_disassembleMode(debugger, dv, debugger->d.cpu->executionMode);
|
_disassembleMode(debugger, dv, debugger->d.cpu->executionMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _disassembleArm(struct CLIDebugger* debugger, struct DebugVector* dv) {
|
static void _disassembleArm(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||||
_disassembleMode(debugger, dv, MODE_ARM);
|
_disassembleMode(debugger, dv, MODE_ARM);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _disassembleThumb(struct CLIDebugger* debugger, struct DebugVector* dv) {
|
static void _disassembleThumb(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||||
_disassembleMode(debugger, dv, MODE_THUMB);
|
_disassembleMode(debugger, dv, MODE_THUMB);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _disassembleMode(struct CLIDebugger* debugger, struct DebugVector* dv, enum ExecutionMode mode) {
|
static void _disassembleMode(struct CLIDebugger* debugger, struct CLIDebugVector* dv, enum ExecutionMode mode) {
|
||||||
uint32_t address;
|
uint32_t address;
|
||||||
int size;
|
int size;
|
||||||
int wordSize;
|
int wordSize;
|
||||||
|
@ -168,14 +144,14 @@ static void _disassembleMode(struct CLIDebugger* debugger, struct DebugVector* d
|
||||||
wordSize = WORD_SIZE_THUMB;
|
wordSize = WORD_SIZE_THUMB;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dv || dv->type != DV_INT_TYPE) {
|
if (!dv || dv->type != CLIDV_INT_TYPE) {
|
||||||
address = debugger->d.cpu->gprs[ARM_PC] - wordSize;
|
address = debugger->d.cpu->gprs[ARM_PC] - wordSize;
|
||||||
} else {
|
} else {
|
||||||
address = dv->intValue;
|
address = dv->intValue;
|
||||||
dv = dv->next;
|
dv = dv->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dv || dv->type != DV_INT_TYPE) {
|
if (!dv || dv->type != CLIDV_INT_TYPE) {
|
||||||
size = 1;
|
size = 1;
|
||||||
} else {
|
} else {
|
||||||
size = dv->intValue;
|
size = dv->intValue;
|
||||||
|
@ -189,7 +165,7 @@ static void _disassembleMode(struct CLIDebugger* debugger, struct DebugVector* d
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _print(struct CLIDebugger* debugger, struct DebugVector* dv) {
|
static void _print(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||||
UNUSED(debugger);
|
UNUSED(debugger);
|
||||||
for ( ; dv; dv = dv->next) {
|
for ( ; dv; dv = dv->next) {
|
||||||
printf(" %u", dv->intValue);
|
printf(" %u", dv->intValue);
|
||||||
|
@ -197,7 +173,7 @@ static void _print(struct CLIDebugger* debugger, struct DebugVector* dv) {
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _printBin(struct CLIDebugger* debugger, struct DebugVector* dv) {
|
static void _printBin(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||||
UNUSED(debugger);
|
UNUSED(debugger);
|
||||||
for ( ; dv; dv = dv->next) {
|
for ( ; dv; dv = dv->next) {
|
||||||
printf(" 0b");
|
printf(" 0b");
|
||||||
|
@ -209,7 +185,7 @@ static void _printBin(struct CLIDebugger* debugger, struct DebugVector* dv) {
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _printHex(struct CLIDebugger* debugger, struct DebugVector* dv) {
|
static void _printHex(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||||
UNUSED(debugger);
|
UNUSED(debugger);
|
||||||
for ( ; dv; dv = dv->next) {
|
for ( ; dv; dv = dv->next) {
|
||||||
printf(" 0x%08X", dv->intValue);
|
printf(" 0x%08X", dv->intValue);
|
||||||
|
@ -217,14 +193,21 @@ static void _printHex(struct CLIDebugger* debugger, struct DebugVector* dv) {
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _printHelp(struct CLIDebugger* debugger, struct DebugVector* dv) {
|
static void _printHelp(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||||
UNUSED(debugger);
|
UNUSED(debugger);
|
||||||
UNUSED(dv);
|
UNUSED(dv);
|
||||||
if (!dv) {
|
if (!dv) {
|
||||||
|
puts("ARM commands:");
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; _debuggerCommands[i].name; ++i) {
|
for (i = 0; _debuggerCommands[i].name; ++i) {
|
||||||
printf("%-10s %s\n", _debuggerCommands[i].name, _debuggerCommands[i].summary);
|
printf("%-10s %s\n", _debuggerCommands[i].name, _debuggerCommands[i].summary);
|
||||||
}
|
}
|
||||||
|
if (debugger->system) {
|
||||||
|
printf("%s commands:\n", debugger->system->name);
|
||||||
|
for (i = 0; debugger->system->commands[i].name; ++i) {
|
||||||
|
printf("%-10s %s\n", debugger->system->commands[i].name, debugger->system->commands[i].summary);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; _debuggerCommands[i].name; ++i) {
|
for (i = 0; _debuggerCommands[i].name; ++i) {
|
||||||
|
@ -232,6 +215,14 @@ static void _printHelp(struct CLIDebugger* debugger, struct DebugVector* dv) {
|
||||||
printf(" %s\n", _debuggerCommands[i].summary);
|
printf(" %s\n", _debuggerCommands[i].summary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (debugger->system) {
|
||||||
|
printf("\n%s commands:\n", debugger->system->name);
|
||||||
|
for (i = 0; debugger->system->commands[i].name; ++i) {
|
||||||
|
if (strcmp(debugger->system->commands[i].name, dv->charValue) == 0) {
|
||||||
|
printf(" %s\n", debugger->system->commands[i].summary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,7 +243,7 @@ static inline void _printLine(struct CLIDebugger* debugger, uint32_t address, en
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _printStatus(struct CLIDebugger* debugger, struct DebugVector* dv) {
|
static void _printStatus(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||||
UNUSED(dv);
|
UNUSED(dv);
|
||||||
int r;
|
int r;
|
||||||
for (r = 0; r < 4; ++r) {
|
for (r = 0; r < 4; ++r) {
|
||||||
|
@ -273,13 +264,13 @@ static void _printStatus(struct CLIDebugger* debugger, struct DebugVector* dv) {
|
||||||
_printLine(debugger, debugger->d.cpu->gprs[ARM_PC] - instructionLength, mode);
|
_printLine(debugger, debugger->d.cpu->gprs[ARM_PC] - instructionLength, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _quit(struct CLIDebugger* debugger, struct DebugVector* dv) {
|
static void _quit(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||||
UNUSED(dv);
|
UNUSED(dv);
|
||||||
debugger->d.state = DEBUGGER_SHUTDOWN;
|
debugger->d.state = DEBUGGER_SHUTDOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _readByte(struct CLIDebugger* debugger, struct DebugVector* dv) {
|
static void _readByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||||
if (!dv || dv->type != DV_INT_TYPE) {
|
if (!dv || dv->type != CLIDV_INT_TYPE) {
|
||||||
printf("%s\n", ERROR_MISSING_ARGS);
|
printf("%s\n", ERROR_MISSING_ARGS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -288,14 +279,14 @@ static void _readByte(struct CLIDebugger* debugger, struct DebugVector* dv) {
|
||||||
printf(" 0x%02X\n", value);
|
printf(" 0x%02X\n", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _reset(struct CLIDebugger* debugger, struct DebugVector* dv) {
|
static void _reset(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||||
UNUSED(dv);
|
UNUSED(dv);
|
||||||
ARMReset(debugger->d.cpu);
|
ARMReset(debugger->d.cpu);
|
||||||
_printStatus(debugger, 0);
|
_printStatus(debugger, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _readHalfword(struct CLIDebugger* debugger, struct DebugVector* dv) {
|
static void _readHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||||
if (!dv || dv->type != DV_INT_TYPE) {
|
if (!dv || dv->type != CLIDV_INT_TYPE) {
|
||||||
printf("%s\n", ERROR_MISSING_ARGS);
|
printf("%s\n", ERROR_MISSING_ARGS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -304,8 +295,8 @@ static void _readHalfword(struct CLIDebugger* debugger, struct DebugVector* dv)
|
||||||
printf(" 0x%04X\n", value);
|
printf(" 0x%04X\n", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _readWord(struct CLIDebugger* debugger, struct DebugVector* dv) {
|
static void _readWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||||
if (!dv || dv->type != DV_INT_TYPE) {
|
if (!dv || dv->type != CLIDV_INT_TYPE) {
|
||||||
printf("%s\n", ERROR_MISSING_ARGS);
|
printf("%s\n", ERROR_MISSING_ARGS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -314,8 +305,8 @@ static void _readWord(struct CLIDebugger* debugger, struct DebugVector* dv) {
|
||||||
printf(" 0x%08X\n", value);
|
printf(" 0x%08X\n", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _setBreakpoint(struct CLIDebugger* debugger, struct DebugVector* dv) {
|
static void _setBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||||
if (!dv || dv->type != DV_INT_TYPE) {
|
if (!dv || dv->type != CLIDV_INT_TYPE) {
|
||||||
printf("%s\n", ERROR_MISSING_ARGS);
|
printf("%s\n", ERROR_MISSING_ARGS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -323,8 +314,8 @@ static void _setBreakpoint(struct CLIDebugger* debugger, struct DebugVector* dv)
|
||||||
ARMDebuggerSetBreakpoint(&debugger->d, address);
|
ARMDebuggerSetBreakpoint(&debugger->d, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _clearBreakpoint(struct CLIDebugger* debugger, struct DebugVector* dv) {
|
static void _clearBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||||
if (!dv || dv->type != DV_INT_TYPE) {
|
if (!dv || dv->type != CLIDV_INT_TYPE) {
|
||||||
printf("%s\n", ERROR_MISSING_ARGS);
|
printf("%s\n", ERROR_MISSING_ARGS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -332,8 +323,8 @@ static void _clearBreakpoint(struct CLIDebugger* debugger, struct DebugVector* d
|
||||||
ARMDebuggerClearBreakpoint(&debugger->d, address);
|
ARMDebuggerClearBreakpoint(&debugger->d, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _setWatchpoint(struct CLIDebugger* debugger, struct DebugVector* dv) {
|
static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||||
if (!dv || dv->type != DV_INT_TYPE) {
|
if (!dv || dv->type != CLIDV_INT_TYPE) {
|
||||||
printf("%s\n", ERROR_MISSING_ARGS);
|
printf("%s\n", ERROR_MISSING_ARGS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -346,7 +337,7 @@ static void _breakIntoDefault(int signal) {
|
||||||
ARMDebuggerEnter(&_activeDebugger->d, DEBUGGER_ENTER_MANUAL);
|
ARMDebuggerEnter(&_activeDebugger->d, DEBUGGER_ENTER_MANUAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t _performOperation(enum Operation operation, uint32_t current, uint32_t next, struct DebugVector* dv) {
|
static uint32_t _performOperation(enum Operation operation, uint32_t current, uint32_t next, struct CLIDebugVector* dv) {
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case OP_ASSIGN:
|
case OP_ASSIGN:
|
||||||
current = next;
|
current = next;
|
||||||
|
@ -364,7 +355,7 @@ static uint32_t _performOperation(enum Operation operation, uint32_t current, ui
|
||||||
if (next != 0) {
|
if (next != 0) {
|
||||||
current /= next;
|
current /= next;
|
||||||
} else {
|
} else {
|
||||||
dv->type = DV_ERROR_TYPE;
|
dv->type = CLIDV_ERROR_TYPE;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -372,7 +363,8 @@ static uint32_t _performOperation(enum Operation operation, uint32_t current, ui
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t _lookupIdentifier(struct ARMDebugger* debugger, const char* name, struct DebugVector* dv) {
|
static uint32_t _lookupIdentifier(struct ARMDebugger* debugger, const char* name, struct CLIDebugVector* dv) {
|
||||||
|
struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
|
||||||
if (strcmp(name, "sp") == 0) {
|
if (strcmp(name, "sp") == 0) {
|
||||||
return debugger->cpu->gprs[ARM_SP];
|
return debugger->cpu->gprs[ARM_SP];
|
||||||
}
|
}
|
||||||
|
@ -395,11 +387,18 @@ static uint32_t _lookupIdentifier(struct ARMDebugger* debugger, const char* name
|
||||||
return debugger->cpu->gprs[reg];
|
return debugger->cpu->gprs[reg];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dv->type = DV_ERROR_TYPE;
|
if (cliDebugger->system) {
|
||||||
|
uint32_t value = cliDebugger->system->lookupIdentifier(cliDebugger->system, name, dv);
|
||||||
|
if (dv->type != CLIDV_ERROR_TYPE) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dv->type = CLIDV_ERROR_TYPE;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t _evaluateParseTree(struct ARMDebugger* debugger, struct ParseTree* tree, struct DebugVector* dv) {
|
static uint32_t _evaluateParseTree(struct ARMDebugger* debugger, struct ParseTree* tree, struct CLIDebugVector* dv) {
|
||||||
switch (tree->token.type) {
|
switch (tree->token.type) {
|
||||||
case TOKEN_UINT_TYPE:
|
case TOKEN_UINT_TYPE:
|
||||||
return tree->token.uintValue;
|
return tree->token.uintValue;
|
||||||
|
@ -409,29 +408,29 @@ static uint32_t _evaluateParseTree(struct ARMDebugger* debugger, struct ParseTre
|
||||||
return _lookupIdentifier(debugger, tree->token.identifierValue, dv);
|
return _lookupIdentifier(debugger, tree->token.identifierValue, dv);
|
||||||
case TOKEN_ERROR_TYPE:
|
case TOKEN_ERROR_TYPE:
|
||||||
default:
|
default:
|
||||||
dv->type = DV_ERROR_TYPE;
|
dv->type = CLIDV_ERROR_TYPE;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct DebugVector* _DVParse(struct CLIDebugger* debugger, const char* string, size_t length) {
|
struct CLIDebugVector* CLIDVParse(struct CLIDebugger* debugger, const char* string, size_t length) {
|
||||||
if (!string || length < 1) {
|
if (!string || length < 1) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DebugVector dvTemp = { .type = DV_INT_TYPE };
|
struct CLIDebugVector dvTemp = { .type = CLIDV_INT_TYPE };
|
||||||
|
|
||||||
struct LexVector lv = { .next = 0 };
|
struct LexVector lv = { .next = 0 };
|
||||||
size_t adjusted = lexExpression(&lv, string, length);
|
size_t adjusted = lexExpression(&lv, string, length);
|
||||||
if (adjusted > length) {
|
if (adjusted > length) {
|
||||||
dvTemp.type = DV_ERROR_TYPE;
|
dvTemp.type = CLIDV_ERROR_TYPE;
|
||||||
lexFree(lv.next);
|
lexFree(lv.next);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ParseTree tree;
|
struct ParseTree tree;
|
||||||
parseLexedExpression(&tree, &lv);
|
parseLexedExpression(&tree, &lv);
|
||||||
if (tree.token.type == TOKEN_ERROR_TYPE) {
|
if (tree.token.type == TOKEN_ERROR_TYPE) {
|
||||||
dvTemp.type = DV_ERROR_TYPE;
|
dvTemp.type = CLIDV_ERROR_TYPE;
|
||||||
} else {
|
} else {
|
||||||
dvTemp.intValue = _evaluateParseTree(&debugger->d, &tree, &dvTemp);
|
dvTemp.intValue = _evaluateParseTree(&debugger->d, &tree, &dvTemp);
|
||||||
}
|
}
|
||||||
|
@ -442,28 +441,28 @@ static struct DebugVector* _DVParse(struct CLIDebugger* debugger, const char* st
|
||||||
length -= adjusted;
|
length -= adjusted;
|
||||||
string += adjusted;
|
string += adjusted;
|
||||||
|
|
||||||
struct DebugVector* dv = malloc(sizeof(struct DebugVector));
|
struct CLIDebugVector* dv = malloc(sizeof(struct CLIDebugVector));
|
||||||
if (dvTemp.type == DV_ERROR_TYPE) {
|
if (dvTemp.type == CLIDV_ERROR_TYPE) {
|
||||||
dv->type = DV_ERROR_TYPE;
|
dv->type = CLIDV_ERROR_TYPE;
|
||||||
dv->next = 0;
|
dv->next = 0;
|
||||||
} else {
|
} else {
|
||||||
*dv = dvTemp;
|
*dv = dvTemp;
|
||||||
if (string[0] == ' ') {
|
if (string[0] == ' ') {
|
||||||
dv->next = _DVParse(debugger, string + 1, length - 1);
|
dv->next = CLIDVParse(debugger, string + 1, length - 1);
|
||||||
if (dv->next && dv->next->type == DV_ERROR_TYPE) {
|
if (dv->next && dv->next->type == CLIDV_ERROR_TYPE) {
|
||||||
dv->type = DV_ERROR_TYPE;
|
dv->type = CLIDV_ERROR_TYPE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return dv;
|
return dv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct DebugVector* _DVStringParse(struct CLIDebugger* debugger, const char* string, size_t length) {
|
struct CLIDebugVector* CLIDVStringParse(struct CLIDebugger* debugger, const char* string, size_t length) {
|
||||||
if (!string || length < 1) {
|
if (!string || length < 1) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DebugVector dvTemp = { .type = DV_CHAR_TYPE };
|
struct CLIDebugVector dvTemp = { .type = CLIDV_CHAR_TYPE };
|
||||||
|
|
||||||
size_t adjusted;
|
size_t adjusted;
|
||||||
const char* next = strchr(string, ' ');
|
const char* next = strchr(string, ' ');
|
||||||
|
@ -478,22 +477,22 @@ static struct DebugVector* _DVStringParse(struct CLIDebugger* debugger, const ch
|
||||||
length -= adjusted;
|
length -= adjusted;
|
||||||
string += adjusted;
|
string += adjusted;
|
||||||
|
|
||||||
struct DebugVector* dv = malloc(sizeof(struct DebugVector));
|
struct CLIDebugVector* dv = malloc(sizeof(struct CLIDebugVector));
|
||||||
*dv = dvTemp;
|
*dv = dvTemp;
|
||||||
if (string[0] == ' ') {
|
if (string[0] == ' ') {
|
||||||
dv->next = _DVStringParse(debugger, string + 1, length - 1);
|
dv->next = CLIDVStringParse(debugger, string + 1, length - 1);
|
||||||
if (dv->next && dv->next->type == DV_ERROR_TYPE) {
|
if (dv->next && dv->next->type == CLIDV_ERROR_TYPE) {
|
||||||
dv->type = DV_ERROR_TYPE;
|
dv->type = CLIDV_ERROR_TYPE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return dv;
|
return dv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _DVFree(struct DebugVector* dv) {
|
static void _DVFree(struct CLIDebugVector* dv) {
|
||||||
struct DebugVector* next;
|
struct CLIDebugVector* next;
|
||||||
while (dv) {
|
while (dv) {
|
||||||
next = dv->next;
|
next = dv->next;
|
||||||
if (dv->type == DV_CHAR_TYPE) {
|
if (dv->type == CLIDV_CHAR_TYPE) {
|
||||||
free(dv->charValue);
|
free(dv->charValue);
|
||||||
}
|
}
|
||||||
free(dv);
|
free(dv);
|
||||||
|
@ -504,7 +503,7 @@ static void _DVFree(struct DebugVector* dv) {
|
||||||
static bool _parse(struct CLIDebugger* debugger, const char* line, size_t count) {
|
static bool _parse(struct CLIDebugger* debugger, const char* line, size_t count) {
|
||||||
const char* firstSpace = strchr(line, ' ');
|
const char* firstSpace = strchr(line, ' ');
|
||||||
size_t cmdLength;
|
size_t cmdLength;
|
||||||
struct DebugVector* dv = 0;
|
struct CLIDebugVector* dv = 0;
|
||||||
if (firstSpace) {
|
if (firstSpace) {
|
||||||
cmdLength = firstSpace - line;
|
cmdLength = firstSpace - line;
|
||||||
} else {
|
} else {
|
||||||
|
@ -521,7 +520,7 @@ static bool _parse(struct CLIDebugger* debugger, const char* line, size_t count)
|
||||||
if (_debuggerCommands[i].parser) {
|
if (_debuggerCommands[i].parser) {
|
||||||
if (firstSpace) {
|
if (firstSpace) {
|
||||||
dv = _debuggerCommands[i].parser(debugger, firstSpace + 1, count - cmdLength - 1);
|
dv = _debuggerCommands[i].parser(debugger, firstSpace + 1, count - cmdLength - 1);
|
||||||
if (dv && dv->type == DV_ERROR_TYPE) {
|
if (dv && dv->type == CLIDV_ERROR_TYPE) {
|
||||||
printf("Parse error\n");
|
printf("Parse error\n");
|
||||||
_DVFree(dv);
|
_DVFree(dv);
|
||||||
return false;
|
return false;
|
||||||
|
@ -659,6 +658,12 @@ static void _cliDebuggerDeinit(struct ARMDebugger* debugger) {
|
||||||
struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
|
struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
|
||||||
history_end(cliDebugger->histate);
|
history_end(cliDebugger->histate);
|
||||||
el_end(cliDebugger->elstate);
|
el_end(cliDebugger->elstate);
|
||||||
|
|
||||||
|
if (cliDebugger->system) {
|
||||||
|
cliDebugger->system->deinit(cliDebugger->system);
|
||||||
|
free(cliDebugger->system);
|
||||||
|
cliDebugger->system = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CLIDebuggerCreate(struct CLIDebugger* debugger) {
|
void CLIDebuggerCreate(struct CLIDebugger* debugger) {
|
||||||
|
@ -667,4 +672,16 @@ void CLIDebuggerCreate(struct CLIDebugger* debugger) {
|
||||||
debugger->d.deinit = _cliDebuggerDeinit;
|
debugger->d.deinit = _cliDebuggerDeinit;
|
||||||
debugger->d.paused = _commandLine;
|
debugger->d.paused = _commandLine;
|
||||||
debugger->d.entered = _reportEntry;
|
debugger->d.entered = _reportEntry;
|
||||||
|
|
||||||
|
debugger->system = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLIDebuggerAttachSystem(struct CLIDebugger* debugger, struct CLIDebuggerSystem* system) {
|
||||||
|
if (debugger->system) {
|
||||||
|
debugger->system->deinit(debugger->system);
|
||||||
|
free(debugger->system);
|
||||||
|
}
|
||||||
|
|
||||||
|
debugger->system = system;
|
||||||
|
system->p = debugger;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,13 +7,56 @@
|
||||||
|
|
||||||
#include <histedit.h>
|
#include <histedit.h>
|
||||||
|
|
||||||
|
struct CLIDebugger;
|
||||||
|
|
||||||
|
struct CLIDebugVector {
|
||||||
|
struct CLIDebugVector* next;
|
||||||
|
enum CLIDVType {
|
||||||
|
CLIDV_ERROR_TYPE,
|
||||||
|
CLIDV_INT_TYPE,
|
||||||
|
CLIDV_CHAR_TYPE
|
||||||
|
} type;
|
||||||
|
union {
|
||||||
|
int32_t intValue;
|
||||||
|
char* charValue;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*CLIDebuggerCommand)(struct CLIDebugger*, struct CLIDebugVector*);
|
||||||
|
typedef struct CLIDebugVector* (*CLIDVParser)(struct CLIDebugger* debugger, const char* string, size_t length);
|
||||||
|
|
||||||
|
struct CLIDebuggerCommandSummary {
|
||||||
|
const char* name;
|
||||||
|
CLIDebuggerCommand command;
|
||||||
|
CLIDVParser parser;
|
||||||
|
const char* summary;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CLIDebuggerSystem {
|
||||||
|
struct CLIDebugger* p;
|
||||||
|
|
||||||
|
void (*init)(struct CLIDebuggerSystem*);
|
||||||
|
void (*deinit)(struct CLIDebuggerSystem*);
|
||||||
|
|
||||||
|
uint32_t (*lookupIdentifier)(struct CLIDebuggerSystem*, const char* name, struct CLIDebugVector* dv);
|
||||||
|
|
||||||
|
struct CLIDebuggerCommandSummary* commands;
|
||||||
|
const char* name;
|
||||||
|
};
|
||||||
|
|
||||||
struct CLIDebugger {
|
struct CLIDebugger {
|
||||||
struct ARMDebugger d;
|
struct ARMDebugger d;
|
||||||
|
|
||||||
|
struct CLIDebuggerSystem* system;
|
||||||
|
|
||||||
EditLine* elstate;
|
EditLine* elstate;
|
||||||
History* histate;
|
History* histate;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CLIDebugVector* CLIDVParse(struct CLIDebugger* debugger, const char* string, size_t length);
|
||||||
|
struct CLIDebugVector* CLIDVStringParse(struct CLIDebugger* debugger, const char* string, size_t length);
|
||||||
|
|
||||||
void CLIDebuggerCreate(struct CLIDebugger*);
|
void CLIDebuggerCreate(struct CLIDebugger*);
|
||||||
|
void CLIDebuggerAttachSystem(struct CLIDebugger*, struct CLIDebuggerSystem*);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -145,7 +145,8 @@ bool _parseGraphicsArg(struct SubParser* parser, struct GBAConfig* config, int o
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ARMDebugger* createDebugger(struct GBAArguments* opts) {
|
struct ARMDebugger* createDebugger(struct GBAArguments* opts, struct GBAThread* context) {
|
||||||
|
UNUSED(context);
|
||||||
union DebugUnion {
|
union DebugUnion {
|
||||||
struct ARMDebugger d;
|
struct ARMDebugger d;
|
||||||
#ifdef USE_CLI_DEBUGGER
|
#ifdef USE_CLI_DEBUGGER
|
||||||
|
|
|
@ -36,12 +36,14 @@ struct GraphicsOpts {
|
||||||
int multiplier;
|
int multiplier;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct GBAThread;
|
||||||
|
|
||||||
bool parseArguments(struct GBAArguments* opts, struct GBAConfig* config, int argc, char* const* argv, struct SubParser* subparser);
|
bool parseArguments(struct GBAArguments* opts, struct GBAConfig* config, int argc, char* const* argv, struct SubParser* subparser);
|
||||||
void freeArguments(struct GBAArguments* opts);
|
void freeArguments(struct GBAArguments* opts);
|
||||||
|
|
||||||
void usage(const char* arg0, const char* extraOptions);
|
void usage(const char* arg0, const char* extraOptions);
|
||||||
|
|
||||||
void initParserForGraphics(struct SubParser* parser, struct GraphicsOpts* opts);
|
void initParserForGraphics(struct SubParser* parser, struct GraphicsOpts* opts);
|
||||||
struct ARMDebugger* createDebugger(struct GBAArguments* opts);
|
struct ARMDebugger* createDebugger(struct GBAArguments* opts, struct GBAThread* context);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -69,7 +69,7 @@ int main(int argc, char** argv) {
|
||||||
context.renderer = &renderer.d;
|
context.renderer = &renderer.d;
|
||||||
}
|
}
|
||||||
|
|
||||||
context.debugger = createDebugger(&args);
|
context.debugger = createDebugger(&args, &context);
|
||||||
char gameCode[5] = { 0 };
|
char gameCode[5] = { 0 };
|
||||||
|
|
||||||
GBAConfigMap(&config, &opts);
|
GBAConfigMap(&config, &opts);
|
||||||
|
|
|
@ -82,7 +82,7 @@ int main(int argc, char** argv) {
|
||||||
.userData = &renderer
|
.userData = &renderer
|
||||||
};
|
};
|
||||||
|
|
||||||
context.debugger = createDebugger(&args);
|
context.debugger = createDebugger(&args, &context);
|
||||||
|
|
||||||
GBAMapOptionsToContext(&opts, &context);
|
GBAMapOptionsToContext(&opts, &context);
|
||||||
GBAMapArgumentsToContext(&args, &context);
|
GBAMapArgumentsToContext(&args, &context);
|
||||||
|
|
Loading…
Reference in New Issue