qttypes.py 105 KB
Newer Older
hjk's avatar
hjk committed
1 2 3 4 5 6 7

#######################################################################
#
# Dumper Implementations
#
#######################################################################

8 9
from __future__ import with_statement

10 11 12 13 14 15 16 17 18 19
movableTypes = set([
    "QBrush", "QBitArray", "QByteArray", "QCustomTypeInfo", "QChar", "QDate",
    "QDateTime", "QFileInfo", "QFixed", "QFixedPoint", "QFixedSize",
    "QHashDummyValue", "QIcon", "QImage", "QLine", "QLineF", "QLatin1Char",
    "QLocale", "QMatrix", "QModelIndex", "QPoint", "QPointF", "QPen",
    "QPersistentModelIndex", "QResourceRoot", "QRect", "QRectF", "QRegExp",
    "QSize", "QSizeF", "QString", "QTime", "QTextBlock", "QUrl", "QVariant",
    "QXmlStreamAttribute", "QXmlStreamNamespaceDeclaration",
    "QXmlStreamNotationDeclaration", "QXmlStreamEntityDeclaration"
])
20

21

22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
def checkSimpleRef(ref):
    count = int(ref["_q_value"])
    check(count > 0)
    check(count < 1000000)

def checkRef(ref):
    try:
        count = int(ref["atomic"]["_q_value"]) # Qt 5.
        minimum = -1
    except:
        count = int(ref["_q_value"]) # Qt 4.
        minimum = 0
    # Assume there aren't a million references to any object.
    check(count >= minimum)
    check(count < 1000000)

38
def qByteArrayData(d, addr):
39 40
    intSize = d.intSize()
    ptrSize = d.ptrSize()
41 42 43 44 45 46
    if d.qtVersion() >= 0x050000:
        # QTypedArray:
        # - QtPrivate::RefCount ref
        # - int size
        # - uint alloc : 31, capacityReserved : 1
        # - qptrdiff offset
47 48 49
        size = d.extractInt(addr + intSize)
        alloc = d.extractInt(addr + 2 * intSize) & 0x7ffffff
        data = addr + d.dereference(addr + 2 * intSize + ptrSize)
50 51 52 53
    else:
        # Data:
        # - QBasicAtomicInt ref;
        # - int alloc, size;
54
        # - [padding]
55
        # - char *data;
56 57
        alloc = d.extractInt(addr + intSize)
        size = d.extractInt(addr + 2 * intSize)
58
        data = d.dereference(addr + 2 * intSize + ptrSize)
59
    return data, size, alloc
60 61


62
def qEncodeByteArray(d, addr, limit = None):
63
    data, size, alloc = qByteArrayData(d, addr)
64 65 66 67 68 69 70 71
    if alloc != 0:
        check(0 <= size and size <= alloc and alloc <= 100*1000*1000)
    limit = d.computeLimit(size, limit)
    s = d.readRawMemory(data, limit)
    if limit < size:
        s += "2e2e2e"
    return s

72
# addr is the begin of a QByteArrayData structure
73 74
def qEncodeString(d, addr, limit = 0):
    data, size, alloc = qByteArrayData(d, addr)
75 76 77 78 79 80 81 82
    if alloc != 0:
        check(0 <= size and size <= alloc and alloc <= 100*1000*1000)
    limit = d.computeLimit(size, limit)
    s = d.readRawMemory(data, 2 * limit)
    if limit < size:
        s += "2e002e002e00"
    return s

83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
def qPutStringValueByAddress(d, addr):
    d.putValue(qEncodeString(d, d.dereference(addr)), Hex4EncodedLittleEndian)

Dumper.encodeByteArray = \
    lambda d, value: qEncodeByteArray(d, d.dereferenceValue(value))
Dumper.byteArrayData = \
    lambda d, value: qByteArrayData(d, d.dereferenceValue(value))
Dumper.putByteArrayValue = \
    lambda d, value: d.putValue(d.encodeByteArray(value), Hex2EncodedLatin1)

Dumper.encodeString = \
    lambda d, value: qEncodeString(d, d.dereferenceValue(value))
Dumper.stringData = \
    lambda d, value: qByteArrayData(d, d.dereferenceValue(value))
Dumper.putStringValue = \
    lambda d, value: d.putValue(d.encodeString(value), Hex4EncodedLittleEndian)


hjk's avatar
hjk committed
101 102 103 104 105 106 107 108
def mapForms():
    return "Normal,Compact"

def arrayForms():
    if hasPlot():
        return "Normal,Plot"
    return "Normal"

hjk's avatar
hjk committed
109
def qMapCompact(format, keyType, valueType):
hjk's avatar
hjk committed
110 111 112 113
    if format == 2:
        return True # Compact.
    return isSimpleType(keyType) and isSimpleType(valueType)

hjk's avatar
hjk committed
114
def qPutMapName(d, value):
hjk's avatar
hjk committed
115 116 117 118 119 120 121 122 123 124 125 126
    if str(value.type) == d.ns + "QString":
        d.put('key="%s",' % d.encodeString(value))
        d.put('keyencoded="%s",' % Hex4EncodedLittleEndian)
    elif str(value.type) == d.ns + "QByteArray":
        d.put('key="%s",' % d.encodeByteArray(value))
        d.put('keyencoded="%s",' % Hex2EncodedLatin1)
    else:
        if lldbLoaded:
            d.put('name="%s",' % value.GetValue())
        else:
            d.put('name="%s",' % value)

hjk's avatar
hjk committed
127
Dumper.putMapName = qPutMapName
hjk's avatar
hjk committed
128 129

Dumper.isMapCompact = \
hjk's avatar
hjk committed
130
    lambda d, keyType, valueType: qMapCompact(d.currentItemFormat(), keyType, valueType)
hjk's avatar
hjk committed
131 132


133
def qPutQObjectNameValue(d, value):
hjk's avatar
hjk committed
134
    try:
135 136
        intSize = d.intSize()
        ptrSize = d.ptrSize()
hjk's avatar
hjk committed
137
        # dd = value["d_ptr"]["d"] is just behind the vtable.
138
        dd = d.dereference(d.addressOf(value) + ptrSize)
hjk's avatar
hjk committed
139 140 141 142 143 144 145 146 147 148 149 150 151 152

        if d.qtVersion() < 0x050000:
            # Size of QObjectData: 5 pointer + 2 int
            #  - vtable
            #   - QObject *q_ptr;
            #   - QObject *parent;
            #   - QObjectList children;
            #   - uint isWidget : 1; etc..
            #   - int postedEvents;
            #   - QMetaObject *metaObject;

            # Offset of objectName in QObjectPrivate: 5 pointer + 2 int
            #   - [QObjectData base]
            #   - QString objectName
153 154
            objectName = d.dereference(dd + 5 * ptrSize + 2 * intSize)

hjk's avatar
hjk committed
155 156 157 158 159 160 161 162 163
        else:
            # Size of QObjectData: 5 pointer + 2 int
            #   - vtable
            #   - QObject *q_ptr;
            #   - QObject *parent;
            #   - QObjectList children;
            #   - uint isWidget : 1; etc...
            #   - int postedEvents;
            #   - QDynamicMetaObjectData *metaObject;
164 165 166
            extra = d.dereference(dd + 5 * ptrSize + 2 * intSize)
            if extra == 0:
                return
hjk's avatar
hjk committed
167 168 169 170 171 172 173 174

            # Offset of objectName in ExtraData: 6 pointer
            #   - QVector<QObjectUserData *> userData; only #ifndef QT_NO_USERDATA
            #   - QList<QByteArray> propertyNames;
            #   - QList<QVariant> propertyValues;
            #   - QVector<int> runningTimers;
            #   - QList<QPointer<QObject> > eventFilters;
            #   - QString objectName
175 176
            objectName = d.dereference(extra + 5 * ptrSize)

177
        data, size, alloc = qByteArrayData(d, objectName)
178

179 180 181 182
        if size > 0:
            str = d.readRawMemory(data, 2 * size)
            d.putValue(str, Hex4EncodedLittleEndian, 1)

hjk's avatar
hjk committed
183
    except:
hjk's avatar
hjk committed
184
        pass
hjk's avatar
hjk committed
185

186
Dumper.putQObjectNameValue = qPutQObjectNameValue
hjk's avatar
hjk committed
187

hjk's avatar
hjk committed
188
###################################################################################
hjk's avatar
hjk committed
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210


def qdump__QAtomicInt(d, value):
    d.putValue(value["_q_value"])
    d.putNumChild(0)


def qdump__QBasicAtomicInt(d, value):
    d.putValue(value["_q_value"])
    d.putNumChild(0)


def qdump__QBasicAtomicPointer(d, value):
    d.putType(value.type)
    p = cleanAddress(value["_q_value"])
    d.putValue(p)
    d.putPointerValue(value.address)
    d.putNumChild(p)
    if d.isExpanded():
        with Children(d):
           d.putItem(value["_q_value"])

211 212 213
def qform__QByteArray():
    return "Inline,As Latin1 in Separate Window,As UTF-8 in Separate Window"

hjk's avatar
hjk committed
214 215
def qdump__QByteArray(d, value):
    d.putByteArrayValue(value)
hjk's avatar
hjk committed
216
    data, size, alloc = d.byteArrayData(value)
217
    d.putNumChild(size)
218 219 220 221
    format = d.currentItemFormat()
    if format == 1:
        d.putDisplay(StopDisplay)
    elif format == 2:
222
        d.putField("editformat", DisplayLatin1String)
hjk's avatar
hjk committed
223
        d.putField("editvalue", d.encodeByteArray(value, None))
224
    elif format == 3:
225
        d.putField("editformat", DisplayUtf8String)
hjk's avatar
hjk committed
226
        d.putField("editvalue", d.encodeByteArray(value, None))
hjk's avatar
hjk committed
227
    if d.isExpanded():
228
        d.putArrayData(d.charType(), data, size)
hjk's avatar
hjk committed
229 230


231 232 233 234 235 236 237 238 239 240 241 242 243
# Fails on Windows.
try:
    import curses.ascii
    def printableChar(ucs):
        if curses.ascii.isprint(ucs):
            return ucs
        return '?'
except:
    def printableChar(ucs):
        if ucs >= 32 and ucs <= 126:
            return ucs
        return '?'

hjk's avatar
hjk committed
244 245
def qdump__QChar(d, value):
    ucs = int(value["ucs"])
246
    d.putValue("'%c' (%d)" % (printableChar(ucs), ucs))
hjk's avatar
hjk committed
247 248 249
    d.putNumChild(0)


hjk's avatar
hjk committed
250
def qform__QAbstractItemModel():
251
    return "Normal,Enhanced"
252

hjk's avatar
hjk committed
253
def qdump__QAbstractItemModel(d, value):
254 255 256 257 258
    format = d.currentItemFormat()
    if format == 1:
        d.putPlainChildren(value)
        return
    #format == 2:
259
    # Create a default-constructed QModelIndex on the stack.
260
    try:
261
        ri = makeValue(d.ns + "QModelIndex", "-1, -1, 0, 0")
hjk's avatar
hjk committed
262
        this_ = makeExpression(value)
263
        ri_ = makeExpression(ri)
264 265 266
        rowCount = int(parseAndEvaluate("%s.rowCount(%s)" % (this_, ri_)))
        columnCount = int(parseAndEvaluate("%s.columnCount(%s)" % (this_, ri_)))
    except:
hjk's avatar
hjk committed
267
        d.putPlainChildren(value)
268
        return
269 270
    d.putValue("%d x %d" % (rowCount, columnCount))
    d.putNumChild(rowCount * columnCount)
hjk's avatar
hjk committed
271 272
    if d.isExpanded():
        with Children(d, numChild=rowCount * columnCount, childType=ri.type):
273 274 275
            i = 0
            for row in xrange(rowCount):
                for column in xrange(columnCount):
hjk's avatar
hjk committed
276
                    with SubItem(d, i):
277 278 279 280 281 282
                        d.putName("[%s, %s]" % (row, column))
                        mi = parseAndEvaluate("%s.index(%d,%d,%s)"
                            % (this_, row, column, ri_))
                        #warn("MI: %s " % mi)
                        #name = "[%d,%d]" % (row, column)
                        #d.putValue("%s" % mi)
hjk's avatar
hjk committed
283
                        d.putItem(mi)
284 285 286 287 288 289 290 291
                        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)")

292 293 294
def qform__QModelIndex():
    return "Normal,Enhanced"

hjk's avatar
hjk committed
295
def qdump__QModelIndex(d, value):
296 297 298 299
    format = d.currentItemFormat()
    if format == 1:
        d.putPlainChildren(value)
        return
hjk's avatar
hjk committed
300 301
    r = value["r"]
    c = value["c"]
302 303 304 305
    try:
        p = value["p"]
    except:
        p = value["i"]
hjk's avatar
hjk committed
306
    m = value["m"]
307 308 309 310 311
    if isNull(m) or r < 0 or c < 0:
        d.putValue("(invalid)")
        d.putPlainChildren(value)
        return

312 313
    mm = m.dereference()
    mm = mm.cast(mm.type.unqualified())
314
    try:
315 316 317
        mi = makeValue(d.ns + "QModelIndex", "%s,%s,%s,%s" % (r, c, p, m))
        mm_ = makeExpression(mm)
        mi_ = makeExpression(mi)
318 319 320
        rowCount = int(parseAndEvaluate("%s.rowCount(%s)" % (mm_, mi_)))
        columnCount = int(parseAndEvaluate("%s.columnCount(%s)" % (mm_, mi_)))
    except:
321
        d.putEmptyValue()
hjk's avatar
hjk committed
322
        d.putPlainChildren(value)
323
        return
324 325 326

    try:
        # Access DisplayRole as value
hjk's avatar
hjk committed
327 328
        val = parseAndEvaluate("%s.data(%s, 0)" % (mm_, mi_))
        v = val["d"]["data"]["ptr"]
329 330 331 332
        d.putStringValue(makeValue(d.ns + 'QString', v))
    except:
        d.putValue("(invalid)")

333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
    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))
                        mi2 = parseAndEvaluate("%s.index(%d,%d,%s)"
                            % (mm_, row, column, mi_))
                        d.putItem(mi2)
                        i = i + 1
            #d.putCallItem("parent", val, "parent")
            #with SubItem(d, "model"):
            #    d.putValue(m)
            #    d.putType(d.ns + "QAbstractItemModel*")
            #    d.putNumChild(1)
350 351
    #gdb.execute("call free($mi)")

hjk's avatar
hjk committed
352

hjk's avatar
hjk committed
353
def qdump__QDate(d, value):
354
    jd = int(value["jd"])
355 356 357 358 359
    if int(jd):
        d.putValue(jd, JulianDate)
        d.putNumChild(1)
        if d.isExpanded():
            qt = d.ns + "Qt::"
360 361
            if lldbLoaded:
                qt += "DateFormat::" # FIXME: Bug?...
362 363 364 365 366 367 368 369 370 371
            # 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
372 373


hjk's avatar
hjk committed
374
def qdump__QTime(d, value):
375 376 377 378 379
    mds = value["mds"]
    if int(mds) >= 0:
        d.putValue(value["mds"], MillisecondsSinceMidnight)
        d.putNumChild(1)
        if d.isExpanded():
380 381
            qtdate = d.ns + "Qt::"
            qttime = d.ns + "Qt::"
382
            if lldbLoaded:
383 384
                qtdate += "DateFormat::" # FIXME: Bug?...
                qttime += "TimeSpec::"
385 386
            # FIXME: This improperly uses complex return values.
            with Children(d):
387 388
                d.putCallItem("toString", value, "toString", qtdate + "TextDate")
                d.putCallItem("(ISO)", value, "toString", qtdate + "ISODate")
389
                d.putCallItem("(SystemLocale)", value, "toString",
390 391 392
                     qtdate + "SystemLocaleDate")
                d.putCallItem("(Locale)", value, "toString", qtdate + "LocaleDate")
                d.putCallItem("toUTC", value, "toTimeSpec", qttime + "UTC")
393 394 395
    else:
        d.putValue("(invalid)")
        d.putNumChild(0)
396 397


398 399
# This relies on the Qt4/Qt5 internal structure layout:
# {sharedref(4), date(8), time(4+x)}
hjk's avatar
hjk committed
400
def qdump__QDateTime(d, value):
401
    base = d.dereferenceValue(value)
402 403 404 405 406 407 408 409 410
    # QDateTimePrivate:
    # - QAtomicInt ref;
    # -     [QDate date;]  (+4)
    # -      -  uint jd in Qt 4,  qint64 in Qt 5
    # -     [QTime time;]  (+4 + dateSize)
    # -      -  uint mds;
    # -  Spec spec;
    dateSize = 8 if d.qtVersion() >= 0x050000 else 4
    mds = d.extractInt(base + 4 + dateSize)
411
    if mds >= 0:
412
        jd = d.extractInt(base + 4)
413
        d.putValue("%s/%s" % (jd, mds), JulianDateAndMillisecondsSinceMidnight)
414 415 416 417
        d.putNumChild(1)
        if d.isExpanded():
            # FIXME: This improperly uses complex return values.
            with Children(d):
418 419
                qtdate = d.ns + "Qt::"
                qttime = d.ns + "Qt::"
420
                if lldbLoaded:
421 422
                    qtdate += "DateFormat::" # FIXME: Bug?...
                    qttime += "TimeSpec::" # FIXME: Bug?...
423
                d.putCallItem("toTime_t", value, "toTime_t")
424 425 426 427 428 429
                #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")
430 431 432
    else:
        d.putValue("(invalid)")
        d.putNumChild(0)
hjk's avatar
hjk committed
433 434 435


def qdump__QDir(d, value):
hjk's avatar
hjk committed
436
    d.putNumChild(1)
437
    privAddress = d.dereferenceValue(value)
438 439 440 441 442 443 444 445 446 447
    bit32 = d.is32bit()
    qt5 = d.qtVersion() >= 0x050000
    offset = (32 if bit32 else 40) if qt5 else 36
    filePathAddress = privAddress + offset
    #try:
    #    # Up to Qt 4.7
    #    d.putStringValue(data["path"])
    #except:
    #    # Qt 4.8 and later.
    #    d.putStringValue(data["dirEntry"]["m_filePath"])
448
    qPutStringValueByAddress(d, filePathAddress)
hjk's avatar
hjk committed
449 450
    if d.isExpanded():
        with Children(d):
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
            call(value, "count")  # Fill cache.
            #d.putCallItem("absolutePath", value, "absolutePath")
            #d.putCallItem("canonicalPath", value, "canonicalPath")
            with SubItem(d, "absolutePath"):
                # d_ptr.d.priv.absoluteDirEntry.m_filePath
                offset = (48 if bit32 else 60) if qt5 else 36
                typ = d.lookupType(d.ns + "QString")
                d.putItem(d.createValue(privAddress + offset, typ))
            with SubItem(d, "entryInfoList"):
                # d_ptr.d.priv.fileInfos
                offset = (28 if bit32 else 32) if qt5 else 32
                typ = d.lookupType(d.ns + "QFileInfoList")
                d.putItem(d.createValue(privAddress + offset, typ))
            with SubItem(d, "entryList"):
                # d.ptr.d.priv.files
                offset = 24 if qt5 else 28
                typ = d.lookupType(d.ns + "QStringList")
                d.putItem(d.createValue(privAddress + offset, typ))
hjk's avatar
hjk committed
469 470


hjk's avatar
hjk committed
471
def qdump__QFile(d, value):
hjk's avatar
hjk committed
472
    try:
473
        # Try using debug info first.
474
        ptype = d.lookupType(d.ns + "QFilePrivate").pointer()
hjk's avatar
hjk committed
475
        d_ptr = value["d_ptr"]["d"]
476 477
        fileNameAddress = d.addressOf(d_ptr.cast(ptype).dereference()["fileName"])
        d.putNumChild(1)
hjk's avatar
hjk committed
478
    except:
479
        # 176 is the best guess.
480 481 482
        privAddress = d.dereference(d.addressOf(value) + d.ptrSize())
        fileNameAddress = privAddress + 176 # Qt 5, 32 bit
        d.putNumChild(0)
483
    qPutStringValueByAddress(d, fileNameAddress)
hjk's avatar
hjk committed
484 485
    if d.isExpanded():
        with Children(d):
hjk's avatar
hjk committed
486
            base = fieldAt(value.type, 0).type
487
            d.putSubItem("[%s]" % str(base), value.cast(base), False)
hjk's avatar
hjk committed
488
            d.putCallItem("exists", value, "exists")
hjk's avatar
hjk committed
489 490


hjk's avatar
hjk committed
491
def qdump__QFileInfo(d, value):
492
    privAddress = d.dereferenceValue(value)
493 494 495 496 497 498 499 500
    #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()
501
    qPutStringValueByAddress(d, filePathAddress)
hjk's avatar
hjk committed
502
    d.putNumChild(1)
hjk's avatar
hjk committed
503
    if d.isExpanded():
504
        with Children(d, childType=d.lookupType(d.ns + "QString")):
hjk's avatar
hjk committed
505 506 507 508 509 510 511
            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")
512 513
            if False:
                #ifdef Q_OS_MACX
hjk's avatar
hjk committed
514 515 516 517
                d.putCallItem("isBundle", value, "isBundle")
                d.putCallItem("bundleName", value, "bundleName")
            d.putCallItem("fileName", value, "fileName")
            d.putCallItem("filePath", value, "filePath")
518
            # Crashes gdb (archer-tromey-python, at dad6b53fe)
hjk's avatar
hjk committed
519 520 521
            #d.putCallItem("group", value, "group")
            #d.putCallItem("owner", value, "owner")
            d.putCallItem("path", value, "path")
522

hjk's avatar
hjk committed
523 524
            d.putCallItem("groupid", value, "groupId")
            d.putCallItem("ownerid", value, "ownerId")
525 526

            #QFile::Permissions permissions () const
hjk's avatar
hjk committed
527
            perms = call(value, "permissions")
528 529 530
            if perms is None:
                d.putValue("<not available>")
            else:
hjk's avatar
hjk committed
531
                with SubItem(d, "permissions"):
532
                    d.putEmptyValue()
533 534
                    d.putType(d.ns + "QFile::Permissions")
                    d.putNumChild(10)
hjk's avatar
hjk committed
535
                    if d.isExpanded():
536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552
                        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
553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571
            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
572 573 574 575
    d.putValue("%s/64 = %s" % (v, v/64.0))
    d.putNumChild(0)


hjk's avatar
hjk committed
576
def qdump__QFiniteStack(d, value):
hjk's avatar
hjk committed
577 578
    alloc = int(value["_alloc"])
    size = int(value["_size"])
hjk's avatar
hjk committed
579 580 581 582
    check(0 <= size and size <= alloc and alloc <= 1000 * 1000 * 1000)
    d.putItemCount(size)
    d.putNumChild(size)
    if d.isExpanded():
583
        innerType = d.templateArgument(value.type, 0)
hjk's avatar
hjk committed
584 585
        d.putArrayData(innerType, value["_array"], size)

586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
# 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
601 602
#    Traceback (most recent call last): File "<string>", line 1,
#      in <module> RuntimeError: No type named N::S::E.
603 604 605 606 607
#  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
608 609
def qdump__QFlags(d, value):
    i = value["i"]
610
    try:
611
        enumType = d.templateArgument(value.type.unqualified(), 0)
612 613 614
        d.putValue("%s (%s)" % (i.cast(enumType), i))
    except:
        d.putValue("%s" % i)
hjk's avatar
hjk committed
615 616 617
    d.putNumChild(0)


618 619 620
def qform__QHash():
    return mapForms()

hjk's avatar
hjk committed
621
def qdump__QHash(d, value):
hjk's avatar
hjk committed
622 623

    def hashDataFirstNode(value):
hjk's avatar
hjk committed
624 625 626
        val = value.cast(hashDataType)
        bucket = val["buckets"]
        e = val.cast(hashNodeType)
hjk's avatar
hjk committed
627
        for n in xrange(int(val["numBuckets"]) - 1, -1, -1):
hjk's avatar
hjk committed
628 629 630 631 632 633 634 635 636 637 638 639 640
            n = n - 1
            if n < 0:
                break
            if bucket.dereference() != e:
                return bucket.dereference()
            bucket = bucket + 1
        return e;

    def hashDataNextNode(node):
        next = node["next"]
        if next["next"]:
            return next
        d = node.cast(hashDataType.pointer()).dereference()
hjk's avatar
hjk committed
641 642
        numBuckets = int(d["numBuckets"])
        start = (int(node["h"]) % numBuckets) + 1
hjk's avatar
hjk committed
643
        bucket = d["buckets"] + start
644
        for n in xrange(numBuckets - start):
hjk's avatar
hjk committed
645 646 647 648 649
            if bucket.dereference() != next:
                return bucket.dereference()
            bucket += 1
        return node

650 651
    keyType = d.templateArgument(value.type, 0)
    valueType = d.templateArgument(value.type, 1)
hjk's avatar
hjk committed
652

hjk's avatar
hjk committed
653 654
    d_ptr = value["d"]
    e_ptr = value["e"]
hjk's avatar
hjk committed
655
    size = int(d_ptr["size"])
hjk's avatar
hjk committed
656 657 658 659

    hashDataType = d_ptr.type
    hashNodeType = e_ptr.type

660
    check(0 <= size and size <= 100 * 1000 * 1000)
661
    checkRef(d_ptr["ref"])
hjk's avatar
hjk committed
662

663 664
    d.putItemCount(size)
    d.putNumChild(size)
hjk's avatar
hjk committed
665
    if d.isExpanded():
hjk's avatar
hjk committed
666
        isCompact = d.isMapCompact(keyType, valueType)
hjk's avatar
hjk committed
667
        node = hashDataFirstNode(value)
hjk's avatar
hjk committed
668
        innerType = e_ptr.dereference().type
669
        childType = innerType
670
        if isCompact:
671
            childType = valueType
hjk's avatar
hjk committed
672
        with Children(d, size, maxNumChild=1000, childType=childType):
673 674
            for i in d.childRange():
                it = node.dereference().cast(innerType)
hjk's avatar
hjk committed
675
                with SubItem(d, i):
676 677 678
                    if isCompact:
                        d.putMapName(it["key"])
                        d.putItem(it["value"])
679 680
                        d.putType(valueType)
                    else:
hjk's avatar
hjk committed
681
                        d.putItem(it)
682
                node = hashDataNextNode(node)
hjk's avatar
hjk committed
683 684


hjk's avatar
hjk committed
685
def qdump__QHashNode(d, value):
686 687
    keyType = d.templateArgument(value.type, 0)
    valueType = d.templateArgument(value.type, 1)
hjk's avatar
hjk committed
688 689
    key = value["key"]
    val = value["value"]
hjk's avatar
hjk committed
690

691 692 693 694
    #if isSimpleType(keyType) and isSimpleType(valueType):
    #    d.putName(key)
    #    d.putValue(val)
    #else:
695
    d.putEmptyValue()
hjk's avatar
hjk committed
696

697
    d.putNumChild(2)
hjk's avatar
hjk committed
698
    if d.isExpanded():
699
        with Children(d):
hjk's avatar
hjk committed
700 701
            d.putSubItem("key", key)
            d.putSubItem("value", val)
hjk's avatar
hjk committed
702 703


704 705
def qHashIteratorHelper(d, value):
    typeName = str(value.type)
706
    hashType = d.lookupType(typeName[0:typeName.rfind("::")])
707 708
    keyType = d.templateArgument(hashType, 0)
    valueType = d.templateArgument(hashType, 1)
709
    d.putNumChild(1)
710
    d.putEmptyValue()
711 712 713
    if d.isExpanded():
        with Children(d):
            typeName = "%sQHash<%s,%s>::Node" % (d.ns, keyType, valueType)
714
            node = value["i"].cast(d.lookupType(typeName).pointer())
715 716 717 718 719 720 721 722 723 724
            d.putSubItem("key", node["key"])
            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
725
def qdump__QHostAddress(d, value):
726
    privAddress = d.dereferenceValue(value)
727 728
    isQt5 = d.qtVersion() >= 0x050000
    ipStringAddress = privAddress + (0 if isQt5 else 24)
729 730
    # value.d.d->ipString
    ipString = qEncodeString(d, d.dereference(ipStringAddress))
731 732
    if len(ipString) > 0:
        d.putValue(ipString, Hex4EncodedLittleEndian)
hjk's avatar
hjk committed
733
    else:
734
        # value.d.d->a
735
        a = d.extractInt(privAddress + (2 * d.ptrSize() if isQt5 else 0))
736 737 738 739 740
        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));
hjk's avatar
hjk committed
741
    d.putNumChild(1)
hjk's avatar
hjk committed
742
    if d.isExpanded():
hjk's avatar
hjk committed
743
        with Children(d):
744
           d.putFields(value["d"]["d"].dereference())
hjk's avatar
hjk committed
745

hjk's avatar
hjk committed
746
def qdump__QList(d, value):
747 748 749 750 751
    dptr = childAt(value, 0)["d"]
    private = dptr.dereference()
    begin = int(private["begin"])
    end = int(private["end"])
    array = private["array"]
hjk's avatar
hjk committed
752
    check(begin >= 0 and end >= 0 and end <= 1000 * 1000 * 1000)
753 754
    size = end - begin
    check(size >= 0)
755
    checkRef(private["ref"])
hjk's avatar
hjk committed
756

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

759 760
    d.putItemCount(size)
    d.putNumChild(size)
hjk's avatar
hjk committed
761
    if d.isExpanded():
hjk's avatar
hjk committed
762 763 764 765 766 767
        innerSize = innerType.sizeof
        # 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:
768 769 770 771 772
        stepSize = dptr.type.sizeof
        isInternal = innerSize <= stepSize and d.isMovableType(innerType)
        addr = d.addressOf(array) + begin * stepSize
        if isInternal:
            if innerSize == stepSize:
773
                p = d.createPointerValue(addr, innerType)
774 775 776 777
                d.putArrayData(innerType, p, size)
            else:
                with Children(d, size, childType=innerType):
                    for i in d.childRange():
778 779
                        p = d.createValue(addr + i * stepSize, innerType)
                        d.putSubItem(i, p)
780
        else:
781
            p = d.createPointerValue(addr, innerType.pointer())
782 783 784 785 786
            # 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
787

hjk's avatar
hjk committed
788 789
def qform__QImage():
    return "Normal,Displayed"
hjk's avatar
hjk committed
790

hjk's avatar
hjk committed
791
def qdump__QImage(d, value):
792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812
    # This relies on current QImage layout:
    # QImageData:
    # - QAtomicInt ref
    # - int width, height, depth, nbytes
    # - qreal devicePixelRatio  (+20)  # Assume qreal == double, Qt 5 only
    # - QVector<QRgb> colortable (+20 + gap)
    # - uchar *data (+20 + gap + ptr)
    # [- uchar **jumptable jumptable with Qt 3 suppor]
    # - enum format (+20 + gap + 2 * ptr)

    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)
    pixelRatioSize = 8 if isQt5 else 0
    jumpTableSize = ptrSize if not isQt5 else 0  # FIXME: Assumes Qt3 Support
    bits = d.dereference(base + 20 + pixelRatioSize + ptrSize)
    iformat = d.extractInt(base + 20 + pixelRatioSize + jumpTableSize + 2 * ptrSize)
813
    d.putValue("(%dx%d)" % (width, height))
814
    d.putNumChild(1)
hjk's avatar
hjk committed
815
    if d.isExpanded():
816
        with Children(d):
817 818 819 820
            d.putIntItem("width", width)
            d.putIntItem("height", height)
            d.putIntItem("nbytes", nbytes)
            d.putIntItem("format", iformat)
hjk's avatar
hjk committed
821
            with SubItem(d, "data"):
822
                d.putValue("0x%x" % bits)
823
                d.putNumChild(0)
824 825
                d.putType("void *")

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


hjk's avatar
hjk committed
845 846 847
def qdump__QLinkedList(d, value):
    d_ptr = value["d"]
    e_ptr = value["e"]
hjk's avatar
hjk committed
848
    n = int(d_ptr["size"])
hjk's avatar
hjk committed
849
    check(0 <= n and n <= 100*1000*1000)
850
    checkRef(d_ptr["ref"])
hjk's avatar
hjk committed
851
    d.putItemCount(n)
852
    d.putNumChild(n)
hjk's avatar
hjk committed
853
    if d.isExpanded():
854
        innerType = d.templateArgument(value.type, 0)
hjk's avatar
hjk committed
855
        with Children(d, n, maxNumChild=1000, childType=innerType):
856 857
            p = e_ptr["n"]
            for i in d.childRange():
hjk's avatar
hjk committed
858
                d.putSubItem(i, p["t"])
859
                p = p["n"]
hjk's avatar
hjk committed
860

861
qqLocalesCount = None
hjk's avatar
hjk committed
862

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


hjk's avatar
hjk committed
905
def qdump__QMapNode(d, value):
906
    d.putEmptyValue()
907
    d.putNumChild(2)
hjk's avatar
hjk committed
908 909 910 911 912 913
    if d.isExpanded():
        with Children(d):
            d.putSubItem("key", value["key"])
            d.putSubItem("value", value["value"])


914
def qdumpHelper__Qt4_QMap(d, value, forceLong):
hjk's avatar
hjk committed
915 916
    d_ptr = value["d"].dereference()
    e_ptr = value["e"].dereference()
hjk's avatar
hjk committed
917
    n = int(d_ptr["size"])
hjk's avatar
hjk committed
918
    check(0 <= n and n <= 100*1000*1000)
919
    checkRef(d_ptr["ref"])