all repos — mgba @ f2134880898dd3ceaba7945c992c8ff34e245682

mGBA Game Boy Advance Emulator

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}