all repos — mgba @ 51a122f20d45119f34cca7e920c0eb9dacc15902

mGBA Game Boy Advance Emulator

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}