all repos — mgba @ e30674d05301e40ad386fd4ed32341a8bb533d95

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