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}