Commit 5c8e6e9f authored by Friedemann Kleint's avatar Friedemann Kleint
Browse files

Trk: Make it run on Windows.

Add options page with overrideable device. Correct
wiring of the rfcomm process.
parent 4843f44c
......@@ -6,14 +6,20 @@ HEADERS += \
$$PWD/gdbengine.h \
$$PWD/gdboptionspage.h \
$$PWD/trkgdbadapter.h \
#$$PWD/gdboptionspage.h \
$$PWD/trkoptions.h \
$$PWD/trkoptionswidget.h \
$$PWD/trkoptionspage.h
SOURCES += \
$$PWD/gdbmi.cpp \
$$PWD/gdbengine.cpp \
$$PWD/gdboptionspage.cpp \
$$PWD/trkgdbadapter.cpp
$$PWD/trkgdbadapter.cpp \
$$PWD/trkoptions.cpp \
$$PWD/trkoptionswidget.cpp \
$$PWD/trkoptionspage.cpp
FORMS += $$PWD/gdboptionspage.ui
FORMS += $$PWD/gdboptionspage.ui \
$$PWD/trkoptionswidget.ui
RESOURCES += $$PWD/gdb.qrc
......@@ -31,6 +31,8 @@
#include "gdbengine.h"
#include "gdboptionspage.h"
#include "trkoptions.h"
#include "trkoptionspage.h"
#include "trkgdbadapter.h"
#include "watchutils.h"
......@@ -4313,9 +4315,11 @@ IDebuggerEngine *createGdbEngine(DebuggerManager *parent,
IDebuggerEngine *createSymbianEngine(DebuggerManager *parent,
QList<Core::IOptionsPage*> *opts)
{
Q_UNUSED(opts);
//opts->push_back(new GdbOptionsPage);
TrkGdbAdapter *adapter = new TrkGdbAdapter;
QSharedPointer<TrkOptions> options(new TrkOptions);
options->fromSettings(Core::ICore::instance()->settings());
opts->push_back(new TrkOptionsPage(options));
TrkGdbAdapter *adapter = new TrkGdbAdapter(options);
GdbEngine *engine = new GdbEngine(parent, adapter);
QObject::connect(adapter, SIGNAL(output(QString)),
parent, SLOT(showDebuggerOutput(QString)));
......
......@@ -28,6 +28,7 @@
**************************************************************************/
#include "trkgdbadapter.h"
#include "trkoptions.h"
#ifndef STANDALONE_RUNNER
#include "gdbengine.h"
#endif
......@@ -36,6 +37,9 @@
# include <unistd.h>
#endif
#include <QtCore/QTimer>
#include <QtCore/QDir>
#define TrkCB(s) TrkCallback(this, &TrkGdbAdapter::s)
......@@ -71,21 +75,21 @@ static QByteArray dumpRegister(int n, uint value)
namespace Debugger {
namespace Internal {
TrkGdbAdapter::TrkGdbAdapter()
TrkGdbAdapter::TrkGdbAdapter(const TrkOptionsPtr &options) :
m_options(options),
m_running(false),
m_gdbAckMode(true),
m_verbose(2),
m_bufferedMemoryRead(true),
m_waitCount(0)
{
m_running = false;
m_gdbAckMode = true;
m_verbose = 2;
m_serialFrame = false;
m_bufferedMemoryRead = true;
m_rfcommDevice = "/dev/rfcomm0";
#ifdef Q_OS_WIN
int userId = 0;
const DWORD portOffset = GetCurrentProcessId() % 100;
#else
uid_t userId = getuid();
const uid_t portOffset = getuid();
#endif
m_gdbServerName = QString("127.0.0.1:%1").arg(2222 + userId);
m_gdbServerName = QString::fromLatin1("127.0.0.1:%1").arg(2222 + portOffset);
connect(&m_gdbProc, SIGNAL(readyReadStandardError()),
this, SIGNAL(readyReadStandardError()));
connect(&m_gdbProc, SIGNAL(readyReadStandardOutput()),
......@@ -103,18 +107,18 @@ TrkGdbAdapter::TrkGdbAdapter()
this, SLOT(handleRfcommReadyReadStandardError()));
connect(&m_rfcommProc, SIGNAL(readyReadStandardOutput()),
this, SLOT(handleRfcommReadyReadStandardOutput()));
connect(&m_gdbProc, SIGNAL(error(QProcess::ProcessError)),
connect(&m_rfcommProc, SIGNAL(error(QProcess::ProcessError)),
this, SLOT(handleRfcommError(QProcess::ProcessError)));
connect(&m_gdbProc, SIGNAL(finished(int, QProcess::ExitStatus)),
connect(&m_rfcommProc, SIGNAL(finished(int, QProcess::ExitStatus)),
this, SLOT(handleRfcommFinished(int, QProcess::ExitStatus)));
connect(&m_gdbProc, SIGNAL(started()),
connect(&m_rfcommProc, SIGNAL(started()),
this, SLOT(handleRfcommStarted()));
connect(&m_gdbProc, SIGNAL(stateChanged(QProcess::ProcessState)),
connect(&m_rfcommProc, SIGNAL(stateChanged(QProcess::ProcessState)),
this, SLOT(handleRfcommStateChanged(QProcess::ProcessState)));
if (m_verbose > 1)
m_trkDevice.setVerbose(true);
m_trkDevice.setSerialFrame(m_serialFrame);
m_trkDevice.setSerialFrame(m_options->mode != TrkOptions::BlueTooth);
connect(&m_trkDevice, SIGNAL(logMessage(QString)),
this, SLOT(trkLogMessage(QString)));
......@@ -126,6 +130,25 @@ TrkGdbAdapter::~TrkGdbAdapter()
logMessage("Shutting down.\n");
}
QString TrkGdbAdapter::overrideTrkDevice() const
{
return m_overrideTrkDevice;
}
void TrkGdbAdapter::setOverrideTrkDevice(const QString &d)
{
m_overrideTrkDevice = d;
}
QString TrkGdbAdapter::effectiveTrkDevice() const
{
if (!m_overrideTrkDevice.isEmpty())
return m_overrideTrkDevice;
if (m_options->mode == TrkOptions::BlueTooth)
return m_options->blueToothDevice;
return m_options->serialPort;
}
void TrkGdbAdapter::trkLogMessage(const QString &msg)
{
logMessage("TRK " + msg);
......@@ -196,9 +219,16 @@ QByteArray TrkGdbAdapter::trkStepRangeMessage(byte option)
void TrkGdbAdapter::startInferior()
{
QString errorMessage;
if (!m_trkDevice.open(m_rfcommDevice, &errorMessage)) {
emit output("LOOPING");
QTimer::singleShot(1000, this, SLOT(startInferior()));
const QString device = effectiveTrkDevice();
if (!m_trkDevice.open(device, &errorMessage)) {
emit output(QString::fromLatin1("Waiting on %1 (%2)").arg(device, errorMessage));
// Do not loop forever
if (m_waitCount++ < (m_options->mode == TrkOptions::BlueTooth ? 60 : 5)) {
QTimer::singleShot(1000, this, SLOT(startInferior()));
} else {
emit output(QString::fromLatin1("Failed to connect to %1 after %2 attempts").arg(device).arg(m_waitCount));
emit finished(-44, QProcess::CrashExit);
}
return;
}
......@@ -1283,14 +1313,21 @@ void TrkGdbAdapter::handleGdbStateChanged(QProcess::ProcessState newState)
void TrkGdbAdapter::run()
{
emit output("### Starting TrkGdbAdapter");
m_rfcommProc.start("rfcomm -r listen " + m_rfcommDevice + " 1");
m_rfcommProc.waitForStarted();
if (m_rfcommProc.state() != QProcess::Running) {
emit finished(-44, QProcess::CrashExit);
return;
emit output(QLatin1String("### Starting TrkGdbAdapter"));
if (m_options->mode == TrkOptions::BlueTooth) {
const QString device = effectiveTrkDevice();
const QString blueToothListener = QLatin1String("rfcomm");
emit output(QString::fromLatin1("### Starting BlueTooth listener %1 on %2").arg(blueToothListener, device));
m_rfcommProc.start(blueToothListener + QLatin1String(" -r listen ") + m_options->blueToothDevice + QLatin1String(" 1"));
m_rfcommProc.waitForStarted();
if (m_rfcommProc.state() != QProcess::Running) {
const QString msg = QString::fromLocal8Bit(m_rfcommProc.readAllStandardError());
emit output(QString::fromLatin1("Failed to start BlueTooth listener %1 on %2: %3\n%4").arg(blueToothListener, device, m_rfcommProc.errorString(), msg));
emit finished(-44, QProcess::CrashExit);
return;
}
}
m_waitCount = 0;
connect(&m_trkDevice, SIGNAL(messageReceived(trk::TrkResult)),
this, SLOT(handleTrkResult(trk::TrkResult)));
......@@ -1300,6 +1337,29 @@ void TrkGdbAdapter::run()
startInferior();
}
#ifdef Q_OS_WIN
// Prepend environment of the Symbian Gdb by Cygwin '/bin'
static void setGdbCygwinEnvironment(const QString &cygwin, QProcess *process)
{
if (cygwin.isEmpty() || !QFileInfo(cygwin).isDir())
return;
const QString cygwinBinPath = QDir::toNativeSeparators(cygwin) + QLatin1String("\\bin");
QStringList env = process->environment();
if (env.isEmpty())
env = QProcess::systemEnvironment();
const QRegExp pathPattern(QLatin1String("^PATH=.*"));
const int index = env.indexOf(pathPattern);
if (index == -1)
return;
QString pathValue = env.at(index).mid(5);
if (pathValue.startsWith(cygwinBinPath))
return;
env[index] = QLatin1String("PATH=") + cygwinBinPath + QLatin1Char(';');
process->setEnvironment(env);
}
#endif
void TrkGdbAdapter::startGdb()
{
if (!m_gdbServer.listen(QHostAddress(gdbServerIP()), gdbServerPort())) {
......@@ -1316,11 +1376,15 @@ void TrkGdbAdapter::startGdb()
this, SLOT(handleGdbConnection()));
logMessage("STARTING GDB");
emit output(QString::fromLatin1("### Starting gdb %1").arg(m_options->gdb));
QStringList gdbArgs;
gdbArgs.append("--nx"); // Do not read .gdbinit file
gdbArgs.append("-i");
gdbArgs.append("mi");
m_gdbProc.start(QDir::currentPath() + "/cs-gdb", gdbArgs);
gdbArgs.append(QLatin1String("--nx")); // Do not read .gdbinit file
gdbArgs.append(QLatin1String("-i"));
gdbArgs.append(QLatin1String("mi"));
#ifdef Q_OS_WIN
setGdbCygwinEnvironment(m_options->cygwin, &m_gdbProc);
#endif
m_gdbProc.start(m_options->gdb, gdbArgs);
}
void TrkGdbAdapter::sendGdbMessage(const QString &msg, GdbCallback callback,
......@@ -1379,12 +1443,15 @@ void TrkGdbAdapter::start(const QString &program, const QStringList &args,
QIODevice::OpenMode mode)
{
Q_UNUSED(mode);
Q_UNUSED(program);
Q_UNUSED(args);
run();
}
void TrkGdbAdapter::kill()
{
m_rfcommProc.kill();
if (m_options->mode == TrkOptions::BlueTooth && m_rfcommProc.state() == QProcess::Running)
m_rfcommProc.kill();
m_gdbProc.kill();
}
......@@ -1402,7 +1469,7 @@ bool TrkGdbAdapter::waitForFinished(int msecs)
m_rfcommProc.terminate();
m_rfcommProc.waitForFinished();
QProcess proc;
proc.start("rfcomm release " + m_rfcommDevice.toLatin1());
proc.start("rfcomm release " + m_options->blueToothDevice);
proc.waitForFinished();
return m_gdbProc.waitForFinished(msecs);
}
......
......@@ -34,34 +34,22 @@
#include "trkdevice.h"
#include "abstractgdbadapter.h"
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QHash>
#include <QtCore/QPointer>
#include <QtCore/QSharedPointer>
#include <QtCore/QProcess>
#include <QtCore/QQueue>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QTextStream>
#include <QtCore/QTimer>
#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QMainWindow>
#include <QtGui/QKeyEvent>
#include <QtGui/QTextBlock>
#include <QtGui/QTextEdit>
#include <QtGui/QToolBar>
#include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
#include <QtNetwork/QLocalServer>
#include <QtNetwork/QLocalSocket>
namespace Debugger {
namespace Internal {
struct TrkOptions;
struct GdbResult
{
QByteArray data;
......@@ -81,18 +69,22 @@ public:
typedef trk::TrkResult TrkResult;
typedef trk::Callback<const TrkResult &> TrkCallback;
typedef trk::Callback<const GdbResult &> GdbCallback;
typedef QSharedPointer<TrkOptions> TrkOptionsPtr;
TrkGdbAdapter();
explicit TrkGdbAdapter(const TrkOptionsPtr &options);
~TrkGdbAdapter();
void setGdbServerName(const QString &name);
QString gdbServerName() const { return m_gdbServerName; }
QString gdbServerIP() const;
uint gdbServerPort() const;
void setVerbose(int verbose) { m_verbose = verbose; }
void setSerialFrame(bool b) { m_serialFrame = b; }
void setBufferedMemoryRead(bool b) { m_bufferedMemoryRead = b; }
trk::Session &session() { return m_session; }
// Set a device (from the project) to override the settings.
QString overrideTrkDevice() const;
void setOverrideTrkDevice(const QString &);
public slots:
void startInferior();
void run();
......@@ -108,7 +100,9 @@ private slots:
private:
friend class RunnerGui;
QString m_rfcommDevice; // /dev/rfcomm0
const TrkOptionsPtr m_options;
QString m_overrideTrkDevice;
QString m_gdbServerName; // 127.0.0.1:(2222+uid)
QProcess m_gdbProc;
......@@ -237,13 +231,15 @@ public:
Q_SLOT void handleRfcommStarted();
Q_SLOT void handleRfcommStateChanged(QProcess::ProcessState newState);
QString effectiveTrkDevice() const;
// Debuggee state
Q_SLOT void executeCommand(const QString &msg);
trk::Session m_session; // global-ish data (process id, target information)
trk::Snapshot m_snapshot; // local-ish data (memory and registers)
int m_verbose;
bool m_serialFrame;
bool m_bufferedMemoryRead;
int m_waitCount;
};
} // namespace Internal
......
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#include "trkoptions.h"
#include <QtCore/QSettings>
#include <QtCore/QFileInfo>
#ifdef Q_OS_WIN
# define SERIALPORT_ROOT "COM"
enum { firstSerialPort = 1, lastSerialPort = 12 };
enum { modeDefault = Debugger::Internal::TrkOptions::Serial };
static const char *serialPortDefaultC = SERIALPORT_ROOT"1";
static const char *gdbDefaultC = "symgdb";
#else
# define SERIALPORT_ROOT "/dev/ttyS"
enum { firstSerialPort = 0, lastSerialPort = 3 };
enum { modeDefault = Debugger::Internal::TrkOptions::BlueTooth };
static const char *serialPortDefaultC = SERIALPORT_ROOT"0";
static const char *gdbDefaultC = "symgdb";
#endif
static const char *settingsGroupC = "S60Debugger";
static const char *serialPortKeyC = "Port";
static const char *modeKeyC = "Mode";
static const char *blueToothDeviceKeyC = "BlueToothDevice";
static const char *blueToothDeviceDefaultC = "/dev/rfcomm0";
static const char *gdbKeyC = "gdb";
static const char *cygwinKeyC = "Cygwin";
static inline QString cygwinDefault()
{
#ifdef Q_OS_WIN
// Some smartness to check for Cygwin
static bool firstTime = true;
static QString rc = QLatin1String("C:/cygwin");
if (firstTime) {
if (!QFileInfo(rc).isDir())
rc.clear();
firstTime = false;
}
return rc;
#else
return QString();
#endif
}
namespace Debugger {
namespace Internal {
TrkOptions::TrkOptions() :
mode(modeDefault),
serialPort(QLatin1String(serialPortDefaultC)),
blueToothDevice(QLatin1String(blueToothDeviceDefaultC)),
gdb(QLatin1String(gdbDefaultC)),
cygwin(cygwinDefault())
{
}
void TrkOptions::fromSettings(const QSettings *s)
{
const QString keyRoot = QLatin1String(settingsGroupC) + QLatin1Char('/');
mode = s->value(keyRoot + QLatin1String(modeKeyC), modeDefault).toInt();
serialPort = s->value(keyRoot + QLatin1String(serialPortKeyC), QLatin1String(serialPortDefaultC)).toString();
gdb = s->value(keyRoot + QLatin1String(gdbKeyC),QLatin1String(gdbDefaultC)).toString();
cygwin = s->value(keyRoot + QLatin1String(cygwinKeyC), cygwinDefault()).toString();
blueToothDevice = s->value(keyRoot + QLatin1String(blueToothDeviceKeyC), QLatin1String(blueToothDeviceDefaultC)).toString();
}
void TrkOptions::toSettings(QSettings *s) const
{
s->beginGroup(QLatin1String(settingsGroupC));
s->setValue(QLatin1String(modeKeyC), mode);
s->setValue(QLatin1String(serialPortKeyC), serialPort);
s->setValue(QLatin1String(blueToothDeviceKeyC), blueToothDevice);
s->setValue(QLatin1String(gdbKeyC), gdb);
s->setValue(QLatin1String(cygwinKeyC), cygwin);
s->endGroup();
}
bool TrkOptions::equals(const TrkOptions &o) const
{
return mode == o.mode
&& serialPort == o.serialPort
&& blueToothDevice == o.blueToothDevice
&& gdb == o.gdb
&& cygwin == o.cygwin;
}
QStringList TrkOptions::serialPorts()
{
QStringList rc;
const QString root = QLatin1String(SERIALPORT_ROOT);
for (int p = firstSerialPort; p != lastSerialPort; p++)
rc.push_back(root + QString::number(p));
return rc;
}
QStringList TrkOptions::blueToothDevices()
{
QStringList rc;
rc.push_back(QLatin1String(blueToothDeviceDefaultC));
return rc;
}
} // namespace Internal
} // namespace Debugger
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#ifndef TRKOPTIONS_H
#define TRKOPTIONS_H
#include <QtCore/QStringList>
QT_BEGIN_NAMESPACE
class QSettings;
QT_END_NAMESPACE
namespace Debugger {
namespace Internal {
/* Parameter to be used for debugging S60 via TRK.
* GDB is a Symbian-ARM Gdb. It is Cygwin-built on Windows; the cygwin
* location 'x/bin' will prepended to the execution path.
* Communication happens either via BlueTooth (Linux only) or
* serial ports. */
struct TrkOptions
{
enum Mode { Serial, BlueTooth };
TrkOptions();
void fromSettings(const QSettings *s);
void toSettings(QSettings *s) const;
bool equals(const TrkOptions &o) const;
// Lists of choices for the devices
static QStringList serialPorts();
static QStringList blueToothDevices();
int mode;
QString serialPort;
QString blueToothDevice;
QString gdb;
QString cygwin; // ignored on Linux
};
inline bool operator==(const TrkOptions &o1, const TrkOptions &o2) { return o1.equals(o2); }
inline bool operator!=(const TrkOptions &o1, const TrkOptions &o2) { return !o1.equals(o2); }
} // namespace Internal
} // namespace Debugger
#endif // TRKOPTIONS_H
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#include "trkoptionspage.h"
#include "trkoptionswidget.h"
#include "trkoptions.h"
#include "debuggerconstants.h"
#include <coreplugin/icore.h>
<