all repos — mgba @ 56291e63e58203358ea27c0efe5196db682eeb0b

mGBA Game Boy Advance Emulator

src/debugger/debugger.c (view raw)

  1/* Copyright (c) 2013-2014 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 "debugger.h"
  7
  8#include "arm.h"
  9#include "isa-inlines.h"
 10
 11#include "memory-debugger.h"
 12
 13const uint32_t ARM_DEBUGGER_ID = 0xDEADBEEF;
 14
 15static struct DebugBreakpoint* _lookupBreakpoint(struct DebugBreakpoint* breakpoints, uint32_t address) {
 16	for (; breakpoints; breakpoints = breakpoints->next) {
 17		if (breakpoints->address == address) {
 18			return breakpoints;
 19		}
 20	}
 21	return 0;
 22}
 23
 24static void _checkBreakpoints(struct ARMDebugger* debugger) {
 25	int instructionLength;
 26	enum ExecutionMode mode = debugger->cpu->cpsr.t;
 27	if (mode == MODE_ARM) {
 28		instructionLength = WORD_SIZE_ARM;
 29	} else {
 30		instructionLength = WORD_SIZE_THUMB;
 31	}
 32	struct DebugBreakpoint* breakpoint = _lookupBreakpoint(debugger->breakpoints, debugger->cpu->gprs[ARM_PC] - instructionLength);
 33	if (!breakpoint) {
 34		return;
 35	}
 36	struct DebuggerEntryInfo info = {
 37		.address = breakpoint->address
 38	};
 39	ARMDebuggerEnter(debugger, DEBUGGER_ENTER_BREAKPOINT, &info);
 40}
 41
 42static void ARMDebuggerInit(struct ARMCore*, struct ARMComponent*);
 43static void ARMDebuggerDeinit(struct ARMComponent*);
 44
 45void ARMDebuggerCreate(struct ARMDebugger* debugger) {
 46	debugger->d.id = ARM_DEBUGGER_ID;
 47	debugger->d.init = ARMDebuggerInit;
 48	debugger->d.deinit = ARMDebuggerDeinit;
 49}
 50
 51void ARMDebuggerInit(struct ARMCore* cpu, struct ARMComponent* component) {
 52	struct ARMDebugger* debugger = (struct ARMDebugger*) component;
 53	debugger->cpu = cpu;
 54	debugger->state = DEBUGGER_RUNNING;
 55	debugger->breakpoints = 0;
 56	debugger->originalMemory = cpu->memory;
 57	debugger->watchpoints = 0;
 58	debugger->currentBreakpoint = 0;
 59	if (debugger->init) {
 60		debugger->init(debugger);
 61	}
 62}
 63
 64void ARMDebuggerDeinit(struct ARMComponent* component) {
 65	struct ARMDebugger* debugger = (struct ARMDebugger*) component;
 66	debugger->deinit(debugger);
 67}
 68
 69void ARMDebuggerRun(struct ARMDebugger* debugger) {
 70	switch (debugger->state) {
 71	case DEBUGGER_RUNNING:
 72		if (!debugger->breakpoints && !debugger->watchpoints) {
 73			ARMRunLoop(debugger->cpu);
 74		} else {
 75			ARMRun(debugger->cpu);
 76			_checkBreakpoints(debugger);
 77		}
 78		break;
 79	case DEBUGGER_CUSTOM:
 80		ARMRun(debugger->cpu);
 81		_checkBreakpoints(debugger);
 82		debugger->custom(debugger);
 83		break;
 84	case DEBUGGER_PAUSED:
 85		if (debugger->paused) {
 86			debugger->paused(debugger);
 87		} else {
 88			debugger->state = DEBUGGER_RUNNING;
 89		}
 90		if (debugger->state != DEBUGGER_PAUSED && debugger->currentBreakpoint) {
 91			if (debugger->currentBreakpoint->isSw && debugger->setSoftwareBreakpoint) {
 92				debugger->setSoftwareBreakpoint(debugger, debugger->currentBreakpoint->address, debugger->currentBreakpoint->sw.mode, &debugger->currentBreakpoint->sw.opcode);
 93			}
 94			debugger->currentBreakpoint = 0;
 95		}
 96		break;
 97	case DEBUGGER_SHUTDOWN:
 98		return;
 99	}
100}
101
102void ARMDebuggerEnter(struct ARMDebugger* debugger, enum DebuggerEntryReason reason, struct DebuggerEntryInfo* info) {
103	debugger->state = DEBUGGER_PAUSED;
104	struct ARMCore* cpu = debugger->cpu;
105	cpu->nextEvent = 0;
106	if (reason == DEBUGGER_ENTER_BREAKPOINT) {
107		struct DebugBreakpoint* breakpoint = _lookupBreakpoint(debugger->swBreakpoints, _ARMPCAddress(cpu));
108		debugger->currentBreakpoint = breakpoint;
109		if (breakpoint && breakpoint->isSw) {
110			info->address = breakpoint->address;
111			if (debugger->clearSoftwareBreakpoint) {
112				debugger->clearSoftwareBreakpoint(debugger, breakpoint->address, breakpoint->sw.mode, breakpoint->sw.opcode);
113			}
114
115			// Roll back CPU state
116			if (breakpoint->sw.mode == MODE_ARM) {
117				cpu->gprs[ARM_PC] -= WORD_SIZE_ARM;
118			} else {
119				cpu->gprs[ARM_PC] -= WORD_SIZE_THUMB;
120			}
121			cpu->prefetch[1] = cpu->prefetch[0];
122			cpu->prefetch[0] = breakpoint->sw.opcode;
123		}
124	}
125	if (debugger->entered) {
126		debugger->entered(debugger, reason, info);
127	}
128}
129
130void ARMDebuggerSetBreakpoint(struct ARMDebugger* debugger, uint32_t address) {
131	struct DebugBreakpoint* breakpoint = malloc(sizeof(struct DebugBreakpoint));
132	breakpoint->address = address;
133	breakpoint->next = debugger->breakpoints;
134	breakpoint->isSw = false;
135	debugger->breakpoints = breakpoint;
136}
137
138bool ARMDebuggerSetSoftwareBreakpoint(struct ARMDebugger* debugger, uint32_t address, enum ExecutionMode mode) {
139	uint32_t opcode;
140	if (!debugger->setSoftwareBreakpoint || !debugger->setSoftwareBreakpoint(debugger, address, mode, &opcode)) {
141		return false;
142	}
143
144	struct DebugBreakpoint* breakpoint = malloc(sizeof(struct DebugBreakpoint));
145	breakpoint->address = address;
146	breakpoint->next = debugger->swBreakpoints;
147	breakpoint->isSw = true;
148	breakpoint->sw.opcode = opcode;
149	breakpoint->sw.mode = mode;
150	debugger->swBreakpoints = breakpoint;
151
152	return true;
153}
154
155void ARMDebuggerClearBreakpoint(struct ARMDebugger* debugger, uint32_t address) {
156	struct DebugBreakpoint** previous = &debugger->breakpoints;
157	struct DebugBreakpoint* breakpoint;
158	for (; (breakpoint = *previous); previous = &breakpoint->next) {
159		if (breakpoint->address == address) {
160			*previous = breakpoint->next;
161			free(breakpoint);
162		}
163	}
164}
165
166void ARMDebuggerSetWatchpoint(struct ARMDebugger* debugger, uint32_t address) {
167	if (!debugger->watchpoints) {
168		ARMDebuggerInstallMemoryShim(debugger);
169	}
170	struct DebugWatchpoint* watchpoint = malloc(sizeof(struct DebugWatchpoint));
171	watchpoint->address = address;
172	watchpoint->next = debugger->watchpoints;
173	debugger->watchpoints = watchpoint;
174}
175
176void ARMDebuggerClearWatchpoint(struct ARMDebugger* debugger, uint32_t address) {
177	struct DebugWatchpoint** previous = &debugger->watchpoints;
178	struct DebugWatchpoint* breakpoint;
179	for (; (breakpoint = *previous); previous = &breakpoint->next) {
180		if (breakpoint->address == address) {
181			*previous = breakpoint->next;
182			free(breakpoint);
183		}
184	}
185	if (!debugger->watchpoints) {
186		ARMDebuggerRemoveMemoryShim(debugger);
187	}
188}