diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 342967cd50ba9ebe4da4d7d345176def0d2c2044..8aa7e399c011e07a0af31c2ccba790d099d88cc4 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -924,7 +924,8 @@ public slots: QVariant configValue(const QString &name) const { return settings()->value(name); } - DebuggerRunControl *createDebugger(const DebuggerStartParameters &sp); + DebuggerRunControl *createDebugger(const DebuggerStartParameters &sp, + ProjectExplorer::RunConfiguration *rc = 0); void startDebugger(ProjectExplorer::RunControl *runControl); void displayDebugger(ProjectExplorer::RunControl *runControl); @@ -1921,9 +1922,10 @@ void DebuggerPluginPrivate::showToolTip(ITextEditor *editor, const QPoint &point } DebuggerRunControl * -DebuggerPluginPrivate::createDebugger(const DebuggerStartParameters &sp) +DebuggerPluginPrivate::createDebugger(const DebuggerStartParameters &sp, + ProjectExplorer::RunConfiguration *rc) { - return m_debuggerRunControlFactory->create(sp); + return m_debuggerRunControlFactory->create(sp, rc); } void DebuggerPluginPrivate::displayDebugger(ProjectExplorer::RunControl *rc) @@ -2643,9 +2645,10 @@ QWidget *DebuggerPlugin::mainWindow() const } DebuggerRunControl * -DebuggerPlugin::createDebugger(const DebuggerStartParameters &sp) +DebuggerPlugin::createDebugger(const DebuggerStartParameters &sp, + ProjectExplorer::RunConfiguration *rc) { - return instance()->d->createDebugger(sp); + return instance()->d->createDebugger(sp, rc); } void DebuggerPlugin::startDebugger(ProjectExplorer::RunControl *runControl) diff --git a/src/plugins/debugger/debuggerplugin.h b/src/plugins/debugger/debuggerplugin.h index f1429f509458fb1c35596ed0d3370ce7850c5a05..2cb55de74d5140e5d654ae57584fffdd5ca2c02b 100644 --- a/src/plugins/debugger/debuggerplugin.h +++ b/src/plugins/debugger/debuggerplugin.h @@ -44,6 +44,7 @@ class Snapshot; } namespace ProjectExplorer { +class RunConfiguration; class RunControl; } @@ -82,7 +83,8 @@ public: void readSettings(); void writeSettings() const; - static DebuggerRunControl *createDebugger(const DebuggerStartParameters &sp); + static DebuggerRunControl *createDebugger(const DebuggerStartParameters &sp, + ProjectExplorer::RunConfiguration *rc = 0); static void startDebugger(ProjectExplorer::RunControl *runControl); static void displayDebugger(ProjectExplorer::RunControl *runControl); diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 01a7faa59a51fc9a2b6797dfa258c26950b8e1dd..d0a363d3934cc5733c9d236531cba800a3eb2a22 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -179,7 +179,6 @@ static QByteArray parsePlainConsoleStream(const GdbResponse &response) GdbEngine::GdbEngine(const DebuggerStartParameters &startParameters) : DebuggerEngine(startParameters) { - m_gdbAdapter = 0; m_progress = 0; m_commandTimer = new QTimer(this); @@ -189,6 +188,7 @@ GdbEngine::GdbEngine(const DebuggerStartParameters &startParameters) // Needs no resetting in initializeVariables() m_busy = false; initializeVariables(); + m_gdbAdapter = createAdapter(); connect(theDebuggerAction(AutoDerefPointers), SIGNAL(valueChanged(QVariant)), this, SLOT(setAutoDerefPointers(QVariant))); @@ -1754,7 +1754,6 @@ void GdbEngine::setupEngine() //qDebug() << "GDB START DEBUGGER"; QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state()); QTC_ASSERT(m_debuggingHelperState == DebuggingHelperUninitialized, /**/); - QTC_ASSERT(m_gdbAdapter == 0, /**/); m_progress = new QFutureInterface<void>(); m_progress->setProgressRange(0, 100); @@ -1763,7 +1762,6 @@ void GdbEngine::setupEngine() fp->setKeepOnFinish(false); m_progress->reportStarted(); - m_gdbAdapter = createAdapter(); //qDebug() << "CREATED ADAPTER: " << m_gdbAdapter; if (m_gdbAdapter->dumperHandling() != AbstractGdbAdapter::DumperNotAvailable) { diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index d47fef51d1f4190ea6a96e0ca886917538070a3c..b2619c285a930509504a4c697d65d0b2f0716266 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -83,13 +83,14 @@ enum DebuggingHelperState }; -class GdbEngine : public DebuggerEngine +class DEBUGGER_EXPORT GdbEngine : public DebuggerEngine { Q_OBJECT public: explicit GdbEngine(const DebuggerStartParameters &startParameters); ~GdbEngine(); + AbstractGdbAdapter *gdbAdapter() const { return m_gdbAdapter; } private: friend class AbstractGdbAdapter; diff --git a/src/plugins/debugger/gdb/remotegdbserveradapter.cpp b/src/plugins/debugger/gdb/remotegdbserveradapter.cpp index e4f83f1523ab3daa9debd5d5226527d2d06c8ee6..fd1b564929fb38525860c607fc51fcc42fce3e44 100644 --- a/src/plugins/debugger/gdb/remotegdbserveradapter.cpp +++ b/src/plugins/debugger/gdb/remotegdbserveradapter.cpp @@ -62,6 +62,8 @@ RemoteGdbServerAdapter::RemoteGdbServerAdapter(GdbEngine *engine, int toolChainT this, SLOT(readUploadStandardOutput())); connect(&m_uploadProc, SIGNAL(readyReadStandardError()), this, SLOT(readUploadStandardError())); + connect(&m_uploadProc, SIGNAL(finished(int)), this, + SLOT(uploadProcFinished())); } AbstractGdbAdapter::DumperHandling RemoteGdbServerAdapter::dumperHandling() const @@ -86,22 +88,13 @@ void RemoteGdbServerAdapter::startAdapter() { QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state()); showMessage(_("TRYING TO START ADAPTER")); - - // FIXME: make asynchroneous - // Start the remote server if (startParameters().serverStartScript.isEmpty()) { - showMessage(_("No server start script given. " - "Assuming server runs already."), StatusBar); + showMessage(_("No server start script given. "), StatusBar); + emit requestSetup(); } else { m_uploadProc.start(_("/bin/sh ") + startParameters().serverStartScript); m_uploadProc.waitForStarted(); } - - if (!m_engine->startGdb(QStringList(), startParameters().debuggerCommand)) - // FIXME: cleanup missing - return; - - m_engine->handleAdapterStarted(); } void RemoteGdbServerAdapter::uploadProcError(QProcess::ProcessError error) @@ -154,6 +147,15 @@ void RemoteGdbServerAdapter::readUploadStandardError() showMessage(msg, AppError); } +void RemoteGdbServerAdapter::uploadProcFinished() +{ + if (m_uploadProc.exitStatus() == QProcess::NormalExit + && m_uploadProc.exitCode() == 0) + handleSetupDone(); + else + handleSetupFailed(m_uploadProc.errorString()); +} + void RemoteGdbServerAdapter::setupInferior() { QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state()); @@ -245,5 +247,20 @@ void RemoteGdbServerAdapter::shutdownAdapter() m_engine->notifyAdapterShutdownOk(); } +void RemoteGdbServerAdapter::handleSetupDone() +{ + QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state()); + + if (m_engine->startGdb(QStringList(), startParameters().debuggerCommand)) + m_engine->handleAdapterStarted(); +} + +void RemoteGdbServerAdapter::handleSetupFailed(const QString &reason) +{ + QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state()); + + m_engine->handleAdapterStartFailed(reason); +} + } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/gdb/remotegdbserveradapter.h b/src/plugins/debugger/gdb/remotegdbserveradapter.h index 7d8ed8f38ddf4245bdea976c82e6fae266453399..fa4f8c6d2de7b747a787bd93a1cd86b5e5741b92 100644 --- a/src/plugins/debugger/gdb/remotegdbserveradapter.h +++ b/src/plugins/debugger/gdb/remotegdbserveradapter.h @@ -43,12 +43,14 @@ namespace Internal { // /////////////////////////////////////////////////////////////////////// -class RemoteGdbServerAdapter : public AbstractGdbAdapter +class DEBUGGER_EXPORT RemoteGdbServerAdapter : public AbstractGdbAdapter { Q_OBJECT public: RemoteGdbServerAdapter(GdbEngine *engine, int toolChainType, QObject *parent = 0); + void handleSetupDone(); + void handleSetupFailed(const QString &reason); private: DumperHandling dumperHandling() const; @@ -62,9 +64,14 @@ private: AbstractGdbProcess *gdbProc() { return &m_gdbProc; } +signals: + void requestSetup(); + +private: Q_SLOT void readUploadStandardOutput(); Q_SLOT void readUploadStandardError(); Q_SLOT void uploadProcError(QProcess::ProcessError error); + Q_SLOT void uploadProcFinished(); void handleSetTargetAsync(const GdbResponse &response); void handleFileExecAndSymbols(const GdbResponse &response); diff --git a/src/plugins/debugger/gdb/remoteplaingdbadapter.cpp b/src/plugins/debugger/gdb/remoteplaingdbadapter.cpp index 5121504797d5f0d8061007f77fe1ff126cb9ad63..6fc15c1c8f57c2fb8afeca6678f523f4ee9abf44 100644 --- a/src/plugins/debugger/gdb/remoteplaingdbadapter.cpp +++ b/src/plugins/debugger/gdb/remoteplaingdbadapter.cpp @@ -48,13 +48,7 @@ void RemotePlainGdbAdapter::startAdapter() QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state()); showMessage(QLatin1String("TRYING TO START ADAPTER")); - if (!startParameters().workingDirectory.isEmpty()) - m_gdbProc.setWorkingDirectory(startParameters().workingDirectory); - if (!startParameters().environment.isEmpty()) - m_gdbProc.setEnvironment(startParameters().environment); - - if (m_engine->startGdb(QStringList(), m_engine->startParameters().debuggerCommand)) - m_engine->handleAdapterStarted(); + emit requestSetup(); } void RemotePlainGdbAdapter::interruptInferior() @@ -97,5 +91,25 @@ void RemotePlainGdbAdapter::shutdownAdapter() m_engine->notifyAdapterShutdownOk(); } +void RemotePlainGdbAdapter::handleSetupDone() +{ + QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state()); + + if (!startParameters().workingDirectory.isEmpty()) + m_gdbProc.setWorkingDirectory(startParameters().workingDirectory); + if (!startParameters().environment.isEmpty()) + m_gdbProc.setEnvironment(startParameters().environment); + + if (m_engine->startGdb(QStringList(), m_engine->startParameters().debuggerCommand)) + m_engine->handleAdapterStarted(); +} + +void RemotePlainGdbAdapter::handleSetupFailed(const QString &reason) +{ + QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state()); + + m_engine->handleAdapterStartFailed(reason); +} + } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/gdb/remoteplaingdbadapter.h b/src/plugins/debugger/gdb/remoteplaingdbadapter.h index f6a6bf32cd03c172138cac101d2818d5046817ef..43080a95b1ebad2e4de22e840ef2a6c4eb34ccdf 100644 --- a/src/plugins/debugger/gdb/remoteplaingdbadapter.h +++ b/src/plugins/debugger/gdb/remoteplaingdbadapter.h @@ -36,13 +36,18 @@ namespace Debugger { namespace Internal { -class RemotePlainGdbAdapter : public AbstractPlainGdbAdapter +class DEBUGGER_EXPORT RemotePlainGdbAdapter : public AbstractPlainGdbAdapter { Q_OBJECT public: friend class RemoteGdbProcess; RemotePlainGdbAdapter(GdbEngine *engine, QObject *parent = 0); + void handleSetupDone(); + void handleSetupFailed(const QString &reason); + +signals: + void requestSetup(); private: void startAdapter(); diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemodebugsupport.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemodebugsupport.cpp new file mode 100644 index 0000000000000000000000000000000000000000..edece998b3ce6d06201c0dd04af27d7c1c6922ea --- /dev/null +++ b/src/plugins/qt4projectmanager/qt-maemo/maemodebugsupport.cpp @@ -0,0 +1,292 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Creator. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "maemodebugsupport.h" + +#include "maemodeployables.h" +#include "maemodeploystep.h" +#include "maemoglobal.h" +#include "maemorunconfiguration.h" +#include "maemosshrunner.h" + +#include <coreplugin/ssh/sftpchannel.h> +#include <debugger/debuggerengine.h> +#include <debugger/debuggerplugin.h> +#include <debugger/debuggerrunner.h> +#include <debugger/gdb/remotegdbserveradapter.h> +#include <debugger/gdb/remoteplaingdbadapter.h> +#include <projectexplorer/toolchain.h> + +#include <QtCore/QFileInfo> + +using namespace Core; +using namespace Debugger; +using namespace Debugger::Internal; +using namespace ProjectExplorer; + +namespace Qt4ProjectManager { +namespace Internal { + +RunControl *MaemoDebugSupport::createDebugRunControl(MaemoRunConfiguration *runConfig) +{ + DebuggerStartParameters params; + const MaemoDeviceConfig &devConf = runConfig->deviceConfig(); +#ifdef USE_GDBSERVER + params.startMode = AttachToRemote; + params.executable = runConfig->localExecutableFilePath(); + params.debuggerCommand = runConfig->gdbCmd(); + params.remoteChannel = devConf.server.host + QLatin1Char(':') + + gdbServerPort(runConfig, devConf); + params.remoteArchitecture = QLatin1String("arm"); +#else + params.startMode = StartRemoteGdb; + params.executable = runConfig->remoteExecutableFilePath(); + params.debuggerCommand = MaemoGlobal::remoteCommandPrefix(runConfig->remoteExecutableFilePath()) + + QLatin1String(" /usr/bin/gdb"); + params.connParams = devConf.server; +#endif + params.processArgs = runConfig->arguments(); + params.sysRoot = runConfig->sysRoot(); + params.toolChainType = ToolChain::GCC_MAEMO; + params.dumperLibrary = runConfig->dumperLib(); + params.remoteDumperLib = uploadDir(devConf).toUtf8() + '/' + + QFileInfo(runConfig->dumperLib()).fileName().toUtf8(); + + DebuggerRunControl * const debuggerRunControl + = DebuggerPlugin::createDebugger(params, runConfig); + new MaemoDebugSupport(runConfig, debuggerRunControl); + return debuggerRunControl; +} + +MaemoDebugSupport::MaemoDebugSupport(MaemoRunConfiguration *runConfig, + DebuggerRunControl *runControl) + : QObject(runControl), m_runControl(runControl), m_runConfig(runConfig), + m_deviceConfig(m_runConfig->deviceConfig()), + m_runner(new MaemoSshRunner(this, m_runConfig)) +{ + GdbEngine *engine = qobject_cast<GdbEngine *>(m_runControl->engine()); + Q_ASSERT(engine); + m_gdbAdapter = qobject_cast<GdbAdapter *>(engine->gdbAdapter()); + Q_ASSERT(m_gdbAdapter); + connect(m_gdbAdapter, SIGNAL(requestSetup()), this, + SLOT(handleAdapterSetupRequested())); + connect(m_runControl, SIGNAL(finished()), this, + SLOT(handleDebuggingFinished())); +#ifdef USE_GDBSERVER + m_runner->addProcsToKill(QStringList() << QLatin1String("gdbserver")); +#else + m_runner->addProcsToKill(QStringList() << QLatin1String("gdb")); +#endif +} + +MaemoDebugSupport::~MaemoDebugSupport() {} + +void MaemoDebugSupport::handleAdapterSetupRequested() +{ + if (!m_deviceConfig.isValid()) { + handleAdapterSetupFailed(tr("No device configuration set for run configuration.")); + return; + } + m_adapterStarted = false; + m_stopped = false; + m_runControl->showMessage(tr("Preparing remote side ..."), AppStuff); + disconnect(m_runner, 0, this, 0); + connect(m_runner, SIGNAL(error(QString)), this, + SLOT(handleSshError(QString))); + connect(m_runner, SIGNAL(readyForExecution()), this, + SLOT(startExecution())); + m_runner->start(); +} + +void MaemoDebugSupport::handleSshError(const QString &error) +{ + if (!m_stopped && !m_adapterStarted) + handleAdapterSetupFailed(error); +} + +void MaemoDebugSupport::startExecution() +{ + if (m_stopped) + return; + + const QString &dumperLib = m_runConfig->dumperLib(); + if (!dumperLib.isEmpty() + && m_runConfig->deployStep()->currentlyNeedsDeployment(m_deviceConfig.server.host, + MaemoDeployable(dumperLib, uploadDir(m_deviceConfig)))) { + m_uploader = m_runner->connection()->createSftpChannel(); + connect(m_uploader.data(), SIGNAL(initialized()), this, + SLOT(handleSftpChannelInitialized())); + connect(m_uploader.data(), SIGNAL(initializationFailed(QString)), this, + SLOT(handleSftpChannelInitializationFailed(QString))); + connect(m_uploader.data(), SIGNAL(finished(Core::SftpJobId, QString)), + this, SLOT(handleSftpJobFinished(Core::SftpJobId, QString))); + m_uploader->initialize(); + } else { + startDebugging(); + } +} + +void MaemoDebugSupport::handleSftpChannelInitialized() +{ + if (m_stopped) + return; + + const QString dumperLib = m_runConfig->dumperLib(); + const QString fileName = QFileInfo(dumperLib).fileName(); + const QString remoteFilePath = uploadDir(m_deviceConfig) + '/' + fileName; + m_uploadJob = m_uploader->uploadFile(dumperLib, remoteFilePath, + SftpOverwriteExisting); + if (m_uploadJob == SftpInvalidJob) { + handleAdapterSetupFailed(tr("Upload failed: Could not open file '%1'") + .arg(dumperLib)); + } else { + m_runControl->showMessage(tr("Started uploading debugging helpers ('%1').") + .arg(dumperLib), AppStuff); + } +} + +void MaemoDebugSupport::handleSftpChannelInitializationFailed(const QString &error) +{ + if (m_stopped) + return; + + handleAdapterSetupFailed(error); +} + +void MaemoDebugSupport::handleSftpJobFinished(Core::SftpJobId job, + const QString &error) +{ + if (m_stopped) + return; + + if (job != m_uploadJob) { + qWarning("Warning: Unknown debugging helpers upload job %d finished.", job); + return; + } + + if (!error.isEmpty()) { + handleAdapterSetupFailed(tr("Could not upload debugging helpers: %1.") + .arg(error)); + } else { + m_runConfig->deployStep()->setDeployed(m_deviceConfig.server.host, + MaemoDeployable(m_runConfig->dumperLib(), uploadDir(m_deviceConfig))); + m_runControl->showMessage(tr("Finished uploading debugging helpers."), AppStuff); + startDebugging(); + } + m_uploadJob = SftpInvalidJob; +} + +void MaemoDebugSupport::startDebugging() +{ +#ifdef USE_GDBSERVER + connect(m_runner, SIGNAL(remoteErrorOutput(QByteArray)), this, + SLOT(handleRemoteErrorOutput(QByteArray))); + connect(m_runner, SIGNAL(remoteOutput(QByteArray)), this, + SLOT(handleRemoteOutput(QByteArray))); + connect(m_runner, SIGNAL(remoteProcessStarted()), this, + SLOT(handleRemoteProcessStarted())); + const QString &remoteExe = m_runConfig->remoteExecutableFilePath(); + m_runner->startExecution(QString::fromLocal8Bit("%1 gdbserver :%2 %3 %4") + .arg(MaemoGlobal::remoteCommandPrefix(remoteExe)) + .arg(gdbServerPort(m_runConfig, m_deviceConfig)) + .arg(remoteExe).arg(m_runConfig->arguments() + .join(QLatin1String(" "))).toUtf8()); +#else + stopSsh(); + handleAdapterSetupDone(); +#endif +} + +void MaemoDebugSupport::handleRemoteProcessStarted() +{ + handleAdapterSetupDone(); +} + +void MaemoDebugSupport::handleDebuggingFinished() +{ + m_stopped = true; + stopSsh(); +} + +void MaemoDebugSupport::handleRemoteOutput(const QByteArray &output) +{ + m_runControl->showMessage(QString::fromUtf8(output), AppOutput); +} + +void MaemoDebugSupport::handleRemoteErrorOutput(const QByteArray &output) +{ + m_runControl->showMessage(QString::fromUtf8(output), AppOutput); +} + +void MaemoDebugSupport::stopSsh() +{ + disconnect(m_runner, 0, this, 0); + if (m_uploader) { + disconnect(m_uploader.data(), 0, this, 0); + m_uploader->closeChannel(); + } + m_runner->stop(); +} + +void MaemoDebugSupport::handleAdapterSetupFailed(const QString &error) +{ + m_gdbAdapter->handleSetupFailed(tr("Initial setup failed: %1").arg(error)); + m_stopped = true; + stopSsh(); +} + +void MaemoDebugSupport::handleAdapterSetupDone() +{ + m_adapterStarted = true; + m_gdbAdapter->handleSetupDone(); +} + +QString MaemoDebugSupport::gdbServerPort(const MaemoRunConfiguration *rc, + const MaemoDeviceConfig &devConf) +{ + // During configuration we don't know which port to use, so we display + // something in the config dialog, but we will make sure we use + // the right port from the information file. + return devConf.type == MaemoDeviceConfig::Physical + ? QString::number(devConf.gdbServerPort) + : rc->runtimeGdbServerPort(); +} + +QString MaemoDebugSupport::uploadDir(const MaemoDeviceConfig &devConf) +{ + return MaemoGlobal::homeDirOnDevice(devConf.server.uname); +} + +} // namespace Internal +} // namespace Qt4ProjectManager diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemodebugsupport.h b/src/plugins/qt4projectmanager/qt-maemo/maemodebugsupport.h new file mode 100644 index 0000000000000000000000000000000000000000..b0c44e14f107831a0ffe5ed2970433806cb05748 --- /dev/null +++ b/src/plugins/qt4projectmanager/qt-maemo/maemodebugsupport.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Creator. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MAEMODEBUGSUPPORT_H +#define MAEMODEBUGSUPPORT_H + +#include "maemodeviceconfigurations.h" + +#include <coreplugin/ssh/sftpdefs.h> + +#include <QtCore/QObject> +#include <QtCore/QSharedPointer> + +#define USE_GDBSERVER + +namespace Core { class SftpChannel; } + +namespace Debugger { +class DebuggerRunControl; +namespace Internal { +class RemoteGdbServerAdapter; +class RemotePlainGdbAdapter; +} +} + +namespace ProjectExplorer { class RunControl; } + +namespace Qt4ProjectManager { +namespace Internal { + +class MaemoRunConfiguration; +class MaemoSshRunner; + +class MaemoDebugSupport : public QObject +{ + Q_OBJECT +public: + static ProjectExplorer::RunControl *createDebugRunControl(MaemoRunConfiguration *runConfig); + + MaemoDebugSupport(MaemoRunConfiguration *runConfig, + Debugger::DebuggerRunControl *runControl); + ~MaemoDebugSupport(); + + static QString gdbServerPort(const MaemoRunConfiguration *rc, + const MaemoDeviceConfig &devConf); + static QString uploadDir(const MaemoDeviceConfig &devConf); + +private slots: + void handleAdapterSetupRequested(); + void handleSshError(const QString &error); + void startExecution(); + void handleSftpChannelInitialized(); + void handleSftpChannelInitializationFailed(const QString &error); + void handleSftpJobFinished(Core::SftpJobId job, const QString &error); + void handleRemoteProcessStarted(); + void handleDebuggingFinished(); + void handleRemoteOutput(const QByteArray &output); + void handleRemoteErrorOutput(const QByteArray &output); + +private: + void stopSsh(); + void handleAdapterSetupFailed(const QString &error); + void handleAdapterSetupDone(); + void startDebugging(); + + Debugger::DebuggerRunControl *m_runControl; + MaemoRunConfiguration * const m_runConfig; + const MaemoDeviceConfig m_deviceConfig; + MaemoSshRunner * const m_runner; + + +#ifdef USE_GDBSERVER + typedef Debugger::Internal::RemoteGdbServerAdapter GdbAdapter; +#else + typedef Debugger::Internal::RemotePlainGdbAdapter GdbAdapter; +#endif + GdbAdapter *m_gdbAdapter; + + QSharedPointer<Core::SftpChannel> m_uploader; + Core::SftpJobId m_uploadJob; + bool m_adapterStarted; + bool m_stopped; +}; + +} // namespace Internal +} // namespace Qt4ProjectManager + +#endif // MAEMODEBUGSUPPORT_H diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemoglobal.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemoglobal.cpp index 9a797fd7ad9883490538331d0f0324a7854c96ac..fcacff25858bb85b1f39cf07840c8e4baa3bf7c1 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemoglobal.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemoglobal.cpp @@ -46,5 +46,11 @@ QString MaemoGlobal::remoteSudo() return QLatin1String("/usr/lib/mad-developer/devrootsh"); } +QString MaemoGlobal::remoteCommandPrefix(const QString &commandFilePath) +{ + return QString::fromLocal8Bit("%1 chmod a+x %2 && source /etc/profile && DISPLAY=:0.0 ") + .arg(remoteSudo()).arg(commandFilePath); +} + } // namespace Internal } // namespace Qt4ProjectManager diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemoglobal.h b/src/plugins/qt4projectmanager/qt-maemo/maemoglobal.h index 7a8b2ff8df9838a23605c051ee55b8ae7a607eea..ad8f5c6f0f533a28daf037b663632fc7992a7095 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemoglobal.h +++ b/src/plugins/qt4projectmanager/qt-maemo/maemoglobal.h @@ -46,6 +46,7 @@ class MaemoGlobal public: static QString homeDirOnDevice(const QString &uname); static QString remoteSudo(); + static QString remoteCommandPrefix(const QString &commandFilePath); template<class T> static T *buildStep(const ProjectExplorer::BuildConfiguration *bc) { diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.cpp index 1dc98468182eb2c515b9a41743ee989afa32fc74..515e2230414d506fd204797e76bbfc817de279ba 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.cpp @@ -39,21 +39,10 @@ #include "maemorunconfiguration.h" #include "maemosshrunner.h" -#include <coreplugin/icore.h> -#include <coreplugin/ssh/sftpchannel.h> -#include <coreplugin/ssh/sshconnection.h> -#include <debugger/debuggerengine.h> -#include <debugger/debuggerplugin.h> -#include <debugger/debuggerrunner.h> -#include <extensionsystem/pluginmanager.h> #include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/toolchain.h> -#include <qt4projectmanager/qt4buildconfiguration.h> #include <utils/qtcassert.h> -#include <QtCore/QFileInfo> -#include <QtCore/QStringBuilder> - #include <QtGui/QMessageBox> using namespace Core; @@ -61,15 +50,11 @@ using namespace Core; namespace Qt4ProjectManager { namespace Internal { -#define USE_GDBSERVER - using ProjectExplorer::RunConfiguration; using ProjectExplorer::ToolChain; -using namespace Debugger; - -AbstractMaemoRunControl::AbstractMaemoRunControl(RunConfiguration *rc, QString mode) - : RunControl(rc, mode) +MaemoRunControl::MaemoRunControl(RunConfiguration *rc) + : RunControl(rc, ProjectExplorer::Constants::RUNMODE) , m_runConfig(qobject_cast<MaemoRunConfiguration *>(rc)) , m_devConfig(m_runConfig ? m_runConfig->deviceConfig() : MaemoDeviceConfig()) , m_runner(new MaemoSshRunner(this, m_runConfig)) @@ -77,11 +62,12 @@ AbstractMaemoRunControl::AbstractMaemoRunControl(RunConfiguration *rc, QString m { } -AbstractMaemoRunControl::~AbstractMaemoRunControl() +MaemoRunControl::~MaemoRunControl() { + stop(); } -void AbstractMaemoRunControl::start() +void MaemoRunControl::start() { if (!m_devConfig.isValid()) { handleError(tr("No device configuration set for run configuration.")); @@ -90,6 +76,7 @@ void AbstractMaemoRunControl::start() m_running = true; m_stopped = false; emit started(); + disconnect(m_runner, 0, this, 0); connect(m_runner, SIGNAL(error(QString)), this, SLOT(handleSshError(QString))); connect(m_runner, SIGNAL(readyForExecution()), this, @@ -106,29 +93,32 @@ void AbstractMaemoRunControl::start() } } -void AbstractMaemoRunControl::stop() +void MaemoRunControl::stop() { m_stopped = true; - if (m_runner) + if (m_runner) { + disconnect(m_runner, 0, this, 0); m_runner->stop(); - stopInternal(); + } + setFinished(); } -void AbstractMaemoRunControl::handleSshError(const QString &error) +void MaemoRunControl::handleSshError(const QString &error) { handleError(error); setFinished(); } -void AbstractMaemoRunControl::startExecution() +void MaemoRunControl::startExecution() { emit appendMessage(this, tr("Starting remote process ..."), false); + const QString &remoteExe = m_runConfig->remoteExecutableFilePath(); m_runner->startExecution(QString::fromLocal8Bit("%1 %2 %3") - .arg(targetCmdLinePrefix()).arg(m_runConfig->remoteExecutableFilePath()) - .arg(arguments()).toUtf8()); + .arg(MaemoGlobal::remoteCommandPrefix(remoteExe)).arg(remoteExe) + .arg(m_runConfig->arguments().join(QLatin1String(" "))).toUtf8()); } -void AbstractMaemoRunControl::handleRemoteProcessFinished(int exitCode) +void MaemoRunControl::handleRemoteProcessFinished(int exitCode) { if (m_stopped) return; @@ -139,232 +129,33 @@ void AbstractMaemoRunControl::handleRemoteProcessFinished(int exitCode) setFinished(); } -void AbstractMaemoRunControl::handleRemoteOutput(const QByteArray &output) +void MaemoRunControl::handleRemoteOutput(const QByteArray &output) { emit addToOutputWindowInline(this, QString::fromUtf8(output), false); } -void AbstractMaemoRunControl::handleRemoteErrorOutput(const QByteArray &output) +void MaemoRunControl::handleRemoteErrorOutput(const QByteArray &output) { emit addToOutputWindowInline(this, QString::fromUtf8(output), true); } -bool AbstractMaemoRunControl::isRunning() const +bool MaemoRunControl::isRunning() const { return m_running; } -const QString AbstractMaemoRunControl::targetCmdLinePrefix() const -{ - return QString::fromLocal8Bit("%1 chmod a+x %2 && source /etc/profile && DISPLAY=:0.0 ") - .arg(MaemoGlobal::remoteSudo()) - .arg(m_runConfig->remoteExecutableFilePath()); -} - -QString AbstractMaemoRunControl::arguments() const -{ - return m_runConfig->arguments().join(" "); -} - -void AbstractMaemoRunControl::handleError(const QString &errString) +void MaemoRunControl::handleError(const QString &errString) { QMessageBox::critical(0, tr("Remote Execution Failure"), errString); emit appendMessage(this, errString, true); stop(); } -void AbstractMaemoRunControl::setFinished() +void MaemoRunControl::setFinished() { m_running = false; emit finished(); } - -MaemoRunControl::MaemoRunControl(RunConfiguration *runConfiguration) - : AbstractMaemoRunControl(runConfiguration, ProjectExplorer::Constants::RUNMODE) -{ -} - -MaemoRunControl::~MaemoRunControl() -{ - stop(); -} - -void MaemoRunControl::stopInternal() -{ - setFinished(); -} - - -MaemoDebugRunControl::MaemoDebugRunControl(RunConfiguration *runConfiguration) - : AbstractMaemoRunControl(runConfiguration, ProjectExplorer::Constants::DEBUGMODE) - , m_debuggerRunControl(0) - , m_startParams(new DebuggerStartParameters) - , m_uploadJob(SftpInvalidJob) -{ -#ifdef USE_GDBSERVER - m_startParams->startMode = AttachToRemote; - m_startParams->executable = m_runConfig->localExecutableFilePath(); - m_startParams->debuggerCommand = m_runConfig->gdbCmd(); - m_startParams->remoteChannel - = m_devConfig.server.host % QLatin1Char(':') % gdbServerPort(); - m_startParams->remoteArchitecture = QLatin1String("arm"); - m_runner->addProcsToKill(QStringList() << QLatin1String("gdbserver")); -#else - m_startParams->startMode = StartRemoteGdb; - m_startParams->executable = m_runConfig->remoteExecutableFilePath(); - m_startParams->debuggerCommand = targetCmdLinePrefix() - + QLatin1String(" /usr/bin/gdb"); - m_startParams->connParams = m_devConfig.server; - m_runner->addProcsToKill(QStringList() << QLatin1String("gdb")); -#endif - m_startParams->processArgs = m_runConfig->arguments(); - m_startParams->sysRoot = m_runConfig->sysRoot(); - m_startParams->toolChainType = ToolChain::GCC_MAEMO; - m_startParams->dumperLibrary = m_runConfig->dumperLib(); - m_startParams->remoteDumperLib = uploadDir().toUtf8() + '/' - + QFileInfo(m_runConfig->dumperLib()).fileName().toUtf8(); - - m_debuggerRunControl = DebuggerPlugin::createDebugger(*m_startParams.data()); - connect(m_debuggerRunControl, SIGNAL(finished()), this, - SLOT(debuggingFinished()), Qt::QueuedConnection); -} - -MaemoDebugRunControl::~MaemoDebugRunControl() -{ - disconnect(SIGNAL(addToOutputWindow(ProjectExplorer::RunControl*,QString, bool))); - disconnect(SIGNAL(addToOutputWindowInline(ProjectExplorer::RunControl*,QString, bool))); - stop(); -} - -void MaemoDebugRunControl::startExecution() -{ - const QString &dumperLib = m_runConfig->dumperLib(); - if (!dumperLib.isEmpty() - && m_runConfig->deployStep()->currentlyNeedsDeployment(m_devConfig.server.host, - MaemoDeployable(dumperLib, uploadDir()))) { - m_uploader = m_runner->connection()->createSftpChannel(); - connect(m_uploader.data(), SIGNAL(initialized()), this, - SLOT(handleSftpChannelInitialized())); - connect(m_uploader.data(), SIGNAL(initializationFailed(QString)), this, - SLOT(handleSftpChannelInitializationFailed(QString))); - connect(m_uploader.data(), SIGNAL(finished(Core::SftpJobId, QString)), - this, SLOT(handleSftpJobFinished(Core::SftpJobId, QString))); - m_uploader->initialize(); - } else { - startDebugging(); - } -} - -void MaemoDebugRunControl::handleSftpChannelInitialized() -{ - if (m_stopped) - return; - - const QString dumperLib = m_runConfig->dumperLib(); - const QString fileName = QFileInfo(dumperLib).fileName(); - const QString remoteFilePath = uploadDir() + '/' + fileName; - m_uploadJob = m_uploader->uploadFile(dumperLib, remoteFilePath, - SftpOverwriteExisting); - if (m_uploadJob == SftpInvalidJob) { - handleError(tr("Upload failed: Could not open file '%1'") - .arg(dumperLib)); - } else { - emit appendMessage(this, - tr("Started uploading debugging helpers ('%1').").arg(dumperLib), - false); - } -} - -void MaemoDebugRunControl::handleSftpChannelInitializationFailed(const QString &error) -{ - handleError(error); -} - -void MaemoDebugRunControl::handleSftpJobFinished(Core::SftpJobId job, - const QString &error) -{ - if (m_stopped) - return; - - if (job != m_uploadJob) { - qWarning("Warning: Unknown debugging helpers upload job %d finished.", job); - return; - } - - if (!error.isEmpty()) { - handleError(tr("Error: Could not upload debugging helpers.")); - } else { - m_runConfig->deployStep()->setDeployed(m_devConfig.server.host, - MaemoDeployable(m_runConfig->dumperLib(), uploadDir())); - emit appendMessage(this, - tr("Finished uploading debugging helpers."), false); - startDebugging(); - } -} - -void MaemoDebugRunControl::startDebugging() -{ -#ifdef USE_GDBSERVER - m_runner->startExecution(QString::fromLocal8Bit("%1 gdbserver :%2 %3 %4") - .arg(targetCmdLinePrefix()).arg(gdbServerPort()) - .arg(m_runConfig->remoteExecutableFilePath()) - .arg(arguments()).toUtf8()); -#else - DebuggerPlugin::startDebugger(m_debuggerRunControl); -#endif -} - -bool MaemoDebugRunControl::isDeploying() const -{ - return m_uploader && m_uploadJob != SftpInvalidJob; -} - -void MaemoDebugRunControl::stopInternal() -{ - if (isDeploying()) { - disconnect(m_uploader.data(), 0, this, 0); - m_uploader->closeChannel(); - m_uploadJob = SftpInvalidJob; - setFinished(); - } else if (m_debuggerRunControl && m_debuggerRunControl->engine()) { - m_debuggerRunControl->engine()->quitDebugger(); - } else { - setFinished(); - } -} - -void MaemoDebugRunControl::debuggingFinished() -{ -#ifdef USE_GDBSERVER - m_runner->stop(); -#endif - setFinished(); -} - -void MaemoDebugRunControl::handleRemoteProcessStarted() -{ - DebuggerPlugin::startDebugger(m_debuggerRunControl); -} - -void MaemoDebugRunControl::debuggerOutput(const QString &output) -{ - emit appendMessage(this, QLatin1String("[gdb says:] ") + output, true); -} - -QString MaemoDebugRunControl::gdbServerPort() const -{ - return m_devConfig.type == MaemoDeviceConfig::Physical - ? QString::number(m_devConfig.gdbServerPort) - : m_runConfig->runtimeGdbServerPort(); // During configuration we don't - // know which port to use, so we display something in the config dialog, - // but we will make sure we use the right port from the information file. -} - -QString MaemoDebugRunControl::uploadDir() const -{ - return MaemoGlobal::homeDirOnDevice(m_devConfig.server.uname); -} - } // namespace Internal } // namespace Qt4ProjectManager diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.h b/src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.h index 4604898a5b0cb16b63e7c68f7f9c91bb6dfb147a..2acf240213db8acc56eaf361346d7c194fdf549a 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.h +++ b/src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.h @@ -37,105 +37,45 @@ #include "maemodeviceconfigurations.h" -#include <coreplugin/ssh/sftpdefs.h> #include <projectexplorer/runconfiguration.h> #include <QtCore/QString> -namespace Core { - class SftpChannel; - class SshConnection; - class SshRemoteProcess; -} - -namespace Debugger { - class DebuggerRunControl; - class DebuggerStartParameters; -} // namespace Debugger - namespace Qt4ProjectManager { namespace Internal { class MaemoRunConfiguration; class MaemoSshRunner; -class AbstractMaemoRunControl : public ProjectExplorer::RunControl +class MaemoRunControl : public ProjectExplorer::RunControl { Q_OBJECT public: - explicit AbstractMaemoRunControl(ProjectExplorer::RunConfiguration *runConfig, QString mode); - virtual ~AbstractMaemoRunControl(); - -protected: - virtual void start(); - virtual void stop(); - - void setFinished(); - void handleError(const QString &errString); - const QString targetCmdLinePrefix() const; - QString arguments() const; + explicit MaemoRunControl(ProjectExplorer::RunConfiguration *runConfig); + virtual ~MaemoRunControl(); private slots: - virtual void startExecution(); + void startExecution(); void handleSshError(const QString &error); - virtual void handleRemoteProcessStarted() {} + void handleRemoteProcessStarted() {} void handleRemoteProcessFinished(int exitCode); void handleRemoteOutput(const QByteArray &output); void handleRemoteErrorOutput(const QByteArray &output); -protected: +private: + virtual void start(); + virtual void stop(); + virtual bool isRunning() const; + + void setFinished(); + void handleError(const QString &errString); + MaemoRunConfiguration *m_runConfig; // TODO this pointer can be invalid const MaemoDeviceConfig m_devConfig; MaemoSshRunner * const m_runner; bool m_stopped; - -private: - virtual bool isRunning() const; - virtual void stopInternal()=0; - bool m_running; }; -class MaemoRunControl : public AbstractMaemoRunControl -{ - Q_OBJECT -public: - explicit MaemoRunControl(ProjectExplorer::RunConfiguration *runConfiguration); - ~MaemoRunControl(); - -private: - virtual void stopInternal(); -}; - -class MaemoDebugRunControl : public AbstractMaemoRunControl -{ - Q_OBJECT -public: - explicit MaemoDebugRunControl(ProjectExplorer::RunConfiguration *runConfiguration); - ~MaemoDebugRunControl(); - -private slots: - virtual void handleRemoteProcessStarted(); - void debuggerOutput(const QString &output); - void debuggingFinished(); - void handleSftpChannelInitialized(); - void handleSftpChannelInitializationFailed(const QString &error); - void handleSftpJobFinished(Core::SftpJobId job, const QString &error); - -private: - virtual void stopInternal(); - virtual void startExecution(); - QString uploadDir() const; - - QString gdbServerPort() const; - void startDebugging(); - bool isDeploying() const; - - Debugger::DebuggerRunControl *m_debuggerRunControl; - QSharedPointer<Debugger::DebuggerStartParameters> m_startParams; - QSharedPointer<Core::SftpChannel> m_uploader; - Core::SftpJobId m_uploadJob; -}; - } // namespace Internal } // namespace Qt4ProjectManager diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemorunfactories.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemorunfactories.cpp index b2ad7b1ad03d5af7e0cde76b981d45290138d4ae..b527557290f5c99745cc4c8e9c55d5e7c37cfdab 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemorunfactories.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemorunfactories.cpp @@ -35,6 +35,7 @@ #include "maemorunfactories.h" #include "maemoconstants.h" +#include "maemodebugsupport.h" #include "maemorunconfiguration.h" #include "maemoruncontrol.h" @@ -171,7 +172,7 @@ RunControl* MaemoRunControlFactory::create(RunConfiguration *runConfig, || mode == ProjectExplorer::Constants::DEBUGMODE); if (mode == ProjectExplorer::Constants::RUNMODE) return new MaemoRunControl(rc); - return new MaemoDebugRunControl(rc); + return MaemoDebugSupport::createDebugRunControl(rc); } QString MaemoRunControlFactory::displayName() const diff --git a/src/plugins/qt4projectmanager/qt-maemo/qt-maemo.pri b/src/plugins/qt4projectmanager/qt-maemo/qt-maemo.pri index 8fb70f8959840ed9e9225fea258b33a7c8733f64..1e732cad2f48e428bbc311d0ff34926cb25a3b7d 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/qt-maemo.pri +++ b/src/plugins/qt4projectmanager/qt-maemo/qt-maemo.pri @@ -24,7 +24,8 @@ HEADERS += \ $$PWD/maemodeploystepwidget.h \ $$PWD/maemodeploystepfactory.h \ $$PWD/maemoglobal.h \ - $$PWD/maemosshrunner.h + $$PWD/maemosshrunner.h \ + $$PWD/maemodebugsupport.h SOURCES += \ $$PWD/maemoconfigtestdialog.cpp \ @@ -50,7 +51,8 @@ SOURCES += \ $$PWD/maemodeploystepwidget.cpp \ $$PWD/maemodeploystepfactory.cpp \ $$PWD/maemoglobal.cpp \ - $$PWD/maemosshrunner.cpp + $$PWD/maemosshrunner.cpp \ + $$PWD/maemodebugsupport.cpp FORMS += \ $$PWD/maemoconfigtestdialog.ui \