forked from qt-creator/qt-creator
Started Console process handling for CDB.
Introduced "Suspend" mode for the process stub and corresponding mode enumeration in console process (Windows).
This commit is contained in:
86
src/libs/utils/consoleprocess.cpp
Normal file
86
src/libs/utils/consoleprocess.cpp
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator
|
||||||
|
**
|
||||||
|
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||||
|
**
|
||||||
|
** Contact: Qt Software Information (qt-info@nokia.com)
|
||||||
|
**
|
||||||
|
** Commercial Usage
|
||||||
|
**
|
||||||
|
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||||
|
** accordance with the Qt Commercial License Agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and Nokia.
|
||||||
|
**
|
||||||
|
** GNU Lesser General Public License Usage
|
||||||
|
**
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||||
|
** General Public License version 2.1 as published by the Free Software
|
||||||
|
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||||
|
** packaging of this file. Please review the following information to
|
||||||
|
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||||
|
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||||
|
**
|
||||||
|
** If you are unsure which license is appropriate for your use, please
|
||||||
|
** contact the sales department at qt-sales@nokia.com.
|
||||||
|
**
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
#include "consoleprocess.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
namespace Utils {
|
||||||
|
|
||||||
|
QString ConsoleProcess::modeOption(Mode m)
|
||||||
|
{
|
||||||
|
switch (m) {
|
||||||
|
case Debug:
|
||||||
|
return QLatin1String("debug");
|
||||||
|
case Suspend:
|
||||||
|
return QLatin1String("suspend");
|
||||||
|
case Run:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return QLatin1String("run");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ConsoleProcess::msgCommChannelFailed(const QString &error)
|
||||||
|
{
|
||||||
|
return tr("Cannot set up communication channel: %1").arg(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ConsoleProcess::msgPromptToClose()
|
||||||
|
{
|
||||||
|
//! Showed in a terminal which might have
|
||||||
|
//! a different character set on Windows.
|
||||||
|
return tr("Press <RETURN> to close this window...");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ConsoleProcess::msgCannotCreateTempFile(const QString &why)
|
||||||
|
{
|
||||||
|
return tr("Cannot create temporary file: %1").arg(why);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ConsoleProcess::msgCannotCreateTempDir(const QString & dir, const QString &why)
|
||||||
|
{
|
||||||
|
return tr("Cannot create temporary directory '%1': %2").arg(dir, why);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ConsoleProcess::msgUnexpectedOutput()
|
||||||
|
{
|
||||||
|
return tr("Unexpected output from helper program.");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ConsoleProcess::msgCannotChangeToWorkDir(const QString & dir, const QString &why)
|
||||||
|
{
|
||||||
|
return tr("Cannot change to working directory '%1': %2").arg(dir, why);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ConsoleProcess::msgCannotExecute(const QString & p, const QString &why)
|
||||||
|
{
|
||||||
|
return tr("Cannot execute '%1': %2").arg(p, why);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -59,14 +59,15 @@ class QWORKBENCH_UTILS_EXPORT ConsoleProcess : public QObject, public AbstractPr
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
enum Mode { Run, Debug, Suspend };
|
||||||
ConsoleProcess(QObject *parent = 0);
|
ConsoleProcess(QObject *parent = 0);
|
||||||
~ConsoleProcess();
|
~ConsoleProcess();
|
||||||
|
|
||||||
bool start(const QString &program, const QStringList &args);
|
bool start(const QString &program, const QStringList &args);
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
void setDebug(bool on) { m_debug = on; }
|
void setMode(Mode m) { m_mode = m; }
|
||||||
bool isDebug() const { return m_debug; }
|
Mode mode() const { return m_mode; }
|
||||||
|
|
||||||
bool isRunning() const; // This reflects the state of the console+stub
|
bool isRunning() const; // This reflects the state of the console+stub
|
||||||
qint64 applicationPID() const { return m_appPid; }
|
qint64 applicationPID() const { return m_appPid; }
|
||||||
@@ -99,6 +100,15 @@ private slots:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static QString modeOption(Mode m);
|
||||||
|
static QString msgCommChannelFailed(const QString &error);
|
||||||
|
static QString msgPromptToClose();
|
||||||
|
static QString msgCannotCreateTempFile(const QString &why);
|
||||||
|
static QString msgCannotCreateTempDir(const QString & dir, const QString &why);
|
||||||
|
static QString msgUnexpectedOutput();
|
||||||
|
static QString msgCannotChangeToWorkDir(const QString & dir, const QString &why);
|
||||||
|
static QString msgCannotExecute(const QString & p, const QString &why);
|
||||||
|
|
||||||
QString stubServerListen();
|
QString stubServerListen();
|
||||||
void stubServerShutdown();
|
void stubServerShutdown();
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
@@ -106,7 +116,7 @@ private:
|
|||||||
void cleanupInferior();
|
void cleanupInferior();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool m_debug;
|
Mode m_mode;
|
||||||
qint64 m_appPid;
|
qint64 m_appPid;
|
||||||
int m_appCode;
|
int m_appCode;
|
||||||
QString m_executable;
|
QString m_executable;
|
||||||
|
|||||||
@@ -44,14 +44,13 @@
|
|||||||
|
|
||||||
using namespace Core::Utils;
|
using namespace Core::Utils;
|
||||||
|
|
||||||
ConsoleProcess::ConsoleProcess(QObject *parent)
|
ConsoleProcess::ConsoleProcess(QObject *parent) :
|
||||||
: QObject(parent)
|
QObject(parent),
|
||||||
|
m_mode(Run),
|
||||||
|
m_appPid(0),
|
||||||
|
m_stubSocket(0),
|
||||||
|
m_settings(0)
|
||||||
{
|
{
|
||||||
m_debug = false;
|
|
||||||
m_appPid = 0;
|
|
||||||
m_stubSocket = 0;
|
|
||||||
m_settings = 0;
|
|
||||||
|
|
||||||
connect(&m_stubServer, SIGNAL(newConnection()), SLOT(stubConnectionAvailable()));
|
connect(&m_stubServer, SIGNAL(newConnection()), SLOT(stubConnectionAvailable()));
|
||||||
|
|
||||||
m_process.setProcessChannelMode(QProcess::ForwardedChannels);
|
m_process.setProcessChannelMode(QProcess::ForwardedChannels);
|
||||||
@@ -69,9 +68,9 @@ bool ConsoleProcess::start(const QString &program, const QStringList &args)
|
|||||||
if (isRunning())
|
if (isRunning())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
QString err = stubServerListen();
|
const QString err = stubServerListen();
|
||||||
if (!err.isEmpty()) {
|
if (!err.isEmpty()) {
|
||||||
emit processError(tr("Cannot set up communication channel: %1").arg(err));
|
emit processError(msgCommChannelFailed(err));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +78,7 @@ bool ConsoleProcess::start(const QString &program, const QStringList &args)
|
|||||||
m_tempFile = new QTemporaryFile();
|
m_tempFile = new QTemporaryFile();
|
||||||
if (!m_tempFile->open()) {
|
if (!m_tempFile->open()) {
|
||||||
stubServerShutdown();
|
stubServerShutdown();
|
||||||
emit processError(tr("Cannot create temporary file: %1").arg(m_tempFile->errorString()));
|
emit processError(msgCannotCreateTempFile(m_tempFile->errorString()));
|
||||||
delete m_tempFile;
|
delete m_tempFile;
|
||||||
m_tempFile = 0;
|
m_tempFile = 0;
|
||||||
return false;
|
return false;
|
||||||
@@ -94,13 +93,13 @@ bool ConsoleProcess::start(const QString &program, const QStringList &args)
|
|||||||
QStringList xtermArgs = terminalEmulator(m_settings).split(QLatin1Char(' ')); // FIXME: quoting
|
QStringList xtermArgs = terminalEmulator(m_settings).split(QLatin1Char(' ')); // FIXME: quoting
|
||||||
xtermArgs
|
xtermArgs
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
<< (QCoreApplication::applicationDirPath() + "/../Resources/qtcreator_process_stub")
|
<< (QCoreApplication::applicationDirPath() + QLatin1String("/../Resources/qtcreator_process_stub"))
|
||||||
#else
|
#else
|
||||||
<< (QCoreApplication::applicationDirPath() + "/qtcreator_process_stub")
|
<< (QCoreApplication::applicationDirPath() + QLatin1String("/qtcreator_process_stub"))
|
||||||
#endif
|
#endif
|
||||||
<< (m_debug ? "debug" : "exec")
|
<< modeOption(m_mode)
|
||||||
<< m_stubServer.fullServerName()
|
<< m_stubServer.fullServerName()
|
||||||
<< tr("Press <RETURN> to close this window...")
|
<< msgPromptToClose()
|
||||||
<< workingDirectory()
|
<< workingDirectory()
|
||||||
<< (m_tempFile ? m_tempFile->fileName() : 0)
|
<< (m_tempFile ? m_tempFile->fileName() : 0)
|
||||||
<< program << args;
|
<< program << args;
|
||||||
@@ -145,7 +144,7 @@ QString ConsoleProcess::stubServerListen()
|
|||||||
{
|
{
|
||||||
QTemporaryFile tf;
|
QTemporaryFile tf;
|
||||||
if (!tf.open())
|
if (!tf.open())
|
||||||
return tr("Cannot create temporary file: %1").arg(tf.errorString());
|
return msgCannotCreateTempFile(tf.errorString());
|
||||||
stubFifoDir = QFile::encodeName(tf.fileName());
|
stubFifoDir = QFile::encodeName(tf.fileName());
|
||||||
}
|
}
|
||||||
// By now the temp file was deleted again
|
// By now the temp file was deleted again
|
||||||
@@ -153,9 +152,9 @@ QString ConsoleProcess::stubServerListen()
|
|||||||
if (!::mkdir(m_stubServerDir.constData(), 0700))
|
if (!::mkdir(m_stubServerDir.constData(), 0700))
|
||||||
break;
|
break;
|
||||||
if (errno != EEXIST)
|
if (errno != EEXIST)
|
||||||
return tr("Cannot create temporary directory '%1': %2").arg(stubFifoDir, strerror(errno));
|
return msgCannotCreateTempDir(stubFifoDir, QString::fromLocal8Bit(strerror(errno)));
|
||||||
}
|
}
|
||||||
QString stubServer = stubFifoDir + "/stub-socket";
|
const QString stubServer = stubFifoDir + "/stub-socket";
|
||||||
if (!m_stubServer.listen(stubServer)) {
|
if (!m_stubServer.listen(stubServer)) {
|
||||||
::rmdir(m_stubServerDir.constData());
|
::rmdir(m_stubServerDir.constData());
|
||||||
return tr("Cannot create socket '%1': %2").arg(stubServer, m_stubServer.errorString());
|
return tr("Cannot create socket '%1': %2").arg(stubServer, m_stubServer.errorString());
|
||||||
@@ -190,11 +189,9 @@ void ConsoleProcess::readStubOutput()
|
|||||||
QByteArray out = m_stubSocket->readLine();
|
QByteArray out = m_stubSocket->readLine();
|
||||||
out.chop(1); // \n
|
out.chop(1); // \n
|
||||||
if (out.startsWith("err:chdir ")) {
|
if (out.startsWith("err:chdir ")) {
|
||||||
emit processError(tr("Cannot change to working directory '%1': %2")
|
emit processError(msgCannotChangeToWorkDir(workingDirectory(), errorMsg(out.mid(10).toInt())));
|
||||||
.arg(workingDirectory(), errorMsg(out.mid(10).toInt())));
|
|
||||||
} else if (out.startsWith("err:exec ")) {
|
} else if (out.startsWith("err:exec ")) {
|
||||||
emit processError(tr("Cannot execute '%1': %2")
|
emit processError(msgCannotExecute(m_executable, errorMsg(out.mid(9).toInt())));
|
||||||
.arg(m_executable, errorMsg(out.mid(9).toInt())));
|
|
||||||
} else if (out.startsWith("pid ")) {
|
} else if (out.startsWith("pid ")) {
|
||||||
// Will not need it any more
|
// Will not need it any more
|
||||||
delete m_tempFile;
|
delete m_tempFile;
|
||||||
@@ -213,7 +210,7 @@ void ConsoleProcess::readStubOutput()
|
|||||||
m_appPid = 0;
|
m_appPid = 0;
|
||||||
emit processStopped();
|
emit processStopped();
|
||||||
} else {
|
} else {
|
||||||
emit processError(tr("Unexpected output from helper program."));
|
emit processError(msgUnexpectedOutput());
|
||||||
m_process.terminate();
|
m_process.terminate();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -250,7 +247,7 @@ QString ConsoleProcess::defaultTerminalEmulator()
|
|||||||
|
|
||||||
QString ConsoleProcess::terminalEmulator(const QSettings *settings)
|
QString ConsoleProcess::terminalEmulator(const QSettings *settings)
|
||||||
{
|
{
|
||||||
QString dflt = defaultTerminalEmulator() + QLatin1String(" -e");
|
const QString dflt = defaultTerminalEmulator() + QLatin1String(" -e");
|
||||||
if (!settings)
|
if (!settings)
|
||||||
return dflt;
|
return dflt;
|
||||||
return settings->value(QLatin1String("General/TerminalEmulator"), dflt).toString();
|
return settings->value(QLatin1String("General/TerminalEmulator"), dflt).toString();
|
||||||
|
|||||||
@@ -42,18 +42,17 @@
|
|||||||
|
|
||||||
using namespace Core::Utils;
|
using namespace Core::Utils;
|
||||||
|
|
||||||
ConsoleProcess::ConsoleProcess(QObject *parent)
|
ConsoleProcess::ConsoleProcess(QObject *parent) :
|
||||||
: QObject(parent)
|
QObject(parent),
|
||||||
|
m_mode(Run),
|
||||||
|
m_appPid(0),
|
||||||
|
m_pid(0),
|
||||||
|
m_hInferior(NULL),
|
||||||
|
m_tempFile(0),
|
||||||
|
m_stubSocket(0),
|
||||||
|
processFinishedNotifier(0),
|
||||||
|
inferiorFinishedNotifier(0)
|
||||||
{
|
{
|
||||||
m_debug = false;
|
|
||||||
m_appPid = 0;
|
|
||||||
m_pid = 0;
|
|
||||||
m_hInferior = NULL;
|
|
||||||
m_tempFile = 0;
|
|
||||||
m_stubSocket = 0;
|
|
||||||
processFinishedNotifier = 0;
|
|
||||||
inferiorFinishedNotifier = 0;
|
|
||||||
|
|
||||||
connect(&m_stubServer, SIGNAL(newConnection()), SLOT(stubConnectionAvailable()));
|
connect(&m_stubServer, SIGNAL(newConnection()), SLOT(stubConnectionAvailable()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,9 +66,9 @@ bool ConsoleProcess::start(const QString &program, const QStringList &args)
|
|||||||
if (isRunning())
|
if (isRunning())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
QString err = stubServerListen();
|
const QString err = stubServerListen();
|
||||||
if (!err.isEmpty()) {
|
if (!err.isEmpty()) {
|
||||||
emit processError(tr("Cannot set up communication channel: %1").arg(err));
|
emit processError(msgCommChannelFailed(err));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,7 +76,7 @@ bool ConsoleProcess::start(const QString &program, const QStringList &args)
|
|||||||
m_tempFile = new QTemporaryFile();
|
m_tempFile = new QTemporaryFile();
|
||||||
if (!m_tempFile->open()) {
|
if (!m_tempFile->open()) {
|
||||||
stubServerShutdown();
|
stubServerShutdown();
|
||||||
emit processError(tr("Cannot create temporary file: %1").arg(m_tempFile->errorString()));
|
emit processError(msgCannotCreateTempFile(m_tempFile->errorString()));
|
||||||
delete m_tempFile;
|
delete m_tempFile;
|
||||||
m_tempFile = 0;
|
m_tempFile = 0;
|
||||||
return false;
|
return false;
|
||||||
@@ -102,15 +101,15 @@ bool ConsoleProcess::start(const QString &program, const QStringList &args)
|
|||||||
workDir.append('\\');
|
workDir.append('\\');
|
||||||
|
|
||||||
QStringList stubArgs;
|
QStringList stubArgs;
|
||||||
stubArgs << (m_debug ? "debug" : "exec")
|
stubArgs << modeOption(m_mode)
|
||||||
<< m_stubServer.fullServerName()
|
<< m_stubServer.fullServerName()
|
||||||
<< workDir
|
<< workDir
|
||||||
<< (m_tempFile ? m_tempFile->fileName() : 0)
|
<< (m_tempFile ? m_tempFile->fileName() : 0)
|
||||||
<< createWinCommandline(program, args)
|
<< createWinCommandline(program, args)
|
||||||
<< tr("Press <RETURN> to close this window...");
|
<< msgPromptToClose();
|
||||||
|
|
||||||
QString cmdLine = createWinCommandline(
|
const QString cmdLine = createWinCommandline(
|
||||||
QCoreApplication::applicationDirPath() + "/qtcreator_process_stub.exe", stubArgs);
|
QCoreApplication::applicationDirPath() + QLatin1String("/qtcreator_process_stub.exe"), stubArgs);
|
||||||
|
|
||||||
bool success = CreateProcessW(0, (WCHAR*)cmdLine.utf16(),
|
bool success = CreateProcessW(0, (WCHAR*)cmdLine.utf16(),
|
||||||
0, 0, FALSE, CREATE_NEW_CONSOLE,
|
0, 0, FALSE, CREATE_NEW_CONSOLE,
|
||||||
@@ -180,13 +179,11 @@ void ConsoleProcess::readStubOutput()
|
|||||||
QByteArray out = m_stubSocket->readLine();
|
QByteArray out = m_stubSocket->readLine();
|
||||||
out.chop(2); // \r\n
|
out.chop(2); // \r\n
|
||||||
if (out.startsWith("err:chdir ")) {
|
if (out.startsWith("err:chdir ")) {
|
||||||
emit processError(tr("Cannot change to working directory '%1': %2")
|
emit processError(msgCannotChangeToWorkDir(workingDirectory(), winErrorMessage(out.mid(10).toInt())));
|
||||||
.arg(workingDirectory(), winErrorMessage(out.mid(10).toInt())));
|
|
||||||
} else if (out.startsWith("err:exec ")) {
|
} else if (out.startsWith("err:exec ")) {
|
||||||
emit processError(tr("Cannot execute '%1': %2")
|
emit processError(msgCannotExecute(m_executable, winErrorMessage(out.mid(9).toInt())));
|
||||||
.arg(m_executable, winErrorMessage(out.mid(9).toInt())));
|
|
||||||
} else if (out.startsWith("pid ")) {
|
} else if (out.startsWith("pid ")) {
|
||||||
// Will not need it any more
|
// Wil not need it any more
|
||||||
delete m_tempFile;
|
delete m_tempFile;
|
||||||
m_tempFile = 0;
|
m_tempFile = 0;
|
||||||
|
|
||||||
@@ -204,7 +201,7 @@ void ConsoleProcess::readStubOutput()
|
|||||||
connect(inferiorFinishedNotifier, SIGNAL(activated(HANDLE)), SLOT(inferiorExited()));
|
connect(inferiorFinishedNotifier, SIGNAL(activated(HANDLE)), SLOT(inferiorExited()));
|
||||||
emit processStarted();
|
emit processStarted();
|
||||||
} else {
|
} else {
|
||||||
emit processError(tr("Unexpected output from helper program."));
|
emit processError(msgUnexpectedOutput());
|
||||||
TerminateProcess(m_pid->hProcess, (unsigned)-1);
|
TerminateProcess(m_pid->hProcess, (unsigned)-1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,8 @@
|
|||||||
static FILE *qtcFd;
|
static FILE *qtcFd;
|
||||||
static wchar_t *sleepMsg;
|
static wchar_t *sleepMsg;
|
||||||
|
|
||||||
|
enum RunMode { Run, Debug, Suspend };
|
||||||
|
|
||||||
/* Print some "press enter" message, wait for that, exit. */
|
/* Print some "press enter" message, wait for that, exit. */
|
||||||
static void doExit(int code)
|
static void doExit(int code)
|
||||||
{
|
{
|
||||||
@@ -112,6 +114,7 @@ int main()
|
|||||||
STARTUPINFOW si;
|
STARTUPINFOW si;
|
||||||
PROCESS_INFORMATION pi;
|
PROCESS_INFORMATION pi;
|
||||||
DEBUG_EVENT dbev;
|
DEBUG_EVENT dbev;
|
||||||
|
enum RunMode mode = Run;
|
||||||
|
|
||||||
argv = CommandLineToArgvW(GetCommandLine(), &argc);
|
argv = CommandLineToArgvW(GetCommandLine(), &argc);
|
||||||
|
|
||||||
@@ -158,8 +161,20 @@ int main()
|
|||||||
si.cb = sizeof(si);
|
si.cb = sizeof(si);
|
||||||
|
|
||||||
creationFlags = CREATE_UNICODE_ENVIRONMENT;
|
creationFlags = CREATE_UNICODE_ENVIRONMENT;
|
||||||
if (!wcscmp(argv[ArgAction], L"debug"))
|
if (!wcscmp(argv[ArgAction], L"debug")) {
|
||||||
|
mode = Debug;
|
||||||
|
} else if (!wcscmp(argv[ArgAction], L"suspend")) {
|
||||||
|
mode = Suspend;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case Debug:
|
||||||
creationFlags |= DEBUG_ONLY_THIS_PROCESS;
|
creationFlags |= DEBUG_ONLY_THIS_PROCESS;
|
||||||
|
break;
|
||||||
|
case Suspend:
|
||||||
|
creationFlags |= CREATE_SUSPENDED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (!CreateProcessW(0, argv[ArgCmdLine], 0, 0, FALSE, creationFlags, env, 0, &si, &pi)) {
|
if (!CreateProcessW(0, argv[ArgCmdLine], 0, 0, FALSE, creationFlags, env, 0, &si, &pi)) {
|
||||||
/* Only expected error: no such file or direcotry, i.e. executable not found */
|
/* Only expected error: no such file or direcotry, i.e. executable not found */
|
||||||
sendMsg("err:exec %d\n", GetLastError());
|
sendMsg("err:exec %d\n", GetLastError());
|
||||||
@@ -172,7 +187,7 @@ int main()
|
|||||||
So instead we start a debugged process, eat all the initial
|
So instead we start a debugged process, eat all the initial
|
||||||
debug events, suspend the process and detach from it. If gdb
|
debug events, suspend the process and detach from it. If gdb
|
||||||
tries to attach *now*, everything goes smoothly. Yay. */
|
tries to attach *now*, everything goes smoothly. Yay. */
|
||||||
if (creationFlags & DEBUG_ONLY_THIS_PROCESS) {
|
if (mode == Debug) {
|
||||||
do {
|
do {
|
||||||
if (!WaitForDebugEvent (&dbev, INFINITE))
|
if (!WaitForDebugEvent (&dbev, INFINITE))
|
||||||
systemError("Cannot fetch debug event, error %d\n");
|
systemError("Cannot fetch debug event, error %d\n");
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ SOURCES += \
|
|||||||
savedaction.cpp \
|
savedaction.cpp \
|
||||||
submiteditorwidget.cpp \
|
submiteditorwidget.cpp \
|
||||||
synchronousprocess.cpp \
|
synchronousprocess.cpp \
|
||||||
submitfieldwidget.cpp
|
submitfieldwidget.cpp \
|
||||||
|
consoleprocess.cpp
|
||||||
|
|
||||||
win32 {
|
win32 {
|
||||||
SOURCES += abstractprocess_win.cpp \
|
SOURCES += abstractprocess_win.cpp \
|
||||||
|
|||||||
@@ -392,7 +392,7 @@ CdbDebugEngine::CdbDebugEngine(DebuggerManager *parent, const QSharedPointer<Cdb
|
|||||||
IDebuggerEngine(parent),
|
IDebuggerEngine(parent),
|
||||||
m_d(new CdbDebugEnginePrivate(parent, options, this))
|
m_d(new CdbDebugEnginePrivate(parent, options, this))
|
||||||
{
|
{
|
||||||
// m_d->m_consoleStubProc.setDebug(true);
|
m_d->m_consoleStubProc.setMode(Core::Utils::ConsoleProcess::Suspend);
|
||||||
connect(&m_d->m_consoleStubProc, SIGNAL(processError(QString)), this, SLOT(slotConsoleStubError(QString)));
|
connect(&m_d->m_consoleStubProc, SIGNAL(processError(QString)), this, SLOT(slotConsoleStubError(QString)));
|
||||||
connect(&m_d->m_consoleStubProc, SIGNAL(processStarted()), this, SLOT(slotConsoleStubStarted()));
|
connect(&m_d->m_consoleStubProc, SIGNAL(processStarted()), this, SLOT(slotConsoleStubStarted()));
|
||||||
connect(&m_d->m_consoleStubProc, SIGNAL(wrapperStopped()), this, SLOT(slotConsoleStubTerminated()));
|
connect(&m_d->m_consoleStubProc, SIGNAL(wrapperStopped()), this, SLOT(slotConsoleStubTerminated()));
|
||||||
@@ -469,10 +469,12 @@ bool CdbDebugEngine::startDebugger()
|
|||||||
m_d->m_debuggerManager->showStatusMessage("Starting Debugger", -1);
|
m_d->m_debuggerManager->showStatusMessage("Starting Debugger", -1);
|
||||||
QString errorMessage;
|
QString errorMessage;
|
||||||
bool rc = false;
|
bool rc = false;
|
||||||
|
bool needWatchTimer = false;
|
||||||
m_d->clearForRun();
|
m_d->clearForRun();
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case AttachExternal:
|
case AttachExternal:
|
||||||
rc = startAttachDebugger(m_d->m_debuggerManager->m_attachedPID, &errorMessage);
|
rc = startAttachDebugger(m_d->m_debuggerManager->m_attachedPID, &errorMessage);
|
||||||
|
needWatchTimer = true;
|
||||||
break;
|
break;
|
||||||
case StartInternal:
|
case StartInternal:
|
||||||
case StartExternal:
|
case StartExternal:
|
||||||
@@ -484,7 +486,9 @@ bool CdbDebugEngine::startDebugger()
|
|||||||
rc = m_d->m_consoleStubProc.start(m_d->m_debuggerManager->m_executable, m_d->m_debuggerManager->m_processArgs);
|
rc = m_d->m_consoleStubProc.start(m_d->m_debuggerManager->m_executable, m_d->m_debuggerManager->m_processArgs);
|
||||||
if (!rc)
|
if (!rc)
|
||||||
errorMessage = tr("The console stub process was unable to start '%1'.").arg(m_d->m_debuggerManager->m_executable);
|
errorMessage = tr("The console stub process was unable to start '%1'.").arg(m_d->m_debuggerManager->m_executable);
|
||||||
|
// continues in slotConsoleStubStarted()...
|
||||||
} else {
|
} else {
|
||||||
|
needWatchTimer = true;
|
||||||
rc = startDebuggerWithExecutable(mode, &errorMessage);
|
rc = startDebuggerWithExecutable(mode, &errorMessage);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -494,7 +498,8 @@ bool CdbDebugEngine::startDebugger()
|
|||||||
}
|
}
|
||||||
if (rc) {
|
if (rc) {
|
||||||
m_d->m_debuggerManager->showStatusMessage(tr("Debugger Running"), -1);
|
m_d->m_debuggerManager->showStatusMessage(tr("Debugger Running"), -1);
|
||||||
startWatchTimer();
|
if (needWatchTimer)
|
||||||
|
startWatchTimer();
|
||||||
} else {
|
} else {
|
||||||
qWarning("%s\n", qPrintable(errorMessage));
|
qWarning("%s\n", qPrintable(errorMessage));
|
||||||
}
|
}
|
||||||
@@ -503,12 +508,12 @@ bool CdbDebugEngine::startDebugger()
|
|||||||
|
|
||||||
bool CdbDebugEngine::startAttachDebugger(qint64 pid, QString *errorMessage)
|
bool CdbDebugEngine::startAttachDebugger(qint64 pid, QString *errorMessage)
|
||||||
{
|
{
|
||||||
// Need to aatrach invasively, otherwise, no notification signals
|
// Need to attrach invasively, otherwise, no notification signals
|
||||||
// for for CreateProcess/ExitProcess occur.
|
// for for CreateProcess/ExitProcess occur.
|
||||||
const HRESULT hr = m_d->m_cif.debugClient->AttachProcess(NULL, pid,
|
const ULONG flags = DEBUG_ATTACH_INVASIVE_RESUME_PROCESS;
|
||||||
DEBUG_ATTACH_INVASIVE_RESUME_PROCESS);
|
const HRESULT hr = m_d->m_cif.debugClient->AttachProcess(NULL, pid, flags);
|
||||||
if (debugCDB)
|
if (debugCDB)
|
||||||
qDebug() << "Attaching to " << pid << " returns " << hr;
|
qDebug() << "Attaching to " << pid << " returns " << hr << executionStatusString(m_d->m_cif.debugControl);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
*errorMessage = tr("AttachProcess failed for pid %1: %2").arg(pid).arg(msgDebugEngineComResult(hr));
|
*errorMessage = tr("AttachProcess failed for pid %1: %2").arg(pid).arg(msgDebugEngineComResult(hr));
|
||||||
return false;
|
return false;
|
||||||
@@ -560,7 +565,6 @@ bool CdbDebugEngine::startDebuggerWithExecutable(DebuggerStartMode sm, QString *
|
|||||||
m_d->m_mode = sm;
|
m_d->m_mode = sm;
|
||||||
}
|
}
|
||||||
m_d->m_debuggerManagerAccess->notifyInferiorRunning();
|
m_d->m_debuggerManagerAccess->notifyInferiorRunning();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1318,7 +1322,9 @@ void CdbDebugEngine::slotConsoleStubStarted()
|
|||||||
QString errorMessage;
|
QString errorMessage;
|
||||||
if (startAttachDebugger(appPid, &errorMessage)) {
|
if (startAttachDebugger(appPid, &errorMessage)) {
|
||||||
m_d->m_debuggerManager->m_attachedPID = appPid;
|
m_d->m_debuggerManager->m_attachedPID = appPid;
|
||||||
|
startWatchTimer();
|
||||||
m_d->m_debuggerManagerAccess->notifyInferiorPidChanged(appPid);
|
m_d->m_debuggerManagerAccess->notifyInferiorPidChanged(appPid);
|
||||||
|
m_d->m_debuggerManagerAccess->notifyInferiorRunning();
|
||||||
} else {
|
} else {
|
||||||
QMessageBox::critical(m_d->m_debuggerManager->mainWindow(), tr("Debugger Error"), errorMessage);
|
QMessageBox::critical(m_d->m_debuggerManager->mainWindow(), tr("Debugger Error"), errorMessage);
|
||||||
}
|
}
|
||||||
@@ -1343,7 +1349,8 @@ void CdbDebugEnginePrivate::notifyCrashed()
|
|||||||
void CdbDebugEnginePrivate::handleDebugEvent()
|
void CdbDebugEnginePrivate::handleDebugEvent()
|
||||||
{
|
{
|
||||||
if (debugCDB)
|
if (debugCDB)
|
||||||
qDebug() << Q_FUNC_INFO << m_hDebuggeeProcess;
|
qDebug() << Q_FUNC_INFO << '\n' << m_hDebuggeeProcess << m_breakEventMode
|
||||||
|
<< executionStatusString(m_cif.debugControl);
|
||||||
|
|
||||||
// restore mode and do special handling
|
// restore mode and do special handling
|
||||||
const HandleBreakEventMode mode = m_breakEventMode;
|
const HandleBreakEventMode mode = m_breakEventMode;
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
#include "breakhandler.h"
|
#include "breakhandler.h"
|
||||||
#include "cdbstacktracecontext.h"
|
#include "cdbstacktracecontext.h"
|
||||||
|
|
||||||
enum { cppExceptionCode = 0xe06d7363 };
|
enum { cppExceptionCode = 0xe06d7363, startupCompleteTrap = 0x406d1388 };
|
||||||
|
|
||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
#include <QtCore/QTextStream>
|
#include <QtCore/QTextStream>
|
||||||
@@ -245,6 +245,9 @@ void formatException(const EXCEPTION_RECORD64 *e, QTextStream &str)
|
|||||||
case cppExceptionCode:
|
case cppExceptionCode:
|
||||||
str << "C++ exception";
|
str << "C++ exception";
|
||||||
break;
|
break;
|
||||||
|
case startupCompleteTrap:
|
||||||
|
str << "Startup complete";
|
||||||
|
break;
|
||||||
case EXCEPTION_ACCESS_VIOLATION: {
|
case EXCEPTION_ACCESS_VIOLATION: {
|
||||||
const bool writeOperation = e->ExceptionInformation[0];
|
const bool writeOperation = e->ExceptionInformation[0];
|
||||||
str << (writeOperation ? "write" : "read")
|
str << (writeOperation ? "write" : "read")
|
||||||
@@ -341,7 +344,7 @@ static bool isFatalException(LONG code)
|
|||||||
switch (code) {
|
switch (code) {
|
||||||
case EXCEPTION_BREAKPOINT:
|
case EXCEPTION_BREAKPOINT:
|
||||||
case EXCEPTION_SINGLE_STEP:
|
case EXCEPTION_SINGLE_STEP:
|
||||||
case 0x406d1388: // Mysterious exception at start of application
|
case startupCompleteTrap: // Mysterious exception at start of application
|
||||||
return false;
|
return false;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -362,7 +365,7 @@ STDMETHODIMP CdbDebugEventCallback::Exception(
|
|||||||
}
|
}
|
||||||
const bool fatal = isFatalException(Exception->ExceptionCode);
|
const bool fatal = isFatalException(Exception->ExceptionCode);
|
||||||
if (debugCDB)
|
if (debugCDB)
|
||||||
qDebug() << Q_FUNC_INFO << '\n' << fatal << msg;
|
qDebug() << Q_FUNC_INFO << "\nex=" << Exception->ExceptionCode << " fatal=" << fatal << msg;
|
||||||
m_pEngine->m_d->m_debuggerManagerAccess->showApplicationOutput(msg);
|
m_pEngine->m_d->m_debuggerManagerAccess->showApplicationOutput(msg);
|
||||||
if (fatal)
|
if (fatal)
|
||||||
m_pEngine->m_d->notifyCrashed();
|
m_pEngine->m_d->notifyCrashed();
|
||||||
|
|||||||
@@ -352,7 +352,7 @@ bool CdbDumperHelper::ensureInitialized(QString *errorMessage)
|
|||||||
return false;
|
return false;
|
||||||
case CallLoadNoQtApp:
|
case CallLoadNoQtApp:
|
||||||
m_access->showDebuggerOutput(m_messagePrefix, QCoreApplication::translate("CdbDumperHelper", "The debuggee does not appear to be Qt application."));
|
m_access->showDebuggerOutput(m_messagePrefix, QCoreApplication::translate("CdbDumperHelper", "The debuggee does not appear to be Qt application."));
|
||||||
disable();
|
m_state = Disabled; // No message here
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -367,7 +367,7 @@ bool CdbDumperHelper::ensureInitialized(QString *errorMessage)
|
|||||||
m_access->showDebuggerOutput(m_messagePrefix, m_helper.toString());
|
m_access->showDebuggerOutput(m_messagePrefix, m_helper.toString());
|
||||||
m_state = Initialized;
|
m_state = Initialized;
|
||||||
} else {
|
} else {
|
||||||
disable();
|
m_state = Disabled; // No message here
|
||||||
*errorMessage = QCoreApplication::translate("CdbDumperHelper", "The custom dumper library could not be initialized: %1").arg(*errorMessage);
|
*errorMessage = QCoreApplication::translate("CdbDumperHelper", "The custom dumper library could not be initialized: %1").arg(*errorMessage);
|
||||||
m_access->showDebuggerOutput(m_messagePrefix, *errorMessage);
|
m_access->showDebuggerOutput(m_messagePrefix, *errorMessage);
|
||||||
m_access->showQtDumperLibraryWarning(*errorMessage);
|
m_access->showQtDumperLibraryWarning(*errorMessage);
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ GdbEngine::GdbEngine(DebuggerManager *parent)
|
|||||||
{
|
{
|
||||||
q = parent;
|
q = parent;
|
||||||
qq = parent->engineInterface();
|
qq = parent->engineInterface();
|
||||||
m_stubProc.setDebug(true);
|
m_stubProc.setMode(Core::Utils::ConsoleProcess::Debug);
|
||||||
initializeVariables();
|
initializeVariables();
|
||||||
initializeConnections();
|
initializeConnections();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user