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 "debugger.h"
|
||||||
|
|
||||||
|
#include "memory-debugger.h"
|
||||||
|
|
||||||
#include "arm.h"
|
#include "arm.h"
|
||||||
|
|
||||||
#include <signal.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 const char* ERROR_MISSING_ARGS = "Arguments missing";
|
||||||
|
|
||||||
static struct ARMDebugger* _activeDebugger;
|
static struct ARMDebugger* _activeDebugger;
|
||||||
|
@ -45,6 +42,7 @@ static void _readByte(struct ARMDebugger*, struct DebugVector*);
|
||||||
static void _readHalfword(struct ARMDebugger*, struct DebugVector*);
|
static void _readHalfword(struct ARMDebugger*, struct DebugVector*);
|
||||||
static void _readWord(struct ARMDebugger*, struct DebugVector*);
|
static void _readWord(struct ARMDebugger*, struct DebugVector*);
|
||||||
static void _setBreakpoint(struct ARMDebugger*, struct DebugVector*);
|
static void _setBreakpoint(struct ARMDebugger*, struct DebugVector*);
|
||||||
|
static void _setWatchpoint(struct ARMDebugger*, struct DebugVector*);
|
||||||
|
|
||||||
static void _breakIntoDefault(int signal);
|
static void _breakIntoDefault(int signal);
|
||||||
|
|
||||||
|
@ -70,6 +68,8 @@ struct {
|
||||||
{ "rw", _readWord },
|
{ "rw", _readWord },
|
||||||
{ "status", _printStatus },
|
{ "status", _printStatus },
|
||||||
{ "x", _breakInto },
|
{ "x", _breakInto },
|
||||||
|
{ "w", _setWatchpoint },
|
||||||
|
{ "watch", _setWatchpoint },
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -203,6 +203,21 @@ static void _setBreakpoint(struct ARMDebugger* debugger, struct DebugVector* dv)
|
||||||
debugger->breakpoints = breakpoint;
|
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) {
|
static void _checkBreakpoints(struct ARMDebugger* debugger) {
|
||||||
struct DebugBreakpoint* breakpoint;
|
struct DebugBreakpoint* breakpoint;
|
||||||
int instructionLength;
|
int instructionLength;
|
||||||
|
@ -532,6 +547,8 @@ void ARMDebuggerInit(struct ARMDebugger* debugger, struct ARMCore* cpu) {
|
||||||
debugger->state = DEBUGGER_PAUSED;
|
debugger->state = DEBUGGER_PAUSED;
|
||||||
debugger->lastCommand = 0;
|
debugger->lastCommand = 0;
|
||||||
debugger->breakpoints = 0;
|
debugger->breakpoints = 0;
|
||||||
|
debugger->memoryShim.p = debugger;
|
||||||
|
debugger->memoryShim.watchpoints = 0;
|
||||||
_activeDebugger = debugger;
|
_activeDebugger = debugger;
|
||||||
signal(SIGINT, _breakIntoDefault);
|
signal(SIGINT, _breakIntoDefault);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,34 @@
|
||||||
#ifndef DEBUGGER_H
|
#ifndef DEBUGGER_H
|
||||||
#define DEBUGGER_H
|
#define DEBUGGER_H
|
||||||
|
|
||||||
|
#include "arm.h"
|
||||||
|
|
||||||
enum DebuggerState {
|
enum DebuggerState {
|
||||||
DEBUGGER_PAUSED,
|
DEBUGGER_PAUSED,
|
||||||
DEBUGGER_RUNNING,
|
DEBUGGER_RUNNING,
|
||||||
DEBUGGER_EXITING
|
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 {
|
struct ARMDebugger {
|
||||||
enum DebuggerState state;
|
enum DebuggerState state;
|
||||||
struct ARMCore* cpu;
|
struct ARMCore* cpu;
|
||||||
|
|
||||||
char* lastCommand;
|
char* lastCommand;
|
||||||
struct DebugBreakpoint* breakpoints;
|
struct DebugBreakpoint* breakpoints;
|
||||||
|
struct DebugMemoryShim memoryShim;
|
||||||
};
|
};
|
||||||
|
|
||||||
void ARMDebuggerInit(struct ARMDebugger*, struct ARMCore*);
|
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