diff --git a/share/qtcreator/debugger/boosttypes.py b/share/qtcreator/debugger/boosttypes.py index af64c6df7fc..938a0a29670 100644 --- a/share/qtcreator/debugger/boosttypes.py +++ b/share/qtcreator/debugger/boosttypes.py @@ -117,25 +117,25 @@ def qdump__boost__unordered__unordered_set(d, value): innerType = value.type[0] bucketCount = d.extractInt(base + ptrSize) #warn("A BUCKET COUNT: %s" % bucketCount) - #warn("X BUCKET COUNT: %s" % d.parseAndEvaluate("s1.table_.bucket_count_")) + #warn("X BUCKET COUNT: %s" % d.parseAndEvaluate("s1.table_.bucket_count_").value()) try: # boost 1.58 table = value["table_"] bucketsAddr = table["buckets_"].integer() #warn("A BUCKETS: 0x%x" % bucketsAddr) - #warn("X BUCKETS: %s" % d.parseAndEvaluate("s1.table_.buckets_")) + #warn("X BUCKETS: 0x%x" % d.parseAndEvaluate("s1.table_.buckets_").pointer()) lastBucketAddr = bucketsAddr + bucketCount * ptrSize #warn("A LAST BUCKET: 0x%x" % lastBucketAddr) - #warn("X LAST BUCKET: %s" % d.parseAndEvaluate("s1.table_.get_bucket(s1.table_.bucket_count_)")) + #warn("X LAST BUCKET: 0x%x" % d.parseAndEvaluate("s1.table_.get_bucket(s1.table_.bucket_count_)").pointer()) previousStartAddr = lastBucketAddr #warn("A PREVIOUS START: 0x%x" % previousStartAddr) - #warn("X PREVIOUS START: %s" % d.parseAndEvaluate("s1.table_.get_previous_start()")) + #warn("X PREVIOUS START: 0x%x" % d.parseAndEvaluate("s1.table_.get_previous_start()").pointer()) item = d.extractPointer(previousStartAddr) #warn("A KEY ADDR: 0x%x" % item) - #warn("X KEY ADDR: %s" % d.parseAndEvaluate("s1.table_.get_previous_start()->next_")) + #warn("X KEY ADDR: 0x%x" % d.parseAndEvaluate("s1.table_.get_previous_start()->next_").pointer()) item = d.extractPointer(previousStartAddr) #warn("A VALUE: %x" % d.extractInt(item + ptrSize)) - #warn("X VALUE: %s" % d.parseAndEvaluate("*(int*)(s1.table_.get_previous_start()->next_ + 1)")) + #warn("X VALUE: %x" % d.parseAndEvaluate("*(int*)(s1.table_.get_previous_start()->next_ + 1)").integer()) with Children(d, size, maxNumChild=10000): for j in d.childRange(): d.putSubItem(j, d.createValue(item + 2 * ptrSize, innerType)) diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py index c0264a1fdb3..79026875ee2 100644 --- a/share/qtcreator/debugger/dumper.py +++ b/share/qtcreator/debugger/dumper.py @@ -217,13 +217,16 @@ class PairedChildrenData: self.pairType = pairType self.keyType = keyType self.valueType = valueType - self.isCompact = d.isMapCompact(self.keyType, self.valueType) - self.childType = valueType if self.isCompact else pairType class PairedChildren(Children): def __init__(self, d, numChild, useKeyAndValue = False, pairType = None, keyType = None, valueType = None, maxNumChild = None): self.d = d + if pairType is not None: + try: + pairType = pairType.stripTypedefs() + except: + pass if keyType is None: keyType = pairType[0].unqualified() if valueType is None: @@ -233,7 +236,6 @@ class PairedChildren(Children): d.pairData.vname = 'value' if useKeyAndValue else 'second' Children.__init__(self, d, numChild, - d.pairData.childType, maxNumChild = maxNumChild, addrBase = None, addrStep = None) @@ -286,6 +288,8 @@ class DumperBase: self.qtNamespaceToReport = None self.passExceptions = False + self.typeData = {} + self.resetCaches() self.resetStats() @@ -416,7 +420,6 @@ class DumperBase: self.currentValue = ReportItem(); self.currentType = ReportItem(); - def exitSubItem(self, item, exType, exValue, exTraceBack): #warn('CURRENT VALUE: %s: %s %s' % # (self.currentIName, self.currentValue, self.currentType)) @@ -510,6 +513,71 @@ class DumperBase: self.ptrSize = lambda: result return result + def lookupType(self, typeName): + nativeType = self.lookupNativeType(typeName) + return None if nativeType is None else self.fromNativeType(nativeType) + + def listTemplateParameters(self, typename): + targs = [] + if not typename.endswith('>'): + return targs + + def push(inner): + # Handle local struct definitions like QList + inner = inner.strip()[::-1] + p = inner.find(')::') + if p > -1: + inner = inner[p+3:].strip() + if inner.startswith('const '): + inner = inner[6:].strip() + if inner.endswith(' const'): + inner = inner[:-6].strip() + #warn("FOUND: %s" % inner) + targs.append(inner) + + #warn("SPLITTING %s" % typename) + level = 0 + inner = '' + for c in typename[::-1]: # Reversed... + #warn("C: %s" % c) + if c == '>': + if level > 0: + inner += c + level += 1 + elif c == '<': + level -= 1 + if level > 0: + inner += c + else: + push(inner) + inner = '' + elif c == ',': + #warn('c: %s level: %s' % (c, level)) + if level == 1: + push(inner) + inner = '' + else: + inner += c + else: + inner += c + + #warn("TARGS: %s %s" % (typename, targs)) + res = [] + for item in targs[::-1]: + c = ord(item[0]) + if c == '-' or (c >= 48 and c < 58): + if item.find('.') > -1: + res.append(float(item)) + else: + val = toInteger(item) + if val > 0x80000000: + val -= 0x100000000 + res.append(val) + else: + res.append(self.Type(self, item)) + #warn("RES: %s %s" % (typename, [(None if t is None else t.name) for t in res])) + return res + # Hex decoding operating on str, return str. def hexdecode(self, s): if sys.version_info[0] == 2: @@ -822,11 +890,6 @@ class DumperBase: self.putField('sortgroup', sortorder) self.putPlainChildren(value) - def isMapCompact(self, keyType, valueType): - if self.currentItemFormat() == CompactMapFormat: - return True - return keyType.isSimpleType() and valueType.isSimpleType() - def check(self, exp): if not exp: error('Check failed: %s' % exp) @@ -846,8 +909,7 @@ class DumperBase: self.checkIntType(maximum) code = (None, 'b', 'H', None, 'I')[tsize] - #blob = self.readRawMemory(base, maximum) - + #blob = self.readRawMemory(base, 1) blob = bytes() while maximum > 1: try: @@ -1064,7 +1126,7 @@ class DumperBase: itemCount = '100' arrayByteSize = int(itemCount) * innerType.size(); - n = int(arrayByteSize / innerType.size()) + n = arrayByteSize // innerType.size() p = value.address() if displayFormat != RawFormat and p: if innerType.name in ('char', 'wchar_t'): @@ -1212,8 +1274,9 @@ class DumperBase: return False def putFormattedPointer(self, value): + #warn("PUT FORMATTED: %s" % value) pointer = value.pointer() - #warn('POINTER: %s' % pointer) + #warn('POINTER: 0x%x' % pointer) if pointer == 0: #warn('NULL POINTER') self.putType(value.type) @@ -1223,8 +1286,7 @@ class DumperBase: typeName = value.type.name - self.putAddress(pointer) - self.putOriginalAddress(value) + self.putAddress(value.address()) try: self.readRawMemory(pointer, 1) @@ -1238,7 +1300,7 @@ class DumperBase: return displayFormat = self.currentItemFormat(value.type.name) - innerType = value.type.target().unqualified() + innerType = value.type.target() #.unqualified() if innerType.name == 'void': #warn('VOID POINTER: %s' % displayFormat) @@ -1284,19 +1346,21 @@ class DumperBase: #warn('INAME: %s' % self.currentIName) #warn('INNER: %s' % innerType.name) if self.autoDerefPointers or self.currentIName.endswith('.this'): - # Generic pointer type with AutomaticFormat. + derefValue = value.dereference() # Never dereference char types. if innerType.name not in ('char', 'signed char', 'unsigned char', 'wchar_t'): + # Generic pointer type with AutomaticFormat. self.putType(innerType) savedCurrentChildType = self.currentChildType self.currentChildType = innerType.name - self.putItem(value.dereference()) + derefValue.name = '*' + self.putItem(derefValue) self.currentChildType = savedCurrentChildType - self.putOriginalAddress(value) + self.putOriginalAddress(pointer) return #warn('GENERIC PLAIN POINTER: %s' % value.type) - #warn('ADDR PLAIN POINTER: 0x%x' % value.address) + #warn('ADDR PLAIN POINTER: 0x%x' % value.laddress) self.putType(typeName) self.putValue('0x%x' % pointer) self.putNumChild(1) @@ -1305,9 +1369,9 @@ class DumperBase: with SubItem(self, '*'): self.putItem(value.dereference()) - def putOriginalAddress(self, value): - if value.address() is not None: - self.put('origaddr="0x%x",' % value.address()) + def putOriginalAddress(self, address): + if address is not None: + self.put('origaddr="0x%x",' % address) def putQObjectNameValue(self, value): try: @@ -1938,12 +2002,12 @@ class DumperBase: # Should check: innerType == ns::QObjectPrivate::ConnectionList base = self.extractPointer(connections) data, size, alloc = self.vectorDataHelper(base) - connectionType = self.createType('@QObjectPrivate::Connection*') + connectionType = self.createType('@QObjectPrivate::Connection') for i in xrange(size): first = self.extractPointer(data + i * 2 * ptrSize) while first: self.putSubItem('%s' % pp, - self.createValue(first, connectionType)) + self.createPointerValue(first, connectionType)) first = self.extractPointer(first + 3 * ptrSize) # We need to enforce some upper limit. pp += 1 @@ -1974,7 +2038,8 @@ class DumperBase: self.checkIntType(n) addrBase = base innerSize = innerType.size() - #warn('ADDRESS: %s INNERSIZE: %s INNERTYPE: %s' % (addrBase, innerSize, innerType)) + self.putNumChild(n) + #warn('ADDRESS: 0x%x INNERSIZE: %s INNERTYPE: %s' % (addrBase, innerSize, innerType)) enc = innerType.simpleEncoding() if enc: self.put('childtype="%s",' % innerType.name) @@ -2466,7 +2531,7 @@ class DumperBase: return False def putItem(self, value): - #warn('ITEM: %s' % value.stringify()) + #warn('PUT ITEM: %s' % value.stringify()) typeobj = value.type #unqualified() typeName = typeobj.name @@ -2489,8 +2554,9 @@ class DumperBase: return if typeobj.code == TypeCodeTypedef: - strippedType = typeobj.stripTypedefs() - self.putItem(value.cast(strippedType)) + #warn('TYPEDEF VALUE: %s' % value.stringify()) + #strippedType = typeobj.ltarget + self.putItem(value.detypedef()) if value.lbitsize is not None and value.lbitsize != value.type.size() * 8: typeName += ' : %s' % value.lbitsize self.putBetterType(typeName) @@ -2535,13 +2601,10 @@ class DumperBase: return if typeobj.code == TypeCodeReference: - target = typeobj.target() - if self.isLldb: - item = value.cast(target.pointer()).dereference() - else: - item = value.cast(target.unqualified()) - self.putItem(item) - self.putBetterType(target.name + ' &') + #warn('REFERENCE VALUE: %s' % value) + val = value.dereference() + self.putItem(val) + self.putBetterType(typeName) return if typeobj.code == TypeCodeComplex: @@ -2574,8 +2637,8 @@ class DumperBase: self.putType(typeName) self.putNumChild(1) self.putEmptyValue() - #warn('STRUCT GUTS: %s ADDRESS: %s ' % (value.name, value.address())) - #metaObjectPtr = self.extractMetaObjectPtr(value.address(), value.type) + #warn('STRUCT GUTS: %s ADDRESS: 0x%x ' % (value.name, value.address())) + metaObjectPtr = self.extractMetaObjectPtr(value.address(), value.type) if self.showQObjectNames: self.preping(self.currentIName) metaObjectPtr = self.extractMetaObjectPtr(value.address(), value.type) @@ -2607,9 +2670,6 @@ class DumperBase: return tiVersion return None - def lookupType(self, typestring): - return self.fromNativeType(self.lookupNativeType(typestring)) - def addToCache(self, typeobj): typename = typeobj.name if typename in self.typesReported: @@ -2622,11 +2682,12 @@ class DumperBase: self.dumper = dumper self.name = None self.type = None - self.ldata = None - self.laddress = None + self.ldata = None # Target address in case of references and pointers. + self.laddress = None # Own address. self.lIsInScope = True self.ldisplay = None self.lbitsize = None + self.targetValue = None # For references. def check(self): if self.laddress is not None and not self.dumper.isInt(self.laddress): @@ -2649,7 +2710,8 @@ class DumperBase: def display(self): if self.type.code == TypeCodeEnum: - return self.type.enumDisplay(self.extractInteger(self.type.bitsize(), False)) + intval = self.extractInteger(self.type.bitsize(), False) + return self.type.typeData.enumDisplay(intval) simple = self.value() if simple is not None: return str(simple) @@ -2663,30 +2725,38 @@ class DumperBase: return 'value of type %s at address 0x%x' % (self.type.name, self.laddress) return '' + def pointer(self): + if self.type.code == TypeCodeTypedef: + return self.detypedef().pointer() + return self.extractInteger(self.dumper.ptrSize() * 8, True) + def integer(self): - unsigned = self.type.stripTypedefs().name.startswith('unsigned') + if self.type.code == TypeCodeTypedef: + return self.detypedef().integer() + unsigned = self.type.name.startswith('unsigned') bitsize = self.type.bitsize() return self.extractInteger(bitsize, unsigned) def floatingPoint(self): + if self.type.code == TypeCodeTypedef: + return self.detypedef().floatingPoint() if self.type.size() == 8: return self.extractSomething('d', 64) if self.type.size() == 4: return self.extractSomething('f', 32) error('BAD FLOAT DATA: %s SIZE: %s' % (self, self.type.size())) - def pointer(self): - return self.extractInteger(8 * self.dumper.ptrSize(), True) - def value(self): if self.type is not None: + if self.type.code == TypeCodeTypedef: + return self.detypedef().value() if self.type.code == TypeCodeIntegral: return self.integer() if self.type.code == TypeCodeFloat: return self.floatingPoint() if self.type.code == TypeCodeTypedef: - return self.cast(self.type.stripTypedefs()).value() - if self.type.stripTypedefs().code == TypeCodePointer: + return self.cast(self.type.ltarget).value() + if self.type.code == TypeCodePointer: return self.pointer() return None @@ -2697,8 +2767,8 @@ class DumperBase: #warn('GET ITEM %s %s' % (self, index)) self.check() if self.type.code == TypeCodeTypedef: - #warn('GET ITEM %s STRIP TYPEDEFS TO %s' % (self, self.type.stripTypedefs())) - return self.cast(self.type.stripTypedefs()).__getitem__(index) + #warn('GET ITEM STRIP TYPEDEFS TO %s' % self.type.ltarget) + return self.cast(self.type.ltarget).__getitem__(index) if isinstance(index, str): if self.type.code == TypeCodePointer: #warn('GET ITEM %s DEREFERENCE TO %s' % (self, self.dereference())) @@ -2725,7 +2795,9 @@ class DumperBase: def extractField(self, field): if self.type.code == TypeCodeTypedef: - return self.cast(self.type.stripTypedefs()).extractField(field) + return self.cast(self.type.ltarget).extractField(field) + if self.type.code == TypeCodeReference: + return self.dereference().extractField(field) if not isinstance(field, self.dumper.Field): error('BAD INDEX TYPE %s' % type(field)) @@ -2756,15 +2828,12 @@ class DumperBase: val.type = None 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 fieldType.code == TypeCodePointer: + objectAddress = self.dumper.extractPointer(val.laddress) + val = self.dumper.createPointerValue(objectAddress, fieldType.ltarget) + elif fieldType.code == TypeCodeReference: + objectAddress = self.dumper.extractPointer(val.laddress) + val = self.dumper.createReferenceValue(objectAddress, fieldType.ltarget) if val.type is None: val.type = fieldType @@ -2795,27 +2864,54 @@ class DumperBase: def dereference(self): self.check() + if self.type.code == TypeCodeTypedef: + return self.detypedef().dereference() val = self.dumper.Value(self.dumper) - val.type = self.type.dereference() - val.laddress = self.pointer() - dynTypeName = self.dumper.dynamicTypeName(val.type, val.laddress) - if dynTypeName is not None: - val.type = self.dumper.createType(dynTypeName) + if self.type.code == TypeCodeReference: + val.laddress = self.pointer() + if val.laddress is None and self.laddress is not None: + val.laddress = self.laddress + val.type = self.type.dereference().dynamicType(val.laddress) + elif self.type.code == TypeCodePointer: + val.laddress = self.pointer() + val.type = self.type.dereference().dynamicType(val.laddress) + else: + error("WRONG: %s" % self.type.code) + #warn("DEREFERENCING FROM: %s" % self) + #warn("DEREFERENCING TO: %s" % val) + #dynTypeName = val.type.dynamicTypeName(val.laddress) + #if dynTypeName is not None: + # val.type = self.dumper.createType(dynTypeName) + return val + + def detypedef(self): + self.check() + if self.type.code != TypeCodeTypedef: + error("WRONG") + val = self.dumper.Value(self.dumper) + val.type = self.type.ltarget + val.ldata = self.ldata + val.laddress = self.laddress + #warn("DETYPEDEF FROM: %s" % self) + #warn("DETYPEDEF TO: %s" % val) return val def extend(self, size): if self.type.size() < size: val = self.dumper.Value(self.dumper) val.laddress = None - if sys.version_info[0] == 3: - val.ldata = self.ldata + bytes('\0' * (size - self.type.size()), encoding='latin1') - else: - val.ldata = self.ldata + bytes('\0' * (size - self.type.size())) + val.ldata = self.zeroExtend(self.ldata) return val if self.type.size() == size: return self error('NOT IMPLEMENTED') + def zeroExtend(self, data, size): + if sys.version_info[0] == 3: + return data + bytes('\0' * (size - len(data)), encoding='latin1') + else: + return data + bytes('\0' * (size - len(data))) + def cast(self, typish): self.check() val = self.dumper.Value(self.dumper) @@ -2843,12 +2939,15 @@ class DumperBase: return self.ldata if size < len(self.ldata): return self.ldata[:size] + #error('ZERO-EXTENDING DATA TO %s BYTES: %s' % (size, self)) + return self.zeroExtend(self.ldata, size) if self.laddress is not None: if size is None: size = self.type.size() res = self.dumper.readRawMemory(self.laddress, size) if len(res) > 0: return res + error('CANNOT CONVERT ADDRESS TO BYTES: %s' % self) error('CANNOT CONVERT TO BYTES: %s' % self) def extractInteger(self, bitsize, unsigned): @@ -2892,8 +2991,8 @@ class DumperBase: if field.isStruct: if field.ltype != field.fieldType(): error('DO NOT SIMPLIFY') - #warn('FIELD POS: %s' % field.ltype) - #warn('FIELD TYE: %s' % field.fieldType()) + #warn('FIELD POS: %s' % field.ltype.stringify()) + #warn('FIELD TYE: %s' % field.fieldType().stringify()) res = self.dumper.createValue(thing, field.fieldType()) #warn('RES TYPE: %s' % res.type) if self.laddress is not None: @@ -2908,75 +3007,151 @@ class DumperBase: ptr = p if self.isInt(p) else p.pointer() 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) + def type(self, typeId): + return self.typeData.get(typeId) - class Type: + def registerType(self, typeId, tdata): + #warn('REGISTER TYPE: %s' % typeId) + self.typeData[typeId] = tdata + #typeId = typeId.replace(' ', '') + #self.typeData[typeId] = tdata + #warn('REGISTERED: %s' % self.typeData) + + def registerTypeAlias(self, existingTypeId, aliasId): + #warn('REGISTER ALIAS %s FOR %s' % (aliasId, existingTypeId)) + self.typeData[aliasId] = self.typeData[existingTypeId] + + class TypeData: def __init__(self, dumper): self.dumper = dumper - self.name = None - self.nativeType = None - self.lfields = None + self.lfields = [] self.lbitsize = None self.lbitpos = None self.ltarget = None # Inner type for arrays - self.templateArguments = None + self.templateArguments = [] self.code = None + self.name = None + self.typeId = None + self.enumDisplay = str + + class Type: + def __init__(self, dumper, typeId): + self.typeId = typeId + self.dumper = dumper def __str__(self): - self.check() - error('Not implemented') - return self.name - #error('Not implemented') + #return self.typeId + return self.stringify() + + @property + def typeData(self): + tdata = self.dumper.typeData.get(self.typeId, None) + if tdata is not None: + #warn('USING : %s' % self.typeId) + return tdata + typeId = self.typeId.replace(' ', '') + if tdata is not None: + #warn('USING FALLBACK : %s' % self.typeId) + return tdata + #warn('EXPANDING LAZILY: %s' % self.typeId) + self.dumper.lookupType(self.typeId) + return self.dumper.typeData.get(self.typeId) + + @property + def name(self): + tdata = self.typeData + if tdata is None: + return self.typeId + return tdata.name + + @property + def code(self): + return self.typeData.code + + @property + def lbitsize(self): + return self.typeData.lbitsize + + @property + def lbitpos(self): + return self.typeData.lbitpos + + @property + def ltarget(self): + return self.typeData.ltarget + + @property + def lfields(self): + return self.typeData.lfields def stringify(self): - return 'Type(name="%s",bsize=%s,bpos=%s,code=%s,ntype=%s)' \ - % (self.name, self.lbitsize, self.lbitpos, self.code, self.nativeType) + tdata = self.typeData + if tdata is None: + return 'Type(id="%s")' % self.typeId + return 'Type(name="%s",bsize=%s,bpos=%s,code=%s)' \ + % (tdata.name, tdata.lbitsize, tdata.lbitpos, tdata.code) def __getitem__(self, index): if self.dumper.isInt(index): return self.templateArgument(index) error('CANNOT INDEX TYPE') + def dynamicTypeName(self, address): + tdata = self.typeData + if tdata is None: + return None + if tdata.code != TypeCodeStruct: + return None + try: + vtbl = self.dumper.extractPointer(address) + except: + return None + #warn('VTBL: 0x%x' % vtbl) + if not self.dumper.canBePointer(vtbl): + return None + return self.dumper.nativeDynamicTypeName(address, self) + + def dynamicType(self, address): + dynTypeName = self.dynamicTypeName(address) + if dynTypeName is not None: + return self.dumper.createType(dynTypeName) + return self + def check(self): - if self.name is None: - error('TYPE WITHOUT NAME') + tdata = self.typeData + if tdata is None: + error('TYPE WITHOUT DATA: %s ALL: %s' % (self.typeId, self.dumper.typeData.keys())) + if tdata.name is None: + error('TYPE WITHOUT NAME: %s' % self.typeId) def dereference(self): + if self.code == TypeCodeTypedef: + return self.ltarget.dereference() self.check() - if self.nativeType is not None: - return self.dumper.nativeTypeDereference(self.nativeType) - error('DONT KNOW HOW TO DEREF: %s' % self.name) + return self.ltarget def unqualified(self): - if self.nativeType is not None: - return self.dumper.nativeTypeUnqualified(self.nativeType) return self def templateArgument(self, position, numeric = False): - if self.templateArguments is not None: - return self.templateArguments[position] - nativeType = self.nativeType - #warn('NATIVE TYPE 0: %s' % dir(nativeType)) - if nativeType is None: - nativeType = self.dumper.lookupNativeType(self.name) - #warn('NATIVE TYPE 1: %s' % dir(nativeType)) - if nativeType is not None: - return self.dumper.nativeTypeTemplateArgument(nativeType, position, numeric) - res = self.dumper.extractTemplateArgument(self.name, position) - #warn('TEMPLATE ARG: RES: %s' % res) - if numeric: - return int(res) - return self.dumper.createType(res) + tdata = self.typeData + #warn('TDATA: %s' % tdata) + #warn('ID: %s' % self.typeId) + if tdata is None: + # Native lookups didn't help. Happens for 'wrong' placement of 'const' + # etc. with LLDB. But not all is lost: + ta = self.dumper.listTemplateParameters(self.typeId) + #warn('MANUAL: %s' % ta) + res = ta[position] + #warn('RES: %s' % res.typeId) + return res + #warn('TA: %s %s' % (position, self.typeId)) + #warn('ARGS: %s' % tdata.templateArguments) + res = tdata.templateArguments[position] + #if tdata.templateArguments is not None: + #if numeric: + # return tdata.templateArguments[position].value() + return res def simpleEncoding(self): res = { @@ -2999,10 +3174,11 @@ class DumperBase: return self.code in (TypeCodeIntegral, TypeCodeFloat, TypeCodeEnum) def alignment(self): + #warn('ALIGN: %s' % self.stringify()) if self.code == TypeCodeTypedef: - return self.stripTypedefs().alignment() + return self.ltarget.alignment() if self.isSimpleType(): - if self.name == 'double': + if self.name in ('double', 'long long', 'unsigned long long'): return self.dumper.ptrSize() # Crude approximation. return self.size() if self.code == TypeCodePointer: @@ -3010,6 +3186,7 @@ class DumperBase: fields = self.fields() align = 1 for field in fields: + #warn(' SUBFIELD: %s TYPE %s' % (field.name, field.fieldType().name)) a = field.fieldType().alignment() #warn(' SUBFIELD: %s ALIGN: %s' % (field.name, a)) if a is not None and a > align: @@ -3018,9 +3195,7 @@ class DumperBase: return align def pointer(self): - if self.nativeType is not None: - return self.dumper.nativeTypePointer(self.nativeType) - error('Cannot create pointer type for %s' % self) + return self.dumper.createPointerType(self) def splitArrayType(self): # -> (inner type, count) @@ -3033,44 +3208,17 @@ class DumperBase: return (self.dumper.createType(s[0:pos1].strip()), int(s[pos1+1:pos2])) def target(self): - if self.nativeType is not None: - target = self.dumper.nativeTypeTarget(self.nativeType) - #warn('DEREFERENCING: %s -> %s ' % (self.nativeType, target)) - if target is not None: - return target - if self.code == TypeCodeArray: - (innerType, itemCount) = self.splitArrayType() - #warn('EXTRACTING ARRAY TYPE: %s -> %s' % (self, innerType)) - # HACK for LLDB 320: - if innerType.code is None and innerType.name.endswith(']'): - innerType.code = TypeCodeArray - return innerType - - strippedType = self.stripTypedefs() - if strippedType.name != self.name: - return strippedType.target() - error('DONT KNOW TARGET FOR: %s' % self) + return self.typeData.ltarget def fields(self): - #warn('GETTING FIELDS FOR: %s' % self.name) - if self.lfields is not None: - warn('USING LFIELDS: %s' % self.lfields) - return self.lfields - nativeType = self.nativeType - if nativeType is None: - nativeType = self.dumper.lookupNativeType(self.name) - #warn('FIELDS LOOKING UP NATIVE TYPE FOR %s -> %s' % (self.name, nativeType)) - if nativeType is not None: - #warn('FIELDS USING NATIVE TYPE %s' % nativeType) - fields = self.dumper.nativeTypeFields(nativeType) - #warn('FIELDS RES: %s FOR %s' % (fields, nativeType)) - return fields - error('DONT KNOW FIELDS FOR: %s' % self.stringify()) - return [] + if self.code == TypeCodeTypedef: + return self.ltarget.fields() + return self.lfields def firstBase(self): - if self.nativeType is not None: - return self.dumper.nativeTypeFirstBase(self.nativeType) + lfields = self.fields() + if len(lfields) > 0 and lfields[0].isBaseClass: + return lfields[0].ltype return None def field(self, name, bitoffset = 0): @@ -3094,14 +3242,10 @@ class DumperBase: return None def stripTypedefs(self): - if self.code != TypeCodeTypedef: + if isinstance(self, self.dumper.Type) and self.code != TypeCodeTypedef: #warn('NO TYPEDEF: %s' % self) return self - if self.nativeType is not None: - res = self.dumper.nativeTypeStripTypedefs(self.nativeType) - #warn('STRIP TYPEDEF: %s -> %s' % (self, res)) - return res - error('DONT KNOW HOW TO STRIP TYPEDEFS FROM %s' % s) + return self.ltarget def size(self): bs = self.bitsize() @@ -3136,11 +3280,6 @@ class DumperBase: return True return strippedName == 'QStringList' and self.dumper.qtVersion() >= 0x050000 - def enumDisplay(self, intval): - if self.nativeType is not None: - return self.dumper.nativeTypeEnumDisplay(self.nativeType, intval) - return '%d' % intval - class Field: def __init__(self, dumper): self.dumper = dumper @@ -3159,8 +3298,8 @@ class DumperBase: return ('Field(name="%s",ltype=%s,parentType=%s,bpos=%s,bsize=%s,' + 'bidx=%s,nidx=%s)') \ % (self.name, - None if self.ltype is None else self.ltype.name, - None if self.parentType is None else self.parentType.name, + self.ltype.stringify(), + self.parentType.typeId, self.lbitpos, self.lbitsize, self.baseIndex, self.nativeIndex) @@ -3207,11 +3346,122 @@ class DumperBase: #error('CANT GET FIELD TYPE FOR %s' % self) return None + def toPointerData(self, address): + if not self.isInt(address): + error('wrong') + size = self.ptrSize() + code = 'I' if size == 4 else 'Q' + return bytes(struct.pack(code, address)) + + def createPointerValue(self, targetAddress, targetType): + if not isinstance(targetType, self.Type): + error('Expected type in createPointerValue(), got %s' + % type(targetType)) + if not self.isInt(targetAddress): + error('Expected integral address value in createPointerValue(), got %s' + % type(targetType)) + val = self.Value(self) + val.ldata = self.toPointerData(targetAddress) + targetType = targetType.dynamicType(targetAddress) + val.type = self.createPointerType(targetType) + return val + + def createReferenceValue(self, targetAddress, targetType): + if not isinstance(targetType, self.Type): + error('Expected type in createReferenceValue(), got %s' + % type(targetType)) + if not self.isInt(targetAddress): + error('Expected integral address value in createReferenceValue(), got %s' + % type(targetType)) + val = self.Value(self) + val.ldata = self.toPointerData(targetAddress) + targetType = targetType.dynamicType(targetAddress) + val.type = self.createReferenceType(targetType) + return val + + def createPointerType(self, targetType): + if not isinstance(targetType, self.Type): + error('Expected type in createPointerType(), got %s' + % type(targetType)) + typeId = targetType.typeId + ' *' + tdata = self.TypeData(self) + tdata.name = targetType.name + '*' + tdata.typeId = typeId + tdata.lbitsize = 8 * self.ptrSize() + tdata.code = TypeCodePointer + tdata.ltarget = targetType + tdata.lfields = [] + self.registerType(typeId, tdata) + return self.Type(self, typeId) + + def createReferenceType(self, targetType): + if not isinstance(targetType, self.Type): + error('Expected type in createReferenceType(), got %s' + % type(targetType)) + typeId = targetType.typeId + ' &' + tdata = self.TypeData(self) + tdata.name = targetType.name + ' &' + tdata.typeId = typeId + tdata.code = TypeCodeReference + tdata.ltarget = targetType + tdata.lbitsize = 8 * self.ptrSize() # Needed for Gdb13393 test. + #tdata.lbitsize = None + self.registerType(typeId, tdata) + return self.Type(self, typeId) + + def createArrayType(self, targetType, count): + if not isinstance(targetType, self.Type): + error('Expected type in createArrayType(), got %s' + % type(targetType)) + typeId = '%s[%d]' % (targetType.typeId, count) + tdata = self.TypeData(self) + tdata.name = '%s[%d]' % (targetType.name, count) + tdata.typeId = typeId + tdata.code = TypeCodeArray + tdata.ltarget = targetType + tdata.lbitsize = count * targetType.lbitsize + fields = [] + for i in range(count): + field = self.Field(self) + field.ltype = targetType + field.parentType = None + field.isBaseClass = False + field.lbitsize = targetType.lbitsize + field.lbitpos = i * targetType.lbitsize * 8 + fields.append(field) + #tdata.lfields = fields + self.registerType(typeId, tdata) + return self.Type(self, typeId) + + def createTypedefedType(self, targetType, typeId): + if not isinstance(targetType, self.Type): + error('Expected type in createTypedefType(), got %s' + % type(targetType)) + # Happens for C-style struct in GDB: typedef { int x; } struct S1; + if targetType.typeId == typeId: + return targetType + tdata = self.TypeData(self) + tdata.name = typeId + tdata.typeId = typeId + tdata.code = TypeCodeTypedef + tdata.ltarget = targetType + tdata.lbitsize = targetType.lbitsize + tdata.lfields = targetType.lfields + self.registerType(typeId, tdata) + return self.Type(self, typeId) + def createType(self, typish, size = None): if isinstance(typish, self.Type): - typish.check() + #typish.check() return typish if isinstance(typish, str): + if typish.endswith(']') and not typish.endswith('[]'): + # Array fallback. + pos1 = typish.rfind('[') + itemType = self.createType(typish[0:pos1].strip()) + itemCount = int(typish[pos1+1:-1]) + return self.createArrayType(itemType, itemCount) + def knownSize(tn): if tn[0] == 'Q': if tn in ('QByteArray', 'QString', 'QList', 'QStringList', @@ -3234,26 +3484,35 @@ class DumperBase: ns = self.qtNamespace() typish = typish.replace('@', ns) if typish.startswith(ns): - size = knownSize(typish[len(ns):]) + if size is None: + size = knownSize(typish[len(ns):]) else: - size = knownSize(typish) + if size is None: + size = knownSize(typish) if size is not None: typish = ns + typish - #typeobj = self.Type(self) - #typeobj.name = typish - nativeType = self.lookupNativeType(typish) # FIXME: Remove? - #warn('FOUND NAT TYPE: %s' % dir(nativeType)) - if nativeType is not None: + + tdata = self.typeData.get(typish, None) + if tdata is not None: + return self.Type(self, typish) + + knownType = self.lookupType(typish) + #warn('KNOWN: %s' % knownType) + if knownType is not None: #warn('USE FROM NATIVE') - typeobj = self.fromNativeType(nativeType) - else: - #warn('FAKING') - typeobj = self.Type(self) - typeobj.name = typish - if size is not None: - typeobj.lbitsize = 8 * size - #warn('CREATE TYPE: %s' % typeobj) + return knownType + + #warn('FAKING: %s SIZE: %s' % (typish, size)) + tdata = self.TypeData(self) + tdata.name = typish + tdata.typeId = typish + + if size is not None: + tdata.lbitsize = 8 * size + self.registerType(typish, tdata) + typeobj = self.Type(self, typish) + #warn('CREATE TYPE: %s' % typeobj.stringify()) typeobj.check() return typeobj error('NEED TYPE, NOT %s' % type(typish)) @@ -3262,38 +3521,37 @@ class DumperBase: val = self.Value(self) val.type = self.createType(typish) if self.isInt(datish): # Used as address. + #warn('CREATING %s AT 0x%x' % (val.type.name, datish)) val.laddress = datish - #warn('CREATING %s AT 0x%x' % (val.type.name, address)) - elif isinstance(datish, bytes): - val.ldata = datish - val.type.lbitsize = 8 * len(datish) + val.type = val.type.dynamicType(datish) + return val + if isinstance(datish, bytes): #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.ldata = datish + val.check() + return val + error('EXPECTING ADDRESS OR BYTES, GOT %s' % type(datish)) + + def createContainerItem(self, data, innerTypish, container): + innerType = self.createType(innerTypish) + name = self.qtNamespace() + '%s<%s>' % (container, innerType.name) + typeId = name + tdata = self.TypeData(self) + tdata.typeId = typeId + tdata.name = name + tdata.templateArguments = [innerType] + tdata.lbitsize = 8 * self.ptrSize() + self.registerType(typeId, tdata) + val = self.Value(self) + val.ldata = data + val.type = self.Type(self, typeId) return val def createListItem(self, data, innerTypish): - innerType = self.createType(innerTypish) - typeobj = self.Type(self) - typeobj.name = self.qtNamespace() + 'QList<%s>' % innerType.name - typeobj.templateArguments = [innerType] - typeobj.lbitsize = 8 * self.ptrSize() - val = self.Value(self) - val.ldata = data - val.type = typeobj - return val + return self.createContainerItem(data, innerTypish, 'QList') def createVectorItem(self, data, innerTypish): - innerType = self.createType(innerTypish) - typeobj = self.Type(self) - typeobj.name = self.qtNamespace() + 'QVector<%s>' % innerType.name - typeobj.templateArguments = [innerType] - typeobj.lbitsize = 8 * self.ptrSize() - val = self.Value(self) - val.ldata = data - val.type = typeobj - return val + return self.createContainerItem(data, innerTypish, 'QVector') class StructBuilder: def __init__(self, dumper): diff --git a/share/qtcreator/debugger/gdbbridge.py b/share/qtcreator/debugger/gdbbridge.py index 9ab49555f51..b1db09ad15d 100644 --- a/share/qtcreator/debugger/gdbbridge.py +++ b/share/qtcreator/debugger/gdbbridge.py @@ -205,17 +205,46 @@ class Dumper(DumperBase): self.output = [] self.setVariableFetchingOptions(args) - def fromNativeDowncastableValue(self, nativeValue): + def fromFrameValue(self, nativeValue): + val = nativeValue if self.useDynamicType: try: - return self.fromNativeValue(nativeValue.cast(nativeValue.dynamic_type)) + val = nativeValue.cast(nativeValue.dynamic_type) except: pass - return self.fromNativeValue(nativeValue) + return self.fromNativeValue(val) def fromNativeValue(self, nativeValue): - #self.check(isinstance(nativeValue, gdb.Value)) + #warn("FROM NATIVE VALUE: %s" % nativeValue) + self.check(isinstance(nativeValue, gdb.Value)) nativeType = nativeValue.type + code = nativeType.code + if code == gdb.TYPE_CODE_REF: + targetType = self.fromNativeType(nativeType.target().unqualified()) + val = self.createReferenceValue(toInteger(nativeValue.address), targetType) + #warn("CREATED REF: %s" % val) + return val + if code == gdb.TYPE_CODE_PTR: + targetType = self.fromNativeType(nativeType.target().unqualified()) + val = self.createPointerValue(toInteger(nativeValue), targetType) + #warn("CREATED PTR 1: %s" % val) + if not nativeValue.address is None: + val.laddress = toInteger(nativeValue.address) + #warn("CREATED PTR 2: %s" % val) + return val + if code == gdb.TYPE_CODE_TYPEDEF: + targetType = nativeType.strip_typedefs().unqualified() + #warn("TARGET TYPE: %s" % targetType) + if targetType.code == gdb.TYPE_CODE_ARRAY: + val = self.Value(self) + val.laddress = toInteger(nativeValue.address) + else: + # Cast may fail (e.g for arrays, see test for Bug5799) + val = self.fromNativeValue(nativeValue.cast(targetType)) + val.type = self.fromNativeType(nativeType) + #warn("CREATED TYPEDEF: %s" % val) + return val + val = self.Value(self) if not nativeValue.address is None: val.laddress = toInteger(nativeValue.address) @@ -238,82 +267,131 @@ class Dumper(DumperBase): 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() + #elif code == gdb.TYPE_CODE_ARRAY: + # val.type.ltarget = nativeValue[0].type.unqualified() return val + def ptrSize(self): + result = gdb.lookup_type('void').pointer().sizeof + self.ptrSize = lambda: result + return result + def fromNativeType(self, nativeType): self.check(isinstance(nativeType, gdb.Type)) - typeobj = self.Type(self) - typeobj.nativeType = nativeType.unqualified() - typeobj.name = str(typeobj.nativeType) - typeobj.lbitsize = nativeType.sizeof * 8 - typeobj.code = { - gdb.TYPE_CODE_TYPEDEF : TypeCodeTypedef, - gdb.TYPE_CODE_METHOD : TypeCodeFunction, - gdb.TYPE_CODE_VOID : TypeCodeVoid, - gdb.TYPE_CODE_FUNC : TypeCodeFunction, - gdb.TYPE_CODE_METHODPTR : TypeCodeFunction, - gdb.TYPE_CODE_MEMBERPTR : TypeCodeFunction, - gdb.TYPE_CODE_PTR : TypeCodePointer, - gdb.TYPE_CODE_REF : TypeCodeReference, - gdb.TYPE_CODE_BOOL : TypeCodeIntegral, - gdb.TYPE_CODE_CHAR : TypeCodeIntegral, - gdb.TYPE_CODE_INT : TypeCodeIntegral, - gdb.TYPE_CODE_FLT : TypeCodeFloat, - gdb.TYPE_CODE_ENUM : TypeCodeEnum, - gdb.TYPE_CODE_ARRAY : TypeCodeArray, - gdb.TYPE_CODE_STRUCT : TypeCodeStruct, - gdb.TYPE_CODE_UNION : TypeCodeStruct, - gdb.TYPE_CODE_COMPLEX : TypeCodeComplex, - gdb.TYPE_CODE_STRING : TypeCodeFortranString, - }[nativeType.code] - return typeobj + code = nativeType.code + #warn('FROM NATIVE TYPE: %s' % nativeType) + #nativeType = nativeType.unqualified() - def nativeTypeDereference(self, nativeType): - return self.fromNativeType(nativeType.strip_typedefs().target()) + if code == gdb.TYPE_CODE_PTR: + #warn('PTR') + targetType = self.fromNativeType(nativeType.target().unqualified()) + return self.createPointerType(targetType) - def nativeTypeUnqualified(self, nativeType): - return self.fromNativeType(nativeType.unqualified()) + if code == gdb.TYPE_CODE_REF: + #warn('REF') + targetType = self.fromNativeType(nativeType.target().unqualified()) + return self.createReferenceType(targetType) - def nativeTypePointer(self, nativeType): - return self.fromNativeType(nativeType.pointer()) + if code == gdb.TYPE_CODE_ARRAY: + #warn('ARRAY') + nativeTargetType = nativeType.target().unqualified() + targetType = self.fromNativeType(nativeTargetType) + count = nativeType.sizeof // nativeTargetType.sizeof + return self.createArrayType(targetType, count) - def nativeTypeTarget(self, nativeType): - while nativeType.code == gdb.TYPE_CODE_TYPEDEF: - nativeType = nativeType.strip_typedefs().unqualified() - return self.fromNativeType(nativeType.target()) + if code == gdb.TYPE_CODE_TYPEDEF: + #warn('TYPEDEF') + nativeTargetType = nativeType.unqualified() + while nativeTargetType.code == gdb.TYPE_CODE_TYPEDEF: + nativeTargetType = nativeTargetType.strip_typedefs().unqualified() + targetType = self.fromNativeType(nativeTargetType) + return self.createTypedefedType(targetType, str(nativeType)) - def nativeTypeFirstBase(self, nativeType): - nativeFields = nativeType.fields() - if len(nativeFields) and nativeFields[0].is_base_class: - return self.fromNativeType(nativeFields[0].type) + if code == gdb.TYPE_CODE_ERROR: + warn('Type error: %s' % nativeType) + return self.Type(self, '') + + typeId = self.nativeTypeId(nativeType) + res = self.typeData.get(typeId, None) + if res is None: + tdata = self.TypeData(self) + tdata.name = str(nativeType) + tdata.typeId = typeId + tdata.lbitsize = nativeType.sizeof * 8 + tdata.code = { + #gdb.TYPE_CODE_TYPEDEF : TypeCodeTypedef, # Handled above. + gdb.TYPE_CODE_METHOD : TypeCodeFunction, + gdb.TYPE_CODE_VOID : TypeCodeVoid, + gdb.TYPE_CODE_FUNC : TypeCodeFunction, + gdb.TYPE_CODE_METHODPTR : TypeCodeFunction, + gdb.TYPE_CODE_MEMBERPTR : TypeCodeFunction, + #gdb.TYPE_CODE_PTR : TypeCodePointer, # Handled above. + #gdb.TYPE_CODE_REF : TypeCodeReference, # Handled above. + gdb.TYPE_CODE_BOOL : TypeCodeIntegral, + gdb.TYPE_CODE_CHAR : TypeCodeIntegral, + gdb.TYPE_CODE_INT : TypeCodeIntegral, + gdb.TYPE_CODE_FLT : TypeCodeFloat, + gdb.TYPE_CODE_ENUM : TypeCodeEnum, + #gdb.TYPE_CODE_ARRAY : TypeCodeArray, + gdb.TYPE_CODE_STRUCT : TypeCodeStruct, + gdb.TYPE_CODE_UNION : TypeCodeStruct, + gdb.TYPE_CODE_COMPLEX : TypeCodeComplex, + gdb.TYPE_CODE_STRING : TypeCodeFortranString, + }[code] + if tdata.code == TypeCodeEnum: + tdata.enumDisplay = lambda intval: self.nativeTypeEnumDisplay(nativeType, intval) + self.registerType(typeId, tdata) # Prevent recursion in fields. + tdata.lfields = self.listFields(nativeType, self.Type(self, typeId)) + tdata.templateArguments = self.listTemplateParameters(nativeType) + self.registerType(typeId, tdata) # Fix up fields and template args + # warn('CREATE TYPE: %s' % typeId) + #else: + # warn('REUSE TYPE: %s' % typeId) + return self.Type(self, typeId) + + def listTemplateParameters(self, nativeType): + targs = [] + pos = 0 + while True: + try: + targ = nativeType.template_argument(pos) + except: + break + if isinstance(targ, gdb.Type): + targs.append(self.fromNativeType(targ.unqualified())) + elif isinstance(targ, gdb.Value): + #targs.append(self.fromNativeValue(targ)) + targs.append(self.fromNativeValue(targ).value()) + else: + error('CRAP') + pos += 1 + return targs def nativeTypeEnumDisplay(self, nativeType, intval): try: - val = gdb.parse_and_eval("(%s)%d" % (nativeType, intval)) - return "%s (%d)" % (val, intval) + val = gdb.parse_and_eval('(%s)%d' % (nativeType, intval)) + return '%s (%d)' % (val, intval) except: - return "%d" % intval + return '%d' % intval - def nativeTypeFields(self, nativeType): - if nativeType.code == gdb.TYPE_CODE_TYPEDEF: - return self.nativeTypeFields(nativeType.strip_typedefs()) + def nativeTypeId(self, nativeType): + name = str(nativeType) + if len(name) == 0: + c = '0' + elif name == 'struct {...}': + c = 's' + elif name == 'union {...}': + c = 'u' + else: + return name + typeId = c + ''.join(['{%s:%s}' % (f.name, self.nativeTypeId(f.type)) for f in nativeType.fields()]) + return typeId + + def listFields(self, nativeType, parentType): + #if nativeType.code == gdb.TYPE_CODE_TYPEDEF: + # return self.listFields(nativeType.strip_typedefs(), parentType) fields = [] - if nativeType.code == gdb.TYPE_CODE_ARRAY: - # An array. - typeobj = nativeType.strip_typedefs() - innerType = typeobj.target() - for i in xrange(int(typeobj.sizeof / innerType.sizeof)): - field = self.Field(self) - field.ltype = self.fromNativeType(innerType) - field.parentType = self.fromNativeType(nativeType) - field.isBaseClass = False - field.lbitsize = innerType.sizeof - field.lbitpos = i * innerType.sizeof * 8 - fields.append(field) - return fields if not nativeType.code in (gdb.TYPE_CODE_STRUCT, gdb.TYPE_CODE_UNION): return fields @@ -321,18 +399,20 @@ class Dumper(DumperBase): nativeIndex = 0 baseIndex = 0 nativeFields = nativeType.fields() - #warn("NATIVE FIELDS: %s" % nativeFields) + #warn('NATIVE FIELDS: %s' % nativeFields) + anonNumber = 0 for nativeField in nativeFields: - #warn("FIELD: %s" % nativeField) - #warn(" DIR: %s" % dir(nativeField)) - #warn(" BITSIZE: %s" % nativeField.bitsize) - #warn(" ARTIFICIAL: %s" % nativeField.artificial) - #warn("FIELD NAME: %s" % nativeField.name) - #warn("FIELD TYPE: %s" % nativeField.type) + #warn('FIELD: %s' % nativeField) + #warn(' DIR: %s' % dir(nativeField)) + #warn(' BITSIZE: %s' % nativeField.bitsize) + #warn(' ARTIFICIAL: %s' % nativeField.artificial) + #warn('FIELD NAME: %s' % nativeField.name) + #warn('FIELD TYPE: %s' % nativeField.type) + #warn('FIELD TYPE ID: %s' % self.nativeTypeId(nativeField.type)) #self.check(isinstance(nativeField, gdb.Field)) field = self.Field(self) - field.ltype = self.fromNativeType(nativeField.type) - field.parentType = self.fromNativeType(nativeType) + field.ltype = self.fromNativeType(nativeField.type.unqualified()) + field.parentType = parentType field.name = nativeField.name field.isBaseClass = nativeField.is_base_class if hasattr(nativeField, 'bitpos'): @@ -356,36 +436,31 @@ class Dumper(DumperBase): # Something without a name. # Anonymous union? We need a dummy name to distinguish # multiple anonymous unions in the struct. - self.anonNumber += 1 - field.name = "#%s" % self.anonNumber + anonNumber += 1 + field.name = '#%s' % anonNumber else: # Normal named field. field.name = nativeField.name field.nativeIndex = nativeIndex + #warn('FIELD RESULT: %s' % field) fields.append(field) nativeIndex += 1 - #warn("FIELDS: %s" % fields) + #warn('FIELDS: %s' % fields) return fields - def nativeTypeStripTypedefs(self, typeobj): - typeobj = typeobj.unqualified() - while typeobj.code == gdb.TYPE_CODE_TYPEDEF: - typeobj = typeobj.strip_typedefs().unqualified() - return self.fromNativeType(typeobj) - def listOfLocals(self, partialVar): frame = gdb.selected_frame() try: block = frame.block() - #warn("BLOCK: %s " % block) + #warn('BLOCK: %s ' % block) except RuntimeError as error: - #warn("BLOCK IN FRAME NOT ACCESSIBLE: %s" % error) + #warn('BLOCK IN FRAME NOT ACCESSIBLE: %s' % error) return [] except: - warn("BLOCK NOT ACCESSIBLE FOR UNKNOWN REASONS") + warn('BLOCK NOT ACCESSIBLE FOR UNKNOWN REASONS') return [] items = [] @@ -409,10 +484,18 @@ class Dumper(DumperBase): # "NotImplementedError: Symbol type not yet supported in # Python scripts." #warn("SYMBOL %s (%s, %s)): " % (symbol, name, symbol.name)) - try: - value = self.fromNativeDowncastableValue(frame.read_var(name, block)) - #warn("READ 1: %s" % value) + if False and self.passExceptions: + value = self.fromFrameValue(frame.read_var(name, block)) value.name = name + #warn("READ 1: %s" % value.stringify()) + items.append(value) + continue + + try: + # Same as above, but for production. + value = self.fromFrameValue(frame.read_var(name, block)) + value.name = name + #warn("READ 1: %s" % value.stringify()) items.append(value) continue except: @@ -420,7 +503,7 @@ class Dumper(DumperBase): try: #warn("READ 2: %s" % item.value) - value = self.fromNativeDowncastableValue(frame.read_var(name)) + value = self.fromFrameValue(frame.read_var(name)) value.name = name items.append(value) continue @@ -435,7 +518,8 @@ class Dumper(DumperBase): try: #warn("READ 3: %s %s" % (name, item.value)) #warn("ITEM 3: %s" % item.value) - value = self.fromNativeDowncastableValue(gdb.parse_and_eval(name)) + value = self.fromFrameValue(gdb.parse_and_eval(name)) + value.name = name items.append(value) except: # Can happen in inlined code (see last line of @@ -550,10 +634,11 @@ class Dumper(DumperBase): exp = "((%s*)0x%x)->%s(%s)" % (typeName, addr, function, arg) #warn("CALL: %s" % exp) result = gdb.parse_and_eval(exp) - #warn(" -> %s" % result) + warn(" -> %s" % result) + res = self.fromNativeValue(result) if not value.address(): gdb.parse_and_eval("free((void*)0x%x)" % addr) - return self.fromNativeValue(result) + return res def makeExpression(self, value): typename = "::" + value.type.name @@ -573,13 +658,6 @@ class Dumper(DumperBase): #warn(" VALUE: %s" % value) return value - def nativeTypeTemplateArgument(self, nativeType, position, numeric): - #warn("NATIVE TYPE: %s" % dir(nativeType)) - arg = nativeType.template_argument(position) - if numeric: - return int(str(arg)) - return self.fromNativeType(arg) - def pokeValue(self, value): # Allocates inferior memory and copies the contents of value. # Returns a pointer to the copy. @@ -885,9 +963,6 @@ class Dumper(DumperBase): def enumExpression(self, enumType, enumValue): return self.qtNamespace() + "Qt::" + enumValue - def lookupType(self, typeName): - return self.fromNativeType(self.lookupNativeType(typeName)) - def lookupNativeType(self, typeName): nativeType = self.lookupNativeTypeHelper(typeName) if not nativeType is None: @@ -1154,7 +1229,7 @@ class CliDumper(Dumper): def putNumChild(self, numchild): pass - def putOriginalAddress(self, value): + def putOriginalAddress(self, address): pass def fetchVariables(self, args): @@ -1205,4 +1280,4 @@ class InterpreterMessageBreakpoint(gdb.Breakpoint): print("Interpreter event received.") return theDumper.handleInterpreterMessage() -InterpreterMessageBreakpoint() +#InterpreterMessageBreakpoint() diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py index a1b336e966f..24b3d6ada15 100644 --- a/share/qtcreator/debugger/lldbbridge.py +++ b/share/qtcreator/debugger/lldbbridge.py @@ -44,7 +44,7 @@ from dumper import * qqWatchpointOffset = 10000 def showException(msg, exType, exValue, exTraceback): - warn("**** CAUGHT EXCEPTION: %s ****" % msg) + warn('**** CAUGHT EXCEPTION: %s ****' % msg) import traceback lines = [line for line in traceback.format_exception(exType, exValue, exTraceback)] warn('\n'.join(lines)) @@ -55,13 +55,16 @@ def fileNameAsString(file): def check(exp): if not exp: - raise RuntimeError("Check failed") + raise RuntimeError('Check failed') class Dumper(DumperBase): def __init__(self): DumperBase.__init__(self) lldb.theDumper = self + self.isLldb = True + self.typeCache = {} + self.outputLock = threading.Lock() self.debugger = lldb.SBDebugger.Create() #self.debugger.SetLoggingCallback(loggingCallback) @@ -69,18 +72,18 @@ class Dumper(DumperBase): # s = args.strip() # s = s.replace('"', "'") # sys.stdout.write('log="%s"@\n' % s) - #Same as: self.debugger.HandleCommand("log enable lldb dyld step") - #self.debugger.EnableLog("lldb", ["dyld", "step", "process", "state", - # "thread", "events", - # "communication", "unwind", "commands"]) - #self.debugger.EnableLog("lldb", ["all"]) + #Same as: self.debugger.HandleCommand('log enable lldb dyld step') + #self.debugger.EnableLog('lldb', ['dyld', 'step', 'process', 'state', + # 'thread', 'events', + # 'communication', 'unwind', 'commands']) + #self.debugger.EnableLog('lldb', ['all']) self.debugger.Initialize() - self.debugger.HandleCommand("settings set auto-confirm on") + self.debugger.HandleCommand('settings set auto-confirm on') - # FIXME: warn("DISABLING DEFAULT FORMATTERS") + # FIXME: warn('DISABLING DEFAULT FORMATTERS') # It doesn't work at all with 179.5 and we have some bad # interaction in 300 - # if not hasattr(lldb.SBType, 'GetCanonicalType'): # "Test" for 179.5 + # if not hasattr(lldb.SBType, 'GetCanonicalType'): # 'Test' for 179.5 #self.debugger.HandleCommand('type category delete gnu-libstdc++') #self.debugger.HandleCommand('type category delete libcxx') #self.debugger.HandleCommand('type category delete default') @@ -109,24 +112,67 @@ class Dumper(DumperBase): self.interpreterBreakpointResolvers = [] self.report('lldbversion=\"%s\"' % lldb.SBDebugger.GetVersionString()) - self.reportState("enginesetupok") + self.reportState('enginesetupok') self.debuggerCommandInProgress = False + def fromNativeFrameValue(self, nativeValue): + return self.fromNativeValue(nativeValue) + def fromNativeValue(self, nativeValue): + self.check(isinstance(nativeValue, lldb.SBValue)) nativeValue.SetPreferSyntheticValue(False) nativeType = nativeValue.GetType() + code = nativeType.GetTypeClass() + if code == lldb.eTypeClassReference: + nativeTargetType = nativeType.GetDereferencedType() + if not nativeTargetType.IsPointerType(): + nativeTargetType = nativeTargetType.GetUnqualifiedType() + targetType = self.fromNativeType(nativeTargetType) + val = self.createReferenceValue(nativeValue.GetValueAsUnsigned(), targetType) + val.laddress = nativeValue.AddressOf().GetValueAsUnsigned() + #warn('CREATED REF: %s' % val) + return val + if code == lldb.eTypeClassPointer: + nativeTargetType = nativeType.GetPointeeType() + if not nativeTargetType.IsPointerType(): + nativeTargetType = nativeTargetType.GetUnqualifiedType() + targetType = self.fromNativeType(nativeTargetType) + val = self.createPointerValue(nativeValue.GetValueAsUnsigned(), targetType) + #warn('CREATED PTR 1: %s' % val) + val.laddress = nativeValue.AddressOf().GetValueAsUnsigned() + #warn('CREATED PTR 2: %s' % val) + return val + if code == lldb.eTypeClassTypedef: + nativeTargetType = nativeType.GetUnqualifiedType() + if hasattr(nativeTargetType, 'GetCanonicalType'): + nativeTargetType = nativeTargetType.GetCanonicalType() + val = self.fromNativeValue(nativeValue.Cast(nativeTargetType)) + val.type = self.fromNativeType(nativeType) + #warn('CREATED TYPEDEF: %s' % val) + return val + val = self.Value(self) + address = nativeValue.GetLoadAddress() + if not address is None: + val.laddress = address + if True: + #val.name = nativeValue.GetName() + data = nativeValue.GetData() + error = lldb.SBError() + size = nativeValue.GetType().GetByteSize() + if size > 1: + # 0 happens regularly e.g. for cross-shared-object types. + # 1 happens on Linux + try: + val.ldata = data.ReadRawData(error, 0, size) + except: + pass + val.type = self.fromNativeType(nativeType) val.lIsInScope = nativeValue.IsInScope() - #val.name = nativeValue.GetName() - 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()) + + #if code not in (lldb.eTypeClassPointer, lldb.eTypeClassReference): + # val.laddress = int(nativeValue.GetLoadAddress()) if code == lldb.eTypeClassEnumeration: intval = nativeValue.GetValueAsSigned() if hasattr(nativeType, 'get_enum_members_array'): @@ -137,69 +183,233 @@ class Dumper(DumperBase): if diff & mask == 0: path = nativeType.GetName().split('::') path[-1] = enumMember.GetName() - val.ldisplay = "%s (%d)" % ('::'.join(path), intval) - val.ldisplay = "%d" % intval + 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()) + elif code == lldb.eTypeClassReference: + #val.laddress = int(nativeValue.GetLoadAddress()) + #val.ldata = None + derefNativeValue = nativeValue.Dereference() + derefNativeValue = derefNativeValue.Cast(derefNativeValue.GetType().GetUnqualifiedType()) + val1 = self.Value(self) + val1.type = val.type + val1.targetValue = self.fromNativeValue(derefNativeValue) + return val1 + #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 - def fromNativeType(self, nativeType): - typeobj = self.Type(self) - if nativeType.IsPointerType(): - typeobj.nativeType = nativeType - else: - # This strips typedefs for pointers. We don't want that. - typeobj.nativeType = nativeType.GetUnqualifiedType() - if hasattr(typeobj.nativeType, "GetDisplayTypeName"): - typeobj.name = typeobj.nativeType.GetDisplayTypeName() # Xcode 6 (lldb-320) - else: - typeobj.name = typeobj.nativeType.GetName() # Xcode 5 (lldb-310) - typeobj.lbitsize = nativeType.GetByteSize() * 8 - code = nativeType.GetTypeClass() - try: - typeobj.code = { - lldb.eTypeClassArray : TypeCodeArray, - lldb.eTypeClassVector : TypeCodeArray, - lldb.eTypeClassComplexInteger : TypeCodeComplex, - lldb.eTypeClassComplexFloat : TypeCodeComplex, - lldb.eTypeClassClass : TypeCodeStruct, - lldb.eTypeClassStruct : TypeCodeStruct, - lldb.eTypeClassUnion : TypeCodeStruct, - lldb.eTypeClassEnumeration : TypeCodeEnum, - lldb.eTypeClassTypedef : TypeCodeTypedef, - lldb.eTypeClassReference : TypeCodeReference, - lldb.eTypeClassPointer : TypeCodePointer, - lldb.eTypeClassFunction : TypeCodeFunction, - lldb.eTypeClassMemberPointer : TypeCodeMemberPointer - }[code] - except KeyError: - if code == lldb.eTypeClassBuiltin: - if isFloatingPointTypeName(typeobj.name): - typeobj.code = TypeCodeFloat - elif isIntegralTypeName(typeobj.name): - typeobj.code = TypeCodeIntegral - else: - warn("UNKNOWN TYPE KEY: %s: %s" % (typeobj.name, code)) - else: - warn("UNKNOWN TYPE KEY: %s: %s" % (typeobj.name, code)) - #warn("CREATE TYPE: %s CODE: %s" % (typeobj.name, typeobj.code)) - return typeobj + def ptrSize(self): + result = self.target.GetAddressByteSize() + self.ptrSize = lambda: result + return result - def nativeTypeFields(self, nativeType): + def fromNativeType(self, nativeType): + self.check(isinstance(nativeType, lldb.SBType)) + code = nativeType.GetTypeClass() + + #warn('CURRENT: %s' % self.typeData.keys()) + #warn('FROM NATIVE TYPE: %s' % nativeType.GetName()) + if code == lldb.eTypeClassInvalid: + return None + + if code == lldb.eTypeClassBuiltin: + nativeType = nativeType.GetUnqualifiedType() + + if code == lldb.eTypeClassPointer: + #warn('PTR') + nativeTargetType = nativeType.GetPointeeType() + if not nativeTargetType.IsPointerType(): + nativeTargetType = nativeTargetType.GetUnqualifiedType() + #warn('PTR: %s' % nativeTargetType.name) + return self.createPointerType(self.fromNativeType(nativeTargetType)) + + if code == lldb.eTypeClassReference: + #warn('REF') + nativeTargetType = nativeType.GetDereferencedType() + if not nativeTargetType.IsPointerType(): + nativeTargetType = nativeTargetType.GetUnqualifiedType() + #warn('REF: %s' % nativeTargetType.name) + return self.createReferenceType(self.fromNativeType(nativeTargetType)) + + if code in (lldb.eTypeClassArray, lldb.eTypeClassVector): + #warn('ARRAY: %s' % nativeType.GetName()) + if hasattr(nativeType, 'GetArrayElementType'): # New in 3.8(?) / 350.x + nativeTargetType = nativeType.GetArrayElementType() + if not nativeTargetType.IsValid(): + if hasattr(nativeType, 'GetVectorElementType'): # New in 3.8(?) / 350.x + #warn('BAD: %s ' % nativeTargetType.get_fields_array()) + nativeTargetType = nativeType.GetVectorElementType() + elif hasattr(nativeType, 'GetVectorElementType'): # New in 3.8(?) / 350.x + nativeTargetType = nativeType.GetVectorElementType() + else: + return self.createType(nativeType.GetName()) + + #warn('NATIVE TARGET TYPE: %s' % nativeTargetType) + #warn('NATIVE TARGE NAME: %s' % nativeTargetType.GetName()) + targetType = self.fromNativeType(nativeTargetType) + count = nativeType.GetByteSize() // nativeTargetType.GetByteSize() + return self.createArrayType(targetType, count) + + if code == lldb.eTypeClassTypedef: + #warn('TYPEDEF') + nativeTargetType = nativeType.GetUnqualifiedType() + if hasattr(nativeTargetType, 'GetCanonicalType'): + nativeTargetType = nativeTargetType.GetCanonicalType() + targetType = self.fromNativeType(nativeTargetType) + return self.createTypedefedType(targetType, nativeType.GetName()) + + nativeType = nativeType.GetUnqualifiedType() + typeId = self.nativeTypeId(nativeType) + res = self.typeData.get(typeId, None) + if res is None: + # # This strips typedefs for pointers. We don't want that. + # typeobj.nativeType = nativeType.GetUnqualifiedType() + tdata = self.TypeData(self) + if hasattr(nativeType, 'GetDisplayTypeName'): + tdata.name = nativeType.GetDisplayTypeName() # Xcode 6 (lldb-320) + else: + tdata.name = nativeType.GetName() # Xcode 5 (lldb-310) + tdata.typeId = typeId + tdata.lbitsize = nativeType.GetByteSize() * 8 + if code == lldb.eTypeClassBuiltin: + if isFloatingPointTypeName(tdata.name): + tdata.code = TypeCodeFloat + elif isIntegralTypeName(tdata.name): + tdata.code = TypeCodeIntegral + elif tdata.name == 'void': + tdata.code = TypeCodeVoid + else: + warn('UNKNOWN TYPE KEY: %s: %s' % (tdata.name, code)) + else: + # eTypeClassInvalid = (0u), + # eTypeClassArray = (1u << 0), + # eTypeClassBlockPointer = (1u << 1), + # eTypeClassBuiltin = (1u << 2), + # eTypeClassClass = (1u << 3), + # eTypeClassComplexFloat = (1u << 4), + # eTypeClassComplexInteger = (1u << 5), + # eTypeClassEnumeration = (1u << 6), + # eTypeClassFunction = (1u << 7), + # eTypeClassMemberPointer = (1u << 8), + # eTypeClassObjCObject = (1u << 9), + # eTypeClassObjCInterface = (1u << 10), + # eTypeClassObjCObjectPointer = (1u << 11), + # eTypeClassPointer = (1u << 12), + # eTypeClassReference = (1u << 13), + # eTypeClassStruct = (1u << 14), + # eTypeClassTypedef = (1u << 15), + # eTypeClassUnion = (1u << 16), + # eTypeClassVector = (1u << 17), + # // Define the last type class as the MSBit of a 32 bit value + # eTypeClassOther = (1u << 31), + # // Define a mask that can be used for any type when finding types + # eTypeClassAny = (0xffffffffu) + tdata.code = { + #lldb.eTypeClassArray : TypeCodeArray, + #lldb.eTypeClassVector : TypeCodeArray, + lldb.eTypeClassComplexInteger : TypeCodeComplex, + lldb.eTypeClassComplexFloat : TypeCodeComplex, + lldb.eTypeClassClass : TypeCodeStruct, + lldb.eTypeClassStruct : TypeCodeStruct, + lldb.eTypeClassUnion : TypeCodeStruct, + lldb.eTypeClassEnumeration : TypeCodeEnum, + #lldb.eTypeClassTypedef : TypeCodeTypedef, + #lldb.eTypeClassReference : TypeCodeReference, + #lldb.eTypeClassPointer : TypeCodePointer, + lldb.eTypeClassFunction : TypeCodeFunction, + lldb.eTypeClassMemberPointer : TypeCodeMemberPointer + }[code] + if tdata.code == TypeCodeEnum: + tdata.enumDisplay = lambda intval: self.nativeTypeEnumDisplay(nativeType, intval) + self.registerType(typeId, tdata) # Prevent recursion in fields. + tdata.lfields = self.listFields(nativeType, self.Type(self, typeId)) + tdata.templateArguments = self.listTemplateParametersHelper(nativeType) + self.registerType(typeId, tdata) # Fix up fields and template args + # warn('CREATE TYPE: %s' % typeId) + #else: + # warn('REUSE TYPE: %s' % typeId) + return self.Type(self, typeId) + + def listTemplateParametersHelper(self, nativeType): + stringArgs = self.listTemplateParameters(nativeType.GetName()) + n = nativeType.GetNumberOfTemplateArguments() + if n != len(stringArgs): + # Something wrong in the debug info. + # Should work in theory, doesn't work in practice. + # Items like std::allocator report 0 + # for nativeType.GetNumberOfTemplateArguments() with LLDB 3.8 + return stringArgs + + targs = [] + for i in range(nativeType.GetNumberOfTemplateArguments()): + kind = nativeType.GetTemplateArgumentKind(i) + # eTemplateArgumentKindNull = 0, + # eTemplateArgumentKindType, + # eTemplateArgumentKindDeclaration, + # eTemplateArgumentKindIntegral, + # eTemplateArgumentKindTemplate, + # eTemplateArgumentKindTemplateExpansion, + # eTemplateArgumentKindExpression, + # eTemplateArgumentKindPack + if kind == lldb.eTemplateArgumentKindType: + innerType = nativeType.GetTemplateArgumentType(i).GetUnqualifiedType().GetCanonicalType() + targs.append(self.fromNativeType(innerType)) + #elif kind == lldb.eTemplateArgumentKindIntegral: + # innerType = nativeType.GetTemplateArgumentType(i).GetUnqualifiedType().GetCanonicalType() + # #warn('INNER TYP: %s' % innerType) + # basicType = innerType.GetBasicType() + # #warn('IBASIC TYP: %s' % basicType) + # inner = self.extractTemplateArgument(nativeType.GetName(), i) + # exp = '(%s)%s' % (innerType.GetName(), inner) + # #warn('EXP : %s' % exp) + # val = self.nativeParseAndEvaluate('(%s)%s' % (innerType.GetName(), inner)) + # # Clang writes 'int' and '0xfffffff' into the debug info + # # LLDB manages to read a value of 0xfffffff... + # #if basicType == lldb.eBasicTypeInt: + # value = val.GetValueAsUnsigned() + # if value >= 0x8000000: + # value -= 0x100000000 + # #warn('KIND: %s' % kind) + # targs.append(value) + else: + #warn('UNHANDLED TEMPLATE TYPE : %s' % kind) + targs.append(stringArgs[i]) # Best we can do. + #warn('TARGS: %s %s' % (nativeType.GetName(), [str(x) for x in targs])) + return targs + + def nativeTypeId(self, nativeType): + if hasattr(nativeType, 'GetDisplayTypeName'): + name = nativeType.GetDisplayTypeName() # Xcode 6 (lldb-320) + else: + name = nativeType.GetName() # Xcode 5 (lldb-310) + if name is None or len(name) == 0: + c = '0' + elif name == '(anonymous struct)' and nativeType.GetTypeClass() == lldb.eTypeClassStruct: + c = 's' + elif name == '(anonymous struct)' and nativeType.GetTypeClass() == lldb.eTypeClassUnion: + c = 'u' + else: + return name + fields = nativeType.get_fields_array() + typeId = c + ''.join(['{%s:%s}' % (f.name, self.nativeTypeId(f.GetType())) for f in fields]) + #warn('NATIVE TYPE ID FOR %s IS %s' % (name, typeId)) + return typeId + + def listFields(self, nativeType, parentType): fields = [] if self.currentContextValue is not None: addr = self.currentContextValue.AddressOf().GetValueAsUnsigned() else: - warn("CREATING DUMMY CONTEXT") + warn('CREATING DUMMY CONTEXT') addr = 0 # FIXME: 0 doesn't produce valid member offsets. addr = 0x7fffffffe0a0 sbaddr = lldb.SBAddress(addr, self.target) @@ -226,9 +436,9 @@ class Dumper(DumperBase): f.GetOffsetInBits())) for f in nativeType.get_fields_array()) - #warn("BASE NAMES: %s" % baseNames) - #warn("VIRTUAL NAMES: %s" % virtualNames) - #warn("FIELD BITS: %s" % fieldBits) + #warn('BASE NAMES: %s' % baseNames) + #warn('VIRTUAL NAMES: %s' % virtualNames) + #warn('FIELD BITS: %s' % fieldBits) fieldParentType = self.fromNativeType(nativeType).stripTypedefs() # This does not list empty base entries. @@ -237,10 +447,10 @@ class Dumper(DumperBase): fieldName = dummyChild.GetName() if fieldName is None: anonNumber += 1 - fieldName = "#%s" % anonNumber - fieldType = dummyChild.GetType() - #warn("CHILD AT: %s: %s %s" % (i, fieldName, fieldType.GetName())) - #warn(" AT: %s: %s %s" % (i, fieldName, fieldType.GetName())) + fieldName = '#%s' % anonNumber + fieldType = dummyChild.GetType().GetUnqualifiedType() + #warn('CHILD AT: %s: %s %s' % (i, fieldName, fieldType.GetName())) + #warn(' AT: %s: %s %s' % (i, fieldName, fieldType.GetName())) caddr = dummyChild.AddressOf().GetValueAsUnsigned() child = self.Value(self) child.type = self.fromNativeType(fieldType) @@ -257,12 +467,12 @@ class Dumper(DumperBase): field.lbitsize = fieldType.GetByteSize() * 8 field.lbitpos = (caddr - addr) * 8 if fieldName in baseNames: - #warn("BASE: %s P0S: 0x%x - 0x%x = %s" % (fieldName, caddr, addr, caddr - addr)) + #warn('BASE: %s P0S: 0x%x - 0x%x = %s' % (fieldName, caddr, addr, caddr - addr)) field.isBaseClass = True field.baseIndex = baseNames[fieldName] if fieldName in virtualNames: field.isVirtualBase = True - #warn("ADDING VRITUAL BASE: %s" % fieldName) + #warn('ADDING VIRTUAL BASE: %s' % fieldName) fields.append(field) # Add empty bases. @@ -287,29 +497,10 @@ class Dumper(DumperBase): field.lbitpos = 0 fields.append(field) - #warn("FIELD NAMES: %s" % [field.name for field in fields]) - #warn("FIELDS: %s" % fields) + #warn('FIELD NAMES: %s' % [field.name for field in fields]) + #warn('FIELDS: %s' % fields) return fields - def nativeTypeUnqualified(self, nativeType): - return self.fromNativeType(nativeType.GetUnqualifiedType()) - - def nativeTypePointer(self, nativeType): - return self.fromNativeType(nativeType.GetPointerType()) - - def nativeTypeStripTypedefs(self, typeobj): - if hasattr(typeobj, 'GetCanonicalType'): - return self.fromNativeType(typeobj.GetCanonicalType()) - return self.fromNativeType(typeobj) - - def nativeTypeFirstBase(self, nativeType): - #warn("FIRST BASE FROM: %s" % nativeType) - if nativeType.GetNumberOfDirectBaseClasses() == 0: - return None - t = nativeType.GetDirectBaseClassAtIndex(0) - #warn(" GOT BASE FROM: %s" % t) - return self.fromNativeType(nativeType.GetDirectBaseClassAtIndex(0).GetType()) - def nativeTypeEnumDisplay(self, nativeType, intval): if hasattr(nativeType, 'get_enum_members_array'): for enumMember in nativeType.get_enum_members_array(): @@ -319,8 +510,8 @@ class Dumper(DumperBase): if diff & mask == 0: path = nativeType.GetName().split('::') path[-1] = enumMember.GetName() - return "%s (%d)" % ('::'.join(path), intval) - return "%d" % intval + return '%s (%d)' % ('::'.join(path), intval) + return '%d' % intval def nativeDynamicTypeName(self, address, baseType): return None # FIXME: Seems sufficient, no idea why. @@ -371,18 +562,18 @@ class Dumper(DumperBase): def enumExpression(self, enumType, enumValue): ns = self.qtNamespace() - return ns + "Qt::" + enumType + "(" \ - + ns + "Qt::" + enumType + "::" + enumValue + ")" + return ns + 'Qt::' + enumType + '(' \ + + ns + 'Qt::' + enumType + '::' + enumValue + ')' def callHelper(self, rettype, value, func, args): # args is a tuple. arg = ','.join(args) - #warn("PRECALL: %s -> %s(%s)" % (value.address(), func, arg)) + #warn('PRECALL: %s -> %s(%s)' % (value.address(), func, arg)) typename = value.type.name - exp = "((%s*)0x%x)->%s(%s)" % (typename, value.address(), func, arg) - #warn("CALL: %s" % exp) + exp = '((%s*)0x%x)->%s(%s)' % (typename, value.address(), func, arg) + #warn('CALL: %s' % exp) result = self.currentContextValue.CreateValueFromExpression('', exp) - #warn(" -> %s" % result) + #warn(' -> %s' % result) return self.fromNativeValue(result) def pokeValue(self, typeName, *args): @@ -390,12 +581,12 @@ class Dumper(DumperBase): frame = thread.GetFrameAtIndex(0) inner = ','.join(args) value = frame.EvaluateExpression(typeName + '{' + inner + '}') - #self.warn(" TYPE: %s" % value.type) - #self.warn(" ADDR: 0x%x" % value.address) - #self.warn(" VALUE: %s" % value) + #self.warn(' TYPE: %s' % value.type) + #self.warn(' ADDR: 0x%x' % value.address) + #self.warn(' VALUE: %s' % value) return value - def parseAndEvaluate(self, exp): + def nativeParseAndEvaluate(self, exp): thread = self.currentThread() frame = thread.GetFrameAtIndex(0) val = frame.EvaluateExpression(exp) @@ -403,51 +594,15 @@ class Dumper(DumperBase): #val = self.target.EvaluateExpression(exp, options) err = val.GetError() if err.Fail(): - #warn("FAILING TO EVAL: %s" % exp) + #warn('FAILING TO EVAL: %s' % exp) return None - #warn("NO ERROR.") - #warn("EVAL: %s -> %s" % (exp, val.IsValid())) - return self.fromNativeValue(val) + #warn('NO ERROR.') + #warn('EVAL: %s -> %s' % (exp, val.IsValid())) + return val - def nativeTypeTemplateArgument(self, nativeType, position, numeric = False): - if numeric: - # There seems no API to extract the numeric value. - inner = self.extractTemplateArgument(nativeType.GetName(), position) - innerType = nativeType.GetTemplateArgumentType(position) - basicType = innerType.GetBasicType() - value = toInteger(inner) - # Clang writes 'int' and '0xfffffff' into the debug info - # LLDB manages to read a value of 0xfffffff... - if basicType == lldb.eBasicTypeInt and value >= 0x8000000: - value -= 0x100000000 - return value - else: - #warn("nativeTypeTemplateArgument: %s: pos %s" % (nativeType, position)) - typeobj = nativeType.GetTemplateArgumentType(position).GetUnqualifiedType() - if typeobj.IsValid(): - # warn("TYPE: %s" % typeobj) - return self.fromNativeType(typeobj) - inner = self.extractTemplateArgument(nativeType.GetName(), position) - #warn("INNER: %s" % inner) - return self.lookupType(inner) - - def nativeTypeDereference(self, nativeType): - return self.fromNativeType(nativeType.GetPointeeType()) - - def nativeTypeTarget(self, nativeType): - code = nativeType.GetTypeClass() - if code == lldb.eTypeClassPointer: - return self.fromNativeType(nativeType.GetPointeeType()) - if code == lldb.eTypeClassReference: - return self.fromNativeType(nativeType.GetDereferencedType()) - if code == lldb.eTypeClassArray: - if hasattr(nativeType, "GetArrayElementType"): # New in 3.8(?) / 350.x - return self.fromNativeType(nativeType.GetArrayElementType()) - fields = nativeType.get_fields_array() - return None if not len(fields) else self.nativeTypeTarget(fields[0]) - if code == lldb.eTypeClassVector: - return self.fromNativeType(nativeType.GetVectorElementType()) - return self.fromNativeType(nativeType) + def parseAndEvaluate(self, exp): + val = self.nativeParseAndEvaluate(exp) + return None if val is None else self.fromNativeValue(val) def isWindowsTarget(self): return False @@ -524,41 +679,70 @@ class Dumper(DumperBase): return re.sub('\\bconst\\b', '', name).replace(' ', '') def lookupNativeType(self, name): - #warn("LOOKUP TYPE NAME: %s" % name) + #warn('LOOKUP TYPE NAME: %s' % name) + typeobj = self.typeCache.get(name) + if not typeobj is None: + #warn('CACHED: %s' % name) + return typeobj typeobj = self.target.FindFirstType(name) if typeobj.IsValid(): - #warn("VALID FIRST : %s" % dir(typeobj)) + #warn('VALID FIRST : %s' % typeobj) + self.typeCache[name] = typeobj return typeobj - typeobj = self.target.FindFirstType(name + '*') - if typeobj.IsValid(): - return typeob.GetPointeeType() - typeobj = self.target.FindFirstType(name + '&') - if typeobj.IsValid(): - return typeob.GetReferencedType() if name.endswith('*'): - typeobj = self.target.FindFirstType(name[:-1].strip()) - if typeobj.IsValid(): + #warn('RECURSE PTR') + typeobj = self.lookupNativeType(name[:-1].strip()) + if typeobj is not None: + #warn('RECURSE RESULT X: %s' % typeobj) + self.fromNativeType(typeobj.GetPointerType()) + #warn('RECURSE RESULT: %s' % typeobj.GetPointerType()) return typeobj.GetPointerType() - #warn("LOOKUP RESULT: %s" % typeobj.name) - #warn("LOOKUP VALID: %s" % typeobj.IsValid()) + + #typeobj = self.target.FindFirstType(name[:-1].strip()) + #if typeobj.IsValid(): + # self.typeCache[name] = typeobj.GetPointerType() + # return typeobj.GetPointerType() + + if name.endswith(' const'): + #warn('LOOKUP END CONST') + typeobj = self.lookupNativeType(name[:-6]) + if typeobj is not None: + return typeobj + + if name.startswith('const '): + #warn('LOOKUP START CONST') + typeobj = self.lookupNativeType(name[6:]) + if typeobj is not None: + return typeobj + needle = self.canonicalTypeName(name) - #self.warn("NEEDLE: %s " % needle) + #warn('NEEDLE: %s ' % needle) for i in xrange(self.target.GetNumModules()): module = self.target.GetModuleAtIndex(i) # SBModule.GetType is new somewhere after early 300.x # So this may fail. for t in module.GetTypes(): n = self.canonicalTypeName(t.GetName()) + #warn('N: %s' % n) if n == needle: - #self.warn("FOUND TYPE DIRECT 2: %s " % t) + #warn('FOUND TYPE DIRECT 2: %s ' % t) + self.typeCache[name] = t return t if n == needle + '*': - #self.warn("FOUND TYPE BY POINTER 2: %s " % t.GetPointeeType()) - return t.GetPointeeType() + res = t.GetPointeeType() + self.typeCache[name] = res + x = self.fromNativeType(res) # Register under both names + self.registerTypeAlias(x.typeId, name) + #warn('FOUND TYPE BY POINTER: %s ' % res.name) + return res if n == needle + '&': - #self.warn("FOUND TYPE BY REFERENCE 2: %s " % t) - return t.GetDereferencedType() - #warn("NOT FOUND: %s " % needle) + res = t.GetDereferencedType().GetUnqualifiedType() + self.typeCache[name] = res + x = self.fromNativeType(res) # Register under both names + self.registerTypeAlias(x.typeId, name) + #warn('FOUND TYPE BY REFERENCE: %s ' % res.name) + return res + #warn('NOT FOUND: %s ' % needle) return None def setupInferior(self, args): @@ -584,7 +768,7 @@ class Dumper(DumperBase): self.ignoreStops = 0 self.silentStops = 0 - if platform.system() == "Linux": + if platform.system() == 'Linux': if self.startMode_ == AttachCore: pass else: @@ -610,7 +794,7 @@ class Dumper(DumperBase): if self.nativeMixed: self.interpreterEventBreakpoint = \ - self.target.BreakpointCreateByName("qt_qmlDebugMessageAvailable") + self.target.BreakpointCreateByName('qt_qmlDebugMessageAvailable') state = 1 if self.target.IsValid() else 0 self.reportResult('success="%s",msg="%s",exe="%s"' @@ -632,7 +816,7 @@ class Dumper(DumperBase): attachInfo = lldb.SBAttachInfo(self.attachPid_) self.process = self.target.Attach(attachInfo, error) if not error.Success(): - self.reportState("inferiorrunfailed") + self.reportState('inferiorrunfailed') return self.report('pid="%s"' % self.process.GetProcessID()) # Even if it stops it seems that LLDB assumes it is running @@ -641,29 +825,29 @@ class Dumper(DumperBase): if self.process and self.process.GetState() == lldb.eStateStopped: # lldb stops the process after attaching. This happens before the # eventloop starts. Relay the correct state back. - self.reportState("enginerunandinferiorstopok") + self.reportState('enginerunandinferiorstopok') else: - self.reportState("enginerunandinferiorrunok") + self.reportState('enginerunandinferiorrunok') elif self.startMode_ == AttachToRemoteServer or self.startMode_ == AttachToRemoteProcess: self.process = self.target.ConnectRemote( self.debugger.GetListener(), self.remoteChannel_, None, error) if not error.Success(): self.report(self.describeError(error)) - self.reportState("enginerunfailed") + self.reportState('enginerunfailed') return # Even if it stops it seems that LLDB assumes it is running # and later detects that it did stop after all, so it is be # better to mirror that and wait for the spontaneous stop. - self.reportState("enginerunandinferiorrunok") + self.reportState('enginerunandinferiorrunok') elif self.startMode_ == AttachCore: coreFile = args.get('coreFile', ''); self.process = self.target.LoadCore(coreFile) - self.reportState("enginerunokandinferiorunrunnable") + self.reportState('enginerunokandinferiorunrunnable') else: launchInfo = lldb.SBLaunchInfo(self.processArgs_) launchInfo.SetWorkingDirectory(self.workingDirectory_) - environmentList = [key + "=" + value for key,value in os.environ.items()] + environmentList = [key + '=' + value for key,value in os.environ.items()] if self.dyldImageSuffix: environmentList.append('DYLD_IMAGE_SUFFIX=' + self.dyldImageSuffix) if self.dyldLibraryPath: @@ -676,10 +860,10 @@ class Dumper(DumperBase): self.process = self.target.Launch(launchInfo, error) if not error.Success(): self.report(self.describeError(error)) - self.reportState("enginerunfailed") + self.reportState('enginerunfailed') return self.report('pid="%s"' % self.process.GetProcessID()) - self.reportState("enginerunandinferiorrunok") + self.reportState('enginerunandinferiorrunok') def loop(self): event = lldb.SBEvent() @@ -737,11 +921,11 @@ class Dumper(DumperBase): for i in xrange(0, self.process.GetNumThreads()): thread = self.process.GetThreadAtIndex(i) if thread.is_stopped: - state = "stopped" + state = 'stopped' elif thread.is_suspended: - state = "suspended" + state = 'suspended' else: - state = "unknown" + state = 'unknown' reason = thread.GetStopReason() result += '{id="%d"' % thread.GetThreadID() result += ',index="%s"' % i @@ -803,7 +987,7 @@ class Dumper(DumperBase): functionName = frame.GetFunctionName() - if isNativeMixed and functionName == "::qt_qmlDebugMessageAvailable()": + if isNativeMixed and functionName == '::qt_qmlDebugMessageAvailable()': interpreterStack = self.extractInterpreterStack() for interpreterFrame in interpreterStack.get('frames', []): function = interpreterFrame.get('function', '') @@ -843,8 +1027,9 @@ class Dumper(DumperBase): error = lldb.SBError() #warn("READ: %s %s" % (address, size)) res = self.process.ReadMemory(address, size, error) - if res is None: - return bytes() + if res is None or len(res) != size: + # Using code in e.g. readToFirstZero relies on exceptions. + raise RuntimeError("Unreadable %s bytes at 0x%x" % (size, address)) return res def findStaticMetaObject(self, typeName): @@ -919,7 +1104,7 @@ class Dumper(DumperBase): # This can happen for unnamed function parameters with # default values: void foo(int = 0) continue - value = self.fromNativeValue(val) + value = self.fromNativeFrameValue(val) value.name = name variables.append(value) @@ -1120,13 +1305,13 @@ class Dumper(DumperBase): def createBreakpointAtMain(self): return self.target.BreakpointCreateByName( - "main", self.target.GetExecutable().GetFilename()) + 'main', self.target.GetExecutable().GetFilename()) def insertBreakpoint(self, args): - bpType = args["type"] + bpType = args['type'] if bpType == BreakpointByFileAndLine: - fileName = args["file"] - if fileName.endswith(".js") or fileName.endswith(".qml"): + fileName = args['file'] + if fileName.endswith('.js') or fileName.endswith('.qml'): self.insertInterpreterBreakpoint(args) return @@ -1134,11 +1319,11 @@ class Dumper(DumperBase): more = True if bpType == BreakpointByFileAndLine: bp = self.target.BreakpointCreateByLocation( - str(args["file"]), int(args["line"])) + str(args['file']), int(args['line'])) elif bpType == BreakpointByFunction: - bp = self.target.BreakpointCreateByName(args["function"]) + bp = self.target.BreakpointCreateByName(args['function']) elif bpType == BreakpointByAddress: - bp = self.target.BreakpointCreateByAddress(args["address"]) + bp = self.target.BreakpointCreateByAddress(args['address']) elif bpType == BreakpointAtMain: bp = self.createBreakpointAtMain() elif bpType == BreakpointAtThrow: @@ -1150,14 +1335,14 @@ class Dumper(DumperBase): elif bpType == WatchpointAtAddress: error = lldb.SBError() # This might yield bp.IsValid() == False and - # error.desc == "process is not alive". - bp = self.target.WatchAddress(args["address"], 4, False, True, error) + # error.desc == 'process is not alive'. + bp = self.target.WatchAddress(args['address'], 4, False, True, error) extra = self.describeError(error) elif bpType == WatchpointAtExpression: # FIXME: Top level-only for now. try: frame = self.currentFrame() - value = frame.FindVariable(args["expression"]) + value = frame.FindVariable(args['expression']) error = lldb.SBError() bp = self.target.WatchAddress(value.GetLoadAddress(), value.GetByteSize(), False, True, error) @@ -1165,45 +1350,45 @@ class Dumper(DumperBase): bp = self.target.BreakpointCreateByName(None) else: # This leaves the unhandled breakpoint in a (harmless) - # "pending" state. + # 'pending' state. bp = self.target.BreakpointCreateByName(None) more = False if more and bp.IsValid(): - bp.SetIgnoreCount(int(args["ignorecount"])) - bp.SetCondition(self.hexdecode(args["condition"])) - bp.SetEnabled(bool(args["enabled"])) + bp.SetIgnoreCount(int(args['ignorecount'])) + bp.SetCondition(self.hexdecode(args['condition'])) + bp.SetEnabled(bool(args['enabled'])) bp.SetScriptCallbackBody('\n'.join([ - "def foo(frame = frame, bp_loc = bp_loc, dict = internal_dict):", - " " + self.hexdecode(args["command"]).replace('\n', '\n '), - "from cStringIO import StringIO", - "origout = sys.stdout", - "sys.stdout = StringIO()", - "result = foo()", - "d = lldb.theDumper", - "output = d.hexencode(sys.stdout.getvalue())", - "sys.stdout = origout", - "d.report('output={channel=\"stderr\",data=\"' + output + '\"}')", - "if result is False:", - " d.reportState('continueafternextstop')", - "return True" + 'def foo(frame = frame, bp_loc = bp_loc, dict = internal_dict):', + ' ' + self.hexdecode(args['command']).replace('\n', '\n '), + 'from cStringIO import StringIO', + 'origout = sys.stdout', + 'sys.stdout = StringIO()', + 'result = foo()', + 'd = lldb.theDumper', + 'output = d.hexencode(sys.stdout.getvalue())', + 'sys.stdout = origout', + 'd.report("output={channel=\"stderr\",data=\"' + output + '\"}")', + 'if result is False:', + ' d.reportState("continueafternextstop")', + 'return True' ])) if isinstance(bp, lldb.SBBreakpoint): - bp.SetOneShot(bool(args["oneshot"])) + bp.SetOneShot(bool(args['oneshot'])) self.reportResult(self.describeBreakpoint(bp) + extra, args) def changeBreakpoint(self, args): - lldbId = int(args["lldbid"]) + lldbId = int(args['lldbid']) if lldbId > qqWatchpointOffset: bp = self.target.FindWatchpointByID(lldbId) else: bp = self.target.FindBreakpointByID(lldbId) if bp.IsValid(): - bp.SetIgnoreCount(int(args["ignorecount"])) - bp.SetCondition(self.hexdecode(args["condition"])) - bp.SetEnabled(bool(args["enabled"])) + bp.SetIgnoreCount(int(args['ignorecount'])) + bp.SetCondition(self.hexdecode(args['condition'])) + bp.SetEnabled(bool(args['enabled'])) if isinstance(bp, lldb.SBBreakpoint): - bp.SetOneShot(bool(args["oneshot"])) + bp.SetOneShot(bool(args['oneshot'])) self.reportResult(self.describeBreakpoint(bp), args) def removeBreakpoint(self, args): @@ -1269,16 +1454,16 @@ class Dumper(DumperBase): def shutdownInferior(self, args): self.isShuttingDown_ = True if self.process is None: - self.reportState("inferiorshutdownok") + self.reportState('inferiorshutdownok') else: state = self.process.GetState() if state == lldb.eStateStopped: self.process.Kill() - self.reportState("inferiorshutdownok") + self.reportState('inferiorshutdownok') self.reportResult('', args) def quit(self, args): - self.reportState("engineshutdownok") + self.reportState('engineshutdownok') self.process.Kill() self.reportResult('', args) @@ -1299,7 +1484,7 @@ class Dumper(DumperBase): bp = self.target.BreakpointCreateByAddress(addr) if bp.GetNumLocations() == 0: self.target.BreakpointDelete(bp.GetID()) - self.reportResult(self.describeStatus("No target location found.") + self.reportResult(self.describeStatus('No target location found.') + self.describeLocation(frame), args) return bp.SetOneShot(True) @@ -1311,14 +1496,14 @@ class Dumper(DumperBase): line = int(args['line']) error = self.currentThread().StepOverUntil(frame, lldb.SBFileSpec(file), line) self.reportResult(self.describeError(error), args) - self.reportState("running") - self.reportState("stopped") + self.reportState('running') + self.reportState('stopped') def executeJumpToLocation(self, args): self.reportToken(args) frame = self.currentFrame() if not frame: - self.reportResult(self.describeStatus("No frame available."), args) + self.reportResult(self.describeStatus('No frame available.'), args) return addr = args.get('address', 0) if addr: @@ -1328,17 +1513,17 @@ class Dumper(DumperBase): str(args['file']), int(args['line'])) if bp.GetNumLocations() == 0: self.target.BreakpointDelete(bp.GetID()) - status = "No target location found." + status = 'No target location found.' else: loc = bp.GetLocationAtIndex(0) self.target.BreakpointDelete(bp.GetID()) res = frame.SetPC(loc.GetLoadAddress()) - status = "Jumped." if res else "Cannot jump." + status = 'Jumped.' if res else 'Cannot jump.' self.reportResult(self.describeStatus(status) + self.describeLocation(frame), args) def breakList(self): result = lldb.SBCommandReturnObject() - self.debugger.GetCommandInterpreter().HandleCommand("break list", result) + self.debugger.GetCommandInterpreter().HandleCommand('break list', result) self.report('success="%d",output="%s",error="%s"' % (result.Succeeded(), result.GetOutput(), result.GetError())) @@ -1354,7 +1539,7 @@ class Dumper(DumperBase): self.reportResult('', args) def fetchFullBacktrace(self, _ = None): - command = "thread backtrace all" + command = 'thread backtrace all' result = lldb.SBCommandReturnObject() self.debugger.GetCommandInterpreter().HandleCommand(command, result) self.reportResult(self.hexencode(result.GetOutput()), {}) @@ -1385,7 +1570,7 @@ class Dumper(DumperBase): else: base = args.get('address', 0) if int(base) == 0xffffffffffffffff: - warn("INVALID DISASSEMBLER BASE") + warn('INVALID DISASSEMBLER BASE') return addr = lldb.SBAddress(base, self.target) instructions = self.target.ReadInstructions(addr, 100) @@ -1406,7 +1591,7 @@ class Dumper(DumperBase): if lineNumber != currentLine or fileName != currentFile: currentLine = lineNumber currentFile = fileName - key = "%s:%s" % (fileName, lineNumber) + key = '%s:%s' % (fileName, lineNumber) hunk = hunks.get(key, 0) + 1 hunks[key] = hunk source = sources.get(fileName, None) @@ -1419,8 +1604,8 @@ class Dumper(DumperBase): # With lldb-3.8 files like /data/dev/creator-3.6/tests/ # auto/debugger/qt_tst_dumpers_StdVector_bfNWZa/main.cpp # with non-existent directories appear. - warn("FILE: %s ERROR: %s" % (fileName, error)) - source = "" + warn('FILE: %s ERROR: %s' % (fileName, error)) + source = '' result += '{line="%s"' % lineNumber result += ',file="%s"' % fileName if 0 < lineNumber and lineNumber <= len(source): @@ -1463,7 +1648,7 @@ class Dumper(DumperBase): self.reportResult(self.describeError(error), args) def createResolvePendingBreakpointsHookBreakpoint(self, args): - bp = self.target.BreakpointCreateByName("qt_qmlDebugConnectorOpen") + bp = self.target.BreakpointCreateByName('qt_qmlDebugConnectorOpen') bp.SetOneShot(True) self.interpreterBreakpointResolvers.append( lambda: self.resolvePendingInterpreterBreakpoint(args)) @@ -1479,7 +1664,7 @@ class Tester(Dumper): self.target = self.debugger.CreateTarget(binary, None, None, True, error) if error.GetType(): - warn("ERROR: %s" % error) + warn('ERROR: %s' % error) return s = threading.Thread(target=self.testLoop, args=(args,)) @@ -1494,19 +1679,19 @@ class Tester(Dumper): error = lldb.SBError() launchInfo = lldb.SBLaunchInfo([]) launchInfo.SetWorkingDirectory(os.getcwd()) - environmentList = [key + "=" + value for key,value in os.environ.items()] + environmentList = [key + '=' + value for key,value in os.environ.items()] launchInfo.SetEnvironmentEntries(environmentList, False) self.process = self.target.Launch(launchInfo, error) if error.GetType(): - warn("ERROR: %s" % error) + warn('ERROR: %s' % error) event = lldb.SBEvent() listener = self.debugger.GetListener() while True: state = self.process.GetState() if listener.WaitForEvent(100, event): - #warn("EVENT: %s" % event) + #warn('EVENT: %s' % event) state = lldb.SBProcess.GetStateFromEvent(event) if state == lldb.eStateExited: # 10 break @@ -1515,14 +1700,14 @@ class Tester(Dumper): for i in xrange(0, self.process.GetNumThreads()): thread = self.process.GetThreadAtIndex(i) reason = thread.GetStopReason() - #warn("THREAD: %s REASON: %s" % (thread, reason)) + #warn('THREAD: %s REASON: %s' % (thread, reason)) if (reason == lldb.eStopReasonBreakpoint or reason == lldb.eStopReasonException or reason == lldb.eStopReasonSignal): stoppedThread = thread if stoppedThread: - # This seems highly fragile and depending on the "No-ops" in the + # This seems highly fragile and depending on the 'No-ops' in the # event handling above. frame = stoppedThread.GetFrameAtIndex(0) line = frame.line_entry.line @@ -1531,13 +1716,13 @@ class Tester(Dumper): self.process.SetSelectedThread(stoppedThread) self.fetchVariables(args) #self.describeLocation(frame) - self.report("@NS@%s@" % self.qtNamespace()) - #self.report("ENV=%s" % os.environ.items()) - #self.report("DUMPER=%s" % self.qqDumpers) + self.report('@NS@%s@' % self.qtNamespace()) + #self.report('ENV=%s' % os.environ.items()) + #self.report('DUMPER=%s' % self.qqDumpers) break else: warn('TIMEOUT') - warn("Cannot determined stopped thread") + warn('Cannot determined stopped thread') lldb.SBDebugger.Destroy(self.debugger) diff --git a/share/qtcreator/debugger/misctypes.py b/share/qtcreator/debugger/misctypes.py index 29f46c82ee7..54af7e6414c 100644 --- a/share/qtcreator/debugger/misctypes.py +++ b/share/qtcreator/debugger/misctypes.py @@ -121,7 +121,7 @@ def qdump__Eigen__Matrix(d, value): storage = value['m_storage'] nrows = storage['m_rows'].integer() if argRow == -1 else argRow ncols = storage['m_cols'].integer() if argCol == -1 else argCol - p = storage['m_data'].integer() + p = storage['m_data'].pointer() innerSize = innerType.size() d.putValue('(%s x %s), %s' % (nrows, ncols, ['ColumnMajor', 'RowMajor'][rowMajor])) d.putField('keeporder', '1') diff --git a/share/qtcreator/debugger/qttypes.py b/share/qtcreator/debugger/qttypes.py index 6e8cb59892e..bb53b4af826 100644 --- a/share/qtcreator/debugger/qttypes.py +++ b/share/qtcreator/debugger/qttypes.py @@ -152,7 +152,7 @@ def qdump_X_QModelIndex(d, value): except: p = value['i'] m = value['m'] - if m.integer() == 0 or r < 0 or c < 0: + if m.pointer() == 0 or r < 0 or c < 0: d.putValue('(invalid)') d.putPlainChildren(value) return @@ -196,7 +196,7 @@ def qdump_X_QModelIndex(d, value): def qdump__QDate(d, value): - jd = value.integer() + jd = value.pointer() if jd: d.putValue(jd, 'juliandate') d.putNumChild(1) @@ -332,6 +332,7 @@ def qdump__QDateTime(d, value): d.putNumChild(0) return + d.putNumChild(1) if d.isExpanded(): with Children(d): ns = d.qtNamespace() @@ -1120,7 +1121,7 @@ def qdump__QRegion(d, value): def qdump__QScopedPointer(d, value): - if value.integer() == 0: + if value.pointer() == 0: d.putValue('(null)') d.putNumChild(0) else: @@ -1187,13 +1188,13 @@ def qdump__QSet(d, value): def qdump__QSharedData(d, value): - d.putValue('ref: %s' % d.extractInt(value['ref'].address)) + d.putValue('ref: %s' % value.to('i')) d.putNumChild(0) def qdump__QSharedDataPointer(d, value): d_ptr = value['d'] - if d_ptr.integer() == 0: + if d_ptr.pointer() == 0: d.putValue('(null)') d.putNumChild(0) else: @@ -1206,7 +1207,7 @@ def qdump__QSharedDataPointer(d, value): d.putPlainChildren(value) return d.putBetterType(d.currentType) - d.putItem(d_ptr.cast(innerType.pointer()).dereference()) + d.putItem(d_ptr.dereference()) @@ -1404,6 +1405,7 @@ def qdump__QUrl(d, value): if displayFormat == SeparateFormat: d.putDisplay('utf16:separate', url) + d.putNumChild(1) if d.isExpanded(): with Children(d): d.putIntItem('port', port) @@ -1684,12 +1686,12 @@ def qdump__QVariant(d, value): ptr = p.pointer() (elided, blob) = d.encodeCArray(ptr, 1, 100) typeName = d.hexdecode(blob) - base = data.extractPointer() # Prefer namespaced version. if len(ns) > 0: if not d.lookupNativeType(ns + typeName) is None: typeName = ns + typeName - d.putSubItem('data', d.createValue(base, d.createType(typeName))) + data.type = d.createType(typeName + ' *') + d.putSubItem('data', data) if not typeName is None: d.putBetterType('%sQVariant (%s)' % (ns, typeName)) return None @@ -1706,7 +1708,7 @@ def qedit__QVector(d, value, data): base = value['d'].address() + offset except: # Qt 4. - base = value['p']['array'].integer() + base = value['p']['array'].pointer() d.setValues(base, innerType, values) @@ -1766,6 +1768,7 @@ def qdump_QWeakPointerHelper(d, value, isWeak): def qdump__QXmlAttributes__Attribute(d, value): d.putEmptyValue() + d.putNumChild(1) if d.isExpanded(): with Children(d): (qname, uri, localname, val) = value.split('{QString}' * 4) @@ -2345,7 +2348,7 @@ def qdump__QScriptValue(d, value): #d.putEmptyValue() dd = value['d_ptr']['d'] ns = d.qtNamespace() - if dd.integer() == 0: + if dd.pointer() == 0: d.putValue('(invalid)') d.putNumChild(0) return @@ -2621,9 +2624,9 @@ def qdump__QJsonValue(d, value): def qdump__QJsonArray(d, value): - qdumpHelper_QJsonArray(d, value['d'].integer(), value['a'].integer()) + qdumpHelper_QJsonArray(d, value['d'].pointer(), value['a'].pointer()) def qdump__QJsonObject(d, value): - qdumpHelper_QJsonObject(d, value['d'].integer(), value['o'].integer()) + qdumpHelper_QJsonObject(d, value['d'].pointer(), value['o'].pointer()) diff --git a/share/qtcreator/debugger/stdtypes.py b/share/qtcreator/debugger/stdtypes.py index 2733253bf45..4c8c2cb7545 100644 --- a/share/qtcreator/debugger/stdtypes.py +++ b/share/qtcreator/debugger/stdtypes.py @@ -76,17 +76,17 @@ def qdump__std__deque(d, value): impl = value["_M_impl"] start = impl["_M_start"] finish = impl["_M_finish"] - size = bufsize * int((finish["_M_node"].integer() - start["_M_node"].integer()) / d.ptrSize() - 1) - size += int((finish["_M_cur"].integer() - finish["_M_first"].integer()) / innerSize) - size += int((start["_M_last"].integer() - start["_M_cur"].integer()) / innerSize) + size = bufsize * ((finish["_M_node"].pointer() - start["_M_node"].pointer()) // d.ptrSize() - 1) + size += ((finish["_M_cur"].pointer() - finish["_M_first"].pointer()) // innerSize) + size += ((start["_M_last"].pointer() - start["_M_cur"].pointer()) // innerSize) d.check(0 <= size and size <= 1000 * 1000 * 1000) d.putItemCount(size) if d.isExpanded(): with Children(d, size, maxNumChild=2000, childType=innerType): - pcur = start["_M_cur"].integer() + pcur = start["_M_cur"].pointer() pfirst = start["_M_first"] - plast = start["_M_last"].integer() + plast = start["_M_last"].pointer() pnode = start["_M_node"] for i in d.childRange(): d.putSubItem(i, d.createValue(pcur, innerType)) @@ -99,7 +99,7 @@ def qdump__std__deque(d, value): #warn("NEWNODE: 0x%x %s" % (newnode.pointer(), newnode)) pnode = newnode #warn("PNODE 2: 0x%x %s" % (pnode.pointer(), pnode)) - pfirst = newnode.dereference().integer() + pfirst = newnode.dereference().pointer() plast = pfirst + bufsize * d.ptrSize() pcur = pfirst @@ -237,7 +237,6 @@ def qdump__std__map(d, value): if d.isExpanded(): pairType = value.type[3][0] - pairPointer = pairType.pointer() with PairedChildren(d, size, pairType=pairType, maxNumChild=1000): node = value["_M_t"]["_M_impl"]["_M_header"]["_M_left"] nodeSize = node.dereference().type.size() @@ -245,10 +244,10 @@ def qdump__std__map(d, value): for i in d.childRange(): (pad1, key, pad2, value) = d.split(typeCode, node.pointer() + nodeSize) d.putPairItem(i, (key, value)) - if node["_M_right"].integer() == 0: + if node["_M_right"].pointer() == 0: parent = node["_M_parent"] while True: - if node.integer() != parent["_M_right"].integer(): + if node.pointer() != parent["_M_right"].pointer(): break node = parent parent = parent["_M_parent"] @@ -257,7 +256,7 @@ def qdump__std__map(d, value): else: node = node["_M_right"] while True: - if node["_M_left"].integer() == 0: + if node["_M_left"].pointer() == 0: break node = node["_M_left"] @@ -271,13 +270,13 @@ def qdump_std__map__helper(d, size, value): for i in d.childRange(): pair = node.cast(nodeType).dereference()['_Myval'] d.putPairItem(i, pair) - if node['_Right']['_Isnil'].integer() == 0: + if node['_Right']['_Isnil'].pointer() == 0: node = node['_Right'] - while node['_Left']['_Isnil'].integer() == 0: + while node['_Left']['_Isnil'].pointer() == 0: node = node['_Left'] else: parent = node['_Parent'] - while node and parent['_Right']['_Isnil'].integer() == 0: + while node and parent['_Right']['_Isnil'].pointer() == 0: node = parent parent = parent['_Parent'] if node['_Right'] != parent: @@ -377,7 +376,7 @@ def qdump__std__set(d, value): for i in d.childRange(): (pad, val) = d.split(typeCode, node.pointer() + nodeSize) d.putSubItem(i, val) - if node["_M_right"].integer() == 0: + if node["_M_right"].pointer() == 0: parent = node["_M_parent"] while node == parent["_M_right"]: node = parent @@ -386,7 +385,7 @@ def qdump__std__set(d, value): node = parent else: node = node["_M_right"] - while node["_M_left"].integer() != 0: + while node["_M_left"].pointer() != 0: node = node["_M_left"] def qdump__std__set__QNX(d, value): @@ -419,7 +418,7 @@ def std1TreeMin(d, node): # return __x; # left = node['__left_'] - if left.integer(): + if left.pointer(): node = left return node @@ -428,7 +427,7 @@ def std1TreeIsLeftChild(d, node): # return __x == __x->__parent_->__left_; # other = node['__parent_']['__left_'] - return node.integer() == other.integer() + return node.pointer() == other.pointer() def std1TreeNext(d, node): @@ -440,7 +439,7 @@ def std1TreeNext(d, node): # return __x->__parent_; # right = node['__right_'] - if right.integer(): + if right.pointer(): return std1TreeMin(d, right) while not std1TreeIsLeftChild(d, node): node = node['__parent_'] @@ -612,18 +611,18 @@ def qdump__std____1__wstring(d, value): def qdump__std__shared_ptr(d, value): - if d.isMsvcTarget: + if d.isMsvcTarget(): i = value["_Ptr"] else: i = value["_M_ptr"] - if i.integer() == 0: + if i.pointer() == 0: d.putValue("(null)") d.putNumChild(0) return with Children(d): - short = d.putSubItem("data", i) - if d.isMsvcTarget: + short = d.putSubItem("data", i.dereference()) + if d.isMsvcTarget(): refcount = value["_Rep"] d.putIntItem("usecount", refcount["_Uses"]) d.putIntItem("weakcount", refcount["_Weaks"]) @@ -635,7 +634,7 @@ def qdump__std__shared_ptr(d, value): def qdump__std____1__shared_ptr(d, value): i = value["__ptr_"] - if i.integer() == 0: + if i.pointer() == 0: d.putValue("(null)") d.putNumChild(0) return @@ -733,7 +732,7 @@ def qdump__std__unordered_set(d, value): d.putItemCount(size) if d.isExpanded(): - p = start.integer() + p = start.pointer() valueType = value.type[0] with Children(d, size, childType=valueType): ptrSize = d.ptrSize() @@ -974,10 +973,10 @@ def qdump____gnu_cxx__hash_set(d, value): bucketFinish = buckets["_M_finish"] p = bucketStart itemCount = 0 - for i in xrange(int((bucketFinish.integer() - bucketStart.integer()) / d.ptrSize())): - if p.dereference().integer(): + for i in xrange((bucketFinish.pointer() - bucketStart.pointer()) // d.ptrSize()): + if p.dereference().pointer(): cur = p.dereference() - while cur.integer(): + while cur.pointer(): d.putSubItem(itemCount, cur["_M_val"]) cur = cur["_M_next"] itemCount += 1 diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index ee4e556094a..d9f3ac2bd55 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -1903,9 +1903,9 @@ void tst_Dumpers::dumper_data() + Check("h1.2.value.1", "[1]", "2", "int") + Check("h2", "<3 items>", "@QHash") - + Check("h2.0", "[0] 0", FloatValue("33"), "float") - + Check("h2.1", "[1] 22", FloatValue("22"), "float") - + Check("h2.2", "[2] 11", FloatValue("11"), "float") + + Check("h2.0", "[0] 0", FloatValue("33"), "") + + Check("h2.1", "[1] 22", FloatValue("22"), "") + + Check("h2.2", "[2] 11", FloatValue("11"), "") + Check("h3", "<1 items>", "@QHash<@QString, int>") + Check("h3.0.key", "key", "\"22.0\"", "@QString") @@ -1934,7 +1934,7 @@ void tst_Dumpers::dumper_data() + CheckType("h7.2.value", "@QPointer<@QObject>") + Check("h8", "<3 items>", "Hash") - + Check("h8.0", "[0] 22", FloatValue("22"), "float") + + Check("h8.0", "[0] 22", FloatValue("22"), "") + Check("it1.key", "22", "int") + Check("it1.value", FloatValue("22"), "float") + Check("it3.key", "33", "int") @@ -2347,8 +2347,8 @@ void tst_Dumpers::dumper_data() + Check("m1.1.value.0", "[0]", "\"22\"", "@QString") + Check("m2", "<2 items>", "@QMap") - + Check("m2.0", "[0] 11", FloatValue("31.0"), "float") - + Check("m2.1", "[1] 22", FloatValue("32.0"), "float") + + Check("m2.0", "[0] 11", FloatValue("31.0"), "") + + Check("m2.1", "[1] 22", FloatValue("32.0"), "") + Check("m3", "<2 items>", "T") @@ -2432,8 +2432,8 @@ void tst_Dumpers::dumper_data() + Check("m0", "<0 items>", "@QMultiMap") + Check("m1", "<6 items>", "@QMultiMap") - + Check("m1.0", "[0] 11", FloatValue("11"), "float") - + Check("m1.5", "[5] 22", FloatValue("22"), "float") + + Check("m1.0", "[0] 11", FloatValue("11"), "") + + Check("m1.5", "[5] 22", FloatValue("22"), "") + Check("m2", "<1 items>", "@QMultiMap<@QString, float>") + Check("m2.0.key", "\"22.0\"", "@QString") @@ -4120,23 +4120,23 @@ void tst_Dumpers::dumper_data() "map4.insert(std::pair(22, 25.0));\n") + Check("map1", "<2 items>", "std::map") - + Check("map1.0", "[0] 11", "1", "unsigned int") - + Check("map1.1", "[1] 22", "2", "unsigned int") + + Check("map1.0", "[0] 11", "1", "") + + Check("map1.1", "[1] 22", "2", "") + Check("map2", "<2 items>", "std::map") - + Check("map2.0", "[0] 11", FloatValue("11"), "float") - + Check("map2.1", "[1] 22", FloatValue("22"), "float") + + Check("map2.0", "[0] 11", FloatValue("11"), "") + + Check("map2.1", "[1] 22", FloatValue("22"), "") + Check("map3", "<6 items>", "Map") - + Check("map3.0", "[0] 11", FloatValue("11"), "float") + + Check("map3.0", "[0] 11", FloatValue("11"), "") + Check("it1.first", "11", "int") + Check("it1.second", FloatValue("11"), "float") + Check("it6.first", "66", "int") + Check("it6.second", FloatValue("66"), "float") + Check("map4", "<5 items>", "std::multimap") - + Check("map4.0", "[0] 11", FloatValue("11"), "float") - + Check("map4.4", "[4] 22", FloatValue("25"), "float"); + + Check("map4.0", "[0] 11", FloatValue("11"), "") + + Check("map4.4", "[4] 22", FloatValue("25"), ""); QTest::newRow("StdMapQt") @@ -4188,33 +4188,33 @@ void tst_Dumpers::dumper_data() + CoreProfile() + Check("map1", "<3 items>", "std::map<@QString, Foo>") - + Check("map1.0", "[0] \"22.0\"", "", "std::pair<@QString const, Foo>") + + Check("map1.0", "[0] \"22.0\"", "", "") + Check("map1.0.first", "\"22.0\"", "@QString") + Check("map1.0.second", "", "Foo") + Check("map1.0.second.a", "22", "int") - + Check("map1.1", "[1] \"33.0\"", "", "std::pair<@QString const, Foo>") + + Check("map1.1", "[1] \"33.0\"", "", "") + Check("map1.2.first", "\"44.0\"", "@QString") + Check("map1.2.second", "", "Foo") + Check("map1.2.second.a", "44", "int") + Check("map2", "<2 items>", "std::map") - + Check("map2.0", "[0] \"22.0\"", "", "std::pair") + + Check("map2.0", "[0] \"22.0\"", "", "") + Check("map2.0.first", "\"22.0\"", "char *") + Check("map2.0.first.0", "[0]", "50", "char") + Check("map2.0.second", "", "Foo") + Check("map2.0.second.a", "22", "int") - + Check("map2.1", "[1] \"33.0\"", "", "std::pair") + + Check("map2.1", "[1] \"33.0\"", "", "") + Check("map2.1.first", "\"33.0\"", "char *") + Check("map2.1.first.0", "[0]", "51", "char") + Check("map2.1.second", "", "Foo") + Check("map2.1.second.a", "33", "int") + Check("map3", "<2 items>", "std::map") - + Check("map3.0", "[0] 11", "<1 items>", "std::pair") + + Check("map3.0", "[0] 11", "<1 items>", "") + Check("map3.0.first", "11", "unsigned int") + Check("map3.0.second", "<1 items>", "@QStringList") + Check("map3.0.second.0", "[0]", "\"11\"", "@QString") - + Check("map3.1", "[1] 22", "<1 items>", "std::pair") + + Check("map3.1", "[1] 22", "<1 items>", "") + Check("map3.1.first", "22", "unsigned int") + Check("map3.1.second", "<1 items>", "@QStringList") + Check("map3.1.second.0", "[0]", "\"22\"", "@QString") @@ -4222,26 +4222,25 @@ void tst_Dumpers::dumper_data() + Check("map4.1.second.0", "[0]", "\"22\"", "@QString") + Check("map5", "<2 items>", "std::map<@QString, float>") - + Check("map5.0", "[0] \"11.0\"", FloatValue("11"), "std::pair<@QString const, float>") + + Check("map5.0", "[0] \"11.0\"", FloatValue("11"), "") + Check("map5.0.first", "\"11.0\"", "@QString") + Check("map5.0.second", FloatValue("11"), "float") - + Check("map5.1", "[1] \"22.0\"", FloatValue("22"), "std::pair<@QString const, float>") + + Check("map5.1", "[1] \"22.0\"", FloatValue("22"), "") + Check("map5.1.first", "\"22.0\"", "@QString") + Check("map5.1.second", FloatValue("22"), "float") + Check("map6", "<2 items>", "std::map") - + Check("map6.0", "[0] 11", "\"11.0\"", "std::pair") + + Check("map6.0", "[0] 11", "\"11.0\"", "") + Check("map6.0.first", "11", "int") + Check("map6.0.second", "\"11.0\"", "@QString") - + Check("map6.1", "[1] 22", "\"22.0\"", "std::pair") + + Check("map6.1", "[1] 22", "\"22.0\"", "") + Check("map6.1.first", "22", "int") + Check("map6.1.second", "\"22.0\"", "@QString") + Check("map7", "<3 items>", "std::map<@QString, @QPointer<@QObject>>") - + Check("map7.0", "[0] \".\"", "", "std::pair<@QString const, @QPointer<@QObject>>") + + Check("map7.0", "[0] \".\"", "", "") + Check("map7.0.first", "\".\"", "@QString") + Check("map7.0.second", "", "@QPointer<@QObject>") - + Check("map7.2", "[2] \"Welt\"", "", "std::pair<@QString const, @QPointer<@QObject>>") + Check("map7.2.first", "\"Welt\"", "@QString"); @@ -4672,8 +4671,8 @@ void tst_Dumpers::dumper_data() + Cxx11Profile() + Check("map1", "<2 items>", "std::unordered_map") - + Check("map1.0", "[0] 22", "2", "unsigned int") - + Check("map1.1", "[1] 11", "1", "unsigned int") + + Check("map1.0", "[0] 22", "2", "") + + Check("map1.1", "[1] 11", "1", "") + Check("map2", "<2 items>", "std::unordered_map") + Check("map2.0", "[0] \"22.0\"", FloatValue("22.0"), "") @@ -5382,17 +5381,8 @@ void tst_Dumpers::dumper_data() + Check("y2", "", "X") + Check("y3", "", "X"); - QTest::newRow("RValueReferenceLldb") + QTest::newRow("RValueReference") << Data(rvalueData) - + LldbEngine - + Check("x1", "", "X &&") - + Check("x2", "", "X &&") - + Check("x3", "", "X &&"); - - QTest::newRow("RValueReferenceGdb") - << Data(rvalueData) - + GdbEngine - + GccVersion(0, 40704) + Check("x1", "", "X &") + Check("x2", "", "X &") + Check("x3", "", "X &");