From 3d84da2b4dce03139b7c52e9b9a73144e34898f0 Mon Sep 17 00:00:00 2001
From: hjk <qtc-committer@nokia.com>
Date: Wed, 6 May 2009 16:11:42 +0200
Subject: [PATCH] debugger: initial work to start a remote gdbserver

---
 src/plugins/debugger/debuggerdialogs.cpp  |  11 +++
 src/plugins/debugger/debuggerdialogs.h    |   2 +
 src/plugins/debugger/debuggermanager.cpp  |   3 +
 src/plugins/debugger/debuggermanager.h    |   2 +
 src/plugins/debugger/gdbengine.cpp        | 105 ++++++++++++++++++----
 src/plugins/debugger/gdbengine.h          |   4 +
 src/plugins/debugger/startremotedialog.ui |  10 +++
 tests/manual/fakevim/runremotely.sh       |  15 ++++
 8 files changed, 133 insertions(+), 19 deletions(-)
 create mode 100755 tests/manual/fakevim/runremotely.sh

diff --git a/src/plugins/debugger/debuggerdialogs.cpp b/src/plugins/debugger/debuggerdialogs.cpp
index 79bb783f296..f30ee2c4172 100644
--- a/src/plugins/debugger/debuggerdialogs.cpp
+++ b/src/plugins/debugger/debuggerdialogs.cpp
@@ -312,6 +312,8 @@ StartRemoteDialog::StartRemoteDialog(QWidget *parent)
 {
     m_ui->setupUi(this);
     m_ui->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
+    m_ui->serverStartScript->setExpectedKind(Core::Utils::PathChooser::File);
+    m_ui->serverStartScript->setPromptDialogTitle(tr("Select Executable"));
     
     connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
     connect(m_ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
@@ -354,6 +356,15 @@ QString StartRemoteDialog::remoteArchitecture() const
     return m_ui->architectureComboBox->itemText(index);
 }
 
+void StartRemoteDialog::setServerStartScript(const QString &scriptName)
+{
+    m_ui->serverStartScript->setPath(scriptName);
+}
+
+QString StartRemoteDialog::serverStartScript() const
+{
+    return m_ui->serverStartScript->path();
+}
 
 ///////////////////////////////////////////////////////////////////////
 //
diff --git a/src/plugins/debugger/debuggerdialogs.h b/src/plugins/debugger/debuggerdialogs.h
index 04f1e65ceda..403e094d4cc 100644
--- a/src/plugins/debugger/debuggerdialogs.h
+++ b/src/plugins/debugger/debuggerdialogs.h
@@ -114,6 +114,8 @@ public:
     void setRemoteArchitectures(const QStringList &arches);
     QString remoteChannel() const;
     QString remoteArchitecture() const;
+    void setServerStartScript(const QString &scriptName);
+    QString serverStartScript() const;
 
 private:
     Ui::StartRemoteDialog *m_ui;
diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp
index 9942b002886..cbcd0f76f3e 100644
--- a/src/plugins/debugger/debuggermanager.cpp
+++ b/src/plugins/debugger/debuggermanager.cpp
@@ -936,14 +936,17 @@ void DebuggerManager::startNewDebugger(DebuggerRunControl *runControl)
         dlg.setRemoteArchitectures(arches);
         dlg.setRemoteChannel(configValue(_("LastRemoteChannel")).toString());
         dlg.setRemoteArchitecture(configValue(_("LastRemoteArchtecture")).toString());
+        dlg.setServerStartScript(configValue(_("LastServerStartScript")).toString());
         if (dlg.exec() != QDialog::Accepted) {  
             runControl->debuggingFinished();
             return;
         }
         setConfigValue(_("LastRemoteChannel"), dlg.remoteChannel());
         setConfigValue(_("LastRemoteArchitecture"), dlg.remoteArchitecture());
+        setConfigValue(_("LastServerStartScript"), dlg.serverStartScript());
         m_remoteChannel = dlg.remoteChannel();
         m_remoteArchitecture = dlg.remoteArchitecture();
+        m_serverStartScript = dlg.serverStartScript();
         break;
     }
     }
diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h
index 66336caace8..78d73c2db2b 100644
--- a/src/plugins/debugger/debuggermanager.h
+++ b/src/plugins/debugger/debuggermanager.h
@@ -359,8 +359,10 @@ public:
     QString m_dumperLib;
     int m_attachedPID;
     bool m_useTerminal;
+    // for remote debugging
     QString m_remoteChannel;
     QString m_remoteArchitecture;
+    QString m_serverStartScript;
 
 private:
     void init();
diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp
index f80b76b5f19..94809204e91 100644
--- a/src/plugins/debugger/gdbengine.cpp
+++ b/src/plugins/debugger/gdbengine.cpp
@@ -131,22 +131,28 @@ GdbEngine::~GdbEngine()
 void GdbEngine::initializeConnections()
 {
     // Gdb Process interaction
-    connect(&m_gdbProc, SIGNAL(error(QProcess::ProcessError)), this,
-        SLOT(gdbProcError(QProcess::ProcessError)));
-    connect(&m_gdbProc, SIGNAL(readyReadStandardOutput()), this,
-        SLOT(readGdbStandardOutput()));
-    connect(&m_gdbProc, SIGNAL(readyReadStandardError()), this,
-        SLOT(readGdbStandardError()));
-    connect(&m_gdbProc, SIGNAL(finished(int, QProcess::ExitStatus)), q,
-        SLOT(exitDebugger()));
-
-    connect(&m_stubProc, SIGNAL(processError(QString)), SLOT(stubError(QString)));
-    connect(&m_stubProc, SIGNAL(processStarted()), SLOT(stubStarted()));
-    connect(&m_stubProc, SIGNAL(wrapperStopped()), q, SLOT(exitDebugger()));
+    connect(&m_gdbProc, SIGNAL(error(QProcess::ProcessError)),
+        this, SLOT(gdbProcError(QProcess::ProcessError)));
+    connect(&m_gdbProc, SIGNAL(readyReadStandardOutput()),
+        this, SLOT(readGdbStandardOutput()));
+    connect(&m_gdbProc, SIGNAL(readyReadStandardError()),
+        this, SLOT(readGdbStandardError()));
+    connect(&m_gdbProc, SIGNAL(finished(int, QProcess::ExitStatus)),
+        q, SLOT(exitDebugger()));
+
+    connect(&m_stubProc, SIGNAL(processError(QString)),
+        this, SLOT(stubError(QString)));
+    connect(&m_stubProc, SIGNAL(processStarted()),
+        this, SLOT(stubStarted()));
+    connect(&m_stubProc, SIGNAL(wrapperStopped()),
+        q, SLOT(exitDebugger()));
+
+    connect(&m_uploadProc, SIGNAL(error(QProcess::ProcessError)),
+        this, SLOT(uploadProcError(QProcess::ProcessError)));
 
     // Output
     connect(&m_outputCollector, SIGNAL(byteDelivery(QByteArray)),
-            SLOT(readDebugeeOutput(QByteArray)));
+        this, SLOT(readDebugeeOutput(QByteArray)));
 
     connect(this, SIGNAL(gdbOutputAvailable(QString,QString)),
         q, SLOT(showDebuggerOutput(QString,QString)),
@@ -225,6 +231,43 @@ void GdbEngine::gdbProcError(QProcess::ProcessError error)
     q->exitDebugger();
 }
 
+void GdbEngine::uploadProcError(QProcess::ProcessError error)
+{
+    QString msg;
+    switch (error) {
+        case QProcess::FailedToStart:
+            msg = tr("The upload process failed to start. Either the "
+                "invoked script '%1' is missing, or you may have insufficient "
+                "permissions to invoke the program.")
+                .arg(theDebuggerStringSetting(GdbLocation));
+            break;
+        case QProcess::Crashed:
+            msg = tr("The upload process crashed some time after starting "
+                "successfully.");
+            break;
+        case QProcess::Timedout:
+            msg = tr("The last waitFor...() function timed out. "
+                "The state of QProcess is unchanged, and you can try calling "
+                "waitFor...() again.");
+            break;
+        case QProcess::WriteError:
+            msg = tr("An error occurred when attempting to write "
+                "to the upload process. For example, the process may not be running, "
+                "or it may have closed its input channel.");
+            break;
+        case QProcess::ReadError:
+            msg = tr("An error occurred when attempting to read from "
+                "the upload process. For example, the process may not be running.");
+            break;
+        default:
+            msg = tr("An unknown error in the upload process occurred. "
+                "This is the default return value of error().");
+    }
+
+    q->showStatusMessage(msg);
+    QMessageBox::critical(q->mainWindow(), tr("Error"), msg);
+}
+
 #if 0
 static void dump(const char *first, const char *middle, const QString & to)
 {
@@ -907,6 +950,7 @@ void GdbEngine::handleAqcuiredInferior()
     #endif
     if (theDebuggerBoolSetting(ListSourceFiles))
         reloadSourceFiles();
+
     tryLoadDebuggingHelpers();
 
     #ifndef Q_OS_MAC
@@ -1358,7 +1402,18 @@ bool GdbEngine::startDebugger()
     if (q->startMode() == AttachCore || q->startMode() == AttachExternal) {
         // nothing to do
     } else if (q->startMode() == StartRemote) {
-        // nothing to do
+        // Start the remote server
+        if (q->m_serverStartScript.isEmpty()) {
+            q->showStatusMessage(_("No server start script given. "
+                "Assuming server runs already."));
+        } else {
+            if (!q->m_workingDir.isEmpty())
+                m_uploadProc.setWorkingDirectory(q->m_workingDir);
+            if (!q->m_environment.isEmpty())
+                m_uploadProc.setEnvironment(q->m_environment);
+            m_uploadProc.start(_("/bin/sh ") + q->m_serverStartScript);
+            m_uploadProc.waitForStarted();
+        }
     } else if (q->m_useTerminal) {
         m_stubProc.stop(); // We leave the console open, so recycle it now.
 
@@ -2795,7 +2850,7 @@ bool GdbEngine::hasDebuggingHelperForType(const QString &type) const
     if (!theDebuggerBoolSetting(UseDebuggingHelpers))
         return false;
 
-    if (q->startMode() == AttachCore) {
+    if (!startModeAllowsDumpers()) {
         // "call" is not possible in gdb when looking at core files
         return type == __("QString") || type.endsWith(__("::QString"))
             || type == __("QStringList") || type.endsWith(__("::QStringList"));
@@ -2834,7 +2889,7 @@ void GdbEngine::runDirectDebuggingHelper(const WatchData &data, bool dumpChildre
 
 void GdbEngine::runDebuggingHelper(const WatchData &data0, bool dumpChildren)
 {
-    if (q->startMode() == AttachCore) {
+    if (!startModeAllowsDumpers()) {
         runDirectDebuggingHelper(data0, dumpChildren);
         return;
     }
@@ -3832,6 +3887,9 @@ void GdbEngine::tryLoadDebuggingHelpers()
     if (m_debuggingHelperState != DebuggingHelperUninitialized)
         return;
 
+    if (!startModeAllowsDumpers())
+        return;
+
     PENDING_DEBUG("TRY LOAD CUSTOM DUMPERS");
     m_debuggingHelperState = DebuggingHelperUnavailable;
     if (!qq->qtDumperLibraryEnabled())
@@ -3881,9 +3939,18 @@ void GdbEngine::tryLoadDebuggingHelpers()
 
 void GdbEngine::recheckDebuggingHelperAvailability()
 {
-    // retreive list of dumpable classes
-    execCommand(_("call (void*)qDumpObjectData440(1,%1+1,0,0,0,0,0,0)"));
-    execCommand(_("p (char*)&qDumpOutBuffer"), CB(handleQueryDebuggingHelper));
+    if (startModeAllowsDumpers()) {
+        // retreive list of dumpable classes
+        execCommand(_("call (void*)qDumpObjectData440(1,%1+1,0,0,0,0,0,0)"));
+        execCommand(_("p (char*)&qDumpOutBuffer"), CB(handleQueryDebuggingHelper));
+    }
+}
+
+bool GdbEngine::startModeAllowsDumpers() const
+{
+    return q->startMode() == StartInternal
+        || q->startMode() == StartExternal
+        || q->startMode() == AttachExternal;
 }
 
 IDebuggerEngine *createGdbEngine(DebuggerManager *parent, QList<Core::IOptionsPage*> *opts)
diff --git a/src/plugins/debugger/gdbengine.h b/src/plugins/debugger/gdbengine.h
index 87523ae703b..a3767ce45c4 100644
--- a/src/plugins/debugger/gdbengine.h
+++ b/src/plugins/debugger/gdbengine.h
@@ -191,6 +191,7 @@ private slots:
     void readDebugeeOutput(const QByteArray &data);
     void stubStarted();
     void stubError(const QString &msg);
+    void uploadProcError(QProcess::ProcessError error);
 
 private:
     int terminationIndex(const QByteArray &buffer, int &length);
@@ -226,6 +227,7 @@ private:
     QByteArray m_inbuffer;
 
     QProcess m_gdbProc;
+    QProcess m_uploadProc;
 
     Core::Utils::ConsoleProcess m_stubProc;
 
@@ -354,6 +356,8 @@ private:
         const WatchData &parent);
     void setWatchDataType(WatchData &data, const GdbMi &mi);
     void setLocals(const QList<GdbMi> &locals);
+   
+    bool startModeAllowsDumpers() const;
 
     QString m_editedData;
     int m_pendingRequests;
diff --git a/src/plugins/debugger/startremotedialog.ui b/src/plugins/debugger/startremotedialog.ui
index 5f616cf90b2..af0bc703237 100644
--- a/src/plugins/debugger/startremotedialog.ui
+++ b/src/plugins/debugger/startremotedialog.ui
@@ -49,6 +49,16 @@
      <item row="1" column="1">
       <widget class="QComboBox" name="architectureComboBox"/>
      </item>
+     <item row="2" column="0">
+      <widget class="QLabel" name="serverStartScriptLabel">
+       <property name="text">
+        <string>Server start script</string>
+       </property>
+      </widget>
+     </item>
+     <item row="2" column="1">
+       <widget class="Core::Utils::PathChooser" name="serverStartScript" native="true"/>
+     </item>
     </layout>
    </item>
    <item>
diff --git a/tests/manual/fakevim/runremotely.sh b/tests/manual/fakevim/runremotely.sh
new file mode 100755
index 00000000000..927c8aec9d9
--- /dev/null
+++ b/tests/manual/fakevim/runremotely.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+account=berlin@hd
+sourcedir=/data5/dev/creator/tests/manual/fakevim/
+exename=fakevim
+targetdir=/tmp/run-${exename}
+
+executable=${sourcedir}/${exename}
+qtlibs=`ldd ${executable} | grep libQt | sed -e 's/^.*=> \(.*\) (.*)$/\1/'`
+
+ssh ${account} "mkdir -p ${targetdir}"
+scp ${executable} ${qtlibs} ${account}:${targetdir}
+ssh ${account} "chrpath -r ${targetdir} ${targetdir}/*"
+ssh ${account} "gdbserver localhost:5555 ${targetdir}/${exename}"
+ssh ${account} "rm ${targetdir}/* ; rmdir ${targetdir}"
+
-- 
GitLab