Files
qt-creator/tests/manual/trk/adapter.cpp

366 lines
9.1 KiB
C++

/**************************************************************************
**
** 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://www.qtsoftware.com/contact.
**
**************************************************************************/
#include "trkutils.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QTimer>
#include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
#include <QtNetwork/QLocalServer>
#include <QtNetwork/QLocalSocket>
#ifdef Q_OS_UNIX
#include <signal.h>
void signalHandler(int)
{
qApp->exit(1);
}
#endif
using namespace trk;
class Adapter : public QObject
{
Q_OBJECT
public:
Adapter();
~Adapter();
void setGdbServerName(const QString &name);
void setTrkServerName(const QString &name) { m_trkServerName = name; }
void startServer();
private:
//
// TRK
//
Q_SLOT void readFromTrk();
trk::TrkClient m_trkClient;
QString m_trkServerName;
QByteArray m_trkReadBuffer;
//
// Gdb
//
Q_SLOT void handleGdbConnection();
Q_SLOT void readFromGdb();
void handleGdbResponse(const QByteArray &ba);
void writeToGdb(const QByteArray &msg, bool addAck = true);
void writeAckToGdb();
//
void logMessage(const QString &msg);
QTcpServer m_gdbServer;
QTcpSocket *m_gdbConnection;
QString m_gdbServerName;
quint16 m_gdbServerPort;
QByteArray m_gdbReadBuffer;
bool m_ackMode;
uint m_registers[100];
};
Adapter::Adapter()
{
m_gdbConnection = 0;
m_ackMode = true;
}
Adapter::~Adapter()
{
m_gdbServer.close();
//m_trkClient->disconnectFromServer();
m_trkClient.abort();
logMessage("Shutting down.\n");
}
void Adapter::setGdbServerName(const QString &name)
{
int pos = name.indexOf(':');
if (pos == -1) {
m_gdbServerPort = 0;
m_gdbServerName = name;
} else {
m_gdbServerPort = name.mid(pos + 1).toInt();
m_gdbServerName = name.left(pos);
}
}
void Adapter::startServer()
{
if (!m_trkClient.openPort(m_trkServerName)) {
logMessage("Unable to connect to TRK server");
return;
}
m_trkClient.sendInitialPing();
m_trkClient.sendMessage(0x01); // Connect
//m_trkClient.sendMessage(0x05, CB(handleSupportMask));
//m_trkClient.sendMessage(0x06, CB(handleCpuType));
m_trkClient.sendMessage(0x04); // Versions
//sendMessage(0x09); Unrecognized command
m_trkClient.sendMessage(0x4a, 0,
"10 " + formatString("C:\\data\\usingdlls.sisx")); // Open File
m_trkClient.sendMessage(0x4B, 0, "00 00 00 01 73 1C 3A C8"); // Close File
QByteArray exe = "C:\\sys\\bin\\UsingDLLs.exe";
exe.append('\0');
exe.append('\0');
//m_trkClient.sendMessage(0x40, CB(handleCreateProcess),
// "00 00 00 " + formatString(exe)); // Create Item
logMessage("Connected to TRK server");
return;
if (!m_gdbServer.listen(QHostAddress(m_gdbServerName), m_gdbServerPort)) {
logMessage(QString("Unable to start the gdb server at %1:%2: %3.")
.arg(m_gdbServerName).arg(m_gdbServerPort)
.arg(m_gdbServer.errorString()));
return;
}
logMessage(QString("Gdb server running on port %1. Run arm-gdb now.")
.arg(m_gdbServer.serverPort()));
connect(&m_gdbServer, SIGNAL(newConnection()),
this, SLOT(handleGdbConnection()));
}
void Adapter::logMessage(const QString &msg)
{
qDebug() << "ADAPTER: " << qPrintable(msg);
}
//
// Gdb
//
void Adapter::handleGdbConnection()
{
logMessage("HANDLING GDB CONNECTION");
m_gdbConnection = m_gdbServer.nextPendingConnection();
connect(m_gdbConnection, SIGNAL(disconnected()),
m_gdbConnection, SLOT(deleteLater()));
connect(m_gdbConnection, SIGNAL(readyRead()),
this, SLOT(readFromGdb()));
}
void Adapter::readFromGdb()
{
QByteArray packet = m_gdbConnection->readAll();
m_gdbReadBuffer.append(packet);
logMessage("gdb: -> " + packet);
if (packet != m_gdbReadBuffer)
logMessage("buffer: " + m_gdbReadBuffer);
QByteArray &ba = m_gdbReadBuffer;
while (ba.size()) {
char code = ba.at(0);
ba = ba.mid(1);
if (code == '+') {
//logMessage("ACK");
continue;
}
if (code == '-') {
logMessage("NAK: Retransmission requested");
continue;
}
if (code != '$') {
logMessage("Broken package (2) " + ba);
continue;
}
int pos = ba.indexOf('#');
if (pos == -1) {
logMessage("Invalid checksum format in " + ba);
continue;
}
bool ok = false;
uint checkSum = ba.mid(pos + 1, 2).toInt(&ok, 16);
if (!ok) {
logMessage("Invalid checksum format 2 in " + ba);
return;
}
//logMessage(QString("Packet checksum: %1").arg(checkSum));
uint sum = 0;
for (int i = 0; i < pos; ++i)
sum += ba.at(i);
if (sum % 256 != checkSum) {
logMessage(QString("ERROR: Packet checksum wrong: %1 %2 in " + ba)
.arg(checkSum).arg(sum % 256));
}
QByteArray response = ba.left(pos);
ba = ba.mid(pos + 3);
handleGdbResponse(response);
}
}
void Adapter::writeAckToGdb()
{
if (!m_ackMode)
return;
QByteArray packet = "+";
logMessage("gdb: <- " + packet);
m_gdbConnection->write(packet);
}
void Adapter::writeToGdb(const QByteArray &msg, bool addAck)
{
uint sum = 0;
for (int i = 0; i != msg.size(); ++i)
sum += msg.at(i);
QByteArray checkSum = QByteArray::number(sum % 256, 16);
//logMessage(QString("Packet checksum: %1").arg(sum));
QByteArray packet;
if (addAck)
packet.append("+");
packet.append("$");
packet.append(msg);
packet.append('#');
if (checkSum.size() < 2)
packet.append('0');
packet.append(checkSum);
logMessage("gdb: <- " + packet);
m_gdbConnection->write(packet);
}
void Adapter::handleGdbResponse(const QByteArray &response)
{
// http://sourceware.org/gdb/current/onlinedocs/gdb_34.html
if (response == "qSupported") {
//$qSupported#37
//logMessage("Handling 'qSupported'");
writeToGdb(QByteArray());
}
else if (response == "qAttached") {
//$qAttached#8f
// 1: attached to an existing process
// 0: created a new process
writeToGdb("0");
}
else if (response == "QStartNoAckMode") {
//$qSupported#37
//logMessage("Handling 'QStartNoAckMode'");
writeToGdb(QByteArray("OK"));
m_ackMode = false;
}
else if (response == "g") {
// Read general registers.
writeToGdb("00000000");
}
else if (response.startsWith("Hc")) {
// Set thread for subsequent operations (`m', `M', `g', `G', et.al.).
// for step and continue operations
//$Hc-1#09
writeToGdb("OK");
}
else if (response.startsWith("Hg")) {
// Set thread for subsequent operations (`m', `M', `g', `G', et.al.).
// for 'other operations. 0 - any thread
//$Hg0#df
writeToGdb("OK");
}
else if (response == "pf") {
// current instruction pointer?
writeToGdb("0000");
}
else if (response.startsWith("qC")) {
// Return the current thread ID
//$qC#b4
writeToGdb("QC-1");
}
else if (response.startsWith("?")) {
// Indicate the reason the target halted.
// The reply is the same as for step and continue.
writeToGdb("S0b");
//$?#3f
//$qAttached#8f
//$qOffsets#4b
//$qOffsets#4b
} else {
logMessage("FIXME unknown: " + response);
}
}
void Adapter::readFromTrk()
{
//QByteArray ba = m_gdbConnection->readAll();
//logMessage("Read from gdb: " + ba);
}
int main(int argc, char *argv[])
{
if (argc < 3) {
qDebug() << "Usage: " << argv[0] << " <trkservername> <gdbserverport>";
return 1;
}
#ifdef Q_OS_UNIX
signal(SIGUSR1, signalHandler);
#endif
QCoreApplication app(argc, argv);
Adapter adapter;
adapter.setTrkServerName(argv[1]);
adapter.setGdbServerName(argv[2]);
adapter.startServer();
return app.exec();
}
#include "adapter.moc"