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:
hjk
2017-09-08 08:53:15 +02:00
parent 991663d13b
commit f84d44e4e8
15 changed files with 1033 additions and 1677 deletions

View File

@@ -109,14 +109,9 @@ Project {
name: "gdb" name: "gdb"
prefix: "gdb/" prefix: "gdb/"
files: [ files: [
"attachgdbadapter.cpp", "attachgdbadapter.h",
"coregdbadapter.cpp", "coregdbadapter.h",
"gdbengine.cpp", "gdbengine.h", "gdbengine.cpp", "gdbengine.h",
"gdboptionspage.cpp", "gdboptionspage.cpp",
"gdbplainengine.cpp", "gdbplainengine.h",
"remotegdbserveradapter.cpp", "remotegdbserveradapter.h",
"startgdbserverdialog.cpp", "startgdbserverdialog.h", "startgdbserverdialog.cpp", "startgdbserverdialog.h",
"termgdbadapter.cpp", "termgdbadapter.h"
] ]
} }

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -1,18 +1,8 @@
HEADERS += \ HEADERS += \
$$PWD/gdbengine.h \ $$PWD/gdbengine.h \
$$PWD/attachgdbadapter.h \
$$PWD/coregdbadapter.h \
$$PWD/termgdbadapter.h \
$$PWD/remotegdbserveradapter.h \
$$PWD/gdbplainengine.h \
$$PWD/startgdbserverdialog.h $$PWD/startgdbserverdialog.h
SOURCES += \ SOURCES += \
$$PWD/gdbengine.cpp \ $$PWD/gdbengine.cpp \
$$PWD/gdboptionspage.cpp \ $$PWD/gdboptionspage.cpp \
$$PWD/attachgdbadapter.cpp \
$$PWD/coregdbadapter.cpp \
$$PWD/termgdbadapter.cpp \
$$PWD/remotegdbserveradapter.cpp \
$$PWD/gdbplainengine.cpp \
$$PWD/startgdbserverdialog.cpp $$PWD/startgdbserverdialog.cpp

File diff suppressed because it is too large Load Diff

View File

@@ -33,64 +33,69 @@
#include <debugger/watchutils.h> #include <debugger/watchutils.h>
#include <debugger/debuggeritem.h> #include <debugger/debuggeritem.h>
#include <debugger/debuggertooltipmanager.h> #include <debugger/debuggertooltipmanager.h>
#include <debugger/outputcollector.h>
#include <coreplugin/id.h> #include <coreplugin/id.h>
#include <utils/qtcprocess.h> #include <utils/qtcprocess.h>
#include <utils/consoleprocess.h>
#include <QProcess> #include <QProcess>
#include <QTextCodec> #include <QTextCodec>
#include <QTimer> #include <QTimer>
#include <functional>
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
class GdbProcess; class BreakpointParameters;
class BreakpointResponse;
class DebugInfoTask; class DebugInfoTask;
class DebugInfoTaskHandler; class DebugInfoTaskHandler;
class DebuggerResponse; class DebuggerResponse;
class DisassemblerAgentCookie;
class GdbMi; class GdbMi;
class MemoryAgentCookie; class MemoryAgentCookie;
class BreakpointParameters;
class BreakpointResponse;
class DisassemblerAgentCookie; struct CoreInfo
class DisassemblerLines; {
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 class GdbEngine : public DebuggerEngine
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit GdbEngine(bool useTerminal); explicit GdbEngine(bool useTerminal, DebuggerStartMode startMode);
~GdbEngine() override; ~GdbEngine() final;
private: ////////// General Interface ////////// private: ////////// General Interface //////////
DebuggerEngine *cppEngine() override { return this; } DebuggerEngine *cppEngine() final { return this; }
virtual void handleGdbStartFailed(); void handleGdbStartFailed();
void notifyInferiorSetupFailed() override; void notifyInferiorSetupFailed() final;
void prepareForRestart() override; void prepareForRestart() final;
bool hasCapability(unsigned) const override; bool hasCapability(unsigned) const final;
void detachDebugger() override; void detachDebugger() final;
void shutdownInferior() override; void shutdownInferior() final;
void abortDebugger() override; void abortDebugger() final;
void resetInferior() override; void resetInferior() final;
bool acceptsDebuggerCommands() const override; bool acceptsDebuggerCommands() const final;
void executeDebuggerCommand(const QString &command, DebuggerLanguages languages) override; void executeDebuggerCommand(const QString &command, DebuggerLanguages languages) final;
private: ////////// General State ////////// ////////// General State //////////
DebuggerStartMode startMode() const; const DebuggerStartMode m_startMode;
void reloadLocals(); bool m_registerNamesListed = false;
bool m_registerNamesListed; ////////// Gdb Process Management //////////
protected: ////////// Gdb Process Management //////////
void startGdb(const QStringList &args = QStringList()); void startGdb(const QStringList &args = QStringList());
void handleInferiorShutdown(const DebuggerResponse &response); void handleInferiorShutdown(const DebuggerResponse &response);
@@ -123,9 +128,6 @@ protected: ////////// Gdb Process Management //////////
// Make sure to clean up everything before emitting this signal. // Make sure to clean up everything before emitting this signal.
void handleAdapterCrashed(const QString &msg); void handleAdapterCrashed(const QString &msg);
private:
friend class GdbPlainEngine;
friend class GdbCoreEngine;
void handleGdbFinished(int exitCode, QProcess::ExitStatus exitStatus); void handleGdbFinished(int exitCode, QProcess::ExitStatus exitStatus);
void handleGdbError(QProcess::ProcessError error); void handleGdbError(QProcess::ProcessError error);
void readGdbStandardOutput(); void readGdbStandardOutput();
@@ -138,17 +140,16 @@ private:
QTextCodec::ConverterState m_inferiorOutputCodecState; QTextCodec::ConverterState m_inferiorOutputCodecState;
QByteArray m_inbuffer; QByteArray m_inbuffer;
bool m_busy; bool m_busy = false;
// Name of the convenience variable containing the last // Name of the convenience variable containing the last
// known function return value. // known function return value.
QString m_resultVarName; 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 commandTimeout();
void setTokenBarrier(); void setTokenBarrier();
@@ -166,19 +167,19 @@ private:
// This contains the first token number for the current round // This contains the first token number for the current round
// of evaluation. Responses with older tokens are considers // of evaluation. Responses with older tokens are considers
// out of date and discarded. // out of date and discarded.
int m_oldestAcceptableToken; int m_oldestAcceptableToken = -1;
int m_nonDiscardableCount; 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)(); typedef void (GdbEngine::*CommandsDoneCallback)();
// This function is called after all previous responses have been received. // 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); Q_INVOKABLE void handleResponse(const QString &buff);
void handleAsyncOutput(const QString &asyncClass, const GdbMi &result); void handleAsyncOutput(const QString &asyncClass, const GdbMi &result);
void handleStopResponse(const GdbMi &data); void handleStopResponse(const GdbMi &data);
@@ -188,42 +189,40 @@ protected:
void handleStop3(); void handleStop3();
void resetCommandQueue(); void resetCommandQueue();
bool isSynchronous() const override { return true; } bool isSynchronous() const final { return true; }
// Gdb initialization sequence // Gdb initialization sequence
void handleShowVersion(const DebuggerResponse &response); void handleShowVersion(const DebuggerResponse &response);
void handleListFeatures(const DebuggerResponse &response); void handleListFeatures(const DebuggerResponse &response);
void handlePythonSetup(const DebuggerResponse &response); void handlePythonSetup(const DebuggerResponse &response);
int m_gdbVersion; // 7.6.1 is 70601 int m_gdbVersion = 100; // 7.6.1 is 70601
int m_pythonVersion; // 2.7.2 is 20702 int m_pythonVersion = 0; // 2.7.2 is 20702
bool m_isQnxGdb; bool m_isQnxGdb = false;
private: ////////// Inferior Management ////////// ////////// Inferior Management //////////
// This should be always the last call in a function. // This should be always the last call in a function.
bool stateAcceptsBreakpointChanges() const override; bool stateAcceptsBreakpointChanges() const final;
bool acceptsBreakpoint(Breakpoint bp) const override; bool acceptsBreakpoint(Breakpoint bp) const final;
void insertBreakpoint(Breakpoint bp) override; void insertBreakpoint(Breakpoint bp) final;
void removeBreakpoint(Breakpoint bp) override; void removeBreakpoint(Breakpoint bp) final;
void changeBreakpoint(Breakpoint bp) override; void changeBreakpoint(Breakpoint bp) final;
void executeStep() override; void executeStep() final;
void executeStepOut() override; void executeStepOut() final;
void executeNext() override; void executeNext() final;
void executeStepI() override; void executeStepI() final;
void executeNextI() override; void executeNextI() final;
protected:
void continueInferiorInternal(); void continueInferiorInternal();
void continueInferior() override; void continueInferior() final;
void interruptInferior() override; void interruptInferior() final;
virtual void interruptInferior2() {}
void executeRunToLine(const ContextData &data) override; void executeRunToLine(const ContextData &data) final;
void executeRunToFunction(const QString &functionName) override; void executeRunToFunction(const QString &functionName) final;
void executeJumpToLine(const ContextData &data) override; void executeJumpToLine(const ContextData &data) final;
void executeReturn() override; void executeReturn() final;
void handleExecuteContinue(const DebuggerResponse &response); void handleExecuteContinue(const DebuggerResponse &response);
void handleExecuteStep(const DebuggerResponse &response); void handleExecuteStep(const DebuggerResponse &response);
@@ -234,10 +233,10 @@ private: ////////// Inferior Management //////////
QString msgPtraceError(DebuggerStartMode sm); QString msgPtraceError(DebuggerStartMode sm);
private: ////////// View & Data Stuff ////////// ////////// View & Data Stuff //////////
void selectThread(ThreadId threadId) override; void selectThread(ThreadId threadId) final;
void activateFrame(int index) override; void activateFrame(int index) final;
void handleAutoContinueInferior(); void handleAutoContinueInferior();
// //
@@ -265,14 +264,13 @@ private: ////////// View & Data Stuff //////////
// //
// Modules specific stuff // Modules specific stuff
// //
protected: void loadSymbols(const QString &moduleName) final;
void loadSymbols(const QString &moduleName) override; void loadAllSymbols() final;
void loadAllSymbols() override; void loadSymbolsForStack() final;
void loadSymbolsForStack() override; void requestModuleSymbols(const QString &moduleName) final;
void requestModuleSymbols(const QString &moduleName) override; void requestModuleSections(const QString &moduleName) final;
void requestModuleSections(const QString &moduleName) override; void reloadModules() final;
void reloadModules() override; void examineModules() final;
void examineModules() override;
void reloadModulesInternal(); void reloadModulesInternal();
void handleModulesList(const DebuggerResponse &response); void handleModulesList(const DebuggerResponse &response);
@@ -281,14 +279,14 @@ private: ////////// View & Data Stuff //////////
// //
// Snapshot specific stuff // Snapshot specific stuff
// //
virtual void createSnapshot() override; void createSnapshot() final;
void handleMakeSnapshot(const DebuggerResponse &response, const QString &coreFile); void handleMakeSnapshot(const DebuggerResponse &response, const QString &coreFile);
// //
// Register specific stuff // Register specific stuff
// //
void reloadRegisters() override; void reloadRegisters() final;
void setRegisterValue(const QString &name, const QString &value) override; void setRegisterValue(const QString &name, const QString &value) final;
void handleRegisterListNames(const DebuggerResponse &response); void handleRegisterListNames(const DebuggerResponse &response);
void handleRegisterListing(const DebuggerResponse &response); void handleRegisterListing(const DebuggerResponse &response);
void handleRegisterListValues(const DebuggerResponse &response); void handleRegisterListValues(const DebuggerResponse &response);
@@ -299,7 +297,7 @@ private: ////////// View & Data Stuff //////////
// Disassembler specific stuff // Disassembler specific stuff
// //
// Chain of fallbacks: PointMixed -> PointPlain -> RangeMixed -> RangePlain. // Chain of fallbacks: PointMixed -> PointPlain -> RangeMixed -> RangePlain.
void fetchDisassembler(DisassemblerAgent *agent) override; void fetchDisassembler(DisassemblerAgent *agent) final;
void fetchDisassemblerByCliPointMixed(const DisassemblerAgentCookie &ac); void fetchDisassemblerByCliPointMixed(const DisassemblerAgentCookie &ac);
void fetchDisassemblerByCliRangeMixed(const DisassemblerAgentCookie &ac); void fetchDisassemblerByCliRangeMixed(const DisassemblerAgentCookie &ac);
void fetchDisassemblerByCliRangePlain(const DisassemblerAgentCookie &ac); void fetchDisassemblerByCliRangePlain(const DisassemblerAgentCookie &ac);
@@ -308,7 +306,7 @@ private: ////////// View & Data Stuff //////////
// //
// Source file specific stuff // Source file specific stuff
// //
void reloadSourceFiles() override; void reloadSourceFiles() final;
void reloadSourceFilesInternal(); void reloadSourceFilesInternal();
void handleQuerySources(const DebuggerResponse &response); void handleQuerySources(const DebuggerResponse &response);
@@ -320,13 +318,12 @@ private: ////////// View & Data Stuff //////////
QMap<QString, QString> m_fullToShortName; QMap<QString, QString> m_fullToShortName;
QMultiMap<QString, QString> m_baseNameToFullName; QMultiMap<QString, QString> m_baseNameToFullName;
bool m_sourcesListUpdating; bool m_sourcesListUpdating = false;
// //
// Stack specific stuff // Stack specific stuff
// //
protected: void updateAll() final;
void updateAll() override;
void handleStackListFrames(const DebuggerResponse &response, bool isFull); void handleStackListFrames(const DebuggerResponse &response, bool isFull);
void handleStackSelectThread(const DebuggerResponse &response); void handleStackSelectThread(const DebuggerResponse &response);
void handleThreadListIds(const DebuggerResponse &response); void handleThreadListIds(const DebuggerResponse &response);
@@ -334,20 +331,21 @@ protected:
void handleThreadNames(const DebuggerResponse &response); void handleThreadNames(const DebuggerResponse &response);
DebuggerCommand stackCommand(int depth); DebuggerCommand stackCommand(int depth);
void reloadStack(); void reloadStack();
void reloadFullStack() override; void reloadFullStack() final;
void loadAdditionalQmlStack() override; void loadAdditionalQmlStack() final;
int currentFrame() const; int currentFrame() const;
// //
// Watch specific stuff // Watch specific stuff
// //
virtual void assignValueInDebugger(WatchItem *item, void reloadLocals();
const QString &expr, const QVariant &value) override; 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 fetchMemoryHelper(const MemoryAgentCookie &cookie);
void handleChangeMemory(const DebuggerResponse &response); 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 handleFetchMemory(const DebuggerResponse &response, MemoryAgentCookie ac);
void showToolTip(); void showToolTip();
@@ -358,7 +356,7 @@ protected:
void createFullBacktrace(); void createFullBacktrace();
void doUpdateLocals(const UpdateParameters &parameters) override; void doUpdateLocals(const UpdateParameters &parameters) final;
void handleFetchVariables(const DebuggerResponse &response); void handleFetchVariables(const DebuggerResponse &response);
void setLocals(const QList<GdbMi> &locals); void setLocals(const QList<GdbMi> &locals);
@@ -366,7 +364,7 @@ protected:
// //
// Dumper Management // Dumper Management
// //
void reloadDebuggingHelpers() override; void reloadDebuggingHelpers() final;
// //
// Convenience Functions // Convenience Functions
@@ -374,19 +372,18 @@ protected:
void showExecutionError(const QString &message); void showExecutionError(const QString &message);
QString failedToStartMessage(); QString failedToStartMessage();
static QString tooltipIName(const QString &exp);
// For short-circuiting stack and thread list evaluation. // For short-circuiting stack and thread list evaluation.
bool m_stackNeeded; bool m_stackNeeded = false;
// For suppressing processing *stopped and *running responses // For suppressing processing *stopped and *running responses
// while updating locals. // while updating locals.
bool m_inUpdateLocals; bool m_inUpdateLocals = false;
// HACK: // HACK:
QString m_currentThread; QString m_currentThread;
QString m_lastWinException; QString m_lastWinException;
QString m_lastMissingDebugInfo; QString m_lastMissingDebugInfo;
const bool m_useTerminal;
bool m_terminalTrap; bool m_terminalTrap;
bool usesExecInterrupt() const; bool usesExecInterrupt() const;
bool usesTargetAsync() const; bool usesTargetAsync() const;
@@ -401,7 +398,7 @@ protected:
void requestDebugInformation(const DebugInfoTask &task); void requestDebugInformation(const DebugInfoTask &task);
DebugInfoTaskHandler *m_debugInfoTaskHandler; DebugInfoTaskHandler *m_debugInfoTaskHandler;
bool m_systemDumpersLoaded; bool m_systemDumpersLoaded = false;
static QString msgGdbStopFailed(const QString &why); static QString msgGdbStopFailed(const QString &why);
static QString msgInferiorStopFailed(const QString &why); static QString msgInferiorStopFailed(const QString &why);
@@ -410,14 +407,63 @@ protected:
static QString msgInferiorRunOk(); static QString msgInferiorRunOk();
static QString msgConnectRemoteServerFailed(const QString &why); static QString msgConnectRemoteServerFailed(const QString &why);
void debugLastCommand() override; void debugLastCommand() final;
DebuggerCommand m_lastDebuggableCommand; 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); 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; Utils::QtcProcess m_gdbProc;
OutputCollector m_outputCollector;
QString m_errorString; QString m_errorString;
}; };

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -28,7 +28,7 @@
#include "debuggerstartparameters.h" #include "debuggerstartparameters.h"
#include "debuggerdialogs.h" #include "debuggerdialogs.h"
#include "debuggerkitinformation.h" #include "debuggerkitinformation.h"
#include "gdb/coregdbadapter.h" #include "gdb/gdbengine.h"
#include <projectexplorer/kitinformation.h> #include <projectexplorer/kitinformation.h>
#include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectexplorerconstants.h>
@@ -364,7 +364,7 @@ void AttachCoreDialog::coreFileChanged(const QString &core)
Kit *k = d->kitChooser->currentKit(); Kit *k = d->kitChooser->currentKit();
QTC_ASSERT(k, return); QTC_ASSERT(k, return);
StandardRunnable debugger = DebuggerKitInformation::runnable(k); StandardRunnable debugger = DebuggerKitInformation::runnable(k);
GdbCoreEngine::CoreInfo cinfo = GdbCoreEngine::readExecutableNameFromCore(debugger, core); CoreInfo cinfo = CoreInfo::readExecutableNameFromCore(debugger, core);
if (!cinfo.foundExecutableName.isEmpty()) if (!cinfo.foundExecutableName.isEmpty())
d->localExecFileName->setFileName(FileName::fromString(cinfo.foundExecutableName)); d->localExecFileName->setFileName(FileName::fromString(cinfo.foundExecutableName));
else if (!d->localExecFileName->isValid() && !cinfo.rawStringFromCore.isEmpty()) else if (!d->localExecFileName->isValid() && !cinfo.rawStringFromCore.isEmpty())