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 - GB Memory: Support running from blocked memory
- Qt: Don't unload ROM immediately if it crashes - Qt: Don't unload ROM immediately if it crashes
- GBA Video: Improve sprite cycle counting (fixes mgba.io/i/1274) - GBA Video: Improve sprite cycle counting (fixes mgba.io/i/1274)
- Debugger: Add breakpoint and watchpoint listing
0.7.0: (2019-01-26) 0.7.0: (2019-01-26)
Features: 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 * 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 * 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/cpu.h>
#include <mgba/core/log.h> #include <mgba/core/log.h>
#include <mgba-util/vector.h>
mLOG_DECLARE_CATEGORY(DEBUGGER); mLOG_DECLARE_CATEGORY(DEBUGGER);
@ -36,7 +37,8 @@ enum mDebuggerState {
enum mWatchpointType { enum mWatchpointType {
WATCHPOINT_WRITE = 1, WATCHPOINT_WRITE = 1,
WATCHPOINT_READ = 2, WATCHPOINT_READ = 2,
WATCHPOINT_RW = 3 WATCHPOINT_RW = 3,
WATCHPOINT_WRITE_CHANGE = 4,
}; };
enum mBreakpointType { enum mBreakpointType {
@ -69,6 +71,25 @@ struct mDebuggerEntryInfo {
} type; } 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 mDebugger;
struct ParseTree; struct ParseTree;
struct mDebuggerPlatform { struct mDebuggerPlatform {
@ -79,13 +100,15 @@ struct mDebuggerPlatform {
void (*entered)(struct mDebuggerPlatform*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*); void (*entered)(struct mDebuggerPlatform*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*);
bool (*hasBreakpoints)(struct mDebuggerPlatform*); 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*); 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); void (*trace)(struct mDebuggerPlatform*, char* out, size_t* length);
bool (*getRegister)(struct mDebuggerPlatform*, const char* name, int32_t* value); bool (*getRegister)(struct mDebuggerPlatform*, const char* name, int32_t* value);

View File

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

View File

@ -13,21 +13,6 @@ CXX_GUARD_START
#include <mgba/debugger/debugger.h> #include <mgba/debugger/debugger.h>
#include <mgba/internal/lr35902/lr35902.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 { struct LR35902Segment {
uint16_t start; uint16_t start;
@ -35,17 +20,16 @@ struct LR35902Segment {
const char* name; const char* name;
}; };
DECLARE_VECTOR(LR35902DebugBreakpointList, struct LR35902DebugBreakpoint);
DECLARE_VECTOR(LR35902DebugWatchpointList, struct LR35902DebugWatchpoint);
struct LR35902Debugger { struct LR35902Debugger {
struct mDebuggerPlatform d; struct mDebuggerPlatform d;
struct LR35902Core* cpu; struct LR35902Core* cpu;
struct LR35902DebugBreakpointList breakpoints; struct mBreakpointList breakpoints;
struct LR35902DebugWatchpointList watchpoints; struct mWatchpointList watchpoints;
struct LR35902Memory originalMemory; struct LR35902Memory originalMemory;
ssize_t nextId;
const struct LR35902Segment* segments; const struct LR35902Segment* segments;
}; };

View File

@ -13,12 +13,11 @@
#include <mgba/internal/debugger/parser.h> #include <mgba/internal/debugger/parser.h>
DEFINE_VECTOR(ARMDebugBreakpointList, struct ARMDebugBreakpoint); DEFINE_VECTOR(ARMDebugBreakpointList, struct ARMDebugBreakpoint);
DEFINE_VECTOR(ARMDebugWatchpointList, struct ARMDebugWatchpoint);
static struct ARMDebugBreakpoint* _lookupBreakpoint(struct ARMDebugBreakpointList* breakpoints, uint32_t address) { static struct ARMDebugBreakpoint* _lookupBreakpoint(struct ARMDebugBreakpointList* breakpoints, uint32_t address) {
size_t i; size_t i;
for (i = 0; i < ARMDebugBreakpointListSize(breakpoints); ++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); return ARMDebugBreakpointListGetPointer(breakpoints, i);
} }
} }
@ -26,13 +25,13 @@ static struct ARMDebugBreakpoint* _lookupBreakpoint(struct ARMDebugBreakpointLis
} }
static void _destroyBreakpoint(struct ARMDebugBreakpoint* breakpoint) { static void _destroyBreakpoint(struct ARMDebugBreakpoint* breakpoint) {
if (breakpoint->condition) { if (breakpoint->d.condition) {
parseFree(breakpoint->condition); parseFree(breakpoint->d.condition);
free(breakpoint->condition); free(breakpoint->d.condition);
} }
} }
static void _destroyWatchpoint(struct ARMDebugWatchpoint* watchpoint) { static void _destroyWatchpoint(struct mWatchpoint* watchpoint) {
if (watchpoint->condition) { if (watchpoint->condition) {
parseFree(watchpoint->condition); parseFree(watchpoint->condition);
free(watchpoint->condition); free(watchpoint->condition);
@ -52,15 +51,15 @@ static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform* d) {
if (!breakpoint) { if (!breakpoint) {
return; return;
} }
if (breakpoint->condition) { if (breakpoint->d.condition) {
int32_t value; int32_t value;
int segment; 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; return;
} }
} }
struct mDebuggerEntryInfo info = { struct mDebuggerEntryInfo info = {
.address = breakpoint->address, .address = breakpoint->d.address,
.type.bp.breakType = BREAKPOINT_HARDWARE .type.bp.breakType = BREAKPOINT_HARDWARE
}; };
mDebuggerEnter(d->p, DEBUGGER_ENTER_BREAKPOINT, &info); 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 ARMDebuggerEnter(struct mDebuggerPlatform* d, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info);
static void ARMDebuggerSetBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment); static ssize_t ARMDebuggerSetBreakpoint(struct mDebuggerPlatform*, const struct mBreakpoint*);
static void ARMDebuggerSetConditionalBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment, struct ParseTree* condition); static bool ARMDebuggerClearBreakpoint(struct mDebuggerPlatform*, ssize_t id);
static void ARMDebuggerClearBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment); static void ARMDebuggerListBreakpoints(struct mDebuggerPlatform*, struct mBreakpointList*);
static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type); static ssize_t ARMDebuggerSetWatchpoint(struct mDebuggerPlatform*, const struct mWatchpoint*);
static void ARMDebuggerSetConditionalWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type, struct ParseTree* condition); static void ARMDebuggerListWatchpoints(struct mDebuggerPlatform*, struct mWatchpointList*);
static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform*); static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform*);
static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform*); static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform*);
static void ARMDebuggerTrace(struct mDebuggerPlatform*, char* out, size_t* length); static void ARMDebuggerTrace(struct mDebuggerPlatform*, char* out, size_t* length);
@ -89,11 +87,10 @@ struct mDebuggerPlatform* ARMDebuggerPlatformCreate(void) {
platform->init = ARMDebuggerInit; platform->init = ARMDebuggerInit;
platform->deinit = ARMDebuggerDeinit; platform->deinit = ARMDebuggerDeinit;
platform->setBreakpoint = ARMDebuggerSetBreakpoint; platform->setBreakpoint = ARMDebuggerSetBreakpoint;
platform->setConditionalBreakpoint = ARMDebuggerSetConditionalBreakpoint; platform->listBreakpoints = ARMDebuggerListBreakpoints;
platform->clearBreakpoint = ARMDebuggerClearBreakpoint; platform->clearBreakpoint = ARMDebuggerClearBreakpoint;
platform->setWatchpoint = ARMDebuggerSetWatchpoint; platform->setWatchpoint = ARMDebuggerSetWatchpoint;
platform->setConditionalWatchpoint = ARMDebuggerSetConditionalWatchpoint; platform->listWatchpoints = ARMDebuggerListWatchpoints;
platform->clearWatchpoint = ARMDebuggerClearWatchpoint;
platform->checkBreakpoints = ARMDebuggerCheckBreakpoints; platform->checkBreakpoints = ARMDebuggerCheckBreakpoints;
platform->hasBreakpoints = ARMDebuggerHasBreakpoints; platform->hasBreakpoints = ARMDebuggerHasBreakpoints;
platform->trace = ARMDebuggerTrace; platform->trace = ARMDebuggerTrace;
@ -106,9 +103,10 @@ void ARMDebuggerInit(void* cpu, struct mDebuggerPlatform* platform) {
struct ARMDebugger* debugger = (struct ARMDebugger*) platform; struct ARMDebugger* debugger = (struct ARMDebugger*) platform;
debugger->cpu = cpu; debugger->cpu = cpu;
debugger->originalMemory = debugger->cpu->memory; debugger->originalMemory = debugger->cpu->memory;
debugger->nextId = 1;
ARMDebugBreakpointListInit(&debugger->breakpoints, 0); ARMDebugBreakpointListInit(&debugger->breakpoints, 0);
ARMDebugBreakpointListInit(&debugger->swBreakpoints, 0); ARMDebugBreakpointListInit(&debugger->swBreakpoints, 0);
ARMDebugWatchpointListInit(&debugger->watchpoints, 0); mWatchpointListInit(&debugger->watchpoints, 0);
} }
void ARMDebuggerDeinit(struct mDebuggerPlatform* platform) { void ARMDebuggerDeinit(struct mDebuggerPlatform* platform) {
@ -118,7 +116,7 @@ void ARMDebuggerDeinit(struct mDebuggerPlatform* platform) {
size_t b; size_t b;
for (b = ARMDebugBreakpointListSize(&debugger->swBreakpoints); b; --b) { for (b = ARMDebugBreakpointListSize(&debugger->swBreakpoints); b; --b) {
struct ARMDebugBreakpoint* breakpoint = ARMDebugBreakpointListGetPointer(&debugger->swBreakpoints, b - 1); 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); ARMDebuggerRemoveMemoryShim(debugger);
@ -129,11 +127,11 @@ void ARMDebuggerDeinit(struct mDebuggerPlatform* platform) {
} }
ARMDebugBreakpointListDeinit(&debugger->breakpoints); ARMDebugBreakpointListDeinit(&debugger->breakpoints);
for (i = 0; i < ARMDebugWatchpointListSize(&debugger->watchpoints); ++i) { for (i = 0; i < mWatchpointListSize(&debugger->watchpoints); ++i) {
_destroyWatchpoint(ARMDebugWatchpointListGetPointer(&debugger->watchpoints, i)); _destroyWatchpoint(mWatchpointListGetPointer(&debugger->watchpoints, i));
} }
ARMDebugBreakpointListDeinit(&debugger->swBreakpoints); ARMDebugBreakpointListDeinit(&debugger->swBreakpoints);
ARMDebugWatchpointListDeinit(&debugger->watchpoints); mWatchpointListDeinit(&debugger->watchpoints);
} }
static void ARMDebuggerEnter(struct mDebuggerPlatform* platform, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) { 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; cpu->nextEvent = cpu->cycles;
if (reason == DEBUGGER_ENTER_BREAKPOINT) { if (reason == DEBUGGER_ENTER_BREAKPOINT) {
struct ARMDebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->swBreakpoints, _ARMPCAddress(cpu)); struct ARMDebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->swBreakpoints, _ARMPCAddress(cpu));
if (breakpoint && breakpoint->isSw) { if (breakpoint && breakpoint->d.type == BREAKPOINT_SOFTWARE) {
info->address = breakpoint->address; info->address = breakpoint->d.address;
if (debugger->clearSoftwareBreakpoint) { if (debugger->clearSoftwareBreakpoint) {
debugger->clearSoftwareBreakpoint(debugger, breakpoint->address, breakpoint->sw.mode, breakpoint->sw.opcode); debugger->clearSoftwareBreakpoint(debugger, breakpoint);
} }
ARMRunFake(cpu, breakpoint->sw.opcode); ARMRunFake(cpu, breakpoint->sw.opcode);
if (debugger->setSoftwareBreakpoint) { 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; struct ARMDebugger* debugger = (struct ARMDebugger*) d;
uint32_t opcode; uint32_t opcode;
if (!debugger->setSoftwareBreakpoint || !debugger->setSoftwareBreakpoint(debugger, address, mode, &opcode)) { if (!debugger->setSoftwareBreakpoint || !debugger->setSoftwareBreakpoint(debugger, address, mode, &opcode)) {
return false; return -1;
} }
struct ARMDebugBreakpoint* breakpoint = ARMDebugBreakpointListAppend(&debugger->swBreakpoints); struct ARMDebugBreakpoint* breakpoint = ARMDebugBreakpointListAppend(&debugger->swBreakpoints);
breakpoint->address = address; ssize_t id = debugger->nextId;
breakpoint->isSw = true; ++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.opcode = opcode;
breakpoint->sw.mode = mode; breakpoint->sw.mode = mode;
return true; return id;
} }
void ARMDebuggerClearSoftwareBreakpoint(struct mDebuggerPlatform* d, uint32_t address) { static ssize_t ARMDebuggerSetBreakpoint(struct mDebuggerPlatform* d, const struct mBreakpoint* info) {
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);
struct ARMDebugger* debugger = (struct ARMDebugger*) d; struct ARMDebugger* debugger = (struct ARMDebugger*) d;
struct ARMDebugBreakpoint* breakpoint = ARMDebugBreakpointListAppend(&debugger->breakpoints); struct ARMDebugBreakpoint* breakpoint = ARMDebugBreakpointListAppend(&debugger->breakpoints);
breakpoint->condition = condition; ssize_t id = debugger->nextId;
breakpoint->address = address; ++debugger->nextId;
breakpoint->isSw = false; 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) { static bool ARMDebuggerClearBreakpoint(struct mDebuggerPlatform* d, ssize_t id) {
UNUSED(segment);
struct ARMDebugger* debugger = (struct ARMDebugger*) d; struct ARMDebugger* debugger = (struct ARMDebugger*) d;
struct ARMDebugBreakpointList* breakpoints = &debugger->breakpoints;
size_t i; size_t i;
struct ARMDebugBreakpointList* breakpoints = &debugger->breakpoints;
for (i = 0; i < ARMDebugBreakpointListSize(breakpoints); ++i) { for (i = 0; i < ARMDebugBreakpointListSize(breakpoints); ++i) {
if (ARMDebugBreakpointListGetPointer(breakpoints, i)->address == address) { if (ARMDebugBreakpointListGetPointer(breakpoints, i)->d.id == id) {
_destroyBreakpoint(ARMDebugBreakpointListGetPointer(breakpoints, i)); _destroyBreakpoint(ARMDebugBreakpointListGetPointer(breakpoints, i));
ARMDebugBreakpointListShift(breakpoints, i, 1); 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) { static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform* d) {
struct ARMDebugger* debugger = (struct ARMDebugger*) 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) { static ssize_t ARMDebuggerSetWatchpoint(struct mDebuggerPlatform* d, const struct mWatchpoint* info) {
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);
struct ARMDebugger* debugger = (struct ARMDebugger*) d; struct ARMDebugger* debugger = (struct ARMDebugger*) d;
if (!ARMDebugWatchpointListSize(&debugger->watchpoints)) { if (!mWatchpointListSize(&debugger->watchpoints)) {
ARMDebuggerInstallMemoryShim(debugger); ARMDebuggerInstallMemoryShim(debugger);
} }
struct ARMDebugWatchpoint* watchpoint = ARMDebugWatchpointListAppend(&debugger->watchpoints); struct mWatchpoint* watchpoint = mWatchpointListAppend(&debugger->watchpoints);
watchpoint->address = address; ssize_t id = debugger->nextId;
watchpoint->type = type; ++debugger->nextId;
watchpoint->condition = condition; *watchpoint = *info;
watchpoint->id = id;
return id;
} }
static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) { static void ARMDebuggerListWatchpoints(struct mDebuggerPlatform* d, struct mWatchpointList* list) {
UNUSED(segment);
struct ARMDebugger* debugger = (struct ARMDebugger*) d; struct ARMDebugger* debugger = (struct ARMDebugger*) d;
struct ARMDebugWatchpointList* watchpoints = &debugger->watchpoints; mWatchpointListClear(list);
size_t i; mWatchpointListCopy(list, &debugger->watchpoints);
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);
}
} }
static void ARMDebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* length) { 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) { static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, struct mDebuggerEntryInfo* info, enum mWatchpointType type, uint32_t newValue, int width) {
--width; --width;
struct ARMDebugWatchpoint* watchpoint; struct mWatchpoint* watchpoint;
size_t i; size_t i;
for (i = 0; i < ARMDebugWatchpointListSize(&debugger->watchpoints); ++i) { for (i = 0; i < mWatchpointListSize(&debugger->watchpoints); ++i) {
watchpoint = ARMDebugWatchpointListGetPointer(&debugger->watchpoints, i); watchpoint = mWatchpointListGetPointer(&debugger->watchpoints, i);
if (!((watchpoint->address ^ address) & ~width) && watchpoint->type & type) { if (!((watchpoint->address ^ address) & ~width) && watchpoint->type & type) {
if (watchpoint->condition) { if (watchpoint->condition) {
int32_t value; 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 _readWord(struct CLIDebugger*, struct CLIDebugVector*);
static void _setBreakpoint(struct CLIDebugger*, struct CLIDebugVector*); static void _setBreakpoint(struct CLIDebugger*, struct CLIDebugVector*);
static void _clearBreakpoint(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 _setReadWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
static void _setWriteWatchpoint(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 _trace(struct CLIDebugger*, struct CLIDebugVector*);
static void _writeByte(struct CLIDebugger*, struct CLIDebugVector*); static void _writeByte(struct CLIDebugger*, struct CLIDebugVector*);
static void _writeHalfword(struct CLIDebugger*, struct CLIDebugVector*); static void _writeHalfword(struct CLIDebugger*, struct CLIDebugVector*);
@ -75,6 +78,10 @@ static struct CLIDebuggerCommandSummary _debuggerCommands[] = {
{ "help", _printHelp, "S", "Print help" }, { "help", _printHelp, "S", "Print help" },
{ "i", _printStatus, "", "Print the current status" }, { "i", _printStatus, "", "Print the current status" },
{ "info", _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" }, { "n", _next, "", "Execute next instruction" },
{ "next", _next, "", "Execute next instruction" }, { "next", _next, "", "Execute next instruction" },
{ "p", _print, "I", "Print a value" }, { "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" }, { "r/4", _readWord, "I", "Read a word from a specified offset" },
{ "status", _printStatus, "", "Print the current status" }, { "status", _printStatus, "", "Print the current status" },
{ "trace", _trace, "I", "Trace a fixed number of instructions" }, { "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/1", _writeByte, "II", "Write a byte at a specified offset" },
{ "w/2", _writeHalfword, "II", "Write a halfword at a specified offset" }, { "w/2", _writeHalfword, "II", "Write a halfword at a specified offset" },
{ "w/r", _writeRegister, "SI", "Write a register" }, { "w/r", _writeRegister, "SI", "Write a register" },
{ "w/4", _writeWord, "II", "Write a word at a specified offset" }, { "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/r", _setReadWatchpoint, "Is", "Set a read watchpoint" },
{ "watch/w", _setWriteWatchpoint, "Is", "Set a write watchpoint" }, { "watch/w", _setWriteWatchpoint, "Is", "Set a write watchpoint" },
{ "x/1", _dumpByte, "Ii", "Examine bytes at a specified offset" }, { "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); debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
return; 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) { if (dv->next && dv->next->type == CLIDV_CHAR_TYPE) {
struct ParseTree* tree = _parseTree(dv->next->charValue); struct ParseTree* tree = _parseTree(dv->next->charValue);
if (tree) { if (tree) {
debugger->d.platform->setConditionalBreakpoint(debugger->d.platform, address, dv->segmentValue, tree); breakpoint.condition = tree;
} else { } else {
debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS); 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) { if (!dv || dv->type != CLIDV_INT_TYPE) {
debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS); debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
return; 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"); debugger->backend->printf(debugger->backend, "Watchpoints are not supported by this platform.\n");
return; 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) { if (dv->next && dv->next->type == CLIDV_CHAR_TYPE) {
struct ParseTree* tree = _parseTree(dv->next->charValue); struct ParseTree* tree = _parseTree(dv->next->charValue);
if (tree) { if (tree) {
debugger->d.platform->setConditionalWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_RW, tree); watchpoint.condition = tree;
} else { } else {
debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS); 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) { static void _setReadWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
if (!dv || dv->type != CLIDV_INT_TYPE) { _setWatchpoint(debugger, dv, WATCHPOINT_READ);
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);
}
} }
static void _setWriteWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { static void _setWriteWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
if (!dv || dv->type != CLIDV_INT_TYPE) { _setWatchpoint(debugger, dv, WATCHPOINT_WRITE);
debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS); }
return;
} static void _setWriteChangedWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
if (!debugger->d.platform->setWatchpoint) { _setWatchpoint(debugger, dv, WATCHPOINT_WRITE_CHANGE);
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);
}}
static void _clearBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { static void _clearBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
if (!dv || dv->type != CLIDV_INT_TYPE) { if (!dv || dv->type != CLIDV_INT_TYPE) {
debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS); debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
return; return;
} }
uint32_t address = dv->intValue; uint64_t id = dv->intValue;
debugger->d.platform->clearBreakpoint(debugger->d.platform, address, dv->segmentValue); debugger->d.platform->clearBreakpoint(debugger->d.platform, id);
if (debugger->d.platform->clearWatchpoint) { }
debugger->d.platform->clearWatchpoint(debugger->d.platform, address, dv->segmentValue);
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) { 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"); 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 mDebuggerInit(void* cpu, struct mCPUComponent* component);
static void mDebuggerDeinit(struct mCPUComponent* component); static void mDebuggerDeinit(struct mCPUComponent* component);

View File

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

View File

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