all repos — mgba @ 1a694b0b56ac3ead10ff5dc281ee46985a593223

mGBA Game Boy Advance Emulator

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