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