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