Debugger: Remove use of native values in dumper.py

Lowers the barrier for other debugger backends.

Change-Id: I09e0ad09548b6b4220175245cc0d845ac5aa29d0
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
hjk
2016-09-26 14:29:16 +02:00
committed by hjk
parent b13094d0c8
commit 5efa84830b
7 changed files with 249 additions and 431 deletions

View File

@@ -89,14 +89,18 @@ class Value:
class Type: class Type:
name() -> string # Full name of this type name() -> string # Full name of this type
bitsize() -> int # Size of type in bits bitsize() -> int # Size of type in bits
arrayType() -> bool # Is this an array? code() -> TypeCodeTypedef
pointerType() -> bool # Is this a pointer | TypeCodeStruct
referenceType() -> bool # ... | TypeCodeVoid
functionType() -> bool | TypeCodeIntegral
typedefedType() -> bool | TypeCodeFloat
enumType() -> bool | TypeCodeEnum
integralType() -> bool | TypeCodePointer
floatingPointType() -> bool | TypeCodeArray
| TypeCodeComplex
| TypeCodeReference
| TypeCodeFunction
| TypeCodeMemberPointer
unqualified() -> Type # Type without const/volatile unqualified() -> Type # Type without const/volatile
target() -> Type # Type dereferenced if it is a pointer type, element if array etc target() -> Type # Type dereferenced if it is a pointer type, element if array etc

View File

@@ -212,8 +212,7 @@ class Children:
return True return True
class PairedChildrenData: class PairedChildrenData:
def __init__(self, d, pairType, keyType, valueType, useKeyAndValue): def __init__(self, d, pairType, keyType, valueType):
self.useKeyAndValue = useKeyAndValue
self.pairType = pairType self.pairType = pairType
self.keyType = keyType self.keyType = keyType
self.valueType = valueType self.valueType = valueType
@@ -228,7 +227,9 @@ class PairedChildren(Children):
keyType = pairType[0].unqualified() keyType = pairType[0].unqualified()
if valueType is None: if valueType is None:
valueType = pairType[1] valueType = pairType[1]
d.pairData = PairedChildrenData(d, pairType, keyType, valueType, useKeyAndValue) d.pairData = PairedChildrenData(d, pairType, keyType, valueType)
d.pairData.kname = "key" if useKeyAndValue else "first"
d.pairData.vname = "value" if useKeyAndValue else "second"
Children.__init__(self, d, numChild, Children.__init__(self, d, numChild,
d.pairData.childType, d.pairData.childType,
@@ -671,6 +672,9 @@ class DumperBase:
def putIntItem(self, name, value): def putIntItem(self, name, value):
with SubItem(self, name): with SubItem(self, name):
if isinstance(value, self.Value):
self.putValue(value.display())
else:
self.putValue(value) self.putValue(value)
self.putType("int") self.putType("int")
self.putNumChild(0) self.putNumChild(0)
@@ -682,28 +686,23 @@ class DumperBase:
self.putNumChild(0) self.putNumChild(0)
def putPairItem(self, index, pair): def putPairItem(self, index, pair):
if isinstance(pair, tuple): (first, second) = pair if isinstance(pair, tuple) else pair.members()
(first, second) = pair
elif self.pairData.useKeyAndValue:
(first, second) = (pair["key"], pair["value"])
else:
(first, second) = (pair["first"], pair["second"])
with SubItem(self, index): with SubItem(self, index):
self.putNumChild(2)
(keystr, keyenc, valstr, valenc) = (None, None, None, None) (keystr, keyenc, valstr, valenc) = (None, None, None, None)
with Children(self): with Children(self):
with SubItem(self, "key"): with SubItem(self, self.pairData.kname):
self.putItem(first, True) self.putItem(first)
keystr = self.currentValue.value keystr = self.currentValue.value
keyenc = self.currentValue.encoding keyenc = self.currentValue.encoding
with SubItem(self, "value"): with SubItem(self, self.pairData.vname):
self.putItem(second, True) self.putItem(second)
valstr = self.currentValue.value valstr = self.currentValue.value
valenc = self.currentValue.encoding valenc = self.currentValue.encoding
if index is not None: if index is not None:
self.put('keyprefix="[%s] ",' % index) self.put('keyprefix="[%s] ",' % index)
self.put('keyencoded="%s",key="%s",' % (keyenc, keystr)) self.put('key="%s",' % keystr)
if keyenc is not None:
self.put('keyencoded="%s",' % keyenc)
self.putValue(valstr, valenc) self.putValue(valstr, valenc)
def putCallItem(self, name, rettype, value, func, *args): def putCallItem(self, name, rettype, value, func, *args):
@@ -713,7 +712,6 @@ class DumperBase:
except Exception as error: except Exception as error:
if self.passExceptions: if self.passExceptions:
raise error raise error
else:
children = [('error', error)] children = [('error', error)]
self.putSpecialValue("notcallable", children=children) self.putSpecialValue("notcallable", children=children)
else: else:
@@ -772,7 +770,7 @@ class DumperBase:
self.put('name="[%s]",' % field.name) self.put('name="[%s]",' % field.name)
self.put('sortgroup="%s"' % (1000 - field.baseIndex)) self.put('sortgroup="%s"' % (1000 - field.baseIndex))
self.putAddress(baseValue.address()) self.putAddress(baseValue.address())
self.putItem(baseValue, False) self.putItem(baseValue)
continue continue
with SubItem(self, field.name): with SubItem(self, field.name):
@@ -1004,9 +1002,8 @@ class DumperBase:
def putCStyleArray(self, value): def putCStyleArray(self, value):
arrayType = value.type.unqualified() arrayType = value.type.unqualified()
if self.isGdb and value.nativeValue is not None: innerType = arrayType.ltarget
innerType = self.fromNativeType(value.nativeValue[0].type) if innerType is None:
else:
innerType = value.type.target() innerType = value.type.target()
innerTypeName = innerType.unqualified().name innerTypeName = innerType.unqualified().name
address = value.address() address = value.address()
@@ -1332,22 +1329,22 @@ class DumperBase:
# warn("NO QOBJECT: %s" % value.type) # warn("NO QOBJECT: %s" % value.type)
pass pass
def couldBeQObject(self, objectPtr): def canBePointer(self, p):
def canBePointer(p):
if self.ptrSize() == 4: if self.ptrSize() == 4:
return p > 100000 and (p & 0x3 == 0) return p > 100000 and (p & 0x3 == 0)
else: else:
return p > 100000 and (p & 0x7 == 0) and (p < 0x7fffffffffff) return p > 100000 and (p & 0x7 == 0) and (p < 0x7fffffffffff)
def couldBeQObject(self, objectPtr):
try: try:
(vtablePtr, dd) = self.split('pp', objectPtr) (vtablePtr, dd) = self.split('pp', objectPtr)
except: except:
self.bump("nostruct-1") self.bump("nostruct-1")
return False return False
if not canBePointer(vtablePtr): if not self.canBePointer(vtablePtr):
self.bump("vtable") self.bump("vtable")
return False return False
if not canBePointer(dd): if not self.canBePointer(dd):
self.bump("d_d_ptr") self.bump("d_d_ptr")
return False return False
@@ -1358,7 +1355,7 @@ class DumperBase:
self.bump("nostruct-2") self.bump("nostruct-2")
return False return False
#warn("STRUCT DD: %s 0x%x" % (self.currentIName, qptr)) #warn("STRUCT DD: %s 0x%x" % (self.currentIName, qptr))
if not canBePointer(dvtablePtr): if not self.canBePointer(dvtablePtr):
self.bump("dvtable") self.bump("dvtable")
#warn("DVT: 0x%x" % dvtablePtr) #warn("DVT: 0x%x" % dvtablePtr)
return False return False
@@ -1367,11 +1364,11 @@ class DumperBase:
#warn("QPTR: 0x%x 0x%x" % (qptr, objectPtr)) #warn("QPTR: 0x%x 0x%x" % (qptr, objectPtr))
self.bump("q_ptr") self.bump("q_ptr")
return False return False
if parentPtr and not canBePointer(parentPtr): if parentPtr and not self.canBePointer(parentPtr):
#warn("PAREN") #warn("PAREN")
self.bump("parent") self.bump("parent")
return False return False
if not canBePointer(childrenDPtr): if not self.canBePointer(childrenDPtr):
#warn("CHILD") #warn("CHILD")
self.bump("children") self.bump("children")
return False return False
@@ -1380,7 +1377,7 @@ class DumperBase:
# self.bump("flags") # self.bump("flags")
# return False # return False
#warn("OK") #warn("OK")
#if dynMetaObjectPtr and not canBePointer(dynMetaObjectPtr): #if dynMetaObjectPtr and not self.canBePointer(dynMetaObjectPtr):
# self.bump("dynmo") # self.bump("dynmo")
# return False # return False
@@ -1926,13 +1923,13 @@ class DumperBase:
displayFormat = self.typeformats.get(needle, AutomaticFormat) displayFormat = self.typeformats.get(needle, AutomaticFormat)
return displayFormat return displayFormat
def putSubItem(self, component, value, tryDynamic=True): def putSubItem(self, component, value):
if not isinstance(value, self.Value): if not isinstance(value, self.Value):
error("WRONG VALUE TYPE IN putSubItem: %s" % type(value)) error("WRONG VALUE TYPE IN putSubItem: %s" % type(value))
if not isinstance(value.type, self.Type): if not isinstance(value.type, self.Type):
error("WRONG TYPE TYPE IN putSubItem: %s" % type(value.type)) error("WRONG TYPE TYPE IN putSubItem: %s" % type(value.type))
with SubItem(self, component): with SubItem(self, component):
self.putItem(value, tryDynamic) self.putItem(value)
def putArrayData(self, base, n, innerType, childNumChild = None, maxNumChild = 10000): def putArrayData(self, base, n, innerType, childNumChild = None, maxNumChild = 10000):
self.checkIntType(base) self.checkIntType(base)
@@ -2431,20 +2428,17 @@ class DumperBase:
return True return True
return False return False
def putItem(self, value, tryDynamic=True): def putItem(self, value):
#warn("ITEM: %s" % value.stringify()) #warn("ITEM: %s" % value.stringify())
typeobj = value.type #unqualified() typeobj = value.type #unqualified()
typeName = typeobj.name typeName = typeobj.name
tryDynamic &= self.useDynamicType
self.addToCache(typeobj) # Fill type cache self.addToCache(typeobj) # Fill type cache
if tryDynamic:
self.putAddress(value.address()) self.putAddress(value.address())
if not value.isInScope(): if not value.lIsInScope:
self.putSpecialValue("optimizedout") self.putSpecialValue("optimizedout")
#self.putValue("optimizedout: %s" % value.nativeValue)
#self.putType(typeobj) #self.putType(typeobj)
#self.putSpecialValue('outofscope') #self.putSpecialValue('outofscope')
self.putNumChild(0) self.putNumChild(0)
@@ -2500,49 +2494,12 @@ class DumperBase:
return return
if typeobj.code == TypeCodeReference: if typeobj.code == TypeCodeReference:
try:
# Try to recognize null references explicitly.
if value.address() is 0:
self.putSpecialValue("nullreference")
self.putNumChild(0)
self.putType(typeobj)
return
except:
pass
if self.isLldb: if self.isLldb:
targetType = value.type.target() item = value.cast(typeobj.target().pointer()).dereference()
item = value.cast(targetType.pointer()).dereference()
self.putItem(item)
self.putBetterType(value.type.name)
return
else: else:
if tryDynamic: item = value.cast(typeobj.target().unqualified())
try: self.putItem(item)
# Dynamic references are not supported by gdb, see self.putBetterType(typeobj.name)
# http://sourceware.org/bugzilla/show_bug.cgi?id=14077.
# Find the dynamic type manually using referenced_type.
val = value.referenced_value()
val = val.cast(val.dynamic_type)
self.putItem(val)
self.putBetterType("%s &" % typeobj)
return
except:
pass
try:
# FIXME: This throws "RuntimeError: Attempt to dereference a
# generic pointer." with MinGW's gcc 4.5 when it "identifies"
# a "QWidget &" as "void &" and with optimized out code.
self.putItem(value.cast(typeobj.target().unqualified()))
self.putBetterType("%s &" % self.currentType.value)
return
except Exception as error:
self.putSpecialValue("optimizedout")
#self.putValue("optimizedout: %s" % error)
self.putType(typeobj)
self.putNumChild(0)
return return
if typeobj.code == TypeCodeComplex: if typeobj.code == TypeCodeComplex:
@@ -2625,8 +2582,8 @@ class DumperBase:
self.type = None self.type = None
self.ldata = None self.ldata = None
self.laddress = None self.laddress = None
self.nativeValue = None
self.lIsInScope = True self.lIsInScope = True
self.ldisplay = None
def check(self): def check(self):
if self.laddress is not None and not self.dumper.isInt(self.laddress): if self.laddress is not None and not self.dumper.isInt(self.laddress):
@@ -2639,11 +2596,9 @@ class DumperBase:
return self.stringify() return self.stringify()
def stringify(self): def stringify(self):
self.check()
addr = "None" if self.laddress is None else ("0x%x" % self.laddress) addr = "None" if self.laddress is None else ("0x%x" % self.laddress)
return "Value(name='%s',type=%s,data=%s,address=%s,nativeValue=%s)" \ return "Value(name='%s',type=%s,data=%s,address=%s)" \
% (self.name, self.type.stringify(), self.dumper.hexencode(self.ldata), % (self.name, self.type.stringify(), self.dumper.hexencode(self.ldata), addr)
addr, self.nativeValue)
def display(self): def display(self):
if self.type.code == TypeCodeEnum: if self.type.code == TypeCodeEnum:
@@ -2651,21 +2606,14 @@ class DumperBase:
simple = self.value() simple = self.value()
if simple is not None: if simple is not None:
return str(simple) return str(simple)
if self.type.code == TypeCodeComplex: if self.ldisplay is not None:
if self.nativeValue is not None: return self.ldisplay
if self.dumper.isLldb: #if self.ldata is not None:
return str(self.nativeValue.GetValue()) # if sys.version_info[0] == 2 and isinstance(self.ldata, buffer):
else: # return bytes(self.ldata).encode("hex")
return str( self.nativeValue) # return self.ldata.encode("hex")
if self.nativeValue is not None:
return str(self.nativeValue)
#return "Value(nativeValue=%s)" % self.nativeValue
if self.ldata is not None:
if sys.version_info[0] == 2 and isinstance(self.ldata, buffer):
return bytes(self.data).encode("hex")
return self.data.encode("hex")
if self.laddress is not None: if self.laddress is not None:
return "value of type %s at address 0x%x" % (self.type, self.laddress) return "value of type %s at address 0x%x" % (self.type.name, self.laddress)
return "<unknown data>" return "<unknown data>"
def simpleDisplay(self, showAddress=True): def simpleDisplay(self, showAddress=True):
@@ -2741,66 +2689,52 @@ class DumperBase:
return self.extractField(field) return self.extractField(field)
def extractField(self, field): def extractField(self, field):
#warn("PARENT BASE 0x%x" % self.address()) self.dumper.check(self.type.code != TypeCodeTypedef)
if self.type.code == TypeCodeTypedef:
error("WRONG")
if not isinstance(field, self.dumper.Field): if not isinstance(field, self.dumper.Field):
error("BAD INDEX TYPE %s" % type(field)) error("BAD INDEX TYPE %s" % type(field))
val = None
if self.nativeValue is not None:
#warn("NATIVE, FIELD TYPE: %s " % field)
val = self.dumper.nativeValueChildFromField(self.nativeValue, field)
#warn("BAD INDEX XX VAL: %s TYPE: %s INDEX TYPE: %s "
# % (self, self.type, type(field)))
#warn("FIELD: %s " % field) #warn("FIELD: %s " % field)
fieldType = field.fieldType()
fieldBitsize = field.bitsize() fieldBitsize = field.bitsize()
fieldSize = None if fieldBitsize is None else fieldBitsize >> 3 fieldSize = None if fieldBitsize is None else fieldBitsize >> 3
#warn("BITPOS %s BITSIZE: %s" % (fieldBitpos, fieldBitsize)) fieldBitpos = field.bitpos()
fieldOffset = fieldBitpos >> 3
fieldBitpos -= fieldOffset * 8
if val is None:
val = self.dumper.Value(self.dumper) val = self.dumper.Value(self.dumper)
val.type = fieldType
val.name = field.name val.name = field.name
if self.laddress is not None: if self.laddress is not None:
#warn("ADDRESS")
fieldBitpos = field.bitpos()
fieldOffset = None if fieldBitpos is None else fieldBitpos >> 3
if fieldBitpos is not None:
#warn("BITPOS: %s" % fieldBitpos)
val.laddress = self.laddress + fieldOffset val.laddress = self.laddress + fieldOffset
else: elif self.ldata is not None:
error("NO IDEA 1")
elif len(self.ldata) > 0:
#warn("DATA")
fieldBitpos = field.bitpos()
fieldOffset = None if fieldBitpos is None else fieldBitpos >> 3
if fieldBitpos is not None:
val.ldata = self.ldata[fieldOffset:fieldOffset + fieldSize] val.ldata = self.ldata[fieldOffset:fieldOffset + fieldSize]
else: else:
error("NO IDEA 2") self.dumper.check(False)
else:
error("NO IDEA 3")
#warn("BITPOS %s BITSIZE: %s" % (fieldBitpos, fieldBitsize))
if fieldBitsize is not None and fieldBitsize % 8 != 0: if fieldBitsize is not None and fieldBitsize % 8 != 0:
fieldBitpos = field.bitpos()
#warn("CORRECTING: FITPOS %s BITSIZE: %s" % (fieldBitpos, fieldBitsize))
typeobj = fieldType
typeobj.lbitsize = fieldBitsize
data = val.extractInteger(fieldBitsize, True) data = val.extractInteger(fieldBitsize, True)
data = data >> (fieldBitpos & 3) data = data >> fieldBitpos
data = data & ((1 << fieldBitsize) - 1) data = data & ((1 << fieldBitsize) - 1)
val.laddress = None val.laddress = None
val.ldata = bytes(struct.pack('Q', data)) val.ldata = bytes(struct.pack('Q', data))
val.type = typeobj
val.type = None
fieldType = field.fieldType()
if val.laddress is not None and fieldType is not None:
if fieldType.code in (TypeCodePointer, TypeCodeReference):
baseType = fieldType.dereference()
address = self.dumper.extractPointer(val.laddress)
dynTypeName = self.dumper.dynamicTypeName(baseType, address)
if dynTypeName is not None:
if fieldType.code == TypeCodePointer:
val.type = self.dumper.createType(dynTypeName + '*')
else:
val.type = self.dumper.createType(dynTypeName + ' &')
if val.type is None:
val.type = fieldType
#warn("GOT VAL %s FOR FIELD %s" % (val, field)) #warn("GOT VAL %s FOR FIELD %s" % (val, field))
val.check() val.check()
val.lbitsize = field.bitsize() val.lbitsize = fieldBitsize
return val return val
def members(self): def members(self):
@@ -2813,37 +2747,25 @@ class DumperBase:
def __add__(self, other): def __add__(self, other):
self.check() self.check()
if self.dumper.isInt(other): if self.dumper.isInt(other):
#warn("OTHER INT: %s" % other) stripped = self.type.stripTypedefs()
if self.nativeValue is not None: if stripped.code == TypeCodePointer:
#warn("OTHER NATIVE: %s" % self.nativeValue) address = self.pointer() + stripped.dereference().size()
#warn("OTHER RESULT 1: %s" % (self.nativeValue + other)) val = self.dumper.Value(self.dumper)
res = self.dumper.fromNativeValue(self.nativeValue + other) val.laddress = None
#warn("OTHER RESULT 2: %s" % (self.nativeValue + other)) val.ldata = bytes(struct.pack('Q', address))
#warn("OTHER COOKED: 0x%x" % res.pointer()) val.type = self.type
#warn("OTHER COOKED X: 0x%x" % res.nativeValue) return val
return res
error("BAD DATA TO ADD TO: %s %s" % (self.type, other)) error("BAD DATA TO ADD TO: %s %s" % (self.type, other))
def dereference(self): def dereference(self):
self.check() self.check()
if self.nativeValue is not None:
res = self.dumper.nativeValueDereference(self.nativeValue)
if res is not None:
return res
if self.laddress is not None:
val = self.dumper.Value(self.dumper) val = self.dumper.Value(self.dumper)
val.type = self.type.dereference() val.type = self.type.dereference()
#val.ldata = bytes(self.dumper.readRawMemory(self.laddress, val.type.size())) val.laddress = self.pointer()
#val.laddress = self.dumper.extractPointer(self.laddress) dynTypeName = self.dumper.dynamicTypeName(val.type, val.laddress)
#val.ldata = bytes(self.data(self.dumper.ptrSize())) if dynTypeName is not None:
#val.laddress = self.__int__() val.type = self.dumper.createType(dynTypeName)
bitsize = self.dumper.ptrSize() * 8
val.laddress = self.integer()
#warn("DEREFERENCING %s AT 0x%x -- %s TO %s AT 0x%x --- %s" %
# (self.type, self.laddress, self.dumper.hexencode(self.data),
# val.type, val.laddress, self.dumper.hexencode(val.data)))
return val return val
error("BAD DATA TO DEREFERENCE: %s %s" % (self.type, type(self)))
def extend(self, size): def extend(self, size):
if self.type.size() < size: if self.type.size() < size:
@@ -2860,28 +2782,16 @@ class DumperBase:
def cast(self, typish): def cast(self, typish):
self.check() self.check()
typeobj = self.dumper.createType(typish)
if self.nativeValue is not None and typeobj.nativeType is not None:
res = self.dumper.nativeValueCast(self.nativeValue, typeobj.nativeType)
if res is not None:
return res
#error("BAD NATIVE DATA TO CAST: %s %s" % (self.type, typeobj))
val = self.dumper.Value(self.dumper) val = self.dumper.Value(self.dumper)
val.laddress = self.laddress val.laddress = self.laddress
val.ldata = self.ldata val.ldata = self.ldata
val.type = typeobj val.type = self.dumper.createType(typish)
#warn("CAST %s %s" % (self.type.stringify(), typeobj.stringify()))
return val return val
def downcast(self): def downcast(self):
self.check() self.check()
if self.nativeValue is not None:
return self.dumper.nativeValueDownCast(self.nativeValue)
return self return self
def isInScope(self):
return self.lIsInScope
def address(self): def address(self):
self.check() self.check()
return self.laddress return self.laddress
@@ -2896,38 +2806,28 @@ class DumperBase:
return self.ldata return self.ldata
if size < len(self.ldata): if size < len(self.ldata):
return self.ldata[:size] return self.ldata[:size]
error("DATA PRESENT, BUT NOT BIG ENOUGH: %s WANT: %s"
% (self.stringify(), size))
if self.laddress is not None: if self.laddress is not None:
if size is None: if size is None:
size = self.type.size() size = self.type.size()
res = self.dumper.readRawMemory(self.laddress, size) res = self.dumper.readRawMemory(self.laddress, size)
if len(res) > 0: if len(res) > 0:
return res return res
if self.nativeValue is not None:
if size is None:
size = self.type.size()
res = self.dumper.nativeValueAsBytes(self.nativeValue, size)
if len(res) > 0:
return res
return res
error("CANNOT CONVERT TO BYTES: %s" % self) error("CANNOT CONVERT TO BYTES: %s" % self)
def extractInteger(self, bitsize, unsigned): def extractInteger(self, bitsize, unsigned):
self.check() self.check()
size = (bitsize + 7) >> 3 if bitsize > 32:
if size == 8: size = 8
code = "Q" if unsigned else "q" code = "Q" if unsigned else "q"
elif size == 4: elif bitsize > 16:
size = 4
code = "I" if unsigned else "i" code = "I" if unsigned else "i"
elif size == 2: elif bitsize > 8:
size = 2
code = "H" if unsigned else "h" code = "H" if unsigned else "h"
elif size == 1:
code = "B" if unsigned else "b"
else: else:
code = None size = 1
if code is None: code = "B" if unsigned else "b"
return None
rawBytes = self.data(size) rawBytes = self.data(size)
try: try:
return struct.unpack_from(code, rawBytes, 0)[0] return struct.unpack_from(code, rawBytes, 0)[0]
@@ -2971,6 +2871,18 @@ class DumperBase:
ptr = p if self.isInt(p) else p.pointer() ptr = p if self.isInt(p) else p.pointer()
self.readRawMemory(ptr, 1) self.readRawMemory(ptr, 1)
def dynamicTypeName(self, baseType, address):
if baseType.code != TypeCodeStruct:
return None
try:
vtbl = self.extractPointer(address)
except:
return None
#warn("VTBL: 0x%x" % vtbl)
if not self.canBePointer(vtbl):
return None
return self.nativeDynamicTypeName(address, baseType)
class Type: class Type:
def __init__(self, dumper): def __init__(self, dumper):
self.dumper = dumper self.dumper = dumper
@@ -2979,6 +2891,7 @@ class DumperBase:
self.lfields = None self.lfields = None
self.lbitsize = None self.lbitsize = None
self.lbitpos = None self.lbitpos = None
self.ltarget = None # Inner type for arrays
self.templateArguments = None self.templateArguments = None
self.code = None self.code = None
@@ -3206,7 +3119,9 @@ class DumperBase:
def __str__(self): def __str__(self):
return ("Field(name='%s',ltype=%s,parentType=%s,bpos=%s,bsize=%s," return ("Field(name='%s',ltype=%s,parentType=%s,bpos=%s,bsize=%s,"
+ "bidx=%s,nidx=%s)") \ + "bidx=%s,nidx=%s)") \
% (self.name, self.ltype, self.parentType, % (self.name,
None if self.ltype is None else self.ltype.name,
None if self.parentType is None else self.parentType.name,
self.lbitpos, self.lbitsize, self.lbitpos, self.lbitsize,
self.baseIndex, self.nativeIndex) self.baseIndex, self.nativeIndex)
@@ -3294,32 +3209,22 @@ class DumperBase:
#warn("CREATE TYPE: %s" % typeobj) #warn("CREATE TYPE: %s" % typeobj)
typeobj.check() typeobj.check()
return typeobj return typeobj
if self.isInt(typish):
# Assume it is an typecode, create an "anonymous" Type
typeobj = self.Type(self)
typeobj.code = typish
typeobj.lbitsize = 8 * size
typeobj.name = ' '
return typeobj
error("NEED TYPE, NOT %s" % type(typish)) error("NEED TYPE, NOT %s" % type(typish))
def createValue(self, datish, typish): def createValue(self, datish, typish):
val = self.Value(self)
val.type = self.createType(typish)
if self.isInt(datish): # Used as address. if self.isInt(datish): # Used as address.
#warn("CREATING %s AT 0x%x" % (typish, address))
val = self.Value(self)
val.laddress = datish val.laddress = datish
val.type = self.createType(typish) #warn("CREATING %s AT 0x%x" % (val.type.name, address))
val.check() elif isinstance(datish, bytes):
return val
if isinstance(datish, bytes):
#warn("CREATING %s WITH DATA %s" % (typish, self.hexencode(datish)))
val = self.Value(self)
val.ldata = datish val.ldata = datish
val.type = self.createType(typish)
val.type.lbitsize = 8 * len(datish) val.type.lbitsize = 8 * len(datish)
#warn("CREATING %s WITH DATA %s" % (val.type.name, self.hexencode(datish)))
else:
error("EXPECTING ADDRESS OR BYTES, GOT %s" % type(datish))
val.check() val.check()
return val return val
error("EXPECTING ADDRESS OR BYTES, GOT %s" % type(datish))
def createListItem(self, data, innerTypish): def createListItem(self, data, innerTypish):
innerType = self.createType(innerTypish) innerType = self.createType(innerTypish)

View File

@@ -248,13 +248,32 @@ class Dumper(DumperBase):
return self.fromNativeValue(nativeValue) return self.fromNativeValue(nativeValue)
def fromNativeValue(self, nativeValue): def fromNativeValue(self, nativeValue):
#self.check(isinstance(nativeType, gdb.Value)) #self.check(isinstance(nativeValue, gdb.Value))
nativeType = nativeValue.type
val = self.Value(self) val = self.Value(self)
val.nativeValue = nativeValue
if not nativeValue.address is None: if not nativeValue.address is None:
val.laddress = toInteger(nativeValue.address) val.laddress = toInteger(nativeValue.address)
val.type = self.fromNativeType(nativeValue.type) else:
size = nativeType.sizeof
chars = self.lookupNativeType("unsigned char")
y = nativeValue.cast(chars.array(0, int(nativeType.sizeof - 1)))
buf = bytearray(struct.pack('x' * size))
for i in range(size):
buf[i] = int(y[i])
val.ldata = bytes(buf)
val.type = self.fromNativeType(nativeType)
val.lIsInScope = not nativeValue.is_optimized_out val.lIsInScope = not nativeValue.is_optimized_out
code = nativeType.code
if code == gdb.TYPE_CODE_ENUM:
val.ldisplay = str(nativeValue)
intval = int(nativeValue)
if val.ldisplay != intval:
val.ldisplay += ' (%s)' % intval
elif code == gdb.TYPE_CODE_COMPLEX:
val.ldisplay = str(nativeValue)
elif code == gdb.TYPE_CODE_ARRAY:
val.type.ltarget = nativeValue[0].type.unqualified()
return val return val
def fromNativeType(self, nativeType): def fromNativeType(self, nativeType):
@@ -285,18 +304,6 @@ class Dumper(DumperBase):
}[nativeType.code] }[nativeType.code]
return typeobj return typeobj
def nativeValueDereference(self, nativeValue):
return self.nativeValueDownCast(nativeValue.dereference())
def nativeValueCast(self, nativeValue, nativeType):
try:
return self.fromNativeValue(nativeValue.cast(nativeType))
except:
return None
def nativeValueAddressOf(self, nativeValue):
return toInteger(nativeValue.address)
def nativeTypeDereference(self, nativeType): def nativeTypeDereference(self, nativeType):
return self.fromNativeType(nativeType.strip_typedefs().target()) return self.fromNativeType(nativeType.strip_typedefs().target())
@@ -402,25 +409,6 @@ class Dumper(DumperBase):
typeobj = typeobj.strip_typedefs().unqualified() typeobj = typeobj.strip_typedefs().unqualified()
return self.fromNativeType(typeobj) return self.fromNativeType(typeobj)
def nativeValueChildFromField(self, nativeValue, field):
#warn("EXTRACTING: %s FROM %s" % (field, nativeValue))
if field.nativeIndex is not None:
nativeField = nativeValue.type.fields()[field.nativeIndex]
#warn("NATIVE FIELD: %s" % nativeField)
if nativeField.is_base_class:
return self.fromNativeValue(nativeValue.cast(nativeField.type))
try:
# Fails with GDB 7.5.
return self.nativeValueDownCast(nativeValue[nativeField])
except:
# The generic handling is almost good enough, but does not
# downcast the produced values.
return None
if field.name is not None:
return self.nativeValueDownCast(nativeValue[field.name])
error("FIELD EXTARCTION FAILED: %s" % field)
return None
def listOfLocals(self, partialVar): def listOfLocals(self, partialVar):
frame = gdb.selected_frame() frame = gdb.selected_frame()
@@ -571,20 +559,6 @@ class Dumper(DumperBase):
return None return None
return self.fromNativeValue(val) return self.fromNativeValue(val)
def nativeValueAsBytes(self, nativeValue, size):
# Assume it's a (backend specific) Value.
if nativeValue.address:
return self.readRawMemory(nativeValue.address, size)
# No address. Possibly the result of an inferior call.
# Note: Only a cast to unsigned char[sizeof(origtype)] succeeds
# in this situation in gdb.
chars = self.lookupNativeType("unsigned char")
y = nativeValue.cast(chars.array(0, int(nativeValue.type.sizeof - 1)))
buf = bytearray(struct.pack('x' * size))
for i in range(size):
buf[i] = int(y[i])
return bytes(buf)
def callHelper(self, rettype, value, function, args): def callHelper(self, rettype, value, function, args):
# args is a tuple. # args is a tuple.
arg = "" arg = ""
@@ -963,47 +937,16 @@ class Dumper(DumperBase):
cmd = "set variable (%s)=%s" % (expr, value) cmd = "set variable (%s)=%s" % (expr, value)
gdb.execute(cmd) gdb.execute(cmd)
def hasVTable(self, typeobj): def nativeDynamicTypeName(self, address, baseType):
fields = typeobj.fields() vtbl = gdb.execute("info symbol {%s*}0x%x" % (baseType.name, address), to_string = True)
if len(fields) == 0:
return False
if fields[0].isBaseClass:
return hasVTable(fields[0].type)
return str(fields[0].type) == "int (**)(void)"
def dynamicTypeName(self, value):
if self.hasVTable(value.type):
#vtbl = str(gdb.parse_and_eval("{int(*)(int)}%s" % int(value.address)))
try:
# Fails on 7.1 due to the missing to_string.
vtbl = gdb.execute("info symbol {int*}%s" % int(value.address),
to_string = True)
pos1 = vtbl.find("vtable ") pos1 = vtbl.find("vtable ")
if pos1 != -1: if pos1 == -1:
return None
pos1 += 11 pos1 += 11
pos2 = vtbl.find(" +", pos1) pos2 = vtbl.find(" +", pos1)
if pos2 != -1: if pos2 == -1:
return None
return vtbl[pos1 : pos2] return vtbl[pos1 : pos2]
except:
pass
return str(value.type)
def nativeValueDownCast(self, nativeValue):
try:
return self.fromNativeValue(nativeValue.cast(nativeValue.dynamic_type))
except:
return self.fromNativeValue(nativeValue)
def expensiveDowncast(self, value):
try:
return value.cast(value.dynamic_type)
except:
pass
try:
return value.cast(self.lookupType(self.dynamicTypeName(value)))
except:
pass
return value
def enumExpression(self, enumType, enumValue): def enumExpression(self, enumType, enumValue):
return self.qtNamespace() + "Qt::" + enumValue return self.qtNamespace() + "Qt::" + enumValue

View File

@@ -57,20 +57,6 @@ def check(exp):
if not exp: if not exp:
raise RuntimeError("Check failed") raise RuntimeError("Check failed")
def impl_SBValue__add__(self, offset):
if self.GetType().IsPointerType():
itemsize = self.GetType().GetPointeeType().GetByteSize()
address = self.GetValueAsUnsigned() + offset * itemsize
address = address & 0xFFFFFFFFFFFFFFFF # Force unsigned
return self.CreateValueFromAddress(None, address,
self.GetType().GetPointeeType()).AddressOf()
raise RuntimeError("SBValue.__add__ not implemented: %s" % self.GetType())
return NotImplemented
lldb.SBValue.__add__ = impl_SBValue__add__
class Dumper(DumperBase): class Dumper(DumperBase):
def __init__(self): def __init__(self):
DumperBase.__init__(self) DumperBase.__init__(self)
@@ -154,15 +140,42 @@ class Dumper(DumperBase):
def fromNativeValue(self, nativeValue): def fromNativeValue(self, nativeValue):
nativeValue.SetPreferSyntheticValue(False) nativeValue.SetPreferSyntheticValue(False)
nativeType = nativeValue.GetType()
val = self.Value(self) val = self.Value(self)
val.nativeValue = nativeValue val.type = self.fromNativeType(nativeType)
val.type = self.fromNativeType(nativeValue.type)
val.lIsInScope = nativeValue.IsInScope() val.lIsInScope = nativeValue.IsInScope()
#val.name = nativeValue.GetName() #val.name = nativeValue.GetName()
try: data = nativeValue.GetData()
error = lldb.SBError()
size = nativeValue.GetType().GetByteSize()
if size > 0: # Happens regularly e.g. for cross-shared-object types.
val.ldata = data.ReadRawData(error, 0, size)
code = nativeType.GetTypeClass()
if code not in (lldb.eTypeClassPointer, lldb.eTypeClassReference):
val.laddress = int(nativeValue.GetLoadAddress()) val.laddress = int(nativeValue.GetLoadAddress())
except: if code == lldb.eTypeClassEnumeration:
pass intval = nativeValue.GetValueAsSigned()
if hasattr(nativeType, 'get_enum_members_array'):
for enumMember in nativeType.get_enum_members_array():
# Even when asking for signed we get unsigned with LLDB 3.8.
diff = enumMember.GetValueAsSigned() - intval
mask = (1 << nativeType.GetByteSize() * 8) - 1
if diff & mask == 0:
path = nativeType.GetName().split('::')
path[-1] = enumMember.GetName()
val.ldisplay = "%s (%d)" % ('::'.join(path), intval)
val.ldisplay = "%d" % intval
elif code in (lldb.eTypeClassComplexInteger, lldb.eTypeClassComplexFloat):
val.ldisplay = str(nativeValue.GetValue())
elif code == lldb.eTypeClassArray:
if hasattr(nativeType, "GetArrayElementType"): # New in 3.8(?) / 350.x
val.type.ltarget = self.fromNativeType(nativeType.GetArrayElementType())
else:
fields = nativeType.get_fields_array()
if len(fields):
val.type.ltarget = self.fromNativeType(fields[0])
elif code == lldb.eTypeClassVector:
val.type.ltarget = self.fromNativeType(nativeType.GetVectorElementType())
return val return val
def fromNativeType(self, nativeType): def fromNativeType(self, nativeType):
@@ -217,6 +230,7 @@ class Dumper(DumperBase):
addr = 0x7fffffffe0a0 addr = 0x7fffffffe0a0
sbaddr = lldb.SBAddress(addr, self.target) sbaddr = lldb.SBAddress(addr, self.target)
dummyValue = self.target.CreateValueFromAddress('x', sbaddr, nativeType) dummyValue = self.target.CreateValueFromAddress('x', sbaddr, nativeType)
dummyValue.SetPreferSyntheticValue(False)
anonNumber = 0 anonNumber = 0
@@ -246,8 +260,8 @@ class Dumper(DumperBase):
anonNumber += 1 anonNumber += 1
fieldName = "#%s" % anonNumber fieldName = "#%s" % anonNumber
fieldType = dummyChild.GetType() fieldType = dummyChild.GetType()
#warn("CHILD AT: %s: %s %s" % (i, fieldName, fieldType)) #warn("CHILD AT: %s: %s %s" % (i, fieldName, fieldType.GetName()))
#warn(" AT: %s: %s %s" % (i, fieldName, fieldType)) #warn(" AT: %s: %s %s" % (i, fieldName, fieldType.GetName()))
caddr = dummyChild.AddressOf().GetValueAsUnsigned() caddr = dummyChild.AddressOf().GetValueAsUnsigned()
child = self.Value(self) child = self.Value(self)
child.type = self.fromNativeType(fieldType) child.type = self.fromNativeType(fieldType)
@@ -298,15 +312,6 @@ class Dumper(DumperBase):
#warn("FIELDS: %s" % fields) #warn("FIELDS: %s" % fields)
return fields return fields
def nativeValueDereference(self, nativeValue):
result = nativeValue.Dereference()
if not result.IsValid():
return None
return self.fromNativeValue(result)
def nativeValueCast(self, nativeValue, nativeType):
return self.fromNativeValue(nativeValue.Cast(nativeType))
def nativeTypeUnqualified(self, nativeType): def nativeTypeUnqualified(self, nativeType):
return self.fromNativeType(nativeType.GetUnqualifiedType()) return self.fromNativeType(nativeType.GetUnqualifiedType())
@@ -318,46 +323,6 @@ class Dumper(DumperBase):
return self.fromNativeType(typeobj.GetCanonicalType()) return self.fromNativeType(typeobj.GetCanonicalType())
return self.fromNativeType(typeobj) return self.fromNativeType(typeobj)
def nativeValueChildFromNameHelper(self, nativeValue, fieldName):
val = nativeValue.GetChildMemberWithName(fieldName)
if val.IsValid():
return val
nativeType = nativeValue.GetType()
for i in xrange(nativeType.GetNumberOfDirectBaseClasses()):
baseField = nativeType.GetDirectBaseClassAtIndex(i)
baseType = baseField.GetType()
base = nativeValue.Cast(baseType)
val = self.nativeValueChildFromNameHelper(base, fieldName)
if val is not None:
return val
return None
def nativeValueChildFromField(self, nativeValue, field):
val = None
if field.isVirtualBase is True:
#warn("FETCHING VIRTUAL BASE: %s: %s" % (field.baseIndex, field.name))
pass
if field.nativeIndex is not None:
#warn("FETCHING BY NATIVE INDEX: %s: %s" % (field.nativeIndex, field.name))
val = nativeValue.GetChildAtIndex(field.nativeIndex)
if val.IsValid():
return self.fromNativeValue(val)
elif field.baseIndex is not None:
baseClass = nativeValue.GetType().GetDirectBaseClassAtIndex(field.baseIndex)
if baseClass.IsValid():
#warn("BASE IS VALID, TYPE: %s" % baseClass.GetType())
#warn("BASE BITPOS: %s" % field.lbitpos)
#warn("BASE BITSIZE: %s" % field.lbitsize)
# FIXME: This is wrong for virtual bases.
return None # Let standard behavior kick in.
else:
#warn("FETCHING BY NAME: %s: %s" % (field, field.name))
val = self.nativeValueChildFromNameHelper(nativeValue, field.name)
if val is not None:
return self.fromNativeValue(val)
raise RuntimeError("No such member '%s' in %s" % (field.name, nativeValue.type))
return None
def nativeTypeFirstBase(self, nativeType): def nativeTypeFirstBase(self, nativeType):
#warn("FIRST BASE FROM: %s" % nativeType) #warn("FIRST BASE FROM: %s" % nativeType)
if nativeType.GetNumberOfDirectBaseClasses() == 0: if nativeType.GetNumberOfDirectBaseClasses() == 0:
@@ -378,6 +343,13 @@ class Dumper(DumperBase):
return "%s (%d)" % ('::'.join(path), intval) return "%s (%d)" % ('::'.join(path), intval)
return "%d" % intval return "%d" % intval
def nativeDynamicTypeName(self, address, baseType):
return None # FIXME: Seems sufficient, no idea why.
addr = self.target.ResolveLoadAddress(address)
ctx = self.target.ResolveSymbolContextForAddress(addr, 0)
sym = ctx.GetSymbol()
return sym.GetName()
def stateName(self, s): def stateName(self, s):
try: try:
# See db.StateType # See db.StateType
@@ -480,9 +452,6 @@ class Dumper(DumperBase):
#warn("INNER: %s" % inner) #warn("INNER: %s" % inner)
return self.lookupType(inner) return self.lookupType(inner)
def nativeValueAddressOf(self, nativeValue):
return int(value.GetLoadAddress())
def nativeTypeDereference(self, nativeType): def nativeTypeDereference(self, nativeType):
return self.fromNativeType(nativeType.GetPointeeType()) return self.fromNativeType(nativeType.GetPointeeType())
@@ -917,15 +886,6 @@ class Dumper(DumperBase):
return bytes() return bytes()
return res return res
def nativeValueAsBytes(self, nativeValue, size):
data = nativeValue.GetData()
buf = bytearray(struct.pack('x' * size))
error = lldb.SBError()
#data.ReadRawData(error, 0, buf)
for i in range(size):
buf[i] = data.GetUnsignedInt8(error, i)
return bytes(buf)
def findStaticMetaObject(self, typeName): def findStaticMetaObject(self, typeName):
symbolName = self.mangleName(typeName + '::staticMetaObject') symbolName = self.mangleName(typeName + '::staticMetaObject')
symbol = self.target.FindFirstGlobalVariable(symbolName) symbol = self.target.FindFirstGlobalVariable(symbolName)
@@ -983,6 +943,7 @@ class Dumper(DumperBase):
if len(statics): if len(statics):
for i in xrange(len(statics)): for i in xrange(len(statics)):
staticVar = statics[i] staticVar = statics[i]
staticVar.SetPreferSyntheticValue(False)
typename = staticVar.GetType().GetName() typename = staticVar.GetType().GetName()
name = staticVar.GetName() name = staticVar.GetName()
with SubItem(self, i): with SubItem(self, i):
@@ -1004,6 +965,7 @@ class Dumper(DumperBase):
variables = [] variables = []
for val in values: for val in values:
val.SetPreferSyntheticValue(False)
if not val.IsValid(): if not val.IsValid():
continue continue
self.currentContextValue = val self.currentContextValue = val

View File

@@ -887,11 +887,11 @@ def qdump__QLocale(d, value):
#d.check(index <= qqLocalesCount) #d.check(index <= qqLocalesCount)
dd = value.extractPointer() dd = value.extractPointer()
ns = d.qtNamespace() ns = d.qtNamespace()
(data, ref, numberOptions) = d.split("pi{int}", dd) (data, ref, numberOptions) = d.split("pi4s", dd)
(languageId, scriptId, countryId, (languageId, scriptId, countryId,
decimal, group, listt, percent, zero, decimal, group, listt, percent, zero,
minus, plus, exponential) \ minus, plus, exponential) \
= d.split('{short}{short}{QChar}' = d.split('2s{short}2s'
+ '{QChar}{QChar}{short}{QChar}{QChar}' + '{QChar}{QChar}{short}{QChar}{QChar}'
+ '{QChar}{QChar}{QChar}', data) + '{QChar}{QChar}{QChar}', data)
d.putStringValue(d.call("const char *", value, "name")) d.putStringValue(d.call("const char *", value, "name"))
@@ -899,9 +899,9 @@ def qdump__QLocale(d, value):
if d.isExpanded(): if d.isExpanded():
with Children(d): with Children(d):
prefix = ns + "QLocale::" prefix = ns + "QLocale::"
d.putSubItem("country", countryId.extend(4).cast(prefix + "Country")) d.putSubItem("country", d.createValue(countryId, prefix + "Country"))
d.putSubItem("language", languageId.extend(4).cast(prefix + "Language")) d.putSubItem("language", d.createValue(languageId, prefix + "Language"))
d.putSubItem("numberOptions", numberOptions.cast(prefix + "NumberOptions")) d.putSubItem("numberOptions", d.createValue(numberOptions, prefix + "NumberOptions"))
d.putSubItem("decimalPoint", decimal) d.putSubItem("decimalPoint", decimal)
d.putSubItem("exponential", exponential) d.putSubItem("exponential", exponential)
d.putSubItem("percent", percent) d.putSubItem("percent", percent)
@@ -1189,7 +1189,7 @@ def qdump__QSet(d, value):
typeCode = 'Pi@{%s}' % keyType.name typeCode = 'Pi@{%s}' % keyType.name
(pnext, hashval, padding1, key) = d.split(typeCode, node) (pnext, hashval, padding1, key) = d.split(typeCode, node)
with SubItem(d, i): with SubItem(d, i):
d.putItem(key, i) d.putItem(key)
node = hashDataNextNode(node) node = hashDataNextNode(node)

View File

@@ -227,12 +227,11 @@ def qdump__std__map(d, value):
pairPointer = pairType.pointer() pairPointer = pairType.pointer()
with PairedChildren(d, size, pairType=pairType, maxNumChild=1000): with PairedChildren(d, size, pairType=pairType, maxNumChild=1000):
node = impl["_M_header"]["_M_left"] node = impl["_M_header"]["_M_left"]
typeCode = "p@{%s}@{%s}" % (pairType[0].name, pairType[1].name) nodeSize = node.dereference().type.size()
typeCode = "@{%s}@{%s}" % (pairType[0].name, pairType[1].name)
for i in d.childRange(): for i in d.childRange():
pair = (node + 1).cast(pairPointer).dereference() (pad1, key, pad2, value) = d.split(typeCode, node.pointer() + nodeSize)
d.putPairItem(i, pair) d.putPairItem(i, (key, value))
#(pp, pad1, key, pad2, value) = d.split(typeCode, node.integer())
#d.putPairItem(i, (key, value))
if node["_M_right"].integer() == 0: if node["_M_right"].integer() == 0:
parent = node["_M_parent"] parent = node["_M_parent"]
while True: while True:
@@ -384,9 +383,12 @@ def qdump__std__set(d, value):
if d.isExpanded(): if d.isExpanded():
valueType = value.type[0] valueType = value.type[0]
node = impl["_M_header"]["_M_left"] node = impl["_M_header"]["_M_left"]
nodeSize = node.dereference().type.size()
typeCode = "@{%s}" % valueType.name
with Children(d, size, maxNumChild=1000, childType=valueType): with Children(d, size, maxNumChild=1000, childType=valueType):
for i in d.childRange(): for i in d.childRange():
d.putSubItem(i, (node + 1).cast(valueType.pointer()).dereference()) (pad, val) = d.split(typeCode, node.pointer() + nodeSize)
d.putSubItem(i, val)
if node["_M_right"].integer() == 0: if node["_M_right"].integer() == 0:
parent = node["_M_parent"] parent = node["_M_parent"]
while node == parent["_M_right"]: while node == parent["_M_right"]:

View File

@@ -4106,34 +4106,34 @@ void tst_Dumpers::dumper_data()
+ CoreProfile() + CoreProfile()
+ Check("map1", "<3 items>", "std::map<@QString, Foo>") + Check("map1", "<3 items>", "std::map<@QString, Foo>")
+ Check("map1.0", "[0]", "", "std::pair<@QString const, Foo>") + Check("map1.0", "[0] \"22.0\"", "", "std::pair<@QString const, Foo>")
+ Check("map1.0.first", "\"22.0\"", "@QString") + Check("map1.0.first", "\"22.0\"", "@QString")
+ Check("map1.0.second", "", "Foo") + Check("map1.0.second", "", "Foo")
+ Check("map1.0.second.a", "22", "int") + Check("map1.0.second.a", "22", "int")
+ Check("map1.1", "[1]", "", "std::pair<@QString const, Foo>") + Check("map1.1", "[1] \"33.0\"", "", "std::pair<@QString const, Foo>")
+ Check("map1.2.first", "\"44.0\"", "@QString") + Check("map1.2.first", "\"44.0\"", "@QString")
+ Check("map1.2.second", "", "Foo") + Check("map1.2.second", "", "Foo")
+ Check("map1.2.second.a", "44", "int") + Check("map1.2.second.a", "44", "int")
+ Check("map2", "<2 items>", "std::map<char const*, Foo>") + Check("map2", "<2 items>", "std::map<char const*, Foo>")
+ Check("map2.0", "[0]", "", "std::pair<char const* const, Foo>") + Check("map2.0", "[0] \"22.0\"", "", "std::pair<char const* const, Foo>")
+ CheckType("map2.0.first", "char *") + CheckType("map2.0.first", "char *")
// FIXME // FIXME
//+ Check("map2.0.first.0", "50", "char") //+ Check("map2.0.first.0", "50", "char")
+ Check("map2.0.second", "", "Foo") + Check("map2.0.second", "", "Foo")
+ Check("map2.0.second.a", "22", "int") + Check("map2.0.second.a", "22", "int")
+ Check("map2.1", "[1]", "", "std::pair<char const* const, Foo>") + Check("map2.1", "[1] \"33.0\"", "", "std::pair<char const* const, Foo>")
+ CheckType("map2.1.first", "char *") + CheckType("map2.1.first", "char *")
//+ Check("map2.1.first.*first", "51 '3'", "char") //+ Check("map2.1.first.*first", "51 '3'", "char")
+ Check("map2.1.second", "", "Foo") + Check("map2.1.second", "", "Foo")
+ Check("map2.1.second.a", "33", "int") + Check("map2.1.second.a", "33", "int")
+ Check("map3", "<2 items>", "std::map<unsigned int, @QStringList>") + Check("map3", "<2 items>", "std::map<unsigned int, @QStringList>")
+ Check("map3.0", "[0]", "", "std::pair<unsigned int const, @QStringList>") + Check("map3.0", "[0] 11", "<1 items>", "std::pair<unsigned int const, @QStringList>")
+ Check("map3.0.first", "11", "unsigned int") + Check("map3.0.first", "11", "unsigned int")
+ Check("map3.0.second", "<1 items>", "@QStringList") + Check("map3.0.second", "<1 items>", "@QStringList")
+ Check("map3.0.second.0", "[0]", "\"11\"", "@QString") + Check("map3.0.second.0", "[0]", "\"11\"", "@QString")
+ Check("map3.1", "[1]", "", "std::pair<unsigned int const, @QStringList>") + Check("map3.1", "[1] 22", "<1 items>", "std::pair<unsigned int const, @QStringList>")
+ Check("map3.1.first", "22", "unsigned int") + Check("map3.1.first", "22", "unsigned int")
+ Check("map3.1.second", "<1 items>", "@QStringList") + Check("map3.1.second", "<1 items>", "@QStringList")
+ Check("map3.1.second.0", "[0]", "\"22\"", "@QString") + Check("map3.1.second.0", "[0]", "\"22\"", "@QString")
@@ -4141,26 +4141,26 @@ void tst_Dumpers::dumper_data()
+ Check("map4.1.second.0", "[0]", "\"22\"", "@QString") + Check("map4.1.second.0", "[0]", "\"22\"", "@QString")
+ Check("map5", "<2 items>", "std::map<@QString, float>") + Check("map5", "<2 items>", "std::map<@QString, float>")
+ Check("map5.0", "[0]", "", "std::pair<@QString const, float>") + Check("map5.0", "[0] \"11.0\"", FloatValue("11"), "std::pair<@QString const, float>")
+ Check("map5.0.first", "\"11.0\"", "@QString") + Check("map5.0.first", "\"11.0\"", "@QString")
+ Check("map5.0.second", FloatValue("11"), "float") + Check("map5.0.second", FloatValue("11"), "float")
+ Check("map5.1", "[1]", "", "std::pair<@QString const, float>") + Check("map5.1", "[1] \"22.0\"", FloatValue("22"), "std::pair<@QString const, float>")
+ Check("map5.1.first", "\"22.0\"", "@QString") + Check("map5.1.first", "\"22.0\"", "@QString")
+ Check("map5.1.second", FloatValue("22"), "float") + Check("map5.1.second", FloatValue("22"), "float")
+ Check("map6", "<2 items>", "std::map<int, @QString>") + Check("map6", "<2 items>", "std::map<int, @QString>")
+ Check("map6.0", "[0]", "", "std::pair<int const, @QString>") + Check("map6.0", "[0] 11", "\"11.0\"", "std::pair<int const, @QString>")
+ Check("map6.0.first", "11", "int") + Check("map6.0.first", "11", "int")
+ Check("map6.0.second", "\"11.0\"", "@QString") + Check("map6.0.second", "\"11.0\"", "@QString")
+ Check("map6.1", "[1]", "", "std::pair<int const, @QString>") + Check("map6.1", "[1] 22", "\"22.0\"", "std::pair<int const, @QString>")
+ Check("map6.1.first", "22", "int") + Check("map6.1.first", "22", "int")
+ Check("map6.1.second", "\"22.0\"", "@QString") + Check("map6.1.second", "\"22.0\"", "@QString")
+ Check("map7", "<3 items>", "std::map<@QString, @QPointer<@QObject>>") + Check("map7", "<3 items>", "std::map<@QString, @QPointer<@QObject>>")
+ Check("map7.0", "[0]", "", "std::pair<@QString const, @QPointer<@QObject>>") + Check("map7.0", "[0] \".\"", "", "std::pair<@QString const, @QPointer<@QObject>>")
+ Check("map7.0.first", "\".\"", "@QString") + Check("map7.0.first", "\".\"", "@QString")
+ Check("map7.0.second", "", "@QPointer<@QObject>") + Check("map7.0.second", "", "@QPointer<@QObject>")
+ Check("map7.2", "[2]", "", "std::pair<@QString const, @QPointer<@QObject>>") + Check("map7.2", "[2] \"Welt\"", "", "std::pair<@QString const, @QPointer<@QObject>>")
+ Check("map7.2.first", "\"Welt\"", "@QString"); + Check("map7.2.first", "\"Welt\"", "@QString");
@@ -4948,9 +4948,10 @@ void tst_Dumpers::dumper_data()
QTest::newRow("Bitfields") QTest::newRow("Bitfields")
<< Data("struct S\n" << Data("struct S\n"
"{\n" "{\n"
" S() : x(2), y(3), c(1), b(0), f(5), d(6), i(7) {}\n" " S() : x(2), y(3), z(39), c(1), b(0), f(5), d(6), i(7) {}\n"
" unsigned int x : 3;\n" " unsigned int x : 3;\n"
" unsigned int y : 4;\n" " unsigned int y : 4;\n"
" unsigned int z : 18;\n"
" bool c : 1;\n" " bool c : 1;\n"
" bool b;\n" " bool b;\n"
" float f;\n" " float f;\n"
@@ -4966,7 +4967,8 @@ void tst_Dumpers::dumper_data()
+ Check("s.d", FloatValue("6"), "double") + Check("s.d", FloatValue("6"), "double")
+ Check("s.i", "7", "int") + Check("s.i", "7", "int")
+ Check("s.x", "2", "unsigned int") + Check("s.x", "2", "unsigned int")
+ Check("s.y", "3", "unsigned int"); + Check("s.y", "3", "unsigned int")
+ Check("s.z", "39", "unsigned int");
QTest::newRow("Function") QTest::newRow("Function")