Debugger: Revamp breakpoint/watchpoint API, add listing

This commit is contained in:
Vicki Pfau 2019-01-31 22:52:27 -08:00
parent 0eaa9e487f
commit 0c9802e4da
11 changed files with 361 additions and 275 deletions

View File

@ -12,6 +12,7 @@ Misc:
- GB Memory: Support running from blocked memory
- Qt: Don't unload ROM immediately if it crashes
- GBA Video: Improve sprite cycle counting (fixes mgba.io/i/1274)
- Debugger: Add breakpoint and watchpoint listing
0.7.0: (2019-01-26)
Features:

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2013-2017 Jeffrey Pfau
/* Copyright (c) 2013-2019 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
@ -12,6 +12,7 @@ CXX_GUARD_START
#include <mgba/core/cpu.h>
#include <mgba/core/log.h>
#include <mgba-util/vector.h>
mLOG_DECLARE_CATEGORY(DEBUGGER);
@ -36,7 +37,8 @@ enum mDebuggerState {
enum mWatchpointType {
WATCHPOINT_WRITE = 1,
WATCHPOINT_READ = 2,
WATCHPOINT_RW = 3
WATCHPOINT_RW = 3,
WATCHPOINT_WRITE_CHANGE = 4,
};
enum mBreakpointType {
@ -69,6 +71,25 @@ struct mDebuggerEntryInfo {
} type;
};
struct mBreakpoint {
ssize_t id;
uint32_t address;
int segment;
enum mBreakpointType type;
struct ParseTree* condition;
};
struct mWatchpoint {
ssize_t id;
uint32_t address;
int segment;
enum mWatchpointType type;
struct ParseTree* condition;
};
DECLARE_VECTOR(mBreakpointList, struct mBreakpoint);
DECLARE_VECTOR(mWatchpointList, struct mWatchpoint);
struct mDebugger;
struct ParseTree;
struct mDebuggerPlatform {
@ -79,13 +100,15 @@ struct mDebuggerPlatform {
void (*entered)(struct mDebuggerPlatform*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*);
bool (*hasBreakpoints)(struct mDebuggerPlatform*);
void (*setBreakpoint)(struct mDebuggerPlatform*, uint32_t address, int segment);
void (*setConditionalBreakpoint)(struct mDebuggerPlatform*, uint32_t address, int segment, struct ParseTree* condition);
void (*clearBreakpoint)(struct mDebuggerPlatform*, uint32_t address, int segment);
void (*setWatchpoint)(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type);
void (*setConditionalWatchpoint)(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type, struct ParseTree* condition);
void (*clearWatchpoint)(struct mDebuggerPlatform*, uint32_t address, int segment);
void (*checkBreakpoints)(struct mDebuggerPlatform*);
bool (*clearBreakpoint)(struct mDebuggerPlatform*, ssize_t id);
ssize_t (*setBreakpoint)(struct mDebuggerPlatform*, const struct mBreakpoint*);
void (*listBreakpoints)(struct mDebuggerPlatform*, struct mBreakpointList*);
ssize_t (*setWatchpoint)(struct mDebuggerPlatform*, const struct mWatchpoint*);
void (*listWatchpoints)(struct mDebuggerPlatform*, struct mWatchpointList*);
void (*trace)(struct mDebuggerPlatform*, char* out, size_t* length);
bool (*getRegister)(struct mDebuggerPlatform*, const char* name, int32_t* value);

View File

@ -17,23 +17,14 @@ CXX_GUARD_START
struct ParseTree;
struct ARMDebugBreakpoint {
uint32_t address;
struct ParseTree* condition;
bool isSw;
struct mBreakpoint d;
struct {
uint32_t opcode;
enum ExecutionMode mode;
} sw;
};
struct ARMDebugWatchpoint {
uint32_t address;
enum mWatchpointType type;
struct ParseTree* condition;
};
DECLARE_VECTOR(ARMDebugBreakpointList, struct ARMDebugBreakpoint);
DECLARE_VECTOR(ARMDebugWatchpointList, struct ARMDebugWatchpoint);
struct ARMDebugger {
struct mDebuggerPlatform d;
@ -41,18 +32,19 @@ struct ARMDebugger {
struct ARMDebugBreakpointList breakpoints;
struct ARMDebugBreakpointList swBreakpoints;
struct ARMDebugWatchpointList watchpoints;
struct mWatchpointList watchpoints;
struct ARMMemory originalMemory;
ssize_t nextId;
void (*entered)(struct mDebugger*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*);
bool (*setSoftwareBreakpoint)(struct ARMDebugger*, uint32_t address, enum ExecutionMode mode, uint32_t* opcode);
bool (*clearSoftwareBreakpoint)(struct ARMDebugger*, uint32_t address, enum ExecutionMode mode, uint32_t opcode);
ssize_t (*setSoftwareBreakpoint)(struct ARMDebugger*, uint32_t address, enum ExecutionMode mode, uint32_t* opcode);
void (*clearSoftwareBreakpoint)(struct ARMDebugger*, const struct ARMDebugBreakpoint*);
};
struct mDebuggerPlatform* ARMDebuggerPlatformCreate(void);
bool ARMDebuggerSetSoftwareBreakpoint(struct mDebuggerPlatform* debugger, uint32_t address, enum ExecutionMode mode);
void ARMDebuggerClearSoftwareBreakpoint(struct mDebuggerPlatform* debugger, uint32_t address);
ssize_t ARMDebuggerSetSoftwareBreakpoint(struct mDebuggerPlatform* debugger, uint32_t address, enum ExecutionMode mode);
CXX_GUARD_END

View File

@ -13,21 +13,6 @@ CXX_GUARD_START
#include <mgba/debugger/debugger.h>
#include <mgba/internal/lr35902/lr35902.h>
#include <mgba-util/vector.h>
struct ParseTree;
struct LR35902DebugBreakpoint {
uint16_t address;
int segment;
struct ParseTree* condition;
};
struct LR35902DebugWatchpoint {
uint16_t address;
int segment;
enum mWatchpointType type;
struct ParseTree* condition;
};
struct LR35902Segment {
uint16_t start;
@ -35,17 +20,16 @@ struct LR35902Segment {
const char* name;
};
DECLARE_VECTOR(LR35902DebugBreakpointList, struct LR35902DebugBreakpoint);
DECLARE_VECTOR(LR35902DebugWatchpointList, struct LR35902DebugWatchpoint);
struct LR35902Debugger {
struct mDebuggerPlatform d;
struct LR35902Core* cpu;
struct LR35902DebugBreakpointList breakpoints;
struct LR35902DebugWatchpointList watchpoints;
struct mBreakpointList breakpoints;
struct mWatchpointList watchpoints;
struct LR35902Memory originalMemory;
ssize_t nextId;
const struct LR35902Segment* segments;
};

View File

@ -13,12 +13,11 @@
#include <mgba/internal/debugger/parser.h>
DEFINE_VECTOR(ARMDebugBreakpointList, struct ARMDebugBreakpoint);
DEFINE_VECTOR(ARMDebugWatchpointList, struct ARMDebugWatchpoint);
static struct ARMDebugBreakpoint* _lookupBreakpoint(struct ARMDebugBreakpointList* breakpoints, uint32_t address) {
size_t i;
for (i = 0; i < ARMDebugBreakpointListSize(breakpoints); ++i) {
if (ARMDebugBreakpointListGetPointer(breakpoints, i)->address == address) {
if (ARMDebugBreakpointListGetPointer(breakpoints, i)->d.address == address) {
return ARMDebugBreakpointListGetPointer(breakpoints, i);
}
}
@ -26,13 +25,13 @@ static struct ARMDebugBreakpoint* _lookupBreakpoint(struct ARMDebugBreakpointLis
}
static void _destroyBreakpoint(struct ARMDebugBreakpoint* breakpoint) {
if (breakpoint->condition) {
parseFree(breakpoint->condition);
free(breakpoint->condition);
if (breakpoint->d.condition) {
parseFree(breakpoint->d.condition);
free(breakpoint->d.condition);
}
}
static void _destroyWatchpoint(struct ARMDebugWatchpoint* watchpoint) {
static void _destroyWatchpoint(struct mWatchpoint* watchpoint) {
if (watchpoint->condition) {
parseFree(watchpoint->condition);
free(watchpoint->condition);
@ -52,15 +51,15 @@ static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform* d) {
if (!breakpoint) {
return;
}
if (breakpoint->condition) {
if (breakpoint->d.condition) {
int32_t value;
int segment;
if (!mDebuggerEvaluateParseTree(d->p, breakpoint->condition, &value, &segment) || !(value || segment >= 0)) {
if (!mDebuggerEvaluateParseTree(d->p, breakpoint->d.condition, &value, &segment) || !(value || segment >= 0)) {
return;
}
}
struct mDebuggerEntryInfo info = {
.address = breakpoint->address,
.address = breakpoint->d.address,
.type.bp.breakType = BREAKPOINT_HARDWARE
};
mDebuggerEnter(d->p, DEBUGGER_ENTER_BREAKPOINT, &info);
@ -71,12 +70,11 @@ static void ARMDebuggerDeinit(struct mDebuggerPlatform* platform);
static void ARMDebuggerEnter(struct mDebuggerPlatform* d, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info);
static void ARMDebuggerSetBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
static void ARMDebuggerSetConditionalBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment, struct ParseTree* condition);
static void ARMDebuggerClearBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type);
static void ARMDebuggerSetConditionalWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type, struct ParseTree* condition);
static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
static ssize_t ARMDebuggerSetBreakpoint(struct mDebuggerPlatform*, const struct mBreakpoint*);
static bool ARMDebuggerClearBreakpoint(struct mDebuggerPlatform*, ssize_t id);
static void ARMDebuggerListBreakpoints(struct mDebuggerPlatform*, struct mBreakpointList*);
static ssize_t ARMDebuggerSetWatchpoint(struct mDebuggerPlatform*, const struct mWatchpoint*);
static void ARMDebuggerListWatchpoints(struct mDebuggerPlatform*, struct mWatchpointList*);
static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform*);
static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform*);
static void ARMDebuggerTrace(struct mDebuggerPlatform*, char* out, size_t* length);
@ -89,11 +87,10 @@ struct mDebuggerPlatform* ARMDebuggerPlatformCreate(void) {
platform->init = ARMDebuggerInit;
platform->deinit = ARMDebuggerDeinit;
platform->setBreakpoint = ARMDebuggerSetBreakpoint;
platform->setConditionalBreakpoint = ARMDebuggerSetConditionalBreakpoint;
platform->listBreakpoints = ARMDebuggerListBreakpoints;
platform->clearBreakpoint = ARMDebuggerClearBreakpoint;
platform->setWatchpoint = ARMDebuggerSetWatchpoint;
platform->setConditionalWatchpoint = ARMDebuggerSetConditionalWatchpoint;
platform->clearWatchpoint = ARMDebuggerClearWatchpoint;
platform->listWatchpoints = ARMDebuggerListWatchpoints;
platform->checkBreakpoints = ARMDebuggerCheckBreakpoints;
platform->hasBreakpoints = ARMDebuggerHasBreakpoints;
platform->trace = ARMDebuggerTrace;
@ -106,9 +103,10 @@ void ARMDebuggerInit(void* cpu, struct mDebuggerPlatform* platform) {
struct ARMDebugger* debugger = (struct ARMDebugger*) platform;
debugger->cpu = cpu;
debugger->originalMemory = debugger->cpu->memory;
debugger->nextId = 1;
ARMDebugBreakpointListInit(&debugger->breakpoints, 0);
ARMDebugBreakpointListInit(&debugger->swBreakpoints, 0);
ARMDebugWatchpointListInit(&debugger->watchpoints, 0);
mWatchpointListInit(&debugger->watchpoints, 0);
}
void ARMDebuggerDeinit(struct mDebuggerPlatform* platform) {
@ -118,7 +116,7 @@ void ARMDebuggerDeinit(struct mDebuggerPlatform* platform) {
size_t b;
for (b = ARMDebugBreakpointListSize(&debugger->swBreakpoints); b; --b) {
struct ARMDebugBreakpoint* breakpoint = ARMDebugBreakpointListGetPointer(&debugger->swBreakpoints, b - 1);
debugger->clearSoftwareBreakpoint(debugger, breakpoint->address, breakpoint->sw.mode, breakpoint->sw.opcode);
debugger->clearSoftwareBreakpoint(debugger, breakpoint);
}
}
ARMDebuggerRemoveMemoryShim(debugger);
@ -129,11 +127,11 @@ void ARMDebuggerDeinit(struct mDebuggerPlatform* platform) {
}
ARMDebugBreakpointListDeinit(&debugger->breakpoints);
for (i = 0; i < ARMDebugWatchpointListSize(&debugger->watchpoints); ++i) {
_destroyWatchpoint(ARMDebugWatchpointListGetPointer(&debugger->watchpoints, i));
for (i = 0; i < mWatchpointListSize(&debugger->watchpoints); ++i) {
_destroyWatchpoint(mWatchpointListGetPointer(&debugger->watchpoints, i));
}
ARMDebugBreakpointListDeinit(&debugger->swBreakpoints);
ARMDebugWatchpointListDeinit(&debugger->watchpoints);
mWatchpointListDeinit(&debugger->watchpoints);
}
static void ARMDebuggerEnter(struct mDebuggerPlatform* platform, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
@ -142,16 +140,16 @@ static void ARMDebuggerEnter(struct mDebuggerPlatform* platform, enum mDebuggerE
cpu->nextEvent = cpu->cycles;
if (reason == DEBUGGER_ENTER_BREAKPOINT) {
struct ARMDebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->swBreakpoints, _ARMPCAddress(cpu));
if (breakpoint && breakpoint->isSw) {
info->address = breakpoint->address;
if (breakpoint && breakpoint->d.type == BREAKPOINT_SOFTWARE) {
info->address = breakpoint->d.address;
if (debugger->clearSoftwareBreakpoint) {
debugger->clearSoftwareBreakpoint(debugger, breakpoint->address, breakpoint->sw.mode, breakpoint->sw.opcode);
debugger->clearSoftwareBreakpoint(debugger, breakpoint);
}
ARMRunFake(cpu, breakpoint->sw.opcode);
if (debugger->setSoftwareBreakpoint) {
debugger->setSoftwareBreakpoint(debugger, breakpoint->address, breakpoint->sw.mode, &breakpoint->sw.opcode);
debugger->setSoftwareBreakpoint(debugger, breakpoint->d.address, breakpoint->sw.mode, &breakpoint->sw.opcode);
}
}
}
@ -160,105 +158,135 @@ static void ARMDebuggerEnter(struct mDebuggerPlatform* platform, enum mDebuggerE
}
}
bool ARMDebuggerSetSoftwareBreakpoint(struct mDebuggerPlatform* d, uint32_t address, enum ExecutionMode mode) {
ssize_t ARMDebuggerSetSoftwareBreakpoint(struct mDebuggerPlatform* d, uint32_t address, enum ExecutionMode mode) {
struct ARMDebugger* debugger = (struct ARMDebugger*) d;
uint32_t opcode;
if (!debugger->setSoftwareBreakpoint || !debugger->setSoftwareBreakpoint(debugger, address, mode, &opcode)) {
return false;
return -1;
}
struct ARMDebugBreakpoint* breakpoint = ARMDebugBreakpointListAppend(&debugger->swBreakpoints);
breakpoint->address = address;
breakpoint->isSw = true;
ssize_t id = debugger->nextId;
++debugger->nextId;
breakpoint->d.id = id;
breakpoint->d.address = address;
breakpoint->d.segment = -1;
breakpoint->d.condition = NULL;
breakpoint->d.type = BREAKPOINT_SOFTWARE;
breakpoint->sw.opcode = opcode;
breakpoint->sw.mode = mode;
return true;
return id;
}
void ARMDebuggerClearSoftwareBreakpoint(struct mDebuggerPlatform* d, uint32_t address) {
struct ARMDebugger* debugger = (struct ARMDebugger*) d;
if (!debugger->clearSoftwareBreakpoint) {
return;
}
struct ARMDebugBreakpoint* breakpoint = NULL;
// Clear the stack backwards in case any overlap
size_t b;
for (b = ARMDebugBreakpointListSize(&debugger->swBreakpoints); b; --b) {
breakpoint = ARMDebugBreakpointListGetPointer(&debugger->swBreakpoints, b - 1);
if (breakpoint->address == address) {
break;
}
breakpoint = NULL;
}
if (breakpoint) {
debugger->clearSoftwareBreakpoint(debugger, address, breakpoint->sw.mode, breakpoint->sw.opcode);
}
}
static void ARMDebuggerSetBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
ARMDebuggerSetConditionalBreakpoint(d, address, segment, NULL);
}
static void ARMDebuggerSetConditionalBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, struct ParseTree* condition) {
UNUSED(segment);
static ssize_t ARMDebuggerSetBreakpoint(struct mDebuggerPlatform* d, const struct mBreakpoint* info) {
struct ARMDebugger* debugger = (struct ARMDebugger*) d;
struct ARMDebugBreakpoint* breakpoint = ARMDebugBreakpointListAppend(&debugger->breakpoints);
breakpoint->condition = condition;
breakpoint->address = address;
breakpoint->isSw = false;
ssize_t id = debugger->nextId;
++debugger->nextId;
breakpoint->d = *info;
breakpoint->d.id = id;
if (info->type == BREAKPOINT_SOFTWARE) {
// TODO
abort();
}
return id;
}
static void ARMDebuggerClearBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
UNUSED(segment);
static bool ARMDebuggerClearBreakpoint(struct mDebuggerPlatform* d, ssize_t id) {
struct ARMDebugger* debugger = (struct ARMDebugger*) d;
struct ARMDebugBreakpointList* breakpoints = &debugger->breakpoints;
size_t i;
struct ARMDebugBreakpointList* breakpoints = &debugger->breakpoints;
for (i = 0; i < ARMDebugBreakpointListSize(breakpoints); ++i) {
if (ARMDebugBreakpointListGetPointer(breakpoints, i)->address == address) {
if (ARMDebugBreakpointListGetPointer(breakpoints, i)->d.id == id) {
_destroyBreakpoint(ARMDebugBreakpointListGetPointer(breakpoints, i));
ARMDebugBreakpointListShift(breakpoints, i, 1);
return true;
}
}
struct ARMDebugBreakpointList* swBreakpoints = &debugger->swBreakpoints;
if (debugger->clearSoftwareBreakpoint) {
for (i = 0; i < ARMDebugBreakpointListSize(swBreakpoints); ++i) {
if (ARMDebugBreakpointListGetPointer(swBreakpoints, i)->d.id == id) {
debugger->clearSoftwareBreakpoint(debugger, ARMDebugBreakpointListGetPointer(swBreakpoints, i));
ARMDebugBreakpointListShift(swBreakpoints, i, 1);
return true;
}
}
}
struct mWatchpointList* watchpoints = &debugger->watchpoints;
for (i = 0; i < mWatchpointListSize(watchpoints); ++i) {
if (mWatchpointListGetPointer(watchpoints, i)->id == id) {
_destroyWatchpoint(mWatchpointListGetPointer(watchpoints, i));
mWatchpointListShift(watchpoints, i, 1);
if (!mWatchpointListSize(&debugger->watchpoints)) {
ARMDebuggerRemoveMemoryShim(debugger);
}
return true;
}
}
return false;
}
static void ARMDebuggerListBreakpoints(struct mDebuggerPlatform* d, struct mBreakpointList* list) {
struct ARMDebugger* debugger = (struct ARMDebugger*) d;
mBreakpointListClear(list);
size_t i, s;
for (i = 0, s = 0; i < ARMDebugBreakpointListSize(&debugger->breakpoints) || s < ARMDebugBreakpointListSize(&debugger->swBreakpoints);) {
struct ARMDebugBreakpoint* hw = NULL;
struct ARMDebugBreakpoint* sw = NULL;
if (i < ARMDebugBreakpointListSize(&debugger->breakpoints)) {
hw = ARMDebugBreakpointListGetPointer(&debugger->breakpoints, i);
}
if (s < ARMDebugBreakpointListSize(&debugger->swBreakpoints)) {
sw = ARMDebugBreakpointListGetPointer(&debugger->swBreakpoints, s);
}
struct mBreakpoint* b = mBreakpointListAppend(list);
if (hw && sw) {
if (hw->d.id < sw->d.id) {
*b = hw->d;
++i;
} else {
*b = sw->d;
++s;
}
} else if (hw) {
*b = hw->d;
++i;
} else if (sw) {
*b = sw->d;
++s;
} else {
abort(); // Should be unreachable
}
}
}
static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform* d) {
struct ARMDebugger* debugger = (struct ARMDebugger*) d;
return ARMDebugBreakpointListSize(&debugger->breakpoints) || ARMDebugWatchpointListSize(&debugger->watchpoints);
return ARMDebugBreakpointListSize(&debugger->breakpoints) || mWatchpointListSize(&debugger->watchpoints);
}
static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, enum mWatchpointType type) {
ARMDebuggerSetConditionalWatchpoint(d, address, segment, type, NULL);
}
static void ARMDebuggerSetConditionalWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, enum mWatchpointType type, struct ParseTree* condition) {
UNUSED(segment);
static ssize_t ARMDebuggerSetWatchpoint(struct mDebuggerPlatform* d, const struct mWatchpoint* info) {
struct ARMDebugger* debugger = (struct ARMDebugger*) d;
if (!ARMDebugWatchpointListSize(&debugger->watchpoints)) {
if (!mWatchpointListSize(&debugger->watchpoints)) {
ARMDebuggerInstallMemoryShim(debugger);
}
struct ARMDebugWatchpoint* watchpoint = ARMDebugWatchpointListAppend(&debugger->watchpoints);
watchpoint->address = address;
watchpoint->type = type;
watchpoint->condition = condition;
struct mWatchpoint* watchpoint = mWatchpointListAppend(&debugger->watchpoints);
ssize_t id = debugger->nextId;
++debugger->nextId;
*watchpoint = *info;
watchpoint->id = id;
return id;
}
static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
UNUSED(segment);
static void ARMDebuggerListWatchpoints(struct mDebuggerPlatform* d, struct mWatchpointList* list) {
struct ARMDebugger* debugger = (struct ARMDebugger*) d;
struct ARMDebugWatchpointList* watchpoints = &debugger->watchpoints;
size_t i;
for (i = 0; i < ARMDebugWatchpointListSize(watchpoints); ++i) {
if (ARMDebugWatchpointListGetPointer(watchpoints, i)->address == address) {
_destroyWatchpoint(ARMDebugWatchpointListGetPointer(watchpoints, i));
ARMDebugWatchpointListShift(watchpoints, i, 1);
}
}
if (!ARMDebugWatchpointListSize(&debugger->watchpoints)) {
ARMDebuggerRemoveMemoryShim(debugger);
}
mWatchpointListClear(list);
mWatchpointListCopy(list, &debugger->watchpoints);
}
static void ARMDebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* length) {

View File

@ -93,10 +93,10 @@ CREATE_SHIM(setActiveRegion, void, (struct ARMCore* cpu, uint32_t address), addr
static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, struct mDebuggerEntryInfo* info, enum mWatchpointType type, uint32_t newValue, int width) {
--width;
struct ARMDebugWatchpoint* watchpoint;
struct mWatchpoint* watchpoint;
size_t i;
for (i = 0; i < ARMDebugWatchpointListSize(&debugger->watchpoints); ++i) {
watchpoint = ARMDebugWatchpointListGetPointer(&debugger->watchpoints, i);
for (i = 0; i < mWatchpointListSize(&debugger->watchpoints); ++i) {
watchpoint = mWatchpointListGetPointer(&debugger->watchpoints, i);
if (!((watchpoint->address ^ address) & ~width) && watchpoint->type & type) {
if (watchpoint->condition) {
int32_t value;

View File

@ -46,9 +46,12 @@ static void _readHalfword(struct CLIDebugger*, struct CLIDebugVector*);
static void _readWord(struct CLIDebugger*, struct CLIDebugVector*);
static void _setBreakpoint(struct CLIDebugger*, struct CLIDebugVector*);
static void _clearBreakpoint(struct CLIDebugger*, struct CLIDebugVector*);
static void _setWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
static void _listBreakpoints(struct CLIDebugger*, struct CLIDebugVector*);
static void _setReadWriteWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
static void _setReadWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
static void _setWriteWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
static void _setWriteChangedWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
static void _listWatchpoints(struct CLIDebugger*, struct CLIDebugVector*);
static void _trace(struct CLIDebugger*, struct CLIDebugVector*);
static void _writeByte(struct CLIDebugger*, struct CLIDebugVector*);
static void _writeHalfword(struct CLIDebugger*, struct CLIDebugVector*);
@ -75,6 +78,10 @@ static struct CLIDebuggerCommandSummary _debuggerCommands[] = {
{ "help", _printHelp, "S", "Print help" },
{ "i", _printStatus, "", "Print the current status" },
{ "info", _printStatus, "", "Print the current status" },
{ "lb", _listBreakpoints, "", "List breakpoints" },
{ "listb", _listBreakpoints, "", "List breakpoints" },
{ "lw", _listWatchpoints, "", "List watchpoints" },
{ "listw", _listWatchpoints, "", "List watchpoints" },
{ "n", _next, "", "Execute next instruction" },
{ "next", _next, "", "Execute next instruction" },
{ "p", _print, "I", "Print a value" },
@ -91,12 +98,13 @@ static struct CLIDebuggerCommandSummary _debuggerCommands[] = {
{ "r/4", _readWord, "I", "Read a word from a specified offset" },
{ "status", _printStatus, "", "Print the current status" },
{ "trace", _trace, "I", "Trace a fixed number of instructions" },
{ "w", _setWatchpoint, "Is", "Set a watchpoint" },
{ "w", _setReadWriteWatchpoint, "Is", "Set a watchpoint" },
{ "w/1", _writeByte, "II", "Write a byte at a specified offset" },
{ "w/2", _writeHalfword, "II", "Write a halfword at a specified offset" },
{ "w/r", _writeRegister, "SI", "Write a register" },
{ "w/4", _writeWord, "II", "Write a word at a specified offset" },
{ "watch", _setWatchpoint, "Is", "Set a watchpoint" },
{ "watch", _setReadWriteWatchpoint, "Is", "Set a watchpoint" },
{ "watch/c", _setWriteChangedWatchpoint, "Is", "Set a change watchpoint" },
{ "watch/r", _setReadWatchpoint, "Is", "Set a read watchpoint" },
{ "watch/w", _setWriteWatchpoint, "Is", "Set a write watchpoint" },
{ "x/1", _dumpByte, "Ii", "Examine bytes at a specified offset" },
@ -488,20 +496,24 @@ static void _setBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector*
debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
return;
}
uint32_t address = dv->intValue;
struct mBreakpoint breakpoint = {
.address = dv->intValue,
.segment = dv->segmentValue,
.type = BREAKPOINT_HARDWARE
};
if (dv->next && dv->next->type == CLIDV_CHAR_TYPE) {
struct ParseTree* tree = _parseTree(dv->next->charValue);
if (tree) {
debugger->d.platform->setConditionalBreakpoint(debugger->d.platform, address, dv->segmentValue, tree);
breakpoint.condition = tree;
} else {
debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
return;
}
} else {
debugger->d.platform->setBreakpoint(debugger->d.platform, address, dv->segmentValue);
}
debugger->d.platform->setBreakpoint(debugger->d.platform, &breakpoint);
}
static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv, enum mWatchpointType type) {
if (!dv || dv->type != CLIDV_INT_TYPE) {
debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
return;
@ -510,72 +522,80 @@ static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector*
debugger->backend->printf(debugger->backend, "Watchpoints are not supported by this platform.\n");
return;
}
uint32_t address = dv->intValue;
struct mWatchpoint watchpoint = {
.address = dv->intValue,
.segment = dv->segmentValue,
.type = type
};
if (dv->next && dv->next->type == CLIDV_CHAR_TYPE) {
struct ParseTree* tree = _parseTree(dv->next->charValue);
if (tree) {
debugger->d.platform->setConditionalWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_RW, tree);
watchpoint.condition = tree;
} else {
debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
return;
}
} else {
debugger->d.platform->setWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_RW);
}
debugger->d.platform->setWatchpoint(debugger->d.platform, &watchpoint);
}
static void _setReadWriteWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
_setWatchpoint(debugger, dv, WATCHPOINT_RW);
}
static void _setReadWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
if (!dv || dv->type != CLIDV_INT_TYPE) {
debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
return;
}
if (!debugger->d.platform->setWatchpoint) {
debugger->backend->printf(debugger->backend, "Watchpoints are not supported by this platform.\n");
return;
}
uint32_t address = dv->intValue;
if (dv->next && dv->next->type == CLIDV_CHAR_TYPE) {
struct ParseTree* tree = _parseTree(dv->next->charValue);
if (tree) {
debugger->d.platform->setConditionalWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_READ, tree);
} else {
debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
}
} else {
debugger->d.platform->setWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_READ);
}
_setWatchpoint(debugger, dv, WATCHPOINT_READ);
}
static void _setWriteWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
if (!dv || dv->type != CLIDV_INT_TYPE) {
debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
return;
}
if (!debugger->d.platform->setWatchpoint) {
debugger->backend->printf(debugger->backend, "Watchpoints are not supported by this platform.\n");
return;
}
uint32_t address = dv->intValue;
if (dv->next && dv->next->type == CLIDV_CHAR_TYPE) {
struct ParseTree* tree = _parseTree(dv->next->charValue);
if (tree) {
debugger->d.platform->setConditionalWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_WRITE, tree);
} else {
debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
}
} else {
debugger->d.platform->setWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_WRITE);
}}
_setWatchpoint(debugger, dv, WATCHPOINT_WRITE);
}
static void _setWriteChangedWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
_setWatchpoint(debugger, dv, WATCHPOINT_WRITE_CHANGE);
}
static void _clearBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
if (!dv || dv->type != CLIDV_INT_TYPE) {
debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
return;
}
uint32_t address = dv->intValue;
debugger->d.platform->clearBreakpoint(debugger->d.platform, address, dv->segmentValue);
if (debugger->d.platform->clearWatchpoint) {
debugger->d.platform->clearWatchpoint(debugger->d.platform, address, dv->segmentValue);
uint64_t id = dv->intValue;
debugger->d.platform->clearBreakpoint(debugger->d.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);
size_t i;
for (i = 0; i < mBreakpointListSize(&breakpoints); ++i) {
struct mBreakpoint* breakpoint = mBreakpointListGetPointer(&breakpoints, i);
if (breakpoint->segment >= 0) {
debugger->backend->printf(debugger->backend, "%" PRIz "i: %02X:%X\n", breakpoint->id, breakpoint->segment, breakpoint->address);
} else {
debugger->backend->printf(debugger->backend, "%" PRIz "i: 0x%X\n", breakpoint->id, breakpoint->address);
}
}
mBreakpointListDeinit(&breakpoints);
}
static void _listWatchpoints(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
UNUSED(dv);
struct mWatchpointList watchpoints;
mWatchpointListInit(&watchpoints, 0);
debugger->d.platform->listWatchpoints(debugger->d.platform, &watchpoints);
size_t i;
for (i = 0; i < mWatchpointListSize(&watchpoints); ++i) {
struct mWatchpoint* watchpoint = mWatchpointListGetPointer(&watchpoints, i);
if (watchpoint->segment >= 0) {
debugger->backend->printf(debugger->backend, "%" PRIz "i: %02X:%X\n", watchpoint->id, watchpoint->segment, watchpoint->address);
} else {
debugger->backend->printf(debugger->backend, "%" PRIz "i: 0x%X\n", watchpoint->id, watchpoint->address);
}
}
mWatchpointListDeinit(&watchpoints);
}
static void _trace(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {

View File

@ -22,6 +22,9 @@ const uint32_t DEBUGGER_ID = 0xDEADBEEF;
mLOG_DEFINE_CATEGORY(DEBUGGER, "Debugger", "core.debugger");
DEFINE_VECTOR(mBreakpointList, struct mBreakpoint);
DEFINE_VECTOR(mWatchpointList, struct mWatchpoint);
static void mDebuggerInit(void* cpu, struct mCPUComponent* component);
static void mDebuggerDeinit(struct mCPUComponent* component);

View File

@ -62,6 +62,8 @@ static void _gdbStubEntered(struct mDebugger* debugger, enum mDebuggerEntryReaso
}
return;
}
// Fall through
case WATCHPOINT_WRITE_CHANGE:
type = "watch";
break;
case WATCHPOINT_READ:
@ -488,21 +490,32 @@ static void _setBreakpoint(struct GDBStub* stub, const char* message) {
readAddress += i + 1;
uint32_t kind = _readHex(readAddress, &i);
struct mBreakpoint breakpoint = {
.address = address,
.type = BREAKPOINT_HARDWARE
};
struct mWatchpoint watchpoint = {
.address = address
};
switch (message[0]) {
case '0':
ARMDebuggerSetSoftwareBreakpoint(stub->d.platform, address, kind == 2 ? MODE_THUMB : MODE_ARM);
break;
case '1':
stub->d.platform->setBreakpoint(stub->d.platform, address, -1);
stub->d.platform->setBreakpoint(stub->d.platform, &breakpoint);
break;
case '2':
stub->d.platform->setWatchpoint(stub->d.platform, address, -1, WATCHPOINT_WRITE);
watchpoint.type = WATCHPOINT_WRITE_CHANGE;
stub->d.platform->setWatchpoint(stub->d.platform, &watchpoint);
break;
case '3':
stub->d.platform->setWatchpoint(stub->d.platform, address, -1, WATCHPOINT_READ);
watchpoint.type = WATCHPOINT_READ;
stub->d.platform->setWatchpoint(stub->d.platform, &watchpoint);
break;
case '4':
stub->d.platform->setWatchpoint(stub->d.platform, address, -1, WATCHPOINT_RW);
watchpoint.type = WATCHPOINT_RW;
stub->d.platform->setWatchpoint(stub->d.platform, &watchpoint);
break;
default:
stub->outgoing[0] = '\0';
@ -517,17 +530,35 @@ static void _clearBreakpoint(struct GDBStub* stub, const char* message) {
const char* readAddress = &message[2];
unsigned i = 0;
uint32_t address = _readHex(readAddress, &i);
struct mBreakpointList breakpoints;
struct mWatchpointList watchpoints;
size_t index;
switch (message[0]) {
case '0':
ARMDebuggerClearSoftwareBreakpoint(stub->d.platform, address);
break;
case '1':
stub->d.platform->clearBreakpoint(stub->d.platform, address, -1);
mBreakpointListInit(&breakpoints, 0);
stub->d.platform->listBreakpoints(stub->d.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);
}
mBreakpointListDeinit(&breakpoints);
break;
case '2':
case '3':
case '4':
stub->d.platform->clearWatchpoint(stub->d.platform, address, -1);
mWatchpointListInit(&watchpoints, 0);
stub->d.platform->listWatchpoints(stub->d.platform, &watchpoints);
for (index = 0; index < mWatchpointListSize(&watchpoints); ++index) {
if (mWatchpointListGetPointer(&watchpoints, index)->address != address) {
continue;
}
stub->d.platform->clearBreakpoint(stub->d.platform, mWatchpointListGetPointer(&watchpoints, index)->id);
}
mWatchpointListDeinit(&watchpoints);
break;
default:
break;

View File

@ -11,27 +11,28 @@
#include <mgba/internal/lr35902/lr35902.h>
#include <mgba/internal/lr35902/debugger/memory-debugger.h>
DEFINE_VECTOR(LR35902DebugBreakpointList, struct LR35902DebugBreakpoint);
DEFINE_VECTOR(LR35902DebugWatchpointList, struct LR35902DebugWatchpoint);
static struct LR35902DebugBreakpoint* _lookupBreakpoint(struct LR35902DebugBreakpointList* breakpoints, uint16_t address) {
static struct mBreakpoint* _lookupBreakpoint(struct mBreakpointList* breakpoints, struct LR35902Core* cpu) {
size_t i;
for (i = 0; i < LR35902DebugBreakpointListSize(breakpoints); ++i) {
if (LR35902DebugBreakpointListGetPointer(breakpoints, i)->address == address) {
return LR35902DebugBreakpointListGetPointer(breakpoints, i);
for (i = 0; i < mBreakpointListSize(breakpoints); ++i) {
struct mBreakpoint* breakpoint = mBreakpointListGetPointer(breakpoints, i);
if (breakpoint->address != cpu->pc) {
continue;
}
if (breakpoint->segment < 0 || breakpoint->segment == cpu->memory.currentSegment(cpu, breakpoint->address)) {
return breakpoint;
}
}
return 0;
return NULL;
}
static void _destroyBreakpoint(struct LR35902DebugBreakpoint* breakpoint) {
static void _destroyBreakpoint(struct mBreakpoint* breakpoint) {
if (breakpoint->condition) {
parseFree(breakpoint->condition);
free(breakpoint->condition);
}
}
static void _destroyWatchpoint(struct LR35902DebugWatchpoint* watchpoint) {
static void _destroyWatchpoint(struct mWatchpoint* watchpoint) {
if (watchpoint->condition) {
parseFree(watchpoint->condition);
free(watchpoint->condition);
@ -40,13 +41,10 @@ static void _destroyWatchpoint(struct LR35902DebugWatchpoint* watchpoint) {
static void LR35902DebuggerCheckBreakpoints(struct mDebuggerPlatform* d) {
struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
struct LR35902DebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->breakpoints, debugger->cpu->pc);
struct mBreakpoint* breakpoint = _lookupBreakpoint(&debugger->breakpoints, debugger->cpu);
if (!breakpoint) {
return;
}
if (breakpoint->segment >= 0 && debugger->cpu->memory.currentSegment(debugger->cpu, breakpoint->address) != breakpoint->segment) {
return;
}
if (breakpoint->condition) {
int32_t value;
int segment;
@ -65,12 +63,11 @@ static void LR35902DebuggerDeinit(struct mDebuggerPlatform* platform);
static void LR35902DebuggerEnter(struct mDebuggerPlatform* d, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info);
static void LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
static void LR35902DebuggerSetConditionalBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment, struct ParseTree* condition);
static void LR35902DebuggerClearBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
static void LR35902DebuggerSetWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type);
static void LR35902DebuggerSetConditionalWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type, struct ParseTree* condition);
static void LR35902DebuggerClearWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
static ssize_t LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform*, const struct mBreakpoint*);
static void LR35902DebuggerListBreakpoints(struct mDebuggerPlatform*, struct mBreakpointList*);
static bool LR35902DebuggerClearBreakpoint(struct mDebuggerPlatform*, ssize_t id);
static ssize_t LR35902DebuggerSetWatchpoint(struct mDebuggerPlatform*, const struct mWatchpoint*);
static void LR35902DebuggerListWatchpoints(struct mDebuggerPlatform*, struct mWatchpointList*);
static void LR35902DebuggerCheckBreakpoints(struct mDebuggerPlatform*);
static bool LR35902DebuggerHasBreakpoints(struct mDebuggerPlatform*);
static void LR35902DebuggerTrace(struct mDebuggerPlatform*, char* out, size_t* length);
@ -83,11 +80,10 @@ struct mDebuggerPlatform* LR35902DebuggerPlatformCreate(void) {
platform->init = LR35902DebuggerInit;
platform->deinit = LR35902DebuggerDeinit;
platform->setBreakpoint = LR35902DebuggerSetBreakpoint;
platform->setConditionalBreakpoint = LR35902DebuggerSetConditionalBreakpoint;
platform->listBreakpoints = LR35902DebuggerListBreakpoints;
platform->clearBreakpoint = LR35902DebuggerClearBreakpoint;
platform->setWatchpoint = LR35902DebuggerSetWatchpoint;
platform->setConditionalWatchpoint = LR35902DebuggerSetConditionalWatchpoint;
platform->clearWatchpoint = LR35902DebuggerClearWatchpoint;
platform->listWatchpoints = LR35902DebuggerListWatchpoints;
platform->checkBreakpoints = LR35902DebuggerCheckBreakpoints;
platform->hasBreakpoints = LR35902DebuggerHasBreakpoints;
platform->trace = LR35902DebuggerTrace;
@ -100,22 +96,23 @@ void LR35902DebuggerInit(void* cpu, struct mDebuggerPlatform* platform) {
struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform;
debugger->cpu = cpu;
debugger->originalMemory = debugger->cpu->memory;
LR35902DebugBreakpointListInit(&debugger->breakpoints, 0);
LR35902DebugWatchpointListInit(&debugger->watchpoints, 0);
mBreakpointListInit(&debugger->breakpoints, 0);
mWatchpointListInit(&debugger->watchpoints, 0);
debugger->nextId = 1;
}
void LR35902DebuggerDeinit(struct mDebuggerPlatform* platform) {
struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform;
size_t i;
for (i = 0; i < LR35902DebugBreakpointListSize(&debugger->breakpoints); ++i) {
_destroyBreakpoint(LR35902DebugBreakpointListGetPointer(&debugger->breakpoints, i));
for (i = 0; i < mBreakpointListSize(&debugger->breakpoints); ++i) {
_destroyBreakpoint(mBreakpointListGetPointer(&debugger->breakpoints, i));
}
LR35902DebugBreakpointListDeinit(&debugger->breakpoints);
mBreakpointListDeinit(&debugger->breakpoints);
for (i = 0; i < LR35902DebugWatchpointListSize(&debugger->watchpoints); ++i) {
_destroyWatchpoint(LR35902DebugWatchpointListGetPointer(&debugger->watchpoints, i));
for (i = 0; i < mWatchpointListSize(&debugger->watchpoints); ++i) {
_destroyWatchpoint(mWatchpointListGetPointer(&debugger->watchpoints, i));
}
LR35902DebugWatchpointListDeinit(&debugger->watchpoints);
mWatchpointListDeinit(&debugger->watchpoints);
}
static void LR35902DebuggerEnter(struct mDebuggerPlatform* platform, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
@ -130,65 +127,72 @@ static void LR35902DebuggerEnter(struct mDebuggerPlatform* platform, enum mDebug
}
}
static void LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
LR35902DebuggerSetConditionalBreakpoint(d, address, segment, NULL);
static ssize_t LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform* d, const struct mBreakpoint* info) {
struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
struct mBreakpoint* breakpoint = mBreakpointListAppend(&debugger->breakpoints);
*breakpoint = *info;
breakpoint->id = debugger->nextId;
++debugger->nextId;
return breakpoint->id;
}
static void LR35902DebuggerSetConditionalBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, struct ParseTree* condition) {
static bool LR35902DebuggerClearBreakpoint(struct mDebuggerPlatform* d, ssize_t id) {
struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
struct LR35902DebugBreakpoint* breakpoint = LR35902DebugBreakpointListAppend(&debugger->breakpoints);
breakpoint->address = address;
breakpoint->segment = segment;
breakpoint->condition = condition;
}
static void LR35902DebuggerClearBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
struct LR35902DebugBreakpointList* breakpoints = &debugger->breakpoints;
size_t i;
for (i = 0; i < LR35902DebugBreakpointListSize(breakpoints); ++i) {
struct LR35902DebugBreakpoint* breakpoint = LR35902DebugBreakpointListGetPointer(breakpoints, i);
if (breakpoint->address == address && breakpoint->segment == segment) {
_destroyBreakpoint(LR35902DebugBreakpointListGetPointer(breakpoints, i));
LR35902DebugBreakpointListShift(breakpoints, i, 1);
struct mBreakpointList* breakpoints = &debugger->breakpoints;
for (i = 0; i < mBreakpointListSize(breakpoints); ++i) {
struct mBreakpoint* breakpoint = mBreakpointListGetPointer(breakpoints, i);
if (breakpoint->id == id) {
_destroyBreakpoint(breakpoint);
mBreakpointListShift(breakpoints, i, 1);
return true;
}
}
struct mWatchpointList* watchpoints = &debugger->watchpoints;
for (i = 0; i < mWatchpointListSize(watchpoints); ++i) {
struct mWatchpoint* watchpoint = mWatchpointListGetPointer(watchpoints, i);
if (watchpoint->id == id) {
_destroyWatchpoint(watchpoint);
mWatchpointListShift(watchpoints, i, 1);
if (!mWatchpointListSize(&debugger->watchpoints)) {
LR35902DebuggerRemoveMemoryShim(debugger);
}
return true;
}
}
return false;
}
static bool LR35902DebuggerHasBreakpoints(struct mDebuggerPlatform* d) {
struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
return LR35902DebugBreakpointListSize(&debugger->breakpoints) || LR35902DebugWatchpointListSize(&debugger->watchpoints);
return mBreakpointListSize(&debugger->breakpoints) || mWatchpointListSize(&debugger->watchpoints);
}
static void LR35902DebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, enum mWatchpointType type) {
LR35902DebuggerSetConditionalWatchpoint(d, address, segment, type, NULL);
}
static void LR35902DebuggerSetConditionalWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, enum mWatchpointType type, struct ParseTree* condition) {
static ssize_t LR35902DebuggerSetWatchpoint(struct mDebuggerPlatform* d, const struct mWatchpoint* info) {
struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
if (!LR35902DebugWatchpointListSize(&debugger->watchpoints)) {
if (!mWatchpointListSize(&debugger->watchpoints)) {
LR35902DebuggerInstallMemoryShim(debugger);
}
struct LR35902DebugWatchpoint* watchpoint = LR35902DebugWatchpointListAppend(&debugger->watchpoints);
watchpoint->address = address;
watchpoint->type = type;
watchpoint->segment = segment;
watchpoint->condition = condition;
struct mWatchpoint* watchpoint = mWatchpointListAppend(&debugger->watchpoints);
*watchpoint = *info;
watchpoint->id = debugger->nextId;
++debugger->nextId;
return watchpoint->id;
}
static void LR35902DebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
static void LR35902DebuggerListBreakpoints(struct mDebuggerPlatform* d, struct mBreakpointList* list) {
struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
struct LR35902DebugWatchpointList* watchpoints = &debugger->watchpoints;
size_t i;
for (i = 0; i < LR35902DebugWatchpointListSize(watchpoints); ++i) {
struct LR35902DebugWatchpoint* watchpoint = LR35902DebugWatchpointListGetPointer(watchpoints, i);
if (watchpoint->address == address && watchpoint->segment == segment) {
LR35902DebugWatchpointListShift(watchpoints, i, 1);
}
}
if (!LR35902DebugWatchpointListSize(&debugger->watchpoints)) {
LR35902DebuggerRemoveMemoryShim(debugger);
}
mBreakpointListClear(list);
mBreakpointListCopy(list, &debugger->breakpoints);
}
static void LR35902DebuggerListWatchpoints(struct mDebuggerPlatform* d, struct mWatchpointList* list) {
struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
mWatchpointListClear(list);
mWatchpointListCopy(list, &debugger->watchpoints);
}
static void LR35902DebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* length) {

View File

@ -43,10 +43,10 @@ CREATE_WATCHPOINT_SHIM(load8, READ, 0, uint8_t, (struct LR35902Core* cpu, uint16
CREATE_WATCHPOINT_SHIM(store8, WRITE, value, void, (struct LR35902Core* cpu, uint16_t address, int8_t value), address, value)
static bool _checkWatchpoints(struct LR35902Debugger* debugger, uint16_t address, struct mDebuggerEntryInfo* info, enum mWatchpointType type, uint8_t newValue) {
struct LR35902DebugWatchpoint* watchpoint;
struct mWatchpoint* watchpoint;
size_t i;
for (i = 0; i < LR35902DebugWatchpointListSize(&debugger->watchpoints); ++i) {
watchpoint = LR35902DebugWatchpointListGetPointer(&debugger->watchpoints, i);
for (i = 0; i < mWatchpointListSize(&debugger->watchpoints); ++i) {
watchpoint = mWatchpointListGetPointer(&debugger->watchpoints, i);
if (watchpoint->address == address && (watchpoint->segment < 0 || watchpoint->segment == debugger->originalMemory.currentSegment(debugger->cpu, address)) && watchpoint->type & type) {
if (watchpoint->condition) {
int32_t value;