Commit 26fa769b authored by hjk's avatar hjk Committed by hjk

Debugger: Add dumper for QMeta{Enum,Method,Property}

Task-number: QTCREATORBUG-16593
Change-Id: Iaa710660d8ef69459596f93831cf8467913f0468
Reviewed-by: Alexandru Croitor's avatarAlexandru Croitor <alexandru.croitor@qt.io>
parent ac1c04b6
...@@ -737,12 +737,16 @@ class DumperBase: ...@@ -737,12 +737,16 @@ class DumperBase:
with Children(self): with Children(self):
self.putFields(value, dumpBase) self.putFields(value, dumpBase)
def putMembersItem(self, value, sortorder = 10):
with SubItem(self, "[members]"):
self.put('sortgroup="%s"' % sortorder)
self.putPlainChildren(value)
def isMapCompact(self, keyType, valueType): def isMapCompact(self, keyType, valueType):
if self.currentItemFormat() == CompactMapFormat: if self.currentItemFormat() == CompactMapFormat:
return True return True
return self.isSimpleType(keyType) and self.isSimpleType(valueType) return self.isSimpleType(keyType) and self.isSimpleType(valueType)
def check(self, exp): def check(self, exp):
if not exp: if not exp:
raise RuntimeError("Check failed") raise RuntimeError("Check failed")
...@@ -923,13 +927,6 @@ class DumperBase: ...@@ -923,13 +927,6 @@ class DumperBase:
# self.expandedINames, self.currentIName in self.expandedINames)) # self.expandedINames, self.currentIName in self.expandedINames))
return self.currentIName in self.expandedINames return self.currentIName in self.expandedINames
def putPlainChildren(self, value):
self.putEmptyValue(-99)
self.putNumChild(1)
if self.currentIName in self.expandedINames:
with Children(self):
self.putFields(value)
def putCStyleArray(self, value): def putCStyleArray(self, value):
arrayType = value.type.unqualified() arrayType = value.type.unqualified()
innerType = value[0].type innerType = value[0].type
...@@ -1325,50 +1322,6 @@ class DumperBase: ...@@ -1325,50 +1322,6 @@ class DumperBase:
self.knownStaticMetaObjects[typeName] = result self.knownStaticMetaObjects[typeName] = result
return result return result
def staticQObjectMetaData(self, metaobject, offset1, offset2, step):
items = []
dd = metaobject["d"]
data = self.extractPointer(dd["data"])
sd = self.extractPointer(dd["stringdata"])
metaObjectVersion = self.extractInt(data)
itemCount = self.extractInt(data + offset1)
itemData = -offset2 if offset2 < 0 else self.extractInt(data + offset2)
if metaObjectVersion >= 7: # Qt 5.
byteArrayDataType = self.lookupType(self.qtNamespace() + "QByteArrayData")
byteArrayDataSize = byteArrayDataType.sizeof
for i in range(itemCount):
x = data + (itemData + step * i) * 4
literal = sd + self.extractInt(x) * byteArrayDataSize
ldata, lsize, lalloc = self.byteArrayDataHelper(literal)
items.append(self.extractBlob(ldata, lsize).toString())
else: # Qt 4.
for i in range(itemCount):
x = data + (itemData + step * i) * 4
ldata = sd + self.extractInt(x)
items.append(self.extractCString(ldata).decode("utf8"))
return items
def staticQObjectPropertyCount(self, metaobject):
return self.extractInt(self.extractPointer(metaobject["d"]["data"]) + 24)
def staticQObjectPropertyNames(self, metaobject):
return self.staticQObjectMetaData(metaobject, 24, 28, 3)
def staticQObjectMethodCount(self, metaobject):
return self.extractInt(self.extractPointer(metaobject["d"]["data"]) + 16)
def staticQObjectMethodNames(self, metaobject):
return self.staticQObjectMetaData(metaobject, 16, 20, 5)
def staticQObjectSignalCount(self, metaobject):
return self.extractInt(self.extractPointer(metaobject["d"]["data"]) + 52)
def staticQObjectSignalNames(self, metaobject):
return self.staticQObjectMetaData(metaobject, 52, -14, 5)
def extractCString(self, addr): def extractCString(self, addr):
result = bytearray() result = bytearray()
while True: while True:
...@@ -1406,6 +1359,21 @@ class DumperBase: ...@@ -1406,6 +1359,21 @@ class DumperBase:
for i in range(size): for i in range(size):
yield self.createValue(data + i * innerSize, innerType) yield self.createValue(data + i * innerSize, innerType)
def putStructGuts(self, value):
self.putEmptyValue()
if self.showQObjectNames:
staticMetaObject = self.extractStaticMetaObject(value.type)
if staticMetaObject:
self.context = value
self.putQObjectNameValue(value)
if self.isExpanded():
self.put('sortable="1"')
with Children(self, 1, childType=None):
self.putFields(value)
if not self.showQObjectNames:
staticMetaObject = self.extractStaticMetaObject(value.type)
if staticMetaObject:
self.putQObjectGuts(value, staticMetaObject)
# This is called is when a QObject derived class is expanded # This is called is when a QObject derived class is expanded
def putQObjectGuts(self, qobject, smo): def putQObjectGuts(self, qobject, smo):
...@@ -1414,9 +1382,14 @@ class DumperBase: ...@@ -1414,9 +1382,14 @@ class DumperBase:
# Parent and children. # Parent and children.
try: try:
if qobject:
d_ptr = qobject["d_ptr"]["d"] d_ptr = qobject["d_ptr"]["d"]
self.putSubItem("[parent]", d_ptr["parent"]) with SubItem(self, "[parent]"):
self.putSubItem("[children]", d_ptr["children"]) self.putItem(d_ptr["parent"])
self.put('sortgroup="9"')
with SubItem(self, "[children]"):
self.putItem(d_ptr["children"])
self.put('sortgroup="1"')
except: except:
pass pass
...@@ -1424,93 +1397,152 @@ class DumperBase: ...@@ -1424,93 +1397,152 @@ class DumperBase:
isQt5 = self.qtVersion() >= 0x50000 isQt5 = self.qtVersion() >= 0x50000
extraDataOffset = 5 * ptrSize + 8 if isQt5 else 6 * ptrSize + 8 extraDataOffset = 5 * ptrSize + 8 if isQt5 else 6 * ptrSize + 8
extraData = self.extractPointer(dd + extraDataOffset) extraData = self.extractPointer(dd + extraDataOffset)
self.putQObjectGutsHelper(extraData, dd, smo) self.putQObjectGutsHelper(qobject, extraData, -1, smo, "QObject")
def putQObjectGutsHelper(self, extraData, dd, smo):
intSize = self.intSize()
ptrSize = self.ptrSize()
data = smo["d"]["data"]
#warn("DATA: %s" % data)
def metaString(offset):
ddata = self.extractPointer(data)
sd = self.extractPointer(smo["d"]["stringdata"])
metaObjectVersion = self.extractInt(ddata) def metaString(self, metaObject, index, revision = 7):
if metaObjectVersion >= 7: # Qt 5. sd = self.extractPointer(metaObject["d"]["stringdata"])
byteArrayDataType = self.lookupType(self.qtNamespace() + "QByteArrayData") if revision >= 7: # Qt 5.
byteArrayDataType = self.lookupQtType("QByteArrayData")
byteArrayDataSize = byteArrayDataType.sizeof byteArrayDataSize = byteArrayDataType.sizeof
literal = sd + offset * byteArrayDataSize literal = toInteger(sd) + toInteger(index) * byteArrayDataSize
ldata, lsize, lalloc = self.byteArrayDataHelper(literal) ldata, lsize, lalloc = self.byteArrayDataHelper(literal)
try:
return self.extractBlob(ldata, lsize).toString() return self.extractBlob(ldata, lsize).toString()
except:
return "<unavailable>"
else: # Qt 4. else: # Qt 4.
ldata = sd + offset ldata = sd + index
return self.extractCString(ldata).decode("utf8") return self.extractCString(ldata).decode("utf8")
def putQMetaStuff(self, value, origType):
metaObject = value["mobj"]
if not metaObject:
self.putEmptyValue()
if self.isExpanded():
with Children(self):
self.putFields(value)
else:
handle = toInteger(value["handle"])
index = toInteger(metaObject["d"]["data"][handle])
name = self.metaString(metaObject.dereference(), index)
self.putValue(name)
self.putNumChild(1)
if self.isExpanded():
with Children(self):
self.putFields(value)
self.putQObjectGutsHelper(0, 0, handle, metaObject, origType)
def putQObjectGutsHelper(self, qobject, extraData, handle, metaObject, origType):
intSize = self.intSize()
ptrSize = self.ptrSize()
data = metaObject["d"]["data"]
def walker(base): def walker(base):
ptr = toInteger(base) ptr = toInteger(base)
while True: while True:
yield self.extractInt(ptr) yield self.extractInt(ptr)
ptr += intSize ptr += intSize
def put1(name, p): def putt(name, value, typeName = ' '):
x = p.next()
with SubItem(self, name): with SubItem(self, name):
self.putValue(x) self.putValue(value)
self.putType("uint") self.putType(typeName)
self.putNumChild(0) self.putNumChild(0)
return x
def put2(name, p): def superData(mo):
xy = (p.next(), p.next()) return mo['d']['superdata']
with SubItem(self, name):
self.putValue("%s %s" % xy)
self.putType("uint")
self.putNumChild(0)
return xy[0]
def putt(name, value): isQMetaObject = origType == "QMetaObject"
with SubItem(self, name): isQObject = origType == "QObject"
self.putValue(value)
self.putType(" ") p = walker(data)
revision = p.next()
classname = p.next()
classinfo = p.next()
classinfo2 = p.next()
methodCount = p.next()
methods = p.next()
propertyCount = p.next()
properties = p.next()
enumCount = p.next()
enums = p.next()
constructorCount = p.next()
constructors = p.next()
flags = p.next()
signalCount = p.next()
globalOffset = 0
superdata = superData(metaObject)
while toInteger(superdata):
sdata = superdata["d"]["data"]
p = walker(sdata)
revision = p.next()
classname = p.next()
classinfo = p.next()
classinfo2 = p.next()
methodCount = p.next()
globalOffset += methodCount
superdata = superData(superdata)
largestStringIndex = -1
for i in range(methodCount):
t = (p.next(), p.next(), p.next(), p.next(), p.next())
if largestStringIndex < t[0]:
largestStringIndex = t[0]
if isQMetaObject:
with SubItem(self, "[strings]"):
self.put('sortgroup="2"')
self.putSpecialValue("minimumitemcount", largestStringIndex + 1)
self.putNumChild(1)
if self.isExpanded():
with Children(self, largestStringIndex + 1):
for i in self.childRange():
with SubItem(self, i):
self.putValue(self.hexencode(self.metaString(metaObject, i)), "latin1")
self.putNumChild(0) self.putNumChild(0)
if isQMetaObject:
with SubItem(self, "[raw]"): with SubItem(self, "[raw]"):
self.put('sortgroup="1"')
p = walker(data)
self.putEmptyValue() self.putEmptyValue()
self.putNumChild(1) self.putNumChild(1)
if self.isExpanded(): if self.isExpanded():
self.put('sortable="0"')
p = walker(data)
with Children(self): with Children(self):
put1("revision", p) putt("revision", revision)
put1("classname", p) putt("classname", classname)
put2("classinfo", p) putt("classinfo", classinfo)
methodCount = put2("methods", p) putt("methods", "%d %d" % (methodCount, methods))
put2("properties", p) putt("properties", "%d %d" % (propertyCount, properties))
put2("enums/sets", p) putt("enums/sets", "%d %d" % (enumCount, enums))
put2("constructors", p) putt("constructors", "%d %d" % (constructorCount, constructors))
put1("flags", p) putt("flags", flags)
signalCount = put1("signalCount", p) putt("signalCount", signalCount)
p = walker(toInteger(data) + 14 * 4)
for i in range(methodCount):
t = (p.next(), p.next(), p.next(), p.next(), p.next())
putt("method %d" % i, "%s %s %s %s %s" % t)
if extraData: putt("[extraData]", "0x%x" % toInteger(extraData), "void *")
with SubItem(self, "[extraData]"):
self.putValue("0x%x" % toInteger(extraData))
self.putType("void *")
self.putNumChild(0)
if isQMetaObject or isQObject:
with SubItem(self, "[properties]"): with SubItem(self, "[properties]"):
propertyCount = 0 self.put('sortgroup="5"')
usesVector = self.qtVersion() >= 0x50700 self.putItemCount(propertyCount)
if self.isExpanded(): if self.isExpanded():
propertyNames = self.staticQObjectPropertyNames(smo) usesVector = self.qtVersion() >= 0x50700
propertyCount = len(propertyNames) # Doesn't include dynamic properties.
with Children(self): with Children(self):
# Static properties. # Static properties.
p = walker(toInteger(data) + properties * 4)
for i in range(propertyCount): for i in range(propertyCount):
name = propertyNames[i] t = (p.next(), p.next(), p.next())
self.putCallItem(str(name), qobject, "property", '"' + name + '"') name = self.metaString(metaObject, t[0])
if qobject:
self.putCallItem(name, qobject, "property", '"' + name + '"')
else:
putt(name, ' ')
# Dynamic properties. # Dynamic properties.
if extraData: if extraData:
...@@ -1527,68 +1559,93 @@ class DumperBase: ...@@ -1527,68 +1559,93 @@ class DumperBase:
self.put('keyencoded="latin1",') self.put('keyencoded="latin1",')
self.putItem(v) self.putItem(v)
propertyCount += 1 propertyCount += 1
self.putItemCount(propertyCount)
else: else:
# We need a handle to [x] for the user to expand the item # We need a handle to [x] for the user to expand the item
# before we know whether there are actual children. Counting # before we know whether there are actual children. Counting
# them is too expensive. # them is too expensive.
self.putNumChild(1) self.putNumChild(1)
self.putSpecialValue("minimumitemcount", 0) self.putSpecialValue("minimumitemcount", propertyCount)
#with SubItem(self, "[methods]"):
# methodCount = self.staticQObjectMethodCount(smo)
# self.putItemCount(methodCount)
# if self.isExpanded():
# methodNames = self.staticQObjectMethodNames(smo)
# with Children(self):
# for i in range(methodCount):
# k = methodNames[i]
# with SubItem(self, k):
# self.putEmptyValue()
#
if isQMetaObject or isQObject:
with SubItem(self, "[methods]"): with SubItem(self, "[methods]"):
methodCount = self.staticQObjectMethodCount(smo) self.put('sortgroup="3"')
self.putItemCount(methodCount) self.putItemCount(methodCount)
if self.isExpanded(): if self.isExpanded():
with Children(self): with Children(self):
p = walker(toInteger(data) + 14 * 4) p = walker(toInteger(data) + 14 * 4)
for i in range(methodCount): for i in range(methodCount):
t = (p.next(), p.next(), p.next(), p.next(), p.next()) t = (p.next(), p.next(), p.next(), p.next(), p.next())
name = metaString(t[0]) name = self.metaString(metaObject, t[0])
with SubItem(self, "[%s]" % i): with SubItem(self, i):
self.putValue(name) self.putValue(name)
self.putType(" ") self.putType(" ")
self.putNumChild(1) self.putNumChild(1)
with Children(self): isSignal = False
putt("name", name)
putt("nameindex", t[0])
flags = t[4] flags = t[4]
if flags == 0x06: if flags == 0x06:
putt("type", "signal") typ = "signal"
isSignal = True
elif flags == 0x0a: elif flags == 0x0a:
putt("type", "slot") typ = "slot"
elif flags == 0x0a: elif flags == 0x0a:
putt("type", "invokable") typ = "invokable"
putt("argc", t[1]) else:
putt("parameter", t[2]) typ = "<unknown>"
putt("tag", t[3]) with Children(self):
putt("flags", t[4]) putt("[nameindex]", t[0])
putt("[type]", typ)
putt("[argc]", t[1])
with SubItem(self, "[signals]"): putt("[parameter]", t[2])
signalCount = self.staticQObjectSignalCount(smo) putt("[tag]", t[3])
self.putItemCount(signalCount) putt("[flags]", t[4])
putt("[localindex]", str(i))
putt("[globalindex]", str(globalOffset + i))
if isQObject:
self.putSubItem("[metaObject]", metaObject)
if isQObject:
with SubItem(self, "d"):
self.put('sortgroup="15"')
self.putItem(qobject["d_ptr"]["d"])
if isQMetaObject:
with SubItem(self, "[superdata]"):
self.put('sortgroup="12"')
superdata = superData(metaObject)
self.putValue("0x%x" % superdata)
if toInteger(superdata):
self.putNumChild(1)
if self.isExpanded(): if self.isExpanded():
signalNames = self.staticQObjectSignalNames(smo)
signalCount = len(signalNames)
with Children(self): with Children(self):
for i in range(signalCount): self.putSubItem('*', superdata)
k = signalNames[i] else:
with SubItem(self, k): self.putNumChild(0)
self.putEmptyValue() self.putType(superdata.type)
if dd:
self.putQObjectConnections(dd) if handle >= 0:
localIndex = (handle - methods) / 5
with SubItem(self, "[localindex]"):
self.put('sortgroup="12"')
self.putValue(localIndex)
with SubItem(self, "[globalindex]"):
self.put('sortgroup="11"')
self.putValue(globalOffset + localIndex)
#with SubItem(self, "[signals]"):
# self.putItemCount(signalCount)
# signalNames = metaData(52, -14, 5)
# warn("NAMES: %s" % signalNames)
# if self.isExpanded():
# with Children(self):
# putt("A", "b")
# for i in range(signalCount):
# k = signalNames[i]
# with SubItem(self, k):
# self.putEmptyValue()
# if dd:
# self.putQObjectConnections(dd)
def putQObjectConnections(self, dd): def putQObjectConnections(self, dd):
with SubItem(self, "[connections]"): with SubItem(self, "[connections]"):
......
...@@ -1136,23 +1136,10 @@ class Dumper(DumperBase): ...@@ -1136,23 +1136,10 @@ class Dumper(DumperBase):
#warn("INAME: %s " % self.currentIName) #warn("INAME: %s " % self.currentIName)
#warn("INAMES: %s " % self.expandedINames) #warn("INAMES: %s " % self.expandedINames)
#warn("EXPANDED: %s " % (self.currentIName in self.expandedINames)) #warn("EXPANDED: %s " % (self.currentIName in self.expandedINames))
if self.showQObjectNames:
staticMetaObject = self.extractStaticMetaObject(value.type)
if staticMetaObject:
self.putQObjectNameValue(value)
self.putType(typeName) self.putType(typeName)
self.putEmptyValue()
self.putNumChild(len(typeobj.fields())) self.putNumChild(len(typeobj.fields()))
self.putStructGuts(value)
if self.currentIName in self.expandedINames:
innerType = None
self.put('sortable="1"')
with Children(self, 1, childType=innerType):
self.putFields(value)
if not self.showQObjectNames:
staticMetaObject = self.extractStaticMetaObject(value.type)
if staticMetaObject:
self.putQObjectGuts(value, staticMetaObject)
def toBlob(self, value): def toBlob(self, value):
size = toInteger(value.type.sizeof) size = toInteger(value.type.sizeof)
...@@ -1251,7 +1238,7 @@ class Dumper(DumperBase): ...@@ -1251,7 +1238,7 @@ class Dumper(DumperBase):
# int (**)(void) # int (**)(void)
n = 100 n = 100
self.putType(" ") self.putType(" ")
self.put('sortgroup="1"') self.put('sortgroup="20"')
self.putValue(value[field.name]) self.putValue(value[field.name])
self.putNumChild(n) self.putNumChild(n)
if self.isExpanded(): if self.isExpanded():
...@@ -1275,7 +1262,7 @@ class Dumper(DumperBase): ...@@ -1275,7 +1262,7 @@ class Dumper(DumperBase):
baseNumber += 1 baseNumber += 1
with UnnamedSubItem(self, "@%d" % baseNumber): with UnnamedSubItem(self, "@%d" % baseNumber):
baseValue = value.cast(field.type) baseValue = value.cast(field.type)
self.put('sortgroup="2"') self.put('sortgroup="30"')
self.putBaseClassName(field.name) self.putBaseClassName(field.name)
self.putAddress(baseValue.address) self.putAddress(baseValue.address)
self.putItem(baseValue, False) self.putItem(baseValue, False)
......
...@@ -1084,27 +1084,14 @@ class Dumper(DumperBase): ...@@ -1084,27 +1084,14 @@ class Dumper(DumperBase):
self.putValue(v) self.putValue(v)
self.putType(typeName) self.putType(typeName)
self.putEmptyValue()
self.putNumChild(numchild) self.putNumChild(numchild)
if self.showQObjectNames: self.putStructGuts(value)
staticMetaObject = self.extractStaticMetaObject(value.GetType())
if staticMetaObject:
self.context = value
self.putQObjectNameValue(value)