all repos — mgba @ a31e13f2d862c8119cbea9fe4b41f0f0403e1949

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