mirror of https://github.com/mgba-emu/mgba.git
Add watchpoints
This commit is contained in:
parent
99769695d7
commit
a7182b8df9
|
@ -1,5 +1,7 @@
|
|||
#include "debugger.h"
|
||||
|
||||
#include "memory-debugger.h"
|
||||
|
||||
#include "arm.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
@ -23,11 +25,6 @@ struct DebugVector {
|
|||
};
|
||||
};
|
||||
|
||||
struct DebugBreakpoint {
|
||||
struct DebugBreakpoint* next;
|
||||
int32_t address;
|
||||
};
|
||||
|
||||
static const char* ERROR_MISSING_ARGS = "Arguments missing";
|
||||
|
||||
static struct ARMDebugger* _activeDebugger;
|
||||
|
@ -45,6 +42,7 @@ static void _readByte(struct ARMDebugger*, struct DebugVector*);
|
|||
static void _readHalfword(struct ARMDebugger*, struct DebugVector*);
|
||||
static void _readWord(struct ARMDebugger*, struct DebugVector*);
|
||||
static void _setBreakpoint(struct ARMDebugger*, struct DebugVector*);
|
||||
static void _setWatchpoint(struct ARMDebugger*, struct DebugVector*);
|
||||
|
||||
static void _breakIntoDefault(int signal);
|
||||
|
||||
|
@ -70,6 +68,8 @@ struct {
|
|||
{ "rw", _readWord },
|
||||
{ "status", _printStatus },
|
||||
{ "x", _breakInto },
|
||||
{ "w", _setWatchpoint },
|
||||
{ "watch", _setWatchpoint },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
@ -203,6 +203,21 @@ static void _setBreakpoint(struct ARMDebugger* debugger, struct DebugVector* dv)
|
|||
debugger->breakpoints = breakpoint;
|
||||
}
|
||||
|
||||
static void _setWatchpoint(struct ARMDebugger* debugger, struct DebugVector* dv) {
|
||||
if (!dv || dv->type != INT_TYPE) {
|
||||
printf("%s\n", ERROR_MISSING_ARGS);
|
||||
return;
|
||||
}
|
||||
uint32_t address = dv->intValue;
|
||||
if (debugger->cpu->memory != &debugger->memoryShim.d) {
|
||||
ARMDebuggerInstallMemoryShim(debugger);
|
||||
}
|
||||
struct DebugBreakpoint* watchpoint = malloc(sizeof(struct DebugBreakpoint));
|
||||
watchpoint->address = address;
|
||||
watchpoint->next = debugger->memoryShim.watchpoints;
|
||||
debugger->memoryShim.watchpoints = watchpoint;
|
||||
}
|
||||
|
||||
static void _checkBreakpoints(struct ARMDebugger* debugger) {
|
||||
struct DebugBreakpoint* breakpoint;
|
||||
int instructionLength;
|
||||
|
@ -532,6 +547,8 @@ void ARMDebuggerInit(struct ARMDebugger* debugger, struct ARMCore* cpu) {
|
|||
debugger->state = DEBUGGER_PAUSED;
|
||||
debugger->lastCommand = 0;
|
||||
debugger->breakpoints = 0;
|
||||
debugger->memoryShim.p = debugger;
|
||||
debugger->memoryShim.watchpoints = 0;
|
||||
_activeDebugger = debugger;
|
||||
signal(SIGINT, _breakIntoDefault);
|
||||
}
|
||||
|
|
|
@ -1,18 +1,34 @@
|
|||
#ifndef DEBUGGER_H
|
||||
#define DEBUGGER_H
|
||||
|
||||
#include "arm.h"
|
||||
|
||||
enum DebuggerState {
|
||||
DEBUGGER_PAUSED,
|
||||
DEBUGGER_RUNNING,
|
||||
DEBUGGER_EXITING
|
||||
};
|
||||
|
||||
struct DebugBreakpoint {
|
||||
struct DebugBreakpoint* next;
|
||||
int32_t address;
|
||||
};
|
||||
|
||||
struct DebugMemoryShim {
|
||||
struct ARMMemory d;
|
||||
struct ARMMemory* original;
|
||||
|
||||
struct ARMDebugger* p;
|
||||
struct DebugBreakpoint* watchpoints;
|
||||
};
|
||||
|
||||
struct ARMDebugger {
|
||||
enum DebuggerState state;
|
||||
struct ARMCore* cpu;
|
||||
|
||||
char* lastCommand;
|
||||
struct DebugBreakpoint* breakpoints;
|
||||
struct DebugMemoryShim memoryShim;
|
||||
};
|
||||
|
||||
void ARMDebuggerInit(struct ARMDebugger*, struct ARMCore*);
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
#include "memory-debugger.h"
|
||||
|
||||
#include "debugger.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static void ARMDebuggerShim_store32(struct ARMMemory*, uint32_t address, int32_t value, int* cycleCounter);
|
||||
static void ARMDebuggerShim_store16(struct ARMMemory*, uint32_t address, int16_t value, int* cycleCounter);
|
||||
static void ARMDebuggerShim_store8(struct ARMMemory*, uint32_t address, int8_t value, int* cycleCounter);
|
||||
static void ARMDebuggerShim_setActiveRegion(struct ARMMemory* memory, uint32_t address);
|
||||
|
||||
#define CREATE_SHIM(NAME, RETURN, TYPES, ARGS...) \
|
||||
static RETURN ARMDebuggerShim_ ## NAME TYPES { \
|
||||
struct DebugMemoryShim* debugMemory = (struct DebugMemoryShim*) memory; \
|
||||
return debugMemory->original->NAME(debugMemory->original, ARGS); \
|
||||
}
|
||||
|
||||
CREATE_SHIM(load32, int32_t, (struct ARMMemory* memory, uint32_t address, int* cycleCounter), address, cycleCounter)
|
||||
CREATE_SHIM(load16, int16_t, (struct ARMMemory* memory, uint32_t address, int* cycleCounter), address, cycleCounter)
|
||||
CREATE_SHIM(loadU16, uint16_t, (struct ARMMemory* memory, uint32_t address, int* cycleCounter), address, cycleCounter)
|
||||
CREATE_SHIM(load8, int8_t, (struct ARMMemory* memory, uint32_t address, int* cycleCounter), address, cycleCounter)
|
||||
CREATE_SHIM(loadU8, uint8_t, (struct ARMMemory* memory, uint32_t address, int* cycleCounter), address, cycleCounter)
|
||||
CREATE_SHIM(waitMultiple, int, (struct ARMMemory* memory, uint32_t startAddress, int count), startAddress, count)
|
||||
|
||||
static int _checkWatchpoints(struct DebugBreakpoint* watchpoints, uint32_t address, int width) {
|
||||
width -= 1;
|
||||
for (; watchpoints; watchpoints = watchpoints->next) {
|
||||
if (!((watchpoints->address ^ address) & ~width)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ARMDebuggerInstallMemoryShim(struct ARMDebugger* debugger) {
|
||||
debugger->memoryShim.original = debugger->cpu->memory;
|
||||
memcpy(&debugger->memoryShim.d, debugger->cpu->memory, sizeof(struct ARMMemory));
|
||||
debugger->memoryShim.d.store32 = ARMDebuggerShim_store32;
|
||||
debugger->memoryShim.d.store16 = ARMDebuggerShim_store16;
|
||||
debugger->memoryShim.d.store8 = ARMDebuggerShim_store8;
|
||||
debugger->memoryShim.d.load32 = ARMDebuggerShim_load32;
|
||||
debugger->memoryShim.d.load16 = ARMDebuggerShim_load16;
|
||||
debugger->memoryShim.d.loadU16 = ARMDebuggerShim_loadU16;
|
||||
debugger->memoryShim.d.load8 = ARMDebuggerShim_load8;
|
||||
debugger->memoryShim.d.loadU8 = ARMDebuggerShim_loadU8;
|
||||
debugger->memoryShim.d.setActiveRegion = ARMDebuggerShim_setActiveRegion;
|
||||
debugger->memoryShim.d.waitMultiple = ARMDebuggerShim_waitMultiple;
|
||||
debugger->cpu->memory = &debugger->memoryShim.d;
|
||||
}
|
||||
|
||||
int32_t ARMDebuggerLoad32(struct ARMMemory* memory, uint32_t address, int* cycleCounter) {
|
||||
struct DebugMemoryShim* debugMemory = (struct DebugMemoryShim*) memory;
|
||||
return debugMemory->original->load32(debugMemory->original, address, cycleCounter);
|
||||
}
|
||||
|
||||
int16_t ARMDebuggerLoad16(struct ARMMemory* memory, uint32_t address, int* cycleCounter) {
|
||||
struct DebugMemoryShim* debugMemory = (struct DebugMemoryShim*) memory;
|
||||
return debugMemory->original->load16(debugMemory->original, address, cycleCounter);
|
||||
}
|
||||
|
||||
uint16_t ARMDebuggerLoadU16(struct ARMMemory* memory, uint32_t address, int* cycleCounter) {
|
||||
struct DebugMemoryShim* debugMemory = (struct DebugMemoryShim*) memory;
|
||||
return debugMemory->original->loadU16(debugMemory->original, address, cycleCounter);
|
||||
}
|
||||
|
||||
int8_t ARMDebuggerLoad8(struct ARMMemory* memory, uint32_t address, int* cycleCounter) {
|
||||
struct DebugMemoryShim* debugMemory = (struct DebugMemoryShim*) memory;
|
||||
return debugMemory->original->load8(debugMemory->original, address, cycleCounter);
|
||||
}
|
||||
|
||||
uint8_t ARMDebuggerLoadU8(struct ARMMemory* memory, uint32_t address, int* cycleCounter) {
|
||||
struct DebugMemoryShim* debugMemory = (struct DebugMemoryShim*) memory;
|
||||
return debugMemory->original->loadU8(debugMemory->original, address, cycleCounter);
|
||||
}
|
||||
|
||||
void ARMDebuggerShim_store32(struct ARMMemory* memory, uint32_t address, int32_t value, int* cycleCounter) {
|
||||
struct DebugMemoryShim* debugMemory = (struct DebugMemoryShim*) memory;
|
||||
if (_checkWatchpoints(debugMemory->watchpoints, address, 4)) {
|
||||
ARMDebuggerEnter(debugMemory->p);
|
||||
}
|
||||
debugMemory->original->store32(debugMemory->original, address, value, cycleCounter);
|
||||
}
|
||||
|
||||
void ARMDebuggerShim_store16(struct ARMMemory* memory, uint32_t address, int16_t value, int* cycleCounter) {
|
||||
struct DebugMemoryShim* debugMemory = (struct DebugMemoryShim*) memory;
|
||||
if (_checkWatchpoints(debugMemory->watchpoints, address, 2)) {
|
||||
ARMDebuggerEnter(debugMemory->p);
|
||||
}
|
||||
debugMemory->original->store16(debugMemory->original, address, value, cycleCounter);
|
||||
}
|
||||
|
||||
void ARMDebuggerShim_store8(struct ARMMemory* memory, uint32_t address, int8_t value, int* cycleCounter) {
|
||||
struct DebugMemoryShim* debugMemory = (struct DebugMemoryShim*) memory;
|
||||
if (_checkWatchpoints(debugMemory->watchpoints, address, 1)) {
|
||||
ARMDebuggerEnter(debugMemory->p);
|
||||
}
|
||||
debugMemory->original->store8(debugMemory->original, address, value, cycleCounter);
|
||||
}
|
||||
|
||||
void ARMDebuggerShim_setActiveRegion(struct ARMMemory* memory, uint32_t address) {
|
||||
struct DebugMemoryShim* debugMemory = (struct DebugMemoryShim*) memory;
|
||||
debugMemory->original->setActiveRegion(debugMemory->original, address);
|
||||
memory->activeRegion = debugMemory->original->activeRegion;
|
||||
memory->activeMask = debugMemory->original->activeMask;
|
||||
memory->activePrefetchCycles32 = debugMemory->original->activePrefetchCycles32;
|
||||
memory->activePrefetchCycles16 = debugMemory->original->activePrefetchCycles16;
|
||||
memory->activeNonseqCycles32 = debugMemory->original->activeNonseqCycles32;
|
||||
memory->activeNonseqCycles16 = debugMemory->original->activeNonseqCycles16;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef MEMORY_DEBUGGER_H
|
||||
#define MEMORY_DEBUGGER_H
|
||||
|
||||
#include "arm.h"
|
||||
|
||||
struct ARMDebugger;
|
||||
|
||||
void ARMDebuggerInstallMemoryShim(struct ARMDebugger* debugger);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue