Debugger: Break out debugger functionality into modules

This commit is contained in:
Vicki Pfau 2022-12-11 20:30:47 -08:00
parent b1f991bf94
commit b21a6158f4
23 changed files with 396 additions and 195 deletions

View File

@ -56,6 +56,7 @@ enum mDebuggerEntryReason {
DEBUGGER_ENTER_STACK
};
struct mDebuggerModule;
struct mDebuggerEntryInfo {
uint32_t address;
union {
@ -76,6 +77,7 @@ struct mDebuggerEntryInfo {
} st;
} type;
ssize_t pointId;
struct mDebuggerModule* target;
};
struct mBreakpoint {
@ -97,6 +99,7 @@ struct mWatchpoint {
DECLARE_VECTOR(mBreakpointList, struct mBreakpoint);
DECLARE_VECTOR(mWatchpointList, struct mWatchpoint);
DECLARE_VECTOR(mDebuggerModuleList, struct mDebuggerModule*);
struct mDebugger;
struct ParseTree;
@ -130,28 +133,50 @@ struct mDebugger {
struct mCPUComponent d;
struct mDebuggerPlatform* platform;
enum mDebuggerState state;
enum mDebuggerType type;
struct mCore* core;
struct mScriptBridge* bridge;
struct mStackTrace stackTrace;
void (*init)(struct mDebugger*);
void (*deinit)(struct mDebugger*);
void (*paused)(struct mDebugger*);
void (*update)(struct mDebugger*);
void (*entered)(struct mDebugger*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*);
void (*custom)(struct mDebugger*);
void (*interrupt)(struct mDebugger*);
struct mDebuggerModuleList modules;
};
struct mDebugger* mDebuggerCreate(enum mDebuggerType type, struct mCore*);
struct mDebuggerModule {
struct mDebugger* p;
enum mDebuggerType type;
bool isPaused;
bool needsCallback;
void (*init)(struct mDebuggerModule*);
void (*deinit)(struct mDebuggerModule*);
void (*paused)(struct mDebuggerModule*);
void (*update)(struct mDebuggerModule*);
void (*entered)(struct mDebuggerModule*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*);
void (*custom)(struct mDebuggerModule*);
void (*interrupt)(struct mDebuggerModule*);
};
void mDebuggerInit(struct mDebugger*);
void mDebuggerDeinit(struct mDebugger*);
void mDebuggerAttach(struct mDebugger*, struct mCore*);
void mDebuggerAttachModule(struct mDebugger*, struct mDebuggerModule*);
void mDebuggerDetachModule(struct mDebugger*, struct mDebuggerModule*);
void mDebuggerRun(struct mDebugger*);
void mDebuggerRunFrame(struct mDebugger*);
void mDebuggerEnter(struct mDebugger*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*);
void mDebuggerInterrupt(struct mDebugger*);
void mDebuggerUpdatePaused(struct mDebugger*);
void mDebuggerShutdown(struct mDebugger*);
void mDebuggerUpdate(struct mDebugger*);
bool mDebuggerIsShutdown(const struct mDebugger*);
struct mDebuggerModule* mDebuggerCreateModule(enum mDebuggerType type, struct mCore*);
void mDebuggerModuleSetNeedsCallback(struct mDebuggerModule*);
bool mDebuggerLookupIdentifier(struct mDebugger* debugger, const char* name, int32_t* value, int* segment);
CXX_GUARD_END

View File

@ -81,7 +81,7 @@ struct CLIDebuggerBackend {
};
struct CLIDebugger {
struct mDebugger d;
struct mDebuggerModule d;
struct CLIDebuggerSystem* system;
struct CLIDebuggerBackend* backend;

View File

@ -31,7 +31,7 @@ enum GDBWatchpointsBehvaior {
};
struct GDBStub {
struct mDebugger d;
struct mDebuggerModule d;
char line[GDB_STUB_MAX_LINE];
char outgoing[GDB_STUB_MAX_LINE];

View File

@ -52,7 +52,7 @@ static inline void _printPSR(struct CLIDebuggerBackend* be, union PSR psr) {
}
static void _disassemble(struct CLIDebuggerSystem* debugger, struct CLIDebugVector* dv) {
struct ARMCore* cpu = debugger->p->d.core->cpu;
struct ARMCore* cpu = debugger->p->d.p->core->cpu;
_disassembleMode(debugger->p, dv, cpu->executionMode);
}
@ -65,7 +65,7 @@ static void _disassembleThumb(struct CLIDebugger* debugger, struct CLIDebugVecto
}
static void _disassembleMode(struct CLIDebugger* debugger, struct CLIDebugVector* dv, enum ExecutionMode mode) {
struct ARMCore* cpu = debugger->d.core->cpu;
struct ARMCore* cpu = debugger->d.p->core->cpu;
uint32_t address;
int size;
int wordSize;
@ -98,7 +98,7 @@ static void _disassembleMode(struct CLIDebugger* debugger, struct CLIDebugVector
static inline uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode) {
struct CLIDebuggerBackend* be = debugger->backend;
struct mCore* core = debugger->d.core;
struct mCore* core = debugger->d.p->core;
char disassembly[64];
struct ARMInstructionInfo info;
address &= ~(WORD_SIZE_THUMB - 1);
@ -130,7 +130,7 @@ static inline uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address
static void _printStatus(struct CLIDebuggerSystem* debugger) {
struct CLIDebuggerBackend* be = debugger->p->backend;
struct ARMCore* cpu = debugger->p->d.core->cpu;
struct ARMCore* cpu = debugger->p->d.p->core->cpu;
int r;
for (r = 0; r < 16; r += 4) {
be->printf(be, "%sr%i: %08X %sr%i: %08X %sr%i: %08X %sr%i: %08X\n",
@ -141,7 +141,7 @@ static void _printStatus(struct CLIDebuggerSystem* debugger) {
}
be->printf(be, "cpsr: ");
_printPSR(be, cpu->cpsr);
be->printf(be, "Cycle: %" PRIu64 "\n", mTimingGlobalTime(debugger->p->d.core->timing));
be->printf(be, "Cycle: %" PRIu64 "\n", mTimingGlobalTime(debugger->p->d.p->core->timing));
int instructionLength;
enum ExecutionMode mode = cpu->cpsr.t;
if (mode == MODE_ARM) {
@ -159,7 +159,7 @@ static void _setBreakpointARM(struct CLIDebugger* debugger, struct CLIDebugVecto
return;
}
uint32_t address = dv->intValue;
ssize_t id = ARMDebuggerSetSoftwareBreakpoint(debugger->d.platform, address, MODE_ARM);
ssize_t id = ARMDebuggerSetSoftwareBreakpoint(debugger->d.p->platform, address, MODE_ARM);
if (id > 0) {
debugger->backend->printf(debugger->backend, INFO_BREAKPOINT_ADDED, id);
}
@ -172,7 +172,7 @@ static void _setBreakpointThumb(struct CLIDebugger* debugger, struct CLIDebugVec
return;
}
uint32_t address = dv->intValue;
ssize_t id = ARMDebuggerSetSoftwareBreakpoint(debugger->d.platform, address, MODE_THUMB);
ssize_t id = ARMDebuggerSetSoftwareBreakpoint(debugger->d.p->platform, address, MODE_THUMB);
if (id > 0) {
debugger->backend->printf(debugger->backend, INFO_BREAKPOINT_ADDED, id);
}

View File

@ -323,9 +323,6 @@ static void ARMDebuggerEnter(struct mDebuggerPlatform* platform, enum mDebuggerE
}
}
}
if (debugger->d.p->entered) {
debugger->d.p->entered(debugger->d.p, reason, info);
}
}
ssize_t ARMDebuggerSetSoftwareBreakpoint(struct mDebuggerPlatform* d, uint32_t address, enum ExecutionMode mode) {

View File

@ -109,10 +109,7 @@ static void _wait(struct mCoreThreadInternal* threadContext) {
#ifdef USE_DEBUGGERS
if (threadContext->core && threadContext->core->debugger) {
struct mDebugger* debugger = threadContext->core->debugger;
if (debugger->interrupt) {
debugger->interrupt(debugger);
}
mDebuggerInterrupt(threadContext->core->debugger);
}
#endif
@ -352,8 +349,8 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
while (impl->state >= mTHREAD_MIN_WAITING && impl->state <= mTHREAD_MAX_WAITING) {
#ifdef USE_DEBUGGERS
if (debugger && debugger->update && debugger->state != DEBUGGER_SHUTDOWN) {
debugger->update(debugger);
if (debugger && debugger->state != DEBUGGER_SHUTDOWN) {
mDebuggerUpdate(debugger);
ConditionWaitTimed(&impl->stateCond, &impl->stateMutex, 10);
} else
#endif

View File

@ -191,7 +191,7 @@ static void _breakInto(struct CLIDebugger* debugger, struct CLIDebugVector* dv)
#endif
static bool CLIDebuggerCheckTraceMode(struct CLIDebugger* debugger, bool requireEnabled) {
struct mDebuggerPlatform* platform = debugger->d.platform;
struct mDebuggerPlatform* platform = debugger->d.p->platform;
if (!platform->getStackTraceMode) {
debugger->backend->printf(debugger->backend, "Stack tracing is not supported by this platform.\n");
return false;
@ -204,13 +204,14 @@ static bool CLIDebuggerCheckTraceMode(struct CLIDebugger* debugger, bool require
static void _continue(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
UNUSED(dv);
debugger->d.state = debugger->traceRemaining != 0 ? DEBUGGER_CALLBACK : DEBUGGER_RUNNING;
debugger->d.needsCallback = debugger->traceRemaining != 0;
debugger->d.isPaused = false;
}
static void _next(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
UNUSED(dv);
struct mDebuggerPlatform* platform = debugger->d.platform;
debugger->d.core->step(debugger->d.core);
struct mDebuggerPlatform* platform = debugger->d.p->platform;
debugger->d.p->core->step(debugger->d.p->core);
if (platform->getStackTraceMode && platform->getStackTraceMode(platform) != STACK_TRACE_DISABLED) {
platform->updateStackTrace(platform);
}
@ -221,7 +222,7 @@ static void _disassemble(struct CLIDebugger* debugger, struct CLIDebugVector* dv
debugger->system->disassemble(debugger->system, dv);
}
static bool _parseExpression(struct mDebugger* debugger, struct CLIDebugVector* dv, int32_t* intValue, int* segmentValue) {
static bool _parseExpression(struct mDebuggerModule* debugger, struct CLIDebugVector* dv, int32_t* intValue, int* segmentValue) {
size_t args = 0;
struct CLIDebugVector* accum;
for (accum = dv; accum; accum = accum->next) {
@ -240,7 +241,7 @@ static bool _parseExpression(struct mDebugger* debugger, struct CLIDebugVector*
if (!tree) {
return false;
}
if (!mDebuggerEvaluateParseTree(debugger, tree, intValue, segmentValue)) {
if (!mDebuggerEvaluateParseTree(debugger->p, tree, intValue, segmentValue)) {
parseFree(tree);
return false;
}
@ -366,7 +367,7 @@ static void _printHelp(struct CLIDebugger* debugger, struct CLIDebugVector* dv)
static void _quit(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
UNUSED(dv);
debugger->d.state = DEBUGGER_SHUTDOWN;
mDebuggerShutdown(debugger->d.p);
}
static void _readByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
@ -377,17 +378,17 @@ static void _readByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
uint32_t address = dv->intValue;
uint8_t value;
if (dv->segmentValue >= 0) {
value = debugger->d.core->rawRead8(debugger->d.core, address, dv->segmentValue);
value = debugger->d.p->core->rawRead8(debugger->d.p->core, address, dv->segmentValue);
} else {
value = debugger->d.core->busRead8(debugger->d.core, address);
value = debugger->d.p->core->busRead8(debugger->d.p->core, address);
}
debugger->backend->printf(debugger->backend, " 0x%02X\n", value);
}
static void _reset(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
UNUSED(dv);
mStackTraceClear(&debugger->d.stackTrace);
debugger->d.core->reset(debugger->d.core);
mStackTraceClear(&debugger->d.p->stackTrace);
debugger->d.p->core->reset(debugger->d.p->core);
_printStatus(debugger, 0);
}
@ -399,9 +400,9 @@ static void _readHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* d
uint32_t address = dv->intValue;
uint16_t value;
if (dv->segmentValue >= 0) {
value = debugger->d.core->rawRead16(debugger->d.core, address & -1, dv->segmentValue);
value = debugger->d.p->core->rawRead16(debugger->d.p->core, address & -1, dv->segmentValue);
} else {
value = debugger->d.core->busRead16(debugger->d.core, address & ~1);
value = debugger->d.p->core->busRead16(debugger->d.p->core, address & ~1);
}
debugger->backend->printf(debugger->backend, " 0x%04X\n", value);
}
@ -414,9 +415,9 @@ static void _readWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
uint32_t address = dv->intValue;
uint32_t value;
if (dv->segmentValue >= 0) {
value = debugger->d.core->rawRead32(debugger->d.core, address & -3, dv->segmentValue);
value = debugger->d.p->core->rawRead32(debugger->d.p->core, address & -3, dv->segmentValue);
} else {
value = debugger->d.core->busRead32(debugger->d.core, address & ~3);
value = debugger->d.p->core->busRead32(debugger->d.p->core, address & ~3);
}
debugger->backend->printf(debugger->backend, " 0x%08X\n", value);
}
@ -437,9 +438,9 @@ static void _writeByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv)
return;
}
if (dv->segmentValue >= 0) {
debugger->d.core->rawWrite8(debugger->d.core, address, value, dv->segmentValue);
debugger->d.p->core->rawWrite8(debugger->d.p->core, address, value, dv->segmentValue);
} else {
debugger->d.core->busWrite8(debugger->d.core, address, value);
debugger->d.p->core->busWrite8(debugger->d.p->core, address, value);
}
}
@ -459,9 +460,9 @@ static void _writeHalfword(struct CLIDebugger* debugger, struct CLIDebugVector*
return;
}
if (dv->segmentValue >= 0) {
debugger->d.core->rawWrite16(debugger->d.core, address, value, dv->segmentValue);
debugger->d.p->core->rawWrite16(debugger->d.p->core, address, value, dv->segmentValue);
} else {
debugger->d.core->busWrite16(debugger->d.core, address, value);
debugger->d.p->core->busWrite16(debugger->d.p->core, address, value);
}
}
@ -474,7 +475,7 @@ static void _writeRegister(struct CLIDebugger* debugger, struct CLIDebugVector*
debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
return;
}
if (!debugger->d.core->writeRegister(debugger->d.core, dv->charValue, &dv->next->intValue)) {
if (!debugger->d.p->core->writeRegister(debugger->d.p->core, dv->charValue, &dv->next->intValue)) {
debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
}
}
@ -491,9 +492,9 @@ static void _writeWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv)
uint32_t address = dv->intValue;
uint32_t value = dv->next->intValue;
if (dv->segmentValue >= 0) {
debugger->d.core->rawWrite32(debugger->d.core, address, value, dv->segmentValue);
debugger->d.p->core->rawWrite32(debugger->d.p->core, address, value, dv->segmentValue);
} else {
debugger->d.core->busWrite32(debugger->d.core, address, value);
debugger->d.p->core->busWrite32(debugger->d.p->core, address, value);
}
}
@ -516,9 +517,9 @@ static void _dumpByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
for (; line > 0; --line, ++address, --words) {
uint32_t value;
if (dv->segmentValue >= 0) {
value = debugger->d.core->rawRead8(debugger->d.core, address, dv->segmentValue);
value = debugger->d.p->core->rawRead8(debugger->d.p->core, address, dv->segmentValue);
} else {
value = debugger->d.core->busRead8(debugger->d.core, address);
value = debugger->d.p->core->busRead8(debugger->d.p->core, address);
}
debugger->backend->printf(debugger->backend, " %02X", value);
}
@ -545,9 +546,9 @@ static void _dumpHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* d
for (; line > 0; --line, address += 2, --words) {
uint32_t value;
if (dv->segmentValue >= 0) {
value = debugger->d.core->rawRead16(debugger->d.core, address, dv->segmentValue);
value = debugger->d.p->core->rawRead16(debugger->d.p->core, address, dv->segmentValue);
} else {
value = debugger->d.core->busRead16(debugger->d.core, address);
value = debugger->d.p->core->busRead16(debugger->d.p->core, address);
}
debugger->backend->printf(debugger->backend, " %04X", value);
}
@ -574,9 +575,9 @@ static void _dumpWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
for (; line > 0; --line, address += 4, --words) {
uint32_t value;
if (dv->segmentValue >= 0) {
value = debugger->d.core->rawRead32(debugger->d.core, address, dv->segmentValue);
value = debugger->d.p->core->rawRead32(debugger->d.p->core, address, dv->segmentValue);
} else {
value = debugger->d.core->busRead32(debugger->d.core, address);
value = debugger->d.p->core->busRead32(debugger->d.p->core, address);
}
debugger->backend->printf(debugger->backend, " %08X", value);
}
@ -590,8 +591,8 @@ static void _source(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
debugger->backend->printf(debugger->backend, "Needs a filename\n");
return;
}
if (debugger->d.bridge && mScriptBridgeLoadScript(debugger->d.bridge, dv->charValue)) {
mScriptBridgeRun(debugger->d.bridge);
if (debugger->d.p->bridge && mScriptBridgeLoadScript(debugger->d.p->bridge, dv->charValue)) {
mScriptBridgeRun(debugger->d.p->bridge);
} else {
debugger->backend->printf(debugger->backend, "Failed to load script\n");
}
@ -647,7 +648,7 @@ static void _setBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector*
return;
}
}
ssize_t id = debugger->d.platform->setBreakpoint(debugger->d.platform, &breakpoint);
ssize_t id = debugger->d.p->platform->setBreakpoint(debugger->d.p->platform, &breakpoint);
if (id > 0) {
debugger->backend->printf(debugger->backend, INFO_BREAKPOINT_ADDED, id);
}
@ -658,7 +659,7 @@ static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector*
debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
return;
}
if (!debugger->d.platform->setWatchpoint) {
if (!debugger->d.p->platform->setWatchpoint) {
debugger->backend->printf(debugger->backend, "Watchpoints are not supported by this platform.\n");
return;
}
@ -677,7 +678,7 @@ static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector*
return;
}
}
ssize_t id = debugger->d.platform->setWatchpoint(debugger->d.platform, &watchpoint);
ssize_t id = debugger->d.p->platform->setWatchpoint(debugger->d.p->platform, &watchpoint);
if (id > 0) {
debugger->backend->printf(debugger->backend, INFO_WATCHPOINT_ADDED, id);
}
@ -692,7 +693,7 @@ static void _setRangeWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVec
debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
return;
}
if (!debugger->d.platform->setWatchpoint) {
if (!debugger->d.p->platform->setWatchpoint) {
debugger->backend->printf(debugger->backend, "Watchpoints are not supported by this platform.\n");
return;
}
@ -719,7 +720,7 @@ static void _setRangeWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVec
return;
}
}
ssize_t id = debugger->d.platform->setWatchpoint(debugger->d.platform, &watchpoint);
ssize_t id = debugger->d.p->platform->setWatchpoint(debugger->d.p->platform, &watchpoint);
if (id > 0) {
debugger->backend->printf(debugger->backend, INFO_WATCHPOINT_ADDED, id);
}
@ -763,14 +764,14 @@ static void _clearBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector
return;
}
uint64_t id = dv->intValue;
debugger->d.platform->clearBreakpoint(debugger->d.platform, id);
debugger->d.p->platform->clearBreakpoint(debugger->d.p->platform, id);
}
static void _listBreakpoints(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
UNUSED(dv);
struct mBreakpointList breakpoints;
mBreakpointListInit(&breakpoints, 0);
debugger->d.platform->listBreakpoints(debugger->d.platform, &breakpoints);
debugger->d.p->platform->listBreakpoints(debugger->d.p->platform, &breakpoints);
size_t i;
for (i = 0; i < mBreakpointListSize(&breakpoints); ++i) {
struct mBreakpoint* breakpoint = mBreakpointListGetPointer(&breakpoints, i);
@ -787,7 +788,7 @@ static void _listWatchpoints(struct CLIDebugger* debugger, struct CLIDebugVector
UNUSED(dv);
struct mWatchpointList watchpoints;
mWatchpointListInit(&watchpoints, 0);
debugger->d.platform->listWatchpoints(debugger->d.platform, &watchpoints);
debugger->d.p->platform->listWatchpoints(debugger->d.p->platform, &watchpoints);
size_t i;
for (i = 0; i < mWatchpointListSize(&watchpoints); ++i) {
struct mWatchpoint* watchpoint = mWatchpointListGetPointer(&watchpoints, i);
@ -823,6 +824,7 @@ static void _trace(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
debugger->traceVf->close(debugger->traceVf);
debugger->traceVf = NULL;
}
debugger->d.needsCallback = debugger->traceRemaining != 0;
if (debugger->traceRemaining == 0) {
return;
}
@ -830,7 +832,7 @@ static void _trace(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
debugger->traceVf = VFileOpen(dv->next->charValue, O_CREAT | O_WRONLY | O_APPEND);
}
if (_doTrace(debugger)) {
debugger->d.state = DEBUGGER_CALLBACK;
mDebuggerUpdatePaused(debugger->d.p);
} else {
debugger->system->printStatus(debugger->system);
}
@ -840,7 +842,7 @@ static bool _doTrace(struct CLIDebugger* debugger) {
char trace[1024];
trace[sizeof(trace) - 1] = '\0';
size_t traceSize = sizeof(trace) - 2;
debugger->d.platform->trace(debugger->d.platform, trace, &traceSize);
debugger->d.p->platform->trace(debugger->d.p->platform, trace, &traceSize);
if (traceSize + 2 <= sizeof(trace)) {
trace[traceSize] = '\n';
trace[traceSize + 1] = '\0';
@ -858,6 +860,7 @@ static bool _doTrace(struct CLIDebugger* debugger) {
debugger->traceVf->close(debugger->traceVf);
debugger->traceVf = NULL;
}
debugger->d.needsCallback = false;
return false;
}
return true;
@ -870,7 +873,7 @@ static void _printStatus(struct CLIDebugger* debugger, struct CLIDebugVector* dv
static void _events(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
UNUSED(dv);
struct mTiming* timing = debugger->d.core->timing;
struct mTiming* timing = debugger->d.p->core->timing;
struct mTimingEvent* next = timing->root;
for (; next; next = next->next) {
debugger->backend->printf(debugger->backend, "%s in %i cycles\n", next->name, mTimingUntil(timing, next));
@ -895,7 +898,7 @@ struct CLIDebugVector* CLIDVParse(struct CLIDebugger* debugger, const char* stri
if (!parseLexedExpression(tree, &lv)) {
dvTemp.type = CLIDV_ERROR_TYPE;
} else {
if (!mDebuggerEvaluateParseTree(&debugger->d, tree, &dvTemp.intValue, &dvTemp.segmentValue)) {
if (!mDebuggerEvaluateParseTree(debugger->d.p, tree, &dvTemp.intValue, &dvTemp.segmentValue)) {
dvTemp.type = CLIDV_ERROR_TYPE;
}
}
@ -1089,7 +1092,7 @@ bool CLIDebuggerRunCommand(struct CLIDebugger* debugger, const char* line, size_
return false;
}
static void _commandLine(struct mDebugger* debugger) {
static void _commandLine(struct mDebuggerModule* debugger) {
struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
const char* line;
size_t len;
@ -1098,10 +1101,10 @@ static void _commandLine(struct mDebugger* debugger) {
} else {
_printStatus(cliDebugger, 0);
}
while (debugger->state == DEBUGGER_PAUSED) {
while (debugger->isPaused && !mDebuggerIsShutdown(debugger->p)) {
line = cliDebugger->backend->readline(cliDebugger->backend, &len);
if (!line || len == 0) {
debugger->state = DEBUGGER_SHUTDOWN;
mDebuggerShutdown(debugger->p);
return;
}
if (line[0] == '\033') {
@ -1124,7 +1127,7 @@ static void _commandLine(struct mDebugger* debugger) {
}
}
static void _reportEntry(struct mDebugger* debugger, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
static void _reportEntry(struct mDebuggerModule* debugger, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
if (cliDebugger->traceRemaining > 0) {
cliDebugger->traceRemaining = 0;
@ -1166,7 +1169,7 @@ static void _reportEntry(struct mDebugger* debugger, enum mDebuggerEntryReason r
case DEBUGGER_ENTER_STACK:
if (info) {
if (info->type.st.traceType == STACK_TRACE_BREAK_ON_CALL) {
struct mStackTrace* stack = &cliDebugger->d.stackTrace;
struct mStackTrace* stack = &cliDebugger->d.p->stackTrace;
struct mStackFrame* frame = mStackTraceGetFrame(stack, 0);
if (frame->interrupt) {
cliDebugger->backend->printf(cliDebugger->backend, "Hit interrupt at at 0x%08X\n", info->address);
@ -1184,7 +1187,7 @@ static void _reportEntry(struct mDebugger* debugger, enum mDebuggerEntryReason r
}
}
static void _cliDebuggerInit(struct mDebugger* debugger) {
static void _cliDebuggerInit(struct mDebuggerModule* debugger) {
struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
cliDebugger->traceRemaining = 0;
cliDebugger->traceVf = NULL;
@ -1195,7 +1198,7 @@ static void _cliDebuggerInit(struct mDebugger* debugger) {
}
}
static void _cliDebuggerDeinit(struct mDebugger* debugger) {
static void _cliDebuggerDeinit(struct mDebuggerModule* debugger) {
struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
if (cliDebugger->traceVf) {
cliDebugger->traceVf->close(cliDebugger->traceVf);
@ -1215,23 +1218,22 @@ static void _cliDebuggerDeinit(struct mDebugger* debugger) {
}
}
static void _cliDebuggerCustom(struct mDebugger* debugger) {
static void _cliDebuggerCustom(struct mDebuggerModule* debugger) {
struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
bool retain = true;
enum mDebuggerState next = DEBUGGER_RUNNING;
if (cliDebugger->traceRemaining) {
retain = _doTrace(cliDebugger) && retain;
next = DEBUGGER_PAUSED;
if (!_doTrace(cliDebugger)) {
debugger->isPaused = true;
debugger->needsCallback = false;
}
}
if (cliDebugger->system) {
retain = cliDebugger->system->custom(cliDebugger->system) && retain;
}
if (!retain && debugger->state == DEBUGGER_CALLBACK) {
debugger->state = next;
if (cliDebugger->system && cliDebugger->system->custom) {
debugger->needsCallback = cliDebugger->system->custom(cliDebugger->system) || debugger->needsCallback;
}
mDebuggerUpdatePaused(debugger->p);
}
static void _cliDebuggerInterrupt(struct mDebugger* debugger) {
static void _cliDebuggerInterrupt(struct mDebuggerModule* debugger) {
struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
if (cliDebugger->backend->interrupt) {
cliDebugger->backend->interrupt(cliDebugger->backend);
@ -1327,13 +1329,13 @@ static void _backtrace(struct CLIDebugger* debugger, struct CLIDebugVector* dv)
if (!CLIDebuggerCheckTraceMode(debugger, true)) {
return;
}
struct mStackTrace* stack = &debugger->d.stackTrace;
struct mStackTrace* stack = &debugger->d.p->stackTrace;
ssize_t frames = mStackTraceGetDepth(stack);
if (dv && dv->type == CLIDV_INT_TYPE && dv->intValue < frames) {
frames = dv->intValue;
}
ssize_t i;
struct mDebuggerSymbols* symbolTable = debugger->d.core->symbolTable;
struct mDebuggerSymbols* symbolTable = debugger->d.p->core->symbolTable;
for (i = 0; i < frames; ++i) {
char trace[1024];
size_t traceSize = sizeof(trace) - 2;
@ -1347,7 +1349,7 @@ static void _finish(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
if (!CLIDebuggerCheckTraceMode(debugger, true)) {
return;
}
struct mStackTrace* stack = &debugger->d.stackTrace;
struct mStackTrace* stack = &debugger->d.p->stackTrace;
struct mStackFrame* frame = mStackTraceGetFrame(stack, 0);
if (!frame) {
debugger->backend->printf(debugger->backend, "No current stack frame.\n");
@ -1373,7 +1375,7 @@ static void _setStackTraceMode(struct CLIDebugger* debugger, struct CLIDebugVect
debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
return;
}
struct mDebuggerPlatform* platform = debugger->d.platform;
struct mDebuggerPlatform* platform = debugger->d.p->platform;
if (strcmp(dv->charValue, "off") == 0) {
platform->setStackTraceMode(platform, STACK_TRACE_DISABLED);
} else if (strcmp(dv->charValue, "trace-only") == 0) {
@ -1390,7 +1392,7 @@ static void _setStackTraceMode(struct CLIDebugger* debugger, struct CLIDebugVect
}
static void _loadSymbols(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
struct mDebuggerSymbols* symbolTable = debugger->d.core->symbolTable;
struct mDebuggerSymbols* symbolTable = debugger->d.p->core->symbolTable;
if (!symbolTable) {
debugger->backend->printf(debugger->backend, "No symbol table available.\n");
return;
@ -1424,7 +1426,7 @@ static void _loadSymbols(struct CLIDebugger* debugger, struct CLIDebugVector* dv
}
static void _setSymbol(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
struct mDebuggerSymbols* symbolTable = debugger->d.core->symbolTable;
struct mDebuggerSymbols* symbolTable = debugger->d.p->core->symbolTable;
if (!symbolTable) {
debugger->backend->printf(debugger->backend, "No symbol table available.\n");
return;
@ -1441,7 +1443,7 @@ static void _setSymbol(struct CLIDebugger* debugger, struct CLIDebugVector* dv)
}
static void _findSymbol(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
struct mDebuggerSymbols* symbolTable = debugger->d.core->symbolTable;
struct mDebuggerSymbols* symbolTable = debugger->d.p->core->symbolTable;
if (!symbolTable) {
debugger->backend->printf(debugger->backend, "No symbol table available.\n");
return;

View File

@ -24,17 +24,18 @@ mLOG_DEFINE_CATEGORY(DEBUGGER, "Debugger", "core.debugger");
DEFINE_VECTOR(mBreakpointList, struct mBreakpoint);
DEFINE_VECTOR(mWatchpointList, struct mWatchpoint);
DEFINE_VECTOR(mDebuggerModuleList, struct mDebuggerModule*);
static void mDebuggerInit(void* cpu, struct mCPUComponent* component);
static void mDebuggerDeinit(struct mCPUComponent* component);
static void _mDebuggerInit(void* cpu, struct mCPUComponent* component);
static void _mDebuggerDeinit(struct mCPUComponent* component);
struct mDebugger* mDebuggerCreate(enum mDebuggerType type, struct mCore* core) {
struct mDebuggerModule* mDebuggerCreateModule(enum mDebuggerType type, struct mCore* core) {
if (!core->supportsDebuggerType(core, type)) {
return NULL;
}
union DebugUnion {
struct mDebugger d;
struct mDebuggerModule d;
struct CLIDebugger cli;
#ifdef USE_GDB_STUB
struct GDBStub gdb;
@ -67,10 +68,19 @@ struct mDebugger* mDebuggerCreate(enum mDebuggerType type, struct mCore* core) {
return &debugger->d;
}
void mDebuggerInit(struct mDebugger* debugger) {
memset(debugger, 0, sizeof(*debugger));
mDebuggerModuleListInit(&debugger->modules, 4);
}
void mDebuggerDeinit(struct mDebugger* debugger) {
mDebuggerModuleListDeinit(&debugger->modules);
}
void mDebuggerAttach(struct mDebugger* debugger, struct mCore* core) {
debugger->d.id = DEBUGGER_ID;
debugger->d.init = mDebuggerInit;
debugger->d.deinit = mDebuggerDeinit;
debugger->d.init = _mDebuggerInit;
debugger->d.deinit = _mDebuggerDeinit;
debugger->core = core;
if (!debugger->core->symbolTable) {
debugger->core->loadSymbols(debugger->core, NULL);
@ -80,7 +90,20 @@ void mDebuggerAttach(struct mDebugger* debugger, struct mCore* core) {
core->attachDebugger(core, debugger);
}
void mDebuggerAttachModule(struct mDebugger* debugger, struct mDebuggerModule* module) {
module->p = debugger;
*mDebuggerModuleListAppend(&debugger->modules) = module;
}
void mDebuggerDetachModule(struct mDebugger* debugger, struct mDebuggerModule* module) {
// TODO
abort();
}
void mDebuggerRun(struct mDebugger* debugger) {
size_t i;
size_t anyPaused = 0;
switch (debugger->state) {
case DEBUGGER_RUNNING:
if (!debugger->platform->hasBreakpoints(debugger->platform)) {
@ -93,12 +116,28 @@ void mDebuggerRun(struct mDebugger* debugger) {
case DEBUGGER_CALLBACK:
debugger->core->step(debugger->core);
debugger->platform->checkBreakpoints(debugger->platform);
debugger->custom(debugger);
for (i = 0; i < mDebuggerModuleListSize(&debugger->modules); ++i) {
struct mDebuggerModule* module = *mDebuggerModuleListGetPointer(&debugger->modules, i);
if (module->needsCallback) {
module->custom(module);
}
}
break;
case DEBUGGER_PAUSED:
if (debugger->paused) {
debugger->paused(debugger);
} else {
for (i = 0; i < mDebuggerModuleListSize(&debugger->modules); ++i) {
struct mDebuggerModule* module = *mDebuggerModuleListGetPointer(&debugger->modules, i);
if (module->isPaused) {
if (module->paused) {
module->paused(module);
}
if (module->isPaused) {
++anyPaused;
}
} else if (module->needsCallback) {
module->custom(module);
}
}
if (debugger->state == DEBUGGER_PAUSED && !anyPaused) {
debugger->state = DEBUGGER_RUNNING;
}
break;
@ -115,30 +154,114 @@ void mDebuggerRunFrame(struct mDebugger* debugger) {
}
void mDebuggerEnter(struct mDebugger* debugger, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
debugger->state = DEBUGGER_PAUSED;
if (debugger->platform->entered) {
debugger->platform->entered(debugger->platform, reason, info);
}
size_t i;
for (i = 0; i < mDebuggerModuleListSize(&debugger->modules); ++i) {
struct mDebuggerModule* module = *mDebuggerModuleListGetPointer(&debugger->modules, i);
if (info && info->target) {
// This check needs to be in the loop to make sure we don't
// accidentally enter a module that isn't registered.
// This is an error by the caller, but it's good to check for.
if (info->target != module) {
continue;
}
// Make this the last loop so we don't hit this one twice
i = mDebuggerModuleListSize(&debugger->modules) - 1;
}
module->isPaused = true;
if (module->entered) {
module->entered(module, reason, info);
}
}
#ifdef ENABLE_SCRIPTING
if (debugger->bridge) {
mScriptBridgeDebuggerEntered(debugger->bridge, reason, info);
}
#endif
mDebuggerUpdatePaused(debugger);
}
static void mDebuggerInit(void* cpu, struct mCPUComponent* component) {
struct mDebugger* debugger = (struct mDebugger*) component;
debugger->state = DEBUGGER_RUNNING;
debugger->platform->init(cpu, debugger->platform);
if (debugger->init) {
debugger->init(debugger);
void mDebuggerInterrupt(struct mDebugger* debugger) {
size_t i;
for (i = 0; i < mDebuggerModuleListSize(&debugger->modules); ++i) {
struct mDebuggerModule* module = *mDebuggerModuleListGetPointer(&debugger->modules, i);
if (module->interrupt) {
module->interrupt(module);
}
}
}
static void mDebuggerDeinit(struct mCPUComponent* component) {
void mDebuggerUpdatePaused(struct mDebugger* debugger) {
if (debugger->state == DEBUGGER_SHUTDOWN) {
return;
}
size_t anyPaused = 0;
size_t anyCallback = 0;
size_t i;
for (i = 0; i < mDebuggerModuleListSize(&debugger->modules); ++i) {
struct mDebuggerModule* module = *mDebuggerModuleListGetPointer(&debugger->modules, i);
if (module->isPaused) {
++anyPaused;
}
if (module->needsCallback) {
++anyCallback;
}
}
if (anyPaused) {
debugger->state = DEBUGGER_PAUSED;
} else if (anyCallback) {
debugger->state = DEBUGGER_CALLBACK;
} else {
debugger->state = DEBUGGER_RUNNING;
}
}
void mDebuggerShutdown(struct mDebugger* debugger) {
debugger->state = DEBUGGER_SHUTDOWN;
}
bool mDebuggerIsShutdown(const struct mDebugger* debugger) {
return debugger->state == DEBUGGER_SHUTDOWN;
}
void mDebuggerUpdate(struct mDebugger* debugger) {
size_t i;
for (i = 0; i < mDebuggerModuleListSize(&debugger->modules); ++i) {
struct mDebuggerModule* module = *mDebuggerModuleListGetPointer(&debugger->modules, i);
if (module->update) {
module->update(module);
}
}
}
static void _mDebuggerInit(void* cpu, struct mCPUComponent* component) {
struct mDebugger* debugger = (struct mDebugger*) component;
if (debugger->deinit) {
debugger->deinit(debugger);
debugger->state = DEBUGGER_RUNNING;
debugger->platform->init(cpu, debugger->platform);
size_t i;
for (i = 0; i < mDebuggerModuleListSize(&debugger->modules); ++i) {
struct mDebuggerModule* module = *mDebuggerModuleListGetPointer(&debugger->modules, i);
if (module->init) {
module->init(module);
}
}
}
static void _mDebuggerDeinit(struct mCPUComponent* component) {
struct mDebugger* debugger = (struct mDebugger*) component;
size_t i;
for (i = 0; i < mDebuggerModuleListSize(&debugger->modules); ++i) {
struct mDebuggerModule* module = *mDebuggerModuleListGetPointer(&debugger->modules, i);
if (module->deinit) {
module->deinit(module);
}
}
debugger->platform->deinit(debugger->platform);
}
@ -161,3 +284,10 @@ bool mDebuggerLookupIdentifier(struct mDebugger* debugger, const char* name, int
}
return false;
}
void mDebuggerModuleSetNeedsCallback(struct mDebuggerModule* debugger) {
debugger->needsCallback = true;
if (debugger->p->state == DEBUGGER_RUNNING) {
debugger->p->state = DEBUGGER_CALLBACK;
}
}

View File

@ -66,14 +66,14 @@ static const char* TARGET_XML = "<target version=\"1.0\">"
static void _sendMessage(struct GDBStub* stub);
static void _gdbStubDeinit(struct mDebugger* debugger) {
static void _gdbStubDeinit(struct mDebuggerModule* debugger) {
struct GDBStub* stub = (struct GDBStub*) debugger;
if (!SOCKET_FAILED(stub->socket)) {
GDBStubShutdown(stub);
}
}
static void _gdbStubEntered(struct mDebugger* debugger, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
static void _gdbStubEntered(struct mDebuggerModule* debugger, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
struct GDBStub* stub = (struct GDBStub*) debugger;
switch (reason) {
case DEBUGGER_ENTER_MANUAL:
@ -128,7 +128,7 @@ static void _gdbStubEntered(struct mDebugger* debugger, enum mDebuggerEntryReaso
_sendMessage(stub);
}
static void _gdbStubPoll(struct mDebugger* debugger) {
static void _gdbStubPoll(struct mDebuggerModule* debugger) {
struct GDBStub* stub = (struct GDBStub*) debugger;
--stub->untilPoll;
if (stub->untilPoll > 0) {
@ -139,13 +139,13 @@ static void _gdbStubPoll(struct mDebugger* debugger) {
GDBStubUpdate(stub);
}
static void _gdbStubWait(struct mDebugger* debugger) {
static void _gdbStubWait(struct mDebuggerModule* debugger) {
struct GDBStub* stub = (struct GDBStub*) debugger;
stub->shouldBlock = true;
GDBStubUpdate(stub);
}
static void _gdbStubUpdate(struct mDebugger* debugger) {
static void _gdbStubUpdate(struct mDebuggerModule* debugger) {
struct GDBStub* stub = (struct GDBStub*) debugger;
stub->shouldBlock = false;
GDBStubUpdate(stub);
@ -252,14 +252,14 @@ static void _writeHostInfo(struct GDBStub* stub) {
}
static void _continue(struct GDBStub* stub, const char* message) {
stub->d.state = DEBUGGER_CALLBACK;
mDebuggerModuleSetNeedsCallback(&stub->d);
stub->untilPoll = GDB_STUB_INTERVAL;
// TODO: parse message
UNUSED(message);
}
static void _step(struct GDBStub* stub, const char* message) {
stub->d.core->step(stub->d.core);
stub->d.p->core->step(stub->d.p->core);
snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGTRAP);
_sendMessage(stub);
// TODO: parse message
@ -281,7 +281,7 @@ static void _writeMemoryBinary(struct GDBStub* stub, const char* message) {
return;
}
struct ARMCore* cpu = stub->d.core->cpu;
struct ARMCore* cpu = stub->d.p->core->cpu;
for (i = 0; i < size; i++) {
uint8_t byte = *readAddress;
++readAddress;
@ -315,7 +315,7 @@ static void _writeMemory(struct GDBStub* stub, const char* message) {
return;
}
struct ARMCore* cpu = stub->d.core->cpu;
struct ARMCore* cpu = stub->d.p->core->cpu;
for (i = 0; i < size; ++i, readAddress += 2) {
uint8_t byte = _hex2int(readAddress, 2);
GBAPatch8(cpu, address + i, byte, 0);
@ -335,7 +335,7 @@ static void _readMemory(struct GDBStub* stub, const char* message) {
_error(stub, GDB_BAD_ARGUMENTS);
return;
}
struct ARMCore* cpu = stub->d.core->cpu;
struct ARMCore* cpu = stub->d.p->core->cpu;
int writeAddress = 0;
for (i = 0; i < size; ++i, writeAddress += 2) {
uint8_t byte = cpu->memory.load8(cpu, address + i, 0);
@ -346,7 +346,7 @@ static void _readMemory(struct GDBStub* stub, const char* message) {
}
static void _writeGPRs(struct GDBStub* stub, const char* message) {
struct ARMCore* cpu = stub->d.core->cpu;
struct ARMCore* cpu = stub->d.p->core->cpu;
const char* readAddress = message;
int r;
@ -365,7 +365,7 @@ static void _writeGPRs(struct GDBStub* stub, const char* message) {
}
static void _readGPRs(struct GDBStub* stub, const char* message) {
struct ARMCore* cpu = stub->d.core->cpu;
struct ARMCore* cpu = stub->d.p->core->cpu;
UNUSED(message);
int r;
int i = 0;
@ -389,7 +389,7 @@ static void _readGPRs(struct GDBStub* stub, const char* message) {
}
static void _writeRegister(struct GDBStub* stub, const char* message) {
struct ARMCore* cpu = stub->d.core->cpu;
struct ARMCore* cpu = stub->d.p->core->cpu;
const char* readAddress = message;
unsigned i = 0;
@ -422,7 +422,7 @@ static void _writeRegister(struct GDBStub* stub, const char* message) {
}
static void _readRegister(struct GDBStub* stub, const char* message) {
struct ARMCore* cpu = stub->d.core->cpu;
struct ARMCore* cpu = stub->d.p->core->cpu;
const char* readAddress = message;
unsigned i = 0;
uint32_t reg = _readHex(readAddress, &i);
@ -507,7 +507,7 @@ static void _generateMemoryMapXml(struct GDBStub* stub, char* memoryMap) {
strncpy(memoryMap, "<memory-map version=\"1.0\">", 27);
index += strlen(memoryMap);
const struct mCoreMemoryBlock* blocks;
size_t nBlocks = stub->d.core->listMemoryBlocks(stub->d.core, &blocks);
size_t nBlocks = stub->d.p->core->listMemoryBlocks(stub->d.p->core, &blocks);
size_t i;
for (i = 0; i < nBlocks; ++i) {
if (!(blocks[i].flags & mCORE_MEMORY_MAPPED)) {
@ -569,7 +569,11 @@ static void _processVReadCommand(struct GDBStub* stub, const char* message) {
stub->outgoing[0] = '\0';
if (!strncmp("Attach", message, 6)) {
strncpy(stub->outgoing, "1", GDB_STUB_MAX_LINE - 4);
mDebuggerEnter(&stub->d, DEBUGGER_ENTER_MANUAL, 0);
stub->d.isPaused = true;
struct mDebuggerEntryInfo info = {
.target = &stub->d
};
mDebuggerEnter(stub->d.p, DEBUGGER_ENTER_MANUAL, &info);
}
_sendMessage(stub);
}
@ -592,19 +596,19 @@ static void _setBreakpoint(struct GDBStub* stub, const char* message) {
switch (message[0]) {
case '0':
case '1':
stub->d.platform->setBreakpoint(stub->d.platform, &breakpoint);
stub->d.p->platform->setBreakpoint(stub->d.p->platform, &breakpoint);
break;
case '2':
watchpoint.type = stub->watchpointsBehavior == GDB_WATCHPOINT_OVERRIDE_LOGIC_ANY_WRITE ? WATCHPOINT_WRITE : WATCHPOINT_WRITE_CHANGE;
stub->d.platform->setWatchpoint(stub->d.platform, &watchpoint);
stub->d.p->platform->setWatchpoint(stub->d.p->platform, &watchpoint);
break;
case '3':
watchpoint.type = WATCHPOINT_READ;
stub->d.platform->setWatchpoint(stub->d.platform, &watchpoint);
stub->d.p->platform->setWatchpoint(stub->d.p->platform, &watchpoint);
break;
case '4':
watchpoint.type = WATCHPOINT_RW;
stub->d.platform->setWatchpoint(stub->d.platform, &watchpoint);
stub->d.p->platform->setWatchpoint(stub->d.p->platform, &watchpoint);
break;
default:
stub->outgoing[0] = '\0';
@ -627,12 +631,12 @@ static void _clearBreakpoint(struct GDBStub* stub, const char* message) {
case '0':
case '1':
mBreakpointListInit(&breakpoints, 0);
stub->d.platform->listBreakpoints(stub->d.platform, &breakpoints);
stub->d.p->platform->listBreakpoints(stub->d.p->platform, &breakpoints);
for (index = 0; index < mBreakpointListSize(&breakpoints); ++index) {
if (mBreakpointListGetPointer(&breakpoints, index)->address != address) {
continue;
}
stub->d.platform->clearBreakpoint(stub->d.platform, mBreakpointListGetPointer(&breakpoints, index)->id);
stub->d.p->platform->clearBreakpoint(stub->d.p->platform, mBreakpointListGetPointer(&breakpoints, index)->id);
}
mBreakpointListDeinit(&breakpoints);
break;
@ -640,13 +644,13 @@ static void _clearBreakpoint(struct GDBStub* stub, const char* message) {
case '3':
case '4':
mWatchpointListInit(&watchpoints, 0);
stub->d.platform->listWatchpoints(stub->d.platform, &watchpoints);
stub->d.p->platform->listWatchpoints(stub->d.p->platform, &watchpoints);
for (index = 0; index < mWatchpointListSize(&watchpoints); ++index) {
struct mWatchpoint* watchpoint = mWatchpointListGetPointer(&watchpoints, index);
if (address >= watchpoint->minAddress && address < watchpoint->maxAddress) {
continue;
}
stub->d.platform->clearBreakpoint(stub->d.platform, watchpoint->id);
stub->d.p->platform->clearBreakpoint(stub->d.p->platform, watchpoint->id);
}
mWatchpointListDeinit(&watchpoints);
break;
@ -660,6 +664,9 @@ static void _clearBreakpoint(struct GDBStub* stub, const char* message) {
size_t _parseGDBMessage(struct GDBStub* stub, const char* message) {
uint8_t checksum = 0;
int parsed = 1;
struct mDebuggerEntryInfo info = {
.target = &stub->d
};
switch (*message) {
case '+':
stub->lineAck = GDB_ACK_RECEIVED;
@ -671,7 +678,8 @@ size_t _parseGDBMessage(struct GDBStub* stub, const char* message) {
++message;
break;
case '\x03':
mDebuggerEnter(&stub->d, DEBUGGER_ENTER_MANUAL, 0);
stub->d.isPaused = true;
mDebuggerEnter(stub->d.p, DEBUGGER_ENTER_MANUAL, &info);
return parsed;
default:
_nak(stub);
@ -820,9 +828,9 @@ void GDBStubHangup(struct GDBStub* stub) {
SocketClose(stub->connection);
stub->connection = INVALID_SOCKET;
}
if (stub->d.state == DEBUGGER_PAUSED) {
stub->d.state = DEBUGGER_RUNNING;
}
stub->d.needsCallback = false;
stub->d.isPaused = false;
mDebuggerUpdatePaused(stub->d.p);
}
void GDBStubShutdown(struct GDBStub* stub) {
@ -835,9 +843,9 @@ void GDBStubShutdown(struct GDBStub* stub) {
void GDBStubUpdate(struct GDBStub* stub) {
if (stub->socket == INVALID_SOCKET) {
if (stub->d.state == DEBUGGER_PAUSED) {
stub->d.state = DEBUGGER_RUNNING;
}
stub->d.needsCallback = false;
stub->d.isPaused = false;
mDebuggerUpdatePaused(stub->d.p);
return;
}
if (stub->connection == INVALID_SOCKET) {
@ -850,7 +858,7 @@ void GDBStubUpdate(struct GDBStub* stub) {
if (!SocketSetBlocking(stub->connection, false)) {
goto connectionLost;
}
mDebuggerEnter(&stub->d, DEBUGGER_ENTER_ATTACHED, 0);
mDebuggerEnter(stub->d.p, DEBUGGER_ENTER_ATTACHED, 0);
} else if (SocketWouldBlock()) {
return;
} else {

View File

@ -20,7 +20,10 @@ static char* _prompt(EditLine* el) {
static void _breakIntoDefault(int signal) {
UNUSED(signal);
mDebuggerEnter(&_activeDebugger->d, DEBUGGER_ENTER_MANUAL, 0);
struct mDebuggerEntryInfo info = {
.target = &_activeDebugger->d
};
mDebuggerEnter(_activeDebugger->d.p, DEBUGGER_ENTER_MANUAL, &info);
}
static unsigned char _tabComplete(EditLine* elstate, int ch) {

View File

@ -58,7 +58,7 @@ static bool _GBCLIDebuggerCustom(struct CLIDebuggerSystem* debugger) {
if (gbDebugger->frameAdvance) {
if (!gbDebugger->inVblank && GBRegisterSTATGetMode(((struct GB*) gbDebugger->core->board)->memory.io[GB_REG_STAT]) == 1) {
mDebuggerEnter(&gbDebugger->d.p->d, DEBUGGER_ENTER_MANUAL, 0);
mDebuggerEnter(gbDebugger->d.p->d.p, DEBUGGER_ENTER_MANUAL, 0);
gbDebugger->frameAdvance = false;
return false;
}
@ -70,7 +70,8 @@ static bool _GBCLIDebuggerCustom(struct CLIDebuggerSystem* debugger) {
static void _frame(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
UNUSED(dv);
debugger->d.state = DEBUGGER_CALLBACK;
debugger->d.needsCallback = true;
mDebuggerUpdatePaused(debugger->d.p);
struct GBCLIDebugger* gbDebugger = (struct GBCLIDebugger*) debugger->system;
gbDebugger->frameAdvance = true;

View File

@ -28,7 +28,7 @@ static const struct SM83Segment _GBCSegments[] = {
static void _printStatus(struct CLIDebuggerSystem* debugger) {
struct CLIDebuggerBackend* be = debugger->p->backend;
struct GB* gb = debugger->p->d.core->board;
struct GB* gb = debugger->p->d.p->core->board;
be->printf(be, "IE: %02X IF: %02X IME: %i\n", gb->memory.ie, gb->memory.io[GB_REG_IF], gb->memory.ime);
be->printf(be, "LCDC: %02X STAT: %02X LY: %02X\n", gb->memory.io[GB_REG_LCDC], gb->memory.io[GB_REG_STAT] | 0x80, gb->memory.io[GB_REG_LY]);
be->printf(be, "Next video mode: %i\n", mTimingUntil(&gb->timing, &gb->video.modeEvent) / 4);

View File

@ -57,7 +57,7 @@ static bool _GBACLIDebuggerCustom(struct CLIDebuggerSystem* debugger) {
if (gbaDebugger->frameAdvance) {
if (!gbaDebugger->inVblank && GBARegisterDISPSTATIsInVblank(((struct GBA*) gbaDebugger->core->board)->memory.io[REG_DISPSTAT >> 1])) {
mDebuggerEnter(&gbaDebugger->d.p->d, DEBUGGER_ENTER_MANUAL, 0);
mDebuggerEnter(gbaDebugger->d.p->d.p, DEBUGGER_ENTER_MANUAL, 0);
gbaDebugger->frameAdvance = false;
return false;
}
@ -69,7 +69,8 @@ static bool _GBACLIDebuggerCustom(struct CLIDebuggerSystem* debugger) {
static void _frame(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
UNUSED(dv);
debugger->d.state = DEBUGGER_CALLBACK;
debugger->d.needsCallback = true;
mDebuggerUpdatePaused(debugger->d.p);
struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger->system;
gbaDebugger->frameAdvance = true;

View File

@ -49,6 +49,10 @@ CoreController::CoreController(mCore* core, QObject* parent)
GBASIODolphinCreate(&m_dolphin);
#endif
#ifdef USE_DEBUGGERS
mDebuggerInit(&m_debugger);
#endif
m_resetActions.append([this]() {
if (m_autoload) {
mCoreLoadState(m_threadContext.core, 0, m_loadStateFlags);
@ -214,6 +218,10 @@ CoreController::~CoreController() {
mCoreThreadJoin(&m_threadContext);
#ifdef USE_DEBUGGERS
mDebuggerDeinit(&m_debugger);
#endif
if (m_cacheSet) {
mCacheSetDeinit(m_cacheSet.get());
m_cacheSet.reset();
@ -319,14 +327,33 @@ void CoreController::loadConfig(ConfigController* config) {
}
#ifdef USE_DEBUGGERS
void CoreController::setDebugger(mDebugger* debugger) {
void CoreController::attachDebugger(bool interrupt) {
Interrupter interrupter(this);
if (debugger) {
mDebuggerAttach(debugger, m_threadContext.core);
mDebuggerEnter(debugger, DEBUGGER_ENTER_ATTACHED, 0);
} else {
m_threadContext.core->detachDebugger(m_threadContext.core);
if (!m_threadContext.core->debugger) {
mDebuggerAttach(&m_debugger, m_threadContext.core);
}
if (interrupt) {
mDebuggerEnter(&m_debugger, DEBUGGER_ENTER_ATTACHED, 0);
}
}
void CoreController::detachDebugger() {
Interrupter interrupter(this);
if (!m_threadContext.core->debugger) {
return;
}
m_threadContext.core->detachDebugger(m_threadContext.core);
}
void CoreController::attachDebuggerModule(mDebuggerModule* module, bool interrupt) {
Interrupter interrupter(this);
mDebuggerAttachModule(&m_debugger, module);
attachDebugger(interrupt);
}
void CoreController::detachDebuggerModule(mDebuggerModule* module) {
Interrupter interrupter(this);
mDebuggerDetachModule(&m_debugger, module);
}
#endif
@ -445,7 +472,7 @@ void CoreController::start() {
void CoreController::stop() {
setSync(false);
#ifdef USE_DEBUGGERS
setDebugger(nullptr);
detachDebugger();
#endif
setPaused(false);
mCoreThreadEnd(&m_threadContext);

View File

@ -103,8 +103,11 @@ public:
mCheatDevice* cheatDevice() { return m_threadContext.core->cheatDevice(m_threadContext.core); }
#ifdef USE_DEBUGGERS
mDebugger* debugger() { return m_threadContext.core->debugger; }
void setDebugger(mDebugger*);
mDebugger* debugger() { return &m_debugger; }
void attachDebugger(bool interrupt = true);
void detachDebugger();
void attachDebuggerModule(mDebuggerModule*, bool interrupt = true);
void detachDebuggerModule(mDebuggerModule*);
#endif
void setMultiplayerController(MultiplayerController*);
@ -293,6 +296,10 @@ private:
bool m_autoload;
int m_autosaveCounter = 0;
#ifdef USE_DEBUGGERS
struct mDebugger m_debugger;
#endif
int m_fastForward = false;
int m_fastForwardForced = false;
int m_fastForwardVolume = -1;

View File

@ -37,8 +37,8 @@ void DebuggerConsoleController::enterLine(const QString& line) {
CoreController::Interrupter interrupter(m_gameController);
QMutexLocker lock(&m_mutex);
m_lines.append(line);
if (m_cliDebugger.d.state == DEBUGGER_RUNNING) {
mDebuggerEnter(&m_cliDebugger.d, DEBUGGER_ENTER_MANUAL, nullptr);
if (m_cliDebugger.d.p->state == DEBUGGER_RUNNING) {
mDebuggerEnter(m_cliDebugger.d.p, DEBUGGER_ENTER_MANUAL, nullptr);
}
m_cond.wakeOne();
}
@ -47,7 +47,7 @@ void DebuggerConsoleController::detach() {
{
CoreController::Interrupter interrupter(m_gameController);
QMutexLocker lock(&m_mutex);
if (m_cliDebugger.d.state != DEBUGGER_SHUTDOWN) {
if (m_cliDebugger.d.p->state != DEBUGGER_SHUTDOWN) {
m_lines.append(QString());
m_cond.wakeOne();
}
@ -82,7 +82,7 @@ void DebuggerConsoleController::init(struct CLIDebuggerBackend* be) {
void DebuggerConsoleController::deinit(struct CLIDebuggerBackend* be) {
Backend* consoleBe = reinterpret_cast<Backend*>(be);
DebuggerConsoleController* self = consoleBe->self;
if (QThread::currentThread() == self->thread() && be->p->d.state != DEBUGGER_SHUTDOWN) {
if (QThread::currentThread() == self->thread() && be->p->d.p->state != DEBUGGER_SHUTDOWN) {
self->m_lines.append(QString());
self->m_cond.wakeOne();
}

View File

@ -9,7 +9,7 @@
using namespace QGBA;
DebuggerController::DebuggerController(mDebugger* debugger, QObject* parent)
DebuggerController::DebuggerController(mDebuggerModule* debugger, QObject* parent)
: QObject(parent)
, m_debugger(debugger)
{
@ -19,7 +19,7 @@ bool DebuggerController::isAttached() {
if (!m_gameController) {
return false;
}
return m_gameController->debugger() == m_debugger;
return m_gameController->debugger() == m_debugger->p;
}
void DebuggerController::setController(std::shared_ptr<CoreController> controller) {
@ -45,7 +45,7 @@ void DebuggerController::attach() {
}
if (m_gameController) {
attachInternal();
m_gameController->setDebugger(m_debugger);
m_gameController->attachDebuggerModule(m_debugger);
} else {
m_autoattach = true;
}
@ -58,7 +58,7 @@ void DebuggerController::detach() {
if (m_gameController) {
CoreController::Interrupter interrupter(m_gameController);
shutdownInternal();
m_gameController->setDebugger(nullptr);
m_gameController->detachDebuggerModule(m_debugger);
} else {
m_autoattach = false;
}
@ -69,7 +69,7 @@ void DebuggerController::breakInto() {
return;
}
CoreController::Interrupter interrupter(m_gameController);
mDebuggerEnter(m_debugger, DEBUGGER_ENTER_MANUAL, 0);
mDebuggerEnter(m_debugger->p, DEBUGGER_ENTER_MANUAL, 0);
}
void DebuggerController::shutdown() {

View File

@ -9,7 +9,7 @@
#include <memory>
struct mDebugger;
struct mDebuggerModule;
namespace QGBA {
@ -19,7 +19,7 @@ class DebuggerController : public QObject {
Q_OBJECT
public:
DebuggerController(mDebugger* debugger, QObject* parent = nullptr);
DebuggerController(mDebuggerModule* debugger, QObject* parent = nullptr);
public:
bool isAttached();
@ -35,7 +35,7 @@ protected:
virtual void attachInternal();
virtual void shutdownInternal();
mDebugger* const m_debugger;
mDebuggerModule* const m_debugger;
std::shared_ptr<CoreController> m_gameController;
private:

View File

@ -20,10 +20,6 @@ ushort GDBController::port() {
return m_port;
}
bool GDBController::isAttached() {
return m_gameController && m_gameController->debugger() == &m_gdbStub.d;
}
void GDBController::setPort(ushort port) {
m_port = port;
}

View File

@ -23,7 +23,6 @@ public:
public:
ushort port();
bool isAttached();
public slots:
void setPort(ushort port);

View File

@ -243,18 +243,23 @@ int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args) {
#endif
#ifdef USE_DEBUGGERS
struct mDebugger* debugger = mDebuggerCreate(args->debuggerType, renderer->core);
if (debugger) {
struct mDebuggerModule* module = mDebuggerCreateModule(args->debuggerType, renderer->core);
struct mDebugger debugger;
mDebuggerInit(&debugger);
if (module) {
#ifdef USE_EDITLINE
if (args->debuggerType == DEBUGGER_CLI) {
struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
struct CLIDebugger* cliDebugger = (struct CLIDebugger*) module;
CLIDebuggerAttachBackend(cliDebugger, CLIDebuggerEditLineBackendCreate());
}
#endif
mDebuggerAttach(debugger, renderer->core);
mDebuggerEnter(debugger, DEBUGGER_ENTER_MANUAL, NULL);
module->isPaused = true;
mDebuggerAttachModule(&debugger, module);
mDebuggerAttach(&debugger, renderer->core);
mDebuggerEnter(&debugger, DEBUGGER_ENTER_MANUAL, NULL);
#ifdef ENABLE_SCRIPTING
mScriptBridgeSetDebugger(bridge, debugger);
mScriptBridgeSetDebugger(bridge, &debugger);
#endif
}
#endif
@ -322,6 +327,13 @@ int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args) {
mScriptBridgeDestroy(bridge);
#endif
#ifdef USE_DEBUGGERS
if (module) {
renderer->core->detachDebugger(renderer->core);
mDebuggerDeinit(&debugger);
}
#endif
return didFail;
}

View File

@ -26,7 +26,7 @@ static inline void _printFlags(struct CLIDebuggerBackend* be, union FlagRegister
}
static void _disassemble(struct CLIDebuggerSystem* debugger, struct CLIDebugVector* dv) {
struct SM83Core* cpu = debugger->p->d.core->cpu;
struct SM83Core* cpu = debugger->p->d.p->core->cpu;
uint16_t address;
int segment = -1;
@ -64,7 +64,7 @@ static inline uint16_t _printLine(struct CLIDebugger* debugger, uint16_t address
uint8_t instruction;
size_t bytesRemaining = 1;
for (bytesRemaining = 1; bytesRemaining; --bytesRemaining) {
instruction = debugger->d.core->rawRead8(debugger->d.core, address, segment);
instruction = debugger->d.p->core->rawRead8(debugger->d.p->core, address, segment);
disPtr += snprintf(disPtr, sizeof(disassembly) - (disPtr - disassembly), "%02X", instruction);
++address;
bytesRemaining += SM83Decode(instruction, &info);
@ -78,16 +78,16 @@ static inline uint16_t _printLine(struct CLIDebugger* debugger, uint16_t address
static void _printStatus(struct CLIDebuggerSystem* debugger) {
struct CLIDebuggerBackend* be = debugger->p->backend;
struct SM83Core* cpu = debugger->p->d.core->cpu;
struct SM83Core* cpu = debugger->p->d.p->core->cpu;
be->printf(be, "A: %02X F: %02X (AF: %04X)\n", cpu->a, cpu->f.packed, cpu->af);
be->printf(be, "B: %02X C: %02X (BC: %04X)\n", cpu->b, cpu->c, cpu->bc);
be->printf(be, "D: %02X E: %02X (DE: %04X)\n", cpu->d, cpu->e, cpu->de);
be->printf(be, "H: %02X L: %02X (HL: %04X)\n", cpu->h, cpu->l, cpu->hl);
be->printf(be, "PC: %04X SP: %04X\n", cpu->pc, cpu->sp);
_printFlags(be, cpu->f);
be->printf(be, "T-cycle: %" PRIu64 "\n", mTimingGlobalTime(debugger->p->d.core->timing));
be->printf(be, "T-cycle: %" PRIu64 "\n", mTimingGlobalTime(debugger->p->d.p->core->timing));
struct SM83Debugger* platDebugger = (struct SM83Debugger*) debugger->p->d.platform;
struct SM83Debugger* platDebugger = (struct SM83Debugger*) debugger->p->d.p->platform;
size_t i;
for (i = 0; platDebugger->segments[i].name; ++i) {
be->printf(be, "%s%s: %02X", i ? " " : "", platDebugger->segments[i].name, cpu->memory.currentSegment(cpu, platDebugger->segments[i].start));

View File

@ -120,10 +120,6 @@ static void SM83DebuggerEnter(struct mDebuggerPlatform* platform, enum mDebugger
struct SM83Debugger* debugger = (struct SM83Debugger*) platform;
struct SM83Core* cpu = debugger->cpu;
cpu->nextEvent = cpu->cycles;
if (debugger->d.p->entered) {
debugger->d.p->entered(debugger->d.p, reason, info);
}
}
static ssize_t SM83DebuggerSetBreakpoint(struct mDebuggerPlatform* d, const struct mBreakpoint* info) {