Commit 71c3d097 authored by hjk's avatar hjk

debugger: try make custom dumpers more "user friendly"

Introduce Dumper.put{Value,Name,StringValue,ByteArrayValue} functions.
No need for explicit specification of valueencoding in user code.
parent 4bac4969
......@@ -123,6 +123,44 @@ def qtNamespace():
except RuntimeError:
return ""
def encodeByteArray(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)
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
return s
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
#######################################################################
#
# Item
......@@ -347,6 +385,26 @@ class Dumper:
if int(numchild) != int(self.childNumChilds[-1]):
self.putField("numchild", numchild)
def putValue(self, value, encoding = None):
if not encoding is None:
self.putField("valueencoded", encoding)
self.putField("value", value)
def putStringValue(self, value):
str = encodeString(value)
self.putCommaIfNeeded()
self.put('valueencoded="%d",value="%s"' % (7, str))
def putByteArrayValue(self, value):
str = encodeByteArray(value)
self.putCommaIfNeeded()
self.put('valueencoded="%d",value="%s"' % (6, str))
def putName(self, name):
self.putCommaIfNeeded()
self.put('name="%s"' % name)
def isExpanded(self, item):
#warn("IS EXPANDED: %s in %s" % (item.iname, self.expandedINames))
if item.iname is None:
......@@ -383,16 +441,16 @@ class Dumper:
def putIntItem(self, name, value):
self.beginHash()
self.putField("name", name)
self.putField("value", value)
self.putName(name)
self.putValue(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.putName(name)
self.putValue(value)
self.putType("bool")
self.putNumChild(0)
self.endHash()
......@@ -402,9 +460,9 @@ class Dumper:
self.safeoutput += self.output
self.output = ""
def dumpInnerValueHelper(self, item, field = "value"):
def dumpInnerValueHelper(self, item):
if isSimpleType(item.value.type):
self.safePutItemHelper(item, field)
self.safePutItemHelper(item)
def safePutItemHelper(self, item):
self.pushOutput()
......@@ -429,10 +487,10 @@ class Dumper:
#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")
self.putName(item.name)
self.putValue("<invalid>")
self.putType(str(item.value.type))
self.putNumChild(0)
#if self.isExpanded(item):
self.beginChildren()
self.endChildren()
......@@ -459,16 +517,16 @@ class Dumper:
self.putItemOrPointerHelper(
Item(item.value.dereference(), item.iname, None, None))
else:
self.putField("value", "(null)")
self.putField("numchild", "0")
self.putValue("(null)")
self.putNumChild(0)
else:
self.safePutItemHelper(item)
def putItemHelper(self, item, field = "value"):
def putItemHelper(self, item):
name = getattr(item, "name", None)
if not name is None:
self.putField("name", name)
self.putName(name)
self.putType(item.value.type)
# FIXME: Gui shows references stripped?
......@@ -494,16 +552,15 @@ class Dumper:
#warn(" DUMPERS: %s" % (strippedType in self.dumpers))
if isSimpleType(type):
self.putField(field, value)
if field == "value":
self.putNumChild(0)
self.putValue(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.putValue(value)
self.putNumChild(0)
......@@ -511,7 +568,7 @@ class Dumper:
isHandled = False
#warn("GENERIC POINTER: %s" % value)
if isNull(value):
self.putField(field, "0x0")
self.putValue("0x0")
self.putNumChild(0)
isHandled = True
......@@ -524,8 +581,8 @@ class Dumper:
for i in xrange(0, 10):
if p.dereference() == 0:
# Found terminating NUL
self.putField("%sencoded" % field, "6")
self.put(',%s="' % field)
self.putField("valueencoded", "6")
self.put(',value="')
p = value
for j in xrange(0, i):
self.put('%02x' % int(p.dereference()))
......@@ -539,11 +596,17 @@ class Dumper:
if not isHandled:
# Generic pointer type.
#warn("GENERIC POINTER: %s" % value)
self.putField(field, str(value.address))
if self.isExpanded(item):
#warn("GENERIC POINTER: %s" % item.value.type.target())
self.put(',')
# Temporary change to target type.
self.childTypes.append(
stripClassTag(str(item.value.type.target())))
self.putItemOrPointerHelper(
Item(item.value.dereference(), item.iname, None, None))
self.childTypes.pop()
else:
self.putValue(str(value.address))
self.putNumChild(1)
else:
......@@ -556,7 +619,7 @@ class Dumper:
#fields = value.type.fields()
fields = value.type.strip_typedefs().fields()
self.putField("value", "{...}")
self.putValue("{...}")
if False:
numfields = 0
......@@ -607,9 +670,8 @@ class Dumper:
child.name = "<anon>"
self.beginHash()
#d.putField("iname", child.iname)
#d.putField("name", child.name)
#d.putName(child.name)
#d.putType(child.value.type)
self.safePutItemHelper(child)
self.endHash()
self.endChildren()
......@@ -8,34 +8,16 @@
#######################################################################
def qqDumpQByteArray(d, item):
#struct Data
# QBasicAtomicInt ref;
# int alloc, size;
# char *data;
# char array[1];
d.putByteArrayValue(item.value)
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 = qmin(size, 1000)
d.putNumChild(n)
d.putNumChild(size)
if d.isExpanded(item):
n = qmin(size, 1000)
innerType = gdb.lookup_type("char")
data = d_ptr['data']
d.beginChildren(n, innerType)
p = gdb.Value(data.cast(innerType.pointer()))
for i in xrange(0, n):
......@@ -49,7 +31,7 @@ def qqDumpQByteArray(d, item):
def qqDumpQChar(d, item):
ucs = int(item.value["ucs"])
c = select(curses.ascii.isprint(ucs), ucs, '?')
d.putField("value", "'%c' (%d)" % (c, ucs))
d.putValue("'%c' (%d)" % (c, ucs))
d.putNumChild(0)
......@@ -64,29 +46,25 @@ def qqDumpQAbstractItem(d, item):
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)
d.putStringValue(call(m, "data(mi, Qt::DisplayRole).toString()"))
d.putNumChild(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))
d.putName("[%s,%s]" % (row, column))
rr = call(m, "rowCount(child)")
cc = call(m, "columnCount(child)")
d.putField("numchild", rr * cc)
d.putField("valueencoded", "6")
d.putNumChild(rr * cc)
d.putField("value",
call(m, "data(child, Qt::DisplayRole).toString())"))
call(m, "data(child, Qt::DisplayRole).toString())"), 6)
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.putName("DisplayRole")
#d.putNumChild(0)
#d.putValue(m->data(mi, Qt::DisplayRole).toString(), 2)
#d.putField("type", ns + "QString")
#d.endHash()
d.endChildren()
......@@ -100,37 +78,33 @@ def qqDumpQAbstractItemModel(d, item):
if columnCount < 0:
return
d.putField("value", "(%s,%s)" % (rowCount, columnCount))
d.putField("numchild", "1")
d.putValue("(%s,%s)" % (rowCount, columnCount))
d.putNumChild(1)
if d.isExpanded(item):
d.beginChildren(1)
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.putNumChild(1)
d.putName(d.ns + "QObject")
d.putValue(call(item.value, "objectName()"), 2)
d.putType(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.putName("[%s,%s]" % (row, column))
d.putValue("m.data(mi, Qt::DisplayRole).toString()", 6)
#d.putNumChild((m.hasChildren(mi) ? 1 : 0)
d.putNumChild(1) #m.rowCount(mi) * m.columnCount(mi))
d.putType(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")
d.putStringValue(call(item.value, "toString(%sQt::TextDate)" % d.ns))
d.putNumChild(3)
if d.isExpanded(item):
d.beginChildren(8)
d.putCallItem("isNull", item, "isNull()")
......@@ -151,10 +125,8 @@ def qqDumpQDateTime(d, item):
def qqDumpQDir(d, item):
path = call(item.value, "path()")
d.putField("valueencoded", "7")
d.putField("value", encodeString(path))
d.putField("numchild", "2")
d.putStringValue(call(item.value, "path()"))
d.putNumChild(2)
if d.isExpanded(item):
d.beginChildren(2)
d.putCallItem("absolutePath", item, "absolutePath()")
......@@ -163,10 +135,8 @@ def qqDumpQDir(d, item):
def qqDumpQFile(d, item):
fileName = call(item.value, "fileName()")
d.putField("valueencoded", "7")
d.putField("value", encodeString(fileName))
d.putField("numchild", "2")
d.putStringValue(call(item.value, "fileName()"))
d.putNumChild(2)
if d.isExpanded(item):
d.beginChildren(2)
d.putCallItem("fileName", item, "fileName()")
......@@ -175,10 +145,8 @@ def qqDumpQFile(d, item):
def qqDumpQFileInfo(d, item):
filePath = call(item.value, "filePath()")
d.putField("valueencoded", "7")
d.putField("value", encodeString(filePath))
d.putField("numchild", "3")
d.putStringValue(call(item.value, "filePath()"))
d.putNumChild(3)
if d.isExpanded(item):
d.beginChildren(10, gdb.lookup_type(d.ns + "QString"))
d.putCallItem("absolutePath", item, "absolutePath()")
......@@ -205,10 +173,10 @@ def qqDumpQFileInfo(d, item):
#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)
d.putName("permissions")
d.putValue(" ")
d.putType(d.ns + "QFile::Permissions")
d.putNumChild(10)
if d.isExpandedIName(item.iname + ".permissions"):
d.beginChildren(10)
d.putBoolItem("ReadOwner", perms & 0x4000)
......@@ -251,7 +219,7 @@ def qqDumpQFlags(d, item):
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.putValue("%s (%s)" % (i.cast(enumType), i))
d.putNumChild(0)
......@@ -298,7 +266,7 @@ def qqDumpQHash(d, item):
check(d_ptr["ref"]["_q_value"] > 0)
d.putItemCount(n)
d.putField("numchild", n)
d.putNumChild(n)
if d.isExpanded(item):
if n > 1000:
n = 1000
......@@ -316,7 +284,7 @@ def qqDumpQHash(d, item):
key = it["key"]
value = it["value"]
if isSimpleKey and isSimpleValue:
d.putField("name", key)
d.putName(key)
d.putItemHelper(Item(value, item.iname, i, None))
d.putType(valueType)
else:
......@@ -333,19 +301,19 @@ def qqDumpQHashNode(d, item):
value = item.value["value"]
if isSimpleType(valueType):
d.dumpInnerValueHelper(Item(value))
d.safePutItemHelper(Item(value))
else:
d.putField("value", " ")
d.putValue(" ")
d.putField("numchild", 2)
d.putNumChild(2)
if d.isExpanded(item):
d.beginChildren()
d.beginHash()
d.putField("name", "key")
d.putName("key")
d.putItemHelper(Item(key, None, None, None))
d.endHash()
d.beginHash()
d.putField("name", "value")
d.putName("value")
d.putItemHelper(Item(value, None, None, None))
d.endHash()
d.endChildren()
......@@ -374,7 +342,7 @@ def qqDumpQList(d, item):
checkPointerRange(p, qmin(n, 100))
d.putItemCount(n)
d.putField("numchild", n)
d.putNumChild(n)
if d.isExpanded(item):
# about 0.5s / 1000 items
if n > 2000:
......@@ -399,7 +367,7 @@ def qqDumpQList(d, item):
if innerTypeIsPointer:
if isNull(p.dereference()):
d.beginHash()
d.putField("value", "(null)")
d.putValue("(null)")
d.putNumChild(0)
d.putType(p.dereference().type)
d.endHash()
......@@ -424,17 +392,16 @@ def qqDumpQImage(d, item):
check(0 <= painters and painters < 1000)
d_ptr = item.value["d"]
if isNull(d_ptr):
d.putField("value", "(null)")
d.putValue("(null)")
else:
check(d_ptr["ref"]["_q_value"] > 0)
d.putField("value", "(%dx%d)" % (d_ptr["width"], d_ptr["height"]))
d.putField("numchild", "0")
d.putValue("(%dx%d)" % (d_ptr["width"], d_ptr["height"]))
d.putNumChild(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.putName("data")
# d.putType(d.ns + "QImageData")
# d.endHash()
# d.endChildren()
......@@ -443,16 +410,15 @@ 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")
# d.putType(d.ns + "QImageData")
# d.putNumChild(0)
# #if 1
# d.putField("value", "<hover here>")
# d.putValue("<hover here>")
# d.putField("valuetooltipencoded", "1")
# d.putField("valuetooltipsize", ba.size())
# d.putField("valuetooltip", ba)
# #else
# d.putField("valueencoded", "1")
# d.putField("value", ba)
# d.putValue(ba, 1)
# #endif
......@@ -465,7 +431,7 @@ def qqDumpQLinkedList(d, item):
check(d_ptr["ref"]["_q_value"] > 0)
d.putItemCount(n)
d.putField("numchild", n)
d.putNumChild(n)
if d.isExpanded(item):
innerType = item.value.type.template_argument(0)
......@@ -482,10 +448,8 @@ def qqDumpQLinkedList(d, item):
def qqDumpQLocale(d, item):
name = call(item.value, "name()")
d.putField("valueencoded", "7")
d.putField("value", encodeString(name))
d.putField("numchild", "8")
d.putStringValue(call(item.value, "name()"))
d.putNumChild(8)
if d.isExpanded(item):
d.beginChildren(1, gdb.lookup_type(d.ns + "QChar"), 0)
d.putCallItem("country", item, "country()")
......@@ -506,16 +470,16 @@ def qqDumpQLocale(d, item):
def qqDumpQMapNode(d, item):
d.putField("value", " ")
d.putField("numchild", 2)
d.putValue(" ")
d.putNumChild(2)
if d.isExpanded(item):
d.beginChildren(2)
d.beginHash()
d.putField("name", "key")
d.putName("key")
d.putItemHelper(Item(item.value["key"], item.iname, "name", None))
d.endHash()
d.beginHash()
d.putField("name", "value")
d.putName("value")
d.putItemHelper(Item(item.value["value"], item.iname, "value", None))
d.endHash()
d.endChildren()
......@@ -529,7 +493,7 @@ def qqDumpQMap(d, item):
check(d_ptr["ref"]["_q_value"] > 0)
d.putItemCount(n)
d.putField("numchild", n)
d.putNumChild(n)
if d.isExpanded(item):
if n > 1000:
n = 1000
......@@ -561,12 +525,9 @@ def qqDumpQMap(d, item):
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.putName(key)
d.putItemHelper(Item(value, item.iname, i, None))
else:
d.putItemHelper(Item(node, item.iname, i, None))
......@@ -585,24 +546,24 @@ def qqDumpQModelIndex(d, item):
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)
d.putValue("(%s, %s)" % (r, c))
d.putNumChild(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.putName("model")
d.putValue(m)
d.putType(d.ns + "QAbstractItemModel*")
d.putNumChild(1)
d.endHash()
d.endChildren()
else:
d.putField("value", "(invalid)")
d.putField("numchild", 0)
d.putValue("(invalid)")
d.putNumChild(0)
def extractCString(table, offset):
......@@ -637,9 +598,8 @@ def qqDumpQObject(d, item):
#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))
#d.putValue("")
d.putStringValue(objectName)
#QSignalMapper::staticMetaObject
#check(d_ptr["ref"]["_q_value"] > 0)
d.putNumChild(4)
......@@ -654,10 +614,10 @@ def qqDumpQObject(d, item):
d.beginHash()
propertyCount = metaData[6]
propertyData = metaData[7]
d.putField("name", "properties")
d.putName("properties")
d.putItemCount(propertyCount)
d.putField("type", "")
d.putField("numchild", propertyCount)
d.putType(" ")
d.putNumChild(propertyCount)
if d.isExpandedIName(item.iname + ".properties"):
d.beginChildren()
for property in xrange(0, propertyCount):
......@@ -665,7 +625,7 @@ def qqDumpQObject(d, item):
offset = propertyData + 3 * property
propertyName = extractCString(metaStringData, metaData[offset])
propertyType = extractCString(metaStringData, metaData[offset + 1])
d.putField("name", propertyName)
d.putName(propertyName)
#flags = metaData[offset + 2]
#warn("FLAGS: %s " % flags)
warn("PROPERTY TYPE: %s " % propertyType)
......@@ -679,12 +639,12 @@ def qqDumpQObject(d, item):
warn("TYPE: %s" % value.type)
if True and propertyType == "QString":
# FIXME: re-use parts of QVariant dumper
#d.putField("type", d.ns + "QString")
#d.putType(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")
#d.putNumChild(0)
else:
iname = "%s.properties.%s" % (item.iname, propertyName)
d.putItemHelper(Item(value, iname, propertyName))
......@@ -695,10 +655,10 @@ def qqDumpQObject(d, item):
# connections
d.beginHash()
connectionCount = 0
d.putField("name", "connections")
d.putName("connections")
d.putItemCount(connectionCount)
d.putField("type", "")
d.putField("numchild", connectionCount)
d.putType(" ")
d.putNumChild(connectionCount)
if connectionCount:
d.putField("childtype", "")
d.putField("childnumchild", "0")
......@@ -711,8 +671,8 @@ def qqDumpQObject(d, item):
for connection in xrange(0, connectionCount):
d.beginHash()
d.putField("name", "connection %d" % connection)
d.putField("value", "")
d.putName("connection %d" % connection)
d.putValue("")
d.endHash()
d.endChildren()
d.endHash()
......@@ -720,10 +680,10 @@ def qqDumpQObject(d, item):
# signals
signalCount = metaData[13]
d.beginHash()
d.putField("name", "signals")
d.putName("signals")
d.putItemCount(signalCount)
d.putField("type", "")
d.putField("numchild", signalCount)
d.putType(" ")
d.putNumChild(signalCount)
if signalCount:
# FIXME: empty type does not work for childtype
#d.putField("childtype", ".")
......@@ -733,9 +693,9 @@ def qqDumpQObject(d, item):
for signal in xrange(0, signalCount):
d.beginHash()
offset = metaData[14 + 5 * signal]
d.putField("name", "signal %d" % signal)