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