diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index 6d64a7e4409..a860e5defaf 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -180,7 +180,7 @@ namespace Internal { 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); } @@ -428,7 +428,7 @@ void CdbEngine::consoleStubProcessStarted() attachParameters.inferior.commandLineArguments.clear(); attachParameters.attachPID = ProcessHandle(m_consoleStub->applicationPID()); attachParameters.startMode = AttachExternal; - attachParameters.useTerminal = false; + attachParameters.inferior.runMode = ApplicationLauncher::Gui; // Force no terminal. showMessage(QString("Attaching to %1...").arg(attachParameters.attachPID.pid()), LogMisc); QString errorMessage; if (!launchCDB(attachParameters, &errorMessage)) { @@ -542,7 +542,7 @@ bool CdbEngine::launchCDB(const DebuggerRunParameters &sp, QString *errorMessage // register idle (debuggee stop) notification << "-c" << ".idle_cmd " + m_extensionCommandPrefix + "idle"; - if (sp.useTerminal) // Separate console + if (sp.inferior.runMode == ApplicationLauncher::Console) // Separate console arguments << "-2"; if (boolSetting(IgnoreFirstChanceAccessViolation)) arguments << "-x"; @@ -610,7 +610,8 @@ bool CdbEngine::launchCDB(const DebuggerRunParameters &sp, QString *errorMessage // Make sure that QTestLib uses OutputDebugString for logging. 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'))); m_process.setEnvironment(mergeEnvironment(inferiorEnvironment.toStringList(), diff --git a/src/plugins/debugger/debuggerdialogs.cpp b/src/plugins/debugger/debuggerdialogs.cpp index 3a17544ab6c..64e1721f4de 100644 --- a/src/plugins/debugger/debuggerdialogs.cpp +++ b/src/plugins/debugger/debuggerdialogs.cpp @@ -425,7 +425,6 @@ void StartApplicationDialog::run(bool attachRemote) } StandardRunnable inferior = newParameters.runnable; - debugger->setUseTerminal(newParameters.runnable.runMode == ApplicationLauncher::Console); const QString inputAddress = dialog.d->channelOverrideEdit->text(); if (!inputAddress.isEmpty()) debugger->setRemoteChannel(inputAddress); diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index ecf31ab8410..ad58dc42daa 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -106,7 +106,6 @@ QDebug operator<<(QDebug str, const DebuggerRunParameters &sp) << " debugger environment=<" << sp.debugger.environment.size() << " variables>" << " workingDir=" << sp.inferior.workingDirectory << " attachPID=" << sp.attachPID.pid() - << " useTerminal=" << sp.useTerminal << " remoteChannel=" << sp.remoteChannel << " abi=" << sp.toolChainAbi.toString() << '\n'; return str; @@ -329,7 +328,7 @@ public: // The state we had before something unexpected happend. DebuggerState m_lastGoodState = DebuggerNotReady; - Terminal m_terminal; +// Terminal m_terminal; ProcessHandle m_inferiorPid; ModulesHandler m_modulesHandler; @@ -545,18 +544,18 @@ void DebuggerEngine::start() d->m_lastGoodState = DebuggerNotReady; d->m_progress.setProgressValue(200); - d->m_terminal.setup(); - if (d->m_terminal.isUsable()) { - connect(&d->m_terminal, &Terminal::stdOutReady, [this](const QString &msg) { - d->m_runTool->appendMessage(msg, Utils::StdOutFormatSameLine); - }); - connect(&d->m_terminal, &Terminal::stdErrReady, [this](const QString &msg) { - d->m_runTool->appendMessage(msg, Utils::StdErrFormatSameLine); - }); - connect(&d->m_terminal, &Terminal::error, [this](const QString &msg) { - d->m_runTool->appendMessage(msg, Utils::ErrorMessageFormat); - }); - } +// d->m_terminal.setup(); +// if (d->m_terminal.isUsable()) { +// connect(&d->m_terminal, &Terminal::stdOutReady, [this](const QString &msg) { +// d->m_runTool->appendMessage(msg, Utils::StdOutFormatSameLine); +// }); +// connect(&d->m_terminal, &Terminal::stdErrReady, [this](const QString &msg) { +// d->m_runTool->appendMessage(msg, Utils::StdErrFormatSameLine); +// }); +// connect(&d->m_terminal, &Terminal::error, [this](const QString &msg) { +// d->m_runTool->appendMessage(msg, Utils::ErrorMessageFormat); +// }); +// } d->queueSetupEngine(); QTC_ASSERT(state() == EngineSetupRequested, qDebug() << this << state()); @@ -1378,9 +1377,10 @@ DebuggerRunTool *DebuggerEngine::runTool() const 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 &) diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h index 89723096d06..5178cb631c5 100644 --- a/src/plugins/debugger/debuggerengine.h +++ b/src/plugins/debugger/debuggerengine.h @@ -74,6 +74,7 @@ class QmlCppEngine; class DebuggerToolTipContext; class MemoryViewSetupData; class Terminal; +class TerminalRunner; class ThreadId; class DebuggerRunParameters @@ -87,7 +88,6 @@ public: Utils::Environment stubEnvironment; Utils::ProcessHandle attachPID; QStringList solibSearchPath; - bool useTerminal = false; // Used by Qml debugging. QUrl qmlServer; @@ -461,7 +461,7 @@ protected: void setMasterEngine(DebuggerEngine *masterEngine); ProjectExplorer::RunControl *runControl() const; - Terminal *terminal() const; + TerminalRunner *terminal() const; static QString msgStopped(const QString &reason = QString()); static QString msgStoppedBySignal(const QString &meaning, const QString &name); diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 5637e4b18e6..5e378ac20c0 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -2878,8 +2878,9 @@ static void createNewDock(QWidget *widget) dockWidget->show(); } -static QString formatStartParameters(const DebuggerRunParameters &sp) +static QString formatStartParameters(const DebuggerRunTool *debugger) { + const DebuggerRunParameters &sp = debugger->runParameters(); QString rc; QTextStream str(&rc); str << "Start parameters: '" << sp.displayName << "' mode: " << sp.startMode @@ -2893,7 +2894,7 @@ static QString formatStartParameters(const DebuggerRunParameters &sp) if (!sp.inferior.executable.isEmpty()) { str << "Executable: " << QDir::toNativeSeparators(sp.inferior.executable) << ' ' << sp.inferior.commandLineArguments; - if (sp.useTerminal) + if (debugger->terminalRunner()) str << " [terminal]"; str << '\n'; if (!sp.inferior.workingDirectory.isEmpty()) @@ -2928,7 +2929,7 @@ void DebuggerPluginPrivate::runControlStarted(DebuggerRunTool *runTool) .arg(runTool->engine()->objectName()) .arg(runTool->runParameters().toolChainAbi.toString()); showStatusMessage(message); - showMessage(formatStartParameters(runTool->runParameters()), LogDebug); + showMessage(formatStartParameters(runTool), LogDebug); showMessage(m_debuggerSettings->dump(), LogDebug); m_snapshotHandler->appendSnapshot(runTool); connectEngine(runTool); diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index e6832afe9aa..1ab8198fcd1 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -24,6 +24,7 @@ ****************************************************************************/ #include "debuggerruncontrol.h" +#include "terminal.h" #include "analyzer/analyzermanager.h" #include "console/console.h" @@ -76,7 +77,7 @@ namespace Debugger { namespace Internal { DebuggerEngine *createCdbEngine(QStringList *error, DebuggerStartMode sm); -DebuggerEngine *createGdbEngine(bool useTerminal, DebuggerStartMode sm); +DebuggerEngine *createGdbEngine(DebuggerStartMode sm); DebuggerEngine *createPdbEngine(); DebuggerEngine *createQmlEngine(bool useTerminal); DebuggerEngine *createQmlCppEngine(DebuggerEngine *cppEngine, bool useTerminal); @@ -173,8 +174,13 @@ public: Utils::QtcProcess m_proc; }; -} // namespace Internal +class DebuggerRunToolPrivate +{ +public: + QPointer terminalRunner; +}; +} // namespace Internal static bool breakOnMainNextTime = false; @@ -284,7 +290,13 @@ void DebuggerRunTool::setBreakOnMain(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) @@ -343,6 +355,7 @@ void DebuggerRunTool::setInferior(const Runnable &runnable) { QTC_ASSERT(runnable.is(), reportFailure(); return); m_runParameters.inferior = runnable.as(); + setUseTerminal(m_runParameters.inferior.runMode == ApplicationLauncher::Console); } void DebuggerRunTool::setInferiorExecutable(const QString &executable) @@ -469,7 +482,7 @@ void DebuggerRunTool::start() switch (m_runParameters.cppEngineType) { case GdbEngineType: - cppEngine = createGdbEngine(m_runParameters.useTerminal, m_runParameters.startMode); + cppEngine = createGdbEngine(m_runParameters.startMode); break; case CdbEngineType: { QStringList errors; @@ -493,11 +506,11 @@ void DebuggerRunTool::start() switch (m_runParameters.masterEngineType) { case QmlEngineType: - m_engine = createQmlEngine(m_runParameters.useTerminal); + m_engine = createQmlEngine(terminalRunner() != nullptr); break; case QmlCppEngineType: if (cppEngine) - m_engine = createQmlCppEngine(cppEngine, m_runParameters.useTerminal); + m_engine = createQmlCppEngine(cppEngine, terminalRunner() != nullptr); break; default: 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()) rp.inferior.environment.set("QV4_FORCE_INTERPRETER", "1"); @@ -727,8 +732,13 @@ bool DebuggerRunTool::fixupParameters() return true; } +Internal::TerminalRunner *DebuggerRunTool::terminalRunner() const +{ + return d->terminalRunner; +} + DebuggerRunTool::DebuggerRunTool(RunControl *runControl, Kit *kit) - : RunWorker(runControl) + : RunWorker(runControl), d(new DebuggerRunToolPrivate) { setDisplayName("DebuggerRunTool"); @@ -745,13 +755,25 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl, Kit *kit) 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(); if (r.is()) { m_runParameters.inferior = r.as(); - m_runParameters.useTerminal = m_runParameters.inferior.runMode == ApplicationLauncher::Console; // Normalize to work around QTBUG-17529 (QtDeclarative fails with 'File name case mismatch'...) m_runParameters.inferior.workingDirectory = FileUtils::normalizePathName(m_runParameters.inferior.workingDirectory); + setUseTerminal(m_runParameters.inferior.runMode == ApplicationLauncher::Console); } if (auto aspect = runConfig ? runConfig->extraAspect() : nullptr) { @@ -760,16 +782,6 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl, Kit *kit) 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"); if (!envBinary.isEmpty()) m_runParameters.debugger.executable = QString::fromLocal8Bit(envBinary); @@ -787,9 +799,6 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl, Kit *kit) if (ok) 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 // the kit at that time anymore. const QList tasks = DebuggerKitInformation::validateDebugger(kit); @@ -842,6 +851,7 @@ DebuggerRunTool::~DebuggerRunTool() engine->disconnect(); delete engine; } + delete d; } void DebuggerRunTool::showMessage(const QString &msg, int channel, int timeout) diff --git a/src/plugins/debugger/debuggerruncontrol.h b/src/plugins/debugger/debuggerruncontrol.h index b766a6d023d..a0379917af3 100644 --- a/src/plugins/debugger/debuggerruncontrol.h +++ b/src/plugins/debugger/debuggerruncontrol.h @@ -37,6 +37,11 @@ namespace Debugger { +namespace Internal { +class TerminalRunner; +class DebuggerRunToolPrivate; +} // Internal + class DEBUGGER_EXPORT DebuggerRunTool : public ProjectExplorer::RunWorker { Q_OBJECT @@ -128,12 +133,15 @@ public: void setTestCase(int testCase); void setOverrideStartScript(const QString &script); + Internal::TerminalRunner *terminalRunner() const; + signals: void aboutToNotifyInferiorSetupOk(); private: bool fixupParameters(); + Internal::DebuggerRunToolPrivate *d; QPointer m_engine; // Master engine Internal::DebuggerRunParameters m_runParameters; bool m_isDying = false; diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 89f57b6d559..7a10520f31c 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -137,11 +137,6 @@ static bool isMostlyHarmlessMessage(const QStringRef &msg) "Invalid argument\\n"; } -static QString mainFunction(const DebuggerRunParameters &rp) -{ - return QLatin1String(rp.toolChainAbi.os() == Abi::WindowsOS && !rp.useTerminal ? "qMain" : "main"); -} - /////////////////////////////////////////////////////////////////////// // // Debuginfo Taskhandler @@ -194,8 +189,8 @@ private: // /////////////////////////////////////////////////////////////////////// -GdbEngine::GdbEngine(bool useTerminal, DebuggerStartMode startMode) - : m_startMode(startMode), m_useTerminal(useTerminal), m_terminalTrap(useTerminal) +GdbEngine::GdbEngine(DebuggerStartMode startMode) + : m_startMode(startMode) { setObjectName("GdbEngine"); @@ -221,26 +216,10 @@ GdbEngine::GdbEngine(bool useTerminal, DebuggerStartMode startMode) // Output connect(&m_outputCollector, &OutputCollector::byteDelivery, 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() { - if (isTermEngine()) - m_stubProc.disconnect(); // Avoid spurious state transitions from late exiting stub - if (isCoreEngine()) { if (m_coreUnpackProcess) { m_coreUnpackProcess->blockSignals(true); @@ -781,9 +760,6 @@ void GdbEngine::interruptInferior() CHECK_STATE(InferiorStopRequested); - if (terminal()->sendInterrupt()) - return; - if (usesExecInterrupt()) { runCommand({"-exec-interrupt"}); } else { @@ -1079,7 +1055,7 @@ void GdbEngine::handleResultRecord(DebuggerResponse *response) Abi abi = rp.toolChainAbi; if (abi.os() == Abi::WindowsOS && cmd.function.startsWith("attach") - && (rp.startMode == AttachExternal || rp.useTerminal)) + && (rp.startMode == AttachExternal || terminal())) { // Ignore spurious 'running' responses to 'attach'. } else { @@ -1240,11 +1216,13 @@ void GdbEngine::handleStopResponse(const GdbMi &data) { // Ignore trap on Windows terminals, which results in // spurious "* stopped" message. - if (m_terminalTrap && (!data.isValid() || !data["reason"].isValid()) - && Abi::hostAbi().os() == Abi::WindowsOS) { - m_terminalTrap = false; - showMessage("IGNORING TERMINAL SIGTRAP", LogMisc); - return; + if (m_expectTerminalTrap) { + m_expectTerminalTrap = false; + if ((!data.isValid() || !data["reason"].isValid()) + && Abi::hostAbi().os() == Abi::WindowsOS) { + showMessage("IGNORING TERMINAL SIGTRAP", LogMisc); + return; + } } if (isDying()) { @@ -1279,7 +1257,7 @@ void GdbEngine::handleStopResponse(const GdbMi &data) // Ignore signals from the process stub. const GdbMi frame = data["frame"]; const QString func = frame["from"].data(); - if (runParameters().useTerminal + if (terminal() && data["reason"].data() == "signal-received" && data["signal-name"].data() == "SIGSTOP" && (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 // appears before the ^done is seen. notifyEngineRunAndInferiorStopOk(); - const DebuggerRunParameters &rp = runParameters(); - if (rp.useTerminal) + if (terminal()) continueInferiorInternal(); return; } else { @@ -1497,7 +1474,7 @@ void GdbEngine::handleStop2(const GdbMi &data) bool isStopperThread = false; if (rp.toolChainAbi.os() == Abi::WindowsOS - && rp.useTerminal + && terminal() && reason == "signal-received" && data["signal-name"].data() == "SIGTRAP") { @@ -2345,7 +2322,7 @@ QString GdbEngine::breakpointLocation(const BreakpointParameters &data) if (data.type == BreakpointAtCatch) return QLatin1String("__cxa_begin_catch"); if (data.type == BreakpointAtMain) - return mainFunction(runParameters()); + return mainFunction(); if (data.type == BreakpointByFunction) return '"' + data.functionName + '"'; if (data.type == BreakpointByAddress) @@ -3800,6 +3777,7 @@ void GdbEngine::startGdb(const QStringList &args) showMessage("ENABLING TEST CASE: " + QString::number(test)); m_gdbProc.disconnect(); // From any previous runs + m_expectTerminalTrap = terminal(); const DebuggerRunParameters &rp = runParameters(); 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. const QString dumperSourcePath = ICore::resourcePath() + "/debugger/"; - if (terminal()->isUsable()) - runCommand({"set inferior-tty " + QString::fromUtf8(terminal()->slaveDevice())}); + //if (terminal()->isUsable()) + // runCommand({"set inferior-tty " + QString::fromUtf8(terminal()->slaveDevice())}); const QFileInfo gdbBinaryFile(rp.debugger.executable); const QString uninstalledData = gdbBinaryFile.absolutePath() + "/data-directory/python"; @@ -3977,9 +3955,7 @@ void GdbEngine::startGdb(const QStringList &args) void GdbEngine::handleGdbStartFailed() { - if (isTermEngine()) - m_stubProc.stop(); - else if (isPlainEngine()) + if (isPlainEngine()) m_outputCollector.shutdown(); } @@ -4120,7 +4096,7 @@ void GdbEngine::handleInferiorPrepared() //runCommand("set follow-exec-mode new"); if (rp.breakOnMain) - runCommand({"tbreak " + mainFunction(rp)}); + runCommand({"tbreak " + mainFunction()}); // Initial attempt to set breakpoints. if (rp.startMode != AttachCore) { @@ -4316,7 +4292,7 @@ void GdbEngine::debugLastCommand() bool GdbEngine::isPlainEngine() const { - return !isCoreEngine() && !isAttachEngine() && !isRemoteEngine() && !m_terminalTrap; + return !isCoreEngine() && !isAttachEngine() && !isRemoteEngine() && !terminal(); } bool GdbEngine::isCoreEngine() const @@ -4336,7 +4312,7 @@ bool GdbEngine::isAttachEngine() const bool GdbEngine::isTermEngine() const { - return !isCoreEngine() && !isAttachEngine() && !isRemoteEngine() && m_terminalTrap; + return !isCoreEngine() && !isAttachEngine() && !isRemoteEngine() && terminal(); } void GdbEngine::setupEngine() @@ -4359,30 +4335,7 @@ void GdbEngine::setupEngine() showMessage("TRYING TO START ADAPTER"); - // Currently, GdbEngines 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, &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()); - } + startGdb(); } else if (isCoreEngine()) { @@ -4492,8 +4445,8 @@ void GdbEngine::setupInferior() } else if (isTermEngine()) { - const qint64 attachedPID = m_stubProc.applicationPID(); - const qint64 attachedMainThreadID = m_stubProc.applicationMainThreadID(); + const qint64 attachedPID = terminal()->applicationPid(); + const qint64 attachedMainThreadID = terminal()->applicationMainThreadId(); notifyInferiorPid(ProcessHandle(attachedPID)); const QString msg = (attachedMainThreadID != -1) ? QString("Going to attach to %1 (%2)").arg(attachedPID).arg(attachedMainThreadID) @@ -4551,9 +4504,12 @@ void GdbEngine::runEngine() } else if (isTermEngine()) { - const qint64 attachedPID = m_stubProc.applicationPID(); + const qint64 attachedPID = terminal()->applicationPid(); + const qint64 mainThreadId = terminal()->applicationMainThreadId(); runCommand({"attach " + QString::number(attachedPID), - [this](const DebuggerResponse &r) { handleStubAttached(r); }}); + [this, mainThreadId](const DebuggerResponse &r) { + handleStubAttached(r, mainThreadId); + }}); } 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 // 'attach' comes in before its '^done' @@ -4923,7 +4879,6 @@ void GdbEngine::handleStubAttached(const DebuggerResponse &response) if (runParameters().toolChainAbi.os() == ProjectExplorer::Abi::WindowsOS) { QString errorMessage; // Resume thread that was suspended by console stub process (see stub code). - const qint64 mainThreadId = m_stubProc.applicationMainThreadID(); if (winResumeThread(mainThreadId, &errorMessage)) { showMessage(QString("Inferior attached, thread %1 resumed"). 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) { if (fileNameFromCore.isEmpty()) @@ -5212,13 +5151,19 @@ QString GdbEngine::msgPtraceError(DebuggerStartMode sm) "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 // -DebuggerEngine *createGdbEngine(bool useTerminal, DebuggerStartMode startMode) +DebuggerEngine *createGdbEngine(DebuggerStartMode startMode) { - return new GdbEngine(useTerminal, startMode); + return new GdbEngine(startMode); } } // namespace Internal diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index a7537cfdebd..554286b9dbd 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -55,6 +55,7 @@ class DebuggerResponse; class DisassemblerAgentCookie; class GdbMi; class MemoryAgentCookie; +class TerminalRunner; struct CoreInfo { @@ -71,7 +72,7 @@ class GdbEngine : public DebuggerEngine Q_OBJECT public: - explicit GdbEngine(bool useTerminal, DebuggerStartMode startMode); + explicit GdbEngine(DebuggerStartMode startMode); ~GdbEngine() final; private: ////////// General Interface ////////// @@ -382,8 +383,7 @@ private: ////////// General Interface ////////// QString m_currentThread; QString m_lastWinException; QString m_lastMissingDebugInfo; - const bool m_useTerminal; - bool m_terminalTrap; + bool m_expectTerminalTrap = false; bool usesExecInterrupt() const; bool usesTargetAsync() const; @@ -441,10 +441,7 @@ private: ////////// General Interface ////////// void interruptLocalInferior(qint64 pid); // Terminal - void handleStubAttached(const DebuggerResponse &response); - void stubExited(); - void stubError(const QString &msg); - Utils::ConsoleProcess m_stubProc; + void handleStubAttached(const DebuggerResponse &response, qint64 mainThreadId); // Core void handleTargetCore(const DebuggerResponse &response); @@ -454,6 +451,7 @@ private: ////////// General Interface ////////// QString coreName() const; void continueSetupEngine(); + QString mainFunction() const; QString m_executable; QString m_coreName; diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index bf00138e9b4..e9f4e78bfb3 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -98,7 +99,6 @@ LldbEngine::LldbEngine() LldbEngine::~LldbEngine() { - m_stubProc.disconnect(); // Avoid spurious state transitions from late exiting stub m_lldbProc.disconnect(); } @@ -155,8 +155,6 @@ void LldbEngine::shutdownEngine() { QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state()); m_lldbProc.kill(); - if (runParameters().useTerminal) - m_stubProc.stop(); notifyEngineShutdownOk(); } @@ -167,48 +165,6 @@ void LldbEngine::abortDebuggerProcess() 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()); startLldb(); } @@ -299,17 +255,17 @@ void LldbEngine::setupInferior() DebuggerCommand cmd2("setupInferior"); cmd2.arg("executable", executable); cmd2.arg("breakonmain", rp.breakOnMain); - cmd2.arg("useterminal", rp.useTerminal); + cmd2.arg("useterminal", bool(terminal())); cmd2.arg("startmode", rp.startMode); cmd2.arg("nativemixed", isNativeMixedActive()); cmd2.arg("workingdirectory", rp.inferior.workingDirectory); cmd2.arg("environment", rp.inferior.environment.toStringList()); cmd2.arg("processargs", args.toUnixArgs()); - if (rp.useTerminal) { + if (terminal()) { QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state()); - const qint64 attachedPID = m_stubProc.applicationPID(); - const qint64 attachedMainThreadID = m_stubProc.applicationMainThreadID(); + const qint64 attachedPID = terminal()->applicationPid(); + const qint64 attachedMainThreadID = terminal()->applicationMainThreadId(); const QString msg = (attachedMainThreadID != -1) ? QString::fromLatin1("Attaching to %1 (%2)").arg(attachedPID).arg(attachedMainThreadID) : QString::fromLatin1("Attaching to %1").arg(attachedPID); @@ -1100,25 +1056,5 @@ DebuggerEngine *createLldbEngine() 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 Debugger diff --git a/src/plugins/debugger/lldb/lldbengine.h b/src/plugins/debugger/lldb/lldbengine.h index dff437497b6..9bc4a0b7c93 100644 --- a/src/plugins/debugger/lldb/lldbengine.h +++ b/src/plugins/debugger/lldb/lldbengine.h @@ -154,12 +154,6 @@ private: QHash m_commandForToken; DebuggerCommandSequence m_onStop; - - // Console handling. - void stubError(const QString &msg); - void stubExited(); - void stubStarted(); - Utils::ConsoleProcess m_stubProc; }; } // namespace Internal diff --git a/src/plugins/debugger/terminal.cpp b/src/plugins/debugger/terminal.cpp index c4f4ba0ba9b..09dcdb156c2 100644 --- a/src/plugins/debugger/terminal.cpp +++ b/src/plugins/debugger/terminal.cpp @@ -25,11 +25,16 @@ #include "terminal.h" +#include "debuggerruncontrol.h" + #include #include #include +#include + #include +#include #ifdef Q_OS_UNIX # define DEBUGGER_USE_TERMINAL @@ -45,6 +50,10 @@ # include #endif +using namespace Core; +using namespace ProjectExplorer; +using namespace Utils; + namespace Debugger { namespace Internal { @@ -159,6 +168,67 @@ void Terminal::onSlaveReaderActivated(int fd) #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 Debugger diff --git a/src/plugins/debugger/terminal.h b/src/plugins/debugger/terminal.h index 67b3bf851a5..0745373e0ea 100644 --- a/src/plugins/debugger/terminal.h +++ b/src/plugins/debugger/terminal.h @@ -28,7 +28,15 @@ #include #include +#include +#include + +#include + namespace Debugger { + +class DebuggerRunTool; + namespace Internal { class Terminal : public QObject @@ -60,5 +68,28 @@ private: 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 Debugger