1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the Qt Creator.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
33 ****************************************************************************/
35 #include "maemodebugsupport.h"
37 #include "maemodeployables.h"
38 #include "maemodeploystep.h"
39 #include "maemoglobal.h"
40 #include "maemosshrunner.h"
41 #include "maemousedportsgatherer.h"
42 #include "qt4maemotarget.h"
44 #include <utils/ssh/sftpchannel.h>
45 #include <debugger/debuggerplugin.h>
46 #include <debugger/debuggerstartparameters.h>
47 #include <debugger/debuggerrunner.h>
48 #include <debugger/debuggerengine.h>
49 #include <projectexplorer/abi.h>
51 #include <QtCore/QDir>
52 #include <QtCore/QFileInfo>
54 #define ASSERT_STATE(state) ASSERT_STATE_GENERIC(State, state, m_state)
56 using namespace Utils;
57 using namespace Debugger;
58 using namespace ProjectExplorer;
60 namespace Qt4ProjectManager {
63 RunControl *MaemoDebugSupport::createDebugRunControl(MaemoRunConfiguration *runConfig)
65 DebuggerStartParameters params;
66 const MaemoDeviceConfig::ConstPtr &devConf = runConfig->deviceConfig();
68 const MaemoRunConfiguration::DebuggingType debuggingType
69 = runConfig->debuggingType();
70 if (debuggingType != MaemoRunConfiguration::DebugCppOnly) {
71 params.qmlServerAddress = runConfig->deviceConfig()->sshParameters().host;
72 params.qmlServerPort = -1;
74 if (debuggingType != MaemoRunConfiguration::DebugQmlOnly) {
75 params.processArgs = runConfig->arguments();
76 params.sysRoot = runConfig->sysRoot();
77 params.toolChainAbi = runConfig->abi();
78 params.dumperLibrary = runConfig->dumperLib();
79 params.remoteDumperLib = uploadDir(devConf).toUtf8() + '/'
80 + QFileInfo(runConfig->dumperLib()).fileName().toUtf8();
81 if (runConfig->useRemoteGdb()) {
82 params.startMode = StartRemoteGdb;
83 params.executable = runConfig->remoteExecutableFilePath();
84 params.debuggerCommand = MaemoGlobal::remoteCommandPrefix(runConfig->deviceConfig()->osVersion(),
85 runConfig->remoteExecutableFilePath())
86 + MaemoGlobal::remoteEnvironment(runConfig->userEnvironmentChanges())
87 + QLatin1String(" /usr/bin/gdb");
88 params.connParams = devConf->sshParameters();
89 params.localMountDir = runConfig->localDirToMountForRemoteGdb();
90 params.remoteMountPoint
91 = runConfig->remoteProjectSourcesMountPoint();
92 const QString execDirAbs
93 = QDir::fromNativeSeparators(QFileInfo(runConfig->localExecutableFilePath()).path());
94 const QString execDirRel
95 = QDir(params.localMountDir).relativeFilePath(execDirAbs);
96 params.remoteSourcesDir = QString(params.remoteMountPoint
97 + QLatin1Char('/') + execDirRel).toUtf8();
99 params.startMode = AttachToRemote;
100 params.executable = runConfig->localExecutableFilePath();
101 params.debuggerCommand = runConfig->gdbCmd();
103 = devConf->sshParameters().host + QLatin1String(":-1");
104 params.useServerStartScript = true;
105 const AbstractQt4MaemoTarget::DebugArchitecture &debugArch
106 = runConfig->maemoTarget()->debugArchitecture();
107 params.remoteArchitecture = debugArch.architecture;
108 params.gnuTarget = debugArch.gnuTarget;
111 params.startMode = AttachToRemote;
113 params.displayName = runConfig->displayName();
115 DebuggerRunControl * const runControl =
116 DebuggerPlugin::createDebugger(params, runConfig);
117 bool useGdb = params.startMode == StartRemoteGdb
118 && debuggingType != MaemoRunConfiguration::DebugQmlOnly;
119 MaemoDebugSupport *debugSupport =
120 new MaemoDebugSupport(runConfig, runControl->engine(), useGdb);
121 connect(runControl, SIGNAL(finished()),
122 debugSupport, SLOT(handleDebuggingFinished()));
126 MaemoDebugSupport::MaemoDebugSupport(MaemoRunConfiguration *runConfig,
127 DebuggerEngine *engine, bool useGdb)
128 : QObject(engine), m_engine(engine), m_runConfig(runConfig),
129 m_deviceConfig(m_runConfig->deviceConfig()),
130 m_runner(new MaemoSshRunner(this, runConfig, true)),
131 m_debuggingType(runConfig->debuggingType()),
132 m_dumperLib(runConfig->dumperLib()),
133 m_userEnvChanges(runConfig->userEnvironmentChanges()),
134 m_state(Inactive), m_gdbServerPort(-1), m_qmlPort(-1),
137 connect(m_engine, SIGNAL(requestRemoteSetup()), this,
138 SLOT(handleAdapterSetupRequested()));
141 MaemoDebugSupport::~MaemoDebugSupport()
146 void MaemoDebugSupport::showMessage(const QString &msg, int channel)
149 m_engine->showMessage(msg, channel);
152 void MaemoDebugSupport::handleAdapterSetupRequested()
154 ASSERT_STATE(Inactive);
156 setState(StartingRunner);
157 showMessage(tr("Preparing remote side ..."), AppStuff);
158 disconnect(m_runner, 0, this, 0);
159 connect(m_runner, SIGNAL(error(QString)), this,
160 SLOT(handleSshError(QString)));
161 connect(m_runner, SIGNAL(readyForExecution()), this,
162 SLOT(startExecution()));
163 connect(m_runner, SIGNAL(reportProgress(QString)), this,
164 SLOT(handleProgressReport(QString)));
168 void MaemoDebugSupport::handleSshError(const QString &error)
170 if (m_state == Debugging) {
171 showMessage(tr("SSH connection error: %1").arg(error),
174 m_engine->notifyInferiorIll();
175 } else if (m_state != Inactive) {
176 handleAdapterSetupFailed(error);
180 void MaemoDebugSupport::startExecution()
182 if (m_state == Inactive)
185 ASSERT_STATE(StartingRunner);
187 if (!useGdb() && m_debuggingType != MaemoRunConfiguration::DebugQmlOnly) {
188 if (!setPort(m_gdbServerPort))
191 if (m_debuggingType != MaemoRunConfiguration::DebugCppOnly) {
192 if (!setPort(m_qmlPort))
196 if (m_debuggingType != MaemoRunConfiguration::DebugQmlOnly
197 && !m_dumperLib.isEmpty()
199 && m_runConfig->deployStep()->currentlyNeedsDeployment(m_deviceConfig->sshParameters().host,
200 MaemoDeployable(m_dumperLib, uploadDir(m_deviceConfig)))) {
201 setState(InitializingUploader);
202 m_uploader = m_runner->connection()->createSftpChannel();
203 connect(m_uploader.data(), SIGNAL(initialized()), this,
204 SLOT(handleSftpChannelInitialized()));
205 connect(m_uploader.data(), SIGNAL(initializationFailed(QString)), this,
206 SLOT(handleSftpChannelInitializationFailed(QString)));
207 connect(m_uploader.data(), SIGNAL(finished(Utils::SftpJobId, QString)),
208 this, SLOT(handleSftpJobFinished(Utils::SftpJobId, QString)));
209 m_uploader->initialize();
211 setState(DumpersUploaded);
216 void MaemoDebugSupport::handleSftpChannelInitialized()
218 if (m_state == Inactive)
221 ASSERT_STATE(InitializingUploader);
223 const QString fileName = QFileInfo(m_dumperLib).fileName();
224 const QString remoteFilePath = uploadDir(m_deviceConfig)
225 + QLatin1Char('/') + fileName;
226 m_uploadJob = m_uploader->uploadFile(m_dumperLib, remoteFilePath,
227 SftpOverwriteExisting);
228 if (m_uploadJob == SftpInvalidJob) {
229 handleAdapterSetupFailed(tr("Upload failed: Could not open file '%1'")
232 setState(UploadingDumpers);
233 showMessage(tr("Started uploading debugging helpers ('%1').")
234 .arg(m_dumperLib), AppStuff);
238 void MaemoDebugSupport::handleSftpChannelInitializationFailed(const QString &error)
240 if (m_state == Inactive)
242 ASSERT_STATE(InitializingUploader);
243 handleAdapterSetupFailed(error);
246 void MaemoDebugSupport::handleSftpJobFinished(Utils::SftpJobId job,
247 const QString &error)
249 if (m_state == Inactive)
252 ASSERT_STATE(UploadingDumpers);
254 if (job != m_uploadJob) {
255 qWarning("Warning: Unknown debugging helpers upload job %d finished.", job);
259 if (!error.isEmpty()) {
260 handleAdapterSetupFailed(tr("Could not upload debugging helpers: %1.")
263 setState(DumpersUploaded);
265 m_runConfig->deployStep()->setDeployed(m_deviceConfig->sshParameters().host,
266 MaemoDeployable(m_dumperLib, uploadDir(m_deviceConfig)));
268 showMessage(tr("Finished uploading debugging helpers."), AppStuff);
271 m_uploadJob = SftpInvalidJob;
274 void MaemoDebugSupport::startDebugging()
276 ASSERT_STATE(DumpersUploaded);
279 handleAdapterSetupDone();
281 setState(StartingRemoteProcess);
282 m_gdbserverOutput.clear();
283 connect(m_runner, SIGNAL(remoteErrorOutput(QByteArray)), this,
284 SLOT(handleRemoteErrorOutput(QByteArray)));
285 connect(m_runner, SIGNAL(remoteOutput(QByteArray)), this,
286 SLOT(handleRemoteOutput(QByteArray)));
287 if (m_debuggingType == MaemoRunConfiguration::DebugQmlOnly) {
288 connect(m_runner, SIGNAL(remoteProcessStarted()),
289 SLOT(handleRemoteProcessStarted()));
291 const QString &remoteExe = m_runner->remoteExecutable();
292 const QString cmdPrefix = MaemoGlobal::remoteCommandPrefix(m_deviceConfig->osVersion(),
294 const QString env = MaemoGlobal::remoteEnvironment(m_userEnvChanges);
295 QString args = m_runner->arguments();
296 if (m_debuggingType != MaemoRunConfiguration::DebugCppOnly) {
297 args += QString(QLatin1String(" -qmljsdebugger=port:%1,block"))
300 const QString remoteCommandLine
301 = m_debuggingType == MaemoRunConfiguration::DebugQmlOnly
302 ? QString::fromLocal8Bit("%1 %2 %3 %4").arg(cmdPrefix).arg(env)
303 .arg(remoteExe).arg(args)
304 : QString::fromLocal8Bit("%1 %2 gdbserver :%3 %4 %5")
305 .arg(cmdPrefix).arg(env).arg(m_gdbServerPort)
306 .arg(remoteExe).arg(args);
307 m_runner->startExecution(remoteCommandLine.toUtf8());
311 void MaemoDebugSupport::handleDebuggingFinished()
316 void MaemoDebugSupport::handleRemoteOutput(const QByteArray &output)
318 ASSERT_STATE(QList<State>() << Inactive << Debugging);
319 showMessage(QString::fromUtf8(output), AppOutput);
322 void MaemoDebugSupport::handleRemoteErrorOutput(const QByteArray &output)
324 ASSERT_STATE(QList<State>() << Inactive << StartingRemoteProcess << Debugging);
329 showMessage(QString::fromUtf8(output), AppOutput);
330 if (m_state == StartingRemoteProcess
331 && m_debuggingType != MaemoRunConfiguration::DebugQmlOnly) {
332 m_gdbserverOutput += output;
333 if (m_gdbserverOutput.contains("Listening on port")) {
334 handleAdapterSetupDone();
335 m_gdbserverOutput.clear();
340 void MaemoDebugSupport::handleProgressReport(const QString &progressOutput)
342 showMessage(progressOutput, AppStuff);
345 void MaemoDebugSupport::handleAdapterSetupFailed(const QString &error)
348 m_engine->handleRemoteSetupFailed(tr("Initial setup failed: %1").arg(error));
351 void MaemoDebugSupport::handleAdapterSetupDone()
354 m_engine->handleRemoteSetupDone(m_gdbServerPort, m_qmlPort);
357 void MaemoDebugSupport::handleRemoteProcessStarted()
359 Q_ASSERT(m_debuggingType == MaemoRunConfiguration::DebugQmlOnly);
360 ASSERT_STATE(StartingRemoteProcess);
361 handleAdapterSetupDone();
364 void MaemoDebugSupport::setState(State newState)
366 if (m_state == newState)
369 if (m_state == Inactive) {
371 disconnect(m_uploader.data(), 0, this, 0);
372 m_uploader->closeChannel();
378 QString MaemoDebugSupport::uploadDir(const MaemoDeviceConfig::ConstPtr &devConf)
380 return MaemoGlobal::homeDirOnDevice(devConf->sshParameters().userName);
383 bool MaemoDebugSupport::useGdb() const
388 bool MaemoDebugSupport::setPort(int &port)
390 port = m_runner->usedPortsGatherer()->getNextFreePort(m_runner->freePorts());
392 handleAdapterSetupFailed(tr("Not enough free ports on device for debugging."));
398 } // namespace Internal
399 } // namespace Qt4ProjectManager