forked from qt-creator/qt-creator
Valgrind: Merge ValgrindRunner and ValgrindProcess
There was a 1:1 matching remaining. Change-Id: I619bedcda867b642eab37396a0bd48bcb3a5829a Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
@@ -31,7 +31,6 @@
|
||||
#include <valgrind/callgrind/callgrindcontroller.h>
|
||||
#include <valgrind/callgrind/callgrindparser.h>
|
||||
#include <valgrind/valgrindrunner.h>
|
||||
#include <valgrind/valgrindprocess.h>
|
||||
|
||||
#include <debugger/analyzer/analyzermanager.h>
|
||||
|
||||
@@ -62,7 +61,7 @@ CallgrindToolRunner::CallgrindToolRunner(RunControl *runControl)
|
||||
connect(&m_controller, &CallgrindController::statusMessage,
|
||||
this, &CallgrindToolRunner::showStatusMessage);
|
||||
|
||||
connect(m_runner.valgrindProcess(), &ValgrindProcess::valgrindStarted,
|
||||
connect(&m_runner, &ValgrindRunner::valgrindStarted,
|
||||
&m_controller, &CallgrindController::setValgrindPid);
|
||||
|
||||
connect(&m_runner, &ValgrindRunner::extraProcessFinished, this, [this] {
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
|
||||
#include "memcheckengine.h"
|
||||
#include "memchecktool.h"
|
||||
#include "valgrindprocess.h"
|
||||
#include "valgrindsettings.h"
|
||||
#include "xmlprotocol/error.h"
|
||||
#include "xmlprotocol/status.h"
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
#include "valgrindrunner.h"
|
||||
#include "xmlprotocol/threadedparser.h"
|
||||
|
||||
#include <QHostAddress>
|
||||
|
||||
namespace Valgrind {
|
||||
namespace Internal {
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ HEADERS += \
|
||||
valgrindconfigwidget.h \
|
||||
valgrindsettings.h \
|
||||
valgrindrunner.h \
|
||||
valgrindprocess.h \
|
||||
callgrindcostdelegate.h \
|
||||
callgrindcostview.h \
|
||||
callgrindhelper.h \
|
||||
@@ -33,7 +32,6 @@ SOURCES += \
|
||||
valgrindconfigwidget.cpp \
|
||||
valgrindsettings.cpp \
|
||||
valgrindrunner.cpp \
|
||||
valgrindprocess.cpp \
|
||||
callgrindcostdelegate.cpp \
|
||||
callgrindcostview.cpp \
|
||||
callgrindhelper.cpp \
|
||||
|
||||
@@ -34,7 +34,6 @@ QtcPlugin {
|
||||
"valgrindconfigwidget.cpp", "valgrindconfigwidget.h", "valgrindconfigwidget.ui",
|
||||
"valgrindengine.cpp", "valgrindengine.h",
|
||||
"valgrindplugin.cpp", "valgrindplugin.h",
|
||||
"valgrindprocess.cpp", "valgrindprocess.h",
|
||||
"valgrindruncontrolfactory.cpp", "valgrindruncontrolfactory.h",
|
||||
"valgrindrunner.cpp", "valgrindrunner.h",
|
||||
"valgrindsettings.cpp", "valgrindsettings.h",
|
||||
|
||||
@@ -27,8 +27,7 @@ HEADERS += \
|
||||
$$PWD/callgrind/callgrindcycledetection.h \
|
||||
$$PWD/callgrind/callgrindproxymodel.h \
|
||||
$$PWD/callgrind/callgrindstackbrowser.h \
|
||||
$$PWD/valgrindrunner.h \
|
||||
$$PWD/valgrindprocess.h
|
||||
$$PWD/valgrindrunner.h
|
||||
|
||||
SOURCES += $$PWD/xmlprotocol/error.cpp \
|
||||
$$PWD/xmlprotocol/frame.cpp \
|
||||
@@ -53,7 +52,6 @@ SOURCES += $$PWD/xmlprotocol/error.cpp \
|
||||
$$PWD/callgrind/callgrindcycledetection.cpp \
|
||||
$$PWD/callgrind/callgrindproxymodel.cpp \
|
||||
$$PWD/callgrind/callgrindstackbrowser.cpp \
|
||||
$$PWD/valgrindrunner.cpp \
|
||||
$$PWD/valgrindprocess.cpp
|
||||
$$PWD/valgrindrunner.cpp
|
||||
|
||||
LIBS += -L$$IDE_PLUGIN_PATH/QtProject
|
||||
|
||||
@@ -1,235 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Author: Milian Wolff, KDAB (milian.wolff@kdab.com)
|
||||
** 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 "valgrindprocess.h"
|
||||
|
||||
#include <ssh/sshconnectionmanager.h>
|
||||
|
||||
#include <utils/fileutils.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/qtcprocess.h>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QEventLoop>
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
|
||||
namespace Valgrind {
|
||||
|
||||
ValgrindProcess::ValgrindProcess()
|
||||
{
|
||||
}
|
||||
|
||||
ValgrindProcess::~ValgrindProcess()
|
||||
{
|
||||
}
|
||||
|
||||
void ValgrindProcess::setProcessChannelMode(QProcess::ProcessChannelMode mode)
|
||||
{
|
||||
m_valgrindProcess.setProcessChannelMode(mode);
|
||||
}
|
||||
|
||||
QString ValgrindProcess::workingDirectory() const
|
||||
{
|
||||
return m_debuggee.workingDirectory;
|
||||
}
|
||||
|
||||
bool ValgrindProcess::isRunning() const
|
||||
{
|
||||
return m_valgrindProcess.isRunning();
|
||||
}
|
||||
|
||||
void ValgrindProcess::setValgrindExecutable(const QString &valgrindExecutable)
|
||||
{
|
||||
m_valgrindExecutable = valgrindExecutable;
|
||||
}
|
||||
|
||||
void ValgrindProcess::setDebuggee(const StandardRunnable &debuggee)
|
||||
{
|
||||
m_debuggee = debuggee;
|
||||
}
|
||||
|
||||
void ValgrindProcess::setValgrindArguments(const QStringList &valgrindArguments)
|
||||
{
|
||||
m_valgrindArguments = valgrindArguments;
|
||||
}
|
||||
|
||||
void ValgrindProcess::close()
|
||||
{
|
||||
m_valgrindProcess.stop();
|
||||
}
|
||||
|
||||
void ValgrindProcess::run(ApplicationLauncher::Mode runMode)
|
||||
{
|
||||
connect(&m_valgrindProcess, &ApplicationLauncher::processExited,
|
||||
this, &ValgrindProcess::finished);
|
||||
connect(&m_valgrindProcess, &ApplicationLauncher::processStarted,
|
||||
this, &ValgrindProcess::localProcessStarted);
|
||||
connect(&m_valgrindProcess, &ApplicationLauncher::error,
|
||||
this, &ValgrindProcess::error);
|
||||
connect(&m_valgrindProcess, &ApplicationLauncher::appendMessage,
|
||||
this, &ValgrindProcess::processOutput);
|
||||
|
||||
connect(&m_valgrindProcess, &ApplicationLauncher::remoteStderr,
|
||||
this, &ValgrindProcess::handleRemoteStderr);
|
||||
connect(&m_valgrindProcess, &ApplicationLauncher::remoteStdout,
|
||||
this, &ValgrindProcess::handleRemoteStdout);
|
||||
connect(&m_valgrindProcess, &ApplicationLauncher::finished,
|
||||
this, &ValgrindProcess::closed);
|
||||
connect(&m_valgrindProcess, &ApplicationLauncher::remoteProcessStarted,
|
||||
this, &ValgrindProcess::remoteProcessStarted);
|
||||
|
||||
StandardRunnable valgrind;
|
||||
valgrind.executable = m_valgrindExecutable;
|
||||
valgrind.workingDirectory = m_debuggee.workingDirectory;
|
||||
valgrind.environment = m_debuggee.environment;
|
||||
valgrind.runMode = runMode;
|
||||
valgrind.device = m_device;
|
||||
|
||||
if (isLocal()) {
|
||||
valgrind.commandLineArguments = argumentString(Utils::HostOsInfo::hostOs());
|
||||
m_valgrindProcess.start(valgrind);
|
||||
} else {
|
||||
valgrind.commandLineArguments = argumentString(Utils::OsTypeLinux);
|
||||
m_valgrindProcess.start(valgrind, m_device);
|
||||
}
|
||||
}
|
||||
|
||||
QString ValgrindProcess::errorString() const
|
||||
{
|
||||
return m_valgrindProcess.errorString();
|
||||
}
|
||||
|
||||
QProcess::ProcessError ValgrindProcess::processError() const
|
||||
{
|
||||
return m_valgrindProcess.processError();
|
||||
}
|
||||
|
||||
void ValgrindProcess::handleRemoteStderr(const QByteArray &b)
|
||||
{
|
||||
if (!b.isEmpty())
|
||||
emit processOutput(QString::fromUtf8(b), Utils::StdErrFormat);
|
||||
}
|
||||
|
||||
void ValgrindProcess::handleRemoteStdout(const QByteArray &b)
|
||||
{
|
||||
if (!b.isEmpty())
|
||||
emit processOutput(QString::fromUtf8(b), Utils::StdOutFormat);
|
||||
}
|
||||
|
||||
bool ValgrindProcess::isLocal() const
|
||||
{
|
||||
return m_device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE;
|
||||
}
|
||||
|
||||
void ValgrindProcess::localProcessStarted()
|
||||
{
|
||||
qint64 pid = m_valgrindProcess.applicationPID().pid();
|
||||
emit valgrindStarted(pid);
|
||||
}
|
||||
|
||||
void ValgrindProcess::remoteProcessStarted()
|
||||
{
|
||||
// find out what PID our process has
|
||||
|
||||
// NOTE: valgrind cloaks its name,
|
||||
// e.g.: valgrind --tool=memcheck foobar
|
||||
// => ps aux, pidof will see valgrind.bin
|
||||
// => pkill/killall/top... will see memcheck-amd64-linux or similar
|
||||
// hence we need to do something more complex...
|
||||
|
||||
// plain path to exe, m_valgrindExe contains e.g. env vars etc. pp.
|
||||
const QString proc = m_valgrindExecutable.split(' ').last();
|
||||
|
||||
StandardRunnable findPid;
|
||||
findPid.executable = "/bin/sh";
|
||||
// sleep required since otherwise we might only match "bash -c..."
|
||||
// and not the actual valgrind run
|
||||
findPid.commandLineArguments = QString("-c \""
|
||||
"sleep 1; ps ax" // list all processes with aliased name
|
||||
" | grep '\\b%1.*%2'" // find valgrind process
|
||||
" | tail -n 1" // limit to single process
|
||||
// we pick the last one, first would be "bash -c ..."
|
||||
" | awk '{print $1;}'" // get pid
|
||||
"\""
|
||||
).arg(proc, Utils::FileName::fromString(m_debuggee.executable).fileName());
|
||||
|
||||
// m_remote.m_findPID = m_remote.m_connection->createRemoteProcess(cmd.toUtf8());
|
||||
connect(&m_findPID, &ApplicationLauncher::remoteStderr,
|
||||
this, &ValgrindProcess::handleRemoteStderr);
|
||||
connect(&m_findPID, &ApplicationLauncher::remoteStdout,
|
||||
this, &ValgrindProcess::findPIDOutputReceived);
|
||||
m_findPID.start(findPid, m_device);
|
||||
}
|
||||
|
||||
void ValgrindProcess::findPIDOutputReceived(const QByteArray &out)
|
||||
{
|
||||
if (out.isEmpty())
|
||||
return;
|
||||
bool ok;
|
||||
qint64 pid = out.trimmed().toLongLong(&ok);
|
||||
if (!ok) {
|
||||
// m_remote.m_errorString = tr("Could not determine remote PID.");
|
||||
// emit ValgrindProcess::error(QProcess::FailedToStart);
|
||||
// close();
|
||||
} else {
|
||||
emit valgrindStarted(pid);
|
||||
}
|
||||
}
|
||||
|
||||
QString ValgrindProcess::argumentString(Utils::OsType osType) const
|
||||
{
|
||||
QString arguments = Utils::QtcProcess::joinArgs(m_valgrindArguments, osType);
|
||||
if (!m_debuggee.executable.isEmpty())
|
||||
Utils::QtcProcess::addArg(&arguments, m_debuggee.executable, osType);
|
||||
Utils::QtcProcess::addArgs(&arguments, m_debuggee.commandLineArguments);
|
||||
return arguments;
|
||||
}
|
||||
|
||||
void ValgrindProcess::setDevice(const ProjectExplorer::IDevice::ConstPtr &device)
|
||||
{
|
||||
m_device = device;
|
||||
}
|
||||
|
||||
void ValgrindProcess::closed(bool success)
|
||||
{
|
||||
Q_UNUSED(success);
|
||||
// QTC_ASSERT(m_remote.m_process, return);
|
||||
|
||||
// m_remote.m_errorString = m_remote.m_process->errorString();
|
||||
// if (status == QSsh::SshRemoteProcess::FailedToStart) {
|
||||
// m_remote.m_error = QProcess::FailedToStart;
|
||||
// emit ValgrindProcess::error(QProcess::FailedToStart);
|
||||
// } else if (status == QSsh::SshRemoteProcess::NormalExit) {
|
||||
// emit finished(m_remote.m_process->exitCode(), QProcess::NormalExit);
|
||||
// } else if (status == QSsh::SshRemoteProcess::CrashExit) {
|
||||
// m_remote.m_error = QProcess::Crashed;
|
||||
// emit finished(m_remote.m_process->exitCode(), QProcess::CrashExit);
|
||||
// }
|
||||
emit finished(0, QProcess::NormalExit);
|
||||
}
|
||||
|
||||
} // namespace Valgrind
|
||||
@@ -1,99 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Author: Milian Wolff, KDAB (milian.wolff@kdab.com)
|
||||
** 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 <projectexplorer/applicationlauncher.h>
|
||||
#include <projectexplorer/devicesupport/idevice.h>
|
||||
#include <projectexplorer/runnables.h>
|
||||
|
||||
#include <ssh/sshremoteprocess.h>
|
||||
#include <ssh/sshconnection.h>
|
||||
#include <utils/osspecificaspects.h>
|
||||
#include <utils/outputformat.h>
|
||||
|
||||
namespace Valgrind {
|
||||
|
||||
/**
|
||||
* Process for supplying local and remote valgrind runs
|
||||
*/
|
||||
class ValgrindProcess : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ValgrindProcess();
|
||||
~ValgrindProcess();
|
||||
|
||||
bool isRunning() const;
|
||||
|
||||
void setValgrindExecutable(const QString &valgrindExecutable);
|
||||
void setValgrindArguments(const QStringList &valgrindArguments);
|
||||
void setDebuggee(const ProjectExplorer::StandardRunnable &debuggee);
|
||||
|
||||
void run(ProjectExplorer::ApplicationLauncher::Mode runMode);
|
||||
void close();
|
||||
|
||||
QString errorString() const;
|
||||
QProcess::ProcessError processError() const;
|
||||
|
||||
void setProcessChannelMode(QProcess::ProcessChannelMode mode);
|
||||
QString workingDirectory() const;
|
||||
|
||||
ProjectExplorer::IDevice::ConstPtr device() const { return m_device; }
|
||||
void setDevice(const ProjectExplorer::IDevice::ConstPtr &device);
|
||||
|
||||
bool isLocal() const;
|
||||
|
||||
signals:
|
||||
void valgrindStarted(qint64 pid);
|
||||
void finished(int, QProcess::ExitStatus);
|
||||
void error(QProcess::ProcessError);
|
||||
void processOutput(const QString &, Utils::OutputFormat format);
|
||||
|
||||
private:
|
||||
void handleRemoteStderr(const QByteArray &b);
|
||||
void handleRemoteStdout(const QByteArray &b);
|
||||
|
||||
void closed(bool success);
|
||||
void localProcessStarted();
|
||||
void remoteProcessStarted();
|
||||
void findPIDOutputReceived(const QByteArray &out);
|
||||
|
||||
QString argumentString(Utils::OsType osType) const;
|
||||
|
||||
ProjectExplorer::StandardRunnable m_debuggee;
|
||||
ProjectExplorer::ApplicationLauncher m_valgrindProcess;
|
||||
ProjectExplorer::IDevice::ConstPtr m_device;
|
||||
|
||||
ProjectExplorer::ApplicationLauncher m_findPID;
|
||||
|
||||
QSsh::SshConnectionParameters m_params;
|
||||
QString m_valgrindExecutable;
|
||||
QStringList m_valgrindArguments;
|
||||
};
|
||||
|
||||
} // namespace Valgrind
|
||||
@@ -25,57 +25,199 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "valgrindrunner.h"
|
||||
#include "valgrindprocess.h"
|
||||
|
||||
#include "xmlprotocol/threadedparser.h"
|
||||
|
||||
#include <projectexplorer/runnables.h>
|
||||
|
||||
#include <utils/environment.h>
|
||||
#include <utils/hostosinfo.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <ssh/sshconnection.h>
|
||||
#include <ssh/sshremoteprocess.h>
|
||||
#include <utils/qtcprocess.h>
|
||||
|
||||
#include <QEventLoop>
|
||||
#include <QNetworkInterface>
|
||||
#include <QTcpServer>
|
||||
#include <QTcpSocket>
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
using namespace Utils;
|
||||
|
||||
namespace Valgrind {
|
||||
|
||||
class ValgrindRunner::Private
|
||||
class ValgrindRunner::Private : public QObject
|
||||
{
|
||||
public:
|
||||
Private(ValgrindRunner *owner) : q(owner) {}
|
||||
|
||||
void run();
|
||||
|
||||
void handleRemoteStderr(const QByteArray &b);
|
||||
void handleRemoteStdout(const QByteArray &b);
|
||||
|
||||
void closed(bool success);
|
||||
void localProcessStarted();
|
||||
void remoteProcessStarted();
|
||||
void findPIDOutputReceived(const QByteArray &out);
|
||||
|
||||
ValgrindRunner *q;
|
||||
StandardRunnable m_debuggee;
|
||||
ApplicationLauncher m_valgrindProcess;
|
||||
IDevice::ConstPtr m_device;
|
||||
|
||||
ApplicationLauncher m_findPID;
|
||||
|
||||
QString m_valgrindExecutable;
|
||||
QStringList m_valgrindArguments;
|
||||
|
||||
QHostAddress localServerAddress;
|
||||
ValgrindProcess process;
|
||||
QProcess::ProcessChannelMode channelMode = QProcess::SeparateChannels;
|
||||
bool finished = false;
|
||||
QString valgrindExecutable;
|
||||
QStringList valgrindArguments;
|
||||
StandardRunnable debuggee;
|
||||
IDevice::ConstPtr device;
|
||||
QString tool;
|
||||
bool m_finished = false;
|
||||
QString m_tool;
|
||||
|
||||
QTcpServer xmlServer;
|
||||
XmlProtocol::ThreadedParser parser;
|
||||
QTcpServer logServer;
|
||||
QTcpSocket *logSocket = nullptr;
|
||||
|
||||
// Workaround for valgrind bug when running vgdb with xml output
|
||||
// https://bugs.kde.org/show_bug.cgi?id=343902
|
||||
bool disableXml = false;
|
||||
};
|
||||
|
||||
void ValgrindRunner::Private::run()
|
||||
{
|
||||
connect(&m_valgrindProcess, &ApplicationLauncher::processExited,
|
||||
this, &ValgrindRunner::Private::closed);
|
||||
connect(&m_valgrindProcess, &ApplicationLauncher::processStarted,
|
||||
this, &ValgrindRunner::Private::localProcessStarted);
|
||||
connect(&m_valgrindProcess, &ApplicationLauncher::error,
|
||||
q, &ValgrindRunner::processError);
|
||||
connect(&m_valgrindProcess, &ApplicationLauncher::appendMessage,
|
||||
q, &ValgrindRunner::processOutputReceived);
|
||||
connect(&m_valgrindProcess, &ApplicationLauncher::finished,
|
||||
q, &ValgrindRunner::finished);
|
||||
|
||||
connect(&m_valgrindProcess, &ApplicationLauncher::remoteStderr,
|
||||
this, &ValgrindRunner::Private::handleRemoteStderr);
|
||||
connect(&m_valgrindProcess, &ApplicationLauncher::remoteStdout,
|
||||
this, &ValgrindRunner::Private::handleRemoteStdout);
|
||||
connect(&m_valgrindProcess, &ApplicationLauncher::remoteProcessStarted,
|
||||
this, &ValgrindRunner::Private::remoteProcessStarted);
|
||||
|
||||
QStringList fullArgs = m_valgrindArguments;
|
||||
fullArgs << QString("--tool=%1").arg(m_tool);
|
||||
if (HostOsInfo::isMacHost())
|
||||
// May be slower to start but without it we get no filenames for symbols.
|
||||
fullArgs << "--dsymutil=yes";
|
||||
fullArgs << m_debuggee.executable;
|
||||
|
||||
StandardRunnable valgrind;
|
||||
valgrind.executable = m_valgrindExecutable;
|
||||
valgrind.workingDirectory = m_debuggee.workingDirectory;
|
||||
valgrind.environment = m_debuggee.environment;
|
||||
valgrind.runMode = m_debuggee.runMode;
|
||||
valgrind.device = m_device;
|
||||
valgrind.commandLineArguments = QtcProcess::joinArgs(fullArgs, m_device->osType());
|
||||
Utils::QtcProcess::addArgs(&valgrind.commandLineArguments, m_debuggee.commandLineArguments);
|
||||
|
||||
if (m_device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE)
|
||||
m_valgrindProcess.start(valgrind);
|
||||
else
|
||||
m_valgrindProcess.start(valgrind, m_device);
|
||||
}
|
||||
|
||||
void ValgrindRunner::Private::handleRemoteStderr(const QByteArray &b)
|
||||
{
|
||||
if (!b.isEmpty())
|
||||
q->processOutputReceived(QString::fromUtf8(b), Utils::StdErrFormat);
|
||||
}
|
||||
|
||||
void ValgrindRunner::Private::handleRemoteStdout(const QByteArray &b)
|
||||
{
|
||||
if (!b.isEmpty())
|
||||
q->processOutputReceived(QString::fromUtf8(b), Utils::StdOutFormat);
|
||||
}
|
||||
|
||||
void ValgrindRunner::Private::localProcessStarted()
|
||||
{
|
||||
qint64 pid = m_valgrindProcess.applicationPID().pid();
|
||||
emit q->valgrindStarted(pid);
|
||||
}
|
||||
|
||||
void ValgrindRunner::Private::remoteProcessStarted()
|
||||
{
|
||||
// find out what PID our process has
|
||||
|
||||
// NOTE: valgrind cloaks its name,
|
||||
// e.g.: valgrind --tool=memcheck foobar
|
||||
// => ps aux, pidof will see valgrind.bin
|
||||
// => pkill/killall/top... will see memcheck-amd64-linux or similar
|
||||
// hence we need to do something more complex...
|
||||
|
||||
// plain path to exe, m_valgrindExe contains e.g. env vars etc. pp.
|
||||
const QString proc = m_valgrindExecutable.split(' ').last();
|
||||
|
||||
StandardRunnable findPid;
|
||||
findPid.executable = "/bin/sh";
|
||||
// sleep required since otherwise we might only match "bash -c..."
|
||||
// and not the actual valgrind run
|
||||
findPid.commandLineArguments = QString("-c \""
|
||||
"sleep 1; ps ax" // list all processes with aliased name
|
||||
" | grep '\\b%1.*%2'" // find valgrind process
|
||||
" | tail -n 1" // limit to single process
|
||||
// we pick the last one, first would be "bash -c ..."
|
||||
" | awk '{print $1;}'" // get pid
|
||||
"\""
|
||||
).arg(proc, Utils::FileName::fromString(m_debuggee.executable).fileName());
|
||||
|
||||
// m_remote.m_findPID = m_remote.m_connection->createRemoteProcess(cmd.toUtf8());
|
||||
connect(&m_findPID, &ApplicationLauncher::remoteStderr,
|
||||
this, &ValgrindRunner::Private::handleRemoteStderr);
|
||||
connect(&m_findPID, &ApplicationLauncher::remoteStdout,
|
||||
this, &ValgrindRunner::Private::findPIDOutputReceived);
|
||||
m_findPID.start(findPid, m_device);
|
||||
}
|
||||
|
||||
void ValgrindRunner::Private::findPIDOutputReceived(const QByteArray &out)
|
||||
{
|
||||
if (out.isEmpty())
|
||||
return;
|
||||
bool ok;
|
||||
qint64 pid = out.trimmed().toLongLong(&ok);
|
||||
if (!ok) {
|
||||
// m_remote.m_errorString = tr("Could not determine remote PID.");
|
||||
// emit ValgrindRunner::Private::error(QProcess::FailedToStart);
|
||||
// close();
|
||||
} else {
|
||||
emit q->valgrindStarted(pid);
|
||||
}
|
||||
}
|
||||
|
||||
void ValgrindRunner::Private::closed(bool success)
|
||||
{
|
||||
Q_UNUSED(success);
|
||||
// QTC_ASSERT(m_remote.m_process, return);
|
||||
|
||||
// m_remote.m_errorString = m_remote.m_process->errorString();
|
||||
// if (status == QSsh::SshRemoteProcess::FailedToStart) {
|
||||
// m_remote.m_error = QProcess::FailedToStart;
|
||||
// q->processError(QProcess::FailedToStart);
|
||||
// } else if (status == QSsh::SshRemoteProcess::NormalExit) {
|
||||
// q->processFinished(m_remote.m_process->exitCode(), QProcess::NormalExit);
|
||||
// } else if (status == QSsh::SshRemoteProcess::CrashExit) {
|
||||
// m_remote.m_error = QProcess::Crashed;
|
||||
// q->processFinished(m_remote.m_process->exitCode(), QProcess::CrashExit);
|
||||
// }
|
||||
q->processFinished(0, QProcess::NormalExit);
|
||||
}
|
||||
|
||||
|
||||
ValgrindRunner::ValgrindRunner(QObject *parent)
|
||||
: QObject(parent), d(new Private)
|
||||
: QObject(parent), d(new Private(this))
|
||||
{
|
||||
setToolName("memcheck");
|
||||
}
|
||||
|
||||
ValgrindRunner::~ValgrindRunner()
|
||||
{
|
||||
if (d->process.isRunning()) {
|
||||
if (d->m_valgrindProcess.isRunning()) {
|
||||
// make sure we don't delete the thread while it's still running
|
||||
waitForFinished();
|
||||
}
|
||||
@@ -89,37 +231,17 @@ ValgrindRunner::~ValgrindRunner()
|
||||
|
||||
void ValgrindRunner::setValgrindExecutable(const QString &executable)
|
||||
{
|
||||
d->valgrindExecutable = executable;
|
||||
}
|
||||
|
||||
QString ValgrindRunner::valgrindExecutable() const
|
||||
{
|
||||
return d->valgrindExecutable;
|
||||
d->m_valgrindExecutable = executable;
|
||||
}
|
||||
|
||||
void ValgrindRunner::setValgrindArguments(const QStringList &toolArguments)
|
||||
{
|
||||
d->valgrindArguments = toolArguments;
|
||||
}
|
||||
|
||||
QStringList ValgrindRunner::valgrindArguments() const
|
||||
{
|
||||
return d->valgrindArguments;
|
||||
}
|
||||
|
||||
QStringList ValgrindRunner::fullValgrindArguments() const
|
||||
{
|
||||
QStringList fullArgs = valgrindArguments();
|
||||
fullArgs << QString("--tool=%1").arg(d->tool);
|
||||
if (Utils::HostOsInfo::isMacHost())
|
||||
// May be slower to start but without it we get no filenames for symbols.
|
||||
fullArgs << QLatin1String("--dsymutil=yes");
|
||||
return fullArgs;
|
||||
d->m_valgrindArguments = toolArguments;
|
||||
}
|
||||
|
||||
void ValgrindRunner::setDebuggee(const StandardRunnable &debuggee)
|
||||
{
|
||||
d->debuggee = debuggee;
|
||||
d->m_debuggee = debuggee;
|
||||
}
|
||||
|
||||
void ValgrindRunner::setProcessChannelMode(QProcess::ProcessChannelMode mode)
|
||||
@@ -134,17 +256,12 @@ void ValgrindRunner::setLocalServerAddress(const QHostAddress &localServerAddres
|
||||
|
||||
void ValgrindRunner::setDevice(const IDevice::ConstPtr &device)
|
||||
{
|
||||
d->device = device;
|
||||
}
|
||||
|
||||
IDevice::ConstPtr ValgrindRunner::device() const
|
||||
{
|
||||
return d->device;
|
||||
d->m_device = device;
|
||||
}
|
||||
|
||||
void ValgrindRunner::waitForFinished() const
|
||||
{
|
||||
if (d->finished)
|
||||
if (d->m_finished)
|
||||
return;
|
||||
|
||||
QEventLoop loop;
|
||||
@@ -154,7 +271,22 @@ void ValgrindRunner::waitForFinished() const
|
||||
|
||||
void ValgrindRunner::setToolName(const QString &toolName)
|
||||
{
|
||||
d->tool = toolName;
|
||||
d->m_tool = toolName;
|
||||
}
|
||||
|
||||
static void handleSocketParameter(const QString &prefix, const QTcpServer &tcpServer,
|
||||
bool *useXml, QStringList *arguments)
|
||||
{
|
||||
QHostAddress serverAddress = tcpServer.serverAddress();
|
||||
if (serverAddress.protocol() != QAbstractSocket::IPv4Protocol) {
|
||||
// Report will end up in the Application Output pane, i.e. not have
|
||||
// clickable items, but that's better than nothing.
|
||||
qWarning("Need IPv4 for valgrind");
|
||||
*useXml = false;
|
||||
} else {
|
||||
*arguments << QString("%1=%2:%3").arg(prefix).arg(serverAddress.toString())
|
||||
.arg(tcpServer.serverPort());
|
||||
}
|
||||
}
|
||||
|
||||
bool ValgrindRunner::start()
|
||||
@@ -162,37 +294,35 @@ bool ValgrindRunner::start()
|
||||
if (!d->localServerAddress.isNull()) {
|
||||
if (!startServers())
|
||||
return false;
|
||||
setValgrindArguments(memcheckLogArguments() + valgrindArguments());
|
||||
|
||||
bool enableXml = !d->disableXml;
|
||||
|
||||
QStringList arguments = {"--child-silent-after-fork=yes"};
|
||||
|
||||
handleSocketParameter("--xml-socket", d->xmlServer, &enableXml, &arguments);
|
||||
handleSocketParameter("--log-socket", d->logServer, &enableXml, &arguments);
|
||||
|
||||
if (enableXml)
|
||||
arguments << "--xml=yes";
|
||||
|
||||
d->m_valgrindArguments = arguments + d->m_valgrindArguments;
|
||||
}
|
||||
|
||||
d->process.setProcessChannelMode(d->channelMode);
|
||||
d->process.setDevice(d->device);
|
||||
d->m_valgrindProcess.setProcessChannelMode(d->channelMode);
|
||||
// consider appending our options last so they override any interfering user-supplied options
|
||||
// -q as suggested by valgrind manual
|
||||
d->process.setValgrindExecutable(d->valgrindExecutable);
|
||||
d->process.setValgrindArguments(fullValgrindArguments());
|
||||
d->process.setDebuggee(d->debuggee);
|
||||
|
||||
QObject::connect(&d->process, &ValgrindProcess::processOutput,
|
||||
this, &ValgrindRunner::processOutputReceived);
|
||||
QObject::connect(&d->process, &ValgrindProcess::valgrindStarted,
|
||||
this, &ValgrindRunner::onValgrindStarted);
|
||||
QObject::connect(&d->process, &ValgrindProcess::finished,
|
||||
this, &ValgrindRunner::processFinished);
|
||||
QObject::connect(&d->process, &ValgrindProcess::error,
|
||||
this, &ValgrindRunner::processError);
|
||||
|
||||
d->process.run(d->debuggee.runMode);
|
||||
d->m_valgrindExecutable = d->m_valgrindExecutable;
|
||||
d->run();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ValgrindRunner::processError(QProcess::ProcessError e)
|
||||
{
|
||||
if (d->finished)
|
||||
if (d->m_finished)
|
||||
return;
|
||||
|
||||
d->finished = true;
|
||||
d->m_finished = true;
|
||||
|
||||
// make sure we don't wait for the connection anymore
|
||||
emit processErrorReceived(errorString(), e);
|
||||
@@ -203,31 +333,26 @@ void ValgrindRunner::processFinished(int ret, QProcess::ExitStatus status)
|
||||
{
|
||||
emit extraProcessFinished();
|
||||
|
||||
if (d->finished)
|
||||
if (d->m_finished)
|
||||
return;
|
||||
|
||||
d->finished = true;
|
||||
d->m_finished = true;
|
||||
|
||||
// make sure we don't wait for the connection anymore
|
||||
emit finished();
|
||||
|
||||
if (ret != 0 || status == QProcess::CrashExit)
|
||||
emit processErrorReceived(errorString(), d->process.processError());
|
||||
emit processErrorReceived(errorString(), d->m_valgrindProcess.processError());
|
||||
}
|
||||
|
||||
QString ValgrindRunner::errorString() const
|
||||
{
|
||||
return d->process.errorString();
|
||||
return d->m_valgrindProcess.errorString();
|
||||
}
|
||||
|
||||
void ValgrindRunner::stop()
|
||||
{
|
||||
d->process.close();
|
||||
}
|
||||
|
||||
ValgrindProcess *ValgrindRunner::valgrindProcess() const
|
||||
{
|
||||
return &d->process;
|
||||
d->m_valgrindProcess.stop();
|
||||
}
|
||||
|
||||
XmlProtocol::ThreadedParser *ValgrindRunner::parser() const
|
||||
@@ -235,19 +360,6 @@ XmlProtocol::ThreadedParser *ValgrindRunner::parser() const
|
||||
return &d->parser;
|
||||
}
|
||||
|
||||
|
||||
// Workaround for valgrind bug when running vgdb with xml output
|
||||
// https://bugs.kde.org/show_bug.cgi?id=343902
|
||||
void ValgrindRunner::disableXml()
|
||||
{
|
||||
d->disableXml = true;
|
||||
}
|
||||
|
||||
void ValgrindRunner::onValgrindStarted(qint64 pid)
|
||||
{
|
||||
emit valgrindStarted(pid);
|
||||
}
|
||||
|
||||
void ValgrindRunner::xmlSocketConnected()
|
||||
{
|
||||
QTcpSocket *socket = d->xmlServer.nextPendingConnection();
|
||||
@@ -295,34 +407,4 @@ bool ValgrindRunner::startServers()
|
||||
return true;
|
||||
}
|
||||
|
||||
static void handleSocketParameter(const QString &prefix, const QTcpServer &tcpServer,
|
||||
bool *useXml, QStringList *arguments)
|
||||
{
|
||||
QHostAddress serverAddress = tcpServer.serverAddress();
|
||||
if (serverAddress.protocol() != QAbstractSocket::IPv4Protocol) {
|
||||
// Report will end up in the Application Output pane, i.e. not have
|
||||
// clickable items, but that's better than nothing.
|
||||
qWarning("Need IPv4 for valgrind");
|
||||
*useXml = false;
|
||||
} else {
|
||||
*arguments << QString("%1=%2:%3").arg(prefix).arg(serverAddress.toString())
|
||||
.arg(tcpServer.serverPort());
|
||||
}
|
||||
}
|
||||
|
||||
QStringList ValgrindRunner::memcheckLogArguments() const
|
||||
{
|
||||
bool enableXml = !d->disableXml;
|
||||
|
||||
QStringList arguments = {"--child-silent-after-fork=yes"};
|
||||
|
||||
handleSocketParameter("--xml-socket", d->xmlServer, &enableXml, &arguments);
|
||||
handleSocketParameter("--log-socket", d->logServer, &enableXml, &arguments);
|
||||
|
||||
if (enableXml)
|
||||
arguments << "--xml=yes";
|
||||
|
||||
return arguments;
|
||||
}
|
||||
|
||||
} // namespace Valgrind
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
#include <projectexplorer/runnables.h>
|
||||
|
||||
#include <utils/outputformat.h>
|
||||
#include <ssh/sshconnection.h>
|
||||
|
||||
#include <QProcess>
|
||||
|
||||
@@ -39,8 +38,6 @@ namespace Valgrind {
|
||||
|
||||
namespace XmlProtocol { class ThreadedParser; }
|
||||
|
||||
class ValgrindProcess;
|
||||
|
||||
class ValgrindRunner : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -49,17 +46,12 @@ public:
|
||||
explicit ValgrindRunner(QObject *parent = 0);
|
||||
~ValgrindRunner();
|
||||
|
||||
QString valgrindExecutable() const;
|
||||
void setValgrindExecutable(const QString &executable);
|
||||
QStringList valgrindArguments() const;
|
||||
QStringList fullValgrindArguments() const;
|
||||
void setValgrindArguments(const QStringList &toolArguments);
|
||||
void setDebuggee(const ProjectExplorer::StandardRunnable &debuggee);
|
||||
void setProcessChannelMode(QProcess::ProcessChannelMode mode);
|
||||
void setLocalServerAddress(const QHostAddress &localServerAddress);
|
||||
|
||||
void setDevice(const ProjectExplorer::IDevice::ConstPtr &device);
|
||||
ProjectExplorer::IDevice::ConstPtr device() const;
|
||||
|
||||
void waitForFinished() const;
|
||||
void setToolName(const QString &toolName);
|
||||
@@ -69,14 +61,10 @@ public:
|
||||
bool start();
|
||||
void stop();
|
||||
|
||||
ValgrindProcess *valgrindProcess() const;
|
||||
|
||||
XmlProtocol::ThreadedParser *parser() const;
|
||||
void disableXml();
|
||||
|
||||
signals:
|
||||
void logMessageReceived(const QByteArray &);
|
||||
|
||||
void processOutputReceived(const QString &, Utils::OutputFormat);
|
||||
void processErrorReceived(const QString &, QProcess::ProcessError);
|
||||
void valgrindStarted(qint64 pid);
|
||||
@@ -85,13 +73,9 @@ signals:
|
||||
|
||||
private:
|
||||
bool startServers();
|
||||
QStringList memcheckLogArguments() const;
|
||||
void onValgrindStarted(qint64 pid);
|
||||
|
||||
void processError(QProcess::ProcessError);
|
||||
void processFinished(int, QProcess::ExitStatus);
|
||||
|
||||
void localHostAddressRetrieved(const QHostAddress &localHostAddress);
|
||||
void xmlSocketConnected();
|
||||
void logSocketConnected();
|
||||
void readLogSocket();
|
||||
|
||||
@@ -27,7 +27,6 @@ QtcAutotest {
|
||||
name: "Other files from plugin"
|
||||
prefix: product.pluginDir + "/"
|
||||
files: [
|
||||
"valgrindprocess.h", "valgrindprocess.cpp",
|
||||
"valgrindrunner.h", "valgrindrunner.cpp",
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user