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