src/sm83/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/sm83/debugger/debugger.h>
7
8#include <mgba/core/core.h>
9#include <mgba/internal/debugger/parser.h>
10#include <mgba/internal/sm83/decoder.h>
11#include <mgba/internal/sm83/sm83.h>
12#include <mgba/internal/sm83/debugger/memory-debugger.h>
13
14static struct mBreakpoint* _lookupBreakpoint(struct mBreakpointList* breakpoints, struct SM83Core* cpu) {
15 size_t i;
16 for (i = 0; i < mBreakpointListSize(breakpoints); ++i) {
17 struct mBreakpoint* breakpoint = mBreakpointListGetPointer(breakpoints, i);
18 if (breakpoint->address != cpu->pc) {
19 continue;
20 }
21 if (breakpoint->segment < 0 || breakpoint->segment == cpu->memory.currentSegment(cpu, breakpoint->address)) {
22 return breakpoint;
23 }
24 }
25 return NULL;
26}
27
28static void _destroyBreakpoint(struct mBreakpoint* breakpoint) {
29 if (breakpoint->condition) {
30 parseFree(breakpoint->condition);
31 free(breakpoint->condition);
32 }
33}
34
35static void _destroyWatchpoint(struct mWatchpoint* watchpoint) {
36 if (watchpoint->condition) {
37 parseFree(watchpoint->condition);
38 free(watchpoint->condition);
39 }
40}
41
42static void SM83DebuggerCheckBreakpoints(struct mDebuggerPlatform* d) {
43 struct SM83Debugger* debugger = (struct SM83Debugger*) d;
44 struct mBreakpoint* breakpoint = _lookupBreakpoint(&debugger->breakpoints, debugger->cpu);
45 if (!breakpoint) {
46 return;
47 }
48 if (breakpoint->condition) {
49 int32_t value;
50 int segment;
51 if (!mDebuggerEvaluateParseTree(d->p, breakpoint->condition, &value, &segment) || !(value || segment >= 0)) {
52 return;
53 }
54 }
55 struct mDebuggerEntryInfo info = {
56 .address = breakpoint->address,
57 .pointId = breakpoint->id
58 };
59 mDebuggerEnter(d->p, DEBUGGER_ENTER_BREAKPOINT, &info);
60}
61
62static void SM83DebuggerInit(void* cpu, struct mDebuggerPlatform* platform);
63static void SM83DebuggerDeinit(struct mDebuggerPlatform* platform);
64
65static void SM83DebuggerEnter(struct mDebuggerPlatform* d, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info);
66
67static ssize_t SM83DebuggerSetBreakpoint(struct mDebuggerPlatform*, const struct mBreakpoint*);
68static void SM83DebuggerListBreakpoints(struct mDebuggerPlatform*, struct mBreakpointList*);
69static bool SM83DebuggerClearBreakpoint(struct mDebuggerPlatform*, ssize_t id);
70static ssize_t SM83DebuggerSetWatchpoint(struct mDebuggerPlatform*, const struct mWatchpoint*);
71static void SM83DebuggerListWatchpoints(struct mDebuggerPlatform*, struct mWatchpointList*);
72static void SM83DebuggerCheckBreakpoints(struct mDebuggerPlatform*);
73static bool SM83DebuggerHasBreakpoints(struct mDebuggerPlatform*);
74static void SM83DebuggerTrace(struct mDebuggerPlatform*, char* out, size_t* length);
75static bool SM83DebuggerGetRegister(struct mDebuggerPlatform*, const char* name, int32_t* value);
76static bool SM83DebuggerSetRegister(struct mDebuggerPlatform*, const char* name, int32_t value);
77
78struct mDebuggerPlatform* SM83DebuggerPlatformCreate(void) {
79 struct SM83Debugger* platform = malloc(sizeof(struct SM83Debugger));
80 platform->d.entered = SM83DebuggerEnter;
81 platform->d.init = SM83DebuggerInit;
82 platform->d.deinit = SM83DebuggerDeinit;
83 platform->d.setBreakpoint = SM83DebuggerSetBreakpoint;
84 platform->d.listBreakpoints = SM83DebuggerListBreakpoints;
85 platform->d.clearBreakpoint = SM83DebuggerClearBreakpoint;
86 platform->d.setWatchpoint = SM83DebuggerSetWatchpoint;
87 platform->d.listWatchpoints = SM83DebuggerListWatchpoints;
88 platform->d.checkBreakpoints = SM83DebuggerCheckBreakpoints;
89 platform->d.hasBreakpoints = SM83DebuggerHasBreakpoints;
90 platform->d.trace = SM83DebuggerTrace;
91 platform->d.getRegister = SM83DebuggerGetRegister;
92 platform->d.setRegister = SM83DebuggerSetRegister;
93 platform->d.getStackTraceMode = NULL;
94 platform->d.setStackTraceMode = NULL;
95 platform->d.updateStackTrace = NULL;
96 platform->printStatus = NULL;
97 return &platform->d;
98}
99
100void SM83DebuggerInit(void* cpu, struct mDebuggerPlatform* platform) {
101 struct SM83Debugger* debugger = (struct SM83Debugger*) platform;
102 debugger->cpu = cpu;
103 debugger->originalMemory = debugger->cpu->memory;
104 mBreakpointListInit(&debugger->breakpoints, 0);
105 mWatchpointListInit(&debugger->watchpoints, 0);
106 debugger->nextId = 1;
107}
108
109void SM83DebuggerDeinit(struct mDebuggerPlatform* platform) {
110 struct SM83Debugger* debugger = (struct SM83Debugger*) platform;
111 size_t i;
112 for (i = 0; i < mBreakpointListSize(&debugger->breakpoints); ++i) {
113 _destroyBreakpoint(mBreakpointListGetPointer(&debugger->breakpoints, i));
114 }
115 mBreakpointListDeinit(&debugger->breakpoints);
116
117 for (i = 0; i < mWatchpointListSize(&debugger->watchpoints); ++i) {
118 _destroyWatchpoint(mWatchpointListGetPointer(&debugger->watchpoints, i));
119 }
120 mWatchpointListDeinit(&debugger->watchpoints);
121}
122
123static void SM83DebuggerEnter(struct mDebuggerPlatform* platform, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
124 UNUSED(reason);
125 UNUSED(info);
126 struct SM83Debugger* debugger = (struct SM83Debugger*) platform;
127 struct SM83Core* cpu = debugger->cpu;
128 cpu->nextEvent = cpu->cycles;
129
130 if (debugger->d.p->entered) {
131 debugger->d.p->entered(debugger->d.p, reason, info);
132 }
133}
134
135static ssize_t SM83DebuggerSetBreakpoint(struct mDebuggerPlatform* d, const struct mBreakpoint* info) {
136 struct SM83Debugger* debugger = (struct SM83Debugger*) d;
137 struct mBreakpoint* breakpoint = mBreakpointListAppend(&debugger->breakpoints);
138 *breakpoint = *info;
139 breakpoint->id = debugger->nextId;
140 ++debugger->nextId;
141 return breakpoint->id;
142
143}
144
145static bool SM83DebuggerClearBreakpoint(struct mDebuggerPlatform* d, ssize_t id) {
146 struct SM83Debugger* debugger = (struct SM83Debugger*) d;
147 size_t i;
148
149 struct mBreakpointList* breakpoints = &debugger->breakpoints;
150 for (i = 0; i < mBreakpointListSize(breakpoints); ++i) {
151 struct mBreakpoint* breakpoint = mBreakpointListGetPointer(breakpoints, i);
152 if (breakpoint->id == id) {
153 _destroyBreakpoint(breakpoint);
154 mBreakpointListShift(breakpoints, i, 1);
155 return true;
156 }
157 }
158
159 struct mWatchpointList* watchpoints = &debugger->watchpoints;
160 for (i = 0; i < mWatchpointListSize(watchpoints); ++i) {
161 struct mWatchpoint* watchpoint = mWatchpointListGetPointer(watchpoints, i);
162 if (watchpoint->id == id) {
163 _destroyWatchpoint(watchpoint);
164 mWatchpointListShift(watchpoints, i, 1);
165 if (!mWatchpointListSize(&debugger->watchpoints)) {
166 SM83DebuggerRemoveMemoryShim(debugger);
167 }
168 return true;
169 }
170 }
171 return false;
172}
173
174static bool SM83DebuggerHasBreakpoints(struct mDebuggerPlatform* d) {
175 struct SM83Debugger* debugger = (struct SM83Debugger*) d;
176 return mBreakpointListSize(&debugger->breakpoints) || mWatchpointListSize(&debugger->watchpoints);
177}
178
179static ssize_t SM83DebuggerSetWatchpoint(struct mDebuggerPlatform* d, const struct mWatchpoint* info) {
180 struct SM83Debugger* debugger = (struct SM83Debugger*) d;
181 if (!mWatchpointListSize(&debugger->watchpoints)) {
182 SM83DebuggerInstallMemoryShim(debugger);
183 }
184 struct mWatchpoint* watchpoint = mWatchpointListAppend(&debugger->watchpoints);
185 *watchpoint = *info;
186 watchpoint->id = debugger->nextId;
187 ++debugger->nextId;
188 return watchpoint->id;
189}
190
191static void SM83DebuggerListBreakpoints(struct mDebuggerPlatform* d, struct mBreakpointList* list) {
192 struct SM83Debugger* debugger = (struct SM83Debugger*) d;
193 mBreakpointListClear(list);
194 mBreakpointListCopy(list, &debugger->breakpoints);
195}
196
197static void SM83DebuggerListWatchpoints(struct mDebuggerPlatform* d, struct mWatchpointList* list) {
198 struct SM83Debugger* debugger = (struct SM83Debugger*) d;
199 mWatchpointListClear(list);
200 mWatchpointListCopy(list, &debugger->watchpoints);
201}
202
203static void SM83DebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* length) {
204 struct SM83Debugger* debugger = (struct SM83Debugger*) d;
205 struct SM83Core* cpu = debugger->cpu;
206
207 char disassembly[64];
208
209 struct SM83InstructionInfo info = {{0}};
210 char* disPtr = disassembly;
211 uint8_t instruction;
212 uint16_t address = cpu->pc;
213 size_t bytesRemaining = 1;
214 for (bytesRemaining = 1; bytesRemaining; --bytesRemaining) {
215 instruction = debugger->d.p->core->rawRead8(debugger->d.p->core, address, -1);
216 disPtr += snprintf(disPtr, sizeof(disassembly) - (disPtr - disassembly), "%02X", instruction);
217 ++address;
218 bytesRemaining += SM83Decode(instruction, &info);
219 };
220 disPtr[0] = ':';
221 disPtr[1] = ' ';
222 disPtr += 2;
223 SM83Disassemble(&info, address, disPtr, sizeof(disassembly) - (disPtr - disassembly));
224
225 *length = snprintf(out, *length, "A: %02X F: %02X B: %02X C: %02X D: %02X E: %02X H: %02X L: %02X SP: %04X PC: %02X:%04X | %s",
226 cpu->a, cpu->f.packed, cpu->b, cpu->c,
227 cpu->d, cpu->e, cpu->h, cpu->l,
228 cpu->sp, cpu->memory.currentSegment(cpu, cpu->pc), cpu->pc, disassembly);
229}
230
231bool SM83DebuggerGetRegister(struct mDebuggerPlatform* d, const char* name, int32_t* value) {
232 struct SM83Debugger* debugger = (struct SM83Debugger*) d;
233 struct SM83Core* cpu = debugger->cpu;
234
235 if (strcmp(name, "a") == 0) {
236 *value = cpu->a;
237 return true;
238 }
239 if (strcmp(name, "b") == 0) {
240 *value = cpu->b;
241 return true;
242 }
243 if (strcmp(name, "c") == 0) {
244 *value = cpu->c;
245 return true;
246 }
247 if (strcmp(name, "d") == 0) {
248 *value = cpu->d;
249 return true;
250 }
251 if (strcmp(name, "e") == 0) {
252 *value = cpu->e;
253 return true;
254 }
255 if (strcmp(name, "h") == 0) {
256 *value = cpu->h;
257 return true;
258 }
259 if (strcmp(name, "l") == 0) {
260 *value = cpu->l;
261 return true;
262 }
263 if (strcmp(name, "bc") == 0) {
264 *value = cpu->bc;
265 return true;
266 }
267 if (strcmp(name, "de") == 0) {
268 *value = cpu->de;
269 return true;
270 }
271 if (strcmp(name, "hl") == 0) {
272 *value = cpu->hl;
273 return true;
274 }
275 if (strcmp(name, "af") == 0) {
276 *value = cpu->af;
277 return true;
278 }
279 if (strcmp(name, "pc") == 0) {
280 *value = cpu->pc;
281 return true;
282 }
283 if (strcmp(name, "sp") == 0) {
284 *value = cpu->sp;
285 return true;
286 }
287 if (strcmp(name, "f") == 0) {
288 *value = cpu->f.packed;
289 return true;
290 }
291 return false;
292}
293
294bool SM83DebuggerSetRegister(struct mDebuggerPlatform* d, const char* name, int32_t value) {
295 struct SM83Debugger* debugger = (struct SM83Debugger*) d;
296 struct SM83Core* cpu = debugger->cpu;
297
298 if (strcmp(name, "a") == 0) {
299 cpu->a = value;
300 return true;
301 }
302 if (strcmp(name, "b") == 0) {
303 cpu->b = value;
304 return true;
305 }
306 if (strcmp(name, "c") == 0) {
307 cpu->c = value;
308 return true;
309 }
310 if (strcmp(name, "d") == 0) {
311 cpu->d = value;
312 return true;
313 }
314 if (strcmp(name, "e") == 0) {
315 cpu->e = value;
316 return true;
317 }
318 if (strcmp(name, "h") == 0) {
319 cpu->h = value;
320 return true;
321 }
322 if (strcmp(name, "l") == 0) {
323 cpu->l = value;
324 return true;
325 }
326 if (strcmp(name, "bc") == 0) {
327 cpu->bc = value;
328 return true;
329 }
330 if (strcmp(name, "de") == 0) {
331 cpu->de = value;
332 return true;
333 }
334 if (strcmp(name, "hl") == 0) {
335 cpu->hl = value;
336 return true;
337 }
338 if (strcmp(name, "af") == 0) {
339 cpu->af = value;
340 cpu->f.packed &= 0xF0;
341 return true;
342 }
343 if (strcmp(name, "pc") == 0) {
344 cpu->pc = value;
345 cpu->memory.setActiveRegion(cpu, cpu->pc);
346 return true;
347 }
348 if (strcmp(name, "sp") == 0) {
349 cpu->sp = value;
350 return true;
351 }
352 if (strcmp(name, "f") == 0) {
353 cpu->f.packed = value & 0xF0;
354 return true;
355 }
356 return false;
357}