diff --git a/share/qtcreator/gdbmacros/dumper.py b/share/qtcreator/gdbmacros/dumper.py new file mode 100644 index 0000000000000000000000000000000000000000..1de980315742830cc6af1142e97c4c8405d3b7f5 --- /dev/null +++ b/share/qtcreator/gdbmacros/dumper.py @@ -0,0 +1,603 @@ + +#Note: Keep name-type-value-numchild-extra order + +#return + +import sys +import traceback +import gdb +#import base64 +import types +import curses.ascii + +verbosity = 0 +verbosity = 1 + +def isSimpleType(typeobj): + type = str(typeobj) + return type == "bool" \ + or type == "char" \ + or type == "double" \ + or type == "float" \ + or type == "int" \ + or type == "long" or type.startswith("long ") \ + or type == "short" or type.startswith("short ") \ + or type == "signed" or type.startswith("signed ") \ + or type == "unsigned" or type.startswith("unsigned ") + +def isStringType(d, typeobj): + type = str(typeobj) + return type == d.ns + "QString" \ + or type == d.ns + "QByteArray" \ + or type == "std::string" \ + or type == "std::wstring" \ + or type == "wstring" + +def warn(message): + if verbosity > 0: + print "XXX: %s " % message.encode("latin1") + pass + +def check(exp): + if not exp: + raise RuntimeError("Check failed") + +#def couldBePointer(p, align): +# type = gdb.lookup_type("unsigned int") +# ptr = gdb.Value(p).cast(type) +# d = int(str(ptr)) +# warn("CHECKING : %s %d " % (p, ((d & 3) == 0 and (d > 1000 or d == 0)))) +# return (d & (align - 1)) and (d > 1000 or d == 0) + + +def checkAccess(p, align = 1): + return p.dereference() + +def checkContents(p, expected, align = 1): + if int(p.dereference()) != expected: + raise RuntimeError("Contents check failed") + +def checkPointer(p, align = 1): + if not isNull(p): + p.dereference() + + +def isNull(p): + s = str(p) + return s == "0x0" or s.startswith("0x0 ") + +movableTypes = set([ + "QBrush", "QBitArray", "QByteArray", + "QCustomTypeInfo", "QChar", + "QDate", "QDateTime", + "QFileInfo", "QFixed", "QFixedPoint", "QFixedSize", + "QHashDummyValue", + "QIcon", "QImage", + "QLine", "QLineF", "QLatin1Char", "QLocal", + "QMatrix", "QModelIndex", + "QPoint", "QPointF", "QPen", "QPersistentModelIndex", + "QResourceRoot", "QRect", "QRectF", "QRegExp", + "QSize", "QSizeF", "QString", + "QTime", "QTextBlock", + "QUrl", + "QVariant", + "QXmlStreamAttribute", "QXmlStreamNamespaceDeclaration", + "QXmlStreamNotationDeclaration", "QXmlStreamEntityDeclaration"]) + + +def stripClassTag(type): + if type.startswith("class "): + return type[6:] + return type + +def checkPointerRange(p, n): + for i in xrange(0, n): + checkPointer(p) + ++p + +def call(value, func): + #warn("CALL: %s -> %s" % (value, func)) + type = stripClassTag(str(value.type)) + if type.find(':') >= 0: + type = "'" + type + "'" + exp = "((%s*)%s)->%s" % (type, value.address, func) + #warn("CALL: %s" % exp) + result = gdb.parse_and_eval(exp) + #warn(" -> %s" % result) + return result + + +####################################################################### +# +# Item +# +####################################################################### + +class Item: + def __init__(self, value, parentiname, iname, name): + self.value = value + self.iname = parentiname if iname is None else "%s.%s" % (parentiname, iname) + self.name = name + + +####################################################################### +# +# FrameCommand +# +####################################################################### + +class FrameCommand(gdb.Command): + """Do fancy stuff. Usage bb --verbose expandedINames""" + + def __init__(self): + super(FrameCommand, self).__init__("bb", gdb.COMMAND_OBSCURE) + + def invoke(self, arg, from_tty): + print('locals={iname="local",name="Locals",value=" ",type=" ",' + + 'children=[%s]}' % self.doit(arg).encode("latin1")) + + def doit(self, arg): + args = arg.split(' ') + #warn("ARG: %s" % arg) + #warn("ARGS: %s" % args) + useFancy = int(args[0]) + passExceptions = int(args[1]) + expandedINames = set() + if len(args) > 2: + expandedINames = set(args[2].split(',')) + watchers = set() + if len(args) > 3: + watchers = set(args[3].split(',')) + #warn("EXPANDED INAMES: %s" % expandedINames) + #warn("WATCHERS: %s" % watchers) + module = sys.modules[__name__] + self.dumpers = {} + + if useFancy: + for key, value in module.__dict__.items(): + #if callable(value): + if key.startswith("qqDump"): + self.dumpers[key[6:]] = value + self.dumpers["std__deque"] = qqDumpStdDeque + self.dumpers["std__list"] = qqDumpStdList + self.dumpers["std__map"] = qqDumpStdMap + self.dumpers["std__set"] = qqDumpStdSet + self.dumpers["std__vector"] = qqDumpStdVector + self.dumpers["string"] = qqDumpStdString + self.dumpers["std__string"] = qqDumpStdString + self.dumpers["std__wstring"] = qqDumpStdString + self.dumpers["std__basic_string"] = qqDumpStdString + self.dumpers["wstring"] = qqDumpStdString + # Hack to work around gdb bug #10898 + #self.dumpers["QString::string"] = qqDumpStdString + #warn("DUMPERS: %s " % self.dumpers) + + try: + frame = gdb.selected_frame() + except RuntimeError as ex: + return "" + + d = Dumper() + d.dumpers = self.dumpers + d.passExceptions = passExceptions + block = frame.block() + + # initialize namespace + type = str(gdb.parse_and_eval("&QString::null").type.target().unqualified()) + d.ns = type[0:len(type) - len("QString::Null")] + #warn(" NAMESPACE IS: '%s'" % d.ns) + #warn("FRAME %s: " % frame) + + while True: + if block is None: + warn("UNEXPECTED 'None' BLOCK") + break + for symbol in block: + name = symbol.print_name + + if name == "__in_chrg": + continue + + # "NotImplementedError: Symbol type not yet supported in + # Python scripts." + #warn("SYMBOL %s: " % symbol.value) + #warn("SYMBOL %s (%s): " % (symbol, name)) + item = Item(0, "local", name, name) + try: + item.value = frame.read_var(name) # this is a gdb value + except RuntimeError: + # happens for void foo() { std::string s; std::wstring w; } + #warn(" FRAME READ VAR ERROR: %s (%s): " % (symbol, name)) + continue + #warn("ITEM %s: " % item.value) + + d.expandedINames = expandedINames + d.useFancy = useFancy + d.beginHash() + d.putField("iname", item.iname) + d.put(",") + + d.safePutItemHelper(item) + + d.endHash() + + # The outermost block in a function has the function member + # FIXME: check whether this is guaranteed. + if not block.function is None: + break + + block = block.superblock + + d.pushOutput() + return d.safeoutput + +FrameCommand() + + + +####################################################################### +# +# The Dumper Class +# +####################################################################### + +class Dumper: + def __init__(self): + self.output = "" + self.safeoutput = "" + self.childTypes = [""] + self.childNumChilds = [-1] + + def put(self, value): + self.output += value + + def putCommaIfNeeded(self): + c = self.output[-1:] + if c == '}' or c == '"' or c == ']' or c == '\n': + self.put(',') + #warn("C:'%s' COND:'%d' OUT:'%s'" % + # (c, c == '}' or c == '"' or c == ']' or c == '\n', self.output)) + + def putField(self, name, value): + self.putCommaIfNeeded() + self.put('%s="%s"' % (name, value)) + + def beginHash(self): + self.putCommaIfNeeded() + self.put('{') + + def endHash(self): + self.put('}') + + def beginItem(self, name): + self.putCommaIfNeeded() + self.put(name) + self.put('="') + + def endItem(self): + self.put('"') + + def beginChildren(self, type = None, children = None): + childType = "" + childNumChild = -1 + if not type is None: + childType = stripClassTag(str(type)) + self.putField("childtype", childType) + if isSimpleType(type) or isStringType(self, type): + self.putField("childnumchild", "0") + childNumChild = 0 + elif type.code == gdb.TYPE_CODE_PTR: + self.putField("childnumchild", "1") + childNumChild = 1 + if not children is None: + self.putField("childnumchild", children) + childNumChild = children + self.childTypes.append(childType) + self.childNumChilds.append(childNumChild) + #warn("BEGIN: %s" % self.childTypes) + self.putCommaIfNeeded() + self.put("children=[") + + def endChildren(self): + #warn("END: %s" % self.childTypes) + self.childTypes.pop() + self.childNumChilds.pop() + self.put(']') + + # convenience + def putItemCount(self, count): + self.putCommaIfNeeded() + self.put('value="<%s items>"' % count) + + def putEllipsis(self): + self.putCommaIfNeeded() + self.put('{name="<incomplete>",value="",type="",numchild="0"}') + + def putType(self, type): + #warn("TYPES: '%s' '%s'" % (type, self.childTypes)) + #warn(" EQUAL 2: %s " % (str(type) == self.childTypes[-1])) + type = stripClassTag(str(type)) + if len(type) > 0 and type != self.childTypes[-1]: + self.putField("type", type) + #self.putField("type", str(type.unqualified())) + + def putNumChild(self, numchild): + #warn("NUM CHILD: '%s' '%s'" % (numchild, self.childNumChilds[-1])) + if int(numchild) != int(self.childNumChilds[-1]): + self.putField("numchild", numchild) + + def isExpanded(self, item): + #warn("IS EXPANDED: %s in %s" % (item.iname, self.expandedINames)) + if item.iname is None: + raise "Illegal iname 'None'" + if item.iname.startswith("None"): + raise "Illegal iname '%s'" % item.iname + #warn(" --> %s" % (item.iname in self.expandedINames)) + return item.iname in self.expandedINames + + def isExpandedIName(self, iname): + return iname in self.expandedINames + + def unputField(self, name): + pos = self.output.rfind(",") + if self.output[pos + 1:].startswith(name): + self.output = self.output[0:pos] + + def stripNamespaceFromType(self, typeobj): + # FIXME: pass ns from plugin + type = stripClassTag(str(typeobj)) + if len(self.ns) > 0 and type.startswith(self.ns): + type = type[len(self.ns):] + pos = type.find("<") + if pos != -1: + type = type[0:pos] + return type + + def isMovableType(self, type): + if type.code == gdb.TYPE_CODE_PTR: + return True + if isSimpleType(type): + return True + return self.stripNamespaceFromType(type) in movableTypes + + def putIntItem(self, name, value): + self.beginHash() + self.putField("name", name) + self.putField("value", value) + self.putType("int") + self.putNumChild(0) + self.endHash() + + def putBoolItem(self, name, value): + self.beginHash() + self.putField("name", name) + self.putField("value", value) + self.putType("bool") + self.putNumChild(0) + self.endHash() + + def pushOutput(self): + #warn("PUSH OUTPUT: %s " % self.output) + self.safeoutput += self.output + self.output = "" + + def dumpInnerValueHelper(self, item, field = "value"): + if isSimpleType(item.value.type): + self.putItemHelper(item, field) + + def safePutItemHelper(self, item): + self.pushOutput() + # This is only used at the top level to ensure continuation + # after failures due to uninitialized or corrupted data. + if self.passExceptions: + # for debugging reasons propagate errors. + self.putItemHelper(item) + + else: + try: + self.putItemHelper(item) + + except RuntimeError as ex: + self.output = "" + # FIXME: Only catch debugger related exceptions + #exType, exValue, exTraceback = sys.exc_info() + #tb = traceback.format_exception(exType, exValue, exTraceback) + warn("Exception: %s" % ex.message) + # DeprecationWarning: BaseException.message + # has been deprecated + #warn("Exception.") + #for line in tb: + # warn("%s" % line) + self.putField("name", item.name) + self.putField("value", "<invalid>") + self.putField("type", str(item.value.type)) + self.putField("numchild", "0") + #if self.isExpanded(item): + self.beginChildren() + self.endChildren() + self.pushOutput() + + def putItem(self, item): + self.beginHash() + self.putItemHelper(item) + self.endHash() + + def putItemOrPointer(self, item): + self.beginHash() + self.putItemOrPointerHelper(item) + self.endHash() + + def putCallItem(self, name, item, func): + result = call(item.value, func) + self.putItem(Item(result, item.iname, name, name)) + + def putItemOrPointerHelper(self, item): + if item.value.type.code == gdb.TYPE_CODE_PTR \ + and str(item.value.type.unqualified) != "char": + if not isNull(item.value): + self.putItemOrPointerHelper( + Item(item.value.dereference(), item.iname, None, None)) + else: + self.putField("value", "(null)") + self.putField("numchild", "0") + else: + self.putItemHelper(item) + + + def putItemHelper(self, item, field = "value"): + name = getattr(item, "name", None) + if not name is None: + self.putField("name", name) + + self.putType(item.value.type) + # FIXME: Gui shows references stripped? + #warn("REAL INAME: %s " % item.iname) + #warn("REAL TYPE: %s " % item.value.type) + #warn("REAL VALUE: %s " % item.value) + + value = item.value + type = value.type + + if type.code == gdb.TYPE_CODE_REF: + type = type.target() + value = value.cast(type) + + if type.code == gdb.TYPE_CODE_TYPEDEF: + type = type.target() + + strippedType = self.stripNamespaceFromType( + type.strip_typedefs().unqualified()).replace("::", "__") + + #warn(" STRIPPED: %s" % strippedType) + #warn(" DUMPERS: %s" % self.dumpers) + #warn(" DUMPERS: %s" % (strippedType in self.dumpers)) + + if isSimpleType(type): + self.putField(field, value) + if field == "value": + self.putNumChild(0) + + elif strippedType in self.dumpers: + self.dumpers[strippedType](self, item) + + elif type.code == gdb.TYPE_CODE_ENUM: + #warn("GENERIC ENUM: %s" % value) + self.putField(field, value) + self.putNumChild(0) + + + elif type.code == gdb.TYPE_CODE_PTR: + isHandled = False + #warn("GENERIC POINTER: %s" % value) + if isNull(value): + self.putField(field, "0x0") + self.putNumChild(0) + isHandled = True + + target = str(type.target().unqualified()) + #warn("TARGET: %s" % target) + if target == "char" and not isHandled: + # Display values up to given length directly + firstNul = -1 + p = value + for i in xrange(0, 10): + if p.dereference() == 0: + # Found terminating NUL + self.putField("%sencoded" % field, "6") + self.put(',%s="' % field) + p = value + for j in xrange(0, i): + self.put('%02x' % int(p.dereference())) + p += 1 + self.put('"') + self.putNumChild(0) + isHandled = True + break + p += 1 + + if not isHandled: + # Generic pointer type. + self.putField(field, str(value.address)) + self.putNumChild(1) + #warn("GENERIC POINTER: %s" % value) + if self.isExpanded(item): + self.beginChildren() + child = Item(value.dereference(), item.iname, "*", "*" + name) + self.beginHash() + self.putField("iname", child.iname) + #name = getattr(item, "name", None) + #if not name is None: + # child.name = "*%s" % name + # self.putField("name", child.name) + #self.putType(child.value.type) + self.putItemHelper(child) + self.endHash() + self.endChildren() + + else: + #warn("COMMON TYPE: %s " % value.type) + #warn("INAME: %s " % item.iname) + #warn("INAMES: %s " % self.expandedINames) + #warn("EXPANDED: %self " % (item.iname in self.expandedINames)) + + # insufficient, see http://sourceware.org/bugzilla/show_bug.cgi?id=10953 + #fields = value.type.fields() + fields = value.type.strip_typedefs().fields() + + self.putField("value", "{...}") + + if False: + numfields = 0 + for field in fields: + bitpos = getattr(field, "bitpos", None) + if not bitpos is None: + ++numfields + else: + numfields = len(fields) + self.putNumChild(numfields) + + if self.isExpanded(item): + innerType = None + if len(fields) == 1 and fields[0].name is None: + innerType = value.type.target() + self.beginChildren(innerType) + + for field in fields: + #warn("FIELD: %s" % field) + #warn(" BITSIZE: %s" % field.bitsize) + #warn(" ARTIFICIAL: %s" % field.artificial) + bitpos = getattr(field, "bitpos", None) + if bitpos is None: # FIXME: Is check correct? + continue # A static class member(?). + + if field.name is None: + innerType = value.type.target() + p = value.cast(innerType.pointer()) + for i in xrange(0, value.type.sizeof / innerType.sizeof): + self.putItem(Item(p.dereference(), item.iname, i, None)) + p = p + 1 + continue + + # ignore vtable pointers for virtual inheritance + if field.name.startswith("_vptr."): + continue + + child = Item(None, item.iname, field.name, field.name) + #warn("FIELD NAME: %s" % field.name) + #warn("FIELD TYPE: %s" % field.type) + if field.name == stripClassTag(str(field.type)): + # Field is base type. + child.value = value.cast(field.type) + else: + # Data member. + child.value = value[field.name] + if not child.name: + child.name = "<anon>" + self.beginHash() + #d.putField("iname", child.iname) + #d.putField("name", child.name) + #d.putType(child.value.type) + self.putItemHelper(child) + self.endHash() + self.endChildren() + diff --git a/share/qtcreator/gdbmacros/gdbmacros.py b/share/qtcreator/gdbmacros/gdbmacros.py new file mode 100644 index 0000000000000000000000000000000000000000..23a8b1b83233e8c2fa05799b6e607379dba65c9b --- /dev/null +++ b/share/qtcreator/gdbmacros/gdbmacros.py @@ -0,0 +1,2004 @@ + +#Note: Keep name-type-value-numchild-extra order + +####################################################################### +# +# Dumper Implementations +# +####################################################################### + +def qqDumpQByteArray(d, item): + #struct Data + # QBasicAtomicInt ref; + # int alloc, size; + # char *data; + # char array[1]; + d_ptr = item.value['d'].dereference() + data = d_ptr['data'] + size = d_ptr['size'] + alloc = d_ptr['alloc'] + check(0 <= size and size <= alloc and alloc <= 100*1000*1000) + check(d_ptr["ref"]["_q_value"] > 0) + if size > 0: + checkAccess(data, 4) + checkAccess(data + size) == 0 + + innerType = gdb.lookup_type("char") + p = gdb.Value(data.cast(innerType.pointer())) + s = "" + for i in xrange(0, size): + s += "%02x" % int(p.dereference()) + p += 1 + d.putField("valueencoded", "6") + d.putField("value", s) + + n = size if size < 1000 else 1000 + d.putNumChild(n) + + if d.isExpanded(item): + d.beginChildren(innerType if n > 0 else None) + p = gdb.Value(data.cast(innerType.pointer())) + for i in xrange(0, n): + d.putItem(Item(p.dereference(), item.iname, i, None)) + p += 1 + if n < size: + d.putEllipsis() + d.endChildren() + + +def qqDumpQChar(d, item): + ucs = int(item.value["ucs"]) + c = ucs if curses.ascii.isprint(ucs) else '?' + d.putField("value", "'%c' (%d)" % (c, ucs)) + d.putNumChild(0) + + +def qqDumpQAbstractItem(d, item): + r = item.value["r"] + c = item.value["c"] + p = item.value["p"] + m = item.value["m"] + rowCount = call(m, "rowCount(mi)") + if rowCount < 0: + return + columnCount = call(m, "columnCount(mi)") + if columnCount < 0: + return + value = call(m, "data(mi, Qt::DisplayRole).toString()") + d.putField("valueencoded", "7") + d.putField("value", encodeString(value)) + d.putField("numchild", rowCount * columnCount) + if d.isExpanded(item): + innerType = gdb.lookup_type(d.ns + "QAbstractItem") + d.beginChildren() + for row in xrange(0, rowCount): + for column in xrange(0, columnCount): + child = call(m, "index(row, column, mi)") + d.putField("name", "[%s,%s]" % (row, column)) + rr = call(m, "rowCount(child)") + cc = call(m, "columnCount(child)") + d.putField("numchild", rr * cc) + d.putField("valueencoded", "6") + d.putField("value", + call(m, "data(child, Qt::DisplayRole).toString())")) + d.endHash() + #d.beginHash() + #d.putField("name", "DisplayRole") + #d.putField("numchild", 0) + #d.putField("value", m->data(mi, Qt::DisplayRole).toString()) + #d.putField("valueencoded", 2) + #d.putField("type", ns + "QString") + #d.endHash() + d.endChildren() + + +def qqDumpQAbstractItemModel(d, item): + rowCount = call(item.value, "rowCount()") + if rowCount < 0: + return + columnCount = call(item.valuem, "columnCount()") + if columnCount < 0: + return + + d.putField("value", "(%s,%s)" % (rowCount, columnCount)) + d.putField("numchild", "1") + if d.isExpanded(item): + d.beginChildren() + d.beginHash() + d.putField("numchild", "1") + d.putField("name", d.ns + "QObject") + d.putField("valueencoded", "2") + d.putField("value", call(item.value, "objectName()")) + d.putField("type", d.ns + "QObject") + d.putField("displayedtype", call(item, "m.metaObject()->className()")) + d.endHash() + for row in xrange(0, rowCount): + for column in xrange(0, columnCount): + mi = call(m, "index(%s,%s)" % (row, column)) + d.beginHash() + d.putField("name", "[%s,%s]" % (row, column)) + d.putField("valueencoded", "6") + d.putField("value", "m.data(mi, Qt::DisplayRole).toString()") + #d.putField("numchild", (m.hasChildren(mi) ? "1" : "0")) + d.putField("numchild", "1") #m.rowCount(mi) * m.columnCount(mi)) + d.putField("type", d.ns + "QAbstractItem") + d.endHash() + d.endChildren() + + +def qqDumpQDateTime(d, item): + date = call(item.value, "toString(%sQt::TextDate)" % d.ns) + d.putField("valueencoded", "7") + d.putField("value", encodeString(date)) + d.putField("numchild", "3") + if d.isExpanded(item): + d.beginChildren() + d.putCallItem("isNull", item, "isNull()") + d.putCallItem("toTime_t", item, "toTime_t()") + d.putCallItem("toString", + item, "toString(%sQt::TextDate)" % d.ns) + d.putCallItem("(ISO)", + item, "toString(%sQt::ISODate)" % d.ns) + d.putCallItem("(SystemLocale)", + item, "toString(%sQt::SystemLocaleDate)" % d.ns) + d.putCallItem("(Locale)", + item, "toString(%sQt::LocaleDate)" % d.ns) + d.putCallItem("toUTC", + item, "toTimeSpec(%sQt::UTC)" % d.ns) + d.putCallItem("toLocalTime", + item, "toTimeSpec(%sQt::LocalTime)" % d.ns) + d.endChildren() + + +def qqDumpQDir(d, item): + path = call(item.value, "path()") + d.putField("valueencoded", "7") + d.putField("value", encodeString(path)) + d.putField("numchild", "2") + if d.isExpanded(item): + d.beginChildren() + d.putCallItem("absolutePath", item, "absolutePath()") + d.putCallItem("canonicalPath", item, "canonicalPath()") + d.endChildren() + + +def qqDumpQFile(d, item): + fileName = call(item.value, "fileName()") + d.putField("valueencoded", "7") + d.putField("value", encodeString(fileName)) + d.putField("numchild", "2") + if d.isExpanded(item): + d.beginChildren() + d.putCallItem("fileName", item, "fileName()") + d.putCallItem("exists", item, "exists()") + d.endChildren() + + +def qqDumpQFileInfo(d, item): + filePath = call(item.value, "filePath()") + d.putField("valueencoded", "7") + d.putField("value", encodeString(filePath)) + d.putField("numchild", "3") + if d.isExpanded(item): + d.beginChildren(gdb.lookup_type(d.ns + "QString")) + d.putCallItem("absolutePath", item, "absolutePath()") + d.putCallItem("absoluteFilePath", item, "absoluteFilePath()") + d.putCallItem("canonicalPath", item, "canonicalPath()") + d.putCallItem("canonicalFilePath", item, "canonicalFilePath()") + d.putCallItem("completeBaseName", item, "completeBaseName()") + d.putCallItem("completeSuffix", item, "completeSuffix()") + d.putCallItem("baseName", item, "baseName()") + if False: + #ifdef Q_OS_MACX + d.putCallItem("isBundle", item, "isBundle()") + d.putCallItem("bundleName", item, "bundleName()") + d.putCallItem("fileName", item, "fileName()") + d.putCallItem("filePath", item, "filePath()") + # Crashes gdb (archer-tromey-python, at dad6b53fe) + #d.putCallItem("group", item, "group()") + #d.putCallItem("owner", item, "owner()") + d.putCallItem("path", item, "path()") + + d.putCallItem("groupid", item, "groupId()") + d.putCallItem("ownerid", item, "ownerId()") + + #QFile::Permissions permissions () const + perms = call(item.value, "permissions()") + d.beginHash() + d.putField("name", "permissions") + d.putField("value", " ") + d.putField("type", d.ns + "QFile::Permissions") + d.putField("numchild", 10) + if d.isExpandedIName(item.iname + ".permissions"): + d.beginChildren() + 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) + d.endChildren() + d.endHash() + + #QDir absoluteDir () const + #QDir dir () const + d.putCallItem("caching", item, "caching()") + d.putCallItem("exists", item, "exists()") + d.putCallItem("isAbsolute", item, "isAbsolute()") + d.putCallItem("isDir", item, "isDir()") + d.putCallItem("isExecutable", item, "isExecutable()") + d.putCallItem("isFile", item, "isFile()") + d.putCallItem("isHidden", item, "isHidden()") + d.putCallItem("isReadable", item, "isReadable()") + d.putCallItem("isRelative", item, "isRelative()") + d.putCallItem("isRoot", item, "isRoot()") + d.putCallItem("isSymLink", item, "isSymLink()") + d.putCallItem("isWritable", item, "isWritable()") + d.putCallItem("created", item, "created()") + d.putCallItem("lastModified", item, "lastModified()") + d.putCallItem("lastRead", item, "lastRead()") + d.endChildren() + + +def qqDumpQFlags(d, item): + #warn("QFLAGS: %s" % item.value) + i = item.value["i"] + enumType = item.value.type.template_argument(0) + #warn("QFLAGS: %s" % item.value["i"].cast(enumType)) + d.putField("value", "%s (%s)" % (i.cast(enumType), i)) + d.putNumChild(0) + + +def qqDumpQHash(d, item): + + def hashDataFirstNode(value): + value = value.cast(hashDataType) + bucket = value["buckets"] + e = value.cast(hashNodeType) + for n in xrange(value["numBuckets"] - 1, -1, -1): + 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() + numBuckets = d["numBuckets"] + start = (node["h"] % numBuckets) + 1 + bucket = d["buckets"] + start + for n in xrange(0, numBuckets - start): + if bucket.dereference() != next: + return bucket.dereference() + bucket += 1 + return node + + keyType = item.value.type.template_argument(0) + valueType = item.value.type.template_argument(1) + + d_ptr = item.value["d"] + e_ptr = item.value["e"] + n = d_ptr["size"] + + hashDataType = d_ptr.type + hashNodeType = e_ptr.type + + check(0 <= n and n <= 100 * 1000 * 1000) + check(d_ptr["ref"]["_q_value"] > 0) + + d.putItemCount(n) + d.putField("numchild", n) + if d.isExpanded(item): + if n > 1000: + n = 1000 + + isSimpleKey = isSimpleType(keyType) + isSimpleValue = isSimpleType(valueType) + node = hashDataFirstNode(item.value) + + innerType = e_ptr.dereference().type + inner = valueType if isSimpleKey and isSimpleValue else innerType + d.beginChildren(inner if n > 0 else None) + for i in xrange(0, n): + it = node.dereference().cast(innerType) + d.beginHash() + key = it["key"] + value = it["value"] + if isSimpleKey and isSimpleValue: + d.putField("name", key) + d.putItemHelper(Item(value, item.iname, i, None)) + d.putType(valueType) + else: + d.putItemHelper(Item(it, item.iname, i, None)) + d.endHash() + node = hashDataNextNode(node) + d.endChildren() + + +def qqDumpQHashNode(d, item): + keyType = item.value.type.template_argument(0) + valueType = item.value.type.template_argument(1) + key = item.value["key"] + value = item.value["value"] + + if isSimpleType(valueType): + d.dumpInnerValueHelper(Item(value)) + else: + d.putField("value", " ") + + d.putField("numchild", 2) + if d.isExpanded(item): + d.beginChildren() + d.beginHash() + d.putField("name", "key") + d.putItemHelper(Item(key, None, None, None)) + d.endHash() + d.beginHash() + d.putField("name", "value") + d.putItemHelper(Item(value, None, None, None)) + d.endHash() + d.endChildren() + + +def qqDumpQList(d, item): + d_ptr = item.value["d"] + begin = d_ptr["begin"] + end = d_ptr["end"] + array = d_ptr["array"] + check(begin >= 0 and end >= 0 and end <= 1000 * 1000 * 1000) + n = end - begin + check(n >= 0) + #if n > 0: + # checkAccess(&list.front()) + # checkAccess(&list.back()) + + check(d_ptr["ref"]["_q_value"] > 0) + + # Additional checks on pointer arrays. + innerType = item.value.type.template_argument(0) + innerTypeIsPointer = innerType.code == gdb.TYPE_CODE_PTR \ + and str(innerType.target().unqualified()) != "char" + if innerTypeIsPointer: + p = gdb.Value(array).cast(innerType.pointer()) + begin + checkPointerRange(p, n if n < 100 else 100) + + d.putItemCount(n) + d.putField("numchild", n) + if d.isExpanded(item): + # about 0.5s / 1000 items + if n > 2000: + n = 2000 + + 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: + isInternal = innerSize <= d_ptr.type.sizeof and d.isMovableType(innerType) + #warn("INTERNAL: %d" % int(isInternal)) + + p = gdb.Value(array).cast(innerType.pointer()) + begin + inner = innerType.target() if innerTypeIsPointer else innerType + d.beginChildren(inner if n > 0 else None) + for i in xrange(0, n): + if innerTypeIsPointer: + if isNull(p.dereference()): + d.beginHash() + d.putField("value", "(null)") + d.putNumChild(0) + d.putType(p.dereference().type) + d.endHash() + else: + d.putItemOrPointer(Item(p.dereference(), item.iname, i, None)) + else: + if isInternal: + d.putItem(Item(p.dereference(), item.iname, i, None)) + else: + pp = p.cast(innerType.pointer().pointer()).dereference() + d.putItem(Item(pp.dereference(), item.iname, i, None)) + p += 1 + + if n < end - begin: + d.putEllipsis() + d.endChildren() + + +def qqDumpQImage(d, item): + painters = item.value["painters"] + check(0 <= painters and painters < 1000) + d_ptr = item.value["d"] + if isNull(d_ptr): + d.putField("value", "(null)") + else: + check(d_ptr["ref"]["_q_value"] > 0) + d.putField("value", "(%dx%d)" % (d_ptr["width"], d_ptr["height"])) + d.putField("numchild", "0") + # if d.isExpanded(item): + # d.beginChildren() + # d.beginHash() + # d.putField("name", "data") + # d.putField("type", d.ns + "QImageData") + # d.putField("addr", d.data) + # d.endHash() + # d.endChildren() + + +def qqDumpQImageData(d, item): + pass +# const QImage &im = *reinterpret_cast<const QImage *>(d.data) +# const QByteArray ba(QByteArray::fromRawData((const char*)im.bits(), im.numBytes())) +# d.putField("type", d.ns + "QImageData") +# d.putField("numchild", "0") +# #if 1 +# d.putField("value", "<hover here>") +# d.putField("valuetooltipencoded", "1") +# d.putField("valuetooltipsize", ba.size()) +# d.putField("valuetooltip", ba) +# #else +# d.putField("valueencoded", "1") +# d.putField("value", ba) +# #endif + + +def qqDumpQLinkedList(d, item): + d_ptr = item.value["d"] + e_ptr = item.value["e"] + nn = d_ptr["size"] + n = nn + check(0 <= n and n <= 100*1000*1000) + check(d_ptr["ref"]["_q_value"] > 0) + + d.putItemCount(n) + d.putField("numchild", n) + + if d.isExpanded(item): + innerType = item.value.type.template_argument(0) + if n > 1000: + n = 1000 + d.beginChildren(innerType if n > 0 else None) + p = e_ptr["n"] + for i in xrange(0, n): + d.putItemOrPointer(Item(p["t"], None, None, None)) + p = p["n"] + if n < nn: + d.putEllipsis() + d.endChildren() + + +def qqDumpQLocale(d, item): + name = call(item.value, "name()") + d.putField("valueencoded", "7") + d.putField("value", encodeString(name)) + d.putField("numchild", "8") + if d.isExpanded(item): + d.beginChildren(gdb.lookup_type(d.ns + "QChar"), 0) + d.putCallItem("country", item, "country()") + d.putCallItem("language", item, "language()") + d.putCallItem("measurementSystem", item, "measurementSystem()") + d.putCallItem("numberOptions", item, "numberOptions()") + d.putCallItem("timeFormat_(short)", item, + "timeFormat(" + d.ns + "QLocale::ShortFormat)") + d.putCallItem("timeFormat_(long)", item, + "timeFormat(" + d.ns + "QLocale::LongFormat)") + d.putCallItem("decimalPoint", item, "decimalPoint()") + d.putCallItem("exponential", item, "exponential()") + d.putCallItem("percent", item, "percent()") + d.putCallItem("zeroDigit", item, "zeroDigit()") + d.putCallItem("groupSeparator", item, "groupSeparator()") + d.putCallItem("negativeSign", item, "negativeSign()") + d.endChildren() + + +def qqDumpQMapNode(d, item): + d.putField("value", " ") + d.putField("numchild", 2) + if d.isExpanded(item): + d.beginChildren() + d.beginHash() + d.putField("name", "key") + d.putItemHelper(Item(item.value["key"], item.iname, "name", None)) + d.endHash() + d.beginHash() + d.putField("name", "value") + d.putItemHelper(Item(item.value["value"], item.iname, "value", None)) + d.endHash() + d.endChildren() + + +def qqDumpQMap(d, item): + d_ptr = item.value["d"].dereference() + e_ptr = item.value["e"].dereference() + n = d_ptr["size"] + check(0 <= n and n <= 100*1000*1000) + check(d_ptr["ref"]["_q_value"] > 0) + + d.putItemCount(n) + d.putField("numchild", n) + if d.isExpanded(item): + if n > 1000: + n = 1000 + + keyType = item.value.type.template_argument(0) + valueType = item.value.type.template_argument(1) + + isSimpleKey = isSimpleType(keyType) + isSimpleValue = isSimpleType(valueType) + + 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 *) + nodeType = gdb.lookup_type(d.ns + "QMapNode<%s, %s>" % (keyType, valueType)) + payloadSize = nodeType.sizeof - 2 * gdb.lookup_type("void").pointer().sizeof + charPtr = gdb.lookup_type("char").pointer() + + innerType = valueType if isSimpleKey and isSimpleValue else nodeType + + d.beginChildren(innerType if n > 0 else None) + for i in xrange(0, n): + itd = it.dereference() + base = it.cast(charPtr) - payloadSize + node = base.cast(nodeType.pointer()).dereference() + d.beginHash() + + key = node["key"] + value = node["value"] + #if isSimpleType(item.value.type): # or isStringType(d, item.value.type): + # d.putItemHelper(item, field) + #dumpInnerValueHelper(d, Item(key), "name"); + #dumpInnerValueHelper(d, Item(value, "value")) + if isSimpleKey and isSimpleValue: + #d.putType(valueType) + d.putField("name", key) + d.putItemHelper(Item(value, item.iname, i, None)) + else: + d.putItemHelper(Item(node, item.iname, i, None)) + d.endHash() + it = it.dereference()["forward"].dereference() + d.endChildren() + + +def qqDumpMultiMap(d, item): + qqDumpMap(d, item) + + +def qqDumpQModelIndex(d, item): + r = item.value["r"] + c = item.value["c"] + p = item.value["p"] + m = item.value["m"] + if r >= 0 and c >= 0 and not isNull(m): + d.putField("value", "(%s, %s)" % (r, c)) + d.putField("numchild", 5) + if d.isExpanded(item): + d.beginChildren() + d.putIntItem("row", r) + d.putIntItem("column", c) + d.putCallItem("parent", item, "parent()") + d.beginHash() + d.putField("name", "model") + d.putField("value", m) + d.putField("type", d.ns + "QAbstractItemModel*") + d.putField("numchild", "1") + d.endHash() + + d.endChildren() + else: + d.putField("value", "(invalid)") + d.putField("numchild", 0) + + +def extractCString(table, offset): + result = "" + while True: + d = table[offset] + if d == 0: + break + result += "%c" % d + offset += 1 + return result + + +def qqDumpQObject(d, item): + #warn("OBJECT: %s " % item.value) + staticMetaObject = item.value["staticMetaObject"] + #warn("SMO: %s " % staticMetaObject) + privateType = gdb.lookup_type(d.ns + "QObjectPrivate") + d_ptr = item.value["d_ptr"]["d"].dereference().cast(privateType) + #warn("D_PTR: %s " % d_ptr) + objectName = d_ptr["objectName"] + #warn("OBJECTNAME: %s " % objectName) + #warn("D_PTR: %s " % d_ptr.dereference()) + mo = d_ptr["metaObject"] + type = d.stripNamespaceFromType(item.value.type) + if isNull(mo): + mo = staticMetaObject + #warn("MO: %s " % mo) + #warn("MO.D: %s " % mo["d"]) + metaData = mo["d"]["data"] + metaStringData = mo["d"]["stringdata"] + #warn("METADATA: %s " % metaData) + #warn("STRINGDATA: %s " % metaStringData) + #warn("TYPE: %s " % item.value.type) + #d.putField("value", "") + d.putField("valueencoded", "7") + d.putField("value", encodeString(objectName)) + #QSignalMapper::staticMetaObject + #check(d_ptr["ref"]["_q_value"] > 0) + d.putNumChild(4) + if d.isExpanded(item): + d.beginChildren() + + # parent and children + d.putItem(Item(d_ptr["parent"], item.iname, "parent", "parent")) + d.putItem(Item(d_ptr["children"], item.iname, "children", "children")) + + # properties + d.beginHash() + propertyCount = metaData[6] + propertyData = metaData[7] + d.putField("name", "properties") + d.putItemCount(propertyCount) + d.putField("type", "") + d.putField("numchild", propertyCount) + if d.isExpandedIName(item.iname + ".properties"): + d.beginChildren() + for property in xrange(0, propertyCount): + d.beginHash() + offset = propertyData + 3 * property + propertyName = extractCString(metaStringData, metaData[offset]) + propertyType = extractCString(metaStringData, metaData[offset + 1]) + d.putField("name", propertyName) + #flags = metaData[offset + 2] + #warn("FLAGS: %s " % flags) + warn("PROPERTY TYPE: %s " % propertyType) + # #exp = '((\'%sQObject\'*)%s)->property("%s")' \ + # % (d.ns, item.value.address, propertyName) + #exp = '"((\'%sQObject\'*)%s)"' % (d.ns, item.value.address,) + #warn("EXPRESSION: %s" % exp) + #value = gdb.parse_and_eval(exp) + value = call(item.value, 'property("%s")' % propertyName) + warn("VALUE: %s" % value) + warn("TYPE: %s" % value.type) + if True and propertyType == "QString": + # FIXME: re-use parts of QVariant dumper + #d.putField("type", d.ns + "QString") + data = value["d"]["data"]["ptr"] + innerType = gdb.lookup_type(d.ns + "QString") + d.putItemHelper( + Item(data.cast(innerType), item.iname, property, None)) + #d.putField("numchild", "0") + else: + iname = "%s.properties.%s" % (item.iname, propertyName) + d.putItemHelper(Item(value, iname, propertyName)) + d.endHash() + d.endChildren() + d.endHash() + + # connections + d.beginHash() + connectionCount = 0 + d.putField("name", "connections") + d.putItemCount(connectionCount) + d.putField("type", "") + d.putField("numchild", connectionCount) + if connectionCount: + d.putField("childtype", "") + d.putField("childnumchild", "0") + + if d.isExpandedIName(item.iname + ".connections"): + d.beginChildren() + + connectionLists = d_ptr["connectionLists"] + warn("CONNECTIONLISTS: %s " % connectionLists) + + for connection in xrange(0, connectionCount): + d.beginHash() + d.putField("name", "connection %d" % connection) + d.putField("value", "") + d.endHash() + d.endChildren() + d.endHash() + + # signals + signalCount = metaData[13] + d.beginHash() + d.putField("name", "signals") + d.putItemCount(signalCount) + d.putField("type", "") + d.putField("numchild", signalCount) + if signalCount: + # FIXME: empty type does not work for childtype + #d.putField("childtype", ".") + d.putField("childnumchild", "0") + if d.isExpandedIName(item.iname + ".signals"): + d.beginChildren() + for signal in xrange(0, signalCount): + d.beginHash() + offset = metaData[14 + 5 * signal] + d.putField("name", "signal %d" % signal) + d.putField("type", "") + d.putField("value", extractCString(metaStringData, offset)) + d.endHash() + d.endChildren() + d.endHash() + + # slots + d.beginHash() + slotCount = metaData[4] - signalCount + d.putField("name", "slots") + d.putItemCount(slotCount) + d.putField("type", "") + d.putField("numchild", slotCount) + if slotCount: + #d.putField("childtype", ".") + d.putField("childnumchild", "0") + if d.isExpandedIName(item.iname + ".slots"): + d.beginChildren() + for slot in xrange(0, slotCount): + d.beginHash() + offset = metaData[14 + 5 * (signalCount + slot)] + d.putField("name", "slot %d" % slot) + d.putField("type", "") + d.putField("value", extractCString(metaStringData, offset)) + d.endHash() + d.endChildren() + d.endHash() + + d.endChildren() + + +# QObject + +# static const uint qt_meta_data_QObject[] = { + +# int revision; +# int className; +# int classInfoCount, classInfoData; +# int methodCount, methodData; +# int propertyCount, propertyData; +# int enumeratorCount, enumeratorData; +# int constructorCount, constructorData; //since revision 2 +# int flags; //since revision 3 +# int signalCount; //since revision 4 + +# // content: +# 4, // revision +# 0, // classname +# 0, 0, // classinfo +# 4, 14, // methods +# 1, 34, // properties +# 0, 0, // enums/sets +# 2, 37, // constructors +# 0, // flags +# 2, // signalCount + +# /* 14 */ + +# // signals: signature, parameters, type, tag, flags +# 9, 8, 8, 8, 0x05, +# 29, 8, 8, 8, 0x25, + +# /* 24 */ +# // slots: signature, parameters, type, tag, flags +# 41, 8, 8, 8, 0x0a, +# 55, 8, 8, 8, 0x08, + +# /* 34 */ +# // properties: name, type, flags +# 90, 82, 0x0a095103, + +# /* 37 */ +# // constructors: signature, parameters, type, tag, flags +# 108, 101, 8, 8, 0x0e, +# 126, 8, 8, 8, 0x2e, + +# 0 // eod +# }; + +# static const char qt_meta_stringdata_QObject[] = { +# "QObject\0\0destroyed(QObject*)\0destroyed()\0" +# "deleteLater()\0_q_reregisterTimers(void*)\0" +# "QString\0objectName\0parent\0QObject(QObject*)\0" +# "QObject()\0" +# }; + + +# QSignalMapper + +# static const uint qt_meta_data_QSignalMapper[] = { + +# // content: +# 4, // revision +# 0, // classname +# 0, 0, // classinfo +# 7, 14, // methods +# 0, 0, // properties +# 0, 0, // enums/sets +# 0, 0, // constructors +# 0, // flags +# 4, // signalCount + +# // signals: signature, parameters, type, tag, flags +# 15, 14, 14, 14, 0x05, +# 27, 14, 14, 14, 0x05, +# 43, 14, 14, 14, 0x05, +# 60, 14, 14, 14, 0x05, + +# // slots: signature, parameters, type, tag, flags +# 77, 14, 14, 14, 0x0a, +# 90, 83, 14, 14, 0x0a, +# 104, 14, 14, 14, 0x08, + +# 0 // eod +# }; + +# static const char qt_meta_stringdata_QSignalMapper[] = { +# "QSignalMapper\0\0mapped(int)\0mapped(QString)\0" +# "mapped(QWidget*)\0mapped(QObject*)\0" +# "map()\0sender\0map(QObject*)\0" +# "_q_senderDestroyed()\0" +# }; + +# const QMetaObject QSignalMapper::staticMetaObject = { +# { &QObject::staticMetaObject, qt_meta_stringdata_QSignalMapper, +# qt_meta_data_QSignalMapper, 0 } +# }; + + + +# checkAccess(deref(d.data)); // is the d-ptr de-referenceable and valid +# const QObject *ob = reinterpret_cast<const QObject *>(d.data) +# const QMetaObject *mo = ob->metaObject() +# d.putField("value", ob->objectName()) +# d.putField("valueencoded", "2") +# d.putField("type", d.ns + "QObject") +# d.putField("displayedtype", mo->className()) +# d.putField("numchild", 4) +# if d.isExpanded(item): +# int slotCount = 0 +# int signalCount = 0 +# for (int i = mo->methodCount(); --i >= 0; ) { +# QMetaMethod::MethodType mt = mo->method(i).methodType() +# signalCount += (mt == QMetaMethod::Signal) +# slotCount += (mt == QMetaMethod::Slot) +# } +# d.beginChildren() +# d.beginHash() +# d.putField("name", "properties") +# // using 'addr' does not work in gdb as 'exp' is recreated as +# // (type *)addr, and here we have different 'types': +# // QObject vs QObjectPropertyList! +# d.putField("addr", d.data) +# d.putField("type", d.ns + "QObjectPropertyList") +# d.putItemCount(mo->propertyCount()) +# d.putField("numchild", mo->propertyCount()) +# d.endHash() +# d.beginHash() +# d.putField("name", "signals") +# d.putField("addr", d.data) +# d.putField("type", d.ns + "QObjectSignalList") +# d.putItemCount(signalCount) +# d.putField("numchild", signalCount) +# d.endHash() +# d.beginHash() +# d.putField("name", "slots") +# d.putField("addr", d.data) +# d.putField("type", d.ns + "QObjectSlotList") +# d.putItemCount(slotCount) +# d.putField("numchild", slotCount) +# d.endHash() +# const QObjectList objectChildren = ob->children() +# if !objectChildren.empty()) { +# d.beginHash() +# d.putField("name", "children") +# d.putField("addr", d.data) +# d.putField("type", ns + "QObjectChildList") +# d.putItemCount(objectChildren.size()) +# d.putField("numchild", objectChildren.size()) +# d.endHash() +# } +# d.beginHash() +# d.putField("name", "parent") +# dumpInnerValueHelper(d, ns + "QObject *", ob->parent()) +# d.endHash() +# #if 1 +# d.beginHash() +# d.putField("name", "className") +# d.putField("value", ob->metaObject()->className()) +# d.putField("type", "") +# d.putField("numchild", "0") +# d.endHash() +# #endif +# d.endChildren() + + +# #if USE_QT_GUI +# static const char *sizePolicyEnumValue(QSizePolicy::Policy p) +# { +# switch (p) { +# case QSizePolicy::Fixed: +# return "Fixed" +# case QSizePolicy::Minimum: +# return "Minimum" +# case QSizePolicy::Maximum: +# return "Maximum" +# case QSizePolicy::Preferred: +# return "Preferred" +# case QSizePolicy::Expanding: +# return "Expanding" +# case QSizePolicy::MinimumExpanding: +# return "MinimumExpanding" +# case QSizePolicy::Ignored: +# break +# } +# return "Ignored" +# } +# +# static QString sizePolicyValue(const QSizePolicy &sp) +# { +# QString rc +# QTextStream str(&rc) +# // Display as in Designer +# str << '[' << sizePolicyEnumValue(sp.horizontalPolicy()) +# << ", " << sizePolicyEnumValue(sp.verticalPolicy()) +# << ", " << sp.horizontalStretch() << ", " << sp.verticalStretch() << ']' +# return rc +# } +# #endif +# +# // Meta enumeration helpers +# static inline void dumpMetaEnumType(QDumper &d, const QMetaEnum &me) +# { +# QByteArray type = me.scope() +# if !type.isEmpty()) +# type += "::" +# type += me.name() +# d.putField("type", type.constData()) +# } +# +# static inline void dumpMetaEnumValue(QDumper &d, const QMetaProperty &mop, +# int value) +# { +# +# const QMetaEnum me = mop.enumerator() +# dumpMetaEnumType(d, me) +# if const char *enumValue = me.valueToKey(value)) { +# d.putField("value", enumValue) +# } else { +# d.putField("value", value) +# } +# d.putField("numchild", 0) +# } +# +# static inline void dumpMetaFlagValue(QDumper &d, const QMetaProperty &mop, +# int value) +# { +# const QMetaEnum me = mop.enumerator() +# dumpMetaEnumType(d, me) +# const QByteArray flagsValue = me.valueToKeys(value) +# if flagsValue.isEmpty()) { +# d.putField("value", value) +# } else { +# d.putField("value", flagsValue.constData()) +# } +# d.putField("numchild", 0) +# } +# +# #ifndef QT_BOOTSTRAPPED +# static void dumpQObjectProperty(QDumper &d) +# { +# const QObject *ob = (const QObject *)d.data +# const QMetaObject *mob = ob->metaObject() +# // extract "local.Object.property" +# QString iname = d.iname +# const int dotPos = iname.lastIndexOf(QLatin1Char('.')) +# if dotPos == -1) +# return +# iname.remove(0, dotPos + 1) +# const int index = mob->indexOfProperty(iname.toAscii()) +# if index == -1) +# return +# const QMetaProperty mop = mob->property(index) +# const QVariant value = mop.read(ob) +# const bool isInteger = value.type() == QVariant::Int +# if isInteger and mop.isEnumType()) { +# dumpMetaEnumValue(d, mop, value.toInt()) +# } elif isInteger and mop.isFlagType()) { +# dumpMetaFlagValue(d, mop, value.toInt()) +# } else { +# dumpQVariant(d, &value) +# } +# d.disarm() +# } +# +# static void dumpQObjectPropertyList(QDumper &d) +# { +# const QObject *ob = (const QObject *)d.data +# const QMetaObject *mo = ob->metaObject() +# const int propertyCount = mo->propertyCount() +# d.putField("addr", "<synthetic>") +# d.putField("type", ns + "QObjectPropertyList") +# d.putField("numchild", propertyCount) +# d.putItemCount(propertyCount) +# if d.isExpanded(item): +# d.beginChildren() +# for (int i = propertyCount; --i >= 0; ) { +# const QMetaProperty & prop = mo->property(i) +# d.beginHash() +# d.putField("name", prop.name()) +# switch (prop.type()) { +# case QVariant::String: +# d.putField("type", prop.typeName()) +# d.putField("value", prop.read(ob).toString()) +# d.putField("valueencoded", "2") +# d.putField("numchild", "0") +# break +# case QVariant::Bool: +# d.putField("type", prop.typeName()) +# d.putField("value", (prop.read(ob).toBool() ? "true" : "false")) +# d.putField("numchild", "0") +# break +# case QVariant::Int: +# if prop.isEnumType()) { +# dumpMetaEnumValue(d, prop, prop.read(ob).toInt()) +# } elif prop.isFlagType()) { +# dumpMetaFlagValue(d, prop, prop.read(ob).toInt()) +# } else { +# d.putField("value", prop.read(ob).toInt()) +# d.putField("numchild", "0") +# } +# break +# default: +# d.putField("addr", d.data) +# d.putField("type", ns + "QObjectProperty") +# d.putField("numchild", "1") +# break +# } +# d.endHash() +# } +# d.endChildren() +# } +# d.disarm() +# } +# +# static void dumpQObjectMethodList(QDumper &d) +# { +# const QObject *ob = (const QObject *)d.data +# const QMetaObject *mo = ob->metaObject() +# d.putField("addr", "<synthetic>") +# d.putField("type", ns + "QObjectMethodList") +# d.putField("numchild", mo->methodCount()) +# if d.isExpanded(item): +# d.putField("childtype", ns + "QMetaMethod::Method") +# d.putField("childnumchild", "0") +# d.beginChildren() +# for (int i = 0; i != mo->methodCount(); ++i) { +# const QMetaMethod & method = mo->method(i) +# int mt = method.methodType() +# d.beginHash() +# d.beginItem("name") +# d.put(i).put(" ").put(mo->indexOfMethod(method.signature())) +# d.put(" ").put(method.signature()) +# d.endItem() +# d.beginItem("value") +# d.put((mt == QMetaMethod::Signal ? "<Signal>" : "<Slot>")) +# d.put(" (").put(mt).put(")") +# d.endItem() +# d.endHash() +# } +# d.endChildren() +# } +# d.disarm() +# } +# +# def qConnectionType(type): +# Qt::ConnectionType connType = static_cast<Qt::ConnectionType>(type) +# const char *output = "unknown" +# switch (connType) { +# case Qt::AutoConnection: output = "auto"; break +# case Qt::DirectConnection: output = "direct"; break +# case Qt::QueuedConnection: output = "queued"; break +# case Qt::BlockingQueuedConnection: output = "blockingqueued"; break +# case 3: output = "autocompat"; break +# #if QT_VERSION >= 0x040600 +# case Qt::UniqueConnection: break; // Can't happen. +# #endif +# return output +# +# #if QT_VERSION >= 0x040400 +# static const ConnectionList &qConnectionList(const QObject *ob, int signalNumber) +# { +# static const ConnectionList emptyList +# const ObjectPrivate *p = reinterpret_cast<const ObjectPrivate *>(dfunc(ob)) +# if !p->connectionLists) +# return emptyList +# typedef QVector<ConnectionList> ConnLists +# const ConnLists *lists = reinterpret_cast<const ConnLists *>(p->connectionLists) +# // there's an optimization making the lists only large enough to hold the +# // last non-empty item +# if signalNumber >= lists->size()) +# return emptyList +# return lists->at(signalNumber) +# } +# #endif +# +# // Write party involved in a slot/signal element, +# // avoid to recursion to self. +# static inline void dumpQObjectConnectionPart(QDumper &d, +# const QObject *owner, +# const QObject *partner, +# int number, const char *namePostfix) +# { +# d.beginHash() +# d.beginItem("name") +# d.put(number).put(namePostfix) +# d.endItem() +# if partner == owner) { +# d.putField("value", "<this>") +# d.putField("type", owner->metaObject()->className()) +# d.putField("numchild", 0) +# d.putField("addr", owner) +# } else { +# dumpInnerValueHelper(d, ns + "QObject *", partner) +# } +# d.endHash() +# +# static void dumpQObjectSignal(QDumper &d) +# { +# unsigned signalNumber = d.extraInt[0] +# +# d.putField("addr", "<synthetic>") +# d.putField("numchild", "1") +# d.putField("type", ns + "QObjectSignal") +# +# #if QT_VERSION >= 0x040400 +# if d.isExpanded(item): +# const QObject *ob = reinterpret_cast<const QObject *>(d.data) +# d.beginChildren() +# const ConnectionList &connList = qConnectionList(ob, signalNumber) +# for (int i = 0; i != connList.size(); ++i) { +# const Connection &conn = connectionAt(connList, i) +# dumpQObjectConnectionPart(d, ob, conn.receiver, i, " receiver") +# d.beginHash() +# d.beginItem("name") +# d.put(i).put(" slot") +# d.endItem() +# d.putField("type", "") +# if conn.receiver) +# d.putField("value", conn.receiver->metaObject()->method(conn.method).signature()) +# else +# d.putField("value", "<invalid receiver>") +# d.putField("numchild", "0") +# d.endHash() +# d.beginHash() +# d.beginItem("name") +# d.put(i).put(" type") +# d.endItem() +# d.putField("type", "") +# d.beginItem("value") +# d.put("<").put(qConnectionType(conn.connectionType)).put(" connection>") +# d.endItem() +# d.putField("numchild", "0") +# d.endHash() +# } +# d.endChildren() +# d.putField("numchild", connList.size()) +# #endif +# +# static void dumpQObjectSignalList(QDumper &d) +# { +# const QObject *ob = reinterpret_cast<const QObject *>(d.data) +# const QMetaObject *mo = ob->metaObject() +# int count = 0 +# const int methodCount = mo->methodCount() +# for (int i = methodCount; --i >= 0; ) +# count += (mo->method(i).methodType() == QMetaMethod::Signal) +# d.putField("type", ns + "QObjectSignalList") +# d.putItemCount(count) +# d.putField("addr", d.data) +# d.putField("numchild", count) +# #if QT_VERSION >= 0x040400 +# if d.isExpanded(item): +# d.beginChildren() +# for (int i = 0; i != methodCount; ++i) { +# const QMetaMethod & method = mo->method(i) +# if method.methodType() == QMetaMethod::Signal) { +# int k = mo->indexOfSignal(method.signature()) +# const ConnectionList &connList = qConnectionList(ob, k) +# d.beginHash() +# d.putField("name", k) +# d.putField("value", method.signature()) +# d.putField("numchild", connList.size()) +# d.putField("addr", d.data) +# d.putField("type", ns + "QObjectSignal") +# d.endHash() +# #endif +# +# static void dumpQObjectSlot(QDumper &d) +# { +# int slotNumber = d.extraInt[0] +# +# d.putField("addr", d.data) +# d.putField("numchild", "1") +# d.putField("type", ns + "QObjectSlot") +# +# #if QT_VERSION >= 0x040400 +# if d.isExpanded(item): +# d.beginChildren() +# int numchild = 0 +# const QObject *ob = reinterpret_cast<const QObject *>(d.data) +# const ObjectPrivate *p = reinterpret_cast<const ObjectPrivate *>(dfunc(ob)) +# #if QT_VERSION >= 0x040600 +# int s = 0 +# for (SenderList senderList = p->senders; senderList != 0 +# senderList = senderList->next, ++s) { +# const QObject *sender = senderList->sender +# int signal = senderList->method; // FIXME: 'method' is wrong. +# #else +# for (int s = 0; s != p->senders.size(); ++s) { +# const QObject *sender = senderAt(p->senders, s) +# int signal = signalAt(p->senders, s) +# #endif +# const ConnectionList &connList = qConnectionList(sender, signal) +# for (int i = 0; i != connList.size(); ++i) { +# const Connection &conn = connectionAt(connList, i) +# if conn.receiver == ob and conn.method == slotNumber) { +# ++numchild +# const QMetaMethod &method = sender->metaObject()->method(signal) +# dumpQObjectConnectionPart(d, ob, sender, s, " sender") +# d.beginHash() +# d.beginItem("name") +# d.put(s).put(" signal") +# d.endItem() +# d.putField("type", "") +# d.putField("value", method.signature()) +# d.putField("numchild", "0") +# d.endHash() +# d.beginHash() +# d.beginItem("name") +# d.put(s).put(" type") +# d.endItem() +# d.putField("type", "") +# d.beginItem("value") +# d.put("<").put(qConnectionType(conn.method)) +# d.put(" connection>") +# d.endItem() +# d.putField("numchild", "0") +# d.endHash() +# } +# } +# } +# d.endChildren() +# d.putField("numchild", numchild) +# } +# #endif +# d.disarm() +# } +# +# static void dumpQObjectSlotList(QDumper &d) +# { +# const QObject *ob = reinterpret_cast<const QObject *>(d.data) +# #if QT_VERSION >= 0x040400 +# const ObjectPrivate *p = reinterpret_cast<const ObjectPrivate *>(dfunc(ob)) +# #endif +# const QMetaObject *mo = ob->metaObject() +# +# int count = 0 +# const int methodCount = mo->methodCount() +# for (int i = methodCount; --i >= 0; ) +# count += (mo->method(i).methodType() == QMetaMethod::Slot) +# +# d.putField("numchild", count) +# d.putItemCount(count) +# d.putField("type", ns + "QObjectSlotList") +# if d.isExpanded(item): +# d.beginChildren() +# #if QT_VERSION >= 0x040400 +# for (int i = 0; i != methodCount; ++i) { +# const QMetaMethod & method = mo->method(i) +# if method.methodType() == QMetaMethod::Slot) { +# d.beginHash() +# int k = mo->indexOfSlot(method.signature()) +# d.putField("name", k) +# d.putField("value", method.signature()) +# +# // count senders. expensive... +# int numchild = 0 +# #if QT_VERSION >= 0x040600 +# int s = 0 +# for (SenderList senderList = p->senders; senderList != 0 +# senderList = senderList->next, ++s) { +# const QObject *sender = senderList->sender +# int signal = senderList->method; // FIXME: 'method' is wrong. +# #else +# for (int s = 0; s != p->senders.size(); ++s) { +# const QObject *sender = senderAt(p->senders, s) +# int signal = signalAt(p->senders, s) +# #endif +# const ConnectionList &connList = qConnectionList(sender, signal) +# for (int c = 0; c != connList.size(); ++c) { +# const Connection &conn = connectionAt(connList, c) +# if conn.receiver == ob and conn.method == k) +# ++numchild +# } +# } +# d.putField("numchild", numchild) +# d.putField("addr", d.data) +# d.putField("type", ns + "QObjectSlot") +# d.endHash() +# } +# } +# #endif +# d.endChildren() +# } +# d.disarm() +# } +# +# static void dumpQObjectChildList(QDumper &d) +# { +# const QObject *ob = reinterpret_cast<const QObject *>(d.data) +# const QObjectList children = ob->children() +# const int size = children.size() +# +# d.putField("numchild", size) +# d.putItemCount(size) +# d.putField("type", ns + "QObjectChildList") +# if d.isExpanded(item): +# d.beginChildren() +# for (int i = 0; i != size; ++i) { +# d.beginHash() +# dumpInnerValueHelper(d, ns + "QObject *", children.at(i)) +# d.endHash() +# } +# d.endChildren() +# } +# d.disarm() +# } +# #endif // QT_BOOTSTRAPPED + + +def qqDumpQPixmap(d, item): + painters = item.value["painters"] + check(0 <= painters and painters < 1000) + d_ptr = item.value["data"]["d"] + if isNull(d_ptr): + d.putField("value", "(null)") + else: + check(d_ptr["ref"]["_q_value"] > 0) + d.putField("value", "(%dx%d)" % (d_ptr["w"], d_ptr["h"])) + d.putField("numchild", "0") + + +def qqDumpQPoint(d, item): + x = item.value["xp"] + y = item.value["yp"] + # should not be needed, but sometimes yield myns::QVariant::Private::Data::qreal + x = x.cast(x.type.strip_typedefs()) + y = y.cast(y.type.strip_typedefs()) + d.putField("value", "(%s, %s)" % (x, y)) + d.putNumChild(2) + if d.isExpanded(item): + d.beginChildren(x.type.strip_typedefs()) + d.putItem(Item(x, None, None, "x")) + d.putItem(Item(y, None, None, "y")) + d.endChildren() + + +def qqDumpQPointF(d, item): + qqDumpQPoint(d, item) + + +def qqDumpQSize(d, item): + w = item.value["wd"] + h = item.value["ht"] + d.putField("value", "(%s, %s)" % (w, h)) + d.putNumChild(2) + if d.isExpanded(item): + d.beginChildren(w.type) + d.putItem(Item(w, item.iname, "w", "w")) + d.putItem(Item(h, item.iname, "h", "h")) + d.endChildren() + + +def qqDumpQSizeF(d, item): + qqDumpQSize(d, item) + + +def qqDumpQRect(d, item): + def pp(l): return ("+%s" % l) if l >= 0 else l + x1 = item.value["x1"] + y1 = item.value["y1"] + x2 = item.value["x2"] + y2 = item.value["y2"] + w = x2 - x1 + 1 + h = y2 - y1 + 1 + d.putField("value", "%sx%s%s%s" % (w, h, pp(x1), pp(y1))) + d.putNumChild(4) + if d.isExpanded(item): + d.beginChildren(x1.type.strip_typedefs()) + d.putItem(Item(x1, None, None, "x1")) + d.putItem(Item(y1, None, None, "y1")) + d.putItem(Item(x2, None, None, "x2")) + d.putItem(Item(y2, None, None, "y2")) + d.endChildren() + + +def qqDumpQRectF(d, item): + def pp(l): return ("+%s" % l) if l >= 0 else l + x = item.value["xp"] + y = item.value["yp"] + w = item.value["w"] + h = item.value["h"] + # FIXME: workaround, see QPoint + x = x.cast(x.type.strip_typedefs()) + y = y.cast(y.type.strip_typedefs()) + w = w.cast(w.type.strip_typedefs()) + h = h.cast(h.type.strip_typedefs()) + d.putField("value", "%sx%s%s%s" % (w, h, pp(x), pp(y))) + d.putNumChild(4) + if d.isExpanded(item): + d.beginChildren(x.type.strip_typedefs()) + d.putItem(Item(x, None, None, "x")) + d.putItem(Item(y, None, None, "y")) + d.putItem(Item(w, None, None, "w")) + d.putItem(Item(h, None, None, "h")) + d.endChildren() + + +def encodeString(value): + d_ptr = value['d'].dereference() + data = d_ptr['data'] + size = d_ptr['size'] + alloc = d_ptr['alloc'] + check(0 <= size and size <= alloc and alloc <= 100*1000*1000) + if size > 0: + checkAccess(data, 4) + checkAccess(data + size * 2) == 0 + check(d_ptr["ref"]["_q_value"] > 0) + p = gdb.Value(d_ptr["data"]) + s = "" + for i in xrange(0, size): + val = int(p.dereference()) + s += "%02x" % (val % 256) + s += "%02x" % (val / 256) + p += 1 + return s + + +def qqDumpQString(d, item): + str = encodeString(item.value) + d.putField("valueencoded", "7") + d.putField("value", str) + d.putNumChild(0) + + +def qqDumpQStringList(d, item): + d_ptr = item.value['d'] + begin = d_ptr['begin'] + end = d_ptr['end'] + n = end - begin + check(n >= 0) + check(n <= 10 * 1000 * 1000) + # checkAccess(&list.front()) + # checkAccess(&list.back()) + check(d_ptr["ref"]["_q_value"] > 0) + d.putItemCount(n) + d.putNumChild(n) + if d.isExpanded(item): + if n > 1000: + n = 1000 + innerType = gdb.lookup_type(d.ns + "QString") + ptr = gdb.Value(d_ptr["array"]).cast(innerType.pointer()) + d.beginChildren(innerType if n > 0 else None) + for i in xrange(0, n): + d.putItem(Item(ptr.dereference(), item.iname, i, None)) + ptr += 1 + if n < end - begin: + d.putEllipsis() + d.endChildren() + + +def qqDumpQSet(d, item): + + def hashDataFirstNode(value): + value = value.cast(hashDataType) + bucket = value["buckets"] + e = value.cast(hashNodeType) + for n in xrange(value["numBuckets"] - 1, -1, -1): + 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() + numBuckets = d["numBuckets"] + start = (node["h"] % numBuckets) + 1 + bucket = d["buckets"] + start + for n in xrange(0, numBuckets - start): + if bucket.dereference() != next: + return bucket.dereference() + bucket += 1 + return node + + keyType = item.value.type.template_argument(0) + + d_ptr = item.value["q_hash"]["d"] + e_ptr = item.value["q_hash"]["e"] + n = d_ptr["size"] + + hashDataType = d_ptr.type + hashNodeType = e_ptr.type + + check(0 <= n and n <= 100 * 1000 * 1000) + check(d_ptr["ref"]["_q_value"] > 0) + + d.putItemCount(n) + d.putField("numchild", n) + if d.isExpanded(item): + if n > 1000: + n = 1000 + + isSimpleKey = isSimpleType(keyType) + + node = hashDataFirstNode(item.value) + + innerType = e_ptr.dereference().type + d.beginChildren(keyType if n > 0 else None) + for i in xrange(0, n): + it = node.dereference().cast(innerType) + d.beginHash() + key = it["key"] + if isSimpleKey: + d.putType(keyType) + d.putItemHelper(Item(key, None, None, None), "value") + else: + d.putItemHelper(Item(key, item.iname, i, None)) + d.endHash() + node = hashDataNextNode(node) + d.endChildren() + + +def qqDumpQSharedPointer(d, item): + qqDumpQWeakPointer(d, item) + + +def qqDumpQStack(d, item): + qqDumpQVector(d, item) + + +def qqDumpQTemporaryFile(d, item): + qqDumpQFile(d, item) + + +#FIXME: X(..) +def qqDumpQTextCodecX(d, item): + #checkPointer(deref(d.data)) + warn("VALUE: %s " % item.value) + #const QTextCodec &codec = *reinterpret_cast<const QTextCodec *>(d.data) + #d.putField("valueencoded", "1") + #d.putField("value", codec.name()) + d.putField("type", d.ns + "QTextCodec") + d.putField("numchild", "2") + if d.isExpanded(item): + d.beginChildren() + #d.putCallItem("name", codec.name()) + #d.putCallItem("mibEnum", codec.mibEnum()) + d.endChildren() + + +def qqDumpQVariant(d, item): + union = item.value["d"] + data = union["data"] + variantType = int(union["type"]) + #warn("VARIANT TYPE: %s : " % variantType) + inner = "" + innert = "" + if variantType == 0: # QVariant::Invalid + d.putField("value", "(invalid)") + d.putNumChild(0) + elif variantType == 1: # QVariant::Bool + d.putField("value", "true" if data["b"] else "false") + d.putNumChild(0) + elif variantType == 2: # QVariant::Int + d.putField("value", data["i"]) + d.putNumChild(0) + elif variantType == 3: # uint + d.putField("value", data["u"]) + d.putNumChild(0) + elif variantType == 4: # qlonglong + d.putField("value", data["ll"]) + d.putNumChild(0) + elif variantType == 5: # qulonglong + d.putField("value", data["ull"]) + d.putNumChild(0) + elif variantType == 6: # QVariant::Double + value = data["d"] + d.putField("value", data["d"]) + d.putNumChild(0) + elif variantType == 7: # QVariant::QChar + inner = d.ns + "QChar" + elif variantType == 8: # QVariant::VariantMap + inner = d.ns + "QMap<" + d.ns + "QString, " + d.ns + "QVariant>" + innert = d.ns + "QVariantMap" + elif variantType == 9: # QVariant::VariantList + inner = d.ns + "QList<" + d.ns + "QVariant>" + innert = d.ns + "QVariantList" + elif variantType == 10: # QVariant::String + inner = d.ns + "QString" + elif variantType == 11: # QVariant::StringList + inner = d.ns + "QStringList" + elif variantType == 12: # QVariant::ByteArray + inner = d.ns + "QByteArray" + elif variantType == 13: # QVariant::BitArray + inner = d.ns + "QBitArray" + elif variantType == 14: # QVariant::Date + inner = d.ns + "QDate" + elif variantType == 15: # QVariant::Time + inner = d.ns + "QTime" + elif variantType == 16: # QVariant::DateTime + inner = d.ns + "QDateTime" + elif variantType == 17: # QVariant::Url + inner = d.ns + "QUrl" + elif variantType == 18: # QVariant::Locale + inner = d.ns + "QLocale" + elif variantType == 19: # QVariant::Rect + inner = d.ns + "QRect" + elif variantType == 20: # QVariant::RectF + inner = d.ns + "QRectF" + elif variantType == 21: # QVariant::Size + inner = d.ns + "QSize" + elif variantType == 22: # QVariant::SizeF + inner = d.ns + "QSizeF" + elif variantType == 23: # QVariant::Line + inner = d.ns + "QLine" + elif variantType == 24: # QVariant::LineF + inner = d.ns + "QLineF" + elif variantType == 25: # QVariant::Point + inner = d.ns + "QPoint" + elif variantType == 26: # QVariant::PointF + inner = d.ns + "QPointF" + elif variantType == 27: # QVariant::RegExp + inner = d.ns + "QRegExp" + elif variantType == 28: # QVariant::VariantHash + inner = d.ns + "QHash<" + d.ns + "QString, " + d.ns + "QVariant>" + innert = d.ns + "QVariantHash" + elif variantType == 64: # QVariant::Font + inner = d.ns + "QFont" + elif variantType == 67: # QVariant::Color + inner = d.ns + "QColor" + elif variantType == 71: # QVariant::Polygon and PointArray + inner = d.ns + "QPointArray" + elif variantType == 75: # QVariant::SizePolicy + inner = d.ns + "QSizePolicy" + elif variantType == 76: # QVariant::KeySequence + inner = d.ns + "QKeySequence" + elif variantType == 76: # QVariant::Quadernion + inner = d.ns + "QQuadernion" + else: + # FIXME: handle User types + d.putField("value", "(unknown type %d)" % variantType) + # typeName = QMetaType::typeName(typ) + # exp = "'qVariantValue<%s >'(*('"NS"QVariant'*)%p)" + d.putNumChild(0) + + if len(inner): + if len(innert) == 0: + innert = inner + d.putField("value", "(%s)" % innert) + d.putNumChild(1) + if d.isExpanded(item): + innerType = gdb.lookup_type(inner) + d.beginChildren() + d.beginHash() + #d.putField("name", "data") + #d.putField("type", innert) + val = gdb.Value(data["ptr"]).cast(innerType) + d.putItemHelper(Item(val, item.iname, "data", "data")) + d.endHash() + d.endChildren() + + +def qqDumpQVector(d, item): + # QBasicAtomicInt ref; + # int alloc; + # int size; + # uint sharable : 1; + # uint capacity : 1; + d_ptr = item.value["d"] + p_ptr = item.value["p"] + alloc = d_ptr["alloc"] + size = d_ptr["size"] + + check(0 <= size and size <= alloc and alloc <= 1000 * 1000 * 1000) + check(d_ptr["ref"]["_q_value"] > 0) + + # Check pointers + innerType = item.value.type.template_argument(0) + #if innerType.code == gdb.TYPE_CODE_PTR and nn > 0: + # for (int i = 0; i != size; ++i) + # if const void *p = addOffset(v, i * innersize + typeddatasize)) + # checkAccess(deref(p)) + + d.putItemCount(size) + d.putNumChild(size) + if d.isExpanded(item): + n = size + if n > 10000: + n = 10000 + p = gdb.Value(p_ptr["array"]).cast(innerType.pointer()) + d.beginChildren(innerType if n > 0 else None) + for i in xrange(0, n): + d.putItemOrPointer(Item(p.dereference(), item.iname, i, None)) + p += 1 + if n < size: + d.putEllipsis() + d.endChildren() + + +def qqDumpQWeakPointer(d, item): + d_ptr = item.value["d"] + value = item.value["value"] + if isNull(d_ptr) and isNull(value): + d.putField("value", "(null)") + d.putNumChild(0) + return + if isNull(value) or isNull(value): + d.putField("value", "<invalid>") + d.putNumChild(0) + return + weakref = d_ptr["weakref"]["_q_value"] + strongref = d_ptr["strongref"]["_q_value"] + check(0 < int(strongref)) + check(int(strongref) <= int(weakref)) + check(int(weakref) <= 10*1000*1000) + + innerType = item.value.type.template_argument(0) + if isSimpleType(value.dereference()): + d.putItemHelper(Item(value.dereference(), item.iname, None, None)) + else: + d.putField("value", "") + + d.putField("numchild", 3) + if d.isExpanded(item): + d.beginChildren() + d.putItem(Item(value.dereference(), item.iname, "data", "data")) + d.putIntItem("weakref", weakref) + d.putIntItem("strongref", strongref) + d.endChildren() + + + +####################################################################### +# +# Standard Library dumper +# +####################################################################### + +def qqDumpStdDeque(d, item): + impl = item.value["_M_impl"] + start = impl["_M_start"] + n = impl["_M_finish"]["_M_cur"] - start["_M_cur"] + d.putItemCount(n) + d.putNumChild(n) + if d.isExpanded(item): + innerType = item.value.type.template_argument(0) + innerSize = innerType.sizeof + bufsize = 512 / innerSize if innerSize < 512 else 1 + d.beginChildren(innerType if n > 0 else None) + pcur = start["_M_cur"] + pfirst = start["_M_first"] + plast = start["_M_last"] + pnode = start["_M_node"] + for i in xrange(0, n): + d.putItemOrPointer(Item(pcur.dereference(), item.iname, i, None)) + pcur += 1 + if pcur == plast: + newnode = pnode + 1 + pnode = newnode + pfirst = newnode.dereference() + plast = pfirst + bufsize + pcur = pfirst + + if n > 1000: + d.putEllipsis() + d.endChildren() + + +def qqDumpStdList(d, item): + impl = item.value["_M_impl"] + node = impl["_M_node"] + head = node.address + n = 0 + p = node["_M_next"] + while p != head and n <= 1001: + n += 1 + p = p["_M_next"] + + d.putItemCount(n if n <= 1000 else "> 1000") + d.putNumChild(n) + + if d.isExpanded(item): + p = node["_M_next"] + innerType = item.value.type.template_argument(0) + d.beginChildren(innerType if n > 0 else None) + for i in xrange(0, n): + innerPointer = innerType.pointer() + value = (p + 1).cast(innerPointer).dereference() + d.putItemOrPointer(Item(value, item.iname, i, None)) + p = p["_M_next"] + if n > 1000: + d.putEllipsis() + d.endChildren() + + +def qqDumpStdMap(d, item): + impl = item.value["_M_t"]["_M_impl"] + n = impl["_M_node_count"] + check(0 <= n and n <= 100*1000*1000) + d.putItemCount(n) + d.putNumChild(n) + + if d.isExpanded(item): + keyType = item.value.type.template_argument(0) + valueType = item.value.type.template_argument(1) + pairType = item.value.type.template_argument(3).template_argument(0) + isSimpleKey = isSimpleType(keyType) + isSimpleValue = isSimpleType(valueType) + innerType = valueType if isSimpleKey and isSimpleValue else pairType + pairPointer = pairType.pointer() + node = impl["_M_header"]["_M_left"] + d.beginChildren(innerType if n > 0 else pairType, + None if isSimpleKey and isSimpleValue else 2) + for i in xrange(0, n if n < 1000 else 1000): + pair = (node + 1).cast(pairPointer).dereference() + + d.beginHash() + if isSimpleKey and isSimpleValue: + d.putField("name", str(pair["first"])) + d.putItemHelper(Item(pair["second"], item.iname, i, None)) + else: + d.putField("value", " ") + if d.isExpandedIName("%s.%d" % (item.iname, i)): + d.beginChildren(None) + iname = "%s.%d." % (item.iname, i) + keyItem = Item(pair["first"], iname + "key", "key", "first") + valueItem = Item(pair["second"], iname + "value", "value", "second") + d.putItem(keyItem) + d.putItem(valueItem) + d.endChildren() + d.endHash() + + if isNull(node["_M_right"]): + parent = node["_M_parent"] + while node == parent["_M_right"]: + node = parent + parent = parent["_M_parent"] + if node["_M_right"] != parent: + node = parent + else: + node = node["_M_right"] + while not isNull(node["_M_left"]): + node = node["_M_left"] + + if n >= 1000: + d.putEllipsis() + d.endChildren() + + +def qqDumpStdSet(d, item): + impl = item.value["_M_t"]["_M_impl"] + n = impl["_M_node_count"] + check(0 <= n and n <= 100*1000*1000) + d.putItemCount(n) + d.putNumChild(n) + if d.isExpanded(item): + valueType = item.value.type.template_argument(0) + node = impl["_M_header"]["_M_left"] + d.beginChildren(valueType if n > 0 else None) + for i in xrange(0, n if n < 1000 else 1000): + element = (node + 1).cast(valueType.pointer()).dereference() + d.putItem(Item(element, item.iname, i, None)) + + if isNull(node["_M_right"]): + parent = node["_M_parent"] + while node == parent["_M_right"]: + node = parent + parent = parent["_M_parent"] + if node["_M_right"] != parent: + node = parent + else: + node = node["_M_right"] + while not isNull(node["_M_left"]): + node = node["_M_left"] + if n >= 1000: + d.putEllipsis() + d.endChildren() + + +def qqDumpStdString(d, item): + data = item.value["_M_dataplus"]["_M_p"] + baseType = item.value.type.unqualified().strip_typedefs() + charType = baseType.template_argument(0) + repType = gdb.lookup_type("%s::_Rep" % baseType).pointer() + rep = (data.cast(repType) - 1).dereference() + size = rep['_M_length'] + alloc = rep['_M_capacity'] + check(rep['_M_refcount'] >= 0) + check(0 <= size and size <= alloc and alloc <= 100*1000*1000) + d.unputField("type") + if str(charType) == "char": + d.putType("std::string") + elif str(charType) == "wchar_t": + d.putType("std::string") + else: + d.putType(baseType) + p = gdb.Value(data.cast(charType.pointer())) + s = "" + format = "%%0%dx" % (2 * charType.sizeof) + n = size if size < 1000 else 10000 + for i in xrange(0, size): + s += format % int(p.dereference()) + p += 1 + d.putField("valueencoded", "6") + d.putField("value", s) + d.putField("numchild", 0) + + +def qqDumpStdVector(d, item): + impl = item.value["_M_impl"] + start = impl["_M_start"] + finish = impl["_M_finish"] + alloc = impl["_M_end_of_storage"] + size = finish - start + + check(0 <= size and size <= 1000 * 1000 * 1000) + check(finish <= alloc) + checkPointer(start) + checkPointer(finish) + checkPointer(alloc) + + d.putItemCount(size) + d.putNumChild(size) + if d.isExpanded(item): + n = size + if n > 10000: + n = 10000 + p = start + innerType = item.value.type.template_argument(0) + d.beginChildren(innerType if n > 0 else None) + for i in xrange(0, n): + d.putItemOrPointer(Item(p.dereference(), item.iname, i, None)) + p += 1 + if n < size: + d.putEllipsis() + d.endChildren() + + +# needed +#gdb.pretty_printers.append(QStringPrinter) + +#gdb.pretty_printers["^QStringList$"] = QStringPrinter +#gdb.pretty_printers["^myns::QList<myns::QString>$"] = QStringPrinter +#gdb.pretty_printers["^myns::QCoreApplication$"] = QStringPrinter +