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