mirror of https://github.com/mgba-emu/mgba.git
Debugger: Revamp breakpoint/watchpoint API, add listing
This commit is contained in:
parent
0eaa9e487f
commit
0c9802e4da
1
CHANGES
1
CHANGES
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue