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