| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | /**************************************************************************
 | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** This file is part of Qt Creator | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** Contact: Nokia Corporation (qt-info@nokia.com) | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** Commercial Usage | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** Licensees holding valid Qt Commercial licenses may use this file in | 
					
						
							|  |  |  | ** accordance with the Qt Commercial License Agreement provided with the | 
					
						
							|  |  |  | ** Software or, alternatively, in accordance with the terms contained in | 
					
						
							|  |  |  | ** a written agreement between you and Nokia. | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** GNU Lesser General Public License Usage | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** Alternatively, this file may be used under the terms of the GNU Lesser | 
					
						
							|  |  |  | ** General Public License version 2.1 as published by the Free Software | 
					
						
							|  |  |  | ** Foundation and appearing in the file LICENSE.LGPL included in the | 
					
						
							|  |  |  | ** packaging of this file.  Please review the following information to | 
					
						
							|  |  |  | ** ensure the GNU Lesser General Public License version 2.1 requirements | 
					
						
							|  |  |  | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** If you are unsure which license is appropriate for your use, please | 
					
						
							|  |  |  | ** contact the sales department at http://qt.nokia.com/contact.
 | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | **************************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "tcftrkgdbadapter.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "tcftrkdevice.h"
 | 
					
						
							|  |  |  | #include "trkutils.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "registerhandler.h"
 | 
					
						
							|  |  |  | #include "threadshandler.h"
 | 
					
						
							|  |  |  | #include "debuggeractions.h"
 | 
					
						
							|  |  |  | #include "debuggerstringutils.h"
 | 
					
						
							|  |  |  | #include "watchutils.h"
 | 
					
						
							|  |  |  | #ifndef STANDALONE_RUNNER
 | 
					
						
							|  |  |  | #include "gdbengine.h"
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <utils/qtcassert.h>
 | 
					
						
							|  |  |  | #include <utils/savedaction.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <QtCore/QTimer>
 | 
					
						
							|  |  |  | #include <QtCore/QDir>
 | 
					
						
							|  |  |  | #include <QtNetwork/QTcpServer>
 | 
					
						
							|  |  |  | #include <QtNetwork/QTcpSocket>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef Q_OS_WIN
 | 
					
						
							|  |  |  | #  include <windows.h>
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | #  include <sys/types.h>
 | 
					
						
							|  |  |  | #  include <unistd.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define CB(callback) \
 | 
					
						
							|  |  |  |     static_cast<GdbEngine::AdapterCallback>(&TcfTrkGdbAdapter::callback), \ | 
					
						
							|  |  |  |     STRINGIFY(callback) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | enum { debug = 0 }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Register names used by the 'SimpleRegister' service
 | 
					
						
							|  |  |  | static const char* tcfTrkSimpleRegisterNamesC[] = | 
					
						
							|  |  |  | {"R0",  "R1", "R2",  "R3", | 
					
						
							|  |  |  |  "R4",  "R5", "R6",  "R7", | 
					
						
							|  |  |  |  "R8",  "R9", "R10", "R11", | 
					
						
							|  |  |  |  "R12", "SP", "LR",  "PC", | 
					
						
							|  |  |  |  "CPSR"}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace Debugger { | 
					
						
							|  |  |  | namespace Internal { | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | using namespace Symbian; | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  | using namespace tcftrk; | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | static inline QString startMsg(const trk::Session &session) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return TcfTrkGdbAdapter::tr("Process started, PID: 0x%1, thread id: 0x%2, " | 
					
						
							|  |  |  |        "code segment: 0x%3, data segment: 0x%4.") | 
					
						
							|  |  |  |          .arg(session.pid, 0, 16).arg(session.tid, 0, 16) | 
					
						
							|  |  |  |          .arg(session.codeseg, 0, 16).arg(session.dataseg, 0, 16); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* -------------- TcfTrkGdbAdapter:
 | 
					
						
							|  |  |  |  * Startup-sequence: | 
					
						
							|  |  |  |  *  - startAdapter connects both sockets/devices | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  |  *  - In the TCF Locator Event, gdb is started and the engine is notified | 
					
						
							|  |  |  |  *    that the adapter has started. | 
					
						
							| 
									
										
										
										
											2010-07-08 18:10:50 +02:00
										 |  |  |  *  - Engine calls setupInferior(), which starts the process. | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |  *  - Initial TCF module load suspended event is emitted (process is suspended). | 
					
						
							|  |  |  |  *    In the event handler, gdb is connected to the remote target. In the | 
					
						
							|  |  |  |  *    gdb answer to conntect remote, inferiorStartPrepared() is emitted. | 
					
						
							|  |  |  |  *  - Engine sets up breakpoints,etc and calls inferiorStartPhase2(), which | 
					
						
							|  |  |  |  *    resumes the suspended TCF process via gdb 'continue'. | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |  * Thread handling (30.06.2010): | 
					
						
							|  |  |  |  * TRK does not report thread creation/termination. So, if we receive | 
					
						
							|  |  |  |  * a stop in a different thread, we store an additional thread in snapshot. | 
					
						
							|  |  |  |  * When continuing in sendTrkContinue(), we delete this thread, since we cannot | 
					
						
							|  |  |  |  * know whether it will exist at the next stop. | 
					
						
							|  |  |  |  * Also note that threads continue running in Symbian even if one crashes. | 
					
						
							|  |  |  |  * TODO: - Maybe thread reporting will be improved in TCF TRK? | 
					
						
							|  |  |  |  *       - Stop all threads once one stops? | 
					
						
							|  |  |  |  *       - Breakpoints do not trigger in threads other than the main thread. */ | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | TcfTrkGdbAdapter::TcfTrkGdbAdapter(GdbEngine *engine) : | 
					
						
							|  |  |  |     AbstractGdbAdapter(engine), | 
					
						
							|  |  |  |     m_running(false), | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  |     m_trkDevice(new TcfTrkDevice(this)), | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     m_gdbAckMode(true), | 
					
						
							|  |  |  |     m_uid(0), | 
					
						
							|  |  |  |     m_verbose(0), | 
					
						
							|  |  |  |     m_firstModuleResumableEvent(false) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_bufferedMemoryRead = true; | 
					
						
							|  |  |  |     // Disable buffering if gdb's dcache is used.
 | 
					
						
							|  |  |  |     m_bufferedMemoryRead = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_gdbServer = 0; | 
					
						
							|  |  |  |     m_gdbConnection = 0; | 
					
						
							|  |  |  |     m_snapshot.reset(); | 
					
						
							|  |  |  | #ifdef Q_OS_WIN
 | 
					
						
							|  |  |  |     const DWORD portOffset = GetCurrentProcessId() % 100; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |     const uid_t portOffset = getuid(); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |     m_gdbServerName = _("127.0.0.1:%1").arg(2222 + portOffset); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     setVerbose(theDebuggerBoolSetting(VerboseLog) ? 1 : 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     connect(theDebuggerAction(VerboseLog), SIGNAL(valueChanged(QVariant)), | 
					
						
							|  |  |  |         this, SLOT(setVerbose(QVariant))); | 
					
						
							|  |  |  |     connect(m_trkDevice, SIGNAL(error(QString)), this, SLOT(tcftrkDeviceError(QString))); | 
					
						
							|  |  |  |     connect(m_trkDevice, SIGNAL(logMessage(QString)), this, SLOT(trkLogMessage(QString))); | 
					
						
							|  |  |  |     connect(m_trkDevice, SIGNAL(tcfEvent(tcftrk::TcfTrkEvent)), this, | 
					
						
							|  |  |  |             SLOT(tcftrkEvent(tcftrk::TcfTrkEvent))); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Set register mappings
 | 
					
						
							|  |  |  |     const int registerCount = sizeof(tcfTrkSimpleRegisterNamesC)/sizeof(const char*); | 
					
						
							|  |  |  |     QVector<QByteArray> registerNames; | 
					
						
							|  |  |  |     registerNames.reserve(registerCount); | 
					
						
							|  |  |  |     for (int i = 0; i < registerCount; i++) | 
					
						
							|  |  |  |         registerNames.push_back(QByteArray(tcfTrkSimpleRegisterNamesC[i])); | 
					
						
							|  |  |  |     m_trkDevice->setRegisterNames(registerNames); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TcfTrkGdbAdapter::~TcfTrkGdbAdapter() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     cleanup(); | 
					
						
							|  |  |  |     logMessage("Shutting down.\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TcfTrkGdbAdapter::setVerbose(const QVariant &value) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     setVerbose(value.toInt()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TcfTrkGdbAdapter::setVerbose(int verbose) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (debug) | 
					
						
							|  |  |  |         qDebug("TcfTrkGdbAdapter::setVerbose %d", verbose); | 
					
						
							|  |  |  |     m_verbose = verbose; | 
					
						
							|  |  |  |     m_trkDevice->setVerbose(m_verbose); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TcfTrkGdbAdapter::trkLogMessage(const QString &msg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     logMessage(_("TRK ") + msg); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TcfTrkGdbAdapter::setGdbServerName(const QString &name) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_gdbServerName = name; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString TcfTrkGdbAdapter::gdbServerIP() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int pos = m_gdbServerName.indexOf(':'); | 
					
						
							|  |  |  |     if (pos == -1) | 
					
						
							|  |  |  |         return m_gdbServerName; | 
					
						
							|  |  |  |     return m_gdbServerName.left(pos); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | uint TcfTrkGdbAdapter::gdbServerPort() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int pos = m_gdbServerName.indexOf(':'); | 
					
						
							|  |  |  |     if (pos == -1) | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     return m_gdbServerName.mid(pos + 1).toUInt(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  | void TcfTrkGdbAdapter::handleTcfTrkRunControlModuleLoadContextSuspendedEvent(const TcfTrkRunControlModuleLoadContextSuspendedEvent &se) | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |     m_snapshot.resetMemory(); | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  |     const ModuleLoadEventInfo &minfo = se.info(); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     // Register in session, keep modules and libraries in sync.
 | 
					
						
							|  |  |  |     const QString moduleName = QString::fromUtf8(minfo.name); | 
					
						
							|  |  |  |     if (true || minfo.loaded) { // TODO: Preliminary TCF Trk Versions always have Loaded=false?
 | 
					
						
							|  |  |  |         m_session.modules.push_back(moduleName); | 
					
						
							|  |  |  |         trk::Library library; | 
					
						
							|  |  |  |         library.name = minfo.name; | 
					
						
							|  |  |  |         library.codeseg = minfo.codeAddress; | 
					
						
							|  |  |  |         library.dataseg = minfo.dataAddress; | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  |         library.pid = RunControlContext::processIdFromTcdfId(se.id()); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |         m_session.libraries.push_back(library); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         const int index = m_session.modules.indexOf(moduleName); | 
					
						
							|  |  |  |         if (index != -1) { | 
					
						
							|  |  |  |             m_session.modules.removeAt(index); | 
					
						
							|  |  |  |             m_session.libraries.removeAt(index); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             // Might happen with preliminary version of TCF TRK.
 | 
					
						
							|  |  |  |             qWarning("Received unload for module '%s' for which no load was received.", | 
					
						
							|  |  |  |                      qPrintable(moduleName)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // Handle resume.
 | 
					
						
							|  |  |  |     if (se.info().requireResume) { | 
					
						
							|  |  |  |         // If it is the first, resumable load event (.exe), make
 | 
					
						
							| 
									
										
										
										
											2010-07-08 18:10:50 +02:00
										 |  |  |         // gdb connect to remote target and resume in setupInferior2(),
 | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |         if (m_firstModuleResumableEvent) { | 
					
						
							|  |  |  |             m_firstModuleResumableEvent = false; | 
					
						
							|  |  |  |             m_session.codeseg = minfo.codeAddress; | 
					
						
							|  |  |  |             m_session.dataseg = minfo.dataAddress; | 
					
						
							|  |  |  |             logMessage(startMsg(m_session)); | 
					
						
							|  |  |  |             const QByteArray symbolFile = m_symbolFile.toLocal8Bit(); | 
					
						
							|  |  |  |             if (symbolFile.isEmpty()) { | 
					
						
							|  |  |  |                 logMessage(_("WARNING: No symbol file available."), LogWarning); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 // Does not seem to be necessary anymore.
 | 
					
						
							|  |  |  |                 // FIXME: Startup sequence can be streamlined now as we do not
 | 
					
						
							|  |  |  |                 // have to wait for the TRK startup to learn the load address.
 | 
					
						
							|  |  |  |                 //m_engine->postCommand("add-symbol-file \"" + symbolFile + "\" "
 | 
					
						
							|  |  |  |                 //    + QByteArray::number(m_session.codeseg));
 | 
					
						
							|  |  |  |                 m_engine->postCommand("symbol-file \"" + symbolFile + "\""); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |             foreach(const QByteArray &s, Symbian::gdbStartupSequence()) | 
					
						
							|  |  |  |                 m_engine->postCommand(s); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |             m_engine->postCommand("target remote " + gdbServerName().toLatin1(), | 
					
						
							|  |  |  |                                   CB(handleTargetRemote)); | 
					
						
							|  |  |  |             if (debug) | 
					
						
							|  |  |  |                 qDebug() << "Initial module load suspended: " << m_session.toString(); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             // Consecutive module load suspended: (not observed yet): Just continue
 | 
					
						
							|  |  |  |             m_trkDevice->sendRunControlResumeCommand(TcfTrkCallback(), se.id()); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TcfTrkGdbAdapter::handleTargetRemote(const GdbResponse &record) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-07-08 18:10:50 +02:00
										 |  |  |     QTC_ASSERT(state() == InferiorSettingUp, qDebug() << state()); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     if (record.resultClass == GdbResultDone) { | 
					
						
							|  |  |  |         setState(InferiorStopped); | 
					
						
							| 
									
										
										
										
											2010-07-08 12:41:26 +02:00
										 |  |  |         m_engine->handleInferiorPrepared(); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |         if (debug) | 
					
						
							|  |  |  |             qDebug() << "handleTargetRemote" << m_session.toString(); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         QString msg = tr("Connecting to TRK server adapter failed:\n") | 
					
						
							|  |  |  |             + QString::fromLocal8Bit(record.data.findChild("msg").data()); | 
					
						
							| 
									
										
										
										
											2010-07-08 18:10:50 +02:00
										 |  |  |         m_engine->handleInferiorSetupFailed(msg); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  | void TcfTrkGdbAdapter::tcftrkEvent(const TcfTrkEvent &e) | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |     if (debug) | 
					
						
							|  |  |  |         qDebug() << e.toString() << m_session.toString() << m_snapshot.toString(); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     logMessage(e.toString()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (e.type()) { | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  |     case TcfTrkEvent::LocatorHello: | 
					
						
							| 
									
										
										
										
											2010-07-12 16:19:13 +02:00
										 |  |  |         m_trkDevice->sendLoggingAddListenerCommand(TcfTrkCallback()); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |         startGdb(); // Commands are only accepted after hello
 | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  |     case TcfTrkEvent::RunControlModuleLoadSuspended: // A module was loaded
 | 
					
						
							|  |  |  |         handleTcfTrkRunControlModuleLoadContextSuspendedEvent(static_cast<const TcfTrkRunControlModuleLoadContextSuspendedEvent &>(e)); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |         break; | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  |     case TcfTrkEvent::RunControlContextAdded: // Thread/process added
 | 
					
						
							|  |  |  |         foreach(const RunControlContext &rc, static_cast<const TcfTrkRunControlContextAddedEvent &>(e).contexts()) | 
					
						
							|  |  |  |             if (rc.type() == RunControlContext::Thread) | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |                 addThread(rc.threadId()); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |         break; | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  |     case TcfTrkEvent::RunControlContextRemoved: // Thread/process removed
 | 
					
						
							|  |  |  |         foreach(const QByteArray &id, static_cast<const TcfTrkRunControlContextRemovedEvent &>(e).ids()) | 
					
						
							|  |  |  |             switch (RunControlContext::typeFromTcfId(id)) { | 
					
						
							|  |  |  |             case RunControlContext::Thread: | 
					
						
							|  |  |  |                 m_snapshot.removeThread(RunControlContext::threadIdFromTcdfId(id)); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  |             case RunControlContext::Process: | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |                 sendGdbServerMessage("W00", "Process exited"); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  |     case TcfTrkEvent::RunControlSuspended: { | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |             // Thread suspended/stopped
 | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  |             const TcfTrkRunControlContextSuspendedEvent &se = static_cast<const TcfTrkRunControlContextSuspendedEvent &>(e); | 
					
						
							|  |  |  |             const unsigned threadId = RunControlContext::threadIdFromTcdfId(se.id()); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |             const QString reason = QString::fromUtf8(se.reasonID()); | 
					
						
							|  |  |  |             showMessage(QString::fromLatin1("Reset snapshot (Thread 0x%1 stopped: '%2')"). | 
					
						
							|  |  |  |                         arg(threadId, 0, 16).arg(reason)); | 
					
						
							|  |  |  |             // Stopped in a new thread: Add.
 | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |             m_snapshot.reset(); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |             m_session.tid = threadId; | 
					
						
							|  |  |  |             if (m_snapshot.indexOfThread(threadId) == -1) | 
					
						
							|  |  |  |                 m_snapshot.addThread(threadId); | 
					
						
							|  |  |  |             m_snapshot.setThreadState(threadId, reason); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |             // Update registers first, then report stopped
 | 
					
						
							|  |  |  |             m_running = false; | 
					
						
							|  |  |  |             m_trkDevice->sendRegistersGetMRangeCommand(TcfTrkCallback(this, &TcfTrkGdbAdapter::handleAndReportReadRegistersAfterStop), | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |                                                        currentThreadContextId(), 0, | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |                                                        Symbian::RegisterCount); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2010-07-12 16:19:13 +02:00
										 |  |  |     case tcftrk::TcfTrkEvent::LoggingWriteEvent: // TODO: Not tested yet.
 | 
					
						
							|  |  |  |         showMessage(e.toString(), AppOutput); | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     default: | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TcfTrkGdbAdapter::startGdb() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     QStringList gdbArgs; | 
					
						
							|  |  |  |     gdbArgs.append(QLatin1String("--nx")); // Do not read .gdbinit file
 | 
					
						
							|  |  |  |     if (!m_engine->startGdb(gdbArgs, QString(), QString())) { | 
					
						
							|  |  |  |         cleanup(); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-07-08 12:41:26 +02:00
										 |  |  |     m_engine->handleAdapterStarted(); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TcfTrkGdbAdapter::tcftrkDeviceError(const QString  &errorString) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     logMessage(errorString); | 
					
						
							| 
									
										
										
										
											2010-07-09 08:48:33 +02:00
										 |  |  |     if (state() == EngineSettingUp) { | 
					
						
							| 
									
										
										
										
											2010-07-08 12:41:26 +02:00
										 |  |  |         m_engine->handleAdapterStartFailed(errorString, QString()); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2010-07-08 12:41:26 +02:00
										 |  |  |         m_engine->handleAdapterCrashed(errorString); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TcfTrkGdbAdapter::logMessage(const QString &msg, int channel) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (m_verbose || channel != LogDebug) | 
					
						
							|  |  |  |         showMessage(msg, channel); | 
					
						
							|  |  |  |     if (debug) | 
					
						
							|  |  |  |         qDebug("%s", qPrintable(msg)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Gdb
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | void TcfTrkGdbAdapter::handleGdbConnection() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     logMessage("HANDLING GDB CONNECTION"); | 
					
						
							|  |  |  |     QTC_ASSERT(m_gdbConnection == 0, /**/); | 
					
						
							|  |  |  |     m_gdbConnection = m_gdbServer->nextPendingConnection(); | 
					
						
							|  |  |  |     QTC_ASSERT(m_gdbConnection, return); | 
					
						
							|  |  |  |     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 TcfTrkGdbAdapter::readGdbServerCommand() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     QTC_ASSERT(m_gdbConnection, return); | 
					
						
							|  |  |  |     QByteArray packet = m_gdbConnection->readAll(); | 
					
						
							|  |  |  |     m_gdbReadBuffer.append(packet); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     logMessage("gdb: -> " + currentTime() + ' ' + 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", LogError); | 
					
						
							|  |  |  |             // This seems too harsh.
 | 
					
						
							|  |  |  |             //emit adapterCrashed("Communication problem encountered.");
 | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (code == char(0x03)) { | 
					
						
							|  |  |  |             logMessage("INTERRUPT RECEIVED"); | 
					
						
							|  |  |  |             interruptInferior(); | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (code != '$') { | 
					
						
							|  |  |  |             logMessage("Broken package (2) " + quoteUnprintableLatin1(ba) | 
					
						
							|  |  |  |                 + trk::hexNumber(code), LogError); | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         int pos = ba.indexOf('#'); | 
					
						
							|  |  |  |         if (pos == -1) { | 
					
						
							|  |  |  |             logMessage("Invalid checksum format in " | 
					
						
							|  |  |  |                 + quoteUnprintableLatin1(ba), LogError); | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         bool ok = false; | 
					
						
							|  |  |  |         uint checkSum = ba.mid(pos + 1, 2).toUInt(&ok, 16); | 
					
						
							|  |  |  |         if (!ok) { | 
					
						
							|  |  |  |             logMessage("Invalid checksum format 2 in " | 
					
						
							|  |  |  |                 + quoteUnprintableLatin1(ba), LogError); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         //logMessage(QString("Packet checksum: %1").arg(checkSum));
 | 
					
						
							|  |  |  |         trk::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), LogError); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         QByteArray cmd = ba.left(pos); | 
					
						
							|  |  |  |         ba.remove(0, pos + 3); | 
					
						
							|  |  |  |         handleGdbServerCommand(cmd); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool TcfTrkGdbAdapter::sendGdbServerPacket(const QByteArray &packet, bool doFlush) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!m_gdbConnection) { | 
					
						
							|  |  |  |         logMessage(_("Cannot write to gdb: No connection (%1)") | 
					
						
							|  |  |  |             .arg(_(packet)), LogError); | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (m_gdbConnection->state() != QAbstractSocket::ConnectedState) { | 
					
						
							|  |  |  |         logMessage(_("Cannot write to gdb: Not connected (%1)") | 
					
						
							|  |  |  |             .arg(_(packet)), LogError); | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (m_gdbConnection->write(packet) == -1) { | 
					
						
							|  |  |  |         logMessage(_("Cannot write to gdb: %1 (%2)") | 
					
						
							|  |  |  |             .arg(m_gdbConnection->errorString()).arg(_(packet)), LogError); | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (doFlush) | 
					
						
							|  |  |  |         m_gdbConnection->flush(); | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TcfTrkGdbAdapter::sendGdbServerAck() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!m_gdbAckMode) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     logMessage("gdb: <- +"); | 
					
						
							|  |  |  |     sendGdbServerPacket(QByteArray(1, '+'), false); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TcfTrkGdbAdapter::sendGdbServerMessage(const QByteArray &msg, const QByteArray &logNote) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     trk::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: <- " + currentTime() + ' ' + packet + QByteArray(pad, ' ') + logNote); | 
					
						
							|  |  |  |     sendGdbServerPacket(packet, true); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static QByteArray msgStepRangeReceived(unsigned from, unsigned to, bool over) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     QByteArray rc = "Stepping range received for step "; | 
					
						
							|  |  |  |     rc += over ? "over" : "into"; | 
					
						
							|  |  |  |     rc += " (0x"; | 
					
						
							|  |  |  |     rc += QByteArray::number(from, 16); | 
					
						
							|  |  |  |     rc += " to 0x"; | 
					
						
							|  |  |  |     rc += QByteArray::number(to, 16); | 
					
						
							|  |  |  |     rc += ')'; | 
					
						
							|  |  |  |     return rc; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TcfTrkGdbAdapter::handleGdbServerCommand(const QByteArray &cmd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (debug) | 
					
						
							|  |  |  |         qDebug("handleGdbServerCommand: %s", cmd.constData()); | 
					
						
							|  |  |  |     // 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(); | 
					
						
							|  |  |  |         sendTrkContinue(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     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.
 | 
					
						
							|  |  |  |         bool ok = false; | 
					
						
							|  |  |  |         const uint signalNumber = cmd.mid(1).toUInt(&ok, 16); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |         //TODO: Meaning of the message is not clear.
 | 
					
						
							|  |  |  |         sendGdbServerAck(); | 
					
						
							|  |  |  |         logMessage(QString::fromLatin1("Not implemented 'Continue with signal' %1: ").arg(signalNumber), LogWarning); | 
					
						
							|  |  |  |         sendGdbServerMessage("O" + QByteArray("Console output").toHex()); | 
					
						
							|  |  |  |         sendGdbServerMessage("W81"); // "Process exited with result 1
 | 
					
						
							|  |  |  |         sendTrkContinue(); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     else if (cmd.startsWith('D')) { | 
					
						
							|  |  |  |         sendGdbServerAck(); | 
					
						
							|  |  |  |         sendGdbServerMessage("OK", "shutting down"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     else if (cmd == "g") { | 
					
						
							|  |  |  |         // Read general registers.
 | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |         if (m_snapshot.registersValid(m_session.tid)) { | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |             logMessage(msgGdbPacket(QLatin1String("Read registers"))); | 
					
						
							|  |  |  |             sendGdbServerAck(); | 
					
						
							|  |  |  |             reportRegisters(); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             sendGdbServerAck(); | 
					
						
							|  |  |  |             m_trkDevice->sendRegistersGetMRangeCommand(TcfTrkCallback(this, &TcfTrkGdbAdapter::handleAndReportReadRegisters), | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |                                                        currentThreadContextId(), 0, | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |                                                        Symbian::RegisterCount); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     else if (cmd == "gg") { | 
					
						
							|  |  |  |         // Force re-reading general registers for debugging purpose.
 | 
					
						
							|  |  |  |         sendGdbServerAck(); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |         m_snapshot.setRegistersValid(m_session.tid, false); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |         m_trkDevice->sendRegistersGetMRangeCommand(TcfTrkCallback(this, &TcfTrkGdbAdapter::handleAndReportReadRegisters), | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |                                                    currentThreadContextId(), 0, | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |                                                    Symbian::RegisterCount); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     else if (cmd.startsWith("salstep,")) { | 
					
						
							|  |  |  |         // Receive address range for current line for future use when stepping.
 | 
					
						
							|  |  |  |         sendGdbServerAck(); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |         m_snapshot.parseGdbStepRange(cmd, false); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |         sendGdbServerMessage("", msgStepRangeReceived(m_snapshot.lineFromAddress, m_snapshot.lineToAddress, m_snapshot.stepOver)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     else if (cmd.startsWith("salnext,")) { | 
					
						
							|  |  |  |         // Receive address range for current line for future use when stepping.
 | 
					
						
							|  |  |  |         sendGdbServerAck(); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |         m_snapshot.parseGdbStepRange(cmd, true); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |         sendGdbServerMessage("", msgStepRangeReceived(m_snapshot.lineFromAddress, m_snapshot.lineToAddress, m_snapshot.stepOver)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     else if (cmd.startsWith("Hc")) { | 
					
						
							|  |  |  |         sendGdbServerAck(); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |         gdbSetCurrentThread(cmd, "Set current thread for step & continue "); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     else if (cmd.startsWith("Hg")) { | 
					
						
							|  |  |  |         sendGdbServerAck(); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |         gdbSetCurrentThread(cmd, "Set current thread "); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     else if (cmd == "k" || cmd.startsWith("vKill")) { | 
					
						
							|  |  |  |         // Kill inferior process
 | 
					
						
							|  |  |  |         logMessage(msgGdbPacket(QLatin1String("kill"))); | 
					
						
							| 
									
										
										
										
											2010-07-05 17:14:45 +02:00
										 |  |  |         // Requires id of main thread to terminate.
 | 
					
						
							|  |  |  |         // Note that calling 'Settings|set|removeExecutable' crashes TCF TRK,
 | 
					
						
							|  |  |  |         // so, it is apparently not required.
 | 
					
						
							|  |  |  |         m_trkDevice->sendRunControlTerminateCommand(TcfTrkCallback(), | 
					
						
							|  |  |  |                                                     mainThreadContextId()); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     else if (cmd.startsWith('m')) { | 
					
						
							|  |  |  |         logMessage(msgGdbPacket(QLatin1String("Read memory"))); | 
					
						
							|  |  |  |         // m addr,length
 | 
					
						
							|  |  |  |         sendGdbServerAck(); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |         const QPair<quint64, unsigned> addrLength = parseGdbReadMemoryRequest(cmd); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |         if (addrLength.first && addrLength.second) { | 
					
						
							|  |  |  |             readMemory(addrLength.first, addrLength.second, m_bufferedMemoryRead); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             sendGdbServerMessage("E20", "Error " + cmd); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |     else if (cmd.startsWith('X'))  { // Write memory
 | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |         const int dataPos = cmd.indexOf(':'); | 
					
						
							|  |  |  |         if (dataPos == -1) { | 
					
						
							|  |  |  |             sendGdbServerMessage("E20", "Error (colon expected) " + cmd); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |         const QPair<quint64, unsigned> addrLength = parseGdbReadMemoryRequest(cmd.left(dataPos)); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |         if (addrLength.first == 0) { | 
					
						
							|  |  |  |             sendGdbServerMessage("E20", "Error (address = 0) " + cmd); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         // Requests with len=0 are apparently used to probe writing.
 | 
					
						
							|  |  |  |         if (addrLength.second == 0) { | 
					
						
							|  |  |  |             sendGdbServerMessage("OK", "Probe memory write at 0x" + QByteArray::number(addrLength.first, 16)); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         // Data appear to be plain binary.
 | 
					
						
							|  |  |  |         const QByteArray data = cmd.mid(dataPos + 1); | 
					
						
							|  |  |  |         if (addrLength.second != unsigned(data.size())) { | 
					
						
							|  |  |  |             sendGdbServerMessage("E20", "Data length mismatch " + cmd); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         logMessage(QString::fromLatin1("Writing %1 bytes from 0x%2: %3"). | 
					
						
							|  |  |  |                    arg(addrLength.second).arg(addrLength.first, 0, 16). | 
					
						
							|  |  |  |                    arg(QString::fromAscii(data.toHex()))); | 
					
						
							|  |  |  |         m_trkDevice->sendMemorySetCommand(TcfTrkCallback(this, &TcfTrkGdbAdapter::handleWriteMemory), | 
					
						
							|  |  |  |                                           m_tcfProcessId, | 
					
						
							|  |  |  |                                           addrLength.first, data); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     else if (cmd.startsWith('p')) { | 
					
						
							|  |  |  |         logMessage(msgGdbPacket(QLatin1String("read register"))); | 
					
						
							|  |  |  |         // 0xf == current instruction pointer?
 | 
					
						
							|  |  |  |         //sendGdbServerMessage("0000", "current IP");
 | 
					
						
							|  |  |  |         sendGdbServerAck(); | 
					
						
							|  |  |  |         bool ok = false; | 
					
						
							|  |  |  |         const uint registerNumber = cmd.mid(1).toUInt(&ok, 16); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |         const int threadIndex = m_snapshot.indexOfThread(m_session.tid); | 
					
						
							|  |  |  |         QTC_ASSERT(threadIndex != -1, return) | 
					
						
							|  |  |  |         const Symbian::Thread &thread =  m_snapshot.threadInfo.at(threadIndex); | 
					
						
							|  |  |  |         if (thread.registerValid) { | 
					
						
							|  |  |  |             sendGdbServerMessage(thread.gdbReportSingleRegister(registerNumber), thread.gdbSingleRegisterLogMessage(registerNumber)); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |         } else { | 
					
						
							|  |  |  |             //qDebug() << "Fetching single register";
 | 
					
						
							|  |  |  |             m_trkDevice->sendRegistersGetMRangeCommand(TcfTrkCallback(this, &TcfTrkGdbAdapter::handleAndReportReadRegistersAfterStop), | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |                                                        currentThreadContextId(), registerNumber, 1); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     else if (cmd.startsWith('P')) { | 
					
						
							|  |  |  |         logMessage(msgGdbPacket(QLatin1String("write register"))); | 
					
						
							|  |  |  |         // $Pe=70f96678#d3
 | 
					
						
							|  |  |  |         sendGdbServerAck(); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |         const QPair<uint, uint> regnumValue = parseGdbWriteRegisterWriteRequest(cmd); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |         // FIXME: Assume all goes well.
 | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |         m_snapshot.setRegisterValue(m_session.tid, regnumValue.first, regnumValue.second); | 
					
						
							|  |  |  |         logMessage(QString::fromLatin1("Setting register #%1 to 0x%2").arg(regnumValue.first).arg(regnumValue.second, 0, 16)); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |         m_trkDevice->sendRegistersSetCommand(TcfTrkCallback(this, &TcfTrkGdbAdapter::handleWriteRegister), | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |                                              currentThreadContextId(), regnumValue.first, regnumValue.second, | 
					
						
							|  |  |  |                                              QVariant(regnumValue.first)); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |         // Note that App TRK refuses to write registers 13 and 14
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     else if (cmd == "qAttached") { | 
					
						
							|  |  |  |         //$qAttached#8f
 | 
					
						
							|  |  |  |         // 1: attached to an existing process
 | 
					
						
							|  |  |  |         // 0: created a new process
 | 
					
						
							|  |  |  |         sendGdbServerAck(); | 
					
						
							|  |  |  |         sendGdbServerMessage(QByteArray(1, '0'), "new process created"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     else if (cmd.startsWith("qC")) { | 
					
						
							|  |  |  |         logMessage(msgGdbPacket(QLatin1String("query thread id"))); | 
					
						
							|  |  |  |         // Return the current thread ID
 | 
					
						
							|  |  |  |         //$qC#b4
 | 
					
						
							|  |  |  |         sendGdbServerAck(); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |         sendGdbServerMessage("QC" + QByteArray::number(m_session.tid, 16)); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     else if (cmd.startsWith("qSupported")) { | 
					
						
							|  |  |  |         //$qSupported#37
 | 
					
						
							|  |  |  |         //$qSupported:multiprocess+#c6
 | 
					
						
							|  |  |  |         //logMessage("Handling 'qSupported'");
 | 
					
						
							|  |  |  |         sendGdbServerAck(); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |         sendGdbServerMessage(Symbian::gdbQSupported); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     else if (cmd.startsWith("qThreadExtraInfo")) { | 
					
						
							|  |  |  |         // $qThreadExtraInfo,1f9#55
 | 
					
						
							|  |  |  |         sendGdbServerAck(); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |         sendGdbServerMessage(m_snapshot.gdbQThreadExtraInfo(cmd)); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     else if (cmd == "qfDllInfo") { | 
					
						
							|  |  |  |         // That's the _first_ query package.
 | 
					
						
							|  |  |  |         // Happens with  gdb 6.4.50.20060226-cvs / CodeSourcery.
 | 
					
						
							|  |  |  |         // Never made it into FSF gdb that got qXfer:libraries:read instead.
 | 
					
						
							|  |  |  |         // http://sourceware.org/ml/gdb/2007-05/msg00038.html
 | 
					
						
							|  |  |  |         // Name=hexname,TextSeg=textaddr[,DataSeg=dataaddr]
 | 
					
						
							|  |  |  |         sendGdbServerAck(); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |         sendGdbServerMessage(m_session.gdbQsDllInfo(), "library information transfer finished"); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     else if (cmd == "qsDllInfo") { | 
					
						
							|  |  |  |         // That's a following query package
 | 
					
						
							|  |  |  |         sendGdbServerAck(); | 
					
						
							|  |  |  |         sendGdbServerMessage(QByteArray(1, 'l'), "library information transfer finished"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     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(); | 
					
						
							|  |  |  |         QByteArray answer = "TextSeg="; | 
					
						
							|  |  |  |         answer.append(QByteArray::number(m_session.codeseg, 16)); | 
					
						
							|  |  |  |         answer.append(";DataSeg="); | 
					
						
							|  |  |  |         answer.append(QByteArray::number(m_session.dataseg, 16)); | 
					
						
							|  |  |  |         sendGdbServerMessage(answer); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     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(); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |         sendGdbServerMessage(Symbian::gdbArchitectureXml); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     else if (cmd == "qfThreadInfo") { | 
					
						
							|  |  |  |         // That's the _first_ query package.
 | 
					
						
							|  |  |  |         sendGdbServerAck(); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |         sendGdbServerMessage(m_snapshot.gdbQsThreadInfo(), "thread information transferred"); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     else if (cmd == "qsThreadInfo") { | 
					
						
							|  |  |  |         // That's a following query package
 | 
					
						
							|  |  |  |         sendGdbServerAck(); | 
					
						
							|  |  |  |         sendGdbServerMessage(QByteArray(1, 'l'), "thread information transfer finished"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     else if (cmd.startsWith("qXfer:libraries:read")) { | 
					
						
							|  |  |  |         sendGdbServerAck(); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |         sendGdbServerMessage(m_session.gdbLibraryList(), "library information transferred"); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     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")) { | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |         const uint pc = m_snapshot.registerValue(m_session.tid, RegisterPC); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |         logMessage(msgGdbPacket(QString::fromLatin1("Step range from 0x%1"). | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |                                 arg(pc, 0, 16))); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |         sendGdbServerAck(); | 
					
						
							|  |  |  |         m_running = true; | 
					
						
							|  |  |  |         sendTrkStepRange(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     else if (cmd.startsWith('T')) { | 
					
						
							|  |  |  |         // FIXME: check whether thread is alive
 | 
					
						
							|  |  |  |         sendGdbServerAck(); | 
					
						
							|  |  |  |         sendGdbServerMessage("OK"); // pretend all is well
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     else if (cmd == "vCont?") { | 
					
						
							|  |  |  |         // actions supported by the vCont packet
 | 
					
						
							|  |  |  |         sendGdbServerAck(); | 
					
						
							|  |  |  |         sendGdbServerMessage("vCont;c;C;s;S"); // we don't support vCont.
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     else if (cmd == "vCont;c") { | 
					
						
							|  |  |  |         // vCont[;action[:thread-id]]...'
 | 
					
						
							|  |  |  |         sendGdbServerAck(); | 
					
						
							|  |  |  |         m_running = true; | 
					
						
							|  |  |  |         sendTrkContinue(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     else if (cmd.startsWith("Z0,") || cmd.startsWith("Z1,")) { | 
					
						
							|  |  |  |         // Insert breakpoint
 | 
					
						
							|  |  |  |         sendGdbServerAck(); | 
					
						
							|  |  |  |         logMessage(msgGdbPacket(QLatin1String("Insert breakpoint"))); | 
					
						
							|  |  |  |         // $Z0,786a4ccc,4#99
 | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |         const QPair<quint64, unsigned> addrLen = parseGdbSetBreakpointRequest(cmd); | 
					
						
							|  |  |  |         if (addrLen.first) { | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |             //qDebug() << "ADDR: " << hexNumber(addr) << " LEN: " << len;
 | 
					
						
							|  |  |  |             logMessage(_("Inserting breakpoint at 0x%1, %2") | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |                 .arg(addrLen.first, 0, 16).arg(addrLen.second)); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |             // const QByteArray ba = trkBreakpointMessage(addr, len, len == 4);
 | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |             tcftrk::Breakpoint bp(addrLen.first); | 
					
						
							|  |  |  |             bp.size = addrLen.second; | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |             bp.setContextId(m_session.pid); | 
					
						
							|  |  |  |             // We use the automatic ids calculated from the location
 | 
					
						
							|  |  |  |             // address instead of the map in snapshot.
 | 
					
						
							|  |  |  |             m_trkDevice->sendBreakpointsAddCommand(TcfTrkCallback(this, &TcfTrkGdbAdapter::handleAndReportSetBreakpoint), | 
					
						
							|  |  |  |                                                    bp); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |         } else { | 
					
						
							|  |  |  |             logMessage("MISPARSED BREAKPOINT '" + cmd + "'')" , LogError); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     else if (cmd.startsWith("z0,") || cmd.startsWith("z1,")) { | 
					
						
							|  |  |  |         // Remove breakpoint
 | 
					
						
							|  |  |  |         sendGdbServerAck(); | 
					
						
							|  |  |  |         logMessage(msgGdbPacket(QLatin1String("Remove breakpoint"))); | 
					
						
							|  |  |  |         // $z0,786a4ccc,4#99
 | 
					
						
							|  |  |  |         const int pos = cmd.lastIndexOf(','); | 
					
						
							|  |  |  |         const uint addr = cmd.mid(3, pos - 3).toUInt(0, 16); | 
					
						
							|  |  |  |         m_trkDevice->sendBreakpointsRemoveCommand(TcfTrkCallback(this, &TcfTrkGdbAdapter::handleClearBreakpoint), | 
					
						
							|  |  |  |                                                   tcftrk::Breakpoint::idFromLocation(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) | 
					
						
							|  |  |  |                     .toUInt(&ok1, 16); | 
					
						
							|  |  |  |                 const int length = data.mid(commaPos + 1).toUInt(&ok2, 16); | 
					
						
							|  |  |  |                 if (ok1 && ok2) { | 
					
						
							|  |  |  |                     const QString msg = _("Read of OS auxiliary " | 
					
						
							|  |  |  |                         "vector (%1, %2) not implemented.").arg(offset).arg(length); | 
					
						
							|  |  |  |                     logMessage(msgGdbPacket(msg), LogWarning); | 
					
						
							|  |  |  |                     sendGdbServerMessage("E20", msg.toLatin1()); | 
					
						
							|  |  |  |                     handled = true; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } // auxv read
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!handled) { | 
					
						
							|  |  |  |             const QString msg = QLatin1String("FIXME unknown 'XFER'-request: ") | 
					
						
							|  |  |  |                 + QString::fromAscii(cmd); | 
					
						
							|  |  |  |             logMessage(msgGdbPacket(msg), LogWarning); | 
					
						
							|  |  |  |             sendGdbServerMessage("E20", msg.toLatin1()); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     } // qPart/qXfer
 | 
					
						
							|  |  |  |        else { | 
					
						
							|  |  |  |         logMessage(msgGdbPacket(QLatin1String("FIXME unknown: ") | 
					
						
							|  |  |  |             + QString::fromAscii(cmd)), LogWarning); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  | void TcfTrkGdbAdapter::gdbSetCurrentThread(const QByteArray &cmd, const char *why) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Thread ID from Hg/Hc commands: '-1': All, '0': arbitrary, else hex thread id.
 | 
					
						
							|  |  |  |     const QByteArray id = cmd.mid(2); | 
					
						
							|  |  |  |     const int threadId = id == "-1" ? -1 : id.toInt(0, 16); | 
					
						
							|  |  |  |     const QByteArray message = QByteArray(why) + QByteArray::number(threadId); | 
					
						
							|  |  |  |     logMessage(msgGdbPacket(QString::fromLatin1(message))); | 
					
						
							|  |  |  |     // Set thread for subsequent operations (`m', `M', `g', `G', et.al.).
 | 
					
						
							|  |  |  |     // for 'other operations.  0 - any thread
 | 
					
						
							|  |  |  |     //$Hg0#df
 | 
					
						
							|  |  |  |     m_session.tid = threadId <= 0 ? m_session.mainTid : uint(threadId); | 
					
						
							|  |  |  |     sendGdbServerMessage("OK", message); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | void TcfTrkGdbAdapter::interruptInferior() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_trkDevice->sendRunControlSuspendCommand(TcfTrkCallback(), m_tcfProcessId); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TcfTrkGdbAdapter::startAdapter() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const ushort tcfTrkPort = 1534; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_snapshot.fullReset(); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |     m_session.reset(); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     m_firstModuleResumableEvent = true; | 
					
						
							|  |  |  |     m_tcfProcessId.clear(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Retrieve parameters
 | 
					
						
							|  |  |  |     const DebuggerStartParameters ¶meters = startParameters(); | 
					
						
							|  |  |  |     m_remoteExecutable = parameters.executable; | 
					
						
							|  |  |  |     m_remoteArguments = parameters.processArgs; | 
					
						
							|  |  |  |     m_symbolFile = parameters.symbolFileName; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QString tcfTrkAddress; | 
					
						
							|  |  |  |     QSharedPointer<QTcpSocket> tcfTrkSocket(new QTcpSocket); | 
					
						
							|  |  |  |     m_trkDevice->setDevice(tcfTrkSocket); | 
					
						
							|  |  |  |     m_trkIODevice = tcfTrkSocket; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (debug) | 
					
						
							|  |  |  |         qDebug() << parameters.processArgs; | 
					
						
							|  |  |  |     // Fixme: 1 of 3 testing hacks.
 | 
					
						
							| 
									
										
										
										
											2010-07-08 12:41:26 +02:00
										 |  |  |     if (parameters.processArgs.size() < 5 || parameters.processArgs.at(0) != _("@tcf@")) { | 
					
						
							|  |  |  |         m_engine->handleAdapterStartFailed(_("Parameter error"), QString()); | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-08 12:41:26 +02:00
										 |  |  |     m_remoteExecutable = parameters.processArgs.at(1); | 
					
						
							|  |  |  |     m_uid = parameters.processArgs.at(2).toUInt(0, 16); | 
					
						
							|  |  |  |     m_symbolFile = parameters.processArgs.at(3); | 
					
						
							|  |  |  |     tcfTrkAddress = parameters.processArgs.at(4); | 
					
						
							|  |  |  |     m_remoteArguments.clear(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     // Unixish gdbs accept only forward slashes
 | 
					
						
							|  |  |  |     m_symbolFile.replace(QLatin1Char('\\'), QLatin1Char('/')); | 
					
						
							|  |  |  |     // Start
 | 
					
						
							| 
									
										
										
										
											2010-07-09 08:48:33 +02:00
										 |  |  |     QTC_ASSERT(state() == EngineSettingUp, qDebug() << state()); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     showMessage(_("TRYING TO START ADAPTER")); | 
					
						
							|  |  |  |     logMessage(QLatin1String("### Starting TcfTrkGdbAdapter")); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QTC_ASSERT(m_gdbServer == 0, delete m_gdbServer); | 
					
						
							|  |  |  |     QTC_ASSERT(m_gdbConnection == 0, m_gdbConnection = 0); | 
					
						
							|  |  |  |     m_gdbServer = new QTcpServer(this); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!m_gdbServer->listen(QHostAddress(gdbServerIP()), gdbServerPort())) { | 
					
						
							|  |  |  |         QString msg = QString("Unable to start the gdb server at %1: %2.") | 
					
						
							|  |  |  |             .arg(m_gdbServerName).arg(m_gdbServer->errorString()); | 
					
						
							|  |  |  |         logMessage(msg, LogError); | 
					
						
							| 
									
										
										
										
											2010-07-08 12:41:26 +02:00
										 |  |  |         m_engine->handleAdapterStartFailed(msg, QString()); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     logMessage(QString("Gdb server running on %1.\nLittle endian assumed.") | 
					
						
							|  |  |  |         .arg(m_gdbServerName)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     connect(m_gdbServer, SIGNAL(newConnection()), | 
					
						
							|  |  |  |         this, SLOT(handleGdbConnection())); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     logMessage(QString::fromLatin1("Connecting to TCF TRK on %1:%2") | 
					
						
							|  |  |  |                .arg(tcfTrkAddress).arg(tcfTrkPort)); | 
					
						
							|  |  |  |     tcfTrkSocket->connectToHost(tcfTrkAddress, tcfTrkPort); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-08 18:10:50 +02:00
										 |  |  | void TcfTrkGdbAdapter::setupInferior() | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-07-08 18:10:50 +02:00
										 |  |  |     QTC_ASSERT(state() == InferiorSettingUp, qDebug() << state()); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     m_trkDevice->sendProcessStartCommand(TcfTrkCallback(this, &TcfTrkGdbAdapter::handleCreateProcess), | 
					
						
							|  |  |  |                                          m_remoteExecutable, m_uid, m_remoteArguments, | 
					
						
							|  |  |  |                                          QString(), true); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  | void TcfTrkGdbAdapter::addThread(unsigned id) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Make thread known, register as main if it is the first one.
 | 
					
						
							|  |  |  |     if (m_snapshot.indexOfThread(id) == -1) { | 
					
						
							|  |  |  |         m_snapshot.addThread(id); | 
					
						
							|  |  |  |         if (m_session.tid == 0) { | 
					
						
							|  |  |  |             m_session.tid = id; | 
					
						
							|  |  |  |             if (m_session.mainTid == 0) | 
					
						
							|  |  |  |                 m_session.mainTid = id; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  | void TcfTrkGdbAdapter::handleCreateProcess(const TcfTrkCommandResult &result) | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     if (debug) | 
					
						
							|  |  |  |         qDebug() << "ProcessCreated: " << result.toString(); | 
					
						
							|  |  |  |     if (!result) { | 
					
						
							|  |  |  |         const QString errorMessage = result.errorString(); | 
					
						
							|  |  |  |         logMessage(QString::fromLatin1("Failed to start process: %1").arg(errorMessage), LogError); | 
					
						
							| 
									
										
										
										
											2010-07-08 18:10:50 +02:00
										 |  |  |         m_engine->handleInferiorSetupFailed(result.errorString()); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     QTC_ASSERT(!result.values.isEmpty(), return); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  |     RunControlContext ctx; | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     ctx.parse(result.values.front()); | 
					
						
							|  |  |  |     logMessage(ctx.toString()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |     m_session.pid = ctx.processId(); | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  |     m_tcfProcessId = RunControlContext::tcfId(m_session.pid); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |     if (const unsigned threadId = ctx.threadId()) | 
					
						
							|  |  |  |         addThread(threadId); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     // See ModuleLoadSuspendedEvent for the rest.
 | 
					
						
							|  |  |  |     m_session.codeseg = 0; | 
					
						
							|  |  |  |     m_session.dataseg = 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-08 18:10:50 +02:00
										 |  |  | void TcfTrkGdbAdapter::runAdapter() | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     m_engine->continueInferiorInternal(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // AbstractGdbAdapter interface implementation
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TcfTrkGdbAdapter::write(const QByteArray &data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Write magic packets directly to TRK.
 | 
					
						
							|  |  |  |     if (data.startsWith("@#")) { | 
					
						
							|  |  |  |         QByteArray data1 = data.mid(2); | 
					
						
							|  |  |  |         if (data1.endsWith(char(10))) | 
					
						
							|  |  |  |             data1.chop(1); | 
					
						
							|  |  |  |         if (data1.endsWith(char(13))) | 
					
						
							|  |  |  |             data1.chop(1); | 
					
						
							|  |  |  |         if (data1.endsWith(' ')) | 
					
						
							|  |  |  |             data1.chop(1); | 
					
						
							|  |  |  |         bool ok; | 
					
						
							|  |  |  |         const uint addr = data1.toUInt(&ok, 0); | 
					
						
							|  |  |  |         logMessage(QString::fromLatin1("Direct step (@#) 0x%1: not implemented").arg(addr, 0, 16), LogError); | 
					
						
							|  |  |  |         // directStep(addr);
 | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (data.startsWith("@$")) { | 
					
						
							|  |  |  |         QByteArray ba = QByteArray::fromHex(data.mid(2)); | 
					
						
							|  |  |  |         qDebug() << "Writing: " << quoteUnprintableLatin1(ba); | 
					
						
							|  |  |  |         // if (ba.size() >= 1)
 | 
					
						
							|  |  |  |         // sendTrkMessage(ba.at(0), TrkCB(handleDirectTrk), ba.mid(1));
 | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (data.startsWith("@@")) { | 
					
						
							|  |  |  |         logMessage(QLatin1String("Direct write (@@): not implemented"), LogError); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     m_gdbProc.write(data); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TcfTrkGdbAdapter::cleanup() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     delete m_gdbServer; | 
					
						
							|  |  |  |     m_gdbServer = 0; | 
					
						
							|  |  |  |     if (!m_trkIODevice.isNull()) { | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  |         QAbstractSocket *socket = qobject_cast<QAbstractSocket *>(m_trkIODevice.data()); | 
					
						
							| 
									
										
										
										
											2010-06-28 16:32:53 +02:00
										 |  |  |         const bool isOpen = socket ? socket->state() == QAbstractSocket::ConnectedState : m_trkIODevice->isOpen(); | 
					
						
							|  |  |  |         if (isOpen) { | 
					
						
							|  |  |  |             if (socket) { | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |                 socket->disconnect(); | 
					
						
							| 
									
										
										
										
											2010-06-28 16:32:53 +02:00
										 |  |  |             } else { | 
					
						
							|  |  |  |                 m_trkIODevice->close(); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2010-06-28 16:32:53 +02:00
										 |  |  |     } //!m_trkIODevice.isNull()
 | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TcfTrkGdbAdapter::shutdown() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     cleanup(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TcfTrkGdbAdapter::trkReloadRegisters() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Take advantage of direct access to cached register values.
 | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |     m_snapshot.syncRegisters(m_session.tid, m_engine->registerHandler()); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TcfTrkGdbAdapter::trkReloadThreads() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |     m_snapshot.syncThreads(m_engine->threadsHandler()); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  | void TcfTrkGdbAdapter::handleWriteRegister(const TcfTrkCommandResult &result) | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     const int registerNumber = result.cookie.toInt(); | 
					
						
							|  |  |  |     if (result) { | 
					
						
							|  |  |  |         sendGdbServerMessage("OK"); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         logMessage(QString::fromLatin1("ERROR writing register #%1: %2").arg(registerNumber).arg(result.errorString()), LogError); | 
					
						
							|  |  |  |         sendGdbServerMessage("E01"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TcfTrkGdbAdapter::reportRegisters() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |     const int threadIndex = m_snapshot.indexOfThread(m_session.tid); | 
					
						
							|  |  |  |     QTC_ASSERT(threadIndex != -1, return); | 
					
						
							|  |  |  |     const Symbian::Thread &thread = m_snapshot.threadInfo.at(threadIndex); | 
					
						
							|  |  |  |     sendGdbServerMessage(thread.gdbReportRegisters(), thread.gdbRegisterLogMessage(m_verbose)); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  | void TcfTrkGdbAdapter::handleReadRegisters(const TcfTrkCommandResult &result) | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     logMessage("       REGISTER RESULT: " + result.toString()); | 
					
						
							|  |  |  |     if (!result) { | 
					
						
							|  |  |  |         logMessage("ERROR: " + result.errorString(), LogError); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  |     if (result.values.isEmpty() || result.values.front().type() != JsonValue::Array) { | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |         logMessage(_("Format error in register message: ") + result.toString(), LogError); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     unsigned i = result.cookie.toUInt(); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |     uint *registers = m_snapshot.registers(m_session.tid); | 
					
						
							|  |  |  |     QTC_ASSERT(registers, return;) | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  |     foreach (const JsonValue &jr, result.values.front().children()) | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |         registers[i++] = jr.data().toUInt(0, 16); | 
					
						
							|  |  |  |     m_snapshot.setRegistersValid(m_session.tid, true); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     if (debug) | 
					
						
							|  |  |  |         qDebug() << "handleReadRegisters: " << m_snapshot.toString(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  | void TcfTrkGdbAdapter::handleAndReportReadRegisters(const TcfTrkCommandResult &result) | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     handleReadRegisters(result); | 
					
						
							|  |  |  |     reportRegisters(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  | void TcfTrkGdbAdapter::handleAndReportReadRegister(const TcfTrkCommandResult &result) | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     handleReadRegisters(result); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |     const uint registerNumber = result.cookie.toUInt(); | 
					
						
							|  |  |  |     const int threadIndex = m_snapshot.indexOfThread(m_session.tid); | 
					
						
							|  |  |  |     QTC_ASSERT(threadIndex != -1, return); | 
					
						
							|  |  |  |     const Symbian::Thread &thread = m_snapshot.threadInfo.at(threadIndex); | 
					
						
							|  |  |  |     sendGdbServerMessage(thread.gdbReportSingleRegister(registerNumber), thread.gdbSingleRegisterLogMessage(registerNumber)); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  | void TcfTrkGdbAdapter::handleAndReportReadRegistersAfterStop(const TcfTrkCommandResult &result) | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     handleReadRegisters(result); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |     handleReadRegisters(result); | 
					
						
							|  |  |  |     const bool reportThread = m_session.tid != m_session.mainTid; | 
					
						
							|  |  |  |     sendGdbServerMessage(m_snapshot.gdbStopMessage(m_session.tid, reportThread), | 
					
						
							|  |  |  |                          "Stopped with registers in thread " + QByteArray::number(m_session.tid, 16)); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  | void TcfTrkGdbAdapter::handleAndReportSetBreakpoint(const TcfTrkCommandResult &result) | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     if (result) { | 
					
						
							|  |  |  |         sendGdbServerMessage("OK"); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         logMessage(QLatin1String("Error setting breakpoint: ") + result.errorString(), LogError); | 
					
						
							|  |  |  |         sendGdbServerMessage("E21"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  | void TcfTrkGdbAdapter::handleClearBreakpoint(const TcfTrkCommandResult &result) | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     logMessage("CLEAR BREAKPOINT "); | 
					
						
							|  |  |  |     if (!result) | 
					
						
							|  |  |  |         logMessage("Error clearing breakpoint: " + result.errorString(), LogError); | 
					
						
							|  |  |  |     sendGdbServerMessage("OK"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TcfTrkGdbAdapter::readMemory(uint addr, uint len, bool buffered) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Q_ASSERT(len < (2 << 16)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // We try to get medium-sized chunks of data from the device
 | 
					
						
							|  |  |  |     if (m_verbose > 2) | 
					
						
							|  |  |  |         logMessage(_("readMemory %1 bytes from 0x%2 blocksize=%3") | 
					
						
							|  |  |  |             .arg(len).arg(addr, 0, 16).arg(MemoryChunkSize)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_snapshot.wantedMemory = MemoryRange(addr, addr + len); | 
					
						
							|  |  |  |     tryAnswerGdbMemoryRequest(buffered); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static QString msgMemoryReadError(uint addr, uint len = 0) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const QString lenS = len ? QString::number(len) : QLatin1String("<unknown>"); | 
					
						
							|  |  |  |     return _("Memory read error at: 0x%1 %2").arg(addr, 0, 16).arg(lenS); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TcfTrkGdbAdapter::sendMemoryGetCommand(const MemoryRange &range, bool buffered) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const QVariant cookie = QVariant::fromValue(range); | 
					
						
							|  |  |  |     const TcfTrkCallback cb = buffered ? | 
					
						
							|  |  |  |                               TcfTrkCallback(this, &TcfTrkGdbAdapter::handleReadMemoryBuffered) : | 
					
						
							|  |  |  |                               TcfTrkCallback(this, &TcfTrkGdbAdapter::handleReadMemoryUnbuffered); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |     m_trkDevice->sendMemoryGetCommand(cb, currentThreadContextId(), range.from, range.size(), cookie); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  | void TcfTrkGdbAdapter::handleReadMemoryBuffered(const TcfTrkCommandResult &result) | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     QTC_ASSERT(qVariantCanConvert<MemoryRange>(result.cookie), return); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  |     const QByteArray memory = TcfTrkDevice::parseMemoryGet(result); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     const MemoryRange range = result.cookie.value<MemoryRange>(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (unsigned(memory.size()) != range.size()) { | 
					
						
							|  |  |  |         logMessage(_("TEMPORARY: ") + msgMemoryReadError(range.from, range.size())); | 
					
						
							|  |  |  |         logMessage(_("RETRYING UNBUFFERED")); | 
					
						
							|  |  |  |         // FIXME: This does not handle large requests properly.
 | 
					
						
							|  |  |  |         sendMemoryGetCommand(range, false); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     m_snapshot.insertMemory(range, memory); | 
					
						
							|  |  |  |     tryAnswerGdbMemoryRequest(true); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  | void TcfTrkGdbAdapter::handleReadMemoryUnbuffered(const TcfTrkCommandResult &result) | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     QTC_ASSERT(qVariantCanConvert<MemoryRange>(result.cookie), return); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  |     const QByteArray memory = TcfTrkDevice::parseMemoryGet(result); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     const MemoryRange range = result.cookie.value<MemoryRange>(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (unsigned(memory.size()) != range.size()) { | 
					
						
							|  |  |  |         logMessage(_("TEMPORARY: ") + msgMemoryReadError(range.from, range.size())); | 
					
						
							|  |  |  |         logMessage(_("RETRYING UNBUFFERED")); | 
					
						
							|  |  |  |         const QByteArray ba = "E20"; | 
					
						
							|  |  |  |         sendGdbServerMessage(ba, msgMemoryReadError(32, range.from).toLatin1()); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     m_snapshot.insertMemory(range, memory); | 
					
						
							|  |  |  |     tryAnswerGdbMemoryRequest(false); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TcfTrkGdbAdapter::tryAnswerGdbMemoryRequest(bool buffered) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     //logMessage("TRYING TO ANSWER MEMORY REQUEST ");
 | 
					
						
							|  |  |  |     MemoryRange wanted = m_snapshot.wantedMemory; | 
					
						
							|  |  |  |     MemoryRange needed = m_snapshot.wantedMemory; | 
					
						
							|  |  |  |     MEMORY_DEBUG("WANTED: " << wanted); | 
					
						
							|  |  |  |     Snapshot::Memory::const_iterator it = m_snapshot.memory.begin(); | 
					
						
							|  |  |  |     Snapshot::Memory::const_iterator et = m_snapshot.memory.end(); | 
					
						
							|  |  |  |     for ( ; it != et; ++it) { | 
					
						
							|  |  |  |         MEMORY_DEBUG("   NEEDED STEP: " << needed); | 
					
						
							|  |  |  |         needed -= it.key(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     MEMORY_DEBUG("NEEDED FINAL: " << needed); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (needed.to == 0) { | 
					
						
							|  |  |  |         // FIXME: need to combine chunks first.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // All fine. Send package to gdb.
 | 
					
						
							|  |  |  |         it = m_snapshot.memory.begin(); | 
					
						
							|  |  |  |         et = m_snapshot.memory.end(); | 
					
						
							|  |  |  |         for ( ; it != et; ++it) { | 
					
						
							|  |  |  |             if (it.key().from <= wanted.from && wanted.to <= it.key().to) { | 
					
						
							|  |  |  |                 int offset = wanted.from - it.key().from; | 
					
						
							|  |  |  |                 int len = wanted.to - wanted.from; | 
					
						
							|  |  |  |                 QByteArray ba = it.value().mid(offset, len); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |                 sendGdbServerMessage(ba.toHex(), | 
					
						
							|  |  |  |                                      m_snapshot.memoryReadLogMessage(wanted.from, m_session.tid, m_verbose, ba)); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         // Happens when chunks are not combined
 | 
					
						
							|  |  |  |         QTC_ASSERT(false, /**/); | 
					
						
							|  |  |  |         showMessage("CHUNKS NOT COMBINED"); | 
					
						
							|  |  |  | #        ifdef MEMORY_DEBUG
 | 
					
						
							|  |  |  |         qDebug() << "CHUNKS NOT COMBINED"; | 
					
						
							|  |  |  |         it = m_snapshot.memory.begin(); | 
					
						
							|  |  |  |         et = m_snapshot.memory.end(); | 
					
						
							|  |  |  |         for ( ; it != et; ++it) | 
					
						
							|  |  |  |             qDebug() << trk::hexNumber(it.key().from) << trk::hexNumber(it.key().to); | 
					
						
							|  |  |  |         qDebug() << "WANTED" << wanted.from << wanted.to; | 
					
						
							|  |  |  | #        endif
 | 
					
						
							|  |  |  |         sendGdbServerMessage("E22", ""); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     MEMORY_DEBUG("NEEDED AND UNSATISFIED: " << needed); | 
					
						
							|  |  |  |     if (buffered) { | 
					
						
							|  |  |  |         uint blockaddr = (needed.from / MemoryChunkSize) * MemoryChunkSize; | 
					
						
							|  |  |  |         logMessage(_("Requesting buffered memory %1 bytes from 0x%2") | 
					
						
							|  |  |  |             .arg(MemoryChunkSize).arg(blockaddr, 0, 16)); | 
					
						
							|  |  |  |         MemoryRange range(blockaddr, blockaddr + MemoryChunkSize); | 
					
						
							|  |  |  |         MEMORY_DEBUG("   FETCH BUFFERED MEMORY : " << range); | 
					
						
							|  |  |  |         sendMemoryGetCommand(range, true); | 
					
						
							|  |  |  |     } else { // Unbuffered, direct requests
 | 
					
						
							|  |  |  |         int len = needed.to - needed.from; | 
					
						
							|  |  |  |         logMessage(_("Requesting unbuffered memory %1 bytes from 0x%2") | 
					
						
							|  |  |  |             .arg(len).arg(needed.from, 0, 16)); | 
					
						
							|  |  |  |         sendMemoryGetCommand(needed, false); | 
					
						
							|  |  |  |         MEMORY_DEBUG("   FETCH UNBUFFERED MEMORY : " << needed); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  | void TcfTrkGdbAdapter::handleWriteMemory(const TcfTrkCommandResult &result) | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     if (result) { | 
					
						
							|  |  |  |         sendGdbServerMessage("OK", "Write memory"); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         logMessage(QLatin1String("Error writing memory: ") + result.errorString(), LogError); | 
					
						
							|  |  |  |         sendGdbServerMessage("E21"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QByteArray TcfTrkGdbAdapter::mainThreadContextId() const | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  |     return RunControlContext::tcfId(m_session.pid, m_session.mainTid); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QByteArray TcfTrkGdbAdapter::currentThreadContextId() const | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  |     return RunControlContext::tcfId(m_session.pid, m_session.tid); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TcfTrkGdbAdapter::sendTrkContinue() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |     // Remove all but main thread as we do not know whether they will exist
 | 
					
						
							|  |  |  |     // at the next stop.
 | 
					
						
							|  |  |  |     if (m_snapshot.threadInfo.size() > 1) | 
					
						
							|  |  |  |         m_snapshot.threadInfo.remove(1, m_snapshot.threadInfo.size() - 1); | 
					
						
							|  |  |  |     m_trkDevice->sendRunControlResumeCommand(TcfTrkCallback(), m_tcfProcessId); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TcfTrkGdbAdapter::sendTrkStepRange() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     uint from = m_snapshot.lineFromAddress; | 
					
						
							|  |  |  |     uint to = m_snapshot.lineToAddress; | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |     const uint pc = m_snapshot.registerValue(m_session.tid, RegisterPC); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |     if (from <= pc && pc <= to) { | 
					
						
							|  |  |  |         const QString msg = QString::fromLatin1("Step in 0x%1 .. 0x%2 instead of 0x%3..."). | 
					
						
							|  |  |  |                             arg(from, 0, 16).arg(to, 0, 16).arg(pc, 0, 16); | 
					
						
							|  |  |  |         showMessage(msg); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         from = pc; | 
					
						
							|  |  |  |         to = pc; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // TODO: Step range does not seem to work yet?
 | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  |     const RunControlResumeMode mode = (from == to && to == pc) ? | 
					
						
							|  |  |  |           (m_snapshot.stepOver ? RM_STEP_OVER       : RM_STEP_INTO) : | 
					
						
							|  |  |  |           (m_snapshot.stepOver ? RM_STEP_OVER_RANGE : RM_STEP_INTO_RANGE); | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     logMessage(QString::fromLatin1("Stepping from 0x%1 to 0x%2 (current PC=0x%3), mode %4"). | 
					
						
							|  |  |  |                arg(from, 0, 16).arg(to, 0, 16).arg(pc).arg(int(mode))); | 
					
						
							|  |  |  |     m_trkDevice->sendRunControlResumeCommand(TcfTrkCallback(this, &TcfTrkGdbAdapter::handleStep), | 
					
						
							| 
									
										
										
										
											2010-06-30 17:14:57 +02:00
										 |  |  |                                              currentThreadContextId(), | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  |                                              mode, 1, from, to); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-08 15:06:09 +02:00
										 |  |  | void TcfTrkGdbAdapter::handleStep(const TcfTrkCommandResult &result) | 
					
						
							| 
									
										
										
										
											2010-06-25 15:06:30 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!result) { // Try fallback with Continue.
 | 
					
						
							|  |  |  |         logMessage(QString::fromLatin1("Error while stepping: %1 (fallback to 'continue')").arg(result.errorString()), LogWarning); | 
					
						
							|  |  |  |         sendTrkContinue(); | 
					
						
							|  |  |  |         // Doing nothing as below does not work as gdb seems to insist on
 | 
					
						
							|  |  |  |         // making some progress through a 'step'.
 | 
					
						
							|  |  |  |         //sendTrkMessage(0x12,
 | 
					
						
							|  |  |  |         //    TrkCB(handleAndReportReadRegistersAfterStop),
 | 
					
						
							|  |  |  |         //    trkReadRegistersMessage());
 | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // The gdb server response is triggered later by the Stop Reply packet.
 | 
					
						
							|  |  |  |     logMessage("STEP FINISHED " + currentTime()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // namespace Internal
 | 
					
						
							|  |  |  | } // namespace Debugger
 |