all repos — mgba @ 0383c82b469e7ca38832f66d07418cd890ea68a5

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