Debugger: Use less GDB inferior calls in normal field extraction

They are not usable in core files.

Change-Id: I2134b61f27c27862c12a679d0acf7bebc9fcc7a2
Reviewed-by: Orgad Shaneh <orgads@gmail.com>
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
hjk
2016-11-07 08:57:26 +01:00
parent ffe305527b
commit 9040c4081e
5 changed files with 468 additions and 240 deletions

View File

@@ -110,7 +110,8 @@ TypeCodeFunction, \
TypeCodeMemberPointer, \ TypeCodeMemberPointer, \
TypeCodeFortranString, \ TypeCodeFortranString, \
TypeCodeUnresolvable, \ TypeCodeUnresolvable, \
= range(0, 14) TypeCodeBitfield, \
= range(0, 15)
def isIntegralTypeName(name): def isIntegralTypeName(name):
return name in ('int', 'unsigned int', 'signed int', return name in ('int', 'unsigned int', 'signed int',
@@ -288,8 +289,11 @@ class DumperBase:
self.typesToReport = {} self.typesToReport = {}
self.qtNamespaceToReport = None self.qtNamespaceToReport = None
self.passExceptions = False self.passExceptions = False
self.isTesting = False
self.typeData = {} self.typeData = {}
self.isBigEndian = False
self.packCode = '<'
self.resetCaches() self.resetCaches()
self.resetStats() self.resetStats()
@@ -333,6 +337,7 @@ class DumperBase:
self.useFancy = int(args.get('fancy', '0')) self.useFancy = int(args.get('fancy', '0'))
self.forceQtNamespace = int(args.get('forcens', '0')) self.forceQtNamespace = int(args.get('forcens', '0'))
self.passExceptions = int(args.get('passexceptions', '0')) self.passExceptions = int(args.get('passexceptions', '0'))
self.isTesting = int(args.get('testing', '0'))
self.showQObjectNames = int(args.get('qobjectnames', '0')) self.showQObjectNames = int(args.get('qobjectnames', '0'))
self.nativeMixed = int(args.get('nativemixed', '0')) self.nativeMixed = int(args.get('nativemixed', '0'))
self.autoDerefPointers = int(args.get('autoderef', '0')) self.autoDerefPointers = int(args.get('autoderef', '0'))
@@ -389,11 +394,11 @@ class DumperBase:
self.counts[key] = 1 self.counts[key] = 1
def preping(self, key): def preping(self, key):
import time return
self.pretimings[key] = time.time() self.pretimings[key] = time.time()
def ping(self, key): def ping(self, key):
import time return
elapsed = int(1000000 * (time.time() - self.pretimings[key])) elapsed = int(1000000 * (time.time() - self.pretimings[key]))
self.timings.append([key, elapsed]) self.timings.append([key, elapsed])
@@ -518,6 +523,9 @@ class DumperBase:
nativeType = self.lookupNativeType(typeName) nativeType = self.lookupNativeType(typeName)
return None if nativeType is None else self.fromNativeType(nativeType) return None if nativeType is None else self.fromNativeType(nativeType)
def nativeDynamicType(self, address, baseType):
return baseType # Override in backends.
def listTemplateParameters(self, typename): def listTemplateParameters(self, typename):
targs = [] targs = []
if not typename.endswith('>'): if not typename.endswith('>'):
@@ -880,9 +888,9 @@ class DumperBase:
continue continue
if item.isBaseClass and dumpBase: if item.isBaseClass and dumpBase:
baseIndex += 1
# We cannot use nativeField.name as part of the iname as # We cannot use nativeField.name as part of the iname as
# it might contain spaces and other strange characters. # it might contain spaces and other strange characters.
baseIndex += 1
with UnnamedSubItem(self, "@%d" % baseIndex): with UnnamedSubItem(self, "@%d" % baseIndex):
self.putField('iname', self.currentIName) self.putField('iname', self.currentIName)
self.putField('name', '[%s]' % item.name) self.putField('name', '[%s]' % item.name)
@@ -918,7 +926,7 @@ class DumperBase:
self.checkIntType(tsize) self.checkIntType(tsize)
self.checkIntType(maximum) self.checkIntType(maximum)
code = (None, 'b', 'H', None, 'I')[tsize] code = self.packCode + (None, 'b', 'H', None, 'I')[tsize]
#blob = self.readRawMemory(base, 1) #blob = self.readRawMemory(base, 1)
blob = bytes() blob = bytes()
while maximum > 1: while maximum > 1:
@@ -1284,6 +1292,11 @@ class DumperBase:
return False return False
def putFormattedPointer(self, value): def putFormattedPointer(self, value):
self.preping('formattedPointer')
self.putFormattedPointerX(value)
self.ping('formattedPointer')
def putFormattedPointerX(self, value):
#warn("PUT FORMATTED: %s" % value) #warn("PUT FORMATTED: %s" % value)
pointer = value.pointer() pointer = value.pointer()
#warn('POINTER: 0x%x' % pointer) #warn('POINTER: 0x%x' % pointer)
@@ -2573,6 +2586,11 @@ class DumperBase:
return False return False
def putItem(self, value): def putItem(self, value):
self.preping('putItem')
self.putItemX(value)
self.ping('putItem')
def putItemX(self, value):
#warn('PUT ITEM: %s' % value.stringify()) #warn('PUT ITEM: %s' % value.stringify())
typeobj = value.type #unqualified() typeobj = value.type #unqualified()
@@ -2597,10 +2615,7 @@ class DumperBase:
if typeobj.code == TypeCodeTypedef: if typeobj.code == TypeCodeTypedef:
#warn('TYPEDEF VALUE: %s' % value.stringify()) #warn('TYPEDEF VALUE: %s' % value.stringify())
#strippedType = typeobj.ltarget
self.putItem(value.detypedef()) self.putItem(value.detypedef())
if value.lbitsize is not None and value.lbitsize != value.type.size() * 8:
typeName += ' : %s' % value.lbitsize
self.putBetterType(typeName) self.putBetterType(typeName)
return return
@@ -2627,16 +2642,17 @@ class DumperBase:
self.putCStyleArray(value) self.putCStyleArray(value)
return return
if typeobj.code == TypeCodeBitfield:
#warn('BITFIELD VALUE: %s %s' % (value.name, value))
self.putNumChild(0)
self.putValue(value.lvalue)
self.putType(typeName)
return
if typeobj.code == TypeCodeIntegral: if typeobj.code == TypeCodeIntegral:
#warn('INTEGER: %s %s' % (value.name, value)) #warn('INTEGER: %s %s' % (value.name, value))
val = value.value() val = value.value()
self.putNumChild(0) self.putNumChild(0)
if value.lbitsize is not None and value.lbitsize != value.type.size() * 8:
typeName += ' : %s' % value.lbitsize
val = val >> value.lbitpos
val = val & ((1 << value.lbitsize) - 1)
#warn('VAL: %s BITPOS: %s BITSIZE: %s'
# % (val, value.lbitpos, value.lbitsize))
self.putValue(val) self.putValue(val)
self.putType(typeName) self.putType(typeName)
return return
@@ -2806,6 +2822,8 @@ class DumperBase:
return self.detypedef().value() return self.detypedef().value()
if self.type.code == TypeCodeIntegral: if self.type.code == TypeCodeIntegral:
return self.integer() return self.integer()
if self.type.code == TypeCodeBitfield:
return self.integer()
if self.type.code == TypeCodeFloat: if self.type.code == TypeCodeFloat:
return self.floatingPoint() return self.floatingPoint()
if self.type.code == TypeCodeTypedef: if self.type.code == TypeCodeTypedef:
@@ -2887,15 +2905,40 @@ class DumperBase:
error('BAD INDEX TYPE %s' % type(field)) error('BAD INDEX TYPE %s' % type(field))
#warn('FIELD: %s ' % field) #warn('FIELD: %s ' % field)
fieldBitsize = field.bitsize()
fieldSize = None if fieldBitsize is None else fieldBitsize >> 3
fieldBitpos = field.bitpos()
fieldOffset = fieldBitpos >> 3
fieldBitpos -= fieldOffset * 8
fieldType = field.fieldType()
val = self.dumper.Value(self.dumper) val = self.dumper.Value(self.dumper)
val.name = field.name val.name = field.name
val.isBaseClass = field.isBaseClass
val.type = field.fieldType()
if field.isArtificial:
if self.laddress is not None:
val.laddress = self.laddress
if self.ldata is not None:
val.ldata = self.ldata
return val
fieldBitsize = field.lbitsize
fieldSize = (fieldBitsize + 7) // 8
fieldBitpos = field.lbitpos
fieldOffset = fieldBitpos // 8
fieldType = field.fieldType()
if fieldType.code == TypeCodeBitfield:
fieldBitpos -= fieldOffset * 8
ldata = self.data()
data = 0
for i in range(fieldSize):
data = data << 8
if self.dumper.isBigEndian:
byte = ldata[i]
else:
byte = ldata[fieldOffset + fieldSize - 1 - i]
data += ord(byte)
data = data >> fieldBitpos
data = data & ((1 << fieldBitsize) - 1)
val.lvalue = data
val.laddress = None
return val
if self.laddress is not None: if self.laddress is not None:
val.laddress = self.laddress + fieldOffset val.laddress = self.laddress + fieldOffset
@@ -2904,21 +2947,11 @@ class DumperBase:
else: else:
self.dumper.check(False) self.dumper.check(False)
if fieldBitsize is not None and fieldBitsize != fieldType.size() * 8:
data = val.extractInteger(fieldBitsize, True)
data = data >> fieldBitpos
data = data & ((1 << fieldBitsize) - 1)
val.laddress = None
val.ldata = bytes(struct.pack('Q', data))
val.type = None val.type = None
if val.laddress is not None and fieldType is not None: if fieldType.code == TypeCodeReference:
if fieldType.code == TypeCodePointer: if val.laddress is not None:
objectAddress = self.dumper.extractPointer(val.laddress) val = self.dumper.createReferenceValue(val.laddress, fieldType.ltarget)
val = self.dumper.createPointerValue(objectAddress, fieldType.ltarget) val.name = field.name
elif fieldType.code == TypeCodeReference:
objectAddress = self.dumper.extractPointer(val.laddress)
val = self.dumper.createReferenceValue(objectAddress, fieldType.ltarget)
if val.type is None: if val.type is None:
val.type = fieldType val.type = fieldType
@@ -2926,7 +2959,6 @@ class DumperBase:
val.check() val.check()
val.name = field.name val.name = field.name
val.lbitsize = fieldBitsize val.lbitsize = fieldBitsize
val.isBaseClass = field.isBaseClass
return val return val
# This is the generic version for synthetic values. # This is the generic version for synthetic values.
@@ -2935,9 +2967,22 @@ class DumperBase:
def members(self, includeBases): def members(self, includeBases):
if self.type.code == TypeCodeTypedef: if self.type.code == TypeCodeTypedef:
return self.detypedef().members(includeBases) return self.detypedef().members(includeBases)
tdata = self.type.typeData()
#if isinstance(tdata.lfields, list):
# return tdata.lfields
fields = []
if tdata.lfields is not None:
if isinstance(tdata.lfields, list):
fields = tdata.lfields
else:
fields = list(tdata.lfields(self))
#warn("FIELDS: %s" % fields)
res = [] res = []
anonNumber = 0 anonNumber = 0
for field in self.type.fields(self): for field in fields:
if field.isBaseClass and not includeBases: if field.isBaseClass and not includeBases:
continue continue
if field.name is None or len(field.name) == 0: if field.name is None or len(field.name) == 0:
@@ -2946,7 +2991,7 @@ class DumperBase:
# multiple anonymous unions in the struct. # multiple anonymous unions in the struct.
anonNumber += 1 anonNumber += 1
field.name = '#%s' % anonNumber field.name = '#%s' % anonNumber
res.append(field) res.append(self.extractField(field))
return res return res
def __add__(self, other): def __add__(self, other):
@@ -2957,7 +3002,7 @@ class DumperBase:
address = self.pointer() + stripped.dereference().size() address = self.pointer() + stripped.dereference().size()
val = self.dumper.Value(self.dumper) val = self.dumper.Value(self.dumper)
val.laddress = None val.laddress = None
val.ldata = bytes(struct.pack('Q', address)) val.ldata = bytes(struct.pack(self.dumper.packCode + 'Q', address))
val.type = self.type val.type = self.type
return val return val
error('BAD DATA TO ADD TO: %s %s' % (self.type, other)) error('BAD DATA TO ADD TO: %s %s' % (self.type, other))
@@ -2971,10 +3016,10 @@ class DumperBase:
val.laddress = self.pointer() val.laddress = self.pointer()
if val.laddress is None and self.laddress is not None: if val.laddress is None and self.laddress is not None:
val.laddress = self.laddress val.laddress = self.laddress
val.type = self.type.dereference().dynamicType(val.laddress) val.type = self.dumper.nativeDynamicType(val.laddress, self.type.dereference())
elif self.type.code == TypeCodePointer: elif self.type.code == TypeCodePointer:
val.laddress = self.pointer() val.laddress = self.pointer()
val.type = self.type.dereference().dynamicType(val.laddress) val.type = self.dumper.nativeDynamicType(val.laddress, self.type.dereference())
else: else:
error("WRONG: %s" % self.type.code) error("WRONG: %s" % self.type.code)
#warn("DEREFERENCING FROM: %s" % self) #warn("DEREFERENCING FROM: %s" % self)
@@ -3007,10 +3052,12 @@ class DumperBase:
error('NOT IMPLEMENTED') error('NOT IMPLEMENTED')
def zeroExtend(self, data, size): def zeroExtend(self, data, size):
ext = '\0' * (size - len(data))
if sys.version_info[0] == 3: if sys.version_info[0] == 3:
return data + bytes('\0' * (size - len(data)), encoding='latin1') pad = bytes(ext, encoding='latin1')
else: else:
return data + bytes('\0' * (size - len(data))) pad = bytes(ext)
return pad + data if self.dumper.isBigEndian else data + pad
def cast(self, typish): def cast(self, typish):
self.check() self.check()
@@ -3051,6 +3098,7 @@ class DumperBase:
error('CANNOT CONVERT TO BYTES: %s' % self) error('CANNOT CONVERT TO BYTES: %s' % self)
def extractInteger(self, bitsize, unsigned): def extractInteger(self, bitsize, unsigned):
self.dumper.preping('extractInt')
self.check() self.check()
if bitsize > 32: if bitsize > 32:
size = 8 size = 8
@@ -3065,27 +3113,30 @@ class DumperBase:
size = 1 size = 1
code = 'B' if unsigned else 'b' code = 'B' if unsigned else 'b'
rawBytes = self.data(size) rawBytes = self.data(size)
try: res = struct.unpack_from(self.dumper.packCode + code, rawBytes, 0)[0]
return struct.unpack_from(code, rawBytes, 0)[0] #warn('Extract: Code: %s Bytes: %s Bitsize: %s Size: %s'
except: # % (self.dumper.packCode + code, self.dumper.hexencode(rawBytes), bitsize, size))
pass self.dumper.ping('extractInt')
error('Cannot extract: Code: %s Bytes: %s Bitsize: %s Size: %s' return res
% (code, self.dumper.hexencode(rawBytes), bitsize, size))
def extractSomething(self, code, bitsize): def extractSomething(self, code, bitsize):
self.dumper.preping('extractSomething')
self.check() self.check()
size = (bitsize + 7) >> 3 size = (bitsize + 7) >> 3
rawBytes = self.data(size) rawBytes = self.data(size)
return struct.unpack_from(code, rawBytes, 0)[0] res = struct.unpack_from(self.dumper.packCode + code, rawBytes, 0)[0]
self.dumper.ping('extractSomething')
return res
def to(self, pattern): def to(self, pattern):
return self.split(pattern)[0] return self.split(pattern)[0]
def split(self, pattern): def split(self, pattern):
self.dumper.preping('split')
#warn('EXTRACT STRUCT FROM: %s' % self.type) #warn('EXTRACT STRUCT FROM: %s' % self.type)
(pp, size, fields) = self.dumper.describeStruct(pattern) (pp, size, fields) = self.dumper.describeStruct(pattern)
#warn('SIZE: %s ' % size) #warn('SIZE: %s ' % size)
result = struct.unpack_from(pp, self.data(size)) result = struct.unpack_from(self.dumper.packCode + pp, self.data(size))
def structFixer(field, thing): def structFixer(field, thing):
#warn('STRUCT MEMBER: %s' % type(thing)) #warn('STRUCT MEMBER: %s' % type(thing))
if field.isStruct: if field.isStruct:
@@ -3101,6 +3152,7 @@ class DumperBase:
return thing return thing
if len(fields) != len(result): if len(fields) != len(result):
error('STRUCT ERROR: %s %s' (fields, result)) error('STRUCT ERROR: %s %s' (fields, result))
self.dumper.ping('split')
return tuple(map(structFixer, fields, result)) return tuple(map(structFixer, fields, result))
def checkPointer(self, p, align = 1): def checkPointer(self, p, align = 1):
@@ -3127,7 +3179,6 @@ class DumperBase:
self.lfields = None # None or Value -> list of member Values self.lfields = None # None or Value -> list of member Values
self.lalignment = None # Function returning alignment of this struct self.lalignment = None # Function returning alignment of this struct
self.lbitsize = None self.lbitsize = None
self.lbitpos = None
self.ltarget = None # Inner type for arrays self.ltarget = None # Inner type for arrays
self.templateArguments = [] self.templateArguments = []
self.code = None self.code = None
@@ -3141,7 +3192,6 @@ class DumperBase:
tdata.lfields = self.lfields tdata.lfields = self.lfields
tdata.lalignment = self.lalignment tdata.lalignment = self.lalignment
tdata.lbitsize = self.lbitsize tdata.lbitsize = self.lbitsize
tdata.lbitpos = self.lbitpos
tdata.ltarget = self.ltarget tdata.ltarget = self.ltarget
tdata.templateArguments = self.templateArguments tdata.templateArguments = self.templateArguments
tdata.code = self.code tdata.code = self.code
@@ -3199,8 +3249,8 @@ class DumperBase:
tdata = self.typeData() tdata = self.typeData()
if tdata is None: if tdata is None:
return 'Type(id="%s")' % self.typeId return 'Type(id="%s")' % self.typeId
return 'Type(name="%s",bsize=%s,bpos=%s,code=%s)' \ return 'Type(name="%s",bsize=%s,code=%s)' \
% (tdata.name, tdata.lbitsize, tdata.lbitpos, tdata.code) % (tdata.name, tdata.lbitsize, tdata.code)
def __getitem__(self, index): def __getitem__(self, index):
if self.dumper.isInt(index): if self.dumper.isInt(index):
@@ -3223,7 +3273,12 @@ class DumperBase:
return self.dumper.nativeDynamicTypeName(address, self) return self.dumper.nativeDynamicTypeName(address, self)
def dynamicType(self, address): def dynamicType(self, address):
# FIXME: That buys some performance at the cost of a fail
# of Gdb13393 dumper test.
#return self
self.dumper.preping('dynamicType %s 0x%s' % (self.name, address))
dynTypeName = self.dynamicTypeName(address) dynTypeName = self.dynamicTypeName(address)
self.dumper.ping('dynamicType %s 0x%s' % (self.name, address))
if dynTypeName is not None: if dynTypeName is not None:
return self.dumper.createType(dynTypeName) return self.dumper.createType(dynTypeName)
return self return self
@@ -3327,13 +3382,6 @@ class DumperBase:
def target(self): def target(self):
return self.typeData().ltarget return self.typeData().ltarget
def fields(self, value):
tdata = self.typeData()
if tdata.code == TypeCodeTypedef:
return tdata.ltarget.fields(value)
if tdata.lfields is not None:
return tdata.lfields(value)
return []
def field(self, value, name, bitoffset = 0): def field(self, value, name, bitoffset = 0):
#warn('GETTING FIELD %s FOR: %s' % (name, self.name)) #warn('GETTING FIELD %s FOR: %s' % (name, self.name))
@@ -3398,9 +3446,8 @@ class DumperBase:
def __init__(self, dumper): def __init__(self, dumper):
self.dumper = dumper self.dumper = dumper
self.name = None self.name = None
self.nativeIndex = None # Backend-defined index value
self.isBaseClass = False self.isBaseClass = False
self.isVirtualBase = False self.isArtificial = False
self.ltype = None self.ltype = None
self.lbitsize = None self.lbitsize = None
self.lbitpos = None self.lbitpos = None
@@ -3408,34 +3455,23 @@ class DumperBase:
def __str__(self): def __str__(self):
typename = None if self.ltype is None else self.ltype.stringify() typename = None if self.ltype is None else self.ltype.stringify()
return ('Field(name="%s",ltype=%s,bpos=%s,bsize=%s,nidx=%s)') \ return ('Field(name="%s",ltype=%s,bpos=%s,bsize=%s)') \
% (self.name, typename, self.lbitpos, self.lbitsize, % (self.name, typename, self.lbitpos, self.lbitsize)
self.nativeIndex)
def check(self): def check(self):
pass pass
def size(self): def size(self):
return self.bitsize() >> 3 return self.lbitsize // 8
def offset(self): def offset(self):
return self.bitpos() >> 3 return self.lbitpos // 8
def bitsize(self): def bitsize(self):
self.check()
if self.lbitsize is not None:
return self.lbitsize return self.lbitsize
fieldType = self.fieldType()
# FIXME: enforce return value != None.
if fieldType is not None:
return fieldType.bitsize()
return None
def bitpos(self): def bitpos(self):
if self.lbitpos is not None:
#warn('BITPOS KNOWN: %s %s' % (self.name, self.lbitpos))
return self.lbitpos return self.lbitpos
error('DONT KNOW BITPOS FOR FIELD: %s ' % self)
def fieldType(self): def fieldType(self):
if self.ltype is not None: if self.ltype is not None:
@@ -3443,12 +3479,13 @@ class DumperBase:
error('CANT GET FIELD TYPE FOR %s' % self) error('CANT GET FIELD TYPE FOR %s' % self)
return None return None
def ptrCode(self):
return 'I' if self.ptrSize() == 4 else 'Q'
def toPointerData(self, address): def toPointerData(self, address):
if not self.isInt(address): if not self.isInt(address):
error('wrong') error('wrong')
size = self.ptrSize() return bytes(struct.pack(self.packCode + self.ptrCode(), address))
code = 'I' if size == 4 else 'Q'
return bytes(struct.pack(code, address))
def createPointerValue(self, targetAddress, targetTypish): def createPointerValue(self, targetAddress, targetTypish):
if not isinstance(targetTypish, self.Type) and not isinstance(targetTypish, str): if not isinstance(targetTypish, self.Type) and not isinstance(targetTypish, str):
@@ -3476,6 +3513,20 @@ class DumperBase:
val.type = self.createReferenceType(targetType) val.type = self.createReferenceType(targetType)
return val return val
def createBitfieldValue(self, targetType, bitsize):
if not isinstance(targetType, self.Type):
error('Expected type in createBitfieldValue(), got %s'
% type(targetType))
targetTypeId = targetType.typeId
typeId = '%s:%d' % (targetTypeId, bitsize)
tdata = self.TypeData(self)
tdata.name = '%s : %d' % (targetType.name, bitsize)
tdata.typeId = typeId
tdata.code = TypeCodeArray
tdata.ltarget = targetType
self.registerType(typeId, tdata)
return self.Type(self, typeId)
def createPointerType(self, targetType): def createPointerType(self, targetType):
if not isinstance(targetType, self.Type): if not isinstance(targetType, self.Type):
error('Expected type in createPointerType(), got %s' error('Expected type in createPointerType(), got %s'
@@ -3519,6 +3570,19 @@ class DumperBase:
self.registerType(typeId, tdata) self.registerType(typeId, tdata)
return self.Type(self, typeId) return self.Type(self, typeId)
def createBitfieldType(self, targetTypeId, bitsize):
if not isinstance(targetTypeId, str):
error('Expected type in createBitfieldType(), got %s'
% type(targetType))
typeId = '%s:%d' % (targetTypeId, bitsize)
tdata = self.TypeData(self)
tdata.name = '%s : %d' % (targetTypeId, bitsize)
tdata.typeId = typeId
tdata.code = TypeCodeBitfield
tdata.lbitsize = bitsize
self.registerType(typeId, tdata)
return self.Type(self, typeId)
def createTypedefedType(self, targetType, typeId): def createTypedefedType(self, targetType, typeId):
if not isinstance(targetType, self.Type): if not isinstance(targetType, self.Type):
error('Expected type in createTypedefType(), got %s' error('Expected type in createTypedefType(), got %s'
@@ -3661,7 +3725,7 @@ class DumperBase:
if self.autoPadNext: if self.autoPadNext:
self.currentBitsize = 8 * ((self.currentBitsize + 7) >> 3) # Fill up byte. self.currentBitsize = 8 * ((self.currentBitsize + 7) >> 3) # Fill up byte.
padding = (fieldAlign - (self.currentBitsize >> 3)) % fieldAlign padding = (fieldAlign - (self.currentBitsize >> 3)) % fieldAlign
#warn('AUTO PADDING AT %s BITS BY %s BYTES' % (self.currentBitsize, padding)) warn('AUTO PADDING AT %s BITS BY %s BYTES' % (self.currentBitsize, padding))
field = self.dumper.Field(self.dumper) field = self.dumper.Field(self.dumper)
field.code = None field.code = None
#field.lbitpos = self.currentBitsize #field.lbitpos = self.currentBitsize
@@ -3707,7 +3771,7 @@ class DumperBase:
else: else:
typeName += c typeName += c
elif c == 'p': # Pointer as int elif c == 'p': # Pointer as int
builder.addField(ptrSize, 'Q' if ptrSize == 8 else 'I', fieldAlign = ptrSize) builder.addField(ptrSize, self.ptrCode(), fieldAlign = ptrSize)
elif c == 'P': # Pointer as Value elif c == 'P': # Pointer as Value
builder.addField(ptrSize, '%ss' % ptrSize, fieldAlign = ptrSize) builder.addField(ptrSize, '%ss' % ptrSize, fieldAlign = ptrSize)
elif c in ('d'): elif c in ('d'):

View File

@@ -206,8 +206,8 @@ class Dumper(DumperBase):
self.setVariableFetchingOptions(args) self.setVariableFetchingOptions(args)
def fromFrameValue(self, nativeValue): def fromFrameValue(self, nativeValue):
#warn("FROM FRAME VALUE: %s" % nativeValue.address)
val = nativeValue val = nativeValue
if self.useDynamicType:
try: try:
val = nativeValue.cast(nativeValue.dynamic_type) val = nativeValue.cast(nativeValue.dynamic_type)
except: except:
@@ -215,17 +215,21 @@ class Dumper(DumperBase):
return self.fromNativeValue(val) return self.fromNativeValue(val)
def fromNativeValue(self, nativeValue): def fromNativeValue(self, nativeValue):
#warn("FROM NATIVE VALUE: %s" % nativeValue) #warn("FROM NATIVE VALUE: %s" % nativeValue.address)
self.check(isinstance(nativeValue, gdb.Value)) self.check(isinstance(nativeValue, gdb.Value))
nativeType = nativeValue.type nativeType = nativeValue.type
code = nativeType.code code = nativeType.code
if code == gdb.TYPE_CODE_REF: if code == gdb.TYPE_CODE_REF:
targetType = self.fromNativeType(nativeType.target().unqualified()) targetType = self.fromNativeType(nativeType.target().unqualified(), nativeValue)
val = self.createReferenceValue(toInteger(nativeValue.address), targetType) val = self.createReferenceValue(toInteger(nativeValue.address), targetType)
#warn("CREATED REF: %s" % val) #warn("CREATED REF: %s" % val)
return val return val
if code == gdb.TYPE_CODE_PTR: if code == gdb.TYPE_CODE_PTR:
targetType = self.fromNativeType(nativeType.target().unqualified()) try:
nativeTargetValue = nativeValue.dereference()
except:
nativeTargetValue = None
targetType = self.fromNativeType(nativeType.target().unqualified(), nativeTargetValue)
val = self.createPointerValue(toInteger(nativeValue), targetType) val = self.createPointerValue(toInteger(nativeValue), targetType)
#warn("CREATED PTR 1: %s" % val) #warn("CREATED PTR 1: %s" % val)
if not nativeValue.address is None: if not nativeValue.address is None:
@@ -241,7 +245,7 @@ class Dumper(DumperBase):
else: else:
# Cast may fail (e.g for arrays, see test for Bug5799) # Cast may fail (e.g for arrays, see test for Bug5799)
val = self.fromNativeValue(nativeValue.cast(targetType)) val = self.fromNativeValue(nativeValue.cast(targetType))
val.type = self.fromNativeType(nativeType) val.type = self.fromNativeType(nativeType, nativeValue)
#warn("CREATED TYPEDEF: %s" % val) #warn("CREATED TYPEDEF: %s" % val)
return val return val
@@ -257,7 +261,7 @@ class Dumper(DumperBase):
buf[i] = int(y[i]) buf[i] = int(y[i])
val.ldata = bytes(buf) val.ldata = bytes(buf)
val.type = self.fromNativeType(nativeType) val.type = self.fromNativeType(nativeType, nativeValue)
val.lIsInScope = not nativeValue.is_optimized_out val.lIsInScope = not nativeValue.is_optimized_out
code = nativeType.code code = nativeType.code
if code == gdb.TYPE_CODE_ENUM: if code == gdb.TYPE_CODE_ENUM:
@@ -276,7 +280,7 @@ class Dumper(DumperBase):
self.ptrSize = lambda: result self.ptrSize = lambda: result
return result return result
def fromNativeType(self, nativeType): def fromNativeType(self, nativeType, nativeValue = None):
self.check(isinstance(nativeType, gdb.Type)) self.check(isinstance(nativeType, gdb.Type))
code = nativeType.code code = nativeType.code
#warn('FROM NATIVE TYPE: %s' % nativeType) #warn('FROM NATIVE TYPE: %s' % nativeType)
@@ -284,7 +288,9 @@ class Dumper(DumperBase):
if code == gdb.TYPE_CODE_PTR: if code == gdb.TYPE_CODE_PTR:
#warn('PTR') #warn('PTR')
targetType = self.fromNativeType(nativeType.target().unqualified()) if nativeValue is not None:
nativeValue = nativeValue.dereference()
targetType = self.fromNativeType(nativeType.target().unqualified(), nativeValue)
return self.createPointerType(targetType) return self.createPointerType(targetType)
if code == gdb.TYPE_CODE_REF: if code == gdb.TYPE_CODE_REF:
@@ -344,8 +350,7 @@ class Dumper(DumperBase):
if tdata.code == TypeCodeStruct: if tdata.code == TypeCodeStruct:
tdata.lalignment = lambda : \ tdata.lalignment = lambda : \
self.nativeStructAlignment(nativeType) self.nativeStructAlignment(nativeType)
tdata.lfields = lambda value : \ tdata.lfields = self.listMembers(nativeType, nativeValue)
self.listMembers(nativeType, value)
#tdata.lfieldByName = lambda name : \ #tdata.lfieldByName = lambda name : \
# self.nativeTypeFieldTypeByName(nativeType, name) # self.nativeTypeFieldTypeByName(nativeType, name)
tdata.templateArguments = self.listTemplateParameters(nativeType) tdata.templateArguments = self.listTemplateParameters(nativeType)
@@ -394,6 +399,7 @@ class Dumper(DumperBase):
return typeId return typeId
def nativeStructAlignment(self, nativeType): def nativeStructAlignment(self, nativeType):
self.preping('align ' + str(nativeType))
#warn("NATIVE ALIGN FOR %s" % nativeType.name) #warn("NATIVE ALIGN FOR %s" % nativeType.name)
def handleItem(nativeFieldType, align): def handleItem(nativeFieldType, align):
a = self.fromNativeType(nativeFieldType).alignment() a = self.fromNativeType(nativeFieldType).alignment()
@@ -401,62 +407,174 @@ class Dumper(DumperBase):
align = 1 align = 1
for f in nativeType.fields(): for f in nativeType.fields():
align = handleItem(f.type, align) align = handleItem(f.type, align)
self.ping('align ' + str(nativeType))
return align return align
def listMembers(self, nativeType, value):
if not nativeType.code in (gdb.TYPE_CODE_STRUCT, gdb.TYPE_CODE_UNION):
return
if value.laddress == 0: #except:
warn("CANNOT LIST MEMBERS OF NULL VALUE OF %s" % nativeType) # # Happens in the BoostList dumper for a 'const bool'
return # # item named 'constant_time_size'. There isn't anything we can do
if value.laddress is None: # # in this case.
# FIXME: Happens e.g. for QVariant(QBitArray) # pass
addr = self.pokeValue(value) # FIXME: Far too expensive.
#yield value.extractField(field)
def fromNativeField(self, nativeField):
field = self.Field(self)
field.name = nativeField.name
field.isBaseClass = nativeField.is_base_class
# Something without a name.
# Anonymous union? We need a dummy name to distinguish
# multiple anonymous unions in the struct.
# Since GDB commit b5b08fb4 anonymous structs get also reported
# with a 'None' name.
if field.name is not None and len(field.name) == 0:
field.name = None
nativeFieldType = nativeField.type.unqualified()
if hasattr(nativeField, 'bitpos'):
field.lbitpos = nativeField.bitpos
if hasattr(nativeField, 'bitsize') and nativeField.bitsize != 0:
field.lbitsize = nativeField.bitsize
else: else:
addr = value.laddress field.lbitsize = 8 * nativeFieldType.sizeof
nativeTypePointer = nativeType.unqualified().pointer()
nativeValue = gdb.Value(addr).cast(nativeTypePointer).dereference()
#warn('FIELDS FOR %s' % nativeType) if field.lbitsize != nativeFieldType.sizeof * 8:
for nativeField in nativeType.fields(): field.ltype = self.createBitfieldType(str(nativeFieldType), field.lbitsize)
#warn('FIELD: %s' % nativeField) else:
#warn(' BITSIZE: %s' % nativeField.bitsize) field.ltype = self.fromNativeType(nativeFieldType)
#warn(' ARTIFICIAL: %s' % nativeField.artificial) return field
#warn(' NAME: %s' % nativeField.name)
#warn(' TYPE: %s' % nativeField.type) def memberFromField(self, nativeValue, nativeField):
#warn(' TYPEID: %s' % self.nativeTypeId(nativeField.type)) if nativeField.is_base_class:
val = nativeValue[nativeField] return nativeValue.cast(nativeField.type)
#warn('VAL: %s' % val)
try: try:
# Remove 'const', fails for 'const bool' members in some containers. return nativeValue[nativeField]
val = val.cast(nativeField.type.unqualified())
except: except:
pass pass
try: try:
member = self.fromNativeValue(val) return nativeValue[nativeField.name]
except: except:
#warn('CANNOT CREATE FIELD: %s' % nativeField.name) pass
continue return None
member.name = nativeField.name
def listMembers(self, nativeType, nativeValue):
#warn("LISTING MEMBERS OF %s" % nativeType)
try:
nativeValueAddress = toInteger(nativeValue.address)
except:
nativeValueAddress = None
if nativeValue is None or nativeValueAddress is None:
return lambda value : self.listDelayedMembers(nativeType, value)
def needsDeep(someNativeType):
if someNativeType.sizeof >= ptrSize:
for nativeField in someNativeType.fields():
if nativeField.is_base_class: if nativeField.is_base_class:
member.isBaseClass = True if nativeField.bitpos < 0 or needsDeep(nativeField.type):
else: return True
if hasattr(nativeField, 'bitpos'): return False
member.lbitpos = nativeField.bitpos
# Correction for some bitfields. Size 0 can occur for ptrSize = self.ptrSize()
# types without debug information. if needsDeep(nativeType):
bitsize = 8 * nativeField.type.sizeof return self.listDeepMembers(nativeType, nativeValue, nativeValueAddress)
if bitsize > 0:
member.lbitpos = nativeField.bitpos % bitsize return self.listSimpleMembers(nativeType, nativeValue, nativeValueAddress)
if hasattr(nativeField, 'bitsize') and nativeField.bitsize != 0:
member.lbitsize = nativeField.bitsize def listSimpleMembers(self, nativeType, nativeValue, nativeValueAddress):
else: #warn('SIMPLE FIELDS FOR %s' % nativeType)
member.lbitsize = 8 * nativeField.type.sizeof fields = []
#warn('MEMBER: %s' % member) for nativeField in nativeType.fields():
yield member nativeFieldType = nativeField.type.unqualified()
#warn('SIMPLE FIELD: %s' % nativeField.name)
#warn(' BITSIZE: %s' % nativeField.bitsize)
#warn(' NAME: %s' % nativeField.name)
#warn(' TYPE: %s' % nativeFieldType)
#warn(' TYPEID: %s' % self.nativeTypeId(nativeFieldType))
field = self.fromNativeField(nativeField)
if field.ltype.code != TypeCodeBitfield:
nativeMember = self.memberFromField(nativeValue, nativeField)
if nativeMember is None:
warn('CANNOT EXTRACT FIELD %s FROM %s' % (nativeField.name, nativeValue))
#continue
if nativeMember.address is None: # Could be a static member.
warn('NO ADDRESS OF %s' % nativeMember)
continue
nativeMemberAddress = toInteger(nativeMember.address)
offset = nativeMemberAddress - nativeValueAddress
field.lbitpos = 8 * offset
fields.append(field)
return fields
def listDelayedMembers(self, nativeType, value):
#warn('DELAYED FIELDS FOR %s' % nativeType)
if value.laddress is None: if value.laddress is None:
self.releaseValue(addr) error('No address for object of type %s' % nativeType)
nativeTypePointer = nativeType.unqualified().pointer()
nativeValue = gdb.Value(value.laddress).cast(nativeTypePointer).dereference()
return self.listSimpleMembers(nativeType, nativeValue, value.laddress)
# The is expensive as it recurses through all base classes. Ideally this
# should only be used if virtual inheritance is known to be involved.
def listDeepMembers(self, nativeType, nativeValue, nativeBaseAddress, bpbase = 0):
#warn('DEEP FIELDS FOR %s AT 0x%x' % (nativeType, nativeBaseAddress))
fields = []
for nativeField in nativeType.fields():
nativeFieldType = nativeField.type.unqualified()
#warn('DEEP FIELD: %s' % nativeField.name)
#warn(' SIZE: %s' % nativeField.bitsize)
#warn(' POS: %s' % nativeField.bitpos)
#warn(' BPBASE: %s' % bpbase)
#warn(' ARTIFICIAL: %s' % nativeField.artificial)
#warn(' NAME: %s' % nativeField.name)
#warn(' TYPE: %s' % nativeFieldType)
#warn(' TYPEID: %s' % self.nativeTypeId(nativeFieldType))
nativeMember = self.memberFromField(nativeValue, nativeField)
if nativeField.is_base_class:
#warn(' THIS IS VIRTUAL BASE OF TYPE %s' % nativeField.type)
# This is a virtual base, we need to recurse *now*, as later
# there is no way to generate a nativeValue with this type.
#warn(' NATIVE MEMBER: %s' % nativeMember)
pureFieldType = self.fromNativeType(nativeFieldType)
fieldTypeId = pureFieldType.typeId + ' in ' + str(nativeType)
fieldTypeData = pureFieldType.typeData().copy()
bp = - nativeField.bitpos
fieldTypeData.lfields = self.listDeepMembers(
nativeField.type, nativeMember, nativeBaseAddress, bpbase + bp - 64)
self.registerType(fieldTypeId, fieldTypeData)
field = self.Field(self)
field.name = nativeField.name
#field.name = fieldTypeId
field.ltype = self.Type(self, fieldTypeId)
field.isBaseClass = True
field.isArtificial = True
field.lbitsize = None
field.lbitpos = None
fields.append(field)
else:
# This is a normal field or non-virtual base.
field = self.fromNativeField(nativeField)
if field.ltype.code != TypeCodeBitfield:
#if field.lbitpos is None:
try:
nativeMemberAddress = toInteger(nativeMember.address)
#warn(' NATIVE MEMBER ADDRESS: 0x%x' % nativeMemberAddress)
offset = nativeMemberAddress - nativeBaseAddress
#offset = bpbase + nativeField.bitpos
#warn("DEEP OFFSET: %s POS: %s" % (offset // 8, field.lbitpos // 8))
field.lbitpos = offset * 8
except:
field.lbitpos = None
field.lvalue = "XXX"
#else:
# warn("REUSING BITPOS %s FOR %s" % (field.lbitpos, field.name))
fields.append(field)
return fields
def listLocals(self, partialVar): def listLocals(self, partialVar):
frame = gdb.selected_frame() frame = gdb.selected_frame()
@@ -492,19 +610,21 @@ class Dumper(DumperBase):
# "NotImplementedError: Symbol type not yet supported in # "NotImplementedError: Symbol type not yet supported in
# Python scripts." # Python scripts."
#warn("SYMBOL %s (%s, %s)): " % (symbol, name, symbol.name)) #warn("SYMBOL %s (%s, %s)): " % (symbol, name, symbol.name))
if False and self.passExceptions: if self.passExceptions and not self.isTesting:
value = self.fromFrameValue(frame.read_var(name, block)) nativeValue = frame.read_var(name, block)
value = self.fromFrameValue(nativeValue)
value.name = name value.name = name
#warn("READ 1: %s" % value.stringify()) #warn("READ 0: %s" % value.stringify())
items.append(value) items.append(value)
continue continue
try: try:
# Same as above, but for production. # Same as above, but for production.
value = self.fromFrameValue(frame.read_var(name, block)) nativeValue = frame.read_var(name, block)
value = self.fromFrameValue(nativeValue)
value.name = name value.name = name
#warn("READ 1: %s" % value.stringify())
items.append(value) items.append(value)
#warn("READ 1: %s" % value.stringify())
continue continue
except: except:
pass pass
@@ -554,6 +674,11 @@ class Dumper(DumperBase):
self.resetStats() self.resetStats()
self.prepare(args) self.prepare(args)
self.preping('endian')
self.isBigEndian = gdb.execute('show endian', to_string = True).find('big endian') > 0
self.ping('endian')
self.packCode = '>' if self.isBigEndian else '<'
(ok, res) = self.tryFetchInterpreterVariables(args) (ok, res) = self.tryFetchInterpreterVariables(args)
if ok: if ok:
safePrint(res) safePrint(res)
@@ -566,6 +691,7 @@ class Dumper(DumperBase):
partialName = partialVar.split('.')[1].split('@')[0] if isPartial else None partialName = partialVar.split('.')[1].split('@')[0] if isPartial else None
variables = self.listLocals(partialName) variables = self.listLocals(partialName)
#warn("VARIABLES: %s" % variables)
# Take care of the return value of the last function call. # Take care of the return value of the last function call.
if len(self.resultVarName) > 0: if len(self.resultVarName) > 0:
@@ -705,7 +831,13 @@ class Dumper(DumperBase):
return self.cachedInferior return self.cachedInferior
def readRawMemory(self, address, size): def readRawMemory(self, address, size):
return self.selectedInferior().read_memory(address, size) #warn('READ: %s FROM 0x%x' % (size, address))
if address == 0 or size == 0:
return bytes()
self.preping('readMem')
res = self.selectedInferior().read_memory(address, size)
self.ping('readMem')
return res
def findStaticMetaObject(self, typename): def findStaticMetaObject(self, typename):
symbolName = typename + "::staticMetaObject" symbolName = typename + "::staticMetaObject"
@@ -774,21 +906,6 @@ class Dumper(DumperBase):
# Use fallback until we have a better answer. # Use fallback until we have a better answer.
return self.fallbackQtVersion return self.fallbackQtVersion
def isQt3Support(self):
if self.qtVersion() >= 0x050000:
return False
else:
try:
# This will fail on Qt 4 without Qt 3 support
gdb.execute("ptype QChar::null", to_string=True)
self.cachedIsQt3Suport = True
except:
self.cachedIsQt3Suport = False
# Memoize good results.
self.isQt3Support = lambda: self.cachedIsQt3Suport
return self.cachedIsQt3Suport
def createSpecialBreakpoints(self, args): def createSpecialBreakpoints(self, args):
self.specialBreakpoints = [] self.specialBreakpoints = []
def newSpecial(spec): def newSpecial(spec):
@@ -891,6 +1008,12 @@ class Dumper(DumperBase):
self.importPlainDumper(printer) self.importPlainDumper(printer)
def qtNamespace(self): def qtNamespace(self):
self.preping('qtNamespace')
res = self.qtNamespaceX()
self.ping('qtNamespace')
return res
def qtNamespaceX(self):
if not self.currentQtNamespaceGuess is None: if not self.currentQtNamespaceGuess is None:
return self.currentQtNamespaceGuess return self.currentQtNamespaceGuess
@@ -919,28 +1042,8 @@ class Dumper(DumperBase):
except: except:
pass pass
try: self.currentQtNamespaceGuess = ''
# Last fall backs. return ''
s = gdb.execute("ptype QByteArray", to_string=True)
if s.find("QMemArray") >= 0:
# Qt 3.
self.qtNamespaceToReport = ""
self.qtNamespace = lambda: ""
self.qtVersion = lambda: 0x30308
self.fallbackQtVersion = 0x30308
return ""
# Seemingly needed with Debian's GDB 7.4.1
pos1 = s.find("class")
pos2 = s.find("QByteArray")
if pos1 > -1 and pos2 > -1:
ns = s[s.find("class") + 6:s.find("QByteArray")]
self.qtNamespaceToReport = ns
self.qtNamespace = lambda: ns
return ns
except:
pass
self.currentQtNamespaceGuess = ""
return ""
def assignValue(self, args): def assignValue(self, args):
typeName = self.hexdecode(args['type']) typeName = self.hexdecode(args['type'])
@@ -963,18 +1066,31 @@ class Dumper(DumperBase):
gdb.execute(cmd) gdb.execute(cmd)
def nativeDynamicTypeName(self, address, baseType): def nativeDynamicTypeName(self, address, baseType):
try: # Needed for Gdb13393 test.
vtbl = gdb.execute("info symbol {%s*}0x%x" % (baseType.name, address), to_string = True) nativeType = self.lookupNativeType(baseType.name)
except: nativeTypePointer = nativeType.pointer()
return None nativeValue = gdb.Value(address).cast(nativeTypePointer).dereference()
pos1 = vtbl.find("vtable ") val = nativeValue.cast(nativeValue.dynamic_type)
if pos1 == -1: return str(val.type)
return None #try:
pos1 += 11 # vtbl = gdb.execute("info symbol {%s*}0x%x" % (baseType.name, address), to_string = True)
pos2 = vtbl.find(" +", pos1) #except:
if pos2 == -1: # return None
return None #pos1 = vtbl.find("vtable ")
return vtbl[pos1 : pos2] #if pos1 == -1:
# return None
#pos1 += 11
#pos2 = vtbl.find(" +", pos1)
#if pos2 == -1:
# return None
#return vtbl[pos1 : pos2]
def nativeDynamicType(self, address, baseType):
# Needed for Gdb13393 test.
nativeType = self.lookupNativeType(baseType.name)
nativeTypePointer = nativeType.pointer()
nativeValue = gdb.Value(address).cast(nativeTypePointer).dereference()
return self.fromNativeType(nativeValue.dynamic_type)
def enumExpression(self, enumType, enumValue): def enumExpression(self, enumType, enumValue):
return self.qtNamespace() + "Qt::" + enumValue return self.qtNamespace() + "Qt::" + enumValue

View File

@@ -225,17 +225,11 @@ class Dumper(DumperBase):
return align return align
def listMembers(self, nativeType, value): def listMembers(self, nativeType, value):
if value.laddress is not None: #warn("ADDR: 0x%x" % self.fakeAddress)
sbaddr = lldb.SBAddress(value.laddress, self.target) fakeAddress = self.fakeAddress if value.laddress is None else value.laddress
nativeValue = self.target.CreateValueFromAddress('x', sbaddr, nativeType) sbaddr = lldb.SBAddress(fakeAddress, self.target)
else: fakeValue = self.target.CreateValueFromAddress('x', sbaddr, nativeType)
try: fakeValue.SetPreferSyntheticValue(False)
nativeValue = self.target.CreateValueFromData('x', value.data(), nativeType)
except:
return
nativeValue.SetPreferSyntheticValue(False)
nativeType = nativeValue.GetType()
baseNames = {} baseNames = {}
for i in range(nativeType.GetNumberOfDirectBaseClasses()): for i in range(nativeType.GetNumberOfDirectBaseClasses()):
@@ -253,25 +247,44 @@ class Dumper(DumperBase):
if bitsize > 0: if bitsize > 0:
#bitpos = bitpos % bitsize #bitpos = bitpos % bitsize
bitpos = bitpos % 8 # Reported type is always wrapping type! bitpos = bitpos % 8 # Reported type is always wrapping type!
#warn("BIT SIZE: %s POS: %s NAME: %s" % (bitsize, bitpos, f.name))
fieldBits[f.name] = (bitsize, bitpos) fieldBits[f.name] = (bitsize, bitpos)
# Normal members and non-empty base classes. # Normal members and non-empty base classes.
for i in range(nativeValue.GetNumChildren()): for i in range(fakeValue.GetNumChildren()):
fieldObj = nativeValue.GetChildAtIndex(i) nativeField = fakeValue.GetChildAtIndex(i)
fieldObj.SetPreferSyntheticValue(False) nativeField.SetPreferSyntheticValue(False)
fieldName = fieldObj.GetName()
member = self.fromNativeValue(fieldObj) field = self.Field(self)
member.name = fieldName field.name = nativeField.GetName()
if fieldName in baseNames: nativeFieldType = nativeField.GetType()
member.isBaseClass = True
if fieldName in fieldBits: if field.name in fieldBits:
(member.lbitsize, member.lbitpos) = fieldBits[fieldName] (field.lbitsize, field.lbitpos) = fieldBits[field.name]
else: else:
member.lbitsize = fieldObj.GetType().GetByteSize() * 8 field.lbitsize = nativeFieldType.GetByteSize() * 8
#member.lbitpos = (caddr - addr) * 8
#warn("MEMBER: %s" % member) if field.lbitsize != nativeFieldType.GetByteSize() * 8:
yield member field.ltype = self.createBitfieldType(self.typeName(nativeFieldType), field.lbitsize)
else:
fakeMember = fakeValue.GetChildAtIndex(i)
#try:
fakeMemberAddress = fakeMember.GetLoadAddress()
#except:
# # Happens in the BoostList dumper for a 'const bool'
# # item named 'constant_time_size'. There isn't anything we can do
# # in this case.
# continue
offset = fakeMemberAddress - fakeAddress
field.lbitpos = 8 * offset
field.ltype = self.fromNativeType(nativeFieldType)
if field.name in baseNames:
field.isBaseClass = True
field.baseIndex = baseNames[field.name]
yield field
# Empty bases are not covered above. # Empty bases are not covered above.
for i in range(nativeType.GetNumberOfDirectBaseClasses()): for i in range(nativeType.GetNumberOfDirectBaseClasses()):
@@ -357,10 +370,7 @@ class Dumper(DumperBase):
return self.createTypedefedType(targetType, nativeType.GetName()) return self.createTypedefedType(targetType, nativeType.GetName())
nativeType = nativeType.GetUnqualifiedType() nativeType = nativeType.GetUnqualifiedType()
if hasattr(nativeType, 'GetDisplayTypeName'): typeName = self.typeName(nativeType)
typeName = nativeType.GetDisplayTypeName() # Xcode 6 (lldb-320)
else:
typeName = nativeType.GetName() # Xcode 5 (lldb-310)
if code in (lldb.eTypeClassArray, lldb.eTypeClassVector): if code in (lldb.eTypeClassArray, lldb.eTypeClassVector):
#warn('ARRAY: %s' % nativeType.GetName()) #warn('ARRAY: %s' % nativeType.GetName())
@@ -480,11 +490,16 @@ class Dumper(DumperBase):
#warn('TARGS: %s %s' % (nativeType.GetName(), [str(x) for x in targs])) #warn('TARGS: %s %s' % (nativeType.GetName(), [str(x) for x in targs]))
return targs return targs
def nativeTypeId(self, nativeType): def typeName(self, nativeType):
if hasattr(nativeType, 'GetDisplayTypeName'): if hasattr(nativeType, 'GetDisplayTypeName'):
name = nativeType.GetDisplayTypeName() # Xcode 6 (lldb-320) return nativeType.GetDisplayTypeName() # Xcode 6 (lldb-320)
else: return nativeType.GetName() # Xcode 5 (lldb-310)
name = nativeType.GetName() # Xcode 5 (lldb-310)
def nativeTypeId(self, nativeType):
name = self.typeName(nativeType)
def nativeTypeId(self, nativeType):
name = self.typeName(nativeType)
if name is None or len(name) == 0: if name is None or len(name) == 0:
c = '0' c = '0'
elif name == '(anonymous struct)' and nativeType.GetTypeClass() == lldb.eTypeClassStruct: elif name == '(anonymous struct)' and nativeType.GetTypeClass() == lldb.eTypeClassStruct:
@@ -1048,6 +1063,10 @@ class Dumper(DumperBase):
self.setVariableFetchingOptions(args) self.setVariableFetchingOptions(args)
anyModule = self.target.GetModuleAtIndex(0)
anySymbol = anyModule.GetSymbolAtIndex(0)
self.fakeAddress = int(anySymbol.GetStartAddress())
frame = self.currentFrame() frame = self.currentFrame()
if frame is None: if frame is None:
self.reportResult('error="No frame"', args) self.reportResult('error="No frame"', args)

View File

@@ -1632,6 +1632,7 @@ def qdump__QVariant(d, value):
else: else:
#warn('DIRECT ITEM 1: %s' % innerType) #warn('DIRECT ITEM 1: %s' % innerType)
val = d.createValue(data, innerType) val = d.createValue(data, innerType)
val.laddress = value.laddress
d.putEmptyValue(-99) d.putEmptyValue(-99)
d.putItem(val) d.putItem(val)

View File

@@ -1374,7 +1374,7 @@ void tst_Dumpers::dumper()
"python theDumper.fetchVariables({" "python theDumper.fetchVariables({"
"'token':2,'fancy':1,'forcens':1," "'token':2,'fancy':1,'forcens':1,"
"'autoderef':1,'dyntype':1,'passexceptions':1," "'autoderef':1,'dyntype':1,'passexceptions':1,"
"'qobjectnames':1," "'testing':1,'qobjectnames':1,"
"'expanded':[" + expandedq + "]})\n"; "'expanded':[" + expandedq + "]})\n";
cmds += "quit\n"; cmds += "quit\n";
@@ -1398,7 +1398,7 @@ void tst_Dumpers::dumper()
"!qtcreatorcdbext.script -t 42 theDumper.fetchVariables({" "!qtcreatorcdbext.script -t 42 theDumper.fetchVariables({"
"'token':2,'fancy':1,'forcens':1," "'token':2,'fancy':1,'forcens':1,"
"'autoderef':1,'dyntype':1,'passexceptions':0," "'autoderef':1,'dyntype':1,'passexceptions':0,"
"'qobjectnames':1," "'testing':1,'qobjectnames':1,"
"'expanded':[" + expandedq + "]})\n" "'expanded':[" + expandedq + "]})\n"
"q\n"; "q\n";
} else if (m_debuggerEngine == LldbEngine) { } else if (m_debuggerEngine == LldbEngine) {
@@ -1413,7 +1413,7 @@ void tst_Dumpers::dumper()
// "sc print(dir())\n" // "sc print(dir())\n"
"sc Tester('" + t->buildPath.toLatin1() + "/doit', {'fancy':1,'forcens':1," "sc Tester('" + t->buildPath.toLatin1() + "/doit', {'fancy':1,'forcens':1,"
"'autoderef':1,'dyntype':1,'passexceptions':1," "'autoderef':1,'dyntype':1,'passexceptions':1,"
"'qobjectnames':1," "'testing':1,'qobjectnames':1,"
"'expanded':[" + expandedq + "]})\n" "'expanded':[" + expandedq + "]})\n"
"quit\n"; "quit\n";
@@ -5943,7 +5943,12 @@ void tst_Dumpers::dumper_data()
" { T1() : i1(1) {} int i1; };\n" " { T1() : i1(1) {} int i1; };\n"
"struct T2 : virtual VEmpty, virtual VData\n" "struct T2 : virtual VEmpty, virtual VData\n"
" { T2() : i2(1) {} int i2; };\n" " { T2() : i2(1) {} int i2; };\n"
"struct TT : T1, T2 { TT() : c(1) {} int c; };\n"; "struct TT : T1, T2 { TT() : c(1) {} int c; };\n"
"struct A { int a = 1; char aa = 'a'; };\n"
"struct B : virtual A { int b = 2; float bb = 2; };\n"
"struct C : virtual A { int c = 3; double cc = 3; };\n"
"struct D : virtual B, virtual C { int d = 4; };\n";
QTest::newRow("Inheritance") QTest::newRow("Inheritance")
<< Data(inheritanceData, << Data(inheritanceData,
@@ -5956,7 +5961,11 @@ void tst_Dumpers::dumper_data()
"TT tt;\n" "TT tt;\n"
"tt.T1::v = 44;\n" "tt.T1::v = 44;\n"
"tt.T2::v = 45;\n" "tt.T2::v = 45;\n"
"unused(&tt.T2::v);\n") "unused(&tt.T2::v);\n"
"D dd; unused(&dd);\n"
"D *dp = new D; unused(&dp);\n"
"D &dr = dd; unused(&dr);\n")
+ Cxx11Profile()
+ Check("c.c", "1", "int") + Check("c.c", "1", "int")
+ Check("c.@1.@2.a", "42", "int") % NoLldbEngine + Check("c.@1.@2.a", "42", "int") % NoLldbEngine
+ Check("c.@1.@4.v", "45", "int") % NoLldbEngine + Check("c.@1.@4.v", "45", "int") % NoLldbEngine
@@ -5970,7 +5979,26 @@ void tst_Dumpers::dumper_data()
+ Check("tt.@1.@2.v", "45", "int") % NoLldbEngine + Check("tt.@1.@2.v", "45", "int") % NoLldbEngine
+ Check("tt.@2.@2.v", "45", "int") % NoLldbEngine + Check("tt.@2.@2.v", "45", "int") % NoLldbEngine
+ Check("tt.@1.@1.v", "45", "int") % LldbEngine + Check("tt.@1.@1.v", "45", "int") % LldbEngine
+ Check("tt.@2.@1.v", "45", "int") % LldbEngine; + Check("tt.@2.@1.v", "45", "int") % LldbEngine
+ Check("dd.@1.@1.a", "1", "int") // B::a
+ Check("dd.@2.@1.a", "1", "int") // C::a
+ Check("dd.@1.b", "2", "int")
+ Check("dd.@2.c", "3", "int")
+ Check("dd.d", "4", "int")
+ Check("dp.@1.@1.a", "1", "int") // B::a
+ Check("dp.@2.@1.a", "1", "int") // C::a
+ Check("dp.@1.b", "2", "int")
+ Check("dp.@2.c", "3", "int")
+ Check("dp.d", "4", "int")
+ Check("dr.@1.@1.a", "1", "int") // B::a
+ Check("dr.@2.@1.a", "1", "int") // C::a
+ Check("dr.@1.b", "2", "int")
+ Check("dr.@2.c", "3", "int")
+ Check("dr.d", "4", "int");
QTest::newRow("Gdb13393") QTest::newRow("Gdb13393")
<< Data( << Data(