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.
**
**************************************************************************/
#ifndef Q_OS_WIN
# include <sys/types.h>
# include <unistd.h>
#endif
#include <QtCore/QTimer>
#include <QtCore/QDir>
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
using namespace trk;
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;
}
namespace Debugger {
namespace Internal {
TrkGdbAdapter::TrkGdbAdapter(GdbEngine *engine, const TrkOptionsPtr &options) :
AbstractGdbAdapter(engine),
m_options(options),
m_running(false),
m_gdbAckMode(true),
m_verbose(2),
m_bufferedMemoryRead(true),
m_waitCount(0)
const DWORD portOffset = GetCurrentProcessId() % 100;
m_gdbServerName = QString::fromLatin1("127.0.0.1:%1").arg(2222 + portOffset);
connect(&m_gdbProc, SIGNAL(readyReadStandardError()),
connect(&m_gdbProc, SIGNAL(readyReadStandardOutput()),
connect(&m_gdbProc, SIGNAL(error(QProcess::ProcessError)),
this, SLOT(handleGdbError(QProcess::ProcessError)));
connect(&m_gdbProc, SIGNAL(finished(int, QProcess::ExitStatus)),
this, SLOT(handleGdbFinished(int, QProcess::ExitStatus)));
connect(&m_gdbProc, SIGNAL(started()),
this, SLOT(handleGdbStarted()));
connect(&m_gdbProc, SIGNAL(stateChanged(QProcess::ProcessState)),
this, SLOT(handleGdbStateChanged(QProcess::ProcessState)));
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)));
if (m_verbose > 1)
m_trkDevice.setVerbose(true);
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 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::trkReadMemoryMessage(uint addr, uint len)
{
QByteArray ba;
appendByte(&ba, 0x08); // Options, FIXME: why?
appendShort(&ba, len);
appendInt(&ba, addr);
appendInt(&ba, m_session.pid);
appendInt(&ba, m_session.tid);
return ba;
}
QByteArray TrkGdbAdapter::trkStepRangeMessage(byte option)
{
QByteArray ba;
appendByte(&ba, option);
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;
}
const QString device = effectiveTrkDevice();
if (!m_trkDevice.open(device, &errorMessage)) {
logMessage(QString::fromLatin1("Waiting on %1 (%2)").arg(device, errorMessage));
// Do not loop forever
if (m_waitCount++ < (m_options->mode == TrkOptions::BlueTooth ? 60 : 5)) {
QTimer::singleShot(1000, this, SLOT(startInferiorEarly()));
QString msg = QString::fromLatin1("Failed to connect to %1 after "
"%2 attempts").arg(device).arg(m_waitCount);
logMessage(msg);
emit adapterStartFailed(msg);
QTimer::singleShot(1000, this, SLOT(startInferiorEarly()));
return;
}
m_trkDevice.sendTrkInitialPing();
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
QByteArray ba;
appendByte(&ba, 0); // ?
appendByte(&ba, 0); // ?
appendByte(&ba, 0); // ?
QByteArray file("C:\\sys\\bin\\filebrowseapp.exe");
appendString(&ba, file, TargetByteOrder);
sendTrkMessage(0x40, TrkCB(handleCreateProcess), ba); // Create Item
//sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, TrkCB(startGdbServer));
}
{
logMessage("HANDLING GDB CONNECTION");
m_gdbConnection = m_gdbServer.nextPendingConnection();
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;
}
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
{
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)
{
if (!m_gdbConnection) {
logMessage(QString::fromLatin1("Cannot write to gdb: No connection (%1)")
return false;
}
if (m_gdbConnection->state() != QAbstractSocket::ConnectedState) {
logMessage(QString::fromLatin1("Cannot write to gdb: Not connected (%1)")
return false;
}
if (m_gdbConnection->write(packet) == -1) {
logMessage(QString::fromLatin1("Cannot write to gdb: %1 (%2)")
.arg(m_gdbConnection->errorString()).arg(QString::fromLatin1(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)
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
{
// 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")));
QByteArray ba;
appendByte(&ba, 0); // ?
appendByte(&ba, 0); // Sub-command: Delete Process
appendInt(&ba, m_session.pid);
sendTrkMessage(0x41, TrkCB(handleDeleteProcess),
ba, "Delete process"); // Delete Item
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
}
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);
} 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");
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
}
}
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");
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
}
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 == "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(QString::fromLatin1("Inserting breakpoint at 0x%1, %2")
.arg(addr, 0, 16).arg(len));
const QByteArray ba = trkBreakpointMessage(addr, len, m_session.pid);
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(QString::fromLatin1("NO RECORDED BP AT 0x%1, %2")
.arg(addr, 0, 16).arg(len));
} else {
m_session.addressToBP.remove(addr);
QByteArray ba;
appendByte(&ba, 0x00);
appendShort(&ba, bp);
appendInt(&ba, addr);
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 = QString::fromLatin1("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)));
}
}
{
if (msg == "EI") {
sendGdbMessage("-exec-interrupt");
} else if (msg == "C") {
sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE");
} else if (msg == "S") {
sendTrkMessage(0x19, TrkCallback(), trkStepRangeMessage(0x01), "STEP");
} else if (msg == "N") {
sendTrkMessage(0x19, TrkCallback(), trkStepRangeMessage(0x11), "NEXT");
} else if (msg == "I") {
interruptInferior();
} else {
logMessage("EXECUTING GDB COMMAND " + msg);
sendGdbMessage(msg);
}
}
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;
break;
}
case 0x90: { // Notified Stopped
// 90 01 78 6a 40 40 00 00 07 23 00 00 07 24 00 00
const char *data = result.data.data();
const uint addr = extractInt(data);
const uint pid = extractInt(data + 4);
const uint tid = extractInt(data + 8);
logMessage(prefix + QString::fromLatin1("NOTE: PID %1/TID %2 "
"STOPPED at 0x%3").arg(pid).arg(tid).arg(addr, 0, 16));
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"));
}
// We almost always need register values, so get them
// now before informing gdb about the stop. In theory
//sendGdbServerMessage("S05", "Target stopped");
sendTrkMessage(0x12,
TrkCB(handleAndReportReadRegistersAfterStop),
trkReadRegisterMessage());
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
break;
}
case 0x91: { // Notify Exception (obsolete)
logMessage(prefix + "NOTE: EXCEPTION " + str);
sendTrkAck(result.token);
break;
}
case 0x92: { //
logMessage(prefix + "NOTE: INTERNAL ERROR: " + str);
sendTrkAck(result.token);
break;
}
// target->host OS notification
case 0xa0: { // Notify Created
const char *data = result.data.data();
const byte error = result.data.at(0);
// type: 1 byte; for dll item, this value is 2.
const byte type = result.data.at(1);
const uint pid = extractInt(data + 2);
const uint tid = extractInt(data + 6);
const uint codeseg = extractInt(data + 10);
const uint dataseg = extractInt(data + 14);
const uint len = extractShort(data + 18);
const QByteArray name = result.data.mid(20, len); // library name
m_session.modules += QString::fromAscii(name);
QString logMsg;
QTextStream str(&logMsg);
str << prefix << " NOTE: LIBRARY LOAD: token=" << result.token;
if (error)
str << " ERROR: " << int(error);
str << " TYPE: " << int(type) << " PID: " << pid << " TID: " << tid;
str << " CODE: " << hexxNumber(codeseg);
str << " DATA: " << hexxNumber(dataseg);
str << " NAME: '" << name << '\'';
logMessage(logMsg);
// This lets gdb trigger a register update etc
//sendGdbServerMessage("T05library:r;");
sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE");
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);
logMessage(QString::fromLatin1("%1 %2 UNLOAD: %3")
.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: {
logMessage(prefix + "INVALID: " + str);
break;
}
}
}
{
//---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);
}
void TrkGdbAdapter::handleCreateProcess(const TrkResult &result)
{
// 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]
const char *data = result.data.data();
m_session.pid = extractInt(data + 1);
m_session.tid = extractInt(data + 5);
m_session.codeseg = extractInt(data + 9);
m_session.dataseg = extractInt(data + 13);
logMessage("PID: " + hexxNumber(m_session.pid));
logMessage("TID: " + hexxNumber(m_session.tid));
logMessage("COD: " + hexxNumber(m_session.codeseg));
logMessage("DAT: " + hexxNumber(m_session.dataseg));
QByteArray ba;
appendInt(&ba, m_session.pid);
appendInt(&ba, m_session.tid);
startGdb();
}
void TrkGdbAdapter::handleDeleteProcess(const TrkResult &result)
{
Q_UNUSED(result);
logMessage("TRK Process killed");
//sendTrkMessage(0x01, TrkCB(handleDeleteProcess2)); // Ping
sendTrkMessage(0x02, TrkCB(handleDeleteProcess2)); // Disconnect
}
void TrkGdbAdapter::handleDeleteProcess2(const TrkResult &result)
{
Q_UNUSED(result);
logMessage("process killed");
sendGdbServerAck();
sendGdbServerMessage("", "process killed");
}
void TrkGdbAdapter::handleReadRegisters(const TrkResult &result)
{
logMessage(" RESULT: " + result.toString());
// [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()) {
logMessage("ERROR: " + result.errorString());
return;
}
const char *data = result.data.data() + 1; // Skip ok byte
for (int i = 0; i < RegisterCount; ++i)
m_snapshot.registers[i] = extractInt(data + 4 * i);
}