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
|
- 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:
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue