From 9b4055122c50af064e4102af35aaa7735a6d7345 Mon Sep 17 00:00:00 2001 From: mae Date: Mon, 7 Sep 2009 16:15:59 +0200 Subject: [PATCH 01/23] Fix code folding issue with empty nested blocks like in: void main() { { } int i; } --- src/plugins/texteditor/basetexteditor.cpp | 2 +- src/plugins/texteditor/basetexteditor.h | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp index 8c23d975df5..80a1f0268cc 100644 --- a/src/plugins/texteditor/basetexteditor.cpp +++ b/src/plugins/texteditor/basetexteditor.cpp @@ -2833,7 +2833,7 @@ void BaseTextEditor::extraAreaMouseEvent(QMouseEvent *e) document()->findBlockByNumber(d->m_highlightBlocksInfo.open.last()).position() ); QTextBlock c = cursor.block(); - if (!TextBlockUserData::canCollapse(c)) + if (TextBlockUserData::hasCollapseAfter(c.previous())) c = c.previous(); toggleBlockVisible(c); d->moveCursorVisible(false); diff --git a/src/plugins/texteditor/basetexteditor.h b/src/plugins/texteditor/basetexteditor.h index 906e73a14fe..34554082925 100644 --- a/src/plugins/texteditor/basetexteditor.h +++ b/src/plugins/texteditor/basetexteditor.h @@ -145,13 +145,10 @@ public: inline static bool hasCollapseAfter(const QTextBlock & block) { - if (!block.isValid()) - return false; - TextBlockUserData *data = static_cast(block.userData()); - if (data && data->collapseMode() != NoCollapse) { + if (!block.isValid()) { return false; } else if (block.next().isValid()) { - data = static_cast(block.next().userData()); + TextBlockUserData *data = static_cast(block.next().userData()); if (data && data->collapseMode() == TextBlockUserData::CollapseThis && !data->m_ifdefedOut) return true; } From b208e15aef2abbce02104aa577be8f426c341dc0 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 3 Sep 2009 17:35:40 +0200 Subject: [PATCH 02/23] debugger: work on trk --- tests/manual/trk/runner.cpp | 918 +++++++++++++++++++------------- tests/manual/trk/trkdevice.h | 2 +- tests/manual/trk/trkdevicex.cpp | 1 + tests/manual/trk/trkfunctor.h | 3 + tests/manual/trk/trkutils.h | 1 + 5 files changed, 563 insertions(+), 362 deletions(-) diff --git a/tests/manual/trk/runner.cpp b/tests/manual/trk/runner.cpp index eeb080ca0d8..1ed357b5df0 100755 --- a/tests/manual/trk/runner.cpp +++ b/tests/manual/trk/runner.cpp @@ -53,13 +53,40 @@ #include #include +/* +fetch-register p info registers +set-register P set +binary-download X load, set +read-aux-vector qXfer:auxv:read info auxv +symbol-lookup qSymbol Detecting multiple threads +attach vAttach attach +verbose-resume vCont Stepping or resuming multiple threads +run vRun run +software-breakpoint Z0 break +hardware-breakpoint Z1 hbreak +write-watchpoint Z2 watch +read-watchpoint Z3 rwatch +access-watchpoint Z4 awatch +target-features qXfer:features:read set architecture +library-info qXfer:libraries:read info sharedlibrary +memory-map qXfer:memory-map:read info mem +read-spu-object qXfer:spu:read info spu +write-spu-object qXfer:spu:write info spu +get-thread-local- +storage-address qGetTLSAddr Displaying __thread variables +supported-packets qSupported Remote communications parameters +pass-signals QPassSignals handle signal +hostio-close-packet vFile:close remote get, remote put +hostio-open-packet vFile:open remote get, remote put +hostio-pread-packet vFile:pread remote get, remote put +hostio-pwrite-packet vFile:pwrite remote get, remote put +hostio-unlink-packet vFile:unlink remote delete +*/ using namespace trk; enum { KnownRegisters = RegisterPSGdb + 1}; -#define CB(s) Callback(this, &Adapter::s) - static const char *registerNames[KnownRegisters] = { "A1", "A2", "A3", "A4", @@ -85,6 +112,14 @@ static QByteArray dumpRegister(int n, uint value) return ba; } +#define TrkCB(s) TrkCallback(this, &Adapter::s) +#define GdbCB(s) GdbCallback(this, &Adapter::s) + +struct GdbResult +{ + QByteArray data; +}; + /////////////////////////////////////////////////////////////////////// // // Adapter @@ -96,7 +131,8 @@ class Adapter : public QObject Q_OBJECT public: - typedef TrkFunctor1 Callback; + typedef TrkFunctor1 TrkCallback; + typedef TrkFunctor1 GdbCallback; Adapter(); ~Adapter(); @@ -110,10 +146,7 @@ public: void setBufferedMemoryRead(bool b) { m_bufferedMemoryRead = b; } public slots: - void startServer(); - -private slots: - void handleResult(const trk::TrkResult &data); + void startInferior(); signals: void output(const QString &senderName, const QString &data); @@ -121,13 +154,10 @@ signals: private slots: void handleProcError(QProcess::ProcessError error); void handleProcFinished(int exitCode, QProcess::ExitStatus exitStatus); - void handleProcReadyReadStandardError(); - void handleProcReadyReadStandardOutput(); void handleProcStarted(); void handleProcStateChanged(QProcess::ProcessState newState); void run(); void startGdb(); - void writeToGdb(const QString &msg); private: friend class RunnerGui; @@ -135,28 +165,27 @@ private: void sendOutput(QObject *sender, const QString &data); void sendOutput(const QString &data) { sendOutput(0, data); } - QString m_endianness; QString m_trkServerName; // QString m_gdbServerName; // 127.0.0.1:(2222+uid) QProcess m_gdbProc; QProcess m_rfcommProc; + bool m_running; public: // // TRK // - - bool openTrkPort(const QString &port, QString *errorMessage); // or server name for local server + bool openTrkPort(const QString &port, QString *errorMessage); void sendTrkMessage(byte code, - Callback callBack = Callback(), + TrkCallback callback = TrkCallback(), const QByteArray &data = QByteArray(), const QVariant &cookie = QVariant(), bool invokeOnFailure = false); + Q_SLOT void handleTrkResult(const trk::TrkResult &data); + Q_SLOT void handleTrkError(const QString &msg); // convenience messages - void sendTrkInitialPing(); - void sendTrkContinue(); void waitForTrkFinished(); void sendTrkAck(byte token); @@ -176,20 +205,25 @@ public: void handleAndReportCreateProcess(const TrkResult &result); void handleAndReportReadRegisters(const TrkResult &result); QByteArray memoryReadLogMessage(uint addr, uint len, const QByteArray &ba) const; + QByteArray trkContinueMessage(); + QByteArray trkBreakpointMessage(uint addr, int len, int pid, + bool armMode = true); void handleAndReportSetBreakpoint(const TrkResult &result); void handleReadMemoryBuffered(const TrkResult &result); void handleReadMemoryUnbuffered(const TrkResult &result); void handleStepRange(const TrkResult &result); + void handleReadRegisters(const TrkResult &result); void reportReadMemoryBuffered(const TrkResult &result); void reportToGdb(const TrkResult &result); void clearTrkBreakpoint(const Breakpoint &bp); - void handleSetTrkBreakpoint(const TrkResult &result); + // set breakpoints behind gdb's back void setTrkBreakpoint(const Breakpoint &bp); + void handleSetTrkBreakpoint(const TrkResult &result); + void handleSetTrkMainBreakpoint(const TrkResult &result); void readMemory(uint addr, uint len); - void startInferiorIfNeeded(); void interruptInferior(); TrkDevice m_trkDevice; @@ -199,59 +233,94 @@ public: // // 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); + struct GdbCommand + { + GdbCommand() : flags(0), callback(GdbCallback()), callbackName(0) {} + int flags; + GdbCallback callback; + const char *callbackName; + QString command; + QVariant cookie; + //QTime postTime; + }; + + void sendGdbMessage(const QString &msg, + GdbCallback callback = GdbCallback(), + const QVariant &cookie = QVariant()); + Q_SLOT void handleGdbConnection(); + Q_SLOT void readGdbServerCommand(); + void readGdbResponse(); + void handleGdbServerCommand(const QByteArray &ba); + void sendGdbServerMessage(const QByteArray &msg, + const QByteArray &logNote = QByteArray()); + void sendGdbServerMessageAfterTrkResponse(const QByteArray &msg, + const QByteArray &logNote = QByteArray()); + void sendGdbServerAck(); + bool sendGdbServerPacket(const QByteArray &packet, bool doFlush); + + Q_SLOT void handleGdbReadyReadStandardError(); + Q_SLOT void handleGdbReadyReadStandardOutput(); void logMessage(const QString &msg, bool force = false); Q_SLOT void trkLogMessage(const QString &msg); + void handleInfoAddress(const GdbResult &result); + void handleInfoMainAddress(const GdbResult &result); + QTcpServer m_gdbServer; QPointer m_gdbConnection; QByteArray m_gdbReadBuffer; bool m_gdbAckMode; + QHash m_gdbCookieForToken; + + // + // Rfcomm + // + Q_SLOT void handleRfcommReadyReadStandardError(); + Q_SLOT void handleRfcommReadyReadStandardOutput(); + // Debuggee state + void executeCommand(const QString &msg); 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; }; Adapter::Adapter() { + m_running = false; m_gdbAckMode = true; m_verbose = 2; m_registerEndianness = LittleEndian; //m_serialFrame = true; m_serialFrame = false; - m_startInferiorTriggered = false; - //m_bufferedMemoryRead = true; - m_bufferedMemoryRead = false; + m_bufferedMemoryRead = true; + //m_bufferedMemoryRead = false; // m_breakpoints.append(Breakpoint(0x0040)); // E32Main m_breakpoints.append(Breakpoint(0x0cc8)); // E32Main + m_breakpoints.append(Breakpoint(0x0cd0)); // E32Main m_trkServerName = "/dev/rfcomm0"; - m_endianness = "little"; - uid_t userId = getuid(); m_gdbServerName = QString("127.0.0.1:%1").arg(2222 + userId); m_gdbProc.setObjectName("GDB PROCESS"); connectProcess(&m_gdbProc); + connect(&m_gdbProc, SIGNAL(readyReadStandardError()), + this, SLOT(handleGdbReadyReadStandardError())); + connect(&m_gdbProc, SIGNAL(readyReadStandardOutput()), + this, SLOT(handleGdbReadyReadStandardOutput())); m_rfcommProc.setObjectName("RFCOMM PROCESS"); connectProcess(&m_rfcommProc); + connect(&m_rfcommProc, SIGNAL(readyReadStandardError()), + this, SLOT(handleRfcommReadyReadStandardError())); + connect(&m_rfcommProc, SIGNAL(readyReadStandardOutput()), + this, SLOT(handleRfcommReadyReadStandardOutput())); connect(&m_trkDevice, SIGNAL(logMessage(QString)), this, SLOT(trkLogMessage(QString))); @@ -289,42 +358,35 @@ uint Adapter::gdbServerPort() const return m_gdbServerName.mid(pos + 1).toUInt(); } -void Adapter::startServer() +void Adapter::startInferior() { QString errorMessage; if (!openTrkPort(m_trkServerName, &errorMessage)) { logMessage(errorMessage, true); logMessage("LOOPING"); - QTimer::singleShot(1000, this, SLOT(startServer())); + QTimer::singleShot(1000, this, SLOT(startInferior())); return; } - sendTrkInitialPing(); + m_trkDevice.sendTrkInitialPing(); sendTrkMessage(0x01); // Connect - sendTrkMessage(0x05, CB(handleSupportMask)); - sendTrkMessage(0x06, CB(handleCpuType)); - sendTrkMessage(0x04, CB(handleTrkVersions)); // Versions + sendTrkMessage(0x05, TrkCB(handleSupportMask)); + sendTrkMessage(0x06, TrkCB(handleCpuType)); + sendTrkMessage(0x04, TrkCB(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"); + QByteArray ba; + appendByte(&ba, 0); // ? + appendByte(&ba, 0); // ? + appendByte(&ba, 0); // ? - 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(); + QByteArray file("C:\\sys\\bin\\filebrowseapp.exe"); + appendString(&ba, file, TargetByteOrder); + sendTrkMessage(0x40, TrkCB(handleCreateProcess), ba); // Create Item + //sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, TrkCB(startGdbServer)); } void Adapter::logMessage(const QString &msg, bool force) @@ -344,8 +406,7 @@ void Adapter::handleGdbConnection() connect(m_gdbConnection, SIGNAL(disconnected()), m_gdbConnection, SLOT(deleteLater())); connect(m_gdbConnection, SIGNAL(readyRead()), - this, SLOT(readFromGdb())); - m_startInferiorTriggered = false; + this, SLOT(readGdbServerCommand())); } static inline QString msgGdbPacket(const QString &p) @@ -353,7 +414,7 @@ static inline QString msgGdbPacket(const QString &p) return QLatin1String("gdb: ") + p; } -void Adapter::readFromGdb() +void Adapter::readGdbServerCommand() { QByteArray packet = m_gdbConnection->readAll(); m_gdbReadBuffer.append(packet); @@ -416,18 +477,25 @@ void Adapter::readFromGdb() QByteArray response = ba.left(pos); ba.remove(0, pos + 3); - handleGdbResponse(response); + handleGdbServerCommand(response); } } -bool Adapter::sendGdbPacket(const QByteArray &packet, bool doFlush) +bool Adapter::sendGdbServerPacket(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); + if (!m_gdbConnection) { + logMessage(QString::fromLatin1("Cannot write to gdb: No connection (%1)") + .arg(QString::fromLatin1(packet)), true); + return false; + } + if (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); + logMessage(QString::fromLatin1("Cannot write to gdb: %1 (%2)") + .arg(m_gdbConnection->errorString()).arg(QString::fromLatin1(packet)), true); return false; } if (doFlush) @@ -435,16 +503,16 @@ bool Adapter::sendGdbPacket(const QByteArray &packet, bool doFlush) return true; } -void Adapter::sendGdbAckMessage() +void Adapter::sendGdbServerAck() { if (!m_gdbAckMode) return; QByteArray packet = "+"; logMessage("gdb: <- " + packet); - sendGdbPacket(packet, false); + sendGdbServerPacket(packet, false); } -void Adapter::sendGdbMessage(const QByteArray &msg, const QByteArray &logNote) +void Adapter::sendGdbServerMessage(const QByteArray &msg, const QByteArray &logNote) { byte sum = 0; for (int i = 0; i != msg.size(); ++i) @@ -462,13 +530,14 @@ void Adapter::sendGdbMessage(const QByteArray &msg, const QByteArray &logNote) packet.append(checkSum); int pad = qMax(0, 24 - packet.size()); logMessage("gdb: <- " + packet + QByteArray(pad, ' ') + logNote); - sendGdbPacket(packet, true); + sendGdbServerPacket(packet, true); } -void Adapter::sendGdbMessageAfterSync(const QByteArray &msg, const QByteArray &logNote) +void Adapter::sendGdbServerMessageAfterTrkResponse(const QByteArray &msg, + const QByteArray &logNote) { QByteArray ba = msg + char(1) + logNote; - sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, CB(reportToGdb), "", ba); // Answer gdb + sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, TrkCB(reportToGdb), "", ba); // Answer gdb } void Adapter::reportToGdb(const TrkResult &result) @@ -484,10 +553,10 @@ void Adapter::reportToGdb(const TrkResult &result) message.replace("@DATASEG@", hexNumber(m_session.dataseg)); message.replace("@PID@", hexNumber(m_session.pid)); message.replace("@TID@", hexNumber(m_session.tid)); - sendGdbMessage(message, note); + sendGdbServerMessage(message, note); } -static QByteArray trkBreakpointMessage(uint addr, int len, int pid, bool armMode = true) +QByteArray Adapter::trkBreakpointMessage(uint addr, int len, int pid, bool armMode) { QByteArray ba; appendByte(&ba, 0x82); // unused option @@ -500,118 +569,111 @@ static QByteArray trkBreakpointMessage(uint addr, int len, int pid, bool armMode return ba; } -void Adapter::handleGdbResponse(const QByteArray &response) +void Adapter::handleGdbServerCommand(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"); + sendGdbServerAck(); + //sendGdbServerMessage("", "extended mode not enabled"); + sendGdbServerMessage("OK", "extended mode enabled"); } else if (response.startsWith("?")) { - if (m_verbose) - logMessage(msgGdbPacket(QLatin1String("Query halted"))); + 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)"); + sendGdbServerAck(); + // The command below will trigger fetching a stack trace while + // the process does not seem to be fully functional. Most notably + // the PC points to a 0x9..., which is not in "our" range + //sendGdbServerMessage("T05library:r;", "target halted (library load)"); + //sendGdbServerMessage("S05", "target halted (trap)"); + sendGdbServerMessage("S00", "target halted (trap)"); + //sendGdbServerMessage("O" + QByteArray("Starting...").toHex()); } else if (response == "c") { - if (m_verbose) - logMessage(msgGdbPacket(QLatin1String("continue"))); - sendGdbAckMessage(); + logMessage(msgGdbPacket(QLatin1String("Continue"))); + sendGdbServerAck(); 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"); + sendTrkMessage(0x18, TrkCallback(), ba); } else if (response.startsWith("C")) { - if (m_verbose) - logMessage(msgGdbPacket(QLatin1String("continue with signal"))); + 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(); + sendGdbServerAck(); 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, CB(handleSignalContinue), ba, signalNumber); // Continue + sendTrkMessage(0x18, TrkCB(handleSignalContinue), ba, signalNumber); // Continue } else if (response.startsWith("D")) { - sendGdbAckMessage(); - sendGdbMessage("OK", "shutting down"); + sendGdbServerAck(); + sendGdbServerMessage("OK", "shutting down"); qApp->quit(); } else if (response == "g") { - if (m_verbose) - logMessage(msgGdbPacket(QLatin1String("read registers"))); + logMessage(msgGdbPacket(QLatin1String("Read registers"))); // Read general registers. - //sendGdbMessage("00000000", "read registers"); - sendGdbAckMessage(); + //sendGdbServerMessage("00000000", "read registers"); + sendGdbServerAck(); 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, CB(handleAndReportReadRegisters), ba, QVariant(), true); + sendTrkMessage(0x12, TrkCB(handleAndReportReadRegisters), ba, QVariant(), true); } else if (response.startsWith("Hc")) { - if (m_verbose) - logMessage(msgGdbPacket(QLatin1String("Set thread & continue"))); + 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"); + sendGdbServerAck(); + sendGdbServerMessage("OK", "Set current thread for step & continue"); } else if (response.startsWith("Hg")) { - if (m_verbose) - logMessage(msgGdbPacket(QLatin1String("Set thread"))); + 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(); + sendGdbServerAck(); m_session.currentThread = response.mid(2).toInt(0, 16); - sendGdbMessage("OK", "Set current thread " + sendGdbServerMessage("OK", "Set current thread " + QByteArray::number(m_session.currentThread)); } else if (response == "k") { - if (m_verbose) - logMessage(msgGdbPacket(QLatin1String("kill"))); + logMessage(msgGdbPacket(QLatin1String("kill"))); // kill - sendGdbAckMessage(); + sendGdbServerAck(); 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"); + sendTrkMessage(0x41, TrkCallback(), ba, "Delete process"); // Delete Item + sendGdbServerMessageAfterTrkResponse("", "process killed"); } else if (response.startsWith("m")) { - if (m_verbose) - logMessage(msgGdbPacket(QLatin1String("read memory"))); + logMessage(msgGdbPacket(QLatin1String("Read memory"))); // m addr,length - sendGdbAckMessage(); + sendGdbServerAck(); uint addr = 0, len = 0; do { const int pos = response.indexOf(','); @@ -628,15 +690,14 @@ void Adapter::handleGdbResponse(const QByteArray &response) if (len) { readMemory(addr, len); } else { - sendGdbMessage("E20", "Error " + response); + sendGdbServerMessage("E20", "Error " + response); } } else if (response.startsWith("p")) { - if (m_verbose) - logMessage(msgGdbPacket(QLatin1String("read register"))); + logMessage(msgGdbPacket(QLatin1String("read register"))); // 0xf == current instruction pointer? - //sendGdbMessage("0000", "current IP"); - sendGdbAckMessage(); + //sendGdbServerMessage("0000", "current IP"); + sendGdbServerAck(); #if 0 A1 = 0, first integer-like argument A4 = 3, last integer-like argument @@ -676,15 +737,15 @@ void Adapter::handleGdbResponse(const QByteArray &response) QByteArray ba; appendInt(&ba, m_snapshot.registers[RegisterPSTrk], m_registerEndianness); logMsg += dumpRegister(registerNumber, m_snapshot.registers[RegisterPSTrk]); - sendGdbMessage(ba.toHex(), logMsg); + sendGdbServerMessage(ba.toHex(), logMsg); } else if (registerNumber < RegisterCount) { QByteArray ba; appendInt(&ba, m_snapshot.registers[registerNumber], m_registerEndianness); logMsg += dumpRegister(registerNumber, m_snapshot.registers[registerNumber]); - sendGdbMessage(ba.toHex(), logMsg); + sendGdbServerMessage(ba.toHex(), logMsg); } else { - sendGdbMessage("0000", "read single unknown register #" + QByteArray::number(registerNumber)); - //sendGdbMessage("E01", "read single unknown register"); + sendGdbServerMessage("0000", "read single unknown register #" + QByteArray::number(registerNumber)); + //sendGdbServerMessage("E01", "read single unknown register"); } } @@ -692,31 +753,29 @@ void Adapter::handleGdbResponse(const QByteArray &response) //$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"); + sendGdbServerAck(); + sendGdbServerMessage("0", "new process created"); + //sendGdbServerMessage("1", "attached to existing process"); + //sendGdbServerMessage("E01", "new process created"); } else if (response.startsWith("qC")) { - if (m_verbose) - logMessage(msgGdbPacket(QLatin1String("query thread id"))); + logMessage(msgGdbPacket(QLatin1String("query thread id"))); // Return the current thread ID //$qC#b4 - sendGdbAckMessage(); - startInferiorIfNeeded(); - sendGdbMessageAfterSync("QC@TID@"); + sendGdbServerAck(); + sendGdbServerMessageAfterTrkResponse("QC@TID@"); } else if (response.startsWith("qSupported")) { //$qSupported#37 //$qSupported:multiprocess+#c6 //logMessage("Handling 'qSupported'"); - sendGdbAckMessage(); + sendGdbServerAck(); if (0) - sendGdbMessage(QByteArray(), "nothing supported"); + sendGdbServerMessage(QByteArray(), "nothing supported"); else - sendGdbMessage( + sendGdbServerMessage( "PacketSize=7cf;" //"QPassSignals+;" "qXfer:libraries:read+;" @@ -727,38 +786,38 @@ void Adapter::handleGdbResponse(const QByteArray &response) else if (response == "qPacketInfo") { // happens with gdb 6.4.50.20060226-cvs / CodeSourcery // deprecated by qSupported? - sendGdbAckMessage(); - sendGdbMessage("", "FIXME: nothing?"); + + sendGdbServerAck(); + sendGdbServerMessage("", "FIXME: nothing?"); } else if (response == "qOffsets") { - sendGdbAckMessage(); - startInferiorIfNeeded(); - sendGdbMessageAfterSync("TextSeg=@CODESEG@;DataSeg=@DATASEG@"); + sendGdbServerAck(); + sendGdbServerMessageAfterTrkResponse("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(); + sendGdbServerAck(); if (1) - sendGdbMessage("OK", "no further symbols needed"); + sendGdbServerMessage("OK", "no further symbols needed"); else - sendGdbMessage("qSymbol:" + QByteArray("_Z7E32Mainv").toHex(), "ask for more"); + sendGdbServerMessage("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("lsymbianelf"); + sendGdbServerAck(); + sendGdbServerMessage("lsymbianelf"); } else if (response == "QStartNoAckMode") { //$qSupported#37 //logMessage("Handling 'QStartNoAckMode'"); - sendGdbAckMessage(); - sendGdbMessage("OK", "ack no-ack mode"); + sendGdbServerAck(); + sendGdbServerMessage("OK", "ack no-ack mode"); m_gdbAckMode = false; } @@ -766,57 +825,75 @@ void Adapter::handleGdbResponse(const QByteArray &response) // 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(); + sendGdbServerAck(); // FIXME: use the parameters - sendGdbMessage("OK", "passing signals accepted"); + sendGdbServerMessage("OK", "passing signals accepted"); } else if (response == "s") { if (m_verbose) logMessage(msgGdbPacket(QLatin1String("Step range"))); - sendGdbAckMessage(); + sendGdbServerAck(); 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_snapshot.registers[RegisterPC] + 8); // end address appendInt(&ba, m_session.pid); appendInt(&ba, m_session.tid); - sendTrkMessage(0x19, CB(handleStepRange), ba, "Step range"); + sendTrkMessage(0x19, TrkCB(handleStepRange), ba, "Step range"); // FIXME: should be triggered by "real" stop" - //sendGdbMessageAfterSync("S05", "target halted"); + //sendGdbServerMessageAfterTrkResponse("S05", "target halted"); } else if (response == "vCont?") { // actions supported by the vCont packet - sendGdbAckMessage(); - sendGdbMessage(""); // we don't support vCont. - //sendGdbMessage("vCont;c"); + sendGdbServerAck(); + sendGdbServerMessage("OK"); // we don't support vCont. + //sendGdbServerMessage("vCont;c"); } - //else if (response.startsWith("vCont")) { - // // vCont[;action[:thread-id]]...' - //} + else if (response == "vCont;c") { + // vCont[;action[:thread-id]]...' + sendGdbServerAck(); + m_running = true; + sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE"); + } + + else if (response.startsWith("vCont;s")) { + // vCont[;action[:thread-id]]...' + sendGdbServerAck(); + m_running = true; + sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE"); + } else if (response.startsWith("vKill")) { // kill - sendGdbAckMessage(); + sendGdbServerAck(); 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"); + sendTrkMessage(0x41, TrkCallback(), ba, "Delete process"); // Delete Item + sendGdbServerMessageAfterTrkResponse("", "process killed"); } - else if (response.startsWith("Z0,")) { // Insert breakpoint + else if (0 && response.startsWith("Z0,")) { + // Tell gdb we don't support software breakpoints + sendGdbServerMessage(""); + } + + else if (response.startsWith("Z0,") || response.startsWith("Z1,")) { + // 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 addr = response.mid(3, pos - 3).toInt(&ok, 16); const uint len = response.mid(pos + 1).toInt(&ok, 16); + qDebug() << "ADDR: " << hexNumber(addr) << " LEN: " << len; if (m_verbose) - logMessage(QString::fromLatin1("Inserting breakpoint at 0x%1, %2").arg(addr,0 ,16).arg(len)); + logMessage(QString::fromLatin1("Inserting breakpoint at 0x%1, %2") + .arg(addr, 0, 16).arg(len)); //---IDE------------------------------------------------------ // Command: 0x1B Set Break @@ -830,7 +907,7 @@ void Adapter::handleGdbResponse(const QByteArray &response) // [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 = trkBreakpointMessage(addr, len, m_session.pid); - sendTrkMessage(0x1B, CB(handleAndReportSetBreakpoint), ba); + sendTrkMessage(0x1B, TrkCB(handleAndReportSetBreakpoint), ba); //m_session.toekn //---TRK------------------------------------------------------ @@ -846,71 +923,67 @@ void Adapter::handleGdbResponse(const QByteArray &response) 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 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); + 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()); + sendGdbServerMessage("E20", msg.toLatin1()); handled = true; } } } // auxv read if (!handled) { - const QString msg = QLatin1String("FIXME unknown 'XFER'-request: ") + QString::fromAscii(response); + const QString msg = QLatin1String("FIXME unknown 'XFER'-request: ") + + QString::fromAscii(response); logMessage(msgGdbPacket(msg), true); - sendGdbMessage("E20", msg.toLatin1()); + sendGdbServerMessage("E20", msg.toLatin1()); } } // qPart/qXfer else { - logMessage(msgGdbPacket(QLatin1String("FIXME unknown: ") + QString::fromAscii(response))); + logMessage(msgGdbPacket(QLatin1String("FIXME unknown: ") + + QString::fromAscii(response))); } } -void Adapter::executeGdbCommand(const QString &msg) +void Adapter::executeCommand(const QString &msg) { - logMessage("EXECUTING GDB COMMAND " + msg); - if (msg == "S") - writeToGdb("-exec-interrupt"); - if (msg == "I") + if (msg == "EI") { + sendGdbMessage("-exec-interrupt"); + } else if (msg == "C") { + sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE"); + } else if (msg == "I") { interruptInferior(); - else - writeToGdb(msg); + } else { + logMessage("EXECUTING GDB COMMAND " + msg); + sendGdbMessage(msg); + } } bool Adapter::openTrkPort(const QString &port, QString *errorMessage) { connect(&m_trkDevice, SIGNAL(messageReceived(trk::TrkResult)), - this, SLOT(handleResult(trk::TrkResult))); + this, SLOT(handleTrkResult(trk::TrkResult))); + connect(&m_trkDevice, SIGNAL(error(QString)), + this, SLOT(handleTrkError(QString))); 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, +void Adapter::sendTrkMessage(byte code, TrkCallback 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"); + m_trkDevice.sendTrkMessage(code, callback, data, cookie, invokeOnFailure); } void Adapter::waitForTrkFinished() { // initiate one last roundtrip to ensure all is flushed - sendTrkMessage(0x0, CB(handleWaitForFinished)); + sendTrkMessage(0x0, TrkCB(handleWaitForFinished)); } void Adapter::sendTrkAck(byte token) @@ -919,10 +992,19 @@ void Adapter::sendTrkAck(byte token) m_trkDevice.sendTrkAck(token); } -void Adapter::handleResult(const TrkResult &result) +void Adapter::handleTrkError(const QString &msg) { + logMessage("## TRK ERROR: " + msg); +} + +void Adapter::handleTrkResult(const TrkResult &result) +{ + logMessage("HANDLING RESULT: " + result.data); if (result.isDebugOutput) { - logMessage(QLatin1String("APPLICATION OUTPUT: ") + QString::fromAscii(result.data)); + sendTrkAck(result.token); + logMessage(QLatin1String("APPLICATION OUTPUT: ") + + QString::fromAscii(result.data)); + sendGdbServerMessage("O" + result.data.toHex()); return; } QByteArray prefix = "READ BUF: "; @@ -932,23 +1014,27 @@ void Adapter::handleResult(const TrkResult &result) 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; + 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 + const uint addr = extractInt(data); + const uint pid = extractInt(data + 4); + const uint tid = extractInt(data + 8); 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"); + if (m_running) { + m_running = false; + sendGdbServerMessage("S05", "Target stopped"); + } } else { if (m_verbose) logMessage(QLatin1String("Ignoring stop at 0")); @@ -970,32 +1056,35 @@ void Adapter::handleResult(const TrkResult &result) 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 + // type: 1 byte; for dll item, this value is 2. + const byte type = result.data.at(1); + const uint pid = extractInt(data + 2); + const uint tid = extractInt(data + 6); + const uint codeseg = extractInt(data + 10); + const uint dataseg = extractInt(data + 14); + const uint len = extractShort(data + 18); + const QByteArray name = result.data.mid(20, len); // library name m_session.modules += QString::fromAscii(name); QString logMsg; QTextStream str(&logMsg); - str<< prefix << " NOTE: LIBRARY LOAD: token=" << result.token; + str << prefix << " NOTE: LIBRARY LOAD: token=" << result.token; if (error) - str<< " ERROR: " << int(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 << " CODE: 0x" << hexNumber(codeseg); + str << " DATA: 0x" << hexNumber(dataseg); str << " NAME: '" << name << '\''; logMessage(logMsg); - sendTrkContinue(); + sendGdbServerMessage("T05library:" + name); + //sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE"); 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(); + const ushort itemType = extractByte(result.data.data() + 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") @@ -1003,6 +1092,10 @@ void Adapter::handleResult(const TrkResult &result) .arg(itemType ? QLatin1String("LIB") : QLatin1String("PROCESS")) .arg(name)); sendTrkAck(result.token); + if (itemType == 0) { + sendGdbServerMessage("W00", "Process exited"); + //sendTrkMessage(0x02, TrkCB(handleDisconnect)); + } break; } case 0xa2: { // NotifyProcessorStarted @@ -1062,8 +1155,9 @@ void Adapter::setTrkBreakpoint(const Breakpoint &bp) // 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 = trkBreakpointMessage(m_session.codeseg + bp.offset, 1, m_session.pid); - sendTrkMessage(0x1B, CB(handleSetTrkBreakpoint), ba); + const QByteArray ba = trkBreakpointMessage(m_session.codeseg + bp.offset, + 1, m_session.pid); + sendTrkMessage(0x1B, TrkCB(handleSetTrkBreakpoint), ba); //---TRK------------------------------------------------------ // Command: 0x80 Acknowledge @@ -1077,9 +1171,10 @@ void Adapter::handleSetTrkBreakpoint(const TrkResult &result) // Command: 0x80 Acknowledge // Error: 0x00 // [80 09 00 00 00 00 0A] - const uint bpnr = extractInt(result.data.data()); + const uint bpnr = extractInt(result.data.data()); if (m_verbose) - logMessage(QString::fromLatin1("SET BREAKPOINT %1 %2").arg(bpnr).arg(stringFromArray(result.data.data()))); + logMessage("SET BREAKPOINT 0x" + hexNumber(bpnr) + + stringFromArray(result.data.data())); } void Adapter::handleCreateProcess(const TrkResult &result) @@ -1098,28 +1193,22 @@ void Adapter::handleCreateProcess(const TrkResult &result) logMessage("COD: 0x" + hexNumber(m_session.codeseg)); logMessage("DAT: 0x" + hexNumber(m_session.dataseg)); - writeToGdb("add-symbol-file filebrowseapp.sym 0x" - + hexNumber(m_session.codeseg)); - writeToGdb("symbol-file filebrowseapp.sym"); + QByteArray ba; + appendInt(&ba, m_session.pid); + appendInt(&ba, m_session.tid); - foreach (const Breakpoint &bp, m_breakpoints) - setTrkBreakpoint(bp); + startGdb(); - sendTrkContinue(); #if 0 - //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, CB(handleReadInfo), + sendTrkMessage(0x42, TrkCB(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, CB(handleReadInfo), + //sendTrkMessage(0x42, TrkCB(handleReadInfo), // "00 01 00 00 00 00"); //---TRK------------------------------------------------------ // Command: 0x80 Acknowledge @@ -1131,7 +1220,7 @@ void Adapter::handleCreateProcess(const TrkResult &result) // 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, CB(handleReadInfo), + sendTrkMessage(0x42, TrkCB(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------------------------------------------------------ @@ -1140,37 +1229,24 @@ void Adapter::handleCreateProcess(const TrkResult &result) // [80 0D 20] #endif - //sendTrkMessage(0x18, CB(handleStop), + //sendTrkMessage(0x18, TrkCB(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, CB(handleContinue), ba); - //sendTrkMessage(0x18, CB(handleContinue), - // formatInt(m_session.pid) + "ff ff ff ff"); - //---TRK------------------------------------------------------ - // Command: 0x80 Acknowledge - // Error: 0x00 - // [80 0E 00] -#endif } -void Adapter::handleAndReportReadRegisters(const TrkResult &result) +void Adapter::handleReadRegisters(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) { + for (int i = 0; i < RegisterCount; ++i) m_snapshot.registers[i] = extractInt(data + 4 * i); - } +} + +void Adapter::handleAndReportReadRegisters(const TrkResult &result) +{ + handleReadRegisters(result); QByteArray ba; for (int i = 0; i < 16; ++i) { const uint reg = m_registerEndianness == LittleEndian @@ -1184,24 +1260,27 @@ void Adapter::handleAndReportReadRegisters(const TrkResult &result) logMsg += ' '; } } - sendGdbMessage(ba, logMsg); + sendGdbServerMessage(ba, logMsg); } static inline QString msgMemoryReadError(int code, uint addr, uint len = 0) { const QString lenS = len ? QString::number(len) : QLatin1String(""); - return QString::fromLatin1("Memory read error %1 at: 0x%2 %3").arg(code).arg(addr, 0 ,16).arg(lenS); + return QString::fromLatin1("Memory read error %1 at: 0x%2 %3") + .arg(code).arg(addr, 0 ,16).arg(lenS); } void Adapter::handleReadMemoryBuffered(const TrkResult &result) { + if (extractShort(result.data.data() + 1) + 3 != result.data.size()) + logMessage("\n BAD MEMORY RESULT: " + result.data.toHex() + "\n"); 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); + const QByteArray ba = result.data.mid(3); + m_snapshot.memory.insert(blockaddr, ba); } // Format log message for memory access with some smartness about registers @@ -1236,6 +1315,14 @@ QByteArray Adapter::memoryReadLogMessage(uint addr, uint len, const QByteArray & return logMsg; } +QByteArray Adapter::trkContinueMessage() +{ + QByteArray ba; + appendInt(&ba, m_session.pid); + appendInt(&ba, m_session.tid); + return ba; +} + void Adapter::reportReadMemoryBuffered(const TrkResult &result) { const qulonglong cookie = result.cookie.toULongLong(); @@ -1260,9 +1347,9 @@ void Adapter::reportReadMemoryBuffered(const TrkResult &result) if (ba.isEmpty()) { ba = "E20"; - sendGdbMessage(ba, msgMemoryReadError(32, addr, len).toLatin1()); + sendGdbServerMessage(ba, msgMemoryReadError(32, addr, len).toLatin1()); } else { - sendGdbMessage(ba.toHex(), memoryReadLogMessage(addr, len, ba)); + sendGdbServerMessage(ba.toHex(), memoryReadLogMessage(addr, len, ba)); } } @@ -1270,15 +1357,14 @@ void Adapter::handleReadMemoryUnbuffered(const TrkResult &result) { //logMessage("UNBUFFERED MEMORY READ: " + stringFromArray(result.data)); const uint blockaddr = result.cookie.toUInt(); - if (extractShort(result.data.data() + 1) + 3 != result.data.size()) { + if (extractShort(result.data.data() + 1) + 3 != result.data.size()) logMessage("\n BAD MEMORY RESULT: " + result.data.toHex() + "\n"); - } if (const int errorCode = result.errorCode()) { const QByteArray ba = "E20"; - sendGdbMessage(ba, msgMemoryReadError(32, blockaddr).toLatin1()); + sendGdbServerMessage(ba, msgMemoryReadError(32, blockaddr).toLatin1()); } else { const QByteArray ba = result.data.mid(3); - sendGdbMessage(ba.toHex(), memoryReadLogMessage(blockaddr, ba.size(), ba)); + sendGdbServerMessage(ba.toHex(), memoryReadLogMessage(blockaddr, ba.size(), ba)); } } @@ -1287,7 +1373,7 @@ void Adapter::handleStepRange(const TrkResult &result) // [80 0f 12] //uint bpnr = extractInt(result.data.data()); logMessage("STEPPING FINISHED " + stringFromArray(result.data.data())); - sendGdbMessage("S05", "Stepping finished"); + sendGdbServerMessage("S05", "Stepping finished"); } void Adapter::handleAndReportSetBreakpoint(const TrkResult &result) @@ -1296,9 +1382,10 @@ void Adapter::handleAndReportSetBreakpoint(const TrkResult &result) // 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"); + uint bpnr = extractByte(result.data.data()); + logMessage("SET BREAKPOINT 0x" + hexNumber(bpnr) + " " + + stringFromArray(result.data.data())); + sendGdbServerMessage("OK"); } void Adapter::clearTrkBreakpoint(const Breakpoint &bp) @@ -1310,7 +1397,7 @@ void Adapter::clearTrkBreakpoint(const Breakpoint &bp) appendByte(&ba, 0x00); appendShort(&ba, bp.number); appendInt(&ba, m_session.codeseg + bp.offset); - sendTrkMessage(0x1C, CB(handleClearBreakpoint), ba); + sendTrkMessage(0x1C, TrkCB(handleClearBreakpoint), ba); } void Adapter::handleClearBreakpoint(const TrkResult &result) @@ -1328,8 +1415,8 @@ 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 + sendGdbServerMessage("O" + QByteArray("Console output").toHex()); + sendGdbServerMessage("W81"); // "Process exited with result 1 } void Adapter::handleWaitForFinished(const TrkResult &result) @@ -1386,7 +1473,7 @@ void Adapter::cleanUp() appendByte(&ba, 0x00); appendByte(&ba, 0x00); appendInt(&ba, m_session.pid); - sendTrkMessage(0x41, Callback(), ba, "Delete process"); + sendTrkMessage(0x41, TrkCallback(), ba, "Delete process"); //---TRK------------------------------------------------------ // Command: 0x80 Acknowledge @@ -1396,8 +1483,7 @@ void Adapter::cleanUp() foreach (const Breakpoint &bp, m_breakpoints) clearTrkBreakpoint(bp); - sendTrkMessage(0x02, CB(handleDisconnect)); - m_startInferiorTriggered = false; + sendTrkMessage(0x02, TrkCB(handleDisconnect)); //---IDE------------------------------------------------------ // Command: 0x1C Clear Break // [1C 25 00 00 00 0A 78 6A 43 40] @@ -1427,7 +1513,7 @@ void Adapter::cleanUp() //---IDE------------------------------------------------------ // Command: 0x02 Disconnect // [02 27] -// sendTrkMessage(0x02, CB(handleDisconnect)); +// sendTrkMessage(0x02, TrkCB(handleDisconnect)); //---TRK------------------------------------------------------ // Command: 0x80 Acknowledge // Error: 0x00 @@ -1450,58 +1536,45 @@ void Adapter::readMemory(uint addr, uint len) // 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)); + 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, CB(handleReadMemoryBuffered), - memoryRequestTrkMessage(blockaddr, MemoryChunkSize, m_session.pid, m_session.tid), - QVariant(blockaddr), true); + logMessage(QString::fromLatin1("Requesting buffered " + "memory %1 bytes from 0x%2") + .arg(MemoryChunkSize).arg(blockaddr, 0, 16)); + sendTrkMessage(0x10, TrkCB(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, CB(reportReadMemoryBuffered), QByteArray(), cookie); + sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, TrkCB(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, CB(handleReadMemoryUnbuffered), - memoryRequestTrkMessage(addr, len, m_session.pid, m_session.tid), - QVariant(addr), true); + logMessage(QString::fromLatin1("Requesting unbuffered memory %1 " + "bytes from 0x%2").arg(len).arg(addr, 0, 16)); + sendTrkMessage(0x10, TrkCB(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; - } - // 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, CB(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); + // We choose 2, as 1 does not seem to work. + appendByte(&ba, 2); appendInt(&ba, m_session.pid); appendInt(&ba, m_session.tid); // threadID: 4 bytes Variable number of bytes. - sendTrkMessage(0x1A, Callback(), ba, "Interrupting..."); + sendTrkMessage(0x1a, TrkCallback(), ba, "Interrupting..."); } void Adapter::connectProcess(QProcess *proc) @@ -1510,10 +1583,6 @@ void Adapter::connectProcess(QProcess *proc) 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)), @@ -1539,18 +1608,6 @@ void Adapter::handleProcFinished(int exitCode, QProcess::ExitStatus exitStatus) QString("ProcessFinished %1 %2").arg(exitCode).arg(exitStatus)); } -void Adapter::handleProcReadyReadStandardError() -{ - QByteArray ba = qobject_cast(sender())->readAllStandardError(); - sendOutput(sender(), QString("stderr: %1").arg(QString::fromLatin1(ba))); -} - -void Adapter::handleProcReadyReadStandardOutput() -{ - QByteArray ba = qobject_cast(sender())->readAllStandardOutput(); - sendOutput(sender(), QString("stdout: %1").arg(QString::fromLatin1(ba))); -} - void Adapter::handleProcStarted() { sendOutput(sender(), QString("Process Started")); @@ -1563,18 +1620,26 @@ void Adapter::handleProcStateChanged(QProcess::ProcessState newState) void Adapter::run() { - startServer(); + startInferior(); 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); } void Adapter::startGdb() { + 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())); + logMessage("STARTING GDB"); QStringList gdbArgs; gdbArgs.append("--nx"); // Do not read .gdbinit file @@ -1583,26 +1648,155 @@ void Adapter::startGdb() m_gdbProc.start(QDir::currentPath() + "/cs-gdb", gdbArgs); m_gdbProc.waitForStarted(); - //writeToGdb("set remote noack-packet on"); - writeToGdb("set confirm off"); - writeToGdb("set endian " + m_endianness); - //writeToGdb("set debug remote 1"); - //writeToGdb("target remote " + m_gdbServerName); - writeToGdb("target extended-remote " + m_gdbServerName); - //writeToGdb("file filebrowseapp.sym"); -// writeToGdb("add-symbol-file filebrowseapp.sym " + m_baseAddress); -// writeToGdb("symbol-file filebrowseapp.sym"); -// writeToGdb("print E32Main"); -// writeToGdb("break E32Main"); - //writeToGdb("continue"); - //writeToGdb("info files"); - //writeToGdb("file filebrowseapp.sym -readnow"); + sendGdbMessage("set confirm off"); // confirm potentially dangerous operations? + sendGdbMessage("set endian little"); + sendGdbMessage("set remotebreak on"); + sendGdbMessage("set breakpoint pending on"); + + // FIXME: "remote noack" does not seem to be supported on cs-gdb? + //sendGdbMessage("set remote noack-packet"); + + // FIXME: creates a lot of noise a la '&"putpkt: Junk: Ack " &' + // even thouhg the communication seems sane + //sendGdbMessage("set debug remote 1"); // creates l + + //sendGdbMessage("target remote " + m_gdbServerName); +// sendGdbMessage("target extended-remote " + m_gdbServerName); + //sendGdbMessage("target extended-async " + m_gdbServerName); + //sendGdbMessage("set remotecache ...") // Set cache use for remote targets + //sendGdbMessage("file filebrowseapp.sym"); +// sendGdbMessage("add-symbol-file filebrowseapp.sym " + m_baseAddress); +// sendGdbMessage("symbol-file filebrowseapp.sym"); +// sendGdbMessage("print E32Main"); +// sendGdbMessage("break E32Main"); + //sendGdbMessage("continue"); + //sendGdbMessage("info files"); + //sendGdbMessage("file filebrowseapp.sym -readnow"); + + sendGdbMessage("add-symbol-file filebrowseapp.sym 0x" + + hexNumber(m_session.codeseg)); + sendGdbMessage("symbol-file filebrowseapp.sym"); + + // -symbol-info-address not implemented in cs-gdb 6.4-6.8 (at least) + sendGdbMessage("info address E32Main", GdbCB(handleInfoMainAddress)); + +#if 1 + // FIXME: Gdb based version. That's the goal + //sendGdbMessage("break E32Main"); + //sendGdbMessage("continue"); + QByteArray ba; + appendInt(&ba, m_session.pid); + appendInt(&ba, m_session.tid); + //sendTrkMessage(0x18, TrkCB(handleContinueAfterCreateProcess), + // trkContinueMessage(), "CONTINUE"); +#else + // Directly talk to TRK. Works for now... + sendGdbMessage("break E32Main"); + sendGdbMessage("break filebrowseappui.cpp:39"); + //foreach (const Breakpoint &bp, m_breakpoints) + // setTrkBreakpoint(bp); + //sendTrkContinue(); + // sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE"); +#endif } -void Adapter::writeToGdb(const QString &msg) +void Adapter::sendGdbMessage(const QString &msg, GdbCallback callback, + const QVariant &cookie) { - logMessage("<- GDB: " + msg); - m_gdbProc.write(msg.toLatin1() + "\n"); + static int token = 0; + ++token; + GdbCommand data; + data.command = msg; + data.callback = callback; + data.cookie = cookie; + m_gdbCookieForToken[++token] = data; + logMessage(QString("<- GDB: %1 %2").arg(token).arg(msg)); + m_gdbProc.write(QString("%1%2\n").arg(token).arg(msg).toLatin1()); +} + +void Adapter::handleGdbReadyReadStandardError() +{ + QByteArray ba = qobject_cast(sender())->readAllStandardError(); + sendOutput(sender(), QString("stderr: %1").arg(QString::fromLatin1(ba))); +} + +void Adapter::handleGdbReadyReadStandardOutput() +{ + QByteArray ba = qobject_cast(sender())->readAllStandardOutput(); + QString str = QString::fromLatin1(ba); + // FIXME: fragile. merge with gdbengine logic +#if 0 + QRegExp re(QString(".*([0-9]+)[^]done.*")); + int pos = re.indexIn(str); + if (pos == -1) { + logMessage(QString("\n-> GDB: %1 %**% %2 %**%\n").arg(str).arg(pos)); + return; + } + int token = re.cap(1).toInt(); + logMessage(QString("\n-> GDB: %1 %2##\n").arg(token).arg(QString::fromLatin1(ba))); + if (!token) + return; + GdbCommand cmd = m_gdbCookieForToken.take(token); + logMessage("FOUND CALLBACK FOR " + cmd.command); + GdbResult result; + result.data = ba; + if (!cmd.callback.isNull()) + cmd.callback(result); +#else + QRegExp re(QString("Symbol .._Z7E32Mainv.. is a function at address 0x(.*)\\.")); + if (re.indexIn(str) == -1) { + logMessage(QString("-> GDB: %1").arg(str)); + return; + } + logMessage(QString("-> GDB MAIN: %1").arg(re.cap(1))); + GdbResult result; + result.data = re.cap(1).toLatin1(); + handleInfoMainAddress(result); +#endif +} + +void Adapter::handleInfoMainAddress(const GdbResult &result) +{ + bool ok; + uint addr = result.data.toInt(&ok, 16); + const QByteArray ba = trkBreakpointMessage(addr, 1, m_session.pid); + sendTrkMessage(0x1B, TrkCB(handleSetTrkMainBreakpoint), ba); +} + +void Adapter::handleSetTrkMainBreakpoint(const TrkResult &result) +{ + //---TRK------------------------------------------------------ + // [80 09 00 00 00 00 0A] + const uint bpnr = extractInt(result.data.data()); + logMessage("SET MAIN BREAKPOINT 0x" + hexNumber(bpnr) + + stringFromArray(result.data.data())); + + // 'continue after initial break' + QByteArray ba; + appendInt(&ba, m_session.pid); + appendInt(&ba, m_session.tid); + sendTrkMessage(0x18, TrkCallback(), ba, "CONTINUE"); + + // this attaches + sendGdbMessage("target remote " + m_gdbServerName); +} + +void Adapter::handleInfoAddress(const GdbResult &result) +{ + Q_UNUSED(result); + // FIXME +} + +void Adapter::handleRfcommReadyReadStandardError() +{ + QByteArray ba = qobject_cast(sender())->readAllStandardError(); + sendOutput(sender(), QString("stderr: %1").arg(QString::fromLatin1(ba))); +} + +void Adapter::handleRfcommReadyReadStandardOutput() +{ + QByteArray ba = qobject_cast(sender())->readAllStandardOutput(); + sendOutput(sender(), QString("stdout: %1").arg(QString::fromLatin1(ba))); } /////////////////////////////////////////////////////////////////////// @@ -1640,16 +1834,18 @@ void RunnerGui::handleOutput(const QString &senderName, const QString &data) QTextCursor tc = textCursor(); tc.movePosition(QTextCursor::End); setTextCursor(tc); - if (senderName.startsWith("GDB PROCESS")) { - QString str = data; - int pos = str.indexOf("~\""); - if (pos != -1) - str = str.mid(pos + 2); - str.replace("\\t", QString(QChar(0x09))); - str.replace("\\n", QString("\n")); - insertHtml("" + str + ""); - setCurrentCharFormat(QTextCharFormat()); - } +/* + QString str = data; + int pos1 = str.indexOf("#"); + int pos2 = str.indexOf(")", pos1); + if (pos1 != -1 && pos2 != -1) + str = str.left(pos1) + "" + str.mid(pos1, pos2 - pos1 + 1) + + " " + str.mid(pos2 + 1); + str.replace("\\t", QString(QChar(0x09))); + str.replace("\\n", QString("\n")); + insertHtml(str + "\n"); +*/ + setCurrentCharFormat(QTextCharFormat()); ensureCursorVisible(); } @@ -1657,7 +1853,7 @@ void RunnerGui::handleOutput(const QString &senderName, const QString &data) void RunnerGui::keyPressEvent(QKeyEvent *ev) { if (ev->modifiers() == Qt::ControlModifier && ev->key() == Qt::Key_Return) - m_adapter->executeGdbCommand(textCursor().block().text()); + m_adapter->executeCommand(textCursor().block().text()); else QTextEdit::keyPressEvent(ev); } diff --git a/tests/manual/trk/trkdevice.h b/tests/manual/trk/trkdevice.h index 7b2a5dbcd38..7bfdff7411b 100644 --- a/tests/manual/trk/trkdevice.h +++ b/tests/manual/trk/trkdevice.h @@ -111,7 +111,7 @@ public: explicit TrkWriteQueueDevice(QObject *parent = 0); virtual ~TrkWriteQueueDevice(); - // Construct as 'TrkWriteQueueDevice::Callback(instance, &Klass::method);' + // Construct as 'TrkWriteQueueDevice::Callback(instance, &Class::method);' typedef TrkFunctor1 Callback; // Enqueue a message with a notification callback. diff --git a/tests/manual/trk/trkdevicex.cpp b/tests/manual/trk/trkdevicex.cpp index 31382de3f03..d9abfdf1dfb 100644 --- a/tests/manual/trk/trkdevicex.cpp +++ b/tests/manual/trk/trkdevicex.cpp @@ -492,6 +492,7 @@ void TrkDevice::tryTrkRead() while (extractResult(&d->trkReadBuffer, d->serialFrame, &r, &rawData)) { //if (verbose()) // logMessage("Read TrkResult " + r.data.toHex()); + qDebug() << "RECEIVE DATA: " << r.data.toHex(); emit messageReceived(r); if (!rawData.isEmpty()) emit rawDataReceived(rawData); diff --git a/tests/manual/trk/trkfunctor.h b/tests/manual/trk/trkfunctor.h index 69a67e97a61..3dbd027774b 100644 --- a/tests/manual/trk/trkfunctor.h +++ b/tests/manual/trk/trkfunctor.h @@ -32,6 +32,9 @@ #include + +// FIXME: rename into something less TRK-specific + namespace trk { namespace Internal { /* Helper class for the 1-argument functor: diff --git a/tests/manual/trk/trkutils.h b/tests/manual/trk/trkutils.h index 42df54b680d..6bc05db157d 100644 --- a/tests/manual/trk/trkutils.h +++ b/tests/manual/trk/trkutils.h @@ -72,6 +72,7 @@ enum Command { QByteArray decode7d(const QByteArray &ba); QByteArray encode7d(const QByteArray &ba); +inline byte extractByte(const char *data) { return *data; } ushort extractShort(const char *data); uint extractInt(const char *data); From 1b4d1f1fd49941a1fba8b3bd6d1042aad02ca220 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 8 Sep 2009 12:43:14 +0200 Subject: [PATCH 03/23] Suppress warning dialog when the QML Viewer executable cannot be found. --- src/plugins/qmlprojectmanager/qmlproject.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp index a0dc6873c93..2d61bd50366 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.cpp +++ b/src/plugins/qmlprojectmanager/qmlproject.cpp @@ -344,12 +344,7 @@ QString QmlRunConfiguration::type() const QString QmlRunConfiguration::executable() const { - if (! QFile::exists(m_qmlViewer)) { - QMessageBox::information(Core::ICore::instance()->mainWindow(), - tr("QML Viewer"), - tr("Could not find the qmlviewer executable, please specify one.")); - } - + // No need to verify if the QML Viewer exists. The console will tell us anyway when we try to launch it. return m_qmlViewer; } From 61ed06d58e137c3daf49f3011d1124c948a5c795 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Tue, 8 Sep 2009 13:03:24 +0200 Subject: [PATCH 04/23] Moved mouse navigation into BaseTextEditor so that it can be reused For implementing mouse navigation in the QML editor. --- src/plugins/cppeditor/cppeditor.cpp | 100 +---------------- src/plugins/cppeditor/cppeditor.h | 36 +------ src/plugins/texteditor/basetexteditor.cpp | 125 +++++++++++++++++++++- src/plugins/texteditor/basetexteditor.h | 50 ++++++++- src/plugins/texteditor/basetexteditor_p.h | 6 +- 5 files changed, 179 insertions(+), 138 deletions(-) diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index 5bea06a0453..597a2769e85 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -527,8 +527,6 @@ CPPEditorEditable::CPPEditorEditable(CPPEditor *editor) CPPEditor::CPPEditor(QWidget *parent) : TextEditor::BaseTextEditor(parent) - , m_mouseNavigationEnabled(true) - , m_showingLink(false) , m_currentRenameSelection(-1) , m_inRename(false) { @@ -1073,7 +1071,7 @@ void CPPEditor::switchDeclarationDefinition() } CPPEditor::Link CPPEditor::findLinkAt(const QTextCursor &cursor, - bool lookupDefinition) + bool resolveTarget) { Link link; @@ -1153,7 +1151,7 @@ CPPEditor::Link CPPEditor::findLinkAt(const QTextCursor &cursor, if (Symbol *symbol = result.second) { Symbol *def = 0; - if (lookupDefinition && !lastSymbol->isFunction()) + if (resolveTarget && !lastSymbol->isFunction()) def = findDefinition(symbol); link = linkToSymbol(def ? def : symbol); @@ -1190,7 +1188,7 @@ CPPEditor::Link CPPEditor::findLinkAt(const QTextCursor &cursor, void CPPEditor::jumpToDefinition() { - openCppEditorAt(findLinkAt(textCursor())); + openLink(findLinkAt(textCursor())); } Symbol *CPPEditor::findDefinition(Symbol *symbol) @@ -1342,68 +1340,6 @@ void CPPEditor::contextMenuEvent(QContextMenuEvent *e) delete menu; } -void CPPEditor::mouseMoveEvent(QMouseEvent *e) -{ - bool linkFound = false; - - if (m_mouseNavigationEnabled && e->modifiers() & Qt::ControlModifier) { - // Link emulation behaviour for 'go to definition' - const QTextCursor cursor = cursorForPosition(e->pos()); - - // Check that the mouse was actually on the text somewhere - bool onText = cursorRect(cursor).right() >= e->x(); - if (!onText) { - QTextCursor nextPos = cursor; - nextPos.movePosition(QTextCursor::Right); - onText = cursorRect(nextPos).right() >= e->x(); - } - - const Link link = findLinkAt(cursor, false); - - if (onText && !link.fileName.isEmpty()) { - showLink(link); - linkFound = true; - } - } - - if (!linkFound) - clearLink(); - - TextEditor::BaseTextEditor::mouseMoveEvent(e); -} - -void CPPEditor::mouseReleaseEvent(QMouseEvent *e) -{ - if (m_mouseNavigationEnabled && e->modifiers() & Qt::ControlModifier - && !(e->modifiers() & Qt::ShiftModifier) - && e->button() == Qt::LeftButton) { - - const QTextCursor cursor = cursorForPosition(e->pos()); - if (openCppEditorAt(findLinkAt(cursor))) { - clearLink(); - e->accept(); - return; - } - } - - TextEditor::BaseTextEditor::mouseReleaseEvent(e); -} - -void CPPEditor::leaveEvent(QEvent *e) -{ - clearLink(); - TextEditor::BaseTextEditor::leaveEvent(e); -} - -void CPPEditor::keyReleaseEvent(QKeyEvent *e) -{ - // Clear link emulation when Ctrl is released - if (e->key() == Qt::Key_Control) - clearLink(); - - TextEditor::BaseTextEditor::keyReleaseEvent(e); -} - void CPPEditor::keyPressEvent(QKeyEvent *e) { if (m_currentRenameSelection == -1) { @@ -1491,29 +1427,6 @@ void CPPEditor::keyPressEvent(QKeyEvent *e) TextEditor::BaseTextEditor::keyPressEvent(e); } -void CPPEditor::showLink(const Link &link) -{ - QTextEdit::ExtraSelection sel; - sel.cursor = textCursor(); - sel.cursor.setPosition(link.pos); - sel.cursor.setPosition(link.pos + link.length, QTextCursor::KeepAnchor); - sel.format = m_linkFormat; - sel.format.setFontUnderline(true); - setExtraSelections(OtherSelection, QList() << sel); - viewport()->setCursor(Qt::PointingHandCursor); - m_showingLink = true; -} - -void CPPEditor::clearLink() -{ - if (!m_showingLink) - return; - - setExtraSelections(OtherSelection, QList()); - viewport()->setCursor(Qt::IBeamCursor); - m_showingLink = false; -} - QList CPPEditorEditable::context() const { return m_context; @@ -1557,17 +1470,10 @@ void CPPEditor::setFontSettings(const TextEditor::FontSettings &fs) highlighter->setFormats(formats.constBegin(), formats.constEnd()); highlighter->rehighlight(); - m_linkFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_LINK)); m_occurrencesFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_OCCURRENCES)); m_occurrenceRenameFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_OCCURRENCES_RENAME)); } -void CPPEditor::setDisplaySettings(const TextEditor::DisplaySettings &ds) -{ - TextEditor::BaseTextEditor::setDisplaySettings(ds); - m_mouseNavigationEnabled = ds.m_mouseNavigation; -} - void CPPEditor::unCommentSelection() { Core::Utils::unCommentSelection(this); diff --git a/src/plugins/cppeditor/cppeditor.h b/src/plugins/cppeditor/cppeditor.h index 27991a550f3..40e2e71972f 100644 --- a/src/plugins/cppeditor/cppeditor.h +++ b/src/plugins/cppeditor/cppeditor.h @@ -193,7 +193,6 @@ public: public Q_SLOTS: virtual void setFontSettings(const TextEditor::FontSettings &); - virtual void setDisplaySettings(const TextEditor::DisplaySettings &); void setSortedMethodOverview(bool sort); void switchDeclarationDefinition(); void jumpToDefinition(); @@ -208,10 +207,6 @@ public Q_SLOTS: protected: bool event(QEvent *e); void contextMenuEvent(QContextMenuEvent *); - void mouseMoveEvent(QMouseEvent *); - void mouseReleaseEvent(QMouseEvent *); - void leaveEvent(QEvent *); - void keyReleaseEvent(QKeyEvent *); void keyPressEvent(QKeyEvent *); TextEditor::BaseTextEditorEditable *createEditableInterface(); @@ -261,36 +256,11 @@ private: const QString &text = QString()); void abortRename(); - struct Link - { - Link(const QString &fileName = QString(), - int line = 0, - int column = 0) - : pos(-1) - , length(-1) - , fileName(fileName) - , line(line) - , column(column) - {} - - int pos; // Link position - int length; // Link length - - QString fileName; // Target file - int line; // Target line - int column; // Target column - }; - - void showLink(const Link &); - void clearLink(); - - Link findLinkAt(const QTextCursor &, bool lookupDefinition = true); - static Link linkToSymbol(CPlusPlus::Symbol *symbol); + Link findLinkAt(const QTextCursor &, bool resolveTarget = true); + bool openLink(const Link &link) { return openCppEditorAt(link); } bool openCppEditorAt(const Link &); - bool m_mouseNavigationEnabled; - bool m_showingLink; - QTextCharFormat m_linkFormat; + static Link linkToSymbol(CPlusPlus::Symbol *symbol); CppTools::CppModelManagerInterface *m_modelManager; diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp index 80a1f0268cc..59c55fcb2d4 100644 --- a/src/plugins/texteditor/basetexteditor.cpp +++ b/src/plugins/texteditor/basetexteditor.cpp @@ -1337,6 +1337,16 @@ bool BaseTextEditor::codeFoldingSupported() const return d->m_codeFoldingSupported; } +void BaseTextEditor::setMouseNavigationEnabled(bool b) +{ + d->m_mouseNavigationEnabled = b; +} + +bool BaseTextEditor::mouseNavigationEnabled() const +{ + return d->m_mouseNavigationEnabled; +} + void BaseTextEditor::setRevisionsVisible(bool b) { d->m_revisionsVisible = b; @@ -1372,12 +1382,14 @@ BaseTextEditorPrivate::BaseTextEditorPrivate() m_marksVisible(false), m_codeFoldingVisible(false), m_codeFoldingSupported(false), + m_mouseNavigationEnabled(true), m_revisionsVisible(false), m_lineNumbersVisible(true), m_highlightCurrentLine(true), m_requestMarkEnabled(true), m_lineSeparatorsAllowed(false), m_visibleWrapColumn(0), + m_showingLink(false), m_editable(0), m_actionHack(0), m_inBlockSelectionMode(false), @@ -2721,6 +2733,32 @@ void BaseTextEditorPrivate::clearVisibleCollapsedBlock() void BaseTextEditor::mouseMoveEvent(QMouseEvent *e) { d->m_lastEventWasBlockSelectionEvent = (e->modifiers() & Qt::AltModifier); + + bool linkFound = false; + + if (d->m_mouseNavigationEnabled && e->modifiers() & Qt::ControlModifier) { + // Link emulation behaviour for 'go to definition' + const QTextCursor cursor = cursorForPosition(e->pos()); + + // Check that the mouse was actually on the text somewhere + bool onText = cursorRect(cursor).right() >= e->x(); + if (!onText) { + QTextCursor nextPos = cursor; + nextPos.movePosition(QTextCursor::Right); + onText = cursorRect(nextPos).right() >= e->x(); + } + + const Link link = findLinkAt(cursor, false); + + if (onText && link.isValid()) { + showLink(link); + linkFound = true; + } + } + + if (!linkFound) + clearLink(); + if (e->buttons() == Qt::NoButton) { const QTextBlock collapsedBlock = collapsedBlockAt(e->pos()); const int blockNumber = collapsedBlock.next().blockNumber(); @@ -2767,6 +2805,38 @@ void BaseTextEditor::mousePressEvent(QMouseEvent *e) QPlainTextEdit::mousePressEvent(e); } +void BaseTextEditor::mouseReleaseEvent(QMouseEvent *e) +{ + if (d->m_mouseNavigationEnabled && e->modifiers() & Qt::ControlModifier + && !(e->modifiers() & Qt::ShiftModifier) + && e->button() == Qt::LeftButton) { + + const QTextCursor cursor = cursorForPosition(e->pos()); + if (openLink(findLinkAt(cursor))) { + clearLink(); + return; + } + } + + QPlainTextEdit::mouseReleaseEvent(e); +} + +void BaseTextEditor::leaveEvent(QEvent *e) +{ + // Clear link emulation when the mouse leaves the editor + clearLink(); + QPlainTextEdit::leaveEvent(e); +} + +void BaseTextEditor::keyReleaseEvent(QKeyEvent *e) +{ + // Clear link emulation when Ctrl is released + if (e->key() == Qt::Key_Control) + clearLink(); + + QPlainTextEdit::keyReleaseEvent(e); +} + void BaseTextEditor::extraAreaLeaveEvent(QEvent *) { // fake missing mouse move event from Qt @@ -3186,6 +3256,50 @@ void BaseTextEditor::indent(QTextDocument *doc, const QTextCursor &cursor, QChar } } +BaseTextEditor::Link BaseTextEditor::findLinkAt(const QTextCursor &, bool) +{ + return Link(); +} + +bool BaseTextEditor::openLink(const Link &link) +{ + if (link.fileName.isEmpty()) + return false; + + if (baseTextDocument()->fileName() == link.fileName) { + Core::EditorManager *editorManager = Core::EditorManager::instance(); + editorManager->addCurrentPositionToNavigationHistory(); + gotoLine(link.line, link.column); + setFocus(); + return true; + } + + return openEditorAt(link.fileName, link.line, link.column); +} + +void BaseTextEditor::showLink(const Link &link) +{ + QTextEdit::ExtraSelection sel; + sel.cursor = textCursor(); + sel.cursor.setPosition(link.pos); + sel.cursor.setPosition(link.pos + link.length, QTextCursor::KeepAnchor); + sel.format = d->m_linkFormat; + sel.format.setFontUnderline(true); + setExtraSelections(OtherSelection, QList() << sel); + viewport()->setCursor(Qt::PointingHandCursor); + d->m_showingLink = true; +} + +void BaseTextEditor::clearLink() +{ + if (!d->m_showingLink) + return; + + setExtraSelections(OtherSelection, QList()); + viewport()->setCursor(Qt::IBeamCursor); + d->m_showingLink = false; +} + void BaseTextEditorPrivate::updateMarksBlock(const QTextBlock &block) { if (const TextBlockUserData *userData = TextEditDocumentLayout::testUserData(block)) @@ -4005,8 +4119,8 @@ void BaseTextEditor::unCommentSelection() void BaseTextEditor::showEvent(QShowEvent* e) { if (!d->m_fontSettings.isEmpty()) { - setFontSettings(d->m_fontSettings); - d->m_fontSettings.clear(); + setFontSettings(d->m_fontSettings); + d->m_fontSettings.clear(); } QPlainTextEdit::showEvent(e); } @@ -4015,11 +4129,12 @@ void BaseTextEditor::showEvent(QShowEvent* e) void BaseTextEditor::setFontSettingsIfVisible(const TextEditor::FontSettings &fs) { if (!isVisible()) { - d->m_fontSettings = fs; - return; + d->m_fontSettings = fs; + return; } setFontSettings(fs); } + void BaseTextEditor::setFontSettings(const TextEditor::FontSettings &fs) { const QTextCharFormat textFormat = fs.toTextCharFormat(QLatin1String(Constants::C_TEXT)); @@ -4030,6 +4145,7 @@ void BaseTextEditor::setFontSettings(const TextEditor::FontSettings &fs) const QTextCharFormat parenthesesFormat = fs.toTextCharFormat(QLatin1String(Constants::C_PARENTHESES)); d->m_currentLineFormat = fs.toTextCharFormat(QLatin1String(Constants::C_CURRENT_LINE)); d->m_currentLineNumberFormat = fs.toTextCharFormat(QLatin1String(Constants::C_CURRENT_LINE_NUMBER)); + d->m_linkFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_LINK)); d->m_ifdefedOutFormat = fs.toTextCharFormat(QLatin1String(Constants::C_DISABLED_CODE)); QFont font(textFormat.font()); @@ -4082,6 +4198,7 @@ void BaseTextEditor::setDisplaySettings(const DisplaySettings &ds) setCodeFoldingVisible(ds.m_displayFoldingMarkers); setHighlightCurrentLine(ds.m_highlightCurrentLine); setRevisionsVisible(ds.m_markTextChanges); + setMouseNavigationEnabled(ds.m_mouseNavigation); if (d->m_displaySettings.m_visualizeWhitespace != ds.m_visualizeWhitespace) { if (QSyntaxHighlighter *highlighter = baseTextDocument()->syntaxHighlighter()) diff --git a/src/plugins/texteditor/basetexteditor.h b/src/plugins/texteditor/basetexteditor.h index 34554082925..17a67d3b0a9 100644 --- a/src/plugins/texteditor/basetexteditor.h +++ b/src/plugins/texteditor/basetexteditor.h @@ -274,8 +274,7 @@ private: }; -class TEXTEDITOR_EXPORT BaseTextEditor - : public QPlainTextEdit +class TEXTEDITOR_EXPORT BaseTextEditor : public QPlainTextEdit { Q_OBJECT @@ -345,6 +344,9 @@ public: void setCodeFoldingSupported(bool b); bool codeFoldingSupported() const; + void setMouseNavigationEnabled(bool b); + bool mouseNavigationEnabled() const; + void setRevisionsVisible(bool b); bool revisionsVisible() const; @@ -496,14 +498,54 @@ protected: void timerEvent(QTimerEvent *); void mouseMoveEvent(QMouseEvent *); void mousePressEvent(QMouseEvent *); + void mouseReleaseEvent(QMouseEvent *); + void leaveEvent(QEvent *); + void keyReleaseEvent(QKeyEvent *); - // Rertuns true if key triggers an indent. + // Returns true if key triggers an indent. virtual bool isElectricCharacter(const QChar &ch) const; // Indent a text block based on previous line. Default does nothing virtual void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar); // Indent at cursor. Calls indentBlock for selection or current line. virtual void indent(QTextDocument *doc, const QTextCursor &cursor, QChar typedChar); + struct Link + { + Link(const QString &fileName = QString(), + int line = 0, + int column = 0) + : pos(-1) + , length(-1) + , fileName(fileName) + , line(line) + , column(column) + {} + + bool isValid() const + { return !(pos == -1 || length == -1); } + + int pos; // Link position + int length; // Link length + + QString fileName; // Target file + int line; // Target line + int column; // Target column + }; + + /*! + Reimplement this function to enable code navigation. + + \a resolveTarget is set to true when the target of the link is relevant + (it isn't until the link is used). + */ + virtual Link findLinkAt(const QTextCursor &, bool resolveTarget = true); + + /*! + Reimplement this function if you want to customize the way a link is + opened. Returns whether the link was opened succesfully. + */ + virtual bool openLink(const Link &link); + protected slots: virtual void slotUpdateExtraAreaWidth(); virtual void slotModificationChanged(bool); @@ -537,6 +579,8 @@ private: QTextBlock collapsedBlockAt(const QPoint &pos, QRect *box = 0) const; + void showLink(const Link &); + void clearLink(); // parentheses matcher private slots: diff --git a/src/plugins/texteditor/basetexteditor_p.h b/src/plugins/texteditor/basetexteditor_p.h index dbf5b66d1e8..1956f858800 100644 --- a/src/plugins/texteditor/basetexteditor_p.h +++ b/src/plugins/texteditor/basetexteditor_p.h @@ -194,6 +194,7 @@ public: uint m_marksVisible : 1; uint m_codeFoldingVisible : 1; uint m_codeFoldingSupported : 1; + uint m_mouseNavigationEnabled : 1; uint m_revisionsVisible : 1; uint m_lineNumbersVisible : 1; uint m_highlightCurrentLine : 1; @@ -201,6 +202,9 @@ public: uint m_lineSeparatorsAllowed : 1; int m_visibleWrapColumn; + QTextCharFormat m_linkFormat; + bool m_showingLink; + QTextCharFormat m_ifdefedOutFormat; QRegExp m_searchExpr; @@ -226,7 +230,7 @@ public: QString copyBlockSelection(); void removeBlockSelection(const QString &text = QString()); bool m_moveLineUndoHack; - + QTextCursor m_findScope; QTextCursor m_selectBlockAnchor; From e58ff77bd396af02ddd38fcac82ac3eb6eeb8e8b Mon Sep 17 00:00:00 2001 From: dt Date: Mon, 7 Sep 2009 18:58:04 +0200 Subject: [PATCH 05/23] Take the build environment into account for searching what to execute. Fixes a bug where the cmake plugin wasn't finding make, if the make commands directory was added to path in the build environment. --- src/plugins/cmakeprojectmanager/cmakeproject.cpp | 2 +- src/plugins/projectexplorer/abstractprocessstep.cpp | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index e05614029c3..455c6e87095 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -500,7 +500,7 @@ void CMakeProject::setUserEnvironmentChanges(const QString &buildConfig, const Q QStringList list = EnvironmentItem::toStringList(diff); if (list == value(buildConfig, "userEnvironmentChanges")) return; - setValue(buildConfig, "userEnvironmentChanges", EnvironmentItem::toStringList(diff)); + setValue(buildConfig, "userEnvironmentChanges", list); emit environmentChanged(buildConfig); } diff --git a/src/plugins/projectexplorer/abstractprocessstep.cpp b/src/plugins/projectexplorer/abstractprocessstep.cpp index a766a1e5a8b..e3b7757881e 100644 --- a/src/plugins/projectexplorer/abstractprocessstep.cpp +++ b/src/plugins/projectexplorer/abstractprocessstep.cpp @@ -58,7 +58,13 @@ void AbstractProcessStep::setCommand(const QString &buildConfiguration, const QS QString AbstractProcessStep::command(const QString &buildConfiguration) const { - return value(buildConfiguration, PROCESS_COMMAND).toString(); + QString result = value(buildConfiguration, PROCESS_COMMAND).toString(); + if (QFileInfo(result).isRelative()) { + QString searchInPath = environment(buildConfiguration).searchInPath(result); + if (!searchInPath.isEmpty()) + result = searchInPath; + } + return result; } void AbstractProcessStep::setWorkingDirectory(const QString &buildConfiguration, const QString &workingDirectory) From d9e7a39081091629dfa5231f7a666e7ee9805a6d Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 8 Sep 2009 09:42:59 +0200 Subject: [PATCH 06/23] debugger: simplify trk device logic a bit --- tests/manual/trk/runner.cpp | 1 - tests/manual/trk/trkdevicex.cpp | 44 ++++++++++++++++----------------- tests/manual/trk/trkdevicex.h | 6 ----- 3 files changed, 22 insertions(+), 29 deletions(-) diff --git a/tests/manual/trk/runner.cpp b/tests/manual/trk/runner.cpp index 1ed357b5df0..cd0df3010d1 100755 --- a/tests/manual/trk/runner.cpp +++ b/tests/manual/trk/runner.cpp @@ -999,7 +999,6 @@ void Adapter::handleTrkError(const QString &msg) void Adapter::handleTrkResult(const TrkResult &result) { - logMessage("HANDLING RESULT: " + result.data); if (result.isDebugOutput) { sendTrkAck(result.token); logMessage(QLatin1String("APPLICATION OUTPUT: ") + diff --git a/tests/manual/trk/trkdevicex.cpp b/tests/manual/trk/trkdevicex.cpp index d9abfdf1dfb..12f4f08481d 100644 --- a/tests/manual/trk/trkdevicex.cpp +++ b/tests/manual/trk/trkdevicex.cpp @@ -257,8 +257,18 @@ void TrkWriteQueue::queueTrkInitialPing() trkWriteQueue.append(TrkMessage(0, 0)); } -struct TrkDevicePrivate { + +/////////////////////////////////////////////////////////////////////// +// +// TrkDevicePrivate +// +/////////////////////////////////////////////////////////////////////// + +struct TrkDevicePrivate +{ TrkDevicePrivate(); + + TrkWriteQueue queue; #ifdef Q_OS_WIN HANDLE hdevice; #else @@ -298,11 +308,13 @@ TrkDevicePrivate::TrkDevicePrivate() : TrkDevice::TrkDevice(QObject *parent) : QObject(parent), - d(new TrkDevicePrivate), - qd(new TrkWriteQueue) + d(new TrkDevicePrivate) +{} + +TrkDevice::~TrkDevice() { - connect(this, SIGNAL(messageReceived(trk::TrkResult)), - this, SLOT(slotHandleResult(trk::TrkResult))); + close(); + delete d; } bool TrkDevice::open(const QString &port, QString *errorMessage) @@ -355,14 +367,6 @@ bool TrkDevice::open(const QString &port, QString *errorMessage) #endif } - -TrkDevice::~TrkDevice() -{ - close(); - delete d; - delete qd; -} - void TrkDevice::close() { if (!isOpen()) @@ -493,6 +497,7 @@ void TrkDevice::tryTrkRead() //if (verbose()) // logMessage("Read TrkResult " + r.data.toHex()); qDebug() << "RECEIVE DATA: " << r.data.toHex(); + d->queue.slotHandleResult(r); emit messageReceived(r); if (!rawData.isEmpty()) emit rawDataReceived(rawData); @@ -515,12 +520,12 @@ void TrkDevice::emitError(const QString &s) void TrkDevice::sendTrkMessage(byte code, Callback callback, const QByteArray &data, const QVariant &cookie, bool invokeOnNAK) { - qd->queueTrkMessage(code, callback, data, cookie, invokeOnNAK); + d->queue.queueTrkMessage(code, callback, data, cookie, invokeOnNAK); } void TrkDevice::sendTrkInitialPing() { - qd->queueTrkInitialPing(); + d->queue.queueTrkInitialPing(); } bool TrkDevice::sendTrkAck(byte token) @@ -536,10 +541,10 @@ bool TrkDevice::sendTrkAck(byte token) void TrkDevice::tryTrkWrite() { TrkMessage message; - if (!qd->pendingMessage(&message)) + if (!d->queue.pendingMessage(&message)) return; const bool success = trkWriteRawMessage(message); - qd->notifyWriteResult(success); + d->queue.notifyWriteResult(success); } bool TrkDevice::trkWriteRawMessage(const TrkMessage &msg) @@ -554,10 +559,5 @@ bool TrkDevice::trkWriteRawMessage(const TrkMessage &msg) return rc; } -void TrkDevice::slotHandleResult(const TrkResult &result) -{ - qd->slotHandleResult(result); -} - } // namespace trk diff --git a/tests/manual/trk/trkdevicex.h b/tests/manual/trk/trkdevicex.h index 9d0e9da0dcc..1873f458e7c 100644 --- a/tests/manual/trk/trkdevicex.h +++ b/tests/manual/trk/trkdevicex.h @@ -46,8 +46,6 @@ namespace trk { struct TrkResult; struct TrkMessage; struct TrkDevicePrivate; -class TrkWriteQueue; -struct TrkWriteQueueIODevicePrivate; /* TrkDevice: Implements a Windows COM or Linux device for * Trk communications. Provides synchronous write and asynchronous @@ -116,15 +114,11 @@ public: // Send an Ack synchronously, bypassing the queue bool sendTrkAck(unsigned char token); -private slots: - void slotHandleResult(const trk::TrkResult &); - private: void tryTrkWrite(); bool trkWriteRawMessage(const TrkMessage &msg); TrkDevicePrivate *d; - TrkWriteQueue *qd; }; } // namespace trk From 2da891ee887eecbe8421da50f5461541f45234d1 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 8 Sep 2009 10:12:50 +0200 Subject: [PATCH 07/23] trk: fix size of 'kill' packet. also, do not announce the library loading to gdb as it starts asking questions afterwards. --- tests/manual/trk/runner.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/manual/trk/runner.cpp b/tests/manual/trk/runner.cpp index cd0df3010d1..c6d03cfa602 100755 --- a/tests/manual/trk/runner.cpp +++ b/tests/manual/trk/runner.cpp @@ -664,6 +664,7 @@ void Adapter::handleGdbServerCommand(const QByteArray &response) // kill sendGdbServerAck(); QByteArray ba; + appendByte(&ba, 0); // ? appendByte(&ba, 0); // Sub-command: Delete Process appendInt(&ba, m_session.pid); sendTrkMessage(0x41, TrkCallback(), ba, "Delete process"); // Delete Item @@ -1006,6 +1007,7 @@ void Adapter::handleTrkResult(const TrkResult &result) sendGdbServerMessage("O" + result.data.toHex()); return; } + logMessage("READ TRK " + result.toString()); QByteArray prefix = "READ BUF: "; QByteArray str = result.toString().toUtf8(); switch (result.code) { @@ -1074,8 +1076,9 @@ void Adapter::handleTrkResult(const TrkResult &result) str << " DATA: 0x" << hexNumber(dataseg); str << " NAME: '" << name << '\''; logMessage(logMsg); - sendGdbServerMessage("T05library:" + name); - //sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE"); + // This lets gdb trigger a register update etc + //sendGdbServerMessage("T05library:r;"); + sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE"); break; } case 0xa1: { // NotifyDeleted From db8cddf55bf9b12796f37619b4a20c86abddd9d3 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 8 Sep 2009 10:17:10 +0200 Subject: [PATCH 08/23] trk: rename 'response' to 'cmd' in handleGdbServerCommand --- tests/manual/trk/runner.cpp | 95 +++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 51 deletions(-) diff --git a/tests/manual/trk/runner.cpp b/tests/manual/trk/runner.cpp index c6d03cfa602..27fb8e0cfb4 100755 --- a/tests/manual/trk/runner.cpp +++ b/tests/manual/trk/runner.cpp @@ -251,7 +251,7 @@ public: Q_SLOT void handleGdbConnection(); Q_SLOT void readGdbServerCommand(); void readGdbResponse(); - void handleGdbServerCommand(const QByteArray &ba); + void handleGdbServerCommand(const QByteArray &cmd); void sendGdbServerMessage(const QByteArray &msg, const QByteArray &logNote = QByteArray()); void sendGdbServerMessageAfterTrkResponse(const QByteArray &msg, @@ -475,9 +475,9 @@ void Adapter::readGdbServerCommand() + quoteUnprintableLatin1(ba)).arg(checkSum).arg(sum)); } - QByteArray response = ba.left(pos); + QByteArray cmd = ba.left(pos); ba.remove(0, pos + 3); - handleGdbServerCommand(response); + handleGdbServerCommand(cmd); } } @@ -569,18 +569,18 @@ QByteArray Adapter::trkBreakpointMessage(uint addr, int len, int pid, bool armMo return ba; } -void Adapter::handleGdbServerCommand(const QByteArray &response) +void Adapter::handleGdbServerCommand(const QByteArray &cmd) { // http://sourceware.org/gdb/current/onlinedocs/gdb_34.html if (0) {} - else if (response == "!") { + else if (cmd == "!") { sendGdbServerAck(); //sendGdbServerMessage("", "extended mode not enabled"); sendGdbServerMessage("OK", "extended mode enabled"); } - else if (response.startsWith("?")) { + else if (cmd.startsWith("?")) { logMessage(msgGdbPacket(QLatin1String("Query halted"))); // Indicate the reason the target halted. // The reply is the same as for step and continue. @@ -594,7 +594,7 @@ void Adapter::handleGdbServerCommand(const QByteArray &response) //sendGdbServerMessage("O" + QByteArray("Starting...").toHex()); } - else if (response == "c") { + else if (cmd == "c") { logMessage(msgGdbPacket(QLatin1String("Continue"))); sendGdbServerAck(); QByteArray ba; @@ -606,26 +606,26 @@ void Adapter::handleGdbServerCommand(const QByteArray &response) sendTrkMessage(0x18, TrkCallback(), ba); } - else if (response.startsWith("C")) { + else if (cmd.startsWith("C")) { 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. sendGdbServerAck(); bool ok = false; - uint signalNumber = response.mid(1).toInt(&ok, 16); + uint signalNumber = cmd.mid(1).toInt(&ok, 16); QByteArray ba; appendInt(&ba, m_session.pid); appendInt(&ba, m_session.tid); sendTrkMessage(0x18, TrkCB(handleSignalContinue), ba, signalNumber); // Continue } - else if (response.startsWith("D")) { + else if (cmd.startsWith("D")) { sendGdbServerAck(); sendGdbServerMessage("OK", "shutting down"); qApp->quit(); } - else if (response == "g") { + else if (cmd == "g") { logMessage(msgGdbPacket(QLatin1String("Read registers"))); // Read general registers. //sendGdbServerMessage("00000000", "read registers"); @@ -639,7 +639,7 @@ void Adapter::handleGdbServerCommand(const QByteArray &response) sendTrkMessage(0x12, TrkCB(handleAndReportReadRegisters), ba, QVariant(), true); } - else if (response.startsWith("Hc")) { + else if (cmd.startsWith("Hc")) { logMessage(msgGdbPacket(QLatin1String("Set thread & continue"))); // Set thread for subsequent operations (`m', `M', `g', `G', et.al.). // for step and continue operations @@ -648,18 +648,18 @@ void Adapter::handleGdbServerCommand(const QByteArray &response) sendGdbServerMessage("OK", "Set current thread for step & continue"); } - else if (response.startsWith("Hg")) { + else if (cmd.startsWith("Hg")) { logMessage(msgGdbPacket(QLatin1String("Set thread"))); // Set thread for subsequent operations (`m', `M', `g', `G', et.al.). // for 'other operations. 0 - any thread //$Hg0#df sendGdbServerAck(); - m_session.currentThread = response.mid(2).toInt(0, 16); + m_session.currentThread = cmd.mid(2).toInt(0, 16); sendGdbServerMessage("OK", "Set current thread " + QByteArray::number(m_session.currentThread)); } - else if (response == "k") { + else if (cmd == "k") { logMessage(msgGdbPacket(QLatin1String("kill"))); // kill sendGdbServerAck(); @@ -671,30 +671,30 @@ void Adapter::handleGdbServerCommand(const QByteArray &response) sendGdbServerMessageAfterTrkResponse("", "process killed"); } - else if (response.startsWith("m")) { + else if (cmd.startsWith("m")) { logMessage(msgGdbPacket(QLatin1String("Read memory"))); // m addr,length sendGdbServerAck(); uint addr = 0, len = 0; do { - const int pos = response.indexOf(','); + const int pos = cmd.indexOf(','); if (pos == -1) break; bool ok; - addr = response.mid(1, pos - 1).toUInt(&ok, 16); + addr = cmd.mid(1, pos - 1).toUInt(&ok, 16); if (!ok) break; - len = response.mid(pos + 1).toUInt(&ok, 16); + len = cmd.mid(pos + 1).toUInt(&ok, 16); if (!ok) break; } while (false); if (len) { readMemory(addr, len); } else { - sendGdbServerMessage("E20", "Error " + response); + sendGdbServerMessage("E20", "Error " + cmd); } } - else if (response.startsWith("p")) { + else if (cmd.startsWith("p")) { logMessage(msgGdbPacket(QLatin1String("read register"))); // 0xf == current instruction pointer? //sendGdbServerMessage("0000", "current IP"); @@ -732,7 +732,7 @@ void Adapter::handleGdbServerCommand(const QByteArray &response) LAST_FP_ARG = F3 #endif bool ok = false; - const uint registerNumber = response.mid(1).toInt(&ok, 16); + const uint registerNumber = cmd.mid(1).toInt(&ok, 16); QByteArray logMsg = "Read Register"; if (registerNumber == RegisterPSGdb) { QByteArray ba; @@ -750,7 +750,7 @@ void Adapter::handleGdbServerCommand(const QByteArray &response) } } - else if (response == "qAttached") { + else if (cmd == "qAttached") { //$qAttached#8f // 1: attached to an existing process // 0: created a new process @@ -760,7 +760,7 @@ void Adapter::handleGdbServerCommand(const QByteArray &response) //sendGdbServerMessage("E01", "new process created"); } - else if (response.startsWith("qC")) { + else if (cmd.startsWith("qC")) { logMessage(msgGdbPacket(QLatin1String("query thread id"))); // Return the current thread ID //$qC#b4 @@ -768,7 +768,7 @@ void Adapter::handleGdbServerCommand(const QByteArray &response) sendGdbServerMessageAfterTrkResponse("QC@TID@"); } - else if (response.startsWith("qSupported")) { + else if (cmd.startsWith("qSupported")) { //$qSupported#37 //$qSupported:multiprocess+#c6 //logMessage("Handling 'qSupported'"); @@ -784,7 +784,7 @@ void Adapter::handleGdbServerCommand(const QByteArray &response) "qXfer:features:read+"); } - else if (response == "qPacketInfo") { + else if (cmd == "qPacketInfo") { // happens with gdb 6.4.50.20060226-cvs / CodeSourcery // deprecated by qSupported? @@ -792,12 +792,12 @@ void Adapter::handleGdbServerCommand(const QByteArray &response) sendGdbServerMessage("", "FIXME: nothing?"); } - else if (response == "qOffsets") { + else if (cmd == "qOffsets") { sendGdbServerAck(); sendGdbServerMessageAfterTrkResponse("TextSeg=@CODESEG@;DataSeg=@DATASEG@"); } - else if (response == "qSymbol::") { + else if (cmd == "qSymbol::") { if (m_verbose) logMessage(msgGdbPacket(QLatin1String("notify can handle symbol lookup"))); // Notify the target that GDB is prepared to serve symbol lookup requests. @@ -808,13 +808,13 @@ void Adapter::handleGdbServerCommand(const QByteArray &response) sendGdbServerMessage("qSymbol:" + QByteArray("_Z7E32Mainv").toHex(), "ask for more"); } - else if (response.startsWith("qXfer:features:read:target.xml:")) { + else if (cmd.startsWith("qXfer:features:read:target.xml:")) { // $qXfer:features:read:target.xml:0,7ca#46...Ack sendGdbServerAck(); sendGdbServerMessage("lsymbianelf"); } - else if (response == "QStartNoAckMode") { + else if (cmd == "QStartNoAckMode") { //$qSupported#37 //logMessage("Handling 'QStartNoAckMode'"); sendGdbServerAck(); @@ -822,7 +822,7 @@ void Adapter::handleGdbServerCommand(const QByteArray &response) m_gdbAckMode = false; } - else if (response.startsWith("QPassSignals")) { + else if (cmd.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 @@ -831,7 +831,7 @@ void Adapter::handleGdbServerCommand(const QByteArray &response) sendGdbServerMessage("OK", "passing signals accepted"); } - else if (response == "s") { + else if (cmd == "s" || cmd.startsWith("vCont;s")) { if (m_verbose) logMessage(msgGdbPacket(QLatin1String("Step range"))); sendGdbServerAck(); @@ -846,28 +846,21 @@ void Adapter::handleGdbServerCommand(const QByteArray &response) //sendGdbServerMessageAfterTrkResponse("S05", "target halted"); } - else if (response == "vCont?") { + else if (cmd == "vCont?") { // actions supported by the vCont packet sendGdbServerAck(); sendGdbServerMessage("OK"); // we don't support vCont. //sendGdbServerMessage("vCont;c"); } - else if (response == "vCont;c") { + else if (cmd == "vCont;c") { // vCont[;action[:thread-id]]...' sendGdbServerAck(); m_running = true; sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE"); } - else if (response.startsWith("vCont;s")) { - // vCont[;action[:thread-id]]...' - sendGdbServerAck(); - m_running = true; - sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE"); - } - - else if (response.startsWith("vKill")) { + else if (cmd.startsWith("vKill")) { // kill sendGdbServerAck(); QByteArray ba; @@ -877,20 +870,20 @@ void Adapter::handleGdbServerCommand(const QByteArray &response) sendGdbServerMessageAfterTrkResponse("", "process killed"); } - else if (0 && response.startsWith("Z0,")) { + else if (0 && cmd.startsWith("Z0,")) { // Tell gdb we don't support software breakpoints sendGdbServerMessage(""); } - else if (response.startsWith("Z0,") || response.startsWith("Z1,")) { + else if (cmd.startsWith("Z0,") || cmd.startsWith("Z1,")) { // Insert breakpoint if (m_verbose) logMessage(msgGdbPacket(QLatin1String("Insert breakpoint"))); // $z0,786a4ccc,4#99 - const int pos = response.lastIndexOf(','); + const int pos = cmd.lastIndexOf(','); bool ok = false; - const uint addr = response.mid(3, pos - 3).toInt(&ok, 16); - const uint len = response.mid(pos + 1).toInt(&ok, 16); + const uint addr = cmd.mid(3, pos - 3).toInt(&ok, 16); + const uint len = cmd.mid(pos + 1).toInt(&ok, 16); qDebug() << "ADDR: " << hexNumber(addr) << " LEN: " << len; if (m_verbose) logMessage(QString::fromLatin1("Inserting breakpoint at 0x%1, %2") @@ -915,8 +908,8 @@ void Adapter::handleGdbServerCommand(const QByteArray &response) // 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(':')); + } else if (cmd.startsWith("qPart:") || cmd.startsWith("qXfer:")) { + QByteArray data = cmd.mid(1 + cmd.indexOf(':')); // "qPart:auxv:read::0,147": Read OS auxiliary data (see info aux) bool handled = false; if (data.startsWith("auxv:read::")) { @@ -938,14 +931,14 @@ void Adapter::handleGdbServerCommand(const QByteArray &response) } // auxv read if (!handled) { const QString msg = QLatin1String("FIXME unknown 'XFER'-request: ") - + QString::fromAscii(response); + + QString::fromAscii(cmd); logMessage(msgGdbPacket(msg), true); sendGdbServerMessage("E20", msg.toLatin1()); } } // qPart/qXfer else { logMessage(msgGdbPacket(QLatin1String("FIXME unknown: ") - + QString::fromAscii(response))); + + QString::fromAscii(cmd))); } } From fbeeb8677ab3520ca5c41f8c317834a79fd3c419 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 8 Sep 2009 10:38:06 +0200 Subject: [PATCH 09/23] trk: remove a debug message --- tests/manual/trk/trkdevicex.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/manual/trk/trkdevicex.cpp b/tests/manual/trk/trkdevicex.cpp index 12f4f08481d..0323d82eadf 100644 --- a/tests/manual/trk/trkdevicex.cpp +++ b/tests/manual/trk/trkdevicex.cpp @@ -496,7 +496,6 @@ void TrkDevice::tryTrkRead() while (extractResult(&d->trkReadBuffer, d->serialFrame, &r, &rawData)) { //if (verbose()) // logMessage("Read TrkResult " + r.data.toHex()); - qDebug() << "RECEIVE DATA: " << r.data.toHex(); d->queue.slotHandleResult(r); emit messageReceived(r); if (!rawData.isEmpty()) From 0fc3129b3c18dbc29cf24d461b7b31571c0a834b Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 8 Sep 2009 10:57:33 +0200 Subject: [PATCH 10/23] trk: we always want to be called back independent of ACK/NAK --- tests/manual/trk/runner.cpp | 97 ++++++++++++++++++--------------- tests/manual/trk/trkdevicex.cpp | 22 +++----- tests/manual/trk/trkdevicex.h | 4 +- 3 files changed, 62 insertions(+), 61 deletions(-) diff --git a/tests/manual/trk/runner.cpp b/tests/manual/trk/runner.cpp index 27fb8e0cfb4..f73f8409363 100755 --- a/tests/manual/trk/runner.cpp +++ b/tests/manual/trk/runner.cpp @@ -180,8 +180,7 @@ public: void sendTrkMessage(byte code, TrkCallback callback = TrkCallback(), const QByteArray &data = QByteArray(), - const QVariant &cookie = QVariant(), - bool invokeOnFailure = false); + const QVariant &cookie = QVariant()); Q_SLOT void handleTrkResult(const trk::TrkResult &data); Q_SLOT void handleTrkError(const QString &msg); @@ -206,8 +205,9 @@ public: void handleAndReportReadRegisters(const TrkResult &result); QByteArray memoryReadLogMessage(uint addr, uint len, const QByteArray &ba) const; QByteArray trkContinueMessage(); - QByteArray trkBreakpointMessage(uint addr, int len, int pid, - bool armMode = true); + QByteArray trkReadRegisterMessage(); + QByteArray trkReadMemoryMessage(uint addr, uint len); + QByteArray trkBreakpointMessage(uint addr, uint len, bool armMode = true); void handleAndReportSetBreakpoint(const TrkResult &result); void handleReadMemoryBuffered(const TrkResult &result); void handleReadMemoryUnbuffered(const TrkResult &result); @@ -358,6 +358,36 @@ uint Adapter::gdbServerPort() const return m_gdbServerName.mid(pos + 1).toUInt(); } +QByteArray Adapter::trkContinueMessage() +{ + QByteArray ba; + appendInt(&ba, m_session.pid); + appendInt(&ba, m_session.tid); + return ba; +} + +QByteArray Adapter::trkReadRegisterMessage() +{ + 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); + return ba; +} + +QByteArray Adapter::trkReadMemoryMessage(uint addr, uint len) +{ + QByteArray ba; + appendByte(&ba, 0x08); // Options, FIXME: why? + appendShort(&ba, len); + appendInt(&ba, addr); + appendInt(&ba, m_session.pid); + appendInt(&ba, m_session.tid); + return ba; +} + void Adapter::startInferior() { QString errorMessage; @@ -556,7 +586,7 @@ void Adapter::reportToGdb(const TrkResult &result) sendGdbServerMessage(message, note); } -QByteArray Adapter::trkBreakpointMessage(uint addr, int len, int pid, bool armMode) +QByteArray Adapter::trkBreakpointMessage(uint addr, uint len, bool armMode) { QByteArray ba; appendByte(&ba, 0x82); // unused option @@ -564,7 +594,7 @@ QByteArray Adapter::trkBreakpointMessage(uint addr, int len, int pid, bool armMo appendInt(&ba, addr); appendInt(&ba, len); appendInt(&ba, 0x00000001); - appendInt(&ba, pid); + appendInt(&ba, m_session.pid); appendInt(&ba, 0xFFFFFFFF); return ba; } @@ -630,13 +660,8 @@ void Adapter::handleGdbServerCommand(const QByteArray &cmd) // Read general registers. //sendGdbServerMessage("00000000", "read registers"); sendGdbServerAck(); - 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, TrkCB(handleAndReportReadRegisters), ba, QVariant(), true); + sendTrkMessage(0x12, TrkCB(handleAndReportReadRegisters), + trkReadRegisterMessage()); } else if (cmd.startsWith("Hc")) { @@ -787,7 +812,6 @@ void Adapter::handleGdbServerCommand(const QByteArray &cmd) else if (cmd == "qPacketInfo") { // happens with gdb 6.4.50.20060226-cvs / CodeSourcery // deprecated by qSupported? - sendGdbServerAck(); sendGdbServerMessage("", "FIXME: nothing?"); } @@ -832,9 +856,12 @@ void Adapter::handleGdbServerCommand(const QByteArray &cmd) } else if (cmd == "s" || cmd.startsWith("vCont;s")) { - if (m_verbose) - logMessage(msgGdbPacket(QLatin1String("Step range"))); + static int used = 0; + if (!used) { + ++used; + logMessage(msgGdbPacket(QLatin1String("Step range"))); sendGdbServerAck(); + m_running = true; QByteArray ba; appendByte(&ba, 0); // options appendInt(&ba, m_snapshot.registers[RegisterPC]); // start address @@ -844,6 +871,7 @@ void Adapter::handleGdbServerCommand(const QByteArray &cmd) sendTrkMessage(0x19, TrkCB(handleStepRange), ba, "Step range"); // FIXME: should be triggered by "real" stop" //sendGdbServerMessageAfterTrkResponse("S05", "target halted"); + } } else if (cmd == "vCont?") { @@ -948,6 +976,8 @@ void Adapter::executeCommand(const QString &msg) sendGdbMessage("-exec-interrupt"); } else if (msg == "C") { sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE"); + } else if (msg == "R") { + sendTrkMessage(0x18, TrkCallback(), trkReadRegisterMessage(), "READ REGS"); } else if (msg == "I") { interruptInferior(); } else { @@ -969,9 +999,9 @@ bool Adapter::openTrkPort(const QString &port, QString *errorMessage) } void Adapter::sendTrkMessage(byte code, TrkCallback callback, - const QByteArray &data, const QVariant &cookie, bool invokeOnFailure) + const QByteArray &data, const QVariant &cookie) { - m_trkDevice.sendTrkMessage(code, callback, data, cookie, invokeOnFailure); + m_trkDevice.sendTrkMessage(code, callback, data, cookie); } void Adapter::waitForTrkFinished() @@ -1310,14 +1340,6 @@ QByteArray Adapter::memoryReadLogMessage(uint addr, uint len, const QByteArray & return logMsg; } -QByteArray Adapter::trkContinueMessage() -{ - QByteArray ba; - appendInt(&ba, m_session.pid); - appendInt(&ba, m_session.tid); - return ba; -} - void Adapter::reportReadMemoryBuffered(const TrkResult &result) { const qulonglong cookie = result.cookie.toULongLong(); @@ -1368,7 +1390,7 @@ void Adapter::handleStepRange(const TrkResult &result) // [80 0f 12] //uint bpnr = extractInt(result.data.data()); logMessage("STEPPING FINISHED " + stringFromArray(result.data.data())); - sendGdbServerMessage("S05", "Stepping finished"); + //sendGdbServerMessage("S05", "Stepping finished"); } void Adapter::handleAndReportSetBreakpoint(const TrkResult &result) @@ -1514,17 +1536,6 @@ void Adapter::cleanUp() // 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)); @@ -1543,9 +1554,8 @@ void Adapter::readMemory(uint addr, uint len) "memory %1 bytes from 0x%2") .arg(MemoryChunkSize).arg(blockaddr, 0, 16)); sendTrkMessage(0x10, TrkCB(handleReadMemoryBuffered), - memoryRequestTrkMessage(blockaddr, MemoryChunkSize, - m_session.pid, m_session.tid), - QVariant(blockaddr), true); + trkReadMemoryMessage(blockaddr, MemoryChunkSize), + QVariant(blockaddr)); } } const qulonglong cookie = (qulonglong(addr) << 32) + len; @@ -1556,8 +1566,7 @@ void Adapter::readMemory(uint addr, uint len) logMessage(QString::fromLatin1("Requesting unbuffered memory %1 " "bytes from 0x%2").arg(len).arg(addr, 0, 16)); sendTrkMessage(0x10, TrkCB(handleReadMemoryUnbuffered), - memoryRequestTrkMessage(addr, len, m_session.pid, m_session.tid), - QVariant(addr), true); + trkReadMemoryMessage(addr, len), QVariant(addr)); } } @@ -1754,7 +1763,7 @@ void Adapter::handleInfoMainAddress(const GdbResult &result) { bool ok; uint addr = result.data.toInt(&ok, 16); - const QByteArray ba = trkBreakpointMessage(addr, 1, m_session.pid); + const QByteArray ba = trkBreakpointMessage(addr, 1); sendTrkMessage(0x1B, TrkCB(handleSetTrkMainBreakpoint), ba); } diff --git a/tests/manual/trk/trkdevicex.cpp b/tests/manual/trk/trkdevicex.cpp index 0323d82eadf..42c7f72e175 100644 --- a/tests/manual/trk/trkdevicex.cpp +++ b/tests/manual/trk/trkdevicex.cpp @@ -117,14 +117,12 @@ struct TrkMessage QByteArray data; QVariant cookie; Callback callback; - bool invokeOnNAK; }; TrkMessage::TrkMessage(byte c, byte t, Callback cb) : code(c), token(t), - callback(cb), - invokeOnNAK(false) + callback(cb) { } @@ -144,8 +142,7 @@ public: // Enqueue messages. void queueTrkMessage(byte code, Callback callback, - const QByteArray &data, const QVariant &cookie, - bool invokeOnNAK); + const QByteArray &data, const QVariant &cookie); void queueTrkInitialPing(); // Call this from the device read notification with the results. @@ -184,14 +181,13 @@ byte TrkWriteQueue::nextTrkWriteToken() } void TrkWriteQueue::queueTrkMessage(byte code, Callback callback, - const QByteArray &data, const QVariant &cookie, bool invokeOnNAK) + const QByteArray &data, const QVariant &cookie) { const byte token = code == TRK_WRITE_QUEUE_NOOP_CODE ? byte(0) : nextTrkWriteToken(); TrkMessage msg(code, token, callback); msg.data = data; msg.cookie = cookie; - msg.invokeOnNAK = invokeOnNAK; trkWriteQueue.append(msg); } @@ -233,16 +229,14 @@ void TrkWriteQueue::notifyWriteResult(bool ok) void TrkWriteQueue::slotHandleResult(const TrkResult &result) { trkWriteBusy = false; - if (result.code != TrkNotifyAck && result.code != TrkNotifyNak) - return; + //if (result.code != TrkNotifyAck && result.code != TrkNotifyNak) + // return; // Find which request the message belongs to and invoke callback // if ACK or on NAK if desired. const TokenMessageMap::iterator it = writtenTrkMessages.find(result.token); if (it == writtenTrkMessages.end()) return; - const bool invokeCB = it.value().callback - && (result.code == TrkNotifyAck || it.value().invokeOnNAK); - + const bool invokeCB = it.value().callback; if (invokeCB) { TrkResult result1 = result; result1.cookie = it.value().cookie; @@ -517,9 +511,9 @@ void TrkDevice::emitError(const QString &s) } void TrkDevice::sendTrkMessage(byte code, Callback callback, - const QByteArray &data, const QVariant &cookie, bool invokeOnNAK) + const QByteArray &data, const QVariant &cookie) { - d->queue.queueTrkMessage(code, callback, data, cookie, invokeOnNAK); + d->queue.queueTrkMessage(code, callback, data, cookie); } void TrkDevice::sendTrkInitialPing() diff --git a/tests/manual/trk/trkdevicex.h b/tests/manual/trk/trkdevicex.h index 1873f458e7c..5a7a7440775 100644 --- a/tests/manual/trk/trkdevicex.h +++ b/tests/manual/trk/trkdevicex.h @@ -104,9 +104,7 @@ public: void sendTrkMessage(unsigned char code, Callback callBack = Callback(), const QByteArray &data = QByteArray(), - const QVariant &cookie = QVariant(), - // Invoke callback on receiving NAK, too. - bool invokeOnNAK = false); + const QVariant &cookie = QVariant()); // Enqeue an initial ping void sendTrkInitialPing(); From a1ea6f5f1f864c8d0e641de3420a5c30662a959c Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 8 Sep 2009 12:49:03 +0200 Subject: [PATCH 11/23] trk: refactoring --- tests/manual/trk/runner.cpp | 54 +++++++++++++++++++---------------- tests/manual/trk/trkutils.cpp | 16 +++++++++++ tests/manual/trk/trkutils.h | 2 ++ 3 files changed, 47 insertions(+), 25 deletions(-) diff --git a/tests/manual/trk/runner.cpp b/tests/manual/trk/runner.cpp index f73f8409363..a0bcef7f302 100755 --- a/tests/manual/trk/runner.cpp +++ b/tests/manual/trk/runner.cpp @@ -108,7 +108,7 @@ static QByteArray dumpRegister(int n, uint value) ba += '#'; ba += QByteArray::number(n); } - ba += "=0x" + hexNumber(value); + ba += "=" + hexxNumber(value); return ba; } @@ -856,22 +856,19 @@ void Adapter::handleGdbServerCommand(const QByteArray &cmd) } else if (cmd == "s" || cmd.startsWith("vCont;s")) { - static int used = 0; - if (!used) { - ++used; logMessage(msgGdbPacket(QLatin1String("Step range"))); + logMessage(" from " + hexxNumber(m_snapshot.registers[RegisterPC])); sendGdbServerAck(); m_running = true; QByteArray ba; - appendByte(&ba, 0); // options + appendByte(&ba, 1); // options appendInt(&ba, m_snapshot.registers[RegisterPC]); // start address - appendInt(&ba, m_snapshot.registers[RegisterPC] + 8); // end address + appendInt(&ba, m_snapshot.registers[RegisterPC] + 4); // end address appendInt(&ba, m_session.pid); appendInt(&ba, m_session.tid); sendTrkMessage(0x19, TrkCB(handleStepRange), ba, "Step range"); // FIXME: should be triggered by "real" stop" //sendGdbServerMessageAfterTrkResponse("S05", "target halted"); - } } else if (cmd == "vCont?") { @@ -977,7 +974,8 @@ void Adapter::executeCommand(const QString &msg) } else if (msg == "C") { sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE"); } else if (msg == "R") { - sendTrkMessage(0x18, TrkCallback(), trkReadRegisterMessage(), "READ REGS"); + sendTrkMessage(0x18, TrkCB(handleReadRegisters), + trkReadRegisterMessage(), "READ REGS"); } else if (msg == "I") { interruptInferior(); } else { @@ -1095,8 +1093,8 @@ void Adapter::handleTrkResult(const TrkResult &result) if (error) str << " ERROR: " << int(error); str << " TYPE: " << int(type) << " PID: " << pid << " TID: " << tid; - str << " CODE: 0x" << hexNumber(codeseg); - str << " DATA: 0x" << hexNumber(dataseg); + str << " CODE: " << hexxNumber(codeseg); + str << " DATA: " << hexxNumber(dataseg); str << " NAME: '" << name << '\''; logMessage(logMsg); // This lets gdb trigger a register update etc @@ -1198,7 +1196,7 @@ void Adapter::handleSetTrkBreakpoint(const TrkResult &result) // [80 09 00 00 00 00 0A] const uint bpnr = extractInt(result.data.data()); if (m_verbose) - logMessage("SET BREAKPOINT 0x" + hexNumber(bpnr) + logMessage("SET BREAKPOINT " + hexxNumber(bpnr) + stringFromArray(result.data.data())); } @@ -1213,10 +1211,10 @@ void Adapter::handleCreateProcess(const TrkResult &result) m_session.codeseg = extractInt(data + 9); m_session.dataseg = extractInt(data + 13); - logMessage("PID: 0x" + hexNumber(m_session.pid)); - logMessage("TID: 0x" + hexNumber(m_session.tid)); - logMessage("COD: 0x" + hexNumber(m_session.codeseg)); - logMessage("DAT: 0x" + hexNumber(m_session.dataseg)); + logMessage("PID: " + hexxNumber(m_session.pid)); + logMessage("TID: " + hexxNumber(m_session.tid)); + logMessage("COD: " + hexxNumber(m_session.codeseg)); + logMessage("DAT: " + hexxNumber(m_session.dataseg)); QByteArray ba; appendInt(&ba, m_session.pid); @@ -1263,7 +1261,10 @@ void Adapter::handleReadRegisters(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...] - + if (result.errorCode()) { + logMessage("ERROR: " + result.errorString()); + return; + } 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); @@ -1313,8 +1314,7 @@ QByteArray Adapter::memoryReadLogMessage(uint addr, uint len, const QByteArray & { QByteArray logMsg = "memory contents"; if (m_verbose > 1) { - logMsg += " addr: 0x"; - logMsg += QByteArray::number(addr, 16); + logMsg += " addr: " + hexxNumber(addr); // indicate dereferencing of registers if (len == 4) { if (addr == m_snapshot.registers[RegisterPC]) { @@ -1387,9 +1387,12 @@ void Adapter::handleReadMemoryUnbuffered(const TrkResult &result) void Adapter::handleStepRange(const TrkResult &result) { - // [80 0f 12] - //uint bpnr = extractInt(result.data.data()); - logMessage("STEPPING FINISHED " + stringFromArray(result.data.data())); + // [80 0f 00] + if (result.errorCode()) { + logMessage("ERROR: " + result.errorString()); + return; + } + logMessage("STEPPING FINISHED "); //sendGdbServerMessage("S05", "Stepping finished"); } @@ -1400,7 +1403,7 @@ void Adapter::handleAndReportSetBreakpoint(const TrkResult &result) // Error: 0x00 // [80 09 00 00 00 00 0A] uint bpnr = extractByte(result.data.data()); - logMessage("SET BREAKPOINT 0x" + hexNumber(bpnr) + " " + logMessage("SET BREAKPOINT " + hexxNumber(bpnr) + " " + stringFromArray(result.data.data())); sendGdbServerMessage("OK"); } @@ -1656,6 +1659,7 @@ void Adapter::startGdb() sendGdbMessage("set endian little"); sendGdbMessage("set remotebreak on"); sendGdbMessage("set breakpoint pending on"); + sendGdbMessage("set trust-readonly-sections on"); // FIXME: "remote noack" does not seem to be supported on cs-gdb? //sendGdbMessage("set remote noack-packet"); @@ -1677,8 +1681,8 @@ void Adapter::startGdb() //sendGdbMessage("info files"); //sendGdbMessage("file filebrowseapp.sym -readnow"); - sendGdbMessage("add-symbol-file filebrowseapp.sym 0x" - + hexNumber(m_session.codeseg)); + sendGdbMessage("add-symbol-file filebrowseapp.sym " + + hexxNumber(m_session.codeseg)); sendGdbMessage("symbol-file filebrowseapp.sym"); // -symbol-info-address not implemented in cs-gdb 6.4-6.8 (at least) @@ -1772,7 +1776,7 @@ void Adapter::handleSetTrkMainBreakpoint(const TrkResult &result) //---TRK------------------------------------------------------ // [80 09 00 00 00 00 0A] const uint bpnr = extractInt(result.data.data()); - logMessage("SET MAIN BREAKPOINT 0x" + hexNumber(bpnr) + logMessage("SET MAIN BREAKPOINT " + hexxNumber(bpnr) + stringFromArray(result.data.data())); // 'continue after initial break' diff --git a/tests/manual/trk/trkutils.cpp b/tests/manual/trk/trkutils.cpp index 81925c07d67..4036b2ad656 100644 --- a/tests/manual/trk/trkutils.cpp +++ b/tests/manual/trk/trkutils.cpp @@ -43,6 +43,11 @@ QByteArray hexNumber(uint n, int digits) return QByteArray(digits - ba.size(), '0') + ba; } +QByteArray hexxNumber(uint n, int digits) +{ + return "0x" + hexNumber(n, digits); +} + TrkResult::TrkResult() : code(0), token(0), @@ -345,5 +350,16 @@ int TrkResult::errorCode() const return errorCode; return isNAK ? 0xff : 0; } + +QString TrkResult::errorString() const +{ + // NAK means always error, else data sized 1 with a non-null element + if (code == 0xff) + return "NAK"; + if (data.size() < 1) + return "Unknown error packet"; + return errorMessage(data.at(0)); +} + } // namespace trk diff --git a/tests/manual/trk/trkutils.h b/tests/manual/trk/trkutils.h index 6bc05db157d..3ed06e3ca4a 100644 --- a/tests/manual/trk/trkutils.h +++ b/tests/manual/trk/trkutils.h @@ -178,6 +178,7 @@ struct TrkResult QString toString() const; // 0 for no error. int errorCode() const; + QString errorString() const; byte code; byte token; @@ -193,6 +194,7 @@ ushort isValidTrkResult(const QByteArray &buffer, bool serialFrame); bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *r, QByteArray *rawData = 0); QByteArray errorMessage(byte code); QByteArray hexNumber(uint n, int digits = 0); +QByteArray hexxNumber(uint n, int digits = 0); // prepends '0x', too uint swapEndian(uint in); From ae09799416aaed3e506038b33f59d2ed8f2aff9b Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 8 Sep 2009 13:08:58 +0200 Subject: [PATCH 12/23] trk: make ad-hoc UI a bit friendlier --- tests/manual/trk/runner.cpp | 103 ++++++++++++++++++++++++------------ 1 file changed, 69 insertions(+), 34 deletions(-) diff --git a/tests/manual/trk/runner.cpp b/tests/manual/trk/runner.cpp index a0bcef7f302..74ba1954eea 100755 --- a/tests/manual/trk/runner.cpp +++ b/tests/manual/trk/runner.cpp @@ -30,7 +30,6 @@ #include "trkutils.h" #include "trkdevicex.h" -#include #include #include #include @@ -43,10 +42,13 @@ #include #include +#include #include +#include #include #include #include +#include #include #include @@ -281,7 +283,7 @@ public: Q_SLOT void handleRfcommReadyReadStandardOutput(); // Debuggee state - void executeCommand(const QString &msg); + Q_SLOT void executeCommand(const QString &msg); Session m_session; // global-ish data (process id, target information) Snapshot m_snapshot; // local-ish data (memory and registers) int m_verbose; @@ -1813,57 +1815,90 @@ void Adapter::handleRfcommReadyReadStandardOutput() // /////////////////////////////////////////////////////////////////////// -class RunnerGui : public QTextEdit +class TextEdit : public QTextEdit +{ + Q_OBJECT + +signals: + void executeCommand(QString); + +public slots: + void handleOutput(const QString &senderName, const QString &data) + { + QString str = senderName + data; + str.replace("\\t", QString(QChar(0x09))); + str.replace("\\n", QString("\n")); + append(str); + + QTextCursor tc = textCursor(); + tc.movePosition(QTextCursor::End); + setTextCursor(tc); + /* + int pos1 = str.indexOf("#"); + int pos2 = str.indexOf(")", pos1); + if (pos1 != -1 && pos2 != -1) + str = str.left(pos1) + "" + str.mid(pos1, pos2 - pos1 + 1) + + " " + str.mid(pos2 + 1); + insertHtml(str + "\n"); + */ + setCurrentCharFormat(QTextCharFormat()); + ensureCursorVisible(); + } + + void keyPressEvent(QKeyEvent *ev) + { + if (ev->modifiers() == Qt::ControlModifier && ev->key() == Qt::Key_Return) + emit executeCommand(textCursor().block().text()); + else + QTextEdit::keyPressEvent(ev); + } +}; + +/////////////////////////////////////////////////////////////////////// +// +// RunnerGui +// +/////////////////////////////////////////////////////////////////////// + +class RunnerGui : public QMainWindow { Q_OBJECT public: RunnerGui(Adapter *adapter); - void keyPressEvent(QKeyEvent *ev); private slots: - void handleOutput(const QString &senderName, const QString &data); + void executeStepICommand(); private: Adapter *m_adapter; + TextEdit m_textEdit; + QToolBar m_toolBar; + QAction m_stepIAction; }; RunnerGui::RunnerGui(Adapter *adapter) - : m_adapter(adapter) + : m_adapter(adapter), m_stepIAction(0) { resize(1200, 1000); + setCentralWidget(&m_textEdit); + + addToolBar(&m_toolBar); + + m_stepIAction.setText("StepI"); + m_toolBar.addAction(&m_stepIAction); + connect(adapter, SIGNAL(output(QString,QString)), - this, SLOT(handleOutput(QString,QString))); + &m_textEdit, SLOT(handleOutput(QString,QString))); + connect(&m_textEdit, SIGNAL(executeCommand(QString)), + m_adapter, SLOT(executeCommand(QString))); + connect(&m_stepIAction, SIGNAL(triggered()), + this, SLOT(executeStepICommand())); } -void RunnerGui::handleOutput(const QString &senderName, const QString &data) +void RunnerGui::executeStepICommand() { - append(senderName + data); - QTextCursor tc = textCursor(); - tc.movePosition(QTextCursor::End); - setTextCursor(tc); -/* - QString str = data; - int pos1 = str.indexOf("#"); - int pos2 = str.indexOf(")", pos1); - if (pos1 != -1 && pos2 != -1) - str = str.left(pos1) + "" + str.mid(pos1, pos2 - pos1 + 1) - + " " + str.mid(pos2 + 1); - str.replace("\\t", QString(QChar(0x09))); - str.replace("\\n", QString("\n")); - insertHtml(str + "\n"); -*/ - setCurrentCharFormat(QTextCharFormat()); - ensureCursorVisible(); - -} - -void RunnerGui::keyPressEvent(QKeyEvent *ev) -{ - if (ev->modifiers() == Qt::ControlModifier && ev->key() == Qt::Key_Return) - m_adapter->executeCommand(textCursor().block().text()); - else - QTextEdit::keyPressEvent(ev); + m_adapter->executeCommand("stepi"); } /////////////////////////////////////////////////////////////////////// From 087eca4566f70ab95819b4f1c584bbc714b786e5 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 8 Sep 2009 14:45:19 +0200 Subject: [PATCH 13/23] trk: step-by-instruction --- tests/manual/trk/runner.cpp | 111 +++++++++++++++++++++--------------- 1 file changed, 65 insertions(+), 46 deletions(-) diff --git a/tests/manual/trk/runner.cpp b/tests/manual/trk/runner.cpp index 74ba1954eea..9d2d719d88d 100755 --- a/tests/manual/trk/runner.cpp +++ b/tests/manual/trk/runner.cpp @@ -230,8 +230,6 @@ public: TrkDevice m_trkDevice; - QList m_breakpoints; - // // Gdb // @@ -302,9 +300,6 @@ Adapter::Adapter() m_serialFrame = false; m_bufferedMemoryRead = true; //m_bufferedMemoryRead = false; - // m_breakpoints.append(Breakpoint(0x0040)); // E32Main - m_breakpoints.append(Breakpoint(0x0cc8)); // E32Main - m_breakpoints.append(Breakpoint(0x0cd0)); // E32Main m_trkServerName = "/dev/rfcomm0"; uid_t userId = getuid(); @@ -863,9 +858,10 @@ void Adapter::handleGdbServerCommand(const QByteArray &cmd) sendGdbServerAck(); m_running = true; QByteArray ba; - appendByte(&ba, 1); // options + appendByte(&ba, 0x01); // options appendInt(&ba, m_snapshot.registers[RegisterPC]); // start address - appendInt(&ba, m_snapshot.registers[RegisterPC] + 4); // end address + //appendInt(&ba, m_snapshot.registers[RegisterPC] + 4); // end address + appendInt(&ba, -1); // end address appendInt(&ba, m_session.pid); appendInt(&ba, m_session.tid); sendTrkMessage(0x19, TrkCB(handleStepRange), ba, "Step range"); @@ -911,10 +907,9 @@ void Adapter::handleGdbServerCommand(const QByteArray &cmd) bool ok = false; const uint addr = cmd.mid(3, pos - 3).toInt(&ok, 16); const uint len = cmd.mid(pos + 1).toInt(&ok, 16); - qDebug() << "ADDR: " << hexNumber(addr) << " LEN: " << len; - if (m_verbose) - logMessage(QString::fromLatin1("Inserting breakpoint at 0x%1, %2") - .arg(addr, 0, 16).arg(len)); + //qDebug() << "ADDR: " << hexNumber(addr) << " LEN: " << len; + logMessage(QString::fromLatin1("Inserting breakpoint at 0x%1, %2") + .arg(addr, 0, 16).arg(len)); //---IDE------------------------------------------------------ // Command: 0x1B Set Break @@ -1060,8 +1055,7 @@ void Adapter::handleTrkResult(const TrkResult &result) sendGdbServerMessage("S05", "Target stopped"); } } else { - if (m_verbose) - logMessage(QLatin1String("Ignoring stop at 0")); + logMessage(QLatin1String("Ignoring stop at 0")); } break; } @@ -1197,9 +1191,8 @@ void Adapter::handleSetTrkBreakpoint(const TrkResult &result) // Error: 0x00 // [80 09 00 00 00 00 0A] const uint bpnr = extractInt(result.data.data()); - if (m_verbose) - logMessage("SET BREAKPOINT " + hexxNumber(bpnr) - + stringFromArray(result.data.data())); + logMessage("SET BREAKPOINT " + hexxNumber(bpnr) + + stringFromArray(result.data.data())); } void Adapter::handleCreateProcess(const TrkResult &result) @@ -1502,8 +1495,8 @@ void Adapter::cleanUp() // Error: 0x00 // [80 24 00] - foreach (const Breakpoint &bp, m_breakpoints) - clearTrkBreakpoint(bp); + //foreach (const Breakpoint &bp, m_breakpoints) + // clearTrkBreakpoint(bp); sendTrkMessage(0x02, TrkCB(handleDisconnect)); //---IDE------------------------------------------------------ @@ -1662,6 +1655,7 @@ void Adapter::startGdb() sendGdbMessage("set remotebreak on"); sendGdbMessage("set breakpoint pending on"); sendGdbMessage("set trust-readonly-sections on"); + //sendGdbMessage("mem 0 ~0ll rw 8 cache"); // FIXME: "remote noack" does not seem to be supported on cs-gdb? //sendGdbMessage("set remote noack-packet"); @@ -1688,24 +1682,21 @@ void Adapter::startGdb() sendGdbMessage("symbol-file filebrowseapp.sym"); // -symbol-info-address not implemented in cs-gdb 6.4-6.8 (at least) - sendGdbMessage("info address E32Main", GdbCB(handleInfoMainAddress)); + sendGdbMessage("info address E32Main", + GdbCB(handleInfoMainAddress)); + sendGdbMessage("info address CFileBrowseAppUi::HandleCommandL", + GdbCB(handleInfoMainAddress)); #if 1 // FIXME: Gdb based version. That's the goal //sendGdbMessage("break E32Main"); //sendGdbMessage("continue"); - QByteArray ba; - appendInt(&ba, m_session.pid); - appendInt(&ba, m_session.tid); //sendTrkMessage(0x18, TrkCB(handleContinueAfterCreateProcess), // trkContinueMessage(), "CONTINUE"); #else // Directly talk to TRK. Works for now... sendGdbMessage("break E32Main"); sendGdbMessage("break filebrowseappui.cpp:39"); - //foreach (const Breakpoint &bp, m_breakpoints) - // setTrkBreakpoint(bp); - //sendTrkContinue(); // sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE"); #endif } @@ -1753,42 +1744,43 @@ void Adapter::handleGdbReadyReadStandardOutput() if (!cmd.callback.isNull()) cmd.callback(result); #else + bool ok; QRegExp re(QString("Symbol .._Z7E32Mainv.. is a function at address 0x(.*)\\.")); - if (re.indexIn(str) == -1) { - logMessage(QString("-> GDB: %1").arg(str)); + if (re.indexIn(str) != -1) { + logMessage(QString("-> GDB MAIN BREAKPOINT: %1").arg(re.cap(1))); + uint addr = re.cap(1).toInt(&ok, 16); + sendTrkMessage(0x1B, TrkCallback(), trkBreakpointMessage(addr, 1)); return; } - logMessage(QString("-> GDB MAIN: %1").arg(re.cap(1))); - GdbResult result; - result.data = re.cap(1).toLatin1(); - handleInfoMainAddress(result); + QRegExp re1(QString("Symbol .._ZN16CFileBrowseAppUi14HandleCommandLEi.. is a function at address 0x(.*)\\.")); + if (re1.indexIn(str) != -1) { + logMessage(QString("-> GDB USER BREAKPOINT: %1").arg(re1.cap(1))); + uint addr = re1.cap(1).toInt(&ok, 16); + sendTrkMessage(0x1B, TrkCallback(), trkBreakpointMessage(addr, 1)); + + sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE"); + sendGdbMessage("target remote " + m_gdbServerName); + return; + } + logMessage(QString("-> GDB: %1").arg(str)); #endif } void Adapter::handleInfoMainAddress(const GdbResult &result) { - bool ok; - uint addr = result.data.toInt(&ok, 16); - const QByteArray ba = trkBreakpointMessage(addr, 1); - sendTrkMessage(0x1B, TrkCB(handleSetTrkMainBreakpoint), ba); + Q_UNUSED(result); } void Adapter::handleSetTrkMainBreakpoint(const TrkResult &result) { + Q_UNUSED(result); +/* //---TRK------------------------------------------------------ // [80 09 00 00 00 00 0A] const uint bpnr = extractInt(result.data.data()); logMessage("SET MAIN BREAKPOINT " + hexxNumber(bpnr) + stringFromArray(result.data.data())); - - // 'continue after initial break' - QByteArray ba; - appendInt(&ba, m_session.pid); - appendInt(&ba, m_session.tid); - sendTrkMessage(0x18, TrkCallback(), ba, "CONTINUE"); - - // this attaches - sendGdbMessage("target remote " + m_gdbServerName); +*/ } void Adapter::handleInfoAddress(const GdbResult &result) @@ -1869,16 +1861,23 @@ public: private slots: void executeStepICommand(); + void executeStepCommand(); + void executeDisassICommand(); private: Adapter *m_adapter; TextEdit m_textEdit; QToolBar m_toolBar; QAction m_stepIAction; + QAction m_stepAction; + QAction m_disassIAction; }; RunnerGui::RunnerGui(Adapter *adapter) - : m_adapter(adapter), m_stepIAction(0) + : m_adapter(adapter), + m_stepIAction(0), + m_stepAction(0), + m_disassIAction(0) { resize(1200, 1000); setCentralWidget(&m_textEdit); @@ -1886,19 +1885,39 @@ RunnerGui::RunnerGui(Adapter *adapter) addToolBar(&m_toolBar); m_stepIAction.setText("StepI"); + m_disassIAction.setText("DisassI"); m_toolBar.addAction(&m_stepIAction); + m_toolBar.addAction(&m_stepAction); + m_toolBar.addAction(&m_disassIAction); connect(adapter, SIGNAL(output(QString,QString)), &m_textEdit, SLOT(handleOutput(QString,QString))); connect(&m_textEdit, SIGNAL(executeCommand(QString)), m_adapter, SLOT(executeCommand(QString))); + connect(&m_stepIAction, SIGNAL(triggered()), this, SLOT(executeStepICommand())); + connect(&m_stepAction, SIGNAL(triggered()), + this, SLOT(executeStepCommand())); + connect(&m_disassIAction, SIGNAL(triggered()), + this, SLOT(executeDisassICommand())); +} + +void RunnerGui::executeStepCommand() +{ + //m_adapter->executeCommand("stepi"); + m_adapter->executeCommand("-exec-step"); } void RunnerGui::executeStepICommand() { - m_adapter->executeCommand("stepi"); + //m_adapter->executeCommand("stepi"); + m_adapter->executeCommand("-exec-step-instruction"); +} + +void RunnerGui::executeDisassICommand() +{ + m_adapter->executeCommand("disass $pc $pc+4"); } /////////////////////////////////////////////////////////////////////// From f1c881c4e08af3949bfd438e9d9b5c29012ab9d8 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 8 Sep 2009 14:13:50 +0200 Subject: [PATCH 14/23] cache_valuemap doesn't have to be a member any more --- src/shared/proparser/profileevaluator.cpp | 5 +++-- src/shared/proparser/profileevaluator.h | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shared/proparser/profileevaluator.cpp b/src/shared/proparser/profileevaluator.cpp index c4718c08495..948ff00cf30 100644 --- a/src/shared/proparser/profileevaluator.cpp +++ b/src/shared/proparser/profileevaluator.cpp @@ -1139,10 +1139,11 @@ ProItem::ProItemReturn ProFileEvaluator::Private::visitBeginProFile(ProFile * pr } if (!qmake_cache.isEmpty()) { qmake_cache = QDir::cleanPath(qmake_cache); - if (evaluateFileInto(qmake_cache, &m_option->cache_valuemap, 0)) { + QHash cache_valuemap; + if (evaluateFileInto(qmake_cache, &cache_valuemap, 0)) { m_option->cachefile = qmake_cache; if (m_option->qmakespec.isEmpty()) { - const QStringList &vals = m_option->cache_valuemap.value(QLatin1String("QMAKESPEC")); + const QStringList &vals = cache_valuemap.value(QLatin1String("QMAKESPEC")); if (!vals.isEmpty()) m_option->qmakespec = vals.first(); } diff --git a/src/shared/proparser/profileevaluator.h b/src/shared/proparser/profileevaluator.h index cba159c6b8f..691dd78e02b 100644 --- a/src/shared/proparser/profileevaluator.h +++ b/src/shared/proparser/profileevaluator.h @@ -88,8 +88,7 @@ public: friend class ProFileEvaluator; friend class ProFileEvaluator::Private; static QString field_sep; // Just a cache for quick construction - QHash cache_valuemap; // Cached results of .qmake.cache - QHash base_valuemap; // ~ and qmake.conf and default_pre.prf + QHash base_valuemap; // Cached results of qmake.conf, .qmake.cache & default_pre.prf FunctionDefs base_functions; QStringList feature_roots; }; From 37c5e2ddd32ae3ebad15d7226f2d5387710d65ec Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 8 Sep 2009 14:18:06 +0200 Subject: [PATCH 15/23] revert acd090200 - no crash or even memory corruption reproducible --- src/shared/proparser/profileevaluator.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/shared/proparser/profileevaluator.cpp b/src/shared/proparser/profileevaluator.cpp index 948ff00cf30..7495bcc7bfd 100644 --- a/src/shared/proparser/profileevaluator.cpp +++ b/src/shared/proparser/profileevaluator.cpp @@ -1198,7 +1198,8 @@ ProItem::ProItemReturn ProFileEvaluator::Private::visitBeginProFile(ProFile * pr &m_option->base_valuemap, &m_option->base_functions)) { errorMessage(format("Could not read qmake configuration file %1").arg(spec)); } else { - evaluateFileInto(qmake_cache, &m_option->base_valuemap, 0); + evaluateFileInto(qmake_cache, + &m_option->base_valuemap, &m_option->base_functions); } } From 2513c0a93f2fabbe4a0fad1433d36c8f7c0949d3 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 8 Sep 2009 14:19:34 +0200 Subject: [PATCH 16/23] don't attempt to read qmake cache if there is none evaluating a file (which might not exist) is a bit different than just merging a (possibly empty) map ... --- src/shared/proparser/profileevaluator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shared/proparser/profileevaluator.cpp b/src/shared/proparser/profileevaluator.cpp index 7495bcc7bfd..d536a03ef0f 100644 --- a/src/shared/proparser/profileevaluator.cpp +++ b/src/shared/proparser/profileevaluator.cpp @@ -1197,8 +1197,8 @@ ProItem::ProItemReturn ProFileEvaluator::Private::visitBeginProFile(ProFile * pr if (!evaluateFileInto(spec, &m_option->base_valuemap, &m_option->base_functions)) { errorMessage(format("Could not read qmake configuration file %1").arg(spec)); - } else { - evaluateFileInto(qmake_cache, + } else if (!m_option->cachefile.isEmpty()) { + evaluateFileInto(m_option->cachefile, &m_option->base_valuemap, &m_option->base_functions); } } From 5d26f533688cca90914c335f26ee6112c6cd292f Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 9 Sep 2009 11:46:18 +0200 Subject: [PATCH 17/23] trk: progress in breakpoint setting; removal of unused code --- tests/manual/trk/runner.cpp | 254 +++++++++++++----------------------- tests/manual/trk/trkutils.h | 2 +- 2 files changed, 91 insertions(+), 165 deletions(-) diff --git a/tests/manual/trk/runner.cpp b/tests/manual/trk/runner.cpp index 9d2d719d88d..bf55d0b6f40 100755 --- a/tests/manual/trk/runner.cpp +++ b/tests/manual/trk/runner.cpp @@ -141,7 +141,6 @@ public: 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; } @@ -167,7 +166,7 @@ private: void sendOutput(QObject *sender, const QString &data); void sendOutput(const QString &data) { sendOutput(0, data); } - QString m_trkServerName; // + QString m_rfcommDevice; // /dev/rfcomm0 QString m_gdbServerName; // 127.0.0.1:(2222+uid) QProcess m_gdbProc; @@ -178,7 +177,6 @@ public: // // TRK // - bool openTrkPort(const QString &port, QString *errorMessage); void sendTrkMessage(byte code, TrkCallback callback = TrkCallback(), const QByteArray &data = QByteArray(), @@ -187,17 +185,12 @@ public: Q_SLOT void handleTrkError(const QString &msg); // convenience messages - 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); @@ -218,8 +211,6 @@ public: void reportReadMemoryBuffered(const TrkResult &result); void reportToGdb(const TrkResult &result); - void clearTrkBreakpoint(const Breakpoint &bp); - // set breakpoints behind gdb's back void setTrkBreakpoint(const Breakpoint &bp); void handleSetTrkBreakpoint(const TrkResult &result); @@ -296,11 +287,9 @@ Adapter::Adapter() m_gdbAckMode = true; m_verbose = 2; m_registerEndianness = LittleEndian; - //m_serialFrame = true; m_serialFrame = false; m_bufferedMemoryRead = true; - //m_bufferedMemoryRead = false; - m_trkServerName = "/dev/rfcomm0"; + m_rfcommDevice = "/dev/rfcomm0"; uid_t userId = getuid(); m_gdbServerName = QString("127.0.0.1:%1").arg(2222 + userId); @@ -319,6 +308,10 @@ Adapter::Adapter() connect(&m_rfcommProc, SIGNAL(readyReadStandardOutput()), this, SLOT(handleRfcommReadyReadStandardOutput())); + if (m_verbose > 1) + m_trkDevice.setVerbose(true); + m_trkDevice.setSerialFrame(m_serialFrame); + connect(&m_trkDevice, SIGNAL(logMessage(QString)), this, SLOT(trkLogMessage(QString))); } @@ -388,8 +381,7 @@ QByteArray Adapter::trkReadMemoryMessage(uint addr, uint len) void Adapter::startInferior() { QString errorMessage; - if (!openTrkPort(m_trkServerName, &errorMessage)) { - logMessage(errorMessage, true); + if (!m_trkDevice.open(m_rfcommDevice, &errorMessage)) { logMessage("LOOPING"); QTimer::singleShot(1000, this, SLOT(startInferior())); return; @@ -800,7 +792,7 @@ void Adapter::handleGdbServerCommand(const QByteArray &cmd) else sendGdbServerMessage( "PacketSize=7cf;" - //"QPassSignals+;" + "QPassSignals+;" "qXfer:libraries:read+;" //"qXfer:auxv:read+;" "qXfer:features:read+"); @@ -872,8 +864,8 @@ void Adapter::handleGdbServerCommand(const QByteArray &cmd) else if (cmd == "vCont?") { // actions supported by the vCont packet sendGdbServerAck(); - sendGdbServerMessage("OK"); // we don't support vCont. - //sendGdbServerMessage("vCont;c"); + //sendGdbServerMessage("OK"); // we don't support vCont. + sendGdbServerMessage("vCont;c;C;s;S"); } else if (cmd == "vCont;c") { @@ -899,10 +891,10 @@ void Adapter::handleGdbServerCommand(const QByteArray &cmd) } else if (cmd.startsWith("Z0,") || cmd.startsWith("Z1,")) { + sendGdbServerAck(); // Insert breakpoint - if (m_verbose) - logMessage(msgGdbPacket(QLatin1String("Insert breakpoint"))); - // $z0,786a4ccc,4#99 + logMessage(msgGdbPacket(QLatin1String("Insert breakpoint"))); + // $Z0,786a4ccc,4#99 const int pos = cmd.lastIndexOf(','); bool ok = false; const uint addr = cmd.mid(3, pos - 3).toInt(&ok, 16); @@ -923,14 +915,40 @@ void Adapter::handleGdbServerCommand(const QByteArray &cmd) // [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 = trkBreakpointMessage(addr, len, m_session.pid); - sendTrkMessage(0x1B, TrkCB(handleAndReportSetBreakpoint), ba); - //m_session.toekn - + sendTrkMessage(0x1B, TrkCB(handleAndReportSetBreakpoint), ba, addr); //---TRK------------------------------------------------------ // Command: 0x80 Acknowledge // Error: 0x00 // [80 09 00 00 00 00 0A] - } else if (cmd.startsWith("qPart:") || cmd.startsWith("qXfer:")) { + } + + else if (cmd.startsWith("z0,") || cmd.startsWith("z1,")) { + sendGdbServerAck(); + // Remove breakpoint + logMessage(msgGdbPacket(QLatin1String("Remove breakpoint"))); + // $z0,786a4ccc,4#99 + const int pos = cmd.lastIndexOf(','); + bool ok = false; + const uint addr = cmd.mid(3, pos - 3).toInt(&ok, 16); + const uint len = cmd.mid(pos + 1).toInt(&ok, 16); + const uint bp = m_session.addressToBP[addr]; + if (bp == 0) { + logMessage(QString::fromLatin1("NO RECORDED BP AT 0x%1, %2") + .arg(addr, 0, 16).arg(len)); + } else { + //---IDE------------------------------------------------------ + // Command: 0x1C Clear Break + // [1C 25 00 00 00 0A 78 6A 43 40] + m_session.addressToBP.remove(addr); + QByteArray ba; + appendByte(&ba, 0x00); + appendShort(&ba, bp); + appendInt(&ba, addr); + sendTrkMessage(0x1C, TrkCB(handleClearBreakpoint), ba, addr); + } + } + + else if (cmd.startsWith("qPart:") || cmd.startsWith("qXfer:")) { QByteArray data = cmd.mid(1 + cmd.indexOf(':')); // "qPart:auxv:read::0,147": Read OS auxiliary data (see info aux) bool handled = false; @@ -981,30 +999,12 @@ void Adapter::executeCommand(const QString &msg) } } -bool Adapter::openTrkPort(const QString &port, QString *errorMessage) -{ - connect(&m_trkDevice, SIGNAL(messageReceived(trk::TrkResult)), - this, SLOT(handleTrkResult(trk::TrkResult))); - connect(&m_trkDevice, SIGNAL(error(QString)), - this, SLOT(handleTrkError(QString))); - if (m_verbose > 1) - m_trkDevice.setVerbose(true); - m_trkDevice.setSerialFrame(m_serialFrame); - return m_trkDevice.open(port, errorMessage); -} - void Adapter::sendTrkMessage(byte code, TrkCallback callback, const QByteArray &data, const QVariant &cookie) { m_trkDevice.sendTrkMessage(code, callback, data, cookie); } -void Adapter::waitForTrkFinished() -{ - // initiate one last roundtrip to ensure all is flushed - sendTrkMessage(0x0, TrkCB(handleWaitForFinished)); -} - void Adapter::sendTrkAck(byte token) { logMessage(QString("SENDING ACKNOWLEDGEMENT FOR TOKEN %1").arg(int(token))); @@ -1398,31 +1398,27 @@ void Adapter::handleAndReportSetBreakpoint(const TrkResult &result) // Error: 0x00 // [80 09 00 00 00 00 0A] uint bpnr = extractByte(result.data.data()); + uint addr = result.cookie.toUInt(); + m_session.addressToBP[addr] = bpnr; logMessage("SET BREAKPOINT " + hexxNumber(bpnr) + " " + stringFromArray(result.data.data())); sendGdbServerMessage("OK"); -} - -void Adapter::clearTrkBreakpoint(const Breakpoint &bp) -{ - //---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, TrkCB(handleClearBreakpoint), ba); + //sendGdbServerMessage("OK"); } void Adapter::handleClearBreakpoint(const TrkResult &result) { - Q_UNUSED(result); + logMessage("CLEAR BREAKPOINT "); + if (result.errorCode()) { + logMessage("ERROR: " + result.errorString()); + //return; + } //---TRK------------------------------------------------------ // Command: 0x80 Acknowledge // Error: 0x00 // [80 09 00 00 00 00 0A] - logMessage("CLEAR BREAKPOINT "); + // FIXME: + sendGdbServerMessage("OK"); } void Adapter::handleSignalContinue(const TrkResult &result) @@ -1434,12 +1430,6 @@ void Adapter::handleSignalContinue(const TrkResult &result) sendGdbServerMessage("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(); @@ -1472,68 +1462,6 @@ 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, TrkCallback(), ba, "Delete process"); - - //---TRK------------------------------------------------------ - // Command: 0x80 Acknowledge - // Error: 0x00 - // [80 24 00] - - //foreach (const Breakpoint &bp, m_breakpoints) - // clearTrkBreakpoint(bp); - - sendTrkMessage(0x02, TrkCB(handleDisconnect)); - //---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, TrkCB(handleDisconnect)); - //---TRK------------------------------------------------------ - // Command: 0x80 Acknowledge - // Error: 0x00 -} - void Adapter::readMemory(uint addr, uint len) { Q_ASSERT(len < (2 << 16)); @@ -1622,9 +1550,16 @@ void Adapter::handleProcStateChanged(QProcess::ProcessState newState) void Adapter::run() { - startInferior(); sendOutput("### Starting Adapter"); - m_rfcommProc.start("rfcomm listen /dev/rfcomm0 1"); + m_rfcommProc.start("rfcomm listen " + m_rfcommDevice + " 1"); + m_rfcommProc.waitForStarted(); + + connect(&m_trkDevice, SIGNAL(messageReceived(trk::TrkResult)), + this, SLOT(handleTrkResult(trk::TrkResult))); + connect(&m_trkDevice, SIGNAL(error(QString)), + this, SLOT(handleTrkError(QString))); + + startInferior(); } void Adapter::startGdb() @@ -1710,7 +1645,7 @@ void Adapter::sendGdbMessage(const QString &msg, GdbCallback callback, data.command = msg; data.callback = callback; data.cookie = cookie; - m_gdbCookieForToken[++token] = data; + m_gdbCookieForToken[token] = data; logMessage(QString("<- GDB: %1 %2").arg(token).arg(msg)); m_gdbProc.write(QString("%1%2\n").arg(token).arg(msg).toLatin1()); } @@ -1860,64 +1795,55 @@ public: RunnerGui(Adapter *adapter); private slots: - void executeStepICommand(); - void executeStepCommand(); - void executeDisassICommand(); + void executeStepICommand() { executeCommand("-exec-step-instruction"); } + void executeStepCommand() { executeCommand("-exec-step"); } + void executeNextICommand() { executeCommand("-exec-next-instruction"); } + void executeNextCommand() { executeCommand("-exec-next"); } + void executeContinueCommand() { executeCommand("-exec-continue"); } + void executeDisassICommand() { executeCommand("disass $pc $pc+4"); } private: + void executeCommand(const QString &cmd) { m_adapter->executeCommand(cmd); } + void connectAction(QAction *&, QString name, const char *slot); + Adapter *m_adapter; TextEdit m_textEdit; QToolBar m_toolBar; - QAction m_stepIAction; - QAction m_stepAction; - QAction m_disassIAction; + QAction *m_stepIAction; + QAction *m_stepAction; + QAction *m_nextIAction; + QAction *m_nextAction; + QAction *m_disassIAction; + QAction *m_continueAction; }; RunnerGui::RunnerGui(Adapter *adapter) - : m_adapter(adapter), - m_stepIAction(0), - m_stepAction(0), - m_disassIAction(0) + : m_adapter(adapter) { resize(1200, 1000); setCentralWidget(&m_textEdit); addToolBar(&m_toolBar); - m_stepIAction.setText("StepI"); - m_disassIAction.setText("DisassI"); - m_toolBar.addAction(&m_stepIAction); - m_toolBar.addAction(&m_stepAction); - m_toolBar.addAction(&m_disassIAction); + connectAction(m_stepIAction, "Step Inst", SLOT(executeStepICommand())); + connectAction(m_stepAction, "Step", SLOT(executeStepCommand())); + connectAction(m_nextIAction, "Next Inst", SLOT(executeNextICommand())); + connectAction(m_nextAction, "Next", SLOT(executeNextCommand())); + connectAction(m_disassIAction, "Disass Inst", SLOT(executeDisassICommand())); + connectAction(m_continueAction, "Continue", SLOT(executeContinueCommand())); connect(adapter, SIGNAL(output(QString,QString)), &m_textEdit, SLOT(handleOutput(QString,QString))); connect(&m_textEdit, SIGNAL(executeCommand(QString)), m_adapter, SLOT(executeCommand(QString))); - - connect(&m_stepIAction, SIGNAL(triggered()), - this, SLOT(executeStepICommand())); - connect(&m_stepAction, SIGNAL(triggered()), - this, SLOT(executeStepCommand())); - connect(&m_disassIAction, SIGNAL(triggered()), - this, SLOT(executeDisassICommand())); } -void RunnerGui::executeStepCommand() +void RunnerGui::connectAction(QAction *&action, QString name, const char *slot) { - //m_adapter->executeCommand("stepi"); - m_adapter->executeCommand("-exec-step"); -} - -void RunnerGui::executeStepICommand() -{ - //m_adapter->executeCommand("stepi"); - m_adapter->executeCommand("-exec-step-instruction"); -} - -void RunnerGui::executeDisassICommand() -{ - m_adapter->executeCommand("disass $pc $pc+4"); + action = new QAction(this); + action->setText(name); + m_toolBar.addAction(action); + connect(action, SIGNAL(triggered()), this, slot); } /////////////////////////////////////////////////////////////////////// diff --git a/tests/manual/trk/trkutils.h b/tests/manual/trk/trkutils.h index 3ed06e3ca4a..7b1709498ce 100644 --- a/tests/manual/trk/trkutils.h +++ b/tests/manual/trk/trkutils.h @@ -144,7 +144,7 @@ struct Session uint tid; uint codeseg; uint dataseg; - QHash tokenToBreakpointIndex; + QHash addressToBP; // Gdb request uint currentThread; From 1614d6b6b85dc0762215f8e812dd68469457acad Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 9 Sep 2009 12:39:15 +0200 Subject: [PATCH 18/23] debugger: small refactoring of the access to the gdb process in the gdbengine That's the first step to make the gdb/trk Adapter work with the otherwise unmodified gdb engine. GdbProcessBase is inherited by GdbProcess and the gdb/trk Adapter. In the GdbProcess case it's just a wrapper around a QProcess running gdb, in the Adapter case it's the interface to the gdb process in the whole rfomm/gdb/gdbserver combo. --- src/plugins/debugger/gdb/gdbengine.cpp | 76 +++++++++++++------------- src/plugins/debugger/gdb/gdbengine.h | 70 +++++++++++++++++++++++- 2 files changed, 107 insertions(+), 39 deletions(-) diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 89669c9df5e..055d8adfdf2 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -144,7 +144,7 @@ static QByteArray parsePlainConsoleStream(const GdbResultRecord &record) // /////////////////////////////////////////////////////////////////////// -GdbEngine::GdbEngine(DebuggerManager *parent) : +GdbEngine::GdbEngine(DebuggerManager *parent, GdbProcessBase *gdbProc) : #ifdef Q_OS_WIN // Do injection loading with MinGW (call loading does not work with 64bit) m_dumperInjectionLoad(true), #else @@ -153,6 +153,7 @@ GdbEngine::GdbEngine(DebuggerManager *parent) : q(parent), qq(parent->engineInterface()) { + m_gdbProc = gdbProc; m_stubProc.setMode(Core::Utils::ConsoleProcess::Debug); #ifdef Q_OS_UNIX m_stubProc.setSettings(Core::ICore::instance()->settings()); @@ -164,19 +165,20 @@ GdbEngine::GdbEngine(DebuggerManager *parent) : GdbEngine::~GdbEngine() { // prevent sending error messages afterwards - m_gdbProc.disconnect(this); + m_gdbProc->disconnect(this); + delete m_gdbProc; } void GdbEngine::initializeConnections() { // Gdb Process interaction - connect(&m_gdbProc, SIGNAL(error(QProcess::ProcessError)), + connect(m_gdbProc, SIGNAL(error(QProcess::ProcessError)), this, SLOT(gdbProcError(QProcess::ProcessError))); - connect(&m_gdbProc, SIGNAL(readyReadStandardOutput()), + connect(m_gdbProc, SIGNAL(readyReadStandardOutput()), this, SLOT(readGdbStandardOutput())); - connect(&m_gdbProc, SIGNAL(readyReadStandardError()), + connect(m_gdbProc, SIGNAL(readyReadStandardError()), this, SLOT(readGdbStandardError())); - connect(&m_gdbProc, SIGNAL(finished(int, QProcess::ExitStatus)), + connect(m_gdbProc, SIGNAL(finished(int, QProcess::ExitStatus)), q, SLOT(exitDebugger())); connect(&m_stubProc, SIGNAL(processError(QString)), @@ -614,7 +616,7 @@ void GdbEngine::stubError(const QString &msg) void GdbEngine::readGdbStandardError() { - qWarning() << "Unexpected gdb stderr:" << m_gdbProc.readAllStandardError(); + qWarning() << "Unexpected gdb stderr:" << m_gdbProc->readAllStandardError(); } void GdbEngine::readGdbStandardOutput() @@ -622,7 +624,7 @@ void GdbEngine::readGdbStandardOutput() int newstart = 0; int scan = m_inbuffer.size(); - m_inbuffer.append(m_gdbProc.readAllStandardOutput()); + m_inbuffer.append(m_gdbProc->readAllStandardOutput()); while (newstart < m_inbuffer.size()) { int start = newstart; @@ -651,7 +653,7 @@ void GdbEngine::interruptInferior() { qq->notifyInferiorStopRequested(); - if (m_gdbProc.state() == QProcess::NotRunning) { + if (m_gdbProc->state() == QProcess::NotRunning) { debugMessage(_("TRYING TO INTERRUPT INFERIOR WITHOUT RUNNING GDB")); qq->notifyInferiorExited(); return; @@ -698,7 +700,7 @@ void GdbEngine::postCommand(const QString &command, GdbCommandFlags flags, GdbCommandCallback callback, const char *callbackName, const QVariant &cookie) { - if (m_gdbProc.state() == QProcess::NotRunning) { + if (m_gdbProc->state() == QProcess::NotRunning) { debugMessage(_("NO GDB PROCESS RUNNING, CMD IGNORED: ") + command); return; } @@ -742,7 +744,7 @@ void GdbEngine::flushCommand(GdbCommand &cmd) if (cmd.flags & EmbedToken) cmd.command = cmd.command.arg(currentToken()); - m_gdbProc.write(cmd.command.toLatin1() + "\r\n"); + m_gdbProc->write(cmd.command.toLatin1() + "\r\n"); //emit gdbInputAvailable(QString(), " " + currentTime()); //emit gdbInputAvailable(QString(), "[" + currentTime() + "] " + cmd.command); emit gdbInputAvailable(LogInput, cmd.command); @@ -829,12 +831,12 @@ void GdbEngine::handleResultRecord(const GdbResultRecord &record) void GdbEngine::executeDebuggerCommand(const QString &command) { - if (m_gdbProc.state() == QProcess::NotRunning) { + if (m_gdbProc->state() == QProcess::NotRunning) { debugMessage(_("NO GDB PROCESS RUNNING, PLAIN CMD IGNORED: ") + command); return; } - m_gdbProc.write(command.toLocal8Bit() + "\r\n"); + m_gdbProc->write(command.toLocal8Bit() + "\r\n"); } void GdbEngine::handleTargetCore(const GdbResultRecord &, const QVariant &) @@ -1434,15 +1436,15 @@ void GdbEngine::detachDebugger() void GdbEngine::exitDebugger() { - debugMessage(_("GDBENGINE EXITDEBUGGER: %1").arg(m_gdbProc.state())); - if (m_gdbProc.state() == QProcess::Starting) { + debugMessage(_("GDBENGINE EXITDEBUGGER: %1").arg(m_gdbProc->state())); + if (m_gdbProc->state() == QProcess::Starting) { debugMessage(_("WAITING FOR GDB STARTUP TO SHUTDOWN: %1") - .arg(m_gdbProc.state())); - m_gdbProc.waitForStarted(); + .arg(m_gdbProc->state())); + m_gdbProc->waitForStarted(); } - if (m_gdbProc.state() == QProcess::Running) { + if (m_gdbProc->state() == QProcess::Running) { debugMessage(_("WAITING FOR RUNNING GDB TO SHUTDOWN: %1") - .arg(m_gdbProc.state())); + .arg(m_gdbProc->state())); if (q->status() != DebuggerInferiorStopped && q->status() != DebuggerProcessStartingUp) { QTC_ASSERT(q->status() == DebuggerInferiorRunning, @@ -1455,17 +1457,17 @@ void GdbEngine::exitDebugger() postCommand(_("kill")); postCommand(_("-gdb-exit"), CB(handleExit)); // 20s can easily happen when loading webkit debug information - if (!m_gdbProc.waitForFinished(20000)) { + if (!m_gdbProc->waitForFinished(20000)) { debugMessage(_("FORCING TERMINATION: %1") - .arg(m_gdbProc.state())); - m_gdbProc.terminate(); - m_gdbProc.waitForFinished(20000); + .arg(m_gdbProc->state())); + m_gdbProc->terminate(); + m_gdbProc->waitForFinished(20000); } } - if (m_gdbProc.state() != QProcess::NotRunning) { + if (m_gdbProc->state() != QProcess::NotRunning) { debugMessage(_("PROBLEM STOPPING DEBUGGER: STATE %1") - .arg(m_gdbProc.state())); - m_gdbProc.kill(); + .arg(m_gdbProc->state())); + m_gdbProc->kill(); } m_outputCollector.shutdown(); @@ -1487,9 +1489,9 @@ bool GdbEngine::startDebugger(const QSharedPointer &sp) QStringList gdbArgs; - if (m_gdbProc.state() != QProcess::NotRunning) { - debugMessage(_("GDB IS ALREADY RUNNING, STATE: %1").arg(m_gdbProc.state())); - m_gdbProc.kill(); + if (m_gdbProc->state() != QProcess::NotRunning) { + debugMessage(_("GDB IS ALREADY RUNNING, STATE: %1").arg(m_gdbProc->state())); + m_gdbProc->kill(); return false; } @@ -1529,16 +1531,16 @@ bool GdbEngine::startDebugger(const QSharedPointer &sp) gdbArgs.prepend(_("--tty=") + m_outputCollector.serverName()); if (!sp->workingDir.isEmpty()) - m_gdbProc.setWorkingDirectory(sp->workingDir); + m_gdbProc->setWorkingDirectory(sp->workingDir); if (!sp->environment.isEmpty()) - m_gdbProc.setEnvironment(sp->environment); + m_gdbProc->setEnvironment(sp->environment); } #if 0 qDebug() << "Command:" << q->settings()->m_gdbCmd; - qDebug() << "WorkingDirectory:" << m_gdbProc.workingDirectory(); + qDebug() << "WorkingDirectory:" << m_gdbProc->workingDirectory(); qDebug() << "ScriptFile:" << q->settings()->m_scriptFile; - qDebug() << "Environment:" << m_gdbProc.environment(); + qDebug() << "Environment:" << m_gdbProc->environment(); qDebug() << "Arguments:" << gdbArgs; qDebug() << "BuildDir:" << sp->buildDir; qDebug() << "ExeFile:" << sp->executable; @@ -1546,10 +1548,10 @@ bool GdbEngine::startDebugger(const QSharedPointer &sp) QString loc = theDebuggerStringSetting(GdbLocation); q->showStatusMessage(tr("Starting Debugger: ") + loc + _c(' ') + gdbArgs.join(_(" "))); - m_gdbProc.start(loc, gdbArgs); - if (!m_gdbProc.waitForStarted()) { + m_gdbProc->start(loc, gdbArgs); + if (!m_gdbProc->waitForStarted()) { QMessageBox::critical(q->mainWindow(), tr("Debugger Startup Failure"), - tr("Cannot start debugger: %1").arg(m_gdbProc.errorString())); + tr("Cannot start debugger: %1").arg(m_gdbProc->errorString())); m_outputCollector.shutdown(); m_stubProc.blockSignals(true); m_stubProc.stop(); @@ -4198,7 +4200,7 @@ void GdbEngine::handleFetchDisassemblerByAddress0(const GdbResultRecord &record, IDebuggerEngine *createGdbEngine(DebuggerManager *parent, QList *opts) { opts->push_back(new GdbOptionsPage); - return new GdbEngine(parent); + return new GdbEngine(parent, new GdbProcess); } } // namespace Internal diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index 2694ec01fbd..60af08ae3cc 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -56,6 +56,7 @@ QT_END_NAMESPACE namespace Debugger { namespace Internal { + class DebuggerManager; class IDebuggerManagerAccessForEngines; class GdbResultRecord; @@ -72,13 +73,78 @@ enum DebuggingHelperState DebuggingHelperUnavailable, }; +// GdbProcessBase is inherited by GdbProcess and the gdb/trk Adapter. +// In the GdbProcess case it's just a wrapper around a QProcess running +// gdb, in the Adapter case it's the interface to the gdb process in +// the whole rfomm/gdb/gdbserver combo. +class GdbProcessBase : public QObject +{ + Q_OBJECT + +public: + GdbProcessBase(QObject *parent) : QObject(parent) {} + + virtual void start(const QString &program, const QStringList &args, + QIODevice::OpenMode mode = QIODevice::ReadWrite) = 0; + virtual void kill() = 0; + virtual void terminate() = 0; + virtual bool waitForStarted(int msecs = 30000) = 0; + virtual bool waitForFinished(int msecs = 30000) = 0; + virtual QProcess::ProcessState state() const = 0; + virtual QString errorString() const = 0; + virtual QByteArray readAllStandardError() = 0; + virtual QByteArray readAllStandardOutput() = 0; + virtual qint64 write(const char *data) = 0; + virtual void setWorkingDirectory(const QString &dir) = 0; + virtual void setEnvironment(const QStringList &env) = 0; + +signals: + void error(QProcess::ProcessError); + void readyReadStandardOutput(); + void readyReadStandardError(); + void finished(int, QProcess::ExitStatus); +}; + +class GdbProcess : public GdbProcessBase +{ +public: + GdbProcess(QObject *parent = 0) + : GdbProcessBase(parent) + { + connect(&m_proc, SIGNAL(error(QProcess::ProcessError)), + this, SIGNAL(error(QProcess::ProcessError))); + connect(&m_proc, SIGNAL(readyReadStandardOutput()), + this, SIGNAL(readyReadStandardOutput())); + connect(&m_proc, SIGNAL(readyReadStandardError()), + this, SIGNAL(readyReadStandardError())); + connect(&m_proc, SIGNAL(finished(int, QProcess::ExitStatus)), + this, SIGNAL(finished(int, QProcess::ExitStatus))); + } + + void start(const QString &program, const QStringList &args, + QIODevice::OpenMode mode) { m_proc.start(program, args, mode); } + void kill() { m_proc.kill(); } + void terminate() { m_proc.terminate(); } + bool waitForStarted(int msecs) { return m_proc.waitForStarted(msecs); } + bool waitForFinished(int msecs) { return m_proc.waitForFinished(msecs); } + QProcess::ProcessState state() const { return m_proc.state(); } + QString errorString() const { return m_proc.errorString(); } + QByteArray readAllStandardError() { return m_proc.readAllStandardError(); } + QByteArray readAllStandardOutput() { return m_proc.readAllStandardOutput(); } + qint64 write(const char *data) { return m_proc.write(data); } + void setWorkingDirectory(const QString &dir) { m_proc.setWorkingDirectory(dir); } + void setEnvironment(const QStringList &env) { m_proc.setEnvironment(env); } + +private: + QProcess m_proc; +}; class GdbEngine : public IDebuggerEngine { Q_OBJECT public: - GdbEngine(DebuggerManager *parent); + GdbEngine(DebuggerManager *parent, GdbProcessBase *gdbProc); ~GdbEngine(); signals: @@ -251,7 +317,7 @@ private: QByteArray m_inbuffer; - QProcess m_gdbProc; + GdbProcessBase *m_gdbProc; QProcess m_uploadProc; Core::Utils::ConsoleProcess m_stubProc; From f269031b5e147106eb1cea54c2ee390cb072bebe Mon Sep 17 00:00:00 2001 From: mae Date: Wed, 9 Sep 2009 13:55:11 +0200 Subject: [PATCH 19/23] Make indentation/tabbing more developer friendly: - when doing backspace, preserve the previous indentation litterally - when having auto-indentation turned off, simply repeat the previous indentation litterally instead of jumping to 0 --- src/plugins/texteditor/basetexteditor.cpp | 22 ++++++++++++---------- src/plugins/texteditor/tabsettings.cpp | 6 ++++++ src/plugins/texteditor/tabsettings.h | 1 + 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp index 59c55fcb2d4..a675ea4e8bc 100644 --- a/src/plugins/texteditor/basetexteditor.cpp +++ b/src/plugins/texteditor/basetexteditor.cpp @@ -887,13 +887,18 @@ void BaseTextEditor::keyPressEvent(QKeyEvent *e) QTextCursor cursor = textCursor(); if (d->m_inBlockSelectionMode) cursor.clearSelection(); - if (d->m_document->tabSettings().m_autoIndent) { + const TabSettings &ts = d->m_document->tabSettings(); + if (ts.m_autoIndent) { cursor.beginEditBlock(); cursor.insertBlock(); indent(document(), cursor, QChar::Null); cursor.endEditBlock(); } else { + cursor.beginEditBlock(); + QString previousBlockText = cursor.block().text(); cursor.insertBlock(); + cursor.insertText(ts.indentationString(previousBlockText)); + cursor.endEditBlock(); } e->accept(); setTextCursor(cursor); @@ -3189,17 +3194,14 @@ void BaseTextEditor::handleBackspaceKey() continue; previousIndent = tabSettings.columnAt(previousNonEmptyBlockText, tabSettings.firstNonSpace(previousNonEmptyBlockText)); - if (previousIndent < indent) + if (previousIndent < indent) { + cursor.beginEditBlock(); + cursor.setPosition(currentBlock.position(), QTextCursor::KeepAnchor); + cursor.insertText(tabSettings.indentationString(previousNonEmptyBlockText)); + cursor.endEditBlock(); break; + } } - - if (previousIndent >= indent) - previousIndent = 0; - - cursor.beginEditBlock(); - cursor.setPosition(currentBlock.position(), QTextCursor::KeepAnchor); - cursor.insertText(tabSettings.indentationString(0, previousIndent)); - cursor.endEditBlock(); } void BaseTextEditor::wheelEvent(QWheelEvent *e) diff --git a/src/plugins/texteditor/tabsettings.cpp b/src/plugins/texteditor/tabsettings.cpp index e0225ce8bcd..1c20ab7b904 100644 --- a/src/plugins/texteditor/tabsettings.cpp +++ b/src/plugins/texteditor/tabsettings.cpp @@ -110,6 +110,12 @@ int TabSettings::firstNonSpace(const QString &text) const return i; } +QString TabSettings::indentationString(const QString &text) const +{ + return text.left(firstNonSpace(text)); +} + + int TabSettings::trailingWhitespaces(const QString &text) const { int i = 0; diff --git a/src/plugins/texteditor/tabsettings.h b/src/plugins/texteditor/tabsettings.h index ec2c3dfe8ea..2fbede49502 100644 --- a/src/plugins/texteditor/tabsettings.h +++ b/src/plugins/texteditor/tabsettings.h @@ -63,6 +63,7 @@ struct TEXTEDITOR_EXPORT TabSettings int spacesLeftFromPosition(const QString &text, int position) const; int indentedColumn(int column, bool doIndent = true) const; QString indentationString(int startColumn, int targetColumn) const; + QString indentationString(const QString &text) const; void indentLine(QTextBlock block, int newIndent) const; From 32229e30b49f08b7f0b11f7ceae0fd0b78e46af2 Mon Sep 17 00:00:00 2001 From: mae Date: Wed, 9 Sep 2009 14:58:47 +0200 Subject: [PATCH 20/23] mark all-whitespace-lines with the correct visual format. --- src/plugins/cppeditor/cpphighlighter.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/cppeditor/cpphighlighter.cpp b/src/plugins/cppeditor/cpphighlighter.cpp index 95e25b4b257..d2cda6f77df 100644 --- a/src/plugins/cppeditor/cpphighlighter.cpp +++ b/src/plugins/cppeditor/cpphighlighter.cpp @@ -73,6 +73,8 @@ void CppHighlighter::highlightBlock(const QString &text) userData->setCollapseMode(TextBlockUserData::NoCollapse); } TextEditDocumentLayout::clearParentheses(currentBlock()); + if (text.length()) // the empty line can still contain whitespace + setFormat(0, text.length(), visualSpaceFormat); return; } @@ -171,7 +173,7 @@ void CppHighlighter::highlightBlock(const QString &text) } // mark the trailing white spaces - if (! tokens.isEmpty()) { + { const SimpleToken tk = tokens.last(); const int lastTokenEnd = tk.position() + tk.length(); if (text.length() > lastTokenEnd) From 16e7f0c16f57e984310cd1bba838a69221f4a18a Mon Sep 17 00:00:00 2001 From: mae Date: Wed, 9 Sep 2009 16:16:46 +0200 Subject: [PATCH 21/23] be more conservative when reindenting code: only change the actual whitespace when the indentation column changes. Complete whitespace cleanup can still be done either automatically on save (when configured) or when explicitely called with the "Clean Whitespace" action from Edit/Advanced. --- src/plugins/texteditor/basetextdocument.cpp | 11 +++++------ src/plugins/texteditor/basetextdocument.h | 2 +- src/plugins/texteditor/tabsettings.cpp | 14 +++++++------- src/plugins/texteditor/tabsettings.h | 1 + 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/plugins/texteditor/basetextdocument.cpp b/src/plugins/texteditor/basetextdocument.cpp index 8de81100d8c..b2b0e75eeea 100644 --- a/src/plugins/texteditor/basetextdocument.cpp +++ b/src/plugins/texteditor/basetextdocument.cpp @@ -93,7 +93,7 @@ bool BaseTextDocument::save(const QString &fileName) cursor.beginEditBlock(); if (m_storageSettings.m_cleanWhitespace) - cleanWhitespace(cursor, m_storageSettings.m_inEntireDocument); + cleanWhitespace(cursor, m_storageSettings.m_cleanIndentation, m_storageSettings.m_inEntireDocument); if (m_storageSettings.m_addFinalNewLine) ensureFinalNewLine(cursor); cursor.endEditBlock(); @@ -305,13 +305,12 @@ void BaseTextDocument::cleanWhitespace() { QTextCursor cursor(m_document); cursor.beginEditBlock(); - cleanWhitespace(cursor, true); - if (m_storageSettings.m_addFinalNewLine) - ensureFinalNewLine(cursor); + cleanWhitespace(cursor, true, true); + ensureFinalNewLine(cursor); cursor.endEditBlock(); } -void BaseTextDocument::cleanWhitespace(QTextCursor& cursor, bool inEntireDocument) +void BaseTextDocument::cleanWhitespace(QTextCursor& cursor, bool cleanIndentation, bool inEntireDocument) { TextEditDocumentLayout *documentLayout = qobject_cast(m_document->documentLayout()); @@ -327,7 +326,7 @@ void BaseTextDocument::cleanWhitespace(QTextCursor& cursor, bool inEntireDocumen cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor, trailing); cursor.removeSelectedText(); } - if (m_storageSettings.m_cleanIndentation && !m_tabSettings.isIndentationClean(blockText)) { + if (cleanIndentation && !m_tabSettings.isIndentationClean(blockText)) { cursor.setPosition(block.position()); int firstNonSpace = m_tabSettings.firstNonSpace(blockText); if (firstNonSpace == blockText.length()) { diff --git a/src/plugins/texteditor/basetextdocument.h b/src/plugins/texteditor/basetextdocument.h index 88e1c609a13..24dabd7a0aa 100644 --- a/src/plugins/texteditor/basetextdocument.h +++ b/src/plugins/texteditor/basetextdocument.h @@ -146,7 +146,7 @@ private: bool m_hasDecodingError; QByteArray m_decodingErrorSample; - void cleanWhitespace(QTextCursor& cursor, bool onlyInModifiedLines); + void cleanWhitespace(QTextCursor& cursor, bool cleanIndentation, bool inEntireDocument); void ensureFinalNewLine(QTextCursor& cursor); }; diff --git a/src/plugins/texteditor/tabsettings.cpp b/src/plugins/texteditor/tabsettings.cpp index 1c20ab7b904..393434d9085 100644 --- a/src/plugins/texteditor/tabsettings.cpp +++ b/src/plugins/texteditor/tabsettings.cpp @@ -116,6 +116,12 @@ QString TabSettings::indentationString(const QString &text) const } +int TabSettings::indentationColumn(const QString &text) const +{ + return columnAt(text, firstNonSpace(text)); +} + + int TabSettings::trailingWhitespaces(const QString &text) const { int i = 0; @@ -231,7 +237,7 @@ void TabSettings::indentLine(QTextBlock block, int newIndent) const const int oldBlockLength = text.size(); // Quickly check whether indenting is required. - if (oldBlockLength == 0 && newIndent == 0) + if (indentationColumn(text) == newIndent) return; const QString indentString = indentationString(0, newIndent); @@ -240,12 +246,6 @@ void TabSettings::indentLine(QTextBlock block, int newIndent) const if (oldBlockLength == indentString.length() && text == indentString) return; - if (oldBlockLength > indentString.length() && - text.startsWith(indentString) && - !text.at(indentString.length()).isSpace()) { - return; - } - QTextCursor cursor(block); cursor.beginEditBlock(); cursor.movePosition(QTextCursor::StartOfBlock); diff --git a/src/plugins/texteditor/tabsettings.h b/src/plugins/texteditor/tabsettings.h index 2fbede49502..f26e0bb5ad9 100644 --- a/src/plugins/texteditor/tabsettings.h +++ b/src/plugins/texteditor/tabsettings.h @@ -64,6 +64,7 @@ struct TEXTEDITOR_EXPORT TabSettings int indentedColumn(int column, bool doIndent = true) const; QString indentationString(int startColumn, int targetColumn) const; QString indentationString(const QString &text) const; + int indentationColumn(const QString &text) const; void indentLine(QTextBlock block, int newIndent) const; From 99435d5f0e2f6993df22965b38564cd73e3409f1 Mon Sep 17 00:00:00 2001 From: mae Date: Wed, 9 Sep 2009 16:37:09 +0200 Subject: [PATCH 22/23] Make "Edit/Advanced/Clean_Whitespace work on the current selection (if there is one) --- src/plugins/texteditor/basetextdocument.cpp | 22 +++++++++++++-------- src/plugins/texteditor/basetextdocument.h | 2 +- src/plugins/texteditor/basetexteditor.cpp | 2 +- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/plugins/texteditor/basetextdocument.cpp b/src/plugins/texteditor/basetextdocument.cpp index b2b0e75eeea..6da82ccdf59 100644 --- a/src/plugins/texteditor/basetextdocument.cpp +++ b/src/plugins/texteditor/basetextdocument.cpp @@ -301,13 +301,15 @@ void BaseTextDocument::setSyntaxHighlighter(QSyntaxHighlighter *highlighter) -void BaseTextDocument::cleanWhitespace() +void BaseTextDocument::cleanWhitespace(const QTextCursor &cursor) { - QTextCursor cursor(m_document); - cursor.beginEditBlock(); - cleanWhitespace(cursor, true, true); - ensureFinalNewLine(cursor); - cursor.endEditBlock(); + bool hasSelection = cursor.hasSelection(); + QTextCursor copyCursor = cursor; + copyCursor.beginEditBlock(); + cleanWhitespace(copyCursor, true, true); + if (!hasSelection) + ensureFinalNewLine(copyCursor); + copyCursor.endEditBlock(); } void BaseTextDocument::cleanWhitespace(QTextCursor& cursor, bool cleanIndentation, bool inEntireDocument) @@ -315,8 +317,12 @@ void BaseTextDocument::cleanWhitespace(QTextCursor& cursor, bool cleanIndentatio TextEditDocumentLayout *documentLayout = qobject_cast(m_document->documentLayout()); - QTextBlock block = m_document->firstBlock(); - while (block.isValid()) { + QTextBlock block = m_document->findBlock(cursor.selectionStart()); + QTextBlock end; + if (cursor.hasSelection()) + end = m_document->findBlock(cursor.selectionEnd()-1).next(); + + while (block.isValid() && block != end) { if (inEntireDocument || block.revision() > documentLayout->lastSaveRevision) { diff --git a/src/plugins/texteditor/basetextdocument.h b/src/plugins/texteditor/basetextdocument.h index 24dabd7a0aa..eaf37c91caf 100644 --- a/src/plugins/texteditor/basetextdocument.h +++ b/src/plugins/texteditor/basetextdocument.h @@ -110,7 +110,7 @@ public: void reload(QTextCodec *codec); - void cleanWhitespace(); + void cleanWhitespace(const QTextCursor &cursor); signals: void titleChanged(QString title); diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp index a675ea4e8bc..cce27c4c21b 100644 --- a/src/plugins/texteditor/basetexteditor.cpp +++ b/src/plugins/texteditor/basetexteditor.cpp @@ -833,7 +833,7 @@ void BaseTextEditor::moveLineUpDown(bool up) void BaseTextEditor::cleanWhitespace() { - d->m_document->cleanWhitespace(); + d->m_document->cleanWhitespace(textCursor()); } void BaseTextEditor::keyPressEvent(QKeyEvent *e) From ffaa42e5855c6afd6dc0cf98f78e5b9fc4eab4df Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 9 Sep 2009 17:24:21 +0200 Subject: [PATCH 23/23] debugger: merge trk adapter into debugger sources --- src/plugins/debugger/debugger.pro | 2 + src/plugins/debugger/debuggermanager.cpp | 2 + src/plugins/debugger/gdb/gdbengine.h | 33 +- src/plugins/debugger/gdb/gdbprocessbase.h | 74 + src/plugins/debugger/symbian/symbian.pri | 14 + .../debugger/symbian/symbianadapter.cpp | 1599 ++++++++++++++++ src/plugins/debugger/symbian/symbianadapter.h | 247 +++ .../debugger/symbian/symbianengine.cpp | 66 + .../plugins/debugger/symbian/trkclient.cpp | 3 +- .../plugins/debugger/symbian/trkclient.h | 0 .../plugins/debugger/symbian}/trkfunctor.h | 4 +- .../plugins/debugger/symbian}/trkutils.cpp | 0 .../plugins/debugger/symbian}/trkutils.h | 1 - tests/manual/trk/adapter.pro | 18 +- tests/manual/trk/runner.cpp | 1634 +---------------- tests/manual/trk/runner.pro | 16 +- tests/manual/trk/trklauncher.pri | 18 +- tests/manual/trk/trkserver.pro | 11 +- 18 files changed, 2058 insertions(+), 1684 deletions(-) create mode 100644 src/plugins/debugger/gdb/gdbprocessbase.h create mode 100644 src/plugins/debugger/symbian/symbian.pri create mode 100644 src/plugins/debugger/symbian/symbianadapter.cpp create mode 100644 src/plugins/debugger/symbian/symbianadapter.h create mode 100644 src/plugins/debugger/symbian/symbianengine.cpp rename tests/manual/trk/trkdevicex.cpp => src/plugins/debugger/symbian/trkclient.cpp (99%) rename tests/manual/trk/trkdevicex.h => src/plugins/debugger/symbian/trkclient.h (100%) rename {tests/manual/trk => src/plugins/debugger/symbian}/trkfunctor.h (98%) rename {tests/manual/trk => src/plugins/debugger/symbian}/trkutils.cpp (100%) rename {tests/manual/trk => src/plugins/debugger/symbian}/trkutils.h (99%) diff --git a/src/plugins/debugger/debugger.pro b/src/plugins/debugger/debugger.pro index 3cdc4f16f56..c9be97b7260 100644 --- a/src/plugins/debugger/debugger.pro +++ b/src/plugins/debugger/debugger.pro @@ -87,5 +87,7 @@ include(cdb/cdb.pri) include(gdb/gdb.pri) include(script/script.pri) include(tcf/tcf.pri) +include(symbian/symbian.pri) include(shared/shared.pri) + OTHER_FILES += Debugger.pluginspec diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index a17056ec1f8..b4a5c84a7ee 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -103,6 +103,8 @@ namespace Internal { IDebuggerEngine *createGdbEngine(DebuggerManager *parent, QList *); +IDebuggerEngine *createSymbianEngine(DebuggerManager *parent, QList *); + QDebug operator<<(QDebug str, const DebuggerStartParameters &p) { QDebug nospace = str.nospace(); diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index 60af08ae3cc..88eadb4c095 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -32,6 +32,7 @@ #include "idebuggerengine.h" #include "gdbmi.h" +#include "gdbprocessbase.h" #include "outputcollector.h" #include "watchutils.h" @@ -73,38 +74,6 @@ enum DebuggingHelperState DebuggingHelperUnavailable, }; -// GdbProcessBase is inherited by GdbProcess and the gdb/trk Adapter. -// In the GdbProcess case it's just a wrapper around a QProcess running -// gdb, in the Adapter case it's the interface to the gdb process in -// the whole rfomm/gdb/gdbserver combo. -class GdbProcessBase : public QObject -{ - Q_OBJECT - -public: - GdbProcessBase(QObject *parent) : QObject(parent) {} - - virtual void start(const QString &program, const QStringList &args, - QIODevice::OpenMode mode = QIODevice::ReadWrite) = 0; - virtual void kill() = 0; - virtual void terminate() = 0; - virtual bool waitForStarted(int msecs = 30000) = 0; - virtual bool waitForFinished(int msecs = 30000) = 0; - virtual QProcess::ProcessState state() const = 0; - virtual QString errorString() const = 0; - virtual QByteArray readAllStandardError() = 0; - virtual QByteArray readAllStandardOutput() = 0; - virtual qint64 write(const char *data) = 0; - virtual void setWorkingDirectory(const QString &dir) = 0; - virtual void setEnvironment(const QStringList &env) = 0; - -signals: - void error(QProcess::ProcessError); - void readyReadStandardOutput(); - void readyReadStandardError(); - void finished(int, QProcess::ExitStatus); -}; - class GdbProcess : public GdbProcessBase { public: diff --git a/src/plugins/debugger/gdb/gdbprocessbase.h b/src/plugins/debugger/gdb/gdbprocessbase.h new file mode 100644 index 00000000000..b6adfc763bb --- /dev/null +++ b/src/plugins/debugger/gdb/gdbprocessbase.h @@ -0,0 +1,74 @@ +/************************************************************************** +** +** 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 DEBUGGER_PROCESSBASE_H +#define DEBUGGER_PROCESSBASE_H + +#include +#include + +namespace Debugger { +namespace Internal { + +// GdbProcessBase is inherited by GdbProcess and the gdb/trk Adapter. +// In the GdbProcess case it's just a wrapper around a QProcess running +// gdb, in the Adapter case it's the interface to the gdb process in +// the whole rfomm/gdb/gdbserver combo. +class GdbProcessBase : public QObject +{ + Q_OBJECT + +public: + GdbProcessBase(QObject *parent = 0) : QObject(parent) {} + + virtual void start(const QString &program, const QStringList &args, + QIODevice::OpenMode mode = QIODevice::ReadWrite) = 0; + virtual void kill() = 0; + virtual void terminate() = 0; + virtual bool waitForStarted(int msecs = 30000) = 0; + virtual bool waitForFinished(int msecs = 30000) = 0; + virtual QProcess::ProcessState state() const = 0; + virtual QString errorString() const = 0; + virtual QByteArray readAllStandardError() = 0; + virtual QByteArray readAllStandardOutput() = 0; + virtual qint64 write(const char *data) = 0; + virtual void setWorkingDirectory(const QString &dir) = 0; + virtual void setEnvironment(const QStringList &env) = 0; + +signals: + void error(QProcess::ProcessError); + void readyReadStandardOutput(); + void readyReadStandardError(); + void finished(int, QProcess::ExitStatus); +}; + +} // namespace Internal +} // namespace Debugger + +#endif // DEBUGGER_PROCESSBASE_H diff --git a/src/plugins/debugger/symbian/symbian.pri b/src/plugins/debugger/symbian/symbian.pri new file mode 100644 index 00000000000..1ffb8081d4f --- /dev/null +++ b/src/plugins/debugger/symbian/symbian.pri @@ -0,0 +1,14 @@ +HEADERS += \ + $$PWD/trkclient.h \ + $$PWD/symbianadapter.h \ + #$$PWD/gdboptionspage.h \ + +SOURCES += \ + $$PWD/trkclient.cpp \ + $$PWD/symbianadapter.cpp \ + $$PWD/symbianengine.cpp \ + #$$PWD/gdboptionspage.cpp \ + +#FORMS += $$PWD/gdboptionspage.ui + +#RESOURCES += $$PWD/gdb.qrc diff --git a/src/plugins/debugger/symbian/symbianadapter.cpp b/src/plugins/debugger/symbian/symbianadapter.cpp new file mode 100644 index 00000000000..8f66b331242 --- /dev/null +++ b/src/plugins/debugger/symbian/symbianadapter.cpp @@ -0,0 +1,1599 @@ +/************************************************************************** +** +** 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 "symbianadapter.h" + +#define TrkCB(s) TrkCallback(this, &SymbianAdapter::s) +#define GdbCB(s) GdbCallback(this, &SymbianAdapter::s) + + +/* +fetch-register p info registers +set-register P set +binary-download X load, set +read-aux-vector qXfer:auxv:read info auxv +symbol-lookup qSymbol Detecting multiple threads +attach vAttach attach +verbose-resume vCont Stepping or resuming multiple threads +run vRun run +software-breakpoint Z0 break +hardware-breakpoint Z1 hbreak +write-watchpoint Z2 watch +read-watchpoint Z3 rwatch +access-watchpoint Z4 awatch +target-features qXfer:features:read set architecture +library-info qXfer:libraries:read info sharedlibrary +memory-map qXfer:memory-map:read info mem +read-spu-object qXfer:spu:read info spu +write-spu-object qXfer:spu:write info spu +get-thread-local- +storage-address qGetTLSAddr Displaying __thread variables +supported-packets qSupported Remote communications parameters +pass-signals QPassSignals handle signal +hostio-close-packet vFile:close remote get, remote put +hostio-open-packet vFile:open remote get, remote put +hostio-pread-packet vFile:pread remote get, remote put +hostio-pwrite-packet vFile:pwrite remote get, remote put +hostio-unlink-packet vFile:unlink remote delete +*/ + +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 QByteArray dumpRegister(int n, uint value) +{ + QByteArray ba; + ba += ' '; + if (n < KnownRegisters && registerNames[n]) { + ba += registerNames[n]; + } else { + ba += '#'; + ba += QByteArray::number(n); + } + ba += "=" + hexxNumber(value); + return ba; +} + +namespace Debugger { +namespace Internal { + +trk::Endianness m_registerEndianness = LittleEndian; + +SymbianAdapter::SymbianAdapter() +{ + m_running = false; + m_gdbAckMode = true; + m_verbose = 2; + m_serialFrame = false; + m_bufferedMemoryRead = true; + m_rfcommDevice = "/dev/rfcomm0"; + + uid_t userId = getuid(); + m_gdbServerName = QString("127.0.0.1:%1").arg(2222 + userId); + + m_gdbProc.setObjectName("GDB PROCESS"); + connectProcess(&m_gdbProc); + connect(&m_gdbProc, SIGNAL(readyReadStandardError()), + this, SLOT(handleGdbReadyReadStandardError())); + connect(&m_gdbProc, SIGNAL(readyReadStandardOutput()), + this, SLOT(handleGdbReadyReadStandardOutput())); + + m_rfcommProc.setObjectName("RFCOMM PROCESS"); + connectProcess(&m_rfcommProc); + connect(&m_rfcommProc, SIGNAL(readyReadStandardError()), + this, SLOT(handleRfcommReadyReadStandardError())); + connect(&m_rfcommProc, SIGNAL(readyReadStandardOutput()), + this, SLOT(handleRfcommReadyReadStandardOutput())); + + if (m_verbose > 1) + m_trkDevice.setVerbose(true); + m_trkDevice.setSerialFrame(m_serialFrame); + + connect(&m_trkDevice, SIGNAL(logMessage(QString)), + this, SLOT(trkLogMessage(QString))); +} + +SymbianAdapter::~SymbianAdapter() +{ + m_gdbServer.close(); + logMessage("Shutting down.\n", true); +} + +void SymbianAdapter::trkLogMessage(const QString &msg) +{ + logMessage("TRK " + msg); +} + +void SymbianAdapter::setGdbServerName(const QString &name) +{ + m_gdbServerName = name; +} + +QString SymbianAdapter::gdbServerIP() const +{ + int pos = m_gdbServerName.indexOf(':'); + if (pos == -1) + return m_gdbServerName; + return m_gdbServerName.left(pos); +} + +uint SymbianAdapter::gdbServerPort() const +{ + int pos = m_gdbServerName.indexOf(':'); + if (pos == -1) + return 0; + return m_gdbServerName.mid(pos + 1).toUInt(); +} + +QByteArray SymbianAdapter::trkContinueMessage() +{ + QByteArray ba; + appendInt(&ba, m_session.pid); + appendInt(&ba, m_session.tid); + return ba; +} + +QByteArray SymbianAdapter::trkReadRegisterMessage() +{ + 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); + return ba; +} + +QByteArray SymbianAdapter::trkReadMemoryMessage(uint addr, uint len) +{ + QByteArray ba; + appendByte(&ba, 0x08); // Options, FIXME: why? + appendShort(&ba, len); + appendInt(&ba, addr); + appendInt(&ba, m_session.pid); + appendInt(&ba, m_session.tid); + return ba; +} + +void SymbianAdapter::startInferior() +{ + QString errorMessage; + if (!m_trkDevice.open(m_rfcommDevice, &errorMessage)) { + logMessage("LOOPING"); + QTimer::singleShot(1000, this, SLOT(startInferior())); + return; + } + + m_trkDevice.sendTrkInitialPing(); + sendTrkMessage(0x01); // Connect + sendTrkMessage(0x05, TrkCB(handleSupportMask)); + sendTrkMessage(0x06, TrkCB(handleCpuType)); + sendTrkMessage(0x04, TrkCB(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 + + QByteArray ba; + appendByte(&ba, 0); // ? + appendByte(&ba, 0); // ? + appendByte(&ba, 0); // ? + + QByteArray file("C:\\sys\\bin\\filebrowseapp.exe"); + appendString(&ba, file, TargetByteOrder); + sendTrkMessage(0x40, TrkCB(handleCreateProcess), ba); // Create Item + //sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, TrkCB(startGdbServer)); +} + +void SymbianAdapter::logMessage(const QString &msg, bool force) +{ + if (m_verbose || force) + emit output(QString(), msg); +} + +// +// Gdb +// +void SymbianAdapter::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(readGdbServerCommand())); +} + +static inline QString msgGdbPacket(const QString &p) +{ + return QLatin1String("gdb: ") + p; +} + +void SymbianAdapter::readGdbServerCommand() +{ + QByteArray packet = m_gdbConnection->readAll(); + m_gdbReadBuffer.append(packet); + + logMessage("gdb: -> " + 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 cmd = ba.left(pos); + ba.remove(0, pos + 3); + handleGdbServerCommand(cmd); + } +} + +bool SymbianAdapter::sendGdbServerPacket(const QByteArray &packet, bool doFlush) +{ + if (!m_gdbConnection) { + logMessage(QString::fromLatin1("Cannot write to gdb: No connection (%1)") + .arg(QString::fromLatin1(packet)), true); + return false; + } + if (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 SymbianAdapter::sendGdbServerAck() +{ + if (!m_gdbAckMode) + return; + QByteArray packet = "+"; + logMessage("gdb: <- " + packet); + sendGdbServerPacket(packet, false); +} + +void SymbianAdapter::sendGdbServerMessage(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); + sendGdbServerPacket(packet, true); +} + +void SymbianAdapter::sendGdbServerMessageAfterTrkResponse(const QByteArray &msg, + const QByteArray &logNote) +{ + QByteArray ba = msg + char(1) + logNote; + sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, TrkCB(reportToGdb), "", ba); // Answer gdb +} + +void SymbianAdapter::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)); + sendGdbServerMessage(message, note); +} + +QByteArray SymbianAdapter::trkBreakpointMessage(uint addr, uint len, bool armMode) +{ + 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, m_session.pid); + appendInt(&ba, 0xFFFFFFFF); + return ba; +} + +void SymbianAdapter::handleGdbServerCommand(const QByteArray &cmd) +{ + // http://sourceware.org/gdb/current/onlinedocs/gdb_34.html + if (0) {} + + else if (cmd == "!") { + sendGdbServerAck(); + //sendGdbServerMessage("", "extended mode not enabled"); + sendGdbServerMessage("OK", "extended mode enabled"); + } + + else if (cmd.startsWith("?")) { + logMessage(msgGdbPacket(QLatin1String("Query halted"))); + // Indicate the reason the target halted. + // The reply is the same as for step and continue. + sendGdbServerAck(); + // The command below will trigger fetching a stack trace while + // the process does not seem to be fully functional. Most notably + // the PC points to a 0x9..., which is not in "our" range + //sendGdbServerMessage("T05library:r;", "target halted (library load)"); + //sendGdbServerMessage("S05", "target halted (trap)"); + sendGdbServerMessage("S00", "target halted (trap)"); + //sendGdbServerMessage("O" + QByteArray("Starting...").toHex()); + } + + else if (cmd == "c") { + logMessage(msgGdbPacket(QLatin1String("Continue"))); + sendGdbServerAck(); + 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, TrkCallback(), ba); + } + + else if (cmd.startsWith("C")) { + 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. + sendGdbServerAck(); + bool ok = false; + uint signalNumber = cmd.mid(1).toInt(&ok, 16); + QByteArray ba; + appendInt(&ba, m_session.pid); + appendInt(&ba, m_session.tid); + sendTrkMessage(0x18, TrkCB(handleSignalContinue), ba, signalNumber); // Continue + } + + else if (cmd.startsWith("D")) { + sendGdbServerAck(); + sendGdbServerMessage("OK", "shutting down"); + qApp->quit(); + } + + else if (cmd == "g") { + logMessage(msgGdbPacket(QLatin1String("Read registers"))); + // Read general registers. + //sendGdbServerMessage("00000000", "read registers"); + sendGdbServerAck(); + sendTrkMessage(0x12, TrkCB(handleAndReportReadRegisters), + trkReadRegisterMessage()); + } + + else if (cmd.startsWith("Hc")) { + 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 + sendGdbServerAck(); + sendGdbServerMessage("OK", "Set current thread for step & continue"); + } + + else if (cmd.startsWith("Hg")) { + logMessage(msgGdbPacket(QLatin1String("Set thread"))); + // Set thread for subsequent operations (`m', `M', `g', `G', et.al.). + // for 'other operations. 0 - any thread + //$Hg0#df + sendGdbServerAck(); + m_session.currentThread = cmd.mid(2).toInt(0, 16); + sendGdbServerMessage("OK", "Set current thread " + + QByteArray::number(m_session.currentThread)); + } + + else if (cmd == "k") { + logMessage(msgGdbPacket(QLatin1String("kill"))); + // kill + sendGdbServerAck(); + QByteArray ba; + appendByte(&ba, 0); // ? + appendByte(&ba, 0); // Sub-command: Delete Process + appendInt(&ba, m_session.pid); + sendTrkMessage(0x41, TrkCallback(), ba, "Delete process"); // Delete Item + sendGdbServerMessageAfterTrkResponse("", "process killed"); + } + + else if (cmd.startsWith("m")) { + logMessage(msgGdbPacket(QLatin1String("Read memory"))); + // m addr,length + sendGdbServerAck(); + uint addr = 0, len = 0; + do { + const int pos = cmd.indexOf(','); + if (pos == -1) + break; + bool ok; + addr = cmd.mid(1, pos - 1).toUInt(&ok, 16); + if (!ok) + break; + len = cmd.mid(pos + 1).toUInt(&ok, 16); + if (!ok) + break; + } while (false); + if (len) { + readMemory(addr, len); + } else { + sendGdbServerMessage("E20", "Error " + cmd); + } + } + else if (cmd.startsWith("p")) { + logMessage(msgGdbPacket(QLatin1String("read register"))); + // 0xf == current instruction pointer? + //sendGdbServerMessage("0000", "current IP"); + sendGdbServerAck(); + #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 = cmd.mid(1).toInt(&ok, 16); + QByteArray logMsg = "Read Register"; + if (registerNumber == RegisterPSGdb) { + QByteArray ba; + appendInt(&ba, m_snapshot.registers[RegisterPSTrk], m_registerEndianness); + logMsg += dumpRegister(registerNumber, m_snapshot.registers[RegisterPSTrk]); + sendGdbServerMessage(ba.toHex(), logMsg); + } else if (registerNumber < RegisterCount) { + QByteArray ba; + appendInt(&ba, m_snapshot.registers[registerNumber], m_registerEndianness); + logMsg += dumpRegister(registerNumber, m_snapshot.registers[registerNumber]); + sendGdbServerMessage(ba.toHex(), logMsg); + } else { + sendGdbServerMessage("0000", "read single unknown register #" + QByteArray::number(registerNumber)); + //sendGdbServerMessage("E01", "read single unknown register"); + } + } + + else if (cmd == "qAttached") { + //$qAttached#8f + // 1: attached to an existing process + // 0: created a new process + sendGdbServerAck(); + sendGdbServerMessage("0", "new process created"); + //sendGdbServerMessage("1", "attached to existing process"); + //sendGdbServerMessage("E01", "new process created"); + } + + else if (cmd.startsWith("qC")) { + logMessage(msgGdbPacket(QLatin1String("query thread id"))); + // Return the current thread ID + //$qC#b4 + sendGdbServerAck(); + sendGdbServerMessageAfterTrkResponse("QC@TID@"); + } + + else if (cmd.startsWith("qSupported")) { + //$qSupported#37 + //$qSupported:multiprocess+#c6 + //logMessage("Handling 'qSupported'"); + sendGdbServerAck(); + if (0) + sendGdbServerMessage(QByteArray(), "nothing supported"); + else + sendGdbServerMessage( + "PacketSize=7cf;" + "QPassSignals+;" + "qXfer:libraries:read+;" + //"qXfer:auxv:read+;" + "qXfer:features:read+"); + } + + else if (cmd == "qPacketInfo") { + // happens with gdb 6.4.50.20060226-cvs / CodeSourcery + // deprecated by qSupported? + sendGdbServerAck(); + sendGdbServerMessage("", "FIXME: nothing?"); + } + + else if (cmd == "qOffsets") { + sendGdbServerAck(); + sendGdbServerMessageAfterTrkResponse("TextSeg=@CODESEG@;DataSeg=@DATASEG@"); + } + + else if (cmd == "qSymbol::") { + if (m_verbose) + logMessage(msgGdbPacket(QLatin1String("notify can handle symbol lookup"))); + // Notify the target that GDB is prepared to serve symbol lookup requests. + sendGdbServerAck(); + if (1) + sendGdbServerMessage("OK", "no further symbols needed"); + else + sendGdbServerMessage("qSymbol:" + QByteArray("_Z7E32Mainv").toHex(), "ask for more"); + } + + else if (cmd.startsWith("qXfer:features:read:target.xml:")) { + // $qXfer:features:read:target.xml:0,7ca#46...Ack + sendGdbServerAck(); + sendGdbServerMessage("lsymbianelf"); + } + + else if (cmd == "QStartNoAckMode") { + //$qSupported#37 + //logMessage("Handling 'QStartNoAckMode'"); + sendGdbServerAck(); + sendGdbServerMessage("OK", "ack no-ack mode"); + m_gdbAckMode = false; + } + + else if (cmd.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 + sendGdbServerAck(); + // FIXME: use the parameters + sendGdbServerMessage("OK", "passing signals accepted"); + } + + else if (cmd == "s" || cmd.startsWith("vCont;s")) { + logMessage(msgGdbPacket(QLatin1String("Step range"))); + logMessage(" from " + hexxNumber(m_snapshot.registers[RegisterPC])); + sendGdbServerAck(); + m_running = true; + QByteArray ba; + appendByte(&ba, 0x01); // options + appendInt(&ba, m_snapshot.registers[RegisterPC]); // start address + //appendInt(&ba, m_snapshot.registers[RegisterPC] + 4); // end address + appendInt(&ba, -1); // end address + appendInt(&ba, m_session.pid); + appendInt(&ba, m_session.tid); + sendTrkMessage(0x19, TrkCB(handleStepRange), ba, "Step range"); + // FIXME: should be triggered by "real" stop" + //sendGdbServerMessageAfterTrkResponse("S05", "target halted"); + } + + else if (cmd == "vCont?") { + // actions supported by the vCont packet + sendGdbServerAck(); + //sendGdbServerMessage("OK"); // we don't support vCont. + sendGdbServerMessage("vCont;c;C;s;S"); + } + + else if (cmd == "vCont;c") { + // vCont[;action[:thread-id]]...' + sendGdbServerAck(); + m_running = true; + sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE"); + } + + else if (cmd.startsWith("vKill")) { + // kill + sendGdbServerAck(); + QByteArray ba; + appendByte(&ba, 0); // Sub-command: Delete Process + appendInt(&ba, m_session.pid); + sendTrkMessage(0x41, TrkCallback(), ba, "Delete process"); // Delete Item + sendGdbServerMessageAfterTrkResponse("", "process killed"); + } + + else if (0 && cmd.startsWith("Z0,")) { + // Tell gdb we don't support software breakpoints + sendGdbServerMessage(""); + } + + else if (cmd.startsWith("Z0,") || cmd.startsWith("Z1,")) { + sendGdbServerAck(); + // Insert breakpoint + logMessage(msgGdbPacket(QLatin1String("Insert breakpoint"))); + // $Z0,786a4ccc,4#99 + const int pos = cmd.lastIndexOf(','); + bool ok = false; + const uint addr = cmd.mid(3, pos - 3).toInt(&ok, 16); + const uint len = cmd.mid(pos + 1).toInt(&ok, 16); + //qDebug() << "ADDR: " << hexNumber(addr) << " LEN: " << len; + 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 = trkBreakpointMessage(addr, len, m_session.pid); + sendTrkMessage(0x1B, TrkCB(handleAndReportSetBreakpoint), ba, addr); + //---TRK------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x00 + // [80 09 00 00 00 00 0A] + } + + else if (cmd.startsWith("z0,") || cmd.startsWith("z1,")) { + sendGdbServerAck(); + // Remove breakpoint + logMessage(msgGdbPacket(QLatin1String("Remove breakpoint"))); + // $z0,786a4ccc,4#99 + const int pos = cmd.lastIndexOf(','); + bool ok = false; + const uint addr = cmd.mid(3, pos - 3).toInt(&ok, 16); + const uint len = cmd.mid(pos + 1).toInt(&ok, 16); + const uint bp = m_session.addressToBP[addr]; + if (bp == 0) { + logMessage(QString::fromLatin1("NO RECORDED BP AT 0x%1, %2") + .arg(addr, 0, 16).arg(len)); + } else { + //---IDE------------------------------------------------------ + // Command: 0x1C Clear Break + // [1C 25 00 00 00 0A 78 6A 43 40] + m_session.addressToBP.remove(addr); + QByteArray ba; + appendByte(&ba, 0x00); + appendShort(&ba, bp); + appendInt(&ba, addr); + sendTrkMessage(0x1C, TrkCB(handleClearBreakpoint), ba, addr); + } + } + + else if (cmd.startsWith("qPart:") || cmd.startsWith("qXfer:")) { + QByteArray data = cmd.mid(1 + cmd.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); + sendGdbServerMessage("E20", msg.toLatin1()); + handled = true; + } + } + } // auxv read + if (!handled) { + const QString msg = QLatin1String("FIXME unknown 'XFER'-request: ") + + QString::fromAscii(cmd); + logMessage(msgGdbPacket(msg), true); + sendGdbServerMessage("E20", msg.toLatin1()); + } + } // qPart/qXfer + else { + logMessage(msgGdbPacket(QLatin1String("FIXME unknown: ") + + QString::fromAscii(cmd))); + } +} + +void SymbianAdapter::executeCommand(const QString &msg) +{ + if (msg == "EI") { + sendGdbMessage("-exec-interrupt"); + } else if (msg == "C") { + sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE"); + } else if (msg == "R") { + sendTrkMessage(0x18, TrkCB(handleReadRegisters), + trkReadRegisterMessage(), "READ REGS"); + } else if (msg == "I") { + interruptInferior(); + } else { + logMessage("EXECUTING GDB COMMAND " + msg); + sendGdbMessage(msg); + } +} + +void SymbianAdapter::sendTrkMessage(byte code, TrkCallback callback, + const QByteArray &data, const QVariant &cookie) +{ + m_trkDevice.sendTrkMessage(code, callback, data, cookie); +} + +void SymbianAdapter::sendTrkAck(byte token) +{ + logMessage(QString("SENDING ACKNOWLEDGEMENT FOR TOKEN %1").arg(int(token))); + m_trkDevice.sendTrkAck(token); +} + +void SymbianAdapter::handleTrkError(const QString &msg) +{ + logMessage("## TRK ERROR: " + msg); +} + +void SymbianAdapter::handleTrkResult(const TrkResult &result) +{ + if (result.isDebugOutput) { + sendTrkAck(result.token); + logMessage(QLatin1String("APPLICATION OUTPUT: ") + + QString::fromAscii(result.data)); + sendGdbServerMessage("O" + result.data.toHex()); + return; + } + logMessage("READ TRK " + result.toString()); + 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); + const uint pid = extractInt(data + 4); + const uint tid = extractInt(data + 8); + 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 + if (m_running) { + m_running = false; + sendGdbServerMessage("S05", "Target stopped"); + } + } else { + logMessage(QLatin1String("Ignoring stop at 0")); + } + 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); + // type: 1 byte; for dll item, this value is 2. + const byte type = result.data.at(1); + const uint pid = extractInt(data + 2); + const uint tid = extractInt(data + 6); + const uint codeseg = extractInt(data + 10); + const uint dataseg = extractInt(data + 14); + const uint len = extractShort(data + 18); + const QByteArray name = result.data.mid(20, len); // 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 << " CODE: " << hexxNumber(codeseg); + str << " DATA: " << hexxNumber(dataseg); + str << " NAME: '" << name << '\''; + logMessage(logMsg); + // This lets gdb trigger a register update etc + //sendGdbServerMessage("T05library:r;"); + sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE"); + break; + } + case 0xa1: { // NotifyDeleted + const ushort itemType = extractByte(result.data.data() + 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); + if (itemType == 0) { + sendGdbServerMessage("W00", "Process exited"); + //sendTrkMessage(0x02, TrkCB(handleDisconnect)); + } + 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 SymbianAdapter::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 SymbianAdapter::handleSetTrkBreakpoint(const TrkResult &result) +{ + //---TRK------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x00 + // [80 09 00 00 00 00 0A] + const uint bpnr = extractInt(result.data.data()); + logMessage("SET BREAKPOINT " + hexxNumber(bpnr) + + stringFromArray(result.data.data())); +} + +void SymbianAdapter::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); + + logMessage("PID: " + hexxNumber(m_session.pid)); + logMessage("TID: " + hexxNumber(m_session.tid)); + logMessage("COD: " + hexxNumber(m_session.codeseg)); + logMessage("DAT: " + hexxNumber(m_session.dataseg)); + + QByteArray ba; + appendInt(&ba, m_session.pid); + appendInt(&ba, m_session.tid); + + startGdb(); + + +#if 0 + //---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, TrkCB(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, TrkCB(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, TrkCB(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, TrkCB(handleStop), + // "01 " + formatInt(m_session.pid) + formatInt(m_session.tid)); +} + +void SymbianAdapter::handleReadRegisters(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...] + if (result.errorCode()) { + logMessage("ERROR: " + result.errorString()); + return; + } + 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); +} + +void SymbianAdapter::handleAndReportReadRegisters(const TrkResult &result) +{ + handleReadRegisters(result); + 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) { + logMsg += dumpRegister(i, m_snapshot.registers[i]); + logMsg += ' '; + } + } + sendGdbServerMessage(ba, logMsg); +} + +static inline QString msgMemoryReadError(int code, uint addr, uint len = 0) +{ + const QString lenS = len ? QString::number(len) : QLatin1String(""); + return QString::fromLatin1("Memory read error %1 at: 0x%2 %3") + .arg(code).arg(addr, 0 ,16).arg(lenS); +} + +void SymbianAdapter::handleReadMemoryBuffered(const TrkResult &result) +{ + if (extractShort(result.data.data() + 1) + 3 != result.data.size()) + logMessage("\n BAD MEMORY RESULT: " + result.data.toHex() + "\n"); + const uint blockaddr = result.cookie.toUInt(); + if (const int errorCode = result.errorCode()) { + logMessage(msgMemoryReadError(errorCode, blockaddr)); + return; + } + const QByteArray ba = result.data.mid(3); + m_snapshot.memory.insert(blockaddr, ba); +} + +// Format log message for memory access with some smartness about registers +QByteArray SymbianAdapter::memoryReadLogMessage(uint addr, uint len, const QByteArray &ba) const +{ + QByteArray logMsg = "memory contents"; + if (m_verbose > 1) { + logMsg += " addr: " + hexxNumber(addr); + // 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).toAscii(); + } + return logMsg; +} + +void SymbianAdapter::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()); + } + const int previousChunkOverlap = addr % MemoryChunkSize; + if (previousChunkOverlap != 0 && ba.size() > previousChunkOverlap) + ba.remove(0, previousChunkOverlap); + if (ba.size() > int(len)) + ba.truncate(len); + + if (ba.isEmpty()) { + ba = "E20"; + sendGdbServerMessage(ba, msgMemoryReadError(32, addr, len).toLatin1()); + } else { + sendGdbServerMessage(ba.toHex(), memoryReadLogMessage(addr, len, ba)); + } +} + +void SymbianAdapter::handleReadMemoryUnbuffered(const TrkResult &result) +{ + //logMessage("UNBUFFERED MEMORY READ: " + stringFromArray(result.data)); + const uint blockaddr = result.cookie.toUInt(); + if (extractShort(result.data.data() + 1) + 3 != result.data.size()) + logMessage("\n BAD MEMORY RESULT: " + result.data.toHex() + "\n"); + if (const int errorCode = result.errorCode()) { + const QByteArray ba = "E20"; + sendGdbServerMessage(ba, msgMemoryReadError(32, blockaddr).toLatin1()); + } else { + const QByteArray ba = result.data.mid(3); + sendGdbServerMessage(ba.toHex(), memoryReadLogMessage(blockaddr, ba.size(), ba)); + } +} + +void SymbianAdapter::handleStepRange(const TrkResult &result) +{ + // [80 0f 00] + if (result.errorCode()) { + logMessage("ERROR: " + result.errorString()); + return; + } + logMessage("STEPPING FINISHED "); + //sendGdbServerMessage("S05", "Stepping finished"); +} + +void SymbianAdapter::handleAndReportSetBreakpoint(const TrkResult &result) +{ + //---TRK------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x00 + // [80 09 00 00 00 00 0A] + uint bpnr = extractByte(result.data.data()); + uint addr = result.cookie.toUInt(); + m_session.addressToBP[addr] = bpnr; + logMessage("SET BREAKPOINT " + hexxNumber(bpnr) + " " + + stringFromArray(result.data.data())); + sendGdbServerMessage("OK"); + //sendGdbServerMessage("OK"); +} + +void SymbianAdapter::handleClearBreakpoint(const TrkResult &result) +{ + logMessage("CLEAR BREAKPOINT "); + if (result.errorCode()) { + logMessage("ERROR: " + result.errorString()); + //return; + } + //---TRK------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x00 + // [80 09 00 00 00 00 0A] + // FIXME: + sendGdbServerMessage("OK"); +} + +void SymbianAdapter::handleSignalContinue(const TrkResult &result) +{ + int signalNumber = result.cookie.toInt(); + logMessage(" HANDLE SIGNAL CONTINUE: " + stringFromArray(result.data)); + logMessage("NUMBER" + QString::number(signalNumber)); + sendGdbServerMessage("O" + QByteArray("Console output").toHex()); + sendGdbServerMessage("W81"); // "Process exited with result 1 +} + +void SymbianAdapter::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 SymbianAdapter::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 SymbianAdapter::handleDisconnect(const TrkResult & /*result*/) +{ + logMessage(QLatin1String("Trk disconnected"), true); +} + +void SymbianAdapter::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, TrkCB(handleReadMemoryBuffered), + trkReadMemoryMessage(blockaddr, MemoryChunkSize), + QVariant(blockaddr)); + } + } + const qulonglong cookie = (qulonglong(addr) << 32) + len; + sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, TrkCB(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, TrkCB(handleReadMemoryUnbuffered), + trkReadMemoryMessage(addr, len), QVariant(addr)); + } +} + +void SymbianAdapter::interruptInferior() +{ + QByteArray ba; + // stop the thread (2) or the process (1) or the whole system (0) + // We choose 2, as 1 does not seem to work. + appendByte(&ba, 2); + appendInt(&ba, m_session.pid); + appendInt(&ba, m_session.tid); // threadID: 4 bytes Variable number of bytes. + sendTrkMessage(0x1a, TrkCallback(), ba, "Interrupting..."); +} + +void SymbianAdapter::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(started()), + this, SLOT(handleProcStarted())); + connect(proc, SIGNAL(stateChanged(QProcess::ProcessState)), + this, SLOT(handleProcStateChanged(QProcess::ProcessState))); +} + +void SymbianAdapter::sendOutput(QObject *sender, const QString &data) +{ + if (sender) + emit output(sender->objectName() + " : ", data); + else + emit output(QString(), data); +} + +void SymbianAdapter::handleProcError(QProcess::ProcessError error) +{ + sendOutput(sender(), QString("Process Error %1").arg(error)); +} + +void SymbianAdapter::handleProcFinished(int exitCode, QProcess::ExitStatus exitStatus) +{ + sendOutput(sender(), + QString("ProcessFinished %1 %2").arg(exitCode).arg(exitStatus)); +} + +void SymbianAdapter::handleProcStarted() +{ + sendOutput(sender(), QString("Process Started")); +} + +void SymbianAdapter::handleProcStateChanged(QProcess::ProcessState newState) +{ + sendOutput(sender(), QString("Process State %1").arg(newState)); +} + +void SymbianAdapter::run() +{ + sendOutput("### Starting SymbianAdapter"); + m_rfcommProc.start("rfcomm listen " + m_rfcommDevice + " 1"); + m_rfcommProc.waitForStarted(); + + connect(&m_trkDevice, SIGNAL(messageReceived(trk::TrkResult)), + this, SLOT(handleTrkResult(trk::TrkResult))); + connect(&m_trkDevice, SIGNAL(error(QString)), + this, SLOT(handleTrkError(QString))); + + startInferior(); +} + +void SymbianAdapter::startGdb() +{ + 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())); + + 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(); + + sendGdbMessage("set confirm off"); // confirm potentially dangerous operations? + sendGdbMessage("set endian little"); + sendGdbMessage("set remotebreak on"); + sendGdbMessage("set breakpoint pending on"); + sendGdbMessage("set trust-readonly-sections on"); + //sendGdbMessage("mem 0 ~0ll rw 8 cache"); + + // FIXME: "remote noack" does not seem to be supported on cs-gdb? + //sendGdbMessage("set remote noack-packet"); + + // FIXME: creates a lot of noise a la '&"putpkt: Junk: Ack " &' + // even thouhg the communication seems sane + //sendGdbMessage("set debug remote 1"); // creates l + + //sendGdbMessage("target remote " + m_gdbServerName); +// sendGdbMessage("target extended-remote " + m_gdbServerName); + //sendGdbMessage("target extended-async " + m_gdbServerName); + //sendGdbMessage("set remotecache ...") // Set cache use for remote targets + //sendGdbMessage("file filebrowseapp.sym"); +// sendGdbMessage("add-symbol-file filebrowseapp.sym " + m_baseAddress); +// sendGdbMessage("symbol-file filebrowseapp.sym"); +// sendGdbMessage("print E32Main"); +// sendGdbMessage("break E32Main"); + //sendGdbMessage("continue"); + //sendGdbMessage("info files"); + //sendGdbMessage("file filebrowseapp.sym -readnow"); + + sendGdbMessage("add-symbol-file filebrowseapp.sym " + + hexxNumber(m_session.codeseg)); + sendGdbMessage("symbol-file filebrowseapp.sym"); + + // -symbol-info-address not implemented in cs-gdb 6.4-6.8 (at least) + sendGdbMessage("info address E32Main", + GdbCB(handleInfoMainAddress)); + sendGdbMessage("info address CFileBrowseAppUi::HandleCommandL", + GdbCB(handleInfoMainAddress)); + +#if 1 + // FIXME: Gdb based version. That's the goal + //sendGdbMessage("break E32Main"); + //sendGdbMessage("continue"); + //sendTrkMessage(0x18, TrkCB(handleContinueAfterCreateProcess), + // trkContinueMessage(), "CONTINUE"); +#else + // Directly talk to TRK. Works for now... + sendGdbMessage("break E32Main"); + sendGdbMessage("break filebrowseappui.cpp:39"); + // sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE"); +#endif +} + +void SymbianAdapter::sendGdbMessage(const QString &msg, GdbCallback callback, + const QVariant &cookie) +{ + static int token = 0; + ++token; + GdbCommand data; + data.command = msg; + data.callback = callback; + data.cookie = cookie; + m_gdbCookieForToken[token] = data; + logMessage(QString("<- GDB: %1 %2").arg(token).arg(msg)); + m_gdbProc.write(QString("%1%2\n").arg(token).arg(msg).toLatin1()); +} + +void SymbianAdapter::handleGdbReadyReadStandardError() +{ + QByteArray ba = qobject_cast(sender())->readAllStandardError(); + sendOutput(sender(), QString("stderr: %1").arg(QString::fromLatin1(ba))); +} + +void SymbianAdapter::handleGdbReadyReadStandardOutput() +{ + QByteArray ba = qobject_cast(sender())->readAllStandardOutput(); + QString str = QString::fromLatin1(ba); + // FIXME: fragile. merge with gdbengine logic +#if 0 + QRegExp re(QString(".*([0-9]+)[^]done.*")); + int pos = re.indexIn(str); + if (pos == -1) { + logMessage(QString("\n-> GDB: %1 %**% %2 %**%\n").arg(str).arg(pos)); + return; + } + int token = re.cap(1).toInt(); + logMessage(QString("\n-> GDB: %1 %2##\n").arg(token).arg(QString::fromLatin1(ba))); + if (!token) + return; + GdbCommand cmd = m_gdbCookieForToken.take(token); + logMessage("FOUND CALLBACK FOR " + cmd.command); + GdbResult result; + result.data = ba; + if (!cmd.callback.isNull()) + cmd.callback(result); +#else + bool ok; + QRegExp re(QString("Symbol .._Z7E32Mainv.. is a function at address 0x(.*)\\.")); + if (re.indexIn(str) != -1) { + logMessage(QString("-> GDB MAIN BREAKPOINT: %1").arg(re.cap(1))); + uint addr = re.cap(1).toInt(&ok, 16); + sendTrkMessage(0x1B, TrkCallback(), trkBreakpointMessage(addr, 1)); + return; + } + QRegExp re1(QString("Symbol .._ZN16CFileBrowseAppUi14HandleCommandLEi.. is a function at address 0x(.*)\\.")); + if (re1.indexIn(str) != -1) { + logMessage(QString("-> GDB USER BREAKPOINT: %1").arg(re1.cap(1))); + uint addr = re1.cap(1).toInt(&ok, 16); + sendTrkMessage(0x1B, TrkCallback(), trkBreakpointMessage(addr, 1)); + + sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE"); + sendGdbMessage("target remote " + m_gdbServerName); + return; + } + logMessage(QString("-> GDB: %1").arg(str)); +#endif +} + +void SymbianAdapter::handleInfoMainAddress(const GdbResult &result) +{ + Q_UNUSED(result); +} + +void SymbianAdapter::handleSetTrkMainBreakpoint(const TrkResult &result) +{ + Q_UNUSED(result); +/* + //---TRK------------------------------------------------------ + // [80 09 00 00 00 00 0A] + const uint bpnr = extractInt(result.data.data()); + logMessage("SET MAIN BREAKPOINT " + hexxNumber(bpnr) + + stringFromArray(result.data.data())); +*/ +} + +void SymbianAdapter::handleInfoAddress(const GdbResult &result) +{ + Q_UNUSED(result); + // FIXME +} + +void SymbianAdapter::handleRfcommReadyReadStandardError() +{ + QByteArray ba = qobject_cast(sender())->readAllStandardError(); + sendOutput(sender(), QString("stderr: %1").arg(QString::fromLatin1(ba))); +} + +void SymbianAdapter::handleRfcommReadyReadStandardOutput() +{ + QByteArray ba = qobject_cast(sender())->readAllStandardOutput(); + sendOutput(sender(), QString("stdout: %1").arg(QString::fromLatin1(ba))); +} + +// +// GdbProcessBase +// + +void SymbianAdapter::start(const QString &program, const QStringList &args, + QIODevice::OpenMode mode) +{ + //m_gdbProc.start(program, args, mode); +} + +void SymbianAdapter::kill() +{ + //m_gdbProc.kill(); +} + +void SymbianAdapter::terminate() +{ + //m_gdbProc.terminate(); +} + +bool SymbianAdapter::waitForStarted(int msecs) +{ + //return m_gdbProc.waitForStarted(msecs); + return true; +} + +bool SymbianAdapter::waitForFinished(int msecs) +{ + //return m_gdbProc.waitForFinished(msecs); + return true; +} + +QProcess::ProcessState SymbianAdapter::state() const +{ + return m_gdbProc.state(); +} + +QString SymbianAdapter::errorString() const +{ + return m_gdbProc.errorString(); +} + +QByteArray SymbianAdapter::readAllStandardError() +{ + return m_gdbProc.readAllStandardError(); +} + +QByteArray SymbianAdapter::readAllStandardOutput() +{ + return m_gdbProc.readAllStandardOutput(); +} + +qint64 SymbianAdapter::write(const char *data) +{ + return m_gdbProc.write(data); +} + +void SymbianAdapter::setWorkingDirectory(const QString &dir) +{ + m_gdbProc.setWorkingDirectory(dir); +} + +void SymbianAdapter::setEnvironment(const QStringList &env) +{ + m_gdbProc.setEnvironment(env); +} + +} // namespace Internal +} // namespace Debugger diff --git a/src/plugins/debugger/symbian/symbianadapter.h b/src/plugins/debugger/symbian/symbianadapter.h new file mode 100644 index 00000000000..45c5b762c04 --- /dev/null +++ b/src/plugins/debugger/symbian/symbianadapter.h @@ -0,0 +1,247 @@ +/************************************************************************** +** +** 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 DEBUGGER_SYMBIANADAPTER_H +#define DEBUGGER_SYMBIANADAPTER_H + +#include "trkutils.h" +#include "trkclient.h" +#include "../gdb/gdbprocessbase.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace Debugger { +namespace Internal { + +struct GdbResult +{ + QByteArray data; +}; + +/////////////////////////////////////////////////////////////////////// +// +// SymbianAdapter +// +/////////////////////////////////////////////////////////////////////// + +class SymbianAdapter : public GdbProcessBase +{ + Q_OBJECT + +public: + typedef trk::TrkResult TrkResult; + typedef trk::TrkFunctor1 TrkCallback; + typedef trk::TrkFunctor1 GdbCallback; + + SymbianAdapter(); + ~SymbianAdapter(); + void setGdbServerName(const QString &name); + 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; } + +public slots: + void startInferior(); + +signals: + void output(const QString &senderName, const QString &data); + +private slots: + void handleProcError(QProcess::ProcessError error); + void handleProcFinished(int exitCode, QProcess::ExitStatus exitStatus); + void handleProcStarted(); + void handleProcStateChanged(QProcess::ProcessState newState); + void run(); + void startGdb(); + +private: + friend class RunnerGui; + void connectProcess(QProcess *proc); + void sendOutput(QObject *sender, const QString &data); + void sendOutput(const QString &data) { sendOutput(0, data); } + + QString m_rfcommDevice; // /dev/rfcomm0 + QString m_gdbServerName; // 127.0.0.1:(2222+uid) + + QProcess m_gdbProc; + QProcess m_rfcommProc; + bool m_running; + +public: + // + // Implementation of GdbProcessBase + // + void start(const QString &program, const QStringList &args, + QIODevice::OpenMode mode = QIODevice::ReadWrite); + void kill(); + void terminate(); + bool waitForStarted(int msecs = 30000); + bool waitForFinished(int msecs = 30000); + QProcess::ProcessState state() const; + QString errorString() const; + QByteArray readAllStandardError(); + QByteArray readAllStandardOutput(); + qint64 write(const char *data); + void setWorkingDirectory(const QString &dir); + void setEnvironment(const QStringList &env); + + // + // TRK + // + void sendTrkMessage(byte code, + TrkCallback callback = TrkCallback(), + const QByteArray &data = QByteArray(), + const QVariant &cookie = QVariant()); + Q_SLOT void handleTrkResult(const trk::TrkResult &data); + Q_SLOT void handleTrkError(const QString &msg); + + // convenience messages + void sendTrkAck(byte token); + + void handleCpuType(const TrkResult &result); + void handleCreateProcess(const TrkResult &result); + void handleClearBreakpoint(const TrkResult &result); + void handleSignalContinue(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; + QByteArray trkContinueMessage(); + QByteArray trkReadRegisterMessage(); + QByteArray trkReadMemoryMessage(uint addr, uint len); + QByteArray trkBreakpointMessage(uint addr, uint len, bool armMode = true); + void handleAndReportSetBreakpoint(const TrkResult &result); + void handleReadMemoryBuffered(const TrkResult &result); + void handleReadMemoryUnbuffered(const TrkResult &result); + void handleStepRange(const TrkResult &result); + void handleReadRegisters(const TrkResult &result); + void reportReadMemoryBuffered(const TrkResult &result); + void reportToGdb(const TrkResult &result); + + // set breakpoints behind gdb's back + void handleSetTrkBreakpoint(const TrkResult &result); + void handleSetTrkMainBreakpoint(const TrkResult &result); + + void readMemory(uint addr, uint len); + void interruptInferior(); + + trk::TrkDevice m_trkDevice; + + // + // Gdb + // + struct GdbCommand + { + GdbCommand() : flags(0), callback(GdbCallback()), callbackName(0) {} + + int flags; + GdbCallback callback; + const char *callbackName; + QString command; + QVariant cookie; + //QTime postTime; + }; + + void sendGdbMessage(const QString &msg, + GdbCallback callback = GdbCallback(), + const QVariant &cookie = QVariant()); + Q_SLOT void handleGdbConnection(); + Q_SLOT void readGdbServerCommand(); + void readGdbResponse(); + void handleGdbServerCommand(const QByteArray &cmd); + void sendGdbServerMessage(const QByteArray &msg, + const QByteArray &logNote = QByteArray()); + void sendGdbServerMessageAfterTrkResponse(const QByteArray &msg, + const QByteArray &logNote = QByteArray()); + void sendGdbServerAck(); + bool sendGdbServerPacket(const QByteArray &packet, bool doFlush); + + Q_SLOT void handleGdbReadyReadStandardError(); + Q_SLOT void handleGdbReadyReadStandardOutput(); + void logMessage(const QString &msg, bool force = false); + Q_SLOT void trkLogMessage(const QString &msg); + + void handleInfoAddress(const GdbResult &result); + void handleInfoMainAddress(const GdbResult &result); + + QTcpServer m_gdbServer; + QPointer m_gdbConnection; + QByteArray m_gdbReadBuffer; + bool m_gdbAckMode; + + QHash m_gdbCookieForToken; + + // + // Rfcomm + // + Q_SLOT void handleRfcommReadyReadStandardError(); + Q_SLOT void handleRfcommReadyReadStandardOutput(); + + // 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; +}; + +} // namespace Internal +} // namespace Debugger + +#endif // DEBUGGER_SYMBIANADAPTER_H diff --git a/src/plugins/debugger/symbian/symbianengine.cpp b/src/plugins/debugger/symbian/symbianengine.cpp new file mode 100644 index 00000000000..11c6b03c8ad --- /dev/null +++ b/src/plugins/debugger/symbian/symbianengine.cpp @@ -0,0 +1,66 @@ +/************************************************************************** +** +** 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. +** +**************************************************************************/ + +#define QT_NO_CAST_FROM_ASCII + +#include "gdb/gdbengine.h" +#include "symbianadapter.h" + +//#include "debuggerdialogs.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +namespace Debugger { +namespace Internal { + + +IDebuggerEngine *createSymbianEngine(DebuggerManager *parent, + QList *opts) +{ + Q_UNUSED(opts); + //opts->push_back(new GdbOptionsPage); + return new GdbEngine(parent, new SymbianAdapter); +} + +} // namespace Internal +} // namespace Debugger + + diff --git a/tests/manual/trk/trkdevicex.cpp b/src/plugins/debugger/symbian/trkclient.cpp similarity index 99% rename from tests/manual/trk/trkdevicex.cpp rename to src/plugins/debugger/symbian/trkclient.cpp index 42c7f72e175..5ae9766ac5a 100644 --- a/tests/manual/trk/trkdevicex.cpp +++ b/src/plugins/debugger/symbian/trkclient.cpp @@ -27,7 +27,7 @@ ** **************************************************************************/ -#include "trkdevicex.h" +#include "trkclient.h" #include "trkutils.h" #include @@ -35,7 +35,6 @@ #include #include #include -#include #ifdef Q_OS_WIN # include diff --git a/tests/manual/trk/trkdevicex.h b/src/plugins/debugger/symbian/trkclient.h similarity index 100% rename from tests/manual/trk/trkdevicex.h rename to src/plugins/debugger/symbian/trkclient.h diff --git a/tests/manual/trk/trkfunctor.h b/src/plugins/debugger/symbian/trkfunctor.h similarity index 98% rename from tests/manual/trk/trkfunctor.h rename to src/plugins/debugger/symbian/trkfunctor.h index 3dbd027774b..4b0d3669120 100644 --- a/tests/manual/trk/trkfunctor.h +++ b/src/plugins/debugger/symbian/trkfunctor.h @@ -27,8 +27,8 @@ ** **************************************************************************/ -#ifndef _TRK_FUNCTOR_H_ -#define _TRK_FUNCTOR_H_ +#ifndef DEBUGGER_TRK_FUNCTOR_H +#define DEBUGGER_TRK_FUNCTOR_H #include diff --git a/tests/manual/trk/trkutils.cpp b/src/plugins/debugger/symbian/trkutils.cpp similarity index 100% rename from tests/manual/trk/trkutils.cpp rename to src/plugins/debugger/symbian/trkutils.cpp diff --git a/tests/manual/trk/trkutils.h b/src/plugins/debugger/symbian/trkutils.h similarity index 99% rename from tests/manual/trk/trkutils.h rename to src/plugins/debugger/symbian/trkutils.h index 7b1709498ce..6f1b280eb85 100644 --- a/tests/manual/trk/trkutils.h +++ b/src/plugins/debugger/symbian/trkutils.h @@ -197,7 +197,6 @@ QByteArray hexNumber(uint n, int digits = 0); QByteArray hexxNumber(uint n, int digits = 0); // prepends '0x', too uint swapEndian(uint in); - } // namespace trk #endif // DEBUGGER_TRK_UTILS diff --git a/tests/manual/trk/adapter.pro b/tests/manual/trk/adapter.pro index 22f4aa3cddb..9ee1a95d8f7 100644 --- a/tests/manual/trk/adapter.pro +++ b/tests/manual/trk/adapter.pro @@ -1,14 +1,20 @@ TEMPLATE = app +DEBUGGERHOME = ../../../src/plugins/debugger/symbian + +INCLUDEPATH *= $$DEBUGGERHOME + +UTILSDIR = ../../../src/libs QT = core network win32:CONFIG+=console -HEADERS += trkutils.h \ -trkfunctor.h \ -trkdevice.h \ +HEADERS += \ + $$DEBUGGERHOME/trkutils.h \ + $$DEBUGGERHOME/trkfunctor.h \ + $$PWD/trkdevice.h \ SOURCES += \ - adapter.cpp \ - trkutils.cpp \ - trkdevice.cpp + $$DEBUGGERHOME/trkutils.cpp \ + $$PWD/trkdevice.cpp \ + $$PWD/adapter.cpp \ diff --git a/tests/manual/trk/runner.cpp b/tests/manual/trk/runner.cpp index bf55d0b6f40..4724df4d179 100755 --- a/tests/manual/trk/runner.cpp +++ b/tests/manual/trk/runner.cpp @@ -27,8 +27,7 @@ ** **************************************************************************/ -#include "trkutils.h" -#include "trkdevicex.h" +#include "symbianadapter.h" #include #include @@ -114,1627 +113,6 @@ static QByteArray dumpRegister(int n, uint value) return ba; } -#define TrkCB(s) TrkCallback(this, &Adapter::s) -#define GdbCB(s) GdbCallback(this, &Adapter::s) - -struct GdbResult -{ - QByteArray data; -}; - -/////////////////////////////////////////////////////////////////////// -// -// Adapter -// -/////////////////////////////////////////////////////////////////////// - -class Adapter : public QObject -{ - Q_OBJECT - -public: - typedef TrkFunctor1 TrkCallback; - typedef TrkFunctor1 GdbCallback; - - Adapter(); - ~Adapter(); - void setGdbServerName(const QString &name); - QString gdbServerIP() const; - uint gdbServerPort() const; - 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) { m_bufferedMemoryRead = b; } - -public slots: - void startInferior(); - -signals: - void output(const QString &senderName, const QString &data); - -private slots: - void handleProcError(QProcess::ProcessError error); - void handleProcFinished(int exitCode, QProcess::ExitStatus exitStatus); - void handleProcStarted(); - void handleProcStateChanged(QProcess::ProcessState newState); - void run(); - void startGdb(); - -private: - friend class RunnerGui; - void connectProcess(QProcess *proc); - void sendOutput(QObject *sender, const QString &data); - void sendOutput(const QString &data) { sendOutput(0, data); } - - QString m_rfcommDevice; // /dev/rfcomm0 - QString m_gdbServerName; // 127.0.0.1:(2222+uid) - - QProcess m_gdbProc; - QProcess m_rfcommProc; - bool m_running; - -public: - // - // TRK - // - void sendTrkMessage(byte code, - TrkCallback callback = TrkCallback(), - const QByteArray &data = QByteArray(), - const QVariant &cookie = QVariant()); - Q_SLOT void handleTrkResult(const trk::TrkResult &data); - Q_SLOT void handleTrkError(const QString &msg); - - // convenience messages - void sendTrkAck(byte token); - - void handleCpuType(const TrkResult &result); - void handleCreateProcess(const TrkResult &result); - void handleClearBreakpoint(const TrkResult &result); - void handleSignalContinue(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; - QByteArray trkContinueMessage(); - QByteArray trkReadRegisterMessage(); - QByteArray trkReadMemoryMessage(uint addr, uint len); - QByteArray trkBreakpointMessage(uint addr, uint len, bool armMode = true); - void handleAndReportSetBreakpoint(const TrkResult &result); - void handleReadMemoryBuffered(const TrkResult &result); - void handleReadMemoryUnbuffered(const TrkResult &result); - void handleStepRange(const TrkResult &result); - void handleReadRegisters(const TrkResult &result); - void reportReadMemoryBuffered(const TrkResult &result); - void reportToGdb(const TrkResult &result); - - // set breakpoints behind gdb's back - void setTrkBreakpoint(const Breakpoint &bp); - void handleSetTrkBreakpoint(const TrkResult &result); - void handleSetTrkMainBreakpoint(const TrkResult &result); - - void readMemory(uint addr, uint len); - void interruptInferior(); - - TrkDevice m_trkDevice; - - // - // Gdb - // - struct GdbCommand - { - GdbCommand() : flags(0), callback(GdbCallback()), callbackName(0) {} - - int flags; - GdbCallback callback; - const char *callbackName; - QString command; - QVariant cookie; - //QTime postTime; - }; - - void sendGdbMessage(const QString &msg, - GdbCallback callback = GdbCallback(), - const QVariant &cookie = QVariant()); - Q_SLOT void handleGdbConnection(); - Q_SLOT void readGdbServerCommand(); - void readGdbResponse(); - void handleGdbServerCommand(const QByteArray &cmd); - void sendGdbServerMessage(const QByteArray &msg, - const QByteArray &logNote = QByteArray()); - void sendGdbServerMessageAfterTrkResponse(const QByteArray &msg, - const QByteArray &logNote = QByteArray()); - void sendGdbServerAck(); - bool sendGdbServerPacket(const QByteArray &packet, bool doFlush); - - Q_SLOT void handleGdbReadyReadStandardError(); - Q_SLOT void handleGdbReadyReadStandardOutput(); - void logMessage(const QString &msg, bool force = false); - Q_SLOT void trkLogMessage(const QString &msg); - - void handleInfoAddress(const GdbResult &result); - void handleInfoMainAddress(const GdbResult &result); - - QTcpServer m_gdbServer; - QPointer m_gdbConnection; - QByteArray m_gdbReadBuffer; - bool m_gdbAckMode; - - QHash m_gdbCookieForToken; - - // - // Rfcomm - // - Q_SLOT void handleRfcommReadyReadStandardError(); - Q_SLOT void handleRfcommReadyReadStandardOutput(); - - // Debuggee state - Q_SLOT void executeCommand(const QString &msg); - 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_bufferedMemoryRead; -}; - -Adapter::Adapter() -{ - m_running = false; - m_gdbAckMode = true; - m_verbose = 2; - m_registerEndianness = LittleEndian; - m_serialFrame = false; - m_bufferedMemoryRead = true; - m_rfcommDevice = "/dev/rfcomm0"; - - uid_t userId = getuid(); - m_gdbServerName = QString("127.0.0.1:%1").arg(2222 + userId); - - m_gdbProc.setObjectName("GDB PROCESS"); - connectProcess(&m_gdbProc); - connect(&m_gdbProc, SIGNAL(readyReadStandardError()), - this, SLOT(handleGdbReadyReadStandardError())); - connect(&m_gdbProc, SIGNAL(readyReadStandardOutput()), - this, SLOT(handleGdbReadyReadStandardOutput())); - - m_rfcommProc.setObjectName("RFCOMM PROCESS"); - connectProcess(&m_rfcommProc); - connect(&m_rfcommProc, SIGNAL(readyReadStandardError()), - this, SLOT(handleRfcommReadyReadStandardError())); - connect(&m_rfcommProc, SIGNAL(readyReadStandardOutput()), - this, SLOT(handleRfcommReadyReadStandardOutput())); - - if (m_verbose > 1) - m_trkDevice.setVerbose(true); - m_trkDevice.setSerialFrame(m_serialFrame); - - connect(&m_trkDevice, SIGNAL(logMessage(QString)), - this, SLOT(trkLogMessage(QString))); -} - -Adapter::~Adapter() -{ - m_gdbServer.close(); - logMessage("Shutting down.\n", true); -} - -void Adapter::trkLogMessage(const QString &msg) -{ - logMessage("TRK " + msg); -} - -void Adapter::setGdbServerName(const QString &name) -{ - m_gdbServerName = name; -} - -QString Adapter::gdbServerIP() const -{ - int pos = m_gdbServerName.indexOf(':'); - if (pos == -1) - return m_gdbServerName; - return m_gdbServerName.left(pos); -} - -uint Adapter::gdbServerPort() const -{ - int pos = m_gdbServerName.indexOf(':'); - if (pos == -1) - return 0; - return m_gdbServerName.mid(pos + 1).toUInt(); -} - -QByteArray Adapter::trkContinueMessage() -{ - QByteArray ba; - appendInt(&ba, m_session.pid); - appendInt(&ba, m_session.tid); - return ba; -} - -QByteArray Adapter::trkReadRegisterMessage() -{ - 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); - return ba; -} - -QByteArray Adapter::trkReadMemoryMessage(uint addr, uint len) -{ - QByteArray ba; - appendByte(&ba, 0x08); // Options, FIXME: why? - appendShort(&ba, len); - appendInt(&ba, addr); - appendInt(&ba, m_session.pid); - appendInt(&ba, m_session.tid); - return ba; -} - -void Adapter::startInferior() -{ - QString errorMessage; - if (!m_trkDevice.open(m_rfcommDevice, &errorMessage)) { - logMessage("LOOPING"); - QTimer::singleShot(1000, this, SLOT(startInferior())); - return; - } - - m_trkDevice.sendTrkInitialPing(); - sendTrkMessage(0x01); // Connect - sendTrkMessage(0x05, TrkCB(handleSupportMask)); - sendTrkMessage(0x06, TrkCB(handleCpuType)); - sendTrkMessage(0x04, TrkCB(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 - - QByteArray ba; - appendByte(&ba, 0); // ? - appendByte(&ba, 0); // ? - appendByte(&ba, 0); // ? - - QByteArray file("C:\\sys\\bin\\filebrowseapp.exe"); - appendString(&ba, file, TargetByteOrder); - sendTrkMessage(0x40, TrkCB(handleCreateProcess), ba); // Create Item - //sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, TrkCB(startGdbServer)); -} - -void Adapter::logMessage(const QString &msg, bool force) -{ - if (m_verbose || force) - emit output(QString(), 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(readGdbServerCommand())); -} - -static inline QString msgGdbPacket(const QString &p) -{ - return QLatin1String("gdb: ") + p; -} - -void Adapter::readGdbServerCommand() -{ - QByteArray packet = m_gdbConnection->readAll(); - m_gdbReadBuffer.append(packet); - - logMessage("gdb: -> " + 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 cmd = ba.left(pos); - ba.remove(0, pos + 3); - handleGdbServerCommand(cmd); - } -} - -bool Adapter::sendGdbServerPacket(const QByteArray &packet, bool doFlush) -{ - if (!m_gdbConnection) { - logMessage(QString::fromLatin1("Cannot write to gdb: No connection (%1)") - .arg(QString::fromLatin1(packet)), true); - return false; - } - if (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::sendGdbServerAck() -{ - if (!m_gdbAckMode) - return; - QByteArray packet = "+"; - logMessage("gdb: <- " + packet); - sendGdbServerPacket(packet, false); -} - -void Adapter::sendGdbServerMessage(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); - sendGdbServerPacket(packet, true); -} - -void Adapter::sendGdbServerMessageAfterTrkResponse(const QByteArray &msg, - const QByteArray &logNote) -{ - QByteArray ba = msg + char(1) + logNote; - sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, TrkCB(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)); - sendGdbServerMessage(message, note); -} - -QByteArray Adapter::trkBreakpointMessage(uint addr, uint len, bool armMode) -{ - 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, m_session.pid); - appendInt(&ba, 0xFFFFFFFF); - return ba; -} - -void Adapter::handleGdbServerCommand(const QByteArray &cmd) -{ - // http://sourceware.org/gdb/current/onlinedocs/gdb_34.html - if (0) {} - - else if (cmd == "!") { - sendGdbServerAck(); - //sendGdbServerMessage("", "extended mode not enabled"); - sendGdbServerMessage("OK", "extended mode enabled"); - } - - else if (cmd.startsWith("?")) { - logMessage(msgGdbPacket(QLatin1String("Query halted"))); - // Indicate the reason the target halted. - // The reply is the same as for step and continue. - sendGdbServerAck(); - // The command below will trigger fetching a stack trace while - // the process does not seem to be fully functional. Most notably - // the PC points to a 0x9..., which is not in "our" range - //sendGdbServerMessage("T05library:r;", "target halted (library load)"); - //sendGdbServerMessage("S05", "target halted (trap)"); - sendGdbServerMessage("S00", "target halted (trap)"); - //sendGdbServerMessage("O" + QByteArray("Starting...").toHex()); - } - - else if (cmd == "c") { - logMessage(msgGdbPacket(QLatin1String("Continue"))); - sendGdbServerAck(); - 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, TrkCallback(), ba); - } - - else if (cmd.startsWith("C")) { - 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. - sendGdbServerAck(); - bool ok = false; - uint signalNumber = cmd.mid(1).toInt(&ok, 16); - QByteArray ba; - appendInt(&ba, m_session.pid); - appendInt(&ba, m_session.tid); - sendTrkMessage(0x18, TrkCB(handleSignalContinue), ba, signalNumber); // Continue - } - - else if (cmd.startsWith("D")) { - sendGdbServerAck(); - sendGdbServerMessage("OK", "shutting down"); - qApp->quit(); - } - - else if (cmd == "g") { - logMessage(msgGdbPacket(QLatin1String("Read registers"))); - // Read general registers. - //sendGdbServerMessage("00000000", "read registers"); - sendGdbServerAck(); - sendTrkMessage(0x12, TrkCB(handleAndReportReadRegisters), - trkReadRegisterMessage()); - } - - else if (cmd.startsWith("Hc")) { - 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 - sendGdbServerAck(); - sendGdbServerMessage("OK", "Set current thread for step & continue"); - } - - else if (cmd.startsWith("Hg")) { - logMessage(msgGdbPacket(QLatin1String("Set thread"))); - // Set thread for subsequent operations (`m', `M', `g', `G', et.al.). - // for 'other operations. 0 - any thread - //$Hg0#df - sendGdbServerAck(); - m_session.currentThread = cmd.mid(2).toInt(0, 16); - sendGdbServerMessage("OK", "Set current thread " - + QByteArray::number(m_session.currentThread)); - } - - else if (cmd == "k") { - logMessage(msgGdbPacket(QLatin1String("kill"))); - // kill - sendGdbServerAck(); - QByteArray ba; - appendByte(&ba, 0); // ? - appendByte(&ba, 0); // Sub-command: Delete Process - appendInt(&ba, m_session.pid); - sendTrkMessage(0x41, TrkCallback(), ba, "Delete process"); // Delete Item - sendGdbServerMessageAfterTrkResponse("", "process killed"); - } - - else if (cmd.startsWith("m")) { - logMessage(msgGdbPacket(QLatin1String("Read memory"))); - // m addr,length - sendGdbServerAck(); - uint addr = 0, len = 0; - do { - const int pos = cmd.indexOf(','); - if (pos == -1) - break; - bool ok; - addr = cmd.mid(1, pos - 1).toUInt(&ok, 16); - if (!ok) - break; - len = cmd.mid(pos + 1).toUInt(&ok, 16); - if (!ok) - break; - } while (false); - if (len) { - readMemory(addr, len); - } else { - sendGdbServerMessage("E20", "Error " + cmd); - } - } - else if (cmd.startsWith("p")) { - logMessage(msgGdbPacket(QLatin1String("read register"))); - // 0xf == current instruction pointer? - //sendGdbServerMessage("0000", "current IP"); - sendGdbServerAck(); - #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 = cmd.mid(1).toInt(&ok, 16); - QByteArray logMsg = "Read Register"; - if (registerNumber == RegisterPSGdb) { - QByteArray ba; - appendInt(&ba, m_snapshot.registers[RegisterPSTrk], m_registerEndianness); - logMsg += dumpRegister(registerNumber, m_snapshot.registers[RegisterPSTrk]); - sendGdbServerMessage(ba.toHex(), logMsg); - } else if (registerNumber < RegisterCount) { - QByteArray ba; - appendInt(&ba, m_snapshot.registers[registerNumber], m_registerEndianness); - logMsg += dumpRegister(registerNumber, m_snapshot.registers[registerNumber]); - sendGdbServerMessage(ba.toHex(), logMsg); - } else { - sendGdbServerMessage("0000", "read single unknown register #" + QByteArray::number(registerNumber)); - //sendGdbServerMessage("E01", "read single unknown register"); - } - } - - else if (cmd == "qAttached") { - //$qAttached#8f - // 1: attached to an existing process - // 0: created a new process - sendGdbServerAck(); - sendGdbServerMessage("0", "new process created"); - //sendGdbServerMessage("1", "attached to existing process"); - //sendGdbServerMessage("E01", "new process created"); - } - - else if (cmd.startsWith("qC")) { - logMessage(msgGdbPacket(QLatin1String("query thread id"))); - // Return the current thread ID - //$qC#b4 - sendGdbServerAck(); - sendGdbServerMessageAfterTrkResponse("QC@TID@"); - } - - else if (cmd.startsWith("qSupported")) { - //$qSupported#37 - //$qSupported:multiprocess+#c6 - //logMessage("Handling 'qSupported'"); - sendGdbServerAck(); - if (0) - sendGdbServerMessage(QByteArray(), "nothing supported"); - else - sendGdbServerMessage( - "PacketSize=7cf;" - "QPassSignals+;" - "qXfer:libraries:read+;" - //"qXfer:auxv:read+;" - "qXfer:features:read+"); - } - - else if (cmd == "qPacketInfo") { - // happens with gdb 6.4.50.20060226-cvs / CodeSourcery - // deprecated by qSupported? - sendGdbServerAck(); - sendGdbServerMessage("", "FIXME: nothing?"); - } - - else if (cmd == "qOffsets") { - sendGdbServerAck(); - sendGdbServerMessageAfterTrkResponse("TextSeg=@CODESEG@;DataSeg=@DATASEG@"); - } - - else if (cmd == "qSymbol::") { - if (m_verbose) - logMessage(msgGdbPacket(QLatin1String("notify can handle symbol lookup"))); - // Notify the target that GDB is prepared to serve symbol lookup requests. - sendGdbServerAck(); - if (1) - sendGdbServerMessage("OK", "no further symbols needed"); - else - sendGdbServerMessage("qSymbol:" + QByteArray("_Z7E32Mainv").toHex(), "ask for more"); - } - - else if (cmd.startsWith("qXfer:features:read:target.xml:")) { - // $qXfer:features:read:target.xml:0,7ca#46...Ack - sendGdbServerAck(); - sendGdbServerMessage("lsymbianelf"); - } - - else if (cmd == "QStartNoAckMode") { - //$qSupported#37 - //logMessage("Handling 'QStartNoAckMode'"); - sendGdbServerAck(); - sendGdbServerMessage("OK", "ack no-ack mode"); - m_gdbAckMode = false; - } - - else if (cmd.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 - sendGdbServerAck(); - // FIXME: use the parameters - sendGdbServerMessage("OK", "passing signals accepted"); - } - - else if (cmd == "s" || cmd.startsWith("vCont;s")) { - logMessage(msgGdbPacket(QLatin1String("Step range"))); - logMessage(" from " + hexxNumber(m_snapshot.registers[RegisterPC])); - sendGdbServerAck(); - m_running = true; - QByteArray ba; - appendByte(&ba, 0x01); // options - appendInt(&ba, m_snapshot.registers[RegisterPC]); // start address - //appendInt(&ba, m_snapshot.registers[RegisterPC] + 4); // end address - appendInt(&ba, -1); // end address - appendInt(&ba, m_session.pid); - appendInt(&ba, m_session.tid); - sendTrkMessage(0x19, TrkCB(handleStepRange), ba, "Step range"); - // FIXME: should be triggered by "real" stop" - //sendGdbServerMessageAfterTrkResponse("S05", "target halted"); - } - - else if (cmd == "vCont?") { - // actions supported by the vCont packet - sendGdbServerAck(); - //sendGdbServerMessage("OK"); // we don't support vCont. - sendGdbServerMessage("vCont;c;C;s;S"); - } - - else if (cmd == "vCont;c") { - // vCont[;action[:thread-id]]...' - sendGdbServerAck(); - m_running = true; - sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE"); - } - - else if (cmd.startsWith("vKill")) { - // kill - sendGdbServerAck(); - QByteArray ba; - appendByte(&ba, 0); // Sub-command: Delete Process - appendInt(&ba, m_session.pid); - sendTrkMessage(0x41, TrkCallback(), ba, "Delete process"); // Delete Item - sendGdbServerMessageAfterTrkResponse("", "process killed"); - } - - else if (0 && cmd.startsWith("Z0,")) { - // Tell gdb we don't support software breakpoints - sendGdbServerMessage(""); - } - - else if (cmd.startsWith("Z0,") || cmd.startsWith("Z1,")) { - sendGdbServerAck(); - // Insert breakpoint - logMessage(msgGdbPacket(QLatin1String("Insert breakpoint"))); - // $Z0,786a4ccc,4#99 - const int pos = cmd.lastIndexOf(','); - bool ok = false; - const uint addr = cmd.mid(3, pos - 3).toInt(&ok, 16); - const uint len = cmd.mid(pos + 1).toInt(&ok, 16); - //qDebug() << "ADDR: " << hexNumber(addr) << " LEN: " << len; - 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 = trkBreakpointMessage(addr, len, m_session.pid); - sendTrkMessage(0x1B, TrkCB(handleAndReportSetBreakpoint), ba, addr); - //---TRK------------------------------------------------------ - // Command: 0x80 Acknowledge - // Error: 0x00 - // [80 09 00 00 00 00 0A] - } - - else if (cmd.startsWith("z0,") || cmd.startsWith("z1,")) { - sendGdbServerAck(); - // Remove breakpoint - logMessage(msgGdbPacket(QLatin1String("Remove breakpoint"))); - // $z0,786a4ccc,4#99 - const int pos = cmd.lastIndexOf(','); - bool ok = false; - const uint addr = cmd.mid(3, pos - 3).toInt(&ok, 16); - const uint len = cmd.mid(pos + 1).toInt(&ok, 16); - const uint bp = m_session.addressToBP[addr]; - if (bp == 0) { - logMessage(QString::fromLatin1("NO RECORDED BP AT 0x%1, %2") - .arg(addr, 0, 16).arg(len)); - } else { - //---IDE------------------------------------------------------ - // Command: 0x1C Clear Break - // [1C 25 00 00 00 0A 78 6A 43 40] - m_session.addressToBP.remove(addr); - QByteArray ba; - appendByte(&ba, 0x00); - appendShort(&ba, bp); - appendInt(&ba, addr); - sendTrkMessage(0x1C, TrkCB(handleClearBreakpoint), ba, addr); - } - } - - else if (cmd.startsWith("qPart:") || cmd.startsWith("qXfer:")) { - QByteArray data = cmd.mid(1 + cmd.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); - sendGdbServerMessage("E20", msg.toLatin1()); - handled = true; - } - } - } // auxv read - if (!handled) { - const QString msg = QLatin1String("FIXME unknown 'XFER'-request: ") - + QString::fromAscii(cmd); - logMessage(msgGdbPacket(msg), true); - sendGdbServerMessage("E20", msg.toLatin1()); - } - } // qPart/qXfer - else { - logMessage(msgGdbPacket(QLatin1String("FIXME unknown: ") - + QString::fromAscii(cmd))); - } -} - -void Adapter::executeCommand(const QString &msg) -{ - if (msg == "EI") { - sendGdbMessage("-exec-interrupt"); - } else if (msg == "C") { - sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE"); - } else if (msg == "R") { - sendTrkMessage(0x18, TrkCB(handleReadRegisters), - trkReadRegisterMessage(), "READ REGS"); - } else if (msg == "I") { - interruptInferior(); - } else { - logMessage("EXECUTING GDB COMMAND " + msg); - sendGdbMessage(msg); - } -} - -void Adapter::sendTrkMessage(byte code, TrkCallback callback, - const QByteArray &data, const QVariant &cookie) -{ - m_trkDevice.sendTrkMessage(code, callback, data, cookie); -} - -void Adapter::sendTrkAck(byte token) -{ - logMessage(QString("SENDING ACKNOWLEDGEMENT FOR TOKEN %1").arg(int(token))); - m_trkDevice.sendTrkAck(token); -} - -void Adapter::handleTrkError(const QString &msg) -{ - logMessage("## TRK ERROR: " + msg); -} - -void Adapter::handleTrkResult(const TrkResult &result) -{ - if (result.isDebugOutput) { - sendTrkAck(result.token); - logMessage(QLatin1String("APPLICATION OUTPUT: ") + - QString::fromAscii(result.data)); - sendGdbServerMessage("O" + result.data.toHex()); - return; - } - logMessage("READ TRK " + result.toString()); - 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); - const uint pid = extractInt(data + 4); - const uint tid = extractInt(data + 8); - 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 - if (m_running) { - m_running = false; - sendGdbServerMessage("S05", "Target stopped"); - } - } else { - logMessage(QLatin1String("Ignoring stop at 0")); - } - 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); - // type: 1 byte; for dll item, this value is 2. - const byte type = result.data.at(1); - const uint pid = extractInt(data + 2); - const uint tid = extractInt(data + 6); - const uint codeseg = extractInt(data + 10); - const uint dataseg = extractInt(data + 14); - const uint len = extractShort(data + 18); - const QByteArray name = result.data.mid(20, len); // 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 << " CODE: " << hexxNumber(codeseg); - str << " DATA: " << hexxNumber(dataseg); - str << " NAME: '" << name << '\''; - logMessage(logMsg); - // This lets gdb trigger a register update etc - //sendGdbServerMessage("T05library:r;"); - sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE"); - break; - } - case 0xa1: { // NotifyDeleted - const ushort itemType = extractByte(result.data.data() + 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); - if (itemType == 0) { - sendGdbServerMessage("W00", "Process exited"); - //sendTrkMessage(0x02, TrkCB(handleDisconnect)); - } - 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 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) -{ - //---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 = trkBreakpointMessage(m_session.codeseg + bp.offset, - 1, m_session.pid); - sendTrkMessage(0x1B, TrkCB(handleSetTrkBreakpoint), ba); - - //---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()); - logMessage("SET BREAKPOINT " + hexxNumber(bpnr) - + 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); - - logMessage("PID: " + hexxNumber(m_session.pid)); - logMessage("TID: " + hexxNumber(m_session.tid)); - logMessage("COD: " + hexxNumber(m_session.codeseg)); - logMessage("DAT: " + hexxNumber(m_session.dataseg)); - - QByteArray ba; - appendInt(&ba, m_session.pid); - appendInt(&ba, m_session.tid); - - startGdb(); - - -#if 0 - //---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, TrkCB(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, TrkCB(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, TrkCB(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, TrkCB(handleStop), - // "01 " + formatInt(m_session.pid) + formatInt(m_session.tid)); -} - -void Adapter::handleReadRegisters(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...] - if (result.errorCode()) { - logMessage("ERROR: " + result.errorString()); - return; - } - 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); -} - -void Adapter::handleAndReportReadRegisters(const TrkResult &result) -{ - handleReadRegisters(result); - 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) { - logMsg += dumpRegister(i, m_snapshot.registers[i]); - logMsg += ' '; - } - } - sendGdbServerMessage(ba, logMsg); -} - -static inline QString msgMemoryReadError(int code, uint addr, uint len = 0) -{ - const QString lenS = len ? QString::number(len) : QLatin1String(""); - return QString::fromLatin1("Memory read error %1 at: 0x%2 %3") - .arg(code).arg(addr, 0 ,16).arg(lenS); -} - -void Adapter::handleReadMemoryBuffered(const TrkResult &result) -{ - if (extractShort(result.data.data() + 1) + 3 != result.data.size()) - logMessage("\n BAD MEMORY RESULT: " + result.data.toHex() + "\n"); - const uint blockaddr = result.cookie.toUInt(); - if (const int errorCode = result.errorCode()) { - logMessage(msgMemoryReadError(errorCode, blockaddr)); - return; - } - const QByteArray ba = result.data.mid(3); - m_snapshot.memory.insert(blockaddr, ba); -} - -// Format log message for memory access with some smartness about registers -QByteArray Adapter::memoryReadLogMessage(uint addr, uint len, const QByteArray &ba) const -{ - QByteArray logMsg = "memory contents"; - if (m_verbose > 1) { - logMsg += " addr: " + hexxNumber(addr); - // 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; -} - -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()); - } - const int previousChunkOverlap = addr % MemoryChunkSize; - if (previousChunkOverlap != 0 && ba.size() > previousChunkOverlap) - ba.remove(0, previousChunkOverlap); - if (ba.size() > int(len)) - ba.truncate(len); - - if (ba.isEmpty()) { - ba = "E20"; - sendGdbServerMessage(ba, msgMemoryReadError(32, addr, len).toLatin1()); - } else { - sendGdbServerMessage(ba.toHex(), memoryReadLogMessage(addr, len, ba)); - } -} - -void Adapter::handleReadMemoryUnbuffered(const TrkResult &result) -{ - //logMessage("UNBUFFERED MEMORY READ: " + stringFromArray(result.data)); - const uint blockaddr = result.cookie.toUInt(); - if (extractShort(result.data.data() + 1) + 3 != result.data.size()) - logMessage("\n BAD MEMORY RESULT: " + result.data.toHex() + "\n"); - if (const int errorCode = result.errorCode()) { - const QByteArray ba = "E20"; - sendGdbServerMessage(ba, msgMemoryReadError(32, blockaddr).toLatin1()); - } else { - const QByteArray ba = result.data.mid(3); - sendGdbServerMessage(ba.toHex(), memoryReadLogMessage(blockaddr, ba.size(), ba)); - } -} - -void Adapter::handleStepRange(const TrkResult &result) -{ - // [80 0f 00] - if (result.errorCode()) { - logMessage("ERROR: " + result.errorString()); - return; - } - logMessage("STEPPING FINISHED "); - //sendGdbServerMessage("S05", "Stepping finished"); -} - -void Adapter::handleAndReportSetBreakpoint(const TrkResult &result) -{ - //---TRK------------------------------------------------------ - // Command: 0x80 Acknowledge - // Error: 0x00 - // [80 09 00 00 00 00 0A] - uint bpnr = extractByte(result.data.data()); - uint addr = result.cookie.toUInt(); - m_session.addressToBP[addr] = bpnr; - logMessage("SET BREAKPOINT " + hexxNumber(bpnr) + " " - + stringFromArray(result.data.data())); - sendGdbServerMessage("OK"); - //sendGdbServerMessage("OK"); -} - -void Adapter::handleClearBreakpoint(const TrkResult &result) -{ - logMessage("CLEAR BREAKPOINT "); - if (result.errorCode()) { - logMessage("ERROR: " + result.errorString()); - //return; - } - //---TRK------------------------------------------------------ - // Command: 0x80 Acknowledge - // Error: 0x00 - // [80 09 00 00 00 00 0A] - // FIXME: - sendGdbServerMessage("OK"); -} - -void Adapter::handleSignalContinue(const TrkResult &result) -{ - int signalNumber = result.cookie.toInt(); - logMessage(" HANDLE SIGNAL CONTINUE: " + stringFromArray(result.data)); - logMessage("NUMBER" + QString::number(signalNumber)); - sendGdbServerMessage("O" + QByteArray("Console output").toHex()); - sendGdbServerMessage("W81"); // "Process exited with result 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::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, TrkCB(handleReadMemoryBuffered), - trkReadMemoryMessage(blockaddr, MemoryChunkSize), - QVariant(blockaddr)); - } - } - const qulonglong cookie = (qulonglong(addr) << 32) + len; - sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, TrkCB(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, TrkCB(handleReadMemoryUnbuffered), - trkReadMemoryMessage(addr, len), QVariant(addr)); - } -} - -void Adapter::interruptInferior() -{ - QByteArray ba; - // stop the thread (2) or the process (1) or the whole system (0) - // We choose 2, as 1 does not seem to work. - appendByte(&ba, 2); - appendInt(&ba, m_session.pid); - appendInt(&ba, m_session.tid); // threadID: 4 bytes Variable number of bytes. - sendTrkMessage(0x1a, TrkCallback(), 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(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::handleProcStarted() -{ - sendOutput(sender(), QString("Process Started")); -} - -void Adapter::handleProcStateChanged(QProcess::ProcessState newState) -{ - sendOutput(sender(), QString("Process State %1").arg(newState)); -} - -void Adapter::run() -{ - sendOutput("### Starting Adapter"); - m_rfcommProc.start("rfcomm listen " + m_rfcommDevice + " 1"); - m_rfcommProc.waitForStarted(); - - connect(&m_trkDevice, SIGNAL(messageReceived(trk::TrkResult)), - this, SLOT(handleTrkResult(trk::TrkResult))); - connect(&m_trkDevice, SIGNAL(error(QString)), - this, SLOT(handleTrkError(QString))); - - startInferior(); -} - -void Adapter::startGdb() -{ - 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())); - - 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(); - - sendGdbMessage("set confirm off"); // confirm potentially dangerous operations? - sendGdbMessage("set endian little"); - sendGdbMessage("set remotebreak on"); - sendGdbMessage("set breakpoint pending on"); - sendGdbMessage("set trust-readonly-sections on"); - //sendGdbMessage("mem 0 ~0ll rw 8 cache"); - - // FIXME: "remote noack" does not seem to be supported on cs-gdb? - //sendGdbMessage("set remote noack-packet"); - - // FIXME: creates a lot of noise a la '&"putpkt: Junk: Ack " &' - // even thouhg the communication seems sane - //sendGdbMessage("set debug remote 1"); // creates l - - //sendGdbMessage("target remote " + m_gdbServerName); -// sendGdbMessage("target extended-remote " + m_gdbServerName); - //sendGdbMessage("target extended-async " + m_gdbServerName); - //sendGdbMessage("set remotecache ...") // Set cache use for remote targets - //sendGdbMessage("file filebrowseapp.sym"); -// sendGdbMessage("add-symbol-file filebrowseapp.sym " + m_baseAddress); -// sendGdbMessage("symbol-file filebrowseapp.sym"); -// sendGdbMessage("print E32Main"); -// sendGdbMessage("break E32Main"); - //sendGdbMessage("continue"); - //sendGdbMessage("info files"); - //sendGdbMessage("file filebrowseapp.sym -readnow"); - - sendGdbMessage("add-symbol-file filebrowseapp.sym " - + hexxNumber(m_session.codeseg)); - sendGdbMessage("symbol-file filebrowseapp.sym"); - - // -symbol-info-address not implemented in cs-gdb 6.4-6.8 (at least) - sendGdbMessage("info address E32Main", - GdbCB(handleInfoMainAddress)); - sendGdbMessage("info address CFileBrowseAppUi::HandleCommandL", - GdbCB(handleInfoMainAddress)); - -#if 1 - // FIXME: Gdb based version. That's the goal - //sendGdbMessage("break E32Main"); - //sendGdbMessage("continue"); - //sendTrkMessage(0x18, TrkCB(handleContinueAfterCreateProcess), - // trkContinueMessage(), "CONTINUE"); -#else - // Directly talk to TRK. Works for now... - sendGdbMessage("break E32Main"); - sendGdbMessage("break filebrowseappui.cpp:39"); - // sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE"); -#endif -} - -void Adapter::sendGdbMessage(const QString &msg, GdbCallback callback, - const QVariant &cookie) -{ - static int token = 0; - ++token; - GdbCommand data; - data.command = msg; - data.callback = callback; - data.cookie = cookie; - m_gdbCookieForToken[token] = data; - logMessage(QString("<- GDB: %1 %2").arg(token).arg(msg)); - m_gdbProc.write(QString("%1%2\n").arg(token).arg(msg).toLatin1()); -} - -void Adapter::handleGdbReadyReadStandardError() -{ - QByteArray ba = qobject_cast(sender())->readAllStandardError(); - sendOutput(sender(), QString("stderr: %1").arg(QString::fromLatin1(ba))); -} - -void Adapter::handleGdbReadyReadStandardOutput() -{ - QByteArray ba = qobject_cast(sender())->readAllStandardOutput(); - QString str = QString::fromLatin1(ba); - // FIXME: fragile. merge with gdbengine logic -#if 0 - QRegExp re(QString(".*([0-9]+)[^]done.*")); - int pos = re.indexIn(str); - if (pos == -1) { - logMessage(QString("\n-> GDB: %1 %**% %2 %**%\n").arg(str).arg(pos)); - return; - } - int token = re.cap(1).toInt(); - logMessage(QString("\n-> GDB: %1 %2##\n").arg(token).arg(QString::fromLatin1(ba))); - if (!token) - return; - GdbCommand cmd = m_gdbCookieForToken.take(token); - logMessage("FOUND CALLBACK FOR " + cmd.command); - GdbResult result; - result.data = ba; - if (!cmd.callback.isNull()) - cmd.callback(result); -#else - bool ok; - QRegExp re(QString("Symbol .._Z7E32Mainv.. is a function at address 0x(.*)\\.")); - if (re.indexIn(str) != -1) { - logMessage(QString("-> GDB MAIN BREAKPOINT: %1").arg(re.cap(1))); - uint addr = re.cap(1).toInt(&ok, 16); - sendTrkMessage(0x1B, TrkCallback(), trkBreakpointMessage(addr, 1)); - return; - } - QRegExp re1(QString("Symbol .._ZN16CFileBrowseAppUi14HandleCommandLEi.. is a function at address 0x(.*)\\.")); - if (re1.indexIn(str) != -1) { - logMessage(QString("-> GDB USER BREAKPOINT: %1").arg(re1.cap(1))); - uint addr = re1.cap(1).toInt(&ok, 16); - sendTrkMessage(0x1B, TrkCallback(), trkBreakpointMessage(addr, 1)); - - sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE"); - sendGdbMessage("target remote " + m_gdbServerName); - return; - } - logMessage(QString("-> GDB: %1").arg(str)); -#endif -} - -void Adapter::handleInfoMainAddress(const GdbResult &result) -{ - Q_UNUSED(result); -} - -void Adapter::handleSetTrkMainBreakpoint(const TrkResult &result) -{ - Q_UNUSED(result); -/* - //---TRK------------------------------------------------------ - // [80 09 00 00 00 00 0A] - const uint bpnr = extractInt(result.data.data()); - logMessage("SET MAIN BREAKPOINT " + hexxNumber(bpnr) - + stringFromArray(result.data.data())); -*/ -} - -void Adapter::handleInfoAddress(const GdbResult &result) -{ - Q_UNUSED(result); - // FIXME -} - -void Adapter::handleRfcommReadyReadStandardError() -{ - QByteArray ba = qobject_cast(sender())->readAllStandardError(); - sendOutput(sender(), QString("stderr: %1").arg(QString::fromLatin1(ba))); -} - -void Adapter::handleRfcommReadyReadStandardOutput() -{ - QByteArray ba = qobject_cast(sender())->readAllStandardOutput(); - sendOutput(sender(), QString("stdout: %1").arg(QString::fromLatin1(ba))); -} /////////////////////////////////////////////////////////////////////// // @@ -1787,12 +165,14 @@ public slots: // /////////////////////////////////////////////////////////////////////// +using namespace Debugger::Internal; + class RunnerGui : public QMainWindow { Q_OBJECT public: - RunnerGui(Adapter *adapter); + RunnerGui(SymbianAdapter *adapter); private slots: void executeStepICommand() { executeCommand("-exec-step-instruction"); } @@ -1806,7 +186,7 @@ private: void executeCommand(const QString &cmd) { m_adapter->executeCommand(cmd); } void connectAction(QAction *&, QString name, const char *slot); - Adapter *m_adapter; + SymbianAdapter *m_adapter; TextEdit m_textEdit; QToolBar m_toolBar; QAction *m_stepIAction; @@ -1817,7 +197,7 @@ private: QAction *m_continueAction; }; -RunnerGui::RunnerGui(Adapter *adapter) +RunnerGui::RunnerGui(SymbianAdapter *adapter) : m_adapter(adapter) { resize(1200, 1000); @@ -1855,7 +235,7 @@ void RunnerGui::connectAction(QAction *&action, QString name, const char *slot) int main(int argc, char *argv[]) { QApplication app(argc, argv); - Adapter adapter; + SymbianAdapter adapter; RunnerGui gui(&adapter); gui.show(); QTimer::singleShot(0, &adapter, SLOT(run())); diff --git a/tests/manual/trk/runner.pro b/tests/manual/trk/runner.pro index 4ced7ccd71a..21461da2d94 100644 --- a/tests/manual/trk/runner.pro +++ b/tests/manual/trk/runner.pro @@ -1,15 +1,21 @@ TEMPLATE = app +DEBUGGERHOME = ../../../src/plugins/debugger/symbian +INCLUDEPATH *= $$DEBUGGERHOME + QT += network win32:CONFIG+=console HEADERS += \ - trkutils.h \ - trkdevicex.h \ + $$DEBUGGERHOME/../gdb/gdbprocessbase.h \ + $$DEBUGGERHOME/trkutils.h \ + $$DEBUGGERHOME/trkclient.h \ + $$DEBUGGERHOME/symbianadapter.h \ SOURCES += \ - runner.cpp \ - trkutils.cpp \ - trkdevicex.cpp \ + $$DEBUGGERHOME/trkutils.cpp \ + $$DEBUGGERHOME/trkclient.cpp \ + $$DEBUGGERHOME/symbianadapter.cpp \ + $$PWD/runner.cpp \ diff --git a/tests/manual/trk/trklauncher.pri b/tests/manual/trk/trklauncher.pri index 3593888b861..74b37e42e3c 100644 --- a/tests/manual/trk/trklauncher.pri +++ b/tests/manual/trk/trklauncher.pri @@ -1,9 +1,15 @@ DEFINES += DEBUG_TRK=0 -INCLUDEPATH *= $$PWD -SOURCES += $$PWD/launcher.cpp \ - $$PWD/trkutils.cpp \ - $$PWD/trkdevice.cpp -HEADERS += $$PWD/trkutils.h \ - $$PWD/trkfunctor.h \ +DEBUGGERHOME = ../../../src/plugins/debugger/symbian + +INCLUDEPATH *= $$DEBUGGERHOME + +SOURCES += \ + $$DEBUGGERHOME/trkutils.cpp \ + $$PWD/trkdevice.cpp \ + $$PWD/launcher.cpp \ + +HEADERS += \ + $$DEBUGGERHOME/trkutils.h \ + $$DEBUGGERHOME/trkfunctor.h \ $$PWD/trkdevice.h \ $$PWD/launcher.h diff --git a/tests/manual/trk/trkserver.pro b/tests/manual/trk/trkserver.pro index a333dc2c363..6fbbc85c06c 100644 --- a/tests/manual/trk/trkserver.pro +++ b/tests/manual/trk/trkserver.pro @@ -1,12 +1,17 @@ TEMPLATE = app +DEBUGGERHOME = ../../../src/plugins/debugger/symbian + QT = core network win32:CONFIG+=console +INCLUDEPATH *= $$DEBUGGERHOME + + HEADERS += \ - trkutils.h + $$DEBUGGERHOME/trkutils.h SOURCES += \ - trkutils.cpp \ - trkserver.cpp + $$DEBUGGERHOME/trkutils.cpp \ + $$PWD/trkserver.cpp