Commit beba423a authored by Friedemann Kleint's avatar Friedemann Kleint

Debugger[Trk]: Added TCF experimental adapter.

Added adapter to work with TCF over WLAN.
Factor out common code for Symbian from TrkAdapter.
Improve message logging in TrkGdbAdapter, some cleanup.
Added new TcfTrkGdbAdapter based on TcfTrkDevice
in symbianutils based on JSON, using QTcpSocket.
To be started via special @tcf@ argument.
Rubber-stamped-by: hjk
parent 03be40dd
......@@ -570,8 +570,6 @@ bool StartExternalDialog::breakAtMain() const
return m_ui->checkBoxBreakAtMain->isChecked();
}
///////////////////////////////////////////////////////////////////////
//
// StartRemoteDialog
......
......@@ -1585,6 +1585,10 @@ void DebuggerPluginPrivate::startExternalApplication()
sp.breakAtMain = dlg.breakAtMain();
if (!dlg.executableArguments().isEmpty())
sp.processArgs = dlg.executableArguments().split(QLatin1Char(' '));
// Fixme: 1 of 3 testing hacks.
if (!sp.processArgs.isEmpty()
&& (sp.processArgs.front() == _("@tcf@") || sp.processArgs.front() == _("@sym@")))
sp.toolChainType = ProjectExplorer::ToolChain::RVCT_ARMV5;
startDebugger(m_debuggerRunControlFactory->create(sp));
}
......
......@@ -338,6 +338,10 @@ void DebuggerRunControl::createEngine(const DebuggerStartParameters &sp)
else
engineType = engineForToolChain(sp.toolChainType);
// Fixme: 1 of 3 testing hacks.
if (sp.processArgs.size() >= 5 && sp.processArgs.at(0) == _("@tcf@"))
engineType = GdbEngineType;
if (engineType == NoEngineType
&& sp.startMode != AttachToRemote
&& !sp.executable.isEmpty())
......
......@@ -10,12 +10,14 @@ HEADERS += \
$$PWD/termgdbadapter.h \
$$PWD/remotegdbserveradapter.h \
$$PWD/trkgdbadapter.h \
$$PWD/tcftrkgdbadapter.h \
$$PWD/s60debuggerbluetoothstarter.h \
$$PWD/abstractgdbprocess.h \
$$PWD/localgdbprocess.h \
$$PWD/remotegdbprocess.h \
$$PWD/remoteplaingdbadapter.h \
$$PWD/abstractplaingdbadapter.h
$$PWD/abstractplaingdbadapter.h \
$$PWD/symbian.h
SOURCES += \
$$PWD/gdbmi.cpp \
......@@ -31,12 +33,14 @@ SOURCES += \
$$PWD/termgdbadapter.cpp \
$$PWD/remotegdbserveradapter.cpp \
$$PWD/trkgdbadapter.cpp \
$$PWD/tcftrkgdbadapter.cpp \
$$PWD/s60debuggerbluetoothstarter.cpp \
$$PWD/abstractgdbprocess.cpp \
$$PWD/localgdbprocess.cpp \
$$PWD/remotegdbprocess.cpp \
$$PWD/remoteplaingdbadapter.cpp \
$$PWD/abstractplaingdbadapter.cpp
$$PWD/abstractplaingdbadapter.cpp \
$$PWD/symbian.cpp
FORMS += $$PWD/gdboptionspage.ui
......
......@@ -43,6 +43,7 @@
#include "remotegdbserveradapter.h"
#include "remoteplaingdbadapter.h"
#include "trkgdbadapter.h"
#include "tcftrkgdbadapter.h"
#include "watchutils.h"
#include "debuggeractions.h"
......@@ -1745,15 +1746,14 @@ AbstractGdbAdapter *GdbEngine::createAdapter()
case ProjectExplorer::ToolChain::RVCT_ARMV6:
case ProjectExplorer::ToolChain::RVCT_ARMV5_GNUPOC:
case ProjectExplorer::ToolChain::GCCE_GNUPOC:
// fixme: 1 of 3 testing hacks
if (sp.processArgs.size() >= 5 && sp.processArgs.at(0) == _("@tcf@"))
return new TcfTrkGdbAdapter(this);
return new TrkGdbAdapter(this);
default:
break;
}
// @todo: remove testing hack
if (sp.processArgs.size() == 3 && sp.processArgs.at(0) == _("@sym@"))
return new TrkGdbAdapter(this);
switch (sp.startMode) {
case AttachCore:
return new CoreGdbAdapter(this);
......
......@@ -99,6 +99,7 @@ private:
friend class RemoteGdbServerAdapter;
friend class RemotePlainGdbAdapter;
friend class TrkGdbAdapter;
friend class TcfTrkGdbAdapter;
private: ////////// General Interface //////////
......
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 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 "symbian.h"
#include <trkutils.h>
#include <utils/qtcassert.h>
#include <QtCore/QDebug>
#include <QtCore/QTextStream>
namespace Debugger {
namespace Internal {
///////////////////////////////////////////////////////////////////////////
//
// MemoryRange
//
///////////////////////////////////////////////////////////////////////////
MemoryRange::MemoryRange(uint f, uint t)
: from(f), to(t)
{
QTC_ASSERT(f <= t, qDebug() << "F: " << f << " T: " << t);
}
bool MemoryRange::intersects(const MemoryRange &other) const
{
Q_UNUSED(other);
QTC_ASSERT(false, /**/);
return false; // FIXME
}
void MemoryRange::operator-=(const MemoryRange &other)
{
if (from == 0 && to == 0)
return;
MEMORY_DEBUG(" SUB: " << *this << " - " << other);
if (other.from <= from && to <= other.to) {
from = to = 0;
return;
}
if (other.from <= from && other.to <= to) {
from = qMax(from, other.to);
return;
}
if (from <= other.from && to <= other.to) {
to = qMin(other.from, to);
return;
}
// This would split the range.
QTC_ASSERT(false, qDebug() << "Memory::operator-() not handled for: "
<< *this << " - " << other);
}
QDebug operator<<(QDebug d, const MemoryRange &range)
{
return d << QString("[%1,%2] (size %3) ")
.arg(range.from, 0, 16).arg(range.to, 0, 16).arg(range.size());
}
namespace Symbian {
static const char *registerNames[KnownRegisters] =
{
"A1", "A2", "A3", "A4",
0, 0, 0, 0,
0, 0, 0, "AP",
"IP", "SP", "LR", "PC",
"PSTrk", 0, 0, 0,
0, 0, 0, 0,
0, "PSGdb"
};
const char *registerName(int i)
{
return registerNames[i];
}
QByteArray dumpRegister(uint n, uint value)
{
QByteArray ba;
ba += ' ';
if (n < KnownRegisters && registerNames[n]) {
ba += registerNames[n];
} else {
ba += '#';
ba += QByteArray::number(n);
}
ba += '=';
ba += trk::hexxNumber(value);
return ba;
}
///////////////////////////////////////////////////////////////////////////
//
// Snapshot
//
///////////////////////////////////////////////////////////////////////////
void Snapshot::reset()
{
for (Memory::Iterator it = memory.begin(); it != memory.end(); ++it) {
if (isReadOnly(it.key())) {
MEMORY_DEBUG("KEEPING READ-ONLY RANGE" << it.key());
} else {
it = memory.erase(it);
}
}
for (int i = 0; i < RegisterCount; ++i)
registers[i] = 0;
registerValid = false;
wantedMemory = MemoryRange();
lineFromAddress = 0;
lineToAddress = 0;
}
void Snapshot::fullReset()
{
memory.clear();
reset();
}
void Snapshot::insertMemory(const MemoryRange &range, const QByteArray &ba)
{
QTC_ASSERT(range.size() == uint(ba.size()),
qDebug() << "RANGE: " << range << " BA SIZE: " << ba.size(); return);
MEMORY_DEBUG("INSERT: " << range);
// Try to combine with existing chunk.
Snapshot::Memory::iterator it = memory.begin();
Snapshot::Memory::iterator et = memory.end();
for ( ; it != et; ++it) {
if (range.from == it.key().to) {
MEMORY_DEBUG("COMBINING " << it.key() << " AND " << range);
QByteArray data = *it;
data.append(ba);
const MemoryRange res(it.key().from, range.to);
memory.remove(it.key());
MEMORY_DEBUG(" TO(1) " << res);
insertMemory(res, data);
return;
}
if (it.key().from == range.to) {
MEMORY_DEBUG("COMBINING " << range << " AND " << it.key());
QByteArray data = ba;
data.append(*it);
const MemoryRange res(range.from, it.key().to);
memory.remove(it.key());
MEMORY_DEBUG(" TO(2) " << res);
insertMemory(res, data);
return;
}
}
// Not combinable, add chunk.
memory.insert(range, ba);
}
QString Snapshot::toString() const
{
typedef QMap<MemoryRange, QByteArray>::const_iterator MemCacheConstIt;
QString rc;
QTextStream str(&rc);
str << "Register valid " << registerValid << ' ';
for (int i = 0; i < RegisterCount; i++) {
if (i)
str << ", ";
str << " R" << i << "=0x";
str.setIntegerBase(16);
str << registers[i];
str.setIntegerBase(10);
}
str << '\n';
// For next step.
if (!memory.isEmpty()) {
str.setIntegerBase(16);
str << "Memory:\n";
const MemCacheConstIt mcend = memory.constEnd();
for (MemCacheConstIt it = memory.constBegin(); it != mcend; ++it)
str << " 0x" << it.key().from << " - 0x" << it.key().to << '\n';
}
return rc;
}
} // namespace Symbian
} // namespace Internal
} // namespace Debugger
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 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 SYMBIANUTILS_H
#define SYMBIANUTILS_H
#include <QtCore/QMap>
#include <QtCore/QByteArray>
#include <QtCore/QMetaType>
QT_BEGIN_NAMESPACE
class QDebug;
QT_END_NAMESPACE
//#define DEBUG_MEMORY 1
#if DEBUG_MEMORY
# define MEMORY_DEBUG(s) qDebug() << s
#else
# define MEMORY_DEBUG(s)
#endif
#define MEMORY_DEBUGX(s) qDebug() << s
namespace Debugger {
namespace Internal {
struct GdbResult {
QByteArray data;
};
struct MemoryRange
{
MemoryRange() : from(0), to(0) {}
MemoryRange(uint f, uint t);
void operator-=(const MemoryRange &other);
bool intersects(const MemoryRange &other) const;
quint64 hash() const { return (quint64(from) << 32) + to; }
bool operator==(const MemoryRange &other) const { return hash() == other.hash(); }
bool operator<(const MemoryRange &other) const { return hash() < other.hash(); }
uint size() const { return to - from; }
uint from; // Inclusive.
uint to; // Exclusive.
};
QDebug operator<<(QDebug d, const MemoryRange &range);
namespace Symbian {
enum CodeMode
{
ArmMode = 0,
ThumbMode,
};
enum TargetConstants
{
RegisterCount = 17,
RegisterSP = 13, // Stack Pointer
RegisterLR = 14, // Return address
RegisterPC = 15, // Program counter
RegisterPSGdb = 25, // gdb's view of the world
RegisterPSTrk = 16, // TRK's view of the world
MemoryChunkSize = 256
};
enum { KnownRegisters = RegisterPSGdb + 1};
const char *registerName(int i);
QByteArray dumpRegister(uint n, uint value);
inline bool isReadOnly(const MemoryRange &mr)
{
return mr.from >= 0x70000000 && mr.to < 0x80000000;
}
struct Snapshot
{
Snapshot() { reset(); }
void reset(); // Leaves read-only memory cache alive.
void fullReset(); // Also removes read-only memory cache.
void insertMemory(const MemoryRange &range, const QByteArray &ba);
QString toString() const;
uint registers[RegisterCount];
bool registerValid;
typedef QMap<MemoryRange, QByteArray> Memory;
Memory memory;
// Current state.
MemoryRange wantedMemory;
// For next step.
uint lineFromAddress;
uint lineToAddress;
bool stepOver;
};
struct Breakpoint
{
Breakpoint(uint offset_ = 0)
{
number = 0;
offset = offset_;
mode = ArmMode;
}
uint offset;
ushort number;
CodeMode mode;
};
} // namespace Symbian
} // namespace Internal
} // namespace Debugger
Q_DECLARE_METATYPE(Debugger::Internal::MemoryRange);
#endif // SYMBIANUTILS_H
This diff is collapsed.
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 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 DEBUGGER_TCFTRKGDBADAPTER_H
#define DEBUGGER_TCFTRKGDBADAPTER_H
#include "abstractgdbadapter.h"
#include "callback.h"
#include "trkutils.h"
#include "symbian.h"
#include <QtCore/QPointer>
#include <QtCore/QSharedPointer>
#include <QtCore/QStringList>
#include <QtCore/QHash>
QT_BEGIN_NAMESPACE
class QTcpServer;
class QTcpSocket;
class QIODevice;
QT_END_NAMESPACE
namespace tcftrk {
struct TcfTrkCommandResult;
class TcfTrkDevice;
class TcfTrkEvent;
class TcfTrkRunControlModuleLoadContextSuspendedEvent;
}
namespace Debugger {
namespace Internal {
struct MemoryRange;
struct GdbResult;
///////////////////////////////////////////////////////////////////////
//
// TcfTrkGdbAdapter
//
///////////////////////////////////////////////////////////////////////
class TcfTrkGdbAdapter : public AbstractGdbAdapter
{
Q_OBJECT
public:
typedef trk::Callback<const GdbResult &> GdbResultCallback;
typedef trk::Callback<const tcftrk::TcfTrkCommandResult &> TcfTrkCallback;
typedef trk::Callback<const GdbResponse &> GdbCallback;
explicit TcfTrkGdbAdapter(GdbEngine *engine);
virtual ~TcfTrkGdbAdapter();
void setGdbServerName(const QString &name);
QString gdbServerName() const { return m_gdbServerName; }
QString gdbServerIP() const;
uint gdbServerPort() const;
Q_SLOT void setVerbose(const QVariant &value);
void setVerbose(int verbose);
void setBufferedMemoryRead(bool b) { m_bufferedMemoryRead = b; }
void trkReloadRegisters();
void trkReloadThreads();
signals:
void output(const QString &msg);
public:
//
// Implementation of GdbProcessBase
//
void start(const QString &program, const QStringList &args,
QIODevice::OpenMode mode = QIODevice::ReadWrite);
void write(const QByteArray &data);
bool isTrkAdapter() const { return true; }
virtual DumperHandling dumperHandling() const { return DumperNotAvailable; }
private:
void startAdapter();
void startInferior();
void startInferiorPhase2();
void interruptInferior();
void shutdown();
void handleWriteRegister(const tcftrk::TcfTrkCommandResult &result);
void reportRegisters();
void handleReadRegisters(const tcftrk::TcfTrkCommandResult &result);
void handleAndReportReadRegisters(const tcftrk::TcfTrkCommandResult &result);
void handleAndReportReadRegister(const tcftrk::TcfTrkCommandResult &result);
void handleAndReportReadRegistersAfterStop(const tcftrk::TcfTrkCommandResult &result);
void handleAndReportSetBreakpoint(const tcftrk::TcfTrkCommandResult &result);
void handleClearBreakpoint(const tcftrk::TcfTrkCommandResult &result);
void handleSignalContinue(const tcftrk::TcfTrkCommandResult &result);
void readMemory(uint addr, uint len, bool buffered);
void handleReadMemoryBuffered(const tcftrk::TcfTrkCommandResult &result);
void handleReadMemoryUnbuffered(const tcftrk::TcfTrkCommandResult &result);
void handleWriteMemory(const tcftrk::TcfTrkCommandResult &result);
void tryAnswerGdbMemoryRequest(bool buffered);
inline void sendMemoryGetCommand(const MemoryRange &range, bool buffered);
inline QByteArray mainThreadContextId() const;
QByteArray memoryReadLogMessage(uint addr, const QByteArray &ba) const;
AbstractGdbProcess *gdbProc() { return &m_gdbProc; }
void cleanup();
void handleTargetRemote(const GdbResponse &response);
QString m_gdbServerName; // 127.0.0.1:(2222+uid)
bool m_running;
tcftrk::TcfTrkDevice *m_trkDevice;
QSharedPointer<QIODevice> m_trkIODevice;