qttypes.py 94.3 KB
Newer Older
hjk's avatar
hjk committed
1
############################################################################
hjk's avatar
hjk committed
2
#
Eike Ziller's avatar
Eike Ziller committed
3
4
# Copyright (C) 2015 The Qt Company Ltd.
# Contact: http://www.qt.io/licensing
hjk's avatar
hjk committed
5
#
hjk's avatar
hjk committed
6
7
8
9
10
11
# 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
Eike Ziller's avatar
Eike Ziller committed
12
13
# a written agreement between you and The Qt Company.  For licensing terms and
# conditions see http://www.qt.io/terms-conditions.  For further information
Eike Ziller's avatar
Eike Ziller committed
14
# use the contact form at http://www.qt.io/contact-us.
hjk's avatar
hjk committed
15
16
17
#
# GNU Lesser General Public License Usage
# Alternatively, this file may be used under the terms of the GNU Lesser
Eike Ziller's avatar
Eike Ziller committed
18
19
20
21
22
23
# General Public License version 2.1 or version 3 as published by the Free
# Software Foundation and appearing in the file LICENSE.LGPLv21 and
# LICENSE.LGPLv3 included in the packaging of this file.  Please review the
# following information to ensure the GNU Lesser General Public License
# requirements will be met: https://www.gnu.org/licenses/lgpl.html and
# http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
hjk's avatar
hjk committed
24
#
Eike Ziller's avatar
Eike Ziller committed
25
26
# In addition, as a special exception, The Qt Company gives you certain additional
# rights.  These rights are described in The Qt Company LGPL Exception
hjk's avatar
hjk committed
27
28
29
# version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
#
#############################################################################
hjk's avatar
hjk committed
30

31
import platform
32
from dumper import *
hjk's avatar
hjk committed
33
34
35


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


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


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

55
def qform__QByteArray():
56
57
    return [Latin1StringFormat, SeparateLatin1StringFormat,
            Utf8StringFormat, SeparateUtf8StringFormat ]
58

hjk's avatar
hjk committed
59
def qdump__QByteArray(d, value):
hjk's avatar
hjk committed
60
    data, size, alloc = d.byteArrayData(value)
61
    d.check(alloc == 0 or (0 <= size and size <= alloc and alloc <= 100000000))
62
    d.putNumChild(size)
63
    elided, p = d.encodeByteArrayHelper(d.extractPointer(value), d.displayStringLimit)
64
65
    displayFormat = d.currentItemFormat()
    if displayFormat == AutomaticFormat or displayFormat == Latin1StringFormat:
66
        d.putValue(p, Hex2EncodedLatin1, elided=elided)
67
    elif displayFormat == SeparateLatin1StringFormat:
68
        d.putValue(p, Hex2EncodedLatin1, elided=elided)
69
        d.putField("editformat", DisplayLatin1String)
70
        d.putField("editvalue", d.encodeByteArray(value, limit=100000))
71
    elif displayFormat == Utf8StringFormat:
72
        d.putValue(p, Hex2EncodedUtf8, elided=elided)
73
    elif displayFormat == SeparateUtf8StringFormat:
74
        d.putValue(p, Hex2EncodedUtf8, elided=elided)
75
        d.putField("editformat", DisplayUtf8String)
76
        d.putField("editvalue", d.encodeByteArray(value, limit=100000))
hjk's avatar
hjk committed
77
    if d.isExpanded():
78
        d.putArrayData(data, size, d.charType())
hjk's avatar
hjk committed
79

hjk's avatar
hjk committed
80
81
def qdump__QByteArrayData(d, value):
    data, size, alloc = d.byteArrayDataHelper(d.addressOf(value))
82
    d.check(alloc == 0 or (0 <= size and size <= alloc and alloc <= 100000000))
hjk's avatar
hjk committed
83
84
85
86
87
88
    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
89

hjk's avatar
hjk committed
90
def qdump__QChar(d, value):
hjk's avatar
hjk committed
91
    d.putValue(int(value["ucs"]))
hjk's avatar
hjk committed
92
93
94
    d.putNumChild(0)


hjk's avatar
hjk committed
95
def qform__QAbstractItemModel():
96
    return [SimpleFormat, EnhancedFormat]
97

hjk's avatar
hjk committed
98
def qdump__QAbstractItemModel(d, value):
99
100
    displayFormat = d.currentItemFormat()
    if displayFormat == SimpleFormat:
101
102
        d.putPlainChildren(value)
        return
103
    #displayFormat == EnhancedFormat:
104
    # Create a default-constructed QModelIndex on the stack.
105
    try:
106
        ri = d.makeValue(d.qtNamespace() + "QModelIndex", "-1, -1, 0, 0")
hjk's avatar
hjk committed
107
108
        this_ = d.makeExpression(value)
        ri_ = d.makeExpression(ri)
109
110
        rowCount = int(d.parseAndEvaluate("%s.rowCount(%s)" % (this_, ri_)))
        columnCount = int(d.parseAndEvaluate("%s.columnCount(%s)" % (this_, ri_)))
111
    except:
hjk's avatar
hjk committed
112
        d.putPlainChildren(value)
113
        return
114
115
    d.putValue("%d x %d" % (rowCount, columnCount))
    d.putNumChild(rowCount * columnCount)
hjk's avatar
hjk committed
116
117
    if d.isExpanded():
        with Children(d, numChild=rowCount * columnCount, childType=ri.type):
118
119
120
            i = 0
            for row in xrange(rowCount):
                for column in xrange(columnCount):
hjk's avatar
hjk committed
121
                    with SubItem(d, i):
122
                        d.putName("[%s, %s]" % (row, column))
123
                        mi = d.parseAndEvaluate("%s.index(%d,%d,%s)"
124
125
126
127
                            % (this_, row, column, ri_))
                        #warn("MI: %s " % mi)
                        #name = "[%d,%d]" % (row, column)
                        #d.putValue("%s" % mi)
hjk's avatar
hjk committed
128
                        d.putItem(mi)
129
130
131
132
133
134
135
136
                        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)")

137
def qform__QModelIndex():
138
    return [SimpleFormat, EnhancedFormat]
139

hjk's avatar
hjk committed
140
def qdump__QModelIndex(d, value):
141
142
    displayFormat = d.currentItemFormat()
    if displayFormat == SimpleFormat:
143
144
        d.putPlainChildren(value)
        return
hjk's avatar
hjk committed
145
146
    r = value["r"]
    c = value["c"]
147
148
149
150
    try:
        p = value["p"]
    except:
        p = value["i"]
hjk's avatar
hjk committed
151
    m = value["m"]
152
    if d.isNull(m) or r < 0 or c < 0:
153
154
155
156
        d.putValue("(invalid)")
        d.putPlainChildren(value)
        return

157
158
    mm = m.dereference()
    mm = mm.cast(mm.type.unqualified())
159
    ns = d.qtNamespace()
160
    try:
161
        mi = d.makeValue(ns + "QModelIndex", "%s,%s,%s,%s" % (r, c, p, m))
hjk's avatar
hjk committed
162
163
        mm_ = d.makeExpression(mm)
        mi_ = d.makeExpression(mi)
164
165
        rowCount = int(d.parseAndEvaluate("%s.rowCount(%s)" % (mm_, mi_)))
        columnCount = int(d.parseAndEvaluate("%s.columnCount(%s)" % (mm_, mi_)))
166
    except:
hjk's avatar
hjk committed
167
        d.putPlainChildren(value)
168
        return
169
170
171

    try:
        # Access DisplayRole as value
172
        val = d.parseAndEvaluate("%s.data(%s, 0)" % (mm_, mi_))
hjk's avatar
hjk committed
173
        v = val["d"]["data"]["ptr"]
174
        d.putStringValue(d.makeValue(ns + 'QString', v))
175
    except:
hjk's avatar
hjk committed
176
        d.putValue("")
177

178
    d.putNumChild(1)
179
180
    if d.isExpanded():
        with Children(d):
181
            d.putFields(value, False)
182
183
184
185
186
            i = 0
            for row in xrange(rowCount):
                for column in xrange(columnCount):
                    with UnnamedSubItem(d, i):
                        d.putName("[%s, %s]" % (row, column))
187
                        mi2 = d.parseAndEvaluate("%s.index(%d,%d,%s)"
188
189
190
                            % (mm_, row, column, mi_))
                        d.putItem(mi2)
                        i = i + 1
191
            d.putCallItem("parent", value, "parent")
192
193
    #gdb.execute("call free($mi)")

hjk's avatar
hjk committed
194

hjk's avatar
hjk committed
195
def qdump__QDate(d, value):
196
    jd = int(value["jd"])
197
    if jd:
198
199
200
201
202
        d.putValue(jd, JulianDate)
        d.putNumChild(1)
        if d.isExpanded():
            # FIXME: This improperly uses complex return values.
            with Children(d):
203
204
205
206
207
208
209
210
211
                if d.canCallLocale():
                    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"))
212
                d.putFields(value)
213
214
215
    else:
        d.putValue("(invalid)")
        d.putNumChild(0)
hjk's avatar
hjk committed
216
217


hjk's avatar
hjk committed
218
def qdump__QTime(d, value):
hjk's avatar
hjk committed
219
220
221
    mds = int(value["mds"])
    if mds >= 0:
        d.putValue(mds, MillisecondsSinceMidnight)
222
223
224
225
        d.putNumChild(1)
        if d.isExpanded():
            # FIXME: This improperly uses complex return values.
            with Children(d):
226
227
228
229
                d.putCallItem("toString", value, "toString",
                    d.enumExpression("DateFormat", "TextDate"))
                d.putCallItem("(ISO)", value, "toString",
                    d.enumExpression("DateFormat", "ISODate"))
230
231
232
233
234
                if d.canCallLocale():
                    d.putCallItem("(SystemLocale)", value, "toString",
                        d.enumExpression("DateFormat", "SystemLocaleDate"))
                    d.putCallItem("(Locale)", value, "toString",
                        d.enumExpression("DateFormat", "LocaleDate"))
235
                d.putFields(value)
236
237
238
    else:
        d.putValue("(invalid)")
        d.putNumChild(0)
239
240


hjk's avatar
hjk committed
241
def qdump__QTimeZone(d, value):
242
    base = d.extractPointer(value)
243
    if base == 0:
hjk's avatar
hjk committed
244
245
246
247
        d.putValue("(null)")
        d.putNumChild(0)
        return
    idAddr = base + 2 * d.ptrSize() # [QSharedData] + [vptr]
hjk's avatar
hjk committed
248
    d.putByteArrayValue(idAddr)
hjk's avatar
hjk committed
249
250
251
    d.putPlainChildren(value["d"])


hjk's avatar
hjk committed
252
def qdump__QDateTime(d, value):
253
254
255
256
    qtVersion = d.qtVersion()
    isValid = False
    # This relies on the Qt4/Qt5 internal structure layout:
    # {sharedref(4), ...
257
    base = d.extractPointer(value)
258
    is32bit = d.is32bit()
259
    if qtVersion >= 0x050200:
260
        if d.isWindowsTarget():
261
262
263
264
265
266
267
268
269
270
271
272
            msecsOffset = 8
            specOffset = 16
            offsetFromUtcOffset = 20
            timeZoneOffset = 24
            statusOffset = 28 if is32bit else 32
        else:
            msecsOffset = 4 if is32bit else 8
            specOffset = 12 if is32bit else 16
            offsetFromUtcOffset = 16 if is32bit else 20
            timeZoneOffset = 20 if is32bit else 24
            statusOffset = 24 if is32bit else 32
        status = d.extractInt(base + statusOffset)
273
        if int(status & 0x0c == 0x0c): # ValidDate and ValidTime
274
            isValid = True
275
276
277
278
            msecs = d.extractInt64(base + msecsOffset)
            spec = d.extractInt(base + specOffset)
            offset = d.extractInt(base + offsetFromUtcOffset)
            tzp = d.extractPointer(base + timeZoneOffset)
279
280
281
282
            if tzp == 0:
                tz = ""
            else:
                idBase = tzp + 2 * d.ptrSize() # [QSharedData] + [vptr]
283
                elided, tz = d.encodeByteArrayHelper(d.extractPointer(idBase), limit=100)
284
285
            d.putValue("%s/%s/%s/%s/%s" % (msecs, spec, offset, tz, status),
                DateTimeInternal)
286
287
288
289
290
291
    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;]
292
        # -      -  uint jd in Qt 4,  qint64 in Qt 5.0 and Qt 5.1; padded on 64 bit
293
294
295
        # -     [QTime time;]
        # -      -  uint mds;
        # -  Spec spec;
296
297
298
299
        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
300
301
302
303
304
305
306
        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:
307
308
309
310
311
        d.putNumChild(1)
        if d.isExpanded():
            # FIXME: This improperly uses complex return values.
            with Children(d):
                d.putCallItem("toTime_t", value, "toTime_t")
312
313
314
315
316
317
318
319
320
321
322
323
324
                if d.canCallLocale():
                    d.putCallItem("toString", value, "toString",
                        d.enumExpression("DateFormat", "TextDate"))
                    d.putCallItem("(ISO)", value, "toString",
                        d.enumExpression("DateFormat", "ISODate"))
                    d.putCallItem("toUTC", value, "toTimeSpec",
                        d.enumExpression("TimeSpec", "UTC"))
                    d.putCallItem("(SystemLocale)", value, "toString",
                        d.enumExpression("DateFormat", "SystemLocaleDate"))
                    d.putCallItem("(Locale)", value, "toString",
                        d.enumExpression("DateFormat", "LocaleDate"))
                    d.putCallItem("toLocalTime", value, "toTimeSpec",
                        d.enumExpression("TimeSpec", "LocalTime"))
325
                d.putFields(value)
326
327
328
    else:
        d.putValue("(invalid)")
        d.putNumChild(0)
hjk's avatar
hjk committed
329
330
331


def qdump__QDir(d, value):
hjk's avatar
hjk committed
332
    d.putNumChild(1)
333
    privAddress = d.extractPointer(value)
334
335
    bit32 = d.is32bit()
    qt5 = d.qtVersion() >= 0x050000
336
337
338
339
340
341
342
343
344
345

    # 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:
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
    # 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;
361

362
363
364
365
366
367
368
369
    # QFileSystemEntry:
    # QString m_filePath
    # QByteArray m_nativeFilePath
    # qint16 m_lastSeparator
    # qint16 m_firstDotInFileName
    # qint16 m_lastDotInFileName
    # + 2 byte padding
    fileSystemEntrySize = 2 * d.ptrSize() + 8
370

371
372
373
374
375
    if d.qtVersion() < 0x050200:
        case = 0
    elif d.qtVersion() >= 0x050300:
        case = 1
    else:
376
        # Try to distinguish bool vs QStringList at the first item
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
        # 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:
394
395
396
397
398
399
400
401
        # 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

hjk's avatar
hjk committed
402
    d.putStringValue(privAddress + dirEntryOffset)
hjk's avatar
hjk committed
403
404
    if d.isExpanded():
        with Children(d):
405
            ns = d.qtNamespace()
406
            d.call(value, "count")  # Fill cache.
407
408
409
            #d.putCallItem("absolutePath", value, "absolutePath")
            #d.putCallItem("canonicalPath", value, "canonicalPath")
            with SubItem(d, "absolutePath"):
410
                typ = d.lookupType(ns + "QString")
411
                d.putItem(d.createValue(privAddress + absoluteDirEntryOffset, typ))
412
            with SubItem(d, "entryInfoList"):
413
                typ = d.lookupType(ns + "QList<" + ns + "QFileInfo>")
414
                d.putItem(d.createValue(privAddress + fileInfosOffset, typ))
415
            with SubItem(d, "entryList"):
416
                typ = d.lookupType(ns + "QStringList")
417
                d.putItem(d.createValue(privAddress + filesOffset, typ))
418
            d.putFields(value)
hjk's avatar
hjk committed
419
420


hjk's avatar
hjk committed
421
def qdump__QFile(d, value):
422
    # 9fc0965 and a373ffcd change the layout of the private structure
hjk's avatar
hjk committed
423
    qtVersion = d.qtVersion()
424
    is32bit = d.is32bit()
425
426
427
428
429
430
431
432
433
434
435
    if qtVersion >= 0x050500:
        if d.isWindowsTarget():
            offset = 164 if is32bit else 248
        else:
            offset = 156 if is32bit else 248
    elif qtVersion >= 0x050400:
        if d.isWindowsTarget():
            offset = 188 if is32bit else 272
        else:
            offset = 180 if is32bit else 272
    elif qtVersion > 0x050200:
436
437
438
439
        if d.isWindowsTarget():
            offset = 180 if is32bit else 272
        else:
            offset = 176 if is32bit else 272
hjk's avatar
hjk committed
440
    elif qtVersion >= 0x050000:
441
        offset = 176 if is32bit else 280
hjk's avatar
hjk committed
442
    else:
443
444
445
446
        if d.isWindowsTarget():
            offset = 144 if is32bit else 232
        else:
            offset = 140 if is32bit else 232
447
    privAddress = d.extractPointer(d.addressOf(value) + d.ptrSize())
hjk's avatar
hjk committed
448
    fileNameAddress = privAddress + offset
hjk's avatar
hjk committed
449
    d.putStringValue(fileNameAddress)
hjk's avatar
hjk committed
450
    d.putNumChild(1)
hjk's avatar
hjk committed
451
452
    if d.isExpanded():
        with Children(d):
hjk's avatar
hjk committed
453
            d.putCallItem("exists", value, "exists")
hjk's avatar
hjk committed
454
            d.putFields(value)
hjk's avatar
hjk committed
455
456


hjk's avatar
hjk committed
457
def qdump__QFileInfo(d, value):
458
    privAddress = d.extractPointer(value)
459
460
461
462
463
464
465
466
    #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()
hjk's avatar
hjk committed
467
    d.putStringValue(filePathAddress)
hjk's avatar
hjk committed
468
    d.putNumChild(1)
hjk's avatar
hjk committed
469
    if d.isExpanded():
470
471
        ns = d.qtNamespace()
        with Children(d, childType=d.lookupType(ns + "QString")):
hjk's avatar
hjk committed
472
473
474
475
476
477
478
            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")
479
480
            if False:
                #ifdef Q_OS_MACX
hjk's avatar
hjk committed
481
482
483
484
                d.putCallItem("isBundle", value, "isBundle")
                d.putCallItem("bundleName", value, "bundleName")
            d.putCallItem("fileName", value, "fileName")
            d.putCallItem("filePath", value, "filePath")
485
            # Crashes gdb (archer-tromey-python, at dad6b53fe)
hjk's avatar
hjk committed
486
487
488
            #d.putCallItem("group", value, "group")
            #d.putCallItem("owner", value, "owner")
            d.putCallItem("path", value, "path")
489

hjk's avatar
hjk committed
490
491
            d.putCallItem("groupid", value, "groupId")
            d.putCallItem("ownerid", value, "ownerId")
492
493

            #QFile::Permissions permissions () const
494
            perms = d.call(value, "permissions")
495
496
497
            if perms is None:
                d.putValue("<not available>")
            else:
hjk's avatar
hjk committed
498
                with SubItem(d, "permissions"):
499
                    d.putEmptyValue()
500
                    d.putType(ns + "QFile::Permissions")
501
                    d.putNumChild(10)
hjk's avatar
hjk committed
502
                    if d.isExpanded():
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
                        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
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
            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")
535
            d.putFields(value)
hjk's avatar
hjk committed
536
537
538
539


def qdump__QFixed(d, value):
    v = int(value["val"])
hjk's avatar
hjk committed
540
541
542
543
    d.putValue("%s/64 = %s" % (v, v/64.0))
    d.putNumChild(0)


544
545
546
def qform__QFiniteStack():
    return arrayForms()

hjk's avatar
hjk committed
547
def qdump__QFiniteStack(d, value):
hjk's avatar
hjk committed
548
549
    alloc = int(value["_alloc"])
    size = int(value["_size"])
550
    d.check(0 <= size and size <= alloc and alloc <= 1000 * 1000 * 1000)
hjk's avatar
hjk committed
551
    d.putItemCount(size)
552
    d.putPlotData(value["_array"], size, d.templateArgument(value.type, 0))
hjk's avatar
hjk committed
553

554

hjk's avatar
hjk committed
555
556
def qdump__QFlags(d, value):
    i = value["i"]
557
    try:
558
        enumType = d.templateArgument(value.type.unqualified(), 0)
559
560
561
        d.putValue("%s (%s)" % (i.cast(enumType), i))
    except:
        d.putValue("%s" % i)
hjk's avatar
hjk committed
562
563
564
    d.putNumChild(0)


565
566
567
def qform__QHash():
    return mapForms()

hjk's avatar
hjk committed
568
def qdump__QHash(d, value):
hjk's avatar
hjk committed
569

hjk's avatar
hjk committed
570
571
572
    def hashDataFirstNode(dPtr, numBuckets):
        ePtr = dPtr.cast(nodeTypePtr)
        bucket = dPtr.dereference()["buckets"]
573
        for n in xrange(numBuckets - 1, -1, -1):
hjk's avatar
hjk committed
574
575
576
            n = n - 1
            if n < 0:
                break
577
            if d.pointerValue(bucket.dereference()) != d.pointerValue(ePtr):
hjk's avatar
hjk committed
578
579
                return bucket.dereference()
            bucket = bucket + 1
hjk's avatar
hjk committed
580
        return ePtr;
hjk's avatar
hjk committed
581

582
583
    def hashDataNextNode(nodePtr, numBuckets):
        nextPtr = nodePtr.dereference()["next"]
584
        if d.pointerValue(nextPtr.dereference()["next"]):
585
586
587
588
            return nextPtr
        start = (int(nodePtr.dereference()["h"]) % numBuckets) + 1
        dPtr = nextPtr.cast(dataTypePtr)
        bucket = dPtr.dereference()["buckets"] + start
589
        for n in xrange(numBuckets - start):
590
            if d.pointerValue(bucket.dereference()) != d.pointerValue(nextPtr):
hjk's avatar
hjk committed
591
592
                return bucket.dereference()
            bucket += 1
593
        return nextPtr
hjk's avatar
hjk committed
594

595
596
    keyType = d.templateArgument(value.type, 0)
    valueType = d.templateArgument(value.type, 1)
hjk's avatar
hjk committed
597

598
    anon = d.childAt(value, 0)
599
600
    d_ptr = anon["d"]
    e_ptr = anon["e"]
hjk's avatar
hjk committed
601
    size = int(d_ptr["size"])
hjk's avatar
hjk committed
602

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

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

609
    d.putItemCount(size)
hjk's avatar
hjk committed
610
    if d.isExpanded():
611
        numBuckets = int(d_ptr.dereference()["numBuckets"])
hjk's avatar
hjk committed
612
        innerType = e_ptr.dereference().type
613
614
        isCompact = d.isMapCompact(keyType, valueType)
        childType = valueType if isCompact else innerType
hjk's avatar
hjk committed
615
        with Children(d, size, maxNumChild=1000, childType=childType):
616
            j = 0
617
            for i in d.childRange():
618
619
620
621
622
                if i == 0:
                    node = hashDataFirstNode(d_ptr, numBuckets)
                else:
                    node = hashDataNextNode(node, numBuckets)
                it = node.dereference().cast(innerType)
hjk's avatar
hjk committed
623
                with SubItem(d, i):
624
                    if isCompact:
625
                        key = it["key"]
626
                        d.putMapName(key, j)
627
                        d.putItem(it["value"])
628
                        d.putType(valueType)
629
                        j += 1
630
                    else:
hjk's avatar
hjk committed
631
                        d.putItem(it)
hjk's avatar
hjk committed
632
633


634
635
636
def qform__QHashNode():
    return mapForms()

hjk's avatar
hjk committed
637
638
639
def qdump__QHashNode(d, value):
    key = value["key"]
    val = value["value"]
640
641
642
643
644
645
646
647
648
649
650
    if d.isMapCompact(key.type, val.type):
        d.putMapName(key)
        d.putItem(val)
        d.putType(value.type)
    else:
        d.putEmptyValue()
        d.putNumChild(2)
        if d.isExpanded():
            with Children(d):
                d.putSubItem("key", key)
                d.putSubItem("value", val)
hjk's avatar
hjk committed
651
652


653
654
def qHashIteratorHelper(d, value):
    typeName = str(value.type)
655
656
    hashTypeName = typeName[0:typeName.rfind("::")]
    hashType = d.lookupType(hashTypeName)
657
658
    keyType = d.templateArgument(hashType, 0)
    valueType = d.templateArgument(hashType, 1)
659
    d.putNumChild(1)
660
    d.putEmptyValue()
661
662
    if d.isExpanded():
        with Children(d):
663
664
665
666
            # 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)
667
668
669
670
671
672
673
            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)
674
675
676
677
678
679
680
681
682
            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
683
def qdump__QHostAddress(d, value):
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
    # 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)

699
    privAddress = d.extractPointer(value)
700
    isQt5 = d.qtVersion() >= 0x050000
701
    sizeofQString = d.ptrSize()
702
    ipStringAddress = privAddress + (0 if isQt5 else 24)
703
    isParsedAddress = privAddress + 24 + 2 * sizeofQString
704
    # value.d.d->ipString
hjk's avatar
hjk committed
705
    ipString = d.encodeString(ipStringAddress, limit=100)
706
    if d.extractByte(isParsedAddress) and len(ipString) > 0:
707
        d.putValue(ipString, Hex4EncodedLittleEndian)
hjk's avatar
hjk committed
708
    else:
709
710
711
712
713
714
715
        # 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
716
717
            a6Offset = 4 + (2 * sizeofQString if isQt5 else 0)
            data = d.readMemory(privAddress + a6Offset, 16)
718
719
            address = ':'.join("%x" % int(data[i:i+4], 16) for i in xrange(0, 32, 4))
            scopeId = privAddress + sizeofQString + (0 if isQt5 else 24)
hjk's avatar
hjk committed
720
            scopeId = d.encodeString(scopeId, limit=100)
721
722
723
724
725
726
727
728
729
730
731
732
            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>")

733
734
    d.putPlainChildren(value["d"]["d"].dereference())

hjk's avatar
hjk committed
735

736
def qdump__QIPv6Address(d, value):
737
738
739
740
741
742
743
744
745
746
747
    #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)
748

749
def qform__QList():
750
    return [DirectQListStorageFormat, IndirectQListStorageFormat]
751

hjk's avatar
hjk committed
752
def qdump__QList(d, value):
753
754
755
756
757
758
    base = d.extractPointer(value)
    begin = d.extractInt(base + 8)
    end = d.extractInt(base + 12)
    array = base + 16
    if d.qtVersion() < 0x50000:
        array += d.ptrSize()
759
    d.check(begin >= 0 and end >= 0 and end <= 1000 * 1000 * 1000)
760
    size = end - begin
761
    d.check(size >= 0)
762
    #d.checkRef(private["ref"])
hjk's avatar
hjk committed
763

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

766
    d.putItemCount(size)
hjk's avatar
hjk committed
767
    if d.isExpanded():
hjk's avatar
hjk committed
768
        innerSize = innerType.sizeof
769
770
        stepSize = d.ptrSize()
        addr = array + begin * stepSize
hjk's avatar
hjk committed
771
772
773
774
775
        # 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:
776
777
        displayFormat = d.currentItemFormat()
        if displayFormat == DirectQListStorageFormat:
778
            isInternal = True
779
        elif displayFormat == IndirectQListStorageFormat:
780
781
782
            isInternal = False
        else:
            isInternal = innerSize <= stepSize and d.isMovableType(innerType)
783
784
        if isInternal:
            if innerSize == stepSize:
785
                d.putArrayData(addr, size, innerType)
786
787
788
            else:
                with Children(d, size, childType=innerType):
                    for i in d.childRange():
789
790
                        p = d.createValue(addr + i * stepSize, innerType)
                        d.putSubItem(i, p)
791
        else:
792
793
794
            # about 0.5s / 1000 items
            with Children(d, size, maxNumChild=2000, childType=innerType):
                for i in d.childRange():
795
796
797
                    p = d.extractPointer(addr + i * stepSize)
                    x = d.createValue(p, innerType)
                    d.putSubItem(i, x)
hjk's avatar
hjk committed
798

hjk's avatar
hjk committed
799
def qform__QImage():
800
    return [SimpleFormat, SeparateFormat]
hjk's avatar
hjk committed
801

hjk's avatar
hjk committed
802
def qdump__QImage(d, value):
803
804
805
806
    # This relies on current QImage layout:
    # QImageData:
    # - QAtomicInt ref
    # - int width, height, depth, nbytes
807
808
809
810
    # - 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)
811
    # [- uchar **jumptable jumptable with Qt 3 suppor]
812
    # - enum format (+20 + padding + gap + 2 * ptr)
813
814
815
816

    ptrSize = d.ptrSize()
    isQt5 = d.qtVersion() >= 0x050000
    offset = (3 if isQt5 else 2) * ptrSize
817
    base = d.extractPointer(d.addressOf(value) + offset)
818
819
820
821
    if base == 0:
        d.putValue("(invalid)")
        return
    qt3Support = d.isQt3Support()
822
823
824
    width = d.extractInt(base + 4)
    height = d.extractInt(base + 8)
    nbytes = d.extractInt(base + 16)
825
    padding = d.ptrSize() - d.intSize()
826
    pixelRatioSize = 8 if isQt5 else 0
827
    jumpTableSize = ptrSize if qt3Support else 0
828
    bits = d.extractPointer(base + 20 + padding + pixelRatioSize + ptrSize)
829
    iformat = d.extractInt(base + 20 + padding + pixelRatioSize + jumpTableSize + 2 * ptrSize)
830
    d.putValue("(%dx%d)" % (width, height))
831
    d.putNumChild(1)
hjk's avatar
hjk committed
832
    if d.isExpanded():
833
        with Children(d):
834
835
836
837
            d.putIntItem("width", width)
            d.putIntItem("height", height)
            d.putIntItem("nbytes", nbytes)
            d.putIntItem("format", iformat)
hjk's avatar
hjk committed
838
            with SubItem(d, "data"):
839
                d.putValue("0x%x" % bits)
840
                d.putNumChild(0)
841
842
                d.putType("void *")

843
    displayFormat = d.currentItemFormat()
844
    if displayFormat == SeparateFormat:
845
846
847
848
849
850
851
852
853
854
855
        # 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))
856
        d.put(d.readMemory(bits, nbytes))
857
        d.put('",')
hjk's avatar
hjk committed
858
859


hjk's avatar
hjk committed
860
def qdump__QLinkedList(d, value):
861
    dd = d.extractPointer(value)
hjk's avatar
hjk committed
862
863
864
    ptrSize = d.ptrSize()
    n = d.extractInt(dd + 4 + 2 * ptrSize);
    ref = d.extractInt(dd + 2 * ptrSize);
865
866
    d.check(0 <= n and n <= 100*1000*1000)
    d.check(-1 <= ref and ref <= 1000)
hjk's avatar
hjk committed
867
    d.putItemCount(n)
hjk's avatar
hjk committed
868
    if d.isExpanded():
869
        innerType = d.templateArgument(value.type, 0)
hjk's avatar
hjk committed
870
        with Children(d, n, maxNumChild=1000, childType=innerType):
871
            pp = d.extractPointer(dd)
872
            for i in d.childRange():
hjk's avatar
hjk committed
873
                d.putSubItem(i, d.createValue(pp + 2 * ptrSize, innerType))
874
                pp = d.extractPointer(pp)
hjk's avatar
hjk committed
875

876
qqLocalesCount = None
hjk's avatar
hjk committed
877

hjk's avatar
hjk committed
878
def qdump__QLocale(d, value):
879
880
881
882
    # 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
883
884
885
    #global qqLocalesCount
    #if qqLocalesCount is None:
    #    #try:
886
    #        qqLocalesCount = int(value(ns + 'locale_data_size'))
hjk's avatar
hjk committed
887
888
889
890
891
892
893
894
895
    #    #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"]...)
896
897
898
    #d.check(index >= 0)
    #d.check(index <= qqLocalesCount)
    d.putStringValue(d.call(value, "name"))
899
900
901
    d.putNumChild(0)
    return
    # FIXME: Poke back for variants.
hjk's avatar
hjk committed
902
    if d.isExpanded():
903
904
        ns = d.qtNamespace()
        with Children(d, childType=d.lookupType(ns + "QChar"), childNumChild=0):
hjk's avatar
hjk committed
905
906
907
908
909
            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,
910
                "timeFormat", ns + "QLocale::ShortFormat")
hjk's avatar
hjk committed
911
            d.putCallItem("timeFormat_(long)", value,
912
                "timeFormat", ns + "QLocale::LongFormat")
hjk's avatar
hjk committed
913
914
915
916
917
918
            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")
919
            d.putFields(value)
hjk's avatar
hjk committed
920
921


hjk's avatar
hjk committed
922
def qdump__QMapNode(d, value):
hjk's avatar