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