forked from qt-creator/qt-creator
Valgrind: Fix Memcheck startup on remote linux
Remote CallGrind is still dysfunctional. Change-Id: Ib9ab537dc068c94c7e61ac48b1a4b9d655ccb60f Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
@@ -468,12 +468,24 @@ static DebuggerRunConfigurationAspect *debuggerAspect(const RunControl *runContr
|
||||
return runControl->runConfiguration()->extraAspect<DebuggerRunConfigurationAspect>();
|
||||
}
|
||||
|
||||
static bool cppDebugging(const RunControl *runControl)
|
||||
{
|
||||
auto aspect = debuggerAspect(runControl);
|
||||
return aspect ? aspect->useCppDebugger() : true; // For cases like valgrind-with-gdb.
|
||||
}
|
||||
|
||||
static bool qmlDebugging(const RunControl *runControl)
|
||||
{
|
||||
auto aspect = debuggerAspect(runControl);
|
||||
return aspect ? aspect->useCppDebugger() : false; // For cases like valgrind-with-gdb.
|
||||
}
|
||||
|
||||
/// DebuggerRunTool
|
||||
|
||||
DebuggerRunTool::DebuggerRunTool(RunControl *runControl)
|
||||
: RunWorker(runControl),
|
||||
m_isCppDebugging(debuggerAspect(runControl)->useCppDebugger()),
|
||||
m_isQmlDebugging(debuggerAspect(runControl)->useQmlDebugger())
|
||||
m_isCppDebugging(cppDebugging(runControl)),
|
||||
m_isQmlDebugging(qmlDebugging(runControl))
|
||||
{
|
||||
setDisplayName("DebuggerRunTool");
|
||||
}
|
||||
|
@@ -192,15 +192,15 @@ void CallgrindController::getLocalDataFile()
|
||||
QString fileName = workingDir.isEmpty() ? baseFileName : (workingDir + QLatin1Char('/') + baseFileName);
|
||||
|
||||
if (!m_valgrindProc->isLocal()) {
|
||||
///TODO: error handling
|
||||
emit statusMessage(tr("Downloading remote profile data..."));
|
||||
m_ssh = m_valgrindProc->connection();
|
||||
// if there are files like callgrind.out.PID.NUM, set it to the most recent one of those
|
||||
QString cmd = QString::fromLatin1("ls -t %1* | head -n 1").arg(fileName);
|
||||
m_findRemoteFile = m_ssh->createRemoteProcess(cmd.toUtf8());
|
||||
connect(m_findRemoteFile.data(), &QSsh::SshRemoteProcess::readyReadStandardOutput,
|
||||
this, &CallgrindController::foundRemoteFile);
|
||||
m_findRemoteFile->start();
|
||||
// ///TODO: error handling
|
||||
// emit statusMessage(tr("Downloading remote profile data..."));
|
||||
// m_ssh = m_valgrindProc->connection();
|
||||
// // if there are files like callgrind.out.PID.NUM, set it to the most recent one of those
|
||||
// QString cmd = QString::fromLatin1("ls -t %1* | head -n 1").arg(fileName);
|
||||
// m_findRemoteFile = m_ssh->createRemoteProcess(cmd.toUtf8());
|
||||
// connect(m_findRemoteFile.data(), &QSsh::SshRemoteProcess::readyReadStandardOutput,
|
||||
// this, &CallgrindController::foundRemoteFile);
|
||||
// m_findRemoteFile->start();
|
||||
} else {
|
||||
QDir dir(workingDir, QString::fromLatin1("%1.*").arg(baseFileName), QDir::Time);
|
||||
QStringList outputFiles = dir.entryList();
|
||||
|
@@ -51,8 +51,33 @@ using namespace Valgrind::XmlProtocol;
|
||||
namespace Valgrind {
|
||||
namespace Internal {
|
||||
|
||||
class LocalAddressFinder : public RunWorker
|
||||
{
|
||||
public:
|
||||
LocalAddressFinder(RunControl *runControl, QHostAddress *localServerAddress)
|
||||
: RunWorker(runControl), connection(device()->sshParameters())
|
||||
{
|
||||
connect(&connection, &QSsh::SshConnection::connected, this, [this, localServerAddress] {
|
||||
*localServerAddress = connection.connectionInfo().localAddress;
|
||||
reportStarted();
|
||||
});
|
||||
connect(&connection, &QSsh::SshConnection::error, this, [this] {
|
||||
reportFailure();
|
||||
});
|
||||
}
|
||||
|
||||
void start() override
|
||||
{
|
||||
connection.connectToHost();
|
||||
}
|
||||
|
||||
QSsh::SshConnection connection;
|
||||
};
|
||||
|
||||
MemcheckToolRunner::MemcheckToolRunner(RunControl *runControl, bool withGdb)
|
||||
: ValgrindToolRunner(runControl), m_withGdb(withGdb)
|
||||
: ValgrindToolRunner(runControl),
|
||||
m_withGdb(withGdb),
|
||||
m_localServerAddress(QHostAddress::LocalHost)
|
||||
{
|
||||
setDisplayName("MemcheckToolRunner");
|
||||
connect(m_runner.parser(), &XmlProtocol::ThreadedParser::error,
|
||||
@@ -65,11 +90,15 @@ MemcheckToolRunner::MemcheckToolRunner(RunControl *runControl, bool withGdb)
|
||||
this, &MemcheckToolRunner::startDebugger);
|
||||
connect(&m_runner, &ValgrindRunner::logMessageReceived,
|
||||
this, &MemcheckToolRunner::appendLog);
|
||||
m_runner.disableXml();
|
||||
// m_runner.disableXml();
|
||||
} else {
|
||||
connect(m_runner.parser(), &XmlProtocol::ThreadedParser::internalError,
|
||||
this, &MemcheckToolRunner::internalParserError);
|
||||
}
|
||||
|
||||
// We need a real address to connect to from the outside.
|
||||
if (device()->type() != ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE)
|
||||
addDependency(new LocalAddressFinder(runControl, &m_localServerAddress));
|
||||
}
|
||||
|
||||
QString MemcheckToolRunner::progressTitle() const
|
||||
@@ -79,10 +108,7 @@ QString MemcheckToolRunner::progressTitle() const
|
||||
|
||||
void MemcheckToolRunner::start()
|
||||
{
|
||||
// MemcheckTool::engineStarting(this);
|
||||
|
||||
appendMessage(tr("Analyzing memory of %1").arg(executable()) + QLatin1Char('\n'),
|
||||
Utils::NormalMessageFormat);
|
||||
m_runner.setLocalServerAddress(m_localServerAddress);
|
||||
ValgrindToolRunner::start();
|
||||
}
|
||||
|
||||
@@ -149,12 +175,10 @@ void MemcheckToolRunner::startDebugger()
|
||||
sp.useContinueInsteadOfRun = true;
|
||||
sp.expectedSignals.append("SIGTRAP");
|
||||
|
||||
QString errorMessage;
|
||||
auto gdbRunControl = new RunControl(nullptr, ProjectExplorer::Constants::DEBUG_RUN_MODE);
|
||||
(void) new Debugger::DebuggerRunTool(gdbRunControl, sp, &errorMessage);
|
||||
connect(gdbRunControl, &RunControl::finished,
|
||||
gdbRunControl, &RunControl::deleteLater);
|
||||
gdbRunControl->initiateStart();
|
||||
auto gdbWorker = new Debugger::DebuggerRunTool(runControl());
|
||||
gdbWorker->setStartParameters(sp);
|
||||
gdbWorker->initiateStart();
|
||||
connect(runControl(), &RunControl::finished, gdbWorker, &RunControl::deleteLater);
|
||||
}
|
||||
|
||||
void MemcheckToolRunner::appendLog(const QByteArray &data)
|
||||
|
@@ -60,6 +60,7 @@ private:
|
||||
void appendLog(const QByteArray &data);
|
||||
|
||||
const bool m_withGdb;
|
||||
QHostAddress m_localServerAddress;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
@@ -106,6 +106,7 @@ void ValgrindToolRunner::stop()
|
||||
{
|
||||
m_isStopping = true;
|
||||
m_runner.stop();
|
||||
reportStopped(); // FIXME: Restrict to non-running scenarios?
|
||||
}
|
||||
|
||||
QString ValgrindToolRunner::executable() const
|
||||
|
@@ -39,26 +39,18 @@ using namespace ProjectExplorer;
|
||||
|
||||
namespace Valgrind {
|
||||
|
||||
ValgrindProcess::ValgrindProcess(const IDevice::ConstPtr &device,
|
||||
QObject *parent)
|
||||
ValgrindProcess::ValgrindProcess(const IDevice::ConstPtr &device, QObject *parent)
|
||||
: QObject(parent), m_device(device)
|
||||
{
|
||||
m_remote.m_connection = 0;
|
||||
m_remote.m_error = QProcess::UnknownError;
|
||||
m_pid = 0;
|
||||
}
|
||||
|
||||
ValgrindProcess::~ValgrindProcess()
|
||||
{
|
||||
if (m_remote.m_connection)
|
||||
QSsh::releaseConnection(m_remote.m_connection);
|
||||
}
|
||||
|
||||
void ValgrindProcess::setProcessChannelMode(QProcess::ProcessChannelMode mode)
|
||||
{
|
||||
if (isLocal())
|
||||
m_localProcess.setProcessChannelMode(mode);
|
||||
///TODO: remote support this by handling the mode internally
|
||||
m_valgrindProcess.setProcessChannelMode(mode);
|
||||
}
|
||||
|
||||
QString ValgrindProcess::workingDirectory() const
|
||||
@@ -68,10 +60,7 @@ QString ValgrindProcess::workingDirectory() const
|
||||
|
||||
bool ValgrindProcess::isRunning() const
|
||||
{
|
||||
if (isLocal())
|
||||
return m_localProcess.isRunning();
|
||||
else
|
||||
return m_remote.m_process && m_remote.m_process->isRunning();
|
||||
return m_valgrindProcess.isRunning();
|
||||
}
|
||||
|
||||
void ValgrindProcess::setValgrindExecutable(const QString &valgrindExecutable)
|
||||
@@ -91,94 +80,53 @@ void ValgrindProcess::setValgrindArguments(const QStringList &valgrindArguments)
|
||||
|
||||
void ValgrindProcess::close()
|
||||
{
|
||||
if (isLocal()) {
|
||||
m_localProcess.stop();
|
||||
} else {
|
||||
QTC_ASSERT(m_remote.m_connection->state() == QSsh::SshConnection::Connected, return);
|
||||
if (m_remote.m_process) {
|
||||
if (m_pid) {
|
||||
const QString killTemplate = QString::fromLatin1("kill -%2 %1" // kill
|
||||
).arg(m_pid);
|
||||
|
||||
const QString niceKill = killTemplate.arg(QLatin1String("SIGTERM"));
|
||||
const QString brutalKill = killTemplate.arg(QLatin1String("SIGKILL"));
|
||||
const QString remoteCall = niceKill + QLatin1String("; sleep 1; ") + brutalKill;
|
||||
|
||||
QSsh::SshRemoteProcess::Ptr cleanup = m_remote.m_connection->createRemoteProcess(remoteCall.toUtf8());
|
||||
cleanup->start();
|
||||
}
|
||||
}
|
||||
}
|
||||
m_valgrindProcess.stop();
|
||||
}
|
||||
|
||||
void ValgrindProcess::run(ApplicationLauncher::Mode runMode)
|
||||
{
|
||||
if (isLocal()) {
|
||||
connect(&m_localProcess, &ApplicationLauncher::processExited,
|
||||
connect(&m_valgrindProcess, &ApplicationLauncher::processExited,
|
||||
this, &ValgrindProcess::finished);
|
||||
connect(&m_localProcess, &ApplicationLauncher::processStarted,
|
||||
connect(&m_valgrindProcess, &ApplicationLauncher::processStarted,
|
||||
this, &ValgrindProcess::localProcessStarted);
|
||||
connect(&m_localProcess, &ApplicationLauncher::error,
|
||||
connect(&m_valgrindProcess, &ApplicationLauncher::error,
|
||||
this, &ValgrindProcess::error);
|
||||
connect(&m_localProcess, &ApplicationLauncher::appendMessage,
|
||||
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.runMode = runMode;
|
||||
valgrind.commandLineArguments = argumentString(Utils::HostOsInfo::hostOs());
|
||||
valgrind.workingDirectory = m_debuggee.workingDirectory;
|
||||
valgrind.environment = m_debuggee.environment;
|
||||
m_localProcess.start(valgrind);
|
||||
valgrind.runMode = runMode;
|
||||
valgrind.device = m_device;
|
||||
|
||||
if (isLocal()) {
|
||||
valgrind.commandLineArguments = argumentString(Utils::HostOsInfo::hostOs());
|
||||
m_valgrindProcess.start(valgrind);
|
||||
} else {
|
||||
// connect to host and wait for connection
|
||||
if (!m_remote.m_connection)
|
||||
m_remote.m_connection = QSsh::acquireConnection(m_device->sshParameters());
|
||||
|
||||
if (m_remote.m_connection->state() != QSsh::SshConnection::Connected) {
|
||||
connect(m_remote.m_connection, &QSsh::SshConnection::connected,
|
||||
this, &ValgrindProcess::connected);
|
||||
connect(m_remote.m_connection, &QSsh::SshConnection::error,
|
||||
this, &ValgrindProcess::handleError);
|
||||
if (m_remote.m_connection->state() == QSsh::SshConnection::Unconnected)
|
||||
m_remote.m_connection->connectToHost();
|
||||
} else {
|
||||
connected();
|
||||
}
|
||||
valgrind.commandLineArguments = argumentString(Utils::OsTypeLinux);
|
||||
m_valgrindProcess.start(valgrind, m_device);
|
||||
}
|
||||
}
|
||||
|
||||
QString ValgrindProcess::errorString() const
|
||||
{
|
||||
if (isLocal())
|
||||
return m_localProcess.errorString();
|
||||
else
|
||||
return m_remote.m_errorString;
|
||||
return m_valgrindProcess.errorString();
|
||||
}
|
||||
|
||||
QProcess::ProcessError ValgrindProcess::processError() const
|
||||
{
|
||||
if (isLocal())
|
||||
return m_localProcess.processError();
|
||||
else
|
||||
return m_remote.m_error;
|
||||
}
|
||||
|
||||
void ValgrindProcess::handleError(QSsh::SshError error)
|
||||
{
|
||||
if (!isLocal()) {
|
||||
switch (error) {
|
||||
case QSsh::SshTimeoutError:
|
||||
m_remote.m_error = QProcess::Timedout;
|
||||
break;
|
||||
default:
|
||||
m_remote.m_error = QProcess::FailedToStart;
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_remote.m_errorString = m_remote.m_connection->errorString();
|
||||
emit this->error(m_remote.m_error);
|
||||
return m_valgrindProcess.processError();
|
||||
}
|
||||
|
||||
qint64 ValgrindProcess::pid() const
|
||||
@@ -186,53 +134,16 @@ qint64 ValgrindProcess::pid() const
|
||||
return m_pid;
|
||||
}
|
||||
|
||||
void ValgrindProcess::handleRemoteStderr()
|
||||
void ValgrindProcess::handleRemoteStderr(const QByteArray &b)
|
||||
{
|
||||
const QString b = QString::fromUtf8(m_remote.m_process->readAllStandardError());
|
||||
if (!b.isEmpty())
|
||||
emit processOutput(b, Utils::StdErrFormat);
|
||||
emit processOutput(QString::fromUtf8(b), Utils::StdErrFormat);
|
||||
}
|
||||
|
||||
void ValgrindProcess::handleRemoteStdout()
|
||||
void ValgrindProcess::handleRemoteStdout(const QByteArray &b)
|
||||
{
|
||||
const QString b = QString::fromUtf8(m_remote.m_process->readAllStandardOutput());
|
||||
if (!b.isEmpty())
|
||||
emit processOutput(b, Utils::StdOutFormat);
|
||||
}
|
||||
|
||||
/// Remote
|
||||
void ValgrindProcess::connected()
|
||||
{
|
||||
QTC_ASSERT(m_remote.m_connection->state() == QSsh::SshConnection::Connected, return);
|
||||
|
||||
emit localHostAddressRetrieved(m_remote.m_connection->connectionInfo().localAddress);
|
||||
|
||||
// connected, run command
|
||||
QString cmd;
|
||||
|
||||
if (!m_debuggee.workingDirectory.isEmpty())
|
||||
cmd += QString::fromLatin1("cd '%1' && ").arg(m_debuggee.workingDirectory);
|
||||
|
||||
cmd += m_valgrindExecutable + QLatin1Char(' ') + argumentString(Utils::OsTypeLinux);
|
||||
|
||||
m_remote.m_process = m_remote.m_connection->createRemoteProcess(cmd.toUtf8());
|
||||
for (auto it = m_debuggee.environment.constBegin(); it != m_debuggee.environment.constEnd(); ++it)
|
||||
m_remote.m_process->addToEnvironment(it.key().toUtf8(), it.value().toUtf8());
|
||||
|
||||
connect(m_remote.m_process.data(), &QSsh::SshRemoteProcess::readyReadStandardError,
|
||||
this, &ValgrindProcess::handleRemoteStderr);
|
||||
connect(m_remote.m_process.data(), &QSsh::SshRemoteProcess::readyReadStandardOutput,
|
||||
this, &ValgrindProcess::handleRemoteStdout);
|
||||
connect(m_remote.m_process.data(), &QSsh::SshRemoteProcess::closed,
|
||||
this, &ValgrindProcess::closed);
|
||||
connect(m_remote.m_process.data(), &QSsh::SshRemoteProcess::started,
|
||||
this, &ValgrindProcess::remoteProcessStarted);
|
||||
m_remote.m_process->start();
|
||||
}
|
||||
|
||||
QSsh::SshConnection *ValgrindProcess::connection() const
|
||||
{
|
||||
return m_remote.m_connection;
|
||||
emit processOutput(QString::fromUtf8(b), Utils::StdOutFormat);
|
||||
}
|
||||
|
||||
bool ValgrindProcess::isLocal() const
|
||||
@@ -242,14 +153,12 @@ bool ValgrindProcess::isLocal() const
|
||||
|
||||
void ValgrindProcess::localProcessStarted()
|
||||
{
|
||||
m_pid = m_localProcess.applicationPID().pid();
|
||||
m_pid = m_valgrindProcess.applicationPID().pid();
|
||||
emit started();
|
||||
}
|
||||
|
||||
void ValgrindProcess::remoteProcessStarted()
|
||||
{
|
||||
QTC_ASSERT(m_remote.m_connection->state() == QSsh::SshConnection::Connected, return);
|
||||
|
||||
// find out what PID our process has
|
||||
|
||||
// NOTE: valgrind cloaks its name,
|
||||
@@ -259,34 +168,40 @@ void ValgrindProcess::remoteProcessStarted()
|
||||
// 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(QLatin1Char(' ')).last();
|
||||
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
|
||||
const QString cmd = QString::fromLatin1("sleep 1; ps ax" // list all processes with aliased name
|
||||
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_remote.m_findPID.data(), &QSsh::SshRemoteProcess::readyReadStandardError,
|
||||
// m_remote.m_findPID = m_remote.m_connection->createRemoteProcess(cmd.toUtf8());
|
||||
connect(&m_findPID, &ApplicationLauncher::remoteStderr,
|
||||
this, &ValgrindProcess::handleRemoteStderr);
|
||||
connect(m_remote.m_findPID.data(), &QSsh::SshRemoteProcess::readyReadStandardOutput,
|
||||
connect(&m_findPID, &ApplicationLauncher::remoteStdout,
|
||||
this, &ValgrindProcess::findPIDOutputReceived);
|
||||
m_remote.m_findPID->start();
|
||||
m_findPID.start(findPid, m_device);
|
||||
}
|
||||
|
||||
void ValgrindProcess::findPIDOutputReceived()
|
||||
void ValgrindProcess::findPIDOutputReceived(const QByteArray &out)
|
||||
{
|
||||
if (out.isEmpty())
|
||||
return;
|
||||
bool ok;
|
||||
m_pid = m_remote.m_findPID->readAllStandardOutput().trimmed().toLongLong(&ok);
|
||||
m_pid = out.trimmed().toLongLong(&ok);
|
||||
if (!ok) {
|
||||
m_pid = 0;
|
||||
m_remote.m_errorString = tr("Could not determine remote PID.");
|
||||
m_remote.m_error = QProcess::FailedToStart;
|
||||
emit ValgrindProcess::error(QProcess::FailedToStart);
|
||||
close();
|
||||
// m_remote.m_errorString = tr("Could not determine remote PID.");
|
||||
// emit ValgrindProcess::error(QProcess::FailedToStart);
|
||||
// close();
|
||||
} else {
|
||||
emit started();
|
||||
}
|
||||
@@ -301,20 +216,22 @@ QString ValgrindProcess::argumentString(Utils::OsType osType) const
|
||||
return arguments;
|
||||
}
|
||||
|
||||
void ValgrindProcess::closed(int status)
|
||||
void ValgrindProcess::closed(bool success)
|
||||
{
|
||||
QTC_ASSERT(m_remote.m_process, return);
|
||||
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);
|
||||
}
|
||||
// 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
|
||||
|
@@ -66,7 +66,6 @@ public:
|
||||
ProjectExplorer::IDevice::ConstPtr device() const { return m_device; }
|
||||
|
||||
qint64 pid() const;
|
||||
QSsh::SshConnection *connection() const;
|
||||
bool isLocal() const;
|
||||
|
||||
signals:
|
||||
@@ -74,33 +73,24 @@ signals:
|
||||
void finished(int, QProcess::ExitStatus);
|
||||
void error(QProcess::ProcessError);
|
||||
void processOutput(const QString &, Utils::OutputFormat format);
|
||||
void localHostAddressRetrieved(const QHostAddress &localHostAddress);
|
||||
|
||||
private:
|
||||
void handleRemoteStderr();
|
||||
void handleRemoteStdout();
|
||||
void handleError(QSsh::SshError);
|
||||
void handleRemoteStderr(const QByteArray &b);
|
||||
void handleRemoteStdout(const QByteArray &b);
|
||||
|
||||
void closed(int);
|
||||
void connected();
|
||||
void closed(bool success);
|
||||
void localProcessStarted();
|
||||
void remoteProcessStarted();
|
||||
void findPIDOutputReceived();
|
||||
void findPIDOutputReceived(const QByteArray &out);
|
||||
|
||||
QString argumentString(Utils::OsType osType) const;
|
||||
|
||||
ProjectExplorer::StandardRunnable m_debuggee;
|
||||
ProjectExplorer::ApplicationLauncher m_localProcess;
|
||||
qint64 m_pid;
|
||||
ProjectExplorer::ApplicationLauncher m_valgrindProcess;
|
||||
qint64 m_pid = 0;
|
||||
ProjectExplorer::IDevice::ConstPtr m_device;
|
||||
|
||||
struct Remote {
|
||||
QSsh::SshConnection *m_connection;
|
||||
QSsh::SshRemoteProcess::Ptr m_process;
|
||||
QString m_errorString;
|
||||
QProcess::ProcessError m_error;
|
||||
QSsh::SshRemoteProcess::Ptr m_findPID;
|
||||
} m_remote;
|
||||
ProjectExplorer::ApplicationLauncher m_findPID;
|
||||
|
||||
QSsh::SshConnectionParameters m_params;
|
||||
QString m_valgrindExecutable;
|
||||
|
@@ -39,6 +39,7 @@
|
||||
#include <ssh/sshremoteprocess.h>
|
||||
|
||||
#include <QEventLoop>
|
||||
#include <QNetworkInterface>
|
||||
#include <QTcpServer>
|
||||
#include <QTcpSocket>
|
||||
|
||||
@@ -49,6 +50,7 @@ namespace Valgrind {
|
||||
class ValgrindRunner::Private
|
||||
{
|
||||
public:
|
||||
QHostAddress localServerAddress;
|
||||
ValgrindProcess *process = nullptr;
|
||||
QProcess::ProcessChannelMode channelMode = QProcess::SeparateChannels;
|
||||
bool finished = false;
|
||||
@@ -125,6 +127,11 @@ void ValgrindRunner::setProcessChannelMode(QProcess::ProcessChannelMode mode)
|
||||
d->channelMode = mode;
|
||||
}
|
||||
|
||||
void ValgrindRunner::setLocalServerAddress(const QHostAddress &localServerAddress)
|
||||
{
|
||||
d->localServerAddress = localServerAddress;
|
||||
}
|
||||
|
||||
void ValgrindRunner::setDevice(const IDevice::ConstPtr &device)
|
||||
{
|
||||
d->device = device;
|
||||
@@ -152,10 +159,8 @@ void ValgrindRunner::setToolName(const QString &toolName)
|
||||
|
||||
bool ValgrindRunner::start()
|
||||
{
|
||||
// FIXME: Remove hack.
|
||||
if (d->tool == "memcheck"
|
||||
&& device()->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) {
|
||||
if (!startServers(QHostAddress::LocalHost))
|
||||
if (!d->localServerAddress.isNull()) {
|
||||
if (!startServers())
|
||||
return false;
|
||||
setValgrindArguments(memcheckLogArguments() + valgrindArguments());
|
||||
}
|
||||
@@ -176,8 +181,6 @@ bool ValgrindRunner::start()
|
||||
this, &ValgrindRunner::processFinished);
|
||||
QObject::connect(d->process, &ValgrindProcess::error,
|
||||
this, &ValgrindRunner::processError);
|
||||
QObject::connect(d->process, &ValgrindProcess::localHostAddressRetrieved,
|
||||
this, &ValgrindRunner::localHostAddressRetrieved);
|
||||
|
||||
d->process->run(d->debuggee.runMode);
|
||||
|
||||
@@ -214,14 +217,6 @@ void ValgrindRunner::processFinished(int ret, QProcess::ExitStatus status)
|
||||
emit processErrorReceived(errorString(), d->process->processError());
|
||||
}
|
||||
|
||||
void ValgrindRunner::localHostAddressRetrieved(const QHostAddress &localHostAddress)
|
||||
{
|
||||
if (startServers(localHostAddress)) {
|
||||
setValgrindArguments(memcheckLogArguments() + valgrindArguments());
|
||||
valgrindProcess()->setValgrindArguments(fullValgrindArguments());
|
||||
}
|
||||
}
|
||||
|
||||
QString ValgrindRunner::errorString() const
|
||||
{
|
||||
return d->process ? d->process->errorString() : QString();
|
||||
@@ -274,10 +269,10 @@ void ValgrindRunner::readLogSocket()
|
||||
emit logMessageReceived(d->logSocket->readAll());
|
||||
}
|
||||
|
||||
bool ValgrindRunner::startServers(const QHostAddress &localHostAddress)
|
||||
bool ValgrindRunner::startServers()
|
||||
{
|
||||
bool check = d->xmlServer.listen(localHostAddress);
|
||||
const QString ip = localHostAddress.toString();
|
||||
bool check = d->xmlServer.listen(d->localServerAddress);
|
||||
const QString ip = d->localServerAddress.toString();
|
||||
if (!check) {
|
||||
emit processErrorReceived(tr("XmlServer on %1:").arg(ip) + ' '
|
||||
+ d->xmlServer.errorString(), QProcess::FailedToStart );
|
||||
@@ -286,7 +281,7 @@ bool ValgrindRunner::startServers(const QHostAddress &localHostAddress)
|
||||
d->xmlServer.setMaxPendingConnections(1);
|
||||
connect(&d->xmlServer, &QTcpServer::newConnection,
|
||||
this, &ValgrindRunner::xmlSocketConnected);
|
||||
check = d->logServer.listen(localHostAddress);
|
||||
check = d->logServer.listen(d->localServerAddress);
|
||||
if (!check) {
|
||||
emit processErrorReceived(tr("LogServer on %1:").arg(ip) + ' '
|
||||
+ d->logServer.errorString(), QProcess::FailedToStart );
|
||||
@@ -298,16 +293,33 @@ bool ValgrindRunner::startServers(const QHostAddress &localHostAddress)
|
||||
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
|
||||
{
|
||||
QStringList arguments;
|
||||
if (!d->disableXml)
|
||||
arguments << QLatin1String("--xml=yes");
|
||||
arguments << QString::fromLatin1("--xml-socket=%1:%2")
|
||||
.arg(d->xmlServer.serverAddress().toString()).arg(d->xmlServer.serverPort())
|
||||
<< QLatin1String("--child-silent-after-fork=yes")
|
||||
<< QString::fromLatin1("--log-socket=%1:%2")
|
||||
.arg(d->logServer.serverAddress().toString()).arg(d->logServer.serverPort());
|
||||
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;
|
||||
}
|
||||
|
||||
|
@@ -56,6 +56,7 @@ public:
|
||||
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;
|
||||
@@ -84,7 +85,7 @@ signals:
|
||||
void extraProcessFinished();
|
||||
|
||||
private:
|
||||
bool startServers(const QHostAddress &localHostAddress);
|
||||
bool startServers();
|
||||
QStringList memcheckLogArguments() const;
|
||||
|
||||
void processError(QProcess::ProcessError);
|
||||
|
Reference in New Issue
Block a user