runner.cpp 65 KB
Newer Older
hjk's avatar
hjk committed
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.
**
**************************************************************************/

30
#include "trkutils.h"
hjk's avatar
hjk committed
31
#include "trkdevicex.h"
32

hjk's avatar
hjk committed
33
34
35
36
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QHash>
37
#include <QtCore/QPointer>
hjk's avatar
hjk committed
38
#include <QtCore/QProcess>
39
#include <QtCore/QQueue>
hjk's avatar
hjk committed
40
41
42
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QTextStream>
hjk's avatar
hjk committed
43
#include <QtCore/QTimer>
hjk's avatar
hjk committed
44

hjk's avatar
hjk committed
45
#include <QtGui/QAction>
hjk's avatar
hjk committed
46
#include <QtGui/QApplication>
hjk's avatar
hjk committed
47
#include <QtGui/QMainWindow>
48
49
#include <QtGui/QKeyEvent>
#include <QtGui/QTextBlock>
hjk's avatar
hjk committed
50
#include <QtGui/QTextEdit>
hjk's avatar
hjk committed
51
#include <QtGui/QToolBar>
hjk's avatar
hjk committed
52

53
54
55
56
57
#include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
#include <QtNetwork/QLocalServer>
#include <QtNetwork/QLocalSocket>

hjk's avatar
hjk committed
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
/*
fetch-register          p                       info registers
set-register            P                       set
binary-download         X                       load, set
read-aux-vector         qXfer:auxv:read         info auxv
symbol-lookup           qSymbol                 Detecting multiple threads
attach                  vAttach                 attach
verbose-resume          vCont                   Stepping or resuming multiple threads
run                     vRun                    run
software-breakpoint     Z0                      break
hardware-breakpoint     Z1                      hbreak
write-watchpoint        Z2                      watch
read-watchpoint         Z3                      rwatch
access-watchpoint       Z4                      awatch
target-features         qXfer:features:read     set architecture
library-info            qXfer:libraries:read    info sharedlibrary
memory-map              qXfer:memory-map:read   info mem
read-spu-object         qXfer:spu:read          info spu
write-spu-object        qXfer:spu:write         info spu
get-thread-local-
storage-address         qGetTLSAddr             Displaying __thread variables
supported-packets       qSupported              Remote communications parameters
pass-signals            QPassSignals            handle signal
hostio-close-packet     vFile:close             remote get, remote put
hostio-open-packet      vFile:open              remote get, remote put
hostio-pread-packet     vFile:pread             remote get, remote put
hostio-pwrite-packet    vFile:pwrite            remote get, remote put
hostio-unlink-packet    vFile:unlink            remote delete
*/
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102

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"
};

hjk's avatar
hjk committed
103
static QByteArray dumpRegister(int n, uint value)
104
{
hjk's avatar
hjk committed
105
106
    QByteArray ba;
    ba += ' ';
107
    if (n < KnownRegisters && registerNames[n]) {
hjk's avatar
hjk committed
108
        ba += registerNames[n];
109
    } else {
hjk's avatar
hjk committed
110
111
        ba += '#';
        ba += QByteArray::number(n);
112
    }
hjk's avatar
hjk committed
113
    ba += "=" + hexxNumber(value);
hjk's avatar
hjk committed
114
    return ba;
115
}
hjk's avatar
hjk committed
116

hjk's avatar
hjk committed
117
118
119
120
121
122
123
124
#define TrkCB(s) TrkCallback(this, &Adapter::s)
#define GdbCB(s) GdbCallback(this, &Adapter::s)

struct GdbResult
{
    QByteArray data;
};

hjk's avatar
hjk committed
125
126
///////////////////////////////////////////////////////////////////////
//
127
// Adapter
hjk's avatar
hjk committed
128
129
130
//
///////////////////////////////////////////////////////////////////////

131
class Adapter : public QObject
hjk's avatar
hjk committed
132
133
134
135
{
    Q_OBJECT

public:
hjk's avatar
hjk committed
136
137
    typedef TrkFunctor1<const TrkResult &> TrkCallback;
    typedef TrkFunctor1<const GdbResult &> GdbCallback;
138
139
140
141
142
143
144
145
146
147

    Adapter();
    ~Adapter();
    void setGdbServerName(const QString &name);
    QString gdbServerIP() const;
    uint gdbServerPort() const;
    void setTrkServerName(const QString &name) { m_trkServerName = name; }
    void setVerbose(int verbose) { m_verbose = verbose; }
    void setSerialFrame(bool b) { m_serialFrame = b; }
    void setRegisterEndianness(Endianness r) { m_registerEndianness = r; }
hjk's avatar
hjk committed
148
    void setBufferedMemoryRead(bool b) { m_bufferedMemoryRead = b; }
149
150

public slots:
hjk's avatar
hjk committed
151
    void startInferior();
hjk's avatar
hjk committed
152
153
154
155
156
157
158
159
160
161

signals:
    void output(const QString &senderName, const QString &data);

private slots:
    void handleProcError(QProcess::ProcessError error);
    void handleProcFinished(int exitCode, QProcess::ExitStatus exitStatus);
    void handleProcStarted();
    void handleProcStateChanged(QProcess::ProcessState newState);
    void run();
162
    void startGdb();
hjk's avatar
hjk committed
163
164

private:
hjk's avatar
hjk committed
165
166
167
168
    friend class RunnerGui;
    void connectProcess(QProcess *proc);
    void sendOutput(QObject *sender, const QString &data);
    void sendOutput(const QString &data) { sendOutput(0, data); }
hjk's avatar
hjk committed
169

hjk's avatar
hjk committed
170
    QString m_trkServerName; // 
171
172
173
174
    QString m_gdbServerName; // 127.0.0.1:(2222+uid)

    QProcess m_gdbProc;
    QProcess m_rfcommProc;
hjk's avatar
hjk committed
175
    bool m_running;
176
177
178
179
180

public:
    //
    // TRK
    //
hjk's avatar
hjk committed
181
    bool openTrkPort(const QString &port, QString *errorMessage);
182
    void sendTrkMessage(byte code,
hjk's avatar
hjk committed
183
        TrkCallback callback = TrkCallback(),
184
        const QByteArray &data = QByteArray(),
185
        const QVariant &cookie = QVariant());
hjk's avatar
hjk committed
186
187
    Q_SLOT void handleTrkResult(const trk::TrkResult &data);
    Q_SLOT void handleTrkError(const QString &msg);
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208

    // convenience messages
    void waitForTrkFinished();
    void sendTrkAck(byte token);

    // kill process and breakpoints
    void cleanUp();

    void handleCpuType(const TrkResult &result);
    void handleCreateProcess(const TrkResult &result);
    void handleClearBreakpoint(const TrkResult &result);
    void handleSignalContinue(const TrkResult &result);
    void handleWaitForFinished(const TrkResult &result);
    void handleStop(const TrkResult &result);
    void handleSupportMask(const TrkResult &result);
    void handleTrkVersions(const TrkResult &result);
    void handleDisconnect(const TrkResult &result);

    void handleAndReportCreateProcess(const TrkResult &result);
    void handleAndReportReadRegisters(const TrkResult &result);
    QByteArray memoryReadLogMessage(uint addr, uint len, const QByteArray &ba) const;
hjk's avatar
hjk committed
209
    QByteArray trkContinueMessage();
210
211
212
    QByteArray trkReadRegisterMessage();
    QByteArray trkReadMemoryMessage(uint addr, uint len);
    QByteArray trkBreakpointMessage(uint addr, uint len, bool armMode = true);
213
214
215
    void handleAndReportSetBreakpoint(const TrkResult &result);
    void handleReadMemoryBuffered(const TrkResult &result);
    void handleReadMemoryUnbuffered(const TrkResult &result);
hjk's avatar
hjk committed
216
    void handleStepRange(const TrkResult &result);
hjk's avatar
hjk committed
217
    void handleReadRegisters(const TrkResult &result);
218
219
220
221
    void reportReadMemoryBuffered(const TrkResult &result);
    void reportToGdb(const TrkResult &result);

    void clearTrkBreakpoint(const Breakpoint &bp);
hjk's avatar
hjk committed
222

hjk's avatar
hjk committed
223
    // set breakpoints behind gdb's back
224
    void setTrkBreakpoint(const Breakpoint &bp);
hjk's avatar
hjk committed
225
226
    void handleSetTrkBreakpoint(const TrkResult &result);
    void handleSetTrkMainBreakpoint(const TrkResult &result);
227
228
229
230

    void readMemory(uint addr, uint len);
    void interruptInferior();

hjk's avatar
hjk committed
231
    TrkDevice m_trkDevice;
232
233
234
235

    //
    // Gdb
    //
hjk's avatar
hjk committed
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
    struct GdbCommand
    {
        GdbCommand() : flags(0), callback(GdbCallback()), callbackName(0) {}

        int flags;
        GdbCallback callback;
        const char *callbackName;
        QString command;
        QVariant cookie;
        //QTime postTime;
    };

    void sendGdbMessage(const QString &msg,
        GdbCallback callback = GdbCallback(),
        const QVariant &cookie = QVariant());
251
    Q_SLOT void handleGdbConnection();
hjk's avatar
hjk committed
252
253
    Q_SLOT void readGdbServerCommand();
    void readGdbResponse();
254
    void handleGdbServerCommand(const QByteArray &cmd);
hjk's avatar
hjk committed
255
    void sendGdbServerMessage(const QByteArray &msg,
hjk's avatar
hjk committed
256
        const QByteArray &logNote = QByteArray());
hjk's avatar
hjk committed
257
    void sendGdbServerMessageAfterTrkResponse(const QByteArray &msg,
hjk's avatar
hjk committed
258
        const QByteArray &logNote = QByteArray());
hjk's avatar
hjk committed
259
260
    void sendGdbServerAck();
    bool sendGdbServerPacket(const QByteArray &packet, bool doFlush);
261

hjk's avatar
hjk committed
262
263
    Q_SLOT void handleGdbReadyReadStandardError();
    Q_SLOT void handleGdbReadyReadStandardOutput();
264
    void logMessage(const QString &msg, bool force = false);
hjk's avatar
hjk committed
265
    Q_SLOT void trkLogMessage(const QString &msg);
266

hjk's avatar
hjk committed
267
268
269
    void handleInfoAddress(const GdbResult &result);
    void handleInfoMainAddress(const GdbResult &result);

270
271
272
273
274
    QTcpServer m_gdbServer;
    QPointer<QTcpSocket> m_gdbConnection;
    QByteArray m_gdbReadBuffer;
    bool m_gdbAckMode;

hjk's avatar
hjk committed
275
276
277
278
279
280
281
282
    QHash<int, GdbCommand> m_gdbCookieForToken;

    //
    // Rfcomm
    //
    Q_SLOT void handleRfcommReadyReadStandardError();
    Q_SLOT void handleRfcommReadyReadStandardOutput();

283
    // Debuggee state
hjk's avatar
hjk committed
284
    Q_SLOT void executeCommand(const QString &msg);
285
286
287
288
289
290
    Session m_session; // global-ish data (process id, target information)
    Snapshot m_snapshot; // local-ish data (memory and registers)
    int m_verbose;
    Endianness m_registerEndianness;
    bool m_serialFrame;
    bool m_bufferedMemoryRead;
hjk's avatar
hjk committed
291
292
};

293
Adapter::Adapter()
hjk's avatar
hjk committed
294
{
hjk's avatar
hjk committed
295
    m_running = false;
296
    m_gdbAckMode = true;
hjk's avatar
hjk committed
297
    m_verbose = 2;
298
299
300
    m_registerEndianness = LittleEndian;
    //m_serialFrame = true;
    m_serialFrame = false;
hjk's avatar
hjk committed
301
302
    m_bufferedMemoryRead = true;
    //m_bufferedMemoryRead = false;
303
304
    m_trkServerName = "/dev/rfcomm0";

hjk's avatar
hjk committed
305
    uid_t userId = getuid();
306
    m_gdbServerName = QString("127.0.0.1:%1").arg(2222 + userId);
hjk's avatar
hjk committed
307

308
309
    m_gdbProc.setObjectName("GDB PROCESS");
    connectProcess(&m_gdbProc);
hjk's avatar
hjk committed
310
311
312
313
    connect(&m_gdbProc, SIGNAL(readyReadStandardError()),
        this, SLOT(handleGdbReadyReadStandardError()));
    connect(&m_gdbProc, SIGNAL(readyReadStandardOutput()),
        this, SLOT(handleGdbReadyReadStandardOutput()));
hjk's avatar
hjk committed
314

315
316
    m_rfcommProc.setObjectName("RFCOMM PROCESS");
    connectProcess(&m_rfcommProc);
hjk's avatar
hjk committed
317
318
319
320
    connect(&m_rfcommProc, SIGNAL(readyReadStandardError()),
        this, SLOT(handleRfcommReadyReadStandardError()));
    connect(&m_rfcommProc, SIGNAL(readyReadStandardOutput()),
        this, SLOT(handleRfcommReadyReadStandardOutput()));
hjk's avatar
hjk committed
321
322
323

    connect(&m_trkDevice, SIGNAL(logMessage(QString)),
        this, SLOT(trkLogMessage(QString)));
hjk's avatar
hjk committed
324
325
}

326
Adapter::~Adapter()
hjk's avatar
hjk committed
327
{
328
329
    m_gdbServer.close();
    logMessage("Shutting down.\n", true);
hjk's avatar
hjk committed
330
331
}

hjk's avatar
hjk committed
332
333
334
335
336
void Adapter::trkLogMessage(const QString &msg)
{
    logMessage("TRK " + msg);
}

337
338
339
340
void Adapter::setGdbServerName(const QString &name)
{
    m_gdbServerName = name;
}
hjk's avatar
hjk committed
341

342
QString Adapter::gdbServerIP() const
hjk's avatar
hjk committed
343
{
344
345
346
347
    int pos = m_gdbServerName.indexOf(':');
    if (pos == -1)
        return m_gdbServerName;
    return m_gdbServerName.left(pos);
hjk's avatar
hjk committed
348
349
}

350
uint Adapter::gdbServerPort() const
hjk's avatar
hjk committed
351
{
352
353
354
355
    int pos = m_gdbServerName.indexOf(':');
    if (pos == -1)
        return 0;
    return m_gdbServerName.mid(pos + 1).toUInt();
hjk's avatar
hjk committed
356
357
}

358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
QByteArray Adapter::trkContinueMessage()
{
    QByteArray ba;
    appendInt(&ba, m_session.pid);
    appendInt(&ba, m_session.tid);
    return ba;
}

QByteArray Adapter::trkReadRegisterMessage()
{
    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 Adapter::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;
}

hjk's avatar
hjk committed
388
void Adapter::startInferior()
hjk's avatar
hjk committed
389
{
390
391
392
393
    QString errorMessage;
    if (!openTrkPort(m_trkServerName, &errorMessage)) {
        logMessage(errorMessage, true);
        logMessage("LOOPING");
hjk's avatar
hjk committed
394
        QTimer::singleShot(1000, this, SLOT(startInferior()));
395
396
397
        return;
    }

hjk's avatar
hjk committed
398
    m_trkDevice.sendTrkInitialPing();
399
    sendTrkMessage(0x01); // Connect
hjk's avatar
hjk committed
400
401
402
    sendTrkMessage(0x05, TrkCB(handleSupportMask));
    sendTrkMessage(0x06, TrkCB(handleCpuType));
    sendTrkMessage(0x04, TrkCB(handleTrkVersions)); // Versions
403
404
405
406
407
    //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

hjk's avatar
hjk committed
408
409
410
411
    QByteArray ba;
    appendByte(&ba, 0); // ?
    appendByte(&ba, 0); // ?
    appendByte(&ba, 0); // ?
412

hjk's avatar
hjk committed
413
414
415
416
    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));
hjk's avatar
hjk committed
417
418
}

419
void Adapter::logMessage(const QString &msg, bool force)
hjk's avatar
hjk committed
420
{
421
    if (m_verbose || force)
hjk's avatar
hjk committed
422
        emit output(QString(), msg);
hjk's avatar
hjk committed
423
424
}

425
426
427
428
//
// Gdb
//
void Adapter::handleGdbConnection()
hjk's avatar
hjk committed
429
{
430
431
432
433
434
435
    logMessage("HANDLING GDB CONNECTION");

    m_gdbConnection = m_gdbServer.nextPendingConnection();
    connect(m_gdbConnection, SIGNAL(disconnected()),
            m_gdbConnection, SLOT(deleteLater()));
    connect(m_gdbConnection, SIGNAL(readyRead()),
hjk's avatar
hjk committed
436
            this, SLOT(readGdbServerCommand()));
hjk's avatar
hjk committed
437
438
}

439
static inline QString msgGdbPacket(const QString &p)
hjk's avatar
hjk committed
440
{
hjk's avatar
hjk committed
441
    return QLatin1String("gdb:                              ") + p;
hjk's avatar
hjk committed
442
443
}

hjk's avatar
hjk committed
444
void Adapter::readGdbServerCommand()
hjk's avatar
hjk committed
445
{
446
447
448
    QByteArray packet = m_gdbConnection->readAll();
    m_gdbReadBuffer.append(packet);

hjk's avatar
hjk committed
449
    logMessage("gdb: -> " + QString::fromAscii(packet));
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
    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));
        }

505
        QByteArray cmd = ba.left(pos);
506
        ba.remove(0, pos + 3);
507
        handleGdbServerCommand(cmd);
508
509
510
    }
}

hjk's avatar
hjk committed
511
bool Adapter::sendGdbServerPacket(const QByteArray &packet, bool doFlush)
512
{
hjk's avatar
hjk committed
513
514
515
516
517
518
519
520
    if (!m_gdbConnection) {
        logMessage(QString::fromLatin1("Cannot write to gdb: No connection (%1)")
            .arg(QString::fromLatin1(packet)), true);
        return false;
    }
    if (m_gdbConnection->state() != QAbstractSocket::ConnectedState) {
        logMessage(QString::fromLatin1("Cannot write to gdb: Not connected (%1)")
            .arg(QString::fromLatin1(packet)), true);
521
522
523
        return false;
    }
    if (m_gdbConnection->write(packet) == -1) {
hjk's avatar
hjk committed
524
525
        logMessage(QString::fromLatin1("Cannot write to gdb: %1 (%2)")
            .arg(m_gdbConnection->errorString()).arg(QString::fromLatin1(packet)), true);
526
527
528
529
530
531
532
        return false;
    }
    if (doFlush)
        m_gdbConnection->flush();
    return true;
}

hjk's avatar
hjk committed
533
void Adapter::sendGdbServerAck()
534
535
536
537
538
{
    if (!m_gdbAckMode)
        return;
    QByteArray packet = "+";
    logMessage("gdb: <- " + packet);
hjk's avatar
hjk committed
539
    sendGdbServerPacket(packet, false);
540
541
}

hjk's avatar
hjk committed
542
void Adapter::sendGdbServerMessage(const QByteArray &msg, const QByteArray &logNote)
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
{
    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);
hjk's avatar
hjk committed
560
    sendGdbServerPacket(packet, true);
561
562
}

hjk's avatar
hjk committed
563
564
void Adapter::sendGdbServerMessageAfterTrkResponse(const QByteArray &msg,
    const QByteArray &logNote)
565
566
{
    QByteArray ba = msg + char(1) + logNote;
hjk's avatar
hjk committed
567
    sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, TrkCB(reportToGdb), "", ba); // Answer gdb
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
}

void Adapter::reportToGdb(const TrkResult &result)
{
    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));
hjk's avatar
hjk committed
583
    sendGdbServerMessage(message, note);
584
585
}

586
QByteArray Adapter::trkBreakpointMessage(uint addr, uint len, bool armMode)
587
588
589
590
591
592
593
{
    QByteArray ba;
    appendByte(&ba, 0x82);  // unused option
    appendByte(&ba, armMode /*bp.mode == ArmMode*/ ? 0x00 : 0x01);
    appendInt(&ba, addr);
    appendInt(&ba, len);
    appendInt(&ba, 0x00000001);
594
    appendInt(&ba, m_session.pid);
595
596
597
598
    appendInt(&ba, 0xFFFFFFFF);
    return ba;
}

599
void Adapter::handleGdbServerCommand(const QByteArray &cmd)
600
601
602
603
{
    // http://sourceware.org/gdb/current/onlinedocs/gdb_34.html
    if (0) {}

604
    else if (cmd == "!") {
hjk's avatar
hjk committed
605
606
607
        sendGdbServerAck();
        //sendGdbServerMessage("", "extended mode not enabled");
        sendGdbServerMessage("OK", "extended mode enabled");
608
609
    }

610
    else if (cmd.startsWith("?")) {
hjk's avatar
hjk committed
611
        logMessage(msgGdbPacket(QLatin1String("Query halted")));
612
613
        // Indicate the reason the target halted.
        // The reply is the same as for step and continue.
hjk's avatar
hjk committed
614
615
616
617
618
619
620
621
        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());
622
623
    }

624
    else if (cmd == "c") {
hjk's avatar
hjk committed
625
626
        logMessage(msgGdbPacket(QLatin1String("Continue")));
        sendGdbServerAck();
627
628
629
630
631
632
        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);
hjk's avatar
hjk committed
633
        sendTrkMessage(0x18, TrkCallback(), ba);
634
635
    }

636
    else if (cmd.startsWith("C")) {
hjk's avatar
hjk committed
637
        logMessage(msgGdbPacket(QLatin1String("Continue with signal")));
638
639
        // C sig[;addr] Continue with signal sig (hex signal number)
        //Reply: See section D.3 Stop Reply Packets, for the reply specifications.
hjk's avatar
hjk committed
640
        sendGdbServerAck();
641
        bool ok = false;
642
        uint signalNumber = cmd.mid(1).toInt(&ok, 16);
643
644
645
        QByteArray ba;
        appendInt(&ba, m_session.pid);
        appendInt(&ba, m_session.tid);
hjk's avatar
hjk committed
646
        sendTrkMessage(0x18, TrkCB(handleSignalContinue), ba, signalNumber); // Continue
647
648
    }

649
    else if (cmd.startsWith("D")) {
hjk's avatar
hjk committed
650
651
        sendGdbServerAck();
        sendGdbServerMessage("OK", "shutting down");
652
653
654
        qApp->quit();
    }

655
    else if (cmd == "g") {
hjk's avatar
hjk committed
656
        logMessage(msgGdbPacket(QLatin1String("Read registers")));
657
        // Read general registers.
hjk's avatar
hjk committed
658
659
        //sendGdbServerMessage("00000000", "read registers");
        sendGdbServerAck();
660
661
        sendTrkMessage(0x12, TrkCB(handleAndReportReadRegisters),
            trkReadRegisterMessage());
662
663
    }

664
    else if (cmd.startsWith("Hc")) {
hjk's avatar
hjk committed
665
        logMessage(msgGdbPacket(QLatin1String("Set thread & continue")));
666
667
668
        // Set thread for subsequent operations (`m', `M', `g', `G', et.al.).
        // for step and continue operations
        //$Hc-1#09
hjk's avatar
hjk committed
669
670
        sendGdbServerAck();
        sendGdbServerMessage("OK", "Set current thread for step & continue");
671
672
    }

673
    else if (cmd.startsWith("Hg")) {
hjk's avatar
hjk committed
674
        logMessage(msgGdbPacket(QLatin1String("Set thread")));
675
676
677
        // Set thread for subsequent operations (`m', `M', `g', `G', et.al.).
        // for 'other operations.  0 - any thread
        //$Hg0#df
hjk's avatar
hjk committed
678
        sendGdbServerAck();
679
        m_session.currentThread = cmd.mid(2).toInt(0, 16);
hjk's avatar
hjk committed
680
        sendGdbServerMessage("OK", "Set current thread "
681
682
683
            + QByteArray::number(m_session.currentThread));
    }

684
    else if (cmd == "k") {
hjk's avatar
hjk committed
685
        logMessage(msgGdbPacket(QLatin1String("kill")));
686
        // kill
hjk's avatar
hjk committed
687
        sendGdbServerAck();
688
        QByteArray ba;
689
        appendByte(&ba, 0); // ?
690
691
        appendByte(&ba, 0); // Sub-command: Delete Process
        appendInt(&ba, m_session.pid);
hjk's avatar
hjk committed
692
693
        sendTrkMessage(0x41, TrkCallback(), ba, "Delete process"); // Delete Item
        sendGdbServerMessageAfterTrkResponse("", "process killed");
694
695
    }

696
    else if (cmd.startsWith("m")) {
hjk's avatar
hjk committed
697
        logMessage(msgGdbPacket(QLatin1String("Read memory")));
698
        // m addr,length
hjk's avatar
hjk committed
699
        sendGdbServerAck();
700
701
        uint addr = 0, len = 0;
        do {
702
            const int pos = cmd.indexOf(',');
703
704
705
            if (pos == -1)
                break;
            bool ok;
706
            addr = cmd.mid(1, pos - 1).toUInt(&ok, 16);
707
708
            if (!ok)
                break;
709
            len = cmd.mid(pos + 1).toUInt(&ok, 16);
710
711
712
713
714
715
            if (!ok)
                break;
        } while (false);
        if (len) {
            readMemory(addr, len);
        } else {
716
            sendGdbServerMessage("E20", "Error " + cmd);
717
718
        }
    }
719
    else if (cmd.startsWith("p")) {
hjk's avatar
hjk committed
720
        logMessage(msgGdbPacket(QLatin1String("read register")));
721
        // 0xf == current instruction pointer?
hjk's avatar
hjk committed
722
723
        //sendGdbServerMessage("0000", "current IP");
        sendGdbServerAck();
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
        #if 0
          A1 = 0,	 first integer-like argument
          A4 = 3,	 last integer-like argument
          AP = 11,
          IP = 12,
          SP = 13,	 Contains address of top of stack
          LR = 14,	 address to return to from a function call
          PC = 15,	 Contains program counter
          F0 = 16,	 first floating point register
          F3 = 19,	 last floating point argument register
          F7 = 23, 	 last floating point register
          FPS = 24,	 floating point status register
          PS = 25,	 Contains processor status
          WR0,		 WMMX data registers.
          WR15 = WR0 + 15,
          WC0,		 WMMX control registers.
          WCSSF = WC0 + 2,
          WCASF = WC0 + 3,
          WC7 = WC0 + 7,
          WCGR0,		WMMX general purpose registers.
          WCGR3 = WCGR0 + 3,
          WCGR7 = WCGR0 + 7,
          NUM_REGS,

          // Other useful registers.
          FP = 11,		Frame register in ARM code, if used.
          THUMB_FP = 7,		Frame register in Thumb code, if used.
          NUM_ARG_REGS = 4,
          LAST_ARG = A4,
          NUM_FP_ARG_REGS = 4,
          LAST_FP_ARG = F3
        #endif
        bool ok = false;
757
        const uint registerNumber = cmd.mid(1).toInt(&ok, 16);
hjk's avatar
hjk committed
758
        QByteArray logMsg = "Read Register";
759
760
761
        if (registerNumber == RegisterPSGdb) {
            QByteArray ba;
            appendInt(&ba, m_snapshot.registers[RegisterPSTrk], m_registerEndianness);
hjk's avatar
hjk committed
762
            logMsg += dumpRegister(registerNumber, m_snapshot.registers[RegisterPSTrk]);
hjk's avatar
hjk committed
763
            sendGdbServerMessage(ba.toHex(), logMsg);
764
765
766
        } else if (registerNumber < RegisterCount) {
            QByteArray ba;
            appendInt(&ba, m_snapshot.registers[registerNumber], m_registerEndianness);
hjk's avatar
hjk committed
767
            logMsg += dumpRegister(registerNumber, m_snapshot.registers[registerNumber]);
hjk's avatar
hjk committed
768
            sendGdbServerMessage(ba.toHex(), logMsg);
769
        } else {
hjk's avatar
hjk committed
770
771
            sendGdbServerMessage("0000", "read single unknown register #" + QByteArray::number(registerNumber));
            //sendGdbServerMessage("E01", "read single unknown register");
772
773
774
        }
    }

775
    else if (cmd == "qAttached") {
776
777
778
        //$qAttached#8f
        // 1: attached to an existing process
        // 0: created a new process
hjk's avatar
hjk committed
779
780
781
782
        sendGdbServerAck();
        sendGdbServerMessage("0", "new process created");
        //sendGdbServerMessage("1", "attached to existing process");
        //sendGdbServerMessage("E01", "new process created");
783
784
    }

785
    else if (cmd.startsWith("qC")) {
hjk's avatar
hjk committed
786
        logMessage(msgGdbPacket(QLatin1String("query thread id")));
787
788
        // Return the current thread ID
        //$qC#b4
hjk's avatar
hjk committed
789
790
        sendGdbServerAck();
        sendGdbServerMessageAfterTrkResponse("QC@TID@");
791
792
    }

793
    else if (cmd.startsWith("qSupported")) {
794
795
796
        //$qSupported#37
        //$qSupported:multiprocess+#c6
        //logMessage("Handling 'qSupported'");
hjk's avatar
hjk committed
797
        sendGdbServerAck();
798
        if (0)
hjk's avatar
hjk committed
799
            sendGdbServerMessage(QByteArray(), "nothing supported");
800
        else
hjk's avatar
hjk committed
801
            sendGdbServerMessage(
802
803
804
805
806
807
808
                "PacketSize=7cf;"
                //"QPassSignals+;"
                "qXfer:libraries:read+;"
                //"qXfer:auxv:read+;"
                "qXfer:features:read+");
    }

809
    else if (cmd == "qPacketInfo") {
810
811
        // happens with  gdb 6.4.50.20060226-cvs / CodeSourcery
        // deprecated by qSupported?
hjk's avatar
hjk committed
812
813
        sendGdbServerAck();
        sendGdbServerMessage("", "FIXME: nothing?");
814
815
    }

816
    else if (cmd == "qOffsets") {
hjk's avatar
hjk committed
817
818
        sendGdbServerAck();
        sendGdbServerMessageAfterTrkResponse("TextSeg=@CODESEG@;DataSeg=@DATASEG@");
819
820
    }

821
    else if (cmd == "qSymbol::") {
822
823
824
        if (m_verbose)
            logMessage(msgGdbPacket(QLatin1String("notify can handle symbol lookup")));
        // Notify the target that GDB is prepared to serve symbol lookup requests.
hjk's avatar
hjk committed
825
        sendGdbServerAck();
826
        if (1)
hjk's avatar
hjk committed
827
            sendGdbServerMessage("OK", "no further symbols needed");
828
        else
hjk's avatar
hjk committed
829
            sendGdbServerMessage("qSymbol:" + QByteArray("_Z7E32Mainv").toHex(), "ask for more");
830
831
    }

832
    else if (cmd.startsWith("qXfer:features:read:target.xml:")) {
833
        //  $qXfer:features:read:target.xml:0,7ca#46...Ack
hjk's avatar
hjk committed
834
835
        sendGdbServerAck();
        sendGdbServerMessage("l<target><architecture>symbianelf</architecture></target>");
836
837
    }

838
    else if (cmd == "QStartNoAckMode") {
839
840
        //$qSupported#37
        //logMessage("Handling 'QStartNoAckMode'");
hjk's avatar
hjk committed
841
842
        sendGdbServerAck();
        sendGdbServerMessage("OK", "ack no-ack mode");
843
844
845
        m_gdbAckMode = false;
    }

846
    else if (cmd.startsWith("QPassSignals")) {
847
848
849
        // 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
hjk's avatar
hjk committed
850
        sendGdbServerAck();
851
        // FIXME: use the parameters
hjk's avatar
hjk committed
852
        sendGdbServerMessage("OK", "passing signals accepted");
853
854
    }

855
    else if (cmd == "s" || cmd.startsWith("vCont;s")) {
856
        logMessage(msgGdbPacket(QLatin1String("Step range")));
hjk's avatar
hjk committed
857
        logMessage("  from " + hexxNumber(m_snapshot.registers[RegisterPC]));
hjk's avatar
hjk committed
858
        sendGdbServerAck();
859
        m_running = true;
860
        QByteArray ba;
hjk's avatar
hjk committed
861
        appendByte(&ba, 0x01); // options
862
        appendInt(&ba, m_snapshot.registers[RegisterPC]); // start address
hjk's avatar
hjk committed
863
864
        //appendInt(&ba, m_snapshot.registers[RegisterPC] + 4); // end address
        appendInt(&ba, -1); // end address
865
866
        appendInt(&ba, m_session.pid);
        appendInt(&ba, m_session.tid);
hjk's avatar
hjk committed
867
        sendTrkMessage(0x19, TrkCB(handleStepRange), ba, "Step range");
868
        // FIXME: should be triggered by "real" stop"
hjk's avatar
hjk committed
869
        //sendGdbServerMessageAfterTrkResponse("S05", "target halted");
870
871
    }

872
    else if (cmd == "vCont?") {
873
        // actions supported by the vCont packet
hjk's avatar
hjk committed
874
875
876
877
878
        sendGdbServerAck();
        sendGdbServerMessage("OK"); // we don't support vCont.
        //sendGdbServerMessage("vCont;c");
    }

879
    else if (cmd == "vCont;c") {
hjk's avatar
hjk committed
880
881
882
883
        // vCont[;action[:thread-id]]...'
        sendGdbServerAck();
        m_running = true;
        sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE");
884
885
    }

886
    else if (cmd.startsWith("vKill")) {
887
        // kill
hjk's avatar
hjk committed
888
        sendGdbServerAck();
889
890
891
        QByteArray ba;
        appendByte(&ba, 0); // Sub-command: Delete Process
        appendInt(&ba, m_session.pid);
hjk's avatar
hjk committed
892
893
894
895
        sendTrkMessage(0x41, TrkCallback(), ba, "Delete process"); // Delete Item
        sendGdbServerMessageAfterTrkResponse("", "process killed");
    }

896
    else if (0 && cmd.startsWith("Z0,")) {
hjk's avatar
hjk committed
897
898
        // Tell gdb  we don't support software breakpoints
        sendGdbServerMessage("");
899
900
    }

901
    else if (cmd.startsWith("Z0,") || cmd.startsWith("Z1,")) {
hjk's avatar
hjk committed
902
        // Insert breakpoint
903
904
905
        if (m_verbose)
            logMessage(msgGdbPacket(QLatin1String("Insert breakpoint")));
        // $z0,786a4ccc,4#99
906
        const int pos = cmd.lastIndexOf(',');
907
        bool ok = false;
908
909
        const uint addr = cmd.mid(3, pos - 3).toInt(&ok, 16);
        const uint len = cmd.mid(pos + 1).toInt(&ok, 16);
hjk's avatar
hjk committed
910
911
912
        //qDebug() << "ADDR: " << hexNumber(addr) << " LEN: " << len;
        logMessage(QString::fromLatin1("Inserting breakpoint at 0x%1, %2")
            .arg(addr, 0, 16).arg(len));
913
914
915
916
917
918
919
920
921
922
923
924

        //---IDE------------------------------------------------------
        //  Command: 0x1B Set Break
        //BreakType: 0x82
        //  Options: 0x00
        //  Address: 0x78674340 (2020033344)    i.e + 0x00000340
        //   Length: 0x00000001 (1)
        //    Count: 0x00000000 (0)
        //ProcessID: 0x000001b5 (437)
        // ThreadID: 0xffffffff (-1)
        // [1B 09 82 00 78 67 43 40 00 00 00 01 00 00 00 00
        //  00 00 01 B5 FF FF FF FF]
hjk's avatar
hjk committed
925
        const QByteArray ba = trkBreakpointMessage(addr, len, m_session.pid);
hjk's avatar
hjk committed
926
        sendTrkMessage(0x1B, TrkCB(handleAndReportSetBreakpoint), ba);
927
928
929
930
931
932
        //m_session.toekn

        //---TRK------------------------------------------------------
        //  Command: 0x80 Acknowledge
        //    Error: 0x00
        // [80 09 00 00 00 00 0A]
933
934
    } else if (cmd.startsWith("qPart:") || cmd.startsWith("qXfer:"))  {
        QByteArray data  = cmd.mid(1 + cmd.indexOf(':'));
935
936
937
938
939
940
941
        // "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;
hjk's avatar
hjk committed
942
943
                const int offset = data.mid(offsetPos,  commaPos - offsetPos)
                    .toInt(&ok1, 16);
944
945
                const int length = data.mid(commaPos + 1).toInt(&ok2, 16);
                if (ok1 && ok2) {
hjk's avatar
hjk committed
946
947
                    const QString msg = QString::fromLatin1("Read of OS auxilary "
                        "vector (%1, %2) not implemented.").arg(offset).arg(length);
948
                    logMessage(msgGdbPacket(msg), true);
hjk's avatar
hjk committed
949
                    sendGdbServerMessage("E20", msg.toLatin1());
950
951
952
953
954
                    handled = true;
                }
            }
        } // auxv read
        if (!handled) {
hjk's avatar
hjk committed
955
            const QString msg = QLatin1String("FIXME unknown 'XFER'-request: ")
956
                + QString::fromAscii(cmd);
957
            logMessage(msgGdbPacket(msg), true);
hjk's avatar
hjk committed
958
            sendGdbServerMessage("E20", msg.toLatin1());
959
960
961
        }
    } // qPart/qXfer
    else {
hjk's avatar
hjk committed
962
        logMessage(msgGdbPacket(QLatin1String("FIXME unknown: ")
963
            + QString::fromAscii(cmd)));
964
965
966
    }
}

hjk's avatar
hjk committed
967
void Adapter::executeCommand(const QString &msg)
968
{
hjk's avatar
hjk committed
969
970
971
972
    if (msg == "EI") {
        sendGdbMessage("-exec-interrupt");
    } else if (msg == "C") {
        sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE");
973
    } else if (msg == "R") {
hjk's avatar
hjk committed
974
975
        sendTrkMessage(0x18, TrkCB(handleReadRegisters),
            trkReadRegisterMessage(), "READ REGS");
hjk's avatar
hjk committed
976
    } else if (msg == "I") {
hjk's avatar
hjk committed
977
        interruptInferior();
hjk's avatar
hjk committed
978
979
980
981
    } else {
        logMessage("EXECUTING GDB COMMAND " + msg);
        sendGdbMessage(msg);
    }
982
983
984
985
986
}

bool Adapter::openTrkPort(const QString &port, QString *errorMessage)
{
    connect(&m_trkDevice, SIGNAL(messageReceived(trk::TrkResult)),
hjk's avatar
hjk committed
987
988
989
        this, SLOT(handleTrkResult(trk::TrkResult)));
    connect(&m_trkDevice, SIGNAL(error(QString)),
        this, SLOT(handleTrkError(QString)));
990
991
992
993
994
995
    if (m_verbose > 1)
        m_trkDevice.setVerbose(true);
    m_trkDevice.setSerialFrame(m_serialFrame);
    return m_trkDevice.open(port, errorMessage);
}

hjk's avatar
hjk committed
996
void Adapter::sendTrkMessage(byte code, TrkCallback callback,
997
    const QByteArray &data, const QVariant &cookie)
998
{
999
    m_trkDevice.sendTrkMessage(code, callback, data, cookie);
1000
1001
1002
1003
1004
}

void Adapter::waitForTrkFinished()
{
    // initiate one last roundtrip to ensure all is flushed
hjk's avatar
hjk committed
1005
    sendTrkMessage(0x0, TrkCB(handleWaitForFinished));
hjk's avatar
hjk committed
1006
1007
}

1008
1009
1010
1011
1012
void Adapter::sendTrkAck(byte token)
{
    logMessage(QString("SENDING ACKNOWLEDGEMENT FOR TOKEN %1").arg(int(token)));
    m_trkDevice.sendTrkAck(token);
}
hjk's avatar
hjk committed
1013

hjk's avatar
hjk committed
1014
1015
1016
1017
1018
1019
void Adapter::handleTrkError(const QString &msg)
{
    logMessage("## TRK ERROR: " + msg);
}

void Adapter::handleTrkResult(const TrkResult &result)
1020
1021
{
    if (result.isDebugOutput) {
hjk's avatar
hjk committed
1022
1023
1024
1025
        sendTrkAck(result.token);
        logMessage(QLatin1String("APPLICATION OUTPUT: ") +
            QString::fromAscii(result.data));
        sendGdbServerMessage("O" + result.data.toHex());
1026
1027
        return;
    }