src/debugger/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.h"
9#include "isa-inlines.h"
10
11#include "memory-debugger.h"
12
13const uint32_t ARM_DEBUGGER_ID = 0xDEADBEEF;
14
15DEFINE_VECTOR(DebugBreakpointList, struct DebugBreakpoint);
16DEFINE_VECTOR(DebugWatchpointList, struct DebugWatchpoint);
17
18static struct DebugBreakpoint* _lookupBreakpoint(struct DebugBreakpointList* breakpoints, uint32_t address) {
19 size_t i;
20 for (i = 0; i < DebugBreakpointListSize(breakpoints); ++i) {
21 if (DebugBreakpointListGetPointer(breakpoints, i)->address == address) {
22 return DebugBreakpointListGetPointer(breakpoints, i);
23 }
24 }
25 return 0;
26}
27
28static void _checkBreakpoints(struct ARMDebugger* debugger) {
29 int instructionLength;
30 enum ExecutionMode mode = debugger->cpu->cpsr.t;
31 if (mode == MODE_ARM) {
32 instructionLength = WORD_SIZE_ARM;
33 } else {
34 instructionLength = WORD_SIZE_THUMB;
35 }
36 struct DebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->breakpoints, debugger->cpu->gprs[ARM_PC] - instructionLength);
37 if (!breakpoint) {
38 return;
39 }
40 struct DebuggerEntryInfo info = {
41 .address = breakpoint->address
42 };
43 ARMDebuggerEnter(debugger, DEBUGGER_ENTER_BREAKPOINT, &info);
44}
45
46static void ARMDebuggerInit(void* cpu, struct mCPUComponent*);
47static void ARMDebuggerDeinit(struct mCPUComponent*);
48
49void ARMDebuggerCreate(struct ARMDebugger* debugger) {
50 debugger->d.id = ARM_DEBUGGER_ID;
51 debugger->d.init = ARMDebuggerInit;
52 debugger->d.deinit = ARMDebuggerDeinit;
53}
54
55void ARMDebuggerInit(void* cpu, struct mCPUComponent* component) {
56 struct ARMDebugger* debugger = (struct ARMDebugger*) component;
57 debugger->cpu = cpu;
58 debugger->state = DEBUGGER_RUNNING;
59 debugger->originalMemory = debugger->cpu->memory;
60 debugger->currentBreakpoint = 0;
61 DebugBreakpointListInit(&debugger->breakpoints, 0);
62 DebugBreakpointListInit(&debugger->swBreakpoints, 0);
63 DebugWatchpointListInit(&debugger->watchpoints, 0);
64 if (debugger->init) {
65 debugger->init(debugger);
66 }
67}
68
69void ARMDebuggerDeinit(struct mCPUComponent* component) {
70 struct ARMDebugger* debugger = (struct ARMDebugger*) component;
71 debugger->deinit(debugger);
72 DebugBreakpointListDeinit(&debugger->breakpoints);
73 DebugBreakpointListDeinit(&debugger->swBreakpoints);
74 DebugWatchpointListDeinit(&debugger->watchpoints);
75}
76
77void ARMDebuggerRun(struct ARMDebugger* debugger) {
78 switch (debugger->state) {
79 case DEBUGGER_RUNNING:
80 if (!DebugBreakpointListSize(&debugger->breakpoints) && !DebugWatchpointListSize(&debugger->watchpoints)) {
81 ARMRunLoop(debugger->cpu);
82 } else {
83 ARMRun(debugger->cpu);
84 _checkBreakpoints(debugger);
85 }
86 break;
87 case DEBUGGER_CUSTOM:
88 ARMRun(debugger->cpu);
89 _checkBreakpoints(debugger);
90 debugger->custom(debugger);
91 break;
92 case DEBUGGER_PAUSED:
93 if (debugger->paused) {
94 debugger->paused(debugger);
95 } else {
96 debugger->state = DEBUGGER_RUNNING;
97 }
98 if (debugger->state != DEBUGGER_PAUSED && debugger->currentBreakpoint) {
99 if (debugger->currentBreakpoint->isSw && debugger->setSoftwareBreakpoint) {
100 debugger->setSoftwareBreakpoint(debugger, debugger->currentBreakpoint->address, debugger->currentBreakpoint->sw.mode, &debugger->currentBreakpoint->sw.opcode);
101 }
102 debugger->currentBreakpoint = 0;
103 }
104 break;
105 case DEBUGGER_SHUTDOWN:
106 return;
107 }
108}
109
110void ARMDebuggerEnter(struct ARMDebugger* debugger, enum DebuggerEntryReason reason, struct DebuggerEntryInfo* info) {
111 debugger->state = DEBUGGER_PAUSED;
112 struct ARMCore* cpu = debugger->cpu;
113 cpu->nextEvent = cpu->cycles;
114 if (reason == DEBUGGER_ENTER_BREAKPOINT) {
115 struct DebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->swBreakpoints, _ARMPCAddress(cpu));
116 debugger->currentBreakpoint = breakpoint;
117 if (breakpoint && breakpoint->isSw) {
118 info->address = breakpoint->address;
119 if (debugger->clearSoftwareBreakpoint) {
120 debugger->clearSoftwareBreakpoint(debugger, breakpoint->address, breakpoint->sw.mode, breakpoint->sw.opcode);
121 }
122
123 ARMRunFake(cpu, breakpoint->sw.opcode);
124 }
125 }
126 if (debugger->entered) {
127 debugger->entered(debugger, reason, info);
128 }
129}
130
131void ARMDebuggerSetBreakpoint(struct ARMDebugger* debugger, uint32_t address) {
132 struct DebugBreakpoint* breakpoint = DebugBreakpointListAppend(&debugger->breakpoints);
133 breakpoint->address = address;
134 breakpoint->isSw = false;
135}
136
137bool ARMDebuggerSetSoftwareBreakpoint(struct ARMDebugger* debugger, uint32_t address, enum ExecutionMode mode) {
138 uint32_t opcode;
139 if (!debugger->setSoftwareBreakpoint || !debugger->setSoftwareBreakpoint(debugger, address, mode, &opcode)) {
140 return false;
141 }
142
143 struct DebugBreakpoint* breakpoint = DebugBreakpointListAppend(&debugger->swBreakpoints);
144 breakpoint->address = address;
145 breakpoint->isSw = true;
146 breakpoint->sw.opcode = opcode;
147 breakpoint->sw.mode = mode;
148
149 return true;
150}
151
152void ARMDebuggerClearBreakpoint(struct ARMDebugger* debugger, uint32_t address) {
153 struct DebugBreakpointList* breakpoints = &debugger->breakpoints;
154 size_t i;
155 for (i = 0; i < DebugBreakpointListSize(breakpoints); ++i) {
156 if (DebugBreakpointListGetPointer(breakpoints, i)->address == address) {
157 DebugBreakpointListShift(breakpoints, i, 1);
158 }
159 }
160
161}
162
163void ARMDebuggerSetWatchpoint(struct ARMDebugger* debugger, uint32_t address, enum WatchpointType type) {
164 if (!DebugWatchpointListSize(&debugger->watchpoints)) {
165 ARMDebuggerInstallMemoryShim(debugger);
166 }
167 struct DebugWatchpoint* watchpoint = DebugWatchpointListAppend(&debugger->watchpoints);
168 watchpoint->address = address;
169 watchpoint->type = type;
170}
171
172void ARMDebuggerClearWatchpoint(struct ARMDebugger* debugger, uint32_t address) {
173 struct DebugWatchpointList* watchpoints = &debugger->watchpoints;
174 size_t i;
175 for (i = 0; i < DebugWatchpointListSize(watchpoints); ++i) {
176 if (DebugWatchpointListGetPointer(watchpoints, i)->address == address) {
177 DebugWatchpointListShift(watchpoints, i, 1);
178 }
179 }
180 if (!DebugWatchpointListSize(&debugger->watchpoints)) {
181 ARMDebuggerRemoveMemoryShim(debugger);
182 }
183}