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}