aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhjk <hjk@qt.io>2017-09-08 08:53:15 +0200
committerhjk <hjk@qt.io>2017-09-12 07:01:59 +0000
commitf84d44e4e886bedbb80dcde1d8ca021d3c026eb3 (patch)
treeb2e02639bcfbc0851023b5caf7988911441d1034
parent991663d13b2e3460d64a9aefcadc1be2a1812680 (diff)
Debugger: Merge *Adapter classes into GdbEngine
The main reason for having the adapters (complex target specific state handling) is mostly gone now, leaving us mainly with the drawbacks of the solution: An additional indirection, and using a hierarchy for code sharing. So drop that, and use if/else chains instead of virtual functions now, and start simplifying the result. Change-Id: Idcf3a28da103c01cfa80cf9bab8ef51fe879b6d7 Reviewed-by: Christian Stenger <christian.stenger@qt.io> Reviewed-by: hjk <hjk@qt.io>
-rw-r--r--src/plugins/debugger/debugger.qbs5
-rw-r--r--src/plugins/debugger/gdb/attachgdbadapter.cpp125
-rw-r--r--src/plugins/debugger/gdb/attachgdbadapter.h57
-rw-r--r--src/plugins/debugger/gdb/coregdbadapter.cpp321
-rw-r--r--src/plugins/debugger/gdb/coregdbadapter.h78
-rw-r--r--src/plugins/debugger/gdb/gdb.pri10
-rw-r--r--src/plugins/debugger/gdb/gdbengine.cpp953
-rw-r--r--src/plugins/debugger/gdb/gdbengine.h246
-rw-r--r--src/plugins/debugger/gdb/gdbplainengine.cpp145
-rw-r--r--src/plugins/debugger/gdb/gdbplainengine.h57
-rw-r--r--src/plugins/debugger/gdb/remotegdbserveradapter.cpp375
-rw-r--r--src/plugins/debugger/gdb/remotegdbserveradapter.h62
-rw-r--r--src/plugins/debugger/gdb/termgdbadapter.cpp205
-rw-r--r--src/plugins/debugger/gdb/termgdbadapter.h67
-rw-r--r--src/plugins/debugger/loadcoredialog.cpp4
15 files changed, 1033 insertions, 1677 deletions
diff --git a/src/plugins/debugger/debugger.qbs b/src/plugins/debugger/debugger.qbs
index 758e3a0b93..6bc9384e26 100644
--- a/src/plugins/debugger/debugger.qbs
+++ b/src/plugins/debugger/debugger.qbs
@@ -109,14 +109,9 @@ Project {
name: "gdb"
prefix: "gdb/"
files: [
- "attachgdbadapter.cpp", "attachgdbadapter.h",
- "coregdbadapter.cpp", "coregdbadapter.h",
"gdbengine.cpp", "gdbengine.h",
"gdboptionspage.cpp",
- "gdbplainengine.cpp", "gdbplainengine.h",
- "remotegdbserveradapter.cpp", "remotegdbserveradapter.h",
"startgdbserverdialog.cpp", "startgdbserverdialog.h",
- "termgdbadapter.cpp", "termgdbadapter.h"
]
}
diff --git a/src/plugins/debugger/gdb/attachgdbadapter.cpp b/src/plugins/debugger/gdb/attachgdbadapter.cpp
deleted file mode 100644
index 519647d703..0000000000
--- a/src/plugins/debugger/gdb/attachgdbadapter.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "attachgdbadapter.h"
-
-#include <coreplugin/messagebox.h>
-
-#include <debugger/debuggerprotocol.h>
-#include <debugger/debuggerstartparameters.h>
-
-#include <utils/qtcassert.h>
-#include <utils/qtcfallthrough.h>
-
-namespace Debugger {
-namespace Internal {
-
-GdbAttachEngine::GdbAttachEngine(bool useTerminal)
- : GdbEngine(useTerminal)
-{
-}
-
-void GdbAttachEngine::setupEngine()
-{
- QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
- showMessage("TRYING TO START ADAPTER");
-
- startGdb();
-}
-
-void GdbAttachEngine::setupInferior()
-{
- QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
- // Task 254674 does not want to remove them
- //qq->breakHandler()->removeAllBreakpoints();
- handleInferiorPrepared();
-}
-
-void GdbAttachEngine::runEngine()
-{
- QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
- const qint64 pid = runParameters().attachPID.pid();
- showStatusMessage(tr("Attaching to process %1.").arg(pid));
- runCommand({"attach " + QString::number(pid),
- [this](const DebuggerResponse &r) { handleAttach(r); }});
- // In some cases we get only output like
- // "Could not attach to process. If your uid matches the uid of the target\n"
- // "process, check the setting of /proc/sys/kernel/yama/ptrace_scope, or try\n"
- // " again as the root user. For more details, see /etc/sysctl.d/10-ptrace.conf\n"
- // " ptrace: Operation not permitted.\n"
- // but no(!) ^ response. Use a second command to force *some* output
- runCommand({"print 24"});
-}
-
-void GdbAttachEngine::handleAttach(const DebuggerResponse &response)
-{
- QTC_ASSERT(state() == EngineRunRequested || state() == InferiorStopOk,
- qDebug() << state());
- switch (response.resultClass) {
- case ResultDone:
- case ResultRunning:
- showMessage("INFERIOR ATTACHED");
- if (state() == EngineRunRequested) {
- // Happens e.g. for "Attach to unstarted application"
- // We will get a '*stopped' later that we'll interpret as 'spontaneous'
- // So acknowledge the current state and put a delayed 'continue' in the pipe.
- showMessage(tr("Attached to running application"), StatusBar);
- notifyEngineRunAndInferiorRunOk();
- } else {
- // InferiorStopOk, e.g. for "Attach to running application".
- // The *stopped came in between sending the 'attach' and
- // receiving its '^done'.
- if (runParameters().continueAfterAttach)
- continueInferiorInternal();
- }
- break;
- case ResultError:
- if (response.data["msg"].data() == "ptrace: Operation not permitted.") {
- QString msg = msgPtraceError(runParameters().startMode);
- showStatusMessage(tr("Failed to attach to application: %1").arg(msg));
- Core::AsynchronousMessageBox::warning(tr("Debugger Error"), msg);
- notifyEngineIll();
- break;
- }
- Q_FALLTHROUGH(); // if msg != "ptrace: ..."
- default:
- showStatusMessage(tr("Failed to attach to application: %1")
- .arg(QString(response.data["msg"].data())));
- notifyEngineIll();
- }
-}
-
-void GdbAttachEngine::interruptInferior2()
-{
- interruptLocalInferior(runParameters().attachPID.pid());
-}
-
-void GdbAttachEngine::shutdownEngine()
-{
- notifyAdapterShutdownOk();
-}
-
-} // namespace Internal
-} // namespace Debugger
diff --git a/src/plugins/debugger/gdb/attachgdbadapter.h b/src/plugins/debugger/gdb/attachgdbadapter.h
deleted file mode 100644
index cabf468806..0000000000
--- a/src/plugins/debugger/gdb/attachgdbadapter.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "gdbengine.h"
-
-namespace Debugger {
-namespace Internal {
-
-///////////////////////////////////////////////////////////////////////
-//
-// AttachGdbAdapter
-//
-///////////////////////////////////////////////////////////////////////
-
-class GdbAttachEngine : public GdbEngine
-{
- Q_OBJECT
-
-public:
- explicit GdbAttachEngine(bool useTerminal);
-
-private:
- void setupEngine() override;
- void setupInferior() override;
- void runEngine() override;
- void interruptInferior2() override;
- void shutdownEngine() override;
-
- void handleAttach(const DebuggerResponse &response);
-};
-
-} // namespace Internal
-} // namespace Debugger
diff --git a/src/plugins/debugger/gdb/coregdbadapter.cpp b/src/plugins/debugger/gdb/coregdbadapter.cpp
deleted file mode 100644
index df6d040ccd..0000000000
--- a/src/plugins/debugger/gdb/coregdbadapter.cpp
+++ /dev/null
@@ -1,321 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "coregdbadapter.h"
-
-#include <coreplugin/messagebox.h>
-
-#include <debugger/debuggercore.h>
-#include <debugger/debuggerprotocol.h>
-#include <debugger/debuggerstartparameters.h>
-
-#include <utils/fileutils.h>
-#include <utils/qtcassert.h>
-#include <utils/synchronousprocess.h>
-#include <utils/temporarydirectory.h>
-#include <utils/temporaryfile.h>
-
-#include <QDir>
-
-using namespace Utils;
-using namespace ProjectExplorer;
-
-namespace Debugger {
-namespace Internal {
-
-#define CB(callback) [this](const DebuggerResponse &r) { callback(r); }
-#define CHECK_STATE(s) do { checkState(s, __FILE__, __LINE__); } while (0)
-
-///////////////////////////////////////////////////////////////////////
-//
-// CoreGdbAdapter
-//
-///////////////////////////////////////////////////////////////////////
-
-GdbCoreEngine::GdbCoreEngine(bool useTerminal)
- : GdbEngine(useTerminal)
-{}
-
-GdbCoreEngine::~GdbCoreEngine()
-{
- if (m_coreUnpackProcess) {
- m_coreUnpackProcess->blockSignals(true);
- m_coreUnpackProcess->terminate();
- m_coreUnpackProcess->deleteLater();
- m_coreUnpackProcess = 0;
- if (m_tempCoreFile.isOpen())
- m_tempCoreFile.close();
- }
- if (!m_tempCoreName.isEmpty()) {
- QFile tmpFile(m_tempCoreName);
- tmpFile.remove();
- }
-}
-
-void GdbCoreEngine::setupEngine()
-{
- QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
- showMessage("TRYING TO START ADAPTER");
-
- const DebuggerRunParameters &rp = runParameters();
- m_executable = rp.inferior.executable;
- QFileInfo fi(rp.coreFile);
- m_coreName = fi.absoluteFilePath();
-
- unpackCoreIfNeeded();
-}
-
-static QString findExecutableFromName(const QString &fileNameFromCore, const QString &coreFile)
-{
- if (fileNameFromCore.isEmpty())
- return fileNameFromCore;
- QFileInfo fi(fileNameFromCore);
- if (fi.isFile())
- return fileNameFromCore;
-
- // turn the filename into an absolute path, using the location of the core as a hint
- QString absPath;
- if (fi.isAbsolute()) {
- absPath = fileNameFromCore;
- } else {
- QFileInfo coreInfo(coreFile);
- QDir coreDir = coreInfo.dir();
- absPath = FileUtils::resolvePath(coreDir.absolutePath(), fileNameFromCore);
- }
- if (QFileInfo(absPath).isFile() || absPath.isEmpty())
- return absPath;
-
- // remove possible trailing arguments
- QLatin1Char sep(' ');
- QStringList pathFragments = absPath.split(sep);
- while (pathFragments.size() > 0) {
- QString joined_path = pathFragments.join(sep);
- if (QFileInfo(joined_path).isFile()) {
- return joined_path;
- }
- pathFragments.pop_back();
- }
-
- return QString();
-}
-
-GdbCoreEngine::CoreInfo
-GdbCoreEngine::readExecutableNameFromCore(const StandardRunnable &debugger, const QString &coreFile)
-{
- CoreInfo cinfo;
-#if 0
- ElfReader reader(coreFile);
- cinfo.rawStringFromCore = QString::fromLocal8Bit(reader.readCoreName(&cinfo.isCore));
- cinfo.foundExecutableName = findExecutableFromName(cinfo.rawStringFromCore, coreFile);
-#else
- QStringList args;
- args.append(QLatin1String("-nx"));
- args.append(QLatin1String("-batch"));
- args.append(QLatin1String("-c"));
- args.append(coreFile);
-
- SynchronousProcess proc;
- QStringList envLang = QProcess::systemEnvironment();
- Utils::Environment::setupEnglishOutput(&envLang);
- proc.setEnvironment(envLang);
- SynchronousProcessResponse response = proc.runBlocking(debugger.executable, args);
-
- if (response.result == SynchronousProcessResponse::Finished) {
- QString output = response.stdOut();
- // Core was generated by `/data/dev/creator-2.6/bin/qtcreator'.
- // Program terminated with signal 11, Segmentation fault.
- int pos1 = output.indexOf("Core was generated by");
- if (pos1 != -1) {
- pos1 += 23;
- int pos2 = output.indexOf('\'', pos1);
- if (pos2 != -1) {
- cinfo.isCore = true;
- cinfo.rawStringFromCore = output.mid(pos1, pos2 - pos1);
- cinfo.foundExecutableName = findExecutableFromName(cinfo.rawStringFromCore, coreFile);
- }
- }
- }
-#endif
- return cinfo;
-}
-
-void GdbCoreEngine::continueSetupEngine()
-{
- bool isCore = true;
- if (m_coreUnpackProcess) {
- isCore = m_coreUnpackProcess->exitCode() == 0;
- m_coreUnpackProcess->deleteLater();
- m_coreUnpackProcess = 0;
- if (m_tempCoreFile.isOpen())
- m_tempCoreFile.close();
- }
- if (isCore && m_executable.isEmpty()) {
- GdbCoreEngine::CoreInfo cinfo =
- readExecutableNameFromCore(runParameters().debugger, coreFileName());
-
- if (cinfo.isCore) {
- m_executable = cinfo.foundExecutableName;
- if (m_executable.isEmpty()) {
- Core::AsynchronousMessageBox::warning(
- tr("Error Loading Symbols"),
- tr("No executable to load symbols from specified core."));
- notifyEngineSetupFailed();
- return;
- }
- }
- }
- if (isCore) {
- startGdb();
- } else {
- Core::AsynchronousMessageBox::warning(
- tr("Error Loading Core File"),
- tr("The specified file does not appear to be a core file."));
- notifyEngineSetupFailed();
- }
-}
-
-void GdbCoreEngine::writeCoreChunk()
-{
- m_tempCoreFile.write(m_coreUnpackProcess->readAll());
-}
-
-void GdbCoreEngine::setupInferior()
-{
- CHECK_STATE(InferiorSetupRequested);
- setLinuxOsAbi();
- // Do that first, otherwise no symbols are loaded.
- QFileInfo fi(m_executable);
- QString path = fi.absoluteFilePath();
- runCommand({"-file-exec-and-symbols \"" + path + '"',
- CB(handleFileExecAndSymbols)});
-}
-
-void GdbCoreEngine::handleFileExecAndSymbols(const DebuggerResponse &response)
-{
- CHECK_STATE(InferiorSetupRequested);
- QString core = coreFileName();
- if (response.resultClass == ResultDone) {
- showMessage(tr("Symbols found."), StatusBar);
- handleInferiorPrepared();
- } else {
- QString msg = tr("No symbols found in core file <i>%1</i>.").arg(core)
- + ' ' + tr("This can be caused by a path length limitation "
- "in the core file.")
- + ' ' + tr("Try to specify the binary using the "
- "<i>Debug->Start Debugging->Attach to Core</i> dialog.");
- notifyInferiorSetupFailed(msg);
- }
-}
-
-void GdbCoreEngine::runEngine()
-{
- CHECK_STATE(EngineRunRequested);
- runCommand({"target core " + coreFileName(), CB(handleTargetCore)});
-}
-
-void GdbCoreEngine::handleTargetCore(const DebuggerResponse &response)
-{
- CHECK_STATE(EngineRunRequested);
- notifyEngineRunOkAndInferiorUnrunnable();
- showMessage(tr("Attached to core."), StatusBar);
- if (response.resultClass == ResultError) {
- // We'll accept any kind of error e.g. &"Cannot access memory at address 0x2abc2a24\n"
- // Even without the stack, the user can find interesting stuff by exploring
- // the memory, globals etc.
- showStatusMessage(tr("Attach to core \"%1\" failed:").arg(runParameters().coreFile)
- + '\n' + response.data["msg"].data()
- + '\n' + tr("Continuing nevertheless."));
- }
- // Due to the auto-solib-add off setting, we don't have any
- // symbols yet. Load them in order of importance.
- reloadStack();
- reloadModulesInternal();
- runCommand({"p 5", CB(handleRoundTrip)});
-}
-
-void GdbCoreEngine::handleRoundTrip(const DebuggerResponse &response)
-{
- CHECK_STATE(InferiorUnrunnable);
- Q_UNUSED(response);
- loadSymbolsForStack();
- handleStop3();
- QTimer::singleShot(1000, this, &GdbEngine::loadAllSymbols);
-}
-
-void GdbCoreEngine::interruptInferior()
-{
- // A core never runs, so this cannot be called.
- QTC_CHECK(false);
-}
-
-void GdbCoreEngine::shutdownEngine()
-{
- notifyAdapterShutdownOk();
-}
-
-static QString tempCoreFilename()
-{
- Utils::TemporaryFile tmp("tmpcore-XXXXXX");
- tmp.open();
- return tmp.fileName();
-}
-
-void GdbCoreEngine::unpackCoreIfNeeded()
-{
- QStringList arguments;
- const QString msg = "Unpacking core file to %1";
- if (m_coreName.endsWith(QLatin1String(".lzo"))) {
- m_tempCoreName = tempCoreFilename();
- showMessage(msg.arg(m_tempCoreName));
- arguments << QLatin1String("-o") << m_tempCoreName << QLatin1String("-x") << m_coreName;
- m_coreUnpackProcess = new QProcess(this);
- m_coreUnpackProcess->setWorkingDirectory(Utils::TemporaryDirectory::masterDirectoryPath());
- m_coreUnpackProcess->start(QLatin1String("lzop"), arguments);
- connect(m_coreUnpackProcess, static_cast<void (QProcess::*)(int)>(&QProcess::finished),
- this, &GdbCoreEngine::continueSetupEngine);
- } else if (m_coreName.endsWith(QLatin1String(".gz"))) {
- m_tempCoreName = tempCoreFilename();
- showMessage(msg.arg(m_tempCoreName));
- m_tempCoreFile.setFileName(m_tempCoreName);
- m_tempCoreFile.open(QFile::WriteOnly);
- arguments << QLatin1String("-c") << QLatin1String("-d") << m_coreName;
- m_coreUnpackProcess = new QProcess(this);
- m_coreUnpackProcess->setWorkingDirectory(Utils::TemporaryDirectory::masterDirectoryPath());
- m_coreUnpackProcess->start(QLatin1String("gzip"), arguments);
- connect(m_coreUnpackProcess, &QProcess::readyRead, this, &GdbCoreEngine::writeCoreChunk);
- connect(m_coreUnpackProcess, static_cast<void (QProcess::*)(int)>(&QProcess::finished),
- this, &GdbCoreEngine::continueSetupEngine);
- } else {
- continueSetupEngine();
- }
-}
-
-QString GdbCoreEngine::coreFileName() const
-{
- return m_tempCoreName.isEmpty() ? m_coreName : m_tempCoreName;
-}
-
-} // namespace Internal
-} // namespace Debugger
diff --git a/src/plugins/debugger/gdb/coregdbadapter.h b/src/plugins/debugger/gdb/coregdbadapter.h
deleted file mode 100644
index b4b7081455..0000000000
--- a/src/plugins/debugger/gdb/coregdbadapter.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "gdbengine.h"
-
-#include <QFile>
-
-namespace Debugger {
-namespace Internal {
-
-class GdbCoreEngine : public GdbEngine
-{
- Q_OBJECT
-
-public:
- explicit GdbCoreEngine(bool useTerminal);
- ~GdbCoreEngine() override;
-
- struct CoreInfo
- {
- QString rawStringFromCore;
- QString foundExecutableName; // empty if no corresponding exec could be found
- bool isCore = false;
- };
- static CoreInfo readExecutableNameFromCore(const ProjectExplorer::StandardRunnable &debugger,
- const QString &coreFile);
-
-private:
- void setupEngine() override;
- void setupInferior() override;
- void runEngine() override;
- void interruptInferior() override;
- void shutdownEngine() override;
-
- void handleFileExecAndSymbols(const DebuggerResponse &response);
- void handleTargetCore(const DebuggerResponse &response);
- void handleRoundTrip(const DebuggerResponse &response);
- void unpackCoreIfNeeded();
- QString coreFileName() const;
- QString coreName() const;
-
- void continueSetupEngine();
- void writeCoreChunk();
-
-private:
- QString m_executable;
- QString m_coreName;
- QString m_tempCoreName;
- QProcess *m_coreUnpackProcess = nullptr;
- QFile m_tempCoreFile;
-};
-
-} // namespace Internal
-} // namespace Debugger
diff --git a/src/plugins/debugger/gdb/gdb.pri b/src/plugins/debugger/gdb/gdb.pri
index 3bed54bcc4..4e0883fa03 100644
--- a/src/plugins/debugger/gdb/gdb.pri
+++ b/src/plugins/debugger/gdb/gdb.pri
@@ -1,18 +1,8 @@
HEADERS += \
$$PWD/gdbengine.h \
- $$PWD/attachgdbadapter.h \
- $$PWD/coregdbadapter.h \
- $$PWD/termgdbadapter.h \
- $$PWD/remotegdbserveradapter.h \
- $$PWD/gdbplainengine.h \
$$PWD/startgdbserverdialog.h
SOURCES += \
$$PWD/gdbengine.cpp \
$$PWD/gdboptionspage.cpp \
- $$PWD/attachgdbadapter.cpp \
- $$PWD/coregdbadapter.cpp \
- $$PWD/termgdbadapter.cpp \
- $$PWD/remotegdbserveradapter.cpp \
- $$PWD/gdbplainengine.cpp \
$$PWD/startgdbserverdialog.cpp
diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp
index 8a10f42ed8..e3c2cc3cca 100644
--- a/src/plugins/debugger/gdb/gdbengine.cpp
+++ b/src/plugins/debugger/gdb/gdbengine.cpp
@@ -25,12 +25,6 @@
#include "gdbengine.h"
-#include "attachgdbadapter.h"
-#include "coregdbadapter.h"
-#include "gdbplainengine.h"
-#include "termgdbadapter.h"
-#include "remotegdbserveradapter.h"
-
#include <debugger/debuggerstartparameters.h>
#include <debugger/debuggerinternalconstants.h>
#include <debugger/debuggerruncontrol.h>
@@ -73,9 +67,10 @@
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <utils/savedaction.h>
+#include <utils/synchronousprocess.h>
+#include <utils/temporarydirectory.h>
#include <utils/temporaryfile.h>
-#include <QBuffer>
#include <QDirIterator>
#include <QMessageBox>
#include <QProcess>
@@ -97,11 +92,6 @@ enum { debugPending = 0 };
#define CHECK_STATE(s) do { checkState(s, __FILE__, __LINE__); } while (0)
-QString GdbEngine::tooltipIName(const QString &exp)
-{
- return "tooltip." + toHex(exp);
-}
-
static bool stateAcceptsGdbCommands(DebuggerState state)
{
switch (state) {
@@ -205,27 +195,13 @@ private:
//
///////////////////////////////////////////////////////////////////////
-GdbEngine::GdbEngine(bool useTerminal)
+GdbEngine::GdbEngine(bool useTerminal, DebuggerStartMode startMode)
+ : m_startMode(startMode), m_useTerminal(useTerminal), m_terminalTrap(useTerminal)
{
setObjectName("GdbEngine");
- m_busy = false;
- m_gdbVersion = 100;
- m_pythonVersion = 0;
- m_isQnxGdb = false;
- m_registerNamesListed = false;
- m_sourcesListUpdating = false;
- m_oldestAcceptableToken = -1;
- m_nonDiscardableCount = 0;
m_gdbOutputCodec = QTextCodec::codecForLocale();
m_inferiorOutputCodec = QTextCodec::codecForLocale();
- m_pendingBreakpointRequests = 0;
- m_commandsDoneCallback = 0;
- m_stackNeeded = false;
- m_terminalTrap = useTerminal;
- m_systemDumpersLoaded = false;
- m_rerunPending = false;
- m_inUpdateLocals = false;
m_debugInfoTaskHandler = new DebugInfoTaskHandler(this);
//ExtensionSystem::PluginManager::addObject(m_debugInfoTaskHandler);
@@ -242,10 +218,45 @@ GdbEngine::GdbEngine(bool useTerminal)
this, &GdbEngine::reloadLocals);
connect(action(UseDynamicType), &SavedAction::valueChanged,
this, &GdbEngine::reloadLocals);
+
+ // 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);
+ m_coreUnpackProcess->terminate();
+ m_coreUnpackProcess->deleteLater();
+ m_coreUnpackProcess = nullptr;
+ if (m_tempCoreFile.isOpen())
+ m_tempCoreFile.close();
+ }
+ if (!m_tempCoreName.isEmpty()) {
+ QFile tmpFile(m_tempCoreName);
+ tmpFile.remove();
+ }
+ }
+
//ExtensionSystem::PluginManager::removeObject(m_debugInfoTaskHandler);
delete m_debugInfoTaskHandler;
m_debugInfoTaskHandler = 0;
@@ -254,35 +265,14 @@ GdbEngine::~GdbEngine()
disconnect();
}
-DebuggerStartMode GdbEngine::startMode() const
-{
- return runParameters().startMode;
-}
-
QString GdbEngine::failedToStartMessage()
{
return tr("The gdb process failed to start.");
}
-#if 0
-static void dump(const char *first, const char *middle, const QString & to)
-{
- QString ba(first, middle - first);
- Q_UNUSED(to)
- // note that qDebug cuts off output after a certain size... (bug?)
- qDebug("\n>>>>> %s\n%s\n====\n%s\n<<<<<\n",
- qPrintable(currentTime()),
- qPrintable(QString(ba).trimmed()),
- qPrintable(to.trimmed()));
- //qDebug() << "";
- //qDebug() << qPrintable(currentTime())
- // << " Reading response: " << QString(ba).trimmed() << "\n";
-}
-#endif
-
// Parse "~:gdb: unknown target exception 0xc0000139 at 0x77bef04e\n"
// and return an exception message
-static inline QString msgWinException(const QString &data, unsigned *exCodeIn = 0)
+static QString msgWinException(const QString &data, unsigned *exCodeIn = 0)
{
if (exCodeIn)
*exCodeIn = 0;
@@ -787,6 +777,9 @@ void GdbEngine::readGdbStandardOutput()
void GdbEngine::interruptInferior()
{
+ // A core never runs, so this cannot be called.
+ QTC_ASSERT(!isCoreEngine(), return);
+
CHECK_STATE(InferiorStopRequested);
if (terminal()->sendInterrupt())
@@ -1017,7 +1010,7 @@ void GdbEngine::handleResultRecord(DebuggerResponse *response)
//notifyInferiorIll();
//showStatusMessage(tr("Executable failed: %1").arg(msg));
//shutdown();
- //Core::AsynchronousMessageBox::critical(tr("Executable failed"), msg);
+ //AsynchronousMessageBox::critical(tr("Executable failed"), msg);
} else if (msg.contains("Cannot insert breakpoint")) {
// For breakpoints set by address to non-existent addresses we
// might get something like "6^error,msg="Warning:\nCannot insert
@@ -1862,7 +1855,7 @@ void GdbEngine::setLinuxOsAbi()
void GdbEngine::detachDebugger()
{
CHECK_STATE(InferiorStopOk);
- QTC_ASSERT(startMode() != AttachCore, qDebug() << startMode());
+ QTC_ASSERT(m_startMode != AttachCore, qDebug() << m_startMode);
DebuggerCommand cmd("detach", ExitRequest);
cmd.callback = [this](const DebuggerResponse &) {
CHECK_STATE(InferiorStopOk);
@@ -3984,6 +3977,10 @@ void GdbEngine::startGdb(const QStringList &args)
void GdbEngine::handleGdbStartFailed()
{
+ if (isTermEngine())
+ m_stubProc.stop();
+ else if (isPlainEngine())
+ m_outputCollector.shutdown();
}
void GdbEngine::loadInitScript()
@@ -4314,7 +4311,7 @@ QString GdbEngine::msgConnectRemoteServerFailed(const QString &why)
void GdbEngine::interruptLocalInferior(qint64 pid)
{
- QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state(); return);
+ CHECK_STATE(InferiorStopRequested);
if (pid <= 0) {
showMessage("TRYING TO INTERRUPT INFERIOR BEFORE PID WAS OBTAINED", LogError);
return;
@@ -4333,25 +4330,836 @@ void GdbEngine::debugLastCommand()
runCommand(m_lastDebuggableCommand);
}
-//
-// Factory
-//
+bool GdbEngine::isPlainEngine() const
+{
+ return !isCoreEngine() && !isAttachEngine() && !isRemoteEngine() && !m_terminalTrap;
+}
+
+bool GdbEngine::isCoreEngine() const
+{
+ return m_startMode == AttachCore;
+}
-DebuggerEngine *createGdbEngine(bool useTerminal, DebuggerStartMode sm)
+bool GdbEngine::isRemoteEngine() const
{
- switch (sm) {
- case AttachCore:
- return new GdbCoreEngine(useTerminal);
- case StartRemoteProcess:
- case AttachToRemoteServer:
- return new GdbRemoteServerEngine(useTerminal);
- case AttachExternal:
- return new GdbAttachEngine(useTerminal);
+ return m_startMode == StartRemoteProcess || m_startMode == AttachToRemoteServer;
+}
+
+bool GdbEngine::isAttachEngine() const
+{
+ return m_startMode == AttachExternal;
+}
+
+bool GdbEngine::isTermEngine() const
+{
+ return !isCoreEngine() && !isAttachEngine() && !isRemoteEngine() && m_terminalTrap;
+}
+
+void GdbEngine::setupEngine()
+{
+ CHECK_STATE(EngineSetupRequested);
+ showMessage("TRYING TO START ADAPTER");
+
+ if (isAttachEngine()) {
+
+ startGdb();
+
+ } else if (isRemoteEngine()) {
+
+ if (HostOsInfo::isWindowsHost())
+ m_gdbProc.setUseCtrlCStub(runParameters().useCtrlCStub); // This is only set for QNX
+
+ startGdb();
+
+ } else if (isTermEngine()) {
+
+ 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());
+ }
+
+ } else if (isCoreEngine()) {
+
+ CHECK_STATE(EngineSetupRequested);
+ showMessage("TRYING TO START ADAPTER");
+
+ const DebuggerRunParameters &rp = runParameters();
+ m_executable = rp.inferior.executable;
+ QFileInfo fi(rp.coreFile);
+ m_coreName = fi.absoluteFilePath();
+
+ unpackCoreIfNeeded();
+
+ } else if (isPlainEngine()) {
+
+ QStringList gdbArgs;
+
+ if (!m_outputCollector.listen()) {
+ handleAdapterStartFailed(tr("Cannot set up communication with child process: %1")
+ .arg(m_outputCollector.errorString()));
+ return;
+ }
+ gdbArgs.append("--tty=" + m_outputCollector.serverName());
+
+ startGdb(gdbArgs);
+ }
+}
+
+void GdbEngine::setupInferior()
+{
+ CHECK_STATE(InferiorSetupRequested);
+
+ if (isAttachEngine()) {
+ // Task 254674 does not want to remove them
+ //qq->breakHandler()->removeAllBreakpoints();
+ handleInferiorPrepared();
+
+ } else if (isRemoteEngine()) {
+
+ setLinuxOsAbi();
+ const DebuggerRunParameters &rp = runParameters();
+ QString symbolFile;
+ if (!rp.symbolFile.isEmpty()) {
+ QFileInfo fi(rp.symbolFile);
+ symbolFile = fi.absoluteFilePath();
+ }
+
+ //const QByteArray sysroot = sp.sysroot.toLocal8Bit();
+ //const QByteArray remoteArch = sp.remoteArchitecture.toLatin1();
+ const QString args = runParameters().inferior.commandLineArguments;
+
+ // if (!remoteArch.isEmpty())
+ // postCommand("set architecture " + remoteArch);
+ const QString solibSearchPath = rp.solibSearchPath.join(HostOsInfo::pathListSeparator());
+ if (!solibSearchPath.isEmpty())
+ runCommand({"set solib-search-path " + solibSearchPath});
+
+ if (!args.isEmpty())
+ runCommand({"-exec-arguments " + args});
+
+ setEnvironmentVariables();
+
+ // This has to be issued before 'target remote'. On pre-7.0 the
+ // command is not present and will result in ' No symbol table is
+ // loaded. Use the "file" command.' as gdb tries to set the
+ // value of a variable with name 'target-async'.
+ //
+ // Testing with -list-target-features which was introduced at
+ // the same time would not work either, as this need an existing
+ // target.
+ //
+ // Using it even without a target and having it fail might still
+ // be better as:
+ // Some external comment: '[but] "set target-async on" with a native
+ // windows gdb will work, but then fail when you actually do
+ // "run"/"attach", I think..
+
+
+ // gdb/mi/mi-main.c:1958: internal-error:
+ // mi_execute_async_cli_command: Assertion `is_running (inferior_ptid)'
+ // failed.\nA problem internal to GDB has been detected,[...]
+ if (usesTargetAsync())
+ runCommand({"set target-async on", CB(handleSetTargetAsync)});
+
+ if (symbolFile.isEmpty()) {
+ showMessage(tr("No symbol file given."), StatusBar);
+ callTargetRemote();
+ return;
+ }
+
+ if (!symbolFile.isEmpty()) {
+ runCommand({"-file-exec-and-symbols \"" + symbolFile + '"',
+ CB(handleFileExecAndSymbols)});
+ }
+
+ } else if (isCoreEngine()) {
+
+ setLinuxOsAbi();
+ // Do that first, otherwise no symbols are loaded.
+ QFileInfo fi(m_executable);
+ QString path = fi.absoluteFilePath();
+ runCommand({"-file-exec-and-symbols \"" + path + '"',
+ CB(handleFileExecAndSymbols)});
+
+ } else if (isTermEngine()) {
+
+ const qint64 attachedPID = m_stubProc.applicationPID();
+ const qint64 attachedMainThreadID = m_stubProc.applicationMainThreadID();
+ notifyInferiorPid(ProcessHandle(attachedPID));
+ const QString msg = (attachedMainThreadID != -1)
+ ? QString("Going to attach to %1 (%2)").arg(attachedPID).arg(attachedMainThreadID)
+ : QString("Going to attach to %1").arg(attachedPID);
+ showMessage(msg, LogMisc);
+ handleInferiorPrepared();
+
+ } else if (isPlainEngine()) {
+
+ setEnvironmentVariables();
+ const DebuggerRunParameters &rp = runParameters();
+ if (!rp.inferior.workingDirectory.isEmpty())
+ runCommand({"cd " + rp.inferior.workingDirectory});
+ if (!rp.inferior.commandLineArguments.isEmpty()) {
+ QString args = rp.inferior.commandLineArguments;
+ runCommand({"-exec-arguments " + args});
+ }
+
+ QString executable = QFileInfo(runParameters().inferior.executable).absoluteFilePath();
+ runCommand({"-file-exec-and-symbols \"" + executable + '"',
+ CB(handleFileExecAndSymbols)});
+ }
+}
+
+void GdbEngine::runEngine()
+{
+ CHECK_STATE(EngineRunRequested);
+
+ if (isAttachEngine()) {
+
+ const qint64 pid = runParameters().attachPID.pid();
+ showStatusMessage(tr("Attaching to process %1.").arg(pid));
+ runCommand({"attach " + QString::number(pid),
+ [this](const DebuggerResponse &r) { handleAttach(r); }});
+ // In some cases we get only output like
+ // "Could not attach to process. If your uid matches the uid of the target\n"
+ // "process, check the setting of /proc/sys/kernel/yama/ptrace_scope, or try\n"
+ // " again as the root user. For more details, see /etc/sysctl.d/10-ptrace.conf\n"
+ // " ptrace: Operation not permitted.\n"
+ // but no(!) ^ response. Use a second command to force *some* output
+ runCommand({"print 24"});
+
+ } else if (isRemoteEngine()) {
+
+ if (runParameters().useContinueInsteadOfRun) {
+ notifyEngineRunAndInferiorStopOk();
+ continueInferiorInternal();
+ } else {
+ runCommand({"-exec-run", DebuggerCommand::RunRequest, CB(handleExecRun)});
+ }
+
+ } else if (isCoreEngine()) {
+
+ runCommand({"target core " + coreFileName(), CB(handleTargetCore)});
+
+ } else if (isTermEngine()) {
+
+ const qint64 attachedPID = m_stubProc.applicationPID();
+ runCommand({"attach " + QString::number(attachedPID),
+ [this](const DebuggerResponse &r) { handleStubAttached(r); }});
+
+ } else if (isPlainEngine()) {
+
+ if (runParameters().useContinueInsteadOfRun)
+ runCommand({"-exec-continue", DebuggerCommand::RunRequest, CB(handleExecuteContinue)});
+ else
+ runCommand({"-exec-run", DebuggerCommand::RunRequest, CB(handleExecRun)});
+
+ }
+}
+
+void GdbEngine::handleAttach(const DebuggerResponse &response)
+{
+ if (isAttachEngine()) {
+
+ QTC_ASSERT(state() == EngineRunRequested || state() == InferiorStopOk, qDebug() << state());
+ switch (response.resultClass) {
+ case ResultDone:
+ case ResultRunning:
+ showMessage("INFERIOR ATTACHED");
+ if (state() == EngineRunRequested) {
+ // Happens e.g. for "Attach to unstarted application"
+ // We will get a '*stopped' later that we'll interpret as 'spontaneous'
+ // So acknowledge the current state and put a delayed 'continue' in the pipe.
+ showMessage(tr("Attached to running application"), StatusBar);
+ notifyEngineRunAndInferiorRunOk();
+ } else {
+ // InferiorStopOk, e.g. for "Attach to running application".
+ // The *stopped came in between sending the 'attach' and
+ // receiving its '^done'.
+ if (runParameters().continueAfterAttach)
+ continueInferiorInternal();
+ }
+ break;
+ case ResultError:
+ if (response.data["msg"].data() == "ptrace: Operation not permitted.") {
+ QString msg = msgPtraceError(runParameters().startMode);
+ showStatusMessage(tr("Failed to attach to application: %1").arg(msg));
+ AsynchronousMessageBox::warning(tr("Debugger Error"), msg);
+ notifyEngineIll();
+ break;
+ }
+ showStatusMessage(tr("Failed to attach to application: %1")
+ .arg(QString(response.data["msg"].data())));
+ notifyEngineIll();
+ break;
+ default:
+ showStatusMessage(tr("Failed to attach to application: %1")
+ .arg(QString(response.data["msg"].data())));
+ notifyEngineIll();
+ break;
+ }
+
+ } else if (isRemoteEngine()) {
+
+ CHECK_STATE(InferiorSetupRequested);
+ switch (response.resultClass) {
+ case ResultDone:
+ case ResultRunning: {
+ showMessage("INFERIOR ATTACHED");
+ showMessage(msgAttachedToStoppedInferior(), StatusBar);
+ handleInferiorPrepared();
+ break;
+ }
+ case ResultError:
+ if (response.data["msg"].data() == "ptrace: Operation not permitted.") {
+ notifyInferiorSetupFailed(msgPtraceError(runParameters().startMode));
+ break;
+ }
+ notifyInferiorSetupFailed(response.data["msg"].data());
+ break;
+ default:
+ notifyInferiorSetupFailed(response.data["msg"].data());
+ break;
+ }
+
+ }
+}
+
+void GdbEngine::interruptInferior2()
+{
+ if (isAttachEngine()) {
+
+ interruptLocalInferior(runParameters().attachPID.pid());
+
+ } else if (isRemoteEngine()) {
+
+ CHECK_STATE(InferiorStopRequested);
+ if (usesTargetAsync()) {
+ runCommand({"-exec-interrupt", CB(handleInterruptInferior)});
+ } else if (m_isQnxGdb && HostOsInfo::isWindowsHost()) {
+ m_gdbProc.interrupt();
+ } else {
+ qint64 pid = m_gdbProc.processId();
+ bool ok = interruptProcess(pid, GdbEngineType, &m_errorString);
+ if (!ok) {
+ // FIXME: Extra state needed?
+ showMessage("NOTE: INFERIOR STOP NOT POSSIBLE");
+ showStatusMessage(tr("Interrupting not possible"));
+ notifyInferiorRunOk();
+ }
+ }
+
+ } else if (isTermEngine() || isPlainEngine()) {
+
+ interruptLocalInferior(inferiorPid());
+
+ }
+}
+
+void GdbEngine::shutdownEngine()
+{
+ if (isPlainEngine()) {
+ showMessage(QString("PLAIN ADAPTER SHUTDOWN %1").arg(state()));
+ m_outputCollector.shutdown();
+ }
+
+ notifyAdapterShutdownOk();
+}
+
+void GdbEngine::handleFileExecAndSymbols(const DebuggerResponse &response)
+{
+ CHECK_STATE(InferiorSetupRequested);
+
+ if (isRemoteEngine()) {
+ if (response.resultClass == ResultDone) {
+ callTargetRemote();
+ } else {
+ QString reason = response.data["msg"].data();
+ QString msg = tr("Reading debug information failed:") + '\n' + reason;
+ if (reason.endsWith("No such file or directory.")) {
+ showMessage("INFERIOR STARTUP: BINARY NOT FOUND");
+ showMessage(msg, StatusBar);
+ callTargetRemote(); // Proceed nevertheless.
+ } else {
+ notifyInferiorSetupFailed(msg);
+ }
+ }
+
+ } else if (isCoreEngine()) {
+
+ QString core = coreFileName();
+ if (response.resultClass == ResultDone) {
+ showMessage(tr("Symbols found."), StatusBar);
+ handleInferiorPrepared();
+ } else {
+ QString msg = tr("No symbols found in core file <i>%1</i>.").arg(core)
+ + ' ' + tr("This can be caused by a path length limitation "
+ "in the core file.")
+ + ' ' + tr("Try to specify the binary using the "
+ "<i>Debug->Start Debugging->Attach to Core</i> dialog.");
+ notifyInferiorSetupFailed(msg);
+ }
+
+ } else if (isPlainEngine()) {
+
+ if (response.resultClass == ResultDone) {
+ handleInferiorPrepared();
+ } else {
+ QString msg = response.data["msg"].data();
+ // Extend the message a bit in unknown cases.
+ if (!msg.endsWith("File format not recognized"))
+ msg = tr("Starting executable failed:") + '\n' + msg;
+ notifyInferiorSetupFailed(msg);
+ }
+
+ }
+}
+
+void GdbEngine::handleExecRun(const DebuggerResponse &response)
+{
+ CHECK_STATE(EngineRunRequested);
+
+ if (isRemoteEngine()) {
+
+ if (response.resultClass == ResultRunning) {
+ notifyEngineRunAndInferiorRunOk();
+ showMessage("INFERIOR STARTED");
+ showMessage(msgInferiorSetupOk(), StatusBar);
+ } else {
+ showMessage(response.data["msg"].data());
+ notifyEngineRunFailed();
+ }
+
+ } else if (isPlainEngine()) {
+
+ if (response.resultClass == ResultRunning) {
+ notifyEngineRunAndInferiorRunOk(); // For gdb < 7.0
+ //showStatusMessage(tr("Running..."));
+ showMessage("INFERIOR STARTED");
+ showMessage(msgInferiorSetupOk(), StatusBar);
+ // FIXME: That's the wrong place for it.
+ if (boolSetting(EnableReverseDebugging))
+ runCommand({"target record"});
+ } else {
+ QString msg = response.data["msg"].data();
+ //QTC_CHECK(status() == InferiorRunOk);
+ //interruptInferior();
+ showMessage(msg);
+ notifyEngineRunFailed();
+ }
+
+ }
+}
+
+void GdbEngine::handleSetTargetAsync(const DebuggerResponse &response)
+{
+ CHECK_STATE(InferiorSetupRequested);
+ if (response.resultClass == ResultError)
+ qDebug() << "Adapter too old: does not support asynchronous mode.";
+}
+
+void GdbEngine::callTargetRemote()
+{
+ QString channel = runParameters().remoteChannel;
+
+ // Don't touch channels with explicitly set protocols.
+ if (!channel.startsWith("tcp:") && !channel.startsWith("udp:")
+ && !channel.startsWith("file:") && channel.contains(':')
+ && !channel.startsWith('|'))
+ {
+ // "Fix" the IPv6 case with host names without '['...']'
+ if (!channel.startsWith('[') && channel.count(':') >= 2) {
+ channel.insert(0, '[');
+ channel.insert(channel.lastIndexOf(':'), ']');
+ }
+ channel = "tcp:" + channel;
+ }
+
+ if (m_isQnxGdb)
+ runCommand({"target qnx " + channel, CB(handleTargetQnx)});
+ else if (runParameters().useExtendedRemote)
+ runCommand({"target extended-remote " + channel, CB(handleTargetExtendedRemote)});
+ else
+ runCommand({"target remote " + channel, CB(handleTargetRemote)});
+}
+
+void GdbEngine::handleTargetRemote(const DebuggerResponse &response)
+{
+ CHECK_STATE(InferiorSetupRequested);
+ if (response.resultClass == ResultDone) {
+ // gdb server will stop the remote application itself.
+ showMessage("INFERIOR STARTED");
+ showMessage(msgAttachedToStoppedInferior(), StatusBar);
+ QString commands = expand(stringSetting(GdbPostAttachCommands));
+ if (!commands.isEmpty())
+ runCommand({commands, NativeCommand});
+ handleInferiorPrepared();
+ } else {
+ // 16^error,msg="hd:5555: Connection timed out."
+ notifyInferiorSetupFailed(msgConnectRemoteServerFailed(response.data["msg"].data()));
+ }
+}
+
+void GdbEngine::handleTargetExtendedRemote(const DebuggerResponse &response)
+{
+ CHECK_STATE(InferiorSetupRequested);
+ if (response.resultClass == ResultDone) {
+ showMessage("ATTACHED TO GDB SERVER STARTED");
+ showMessage(msgAttachedToStoppedInferior(), StatusBar);
+ QString commands = expand(stringSetting(GdbPostAttachCommands));
+ if (!commands.isEmpty())
+ runCommand({commands, NativeCommand});
+ if (runParameters().attachPID.isValid()) { // attach to pid if valid
+ // gdb server will stop the remote application itself.
+ runCommand({"attach " + QString::number(runParameters().attachPID.pid()),
+ CB(handleTargetExtendedAttach)});
+ } else if (!runParameters().inferior.executable.isEmpty()) {
+ runCommand({"-gdb-set remote exec-file " + runParameters().inferior.executable,
+ CB(handleTargetExtendedAttach)});
+ } else {
+ const QString title = tr("No Remote Executable or Process ID Specified");
+ const QString msg = tr(
+ "No remote executable could be determined from your build system files.<p>"
+ "In case you use qmake, consider adding<p>"
+ "&nbsp;&nbsp;&nbsp;&nbsp;target.path = /tmp/your_executable # path on device<br>"
+ "&nbsp;&nbsp;&nbsp;&nbsp;INSTALLS += target</p>"
+ "to your .pro file.");
+ QMessageBox *mb = showMessageBox(QMessageBox::Critical, title, msg,
+ QMessageBox::Ok | QMessageBox::Cancel);
+ mb->button(QMessageBox::Cancel)->setText(tr("Continue Debugging"));
+ mb->button(QMessageBox::Ok)->setText(tr("Stop Debugging"));
+ if (mb->exec() == QMessageBox::Ok) {
+ showMessage("KILLING DEBUGGER AS REQUESTED BY USER");
+ notifyInferiorSetupFailed(title);
+ } else {
+ showMessage("CONTINUE DEBUGGER AS REQUESTED BY USER");
+ handleInferiorPrepared(); // This will likely fail.
+ }
+ }
+ } else {
+ notifyInferiorSetupFailed(msgConnectRemoteServerFailed(response.data["msg"].data()));
+ }
+}
+
+void GdbEngine::handleTargetExtendedAttach(const DebuggerResponse &response)
+{
+ CHECK_STATE(InferiorSetupRequested);
+ if (response.resultClass == ResultDone) {
+ // gdb server will stop the remote application itself.
+ handleInferiorPrepared();
+ } else {
+ notifyInferiorSetupFailed(msgConnectRemoteServerFailed(response.data["msg"].data()));
+ }
+}
+
+void GdbEngine::handleTargetQnx(const DebuggerResponse &response)
+{
+ CHECK_STATE(InferiorSetupRequested);
+ if (response.resultClass == ResultDone) {
+ // gdb server will stop the remote application itself.
+ showMessage("INFERIOR STARTED");
+ showMessage(msgAttachedToStoppedInferior(), StatusBar);
+
+ const DebuggerRunParameters &rp = runParameters();
+ const QString remoteExecutable = rp.inferior.executable;
+ if (rp.attachPID.isValid())
+ runCommand({"attach " + QString::number(rp.attachPID.pid()), CB(handleAttach)});
+ else if (!remoteExecutable.isEmpty())
+ runCommand({"set nto-executable " + remoteExecutable, CB(handleSetNtoExecutable)});
+ else
+ handleInferiorPrepared();
+ } else {
+ // 16^error,msg="hd:5555: Connection timed out."
+ notifyInferiorSetupFailed(response.data["msg"].data());
+ }
+}
+
+void GdbEngine::handleSetNtoExecutable(const DebuggerResponse &response)
+{
+ CHECK_STATE(InferiorSetupRequested);
+ switch (response.resultClass) {
+ case ResultDone:
+ case ResultRunning: {
+ showMessage("EXECUTABLE SET");
+ showMessage(msgAttachedToStoppedInferior(), StatusBar);
+ handleInferiorPrepared();
+ break;
+ }
+ case ResultError:
default:
- if (useTerminal)
- return new GdbTermEngine(useTerminal);
- return new GdbPlainEngine(useTerminal);
+ notifyInferiorSetupFailed(response.data["msg"].data());
+ }
+}
+
+void GdbEngine::handleInterruptInferior(const DebuggerResponse &response)
+{
+ if (response.resultClass == ResultDone) {
+ // The gdb server will trigger extra output that we will pick up
+ // to do a proper state transition.
+ } else {
+ // FIXME: On some gdb versions like git 170ffa5d7dd this produces
+ // >810^error,msg="mi_cmd_exec_interrupt: Inferior not executing."
+ notifyInferiorStopOk();
+ }
+}
+
+void GdbEngine::handleStubAttached(const DebuggerResponse &response)
+{
+ // InferiorStopOk can happen if the "*stopped" in response to the
+ // 'attach' comes in before its '^done'
+ QTC_ASSERT(state() == EngineRunRequested || state() == InferiorStopOk, qDebug() << state());
+
+ switch (response.resultClass) {
+ case ResultDone:
+ case ResultRunning:
+ 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);
+ } else {
+ showMessage(QString("Inferior attached, unable to resume thread %1: %2").
+ arg(mainThreadId).arg(errorMessage),
+ LogWarning);
+ }
+ notifyEngineRunAndInferiorStopOk();
+ continueInferiorInternal();
+ } else {
+ showMessage("INFERIOR ATTACHED AND RUNNING");
+ //notifyEngineRunAndInferiorRunOk();
+ // Wait for the upcoming *stopped and handle it there.
+ }
+ break;
+ case ResultError:
+ if (response.data["msg"].data() == "ptrace: Operation not permitted.") {
+ showMessage(msgPtraceError(runParameters().startMode));
+ notifyEngineRunFailed();
+ break;
+ }
+ showMessage(response.data["msg"].data());
+ notifyEngineIll();
+ break;
+ default:
+ showMessage(QString("Invalid response %1").arg(response.resultClass));
+ notifyEngineIll();
+ break;
+ }
+}
+
+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())
+ return fileNameFromCore;
+ QFileInfo fi(fileNameFromCore);
+ if (fi.isFile())
+ return fileNameFromCore;
+
+ // turn the filename into an absolute path, using the location of the core as a hint
+ QString absPath;
+ if (fi.isAbsolute()) {
+ absPath = fileNameFromCore;
+ } else {
+ QFileInfo coreInfo(coreFile);
+ QDir coreDir = coreInfo.dir();
+ absPath = FileUtils::resolvePath(coreDir.absolutePath(), fileNameFromCore);
+ }
+ if (QFileInfo(absPath).isFile() || absPath.isEmpty())
+ return absPath;
+
+ // remove possible trailing arguments
+ QLatin1Char sep(' ');
+ QStringList pathFragments = absPath.split(sep);
+ while (pathFragments.size() > 0) {
+ QString joined_path = pathFragments.join(sep);
+ if (QFileInfo(joined_path).isFile()) {
+ return joined_path;
+ }
+ pathFragments.pop_back();
}
+
+ return QString();
+}
+
+CoreInfo CoreInfo::readExecutableNameFromCore(const StandardRunnable &debugger, const QString &coreFile)
+{
+ CoreInfo cinfo;
+#if 0
+ ElfReader reader(coreFile);
+ cinfo.rawStringFromCore = QString::fromLocal8Bit(reader.readCoreName(&cinfo.isCore));
+ cinfo.foundExecutableName = findExecutableFromName(cinfo.rawStringFromCore, coreFile);
+#else
+ QStringList args = {"-nx", "-batch", "-c", coreFile};
+
+ SynchronousProcess proc;
+ QStringList envLang = QProcess::systemEnvironment();
+ Utils::Environment::setupEnglishOutput(&envLang);
+ proc.setEnvironment(envLang);
+ SynchronousProcessResponse response = proc.runBlocking(debugger.executable, args);
+
+ if (response.result == SynchronousProcessResponse::Finished) {
+ QString output = response.stdOut();
+ // Core was generated by `/data/dev/creator-2.6/bin/qtcreator'.
+ // Program terminated with signal 11, Segmentation fault.
+ int pos1 = output.indexOf("Core was generated by");
+ if (pos1 != -1) {
+ pos1 += 23;
+ int pos2 = output.indexOf('\'', pos1);
+ if (pos2 != -1) {
+ cinfo.isCore = true;
+ cinfo.rawStringFromCore = output.mid(pos1, pos2 - pos1);
+ cinfo.foundExecutableName = findExecutableFromName(cinfo.rawStringFromCore, coreFile);
+ }
+ }
+ }
+#endif
+ return cinfo;
+}
+
+void GdbEngine::continueSetupEngine()
+{
+ if (isCoreEngine()) {
+ bool isCore = true;
+ if (m_coreUnpackProcess) {
+ isCore = m_coreUnpackProcess->exitCode() == 0;
+ m_coreUnpackProcess->deleteLater();
+ m_coreUnpackProcess = 0;
+ if (m_tempCoreFile.isOpen())
+ m_tempCoreFile.close();
+ }
+ if (isCore && m_executable.isEmpty()) {
+ CoreInfo cinfo =
+ CoreInfo::readExecutableNameFromCore(runParameters().debugger, coreFileName());
+
+ if (cinfo.isCore) {
+ m_executable = cinfo.foundExecutableName;
+ if (m_executable.isEmpty()) {
+ AsynchronousMessageBox::warning(tr("Error Loading Symbols"),
+ tr("No executable to load symbols from specified core."));
+ notifyEngineSetupFailed();
+ return;
+ }
+ }
+ }
+ if (isCore) {
+ startGdb();
+ } else {
+ AsynchronousMessageBox::warning(tr("Error Loading Core File"),
+ tr("The specified file does not appear to be a core file."));
+ notifyEngineSetupFailed();
+ }
+ }
+}
+
+void GdbEngine::handleTargetCore(const DebuggerResponse &response)
+{
+ CHECK_STATE(EngineRunRequested);
+ notifyEngineRunOkAndInferiorUnrunnable();
+ showMessage(tr("Attached to core."), StatusBar);
+ if (response.resultClass == ResultError) {
+ // We'll accept any kind of error e.g. &"Cannot access memory at address 0x2abc2a24\n"
+ // Even without the stack, the user can find interesting stuff by exploring
+ // the memory, globals etc.
+ showStatusMessage(tr("Attach to core \"%1\" failed:").arg(runParameters().coreFile)
+ + '\n' + response.data["msg"].data()
+ + '\n' + tr("Continuing nevertheless."));
+ }
+ // Due to the auto-solib-add off setting, we don't have any
+ // symbols yet. Load them in order of importance.
+ reloadStack();
+ reloadModulesInternal();
+ runCommand({"p 5", CB(handleCoreRoundTrip)});
+}
+
+void GdbEngine::handleCoreRoundTrip(const DebuggerResponse &response)
+{
+ CHECK_STATE(InferiorUnrunnable);
+ Q_UNUSED(response);
+ loadSymbolsForStack();
+ handleStop3();
+ QTimer::singleShot(1000, this, &GdbEngine::loadAllSymbols);
+}
+
+static QString tempCoreFilename()
+{
+ Utils::TemporaryFile tmp("tmpcore-XXXXXX");
+ tmp.open();
+ return tmp.fileName();
+}
+
+void GdbEngine::unpackCoreIfNeeded()
+{
+ QStringList arguments;
+ const QString msg = "Unpacking core file to %1";
+ if (m_coreName.endsWith(".lzo")) {
+ m_tempCoreName = tempCoreFilename();
+ showMessage(msg.arg(m_tempCoreName));
+ arguments << "-o" << m_tempCoreName << "-x" << m_coreName;
+ m_coreUnpackProcess = new QProcess(this);
+ m_coreUnpackProcess->setWorkingDirectory(TemporaryDirectory::masterDirectoryPath());
+ m_coreUnpackProcess->start("lzop", arguments);
+ connect(m_coreUnpackProcess, static_cast<void (QProcess::*)(int)>(&QProcess::finished),
+ this, &GdbEngine::continueSetupEngine);
+ } else if (m_coreName.endsWith(".gz")) {
+ m_tempCoreName = tempCoreFilename();
+ showMessage(msg.arg(m_tempCoreName));
+ m_tempCoreFile.setFileName(m_tempCoreName);
+ m_tempCoreFile.open(QFile::WriteOnly);
+ arguments << "-c" << "-d" << m_coreName;
+ m_coreUnpackProcess = new QProcess(this);
+ m_coreUnpackProcess->setWorkingDirectory(TemporaryDirectory::masterDirectoryPath());
+ m_coreUnpackProcess->start("gzip", arguments);
+ connect(m_coreUnpackProcess, &QProcess::readyRead, this, [this] {
+ m_tempCoreFile.write(m_coreUnpackProcess->readAll());
+ });
+ connect(m_coreUnpackProcess, static_cast<void (QProcess::*)(int)>(&QProcess::finished),
+ this, &GdbEngine::continueSetupEngine);
+ } else {
+ continueSetupEngine();
+ }
+}
+
+QString GdbEngine::coreFileName() const
+{
+ return m_tempCoreName.isEmpty() ? m_coreName : m_tempCoreName;
}
void GdbEngine::doUpdateLocals(const UpdateParameters &params)
@@ -4417,6 +5225,15 @@ QString GdbEngine::msgPtraceError(DebuggerStartMode sm)
"For more details, see /etc/sysctl.d/10-ptrace.conf\n");
}
+//
+// Factory
+//
+
+DebuggerEngine *createGdbEngine(bool useTerminal, DebuggerStartMode startMode)
+{
+ return new GdbEngine(useTerminal, startMode);
+}
+
} // namespace Internal
} // namespace Debugger
diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h
index 3a5a9d6645..01b1d86a49 100644
--- a/src/plugins/debugger/gdb/gdbengine.h
+++ b/src/plugins/debugger/gdb/gdbengine.h
@@ -33,64 +33,69 @@
#include <debugger/watchutils.h>
#include <debugger/debuggeritem.h>
#include <debugger/debuggertooltipmanager.h>
+#include <debugger/outputcollector.h>
#include <coreplugin/id.h>
#include <utils/qtcprocess.h>
+#include <utils/consoleprocess.h>
#include <QProcess>
#include <QTextCodec>
#include <QTimer>
-#include <functional>
-
namespace Debugger {
namespace Internal {
-class GdbProcess;
+class BreakpointParameters;
+class BreakpointResponse;
class DebugInfoTask;
class DebugInfoTaskHandler;
class DebuggerResponse;
+class DisassemblerAgentCookie;
class GdbMi;
class MemoryAgentCookie;
-class BreakpointParameters;
-class BreakpointResponse;
-class DisassemblerAgentCookie;
-class DisassemblerLines;
+struct CoreInfo
+{
+ QString rawStringFromCore;
+ QString foundExecutableName; // empty if no corresponding exec could be found
+ bool isCore = false;
+
+ static CoreInfo readExecutableNameFromCore(const ProjectExplorer::StandardRunnable &debugger,
+ const QString &coreFile);
+};
class GdbEngine : public DebuggerEngine
{
Q_OBJECT
public:
- explicit GdbEngine(bool useTerminal);
- ~GdbEngine() override;
+ explicit GdbEngine(bool useTerminal, DebuggerStartMode startMode);
+ ~GdbEngine() final;
private: ////////// General Interface //////////
- DebuggerEngine *cppEngine() override { return this; }
+ DebuggerEngine *cppEngine() final { return this; }
- virtual void handleGdbStartFailed();
- void notifyInferiorSetupFailed() override;
- void prepareForRestart() override;
+ void handleGdbStartFailed();
+ void notifyInferiorSetupFailed() final;
+ void prepareForRestart() final;
- bool hasCapability(unsigned) const override;
- void detachDebugger() override;
- void shutdownInferior() override;
- void abortDebugger() override;
- void resetInferior() override;
+ bool hasCapability(unsigned) const final;
+ void detachDebugger() final;
+ void shutdownInferior() final;
+ void abortDebugger() final;
+ void resetInferior() final;
- bool acceptsDebuggerCommands() const override;
- void executeDebuggerCommand(const QString &command, DebuggerLanguages languages) override;
+ bool acceptsDebuggerCommands() const final;
+ void executeDebuggerCommand(const QString &command, DebuggerLanguages languages) final;
-private: ////////// General State //////////
+ ////////// General State //////////
- DebuggerStartMode startMode() const;
- void reloadLocals();
-
- bool m_registerNamesListed;
+ const DebuggerStartMode m_startMode;
+ bool m_registerNamesListed = false;
-protected: ////////// Gdb Process Management //////////
+ ////////// Gdb Process Management //////////
void startGdb(const QStringList &args = QStringList());
void handleInferiorShutdown(const DebuggerResponse &response);
@@ -123,9 +128,6 @@ protected: ////////// Gdb Process Management //////////
// Make sure to clean up everything before emitting this signal.
void handleAdapterCrashed(const QString &msg);
-private:
- friend class GdbPlainEngine;
- friend class GdbCoreEngine;
void handleGdbFinished(int exitCode, QProcess::ExitStatus exitStatus);
void handleGdbError(QProcess::ProcessError error);
void readGdbStandardOutput();
@@ -138,17 +140,16 @@ private:
QTextCodec::ConverterState m_inferiorOutputCodecState;
QByteArray m_inbuffer;
- bool m_busy;
+ bool m_busy = false;
// Name of the convenience variable containing the last
// known function return value.
QString m_resultVarName;
-protected: ////////// Gdb Command Management //////////
+ ////////// Gdb Command Management //////////
- void runCommand(const DebuggerCommand &command) override;
+ void runCommand(const DebuggerCommand &command) final;
-private:
void commandTimeout();
void setTokenBarrier();
@@ -166,19 +167,19 @@ private:
// This contains the first token number for the current round
// of evaluation. Responses with older tokens are considers
// out of date and discarded.
- int m_oldestAcceptableToken;
- int m_nonDiscardableCount;
+ int m_oldestAcceptableToken = -1;
+ int m_nonDiscardableCount = 0;
- int m_pendingBreakpointRequests; // Watch updating commands in flight
+ int m_pendingBreakpointRequests = 0; // Watch updating commands in flight
typedef void (GdbEngine::*CommandsDoneCallback)();
// This function is called after all previous responses have been received.
- CommandsDoneCallback m_commandsDoneCallback;
+ CommandsDoneCallback m_commandsDoneCallback = nullptr;
+
+ bool m_rerunPending = false;
- bool m_rerunPending;
+ ////////// Gdb Output, State & Capability Handling //////////
-private: ////////// Gdb Output, State & Capability Handling //////////
-protected:
Q_INVOKABLE void handleResponse(const QString &buff);
void handleAsyncOutput(const QString &asyncClass, const GdbMi &result);
void handleStopResponse(const GdbMi &data);
@@ -188,42 +189,40 @@ protected:
void handleStop3();
void resetCommandQueue();
- bool isSynchronous() const override { return true; }
+ bool isSynchronous() const final { return true; }
// Gdb initialization sequence
void handleShowVersion(const DebuggerResponse &response);
void handleListFeatures(const DebuggerResponse &response);
void handlePythonSetup(const DebuggerResponse &response);
- int m_gdbVersion; // 7.6.1 is 70601
- int m_pythonVersion; // 2.7.2 is 20702
- bool m_isQnxGdb;
+ int m_gdbVersion = 100; // 7.6.1 is 70601
+ int m_pythonVersion = 0; // 2.7.2 is 20702
+ bool m_isQnxGdb = false;
-private: ////////// Inferior Management //////////
+ ////////// Inferior Management //////////
// This should be always the last call in a function.
- bool stateAcceptsBreakpointChanges() const override;
- bool acceptsBreakpoint(Breakpoint bp) const override;
- void insertBreakpoint(Breakpoint bp) override;
- void removeBreakpoint(Breakpoint bp) override;
- void changeBreakpoint(Breakpoint bp) override;
-
- void executeStep() override;
- void executeStepOut() override;
- void executeNext() override;
- void executeStepI() override;
- void executeNextI() override;
-
- protected:
+ bool stateAcceptsBreakpointChanges() const final;
+ bool acceptsBreakpoint(Breakpoint bp) const final;
+ void insertBreakpoint(Breakpoint bp) final;
+ void removeBreakpoint(Breakpoint bp) final;
+ void changeBreakpoint(Breakpoint bp) final;
+
+ void executeStep() final;
+ void executeStepOut() final;
+ void executeNext() final;
+ void executeStepI() final;
+ void executeNextI() final;
+
void continueInferiorInternal();
- void continueInferior() override;
- void interruptInferior() override;
- virtual void interruptInferior2() {}
+ void continueInferior() final;
+ void interruptInferior() final;
- void executeRunToLine(const ContextData &data) override;
- void executeRunToFunction(const QString &functionName) override;
- void executeJumpToLine(const ContextData &data) override;
- void executeReturn() override;
+ void executeRunToLine(const ContextData &data) final;
+ void executeRunToFunction(const QString &functionName) final;
+ void executeJumpToLine(const ContextData &data) final;
+ void executeReturn() final;
void handleExecuteContinue(const DebuggerResponse &response);
void handleExecuteStep(const DebuggerResponse &response);
@@ -234,10 +233,10 @@ private: ////////// Inferior Management //////////
QString msgPtraceError(DebuggerStartMode sm);
-private: ////////// View & Data Stuff //////////
+ ////////// View & Data Stuff //////////
- void selectThread(ThreadId threadId) override;
- void activateFrame(int index) override;
+ void selectThread(ThreadId threadId) final;
+ void activateFrame(int index) final;
void handleAutoContinueInferior();
//
@@ -265,14 +264,13 @@ private: ////////// View & Data Stuff //////////
//
// Modules specific stuff
//
- protected:
- void loadSymbols(const QString &moduleName) override;
- void loadAllSymbols() override;
- void loadSymbolsForStack() override;
- void requestModuleSymbols(const QString &moduleName) override;
- void requestModuleSections(const QString &moduleName) override;
- void reloadModules() override;
- void examineModules() override;
+ void loadSymbols(const QString &moduleName) final;
+ void loadAllSymbols() final;
+ void loadSymbolsForStack() final;
+ void requestModuleSymbols(const QString &moduleName) final;
+ void requestModuleSections(const QString &moduleName) final;
+ void reloadModules() final;
+ void examineModules() final;
void reloadModulesInternal();
void handleModulesList(const DebuggerResponse &response);
@@ -281,14 +279,14 @@ private: ////////// View & Data Stuff //////////
//
// Snapshot specific stuff
//
- virtual void createSnapshot() override;
+ void createSnapshot() final;
void handleMakeSnapshot(const DebuggerResponse &response, const QString &coreFile);
//
// Register specific stuff
//
- void reloadRegisters() override;
- void setRegisterValue(const QString &name, const QString &value) override;
+ void reloadRegisters() final;
+ void setRegisterValue(const QString &name, const QString &value) final;
void handleRegisterListNames(const DebuggerResponse &response);
void handleRegisterListing(const DebuggerResponse &response);
void handleRegisterListValues(const DebuggerResponse &response);
@@ -299,7 +297,7 @@ private: ////////// View & Data Stuff //////////
// Disassembler specific stuff
//
// Chain of fallbacks: PointMixed -> PointPlain -> RangeMixed -> RangePlain.
- void fetchDisassembler(DisassemblerAgent *agent) override;
+ void fetchDisassembler(DisassemblerAgent *agent) final;
void fetchDisassemblerByCliPointMixed(const DisassemblerAgentCookie &ac);
void fetchDisassemblerByCliRangeMixed(const DisassemblerAgentCookie &ac);
void fetchDisassemblerByCliRangePlain(const DisassemblerAgentCookie &ac);
@@ -308,7 +306,7 @@ private: ////////// View & Data Stuff //////////
//
// Source file specific stuff
//
- void reloadSourceFiles() override;
+ void reloadSourceFiles() final;
void reloadSourceFilesInternal();
void handleQuerySources(const DebuggerResponse &response);
@@ -320,13 +318,12 @@ private: ////////// View & Data Stuff //////////
QMap<QString, QString> m_fullToShortName;
QMultiMap<QString, QString> m_baseNameToFullName;
- bool m_sourcesListUpdating;
+ bool m_sourcesListUpdating = false;
//
// Stack specific stuff
//
-protected:
- void updateAll() override;
+ void updateAll() final;
void handleStackListFrames(const DebuggerResponse &response, bool isFull);
void handleStackSelectThread(const DebuggerResponse &response);
void handleThreadListIds(const DebuggerResponse &response);
@@ -334,20 +331,21 @@ protected:
void handleThreadNames(const DebuggerResponse &response);
DebuggerCommand stackCommand(int depth);
void reloadStack();
- void reloadFullStack() override;
- void loadAdditionalQmlStack() override;
+ void reloadFullStack() final;
+ void loadAdditionalQmlStack() final;
int currentFrame() const;
//
// Watch specific stuff
//
- virtual void assignValueInDebugger(WatchItem *item,
- const QString &expr, const QVariant &value) override;
+ void reloadLocals();
+ void assignValueInDebugger(WatchItem *item,
+ const QString &expr, const QVariant &value) final;
- void fetchMemory(MemoryAgent *agent, quint64 addr, quint64 length) override;
+ void fetchMemory(MemoryAgent *agent, quint64 addr, quint64 length) final;
void fetchMemoryHelper(const MemoryAgentCookie &cookie);
void handleChangeMemory(const DebuggerResponse &response);
- void changeMemory(MemoryAgent *agent, quint64 addr, const QByteArray &data) override;
+ void changeMemory(MemoryAgent *agent, quint64 addr, const QByteArray &data) final;
void handleFetchMemory(const DebuggerResponse &response, MemoryAgentCookie ac);
void showToolTip();
@@ -358,7 +356,7 @@ protected:
void createFullBacktrace();
- void doUpdateLocals(const UpdateParameters &parameters) override;
+ void doUpdateLocals(const UpdateParameters &parameters) final;
void handleFetchVariables(const DebuggerResponse &response);
void setLocals(const QList<GdbMi> &locals);
@@ -366,7 +364,7 @@ protected:
//
// Dumper Management
//
- void reloadDebuggingHelpers() override;
+ void reloadDebuggingHelpers() final;
//
// Convenience Functions
@@ -374,19 +372,18 @@ protected:
void showExecutionError(const QString &message);
QString failedToStartMessage();
- static QString tooltipIName(const QString &exp);
-
// For short-circuiting stack and thread list evaluation.
- bool m_stackNeeded;
+ bool m_stackNeeded = false;
// For suppressing processing *stopped and *running responses
// while updating locals.
- bool m_inUpdateLocals;
+ bool m_inUpdateLocals = false;
// HACK:
QString m_currentThread;
QString m_lastWinException;
QString m_lastMissingDebugInfo;
+ const bool m_useTerminal;
bool m_terminalTrap;
bool usesExecInterrupt() const;
bool usesTargetAsync() const;
@@ -401,7 +398,7 @@ protected:
void requestDebugInformation(const DebugInfoTask &task);
DebugInfoTaskHandler *m_debugInfoTaskHandler;
- bool m_systemDumpersLoaded;
+ bool m_systemDumpersLoaded = false;
static QString msgGdbStopFailed(const QString &why);
static QString msgInferiorStopFailed(const QString &why);
@@ -410,14 +407,63 @@ protected:
static QString msgInferiorRunOk();
static QString msgConnectRemoteServerFailed(const QString &why);
- void debugLastCommand() override;
+ void debugLastCommand() final;
DebuggerCommand m_lastDebuggableCommand;
-protected:
+ bool isPlainEngine() const;
+ bool isCoreEngine() const;
+ bool isRemoteEngine() const;
+ bool isAttachEngine() const;
+ bool isTermEngine() const;
+
+ void setupEngine() final;
+ void setupInferior() final;
+ void runEngine() final;
+ void shutdownEngine() final;
+
+ void interruptInferior2();
+
+ // Plain
+ void handleExecRun(const DebuggerResponse &response);
+ void handleFileExecAndSymbols(const DebuggerResponse &response);
+
+ // Attach
+ void handleAttach(const DebuggerResponse &response);
+
+ // Remote
+ void callTargetRemote();
+ void handleSetTargetAsync(const DebuggerResponse &response);
+ void handleTargetRemote(const DebuggerResponse &response);
+ void handleTargetExtendedRemote(const DebuggerResponse &response);
+ void handleTargetExtendedAttach(const DebuggerResponse &response);
+ void handleTargetQnx(const DebuggerResponse &response);
+ void handleSetNtoExecutable(const DebuggerResponse &response);
+ void handleInterruptInferior(const DebuggerResponse &response);
void interruptLocalInferior(qint64 pid);
-protected:
+ // Terminal
+ void handleStubAttached(const DebuggerResponse &response);
+ void stubExited();
+ void stubError(const QString &msg);
+ Utils::ConsoleProcess m_stubProc;
+
+ // Core
+ void handleTargetCore(const DebuggerResponse &response);
+ void handleCoreRoundTrip(const DebuggerResponse &response);
+ void unpackCoreIfNeeded();
+ QString coreFileName() const;
+ QString coreName() const;
+
+ void continueSetupEngine();
+
+ QString m_executable;
+ QString m_coreName;
+ QString m_tempCoreName;
+ QProcess *m_coreUnpackProcess = nullptr;
+ QFile m_tempCoreFile;
+
Utils::QtcProcess m_gdbProc;
+ OutputCollector m_outputCollector;
QString m_errorString;
};
diff --git a/src/plugins/debugger/gdb/gdbplainengine.cpp b/src/plugins/debugger/gdb/gdbplainengine.cpp
deleted file mode 100644
index a1b5bf7ed4..0000000000
--- a/src/plugins/debugger/gdb/gdbplainengine.cpp
+++ /dev/null
@@ -1,145 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "gdbplainengine.h"
-
-#include <debugger/debuggeractions.h>
-#include <debugger/debuggercore.h>
-#include <debugger/debuggerprotocol.h>
-#include <debugger/debuggerstartparameters.h>
-
-#include <utils/hostosinfo.h>
-#include <utils/qtcassert.h>
-
-#include <QFileInfo>
-
-namespace Debugger {
-namespace Internal {
-
-#define CB(callback) [this](const DebuggerResponse &r) { callback(r); }
-
-GdbPlainEngine::GdbPlainEngine(bool useTerminal)
- : GdbEngine(useTerminal)
-{
- // Output
- connect(&m_outputCollector, &OutputCollector::byteDelivery,
- this, &GdbEngine::readDebuggeeOutput);
-}
-
-void GdbPlainEngine::setupInferior()
-{
- QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
- setEnvironmentVariables();
- const DebuggerRunParameters &rp = runParameters();
- if (!rp.inferior.workingDirectory.isEmpty())
- runCommand({"cd " + rp.inferior.workingDirectory});
- if (!rp.inferior.commandLineArguments.isEmpty()) {
- QString args = rp.inferior.commandLineArguments;
- runCommand({"-exec-arguments " + args});
- }
-
- QString executable = QFileInfo(runParameters().inferior.executable).absoluteFilePath();
- runCommand({"-file-exec-and-symbols \"" + executable + '"',
- CB(handleFileExecAndSymbols)});
-}
-
-void GdbPlainEngine::handleFileExecAndSymbols(const DebuggerResponse &response)
-{
- QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
- if (response.resultClass == ResultDone) {
- handleInferiorPrepared();
- } else {
- QString msg = response.data["msg"].data();
- // Extend the message a bit in unknown cases.
- if (!msg.endsWith("File format not recognized"))
- msg = tr("Starting executable failed:") + '\n' + msg;
- notifyInferiorSetupFailed(msg);
- }
-}
-
-void GdbPlainEngine::runEngine()
-{
- if (runParameters().useContinueInsteadOfRun)
- runCommand({"-exec-continue", DebuggerCommand::RunRequest, CB(handleExecuteContinue)});
- else
- runCommand({"-exec-run", DebuggerCommand::RunRequest, CB(handleExecRun)});
-}
-
-void GdbPlainEngine::handleExecRun(const DebuggerResponse &response)
-{
- QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
- if (response.resultClass == ResultRunning) {
- notifyEngineRunAndInferiorRunOk(); // For gdb < 7.0
- //showStatusMessage(tr("Running..."));
- showMessage("INFERIOR STARTED");
- showMessage(msgInferiorSetupOk(), StatusBar);
- // FIXME: That's the wrong place for it.
- if (boolSetting(EnableReverseDebugging))
- runCommand({"target record"});
- } else {
- QString msg = response.data["msg"].data();
- //QTC_CHECK(status() == InferiorRunOk);
- //interruptInferior();
- showMessage(msg);
- notifyEngineRunFailed();
- }
-}
-
-void GdbPlainEngine::setupEngine()
-{
- QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
- showMessage("TRYING TO START ADAPTER");
-
- QStringList gdbArgs;
-
- if (!m_outputCollector.listen()) {
- handleAdapterStartFailed(tr("Cannot set up communication with child process: %1")
- .arg(m_outputCollector.errorString()));
- return;
- }
- gdbArgs.append("--tty=" + m_outputCollector.serverName());
-
- startGdb(gdbArgs);
-}
-
-void GdbPlainEngine::handleGdbStartFailed()
-{
- m_outputCollector.shutdown();
-}
-
-void GdbPlainEngine::interruptInferior2()
-{
- interruptLocalInferior(inferiorPid());
-}
-
-void GdbPlainEngine::shutdownEngine()
-{
- showMessage(QString("PLAIN ADAPTER SHUTDOWN %1").arg(state()));
- m_outputCollector.shutdown();
- notifyAdapterShutdownOk();
-}
-
-} // namespace Debugger
-} // namespace Internal
diff --git a/src/plugins/debugger/gdb/gdbplainengine.h b/src/plugins/debugger/gdb/gdbplainengine.h
deleted file mode 100644
index a2f6e04a6b..0000000000
--- a/src/plugins/debugger/gdb/gdbplainengine.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "gdbengine.h"
-#include <debugger/outputcollector.h>
-
-namespace Debugger {
-namespace Internal {
-
-class GdbPlainEngine : public GdbEngine
-{
- // Needs tr - Context
- Q_OBJECT
-
-public:
- explicit GdbPlainEngine(bool useTerminal);
-
-private:
- void handleExecRun(const DebuggerResponse &response);
- void handleFileExecAndSymbols(const DebuggerResponse &response);
-
- void setupInferior() override;
- void runEngine() override;
- void setupEngine() override;
- void handleGdbStartFailed() override;
- void interruptInferior2() override;
- void shutdownEngine() override;
-
- OutputCollector m_outputCollector;
-};
-
-} // namespace Debugger
-} // namespace Internal
diff --git a/src/plugins/debugger/gdb/remotegdbserveradapter.cpp b/src/plugins/debugger/gdb/remotegdbserveradapter.cpp
deleted file mode 100644
index 5184e4b7c4..0000000000
--- a/src/plugins/debugger/gdb/remotegdbserveradapter.cpp
+++ /dev/null
@@ -1,375 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "remotegdbserveradapter.h"
-
-#include <debugger/debuggeractions.h>
-#include <debugger/debuggercore.h>
-#include <debugger/debuggerprotocol.h>
-#include <debugger/debuggerruncontrol.h>
-#include <debugger/procinterrupt.h>
-
-#include <utils/hostosinfo.h>
-#include <utils/qtcfallthrough.h>
-#include <utils/qtcassert.h>
-#include <utils/qtcprocess.h>
-
-#include <QAbstractButton>
-#include <QFileInfo>
-#include <QMessageBox>
-
-using namespace Utils;
-
-namespace Debugger {
-namespace Internal {
-
-#define CB(callback) [this](const DebuggerResponse &r) { callback(r); }
-
-///////////////////////////////////////////////////////////////////////
-//
-// RemoteGdbAdapter
-//
-///////////////////////////////////////////////////////////////////////
-
-GdbRemoteServerEngine::GdbRemoteServerEngine(bool useTerminal)
- : GdbEngine(useTerminal)
-{
-}
-
-void GdbRemoteServerEngine::setupEngine()
-{
- if (HostOsInfo::isWindowsHost())
- m_gdbProc.setUseCtrlCStub(runParameters().useCtrlCStub); // This is only set for QNX
-
- QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
- showMessage("TRYING TO START ADAPTER");
-
- startGdb();
-}
-
-void GdbRemoteServerEngine::setupInferior()
-{
- QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
- setLinuxOsAbi();
- const DebuggerRunParameters &rp = runParameters();
- QString symbolFile;
- if (!rp.symbolFile.isEmpty()) {
- QFileInfo fi(rp.symbolFile);
- symbolFile = fi.absoluteFilePath();
- }
-
- //const QByteArray sysroot = sp.sysroot.toLocal8Bit();
- //const QByteArray remoteArch = sp.remoteArchitecture.toLatin1();
- const QString args = runParameters().inferior.commandLineArguments;
-
-// if (!remoteArch.isEmpty())
-// postCommand("set architecture " + remoteArch);
- const QString solibSearchPath = rp.solibSearchPath.join(HostOsInfo::pathListSeparator());
- if (!solibSearchPath.isEmpty())
- runCommand({"set solib-search-path " + solibSearchPath});
-
- if (!args.isEmpty())
- runCommand({"-exec-arguments " + args});
-
- setEnvironmentVariables();
-
- // This has to be issued before 'target remote'. On pre-7.0 the
- // command is not present and will result in ' No symbol table is
- // loaded. Use the "file" command.' as gdb tries to set the
- // value of a variable with name 'target-async'.
- //
- // Testing with -list-target-features which was introduced at
- // the same time would not work either, as this need an existing
- // target.
- //
- // Using it even without a target and having it fail might still
- // be better as:
- // Some external comment: '[but] "set target-async on" with a native
- // windows gdb will work, but then fail when you actually do
- // "run"/"attach", I think..
-
-
- // gdb/mi/mi-main.c:1958: internal-error:
- // mi_execute_async_cli_command: Assertion `is_running (inferior_ptid)'
- // failed.\nA problem internal to GDB has been detected,[...]
- if (usesTargetAsync())
- runCommand({"set target-async on", CB(handleSetTargetAsync)});
-
- if (symbolFile.isEmpty()) {
- showMessage(tr("No symbol file given."), StatusBar);
- callTargetRemote();
- return;
- }
-
- if (!symbolFile.isEmpty()) {
- runCommand({"-file-exec-and-symbols \"" + symbolFile + '"',
- CB(handleFileExecAndSymbols)});
- }
-}
-
-void GdbRemoteServerEngine::handleSetTargetAsync(const DebuggerResponse &response)
-{
- QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
- if (response.resultClass == ResultError)
- qDebug() << "Adapter too old: does not support asynchronous mode.";
-}
-
-void GdbRemoteServerEngine::handleFileExecAndSymbols(const DebuggerResponse &response)
-{
- QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
- if (response.resultClass == ResultDone) {
- callTargetRemote();
- } else {
- QString reason = response.data["msg"].data();
- QString msg = tr("Reading debug information failed:") + '\n' + reason;
- if (reason.endsWith("No such file or directory.")) {
- showMessage("INFERIOR STARTUP: BINARY NOT FOUND");
- showMessage(msg, StatusBar);
- callTargetRemote(); // Proceed nevertheless.
- } else {
- notifyInferiorSetupFailed(msg);
- }
- }
-}
-
-void GdbRemoteServerEngine::callTargetRemote()
-{
- QString channel = runParameters().remoteChannel;
-
- // Don't touch channels with explicitly set protocols.
- if (!channel.startsWith("tcp:") && !channel.startsWith("udp:")
- && !channel.startsWith("file:") && channel.contains(':')
- && !channel.startsWith('|'))
- {
- // "Fix" the IPv6 case with host names without '['...']'
- if (!channel.startsWith('[') && channel.count(':') >= 2) {
- channel.insert(0, '[');
- channel.insert(channel.lastIndexOf(':'), ']');
- }
- channel = "tcp:" + channel;
- }
-
- if (m_isQnxGdb)
- runCommand({"target qnx " + channel, CB(handleTargetQnx)});
- else if (runParameters().useExtendedRemote)
- runCommand({"target extended-remote " + channel, CB(handleTargetExtendedRemote)});
- else
- runCommand({"target remote " + channel, CB(handleTargetRemote)});
-}
-
-void GdbRemoteServerEngine::handleTargetRemote(const DebuggerResponse &response)
-{
- QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
- if (response.resultClass == ResultDone) {
- // gdb server will stop the remote application itself.
- showMessage("INFERIOR STARTED");
- showMessage(msgAttachedToStoppedInferior(), StatusBar);
- QString commands = expand(stringSetting(GdbPostAttachCommands));
- if (!commands.isEmpty())
- runCommand({commands, NativeCommand});
- handleInferiorPrepared();
- } else {
- // 16^error,msg="hd:5555: Connection timed out."
- notifyInferiorSetupFailed(msgConnectRemoteServerFailed(response.data["msg"].data()));
- }
-}
-
-void GdbRemoteServerEngine::handleTargetExtendedRemote(const DebuggerResponse &response)
-{
- QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
- if (response.resultClass == ResultDone) {
- showMessage("ATTACHED TO GDB SERVER STARTED");
- showMessage(msgAttachedToStoppedInferior(), StatusBar);
- QString commands = expand(stringSetting(GdbPostAttachCommands));
- if (!commands.isEmpty())
- runCommand({commands, NativeCommand});
- if (runParameters().attachPID.isValid()) { // attach to pid if valid
- // gdb server will stop the remote application itself.
- runCommand({"attach " + QString::number(runParameters().attachPID.pid()),
- CB(handleTargetExtendedAttach)});
- } else if (!runParameters().inferior.executable.isEmpty()) {
- runCommand({"-gdb-set remote exec-file " + runParameters().inferior.executable,
- CB(handleTargetExtendedAttach)});
- } else {
- const QString title = tr("No Remote Executable or Process ID Specified");
- const QString msg = tr(
- "No remote executable could be determined from your build system files.<p>"
- "In case you use qmake, consider adding<p>"
- "&nbsp;&nbsp;&nbsp;&nbsp;target.path = /tmp/your_executable # path on device<br>"
- "&nbsp;&nbsp;&nbsp;&nbsp;INSTALLS += target</p>"
- "to your .pro file.");
- QMessageBox *mb = showMessageBox(QMessageBox::Critical, title, msg,
- QMessageBox::Ok | QMessageBox::Cancel);
- mb->button(QMessageBox::Cancel)->setText(tr("Continue Debugging"));
- mb->button(QMessageBox::Ok)->setText(tr("Stop Debugging"));
- if (mb->exec() == QMessageBox::Ok) {
- showMessage("KILLING DEBUGGER AS REQUESTED BY USER");
- notifyInferiorSetupFailed(title);
- } else {
- showMessage("CONTINUE DEBUGGER AS REQUESTED BY USER");
- handleInferiorPrepared(); // This will likely fail.
- }
- }
- } else {
- notifyInferiorSetupFailed(msgConnectRemoteServerFailed(response.data["msg"].data()));
- }
-}
-
-void GdbRemoteServerEngine::handleTargetExtendedAttach(const DebuggerResponse &response)
-{
- QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
- if (response.resultClass == ResultDone) {
- // gdb server will stop the remote application itself.
- handleInferiorPrepared();
- } else {
- notifyInferiorSetupFailed(msgConnectRemoteServerFailed(response.data["msg"].data()));
- }
-}
-
-void GdbRemoteServerEngine::handleTargetQnx(const DebuggerResponse &response)
-{
- QTC_ASSERT(m_isQnxGdb, qDebug() << m_isQnxGdb);
- QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
- if (response.resultClass == ResultDone) {
- // gdb server will stop the remote application itself.
- showMessage("INFERIOR STARTED");
- showMessage(msgAttachedToStoppedInferior(), StatusBar);
-
- const DebuggerRunParameters &rp = isMasterEngine() ? runParameters() : masterEngine()->runParameters();
- const QString remoteExecutable = rp.inferior.executable;
- if (rp.attachPID.isValid())
- runCommand({"attach " + QString::number(rp.attachPID.pid()), CB(handleAttach)});
- else if (!remoteExecutable.isEmpty())
- runCommand({"set nto-executable " + remoteExecutable, CB(handleSetNtoExecutable)});
- else
- handleInferiorPrepared();
- } else {
- // 16^error,msg="hd:5555: Connection timed out."
- notifyInferiorSetupFailed(response.data["msg"].data());
- }
-}
-
-void GdbRemoteServerEngine::handleAttach(const DebuggerResponse &response)
-{
- QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
- switch (response.resultClass) {
- case ResultDone:
- case ResultRunning: {
- showMessage("INFERIOR ATTACHED");
- showMessage(msgAttachedToStoppedInferior(), StatusBar);
- handleInferiorPrepared();
- break;
- }
- case ResultError:
- if (response.data["msg"].data() == "ptrace: Operation not permitted.") {
- notifyInferiorSetupFailed(msgPtraceError(runParameters().startMode));
- break;
- }
- Q_FALLTHROUGH(); // if msg != "ptrace: ..."
- default:
- notifyInferiorSetupFailed(response.data["msg"].data());
- }
-}
-
-void GdbRemoteServerEngine::handleSetNtoExecutable(const DebuggerResponse &response)
-{
- QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
- switch (response.resultClass) {
- case ResultDone:
- case ResultRunning: {
- showMessage("EXECUTABLE SET");
- showMessage(msgAttachedToStoppedInferior(), StatusBar);
- handleInferiorPrepared();
- break;
- }
- case ResultError:
- default:
- notifyInferiorSetupFailed(response.data["msg"].data());
- }
-}
-
-void GdbRemoteServerEngine::runEngine()
-{
- QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
-
- if (runParameters().useContinueInsteadOfRun) {
- notifyEngineRunAndInferiorStopOk();
- continueInferiorInternal();
- } else {
- runCommand({"-exec-run", DebuggerCommand::RunRequest, CB(handleExecRun)});
- }
-}
-
-void GdbRemoteServerEngine::handleExecRun(const DebuggerResponse &response)
-{
- QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
- if (response.resultClass == ResultRunning) {
- notifyEngineRunAndInferiorRunOk();
- showMessage("INFERIOR STARTED");
- showMessage(msgInferiorSetupOk(), StatusBar);
- } else {
- showMessage(response.data["msg"].data());
- notifyEngineRunFailed();
- }
-}
-
-void GdbRemoteServerEngine::interruptInferior2()
-{
- QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state());
- if (usesTargetAsync()) {
- runCommand({"-exec-interrupt", CB(handleInterruptInferior)});
- } else if (m_isQnxGdb && HostOsInfo::isWindowsHost()) {
- m_gdbProc.interrupt();
- } else {
- qint64 pid = m_gdbProc.processId();
- bool ok = interruptProcess(pid, GdbEngineType, &m_errorString);
- if (!ok) {
- // FIXME: Extra state needed?
- showMessage("NOTE: INFERIOR STOP NOT POSSIBLE");
- showStatusMessage(tr("Interrupting not possible"));
- notifyInferiorRunOk();
- }
- }
-}
-
-void GdbRemoteServerEngine::handleInterruptInferior(const DebuggerResponse &response)
-{
- if (response.resultClass == ResultDone) {
- // The gdb server will trigger extra output that we will pick up
- // to do a proper state transition.
- } else {
- // FIXME: On some gdb versions like git 170ffa5d7dd this produces
- // >810^error,msg="mi_cmd_exec_interrupt: Inferior not executing."
- notifyInferiorStopOk();
- }
-}
-
-void GdbRemoteServerEngine::shutdownEngine()
-{
- notifyAdapterShutdownOk();
-}
-
-} // namespace Internal
-} // namespace Debugger
diff --git a/src/plugins/debugger/gdb/remotegdbserveradapter.h b/src/plugins/debugger/gdb/remotegdbserveradapter.h
deleted file mode 100644
index a72c3814f7..0000000000
--- a/src/plugins/debugger/gdb/remotegdbserveradapter.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "gdbengine.h"
-
-namespace Debugger {
-namespace Internal {
-
-class GdbRemoteServerEngine : public GdbEngine
-{
- Q_OBJECT
-
-public:
- explicit GdbRemoteServerEngine(bool useTerminal);
-
-private:
- void setupEngine() override;
- void setupInferior() override;
- void runEngine() override;
- void interruptInferior2() override;
- void shutdownEngine() override;
-
- void callTargetRemote();
-
- void handleSetTargetAsync(const DebuggerResponse &response);
- void handleFileExecAndSymbols(const DebuggerResponse &response);
- void handleTargetRemote(const DebuggerResponse &response);
- void handleTargetExtendedRemote(const DebuggerResponse &response);
- void handleTargetExtendedAttach(const DebuggerResponse &response);
- void handleTargetQnx(const DebuggerResponse &response);
- void handleAttach(const DebuggerResponse &response);
- void handleSetNtoExecutable(const DebuggerResponse &response);
- void handleInterruptInferior(const DebuggerResponse &response);
- void handleExecRun(const DebuggerResponse &response);
-};
-
-} // namespace Internal
-} // namespace Debugger
diff --git a/src/plugins/debugger/gdb/termgdbadapter.cpp b/src/plugins/debugger/gdb/termgdbadapter.cpp
deleted file mode 100644
index 33a1390b02..0000000000
--- a/src/plugins/debugger/gdb/termgdbadapter.cpp
+++ /dev/null
@@ -1,205 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "termgdbadapter.h"
-
-#include <debugger/debuggercore.h>
-#include <debugger/debuggerprotocol.h>
-#include <debugger/debuggerstartparameters.h>
-#include <debugger/shared/hostutils.h>
-
-#include <utils/hostosinfo.h>
-#include <utils/qtcassert.h>
-#include <coreplugin/icore.h>
-#include <coreplugin/messagebox.h>
-
-using namespace Utils;
-
-namespace Debugger {
-namespace Internal {
-
-///////////////////////////////////////////////////////////////////////
-//
-// TermGdbAdapter
-//
-///////////////////////////////////////////////////////////////////////
-
-GdbTermEngine::GdbTermEngine(bool useTerminal)
- : GdbEngine(useTerminal)
-{
- 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());
- }
-}
-
-GdbTermEngine::~GdbTermEngine()
-{
- m_stubProc.disconnect(); // Avoid spurious state transitions from late exiting stub
-}
-
-void GdbTermEngine::setupEngine()
-{
- 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, &GdbTermEngine::stubError);
- connect(&m_stubProc, &ConsoleProcess::processStarted,
- this, &GdbTermEngine::stubStarted);
- connect(&m_stubProc, &ConsoleProcess::stubStopped,
- this, &GdbTermEngine::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());
- return;
- }
-}
-
-void GdbTermEngine::stubStarted()
-{
- startGdb();
-}
-
-void GdbTermEngine::handleGdbStartFailed()
-{
- m_stubProc.stop();
-}
-
-void GdbTermEngine::setupInferior()
-{
- QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
- const qint64 attachedPID = m_stubProc.applicationPID();
- const qint64 attachedMainThreadID = m_stubProc.applicationMainThreadID();
- notifyInferiorPid(ProcessHandle(attachedPID));
- const QString msg = (attachedMainThreadID != -1)
- ? QString("Going to attach to %1 (%2)").arg(attachedPID).arg(attachedMainThreadID)
- : QString("Going to attach to %1").arg(attachedPID);
- showMessage(msg, LogMisc);
- handleInferiorPrepared();
-}
-
-void GdbTermEngine::runEngine()
-{
- QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
- const qint64 attachedPID = m_stubProc.applicationPID();
- runCommand({"attach " + QString::number(attachedPID),
- [this](const DebuggerResponse &r) { handleStubAttached(r); }});
-}
-
-void GdbTermEngine::handleStubAttached(const DebuggerResponse &response)
-{
- // InferiorStopOk can happen if the "*stopped" in response to the
- // 'attach' comes in before its '^done'
- QTC_ASSERT(state() == EngineRunRequested || state() == InferiorStopOk,
- qDebug() << state());
-
- switch (response.resultClass) {
- case ResultDone:
- case ResultRunning:
- 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);
- } else {
- showMessage(QString("Inferior attached, unable to resume thread %1: %2").
- arg(mainThreadId).arg(errorMessage),
- LogWarning);
- }
- notifyEngineRunAndInferiorStopOk();
- continueInferiorInternal();
- } else {
- showMessage("INFERIOR ATTACHED AND RUNNING");
- //notifyEngineRunAndInferiorRunOk();
- // Wait for the upcoming *stopped and handle it there.
- }
- break;
- case ResultError:
- if (response.data["msg"].data() == "ptrace: Operation not permitted.") {
- showMessage(msgPtraceError(runParameters().startMode));
- notifyEngineRunFailed();
- break;
- }
- showMessage(response.data["msg"].data());
- notifyEngineIll();
- break;
- default:
- showMessage(QString("Invalid response %1").arg(response.resultClass));
- notifyEngineIll();
- break;
- }
-}
-
-void GdbTermEngine::interruptInferior2()
-{
- interruptLocalInferior(inferiorPid());
-}
-
-void GdbTermEngine::stubError(const QString &msg)
-{
- Core::AsynchronousMessageBox::critical(tr("Debugger Error"), msg);
- notifyEngineIll();
-}
-
-void GdbTermEngine::stubExited()
-{
- if (state() == EngineShutdownRequested || state() == DebuggerFinished) {
- showMessage("STUB EXITED EXPECTEDLY");
- return;
- }
- showMessage("STUB EXITED");
- notifyEngineIll();
-}
-
-void GdbTermEngine::shutdownEngine()
-{
- notifyAdapterShutdownOk();
-}
-
-} // namespace Internal
-} // namespace Debugger
diff --git a/src/plugins/debugger/gdb/termgdbadapter.h b/src/plugins/debugger/gdb/termgdbadapter.h
deleted file mode 100644
index 73a2413637..0000000000
--- a/src/plugins/debugger/gdb/termgdbadapter.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "gdbengine.h"
-
-#include <utils/consoleprocess.h>
-
-namespace Debugger {
-namespace Internal {
-
-///////////////////////////////////////////////////////////////////////
-//
-// TermGdbAdapter
-//
-///////////////////////////////////////////////////////////////////////
-
-class GdbTermEngine : public GdbEngine
-{
- Q_OBJECT
-
-public:
- explicit GdbTermEngine(bool useTerminal);
- ~GdbTermEngine() override;
-
-private:
- void setupEngine() override;
- void handleGdbStartFailed() override;
- void setupInferior() override;
- void runEngine() override;
- void interruptInferior2() override;
- void shutdownEngine() override;
-
- void handleStubAttached(const DebuggerResponse &response);
-
- void stubStarted();
- void stubExited();
- void stubError(const QString &msg);
-
- Utils::ConsoleProcess m_stubProc;
-};
-
-} // namespace Internal
-} // namespace Debugger
diff --git a/src/plugins/debugger/loadcoredialog.cpp b/src/plugins/debugger/loadcoredialog.cpp
index d0e8d87636..cb0fb49cee 100644
--- a/src/plugins/debugger/loadcoredialog.cpp
+++ b/src/plugins/debugger/loadcoredialog.cpp
@@ -28,7 +28,7 @@
#include "debuggerstartparameters.h"
#include "debuggerdialogs.h"
#include "debuggerkitinformation.h"
-#include "gdb/coregdbadapter.h"
+#include "gdb/gdbengine.h"
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/projectexplorerconstants.h>
@@ -364,7 +364,7 @@ void AttachCoreDialog::coreFileChanged(const QString &core)
Kit *k = d->kitChooser->currentKit();
QTC_ASSERT(k, return);
StandardRunnable debugger = DebuggerKitInformation::runnable(k);
- GdbCoreEngine::CoreInfo cinfo = GdbCoreEngine::readExecutableNameFromCore(debugger, core);
+ CoreInfo cinfo = CoreInfo::readExecutableNameFromCore(debugger, core);
if (!cinfo.foundExecutableName.isEmpty())
d->localExecFileName->setFileName(FileName::fromString(cinfo.foundExecutableName));
else if (!d->localExecFileName->isValid() && !cinfo.rawStringFromCore.isEmpty())