Debugger: Move external terminal into separate RunWorker

Change-Id: Ifb9701f840195ba90db48a0f6fa07b28e0409648
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
hjk
2017-09-27 08:22:02 +02:00
parent 6f481bd9da
commit 895acd23e3
13 changed files with 223 additions and 230 deletions

View File

@@ -180,7 +180,7 @@ namespace Internal {
static inline bool isCreatorConsole(const DebuggerRunParameters &sp) static inline bool isCreatorConsole(const DebuggerRunParameters &sp)
{ {
return !boolSetting(UseCdbConsole) && sp.useTerminal return !boolSetting(UseCdbConsole) && sp.inferior.runMode == ApplicationLauncher::Console
&& (sp.startMode == StartInternal || sp.startMode == StartExternal); && (sp.startMode == StartInternal || sp.startMode == StartExternal);
} }
@@ -428,7 +428,7 @@ void CdbEngine::consoleStubProcessStarted()
attachParameters.inferior.commandLineArguments.clear(); attachParameters.inferior.commandLineArguments.clear();
attachParameters.attachPID = ProcessHandle(m_consoleStub->applicationPID()); attachParameters.attachPID = ProcessHandle(m_consoleStub->applicationPID());
attachParameters.startMode = AttachExternal; attachParameters.startMode = AttachExternal;
attachParameters.useTerminal = false; attachParameters.inferior.runMode = ApplicationLauncher::Gui; // Force no terminal.
showMessage(QString("Attaching to %1...").arg(attachParameters.attachPID.pid()), LogMisc); showMessage(QString("Attaching to %1...").arg(attachParameters.attachPID.pid()), LogMisc);
QString errorMessage; QString errorMessage;
if (!launchCDB(attachParameters, &errorMessage)) { if (!launchCDB(attachParameters, &errorMessage)) {
@@ -542,7 +542,7 @@ bool CdbEngine::launchCDB(const DebuggerRunParameters &sp, QString *errorMessage
// register idle (debuggee stop) notification // register idle (debuggee stop) notification
<< "-c" << "-c"
<< ".idle_cmd " + m_extensionCommandPrefix + "idle"; << ".idle_cmd " + m_extensionCommandPrefix + "idle";
if (sp.useTerminal) // Separate console if (sp.inferior.runMode == ApplicationLauncher::Console) // Separate console
arguments << "-2"; arguments << "-2";
if (boolSetting(IgnoreFirstChanceAccessViolation)) if (boolSetting(IgnoreFirstChanceAccessViolation))
arguments << "-x"; arguments << "-x";
@@ -610,7 +610,8 @@ bool CdbEngine::launchCDB(const DebuggerRunParameters &sp, QString *errorMessage
// Make sure that QTestLib uses OutputDebugString for logging. // Make sure that QTestLib uses OutputDebugString for logging.
const QString qtLoggingToConsoleKey = QStringLiteral("QT_LOGGING_TO_CONSOLE"); const QString qtLoggingToConsoleKey = QStringLiteral("QT_LOGGING_TO_CONSOLE");
if (!sp.useTerminal && !inferiorEnvironment.hasKey(qtLoggingToConsoleKey)) if (sp.inferior.runMode != ApplicationLauncher::Console
&& !inferiorEnvironment.hasKey(qtLoggingToConsoleKey))
inferiorEnvironment.set(qtLoggingToConsoleKey, QString(QLatin1Char('0'))); inferiorEnvironment.set(qtLoggingToConsoleKey, QString(QLatin1Char('0')));
m_process.setEnvironment(mergeEnvironment(inferiorEnvironment.toStringList(), m_process.setEnvironment(mergeEnvironment(inferiorEnvironment.toStringList(),

View File

@@ -425,7 +425,6 @@ void StartApplicationDialog::run(bool attachRemote)
} }
StandardRunnable inferior = newParameters.runnable; StandardRunnable inferior = newParameters.runnable;
debugger->setUseTerminal(newParameters.runnable.runMode == ApplicationLauncher::Console);
const QString inputAddress = dialog.d->channelOverrideEdit->text(); const QString inputAddress = dialog.d->channelOverrideEdit->text();
if (!inputAddress.isEmpty()) if (!inputAddress.isEmpty())
debugger->setRemoteChannel(inputAddress); debugger->setRemoteChannel(inputAddress);

View File

@@ -106,7 +106,6 @@ QDebug operator<<(QDebug str, const DebuggerRunParameters &sp)
<< " debugger environment=<" << sp.debugger.environment.size() << " variables>" << " debugger environment=<" << sp.debugger.environment.size() << " variables>"
<< " workingDir=" << sp.inferior.workingDirectory << " workingDir=" << sp.inferior.workingDirectory
<< " attachPID=" << sp.attachPID.pid() << " attachPID=" << sp.attachPID.pid()
<< " useTerminal=" << sp.useTerminal
<< " remoteChannel=" << sp.remoteChannel << " remoteChannel=" << sp.remoteChannel
<< " abi=" << sp.toolChainAbi.toString() << '\n'; << " abi=" << sp.toolChainAbi.toString() << '\n';
return str; return str;
@@ -329,7 +328,7 @@ public:
// The state we had before something unexpected happend. // The state we had before something unexpected happend.
DebuggerState m_lastGoodState = DebuggerNotReady; DebuggerState m_lastGoodState = DebuggerNotReady;
Terminal m_terminal; // Terminal m_terminal;
ProcessHandle m_inferiorPid; ProcessHandle m_inferiorPid;
ModulesHandler m_modulesHandler; ModulesHandler m_modulesHandler;
@@ -545,18 +544,18 @@ void DebuggerEngine::start()
d->m_lastGoodState = DebuggerNotReady; d->m_lastGoodState = DebuggerNotReady;
d->m_progress.setProgressValue(200); d->m_progress.setProgressValue(200);
d->m_terminal.setup(); // d->m_terminal.setup();
if (d->m_terminal.isUsable()) { // if (d->m_terminal.isUsable()) {
connect(&d->m_terminal, &Terminal::stdOutReady, [this](const QString &msg) { // connect(&d->m_terminal, &Terminal::stdOutReady, [this](const QString &msg) {
d->m_runTool->appendMessage(msg, Utils::StdOutFormatSameLine); // d->m_runTool->appendMessage(msg, Utils::StdOutFormatSameLine);
}); // });
connect(&d->m_terminal, &Terminal::stdErrReady, [this](const QString &msg) { // connect(&d->m_terminal, &Terminal::stdErrReady, [this](const QString &msg) {
d->m_runTool->appendMessage(msg, Utils::StdErrFormatSameLine); // d->m_runTool->appendMessage(msg, Utils::StdErrFormatSameLine);
}); // });
connect(&d->m_terminal, &Terminal::error, [this](const QString &msg) { // connect(&d->m_terminal, &Terminal::error, [this](const QString &msg) {
d->m_runTool->appendMessage(msg, Utils::ErrorMessageFormat); // d->m_runTool->appendMessage(msg, Utils::ErrorMessageFormat);
}); // });
} // }
d->queueSetupEngine(); d->queueSetupEngine();
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << this << state()); QTC_ASSERT(state() == EngineSetupRequested, qDebug() << this << state());
@@ -1378,9 +1377,10 @@ DebuggerRunTool *DebuggerEngine::runTool() const
return d->m_runTool.data(); return d->m_runTool.data();
} }
Terminal *DebuggerEngine::terminal() const TerminalRunner *DebuggerEngine::terminal() const
{ {
return &d->m_terminal; QTC_ASSERT(d->m_runTool, return nullptr);
return d->m_runTool->terminalRunner();
} }
void DebuggerEngine::selectWatchData(const QString &) void DebuggerEngine::selectWatchData(const QString &)

View File

@@ -74,6 +74,7 @@ class QmlCppEngine;
class DebuggerToolTipContext; class DebuggerToolTipContext;
class MemoryViewSetupData; class MemoryViewSetupData;
class Terminal; class Terminal;
class TerminalRunner;
class ThreadId; class ThreadId;
class DebuggerRunParameters class DebuggerRunParameters
@@ -87,7 +88,6 @@ public:
Utils::Environment stubEnvironment; Utils::Environment stubEnvironment;
Utils::ProcessHandle attachPID; Utils::ProcessHandle attachPID;
QStringList solibSearchPath; QStringList solibSearchPath;
bool useTerminal = false;
// Used by Qml debugging. // Used by Qml debugging.
QUrl qmlServer; QUrl qmlServer;
@@ -461,7 +461,7 @@ protected:
void setMasterEngine(DebuggerEngine *masterEngine); void setMasterEngine(DebuggerEngine *masterEngine);
ProjectExplorer::RunControl *runControl() const; ProjectExplorer::RunControl *runControl() const;
Terminal *terminal() const; TerminalRunner *terminal() const;
static QString msgStopped(const QString &reason = QString()); static QString msgStopped(const QString &reason = QString());
static QString msgStoppedBySignal(const QString &meaning, const QString &name); static QString msgStoppedBySignal(const QString &meaning, const QString &name);

View File

@@ -2878,8 +2878,9 @@ static void createNewDock(QWidget *widget)
dockWidget->show(); dockWidget->show();
} }
static QString formatStartParameters(const DebuggerRunParameters &sp) static QString formatStartParameters(const DebuggerRunTool *debugger)
{ {
const DebuggerRunParameters &sp = debugger->runParameters();
QString rc; QString rc;
QTextStream str(&rc); QTextStream str(&rc);
str << "Start parameters: '" << sp.displayName << "' mode: " << sp.startMode str << "Start parameters: '" << sp.displayName << "' mode: " << sp.startMode
@@ -2893,7 +2894,7 @@ static QString formatStartParameters(const DebuggerRunParameters &sp)
if (!sp.inferior.executable.isEmpty()) { if (!sp.inferior.executable.isEmpty()) {
str << "Executable: " << QDir::toNativeSeparators(sp.inferior.executable) str << "Executable: " << QDir::toNativeSeparators(sp.inferior.executable)
<< ' ' << sp.inferior.commandLineArguments; << ' ' << sp.inferior.commandLineArguments;
if (sp.useTerminal) if (debugger->terminalRunner())
str << " [terminal]"; str << " [terminal]";
str << '\n'; str << '\n';
if (!sp.inferior.workingDirectory.isEmpty()) if (!sp.inferior.workingDirectory.isEmpty())
@@ -2928,7 +2929,7 @@ void DebuggerPluginPrivate::runControlStarted(DebuggerRunTool *runTool)
.arg(runTool->engine()->objectName()) .arg(runTool->engine()->objectName())
.arg(runTool->runParameters().toolChainAbi.toString()); .arg(runTool->runParameters().toolChainAbi.toString());
showStatusMessage(message); showStatusMessage(message);
showMessage(formatStartParameters(runTool->runParameters()), LogDebug); showMessage(formatStartParameters(runTool), LogDebug);
showMessage(m_debuggerSettings->dump(), LogDebug); showMessage(m_debuggerSettings->dump(), LogDebug);
m_snapshotHandler->appendSnapshot(runTool); m_snapshotHandler->appendSnapshot(runTool);
connectEngine(runTool); connectEngine(runTool);

View File

@@ -24,6 +24,7 @@
****************************************************************************/ ****************************************************************************/
#include "debuggerruncontrol.h" #include "debuggerruncontrol.h"
#include "terminal.h"
#include "analyzer/analyzermanager.h" #include "analyzer/analyzermanager.h"
#include "console/console.h" #include "console/console.h"
@@ -76,7 +77,7 @@ namespace Debugger {
namespace Internal { namespace Internal {
DebuggerEngine *createCdbEngine(QStringList *error, DebuggerStartMode sm); DebuggerEngine *createCdbEngine(QStringList *error, DebuggerStartMode sm);
DebuggerEngine *createGdbEngine(bool useTerminal, DebuggerStartMode sm); DebuggerEngine *createGdbEngine(DebuggerStartMode sm);
DebuggerEngine *createPdbEngine(); DebuggerEngine *createPdbEngine();
DebuggerEngine *createQmlEngine(bool useTerminal); DebuggerEngine *createQmlEngine(bool useTerminal);
DebuggerEngine *createQmlCppEngine(DebuggerEngine *cppEngine, bool useTerminal); DebuggerEngine *createQmlCppEngine(DebuggerEngine *cppEngine, bool useTerminal);
@@ -173,8 +174,13 @@ public:
Utils::QtcProcess m_proc; Utils::QtcProcess m_proc;
}; };
} // namespace Internal class DebuggerRunToolPrivate
{
public:
QPointer<TerminalRunner> terminalRunner;
};
} // namespace Internal
static bool breakOnMainNextTime = false; static bool breakOnMainNextTime = false;
@@ -284,7 +290,13 @@ void DebuggerRunTool::setBreakOnMain(bool on)
void DebuggerRunTool::setUseTerminal(bool on) void DebuggerRunTool::setUseTerminal(bool on)
{ {
m_runParameters.useTerminal = on; if (on && !d->terminalRunner && m_runParameters.cppEngineType == GdbEngineType) {
d->terminalRunner = new TerminalRunner(this);
addStartDependency(d->terminalRunner);
}
if (!on && d->terminalRunner) {
QTC_CHECK(false); // User code can only switch from no terminal to one terminal.
}
} }
void DebuggerRunTool::setCommandsAfterConnect(const QString &commands) void DebuggerRunTool::setCommandsAfterConnect(const QString &commands)
@@ -343,6 +355,7 @@ void DebuggerRunTool::setInferior(const Runnable &runnable)
{ {
QTC_ASSERT(runnable.is<StandardRunnable>(), reportFailure(); return); QTC_ASSERT(runnable.is<StandardRunnable>(), reportFailure(); return);
m_runParameters.inferior = runnable.as<StandardRunnable>(); m_runParameters.inferior = runnable.as<StandardRunnable>();
setUseTerminal(m_runParameters.inferior.runMode == ApplicationLauncher::Console);
} }
void DebuggerRunTool::setInferiorExecutable(const QString &executable) void DebuggerRunTool::setInferiorExecutable(const QString &executable)
@@ -469,7 +482,7 @@ void DebuggerRunTool::start()
switch (m_runParameters.cppEngineType) { switch (m_runParameters.cppEngineType) {
case GdbEngineType: case GdbEngineType:
cppEngine = createGdbEngine(m_runParameters.useTerminal, m_runParameters.startMode); cppEngine = createGdbEngine(m_runParameters.startMode);
break; break;
case CdbEngineType: { case CdbEngineType: {
QStringList errors; QStringList errors;
@@ -493,11 +506,11 @@ void DebuggerRunTool::start()
switch (m_runParameters.masterEngineType) { switch (m_runParameters.masterEngineType) {
case QmlEngineType: case QmlEngineType:
m_engine = createQmlEngine(m_runParameters.useTerminal); m_engine = createQmlEngine(terminalRunner() != nullptr);
break; break;
case QmlCppEngineType: case QmlCppEngineType:
if (cppEngine) if (cppEngine)
m_engine = createQmlCppEngine(cppEngine, m_runParameters.useTerminal); m_engine = createQmlCppEngine(cppEngine, terminalRunner() != nullptr);
break; break;
default: default:
m_engine = cppEngine; m_engine = cppEngine;
@@ -710,14 +723,6 @@ bool DebuggerRunTool::fixupParameters()
} }
} }
// FIXME: We can't handle terminals yet.
if (rp.useTerminal && rp.cppEngineType == LldbEngineType) {
qWarning("Run in Terminal is not supported yet with the LLDB backend");
appendMessage(DebuggerPlugin::tr("Run in Terminal is not supported with the LLDB backend."),
ErrorMessageFormat);
rp.useTerminal = false;
}
if (rp.isNativeMixedDebugging()) if (rp.isNativeMixedDebugging())
rp.inferior.environment.set("QV4_FORCE_INTERPRETER", "1"); rp.inferior.environment.set("QV4_FORCE_INTERPRETER", "1");
@@ -727,8 +732,13 @@ bool DebuggerRunTool::fixupParameters()
return true; return true;
} }
Internal::TerminalRunner *DebuggerRunTool::terminalRunner() const
{
return d->terminalRunner;
}
DebuggerRunTool::DebuggerRunTool(RunControl *runControl, Kit *kit) DebuggerRunTool::DebuggerRunTool(RunControl *runControl, Kit *kit)
: RunWorker(runControl) : RunWorker(runControl), d(new DebuggerRunToolPrivate)
{ {
setDisplayName("DebuggerRunTool"); setDisplayName("DebuggerRunTool");
@@ -745,13 +755,25 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl, Kit *kit)
QString(), QString(), optionalPrompt); QString(), QString(), optionalPrompt);
}); });
if (runConfig)
m_runParameters.displayName = runConfig->displayName();
if (runConfig && !kit)
kit = runConfig->target()->kit();
QTC_ASSERT(kit, return);
m_runParameters.cppEngineType = DebuggerKitInformation::engineType(kit);
m_runParameters.sysRoot = SysRootKitInformation::sysRoot(kit).toString();
m_runParameters.macroExpander = kit->macroExpander();
m_runParameters.debugger = DebuggerKitInformation::runnable(kit);
Runnable r = runnable(); Runnable r = runnable();
if (r.is<StandardRunnable>()) { if (r.is<StandardRunnable>()) {
m_runParameters.inferior = r.as<StandardRunnable>(); m_runParameters.inferior = r.as<StandardRunnable>();
m_runParameters.useTerminal = m_runParameters.inferior.runMode == ApplicationLauncher::Console;
// Normalize to work around QTBUG-17529 (QtDeclarative fails with 'File name case mismatch'...) // Normalize to work around QTBUG-17529 (QtDeclarative fails with 'File name case mismatch'...)
m_runParameters.inferior.workingDirectory = m_runParameters.inferior.workingDirectory =
FileUtils::normalizePathName(m_runParameters.inferior.workingDirectory); FileUtils::normalizePathName(m_runParameters.inferior.workingDirectory);
setUseTerminal(m_runParameters.inferior.runMode == ApplicationLauncher::Console);
} }
if (auto aspect = runConfig ? runConfig->extraAspect<DebuggerRunConfigurationAspect>() : nullptr) { if (auto aspect = runConfig ? runConfig->extraAspect<DebuggerRunConfigurationAspect>() : nullptr) {
@@ -760,16 +782,6 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl, Kit *kit)
m_runParameters.multiProcess = aspect->useMultiProcess(); m_runParameters.multiProcess = aspect->useMultiProcess();
} }
if (runConfig)
m_runParameters.displayName = runConfig->displayName();
if (runConfig && !kit)
kit = runConfig->target()->kit();
QTC_ASSERT(kit, return);
m_runParameters.macroExpander = kit->macroExpander();
m_runParameters.debugger = DebuggerKitInformation::runnable(kit);
const QByteArray envBinary = qgetenv("QTC_DEBUGGER_PATH"); const QByteArray envBinary = qgetenv("QTC_DEBUGGER_PATH");
if (!envBinary.isEmpty()) if (!envBinary.isEmpty())
m_runParameters.debugger.executable = QString::fromLocal8Bit(envBinary); m_runParameters.debugger.executable = QString::fromLocal8Bit(envBinary);
@@ -787,9 +799,6 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl, Kit *kit)
if (ok) if (ok)
m_runParameters.nativeMixedEnabled = bool(nativeMixedOverride); m_runParameters.nativeMixedEnabled = bool(nativeMixedOverride);
m_runParameters.cppEngineType = DebuggerKitInformation::engineType(kit);
m_runParameters.sysRoot = SysRootKitInformation::sysRoot(kit).toString();
// This will only be shown in some cases, but we don't want to access // This will only be shown in some cases, but we don't want to access
// the kit at that time anymore. // the kit at that time anymore.
const QList<Task> tasks = DebuggerKitInformation::validateDebugger(kit); const QList<Task> tasks = DebuggerKitInformation::validateDebugger(kit);
@@ -842,6 +851,7 @@ DebuggerRunTool::~DebuggerRunTool()
engine->disconnect(); engine->disconnect();
delete engine; delete engine;
} }
delete d;
} }
void DebuggerRunTool::showMessage(const QString &msg, int channel, int timeout) void DebuggerRunTool::showMessage(const QString &msg, int channel, int timeout)

View File

@@ -37,6 +37,11 @@
namespace Debugger { namespace Debugger {
namespace Internal {
class TerminalRunner;
class DebuggerRunToolPrivate;
} // Internal
class DEBUGGER_EXPORT DebuggerRunTool : public ProjectExplorer::RunWorker class DEBUGGER_EXPORT DebuggerRunTool : public ProjectExplorer::RunWorker
{ {
Q_OBJECT Q_OBJECT
@@ -128,12 +133,15 @@ public:
void setTestCase(int testCase); void setTestCase(int testCase);
void setOverrideStartScript(const QString &script); void setOverrideStartScript(const QString &script);
Internal::TerminalRunner *terminalRunner() const;
signals: signals:
void aboutToNotifyInferiorSetupOk(); void aboutToNotifyInferiorSetupOk();
private: private:
bool fixupParameters(); bool fixupParameters();
Internal::DebuggerRunToolPrivate *d;
QPointer<Internal::DebuggerEngine> m_engine; // Master engine QPointer<Internal::DebuggerEngine> m_engine; // Master engine
Internal::DebuggerRunParameters m_runParameters; Internal::DebuggerRunParameters m_runParameters;
bool m_isDying = false; bool m_isDying = false;

View File

@@ -137,11 +137,6 @@ static bool isMostlyHarmlessMessage(const QStringRef &msg)
"Invalid argument\\n"; "Invalid argument\\n";
} }
static QString mainFunction(const DebuggerRunParameters &rp)
{
return QLatin1String(rp.toolChainAbi.os() == Abi::WindowsOS && !rp.useTerminal ? "qMain" : "main");
}
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
// //
// Debuginfo Taskhandler // Debuginfo Taskhandler
@@ -194,8 +189,8 @@ private:
// //
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
GdbEngine::GdbEngine(bool useTerminal, DebuggerStartMode startMode) GdbEngine::GdbEngine(DebuggerStartMode startMode)
: m_startMode(startMode), m_useTerminal(useTerminal), m_terminalTrap(useTerminal) : m_startMode(startMode)
{ {
setObjectName("GdbEngine"); setObjectName("GdbEngine");
@@ -221,26 +216,10 @@ GdbEngine::GdbEngine(bool useTerminal, DebuggerStartMode startMode)
// Output // Output
connect(&m_outputCollector, &OutputCollector::byteDelivery, connect(&m_outputCollector, &OutputCollector::byteDelivery,
this, &GdbEngine::readDebuggeeOutput); this, &GdbEngine::readDebuggeeOutput);
if (isTermEngine()) {
if (HostOsInfo::isWindowsHost()) {
// Windows up to xp needs a workaround for attaching to freshly started processes. see proc_stub_win
if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA)
m_stubProc.setMode(ConsoleProcess::Suspend);
else
m_stubProc.setMode(ConsoleProcess::Debug);
} else {
m_stubProc.setMode(ConsoleProcess::Debug);
m_stubProc.setSettings(ICore::settings());
}
}
} }
GdbEngine::~GdbEngine() GdbEngine::~GdbEngine()
{ {
if (isTermEngine())
m_stubProc.disconnect(); // Avoid spurious state transitions from late exiting stub
if (isCoreEngine()) { if (isCoreEngine()) {
if (m_coreUnpackProcess) { if (m_coreUnpackProcess) {
m_coreUnpackProcess->blockSignals(true); m_coreUnpackProcess->blockSignals(true);
@@ -781,9 +760,6 @@ void GdbEngine::interruptInferior()
CHECK_STATE(InferiorStopRequested); CHECK_STATE(InferiorStopRequested);
if (terminal()->sendInterrupt())
return;
if (usesExecInterrupt()) { if (usesExecInterrupt()) {
runCommand({"-exec-interrupt"}); runCommand({"-exec-interrupt"});
} else { } else {
@@ -1079,7 +1055,7 @@ void GdbEngine::handleResultRecord(DebuggerResponse *response)
Abi abi = rp.toolChainAbi; Abi abi = rp.toolChainAbi;
if (abi.os() == Abi::WindowsOS if (abi.os() == Abi::WindowsOS
&& cmd.function.startsWith("attach") && cmd.function.startsWith("attach")
&& (rp.startMode == AttachExternal || rp.useTerminal)) && (rp.startMode == AttachExternal || terminal()))
{ {
// Ignore spurious 'running' responses to 'attach'. // Ignore spurious 'running' responses to 'attach'.
} else { } else {
@@ -1240,12 +1216,14 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
{ {
// Ignore trap on Windows terminals, which results in // Ignore trap on Windows terminals, which results in
// spurious "* stopped" message. // spurious "* stopped" message.
if (m_terminalTrap && (!data.isValid() || !data["reason"].isValid()) if (m_expectTerminalTrap) {
m_expectTerminalTrap = false;
if ((!data.isValid() || !data["reason"].isValid())
&& Abi::hostAbi().os() == Abi::WindowsOS) { && Abi::hostAbi().os() == Abi::WindowsOS) {
m_terminalTrap = false;
showMessage("IGNORING TERMINAL SIGTRAP", LogMisc); showMessage("IGNORING TERMINAL SIGTRAP", LogMisc);
return; return;
} }
}
if (isDying()) { if (isDying()) {
notifyInferiorStopOk(); notifyInferiorStopOk();
@@ -1279,7 +1257,7 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
// Ignore signals from the process stub. // Ignore signals from the process stub.
const GdbMi frame = data["frame"]; const GdbMi frame = data["frame"];
const QString func = frame["from"].data(); const QString func = frame["from"].data();
if (runParameters().useTerminal if (terminal()
&& data["reason"].data() == "signal-received" && data["reason"].data() == "signal-received"
&& data["signal-name"].data() == "SIGSTOP" && data["signal-name"].data() == "SIGSTOP"
&& (func.endsWith("/ld-linux.so.2") && (func.endsWith("/ld-linux.so.2")
@@ -1371,8 +1349,7 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
// This is gdb 7+'s initial *stopped in response to attach that // This is gdb 7+'s initial *stopped in response to attach that
// appears before the ^done is seen. // appears before the ^done is seen.
notifyEngineRunAndInferiorStopOk(); notifyEngineRunAndInferiorStopOk();
const DebuggerRunParameters &rp = runParameters(); if (terminal())
if (rp.useTerminal)
continueInferiorInternal(); continueInferiorInternal();
return; return;
} else { } else {
@@ -1497,7 +1474,7 @@ void GdbEngine::handleStop2(const GdbMi &data)
bool isStopperThread = false; bool isStopperThread = false;
if (rp.toolChainAbi.os() == Abi::WindowsOS if (rp.toolChainAbi.os() == Abi::WindowsOS
&& rp.useTerminal && terminal()
&& reason == "signal-received" && reason == "signal-received"
&& data["signal-name"].data() == "SIGTRAP") && data["signal-name"].data() == "SIGTRAP")
{ {
@@ -2345,7 +2322,7 @@ QString GdbEngine::breakpointLocation(const BreakpointParameters &data)
if (data.type == BreakpointAtCatch) if (data.type == BreakpointAtCatch)
return QLatin1String("__cxa_begin_catch"); return QLatin1String("__cxa_begin_catch");
if (data.type == BreakpointAtMain) if (data.type == BreakpointAtMain)
return mainFunction(runParameters()); return mainFunction();
if (data.type == BreakpointByFunction) if (data.type == BreakpointByFunction)
return '"' + data.functionName + '"'; return '"' + data.functionName + '"';
if (data.type == BreakpointByAddress) if (data.type == BreakpointByAddress)
@@ -3800,6 +3777,7 @@ void GdbEngine::startGdb(const QStringList &args)
showMessage("ENABLING TEST CASE: " + QString::number(test)); showMessage("ENABLING TEST CASE: " + QString::number(test));
m_gdbProc.disconnect(); // From any previous runs m_gdbProc.disconnect(); // From any previous runs
m_expectTerminalTrap = terminal();
const DebuggerRunParameters &rp = runParameters(); const DebuggerRunParameters &rp = runParameters();
if (rp.debugger.executable.isEmpty()) { if (rp.debugger.executable.isEmpty()) {
@@ -3951,8 +3929,8 @@ void GdbEngine::startGdb(const QStringList &args)
// Don't use ConsoleCommand, otherwise Mac won't markup the output. // Don't use ConsoleCommand, otherwise Mac won't markup the output.
const QString dumperSourcePath = ICore::resourcePath() + "/debugger/"; const QString dumperSourcePath = ICore::resourcePath() + "/debugger/";
if (terminal()->isUsable()) //if (terminal()->isUsable())
runCommand({"set inferior-tty " + QString::fromUtf8(terminal()->slaveDevice())}); // runCommand({"set inferior-tty " + QString::fromUtf8(terminal()->slaveDevice())});
const QFileInfo gdbBinaryFile(rp.debugger.executable); const QFileInfo gdbBinaryFile(rp.debugger.executable);
const QString uninstalledData = gdbBinaryFile.absolutePath() + "/data-directory/python"; const QString uninstalledData = gdbBinaryFile.absolutePath() + "/data-directory/python";
@@ -3977,9 +3955,7 @@ void GdbEngine::startGdb(const QStringList &args)
void GdbEngine::handleGdbStartFailed() void GdbEngine::handleGdbStartFailed()
{ {
if (isTermEngine()) if (isPlainEngine())
m_stubProc.stop();
else if (isPlainEngine())
m_outputCollector.shutdown(); m_outputCollector.shutdown();
} }
@@ -4120,7 +4096,7 @@ void GdbEngine::handleInferiorPrepared()
//runCommand("set follow-exec-mode new"); //runCommand("set follow-exec-mode new");
if (rp.breakOnMain) if (rp.breakOnMain)
runCommand({"tbreak " + mainFunction(rp)}); runCommand({"tbreak " + mainFunction()});
// Initial attempt to set breakpoints. // Initial attempt to set breakpoints.
if (rp.startMode != AttachCore) { if (rp.startMode != AttachCore) {
@@ -4316,7 +4292,7 @@ void GdbEngine::debugLastCommand()
bool GdbEngine::isPlainEngine() const bool GdbEngine::isPlainEngine() const
{ {
return !isCoreEngine() && !isAttachEngine() && !isRemoteEngine() && !m_terminalTrap; return !isCoreEngine() && !isAttachEngine() && !isRemoteEngine() && !terminal();
} }
bool GdbEngine::isCoreEngine() const bool GdbEngine::isCoreEngine() const
@@ -4336,7 +4312,7 @@ bool GdbEngine::isAttachEngine() const
bool GdbEngine::isTermEngine() const bool GdbEngine::isTermEngine() const
{ {
return !isCoreEngine() && !isAttachEngine() && !isRemoteEngine() && m_terminalTrap; return !isCoreEngine() && !isAttachEngine() && !isRemoteEngine() && terminal();
} }
void GdbEngine::setupEngine() void GdbEngine::setupEngine()
@@ -4359,30 +4335,7 @@ void GdbEngine::setupEngine()
showMessage("TRYING TO START ADAPTER"); showMessage("TRYING TO START ADAPTER");
// Currently, GdbEngines are not re-used startGdb();
// // We leave the console open, so recycle it now.
// m_stubProc.blockSignals(true);
// m_stubProc.stop();
// m_stubProc.blockSignals(false);
m_stubProc.setWorkingDirectory(runParameters().inferior.workingDirectory);
// Set environment + dumper preload.
m_stubProc.setEnvironment(runParameters().stubEnvironment);
connect(&m_stubProc, &ConsoleProcess::processError,
this, &GdbEngine::stubError);
connect(&m_stubProc, &ConsoleProcess::processStarted,
this, [this] { startGdb(); });
connect(&m_stubProc, &ConsoleProcess::stubStopped,
this, &GdbEngine::stubExited);
// FIXME: Starting the stub implies starting the inferior. This is
// fairly unclean as far as the state machine and error reporting go.
if (!m_stubProc.start(runParameters().inferior.executable,
runParameters().inferior.commandLineArguments)) {
// Error message for user is delivered via a signal.
handleAdapterStartFailed(QString());
}
} else if (isCoreEngine()) { } else if (isCoreEngine()) {
@@ -4492,8 +4445,8 @@ void GdbEngine::setupInferior()
} else if (isTermEngine()) { } else if (isTermEngine()) {
const qint64 attachedPID = m_stubProc.applicationPID(); const qint64 attachedPID = terminal()->applicationPid();
const qint64 attachedMainThreadID = m_stubProc.applicationMainThreadID(); const qint64 attachedMainThreadID = terminal()->applicationMainThreadId();
notifyInferiorPid(ProcessHandle(attachedPID)); notifyInferiorPid(ProcessHandle(attachedPID));
const QString msg = (attachedMainThreadID != -1) const QString msg = (attachedMainThreadID != -1)
? QString("Going to attach to %1 (%2)").arg(attachedPID).arg(attachedMainThreadID) ? QString("Going to attach to %1 (%2)").arg(attachedPID).arg(attachedMainThreadID)
@@ -4551,9 +4504,12 @@ void GdbEngine::runEngine()
} else if (isTermEngine()) { } else if (isTermEngine()) {
const qint64 attachedPID = m_stubProc.applicationPID(); const qint64 attachedPID = terminal()->applicationPid();
const qint64 mainThreadId = terminal()->applicationMainThreadId();
runCommand({"attach " + QString::number(attachedPID), runCommand({"attach " + QString::number(attachedPID),
[this](const DebuggerResponse &r) { handleStubAttached(r); }}); [this, mainThreadId](const DebuggerResponse &r) {
handleStubAttached(r, mainThreadId);
}});
} else if (isPlainEngine()) { } else if (isPlainEngine()) {
@@ -4911,7 +4867,7 @@ void GdbEngine::handleInterruptInferior(const DebuggerResponse &response)
} }
} }
void GdbEngine::handleStubAttached(const DebuggerResponse &response) void GdbEngine::handleStubAttached(const DebuggerResponse &response, qint64 mainThreadId)
{ {
// InferiorStopOk can happen if the "*stopped" in response to the // InferiorStopOk can happen if the "*stopped" in response to the
// 'attach' comes in before its '^done' // 'attach' comes in before its '^done'
@@ -4923,7 +4879,6 @@ void GdbEngine::handleStubAttached(const DebuggerResponse &response)
if (runParameters().toolChainAbi.os() == ProjectExplorer::Abi::WindowsOS) { if (runParameters().toolChainAbi.os() == ProjectExplorer::Abi::WindowsOS) {
QString errorMessage; QString errorMessage;
// Resume thread that was suspended by console stub process (see stub code). // Resume thread that was suspended by console stub process (see stub code).
const qint64 mainThreadId = m_stubProc.applicationMainThreadID();
if (winResumeThread(mainThreadId, &errorMessage)) { if (winResumeThread(mainThreadId, &errorMessage)) {
showMessage(QString("Inferior attached, thread %1 resumed"). showMessage(QString("Inferior attached, thread %1 resumed").
arg(mainThreadId), LogMisc); arg(mainThreadId), LogMisc);
@@ -4956,22 +4911,6 @@ void GdbEngine::handleStubAttached(const DebuggerResponse &response)
} }
} }
void GdbEngine::stubError(const QString &msg)
{
AsynchronousMessageBox::critical(tr("Debugger Error"), msg);
notifyEngineIll();
}
void GdbEngine::stubExited()
{
if (state() == EngineShutdownRequested || state() == DebuggerFinished) {
showMessage("STUB EXITED EXPECTEDLY");
} else {
showMessage("STUB EXITED");
notifyEngineIll();
}
}
static QString findExecutableFromName(const QString &fileNameFromCore, const QString &coreFile) static QString findExecutableFromName(const QString &fileNameFromCore, const QString &coreFile)
{ {
if (fileNameFromCore.isEmpty()) if (fileNameFromCore.isEmpty())
@@ -5212,13 +5151,19 @@ QString GdbEngine::msgPtraceError(DebuggerStartMode sm)
"For more details, see /etc/sysctl.d/10-ptrace.conf\n"); "For more details, see /etc/sysctl.d/10-ptrace.conf\n");
} }
QString GdbEngine::mainFunction() const
{
const DebuggerRunParameters &rp = runParameters();
return QLatin1String(rp.toolChainAbi.os() == Abi::WindowsOS && !terminal() ? "qMain" : "main");
}
// //
// Factory // Factory
// //
DebuggerEngine *createGdbEngine(bool useTerminal, DebuggerStartMode startMode) DebuggerEngine *createGdbEngine(DebuggerStartMode startMode)
{ {
return new GdbEngine(useTerminal, startMode); return new GdbEngine(startMode);
} }
} // namespace Internal } // namespace Internal

View File

@@ -55,6 +55,7 @@ class DebuggerResponse;
class DisassemblerAgentCookie; class DisassemblerAgentCookie;
class GdbMi; class GdbMi;
class MemoryAgentCookie; class MemoryAgentCookie;
class TerminalRunner;
struct CoreInfo struct CoreInfo
{ {
@@ -71,7 +72,7 @@ class GdbEngine : public DebuggerEngine
Q_OBJECT Q_OBJECT
public: public:
explicit GdbEngine(bool useTerminal, DebuggerStartMode startMode); explicit GdbEngine(DebuggerStartMode startMode);
~GdbEngine() final; ~GdbEngine() final;
private: ////////// General Interface ////////// private: ////////// General Interface //////////
@@ -382,8 +383,7 @@ private: ////////// General Interface //////////
QString m_currentThread; QString m_currentThread;
QString m_lastWinException; QString m_lastWinException;
QString m_lastMissingDebugInfo; QString m_lastMissingDebugInfo;
const bool m_useTerminal; bool m_expectTerminalTrap = false;
bool m_terminalTrap;
bool usesExecInterrupt() const; bool usesExecInterrupt() const;
bool usesTargetAsync() const; bool usesTargetAsync() const;
@@ -441,10 +441,7 @@ private: ////////// General Interface //////////
void interruptLocalInferior(qint64 pid); void interruptLocalInferior(qint64 pid);
// Terminal // Terminal
void handleStubAttached(const DebuggerResponse &response); void handleStubAttached(const DebuggerResponse &response, qint64 mainThreadId);
void stubExited();
void stubError(const QString &msg);
Utils::ConsoleProcess m_stubProc;
// Core // Core
void handleTargetCore(const DebuggerResponse &response); void handleTargetCore(const DebuggerResponse &response);
@@ -454,6 +451,7 @@ private: ////////// General Interface //////////
QString coreName() const; QString coreName() const;
void continueSetupEngine(); void continueSetupEngine();
QString mainFunction() const;
QString m_executable; QString m_executable;
QString m_coreName; QString m_coreName;

View File

@@ -32,6 +32,7 @@
#include <debugger/debuggermainwindow.h> #include <debugger/debuggermainwindow.h>
#include <debugger/debuggerprotocol.h> #include <debugger/debuggerprotocol.h>
#include <debugger/debuggertooltipmanager.h> #include <debugger/debuggertooltipmanager.h>
#include <debugger/terminal.h>
#include <debugger/breakhandler.h> #include <debugger/breakhandler.h>
#include <debugger/disassemblerlines.h> #include <debugger/disassemblerlines.h>
@@ -98,7 +99,6 @@ LldbEngine::LldbEngine()
LldbEngine::~LldbEngine() LldbEngine::~LldbEngine()
{ {
m_stubProc.disconnect(); // Avoid spurious state transitions from late exiting stub
m_lldbProc.disconnect(); m_lldbProc.disconnect();
} }
@@ -155,8 +155,6 @@ void LldbEngine::shutdownEngine()
{ {
QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state()); QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
m_lldbProc.kill(); m_lldbProc.kill();
if (runParameters().useTerminal)
m_stubProc.stop();
notifyEngineShutdownOk(); notifyEngineShutdownOk();
} }
@@ -167,48 +165,6 @@ void LldbEngine::abortDebuggerProcess()
void LldbEngine::setupEngine() void LldbEngine::setupEngine()
{ {
if (runParameters().useTerminal) {
QTC_CHECK(false); // See above.
if (HostOsInfo::isWindowsHost()) {
// Windows up to xp needs a workaround for attaching to freshly started processes. see proc_stub_win
if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA)
m_stubProc.setMode(ConsoleProcess::Suspend);
else
m_stubProc.setMode(ConsoleProcess::Debug);
} else {
m_stubProc.setMode(ConsoleProcess::Debug);
m_stubProc.setSettings(ICore::settings());
}
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
showMessage("TRYING TO START ADAPTER");
// Currently, adapters are not re-used
// // We leave the console open, so recycle it now.
// m_stubProc.blockSignals(true);
// m_stubProc.stop();
// m_stubProc.blockSignals(false);
m_stubProc.setWorkingDirectory(runParameters().inferior.workingDirectory);
// Set environment + dumper preload.
m_stubProc.setEnvironment(runParameters().stubEnvironment);
connect(&m_stubProc, &ConsoleProcess::processError, this, &LldbEngine::stubError);
connect(&m_stubProc, &ConsoleProcess::processStarted, this, &LldbEngine::stubStarted);
connect(&m_stubProc, &ConsoleProcess::stubStopped, this, &LldbEngine::stubExited);
// FIXME: Starting the stub implies starting the inferior. This is
// fairly unclean as far as the state machine and error reporting go.
if (!m_stubProc.start(runParameters().inferior.executable,
runParameters().inferior.commandLineArguments)) {
// Error message for user is delivered via a signal.
//handleAdapterStartFailed(QString());
notifyEngineSetupFailed();
return;
}
}
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state()); QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
startLldb(); startLldb();
} }
@@ -299,17 +255,17 @@ void LldbEngine::setupInferior()
DebuggerCommand cmd2("setupInferior"); DebuggerCommand cmd2("setupInferior");
cmd2.arg("executable", executable); cmd2.arg("executable", executable);
cmd2.arg("breakonmain", rp.breakOnMain); cmd2.arg("breakonmain", rp.breakOnMain);
cmd2.arg("useterminal", rp.useTerminal); cmd2.arg("useterminal", bool(terminal()));
cmd2.arg("startmode", rp.startMode); cmd2.arg("startmode", rp.startMode);
cmd2.arg("nativemixed", isNativeMixedActive()); cmd2.arg("nativemixed", isNativeMixedActive());
cmd2.arg("workingdirectory", rp.inferior.workingDirectory); cmd2.arg("workingdirectory", rp.inferior.workingDirectory);
cmd2.arg("environment", rp.inferior.environment.toStringList()); cmd2.arg("environment", rp.inferior.environment.toStringList());
cmd2.arg("processargs", args.toUnixArgs()); cmd2.arg("processargs", args.toUnixArgs());
if (rp.useTerminal) { if (terminal()) {
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state()); QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
const qint64 attachedPID = m_stubProc.applicationPID(); const qint64 attachedPID = terminal()->applicationPid();
const qint64 attachedMainThreadID = m_stubProc.applicationMainThreadID(); const qint64 attachedMainThreadID = terminal()->applicationMainThreadId();
const QString msg = (attachedMainThreadID != -1) const QString msg = (attachedMainThreadID != -1)
? QString::fromLatin1("Attaching to %1 (%2)").arg(attachedPID).arg(attachedMainThreadID) ? QString::fromLatin1("Attaching to %1 (%2)").arg(attachedPID).arg(attachedMainThreadID)
: QString::fromLatin1("Attaching to %1").arg(attachedPID); : QString::fromLatin1("Attaching to %1").arg(attachedPID);
@@ -1100,25 +1056,5 @@ DebuggerEngine *createLldbEngine()
return new LldbEngine; return new LldbEngine;
} }
void LldbEngine::stubStarted()
{
startLldb();
}
void LldbEngine::stubError(const QString &msg)
{
AsynchronousMessageBox::critical(tr("Debugger Error"), msg);
}
void LldbEngine::stubExited()
{
if (state() == EngineShutdownRequested || state() == DebuggerFinished) {
showMessage("STUB EXITED EXPECTEDLY");
return;
}
showMessage("STUB EXITED");
notifyEngineIll();
}
} // namespace Internal } // namespace Internal
} // namespace Debugger } // namespace Debugger

View File

@@ -154,12 +154,6 @@ private:
QHash<int, DebuggerCommand> m_commandForToken; QHash<int, DebuggerCommand> m_commandForToken;
DebuggerCommandSequence m_onStop; DebuggerCommandSequence m_onStop;
// Console handling.
void stubError(const QString &msg);
void stubExited();
void stubStarted();
Utils::ConsoleProcess m_stubProc;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -25,11 +25,16 @@
#include "terminal.h" #include "terminal.h"
#include "debuggerruncontrol.h"
#include <QDebug> #include <QDebug>
#include <QIODevice> #include <QIODevice>
#include <QSocketNotifier> #include <QSocketNotifier>
#include <coreplugin/icore.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/hostosinfo.h>
#ifdef Q_OS_UNIX #ifdef Q_OS_UNIX
# define DEBUGGER_USE_TERMINAL # define DEBUGGER_USE_TERMINAL
@@ -45,6 +50,10 @@
# include <sys/stat.h> # include <sys/stat.h>
#endif #endif
using namespace Core;
using namespace ProjectExplorer;
using namespace Utils;
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
@@ -159,6 +168,67 @@ void Terminal::onSlaveReaderActivated(int fd)
#endif #endif
} }
TerminalRunner::TerminalRunner(DebuggerRunTool *debugger)
: RunWorker(debugger->runControl())
{
setDisplayName("TerminalRunner");
const DebuggerRunParameters &rp = debugger->runParameters();
m_stubRunnable = rp.inferior;
m_stubRunnable.environment = rp.stubEnvironment;
m_stubRunnable.workingDirectory = rp.inferior.workingDirectory;
connect(&m_stubProc, &ConsoleProcess::processError,
this, &TerminalRunner::stubError);
connect(&m_stubProc, &ConsoleProcess::processStarted,
this, &TerminalRunner::stubStarted);
connect(&m_stubProc, &ConsoleProcess::stubStopped,
this, &TerminalRunner::stubExited);
}
void TerminalRunner::start()
{
m_stubProc.setEnvironment(m_stubRunnable.environment);
m_stubProc.setWorkingDirectory(m_stubRunnable.workingDirectory);
if (HostOsInfo::isWindowsHost()) {
// Windows up to xp needs a workaround for attaching to freshly started processes. see proc_stub_win
if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA)
m_stubProc.setMode(ConsoleProcess::Suspend);
else
m_stubProc.setMode(ConsoleProcess::Debug);
} else {
m_stubProc.setMode(ConsoleProcess::Debug);
m_stubProc.setSettings(Core::ICore::settings());
}
// Error message for user is delivered via a signal.
m_stubProc.start(m_stubRunnable.executable, m_stubRunnable.commandLineArguments);
}
void TerminalRunner::stop()
{
m_stubProc.stop();
reportStopped();
}
void TerminalRunner::stubStarted()
{
m_applicationPid = m_stubProc.applicationPID();
m_applicationMainThreadId = m_stubProc.applicationMainThreadID();
reportStarted();
}
void TerminalRunner::stubError(const QString &msg)
{
reportFailure(msg);
}
void TerminalRunner::stubExited()
{
reportStopped();
}
} // namespace Internal } // namespace Internal
} // namespace Debugger } // namespace Debugger

View File

@@ -28,7 +28,15 @@
#include <QCoreApplication> #include <QCoreApplication>
#include <QSocketNotifier> #include <QSocketNotifier>
#include <projectexplorer/runconfiguration.h>
#include <projectexplorer/runnables.h>
#include <utils/consoleprocess.h>
namespace Debugger { namespace Debugger {
class DebuggerRunTool;
namespace Internal { namespace Internal {
class Terminal : public QObject class Terminal : public QObject
@@ -60,5 +68,28 @@ private:
QByteArray m_slaveName; QByteArray m_slaveName;
}; };
class TerminalRunner : public ProjectExplorer::RunWorker
{
public:
explicit TerminalRunner(DebuggerRunTool *runControl);
qint64 applicationPid() const { return m_applicationPid; }
qint64 applicationMainThreadId() const { return m_applicationMainThreadId; }
private:
void start() final;
void stop() final;
void stubStarted();
void stubExited();
void stubError(const QString &msg);
Utils::ConsoleProcess m_stubProc;
ProjectExplorer::StandardRunnable m_stubRunnable;
qint64 m_applicationPid = 0;
qint64 m_applicationMainThreadId = 0;
};
} // namespace Internal } // namespace Internal
} // namespace Debugger } // namespace Debugger