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