all repos — mgba @ a2447d09e3e0bacaf8e8c0b750fac18f13de4fdf

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);
 53
 54struct mDebuggerPlatform* LR35902DebuggerPlatformCreate(void) {
 55	struct mDebuggerPlatform* platform = (struct mDebuggerPlatform*) malloc(sizeof(struct LR35902Debugger));
 56	platform->entered = LR35902DebuggerEnter;
 57	platform->init = LR35902DebuggerInit;
 58	platform->deinit = LR35902DebuggerDeinit;
 59	platform->setBreakpoint = LR35902DebuggerSetBreakpoint;
 60	platform->clearBreakpoint = LR35902DebuggerClearBreakpoint;
 61	platform->setWatchpoint = LR35902DebuggerSetWatchpoint;
 62	platform->clearWatchpoint = LR35902DebuggerClearWatchpoint;
 63	platform->checkBreakpoints = LR35902DebuggerCheckBreakpoints;
 64	platform->hasBreakpoints = LR35902DebuggerHasBreakpoints;
 65	platform->trace = LR35902DebuggerTrace;
 66	return platform;
 67}
 68
 69void LR35902DebuggerInit(void* cpu, struct mDebuggerPlatform* platform) {
 70	struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform;
 71	debugger->cpu = cpu;
 72	LR35902DebugBreakpointListInit(&debugger->breakpoints, 0);
 73	LR35902DebugWatchpointListInit(&debugger->watchpoints, 0);
 74}
 75
 76void LR35902DebuggerDeinit(struct mDebuggerPlatform* platform) {
 77	struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform;
 78	LR35902DebugBreakpointListDeinit(&debugger->breakpoints);
 79	LR35902DebugWatchpointListDeinit(&debugger->watchpoints);
 80}
 81
 82static void LR35902DebuggerEnter(struct mDebuggerPlatform* platform, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
 83	UNUSED(reason);
 84	UNUSED(info);
 85	struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform;
 86	struct LR35902Core* cpu = debugger->cpu;
 87	cpu->nextEvent = cpu->cycles;
 88
 89	if (debugger->d.p->entered) {
 90		debugger->d.p->entered(debugger->d.p, reason, info);
 91	}
 92}
 93
 94static void LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
 95	struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
 96	struct LR35902DebugBreakpoint* breakpoint = LR35902DebugBreakpointListAppend(&debugger->breakpoints);
 97	breakpoint->address = address;
 98	breakpoint->segment = segment;
 99}
100
101static void LR35902DebuggerClearBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
102	struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
103	struct LR35902DebugBreakpointList* breakpoints = &debugger->breakpoints;
104	size_t i;
105	for (i = 0; i < LR35902DebugBreakpointListSize(breakpoints); ++i) {
106		struct LR35902DebugBreakpoint* breakpoint = LR35902DebugBreakpointListGetPointer(breakpoints, i);
107		if (breakpoint->address == address && breakpoint->segment == segment) {
108			LR35902DebugBreakpointListShift(breakpoints, i, 1);
109		}
110	}
111}
112
113static bool LR35902DebuggerHasBreakpoints(struct mDebuggerPlatform* d) {
114	struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
115	return LR35902DebugBreakpointListSize(&debugger->breakpoints) || LR35902DebugWatchpointListSize(&debugger->watchpoints);
116}
117
118static void LR35902DebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, enum mWatchpointType type) {
119	struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
120	if (!LR35902DebugWatchpointListSize(&debugger->watchpoints)) {
121		LR35902DebuggerInstallMemoryShim(debugger);
122	}
123	struct LR35902DebugWatchpoint* watchpoint = LR35902DebugWatchpointListAppend(&debugger->watchpoints);
124	watchpoint->address = address;
125	watchpoint->type = type;
126	watchpoint->segment = segment;
127}
128
129static void LR35902DebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
130	struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
131	struct LR35902DebugWatchpointList* watchpoints = &debugger->watchpoints;
132	size_t i;
133	for (i = 0; i < LR35902DebugWatchpointListSize(watchpoints); ++i) {
134		struct LR35902DebugWatchpoint* watchpoint = LR35902DebugWatchpointListGetPointer(watchpoints, i);
135		if (watchpoint->address == address && watchpoint->segment == segment) {
136			LR35902DebugWatchpointListShift(watchpoints, i, 1);
137		}
138	}
139	if (!LR35902DebugWatchpointListSize(&debugger->watchpoints)) {
140		LR35902DebuggerRemoveMemoryShim(debugger);
141	}
142}
143
144static void LR35902DebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* length) {
145	struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
146	struct LR35902Core* cpu = debugger->cpu;
147
148	char disassembly[64];
149
150	struct LR35902InstructionInfo info = {{0}};
151	char* disPtr = disassembly;
152	uint8_t instruction;
153	uint16_t address = cpu->pc;
154	size_t bytesRemaining = 1;
155	for (bytesRemaining = 1; bytesRemaining; --bytesRemaining) {
156		instruction = debugger->d.p->core->rawRead8(debugger->d.p->core, address, -1);
157		disPtr += snprintf(disPtr, sizeof(disassembly) - (disPtr - disassembly), "%02X", instruction);
158		++address;
159		bytesRemaining += LR35902Decode(instruction, &info);
160	};
161	disPtr[0] = ':';
162	disPtr[1] = ' ';
163	disPtr += 2;
164	LR35902Disassemble(&info, disPtr, sizeof(disassembly) - (disPtr - disassembly));
165
166	*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",
167		               cpu->a, cpu->f.packed, cpu->b, cpu->c,
168		               cpu->d, cpu->e, cpu->h, cpu->l,
169		               cpu->sp, cpu->pc, disassembly);
170}