all repos — mgba @ 6116f730e713585d5d2214ba0b89df836b40d8ff

mGBA Game Boy Advance Emulator

src/debugger/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 "debugger.h"
  9
 10#include <string.h>
 11
 12static bool _checkWatchpoints(struct DebugBreakpoint* watchpoints, uint32_t address, int width);
 13static uint32_t _popcount32(unsigned bits) {
 14	bits = bits - ((bits >> 1) & 0x55555555);
 15	bits = (bits & 0x33333333) + ((bits >> 2) & 0x33333333);
 16	return (((bits + (bits >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
 17}
 18
 19#define FIND_DEBUGGER(DEBUGGER, CPU) \
 20	{ \
 21		DEBUGGER = 0; \
 22		int i; \
 23		for (i = 0; i < CPU->numComponents; ++i) { \
 24			if (CPU->components[i]->id == ARM_DEBUGGER_ID) { \
 25				DEBUGGER = (struct ARMDebugger*) cpu->components[i]; \
 26				break; \
 27			} \
 28		} \
 29	}
 30
 31#define CREATE_SHIM(NAME, RETURN, TYPES, ARGS...) \
 32	static RETURN ARMDebuggerShim_ ## NAME TYPES { \
 33		struct ARMDebugger* debugger; \
 34		FIND_DEBUGGER(debugger, cpu); \
 35		return debugger->originalMemory.NAME(cpu, ARGS); \
 36	}
 37
 38#define CREATE_WATCHPOINT_SHIM(NAME, WIDTH, RETURN, TYPES, ARGS...) \
 39	static RETURN ARMDebuggerShim_ ## NAME TYPES { \
 40		struct ARMDebugger* debugger; \
 41		FIND_DEBUGGER(debugger, cpu); \
 42		if (_checkWatchpoints(debugger->watchpoints, address, WIDTH)) { \
 43			ARMDebuggerEnter(debugger, DEBUGGER_ENTER_WATCHPOINT); \
 44		} \
 45		return debugger->originalMemory.NAME(cpu, ARGS); \
 46	}
 47
 48#define CREATE_MULTIPLE_WATCHPOINT_SHIM(NAME) \
 49	static uint32_t ARMDebuggerShim_ ## NAME (struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) { \
 50		struct ARMDebugger* debugger; \
 51		FIND_DEBUGGER(debugger, cpu); \
 52		uint32_t popcount = _popcount32(mask); \
 53		int offset = 4; \
 54		int base = address; \
 55		if (direction & LSM_D) { \
 56			offset = -4; \
 57			base -= (popcount << 2) - 4; \
 58		} \
 59		if (direction & LSM_B) { \
 60			base += offset; \
 61		} \
 62		unsigned i; \
 63		for (i = 0; i < popcount; ++i) { \
 64			if (_checkWatchpoints(debugger->watchpoints, base + 4 * i, 4)) { \
 65				ARMDebuggerEnter(debugger, DEBUGGER_ENTER_WATCHPOINT); \
 66			} \
 67		} \
 68		return debugger->originalMemory.NAME(cpu, address, mask, direction, cycleCounter); \
 69	}
 70
 71CREATE_WATCHPOINT_SHIM(load32, 4, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), address, cycleCounter)
 72CREATE_WATCHPOINT_SHIM(load16, 2, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), address, cycleCounter)
 73CREATE_WATCHPOINT_SHIM(load8, 1, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), address, cycleCounter)
 74CREATE_WATCHPOINT_SHIM(store32, 4, void, (struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter), address, value, cycleCounter)
 75CREATE_WATCHPOINT_SHIM(store16, 2, void, (struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter), address, value, cycleCounter)
 76CREATE_WATCHPOINT_SHIM(store8, 1, void, (struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter), address, value, cycleCounter)
 77CREATE_MULTIPLE_WATCHPOINT_SHIM(loadMultiple)
 78CREATE_MULTIPLE_WATCHPOINT_SHIM(storeMultiple)
 79CREATE_SHIM(setActiveRegion, void, (struct ARMCore* cpu, uint32_t address), address)
 80
 81static bool _checkWatchpoints(struct DebugBreakpoint* watchpoints, uint32_t address, int width) {
 82	width -= 1;
 83	for (; watchpoints; watchpoints = watchpoints->next) {
 84		if (!((watchpoints->address ^ address) & ~width)) {
 85			return true;
 86		}
 87	}
 88	return false;
 89}
 90
 91void ARMDebuggerInstallMemoryShim(struct ARMDebugger* debugger) {
 92	debugger->originalMemory = debugger->cpu->memory;
 93	debugger->cpu->memory.store32 = ARMDebuggerShim_store32;
 94	debugger->cpu->memory.store16 = ARMDebuggerShim_store16;
 95	debugger->cpu->memory.store8 = ARMDebuggerShim_store8;
 96	debugger->cpu->memory.load32 = ARMDebuggerShim_load32;
 97	debugger->cpu->memory.load16 = ARMDebuggerShim_load16;
 98	debugger->cpu->memory.load8 = ARMDebuggerShim_load8;
 99	debugger->cpu->memory.storeMultiple = ARMDebuggerShim_storeMultiple;
100	debugger->cpu->memory.loadMultiple = ARMDebuggerShim_loadMultiple;
101	debugger->cpu->memory.setActiveRegion = ARMDebuggerShim_setActiveRegion;
102}
103
104void ARMDebuggerRemoveMemoryShim(struct ARMDebugger* debugger) {
105	debugger->cpu->memory.store32 = debugger->originalMemory.store32;
106	debugger->cpu->memory.store16 = debugger->originalMemory.store16;
107	debugger->cpu->memory.store8 = debugger->originalMemory.store8;
108	debugger->cpu->memory.load32 = debugger->originalMemory.load32;
109	debugger->cpu->memory.load16 = debugger->originalMemory.load16;
110	debugger->cpu->memory.load8 = debugger->originalMemory.load8;
111	debugger->cpu->memory.storeMultiple = debugger->originalMemory.storeMultiple;
112	debugger->cpu->memory.loadMultiple = debugger->originalMemory.loadMultiple;
113	debugger->cpu->memory.setActiveRegion = debugger->originalMemory.setActiveRegion;
114}