breakhandler.cpp 49.1 KB
Newer Older
1
/**************************************************************************
con's avatar
con committed
2
3
4
**
** This file is part of Qt Creator
**
con's avatar
con committed
5
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
con's avatar
con committed
6
**
hjk's avatar
hjk committed
7
** Contact: Nokia Corporation (info@qt.nokia.com)
con's avatar
con committed
8
**
9
**
10
** GNU Lesser General Public License Usage
11
**
hjk's avatar
hjk committed
12
13
14
15
16
17
** 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.
18
**
con's avatar
con committed
19
** In addition, as a special exception, Nokia gives you certain additional
hjk's avatar
hjk committed
20
** rights. These rights are described in the Nokia Qt LGPL Exception
con's avatar
con committed
21
22
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
23
24
25
26
27
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
con's avatar
con committed
28
** If you have questions regarding the use of this file, please contact
Tobias Hunger's avatar
Tobias Hunger committed
29
** Nokia at info@qt.nokia.com.
con's avatar
con committed
30
**
31
**************************************************************************/
hjk's avatar
hjk committed
32

con's avatar
con committed
33
#include "breakhandler.h"
34
#include "debuggerinternalconstants.h"
Arvid Ephraim Picciani's avatar
Arvid Ephraim Picciani committed
35
#include "breakpointmarker.h"
con's avatar
con committed
36

37
#include "debuggeractions.h"
38
#include "debuggercore.h"
39
#include "debuggerengine.h"
40
#include "debuggerstringutils.h"
41
#include "stackframe.h"
42

hjk's avatar
hjk committed
43
#include <utils/qtcassert.h>
hjk's avatar
hjk committed
44

hjk's avatar
hjk committed
45
46
47
48
#if USE_BREAK_MODEL_TEST
#include "modeltest.h"
#endif

49
#include <QtCore/QDir>
con's avatar
con committed
50
#include <QtCore/QFileInfo>
hjk's avatar
hjk committed
51
#include <QtCore/QTimerEvent>
con's avatar
con committed
52

53
54
#define BREAK_ASSERT(cond, action) if (cond) {} else { action; }
//#define BREAK_ASSERT(cond, action) QTC_ASSERT(cond, action)
55

con's avatar
con committed
56
57
58
59
60
61
//////////////////////////////////////////////////////////////////
//
// BreakHandler
//
//////////////////////////////////////////////////////////////////

62
63
64
namespace Debugger {
namespace Internal {

65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
static QString stateToString(BreakpointState state)
{
    switch (state) {
        case BreakpointNew:
            return BreakHandler::tr("New");
        case BreakpointInsertRequested:
            return BreakHandler::tr("Insertion requested");
        case BreakpointInsertProceeding:
            return BreakHandler::tr("Insertion proceeding");
        case BreakpointChangeRequested:
            return BreakHandler::tr("Change requested");
        case BreakpointChangeProceeding:
            return BreakHandler::tr("Change proceeding");
        case BreakpointInserted:
            return BreakHandler::tr("Breakpoint inserted");
        case BreakpointRemoveRequested:
            return BreakHandler::tr("Removal requested");
        case BreakpointRemoveProceeding:
            return BreakHandler::tr("Removal proceeding");
        case BreakpointDead:
            return BreakHandler::tr("Dead");
        default:
            break;
    }
    //: Invalid breakpoint state.
    return BreakHandler::tr("<invalid state>");
}

Friedemann Kleint's avatar
Friedemann Kleint committed
93
94
95
96
97
static QString msgBreakpointAtSpecialFunc(const char *func)
{
    return BreakHandler::tr("Breakpoint at \"%1\"").arg(QString::fromAscii(func));
}

98
99
100
101
102
103
104
105
106
107
static QString typeToString(BreakpointType type)
{
    switch (type) {
        case BreakpointByFileAndLine:
            return BreakHandler::tr("Breakpoint by File and Line");
        case BreakpointByFunction:
            return BreakHandler::tr("Breakpoint by Function");
        case BreakpointByAddress:
            return BreakHandler::tr("Breakpoint by Address");
        case BreakpointAtThrow:
Friedemann Kleint's avatar
Friedemann Kleint committed
108
            return msgBreakpointAtSpecialFunc("throw");
109
        case BreakpointAtCatch:
Friedemann Kleint's avatar
Friedemann Kleint committed
110
            return msgBreakpointAtSpecialFunc("catch");
111
        case BreakpointAtFork:
Friedemann Kleint's avatar
Friedemann Kleint committed
112
            return msgBreakpointAtSpecialFunc("fork");
113
        case BreakpointAtExec:
Friedemann Kleint's avatar
Friedemann Kleint committed
114
            return msgBreakpointAtSpecialFunc("exec");
115
116
        //case BreakpointAtVFork:
        //    return msgBreakpointAtSpecialFunc("vfork");
117
        case BreakpointAtSysCall:
Friedemann Kleint's avatar
Friedemann Kleint committed
118
            return msgBreakpointAtSpecialFunc("syscall");
119
120
        case BreakpointAtMain:
            return BreakHandler::tr("Breakpoint at Function \"main()\"");
121
122
123
124
        case WatchpointAtAddress:
            return BreakHandler::tr("Watchpoint at Address");
        case WatchpointAtExpression:
            return BreakHandler::tr("Watchpoint at Expression");
125
126
        case BreakpointOnSignalHandler:
            return BreakHandler::tr("Breakpoint on Signal Handler");
127
128
129
130
131
132
        case UnknownType:
            break;
    }
    return BreakHandler::tr("Unknown Breakpoint Type");
}

133
BreakHandler::BreakHandler()
134
  : m_syncTimerId(-1)
hjk's avatar
hjk committed
135
136
137
138
139
{
#if USE_BREAK_MODEL_TEST
    new ModelTest(this, 0);
#endif
}
con's avatar
con committed
140

hjk's avatar
hjk committed
141
BreakHandler::~BreakHandler()
hjk's avatar
hjk committed
142
{}
hjk's avatar
hjk committed
143

144
145
146
147
148
149
150
151
152
153
154
155
QIcon BreakHandler::breakpointIcon()
{
    static QIcon icon(_(":/debugger/images/breakpoint_16.png"));
    return icon;
}

QIcon BreakHandler::disabledBreakpointIcon()
{
    static QIcon icon(_(":/debugger/images/breakpoint_disabled_16.png"));
    return icon;
}

hjk's avatar
hjk committed
156
QIcon BreakHandler::pendingBreakpointIcon()
157
158
159
160
161
{
    static QIcon icon(_(":/debugger/images/breakpoint_pending_16.png"));
    return icon;
}

hjk's avatar
hjk committed
162
163
164
165
166
167
QIcon BreakHandler::watchpointIcon()
{
    static QIcon icon(_(":/debugger/images/watchpoint.png"));
    return icon;
}

168
169
170
171
172
173
QIcon BreakHandler::tracepointIcon()
{
    static QIcon icon(_(":/debugger/images/tracepoint.png"));
    return icon;
}

174
175
176
177
178
179
180
181
QIcon BreakHandler::emptyIcon()
{
    static QIcon icon(_(":/debugger/images/breakpoint_pending_16.png"));
    //static QIcon icon(_(":/debugger/images/watchpoint.png"));
    //static QIcon icon(_(":/debugger/images/debugger_empty_14.png"));
    return icon;
}

hjk's avatar
hjk committed
182
static inline bool fileNameMatch(const QString &f1, const QString &f2)
hjk's avatar
hjk committed
183
{
hjk's avatar
hjk committed
184
185
186
187
188
#ifdef Q_OS_WIN
    return f1.compare(f2, Qt::CaseInsensitive) == 0;
#else
    return f1 == f2;
#endif
hjk's avatar
hjk committed
189
190
}

191
static bool isSimilarTo(const BreakpointParameters &data, const BreakpointResponse &needle)
con's avatar
con committed
192
{
hjk's avatar
hjk committed
193
194
    // Clear hit.
    // Clear miss.
195
196
    if (needle.type != UnknownType && data.type != UnknownType
            && data.type != needle.type)
hjk's avatar
hjk committed
197
        return false;
con's avatar
con committed
198

hjk's avatar
hjk committed
199
    // Clear hit.
200
    if (data.address && data.address == needle.address)
hjk's avatar
hjk committed
201
202
203
204
        return true;

    // At least at a position we were looking for.
    // FIXME: breaks multiple breakpoints at the same location
205
206
207
    if (!data.fileName.isEmpty()
            && fileNameMatch(data.fileName, needle.fileName)
            && data.lineNumber == needle.lineNumber)
hjk's avatar
hjk committed
208
209
210
211
        return true;

    // At least at a position we were looking for.
    // FIXME: breaks multiple breakpoints at the same location
212
213
214
    if (!data.fileName.isEmpty()
            && fileNameMatch(data.fileName, needle.fileName)
            && data.lineNumber == needle.lineNumber)
hjk's avatar
hjk committed
215
216
217
        return true;

    return false;
con's avatar
con committed
218
219
}

220
BreakpointModelId BreakHandler::findSimilarBreakpoint(const BreakpointResponse &needle) const
con's avatar
con committed
221
{
222
    // Search a breakpoint we might refer to.
223
    ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
hjk's avatar
hjk committed
224
    for ( ; it != et; ++it) {
225
        const BreakpointModelId id = it.key();
226
        const BreakpointParameters &data = it->data;
227
        const BreakpointResponse &response = it->response;
228
        //qDebug() << "COMPARING " << data.toString() << " WITH " << needle.toString();
229
        if (response.id.isValid() && response.id.majorPart() == needle.id.majorPart())
hjk's avatar
hjk committed
230
231
232
233
            return id;

        if (isSimilarTo(data, needle))
            return id;
con's avatar
con committed
234
    }
235
    return BreakpointModelId();
con's avatar
con committed
236
237
}

238
BreakpointModelId BreakHandler::findBreakpointByResponseId(const BreakpointResponseId &id) const
con's avatar
con committed
239
{
240
    ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
hjk's avatar
hjk committed
241
    for ( ; it != et; ++it)
242
        if (it->response.id.majorPart() == id.majorPart())
hjk's avatar
hjk committed
243
            return it.key();
244
    return BreakpointModelId();
con's avatar
con committed
245
246
}

247
BreakpointModelId BreakHandler::findBreakpointByFunction(const QString &functionName) const
248
{
249
    ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
hjk's avatar
hjk committed
250
    for ( ; it != et; ++it)
251
        if (it->data.functionName == functionName)
hjk's avatar
hjk committed
252
            return it.key();
253
    return BreakpointModelId();
hjk's avatar
hjk committed
254
255
}

256
BreakpointModelId BreakHandler::findBreakpointByAddress(quint64 address) const
hjk's avatar
hjk committed
257
{
258
    ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
hjk's avatar
hjk committed
259
    for ( ; it != et; ++it)
260
        if (it->data.address == address || it->response.address == address)
hjk's avatar
hjk committed
261
            return it.key();
262
    return BreakpointModelId();
hjk's avatar
hjk committed
263
264
}

265
BreakpointModelId BreakHandler::findBreakpointByFileAndLine(const QString &fileName,
hjk's avatar
hjk committed
266
267
    int lineNumber, bool useMarkerPosition)
{
268
    ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
hjk's avatar
hjk committed
269
    for ( ; it != et; ++it)
270
        if (it->isLocatedAt(fileName, lineNumber, useMarkerPosition))
hjk's avatar
hjk committed
271
            return it.key();
272
    return BreakpointModelId();
hjk's avatar
hjk committed
273
274
}

275
const BreakpointParameters &BreakHandler::breakpointData(BreakpointModelId id) const
276
{
277
    static BreakpointParameters dummy;
278
    ConstIterator it = m_storage.find(id);
279
    BREAK_ASSERT(it != m_storage.end(), return dummy);
280
    return it->data;
hjk's avatar
hjk committed
281
282
}

283
BreakpointModelId BreakHandler::findWatchpoint(const BreakpointParameters &data) const
hjk's avatar
hjk committed
284
{
285
    ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
hjk's avatar
hjk committed
286
    for ( ; it != et; ++it)
hjk's avatar
hjk committed
287
288
289
        if (it->data.isWatchpoint()
                && it->data.address == data.address
                && it->data.size == data.size
290
                && it->data.expression == data.expression
hjk's avatar
hjk committed
291
                && it->data.bitpos == data.bitpos)
hjk's avatar
hjk committed
292
            return it.key();
293
    return BreakpointModelId();
hjk's avatar
hjk committed
294
295
}

con's avatar
con committed
296
297
void BreakHandler::saveBreakpoints()
{
298
    const QString one = _("1");
299
    //qDebug() << "SAVING BREAKPOINTS...";
300
    QTC_ASSERT(debuggerCore(), return);
con's avatar
con committed
301
    QList<QVariant> list;
302
    ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
hjk's avatar
hjk committed
303
    for ( ; it != et; ++it) {
304
        const BreakpointParameters &data = it->data;
con's avatar
con committed
305
        QMap<QString, QVariant> map;
306
307
308
309
310
311
312
313
314
315
316
317
318
319
        if (data.type != BreakpointByFileAndLine)
            map.insert(_("type"), data.type);
        if (!data.fileName.isEmpty())
            map.insert(_("filename"), data.fileName);
        if (data.lineNumber)
            map.insert(_("linenumber"), data.lineNumber);
        if (!data.functionName.isEmpty())
            map.insert(_("funcname"), data.functionName);
        if (data.address)
            map.insert(_("address"), data.address);
        if (!data.condition.isEmpty())
            map.insert(_("condition"), data.condition);
        if (data.ignoreCount)
            map.insert(_("ignorecount"), data.ignoreCount);
320
        if (data.threadSpec >= 0)
321
322
            map.insert(_("threadspec"), data.threadSpec);
        if (!data.enabled)
323
            map.insert(_("disabled"), one);
324
325
        if (data.pathUsage != BreakpointPathUsageEngineDefault)
            map.insert(_("usefullpath"), QString::number(data.pathUsage));
hjk's avatar
hjk committed
326
        if (data.tracepoint)
327
328
329
            map.insert(_("tracepoint"), one);
        if (!data.module.isEmpty())
            map.insert(_("module"), data.module);
330
331
        if (!data.command.isEmpty())
            map.insert(_("command"), data.command);
332
333
        if (!data.expression.isEmpty())
            map.insert(_("expression"), data.expression);
334
335
        if (!data.message.isEmpty())
            map.insert(_("message"), data.message);
con's avatar
con committed
336
337
        list.append(map);
    }
338
    debuggerCore()->setSessionValue("Breakpoints", list);
339
    //qDebug() << "SAVED BREAKPOINTS" << this << list.size();
con's avatar
con committed
340
341
342
343
}

void BreakHandler::loadBreakpoints()
{
344
    QTC_ASSERT(debuggerCore(), return);
345
    //qDebug() << "LOADING BREAKPOINTS...";
346
    QVariant value = debuggerCore()->sessionValue("Breakpoints");
con's avatar
con committed
347
    QList<QVariant> list = value.toList();
hjk's avatar
hjk committed
348
    //clear();
con's avatar
con committed
349
350
    foreach (const QVariant &var, list) {
        const QMap<QString, QVariant> map = var.toMap();
hjk's avatar
hjk committed
351
        BreakpointParameters data(BreakpointByFileAndLine);
352
        QVariant v = map.value(_("filename"));
353
        if (v.isValid())
hjk's avatar
hjk committed
354
            data.fileName = v.toString();
355
        v = map.value(_("linenumber"));
356
        if (v.isValid())
hjk's avatar
hjk committed
357
            data.lineNumber = v.toString().toInt();
358
        v = map.value(_("condition"));
359
        if (v.isValid())
hjk's avatar
hjk committed
360
            data.condition = v.toString().toLatin1();
361
362
        v = map.value(_("address"));
        if (v.isValid())
hjk's avatar
hjk committed
363
            data.address = v.toString().toULongLong();
364
        v = map.value(_("ignorecount"));
365
        if (v.isValid())
hjk's avatar
hjk committed
366
            data.ignoreCount = v.toString().toInt();
367
        v = map.value(_("threadspec"));
368
        if (v.isValid())
369
            data.threadSpec = v.toString().toInt();
370
        v = map.value(_("funcname"));
371
        if (v.isValid())
hjk's avatar
hjk committed
372
            data.functionName = v.toString();
373
        v = map.value(_("disabled"));
374
        if (v.isValid())
hjk's avatar
hjk committed
375
            data.enabled = !v.toInt();
376
        v = map.value(_("usefullpath"));
377
        if (v.isValid())
378
            data.pathUsage = static_cast<BreakpointPathUsage>(v.toInt());
hjk's avatar
hjk committed
379
380
381
        v = map.value(_("tracepoint"));
        if (v.isValid())
            data.tracepoint = bool(v.toInt());
382
        v = map.value(_("type"));
383
        if (v.isValid() && v.toInt() != UnknownType)
hjk's avatar
hjk committed
384
            data.type = BreakpointType(v.toInt());
385
386
387
        v = map.value(_("module"));
        if (v.isValid())
            data.module = v.toString();
388
389
390
        v = map.value(_("command"));
        if (v.isValid())
            data.command = v.toString();
391
392
393
        v = map.value(_("expression"));
        if (v.isValid())
            data.expression = v.toString();
394
395
396
        v = map.value(_("message"));
        if (v.isValid())
            data.message = v.toString();
hjk's avatar
hjk committed
397
        appendBreakpoint(data);
con's avatar
con committed
398
    }
399
    //qDebug() << "LOADED BREAKPOINTS" << this << list.size();
con's avatar
con committed
400
401
402
403
}

void BreakHandler::updateMarkers()
{
404
    Iterator it = m_storage.begin(), et = m_storage.end();
hjk's avatar
hjk committed
405
    for ( ; it != et; ++it)
406
        it->updateMarker(it.key());
Arvid Ephraim Picciani's avatar
Arvid Ephraim Picciani committed
407
}
hjk's avatar
hjk committed
408

con's avatar
con committed
409
410
411
412
413
414
QVariant BreakHandler::headerData(int section,
    Qt::Orientation orientation, int role) const
{
    if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
        static QString headers[] = {
            tr("Number"),  tr("Function"), tr("File"), tr("Line"),
hjk's avatar
hjk committed
415
            tr("Address"), tr("Condition"), tr("Ignore"), tr("Threads")
con's avatar
con committed
416
417
418
419
420
421
        };
        return headers[section];
    }
    return QVariant();
}

422
BreakpointModelId BreakHandler::findBreakpointByIndex(const QModelIndex &index) const
hjk's avatar
hjk committed
423
{
hjk's avatar
hjk committed
424
425
    //qDebug() << "FIND: " << index <<
    //    BreakpointId::fromInternalId(index.internalId());
426
    return BreakpointModelId::fromInternalId(index.internalId());
hjk's avatar
hjk committed
427
428
}

429
BreakpointModelIds BreakHandler::findBreakpointsByIndex(const QList<QModelIndex> &list) const
430
{
431
    QSet<BreakpointModelId> ids;
432
    foreach (const QModelIndex &index, list)
433
434
        ids.insert(findBreakpointByIndex(index));
    return ids.toList();
435
436
}

437
438
439
440
441
442
Qt::ItemFlags BreakHandler::flags(const QModelIndex &index) const
{
//    switch (index.column()) {
//        //case 0:
//        //    return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled;
//        default:
443
            return QAbstractItemModel::flags(index);
444
445
446
//    }
}

447
QString BreakHandler::displayFromThreadSpec(int spec)
448
{
449
450
451
452
453
454
455
456
    return spec == -1 ? BreakHandler::tr("(all)") : QString::number(spec);
}

int BreakHandler::threadSpecFromDisplay(const QString &str)
{
    bool ok = false;
    int result = str.toInt(&ok);
    return ok ? result : -1;
457
458
}

hjk's avatar
hjk committed
459
460
461
462
463
464
465
QModelIndex BreakHandler::createIndex(int row, int column, quint32 id) const
{
    return QAbstractItemModel::createIndex(row, column, id);
}

QModelIndex BreakHandler::createIndex(int row, int column, void *ptr) const
{
466
    QTC_CHECK(false); // This function is not used.
hjk's avatar
hjk committed
467
468
469
470
471
472
473
    return QAbstractItemModel::createIndex(row, column, ptr);
}

int BreakHandler::columnCount(const QModelIndex &idx) const
{
    if (idx.column() > 0)
        return 0;
474
    const BreakpointModelId id = findBreakpointByIndex(idx);
hjk's avatar
hjk committed
475
476
477
478
479
480
481
482
483
    return id.isMinor() ? 0 : 8;
}

int BreakHandler::rowCount(const QModelIndex &idx) const
{
    if (idx.column() > 0)
        return 0;
    if (!idx.isValid())
        return m_storage.size();
484
    const BreakpointModelId id = findBreakpointByIndex(idx);
hjk's avatar
hjk committed
485
486
487
488
489
    if (id.isMajor())
        return m_storage.value(id).subItems.size();
    return 0;
}

490
491
QModelIndex BreakHandler::index(int row, int col, const QModelIndex &parent) const
{
hjk's avatar
hjk committed
492
493
494
495
    if (row < 0 || col < 0)
        return QModelIndex();
    if (parent.column() > 0)
        return QModelIndex();
496
    BreakpointModelId id = findBreakpointByIndex(parent);
hjk's avatar
hjk committed
497
498
499
500
    if (id.isMajor()) {
        ConstIterator it = m_storage.find(id);
        if (row >= it->subItems.size())
            return QModelIndex();
501
        BreakpointModelId sub = id.child(row);
hjk's avatar
hjk committed
502
503
504
505
506
507
508
509
510
        return createIndex(row, col, sub.toInternalId());
    }
    if (id.isMinor())
        return QModelIndex();
    QTC_ASSERT(!id.isValid(), return QModelIndex());
    if (row >= m_storage.size())
        return QModelIndex();
    id = at(row);
    return createIndex(row, col, id.toInternalId());
511
512
}

hjk's avatar
hjk committed
513
QModelIndex BreakHandler::parent(const QModelIndex &idx) const
514
{
hjk's avatar
hjk committed
515
516
    if (!idx.isValid())
        return QModelIndex();
517
    BreakpointModelId id = findBreakpointByIndex(idx);
hjk's avatar
hjk committed
518
519
520
    if (id.isMajor())
        return QModelIndex();
    if (id.isMinor()) {
521
        BreakpointModelId pid = id.parent();
hjk's avatar
hjk committed
522
523
524
        int row = indexOf(pid);
        return createIndex(row, 0, pid.toInternalId());
    }
525
526
527
    return QModelIndex();
}

con's avatar
con committed
528
529
530
531
QVariant BreakHandler::data(const QModelIndex &mi, int role) const
{
    static const QString empty = QString(QLatin1Char('-'));

532
533
534
    if (!mi.isValid())
        return QVariant();

535
    BreakpointModelId id = findBreakpointByIndex(mi);
hjk's avatar
hjk committed
536

537
    BreakpointModelId pid = id;
hjk's avatar
hjk committed
538
539
540
541
542
    if (id.isMinor())
        pid = id.parent();

    ConstIterator it = m_storage.find(pid);
    QTC_ASSERT(it != m_storage.end(), return QVariant());
543
    const BreakpointParameters &data = it->data;
544
    const BreakpointResponse &response = it->response;
545

546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
    bool orig = false;
    switch (it->state) {
        case BreakpointInsertRequested:
        case BreakpointInsertProceeding:
        case BreakpointChangeRequested:
        case BreakpointChangeProceeding:
        case BreakpointInserted:
        case BreakpointRemoveRequested:
        case BreakpointRemoveProceeding:
            break;
        case BreakpointNew:
        case BreakpointDead:
            orig = true;
            break;
    };

hjk's avatar
hjk committed
562
563
564
565
566
567
568
569
570
571
    if (id.isMinor()) {
        QTC_ASSERT(id.minorPart() <= it->subItems.size(), return QVariant());
        const BreakpointResponse &res = it->subItems.at(id.minorPart() - 1);
        switch (mi.column()) {
        case 0:
            if (role == Qt::DisplayRole)
                return id.toString();
        case 1:
            if (role == Qt::DisplayRole)
                return res.functionName;
572
573
574
575
        case 4:
            if (role == Qt::DisplayRole)
                if (res.address)
                    return QString::fromAscii("0x%1").arg(res.address, 0, 16);
hjk's avatar
hjk committed
576
577
578
579
        }
        return QVariant();
    }

con's avatar
con committed
580
581
    switch (mi.column()) {
        case 0:
582
            if (role == Qt::DisplayRole)
hjk's avatar
hjk committed
583
                return id.toString();
584
585
            if (role == Qt::DecorationRole)
                return it->icon();
con's avatar
con committed
586
587
588
            break;
        case 1:
            if (role == Qt::DisplayRole) {
589
590
591
592
                if (!response.functionName.isEmpty())
                    return response.functionName;
                if (!data.functionName.isEmpty())
                    return data.functionName;
593
594
595
596
597
                if (data.type == BreakpointAtMain
                        || data.type == BreakpointAtThrow
                        || data.type == BreakpointAtCatch
                        || data.type == BreakpointAtFork
                        || data.type == BreakpointAtExec
598
                        //|| data.type == BreakpointAtVFork
599
600
                        || data.type == BreakpointAtSysCall)
                    return typeToString(data.type);
601
                if (data.type == WatchpointAtAddress)
602
                    return tr("Data at 0x%1").arg(data.address, 0, 16);
603
                if (data.type == WatchpointAtExpression)
604
                    return tr("Data at %1").arg(data.expression);
605
                return empty;
con's avatar
con committed
606
607
608
609
            }
            break;
        case 2:
            if (role == Qt::DisplayRole) {
610
611
612
613
                QString str;
                if (!response.fileName.isEmpty())
                    str = response.fileName;
                if (str.isEmpty() && !data.fileName.isEmpty())
614
                    str = data.fileName;
615
616
617
618
619
                if (str.isEmpty()) {
                    QString s = QFileInfo(str).fileName();
                    if (!s.isEmpty())
                        str = s;
                }
hjk's avatar
hjk committed
620
                // FIXME: better?
621
622
                //if (data.multiple && str.isEmpty() && !response.fileName.isEmpty())
                //    str = response.fileName;
623
                if (!str.isEmpty())
624
                    return QDir::toNativeSeparators(str);
625
                return empty;
con's avatar
con committed
626
627
628
629
            }
            break;
        case 3:
            if (role == Qt::DisplayRole) {
630
631
632
633
634
                if (response.lineNumber > 0)
                    return response.lineNumber;
                if (data.lineNumber > 0)
                    return data.lineNumber;
                return empty;
con's avatar
con committed
635
            }
636
            if (role == Qt::UserRole + 1)
637
                return data.lineNumber;
con's avatar
con committed
638
639
            break;
        case 4:
hjk's avatar
hjk committed
640
641
642
            if (role == Qt::DisplayRole) {
                const quint64 address = orig ? data.address : response.address;
                if (address)
643
644
                    return QString::fromAscii("0x%1").arg(address, 0, 16);
                return QVariant();
hjk's avatar
hjk committed
645
646
647
            }
            break;
        case 5:
con's avatar
con committed
648
            if (role == Qt::DisplayRole)
649
                return orig ? data.condition : response.condition;
con's avatar
con committed
650
651
            if (role == Qt::ToolTipRole)
                return tr("Breakpoint will only be hit if this condition is met.");
652
            if (role == Qt::UserRole + 1)
653
                return data.condition;
con's avatar
con committed
654
            break;
hjk's avatar
hjk committed
655
        case 6:
656
            if (role == Qt::DisplayRole) {
hjk's avatar
hjk committed
657
                const int ignoreCount =
658
                    orig ? data.ignoreCount : response.ignoreCount;
659
660
                return ignoreCount ? QVariant(ignoreCount) : QVariant(QString());
            }
con's avatar
con committed
661
662
            if (role == Qt::ToolTipRole)
                return tr("Breakpoint will only be hit after being ignored so many times.");
663
            if (role == Qt::UserRole + 1)
664
                return data.ignoreCount;
665
            break;
hjk's avatar
hjk committed
666
        case 7:
667
            if (role == Qt::DisplayRole)
668
                return displayFromThreadSpec(orig ? data.threadSpec : response.threadSpec);
669
670
671
            if (role == Qt::ToolTipRole)
                return tr("Breakpoint will only be hit in the specified thread(s).");
            if (role == Qt::UserRole + 1)
672
                return displayFromThreadSpec(data.threadSpec);
673
            break;
con's avatar
con committed
674
    }
675
676
677
678
679
680
681
682
683
684
685
686
    switch (role) {
    case Qt::ToolTipRole:
        if (debuggerCore()->boolSetting(UseToolTipsInBreakpointsView))
                return QVariant(it->toToolTip());
        break;
    case EngineCapabilitiesRole:  {
        const unsigned caps = it.value().engine ?
                              it.value().engine->debuggerCapabilities() :
                              unsigned(AllDebuggerCapabilities);
        return QVariant(caps);
    }
    }
con's avatar
con committed
687
688
689
    return QVariant();
}

hjk's avatar
hjk committed
690
#define GETTER(type, getter) \
691
type BreakHandler::getter(BreakpointModelId id) const \
hjk's avatar
hjk committed
692
{ \
693
    ConstIterator it = m_storage.find(id); \
694
    BREAK_ASSERT(it != m_storage.end(), \
695
696
        qDebug() << "ID" << id << "NOT KNOWN"; \
        return type()); \
697
    return it->data.getter; \
698
699
}

700
#define SETTER(type, getter, setter) \
701
void BreakHandler::setter(BreakpointModelId id, const type &value) \
hjk's avatar
hjk committed
702
{ \
703
    Iterator it = m_storage.find(id); \
704
    BREAK_ASSERT(it != m_storage.end(), \
705
        qDebug() << "ID" << id << "NOT KNOWN"; return); \
706
    if (it->data.getter == value) \
707
        return; \
708
    it->data.getter = value; \
709
710
711
712
    if (it->state != BreakpointNew) { \
        it->state = BreakpointChangeRequested; \
        scheduleSynchronization(); \
    } \
713
714
}

hjk's avatar
hjk committed
715
716
#define PROPERTY(type, getter, setter) \
    GETTER(type, getter) \
717
    SETTER(type, getter, setter)
Friedemann Kleint's avatar
Friedemann Kleint committed
718

con's avatar
con committed
719

720
PROPERTY(BreakpointPathUsage, pathUsage, setPathUsage)
hjk's avatar
hjk committed
721
722
723
PROPERTY(QString, fileName, setFileName)
PROPERTY(QString, functionName, setFunctionName)
PROPERTY(BreakpointType, type, setType)
724
PROPERTY(int, threadSpec, setThreadSpec)
hjk's avatar
hjk committed
725
PROPERTY(QByteArray, condition, setCondition)
726
GETTER(int, lineNumber)
hjk's avatar
hjk committed
727
PROPERTY(quint64, address, setAddress)
728
PROPERTY(QString, expression, setExpression)
729
PROPERTY(QString, message, setMessage)
730
PROPERTY(int, ignoreCount, setIgnoreCount)
hjk's avatar
hjk committed
731

732
bool BreakHandler::isEnabled(BreakpointModelId id) const
733
734
{
    ConstIterator it = m_storage.find(id);
735
    BREAK_ASSERT(it != m_storage.end(), return false);
736
    return it->data.enabled;
737
738
}

739
void BreakHandler::setEnabled(BreakpointModelId id, bool on)
740
741
{
    Iterator it = m_storage.find(id);
742
    BREAK_ASSERT(it != m_storage.end(), return);
743
    //qDebug() << "SET ENABLED: " << id << it->data.isEnabled() << on;
744
745
746
747
    if (it->data.enabled == on)
        return;
    it->data.enabled = on;
    it->destroyMarker();
748
    it->updateMarker(id);
749
750
751
752
    if (it->engine) {
        it->state = BreakpointChangeRequested;
        scheduleSynchronization();
    }
753
754
}

755
bool BreakHandler::isWatchpoint(BreakpointModelId id) const
756
757
758
759
760
761
{
    ConstIterator it = m_storage.find(id);
    BREAK_ASSERT(it != m_storage.end(), return false);
    return it->data.isWatchpoint();
}

762
bool BreakHandler::isTracepoint(BreakpointModelId id) const
hjk's avatar
hjk committed
763
764
{
    ConstIterator it = m_storage.find(id);
765
    BREAK_ASSERT(it != m_storage.end(), return false);
hjk's avatar
hjk committed
766
767
768
    return it->data.tracepoint;
}

769
770
771
772
773
774
775
bool BreakHandler::needsChildren(BreakpointModelId id) const
{
    ConstIterator it = m_storage.find(id);
    BREAK_ASSERT(it != m_storage.end(), return false);
    return it->response.multiple && it->subItems.isEmpty();
}

776
void BreakHandler::setTracepoint(BreakpointModelId id, bool on)
hjk's avatar
hjk committed
777
778
{
    Iterator it = m_storage.find(id);
779
    BREAK_ASSERT(it != m_storage.end(), return);
hjk's avatar
hjk committed
780
781
782
783
    if (it->data.tracepoint == on)
        return;
    it->data.tracepoint = on;
    it->destroyMarker();
784
    it->updateMarker(id);
785
786
787
788
789

    if (it->engine) {
        it->state = BreakpointChangeRequested;
        scheduleSynchronization();
    }
hjk's avatar
hjk committed
790
791
}

792
void BreakHandler::setMarkerFileAndLine(BreakpointModelId id,
793
794
795
    const QString &fileName, int lineNumber)
{
    Iterator it = m_storage.find(id);
796
797
    BREAK_ASSERT(it != m_storage.end(),
        qDebug() << "MARKER_FILE_AND_LINE: " << id; return);
798
    if (it->response.fileName == fileName && it->response.lineNumber == lineNumber)
799
800
801
        return;
    it->response.fileName = fileName;
    it->response.lineNumber = lineNumber;
802
    it->destroyMarker();
803
    it->updateMarker(id);
804
    emit layoutChanged();
805
806
}

807
BreakpointState BreakHandler::state(BreakpointModelId id) const
808
809
{
    ConstIterator it = m_storage.find(id);
810
811
    BREAK_ASSERT(it != m_storage.end(),
        qDebug() << "STATE: " << id; return BreakpointDead);
812
813
814
    return it->state;
}

815
DebuggerEngine *BreakHandler::engine(BreakpointModelId id) const
816
817
{
    ConstIterator it = m_storage.find(id);
818
    BREAK_ASSERT(it != m_storage.end(), qDebug() << id; return 0);
819
820
821
    return it->engine;
}

822
void BreakHandler::setEngine(BreakpointModelId id, DebuggerEngine *value)
823
824
{
    Iterator it = m_storage.find(id);
825
826
827
    BREAK_ASSERT(it != m_storage.end(), qDebug() << "SET ENGINE" << id; return);
    QTC_ASSERT(it->state == BreakpointNew, qDebug() << "STATE: " << it->state <<id);
    QTC_ASSERT(!it->engine, qDebug() << "NO ENGINE" << id; return);
828
829
    it->engine = value;
    it->state = BreakpointInsertRequested;
830
    it->response = BreakpointResponse();
831
    it->updateMarker(id);
832
833
834
835
836
837
838
839
840
841
842
843
    scheduleSynchronization();
}

static bool isAllowedTransition(BreakpointState from, BreakpointState to)
{
    switch (from) {
    case BreakpointNew:
        return to == BreakpointInsertRequested;
    case BreakpointInsertRequested:
        return to == BreakpointInsertProceeding;
    case BreakpointInsertProceeding:
        return to == BreakpointInserted
844
845
            || to == BreakpointDead
            || to == BreakpointChangeRequested;
846
847
848
849
850
851
    case BreakpointChangeRequested:
        return to == BreakpointChangeProceeding;
    case BreakpointChangeProceeding:
        return to == BreakpointInserted
            || to == BreakpointDead;
    case BreakpointInserted:
852
853
        return to == BreakpointChangeRequested
            || to == BreakpointRemoveRequested;
854
    case BreakpointRemoveRequested:
855
        return to == BreakpointRemoveProceeding;
856
    case BreakpointRemoveProceeding:
857
        return to == BreakpointDead;
858
859
860
861
862
863
864
    case BreakpointDead:
        return false;
    }
    qDebug() << "UNKNOWN BREAKPOINT STATE:" << from;
    return false;
}

865
bool BreakHandler::isEngineRunning(BreakpointModelId id) const
866
867
868
869
870
871
872
873
{
    if (const DebuggerEngine *e = engine(id)) {
        const DebuggerState state = e->state();
        return state != DebuggerFinished && state != DebuggerNotReady;
    }
    return false;
}

874
void BreakHandler::setState(BreakpointModelId id, BreakpointState state)
875
876
{
    Iterator it = m_storage.find(id);
877
878
    //qDebug() << "BREAKPOINT STATE TRANSITION, ID: " << id
    //    << " FROM: " << it->state << " TO: " << state;
879
    BREAK_ASSERT(it != m_storage.end(), qDebug() << id; return);
880
881
882
883
    QTC_ASSERT(isAllowedTransition(it->state, state),
        qDebug() << "UNEXPECTED BREAKPOINT STATE TRANSITION"
            << it->state << state);

hjk's avatar
hjk committed
884
885
886
887
    if (it->state == state) {
        qDebug() << "STATE UNCHANGED: " << id << state;
        return;
    }
888

889
    it->state = state;
890
891
892
893

    // FIXME: updateMarker() should recognize t