1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the tools applications of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "launcher.h"
43 #include "trkutils.h"
44 #include "trkutils_p.h"
45 #include "trkdevice.h"
46 #include "bluetoothlistener.h"
47 #include "symbiandevicemanager.h"
48 
49 #include <QtCore/QTimer>
50 #include <QtCore/QDateTime>
51 #include <QtCore/QVariant>
52 #include <QtCore/QDebug>
53 #include <QtCore/QQueue>
54 #include <QtCore/QFile>
55 #include <QtCore/QFileInfo>
56 #include <QtCore/QScopedPointer>
57 
58 #include <cstdio>
59 
60 namespace trk {
61 
62 struct CrashReportState {
63     CrashReportState();
64     void clear();
65 
66     typedef uint Thread;
67     typedef QList<Thread> Threads;
68     Threads threads;
69 
70     QList<uint> registers;
71     QByteArray stack;
72     uint sp;
73     uint fetchingStackPID;
74     uint fetchingStackTID;
75 };
76 
CrashReportState()77 CrashReportState::CrashReportState()
78 {
79     clear();
80 }
81 
clear()82 void CrashReportState::clear()
83 {
84     threads.clear();
85     stack.clear();
86     sp = fetchingStackPID = fetchingStackTID = 0;
87 }
88 
89 struct LauncherPrivate {
90     struct TransferState {
91         int currentFileName;
92         uint copyFileHandle;
93         QScopedPointer<QByteArray> data;
94         qint64 position;
95         QScopedPointer<QFile> localFile;
96     };
97 
98     struct CopyState : public TransferState {
99         QStringList sourceFileNames;
100         QStringList destinationFileNames;
101     };
102 
103     struct DownloadState : public TransferState {
104         QString sourceFileName;
105         QString destinationFileName;
106     };
107 
108     explicit LauncherPrivate(const TrkDevicePtr &d);
109 
110     TrkDevicePtr m_device;
111     QByteArray m_trkReadBuffer;
112     Launcher::State m_state;
113 
114     void logMessage(const QString &msg);
115     // Debuggee state
116     Session m_session; // global-ish data (process id, target information)
117 
118     CopyState m_copyState;
119     DownloadState m_downloadState;
120     QString m_fileName;
121     QString m_commandLineArgs;
122     QStringList m_installFileNames;
123     int m_currentInstallFileName;
124     int m_verbose;
125     Launcher::Actions m_startupActions;
126     bool m_closeDevice;
127     CrashReportState m_crashReportState;
128     Launcher::InstallationMode m_installationMode;
129     Launcher::InstallationMode m_currentInstallationStep;
130     char m_installationDrive;
131 };
132 
LauncherPrivate(const TrkDevicePtr & d)133 LauncherPrivate::LauncherPrivate(const TrkDevicePtr &d) :
134     m_device(d),
135     m_state(Launcher::Disconnected),
136     m_verbose(0),
137     m_closeDevice(true),
138     m_installationMode(Launcher::InstallationModeSilentAndUser),
139     m_currentInstallationStep(Launcher::InstallationModeSilent),
140     m_installationDrive('C')
141 {
142     if (m_device.isNull())
143         m_device = TrkDevicePtr(new TrkDevice);
144 }
145 
Launcher(Actions startupActions,const TrkDevicePtr & dev,QObject * parent)146 Launcher::Launcher(Actions startupActions,
147                    const TrkDevicePtr &dev,
148                    QObject *parent) :
149     QObject(parent),
150     d(new LauncherPrivate(dev))
151 {
152     d->m_startupActions = startupActions;
153     connect(d->m_device.data(), SIGNAL(messageReceived(trk::TrkResult)), this, SLOT(handleResult(trk::TrkResult)));
154 }
155 
~Launcher()156 Launcher::~Launcher()
157 {
158     // Destroyed before protocol was through: Close
159     if (d->m_closeDevice && d->m_device->isOpen())
160         d->m_device->close();
161     emit destroyed(d->m_device->port());
162     logMessage("Shutting down.\n");
163     delete d;
164 }
165 
state() const166 Launcher::State Launcher::state() const
167 {
168     return d->m_state;
169 }
170 
setState(State s)171 void Launcher::setState(State s)
172 {
173     if (s != d->m_state) {
174         d->m_state = s;
175         emit stateChanged(s);
176     }
177 }
178 
setInstallationMode(InstallationMode installation)179 void Launcher::setInstallationMode(InstallationMode installation)
180 {
181     d->m_installationMode = installation;
182 }
183 
setInstallationDrive(char drive)184 void Launcher::setInstallationDrive(char drive)
185 {
186     d->m_installationDrive = drive;
187 }
188 
addStartupActions(trk::Launcher::Actions startupActions)189 void Launcher::addStartupActions(trk::Launcher::Actions startupActions)
190 {
191     d->m_startupActions = Actions(d->m_startupActions | startupActions);
192 }
193 
setTrkServerName(const QString & name)194 void Launcher::setTrkServerName(const QString &name)
195 {
196     d->m_device->setPort(name);
197 }
198 
trkServerName() const199 QString Launcher::trkServerName() const
200 {
201     return d->m_device->port();
202 }
203 
trkDevice() const204 TrkDevicePtr Launcher::trkDevice() const
205 {
206     return d->m_device;
207 }
208 
setFileName(const QString & name)209 void Launcher::setFileName(const QString &name)
210 {
211     d->m_fileName = name;
212 }
213 
setCopyFileNames(const QStringList & srcNames,const QStringList & dstNames)214 void Launcher::setCopyFileNames(const QStringList &srcNames, const QStringList &dstNames)
215 {
216     d->m_copyState.sourceFileNames = srcNames;
217     d->m_copyState.destinationFileNames = dstNames;
218     d->m_copyState.currentFileName = 0;
219 }
220 
setDownloadFileName(const QString & srcName,const QString & dstName)221 void Launcher::setDownloadFileName(const QString &srcName, const QString &dstName)
222 {
223     d->m_downloadState.sourceFileName = srcName;
224     d->m_downloadState.destinationFileName = dstName;
225 }
226 
setInstallFileNames(const QStringList & names)227 void Launcher::setInstallFileNames(const QStringList &names)
228 {
229     d->m_installFileNames = names;
230     d->m_currentInstallFileName = 0;
231 }
232 
setCommandLineArgs(const QString & args)233 void Launcher::setCommandLineArgs(const QString &args)
234 {
235     d->m_commandLineArgs = args;
236 }
237 
setSerialFrame(bool b)238 void Launcher::setSerialFrame(bool b)
239 {
240     d->m_device->setSerialFrame(b);
241 }
242 
serialFrame() const243 bool Launcher::serialFrame() const
244 {
245     return d->m_device->serialFrame();
246 }
247 
248 
closeDevice() const249 bool Launcher::closeDevice() const
250 {
251     return d->m_closeDevice;
252 }
253 
setCloseDevice(bool c)254 void Launcher::setCloseDevice(bool c)
255 {
256     d->m_closeDevice = c;
257 }
258 
installationMode() const259 Launcher::InstallationMode Launcher::installationMode() const
260 {
261     return d->m_installationMode;
262 }
263 
installationDrive() const264 char Launcher::installationDrive() const
265 {
266     return d->m_installationDrive;
267 }
268 
startServer(QString * errorMessage)269 bool Launcher::startServer(QString *errorMessage)
270 {
271     errorMessage->clear();
272     d->m_crashReportState.clear();
273     if (d->m_verbose) {
274         QString msg;
275         QTextStream str(&msg);
276         str.setIntegerBase(16);
277         str << "Actions=0x" << d->m_startupActions;
278         str.setIntegerBase(10);
279         str << " Port=" << trkServerName();
280         if (!d->m_fileName.isEmpty())
281             str << " Executable=" << d->m_fileName;
282         if (!d->m_commandLineArgs.isEmpty())
283             str << " Arguments= " << d->m_commandLineArgs;
284         for (int i = 0; i < d->m_copyState.sourceFileNames.size(); ++i) {
285             str << " Package/Source=" << d->m_copyState.sourceFileNames.at(i);
286             str << " Remote Package/Destination=" << d->m_copyState.destinationFileNames.at(i);
287         }
288         if (!d->m_downloadState.sourceFileName.isEmpty())
289             str << " Source=" << d->m_downloadState.sourceFileName;
290         if (!d->m_downloadState.destinationFileName.isEmpty())
291             str << " Destination=" << d->m_downloadState.destinationFileName;
292         if (!d->m_installFileNames.isEmpty())
293             foreach (const QString &installFileName, d->m_installFileNames)
294                 str << " Install file=" << installFileName;
295         logMessage(msg);
296     }
297     if (d->m_startupActions & ActionCopy) {
298         if (d->m_copyState.sourceFileNames.isEmpty()) {
299             qWarning("No local filename given for copying package.");
300             return false;
301         } else if (d->m_copyState.destinationFileNames.isEmpty()) {
302             qWarning("No remote filename given for copying package.");
303             return false;
304         }
305     }
306     if (d->m_startupActions & ActionInstall && d->m_installFileNames.isEmpty()) {
307         qWarning("No package name given for installing.");
308         return false;
309     }
310     if (d->m_startupActions & ActionRun && d->m_fileName.isEmpty()) {
311         qWarning("No remote executable given for running.");
312         return false;
313     }
314     if (!d->m_device->isOpen() && !d->m_device->open(errorMessage))
315         return false;
316     setState(Connecting);
317     // Set up the temporary 'waiting' state if we do not get immediate connection
318     QTimer::singleShot(1000, this, SLOT(slotWaitingForTrk()));
319     d->m_device->sendTrkInitialPing();
320     d->m_device->sendTrkMessage(TrkDisconnect); // Disconnect, as trk might be still connected
321     d->m_device->sendTrkMessage(TrkSupported, TrkCallback(this, &Launcher::handleSupportMask));
322     d->m_device->sendTrkMessage(TrkCpuType, TrkCallback(this, &Launcher::handleCpuType));
323     d->m_device->sendTrkMessage(TrkVersions, TrkCallback(this, &Launcher::handleTrkVersion));
324     if (d->m_startupActions != ActionPingOnly)
325         d->m_device->sendTrkMessage(TrkConnect, TrkCallback(this, &Launcher::handleConnect));
326     return true;
327 }
328 
slotWaitingForTrk()329 void Launcher::slotWaitingForTrk()
330 {
331     // Set temporary state if we are still in connected state
332     if (state() == Connecting)
333         setState(WaitingForTrk);
334 }
335 
handleConnect(const TrkResult & result)336 void Launcher::handleConnect(const TrkResult &result)
337 {
338     if (result.errorCode()) {
339         emit canNotConnect(result.errorString());
340         return;
341     }
342     setState(Connected);
343     if (d->m_startupActions & ActionCopy)
344         copyFileToRemote();
345     else if (d->m_startupActions & ActionInstall)
346         installRemotePackage();
347     else if (d->m_startupActions & ActionRun)
348         startInferiorIfNeeded();
349     else if (d->m_startupActions & ActionDownload)
350         copyFileFromRemote();
351 }
352 
setVerbose(int v)353 void Launcher::setVerbose(int v)
354 {
355     d->m_verbose = v;
356     d->m_device->setVerbose(v);
357 }
358 
logMessage(const QString & msg)359 void Launcher::logMessage(const QString &msg)
360 {
361     if (d->m_verbose)
362         qDebug() << "LAUNCHER: " << qPrintable(msg);
363 }
364 
handleFinished()365 void Launcher::handleFinished()
366 {
367     if (d->m_closeDevice)
368         d->m_device->close();
369     emit finished();
370 }
371 
terminate()372 void Launcher::terminate()
373 {
374     switch (state()) {
375     case DeviceDescriptionReceived:
376     case Connected:
377         if (d->m_session.pid) {
378             QByteArray ba;
379             appendShort(&ba, 0x0000, TargetByteOrder);
380             appendInt(&ba, d->m_session.pid, TargetByteOrder);
381             d->m_device->sendTrkMessage(TrkDeleteItem, TrkCallback(this, &Launcher::handleRemoteProcessKilled), ba);
382             return;
383         }
384         if (d->m_copyState.copyFileHandle)
385             closeRemoteFile(true);
386         disconnectTrk();
387         break;
388     case Disconnected:
389         break;
390     case Connecting:
391     case WaitingForTrk:
392         setState(Disconnected);
393         handleFinished();
394         break;
395     }
396 }
397 
handleRemoteProcessKilled(const TrkResult & result)398 void Launcher::handleRemoteProcessKilled(const TrkResult &result)
399 {
400     Q_UNUSED(result)
401     disconnectTrk();
402 }
403 
msgStopped(uint pid,uint tid,uint address,const QString & why)404 QString Launcher::msgStopped(uint pid, uint tid, uint address, const QString &why)
405 {
406     return QString::fromLatin1("Process %1, thread %2 stopped at 0x%3: %4").
407             arg(pid).arg(tid).arg(address, 0, 16).
408             arg(why.isEmpty() ? QString::fromLatin1("<Unknown reason>") : why);
409 }
410 
parseNotifyStopped(const QByteArray & dataBA,uint * pid,uint * tid,uint * address,QString * why)411 bool Launcher::parseNotifyStopped(const QByteArray &dataBA,
412                                   uint *pid, uint *tid, uint *address,
413                                   QString *why /* = 0 */)
414 {
415     if (why)
416         why->clear();
417     *address = *pid = *tid = 0;
418     if (dataBA.size() < 12)
419         return false;
420     const char *data = dataBA.data();
421     *address = extractInt(data);
422     *pid = extractInt(data + 4);
423     *tid = extractInt(data + 8);
424     if (why && dataBA.size() >= 14) {
425         const unsigned short len = extractShort(data + 12);
426         if (len > 0)
427             *why = QString::fromLatin1(data + 14, len);
428     }
429     return true;
430 }
431 
handleResult(const TrkResult & result)432 void Launcher::handleResult(const TrkResult &result)
433 {
434     QByteArray prefix = "READ BUF:                                       ";
435     QByteArray str = result.toString().toUtf8();
436     if (result.isDebugOutput) { // handle application output
437         QString msg;
438         if (result.multiplex == MuxTextTrace) {
439             if (result.data.length() > 8) {
440             quint64 timestamp = extractInt64(result.data) & 0x0FFFFFFFFFFFFFFFULL;
441             quint64 secs = timestamp / 1000000000;
442             quint64 ns = timestamp % 1000000000;
443             msg = QString("[%1.%2] %3").arg(secs).arg(ns,9,10,QLatin1Char('0')).arg(QString(result.data.mid(8)));
444             logMessage("TEXT TRACE: " + msg);
445             }
446         } else {
447             logMessage("APPLICATION OUTPUT: " + stringFromArray(result.data));
448             msg = result.data;
449         }
450         msg.replace("\r\n", "\n");
451         if(!msg.endsWith('\n')) msg.append('\n');
452         emit applicationOutputReceived(msg);
453         return;
454     }
455     switch (result.code) {
456         case TrkNotifyAck:
457             break;
458         case TrkNotifyNak: { // NAK
459             logMessage(prefix + QLatin1String("NAK: ") + str);
460             //logMessage(prefix << "TOKEN: " << result.token);
461             logMessage(prefix + QLatin1String("ERROR: ") + errorMessage(result.data.at(0)));
462             break;
463         }
464         case TrkNotifyStopped: { // Notified Stopped
465             QString reason;
466             uint pc;
467             uint pid;
468             uint tid;
469             parseNotifyStopped(result.data, &pid, &tid, &pc, &reason);
470             logMessage(prefix + msgStopped(pid, tid, pc, reason));
471             emit(processStopped(pc, pid, tid, reason));
472             d->m_device->sendTrkAck(result.token);
473             break;
474         }
475         case TrkNotifyException: { // Notify Exception (obsolete)
476             logMessage(prefix + QLatin1String("NOTE: EXCEPTION  ") + str);
477             d->m_device->sendTrkAck(result.token);
478             break;
479         }
480         case TrkNotifyInternalError: { //
481             logMessage(prefix + QLatin1String("NOTE: INTERNAL ERROR: ") + str);
482             d->m_device->sendTrkAck(result.token);
483             break;
484         }
485 
486         // target->host OS notification
487         case TrkNotifyCreated: { // Notify Created
488 
489             if (result.data.size() < 10)
490                 break;
491             const char *data = result.data.constData();
492             const byte error = result.data.at(0);
493             Q_UNUSED(error)
494             const byte type = result.data.at(1); // type: 1 byte; for dll item, this value is 2.
495             const uint tid = extractInt(data + 6); //threadID: 4 bytes
496             Q_UNUSED(tid)
497             if (type == kDSOSDLLItem && result.data.size() >=20) {
498                 const Library lib = Library(result);
499                 d->m_session.libraries.push_back(lib);
500                 emit libraryLoaded(lib);
501             }
502             QByteArray ba;
503             ba.append(result.data.mid(2, 8));
504             d->m_device->sendTrkMessage(TrkContinue, TrkCallback(), ba, "CONTINUE");
505             break;
506         }
507         case TrkNotifyDeleted: { // NotifyDeleted
508             const ushort itemType = (unsigned char)result.data.at(1);
509             const uint pid = result.data.size() >= 6 ? extractShort(result.data.constData() + 2) : 0;
510             const uint tid = result.data.size() >= 10 ? extractShort(result.data.constData() + 6) : 0;
511             Q_UNUSED(tid)
512             const ushort len = result.data.size() > 12 ? extractShort(result.data.constData() + 10) : ushort(0);
513             const QString name = len ? QString::fromAscii(result.data.mid(12, len)) : QString();
514             logMessage(QString::fromLatin1("%1 %2 UNLOAD: %3").
515                        arg(QString::fromAscii(prefix)).arg(itemType ? QLatin1String("LIB") : QLatin1String("PROCESS")).
516                        arg(name));
517             d->m_device->sendTrkAck(result.token);
518             if (itemType == kDSOSProcessItem // process
519                 && result.data.size() >= 10
520                 && d->m_session.pid == extractInt(result.data.data() + 6)) {
521                     if (d->m_startupActions & ActionDownload)
522                         copyFileFromRemote();
523                     else
524                         disconnectTrk();
525             }
526             else if (itemType == kDSOSDLLItem && len) {
527                 // Remove libraries of process.
528                 for (QList<Library>::iterator it = d->m_session.libraries.begin(); it != d->m_session.libraries.end(); ) {
529                     if ((*it).pid == pid && (*it).name == name) {
530                         emit libraryUnloaded(*it);
531                         it = d->m_session.libraries.erase(it);
532                     } else {
533                         ++it;
534                     }
535                 }
536             }
537             break;
538         }
539         case TrkNotifyProcessorStarted: { // NotifyProcessorStarted
540             logMessage(prefix + QLatin1String("NOTE: PROCESSOR STARTED: ") + str);
541             d->m_device->sendTrkAck(result.token);
542             break;
543         }
544         case TrkNotifyProcessorStandBy: { // NotifyProcessorStandby
545             logMessage(prefix + QLatin1String("NOTE: PROCESSOR STANDBY: ") + str);
546             d->m_device->sendTrkAck(result.token);
547             break;
548         }
549         case TrkNotifyProcessorReset: { // NotifyProcessorReset
550             logMessage(prefix + QLatin1String("NOTE: PROCESSOR RESET: ") + str);
551             d->m_device->sendTrkAck(result.token);
552             break;
553         }
554         default: {
555             logMessage(prefix + QLatin1String("INVALID: ") + str);
556             break;
557         }
558     }
559 }
560 
deviceDescription(unsigned verbose) const561 QString Launcher::deviceDescription(unsigned verbose) const
562 {
563     return d->m_session.deviceDescription(verbose);
564 }
565 
handleTrkVersion(const TrkResult & result)566 void Launcher::handleTrkVersion(const TrkResult &result)
567 {
568     if (result.errorCode() || result.data.size() < 5) {
569         if (d->m_startupActions == ActionPingOnly) {
570             setState(Disconnected);
571             handleFinished();
572         }
573         return;
574     }
575     d->m_session.trkAppVersion.trkMajor = result.data.at(1);
576     d->m_session.trkAppVersion.trkMinor = result.data.at(2);
577     d->m_session.trkAppVersion.protocolMajor = result.data.at(3);
578     d->m_session.trkAppVersion.protocolMinor = result.data.at(4);
579     setState(DeviceDescriptionReceived);
580     const QString msg = deviceDescription();
581     emit deviceDescriptionReceived(trkServerName(), msg);
582     // Ping mode: Log & Terminate
583     if (d->m_startupActions == ActionPingOnly) {
584         qWarning("%s", qPrintable(msg));
585         setState(Disconnected);
586         handleFinished();
587     }
588 }
589 
msgCannotOpenRemoteFile(const QString & fileName,const QString & message)590 static inline QString msgCannotOpenRemoteFile(const QString &fileName, const QString &message)
591 {
592     return Launcher::tr("Cannot open remote file '%1': %2").arg(fileName, message);
593 }
594 
msgCannotOpenLocalFile(const QString & fileName,const QString & message)595 static inline QString msgCannotOpenLocalFile(const QString &fileName, const QString &message)
596 {
597     return Launcher::tr("Cannot open '%1': %2").arg(fileName, message);
598 }
599 
handleFileCreation(const TrkResult & result)600 void Launcher::handleFileCreation(const TrkResult &result)
601 {
602     if (result.errorCode() || result.data.size() < 6) {
603         const QString msg = msgCannotOpenRemoteFile(d->m_copyState.destinationFileNames.at(d->m_copyState.currentFileName), result.errorString());
604         logMessage(msg);
605         emit canNotCreateFile(d->m_copyState.destinationFileNames.at(d->m_copyState.currentFileName), msg);
606         disconnectTrk();
607         return;
608     }
609     const char *data = result.data.data();
610     d->m_copyState.copyFileHandle = extractInt(data + 2);
611     const QString localFileName = d->m_copyState.sourceFileNames.at(d->m_copyState.currentFileName);
612     QFile file(localFileName);
613     d->m_copyState.position = 0;
614     if (!file.open(QIODevice::ReadOnly)) {
615         const QString msg = msgCannotOpenLocalFile(localFileName, file.errorString());
616         logMessage(msg);
617         emit canNotOpenLocalFile(localFileName, msg);
618         closeRemoteFile(true);
619         disconnectTrk();
620         return;
621     }
622     d->m_copyState.data.reset(new QByteArray(file.readAll()));
623     file.close();
624     continueCopying();
625 }
626 
handleFileOpened(const TrkResult & result)627 void Launcher::handleFileOpened(const TrkResult &result)
628 {
629     if (result.errorCode() || result.data.size() < 6) {
630         const QString msg = msgCannotOpenRemoteFile(d->m_downloadState.sourceFileName, result.errorString());
631         logMessage(msg);
632         emit canNotOpenFile(d->m_downloadState.sourceFileName, msg);
633         disconnectTrk();
634         return;
635     }
636     d->m_downloadState.position = 0;
637     const QString localFileName = d->m_downloadState.destinationFileName;
638     bool opened = false;
639     if (localFileName == QLatin1String("-")) {
640         d->m_downloadState.localFile.reset(new QFile);
641         opened = d->m_downloadState.localFile->open(stdout, QFile::WriteOnly);
642     } else {
643         d->m_downloadState.localFile.reset(new QFile(localFileName));
644         opened = d->m_downloadState.localFile->open(QFile::WriteOnly | QFile::Truncate);
645     }
646     if (!opened) {
647         const QString msg = msgCannotOpenLocalFile(localFileName, d->m_downloadState.localFile->errorString());
648         logMessage(msg);
649         emit canNotOpenLocalFile(localFileName, msg);
650         closeRemoteFile(true);
651         disconnectTrk();
652     }
653     continueReading();
654 }
655 
continueReading()656 void Launcher::continueReading()
657 {
658     QByteArray ba;
659     appendInt(&ba, d->m_downloadState.copyFileHandle, TargetByteOrder);
660     appendShort(&ba, 2048, TargetByteOrder);
661     d->m_device->sendTrkMessage(TrkReadFile, TrkCallback(this, &Launcher::handleRead), ba);
662 }
663 
handleRead(const TrkResult & result)664 void Launcher::handleRead(const TrkResult &result)
665 {
666     if (result.errorCode() || result.data.size() < 4) {
667         d->m_downloadState.localFile->close();
668         closeRemoteFile(true);
669         disconnectTrk();
670     } else {
671         int length = extractShort(result.data.data() + 2);
672         //TRK doesn't tell us the file length, so we need to keep reading until it returns 0 length
673         if (length > 0) {
674             d->m_downloadState.localFile->write(result.data.data() + 4, length);
675             continueReading();
676         } else {
677             closeRemoteFile(true);
678             disconnectTrk();
679         }
680     }
681 }
682 
handleCopy(const TrkResult & result)683 void Launcher::handleCopy(const TrkResult &result)
684 {
685     if (result.errorCode() || result.data.size() < 4) {
686         closeRemoteFile(true);
687         emit canNotWriteFile(d->m_copyState.destinationFileNames.at(d->m_copyState.currentFileName), result.errorString());
688         disconnectTrk();
689     } else {
690         continueCopying(extractShort(result.data.data() + 2));
691     }
692 }
693 
continueCopying(uint lastCopiedBlockSize)694 void Launcher::continueCopying(uint lastCopiedBlockSize)
695 {
696     qint64 size = d->m_copyState.data->length();
697     d->m_copyState.position += lastCopiedBlockSize;
698     if (size == 0)
699         emit copyProgress(100);
700     else {
701         const qint64 hundred = 100;
702         const qint64 percent = qMin( (d->m_copyState.position * hundred) / size, hundred);
703         emit copyProgress(static_cast<int>(percent));
704     }
705     if (d->m_copyState.position < size) {
706         QByteArray ba;
707         appendInt(&ba, d->m_copyState.copyFileHandle, TargetByteOrder);
708         appendString(&ba, d->m_copyState.data->mid(d->m_copyState.position, 2048), TargetByteOrder, false);
709         d->m_device->sendTrkMessage(TrkWriteFile, TrkCallback(this, &Launcher::handleCopy), ba);
710     } else {
711         closeRemoteFile();
712     }
713 }
714 
closeRemoteFile(bool failed)715 void Launcher::closeRemoteFile(bool failed)
716 {
717     QByteArray ba;
718     appendInt(&ba, d->m_copyState.copyFileHandle, TargetByteOrder);
719     appendDateTime(&ba, QDateTime::currentDateTime(), TargetByteOrder);
720     d->m_device->sendTrkMessage(TrkCloseFile,
721                                failed ? TrkCallback() : TrkCallback(this, &Launcher::handleFileCopied),
722                                ba);
723     d->m_copyState.data.reset(0);
724     d->m_copyState.copyFileHandle = 0;
725     d->m_copyState.position = 0;
726 }
727 
handleFileCopied(const TrkResult & result)728 void Launcher::handleFileCopied(const TrkResult &result)
729 {
730     if (result.errorCode())
731         emit canNotCloseFile(d->m_copyState.destinationFileNames.at(d->m_copyState.currentFileName), result.errorString());
732 
733     ++d->m_copyState.currentFileName;
734 
735     if (d->m_startupActions & ActionInstall && d->m_copyState.currentFileName < d->m_copyState.sourceFileNames.size()) {
736         copyFileToRemote();
737     } else if (d->m_startupActions & ActionInstall) {
738         installRemotePackage();
739     } else if (d->m_startupActions & ActionRun) {
740         startInferiorIfNeeded();
741     } else if (d->m_startupActions & ActionDownload) {
742         copyFileFromRemote();
743     } else {
744         disconnectTrk();
745     }
746 }
747 
handleCpuType(const TrkResult & result)748 void Launcher::handleCpuType(const TrkResult &result)
749 {
750     logMessage("HANDLE CPU TYPE: " + result.toString());
751     if(result.errorCode() || result.data.size() < 7)
752         return;
753     //---TRK------------------------------------------------------
754     //  Command: 0x80 Acknowledge
755     //    Error: 0x00
756     // [80 03 00  04 00 00 04 00 00 00]
757     d->m_session.cpuMajor = result.data.at(1);
758     d->m_session.cpuMinor = result.data.at(2);
759     d->m_session.bigEndian = result.data.at(3);
760     d->m_session.defaultTypeSize = result.data.at(4);
761     d->m_session.fpTypeSize = result.data.at(5);
762     d->m_session.extended1TypeSize = result.data.at(6);
763     //d->m_session.extended2TypeSize = result.data[6];
764 }
765 
handleCreateProcess(const TrkResult & result)766 void Launcher::handleCreateProcess(const TrkResult &result)
767 {
768     if (result.errorCode()) {
769         emit canNotRun(result.errorString());
770         disconnectTrk();
771         return;
772     }
773     //  40 00 00]
774     //logMessage("       RESULT: " + result.toString());
775     // [80 08 00   00 00 01 B5   00 00 01 B6   78 67 40 00   00 40 00 00]
776     const char *data = result.data.data();
777     d->m_session.pid = extractInt(data + 1);
778     d->m_session.tid = extractInt(data + 5);
779     d->m_session.codeseg = extractInt(data + 9);
780     d->m_session.dataseg = extractInt(data + 13);
781     if (d->m_verbose) {
782         const QString msg = QString::fromLatin1("Process id: %1 Thread id: %2 code: 0x%3 data: 0x%4").
783                             arg(d->m_session.pid).arg(d->m_session.tid).arg(d->m_session.codeseg, 0, 16).
784                             arg(d->m_session.dataseg,  0 ,16);
785         logMessage(msg);
786     }
787     emit applicationRunning(d->m_session.pid);
788     //create a "library" entry for the executable which launched the process
789     Library lib;
790     lib.pid = d->m_session.pid;
791     lib.codeseg = d->m_session.codeseg;
792     lib.dataseg = d->m_session.dataseg;
793     lib.name = d->m_fileName.toUtf8();
794     d->m_session.libraries << lib;
795     emit libraryLoaded(lib);
796 
797     QByteArray ba;
798     appendInt(&ba, d->m_session.pid);
799     appendInt(&ba, d->m_session.tid);
800     d->m_device->sendTrkMessage(TrkContinue, TrkCallback(), ba, "CONTINUE");
801 }
802 
handleWaitForFinished(const TrkResult & result)803 void Launcher::handleWaitForFinished(const TrkResult &result)
804 {
805     logMessage("   FINISHED: " + stringFromArray(result.data));
806     setState(Disconnected);
807     handleFinished();
808 }
809 
handleSupportMask(const TrkResult & result)810 void Launcher::handleSupportMask(const TrkResult &result)
811 {
812     if (result.errorCode() || result.data.size() < 32)
813         return;
814     const char *data = result.data.data() + 1;
815 
816     if (d->m_verbose > 1) {
817         QString str = QLatin1String("SUPPORTED: ");
818         for (int i = 0; i < 32; ++i) {
819             for (int j = 0; j < 8; ++j) {
820                 if (data[i] & (1 << j)) {
821                     str.append(QString::number(i * 8 + j, 16));
822                     str.append(QLatin1Char(' '));
823                 }
824             }
825         }
826         logMessage(str);
827     }
828 }
829 
cleanUp()830 void Launcher::cleanUp()
831 {
832     //
833     //---IDE------------------------------------------------------
834     //  Command: 0x41 Delete Item
835     //  Sub Cmd: Delete Process
836     //ProcessID: 0x0000071F (1823)
837     // [41 24 00 00 00 00 07 1F]
838     QByteArray ba(2, char(0));
839     appendInt(&ba, d->m_session.pid);
840     d->m_device->sendTrkMessage(TrkDeleteItem, TrkCallback(), ba, "Delete process");
841 
842     //---TRK------------------------------------------------------
843     //  Command: 0x80 Acknowledge
844     //    Error: 0x00
845     // [80 24 00]
846 
847     //---IDE------------------------------------------------------
848     //  Command: 0x1C Clear Break
849     // [1C 25 00 00 00 0A 78 6A 43 40]
850 
851         //---TRK------------------------------------------------------
852         //  Command: 0xA1 Notify Deleted
853         // [A1 09 00 00 00 00 00 00 00 00 07 1F]
854         //---IDE------------------------------------------------------
855         //  Command: 0x80 Acknowledge
856         //    Error: 0x00
857         // [80 09 00]
858 
859     //---TRK------------------------------------------------------
860     //  Command: 0x80 Acknowledge
861     //    Error: 0x00
862     // [80 25 00]
863 
864     //---IDE------------------------------------------------------
865     //  Command: 0x1C Clear Break
866     // [1C 26 00 00 00 0B 78 6A 43 70]
867     //---TRK------------------------------------------------------
868     //  Command: 0x80 Acknowledge
869     //    Error: 0x00
870     // [80 26 00]
871 
872 
873     //---IDE------------------------------------------------------
874     //  Command: 0x02 Disconnect
875     // [02 27]
876 //    sendTrkMessage(0x02, TrkCallback(this, &Launcher::handleDisconnect));
877     //---TRK------------------------------------------------------
878     //  Command: 0x80 Acknowledge
879     // Error: 0x00
880 }
881 
disconnectTrk()882 void Launcher::disconnectTrk()
883 {
884     d->m_device->sendTrkMessage(TrkDisconnect, TrkCallback(this, &Launcher::handleWaitForFinished));
885 }
886 
copyFileToRemote()887 void Launcher::copyFileToRemote()
888 {
889     QFileInfo fileInfo(d->m_copyState.destinationFileNames.at(d->m_copyState.currentFileName));
890     emit copyingStarted(fileInfo.fileName());
891     QByteArray ba;
892     ba.append(char(10)); //kDSFileOpenWrite | kDSFileOpenBinary
893     appendString(&ba, d->m_copyState.destinationFileNames.at(d->m_copyState.currentFileName).toLocal8Bit(), TargetByteOrder, false);
894     d->m_device->sendTrkMessage(TrkOpenFile, TrkCallback(this, &Launcher::handleFileCreation), ba);
895 }
896 
copyFileFromRemote()897 void Launcher::copyFileFromRemote()
898 {
899     QFileInfo fileInfo(d->m_downloadState.sourceFileName);
900     emit copyingStarted(fileInfo.fileName());
901     QByteArray ba;
902     ba.append(char(9)); //kDSFileOpenRead | kDSFileOpenBinary
903     appendString(&ba, d->m_downloadState.sourceFileName.toLocal8Bit(), TargetByteOrder, false);
904     d->m_device->sendTrkMessage(TrkOpenFile, TrkCallback(this, &Launcher::handleFileOpened), ba);
905 }
906 
installRemotePackageSilently()907 void Launcher::installRemotePackageSilently()
908 {
909     emit installingStarted(d->m_installFileNames.at(d->m_currentInstallFileName));
910     d->m_currentInstallationStep = InstallationModeSilent;
911     QByteArray ba;
912     ba.append(static_cast<char>(QChar::toUpper((ushort)d->m_installationDrive)));
913     appendString(&ba, d->m_installFileNames.at(d->m_currentInstallFileName).toLocal8Bit(), TargetByteOrder, false);
914     d->m_device->sendTrkMessage(TrkInstallFile, TrkCallback(this, &Launcher::handleInstallPackageFinished), ba);
915 }
916 
installRemotePackageByUser()917 void Launcher::installRemotePackageByUser()
918 {
919     emit installingStarted(d->m_installFileNames.at(d->m_currentInstallFileName));
920     d->m_currentInstallationStep = InstallationModeUser;
921     QByteArray ba;
922     appendString(&ba, d->m_installFileNames.at(d->m_currentInstallFileName).toLocal8Bit(), TargetByteOrder, false);
923     d->m_device->sendTrkMessage(TrkInstallFile2, TrkCallback(this, &Launcher::handleInstallPackageFinished), ba);
924 }
925 
installRemotePackage()926 void Launcher::installRemotePackage()
927 {
928     switch (installationMode()) {
929     case InstallationModeSilent:
930     case InstallationModeSilentAndUser:
931         installRemotePackageSilently();
932         break;
933     case InstallationModeUser:
934         installRemotePackageByUser();
935         break;
936     default:
937         break;
938     }
939 }
940 
handleInstallPackageFinished(const TrkResult & result)941 void Launcher::handleInstallPackageFinished(const TrkResult &result)
942 {
943     if (result.errorCode()) {
944         if (installationMode() == InstallationModeSilentAndUser
945             && d->m_currentInstallationStep & InstallationModeSilent) {
946             installRemotePackageByUser();
947             return;
948         }
949         emit canNotInstall(d->m_installFileNames.at(d->m_currentInstallFileName), result.errorString());
950         disconnectTrk();
951         return;
952     }
953 
954     ++d->m_currentInstallFileName;
955 
956     if (d->m_currentInstallFileName == d->m_installFileNames.size())
957         emit installingFinished();
958 
959     if (d->m_startupActions & ActionInstall && d->m_currentInstallFileName < d->m_installFileNames.size()) {
960         installRemotePackage();
961     } else if (d->m_startupActions & ActionRun) {
962         startInferiorIfNeeded();
963     } else if (d->m_startupActions & ActionDownload) {
964         copyFileFromRemote();
965     } else {
966         disconnectTrk();
967     }
968 }
969 
startProcessMessage(const QString & executable,const QString & arguments)970 QByteArray Launcher::startProcessMessage(const QString &executable,
971                                          const QString &arguments)
972 {
973     // It's not started yet
974     QByteArray ba;
975     appendShort(&ba, 0, TargetByteOrder); // create new process (kDSOSProcessItem)
976     ba.append(char(0)); // options - currently unused
977     // One string consisting of binary terminated by '\0' and arguments terminated by '\0'
978     QByteArray commandLineBa = executable.toLocal8Bit();
979     commandLineBa.append(char(0));
980     if (!arguments.isEmpty())
981         commandLineBa.append(arguments.toLocal8Bit());
982     appendString(&ba, commandLineBa, TargetByteOrder, true);
983     return ba;
984 }
985 
readMemoryMessage(uint pid,uint tid,uint from,uint len)986 QByteArray Launcher::readMemoryMessage(uint pid, uint tid, uint from, uint len)
987 {
988     QByteArray ba;
989     ba.reserve(11);
990     ba.append(char(0x8)); // Options, FIXME: why?
991     appendShort(&ba, len);
992     appendInt(&ba, from);
993     appendInt(&ba, pid);
994     appendInt(&ba, tid);
995     return ba;
996 }
997 
readRegistersMessage(uint pid,uint tid)998 QByteArray Launcher::readRegistersMessage(uint pid, uint tid)
999 {
1000     QByteArray ba;
1001     ba.reserve(15);
1002     ba.append(char(0)); // Register set, only 0 supported
1003     appendShort(&ba, 0); //R0
1004     appendShort(&ba, 16); // last register CPSR
1005     appendInt(&ba, pid);
1006     appendInt(&ba, tid);
1007     return ba;
1008 }
1009 
startInferiorIfNeeded()1010 void Launcher::startInferiorIfNeeded()
1011 {
1012     emit startingApplication();
1013     if (d->m_session.pid != 0) {
1014         logMessage("Process already 'started'");
1015         return;
1016     }
1017 
1018     d->m_device->sendTrkMessage(TrkCreateItem, TrkCallback(this, &Launcher::handleCreateProcess),
1019                                 startProcessMessage(d->m_fileName, d->m_commandLineArgs)); // Create Item
1020 }
1021 
resumeProcess(uint pid,uint tid)1022 void Launcher::resumeProcess(uint pid, uint tid)
1023 {
1024     QByteArray ba;
1025     appendInt(&ba, pid, BigEndian);
1026     appendInt(&ba, tid, BigEndian);
1027     d->m_device->sendTrkMessage(TrkContinue, TrkCallback(), ba, "CONTINUE");
1028 }
1029 
1030 // Acquire a device from SymbianDeviceManager, return 0 if not available.
acquireFromDeviceManager(const QString & serverName,QObject * parent,QString * errorMessage)1031 Launcher *Launcher::acquireFromDeviceManager(const QString &serverName,
1032                                              QObject *parent,
1033                                              QString *errorMessage)
1034 {
1035     SymbianUtils::SymbianDeviceManager *sdm = SymbianUtils::SymbianDeviceManager::instance();
1036     const QSharedPointer<trk::TrkDevice> device = sdm->acquireDevice(serverName);
1037     if (device.isNull()) {
1038         if (serverName.isEmpty())
1039             *errorMessage = tr("No device is connected. Please connect a device and try again.");
1040         else
1041             *errorMessage = tr("Unable to acquire a device for port '%1'. It appears to be in use.").arg(serverName);
1042         return 0;
1043     }
1044     // Wire release signal.
1045     Launcher *rc = new Launcher(trk::Launcher::ActionPingOnly, device, parent);
1046     connect(rc, SIGNAL(deviceDescriptionReceived(QString,QString)),
1047             sdm, SLOT(setAdditionalInformation(QString,QString)));
1048     connect(rc, SIGNAL(destroyed(QString)), sdm, SLOT(releaseDevice(QString)));
1049     return rc;
1050 }
1051 
1052 // Preliminary release of device, disconnecting the signal.
releaseToDeviceManager(Launcher * launcher)1053 void Launcher::releaseToDeviceManager(Launcher *launcher)
1054 {
1055     Q_ASSERT(launcher);
1056 
1057     SymbianUtils::SymbianDeviceManager *sdm = SymbianUtils::SymbianDeviceManager::instance();
1058     // Disentangle launcher and its device, remove connection from destroyed
1059     launcher->setCloseDevice(false);
1060     TrkDevice *device = launcher->trkDevice().data();
1061     launcher->disconnect(device);
1062     device->disconnect(launcher);
1063     launcher->disconnect(sdm);
1064     sdm->releaseDevice(launcher->trkServerName());
1065 }
1066 
getRegistersAndCallStack(uint pid,uint tid)1067 void Launcher::getRegistersAndCallStack(uint pid, uint tid)
1068 {
1069     d->m_device->sendTrkMessage(TrkReadRegisters,
1070                                 TrkCallback(this, &Launcher::handleReadRegisters),
1071                                 Launcher::readRegistersMessage(pid, tid));
1072     d->m_crashReportState.fetchingStackPID = pid;
1073     d->m_crashReportState.fetchingStackTID = tid;
1074 }
1075 
handleReadRegisters(const TrkResult & result)1076 void Launcher::handleReadRegisters(const TrkResult &result)
1077 {
1078     if(result.errorCode() || result.data.size() < (17*4)) {
1079         terminate();
1080         return;
1081     }
1082     const char* data = result.data.constData() + 1;
1083     d->m_crashReportState.registers.clear();
1084     d->m_crashReportState.stack.clear();
1085     for (int i=0;i<17;i++) {
1086         uint r = extractInt(data);
1087         data += 4;
1088         d->m_crashReportState.registers.append(r);
1089     }
1090     d->m_crashReportState.sp = d->m_crashReportState.registers.at(13);
1091 
1092     const ushort len = 1024 - (d->m_crashReportState.sp % 1024); //read to 1k boundary first
1093     const QByteArray ba = Launcher::readMemoryMessage(d->m_crashReportState.fetchingStackPID,
1094                                                       d->m_crashReportState.fetchingStackTID,
1095                                                       d->m_crashReportState.sp,
1096                                                       len);
1097     d->m_device->sendTrkMessage(TrkReadMemory, TrkCallback(this, &Launcher::handleReadStack), ba);
1098     d->m_crashReportState.sp += len;
1099 }
1100 
handleReadStack(const TrkResult & result)1101 void Launcher::handleReadStack(const TrkResult &result)
1102 {
1103     if (result.errorCode()) {
1104         //error implies memory fault when reaching end of stack
1105         emit registersAndCallStackReadComplete(d->m_crashReportState.registers, d->m_crashReportState.stack);
1106         return;
1107     }
1108 
1109     const uint len = extractShort(result.data.constData() + 1);
1110     d->m_crashReportState.stack.append(result.data.mid(3, len));
1111 
1112     if (d->m_crashReportState.sp - d->m_crashReportState.registers.at(13) > 0x10000) {
1113         //read enough stack, stop here
1114         emit registersAndCallStackReadComplete(d->m_crashReportState.registers, d->m_crashReportState.stack);
1115         return;
1116     }
1117     //read 1k more
1118     const QByteArray ba = Launcher::readMemoryMessage(d->m_crashReportState.fetchingStackPID,
1119                                                       d->m_crashReportState.fetchingStackTID,
1120                                                       d->m_crashReportState.sp,
1121                                                       1024);
1122     d->m_device->sendTrkMessage(TrkReadMemory, TrkCallback(this, &Launcher::handleReadStack), ba);
1123     d->m_crashReportState.sp += 1024;
1124 }
1125 
1126 } // namespace trk
1127