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 738 739 740 741 742
    base = d.extractPointer(value)
    begin = d.extractInt(base + 8)
    end = d.extractInt(base + 12)
    array = base + 16
    if d.qtVersion() < 0x50000:
        array += d.ptrSize()
743
    d.check(begin >= 0 and end >= 0 and end <= 1000 * 1000 * 1000)
744
    size = end - begin
745
    d.check(size >= 0)
746
    #d.checkRef(private["ref"])
hjk's avatar
hjk committed
747

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

750 751
    d.putItemCount(size)
    d.putNumChild(size)
hjk's avatar
hjk committed
752
    if d.isExpanded():
hjk's avatar
hjk committed
753
        innerSize = innerType.sizeof
754 755
        stepSize = d.ptrSize()
        addr = array + begin * stepSize
hjk's avatar
hjk committed
756 757 758 759 760
        # 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:
761 762 763 764 765 766 767
        format = d.currentItemFormat()
        if format == 1:
            isInternal = True
        elif format == 2:
            isInternal = False
        else:
            isInternal = innerSize <= stepSize and d.isMovableType(innerType)
768 769
        if isInternal:
            if innerSize == stepSize:
770
                p = d.createPointerValue(addr, innerType)
771 772 773 774
                d.putArrayData(innerType, p, size)
            else:
                with Children(d, size, childType=innerType):
                    for i in d.childRange():
775 776
                        p = d.createValue(addr + i * stepSize, innerType)
                        d.putSubItem(i, p)
777
        else:
778 779 780
            # about 0.5s / 1000 items
            with Children(d, size, maxNumChild=2000, childType=innerType):
                for i in d.childRange():
781 782 783
                    p = d.extractPointer(addr + i * stepSize)
                    x = d.createValue(p, innerType)
                    d.putSubItem(i, x)
hjk's avatar
hjk committed
784

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

hjk's avatar
hjk committed
788
def qdump__QImage(d, value):
789 790 791 792
    # This relies on current QImage layout:
    # QImageData:
    # - QAtomicInt ref
    # - int width, height, depth, nbytes
793 794 795 796
    # - 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)
797
    # [- uchar **jumptable jumptable with Qt 3 suppor]
798
    # - enum format (+20 + padding + gap + 2 * ptr)
799 800 801 802

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

hjk's avatar
hjk committed
829
    format = d.currentItemFormat()
830
    if format == 1:
831
        d.putDisplay(StopDisplay)
832
    elif format == 2:
833 834 835 836 837 838 839 840 841 842 843
        # 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))
844
        d.put(d.readMemory(bits, nbytes))
845
        d.put('",')
hjk's avatar
hjk committed
846 847


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

865
qqLocalesCount = None
hjk's avatar
hjk committed
866

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


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


919
def qdumpHelper__Qt4_QMap(d, value):