diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp
index ebb839fc907bedb05b19dacbbb1b398152ae8dff..2195708fd9f3dd4f242275b1a1074feedf9822ce 100644
--- a/src/plugins/debugger/debuggerruncontrol.cpp
+++ b/src/plugins/debugger/debuggerruncontrol.cpp
@@ -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");
 }
diff --git a/src/plugins/valgrind/callgrind/callgrindcontroller.cpp b/src/plugins/valgrind/callgrind/callgrindcontroller.cpp
index faf1c980b4d6d7e96d7b5810b9a95f7cf84d87c9..b28c5a98af77e1a92a13d0e59153a50e4c568e1f 100644
--- a/src/plugins/valgrind/callgrind/callgrindcontroller.cpp
+++ b/src/plugins/valgrind/callgrind/callgrindcontroller.cpp
@@ -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();
diff --git a/src/plugins/valgrind/memcheckengine.cpp b/src/plugins/valgrind/memcheckengine.cpp
index d6f44798e295dbfbe256c7839c9c61c9daee5475..918abbcb2a3a9e5b91060056b2f8bf25d4f3f279 100644
--- a/src/plugins/valgrind/memcheckengine.cpp
+++ b/src/plugins/valgrind/memcheckengine.cpp
@@ -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)
diff --git a/src/plugins/valgrind/memcheckengine.h b/src/plugins/valgrind/memcheckengine.h
index e77d4ec02d6dfd51268ff256ad8d796c63fc3716..40d97ac7038154fe69bd8ed16de2459f211cfb7c 100644
--- a/src/plugins/valgrind/memcheckengine.h
+++ b/src/plugins/valgrind/memcheckengine.h
@@ -60,6 +60,7 @@ private:
     void appendLog(const QByteArray &data);
 
     const bool m_withGdb;
+    QHostAddress m_localServerAddress;
 };
 
 } // namespace Internal
diff --git a/src/plugins/valgrind/valgrindengine.cpp b/src/plugins/valgrind/valgrindengine.cpp
index 649a1d75948257b84701cf4dbdbc1baa5ea9e25f..b87728ba4829fce8abe46671741a6fee8ced48ad 100644
--- a/src/plugins/valgrind/valgrindengine.cpp
+++ b/src/plugins/valgrind/valgrindengine.cpp
@@ -106,6 +106,7 @@ void ValgrindToolRunner::stop()
 {
     m_isStopping = true;
     m_runner.stop();
+    reportStopped(); // FIXME: Restrict to non-running scenarios?
 }
 
 QString ValgrindToolRunner::executable() const
diff --git a/src/plugins/valgrind/valgrindprocess.cpp b/src/plugins/valgrind/valgrindprocess.cpp
index 5f45c90bb155cd517b0e517862b01fb97b631213..e0fa607c282e6b0cc08ed892bf5aa7fc1585fa5e 100644
--- a/src/plugins/valgrind/valgrindprocess.cpp
+++ b/src/plugins/valgrind/valgrindprocess.cpp
@@ -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)
 {
+    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()) {
-        connect(&m_localProcess, &ApplicationLauncher::processExited,
-                this, &ValgrindProcess::finished);
-        connect(&m_localProcess, &ApplicationLauncher::processStarted,
-                this, &ValgrindProcess::localProcessStarted);
-        connect(&m_localProcess, &ApplicationLauncher::error,
-                this, &ValgrindProcess::error);
-        connect(&m_localProcess, &ApplicationLauncher::appendMessage,
-                this, &ValgrindProcess::processOutput);
-
-        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);
-
+        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
-                                            " | 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,
+    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_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);
-
-    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);
-    }
+    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
diff --git a/src/plugins/valgrind/valgrindprocess.h b/src/plugins/valgrind/valgrindprocess.h
index b85214e09543c8a84c54616d4fadd62d6fda1540..50182eb1a2e6c66c41480c9da7d89550e59c62df 100644
--- a/src/plugins/valgrind/valgrindprocess.h
+++ b/src/plugins/valgrind/valgrindprocess.h
@@ -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;
diff --git a/src/plugins/valgrind/valgrindrunner.cpp b/src/plugins/valgrind/valgrindrunner.cpp
index 5f348cb3536ef6bd79bba09f5d1ce4dbee8433f4..e85a872aef8d998150c1e5e792c3921cb979d01f 100644
--- a/src/plugins/valgrind/valgrindrunner.cpp
+++ b/src/plugins/valgrind/valgrindrunner.cpp
@@ -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;
 }
 
diff --git a/src/plugins/valgrind/valgrindrunner.h b/src/plugins/valgrind/valgrindrunner.h
index 9732d0935674ecbed53c8c7384559e526ce53442..371ec7d5790f8d63a36112e76718e35b4d3d75f6 100644
--- a/src/plugins/valgrind/valgrindrunner.h
+++ b/src/plugins/valgrind/valgrindrunner.h
@@ -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);