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 "DebuggerConsoleController.h"
7
8 #include "CoreController.h"
9
10 #include <QMutexLocker>
11 #include <QThread>
12
13 #include <mgba/internal/debugger/cli-debugger.h>
14
15 using namespace QGBA;
16
DebuggerConsoleController(QObject * parent)17 DebuggerConsoleController::DebuggerConsoleController(QObject* parent)
18 : DebuggerController(&m_cliDebugger.d, parent)
19 {
20 m_backend.d.printf = printf;
21 m_backend.d.init = init;
22 m_backend.d.deinit = deinit;
23 m_backend.d.readline = readLine;
24 m_backend.d.lineAppend = lineAppend;
25 m_backend.d.historyLast = historyLast;
26 m_backend.d.historyAppend = historyAppend;
27 m_backend.self = this;
28
29 CLIDebuggerCreate(&m_cliDebugger);
30 CLIDebuggerAttachBackend(&m_cliDebugger, &m_backend.d);
31 }
32
enterLine(const QString & line)33 void DebuggerConsoleController::enterLine(const QString& line) {
34 CoreController::Interrupter interrupter(m_gameController);
35 QMutexLocker lock(&m_mutex);
36 m_lines.append(line);
37 if (m_cliDebugger.d.state == DEBUGGER_RUNNING) {
38 mDebuggerEnter(&m_cliDebugger.d, DEBUGGER_ENTER_MANUAL, nullptr);
39 }
40 m_cond.wakeOne();
41 }
42
detach()43 void DebuggerConsoleController::detach() {
44 {
45 CoreController::Interrupter interrupter(m_gameController);
46 QMutexLocker lock(&m_mutex);
47 if (m_cliDebugger.d.state != DEBUGGER_SHUTDOWN) {
48 m_lines.append(QString());
49 m_cond.wakeOne();
50 }
51 }
52 DebuggerController::detach();
53 }
54
attachInternal()55 void DebuggerConsoleController::attachInternal() {
56 CoreController::Interrupter interrupter(m_gameController);
57 QMutexLocker lock(&m_mutex);
58 m_history.clear();
59 mCore* core = m_gameController->thread()->core;
60 CLIDebuggerAttachBackend(&m_cliDebugger, &m_backend.d);
61 CLIDebuggerAttachSystem(&m_cliDebugger, core->cliDebuggerSystem(core));
62 }
63
printf(struct CLIDebuggerBackend * be,const char * fmt,...)64 void DebuggerConsoleController::printf(struct CLIDebuggerBackend* be, const char* fmt, ...) {
65 Backend* consoleBe = reinterpret_cast<Backend*>(be);
66 DebuggerConsoleController* self = consoleBe->self;
67 va_list args;
68 va_start(args, fmt);
69 self->log(QString().vsprintf(fmt, args));
70 va_end(args);
71 }
72
init(struct CLIDebuggerBackend * be)73 void DebuggerConsoleController::init(struct CLIDebuggerBackend* be) {
74 Backend* consoleBe = reinterpret_cast<Backend*>(be);
75 DebuggerConsoleController* self = consoleBe->self;
76 UNUSED(self);
77 }
78
deinit(struct CLIDebuggerBackend * be)79 void DebuggerConsoleController::deinit(struct CLIDebuggerBackend* be) {
80 Backend* consoleBe = reinterpret_cast<Backend*>(be);
81 DebuggerConsoleController* self = consoleBe->self;
82 if (QThread::currentThread() == self->thread() && be->p->d.state != DEBUGGER_SHUTDOWN) {
83 self->m_lines.append(QString());
84 self->m_cond.wakeOne();
85 }
86 }
87
readLine(struct CLIDebuggerBackend * be,size_t * len)88 const char* DebuggerConsoleController::readLine(struct CLIDebuggerBackend* be, size_t* len) {
89 Backend* consoleBe = reinterpret_cast<Backend*>(be);
90 DebuggerConsoleController* self = consoleBe->self;
91 CoreController::Interrupter interrupter(self->m_gameController);
92 QMutexLocker lock(&self->m_mutex);
93 while (self->m_lines.isEmpty()) {
94 self->m_cond.wait(&self->m_mutex);
95 }
96 QString last = self->m_lines.takeFirst();
97 if (last.isNull()) {
98 return nullptr;
99 }
100 self->m_last = last.toUtf8();
101 *len = self->m_last.size();
102 return self->m_last.constData();
103
104 }
105
lineAppend(struct CLIDebuggerBackend * be,const char * line)106 void DebuggerConsoleController::lineAppend(struct CLIDebuggerBackend* be, const char* line) {
107 Backend* consoleBe = reinterpret_cast<Backend*>(be);
108 DebuggerConsoleController* self = consoleBe->self;
109 self->lineAppend(QString::fromUtf8(line));
110 }
111
historyLast(struct CLIDebuggerBackend * be,size_t * len)112 const char* DebuggerConsoleController::historyLast(struct CLIDebuggerBackend* be, size_t* len) {
113 Backend* consoleBe = reinterpret_cast<Backend*>(be);
114 DebuggerConsoleController* self = consoleBe->self;
115 CoreController::Interrupter interrupter(self->m_gameController);
116 QMutexLocker lock(&self->m_mutex);
117 if (self->m_history.isEmpty()) {
118 return "i";
119 }
120 self->m_last = self->m_history.last().toUtf8();
121 *len = self->m_last.size();
122 return self->m_last.constData();
123 }
124
historyAppend(struct CLIDebuggerBackend * be,const char * line)125 void DebuggerConsoleController::historyAppend(struct CLIDebuggerBackend* be, const char* line) {
126 Backend* consoleBe = reinterpret_cast<Backend*>(be);
127 DebuggerConsoleController* self = consoleBe->self;
128 CoreController::Interrupter interrupter(self->m_gameController);
129 QMutexLocker lock(&self->m_mutex);
130 self->m_history.append(QString::fromUtf8(line));
131 }
132