trkgdbadapter.cpp 73.1 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 "stackhandler.h"
40
#include "debuggeractions.h"
41
#include "debuggerstringutils.h"
hjk's avatar
hjk committed
42
#ifndef STANDALONE_RUNNER
43
#include "gdbengine.h"
hjk's avatar
hjk committed
44
#endif
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
45
46
47
48
49
50

#include <utils/qtcassert.h>

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

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

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

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

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

using namespace trk;

74
75
76
namespace Debugger {
namespace Internal {

77
78
enum { KnownRegisters = RegisterPSGdb + 1};

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

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

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

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

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

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

133
134
135
bool MemoryRange::intersects(const MemoryRange &other) const
{
    Q_UNUSED(other);
136
    QTC_ASSERT(false, /**/);
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
    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);
}

162
163
164
165
166
bool MemoryRange::isReadOnly() const
{
    return from >= 0x70000000 && to < 0x80000000;
}

167
168
169
170
171
172
173
174
///////////////////////////////////////////////////////////////////////////
//
// Snapshot
//
///////////////////////////////////////////////////////////////////////////

void Snapshot::reset()
{
175
176
177
178
179
180
181
    for (Memory::Iterator it = memory.begin(); it != memory.end(); ++it) {
        if (it.key().isReadOnly()) {
            MEMORY_DEBUG("KEEPING READ-ONLY RANGE" << it.key());
        } else {
            it = memory.erase(it);
        }
    }
182
183
    for (int i = 0; i < RegisterCount; ++i)
        registers[i] = 0;
hjk's avatar
hjk committed
184
    registerValid = false;
185
    wantedMemory = MemoryRange();
186
187
    lineFromAddress = 0;
    lineToAddress = 0;
188
189
}

190
191
192
193
194
195
void Snapshot::fullReset()
{
    memory.clear();
    reset();
}

196
197
void Snapshot::insertMemory(const MemoryRange &range, const QByteArray &ba)
{
198
    QTC_ASSERT(range.size() == uint(ba.size()),
199
        qDebug() << "RANGE: " << range << " BA SIZE: " << ba.size(); return);
200

201
202
203
204
205
206
207
208
209
    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);
210
            const MemoryRange res(it.key().from, range.to);
211
            memory.remove(it.key());
212
            MEMORY_DEBUG(" TO(1)  " << res);
213
            insertMemory(res, data);
214
215
216
217
218
219
            return;
        }
        if (it.key().from == range.to) {
            MEMORY_DEBUG("COMBINING " << range << " AND " << it.key());
            QByteArray data = ba;
            data.append(*it);
220
            const MemoryRange res(range.from, it.key().to);
221
            memory.remove(it.key());
222
            MEMORY_DEBUG(" TO(2)  " << res);
223
            insertMemory(res, data);
224
225
226
227
228
229
230
            return;
        }
    }

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

232
233
234
235
236
///////////////////////////////////////////////////////////////////////////
//
// TrkGdbAdapter
//
///////////////////////////////////////////////////////////////////////////
237

hjk's avatar
hjk committed
238
239
TrkGdbAdapter::TrkGdbAdapter(GdbEngine *engine, const TrkOptionsPtr &options) :
    AbstractGdbAdapter(engine),
240
    m_options(options),
241
    m_overrideTrkDeviceType(-1),
242
    m_running(false),
243
    m_trkDevice(new trk::TrkDevice),
244
    m_gdbAckMode(true),
hjk's avatar
hjk committed
245
    m_verbose(0)
246
{
hjk's avatar
hjk committed
247
    m_bufferedMemoryRead = true;
248
249
    // Disable buffering if gdb's dcache is used.
    m_bufferedMemoryRead = false;
hjk's avatar
hjk committed
250

hjk's avatar
hjk committed
251
252
    m_gdbServer = 0;
    m_gdbConnection = 0;
hjk's avatar
hjk committed
253
    m_snapshot.reset();
dt's avatar
dt committed
254
#ifdef Q_OS_WIN
255
    const DWORD portOffset = GetCurrentProcessId() % 100;
dt's avatar
dt committed
256
#else
257
    const uid_t portOffset = getuid();
dt's avatar
dt committed
258
#endif
259
    m_gdbServerName = _("127.0.0.1:%1").arg(2222 + portOffset);
260

261
    connect(m_trkDevice.data(), SIGNAL(messageReceived(trk::TrkResult)),
hjk's avatar
hjk committed
262
        this, SLOT(handleTrkResult(trk::TrkResult)));
263
    connect(m_trkDevice.data(), SIGNAL(error(QString)),
hjk's avatar
hjk committed
264
265
        this, SLOT(handleTrkError(QString)));

266
    setVerbose(theDebuggerBoolSetting(VerboseLog));
267
    m_trkDevice->setSerialFrame(effectiveTrkDeviceType() != TrkOptions::BlueTooth);
268

269
    connect(m_trkDevice.data(), SIGNAL(logMessage(QString)),
270
        this, SLOT(trkLogMessage(QString)));
271
272
    connect(theDebuggerAction(VerboseLog), SIGNAL(valueChanged(QVariant)),
        this, SLOT(setVerbose(QVariant)));
273
274
}

hjk's avatar
hjk committed
275
TrkGdbAdapter::~TrkGdbAdapter()
276
{
Friedemann Kleint's avatar
Friedemann Kleint committed
277
    cleanup();
hjk's avatar
hjk committed
278
    logMessage("Shutting down.\n");
279
280
}

281
282
283
284
285
286
287
288
289
290
291
void TrkGdbAdapter::setVerbose(const QVariant &value)
{
    setVerbose(value.toInt());
}

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

292
293
294
295
296
297
298
299
300
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;
}

301
302
303
304
305
306
307
int TrkGdbAdapter::effectiveTrkDeviceType() const
{
    if (m_overrideTrkDeviceType >= 0)
        return m_overrideTrkDeviceType;
    return m_options->mode;
}

hjk's avatar
hjk committed
308
void TrkGdbAdapter::trkLogMessage(const QString &msg)
309
310
311
312
{
    logMessage("TRK " + msg);
}

hjk's avatar
hjk committed
313
void TrkGdbAdapter::setGdbServerName(const QString &name)
314
315
316
317
{
    m_gdbServerName = name;
}

hjk's avatar
hjk committed
318
QString TrkGdbAdapter::gdbServerIP() const
319
320
321
322
323
324
325
{
    int pos = m_gdbServerName.indexOf(':');
    if (pos == -1)
        return m_gdbServerName;
    return m_gdbServerName.left(pos);
}

hjk's avatar
hjk committed
326
uint TrkGdbAdapter::gdbServerPort() const
327
328
329
330
331
332
333
{
    int pos = m_gdbServerName.indexOf(':');
    if (pos == -1)
        return 0;
    return m_gdbServerName.mid(pos + 1).toUInt();
}

hjk's avatar
hjk committed
334
QByteArray TrkGdbAdapter::trkContinueMessage()
335
336
337
338
339
340
341
{
    QByteArray ba;
    appendInt(&ba, m_session.pid);
    appendInt(&ba, m_session.tid);
    return ba;
}

342
QByteArray TrkGdbAdapter::trkReadRegistersMessage()
343
344
345
346
347
348
349
350
351
352
{
    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;
}

353
   QByteArray TrkGdbAdapter::trkWriteRegisterMessage(trk::byte reg, uint value)
354
355
356
357
358
359
360
361
362
363
364
{
    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;
}

365
QByteArray TrkGdbAdapter::trkReadMemoryMessage(uint from, uint len)
366
367
{
    QByteArray ba;
368
    ba.reserve(11);
369
370
    appendByte(&ba, 0x08); // Options, FIXME: why?
    appendShort(&ba, len);
371
    appendInt(&ba, from);
372
373
374
375
376
    appendInt(&ba, m_session.pid);
    appendInt(&ba, m_session.tid);
    return ba;
}

377
378
379
380
381
QByteArray TrkGdbAdapter::trkReadMemoryMessage(const MemoryRange &range)
{
    return trkReadMemoryMessage(range.from, range.size());
}

hjk's avatar
hjk committed
382
383
384
385
386
387
388
389
390
391
392
393
394
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;
}

395
QByteArray TrkGdbAdapter::trkStepRangeMessage()
hjk's avatar
hjk committed
396
{
397
    //qDebug() << "STEP ON " << hexxNumber(m_snapshot.registers[RegisterPC]);
398
399
400
    uint from = m_snapshot.lineFromAddress;
    uint to = m_snapshot.lineToAddress;
    uint pc = m_snapshot.registers[RegisterPC];
401
    trk::byte option = 0x01; // Step into.
402
403
    if (m_snapshot.stepOver)
        option = 0x11;  // Step over.
404
    if (from <= pc && pc <= to) {
405
        //to = qMax(to - 4, from);
406
407
        debugMessage("STEP IN " + hexxNumber(from) + " " + hexxNumber(to)
            + " INSTEAD OF " + hexxNumber(pc));
408
409
410
411
    } else {
        from = pc;
        to = pc;
    }
412

413
    //qDebug() << "USING" << int(option) << (option == 1 ? " INTO " : " OVER");
414
415
416
    QByteArray ba;
    ba.reserve(17);
    appendByte(&ba, option);
417
418
    appendInt(&ba, from); // Start address
    appendInt(&ba, to); // End address
hjk's avatar
hjk committed
419
420
421
422
423
    appendInt(&ba, m_session.pid);
    appendInt(&ba, m_session.tid);
    return ba;
}

424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
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;
}

446
447
448
449
450
451
452
453
454
455
456
void TrkGdbAdapter::emitDelayedInferiorStartFailed(const QString &msg)
{
    m_adapterFailMessage = msg;
    QTimer::singleShot(0, this, SLOT(slotEmitDelayedInferiorStartFailed()));
}

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

457

hjk's avatar
hjk committed
458
void TrkGdbAdapter::logMessage(const QString &msg)
459
{
460
461
    if (m_verbose)
        debugMessage("TRK LOG: " + msg);
462
463
464
465
466
}

//
// Gdb
//
hjk's avatar
hjk committed
467
void TrkGdbAdapter::handleGdbConnection()
468
469
{
    logMessage("HANDLING GDB CONNECTION");
hjk's avatar
hjk committed
470
471
472
    QTC_ASSERT(m_gdbConnection == 0, /**/);
    m_gdbConnection = m_gdbServer->nextPendingConnection();
    QTC_ASSERT(m_gdbConnection, return);
473
474
475
476
477
478
479
480
481
482
483
    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
484
void TrkGdbAdapter::readGdbServerCommand()
485
{
hjk's avatar
hjk committed
486
    QTC_ASSERT(m_gdbConnection, return);
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
    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");
506
507
            // This seems too harsh.
            //emit adapterCrashed("Communication problem encountered.");
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
            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));
539
        trk::byte sum = 0;
540
541
542
543
544
545
546
547
548
549
550
551
552
553
        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
554
bool TrkGdbAdapter::sendGdbServerPacket(const QByteArray &packet, bool doFlush)
555
556
{
    if (!m_gdbConnection) {
557
558
        logMessage(_("Cannot write to gdb: No connection (%1)")
            .arg(_(packet)));
559
560
561
        return false;
    }
    if (m_gdbConnection->state() != QAbstractSocket::ConnectedState) {
562
563
        logMessage(_("Cannot write to gdb: Not connected (%1)")
            .arg(_(packet)));
564
565
566
        return false;
    }
    if (m_gdbConnection->write(packet) == -1) {
567
568
        logMessage(_("Cannot write to gdb: %1 (%2)")
            .arg(m_gdbConnection->errorString()).arg(_(packet)));
569
570
571
572
573
574
575
        return false;
    }
    if (doFlush)
        m_gdbConnection->flush();
    return true;
}

hjk's avatar
hjk committed
576
void TrkGdbAdapter::sendGdbServerAck()
577
578
579
{
    if (!m_gdbAckMode)
        return;
hjk's avatar
hjk committed
580
    logMessage("gdb: <- +");
581
    sendGdbServerPacket(QByteArray(1, '+'), false);
582
583
}

hjk's avatar
hjk committed
584
void TrkGdbAdapter::sendGdbServerMessage(const QByteArray &msg, const QByteArray &logNote)
585
{
586
    trk::byte sum = 0;
587
588
589
590
591
592
593
594
595
    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;
596
    packet.append('$');
597
598
599
600
601
602
603
604
    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
605
void TrkGdbAdapter::sendGdbServerMessageAfterTrkResponse(const QByteArray &msg,
606
607
608
609
610
611
    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
612
void TrkGdbAdapter::reportToGdb(const TrkResult &result)
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
{
    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
628
QByteArray TrkGdbAdapter::trkBreakpointMessage(uint addr, uint len, bool armMode)
629
630
631
632
633
634
635
636
637
638
639
640
{
    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
641
void TrkGdbAdapter::handleGdbServerCommand(const QByteArray &cmd)
642
643
644
645
646
647
648
649
650
651
{
    // 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");
    }

652
    else if (cmd.startsWith('?')) {
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
        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);
    }

678
    else if (cmd.startsWith('C')) {
679
680
681
682
683
        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;
684
        uint signalNumber = cmd.mid(1).toUInt(&ok, 16);
685
686
687
        QByteArray ba;
        appendInt(&ba, m_session.pid);
        appendInt(&ba, m_session.tid);
hjk's avatar
hjk committed
688
        sendTrkMessage(0x18, TrkCB(handleSignalContinue), ba, signalNumber);
689
690
    }

691
    else if (cmd.startsWith('D')) {
692
693
694
695
696
697
        sendGdbServerAck();
        sendGdbServerMessage("OK", "shutting down");
    }

    else if (cmd == "g") {
        // Read general registers.
hjk's avatar
hjk committed
698
        if (m_snapshot.registerValid) {
699
            //qDebug() << "Using cached register contents";
hjk's avatar
hjk committed
700
701
702
703
            logMessage(msgGdbPacket(QLatin1String("Read registers")));
            sendGdbServerAck();
            reportRegisters();
        } else {
704
705
            //qDebug() << "Fetching register contents";
            sendGdbServerAck();
hjk's avatar
hjk committed
706
707
708
709
            sendTrkMessage(0x12,
                TrkCB(handleAndReportReadRegisters),
                trkReadRegistersMessage());
        }
710
711
    }

712
713
714
715
716
717
718
719
720
    else if (cmd == "gg") {
        // Force re-reading general registers for debugging purpose.
        sendGdbServerAck();
        m_snapshot.registerValid = false;
        sendTrkMessage(0x12,
            TrkCB(handleAndReportReadRegisters),
            trkReadRegistersMessage());
    }

721
    else if (cmd.startsWith("salstep,")) {
722
723
        // Receive address range for current line for future use when stepping.
        sendGdbServerAck();
724
        int pos = cmd.indexOf(',', 8);
725
        m_snapshot.lineFromAddress = cmd.mid(8, pos - 8).toUInt(0, 16);
726
        m_snapshot.lineToAddress = cmd.mid(pos + 1).toUInt(0, 16);
727
728
729
730
        m_snapshot.stepOver = false;
        sendGdbServerMessage("", "Stepping range received for Step Into");
    }

731
    else if (cmd.startsWith("salnext,")) {
732
733
        // Receive address range for current line for future use when stepping.
        sendGdbServerAck();
734
        int pos = cmd.indexOf(',', 8);
735
736
737
738
        m_snapshot.lineFromAddress = cmd.mid(8, pos - 8).toUInt(0, 16);
        m_snapshot.lineToAddress = cmd.mid(pos + 1).toUInt(0, 16);
        m_snapshot.stepOver = true;
        sendGdbServerMessage("", "Stepping range received for Step Over");
739
740
    }

741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
    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();
756
        m_session.currentThread = cmd.mid(2).toUInt(0, 16);
757
758
759
760
        sendGdbServerMessage("OK", "Set current thread "
            + QByteArray::number(m_session.currentThread));
    }

hjk's avatar
hjk committed
761
762
    else if (cmd == "k" || cmd.startsWith("vKill")) {
        // Kill inferior process
763
        logMessage(msgGdbPacket(QLatin1String("kill")));
hjk's avatar
hjk committed
764
        sendTrkMessage(0x41, TrkCB(handleDeleteProcess),
765
            trkDeleteProcessMessage(), "Delete process");
766
767
    }

768
    else if (cmd.startsWith('m')) {
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
        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) {
786
            readMemory(addr, len, m_bufferedMemoryRead);
787
788
789
790
        } else {
            sendGdbServerMessage("E20", "Error " + cmd);
        }
    }
791

792
    else if (cmd.startsWith('p')) {
793
794
795
796
797
        logMessage(msgGdbPacket(QLatin1String("read register")));
        // 0xf == current instruction pointer?
        //sendGdbServerMessage("0000", "current IP");
        sendGdbServerAck();
        bool ok = false;
798
        const uint registerNumber = cmd.mid(1).toUInt(&ok, 16);
hjk's avatar
hjk committed
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
        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");
            }
816
        } else {
817
            //qDebug() << "Fetching single register";
hjk's avatar
hjk committed
818
819
820
            sendTrkMessage(0x12,
                TrkCB(handleAndReportReadRegister),
                trkReadRegistersMessage(), registerNumber);
821
822
823
        }
    }

824
    else if (cmd.startsWith('P')) {
825
826
827
828
829
830
831
        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;
832
833
        const uint registerNumber = regName.toUInt(&ok, 16);
        const uint value = swapEndian(valueName.toUInt(&ok, 16));
834
835
        // FIXME: Assume all goes well.
        m_snapshot.registers[registerNumber] = value;
836
837
838
839
840
        QByteArray ba = trkWriteRegisterMessage(registerNumber, value);
        sendTrkMessage(0x13, TrkCB(handleWriteRegister), ba, "Write register");
        // Note that App TRK refuses to write registers 13 and 14
    }

841
842
843
844
845
    else if (cmd == "qAttached") {
        //$qAttached#8f
        // 1: attached to an existing process
        // 0: created a new process
        sendGdbServerAck();
846
847
        sendGdbServerMessage(QByteArray(1, '0'), "new process created");
        //sendGdbServerMessage('1', "attached to existing process");
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
        //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
864
865
866
        sendGdbServerMessage(
            "PacketSize=7cf;"
            "QPassSignals+;"
hjk's avatar
hjk committed
867
            "QStartNoAckMode+;"
hjk's avatar
hjk committed
868
869
870
871
872
            "qXfer:libraries:read+;"
            //"qXfer:auxv:read+;"
            "qXfer:features:read+");
    }

873
874
875
876
877
878
    else if (cmd.startsWith("qThreadExtraInfo")) {
        // $qThreadExtraInfo,1f9#55
        sendGdbServerAck();
        sendGdbServerMessage(QByteArray("Nothing special").toHex());
    }

hjk's avatar
hjk committed
879
    else if (cmd == "qfDllInfo") {
880
881
882
883
884
885
        // 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();
886
        if (!m_session.libraries.isEmpty()) {
887
            QByteArray response(1, 'm');
888
889
890
891
892
893
894
895
896
            // 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
897
            sendGdbServerMessage(response, "library information transferred");
898
        } else {
899
            sendGdbServerMessage(QByteArray(1, 'l'), "library information transfer finished");
900
901
902
903
904
        }
    }

    else if (cmd == "qsDllInfo") {
        // That's a following query package
hjk's avatar
hjk committed
905
        sendGdbServerAck();
906
        sendGdbServerMessage(QByteArray(1, 'l'), "library information transfer finished");
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
    }

    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
929
930
            sendGdbServerMessage("qSymbol:" + QByteArray("_Z7E32Mainv").toHex(),
                "ask for more");
931
932
933
934
935
    }

    else if (cmd.startsWith("qXfer:features:read:target.xml:")) {
        //  $qXfer:features:read:target.xml:0,7ca#46...Ack
        sendGdbServerAck();
hjk's avatar
hjk committed
936
937
938
939
940
941
942
943
944
        //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()) {
945
            QByteArray response(1, 'm');
hjk's avatar
hjk committed
946
947
948
            // 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
949
            sendGdbServerMessage(response, "thread information transferred");
hjk's avatar
hjk committed
950
        } else {
951
            sendGdbServerMessage(QByteArray(1, 'l'), "thread information transfer finished");
hjk's avatar
hjk committed
952
953
954
955
956
957
        }
    }

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

961
    else if (cmd.startsWith("qXfer:libraries:read")) {
962
        //qDebug() << "COMMAND: " << cmd;
963
        sendGdbServerAck();
hjk's avatar
hjk committed
964
965
966
967
        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 + "\">";
968
969
970
971
            //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
972
973
974
            response += "</library>";
        }
        response += "</library-list>";
Tobias Hunger's avatar
Tobias Hunger committed
975
        sendGdbServerMessage(response, "library information transferred");
976
977
    }

978
979
    else if (cmd == "QStartNoAckMode") {
        //$qSupported#37
hjk's avatar
hjk committed
980
        logMessage("Handling 'QStartNoAckMode'");
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
        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();
999
        //m_snapshot.reset();
1000
        m_running = true;
1001
1002
        QByteArray ba = trkStepRangeMessage();
        sendTrkMessage(0x19, TrkCB(handleStep), ba, "Step range");
1003
1004
    }

hjk's avatar
hjk committed
1005
1006
1007
1008
1009
1010
1011
    else if (cmd.startsWith('T')) {
        // FIXME: check whether thread is alive
        sendGdbServerAck();
        sendGdbServerMessage("OK"); // pretend all is well
        //sendGdbServerMessage("E nn");
    }

1012
1013
1014
1015
    else if (cmd == "vCont?") {
        // actions supported by the vCont packet
        sendGdbServerAck();
        //sendGdbServerMessage("OK"); // we don't support vCont.
1016
        sendGdbServerMessage("vCont;c;C;s;S");
1017
1018
1019
1020
1021
    }

    else if (cmd == "vCont;c") {
        // vCont[;action[:thread-id]]...'
        sendGdbServerAck();
1022
        //m_snapshot.reset();
1023
1024
1025
1026
1027
1028
        m_running = true;
        sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE");
    }

    else if (cmd.startsWith("Z0,") || cmd.startsWith("Z1,")) {
        // Insert breakpoint
hjk's avatar
hjk committed
1029
        sendGdbServerAck();
1030
1031
1032
        logMessage(msgGdbPacket(QLatin1String("Insert breakpoint")));
        // $Z0,786a4ccc,4#99
        const int pos = cmd.lastIndexOf(',');
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
        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);
        }
1049
1050
1051
1052
    }

    else if (cmd.startsWith("z0,") || cmd.startsWith("z1,")) {
        // Remove breakpoint
hjk's avatar
hjk committed
1053
        sendGdbServerAck();
1054
1055
1056
1057
        logMessage(msgGdbPacket(QLatin1String("Remove breakpoint")));
        // $z0,786a4ccc,4#99
        const int pos = cmd.lastIndexOf(',');
        bool ok = false;
1058
1059
        const uint addr = cmd.mid(3, pos - 3).toUInt(&ok, 16);
        const uint len = cmd.mid(pos + 1).toUInt(&ok, 16);
1060
1061
        const uint bp = m_session.addressToBP[addr];
        if (bp == 0) {
1062
            logMessage(_("NO RECORDED BP AT 0x%1, %2")
1063
                .arg(addr, 0, 16).arg(len));
hjk's avatar
hjk committed
1064
            sendGdbServerMessage("E00");
1065
1066
1067
        } else {
            m_session.addressToBP.remove(addr);
            QByteArray ba;
1068
            appendInt(&ba, bp);
1069
1070
1071
1072
1073
            sendTrkMessage(0x1C, TrkCB(handleClearBreakpoint), ba, addr);
        }
    }

    else if (cmd.startsWith("qPart:") || cmd.startsWith("qXfer:"))  {
hjk's avatar
hjk committed
1074
        QByteArray data = cmd.mid(1 + cmd.indexOf(':'));
1075
1076
1077
1078
1079
        // "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(',');
1080
            if (commaPos != -1) {
1081
1082
                bool ok1 = false, ok2 = false;
                const int offset = data.mid(offsetPos,  commaPos - offsetPos)
1083
1084
                    .toUInt(&ok1, 16);
                const int length = data.mid(commaPos + 1).toUInt(&ok2, 16);
1085
                if (ok1 && ok2) {
Tobias Hunger's avatar
Tobias Hunger committed
1086
                    const QString msg = _("Read of OS auxiliary "
1087
                        "vector (%1, %2) not implemented.").arg(offset).arg(length);
hjk's avatar
hjk committed
1088
                    logMessage(msgGdbPacket(msg));
1089
1090
1091
1092
1093
                    sendGdbServerMessage("E20", msg.toLatin1());
                    handled = true;
                }
            }
        } // auxv read
hjk's avatar
hjk committed
1094

1095
1096
1097
        if (!handled) {
            const QString msg = QLatin1String("FIXME unknown 'XFER'-request: ")
                + QString::fromAscii(cmd);
hjk's avatar
hjk committed
1098
            logMessage(msgGdbPacket(msg));
1099
1100
1101
1102
1103
1104
1105
1106
1107
            sendGdbServerMessage("E20", msg.toLatin1());
        }
    } // qPart/qXfer
    else {
        logMessage(msgGdbPacket(QLatin1String("FIXME unknown: ")
            + QString::fromAscii(cmd)));
    }
}

1108
void TrkGdbAdapter::sendTrkMessage(trk::byte code, TrkCallback callback,
1109
1110
    const QByteArray &data, const QVariant &cookie)
{
1111
1112
1113
    if (m_verbose >= 2)
        logMessage("trk: -> " + QByteArray::number(code, 16) + "  "
            + stringFromArray(data));
1114
    m_trkDevice->sendTrkMessage(code, callback, data, cookie);
1115
1116
}

1117
void TrkGdbAdapter::sendTrkAck(trk::byte token)
1118
{
1119
    //logMessage(QString("SENDING ACKNOWLEDGEMENT FOR TOKEN %1").arg(int(token)));
1120
    m_trkDevice->sendTrkAck(token);
1121
1122
}

hjk's avatar
hjk committed
1123
void TrkGdbAdapter::handleTrkError(const QString &msg)
1124
1125
1126
1127
{
    logMessage("## TRK ERROR: " + msg);
}

hjk's avatar
hjk committed
1128
void TrkGdbAdapter::handleTrkResult(const TrkResult &result)
1129
{
1130
1131
    if (m_verbose >= 2)
        logMessage("trk: <- " + result.toString());
1132
    if (result.isDebugOutput) {
1133
1134
1135
        // It looks like those messages _must not_ be acknowledged.
        // If we do so, TRK will complain about wrong sequencing.
        //sendTrkAck(result.token);
1136
1137
1138
1139
1140
        logMessage(QLatin1String("APPLICATION OUTPUT: ") +
            QString::fromAscii(result.data));
        sendGdbServerMessage("O" + result.data.toHex());
        return;
    }
1141
    //logMessage("READ TRK " + result.toString());
1142
1143
1144
1145
1146
1147
1148
1149
1150
    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;
hjk's avatar
hjk committed
1151
            logMessage(logMsg);
1152
1153
            break;
        }
Friedemann Kleint's avatar
Friedemann Kleint committed
1154
        case TrkNotifyStopped: {  // 0x90 Notified Stopped
1155
            // 90 01   78 6a 40 40   00 00 07 23   00 00 07 24  00 00
1156
1157
            debugMessage(_("RESET SNAPSHOT (NOTIFY STOPPED)"));
            m_snapshot.reset();
1158
1159
1160
1161
1162
1163
1164
1165
            QString reason;
            uint addr;
            uint pid;
            uint tid;
            trk::Launcher::parseNotifyStopped(result.data, &pid, &tid, &addr, &reason);
            const QString msg = trk::Launcher::msgStopped(pid, tid, addr, reason);
            logMessage(prefix + msg);
            m_engine->manager()->showDebuggerOutput(LogMisc, msg);
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
            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"));
            }
1176
1177

            #if 1
hjk's avatar
hjk committed
1178
            // We almost always need register values, so get them
1179
            // now before informing gdb about the stop.s
1180
            //qDebug() << "Auto-fetching registers";
hjk's avatar
hjk committed
1181
1182
            sendTrkMessage(0x12,
                TrkCB(handleAndReportReadRegistersAfterStop),
1183
                trkReadRegistersMessage());
1184
1185
1186
1187
1188
            #else
            // As a source-line step typically consists of
            // several instruction steps, better avoid the multiple
            // roundtrips through TRK in favour of an additional
            // roundtrip through gdb. But gdb will ask for all registers.
1189
1190
1191
1192
1193
1194
1195
                #if 1
                sendGdbServerMessage("S05", "Target stopped");
                #else
                QByteArray ba = "T05";
                appendRegister(&ba, RegisterPSGdb, addr);
                sendGdbServerMessage(ba, "Registers");
                #endif
1196
            #endif
1197
1198
            break;
        }
Friedemann Kleint's avatar
Friedemann Kleint committed
1199
        case TrkNotifyException: { // 0x91 Notify Exception (obsolete)
1200
1201
            debugMessage(_("RESET SNAPSHOT (NOTIFY EXCEPTION)"));
            m_snapshot.reset();
1202
1203
1204
1205
1206
            logMessage(prefix + "NOTE: EXCEPTION  " + str);
            sendTrkAck(result.token);
            break;
        }
        case 0x92: { //
1207
1208
            debugMessage(_("RESET SNAPSHOT (NOTIFY INTERNAL ERROR)"));
            m_snapshot.reset();
1209
1210
1211
1212
1213
1214
1215
            logMessage(prefix + "NOTE: INTERNAL ERROR: " + str);
            sendTrkAck(result.token);
            break;
        }

        // target->host OS notification
        case 0xa0: { // Notify Created
1216
1217
            // Sending this ACK does not seem to make a difference. Why?
            //sendTrkAck(result.token);
1218
            debugMessage(_("RESET SNAPSHOT (NOTIFY CREATED)"));
1219
            m_snapshot.fullReset();
1220
            const char *data = result.data.data();
1221
            const trk::byte error = result.data.at(0);
1222
            // type: 1 byte; for dll item, this value is 2.
1223
            const trk::byte type = result.data.at(1);
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
            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 << '\'';
1240
1241
1242
1243
1244
            Library lib;
            lib.name = name;
            lib.codeseg = codeseg;
            lib.dataseg = dataseg;
            m_session.libraries.append(lib);