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 "memory-debugger.h"
7
8#include "arm/debugger/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}