all repos — mgba @ 37a0839a251b432d2d0bb1ebe70d4aa100008c1d

mGBA Game Boy Advance Emulator

src/arm/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/arm.h"
  9#include "arm/isa-inlines.h"
 10#include "arm/memory-debugger.h"
 11#include "core/core.h"
 12
 13DEFINE_VECTOR(ARMDebugBreakpointList, struct ARMDebugBreakpoint);
 14DEFINE_VECTOR(ARMDebugWatchpointList, struct ARMDebugWatchpoint);
 15
 16static struct ARMDebugBreakpoint* _lookupBreakpoint(struct ARMDebugBreakpointList* breakpoints, uint32_t address) {
 17	size_t i;
 18	for (i = 0; i < ARMDebugBreakpointListSize(breakpoints); ++i) {
 19		if (ARMDebugBreakpointListGetPointer(breakpoints, i)->address == address) {
 20			return ARMDebugBreakpointListGetPointer(breakpoints, i);
 21		}
 22	}
 23	return 0;
 24}
 25
 26static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform* d) {
 27	struct ARMDebugger* debugger = (struct ARMDebugger*) d;
 28	int instructionLength;
 29	enum ExecutionMode mode = debugger->cpu->cpsr.t;
 30	if (mode == MODE_ARM) {
 31		instructionLength = WORD_SIZE_ARM;
 32	} else {
 33		instructionLength = WORD_SIZE_THUMB;
 34	}
 35	struct ARMDebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->breakpoints, debugger->cpu->gprs[ARM_PC] - instructionLength);
 36	if (!breakpoint) {
 37		return;
 38	}
 39	struct mDebuggerEntryInfo info = {
 40		.address = breakpoint->address
 41	};
 42	mDebuggerEnter(d->p, DEBUGGER_ENTER_BREAKPOINT, &info);
 43}
 44
 45static void ARMDebuggerInit(void* cpu, struct mDebuggerPlatform* platform);
 46static void ARMDebuggerDeinit(struct mDebuggerPlatform* platform);
 47
 48static void ARMDebuggerEnter(struct mDebuggerPlatform* d, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info);
 49
 50static void ARMDebuggerSetBreakpoint(struct mDebuggerPlatform*, uint32_t address);
 51static void ARMDebuggerClearBreakpoint(struct mDebuggerPlatform*, uint32_t address);
 52static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform*, uint32_t address, enum mWatchpointType type);
 53static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform*, uint32_t address);
 54static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform*);
 55static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform*);
 56
 57struct mDebuggerPlatform* ARMDebuggerPlatformCreate(void) {
 58	struct mDebuggerPlatform* platform = malloc(sizeof(struct ARMDebugger));
 59	platform->entered = ARMDebuggerEnter;
 60	platform->init = ARMDebuggerInit;
 61	platform->deinit = ARMDebuggerDeinit;
 62	platform->setBreakpoint = ARMDebuggerSetBreakpoint;
 63	platform->clearBreakpoint = ARMDebuggerClearBreakpoint;
 64	platform->setWatchpoint = ARMDebuggerSetWatchpoint;
 65	platform->clearWatchpoint = ARMDebuggerClearWatchpoint;
 66	platform->checkBreakpoints = ARMDebuggerCheckBreakpoints;
 67	platform->hasBreakpoints = ARMDebuggerHasBreakpoints;
 68	return platform;
 69}
 70
 71void ARMDebuggerInit(void* cpu, struct mDebuggerPlatform* platform) {
 72	struct ARMDebugger* debugger = (struct ARMDebugger*) platform;
 73	debugger->cpu = cpu;
 74	debugger->originalMemory = debugger->cpu->memory;
 75	ARMDebugBreakpointListInit(&debugger->breakpoints, 0);
 76	ARMDebugBreakpointListInit(&debugger->swBreakpoints, 0);
 77	ARMDebugWatchpointListInit(&debugger->watchpoints, 0);
 78}
 79
 80void ARMDebuggerDeinit(struct mDebuggerPlatform* platform) {
 81	struct ARMDebugger* debugger = (struct ARMDebugger*) platform;
 82	ARMDebugBreakpointListDeinit(&debugger->breakpoints);
 83	ARMDebugBreakpointListDeinit(&debugger->swBreakpoints);
 84	ARMDebugWatchpointListDeinit(&debugger->watchpoints);
 85}
 86
 87static void ARMDebuggerEnter(struct mDebuggerPlatform* platform, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
 88	struct ARMDebugger* debugger = (struct ARMDebugger*) platform;
 89	struct ARMCore* cpu = debugger->cpu;
 90	cpu->nextEvent = cpu->cycles;
 91	if (reason == DEBUGGER_ENTER_BREAKPOINT) {
 92		struct ARMDebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->swBreakpoints, _ARMPCAddress(cpu));
 93		if (breakpoint && breakpoint->isSw) {
 94			info->address = breakpoint->address;
 95			if (debugger->clearSoftwareBreakpoint) {
 96				debugger->clearSoftwareBreakpoint(debugger, breakpoint->address, breakpoint->sw.mode, breakpoint->sw.opcode);
 97			}
 98
 99			ARMRunFake(cpu, breakpoint->sw.opcode);
100
101			if (debugger->setSoftwareBreakpoint) {
102				debugger->setSoftwareBreakpoint(debugger, breakpoint->address, breakpoint->sw.mode, &breakpoint->sw.opcode);
103			}
104		}
105	}
106	if (debugger->entered) {
107		debugger->entered(debugger->d.p, reason, info);
108	}
109}
110
111bool ARMDebuggerSetSoftwareBreakpoint(struct mDebuggerPlatform* d, uint32_t address, enum ExecutionMode mode) {
112	struct ARMDebugger* debugger = (struct ARMDebugger*) d;
113	uint32_t opcode;
114	if (!debugger->setSoftwareBreakpoint || !debugger->setSoftwareBreakpoint(debugger, address, mode, &opcode)) {
115		return false;
116	}
117
118	struct ARMDebugBreakpoint* breakpoint = ARMDebugBreakpointListAppend(&debugger->swBreakpoints);
119	breakpoint->address = address;
120	breakpoint->isSw = true;
121	breakpoint->sw.opcode = opcode;
122	breakpoint->sw.mode = mode;
123
124	return true;
125}
126
127static void ARMDebuggerSetBreakpoint(struct mDebuggerPlatform* d, uint32_t address) {
128	struct ARMDebugger* debugger = (struct ARMDebugger*) d;
129	struct ARMDebugBreakpoint* breakpoint = ARMDebugBreakpointListAppend(&debugger->breakpoints);
130	breakpoint->address = address;
131	breakpoint->isSw = false;
132}
133
134static void ARMDebuggerClearBreakpoint(struct mDebuggerPlatform* d, uint32_t address) {
135	struct ARMDebugger* debugger = (struct ARMDebugger*) d;
136	struct ARMDebugBreakpointList* breakpoints = &debugger->breakpoints;
137	size_t i;
138	for (i = 0; i < ARMDebugBreakpointListSize(breakpoints); ++i) {
139		if (ARMDebugBreakpointListGetPointer(breakpoints, i)->address == address) {
140			ARMDebugBreakpointListShift(breakpoints, i, 1);
141		}
142	}
143}
144
145static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform* d) {
146	struct ARMDebugger* debugger = (struct ARMDebugger*) d;
147	return ARMDebugBreakpointListSize(&debugger->breakpoints) || ARMDebugWatchpointListSize(&debugger->watchpoints);
148}
149
150static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t address, enum mWatchpointType type) {
151	struct ARMDebugger* debugger = (struct ARMDebugger*) d;
152	if (!ARMDebugWatchpointListSize(&debugger->watchpoints)) {
153		ARMDebuggerInstallMemoryShim(debugger);
154	}
155	struct ARMDebugWatchpoint* watchpoint = ARMDebugWatchpointListAppend(&debugger->watchpoints);
156	watchpoint->address = address;
157	watchpoint->type = type;
158}
159
160static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t address) {
161	struct ARMDebugger* debugger = (struct ARMDebugger*) d;
162	struct ARMDebugWatchpointList* watchpoints = &debugger->watchpoints;
163	size_t i;
164	for (i = 0; i < ARMDebugWatchpointListSize(watchpoints); ++i) {
165		if (ARMDebugWatchpointListGetPointer(watchpoints, i)->address == address) {
166			ARMDebugWatchpointListShift(watchpoints, i, 1);
167		}
168	}
169	if (!ARMDebugWatchpointListSize(&debugger->watchpoints)) {
170		ARMDebuggerRemoveMemoryShim(debugger);
171	}
172}