src/debugger/debugger.c (view raw)
1/* Copyright (c) 2013-2016 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 <mgba/debugger/debugger.h>
7
8#include <mgba/core/core.h>
9
10#include <mgba/internal/debugger/cli-debugger.h>
11#include <mgba/internal/debugger/symbols.h>
12
13#ifdef USE_GDB_STUB
14#include <mgba/internal/debugger/gdb-stub.h>
15#endif
16
17#if ENABLE_SCRIPTING
18#include <mgba/core/scripting.h>
19#endif
20
21const uint32_t DEBUGGER_ID = 0xDEADBEEF;
22
23mLOG_DEFINE_CATEGORY(DEBUGGER, "Debugger", "core.debugger");
24
25DEFINE_VECTOR(mBreakpointList, struct mBreakpoint);
26DEFINE_VECTOR(mWatchpointList, struct mWatchpoint);
27
28static void mDebuggerInit(void* cpu, struct mCPUComponent* component);
29static void mDebuggerDeinit(struct mCPUComponent* component);
30
31struct mDebugger* mDebuggerCreate(enum mDebuggerType type, struct mCore* core) {
32 if (!core->supportsDebuggerType(core, type)) {
33 return NULL;
34 }
35
36 union DebugUnion {
37 struct mDebugger d;
38 struct CLIDebugger cli;
39#ifdef USE_GDB_STUB
40 struct GDBStub gdb;
41#endif
42 };
43
44 union DebugUnion* debugger = malloc(sizeof(union DebugUnion));
45 memset(debugger, 0, sizeof(*debugger));
46
47 switch (type) {
48 case DEBUGGER_CLI:
49 CLIDebuggerCreate(&debugger->cli);
50 struct CLIDebuggerSystem* sys = core->cliDebuggerSystem(core);
51 CLIDebuggerAttachSystem(&debugger->cli, sys);
52 break;
53 case DEBUGGER_GDB:
54#ifdef USE_GDB_STUB
55 GDBStubCreate(&debugger->gdb);
56 GDBStubListen(&debugger->gdb, 2345, 0);
57 break;
58#endif
59 case DEBUGGER_NONE:
60 case DEBUGGER_CUSTOM:
61 case DEBUGGER_MAX:
62 free(debugger);
63 return 0;
64 break;
65 }
66
67 return &debugger->d;
68}
69
70void mDebuggerAttach(struct mDebugger* debugger, struct mCore* core) {
71 debugger->d.id = DEBUGGER_ID;
72 debugger->d.init = mDebuggerInit;
73 debugger->d.deinit = mDebuggerDeinit;
74 debugger->core = core;
75 if (!debugger->core->symbolTable) {
76 debugger->core->loadSymbols(debugger->core, NULL);
77 }
78 debugger->platform = core->debuggerPlatform(core);
79 debugger->platform->p = debugger;
80 core->attachDebugger(core, debugger);
81}
82
83void mDebuggerRun(struct mDebugger* debugger) {
84 switch (debugger->state) {
85 case DEBUGGER_RUNNING:
86 if (!debugger->platform->hasBreakpoints(debugger->platform)) {
87 debugger->core->runLoop(debugger->core);
88 } else {
89 debugger->core->step(debugger->core);
90 debugger->platform->checkBreakpoints(debugger->platform);
91 }
92 break;
93 case DEBUGGER_CALLBACK:
94 debugger->core->step(debugger->core);
95 debugger->platform->checkBreakpoints(debugger->platform);
96 debugger->custom(debugger);
97 break;
98 case DEBUGGER_PAUSED:
99 if (debugger->paused) {
100 debugger->paused(debugger);
101 } else {
102 debugger->state = DEBUGGER_RUNNING;
103 }
104 break;
105 case DEBUGGER_SHUTDOWN:
106 return;
107 }
108}
109
110void mDebuggerRunFrame(struct mDebugger* debugger) {
111 int32_t frame = debugger->core->frameCounter(debugger->core);
112 do {
113 mDebuggerRun(debugger);
114 } while (debugger->core->frameCounter(debugger->core) == frame);
115}
116
117void mDebuggerEnter(struct mDebugger* debugger, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
118 debugger->state = DEBUGGER_PAUSED;
119 if (debugger->platform->entered) {
120 debugger->platform->entered(debugger->platform, reason, info);
121 }
122#ifdef ENABLE_SCRIPTING
123 if (debugger->bridge) {
124 mScriptBridgeDebuggerEntered(debugger->bridge, reason, info);
125 }
126#endif
127}
128
129static void mDebuggerInit(void* cpu, struct mCPUComponent* component) {
130 struct mDebugger* debugger = (struct mDebugger*) component;
131 debugger->state = DEBUGGER_RUNNING;
132 debugger->platform->init(cpu, debugger->platform);
133 if (debugger->init) {
134 debugger->init(debugger);
135 }
136}
137
138static void mDebuggerDeinit(struct mCPUComponent* component) {
139 struct mDebugger* debugger = (struct mDebugger*) component;
140 if (debugger->deinit) {
141 debugger->deinit(debugger);
142 }
143 debugger->platform->deinit(debugger->platform);
144}
145
146bool mDebuggerLookupIdentifier(struct mDebugger* debugger, const char* name, int32_t* value, int* segment) {
147 *segment = -1;
148#ifdef ENABLE_SCRIPTING
149 if (debugger->bridge && mScriptBridgeLookupSymbol(debugger->bridge, name, value)) {
150 return true;
151 }
152#endif
153 if (debugger->core->symbolTable && mDebuggerSymbolLookup(debugger->core->symbolTable, name, value, segment)) {
154 return true;
155 }
156 if (debugger->core->lookupIdentifier(debugger->core, name, value, segment)) {
157 return true;
158 }
159 if (debugger->platform && debugger->platform->getRegister(debugger->platform, name, value)) {
160 return true;
161 }
162 return false;
163}