all repos — mgba @ 74fc29fc68e7ae84f0c27130d1d98299434ce6f2

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 DEBUGGER_ID = 0xDEADBEEF;
 14
 15DEFINE_VECTOR(DebugBreakpointList, struct DebugBreakpoint);
 16DEFINE_VECTOR(DebugWatchpointList, struct DebugWatchpoint);
 17
 18static struct DebugBreakpoint* _lookupBreakpoint(struct DebugBreakpointList* breakpoints, uint32_t address) {
 19	size_t i;
 20	for (i = 0; i < DebugBreakpointListSize(breakpoints); ++i) {
 21		if (DebugBreakpointListGetPointer(breakpoints, i)->address == address) {
 22			return DebugBreakpointListGetPointer(breakpoints, i);
 23		}
 24	}
 25	return 0;
 26}
 27
 28static void _checkBreakpoints(struct Debugger* debugger) {
 29	int instructionLength;
 30	enum ExecutionMode mode = debugger->cpu->cpsr.t;
 31	if (mode == MODE_ARM) {
 32		instructionLength = WORD_SIZE_ARM;
 33	} else {
 34		instructionLength = WORD_SIZE_THUMB;
 35	}
 36	struct DebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->breakpoints, debugger->cpu->gprs[ARM_PC] - instructionLength);
 37	if (!breakpoint) {
 38		return;
 39	}
 40	struct DebuggerEntryInfo info = {
 41		.address = breakpoint->address
 42	};
 43	DebuggerEnter(debugger, DEBUGGER_ENTER_BREAKPOINT, &info);
 44}
 45
 46static void DebuggerInit(void* cpu, struct mCPUComponent*);
 47static void DebuggerDeinit(struct mCPUComponent*);
 48
 49void DebuggerCreate(struct Debugger* debugger) {
 50	debugger->d.id = DEBUGGER_ID;
 51	debugger->d.init = DebuggerInit;
 52	debugger->d.deinit = DebuggerDeinit;
 53}
 54
 55void DebuggerInit(void* cpu, struct mCPUComponent* component) {
 56	struct Debugger* debugger = (struct Debugger*) component;
 57	debugger->cpu = cpu;
 58	debugger->state = DEBUGGER_RUNNING;
 59	debugger->originalMemory = debugger->cpu->memory;
 60	debugger->currentBreakpoint = 0;
 61	DebugBreakpointListInit(&debugger->breakpoints, 0);
 62	DebugBreakpointListInit(&debugger->swBreakpoints, 0);
 63	DebugWatchpointListInit(&debugger->watchpoints, 0);
 64	if (debugger->init) {
 65		debugger->init(debugger);
 66	}
 67}
 68
 69void DebuggerDeinit(struct mCPUComponent* component) {
 70	struct Debugger* debugger = (struct Debugger*) component;
 71	debugger->deinit(debugger);
 72	DebugBreakpointListDeinit(&debugger->breakpoints);
 73	DebugBreakpointListDeinit(&debugger->swBreakpoints);
 74	DebugWatchpointListDeinit(&debugger->watchpoints);
 75}
 76
 77void DebuggerRun(struct Debugger* debugger) {
 78	switch (debugger->state) {
 79	case DEBUGGER_RUNNING:
 80		if (!DebugBreakpointListSize(&debugger->breakpoints) && !DebugWatchpointListSize(&debugger->watchpoints)) {
 81			ARMRunLoop(debugger->cpu);
 82		} else {
 83			ARMRun(debugger->cpu);
 84			_checkBreakpoints(debugger);
 85		}
 86		break;
 87	case DEBUGGER_CUSTOM:
 88		ARMRun(debugger->cpu);
 89		_checkBreakpoints(debugger);
 90		debugger->custom(debugger);
 91		break;
 92	case DEBUGGER_PAUSED:
 93		if (debugger->paused) {
 94			debugger->paused(debugger);
 95		} else {
 96			debugger->state = DEBUGGER_RUNNING;
 97		}
 98		if (debugger->state != DEBUGGER_PAUSED && debugger->currentBreakpoint) {
 99			if (debugger->currentBreakpoint->isSw && debugger->setSoftwareBreakpoint) {
100				debugger->setSoftwareBreakpoint(debugger, debugger->currentBreakpoint->address, debugger->currentBreakpoint->sw.mode, &debugger->currentBreakpoint->sw.opcode);
101			}
102			debugger->currentBreakpoint = 0;
103		}
104		break;
105	case DEBUGGER_SHUTDOWN:
106		return;
107	}
108}
109
110void DebuggerEnter(struct Debugger* debugger, enum DebuggerEntryReason reason, struct DebuggerEntryInfo* info) {
111	debugger->state = DEBUGGER_PAUSED;
112	struct ARMCore* cpu = debugger->cpu;
113	cpu->nextEvent = cpu->cycles;
114	if (reason == DEBUGGER_ENTER_BREAKPOINT) {
115		struct DebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->swBreakpoints, _ARMPCAddress(cpu));
116		debugger->currentBreakpoint = breakpoint;
117		if (breakpoint && breakpoint->isSw) {
118			info->address = breakpoint->address;
119			if (debugger->clearSoftwareBreakpoint) {
120				debugger->clearSoftwareBreakpoint(debugger, breakpoint->address, breakpoint->sw.mode, breakpoint->sw.opcode);
121			}
122
123			ARMRunFake(cpu, breakpoint->sw.opcode);
124		}
125	}
126	if (debugger->entered) {
127		debugger->entered(debugger, reason, info);
128	}
129}
130
131void DebuggerSetBreakpoint(struct Debugger* debugger, uint32_t address) {
132	struct DebugBreakpoint* breakpoint = DebugBreakpointListAppend(&debugger->breakpoints);
133	breakpoint->address = address;
134	breakpoint->isSw = false;
135}
136
137bool DebuggerSetSoftwareBreakpoint(struct Debugger* debugger, uint32_t address, enum ExecutionMode mode) {
138	uint32_t opcode;
139	if (!debugger->setSoftwareBreakpoint || !debugger->setSoftwareBreakpoint(debugger, address, mode, &opcode)) {
140		return false;
141	}
142
143	struct DebugBreakpoint* breakpoint = DebugBreakpointListAppend(&debugger->swBreakpoints);
144	breakpoint->address = address;
145	breakpoint->isSw = true;
146	breakpoint->sw.opcode = opcode;
147	breakpoint->sw.mode = mode;
148
149	return true;
150}
151
152void DebuggerClearBreakpoint(struct Debugger* debugger, uint32_t address) {
153	struct DebugBreakpointList* breakpoints = &debugger->breakpoints;
154	size_t i;
155	for (i = 0; i < DebugBreakpointListSize(breakpoints); ++i) {
156		if (DebugBreakpointListGetPointer(breakpoints, i)->address == address) {
157			DebugBreakpointListShift(breakpoints, i, 1);
158		}
159	}
160
161}
162
163void DebuggerSetWatchpoint(struct Debugger* debugger, uint32_t address, enum WatchpointType type) {
164	if (!DebugWatchpointListSize(&debugger->watchpoints)) {
165		DebuggerInstallMemoryShim(debugger);
166	}
167	struct DebugWatchpoint* watchpoint = DebugWatchpointListAppend(&debugger->watchpoints);
168	watchpoint->address = address;
169	watchpoint->type = type;
170}
171
172void DebuggerClearWatchpoint(struct Debugger* debugger, uint32_t address) {
173	struct DebugWatchpointList* watchpoints = &debugger->watchpoints;
174	size_t i;
175	for (i = 0; i < DebugWatchpointListSize(watchpoints); ++i) {
176		if (DebugWatchpointListGetPointer(watchpoints, i)->address == address) {
177			DebugWatchpointListShift(watchpoints, i, 1);
178		}
179	}
180	if (!DebugWatchpointListSize(&debugger->watchpoints)) {
181		DebuggerRemoveMemoryShim(debugger);
182	}
183}