Debugger: Fix watchpoints

This commit is contained in:
Jeffrey Pfau 2016-01-12 17:43:09 -08:00
parent b6f1ddc4fe
commit 16ba5bd05f
6 changed files with 33 additions and 23 deletions

View File

@ -30,6 +30,7 @@ Bugfixes:
- GBA: Fix Iridion II savetype - GBA: Fix Iridion II savetype
- Libretro: Fix aspect ratio - Libretro: Fix aspect ratio
- Qt: Fix some potential crashes with the gamepad mapping - Qt: Fix some potential crashes with the gamepad mapping
- Debugger: Fix watchpoints in gdb
Misc: Misc:
- Qt: Window size command line options are now supported - Qt: Window size command line options are now supported
- Qt: Increase usability of key mapper - Qt: Increase usability of key mapper

View File

@ -536,7 +536,7 @@ static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector*
return; return;
} }
uint32_t address = dv->intValue; uint32_t address = dv->intValue;
ARMDebuggerSetWatchpoint(&debugger->d, address); ARMDebuggerSetWatchpoint(&debugger->d, address, WATCHPOINT_RW); // TODO: ro/wo
} }
static void _breakIntoDefault(int signal) { static void _breakIntoDefault(int signal) {

View File

@ -161,12 +161,13 @@ void ARMDebuggerClearBreakpoint(struct ARMDebugger* debugger, uint32_t address)
} }
} }
void ARMDebuggerSetWatchpoint(struct ARMDebugger* debugger, uint32_t address) { void ARMDebuggerSetWatchpoint(struct ARMDebugger* debugger, uint32_t address, enum WatchpointType type) {
if (!debugger->watchpoints) { if (!debugger->watchpoints) {
ARMDebuggerInstallMemoryShim(debugger); ARMDebuggerInstallMemoryShim(debugger);
} }
struct DebugWatchpoint* watchpoint = malloc(sizeof(struct DebugWatchpoint)); struct DebugWatchpoint* watchpoint = malloc(sizeof(struct DebugWatchpoint));
watchpoint->address = address; watchpoint->address = address;
watchpoint->type = type;
watchpoint->next = debugger->watchpoints; watchpoint->next = debugger->watchpoints;
debugger->watchpoints = watchpoint; debugger->watchpoints = watchpoint;
} }

View File

@ -32,7 +32,7 @@ struct DebugBreakpoint {
enum WatchpointType { enum WatchpointType {
WATCHPOINT_WRITE = 1, WATCHPOINT_WRITE = 1,
WATCHPOINT_READ = 2, WATCHPOINT_READ = 2,
WATCHPOINT_RW = 3 WATCHPOINT_RW = WATCHPOINT_WRITE | WATCHPOINT_READ
}; };
struct DebugWatchpoint { struct DebugWatchpoint {
@ -101,7 +101,7 @@ void ARMDebuggerEnter(struct ARMDebugger*, enum DebuggerEntryReason, struct Debu
void ARMDebuggerSetBreakpoint(struct ARMDebugger* debugger, uint32_t address); void ARMDebuggerSetBreakpoint(struct ARMDebugger* debugger, uint32_t address);
bool ARMDebuggerSetSoftwareBreakpoint(struct ARMDebugger* debugger, uint32_t address, enum ExecutionMode mode); bool ARMDebuggerSetSoftwareBreakpoint(struct ARMDebugger* debugger, uint32_t address, enum ExecutionMode mode);
void ARMDebuggerClearBreakpoint(struct ARMDebugger* debugger, uint32_t address); void ARMDebuggerClearBreakpoint(struct ARMDebugger* debugger, uint32_t address);
void ARMDebuggerSetWatchpoint(struct ARMDebugger* debugger, uint32_t address); void ARMDebuggerSetWatchpoint(struct ARMDebugger* debugger, uint32_t address, enum WatchpointType type);
void ARMDebuggerClearWatchpoint(struct ARMDebugger* debugger, uint32_t address); void ARMDebuggerClearWatchpoint(struct ARMDebugger* debugger, uint32_t address);
#endif #endif

View File

@ -40,9 +40,9 @@ static void _gdbStubEntered(struct ARMDebugger* debugger, enum DebuggerEntryReas
snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGINT); snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGINT);
break; break;
case DEBUGGER_ENTER_BREAKPOINT: case DEBUGGER_ENTER_BREAKPOINT:
snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGTRAP); snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGTRAP); // TODO: Use hwbreak/swbreak if gdb supports it
break; break;
case DEBUGGER_ENTER_WATCHPOINT: // TODO: Make watchpoints raise with address case DEBUGGER_ENTER_WATCHPOINT:
if (info) { if (info) {
const char* type = 0; const char* type = 0;
switch (info->watchType) { switch (info->watchType) {
@ -56,7 +56,7 @@ static void _gdbStubEntered(struct ARMDebugger* debugger, enum DebuggerEntryReas
type = "awatch"; type = "awatch";
break; break;
} }
snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "T%02x%s:%08X", SIGTRAP, type, info->address); snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "T%02x%s:%08x;", SIGTRAP, type, info->address);
} else { } else {
snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGTRAP); snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGTRAP);
} }
@ -317,9 +317,17 @@ static void _setBreakpoint(struct GDBStub* stub, const char* message) {
_sendMessage(stub); _sendMessage(stub);
break; break;
case '2': case '2':
ARMDebuggerSetWatchpoint(&stub->d, address, WATCHPOINT_WRITE);
strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
_sendMessage(stub);
break;
case '3': case '3':
ARMDebuggerSetWatchpoint(&stub->d, address, WATCHPOINT_READ);
strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
_sendMessage(stub);
break;
case '4': case '4':
ARMDebuggerSetWatchpoint(&stub->d, address); ARMDebuggerSetWatchpoint(&stub->d, address, WATCHPOINT_RW);
strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4); strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
_sendMessage(stub); _sendMessage(stub);
break; break;

View File

@ -11,7 +11,7 @@
#include <string.h> #include <string.h>
static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, struct DebuggerEntryInfo* info, int width); static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, struct DebuggerEntryInfo* info, enum WatchpointType type, int width);
#define FIND_DEBUGGER(DEBUGGER, CPU) \ #define FIND_DEBUGGER(DEBUGGER, CPU) \
{ \ { \
@ -32,18 +32,18 @@ static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, st
return debugger->originalMemory.NAME(cpu, __VA_ARGS__); \ return debugger->originalMemory.NAME(cpu, __VA_ARGS__); \
} }
#define CREATE_WATCHPOINT_SHIM(NAME, WIDTH, RETURN, TYPES, ...) \ #define CREATE_WATCHPOINT_SHIM(NAME, WIDTH, RETURN, TYPES, ACCESS_TYPE, ...) \
static RETURN ARMDebuggerShim_ ## NAME TYPES { \ static RETURN ARMDebuggerShim_ ## NAME TYPES { \
struct ARMDebugger* debugger; \ struct ARMDebugger* debugger; \
FIND_DEBUGGER(debugger, cpu); \ FIND_DEBUGGER(debugger, cpu); \
struct DebuggerEntryInfo info; \ struct DebuggerEntryInfo info; \
if (_checkWatchpoints(debugger, address, &info, WIDTH)) { \ if (_checkWatchpoints(debugger, address, &info, ACCESS_TYPE, WIDTH)) { \
ARMDebuggerEnter(debugger, DEBUGGER_ENTER_WATCHPOINT, &info); \ ARMDebuggerEnter(debugger, DEBUGGER_ENTER_WATCHPOINT, &info); \
} \ } \
return debugger->originalMemory.NAME(cpu, __VA_ARGS__); \ return debugger->originalMemory.NAME(cpu, __VA_ARGS__); \
} }
#define CREATE_MULTIPLE_WATCHPOINT_SHIM(NAME) \ #define CREATE_MULTIPLE_WATCHPOINT_SHIM(NAME, ACCESS_TYPE) \
static uint32_t ARMDebuggerShim_ ## NAME (struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) { \ static uint32_t ARMDebuggerShim_ ## NAME (struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) { \
struct ARMDebugger* debugger; \ struct ARMDebugger* debugger; \
FIND_DEBUGGER(debugger, cpu); \ FIND_DEBUGGER(debugger, cpu); \
@ -60,28 +60,28 @@ static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, st
unsigned i; \ unsigned i; \
for (i = 0; i < popcount; ++i) { \ for (i = 0; i < popcount; ++i) { \
struct DebuggerEntryInfo info; \ struct DebuggerEntryInfo info; \
if (_checkWatchpoints(debugger, base + 4 * i, &info, 4)) { \ if (_checkWatchpoints(debugger, base + 4 * i, &info, ACCESS_TYPE, 4)) { \
ARMDebuggerEnter(debugger, DEBUGGER_ENTER_WATCHPOINT, &info); \ ARMDebuggerEnter(debugger, DEBUGGER_ENTER_WATCHPOINT, &info); \
} \ } \
} \ } \
return debugger->originalMemory.NAME(cpu, address, mask, direction, cycleCounter); \ return debugger->originalMemory.NAME(cpu, address, mask, direction, cycleCounter); \
} }
CREATE_WATCHPOINT_SHIM(load32, 4, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), address, cycleCounter) CREATE_WATCHPOINT_SHIM(load32, 4, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), WATCHPOINT_READ, address, cycleCounter)
CREATE_WATCHPOINT_SHIM(load16, 2, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), address, cycleCounter) CREATE_WATCHPOINT_SHIM(load16, 2, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), WATCHPOINT_READ, address, cycleCounter)
CREATE_WATCHPOINT_SHIM(load8, 1, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), address, cycleCounter) CREATE_WATCHPOINT_SHIM(load8, 1, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), WATCHPOINT_READ, address, cycleCounter)
CREATE_WATCHPOINT_SHIM(store32, 4, void, (struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter), address, value, cycleCounter) CREATE_WATCHPOINT_SHIM(store32, 4, void, (struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter), WATCHPOINT_WRITE, address, value, cycleCounter)
CREATE_WATCHPOINT_SHIM(store16, 2, void, (struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter), address, value, cycleCounter) CREATE_WATCHPOINT_SHIM(store16, 2, void, (struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter), WATCHPOINT_WRITE, address, value, cycleCounter)
CREATE_WATCHPOINT_SHIM(store8, 1, void, (struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter), address, value, cycleCounter) CREATE_WATCHPOINT_SHIM(store8, 1, void, (struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter), WATCHPOINT_WRITE, address, value, cycleCounter)
CREATE_MULTIPLE_WATCHPOINT_SHIM(loadMultiple) CREATE_MULTIPLE_WATCHPOINT_SHIM(loadMultiple, WATCHPOINT_READ)
CREATE_MULTIPLE_WATCHPOINT_SHIM(storeMultiple) CREATE_MULTIPLE_WATCHPOINT_SHIM(storeMultiple, WATCHPOINT_WRITE)
CREATE_SHIM(setActiveRegion, void, (struct ARMCore* cpu, uint32_t address), address) CREATE_SHIM(setActiveRegion, void, (struct ARMCore* cpu, uint32_t address), address)
static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, struct DebuggerEntryInfo* info, int width) { static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, struct DebuggerEntryInfo* info, enum WatchpointType type, int width) {
--width; --width;
struct DebugWatchpoint* watchpoints; struct DebugWatchpoint* watchpoints;
for (watchpoints = debugger->watchpoints; watchpoints; watchpoints = watchpoints->next) { for (watchpoints = debugger->watchpoints; watchpoints; watchpoints = watchpoints->next) {
if (!((watchpoints->address ^ address) & ~width)) { if (!((watchpoints->address ^ address) & ~width) && watchpoints->type & type) {
switch (width + 1) { switch (width + 1) {
case 1: case 1:
info->oldValue = debugger->originalMemory.load8(debugger->cpu, address, 0); info->oldValue = debugger->originalMemory.load8(debugger->cpu, address, 0);