2009-09-09 17:24:21 +02:00
|
|
|
/**************************************************************************
|
|
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator
|
|
|
|
|
**
|
2011-01-11 16:28:15 +01:00
|
|
|
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
2009-09-09 17:24:21 +02:00
|
|
|
**
|
|
|
|
|
** Contact: Nokia Corporation (qt-info@nokia.com)
|
|
|
|
|
**
|
2010-12-17 16:01:08 +01:00
|
|
|
** No Commercial Usage
|
2009-09-09 17:24:21 +02:00
|
|
|
**
|
2010-12-17 16:01:08 +01:00
|
|
|
** This file contains pre-release code and may not be distributed.
|
|
|
|
|
** You may use this file in accordance with the terms and conditions
|
|
|
|
|
** contained in the Technology Preview License Agreement accompanying
|
|
|
|
|
** this package.
|
2009-09-09 17:24:21 +02:00
|
|
|
**
|
|
|
|
|
** 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.
|
|
|
|
|
**
|
2010-12-17 16:01:08 +01:00
|
|
|
** In addition, as a special exception, Nokia gives you certain additional
|
|
|
|
|
** rights. These rights are described in the Nokia Qt LGPL Exception
|
|
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
|
**
|
|
|
|
|
** If you have questions regarding the use of this file, please contact
|
|
|
|
|
** Nokia at qt-info@nokia.com.
|
2009-09-09 17:24:21 +02:00
|
|
|
**
|
|
|
|
|
**************************************************************************/
|
|
|
|
|
|
2009-09-11 15:53:08 +02:00
|
|
|
#include "trkgdbadapter.h"
|
2010-02-04 11:36:49 +01:00
|
|
|
|
2011-01-10 10:14:23 +01:00
|
|
|
#include "debuggerstartparameters.h"
|
2010-11-02 16:14:00 +01:00
|
|
|
#include "gdbmi.h"
|
2010-01-21 15:46:33 +01:00
|
|
|
#include "launcher.h"
|
2010-02-11 12:31:59 +01:00
|
|
|
#include "symbiandevicemanager.h"
|
2009-10-26 11:55:02 +01:00
|
|
|
#include "s60debuggerbluetoothstarter.h"
|
|
|
|
|
#include "bluetoothlistener_gui.h"
|
2009-10-20 17:51:06 +02:00
|
|
|
|
2010-02-04 11:36:49 +01:00
|
|
|
#include "registerhandler.h"
|
2010-05-18 12:12:22 +02:00
|
|
|
#include "threadshandler.h"
|
2010-01-15 12:01:26 +01:00
|
|
|
#include "debuggeractions.h"
|
2010-11-10 16:33:11 +01:00
|
|
|
#include "debuggercore.h"
|
2009-09-25 15:02:16 +02:00
|
|
|
#include "debuggerstringutils.h"
|
2010-02-09 15:02:55 +01:00
|
|
|
#include "watchutils.h"
|
2009-09-11 12:30:53 +02:00
|
|
|
#ifndef STANDALONE_RUNNER
|
2009-09-11 15:34:41 +02:00
|
|
|
#include "gdbengine.h"
|
2009-09-11 12:30:53 +02:00
|
|
|
#endif
|
2009-10-20 17:51:06 +02:00
|
|
|
|
|
|
|
|
#include <utils/qtcassert.h>
|
2010-10-19 11:14:03 +02:00
|
|
|
#include <utils/qtcprocess.h>
|
2010-03-18 10:59:06 +01:00
|
|
|
#include <utils/savedaction.h>
|
2009-10-20 17:51:06 +02:00
|
|
|
|
|
|
|
|
#include <QtCore/QTimer>
|
|
|
|
|
#include <QtCore/QDir>
|
2010-06-25 15:06:30 +02:00
|
|
|
#include <QtNetwork/QTcpServer>
|
|
|
|
|
#include <QtNetwork/QTcpSocket>
|
2009-10-20 17:51:06 +02:00
|
|
|
|
2009-09-22 11:54:28 +02:00
|
|
|
#ifdef Q_OS_WIN
|
2010-09-09 09:58:17 +02:00
|
|
|
# include "dbgwinutils.h"
|
2009-09-22 11:54:28 +02:00
|
|
|
#else
|
2009-09-12 09:17:09 +02:00
|
|
|
# include <sys/types.h>
|
|
|
|
|
# include <unistd.h>
|
|
|
|
|
#endif
|
2009-09-09 17:24:21 +02:00
|
|
|
|
2009-09-22 09:27:19 +02:00
|
|
|
#define CB(callback) \
|
|
|
|
|
static_cast<GdbEngine::AdapterCallback>(&TrkGdbAdapter::callback), \
|
|
|
|
|
STRINGIFY(callback)
|
|
|
|
|
|
2009-09-11 15:53:08 +02:00
|
|
|
#define TrkCB(s) TrkCallback(this, &TrkGdbAdapter::s)
|
2009-09-09 17:24:21 +02:00
|
|
|
|
|
|
|
|
using namespace trk;
|
|
|
|
|
|
2009-10-05 17:37:15 +02:00
|
|
|
namespace Debugger {
|
|
|
|
|
namespace Internal {
|
2010-06-25 15:06:30 +02:00
|
|
|
using namespace Symbian;
|
2009-09-09 17:24:21 +02:00
|
|
|
|
2010-02-05 12:24:46 +01:00
|
|
|
static inline void appendByte(QByteArray *ba, trk::byte b) { ba->append(b); }
|
|
|
|
|
|
2009-10-05 17:37:15 +02:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// TrkGdbAdapter
|
|
|
|
|
//
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
2009-09-09 17:24:21 +02:00
|
|
|
|
2010-06-30 17:14:57 +02:00
|
|
|
/* Thread handling:
|
|
|
|
|
* 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 trkContinueAll(), 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: Stop all threads once one stops? */
|
|
|
|
|
|
2010-04-09 08:43:26 +02:00
|
|
|
TrkGdbAdapter::TrkGdbAdapter(GdbEngine *engine) :
|
2009-09-21 11:09:38 +02:00
|
|
|
AbstractGdbAdapter(engine),
|
2009-09-18 12:51:15 +02:00
|
|
|
m_running(false),
|
|
|
|
|
m_gdbAckMode(true),
|
2009-12-18 16:25:59 +01:00
|
|
|
m_verbose(0)
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
2009-12-18 16:25:59 +01:00
|
|
|
m_bufferedMemoryRead = true;
|
2010-01-18 16:43:20 +01:00
|
|
|
// Disable buffering if gdb's dcache is used.
|
|
|
|
|
m_bufferedMemoryRead = false;
|
2009-12-18 16:25:59 +01:00
|
|
|
|
2009-09-30 09:16:55 +02:00
|
|
|
m_gdbServer = 0;
|
|
|
|
|
m_gdbConnection = 0;
|
2009-12-18 16:25:59 +01:00
|
|
|
m_snapshot.reset();
|
2009-09-14 15:27:12 +02:00
|
|
|
#ifdef Q_OS_WIN
|
2010-09-09 09:58:17 +02:00
|
|
|
const unsigned long portOffset = winGetCurrentProcessId() % 100;
|
2009-09-14 15:27:12 +02:00
|
|
|
#else
|
2009-09-18 12:51:15 +02:00
|
|
|
const uid_t portOffset = getuid();
|
2009-09-14 15:27:12 +02:00
|
|
|
#endif
|
2009-10-01 13:57:27 +02:00
|
|
|
m_gdbServerName = _("127.0.0.1:%1").arg(2222 + portOffset);
|
2009-10-06 13:33:06 +02:00
|
|
|
|
2010-11-10 16:33:11 +01:00
|
|
|
setVerbose(debuggerCore()->boolSetting(VerboseLog));
|
2009-09-09 17:24:21 +02:00
|
|
|
|
2010-11-10 16:33:11 +01:00
|
|
|
connect(debuggerCore()->action(VerboseLog), SIGNAL(valueChanged(QVariant)),
|
2010-01-15 12:01:26 +01:00
|
|
|
this, SLOT(setVerbose(QVariant)));
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
2009-09-11 15:53:08 +02:00
|
|
|
TrkGdbAdapter::~TrkGdbAdapter()
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
2009-10-05 15:07:47 +02:00
|
|
|
cleanup();
|
2009-09-10 13:09:42 +02:00
|
|
|
logMessage("Shutting down.\n");
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
2010-01-15 12:01:26 +01:00
|
|
|
void TrkGdbAdapter::setVerbose(const QVariant &value)
|
|
|
|
|
{
|
|
|
|
|
setVerbose(value.toInt());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrkGdbAdapter::setVerbose(int verbose)
|
|
|
|
|
{
|
|
|
|
|
m_verbose = verbose;
|
2010-02-11 12:31:59 +01:00
|
|
|
if (!m_trkDevice.isNull())
|
|
|
|
|
m_trkDevice->setVerbose(m_verbose);
|
2009-10-22 16:42:25 +02:00
|
|
|
}
|
|
|
|
|
|
2009-09-11 15:53:08 +02:00
|
|
|
void TrkGdbAdapter::trkLogMessage(const QString &msg)
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
|
|
|
|
logMessage("TRK " + msg);
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-11 15:53:08 +02:00
|
|
|
void TrkGdbAdapter::setGdbServerName(const QString &name)
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
|
|
|
|
m_gdbServerName = name;
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-11 15:53:08 +02:00
|
|
|
QString TrkGdbAdapter::gdbServerIP() const
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
|
|
|
|
int pos = m_gdbServerName.indexOf(':');
|
|
|
|
|
if (pos == -1)
|
|
|
|
|
return m_gdbServerName;
|
|
|
|
|
return m_gdbServerName.left(pos);
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-11 15:53:08 +02:00
|
|
|
uint TrkGdbAdapter::gdbServerPort() const
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
|
|
|
|
int pos = m_gdbServerName.indexOf(':');
|
|
|
|
|
if (pos == -1)
|
|
|
|
|
return 0;
|
|
|
|
|
return m_gdbServerName.mid(pos + 1).toUInt();
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-30 17:14:57 +02:00
|
|
|
QByteArray TrkGdbAdapter::trkContinueMessage(uint threadId)
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
|
|
|
|
QByteArray ba;
|
|
|
|
|
appendInt(&ba, m_session.pid);
|
2010-06-30 17:14:57 +02:00
|
|
|
appendInt(&ba, threadId);
|
2009-09-09 17:24:21 +02:00
|
|
|
return ba;
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-07 14:00:54 +02:00
|
|
|
QByteArray TrkGdbAdapter::trkWriteRegisterMessage(trk::byte reg, uint value)
|
2009-09-25 13:28:43 +02:00
|
|
|
{
|
|
|
|
|
QByteArray ba;
|
|
|
|
|
appendByte(&ba, 0); // ?
|
|
|
|
|
appendShort(&ba, reg);
|
|
|
|
|
appendShort(&ba, reg);
|
|
|
|
|
appendInt(&ba, m_session.pid);
|
|
|
|
|
appendInt(&ba, m_session.tid);
|
|
|
|
|
appendInt(&ba, value);
|
|
|
|
|
return ba;
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-05 17:37:15 +02:00
|
|
|
QByteArray TrkGdbAdapter::trkReadMemoryMessage(const MemoryRange &range)
|
|
|
|
|
{
|
2010-07-07 14:00:54 +02:00
|
|
|
return trk::Launcher::readMemoryMessage(m_session.pid, m_session.tid, range.from, range.size());
|
2009-10-05 17:37:15 +02:00
|
|
|
}
|
|
|
|
|
|
2009-10-02 16:56:48 +02:00
|
|
|
QByteArray TrkGdbAdapter::trkWriteMemoryMessage(uint addr, const QByteArray &data)
|
|
|
|
|
{
|
|
|
|
|
QByteArray ba;
|
|
|
|
|
ba.reserve(11 + data.size());
|
|
|
|
|
appendByte(&ba, 0x08); // Options, FIXME: why?
|
|
|
|
|
appendShort(&ba, data.size());
|
|
|
|
|
appendInt(&ba, addr);
|
|
|
|
|
appendInt(&ba, m_session.pid);
|
|
|
|
|
appendInt(&ba, m_session.tid);
|
|
|
|
|
ba.append(data);
|
|
|
|
|
return ba;
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-05 16:00:54 +01:00
|
|
|
QByteArray TrkGdbAdapter::trkStepRangeMessage()
|
2009-09-11 16:44:42 +02:00
|
|
|
{
|
2010-01-13 10:32:00 +01:00
|
|
|
//qDebug() << "STEP ON " << hexxNumber(m_snapshot.registers[RegisterPC]);
|
2010-02-04 09:55:07 +01:00
|
|
|
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-02-05 16:00:54 +01:00
|
|
|
trk::byte option = 0x01; // Step into.
|
2010-02-08 12:39:25 +01:00
|
|
|
if (m_snapshot.stepOver)
|
|
|
|
|
option = 0x11; // Step over.
|
2010-02-04 09:55:07 +01:00
|
|
|
if (from <= pc && pc <= to) {
|
2010-02-26 14:25:36 +01:00
|
|
|
//to = qMax(to - 4, from);
|
2010-02-08 12:39:25 +01:00
|
|
|
//to = qMax(to - 4, from);
|
2010-06-14 18:19:02 +02:00
|
|
|
showMessage("STEP IN " + hexxNumber(from) + " " + hexxNumber(to)
|
2010-02-05 13:48:10 +01:00
|
|
|
+ " INSTEAD OF " + hexxNumber(pc));
|
2010-02-04 09:55:07 +01:00
|
|
|
} else {
|
|
|
|
|
from = pc;
|
|
|
|
|
to = pc;
|
|
|
|
|
}
|
2010-06-25 15:06:30 +02:00
|
|
|
logMessage(QString::fromLatin1("Stepping from 0x%1 to 0x%2 (current PC=0x%3), option 0x%4").
|
|
|
|
|
arg(from, 0, 16).arg(to, 0, 16).arg(pc).arg(option, 0, 16));
|
2010-02-05 16:00:54 +01:00
|
|
|
QByteArray ba;
|
|
|
|
|
ba.reserve(17);
|
|
|
|
|
appendByte(&ba, option);
|
2010-02-04 09:55:07 +01:00
|
|
|
appendInt(&ba, from); // Start address
|
|
|
|
|
appendInt(&ba, to); // End address
|
2009-09-11 16:44:42 +02:00
|
|
|
appendInt(&ba, m_session.pid);
|
|
|
|
|
appendInt(&ba, m_session.tid);
|
|
|
|
|
return ba;
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-01 17:03:37 +02:00
|
|
|
QByteArray TrkGdbAdapter::trkDeleteProcessMessage()
|
|
|
|
|
{
|
|
|
|
|
QByteArray ba;
|
|
|
|
|
ba.reserve(6);
|
|
|
|
|
appendByte(&ba, 0); // ?
|
|
|
|
|
appendByte(&ba, 0); // Sub-command: Delete Process
|
|
|
|
|
appendInt(&ba, m_session.pid);
|
|
|
|
|
return ba;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QByteArray TrkGdbAdapter::trkInterruptMessage()
|
|
|
|
|
{
|
|
|
|
|
QByteArray ba;
|
|
|
|
|
ba.reserve(9);
|
|
|
|
|
// Stop the thread (2) or the process (1) or the whole system (0).
|
|
|
|
|
// We choose 2, as 1 does not seem to work.
|
|
|
|
|
appendByte(&ba, 2);
|
|
|
|
|
appendInt(&ba, m_session.pid);
|
2010-06-30 17:14:57 +02:00
|
|
|
appendInt(&ba, m_session.mainTid); // threadID: 4 bytes Variable number of bytes.
|
2009-10-01 17:03:37 +02:00
|
|
|
return ba;
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-08 18:10:50 +02:00
|
|
|
void TrkGdbAdapter::emitDelayedInferiorSetupFailed(const QString &msg)
|
2009-10-13 09:53:47 +02:00
|
|
|
{
|
|
|
|
|
m_adapterFailMessage = msg;
|
2010-07-08 18:10:50 +02:00
|
|
|
QTimer::singleShot(0, this, SLOT(slotEmitDelayedInferiorSetupFailed()));
|
2009-10-13 09:53:47 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-08 18:10:50 +02:00
|
|
|
void TrkGdbAdapter::slotEmitDelayedInferiorSetupFailed()
|
2009-10-13 09:53:47 +02:00
|
|
|
{
|
2010-07-09 17:07:59 +02:00
|
|
|
m_engine->notifyInferiorSetupFailed(m_adapterFailMessage);
|
2009-10-13 09:53:47 +02:00
|
|
|
}
|
|
|
|
|
|
2009-09-09 17:24:21 +02:00
|
|
|
|
2010-06-25 15:06:30 +02:00
|
|
|
void TrkGdbAdapter::logMessage(const QString &msg, int logChannel)
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
2010-06-25 15:06:30 +02:00
|
|
|
if (m_verbose || logChannel != LogDebug)
|
|
|
|
|
showMessage("TRK LOG: " + msg, logChannel);
|
2010-11-05 13:03:32 +01:00
|
|
|
MEMORY_DEBUG("GDB: " << msg);
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Gdb
|
|
|
|
|
//
|
2009-09-11 15:53:08 +02:00
|
|
|
void TrkGdbAdapter::handleGdbConnection()
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
|
|
|
|
logMessage("HANDLING GDB CONNECTION");
|
2009-09-30 09:16:55 +02:00
|
|
|
QTC_ASSERT(m_gdbConnection == 0, /**/);
|
|
|
|
|
m_gdbConnection = m_gdbServer->nextPendingConnection();
|
|
|
|
|
QTC_ASSERT(m_gdbConnection, return);
|
2009-09-09 17:24:21 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-11 15:53:08 +02:00
|
|
|
void TrkGdbAdapter::readGdbServerCommand()
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
2009-09-30 09:16:55 +02:00
|
|
|
QTC_ASSERT(m_gdbConnection, return);
|
2009-09-09 17:24:21 +02:00
|
|
|
QByteArray packet = m_gdbConnection->readAll();
|
|
|
|
|
m_gdbReadBuffer.append(packet);
|
|
|
|
|
|
2010-02-09 15:02:55 +01:00
|
|
|
logMessage("gdb: -> " + currentTime() + ' ' + QString::fromAscii(packet));
|
2009-09-09 17:24:21 +02:00
|
|
|
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 == '-') {
|
2010-06-25 15:06:30 +02:00
|
|
|
logMessage("NAK: Retransmission requested", LogError);
|
2010-01-13 15:19:57 +01:00
|
|
|
// This seems too harsh.
|
|
|
|
|
//emit adapterCrashed("Communication problem encountered.");
|
2009-09-09 17:24:21 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (code == char(0x03)) {
|
|
|
|
|
logMessage("INTERRUPT RECEIVED");
|
|
|
|
|
interruptInferior();
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (code != '$') {
|
|
|
|
|
logMessage("Broken package (2) " + quoteUnprintableLatin1(ba)
|
2010-06-25 15:06:30 +02:00
|
|
|
+ hexNumber(code), LogError);
|
2009-09-09 17:24:21 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int pos = ba.indexOf('#');
|
|
|
|
|
if (pos == -1) {
|
|
|
|
|
logMessage("Invalid checksum format in "
|
2010-06-25 15:06:30 +02:00
|
|
|
+ quoteUnprintableLatin1(ba), LogError);
|
2009-09-09 17:24:21 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ok = false;
|
|
|
|
|
uint checkSum = ba.mid(pos + 1, 2).toUInt(&ok, 16);
|
|
|
|
|
if (!ok) {
|
|
|
|
|
logMessage("Invalid checksum format 2 in "
|
2010-06-25 15:06:30 +02:00
|
|
|
+ quoteUnprintableLatin1(ba), LogError);
|
2009-09-09 17:24:21 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//logMessage(QString("Packet checksum: %1").arg(checkSum));
|
2010-02-05 12:24:46 +01:00
|
|
|
trk::byte sum = 0;
|
2009-09-09 17:24:21 +02:00
|
|
|
for (int i = 0; i < pos; ++i)
|
|
|
|
|
sum += ba.at(i);
|
|
|
|
|
|
|
|
|
|
if (sum != checkSum) {
|
|
|
|
|
logMessage(QString("ERROR: Packet checksum wrong: %1 %2 in "
|
2010-06-25 15:06:30 +02:00
|
|
|
+ quoteUnprintableLatin1(ba)).arg(checkSum).arg(sum), LogError);
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QByteArray cmd = ba.left(pos);
|
|
|
|
|
ba.remove(0, pos + 3);
|
|
|
|
|
handleGdbServerCommand(cmd);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-11 15:53:08 +02:00
|
|
|
bool TrkGdbAdapter::sendGdbServerPacket(const QByteArray &packet, bool doFlush)
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
|
|
|
|
if (!m_gdbConnection) {
|
2009-10-01 13:57:27 +02:00
|
|
|
logMessage(_("Cannot write to gdb: No connection (%1)")
|
2010-06-25 15:06:30 +02:00
|
|
|
.arg(_(packet)), LogError);
|
2009-09-09 17:24:21 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (m_gdbConnection->state() != QAbstractSocket::ConnectedState) {
|
2009-10-01 13:57:27 +02:00
|
|
|
logMessage(_("Cannot write to gdb: Not connected (%1)")
|
2010-06-25 15:06:30 +02:00
|
|
|
.arg(_(packet)), LogError);
|
2009-09-09 17:24:21 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (m_gdbConnection->write(packet) == -1) {
|
2009-10-01 13:57:27 +02:00
|
|
|
logMessage(_("Cannot write to gdb: %1 (%2)")
|
2010-06-25 15:06:30 +02:00
|
|
|
.arg(m_gdbConnection->errorString()).arg(_(packet)), LogError);
|
2009-09-09 17:24:21 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (doFlush)
|
|
|
|
|
m_gdbConnection->flush();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-11 15:53:08 +02:00
|
|
|
void TrkGdbAdapter::sendGdbServerAck()
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
|
|
|
|
if (!m_gdbAckMode)
|
|
|
|
|
return;
|
2010-01-18 16:58:55 +01:00
|
|
|
logMessage("gdb: <- +");
|
2010-02-03 17:22:44 +01:00
|
|
|
sendGdbServerPacket(QByteArray(1, '+'), false);
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
2009-09-11 15:53:08 +02:00
|
|
|
void TrkGdbAdapter::sendGdbServerMessage(const QByteArray &msg, const QByteArray &logNote)
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
2010-02-05 12:24:46 +01:00
|
|
|
trk::byte sum = 0;
|
2009-09-09 17:24:21 +02:00
|
|
|
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;
|
2010-02-03 17:22:44 +01:00
|
|
|
packet.append('$');
|
2009-09-09 17:24:21 +02:00
|
|
|
packet.append(msg);
|
|
|
|
|
packet.append('#');
|
|
|
|
|
packet.append(checkSum);
|
|
|
|
|
int pad = qMax(0, 24 - packet.size());
|
2010-02-09 15:02:55 +01:00
|
|
|
logMessage("gdb: <- " + currentTime() + ' ' + packet + QByteArray(pad, ' ') + logNote);
|
2009-09-09 17:24:21 +02:00
|
|
|
sendGdbServerPacket(packet, true);
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-11 15:53:08 +02:00
|
|
|
void TrkGdbAdapter::sendGdbServerMessageAfterTrkResponse(const QByteArray &msg,
|
2009-09-09 17:24:21 +02:00
|
|
|
const QByteArray &logNote)
|
|
|
|
|
{
|
|
|
|
|
QByteArray ba = msg + char(1) + logNote;
|
|
|
|
|
sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, TrkCB(reportToGdb), "", ba); // Answer gdb
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-11 15:53:08 +02:00
|
|
|
void TrkGdbAdapter::reportToGdb(const TrkResult &result)
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
|
|
|
|
QByteArray message = result.cookie.toByteArray();
|
|
|
|
|
QByteArray note;
|
|
|
|
|
int pos = message.lastIndexOf(char(1)); // HACK
|
|
|
|
|
if (pos != -1) {
|
|
|
|
|
note = message.mid(pos + 1);
|
|
|
|
|
message = message.left(pos);
|
|
|
|
|
}
|
|
|
|
|
message.replace("@CODESEG@", hexNumber(m_session.codeseg));
|
|
|
|
|
message.replace("@DATASEG@", hexNumber(m_session.dataseg));
|
|
|
|
|
message.replace("@PID@", hexNumber(m_session.pid));
|
|
|
|
|
message.replace("@TID@", hexNumber(m_session.tid));
|
|
|
|
|
sendGdbServerMessage(message, note);
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-11 15:53:08 +02:00
|
|
|
QByteArray TrkGdbAdapter::trkBreakpointMessage(uint addr, uint len, bool armMode)
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
|
|
|
|
QByteArray ba;
|
|
|
|
|
appendByte(&ba, 0x82); // unused option
|
|
|
|
|
appendByte(&ba, armMode /*bp.mode == ArmMode*/ ? 0x00 : 0x01);
|
|
|
|
|
appendInt(&ba, addr);
|
|
|
|
|
appendInt(&ba, len);
|
|
|
|
|
appendInt(&ba, 0x00000001);
|
|
|
|
|
appendInt(&ba, m_session.pid);
|
|
|
|
|
appendInt(&ba, 0xFFFFFFFF);
|
|
|
|
|
return ba;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-25 15:06:30 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-11 15:53:08 +02:00
|
|
|
void TrkGdbAdapter::handleGdbServerCommand(const QByteArray &cmd)
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
|
|
|
|
// 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");
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-03 17:22:44 +01:00
|
|
|
else if (cmd.startsWith('?')) {
|
2009-09-09 17:24:21 +02:00
|
|
|
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();
|
2010-06-30 17:14:57 +02:00
|
|
|
m_running = true;
|
|
|
|
|
trkContinueAll("gdb 'c'");
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
2010-02-03 17:22:44 +01:00
|
|
|
else if (cmd.startsWith('C')) {
|
2009-09-09 17:24:21 +02:00
|
|
|
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.
|
2010-06-30 17:14:57 +02:00
|
|
|
//TODO: Meaning of the message is not clear.
|
2009-09-09 17:24:21 +02:00
|
|
|
sendGdbServerAck();
|
|
|
|
|
bool ok = false;
|
2010-06-30 17:14:57 +02:00
|
|
|
const uint signalNumber = cmd.mid(1).toUInt(&ok, 16);
|
|
|
|
|
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
|
|
|
|
|
trkContinueAll("gdb 'C'");
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
2010-02-03 17:22:44 +01:00
|
|
|
else if (cmd.startsWith('D')) {
|
2009-09-09 17:24:21 +02:00
|
|
|
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-01-29 15:47:51 +01:00
|
|
|
//qDebug() << "Using cached register contents";
|
2009-12-18 16:25:59 +01:00
|
|
|
logMessage(msgGdbPacket(QLatin1String("Read registers")));
|
|
|
|
|
sendGdbServerAck();
|
|
|
|
|
reportRegisters();
|
|
|
|
|
} else {
|
2010-01-29 15:47:51 +01:00
|
|
|
//qDebug() << "Fetching register contents";
|
|
|
|
|
sendGdbServerAck();
|
2009-12-18 16:25:59 +01:00
|
|
|
sendTrkMessage(0x12,
|
|
|
|
|
TrkCB(handleAndReportReadRegisters),
|
2010-07-07 14:00:54 +02:00
|
|
|
Launcher::readRegistersMessage(m_session.pid, m_session.tid));
|
2009-12-18 16:25:59 +01:00
|
|
|
}
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
2010-01-29 15:47:51 +01:00
|
|
|
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-01-29 15:47:51 +01:00
|
|
|
sendTrkMessage(0x12,
|
|
|
|
|
TrkCB(handleAndReportReadRegisters),
|
2010-07-07 14:00:54 +02:00
|
|
|
Launcher::readRegistersMessage(m_session.pid, m_session.tid));
|
2010-01-29 15:47:51 +01:00
|
|
|
}
|
|
|
|
|
|
2010-02-05 16:00:54 +01:00
|
|
|
else if (cmd.startsWith("salstep,")) {
|
2010-02-04 09:55:07 +01:00
|
|
|
// 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));
|
2010-02-05 16:00:54 +01:00
|
|
|
}
|
|
|
|
|
|
2010-02-08 12:39:25 +01:00
|
|
|
else if (cmd.startsWith("salnext,")) {
|
2010-02-05 16:00:54 +01:00
|
|
|
// 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));
|
2010-02-04 09:55:07 +01:00
|
|
|
}
|
|
|
|
|
|
2009-09-09 17:24:21 +02:00
|
|
|
else if (cmd.startsWith("Hc")) {
|
|
|
|
|
sendGdbServerAck();
|
2010-06-30 17:14:57 +02:00
|
|
|
gdbSetCurrentThread(cmd, "Set current thread for step & continue ");
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (cmd.startsWith("Hg")) {
|
|
|
|
|
sendGdbServerAck();
|
2010-06-30 17:14:57 +02:00
|
|
|
gdbSetCurrentThread(cmd, "Set current thread ");
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
2009-09-11 14:19:04 +02:00
|
|
|
else if (cmd == "k" || cmd.startsWith("vKill")) {
|
2010-12-02 15:16:53 +01:00
|
|
|
trkKill();
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
2010-02-03 17:22:44 +01:00
|
|
|
else if (cmd.startsWith('m')) {
|
2009-09-09 17:24:21 +02:00
|
|
|
logMessage(msgGdbPacket(QLatin1String("Read memory")));
|
|
|
|
|
// m addr,length
|
|
|
|
|
sendGdbServerAck();
|
2010-06-30 17:14:57 +02:00
|
|
|
const QPair<quint64, unsigned> addrLength = parseGdbReadMemoryRequest(cmd);
|
|
|
|
|
if (addrLength.second) {
|
|
|
|
|
readMemory(addrLength.first, addrLength.second, m_bufferedMemoryRead);
|
2009-09-09 17:24:21 +02:00
|
|
|
} else {
|
|
|
|
|
sendGdbServerMessage("E20", "Error " + cmd);
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-09-25 13:28:43 +02:00
|
|
|
|
2010-02-03 17:22:44 +01:00
|
|
|
else if (cmd.startsWith('p')) {
|
2009-09-09 17:24:21 +02:00
|
|
|
logMessage(msgGdbPacket(QLatin1String("read register")));
|
|
|
|
|
// 0xf == current instruction pointer?
|
|
|
|
|
//sendGdbServerMessage("0000", "current IP");
|
|
|
|
|
sendGdbServerAck();
|
|
|
|
|
bool ok = false;
|
2010-01-13 15:19:57 +01:00
|
|
|
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[threadIndex];
|
|
|
|
|
if (thread.registerValid) {
|
|
|
|
|
sendGdbServerMessage(thread.gdbReportSingleRegister(registerNumber), thread.gdbSingleRegisterLogMessage(registerNumber));
|
2009-09-09 17:24:21 +02:00
|
|
|
} else {
|
2010-01-29 15:47:51 +01:00
|
|
|
//qDebug() << "Fetching single register";
|
2009-12-18 16:25:59 +01:00
|
|
|
sendTrkMessage(0x12,
|
|
|
|
|
TrkCB(handleAndReportReadRegister),
|
2010-07-07 14:00:54 +02:00
|
|
|
Launcher::readRegistersMessage(m_session.pid, m_session.tid), registerNumber);
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-03 17:22:44 +01:00
|
|
|
else if (cmd.startsWith('P')) {
|
2009-09-25 13:28:43 +02:00
|
|
|
logMessage(msgGdbPacket(QLatin1String("write register")));
|
|
|
|
|
// $Pe=70f96678#d3
|
|
|
|
|
sendGdbServerAck();
|
2010-06-30 17:14:57 +02:00
|
|
|
const QPair<uint, uint> regnumValue = parseGdbWriteRegisterWriteRequest(cmd);
|
2009-09-29 09:49:09 +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);
|
|
|
|
|
QByteArray ba = trkWriteRegisterMessage(regnumValue.first, regnumValue.second);
|
2009-09-25 13:28:43 +02:00
|
|
|
sendTrkMessage(0x13, TrkCB(handleWriteRegister), ba, "Write register");
|
|
|
|
|
// Note that App TRK refuses to write registers 13 and 14
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-09 17:24:21 +02:00
|
|
|
else if (cmd == "qAttached") {
|
|
|
|
|
//$qAttached#8f
|
|
|
|
|
// 1: attached to an existing process
|
|
|
|
|
// 0: created a new process
|
|
|
|
|
sendGdbServerAck();
|
2010-02-03 17:22:44 +01:00
|
|
|
sendGdbServerMessage(QByteArray(1, '0'), "new process created");
|
|
|
|
|
//sendGdbServerMessage('1', "attached to existing process");
|
2009-09-09 17:24:21 +02:00
|
|
|
//sendGdbServerMessage("E01", "new process created");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (cmd.startsWith("qC")) {
|
|
|
|
|
logMessage(msgGdbPacket(QLatin1String("query thread id")));
|
|
|
|
|
// Return the current thread ID
|
|
|
|
|
//$qC#b4
|
|
|
|
|
sendGdbServerAck();
|
|
|
|
|
sendGdbServerMessageAfterTrkResponse("QC@TID@");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (cmd.startsWith("qSupported")) {
|
|
|
|
|
//$qSupported#37
|
|
|
|
|
//$qSupported:multiprocess+#c6
|
|
|
|
|
//logMessage("Handling 'qSupported'");
|
2010-07-08 18:10:50 +02:00
|
|
|
sendGdbServerAck();
|
2010-06-30 17:14:57 +02:00
|
|
|
sendGdbServerMessage(Symbian::gdbQSupported);
|
2009-09-11 14:19:04 +02:00
|
|
|
}
|
|
|
|
|
|
2010-09-14 16:39:44 +02:00
|
|
|
// Tracepoint handling as of gdb 7.2 onwards
|
|
|
|
|
else if (cmd == "qTStatus") { // Tracepoints
|
|
|
|
|
sendGdbServerAck();
|
|
|
|
|
sendGdbServerMessage("T0;tnotrun:0", QByteArray("No trace experiment running"));
|
|
|
|
|
}
|
|
|
|
|
// Trace variables as of gdb 7.2 onwards
|
|
|
|
|
else if (cmd == "qTfV" || cmd == "qTsP" || cmd == "qTfP") {
|
|
|
|
|
sendGdbServerAck();
|
|
|
|
|
sendGdbServerMessage("l", QByteArray("No trace points"));
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-29 15:47:51 +01:00
|
|
|
else if (cmd.startsWith("qThreadExtraInfo")) {
|
|
|
|
|
// $qThreadExtraInfo,1f9#55
|
|
|
|
|
sendGdbServerAck();
|
2010-06-30 17:14:57 +02:00
|
|
|
sendGdbServerMessage(m_snapshot.gdbQThreadExtraInfo(cmd));
|
2010-01-29 15:47:51 +01:00
|
|
|
}
|
|
|
|
|
|
2009-09-11 14:19:04 +02:00
|
|
|
else if (cmd == "qfDllInfo") {
|
2009-10-23 15:46:39 +02:00
|
|
|
// 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 transferred");
|
2009-10-23 15:46:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (cmd == "qsDllInfo") {
|
|
|
|
|
// That's a following query package
|
2009-09-11 14:19:04 +02:00
|
|
|
sendGdbServerAck();
|
2010-02-03 17:22:44 +01:00
|
|
|
sendGdbServerMessage(QByteArray(1, 'l'), "library information transfer finished");
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (cmd == "qPacketInfo") {
|
|
|
|
|
// happens with gdb 6.4.50.20060226-cvs / CodeSourcery
|
|
|
|
|
// deprecated by qSupported?
|
|
|
|
|
sendGdbServerAck();
|
|
|
|
|
sendGdbServerMessage("", "FIXME: nothing?");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (cmd == "qOffsets") {
|
|
|
|
|
sendGdbServerAck();
|
|
|
|
|
sendGdbServerMessageAfterTrkResponse("TextSeg=@CODESEG@;DataSeg=@DATASEG@");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (cmd == "qSymbol::") {
|
|
|
|
|
if (m_verbose)
|
|
|
|
|
logMessage(msgGdbPacket(QLatin1String("notify can handle symbol lookup")));
|
|
|
|
|
// Notify the target that GDB is prepared to serve symbol lookup requests.
|
|
|
|
|
sendGdbServerAck();
|
|
|
|
|
if (1)
|
|
|
|
|
sendGdbServerMessage("OK", "no further symbols needed");
|
|
|
|
|
else
|
2009-09-11 14:19:04 +02:00
|
|
|
sendGdbServerMessage("qSymbol:" + QByteArray("_Z7E32Mainv").toHex(),
|
|
|
|
|
"ask for more");
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
2009-12-18 16:25:59 +01: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");
|
2009-12-18 16:25:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (cmd == "qsThreadInfo") {
|
|
|
|
|
// That's a following query package
|
|
|
|
|
sendGdbServerAck();
|
2010-02-03 17:22:44 +01:00
|
|
|
sendGdbServerMessage(QByteArray(1, 'l'), "thread information transfer finished");
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
2009-10-02 10:02:34 +02:00
|
|
|
else if (cmd.startsWith("qXfer:libraries:read")) {
|
|
|
|
|
sendGdbServerAck();
|
2010-06-30 17:14:57 +02:00
|
|
|
sendGdbServerMessage(m_session.gdbLibraryList(), "library information transferred");
|
2009-10-02 10:02:34 +02:00
|
|
|
}
|
|
|
|
|
|
2009-09-09 17:24:21 +02:00
|
|
|
else if (cmd == "QStartNoAckMode") {
|
|
|
|
|
//$qSupported#37
|
2010-01-18 16:58:55 +01:00
|
|
|
logMessage("Handling 'QStartNoAckMode'");
|
2009-09-09 17:24:21 +02:00
|
|
|
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)));
|
2009-09-09 17:24:21 +02:00
|
|
|
sendGdbServerAck();
|
2010-01-19 17:09:18 +01:00
|
|
|
//m_snapshot.reset();
|
2009-09-09 17:24:21 +02:00
|
|
|
m_running = true;
|
2010-02-05 16:00:54 +01:00
|
|
|
QByteArray ba = trkStepRangeMessage();
|
|
|
|
|
sendTrkMessage(0x19, TrkCB(handleStep), ba, "Step range");
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
2009-12-18 16:25:59 +01:00
|
|
|
else if (cmd.startsWith('T')) {
|
|
|
|
|
// FIXME: check whether thread is alive
|
|
|
|
|
sendGdbServerAck();
|
|
|
|
|
sendGdbServerMessage("OK"); // pretend all is well
|
|
|
|
|
//sendGdbServerMessage("E nn");
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-09 17:24:21 +02:00
|
|
|
else if (cmd == "vCont?") {
|
|
|
|
|
// actions supported by the vCont packet
|
|
|
|
|
sendGdbServerAck();
|
|
|
|
|
//sendGdbServerMessage("OK"); // we don't support vCont.
|
2009-09-15 15:01:25 +02:00
|
|
|
sendGdbServerMessage("vCont;c;C;s;S");
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (cmd == "vCont;c") {
|
|
|
|
|
// vCont[;action[:thread-id]]...'
|
|
|
|
|
sendGdbServerAck();
|
2010-01-19 17:09:18 +01:00
|
|
|
//m_snapshot.reset();
|
2009-09-09 17:24:21 +02:00
|
|
|
m_running = true;
|
2010-06-30 17:14:57 +02:00
|
|
|
trkContinueAll("gdb 'vCont;c'");
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (cmd.startsWith("Z0,") || cmd.startsWith("Z1,")) {
|
|
|
|
|
// Insert breakpoint
|
2009-09-11 14:19:04 +02:00
|
|
|
sendGdbServerAck();
|
2009-09-09 17:24:21 +02:00
|
|
|
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-01-13 10:32:00 +01: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));
|
|
|
|
|
const bool armMode = addrLen.second == 4;
|
|
|
|
|
const QByteArray ba = trkBreakpointMessage(addrLen.first, addrLen.second, armMode);
|
|
|
|
|
sendTrkMessage(0x1B, TrkCB(handleAndReportSetBreakpoint), ba, QVariant(addrLen.first));
|
|
|
|
|
} else {
|
|
|
|
|
logMessage("MISPARSED BREAKPOINT '" + cmd + "')", LogError);
|
2010-01-13 10:32:00 +01:00
|
|
|
}
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (cmd.startsWith("z0,") || cmd.startsWith("z1,")) {
|
|
|
|
|
// Remove breakpoint
|
2009-09-11 14:19:04 +02:00
|
|
|
sendGdbServerAck();
|
2009-09-09 17:24:21 +02:00
|
|
|
logMessage(msgGdbPacket(QLatin1String("Remove breakpoint")));
|
|
|
|
|
// $z0,786a4ccc,4#99
|
|
|
|
|
const int pos = cmd.lastIndexOf(',');
|
|
|
|
|
bool ok = false;
|
2010-01-13 10:32:00 +01:00
|
|
|
const uint addr = cmd.mid(3, pos - 3).toUInt(&ok, 16);
|
|
|
|
|
const uint len = cmd.mid(pos + 1).toUInt(&ok, 16);
|
2009-09-09 17:24:21 +02:00
|
|
|
const uint bp = m_session.addressToBP[addr];
|
|
|
|
|
if (bp == 0) {
|
2009-10-01 13:57:27 +02:00
|
|
|
logMessage(_("NO RECORDED BP AT 0x%1, %2")
|
2010-06-25 15:06:30 +02:00
|
|
|
.arg(addr, 0, 16).arg(len), LogError);
|
2009-09-10 13:09:42 +02:00
|
|
|
sendGdbServerMessage("E00");
|
2009-09-09 17:24:21 +02:00
|
|
|
} else {
|
|
|
|
|
m_session.addressToBP.remove(addr);
|
|
|
|
|
QByteArray ba;
|
2009-10-01 13:28:18 +02:00
|
|
|
appendInt(&ba, bp);
|
2009-09-09 17:24:21 +02:00
|
|
|
sendTrkMessage(0x1C, TrkCB(handleClearBreakpoint), ba, addr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (cmd.startsWith("qPart:") || cmd.startsWith("qXfer:")) {
|
2009-12-18 16:25:59 +01:00
|
|
|
QByteArray data = cmd.mid(1 + cmd.indexOf(':'));
|
2009-09-09 17:24:21 +02:00
|
|
|
// "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(',');
|
2010-01-29 21:33:57 +01:00
|
|
|
if (commaPos != -1) {
|
2009-09-09 17:24:21 +02:00
|
|
|
bool ok1 = false, ok2 = false;
|
|
|
|
|
const int offset = data.mid(offsetPos, commaPos - offsetPos)
|
2010-01-13 10:32:00 +01:00
|
|
|
.toUInt(&ok1, 16);
|
|
|
|
|
const int length = data.mid(commaPos + 1).toUInt(&ok2, 16);
|
2009-09-09 17:24:21 +02:00
|
|
|
if (ok1 && ok2) {
|
2010-01-11 10:22:55 +01:00
|
|
|
const QString msg = _("Read of OS auxiliary "
|
2009-09-09 17:24:21 +02:00
|
|
|
"vector (%1, %2) not implemented.").arg(offset).arg(length);
|
2010-06-25 15:06:30 +02:00
|
|
|
logMessage(msgGdbPacket(msg), LogWarning);
|
2009-09-09 17:24:21 +02:00
|
|
|
sendGdbServerMessage("E20", msg.toLatin1());
|
|
|
|
|
handled = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} // auxv read
|
2009-12-18 16:25:59 +01:00
|
|
|
|
2009-09-09 17:24:21 +02:00
|
|
|
if (!handled) {
|
|
|
|
|
const QString msg = QLatin1String("FIXME unknown 'XFER'-request: ")
|
|
|
|
|
+ QString::fromAscii(cmd);
|
2010-06-25 15:06:30 +02:00
|
|
|
logMessage(msgGdbPacket(msg), LogWarning);
|
2009-09-09 17:24:21 +02:00
|
|
|
sendGdbServerMessage("E20", msg.toLatin1());
|
|
|
|
|
}
|
|
|
|
|
} // qPart/qXfer
|
2010-10-01 18:37:30 +02:00
|
|
|
|
|
|
|
|
else if (cmd.startsWith("X")) {
|
|
|
|
|
logMessage(msgGdbPacket(QLatin1String("Write memory")));
|
|
|
|
|
// X addr,length
|
|
|
|
|
sendGdbServerAck();
|
|
|
|
|
const QPair<quint64, unsigned> addrLength = parseGdbReadMemoryRequest(cmd);
|
|
|
|
|
int pos = cmd.indexOf(':');
|
|
|
|
|
m_snapshot.resetMemory();
|
|
|
|
|
writeMemory(addrLength.first, cmd.mid(pos + 1, addrLength.second));
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-09 17:24:21 +02:00
|
|
|
else {
|
|
|
|
|
logMessage(msgGdbPacket(QLatin1String("FIXME unknown: ")
|
2010-06-25 15:06:30 +02:00
|
|
|
+ QString::fromAscii(cmd)), LogWarning);
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-30 17:14:57 +02:00
|
|
|
void TrkGdbAdapter::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-12-02 15:16:53 +01:00
|
|
|
void TrkGdbAdapter::trkKill()
|
|
|
|
|
{
|
|
|
|
|
// Kill inferior process
|
|
|
|
|
logMessage(msgGdbPacket(QLatin1String("kill")));
|
|
|
|
|
sendTrkMessage(0x41, TrkCB(handleDeleteProcess),
|
|
|
|
|
trkDeleteProcessMessage(), "Delete process");
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-30 17:14:57 +02:00
|
|
|
void TrkGdbAdapter::trkContinueAll(const char *why)
|
|
|
|
|
{
|
|
|
|
|
if (why)
|
|
|
|
|
logMessage(QString::fromLatin1("Continuing %1 threads (%2)").
|
|
|
|
|
arg(m_snapshot.threadInfo.size()).arg(QString::fromLatin1(why)));
|
|
|
|
|
|
|
|
|
|
// Starting from the last one, continue all threads.
|
|
|
|
|
QTC_ASSERT(!m_snapshot.threadInfo.isEmpty(), return; );
|
|
|
|
|
trkContinueNext(m_snapshot.threadInfo.size() - 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrkGdbAdapter::trkContinueNext(int threadIndex)
|
|
|
|
|
{
|
|
|
|
|
const uint threadId = m_snapshot.threadInfo.at(threadIndex).id;
|
|
|
|
|
logMessage(QString::fromLatin1("Continuing thread 0x%1 of %2").
|
|
|
|
|
arg(threadId,0, 16).arg(m_snapshot.threadInfo.size()));
|
|
|
|
|
sendTrkMessage(0x18, TrkCallback(this, &TrkGdbAdapter::handleTrkContinueNext),
|
|
|
|
|
trkContinueMessage(threadId), QVariant(threadIndex));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrkGdbAdapter::handleTrkContinueNext(const TrkResult &result)
|
|
|
|
|
{
|
2010-07-08 18:10:50 +02:00
|
|
|
const int index = result.cookie.toInt();
|
2010-06-30 17:14:57 +02:00
|
|
|
if (result.errorCode()) {
|
|
|
|
|
logMessage("Error continuing thread: " + result.errorString(), LogError);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// Remove the thread (unless main) if it is continued since we
|
|
|
|
|
// do not get thread creation/deletion events
|
|
|
|
|
QTC_ASSERT(index < m_snapshot.threadInfo.size(), return; );
|
|
|
|
|
if (m_snapshot.threadInfo.at(index).id != m_session.mainTid)
|
|
|
|
|
m_snapshot.threadInfo.remove(index);
|
|
|
|
|
if (index > 0 && m_running) // Stopped in-between
|
|
|
|
|
trkContinueNext(index - 1);
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-05 12:24:46 +01:00
|
|
|
void TrkGdbAdapter::sendTrkMessage(trk::byte code, TrkCallback callback,
|
2009-09-09 17:24:21 +02:00
|
|
|
const QByteArray &data, const QVariant &cookie)
|
|
|
|
|
{
|
2010-02-01 12:16:27 +01:00
|
|
|
if (m_verbose >= 2)
|
|
|
|
|
logMessage("trk: -> " + QByteArray::number(code, 16) + " "
|
|
|
|
|
+ stringFromArray(data));
|
2009-10-26 11:55:02 +01:00
|
|
|
m_trkDevice->sendTrkMessage(code, callback, data, cookie);
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
2010-02-05 12:24:46 +01:00
|
|
|
void TrkGdbAdapter::sendTrkAck(trk::byte token)
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
2009-09-15 15:01:25 +02:00
|
|
|
//logMessage(QString("SENDING ACKNOWLEDGEMENT FOR TOKEN %1").arg(int(token)));
|
2009-10-26 11:55:02 +01:00
|
|
|
m_trkDevice->sendTrkAck(token);
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
2009-09-11 15:53:08 +02:00
|
|
|
void TrkGdbAdapter::handleTrkError(const QString &msg)
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
2010-06-25 15:06:30 +02:00
|
|
|
logMessage("## TRK ERROR: " + msg, LogError);
|
2010-07-08 12:41:26 +02:00
|
|
|
m_engine->handleAdapterCrashed("TRK problem encountered:\n" + msg);
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
2009-09-11 15:53:08 +02:00
|
|
|
void TrkGdbAdapter::handleTrkResult(const TrkResult &result)
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
2010-02-01 12:16:27 +01:00
|
|
|
if (m_verbose >= 2)
|
|
|
|
|
logMessage("trk: <- " + result.toString());
|
2009-09-09 17:24:21 +02:00
|
|
|
if (result.isDebugOutput) {
|
2010-01-13 15:19:57 +01:00
|
|
|
// It looks like those messages _must not_ be acknowledged.
|
|
|
|
|
// If we do so, TRK will complain about wrong sequencing.
|
|
|
|
|
//sendTrkAck(result.token);
|
2010-06-25 15:06:30 +02:00
|
|
|
logMessage(QString::fromAscii(result.data), AppOutput);
|
2009-09-09 17:24:21 +02:00
|
|
|
sendGdbServerMessage("O" + result.data.toHex());
|
|
|
|
|
return;
|
|
|
|
|
}
|
2009-09-15 15:01:25 +02:00
|
|
|
//logMessage("READ TRK " + result.toString());
|
2009-09-09 17:24:21 +02:00
|
|
|
QByteArray prefix = "READ BUF: ";
|
|
|
|
|
QByteArray str = result.toString().toUtf8();
|
|
|
|
|
switch (result.code) {
|
|
|
|
|
case 0x80: // ACK
|
|
|
|
|
break;
|
|
|
|
|
case 0xff: { // NAK. This mostly means transmission error, not command failed.
|
|
|
|
|
QString logMsg;
|
|
|
|
|
QTextStream(&logMsg) << prefix << "NAK: for token=" << result.token
|
|
|
|
|
<< " ERROR: " << errorMessage(result.data.at(0)) << ' ' << str;
|
2010-06-25 15:06:30 +02:00
|
|
|
logMessage(logMsg, LogError);
|
2009-09-09 17:24:21 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2010-01-21 16:55:15 +01:00
|
|
|
case TrkNotifyStopped: { // 0x90 Notified Stopped
|
2009-09-09 17:24:21 +02:00
|
|
|
// 90 01 78 6a 40 40 00 00 07 23 00 00 07 24 00 00
|
2010-06-14 18:19:02 +02:00
|
|
|
showMessage(_("RESET SNAPSHOT (NOTIFY STOPPED)"));
|
2010-11-05 13:03:32 +01:00
|
|
|
MEMORY_DEBUG("WE STOPPED");
|
2010-01-13 12:35:57 +01:00
|
|
|
m_snapshot.reset();
|
2010-11-05 13:03:32 +01:00
|
|
|
MEMORY_DEBUG(" AFTER CLEANING: " << m_snapshot.memory.size() << " BLOCKS LEFT");
|
2010-01-21 15:46:33 +01:00
|
|
|
QString reason;
|
|
|
|
|
uint addr;
|
|
|
|
|
uint pid;
|
|
|
|
|
uint tid;
|
|
|
|
|
trk::Launcher::parseNotifyStopped(result.data, &pid, &tid, &addr, &reason);
|
|
|
|
|
const QString msg = trk::Launcher::msgStopped(pid, tid, addr, reason);
|
2010-06-30 17:14:57 +02:00
|
|
|
// Unknown thread: Add.
|
2010-07-08 18:10:50 +02:00
|
|
|
m_session.tid = tid;
|
2010-06-30 17:14:57 +02:00
|
|
|
if (m_snapshot.indexOfThread(tid) == -1)
|
2010-07-08 18:10:50 +02:00
|
|
|
m_snapshot.addThread(tid);
|
2010-06-30 17:14:57 +02:00
|
|
|
m_snapshot.setThreadState(tid, reason);
|
|
|
|
|
|
2010-01-21 15:46:33 +01:00
|
|
|
logMessage(prefix + msg);
|
2010-06-14 18:19:02 +02:00
|
|
|
showMessage(msg, LogMisc);
|
2009-09-09 17:24:21 +02:00
|
|
|
sendTrkAck(result.token);
|
|
|
|
|
if (addr) {
|
|
|
|
|
// Todo: Do not send off GdbMessages if a synced gdb
|
|
|
|
|
// query is pending, queue instead
|
|
|
|
|
if (m_running) {
|
|
|
|
|
m_running = false;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
logMessage(QLatin1String("Ignoring stop at 0"));
|
|
|
|
|
}
|
2010-01-19 17:09:18 +01:00
|
|
|
|
2010-06-10 13:12:12 +02:00
|
|
|
# if 1
|
2009-09-14 10:28:09 +02:00
|
|
|
// We almost always need register values, so get them
|
2010-01-19 17:09:18 +01:00
|
|
|
// now before informing gdb about the stop.s
|
2010-09-29 16:39:46 +02:00
|
|
|
const int signalNumber = reason.contains(QLatin1String("exception"), Qt::CaseInsensitive)
|
|
|
|
|
|| reason.contains(QLatin1String("panic"), Qt::CaseInsensitive) ?
|
|
|
|
|
gdbServerSignalSegfault : gdbServerSignalTrap;
|
2009-09-14 10:28:09 +02:00
|
|
|
sendTrkMessage(0x12,
|
|
|
|
|
TrkCB(handleAndReportReadRegistersAfterStop),
|
2010-09-29 16:39:46 +02:00
|
|
|
Launcher::readRegistersMessage(m_session.pid, m_session.tid), signalNumber);
|
2010-06-10 13:12:12 +02:00
|
|
|
# else
|
2010-01-19 17:09:18 +01:00
|
|
|
// As a source-line step typically consists of
|
|
|
|
|
// several instruction steps, better avoid the multiple
|
|
|
|
|
// roundtrips through TRK in favour of an additional
|
|
|
|
|
// roundtrip through gdb. But gdb will ask for all registers.
|
2010-06-10 13:12:12 +02:00
|
|
|
# if 1
|
2010-02-01 12:16:27 +01:00
|
|
|
sendGdbServerMessage("S05", "Target stopped");
|
2010-06-10 13:12:12 +02:00
|
|
|
# else
|
2010-02-01 12:16:27 +01:00
|
|
|
QByteArray ba = "T05";
|
|
|
|
|
appendRegister(&ba, RegisterPSGdb, addr);
|
|
|
|
|
sendGdbServerMessage(ba, "Registers");
|
2010-06-10 13:12:12 +02:00
|
|
|
# endif
|
|
|
|
|
# endif
|
2009-09-09 17:24:21 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2010-01-21 16:55:15 +01:00
|
|
|
case TrkNotifyException: { // 0x91 Notify Exception (obsolete)
|
2010-06-14 18:19:02 +02:00
|
|
|
showMessage(_("RESET SNAPSHOT (NOTIFY EXCEPTION)"));
|
2010-01-13 12:35:57 +01:00
|
|
|
m_snapshot.reset();
|
2010-06-25 15:06:30 +02:00
|
|
|
logMessage(prefix + "NOTE: EXCEPTION " + str, AppError);
|
2009-09-09 17:24:21 +02:00
|
|
|
sendTrkAck(result.token);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 0x92: { //
|
2010-06-14 18:19:02 +02:00
|
|
|
showMessage(_("RESET SNAPSHOT (NOTIFY INTERNAL ERROR)"));
|
2010-01-13 12:35:57 +01:00
|
|
|
m_snapshot.reset();
|
2010-06-25 15:06:30 +02:00
|
|
|
logMessage(prefix + "NOTE: INTERNAL ERROR: " + str, LogError);
|
2009-09-09 17:24:21 +02:00
|
|
|
sendTrkAck(result.token);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// target->host OS notification
|
|
|
|
|
case 0xa0: { // Notify Created
|
2010-01-13 15:19:57 +01:00
|
|
|
// Sending this ACK does not seem to make a difference. Why?
|
|
|
|
|
//sendTrkAck(result.token);
|
2010-06-30 17:14:57 +02:00
|
|
|
m_snapshot.resetMemory();
|
2009-09-09 17:24:21 +02:00
|
|
|
const char *data = result.data.data();
|
2010-02-05 12:24:46 +01:00
|
|
|
const trk::byte error = result.data.at(0);
|
2009-09-09 17:24:21 +02:00
|
|
|
// type: 1 byte; for dll item, this value is 2.
|
2010-02-05 12:24:46 +01:00
|
|
|
const trk::byte type = result.data.at(1);
|
2009-09-09 17:24:21 +02:00
|
|
|
const uint tid = extractInt(data + 6);
|
2010-07-07 14:00:54 +02:00
|
|
|
const Library lib = Library(result);
|
|
|
|
|
m_session.libraries.push_back(lib);
|
|
|
|
|
m_session.modules += QString::fromAscii(lib.name);
|
2009-09-09 17:24:21 +02:00
|
|
|
QString logMsg;
|
|
|
|
|
QTextStream str(&logMsg);
|
|
|
|
|
str << prefix << " NOTE: LIBRARY LOAD: token=" << result.token;
|
|
|
|
|
if (error)
|
|
|
|
|
str << " ERROR: " << int(error);
|
2010-07-07 14:00:54 +02:00
|
|
|
str << " TYPE: " << int(type) << " PID: " << lib.pid << " TID: " << tid;
|
|
|
|
|
str << " CODE: " << hexxNumber(lib.codeseg);
|
|
|
|
|
str << " DATA: " << hexxNumber(lib.dataseg);
|
|
|
|
|
str << " NAME: '" << lib.name << '\'';
|
2010-06-30 17:14:57 +02:00
|
|
|
if (tid && tid != unsigned(-1) && m_snapshot.indexOfThread(tid) == -1)
|
|
|
|
|
m_snapshot.addThread(tid);
|
2009-09-09 17:24:21 +02:00
|
|
|
logMessage(logMsg);
|
2010-12-02 14:07:53 +01:00
|
|
|
// Load local symbol file into gdb provided there is one
|
|
|
|
|
if (lib.codeseg) {
|
|
|
|
|
const QString localSymFileName = Symbian::localSymFileForLibrary(lib.name, m_symbolFileFolder);
|
|
|
|
|
if (!localSymFileName.isEmpty()) {
|
|
|
|
|
showMessage(Symbian::msgLoadLocalSymFile(localSymFileName, lib.name, lib.codeseg), LogMisc);
|
|
|
|
|
m_engine->postCommand(Symbian::symFileLoadCommand(localSymFileName, lib.codeseg, lib.dataseg));
|
|
|
|
|
} // has local sym
|
|
|
|
|
} // code seg
|
|
|
|
|
|
2009-10-02 11:45:19 +02:00
|
|
|
// This lets gdb trigger a register update etc.
|
|
|
|
|
// With CS gdb 6.4 we get a non-standard $qfDllInfo#7f+ request
|
|
|
|
|
// afterwards, so don't use it for now.
|
|
|
|
|
//sendGdbServerMessage("T05library:;");
|
2010-01-13 15:19:57 +01:00
|
|
|
/*
|
|
|
|
|
// Causes too much "stopped" (by SIGTRAP) messages that need
|
|
|
|
|
// to be answered by "continue". Auto-continuing each SIGTRAP
|
|
|
|
|
// is not possible as this is also the real message for a user
|
|
|
|
|
// initiated interrupt.
|
2009-10-23 15:46:39 +02:00
|
|
|
sendGdbServerMessage("T05load:Name=" + lib.name.toHex()
|
|
|
|
|
+ ",TextSeg=" + hexNumber(lib.codeseg)
|
|
|
|
|
+ ",DataSeg=" + hexNumber(lib.dataseg) + ';');
|
2010-01-13 15:19:57 +01:00
|
|
|
*/
|
2010-02-01 12:16:27 +01:00
|
|
|
|
|
|
|
|
// After 'continue' the very first time after starting debugging
|
|
|
|
|
// a process some library load events are generated, these are
|
|
|
|
|
// actually static dependencies for the process. For these libraries,
|
|
|
|
|
// the thread id is -1 which means the debugger doesn't have
|
|
|
|
|
// to continue. The debugger can safely assume that the
|
|
|
|
|
// thread resumption will be handled by the agent itself.
|
|
|
|
|
if (tid != unsigned(-1))
|
2010-06-30 17:14:57 +02:00
|
|
|
sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(m_session.mainTid), "CONTINUE");
|
2009-09-09 17:24:21 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 0xa1: { // NotifyDeleted
|
|
|
|
|
const ushort itemType = extractByte(result.data.data() + 1);
|
|
|
|
|
const ushort len = result.data.size() > 12
|
|
|
|
|
? extractShort(result.data.data() + 10) : ushort(0);
|
|
|
|
|
const QString name = len
|
|
|
|
|
? QString::fromAscii(result.data.mid(12, len)) : QString();
|
|
|
|
|
if (!name.isEmpty())
|
|
|
|
|
m_session.modules.removeAll(name);
|
2009-10-01 13:57:27 +02:00
|
|
|
logMessage(_("%1 %2 UNLOAD: %3")
|
2009-09-09 17:24:21 +02:00
|
|
|
.arg(QString::fromAscii(prefix))
|
|
|
|
|
.arg(itemType ? QLatin1String("LIB") : QLatin1String("PROCESS"))
|
|
|
|
|
.arg(name));
|
|
|
|
|
sendTrkAck(result.token);
|
|
|
|
|
if (itemType == 0) {
|
|
|
|
|
sendGdbServerMessage("W00", "Process exited");
|
|
|
|
|
//sendTrkMessage(0x02, TrkCB(handleDisconnect));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 0xa2: { // NotifyProcessorStarted
|
|
|
|
|
logMessage(prefix + "NOTE: PROCESSOR STARTED: " + str);
|
|
|
|
|
sendTrkAck(result.token);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 0xa6: { // NotifyProcessorStandby
|
|
|
|
|
logMessage(prefix + "NOTE: PROCESSOR STANDBY: " + str);
|
|
|
|
|
sendTrkAck(result.token);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 0xa7: { // NotifyProcessorReset
|
|
|
|
|
logMessage(prefix + "NOTE: PROCESSOR RESET: " + str);
|
|
|
|
|
sendTrkAck(result.token);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default: {
|
2010-06-25 15:06:30 +02:00
|
|
|
logMessage(prefix + "INVALID: " + str, LogError);
|
2009-09-09 17:24:21 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-11 15:53:08 +02:00
|
|
|
void TrkGdbAdapter::handleCpuType(const TrkResult &result)
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
|
|
|
|
//---TRK------------------------------------------------------
|
|
|
|
|
// Command: 0x80 Acknowledge
|
|
|
|
|
// Error: 0x00
|
|
|
|
|
// [80 03 00 04 00 00 04 00 00 00]
|
|
|
|
|
m_session.cpuMajor = result.data[1];
|
|
|
|
|
m_session.cpuMinor = result.data[2];
|
|
|
|
|
m_session.bigEndian = result.data[3];
|
|
|
|
|
m_session.defaultTypeSize = result.data[4];
|
|
|
|
|
m_session.fpTypeSize = result.data[5];
|
|
|
|
|
m_session.extended1TypeSize = result.data[6];
|
|
|
|
|
//m_session.extended2TypeSize = result.data[6];
|
|
|
|
|
QString logMsg;
|
|
|
|
|
QTextStream(&logMsg) << "HANDLE CPU TYPE: CPU=" << m_session.cpuMajor << '.'
|
|
|
|
|
<< m_session.cpuMinor << " bigEndian=" << m_session.bigEndian
|
|
|
|
|
<< " defaultTypeSize=" << m_session.defaultTypeSize
|
|
|
|
|
<< " fpTypeSize=" << m_session.fpTypeSize
|
|
|
|
|
<< " extended1TypeSize=" << m_session.extended1TypeSize;
|
|
|
|
|
logMessage(logMsg);
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-16 13:43:03 +02:00
|
|
|
void TrkGdbAdapter::handleDeleteProcess(const TrkResult &result)
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(result);
|
2009-10-29 14:18:49 +01:00
|
|
|
logMessage("Inferior process killed");
|
2009-09-16 13:43:03 +02:00
|
|
|
//sendTrkMessage(0x01, TrkCB(handleDeleteProcess2)); // Ping
|
|
|
|
|
sendTrkMessage(0x02, TrkCB(handleDeleteProcess2)); // Disconnect
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrkGdbAdapter::handleDeleteProcess2(const TrkResult &result)
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(result);
|
2010-12-02 15:16:53 +01:00
|
|
|
QString msg = QString::fromLatin1("App TRK disconnected");
|
|
|
|
|
|
|
|
|
|
const bool emergencyShutdown = m_gdbProc.state() != QProcess::Running;
|
|
|
|
|
if (emergencyShutdown)
|
|
|
|
|
msg += QString::fromLatin1(" (emergency shutdown");
|
|
|
|
|
logMessage(msg);
|
|
|
|
|
if (emergencyShutdown) {
|
|
|
|
|
cleanup();
|
|
|
|
|
m_engine->notifyAdapterShutdownOk();
|
|
|
|
|
} else {
|
|
|
|
|
sendGdbServerAck();
|
|
|
|
|
sendGdbServerMessage("", "process killed");
|
|
|
|
|
}
|
2009-09-16 13:43:03 +02:00
|
|
|
}
|
|
|
|
|
|
2009-09-11 15:53:08 +02:00
|
|
|
void TrkGdbAdapter::handleReadRegisters(const TrkResult &result)
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
2009-12-18 16:25:59 +01:00
|
|
|
logMessage(" REGISTER RESULT: " + result.toString());
|
2009-09-09 17:24:21 +02:00
|
|
|
// [80 0B 00 00 00 00 00 C9 24 FF BC 00 00 00 00 00
|
|
|
|
|
// 60 00 00 00 00 00 00 78 67 79 70 00 00 00 00 00...]
|
|
|
|
|
if (result.errorCode()) {
|
2010-06-25 15:06:30 +02:00
|
|
|
logMessage("ERROR: " + result.errorString(), LogError);
|
2009-09-09 17:24:21 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const char *data = result.data.data() + 1; // Skip ok byte
|
2010-06-30 17:14:57 +02:00
|
|
|
uint *registers = m_snapshot.registers(m_session.tid);
|
|
|
|
|
QTC_ASSERT(registers, return;)
|
2009-09-09 17:24:21 +02:00
|
|
|
for (int i = 0; i < RegisterCount; ++i)
|
2010-06-30 17:14:57 +02:00
|
|
|
registers[i] = extractInt(data + 4 * i);
|
|
|
|
|
m_snapshot.setRegistersValid(m_session.tid, true);
|
2010-01-29 21:33:57 +01:00
|
|
|
}
|
2009-09-09 17:24:21 +02:00
|
|
|
|
2009-09-25 13:28:43 +02:00
|
|
|
void TrkGdbAdapter::handleWriteRegister(const TrkResult &result)
|
|
|
|
|
{
|
|
|
|
|
logMessage(" RESULT: " + result.toString() + result.cookie.toString());
|
|
|
|
|
if (result.errorCode()) {
|
2010-06-25 15:06:30 +02:00
|
|
|
logMessage("ERROR: " + result.errorString(), LogError);
|
2009-09-25 13:28:43 +02:00
|
|
|
sendGdbServerMessage("E01");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
sendGdbServerMessage("OK");
|
2010-01-29 21:33:57 +01:00
|
|
|
}
|
2009-09-25 13:28:43 +02:00
|
|
|
|
2009-09-14 10:28:09 +02:00
|
|
|
void TrkGdbAdapter::reportRegisters()
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
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));
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
2009-12-18 16:25:59 +01:00
|
|
|
void TrkGdbAdapter::handleAndReportReadRegisters(const TrkResult &result)
|
|
|
|
|
{
|
|
|
|
|
handleReadRegisters(result);
|
|
|
|
|
reportRegisters();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrkGdbAdapter::handleAndReportReadRegister(const TrkResult &result)
|
|
|
|
|
{
|
|
|
|
|
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));
|
2009-12-18 16:25:59 +01:00
|
|
|
}
|
|
|
|
|
|
2009-09-14 09:46:34 +02:00
|
|
|
void TrkGdbAdapter::handleAndReportReadRegistersAfterStop(const TrkResult &result)
|
|
|
|
|
{
|
2010-07-08 18:10:50 +02:00
|
|
|
handleReadRegisters(result);
|
2010-06-30 17:14:57 +02:00
|
|
|
const bool reportThread = m_session.tid != m_session.mainTid;
|
2010-09-29 16:39:46 +02:00
|
|
|
const int signalNumber = result.cookie.isValid() ? result.cookie.toInt() : int(gdbServerSignalTrap);
|
|
|
|
|
sendGdbServerMessage(m_snapshot.gdbStopMessage(m_session.tid, signalNumber, reportThread),
|
2010-06-30 17:14:57 +02:00
|
|
|
"Stopped with registers in thread " + QByteArray::number(m_session.tid, 16));
|
2009-09-14 09:46:34 +02:00
|
|
|
}
|
|
|
|
|
|
2009-09-10 16:30:04 +02:00
|
|
|
static QString msgMemoryReadError(int code, uint addr, uint len = 0)
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
|
|
|
|
const QString lenS = len ? QString::number(len) : QLatin1String("<unknown>");
|
2009-10-01 13:57:27 +02:00
|
|
|
return _("Memory read error %1 at: 0x%2 %3")
|
2009-09-09 17:24:21 +02:00
|
|
|
.arg(code).arg(addr, 0 ,16).arg(lenS);
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-05 17:37:15 +02:00
|
|
|
void TrkGdbAdapter::handleReadMemoryBuffered(const TrkResult &result)
|
|
|
|
|
{
|
|
|
|
|
if (extractShort(result.data.data() + 1) + 3 != result.data.size())
|
2010-06-25 15:06:30 +02:00
|
|
|
logMessage("\n BAD MEMORY RESULT: " + result.data.toHex() + "\n", LogError);
|
2009-10-05 17:37:15 +02:00
|
|
|
const MemoryRange range = result.cookie.value<MemoryRange>();
|
2010-11-05 13:03:32 +01:00
|
|
|
MEMORY_DEBUG("HANDLE READ MEMORY ***BUFFERED*** FOR " << range);
|
2009-10-05 17:37:15 +02:00
|
|
|
if (const int errorCode = result.errorCode()) {
|
|
|
|
|
logMessage(_("TEMPORARY: ") + msgMemoryReadError(errorCode, range.from));
|
|
|
|
|
logMessage(_("RETRYING UNBUFFERED"));
|
|
|
|
|
// FIXME: This does not handle large requests properly.
|
|
|
|
|
sendTrkMessage(0x10, TrkCB(handleReadMemoryUnbuffered),
|
|
|
|
|
trkReadMemoryMessage(range), QVariant::fromValue(range));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const QByteArray ba = result.data.mid(3);
|
2010-11-05 13:03:32 +01:00
|
|
|
MEMORY_DEBUG("INSERT KNOWN MEMORY RANGE: " << range << m_snapshot.memory.size() << " BLOCKS");
|
2009-10-05 17:37:15 +02:00
|
|
|
m_snapshot.insertMemory(range, ba);
|
|
|
|
|
tryAnswerGdbMemoryRequest(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrkGdbAdapter::handleReadMemoryUnbuffered(const TrkResult &result)
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
2009-10-05 17:37:15 +02:00
|
|
|
if (extractShort(result.data.data() + 1) + 3 != result.data.size())
|
2010-06-25 15:06:30 +02:00
|
|
|
logMessage("\n BAD MEMORY RESULT: " + result.data.toHex() + "\n", LogError);
|
2009-10-05 17:37:15 +02:00
|
|
|
const MemoryRange range = result.cookie.value<MemoryRange>();
|
2010-11-05 13:03:32 +01:00
|
|
|
MEMORY_DEBUG("HANDLE READ MEMORY UNBUFFERED FOR " << range);
|
2009-10-05 17:37:15 +02:00
|
|
|
if (const int errorCode = result.errorCode()) {
|
|
|
|
|
logMessage(_("TEMPORARY: ") + msgMemoryReadError(errorCode, range.from));
|
|
|
|
|
logMessage(_("RETRYING UNBUFFERED"));
|
2010-01-11 16:13:47 +01:00
|
|
|
#if 1
|
2009-10-05 17:37:15 +02:00
|
|
|
const QByteArray ba = "E20";
|
|
|
|
|
sendGdbServerMessage(ba, msgMemoryReadError(32, range.from).toLatin1());
|
2010-01-11 16:13:47 +01:00
|
|
|
#else
|
|
|
|
|
// emit bogus data to make Python happy
|
|
|
|
|
MemoryRange wanted = m_snapshot.wantedMemory;
|
|
|
|
|
qDebug() << "SENDING BOGUS DATA FOR " << wanted;
|
|
|
|
|
m_snapshot.insertMemory(wanted, QByteArray(wanted.size(), 0xa5));
|
|
|
|
|
tryAnswerGdbMemoryRequest(false);
|
|
|
|
|
#endif
|
2009-10-05 17:37:15 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const QByteArray ba = result.data.mid(3);
|
|
|
|
|
m_snapshot.insertMemory(range, ba);
|
2010-11-05 13:03:32 +01:00
|
|
|
MEMORY_DEBUG("INSERT KNOWN MEMORY RANGE: " << range << m_snapshot.memory.size() << " BLOCKS");
|
2009-10-05 17:37:15 +02:00
|
|
|
tryAnswerGdbMemoryRequest(false);
|
2009-09-29 08:51:28 +02:00
|
|
|
}
|
2009-09-09 17:24:21 +02:00
|
|
|
|
2009-10-05 17:37:15 +02:00
|
|
|
void TrkGdbAdapter::tryAnswerGdbMemoryRequest(bool buffered)
|
2009-09-29 08:51:28 +02:00
|
|
|
{
|
2010-02-08 14:55:42 +01:00
|
|
|
//logMessage("TRYING TO ANSWER MEMORY REQUEST ");
|
2009-10-05 17:37:15 +02:00
|
|
|
|
|
|
|
|
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) {
|
2010-01-11 16:13:47 +01:00
|
|
|
MEMORY_DEBUG(" NEEDED STEP: " << needed);
|
2010-01-29 21:33:57 +01:00
|
|
|
needed -= it.key();
|
2009-10-05 17:37:15 +02:00
|
|
|
}
|
2010-01-11 16:13:47 +01:00
|
|
|
MEMORY_DEBUG("NEEDED FINAL: " << needed);
|
2009-10-05 17:37:15 +02:00
|
|
|
|
|
|
|
|
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));
|
2009-10-05 17:37:15 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-02-01 12:16:27 +01:00
|
|
|
// Happens when chunks are not combined
|
2009-10-05 17:37:15 +02:00
|
|
|
QTC_ASSERT(false, /**/);
|
2010-06-14 18:19:02 +02:00
|
|
|
showMessage("CHUNKS NOT COMBINED");
|
2010-06-10 13:12:12 +02:00
|
|
|
# ifdef MEMORY_DEBUG
|
2010-01-15 15:06:03 +01:00
|
|
|
qDebug() << "CHUNKS NOT COMBINED";
|
|
|
|
|
it = m_snapshot.memory.begin();
|
|
|
|
|
et = m_snapshot.memory.end();
|
|
|
|
|
for ( ; it != et; ++it)
|
2010-01-29 15:47:51 +01:00
|
|
|
qDebug() << hexNumber(it.key().from) << hexNumber(it.key().to);
|
2010-01-15 15:06:03 +01:00
|
|
|
qDebug() << "WANTED" << wanted.from << wanted.to;
|
2010-06-10 13:12:12 +02:00
|
|
|
# endif
|
2010-01-15 15:06:03 +01:00
|
|
|
sendGdbServerMessage("E22", "");
|
2009-10-05 17:37:15 +02:00
|
|
|
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);
|
2010-02-08 14:55:42 +01:00
|
|
|
MEMORY_DEBUG(" FETCH BUFFERED MEMORY : " << range);
|
2009-10-05 17:37:15 +02:00
|
|
|
sendTrkMessage(0x10, TrkCB(handleReadMemoryBuffered),
|
|
|
|
|
trkReadMemoryMessage(range),
|
|
|
|
|
QVariant::fromValue(range));
|
|
|
|
|
} 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));
|
2010-11-05 13:03:32 +01:00
|
|
|
MEMORY_DEBUG(" FETCH UNBUFFERED MEMORY : " << needed);
|
2009-10-05 17:37:15 +02:00
|
|
|
sendTrkMessage(0x10, TrkCB(handleReadMemoryUnbuffered),
|
|
|
|
|
trkReadMemoryMessage(needed),
|
|
|
|
|
QVariant::fromValue(needed));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
void TrkGdbAdapter::reportReadMemoryBuffered(const TrkResult &result)
|
|
|
|
|
{
|
|
|
|
|
const MemoryRange range = result.cookie.value<MemoryRange>();
|
2009-09-09 17:24:21 +02:00
|
|
|
// Gdb accepts less memory according to documentation.
|
|
|
|
|
// Send E on complete failure.
|
|
|
|
|
QByteArray ba;
|
2009-10-05 17:37:15 +02:00
|
|
|
uint blockaddr = (range.from / MemoryChunkSize) * MemoryChunkSize;
|
2009-09-09 17:24:21 +02:00
|
|
|
for (; blockaddr < addr + len; blockaddr += MemoryChunkSize) {
|
|
|
|
|
const Snapshot::Memory::const_iterator it = m_snapshot.memory.constFind(blockaddr);
|
|
|
|
|
if (it == m_snapshot.memory.constEnd())
|
|
|
|
|
break;
|
|
|
|
|
ba.append(it.value());
|
|
|
|
|
}
|
|
|
|
|
const int previousChunkOverlap = addr % MemoryChunkSize;
|
|
|
|
|
if (previousChunkOverlap != 0 && ba.size() > previousChunkOverlap)
|
|
|
|
|
ba.remove(0, previousChunkOverlap);
|
|
|
|
|
if (ba.size() > int(len))
|
|
|
|
|
ba.truncate(len);
|
|
|
|
|
|
|
|
|
|
if (ba.isEmpty()) {
|
|
|
|
|
ba = "E20";
|
|
|
|
|
sendGdbServerMessage(ba, msgMemoryReadError(32, addr, len).toLatin1());
|
|
|
|
|
} else {
|
|
|
|
|
sendGdbServerMessage(ba.toHex(), memoryReadLogMessage(addr, len, ba));
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-10-05 17:37:15 +02:00
|
|
|
*/
|
2009-09-09 17:24:21 +02:00
|
|
|
|
2010-02-05 16:00:54 +01:00
|
|
|
void TrkGdbAdapter::handleStep(const TrkResult &result)
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
|
|
|
|
if (result.errorCode()) {
|
2010-06-25 15:06:30 +02:00
|
|
|
logMessage("ERROR: " + result.errorString() + " in handleStep", LogError);
|
2010-01-15 11:36:57 +01:00
|
|
|
|
2010-02-05 16:00:54 +01:00
|
|
|
// Try fallback with Continue.
|
2010-06-14 18:19:02 +02:00
|
|
|
showMessage("FALLBACK TO 'CONTINUE'");
|
2010-06-30 17:14:57 +02:00
|
|
|
trkContinueAll("Step failed");
|
2010-02-05 16:00:54 +01:00
|
|
|
//sendGdbServerMessage("S05", "Stepping finished");
|
2010-01-15 11:36:57 +01:00
|
|
|
|
|
|
|
|
// Doing nothing as below does not work as gdb seems to insist on
|
|
|
|
|
// making some progress through a 'step'.
|
|
|
|
|
//sendTrkMessage(0x12,
|
|
|
|
|
// TrkCB(handleAndReportReadRegistersAfterStop),
|
2010-07-07 14:00:54 +02:00
|
|
|
// Launcher::readRegistersMessage(m_session.pid, m_session.tid));
|
2009-09-09 17:24:21 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2010-02-09 15:02:55 +01:00
|
|
|
// The gdb server response is triggered later by the Stop Reply packet.
|
|
|
|
|
logMessage("STEP FINISHED " + currentTime());
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
2009-09-11 15:53:08 +02:00
|
|
|
void TrkGdbAdapter::handleAndReportSetBreakpoint(const TrkResult &result)
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
|
|
|
|
//---TRK------------------------------------------------------
|
|
|
|
|
// Command: 0x80 Acknowledge
|
|
|
|
|
// Error: 0x00
|
|
|
|
|
// [80 09 00 00 00 00 0A]
|
2009-10-01 09:02:58 +02:00
|
|
|
if (result.errorCode()) {
|
2010-06-25 15:06:30 +02:00
|
|
|
logMessage("ERROR WHEN SETTING BREAKPOINT: " + result.errorString(), LogError);
|
2010-01-13 10:32:00 +01:00
|
|
|
sendGdbServerMessage("E21");
|
2009-10-01 09:02:58 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2009-09-15 11:39:37 +02:00
|
|
|
uint bpnr = extractInt(result.data.data() + 1);
|
2009-09-09 17:24:21 +02:00
|
|
|
uint addr = result.cookie.toUInt();
|
|
|
|
|
m_session.addressToBP[addr] = bpnr;
|
|
|
|
|
logMessage("SET BREAKPOINT " + hexxNumber(bpnr) + " "
|
|
|
|
|
+ stringFromArray(result.data.data()));
|
|
|
|
|
sendGdbServerMessage("OK");
|
|
|
|
|
//sendGdbServerMessage("OK");
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-11 15:53:08 +02:00
|
|
|
void TrkGdbAdapter::handleClearBreakpoint(const TrkResult &result)
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
|
|
|
|
logMessage("CLEAR BREAKPOINT ");
|
|
|
|
|
if (result.errorCode()) {
|
2010-06-25 15:06:30 +02:00
|
|
|
logMessage("ERROR: " + result.errorString(), LogError);
|
2009-09-09 17:24:21 +02:00
|
|
|
//return;
|
2010-01-29 21:33:57 +01:00
|
|
|
}
|
2009-09-09 17:24:21 +02:00
|
|
|
sendGdbServerMessage("OK");
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-11 15:53:08 +02:00
|
|
|
void TrkGdbAdapter::handleSupportMask(const TrkResult &result)
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
|
|
|
|
const char *data = result.data.data();
|
|
|
|
|
QByteArray str;
|
|
|
|
|
for (int i = 0; i < 32; ++i) {
|
|
|
|
|
//str.append(" [" + formatByte(data[i]) + "]: ");
|
|
|
|
|
for (int j = 0; j < 8; ++j)
|
|
|
|
|
if (data[i] & (1 << j))
|
|
|
|
|
str.append(QByteArray::number(i * 8 + j, 16));
|
|
|
|
|
}
|
|
|
|
|
logMessage("SUPPORTED: " + str);
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-26 11:55:02 +01:00
|
|
|
void TrkGdbAdapter::handleTrkVersionsStartGdb(const TrkResult &result)
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
|
|
|
|
QString logMsg;
|
|
|
|
|
QTextStream str(&logMsg);
|
|
|
|
|
str << "Versions: ";
|
|
|
|
|
if (result.data.size() >= 5) {
|
2009-10-29 14:18:49 +01:00
|
|
|
str << "App TRK version " << int(result.data.at(1)) << '.'
|
2009-09-09 17:24:21 +02:00
|
|
|
<< int(result.data.at(2))
|
2009-10-29 14:18:49 +01:00
|
|
|
<< ", TRK protocol version " << int(result.data.at(3))
|
2009-09-09 17:24:21 +02:00
|
|
|
<< '.' << int(result.data.at(4));
|
|
|
|
|
}
|
|
|
|
|
logMessage(logMsg);
|
2010-02-25 17:52:34 +01:00
|
|
|
// As we are called from the TrkDevice handler, do not lock up when shutting
|
|
|
|
|
// down the device in case of gdb launch errors.
|
|
|
|
|
QTimer::singleShot(0, this, SLOT(slotStartGdb()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrkGdbAdapter::slotStartGdb()
|
|
|
|
|
{
|
2009-10-26 11:55:02 +01:00
|
|
|
QStringList gdbArgs;
|
|
|
|
|
gdbArgs.append(QLatin1String("--nx")); // Do not read .gdbinit file
|
2010-04-09 08:43:26 +02:00
|
|
|
if (!m_engine->startGdb(gdbArgs, QString(), QString())) {
|
2009-10-26 11:55:02 +01:00
|
|
|
cleanup();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2010-07-08 12:41:26 +02:00
|
|
|
m_engine->handleAdapterStarted();
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
2009-09-11 15:53:08 +02:00
|
|
|
void TrkGdbAdapter::handleDisconnect(const TrkResult & /*result*/)
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
2009-10-29 14:18:49 +01:00
|
|
|
logMessage(QLatin1String("App TRK disconnected"));
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
2009-10-05 17:37:15 +02:00
|
|
|
void TrkGdbAdapter::readMemory(uint addr, uint len, bool buffered)
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
|
|
|
|
Q_ASSERT(len < (2 << 16));
|
|
|
|
|
|
|
|
|
|
// We try to get medium-sized chunks of data from the device
|
|
|
|
|
if (m_verbose > 2)
|
2009-10-01 13:57:27 +02:00
|
|
|
logMessage(_("readMemory %1 bytes from 0x%2 blocksize=%3")
|
2009-09-09 17:24:21 +02:00
|
|
|
.arg(len).arg(addr, 0, 16).arg(MemoryChunkSize));
|
|
|
|
|
|
2009-10-05 17:37:15 +02:00
|
|
|
m_snapshot.wantedMemory = MemoryRange(addr, addr + len);
|
|
|
|
|
tryAnswerGdbMemoryRequest(buffered);
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
2010-10-01 18:37:30 +02:00
|
|
|
void TrkGdbAdapter::writeMemory(uint addr, const QByteArray &data)
|
|
|
|
|
{
|
|
|
|
|
Q_ASSERT(data.size() < (2 << 16));
|
|
|
|
|
if (m_verbose > 2) {
|
|
|
|
|
logMessage(_("writeMemory %1 bytes from 0x%2 blocksize=%3 data=%4")
|
|
|
|
|
.arg(data.size()).arg(addr, 0, 16).arg(MemoryChunkSize).arg(QString::fromLatin1(data.toHex())));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sendTrkMessage(0x11, TrkCB(handleWriteMemory),
|
|
|
|
|
trkWriteMemoryMessage(addr, data));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrkGdbAdapter::handleWriteMemory(const TrkResult &result)
|
|
|
|
|
{
|
|
|
|
|
logMessage(" RESULT: " + result.toString() + result.cookie.toString());
|
|
|
|
|
if (result.errorCode()) {
|
|
|
|
|
logMessage("ERROR: " + result.errorString(), LogError);
|
|
|
|
|
sendGdbServerMessage("E01");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
sendGdbServerMessage("OK");
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-11 15:53:08 +02:00
|
|
|
void TrkGdbAdapter::interruptInferior()
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
2009-10-01 17:03:37 +02:00
|
|
|
sendTrkMessage(0x1a, TrkCallback(), trkInterruptMessage(), "Interrupting...");
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
2010-02-11 12:31:59 +01:00
|
|
|
void TrkGdbAdapter::trkDeviceRemoved(const SymbianUtils::SymbianDevice &dev)
|
|
|
|
|
{
|
2010-04-09 08:43:26 +02:00
|
|
|
if (state() != DebuggerNotReady && !m_trkDevice.isNull() && m_trkDevice->port() == dev.portName()) {
|
2010-02-11 12:31:59 +01:00
|
|
|
const QString message = QString::fromLatin1("Device '%1' has been disconnected.").arg(dev.friendlyName());
|
|
|
|
|
logMessage(message);
|
2010-07-08 12:41:26 +02:00
|
|
|
m_engine->handleAdapterCrashed(message);
|
2010-02-11 12:31:59 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TrkGdbAdapter::initializeDevice(const QString &remoteChannel, QString *errorMessage)
|
|
|
|
|
{
|
|
|
|
|
if (remoteChannel.isEmpty()) {
|
2010-04-09 08:43:26 +02:00
|
|
|
*errorMessage = tr("Port specification missing.");
|
|
|
|
|
return false;
|
2010-02-11 12:31:59 +01:00
|
|
|
}
|
2010-04-09 08:43:26 +02:00
|
|
|
// Run config: Acquire from device manager.
|
2010-06-16 11:08:54 +02:00
|
|
|
m_trkDevice = SymbianUtils::SymbianDeviceManager::instance()
|
|
|
|
|
->acquireDevice(remoteChannel);
|
2010-04-09 08:43:26 +02:00
|
|
|
if (m_trkDevice.isNull()) {
|
|
|
|
|
*errorMessage = tr("Unable to acquire a device on '%1'. It appears to be in use.").arg(remoteChannel);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
connect(SymbianUtils::SymbianDeviceManager::instance(), SIGNAL(deviceRemoved(const SymbianUtils::SymbianDevice)),
|
|
|
|
|
this, SLOT(trkDeviceRemoved(SymbianUtils::SymbianDevice)));
|
2010-02-11 12:31:59 +01:00
|
|
|
connect(m_trkDevice.data(), SIGNAL(messageReceived(trk::TrkResult)),
|
|
|
|
|
this, SLOT(handleTrkResult(trk::TrkResult)));
|
|
|
|
|
connect(m_trkDevice.data(), SIGNAL(error(QString)),
|
|
|
|
|
this, SLOT(handleTrkError(QString)));
|
|
|
|
|
connect(m_trkDevice.data(), SIGNAL(logMessage(QString)),
|
|
|
|
|
this, SLOT(trkLogMessage(QString)));
|
|
|
|
|
m_trkDevice->setVerbose(m_verbose);
|
|
|
|
|
|
|
|
|
|
// Prompt the user to start communication
|
|
|
|
|
const trk::PromptStartCommunicationResult src =
|
|
|
|
|
S60DebuggerBluetoothStarter::startCommunication(m_trkDevice,
|
|
|
|
|
0, errorMessage);
|
|
|
|
|
switch (src) {
|
|
|
|
|
case trk::PromptStartCommunicationConnected:
|
|
|
|
|
break;
|
|
|
|
|
case trk::PromptStartCommunicationCanceled:
|
2010-02-25 16:05:45 +01:00
|
|
|
errorMessage->clear();
|
2010-02-11 12:31:59 +01:00
|
|
|
return false;
|
|
|
|
|
case trk::PromptStartCommunicationError:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-23 10:14:53 +02:00
|
|
|
void TrkGdbAdapter::startAdapter()
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
2010-02-08 14:55:42 +01:00
|
|
|
m_snapshot.fullReset();
|
|
|
|
|
|
2009-09-29 13:49:35 +02:00
|
|
|
// Retrieve parameters
|
2009-09-30 12:27:03 +02:00
|
|
|
const DebuggerStartParameters ¶meters = startParameters();
|
2009-09-29 13:49:35 +02:00
|
|
|
m_remoteExecutable = parameters.executable;
|
2010-01-21 12:35:09 +01:00
|
|
|
m_remoteArguments = parameters.processArgs;
|
2009-09-29 13:49:35 +02:00
|
|
|
m_symbolFile = parameters.symbolFileName;
|
2010-12-02 14:07:53 +01:00
|
|
|
if (!m_symbolFile.isEmpty())
|
|
|
|
|
m_symbolFileFolder = QFileInfo(m_symbolFile).absolutePath();
|
2010-08-30 10:55:43 +02:00
|
|
|
QString remoteChannel = parameters.remoteChannel;
|
2009-09-30 08:33:26 +02:00
|
|
|
// FIXME: testing hack, remove!
|
2010-10-19 11:14:03 +02:00
|
|
|
if (m_remoteArguments.startsWith(__("@sym@ "))) {
|
|
|
|
|
QStringList pa = Utils::QtcProcess::splitArgs(m_remoteArguments);
|
|
|
|
|
remoteChannel = pa.at(1);
|
|
|
|
|
m_remoteExecutable = pa.at(2);
|
|
|
|
|
m_symbolFile = pa.at(3);
|
2010-01-21 12:35:09 +01:00
|
|
|
m_remoteArguments.clear();
|
2009-09-29 13:49:35 +02:00
|
|
|
}
|
2009-10-02 16:13:46 +02:00
|
|
|
// Unixish gdbs accept only forward slashes
|
|
|
|
|
m_symbolFile.replace(QLatin1Char('\\'), QLatin1Char('/'));
|
2009-09-29 13:49:35 +02:00
|
|
|
// Start
|
2010-07-09 17:07:59 +02:00
|
|
|
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
|
2010-06-14 18:19:02 +02:00
|
|
|
showMessage(_("TRYING TO START ADAPTER"));
|
2009-09-21 11:09:38 +02:00
|
|
|
logMessage(QLatin1String("### Starting TrkGdbAdapter"));
|
2010-02-11 12:31:59 +01:00
|
|
|
|
2009-10-26 15:37:09 +01:00
|
|
|
// Prompt the user to start communication
|
2010-01-29 21:33:57 +01:00
|
|
|
QString message;
|
2010-08-30 10:55:43 +02:00
|
|
|
if (!initializeDevice(remoteChannel, &message)) {
|
2010-02-11 12:31:59 +01:00
|
|
|
if (message.isEmpty()) {
|
2010-07-08 12:41:26 +02:00
|
|
|
m_engine->handleAdapterStartFailed(QString(), QString());
|
2010-02-11 12:31:59 +01:00
|
|
|
} else {
|
2010-06-25 15:06:30 +02:00
|
|
|
logMessage(message, LogError);
|
2010-07-08 12:41:26 +02:00
|
|
|
m_engine->handleAdapterStartFailed(message, QString());
|
2010-02-11 12:31:59 +01:00
|
|
|
}
|
2009-10-26 15:37:09 +01:00
|
|
|
return;
|
2009-09-11 10:56:45 +02:00
|
|
|
}
|
2009-09-09 17:24:21 +02:00
|
|
|
|
2009-10-12 16:39:13 +02:00
|
|
|
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());
|
2010-06-25 15:06:30 +02:00
|
|
|
logMessage(msg, LogError);
|
2010-07-08 12:41:26 +02:00
|
|
|
m_engine->handleAdapterStartFailed(msg, QString());
|
2009-10-12 16:39:13 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
logMessage(QString("Gdb server running on %1.\nLittle endian assumed.")
|
|
|
|
|
.arg(m_gdbServerName));
|
|
|
|
|
|
|
|
|
|
connect(m_gdbServer, SIGNAL(newConnection()),
|
|
|
|
|
this, SLOT(handleGdbConnection()));
|
|
|
|
|
|
2009-10-26 11:55:02 +01:00
|
|
|
m_trkDevice->sendTrkInitialPing();
|
|
|
|
|
sendTrkMessage(0x02); // Disconnect, as trk might be still connected
|
|
|
|
|
sendTrkMessage(0x01); // Connect
|
|
|
|
|
sendTrkMessage(0x05, TrkCB(handleSupportMask));
|
|
|
|
|
sendTrkMessage(0x06, TrkCB(handleCpuType));
|
|
|
|
|
sendTrkMessage(0x04, TrkCB(handleTrkVersionsStartGdb)); // Versions
|
2009-09-21 11:09:38 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-08 18:10:50 +02:00
|
|
|
void TrkGdbAdapter::setupInferior()
|
2009-09-21 11:09:38 +02:00
|
|
|
{
|
2010-07-09 17:07:59 +02:00
|
|
|
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
|
2010-01-21 12:35:09 +01:00
|
|
|
sendTrkMessage(0x40, TrkCB(handleCreateProcess),
|
|
|
|
|
trk::Launcher::startProcessMessage(m_remoteExecutable, m_remoteArguments));
|
2009-10-12 16:39:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrkGdbAdapter::handleCreateProcess(const TrkResult &result)
|
|
|
|
|
{
|
2010-07-09 17:07:59 +02:00
|
|
|
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
|
2009-10-12 16:39:13 +02:00
|
|
|
// 40 00 00]
|
|
|
|
|
//logMessage(" RESULT: " + result.toString());
|
|
|
|
|
// [80 08 00 00 00 01 B5 00 00 01 B6 78 67 40 00 00 40 00 00]
|
|
|
|
|
if (result.errorCode()) {
|
2010-06-25 15:06:30 +02:00
|
|
|
logMessage("ERROR: " + result.errorString(), LogError);
|
2009-10-12 16:39:13 +02:00
|
|
|
QString msg = _("Cannot start executable \"%1\" on the device:\n%2")
|
|
|
|
|
.arg(m_remoteExecutable).arg(result.errorString());
|
|
|
|
|
// Delay cleanup as not to close a trk device from its read handler,
|
|
|
|
|
// which blocks.
|
2010-07-08 18:10:50 +02:00
|
|
|
emitDelayedInferiorSetupFailed(msg);
|
2009-10-12 16:39:13 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2010-06-30 17:14:57 +02:00
|
|
|
showMessage(_("RESET SNAPSHOT (NOTIFY CREATED)"));
|
|
|
|
|
m_snapshot.fullReset();
|
2009-10-12 16:39:13 +02:00
|
|
|
const char *data = result.data.data();
|
|
|
|
|
m_session.pid = extractInt(data + 1);
|
2010-06-30 17:14:57 +02:00
|
|
|
m_session.mainTid = m_session.tid = extractInt(data + 5);
|
2009-10-12 16:39:13 +02:00
|
|
|
m_session.codeseg = extractInt(data + 9);
|
|
|
|
|
m_session.dataseg = extractInt(data + 13);
|
2010-06-30 17:14:57 +02:00
|
|
|
m_snapshot.addThread(m_session.mainTid);
|
2010-01-13 12:35:57 +01:00
|
|
|
const QString startMsg =
|
|
|
|
|
tr("Process started, PID: 0x%1, thread id: 0x%2, "
|
|
|
|
|
"code segment: 0x%3, data segment: 0x%4.")
|
|
|
|
|
.arg(m_session.pid, 0, 16).arg(m_session.tid, 0, 16)
|
|
|
|
|
.arg(m_session.codeseg, 0, 16).arg(m_session.dataseg, 0, 16);
|
2010-08-27 11:14:08 +02:00
|
|
|
logMessage(startMsg, LogMisc);
|
|
|
|
|
// 26.8.2010: When paging occurs in S^3, bogus starting ROM addresses
|
|
|
|
|
// like 0x500000 or 0x40000 are reported. Warn about symbol resolution errors.
|
2011-02-07 14:26:34 +01:00
|
|
|
// Code duplicated in CodaAdapter. @TODO: Hopefully fixed in future TRK versions.
|
2010-08-27 11:14:08 +02:00
|
|
|
if ((m_session.codeseg & 0xFFFFF) == 0) {
|
|
|
|
|
const QString warnMessage = tr("The reported code segment address (0x%1) might be invalid. Symbol resolution or setting breakoints may not work.").
|
|
|
|
|
arg(m_session.codeseg, 0, 16);
|
|
|
|
|
logMessage(warnMessage, LogError);
|
|
|
|
|
}
|
2009-10-12 16:39:13 +02:00
|
|
|
|
2010-12-02 13:45:02 +01:00
|
|
|
m_engine->postCommand("set gnutarget arm-none-symbianelf");
|
|
|
|
|
|
2010-02-01 12:16:27 +01:00
|
|
|
const QByteArray symbolFile = m_symbolFile.toLocal8Bit();
|
|
|
|
|
if (symbolFile.isEmpty()) {
|
2010-11-25 17:47:56 +01:00
|
|
|
logMessage(_("WARNING: No symbol file available."), LogError);
|
2009-09-29 13:49:35 +02:00
|
|
|
} else {
|
2010-01-15 16:25:02 +01:00
|
|
|
// 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));
|
2010-02-01 12:16:27 +01:00
|
|
|
m_engine->postCommand("symbol-file \"" + symbolFile + "\"");
|
2009-09-29 13:49:35 +02:00
|
|
|
}
|
2010-06-30 17:14:57 +02:00
|
|
|
foreach(const QByteArray &s, Symbian::gdbStartupSequence())
|
|
|
|
|
m_engine->postCommand(s);
|
2010-02-11 13:11:56 +01:00
|
|
|
//m_engine->postCommand("set remotelogfile /tmp/gdb-remotelog");
|
2010-03-24 14:46:37 +01:00
|
|
|
//m_engine->postCommand("set debug remote 1"); // FIXME: Make an option.
|
2010-01-05 16:51:55 +01:00
|
|
|
m_engine->postCommand("target remote " + gdbServerName().toLatin1(),
|
2009-09-22 09:27:19 +02:00
|
|
|
CB(handleTargetRemote));
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-24 11:16:00 +02:00
|
|
|
void TrkGdbAdapter::handleTargetRemote(const GdbResponse &record)
|
2009-09-22 09:27:19 +02:00
|
|
|
{
|
2010-07-09 17:07:59 +02:00
|
|
|
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
|
2009-09-22 09:27:19 +02:00
|
|
|
if (record.resultClass == GdbResultDone) {
|
2010-07-08 12:41:26 +02:00
|
|
|
m_engine->handleInferiorPrepared();
|
2009-10-12 12:00:07 +02:00
|
|
|
} else {
|
2009-10-29 14:18:49 +01:00
|
|
|
QString msg = tr("Connecting to TRK server adapter failed:\n")
|
2010-01-04 14:11:07 +01:00
|
|
|
+ QString::fromLocal8Bit(record.data.findChild("msg").data());
|
2010-07-09 17:07:59 +02:00
|
|
|
m_engine->notifyInferiorSetupFailed(msg);
|
2009-09-22 09:27:19 +02:00
|
|
|
}
|
2009-09-21 11:09:38 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-09 17:07:59 +02:00
|
|
|
void TrkGdbAdapter::runEngine()
|
2009-10-19 19:04:01 +02:00
|
|
|
{
|
2010-07-20 12:14:59 +02:00
|
|
|
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
|
|
|
|
|
m_engine->notifyEngineRunAndInferiorStopOk();
|
2009-10-20 14:08:59 +02:00
|
|
|
m_engine->continueInferiorInternal();
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
2009-09-22 09:27:19 +02:00
|
|
|
// AbstractGdbAdapter interface implementation
|
2009-09-09 17:24:21 +02:00
|
|
|
//
|
|
|
|
|
|
2009-09-28 13:35:39 +02:00
|
|
|
void TrkGdbAdapter::write(const QByteArray &data)
|
2009-09-09 17:24:21 +02:00
|
|
|
{
|
2009-09-28 14:49:44 +02:00
|
|
|
// Write magic packets directly to TRK.
|
|
|
|
|
if (data.startsWith("@#")) {
|
2009-09-29 09:49:09 +02:00
|
|
|
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;
|
2010-01-13 15:19:57 +01:00
|
|
|
uint addr = data1.toUInt(&ok, 0);
|
2009-09-29 09:49:09 +02:00
|
|
|
qDebug() << "Writing: " << quoteUnprintableLatin1(data1) << addr;
|
|
|
|
|
directStep(addr);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2009-10-02 16:56:48 +02:00
|
|
|
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("@@")) {
|
|
|
|
|
// Read data
|
|
|
|
|
sendTrkMessage(0x10, TrkCB(handleDirectWrite1),
|
2010-07-07 14:00:54 +02:00
|
|
|
Launcher::readMemoryMessage(m_session.pid, m_session.tid, m_session.dataseg, 12));
|
2009-10-02 16:56:48 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2010-05-05 12:49:08 +02:00
|
|
|
m_gdbProc.write(data);
|
2009-09-09 17:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
2009-10-02 16:56:48 +02:00
|
|
|
uint oldPC;
|
|
|
|
|
QByteArray oldMem;
|
|
|
|
|
uint scratch;
|
|
|
|
|
|
|
|
|
|
void TrkGdbAdapter::handleDirectWrite1(const TrkResult &response)
|
|
|
|
|
{
|
|
|
|
|
scratch = m_session.dataseg + 512;
|
|
|
|
|
logMessage("DIRECT WRITE1: " + response.toString());
|
|
|
|
|
if (const int errorCode = response.errorCode()) {
|
2010-06-25 15:06:30 +02:00
|
|
|
logMessage("ERROR: " + response.errorString() + "in handleDirectWrite1", LogError);
|
2009-10-02 16:56:48 +02:00
|
|
|
} else {
|
|
|
|
|
oldMem = response.data.mid(3);
|
2010-06-30 17:14:57 +02:00
|
|
|
oldPC = m_snapshot.registerValue(m_session.tid, RegisterPC);
|
2009-10-02 16:56:48 +02:00
|
|
|
logMessage("READ MEM: " + oldMem.toHex());
|
|
|
|
|
//qDebug("READ MEM: " + oldMem.toHex());
|
|
|
|
|
QByteArray ba;
|
|
|
|
|
appendByte(&ba, 0xaa);
|
|
|
|
|
appendByte(&ba, 0xaa);
|
|
|
|
|
appendByte(&ba, 0xaa);
|
|
|
|
|
appendByte(&ba, 0xaa);
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
// Arm:
|
|
|
|
|
// 0: e51f4004 ldr r4, [pc, #-4] ; 4 <.text+0x4>
|
|
|
|
|
appendByte(&ba, 0x04);
|
|
|
|
|
appendByte(&ba, 0x50); // R5
|
|
|
|
|
appendByte(&ba, 0x1f);
|
|
|
|
|
appendByte(&ba, 0xe5);
|
|
|
|
|
#else
|
|
|
|
|
// Thumb:
|
2010-01-29 21:33:57 +01:00
|
|
|
// subs r0, #16
|
2009-10-02 16:56:48 +02:00
|
|
|
appendByte(&ba, 0x08);
|
|
|
|
|
appendByte(&ba, 0x3b);
|
2010-01-29 21:33:57 +01:00
|
|
|
// subs r0, #16
|
2009-10-02 16:56:48 +02:00
|
|
|
appendByte(&ba, 0x08);
|
|
|
|
|
appendByte(&ba, 0x3b);
|
|
|
|
|
//
|
|
|
|
|
appendByte(&ba, 0x08);
|
|
|
|
|
appendByte(&ba, 0x3b);
|
2010-01-29 21:33:57 +01:00
|
|
|
// subs r0, #16
|
2009-10-02 16:56:48 +02:00
|
|
|
appendByte(&ba, 0x08);
|
|
|
|
|
appendByte(&ba, 0x3b);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Write data
|
|
|
|
|
sendTrkMessage(0x11, TrkCB(handleDirectWrite2),
|
|
|
|
|
trkWriteMemoryMessage(scratch, ba));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrkGdbAdapter::handleDirectWrite2(const TrkResult &response)
|
|
|
|
|
{
|
|
|
|
|
logMessage("DIRECT WRITE2: " + response.toString());
|
|
|
|
|
if (const int errorCode = response.errorCode()) {
|
2010-06-25 15:06:30 +02:00
|
|
|
logMessage("ERROR: " + response.errorString() + "in handleDirectWrite1", LogError);
|
2009-10-02 16:56:48 +02:00
|
|
|
} else {
|
|
|
|
|
// Check
|
|
|
|
|
sendTrkMessage(0x10, TrkCB(handleDirectWrite3),
|
2010-07-07 14:00:54 +02:00
|
|
|
trk::Launcher::readMemoryMessage(m_session.pid, m_session.tid, scratch, 12));
|
2009-10-02 16:56:48 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrkGdbAdapter::handleDirectWrite3(const TrkResult &response)
|
|
|
|
|
{
|
|
|
|
|
logMessage("DIRECT WRITE3: " + response.toString());
|
|
|
|
|
if (const int errorCode = response.errorCode()) {
|
2010-06-25 15:06:30 +02:00
|
|
|
logMessage("ERROR: " + response.errorString() + "in handleDirectWrite1", LogError);
|
2009-10-02 16:56:48 +02:00
|
|
|
} else {
|
|
|
|
|
// Set PC
|
|
|
|
|
sendTrkMessage(0x13, TrkCB(handleDirectWrite4),
|
|
|
|
|
trkWriteRegisterMessage(RegisterPC, scratch + 4));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrkGdbAdapter::handleDirectWrite4(const TrkResult &response)
|
2010-07-08 18:10:50 +02:00
|
|
|
{
|
2010-06-30 17:14:57 +02:00
|
|
|
m_snapshot.setRegisterValue(m_session.tid, RegisterPC, scratch + 4);
|
2009-10-02 16:56:48 +02:00
|
|
|
return;
|
|
|
|
|
logMessage("DIRECT WRITE4: " + response.toString());
|
|
|
|
|
if (const int errorCode = response.errorCode()) {
|
2010-06-25 15:06:30 +02:00
|
|
|
logMessage("ERROR: " + response.errorString() + "in handleDirectWrite1", LogError);
|
2009-10-02 16:56:48 +02:00
|
|
|
} else {
|
|
|
|
|
QByteArray ba1;
|
|
|
|
|
appendByte(&ba1, 0x11); // options "step over"
|
|
|
|
|
appendInt(&ba1, scratch + 4);
|
|
|
|
|
appendInt(&ba1, scratch + 4);
|
|
|
|
|
appendInt(&ba1, m_session.pid);
|
|
|
|
|
appendInt(&ba1, m_session.tid);
|
|
|
|
|
sendTrkMessage(0x19, TrkCB(handleDirectWrite5), ba1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrkGdbAdapter::handleDirectWrite5(const TrkResult &response)
|
|
|
|
|
{
|
|
|
|
|
logMessage("DIRECT WRITE5: " + response.toString());
|
|
|
|
|
if (const int errorCode = response.errorCode()) {
|
2010-06-25 15:06:30 +02:00
|
|
|
logMessage("ERROR: " + response.errorString() + "in handleDirectWrite1", LogError);
|
2009-10-02 16:56:48 +02:00
|
|
|
} else {
|
|
|
|
|
// Restore PC
|
|
|
|
|
sendTrkMessage(0x13, TrkCB(handleDirectWrite6),
|
|
|
|
|
trkWriteRegisterMessage(RegisterPC, oldPC));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrkGdbAdapter::handleDirectWrite6(const TrkResult &response)
|
|
|
|
|
{
|
|
|
|
|
logMessage("DIRECT WRITE6: " + response.toString());
|
|
|
|
|
if (const int errorCode = response.errorCode()) {
|
2010-06-25 15:06:30 +02:00
|
|
|
logMessage("ERROR: " + response.errorString() + "in handleDirectWrite1", LogError);
|
2009-10-02 16:56:48 +02:00
|
|
|
} else {
|
|
|
|
|
// Restore memory
|
|
|
|
|
sendTrkMessage(0x11, TrkCB(handleDirectWrite7),
|
|
|
|
|
trkWriteMemoryMessage(scratch, oldMem));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrkGdbAdapter::handleDirectWrite7(const TrkResult &response)
|
|
|
|
|
{
|
|
|
|
|
logMessage("DIRECT WRITE7: " + response.toString());
|
|
|
|
|
if (const int errorCode = response.errorCode()) {
|
2010-06-25 15:06:30 +02:00
|
|
|
logMessage("ERROR: " + response.errorString() + "in handleDirectWrite1", LogError);
|
2009-10-02 16:56:48 +02:00
|
|
|
} else {
|
|
|
|
|
// Check
|
|
|
|
|
sendTrkMessage(0x10, TrkCB(handleDirectWrite8),
|
2010-07-07 14:00:54 +02:00
|
|
|
trk::Launcher::readMemoryMessage(m_session.pid, m_session.tid,
|
|
|
|
|
scratch, 8));
|
2009-10-02 16:56:48 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrkGdbAdapter::handleDirectWrite8(const TrkResult &response)
|
|
|
|
|
{
|
|
|
|
|
logMessage("DIRECT WRITE8: " + response.toString());
|
|
|
|
|
if (const int errorCode = response.errorCode()) {
|
2010-06-25 15:06:30 +02:00
|
|
|
logMessage("ERROR: " + response.errorString() + "in handleDirectWrite1", LogError);
|
2009-10-02 16:56:48 +02:00
|
|
|
} else {
|
|
|
|
|
// Re-read registers
|
|
|
|
|
sendTrkMessage(0x12,
|
|
|
|
|
TrkCB(handleAndReportReadRegistersAfterStop),
|
2010-07-07 14:00:54 +02:00
|
|
|
Launcher::readRegistersMessage(m_session.pid, m_session.tid));
|
2009-10-02 16:56:48 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrkGdbAdapter::handleDirectWrite9(const TrkResult &response)
|
|
|
|
|
{
|
|
|
|
|
logMessage("DIRECT WRITE9: " + response.toString());
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-28 14:49:44 +02:00
|
|
|
void TrkGdbAdapter::handleDirectTrk(const TrkResult &result)
|
|
|
|
|
{
|
|
|
|
|
logMessage("HANDLE DIRECT TRK: " + stringFromArray(result.data));
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-29 09:49:09 +02:00
|
|
|
void TrkGdbAdapter::directStep(uint addr)
|
|
|
|
|
{
|
|
|
|
|
// Write PC:
|
|
|
|
|
qDebug() << "ADDR: " << addr;
|
2010-06-30 17:14:57 +02:00
|
|
|
oldPC = m_snapshot.registerValue(m_session.tid, RegisterPC);
|
|
|
|
|
m_snapshot.setRegisterValue(m_session.tid, RegisterPC, addr);
|
2009-09-29 09:49:09 +02:00
|
|
|
QByteArray ba = trkWriteRegisterMessage(RegisterPC, addr);
|
|
|
|
|
sendTrkMessage(0x13, TrkCB(handleDirectStep1), ba, "Write PC");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrkGdbAdapter::handleDirectStep1(const TrkResult &result)
|
|
|
|
|
{
|
|
|
|
|
logMessage("HANDLE DIRECT STEP1: " + stringFromArray(result.data));
|
|
|
|
|
QByteArray ba;
|
2010-06-30 17:14:57 +02:00
|
|
|
const uint pc = oldPC = m_snapshot.registerValue(m_session.tid, RegisterPC);
|
2009-09-29 09:49:09 +02:00
|
|
|
appendByte(&ba, 0x11); // options "step over"
|
2010-06-30 17:14:57 +02:00
|
|
|
appendInt(&ba, pc);
|
|
|
|
|
appendInt(&ba, pc);
|
2009-09-29 09:49:09 +02:00
|
|
|
appendInt(&ba, m_session.pid);
|
|
|
|
|
appendInt(&ba, m_session.tid);
|
|
|
|
|
sendTrkMessage(0x19, TrkCB(handleDirectStep2), ba, "Direct step");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrkGdbAdapter::handleDirectStep2(const TrkResult &result)
|
|
|
|
|
{
|
|
|
|
|
logMessage("HANDLE DIRECT STEP2: " + stringFromArray(result.data));
|
2010-06-30 17:14:57 +02:00
|
|
|
m_snapshot.setRegisterValue(m_session.tid, RegisterPC, oldPC);
|
|
|
|
|
QByteArray ba = trkWriteRegisterMessage(RegisterPC, oldPC);
|
2009-09-29 09:49:09 +02:00
|
|
|
sendTrkMessage(0x13, TrkCB(handleDirectStep3), ba, "Write PC");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrkGdbAdapter::handleDirectStep3(const TrkResult &result)
|
|
|
|
|
{
|
|
|
|
|
logMessage("HANDLE DIRECT STEP2: " + stringFromArray(result.data));
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-05 15:07:47 +02:00
|
|
|
void TrkGdbAdapter::cleanup()
|
|
|
|
|
{
|
2010-02-11 12:31:59 +01:00
|
|
|
if (!m_trkDevice.isNull()) {
|
|
|
|
|
m_trkDevice->close();
|
2010-04-09 08:43:26 +02:00
|
|
|
m_trkDevice->disconnect(this);
|
|
|
|
|
SymbianUtils::SymbianDeviceManager::instance()->releaseDevice(m_trkDevice->port());
|
2010-02-11 12:31:59 +01:00
|
|
|
m_trkDevice = TrkDevicePtr();
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-12 15:11:51 +02:00
|
|
|
delete m_gdbServer;
|
|
|
|
|
m_gdbServer = 0;
|
2009-10-05 15:07:47 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-09 17:07:59 +02:00
|
|
|
void TrkGdbAdapter::shutdownInferior()
|
|
|
|
|
{
|
|
|
|
|
m_engine->defaultInferiorShutdown("kill");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrkGdbAdapter::shutdownAdapter()
|
2009-09-21 11:09:38 +02:00
|
|
|
{
|
2010-12-02 15:16:53 +01:00
|
|
|
if (m_gdbProc.state() == QProcess::Running) {
|
|
|
|
|
cleanup();
|
|
|
|
|
m_engine->notifyAdapterShutdownOk();
|
|
|
|
|
} else {
|
|
|
|
|
// Something is wrong, gdb crashed. Kill debuggee (see handleDeleteProcess2)
|
|
|
|
|
if (m_trkDevice->isOpen()) {
|
|
|
|
|
logMessage("Emergency shutdown of TRK", LogError);
|
|
|
|
|
trkKill();
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-09-11 12:30:53 +02:00
|
|
|
}
|
|
|
|
|
|
2010-02-04 11:36:49 +01:00
|
|
|
void TrkGdbAdapter::trkReloadRegisters()
|
|
|
|
|
{
|
2010-06-30 17:14:57 +02:00
|
|
|
m_snapshot.syncRegisters(m_session.tid, m_engine->registerHandler());
|
2010-02-04 11:36:49 +01:00
|
|
|
}
|
|
|
|
|
|
2010-02-08 12:39:25 +01:00
|
|
|
void TrkGdbAdapter::trkReloadThreads()
|
|
|
|
|
{
|
2010-06-30 17:14:57 +02:00
|
|
|
m_snapshot.syncThreads(m_engine->threadsHandler());
|
2010-02-08 12:39:25 +01:00
|
|
|
}
|
2010-02-04 11:36:49 +01:00
|
|
|
|
2009-09-09 17:24:21 +02:00
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace Debugger
|