all repos — mgba @ d6ac0dc6f526ac111c4e750e282050c034724b76

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 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}