all repos — mgba @ 72b826dd2077dcc4affe3dc0388750c3b7b13d7c

mGBA Game Boy Advance Emulator

src/arm/memory-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 "memory-debugger.h"
  7
  8#include "arm/debugger.h"
  9
 10#include "util/math.h"
 11
 12#include <string.h>
 13
 14static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, struct mDebuggerEntryInfo* info, enum mWatchpointType type, uint32_t newValue, int width);
 15
 16#define FIND_DEBUGGER(DEBUGGER, CPU) \
 17	do { \
 18		DEBUGGER = 0; \
 19		size_t i; \
 20		for (i = 0; i < CPU->numComponents; ++i) { \
 21			if (CPU->components[i]->id == DEBUGGER_ID) { \
 22				DEBUGGER = (struct ARMDebugger*) ((struct mDebugger*) cpu->components[i])->platform; \
 23				goto debuggerFound; \
 24			} \
 25		} \
 26		abort(); \
 27		debuggerFound: break; \
 28	} while(0)
 29
 30#define CREATE_SHIM(NAME, RETURN, TYPES, ...) \
 31	static RETURN DebuggerShim_ ## NAME TYPES { \
 32		struct ARMDebugger* debugger; \
 33		FIND_DEBUGGER(debugger, cpu); \
 34		return debugger->originalMemory.NAME(cpu, __VA_ARGS__); \
 35	}
 36
 37#define CREATE_WATCHPOINT_READ_SHIM(NAME, WIDTH, RETURN, TYPES, ...) \
 38	static RETURN DebuggerShim_ ## NAME TYPES { \
 39		struct ARMDebugger* debugger; \
 40		FIND_DEBUGGER(debugger, cpu); \
 41		struct mDebuggerEntryInfo info; \
 42		if (_checkWatchpoints(debugger, address, &info, WATCHPOINT_READ, 0, WIDTH)) { \
 43			mDebuggerEnter(debugger->d.p, DEBUGGER_ENTER_WATCHPOINT, &info); \
 44		} \
 45		return debugger->originalMemory.NAME(cpu, __VA_ARGS__); \
 46	}
 47
 48#define CREATE_WATCHPOINT_WRITE_SHIM(NAME, WIDTH, RETURN, TYPES, ...) \
 49	static RETURN DebuggerShim_ ## NAME TYPES { \
 50		struct ARMDebugger* debugger; \
 51		FIND_DEBUGGER(debugger, cpu); \
 52		struct mDebuggerEntryInfo info; \
 53		if (_checkWatchpoints(debugger, address, &info, WATCHPOINT_WRITE, value, WIDTH)) { \
 54			mDebuggerEnter(debugger->d.p, DEBUGGER_ENTER_WATCHPOINT, &info); \
 55		} \
 56		return debugger->originalMemory.NAME(cpu, __VA_ARGS__); \
 57	}
 58
 59#define CREATE_MULTIPLE_WATCHPOINT_SHIM(NAME, ACCESS_TYPE) \
 60	static uint32_t DebuggerShim_ ## NAME (struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) { \
 61		struct ARMDebugger* debugger; \
 62		FIND_DEBUGGER(debugger, cpu); \
 63		uint32_t popcount = popcount32(mask); \
 64		int offset = 4; \
 65		int base = address; \
 66		if (direction & LSM_D) { \
 67			offset = -4; \
 68			base -= (popcount << 2) - 4; \
 69		} \
 70		if (direction & LSM_B) { \
 71			base += offset; \
 72		} \
 73		unsigned i; \
 74		for (i = 0; i < popcount; ++i) { \
 75			struct mDebuggerEntryInfo info; \
 76			if (_checkWatchpoints(debugger, base + 4 * i, &info, ACCESS_TYPE, 0, 4)) { \
 77				mDebuggerEnter(debugger->d.p, DEBUGGER_ENTER_WATCHPOINT, &info); \
 78			} \
 79		} \
 80		return debugger->originalMemory.NAME(cpu, address, mask, direction, cycleCounter); \
 81	}
 82
 83CREATE_WATCHPOINT_READ_SHIM(load32, 4, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), address, cycleCounter)
 84CREATE_WATCHPOINT_READ_SHIM(load16, 2, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), address, cycleCounter)
 85CREATE_WATCHPOINT_READ_SHIM(load8, 1, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), address, cycleCounter)
 86CREATE_WATCHPOINT_WRITE_SHIM(store32, 4, void, (struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter), address, value, cycleCounter)
 87CREATE_WATCHPOINT_WRITE_SHIM(store16, 2, void, (struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter), address, value, cycleCounter)
 88CREATE_WATCHPOINT_WRITE_SHIM(store8, 1, void, (struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter), address, value, cycleCounter)
 89CREATE_MULTIPLE_WATCHPOINT_SHIM(loadMultiple, WATCHPOINT_READ)
 90CREATE_MULTIPLE_WATCHPOINT_SHIM(storeMultiple, WATCHPOINT_WRITE)
 91CREATE_SHIM(setActiveRegion, void, (struct ARMCore* cpu, uint32_t address), address)
 92
 93static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, struct mDebuggerEntryInfo* info, enum mWatchpointType type, uint32_t newValue, int width) {
 94	--width;
 95	struct ARMDebugWatchpoint* watchpoint;
 96	size_t i;
 97	for (i = 0; i < ARMDebugWatchpointListSize(&debugger->watchpoints); ++i) {
 98		watchpoint = ARMDebugWatchpointListGetPointer(&debugger->watchpoints, i);
 99		if (!((watchpoint->address ^ address) & ~width) && watchpoint->type & type) {
100			switch (width + 1) {
101			case 1:
102				info->oldValue = debugger->originalMemory.load8(debugger->cpu, address, 0);
103				break;
104			case 2:
105				info->oldValue = debugger->originalMemory.load16(debugger->cpu, address, 0);
106				break;
107			case 4:
108				info->oldValue = debugger->originalMemory.load32(debugger->cpu, address, 0);
109				break;
110			}
111			info->newValue = newValue;
112			info->address = address;
113			info->watchType = watchpoint->type;
114			info->accessType = type;
115			return true;
116		}
117	}
118	return false;
119}
120
121void ARMDebuggerInstallMemoryShim(struct ARMDebugger* debugger) {
122	debugger->originalMemory = debugger->cpu->memory;
123	debugger->cpu->memory.store32 = DebuggerShim_store32;
124	debugger->cpu->memory.store16 = DebuggerShim_store16;
125	debugger->cpu->memory.store8 = DebuggerShim_store8;
126	debugger->cpu->memory.load32 = DebuggerShim_load32;
127	debugger->cpu->memory.load16 = DebuggerShim_load16;
128	debugger->cpu->memory.load8 = DebuggerShim_load8;
129	debugger->cpu->memory.storeMultiple = DebuggerShim_storeMultiple;
130	debugger->cpu->memory.loadMultiple = DebuggerShim_loadMultiple;
131	debugger->cpu->memory.setActiveRegion = DebuggerShim_setActiveRegion;
132}
133
134void ARMDebuggerRemoveMemoryShim(struct ARMDebugger* debugger) {
135	debugger->cpu->memory.store32 = debugger->originalMemory.store32;
136	debugger->cpu->memory.store16 = debugger->originalMemory.store16;
137	debugger->cpu->memory.store8 = debugger->originalMemory.store8;
138	debugger->cpu->memory.load32 = debugger->originalMemory.load32;
139	debugger->cpu->memory.load16 = debugger->originalMemory.load16;
140	debugger->cpu->memory.load8 = debugger->originalMemory.load8;
141	debugger->cpu->memory.storeMultiple = debugger->originalMemory.storeMultiple;
142	debugger->cpu->memory.loadMultiple = debugger->originalMemory.loadMultiple;
143	debugger->cpu->memory.setActiveRegion = debugger->originalMemory.setActiveRegion;
144}