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 "s60debuggerbluetoothstarter.h"
#include "bluetoothlistener_gui.h"
#include "debuggerstringutils.h"
#include <utils/qtcassert.h>
#include <QtCore/QTimer>
#include <QtCore/QDir>
# include <sys/types.h>
# include <unistd.h>
#endif
#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(uint 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;
}
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
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)
{
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);
const MemoryRange res(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);
const MemoryRange res(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_overrideTrkDeviceType(-1),
m_trkDevice(new trk::TrkDevice),

Friedemann Kleint
committed
m_verbose(0),
m_bufferedMemoryRead(true)

Friedemann Kleint
committed
const QByteArray trkVerbose = qgetenv("QTC_TRK_VERBOSE");
if (!trkVerbose.isEmpty()) {
bool ok;
m_verbose = trkVerbose.toInt(&ok);
if (!ok)
m_verbose = 1;
}
const DWORD portOffset = GetCurrentProcessId() % 100;
m_gdbServerName = _("127.0.0.1:%1").arg(2222 + portOffset);
connect(m_trkDevice.data(), SIGNAL(messageReceived(trk::TrkResult)),
connect(m_trkDevice.data(), SIGNAL(error(QString)),
m_trkDevice->setVerbose(m_verbose);
m_trkDevice->setSerialFrame(effectiveTrkDeviceType() != TrkOptions::BlueTooth);
connect(m_trkDevice.data(), SIGNAL(logMessage(QString)),
this, SLOT(trkLogMessage(QString)));
}
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;
}
int TrkGdbAdapter::effectiveTrkDeviceType() const
{
if (m_overrideTrkDeviceType >= 0)
return m_overrideTrkDeviceType;
return m_options->mode;
}
{
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);
}
{
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;
}
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
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
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)
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
{
// 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).toUInt(&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).toUInt(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).toUInt(&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.toUInt(&ok, 16);
const uint value = swapEndian(valueName.toUInt(&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") {
// 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();
if (!m_session.libraries.isEmpty()) {
QByteArray response = "m";
// FIXME: Limit packet length by using qsDllInfo packages?
for (int i = 0; i != m_session.libraries.size(); ++i) {
if (i)
response += ';';
const Library &lib = m_session.libraries.at(i);
response += "Name=" + lib.name.toHex()
+ ",TextSeg=" + hexNumber(lib.codeseg)
+ ",DataSeg=" + hexNumber(lib.dataseg);
}
sendGdbServerMessage(response, "library information transfered");
} else {
sendGdbServerMessage("l", "library information transfer finished");
}
}
else if (cmd == "qsDllInfo") {
// That's a following query package
sendGdbServerMessage("l", "library information transfer finished");
}
else if (cmd == "qPacketInfo") {
// happens with gdb 6.4.50.20060226-cvs / CodeSourcery
// deprecated by qSupported?
sendGdbServerAck();
sendGdbServerMessage("", "FIXME: nothing?");
}
else if (cmd == "qOffsets") {
sendGdbServerAck();
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 ok1 = false;
bool ok2 = false;
const uint addr = cmd.mid(3, pos - 3).toUInt(&ok1, 16);
const uint len = cmd.mid(pos + 1).toUInt(&ok2, 16);
if (!ok1) {
logMessage("MISPARSED ADDRESS FROM " + cmd +
" (" + cmd.mid(3, pos - 3) + ")");
} else if (!ok2) {
logMessage("MISPARSED BREAKPOINT SIZE FROM " + cmd);
} else {
//qDebug() << "ADDR: " << hexNumber(addr) << " LEN: " << len;
logMessage(_("Inserting breakpoint at 0x%1, %2")
.arg(addr, 0, 16).arg(len));
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).toUInt(&ok, 16);
const uint len = cmd.mid(pos + 1).toUInt(&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)
.toUInt(&ok1, 16);
const int length = data.mid(commaPos + 1).toUInt(&ok2, 16);
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) {
// It looks like those messages _must not_ be acknowledged.
// If we do so, TRK will complain about wrong sequencing.
//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;
break;
}
case 0x90: { // Notified Stopped
// 90 01 78 6a 40 40 00 00 07 23 00 00 07 24 00 00
debugMessage(_("RESET SNAPSHOT (NOTIFY STOPPED)"));
m_snapshot.reset();
const char *data = result.data.data();
const uint addr = extractInt(data);
const uint pid = extractInt(data + 4);