all repos — mgba @ c14da05d8dca225010677643c32fea5c0ac8517a

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->swBreakpoints = 0;
 57	debugger->originalMemory = cpu->memory;
 58	debugger->watchpoints = 0;
 59	debugger->currentBreakpoint = 0;
 60	if (debugger->init) {
 61		debugger->init(debugger);
 62	}
 63}
 64
 65void ARMDebuggerDeinit(struct ARMComponent* component) {
 66	struct ARMDebugger* debugger = (struct ARMDebugger*) component;
 67	debugger->deinit(debugger);
 68}
 69
 70void ARMDebuggerRun(struct ARMDebugger* debugger) {
 71	switch (debugger->state) {
 72	case DEBUGGER_RUNNING:
 73		if (!debugger->breakpoints && !debugger->watchpoints) {
 74			ARMRunLoop(debugger->cpu);
 75		} else {
 76			ARMRun(debugger->cpu);
 77			_checkBreakpoints(debugger);
 78		}
 79		break;
 80	case DEBUGGER_CUSTOM:
 81		ARMRun(debugger->cpu);
 82		_checkBreakpoints(debugger);
 83		debugger->custom(debugger);
 84		break;
 85	case DEBUGGER_PAUSED:
 86		if (debugger->paused) {
 87			debugger->paused(debugger);
 88		} else {
 89			debugger->state = DEBUGGER_RUNNING;
 90		}
 91		if (debugger->state != DEBUGGER_PAUSED && debugger->currentBreakpoint) {
 92			if (debugger->currentBreakpoint->isSw && debugger->setSoftwareBreakpoint) {
 93				debugger->setSoftwareBreakpoint(debugger, debugger->currentBreakpoint->address, debugger->currentBreakpoint->sw.mode, &debugger->currentBreakpoint->sw.opcode);
 94			}
 95			debugger->currentBreakpoint = 0;
 96		}
 97		break;
 98	case DEBUGGER_SHUTDOWN:
 99		return;
100	}
101}
102
103void ARMDebuggerEnter(struct ARMDebugger* debugger, enum DebuggerEntryReason reason, struct DebuggerEntryInfo* info) {
104	debugger->state = DEBUGGER_PAUSED;
105	struct ARMCore* cpu = debugger->cpu;
106	cpu->nextEvent = 0;
107	if (reason == DEBUGGER_ENTER_BREAKPOINT) {
108		struct DebugBreakpoint* breakpoint = _lookupBreakpoint(debugger->swBreakpoints, _ARMPCAddress(cpu));
109		debugger->currentBreakpoint = breakpoint;
110		if (breakpoint && breakpoint->isSw) {
111			info->address = breakpoint->address;
112			if (debugger->clearSoftwareBreakpoint) {
113				debugger->clearSoftwareBreakpoint(debugger, breakpoint->address, breakpoint->sw.mode, breakpoint->sw.opcode);
114			}
115
116			ARMRunFake(cpu, breakpoint->sw.opcode);
117		}
118	}
119	if (debugger->entered) {
120		debugger->entered(debugger, reason, info);
121	}
122}
123
124void ARMDebuggerSetBreakpoint(struct ARMDebugger* debugger, uint32_t address) {
125	struct DebugBreakpoint* breakpoint = malloc(sizeof(struct DebugBreakpoint));
126	breakpoint->address = address;
127	breakpoint->next = debugger->breakpoints;
128	breakpoint->isSw = false;
129	debugger->breakpoints = breakpoint;
130}
131
132bool ARMDebuggerSetSoftwareBreakpoint(struct ARMDebugger* debugger, uint32_t address, enum ExecutionMode mode) {
133	uint32_t opcode;
134	if (!debugger->setSoftwareBreakpoint || !debugger->setSoftwareBreakpoint(debugger, address, mode, &opcode)) {
135		return false;
136	}
137
138	struct DebugBreakpoint* breakpoint = malloc(sizeof(struct DebugBreakpoint));
139	breakpoint->address = address;
140	breakpoint->next = debugger->swBreakpoints;
141	breakpoint->isSw = true;
142	breakpoint->sw.opcode = opcode;
143	breakpoint->sw.mode = mode;
144	debugger->swBreakpoints = breakpoint;
145
146	return true;
147}
148
149void ARMDebuggerClearBreakpoint(struct ARMDebugger* debugger, uint32_t address) {
150	struct DebugBreakpoint** previous = &debugger->breakpoints;
151	struct DebugBreakpoint* breakpoint;
152	struct DebugBreakpoint** next;
153	while ((breakpoint = *previous)) {
154		next = &breakpoint->next;
155		if (breakpoint->address == address) {
156			*previous = *next;
157			free(breakpoint);
158			continue;
159		}
160		previous = next;
161	}
162}
163
164void ARMDebuggerSetWatchpoint(struct ARMDebugger* debugger, uint32_t address) {
165	if (!debugger->watchpoints) {
166		ARMDebuggerInstallMemoryShim(debugger);
167	}
168	struct DebugWatchpoint* watchpoint = malloc(sizeof(struct DebugWatchpoint));
169	watchpoint->address = address;
170	watchpoint->next = debugger->watchpoints;
171	debugger->watchpoints = watchpoint;
172}
173
174void ARMDebuggerClearWatchpoint(struct ARMDebugger* debugger, uint32_t address) {
175	struct DebugWatchpoint** previous = &debugger->watchpoints;
176	struct DebugWatchpoint* watchpoint;
177	struct DebugWatchpoint** next;
178	while ((watchpoint = *previous)) {
179		next = &watchpoint->next;
180		if (watchpoint->address == address) {
181			*previous = *next;
182			free(watchpoint);
183			continue;
184		}
185		previous = next;
186	}
187	if (!debugger->watchpoints) {
188		ARMDebuggerRemoveMemoryShim(debugger);
189	}
190}