qttypes.py 84.7 KB
Newer Older
hjk's avatar
hjk committed
1
############################################################################
hjk's avatar
hjk committed
2
#
3
# Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
# Contact: http://www.qt-project.org/legal
hjk's avatar
hjk committed
5
#
hjk's avatar
hjk committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# This file is part of Qt Creator.
#
# Commercial License Usage
# Licensees holding valid commercial Qt licenses may use this file in
# accordance with the commercial license agreement provided with the
# Software or, alternatively, in accordance with the terms contained in
# a written agreement between you and Digia.  For licensing terms and
# conditions see http://qt.digia.com/licensing.  For further information
# use the contact form at http://qt.digia.com/contact-us.
#
# 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.
#
# In addition, as a special exception, Digia gives you certain additional
# rights.  These rights are described in the Digia Qt LGPL Exception
# version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
#
#############################################################################
hjk's avatar
hjk committed
29

30
from dumper import *
hjk's avatar
hjk committed
31
32
33


def qdump__QAtomicInt(d, value):
hjk's avatar
hjk committed
34
    d.putValue(int(value["_q_value"]))
hjk's avatar
hjk committed
35
36
37
38
    d.putNumChild(0)


def qdump__QBasicAtomicInt(d, value):
hjk's avatar
hjk committed
39
    d.putValue(int(value["_q_value"]))
hjk's avatar
hjk committed
40
41
42
    d.putNumChild(0)


hjk's avatar
hjk committed
43
def qdump__QAtomicPointer(d, value):
hjk's avatar
hjk committed
44
    d.putType(value.type)
hjk's avatar
hjk committed
45
46
47
48
    q = value["_q_value"]
    p = int(q)
    d.putValue("@0x%x" % p)
    d.putNumChild(1 if p else 0)
hjk's avatar
hjk committed
49
50
    if d.isExpanded():
        with Children(d):
hjk's avatar
hjk committed
51
           d.putSubItem("_q_value", q.dereference())
hjk's avatar
hjk committed
52

53
54
55
def qform__QByteArray():
    return "Inline,As Latin1 in Separate Window,As UTF-8 in Separate Window"

hjk's avatar
hjk committed
56
57
def qdump__QByteArray(d, value):
    d.putByteArrayValue(value)
hjk's avatar
hjk committed
58
    data, size, alloc = d.byteArrayData(value)
59
    d.putNumChild(size)
60
61
62
63
    format = d.currentItemFormat()
    if format == 1:
        d.putDisplay(StopDisplay)
    elif format == 2:
64
        d.putField("editformat", DisplayLatin1String)
65
        d.putField("editvalue", d.encodeByteArray(value))
66
    elif format == 3:
67
        d.putField("editformat", DisplayUtf8String)
68
        d.putField("editvalue", d.encodeByteArray(value))
hjk's avatar
hjk committed
69
    if d.isExpanded():
70
        d.putArrayData(d.charType(), data, size)
hjk's avatar
hjk committed
71

hjk's avatar
hjk committed
72
73
74
75
76
77
78
79
def qdump__QByteArrayData(d, value):
    data, size, alloc = d.byteArrayDataHelper(d.addressOf(value))
    d.putValue(d.readMemory(data, size), Hex2EncodedLatin1)
    d.putNumChild(1)
    if d.isExpanded():
        with Children(d):
            d.putIntItem("size", size)
            d.putIntItem("alloc", alloc)
hjk's avatar
hjk committed
80

hjk's avatar
hjk committed
81
def qdump__QChar(d, value):
hjk's avatar
hjk committed
82
    d.putValue(int(value["ucs"]))
hjk's avatar
hjk committed
83
84
85
    d.putNumChild(0)


hjk's avatar
hjk committed
86
def qform__QAbstractItemModel():
87
    return "Normal,Enhanced"
88

hjk's avatar
hjk committed
89
def qdump__QAbstractItemModel(d, value):
90
91
92
93
94
    format = d.currentItemFormat()
    if format == 1:
        d.putPlainChildren(value)
        return
    #format == 2:
95
    # Create a default-constructed QModelIndex on the stack.
96
    try:
97
        ri = d.makeValue(d.qtNamespace() + "QModelIndex", "-1, -1, 0, 0")
hjk's avatar
hjk committed
98
99
        this_ = d.makeExpression(value)
        ri_ = d.makeExpression(ri)
100
101
        rowCount = int(d.parseAndEvaluate("%s.rowCount(%s)" % (this_, ri_)))
        columnCount = int(d.parseAndEvaluate("%s.columnCount(%s)" % (this_, ri_)))
102
    except:
hjk's avatar
hjk committed
103
        d.putPlainChildren(value)
104
        return
105
106
    d.putValue("%d x %d" % (rowCount, columnCount))
    d.putNumChild(rowCount * columnCount)
hjk's avatar
hjk committed
107
108
    if d.isExpanded():
        with Children(d, numChild=rowCount * columnCount, childType=ri.type):
109
110
111
            i = 0
            for row in xrange(rowCount):
                for column in xrange(columnCount):
hjk's avatar
hjk committed
112
                    with SubItem(d, i):
113
                        d.putName("[%s, %s]" % (row, column))
114
                        mi = d.parseAndEvaluate("%s.index(%d,%d,%s)"
115
116
117
118
                            % (this_, row, column, ri_))
                        #warn("MI: %s " % mi)
                        #name = "[%d,%d]" % (row, column)
                        #d.putValue("%s" % mi)
hjk's avatar
hjk committed
119
                        d.putItem(mi)
120
121
122
123
124
125
126
127
                        i = i + 1
                        #warn("MI: %s " % mi)
                        #d.putName("[%d,%d]" % (row, column))
                        #d.putValue("%s" % mi)
                        #d.putNumChild(0)
                        #d.putType(mi.type)
    #gdb.execute("call free($ri)")

128
129
130
def qform__QModelIndex():
    return "Normal,Enhanced"

hjk's avatar
hjk committed
131
def qdump__QModelIndex(d, value):
132
133
134
135
    format = d.currentItemFormat()
    if format == 1:
        d.putPlainChildren(value)
        return
hjk's avatar
hjk committed
136
137
    r = value["r"]
    c = value["c"]
138
139
140
141
    try:
        p = value["p"]
    except:
        p = value["i"]
hjk's avatar
hjk committed
142
    m = value["m"]
143
    if d.isNull(m) or r < 0 or c < 0:
144
145
146
147
        d.putValue("(invalid)")
        d.putPlainChildren(value)
        return

148
149
    mm = m.dereference()
    mm = mm.cast(mm.type.unqualified())
150
    ns = d.qtNamespace()
151
    try:
152
        mi = d.makeValue(ns + "QModelIndex", "%s,%s,%s,%s" % (r, c, p, m))
hjk's avatar
hjk committed
153
154
        mm_ = d.makeExpression(mm)
        mi_ = d.makeExpression(mi)
155
156
        rowCount = int(d.parseAndEvaluate("%s.rowCount(%s)" % (mm_, mi_)))
        columnCount = int(d.parseAndEvaluate("%s.columnCount(%s)" % (mm_, mi_)))
157
    except:
158
        d.putEmptyValue()
hjk's avatar
hjk committed
159
        d.putPlainChildren(value)
160
        return
161
162
163

    try:
        # Access DisplayRole as value
164
        val = d.parseAndEvaluate("%s.data(%s, 0)" % (mm_, mi_))
hjk's avatar
hjk committed
165
        v = val["d"]["data"]["ptr"]
166
        d.putStringValue(d.makeValue(ns + 'QString', v))
167
    except:
hjk's avatar
hjk committed
168
        d.putValue("")
169

170
171
172
173
174
175
176
177
    d.putNumChild(rowCount * columnCount)
    if d.isExpanded():
        with Children(d):
            i = 0
            for row in xrange(rowCount):
                for column in xrange(columnCount):
                    with UnnamedSubItem(d, i):
                        d.putName("[%s, %s]" % (row, column))
178
                        mi2 = d.parseAndEvaluate("%s.index(%d,%d,%s)"
179
180
181
182
183
184
                            % (mm_, row, column, mi_))
                        d.putItem(mi2)
                        i = i + 1
            #d.putCallItem("parent", val, "parent")
            #with SubItem(d, "model"):
            #    d.putValue(m)
185
            #    d.putType(ns + "QAbstractItemModel*")
186
            #    d.putNumChild(1)
187
188
    #gdb.execute("call free($mi)")

hjk's avatar
hjk committed
189

hjk's avatar
hjk committed
190
def qdump__QDate(d, value):
191
    jd = int(value["jd"])
192
    if jd:
193
194
195
196
197
        d.putValue(jd, JulianDate)
        d.putNumChild(1)
        if d.isExpanded():
            # FIXME: This improperly uses complex return values.
            with Children(d):
198
199
200
201
                d.putCallItem("toString", value, "toString",
                    d.enumExpression("DateFormat", "TextDate"))
                d.putCallItem("(ISO)", value, "toString",
                    d.enumExpression("DateFormat", "ISODate"))
202
                d.putCallItem("(SystemLocale)", value, "toString",
203
204
205
                    d.enumExpression("DateFormat", "SystemLocaleDate"))
                d.putCallItem("(Locale)", value, "toString",
                    d.enumExpression("DateFormat", "LocaleDate"))
206
207
208
    else:
        d.putValue("(invalid)")
        d.putNumChild(0)
hjk's avatar
hjk committed
209
210


hjk's avatar
hjk committed
211
def qdump__QTime(d, value):
hjk's avatar
hjk committed
212
213
214
    mds = int(value["mds"])
    if mds >= 0:
        d.putValue(mds, MillisecondsSinceMidnight)
215
216
217
218
        d.putNumChild(1)
        if d.isExpanded():
            # FIXME: This improperly uses complex return values.
            with Children(d):
219
220
221
222
                d.putCallItem("toString", value, "toString",
                    d.enumExpression("DateFormat", "TextDate"))
                d.putCallItem("(ISO)", value, "toString",
                    d.enumExpression("DateFormat", "ISODate"))
223
                d.putCallItem("(SystemLocale)", value, "toString",
224
225
226
                    d.enumExpression("DateFormat", "SystemLocaleDate"))
                d.putCallItem("(Locale)", value, "toString",
                    d.enumExpression("DateFormat", "LocaleDate"))
227
228
229
    else:
        d.putValue("(invalid)")
        d.putNumChild(0)
230
231


hjk's avatar
hjk committed
232
def qdump__QTimeZone(d, value):
233
    base = d.extractPointer(value)
234
    if base == 0:
hjk's avatar
hjk committed
235
236
237
238
239
240
241
242
        d.putValue("(null)")
        d.putNumChild(0)
        return
    idAddr = base + 2 * d.ptrSize() # [QSharedData] + [vptr]
    d.putByteArrayValueByAddress(idAddr)
    d.putPlainChildren(value["d"])


hjk's avatar
hjk committed
243
def qdump__QDateTime(d, value):
244
245
246
247
    qtVersion = d.qtVersion()
    isValid = False
    # This relies on the Qt4/Qt5 internal structure layout:
    # {sharedref(4), ...
248
    base = d.extractPointer(value)
249
    if qtVersion >= 0x050200:
250
        dateBase = base + d.ptrSize() # Only QAtomicInt, but will be padded.
251
252
253
254
255
256
        # qint64 m_msecs
        # Qt::TimeSpec m_spec
        # int m_offsetFromUtc
        # QTimeZone m_timeZone // only #ifndef QT_BOOTSTRAPPED
        # StatusFlags m_status
        status = d.extractInt(dateBase + 16 + d.ptrSize())
257
        if int(status & 0x0c == 0x0c): # ValidDate and ValidTime
258
259
260
261
            isValid = True
            msecs = d.extractInt64(dateBase)
            spec = d.extractInt(dateBase + 8)
            offset = d.extractInt(dateBase + 12)
262
            tzp = d.extractPointer(dateBase + 16)
263
264
265
266
            if tzp == 0:
                tz = ""
            else:
                idBase = tzp + 2 * d.ptrSize() # [QSharedData] + [vptr]
267
                tz = d.encodeByteArrayHelper(d.extractPointer(idBase))
268
269
            d.putValue("%s/%s/%s/%s/%s" % (msecs, spec, offset, tz, status),
                DateTimeInternal)
270
271
272
273
274
275
    else:
        # This relies on the Qt4/Qt5 internal structure layout:
        # {sharedref(4), date(8), time(4+x)}
        # QDateTimePrivate:
        # - QAtomicInt ref;    (padded on 64 bit)
        # -     [QDate date;]
276
        # -      -  uint jd in Qt 4,  qint64 in Qt 5.0 and Qt 5.1; padded on 64 bit
277
278
279
        # -     [QTime time;]
        # -      -  uint mds;
        # -  Spec spec;
280
281
282
283
        dateSize = 8 if qtVersion >= 0x050000 else 4 # Qt5: qint64, Qt4 uint
        # 4 byte padding after 4 byte QAtomicInt if we are on 64 bit and QDate is 64 bit
        refPlusPadding = 8 if qtVersion >= 0x050000 and not d.is32bit() else 4
        dateBase = base + refPlusPadding
284
285
286
287
288
289
290
        timeBase = dateBase + dateSize
        mds = d.extractInt(timeBase)
        isValid = mds > 0
        if isValid:
            jd = d.extractInt(dateBase)
            d.putValue("%s/%s" % (jd, mds), JulianDateAndMillisecondsSinceMidnight)
    if isValid:
291
292
293
294
295
        d.putNumChild(1)
        if d.isExpanded():
            # FIXME: This improperly uses complex return values.
            with Children(d):
                d.putCallItem("toTime_t", value, "toTime_t")
296
297
298
299
300
301
302
303
304
305
306
307
                d.putCallItem("toString", value, "toString",
                    d.enumExpression("DateFormat", "TextDate"))
                d.putCallItem("(ISO)", value, "toString",
                    d.enumExpression("DateFormat", "ISODate"))
                d.putCallItem("(SystemLocale)", value, "toString",
                    d.enumExpression("DateFormat", "SystemLocaleDate"))
                d.putCallItem("(Locale)", value, "toString",
                    d.enumExpression("DateFormat", "LocaleDate"))
                d.putCallItem("toUTC", value, "toTimeSpec",
                    d.enumExpression("TimeSpec", "UTC"))
                d.putCallItem("toLocalTime", value, "toTimeSpec",
                    d.enumExpression("TimeSpec", "LocalTime"))
308
309
310
    else:
        d.putValue("(invalid)")
        d.putNumChild(0)
hjk's avatar
hjk committed
311
312
313


def qdump__QDir(d, value):
hjk's avatar
hjk committed
314
    d.putNumChild(1)
315
    privAddress = d.extractPointer(value)
316
317
    bit32 = d.is32bit()
    qt5 = d.qtVersion() >= 0x050000
318
319
320
321
322
323
324
325
326
327

    # Change 9fc0965 reorders members again.
    #  bool fileListsInitialized;\n"
    #  QStringList files;\n"
    #  QFileInfoList fileInfos;\n"
    #  QStringList nameFilters;\n"
    #  QDir::SortFlags sort;\n"
    #  QDir::Filters filters;\n"

    # Before 9fc0965:
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
    # QDirPrivate:
    # QAtomicInt ref
    # QStringList nameFilters;
    # QDir::SortFlags sort;
    # QDir::Filters filters;
    # // qt3support:
    # QChar filterSepChar;
    # bool matchAllDirs;
    # // end qt3support
    # QScopedPointer<QAbstractFileEngine> fileEngine;
    # bool fileListsInitialized;
    # QStringList files;
    # QFileInfoList fileInfos;
    # QFileSystemEntry dirEntry;
    # QFileSystemEntry absoluteDirEntry;
343

344
345
346
347
348
349
350
351
    # QFileSystemEntry:
    # QString m_filePath
    # QByteArray m_nativeFilePath
    # qint16 m_lastSeparator
    # qint16 m_firstDotInFileName
    # qint16 m_lastDotInFileName
    # + 2 byte padding
    fileSystemEntrySize = 2 * d.ptrSize() + 8
352

353
354
355
356
357
    if d.qtVersion() < 0x050200:
        case = 0
    elif d.qtVersion() >= 0x050300:
        case = 1
    else:
358
        # Try to distinguish bool vs QStringList at the first item
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
        # after the (padded) refcount. If it looks like a bool assume
        # this is after 9fc0965. This is not safe.
        firstValue = d.extractInt(privAddress + d.ptrSize())
        case = 1 if firstValue == 0 or firstValue == 1 else 0

    if case == 1:
        if bit32:
            filesOffset = 4
            fileInfosOffset = 8
            dirEntryOffset = 0x20
            absoluteDirEntryOffset = 0x30
        else:
            filesOffset = 0x08
            fileInfosOffset = 0x10
            dirEntryOffset = 0x30
            absoluteDirEntryOffset = 0x48
    else:
376
377
378
379
380
381
382
383
        # Assume this is before 9fc0965.
        qt3support = d.isQt3Support()
        qt3SupportAddition = d.ptrSize() if qt3support else 0
        filesOffset = (24 if bit32 else 40) + qt3SupportAddition
        fileInfosOffset = filesOffset + d.ptrSize()
        dirEntryOffset = fileInfosOffset + d.ptrSize()
        absoluteDirEntryOffset = dirEntryOffset + fileSystemEntrySize

384
    d.putStringValueByAddress(privAddress + dirEntryOffset)
hjk's avatar
hjk committed
385
386
    if d.isExpanded():
        with Children(d):
387
            ns = d.qtNamespace()
388
            d.call(value, "count")  # Fill cache.
389
390
391
            #d.putCallItem("absolutePath", value, "absolutePath")
            #d.putCallItem("canonicalPath", value, "canonicalPath")
            with SubItem(d, "absolutePath"):
392
                typ = d.lookupType(ns + "QString")
393
                d.putItem(d.createValue(privAddress + absoluteDirEntryOffset, typ))
394
            with SubItem(d, "entryInfoList"):
395
                typ = d.lookupType(ns + "QList<" + ns + "QFileInfo>")
396
                d.putItem(d.createValue(privAddress + fileInfosOffset, typ))
397
            with SubItem(d, "entryList"):
398
                typ = d.lookupType(ns + "QStringList")
399
                d.putItem(d.createValue(privAddress + filesOffset, typ))
hjk's avatar
hjk committed
400
401


hjk's avatar
hjk committed
402
def qdump__QFile(d, value):
hjk's avatar
hjk committed
403
404
    # 9fc0965 changes the layout of the private structure
    qtVersion = d.qtVersion()
405
    if qtVersion >= 0x050200:
406
        offset = 176 if d.is32bit() else 272
hjk's avatar
hjk committed
407
    elif qtVersion >= 0x050000:
408
        offset = 180 if d.is32bit() else 280
hjk's avatar
hjk committed
409
410
    else:
        offset = 140 if d.is32bit() else 232
411
    privAddress = d.extractPointer(d.addressOf(value) + d.ptrSize())
hjk's avatar
hjk committed
412
    fileNameAddress = privAddress + offset
413
    d.putStringValueByAddress(fileNameAddress)
hjk's avatar
hjk committed
414
    d.putNumChild(1)
hjk's avatar
hjk committed
415
416
    if d.isExpanded():
        with Children(d):
hjk's avatar
hjk committed
417
            d.putCallItem("exists", value, "exists")
hjk's avatar
hjk committed
418
            d.putFields(value)
hjk's avatar
hjk committed
419
420


hjk's avatar
hjk committed
421
def qdump__QFileInfo(d, value):
422
    privAddress = d.extractPointer(value)
423
424
425
426
427
428
429
430
    #bit32 = d.is32bit()
    #qt5 = d.qtVersion() >= 0x050000
    #try:
    #    d.putStringValue(value["d_ptr"]["d"].dereference()["fileNames"][3])
    #except:
    #    d.putPlainChildren(value)
    #    return
    filePathAddress = privAddress + d.ptrSize()
431
    d.putStringValueByAddress(filePathAddress)
hjk's avatar
hjk committed
432
    d.putNumChild(1)
hjk's avatar
hjk committed
433
    if d.isExpanded():
434
435
        ns = d.qtNamespace()
        with Children(d, childType=d.lookupType(ns + "QString")):
hjk's avatar
hjk committed
436
437
438
439
440
441
442
            d.putCallItem("absolutePath", value, "absolutePath")
            d.putCallItem("absoluteFilePath", value, "absoluteFilePath")
            d.putCallItem("canonicalPath", value, "canonicalPath")
            d.putCallItem("canonicalFilePath", value, "canonicalFilePath")
            d.putCallItem("completeBaseName", value, "completeBaseName")
            d.putCallItem("completeSuffix", value, "completeSuffix")
            d.putCallItem("baseName", value, "baseName")
443
444
            if False:
                #ifdef Q_OS_MACX
hjk's avatar
hjk committed
445
446
447
448
                d.putCallItem("isBundle", value, "isBundle")
                d.putCallItem("bundleName", value, "bundleName")
            d.putCallItem("fileName", value, "fileName")
            d.putCallItem("filePath", value, "filePath")
449
            # Crashes gdb (archer-tromey-python, at dad6b53fe)
hjk's avatar
hjk committed
450
451
452
            #d.putCallItem("group", value, "group")
            #d.putCallItem("owner", value, "owner")
            d.putCallItem("path", value, "path")
453

hjk's avatar
hjk committed
454
455
            d.putCallItem("groupid", value, "groupId")
            d.putCallItem("ownerid", value, "ownerId")
456
457

            #QFile::Permissions permissions () const
458
            perms = d.call(value, "permissions")
459
460
461
            if perms is None:
                d.putValue("<not available>")
            else:
hjk's avatar
hjk committed
462
                with SubItem(d, "permissions"):
463
                    d.putEmptyValue()
464
                    d.putType(ns + "QFile::Permissions")
465
                    d.putNumChild(10)
hjk's avatar
hjk committed
466
                    if d.isExpanded():
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
                        with Children(d, 10):
                            perms = perms['i']
                            d.putBoolItem("ReadOwner",  perms & 0x4000)
                            d.putBoolItem("WriteOwner", perms & 0x2000)
                            d.putBoolItem("ExeOwner",   perms & 0x1000)
                            d.putBoolItem("ReadUser",   perms & 0x0400)
                            d.putBoolItem("WriteUser",  perms & 0x0200)
                            d.putBoolItem("ExeUser",    perms & 0x0100)
                            d.putBoolItem("ReadGroup",  perms & 0x0040)
                            d.putBoolItem("WriteGroup", perms & 0x0020)
                            d.putBoolItem("ExeGroup",   perms & 0x0010)
                            d.putBoolItem("ReadOther",  perms & 0x0004)
                            d.putBoolItem("WriteOther", perms & 0x0002)
                            d.putBoolItem("ExeOther",   perms & 0x0001)

            #QDir absoluteDir () const
            #QDir dir () const
hjk's avatar
hjk committed
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
            d.putCallItem("caching", value, "caching")
            d.putCallItem("exists", value, "exists")
            d.putCallItem("isAbsolute", value, "isAbsolute")
            d.putCallItem("isDir", value, "isDir")
            d.putCallItem("isExecutable", value, "isExecutable")
            d.putCallItem("isFile", value, "isFile")
            d.putCallItem("isHidden", value, "isHidden")
            d.putCallItem("isReadable", value, "isReadable")
            d.putCallItem("isRelative", value, "isRelative")
            d.putCallItem("isRoot", value, "isRoot")
            d.putCallItem("isSymLink", value, "isSymLink")
            d.putCallItem("isWritable", value, "isWritable")
            d.putCallItem("created", value, "created")
            d.putCallItem("lastModified", value, "lastModified")
            d.putCallItem("lastRead", value, "lastRead")


def qdump__QFixed(d, value):
    v = int(value["val"])
hjk's avatar
hjk committed
503
504
505
506
    d.putValue("%s/64 = %s" % (v, v/64.0))
    d.putNumChild(0)


507
508
509
def qform__QFiniteStack():
    return arrayForms()

hjk's avatar
hjk committed
510
def qdump__QFiniteStack(d, value):
hjk's avatar
hjk committed
511
512
    alloc = int(value["_alloc"])
    size = int(value["_size"])
513
    d.check(0 <= size and size <= alloc and alloc <= 1000 * 1000 * 1000)
hjk's avatar
hjk committed
514
515
516
    d.putItemCount(size)
    d.putNumChild(size)
    if d.isExpanded():
517
        innerType = d.templateArgument(value.type, 0)
518
        d.putPlotData(innerType, value["_array"], size)
hjk's avatar
hjk committed
519

520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
# Stock gdb 7.2 seems to have a problem with types here:
#
#  echo -e "namespace N { struct S { enum E { zero, one, two }; }; }\n"\
#      "int main() { N::S::E x = N::S::one;\n return x; }" >> main.cpp
#  g++ -g main.cpp
#  gdb-7.2 -ex 'file a.out' -ex 'b main' -ex 'run' -ex 'step' \
#     -ex 'ptype N::S::E' -ex 'python print gdb.lookup_type("N::S::E")' -ex 'q'
#  gdb-7.1 -ex 'file a.out' -ex 'b main' -ex 'run' -ex 'step' \
#     -ex 'ptype N::S::E' -ex 'python print gdb.lookup_type("N::S::E")' -ex 'q'
#  gdb-cvs -ex 'file a.out' -ex 'b main' -ex 'run' -ex 'step' \
#     -ex 'ptype N::S::E' -ex 'python print gdb.lookup_type("N::S::E")' -ex 'q'
#
# gives as of 2010-11-02
#
#  type = enum N::S::E {N::S::zero, N::S::one, N::S::two} \n
hjk's avatar
hjk committed
535
536
#    Traceback (most recent call last): File "<string>", line 1,
#      in <module> RuntimeError: No type named N::S::E.
537
538
539
540
541
#  type = enum N::S::E {N::S::zero, N::S::one, N::S::two} \n  N::S::E
#  type = enum N::S::E {N::S::zero, N::S::one, N::S::two} \n  N::S::E
#
# i.e. there's something broken in stock 7.2 that is was ok in 7.1 and is ok later.

hjk's avatar
hjk committed
542
543
def qdump__QFlags(d, value):
    i = value["i"]
544
    try:
545
        enumType = d.templateArgument(value.type.unqualified(), 0)
546
547
548
        d.putValue("%s (%s)" % (i.cast(enumType), i))
    except:
        d.putValue("%s" % i)
hjk's avatar
hjk committed
549
550
551
    d.putNumChild(0)


552
553
554
def qform__QHash():
    return mapForms()

hjk's avatar
hjk committed
555
def qdump__QHash(d, value):
hjk's avatar
hjk committed
556

hjk's avatar
hjk committed
557
558
559
    def hashDataFirstNode(dPtr, numBuckets):
        ePtr = dPtr.cast(nodeTypePtr)
        bucket = dPtr.dereference()["buckets"]
560
        for n in xrange(numBuckets - 1, -1, -1):
hjk's avatar
hjk committed
561
562
563
            n = n - 1
            if n < 0:
                break
564
            if d.pointerValue(bucket.dereference()) != d.pointerValue(ePtr):
hjk's avatar
hjk committed
565
566
                return bucket.dereference()
            bucket = bucket + 1
hjk's avatar
hjk committed
567
        return ePtr;
hjk's avatar
hjk committed
568

569
570
    def hashDataNextNode(nodePtr, numBuckets):
        nextPtr = nodePtr.dereference()["next"]
571
        if d.pointerValue(nextPtr.dereference()["next"]):
572
573
574
575
            return nextPtr
        start = (int(nodePtr.dereference()["h"]) % numBuckets) + 1
        dPtr = nextPtr.cast(dataTypePtr)
        bucket = dPtr.dereference()["buckets"] + start
576
        for n in xrange(numBuckets - start):
577
            if d.pointerValue(bucket.dereference()) != d.pointerValue(nextPtr):
hjk's avatar
hjk committed
578
579
                return bucket.dereference()
            bucket += 1
580
        return nextPtr
hjk's avatar
hjk committed
581

582
583
    keyType = d.templateArgument(value.type, 0)
    valueType = d.templateArgument(value.type, 1)
hjk's avatar
hjk committed
584

585
    anon = d.childAt(value, 0)
586
587
    d_ptr = anon["d"]
    e_ptr = anon["e"]
hjk's avatar
hjk committed
588
    size = int(d_ptr["size"])
hjk's avatar
hjk committed
589

hjk's avatar
hjk committed
590
591
    dataTypePtr = d_ptr.type    # QHashData *  = { Node *fakeNext, Node *buckets }
    nodeTypePtr = d_ptr.dereference()["fakeNext"].type    # QHashData::Node
hjk's avatar
hjk committed
592

593
594
    d.check(0 <= size and size <= 100 * 1000 * 1000)
    d.checkRef(d_ptr["ref"])
hjk's avatar
hjk committed
595

596
597
    d.putItemCount(size)
    d.putNumChild(size)
hjk's avatar
hjk committed
598
    if d.isExpanded():
599
        numBuckets = int(d_ptr.dereference()["numBuckets"])
hjk's avatar
hjk committed
600
        nodePtr = hashDataFirstNode(d_ptr, numBuckets)
hjk's avatar
hjk committed
601
        innerType = e_ptr.dereference().type
602
603
        isCompact = d.isMapCompact(keyType, valueType)
        childType = valueType if isCompact else innerType
hjk's avatar
hjk committed
604
        with Children(d, size, maxNumChild=1000, childType=childType):
605
            for i in d.childRange():
606
                it = nodePtr.dereference().cast(innerType)
hjk's avatar
hjk committed
607
                with SubItem(d, i):
608
                    if isCompact:
609
610
611
612
613
614
                        key = it["key"]
                        if not key:
                            # LLDB can't access directly since it's in anonymous union
                            # for Qt4 optimized int keytype
                            key = it[1]["key"]
                        d.putMapName(key)
615
                        d.putItem(it["value"])
616
617
                        d.putType(valueType)
                    else:
hjk's avatar
hjk committed
618
                        d.putItem(it)
619
                nodePtr = hashDataNextNode(nodePtr, numBuckets)
hjk's avatar
hjk committed
620
621


hjk's avatar
hjk committed
622
623
def qdump__QHashNode(d, value):
    key = value["key"]
624
625
626
627
    if not key:
        # LLDB can't access directly since it's in anonymous union
        # for Qt4 optimized int keytype
        key = value[1]["key"]
hjk's avatar
hjk committed
628
    val = value["value"]
629
    d.putEmptyValue()
630
    d.putNumChild(2)
hjk's avatar
hjk committed
631
    if d.isExpanded():
632
        with Children(d):
hjk's avatar
hjk committed
633
634
            d.putSubItem("key", key)
            d.putSubItem("value", val)
hjk's avatar
hjk committed
635
636


637
638
def qHashIteratorHelper(d, value):
    typeName = str(value.type)
639
640
    hashTypeName = typeName[0:typeName.rfind("::")]
    hashType = d.lookupType(hashTypeName)
641
642
    keyType = d.templateArgument(hashType, 0)
    valueType = d.templateArgument(hashType, 1)
643
    d.putNumChild(1)
644
    d.putEmptyValue()
645
646
    if d.isExpanded():
        with Children(d):
647
648
649
650
            # We need something like QHash<int, float>::iterator
            # -> QHashNode<int, float> with 'proper' spacing,
            # as space changes confuse LLDB.
            innerTypeName = hashTypeName.replace("QHash", "QHashNode", 1)
651
652
653
654
655
656
657
            node = value["i"].cast(d.lookupType(innerTypeName).pointer()).dereference()
            key = node["key"]
            if not key:
                # LLDB can't access directly since it's in anonymous union
                # for Qt4 optimized int keytype
                key = node[1]["key"]
            d.putSubItem("key", key)
658
659
660
661
662
663
664
665
666
            d.putSubItem("value", node["value"])

def qdump__QHash__const_iterator(d, value):
    qHashIteratorHelper(d, value)

def qdump__QHash__iterator(d, value):
    qHashIteratorHelper(d, value)


hjk's avatar
hjk committed
667
def qdump__QHostAddress(d, value):
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
    # QHostAddress in Qt 4.5 (byte offsets)
    #   quint32 a        (0)
    #   Q_IPV6ADDR a6    (4)
    #   protocol         (20)
    #   QString ipString (24)
    #   QString scopeId  (24 + ptrSize)
    #   bool isParsed    (24 + 2 * ptrSize)
    # QHostAddress in Qt 5.0
    #   QString ipString (0)
    #   QString scopeId  (ptrSize)
    #   quint32 a        (2*ptrSize)
    #   Q_IPV6ADDR a6    (2*ptrSize + 4)
    #   protocol         (2*ptrSize + 20)
    #   bool isParsed    (2*ptrSize + 24)

683
    privAddress = d.extractPointer(value)
684
    isQt5 = d.qtVersion() >= 0x050000
685
    sizeofQString = d.ptrSize()
686
    ipStringAddress = privAddress + (0 if isQt5 else 24)
687
    isParsedAddress = privAddress + 24 + 2 * sizeofQString
688
    # value.d.d->ipString
689
    ipString = d.encodeStringHelper(d.extractPointer(ipStringAddress))
690
    if d.extractByte(isParsedAddress) and len(ipString) > 0:
691
        d.putValue(ipString, Hex4EncodedLittleEndian)
hjk's avatar
hjk committed
692
    else:
693
694
695
696
697
698
699
        # value.d.d->protocol:
        #  QAbstractSocket::IPv4Protocol = 0
        #  QAbstractSocket::IPv6Protocol = 1
        protoAddress = privAddress + 20 + (2 * sizeofQString if isQt5 else 0);
        proto = d.extractInt(protoAddress)
        if proto == 1:
            # value.d.d->a6
700
701
            a6Offset = 4 + (2 * sizeofQString if isQt5 else 0)
            data = d.readMemory(privAddress + a6Offset, 16)
702
703
            address = ':'.join("%x" % int(data[i:i+4], 16) for i in xrange(0, 32, 4))
            scopeId = privAddress + sizeofQString + (0 if isQt5 else 24)
704
            scopeId = d.encodeStringHelper(d.extractPointer(scopeId))
705
706
707
708
709
710
711
712
713
714
715
716
            d.putValue("%s%%%s" % (address, scopeId), IPv6AddressAndHexScopeId)
        elif proto == 0:
            # value.d.d->a
            a = d.extractInt(privAddress + (2 * sizeofQString if isQt5 else 0))
            a, n4 = divmod(a, 256)
            a, n3 = divmod(a, 256)
            a, n2 = divmod(a, 256)
            a, n1 = divmod(a, 256)
            d.putValue("%d.%d.%d.%d" % (n1, n2, n3, n4));
        else:
            d.putValue("<unspecified>")

717
718
    d.putPlainChildren(value["d"]["d"].dereference())

hjk's avatar
hjk committed
719

720
def qdump__QIPv6Address(d, value):
721
722
723
724
725
726
727
728
729
730
731
    #warn("IPV6.VALUE: %s" % value)
    #warn("IPV6.ADDR: 0x%x" % d.addressOf(value))
    #warn("IPV6.LOADADDR: 0x%x" % value.GetLoadAddress())
    c = value["c"]
    data = d.readMemory(d.addressOf(c), 16)
    d.putValue(':'.join("%x" % int(data[i:i+4], 16) for i in xrange(0, 32, 4)))
    #d.putValue('xx')
    #d.putValue("0x%x - 0x%x" % (d.addressOf(value), d.addressOf(c)))
    #d.putValue("0x%x - 0x%x" % (value.GetAddress(), c.GetAddress()))
    #d.putValue("0x%x - 0x%x" % (value.GetLoadAddress(), c.GetLoadAddress()))
    d.putPlainChildren(c)
732

733
734
735
def qform__QList():
    return "Assume Direct Storage,Assume Indirect Storage"

hjk's avatar
hjk committed
736
def qdump__QList(d, value):
737
    dptr = d.childAt(value, 0)["d"]
738
739
740
741
    private = dptr.dereference()
    begin = int(private["begin"])
    end = int(private["end"])
    array = private["array"]
742
    d.check(begin >= 0 and end >= 0 and end <= 1000 * 1000 * 1000)
743
    size = end - begin
744
745
    d.check(size >= 0)
    d.checkRef(private["ref"])
hjk's avatar
hjk committed
746

747
    innerType = d.templateArgument(value.type, 0)
hjk's avatar
hjk committed
748

749
750
    d.putItemCount(size)
    d.putNumChild(size)
hjk's avatar
hjk committed
751
    if d.isExpanded():
hjk's avatar
hjk committed
752
        innerSize = innerType.sizeof
753
754
        stepSize = dptr.type.sizeof
        addr = d.addressOf(array) + begin * stepSize
hjk's avatar
hjk committed
755
756
757
758
759
        # The exact condition here is:
        #  QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic
        # but this data is available neither in the compiled binary nor
        # in the frontend.
        # So as first approximation only do the 'isLarge' check:
760
761
762
763
764
765
766
        format = d.currentItemFormat()
        if format == 1:
            isInternal = True
        elif format == 2:
            isInternal = False
        else:
            isInternal = innerSize <= stepSize and d.isMovableType(innerType)
767
768
        if isInternal:
            if innerSize == stepSize:
769
                p = d.createPointerValue(addr, innerType)
770
771
772
773
                d.putArrayData(innerType, p, size)
            else:
                with Children(d, size, childType=innerType):
                    for i in d.childRange():
774
775
                        p = d.createValue(addr + i * stepSize, innerType)
                        d.putSubItem(i, p)
776
        else:
777
            p = d.createPointerValue(addr, innerType.pointer())
778
779
780
781
782
            # about 0.5s / 1000 items
            with Children(d, size, maxNumChild=2000, childType=innerType):
                for i in d.childRange():
                    d.putSubItem(i, p.dereference().dereference())
                    p += 1
hjk's avatar
hjk committed
783

hjk's avatar
hjk committed
784
785
def qform__QImage():
    return "Normal,Displayed"
hjk's avatar
hjk committed
786

hjk's avatar
hjk committed
787
def qdump__QImage(d, value):
788
789
790
791
    # This relies on current QImage layout:
    # QImageData:
    # - QAtomicInt ref
    # - int width, height, depth, nbytes
792
793
794
795
    # - padding on 64 bit machines
    # - qreal devicePixelRatio  (+20 + padding)  # Assume qreal == double, Qt 5 only
    # - QVector<QRgb> colortable (+20 + padding + gap)
    # - uchar *data (+20 + padding + gap + ptr)
796
    # [- uchar **jumptable jumptable with Qt 3 suppor]
797
    # - enum format (+20 + padding + gap + 2 * ptr)
798
799
800
801

    ptrSize = d.ptrSize()
    isQt5 = d.qtVersion() >= 0x050000
    offset = (3 if isQt5 else 2) * ptrSize
802
    base = d.extractPointer(d.addressOf(value) + offset)
803
804
805
806
    if base == 0:
        d.putValue("(invalid)")
        return
    qt3Support = d.isQt3Support()
807
808
809
    width = d.extractInt(base + 4)
    height = d.extractInt(base + 8)
    nbytes = d.extractInt(base + 16)
810
    padding = d.ptrSize() - d.intSize()
811
    pixelRatioSize = 8 if isQt5 else 0
812
    jumpTableSize = ptrSize if qt3Support else 0
813
    bits = d.extractPointer(base + 20 + padding + pixelRatioSize + ptrSize)
814
    iformat = d.extractInt(base + 20 + padding + pixelRatioSize + jumpTableSize + 2 * ptrSize)
815
    d.putValue("(%dx%d)" % (width, height))
816
    d.putNumChild(1)
hjk's avatar
hjk committed
817
    if d.isExpanded():
818
        with Children(d):
819
820
821
822
            d.putIntItem("width", width)
            d.putIntItem("height", height)
            d.putIntItem("nbytes", nbytes)
            d.putIntItem("format", iformat)
hjk's avatar
hjk committed
823
            with SubItem(d, "data"):
824
                d.putValue("0x%x" % bits)
825
                d.putNumChild(0)
826
827
                d.putType("void *")

hjk's avatar
hjk committed
828
    format = d.currentItemFormat()
829
    if format == 1:
830
        d.putDisplay(StopDisplay)
831
    elif format == 2:
832
833
834
835
836
837
838
839
840
841
842
        # This is critical for performance. Writing to an external
        # file using the following is faster when using GDB.
        #   file = tempfile.mkstemp(prefix="gdbpy_")
        #   filename = file[1].replace("\\", "\\\\")
        #   gdb.execute("dump binary memory %s %s %s" %
        #       (filename, bits, bits + nbytes))
        #   d.putDisplay(DisplayImageFile, " %d %d %d %d %s"
        #       % (width, height, nbytes, iformat, filename))
        d.putField("editformat", DisplayImageData)
        d.put('editvalue="')
        d.put('%08x%08x%08x%08x' % (width, height, nbytes, iformat))
843
        d.put(d.readMemory(bits, nbytes))
844
        d.put('",')
hjk's avatar
hjk committed
845
846


hjk's avatar
hjk committed
847
def qdump__QLinkedList(d, value):
848
    dd = d.extractPointer(value)
hjk's avatar
hjk committed
849
850
851
    ptrSize = d.ptrSize()
    n = d.extractInt(dd + 4 + 2 * ptrSize);
    ref = d.extractInt(dd + 2 * ptrSize);
852
853
    d.check(0 <= n and n <= 100*1000*1000)
    d.check(-1 <= ref and ref <= 1000)
hjk's avatar
hjk committed
854
    d.putItemCount(n)
855
    d.putNumChild(n)
hjk's avatar
hjk committed
856
    if d.isExpanded():
857
        innerType = d.templateArgument(value.type, 0)
hjk's avatar
hjk committed
858
        with Children(d, n, maxNumChild=1000, childType=innerType):
859
            pp = d.extractPointer(dd)
860
            for i in d.childRange():
hjk's avatar
hjk committed
861
                d.putSubItem(i, d.createValue(pp + 2 * ptrSize, innerType))
862
                pp = d.extractPointer(pp)
hjk's avatar
hjk committed
863

864
qqLocalesCount = None
hjk's avatar
hjk committed
865

hjk's avatar
hjk committed
866
def qdump__QLocale(d, value):
867
868
869
870
    # Check for uninitialized 'index' variable. Retrieve size of
    # QLocale data array from variable in qlocale.cpp.
    # Default is 368 in Qt 4.8, 438 in Qt 5.0.1, the last one
    # being 'System'.
hjk's avatar
hjk committed
871
872
873
    #global qqLocalesCount
    #if qqLocalesCount is None:
    #    #try:
874
    #        qqLocalesCount = int(value(ns + 'locale_data_size'))
hjk's avatar
hjk committed
875
876
877
878
879
880
881
882
883
    #    #except:
    #        qqLocalesCount = 438
    #try:
    #    index = int(value["p"]["index"])
    #except:
    #    try:
    #        index = int(value["d"]["d"]["m_index"])
    #    except:
    #        index = int(value["d"]["d"]["m_data"]...)
884
885
886
    #d.check(index >= 0)
    #d.check(index <= qqLocalesCount)
    d.putStringValue(d.call(value, "name"))
887
888
889
    d.putNumChild(0)
    return
    # FIXME: Poke back for variants.
hjk's avatar
hjk committed
890
    if d.isExpanded():
891
892
        ns = d.qtNamespace()
        with Children(d, childType=d.lookupType(ns + "QChar"), childNumChild=0):
hjk's avatar
hjk committed
893
894
895
896
897
            d.putCallItem("country", value, "country")
            d.putCallItem("language", value, "language")
            d.putCallItem("measurementSystem", value, "measurementSystem")
            d.putCallItem("numberOptions", value, "numberOptions")
            d.putCallItem("timeFormat_(short)", value,
898
                "timeFormat", ns + "QLocale::ShortFormat")
hjk's avatar
hjk committed
899
            d.putCallItem("timeFormat_(long)", value,
900
                "timeFormat", ns + "QLocale::LongFormat")
hjk's avatar
hjk committed
901
902
903
904
905
906
            d.putCallItem("decimalPoint", value, "decimalPoint")
            d.putCallItem("exponential", value, "exponential")
            d.putCallItem("percent", value, "percent")
            d.putCallItem("zeroDigit", value, "zeroDigit")
            d.putCallItem("groupSeparator", value, "groupSeparator")
            d.putCallItem("negativeSign", value, "negativeSign")
hjk's avatar
hjk committed
907
908


hjk's avatar
hjk committed
909
def qdump__QMapNode(d, value):
910
    d.putEmptyValue()
911
    d.putNumChild(2)
hjk's avatar
hjk committed
912
913
914
915
916
917
    if d.isExpanded():
        with Children(d):
            d.putSubItem("key", value["key"])
            d.putSubItem("value", value["value"])


918
def qdumpHelper__Qt4_QMap(d, value):
hjk's avatar
hjk committed
919
920
    d_ptr = value["d"].dereference()
    e_ptr = value["e"].dereference()
hjk's avatar
hjk committed
921
    n = int(d_ptr["size"])
922
923
    d.check(0 <= n and n <= 100*1000*1000)
    d.checkRef(d_ptr["ref"])
hjk's avatar
hjk committed
924
925

    d.putItemCount(n)
926
    d.putNumChild(n)
hjk's avatar
hjk committed
927
    if d.isExpanded():
928
929
        if n > 10000:
            n = 10000
hjk's avatar
hjk committed
930

931
932
        keyType = d.templateArgument(value.type, 0)
        valueType = d.templateArgument(value.type, 1)
hjk's avatar
hjk committed
933
934
935
936
937
938

        it = e_ptr["forward"].dereference()

        # QMapPayloadNode is QMapNode except for the 'forward' member, so
        # its size is most likely the offset of the 'forward' member therein.
        # Or possibly 2 * sizeof(void *)
939
940
941
        # Note: Keeping the spacing in the type lookup
        # below is important for LLDB.
        needle = str(value.type).replace("QMap", "QMapNode", 1)
942
        needle = d.qtNamespace() + "QMapNode<%s,%s>" % (keyType, valueType)
943
        nodeType = d.lookupType(needle)
hjk's avatar
hjk committed
944
        nodePointerType = nodeType.pointer()
945
946
        # symbols reports payload size at wrong size 24
        if d.isArmArchitecture() and d.isQnxTarget() and str(valueType) == 'QVariant':
947
948
949
            payloadSize = 28
        else:
            payloadSize = nodeType.sizeof - 2 * nodePointerType.sizeof
hjk's avatar
hjk committed
950

951
952
        with PairedChildren(d, n, useKeyAndValue=True,
                keyType=keyType, valueType=valueType, pairType=nodeType):
953
            for i in xrange(n):
hjk's avatar
hjk committed
954
955
                base = it.cast(d.charPtrType()) - payloadSize
                node = base.cast(nodePointerType).dereference()
hjk's avatar
hjk committed
956
                with SubItem(d, i):
957
958
                    #d.putField("iname", d.currentIName)
                    d.putPair(node, i)
959
                it = it.dereference()["forward"].dereference()
hjk's avatar
hjk committed
960
961


962
def qdumpHelper__Qt5_QMap(d, value):
963
    d_ptr = value["d"].dereference()
hjk's avatar
hjk committed
964
    n = int(d_ptr["size"])