Newer
Older
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#include "debuggerstringutils.h"
# include <sys/types.h>
# include <unistd.h>
#endif
#include <QtCore/QTimer>
#include <QtCore/QDir>
#define CB(callback) \
static_cast<GdbEngine::AdapterCallback>(&TrkGdbAdapter::callback), \
STRINGIFY(callback)
//#define DEBUG_MEMORY 1
#if DEBUG_MEMORY
# define MEMORY_DEBUG(s) qDebug() << s
#else
# define MEMORY_DEBUG(s)
#endif
#define MEMORY_DEBUGX(s) qDebug() << s
namespace Debugger {
namespace Internal {
enum { KnownRegisters = RegisterPSGdb + 1};
static const char *registerNames[KnownRegisters] =
{
"A1", "A2", "A3", "A4",
0, 0, 0, 0,
0, 0, 0, "AP",
"IP", "SP", "LR", "PC",
"PSTrk", 0, 0, 0,
0, 0, 0, 0,
0, "PSGdb"
};
static QByteArray dumpRegister(int n, uint value)
{
QByteArray ba;
ba += ' ';
if (n < KnownRegisters && registerNames[n]) {
ba += registerNames[n];
} else {
ba += '#';
ba += QByteArray::number(n);
}
ba += "=" + hexxNumber(value);
return ba;
}
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
QDebug operator<<(QDebug d, MemoryRange range)
{
return d << QString("[%1,%2] (size %3) ")
.arg(range.from, 0, 16).arg(range.to, 0, 16).arg(range.size());
}
///////////////////////////////////////////////////////////////////////////
//
// MemoryRange
//
///////////////////////////////////////////////////////////////////////////
bool MemoryRange::intersects(const MemoryRange &other) const
{
Q_UNUSED(other);
return false; // FIXME
}
void MemoryRange::operator-=(const MemoryRange &other)
{
if (from == 0 && to == 0)
return;
MEMORY_DEBUG(" SUB: " << *this << " - " << other);
if (other.from <= from && to <= other.to) {
from = to = 0;
return;
}
if (other.from <= from && other.to <= to) {
from = qMax(from, other.to);
return;
}
if (from <= other.from && to <= other.to) {
to = qMin(other.from, to);
return;
}
// This would split the range.
QTC_ASSERT(false, qDebug() << "Memory::operator-() not handled for: "
<< *this << " - " << other);
}
///////////////////////////////////////////////////////////////////////////
//
// Snapshot
//
///////////////////////////////////////////////////////////////////////////
void Snapshot::reset()
{
memory.clear();
for (int i = 0; i < RegisterCount; ++i)
registers[i] = 0;
wantedMemory = MemoryRange();
}
void Snapshot::insertMemory(const MemoryRange &range, const QByteArray &ba)
{
QTC_ASSERT(range.size() == ba.size(),
qDebug() << "RANGE: " << range << " BA SIZE: " << ba.size(); return);
MEMORY_DEBUG("INSERT: " << range);
// Try to combine with existing chunk.
Snapshot::Memory::iterator it = memory.begin();
Snapshot::Memory::iterator et = memory.end();
for ( ; it != et; ++it) {
if (range.from == it.key().to) {
MEMORY_DEBUG("COMBINING " << it.key() << " AND " << range);
QByteArray data = *it;
data.append(ba);
memory.remove(it.key());
memory.insert(MemoryRange(it.key().from, range.to), data);
MEMORY_DEBUG(" TO " << MemoryRange(it.key().from, range.to));
return;
}
if (it.key().from == range.to) {
MEMORY_DEBUG("COMBINING " << range << " AND " << it.key());
QByteArray data = ba;
data.append(*it);
memory.remove(it.key());
memory.insert(MemoryRange(range.from, it.key().to), data);
MEMORY_DEBUG(" TO " << MemoryRange(range.from, it.key().to));
return;
}
}
// Not combinable, add chunk.
memory.insert(range, ba);
}
///////////////////////////////////////////////////////////////////////////
//
// TrkGdbAdapter
//
///////////////////////////////////////////////////////////////////////////
TrkGdbAdapter::TrkGdbAdapter(GdbEngine *engine, const TrkOptionsPtr &options) :
AbstractGdbAdapter(engine),
m_options(options),
m_running(false),
m_gdbAckMode(true),
m_verbose(2),
const DWORD portOffset = GetCurrentProcessId() % 100;
m_gdbServerName = _("127.0.0.1:%1").arg(2222 + portOffset);
connect(&m_rfcommProc, SIGNAL(readyReadStandardError()),
this, SLOT(handleRfcommReadyReadStandardError()));
connect(&m_rfcommProc, SIGNAL(readyReadStandardOutput()),
this, SLOT(handleRfcommReadyReadStandardOutput()));
connect(&m_rfcommProc, SIGNAL(error(QProcess::ProcessError)),
this, SLOT(handleRfcommError(QProcess::ProcessError)));
connect(&m_rfcommProc, SIGNAL(finished(int, QProcess::ExitStatus)),
this, SLOT(handleRfcommFinished(int, QProcess::ExitStatus)));
connect(&m_rfcommProc, SIGNAL(started()),
connect(&m_rfcommProc, SIGNAL(stateChanged(QProcess::ProcessState)),
this, SLOT(handleRfcommStateChanged(QProcess::ProcessState)));
connect(&m_trkDevice, SIGNAL(messageReceived(trk::TrkResult)),
this, SLOT(handleTrkResult(trk::TrkResult)));
connect(&m_trkDevice, SIGNAL(error(QString)),
this, SLOT(handleTrkError(QString)));
m_trkDevice.setVerbose(m_verbose);
m_trkDevice.setSerialFrame(m_options->mode != TrkOptions::BlueTooth);
connect(&m_trkDevice, SIGNAL(logMessage(QString)),
this, SLOT(trkLogMessage(QString)));
}
QString TrkGdbAdapter::overrideTrkDevice() const
{
return m_overrideTrkDevice;
}
void TrkGdbAdapter::setOverrideTrkDevice(const QString &d)
{
m_overrideTrkDevice = d;
}
QString TrkGdbAdapter::effectiveTrkDevice() const
{
if (!m_overrideTrkDevice.isEmpty())
return m_overrideTrkDevice;
if (m_options->mode == TrkOptions::BlueTooth)
return m_options->blueToothDevice;
return m_options->serialPort;
}
{
logMessage("TRK " + msg);
}
{
m_gdbServerName = name;
}
{
int pos = m_gdbServerName.indexOf(':');
if (pos == -1)
return m_gdbServerName;
return m_gdbServerName.left(pos);
}
{
int pos = m_gdbServerName.indexOf(':');
if (pos == -1)
return 0;
return m_gdbServerName.mid(pos + 1).toUInt();
}
{
QByteArray ba;
appendInt(&ba, m_session.pid);
appendInt(&ba, m_session.tid);
return ba;
}
QByteArray TrkGdbAdapter::trkReadRegistersMessage()
{
QByteArray ba;
appendByte(&ba, 0); // Register set, only 0 supported
appendShort(&ba, 0);
appendShort(&ba, RegisterCount - 1); // last register
appendInt(&ba, m_session.pid);
appendInt(&ba, m_session.tid);
return ba;
}
QByteArray TrkGdbAdapter::trkWriteRegisterMessage(byte reg, uint value)
{
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;
}
QByteArray TrkGdbAdapter::trkReadMemoryMessage(uint from, uint len)
appendByte(&ba, 0x08); // Options, FIXME: why?
appendShort(&ba, len);
appendInt(&ba, m_session.pid);
appendInt(&ba, m_session.tid);
return ba;
}
QByteArray TrkGdbAdapter::trkReadMemoryMessage(const MemoryRange &range)
{
return trkReadMemoryMessage(range.from, range.size());
}
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;
}
QByteArray TrkGdbAdapter::trkStepRangeMessage(byte option)
{
QByteArray ba;
qDebug() << "STEP ON " << hexxNumber(m_snapshot.registers[RegisterPC]);
appendInt(&ba, m_snapshot.registers[RegisterPC]); // Start address
appendInt(&ba, m_snapshot.registers[RegisterPC]); // End address
appendInt(&ba, m_session.pid);
appendInt(&ba, m_session.tid);
return ba;
}
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);
appendInt(&ba, m_session.tid); // threadID: 4 bytes Variable number of bytes.
return ba;
}
void TrkGdbAdapter::emitDelayedInferiorStartFailed(const QString &msg)
{
m_adapterFailMessage = msg;
QTimer::singleShot(0, this, SLOT(slotEmitDelayedInferiorStartFailed()));
}
void TrkGdbAdapter::slotEmitDelayedInferiorStartFailed()
{
emit inferiorStartFailed(m_adapterFailMessage);
}
void TrkGdbAdapter::waitForTrkConnect()
QTC_ASSERT(state() == AdapterStarting, qDebug() << state());
const QString device = effectiveTrkDevice();
if (!m_trkDevice.open(device, &errorMessage)) {
logMessage(_("Waiting on %1 (%2)").arg(device, errorMessage));
if (errorMessage.contains(_("ermission denied"))) {
static int direction = 0;
direction = (direction + 1) % 4;
showStatusMessage(_("Please start TRK on your device! %1")
if (m_waitCount++ < (m_options->mode == TrkOptions::BlueTooth ? 60 : 5)) {
QTimer::singleShot(1000, this, SLOT(waitForTrkConnect()));
QString msg = _("Failed to connect to %1 after "
"%2 attempts").arg(device).arg(m_waitCount);
logMessage(msg);
emit adapterStartFailed(msg, TrkOptionsPage::settingsId());
return;
}
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(handleTrkVersions)); // Versions
//sendTrkMessage(0x09); // Unrecognized command
//sendTrkMessage(0x4a, 0,
// "10 " + formatString("C:\\data\\usingdlls.sisx")); // Open File
//sendTrkMessage(0x4B, 0, "00 00 00 01 73 1C 3A C8"); // Close File
{
logMessage("HANDLING GDB CONNECTION");
QTC_ASSERT(m_gdbConnection == 0, /**/);
m_gdbConnection = m_gdbServer->nextPendingConnection();
QTC_ASSERT(m_gdbConnection, return);
connect(m_gdbConnection, SIGNAL(disconnected()),
m_gdbConnection, SLOT(deleteLater()));
connect(m_gdbConnection, SIGNAL(readyRead()),
this, SLOT(readGdbServerCommand()));
}
static inline QString msgGdbPacket(const QString &p)
{
return QLatin1String("gdb: ") + p;
}
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
QByteArray packet = m_gdbConnection->readAll();
m_gdbReadBuffer.append(packet);
logMessage("gdb: -> " + QString::fromAscii(packet));
if (packet != m_gdbReadBuffer)
logMessage("buffer: " + m_gdbReadBuffer);
QByteArray &ba = m_gdbReadBuffer;
while (ba.size()) {
char code = ba.at(0);
ba = ba.mid(1);
if (code == '+') {
//logMessage("ACK");
continue;
}
if (code == '-') {
logMessage("NAK: Retransmission requested");
continue;
}
if (code == char(0x03)) {
logMessage("INTERRUPT RECEIVED");
interruptInferior();
continue;
}
if (code != '$') {
logMessage("Broken package (2) " + quoteUnprintableLatin1(ba)
+ hexNumber(code));
continue;
}
int pos = ba.indexOf('#');
if (pos == -1) {
logMessage("Invalid checksum format in "
+ quoteUnprintableLatin1(ba));
continue;
}
bool ok = false;
uint checkSum = ba.mid(pos + 1, 2).toUInt(&ok, 16);
if (!ok) {
logMessage("Invalid checksum format 2 in "
+ quoteUnprintableLatin1(ba));
return;
}
//logMessage(QString("Packet checksum: %1").arg(checkSum));
byte sum = 0;
for (int i = 0; i < pos; ++i)
sum += ba.at(i);
if (sum != checkSum) {
logMessage(QString("ERROR: Packet checksum wrong: %1 %2 in "
+ quoteUnprintableLatin1(ba)).arg(checkSum).arg(sum));
}
QByteArray cmd = ba.left(pos);
ba.remove(0, pos + 3);
handleGdbServerCommand(cmd);
}
}
bool TrkGdbAdapter::sendGdbServerPacket(const QByteArray &packet, bool doFlush)
logMessage(_("Cannot write to gdb: No connection (%1)")
.arg(_(packet)));
return false;
}
if (m_gdbConnection->state() != QAbstractSocket::ConnectedState) {
logMessage(_("Cannot write to gdb: Not connected (%1)")
.arg(_(packet)));
return false;
}
if (m_gdbConnection->write(packet) == -1) {
logMessage(_("Cannot write to gdb: %1 (%2)")
.arg(m_gdbConnection->errorString()).arg(_(packet)));
return false;
}
if (doFlush)
m_gdbConnection->flush();
return true;
}
{
if (!m_gdbAckMode)
return;
QByteArray packet = "+";
logMessage("gdb: <- " + packet);
sendGdbServerPacket(packet, false);
}
void TrkGdbAdapter::sendGdbServerMessage(const QByteArray &msg, const QByteArray &logNote)
{
byte sum = 0;
for (int i = 0; i != msg.size(); ++i)
sum += msg.at(i);
char checkSum[30];
qsnprintf(checkSum, sizeof(checkSum) - 1, "%02x ", sum);
//logMessage(QString("Packet checksum: %1").arg(sum));
QByteArray packet;
packet.append("$");
packet.append(msg);
packet.append('#');
packet.append(checkSum);
int pad = qMax(0, 24 - packet.size());
logMessage("gdb: <- " + packet + QByteArray(pad, ' ') + logNote);
sendGdbServerPacket(packet, true);
}
void TrkGdbAdapter::sendGdbServerMessageAfterTrkResponse(const QByteArray &msg,
const QByteArray &logNote)
{
QByteArray ba = msg + char(1) + logNote;
sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, TrkCB(reportToGdb), "", ba); // Answer gdb
}
{
QByteArray message = result.cookie.toByteArray();
QByteArray note;
int pos = message.lastIndexOf(char(1)); // HACK
if (pos != -1) {
note = message.mid(pos + 1);
message = message.left(pos);
}
message.replace("@CODESEG@", hexNumber(m_session.codeseg));
message.replace("@DATASEG@", hexNumber(m_session.dataseg));
message.replace("@PID@", hexNumber(m_session.pid));
message.replace("@TID@", hexNumber(m_session.tid));
sendGdbServerMessage(message, note);
}
QByteArray TrkGdbAdapter::trkBreakpointMessage(uint addr, uint len, bool armMode)
{
QByteArray ba;
appendByte(&ba, 0x82); // unused option
appendByte(&ba, armMode /*bp.mode == ArmMode*/ ? 0x00 : 0x01);
appendInt(&ba, addr);
appendInt(&ba, len);
appendInt(&ba, 0x00000001);
appendInt(&ba, m_session.pid);
appendInt(&ba, 0xFFFFFFFF);
return ba;
}
void TrkGdbAdapter::handleGdbServerCommand(const QByteArray &cmd)
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
{
// http://sourceware.org/gdb/current/onlinedocs/gdb_34.html
if (0) {}
else if (cmd == "!") {
sendGdbServerAck();
//sendGdbServerMessage("", "extended mode not enabled");
sendGdbServerMessage("OK", "extended mode enabled");
}
else if (cmd.startsWith("?")) {
logMessage(msgGdbPacket(QLatin1String("Query halted")));
// Indicate the reason the target halted.
// The reply is the same as for step and continue.
sendGdbServerAck();
// The command below will trigger fetching a stack trace while
// the process does not seem to be fully functional. Most notably
// the PC points to a 0x9..., which is not in "our" range
//sendGdbServerMessage("T05library:r;", "target halted (library load)");
//sendGdbServerMessage("S05", "target halted (trap)");
sendGdbServerMessage("S00", "target halted (trap)");
//sendGdbServerMessage("O" + QByteArray("Starting...").toHex());
}
else if (cmd == "c") {
logMessage(msgGdbPacket(QLatin1String("Continue")));
sendGdbServerAck();
QByteArray ba;
appendByte(&ba, 0); // options
appendInt(&ba, 0); // start address
appendInt(&ba, 0); // end address
appendInt(&ba, m_session.pid);
appendInt(&ba, m_session.tid);
sendTrkMessage(0x18, TrkCallback(), ba);
}
else if (cmd.startsWith("C")) {
logMessage(msgGdbPacket(QLatin1String("Continue with signal")));
// C sig[;addr] Continue with signal sig (hex signal number)
//Reply: See section D.3 Stop Reply Packets, for the reply specifications.
sendGdbServerAck();
bool ok = false;
uint signalNumber = cmd.mid(1).toInt(&ok, 16);
QByteArray ba;
appendInt(&ba, m_session.pid);
appendInt(&ba, m_session.tid);
sendTrkMessage(0x18, TrkCB(handleSignalContinue), ba, signalNumber);
}
else if (cmd.startsWith("D")) {
sendGdbServerAck();
sendGdbServerMessage("OK", "shutting down");
}
else if (cmd == "g") {
// Read general registers.
}
else if (cmd.startsWith("Hc")) {
logMessage(msgGdbPacket(QLatin1String("Set thread & continue")));
// Set thread for subsequent operations (`m', `M', `g', `G', et.al.).
// for step and continue operations
//$Hc-1#09
sendGdbServerAck();
sendGdbServerMessage("OK", "Set current thread for step & continue");
}
else if (cmd.startsWith("Hg")) {
logMessage(msgGdbPacket(QLatin1String("Set thread")));
// Set thread for subsequent operations (`m', `M', `g', `G', et.al.).
// for 'other operations. 0 - any thread
//$Hg0#df
sendGdbServerAck();
m_session.currentThread = cmd.mid(2).toInt(0, 16);
sendGdbServerMessage("OK", "Set current thread "
+ QByteArray::number(m_session.currentThread));
}
else if (cmd == "k" || cmd.startsWith("vKill")) {
// Kill inferior process
logMessage(msgGdbPacket(QLatin1String("kill")));
sendTrkMessage(0x41, TrkCB(handleDeleteProcess),
trkDeleteProcessMessage(), "Delete process");
}
else if (cmd.startsWith("m")) {
logMessage(msgGdbPacket(QLatin1String("Read memory")));
// m addr,length
sendGdbServerAck();
uint addr = 0, len = 0;
do {
const int pos = cmd.indexOf(',');
if (pos == -1)
break;
bool ok;
addr = cmd.mid(1, pos - 1).toUInt(&ok, 16);
if (!ok)
break;
len = cmd.mid(pos + 1).toUInt(&ok, 16);
if (!ok)
break;
} while (false);
if (len) {
readMemory(addr, len, m_bufferedMemoryRead);
} else {
sendGdbServerMessage("E20", "Error " + cmd);
}
}
else if (cmd.startsWith("p")) {
logMessage(msgGdbPacket(QLatin1String("read register")));
// 0xf == current instruction pointer?
//sendGdbServerMessage("0000", "current IP");
sendGdbServerAck();
bool ok = false;
const uint registerNumber = cmd.mid(1).toInt(&ok, 16);
QByteArray logMsg = "Read Register";
if (registerNumber == RegisterPSGdb) {
QByteArray ba;
appendInt(&ba, m_snapshot.registers[RegisterPSTrk], LittleEndian);
logMsg += dumpRegister(registerNumber, m_snapshot.registers[RegisterPSTrk]);
sendGdbServerMessage(ba.toHex(), logMsg);
appendInt(&ba, m_snapshot.registers[registerNumber], LittleEndian);
logMsg += dumpRegister(registerNumber, m_snapshot.registers[registerNumber]);
sendGdbServerMessage(ba.toHex(), logMsg);
} else {
sendGdbServerMessage("0000", "read single unknown register #"
+ QByteArray::number(registerNumber));
//sendGdbServerMessage("E01", "read single unknown register");
else if (cmd.startsWith("P")) {
logMessage(msgGdbPacket(QLatin1String("write register")));
// $Pe=70f96678#d3
sendGdbServerAck();
int pos = cmd.indexOf('=');
QByteArray regName = cmd.mid(1, pos - 1);
QByteArray valueName = cmd.mid(pos + 1);
bool ok = false;
const uint registerNumber = regName.toInt(&ok, 16);
const uint value = swapEndian(valueName.toInt(&ok, 16));
// FIXME: Assume all goes well.
m_snapshot.registers[registerNumber] = value;
QByteArray ba = trkWriteRegisterMessage(registerNumber, value);
sendTrkMessage(0x13, TrkCB(handleWriteRegister), ba, "Write register");
// Note that App TRK refuses to write registers 13 and 14
}
else if (cmd == "qAttached") {
//$qAttached#8f
// 1: attached to an existing process
// 0: created a new process
sendGdbServerAck();
sendGdbServerMessage("0", "new process created");
//sendGdbServerMessage("1", "attached to existing process");
//sendGdbServerMessage("E01", "new process created");
}
else if (cmd.startsWith("qC")) {
logMessage(msgGdbPacket(QLatin1String("query thread id")));
// Return the current thread ID
//$qC#b4
sendGdbServerAck();
sendGdbServerMessageAfterTrkResponse("QC@TID@");
}
else if (cmd.startsWith("qSupported")) {
//$qSupported#37
//$qSupported:multiprocess+#c6
//logMessage("Handling 'qSupported'");
sendGdbServerAck();
sendGdbServerMessage(
"PacketSize=7cf;"
"QPassSignals+;"
"qXfer:libraries:read+;"
//"qXfer:auxv:read+;"
"qXfer:features:read+");
}
else if (cmd == "qfDllInfo") {
// happens with gdb 6.4.50.20060226-cvs / CodeSourcery
// never made it into FSF gdb?
sendGdbServerAck();
sendGdbServerMessage("", "FIXME: nothing?");
}
else if (cmd == "qPacketInfo") {
// happens with gdb 6.4.50.20060226-cvs / CodeSourcery
// deprecated by qSupported?
sendGdbServerAck();
sendGdbServerMessage("", "FIXME: nothing?");
}
else if (cmd == "qOffsets") {
sendGdbServerAck();
sendGdbServerMessageAfterTrkResponse("TextSeg=@CODESEG@;DataSeg=@DATASEG@");
}
else if (cmd == "qSymbol::") {
if (m_verbose)
logMessage(msgGdbPacket(QLatin1String("notify can handle symbol lookup")));
// Notify the target that GDB is prepared to serve symbol lookup requests.
sendGdbServerAck();
if (1)
sendGdbServerMessage("OK", "no further symbols needed");
else
sendGdbServerMessage("qSymbol:" + QByteArray("_Z7E32Mainv").toHex(),
"ask for more");
}
else if (cmd.startsWith("qXfer:features:read:target.xml:")) {
// $qXfer:features:read:target.xml:0,7ca#46...Ack
sendGdbServerAck();
sendGdbServerMessage("l<target><architecture>symbianelf</architecture></target>");
}
else if (cmd.startsWith("qXfer:libraries:read")) {
sendGdbServerAck();
/*
<library-list>
<library name="/lib/libc.so.6">
<segment address="0x10000000"/>
</library>
</library-list>
i */
}
else if (cmd == "QStartNoAckMode") {
//$qSupported#37
//logMessage("Handling 'QStartNoAckMode'");
sendGdbServerAck();
sendGdbServerMessage("OK", "ack no-ack mode");
m_gdbAckMode = false;
}
else if (cmd.startsWith("QPassSignals")) {
// list of signals to pass directly to inferior
// $QPassSignals:e;10;14;17;1a;1b;1c;21;24;25;4c;#8f
// happens only if "QPassSignals+;" is qSupported
sendGdbServerAck();
// FIXME: use the parameters
sendGdbServerMessage("OK", "passing signals accepted");
}
else if (cmd == "s" || cmd.startsWith("vCont;s")) {
logMessage(msgGdbPacket(QLatin1String("Step range")));
logMessage(" from " + hexxNumber(m_snapshot.registers[RegisterPC]));
sendGdbServerAck();
m_running = true;
QByteArray ba = trkStepRangeMessage(0x01); // options "step into"
sendTrkMessage(0x19, TrkCB(handleStepInto), ba, "Step range");
}
else if (cmd == "vCont?") {
// actions supported by the vCont packet
sendGdbServerAck();
//sendGdbServerMessage("OK"); // we don't support vCont.
sendGdbServerMessage("vCont;c;C;s;S");
}
else if (cmd == "vCont;c") {
// vCont[;action[:thread-id]]...'
sendGdbServerAck();
m_running = true;
sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE");
}
else if (cmd.startsWith("Z0,") || cmd.startsWith("Z1,")) {
// Insert breakpoint
logMessage(msgGdbPacket(QLatin1String("Insert breakpoint")));
// $Z0,786a4ccc,4#99
const int pos = cmd.lastIndexOf(',');
bool ok = false;
const uint addr = cmd.mid(3, pos - 3).toInt(&ok, 16);
const uint len = cmd.mid(pos + 1).toInt(&ok, 16);
//qDebug() << "ADDR: " << hexNumber(addr) << " LEN: " << len;
logMessage(_("Inserting breakpoint at 0x%1, %2")
const QByteArray ba = trkBreakpointMessage(addr, len, len == 4);
sendTrkMessage(0x1B, TrkCB(handleAndReportSetBreakpoint), ba, addr);
}
else if (cmd.startsWith("z0,") || cmd.startsWith("z1,")) {
// Remove breakpoint
logMessage(msgGdbPacket(QLatin1String("Remove breakpoint")));
// $z0,786a4ccc,4#99
const int pos = cmd.lastIndexOf(',');
bool ok = false;
const uint addr = cmd.mid(3, pos - 3).toInt(&ok, 16);
const uint len = cmd.mid(pos + 1).toInt(&ok, 16);
const uint bp = m_session.addressToBP[addr];
if (bp == 0) {
logMessage(_("NO RECORDED BP AT 0x%1, %2")
} else {
m_session.addressToBP.remove(addr);
QByteArray ba;
sendTrkMessage(0x1C, TrkCB(handleClearBreakpoint), ba, addr);
}
}
else if (cmd.startsWith("qPart:") || cmd.startsWith("qXfer:")) {
QByteArray data = cmd.mid(1 + cmd.indexOf(':'));
// "qPart:auxv:read::0,147": Read OS auxiliary data (see info aux)
bool handled = false;
if (data.startsWith("auxv:read::")) {
const int offsetPos = data.lastIndexOf(':') + 1;
const int commaPos = data.lastIndexOf(',');
if (commaPos != -1) {
bool ok1 = false, ok2 = false;
const int offset = data.mid(offsetPos, commaPos - offsetPos)
.toInt(&ok1, 16);
const int length = data.mid(commaPos + 1).toInt(&ok2, 16);
if (ok1 && ok2) {
const QString msg = _("Read of OS auxilary "
"vector (%1, %2) not implemented.").arg(offset).arg(length);
sendGdbServerMessage("E20", msg.toLatin1());
handled = true;
}
}
} // auxv read
if (!handled) {
const QString msg = QLatin1String("FIXME unknown 'XFER'-request: ")
+ QString::fromAscii(cmd);
sendGdbServerMessage("E20", msg.toLatin1());
}
} // qPart/qXfer
else {
logMessage(msgGdbPacket(QLatin1String("FIXME unknown: ")
+ QString::fromAscii(cmd)));
}
}
void TrkGdbAdapter::sendTrkMessage(byte code, TrkCallback callback,
const QByteArray &data, const QVariant &cookie)
{
m_trkDevice.sendTrkMessage(code, callback, data, cookie);
}
//logMessage(QString("SENDING ACKNOWLEDGEMENT FOR TOKEN %1").arg(int(token)));
m_trkDevice.sendTrkAck(token);
}
{
logMessage("## TRK ERROR: " + msg);
}
void TrkGdbAdapter::handleTrkResult(const TrkResult &result)
{
if (result.isDebugOutput) {
sendTrkAck(result.token);
logMessage(QLatin1String("APPLICATION OUTPUT: ") +
QString::fromAscii(result.data));
sendGdbServerMessage("O" + result.data.toHex());
return;
}
//logMessage("READ TRK " + result.toString());
QByteArray prefix = "READ BUF: ";
QByteArray str = result.toString().toUtf8();
switch (result.code) {
case 0x80: // ACK
break;
case 0xff: { // NAK. This mostly means transmission error, not command failed.
QString logMsg;
QTextStream(&logMsg) << prefix << "NAK: for token=" << result.token
<< " ERROR: " << errorMessage(result.data.at(0)) << ' ' << str;