src/arm/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 "debugger.h"
7
8#include "arm/arm.h"
9#include "arm/isa-inlines.h"
10#include "arm/memory-debugger.h"
11#include "core/core.h"
12
13DEFINE_VECTOR(ARMDebugBreakpointList, struct ARMDebugBreakpoint);
14DEFINE_VECTOR(ARMDebugWatchpointList, struct ARMDebugWatchpoint);
15
16static struct ARMDebugBreakpoint* _lookupBreakpoint(struct ARMDebugBreakpointList* breakpoints, uint32_t address) {
17 size_t i;
18 for (i = 0; i < ARMDebugBreakpointListSize(breakpoints); ++i) {
19 if (ARMDebugBreakpointListGetPointer(breakpoints, i)->address == address) {
20 return ARMDebugBreakpointListGetPointer(breakpoints, i);
21 }
22 }
23 return 0;
24}
25
26static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform* d) {
27 struct ARMDebugger* debugger = (struct ARMDebugger*) d;
28 int instructionLength;
29 enum ExecutionMode mode = debugger->cpu->cpsr.t;
30 if (mode == MODE_ARM) {
31 instructionLength = WORD_SIZE_ARM;
32 } else {
33 instructionLength = WORD_SIZE_THUMB;
34 }
35 struct ARMDebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->breakpoints, debugger->cpu->gprs[ARM_PC] - instructionLength);
36 if (!breakpoint) {
37 return;
38 }
39 struct mDebuggerEntryInfo info = {
40 .address = breakpoint->address
41 };
42 mDebuggerEnter(d->p, DEBUGGER_ENTER_BREAKPOINT, &info);
43}
44
45static void ARMDebuggerInit(void* cpu, struct mDebuggerPlatform* platform);
46static void ARMDebuggerDeinit(struct mDebuggerPlatform* platform);
47
48static void ARMDebuggerEnter(struct mDebuggerPlatform* d, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info);
49
50static void ARMDebuggerSetBreakpoint(struct mDebuggerPlatform*, uint32_t address);
51static void ARMDebuggerClearBreakpoint(struct mDebuggerPlatform*, uint32_t address);
52static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform*, uint32_t address, enum mWatchpointType type);
53static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform*, uint32_t address);
54static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform*);
55static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform*);
56
57struct mDebuggerPlatform* ARMDebuggerPlatformCreate(void) {
58 struct mDebuggerPlatform* platform = malloc(sizeof(struct ARMDebugger));
59 platform->entered = ARMDebuggerEnter;
60 platform->init = ARMDebuggerInit;
61 platform->deinit = ARMDebuggerDeinit;
62 platform->setBreakpoint = ARMDebuggerSetBreakpoint;
63 platform->clearBreakpoint = ARMDebuggerClearBreakpoint;
64 platform->setWatchpoint = ARMDebuggerSetWatchpoint;
65 platform->clearWatchpoint = ARMDebuggerClearWatchpoint;
66 platform->checkBreakpoints = ARMDebuggerCheckBreakpoints;
67 platform->hasBreakpoints = ARMDebuggerHasBreakpoints;
68 return platform;
69}
70
71void ARMDebuggerInit(void* cpu, struct mDebuggerPlatform* platform) {
72 struct ARMDebugger* debugger = (struct ARMDebugger*) platform;
73 debugger->cpu = cpu;
74 debugger->originalMemory = debugger->cpu->memory;
75 ARMDebugBreakpointListInit(&debugger->breakpoints, 0);
76 ARMDebugBreakpointListInit(&debugger->swBreakpoints, 0);
77 ARMDebugWatchpointListInit(&debugger->watchpoints, 0);
78}
79
80void ARMDebuggerDeinit(struct mDebuggerPlatform* platform) {
81 struct ARMDebugger* debugger = (struct ARMDebugger*) platform;
82 ARMDebugBreakpointListDeinit(&debugger->breakpoints);
83 ARMDebugBreakpointListDeinit(&debugger->swBreakpoints);
84 ARMDebugWatchpointListDeinit(&debugger->watchpoints);
85}
86
87static void ARMDebuggerEnter(struct mDebuggerPlatform* platform, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
88 struct ARMDebugger* debugger = (struct ARMDebugger*) platform;
89 struct ARMCore* cpu = debugger->cpu;
90 cpu->nextEvent = cpu->cycles;
91 if (reason == DEBUGGER_ENTER_BREAKPOINT) {
92 struct ARMDebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->swBreakpoints, _ARMPCAddress(cpu));
93 if (breakpoint && breakpoint->isSw) {
94 info->address = breakpoint->address;
95 if (debugger->clearSoftwareBreakpoint) {
96 debugger->clearSoftwareBreakpoint(debugger, breakpoint->address, breakpoint->sw.mode, breakpoint->sw.opcode);
97 }
98
99 ARMRunFake(cpu, breakpoint->sw.opcode);
100
101 if (debugger->setSoftwareBreakpoint) {
102 debugger->setSoftwareBreakpoint(debugger, breakpoint->address, breakpoint->sw.mode, &breakpoint->sw.opcode);
103 }
104 }
105 }
106 if (debugger->entered) {
107 debugger->entered(debugger->d.p, reason, info);
108 }
109}
110
111bool ARMDebuggerSetSoftwareBreakpoint(struct mDebuggerPlatform* d, uint32_t address, enum ExecutionMode mode) {
112 struct ARMDebugger* debugger = (struct ARMDebugger*) d;
113 uint32_t opcode;
114 if (!debugger->setSoftwareBreakpoint || !debugger->setSoftwareBreakpoint(debugger, address, mode, &opcode)) {
115 return false;
116 }
117
118 struct ARMDebugBreakpoint* breakpoint = ARMDebugBreakpointListAppend(&debugger->swBreakpoints);
119 breakpoint->address = address;
120 breakpoint->isSw = true;
121 breakpoint->sw.opcode = opcode;
122 breakpoint->sw.mode = mode;
123
124 return true;
125}
126
127static void ARMDebuggerSetBreakpoint(struct mDebuggerPlatform* d, uint32_t address) {
128 struct ARMDebugger* debugger = (struct ARMDebugger*) d;
129 struct ARMDebugBreakpoint* breakpoint = ARMDebugBreakpointListAppend(&debugger->breakpoints);
130 breakpoint->address = address;
131 breakpoint->isSw = false;
132}
133
134static void ARMDebuggerClearBreakpoint(struct mDebuggerPlatform* d, uint32_t address) {
135 struct ARMDebugger* debugger = (struct ARMDebugger*) d;
136 struct ARMDebugBreakpointList* breakpoints = &debugger->breakpoints;
137 size_t i;
138 for (i = 0; i < ARMDebugBreakpointListSize(breakpoints); ++i) {
139 if (ARMDebugBreakpointListGetPointer(breakpoints, i)->address == address) {
140 ARMDebugBreakpointListShift(breakpoints, i, 1);
141 }
142 }
143}
144
145static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform* d) {
146 struct ARMDebugger* debugger = (struct ARMDebugger*) d;
147 return ARMDebugBreakpointListSize(&debugger->breakpoints) || ARMDebugWatchpointListSize(&debugger->watchpoints);
148}
149
150static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t address, enum mWatchpointType type) {
151 struct ARMDebugger* debugger = (struct ARMDebugger*) d;
152 if (!ARMDebugWatchpointListSize(&debugger->watchpoints)) {
153 ARMDebuggerInstallMemoryShim(debugger);
154 }
155 struct ARMDebugWatchpoint* watchpoint = ARMDebugWatchpointListAppend(&debugger->watchpoints);
156 watchpoint->address = address;
157 watchpoint->type = type;
158}
159
160static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t address) {
161 struct ARMDebugger* debugger = (struct ARMDebugger*) d;
162 struct ARMDebugWatchpointList* watchpoints = &debugger->watchpoints;
163 size_t i;
164 for (i = 0; i < ARMDebugWatchpointListSize(watchpoints); ++i) {
165 if (ARMDebugWatchpointListGetPointer(watchpoints, i)->address == address) {
166 ARMDebugWatchpointListShift(watchpoints, i, 1);
167 }
168 }
169 if (!ARMDebugWatchpointListSize(&debugger->watchpoints)) {
170 ARMDebuggerRemoveMemoryShim(debugger);
171 }
172}