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