all repos — mgba @ cd0a352a33d1613196ad5c3fa7e2af055e0fbecc

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