From cc6c3eab1a3b14e3156b22e9bb30cc33d8a032a6 Mon Sep 17 00:00:00 2001
From: hjk <qtc-committer@nokia.com>
Date: Tue, 5 Jun 2012 10:25:48 +0200
Subject: [PATCH] debugger: add Load Remote Core

Change-Id: I3ea5ddd608ff9e6764a995dc042466d436ca8474
Reviewed-by: hjk <qthjk@ovi.com>
---
 src/plugins/debugger/debugger.pro             |   2 +
 src/plugins/debugger/debugger.qbs             |   2 +
 src/plugins/debugger/debuggerconstants.h      |   1 +
 src/plugins/debugger/debuggerplugin.cpp       |  46 ++-
 src/plugins/debugger/debuggerrunner.cpp       |   1 +
 src/plugins/debugger/gdb/gdbengine.cpp        |   4 +-
 src/plugins/debugger/loadremotecoredialog.cpp | 269 ++++++++++++++++++
 src/plugins/debugger/loadremotecoredialog.h   |  73 +++++
 8 files changed, 391 insertions(+), 7 deletions(-)
 create mode 100644 src/plugins/debugger/loadremotecoredialog.cpp
 create mode 100644 src/plugins/debugger/loadremotecoredialog.h

diff --git a/src/plugins/debugger/debugger.pro b/src/plugins/debugger/debugger.pro
index beff0420f23..afe40429e6f 100644
--- a/src/plugins/debugger/debugger.pro
+++ b/src/plugins/debugger/debugger.pro
@@ -40,6 +40,7 @@ HEADERS += \
     debuggerstringutils.h \
     disassembleragent.h \
     disassemblerlines.h \
+    loadremotecoredialog.h \
     logwindow.h \
     memoryagent.h \
     moduleshandler.h \
@@ -93,6 +94,7 @@ SOURCES += \
     debuggerstreamops.cpp \
     disassembleragent.cpp \
     disassemblerlines.cpp \
+    loadremotecoredialog.cpp \
     logwindow.cpp \
     memoryagent.cpp \
     moduleshandler.cpp \
diff --git a/src/plugins/debugger/debugger.qbs b/src/plugins/debugger/debugger.qbs
index 9cf8b36f308..55c7b7a6e16 100644
--- a/src/plugins/debugger/debugger.qbs
+++ b/src/plugins/debugger/debugger.qbs
@@ -76,6 +76,8 @@ QtcPlugin {
         "disassembleragent.h",
         "disassemblerlines.cpp",
         "disassemblerlines.h",
+        "loadremotecoredialog.cpp",
+        "loadremotecoredialog.h",
         "localsandexpressionsoptionspage.ui",
         "localsandexpressionswindow.cpp",
         "localsandexpressionswindow.h",
diff --git a/src/plugins/debugger/debuggerconstants.h b/src/plugins/debugger/debuggerconstants.h
index 62b30ecaf6b..18da8fa782a 100644
--- a/src/plugins/debugger/debuggerconstants.h
+++ b/src/plugins/debugger/debuggerconstants.h
@@ -130,6 +130,7 @@ enum DebuggerStartMode
     AttachCore,            // Attach to a core file
     AttachToRemoteServer,  // Attach to a running gdbserver
     AttachToRemoteProcess, // Attach to a running remote process
+    LoadRemoteCore,    // Load a remote core file
     StartRemoteProcess,    // Start and attach to a remote process
     StartRemoteGdb,        // Start gdb itself remotely
     StartRemoteEngine      // Start ipc guest engine on other machine
diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp
index b4c7b57f537..86c9b0dfc65 100644
--- a/src/plugins/debugger/debuggerplugin.cpp
+++ b/src/plugins/debugger/debuggerplugin.cpp
@@ -63,6 +63,7 @@
 #include "watchutils.h"
 #include "debuggertooltipmanager.h"
 #include "localsandexpressionswindow.h"
+#include "loadremotecoredialog.h"
 
 #include "snapshothandler.h"
 #include "threadshandler.h"
@@ -115,19 +116,20 @@
 #include <utils/statuslabel.h>
 #include <utils/fileutils.h>
 
-#include <QTimer>
-#include <QtPlugin>
 #include <QComboBox>
 #include <QDockWidget>
 #include <QFileDialog>
+#include <QInputDialog>
 #include <QMenu>
 #include <QMessageBox>
 #include <QPushButton>
+#include <QTemporaryFile>
 #include <QTextBlock>
 #include <QTextCursor>
+#include <QTimer>
 #include <QToolButton>
+#include <QtPlugin>
 #include <QTreeWidget>
-#include <QInputDialog>
 
 #ifdef WITH_TESTS
 #include <QTest>
@@ -762,6 +764,7 @@ public slots:
     void startRemoteCdbSession();
     void startRemoteProcess();
     void startRemoteServer();
+    void loadRemoteCoreFile();
     bool queryRemoteParameters(DebuggerStartParameters &sp, bool useScript);
     void attachToRemoteServer();
     void attachToRemoteProcess();
@@ -1114,6 +1117,7 @@ public:
     QAction *m_attachToRemoteServerAction;
     QAction *m_startRemoteCdbAction;
     QAction *m_startRemoteLldbAction;
+    QAction *m_loadRemoteCoreAction;
     QAction *m_attachToLocalProcessAction;
     QAction *m_attachToCoreAction;
     QAction *m_detachAction;
@@ -1285,7 +1289,8 @@ void DebuggerPluginPrivate::maybeEnrichParameters(DebuggerStartParameters *sp)
     if (sp->sysroot.isEmpty() &&
               (sp->startMode == AttachToRemoteServer
             || sp->startMode == StartRemoteProcess
-            || sp->startMode == AttachToRemoteProcess)) {
+            || sp->startMode == AttachToRemoteProcess
+            || sp->startMode == LoadRemoteCore)) {
         // FIXME: Get from BaseQtVersion.
         sp->sysroot = QString::fromLocal8Bit(qgetenv("QTC_DEBUGGER_SYSROOT"));
         showMessage(QString::fromLatin1("USING QTC_DEBUGGER_SYSROOT %1")
@@ -1682,6 +1687,28 @@ void DebuggerPluginPrivate::gdbServerStarted(const QString &channel,
     showStatusMessage(tr("gdbserver is now listening at %1").arg(channel));
 }
 
+void DebuggerPluginPrivate::loadRemoteCoreFile()
+{
+    DebuggerStartParameters sp;
+    {
+        QTemporaryFile localCoreFile(QDir::tempPath() + "/remotecore-XXXXXX");
+        localCoreFile.open();
+        sp.coreFile = localCoreFile.fileName();
+    }
+    LoadRemoteCoreFileDialog dlg(mainWindow());
+    dlg.setLocalCoreFileName(sp.coreFile);
+    if (!dlg.exec())
+        return;
+    sp.displayName = tr("Core file \"%1\"").arg(sp.coreFile);
+    sp.startMode = AttachCore;
+    //sp.debuggerCommand = dlg.debuggerCommand();
+    //sp.toolChainAbi = dlg.abi();
+    sp.sysroot = dlg.sysroot();
+    //sp.overrideStartScript = dlg.overrideStartScript();
+    if (DebuggerRunControl *rc = createDebugger(sp))
+        startDebugger(rc);
+}
+
 void DebuggerPluginPrivate::attachToRemoteProcess()
 {
     PluginManager *pm = PluginManager::instance();
@@ -1689,7 +1716,7 @@ void DebuggerPluginPrivate::attachToRemoteProcess()
     QObject *rl = pm->getObjectByName(_("RemoteLinuxPlugin"));
     QTC_ASSERT(rl, return);
     QMetaObject::invokeMethod(rl, "attachToRemoteProcess", Qt::QueuedConnection);
-    // This will call back attachedtToProcess() below.
+    // This will call back attachedToProcess() below.
 }
 
 void DebuggerPluginPrivate::attachedToProcess(const QString &channel,
@@ -3102,6 +3129,10 @@ void DebuggerPluginPrivate::extensionsInitialized()
     act->setText(tr("Attach to Running Remote Process..."));
     connect(act, SIGNAL(triggered()), SLOT(attachToRemoteProcess()));
 
+    act = m_loadRemoteCoreAction = new QAction(this);
+    act->setText(tr("Load Remote Core File..."));
+    connect(act, SIGNAL(triggered()), SLOT(loadRemoteCoreFile()));
+
     act = m_attachToQmlPortAction = new QAction(this);
     act->setText(tr("Attach to QML Port..."));
     connect(act, SIGNAL(triggered()), SLOT(attachToQmlPort()));
@@ -3186,6 +3217,11 @@ void DebuggerPluginPrivate::extensionsInitialized()
     cmd->setDescription(tr("Attach to Remote Process"));
     mstart->addAction(cmd, Debugger::Constants::G_AUTOMATIC_REMOTE);
 
+    cmd = Core::ActionManager::registerAction(m_loadRemoteCoreAction,
+         "Debugger.LoadRemoteCore", globalcontext);
+    cmd->setDescription(tr("Load Remote Core File"));
+    mstart->addAction(cmd, Debugger::Constants::G_AUTOMATIC_REMOTE);
+
 #ifdef WITH_LLDB
     cmd = Core::ActionManager::registerAction(m_startRemoteLldbAction,
         "Debugger.RemoteLldb", globalcontext);
diff --git a/src/plugins/debugger/debuggerrunner.cpp b/src/plugins/debugger/debuggerrunner.cpp
index 64fb0f9a80e..3232b43cf2f 100644
--- a/src/plugins/debugger/debuggerrunner.cpp
+++ b/src/plugins/debugger/debuggerrunner.cpp
@@ -674,6 +674,7 @@ static QList<DebuggerEngineType> engineTypes(const DebuggerStartParameters &sp)
 
     if (sp.startMode != AttachToRemoteServer
             && sp.startMode != AttachToRemoteProcess
+            && sp.startMode != LoadRemoteCore
             && !sp.executable.isEmpty())
         result = enginesForExecutable(sp.executable);
     if (!result.isEmpty())
diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp
index a2b33bb3a6d..d127e1f78ae 100644
--- a/src/plugins/debugger/gdb/gdbengine.cpp
+++ b/src/plugins/debugger/gdb/gdbengine.cpp
@@ -5321,8 +5321,8 @@ bool GdbEngine::usesExecInterrupt() const
 
     // debuggerCore()->boolSetting(TargetAsync)
     DebuggerStartMode mode = startParameters().startMode;
-    return (mode == AttachToRemoteServer
-        || mode == AttachToRemoteProcess) && debuggerCore()->boolSetting(TargetAsync);
+    return (mode == AttachToRemoteServer || mode == AttachToRemoteProcess)
+        && debuggerCore()->boolSetting(TargetAsync);
 }
 
 void GdbEngine::scheduleTestResponse(int testCase, const QByteArray &response)
diff --git a/src/plugins/debugger/loadremotecoredialog.cpp b/src/plugins/debugger/loadremotecoredialog.cpp
new file mode 100644
index 00000000000..ab6ef56680e
--- /dev/null
+++ b/src/plugins/debugger/loadremotecoredialog.cpp
@@ -0,0 +1,269 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**************************************************************************/
+
+#include "loadremotecoredialog.h"
+#include "debuggerstartparameters.h"
+#include "debuggerconstants.h"
+#include "debuggercore.h"
+
+#include <coreplugin/icore.h>
+#include <projectexplorer/abi.h>
+#include <projectexplorer/devicesupport/devicemanager.h>
+#include <projectexplorer/devicesupport/devicemanagermodel.h>
+#include <ssh/sshconnection.h>
+#include <ssh/sshremoteprocessrunner.h>
+#include <ssh/sftpfilesystemmodel.h>
+#include <utils/historycompleter.h>
+#include <utils/pathchooser.h>
+#include <utils/portlist.h>
+#include <utils/qtcassert.h>
+
+#include <QCoreApplication>
+#include <QDebug>
+#include <QDir>
+#include <QRegExp>
+
+#include <QButtonGroup>
+#include <QComboBox>
+#include <QFileDialog>
+#include <QFormLayout>
+#include <QGridLayout>
+#include <QGroupBox>
+#include <QHeaderView>
+#include <QLineEdit>
+#include <QMessageBox>
+#include <QPushButton>
+#include <QRadioButton>
+#include <QScrollArea>
+#include <QStandardItemModel>
+#include <QTableView>
+#include <QTextBrowser>
+#include <QTreeView>
+
+using namespace Core;
+using namespace ProjectExplorer;
+using namespace QSsh;
+using namespace Utils;
+
+namespace Debugger {
+namespace Internal {
+
+///////////////////////////////////////////////////////////////////////
+//
+// LoadRemoteCoreFileDialog
+//
+///////////////////////////////////////////////////////////////////////
+
+class LoadRemoteCoreFileDialogPrivate
+{
+public:
+    DeviceManagerModel *deviceManagerModel;
+
+    QComboBox *deviceComboBox;
+    QTreeView *fileSystemView;
+    QPushButton *loadCoreFileButton;
+    QTextBrowser *textBrowser;
+    QPushButton *closeButton;
+    PathChooser *sysrootPathChooser;
+
+    QSettings *settings;
+    QString remoteCommandLine;
+    QString remoteExecutable;
+    QString localCoreFile;
+
+    SftpFileSystemModel *fileSystemModel;
+    SftpJobId sftpJobId;
+};
+
+LoadRemoteCoreFileDialog::LoadRemoteCoreFileDialog(QWidget *parent)
+    : QDialog(parent), d(new LoadRemoteCoreFileDialogPrivate)
+{
+    setWindowTitle(tr("Select Remote Core File"));
+
+    d->settings = ICore::settings();
+
+    d->deviceComboBox = new QComboBox(this);
+
+    d->sysrootPathChooser = new PathChooser(this);
+    d->sysrootPathChooser->setExpectedKind(PathChooser::Directory);
+    d->sysrootPathChooser->setPromptDialogTitle(tr("Select Sysroot"));
+    d->sysrootPathChooser->setPath(d->settings->value(QLatin1String("LastSysroot")).toString());
+
+    d->fileSystemModel = new SftpFileSystemModel(this);
+
+    //executablePathChooser = new PathChooser(q);
+    //executablePathChooser->setExpectedKind(PathChooser::File);
+    //executablePathChooser->setPromptDialogTitle(tr("Select Executable"));
+    //executablePathChooser->setPath(settings->value(LastLocalExecutable).toString());
+
+    d->fileSystemView = new QTreeView(this);
+    d->fileSystemView->setSortingEnabled(true);
+    d->fileSystemView->header()->setDefaultSectionSize(100);
+    d->fileSystemView->header()->setStretchLastSection(true);
+    d->fileSystemView->setSelectionMode(QAbstractItemView::SingleSelection);
+    d->fileSystemView->setModel(d->fileSystemModel);
+
+    d->loadCoreFileButton = new QPushButton(this);
+    d->loadCoreFileButton->setText(tr("&Load Selected Core File"));
+
+    d->closeButton = new QPushButton(this);
+    d->closeButton->setText(tr("Close"));
+
+    d->textBrowser = new QTextBrowser(this);
+    d->textBrowser->setEnabled(false);
+
+    QFormLayout *formLayout = new QFormLayout();
+    formLayout->addRow(tr("Device:"), d->deviceComboBox);
+    formLayout->addRow(tr("Sysroot:"), d->sysrootPathChooser);
+
+    QHBoxLayout *horizontalLayout2 = new QHBoxLayout();
+    horizontalLayout2->addStretch(1);
+    horizontalLayout2->addWidget(d->loadCoreFileButton);
+    horizontalLayout2->addWidget(d->closeButton);
+
+    formLayout->addRow(d->fileSystemView);
+    formLayout->addRow(d->textBrowser);
+    formLayout->addRow(horizontalLayout2);
+    setLayout(formLayout);
+
+    d->deviceManagerModel = new DeviceManagerModel(DeviceManager::instance(), this);
+
+    QObject::connect(d->closeButton, SIGNAL(clicked()), this, SLOT(reject()));
+
+    d->deviceComboBox->setModel(d->deviceManagerModel);
+    d->deviceComboBox->setCurrentIndex(d->settings->value(QLatin1String("LastDevice")).toInt());
+
+    if (d->deviceManagerModel->rowCount() == 0) {
+        d->fileSystemView->setEnabled(false);
+    } else {
+        d->fileSystemView->setSelectionBehavior(QAbstractItemView::SelectRows);
+        connect(d->fileSystemView->selectionModel(),
+            SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
+            SLOT(updateButtons()));
+        connect(d->sysrootPathChooser, SIGNAL(changed(QString)),
+                SLOT(updateButtons()));
+        connect(d->loadCoreFileButton, SIGNAL(clicked()), SLOT(selectCoreFile()));
+        connect(d->deviceComboBox, SIGNAL(currentIndexChanged(int)),
+            SLOT(attachToDevice(int)));
+        updateButtons();
+        attachToDevice(d->deviceComboBox->currentIndex());
+    }
+}
+
+LoadRemoteCoreFileDialog::~LoadRemoteCoreFileDialog()
+{
+    delete d;
+}
+
+void LoadRemoteCoreFileDialog::setLocalCoreFileName(const QString &fileName)
+{
+    d->localCoreFile = fileName;
+}
+
+QString LoadRemoteCoreFileDialog::localCoreFileName() const
+{
+    return d->localCoreFile;
+}
+
+QString LoadRemoteCoreFileDialog::sysroot() const
+{
+    return d->sysrootPathChooser->path();
+}
+
+void LoadRemoteCoreFileDialog::attachToDevice(int modelIndex)
+{
+    IDevice::ConstPtr device = d->deviceManagerModel->device(modelIndex);
+    if (!device)
+        return;
+    connect(d->fileSystemModel, SIGNAL(sftpOperationFailed(QString)),
+            SLOT(handleSftpOperationFailed(QString)));
+    connect(d->fileSystemModel, SIGNAL(connectionError(QString)),
+            SLOT(handleConnectionError(QString)));
+    d->fileSystemModel->setSshConnection(device->sshParameters());
+    //d->fileSystemModel->setRootDirectory(d->settings->value(QLatin1String("LastSftpRoot")).toString());
+}
+
+void LoadRemoteCoreFileDialog::handleSftpOperationFailed(const QString &errorMessage)
+{
+    d->textBrowser->append(errorMessage);
+    //reject();
+}
+
+void LoadRemoteCoreFileDialog::handleConnectionError(const QString &errorMessage)
+{
+    d->textBrowser->append(errorMessage);
+    //reject();
+}
+
+void LoadRemoteCoreFileDialog::handleSftpOperationFinished(QSsh::SftpJobId, const QString &error)
+{
+    if (error.isEmpty()) {
+        d->textBrowser->append(tr("Download of Core File succeeded."));
+        accept();
+    } else {
+        d->textBrowser->append(error);
+        //reject();
+    }
+}
+
+void LoadRemoteCoreFileDialog::handleRemoteError(const QString &errorMessage)
+{
+    d->textBrowser->append(errorMessage);
+    updateButtons();
+}
+
+void LoadRemoteCoreFileDialog::selectCoreFile()
+{
+    const QModelIndexList &indexes =
+            d->fileSystemView->selectionModel()->selectedIndexes();
+    if (indexes.empty())
+        return;
+
+    d->loadCoreFileButton->setEnabled(false);
+    d->fileSystemView->setEnabled(false);
+
+    d->settings->setValue(QLatin1String("LastSysroot"), d->sysrootPathChooser->path());
+    d->settings->setValue(QLatin1String("LastDevice"), d->deviceComboBox->currentIndex());
+    d->settings->setValue(QLatin1String("LastSftpRoot"), d->fileSystemModel->rootDirectory());
+
+    connect(d->fileSystemModel, SIGNAL(sftpOperationFinished(QSsh::SftpJobId,QString)),
+            SLOT(handleSftpOperationFinished(QSsh::SftpJobId,QString)));
+    d->sftpJobId = d->fileSystemModel->downloadFile(indexes.at(0), d->localCoreFile);
+}
+
+void LoadRemoteCoreFileDialog::updateButtons()
+{
+    d->loadCoreFileButton->setEnabled(d->fileSystemView->selectionModel()->hasSelection());
+}
+
+} // namespace Internal
+} // namespace Debugger
diff --git a/src/plugins/debugger/loadremotecoredialog.h b/src/plugins/debugger/loadremotecoredialog.h
new file mode 100644
index 00000000000..272b1a3e223
--- /dev/null
+++ b/src/plugins/debugger/loadremotecoredialog.h
@@ -0,0 +1,73 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**************************************************************************/
+
+#ifndef DEBUGGER_LOADREMOTECOREDIALOG_H
+#define DEBUGGER_LOADREMOTECOREDIALOG_H
+
+#include <ssh/sftpdefs.h>
+
+#include <QDialog>
+
+namespace Debugger {
+namespace Internal {
+
+class LoadRemoteCoreFileDialogPrivate;
+
+class LoadRemoteCoreFileDialog : public QDialog
+{
+    Q_OBJECT
+
+public:
+    explicit LoadRemoteCoreFileDialog(QWidget *parent);
+    ~LoadRemoteCoreFileDialog();
+
+    void setLocalCoreFileName(const QString &fileName);
+    QString localCoreFileName() const;
+    QString sysroot() const;
+
+private slots:
+    void handleSftpOperationFinished(QSsh::SftpJobId, const QString &error);
+    void handleSftpOperationFailed(const QString &errorMessage);
+    void handleConnectionError(const QString &errorMessage);
+    void updateButtons();
+    void attachToDevice(int modelIndex);
+    void handleRemoteError(const QString &errorMessage);
+    void selectCoreFile();
+
+private:
+    LoadRemoteCoreFileDialogPrivate *d;
+};
+
+} // namespace Debugger
+} // namespace Internal
+
+#endif // DEBUGGER_LOADREMOTECOREDIALOG_H
-- 
GitLab