src/lr35902/debugger/debugger.c (view raw)
1/* Copyright (c) 2013-2016 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include <mgba/internal/lr35902/debugger/debugger.h>
7
8#include <mgba/core/core.h>
9#include <mgba/internal/lr35902/lr35902.h>
10#include <mgba/internal/lr35902/debugger/memory-debugger.h>
11
12DEFINE_VECTOR(LR35902DebugBreakpointList, struct LR35902DebugBreakpoint);
13DEFINE_VECTOR(LR35902DebugWatchpointList, struct LR35902DebugWatchpoint);
14
15static struct LR35902DebugBreakpoint* _lookupBreakpoint(struct LR35902DebugBreakpointList* breakpoints, uint16_t address) {
16 size_t i;
17 for (i = 0; i < LR35902DebugBreakpointListSize(breakpoints); ++i) {
18 if (LR35902DebugBreakpointListGetPointer(breakpoints, i)->address == address) {
19 return LR35902DebugBreakpointListGetPointer(breakpoints, i);
20 }
21 }
22 return 0;
23}
24
25static void LR35902DebuggerCheckBreakpoints(struct mDebuggerPlatform* d) {
26 struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
27 struct LR35902DebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->breakpoints, debugger->cpu->pc);
28 if (!breakpoint) {
29 return;
30 }
31 if (breakpoint->segment >= 0 && debugger->cpu->memory.currentSegment(debugger->cpu, breakpoint->address) != breakpoint->segment) {
32 return;
33 }
34 struct mDebuggerEntryInfo info = {
35 .address = breakpoint->address
36 };
37 mDebuggerEnter(d->p, DEBUGGER_ENTER_BREAKPOINT, &info);
38}
39
40static void LR35902DebuggerInit(void* cpu, struct mDebuggerPlatform* platform);
41static void LR35902DebuggerDeinit(struct mDebuggerPlatform* platform);
42
43static void LR35902DebuggerEnter(struct mDebuggerPlatform* d, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info);
44
45static void LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
46static void LR35902DebuggerClearBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
47static void LR35902DebuggerSetWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type);
48static void LR35902DebuggerClearWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
49static void LR35902DebuggerCheckBreakpoints(struct mDebuggerPlatform*);
50static bool LR35902DebuggerHasBreakpoints(struct mDebuggerPlatform*);
51
52struct mDebuggerPlatform* LR35902DebuggerPlatformCreate(void) {
53 struct mDebuggerPlatform* platform = (struct mDebuggerPlatform*) malloc(sizeof(struct LR35902Debugger));
54 platform->entered = LR35902DebuggerEnter;
55 platform->init = LR35902DebuggerInit;
56 platform->deinit = LR35902DebuggerDeinit;
57 platform->setBreakpoint = LR35902DebuggerSetBreakpoint;
58 platform->clearBreakpoint = LR35902DebuggerClearBreakpoint;
59 platform->setWatchpoint = LR35902DebuggerSetWatchpoint;
60 platform->clearWatchpoint = LR35902DebuggerClearWatchpoint;
61 platform->checkBreakpoints = LR35902DebuggerCheckBreakpoints;
62 platform->hasBreakpoints = LR35902DebuggerHasBreakpoints;
63 return platform;
64}
65
66void LR35902DebuggerInit(void* cpu, struct mDebuggerPlatform* platform) {
67 struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform;
68 debugger->cpu = cpu;
69 LR35902DebugBreakpointListInit(&debugger->breakpoints, 0);
70 LR35902DebugWatchpointListInit(&debugger->watchpoints, 0);
71}
72
73void LR35902DebuggerDeinit(struct mDebuggerPlatform* platform) {
74 struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform;
75 LR35902DebugBreakpointListDeinit(&debugger->breakpoints);
76 LR35902DebugWatchpointListDeinit(&debugger->watchpoints);
77}
78
79static void LR35902DebuggerEnter(struct mDebuggerPlatform* platform, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
80 UNUSED(reason);
81 UNUSED(info);
82 struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform;
83 struct LR35902Core* cpu = debugger->cpu;
84 cpu->nextEvent = cpu->cycles;
85
86 if (debugger->d.p->entered) {
87 debugger->d.p->entered(debugger->d.p, reason, info);
88 }
89}
90
91static void LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
92 struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
93 struct LR35902DebugBreakpoint* breakpoint = LR35902DebugBreakpointListAppend(&debugger->breakpoints);
94 breakpoint->address = address;
95 breakpoint->segment = segment;
96}
97
98static void LR35902DebuggerClearBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
99 struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
100 struct LR35902DebugBreakpointList* breakpoints = &debugger->breakpoints;
101 size_t i;
102 for (i = 0; i < LR35902DebugBreakpointListSize(breakpoints); ++i) {
103 struct LR35902DebugBreakpoint* breakpoint = LR35902DebugBreakpointListGetPointer(breakpoints, i);
104 if (breakpoint->address == address && breakpoint->segment == segment) {
105 LR35902DebugBreakpointListShift(breakpoints, i, 1);
106 }
107 }
108}
109
110static bool LR35902DebuggerHasBreakpoints(struct mDebuggerPlatform* d) {
111 struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
112 return LR35902DebugBreakpointListSize(&debugger->breakpoints) || LR35902DebugWatchpointListSize(&debugger->watchpoints);
113}
114
115static void LR35902DebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, enum mWatchpointType type) {
116 struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
117 if (!LR35902DebugWatchpointListSize(&debugger->watchpoints)) {
118 LR35902DebuggerInstallMemoryShim(debugger);
119 }
120 struct LR35902DebugWatchpoint* watchpoint = LR35902DebugWatchpointListAppend(&debugger->watchpoints);
121 watchpoint->address = address;
122 watchpoint->type = type;
123 watchpoint->segment = segment;
124}
125
126static void LR35902DebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
127 struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
128 struct LR35902DebugWatchpointList* watchpoints = &debugger->watchpoints;
129 size_t i;
130 for (i = 0; i < LR35902DebugWatchpointListSize(watchpoints); ++i) {
131 struct LR35902DebugWatchpoint* watchpoint = LR35902DebugWatchpointListGetPointer(watchpoints, i);
132 if (watchpoint->address == address && watchpoint->segment == segment) {
133 LR35902DebugWatchpointListShift(watchpoints, i, 1);
134 }
135 }
136 if (!LR35902DebugWatchpointListSize(&debugger->watchpoints)) {
137 LR35902DebuggerRemoveMemoryShim(debugger);
138 }
139}