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