aboutsummaryrefslogtreecommitdiffstats
path: root/share/qtcreator
diff options
context:
space:
mode:
authorhjk <hjk@qt.io>2024-03-20 12:32:54 +0100
committerhjk <hjk@qt.io>2024-05-07 10:15:34 +0000
commit67072d3f5bb1b425a2b9d3bf30d57542e9f88902 (patch)
tree33629f7ce113ae83b6554456cd272250e17cfced /share/qtcreator
parent1218175c7833e7682201f4f8885fba028c992624 (diff)
Debugger: Re-work bridges
The type cache has been split into smaller caches for individual aspects. Type ids are now integral, not strings. In addition, there is new supporting code for logging, timing and profiling Change-Id: I6db72a149650d42aecf8b899869c542b1303d43b Reviewed-by: David Schulz <david.schulz@qt.io> Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Diffstat (limited to 'share/qtcreator')
-rw-r--r--share/qtcreator/debugger/cdbbridge.py161
-rw-r--r--share/qtcreator/debugger/dumper.py2816
-rw-r--r--share/qtcreator/debugger/gdbbridge.py656
-rw-r--r--share/qtcreator/debugger/lldbbridge.py606
-rw-r--r--share/qtcreator/debugger/qttypes.py68
5 files changed, 2208 insertions, 2099 deletions
diff --git a/share/qtcreator/debugger/cdbbridge.py b/share/qtcreator/debugger/cdbbridge.py
index b5fc683cba..4ac053eb55 100644
--- a/share/qtcreator/debugger/cdbbridge.py
+++ b/share/qtcreator/debugger/cdbbridge.py
@@ -75,6 +75,13 @@ class Dumper(DumperBase):
self.outputLock = threading.Lock()
self.isCdb = True
+ #FIXME
+ typeid = self.typeid_for_string('@QVariantMap')
+ del self.type_code_cache[typeid]
+ del self.type_target_cache[typeid]
+ del self.type_size_cache[typeid]
+ del self.type_alignment_cache[typeid]
+
def enumValue(self, nativeValue):
val = nativeValue.nativeDebuggerValue()
# remove '0n' decimal prefix of the native cdb value output
@@ -117,6 +124,7 @@ class Dumper(DumperBase):
elif not nativeValue.type().resolved and nativeValue.type().code() == TypeCode.Struct and not nativeValue.hasChildren():
val.ldisplay = self.enumValue(nativeValue)
val.isBaseClass = val.name == nativeValue.type().name()
+ val.typeid = self.from_native_type(nativeValue.type())
val.nativeValue = nativeValue
val.laddress = nativeValue.address()
val.lbitsize = nativeValue.bitsize()
@@ -137,14 +145,10 @@ class Dumper(DumperBase):
for f in nativeType.fields()])
return typeId
- def nativeValueType(self, nativeValue):
- return self.fromNativeType(nativeValue.type())
-
- def fromNativeType(self, nativeType):
+ def from_native_type(self, nativeType):
self.check(isinstance(nativeType, cdbext.Type))
- typeId = self.nativeTypeId(nativeType)
- if self.typeData.get(typeId, None) is not None:
- return self.Type(self, typeId)
+ typeid = self.typeid_for_string(self.nativeTypeId(nativeType))
+ self.type_nativetype_cache[typeid] = nativeType
if nativeType.name().startswith('void'):
nativeType = FakeVoidType(nativeType.name(), self)
@@ -154,70 +158,61 @@ class Dumper(DumperBase):
if nativeType.name().startswith('<function>'):
code = TypeCode.Function
elif nativeType.targetName() != nativeType.name():
- return self.createPointerType(nativeType.targetName())
+ return self.create_pointer_typeid(self.typeid_for_string(nativeType.targetName()))
if code == TypeCode.Array:
# cdb reports virtual function tables as arrays those ar handled separetly by
# the DumperBase. Declare those types as structs prevents a lookup to a
# none existing type
if not nativeType.name().startswith('__fptr()') and not nativeType.name().startswith('<gentype '):
- targetName = nativeType.targetName()
- count = nativeType.arrayElements()
- if targetName.endswith(']'):
- (prefix, suffix, inner_count) = self.splitArrayType(targetName)
- type_name = '%s[%d][%d]%s' % (prefix, count, inner_count, suffix)
- else:
- type_name = '%s[%d]' % (targetName, count)
- tdata = self.TypeData(self, typeId)
- tdata.name = type_name
- tdata.code = TypeCode.Array
- tdata.ltarget = targetName
- tdata.lbitsize = lambda: nativeType.bitsize()
- return self.Type(self, typeId)
+ targetName = nativeType.targetName().strip()
+ self.type_name_cache[typeid] = nativeType.name()
+ self.type_code_cache[typeid] = code
+ self.type_target_cache[typeid] = self.typeid_for_string(targetName)
+ self.type_size_cache[typeid] = nativeType.bitsize() // 8
+ return typeid
code = TypeCode.Struct
- tdata = self.TypeData(self, typeId)
- tdata.name = nativeType.name()
- tdata.lbitsize = lambda: nativeType.bitsize()
- tdata.code = code
- tdata.moduleName = lambda: nativeType.module()
- if code == TypeCode.Struct:
- tdata.lfields = lambda value: \
- self.listFields(nativeType, value)
- tdata.lalignment = lambda: \
- self.nativeStructAlignment(nativeType)
- tdata.enumDisplay = lambda intval, addr, form: \
+ self.type_name_cache[typeid] = nativeType.name()
+ self.type_size_cache[typeid] = nativeType.bitsize() // 8
+ self.type_code_cache[typeid] = code
+ self.type_modulename_cache[typeid] = nativeType.module()
+ self.type_enum_display_cache[typeid] = lambda intval, addr, form: \
self.nativeTypeEnumDisplay(nativeType, intval, form)
- tdata.templateArguments = lambda: \
- self.listTemplateParameters(nativeType.name())
- return self.Type(self, typeId)
+ return typeid
- def listNativeValueChildren(self, nativeValue):
+ def listNativeValueChildren(self, nativeValue, include_bases):
+ fields = []
index = 0
nativeMember = nativeValue.childFromIndex(index)
while nativeMember:
+ # Why this restriction to things with address? Can't nativeValue
+ # be e.g. located in registers, without address?
if nativeMember.address() != 0:
- yield self.fromNativeValue(nativeMember)
+ if include_bases or nativeMember.name() != nativeMember.type().name():
+ field = self.fromNativeValue(nativeMember)
+ fields.append(field)
index += 1
nativeMember = nativeValue.childFromIndex(index)
+ return fields
- def listValueChildren(self, value):
+ def listValueChildren(self, value, include_bases=True):
nativeValue = value.nativeValue
if nativeValue is None:
nativeValue = cdbext.createValue(value.address(), self.lookupNativeType(value.type.name, 0))
- return self.listNativeValueChildren(nativeValue)
+ return self.listNativeValueChildren(nativeValue, include_bases)
- def listFields(self, nativeType, value):
+ def nativeListMembers(self, value, native_type, include_bases):
nativeValue = value.nativeValue
if nativeValue is None:
- nativeValue = cdbext.createValue(value.address(), nativeType)
- return self.listNativeValueChildren(nativeValue)
+ nativeValue = cdbext.createValue(value.address(), native_type)
+ return self.listNativeValueChildren(nativeValue, include_bases)
def nativeStructAlignment(self, nativeType):
#DumperBase.warn("NATIVE ALIGN FOR %s" % nativeType.name)
def handleItem(nativeFieldType, align):
- a = self.fromNativeType(nativeFieldType).alignment()
+ a = self.type_alignment(self.from_native_type(nativeFieldType))
return a if a > align else align
align = 1
for f in nativeType.fields():
@@ -398,20 +393,6 @@ class Dumper(DumperBase):
else:
return typeName
- def lookupType(self, typeNameIn, module=0):
- if len(typeNameIn) == 0:
- return None
- typeName = self.stripQintTypedefs(typeNameIn)
- if self.typeData.get(typeName, None) is None:
- nativeType = self.lookupNativeType(typeName, module)
- if nativeType is None:
- return None
- _type = self.fromNativeType(nativeType)
- if _type.typeId != typeName:
- self.registerTypeAlias(_type.typeId, typeName)
- return _type
- return self.Type(self, typeName)
-
def lookupNativeType(self, name, module=0):
if name.startswith('void'):
return FakeVoidType(name, self)
@@ -439,9 +420,6 @@ class Dumper(DumperBase):
ptr = cdbext.getAddressByName(type.name + '::staticMetaObject')
return ptr
- def warn(self, msg):
- self.put('{name="%s",value="",type="",numchild="0"},' % msg)
-
def fetchVariables(self, args):
self.resetStats()
(ok, res) = self.tryFetchInterpreterVariables(args)
@@ -458,13 +436,17 @@ class Dumper(DumperBase):
self.anonNumber = 0
variables = []
- for val in cdbext.listOfLocals(self.partialVariable):
- dumperVal = self.fromNativeValue(val)
- dumperVal.lIsInScope = dumperVal.name not in self.uninitialized
- variables.append(dumperVal)
+ try:
+ for val in cdbext.listOfLocals(self.partialVariable):
+ dumperVal = self.fromNativeValue(val)
+ dumperVal.lIsInScope = dumperVal.name not in self.uninitialized
+ variables.append(dumperVal)
- self.handleLocals(variables)
- self.handleWatches(args)
+ self.handleLocals(variables)
+ self.handleWatches(args)
+ except Exception:
+ t,v,tb = sys.exc_info()
+ self.showException("FETCH VARIABLES", t, v, tb)
self.put('],partial="%d"' % (len(self.partialVariable) > 0))
self.put(',timings=%s' % self.timings)
@@ -485,9 +467,6 @@ class Dumper(DumperBase):
def findValueByExpression(self, exp):
return cdbext.parseAndEvaluate(exp)
- def nativeDynamicTypeName(self, address, baseType):
- return None # Does not work with cdb
-
def nativeValueDereferenceReference(self, value):
return self.nativeValueDereferencePointer(value)
@@ -518,7 +497,7 @@ class Dumper(DumperBase):
else:
val = self.Value(self)
val.laddress = value.pointer()
- val._type = DumperBase.Type(self, value.type.targetName)
+ val.typeid = self.typeid_for_string(value.type.targetName)
val.nativeValue = value.nativeValue
return val
@@ -540,14 +519,11 @@ class Dumper(DumperBase):
res = self.nativeParseAndEvaluate(symbolName)
return None if res is None else res.address()
- def putItemX(self, value):
- #DumperBase.warn('PUT ITEM: %s' % value.stringify())
+ def putItem(self, value: DumperBase.Value):
typeobj = value.type # unqualified()
typeName = typeobj.name
- self.addToCache(typeobj) # Fill type cache
-
if not value.lIsInScope:
self.putSpecialValue('optimizedout')
#self.putType(typeobj)
@@ -571,8 +547,7 @@ class Dumper(DumperBase):
return
self.putAddress(value.address())
- if value.lbitsize is not None:
- self.putField('size', value.lbitsize // 8)
+ self.putField('size', self.type_size(value.typeid))
if typeobj.code == TypeCode.Function:
#DumperBase.warn('FUNCTION VALUE: %s' % value)
@@ -738,7 +713,7 @@ class Dumper(DumperBase):
#DumperBase.warn('INAME: %s' % self.currentIName)
if self.autoDerefPointers:
# Generic pointer type with AutomaticFormat, but never dereference char types:
- if value.type.targetName not in (
+ if value.type.targetName.strip() not in (
'char',
'signed char',
'int8_t',
@@ -769,7 +744,7 @@ class Dumper(DumperBase):
def putCStyleArray(self, value):
arrayType = value.type
- innerType = arrayType.ltarget
+ innerType = arrayType.target()
address = value.address()
if address:
self.putValue('@0x%x' % address, priority=-1)
@@ -783,7 +758,7 @@ class Dumper(DumperBase):
p = value.address()
if displayFormat != DisplayFormat.Raw and p:
- if innerType.name in (
+ if innerType.name.strip() in (
'char',
'int8_t',
'qint8',
@@ -828,7 +803,7 @@ class Dumper(DumperBase):
innerSize = innerType.size()
self.putNumChild(n)
#DumperBase.warn('ADDRESS: 0x%x INNERSIZE: %s INNERTYPE: %s' % (addrBase, innerSize, innerType))
- enc = innerType.simpleEncoding()
+ enc = self.type_encoding_cache.get(innerType.typeid, None)
maxNumChild = self.maxArrayCount()
if enc:
self.put('childtype="%s",' % innerType.name)
@@ -863,12 +838,8 @@ class Dumper(DumperBase):
if innerType in ('wchar_t', 'WCHAR'):
self.putType(typeName)
- charSize = self.lookupType('wchar_t').size()
- (length, data) = self.encodeCArray(ptr, charSize, limit)
- if charSize == 2:
- self.putValue(data, 'utf16', length=length)
- else:
- self.putValue(data, 'ucs4', length=length)
+ (length, data) = self.encodeCArray(ptr, 2, limit)
+ self.putValue(data, 'utf16', length=length)
return True
if displayFormat == DisplayFormat.Latin1String:
@@ -931,19 +902,12 @@ class Dumper(DumperBase):
self.putItem(derefValue)
self.currentChildType = savedCurrentChildType
- def extractPointer(self, value):
- code = 'I' if self.ptrSize() == 4 else 'Q'
- return self.extractSomething(value, code, 8 * self.ptrSize())
-
def createValue(self, datish, typish):
- if self.isInt(datish): # Used as address.
+ if isinstance(datish, int): # Used as address.
return self.createValueFromAddressAndType(datish, typish)
if isinstance(datish, bytes):
val = self.Value(self)
- if isinstance(typish, self.Type):
- val._type = typish
- else:
- val._type = self.Type(self, typish)
+ val.typeid = self.create_typeid(typish)
#DumperBase.warn('CREATING %s WITH DATA %s' % (val.type.name, self.hexencode(datish)))
val.ldata = datish
val.check()
@@ -952,11 +916,8 @@ class Dumper(DumperBase):
def createValueFromAddressAndType(self, address, typish):
val = self.Value(self)
- if isinstance(typish, self.Type):
- val._type = typish
- else:
- val._type = self.Type(self, typish)
+ val.typeid = self.create_typeid(typish)
val.laddress = address
if self.useDynamicType:
- val._type = val.type.dynamicType(address)
+ val.typeid = self.dynamic_typeid_at_address(val.typeid, address)
return val
diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py
index 059bf7b23e..488f1e362e 100644
--- a/share/qtcreator/debugger/dumper.py
+++ b/share/qtcreator/debugger/dumper.py
@@ -3,7 +3,7 @@
import os
import codecs
-import collections
+import functools
import glob
import struct
import sys
@@ -31,11 +31,7 @@ except:
def hexencode_(s):
return ''.join(["%x" % c for c in s])
-if sys.version_info[0] >= 3:
- toInteger = int
-else:
- toInteger = long
-
+toInteger = int
class ReportItem():
"""
@@ -55,19 +51,6 @@ class ReportItem():
% (self.value, self.encoding, self.priority, self.length)
-class Timer():
- def __init__(self, d, desc):
- self.d = d
- self.desc = desc + '-' + d.currentIName
-
- def __enter__(self):
- self.starttime = time.time()
-
- def __exit__(self, exType, exValue, exTraceBack):
- elapsed = int(1000 * (time.time() - self.starttime))
- self.d.timings.append([self.desc, elapsed])
-
-
class Children():
def __init__(self, d, numChild=1, childType=None, childNumChild=None,
maxNumChild=None, addrBase=None, addrStep=None):
@@ -147,20 +130,28 @@ class UnnamedSubItem(SubItem):
class DumperBase():
@staticmethod
def warn(message):
- print('bridgemessage={msg="%s"},' % message.replace('"', '$').encode('latin1'))
+ print('bridgemessage={msg="%s"}' % message.replace('"', "'").replace('\\', '\\\\'))
- @staticmethod
- def showException(msg, exType, exValue, exTraceback):
- DumperBase.warn('**** CAUGHT EXCEPTION: %s ****' % msg)
+ #@staticmethod
+ def showException(self, msg, exType, exValue, exTraceback):
+ self.warn('**** CAUGHT EXCEPTION: %s ****' % msg)
try:
import traceback
- for line in traceback.format_exception(exType, exValue, exTraceback):
- DumperBase.warn('%s' % line)
+ for frame_desc in traceback.format_exception(exType, exValue, exTraceback):
+ for line in frame_desc.split('\n'):
+ self.warn(line)
except:
pass
- def timer(self, desc):
- return Timer(self, desc)
+ def dump_location(self):
+ import traceback
+ from io import StringIO
+ io = StringIO()
+ traceback.print_stack(file=io)
+ data = io.getvalue()
+ self.warn('LOCATION:')
+ for line in data.split('\n')[:-3]:
+ self.warn(line)
def __init__(self):
self.isCdb = False
@@ -185,7 +176,6 @@ class DumperBase():
self.passExceptions = False
self.isTesting = False
- self.typeData = {}
self.isBigEndian = False
self.packCode = '<'
@@ -197,6 +187,8 @@ class DumperBase():
self.dumpermodules = []
+ self.init_type_cache()
+
try:
# Fails in the piping case
self.dumpermodules = [
@@ -217,9 +209,10 @@ class DumperBase():
self.currentPrintsAddress = True
self.currentChildType = None
self.currentChildNumChild = None
- self.registerKnownTypes()
+ self.register_known_types()
def setVariableFetchingOptions(self, args):
+ self.last_args = args
self.resultVarName = args.get('resultvarname', '')
self.expandedINames = args.get('expanded', {})
self.stringCutOff = int(args.get('stringcutoff', 10000))
@@ -239,10 +232,25 @@ class DumperBase():
self.partialVariable = args.get('partialvar', '')
self.uninitialized = args.get('uninitialized', [])
self.uninitialized = list(map(lambda x: self.hexdecode(x), self.uninitialized))
- self.partialUpdate = int(args.get('partial', '0'))
- #DumperBase.warn('NAMESPACE: "%s"' % self.qtNamespace())
- #DumperBase.warn('EXPANDED INAMES: %s' % self.expandedINames)
- #DumperBase.warn('WATCHERS: %s' % self.watchers)
+ #self.warn('NAMESPACE: "%s"' % self.qtNamespace())
+ #self.warn('EXPANDED INAMES: %s' % self.expandedINames)
+ #self.warn('WATCHERS: %s' % self.watchers)
+
+ # Call this with 'py theDumper.profile1() from Creator
+ def profile(self):
+ '''Internal profiling'''
+ import cProfile
+ import visualize
+ profiler = cProfile.Profile()
+ profiler.enable()
+ self.profiled_command()
+ profiler.disable()
+ visualize.profile_visualize(profiler.getstats())
+
+ def profiled_command(self):
+ args = self.last_args
+ args['partialvar'] = ''
+ self.fetchVariables(args)
def setFallbackQtVersion(self, args):
version = int(args.get('version', self.fallbackQtVersion))
@@ -279,7 +287,6 @@ class DumperBase():
self.generalCache = {}
self.counts = {}
- self.structPatternCache = {}
self.timings = []
self.expandableINames = set({})
@@ -331,7 +338,7 @@ class DumperBase():
self.currentType = ReportItem()
def exitSubItem(self, item, exType, exValue, exTraceBack):
- #DumperBase.warn('CURRENT VALUE: %s: %s %s' %
+ #self.warn('CURRENT VALUE: %s: %s %s' %
# (self.currentIName, self.currentValue, self.currentType))
if exType is not None:
if self.passExceptions:
@@ -341,9 +348,9 @@ class DumperBase():
if not self.isCli:
try:
if self.currentType.value:
- typeName = self.currentType.value
- if len(typeName) > 0 and typeName != self.currentChildType:
- self.putField('type', typeName)
+ typename = self.currentType.value
+ if len(typename) > 0 and typename != self.currentChildType:
+ self.putField('type', typename)
if self.currentValue.value is None:
self.put('value="",encoding="notaccessible",numchild="0",')
else:
@@ -361,8 +368,8 @@ class DumperBase():
self.indent -= 1
try:
if self.currentType.value:
- typeName = self.currentType.value
- self.put('<%s> = {' % typeName)
+ typename = self.currentType.value
+ self.put('<%s> = {' % typename)
if self.currentValue.value is None:
self.put('<not accessible>')
@@ -388,14 +395,14 @@ class DumperBase():
self.currentType = item.savedType
return True
- def stripForFormat(self, typeName):
- if not isinstance(typeName, str):
- raise RuntimeError('Expected string in stripForFormat(), got %s' % type(typeName))
- if typeName in self.cachedFormats:
- return self.cachedFormats[typeName]
+ def stripForFormat(self, typename):
+ if not isinstance(typename, str):
+ raise RuntimeError('Expected string in stripForFormat(), got %s' % type(typename))
+ if typename in self.cachedFormats:
+ return self.cachedFormats[typename]
stripped = ''
inArray = 0
- for c in typeName:
+ for c in typename:
if c == '<':
break
if c == ' ':
@@ -407,59 +414,192 @@ class DumperBase():
if inArray and ord(c) >= 48 and ord(c) <= 57:
continue
stripped += c
- self.cachedFormats[typeName] = stripped
+ self.cachedFormats[typename] = stripped
return stripped
- def templateArgument(self, typeobj, position):
- return typeobj.templateArgument(position)
+ def templateArgument(self, typeobj, index):
+ return self.type_template_argument(typeobj.typeid, index)
def intType(self):
- result = self.lookupType('int')
- self.intType = lambda: result
- return result
+ return self.type_for_int
def charType(self):
- result = self.lookupType('char')
- self.charType = lambda: result
- return result
+ return self.type_for_char
def ptrSize(self):
result = self.lookupType('void*').size()
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 registerKnownTypes(self):
- tdata = self.TypeData(self, 'unsigned short')
- tdata.lbitsize = 16
- tdata.lalignment = 2
- tdata.code = TypeCode.Integral
+ def lookupType(self, typename):
+ if not isinstance(typename, str):
+ raise RuntimeError('ARG ERROR FOR lookupType, got %s' % type(typename))
+
+ typeid = self.typeid_for_string(typename)
+ native_type = self.type_nativetype_cache.get(typeid)
+ if native_type is None:
+ native_type = self.lookupNativeType(typename)
+ if native_type is None:
+ #sCANNOT DETERMINE SIZE FOR TYelf.dump_location()
+ self.dump_location()
+ self.warn("TYPEIDS: %s" % self.typeid_cache)
+ self.warn("COULD NOT FIND TYPE '%s'" % typename)
+ return None
- tdata = self.TypeData(self, 'QChar')
- tdata.lbitsize = 16
- tdata.lalignment = 2
- tdata.code = TypeCode.Struct
- tdata.lfields = [self.Field(dumper=self, name='ucs',
- type='unsigned short', bitsize=16, bitpos=0)]
- tdata.templateArguments = lambda: []
+ self.type_nativetype_cache[typeid] = native_type
+ typeid = self.from_native_type(native_type)
+ if typeid == 0:
+ return None
+ return self.Type(self, typeid)
+
+ def register_type(self, name, code, size, enc=None):
+ typeid = self.typeid_for_string(name)
+ self.type_code_cache[typeid] = code
+ self.type_size_cache[typeid] = size
+ self.type_alignment_cache[typeid] = size
+ if enc is not None:
+ self.type_encoding_cache[typeid] = enc
+ return typeid
+
+ def register_int(self, name, size, enc=None):
+ typeid = self.typeid_for_string(name)
+ self.type_code_cache[typeid] = TypeCode.Integral
+ self.type_size_cache[typeid] = size
+ self.type_alignment_cache[typeid] = size
+ if enc is not None:
+ self.type_encoding_cache[typeid] = enc
+ return typeid
+
+ def register_enum(self, name, size):
+ typeid = self.typeid_for_string(name)
+ self.type_code_cache[typeid] = TypeCode.Enum
+ self.type_size_cache[typeid] = size
+ self.type_alignment_cache[typeid] = size
+ return typeid
+
+ def register_typedef(self, name, target_typeid):
+ typeid = self.typeid_for_string(name)
+ self.type_code_cache[typeid] = TypeCode.Typedef
+ self.type_target_cache[typeid] = target_typeid
+ self.type_size_cache[typeid] = self.type_size_cache[target_typeid]
+ self.type_alignment_cache[typeid] = self.type_alignment_cache[target_typeid]
+ return typeid
+
+ def register_struct(self, name, p5=0, p6=0, s=0):
+ # p5 = n -> n * ptrsize for Qt 5
+ # p6 = n -> n * ptrsize for Qt 6
+ #if self.qtVersion() >= 0x060000: # FIXME: Qt 5, ptrSize()
+ size = 8 * p6 + s
+ typeid = self.typeid_for_string(name)
+ self.type_code_cache[typeid] = TypeCode.Struct
+ self.type_size_cache[typeid] = size
+ self.type_alignment_cache[typeid] = 8
+ return typeid
+
+ def register_known_types(self):
+ typeid = 0
+ self.typeid_cache[''] = typeid
+ self.type_code_cache[typeid] = TypeCode.Void
+ self.type_name_cache[typeid] = '<Error>'
+ self.type_size_cache[typeid] = 1
+
+ typeid_char = self.register_int('char', 1, 'uint:1')
+ self.type_for_char = self.Type(self, typeid_char)
+ self.register_int('signed char', 1, 'int:1')
+ self.register_int('unsigned char', 1, 'uint:1')
+ self.register_int('bool', 1, 'uint:1')
+ self.register_int('char8_t', 1, 'uint:1')
+ self.register_int('int8_t', 1, 'int:1')
+ self.register_int('uint8_t', 1, 'uint:1')
+ self.register_int('qint8', 1, 'int:1')
+ self.register_int('quint8', 1, 'uint:1')
+
+ self.register_int('short', 2, 'int:2')
+ self.register_int('short int', 2, 'int:2')
+ self.register_int('signed short', 2, 'int:2')
+ self.register_int('signed short int', 2, 'int:2')
+ typeid_unsigned_short = \
+ self.register_int('unsigned short', 2, 'uint:2')
+ self.register_int('unsigned short int', 2, 'uint:2')
+ self.register_int('char16_t', 2, 'uint:2')
+ self.register_int('int16_t', 2, 'int:2')
+ self.register_int('uint16_t', 2, 'uint:2')
+ self.register_int('qint16', 2, 'int:2')
+ self.register_int('quint16', 2, 'uint:2')
+
+ typeid_int = self.register_type('int', 4, 'int:4')
+ self.type_for_int = self.Type(self, typeid_int)
+ self.register_int('int', 4, 'int:4')
+ self.register_int('signed int', 4, 'int:4')
+ self.register_int('unsigned int', 4, 'uint:4')
+ self.register_int('char32_t', 4, 'int:4')
+ self.register_int('int32_t', 4, 'int:4')
+ self.register_int('uint32_t', 4, 'uint:4')
+ self.register_int('qint32', 4, 'int:4')
+ self.register_int('quint32', 4, 'uint:4')
+
+ self.register_int('long long', 8, 'int:8')
+ self.register_int('signed long long', 8, 'int:8')
+ self.register_int('unsigned long long', 8, 'uint:8')
+ self.register_int('int64_t', 8, 'int:8')
+ self.register_int('uint64_t', 8, 'uint:8')
+ self.register_int('qint64', 8, 'int:8')
+ self.register_int('quint64', 8, 'uint:8')
+
+ self.register_type('float', TypeCode.Float, 4, 'float:4')
+ typeid_double = self.register_type('double', TypeCode.Float, 8, 'float:8')
+ self.register_typedef('qreal', typeid_double)
+
+ typeid_qchar = self.register_type('@QChar', TypeCode.Struct, 2, 'uint:2')
+ #self.type_fields_cache[typeid_qchar] = [
+ # self.Field(name='ucs', typeid=typeid_unsigned_short, bitsize=16, bitpos=0)]
+
+ self.register_enum('@Qt::ItemDataRole', 4)
+
+ self.register_struct('@QObject', p5=2, p6=2)
+ self.register_struct('@QObjectPrivate', p5=10, p6=10) # FIXME: Not exact
+
+ self.register_struct('@QByteArray', p5=1, p6=3)
+ self.register_struct('@QString', p5=1, p6=3)
+ self.register_struct('@QStandardItemData', p5=3, p6=5)
+ self.register_struct('@QVariant', p5=2, p6=4)
+ self.register_struct('@QXmlAttributes::Attribute', p5=4, p6=12)
+
+ self.register_struct('@QList<@QObject*>', p5=1, p6=3)
+ self.register_struct('@QList<@QStandardItemData>', p5=1, p6=3)
+ self.register_struct('@QList<@QRect>', p5=1, p6=3)
+
+ typeid_var_list = self.register_struct('@QList<@QVariant>', p5=1, p6=3)
+ self.register_typedef('@QVariantList', typeid_var_list)
+
+ typeid_var_map = self.register_struct('@QMap<@QString, @QVariant>', p5=1, p6=1)
+ self.register_typedef('@QVariantMap', typeid_var_map)
+
+ typeid_var_hash = self.register_struct('@QHash<@QString, @QVariant>', p5=1, p6=1)
+ self.register_typedef('@QVariantHash', typeid_var_hash)
+
+ self.register_struct('@QPoint', s=8)
+ self.register_struct('@QPointF', s=16)
+ self.register_struct('@QLine', s=16)
+ self.register_struct('@QLineF', s=32)
+
+ # FIXME: Comment out for production, see [MARK_A]
+ name1 = 'std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>'
+ self.register_struct(name1, p6=4)
def nativeDynamicType(self, address, baseType):
return baseType # Override in backends.
- def listTemplateParameters(self, typename):
- return self.listTemplateParametersManually(typename)
-
- def listTemplateParametersManually(self, typename):
+ def fill_template_parameters_manually(self, typeid):
+ typename = self.type_name(typeid)
# Undo id mangling for template typedefs. Relevant for QPair.
if typename.endswith('}'):
typename = typename[typename.find('{') + 1 : -1]
- targs = []
if not typename.endswith('>'):
- return targs
+ return
+
+ targs = []
def push(inner):
# Handle local struct definitions like QList<main(int, char**)::SomeStruct>
@@ -471,14 +611,14 @@ class DumperBase():
inner = inner[6:].strip()
if inner.endswith(' const'):
inner = inner[:-6].strip()
- #DumperBase.warn("FOUND: %s" % inner)
+ #self.warn("FOUND: %s" % inner)
targs.append(inner)
- #DumperBase.warn("SPLITTING %s" % typename)
+ #self.warn("SPLITTING %s" % typename)
level = 0
inner = ''
for c in typename[::-1]: # Reversed...
- #DumperBase.warn("C: %s" % c)
+ #self.warn("C: %s" % c)
if c == '>':
if level > 0:
inner += c
@@ -492,7 +632,7 @@ class DumperBase():
inner = ''
break
elif c == ',':
- #DumperBase.warn('c: %s level: %s' % (c, level))
+ #self.warn('c: %s level: %s' % (c, level))
if level == 1:
push(inner)
inner = ''
@@ -501,28 +641,34 @@ class DumperBase():
else:
inner += c
- #DumperBase.warn("TARGS: %s %s" % (typename, targs))
- res = []
+ #self.warn("TARGS: %s %s" % (typename, targs))
+ idx = 0
for item in targs[::-1]:
if len(item) == 0:
continue
- c = ord(item[0])
- if c in (45, 46) or (c >= 48 and c < 58): # '-', '.' or digit.
- if item.find('.') > -1:
- res.append(float(item))
- else:
- if item.endswith('l'):
- item = item[:-1]
- if item.endswith('u'):
- item = item[:-1]
- val = toInteger(item)
- if val > 0x80000000:
- val -= 0x100000000
- res.append(val)
+ if item == "false": # Triggered in StdTuple dumper
+ self.type_template_arguments_cache[(typeid, idx)] = False
+ elif item == "true":
+ self.type_template_arguments_cache[(typeid, idx)] = True
else:
- res.append(self.Type(self, item))
- #DumperBase.warn("RES: %s %s" % (typename, [(None if t is None else t.name) for t in res]))
- return res
+ c = ord(item[0])
+ if c in (45, 46) or (c >= 48 and c < 58): # '-', '.' or digit.
+ if '.' in item:
+ res.append(float(item))
+ else:
+ if item.endswith('l'):
+ item = item[:-1]
+ if item.endswith('u'):
+ item = item[:-1]
+ val = int(item)
+ if val > 0x80000000:
+ val -= 0x100000000
+ self.type_template_arguments_cache[(typeid, idx)] = val
+ else:
+ targ = self.Type(self, self.create_typeid_from_name(item))
+ self.type_template_arguments_cache[(typeid, idx)] = targ
+ idx += 1
+ #self.warn('MANUAL: %s %s' % (type_name, targs))
# Hex decoding operating on str, return str.
@staticmethod
@@ -619,7 +765,7 @@ class DumperBase():
(dummy, dummy, dummy, length) = self.split('IIIp', array_data_ptr)
length = self.extractInt(array_data_ptr + 3 * self.ptrSize()) & 0x3ffffff
alloc = length # pretend.
- data = self.extractPointer(array_data_ptr + self.ptrSize())
+ data = self.extract_pointer_at_address(array_data_ptr + self.ptrSize())
return data, length, alloc
def encodeStringHelper(self, value, limit):
@@ -666,14 +812,14 @@ class DumperBase():
displayFormat=DisplayFormat.Automatic,
makeExpandable=True):
charSize = charType.size()
- self.putCharArrayValue(data, size, charSize, displayFormat=displayFormat)
+ self.putCharArrayValue(data, size, charSize, displayFormat)
if makeExpandable:
self.putNumChild(size)
if self.isExpanded():
with Children(self):
for i in range(size):
- self.putSubItem(size, self.createValue(data + i * charSize, charType))
+ self.putSubItem(size, self.createValueFromAddress(data + i * charSize, charType))
def readMemory(self, addr, size):
return self.hexencode(bytes(self.readRawMemory(addr, size)))
@@ -699,39 +845,6 @@ class DumperBase():
def stringData(self, value): # -> (data, size, alloc)
return self.qArrayData(value)
- def extractTemplateArgument(self, typename, position):
- level = 0
- skipSpace = False
- inner = ''
- for c in typename[typename.find('<') + 1: -1]:
- if c == '<':
- inner += c
- level += 1
- elif c == '>':
- level -= 1
- inner += c
- elif c == ',':
- if level == 0:
- if position == 0:
- return inner.strip()
- position -= 1
- inner = ''
- else:
- inner += c
- skipSpace = True
- else:
- if skipSpace and c == ' ':
- pass
- else:
- inner += c
- skipSpace = False
- # Handle local struct definitions like QList<main(int, char**)::SomeStruct>
- inner = inner.strip()
- p = inner.find(')::')
- if p > -1:
- inner = inner[p + 3:]
- return inner
-
def putStringValue(self, value):
length, data = self.encodeStringHelper(value, self.displayStringLimit)
self.putValue(data, 'utf16', length=length)
@@ -750,10 +863,9 @@ class DumperBase():
self.putType('int')
def putEnumItem(self, name, ival, typish):
- buf = bytearray(struct.pack('i', ival))
val = self.Value(self)
- val.ldata = bytes(buf)
- val._type = self.createType(typish)
+ val.ldata = ival
+ val.typeid = self.create_typeid(typish)
with SubItem(self, name):
self.putItem(val)
@@ -826,15 +938,19 @@ class DumperBase():
def putSymbolValue(self, address):
self.putValue(self.prettySymbolByAddress(address))
- def putVTableChildren(self, item, itemCount):
- p = item.pointer()
+ def putVTableChildren(self, value, itemCount):
+ p = self.value_as_address(value)
+ entry_typeid = self.create_pointer_typeid(self.create_typeid('void'))
for i in range(itemCount):
- deref = self.extractPointer(p)
+ deref = self.extract_pointer_at_address(p)
if deref == 0:
itemCount = i
break
with SubItem(self, i):
- self.putItem(self.createPointerValue(deref, 'void'))
+ val = self.Value(self)
+ val.ldata = deref
+ val.typeid = entry_typeid
+ self.putItem(val)
p += self.ptrSize()
return itemCount
@@ -842,7 +958,9 @@ class DumperBase():
baseIndex = 0
for item in value.members(True):
if item.name is not None:
- if item.name.startswith('_vptr.') or item.name.startswith('__vfptr'):
+ if (item.name.startswith('_vptr.')
+ or item.name.startswith('_vptr$')
+ or item.name.startswith('__vfptr')):
with SubItem(self, '[vptr]'):
# int (**)(void)
self.putType(' ')
@@ -892,15 +1010,22 @@ class DumperBase():
def check(self, exp):
if not exp:
+ self.warn('Check failed: %s' % exp)
+ self.dump_location()
raise RuntimeError('Check failed: %s' % exp)
+ def check_typeid(self, typeid):
+ if not isinstance(typeid, int):
+ size = self.type_size_cache.get(typeid, None)
+ raise RuntimeError('WRONG TYPE FOR TYPEID: %s %s' % (str(typeid), type(typeid)))
+
def checkRef(self, ref):
# Assume there aren't a million references to any object.
self.check(ref >= -1)
self.check(ref < 1000000)
def checkIntType(self, thing):
- if not self.isInt(thing):
+ if not isinstance(thing, int):
raise RuntimeError('Expected an integral value, got %s' % type(thing))
def readToFirstZero(self, base, typesize, maximum):
@@ -919,7 +1044,7 @@ class DumperBase():
maximum = int(maximum / 2)
self.warn('REDUCING READING MAXIMUM TO %s' % maximum)
- #DumperBase.warn('BASE: 0x%x TSIZE: %s MAX: %s' % (base, typesize, maximum))
+ #self.warn('BASE: 0x%x TSIZE: %s MAX: %s' % (base, typesize, maximum))
for i in range(0, maximum, typesize):
t = struct.unpack_from(code, blob, i)[0]
if t == 0:
@@ -1039,11 +1164,14 @@ class DumperBase():
def putType(self, typish, priority=0):
# Higher priority values override lower ones.
if priority >= self.currentType.priority:
- types = (str) if sys.version_info[0] >= 3 else (str, unicode)
- if isinstance(typish, types):
+ if isinstance(typish, str):
self.currentType.value = typish
- else:
+ elif isinstance(typish, int):
+ self.currentType.value = self.type_name(typish)
+ elif isinstance(typish, self.Type):
self.currentType.value = typish.name
+ else:
+ self.currentType.value = str(type(typish))
self.currentType.priority = priority
def putValue(self, value, encoding=None, priority=0, length=None):
@@ -1095,23 +1223,26 @@ class DumperBase():
self.putItem(value)
def isExpanded(self):
- #DumperBase.warn('IS EXPANDED: %s in %s: %s' % (self.currentIName,
+ #self.warn('IS EXPANDED: %s in %s: %s' % (self.currentIName,
# self.expandedINames, self.currentIName in self.expandedINames))
return self.currentIName in self.expandedINames
- def mangleName(self, typeName):
+ def mangleName(self, typename):
return '_ZN%sE' % ''.join(map(lambda x: '%d%s' % (len(x), x),
- typeName.split('::')))
+ typename.split('::')))
- def arrayItemCountFromTypeName(self, typeName, fallbackMax=1):
- itemCount = typeName[typeName.find('[') + 1:typeName.find(']')]
+ def arrayItemCountFromTypeName(self, typename, fallbackMax=1):
+ itemCount = typename[typename.find('[') + 1:typename.find(']')]
return int(itemCount) if itemCount else fallbackMax
def putCStyleArray(self, value):
- arrayType = value.type.unqualified()
- innerType = arrayType.ltarget
+ arrayType = value.type
+ innerType = arrayType.target()
+ #self.warn("ARRAY TYPE: %s" % arrayType)
+ #self.warn("INNER TYPE: %s" % innerType)
if innerType is None:
- innerType = value.type.target().unqualified()
+ innerType = value.type.target()
+
address = value.address()
if address:
self.putValue('@0x%x' % address, priority=-1)
@@ -1161,19 +1292,19 @@ class DumperBase():
def cleanAddress(self, addr):
if addr is None:
return '<no address>'
- return '0x%x' % toInteger(hex(addr), 16)
+ return '0x%x' % int(hex(addr), 16)
- def stripNamespaceFromType(self, typeName):
+ def stripNamespaceFromType(self, typename):
ns = self.qtNamespace()
- if len(ns) > 0 and typeName.startswith(ns):
- typeName = typeName[len(ns):]
- # DumperBase.warn( 'stripping %s' % typeName )
+ if len(ns) > 0 and typename.startswith(ns):
+ typename = typename[len(ns):]
+ # self.warn( 'stripping %s' % typename )
lvl = 0
pos = None
stripChunks = []
- sz = len(typeName)
+ sz = len(typename)
for index in range(0, sz):
- s = typeName[index]
+ s = typename[index]
if s == '<':
lvl += 1
if lvl == 1:
@@ -1188,22 +1319,22 @@ class DumperBase():
if lvl != 0:
raise RuntimeError("unbalanced at end of type name")
for (f, l) in reversed(stripChunks):
- typeName = typeName[:f] + typeName[l:]
- return typeName
+ typename = typename[:f] + typename[l:]
+ return typename
- def tryPutPrettyItem(self, typeName, value):
+ def tryPutPrettyItem(self, typename, value):
value.check()
if self.useFancy and self.currentItemFormat() != DisplayFormat.Raw:
- self.putType(typeName)
+ self.putType(typename)
- nsStrippedType = self.stripNamespaceFromType(typeName)\
+ nsStrippedType = self.stripNamespaceFromType(typename)\
.replace('::', '__')
# Strip leading 'struct' for C structs
if nsStrippedType.startswith('struct '):
nsStrippedType = nsStrippedType[7:]
- #DumperBase.warn('STRIPPED: %s' % nsStrippedType)
+ #self.warn('STRIPPED: %s' % nsStrippedType)
# The following block is only needed for D.
if nsStrippedType.startswith('_A'):
# DMD v2.058 encodes string[] as _Array_uns long long.
@@ -1216,7 +1347,7 @@ class DumperBase():
return True
dumper = self.qqDumpers.get(nsStrippedType)
- #DumperBase.warn('DUMPER: %s' % dumper)
+ #self.warn('DUMPER: %s' % dumper)
if dumper is not None:
dumper(self, value)
return True
@@ -1242,15 +1373,15 @@ class DumperBase():
self.putField('editvalue', value)
# This is shared by pointer and array formatting.
- def tryPutSimpleFormattedPointer(self, ptr, typeName, innerType, displayFormat, limit):
+ def tryPutSimpleFormattedPointer(self, ptr, typename, innerType, displayFormat, limit):
if displayFormat == DisplayFormat.Automatic:
targetType = innerType
if innerType.code == TypeCode.Typedef:
- targetType = innerType.ltarget
+ targetType = innerType.target()
if targetType.name in ('char', 'signed char', 'unsigned char', 'uint8_t', 'CHAR'):
# Use UTF-8 as default for char *.
- self.putType(typeName)
+ self.putType(typename)
(length, shown, data) = self.readToFirstZero(ptr, 1, limit)
self.putValue(data, 'utf8', length=length)
if self.isExpanded():
@@ -1258,7 +1389,7 @@ class DumperBase():
return True
if targetType.name in ('wchar_t', 'WCHAR'):
- self.putType(typeName)
+ self.putType(typename)
charSize = self.lookupType('wchar_t').size()
(length, data) = self.encodeCArray(ptr, charSize, limit)
if charSize == 2:
@@ -1268,58 +1399,54 @@ class DumperBase():
return True
if displayFormat == DisplayFormat.Latin1String:
- self.putType(typeName)
+ self.putType(typename)
(length, data) = self.encodeCArray(ptr, 1, limit)
self.putValue(data, 'latin1', length=length)
return True
if displayFormat == DisplayFormat.SeparateLatin1String:
- self.putType(typeName)
+ self.putType(typename)
(length, data) = self.encodeCArray(ptr, 1, limit)
self.putValue(data, 'latin1', length=length)
self.putDisplay('latin1:separate', data)
return True
if displayFormat == DisplayFormat.Utf8String:
- self.putType(typeName)
+ self.putType(typename)
(length, data) = self.encodeCArray(ptr, 1, limit)
self.putValue(data, 'utf8', length=length)
return True
if displayFormat == DisplayFormat.SeparateUtf8String:
- self.putType(typeName)
+ self.putType(typename)
(length, data) = self.encodeCArray(ptr, 1, limit)
self.putValue(data, 'utf8', length=length)
self.putDisplay('utf8:separate', data)
return True
if displayFormat == DisplayFormat.Local8BitString:
- self.putType(typeName)
+ self.putType(typename)
(length, data) = self.encodeCArray(ptr, 1, limit)
self.putValue(data, 'local8bit', length=length)
return True
if displayFormat == DisplayFormat.Utf16String:
- self.putType(typeName)
+ self.putType(typename)
(length, data) = self.encodeCArray(ptr, 2, limit)
self.putValue(data, 'utf16', length=length)
return True
if displayFormat == DisplayFormat.Ucs4String:
- self.putType(typeName)
+ self.putType(typename)
(length, data) = self.encodeCArray(ptr, 4, limit)
self.putValue(data, 'ucs4', length=length)
return True
return False
- def putFormattedPointer(self, value):
- #with self.timer('formattedPointer'):
- self.putFormattedPointerX(value)
-
def putDerefedPointer(self, value):
- derefValue = value.dereference()
- innerType = value.type.target() # .unqualified()
+ derefValue = self.value_dereference(value)
+ innerType = value.type.target()
self.putType(innerType)
savedCurrentChildType = self.currentChildType
self.currentChildType = innerType.name
@@ -1332,47 +1459,47 @@ class DumperBase():
self.putItem(derefValue)
self.currentChildType = savedCurrentChildType
- def putFormattedPointerX(self, value):
+ def putFormattedPointer(self, value):
self.putOriginalAddress(value.address())
- #DumperBase.warn("PUT FORMATTED: %s" % value)
- pointer = value.pointer()
+ #self.warn("PUT FORMATTED: %s" % value)
+ pointer = self.value_as_address(value)
self.putAddress(pointer)
- #DumperBase.warn('POINTER: 0x%x' % pointer)
+ #self.warn('POINTER: 0x%x' % pointer)
if pointer == 0:
- #DumperBase.warn('NULL POINTER')
- self.putType(value.type)
+ #self.warn('NULL POINTER')
+ self.putType(value.typeid)
self.putValue('0x0')
return
- typeName = value.type.name
+ typename = self.type_name(value.typeid)
try:
self.readRawMemory(pointer, 1)
except:
# Failure to dereference a pointer should at least
# show the value of a pointer.
- #DumperBase.warn('BAD POINTER: %s' % value)
+ #self.warn('BAD POINTER: %s' % value)
self.putValue('0x%x' % pointer)
- self.putType(typeName)
+ self.putType(typename)
return
if self.currentIName.endswith('.this'):
self.putDerefedPointer(value)
return
- displayFormat = self.currentItemFormat(value.type.name)
- innerType = value.type.target() # .unqualified()
+ displayFormat = self.currentItemFormat(typename)
+ innerType = value.type.target()
if innerType.name == 'void':
- #DumperBase.warn('VOID POINTER: %s' % displayFormat)
- self.putType(typeName)
+ #self.warn('VOID POINTER: %s' % displayFormat)
+ self.putType(typename)
self.putSymbolValue(pointer)
return
if displayFormat == DisplayFormat.Raw:
# Explicitly requested bald pointer.
- #DumperBase.warn('RAW')
- self.putType(typeName)
+ #self.warn('RAW')
+ self.putType(typename)
self.putValue('0x%x' % pointer)
self.putExpandable()
if self.currentIName in self.expandedINames:
@@ -1384,27 +1511,27 @@ class DumperBase():
limit = self.displayStringLimit
if displayFormat in (DisplayFormat.SeparateLatin1String, DisplayFormat.SeparateUtf8String):
limit = 1000000
- if self.tryPutSimpleFormattedPointer(pointer, typeName,
+ if self.tryPutSimpleFormattedPointer(pointer, typename,
innerType, displayFormat, limit):
self.putExpandable()
return
if DisplayFormat.Array10 <= displayFormat and displayFormat <= DisplayFormat.Array10000:
n = (10, 100, 1000, 10000)[displayFormat - DisplayFormat.Array10]
- self.putType(typeName)
+ self.putType(typename)
self.putItemCount(n)
- self.putArrayData(value.pointer(), n, innerType)
+ self.putArrayData(self.value_as_address(value), n, innerType)
return
if innerType.code == TypeCode.Function:
# A function pointer.
self.putSymbolValue(pointer)
- self.putType(typeName)
+ self.putType(typename)
return
- #DumperBase.warn('AUTODEREF: %s' % self.autoDerefPointers)
- #DumperBase.warn('INAME: %s' % self.currentIName)
- #DumperBase.warn('INNER: %s' % innerType.name)
+ #self.warn('AUTODEREF: %s' % self.autoDerefPointers)
+ #self.warn('INAME: %s' % self.currentIName)
+ #self.warn('INNER: %s' % innerType.name)
if self.autoDerefPointers:
# Generic pointer type with AutomaticFormat, but never dereference char types:
if innerType.name not in (
@@ -1425,9 +1552,9 @@ class DumperBase():
self.putDerefedPointer(value)
return
- #DumperBase.warn('GENERIC PLAIN POINTER: %s' % value.type)
- #DumperBase.warn('ADDR PLAIN POINTER: 0x%x' % value.laddress)
- self.putType(typeName)
+ #self.warn('GENERIC PLAIN POINTER: %s' % value.type)
+ #self.warn('ADDR PLAIN POINTER: 0x%x' % value.laddress)
+ self.putType(typename)
self.putSymbolValue(pointer)
self.putExpandable()
if self.currentIName in self.expandedINames:
@@ -1458,7 +1585,7 @@ class DumperBase():
# - int postedEvents;
# - QDynamicMetaObjectData *metaObject;
# - QBindingStorage bindingStorage;
- extra = self.extractPointer(dd + 9 * ptrSize + 2 * intSize)
+ extra = self.extract_pointer_at_address(dd + 9 * ptrSize + 2 * intSize)
if extra == 0:
return False
@@ -1478,7 +1605,7 @@ class DumperBase():
# - uint isWidget : 1; etc...
# - int postedEvents;
# - QDynamicMetaObjectData *metaObject;
- extra = self.extractPointer(dd + 5 * ptrSize + 2 * intSize)
+ extra = self.extract_pointer_at_address(dd + 5 * ptrSize + 2 * intSize)
if extra == 0:
return False
@@ -1582,7 +1709,7 @@ class DumperBase():
try:
customEventOffset = 8 if self.isMsvcTarget() else 9
- customEventFunc = self.extractPointer(vtablePtr + customEventOffset * self.ptrSize())
+ customEventFunc = self.extract_pointer_at_address(vtablePtr + customEventOffset * self.ptrSize())
except:
self.bump('nostruct-3')
return False
@@ -1594,7 +1721,7 @@ class DumperBase():
customEventFunc = getJumpAddress_x86(self, customEventFunc)
if customEventFunc in (self.qtCustomEventFunc, self.qtCustomEventPltFunc):
return True
- customEventFunc = self.extractPointer(customEventFunc)
+ customEventFunc = self.extract_pointer_at_address(customEventFunc)
if customEventFunc in (self.qtCustomEventFunc, self.qtCustomEventPltFunc):
return True
# If the object is defined in another module there may be another level of indirection
@@ -1603,18 +1730,18 @@ class DumperBase():
return customEventFunc in (self.qtCustomEventFunc, self.qtCustomEventPltFunc)
# def extractQObjectProperty(objectPtr):
-# vtablePtr = self.extractPointer(objectPtr)
-# metaObjectFunc = self.extractPointer(vtablePtr)
+# vtablePtr = self.extract_pointer_at_address(objectPtr)
+# metaObjectFunc = self.extract_pointer_at_address(vtablePtr)
# cmd = '((void*(*)(void*))0x%x)((void*)0x%x)' % (metaObjectFunc, objectPtr)
# try:
-# #DumperBase.warn('MO CMD: %s' % cmd)
+# #self.warn('MO CMD: %s' % cmd)
# res = self.parseAndEvaluate(cmd)
-# #DumperBase.warn('MO RES: %s' % res)
+# #self.warn('MO RES: %s' % res)
# self.bump('successfulMetaObjectCall')
-# return res.pointer()
+# return self.value_as_address(res)
# except:
# self.bump('failedMetaObjectCall')
-# #DumperBase.warn('COULD NOT EXECUTE: %s' % cmd)
+# #self.warn('COULD NOT EXECUTE: %s' % cmd)
# return 0
def extractMetaObjectPtr(self, objectPtr, typeobj):
@@ -1631,29 +1758,29 @@ class DumperBase():
# contents 'vanishes' as the reported size of the string
# gets zeroed out(?).
# Try vtable, metaObject() is the first entry.
- vtablePtr = self.extractPointer(objectPtr)
- metaObjectFunc = self.extractPointer(vtablePtr)
+ vtablePtr = self.extract_pointer_at_address(objectPtr)
+ metaObjectFunc = self.extract_pointer_at_address(vtablePtr)
cmd = '((void*(*)(void*))0x%x)((void*)0x%x)' % (metaObjectFunc, objectPtr)
try:
- #DumperBase.warn('MO CMD: %s' % cmd)
+ #self.warn('MO CMD: %s' % cmd)
res = self.parseAndEvaluate(cmd)
- #DumperBase.warn('MO RES: %s' % res)
+ #self.warn('MO RES: %s' % res)
self.bump('successfulMetaObjectCall')
- return res.pointer()
+ return self.value_as_address(res)
except:
self.bump('failedMetaObjectCall')
- #DumperBase.warn('COULD NOT EXECUTE: %s' % cmd)
+ #self.warn('COULD NOT EXECUTE: %s' % cmd)
return 0
def extractStaticMetaObjectFromTypeHelper(someTypeObj):
if someTypeObj.isSimpleType():
return 0
- typeName = someTypeObj.name
- isQObjectProper = typeName == self.qtNamespace() + 'QObject'
+ typename = someTypeObj.name
+ isQObjectProper = typename == self.qtNamespace() + 'QObject'
# No templates for now.
- if typeName.find('<') >= 0:
+ if typename.find('<') >= 0:
return 0
result = self.findStaticMetaObject(someTypeObj)
@@ -1706,16 +1833,16 @@ class DumperBase():
ptrSize = self.ptrSize()
- typeName = typeobj.name
- result = self.knownStaticMetaObjects.get(typeName, None)
+ typename = typeobj.name
+ result = self.knownStaticMetaObjects.get(typename, None)
if result is not None: # Is 0 or the static metaobject.
self.bump('typecached')
- #DumperBase.warn('CACHED RESULT: %s %s 0x%x' % (self.currentIName, typeName, result))
+ #self.warn('CACHED RESULT: %s %s 0x%x' % (self.currentIName, typename, result))
return result
if not self.couldBeQObjectPointer(objectPtr):
self.bump('cannotBeQObject')
- #DumperBase.warn('DOES NOT LOOK LIKE A QOBJECT: %s' % self.currentIName)
+ #self.warn('DOES NOT LOOK LIKE A QOBJECT: %s' % self.currentIName)
return 0
metaObjectPtr = 0
@@ -1731,26 +1858,17 @@ class DumperBase():
#if metaObjectPtr:
# self.bump('foundMetaObject')
- # self.knownStaticMetaObjects[typeName] = metaObjectPtr
+ # self.8;
return metaObjectPtr
- def split(self, pattern, value):
- if isinstance(value, self.Value):
- return value.split(pattern)
- if self.isInt(value):
- val = self.Value(self)
- val.laddress = value
- return val.split(pattern)
- raise RuntimeError('CANNOT EXTRACT STRUCT FROM %s' % type(value))
-
def extractCString(self, addr):
result = bytearray()
while True:
- d = self.extractByte(addr)
- if d == 0:
+ d = bytes(self.readRawMemory(addr, 1))
+ if d[0] == 0:
break
- result.append(d)
+ result += d
addr += 1
return result
@@ -1775,21 +1893,21 @@ class DumperBase():
data = array + begin * stepSize
return data, size
- def putTypedPointer(self, name, addr, typeName):
+ def putTypedPointer(self, name, addr, typename):
""" Prints a typed pointer, expandable if the type can be resolved,
and without children otherwise """
with SubItem(self, name):
self.putAddress(addr)
self.putValue('@0x%x' % addr)
- typeObj = self.lookupType(typeName)
+ typeObj = self.lookupType(typename)
if typeObj:
self.putType(typeObj)
self.putExpandable()
if self.isExpanded():
with Children(self):
- self.putFields(self.createValue(addr, typeObj))
+ self.putFields(self.createValueFromAddress(addr, typeObj))
else:
- self.putType(typeName)
+ self.putType(typename)
# This is called is when a QObject derived class is expanded
def tryPutQObjectGuts(self, value):
@@ -1803,24 +1921,24 @@ class DumperBase():
stringdataOffset = ptrSize
if self.isWindowsTarget() and self.qtVersion() >= 0x060000:
stringdataOffset += ptrSize # indirect super data member
- stringdata = self.extractPointer(toInteger(metaObjectPtr) + stringdataOffset)
+ stringdata = self.extract_pointer_at_address(int(metaObjectPtr) + stringdataOffset)
- def unpackString(base, size):
+ def unpack_string(base, size):
try:
s = struct.unpack_from('%ds' % size, self.readRawMemory(base, size))[0]
- return s if sys.version_info[0] == 2 else s.decode('utf8')
+ return s.decode('utf8')
except:
return '<not available>'
if revision >= 9: # Qt 6.
pos, size = self.split('II', stringdata + 8 * index)
- return unpackString(stringdata + pos, size)
+ return unpack_string(stringdata + pos, size)
if revision >= 7: # Qt 5.
byteArrayDataSize = 24 if ptrSize == 8 else 16
- literal = stringdata + toInteger(index) * byteArrayDataSize
+ literal = stringdata + int(index) * byteArrayDataSize
base, size, _ = self.qArrayDataHelper(literal)
- return unpackString(base, size)
+ return unpack_string(base, size)
ldata = stringdata + index
return self.extractCString(ldata).decode('utf8')
@@ -1844,11 +1962,11 @@ class DumperBase():
index = name
elif self.qtVersion() >= 0x050000:
revision = 7
- dataPtr = self.extractPointer(metaObjectPtr + 2 * self.ptrSize())
+ dataPtr = self.extract_pointer_at_address(metaObjectPtr + 2 * self.ptrSize())
index = self.extractInt(dataPtr + 4 * handle)
else:
revision = 6
- dataPtr = self.extractPointer(metaObjectPtr + 2 * self.ptrSize())
+ dataPtr = self.extract_pointer_at_address(metaObjectPtr + 2 * self.ptrSize())
index = self.extractInt(dataPtr + 4 * handle)
#self.putValue("index: %s rev: %s" % (index, revision))
name = self.metaString(metaObjectPtr, index, revision)
@@ -1873,14 +1991,14 @@ class DumperBase():
def putQObjectGutsHelper(self, qobject, qobjectPtr, handle, metaObjectPtr, origType):
ptrSize = self.ptrSize()
- def putt(name, value, typeName=' '):
+ def putt(name, value, typename=' '):
with SubItem(self, name):
self.putValue(value)
- self.putType(typeName)
+ self.putType(typename)
def extractSuperDataPtr(someMetaObjectPtr):
#return someMetaObjectPtr['d']['superdata']
- return self.extractPointer(someMetaObjectPtr)
+ return self.extract_pointer_at_address(someMetaObjectPtr)
def extractDataPtr(someMetaObjectPtr):
# dataPtr = metaObjectPtr['d']['data']
@@ -1888,14 +2006,14 @@ class DumperBase():
offset = 3
else:
offset = 2
- return self.extractPointer(someMetaObjectPtr + offset * ptrSize)
+ return self.extract_pointer_at_address(someMetaObjectPtr + offset * ptrSize)
isQMetaObject = origType == 'QMetaObject'
isQObject = origType == 'QObject'
- #DumperBase.warn('OBJECT GUTS: %s 0x%x ' % (self.currentIName, metaObjectPtr))
+ #self.warn('OBJECT GUTS: %s 0x%x ' % (self.currentIName, metaObjectPtr))
dataPtr = extractDataPtr(metaObjectPtr)
- #DumperBase.warn('DATA PTRS: %s 0x%x ' % (self.currentIName, dataPtr))
+ #self.warn('DATA PTRS: %s 0x%x ' % (self.currentIName, dataPtr))
(revision, classname,
classinfo, classinfo2,
methodCount, methods,
@@ -1913,7 +2031,7 @@ class DumperBase():
ns = self.qtNamespace()
extraData = 0
if qobjectPtr:
- dd = self.extractPointer(qobjectPtr + ptrSize)
+ dd = self.extract_pointer_at_address(qobjectPtr + ptrSize)
if self.qtVersion() >= 0x60000:
(dvtablePtr, qptr, parent, children, bindingStorageData, bindingStatus,
flags, postedEvents, dynMetaObjectPtr, # Up to here QObjectData.
@@ -1942,7 +2060,7 @@ class DumperBase():
if not self.isCli:
self.putSortGroup(8)
- dvtablePtr, qptr, parentPtr, children = self.split('ppp{QList<QObject *>}', dd)
+ dvtablePtr, qptr, parentPtr, children = self.split('ppp{@QList<@QObject *>}', dd)
self.putItem(children)
if isQMetaObject:
@@ -2003,8 +2121,9 @@ class DumperBase():
if False:
with SubItem(self, '[connections]'):
if connectionListsPtr:
- typeName = '@QObjectConnectionListVector'
- self.putItem(self.createValue(connectionListsPtr, typeName))
+ typename = '@QObjectConnectionListVector'
+ self.putItem(self.createValueFromAddress(connectionListsPtr,
+typename))
else:
self.putItemCount(0)
@@ -2053,19 +2172,19 @@ class DumperBase():
if qobject and self.qtPropertyFunc:
# LLDB doesn't like calling it on a derived class, possibly
# due to type information living in a different shared object.
- #base = self.createValue(qobjectPtr, '@QObject')
- #DumperBase.warn("CALL FUNC: 0x%x" % self.qtPropertyFunc)
+ #base = self.createValueFromAddress(qobjectPtr, '@QObject')
+ #self.warn("CALL FUNC: 0x%x" % self.qtPropertyFunc)
cmd = '((QVariant(*)(void*,char*))0x%x)((void*)0x%x,"%s")' \
% (self.qtPropertyFunc, qobjectPtr, name)
try:
- #DumperBase.warn('PROP CMD: %s' % cmd)
+ #self.warn('PROP CMD: %s' % cmd)
res = self.parseAndEvaluate(cmd)
- #DumperBase.warn('PROP RES: %s' % res)
+ #self.warn('PROP RES: %s' % res)
except:
self.bump('failedMetaObjectCall')
putt(name, ' ')
continue
- #DumperBase.warn('COULD NOT EXECUTE: %s' % cmd)
+ #self.warn('COULD NOT EXECUTE: %s' % cmd)
#self.putCallItem(name, '@QVariant', base, 'property', '"' + name + '"')
if res is None:
self.bump('failedMetaObjectCall2')
@@ -2077,37 +2196,42 @@ class DumperBase():
# Dynamic properties.
if extraData:
- def list6Generator(addr, innerType):
+ def list6Generator(addr, inner_typeid):
data, size = self.listData(addr)
+ inner_size = self.type_size(inner_typeid)
for i in range(size):
- yield self.createValue(data + i * innerType.size(), innerType)
+ yield self.createValueFromAddress(data, inner_typeid)
+ data += inner_size
- def list5Generator(addr, innerType):
+ def list5Generator(addr, inner_typeid):
data, size = self.listData(addr)
for i in range(size):
- yield self.createValue(data + i * ptrSize, innerType)
+ yield self.createValueFromAddress(data, inner_typeid)
+ data += ptrSize
- def vectorGenerator(addr, innerType):
+ def vectorGenerator(addr, inner_typeid):
data, size = self.vectorData(addr)
+ inner_size = self.type_size(inner_typeid)
for i in range(size):
- yield self.createValue(data + i * innerType.size(), innerType)
+ yield self.createValueFromAddress(data, inner_typeid)
+ data += inner_size
- byteArrayType = self.createType('@QByteArray')
- variantType = self.createType('@QVariant')
+ variant_typeid = self.cheap_typeid_from_name('@QVariant')
if self.qtVersion() >= 0x60000:
- values = vectorGenerator(extraData + 3 * ptrSize, variantType)
+ values = vectorGenerator(extraData + 3 * ptrSize, variant_typeid)
elif self.qtVersion() >= 0x50600:
- values = vectorGenerator(extraData + 2 * ptrSize, variantType)
+ values = vectorGenerator(extraData + 2 * ptrSize, variant_typeid)
elif self.qtVersion() >= 0x50000:
- values = list5Generator(extraData + 2 * ptrSize, variantType)
+ values = list5Generator(extraData + 2 * ptrSize, variant_typeid)
else:
- values = list5Generator(extraData + 2 * ptrSize,
- variantType.pointer())
+ variantptr_typeid = self.cheap_typeid_from_name('@QVariant')
+ values = list5Generator(extraData + 2 * ptrSize, variantptr_typeid)
+ bytearray_typeid = self.cheap_typeid_from_name('@QByteArray')
if self.qtVersion() >= 0x60000:
- names = list6Generator(extraData, byteArrayType)
+ names = list6Generator(extraData, bytearray_typeid)
else:
- names = list5Generator(extraData + ptrSize, byteArrayType)
+ names = list5Generator(extraData + ptrSize, bytearray_typeid)
for (k, v) in zip(names, values):
with SubItem(self, propertyCount + dynamicPropertyCount):
@@ -2169,7 +2293,7 @@ class DumperBase():
if isQObject:
with SubItem(self, '[d]'):
- self.putItem(self.createValue(dd, '@QObjectPrivate'))
+ self.putItem(self.createValueFromAddress(dd, '@QObjectPrivate'))
self.putSortGroup(15)
if isQMetaObject:
@@ -2199,10 +2323,10 @@ class DumperBase():
with SubItem(self, '[connections]'):
ptrSize = self.ptrSize()
self.putNoType()
- privateType = self.createType('@QObjectPrivate')
+ privateType = self.create_typeid_from_name('@QObjectPrivate')
d_ptr = dd.cast(privateType.pointer()).dereference()
connections = d_ptr['connectionLists']
- if self.connections.integer() == 0:
+ if self.value_as_integer(connections) == 0:
self.putItemCount(0)
else:
connections = connections.dereference()
@@ -2215,72 +2339,74 @@ class DumperBase():
innerType = connections.type[0]
# Should check: innerType == ns::QObjectPrivate::ConnectionList
data, size = self.vectorData(connections)
- connectionType = self.createType('@QObjectPrivate::Connection')
+ connection_typeid = self.create_typeid_from_name('@QObjectPrivate::Connection')
+ connection_ptr_typeid = self.create_pointer_typeid(connection_typeid)
for i in range(size):
- first = self.extractPointer(data + i * 2 * ptrSize)
+ first = self.extract_pointer_at_address(data + i * 2 * ptrSize)
while first:
- self.putSubItem('%s' % pp,
- self.createPointerValue(first, connectionType))
- first = self.extractPointer(first + 3 * ptrSize)
+ val = self.Value(self)
+ val.ldata = first
+ val.typeid = connection_typeid
+ self.putSubItem('%s' % pp, val)
+ first = self.extract_pointer_at_address(first + 3 * ptrSize)
# We need to enforce some upper limit.
pp += 1
if pp > 1000:
break
- def currentItemFormat(self, typeName=None):
+ def currentItemFormat(self, typename=None):
displayFormat = self.formats.get(self.currentIName, DisplayFormat.Automatic)
if displayFormat == DisplayFormat.Automatic:
- if typeName is None:
- typeName = self.currentType.value
- needle = None if typeName is None else self.stripForFormat(typeName)
+ if typename is None:
+ typename = self.currentType.value
+ needle = None if typename is None else self.stripForFormat(typename)
displayFormat = self.typeformats.get(needle, DisplayFormat.Automatic)
return displayFormat
def putSubItem(self, component, value): # -> ReportItem
if not isinstance(value, self.Value):
raise RuntimeError('WRONG VALUE TYPE IN putSubItem: %s' % type(value))
- if not isinstance(value.type, self.Type):
- raise RuntimeError('WRONG TYPE TYPE IN putSubItem: %s' % type(value.type))
res = None
with SubItem(self, component):
self.putItem(value)
res = self.currentValue
return res # The 'short' display.
- def putArrayData(self, base, n, innerType, childNumChild=None):
+ def putArrayData(self, base, n, inner_typish, childNumChild=None):
self.checkIntType(base)
self.checkIntType(n)
- addrBase = base
- innerSize = innerType.size()
+ inner_typeid = self.typeid_for_typish(inner_typish)
+ inner_size = self.type_size_cache.get(inner_typeid, None)
self.putNumChild(n)
- #DumperBase.warn('ADDRESS: 0x%x INNERSIZE: %s INNERTYPE: %s' % (addrBase, innerSize, innerType))
- enc = innerType.simpleEncoding()
+ #self.warn('ADDRESS: 0x%x INNERSIZE: %s INNERTYPE: %s' % (base, inner_size, inner_typeid))
+ enc = self.type_encoding_cache.get(inner_typeid, None)
maxNumChild = self.maxArrayCount()
if enc:
- self.put('childtype="%s",' % innerType.name)
- self.put('addrbase="0x%x",' % addrBase)
- self.put('addrstep="0x%x",' % innerSize)
+ self.put('childtype="%s",' % self.type_name(inner_typeid))
+ self.put('addrbase="0x%x",' % base)
+ self.put('addrstep="0x%x",' % inner_size)
self.put('arrayencoding="%s",' % enc)
self.put('endian="%s",' % self.packCode)
if n > maxNumChild:
self.put('childrenelided="%s",' % n)
n = maxNumChild
self.put('arraydata="')
- self.put(self.readMemory(addrBase, n * innerSize))
+ self.put(self.readMemory(base, n * inner_size))
self.put('",')
else:
+ innerType = self.Type(self, inner_typeid)
with Children(self, n, innerType, childNumChild, maxNumChild,
- addrBase=addrBase, addrStep=innerSize):
+ addrBase=base, addrStep=inner_size):
for i in self.childRange():
- self.putSubItem(i, self.createValue(addrBase + i * innerSize, innerType))
+ self.putSubItem(i, self.createValueFromAddress(base + i * inner_size, innerType))
- def putArrayItem(self, name, addr, n, typeName):
+ def putArrayItem(self, name, addr, n, typename):
self.checkIntType(addr)
self.checkIntType(n)
with SubItem(self, name):
self.putEmptyValue()
- self.putType('%s [%d]' % (typeName, n))
- self.putArrayData(addr, n, self.lookupType(typeName))
+ self.putType('%s [%d]' % (typename, n))
+ self.putArrayData(addr, n, self.lookupType(typename))
self.putAddress(addr)
def putPlotDataHelper(self, base, n, innerType, maxNumChild=1000 * 1000):
@@ -2303,13 +2429,15 @@ class DumperBase():
"""
Special handling for char** argv.
"""
+ ptr_size = self.ptrSize()
n = 0
- p = value
- # p is 0 for "optimized out" cases. Or contains rubbish.
+ argv = self.value_as_address(value)
+ # argv is 0 for "optimized out" cases. Or contains rubbish.
try:
- if value.integer():
- while p.dereference().integer() and n <= 100:
- p += 1
+ if argv:
+ p = argv
+ while self.extract_pointer_at_address(p) and n <= 100:
+ p += ptr_size
n += 1
except:
pass
@@ -2325,44 +2453,54 @@ class DumperBase():
self.putSubItem(i, p.dereference())
p += 1
+ def extract_pointer_at_address(self, address):
+ blob = self.value_data_from_address(address, self.ptrSize())
+ return int.from_bytes(blob, byteorder='little')
+
+ def value_extract_integer(self, value, size, signed):
+ if isinstance(value.lvalue, int):
+ return value.lvalue
+ if isinstance(value.ldata, int):
+ return value.ldata
+ #with self.dumper.timer('extractInt'):
+ value.check()
+ blob = self.value_data(value, size)
+ return int.from_bytes(blob, byteorder='little', signed=signed)
+
+ def value_extract_something(self, valuish, size, signed=False):
+ if isinstance(valuish, int):
+ blob = self.value_data_from_address(valuish, size)
+ elif isinstance(valuish, self.Value):
+ blob = self.value_data(valuish, size)
+ else:
+ raise RuntimeError('CANT EXTRACT FROM %s' % type(valuish))
+ res = int.from_bytes(blob, byteorder='little', signed=signed)
+ #self.warn("EXTRACTED %s SIZE %s FROM %s" % (res, size, blob))
+ return res
+
def extractPointer(self, value):
- try:
- if value.type.code == TypeCode.Array:
- return value.address()
- except:
- pass
- code = 'I' if self.ptrSize() == 4 else 'Q'
- return self.extractSomething(value, code, 8 * self.ptrSize())
+ return self.value_extract_something(value, self.ptrSize())
def extractInt64(self, value):
- return self.extractSomething(value, 'q', 64)
+ return self.value_extract_something(value, 8, True)
def extractUInt64(self, value):
- return self.extractSomething(value, 'Q', 64)
+ return self.value_extract_something(value, 8)
def extractInt(self, value):
- return self.extractSomething(value, 'i', 32)
+ return self.value_extract_something(value, 4, True)
def extractUInt(self, value):
- return self.extractSomething(value, 'I', 32)
+ return self.value_extract_something(value, 4)
def extractShort(self, value):
- return self.extractSomething(value, 'h', 16)
+ return self.value_extract_something(value, 2, True)
def extractUShort(self, value):
- return self.extractSomething(value, 'H', 16)
+ return self.value_extract_something(value, 2)
def extractByte(self, value):
- return self.extractSomething(value, 'b', 8)
-
- def extractSomething(self, value, pattern, bitsize):
- if self.isInt(value):
- val = self.Value(self)
- val.laddress = value
- return val.extractSomething(pattern, bitsize)
- if isinstance(value, self.Value):
- return value.extractSomething(pattern, bitsize)
- raise RuntimeError('CANT EXTRACT FROM %s' % type(value))
+ return self.value_extract_something(value, 1)
# Parses a..b and a.(s).b
def parseRange(self, exp):
@@ -2405,9 +2543,9 @@ class DumperBase():
try:
# Allow integral expressions.
- ss = self.parseAndEvaluate(s[1:len(s) - 1]).integer() if s else 1
- aa = self.parseAndEvaluate(a).integer()
- bb = self.parseAndEvaluate(b).integer()
+ ss = self.value_as_integer(self.parseAndEvaluate(s[1:len(s) - 1])) if s else 1
+ aa = self.value_as_integer(self.parseAndEvaluate(a))
+ bb = self.value_as_integer(self.parseAndEvaluate(b))
if aa < bb and ss > 0:
return True, aa, ss, bb + 1, template
except:
@@ -2419,14 +2557,14 @@ class DumperBase():
self.putField('numchild', numchild)
def handleLocals(self, variables):
- #DumperBase.warn('VARIABLES: %s' % variables)
- #with self.timer('locals'):
+ #self.warn('VARIABLES: %s' % variables)
shadowed = {}
for value in variables:
if value.name == 'argv':
if value.type.code == TypeCode.Pointer:
- if value.type.ltarget.code == TypeCode.Pointer:
- if value.type.ltarget.ltarget.name == 'char':
+ target = value.type.target()
+ if target.code == TypeCode.Pointer:
+ if target.target().name == 'char':
self.putSpecialArgv(value)
continue
@@ -2455,7 +2593,7 @@ class DumperBase():
def handleWatch(self, origexp, exp, iname):
exp = str(exp).strip()
escapedExp = self.hexencode(exp)
- #DumperBase.warn('HANDLING WATCH %s -> %s, INAME: "%s"' % (origexp, exp, iname))
+ #self.warn('HANDLING WATCH %s -> %s, INAME: "%s"' % (origexp, exp, iname))
# Grouped items separated by semicolon.
if exp.find(';') >= 0:
@@ -2475,7 +2613,7 @@ class DumperBase():
# Special array index: e.g a[1..199] or a[1.(3).199] for stride 3.
isRange, begin, step, end, template = self.parseRange(exp)
if isRange:
- #DumperBase.warn('RANGE: %s %s %s in %s' % (begin, step, end, template))
+ #self.warn('RANGE: %s %s %s in %s' % (begin, step, end, template))
r = range(begin, end, step)
n = len(r)
with TopLevelItem(self, iname):
@@ -2714,7 +2852,7 @@ class DumperBase():
self.doContinue()
def doInsertInterpreterBreakpoint(self, args, wasPending):
- #DumperBase.warn('DO INSERT INTERPRETER BREAKPOINT, WAS PENDING: %s' % wasPending)
+ #self.warn('DO INSERT INTERPRETER BREAKPOINT, WAS PENDING: %s' % wasPending)
# Will fail if the service is not yet up and running.
response = self.sendInterpreterRequest('setbreakpoint', args)
bp = None if response is None else response.get('breakpoint', None)
@@ -2749,14 +2887,6 @@ class DumperBase():
def extractInterpreterStack(self):
return self.sendInterpreterRequest('backtrace', {'limit': 10})
- def isInt(self, thing):
- if isinstance(thing, int):
- return True
- if sys.version_info[0] == 2:
- if isinstance(thing, long):
- return True
- return False
-
def putItems(self, count, generator, maxNumChild=10000):
self.putItemCount(count)
if self.isExpanded():
@@ -2765,131 +2895,124 @@ class DumperBase():
self.putSubItem(i, val)
def putItem(self, value):
- #with self.timer('putItem'):
- self.putItemX(value)
-
- def putItemX(self, value):
- #DumperBase.warn('PUT ITEM: %s' % value.stringify())
-
- typeobj = value.type # unqualified()
- typeName = typeobj.name
-
- self.addToCache(typeobj) # Fill type cache
+ #self.warn('PUT ITEM: %s' % value.stringify())
+ #self.dump_location()
+ #self.addToCache(typeobj) # Fill type cache
if not value.lIsInScope:
self.putSpecialValue('optimizedout')
- #self.putType(typeobj)
- #self.putSpecialValue('outofscope')
self.putNumChild(0)
return
if not isinstance(value, self.Value):
raise RuntimeError('WRONG TYPE IN putItem: %s' % type(self.Value))
+ typeid = value.typeid
+ typecode = self.type_code(typeid)
+ typename = self.type_name(typeid)
+
# Try on possibly typedefed type first.
- if self.tryPutPrettyItem(typeName, value):
- if typeobj.code == TypeCode.Pointer:
+ if self.tryPutPrettyItem(typename, value):
+ if typecode == TypeCode.Pointer:
self.putOriginalAddress(value.address())
else:
self.putAddress(value.address())
return
- if typeobj.code == TypeCode.Typedef:
- #DumperBase.warn('TYPEDEF VALUE: %s' % value.stringify())
+ if typecode == TypeCode.Typedef:
+ #self.warn('TYPEDEF VALUE: %s' % value.stringify())
self.putItem(value.detypedef())
- self.putBetterType(typeName)
+ self.putBetterType(typename)
return
- if typeobj.code == TypeCode.Pointer:
+ if typecode == TypeCode.Pointer:
self.putFormattedPointer(value)
if value.summary and self.useFancy:
self.putValue(self.hexencode(value.summary), 'utf8:1:0')
return
self.putAddress(value.address())
- if value.lbitsize is not None:
- self.putField('size', value.lbitsize // 8)
- if typeobj.code == TypeCode.Function:
- #DumperBase.warn('FUNCTION VALUE: %s' % value)
- self.putType(typeobj)
- self.putSymbolValue(value.pointer())
+ if typecode == TypeCode.Function:
+ #self.warn('FUNCTION VALUE: %s' % value)
+ self.putType(typeid)
+ self.putSymbolValue(self.value_as_address(value))
self.putNumChild(0)
return
- if typeobj.code == TypeCode.Enum:
- #DumperBase.warn('ENUM VALUE: %s' % value.stringify())
- self.putType(typeobj.name)
+ if typecode == TypeCode.Enum:
+ #self.warn('ENUM VALUE: %s' % value.stringify())
+ self.putType(typename)
self.putValue(value.display())
self.putNumChild(0)
return
- if typeobj.code == TypeCode.Array:
- #DumperBase.warn('ARRAY VALUE: %s' % value)
+ if typecode == TypeCode.Array:
+ #self.warn('ARRAY VALUE: %s' % value)
self.putCStyleArray(value)
return
- if typeobj.code == TypeCode.Bitfield:
- #DumperBase.warn('BITFIELD VALUE: %s %d %s' % (value.name, value.lvalue, typeName))
+ if typecode == TypeCode.Bitfield:
+ #self.warn('BITFIELD VALUE: %s %d %s' % (value.name, value.lvalue, typename))
self.putNumChild(0)
- dd = typeobj.ltarget.tdata.enumDisplay
- self.putValue(str(value.lvalue) if dd is None else dd(
- value.lvalue, value.laddress, '%d'))
- self.putType(typeName)
+ #dd = typeobj.target().enumDisplay
+ #self.putValue(str(value.lvalue) if dd is None else dd(
+ # value.lvalue, value.laddress, '%d'))
+ self.putValue(self.value_as_integer(value))
+ self.putType(typename)
return
- if typeobj.code == TypeCode.Integral:
- #DumperBase.warn('INTEGER: %s %s' % (value.name, value))
- val = value.value()
+ if typecode == TypeCode.Integral:
+ #self.warn('INTEGER: %s %s' % (value.name, value))
self.putNumChild(0)
- self.putValue(val)
- self.putType(typeName)
+ self.putValue(self.value_as_integer(value))
+ self.putType(typename)
return
- if typeobj.code == TypeCode.Float:
- #DumperBase.warn('FLOAT VALUE: %s' % value)
+ if typecode == TypeCode.Float:
+ #self.warn('FLOAT VALUE: %s' % value)
self.putValue(value.value())
self.putNumChild(0)
- self.putType(typeobj.name)
+ self.putType(typename)
return
- if typeobj.code in (TypeCode.Reference, TypeCode.RValueReference):
- #DumperBase.warn('REFERENCE VALUE: %s' % value)
+ if typecode in (TypeCode.Reference, TypeCode.RValueReference):
+ #self.warn('REFERENCE VALUE: %s' % value)
val = value.dereference()
if val.laddress != 0:
self.putItem(val)
else:
self.putSpecialValue('nullreference')
- self.putBetterType(typeName)
+ self.putBetterType(typename)
return
- if typeobj.code == TypeCode.Complex:
- self.putType(typeobj)
+ if typecode == TypeCode.Complex:
+ self.putType(typeid)
self.putValue(value.display())
self.putNumChild(0)
return
- if typeobj.code == TypeCode.FortranString:
+ if typecode == TypeCode.FortranString:
self.putValue(self.hexencode(value.data()), 'latin1')
self.putNumChild(0)
- self.putType(typeobj)
+ self.putType(typeid)
- if typeName.endswith('[]'):
+ if typename.endswith('[]'):
# D arrays, gdc compiled.
n = value['length']
base = value['ptr']
- self.putType(typeName)
+ self.putType(typename)
self.putItemCount(n)
if self.isExpanded():
- self.putArrayData(base.pointer(), n, base.type.target())
+ self.putArrayData(self.value_as_address(base), n, base.type.target())
return
- #DumperBase.warn('SOME VALUE: %s' % value)
- #DumperBase.warn('GENERIC STRUCT: %s' % typeobj)
- #DumperBase.warn('INAME: %s ' % self.currentIName)
- #DumperBase.warn('INAMES: %s ' % self.expandedINames)
- #DumperBase.warn('EXPANDED: %s ' % (self.currentIName in self.expandedINames))
- self.putType(typeName)
+ #self.warn('SOME VALUE: %s' % value)
+ #self.warn('GENERIC STRUCT: %s' % typeid)
+ #self.warn('INAME: %s ' % self.currentIName)
+ #self.warn('INAMES: %s ' % self.expandedINames)
+ #self.warn('EXPANDED: %s ' % (self.currentIName in self.expandedINames))
+ self.putType(typename)
if value.summary is not None and self.useFancy:
self.putValue(self.hexencode(value.summary), 'utf8:1:0')
@@ -2898,7 +3021,7 @@ class DumperBase():
self.putExpandable()
self.putEmptyValue()
- #DumperBase.warn('STRUCT GUTS: %s ADDRESS: 0x%x ' % (value.name, value.address()))
+ #self.warn('STRUCT GUTS: %s ADDRESS: 0x%x ' % (value.name, value.address()))
if self.showQObjectNames:
#with self.timer(self.currentIName):
self.putQObjectNameValue(value)
@@ -2911,8 +3034,8 @@ class DumperBase():
self.tryPutQObjectGuts(value)
def symbolAddress(self, symbolName):
- res = self.parseAndEvaluate('(size_t)&' + symbolName)
- return None if res is None else res.pointer()
+ res = self.parseAndEvaluate('(void *)&' + symbolName)
+ return None if res is None else self.value_as_address(res)
def qtHookDataSymbolName(self):
return 'qtHookData'
@@ -2922,7 +3045,7 @@ class DumperBase():
if addr:
# Only available with Qt 5.3+
(hookVersion, x, x, x, x, x, tiVersion) = self.split('ppppppp', addr)
- #DumperBase.warn('HOOK: %s TI: %s' % (hookVersion, tiVersion))
+ #self.warn('HOOK: %s TI: %s' % (hookVersion, tiVersion))
if hookVersion >= 3:
self.qtTypeInfoVersion = lambda: tiVersion
return tiVersion
@@ -2954,16 +3077,15 @@ class DumperBase():
#self._stack = inspect.stack()
self.dumper = dumper
self.name = None
- self._type = None
+ self.typeid = None
+ self.code = None
+ self.size = None
self.ldata = None # Target address in case of references and pointers.
self.laddress = None # Own address.
self.lvalue = None
self.lIsInScope = True
self.ldisplay = None
self.summary = None # Always hexencoded UTF-8.
- self.lbitpos = None
- self.lbitsize = None
- self.targetValue = None # For references.
self.isBaseClass = None
self.nativeValue = None
self.autoDerefCount = 0
@@ -2972,49 +3094,47 @@ class DumperBase():
val = self.dumper.Value(self.dumper)
val.dumper = self.dumper
val.name = self.name
- val._type = self._type
+ val.typeid = self.typeid
+ val.code = self.code = None
+ val.size = self.size
val.ldata = self.ldata
val.laddress = self.laddress
+ val.lvalue = self.lvalue
val.lIsInScope = self.lIsInScope
val.ldisplay = self.ldisplay
val.summary = self.summary
- val.lbitpos = self.lbitpos
- val.lbitsize = self.lbitsize
- val.targetValue = self.targetValue
val.nativeValue = self.nativeValue
return val
@property
def type(self):
- if self._type is None and self.nativeValue is not None:
- self._type = self.dumper.nativeValueType(self.nativeValue)
- return self._type
+ return self.dumper.Type(self.dumper, self.typeid)
def check(self):
- if self.laddress is not None and not self.dumper.isInt(self.laddress):
- raise RuntimeError('INCONSISTENT ADDRESS: %s' % type(self.laddress))
- if self.type is not None and not isinstance(self.type, self.dumper.Type):
- raise RuntimeError('INCONSISTENT TYPE: %s' % type(self.type))
+ #if self.typeid is not None and not isinstance(self.typeid, int):
+ # raise RuntimeError('INCONSISTENT TYPE: %s' % type(self.typeid))
+ #if self.laddress is not None and not isinstance(self.laddress, int):
+ # raise RuntimeError('INCONSISTENT ADDRESS: %s' % type(self.laddress))
+ pass
def __str__(self):
#raise RuntimeError('Not implemented')
return self.stringify()
def __int__(self):
- return self.integer()
+ return self.dumper.value_as_integer(self)
def stringify(self):
addr = 'None' if self.laddress is None else ('0x%x' % self.laddress)
- return "Value(name='%s',type=%s,bsize=%s,bpos=%s,data=%s,address=%s)" \
- % (self.name, self.type.name, self.lbitsize, self.lbitpos,
- self.dumper.hexencode(self.ldata), addr)
+ if isinstance(self.ldata, int):
+ data = str(self.ldata)
+ else:
+ data = self.dumper.hexencode(self.ldata)
+ return "Value(name='%s',typeid=%s, type=%s,data=%s,address=%s)" \
+ % (self.name, self.typeid, self.type.name, data, addr)
def displayEnum(self, form='%d', bitsize=None):
- intval = self.integer(bitsize)
- dd = self.type.tdata.enumDisplay
- if dd is None:
- return str(intval)
- return dd(intval, self.laddress, form)
+ return self.dumper.value_display_enum(self, form, bitsize)
def display(self):
if self.ldisplay is not None:
@@ -3023,451 +3143,70 @@ class DumperBase():
if simple is not None:
return str(simple)
#if self.ldata is not None:
- # if sys.version_info[0] == 2 and isinstance(self.ldata, buffer):
- # return bytes(self.ldata).encode('hex')
# return self.ldata.encode('hex')
if self.laddress is not None:
return 'value of type %s at address 0x%x' % (self.type.name, self.laddress)
return '<unknown data>'
def pointer(self):
- if self.type.code == TypeCode.Typedef:
- return self.detypedef().pointer()
- return self.extractInteger(self.dumper.ptrSize() * 8, True)
-
- def integer(self, bitsize=None):
- if self.type.code == TypeCode.Typedef:
- return self.detypedef().integer()
- elif isinstance(self.lvalue, int):
- return self.lvalue
- # Could be something like 'short unsigned int'
- unsigned = self.type.name == 'unsigned' \
- or self.type.name.startswith('unsigned ') \
- or self.type.name.find(' unsigned ') != -1
- if bitsize is None:
- bitsize = self.type.lbitsize
- return self.extractInteger(bitsize, unsigned)
+ return self.dumper.value_as_address(self)
+
+ def as_address(self):
+ return self.dumper.value_as_address(self)
+
+ def integer(self):
+ return self.dumper.value_as_integer(self)
def floatingPoint(self):
- if self.nativeValue is not None and not self.dumper.isCdb:
- return str(self.nativeValue)
- if self.type.code == TypeCode.Typedef:
- return self.detypedef().floatingPoint()
- if self.type.size() == 8:
- return self.extractSomething('d', 64)
- if self.type.size() == 4:
- return self.extractSomething('f', 32)
- # Fall back in case we don't have a nativeValue at hand.
- # FIXME: This assumes Intel's 80bit extended floats. Which might
- # be wrong.
- l, h = self.split('QQ')
- if True: # 80 bit floats
- sign = (h >> 15) & 1
- exp = (h & 0x7fff)
- fraction = l
- bit63 = (l >> 63) & 1
- #DumperBase.warn("SIGN: %s EXP: %s H: 0x%x L: 0x%x" % (sign, exp, h, l))
- if exp == 0:
- if bit63 == 0:
- if l == 0:
- res = '-0' if sign else '0'
- else:
- res = (-1)**sign * l * 2**(-16382) # subnormal
- else:
- res = 'pseudodenormal'
- elif exp == 0x7fff:
- res = 'special'
- else:
- res = (-1)**sign * l * 2**(exp - 16383 - 63)
- else: # 128 bits
- sign = h >> 63
- exp = (h >> 48) & 0x7fff
- fraction = h & (2**48 - 1)
- #DumperBase.warn("SIGN: %s EXP: %s FRAC: %s H: 0x%x L: 0x%x" % (sign, exp, fraction, h, l))
- if exp == 0:
- if fraction == 0:
- res = -0.0 if sign else 0.0
- else:
- res = (-1)**sign * fraction / 2**48 * 2**(-62) # subnormal
- elif exp == 0x7fff:
- res = ('-inf' if sign else 'inf') if fraction == 0 else 'nan'
- else:
- res = (-1)**sign * (1 + fraction / 2**48) * 2**(exp - 63)
- return res
+ return self.dumper.value_as_floating_point(self)
def value(self):
- if self.type is not None:
- if self.type.code == TypeCode.Enum:
- return self.displayEnum()
- if self.type.code == TypeCode.Typedef:
- return self.detypedef().value()
- if self.type.code == TypeCode.Integral:
- return self.integer()
- if self.type.code == TypeCode.Bitfield:
- return self.integer()
- if self.type.code == TypeCode.Float:
- return self.floatingPoint()
- if self.type.code == TypeCode.Pointer:
- return self.pointer()
- return None
+ return self.dumper.value_display(self)
def extractPointer(self):
- return self.split('p')[0]
+ return self.dumper.value_extract_something(self, self.dumper.ptrSize())
def hasMember(self, name):
- return self.findMemberByName(name) is not None
+ return self.dumper.value_member_by_name(self, name) is not None
- def findMemberByName(self, name):
- self.check()
- if self.type.code == TypeCode.Typedef:
- return self.findMemberByName(self.detypedef())
- if self.type.code in (
- TypeCode.Pointer,
- TypeCode.Reference,
- TypeCode.RValueReference):
- res = self.dereference().findMemberByName(name)
- if res is not None:
- return res
- if self.type.code == TypeCode.Struct:
- #DumperBase.warn('SEARCHING FOR MEMBER: %s IN %s' % (name, self.type.name))
- members = self.members(True)
- #DumperBase.warn('MEMBERS: %s' % members)
- for member in members:
- #DumperBase.warn('CHECKING FIELD %s' % member.name)
- if member.type.code == TypeCode.Typedef:
- member = member.detypedef()
- if member.name == name:
- return member
- for member in members:
- if member.type.code == TypeCode.Typedef:
- member = member.detypedef()
- if member.name == name: # Could be base class.
- return member
- if member.type.code == TypeCode.Struct:
- res = member.findMemberByName(name)
- if res is not None:
- return res
- return None
+ def __getitem__(self, indexish):
+ return self.dumper.value_member_by_indexish(self, indexish)
- def __getitem__(self, index):
- #DumperBase.warn('GET ITEM %s %s' % (self, index))
- self.check()
- if self.type.code == TypeCode.Typedef:
- #DumperBase.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 == TypeCode.Pointer:
- #DumperBase.warn('GET ITEM %s DEREFERENCE TO %s' % (self, self.dereference()))
- return self.dereference().__getitem__(index)
- res = self.findMemberByName(index)
- if res is None:
- raise RuntimeError('No member named %s in type %s'
- % (index, self.type.name))
- return res
- elif isinstance(index, self.dumper.Field):
- field = index
- elif self.dumper.isInt(index):
- if self.type.code == TypeCode.Array:
- addr = self.laddress + int(index) * self.type.ltarget.size()
- return self.dumper.createValue(addr, self.type.ltarget)
- if self.type.code == TypeCode.Pointer:
- addr = self.pointer() + int(index) * self.type.ltarget.size()
- return self.dumper.createValue(addr, self.type.ltarget)
- return self.members(False)[index]
- else:
- raise RuntimeError('BAD INDEX TYPE %s' % type(index))
- field.check()
-
- #DumperBase.warn('EXTRACT FIELD: %s, BASE 0x%x' % (field, self.address()))
- if self.type.code == TypeCode.Pointer:
- #DumperBase.warn('IS TYPEDEFED POINTER!')
- res = self.dereference()
- #DumperBase.warn('WAS POINTER: %s' % res)
-
- return field.extract(self)
-
- def extractField(self, field):
- if not isinstance(field, self.dumper.Field):
- raise RuntimeError('BAD INDEX TYPE %s' % type(field))
-
- if field.extractor is not None:
- val = field.extractor(self)
- if val is not None:
- #DumperBase.warn('EXTRACTOR SUCCEEDED: %s ' % val)
- return val
-
- if self.type.code == TypeCode.Typedef:
- return self.cast(self.type.ltarget).extractField(field)
- if self.type.code in (TypeCode.Reference, TypeCode.RValueReference):
- return self.dereference().extractField(field)
- #DumperBase.warn('FIELD: %s ' % (field,))
- val = self.dumper.Value(self.dumper)
- val.name = field.name
- val.isBaseClass = field.isBase
- 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.bitsize
- fieldSize = (fieldBitsize + 7) // 8
- fieldBitpos = field.bitpos
- fieldOffset = fieldBitpos // 8
- fieldType = field.fieldType()
-
- if fieldType.code == TypeCode.Bitfield:
- fieldBitpos -= fieldOffset * 8
- ldata = self.data()
- data = 0
- for i in range(fieldSize):
- data = data << 8
- if self.dumper.isBigEndian:
- lbyte = ldata[i]
- else:
- lbyte = ldata[fieldOffset + fieldSize - 1 - i]
- if isinstance(lbyte, (str, bytes)):
- data += ord(lbyte)
- else:
- data += lbyte
- data = data >> fieldBitpos
- data = data & ((1 << fieldBitsize) - 1)
- val.lvalue = data
- val.laddress = None
- return val
-
- if self.laddress is not None:
- val.laddress = self.laddress + fieldOffset
- elif self.ldata is not None:
- val.ldata = self.ldata[fieldOffset:fieldOffset + fieldSize]
- else:
- self.dumper.check(False)
-
- if fieldType.code in (TypeCode.Reference, TypeCode.RValueReference):
- if val.laddress is not None:
- val = self.dumper.createReferenceValue(val.laddress, fieldType.ltarget)
- val.name = field.name
-
- #DumperBase.warn('GOT VAL %s FOR FIELD %s' % (val, field))
- val.lbitsize = fieldBitsize
- val.check()
- return val
-
- # This is the generic version for synthetic values.
- # The native backends replace it in their fromNativeValue()
- # implementations.
- def members(self, includeBases):
- #DumperBase.warn("LISTING MEMBERS OF %s" % self)
- if self.type.code == TypeCode.Typedef:
- return self.detypedef().members(includeBases)
-
- tdata = self.type.tdata
- #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))
-
- #DumperBase.warn("FIELDS: %s" % fields)
- res = []
- for field in fields:
- if isinstance(field, self.dumper.Value):
- #DumperBase.warn("USING VALUE DIRECTLY %s" % field.name)
- res.append(field)
- continue
- if field.isBase and not includeBases:
- #DumperBase.warn("DROPPING BASE %s" % field.name)
- continue
- res.append(self.extractField(field))
- #DumperBase.warn("GOT MEMBERS: %s" % res)
- return res
+ def members(self, include_bases):
+ return self.dumper.value_members(self, include_bases)
def __add__(self, other):
- self.check()
- if self.dumper.isInt(other):
- stripped = self.type.stripTypedefs()
- if stripped.code == TypeCode.Pointer:
- address = self.pointer() + stripped.dereference().size() * other
- val = self.dumper.Value(self.dumper)
- val.laddress = None
- val.ldata = bytes(struct.pack(self.dumper.packCode + 'Q', address))
- val._type = self._type
- return val
- raise RuntimeError('BAD DATA TO ADD TO: %s %s' % (self.type, other))
+ return self.dumper.value_plus_something(self, other)
def __sub__(self, other):
- self.check()
- if self.type.name == other.type.name:
- stripped = self.type.stripTypedefs()
- if stripped.code == TypeCode.Pointer:
- return (self.pointer() - other.pointer()) // stripped.dereference().size()
- raise RuntimeError('BAD DATA TO SUB TO: %s %s' % (self.type, other))
+ return self.dumper.value_minus_something(self, other)
def dereference(self):
- self.check()
- if self.type.code == TypeCode.Typedef:
- return self.detypedef().dereference()
- val = self.dumper.Value(self.dumper)
- if self.type.code in (TypeCode.Reference, TypeCode.RValueReference):
- val.summary = self.summary
- if self.nativeValue is None:
- val.laddress = self.pointer()
- if val.laddress is None and self.laddress is not None:
- val.laddress = self.laddress
- val._type = self.type.dereference()
- if self.dumper.useDynamicType:
- val._type = self.dumper.nativeDynamicType(val.laddress, val.type)
- else:
- val = self.dumper.nativeValueDereferenceReference(self)
- elif self.type.code == TypeCode.Pointer:
- try:
- val = self.dumper.nativeValueDereferencePointer(self)
- except:
- val.laddress = self.pointer()
- val._type = self.type.dereference()
- if self.dumper.useDynamicType:
- val._type = self.dumper.nativeDynamicType(val.laddress, val.type)
- else:
- raise RuntimeError("WRONG: %s" % self.type.code)
- #DumperBase.warn("DEREFERENCING FROM: %s" % self)
- #DumperBase.warn("DEREFERENCING TO: %s" % val)
- #dynTypeName = val.type.dynamicTypeName(val.laddress)
- #if dynTypeName is not None:
- # val._type = self.dumper.createType(dynTypeName)
- return val
+ return self.dumper.value_dereference(self)
def detypedef(self):
- self.check()
- if self.type.code != TypeCode.Typedef:
- raise RuntimeError("WRONG")
- val = self.copy()
- val._type = self.type.ltarget
- #DumperBase.warn("DETYPEDEF FROM: %s" % self)
- #DumperBase.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
- val.ldata = self.zeroExtend(self.ldata)
- return val
- if self.type.size() == size:
- return self
- raise RuntimeError('NOT IMPLEMENTED')
-
- def zeroExtend(self, data, size):
- ext = '\0' * (size - len(data))
- if sys.version_info[0] == 3:
- pad = bytes(ext, encoding='latin1')
- else:
- pad = bytes(ext)
- return pad + data if self.dumper.isBigEndian else data + pad
+ return self.dumper.value_detypedef(self)
def cast(self, typish):
- self.check()
- val = self.dumper.Value(self.dumper)
- val.laddress = self.laddress
- val.lbitsize = self.lbitsize
- val.ldata = self.ldata
- val._type = self.dumper.createType(typish)
- return val
+ return self.dumper.value_cast(self, typish)
def address(self):
self.check()
return self.laddress
- def data(self, size=None):
- self.check()
- if self.ldata is not None:
- if len(self.ldata) > 0:
- if size is None:
- return self.ldata
- if size == len(self.ldata):
- return self.ldata
- if size < len(self.ldata):
- return self.ldata[:size]
- #raise RuntimeError('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
- raise RuntimeError('CANNOT CONVERT ADDRESS TO BYTES: %s' % self)
- raise RuntimeError('CANNOT CONVERT TO BYTES: %s' % self)
-
- def extractInteger(self, bitsize, unsigned):
- #with self.dumper.timer('extractInt'):
- self.check()
- if bitsize > 32:
- size = 8
- code = 'Q' if unsigned else 'q'
- elif bitsize > 16:
- size = 4
- code = 'I' if unsigned else 'i'
- elif bitsize > 8:
- size = 2
- code = 'H' if unsigned else 'h'
- else:
- size = 1
- code = 'B' if unsigned else 'b'
- rawBytes = self.data(size)
- res = struct.unpack_from(self.dumper.packCode + code, rawBytes, 0)[0]
- #DumperBase.warn('Extract: Code: %s Bytes: %s Bitsize: %s Size: %s'
- # % (self.dumper.packCode + code, self.dumper.hexencode(rawBytes), bitsize, size))
- return res
-
- def extractSomething(self, code, bitsize):
- #with self.dumper.timer('extractSomething'):
- self.check()
- size = (bitsize + 7) >> 3
- rawBytes = self.data(size)
- res = struct.unpack_from(self.dumper.packCode + code, rawBytes, 0)[0]
- return res
+ def data(self):
+ return self.dumper.value_data(self, self.dumper.type_size(self.typeid))
def to(self, pattern):
return self.split(pattern)[0]
def split(self, pattern):
- #with self.dumper.timer('split'):
- #DumperBase.warn('EXTRACT STRUCT FROM: %s' % self.type)
- (pp, size, fields) = self.dumper.describeStruct(pattern)
- #DumperBase.warn('SIZE: %s ' % size)
- result = struct.unpack_from(self.dumper.packCode + pp, self.data(size))
-
- def structFixer(field, thing):
- #DumperBase.warn('STRUCT MEMBER: %s' % type(thing))
- if field.isStruct:
- #if field.type != field.fieldType():
- # raise RuntimeError('DO NOT SIMPLIFY')
- #DumperBase.warn('FIELD POS: %s' % field.type.stringify())
- #DumperBase.warn('FIELD TYE: %s' % field.fieldType().stringify())
- res = self.dumper.createValue(thing, field.fieldType())
- #DumperBase.warn('RES TYPE: %s' % res.type)
- if self.laddress is not None:
- res.laddress = self.laddress + field.offset()
- return res
- return thing
- if len(fields) != len(result):
- raise RuntimeError('STRUCT ERROR: %s %s' % (fields, result))
- return tuple(map(structFixer, fields, result))
+ return self.dumper.value_split(self, pattern)
def checkPointer(self, p, align=1):
- ptr = p if self.isInt(p) else p.pointer()
+ ptr = p if isinstance(p, int) else p.pointer()
self.readRawMemory(ptr, 1)
- def type(self, typeId):
- return self.typeData.get(typeId)
-
def splitArrayType(self, type_name):
# "foo[2][3][4]" -> ("foo", "[3][4]", 2)
pos1 = len(type_name)
@@ -3481,249 +3220,171 @@ class DumperBase():
item_count = type_name[pos1 + 1:pos2]
return (type_name[0:pos1].strip(), type_name[pos2 + 1:].strip(), int(item_count))
- def registerTypeAlias(self, existingTypeId, aliasId):
- #DumperBase.warn('REGISTER ALIAS %s FOR %s' % (aliasId, existingTypeId))
- self.typeData[aliasId] = self.typeData[existingTypeId]
-
- class TypeData():
- def __init__(self, dumper, type_id):
- self.dumper = dumper
- self.lfields = None # None or Value -> list of member Values
- self.lalignment = None # Function returning alignment of this struct
- self.lbitsize = None
- self.ltarget = None # Inner type for arrays
- self.templateArguments = None
- self.code = None
- self.name = type_id
- self.typeId = type_id
- self.enumDisplay = None
- self.moduleName = None
- #DumperBase.warn('REGISTER TYPE: %s' % type_id)
- dumper.typeData[type_id] = self
-
- def copy(self):
- tdata = self.dumper.TypeData(self.dumper, self.typeId)
- tdata.dumper = self.dumper
- tdata.lfields = self.lfields
- tdata.lalignment = self.lalignment
- tdata.lbitsize = self.lbitsize
- tdata.ltarget = self.ltarget
- tdata.templateArguments = self.templateArguments
- tdata.code = self.code
- tdata.name = self.name
- tdata.typeId = self.typeId
- tdata.enumDisplay = self.enumDisplay
- tdata.moduleName = self.moduleName
- return tdata
-
- @property
- def bitsize(self):
- if callable(self.lbitsize):
- self.lbitsize = self.lbitsize()
- return self.lbitsize
+ def registerTypeAlias(self, existing_type_id, alias_id):
+ #self.warn('REGISTER ALIAS %s FOR %s' % (aliasId, existingTypeId))
+ self.type_alias[alias_id] = existing_type_id
+
+ def init_type_cache(self):
+ self.type_name_cache = {}
+ self.type_fields_cache = {}
+ self.type_alignment_cache = {}
+ self.type_bitsize_cache = {}
+ self.type_size_cache = {}
+ self.type_target_cache = {}
+ self.type_template_arguments_cache = {}
+ self.type_code_cache = {}
+ self.type_enum_display_cache = {}
+ self.type_module_name_cache = {}
+ self.type_nativetype_cache = {}
+ self.type_modulename_cache = {}
+ self.type_encoding_cache = {}
+ self.typeid_cache = {} # internal typename -> id
+ self.typeid_current = 100
+ self.typeid_from_typekey = {} # typename -> id
+
+ def dump_type_cache(self):
+ self.warn('NAME: %s' % self.type_name_cache)
+ self.warn('CODE: %s' % self.type_code_cache)
+ #self.warn('FIELDS: %s' % self.type_fields_cache)
+ self.warn('SIZE: %s' % self.type_size_cache)
+ self.warn('TARGS: %s' % self.type_template_arguments_cache)
+ self.warn('BITSIZE: %s' % self.type_bitsize_cache)
+ self.warn('TARGET: %s' % self.type_target_cache)
+ #self.warn('NATIVETYPE: %s' % self.type_nativetype_cache)
+
+ def dump_typeid(self, typeid):
+ self.warn(' NAME: %s' % self.type_name_cache.get(typeid, None))
+ self.warn(' CODE: %s' % self.type_code_cache.get(typeid, None))
+ #self.warn(' FIELDS: %s' % self.type_fields_cache.get(typeid, None))
+ self.warn(' SIZE: %s' % self.type_size_cache.get(typeid, None))
+ self.warn(' TARGS: %s' % self.type_template_arguments_cache.get(typeid, None))
+ self.warn(' BITSIZE: %s' % self.type_bitsize_cache.get(typeid, None))
+ self.warn(' TARGET: %s' % self.type_target_cache.get(typeid, None))
+ #self.warn(' NATIVETYPE: %s' % self.type_nativetype_cache.get(typeid, None))
+
+ def typeid_for_typish(self, typish):
+ if isinstance(typish, int):
+ return typish
+ if isinstance(typish, str):
+ return self.typeid_for_string(typish)
+ if isinstance(typish, self.Type):
+ return typish.typeid
+ self.warn('NO TYPE FOR TYPISH: %s' % str(typish))
+ return 0
+
+ def sanitize_type_name(self, typeid_str):
+ if not ' ' in typeid_str:
+ # FIXME: This uses self.qtNamespace() too early.
+ #typeid_arr.append(self.qtNamespace())
+ return typeid_str.replace('@', '')
+ typeid_arr = []
+ last_char_was_space = False
+ for c in typeid_str:
+ if c == '@' in typeid_str:
+ # FIXME: This uses self.qtNamespace() too early.
+ #typeid_arr.append(self.qtNamespace())
+ pass
+ elif c == ' ':
+ last_char_was_space = True
+ elif c in '&*<>,':
+ last_char_was_space = False
+ typeid_arr.append(c)
+ else:
+ if last_char_was_space:
+ typeid_arr.append(' ')
+ last_char_was_space = False
+ typeid_arr.append(c)
+ #self.warn("SANITIZE: '%s' TO '%s'" % (typeid_str, ''.join(typeid_arr)))
+ return ''.join(typeid_arr)
+
+ def typeid_for_string(self, typeid_str, type_name=None):
+ #typeid = self.typeid_cache.get(typeid_str, None)
+ #if typeid is not None:
+ # return typeid
+ sane_typeid_str = self.sanitize_type_name(typeid_str)
+ typeid = self.typeid_cache.get(sane_typeid_str, None)
+ if typeid is not None:
+ return typeid
+
+ self.typeid_current += 1
+ if type_name is None:
+ type_name = sane_typeid_str
+ typeid = self.typeid_current
+ self.typeid_cache[typeid_str] = typeid
+ self.typeid_cache[sane_typeid_str] = typeid
+ self.type_name_cache[typeid] = type_name
+ #if typeid == 103:
+ #self.warn("CREATED TYPE: %d %s" % (typeid, sane_typeid_str))
+ #if typeid == 135: self.dump_location()
+ return typeid
class Type():
- def __init__(self, dumper, typeId):
- self.typeId = typeId.replace('@', dumper.qtNamespace())
+ __slots__ = ['dumper', 'typeid']
+ def __init__(self, dumper, typeid):
self.dumper = dumper
- self.initialized = False
+ self.typeid = typeid
def __str__(self):
- #return self.typeId
- return self.stringify()
-
- @property
- def tdata(self):
- if not self.initialized:
- self.initialized = True
- self.data = self.dumper.typeData.get(self.typeId, None)
- if self.data is None:
- #DumperBase.warn('USING : %s' % self.typeId)
- self.dumper.lookupType(self.typeId)
- self.data = self.dumper.typeData.get(self.typeId)
- return self.data
-
- def setTdata(self, tdata):
- self.initialized = True
- self.data = tdata
+ return self.dumper.type_stringify(self.typeid)
@property
def name(self):
- return self.typeId if self.tdata is None else self.tdata.name
+ return self.dumper.type_name(self.typeid)
@property
def code(self):
- return self.tdata.code
+ return self.dumper.type_code(self.typeid)
- @property
- def lbitsize(self):
- return self.tdata.bitsize
+ def bitsize(self):
+ return self.dumper.type_bitsize(self.typeid)
- @property
- def lbitpos(self):
- return self.tdata.lbitpos
+ def size(self):
+ return self.dumper.type_size(self.typeid)
- @property
- def ltarget(self):
- if isinstance(self.tdata.ltarget, str):
- self.tdata.ltarget = self.dumper.createType(self.tdata.ltarget)
- return self.tdata.ltarget
+ def target(self):
+ return self.dumper.Type(self.dumper, self.dumper.type_target(self.typeid))
@property
def targetName(self):
- if self.tdata.ltarget is None:
+ target = self.target()
+ if target is None:
return ''
- return self.tdata.ltarget if isinstance(self.tdata.ltarget, str) else self.tdata.ltarget.name
+ return target if isinstance(target, str) else target.name
@property
def moduleName(self):
- if callable(self.tdata.moduleName):
- self.tdata.moduleName = self.tdata.moduleName()
- return self.tdata.moduleName
-
- def stringify(self):
- return 'Type(name="%s",bsize=%s,code=%s)' \
- % (self.tdata.name, self.lbitsize, self.tdata.code)
+ return self.dumper.type_modulename_cache.get(self.typeid, None)
def __getitem__(self, index):
- if self.dumper.isInt(index):
- return self.templateArgument(index)
+ if isinstance(index, int):
+ return self.dumper.type_template_argument(self.typeid, index)
raise RuntimeError('CANNOT INDEX TYPE')
- def dynamicTypeName(self, address):
- if self.tdata.code != TypeCode.Struct:
- return None
- try:
- vtbl = self.dumper.extractPointer(address)
- except:
- return None
- #DumperBase.warn('VTBL: 0x%x' % vtbl)
- if not self.dumper.couldBePointer(vtbl):
- return None
- return self.dumper.nativeDynamicTypeName(address, self)
-
- def dynamicType(self, address):
- # FIXME: That buys some performance at the cost of a fail
- # of Gdb13393 dumper test.
- #return self
- #with self.dumper.timer('dynamicType %s 0x%s' % (self.name, address)):
- dynTypeName = self.dynamicTypeName(address)
- if dynTypeName is not None:
- return self.dumper.createType(dynTypeName)
- return self
-
def check(self):
- if self.tdata.name is None:
- raise RuntimeError('TYPE WITHOUT NAME: %s' % self.typeId)
+ #if self.tdata.name is None:
+ # raise RuntimeError('TYPE WITHOUT NAME: %s' % self.typeid)
+ pass
def dereference(self):
- if self.code == TypeCode.Typedef:
- return self.ltarget.dereference()
- self.check()
- return self.ltarget
-
- def unqualified(self):
- return self
+ return self.dumper.Type(self.dumper, self.dumper.type_dereference(self.typeid))
def templateArguments(self):
- if self.tdata is None:
- return self.dumper.listTemplateParameters(self.typeId)
- return self.tdata.templateArguments()
-
- def templateArgument(self, position):
- #DumperBase.warn('TDATA: %s' % self.tdata)
- #DumperBase.warn('ID: %s' % self.typeId)
- if self.tdata is None or self.tdata.templateArguments 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)
- #DumperBase.warn('MANUAL: %s' % ta)
- res = ta[position]
- #DumperBase.warn('RES: %s' % res.typeId)
- return res
- #DumperBase.warn('TA: %s %s' % (position, self.typeId))
- #DumperBase.warn('ARGS: %s' % self.tdata.templateArguments())
- return self.tdata.templateArguments()[position]
-
- def simpleEncoding(self):
- res = {
- 'bool': 'int:1',
- 'char': 'int:1',
- 'int8_t': 'int:1',
- 'qint8': 'int:1',
- 'signed char': 'int:1',
- 'char8_t': 'uint:1',
- 'unsigned char': 'uint:1',
- 'uint8_t': 'uint:1',
- 'quint8': 'uint:1',
- 'short': 'int:2',
- 'int16_t': 'int:2',
- 'qint16': 'int:2',
- 'unsigned short': 'uint:2',
- 'char16_t': 'uint:2',
- 'uint16_t': 'uint:2',
- 'quint16': 'uint:2',
- 'int': 'int:4',
- 'int32_t': 'int:4',
- 'qint32': 'int:4',
- 'unsigned int': 'uint:4',
- 'char32_t': 'uint:4',
- 'uint32_t': 'uint:4',
- 'quint32': 'uint:4',
- 'long long': 'int:8',
- 'int64_t': 'int:8',
- 'qint64': 'int:8',
- 'unsigned long long': 'uint:8',
- 'uint64_t': 'uint:8',
- 'quint64': 'uint:8',
- 'float': 'float:4',
- 'double': 'float:8',
- 'QChar': 'uint:2'
- }.get(self.name, None)
- return res
+ return self.dumper.type_template_arguments(self.typeid)
+
+ def templateArgument(self, index):
+ return self.dumper.type_template_argument(self.typeid, index)
def isSimpleType(self):
return self.code in (TypeCode.Integral, TypeCode.Float, TypeCode.Enum)
def alignment(self):
- if self.tdata.code == TypeCode.Typedef:
- return self.ltarget.alignment()
- if self.tdata.code in (TypeCode.Integral, TypeCode.Float, TypeCode.Enum):
- if self.tdata.name in ('double', 'long long', 'unsigned long long'):
- # Crude approximation.
- return 8 if self.dumper.isWindowsTarget() else self.dumper.ptrSize()
- return self.size()
- if self.tdata.code in (TypeCode.Pointer, TypeCode.Reference, TypeCode.RValueReference):
- return self.dumper.ptrSize()
- if self.tdata.lalignment is not None:
- #if isinstance(self.tdata.lalignment, function): # Does not work that way.
- if hasattr(self.tdata.lalignment, '__call__'):
- return self.tdata.lalignment()
- return self.tdata.lalignment
- return 1
+ return self.dumper.type_alignment(self.typeid)
def pointer(self):
- return self.dumper.createPointerType(self)
-
- def target(self):
- return self.ltarget
+ return self.dumper.Type(self.dumper, self.dumper.create_pointer_typeid(self.typeid))
def stripTypedefs(self):
- if isinstance(self, self.dumper.Type) and self.code != TypeCode.Typedef:
- #DumperBase.warn('NO TYPEDEF: %s' % self)
- return self
- return self.ltarget
-
- def size(self):
- bs = self.lbitsize
- if bs % 8 != 0:
- DumperBase.warn('ODD SIZE: %s' % self)
- return (7 + bs) >> 3
-
- def bitsize(self):
- if self.lbitsize is not None:
- return self.lbitsize
- raise RuntimeError('DONT KNOW SIZE: %s' % self)
+ return self.dumper.Type(self.dumper, self.dumper.type_target(self.typeid))
def isMovableType(self):
if self.code in (TypeCode.Pointer, TypeCode.Integral, TypeCode.Float):
@@ -3748,264 +3409,195 @@ class DumperBase():
return self.dumper.qtVersion() >= 0x050600
return False
- class Field(collections.namedtuple('Field',
- ['dumper', 'name', 'type', 'bitsize', 'bitpos',
- 'extractor', 'isBase', 'isStruct', 'isArtificial'])):
+ class Field:
+ __slots__ = ['name', 'typeid', 'bitsize', 'bitpos', 'is_struct', 'is_artificial', 'is_base_class']
- def __new__(cls, dumper, name=None, type=None, bitsize=None, bitpos=None,
- extractor=None, isBase=False, isStruct=False, isArtificial=False):
- return super(DumperBase.Field, cls).__new__(
- cls, dumper, name, type, bitsize, bitpos,
- extractor, isBase, isStruct, isArtificial)
+ def __init__(self, name=None, typeid=None, bitsize=None, bitpos=None,
+ extractor=None, is_struct=False, is_artificial=False, is_base_class=False):
+ self.name = name
+ self.typeid = typeid
+ self.bitsize = bitsize
+ self.bitpos = bitpos
+ self.is_struct = is_struct
+ self.is_base_class = is_base_class
- __slots__ = ()
-
- def __str__(self):
- return self.stringify()
-
- def stringify(self):
- #return 'Field(name="%s")' % self.name
- typename = None if self.type is None else self.type.stringify()
- return 'Field(name="%s",type=%s,bitpos=%s,bitsize=%s)' \
- % (self.name, typename, self.bitpos, self.bitsize)
-
- def check(self):
- pass
-
- def size(self):
- return self.bitsize() // 8
-
- def offset(self):
- return self.bitpos // 8
-
- def fieldType(self):
- if self.type is not None:
- return self.type
- raise RuntimeError('CANT GET FIELD TYPE FOR %s' % self)
- return None
def ptrCode(self):
return 'I' if self.ptrSize() == 4 else 'Q'
- def toPointerData(self, address):
- if not self.isInt(address):
- raise RuntimeError('wrong')
- return bytes(struct.pack(self.packCode + self.ptrCode(), address))
-
def fromPointerData(self, bytes_value):
return struct.unpack(self.packCode + self.ptrCode(), bytes_value)
- def createPointerValue(self, targetAddress, targetTypish):
- if not isinstance(targetTypish, self.Type) and not isinstance(targetTypish, str):
- raise RuntimeError('Expected type in createPointerValue(), got %s'
- % type(targetTypish))
- if not self.isInt(targetAddress):
+ def createPointerValue(self, target_address, target_typish):
+ if not isinstance(target_address, int):
raise RuntimeError('Expected integral address value in createPointerValue(), got %s'
- % type(targetTypish))
+ % type(target_typish))
val = self.Value(self)
- val.ldata = self.toPointerData(targetAddress)
- targetType = self.createType(targetTypish)
- if self.useDynamicType:
- targetType = targetType.dynamicType(targetAddress)
- val._type = self.createPointerType(targetType)
+ val.ldata = target_address
+ val.typeid = self.create_pointer_typeid(self.create_typeid(target_typish))
return val
-
- def createReferenceValue(self, targetAddress, targetType):
- if not isinstance(targetType, self.Type):
- raise RuntimeError('Expected type in createReferenceValue(), got %s'
- % type(targetType))
- if not self.isInt(targetAddress):
- raise RuntimeError('Expected integral address value in createReferenceValue(), got %s'
- % type(targetType))
- val = self.Value(self)
- val.ldata = self.toPointerData(targetAddress)
- if self.useDynamicType:
- targetType = targetType.dynamicType(targetAddress)
- val._type = self.createReferenceType(targetType)
- return val
-
- def createPointerType(self, targetType):
- if not isinstance(targetType, (str, self.Type)):
- raise RuntimeError('Expected type or str in createPointerType(), got %s'
- % type(targetType))
- typeId = (targetType if isinstance(targetType, str) else targetType.typeId) + ' *'
- tdata = self.TypeData(self, typeId)
- tdata.name = (targetType if isinstance(targetType, str) else targetType.name) + '*'
- tdata.lbitsize = 8 * self.ptrSize()
- tdata.code = TypeCode.Pointer
- tdata.ltarget = targetType
- return self.Type(self, typeId)
-
- def createReferenceType(self, targetType):
- if not isinstance(targetType, self.Type):
- raise RuntimeError('Expected type in createReferenceType(), got %s'
- % type(targetType))
- typeId = targetType.typeId + ' &'
- tdata = self.TypeData(self, typeId)
- tdata.name = targetType.name + ' &'
- tdata.code = TypeCode.Reference
- tdata.ltarget = targetType
- tdata.lbitsize = 8 * self.ptrSize() # Needed for Gdb13393 test.
- #tdata.lbitsize = None
- return self.Type(self, typeId)
-
- def createRValueReferenceType(self, targetType):
- if not isinstance(targetType, self.Type):
- raise RuntimeError('Expected type in createRValueReferenceType(), got %s'
- % type(targetType))
- typeId = targetType.typeId + ' &&'
- tdata = self.TypeData(self, typeId)
- tdata.name = targetType.name + ' &&'
- tdata.code = TypeCode.RValueReference
- tdata.ltarget = targetType
- tdata.lbitsize = None
- return self.Type(self, typeId)
-
- def createArrayType(self, targetType, count):
- if not isinstance(targetType, self.Type):
- raise RuntimeError('Expected type in createArrayType(), got %s'
- % type(targetType))
- targetTypeId = targetType.typeId
-
- if targetTypeId.endswith(']'):
- (prefix, suffix, inner_count) = self.splitArrayType(targetTypeId)
- type_id = '%s[%d][%d]%s' % (prefix, count, inner_count, suffix)
- type_name = type_id
+ #target_typeid = self.create_typeid(target_typish)
+ #if self.useDynamicType:
+ # target_typeid = self.dynamic_typeid_at_address(target_typeid, target_address)
+ #val.typeid = self.create_pointer_typeid(target_typeid)
+ #return val
+
+ def createPointerType(self, target_typish):
+ typeid = self.create_pointer_typeid(self.typeid_for_typish(target_typish))
+ return self.Type(self, typeid)
+
+ def create_pointer_typeid(self, target_typeid):
+ name = self.type_name(target_typeid) + ' *'
+ typeid = self.typeid_for_string(name)
+ self.type_size_cache[typeid] = self.ptrSize()
+ self.type_alignment_cache[typeid] = self.ptrSize()
+ self.type_code_cache[typeid] = TypeCode.Pointer
+ self.type_target_cache[typeid] = target_typeid
+ return typeid
+
+ def create_reference_typeid(self, target_typeid):
+ type_name = self.type_name_cache[target_typeid] + ' &'
+ typeid = self.typeid_for_string(type_name)
+ self.type_code_cache[typeid] = TypeCode.Reference
+ self.type_target_cache[typeid] = target_typeid
+ #self.type_size_cache[typeid] = self.ptrSize() # Needed for Gdb13393 test.
+ return typeid
+
+ def create_rvalue_reference_typeid(self, target_typeid):
+ type_name = self.type_name_cache[target_typeid] + ' &&'
+ typeid = self.typeid_for_string(type_name)
+ self.type_code_cache[typeid] = TypeCode.RValueReference
+ self.type_target_cache[typeid] = target_typeid
+ return typeid
+
+ def create_array_typeid(self, target_typeid, count):
+ target_type_name = self.type_name(target_typeid)
+ if target_type_name.endswith(']'):
+ (prefix, suffix, inner_count) = self.splitArrayType(target_type_name)
+ type_name = '%s[%d][%d]%s' % (prefix, count, inner_count, suffix)
else:
- type_id = '%s[%d]' % (targetTypeId, count)
- type_name = '%s[%d]' % (targetType.name, count)
-
- tdata = self.TypeData(self, type_id)
- tdata.name = type_name
- tdata.code = TypeCode.Array
- tdata.ltarget = targetType
- tdata.lbitsize = targetType.lbitsize * count
- return self.Type(self, type_id)
-
- def createBitfieldType(self, targetType, bitsize):
- if not isinstance(targetType, self.Type):
- raise RuntimeError('Expected type in createBitfieldType(), got %s'
- % type(targetType))
- typeId = '%s:%d' % (targetType.typeId, bitsize)
- tdata = self.TypeData(self, typeId)
- tdata.name = '%s : %d' % (targetType.typeId, bitsize)
- tdata.code = TypeCode.Bitfield
- tdata.ltarget = targetType
- tdata.lbitsize = bitsize
- return self.Type(self, typeId)
-
- def createTypedefedType(self, targetType, typeName, typeId=None):
- if typeId is None:
- typeId = typeName
- if not isinstance(targetType, self.Type):
- raise RuntimeError('Expected type in createTypedefType(), got %s'
- % type(targetType))
+ type_name = '%s[%d]' % (target_type_name, count)
+ typeid = self.typeid_for_string(type_name)
+ self.type_code_cache[typeid] = TypeCode.Array
+ self.type_target_cache[typeid] = target_typeid
+ self.type_size_cache[typeid] = self.type_size(target_typeid) * count
+ self.type_alignment_cache[typeid] = self.type_alignment_cache.get(target_typeid, None)
+ return typeid
+
+ def create_bitfield_typeid(self, target_typeid, bitsize):
+ target_typename = self.type_name(target_typeid)
+ typeid = self.typeid_for_string('%s:%d' % (target_typename, bitsize))
+ self.type_name_cache[typeid] = '%s : %d' % (target_typename, bitsize)
+ self.type_code_cache[typeid] = TypeCode.Bitfield
+ self.type_target_cache[typeid] = target_typeid
+ self.type_bitsize_cache[typeid] = bitsize
+ return typeid
+
+ def create_typedefed_typeid(self, target_typeid, type_name, type_key):
+ typeid = self.typeid_for_string(type_key, type_name)
# Happens for C-style struct in GDB: typedef { int x; } struct S1;
- if targetType.typeId == typeId:
- return targetType
- tdata = self.TypeData(self, typeId)
- tdata.name = typeName
- tdata.code = TypeCode.Typedef
- tdata.ltarget = targetType
- tdata.lbitsize = targetType.lbitsize
- #tdata.lfields = targetType.lfields
- tdata.lbitsize = targetType.lbitsize
- return self.Type(self, typeId)
-
- def knownArrayTypeSize(self):
- return 3 * self.ptrSize() if self.qtVersion() >= 0x060000 else self.ptrSize()
-
- def knownTypeSize(self, typish):
- if typish[0] == 'Q':
- if typish.startswith('QList<') or typish.startswith('QVector<'):
- return self.knownArrayTypeSize()
- if typish == 'QObject':
- return 2 * self.ptrSize()
- if typish == 'QStandardItemData':
- return 4 * self.ptrSize() if self.qtVersion() >= 0x060000 else 2 * self.ptrSize()
- if typish == 'Qt::ItemDataRole':
- return 4
- if typish == 'QChar':
- return 2
- if typish in ('quint32', 'qint32'):
- return 4
- return None
+ if target_typeid == typeid:
+ return target_typeid
+ self.type_code_cache[typeid] = TypeCode.Typedef
+ self.type_target_cache[typeid] = target_typeid
+ self.type_size_cache[typeid] = self.type_size_cache.get(target_typeid, None)
+ return typeid
def createType(self, typish, size=None):
- if isinstance(typish, self.Type):
- #typish.check()
- if hasattr(typish, 'lbitsize') and typish.lbitsize is not None and typish.lbitsize > 0:
- return typish
- # Size 0 is sometimes reported by GDB but doesn't help at all.
- # Force using the fallback:
- typish = typish.name
+ return self.Type(self, self.create_typeid(typish, size))
+ def create_typeid(self, typish, size=None):
+ if isinstance(typish, int):
+ return typish
+ if isinstance(typish, self.Type):
+ return typish.typeid
if isinstance(typish, str):
- ns = self.qtNamespace()
- typish = typish.replace('@', ns)
- if typish.startswith(ns):
- if size is None:
- size = self.knownTypeSize(typish[len(ns):])
- else:
- if size is None:
- size = self.knownTypeSize(typish)
- if size is not None:
- typish = ns + typish
-
- tdata = self.typeData.get(typish, None)
- if tdata is not None:
- if tdata.lbitsize is not None:
- if callable(tdata.lbitsize) or tdata.lbitsize > 0:
- return self.Type(self, typish)
-
- knownType = self.lookupType(typish)
- #DumperBase.warn('KNOWN: %s' % knownType)
- if knownType is not None:
- #DumperBase.warn('USE FROM NATIVE')
- return knownType
-
- #DumperBase.warn('FAKING: %s SIZE: %s' % (typish, size))
- tdata = self.TypeData(self, typish)
- tdata.templateArguments = lambda: self.listTemplateParameters(typish)
- if size is not None:
- tdata.lbitsize = 8 * size
- if typish.endswith('*'):
- tdata.code = TypeCode.Pointer
- tdata.lbitsize = 8 * self.ptrSize()
- tdata.ltarget = typish[:-1].strip()
-
- typeobj = self.Type(self, tdata.typeId)
- #DumperBase.warn('CREATE TYPE: %s' % typeobj.stringify())
- typeobj.check()
- return typeobj
+ return self.create_typeid_from_name(typish)
raise RuntimeError('NEED TYPE, NOT %s' % type(typish))
- def createValueFromAddressAndType(self, address, typish):
+ def cheap_typeid_from_name(self, typename_):
+ ns = self.qtNamespace()
+ typename = typename_.replace('@', ns)
+ return self.cheap_typeid_from_name_nons(typename)
+
+ def cheap_typeid_from_name_nons(self, typename):
+ if typename in self.typeid_cache:
+ return self.typeid_for_string(typename)
+
+ if typename.startswith('QList<') or typename.startswith('QVector<'):
+ typeid = self.typeid_for_string(typename)
+ if typeid:
+ size = 3 * self.ptrSize() if self.qtVersion() >= 0x060000 else self.ptrSize()
+ self.type_code_cache[typeid] = TypeCode.Struct
+ self.type_size_cache[typeid] = size
+ return typeid
+
+ if typename.endswith('*'):
+ inner_typeid = self.cheap_typeid_from_name_nons(typename[0:-1])
+ if inner_typeid != 0:
+ return self.create_pointer_typeid(inner_typeid)
+
+ return 0
+
+ def create_typeid_from_name(self, typename_, size=None):
+ ns = self.qtNamespace()
+ typename = typename_.replace('@', ns)
+
+ if typename in self.typeid_cache:
+ return self.typeid_for_string(typename)
+
+ # This triggers for boost::variant<int, std::string> due to the mis-encoding
+ # of the second template parameter. [MARK_A]
+ knownType = self.lookupType(typename)
+ #self.warn('KNOWN: %s FOR %s' % (knownType, typename))
+ if knownType is not None:
+ #self.warn('USE FROM NATIVE')
+ #self.dump_location()
+ return knownType.typeid
+
+ #self.warn('FAKING: %s SIZE: %s' % (typename, size))
+ typeid = self.typeid_for_string(typename)
+ if size is not None:
+ self.type_size_cache[typeid] = size
+ self.type_code_cache[typeid] = TypeCode.Struct
+ if typename.endswith('*'):
+ self.type_code_cache[typeid] = TypeCode.Pointer
+ self.type_size_cache[typeid] = self.ptrSize()
+ self.type_target_cache[typeid] = self.typeid_for_string(typename[:-1].strip())
+
+ #self.dump_location()
+ #self.warn('CREATED TYPE: %s' % typeid)
+ return typeid
+
+ def createValueFromAddress(self, address, typish):
val = self.Value(self)
- val._type = self.createType(typish)
- #DumperBase.warn('CREATING %s AT 0x%x' % (val.type.name, datish))
+ val.typeid = self.create_typeid(typish)
+ #self.warn('CREATING %s AT 0x%x' % (val.type.name, address))
val.laddress = address
if self.useDynamicType:
- val._type = val.type.dynamicType(address)
+ val.typeid = self.dynamic_typeid_at_address(val.typeid, address)
+ return val
+
+ def createValueFromData(self, data, typish):
+ val = self.Value(self)
+ val.typeid = self.create_typeid(typish)
+ #self.warn('CREATING %s WITH DATA %s' % (val.type.name, self.hexencode(data)))
+ val.ldata = data
+ val.check()
return val
def createValue(self, datish, typish):
- if self.isInt(datish): # Used as address.
- return self.createValueFromAddressAndType(datish, typish)
+ if isinstance(datish, int): # Used as address.
+ return self.createValueFromAddress(datish, typish)
if isinstance(datish, bytes):
- val = self.Value(self)
- val._type = self.createType(typish)
- #DumperBase.warn('CREATING %s WITH DATA %s' % (val.type.name, self.hexencode(datish)))
- val.ldata = datish
- val.check()
- return val
+ return self.createValueFromData(datish, typish)
raise RuntimeError('EXPECTING ADDRESS OR BYTES, GOT %s' % type(datish))
def createProxyValue(self, proxy_data, type_name):
- tdata = self.TypeData(self, type_name)
- tdata.code = TypeCode.Struct
+ typeid = self.typeid_for_string(type_name)
+ self.type_code_cache[typeid] = TypeCode.Struct
val = self.Value(self)
- val._type = self.Type(self, type_name)
+ val.typeid = typeid
val.ldata = proxy_data
return val
@@ -4013,109 +3605,667 @@ class DumperBase():
def __init__(self, dumper):
self.dumper = dumper
self.pattern = ''
- self.currentBitsize = 0
+ self.current_size = 0
self.fields = []
self.autoPadNext = False
self.maxAlign = 1
- def addField(self, fieldSize, fieldCode=None, fieldIsStruct=False,
- fieldName=None, fieldType=None, fieldAlign=1):
+ def add_field(self, field_size, field_code=None, field_is_struct=False,
+ field_name=None, field_typeid=0, field_align=1):
+
+ if field_code is None:
+ field_code = '%ss' % field_size
- if fieldType is not None:
- fieldType = self.dumper.createType(fieldType)
- if fieldSize is None and fieldType is not None:
- fieldSize = fieldType.size()
- if fieldCode is None:
- fieldCode = '%ss' % fieldSize
+ #self.dumper.warn("FIELD SIZE: %s %s %s " % (field_name, field_size, str(field_align)))
if self.autoPadNext:
- self.currentBitsize = 8 * ((self.currentBitsize + 7) >> 3) # Fill up byte.
- padding = (fieldAlign - (self.currentBitsize >> 3)) % fieldAlign
- #DumperBase.warn('AUTO PADDING AT %s BITS BY %s BYTES' % (self.currentBitsize, padding))
- field = self.dumper.Field(self.dumper, bitpos=self.currentBitsize,
+ padding = (field_align - self.current_size) % field_align
+ #self.warn('AUTO PADDING AT %s BITS BY %s BYTES' % (self.current_size, padding))
+ field = self.dumper.Field(self.dumper, bitpos=self.current_size * 8,
bitsize=padding * 8)
self.pattern += '%ds' % padding
- self.currentBitsize += padding * 8
+ self.current_size += padding
self.fields.append(field)
self.autoPadNext = False
- if fieldAlign > self.maxAlign:
- self.maxAlign = fieldAlign
- #DumperBase.warn("MAX ALIGN: %s" % self.maxAlign)
+ if field_align > self.maxAlign:
+ self.maxAlign = field_align
- field = self.dumper.Field(dumper=self.dumper, name=fieldName, type=fieldType,
- isStruct=fieldIsStruct, bitpos=self.currentBitsize,
- bitsize=fieldSize * 8)
+ #self.warn("MAX ALIGN: %s" % self.maxAlign)
- self.pattern += fieldCode
- self.currentBitsize += fieldSize * 8
+ field = self.dumper.Field(name=field_name, typeid=field_typeid,
+ is_struct=field_is_struct, bitpos=self.current_size *8,
+ bitsize=field_size * 8)
+
+ self.pattern += field_code
+ self.current_size += field_size
self.fields.append(field)
+ def describe_struct_member(self, typename):
+ typename = typename.replace('@', self.qtNamespace())
+
+ typeid = self.cheap_typeid_from_name_nons(typename)
+ if typeid:
+ size = self.type_size_cache.get(typeid, None)
+ if size is not None:
+ return size, typeid
+
+ typeobj = self.lookupType(typename)
+ self.warn("LOOKUP FIELD TYPE: %s TYPEOBJ: %s" % (typename, typeobj))
+ if typeobj is not None:
+ typeid = typeobj.typeid
+ size = self.type_size_cache.get(typeid, None)
+ if size is not None:
+ return size, typeid
+
+ self.warn("UNKNOWN EMBEDDED TYPE: %s" % typename)
+ return 0, 0
+
+ @functools.lru_cache(maxsize = None)
def describeStruct(self, pattern):
- if pattern in self.structPatternCache:
- return self.structPatternCache[pattern]
ptrSize = self.ptrSize()
builder = self.StructBuilder(self)
n = None
- typeName = ''
+ typename = ''
readingTypeName = False
+ #self.warn("PATTERN: %s" % pattern)
for c in pattern:
+ #self.warn("PAT CODE: %s %s" % (c, str(n)))
if readingTypeName:
if c == '}':
readingTypeName = False
- fieldType = self.createType(typeName)
- fieldAlign = fieldType.alignment()
- builder.addField(n, fieldIsStruct=True,
- fieldType=fieldType, fieldAlign=fieldAlign)
- typeName = None
+ n, field_typeid = self.describe_struct_member(typename)
+
+ field_align = self.type_alignment(field_typeid)
+ builder.add_field(n,
+ field_is_struct=True,
+ field_typeid=field_typeid,
+ field_align=field_align)
+ typename = None
n = None
else:
- typeName += c
+ typename += c
elif c == 't': # size_t
- builder.addField(ptrSize, self.ptrCode(), fieldAlign=ptrSize)
+ builder.add_field(ptrSize, self.ptrCode(), field_align=ptrSize)
elif c == 'p': # Pointer as int
- builder.addField(ptrSize, self.ptrCode(), fieldAlign=ptrSize)
+ builder.add_field(ptrSize, self.ptrCode(), field_align=ptrSize)
elif c == 'P': # Pointer as Value
- builder.addField(ptrSize, '%ss' % ptrSize, fieldAlign=ptrSize)
+ builder.add_field(ptrSize, '%ss' % ptrSize, field_align=ptrSize)
elif c in ('d'):
- builder.addField(8, c, fieldAlign=ptrSize) # fieldType = 'double' ?
+ builder.add_field(8, c, field_align=ptrSize) # field_type = 'double' ?
elif c in ('q', 'Q'):
- builder.addField(8, c, fieldAlign=ptrSize)
+ builder.add_field(8, c, field_align=ptrSize)
elif c in ('i', 'I', 'f'):
- builder.addField(4, c, fieldAlign=4)
+ builder.add_field(4, c, field_align=4)
elif c in ('h', 'H'):
- builder.addField(2, c, fieldAlign=2)
+ builder.add_field(2, c, field_align=2)
elif c in ('b', 'B', 'c'):
- builder.addField(1, c, fieldAlign=1)
+ builder.add_field(1, c, field_align=1)
elif c >= '0' and c <= '9':
if n is None:
n = ''
n += c
elif c == 's':
- builder.addField(int(n), fieldAlign=1)
+ builder.add_field(int(n), field_align=1)
n = None
elif c == '{':
readingTypeName = True
- typeName = ''
+ typename = ''
elif c == '@':
if n is None:
# Automatic padding depending on next item
builder.autoPadNext = True
else:
# Explicit padding.
- builder.currentBitsize = 8 * ((builder.currentBitsize + 7) >> 3)
- padding = (int(n) - (builder.currentBitsize >> 3)) % int(n)
+ padding = (int(n) - builder.current_size) % int(n)
field = self.Field(self)
builder.pattern += '%ds' % padding
- builder.currentBitsize += padding * 8
+ builder.current_size += padding
builder.fields.append(field)
n = None
else:
raise RuntimeError('UNKNOWN STRUCT CODE: %s' % c)
pp = builder.pattern
- size = (builder.currentBitsize + 7) >> 3
+ size = builder.current_size
fields = builder.fields
tailPad = (builder.maxAlign - size) % builder.maxAlign
size += tailPad
- self.structPatternCache[pattern] = (pp, size, fields)
+ #self.warn("FIELDS: %s" % ((pp, size, fields),))
return (pp, size, fields)
+
+ def type_stringify(self, typeid):
+ return 'Type(id="%s",name="%s",bsize=%s,code=%s)'% (
+ str(typeid),
+ self.type_name_cache.get(typeid, '?'),
+ self.type_bitsize_cache.get(typeid, '?'),
+ self.type_code_cache.get(typeid, '?'))
+
+ def type_name(self, typeid):
+ name = self.type_name_cache.get(typeid, None)
+ if name is None:
+ self.dump_type_cache()
+ self.check_typeid(typeid)
+ raise RuntimeError('UNNAMED TYPE: %d' % typeid)
+ return name
+
+ def type_code(self, typeid):
+ # This does not seem to be needed for GDB and LLDB
+ if not typeid in self.type_code_cache:
+ typename = self.type_name_cache.get(typeid, None)
+ if typename is None:
+ raise RuntimeError('NAME/ID ERROR FOR %s' % typeid)
+ #self.warn("EMERGENCY LOOKUP: %s " % typename)
+ typeobj = self.lookupType(typename)
+ if typeobj is None:
+ #self.warn("EMERGENCY LOOKUP FAILED: %s " % typeid)
+ #self.dump_type_cache()
+ return TypeCode.Struct
+ #self.warn("EMERGENCY LOOKUP SUCCEEDED: %s " % typeid)
+ typeid = typeobj.typeid
+ return self.type_code_cache[typeid]
+
+ def type_bitpos(self, typeid):
+ return self.type_bitpos_cache[typeid]
+
+ def type_target(self, typeid):
+ return self.type_target_cache.get(typeid, None)
+ targetid = self.type_target_cache.get(typeid, None)
+ if not targetid in self.type_code_cache:
+ typename = self.type_name_cache.get(targetid, None)
+ if typename is None:
+ raise RuntimeError('NAME/ID ERROR FOR TARGET %s' % targetid)
+ typeobj = self.lookupType(typename)
+ if typeobj is None:
+ #self.warn("EMERGENCY LOOKUP FAILED FOR %s %s " % (typename, typeid))
+ #self.dump_type_cache()
+ return 0 # Void type id
+ return targetid
+
+ def type_template_arguments(self, typeid):
+ targs = []
+ #self.dump_type_cache()
+ #self.warn('TRY TEMPLATE ARGS FOR %s' % typeid)
+ for index in range(0, 100):
+ targ = self.type_template_argument(typeid, index)
+ #self.warn('INDEX %s %s' % (index, targ))
+ if targ is None:
+ break
+ targs.append(targ)
+ #self.warn('TARGS %s' % targs)
+ return targs
+
+ def nativeTemplateParameter(self, typeid, index, nativeType):
+ return None
+
+ def type_template_argument(self, typeid, index):
+ targ = self.type_template_arguments_cache.get((typeid, index), None)
+ if targ is not None:
+ return targ
+
+ native_type = self.type_nativetype_cache.get(typeid, None)
+ if native_type is not None:
+ targ = self.nativeTemplateParameter(typeid, index, native_type)
+ if targ is not None:
+ self.type_template_arguments_cache[(typeid, index)] = targ
+ return targ
+
+ # FIXME: The block below is apparently not needed anymore in the GDB
+ # and LLDB cases, so removing also doesn't bring performance. But it
+ # is at least potentially one source of type lookups.
+ #typename = self.type_name(typeid)
+ #self.dump_type_cache()
+ #self.warn('TEMPLATE ARGS FOR %s %s' % (typeid, typename))
+ #typeobj = self.lookupType(typename)
+ #if typeobj is not None:
+ # #self.warn(' FOUNT NATIVE %s %s, %s' % (typeid, typeobj, native_type))
+ # native_type = self.type_nativetype_cache.get(typeobj.typeid, None)
+ # #targ = self.type_template_argument(typeobj.typeid, index)
+ # targ = self.nativeTemplateParameter(typeobj.typeid, index, native_type)
+ # if targ is not None:
+ # self.type_template_arguments_cache[(typeid, index)] = targ
+ # return targ
+
+ # Native lookups didn't help. Happens for 'wrong' placement of 'const'
+ # etc. with LLDB or template parameter packs with gcc in boost::variant
+ # 13.2.0. But not all is lost:
+ self.fill_template_parameters_manually(typeid)
+ targ = self.type_template_arguments_cache.get((typeid, index), None)
+ return targ
+
+ def type_alignment(self, typeid):
+ alignment = self.type_alignment_cache.get(typeid, None)
+ if alignment is not None:
+ return alignment
+
+ code = self.type_code_cache.get(typeid, None)
+ if code in (TypeCode.Typedef, TypeCode.Array):
+ alignment = self.type_alignment(self.type_target_cache[typeid])
+ elif code in (TypeCode.Integral, TypeCode.Float, TypeCode.Enum):
+ name = self.type_name(typeid)
+ if name in ('double', 'long long', 'unsigned long long'):
+ # Crude approximation.
+ alignment = 8 if self.isWindowsTarget() else self.ptrSize()
+ else:
+ alignment = self.type_size(typeid)
+ elif code in (TypeCode.Pointer, TypeCode.Reference, TypeCode.RValueReference):
+ alignment = self.ptrSize()
+ elif self.isCdb:
+ alignment = self.nativeStructAlignment(self.type_nativetype(typeid))
+ else:
+ size = self.type_size(typeid)
+ if size is None:
+ self.dump_type_cache()
+ self.warn("NO ALIGNMENT FOUND FOR SIZE OF TYPE %s" % str(typeid))
+ return 1
+ if size >= self.ptrSize():
+ alignment = self.ptrSize()
+ else:
+ alignment = size
+ #self.warn("GUESSING ALIGNMENT %s FOR TYPEID %s" % (alignment, typeid))
+ self.type_alignment_cache[typeid] = alignment
+ return alignment
+
+
+ def type_nativetype(self, typeid):
+ native_type = self.type_nativetype_cache.get(typeid, None)
+ if native_type is not None:
+ return native_type
+
+ typename = self.type_name(typeid)
+ native_type = self.lookupNativeType(typename)
+ # Also cache unsuccessful attempts
+ self.type_nativetype_cache[typeid] = native_type
+
+ return native_type
+
+
+ def type_size(self, typeid):
+ self.check_typeid(typeid)
+ size = self.type_size_cache.get(typeid, None)
+ if size is not None:
+ return size
+
+ if size is None:
+ nativeType = self.type_nativetype(typeid)
+ if not self.type_size_cache.get(typeid):
+ self.from_native_type(nativeType)
+ size = self.type_size_cache.get(typeid, None)
+
+ if size is not None:
+ self.type_size_cache[typeid] = size
+ else:
+ self.dump_type_cache()
+ self.warn("CANNOT DETERMINE SIZE FOR TYPE %s" % str(typeid))
+
+ return size
+
+ def type_bitsize(self, typeid):
+ bitsize = self.type_bitsize_cache.get(typeid, None)
+ if bitsize is None:
+ bitsize = 8 * self.type_size(typeid)
+ self.type_bitsize_cache[typeid] = bitsize
+ return bitsize
+
+ def dynamic_typeid_at_address(self, base_typeid, address):
+ #with self.dumper.timer('dynamic_typeid_at_address %s 0x%s' % (self.name, address)):
+ type_code = self.type_code_cache.get(base_typeid, None)
+ if type_code != TypeCode.Struct:
+ #self.dump_type_cache()
+ #self.warn('SHORT CUT FOR BASE ID: %d TC: %s' % (base_typeid, type_code))
+ return base_typeid
+
+ # This turned out to be expensive.
+ #try:
+ # vtbl = self.extract_pointer_at_address(address)
+ #except:
+ # return base_typeid
+ ##self.warn('VTBL: 0x%x' % vtbl)
+ #if not self.couldBePointer(vtbl):
+ # return base_typeid
+ #self.warn("DYN TYPE FOR %s %s" % (base_typeid, self.type_name(base_typeid)))
+
+ return self.nativeDynamicType(address, base_typeid)
+
+ # This is the generic version for synthetic values.
+ # The native backends replace it in their fromNativeValue()
+ # implementations.
+ def value_members(self, value, include_bases):
+ #self.warn("LISTING MEMBERS OF %s" % value)
+ #self.warn("LISTING MEMBERS OF TYPE %s %s" % (value.typeid, self.type_name(value.typeid)))
+ typeid = value.typeid
+
+ members = self.type_fields_cache.get(typeid, None)
+ if members is not None:
+ return members
+
+ members = []
+ native_type = self.type_nativetype_cache.get(typeid, None)
+ if native_type is None:
+ native_type = self.lookupNativeType(self.type_name(typeid))
+ if not native_type is None:
+ members = self.nativeListMembers(value, native_type, include_bases)
+ #self.warn("FIELDS 2: %s" % ', '.join(str(f) for f in members))
+ else:
+ self.warn("NO NATIVE TYPE FIELDS FOR: %s" % typeid)
+
+ #self.warn("GOT MEMBERS: %s" % ', '.join(str(f.name) for f in members))
+ return members
+
+ def value_member_by_field(self, value, field):
+ #self.warn("EXTRACTING MEMBER '%s' OF %s AT OFFSET %s" % (field.name, field.typeid, field.bitpos))
+ val = self.Value(self)
+ val.typeid = field.typeid
+ val.name = field.name
+ val.isBaseClass = field.is_base_class
+ #self.warn('CREATING %s WITH DATA %s' % (val.type.name, self.hexencode(data)))
+ field_offset = field.bitpos // 8
+ if value.laddress is not None:
+ val.laddress = value.laddress + field_offset
+ field_size = (field.bitsize + 7) // 8
+ blob = self.value_data(value, field_offset + field_size)
+ val.ldata = blob[field_offset:field_offset + field_size]
+ #self.dump_location()
+ return val
+
+ def value_member_by_name(self, value, name):
+ #field = self.type_fields_cache.get((value.typeid, name), None)
+ #if field is not None:
+ # return self.value_member_by_field(value, field)
+
+ #self.dump_location()
+ #self.warn("WANT MEMBER '%s' OF '%s'" % (name, value))
+ #value.check()
+ value_typecode = self.type_code(value.typeid)
+ if value_typecode == TypeCode.Typedef:
+ return self.value_member_by_name(self.value_detypedef(value), name)
+ if value_typecode in (TypeCode.Pointer, TypeCode.Reference, TypeCode.RValueReference):
+ res = self.value_member_by_name(self.value_dereference(value), name)
+ if res is not None:
+ return res
+ if value_typecode == TypeCode.Struct:
+ #self.warn('SEARCHING FOR MEMBER: %s IN %s' % (name, value.type.name))
+ members = self.value_members(value, True)
+ #self.warn('MEMBERS: %s' % ', '.join(str(m.name) for m in members))
+ base = None
+ for member in members:
+ #self.warn('CHECKING FIELD %s' % member.name)
+ if member.type.code == TypeCode.Typedef:
+ member = member.detypedef()
+ if member.name == name:
+ #self.warn('FOUND MEMBER 1: %s IN %s' % (name, value.type.name))
+ return member
+ if member.isBaseClass:
+ base = member
+ if self.isCdb:
+ if base is not None:
+ # self.warn("CHECKING BASE CLASS '%s' for '%s'" % (base.type.name, name))
+ res = self.value_member_by_name(base, name)
+ if res is not None:
+ # self.warn('FOUND MEMBER 2: %s IN %s' % (name, value.type.name))
+ return res
+ else:
+ for member in members:
+ if member.type.code == TypeCode.Typedef:
+ member = member.detypedef()
+ if member.name == name: # Could be base class.
+ return member
+ if member.type.code == TypeCode.Struct:
+ res = self.value_member_by_name(member, name)
+ if res is not None:
+ #self.warn('FOUND MEMBER 2: %s IN %s' % (name, value.type.name))
+ return res
+
+ #self.warn('DID NOT FIND MEMBER: %s IN %s' % (name, value.type.name))
+ #self.dump_location()
+ return None
+
+ def value_member_by_indexish(self, value, indexish):
+ #self.warn('GET ITEM %s %s' % (self, indexish))
+ #value.check()
+ value_typecode = self.type_code(value.typeid)
+ if isinstance(indexish, str):
+ if value_typecode == TypeCode.Pointer:
+ #self.warn('GET ITEM %s DEREFERENCE TO %s' % (value, value.dereference()))
+ return value.dereference().__getitem__(indexish)
+ res = self.value_member_by_name(value, indexish)
+ if res is None:
+ raise RuntimeError('No member named %s in type %s'
+ % (indexish, value.type.name))
+ return res
+ if isinstance(indexish, int):
+ if value_typecode == TypeCode.Array:
+ addr = value.laddress + int(indexish) * value.type.target().size()
+ return self.createValueFromAddress(addr, value.type.target())
+ if value_typecode == TypeCode.Pointer:
+ addr = value.pointer() + int(indexish) * value.type.target().size()
+ return self.createValueFromAddress(addr, value.type.target())
+ return self.value_members(value, False)[indexish]
+ raise RuntimeError('BAD INDEX TYPE %s' % type(indexish))
+
+ def value_extract_bits(self, value, bitpos, bitsize):
+ value_size = self.type_size(value.typeid)
+ ldata = bytes(self.value_data(value, value_size))
+ bdata = ''.join([format(x, '0>8b')[::-1] for x in ldata])
+ fdata = bdata[bitpos : bitpos + bitsize]
+ fdata = fdata[::-1]
+ return int(fdata, 2)
+
+ def value_display_enum(self, value, form='%d', bitsize=None):
+ size = value.type.size()
+ intval = self.value_extract_integer(value, size, False)
+ dd = self.type_enum_display_cache.get(value.typeid, None)
+ if dd is None:
+ return str(intval)
+ return dd(intval, value.laddress, form)
+
+ def value_as_address(self, value):
+ return self.value_extract_integer(value, self.ptrSize(), False)
+
+ def value_as_integer(self, value):
+ if isinstance(value.ldata, int):
+ return value.ldata
+ type_name = self.type_name(value.typeid)
+ signed = type_name != 'unsigned' \
+ and not type_name.startswith('unsigned ') \
+ and type_name.find(' unsigned ') == -1
+ size = value.type.size()
+ return self.value_extract_integer(value, size, signed)
+
+ def value_as_floating_point(self, value):
+ if value.nativeValue is not None and not self.isCdb:
+ return str(value.nativeValue)
+ if self.type_code(value.typeid) == TypeCode.Typedef:
+ return self.value_as_floating_point(self.value_detypedef(value))
+ if value.type.size() == 8:
+ blob = self.value_data(value, 8)
+ return struct.unpack_from(self.packCode + 'd', blob, 0)[0]
+ if value.type.size() == 4:
+ blob = self.value_data(value, 4)
+ return struct.unpack_from(self.packCode + 'f', blob, 0)[0]
+ # Fall back in case we don't have a nativeValue at hand.
+ # FIXME: This assumes Intel's 80bit extended floats. Which might
+ # be wrong.
+ l, h = value.split('QQ')
+ if True: # 80 bit floats
+ sign = (h >> 15) & 1
+ exp = (h & 0x7fff)
+ fraction = l
+ bit63 = (l >> 63) & 1
+ #self.warn("SIGN: %s EXP: %s H: 0x%x L: 0x%x" % (sign, exp, h, l))
+ if exp == 0:
+ if bit63 == 0:
+ if l == 0:
+ res = '-0' if sign else '0'
+ else:
+ res = (-1)**sign * l * 2**(-16382) # subnormal
+ else:
+ res = 'pseudodenormal'
+ elif exp == 0x7fff:
+ res = 'special'
+ else:
+ res = (-1)**sign * l * 2**(exp - 16383 - 63)
+ else: # 128 bits
+ sign = h >> 63
+ exp = (h >> 48) & 0x7fff
+ fraction = h & (2**48 - 1)
+ #self.warn("SIGN: %s EXP: %s FRAC: %s H: 0x%x L: 0x%x" % (sign, exp, fraction, h, l))
+ if exp == 0:
+ if fraction == 0:
+ res = -0.0 if sign else 0.0
+ else:
+ res = (-1)**sign * fraction / 2**48 * 2**(-62) # subnormal
+ elif exp == 0x7fff:
+ res = ('-inf' if sign else 'inf') if fraction == 0 else 'nan'
+ else:
+ res = (-1)**sign * (1 + fraction / 2**48) * 2**(exp - 63)
+ return res
+
+ def value_data(self, value, size):
+ if value.ldata is not None:
+ return value.ldata[:size]
+ if value.laddress is not None:
+ return self.value_data_from_address(value.laddress, size)
+ raise RuntimeError('CANNOT CONVERT TO BYTES: %s' % value)
+
+ def value_data_from_address(self, address, size):
+ if not isinstance(address, int):
+ raise RuntimeError('ADDRESS WRONG TYPE: %s' % type(address))
+ if not isinstance(size, int):
+ raise RuntimeError('SIZE WRONG TYPE: %s' % type(size))
+ if size <= 0:
+ raise RuntimeError('SIZE WRONG VALUE: %s' % size)
+ res = self.readRawMemory(address, size)
+ if len(res) > 0:
+ return res
+ raise RuntimeError('CANNOT READ %d BYTES FROM ADDRESS: %s %s' % (size, address))
+
+ def value_display(self, value):
+ type_code = self.type_code(value.typeid)
+ if type_code == TypeCode.Enum:
+ return self.value_display_enum(value)
+ if type_code == TypeCode.Typedef:
+ return self.value_display(self.value_detypedef(value))
+ if type_code == TypeCode.Integral:
+ return self.value_as_integer(value)
+ if type_code == TypeCode.Bitfield:
+ return self.value_as_integer(value)
+ if type_code == TypeCode.Float:
+ return self.value_as_floating_point(value)
+ if type_code == TypeCode.Pointer:
+ return self.value_as_address(value)
+ return None
+
+ def value_detypedef(self, value):
+ #value.check()
+ #if value.type.code != TypeCode.Typedef:
+ # raise RuntimeError("WRONG")
+ val = value.copy()
+ val.typeid = self.type_target(value.typeid)
+ #self.warn("DETYPEDEF FROM: %s" % self)
+ #self.warn("DETYPEDEF TO: %s" % val)
+ return val
+
+ def split(self, pattern, value_or_address):
+ if isinstance(value_or_address, self.Value):
+ return self.value_split(value_or_address, pattern)
+ if isinstance(value_or_address, int):
+ val = self.Value(self)
+ val.laddress = value_or_address
+ return self.value_split(val, pattern)
+ raise RuntimeError('CANNOT EXTRACT STRUCT FROM %s' % type(value_or_address))
+
+ def value_split(self, value, pattern):
+ #self.warn('EXTRACT STRUCT FROM: %s' % self.type)
+ (pp, size, fields) = self.describeStruct(pattern)
+ #self.warn('SIZE: %s ' % size)
+
+ blob = self.value_data(value, size)
+ address = value.laddress
+
+ parts = struct.unpack_from(self.packCode + pp, blob)
+
+ def fix_struct(field, part):
+ #self.warn('STRUCT MEMBER: %s' % type(part))
+ if field.is_struct:
+ res = self.Value(self)
+ res.typeid = field.typeid
+ res.ldata = part
+ if address is not None:
+ res.laddress = address + field.bitpos // 8
+ return res
+ return part
+
+ if len(fields) != len(parts):
+ raise RuntimeError('STRUCT ERROR: %s %s' % (fields, parts))
+ return tuple(map(fix_struct, fields, parts))
+
+ def type_dereference(self, typeid):
+ if self.type_code(typeid) == TypeCode.Typedef:
+ return self.type_dereference(self.type_target(typeid))
+ return self.type_target(typeid)
+
+ def type_strip_typedefs(self, typeid):
+ if self.type_code(typeid) == TypeCode.Typedef:
+ return self.type_strip_typedefs(self.type_target(typeid))
+ return typeid
+
+ def value_dereference(self, value):
+ value.check()
+ #if value.type.code == TypeCode.Typedef:
+ # return self.value_dereference(self.value_detypedef(value))
+ val = self.Value(self)
+ if value.type.code in (TypeCode.Reference, TypeCode.RValueReference):
+ val.summary = value.summary
+ if value.nativeValue is None:
+ val.laddress = value.pointer()
+ if val.laddress is None and value.laddress is not None:
+ val.laddress = value.laddress
+ val.typeid = self.type_dereference(value.typeid)
+ if self.useDynamicType:
+ val.typeid = self.nativeDynamicType(val.laddress, val.typeid)
+ else:
+ val = self.nativeValueDereferenceReference(value)
+ elif value.type.code == TypeCode.Pointer:
+ try:
+ val = self.nativeValueDereferencePointer(value)
+ except:
+ val.laddress = value.pointer()
+ val.typeid = self.type_dereference(value.typeid)
+ if self.useDynamicType:
+ val.typeid = self.nativeDynamicType(val.laddress, val.typeid)
+ else:
+ raise RuntimeError("WRONG: %s" % value.type.code)
+
+ return val
+
+ def value_cast(self, value, typish):
+ value.check()
+ val = self.Value(self)
+ val.laddress = value.laddress
+ val.ldata = value.ldata
+ val.typeid = self.create_typeid(typish)
+ return val
+
+ def value_plus_something(self, value, other):
+ value.check()
+ if isinstance(other, int):
+ stripped = self.type_strip_typedefs(value.typeid)
+ if self.type_code(stripped) == TypeCode.Pointer:
+ item_size = self.type_size(self.type_dereference(stripped))
+ address = self.value_as_address(value) + item_size * other
+ val = self.Value(self)
+ val.laddress = None
+ val.ldata = address
+ val.typeid = value.typeid
+ return val
+ raise RuntimeError('BAD DATA TO ADD TO: %s %s' % (value.type, other))
+
+ def value_minus_something(self, value, other):
+ value.check()
+ if other.type.name == value.type.name:
+ stripped = self.type_strip_typedefs(value.typeid)
+ if self.type_code(stripped.code) == TypeCode.Pointer:
+ item_size = self.type_size(self.type_dereference(stripped))
+ return (value.pointer() - other.pointer()) // item_size
+ raise RuntimeError('BAD DATA TO SUB TO: %s %s' % (value.type, other))
+
diff --git a/share/qtcreator/debugger/gdbbridge.py b/share/qtcreator/debugger/gdbbridge.py
index 9699e518fe..f30b0fbafa 100644
--- a/share/qtcreator/debugger/gdbbridge.py
+++ b/share/qtcreator/debugger/gdbbridge.py
@@ -10,11 +10,10 @@ import gdb
import os
import os.path
import re
-import sys
import struct
import tempfile
-from dumper import DumperBase, Children, toInteger, TopLevelItem
+from dumper import DumperBase, Children, TopLevelItem
from utils import TypeCode
from gdbtracepoint import *
@@ -119,7 +118,6 @@ ScanStackCommand()
class PlainDumper():
def __init__(self, printer):
self.printer = printer
- self.typeCache = {}
def __call__(self, d, value):
if value.nativeValue is None:
@@ -137,8 +135,6 @@ class PlainDumper():
if isinstance(val, str):
# encode and avoid extra quotes ('"') at beginning and end
d.putValue(d.hexencode(val), 'utf8:1:0')
- elif sys.version_info[0] <= 2 and isinstance(val, unicode):
- d.putValue(val)
elif val is not None: # Assuming LazyString
d.putCharArrayValue(val.address, val.length,
val.type.target().sizeof)
@@ -166,7 +162,7 @@ def importPlainDumpers(args):
gdb.execute('disable pretty-printer .* .*')
except:
# Might occur in non-ASCII directories
- DumperBase.warn('COULD NOT DISABLE PRETTY PRINTERS')
+ theDumper.warn('COULD NOT DISABLE PRETTY PRINTERS')
else:
theDumper.usePlainDumpers = True
theDumper.importPlainDumpers()
@@ -192,15 +188,17 @@ class Dumper(DumperBase):
# These values will be kept between calls to 'fetchVariables'.
self.isGdb = True
- self.typeCache = {}
self.interpreterBreakpointResolvers = []
+ def warn(self, message):
+ print('bridgemessage={msg="%s"},' % message.replace('"', '$').encode('latin1'))
+
def prepare(self, args):
self.output = []
self.setVariableFetchingOptions(args)
def fromFrameValue(self, nativeValue):
- #DumperBase.warn('FROM FRAME VALUE: %s' % nativeValue.address)
+ #self.warn('FROM FRAME VALUE: %s' % nativeValue.address)
val = nativeValue
if self.useDynamicType:
try:
@@ -209,71 +207,43 @@ class Dumper(DumperBase):
pass
return self.fromNativeValue(val)
- def nativeValueType(self, nativeValue):
- return self.fromNativeType(nativeValue.type)
-
def fromNativeValue(self, nativeValue):
- #DumperBase.warn('FROM NATIVE VALUE: %s' % nativeValue)
+ #self.warn('FROM NATIVE VALUE: %s' % nativeValue)
self.check(isinstance(nativeValue, gdb.Value))
nativeType = nativeValue.type
code = nativeType.code
+
+ val = self.Value(self)
+ val.nativeValue = nativeValue
+
if code == gdb.TYPE_CODE_REF:
- targetType = self.fromNativeType(nativeType.target().unqualified())
- val = self.createReferenceValue(toInteger(nativeValue.address), targetType)
- val.nativeValue = nativeValue
- #DumperBase.warn('CREATED REF: %s' % val)
+ target_typeid = self.from_native_type(nativeType.target().unqualified())
+ val.ldata = int(nativeValue.address)
+ if self.useDynamicType: # needed for Gdb13393
+ target_typeid = self.dynamic_typeid_at_address(target_typeid, val.ldata)
+ val.typeid = self.create_reference_typeid(target_typeid)
+ #self.warn('CREATED REF: %s' % val)
return val
+
if code == gdb.TYPE_CODE_PTR:
- try:
- nativeTargetValue = nativeValue.dereference()
- except:
- nativeTargetValue = None
- targetType = self.fromNativeType(nativeType.target().unqualified())
- val = self.createPointerValue(toInteger(nativeValue), targetType)
- # The nativeValue is needed in case of multiple inheritance, see
- # QTCREATORBUG-17823. Using it triggers nativeValueDereferencePointer()
- # later which
- # is surprisingly expensive.
- val.nativeValue = nativeValue
- #DumperBase.warn('CREATED PTR 1: %s' % val)
+ target_typeid = self.from_native_type(nativeType.target().unqualified())
+ val.ldata = int(nativeValue)
+ val.typeid = self.create_pointer_typeid(target_typeid)
+ #self.warn('CREATED PTR 1: %s' % val)
if nativeValue.address is not None:
- val.laddress = toInteger(nativeValue.address)
- #DumperBase.warn('CREATED PTR 2: %s' % val)
+ val.laddress = int(nativeValue.address)
+ #self.warn('CREATED PTR 2: %s' % val)
return val
- if code == gdb.TYPE_CODE_TYPEDEF:
- targetType = nativeType.strip_typedefs().unqualified()
- #DumperBase.warn('TARGET TYPE: %s' % targetType)
- if targetType.code == gdb.TYPE_CODE_ARRAY:
- val = self.Value(self)
- else:
- try:
- # Cast may fail for arrays, for typedefs to __uint128_t with
- # gdb.error: That operation is not available on integers
- # of more than 8 bytes.
- # See test for Bug5799, QTCREATORBUG-18450.
- val = self.fromNativeValue(nativeValue.cast(targetType))
- except:
- val = self.Value(self)
- #DumperBase.warn('CREATED TYPEDEF: %s' % val)
- else:
- val = self.Value(self)
- val.nativeValue = nativeValue
if nativeValue.address is not None:
- val.laddress = toInteger(nativeValue.address)
- else:
- size = nativeType.sizeof
- chars = self.lookupNativeType('unsigned char')
- y = nativeValue.cast(chars.array(0, int(nativeType.sizeof - 1)))
- buf = bytearray(struct.pack('x' * size))
- for i in range(size):
- try:
- buf[i] = int(y[i])
- except:
- pass
- val.ldata = bytes(buf)
+ val.laddress = int(nativeValue.address)
+ elif code == gdb.TYPE_CODE_STRUCT:
+ try:
+ val.ldata = nativeValue.bytes # GDB 15 only
+ except:
+ val.ldata = self.nativeDataFromValueFallback(nativeValue, nativeValue.type.sizeof)
- val._type = self.fromNativeType(nativeType)
+ val.typeid = self.from_native_type(nativeType)
val.lIsInScope = not nativeValue.is_optimized_out
code = nativeType.code
if code == gdb.TYPE_CODE_ENUM:
@@ -283,10 +253,15 @@ class Dumper(DumperBase):
val.ldisplay += ' (%s)' % intval
elif code == gdb.TYPE_CODE_COMPLEX:
val.ldisplay = str(nativeValue)
- elif code in [gdb.TYPE_CODE_BOOL, gdb.TYPE_CODE_INT]:
+ elif code == gdb.TYPE_CODE_BOOL:
+ # FIXME: why?
+ # Using ldata breaks StdVariant test, not setting lvalue breaks the Bitfield[s2] test.
+ val.lvalue = int(nativeValue)
+ val.ldata = None
+ elif code == gdb.TYPE_CODE_INT:
try:
# extract int presentation from native value and remember it
- val.lvalue = int(nativeValue)
+ val.ldata = int(nativeValue)
except:
# GDB only support converting integers of max. 64 bits to Python int as of now
pass
@@ -294,65 +269,81 @@ class Dumper(DumperBase):
# val.type.ltarget = nativeValue[0].type.unqualified()
return val
+ def nativeDataFromValueFallback(self, nativeValue, size):
+ chars = self.lookupNativeType('unsigned char')
+ try:
+ y = nativeValue.cast(chars.array(0, int(size - 1)))
+ buf = bytearray(struct.pack('x' * size))
+ for i in range(size):
+ try:
+ buf[i] = int(y[i])
+ except:
+ pass
+ return bytes(buf)
+ except:
+ self.warn('VALUE EXTRACTION FAILED: VALUE: %s SIZE: %s' % (nativeValue, size))
+ return None
+
def ptrSize(self):
result = gdb.lookup_type('void').pointer().sizeof
self.ptrSize = lambda: result
return result
- def fromNativeType(self, nativeType):
+ def from_native_type(self, nativeType):
self.check(isinstance(nativeType, gdb.Type))
- code = nativeType.code
- #DumperBase.warn('FROM NATIVE TYPE: %s' % nativeType)
+
+ #self.warn('FROM NATIVE TYPE: %s' % nativeType)
nativeType = nativeType.unqualified()
- if code == gdb.TYPE_CODE_PTR:
- #DumperBase.warn('PTR')
- targetType = self.fromNativeType(nativeType.target().unqualified())
- return self.createPointerType(targetType)
+ typeid_str = self.native_type_key(nativeType)
+ known_typeid = self.typeid_from_typekey.get(typeid_str, None)
+ if known_typeid is not None:
+ return known_typeid
- if code == gdb.TYPE_CODE_REF:
- #DumperBase.warn('REF')
- targetType = self.fromNativeType(nativeType.target().unqualified())
- return self.createReferenceType(targetType)
-
- if hasattr(gdb, "TYPE_CODE_RVALUE_REF"):
- if code == gdb.TYPE_CODE_RVALUE_REF:
- #DumperBase.warn('RVALUEREF')
- targetType = self.fromNativeType(nativeType.target())
- return self.createRValueReferenceType(targetType)
-
- if code == gdb.TYPE_CODE_ARRAY:
- #DumperBase.warn('ARRAY')
+ code = nativeType.code
+
+ if code == gdb.TYPE_CODE_PTR:
+ #self.warn('PTR')
+ target_typeid = self.from_native_type(nativeType.target().unqualified())
+ typeid = self.create_pointer_typeid(target_typeid)
+
+ elif code == gdb.TYPE_CODE_REF:
+ #self.warn('REF')
+ target_typeid = self.from_native_type(nativeType.target().unqualified())
+ typeid = self.create_reference_typeid(target_typeid)
+
+ elif code == gdb.TYPE_CODE_RVALUE_REF and hasattr(gdb, "TYPE_CODE_RVALUE_REF"):
+ #self.warn('RVALUEREF')
+ target_typeid = self.from_native_type(nativeType.target())
+ typeid = self.create_rvalue_reference_typeid(target_typeid)
+
+ elif code == gdb.TYPE_CODE_ARRAY:
+ #self.warn('ARRAY')
nativeTargetType = nativeType.target().unqualified()
- targetType = self.fromNativeType(nativeTargetType)
+ target_typeid = self.from_native_type(nativeTargetType)
if nativeType.sizeof == 0:
# QTCREATORBUG-23998, note that nativeType.name == None here,
# whereas str(nativeType) returns sth like 'QObject [5]'
count = self.arrayItemCountFromTypeName(str(nativeType), 1)
else:
count = nativeType.sizeof // nativeTargetType.sizeof
- return self.createArrayType(targetType, count)
+ typeid = self.create_array_typeid(target_typeid, count)
- if code == gdb.TYPE_CODE_TYPEDEF:
- #DumperBase.warn('TYPEDEF')
+ elif code == gdb.TYPE_CODE_TYPEDEF:
+ #self.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),
- self.nativeTypeId(nativeType))
+ target_typeid = self.from_native_type(nativeTargetType)
+ typeid = self.create_typedefed_typeid(target_typeid, str(nativeType), typeid_str)
- if code == gdb.TYPE_CODE_ERROR:
+ elif code == gdb.TYPE_CODE_ERROR:
self.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, typeId)
- tdata.name = str(nativeType)
- tdata.lbitsize = nativeType.sizeof * 8
- tdata.code = {
+ typeid = 0 # the invalid id
+
+ else:
+ typeid = self.typeid_for_string(typeid_str)
+ type_code = {
#gdb.TYPE_CODE_TYPEDEF : TypeCode.Typedef, # Handled above.
gdb.TYPE_CODE_METHOD: TypeCode.Function,
gdb.TYPE_CODE_VOID: TypeCode.Void,
@@ -372,38 +363,60 @@ class Dumper(DumperBase):
gdb.TYPE_CODE_COMPLEX: TypeCode.Complex,
gdb.TYPE_CODE_STRING: TypeCode.FortranString,
}[code]
- if tdata.code == TypeCode.Enum:
- tdata.enumDisplay = lambda intval, addr, form: \
+ self.type_name_cache[typeid] = str(nativeType)
+ self.type_size_cache[typeid] = nativeType.sizeof
+ self.type_code_cache[typeid] = type_code
+ self.type_nativetype_cache[typeid] = nativeType
+
+ if type_code == TypeCode.Enum:
+ self.type_enum_display_cache[typeid] = lambda intval, addr, form: \
self.nativeTypeEnumDisplay(nativeType, intval, form)
- if tdata.code == TypeCode.Struct:
- tdata.lalignment = lambda: \
- self.nativeStructAlignment(nativeType)
- tdata.lfields = lambda value: \
- self.listMembers(value, nativeType)
- tdata.templateArguments = lambda: \
- self.listTemplateParameters(nativeType)
- # 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).value())
- else:
- raise RuntimeError('UNKNOWN TEMPLATE PARAMETER')
- pos += 1
- targs2 = self.listTemplateParametersManually(str(nativeType))
- return targs if len(targs) >= len(targs2) else targs2
+
+ self.type_nativetype_cache[typeid] = nativeType
+
+# FIXME: Field offset caching (or later extraction?) broken
+# if code == gdb.TYPE_CODE_STRUCT:
+# field_type_name = self.type_name_cache.get(typeid, '')
+# #self.warn("CACHING FIELDS OF %s '%s'" % (typeid, field_type_name))
+# try:
+# fields = nativeType.fields()
+# #self.warn("FOUND FIELDS %s" % fields)
+# except:
+# #self.warn("NO FIELDS IN %s '%s'" % (typeid, field_type_name))
+# fields = []
+# for nativeField in fields:
+# field_name = nativeField.name
+# if field_name.startswith('std::allocator'):
+# continue
+# field_bitpos = nativeField.bitpos
+# field_typeid = self.typeid_for_string(str(nativeType))
+# field_size = nativeField.type.sizeof
+# #self.warn("CACHING '%s' OF %s AT BITPOS %s SIZE %s" %
+# # (field_name, typeid, field_bitpos, field_size))
+# self.type_fields_cache[(typeid, field_name)] = self.Field(
+# name=field_name,
+# typeid=field_typeid,
+# bitpos=field_bitpos,
+# bitsize=field_size * 8
+# )
+# pass
+
+
+ #self.warn("FROM NATIVE TYPE: %s %s %s" % (typeid, id(nativeType), nativeType))
+ self.typeid_from_typekey[str(nativeType)] = typeid
+
+ return typeid
+
+ def nativeTemplateParameter(self, typeid, index, nativeType):
+ try:
+ targ = nativeType.template_argument(index)
+ except:
+ return None
+ if isinstance(targ, gdb.Type):
+ return self.Type(self, self.from_native_type(targ.unqualified()))
+ if isinstance(targ, gdb.Value):
+ return self.fromNativeValue(targ).value()
+ raise RuntimeError('UNKNOWN TEMPLATE PARAMETER')
def nativeTypeEnumDisplay(self, nativeType, intval, form):
try:
@@ -432,7 +445,7 @@ class Dumper(DumperBase):
pass
return form % intval
- def nativeTypeId(self, nativeType):
+ def native_type_key(self, nativeType):
if nativeType and (nativeType.code == gdb.TYPE_CODE_TYPEDEF):
return '%s{%s}' % (nativeType, nativeType.strip_typedefs())
name = str(nativeType)
@@ -444,133 +457,106 @@ class Dumper(DumperBase):
c = 's'
else:
return name
- typeId = c + ''.join(['{%s:%s}' % (f.name, self.nativeTypeId(f.type))
- for f in nativeType.fields()])
- return typeId
-
- def nativeStructAlignment(self, nativeType):
- #DumperBase.warn('NATIVE ALIGN FOR %s' % nativeType.name)
- def handleItem(nativeFieldType, align):
- a = self.fromNativeType(nativeFieldType).alignment()
- return a if a > align else align
- align = 1
- for f in nativeType.fields():
- align = handleItem(f.type, align)
- return align
-
- #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.
- # pass
+ id_str = c + ''.join(['{%s:%s}' %
+ (f.name, self.typeid_for_string(self.native_type_key(f.type)))
+ for f in nativeType.fields()])
+ #self.warn("NATIVE TYPE KEY: %s" % id_str)
+ return id_str
- #yield value.extractField(field)
-
- def memberFromNativeFieldAndValue(self, nativeField, nativeValue, fieldName, value):
- nativeMember = self.nativeMemberFromField(nativeValue, nativeField)
- if nativeMember is None:
- val = self.Value(self)
- val.name = fieldName
- val._type = self.fromNativeType(nativeField.type)
- val.lIsInScope = False
- return val
- val = self.fromNativeValue(nativeMember)
- nativeFieldType = nativeField.type.unqualified()
- if nativeField.bitsize:
- val.lvalue = int(nativeMember)
- val.laddress = None
- fieldType = self.fromNativeType(nativeFieldType)
- val._type = self.createBitfieldType(fieldType, nativeField.bitsize)
- val.isBaseClass = nativeField.is_base_class
- val.name = fieldName
- return val
-
- def nativeMemberFromField(self, nativeValue, nativeField):
- if nativeField.is_base_class:
- return nativeValue.cast(nativeField.type)
- try:
- return nativeValue[nativeField]
- except:
- pass
- try:
- return nativeValue[nativeField.name]
- except:
- pass
- return None
-
- def listMembers(self, value, nativeType):
+ def nativeListMembers(self, value, nativeType, include_base):
nativeValue = value.nativeValue
+ value_size = self.type_size(value.typeid)
+ ldata = bytes(self.value_data(value, value_size))
+ laddress = value.laddress
anonNumber = 0
- #DumperBase.warn('LISTING FIELDS FOR %s' % nativeType)
+ fields = []
+ #self.warn('LISTING FIELDS FOR %s' % nativeType)
for nativeField in nativeType.fields():
- fieldName = nativeField.name
+ if not include_base and nativeField.is_base_class:
+ continue
+
+ field_name = nativeField.name
# 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 fieldName is None or len(fieldName) == 0:
- # Something without a name.
- # Anonymous union? We need a dummy name to distinguish
- # multiple anonymous unions in the struct.
+ if field_name is None or len(field_name) == 0:
anonNumber += 1
- fieldName = '#%s' % anonNumber
- #DumperBase.warn('FIELD: %s' % fieldName)
+ field_name = '#%s' % anonNumber
+ #self.warn('FIELD: %s' % field_name)
+
+ nativeFieldType = nativeField.type.unqualified()
+ field_typeid = self.from_native_type(nativeFieldType)
+ #self.warn(' TYPE: %s' % nativeFieldType)
+ #self.warn(' TYPE KEY: %s' % self.native_type_key(nativeFieldType))
+
+ if nativeValue is not None:
+ try:
+ native_member = nativeValue[nativeField]
+ except:
+ self.warn(' COULD NOT ACCESS FIELD: %s' % nativeFieldType)
+ continue
+
+ val = self.fromNativeValue(native_member)
+ if nativeField.bitsize:
+ val.lvalue = None
+ val.ldata = int(native_member)
+ val.laddress = None
+ val.typeid = self.create_bitfield_typeid(field_typeid, nativeField.bitsize)
+ val.isBaseClass = nativeField.is_base_class
+ val.name = field_name
+ fields.append(val)
+ continue
+
# hasattr(nativeField, 'bitpos') == False indicates a static field,
- # but if we have access to a nativeValue .fromNativeField will
+ # but if we have access to a nativeValue, so fromNativeField will
# also succeed. We essentially skip only static members from
# artificial values, like array members constructed from address.
- if hasattr(nativeField, 'bitpos') or nativeValue is not None:
- yield self.fromNativeField(nativeField, nativeValue, fieldName)
+ if not hasattr(nativeField, 'bitpos'):
+ continue
- def fromNativeField(self, nativeField, nativeValue, fieldName):
- nativeFieldType = nativeField.type.unqualified()
- #DumperBase.warn(' TYPE: %s' % nativeFieldType)
- #DumperBase.warn(' TYPEID: %s' % self.nativeTypeId(nativeFieldType))
-
- if hasattr(nativeField, 'bitpos'):
bitpos = nativeField.bitpos
- else:
- bitpos = 0
- if hasattr(nativeField, 'bitsize') and nativeField.bitsize != 0:
- bitsize = nativeField.bitsize
- else:
- bitsize = 8 * nativeFieldType.sizeof
+ if hasattr(nativeField, 'bitsize') and nativeField.bitsize != 0:
+ bitsize = nativeField.bitsize
+ else:
+ bitsize = 8 * nativeFieldType.sizeof
- fieldType = self.fromNativeType(nativeFieldType)
- if bitsize != nativeFieldType.sizeof * 8:
- fieldType = self.createBitfieldType(fieldType, bitsize)
- else:
- fieldType = fieldType
+ field_typeid = self.from_native_type(nativeFieldType)
+ is_bitfield = bitsize != nativeFieldType.sizeof * 8
+
+ val = self.Value(self)
+ val.name = field_name
+ val.isBaseClass = nativeField.is_base_class
+
+ if is_bitfield:
+ val.typeid = self.create_bitfield_typeid(field_typeid, bitsize)
+ val.ldata = self.value_extract_bits(value, bitpos, bitsize)
+ else:
+ val.typeid = field_typeid
+ field_offset = bitpos // 8
+ if laddress is not None:
+ val.laddress = laddress + field_offset
+ field_size = (bitsize + 7) // 8
+ val.ldata = ldata[field_offset:field_offset + field_size]
+
+ #self.warn('GOT VAL %s FOR FIELD %s' % (val, nativeField))
+ fields.append(val)
+
+ return fields
- if nativeValue is None:
- extractor = None
- else:
- extractor = lambda value, \
- capturedNativeField = nativeField, \
- capturedNativeValue = nativeValue, \
- capturedFieldName = fieldName: \
- self.memberFromNativeFieldAndValue(capturedNativeField,
- capturedNativeValue,
- capturedFieldName,
- value)
-
- #DumperBase.warn("FOUND NATIVE FIELD: %s bitpos: %s" % (fieldName, bitpos))
- return self.Field(dumper=self, name=fieldName, isBase=nativeField.is_base_class,
- bitsize=bitsize, bitpos=bitpos, type=fieldType,
- extractor=extractor)
def listLocals(self, partialVar):
frame = gdb.selected_frame()
try:
block = frame.block()
- #DumperBase.warn('BLOCK: %s ' % block)
+ #self.warn('BLOCK: %s ' % block)
except RuntimeError as error:
- #DumperBase.warn('BLOCK IN FRAME NOT ACCESSIBLE: %s' % error)
+ #self.warn('BLOCK IN FRAME NOT ACCESSIBLE: %s' % error)
return []
except:
self.warn('BLOCK NOT ACCESSIBLE FOR UNKNOWN REASONS')
@@ -594,14 +580,12 @@ class Dumper(DumperBase):
if partialVar is not None and partialVar != name:
continue
- # 'NotImplementedError: Symbol type not yet supported in
- # Python scripts.'
- #DumperBase.warn('SYMBOL %s (%s, %s)): ' % (symbol, name, symbol.name))
+ #self.warn('SYMBOL %s (%s, %s)): ' % (symbol, name, symbol.name))
if self.passExceptions and not self.isTesting:
nativeValue = frame.read_var(name, block)
value = self.fromFrameValue(nativeValue)
value.name = name
- #DumperBase.warn('READ 0: %s' % value.stringify())
+ #self.warn('READ 0: %s' % value.stringify())
items.append(value)
continue
@@ -610,14 +594,14 @@ class Dumper(DumperBase):
nativeValue = frame.read_var(name, block)
value = self.fromFrameValue(nativeValue)
value.name = name
- #DumperBase.warn('READ 1: %s' % value.stringify())
+ #self.warn('READ 1: %s' % value.stringify())
items.append(value)
continue
except:
pass
try:
- #DumperBase.warn('READ 2: %s' % item.value)
+ #self.warn('READ 2: %s' % item.value)
value = self.fromFrameValue(frame.read_var(name))
value.name = name
items.append(value)
@@ -631,8 +615,8 @@ class Dumper(DumperBase):
pass
try:
- #DumperBase.warn('READ 3: %s %s' % (name, item.value))
- #DumperBase.warn('ITEM 3: %s' % item.value)
+ #self.warn('READ 3: %s %s' % (name, item.value))
+ #self.warn('ITEM 3: %s' % item.value)
value = self.fromFrameValue(gdb.parse_and_eval(name))
value.name = name
items.append(value)
@@ -661,16 +645,17 @@ class Dumper(DumperBase):
return self.ptrSize() == 8
def fetchVariables(self, args):
+ start_time = time.perf_counter()
self.resetStats()
self.prepare(args)
self.isBigEndian = gdb.execute('show endian', to_string=True).find('big endian') > 0
self.packCode = '>' if self.isBigEndian else '<'
- (ok, res) = self.tryFetchInterpreterVariables(args)
- if ok:
- safePrint(res)
- return
+ #(ok, res) = self.tryFetchInterpreterVariables(args)
+ #if ok:
+ # safePrint(res)
+ # return
self.put('data=[')
@@ -679,7 +664,7 @@ class Dumper(DumperBase):
partialName = partialVar.split('.')[1].split('@')[0] if isPartial else None
variables = self.listLocals(partialName)
- #DumperBase.warn('VARIABLES: %s' % variables)
+ #self.warn('VARIABLES: %s' % variables)
# Take care of the return value of the last function call.
if len(self.resultVarName) > 0:
@@ -711,9 +696,12 @@ class Dumper(DumperBase):
self.put(',qtnamespace="%s"' % self.qtNamespaceToReport)
self.qtNamespaceToReport = None
+ run_time = time.perf_counter() - start_time
+ #self.warn("PTIME: %s" % run_time)
self.put(',partial="%d"' % isPartial)
+ self.put(',runtime="%s"' % run_time)
self.put(',counts=%s' % self.counts)
- self.put(',timings=%s' % self.timings)
+ #self.put(',timings=%s' % self.timings)
self.reportResult(''.join(self.output), args)
def parseAndEvaluate(self, exp):
@@ -721,7 +709,7 @@ class Dumper(DumperBase):
return None if val is None else self.fromNativeValue(val)
def nativeParseAndEvaluate(self, exp):
- #DumperBase.warn('EVALUATE "%s"' % exp)
+ #self.warn('EVALUATE "%s"' % exp)
try:
val = gdb.parse_and_eval(exp)
return val
@@ -744,20 +732,20 @@ class Dumper(DumperBase):
else:
arg += a
- #DumperBase.warn('CALL: %s -> %s(%s)' % (value, function, arg))
- typeName = value.type.name
- if typeName.find(':') >= 0:
- typeName = "'" + typeName + "'"
+ #self.warn('CALL: %s -> %s(%s)' % (value, function, arg))
+ type_name = value.type.name
+ if type_name.find(':') >= 0:
+ type_name = "'" + type_name + "'"
# 'class' is needed, see http://sourceware.org/bugzilla/show_bug.cgi?id=11912
- #exp = '((class %s*)%s)->%s(%s)' % (typeName, value.laddress, function, arg)
+ #exp = '((class %s*)%s)->%s(%s)' % (type_name, value.laddress, function, arg)
addr = value.address()
if addr is None:
addr = self.pokeValue(value)
- #DumperBase.warn('PTR: %s -> %s(%s)' % (value, function, addr))
- exp = '((%s*)0x%x)->%s(%s)' % (typeName, addr, function, arg)
- #DumperBase.warn('CALL: %s' % exp)
+ #self.warn('PTR: %s -> %s(%s)' % (value, function, addr))
+ exp = '((%s*)0x%x)->%s(%s)' % (type_name, addr, function, arg)
+ #self.warn('CALL: %s' % exp)
result = gdb.parse_and_eval(exp)
- #DumperBase.warn(' -> %s' % result)
+ #self.warn(' -> %s' % result)
res = self.fromNativeValue(result)
if value.address() is None:
self.releaseValue(addr)
@@ -765,9 +753,9 @@ class Dumper(DumperBase):
def makeExpression(self, value):
typename = '::' + value.type.name
- #DumperBase.warn(' TYPE: %s' % typename)
+ #self.warn(' TYPE: %s' % typename)
exp = '(*(%s*)(0x%x))' % (typename, value.address())
- #DumperBase.warn(' EXP: %s' % exp)
+ #self.warn(' EXP: %s' % exp)
return exp
def makeStdString(init):
@@ -785,14 +773,14 @@ class Dumper(DumperBase):
size = value.type.size()
data = value.data()
h = self.hexencode(data)
- #DumperBase.warn('DATA: %s' % h)
+ #self.warn('DATA: %s' % h)
string = ''.join('\\x' + h[2 * i:2 * i + 2] for i in range(size))
exp = '(%s*)memcpy(calloc(1, %d), "%s", %d)' \
% (value.type.name, size, string, size)
- #DumperBase.warn('EXP: %s' % exp)
+ #self.warn('EXP: %s' % exp)
res = gdb.parse_and_eval(exp)
- #DumperBase.warn('RES: %s' % res)
- return toInteger(res)
+ #self.warn('RES: %s' % res)
+ return int(res)
def releaseValue(self, address):
gdb.parse_and_eval('free(0x%x)' % address)
@@ -819,7 +807,7 @@ class Dumper(DumperBase):
return self.cachedInferior
def readRawMemory(self, address, size):
- #DumperBase.warn('READ: %s FROM 0x%x' % (size, address))
+ #self.warn('READ: %s FROM 0x%x' % (size, address))
if address == 0 or size == 0:
return bytes()
res = self.selectedInferior().read_memory(address, size)
@@ -832,7 +820,7 @@ class Dumper(DumperBase):
return 0
try:
# Older GDB ~7.4 don't have gdb.Symbol.value()
- return toInteger(symbol.value().address)
+ return int(symbol.value().address)
except:
pass
@@ -1020,7 +1008,7 @@ class Dumper(DumperBase):
def findSymbol(self, symbolName):
try:
- return toInteger(gdb.parse_and_eval("(size_t)&'%s'" % symbolName))
+ return int(gdb.parse_and_eval("(size_t)&'%s'" % symbolName))
except:
return 0
@@ -1052,30 +1040,24 @@ class Dumper(DumperBase):
def handleQtCoreLoaded(self, objfile):
fd, tmppath = tempfile.mkstemp()
os.close(fd)
- try:
- cmd = 'maint print msymbols -objfile "%s" -- %s' % (objfile.filename, tmppath)
- symbols = gdb.execute(cmd, to_string=True)
- except:
- try:
- # command syntax depends on gdb version - below is gdb < 8
- cmd = 'maint print msymbols %s "%s"' % (tmppath, objfile.filename)
- symbols = gdb.execute(cmd, to_string=True)
- except:
- pass
+ cmd = 'maint print msymbols -objfile "%s" -- %s' % (objfile.filename, tmppath)
+ symbols = gdb.execute(cmd, to_string=True)
ns = ''
with open(tmppath) as f:
+ ns1re = re.compile(r'_ZN?(\d*)(\w*)L17msgHandlerGrabbedE? ')
+ ns2re = re.compile(r'_ZN?(\d*)(\w*)L17currentThreadDataE? ')
for line in f:
- if line.find('msgHandlerGrabbed ') >= 0:
+ if 'msgHandlerGrabbed ' in line:
# [11] b 0x7ffff683c000 _ZN4MynsL17msgHandlerGrabbedE
# section .tbss Myns::msgHandlerGrabbed qlogging.cpp
- ns = re.split(r'_ZN?(\d*)(\w*)L17msgHandlerGrabbedE? ', line)[2]
+ ns = ns1re.split(line)[2]
if len(ns):
ns += '::'
break
- if line.find('currentThreadData ') >= 0:
+ if 'currentThreadData ' in line:
# [ 0] b 0x7ffff67d3000 _ZN2UUL17currentThreadDataE
# section .tbss UU::currentThreadData qthread_unix.cpp\\n
- ns = re.split(r'_ZN?(\d*)(\w*)L17currentThreadDataE? ', line)[2]
+ ns = ns2re.split(line)[2]
if len(ns):
ns += '::'
break
@@ -1104,21 +1086,21 @@ class Dumper(DumperBase):
self.qtPropertyFunc = self.findSymbol(sym)
def assignValue(self, args):
- typeName = self.hexdecode(args['type'])
+ type_name = self.hexdecode(args['type'])
expr = self.hexdecode(args['expr'])
value = self.hexdecode(args['value'])
simpleType = int(args['simpleType'])
ns = self.qtNamespace()
- if typeName.startswith(ns):
- typeName = typeName[len(ns):]
- typeName = typeName.replace('::', '__')
- pos = typeName.find('<')
+ if type_name.startswith(ns):
+ type_name = type_name[len(ns):]
+ type_name = type_name.replace('::', '__')
+ pos = type_name.find('<')
if pos != -1:
- typeName = typeName[0:pos]
- if typeName in self.qqEditable and not simpleType:
- #self.qqEditable[typeName](self, expr, value)
+ type_name = type_name[0:pos]
+ if type_name in self.qqEditable and not simpleType:
+ #self.qqEditable[type_name](self, expr, value)
expr = self.parseAndEvaluate(expr)
- self.qqEditable[typeName](self, expr, value)
+ self.qqEditable[type_name](self, expr, value)
else:
cmd = 'set variable (%s)=%s' % (expr, value)
gdb.execute(cmd)
@@ -1152,63 +1134,28 @@ class Dumper(DumperBase):
nativeValue = value.nativeValue
return self.fromNativeValue(nativeValue.cast(nativeValue.type.target()))
- def nativeDynamicTypeName(self, address, baseType):
- # Needed for Gdb13393 test.
- nativeType = self.lookupNativeType(baseType.name)
- if nativeType is None:
- return None
- nativeTypePointer = nativeType.pointer()
- nativeValue = gdb.Value(address).cast(nativeTypePointer).dereference()
- val = nativeValue.cast(nativeValue.dynamic_type)
- return str(val.type)
- #try:
- # vtbl = gdb.execute('info symbol {%s*}0x%x' % (baseType.name, address), to_string = True)
- #except:
- # return None
- #pos1 = vtbl.find('vtable ')
- #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):
+ def nativeDynamicType(self, address, base_typeid):
# Needed for Gdb13393 test.
- nativeType = self.lookupNativeType(baseType.name)
+ nativeType = self.type_nativetype_cache.get(base_typeid, None)
if nativeType is None:
- return baseType
+ return base_typeid
nativeTypePointer = nativeType.pointer()
nativeValue = gdb.Value(address).cast(nativeTypePointer).dereference()
- return self.fromNativeType(nativeValue.dynamic_type)
+ return self.from_native_type(nativeValue.dynamic_type)
def enumExpression(self, enumType, enumValue):
return self.qtNamespace() + 'Qt::' + enumValue
- def lookupNativeType(self, typeName):
- nativeType = self.lookupNativeTypeHelper(typeName)
- if nativeType is not None:
- self.check(isinstance(nativeType, gdb.Type))
- return nativeType
-
- def lookupNativeTypeHelper(self, typeName):
- typeobj = self.typeCache.get(typeName)
- #DumperBase.warn('LOOKUP 1: %s -> %s' % (typeName, typeobj))
- if typeobj is not None:
- return typeobj
-
- if typeName == 'void':
- typeobj = gdb.lookup_type(typeName)
- self.typeCache[typeName] = typeobj
- self.typesToReport[typeName] = typeobj
+ def lookupNativeType(self, type_name):
+ if type_name == 'void':
+ typeobj = gdb.lookup_type(type_name)
+ self.typesToReport[type_name] = typeobj
return typeobj
#try:
- # typeobj = gdb.parse_and_eval('{%s}&main' % typeName).typeobj
+ # typeobj = gdb.parse_and_eval('{%s}&main' % type_name).typeobj
# if not typeobj is None:
- # self.typeCache[typeName] = typeobj
- # self.typesToReport[typeName] = typeobj
+ # self.typesToReport[type_name] = typeobj
# return typeobj
#except:
# pass
@@ -1217,22 +1164,21 @@ class Dumper(DumperBase):
# gcc produces '{anonymous}', gdb '(anonymous namespace)'
# '<unnamed>' has been seen too. The only thing gdb
# understands when reading things back is '(anonymous namespace)'
- if typeName.find('{anonymous}') != -1:
- ts = typeName
+ if type_name.find('{anonymous}') != -1:
+ ts = type_name
ts = ts.replace('{anonymous}', '(anonymous namespace)')
typeobj = self.lookupNativeType(ts)
if typeobj is not None:
- self.typeCache[typeName] = typeobj
- self.typesToReport[typeName] = typeobj
+ self.typesToReport[type_name] = typeobj
return typeobj
- #DumperBase.warn(" RESULT FOR 7.2: '%s': %s" % (typeName, typeobj))
+ #self.warn(" RESULT FOR 7.2: '%s': %s" % (type_name, typeobj))
# This part should only trigger for
# gdb 7.1 for types with namespace separators.
# And anonymous namespaces.
- ts = typeName
+ ts = type_name
while True:
if ts.startswith('class '):
ts = ts[6:]
@@ -1259,36 +1205,32 @@ class Dumper(DumperBase):
typeobj = self.lookupNativeType(ts[0:-1])
if typeobj is not None:
typeobj = typeobj.pointer()
- self.typeCache[typeName] = typeobj
- self.typesToReport[typeName] = typeobj
+ self.typesToReport[type_name] = typeobj
return typeobj
try:
- #DumperBase.warn("LOOKING UP 1 '%s'" % ts)
+ #self.warn("LOOKING UP 1 '%s'" % ts)
typeobj = gdb.lookup_type(ts)
except RuntimeError as error:
- #DumperBase.warn("LOOKING UP 2 '%s' ERROR %s" % (ts, error))
+ #self.warn("LOOKING UP '%s' FAILED" % ts)
+ pass
+ #self.warn("LOOKING UP 2 '%s' ERROR %s" % (ts, error))
# See http://sourceware.org/bugzilla/show_bug.cgi?id=11912
exp = "(class '%s'*)0" % ts
try:
typeobj = self.parse_and_eval(exp).type.target()
- #DumperBase.warn("LOOKING UP 3 '%s'" % typeobj)
+ #self.warn("LOOKING UP 3 '%s'" % typeobj)
except:
# Can throw 'RuntimeError: No type named class Foo.'
pass
- except:
- #DumperBase.warn("LOOKING UP '%s' FAILED" % ts)
- pass
if typeobj is not None:
- #DumperBase.warn('CACHING: %s' % typeobj)
- self.typeCache[typeName] = typeobj
- self.typesToReport[typeName] = typeobj
+ #self.warn('CACHING: %s' % typeobj)
+ self.typesToReport[type_name] = typeobj
# This could still be None as gdb.lookup_type('char[3]') generates
# 'RuntimeError: No type named char[3]'
- #self.typeCache[typeName] = typeobj
- #self.typesToReport[typeName] = typeobj
+ #self.typesToReport[type_name] = typeobj
return typeobj
def doContinue(self):
@@ -1332,7 +1274,7 @@ class Dumper(DumperBase):
if typeobj.code == gdb.TYPE_CODE_PTR:
dereftype = typeobj.target().unqualified()
if dereftype.name == needle:
- addr = toInteger(value)
+ addr = int(value)
res = None
for pat in pats:
try:
@@ -1442,14 +1384,6 @@ class Dumper(DumperBase):
def reportResult(self, result, args):
print('result={token="%s",%s}' % (args.get("token", 0), result))
- def profile1(self, args):
- '''Internal profiling'''
- import cProfile
- tempDir = tempfile.gettempdir() + '/bbprof'
- cProfile.run('theDumper.fetchVariables(%s)' % args, tempDir)
- import pstats
- pstats.Stats(tempDir).sort_stats('time').print_stats()
-
def profile2(self, args):
import timeit
print(timeit.repeat('theDumper.fetchVariables(%s)' % args,
diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py
index b64d115a0a..6b08ac3d32 100644
--- a/share/qtcreator/debugger/lldbbridge.py
+++ b/share/qtcreator/debugger/lldbbridge.py
@@ -116,33 +116,29 @@ class Dumper(DumperBase):
self.isInterrupting_ = False
self.interpreterBreakpointResolvers = []
- DumperBase.warn = Dumper.warn_impl
self.report('lldbversion=\"%s\"' % lldb.SBDebugger.GetVersionString())
- @staticmethod
- def warn_impl(message):
- if message[-1:] == '\n':
- message += '\n'
+ def warn(self, msg):
+ #self.put('{name="%s",value="",type="",numchild="0"},' % toCString(msg))
+ if msg[-1:] == '\n':
+ msg += '\n'
print('@\nbridgemessage={msg="%s",channel="%s"}\n@'
- % (message.replace('"', '$'), LogChannel.AppError))
-
- def fromNativeFrameValue(self, nativeValue):
- return self.fromNativeValue(nativeValue)
+ % (msg.replace('"', '$'), LogChannel.AppError))
def fromNativeValue(self, nativeValue):
self.check(isinstance(nativeValue, lldb.SBValue))
nativeType = nativeValue.GetType()
- typeName = nativeType.GetName()
+ type_name = nativeType.GetName()
code = nativeType.GetTypeClass()
# Display the result of GetSummary() for Core Foundation string
# and string-like types.
summary = None
if self.useFancy:
- if (typeName.startswith('CF')
- or typeName.startswith('__CF')
- or typeName.startswith('NS')
- or typeName.startswith('__NSCF')):
+ if (type_name.startswith('CF')
+ or type_name.startswith('__CF')
+ or type_name.startswith('NS')
+ or type_name.startswith('__NSCF')):
if code == lldb.eTypeClassPointer:
summary = nativeValue.Dereference().GetSummary()
elif code == lldb.eTypeClassReference:
@@ -156,26 +152,26 @@ class Dumper(DumperBase):
nativeTargetType = nativeType.GetDereferencedType()
if not nativeTargetType.IsPointerType():
nativeTargetType = nativeTargetType.GetUnqualifiedType()
- targetType = self.fromNativeType(nativeTargetType)
- val = self.createReferenceValue(nativeValue.GetValueAsUnsigned(), targetType)
+ target_typeid = self.from_native_type(nativeTargetType)
+ target_address = nativeValue.GetValueAsUnsigned()
+ val = self.Value(self)
+ val.ldata = target_address.to_bytes(self.ptrSize(), 'little')
+ if self.useDynamicType:
+ target_typeid = self.dynamic_typeid_at_address(target_typeid, target_address)
+ val.typeid = self.create_reference_typeid(target_typeid)
val.laddress = nativeValue.AddressOf().GetValueAsUnsigned()
- #DumperBase.warn('CREATED REF: %s' % val)
+ #self.warn('CREATED REF: %s' % val)
+
elif code == lldb.eTypeClassPointer:
nativeTargetType = nativeType.GetPointeeType()
if not nativeTargetType.IsPointerType():
nativeTargetType = nativeTargetType.GetUnqualifiedType()
- targetType = self.fromNativeType(nativeTargetType)
- val = self.createPointerValue(nativeValue.GetValueAsUnsigned(), targetType)
- #DumperBase.warn('CREATED PTR 1: %s' % val)
+ target_typeid = self.from_native_type(nativeTargetType)
+ val = self.Value(self)
+ val.ldata = nativeValue.GetValueAsUnsigned()
+ val.typeid = self.create_pointer_typeid(target_typeid)
val.laddress = nativeValue.AddressOf().GetValueAsUnsigned()
- #DumperBase.warn('CREATED PTR 2: %s' % val)
- elif code == lldb.eTypeClassTypedef:
- nativeTargetType = nativeType.GetUnqualifiedType()
- if hasattr(nativeTargetType, 'GetCanonicalType'):
- nativeTargetType = nativeTargetType.GetCanonicalType()
- val = self.fromNativeValue(nativeValue.Cast(nativeTargetType))
- val._type = self.fromNativeType(nativeType)
- #DumperBase.warn('CREATED TYPEDEF: %s' % val)
+
else:
val = self.Value(self)
address = nativeValue.GetLoadAddress()
@@ -193,7 +189,7 @@ class Dumper(DumperBase):
except:
pass
- val._type = self.fromNativeType(nativeType)
+ val.typeid = self.from_native_type(nativeType)
if code == lldb.eTypeClassEnumeration:
intval = nativeValue.GetValueAsSigned()
@@ -209,43 +205,32 @@ class Dumper(DumperBase):
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())
+ # val.type.ltarget = self.from_native_type(nativeType.GetArrayElementType())
# else:
# fields = nativeType.get_fields_array()
# if len(fields):
- # val.type.ltarget = self.fromNativeType(fields[0])
+ # val.type.ltarget = self.from_native_type(fields[0])
#elif code == lldb.eTypeClassVector:
- # val.type.ltarget = self.fromNativeType(nativeType.GetVectorElementType())
+ # val.type.ltarget = self.from_native_type(nativeType.GetVectorElementType())
val.summary = summary
val.lIsInScope = nativeValue.IsInScope()
val.name = nativeValue.GetName()
return val
- def nativeStructAlignment(self, nativeType):
- def handleItem(nativeFieldType, align):
- a = self.fromNativeType(nativeFieldType).alignment()
- return a if a > align else align
- align = 1
- for i in range(nativeType.GetNumberOfDirectBaseClasses()):
- base = nativeType.GetDirectBaseClassAtIndex(i)
- align = handleItem(base.GetType(), align)
- for i in range(nativeType.GetNumberOfFields()):
- child = nativeType.GetFieldAtIndex(i)
- align = handleItem(child.GetType(), align)
- return align
-
- def listMembers(self, value, nativeType):
- #DumperBase.warn("ADDR: 0x%x" % self.fakeAddress_)
- if value.laddress:
- fakeAddress = lldb.SBAddress(value.laddress, self.target)
- fakeLAddress = value.laddress
- else:
- fakeAddress = self.fakeAddress_
- fakeLAddress = self.fakeLAddress_
+ def nativeListMembers(self, value, nativeType, include_base):
+ #self.warn("ADDR: 0x%x" % self.fakeAddress_)
+ nativeValue = value.nativeValue
+ if nativeValue is None:
+ if value.laddress:
+ fakeAddress = lldb.SBAddress(value.laddress, self.target)
+ fakeLAddress = value.laddress
+ else:
+ fakeAddress = self.fakeAddress_
+ fakeLAddress = self.fakeLAddress_
+ nativeValue = self.target.CreateValueFromAddress('x', fakeAddress, nativeType)
- fakeValue = self.target.CreateValueFromAddress('x', fakeAddress, nativeType)
- fakeValue.SetPreferSyntheticValue(False)
+ nativeValue.SetPreferSyntheticValue(False)
baseNames = {}
for i in range(nativeType.GetNumberOfDirectBaseClasses()):
@@ -262,86 +247,99 @@ class Dumper(DumperBase):
# Normal members and non-empty base classes.
anonNumber = 0
- for i in range(fakeValue.GetNumChildren()):
- nativeField = fakeValue.GetChildAtIndex(i)
+
+ fields = []
+ for i in range(nativeValue.GetNumChildren()):
+ nativeField = nativeValue.GetChildAtIndex(i)
nativeField.SetPreferSyntheticValue(False)
fieldName = nativeField.GetName()
nativeFieldType = nativeField.GetType()
if fieldName in fieldBits:
- (fieldBitsize, fieldBitpos, isBitfield) = fieldBits[fieldName]
+ (bitsize, bitpos, isBitfield) = fieldBits[fieldName]
else:
- fieldBitsize = nativeFieldType.GetByteSize() * 8
- fieldBitpos = None
+ bitsize = nativeFieldType.GetByteSize() * 8
+ bitpos = None
isBitfield = False
if isBitfield: # Bit fields
- fieldType = self.createBitfieldType(
- self.createType(self.typeName(nativeFieldType)), fieldBitsize)
- yield self.Field(self, name=fieldName, type=fieldType,
- bitsize=fieldBitsize, bitpos=fieldBitpos)
+ field_typeid = self.create_bitfield_typeid(
+ self.create_typeid(nativeFieldType.GetName()), bitsize)
+ val = self.Value(self)
+ val.name = fieldName
+ val.isBaseClass = False
+ val.typeid = field_typeid
+ val.ldata = self.value_extract_bits(value, bitpos, bitsize)
+ val.laddress = None
+ fields.append(val)
elif fieldName is None: # Anon members
anonNumber += 1
fieldName = '#%s' % anonNumber
- fakeMember = fakeValue.GetChildAtIndex(i)
+ fakeMember = nativeValue.GetChildAtIndex(i)
fakeMemberAddress = fakeMember.GetLoadAddress()
- offset = fakeMemberAddress - fakeLAddress
- yield self.Field(self, name=fieldName, type=self.fromNativeType(nativeFieldType),
- bitsize=fieldBitsize, bitpos=8 * offset)
+ val = self.Value(self)
+ val.name = fieldName
+ val.isBaseClass = False
+ val.typeid = typeid=self.from_native_type(nativeFieldType)
+ field_offset = fakeMemberAddress - fakeLAddress
+ if value.laddress is not None:
+ val.laddress = value.laddress + field_offset
+ if value.ldata is not None:
+ field_size = (bitsize + 7) // 8
+ val.ldata = value.ldata[field_offset:field_offset + field_size]
+ fields.append(val)
elif fieldName in baseNames: # Simple bases
- member = self.fromNativeValue(fakeValue.GetChildAtIndex(i))
+ member = self.fromNativeValue(nativeValue.GetChildAtIndex(i))
member.isBaseClass = True
- yield member
+ fields.append(member)
else: # Normal named members
- member = self.fromNativeValue(fakeValue.GetChildAtIndex(i))
+ member = self.fromNativeValue(nativeValue.GetChildAtIndex(i))
member.name = nativeField.GetName()
- yield member
-
- # Empty bases are not covered above.
- for i in range(nativeType.GetNumberOfDirectBaseClasses()):
- fieldObj = nativeType.GetDirectBaseClassAtIndex(i)
- fieldType = fieldObj.GetType()
- if fieldType.GetNumberOfFields() == 0:
- if fieldType.GetNumberOfDirectBaseClasses() == 0:
- member = self.Value(self)
- fieldName = fieldObj.GetName()
- member._type = self.fromNativeType(fieldType)
- member.name = fieldName
- member.fields = []
- if False:
- # This would be correct if we came here only for
- # truly empty base classes. Alas, we don't, see below.
- member.ldata = bytes()
- member.lbitsize = fieldType.GetByteSize() * 8
- else:
- # This is a hack. LLDB 3.8 reports declared but not defined
- # types as having no fields and(!) size == 1. At least
- # for the common case of a single base class we can
- # fake the contents by using the whole derived object's
- # data as base class data.
- data = fakeValue.GetData()
- size = nativeType.GetByteSize()
- member.lbitsize = size * 8
- error = lldb.SBError()
- member.laddress = value.laddress
- member.ldata = data.ReadRawData(error, 0, size)
- member.isBaseClass = True
- member.ltype = self.fromNativeType(fieldType)
- member.name = fieldName
- yield member
+ fields.append(member)
+
+
+ if include_base:
+ # Empty bases are not covered above.
+ for i in range(nativeType.GetNumberOfDirectBaseClasses()):
+ fieldObj = nativeType.GetDirectBaseClassAtIndex(i)
+ fieldType = fieldObj.GetType()
+ if fieldType.GetNumberOfFields() == 0:
+ if fieldType.GetNumberOfDirectBaseClasses() == 0:
+ member = self.Value(self)
+ fieldName = fieldObj.GetName()
+ member.typeid = self.from_native_type(fieldType)
+ member.name = fieldName
+ member.fields = []
+ if False:
+ # This would be correct if we came here only for
+ # truly empty base classes. Alas, we don't, see below.
+ member.ldata = bytes()
+ else:
+ # This is a hack. LLDB 3.8 reports declared but not defined
+ # types as having no fields and(!) size == 1. At least
+ # for the common case of a single base class we can
+ # fake the contents by using the whole derived object's
+ # data as base class data.
+ data = nativeValue.GetData()
+ size = nativeType.GetByteSize()
+ error = lldb.SBError()
+ member.laddress = value.laddress
+ member.ldata = data.ReadRawData(error, 0, size)
+ member.isBaseClass = True
+ fields.append(member)
+ return fields
def ptrSize(self):
result = self.target.GetAddressByteSize()
self.ptrSize = lambda: result
return result
- def fromNativeType(self, nativeType):
+ def from_native_type(self, nativeType):
self.check(isinstance(nativeType, lldb.SBType))
- code = nativeType.GetTypeClass()
# eTypeClassInvalid = (0u),
# eTypeClassArray = (1u << 0),
@@ -367,43 +365,41 @@ class Dumper(DumperBase):
# // Define a mask that can be used for any type when finding types
# eTypeClassAny = (0xffffffffu)
- #DumperBase.warn('CURRENT: %s' % self.typeData.keys())
- #DumperBase.warn('FROM NATIVE TYPE: %s' % nativeType.GetName())
- if code == lldb.eTypeClassInvalid:
- return None
+ #self.warn('CURRENT: %s' % self.typeData.keys())
+ #self.warn('FROM NATIVE TYPE: %s' % nativeType.GetName())
- if code == lldb.eTypeClassBuiltin:
- nativeType = nativeType.GetUnqualifiedType()
+ typeid_str = self.native_type_key(nativeType)
+ known_typeid = self.typeid_from_typekey.get(typeid_str, None)
+ if known_typeid is not None:
+ return known_typeid
- if code == lldb.eTypeClassPointer:
- #DumperBase.warn('PTR')
- nativeTargetType = nativeType.GetPointeeType()
- if not nativeTargetType.IsPointerType():
- nativeTargetType = nativeTargetType.GetUnqualifiedType()
- #DumperBase.warn('PTR: %s' % nativeTargetType.name)
- return self.createPointerType(self.fromNativeType(nativeTargetType))
+ code = nativeType.GetTypeClass()
- if code == lldb.eTypeClassReference:
+ if code == lldb.eTypeClassInvalid:
+ typeid = 0
+
+ elif code == lldb.eTypeClassPointer:
+ #self.warn('PTR: %s' % nativeTargetType.name)
+ target_typeid = self.from_native_type(nativeType.GetPointeeType())
+ typeid = self.create_pointer_typeid(target_typeid)
+
+ elif code == lldb.eTypeClassReference:
#DumperBase.warn('REF')
- nativeTargetType = nativeType.GetDereferencedType()
- if not nativeTargetType.IsPointerType():
- nativeTargetType = nativeTargetType.GetUnqualifiedType()
- #DumperBase.warn('REF: %s' % nativeTargetType.name)
- return self.createReferenceType(self.fromNativeType(nativeTargetType))
+ target_typeid = self.from_native_type(nativeType.GetDereferencedType())
+ typeid = self.create_reference_typeid(target_typeid)
- if code == lldb.eTypeClassTypedef:
+ elif code == lldb.eTypeClassTypedef:
#DumperBase.warn('TYPEDEF')
nativeTargetType = nativeType.GetUnqualifiedType()
if hasattr(nativeTargetType, 'GetCanonicalType'):
nativeTargetType = nativeTargetType.GetCanonicalType()
- targetType = self.fromNativeType(nativeTargetType)
- return self.createTypedefedType(targetType, nativeType.GetName(),
- self.nativeTypeId(nativeType))
-
- nativeType = nativeType.GetUnqualifiedType()
- typeName = self.typeName(nativeType)
+ target_typeid = self.from_native_type(nativeTargetType)
+ typeid = self.create_typedefed_typeid(target_typeid, nativeType.GetName(),
+ typeid_str)
- if code in (lldb.eTypeClassArray, lldb.eTypeClassVector):
+ elif code in (lldb.eTypeClassArray, lldb.eTypeClassVector):
+ nativeType = nativeType.GetUnqualifiedType()
+ type_name = nativeType.GetName()
#DumperBase.warn('ARRAY: %s' % nativeType.GetName())
if hasattr(nativeType, 'GetArrayElementType'): # New in 3.8(?) / 350.x
nativeTargetType = nativeType.GetArrayElementType()
@@ -412,141 +408,139 @@ class Dumper(DumperBase):
#DumperBase.warn('BAD: %s ' % nativeTargetType.get_fields_array())
nativeTargetType = nativeType.GetVectorElementType()
count = nativeType.GetByteSize() // nativeTargetType.GetByteSize()
- targetTypeName = nativeTargetType.GetName()
- if targetTypeName.startswith('(anon'):
- typeName = nativeType.GetName()
- pos1 = typeName.rfind('[')
- targetTypeName = typeName[0:pos1].strip()
- #DumperBase.warn("TARGET TYPENAME: %s" % targetTypeName)
- targetType = self.fromNativeType(nativeTargetType)
- targetType.setTdata(targetType.tdata.copy())
- targetType.tdata.name = targetTypeName
- return self.createArrayType(targetType, count)
- if hasattr(nativeType, 'GetVectorElementType'): # New in 3.8(?) / 350.x
+ target_typename = nativeTargetType.GetName()
+ if target_typename.startswith('(anon'):
+ type_name = nativeType.GetName()
+ pos1 = type_name.rfind('[')
+ target_typename = type_name[0:pos1].strip()
+ #DumperBase.warn("TARGET TYPENAME: %s" % target_typename)
+ target_typeid = self.from_native_type(nativeTargetType)
+ #target_typeid.setTdata(target_typeid.tdata.copy())
+ #target_typeid.tdata.name = target_typename
+ typeid = self.create_array_typeid(target_typeid, count)
+ elif hasattr(nativeType, 'GetVectorElementType'): # New in 3.8(?) / 350.x
nativeTargetType = nativeType.GetVectorElementType()
count = nativeType.GetByteSize() // nativeTargetType.GetByteSize()
- targetType = self.fromNativeType(nativeTargetType)
- return self.createArrayType(targetType, count)
- return self.createType(nativeType.GetName())
+ target_typeid = self.from_native_type(nativeTargetType)
+ typeid = self.create_array_typeid(target_typeid, count)
+ else:
+ typeid = self.create_type(nativeType.GetName())
+
+ else:
+ nativeType = nativeType.GetUnqualifiedType()
+ type_name = nativeType.GetName()
- typeId = self.nativeTypeId(nativeType)
- res = self.typeData.get(typeId, None)
- if res is None:
+ typeid = self.typeid_for_string(typeid_str)
+ #if not typeid in self.typeid_cache:
# # This strips typedefs for pointers. We don't want that.
# typeobj.nativeType = nativeType.GetUnqualifiedType()
- tdata = self.TypeData(self, typeId)
- tdata.name = typeName
- tdata.lbitsize = nativeType.GetByteSize() * 8
+ self.type_name_cache[typeid] = type_name
+ self.type_size_cache[typeid] = nativeType.GetByteSize()
+ type_code = None
if code == lldb.eTypeClassBuiltin:
- if utils.isFloatingPointTypeName(typeName):
- tdata.code = TypeCode.Float
- elif utils.isIntegralTypeName(typeName):
- tdata.code = TypeCode.Integral
- elif typeName in ('__int128', 'unsigned __int128'):
- tdata.code = TypeCode.Integral
- elif typeName == 'void':
- tdata.code = TypeCode.Void
- elif typeName == 'wchar_t':
- tdata.code = TypeCode.Integral
- elif typeName in ("char16_t", "char32_t", "char8_t"):
- tdata.code = TypeCode.Integral
+ if utils.isFloatingPointTypeName(type_name):
+ type_code = TypeCode.Float
+ elif utils.isIntegralTypeName(type_name):
+ type_code = TypeCode.Integral
+ elif type_name in ('__int128', 'unsigned __int128'):
+ type_code = TypeCode.Integral
+ elif type_name == 'void':
+ type_code = TypeCode.Void
+ elif type_name == 'wchar_t':
+ type_code = TypeCode.Integral
+ elif type_name in ("char16_t", "char32_t", "char8_t"):
+ type_code = TypeCode.Integral
else:
- self.warn('UNKNOWN TYPE KEY: %s: %s' % (typeName, code))
+ self.warn('UNKNOWN TYPE KEY: %s: %s' % (type_name, code))
elif code == lldb.eTypeClassEnumeration:
- tdata.code = TypeCode.Enum
- tdata.enumDisplay = lambda intval, addr, form: \
+ type_code = TypeCode.Enum
+ self.type_enum_display_cache[typeid] = lambda intval, addr, form: \
self.nativeTypeEnumDisplay(nativeType, intval, form)
elif code in (lldb.eTypeClassComplexInteger, lldb.eTypeClassComplexFloat):
- tdata.code = TypeCode.Complex
+ type_code = TypeCode.Complex
elif code in (lldb.eTypeClassClass, lldb.eTypeClassStruct, lldb.eTypeClassUnion):
- tdata.code = TypeCode.Struct
- tdata.lalignment = lambda: \
- self.nativeStructAlignment(nativeType)
- tdata.lfields = lambda value: \
- self.listMembers(value, nativeType)
- tdata.templateArguments = lambda: \
- self.listTemplateParametersHelper(nativeType)
+ type_code = TypeCode.Struct
elif code == lldb.eTypeClassFunction:
- tdata.code = TypeCode.Function
+ type_code = TypeCode.Function
elif code == lldb.eTypeClassMemberPointer:
- tdata.code = TypeCode.MemberPointer
- # warn('CREATE TYPE: %s' % typeId)
+ type_code = TypeCode.MemberPointer
+
+ if code is not None:
+ self.type_code_cache[typeid] = type_code
+
+ self.type_nativetype_cache[typeid] = nativeType
+ self.typeid_from_typekey[typeid_str] = typeid
+
+ # self.warn('REUSE TYPE: %s' % typeid)
+ return typeid
+
+ def nativeTemplateParameter(self, typeid, index, nativeType):
+ #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<std::pair<unsigned int const, float> report 0
+ # # for nativeType.GetNumberOfTemplateArguments() with LLDB 3.8
+ # return stringArgs
+
+ kind = nativeType.GetTemplateArgumentKind(index)
+ # eTemplateArgumentKindNull = 0,
+ # eTemplateArgumentKindType,
+ # eTemplateArgumentKindDeclaration,
+ # eTemplateArgumentKindIntegral,
+ # eTemplateArgumentKindTemplate,
+ # eTemplateArgumentKindTemplateExpansion,
+ # eTemplateArgumentKindExpression,
+ # eTemplateArgumentKindPack
+ if kind == lldb.eTemplateArgumentKindType:
+ innerType = nativeType.GetTemplateArgumentType(index) \
+ .GetUnqualifiedType().GetCanonicalType()
+ return self.Type(self, self.from_native_type(innerType))
+ #elif kind == lldb.eTemplateArgumentKindIntegral:
+ # innerType = nativeType.GetTemplateArgumentType(i).GetUnqualifiedType().GetCanonicalType()
+ # #DumperBase.warn('INNER TYP: %s' % innerType)
+ # basicType = innerType.GetBasicType()
+ # #DumperBase.warn('IBASIC TYP: %s' % basicType)
+ # inner = self.extractTemplateArgument(nativeType.GetName(), i)
+ # exp = '(%s)%s' % (innerType.GetName(), inner)
+ # #DumperBase.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
+ # #DumperBase.warn('KIND: %s' % kind)
+ # targs.append(value)
#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<std::pair<unsigned int const, float> 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()
- # #DumperBase.warn('INNER TYP: %s' % innerType)
- # basicType = innerType.GetBasicType()
- # #DumperBase.warn('IBASIC TYP: %s' % basicType)
- # inner = self.extractTemplateArgument(nativeType.GetName(), i)
- # exp = '(%s)%s' % (innerType.GetName(), inner)
- # #DumperBase.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
- # #DumperBase.warn('KIND: %s' % kind)
- # targs.append(value)
- else:
- #DumperBase.warn('UNHANDLED TEMPLATE TYPE : %s' % kind)
- targs.append(stringArgs[i]) # Best we can do.
+ # #DumperBase.warn('UNHANDLED TEMPLATE TYPE : %s' % kind)
+ # targs.append(stringArgs[i]) # Best we can do.
#DumperBase.warn('TARGS: %s %s' % (nativeType.GetName(), [str(x) for x in targs]))
- return targs
-
- def typeName(self, nativeType):
- # Don't use GetDisplayTypeName since LLDB removed the inline namespace __1
- # https://reviews.llvm.org/D74478
- return nativeType.GetName()
+ #return targs
+ return None
- def nativeTypeId(self, nativeType):
- if nativeType and (nativeType.GetTypeClass() == lldb.eTypeClassTypedef):
+ def native_type_key(self, nativeType):
+ code = nativeType.GetTypeClass()
+ if nativeType and code == lldb.eTypeClassTypedef:
nativeTargetType = nativeType.GetUnqualifiedType()
if hasattr(nativeTargetType, 'GetCanonicalType'):
nativeTargetType = nativeTargetType.GetCanonicalType()
return '%s{%s}' % (nativeType.name, nativeTargetType.name)
- name = self.typeName(nativeType)
+ # Don't use GetDisplayTypeName since LLDB removed the inline namespace __1
+ # https://reviews.llvm.org/D74478
+ name = nativeType.GetName()
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'
+ elif name == '(anonymous struct)':
+ c = 's' if code == lldb.eTypeClassStruct else 'u'
else:
return name
fields = nativeType.get_fields_array()
- typeId = c + ''.join(['{%s:%s}' % (f.name, self.nativeTypeId(f.GetType())) for f in fields])
- #DumperBase.warn('NATIVE TYPE ID FOR %s IS %s' % (name, typeId))
- return typeId
+ id_str = c + ''.join(['{%s:%s}' %
+ (f.name, self.typeid_for_string(self.native_type_key(f.GetType())))
+ for f in fields])
+ return id_str
def nativeTypeEnumDisplay(self, nativeType, intval, form):
if hasattr(nativeType, 'get_enum_members_array'):
@@ -575,12 +569,82 @@ class Dumper(DumperBase):
return '(' + ' | '.join(flags) + ') (' + (form % intval) + ')'
return form % intval
- def nativeDynamicTypeName(self, address, baseType):
- return None # FIXME: Seems sufficient, no idea why.
- addr = self.target.ResolveLoadAddress(address)
- ctx = self.target.ResolveSymbolContextForAddress(addr, 0)
- sym = ctx.GetSymbol()
- return sym.GetName()
+ def nativeDynamicType(self, address, base_typeid):
+ return self.nativeDynamicType_2(address, base_typeid)
+
+ def nativeDynamicType_1(self, address, base_typeid):
+ # Solutions 1: Breaks StdUniquePtr and QVariant1 test
+ return base_typeid
+
+ def nativeDynamicType_2(self, address, base_typeid):
+ # Solution 2: ~10% slower in total than Solution 1
+ typename = self.type_name(base_typeid)
+ #self.warn("LOOKING FOR DYN TYPE: 0x%x %s" % (address, typename))
+ #self.warn(" PRETTY: 0x%x %s" % (address, self.prettySymbolByAddress(address)))
+
+ expr = '(void*)%s' % address
+ value = self.target.EvaluateExpression(expr)
+
+ #self.warn("VALUE: %s" % value)
+ if value.GetType().GetName() == "void *":
+ #self.warn("NO DYN TYPE: %s" % value)
+ return base_typeid
+
+ dvalue = value.Dereference()
+ #self.warn("DVALUE: %s" % value)
+ sbtype = dvalue.GetType()
+ #self.warn("TYPE: %s" % sbtype)
+
+ #self.warn("OUTPUT: %s" % output)
+ #self.warn("DYNTYPE: %s" % dyn_typename)
+ return self.from_native_type(sbtype)
+
+ def nativeDynamicType_3(self, address, base_typeid):
+ # Solution 3: Doesn't improve over 1
+ typename = self.type_name(base_typeid)
+ self.warn("LOOKING FOR DYN TYPE: 0x%x %s" % (address, typename))
+ #self.warn(" PRETTY: 0x%x %s" % (address, self.prettySymbolByAddress(address)))
+ nativeType = self.type_nativetype_cache.get(base_typeid, None)
+ #self.warn(" NATIVE BASE %s" % nativeType)
+ if nativeType is None:
+ return base_typeid
+ #versionValue = self.target.EvaluateExpression('qtHookData[2]').GetNonSyntheticValue()
+ addr = lldb.SBAddress(address, self.target)
+ value = self.target.CreateValueFromAddress('x', addr, nativeType)
+ self.warn(" VALUE %s" % value)
+ return base_typeid
+
+ def nativeDynamicType_4(self, address, base_typeid):
+ #self.warn("RESULT: %s" % result)
+ #self.warn("ADDRESS: 0x%x" % address)
+
+ #thread = self.currentThread()
+ #frame = thread.GetFrameAtIndex(0)
+ #expr = '(void*)%s' % address
+ #value = self.target.EvaluateExpression(expr)
+ #sbtype = self.lookupNativeType(typename)
+ #addr = self.target.ResolveLoadAddress(address)
+ #addr = lldb.SBAddress(address, self.target)
+ #value = self.target.CreateValueFromAddress('x', addr, sbtype)
+ #x = lldb::DynamicValueType()
+ #lldb.eNoDynamicValues
+ #lldb.eDynamicCanRunTarget
+ #lldb.eDynamicDontRunTarget
+ #dyn_value = value.GetDynamicValue(lldb.eDynamicDontRunTarget)
+ #typ = dyn_value.GetType()
+ self.warn("GOT DYN VALUE: %s" % dyn_value)
+ #self.warn("GOT TYPE: %s FOR OBJECT AT 0x%x" % (typ, address))
+ return self.from_native_type(typ)
+
+ #result = lldb.SBCommandReturnObject()
+ #cmd = 'p (void*)%s' % address
+ #self.debugger.GetCommandInterpreter().HandleCommand(cmd, result)
+ #if not result.Succeeded():
+ # return self.Type(self, typeid)
+ #output = result.GetOutput().strip()
+ #dyn_typename = output[1:output.find('$') - 4]
+ #sbtype = self.lookupNativeType(dyn_typename)
+
def stateName(self, s):
try:
@@ -638,11 +702,11 @@ class Dumper(DumperBase):
#DumperBase.warn(' -> %s' % result)
return self.fromNativeValue(result)
- def pokeValue(self, typeName, *args):
+ def pokeValue(self, type_name, *args):
thread = self.currentThread()
frame = thread.GetFrameAtIndex(0)
inner = ','.join(args)
- value = frame.EvaluateExpression(typeName + '{' + inner + '}')
+ value = frame.EvaluateExpression(type_name + '{' + inner + '}')
#DumperBase.warn(' TYPE: %s' % value.type)
#DumperBase.warn(' ADDR: 0x%x' % value.address)
#DumperBase.warn(' VALUE: %s' % value)
@@ -830,8 +894,6 @@ class Dumper(DumperBase):
#DumperBase.warn('RECURSE PTR')
typeobj = self.lookupNativeType(name[:-1].strip())
if typeobj is not None:
- #DumperBase.warn('RECURSE RESULT X: %s' % typeobj)
- self.fromNativeType(typeobj.GetPointerType())
#DumperBase.warn('RECURSE RESULT: %s' % typeobj.GetPointerType())
return typeobj.GetPointerType()
@@ -1289,14 +1351,12 @@ class Dumper(DumperBase):
def findSymbol(self, symbolName):
return self.target.FindFirstGlobalVariable(symbolName)
- def warn(self, msg):
- self.put('{name="%s",value="",type="",numchild="0"},' % toCString(msg))
-
def fetchVariables(self, args):
- (ok, res) = self.tryFetchInterpreterVariables(args)
- if ok:
- self.reportResult(res, args)
- return
+ start_time = time.perf_counter()
+ #(ok, res) = self.tryFetchInterpreterVariables(args)
+ #if ok:
+ # self.reportResult(res, args)
+ # return
self.setVariableFetchingOptions(args)
@@ -1360,13 +1420,15 @@ class Dumper(DumperBase):
# This can happen for unnamed function parameters with
# default values: void foo(int = 0)
continue
- value = self.fromNativeFrameValue(val)
+ value = self.fromNativeValue(val)
variables.append(value)
self.handleLocals(variables)
self.handleWatches(args)
- self.put('],partial="%d"' % isPartial)
+ run_time = time.perf_counter() - start_time
+
+ self.put('],partial="%d",runtime="%s"' % (isPartial, run_time))
self.reportResult(self.takeOutput(), args)
@@ -1987,14 +2049,14 @@ class Dumper(DumperBase):
value = self.hexdecode(args['value'])
simpleType = int(args['simpleType'])
lhs = self.findValueByExpression(expr)
- typeName = lhs.GetType().GetName()
- typeName = typeName.replace('::', '__')
- pos = typeName.find('<')
+ type_name = lhs.GetType().GetName()
+ type_name = type_name.replace('::', '__')
+ pos = type_name.find('<')
if pos != -1:
- typeName = typeName[0:pos]
- if typeName in self.qqEditable and not simpleType:
+ type_name = type_name[0:pos]
+ if type_name in self.qqEditable and not simpleType:
expr = self.parseAndEvaluate(expr)
- self.qqEditable[typeName](self, expr, value)
+ self.qqEditable[type_name](self, expr, value)
else:
self.parseAndEvaluate(expr + '=' + value)
self.reportResult(self.describeError(error), args)
@@ -2098,10 +2160,10 @@ class Tester(Dumper):
if 'QT_CREATOR_LLDB_PROCESS' in os.environ:
# Initialize Qt Creator dumper
- try:
+ #try:
theDumper = Dumper()
- except Exception as error:
- print('@\nstate="enginesetupfailed",error="{}"@\n'.format(error))
+ #except Exception as error:
+ # print('@\nstate="enginesetupfailed",error="{}"@\n'.format(error))
# ------------------------------ For use in LLDB ------------------------------
diff --git a/share/qtcreator/debugger/qttypes.py b/share/qtcreator/debugger/qttypes.py
index 06e7d47325..af99534c9b 100644
--- a/share/qtcreator/debugger/qttypes.py
+++ b/share/qtcreator/debugger/qttypes.py
@@ -221,15 +221,15 @@ def qdump__Qt__ItemDataRole(d, value):
def qdump__QStandardItemData(d, value):
- d.createType('@Qt::ItemDataRole') # warm up cache
+ #d.createType('@Qt::ItemDataRole') # warm up cache
role, pad, val = value.split('{@Qt::ItemDataRole}@{@QVariant}')
d.putPairContents(role.value(), (role, val), 'role', 'value')
def qdump__QStandardItem(d, value):
- d.createType('@QStandardItemData') # warm up cache
- d.createType('@QStandardItem')
- d.createType('@QStandardItem*')
+ #d.createType('@QStandardItemData') # warm up cache
+ #d.createType('@QStandardItem')
+ #d.createType('@QStandardItem*')
vtable, dptr = value.split('pp')
if d.qtVersion() >= 0x060000:
@@ -549,14 +549,11 @@ def qdump__QDir(d, value):
#d.putCallItem('absolutePath', '@QString', value, 'absolutePath')
#d.putCallItem('canonicalPath', '@QString', value, 'canonicalPath')
with SubItem(d, 'absolutePath'):
- typ = d.lookupType(ns + 'QString')
- d.putItem(d.createValue(privAddress + absoluteDirEntryOffset, typ))
+ d.putItem(d.createValue(privAddress + absoluteDirEntryOffset, '@QString'))
with SubItem(d, 'entryInfoList'):
- typ = d.lookupType(ns + 'QFileInfo')
- qdumpHelper_QList(d, privAddress + fileInfosOffset, typ)
+ qdumpHelper_QList(d, privAddress + fileInfosOffset, '@QFileInfo')
with SubItem(d, 'entryList'):
- typ = d.lookupType(ns + 'QStringList')
- d.putItem(d.createValue(privAddress + filesOffset, typ))
+ d.putItem(d.createValue(privAddress + filesOffset, '@QStringList'))
d.putFields(value)
@@ -1095,14 +1092,15 @@ def qform__QList():
def qdump__QList(d, value):
- return qdumpHelper_QList(d, value, d.createType(value.type[0]))
+ return qdumpHelper_QList(d, value, value.type[0])
def qdump__QVariantList(d, value):
- qdumpHelper_QList(d, value, d.createType('@QVariant'))
+ qdumpHelper_QList(d, value, '@QVariant')
-def qdumpHelper_QList(d, value, innerType):
+def qdumpHelper_QList(d, value, inner_typish):
+ innerType = d.createType(inner_typish)
data, size = d.listData(value, check=True)
d.putItemCount(size)
@@ -1224,7 +1222,8 @@ def qdump__QLocale(d, value):
# index = int(value['d']['d']['m_data']...)
#d.check(index >= 0)
#d.check(index <= qqLocalesCount)
- if d.qtVersion() < 0x50000:
+ qtVersion = d.qtVersion()
+ if qtVersion < 0x50000:
d.putStringValue(d.call('const char *', value, 'name'))
d.putPlainChildren(value)
return
@@ -1238,14 +1237,20 @@ def qdump__QLocale(d, value):
= d.split('2s{short}2s'
+ '{@QChar}{@QChar}{short}{@QChar}{@QChar}'
+ '{@QChar}{@QChar}{@QChar}', data)
+
+ prefix = ns + 'QLocale::'
try:
- d.putStringValue(d.call('const char *', value, 'name'))
+ if qtVersion >= 0x060700:
+ res = d.call('const char *', value, 'name', prefix + 'TagSeparator::Underscore')
+ else:
+ res = d.call('const char *', value, 'name')
+ d.putStringValue(res)
except:
pass
+
d.putExpandable()
if d.isExpanded():
with Children(d):
- prefix = ns + 'QLocale::'
d.putSubItem('country', d.createValue(countryId, prefix + 'Country'))
d.putSubItem('language', d.createValue(languageId, prefix + 'Language'))
d.putSubItem('numberOptions', d.createValue(numberOptions, prefix + 'NumberOptions'))
@@ -1425,7 +1430,9 @@ if False:
d.putSpecialValue('minimumitemcount', 0)
-def qdump__QPair(d, value):
+# FIXME: Qt 5
+# remvign the _xxxx makes GDB work with Qt 5 but breaks LLDB
+def qdump__QPair_xxxx(d, value):
typeCode = '{%s}@{%s}' % (value.type[0].name, value.type[1].name)
first, pad, second = value.split(typeCode)
with Children(d):
@@ -1857,7 +1864,7 @@ def qdump__QStringRef(d, value):
def qdump__QStringList(d, value):
- qdumpHelper_QList(d, value, d.createType('@QString'))
+ qdumpHelper_QList(d, value, '@QString')
d.putBetterType(value.type)
@@ -2304,22 +2311,22 @@ def qdump__QVector(d, value):
if d.qtVersion() >= 0x060000:
data, length = d.listData(value)
d.putItemCount(length)
- d.putPlotData(data, length, d.createType(value.type.ltarget[0]))
+ d.putPlotData(data, length, value.type.target()[0])
# g++ 9.3 does not add the template parameter list to the debug info.
# Fake it for the common case:
if value.type.name == d.qtNamespace() + "QVector":
- d.putBetterType(value.type.name + '<' + value.type.ltarget[0].name + '>')
+ d.putBetterType(value.type.name + '<' + value.type.target()[0].name + '>')
else:
data, length = d.vectorData(value)
d.putItemCount(length)
- d.putPlotData(data, length, d.createType(value.type[0]))
+ d.putPlotData(data, length, value.type[0])
if False:
def qdump__QObjectConnectionList(d, value):
data, length = d.vectorData(value)
d.putItemCount(length)
- d.putPlotData(data, length, d.createType('@QObjectPrivate::ConnectionList'))
+ d.putPlotData(data, length, '@QObjectPrivate::ConnectionList')
def qdump__QVarLengthArray(d, value):
@@ -2913,15 +2920,13 @@ def qdump_64__QJSValue_6(d, value):
elif typ > 7:
val = d.Value(d)
val.ldata = struct.pack('q', dd ^ 0xfffc000000000000)
- val._type = d.createType('double')
- d.putItem(val)
+ d.putItem(val.cast('double'))
d.putType(value.type.name + ' (double)')
elif typ <= 3: # Heap
if dd & 1: # String
val = d.Value(d)
val.ldata = struct.pack('q', dd & ~1)
- val._type = d.createType('@QString*')
- d.putItem(val)
+ d.putItem(val.cast('@QString*'))
d.putType(value.type.name + ' (QString)')
else:
# FIXME: Arrays, Objects missing.
@@ -2955,16 +2960,13 @@ def qdump_64__QJSValue_6(d, value):
val = d.Value(d)
val.ldata = struct.pack('q', pointer)
if typ == 1:
- val._type = d.createType('double*')
- d.putItem(val)
+ d.putItem(val.cast('double*'))
d.putType(value.type.name + ' (double)')
elif typ == 3:
- val._type = d.createType('@QV4::Value*')
- d.putItem(val)
+ d.putItem(val.cast('@QV4::Value*'))
d.putType(value.type.name + ' (QV4::Value)')
elif typ == 5:
- val._type = d.createType('@QString*')
- d.putItem(val)
+ d.putItem(val.cast('@QString*'))
d.putType(value.type.name + ' (QString)')
else:
@@ -3538,7 +3540,7 @@ def qdump__QCborValue(d, value):
d.putPlainChildren(value)
def qdump__QCborValue_proxy(d, value):
- item_data, container_ptr, item_type, is_cbor = value.data()
+ item_data, container_ptr, item_type, is_cbor = value.ldata
def typename(key, is_cbor):
if is_cbor: