1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights. These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
32 **************************************************************************/
34 #include "trkgdbadapter.h"
36 #include "debuggerstartparameters.h"
39 #include "symbiandevicemanager.h"
40 #include "s60debuggerbluetoothstarter.h"
41 #include "bluetoothlistener_gui.h"
43 #include "registerhandler.h"
44 #include "threadshandler.h"
45 #include "debuggeractions.h"
46 #include "debuggercore.h"
47 #include "debuggerstringutils.h"
48 #include "watchutils.h"
49 #ifndef STANDALONE_RUNNER
50 #include "gdbengine.h"
53 #include <utils/qtcassert.h>
54 #include <utils/qtcprocess.h>
55 #include <utils/savedaction.h>
57 #include <QtCore/QTimer>
58 #include <QtCore/QDir>
59 #include <QtNetwork/QTcpServer>
60 #include <QtNetwork/QTcpSocket>
63 # include "dbgwinutils.h"
65 # include <sys/types.h>
69 #define CB(callback) \
70 static_cast<GdbEngine::AdapterCallback>(&TrkGdbAdapter::callback), \
73 #define TrkCB(s) TrkCallback(this, &TrkGdbAdapter::s)
79 using namespace Symbian;
81 static inline void appendByte(QByteArray *ba, trk::byte b) { ba->append(b); }
83 ///////////////////////////////////////////////////////////////////////////
87 ///////////////////////////////////////////////////////////////////////////
90 * TRK does not report thread creation/termination. So, if we receive
91 * a stop in a different thread, we store an additional thread in snapshot.
92 * When continuing in trkContinueAll(), we delete this thread, since we cannot
93 * know whether it will exist at the next stop.
94 * Also note that threads continue running in Symbian even if one crashes.
95 * TODO: Stop all threads once one stops? */
97 TrkGdbAdapter::TrkGdbAdapter(GdbEngine *engine) :
98 AbstractGdbAdapter(engine),
103 m_bufferedMemoryRead = true;
104 // Disable buffering if gdb's dcache is used.
105 m_bufferedMemoryRead = false;
111 const unsigned long portOffset = winGetCurrentProcessId() % 100;
113 const uid_t portOffset = getuid();
115 m_gdbServerName = _("127.0.0.1:%1").arg(2222 + portOffset);
117 setVerbose(debuggerCore()->boolSetting(VerboseLog));
119 connect(debuggerCore()->action(VerboseLog), SIGNAL(valueChanged(QVariant)),
120 this, SLOT(setVerbose(QVariant)));
123 TrkGdbAdapter::~TrkGdbAdapter()
126 logMessage("Shutting down.\n");
129 void TrkGdbAdapter::setVerbose(const QVariant &value)
131 setVerbose(value.toInt());
134 void TrkGdbAdapter::setVerbose(int verbose)
137 if (!m_trkDevice.isNull())
138 m_trkDevice->setVerbose(m_verbose);
141 void TrkGdbAdapter::trkLogMessage(const QString &msg)
143 logMessage("TRK " + msg);
146 void TrkGdbAdapter::setGdbServerName(const QString &name)
148 m_gdbServerName = name;
151 QString TrkGdbAdapter::gdbServerIP() const
153 int pos = m_gdbServerName.indexOf(':');
155 return m_gdbServerName;
156 return m_gdbServerName.left(pos);
159 uint TrkGdbAdapter::gdbServerPort() const
161 int pos = m_gdbServerName.indexOf(':');
164 return m_gdbServerName.mid(pos + 1).toUInt();
167 QByteArray TrkGdbAdapter::trkContinueMessage(uint threadId)
170 appendInt(&ba, m_session.pid);
171 appendInt(&ba, threadId);
175 QByteArray TrkGdbAdapter::trkWriteRegisterMessage(trk::byte reg, uint value)
178 appendByte(&ba, 0); // ?
179 appendShort(&ba, reg);
180 appendShort(&ba, reg);
181 appendInt(&ba, m_session.pid);
182 appendInt(&ba, m_session.tid);
183 appendInt(&ba, value);
187 QByteArray TrkGdbAdapter::trkReadMemoryMessage(const MemoryRange &range)
189 return trk::Launcher::readMemoryMessage(m_session.pid, m_session.tid, range.from, range.size());
192 QByteArray TrkGdbAdapter::trkWriteMemoryMessage(uint addr, const QByteArray &data)
195 ba.reserve(11 + data.size());
196 appendByte(&ba, 0x08); // Options, FIXME: why?
197 appendShort(&ba, data.size());
198 appendInt(&ba, addr);
199 appendInt(&ba, m_session.pid);
200 appendInt(&ba, m_session.tid);
205 QByteArray TrkGdbAdapter::trkStepRangeMessage()
207 //qDebug() << "STEP ON " << hexxNumber(m_snapshot.registers[RegisterPC]);
208 uint from = m_snapshot.lineFromAddress;
209 uint to = m_snapshot.lineToAddress;
210 const uint pc = m_snapshot.registerValue(m_session.tid, RegisterPC);
211 trk::byte option = 0x01; // Step into.
212 if (m_snapshot.stepOver)
213 option = 0x11; // Step over.
214 if (from <= pc && pc <= to) {
215 //to = qMax(to - 4, from);
216 //to = qMax(to - 4, from);
217 showMessage(_("STEP IN ") + hexxNumber(from) + ' ' + hexxNumber(to)
218 + _(" INSTEAD OF ") + hexxNumber(pc));
223 logMessage(QString::fromLatin1("Stepping from 0x%1 to 0x%2 (current PC=0x%3), option 0x%4").
224 arg(from, 0, 16).arg(to, 0, 16).arg(pc).arg(option, 0, 16));
227 appendByte(&ba, option);
228 appendInt(&ba, from); // Start address
229 appendInt(&ba, to); // End address
230 appendInt(&ba, m_session.pid);
231 appendInt(&ba, m_session.tid);
235 QByteArray TrkGdbAdapter::trkDeleteProcessMessage()
239 appendByte(&ba, 0); // ?
240 appendByte(&ba, 0); // Sub-command: Delete Process
241 appendInt(&ba, m_session.pid);
245 QByteArray TrkGdbAdapter::trkInterruptMessage()
249 // Stop the thread (2) or the process (1) or the whole system (0).
250 // We choose 2, as 1 does not seem to work.
252 appendInt(&ba, m_session.pid);
253 appendInt(&ba, m_session.mainTid); // threadID: 4 bytes Variable number of bytes.
257 void TrkGdbAdapter::emitDelayedInferiorSetupFailed(const QString &msg)
259 m_adapterFailMessage = msg;
260 QTimer::singleShot(0, this, SLOT(slotEmitDelayedInferiorSetupFailed()));
263 void TrkGdbAdapter::slotEmitDelayedInferiorSetupFailed()
265 m_engine->notifyInferiorSetupFailed(m_adapterFailMessage);
269 void TrkGdbAdapter::logMessage(const QString &msg, int logChannel)
271 if (m_verbose || logChannel != LogDebug)
272 showMessage("TRK LOG: " + msg, logChannel);
273 MEMORY_DEBUG("GDB: " << msg);
279 void TrkGdbAdapter::handleGdbConnection()
281 logMessage("HANDLING GDB CONNECTION");
282 QTC_ASSERT(m_gdbConnection == 0, /**/);
283 m_gdbConnection = m_gdbServer->nextPendingConnection();
284 QTC_ASSERT(m_gdbConnection, return);
285 connect(m_gdbConnection, SIGNAL(disconnected()),
286 m_gdbConnection, SLOT(deleteLater()));
287 connect(m_gdbConnection, SIGNAL(readyRead()),
288 this, SLOT(readGdbServerCommand()));
291 static inline QString msgGdbPacket(const QString &p)
293 return QLatin1String("gdb: ") + p;
296 void TrkGdbAdapter::readGdbServerCommand()
298 QTC_ASSERT(m_gdbConnection, return);
299 QByteArray packet = m_gdbConnection->readAll();
300 m_gdbReadBuffer.append(packet);
302 logMessage("gdb: -> " + currentTime() + ' ' + QString::fromAscii(packet));
303 if (packet != m_gdbReadBuffer)
304 logMessage(QLatin1String("buffer: ") + m_gdbReadBuffer);
306 QByteArray &ba = m_gdbReadBuffer;
308 char code = ba.at(0);
317 logMessage("NAK: Retransmission requested", LogError);
318 // This seems too harsh.
319 //emit adapterCrashed("Communication problem encountered.");
323 if (code == char(0x03)) {
324 logMessage("INTERRUPT RECEIVED");
330 logMessage("Broken package (2) " + quoteUnprintableLatin1(ba)
331 + hexNumber(code), LogError);
335 int pos = ba.indexOf('#');
337 logMessage("Invalid checksum format in "
338 + quoteUnprintableLatin1(ba), LogError);
343 uint checkSum = ba.mid(pos + 1, 2).toUInt(&ok, 16);
345 logMessage("Invalid checksum format 2 in "
346 + quoteUnprintableLatin1(ba), LogError);
350 //logMessage(QString("Packet checksum: %1").arg(checkSum));
352 for (int i = 0; i < pos; ++i)
355 if (sum != checkSum) {
356 logMessage(QString("ERROR: Packet checksum wrong: %1 %2 in "
357 + quoteUnprintableLatin1(ba)).arg(checkSum).arg(sum), LogError);
360 QByteArray cmd = ba.left(pos);
361 ba.remove(0, pos + 3);
362 handleGdbServerCommand(cmd);
366 bool TrkGdbAdapter::sendGdbServerPacket(const QByteArray &packet, bool doFlush)
368 if (!m_gdbConnection) {
369 logMessage(_("Cannot write to gdb: No connection (%1)")
370 .arg(_(packet)), LogError);
373 if (m_gdbConnection->state() != QAbstractSocket::ConnectedState) {
374 logMessage(_("Cannot write to gdb: Not connected (%1)")
375 .arg(_(packet)), LogError);
378 if (m_gdbConnection->write(packet) == -1) {
379 logMessage(_("Cannot write to gdb: %1 (%2)")
380 .arg(m_gdbConnection->errorString()).arg(_(packet)), LogError);
384 m_gdbConnection->flush();
388 void TrkGdbAdapter::sendGdbServerAck()
392 logMessage("gdb: <- +");
393 sendGdbServerPacket(QByteArray(1, '+'), false);
396 void TrkGdbAdapter::sendGdbServerMessage(const QByteArray &msg, const QByteArray &logNote)
399 for (int i = 0; i != msg.size(); ++i)
403 qsnprintf(checkSum, sizeof(checkSum) - 1, "%02x ", sum);
405 //logMessage(QString("Packet checksum: %1").arg(sum));
411 packet.append(checkSum);
412 int pad = qMax(0, 24 - packet.size());
413 logMessage("gdb: <- " + currentTime() + ' ' + packet + QByteArray(pad, ' ') + logNote);
414 sendGdbServerPacket(packet, true);
417 void TrkGdbAdapter::sendGdbServerMessageAfterTrkResponse(const QByteArray &msg,
418 const QByteArray &logNote)
420 QByteArray ba = msg + char(1) + logNote;
421 sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, TrkCB(reportToGdb), "", ba); // Answer gdb
424 void TrkGdbAdapter::reportToGdb(const TrkResult &result)
426 QByteArray message = result.cookie.toByteArray();
428 int pos = message.lastIndexOf(char(1)); // HACK
430 note = message.mid(pos + 1);
431 message = message.left(pos);
433 message.replace("@CODESEG@", hexNumber(m_session.codeseg));
434 message.replace("@DATASEG@", hexNumber(m_session.dataseg));
435 message.replace("@PID@", hexNumber(m_session.pid));
436 message.replace("@TID@", hexNumber(m_session.tid));
437 sendGdbServerMessage(message, note);
440 QByteArray TrkGdbAdapter::trkBreakpointMessage(uint addr, uint len, bool armMode)
443 appendByte(&ba, 0x82); // unused option
444 appendByte(&ba, armMode /*bp.mode == ArmMode*/ ? 0x00 : 0x01);
445 appendInt(&ba, addr);
447 appendInt(&ba, 0x00000001);
448 appendInt(&ba, m_session.pid);
449 appendInt(&ba, 0xFFFFFFFF);
453 static QByteArray msgStepRangeReceived(unsigned from, unsigned to, bool over)
455 QByteArray rc = "Stepping range received for step ";
456 rc += over ? "over" : "into";
458 rc += QByteArray::number(from, 16);
460 rc += QByteArray::number(to, 16);
465 void TrkGdbAdapter::handleGdbServerCommand(const QByteArray &cmd)
467 // http://sourceware.org/gdb/current/onlinedocs/gdb_34.html
470 else if (cmd == "!") {
472 //sendGdbServerMessage("", "extended mode not enabled");
473 sendGdbServerMessage("OK", "extended mode enabled");
476 else if (cmd.startsWith('?')) {
477 logMessage(msgGdbPacket(QLatin1String("Query halted")));
478 // Indicate the reason the target halted.
479 // The reply is the same as for step and continue.
481 // The command below will trigger fetching a stack trace while
482 // the process does not seem to be fully functional. Most notably
483 // the PC points to a 0x9..., which is not in "our" range
484 //sendGdbServerMessage("T05library:r;", "target halted (library load)");
485 //sendGdbServerMessage("S05", "target halted (trap)");
486 sendGdbServerMessage("S00", "target halted (trap)");
487 //sendGdbServerMessage("O" + QByteArray("Starting...").toHex());
490 else if (cmd == "c") {
491 logMessage(msgGdbPacket(QLatin1String("Continue")));
494 trkContinueAll("gdb 'c'");
497 else if (cmd.startsWith('C')) {
498 logMessage(msgGdbPacket(QLatin1String("Continue with signal")));
499 // C sig[;addr] Continue with signal sig (hex signal number)
500 //Reply: See section D.3 Stop Reply Packets, for the reply specifications.
501 //TODO: Meaning of the message is not clear.
504 const uint signalNumber = cmd.mid(1).toUInt(&ok, 16);
505 logMessage(_("Not implemented 'Continue with signal' %1: ")
506 .arg(signalNumber), LogWarning);
507 sendGdbServerMessage('O' + QByteArray("Console output").toHex());
508 sendGdbServerMessage("W81"); // "Process exited with result 1
509 trkContinueAll("gdb 'C'");
512 else if (cmd.startsWith('D')) {
514 sendGdbServerMessage("OK", "shutting down");
517 else if (cmd == "g") {
518 // Read general registers.
519 if (m_snapshot.registersValid(m_session.tid)) {
520 //qDebug() << "Using cached register contents";
521 logMessage(msgGdbPacket(QLatin1String("Read registers")));
525 //qDebug() << "Fetching register contents";
528 TrkCB(handleAndReportReadRegisters),
529 Launcher::readRegistersMessage(m_session.pid, m_session.tid));
533 else if (cmd == "gg") {
534 // Force re-reading general registers for debugging purpose.
536 m_snapshot.setRegistersValid(m_session.tid, false);
538 TrkCB(handleAndReportReadRegisters),
539 Launcher::readRegistersMessage(m_session.pid, m_session.tid));
542 else if (cmd.startsWith("salstep,")) {
543 // Receive address range for current line for future use when stepping.
545 m_snapshot.parseGdbStepRange(cmd, false);
546 sendGdbServerMessage("", msgStepRangeReceived(m_snapshot.lineFromAddress, m_snapshot.lineToAddress, m_snapshot.stepOver));
549 else if (cmd.startsWith("salnext,")) {
550 // Receive address range for current line for future use when stepping.
552 m_snapshot.parseGdbStepRange(cmd, true);
553 sendGdbServerMessage("", msgStepRangeReceived(m_snapshot.lineFromAddress, m_snapshot.lineToAddress, m_snapshot.stepOver));
556 else if (cmd.startsWith("Hc")) {
558 gdbSetCurrentThread(cmd, "Set current thread for step & continue ");
561 else if (cmd.startsWith("Hg")) {
563 gdbSetCurrentThread(cmd, "Set current thread ");
566 else if (cmd == "k" || cmd.startsWith("vKill")) {
570 else if (cmd.startsWith('m')) {
571 logMessage(msgGdbPacket(QLatin1String("Read memory")));
574 const QPair<quint64, unsigned> addrLength = parseGdbReadMemoryRequest(cmd);
575 if (addrLength.second) {
576 readMemory(addrLength.first, addrLength.second, m_bufferedMemoryRead);
578 sendGdbServerMessage("E20", "Error " + cmd);
582 else if (cmd.startsWith('p')) {
583 logMessage(msgGdbPacket(QLatin1String("read register")));
584 // 0xf == current instruction pointer?
585 //sendGdbServerMessage("0000", "current IP");
588 const uint registerNumber = cmd.mid(1).toUInt(&ok, 16);
589 const int threadIndex = m_snapshot.indexOfThread(m_session.tid);
590 QTC_ASSERT(threadIndex != -1, return)
591 const Symbian::Thread &thread = m_snapshot.threadInfo[threadIndex];
592 if (thread.registerValid) {
593 sendGdbServerMessage(thread.gdbReportSingleRegister(registerNumber), thread.gdbSingleRegisterLogMessage(registerNumber));
595 //qDebug() << "Fetching single register";
597 TrkCB(handleAndReportReadRegister),
598 Launcher::readRegistersMessage(m_session.pid, m_session.tid), registerNumber);
602 else if (cmd.startsWith('P')) {
603 logMessage(msgGdbPacket(QLatin1String("write register")));
606 const QPair<uint, uint> regnumValue = parseGdbWriteRegisterWriteRequest(cmd);
607 // FIXME: Assume all goes well.
608 m_snapshot.setRegisterValue(m_session.tid, regnumValue.first, regnumValue.second);
609 QByteArray ba = trkWriteRegisterMessage(regnumValue.first, regnumValue.second);
610 sendTrkMessage(0x13, TrkCB(handleWriteRegister), ba, "Write register");
611 // Note that App TRK refuses to write registers 13 and 14
614 else if (cmd == "qAttached") {
616 // 1: attached to an existing process
617 // 0: created a new process
619 sendGdbServerMessage(QByteArray(1, '0'), "new process created");
620 //sendGdbServerMessage('1', "attached to existing process");
621 //sendGdbServerMessage("E01", "new process created");
624 else if (cmd.startsWith("qC")) {
625 logMessage(msgGdbPacket(QLatin1String("query thread id")));
626 // Return the current thread ID
629 sendGdbServerMessageAfterTrkResponse("QC@TID@");
632 else if (cmd.startsWith("qSupported")) {
634 //$qSupported:multiprocess+#c6
635 //logMessage("Handling 'qSupported'");
637 sendGdbServerMessage(Symbian::gdbQSupported);
640 // Tracepoint handling as of gdb 7.2 onwards
641 else if (cmd == "qTStatus") { // Tracepoints
643 sendGdbServerMessage("T0;tnotrun:0", QByteArray("No trace experiment running"));
645 // Trace variables as of gdb 7.2 onwards
646 else if (cmd == "qTfV" || cmd == "qTsP" || cmd == "qTfP") {
648 sendGdbServerMessage("l", QByteArray("No trace points"));
651 else if (cmd.startsWith("qThreadExtraInfo")) {
652 // $qThreadExtraInfo,1f9#55
654 sendGdbServerMessage(m_snapshot.gdbQThreadExtraInfo(cmd));
657 else if (cmd == "qfDllInfo") {
658 // That's the _first_ query package.
659 // Happens with gdb 6.4.50.20060226-cvs / CodeSourcery.
660 // Never made it into FSF gdb that got qXfer:libraries:read instead.
661 // http://sourceware.org/ml/gdb/2007-05/msg00038.html
662 // Name=hexname,TextSeg=textaddr[,DataSeg=dataaddr]
664 sendGdbServerMessage(m_session.gdbQsDllInfo(), "library information transferred");
667 else if (cmd == "qsDllInfo") {
668 // That's a following query package
670 sendGdbServerMessage(QByteArray(1, 'l'), "library information transfer finished");
673 else if (cmd == "qPacketInfo") {
674 // happens with gdb 6.4.50.20060226-cvs / CodeSourcery
675 // deprecated by qSupported?
677 sendGdbServerMessage("", "FIXME: nothing?");
680 else if (cmd == "qOffsets") {
682 sendGdbServerMessageAfterTrkResponse("TextSeg=@CODESEG@;DataSeg=@DATASEG@");
685 else if (cmd == "qSymbol::") {
687 logMessage(msgGdbPacket(QLatin1String("notify can handle symbol lookup")));
688 // Notify the target that GDB is prepared to serve symbol lookup requests.
691 sendGdbServerMessage("OK", "no further symbols needed");
693 sendGdbServerMessage("qSymbol:" + QByteArray("_Z7E32Mainv").toHex(),
697 else if (cmd.startsWith("qXfer:features:read:target.xml:")) {
698 // $qXfer:features:read:target.xml:0,7ca#46...Ack
700 sendGdbServerMessage(Symbian::gdbArchitectureXml);
703 else if (cmd == "qfThreadInfo") {
704 // That's the _first_ query package.
706 sendGdbServerMessage(m_snapshot.gdbQsThreadInfo(), "thread information transferred");
709 else if (cmd == "qsThreadInfo") {
710 // That's a following query package
712 sendGdbServerMessage(QByteArray(1, 'l'), "thread information transfer finished");
715 else if (cmd.startsWith("qXfer:libraries:read")) {
717 sendGdbServerMessage(m_session.gdbLibraryList(), "library information transferred");
720 else if (cmd == "QStartNoAckMode") {
722 logMessage("Handling 'QStartNoAckMode'");
724 sendGdbServerMessage("OK", "ack no-ack mode");
725 m_gdbAckMode = false;
728 else if (cmd.startsWith("QPassSignals")) {
729 // list of signals to pass directly to inferior
730 // $QPassSignals:e;10;14;17;1a;1b;1c;21;24;25;4c;#8f
731 // happens only if "QPassSignals+;" is qSupported
733 // FIXME: use the parameters
734 sendGdbServerMessage("OK", "passing signals accepted");
737 else if (cmd == "s" || cmd.startsWith("vCont;s")) {
738 const uint pc = m_snapshot.registerValue(m_session.tid, RegisterPC);
739 logMessage(msgGdbPacket(QString::fromLatin1("Step range from 0x%1").
742 //m_snapshot.reset();
744 QByteArray ba = trkStepRangeMessage();
745 sendTrkMessage(0x19, TrkCB(handleStep), ba, "Step range");
748 else if (cmd.startsWith('T')) {
749 // FIXME: check whether thread is alive
751 sendGdbServerMessage("OK"); // pretend all is well
752 //sendGdbServerMessage("E nn");
755 else if (cmd == "vCont?") {
756 // actions supported by the vCont packet
758 //sendGdbServerMessage("OK"); // we don't support vCont.
759 sendGdbServerMessage("vCont;c;C;s;S");
762 else if (cmd == "vCont;c") {
763 // vCont[;action[:thread-id]]...'
765 //m_snapshot.reset();
767 trkContinueAll("gdb 'vCont;c'");
770 else if (cmd.startsWith("Z0,") || cmd.startsWith("Z1,")) {
773 logMessage(msgGdbPacket(QLatin1String("Insert breakpoint")));
775 const QPair<quint64, unsigned> addrLen = parseGdbSetBreakpointRequest(cmd);
777 //qDebug() << "ADDR: " << hexNumber(addr) << " LEN: " << len;
778 logMessage(_("Inserting breakpoint at 0x%1, %2")
779 .arg(addrLen.first, 0, 16).arg(addrLen.second));
780 const bool armMode = addrLen.second == 4;
781 const QByteArray ba = trkBreakpointMessage(addrLen.first, addrLen.second, armMode);
782 sendTrkMessage(0x1B, TrkCB(handleAndReportSetBreakpoint), ba, QVariant(addrLen.first));
784 logMessage(QLatin1String("MISPARSED BREAKPOINT '") + cmd + "')", LogError);
788 else if (cmd.startsWith("z0,") || cmd.startsWith("z1,")) {
791 logMessage(msgGdbPacket(QLatin1String("Remove breakpoint")));
793 const int pos = cmd.lastIndexOf(',');
795 const uint addr = cmd.mid(3, pos - 3).toUInt(&ok, 16);
796 const uint len = cmd.mid(pos + 1).toUInt(&ok, 16);
797 const uint bp = m_session.addressToBP[addr];
799 logMessage(_("NO RECORDED BP AT 0x%1, %2")
800 .arg(addr, 0, 16).arg(len), LogError);
801 sendGdbServerMessage("E00");
803 m_session.addressToBP.remove(addr);
806 sendTrkMessage(0x1C, TrkCB(handleClearBreakpoint), ba, addr);
810 else if (cmd.startsWith("qPart:") || cmd.startsWith("qXfer:")) {
811 QByteArray data = cmd.mid(1 + cmd.indexOf(':'));
812 // "qPart:auxv:read::0,147": Read OS auxiliary data (see info aux)
813 bool handled = false;
814 if (data.startsWith("auxv:read::")) {
815 const int offsetPos = data.lastIndexOf(':') + 1;
816 const int commaPos = data.lastIndexOf(',');
817 if (commaPos != -1) {
818 bool ok1 = false, ok2 = false;
819 const int offset = data.mid(offsetPos, commaPos - offsetPos)
821 const int length = data.mid(commaPos + 1).toUInt(&ok2, 16);
823 const QString msg = _("Read of OS auxiliary "
824 "vector (%1, %2) not implemented.").arg(offset).arg(length);
825 logMessage(msgGdbPacket(msg), LogWarning);
826 sendGdbServerMessage("E20", msg.toLatin1());
833 const QString msg = QLatin1String("FIXME unknown 'XFER'-request: ")
834 + QString::fromAscii(cmd);
835 logMessage(msgGdbPacket(msg), LogWarning);
836 sendGdbServerMessage("E20", msg.toLatin1());
840 else if (cmd.startsWith('X')) {
841 logMessage(msgGdbPacket(QLatin1String("Write memory")));
844 const QPair<quint64, unsigned> addrLength = parseGdbReadMemoryRequest(cmd);
845 int pos = cmd.indexOf(':');
846 m_snapshot.resetMemory();
847 writeMemory(addrLength.first, cmd.mid(pos + 1, addrLength.second));
851 logMessage(msgGdbPacket(QLatin1String("FIXME unknown: ")
852 + QString::fromAscii(cmd)), LogWarning);
856 void TrkGdbAdapter::gdbSetCurrentThread(const QByteArray &cmd, const char *why)
858 // Thread ID from Hg/Hc commands: '-1': All, '0': arbitrary, else hex thread id.
859 const QByteArray id = cmd.mid(2);
860 const int threadId = id == "-1" ? -1 : id.toInt(0, 16);
861 const QByteArray message = QByteArray(why) + QByteArray::number(threadId);
862 logMessage(msgGdbPacket(QString::fromLatin1(message)));
863 // Set thread for subsequent operations (`m', `M', `g', `G', et.al.).
864 // for 'other operations. 0 - any thread
866 m_session.tid = threadId <= 0 ? m_session.mainTid : uint(threadId);
867 sendGdbServerMessage("OK", message);
870 void TrkGdbAdapter::trkKill()
872 // Kill inferior process
873 logMessage(msgGdbPacket(QLatin1String("kill")));
874 sendTrkMessage(0x41, TrkCB(handleDeleteProcess),
875 trkDeleteProcessMessage(), "Delete process");
878 void TrkGdbAdapter::trkContinueAll(const char *why)
881 logMessage(QString::fromLatin1("Continuing %1 threads (%2)").
882 arg(m_snapshot.threadInfo.size()).arg(QString::fromLatin1(why)));
884 // Starting from the last one, continue all threads.
885 QTC_ASSERT(!m_snapshot.threadInfo.isEmpty(), return; );
886 trkContinueNext(m_snapshot.threadInfo.size() - 1);
889 void TrkGdbAdapter::trkContinueNext(int threadIndex)
891 const uint threadId = m_snapshot.threadInfo.at(threadIndex).id;
892 logMessage(QString::fromLatin1("Continuing thread 0x%1 of %2").
893 arg(threadId,0, 16).arg(m_snapshot.threadInfo.size()));
894 sendTrkMessage(0x18, TrkCallback(this, &TrkGdbAdapter::handleTrkContinueNext),
895 trkContinueMessage(threadId), QVariant(threadIndex));
898 void TrkGdbAdapter::handleTrkContinueNext(const TrkResult &result)
900 const int index = result.cookie.toInt();
901 if (result.errorCode()) {
902 logMessage("Error continuing thread: " + result.errorString(), LogError);
905 // Remove the thread (unless main) if it is continued since we
906 // do not get thread creation/deletion events
907 QTC_ASSERT(index < m_snapshot.threadInfo.size(), return; );
908 if (m_snapshot.threadInfo.at(index).id != m_session.mainTid)
909 m_snapshot.threadInfo.remove(index);
910 if (index > 0 && m_running) // Stopped in-between
911 trkContinueNext(index - 1);
914 void TrkGdbAdapter::sendTrkMessage(trk::byte code, TrkCallback callback,
915 const QByteArray &data, const QVariant &cookie)
918 logMessage("trk: -> " + QByteArray::number(code, 16) + " "
919 + stringFromArray(data));
920 m_trkDevice->sendTrkMessage(code, callback, data, cookie);
923 void TrkGdbAdapter::sendTrkAck(trk::byte token)
925 //logMessage(QString("SENDING ACKNOWLEDGEMENT FOR TOKEN %1").arg(int(token)));
926 m_trkDevice->sendTrkAck(token);
929 void TrkGdbAdapter::handleTrkError(const QString &msg)
931 logMessage("## TRK ERROR: " + msg, LogError);
932 m_engine->handleAdapterCrashed("TRK problem encountered:\n" + msg);
935 void TrkGdbAdapter::handleTrkResult(const TrkResult &result)
938 logMessage("trk: <- " + result.toString());
939 if (result.isDebugOutput) {
940 // It looks like those messages _must not_ be acknowledged.
941 // If we do so, TRK will complain about wrong sequencing.
942 //sendTrkAck(result.token);
943 logMessage(QString::fromAscii(result.data), AppOutput);
944 sendGdbServerMessage('O' + result.data.toHex());
947 //logMessage("READ TRK " + result.toString());
948 QByteArray prefix = "READ BUF: ";
949 QByteArray str = result.toString().toUtf8();
950 switch (result.code) {
953 case 0xff: { // NAK. This mostly means transmission error, not command failed.
955 QTextStream(&logMsg) << prefix << "NAK: for token=" << result.token
956 << " ERROR: " << errorMessage(result.data.at(0)) << ' ' << str;
957 logMessage(logMsg, LogError);
960 case TrkNotifyStopped: { // 0x90 Notified Stopped
961 // 90 01 78 6a 40 40 00 00 07 23 00 00 07 24 00 00
962 showMessage(_("RESET SNAPSHOT (NOTIFY STOPPED)"));
963 MEMORY_DEBUG("WE STOPPED");
965 MEMORY_DEBUG(" AFTER CLEANING: " << m_snapshot.memory.size() << " BLOCKS LEFT");
970 trk::Launcher::parseNotifyStopped(result.data, &pid, &tid, &addr, &reason);
971 const QString msg = trk::Launcher::msgStopped(pid, tid, addr, reason);
972 // Unknown thread: Add.
974 if (m_snapshot.indexOfThread(tid) == -1)
975 m_snapshot.addThread(tid);
976 m_snapshot.setThreadState(tid, reason);
978 logMessage(prefix + msg);
979 showMessage(msg, LogMisc);
980 sendTrkAck(result.token);
982 // Todo: Do not send off GdbMessages if a synced gdb
983 // query is pending, queue instead
988 logMessage(QLatin1String("Ignoring stop at 0"));
992 // We almost always need register values, so get them
993 // now before informing gdb about the stop.s
994 const int signalNumber = reason.contains(QLatin1String("exception"), Qt::CaseInsensitive)
995 || reason.contains(QLatin1String("panic"), Qt::CaseInsensitive) ?
996 gdbServerSignalSegfault : gdbServerSignalTrap;
998 TrkCB(handleAndReportReadRegistersAfterStop),
999 Launcher::readRegistersMessage(m_session.pid, m_session.tid), signalNumber);
1001 // As a source-line step typically consists of
1002 // several instruction steps, better avoid the multiple
1003 // roundtrips through TRK in favour of an additional
1004 // roundtrip through gdb. But gdb will ask for all registers.
1006 sendGdbServerMessage("S05", "Target stopped");
1008 QByteArray ba = "T05";
1009 appendRegister(&ba, RegisterPSGdb, addr);
1010 sendGdbServerMessage(ba, "Registers");
1015 case TrkNotifyException: { // 0x91 Notify Exception (obsolete)
1016 showMessage(_("RESET SNAPSHOT (NOTIFY EXCEPTION)"));
1018 logMessage(prefix + _("NOTE: EXCEPTION ") + str, AppError);
1019 sendTrkAck(result.token);
1023 showMessage(_("RESET SNAPSHOT (NOTIFY INTERNAL ERROR)"));
1025 logMessage(prefix + _("NOTE: INTERNAL ERROR: ") + str, LogError);
1026 sendTrkAck(result.token);
1030 // target->host OS notification
1031 case 0xa0: { // Notify Created
1032 // Sending this ACK does not seem to make a difference. Why?
1033 //sendTrkAck(result.token);
1034 m_snapshot.resetMemory();
1035 const char *data = result.data.data();
1036 const trk::byte error = result.data.at(0);
1037 // type: 1 byte; for dll item, this value is 2.
1038 const trk::byte type = result.data.at(1);
1039 const uint tid = extractInt(data + 6);
1040 const Library lib = Library(result);
1041 m_session.libraries.push_back(lib);
1042 m_session.modules += QString::fromAscii(lib.name);
1044 QTextStream str(&logMsg);
1045 str << prefix << " NOTE: LIBRARY LOAD: token=" << result.token;
1047 str << " ERROR: " << int(error);
1048 str << " TYPE: " << int(type) << " PID: " << lib.pid << " TID: " << tid;
1049 str << " CODE: " << hexxNumber(lib.codeseg);
1050 str << " DATA: " << hexxNumber(lib.dataseg);
1051 str << " NAME: '" << lib.name << '\'';
1052 if (tid && tid != unsigned(-1) && m_snapshot.indexOfThread(tid) == -1)
1053 m_snapshot.addThread(tid);
1055 // Load local symbol file into gdb provided there is one
1057 const QString localSymFileName = Symbian::localSymFileForLibrary(lib.name, m_symbolFileFolder);
1058 if (!localSymFileName.isEmpty()) {
1059 showMessage(Symbian::msgLoadLocalSymFile(localSymFileName, lib.name, lib.codeseg), LogMisc);
1060 m_engine->postCommand(Symbian::symFileLoadCommand(localSymFileName, lib.codeseg, lib.dataseg));
1064 // This lets gdb trigger a register update etc.
1065 // With CS gdb 6.4 we get a non-standard $qfDllInfo#7f+ request
1066 // afterwards, so don't use it for now.
1067 //sendGdbServerMessage("T05library:;");
1069 // Causes too much "stopped" (by SIGTRAP) messages that need
1070 // to be answered by "continue". Auto-continuing each SIGTRAP
1071 // is not possible as this is also the real message for a user
1072 // initiated interrupt.
1073 sendGdbServerMessage("T05load:Name=" + lib.name.toHex()
1074 + ",TextSeg=" + hexNumber(lib.codeseg)
1075 + ",DataSeg=" + hexNumber(lib.dataseg) + ';');
1078 // After 'continue' the very first time after starting debugging
1079 // a process some library load events are generated, these are
1080 // actually static dependencies for the process. For these libraries,
1081 // the thread id is -1 which means the debugger doesn't have
1082 // to continue. The debugger can safely assume that the
1083 // thread resumption will be handled by the agent itself.
1084 if (tid != unsigned(-1))
1085 sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(m_session.mainTid), "CONTINUE");
1088 case 0xa1: { // NotifyDeleted
1089 const ushort itemType = extractByte(result.data.data() + 1);
1090 const ushort len = result.data.size() > 12
1091 ? extractShort(result.data.data() + 10) : ushort(0);
1092 const QString name = len
1093 ? QString::fromAscii(result.data.mid(12, len)) : QString();
1094 if (!name.isEmpty())
1095 m_session.modules.removeAll(name);
1096 logMessage(_("%1 %2 UNLOAD: %3")
1097 .arg(QString::fromAscii(prefix))
1098 .arg(itemType ? QLatin1String("LIB") : QLatin1String("PROCESS"))
1100 sendTrkAck(result.token);
1101 if (itemType == 0) {
1102 sendGdbServerMessage("W00", "Process exited");
1103 //sendTrkMessage(0x02, TrkCB(handleDisconnect));
1107 case 0xa2: { // NotifyProcessorStarted
1108 logMessage(prefix + _("NOTE: PROCESSOR STARTED: ") + str);
1109 sendTrkAck(result.token);
1112 case 0xa6: { // NotifyProcessorStandby
1113 logMessage(prefix + _("NOTE: PROCESSOR STANDBY: ") + str);
1114 sendTrkAck(result.token);
1117 case 0xa7: { // NotifyProcessorReset
1118 logMessage(prefix + _("NOTE: PROCESSOR RESET: ") + str);
1119 sendTrkAck(result.token);
1123 logMessage(prefix + _("INVALID: ") + str, LogError);
1129 void TrkGdbAdapter::handleCpuType(const TrkResult &result)
1131 //---TRK------------------------------------------------------
1132 // Command: 0x80 Acknowledge
1134 // [80 03 00 04 00 00 04 00 00 00]
1135 if (result.data.size() < 7) {
1136 logMessage(_("ERROR: CPUTYPE RESULT ") + result.errorString()
1137 + _(" NOT PARSABLE"), LogError);
1140 m_session.cpuMajor = result.data[1];
1141 m_session.cpuMinor = result.data[2];
1142 m_session.bigEndian = result.data[3];
1143 m_session.defaultTypeSize = result.data[4];
1144 m_session.fpTypeSize = result.data[5];
1145 m_session.extended1TypeSize = result.data[6];
1146 //m_session.extended2TypeSize = result.data[6];
1148 QTextStream(&logMsg) << "HANDLE CPU TYPE: CPU=" << m_session.cpuMajor << '.'
1149 << m_session.cpuMinor << " bigEndian=" << m_session.bigEndian
1150 << " defaultTypeSize=" << m_session.defaultTypeSize
1151 << " fpTypeSize=" << m_session.fpTypeSize
1152 << " extended1TypeSize=" << m_session.extended1TypeSize;
1156 void TrkGdbAdapter::handleDeleteProcess(const TrkResult &result)
1159 logMessage("Inferior process killed");
1160 //sendTrkMessage(0x01, TrkCB(handleDeleteProcess2)); // Ping
1161 sendTrkMessage(0x02, TrkCB(handleDeleteProcess2)); // Disconnect
1164 void TrkGdbAdapter::handleDeleteProcess2(const TrkResult &result)
1167 QString msg = QString::fromLatin1("App TRK disconnected");
1169 const bool emergencyShutdown = m_gdbProc.state() != QProcess::Running;
1170 if (emergencyShutdown)
1171 msg += QString::fromLatin1(" (emergency shutdown");
1173 if (emergencyShutdown) {
1175 m_engine->notifyAdapterShutdownOk();
1178 sendGdbServerMessage("", "process killed");
1182 void TrkGdbAdapter::handleReadRegisters(const TrkResult &result)
1184 logMessage(" REGISTER RESULT: " + result.toString());
1185 // [80 0B 00 00 00 00 00 C9 24 FF BC 00 00 00 00 00
1186 // 60 00 00 00 00 00 00 78 67 79 70 00 00 00 00 00...]
1187 if (result.errorCode()) {
1188 logMessage("ERROR: " + result.errorString(), LogError);
1191 const char *data = result.data.data() + 1; // Skip ok byte
1192 uint *registers = m_snapshot.registers(m_session.tid);
1193 QTC_ASSERT(registers, return;)
1194 for (int i = 0; i < RegisterCount; ++i)
1195 registers[i] = extractInt(data + 4 * i);
1196 m_snapshot.setRegistersValid(m_session.tid, true);
1199 void TrkGdbAdapter::handleWriteRegister(const TrkResult &result)
1201 logMessage(" RESULT: " + result.toString() + result.cookie.toString());
1202 if (result.errorCode()) {
1203 logMessage("ERROR: " + result.errorString(), LogError);
1204 sendGdbServerMessage("E01");
1207 sendGdbServerMessage("OK");
1210 void TrkGdbAdapter::reportRegisters()
1212 const int threadIndex = m_snapshot.indexOfThread(m_session.tid);
1213 QTC_ASSERT(threadIndex != -1, return);
1214 const Symbian::Thread &thread = m_snapshot.threadInfo.at(threadIndex);
1215 sendGdbServerMessage(thread.gdbReportRegisters(), thread.gdbRegisterLogMessage(m_verbose));
1218 void TrkGdbAdapter::handleAndReportReadRegisters(const TrkResult &result)
1220 handleReadRegisters(result);
1224 void TrkGdbAdapter::handleAndReportReadRegister(const TrkResult &result)
1226 handleReadRegisters(result);
1227 const uint registerNumber = result.cookie.toUInt();
1228 const int threadIndex = m_snapshot.indexOfThread(m_session.tid);
1229 QTC_ASSERT(threadIndex != -1, return);
1230 const Symbian::Thread &thread = m_snapshot.threadInfo.at(threadIndex);
1231 sendGdbServerMessage(thread.gdbReportSingleRegister(registerNumber), thread.gdbSingleRegisterLogMessage(registerNumber));
1234 void TrkGdbAdapter::handleAndReportReadRegistersAfterStop(const TrkResult &result)
1236 handleReadRegisters(result);
1237 const bool reportThread = m_session.tid != m_session.mainTid;
1238 const int signalNumber = result.cookie.isValid() ? result.cookie.toInt() : int(gdbServerSignalTrap);
1239 sendGdbServerMessage(m_snapshot.gdbStopMessage(m_session.tid, signalNumber, reportThread),
1240 "Stopped with registers in thread " + QByteArray::number(m_session.tid, 16));
1243 static QString msgMemoryReadError(int code, uint addr, uint len = 0)
1245 const QString lenS = len ? QString::number(len) : QLatin1String("<unknown>");
1246 return _("Memory read error %1 at: 0x%2 %3")
1247 .arg(code).arg(addr, 0, 16).arg(lenS);
1250 void TrkGdbAdapter::handleReadMemoryBuffered(const TrkResult &result)
1252 if (extractShort(result.data.data() + 1) + 3 != result.data.size())
1253 logMessage(_("\n BAD MEMORY RESULT: ") + result.data.toHex() + '\n', LogError);
1254 const MemoryRange range = result.cookie.value<MemoryRange>();
1255 MEMORY_DEBUG("HANDLE READ MEMORY ***BUFFERED*** FOR " << range);
1256 if (const int errorCode = result.errorCode()) {
1257 logMessage(_("TEMPORARY: ") + msgMemoryReadError(errorCode, range.from));
1258 logMessage(_("RETRYING UNBUFFERED"));
1259 // FIXME: This does not handle large requests properly.
1260 sendTrkMessage(0x10, TrkCB(handleReadMemoryUnbuffered),
1261 trkReadMemoryMessage(range), QVariant::fromValue(range));
1264 const QByteArray ba = result.data.mid(3);
1265 MEMORY_DEBUG("INSERT KNOWN MEMORY RANGE: " << range << m_snapshot.memory.size() << " BLOCKS");
1266 m_snapshot.insertMemory(range, ba);
1267 tryAnswerGdbMemoryRequest(true);
1270 void TrkGdbAdapter::handleReadMemoryUnbuffered(const TrkResult &result)
1272 if (extractShort(result.data.data() + 1) + 3 != result.data.size())
1273 logMessage(_("\n BAD MEMORY RESULT: ") + result.data.toHex() + '\n', LogError);
1274 const MemoryRange range = result.cookie.value<MemoryRange>();
1275 MEMORY_DEBUG("HANDLE READ MEMORY UNBUFFERED FOR " << range);
1276 if (const int errorCode = result.errorCode()) {
1277 logMessage(_("TEMPORARY: ") + msgMemoryReadError(errorCode, range.from));
1278 logMessage(_("RETRYING UNBUFFERED"));
1280 const QByteArray ba = "E20";
1281 sendGdbServerMessage(ba, msgMemoryReadError(32, range.from).toLatin1());
1283 // emit bogus data to make Python happy
1284 MemoryRange wanted = m_snapshot.wantedMemory;
1285 qDebug() << "SENDING BOGUS DATA FOR " << wanted;
1286 m_snapshot.insertMemory(wanted, QByteArray(wanted.size(), 0xa5));
1287 tryAnswerGdbMemoryRequest(false);
1291 const QByteArray ba = result.data.mid(3);
1292 m_snapshot.insertMemory(range, ba);
1293 MEMORY_DEBUG("INSERT KNOWN MEMORY RANGE: " << range << m_snapshot.memory.size() << " BLOCKS");
1294 tryAnswerGdbMemoryRequest(false);
1297 void TrkGdbAdapter::tryAnswerGdbMemoryRequest(bool buffered)
1299 //logMessage("TRYING TO ANSWER MEMORY REQUEST ");
1301 MemoryRange wanted = m_snapshot.wantedMemory;
1302 MemoryRange needed = m_snapshot.wantedMemory;
1303 MEMORY_DEBUG("WANTED: " << wanted);
1304 Snapshot::Memory::const_iterator it = m_snapshot.memory.begin();
1305 Snapshot::Memory::const_iterator et = m_snapshot.memory.end();
1306 for ( ; it != et; ++it) {
1307 MEMORY_DEBUG(" NEEDED STEP: " << needed);
1310 MEMORY_DEBUG("NEEDED FINAL: " << needed);
1312 if (needed.to == 0) {
1313 // FIXME: need to combine chunks first.
1315 // All fine. Send package to gdb.
1316 it = m_snapshot.memory.begin();
1317 et = m_snapshot.memory.end();
1318 for ( ; it != et; ++it) {
1319 if (it.key().from <= wanted.from && wanted.to <= it.key().to) {
1320 int offset = wanted.from - it.key().from;
1321 int len = wanted.to - wanted.from;
1322 QByteArray ba = it.value().mid(offset, len);
1323 sendGdbServerMessage(ba.toHex(),
1324 m_snapshot.memoryReadLogMessage(wanted.from, m_session.tid, m_verbose, ba));
1328 // Happens when chunks are not combined
1329 QTC_ASSERT(false, /**/);
1330 showMessage("CHUNKS NOT COMBINED");
1331 # ifdef MEMORY_DEBUG
1332 qDebug() << "CHUNKS NOT COMBINED";
1333 it = m_snapshot.memory.begin();
1334 et = m_snapshot.memory.end();
1335 for ( ; it != et; ++it)
1336 qDebug() << hexNumber(it.key().from) << hexNumber(it.key().to);
1337 qDebug() << "WANTED" << wanted.from << wanted.to;
1339 sendGdbServerMessage("E22", "");
1343 MEMORY_DEBUG("NEEDED AND UNSATISFIED: " << needed);
1345 uint blockaddr = (needed.from / MemoryChunkSize) * MemoryChunkSize;
1346 logMessage(_("Requesting buffered memory %1 bytes from 0x%2")
1347 .arg(MemoryChunkSize).arg(blockaddr, 0, 16));
1348 MemoryRange range(blockaddr, blockaddr + MemoryChunkSize);
1349 MEMORY_DEBUG(" FETCH BUFFERED MEMORY : " << range);
1350 sendTrkMessage(0x10, TrkCB(handleReadMemoryBuffered),
1351 trkReadMemoryMessage(range),
1352 QVariant::fromValue(range));
1353 } else { // Unbuffered, direct requests
1354 int len = needed.to - needed.from;
1355 logMessage(_("Requesting unbuffered memory %1 bytes from 0x%2")
1356 .arg(len).arg(needed.from, 0, 16));
1357 MEMORY_DEBUG(" FETCH UNBUFFERED MEMORY : " << needed);
1358 sendTrkMessage(0x10, TrkCB(handleReadMemoryUnbuffered),
1359 trkReadMemoryMessage(needed),
1360 QVariant::fromValue(needed));
1365 void TrkGdbAdapter::reportReadMemoryBuffered(const TrkResult &result)
1367 const MemoryRange range = result.cookie.value<MemoryRange>();
1368 // Gdb accepts less memory according to documentation.
1369 // Send E on complete failure.
1371 uint blockaddr = (range.from / MemoryChunkSize) * MemoryChunkSize;
1372 for (; blockaddr < addr + len; blockaddr += MemoryChunkSize) {
1373 const Snapshot::Memory::const_iterator it = m_snapshot.memory.constFind(blockaddr);
1374 if (it == m_snapshot.memory.constEnd())
1376 ba.append(it.value());
1378 const int previousChunkOverlap = addr % MemoryChunkSize;
1379 if (previousChunkOverlap != 0 && ba.size() > previousChunkOverlap)
1380 ba.remove(0, previousChunkOverlap);
1381 if (ba.size() > int(len))
1386 sendGdbServerMessage(ba, msgMemoryReadError(32, addr, len).toLatin1());
1388 sendGdbServerMessage(ba.toHex(), memoryReadLogMessage(addr, len, ba));
1393 void TrkGdbAdapter::handleStep(const TrkResult &result)
1395 if (result.errorCode()) {
1396 logMessage("ERROR: " + result.errorString() + " in handleStep", LogError);
1398 // Try fallback with Continue.
1399 showMessage("FALLBACK TO 'CONTINUE'");
1400 trkContinueAll("Step failed");
1401 //sendGdbServerMessage("S05", "Stepping finished");
1403 // Doing nothing as below does not work as gdb seems to insist on
1404 // making some progress through a 'step'.
1405 //sendTrkMessage(0x12,
1406 // TrkCB(handleAndReportReadRegistersAfterStop),
1407 // Launcher::readRegistersMessage(m_session.pid, m_session.tid));
1410 // The gdb server response is triggered later by the Stop Reply packet.
1411 logMessage("STEP FINISHED " + currentTime());
1414 void TrkGdbAdapter::handleAndReportSetBreakpoint(const TrkResult &result)
1416 //---TRK------------------------------------------------------
1417 // Command: 0x80 Acknowledge
1419 // [80 09 00 00 00 00 0A]
1420 if (result.errorCode()) {
1421 logMessage("ERROR WHEN SETTING BREAKPOINT: " + result.errorString(), LogError);
1422 sendGdbServerMessage("E21");
1425 uint bpnr = extractInt(result.data.data() + 1);
1426 uint addr = result.cookie.toUInt();
1427 m_session.addressToBP[addr] = bpnr;
1428 logMessage("SET BREAKPOINT " + hexxNumber(bpnr) + ' '
1429 + stringFromArray(result.data.data()));
1430 sendGdbServerMessage("OK");
1431 //sendGdbServerMessage("OK");
1434 void TrkGdbAdapter::handleClearBreakpoint(const TrkResult &result)
1436 logMessage("CLEAR BREAKPOINT ");
1437 if (result.errorCode()) {
1438 logMessage("ERROR: " + result.errorString(), LogError);
1441 sendGdbServerMessage("OK");
1444 void TrkGdbAdapter::handleSupportMask(const TrkResult &result)
1446 const char *data = result.data.data();
1448 for (int i = 0; i < 32; ++i) {
1449 //str.append(" [" + formatByte(data[i]) + "]: ");
1450 for (int j = 0; j < 8; ++j)
1451 if (data[i] & (1 << j))
1452 str.append(QByteArray::number(i * 8 + j, 16));
1454 logMessage(_("SUPPORTED: ") + str);
1457 void TrkGdbAdapter::handleTrkVersionsStartGdb(const TrkResult &result)
1460 QTextStream str(&logMsg);
1461 str << "Versions: ";
1462 if (result.data.size() >= 5) {
1463 str << "App TRK version " << int(result.data.at(1)) << '.'
1464 << int(result.data.at(2))
1465 << ", TRK protocol version " << int(result.data.at(3))
1466 << '.' << int(result.data.at(4));
1469 // As we are called from the TrkDevice handler, do not lock up when shutting
1470 // down the device in case of gdb launch errors.
1471 QTimer::singleShot(0, this, SLOT(slotStartGdb()));
1474 void TrkGdbAdapter::slotStartGdb()
1476 QStringList gdbArgs;
1477 gdbArgs.append(QLatin1String("--nx")); // Do not read .gdbinit file
1478 if (!m_engine->startGdb(gdbArgs)) {
1482 m_engine->handleAdapterStarted();
1485 void TrkGdbAdapter::handleDisconnect(const TrkResult & /*result*/)
1487 logMessage(QLatin1String("App TRK disconnected"));
1490 void TrkGdbAdapter::readMemory(uint addr, uint len, bool buffered)
1492 Q_ASSERT(len < (2 << 16));
1494 // We try to get medium-sized chunks of data from the device
1496 logMessage(_("readMemory %1 bytes from 0x%2 blocksize=%3")
1497 .arg(len).arg(addr, 0, 16).arg(MemoryChunkSize));
1499 m_snapshot.wantedMemory = MemoryRange(addr, addr + len);
1500 tryAnswerGdbMemoryRequest(buffered);
1503 void TrkGdbAdapter::writeMemory(uint addr, const QByteArray &data)
1505 Q_ASSERT(data.size() < (2 << 16));
1506 if (m_verbose > 2) {
1507 logMessage(_("writeMemory %1 bytes from 0x%2 blocksize=%3 data=%4")
1508 .arg(data.size()).arg(addr, 0, 16).arg(MemoryChunkSize).arg(QString::fromLatin1(data.toHex())));
1511 sendTrkMessage(0x11, TrkCB(handleWriteMemory),
1512 trkWriteMemoryMessage(addr, data));
1515 void TrkGdbAdapter::handleWriteMemory(const TrkResult &result)
1517 logMessage(" RESULT: " + result.toString() + result.cookie.toString());
1518 if (result.errorCode()) {
1519 logMessage("ERROR: " + result.errorString(), LogError);
1520 sendGdbServerMessage("E01");
1523 sendGdbServerMessage("OK");
1526 void TrkGdbAdapter::interruptInferior()
1528 sendTrkMessage(0x1a, TrkCallback(), trkInterruptMessage(), "Interrupting...");
1531 void TrkGdbAdapter::trkDeviceRemoved(const SymbianUtils::SymbianDevice &dev)
1533 if (state() != DebuggerNotReady && !m_trkDevice.isNull() && m_trkDevice->port() == dev.portName()) {
1534 const QString message = QString::fromLatin1("Device '%1' has been disconnected.").arg(dev.friendlyName());
1535 logMessage(message);
1536 m_engine->handleAdapterCrashed(message);
1540 bool TrkGdbAdapter::initializeDevice(const QString &remoteChannel, QString *errorMessage)
1542 if (remoteChannel.isEmpty()) {
1543 *errorMessage = tr("Port specification missing.");
1546 // Run config: Acquire from device manager.
1547 m_trkDevice = SymbianUtils::SymbianDeviceManager::instance()
1548 ->acquireDevice(remoteChannel);
1549 if (m_trkDevice.isNull()) {
1550 *errorMessage = tr("Unable to acquire a device on '%1'. It appears to be in use.").arg(remoteChannel);
1553 connect(SymbianUtils::SymbianDeviceManager::instance(), SIGNAL(deviceRemoved(const SymbianUtils::SymbianDevice)),
1554 this, SLOT(trkDeviceRemoved(SymbianUtils::SymbianDevice)));
1555 connect(m_trkDevice.data(), SIGNAL(messageReceived(trk::TrkResult)),
1556 this, SLOT(handleTrkResult(trk::TrkResult)));
1557 connect(m_trkDevice.data(), SIGNAL(error(QString)),
1558 this, SLOT(handleTrkError(QString)));
1559 connect(m_trkDevice.data(), SIGNAL(logMessage(QString)),
1560 this, SLOT(trkLogMessage(QString)));
1561 m_trkDevice->setVerbose(m_verbose);
1563 // Prompt the user to start communication
1564 const trk::PromptStartCommunicationResult src =
1565 S60DebuggerBluetoothStarter::startCommunication(m_trkDevice,
1568 case trk::PromptStartCommunicationConnected:
1570 case trk::PromptStartCommunicationCanceled:
1571 errorMessage->clear();
1573 case trk::PromptStartCommunicationError:
1579 void TrkGdbAdapter::startAdapter()
1581 m_snapshot.fullReset();
1583 // Retrieve parameters
1584 const DebuggerStartParameters ¶meters = startParameters();
1585 m_remoteExecutable = parameters.executable;
1586 m_remoteArguments = parameters.processArgs;
1587 m_symbolFile = parameters.symbolFileName;
1588 if (!m_symbolFile.isEmpty())
1589 m_symbolFileFolder = QFileInfo(m_symbolFile).absolutePath();
1590 QString remoteChannel = parameters.remoteChannel;
1591 // FIXME: testing hack, remove!
1592 if (m_remoteArguments.startsWith(__("@sym@ "))) {
1593 QStringList pa = Utils::QtcProcess::splitArgs(m_remoteArguments);
1594 remoteChannel = pa.at(1);
1595 m_remoteExecutable = pa.at(2);
1596 m_symbolFile = pa.at(3);
1597 m_remoteArguments.clear();
1599 // Unixish gdbs accept only forward slashes
1600 m_symbolFile.replace(QLatin1Char('\\'), QLatin1Char('/'));
1602 QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
1603 showMessage(_("TRYING TO START ADAPTER"));
1604 logMessage(QLatin1String("### Starting TrkGdbAdapter"));
1606 // Prompt the user to start communication
1608 if (!initializeDevice(remoteChannel, &message)) {
1609 if (message.isEmpty()) {
1610 m_engine->handleAdapterStartFailed(QString(), QString());
1612 logMessage(message, LogError);
1613 m_engine->handleAdapterStartFailed(message, QString());
1618 QTC_ASSERT(m_gdbServer == 0, delete m_gdbServer);
1619 QTC_ASSERT(m_gdbConnection == 0, m_gdbConnection = 0);
1620 m_gdbServer = new QTcpServer(this);
1622 if (!m_gdbServer->listen(QHostAddress(gdbServerIP()), gdbServerPort())) {
1623 QString msg = QString("Unable to start the gdb server at %1: %2.")
1624 .arg(m_gdbServerName).arg(m_gdbServer->errorString());
1625 logMessage(msg, LogError);
1626 m_engine->handleAdapterStartFailed(msg, QString());
1630 logMessage(QString("Gdb server running on %1.\nLittle endian assumed.")
1631 .arg(m_gdbServerName));
1633 connect(m_gdbServer, SIGNAL(newConnection()),
1634 this, SLOT(handleGdbConnection()));
1636 m_trkDevice->sendTrkInitialPing();
1637 sendTrkMessage(0x02); // Disconnect, as trk might be still connected
1638 sendTrkMessage(0x01); // Connect
1639 sendTrkMessage(0x05, TrkCB(handleSupportMask));
1640 sendTrkMessage(0x06, TrkCB(handleCpuType));
1641 sendTrkMessage(0x04, TrkCB(handleTrkVersionsStartGdb)); // Versions
1644 void TrkGdbAdapter::setupInferior()
1646 QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
1647 sendTrkMessage(0x40, TrkCB(handleCreateProcess),
1648 trk::Launcher::startProcessMessage(m_remoteExecutable, m_remoteArguments));
1651 void TrkGdbAdapter::handleCreateProcess(const TrkResult &result)
1653 QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
1655 //logMessage(" RESULT: " + result.toString());
1656 // [80 08 00 00 00 01 B5 00 00 01 B6 78 67 40 00 00 40 00 00]
1657 if (result.errorCode()) {
1658 logMessage("ERROR: " + result.errorString(), LogError);
1659 QString msg = _("Cannot start executable \"%1\" on the device:\n%2")
1660 .arg(m_remoteExecutable).arg(result.errorString());
1661 // Delay cleanup as not to close a trk device from its read handler,
1663 emitDelayedInferiorSetupFailed(msg);
1666 showMessage(_("RESET SNAPSHOT (NOTIFY CREATED)"));
1667 m_snapshot.fullReset();
1668 const char *data = result.data.data();
1669 m_session.pid = extractInt(data + 1);
1670 m_session.mainTid = m_session.tid = extractInt(data + 5);
1671 m_session.codeseg = extractInt(data + 9);
1672 m_session.dataseg = extractInt(data + 13);
1673 m_snapshot.addThread(m_session.mainTid);
1674 const QString startMsg =
1675 tr("Process started, PID: 0x%1, thread id: 0x%2, "
1676 "code segment: 0x%3, data segment: 0x%4.")
1677 .arg(m_session.pid, 0, 16).arg(m_session.tid, 0, 16)
1678 .arg(m_session.codeseg, 0, 16).arg(m_session.dataseg, 0, 16);
1679 logMessage(startMsg, LogMisc);
1680 // 26.8.2010: When paging occurs in S^3, bogus starting ROM addresses
1681 // like 0x500000 or 0x40000 are reported. Warn about symbol resolution errors.
1682 // Code duplicated in CodaAdapter. @TODO: Hopefully fixed in future TRK versions.
1683 if ((m_session.codeseg & 0xFFFFF) == 0) {
1684 const QString warnMessage = tr("The reported code segment address (0x%1) might be invalid. Symbol resolution or setting breakoints may not work.").
1685 arg(m_session.codeseg, 0, 16);
1686 logMessage(warnMessage, LogError);
1689 m_engine->postCommand("set gnutarget arm-none-symbianelf");
1691 const QByteArray symbolFile = m_symbolFile.toLocal8Bit();
1692 if (symbolFile.isEmpty()) {
1693 logMessage(_("WARNING: No symbol file available."), LogError);
1695 // Does not seem to be necessary anymore.
1696 // FIXME: Startup sequence can be streamlined now as we do not
1697 // have to wait for the TRK startup to learn the load address.
1698 //m_engine->postCommand("add-symbol-file \"" + symbolFile + "\" "
1699 // + QByteArray::number(m_session.codeseg));
1700 m_engine->postCommand("symbol-file \"" + symbolFile + "\"");
1702 foreach(const QByteArray &s, Symbian::gdbStartupSequence())
1703 m_engine->postCommand(s);
1704 //m_engine->postCommand("set remotelogfile /tmp/gdb-remotelog");
1705 //m_engine->postCommand("set debug remote 1"); // FIXME: Make an option.
1706 m_engine->postCommand("target remote " + gdbServerName().toLatin1(),
1707 CB(handleTargetRemote));
1710 void TrkGdbAdapter::handleTargetRemote(const GdbResponse &record)
1712 QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
1713 if (record.resultClass == GdbResultDone) {
1714 m_engine->handleInferiorPrepared();
1716 QString msg = tr("Connecting to TRK server adapter failed:\n")
1717 + QString::fromLocal8Bit(record.data.findChild("msg").data());
1718 m_engine->notifyInferiorSetupFailed(msg);
1722 void TrkGdbAdapter::runEngine()
1724 QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
1725 m_engine->notifyEngineRunAndInferiorStopOk();
1726 m_engine->continueInferiorInternal();
1730 // AbstractGdbAdapter interface implementation
1733 void TrkGdbAdapter::write(const QByteArray &data)
1735 // Write magic packets directly to TRK.
1736 if (data.startsWith("@#")) {
1737 QByteArray data1 = data.mid(2);
1738 if (data1.endsWith(char(10)))
1740 if (data1.endsWith(char(13)))
1742 if (data1.endsWith(' '))
1745 uint addr = data1.toUInt(&ok, 0);
1746 qDebug() << "Writing: " << quoteUnprintableLatin1(data1) << addr;
1750 if (data.startsWith("@$")) {
1751 QByteArray ba = QByteArray::fromHex(data.mid(2));
1752 qDebug() << "Writing: " << quoteUnprintableLatin1(ba);
1754 sendTrkMessage(ba.at(0), TrkCB(handleDirectTrk), ba.mid(1));
1757 if (data.startsWith("@@")) {
1759 sendTrkMessage(0x10, TrkCB(handleDirectWrite1),
1760 Launcher::readMemoryMessage(m_session.pid, m_session.tid, m_session.dataseg, 12));
1763 m_gdbProc.write(data);
1770 void TrkGdbAdapter::handleDirectWrite1(const TrkResult &response)
1772 scratch = m_session.dataseg + 512;
1773 logMessage("DIRECT WRITE1: " + response.toString());
1774 if (const int errorCode = response.errorCode()) {
1775 logMessage("ERROR: " + response.errorString() + "in handleDirectWrite1", LogError);
1777 oldMem = response.data.mid(3);
1778 oldPC = m_snapshot.registerValue(m_session.tid, RegisterPC);
1779 logMessage(_("READ MEM: ") + oldMem.toHex());
1780 //qDebug("READ MEM: " + oldMem.toHex());
1782 appendByte(&ba, 0xaa);
1783 appendByte(&ba, 0xaa);
1784 appendByte(&ba, 0xaa);
1785 appendByte(&ba, 0xaa);
1789 // 0: e51f4004 ldr r4, [pc, #-4] ; 4 <.text+0x4>
1790 appendByte(&ba, 0x04);
1791 appendByte(&ba, 0x50); // R5
1792 appendByte(&ba, 0x1f);
1793 appendByte(&ba, 0xe5);
1797 appendByte(&ba, 0x08);
1798 appendByte(&ba, 0x3b);
1800 appendByte(&ba, 0x08);
1801 appendByte(&ba, 0x3b);
1803 appendByte(&ba, 0x08);
1804 appendByte(&ba, 0x3b);
1806 appendByte(&ba, 0x08);
1807 appendByte(&ba, 0x3b);
1811 sendTrkMessage(0x11, TrkCB(handleDirectWrite2),
1812 trkWriteMemoryMessage(scratch, ba));
1816 void TrkGdbAdapter::handleDirectWrite2(const TrkResult &response)
1818 logMessage("DIRECT WRITE2: " + response.toString());
1819 if (const int errorCode = response.errorCode()) {
1820 logMessage("ERROR: " + response.errorString() + "in handleDirectWrite1", LogError);
1823 sendTrkMessage(0x10, TrkCB(handleDirectWrite3),
1824 trk::Launcher::readMemoryMessage(m_session.pid, m_session.tid, scratch, 12));
1828 void TrkGdbAdapter::handleDirectWrite3(const TrkResult &response)
1830 logMessage("DIRECT WRITE3: " + response.toString());
1831 if (const int errorCode = response.errorCode()) {
1832 logMessage("ERROR: " + response.errorString() + "in handleDirectWrite1", LogError);
1835 sendTrkMessage(0x13, TrkCB(handleDirectWrite4),
1836 trkWriteRegisterMessage(RegisterPC, scratch + 4));
1840 void TrkGdbAdapter::handleDirectWrite4(const TrkResult &response)
1842 m_snapshot.setRegisterValue(m_session.tid, RegisterPC, scratch + 4);
1844 logMessage("DIRECT WRITE4: " + response.toString());
1845 if (const int errorCode = response.errorCode()) {
1846 logMessage("ERROR: " + response.errorString() + "in handleDirectWrite1", LogError);
1849 appendByte(&ba1, 0x11); // options "step over"
1850 appendInt(&ba1, scratch + 4);
1851 appendInt(&ba1, scratch + 4);
1852 appendInt(&ba1, m_session.pid);
1853 appendInt(&ba1, m_session.tid);
1854 sendTrkMessage(0x19, TrkCB(handleDirectWrite5), ba1);
1858 void TrkGdbAdapter::handleDirectWrite5(const TrkResult &response)
1860 logMessage("DIRECT WRITE5: " + response.toString());
1861 if (const int errorCode = response.errorCode()) {
1862 logMessage("ERROR: " + response.errorString() + "in handleDirectWrite1", LogError);
1865 sendTrkMessage(0x13, TrkCB(handleDirectWrite6),
1866 trkWriteRegisterMessage(RegisterPC, oldPC));
1870 void TrkGdbAdapter::handleDirectWrite6(const TrkResult &response)
1872 logMessage("DIRECT WRITE6: " + response.toString());
1873 if (const int errorCode = response.errorCode()) {
1874 logMessage("ERROR: " + response.errorString() + "in handleDirectWrite1", LogError);
1877 sendTrkMessage(0x11, TrkCB(handleDirectWrite7),
1878 trkWriteMemoryMessage(scratch, oldMem));
1882 void TrkGdbAdapter::handleDirectWrite7(const TrkResult &response)
1884 logMessage("DIRECT WRITE7: " + response.toString());
1885 if (const int errorCode = response.errorCode()) {
1886 logMessage("ERROR: " + response.errorString() + "in handleDirectWrite1", LogError);
1889 sendTrkMessage(0x10, TrkCB(handleDirectWrite8),
1890 trk::Launcher::readMemoryMessage(m_session.pid, m_session.tid,
1895 void TrkGdbAdapter::handleDirectWrite8(const TrkResult &response)
1897 logMessage("DIRECT WRITE8: " + response.toString());
1898 if (const int errorCode = response.errorCode()) {
1899 logMessage("ERROR: " + response.errorString() + "in handleDirectWrite1", LogError);
1901 // Re-read registers
1902 sendTrkMessage(0x12,
1903 TrkCB(handleAndReportReadRegistersAfterStop),
1904 Launcher::readRegistersMessage(m_session.pid, m_session.tid));
1908 void TrkGdbAdapter::handleDirectWrite9(const TrkResult &response)
1910 logMessage("DIRECT WRITE9: " + response.toString());
1913 void TrkGdbAdapter::handleDirectTrk(const TrkResult &result)
1915 logMessage("HANDLE DIRECT TRK: " + stringFromArray(result.data));
1918 void TrkGdbAdapter::directStep(uint addr)
1921 qDebug() << "ADDR: " << addr;
1922 oldPC = m_snapshot.registerValue(m_session.tid, RegisterPC);
1923 m_snapshot.setRegisterValue(m_session.tid, RegisterPC, addr);
1924 QByteArray ba = trkWriteRegisterMessage(RegisterPC, addr);
1925 sendTrkMessage(0x13, TrkCB(handleDirectStep1), ba, "Write PC");
1928 void TrkGdbAdapter::handleDirectStep1(const TrkResult &result)
1930 logMessage("HANDLE DIRECT STEP1: " + stringFromArray(result.data));
1932 const uint pc = oldPC = m_snapshot.registerValue(m_session.tid, RegisterPC);
1933 appendByte(&ba, 0x11); // options "step over"
1936 appendInt(&ba, m_session.pid);
1937 appendInt(&ba, m_session.tid);
1938 sendTrkMessage(0x19, TrkCB(handleDirectStep2), ba, "Direct step");
1941 void TrkGdbAdapter::handleDirectStep2(const TrkResult &result)
1943 logMessage("HANDLE DIRECT STEP2: " + stringFromArray(result.data));
1944 m_snapshot.setRegisterValue(m_session.tid, RegisterPC, oldPC);
1945 QByteArray ba = trkWriteRegisterMessage(RegisterPC, oldPC);
1946 sendTrkMessage(0x13, TrkCB(handleDirectStep3), ba, "Write PC");
1949 void TrkGdbAdapter::handleDirectStep3(const TrkResult &result)
1951 logMessage("HANDLE DIRECT STEP2: " + stringFromArray(result.data));
1954 void TrkGdbAdapter::cleanup()
1956 if (!m_trkDevice.isNull()) {
1957 m_trkDevice->close();
1958 m_trkDevice->disconnect(this);
1959 SymbianUtils::SymbianDeviceManager::instance()->releaseDevice(m_trkDevice->port());
1960 m_trkDevice = TrkDevicePtr();
1967 void TrkGdbAdapter::shutdownInferior()
1969 m_engine->defaultInferiorShutdown("kill");
1972 void TrkGdbAdapter::shutdownAdapter()
1974 if (m_gdbProc.state() == QProcess::Running) {
1976 m_engine->notifyAdapterShutdownOk();
1978 // Something is wrong, gdb crashed. Kill debuggee (see handleDeleteProcess2)
1979 if (m_trkDevice->isOpen()) {
1980 logMessage("Emergency shutdown of TRK", LogError);
1986 void TrkGdbAdapter::trkReloadRegisters()
1988 m_snapshot.syncRegisters(m_session.tid, m_engine->registerHandler());
1991 void TrkGdbAdapter::trkReloadThreads()
1993 m_snapshot.syncThreads(m_engine->threadsHandler());
1996 } // namespace Internal
1997 } // namespace Debugger