/************************************************************************** ** ** This file is part of Qt Creator ** ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** ** GNU Lesser General Public License Usage ** ** This file may be used under the terms of the GNU Lesser General Public ** License version 2.1 as published by the Free Software Foundation and ** appearing in the file LICENSE.LGPL included in the packaging of this file. ** Please review the following information to ensure the GNU Lesser General ** Public License version 2.1 requirements will be met: ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** Other Usage ** ** Alternatively, this file may be used in accordance with the terms and ** conditions contained in a signed written agreement between you and Nokia. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** **************************************************************************/ #include "s60devicedebugruncontrol.h" #include "codaruncontrol.h" #include "qt4symbiantarget.h" #include "s60deployconfiguration.h" #include "s60devicerunconfiguration.h" #include #include #include #include #include #include #include using namespace ProjectExplorer; using namespace Qt4ProjectManager::Internal; using namespace Qt4ProjectManager; // Return symbol file which should co-exist with the executable. // location in debug builds. This can be 'foo.sym' (ABLD) or 'foo.exe.sym' (Raptor) static inline QString symbolFileFromExecutable(const QString &executable) { // 'foo.exe.sym' (Raptor) const QFileInfo raptorSymFi(executable + QLatin1String(".sym")); if (raptorSymFi.isFile()) return raptorSymFi.absoluteFilePath(); // 'foo.sym' (ABLD) const int lastDotPos = executable.lastIndexOf(QLatin1Char('.')); if (lastDotPos != -1) { const QString symbolFileName = executable.mid(0, lastDotPos) + QLatin1String(".sym"); const QFileInfo symbolFileNameFi(symbolFileName); if (symbolFileNameFi.isFile()) return symbolFileNameFi.absoluteFilePath(); } return QString(); } // Create start parameters from run configuration static Debugger::DebuggerStartParameters s60DebuggerStartParams(const S60DeviceRunConfiguration *rc) { Debugger::DebuggerStartParameters sp; QTC_ASSERT(rc, return sp); const S60DeployConfiguration *activeDeployConf = qobject_cast(rc->target()->activeDeployConfiguration()); QTC_ASSERT(activeDeployConf, return sp); const QString debugFileName = QString::fromLatin1("%1:\\sys\\bin\\%2.exe") .arg(activeDeployConf->installationDrive()).arg(rc->targetName()); sp.remoteChannel = activeDeployConf->serialPortName(); sp.processArgs = rc->commandLineArguments(); if (rc->useQmlDebugger() && !rc->useCppDebugger()) sp.startMode = Debugger::AttachToRemoteServer; else sp.startMode = Debugger::StartInternal; sp.toolChainAbi = rc->abi(); sp.executable = debugFileName; sp.executableUid = rc->executableUid(); sp.serverAddress = activeDeployConf->deviceAddress(); sp.serverPort = activeDeployConf->devicePort().toInt(); sp.displayName = rc->displayName(); sp.qmlServerAddress = activeDeployConf->deviceAddress(); sp.qmlServerPort = rc->qmlDebugServerPort(); if (rc->useQmlDebugger()) { QString qmlArgs = rc->qmlCommandLineArguments(); if (sp.processArgs.length()) sp.processArgs.prepend(" "); sp.processArgs.prepend(qmlArgs); } sp.communicationChannel = activeDeployConf->communicationChannel() == S60DeployConfiguration::CommunicationCodaTcpConnection? Debugger::DebuggerStartParameters::CommunicationChannelTcpIp: Debugger::DebuggerStartParameters::CommunicationChannelUsb; sp.debugClient = Debugger::DebuggerStartParameters::SymbianDebugClientCoda; if (const ProjectExplorer::Project *project = rc->target()->project()) { sp.projectSourceDirectory = project->projectDirectory(); if (const ProjectExplorer::BuildConfiguration *buildConfig = rc->target()->activeBuildConfiguration()) { sp.projectBuildDirectory = buildConfig->buildDirectory(); } sp.projectSourceFiles = project->files(Project::ExcludeGeneratedFiles); } QTC_ASSERT(sp.executableUid, return sp); // Prefer the '*.sym' file over the '.exe', which should exist at the same // location in debug builds. This can be 'foo.exe' (ABLD) or 'foo.exe.sym' (Raptor) sp.symbolFileName = symbolFileFromExecutable(rc->localExecutableFileName()); return sp; } S60DeviceDebugRunControl::S60DeviceDebugRunControl(S60DeviceRunConfiguration *rc, const Debugger::DebuggerStartParameters &sp, const QPair &masterSlaveEngineTypes) : Debugger::DebuggerRunControl(rc, sp, masterSlaveEngineTypes), m_codaRunControl(NULL), m_codaState(ENotUsingCodaRunControl) { if (startParameters().symbolFileName.isEmpty()) { const QString msg = tr("Warning: Cannot locate the symbol file belonging to %1.\n"). arg(rc->localExecutableFileName()); appendMessage(msg, Utils::ErrorMessageFormat); } if (masterSlaveEngineTypes.first == Debugger::QmlEngineType) { connect(engine(), SIGNAL(requestRemoteSetup()), this, SLOT(remoteSetupRequested())); connect(engine(), SIGNAL(stateChanged(Debugger::DebuggerState)), this, SLOT(qmlEngineStateChanged(Debugger::DebuggerState))); } } void S60DeviceDebugRunControl::start() { appendMessage(tr("Launching debugger...\n"), Utils::NormalMessageFormat); Debugger::DebuggerRunControl::start(); } bool S60DeviceDebugRunControl::promptToStop(bool *) const { // We override the settings prompt return Debugger::DebuggerRunControl::promptToStop(0); } void S60DeviceDebugRunControl::remoteSetupRequested() { // This is called from Engine->setupInferior(), ie InferiorSetupRequested state QTC_ASSERT(runConfiguration()->useQmlDebugger() && !runConfiguration()->useCppDebugger(), return); m_codaRunControl = new CodaRunControl(runConfiguration(), Debugger::Constants::DEBUGMODE); connect(m_codaRunControl, SIGNAL(connected()), this, SLOT(codaConnected())); connect(m_codaRunControl, SIGNAL(finished()), this, SLOT(codaFinished())); connect(m_codaRunControl, SIGNAL(appendMessage(ProjectExplorer::RunControl*,QString,Utils::OutputFormat)), this, SLOT(handleMessageFromCoda(ProjectExplorer::RunControl*,QString,Utils::OutputFormat))); connect(this, SIGNAL(finished()), this, SLOT(handleDebuggingFinished())); m_codaState = EWaitingForCodaConnection; m_codaRunControl->connect(); } void S60DeviceDebugRunControl::codaFinished() { if (m_codaRunControl) { m_codaRunControl->deleteLater(); m_codaRunControl = NULL; } if (m_codaState == EWaitingForCodaConnection) { engine()->handleRemoteSetupFailed(QLatin1String("CODA failed to initialise")); // TODO sort out this error string? Unlikely we'll ever hit this state anyway. } else { debuggingFinished(); } m_codaState = ENotUsingCodaRunControl; } void S60DeviceDebugRunControl::codaConnected() { QTC_ASSERT(m_codaState == EWaitingForCodaConnection, return); m_codaState = ECodaConnected; engine()->handleRemoteSetupDone(-1, -1); // calls notifyInferiorSetupOk() } void S60DeviceDebugRunControl::qmlEngineStateChanged(const Debugger::DebuggerState &state) { if (state == Debugger::EngineRunRequested) m_codaRunControl->run(); } void S60DeviceDebugRunControl::handleDebuggingFinished() { if (m_codaRunControl) { m_codaRunControl->stop(); // We'll get a callback to our codaFinished() slot when it's done } } void S60DeviceDebugRunControl::handleMessageFromCoda(ProjectExplorer::RunControl *aCodaRunControl, const QString &msg, Utils::OutputFormat format) { // This only gets used when QmlEngine is the master debug engine. If GDB is running, messages are handled via the gdb adapter Q_UNUSED(aCodaRunControl) Q_UNUSED(format) engine()->showMessage(msg, Debugger::AppOutput); } // S60DeviceDebugRunControlFactory::S60DeviceDebugRunControlFactory(QObject *parent) : IRunControlFactory(parent) { } bool S60DeviceDebugRunControlFactory::canRun(ProjectExplorer::RunConfiguration *runConfiguration, const QString &mode) const { return mode == QLatin1String(Debugger::Constants::DEBUGMODE) && qobject_cast(runConfiguration) != 0; } ProjectExplorer::RunControl* S60DeviceDebugRunControlFactory::create(ProjectExplorer::RunConfiguration *runConfiguration, const QString &mode) { S60DeviceRunConfiguration *rc = qobject_cast(runConfiguration); QTC_ASSERT(rc && mode == QLatin1String(Debugger::Constants::DEBUGMODE), return 0); const Debugger::DebuggerStartParameters startParameters = s60DebuggerStartParams(rc); const Debugger::ConfigurationCheck check = Debugger::checkDebugConfiguration(startParameters); if (!check) { Core::ICore::instance()->showWarningWithOptions(S60DeviceDebugRunControl::tr("Debugger for Symbian Platform"), check.errorMessage, check.errorDetailsString(), check.settingsCategory, check.settingsPage); return 0; } return new S60DeviceDebugRunControl(rc, startParameters, check.masterSlaveEngineTypes); } QString S60DeviceDebugRunControlFactory::displayName() const { return S60DeviceDebugRunControl::tr("Debug on Device"); } ProjectExplorer::RunConfigWidget *S60DeviceDebugRunControlFactory::createConfigurationWidget(RunConfiguration* /*runConfiguration */) { return 0; }