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