trkgdbadapter.cpp 73.5 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**************************************************************************
**
** 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.
**
**************************************************************************/

hjk's avatar
hjk committed
30
#include "trkgdbadapter.h"
31

32
#include "launcher.h"
33
#include "trkoptions.h"
34
#include "trkoptionspage.h"
35
36
#include "s60debuggerbluetoothstarter.h"
#include "bluetoothlistener_gui.h"
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
37

38
#include "registerhandler.h"
39
#include "debuggeractions.h"
40
#include "debuggerstringutils.h"
hjk's avatar
hjk committed
41
#ifndef STANDALONE_RUNNER
42
#include "gdbengine.h"
hjk's avatar
hjk committed
43
#endif
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
44
45
46
47
48
49

#include <utils/qtcassert.h>

#include <QtCore/QTimer>
#include <QtCore/QDir>

hjk's avatar
hjk committed
50
51
52
#ifdef Q_OS_WIN
#  include <windows.h>
#else
53
54
55
#  include <sys/types.h>
#  include <unistd.h>
#endif
56

hjk's avatar
hjk committed
57
58
59
60
#define CB(callback) \
    static_cast<GdbEngine::AdapterCallback>(&TrkGdbAdapter::callback), \
    STRINGIFY(callback)

hjk's avatar
hjk committed
61
#define TrkCB(s) TrkCallback(this, &TrkGdbAdapter::s)
62

63
64
65
66
67
68
69
//#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
70
71
72

using namespace trk;

73
74
75
namespace Debugger {
namespace Internal {

76
77
enum { KnownRegisters = RegisterPSGdb + 1};

78
79
static inline void appendByte(QByteArray *ba, trk::byte b) { ba->append(b); }

80
81
82
83
84
85
86
87
88
89
90
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"
};

91
static QByteArray dumpRegister(uint n, uint value)
92
93
94
95
96
97
98
99
100
{
    QByteArray ba;
    ba += ' ';
    if (n < KnownRegisters && registerNames[n]) {
        ba += registerNames[n];
    } else {
        ba += '#';
        ba += QByteArray::number(n);
    }
101
102
    ba += '=';
    ba += hexxNumber(value);
103
104
105
    return ba;
}

106
107
108
109
110
111
112
113
static void appendRegister(QByteArray *ba, uint regno, uint value)
{
    ba->append(hexNumber(regno, 2));
    ba->append(':');
    ba->append(hexNumber(swapEndian(value), 8));
    ba->append(';');
}

114
115
116
117
118
119
120
121
122
123
124
125
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
//
///////////////////////////////////////////////////////////////////////////

126
127
128
MemoryRange::MemoryRange(uint f, uint t)
    : from(f), to(t)
{
129
    QTC_ASSERT(f <= t, qDebug() << "F: " << f << " T: " << t);
130
131
}

132
133
134
bool MemoryRange::intersects(const MemoryRange &other) const
{
    Q_UNUSED(other);
135
    QTC_ASSERT(false, /**/);
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
    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;
hjk's avatar
hjk committed
172
    registerValid = false;
173
    wantedMemory = MemoryRange();
174
175
    lineFromAddress = 0;
    lineToAddress = 0;
176
177
178
179
}

void Snapshot::insertMemory(const MemoryRange &range, const QByteArray &ba)
{
180
    QTC_ASSERT(range.size() == uint(ba.size()),
181
        qDebug() << "RANGE: " << range << " BA SIZE: " << ba.size(); return);
182

183
184
185
186
187
188
189
190
191
    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);
192
            const MemoryRange res(it.key().from, range.to);
193
            memory.remove(it.key());
194
            MEMORY_DEBUG(" TO(1)  " << res);
195
            insertMemory(res, data);
196
197
198
199
200
201
            return;
        }
        if (it.key().from == range.to) {
            MEMORY_DEBUG("COMBINING " << range << " AND " << it.key());
            QByteArray data = ba;
            data.append(*it);
202
            const MemoryRange res(range.from, it.key().to);
203
            memory.remove(it.key());
204
            MEMORY_DEBUG(" TO(2)  " << res);
205
            insertMemory(res, data);
206
207
208
209
210
211
212
            return;
        }
    }

    // Not combinable, add chunk.
    memory.insert(range, ba);
}
213

214
215
216
217
218
///////////////////////////////////////////////////////////////////////////
//
// TrkGdbAdapter
//
///////////////////////////////////////////////////////////////////////////
219

hjk's avatar
hjk committed
220
221
TrkGdbAdapter::TrkGdbAdapter(GdbEngine *engine, const TrkOptionsPtr &options) :
    AbstractGdbAdapter(engine),
222
    m_options(options),
223
    m_overrideTrkDeviceType(-1),
224
    m_running(false),
225
    m_trkDevice(new trk::TrkDevice),
226
    m_gdbAckMode(true),
hjk's avatar
hjk committed
227
    m_verbose(0)
228
{
hjk's avatar
hjk committed
229
    m_bufferedMemoryRead = true;
230
231
    // Disable buffering if gdb's dcache is used.
    m_bufferedMemoryRead = false;
hjk's avatar
hjk committed
232

hjk's avatar
hjk committed
233
234
    m_gdbServer = 0;
    m_gdbConnection = 0;
hjk's avatar
hjk committed
235
    m_snapshot.reset();
dt's avatar
dt committed
236
#ifdef Q_OS_WIN
237
    const DWORD portOffset = GetCurrentProcessId() % 100;
dt's avatar
dt committed
238
#else
239
    const uid_t portOffset = getuid();
dt's avatar
dt committed
240
#endif
241
    m_gdbServerName = _("127.0.0.1:%1").arg(2222 + portOffset);
242

243
    connect(m_trkDevice.data(), SIGNAL(messageReceived(trk::TrkResult)),
hjk's avatar
hjk committed
244
        this, SLOT(handleTrkResult(trk::TrkResult)));
245
    connect(m_trkDevice.data(), SIGNAL(error(QString)),
hjk's avatar
hjk committed
246
247
        this, SLOT(handleTrkError(QString)));

248
    setVerbose(theDebuggerBoolSetting(VerboseLog));
249
    m_trkDevice->setSerialFrame(effectiveTrkDeviceType() != TrkOptions::BlueTooth);
250

251
    connect(m_trkDevice.data(), SIGNAL(logMessage(QString)),
252
        this, SLOT(trkLogMessage(QString)));
253
254
    connect(theDebuggerAction(VerboseLog), SIGNAL(valueChanged(QVariant)),
        this, SLOT(setVerbose(QVariant)));
255
256
}

hjk's avatar
hjk committed
257
TrkGdbAdapter::~TrkGdbAdapter()
258
{
Friedemann Kleint's avatar
Friedemann Kleint committed
259
    cleanup();
hjk's avatar
hjk committed
260
    logMessage("Shutting down.\n");
261
262
}

263
264
265
266
267
268
269
270
271
272
273
void TrkGdbAdapter::setVerbose(const QVariant &value)
{
    setVerbose(value.toInt());
}

void TrkGdbAdapter::setVerbose(int verbose)
{
    m_verbose = verbose;
    m_trkDevice->setVerbose(m_verbose);
}

274
275
276
277
278
279
280
281
282
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;
}

283
284
285
286
287
288
289
int TrkGdbAdapter::effectiveTrkDeviceType() const
{
    if (m_overrideTrkDeviceType >= 0)
        return m_overrideTrkDeviceType;
    return m_options->mode;
}

hjk's avatar
hjk committed
290
void TrkGdbAdapter::trkLogMessage(const QString &msg)
291
292
293
294
{
    logMessage("TRK " + msg);
}

hjk's avatar
hjk committed
295
void TrkGdbAdapter::setGdbServerName(const QString &name)
296
297
298
299
{
    m_gdbServerName = name;
}

hjk's avatar
hjk committed
300
QString TrkGdbAdapter::gdbServerIP() const
301
302
303
304
305
306
307
{
    int pos = m_gdbServerName.indexOf(':');
    if (pos == -1)
        return m_gdbServerName;
    return m_gdbServerName.left(pos);
}

hjk's avatar
hjk committed
308
uint TrkGdbAdapter::gdbServerPort() const
309
310
311
312
313
314
315
{
    int pos = m_gdbServerName.indexOf(':');
    if (pos == -1)
        return 0;
    return m_gdbServerName.mid(pos + 1).toUInt();
}

hjk's avatar
hjk committed
316
QByteArray TrkGdbAdapter::trkContinueMessage()
317
318
319
320
321
322
323
{
    QByteArray ba;
    appendInt(&ba, m_session.pid);
    appendInt(&ba, m_session.tid);
    return ba;
}

324
QByteArray TrkGdbAdapter::trkReadRegistersMessage()
325
326
327
328
329
330
331
332
333
334
{
    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;
}

335
   QByteArray TrkGdbAdapter::trkWriteRegisterMessage(trk::byte reg, uint value)
336
337
338
339
340
341
342
343
344
345
346
{
    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;
}

347
QByteArray TrkGdbAdapter::trkReadMemoryMessage(uint from, uint len)
348
349
{
    QByteArray ba;
350
    ba.reserve(11);
351
352
    appendByte(&ba, 0x08); // Options, FIXME: why?
    appendShort(&ba, len);
353
    appendInt(&ba, from);
354
355
356
357
358
    appendInt(&ba, m_session.pid);
    appendInt(&ba, m_session.tid);
    return ba;
}

359
360
361
362
363
QByteArray TrkGdbAdapter::trkReadMemoryMessage(const MemoryRange &range)
{
    return trkReadMemoryMessage(range.from, range.size());
}

hjk's avatar
hjk committed
364
365
366
367
368
369
370
371
372
373
374
375
376
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;
}

377
QByteArray TrkGdbAdapter::trkStepRangeMessage(trk::byte option)
hjk's avatar
hjk committed
378
379
{
    QByteArray ba;
hjk's avatar
hjk committed
380
    ba.reserve(17);
hjk's avatar
hjk committed
381
    appendByte(&ba, option);
382
    //qDebug() << "STEP ON " << hexxNumber(m_snapshot.registers[RegisterPC]);
383
384
385
386
    uint from = m_snapshot.lineFromAddress;
    uint to = m_snapshot.lineToAddress;
    uint pc = m_snapshot.registers[RegisterPC];
    if (from <= pc && pc <= to) {
387
388
389
        to = qMax(to - 4, from);
        debugMessage("STEP IN " + hexxNumber(from) + " " + hexxNumber(to)
            + " INSTEAD OF " + hexxNumber(pc));
390
391
392
393
394
395
    } else {
        from = pc;
        to = pc;
    }
    appendInt(&ba, from); // Start address
    appendInt(&ba, to); // End address
hjk's avatar
hjk committed
396
397
398
399
400
    appendInt(&ba, m_session.pid);
    appendInt(&ba, m_session.tid);
    return ba;
}

401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
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;
}

423
424
425
426
427
428
429
430
431
432
433
void TrkGdbAdapter::emitDelayedInferiorStartFailed(const QString &msg)
{
    m_adapterFailMessage = msg;
    QTimer::singleShot(0, this, SLOT(slotEmitDelayedInferiorStartFailed()));
}

void TrkGdbAdapter::slotEmitDelayedInferiorStartFailed()
{
    emit inferiorStartFailed(m_adapterFailMessage);
}

434

hjk's avatar
hjk committed
435
void TrkGdbAdapter::logMessage(const QString &msg)
436
{
437
438
    if (m_verbose)
        debugMessage("TRK LOG: " + msg);
439
440
441
442
443
}

//
// Gdb
//
hjk's avatar
hjk committed
444
void TrkGdbAdapter::handleGdbConnection()
445
446
{
    logMessage("HANDLING GDB CONNECTION");
hjk's avatar
hjk committed
447
448
449
    QTC_ASSERT(m_gdbConnection == 0, /**/);
    m_gdbConnection = m_gdbServer->nextPendingConnection();
    QTC_ASSERT(m_gdbConnection, return);
450
451
452
453
454
455
456
457
458
459
460
    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;
}

hjk's avatar
hjk committed
461
void TrkGdbAdapter::readGdbServerCommand()
462
{
hjk's avatar
hjk committed
463
    QTC_ASSERT(m_gdbConnection, return);
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
    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");
483
484
            // This seems too harsh.
            //emit adapterCrashed("Communication problem encountered.");
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
            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));
516
        trk::byte sum = 0;
517
518
519
520
521
522
523
524
525
526
527
528
529
530
        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);
    }
}

hjk's avatar
hjk committed
531
bool TrkGdbAdapter::sendGdbServerPacket(const QByteArray &packet, bool doFlush)
532
533
{
    if (!m_gdbConnection) {
534
535
        logMessage(_("Cannot write to gdb: No connection (%1)")
            .arg(_(packet)));
536
537
538
        return false;
    }
    if (m_gdbConnection->state() != QAbstractSocket::ConnectedState) {
539
540
        logMessage(_("Cannot write to gdb: Not connected (%1)")
            .arg(_(packet)));
541
542
543
        return false;
    }
    if (m_gdbConnection->write(packet) == -1) {
544
545
        logMessage(_("Cannot write to gdb: %1 (%2)")
            .arg(m_gdbConnection->errorString()).arg(_(packet)));
546
547
548
549
550
551
552
        return false;
    }
    if (doFlush)
        m_gdbConnection->flush();
    return true;
}

hjk's avatar
hjk committed
553
void TrkGdbAdapter::sendGdbServerAck()
554
555
556
{
    if (!m_gdbAckMode)
        return;
hjk's avatar
hjk committed
557
    logMessage("gdb: <- +");
558
    sendGdbServerPacket(QByteArray(1, '+'), false);
559
560
}

hjk's avatar
hjk committed
561
void TrkGdbAdapter::sendGdbServerMessage(const QByteArray &msg, const QByteArray &logNote)
562
{
563
    trk::byte sum = 0;
564
565
566
567
568
569
570
571
572
    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;
573
    packet.append('$');
574
575
576
577
578
579
580
581
    packet.append(msg);
    packet.append('#');
    packet.append(checkSum);
    int pad = qMax(0, 24 - packet.size());
    logMessage("gdb: <- " + packet + QByteArray(pad, ' ') + logNote);
    sendGdbServerPacket(packet, true);
}

hjk's avatar
hjk committed
582
void TrkGdbAdapter::sendGdbServerMessageAfterTrkResponse(const QByteArray &msg,
583
584
585
586
587
588
    const QByteArray &logNote)
{
    QByteArray ba = msg + char(1) + logNote;
    sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, TrkCB(reportToGdb), "", ba); // Answer gdb
}

hjk's avatar
hjk committed
589
void TrkGdbAdapter::reportToGdb(const TrkResult &result)
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
{
    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);
}

hjk's avatar
hjk committed
605
QByteArray TrkGdbAdapter::trkBreakpointMessage(uint addr, uint len, bool armMode)
606
607
608
609
610
611
612
613
614
615
616
617
{
    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;
}

hjk's avatar
hjk committed
618
void TrkGdbAdapter::handleGdbServerCommand(const QByteArray &cmd)
619
620
621
622
623
624
625
626
627
628
{
    // 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");
    }

629
    else if (cmd.startsWith('?')) {
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
        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);
    }

655
    else if (cmd.startsWith('C')) {
656
657
658
659
660
        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;
661
        uint signalNumber = cmd.mid(1).toUInt(&ok, 16);
662
663
664
        QByteArray ba;
        appendInt(&ba, m_session.pid);
        appendInt(&ba, m_session.tid);
hjk's avatar
hjk committed
665
        sendTrkMessage(0x18, TrkCB(handleSignalContinue), ba, signalNumber);
666
667
    }

668
    else if (cmd.startsWith('D')) {
669
670
671
672
673
674
        sendGdbServerAck();
        sendGdbServerMessage("OK", "shutting down");
    }

    else if (cmd == "g") {
        // Read general registers.
hjk's avatar
hjk committed
675
        if (m_snapshot.registerValid) {
676
            //qDebug() << "Using cached register contents";
hjk's avatar
hjk committed
677
678
679
680
            logMessage(msgGdbPacket(QLatin1String("Read registers")));
            sendGdbServerAck();
            reportRegisters();
        } else {
681
682
            //qDebug() << "Fetching register contents";
            sendGdbServerAck();
hjk's avatar
hjk committed
683
684
685
686
            sendTrkMessage(0x12,
                TrkCB(handleAndReportReadRegisters),
                trkReadRegistersMessage());
        }
687
688
    }

689
690
691
692
693
694
695
696
697
    else if (cmd == "gg") {
        // Force re-reading general registers for debugging purpose.
        sendGdbServerAck();
        m_snapshot.registerValid = false;
        sendTrkMessage(0x12,
            TrkCB(handleAndReportReadRegisters),
            trkReadRegistersMessage());
    }

698
699
700
701
702
703
704
705
706
707
708
709
    else if (cmd.startsWith("sal")) {
        // Receive address range for current line for future use when stepping.
        sendGdbServerAck();
        int pos = cmd.indexOf(',');
        //qDebug() << "SAL: " << cmd << cmd.mid(3, pos - 3) << cmd.mid(pos + 1);
        m_snapshot.lineFromAddress = cmd.mid(3, pos - 3).toUInt(0, 16);
        m_snapshot.lineToAddress = cmd.mid(pos + 1).toUInt(0, 16);
        //qDebug() << "SAL: " << hexxNumber(m_snapshot.lineFromAddress)
        //    << hexxNumber(m_snapshot.lineToAddress);
        sendGdbServerMessage("", "Stepping range received");
    }

710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
    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();
725
        m_session.currentThread = cmd.mid(2).toUInt(0, 16);
726
727
728
729
        sendGdbServerMessage("OK", "Set current thread "
            + QByteArray::number(m_session.currentThread));
    }

hjk's avatar
hjk committed
730
731
    else if (cmd == "k" || cmd.startsWith("vKill")) {
        // Kill inferior process
732
        logMessage(msgGdbPacket(QLatin1String("kill")));
hjk's avatar
hjk committed
733
        sendTrkMessage(0x41, TrkCB(handleDeleteProcess),
734
            trkDeleteProcessMessage(), "Delete process");
735
736
    }

737
    else if (cmd.startsWith('m')) {
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
        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) {
755
            readMemory(addr, len, m_bufferedMemoryRead);
756
757
758
759
        } else {
            sendGdbServerMessage("E20", "Error " + cmd);
        }
    }
760

761
    else if (cmd.startsWith('p')) {
762
763
764
765
766
        logMessage(msgGdbPacket(QLatin1String("read register")));
        // 0xf == current instruction pointer?
        //sendGdbServerMessage("0000", "current IP");
        sendGdbServerAck();
        bool ok = false;
767
        const uint registerNumber = cmd.mid(1).toUInt(&ok, 16);
hjk's avatar
hjk committed
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
        if (m_snapshot.registerValid) {
            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);
            } else if (registerNumber < 16) {
                QByteArray ba;
                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");
            }
785
        } else {
786
            //qDebug() << "Fetching single register";
hjk's avatar
hjk committed
787
788
789
            sendTrkMessage(0x12,
                TrkCB(handleAndReportReadRegister),
                trkReadRegistersMessage(), registerNumber);
790
791
792
        }
    }

793
    else if (cmd.startsWith('P')) {
794
795
796
797
798
799
800
        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;
801
802
        const uint registerNumber = regName.toUInt(&ok, 16);
        const uint value = swapEndian(valueName.toUInt(&ok, 16));
803
804
        // FIXME: Assume all goes well.
        m_snapshot.registers[registerNumber] = value;
805
806
807
808
809
        QByteArray ba = trkWriteRegisterMessage(registerNumber, value);
        sendTrkMessage(0x13, TrkCB(handleWriteRegister), ba, "Write register");
        // Note that App TRK refuses to write registers 13 and 14
    }

810
811
812
813
814
    else if (cmd == "qAttached") {
        //$qAttached#8f
        // 1: attached to an existing process
        // 0: created a new process
        sendGdbServerAck();
815
816
        sendGdbServerMessage(QByteArray(1, '0'), "new process created");
        //sendGdbServerMessage('1', "attached to existing process");
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
        //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();
hjk's avatar
hjk committed
833
834
835
        sendGdbServerMessage(
            "PacketSize=7cf;"
            "QPassSignals+;"
hjk's avatar
hjk committed
836
            "QStartNoAckMode+;"
hjk's avatar
hjk committed
837
838
839
840
841
            "qXfer:libraries:read+;"
            //"qXfer:auxv:read+;"
            "qXfer:features:read+");
    }

842
843
844
845
846
847
    else if (cmd.startsWith("qThreadExtraInfo")) {
        // $qThreadExtraInfo,1f9#55
        sendGdbServerAck();
        sendGdbServerMessage(QByteArray("Nothing special").toHex());
    }

hjk's avatar
hjk committed
848
    else if (cmd == "qfDllInfo") {
849
850
851
852
853
854
        // 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();
855
        if (!m_session.libraries.isEmpty()) {
856
            QByteArray response(1, 'm');
857
858
859
860
861
862
863
864
865
            // 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);
            }
Tobias Hunger's avatar
Tobias Hunger committed
866
            sendGdbServerMessage(response, "library information transferred");
867
        } else {
868
            sendGdbServerMessage(QByteArray(1, 'l'), "library information transfer finished");
869
870
871
872
873
        }
    }

    else if (cmd == "qsDllInfo") {
        // That's a following query package
hjk's avatar
hjk committed
874
        sendGdbServerAck();
875
        sendGdbServerMessage(QByteArray(1, 'l'), "library information transfer finished");
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
    }

    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
hjk's avatar
hjk committed
898
899
            sendGdbServerMessage("qSymbol:" + QByteArray("_Z7E32Mainv").toHex(),
                "ask for more");
900
901
902
903
904
    }

    else if (cmd.startsWith("qXfer:features:read:target.xml:")) {
        //  $qXfer:features:read:target.xml:0,7ca#46...Ack
        sendGdbServerAck();
hjk's avatar
hjk committed
905
906
907
908
909
910
911
912
913
        //sendGdbServerMessage("l<target><architecture>symbianelf</architecture></target>");
        sendGdbServerMessage("l<target><architecture>arm</architecture></target>");
        //sendGdbServerMessage("l<target><architecture>arm-none-symbianelf</architecture></target>");
    }

    else if (cmd == "qfThreadInfo") {
        // That's the _first_ query package.
        sendGdbServerAck();
        if (!m_session.threads.isEmpty()) {
914
            QByteArray response(1, 'm');
hjk's avatar
hjk committed
915
916
917
            // FIXME: Limit packet length by using qsThreadInfo packages?
            qDebug()  << "CURRENT THREAD: " << m_session.tid;
            response += hexNumber(m_session.tid);
Tobias Hunger's avatar
Tobias Hunger committed
918
            sendGdbServerMessage(response, "thread information transferred");
hjk's avatar
hjk committed
919
        } else {
920
            sendGdbServerMessage(QByteArray(1, 'l'), "thread information transfer finished");
hjk's avatar
hjk committed
921
922
923
924
925
926
        }
    }

    else if (cmd == "qsThreadInfo") {
        // That's a following query package
        sendGdbServerAck();
927
        sendGdbServerMessage(QByteArray(1, 'l'), "thread information transfer finished");
928
929
    }

930
    else if (cmd.startsWith("qXfer:libraries:read")) {
931
        //qDebug() << "COMMAND: " << cmd;
932
        sendGdbServerAck();
hjk's avatar
hjk committed
933
934
935
936
        QByteArray response = "l<library-list>";
        for (int i = 0; i != m_session.libraries.size(); ++i) {
            const Library &lib = m_session.libraries.at(i);
            response += "<library name=\"" + lib.name + "\">";
937
938
939
940
            //response += "<segment address=\"0x" + hexNumber(lib.codeseg) + "\"/>";
            response += "<section address=\"0x" + hexNumber(lib.codeseg) + "\"/>";
            response += "<section address=\"0x" + hexNumber(lib.dataseg) + "\"/>";
            response += "<section address=\"0x" + hexNumber(lib.dataseg) + "\"/>";
hjk's avatar
hjk committed
941
942
943
            response += "</library>";
        }
        response += "</library-list>";
Tobias Hunger's avatar
Tobias Hunger committed
944
        sendGdbServerMessage(response, "library information transferred");
945
946
    }

947
948
    else if (cmd == "QStartNoAckMode") {
        //$qSupported#37
hjk's avatar
hjk committed
949
        logMessage("Handling 'QStartNoAckMode'");
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
        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();
968
        //m_snapshot.reset();
969
        m_running = true;
hjk's avatar
hjk committed
970
971
        QByteArray ba = trkStepRangeMessage(0x01);  // options "step into"
        sendTrkMessage(0x19, TrkCB(handleStepInto), ba, "Step range");
972
973
    }

hjk's avatar
hjk committed
974
975
976
977
978
979
980
    else if (cmd.startsWith('T')) {
        // FIXME: check whether thread is alive
        sendGdbServerAck();
        sendGdbServerMessage("OK"); // pretend all is well
        //sendGdbServerMessage("E nn");
    }

981
982
983
984
    else if (cmd == "vCont?") {
        // actions supported by the vCont packet
        sendGdbServerAck();
        //sendGdbServerMessage("OK"); // we don't support vCont.
985
        sendGdbServerMessage("vCont;c;C;s;S");
986
987
988
989
990
    }

    else if (cmd == "vCont;c") {
        // vCont[;action[:thread-id]]...'
        sendGdbServerAck();
991
        //m_snapshot.reset();
992
993
994
995
996
997
        m_running = true;
        sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE");
    }

    else if (cmd.startsWith("Z0,") || cmd.startsWith("Z1,")) {
        // Insert breakpoint
hjk's avatar
hjk committed
998
        sendGdbServerAck();
999
1000
        logMessage(msgGdbPacket(QLatin1String("Insert breakpoint")));
        // $Z0,786a4ccc,4#99
For faster browsing, not all history is shown. View entire blame