forked from qt-creator/qt-creator
debugger: make autotest compilable and non-locking again
Change-Id: Ia7cb9e3f4d8aabc1bcd2580dc9d03d06989df1dd Reviewed-on: http://codereview.qt.nokia.com/265 Reviewed-by: hjk <qthjk@ovi.com> Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
This commit is contained in:
@@ -36,16 +36,11 @@
|
|||||||
|
|
||||||
//bool checkUninitialized = true;
|
//bool checkUninitialized = true;
|
||||||
bool checkUninitialized = false;
|
bool checkUninitialized = false;
|
||||||
//#define DO_DEBUG 1
|
#define DO_DEBUG 1
|
||||||
//TESTED_COMPONENT=src/plugins/debugger/gdb
|
//TESTED_COMPONENT=src/plugins/debugger/gdb
|
||||||
|
|
||||||
#include "gdb/gdbmi.h"
|
#include "gdb/gdbmi.h"
|
||||||
|
|
||||||
#include <QtCore/QThread>
|
|
||||||
#include <QtCore/QMutex>
|
|
||||||
#include <QtCore/QSignalMapper>
|
|
||||||
#include <QtCore/QWaitCondition>
|
|
||||||
|
|
||||||
#ifdef QT_GUI_LIB
|
#ifdef QT_GUI_LIB
|
||||||
#include <QtGui/QBitmap>
|
#include <QtGui/QBitmap>
|
||||||
#include <QtGui/QBrush>
|
#include <QtGui/QBrush>
|
||||||
@@ -97,7 +92,7 @@ bool checkUninitialized = false;
|
|||||||
#endif
|
#endif
|
||||||
#define DEBUGX(s) qDebug() << s
|
#define DEBUGX(s) qDebug() << s
|
||||||
|
|
||||||
#define gettid() QString("0x%1").arg((qulonglong)(void *)currentThread(), 0, 16)
|
#define gettid() QString("0x%1").arg((qulonglong)(void *)currentGdbWrapper(), 0, 16)
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
QString gdbBinary = "c:\\MinGw\\bin\\gdb.exe";
|
QString gdbBinary = "c:\\MinGw\\bin\\gdb.exe";
|
||||||
@@ -186,12 +181,14 @@ struct QString3
|
|||||||
|
|
||||||
class tst_Gdb;
|
class tst_Gdb;
|
||||||
|
|
||||||
class Thread : public QThread
|
class GdbWrapper : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Thread(tst_Gdb *test);
|
GdbWrapper(tst_Gdb *test);
|
||||||
|
~GdbWrapper();
|
||||||
|
|
||||||
void startup(QProcess *proc);
|
void startup(QProcess *proc);
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
@@ -199,25 +196,34 @@ public:
|
|||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void readStandardOutput();
|
void readStandardOutput();
|
||||||
|
bool parseOutput(const QByteArray &ba);
|
||||||
void readStandardError();
|
void readStandardError();
|
||||||
void handleGdbStarted();
|
void handleGdbStarted();
|
||||||
void handleGdbError(QProcess::ProcessError);
|
void handleGdbError(QProcess::ProcessError);
|
||||||
void handleGdbFinished(int, QProcess::ExitStatus);
|
void handleGdbFinished(int, QProcess::ExitStatus);
|
||||||
void writeToGdbRequested(const QByteArray &ba)
|
|
||||||
|
QByteArray writeToGdbRequested(const QByteArray &ba)
|
||||||
{
|
{
|
||||||
DEBUG("THREAD GDB IN: " << ba);
|
DEBUG("GDB IN: " << ba);
|
||||||
m_proc->write(ba);
|
m_proc.write(ba);
|
||||||
m_proc->write("\n");
|
m_proc.write("\n");
|
||||||
|
while (true) {
|
||||||
|
m_proc.waitForReadyRead();
|
||||||
|
QByteArray output = m_proc.readAllStandardOutput();
|
||||||
|
if (parseOutput(output))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return m_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QByteArray m_output;
|
|
||||||
QByteArray m_lastStopped; // last seen "*stopped" message
|
QByteArray m_lastStopped; // last seen "*stopped" message
|
||||||
int m_line; // line extracted from last "*stopped" message
|
int m_line; // line extracted from last "*stopped" message
|
||||||
QProcess *m_proc; // owned
|
QProcess m_proc;
|
||||||
tst_Gdb *m_test; // not owned
|
tst_Gdb *m_test; // not owned
|
||||||
QString m_errorString;
|
QString m_errorString;
|
||||||
|
QByteArray m_buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
class tst_Gdb : public QObject
|
class tst_Gdb : public QObject
|
||||||
@@ -232,8 +238,10 @@ public:
|
|||||||
const QByteArray &expanded = QByteArray(), bool fancy = true);
|
const QByteArray &expanded = QByteArray(), bool fancy = true);
|
||||||
void next(int n = 1);
|
void next(int n = 1);
|
||||||
|
|
||||||
signals:
|
QByteArray writeToGdb(const QByteArray &ba)
|
||||||
void writeToGdb(const QByteArray &ba);
|
{
|
||||||
|
return m_gdb->writeToGdbRequested(ba);
|
||||||
|
}
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void initTestCase();
|
void initTestCase();
|
||||||
@@ -307,12 +315,9 @@ private:
|
|||||||
|
|
||||||
QHash<QByteArray, int> m_lineForLabel;
|
QHash<QByteArray, int> m_lineForLabel;
|
||||||
QByteArray m_function;
|
QByteArray m_function;
|
||||||
Thread m_thread;
|
GdbWrapper *m_gdb;
|
||||||
};
|
};
|
||||||
|
|
||||||
QByteArray buffer;
|
|
||||||
QSemaphore freeBytes(1);
|
|
||||||
QSemaphore usedBytes(0);
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Dumpers
|
// Dumpers
|
||||||
@@ -358,66 +363,82 @@ static const QByteArray specQChar(QChar ch)
|
|||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Gdb Thread
|
// GdbWrapper
|
||||||
//
|
//
|
||||||
/////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
Thread::Thread(tst_Gdb *test) : m_proc(0), m_test(test)
|
GdbWrapper::GdbWrapper(tst_Gdb *test) : m_test(test)
|
||||||
{
|
{
|
||||||
//#ifdef Q_OS_WIN
|
qWarning() << "SETUP START\n\n";
|
||||||
// qDebug() << "\nTHREAD CREATED" << GetCurrentProcessId() << GetCurrentThreadId();
|
#ifndef Q_CC_GNU
|
||||||
//#else
|
QSKIP("gdb test not applicable for compiler", SkipAll);
|
||||||
// qDebug() << "\nTHREAD CREATED" << getpid() << gettid();
|
#endif
|
||||||
//#endif
|
//qDebug() << "\nRUN" << getpid() << gettid();
|
||||||
moveToThread(this);
|
QStringList args;
|
||||||
connect(m_test, SIGNAL(writeToGdb(QByteArray)),
|
args << QLatin1String("-i")
|
||||||
this, SLOT(writeToGdbRequested(QByteArray)), Qt::QueuedConnection);
|
<< QLatin1String("mi") << QLatin1String("--args")
|
||||||
|
<< qApp->applicationFilePath();
|
||||||
|
qWarning() << "Starting" << gdbBinary << args;
|
||||||
|
m_proc.start(gdbBinary, args);
|
||||||
|
if (!m_proc.waitForStarted()) {
|
||||||
|
const QString msg = QString::fromLatin1("Unable to run %1: %2")
|
||||||
|
.arg(gdbBinary, m_proc.errorString());
|
||||||
|
QSKIP(msg.toLatin1().constData(), SkipAll);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::startup(QProcess *proc)
|
connect(&m_proc, SIGNAL(error(QProcess::ProcessError)),
|
||||||
{
|
|
||||||
m_proc = proc;
|
|
||||||
m_proc->moveToThread(this);
|
|
||||||
connect(m_proc, SIGNAL(error(QProcess::ProcessError)),
|
|
||||||
this, SLOT(handleGdbError(QProcess::ProcessError)));
|
this, SLOT(handleGdbError(QProcess::ProcessError)));
|
||||||
connect(m_proc, SIGNAL(finished(int, QProcess::ExitStatus)),
|
connect(&m_proc, SIGNAL(finished(int, QProcess::ExitStatus)),
|
||||||
this, SLOT(handleGdbFinished(int, QProcess::ExitStatus)));
|
this, SLOT(handleGdbFinished(int, QProcess::ExitStatus)));
|
||||||
connect(m_proc, SIGNAL(started()),
|
connect(&m_proc, SIGNAL(started()),
|
||||||
this, SLOT(handleGdbStarted()));
|
this, SLOT(handleGdbStarted()));
|
||||||
connect(m_proc, SIGNAL(readyReadStandardOutput()),
|
connect(&m_proc, SIGNAL(readyReadStandardOutput()),
|
||||||
this, SLOT(readStandardOutput()));
|
this, SLOT(readStandardOutput()));
|
||||||
connect(m_proc, SIGNAL(readyReadStandardError()),
|
connect(&m_proc, SIGNAL(readyReadStandardError()),
|
||||||
this, SLOT(readStandardError()));
|
this, SLOT(readStandardError()));
|
||||||
start();
|
|
||||||
|
m_proc.write("python execfile('../../../share/qtcreator/gdbmacros/dumper.py')\n");
|
||||||
|
m_proc.write("python execfile('../../../share/qtcreator/gdbmacros/gdbmacros.py')\n");
|
||||||
|
m_proc.write("bbsetup\n");
|
||||||
|
m_proc.write("break breaker\n");
|
||||||
|
m_proc.write("handle SIGSTOP stop pass\n");
|
||||||
|
m_proc.write("run\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::handleGdbError(QProcess::ProcessError error)
|
GdbWrapper::~GdbWrapper()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void GdbWrapper::handleGdbError(QProcess::ProcessError error)
|
||||||
{
|
{
|
||||||
qDebug() << "GDB ERROR: " << error;
|
qDebug() << "GDB ERROR: " << error;
|
||||||
//this->exit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::handleGdbFinished(int code, QProcess::ExitStatus st)
|
void GdbWrapper::handleGdbFinished(int code, QProcess::ExitStatus st)
|
||||||
{
|
{
|
||||||
qDebug() << "GDB FINISHED: " << code << st;
|
qDebug() << "GDB FINISHED: " << code << st;
|
||||||
//m_waitCondition.wakeAll();
|
|
||||||
//this->exit();
|
|
||||||
//throw 42;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::readStandardOutput()
|
void GdbWrapper::readStandardOutput()
|
||||||
{
|
{
|
||||||
QByteArray ba = m_proc->readAllStandardOutput();
|
//parseOutput(m_proc.readAllStandardOutput());
|
||||||
DEBUG("THREAD GDB OUT: " << ba);
|
}
|
||||||
|
|
||||||
|
bool GdbWrapper::parseOutput(const QByteArray &ba0)
|
||||||
|
{
|
||||||
|
if (ba0.isEmpty())
|
||||||
|
return false;
|
||||||
|
QByteArray ba = ba0;
|
||||||
|
DEBUG("GDB OUT: " << ba);
|
||||||
// =library-loaded...
|
// =library-loaded...
|
||||||
if (ba.startsWith("=")) {
|
if (ba.startsWith("=")) {
|
||||||
//DEBUG("LIBRARY LOADED");
|
DEBUG("LIBRARY LOADED");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
if (ba.startsWith("*stopped")) {
|
if (ba.startsWith("*stopped")) {
|
||||||
m_lastStopped = ba;
|
m_lastStopped = ba;
|
||||||
DEBUG("THREAD GDB OUT 2: " << ba);
|
DEBUG("GDB OUT 2: " << ba);
|
||||||
if (!ba.contains("func=\"breaker\"")) {
|
if (!ba.contains("func=\"breaker\"")) {
|
||||||
int pos1 = ba.indexOf(",line=\"") + 7;
|
int pos1 = ba.indexOf(",line=\"") + 7;
|
||||||
int pos2 = ba.indexOf("\"", pos1);
|
int pos2 = ba.indexOf("\"", pos1);
|
||||||
@@ -467,61 +488,41 @@ void Thread::readStandardOutput()
|
|||||||
|
|
||||||
// No interesting output before 'locals=...'
|
// No interesting output before 'locals=...'
|
||||||
int pos = ba.indexOf("locals={iname=");
|
int pos = ba.indexOf("locals={iname=");
|
||||||
if (pos == -1 && m_output.isEmpty())
|
if (pos == -1 && ba.isEmpty())
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
if (m_output.isEmpty())
|
QByteArray output;
|
||||||
m_output = ba.mid(pos);
|
if (output.isEmpty())
|
||||||
|
output = ba.mid(pos);
|
||||||
else
|
else
|
||||||
m_output += ba;
|
output += ba;
|
||||||
// Up to ^done\n(gdb)
|
// Up to ^done\n(gdb)
|
||||||
pos = m_output.indexOf("(gdb)");
|
pos = output.indexOf("(gdb)");
|
||||||
if (pos == -1)
|
if (pos == -1)
|
||||||
return;
|
return true;
|
||||||
m_output = m_output.left(pos);
|
output = output.left(pos);
|
||||||
pos = m_output.indexOf("^done");
|
pos = output.indexOf("^done");
|
||||||
if (pos >= 4)
|
if (pos >= 4)
|
||||||
m_output = m_output.left(pos - 4);
|
output = output.left(pos - 4);
|
||||||
|
|
||||||
if (m_output.isEmpty())
|
if (output.isEmpty())
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
//qWarning() << "WAKE UP: " << m_output;
|
m_buffer += output;
|
||||||
//qDebug() << "\n2 ABOUT TO ACQUIRE FREE ";
|
return true;
|
||||||
freeBytes.acquire();
|
|
||||||
//qDebug() << "\n2 ACQUIRED FREE ";
|
|
||||||
buffer = m_output;
|
|
||||||
m_output.clear();
|
|
||||||
//m_waitCondition.wakeAll();
|
|
||||||
//qDebug() << "\n2 ABOUT TO RELEASE USED";
|
|
||||||
usedBytes.release();
|
|
||||||
//qDebug() << "\n2 RELEASED USED";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::readStandardError()
|
void GdbWrapper::readStandardError()
|
||||||
{
|
{
|
||||||
QByteArray ba = m_proc->readAllStandardError();
|
QByteArray ba = m_proc.readAllStandardError();
|
||||||
qDebug() << "THREAD GDB ERR: " << ba;
|
qDebug() << "GDB ERR: " << ba;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::handleGdbStarted()
|
void GdbWrapper::handleGdbStarted()
|
||||||
{
|
{
|
||||||
//qDebug() << "\n\nGDB STARTED" << getpid() << gettid() << "\n\n";
|
//qDebug() << "\n\nGDB STARTED" << getpid() << gettid() << "\n\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::run()
|
|
||||||
{
|
|
||||||
m_proc->write("python execfile('../../../share/qtcreator/gdbmacros/dumper.py')\n");
|
|
||||||
m_proc->write("python execfile('../../../share/qtcreator/gdbmacros/gdbmacros.py')\n");
|
|
||||||
m_proc->write("bbsetup\n");
|
|
||||||
m_proc->write("break breaker\n");
|
|
||||||
m_proc->write("handle SIGSTOP stop pass\n");
|
|
||||||
m_proc->write("run\n");
|
|
||||||
qDebug() << "\n2 THREAD RUNNING, RELEASE FREE";
|
|
||||||
freeBytes.release();
|
|
||||||
exec();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
@@ -530,32 +531,12 @@ void Thread::run()
|
|||||||
/////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
tst_Gdb::tst_Gdb()
|
tst_Gdb::tst_Gdb()
|
||||||
: m_thread(this)
|
: m_gdb(0)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_Gdb::initTestCase()
|
void tst_Gdb::initTestCase()
|
||||||
{
|
{
|
||||||
qWarning() << "SETUP START\n\n";
|
|
||||||
#ifndef Q_CC_GNU
|
|
||||||
QSKIP("gdb test not applicable for compiler", SkipAll);
|
|
||||||
#endif
|
|
||||||
//qDebug() << "\nTHREAD RUN" << getpid() << gettid();
|
|
||||||
QProcess *gdbProc = new QProcess;
|
|
||||||
QStringList args;
|
|
||||||
args << QLatin1String("-i")
|
|
||||||
<< QLatin1String("mi") << QLatin1String("--args")
|
|
||||||
<< qApp->applicationFilePath();
|
|
||||||
qWarning() << "Starting" << gdbBinary << args;
|
|
||||||
gdbProc->start(gdbBinary, args);
|
|
||||||
if (!gdbProc->waitForStarted()) {
|
|
||||||
const QString msg = QString::fromLatin1("Unable to run %1: %2")
|
|
||||||
.arg(gdbBinary, gdbProc->errorString());
|
|
||||||
delete gdbProc;
|
|
||||||
QSKIP(msg.toLatin1().constData(), SkipAll);
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString fileName = "tst_gdb.cpp";
|
const QString fileName = "tst_gdb.cpp";
|
||||||
QFile file(fileName);
|
QFile file(fileName);
|
||||||
if (!file.open(QIODevice::ReadOnly)) {
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
@@ -577,13 +558,14 @@ void tst_Gdb::initTestCase()
|
|||||||
m_lineForLabel[QByteArray(funcName + ba.mid(7, pos - 8)).trimmed()] = i + 1;
|
m_lineForLabel[QByteArray(funcName + ba.mid(7, pos - 8)).trimmed()] = i + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//freeBytes.acquire();
|
|
||||||
m_thread.startup(gdbProc);
|
Q_ASSERT(!m_gdb);
|
||||||
//usedBytes.release();
|
m_gdb = new GdbWrapper(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_Gdb::prepare(const QByteArray &function)
|
void tst_Gdb::prepare(const QByteArray &function)
|
||||||
{
|
{
|
||||||
|
Q_ASSERT(m_gdb);
|
||||||
m_function = function;
|
m_function = function;
|
||||||
writeToGdb("b " + function);
|
writeToGdb("b " + function);
|
||||||
writeToGdb("call " + function + "()");
|
writeToGdb("call " + function + "()");
|
||||||
@@ -603,26 +585,15 @@ void tst_Gdb::check(const QByteArray &label, const QByteArray &expected0,
|
|||||||
if (fancy)
|
if (fancy)
|
||||||
options += ",fancy";
|
options += ",fancy";
|
||||||
options += ",autoderef";
|
options += ",autoderef";
|
||||||
writeToGdb("bb options:" + options + " vars: expanded:" + expanded
|
QByteArray ba = writeToGdb("bb options:" + options
|
||||||
|
+ " vars: expanded:" + expanded
|
||||||
+ " typeformats: formats: watchers:\n");
|
+ " typeformats: formats: watchers:\n");
|
||||||
|
|
||||||
//bb options:fancy,autoderef vars: expanded: typeformats:63686172202a=1
|
//bb options:fancy,autoderef vars: expanded: typeformats:63686172202a=1
|
||||||
//formats: watchers:
|
//formats: watchers:
|
||||||
|
|
||||||
//qDebug() << "\n1 ABOUT TO ACQUIRE USED ";
|
|
||||||
usedBytes.acquire();
|
|
||||||
//qDebug() << "\n1 ACQUIRED USED ";
|
|
||||||
QByteArray ba = buffer;
|
|
||||||
buffer.clear();
|
|
||||||
//qDebug() << "\n1 ABOUT TO RELEASE FREE ";
|
|
||||||
freeBytes.release();
|
|
||||||
//qDebug() << "\n1 RELEASED FREE ";
|
|
||||||
|
|
||||||
//locals.fromString("{" + ba + "}");
|
//locals.fromString("{" + ba + "}");
|
||||||
QByteArray received = ba.replace("\"", "'");
|
QByteArray received = ba.replace("\"", "'");
|
||||||
//qDebug() << "OUTPUT: " << ba << "\n\n";
|
|
||||||
//qDebug() << "OUTPUT: " << locals.toString() << "\n\n";
|
|
||||||
|
|
||||||
QByteArray actual = received.trimmed();
|
QByteArray actual = received.trimmed();
|
||||||
int pos = actual.indexOf("^done");
|
int pos = actual.indexOf("^done");
|
||||||
if (pos != -1)
|
if (pos != -1)
|
||||||
@@ -633,7 +604,7 @@ void tst_Gdb::check(const QByteArray &label, const QByteArray &expected0,
|
|||||||
actual.chop(2);
|
actual.chop(2);
|
||||||
QByteArray expected = "locals={iname='local',name='Locals',value=' ',type=' ',"
|
QByteArray expected = "locals={iname='local',name='Locals',value=' ',type=' ',"
|
||||||
"children=[" + expected0 + "]}";
|
"children=[" + expected0 + "]}";
|
||||||
int line = m_thread.m_line;
|
int line = m_gdb->m_line;
|
||||||
|
|
||||||
QByteArrayList l1_0 = actual.split(',');
|
QByteArrayList l1_0 = actual.split(',');
|
||||||
QByteArrayList l1;
|
QByteArrayList l1;
|
||||||
@@ -688,7 +659,7 @@ void tst_Gdb::check(const QByteArray &label, const QByteArray &expected0,
|
|||||||
int expline = m_lineForLabel.value(m_function + '@' + label);
|
int expline = m_lineForLabel.value(m_function + '@' + label);
|
||||||
int actline = line;
|
int actline = line;
|
||||||
if (actline != expline) {
|
if (actline != expline) {
|
||||||
qWarning() << "LAST STOPPED: " << m_thread.m_lastStopped;
|
qWarning() << "LAST STOPPED: " << m_gdb->m_lastStopped;
|
||||||
}
|
}
|
||||||
QCOMPARE(actline, expline);
|
QCOMPARE(actline, expline);
|
||||||
}
|
}
|
||||||
@@ -701,10 +672,13 @@ void tst_Gdb::next(int n)
|
|||||||
|
|
||||||
void tst_Gdb::cleanupTestCase()
|
void tst_Gdb::cleanupTestCase()
|
||||||
{
|
{
|
||||||
|
Q_ASSERT(m_gdb);
|
||||||
writeToGdb("kill");
|
writeToGdb("kill");
|
||||||
writeToGdb("quit");
|
writeToGdb("quit");
|
||||||
//m_thread.m_proc->waitForFinished();
|
//m_gdb.m_proc.waitForFinished();
|
||||||
//m_thread.wait();
|
//m_gdb.wait();
|
||||||
|
delete m_gdb;
|
||||||
|
m_gdb = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user