diff --git a/share/qtcreator/gdbmacros/gdbmacros.cpp b/share/qtcreator/gdbmacros/gdbmacros.cpp index 92c8f707a3ca2a170f3ed83c90d2c7e3b99d546e..a1ecaef2949f2fae64ae13c008843dc6ac52abb5 100644 --- a/share/qtcreator/gdbmacros/gdbmacros.cpp +++ b/share/qtcreator/gdbmacros/gdbmacros.cpp @@ -1085,7 +1085,7 @@ static void qDumpQAbstractItem(QDumper &d) //d.putItem("value", "(").put(rowCount).put(",").put(columnCount).put(")"); d.putItem("value", m->data(mi, Qt::DisplayRole).toString()); d.putItem("valueencoded", "2"); - d.putItem("numchild", "1"); + d.putItem("numchild", rowCount * columnCount); if (d.dumpChildren) { d.beginChildren(); for (int row = 0; row < rowCount; ++row) { @@ -1096,7 +1096,7 @@ static void qDumpQAbstractItem(QDumper &d) d.put("[").put(row).put(",").put(column).put("]"); d.endItem(); //d.putItem("numchild", (m->hasChildren(child) ? "1" : "0")); - d.putItem("numchild", "1"); + d.putItem("numchild", m->rowCount(child) * m->columnCount(child)); d.beginItem("addr"); d.put("$").put(child.row()).put(",").put(child.column()).put(",") .put(child.internalPointer()).put(",").put(child.model()); @@ -1158,7 +1158,7 @@ static void qDumpQAbstractItemModel(QDumper &d) d.putItem("value", m.data(mi, Qt::DisplayRole).toString()); d.putItem("valueencoded", "2"); //d.putItem("numchild", (m.hasChildren(mi) ? "1" : "0")); - d.putItem("numchild", "1"); + d.putItem("numchild", m.rowCount(mi) * m.columnCount(mi)); d.beginItem("addr"); d.put("$").put(mi.row()).put(",").put(mi.column()).put(","); d.put(mi.internalPointer()).put(",").put(mi.model()); @@ -3637,8 +3637,8 @@ void *qDumpObjectData440( "\""NS"QFileInfo\"," "\""NS"QHash\"," "\""NS"QHashNode\"," - "\""NS"QImage\"," - "\""NS"QImageData\"," + //"\""NS"QImage\"," + //"\""NS"QImageData\"," "\""NS"QLinkedList\"," "\""NS"QList\"," "\""NS"QLocale\"," diff --git a/tests/manual/gdbdebugger/simple/app.cpp b/tests/manual/gdbdebugger/simple/app.cpp index 0259c0a2e21c1d2d5bcd12ffb1bd27b82d07841c..de03433ea5934fa4b5b1253641ddbc27319febd2 100644 --- a/tests/manual/gdbdebugger/simple/app.cpp +++ b/tests/manual/gdbdebugger/simple/app.cpp @@ -28,6 +28,7 @@ **************************************************************************/ #include <QtCore/QDebug> +#include <QtCore/QDateTime> #include <QtCore/QDir> #include <QtCore/QHash> #include <QtCore/QLibrary> @@ -194,6 +195,16 @@ void testQByteArray() ba += 2; } +void testQDateTime() +{ + QDateTime date; + date = QDateTime::currentDateTime(); + date = date.addSecs(5); + date = date.addSecs(5); + date = date.addSecs(5); + date = date.addSecs(5); +} + void testQFileInfo() { QFileInfo fi("/tmp/t"); @@ -553,6 +564,7 @@ void testQSet() QObject ob; QSet<QPointer<QObject> > hash; QPointer<QObject> ptr(&ob); + ptr; //hash.insert(ptr); //hash.insert(ptr); //hash.insert(ptr); @@ -592,7 +604,7 @@ public: private: QSharedDataPointer<EmployeeData> d; - }; +}; void testQSharedPointer() @@ -1301,6 +1313,7 @@ int main(int argc, char *argv[]) testQStack(); testUninitialized(); testPointer(); + testQDateTime(); testQFileInfo(); testObject1(); testVector1(); diff --git a/tests/manual/trk/README b/tests/manual/trk/README index 7c834470ceb1d969c8202262297b58c1999b6971..f8b12329459d0ee12767e77b221dfb8af2045773 100644 --- a/tests/manual/trk/README +++ b/tests/manual/trk/README @@ -37,7 +37,8 @@ rfcomm listen /dev/rfcomm0 1 $PWD/trklauncher -v -f {} #The same with the debug adapter: -rfcomm listen /dev/rfcomm0 1 $PWD/run.pl -af -av -w {} +rfcomm listen /dev/rfcomm0 1 $PWD/run.pl -af -av -w {} +rfcomm listen /dev/rfcomm0 1 $PWD/runner -af -av -w {} #Important options: -w wait for adapter, -af omit serial frame. diff --git a/tests/manual/trk/adapter.cpp b/tests/manual/trk/adapter.cpp index b66444c66e645f462376451b3fe692f6f0e1e9b1..12a23d973361fba326b102953094ef9b57367bff 100644 --- a/tests/manual/trk/adapter.cpp +++ b/tests/manual/trk/adapter.cpp @@ -115,7 +115,9 @@ public: void setRegisterEndianness(Endianness r) { m_registerEndianness = r; } void setUseSocket(bool s) { m_useSocket = s; } void setBufferedMemoryRead(bool b) { qDebug() << "Buffered=" << b; m_bufferedMemoryRead = b; } - bool startServer(); + +public slots: + void startServer(); private slots: void handleResult(const trk::TrkResult &data); @@ -141,7 +143,7 @@ private: // kill process and breakpoints void cleanUp(); - void handleCpuType(const TrkResult &result); + void handleCpuType(const TrkResult &result); void handleCreateProcess(const TrkResult &result); void handleClearBreakpoint(const TrkResult &result); void handleSignalContinue(const TrkResult &result); @@ -247,12 +249,14 @@ void Adapter::setGdbServerName(const QString &name) } } -bool Adapter::startServer() +void Adapter::startServer() { QString errorMessage; if (!openTrkPort(m_trkServerName, &errorMessage)) { logMessage(errorMessage, true); - return false; + logMessage("LOOPING"); + QTimer::singleShot(1000, this, SLOT(startServer())); + return; } sendTrkInitialPing(); @@ -271,7 +275,8 @@ bool Adapter::startServer() logMessage(QString("Unable to start the gdb server at %1:%2: %3.") .arg(m_gdbServerName).arg(m_gdbServerPort) .arg(m_gdbServer.errorString()), true); - return false; + QCoreApplication::exit(5); + return; } logMessage(QString("Gdb server running on %1:%2.\nRegister endianness: %3\nRun arm-gdb now.") @@ -279,7 +284,6 @@ bool Adapter::startServer() connect(&m_gdbServer, SIGNAL(newConnection()), this, SLOT(handleGdbConnection())); - return true; } void Adapter::logMessage(const QString &msg, bool force) @@ -1521,9 +1525,8 @@ int main(int argc, char *argv[]) adapter.setRegisterEndianness(options.registerEndianness); adapter.setUseSocket(options.useSocket); adapter.setSerialFrame(options.serialFrame); - if (adapter.startServer()) - return app.exec(); - return 4; + QTimer::singleShot(0, &adapter, SLOT(startServer())); + return app.exec(); } #include "adapter.moc" diff --git a/tests/manual/trk/runner.cpp b/tests/manual/trk/runner.cpp index e1280ffc769f5e3e210747b919ebe4f971dc638d..45cc4ba9bac09517bd889e1a44b7854b04d28058 100755 --- a/tests/manual/trk/runner.cpp +++ b/tests/manual/trk/runner.cpp @@ -27,35 +27,90 @@ ** **************************************************************************/ +#include "trkutils.h" +#include "trkdevice.h" + #include <QtCore/QCoreApplication> #include <QtCore/QDebug> #include <QtCore/QDir> #include <QtCore/QFile> #include <QtCore/QHash> +#include <QtCore/QPointer> #include <QtCore/QProcess> +#include <QtCore/QQueue> #include <QtCore/QString> #include <QtCore/QStringList> #include <QtCore/QTextStream> #include <QtCore/QTimer> #include <QtGui/QApplication> +#include <QtGui/QKeyEvent> +#include <QtGui/QTextBlock> #include <QtGui/QTextEdit> -#include <unistd.h> +#include <QtNetwork/QTcpServer> +#include <QtNetwork/QTcpSocket> +#include <QtNetwork/QLocalServer> +#include <QtNetwork/QLocalSocket> + + +using namespace trk; + +enum { KnownRegisters = RegisterPSGdb + 1}; + +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" +}; + +static inline void dumpRegister(int n, uint value, QByteArray &a) +{ + a += ' '; + if (n < KnownRegisters && registerNames[n]) { + a += registerNames[n]; + } else { + a += '#'; + a += QByteArray::number(n); + } + a += "=0x"; + a += QByteArray::number(value, 16); +} /////////////////////////////////////////////////////////////////////// // -// Runner +// Adapter // /////////////////////////////////////////////////////////////////////// -class Runner : public QObject +class Adapter : public QObject { Q_OBJECT public: - Runner(); - void parseArguments(const QStringList &args); + typedef TrkFunctor1<const TrkResult &> Callback; + + Adapter(); + ~Adapter(); + void setGdbServerName(const QString &name); + QString gdbServerIP() const; + uint gdbServerPort() const; + void setTrkServerName(const QString &name) { m_trkServerName = name; } + void setVerbose(int verbose) { m_verbose = verbose; } + void setSerialFrame(bool b) { m_serialFrame = b; } + void setRegisterEndianness(Endianness r) { m_registerEndianness = r; } + void setBufferedMemoryRead(bool b) { qDebug() << "Buffered=" << b; m_bufferedMemoryRead = b; } + +public slots: + void startServer(); + +private slots: + void handleResult(const trk::TrkResult &data); signals: void output(const QString &senderName, const QString &data); @@ -68,300 +123,1463 @@ private slots: void handleProcStarted(); void handleProcStateChanged(QProcess::ProcessState newState); void run(); - void runRfcomm(); + void startGdb(); private: friend class RunnerGui; - void launchAdapter(); - void launchTrkServer(); - void writeGdbInit(); void connectProcess(QProcess *proc); void sendOutput(QObject *sender, const QString &data); void sendOutput(const QString &data) { sendOutput(0, data); } - QStringList m_adapterOptions; QStringList m_trkServerOptions; QString m_endianness; QString m_trkServerName; - bool m_runTrkServer; bool m_isUnix; bool m_waitForAdapter; - QString m_gdbServerIP; - QString m_gdbServerPort; + QString m_gdbServerName; // 127.0.0.1:(2222+uid) + + QProcess m_gdbProc; + QProcess m_rfcommProc; + +public: + // + // TRK + // + + bool openTrkPort(const QString &port, QString *errorMessage); // or server name for local server + void sendTrkMessage(byte code, + Callback callBack = Callback(), + const QByteArray &data = QByteArray(), + const QVariant &cookie = QVariant(), + bool invokeOnFailure = false); + + // convenience messages + void sendTrkInitialPing(); + void sendTrkContinue(); + void waitForTrkFinished(); + void sendTrkAck(byte token); + + // kill process and breakpoints + void cleanUp(); + + void handleCpuType(const TrkResult &result); + void handleCreateProcess(const TrkResult &result); + void handleClearBreakpoint(const TrkResult &result); + void handleSignalContinue(const TrkResult &result); + void handleWaitForFinished(const TrkResult &result); + void handleStop(const TrkResult &result); + void handleSupportMask(const TrkResult &result); + void handleTrkVersions(const TrkResult &result); + void handleDisconnect(const TrkResult &result); + + void handleAndReportCreateProcess(const TrkResult &result); + void handleAndReportReadRegisters(const TrkResult &result); + QByteArray memoryReadLogMessage(uint addr, uint len, const QByteArray &ba) const; + void handleAndReportSetBreakpoint(const TrkResult &result); + void handleReadMemoryBuffered(const TrkResult &result); + void handleReadMemoryUnbuffered(const TrkResult &result); + void reportReadMemoryBuffered(const TrkResult &result); + void reportToGdb(const TrkResult &result); + + void clearTrkBreakpoint(const Breakpoint &bp); - QProcess m_adapterProc; - QProcess m_trkServerProc; - QProcess m_debuggerProc; + void handleSetTrkBreakpoint(const TrkResult &result); + void setTrkBreakpoint(const Breakpoint &bp); + + void readMemory(uint addr, uint len); + void startInferiorIfNeeded(); + void interruptInferior(); + + TrkWriteQueueDevice m_trkDevice; + + QList<Breakpoint> m_breakpoints; + + // + // Gdb + // + Q_SLOT void handleGdbConnection(); + Q_SLOT void readFromGdb(); + void handleGdbResponse(const QByteArray &ba); + void sendGdbMessage(const QByteArray &msg, const QByteArray &logNote = QByteArray()); + void sendGdbMessageAfterSync(const QByteArray &msg, const QByteArray &logNote = QByteArray()); + void sendGdbAckMessage(); + bool sendGdbPacket(const QByteArray &packet, bool doFlush); + void executeGdbCommand(const QString &msg); + + void logMessage(const QString &msg, bool force = false); + + QTcpServer m_gdbServer; + QPointer<QTcpSocket> m_gdbConnection; + QByteArray m_gdbReadBuffer; + bool m_gdbAckMode; + + // Debuggee state + Session m_session; // global-ish data (process id, target information) + Snapshot m_snapshot; // local-ish data (memory and registers) + int m_verbose; + Endianness m_registerEndianness; + bool m_serialFrame; + bool m_startInferiorTriggered; + bool m_bufferedMemoryRead; }; -Runner::Runner() +Adapter::Adapter() { + m_gdbAckMode = true; + m_verbose = 1; + m_registerEndianness = LittleEndian; + //m_serialFrame = true; + m_serialFrame = false; + m_startInferiorTriggered = false; + m_bufferedMemoryRead = true; + // m_breakpoints.append(Breakpoint(0x0040)); // E32Main + m_trkServerName = "/dev/rfcomm0"; + #ifdef Q_OS_UNIX m_isUnix = true; #else m_isUnix = false; #endif m_endianness = "little"; - m_runTrkServer = true; m_waitForAdapter = false; uid_t userId = getuid(); - m_gdbServerIP = "127.0.0.1"; - m_gdbServerPort = QString::number(2222 + userId); + m_gdbServerName = QString("127.0.0.1:%1").arg(2222 + userId); - m_trkServerProc.setObjectName("TRKSERVER PROCESS"); - m_adapterProc.setObjectName("ADAPTER PROCESS"); - m_debuggerProc.setObjectName("GDB PROCESS"); + m_gdbProc.setObjectName("GDB PROCESS"); + connectProcess(&m_gdbProc); - connectProcess(&m_trkServerProc); - connectProcess(&m_adapterProc); - connectProcess(&m_debuggerProc); + m_rfcommProc.setObjectName("RFCOMM PROCESS"); + connectProcess(&m_rfcommProc); } -void Runner::connectProcess(QProcess *proc) +Adapter::~Adapter() { - connect(proc, SIGNAL(error(QProcess::ProcessError)), - this, SLOT(handleProcError(QProcess::ProcessError))); - connect(proc, SIGNAL(finished(int, QProcess::ExitStatus)), - this, SLOT(handleProcFinished(int, QProcess::ExitStatus))); - connect(proc, SIGNAL(readyReadStandardError()), - this, SLOT(handleProcReadyReadStandardError())); - connect(proc, SIGNAL(readyReadStandardOutput()), - this, SLOT(handleProcReadyReadStandardOutput())); - connect(proc, SIGNAL(started()), - this, SLOT(handleProcStarted())); - connect(proc, SIGNAL(stateChanged(QProcess::ProcessState)), - this, SLOT(handleProcStateChanged(QProcess::ProcessState))); + // Trk + + // Gdb + m_gdbServer.close(); + logMessage("Shutting down.\n", true); } +void Adapter::setGdbServerName(const QString &name) +{ + m_gdbServerName = name; +} -void Runner::sendOutput(QObject *sender, const QString &data) +QString Adapter::gdbServerIP() const { - if (sender) - emit output(sender->objectName(), data); - else - emit output(QString(), data); + int pos = m_gdbServerName.indexOf(':'); + if (pos == -1) + return m_gdbServerName; + return m_gdbServerName.left(pos); } -void Runner::handleProcError(QProcess::ProcessError error) +uint Adapter::gdbServerPort() const { - sendOutput(sender(), QString("Process Error %1").arg(error)); + int pos = m_gdbServerName.indexOf(':'); + if (pos == -1) + return 0; + return m_gdbServerName.mid(pos + 1).toUInt(); } -void Runner::handleProcFinished(int exitCode, QProcess::ExitStatus exitStatus) +void Adapter::startServer() { - sendOutput(sender(), - QString("ProcessFinished %1 %2").arg(exitCode).arg(exitStatus)); + QString errorMessage; + if (!openTrkPort(m_trkServerName, &errorMessage)) { + logMessage(errorMessage, true); + logMessage("LOOPING"); + QTimer::singleShot(1000, this, SLOT(startServer())); + return; + } + + sendTrkInitialPing(); + sendTrkMessage(0x01); // Connect + sendTrkMessage(0x05, Callback(this, &Adapter::handleSupportMask)); + sendTrkMessage(0x06, Callback(this, &Adapter::handleCpuType)); + sendTrkMessage(0x04, Callback(this, &Adapter::handleTrkVersions)); // Versions + //sendTrkMessage(0x09); // Unrecognized command + //sendTrkMessage(0x4a, 0, + // "10 " + formatString("C:\\data\\usingdlls.sisx")); // Open File + //sendTrkMessage(0x4B, 0, "00 00 00 01 73 1C 3A C8"); // Close File + + logMessage("Connected to TRK server"); + + if (!m_gdbServer.listen(QHostAddress(gdbServerIP()), gdbServerPort())) { + logMessage(QString("Unable to start the gdb server at %1: %2.") + .arg(m_gdbServerName).arg(m_gdbServer.errorString()), true); + QCoreApplication::exit(5); + return; + } + + logMessage(QString("Gdb server running on %1.\nRegister endianness: %3.") + .arg(m_gdbServerName).arg(m_registerEndianness), true); + + connect(&m_gdbServer, SIGNAL(newConnection()), + this, SLOT(handleGdbConnection())); + + startGdb(); } -void Runner::handleProcReadyReadStandardError() +void Adapter::logMessage(const QString &msg, bool force) { - QByteArray ba = qobject_cast<QProcess *>(sender())->readAllStandardError(); - sendOutput(sender(), QString("stderr: %1").arg(QString::fromLatin1(ba))); + if (m_verbose || force) + emit output("ADAPTER: ", msg); } -void Runner::handleProcReadyReadStandardOutput() +// +// Gdb +// +void Adapter::handleGdbConnection() { - QByteArray ba = qobject_cast<QProcess *>(sender())->readAllStandardOutput(); - sendOutput(sender(), QString("stdout: %1").arg(QString::fromLatin1(ba))); + 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())); + m_startInferiorTriggered = false; } -void Runner::handleProcStarted() +static inline QString msgGdbPacket(const QString &p) { - sendOutput(sender(), QString("Process Started")); + return QLatin1String("gdb: -> ") + p; } -void Runner::handleProcStateChanged(QProcess::ProcessState newState) +void Adapter::readFromGdb() { - sendOutput(sender(), QString("Process State %1").arg(newState)); + QByteArray packet = m_gdbConnection->readAll(); + m_gdbReadBuffer.append(packet); + + logMessage(msgGdbPacket(QString::fromAscii(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 == char(0x03)) { + logMessage("INTERRUPT RECEIVED"); + interruptInferior(); + continue; + } + + if (code != '$') { + logMessage("Broken package (2) " + quoteUnprintableLatin1(ba) + + hexNumber(code)); + continue; + } + + int pos = ba.indexOf('#'); + if (pos == -1) { + logMessage("Invalid checksum format in " + + quoteUnprintableLatin1(ba)); + continue; + } + + bool ok = false; + uint checkSum = ba.mid(pos + 1, 2).toUInt(&ok, 16); + if (!ok) { + logMessage("Invalid checksum format 2 in " + + quoteUnprintableLatin1(ba)); + return; + } + + //logMessage(QString("Packet checksum: %1").arg(checkSum)); + byte sum = 0; + for (int i = 0; i < pos; ++i) + sum += ba.at(i); + + if (sum != checkSum) { + logMessage(QString("ERROR: Packet checksum wrong: %1 %2 in " + + quoteUnprintableLatin1(ba)).arg(checkSum).arg(sum)); + } + + QByteArray response = ba.left(pos); + ba.remove(0, pos + 3); + handleGdbResponse(response); + } +} + +bool Adapter::sendGdbPacket(const QByteArray &packet, bool doFlush) +{ + if (!m_gdbConnection || m_gdbConnection->state() != QAbstractSocket::ConnectedState) { + logMessage(QString::fromLatin1("Cannot write to gdb: Not connected (%1)").arg(QString::fromLatin1(packet)), true); + return false; + } + if (m_gdbConnection->write(packet) == -1) { + logMessage(QString::fromLatin1("Cannot write to gdb: %1 (%2)").arg(m_gdbConnection->errorString()).arg(QString::fromLatin1(packet)), true); + return false; + } + if (doFlush) + m_gdbConnection->flush(); + return true; +} + +void Adapter::sendGdbAckMessage() +{ + if (!m_gdbAckMode) + return; + QByteArray packet = "+"; + logMessage("gdb: <- " + packet); + sendGdbPacket(packet, false); +} + +void Adapter::sendGdbMessage(const QByteArray &msg, const QByteArray &logNote) +{ + byte sum = 0; + for (int i = 0; i != msg.size(); ++i) + sum += msg.at(i); + + char checkSum[30]; + qsnprintf(checkSum, sizeof(checkSum) - 1, "%02x ", sum); + + //logMessage(QString("Packet checksum: %1").arg(sum)); + + QByteArray packet; + packet.append("$"); + packet.append(msg); + packet.append('#'); + packet.append(checkSum); + int pad = qMax(0, 24 - packet.size()); + logMessage("gdb: <- " + packet + QByteArray(pad, ' ') + logNote); + sendGdbPacket(packet, true); +} + +void Adapter::sendGdbMessageAfterSync(const QByteArray &msg, const QByteArray &logNote) +{ + QByteArray ba = msg + char(1) + logNote; + sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, Callback(this, &Adapter::reportToGdb), "", ba); // Answer gdb +} + +void Adapter::reportToGdb(const TrkResult &result) +{ + QByteArray message = result.cookie.toByteArray(); + QByteArray note; + int pos = message.lastIndexOf(char(1)); // HACK + if (pos != -1) { + note = message.mid(pos + 1); + message = message.left(pos); + } + message.replace("@CODESEG@", hexNumber(m_session.codeseg)); + message.replace("@DATASEG@", hexNumber(m_session.dataseg)); + message.replace("@PID@", hexNumber(m_session.pid)); + message.replace("@TID@", hexNumber(m_session.tid)); + sendGdbMessage(message, note); +} + +static QByteArray breakpointTrkMessage(uint addr, int len, int pid, bool armMode = true) +{ + QByteArray ba; + appendByte(&ba, 0x82); // unused option + appendByte(&ba, armMode /*bp.mode == ArmMode*/ ? 0x00 : 0x01); + appendInt(&ba, addr); + appendInt(&ba, len); + appendInt(&ba, 0x00000001); + appendInt(&ba, pid); + appendInt(&ba, 0xFFFFFFFF); + return ba; +} + +void Adapter::handleGdbResponse(const QByteArray &response) +{ + // http://sourceware.org/gdb/current/onlinedocs/gdb_34.html + if (0) {} + + else if (response == "!") { + sendGdbAckMessage(); + sendGdbMessage("", "extended mode not enabled"); + //sendGdbMessage("OK", "extended mode enabled"); + } + + else if (response.startsWith("?")) { + if (m_verbose) + logMessage(msgGdbPacket(QLatin1String("Query halted"))); + // Indicate the reason the target halted. + // The reply is the same as for step and continue. + sendGdbAckMessage(); + startInferiorIfNeeded(); + sendGdbMessage("T05library:r;", "target halted (library load)"); + // trap 05 + // sendGdbMessage("S05", "target halted (trap)"); + } + + else if (response == "c") { + if (m_verbose) + logMessage(msgGdbPacket(QLatin1String("continue"))); + sendGdbAckMessage(); + QByteArray ba; + appendByte(&ba, 0); // options + appendInt(&ba, 0); // start address + appendInt(&ba, 0); // end address + appendInt(&ba, m_session.pid); + appendInt(&ba, m_session.tid); + sendTrkMessage(0x18, Callback(), ba); + // FIXME: should be triggered by real stop + //sendGdbMessageAfterSync("S11", "target stopped"); + } + + else if (response.startsWith("C")) { + if (m_verbose) + logMessage(msgGdbPacket(QLatin1String("continue with signal"))); + // C sig[;addr] Continue with signal sig (hex signal number) + //Reply: See section D.3 Stop Reply Packets, for the reply specifications. + sendGdbAckMessage(); + bool ok = false; + uint signalNumber = response.mid(1).toInt(&ok, 16); + QByteArray ba; + appendInt(&ba, m_session.pid); + appendInt(&ba, m_session.tid); + sendTrkMessage(0x18, Callback(this, &Adapter::handleSignalContinue), ba, signalNumber); // Continue + } + + else if (response.startsWith("D")) { + sendGdbAckMessage(); + sendGdbMessage("OK", "shutting down"); + qApp->quit(); + } + + else if (response == "g") { + if (m_verbose) + logMessage(msgGdbPacket(QLatin1String("read registers"))); + // Read general registers. + //sendGdbMessage("00000000", "read registers"); + sendGdbAckMessage(); + QByteArray ba; + appendByte(&ba, 0); // Register set, only 0 supported + appendShort(&ba, 0); + appendShort(&ba, RegisterCount - 1); // last register + appendInt(&ba, m_session.pid); + appendInt(&ba, m_session.tid); + sendTrkMessage(0x12, Callback(this, &Adapter::handleAndReportReadRegisters), ba, QVariant(), true); + } + + else if (response.startsWith("Hc")) { + if (m_verbose) + logMessage(msgGdbPacket(QLatin1String("Set thread & continue"))); + // Set thread for subsequent operations (`m', `M', `g', `G', et.al.). + // for step and continue operations + //$Hc-1#09 + sendGdbAckMessage(); + sendGdbMessage("OK", "set current thread for step & continue"); + } + + else if (response.startsWith("Hg")) { + if (m_verbose) + logMessage(msgGdbPacket(QLatin1String("Set thread"))); + // Set thread for subsequent operations (`m', `M', `g', `G', et.al.). + // for 'other operations. 0 - any thread + //$Hg0#df + sendGdbAckMessage(); + m_session.currentThread = response.mid(2).toInt(0, 16); + sendGdbMessage("OK", "set current thread " + + QByteArray::number(m_session.currentThread)); + } + + else if (response == "k") { + if (m_verbose) + logMessage(msgGdbPacket(QLatin1String("kill"))); + // kill + sendGdbAckMessage(); + QByteArray ba; + appendByte(&ba, 0); // Sub-command: Delete Process + appendInt(&ba, m_session.pid); + sendTrkMessage(0x41, Callback(), ba, "Delete process"); // Delete Item + sendGdbMessageAfterSync("", "process killed"); + } + + else if (response.startsWith("m")) { + if (m_verbose) + logMessage(msgGdbPacket(QLatin1String("read memory"))); + // m addr,length + sendGdbAckMessage(); + uint addr = 0, len = 0; + do { + const int pos = response.indexOf(','); + if (pos == -1) + break; + bool ok; + addr = response.mid(1, pos - 1).toUInt(&ok, 16); + if (!ok) + break; + len = response.mid(pos + 1).toUInt(&ok, 16); + if (!ok) + break; + } while (false); + if (len) { + readMemory(addr, len); + } else { + sendGdbMessage("E20", "Error " + response); + } + } + else if (response.startsWith("p")) { + if (m_verbose) + logMessage(msgGdbPacket(QLatin1String("read register"))); + // 0xf == current instruction pointer? + //sendGdbMessage("0000", "current IP"); + sendGdbAckMessage(); + #if 0 + A1 = 0, first integer-like argument + A4 = 3, last integer-like argument + AP = 11, + IP = 12, + SP = 13, Contains address of top of stack + LR = 14, address to return to from a function call + PC = 15, Contains program counter + F0 = 16, first floating point register + F3 = 19, last floating point argument register + F7 = 23, last floating point register + FPS = 24, floating point status register + PS = 25, Contains processor status + WR0, WMMX data registers. + WR15 = WR0 + 15, + WC0, WMMX control registers. + WCSSF = WC0 + 2, + WCASF = WC0 + 3, + WC7 = WC0 + 7, + WCGR0, WMMX general purpose registers. + WCGR3 = WCGR0 + 3, + WCGR7 = WCGR0 + 7, + NUM_REGS, + + // Other useful registers. + FP = 11, Frame register in ARM code, if used. + THUMB_FP = 7, Frame register in Thumb code, if used. + NUM_ARG_REGS = 4, + LAST_ARG = A4, + NUM_FP_ARG_REGS = 4, + LAST_FP_ARG = F3 + #endif + bool ok = false; + const uint registerNumber = response.mid(1).toInt(&ok, 16); + QByteArray logMsg = "read register"; + if (registerNumber == RegisterPSGdb) { + QByteArray ba; + appendInt(&ba, m_snapshot.registers[RegisterPSTrk], m_registerEndianness); + dumpRegister(registerNumber, m_snapshot.registers[RegisterPSTrk], logMsg); + sendGdbMessage(ba.toHex(), logMsg); + } else if (registerNumber < RegisterCount) { + QByteArray ba; + appendInt(&ba, m_snapshot.registers[registerNumber], m_registerEndianness); + dumpRegister(registerNumber, m_snapshot.registers[registerNumber], logMsg); + sendGdbMessage(ba.toHex(), logMsg); + } else { + sendGdbMessage("0000", "read single unknown register #" + QByteArray::number(registerNumber)); + //sendGdbMessage("E01", "read single unknown register"); + } + } + + else if (response == "qAttached") { + //$qAttached#8f + // 1: attached to an existing process + // 0: created a new process + sendGdbAckMessage(); + sendGdbMessage("0", "new process created"); + //sendGdbMessage("1", "attached to existing process"); + //sendGdbMessage("E01", "new process created"); + } + + else if (response.startsWith("qC")) { + if (m_verbose) + logMessage(msgGdbPacket(QLatin1String("query thread id"))); + // Return the current thread ID + //$qC#b4 + sendGdbAckMessage(); + startInferiorIfNeeded(); + sendGdbMessageAfterSync("QC@TID@"); + } + + else if (response.startsWith("qSupported")) { + //$qSupported#37 + //$qSupported:multiprocess+#c6 + //logMessage("Handling 'qSupported'"); + sendGdbAckMessage(); + if (0) + sendGdbMessage(QByteArray(), "nothing supported"); + else + sendGdbMessage( + "PacketSize=7cf;" + //"QPassSignals+;" + "qXfer:libraries:read+;" + //"qXfer:auxv:read+;" + "qXfer:features:read+"); + } + + else if (response == "qPacketInfo") { + // happens with gdb 6.4.50.20060226-cvs / CodeSourcery + // deprecated by qSupported? + sendGdbAckMessage(); + sendGdbMessage("", "FIXME: nothing?"); + } + + else if (response == "qOffsets") { + sendGdbAckMessage(); + startInferiorIfNeeded(); + sendGdbMessageAfterSync("TextSeg=@CODESEG@;DataSeg=@DATASEG@"); + } + + else if (response == "qSymbol::") { + if (m_verbose) + logMessage(msgGdbPacket(QLatin1String("notify can handle symbol lookup"))); + // Notify the target that GDB is prepared to serve symbol lookup requests. + sendGdbAckMessage(); + if (1) + sendGdbMessage("OK", "no further symbols needed"); + else + sendGdbMessage("qSymbol:" + QByteArray("_Z7E32Mainv").toHex(), "ask for more"); + } + + else if (response.startsWith("qXfer:features:read:target.xml:")) { + // $qXfer:features:read:target.xml:0,7ca#46...Ack + sendGdbAckMessage(); + sendGdbMessage("l<target><architecture>symbianelf</architecture></target>"); + } + + else if (response == "QStartNoAckMode") { + //$qSupported#37 + //logMessage("Handling 'QStartNoAckMode'"); + sendGdbAckMessage(); + sendGdbMessage("OK", "ack no-ack mode"); + m_gdbAckMode = false; + } + + else if (response.startsWith("QPassSignals")) { + // list of signals to pass directly to inferior + // $QPassSignals:e;10;14;17;1a;1b;1c;21;24;25;4c;#8f + // happens only if "QPassSignals+;" is qSupported + sendGdbAckMessage(); + // FIXME: use the parameters + sendGdbMessage("OK", "passing signals accepted"); + } + + else if (response == "s") { + if (m_verbose) + logMessage(msgGdbPacket(QLatin1String("Step range"))); + sendGdbAckMessage(); + QByteArray ba; + appendByte(&ba, 0); // options + appendInt(&ba, m_snapshot.registers[RegisterPC]); // start address + appendInt(&ba, m_snapshot.registers[RegisterPC] + 4); // end address + appendInt(&ba, m_session.pid); + appendInt(&ba, m_session.tid); + sendTrkMessage(0x19, Callback(), ba, "Step range"); + // FIXME: should be triggered by "real" stop" + //sendGdbMessageAfterSync("S05", "target halted"); + } + + else if (response == "vCont?") { + // actions supported by the vCont packet + sendGdbAckMessage(); + sendGdbMessage(""); // we don't support vCont. + //sendGdbMessage("vCont;c"); + } + + //else if (response.startsWith("vCont")) { + // // vCont[;action[:thread-id]]...' + //} + + else if (response.startsWith("vKill")) { + // kill + sendGdbAckMessage(); + QByteArray ba; + appendByte(&ba, 0); // Sub-command: Delete Process + appendInt(&ba, m_session.pid); + sendTrkMessage(0x41, Callback(), ba, "Delete process"); // Delete Item + sendGdbMessageAfterSync("", "process killed"); + } + + else if (response.startsWith("Z0,")) { // Insert breakpoint + if (m_verbose) + logMessage(msgGdbPacket(QLatin1String("Insert breakpoint"))); + // $z0,786a4ccc,4#99 + const int pos = response.lastIndexOf(','); + bool ok = false; + const uint addr = response.mid(3, pos - 1).toInt(&ok, 16); + const uint len = response.mid(pos + 1).toInt(&ok, 16); + if (m_verbose) + logMessage(QString::fromLatin1("Inserting breakpoint at 0x%1, %2").arg(addr,0 ,16).arg(len)); + + //---IDE------------------------------------------------------ + // Command: 0x1B Set Break + //BreakType: 0x82 + // Options: 0x00 + // Address: 0x78674340 (2020033344) i.e + 0x00000340 + // Length: 0x00000001 (1) + // Count: 0x00000000 (0) + //ProcessID: 0x000001b5 (437) + // ThreadID: 0xffffffff (-1) + // [1B 09 82 00 78 67 43 40 00 00 00 01 00 00 00 00 + // 00 00 01 B5 FF FF FF FF] + const QByteArray ba = breakpointTrkMessage(addr, len, m_session.pid); + sendTrkMessage(0x1B, Callback(this, &Adapter::handleAndReportSetBreakpoint), ba); + //m_session.toekn + + //---TRK------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x00 + // [80 09 00 00 00 00 0A] + } else if (response.startsWith("qPart:") || response.startsWith("qXfer:")) { + QByteArray data = response.mid(1 + response.indexOf(':')); + // "qPart:auxv:read::0,147": Read OS auxiliary data (see info aux) + bool handled = false; + if (data.startsWith("auxv:read::")) { + const int offsetPos = data.lastIndexOf(':') + 1; + const int commaPos = data.lastIndexOf(','); + if (commaPos != -1) { + bool ok1 = false, ok2 = false; + const int offset = data.mid(offsetPos, commaPos - offsetPos).toInt(&ok1, 16); + const int length = data.mid(commaPos + 1).toInt(&ok2, 16); + if (ok1 && ok2) { + const QString msg = QString::fromLatin1("Read of OS auxilary vector (%1, %2) not implemented.").arg(offset).arg(length); + logMessage(msgGdbPacket(msg), true); + sendGdbMessage("E20", msg.toLatin1()); + handled = true; + } + } + } // auxv read + if (!handled) { + const QString msg = QLatin1String("FIXME unknown 'XFER'-request: ") + QString::fromAscii(response); + logMessage(msgGdbPacket(msg), true); + sendGdbMessage("E20", msg.toLatin1()); + } + } // qPart/qXfer + else { + logMessage(msgGdbPacket(QLatin1String("FIXME unknown: ") + QString::fromAscii(response))); + } +} + +void Adapter::executeGdbCommand(const QString &msg) +{ + logMessage("EXECUTING GDB COMMAND " + msg); + if (msg == "S") + m_gdbProc.write("-exec-interrupt"); + else + m_gdbProc.write(msg.toLatin1()); +} + +bool Adapter::openTrkPort(const QString &port, QString *errorMessage) +{ + connect(&m_trkDevice, SIGNAL(messageReceived(trk::TrkResult)), + this, SLOT(handleResult(trk::TrkResult))); + if (m_verbose > 1) + m_trkDevice.setVerbose(true); + m_trkDevice.setSerialFrame(m_serialFrame); + return m_trkDevice.open(port, errorMessage); +} + +void Adapter::sendTrkMessage(byte code, Callback callBack, + const QByteArray &data, const QVariant &cookie, bool invokeOnFailure) +{ + m_trkDevice.sendTrkMessage(code, callBack, data, cookie, invokeOnFailure); +} + +void Adapter::sendTrkInitialPing() +{ + m_trkDevice.sendTrkInitialPing(); +} + +void Adapter::sendTrkContinue() +{ + QByteArray ba; + appendInt(&ba, m_session.pid); + appendInt(&ba, m_session.tid); + sendTrkMessage(0x18, Callback(), ba, "CONTINUE"); +} + +void Adapter::waitForTrkFinished() +{ + // initiate one last roundtrip to ensure all is flushed + sendTrkMessage(0x0, Callback(this, &Adapter::handleWaitForFinished)); } +void Adapter::sendTrkAck(byte token) +{ + logMessage(QString("SENDING ACKNOWLEDGEMENT FOR TOKEN %1").arg(int(token))); + m_trkDevice.sendTrkAck(token); +} -static QString usage() -{ - return QString("Usage: %1 -w -av -aq -au -tv -tq -l [COM]\n\n" - "Options:\n" - " -av Adapter verbose\n" - " -aq Adapter quiet\n" - " -au Adapter turn off buffered memory read\n" - " -af Adapter turn off serial frame\n" - " -w Wait for termination of Adapter (Bluetooth)\n" - " -tv TrkServer verbose\n" - " -tq TrkServer quiet\n" - "\n" - " trkserver simulator will be run unless COM is specified\n" - "\n" - "Bluetooth:\n" - " rfcomm listen /dev/rfcomm0 1 $PWD/run.pl -av -af -w {}\n") - .arg(QCoreApplication::arguments().at(0)); -} - -void Runner::parseArguments(const QStringList &args) -{ - for (int i = 1; i < args.size(); ++i) { - const QString arg = args.at(i); - if (arg.startsWith('-')) { - if (arg == "-av") { - m_adapterOptions.append("-v"); - } else if (arg == "-aq") { - m_adapterOptions.append("-q"); - } else if (arg == "-af") { - m_adapterOptions.append("-f"); - } else if (arg == "-au") { - m_adapterOptions.append("-u"); - } else if (arg == "-w") { - m_waitForAdapter = true; - } else if (arg == "-tv") { - m_trkServerOptions.append("-v"); - } else if (arg == "-tq") { - m_trkServerOptions.append("-q"); - } else if (arg == "-h") { - qDebug() << usage(); - qApp->exit(0); +void Adapter::handleResult(const TrkResult &result) +{ + if (result.isDebugOutput) { + logMessage(QLatin1String("APPLICATION OUTPUT: ") + QString::fromAscii(result.data)); + return; + } + QByteArray prefix = "READ BUF: "; + QByteArray str = result.toString().toUtf8(); + switch (result.code) { + case 0x80: // ACK + break; + case 0xff: { // NAK. This mostly means transmission error, not command failed. + QString logMsg; + QTextStream(&logMsg) << prefix << "NAK: for token=" << result.token << " ERROR: " << errorMessage(result.data.at(0)) << ' ' << str; + logMessage(logMsg, true); + break; + } + case 0x90: { // Notified Stopped + // 90 01 78 6a 40 40 00 00 07 23 00 00 07 24 00 00 + const char *data = result.data.data(); + const uint addr = extractInt(data); //code address: 4 bytes; code base address for the library + const uint pid = extractInt(data + 4); // ProcessID: 4 bytes; + const uint tid = extractInt(data + 8); // ThreadID: 4 bytes + logMessage(prefix + QString::fromLatin1("NOTE: PID %1/TID %2 STOPPED at 0x%3").arg(pid).arg(tid).arg(addr, 0, 16)); + sendTrkAck(result.token); + if (addr) { + // Todo: Do not send off GdbMessages if a synced gdb query is pending, queue instead + sendGdbMessage("S05", "Target stopped"); } else { - qDebug() << usage(); - qApp->exit(1); + if (m_verbose) + logMessage(QLatin1String("Ignoring stop at 0")); } - } else { - m_trkServerName = arg; - m_runTrkServer = false; + break; + } + case 0x91: { // Notify Exception (obsolete) + logMessage(prefix + "NOTE: EXCEPTION " + str); + sendTrkAck(result.token); + break; + } + case 0x92: { // + logMessage(prefix + "NOTE: INTERNAL ERROR: " + str); + sendTrkAck(result.token); + break; + } + + // target->host OS notification + case 0xa0: { // Notify Created + const char *data = result.data.data(); + const byte error = result.data.at(0); + const byte type = result.data.at(1); // type: 1 byte; for dll item, this value is 2. + const uint pid = extractInt(data + 2); // ProcessID: 4 bytes; + const uint tid = extractInt(data + 6); //threadID: 4 bytes + const uint codeseg = extractInt(data + 10); //code address: 4 bytes; code base address for the library + const uint dataseg = extractInt(data + 14); //data address: 4 bytes; data base address for the library + const uint len = extractShort(data + 18); //length: 2 bytes; length of the library name string to follow + const QByteArray name = result.data.mid(20, len); // name: library name + m_session.modules += QString::fromAscii(name); + QString logMsg; + QTextStream str(&logMsg); + str<< prefix << " NOTE: LIBRARY LOAD: token=" << result.token; + if (error) + str<< " ERROR: " << int(error); + str << " TYPE: " << int(type) << " PID: " << pid << " TID: " << tid; + str.setIntegerBase(16); + str << " CODE: 0x" << codeseg << " DATA: 0x" << dataseg; + str.setIntegerBase(10); + str << " NAME: '" << name << '\''; + logMessage(logMsg); + sendTrkContinue(); + break; + } + case 0xa1: { // NotifyDeleted + const ushort itemType = (unsigned char)result.data.at(1); + const ushort len = result.data.size() > 12 ? extractShort(result.data.data() + 10) : ushort(0); + const QString name = len ? QString::fromAscii(result.data.mid(12, len)) : QString(); + if (!name.isEmpty()) + m_session.modules.removeAll(name); + logMessage(QString::fromLatin1("%1 %2 UNLOAD: %3"). + arg(QString::fromAscii(prefix)).arg(itemType ? QLatin1String("LIB") : QLatin1String("PROCESS")). + arg(name)); + sendTrkAck(result.token); + break; + } + case 0xa2: { // NotifyProcessorStarted + logMessage(prefix + "NOTE: PROCESSOR STARTED: " + str); + sendTrkAck(result.token); + break; + } + case 0xa6: { // NotifyProcessorStandby + logMessage(prefix + "NOTE: PROCESSOR STANDBY: " + str); + sendTrkAck(result.token); + break; + } + case 0xa7: { // NotifyProcessorReset + logMessage(prefix + "NOTE: PROCESSOR RESET: " + str); + sendTrkAck(result.token); + break; + } + default: { + logMessage(prefix + "INVALID: " + str); + break; } } } -void Runner::launchTrkServer() +void Adapter::handleCpuType(const TrkResult &result) +{ + //---TRK------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x00 + // [80 03 00 04 00 00 04 00 00 00] + m_session.cpuMajor = result.data[1]; + m_session.cpuMinor = result.data[2]; + m_session.bigEndian = result.data[3]; + m_session.defaultTypeSize = result.data[4]; + m_session.fpTypeSize = result.data[5]; + m_session.extended1TypeSize = result.data[6]; + //m_session.extended2TypeSize = result.data[6]; + QString logMsg; + QTextStream(&logMsg) << "HANDLE CPU TYPE: CPU=" << m_session.cpuMajor << '.' + << m_session.cpuMinor << " bigEndian=" << m_session.bigEndian + << " defaultTypeSize=" << m_session.defaultTypeSize + << " fpTypeSize=" << m_session.fpTypeSize + << " extended1TypeSize=" << m_session.extended1TypeSize; + logMessage(logMsg); +} + +void Adapter::setTrkBreakpoint(const Breakpoint &bp) { - sendOutput("Launching Trk Server"); - const QString dumpPostfix = ".bin"; + //---IDE------------------------------------------------------ + // Command: 0x1B Set Break + //BreakType: 0x82 + // Options: 0x00 + // Address: 0x78674340 (2020033344) i.e + 0x00000340 + // Length: 0x00000001 (1) + // Count: 0x00000000 (0) + //ProcessID: 0x000001b5 (437) + // ThreadID: 0xffffffff (-1) + // [1B 09 82 00 78 67 43 40 00 00 00 01 00 00 00 00 + // 00 00 01 B5 FF FF FF FF] + const QByteArray ba = breakpointTrkMessage(m_session.codeseg + bp.offset, 1, m_session.pid); + sendTrkMessage(0x1B, Callback(this, &Adapter::handleSetTrkBreakpoint), ba); - QString trkServerName; - if (m_isUnix) - trkServerName = QDir::currentPath() + "/trkserver"; - else - trkServerName = "cmd.exe"; + //---TRK------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x00 + // [80 09 00 00 00 00 0A] +} + +void Adapter::handleSetTrkBreakpoint(const TrkResult &result) +{ + //---TRK------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x00 + // [80 09 00 00 00 00 0A] + const uint bpnr = extractInt(result.data.data()); + if (m_verbose) + logMessage(QString::fromLatin1("SET BREAKPOINT %1 %2").arg(bpnr).arg(stringFromArray(result.data.data()))); +} + +void Adapter::handleCreateProcess(const TrkResult &result) +{ + // 40 00 00] + //logMessage(" RESULT: " + result.toString()); + // [80 08 00 00 00 01 B5 00 00 01 B6 78 67 40 00 00 40 00 00] + const char *data = result.data.data(); + m_session.pid = extractInt(data + 1); + m_session.tid = extractInt(data + 5); + m_session.codeseg = extractInt(data + 9); + m_session.dataseg = extractInt(data + 13); + QString logMsg = QString::fromLatin1("handleCreateProcess PID=%1 TID=%2 CODE=0x%3 (%4) DATA=0x%5 (%6)") + .arg(m_session.pid).arg(m_session.tid).arg(m_session.codeseg, 0 ,16).arg(m_session.codeseg).arg(m_session.dataseg, 0, 16).arg(m_session.dataseg); + logMessage(logMsg); + foreach (const Breakpoint &bp, m_breakpoints) + setTrkBreakpoint(bp); + + sendTrkContinue(); +#if 0 + /* + logMessage("PID: " + formatInt(m_session.pid) + m_session.pid); + logMessage("TID: " + formatInt(m_session.tid) + m_session.tid); + logMessage("COD: " + formatInt(m_session.codeseg) + m_session.codeseg); + logMessage("DAT: " + formatInt(m_session.dataseg) + m_session.dataseg); + */ + + + //setTrkBreakpoint(0x0000, ArmMode); + //clearTrkBreakpoint(0x0000); + + + + +#if 1 + //---IDE------------------------------------------------------ + // Command: 0x42 Read Info + // [42 0C 00 06 00 00 00 00 00 14 50 6F 6C 79 6D 6F + // 72 70 68 69 63 44 4C 4C 32 2E 64 6C 6C 00] + sendTrkMessage(0x42, Callback(this, &Adapter::handleReadInfo), + "00 06 00 00 00 00 00 14 50 6F 6C 79 6D 6F " + "72 70 68 69 63 44 4C 4C 32 2E 64 6C 6C 00"); + //sendTrkMessage(0x42, Callback(this, &Adapter::handleReadInfo), + // "00 01 00 00 00 00"); + //---TRK------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x20 Unspecified general OS-related error + // [80 0C 20] + + + //---IDE------------------------------------------------------ + // Command: 0x42 Read Info + // [42 0D 00 06 00 00 00 00 00 14 50 6F 6C 79 6D 6F + // 72 70 68 69 63 44 4C 4C 31 2E 64 6C 6C 00] + sendTrkMessage(0x42, Callback(this, &Adapter::handleReadInfo), + "00 06 00 00 00 00 00 14 50 6F 6C 79 6D 6F " + "72 70 68 69 63 44 4C 4C 31 2E 64 6C 6C 00"); + //---TRK------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x20 Unspecified general OS-related error + // [80 0D 20] +#endif + + //sendTrkMessage(0x18, Callback(this, &Adapter::handleStop), + // "01 " + formatInt(m_session.pid) + formatInt(m_session.tid)); + + //---IDE------------------------------------------------------ + // Command: 0x18 Continue + //ProcessID: 0x000001B5 (437) + // ThreadID: 0x000001B6 (438) + // [18 0E 00 00 01 B5 00 00 01 B6] + QByteArray ba; + appendInt(&ba, m_session.pid); + appendInt(&ba, m_session.tid); + sendTrkMessage(0x18, Callback(this, &Adapter::handleContinue), ba); + //sendTrkMessage(0x18, Callback(this, &Adapter::handleContinue), + // formatInt(m_session.pid) + "ff ff ff ff"); + //---TRK------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x00 + // [80 0E 00] +#endif +} - QStringList trkServerArgs; - if (!m_isUnix) { - trkServerArgs << "/c" << "start" - << QDir::currentPath() + "/debug/trkserver.exe"; +void Adapter::handleAndReportReadRegisters(const TrkResult &result) +{ + //logMessage(" RESULT: " + result.toString()); + // [80 0B 00 00 00 00 00 C9 24 FF BC 00 00 00 00 00 + // 60 00 00 00 00 00 00 78 67 79 70 00 00 00 00 00...] + + const char *data = result.data.data() + 1; // Skip ok byte + for (int i = 0; i < RegisterCount; ++i) { + m_snapshot.registers[i] = extractInt(data + 4 * i); + } + QByteArray ba; + for (int i = 0; i < 16; ++i) { + const uint reg = m_registerEndianness == LittleEndian ? swapEndian(m_snapshot.registers[i]) : m_snapshot.registers[i]; + ba += hexNumber(reg, 8); } + QByteArray logMsg = "register contents"; + if (m_verbose > 1) { + for (int i = 0; i < RegisterCount; ++i) + dumpRegister(i, m_snapshot.registers[i], logMsg); + } + sendGdbMessage(ba, logMsg); +} - trkServerArgs << m_trkServerOptions; - trkServerArgs << m_trkServerName; - trkServerArgs << "TrkDump-78-6a-40-00" + dumpPostfix; - trkServerArgs << "0x00402000" + dumpPostfix; - trkServerArgs << "0x786a4000" + dumpPostfix; - trkServerArgs << "0x00600000" + dumpPostfix; +static inline QString msgMemoryReadError(int code, uint addr, uint len = 0) +{ + const QString lenS = len ? QString::number(len) : QLatin1String("<unknown>"); + return QString::fromLatin1("Memory read error %1 at: 0x%2 %3").arg(code).arg(addr, 0 ,16).arg(lenS); +} - sendOutput("### Starting " + trkServerName + " " + trkServerArgs.join(" ")); - m_trkServerProc.start(trkServerName, trkServerArgs); - m_trkServerProc.waitForStarted(); +void Adapter::handleReadMemoryBuffered(const TrkResult &result) +{ + const uint blockaddr = result.cookie.toUInt(); + if (const int errorCode = result.errorCode()) { + logMessage(msgMemoryReadError(errorCode, blockaddr)); + return; + } + const QByteArray ba = result.data.mid(1); + m_snapshot.memory.insert(blockaddr , ba); } -void Runner::launchAdapter() +// Format log message for memory access with some smartness about registers +QByteArray Adapter::memoryReadLogMessage(uint addr, uint len, const QByteArray &ba) const { - QString adapterName; - if (m_isUnix) - adapterName = QDir::currentPath() + "/adapter"; - else - adapterName = "cmd.exe"; + QByteArray logMsg = "memory contents"; + if (m_verbose > 1) { + logMsg += " addr: 0x"; + logMsg += QByteArray::number(addr, 16); + // indicate dereferencing of registers + if (len == 4) { + if (addr == m_snapshot.registers[RegisterPC]) { + logMsg += "[PC]"; + } else if (addr == m_snapshot.registers[RegisterPSTrk]) { + logMsg += "[PSTrk]"; + } else if (addr == m_snapshot.registers[RegisterSP]) { + logMsg += "[SP]"; + } else if (addr == m_snapshot.registers[RegisterLR]) { + logMsg += "[LR]"; + } else if (addr > m_snapshot.registers[RegisterSP] && (addr - m_snapshot.registers[RegisterSP]) < 10240) { + logMsg += "[SP+"; // Stack area ...stack seems to be top-down + logMsg += QByteArray::number(addr - m_snapshot.registers[RegisterSP]); + logMsg += ']'; + } + } + logMsg += " length "; + logMsg += QByteArray::number(len); + logMsg += " :"; + logMsg += stringFromArray(ba, 16); + } + return logMsg; +} - QStringList adapterArgs; - if (!m_isUnix) { - adapterArgs << "/c" << "start" - << QDir::currentPath() + "/debug/adapter.exe"; +void Adapter::reportReadMemoryBuffered(const TrkResult &result) +{ + const qulonglong cookie = result.cookie.toULongLong(); + const uint addr = cookie >> 32; + const uint len = uint(cookie); + + // Gdb accepts less memory according to documentation. + // Send E on complete failure. + QByteArray ba; + uint blockaddr = (addr / MemoryChunkSize) * MemoryChunkSize; + for (; blockaddr < addr + len; blockaddr += MemoryChunkSize) { + const Snapshot::Memory::const_iterator it = m_snapshot.memory.constFind(blockaddr); + if (it == m_snapshot.memory.constEnd()) + break; + ba.append(it.value()); } - adapterArgs << m_adapterOptions; - //adapterArgs << "-s"; - adapterArgs << m_trkServerName << m_gdbServerIP + ':' + m_gdbServerPort; + const int previousChunkOverlap = addr % MemoryChunkSize; + if (previousChunkOverlap != 0 && ba.size() > previousChunkOverlap) + ba.remove(0, previousChunkOverlap); + if (ba.size() > int(len)) + ba.truncate(len); - sendOutput("### Starting " + adapterName + " " + adapterArgs.join(" ")); + if (ba.isEmpty()) { + ba = "E20"; + sendGdbMessage(ba, msgMemoryReadError(32, addr, len).toLatin1()); + } else { + sendGdbMessage(ba.toHex(), memoryReadLogMessage(addr, len, ba)); + } +} - m_adapterProc.start(adapterName, adapterArgs); - m_adapterProc.waitForStarted(); - //die ('Unable to launch adapter') if $adapterpid == -1; +void Adapter::handleReadMemoryUnbuffered(const TrkResult &result) +{ + const uint blockaddr = result.cookie.toUInt(); + if (const int errorCode = result.errorCode()) { + const QByteArray ba = "E20"; + sendGdbMessage(ba, msgMemoryReadError(32, blockaddr).toLatin1()); + } else { + const QByteArray ba = result.data.mid(1); + sendGdbMessage(ba.toHex(), memoryReadLogMessage(blockaddr, ba.size(), ba)); + } +} -/* - if (m_waitForAdapter) { - print '### kill -USR1 ',$adapterpid,"\n"; - waitpid($adapterpid, 0); - } -*/ +void Adapter::handleAndReportSetBreakpoint(const TrkResult &result) +{ + //---TRK------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x00 + // [80 09 00 00 00 00 0A] + uint bpnr = extractInt(result.data.data()); + logMessage("SET BREAKPOINT " + bpnr + stringFromArray(result.data.data())); + sendGdbMessage("OK"); } -void Runner::writeGdbInit() +void Adapter::clearTrkBreakpoint(const Breakpoint &bp) { - qDebug() << "WRITE GDBINIT"; - QString gdbInitFile = QDir::currentPath() + "/.gdbinit"; - QFile file(gdbInitFile); - if (!file.open(QIODevice::ReadWrite)) { - sendOutput(QString("Cannot open %1 for writing").arg(gdbInitFile)); + //---IDE------------------------------------------------------ + // Command: 0x1C Clear Break + // [1C 25 00 00 00 0A 78 6A 43 40] + QByteArray ba; + appendByte(&ba, 0x00); + appendShort(&ba, bp.number); + appendInt(&ba, m_session.codeseg + bp.offset); + sendTrkMessage(0x1C, Callback(this, &Adapter::handleClearBreakpoint), ba); +} + +void Adapter::handleClearBreakpoint(const TrkResult &result) +{ + Q_UNUSED(result); + //---TRK------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x00 + // [80 09 00 00 00 00 0A] + logMessage("CLEAR BREAKPOINT "); +} + +void Adapter::handleSignalContinue(const TrkResult &result) +{ + int signalNumber = result.cookie.toInt(); + logMessage(" HANDLE SIGNAL CONTINUE: " + stringFromArray(result.data)); + logMessage("NUMBER" + QString::number(signalNumber)); + sendGdbMessage("O" + QByteArray("Console output").toHex()); + sendGdbMessage("W81"); // "Process exited with result 1 +} + +void Adapter::handleWaitForFinished(const TrkResult &result) +{ + logMessage(" FINISHED: " + stringFromArray(result.data)); + //qApp->exit(1); +} + +void Adapter::handleSupportMask(const TrkResult &result) +{ + const char *data = result.data.data(); + QByteArray str; + for (int i = 0; i < 32; ++i) { + //str.append(" [" + formatByte(data[i]) + "]: "); + for (int j = 0; j < 8; ++j) + if (data[i] & (1 << j)) + str.append(QByteArray::number(i * 8 + j, 16)); + } + logMessage("SUPPORTED: " + str); + } + +void Adapter::handleTrkVersions(const TrkResult &result) +{ + QString logMsg; + QTextStream str(&logMsg); + str << "Versions: "; + if (result.data.size() >= 5) { + str << "Trk version " << int(result.data.at(1)) << '.' << int(result.data.at(2)) + << ", Protocol version " << int(result.data.at(3)) << '.' << int(result.data.at(4)); + } + logMessage(logMsg); +} + +void Adapter::handleDisconnect(const TrkResult & /*result*/) +{ + logMessage(QLatin1String("Trk disconnected"), true); +} + +void Adapter::cleanUp() +{ + // + //---IDE------------------------------------------------------ + // Command: 0x41 Delete Item + // Sub Cmd: Delete Process + //ProcessID: 0x0000071F (1823) + // [41 24 00 00 00 00 07 1F] + logMessage(QString::fromLatin1("Cleanup PID=%1").arg(m_session.pid), true); + if (!m_session.pid) + return; + + QByteArray ba; + appendByte(&ba, 0x00); + appendByte(&ba, 0x00); + appendInt(&ba, m_session.pid); + sendTrkMessage(0x41, Callback(), ba, "Delete process"); + + //---TRK------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x00 + // [80 24 00] + + foreach (const Breakpoint &bp, m_breakpoints) + clearTrkBreakpoint(bp); + + sendTrkMessage(0x02, Callback(this, &Adapter::handleDisconnect)); + m_startInferiorTriggered = false; + //---IDE------------------------------------------------------ + // Command: 0x1C Clear Break + // [1C 25 00 00 00 0A 78 6A 43 40] + + //---TRK------------------------------------------------------ + // Command: 0xA1 Notify Deleted + // [A1 09 00 00 00 00 00 00 00 00 07 1F] + //---IDE------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x00 + // [80 09 00] + + //---TRK------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x00 + // [80 25 00] + + //---IDE------------------------------------------------------ + // Command: 0x1C Clear Break + // [1C 26 00 00 00 0B 78 6A 43 70] + //---TRK------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x00 + // [80 26 00] + + + //---IDE------------------------------------------------------ + // Command: 0x02 Disconnect + // [02 27] +// sendTrkMessage(0x02, Callback(this, &Adapter::handleDisconnect)); + //---TRK------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x00 +} + +static inline QByteArray memoryRequestTrkMessage(uint addr, uint len, int pid, int tid) +{ + QByteArray ba; + appendByte(&ba, 0x08); // Options, FIXME: why? + appendShort(&ba, len); + appendInt(&ba, addr); + appendInt(&ba, pid); + appendInt(&ba, tid); + return ba; +} + +void Adapter::readMemory(uint addr, uint len) +{ + Q_ASSERT(len < (2 << 16)); + + // We try to get medium-sized chunks of data from the device + if (m_verbose > 2) + logMessage(QString::fromLatin1("readMemory %1 bytes from 0x%2 blocksize=%3").arg(len).arg(addr, 0, 16).arg(MemoryChunkSize)); + + if (m_bufferedMemoryRead) { + uint blockaddr = (addr / MemoryChunkSize) * MemoryChunkSize; + for (; blockaddr < addr + len; blockaddr += MemoryChunkSize) { + if (!m_snapshot.memory.contains(blockaddr)) { + if (m_verbose) + logMessage(QString::fromLatin1("Requesting buffered memory %1 bytes from 0x%2").arg(MemoryChunkSize).arg(blockaddr, 0, 16)); + sendTrkMessage(0x10, Callback(this, &Adapter::handleReadMemoryBuffered), + memoryRequestTrkMessage(blockaddr, MemoryChunkSize, m_session.pid, m_session.tid), + QVariant(blockaddr), true); + } + } + const qulonglong cookie = (qulonglong(addr) << 32) + len; + sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, Callback(this, &Adapter::reportReadMemoryBuffered), QByteArray(), cookie); + } else { + if (m_verbose) + logMessage(QString::fromLatin1("Requesting unbuffered memory %1 bytes from 0x%2").arg(len).arg(addr, 0, 16)); + sendTrkMessage(0x10, Callback(this, &Adapter::handleReadMemoryUnbuffered), + memoryRequestTrkMessage(addr, len, m_session.pid, m_session.tid), + QVariant(addr), true); + } +} + +void Adapter::startInferiorIfNeeded() +{ + if (m_startInferiorTriggered) + return; + if (m_session.pid != 0) { + logMessage("Process already 'started'"); return; } - QTextStream ts(&file); - ts << "# This is generated. Changes will be lost."; - ts << "#set remote noack-packet on"; - ts << "set confirm off"; - ts << "set endian " + m_endianness; - ts << "#set debug remote 1"; - ts << "#target remote $m_gdbServerIP:$m_gdbServerPort"; - ts << "target extended-remote $m_gdbServerIP:$m_gdbServerPort"; - ts << "#file filebrowseapp.sym"; - ts << "add-symbol-file filebrowseapp.sym 0x786A4000"; - ts << "symbol-file filebrowseapp.sym"; - ts << "print E32Main"; - ts << "break E32Main"; - ts << "#continue"; - ts << "#info files"; - ts << "#file filebrowseapp.sym -readnow"; - ts << "#add-symbol-file filebrowseapp.sym 0x786A4000"; -} - -void Runner::run() + // It's not started yet + m_startInferiorTriggered = true; + QByteArray ba; + appendByte(&ba, 0); // ? + appendByte(&ba, 0); // ? + appendByte(&ba, 0); // ? + + QByteArray file("C:\\sys\\bin\\filebrowseapp.exe"); + appendString(&ba, file, TargetByteOrder); + sendTrkMessage(0x40, Callback(this, &Adapter::handleCreateProcess), ba); // Create Item +} + +void Adapter::interruptInferior() +{ + QByteArray ba; + // stop the thread (2) or the process (1) or the whole system (0) + appendByte(&ba, 1); + appendInt(&ba, m_session.pid); + appendInt(&ba, m_session.tid); // threadID: 4 bytes Variable number of bytes. + sendTrkMessage(0x1A, Callback(), ba, "Interrupting..."); +} + + +void Adapter::connectProcess(QProcess *proc) +{ + connect(proc, SIGNAL(error(QProcess::ProcessError)), + this, SLOT(handleProcError(QProcess::ProcessError))); + connect(proc, SIGNAL(finished(int, QProcess::ExitStatus)), + this, SLOT(handleProcFinished(int, QProcess::ExitStatus))); + connect(proc, SIGNAL(readyReadStandardError()), + this, SLOT(handleProcReadyReadStandardError())); + connect(proc, SIGNAL(readyReadStandardOutput()), + this, SLOT(handleProcReadyReadStandardOutput())); + connect(proc, SIGNAL(started()), + this, SLOT(handleProcStarted())); + connect(proc, SIGNAL(stateChanged(QProcess::ProcessState)), + this, SLOT(handleProcStateChanged(QProcess::ProcessState))); +} + + +void Adapter::sendOutput(QObject *sender, const QString &data) +{ + if (sender) + emit output(sender->objectName(), data); + else + emit output(QString(), data); +} + +void Adapter::handleProcError(QProcess::ProcessError error) +{ + sendOutput(sender(), QString("Process Error %1").arg(error)); +} + +void Adapter::handleProcFinished(int exitCode, QProcess::ExitStatus exitStatus) +{ + sendOutput(sender(), + QString("ProcessFinished %1 %2").arg(exitCode).arg(exitStatus)); +} + +void Adapter::handleProcReadyReadStandardError() +{ + QByteArray ba = qobject_cast<QProcess *>(sender())->readAllStandardError(); + sendOutput(sender(), QString("stderr: %1").arg(QString::fromLatin1(ba))); +} + +void Adapter::handleProcReadyReadStandardOutput() +{ + QByteArray ba = qobject_cast<QProcess *>(sender())->readAllStandardOutput(); + sendOutput(sender(), QString("stdout: %1").arg(QString::fromLatin1(ba))); +} + +void Adapter::handleProcStarted() +{ + sendOutput(sender(), QString("Process Started")); +} + +void Adapter::handleProcStateChanged(QProcess::ProcessState newState) +{ + sendOutput(sender(), QString("Process State %1").arg(newState)); +} + +void Adapter::run() { if (m_isUnix) { QProcess::execute("killall -s USR adapter trkserver"); QProcess::execute("killall adapter trkserver"); } - launchAdapter(); + startServer(); + sendOutput("### Starting Adapter"); + + m_rfcommProc.start("rfcomm listen /dev/rfcomm0 1"); uid_t userId = getuid(); if (m_trkServerName.isEmpty()) m_trkServerName = QString("TRKSERVER-%1").arg(userId); - - if (m_isUnix) { - QProcess fuserProc; - fuserProc.start("fuser -n tcp -k " + m_gdbServerPort); - fuserProc.waitForStarted(); - fuserProc.closeWriteChannel(); - fuserProc.waitForFinished(); - qDebug() << "fuser: " << fuserProc.readAllStandardOutput(); - qDebug() << "fuser: " << fuserProc.readAllStandardError(); - } - - // Who writes that? - //my $tempFile = File::Spec->catfile(File::Temp::tempdir(), - //m_trkServerName); - //unlink ($tempFile) if -f $tempFile; - - if (m_runTrkServer) - launchTrkServer(); - - writeGdbInit(); } -void Runner::runRfcomm() +void Adapter::startGdb() { - qDebug() << "RUNNING RFCCOMM"; - QProcess *proc = new QProcess; - connectProcess(proc); - proc->start("rfcomm listen /dev/rfcomm0 1"); - proc->waitForStarted(); - qDebug() << "STARTED"; - proc->write("\x90\x01\x00\x05\x7e\x00\x00\xff\x7e"); - qDebug() << "WRITTEN"; - proc->waitForFinished(); + logMessage("STARTING 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); + m_gdbProc.waitForStarted(); + + QTextStream ts(&m_gdbProc); + ts << "# This is generated. Changes will be lost.\n"; + ts << "#set remote noack-packet on\n"; + ts << "set confirm off\n"; + ts << "set endian " + m_endianness + "\n"; + ts << "#set debug remote 1\n"; + ts << "#target remote " + m_gdbServerName + "\n"; + ts << "target extended-remote " + m_gdbServerName + "\n"; + ts << "#file filebrowseapp.sym\n"; +// ts << "add-symbol-file filebrowseapp.sym " + m_baseAddress + "\n"; +// ts << "symbol-file filebrowseapp.sym\n"; +// ts << "print E32Main\n"; +// ts << "break E32Main\n"; + ts << "#continue\n"; + ts << "#info files\n"; + ts << "#file filebrowseapp.sym -readnow\n"; } /////////////////////////////////////////////////////////////////////// @@ -375,26 +1593,36 @@ class RunnerGui : public QTextEdit Q_OBJECT public: - RunnerGui(Runner *runner); + RunnerGui(Adapter *adapter); + void keyPressEvent(QKeyEvent *ev); private slots: void handleOutput(const QString &senderName, const QString &data); private: - Runner *m_runner; + Adapter *m_adapter; }; -RunnerGui::RunnerGui(Runner *runner) - : m_runner(runner) +RunnerGui::RunnerGui(Adapter *adapter) + : m_adapter(adapter) { - resize(600, 800); - connect(runner, SIGNAL(output(QString,QString)), + resize(1000, 1000); + connect(adapter, SIGNAL(output(QString,QString)), this, SLOT(handleOutput(QString,QString))); } void RunnerGui::handleOutput(const QString &senderName, const QString &data) { append(senderName + " : " + data); + ensureCursorVisible(); +} + +void RunnerGui::keyPressEvent(QKeyEvent *ev) +{ + if (ev->modifiers() == Qt::ControlModifier && ev->key() == Qt::Key_Return) + m_adapter->executeGdbCommand(textCursor().block().text()); + else + QTextEdit::keyPressEvent(ev); } /////////////////////////////////////////////////////////////////////// @@ -406,19 +1634,10 @@ void RunnerGui::handleOutput(const QString &senderName, const QString &data) int main(int argc, char *argv[]) { QApplication app(argc, argv); -#if 1 - QStringList args = QCoreApplication::arguments(); - qDebug() << "RUNNER ARGS: " << args; -#else - // Important options: -w wait for adapter, -af omit serial frame. - QStringList args = QStringList() << "-w" << "-af" << "COM5"; -#endif - Runner runner; - runner.parseArguments(args); - RunnerGui gui(&runner); + Adapter adapter; + RunnerGui gui(&adapter); gui.show(); - QTimer::singleShot(0, &runner, SLOT(run())); - //QTimer::singleShot(0, &runner, SLOT(runRfcomm())); + QTimer::singleShot(0, &adapter, SLOT(run())); return app.exec(); } diff --git a/tests/manual/trk/runner.pro b/tests/manual/trk/runner.pro index 57315453b408a6fbd7ab7e86fc05e780070871d6..0bf878e42027672082e8b89352eae99c6cfd3fb3 100644 --- a/tests/manual/trk/runner.pro +++ b/tests/manual/trk/runner.pro @@ -1,9 +1,15 @@ TEMPLATE = app +QT += network + win32:CONFIG+=console -HEADERS += +HEADERS += \ + trkutils.h \ + trkdevice.h \ SOURCES += \ runner.cpp \ + trkutils.cpp \ + trkdevice.cpp \