all repos — mgba @ 00cbb6156ba020772fb44d6678d3b9142695c854

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	debugger->originalMemory = debugger->cpu->memory;
103	LR35902DebugBreakpointListInit(&debugger->breakpoints, 0);
104	LR35902DebugWatchpointListInit(&debugger->watchpoints, 0);
105}
106
107void LR35902DebuggerDeinit(struct mDebuggerPlatform* platform) {
108	struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform;
109	size_t i;
110	for (i = 0; i < LR35902DebugBreakpointListSize(&debugger->breakpoints); ++i) {
111		_destroyBreakpoint(LR35902DebugBreakpointListGetPointer(&debugger->breakpoints, i));
112	}
113	LR35902DebugBreakpointListDeinit(&debugger->breakpoints);
114
115	for (i = 0; i < LR35902DebugWatchpointListSize(&debugger->watchpoints); ++i) {
116		_destroyWatchpoint(LR35902DebugWatchpointListGetPointer(&debugger->watchpoints, i));
117	}
118	LR35902DebugWatchpointListDeinit(&debugger->watchpoints);
119}
120
121static void LR35902DebuggerEnter(struct mDebuggerPlatform* platform, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
122	UNUSED(reason);
123	UNUSED(info);
124	struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform;
125	struct LR35902Core* cpu = debugger->cpu;
126	cpu->nextEvent = cpu->cycles;
127
128	if (debugger->d.p->entered) {
129		debugger->d.p->entered(debugger->d.p, reason, info);
130	}
131}
132
133static void LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
134	LR35902DebuggerSetConditionalBreakpoint(d, address, segment, NULL);
135}
136
137static void LR35902DebuggerSetConditionalBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, struct ParseTree* condition) {
138	struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
139	struct LR35902DebugBreakpoint* breakpoint = LR35902DebugBreakpointListAppend(&debugger->breakpoints);
140	breakpoint->address = address;
141	breakpoint->segment = segment;
142	breakpoint->condition = condition;
143}
144
145static void LR35902DebuggerClearBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
146	struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
147	struct LR35902DebugBreakpointList* breakpoints = &debugger->breakpoints;
148	size_t i;
149	for (i = 0; i < LR35902DebugBreakpointListSize(breakpoints); ++i) {
150		struct LR35902DebugBreakpoint* breakpoint = LR35902DebugBreakpointListGetPointer(breakpoints, i);
151		if (breakpoint->address == address && breakpoint->segment == segment) {
152			_destroyBreakpoint(LR35902DebugBreakpointListGetPointer(breakpoints, i));
153			LR35902DebugBreakpointListShift(breakpoints, i, 1);
154		}
155	}
156}
157
158static bool LR35902DebuggerHasBreakpoints(struct mDebuggerPlatform* d) {
159	struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
160	return LR35902DebugBreakpointListSize(&debugger->breakpoints) || LR35902DebugWatchpointListSize(&debugger->watchpoints);
161}
162
163static void LR35902DebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, enum mWatchpointType type) {
164	LR35902DebuggerSetConditionalWatchpoint(d, address, segment, type, NULL);
165}
166
167static void LR35902DebuggerSetConditionalWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, enum mWatchpointType type, struct ParseTree* condition) {
168	struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
169	if (!LR35902DebugWatchpointListSize(&debugger->watchpoints)) {
170		LR35902DebuggerInstallMemoryShim(debugger);
171	}
172	struct LR35902DebugWatchpoint* watchpoint = LR35902DebugWatchpointListAppend(&debugger->watchpoints);
173	watchpoint->address = address;
174	watchpoint->type = type;
175	watchpoint->segment = segment;
176	watchpoint->condition = condition;
177}
178
179static void LR35902DebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
180	struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
181	struct LR35902DebugWatchpointList* watchpoints = &debugger->watchpoints;
182	size_t i;
183	for (i = 0; i < LR35902DebugWatchpointListSize(watchpoints); ++i) {
184		struct LR35902DebugWatchpoint* watchpoint = LR35902DebugWatchpointListGetPointer(watchpoints, i);
185		if (watchpoint->address == address && watchpoint->segment == segment) {
186			LR35902DebugWatchpointListShift(watchpoints, i, 1);
187		}
188	}
189	if (!LR35902DebugWatchpointListSize(&debugger->watchpoints)) {
190		LR35902DebuggerRemoveMemoryShim(debugger);
191	}
192}
193
194static void LR35902DebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* length) {
195	struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
196	struct LR35902Core* cpu = debugger->cpu;
197
198	char disassembly[64];
199
200	struct LR35902InstructionInfo info = {{0}};
201	char* disPtr = disassembly;
202	uint8_t instruction;
203	uint16_t address = cpu->pc;
204	size_t bytesRemaining = 1;
205	for (bytesRemaining = 1; bytesRemaining; --bytesRemaining) {
206		instruction = debugger->d.p->core->rawRead8(debugger->d.p->core, address, -1);
207		disPtr += snprintf(disPtr, sizeof(disassembly) - (disPtr - disassembly), "%02X", instruction);
208		++address;
209		bytesRemaining += LR35902Decode(instruction, &info);
210	};
211	disPtr[0] = ':';
212	disPtr[1] = ' ';
213	disPtr += 2;
214	LR35902Disassemble(&info, disPtr, sizeof(disassembly) - (disPtr - disassembly));
215
216	*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",
217		               cpu->a, cpu->f.packed, cpu->b, cpu->c,
218		               cpu->d, cpu->e, cpu->h, cpu->l,
219		               cpu->sp, cpu->pc, disassembly);
220}
221
222bool LR35902DebuggerGetRegister(struct mDebuggerPlatform* d, const char* name, int32_t* value) {
223	struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
224	struct LR35902Core* cpu = debugger->cpu;
225
226	if (strcmp(name, "a") == 0) {
227		*value = cpu->a;
228		return true;
229	}
230	if (strcmp(name, "b") == 0) {
231		*value = cpu->b;
232		return true;
233	}
234	if (strcmp(name, "c") == 0) {
235		*value = cpu->c;
236		return true;
237	}
238	if (strcmp(name, "d") == 0) {
239		*value = cpu->d;
240		return true;
241	}
242	if (strcmp(name, "e") == 0) {
243		*value = cpu->e;
244		return true;
245	}
246	if (strcmp(name, "h") == 0) {
247		*value = cpu->h;
248		return true;
249	}
250	if (strcmp(name, "l") == 0) {
251		*value = cpu->l;
252		return true;
253	}
254	if (strcmp(name, "bc") == 0) {
255		*value = cpu->bc;
256		return true;
257	}
258	if (strcmp(name, "de") == 0) {
259		*value = cpu->de;
260		return true;
261	}
262	if (strcmp(name, "hl") == 0) {
263		*value = cpu->hl;
264		return true;
265	}
266	if (strcmp(name, "af") == 0) {
267		*value = cpu->af;
268		return true;
269	}
270	if (strcmp(name, "pc") == 0) {
271		*value = cpu->pc;
272		return true;
273	}
274	if (strcmp(name, "sp") == 0) {
275		*value = cpu->sp;
276		return true;
277	}
278	if (strcmp(name, "f") == 0) {
279		*value = cpu->f.packed;
280		return true;
281	}
282	return false;
283}
284
285bool LR35902DebuggerSetRegister(struct mDebuggerPlatform* d, const char* name, int32_t value) {
286	struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
287	struct LR35902Core* cpu = debugger->cpu;
288
289	if (strcmp(name, "a") == 0) {
290		cpu->a = value;
291		return true;
292	}
293	if (strcmp(name, "b") == 0) {
294		cpu->b = value;
295		return true;
296	}
297	if (strcmp(name, "c") == 0) {
298		cpu->c = value;
299		return true;
300	}
301	if (strcmp(name, "d") == 0) {
302		cpu->d = value;
303		return true;
304	}
305	if (strcmp(name, "e") == 0) {
306		cpu->e = value;
307		return true;
308	}
309	if (strcmp(name, "h") == 0) {
310		cpu->h = value;
311		return true;
312	}
313	if (strcmp(name, "l") == 0) {
314		cpu->l = value;
315		return true;
316	}
317	if (strcmp(name, "bc") == 0) {
318		cpu->bc = value;
319		return true;
320	}
321	if (strcmp(name, "de") == 0) {
322		cpu->de = value;
323		return true;
324	}
325	if (strcmp(name, "hl") == 0) {
326		cpu->hl = value;
327		return true;
328	}
329	if (strcmp(name, "af") == 0) {
330		cpu->af = value;
331		cpu->f.packed &= 0xF0;
332		return true;
333	}
334	if (strcmp(name, "pc") == 0) {
335		cpu->pc = value;
336		cpu->memory.setActiveRegion(cpu, cpu->pc);
337		return true;
338	}
339	if (strcmp(name, "sp") == 0) {
340		cpu->sp = value;
341		return true;
342	}
343	if (strcmp(name, "f") == 0) {
344		cpu->f.packed = value & 0xF0;
345		return true;
346	}
347	return false;
348}