mirror of https://github.com/mgba-emu/mgba.git
Debugger: Break out debugger functionality into modules
This commit is contained in:
parent
b1f991bf94
commit
b21a6158f4
|
@ -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
|
||||
|
|
|
@ -81,7 +81,7 @@ struct CLIDebuggerBackend {
|
|||
};
|
||||
|
||||
struct CLIDebugger {
|
||||
struct mDebugger d;
|
||||
struct mDebuggerModule d;
|
||||
|
||||
struct CLIDebuggerSystem* system;
|
||||
struct CLIDebuggerBackend* backend;
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ public:
|
|||
|
||||
public:
|
||||
ushort port();
|
||||
bool isAttached();
|
||||
|
||||
public slots:
|
||||
void setPort(ushort port);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue