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/debugger/parser.h>
10#include <mgba/internal/lr35902/decoder.h>
11#include <mgba/internal/lr35902/lr35902.h>
12#include <mgba/internal/lr35902/debugger/memory-debugger.h>
13
14static struct mBreakpoint* _lookupBreakpoint(struct mBreakpointList* breakpoints, struct LR35902Core* 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 LR35902DebuggerCheckBreakpoints(struct mDebuggerPlatform* d) {
43 struct LR35902Debugger* debugger = (struct LR35902Debugger*) 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 };
58 mDebuggerEnter(d->p, DEBUGGER_ENTER_BREAKPOINT, &info);
59}
60
61static void LR35902DebuggerInit(void* cpu, struct mDebuggerPlatform* platform);
62static void LR35902DebuggerDeinit(struct mDebuggerPlatform* platform);
63
64static void LR35902DebuggerEnter(struct mDebuggerPlatform* d, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info);
65
66static ssize_t LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform*, const struct mBreakpoint*);
67static void LR35902DebuggerListBreakpoints(struct mDebuggerPlatform*, struct mBreakpointList*);
68static bool LR35902DebuggerClearBreakpoint(struct mDebuggerPlatform*, ssize_t id);
69static ssize_t LR35902DebuggerSetWatchpoint(struct mDebuggerPlatform*, const struct mWatchpoint*);
70static void LR35902DebuggerListWatchpoints(struct mDebuggerPlatform*, struct mWatchpointList*);
71static void LR35902DebuggerCheckBreakpoints(struct mDebuggerPlatform*);
72static bool LR35902DebuggerHasBreakpoints(struct mDebuggerPlatform*);
73static void LR35902DebuggerTrace(struct mDebuggerPlatform*, char* out, size_t* length);
74static bool LR35902DebuggerGetRegister(struct mDebuggerPlatform*, const char* name, int32_t* value);
75static bool LR35902DebuggerSetRegister(struct mDebuggerPlatform*, const char* name, int32_t value);
76
77struct mDebuggerPlatform* LR35902DebuggerPlatformCreate(void) {
78 struct LR35902Debugger* platform = malloc(sizeof(struct LR35902Debugger));
79 platform->d.entered = LR35902DebuggerEnter;
80 platform->d.init = LR35902DebuggerInit;
81 platform->d.deinit = LR35902DebuggerDeinit;
82 platform->d.setBreakpoint = LR35902DebuggerSetBreakpoint;
83 platform->d.listBreakpoints = LR35902DebuggerListBreakpoints;
84 platform->d.clearBreakpoint = LR35902DebuggerClearBreakpoint;
85 platform->d.setWatchpoint = LR35902DebuggerSetWatchpoint;
86 platform->d.listWatchpoints = LR35902DebuggerListWatchpoints;
87 platform->d.checkBreakpoints = LR35902DebuggerCheckBreakpoints;
88 platform->d.hasBreakpoints = LR35902DebuggerHasBreakpoints;
89 platform->d.trace = LR35902DebuggerTrace;
90 platform->d.getRegister = LR35902DebuggerGetRegister;
91 platform->d.setRegister = LR35902DebuggerSetRegister;
92 platform->printStatus = NULL;
93 return &platform->d;
94}
95
96void LR35902DebuggerInit(void* cpu, struct mDebuggerPlatform* platform) {
97 struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform;
98 debugger->cpu = cpu;
99 debugger->originalMemory = debugger->cpu->memory;
100 mBreakpointListInit(&debugger->breakpoints, 0);
101 mWatchpointListInit(&debugger->watchpoints, 0);
102 debugger->nextId = 1;
103}
104
105void LR35902DebuggerDeinit(struct mDebuggerPlatform* platform) {
106 struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform;
107 size_t i;
108 for (i = 0; i < mBreakpointListSize(&debugger->breakpoints); ++i) {
109 _destroyBreakpoint(mBreakpointListGetPointer(&debugger->breakpoints, i));
110 }
111 mBreakpointListDeinit(&debugger->breakpoints);
112
113 for (i = 0; i < mWatchpointListSize(&debugger->watchpoints); ++i) {
114 _destroyWatchpoint(mWatchpointListGetPointer(&debugger->watchpoints, i));
115 }
116 mWatchpointListDeinit(&debugger->watchpoints);
117}
118
119static void LR35902DebuggerEnter(struct mDebuggerPlatform* platform, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
120 UNUSED(reason);
121 UNUSED(info);
122 struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform;
123 struct LR35902Core* cpu = debugger->cpu;
124 cpu->nextEvent = cpu->cycles;
125
126 if (debugger->d.p->entered) {
127 debugger->d.p->entered(debugger->d.p, reason, info);
128 }
129}
130
131static ssize_t LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform* d, const struct mBreakpoint* info) {
132 struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
133 struct mBreakpoint* breakpoint = mBreakpointListAppend(&debugger->breakpoints);
134 *breakpoint = *info;
135 breakpoint->id = debugger->nextId;
136 ++debugger->nextId;
137 return breakpoint->id;
138
139}
140
141static bool LR35902DebuggerClearBreakpoint(struct mDebuggerPlatform* d, ssize_t id) {
142 struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
143 size_t i;
144
145 struct mBreakpointList* breakpoints = &debugger->breakpoints;
146 for (i = 0; i < mBreakpointListSize(breakpoints); ++i) {
147 struct mBreakpoint* breakpoint = mBreakpointListGetPointer(breakpoints, i);
148 if (breakpoint->id == id) {
149 _destroyBreakpoint(breakpoint);
150 mBreakpointListShift(breakpoints, i, 1);
151 return true;
152 }
153 }
154
155 struct mWatchpointList* watchpoints = &debugger->watchpoints;
156 for (i = 0; i < mWatchpointListSize(watchpoints); ++i) {
157 struct mWatchpoint* watchpoint = mWatchpointListGetPointer(watchpoints, i);
158 if (watchpoint->id == id) {
159 _destroyWatchpoint(watchpoint);
160 mWatchpointListShift(watchpoints, i, 1);
161 if (!mWatchpointListSize(&debugger->watchpoints)) {
162 LR35902DebuggerRemoveMemoryShim(debugger);
163 }
164 return true;
165 }
166 }
167 return false;
168}
169
170static bool LR35902DebuggerHasBreakpoints(struct mDebuggerPlatform* d) {
171 struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
172 return mBreakpointListSize(&debugger->breakpoints) || mWatchpointListSize(&debugger->watchpoints);
173}
174
175static ssize_t LR35902DebuggerSetWatchpoint(struct mDebuggerPlatform* d, const struct mWatchpoint* info) {
176 struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
177 if (!mWatchpointListSize(&debugger->watchpoints)) {
178 LR35902DebuggerInstallMemoryShim(debugger);
179 }
180 struct mWatchpoint* watchpoint = mWatchpointListAppend(&debugger->watchpoints);
181 *watchpoint = *info;
182 watchpoint->id = debugger->nextId;
183 ++debugger->nextId;
184 return watchpoint->id;
185}
186
187static void LR35902DebuggerListBreakpoints(struct mDebuggerPlatform* d, struct mBreakpointList* list) {
188 struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
189 mBreakpointListClear(list);
190 mBreakpointListCopy(list, &debugger->breakpoints);
191}
192
193static void LR35902DebuggerListWatchpoints(struct mDebuggerPlatform* d, struct mWatchpointList* list) {
194 struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
195 mWatchpointListClear(list);
196 mWatchpointListCopy(list, &debugger->watchpoints);
197}
198
199static void LR35902DebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* length) {
200 struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
201 struct LR35902Core* cpu = debugger->cpu;
202
203 char disassembly[64];
204
205 struct LR35902InstructionInfo info = {{0}};
206 char* disPtr = disassembly;
207 uint8_t instruction;
208 uint16_t address = cpu->pc;
209 size_t bytesRemaining = 1;
210 for (bytesRemaining = 1; bytesRemaining; --bytesRemaining) {
211 instruction = debugger->d.p->core->rawRead8(debugger->d.p->core, address, -1);
212 disPtr += snprintf(disPtr, sizeof(disassembly) - (disPtr - disassembly), "%02X", instruction);
213 ++address;
214 bytesRemaining += LR35902Decode(instruction, &info);
215 };
216 disPtr[0] = ':';
217 disPtr[1] = ' ';
218 disPtr += 2;
219 LR35902Disassemble(&info, address, disPtr, sizeof(disassembly) - (disPtr - disassembly));
220
221 *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",
222 cpu->a, cpu->f.packed, cpu->b, cpu->c,
223 cpu->d, cpu->e, cpu->h, cpu->l,
224 cpu->sp, cpu->memory.currentSegment(cpu, cpu->pc), cpu->pc, disassembly);
225}
226
227bool LR35902DebuggerGetRegister(struct mDebuggerPlatform* d, const char* name, int32_t* value) {
228 struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
229 struct LR35902Core* cpu = debugger->cpu;
230
231 if (strcmp(name, "a") == 0) {
232 *value = cpu->a;
233 return true;
234 }
235 if (strcmp(name, "b") == 0) {
236 *value = cpu->b;
237 return true;
238 }
239 if (strcmp(name, "c") == 0) {
240 *value = cpu->c;
241 return true;
242 }
243 if (strcmp(name, "d") == 0) {
244 *value = cpu->d;
245 return true;
246 }
247 if (strcmp(name, "e") == 0) {
248 *value = cpu->e;
249 return true;
250 }
251 if (strcmp(name, "h") == 0) {
252 *value = cpu->h;
253 return true;
254 }
255 if (strcmp(name, "l") == 0) {
256 *value = cpu->l;
257 return true;
258 }
259 if (strcmp(name, "bc") == 0) {
260 *value = cpu->bc;
261 return true;
262 }
263 if (strcmp(name, "de") == 0) {
264 *value = cpu->de;
265 return true;
266 }
267 if (strcmp(name, "hl") == 0) {
268 *value = cpu->hl;
269 return true;
270 }
271 if (strcmp(name, "af") == 0) {
272 *value = cpu->af;
273 return true;
274 }
275 if (strcmp(name, "pc") == 0) {
276 *value = cpu->pc;
277 return true;
278 }
279 if (strcmp(name, "sp") == 0) {
280 *value = cpu->sp;
281 return true;
282 }
283 if (strcmp(name, "f") == 0) {
284 *value = cpu->f.packed;
285 return true;
286 }
287 return false;
288}
289
290bool LR35902DebuggerSetRegister(struct mDebuggerPlatform* d, const char* name, int32_t value) {
291 struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
292 struct LR35902Core* cpu = debugger->cpu;
293
294 if (strcmp(name, "a") == 0) {
295 cpu->a = value;
296 return true;
297 }
298 if (strcmp(name, "b") == 0) {
299 cpu->b = value;
300 return true;
301 }
302 if (strcmp(name, "c") == 0) {
303 cpu->c = value;
304 return true;
305 }
306 if (strcmp(name, "d") == 0) {
307 cpu->d = value;
308 return true;
309 }
310 if (strcmp(name, "e") == 0) {
311 cpu->e = value;
312 return true;
313 }
314 if (strcmp(name, "h") == 0) {
315 cpu->h = value;
316 return true;
317 }
318 if (strcmp(name, "l") == 0) {
319 cpu->l = value;
320 return true;
321 }
322 if (strcmp(name, "bc") == 0) {
323 cpu->bc = value;
324 return true;
325 }
326 if (strcmp(name, "de") == 0) {
327 cpu->de = value;
328 return true;
329 }
330 if (strcmp(name, "hl") == 0) {
331 cpu->hl = value;
332 return true;
333 }
334 if (strcmp(name, "af") == 0) {
335 cpu->af = value;
336 cpu->f.packed &= 0xF0;
337 return true;
338 }
339 if (strcmp(name, "pc") == 0) {
340 cpu->pc = value;
341 cpu->memory.setActiveRegion(cpu, cpu->pc);
342 return true;
343 }
344 if (strcmp(name, "sp") == 0) {
345 cpu->sp = value;
346 return true;
347 }
348 if (strcmp(name, "f") == 0) {
349 cpu->f.packed = value & 0xF0;
350 return true;
351 }
352 return false;
353}