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"
|
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"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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 += \
|
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
@@ -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 ¶meters) override;
|
void doUpdateLocals(const UpdateParameters ¶meters) 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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -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 "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())
|
||||||
|
Reference in New Issue
Block a user