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->printStatus = NULL;
94 return &platform->d;
95}
96
97void SM83DebuggerInit(void* cpu, struct mDebuggerPlatform* platform) {
98 struct SM83Debugger* debugger = (struct SM83Debugger*) platform;
99 debugger->cpu = cpu;
100 debugger->originalMemory = debugger->cpu->memory;
101 mBreakpointListInit(&debugger->breakpoints, 0);
102 mWatchpointListInit(&debugger->watchpoints, 0);
103 debugger->nextId = 1;
104}
105
106void SM83DebuggerDeinit(struct mDebuggerPlatform* platform) {
107 struct SM83Debugger* debugger = (struct SM83Debugger*) platform;
108 size_t i;
109 for (i = 0; i < mBreakpointListSize(&debugger->breakpoints); ++i) {
110 _destroyBreakpoint(mBreakpointListGetPointer(&debugger->breakpoints, i));
111 }
112 mBreakpointListDeinit(&debugger->breakpoints);
113
114 for (i = 0; i < mWatchpointListSize(&debugger->watchpoints); ++i) {
115 _destroyWatchpoint(mWatchpointListGetPointer(&debugger->watchpoints, i));
116 }
117 mWatchpointListDeinit(&debugger->watchpoints);
118}
119
120static void SM83DebuggerEnter(struct mDebuggerPlatform* platform, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
121 UNUSED(reason);
122 UNUSED(info);
123 struct SM83Debugger* debugger = (struct SM83Debugger*) platform;
124 struct SM83Core* cpu = debugger->cpu;
125 cpu->nextEvent = cpu->cycles;
126
127 if (debugger->d.p->entered) {
128 debugger->d.p->entered(debugger->d.p, reason, info);
129 }
130}
131
132static ssize_t SM83DebuggerSetBreakpoint(struct mDebuggerPlatform* d, const struct mBreakpoint* info) {
133 struct SM83Debugger* debugger = (struct SM83Debugger*) d;
134 struct mBreakpoint* breakpoint = mBreakpointListAppend(&debugger->breakpoints);
135 *breakpoint = *info;
136 breakpoint->id = debugger->nextId;
137 ++debugger->nextId;
138 return breakpoint->id;
139
140}
141
142static bool SM83DebuggerClearBreakpoint(struct mDebuggerPlatform* d, ssize_t id) {
143 struct SM83Debugger* debugger = (struct SM83Debugger*) d;
144 size_t i;
145
146 struct mBreakpointList* breakpoints = &debugger->breakpoints;
147 for (i = 0; i < mBreakpointListSize(breakpoints); ++i) {
148 struct mBreakpoint* breakpoint = mBreakpointListGetPointer(breakpoints, i);
149 if (breakpoint->id == id) {
150 _destroyBreakpoint(breakpoint);
151 mBreakpointListShift(breakpoints, i, 1);
152 return true;
153 }
154 }
155
156 struct mWatchpointList* watchpoints = &debugger->watchpoints;
157 for (i = 0; i < mWatchpointListSize(watchpoints); ++i) {
158 struct mWatchpoint* watchpoint = mWatchpointListGetPointer(watchpoints, i);
159 if (watchpoint->id == id) {
160 _destroyWatchpoint(watchpoint);
161 mWatchpointListShift(watchpoints, i, 1);
162 if (!mWatchpointListSize(&debugger->watchpoints)) {
163 SM83DebuggerRemoveMemoryShim(debugger);
164 }
165 return true;
166 }
167 }
168 return false;
169}
170
171static bool SM83DebuggerHasBreakpoints(struct mDebuggerPlatform* d) {
172 struct SM83Debugger* debugger = (struct SM83Debugger*) d;
173 return mBreakpointListSize(&debugger->breakpoints) || mWatchpointListSize(&debugger->watchpoints);
174}
175
176static ssize_t SM83DebuggerSetWatchpoint(struct mDebuggerPlatform* d, const struct mWatchpoint* info) {
177 struct SM83Debugger* debugger = (struct SM83Debugger*) d;
178 if (!mWatchpointListSize(&debugger->watchpoints)) {
179 SM83DebuggerInstallMemoryShim(debugger);
180 }
181 struct mWatchpoint* watchpoint = mWatchpointListAppend(&debugger->watchpoints);
182 *watchpoint = *info;
183 watchpoint->id = debugger->nextId;
184 ++debugger->nextId;
185 return watchpoint->id;
186}
187
188static void SM83DebuggerListBreakpoints(struct mDebuggerPlatform* d, struct mBreakpointList* list) {
189 struct SM83Debugger* debugger = (struct SM83Debugger*) d;
190 mBreakpointListClear(list);
191 mBreakpointListCopy(list, &debugger->breakpoints);
192}
193
194static void SM83DebuggerListWatchpoints(struct mDebuggerPlatform* d, struct mWatchpointList* list) {
195 struct SM83Debugger* debugger = (struct SM83Debugger*) d;
196 mWatchpointListClear(list);
197 mWatchpointListCopy(list, &debugger->watchpoints);
198}
199
200static void SM83DebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* length) {
201 struct SM83Debugger* debugger = (struct SM83Debugger*) d;
202 struct SM83Core* cpu = debugger->cpu;
203
204 char disassembly[64];
205
206 struct SM83InstructionInfo info = {{0}};
207 char* disPtr = disassembly;
208 uint8_t instruction;
209 uint16_t address = cpu->pc;
210 size_t bytesRemaining = 1;
211 for (bytesRemaining = 1; bytesRemaining; --bytesRemaining) {
212 instruction = debugger->d.p->core->rawRead8(debugger->d.p->core, address, -1);
213 disPtr += snprintf(disPtr, sizeof(disassembly) - (disPtr - disassembly), "%02X", instruction);
214 ++address;
215 bytesRemaining += SM83Decode(instruction, &info);
216 };
217 disPtr[0] = ':';
218 disPtr[1] = ' ';
219 disPtr += 2;
220 SM83Disassemble(&info, address, disPtr, sizeof(disassembly) - (disPtr - disassembly));
221
222 *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",
223 cpu->a, cpu->f.packed, cpu->b, cpu->c,
224 cpu->d, cpu->e, cpu->h, cpu->l,
225 cpu->sp, cpu->memory.currentSegment(cpu, cpu->pc), cpu->pc, disassembly);
226}
227
228bool SM83DebuggerGetRegister(struct mDebuggerPlatform* d, const char* name, int32_t* value) {
229 struct SM83Debugger* debugger = (struct SM83Debugger*) d;
230 struct SM83Core* cpu = debugger->cpu;
231
232 if (strcmp(name, "a") == 0) {
233 *value = cpu->a;
234 return true;
235 }
236 if (strcmp(name, "b") == 0) {
237 *value = cpu->b;
238 return true;
239 }
240 if (strcmp(name, "c") == 0) {
241 *value = cpu->c;
242 return true;
243 }
244 if (strcmp(name, "d") == 0) {
245 *value = cpu->d;
246 return true;
247 }
248 if (strcmp(name, "e") == 0) {
249 *value = cpu->e;
250 return true;
251 }
252 if (strcmp(name, "h") == 0) {
253 *value = cpu->h;
254 return true;
255 }
256 if (strcmp(name, "l") == 0) {
257 *value = cpu->l;
258 return true;
259 }
260 if (strcmp(name, "bc") == 0) {
261 *value = cpu->bc;
262 return true;
263 }
264 if (strcmp(name, "de") == 0) {
265 *value = cpu->de;
266 return true;
267 }
268 if (strcmp(name, "hl") == 0) {
269 *value = cpu->hl;
270 return true;
271 }
272 if (strcmp(name, "af") == 0) {
273 *value = cpu->af;
274 return true;
275 }
276 if (strcmp(name, "pc") == 0) {
277 *value = cpu->pc;
278 return true;
279 }
280 if (strcmp(name, "sp") == 0) {
281 *value = cpu->sp;
282 return true;
283 }
284 if (strcmp(name, "f") == 0) {
285 *value = cpu->f.packed;
286 return true;
287 }
288 return false;
289}
290
291bool SM83DebuggerSetRegister(struct mDebuggerPlatform* d, const char* name, int32_t value) {
292 struct SM83Debugger* debugger = (struct SM83Debugger*) d;
293 struct SM83Core* cpu = debugger->cpu;
294
295 if (strcmp(name, "a") == 0) {
296 cpu->a = value;
297 return true;
298 }
299 if (strcmp(name, "b") == 0) {
300 cpu->b = value;
301 return true;
302 }
303 if (strcmp(name, "c") == 0) {
304 cpu->c = value;
305 return true;
306 }
307 if (strcmp(name, "d") == 0) {
308 cpu->d = value;
309 return true;
310 }
311 if (strcmp(name, "e") == 0) {
312 cpu->e = value;
313 return true;
314 }
315 if (strcmp(name, "h") == 0) {
316 cpu->h = value;
317 return true;
318 }
319 if (strcmp(name, "l") == 0) {
320 cpu->l = value;
321 return true;
322 }
323 if (strcmp(name, "bc") == 0) {
324 cpu->bc = value;
325 return true;
326 }
327 if (strcmp(name, "de") == 0) {
328 cpu->de = value;
329 return true;
330 }
331 if (strcmp(name, "hl") == 0) {
332 cpu->hl = value;
333 return true;
334 }
335 if (strcmp(name, "af") == 0) {
336 cpu->af = value;
337 cpu->f.packed &= 0xF0;
338 return true;
339 }
340 if (strcmp(name, "pc") == 0) {
341 cpu->pc = value;
342 cpu->memory.setActiveRegion(cpu, cpu->pc);
343 return true;
344 }
345 if (strcmp(name, "sp") == 0) {
346 cpu->sp = value;
347 return true;
348 }
349 if (strcmp(name, "f") == 0) {
350 cpu->f.packed = value & 0xF0;
351 return true;
352 }
353 return false;
354}