all repos — mgba @ e655e0d9254dca7df6c4d4d2efa06a9ada56c977

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