qttypes.py 77.7 KB
Newer Older
hjk's avatar
hjk committed
1
############################################################################
hjk's avatar
hjk committed
2
#
hjk's avatar
hjk committed
3
4
# Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
# 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
193
194
195
    if int(jd):
        d.putValue(jd, JulianDate)
        d.putNumChild(1)
        if d.isExpanded():
196
            qt = d.qtNamespace() + "Qt::"
197
            if d.isLldb:
198
                qt += "DateFormat::" # FIXME: Bug?...
199
200
201
202
203
204
205
206
207
208
            # FIXME: This improperly uses complex return values.
            with Children(d):
                d.putCallItem("toString", value, "toString", qt + "TextDate")
                d.putCallItem("(ISO)", value, "toString", qt + "ISODate")
                d.putCallItem("(SystemLocale)", value, "toString",
                    qt + "SystemLocaleDate")
                d.putCallItem("(Locale)", value, "toString", qt + "LocaleDate")
    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
        d.putNumChild(1)
        if d.isExpanded():
217
218
219
            ns = d.qtNamespace()
            qtdate = ns + "Qt::"
            qttime = ns + "Qt::"
220
            if d.isLldb:
221
                qtdate += "DateFormat::" # FIXME: Bug?...
222
223
            # FIXME: This improperly uses complex return values.
            with Children(d):
224
225
                d.putCallItem("toString", value, "toString", qtdate + "TextDate")
                d.putCallItem("(ISO)", value, "toString", qtdate + "ISODate")
226
                d.putCallItem("(SystemLocale)", value, "toString",
227
228
                     qtdate + "SystemLocaleDate")
                d.putCallItem("(Locale)", value, "toString", qtdate + "LocaleDate")
229
230
231
    else:
        d.putValue("(invalid)")
        d.putNumChild(0)
232
233


hjk's avatar
hjk committed
234
def qdump__QDateTime(d, value):
235
236
237
238
    qtVersion = d.qtVersion()
    isValid = False
    # This relies on the Qt4/Qt5 internal structure layout:
    # {sharedref(4), ...
239
    base = d.dereferenceValue(value)
240
    if qtVersion >= 0x050200:
241
        dateBase = base + d.ptrSize() # Only QAtomicInt, but will be padded.
242
243
244
245
246
247
248
249
250
251
252
        ms = d.extractInt64(dateBase)
        offset = d.extractInt(dateBase + 12)
        isValid = ms > 0
        if isValid:
            d.putValue("%s" % (ms - offset * 1000), MillisecondsSinceEpoch)
    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;]
253
        # -      -  uint jd in Qt 4,  qint64 in Qt 5.0 and Qt 5.1; padded on 64 bit
254
255
256
        # -     [QTime time;]
        # -      -  uint mds;
        # -  Spec spec;
257
258
259
260
        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
261
262
263
264
265
266
267
        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:
268
269
270
271
        d.putNumChild(1)
        if d.isExpanded():
            # FIXME: This improperly uses complex return values.
            with Children(d):
272
273
                qtdate = d.qtNamespace() + "Qt::"
                qttime = qtdate
274
                if d.isLldb:
275
276
                    qtdate += "DateFormat::" # FIXME: Bug?...
                    qttime += "TimeSpec::" # FIXME: Bug?...
277
                d.putCallItem("toTime_t", value, "toTime_t")
hjk's avatar
hjk committed
278
279
280
281
282
283
                d.putCallItem("toString", value, "toString", qtdate + "TextDate")
                d.putCallItem("(ISO)", value, "toString", qtdate + "ISODate")
                d.putCallItem("(SystemLocale)", value, "toString", qtdate + "SystemLocaleDate")
                d.putCallItem("(Locale)", value, "toString", qtdate + "LocaleDate")
                d.putCallItem("toUTC", value, "toTimeSpec", qttime + "UTC")
                d.putCallItem("toLocalTime", value, "toTimeSpec", qttime + "LocalTime")
284
285
286
    else:
        d.putValue("(invalid)")
        d.putNumChild(0)
hjk's avatar
hjk committed
287
288
289


def qdump__QDir(d, value):
hjk's avatar
hjk committed
290
    d.putNumChild(1)
291
    privAddress = d.dereferenceValue(value)
292
293
    bit32 = d.is32bit()
    qt5 = d.qtVersion() >= 0x050000
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
    # 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;
    qt3SupportAddition = 0 if qt5 else d.ptrSize() # qt5 doesn't have qt3support
    filesOffset = (24 if bit32 else 40) + qt3SupportAddition
    fileInfosOffset = filesOffset + d.ptrSize()
    dirEntryOffset = fileInfosOffset + d.ptrSize()
    # QFileSystemEntry:
    # QString m_filePath
    # QByteArray m_nativeFilePath
    # qint16 m_lastSeparator
    # qint16 m_firstDotInFileName
    # qint16 m_lastDotInFileName
    # + 2 byte padding
    fileSystemEntrySize = 2 * d.ptrSize() + 8
    absoluteDirEntryOffset = dirEntryOffset + fileSystemEntrySize
    d.putStringValueByAddress(privAddress + dirEntryOffset)
hjk's avatar
hjk committed
323
324
    if d.isExpanded():
        with Children(d):
325
            ns = d.qtNamespace()
326
            d.call(value, "count")  # Fill cache.
327
328
329
            #d.putCallItem("absolutePath", value, "absolutePath")
            #d.putCallItem("canonicalPath", value, "canonicalPath")
            with SubItem(d, "absolutePath"):
330
                typ = d.lookupType(ns + "QString")
331
                d.putItem(d.createValue(privAddress + absoluteDirEntryOffset, typ))
332
            with SubItem(d, "entryInfoList"):
333
                typ = d.lookupType(ns + "QList<" + ns + "QFileInfo>")
334
                d.putItem(d.createValue(privAddress + fileInfosOffset, typ))
335
            with SubItem(d, "entryList"):
336
                typ = d.lookupType(ns + "QStringList")
337
                d.putItem(d.createValue(privAddress + filesOffset, typ))
hjk's avatar
hjk committed
338
339


hjk's avatar
hjk committed
340
def qdump__QFile(d, value):
hjk's avatar
hjk committed
341
    try:
342
        # Try using debug info first.
343
        ptype = d.lookupType(d.qtNamespace() + "QFilePrivate").pointer()
hjk's avatar
hjk committed
344
        d_ptr = value["d_ptr"]["d"]
345
346
        fileNameAddress = d.addressOf(d_ptr.cast(ptype).dereference()["fileName"])
        d.putNumChild(1)
hjk's avatar
hjk committed
347
    except:
Eike Ziller's avatar
Eike Ziller committed
348
349
350
351
        if d.qtVersion() >= 0x050000:
            offset = 176 if d.is32bit() else 280
        else:
            offset = 140 if d.is32bit() else 232
352
        privAddress = d.dereference(d.addressOf(value) + d.ptrSize())
353
        fileNameAddress = privAddress + offset
354
        d.putNumChild(0)
355
    d.putStringValueByAddress(fileNameAddress)
hjk's avatar
hjk committed
356
357
    if d.isExpanded():
        with Children(d):
358
            base = d.fieldAt(value.type, 0).type
359
            d.putSubItem("[%s]" % str(base), value.cast(base), False)
hjk's avatar
hjk committed
360
            d.putCallItem("exists", value, "exists")
hjk's avatar
hjk committed
361
362


hjk's avatar
hjk committed
363
def qdump__QFileInfo(d, value):
364
    privAddress = d.dereferenceValue(value)
365
366
367
368
369
370
371
372
    #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()
373
    d.putStringValueByAddress(filePathAddress)
hjk's avatar
hjk committed
374
    d.putNumChild(1)
hjk's avatar
hjk committed
375
    if d.isExpanded():
376
377
        ns = d.qtNamespace()
        with Children(d, childType=d.lookupType(ns + "QString")):
hjk's avatar
hjk committed
378
379
380
381
382
383
384
            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")
385
386
            if False:
                #ifdef Q_OS_MACX
hjk's avatar
hjk committed
387
388
389
390
                d.putCallItem("isBundle", value, "isBundle")
                d.putCallItem("bundleName", value, "bundleName")
            d.putCallItem("fileName", value, "fileName")
            d.putCallItem("filePath", value, "filePath")
391
            # Crashes gdb (archer-tromey-python, at dad6b53fe)
hjk's avatar
hjk committed
392
393
394
            #d.putCallItem("group", value, "group")
            #d.putCallItem("owner", value, "owner")
            d.putCallItem("path", value, "path")
395

hjk's avatar
hjk committed
396
397
            d.putCallItem("groupid", value, "groupId")
            d.putCallItem("ownerid", value, "ownerId")
398
399

            #QFile::Permissions permissions () const
400
            perms = d.call(value, "permissions")
401
402
403
            if perms is None:
                d.putValue("<not available>")
            else:
hjk's avatar
hjk committed
404
                with SubItem(d, "permissions"):
405
                    d.putEmptyValue()
406
                    d.putType(ns + "QFile::Permissions")
407
                    d.putNumChild(10)
hjk's avatar
hjk committed
408
                    if d.isExpanded():
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
                        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
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
            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
445
446
447
448
    d.putValue("%s/64 = %s" % (v, v/64.0))
    d.putNumChild(0)


hjk's avatar
hjk committed
449
def qdump__QFiniteStack(d, value):
hjk's avatar
hjk committed
450
451
    alloc = int(value["_alloc"])
    size = int(value["_size"])
452
    d.check(0 <= size and size <= alloc and alloc <= 1000 * 1000 * 1000)
hjk's avatar
hjk committed
453
454
455
    d.putItemCount(size)
    d.putNumChild(size)
    if d.isExpanded():
456
        innerType = d.templateArgument(value.type, 0)
hjk's avatar
hjk committed
457
458
        d.putArrayData(innerType, value["_array"], size)

459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
# 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
474
475
#    Traceback (most recent call last): File "<string>", line 1,
#      in <module> RuntimeError: No type named N::S::E.
476
477
478
479
480
#  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
481
482
def qdump__QFlags(d, value):
    i = value["i"]
483
    try:
484
        enumType = d.templateArgument(value.type.unqualified(), 0)
485
486
487
        d.putValue("%s (%s)" % (i.cast(enumType), i))
    except:
        d.putValue("%s" % i)
hjk's avatar
hjk committed
488
489
490
    d.putNumChild(0)


491
492
493
def qform__QHash():
    return mapForms()

hjk's avatar
hjk committed
494
def qdump__QHash(d, value):
hjk's avatar
hjk committed
495

hjk's avatar
hjk committed
496
497
498
    def hashDataFirstNode(dPtr, numBuckets):
        ePtr = dPtr.cast(nodeTypePtr)
        bucket = dPtr.dereference()["buckets"]
499
        for n in xrange(numBuckets - 1, -1, -1):
hjk's avatar
hjk committed
500
501
502
            n = n - 1
            if n < 0:
                break
503
            if d.pointerValue(bucket.dereference()) != d.pointerValue(ePtr):
hjk's avatar
hjk committed
504
505
                return bucket.dereference()
            bucket = bucket + 1
hjk's avatar
hjk committed
506
        return ePtr;
hjk's avatar
hjk committed
507

508
509
    def hashDataNextNode(nodePtr, numBuckets):
        nextPtr = nodePtr.dereference()["next"]
510
        if d.pointerValue(nextPtr.dereference()["next"]):
511
512
513
514
            return nextPtr
        start = (int(nodePtr.dereference()["h"]) % numBuckets) + 1
        dPtr = nextPtr.cast(dataTypePtr)
        bucket = dPtr.dereference()["buckets"] + start
515
        for n in xrange(numBuckets - start):
516
            if d.pointerValue(bucket.dereference()) != d.pointerValue(nextPtr):
hjk's avatar
hjk committed
517
518
                return bucket.dereference()
            bucket += 1
519
        return nextPtr
hjk's avatar
hjk committed
520

521
522
    keyType = d.templateArgument(value.type, 0)
    valueType = d.templateArgument(value.type, 1)
hjk's avatar
hjk committed
523

524
    anon = d.childAt(value, 0)
525
526
    d_ptr = anon["d"]
    e_ptr = anon["e"]
hjk's avatar
hjk committed
527
    size = int(d_ptr["size"])
hjk's avatar
hjk committed
528

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

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

535
536
    d.putItemCount(size)
    d.putNumChild(size)
hjk's avatar
hjk committed
537
    if d.isExpanded():
538
        numBuckets = int(d_ptr.dereference()["numBuckets"])
hjk's avatar
hjk committed
539
        nodePtr = hashDataFirstNode(d_ptr, numBuckets)
hjk's avatar
hjk committed
540
        innerType = e_ptr.dereference().type
541
542
        isCompact = d.isMapCompact(keyType, valueType)
        childType = valueType if isCompact else innerType
hjk's avatar
hjk committed
543
        with Children(d, size, maxNumChild=1000, childType=childType):
544
            for i in d.childRange():
545
                it = nodePtr.dereference().cast(innerType)
hjk's avatar
hjk committed
546
                with SubItem(d, i):
547
                    if isCompact:
548
549
550
551
552
553
                        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)
554
                        d.putItem(it["value"])
555
556
                        d.putType(valueType)
                    else:
hjk's avatar
hjk committed
557
                        d.putItem(it)
558
                nodePtr = hashDataNextNode(nodePtr, numBuckets)
hjk's avatar
hjk committed
559
560


hjk's avatar
hjk committed
561
562
def qdump__QHashNode(d, value):
    key = value["key"]
563
564
565
566
    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
567
    val = value["value"]
568
    d.putEmptyValue()
569
    d.putNumChild(2)
hjk's avatar
hjk committed
570
    if d.isExpanded():
571
        with Children(d):
hjk's avatar
hjk committed
572
573
            d.putSubItem("key", key)
            d.putSubItem("value", val)
hjk's avatar
hjk committed
574
575


576
577
def qHashIteratorHelper(d, value):
    typeName = str(value.type)
578
579
    hashTypeName = typeName[0:typeName.rfind("::")]
    hashType = d.lookupType(hashTypeName)
580
581
    keyType = d.templateArgument(hashType, 0)
    valueType = d.templateArgument(hashType, 1)
582
    d.putNumChild(1)
583
    d.putEmptyValue()
584
585
    if d.isExpanded():
        with Children(d):
586
587
588
589
            # 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)
590
591
592
593
594
595
596
            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)
597
598
599
600
601
602
603
604
605
            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
606
def qdump__QHostAddress(d, value):
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
    # 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)

622
    privAddress = d.dereferenceValue(value)
623
    isQt5 = d.qtVersion() >= 0x050000
624
    sizeofQString = d.ptrSize()
625
    ipStringAddress = privAddress + (0 if isQt5 else 24)
626
    isParsedAddress = privAddress + 24 + 2 * sizeofQString
627
    # value.d.d->ipString
628
    ipString = d.encodeStringHelper(d.dereference(ipStringAddress))
629
    if d.extractByte(isParsedAddress) and len(ipString) > 0:
630
        d.putValue(ipString, Hex4EncodedLittleEndian)
hjk's avatar
hjk committed
631
    else:
632
633
634
635
636
637
638
639
        # 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
            a6 = privAddress + 4 + (2 * sizeofQString if isQt5 else 0)
640
            data = d.readMemory(a6, 16)
641
642
            address = ':'.join("%x" % int(data[i:i+4], 16) for i in xrange(0, 32, 4))
            scopeId = privAddress + sizeofQString + (0 if isQt5 else 24)
643
            scopeId = d.encodeStringHelper(d.dereference(scopeId))
644
645
646
647
648
649
650
651
652
653
654
655
            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>")

656
657
    d.putPlainChildren(value["d"]["d"].dereference())

hjk's avatar
hjk committed
658

659
def qdump__Q_IPV6ADDR(d, value):
660
    data = d.readMemory(d.addressOf(value), 16)
661
662
663
664
665
666
667
    d.putValue(':'.join("%x" % int(data[i:i+4], 16) for i in xrange(0, 32, 4)))
    d.putPlainChildren(value["c"])

def qdump__QIPv6Address(d, value):
    qdump__Q_IPV6ADDR(d, value)


668
669
670
def qform__QList():
    return "Assume Direct Storage,Assume Indirect Storage"

hjk's avatar
hjk committed
671
def qdump__QList(d, value):
672
    dptr = d.childAt(value, 0)["d"]
673
674
675
676
    private = dptr.dereference()
    begin = int(private["begin"])
    end = int(private["end"])
    array = private["array"]
677
    d.check(begin >= 0 and end >= 0 and end <= 1000 * 1000 * 1000)
678
    size = end - begin
679
680
    d.check(size >= 0)
    d.checkRef(private["ref"])
hjk's avatar
hjk committed
681

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

684
685
    d.putItemCount(size)
    d.putNumChild(size)
hjk's avatar
hjk committed
686
    if d.isExpanded():
hjk's avatar
hjk committed
687
        innerSize = innerType.sizeof
688
689
        stepSize = dptr.type.sizeof
        addr = d.addressOf(array) + begin * stepSize
hjk's avatar
hjk committed
690
691
692
693
694
        # 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:
695
696
697
698
699
700
701
        format = d.currentItemFormat()
        if format == 1:
            isInternal = True
        elif format == 2:
            isInternal = False
        else:
            isInternal = innerSize <= stepSize and d.isMovableType(innerType)
702
703
        if isInternal:
            if innerSize == stepSize:
704
                p = d.createPointerValue(addr, innerType)
705
706
707
708
                d.putArrayData(innerType, p, size)
            else:
                with Children(d, size, childType=innerType):
                    for i in d.childRange():
709
710
                        p = d.createValue(addr + i * stepSize, innerType)
                        d.putSubItem(i, p)
711
        else:
712
            p = d.createPointerValue(addr, innerType.pointer())
713
714
715
716
717
            # 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
718

hjk's avatar
hjk committed
719
720
def qform__QImage():
    return "Normal,Displayed"
hjk's avatar
hjk committed
721

hjk's avatar
hjk committed
722
def qdump__QImage(d, value):
723
724
725
726
    # This relies on current QImage layout:
    # QImageData:
    # - QAtomicInt ref
    # - int width, height, depth, nbytes
727
728
729
730
    # - 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)
731
    # [- uchar **jumptable jumptable with Qt 3 suppor]
732
    # - enum format (+20 + padding + gap + 2 * ptr)
733
734
735
736
737
738
739
740

    ptrSize = d.ptrSize()
    isQt5 = d.qtVersion() >= 0x050000
    offset = (3 if isQt5 else 2) * ptrSize
    base = d.dereference(d.addressOf(value) + offset)
    width = d.extractInt(base + 4)
    height = d.extractInt(base + 8)
    nbytes = d.extractInt(base + 16)
741
    padding = d.ptrSize() - d.intSize()
742
743
    pixelRatioSize = 8 if isQt5 else 0
    jumpTableSize = ptrSize if not isQt5 else 0  # FIXME: Assumes Qt3 Support
744
745
    bits = d.dereference(base + 20 + padding + pixelRatioSize + ptrSize)
    iformat = d.extractInt(base + 20 + padding + pixelRatioSize + jumpTableSize + 2 * ptrSize)
746
    d.putValue("(%dx%d)" % (width, height))
747
    d.putNumChild(1)
hjk's avatar
hjk committed
748
    if d.isExpanded():
749
        with Children(d):
750
751
752
753
            d.putIntItem("width", width)
            d.putIntItem("height", height)
            d.putIntItem("nbytes", nbytes)
            d.putIntItem("format", iformat)
hjk's avatar
hjk committed
754
            with SubItem(d, "data"):
755
                d.putValue("0x%x" % bits)
756
                d.putNumChild(0)
757
758
                d.putType("void *")

hjk's avatar
hjk committed
759
    format = d.currentItemFormat()
760
    if format == 1:
761
        d.putDisplay(StopDisplay)
762
    elif format == 2:
763
764
765
766
767
768
769
770
771
772
773
        # 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))
774
        d.put(d.readMemory(bits, nbytes))
775
        d.put('",')
hjk's avatar
hjk committed
776
777


hjk's avatar
hjk committed
778
def qdump__QLinkedList(d, value):
hjk's avatar
hjk committed
779
780
781
782
    dd = d.dereferenceValue(value)
    ptrSize = d.ptrSize()
    n = d.extractInt(dd + 4 + 2 * ptrSize);
    ref = d.extractInt(dd + 2 * ptrSize);
783
784
    d.check(0 <= n and n <= 100*1000*1000)
    d.check(-1 <= ref and ref <= 1000)
hjk's avatar
hjk committed
785
    d.putItemCount(n)
786
    d.putNumChild(n)
hjk's avatar
hjk committed
787
    if d.isExpanded():
788
        innerType = d.templateArgument(value.type, 0)
hjk's avatar
hjk committed
789
        with Children(d, n, maxNumChild=1000, childType=innerType):
hjk's avatar
hjk committed
790
            pp = d.dereference(dd)
791
            for i in d.childRange():
hjk's avatar
hjk committed
792
793
                d.putSubItem(i, d.createValue(pp + 2 * ptrSize, innerType))
                pp = d.dereference(pp)
hjk's avatar
hjk committed
794

795
qqLocalesCount = None
hjk's avatar
hjk committed
796

hjk's avatar
hjk committed
797
def qdump__QLocale(d, value):
798
799
800
801
    # 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
802
803
804
    #global qqLocalesCount
    #if qqLocalesCount is None:
    #    #try:
805
    #        qqLocalesCount = int(value(ns + 'locale_data_size'))
hjk's avatar
hjk committed
806
807
808
809
810
811
812
813
814
    #    #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"]...)
815
816
817
    #d.check(index >= 0)
    #d.check(index <= qqLocalesCount)
    d.putStringValue(d.call(value, "name"))
818
819
820
    d.putNumChild(0)
    return
    # FIXME: Poke back for variants.
hjk's avatar
hjk committed
821
    if d.isExpanded():
822
823
        ns = d.qtNamespace()
        with Children(d, childType=d.lookupType(ns + "QChar"), childNumChild=0):
hjk's avatar
hjk committed
824
825
826
827
828
            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,
829
                "timeFormat", ns + "QLocale::ShortFormat")
hjk's avatar
hjk committed
830
            d.putCallItem("timeFormat_(long)", value,
831
                "timeFormat", ns + "QLocale::LongFormat")
hjk's avatar
hjk committed
832
833
834
835
836
837
            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
838
839


hjk's avatar
hjk committed
840
def qdump__QMapNode(d, value):
841
    d.putEmptyValue()
842
    d.putNumChild(2)
hjk's avatar
hjk committed
843
844
845
846
847
848
    if d.isExpanded():
        with Children(d):
            d.putSubItem("key", value["key"])
            d.putSubItem("value", value["value"])


849
def qdumpHelper__Qt4_QMap(d, value, forceLong):
hjk's avatar
hjk committed
850
851
    d_ptr = value["d"].dereference()
    e_ptr = value["e"].dereference()
hjk's avatar
hjk committed
852
    n = int(d_ptr["size"])
853
854
    d.check(0 <= n and n <= 100*1000*1000)
    d.checkRef(d_ptr["ref"])
hjk's avatar
hjk committed
855
856

    d.putItemCount(n)
857
    d.putNumChild(n)
hjk's avatar
hjk committed
858
    if d.isExpanded():
859
860
        if n > 10000:
            n = 10000
hjk's avatar
hjk committed
861

862
863
        keyType = d.templateArgument(value.type, 0)
        valueType = d.templateArgument(value.type, 1)
hjk's avatar
hjk committed
864
        isCompact = d.isMapCompact(keyType, valueType)
hjk's avatar
hjk committed
865
866
867
868
869
870

        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 *)
871
        nodeType = d.lookupType(d.qtNamespace() + "QMapNode<%s,%s>" % (keyType, valueType))
hjk's avatar
hjk committed
872
873
        nodePointerType = nodeType.pointer()
        payloadSize = nodeType.sizeof - 2 * nodePointerType.sizeof
hjk's avatar
hjk committed
874

875
        if isCompact:
876
877
878
            innerType = valueType
        else:
            innerType = nodeType
hjk's avatar
hjk committed
879

hjk's avatar
hjk committed
880
        with Children(d, n, childType=innerType):
881
            for i in xrange(n):
hjk's avatar
hjk committed
882
883
                base = it.cast(d.charPtrType()) - payloadSize
                node = base.cast(nodePointerType).dereference()
hjk's avatar
hjk committed
884
                with SubItem(d, i):
885
                    d.putField("iname", d.currentIName)
886
                    if isCompact:
887
                        #d.putType(valueType)
hjk's avatar
hjk committed
888
                        if forceLong:
889
                            d.putName("[%s] %s" % (i, node["key"]))