forked from qt-creator/qt-creator
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>
This commit is contained in:
@@ -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"
|
||||
]
|
||||
}
|
||||
|
||||
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -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();
|
||||
const DebuggerStartMode m_startMode;
|
||||
bool m_registerNamesListed = false;
|
||||
|
||||
bool m_registerNamesListed;
|
||||
|
||||
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;
|
||||
bool m_rerunPending = false;
|
||||
|
||||
////////// 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;
|
||||
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() override;
|
||||
void executeStepOut() override;
|
||||
void executeNext() override;
|
||||
void executeStepI() override;
|
||||
void executeNextI() override;
|
||||
void executeStep() final;
|
||||
void executeStepOut() final;
|
||||
void executeNext() final;
|
||||
void executeStepI() final;
|
||||
void executeNextI() final;
|
||||
|
||||
protected:
|
||||
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 ¶meters) override;
|
||||
void doUpdateLocals(const UpdateParameters ¶meters) 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;
|
||||
};
|
||||
|
||||
|
@@ -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
|
@@ -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
|
@@ -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>"
|
||||
" target.path = /tmp/your_executable # path on device<br>"
|
||||
" 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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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())
|
||||
|
Reference in New Issue
Block a user