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/decoder.h>
10#include <mgba/internal/lr35902/lr35902.h>
11#include <mgba/internal/lr35902/debugger/memory-debugger.h>
12
13DEFINE_VECTOR(LR35902DebugBreakpointList, struct LR35902DebugBreakpoint);
14DEFINE_VECTOR(LR35902DebugWatchpointList, struct LR35902DebugWatchpoint);
15
16static struct LR35902DebugBreakpoint* _lookupBreakpoint(struct LR35902DebugBreakpointList* breakpoints, uint16_t address) {
17 size_t i;
18 for (i = 0; i < LR35902DebugBreakpointListSize(breakpoints); ++i) {
19 if (LR35902DebugBreakpointListGetPointer(breakpoints, i)->address == address) {
20 return LR35902DebugBreakpointListGetPointer(breakpoints, i);
21 }
22 }
23 return 0;
24}
25
26static void LR35902DebuggerCheckBreakpoints(struct mDebuggerPlatform* d) {
27 struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
28 struct LR35902DebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->breakpoints, debugger->cpu->pc);
29 if (!breakpoint) {
30 return;
31 }
32 if (breakpoint->segment >= 0 && debugger->cpu->memory.currentSegment(debugger->cpu, breakpoint->address) != breakpoint->segment) {
33 return;
34 }
35 struct mDebuggerEntryInfo info = {
36 .address = breakpoint->address
37 };
38 mDebuggerEnter(d->p, DEBUGGER_ENTER_BREAKPOINT, &info);
39}
40
41static void LR35902DebuggerInit(void* cpu, struct mDebuggerPlatform* platform);
42static void LR35902DebuggerDeinit(struct mDebuggerPlatform* platform);
43
44static void LR35902DebuggerEnter(struct mDebuggerPlatform* d, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info);
45
46static void LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
47static void LR35902DebuggerClearBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
48static void LR35902DebuggerSetWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type);
49static void LR35902DebuggerClearWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
50static void LR35902DebuggerCheckBreakpoints(struct mDebuggerPlatform*);
51static bool LR35902DebuggerHasBreakpoints(struct mDebuggerPlatform*);
52static void LR35902DebuggerTrace(struct mDebuggerPlatform*, char* out, size_t* length);
53static bool LR35902DebuggerGetRegister(struct mDebuggerPlatform*, const char* name, int32_t* value);
54static bool LR35902DebuggerSetRegister(struct mDebuggerPlatform*, const char* name, int32_t value);
55
56struct mDebuggerPlatform* LR35902DebuggerPlatformCreate(void) {
57 struct mDebuggerPlatform* platform = (struct mDebuggerPlatform*) malloc(sizeof(struct LR35902Debugger));
58 platform->entered = LR35902DebuggerEnter;
59 platform->init = LR35902DebuggerInit;
60 platform->deinit = LR35902DebuggerDeinit;
61 platform->setBreakpoint = LR35902DebuggerSetBreakpoint;
62 platform->clearBreakpoint = LR35902DebuggerClearBreakpoint;
63 platform->setWatchpoint = LR35902DebuggerSetWatchpoint;
64 platform->clearWatchpoint = LR35902DebuggerClearWatchpoint;
65 platform->checkBreakpoints = LR35902DebuggerCheckBreakpoints;
66 platform->hasBreakpoints = LR35902DebuggerHasBreakpoints;
67 platform->trace = LR35902DebuggerTrace;
68 platform->getRegister = LR35902DebuggerGetRegister;
69 platform->setRegister = LR35902DebuggerSetRegister;
70 return platform;
71}
72
73void LR35902DebuggerInit(void* cpu, struct mDebuggerPlatform* platform) {
74 struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform;
75 debugger->cpu = cpu;
76 LR35902DebugBreakpointListInit(&debugger->breakpoints, 0);
77 LR35902DebugWatchpointListInit(&debugger->watchpoints, 0);
78}
79
80void LR35902DebuggerDeinit(struct mDebuggerPlatform* platform) {
81 struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform;
82 LR35902DebugBreakpointListDeinit(&debugger->breakpoints);
83 LR35902DebugWatchpointListDeinit(&debugger->watchpoints);
84}
85
86static void LR35902DebuggerEnter(struct mDebuggerPlatform* platform, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
87 UNUSED(reason);
88 UNUSED(info);
89 struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform;
90 struct LR35902Core* cpu = debugger->cpu;
91 cpu->nextEvent = cpu->cycles;
92
93 if (debugger->d.p->entered) {
94 debugger->d.p->entered(debugger->d.p, reason, info);
95 }
96}
97
98static void LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
99 struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
100 struct LR35902DebugBreakpoint* breakpoint = LR35902DebugBreakpointListAppend(&debugger->breakpoints);
101 breakpoint->address = address;
102 breakpoint->segment = segment;
103}
104
105static void LR35902DebuggerClearBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
106 struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
107 struct LR35902DebugBreakpointList* breakpoints = &debugger->breakpoints;
108 size_t i;
109 for (i = 0; i < LR35902DebugBreakpointListSize(breakpoints); ++i) {
110 struct LR35902DebugBreakpoint* breakpoint = LR35902DebugBreakpointListGetPointer(breakpoints, i);
111 if (breakpoint->address == address && breakpoint->segment == segment) {
112 LR35902DebugBreakpointListShift(breakpoints, i, 1);
113 }
114 }
115}
116
117static bool LR35902DebuggerHasBreakpoints(struct mDebuggerPlatform* d) {
118 struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
119 return LR35902DebugBreakpointListSize(&debugger->breakpoints) || LR35902DebugWatchpointListSize(&debugger->watchpoints);
120}
121
122static void LR35902DebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, enum mWatchpointType type) {
123 struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
124 if (!LR35902DebugWatchpointListSize(&debugger->watchpoints)) {
125 LR35902DebuggerInstallMemoryShim(debugger);
126 }
127 struct LR35902DebugWatchpoint* watchpoint = LR35902DebugWatchpointListAppend(&debugger->watchpoints);
128 watchpoint->address = address;
129 watchpoint->type = type;
130 watchpoint->segment = segment;
131}
132
133static void LR35902DebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
134 struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
135 struct LR35902DebugWatchpointList* watchpoints = &debugger->watchpoints;
136 size_t i;
137 for (i = 0; i < LR35902DebugWatchpointListSize(watchpoints); ++i) {
138 struct LR35902DebugWatchpoint* watchpoint = LR35902DebugWatchpointListGetPointer(watchpoints, i);
139 if (watchpoint->address == address && watchpoint->segment == segment) {
140 LR35902DebugWatchpointListShift(watchpoints, i, 1);
141 }
142 }
143 if (!LR35902DebugWatchpointListSize(&debugger->watchpoints)) {
144 LR35902DebuggerRemoveMemoryShim(debugger);
145 }
146}
147
148static void LR35902DebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* length) {
149 struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
150 struct LR35902Core* cpu = debugger->cpu;
151
152 char disassembly[64];
153
154 struct LR35902InstructionInfo info = {{0}};
155 char* disPtr = disassembly;
156 uint8_t instruction;
157 uint16_t address = cpu->pc;
158 size_t bytesRemaining = 1;
159 for (bytesRemaining = 1; bytesRemaining; --bytesRemaining) {
160 instruction = debugger->d.p->core->rawRead8(debugger->d.p->core, address, -1);
161 disPtr += snprintf(disPtr, sizeof(disassembly) - (disPtr - disassembly), "%02X", instruction);
162 ++address;
163 bytesRemaining += LR35902Decode(instruction, &info);
164 };
165 disPtr[0] = ':';
166 disPtr[1] = ' ';
167 disPtr += 2;
168 LR35902Disassemble(&info, disPtr, sizeof(disassembly) - (disPtr - disassembly));
169
170 *length = snprintf(out, *length, "A: %02X F: %02X B: %02X C: %02X D: %02X E: %02X H: %02X L: %02X SP: %04X PC: %04X | %s",
171 cpu->a, cpu->f.packed, cpu->b, cpu->c,
172 cpu->d, cpu->e, cpu->h, cpu->l,
173 cpu->sp, cpu->pc, disassembly);
174}
175
176bool LR35902DebuggerGetRegister(struct mDebuggerPlatform* d, const char* name, int32_t* value) {
177 struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
178 struct LR35902Core* cpu = debugger->cpu;
179
180 if (strcmp(name, "a") == 0) {
181 *value = cpu->a;
182 return true;
183 }
184 if (strcmp(name, "b") == 0) {
185 *value = cpu->b;
186 return true;
187 }
188 if (strcmp(name, "c") == 0) {
189 *value = cpu->c;
190 return true;
191 }
192 if (strcmp(name, "d") == 0) {
193 *value = cpu->d;
194 return true;
195 }
196 if (strcmp(name, "e") == 0) {
197 *value = cpu->e;
198 return true;
199 }
200 if (strcmp(name, "h") == 0) {
201 *value = cpu->h;
202 return true;
203 }
204 if (strcmp(name, "l") == 0) {
205 *value = cpu->l;
206 return true;
207 }
208 if (strcmp(name, "bc") == 0) {
209 *value = cpu->bc;
210 return true;
211 }
212 if (strcmp(name, "de") == 0) {
213 *value = cpu->de;
214 return true;
215 }
216 if (strcmp(name, "hl") == 0) {
217 *value = cpu->hl;
218 return true;
219 }
220 if (strcmp(name, "af") == 0) {
221 *value = cpu->af;
222 return true;
223 }
224 if (strcmp(name, "pc") == 0) {
225 *value = cpu->pc;
226 return true;
227 }
228 if (strcmp(name, "sp") == 0) {
229 *value = cpu->sp;
230 return true;
231 }
232 if (strcmp(name, "f") == 0) {
233 *value = cpu->f.packed;
234 return true;
235 }
236 return false;
237}
238
239bool LR35902DebuggerSetRegister(struct mDebuggerPlatform* d, const char* name, int32_t value) {
240 struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
241 struct LR35902Core* cpu = debugger->cpu;
242
243 if (strcmp(name, "a") == 0) {
244 cpu->a = value;
245 return true;
246 }
247 if (strcmp(name, "b") == 0) {
248 cpu->b = value;
249 return true;
250 }
251 if (strcmp(name, "c") == 0) {
252 cpu->c = value;
253 return true;
254 }
255 if (strcmp(name, "d") == 0) {
256 cpu->d = value;
257 return true;
258 }
259 if (strcmp(name, "e") == 0) {
260 cpu->e = value;
261 return true;
262 }
263 if (strcmp(name, "h") == 0) {
264 cpu->h = value;
265 return true;
266 }
267 if (strcmp(name, "l") == 0) {
268 cpu->l = value;
269 return true;
270 }
271 if (strcmp(name, "bc") == 0) {
272 cpu->bc = value;
273 return true;
274 }
275 if (strcmp(name, "de") == 0) {
276 cpu->de = value;
277 return true;
278 }
279 if (strcmp(name, "hl") == 0) {
280 cpu->hl = value;
281 return true;
282 }
283 if (strcmp(name, "af") == 0) {
284 cpu->af = value;
285 cpu->f.packed &= 0xF0;
286 return true;
287 }
288 if (strcmp(name, "pc") == 0) {
289 cpu->pc = value;
290 cpu->memory.setActiveRegion(cpu, cpu->pc);
291 return true;
292 }
293 if (strcmp(name, "sp") == 0) {
294 cpu->sp = value;
295 return true;
296 }
297 if (strcmp(name, "f") == 0) {
298 cpu->f.packed = value & 0xF0;
299 return true;
300 }
301 return false;
302}