forked from qt-creator/qt-creator
Debugger: defer type look up
Change-Id: I425c2bfc3c88ebf46af161c5434c0c05a3bb9c97 Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -11,7 +11,7 @@ from utils import TypeCode
|
||||
|
||||
sys.path.insert(1, os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))))
|
||||
|
||||
from dumper import DumperBase, SubItem
|
||||
from dumper import DumperBase, SubItem, Children, DisplayFormat, UnnamedSubItem
|
||||
|
||||
|
||||
class FakeVoidType(cdbext.Type):
|
||||
@@ -84,10 +84,9 @@ class Dumper(DumperBase):
|
||||
self.check(isinstance(nativeValue, cdbext.Value))
|
||||
val = self.Value(self)
|
||||
val.name = nativeValue.name()
|
||||
val._type = self.fromNativeType(nativeValue.type())
|
||||
# There is no cdb api for the size of bitfields.
|
||||
# Workaround this issue by parsing the native debugger text for integral types.
|
||||
if val._type.code == TypeCode.Integral:
|
||||
if nativeValue.type().code() == TypeCode.Integral:
|
||||
try:
|
||||
integerString = nativeValue.nativeDebuggerValue()
|
||||
except UnicodeDecodeError:
|
||||
@@ -106,16 +105,18 @@ class Dumper(DumperBase):
|
||||
base = 16
|
||||
else:
|
||||
base = 10
|
||||
signed = not val._type.name.startswith('unsigned')
|
||||
signed = not nativeValue.type().name().startswith('unsigned')
|
||||
try:
|
||||
val.ldata = int(integerString, base).to_bytes(val._type.size(),
|
||||
val.ldata = int(integerString, base).to_bytes((nativeValue.type().bitsize() +7) // 8,
|
||||
byteorder='little', signed=signed)
|
||||
except:
|
||||
# read raw memory in case the integerString can not be interpreted
|
||||
pass
|
||||
if val._type.code == TypeCode.Enum:
|
||||
if nativeValue.type().code() == TypeCode.Enum:
|
||||
val.ldisplay = self.enumValue(nativeValue)
|
||||
val.isBaseClass = val.name == val._type.name
|
||||
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.nativeValue = nativeValue
|
||||
val.laddress = nativeValue.address()
|
||||
val.lbitsize = nativeValue.bitsize()
|
||||
@@ -136,6 +137,9 @@ class Dumper(DumperBase):
|
||||
for f in nativeType.fields()])
|
||||
return typeId
|
||||
|
||||
def nativeValueType(self, nativeValue):
|
||||
return self.fromNativeType(nativeValue.type())
|
||||
|
||||
def fromNativeType(self, nativeType):
|
||||
self.check(isinstance(nativeType, cdbext.Type))
|
||||
typeId = self.nativeTypeId(nativeType)
|
||||
@@ -150,51 +154,66 @@ class Dumper(DumperBase):
|
||||
if nativeType.name().startswith('<function>'):
|
||||
code = TypeCode.Function
|
||||
elif nativeType.targetName() != nativeType.name():
|
||||
targetType = self.lookupType(nativeType.targetName(), nativeType.moduleId())
|
||||
if targetType is not None and targetType is not nativeType:
|
||||
return self.createPointerType(targetType)
|
||||
return self.createPointerType(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 '):
|
||||
targetType = self.lookupType(nativeType.targetName(), nativeType.moduleId())
|
||||
if targetType is not None:
|
||||
return self.createArrayType(targetType, nativeType.arrayElements())
|
||||
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)
|
||||
|
||||
code = TypeCode.Struct
|
||||
|
||||
tdata = self.TypeData(self, typeId)
|
||||
tdata.name = nativeType.name()
|
||||
tdata.lbitsize = nativeType.bitsize()
|
||||
tdata.lbitsize = lambda: nativeType.bitsize()
|
||||
tdata.code = code
|
||||
tdata.moduleName = nativeType.module()
|
||||
tdata.moduleName = lambda: nativeType.module()
|
||||
if code == TypeCode.Struct:
|
||||
tdata.lfields = lambda value: \
|
||||
self.listFields(nativeType, value)
|
||||
tdata.lalignment = lambda: \
|
||||
self.nativeStructAlignment(nativeType)
|
||||
if code == TypeCode.Enum:
|
||||
tdata.enumDisplay = lambda intval, addr, form: \
|
||||
self.nativeTypeEnumDisplay(nativeType, intval, form)
|
||||
tdata.enumDisplay = lambda intval, addr, form: \
|
||||
self.nativeTypeEnumDisplay(nativeType, intval, form)
|
||||
tdata.templateArguments = lambda: \
|
||||
self.listTemplateParameters(nativeType.name())
|
||||
return self.Type(self, typeId)
|
||||
|
||||
def listFields(self, nativeType, value):
|
||||
if value.address() is None or value.address() == 0:
|
||||
raise Exception("")
|
||||
nativeValue = value.nativeValue
|
||||
if nativeValue is None:
|
||||
nativeValue = cdbext.createValue(value.address(), nativeType)
|
||||
def listNativeValueChildren(self, nativeValue):
|
||||
index = 0
|
||||
nativeMember = nativeValue.childFromIndex(index)
|
||||
while nativeMember is not None:
|
||||
while nativeMember:
|
||||
if nativeMember.address() != 0:
|
||||
yield self.fromNativeValue(nativeMember)
|
||||
index += 1
|
||||
nativeMember = nativeValue.childFromIndex(index)
|
||||
|
||||
def listValueChildren(self, value):
|
||||
nativeValue = value.nativeValue
|
||||
if nativeValue is None:
|
||||
nativeValue = cdbext.createValue(value.address(), self.lookupNativeType(value.type.name, 0))
|
||||
return self.listNativeValueChildren(nativeValue)
|
||||
|
||||
def listFields(self, nativeType, value):
|
||||
nativeValue = value.nativeValue
|
||||
if nativeValue is None:
|
||||
nativeValue = cdbext.createValue(value.address(), nativeType)
|
||||
return self.listNativeValueChildren(nativeValue)
|
||||
|
||||
def nativeStructAlignment(self, nativeType):
|
||||
#DumperBase.warn("NATIVE ALIGN FOR %s" % nativeType.name)
|
||||
def handleItem(nativeFieldType, align):
|
||||
@@ -307,6 +326,7 @@ class Dumper(DumperBase):
|
||||
namespaceIndex = name.find('::')
|
||||
if namespaceIndex > 0:
|
||||
namespace = name[:namespaceIndex + 2]
|
||||
self.qtNamespace = lambda: namespace
|
||||
self.qtCustomEventFunc = self.parseAndEvaluate(
|
||||
'%s!%sQObject::customEvent' %
|
||||
(self.qtCoreModuleName(), namespace)).address()
|
||||
@@ -498,7 +518,7 @@ class Dumper(DumperBase):
|
||||
else:
|
||||
val = self.Value(self)
|
||||
val.laddress = value.pointer()
|
||||
val._type = value.type.dereference()
|
||||
val._type = DumperBase.Type(self, value.type.targetName)
|
||||
val.nativeValue = value.nativeValue
|
||||
|
||||
return val
|
||||
@@ -519,3 +539,424 @@ class Dumper(DumperBase):
|
||||
def symbolAddress(self, symbolName):
|
||||
res = self.nativeParseAndEvaluate(symbolName)
|
||||
return None if res is None else res.address()
|
||||
|
||||
def putItemX(self, value):
|
||||
#DumperBase.warn('PUT ITEM: %s' % value.stringify())
|
||||
|
||||
typeobj = value.type # unqualified()
|
||||
typeName = typeobj.name
|
||||
|
||||
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))
|
||||
|
||||
# Try on possibly typedefed type first.
|
||||
if self.tryPutPrettyItem(typeName, value):
|
||||
if typeobj.code == TypeCode.Pointer:
|
||||
self.putOriginalAddress(value.address())
|
||||
else:
|
||||
self.putAddress(value.address())
|
||||
return
|
||||
|
||||
if typeobj.code == TypeCode.Pointer:
|
||||
self.putFormattedPointer(value)
|
||||
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())
|
||||
self.putNumChild(0)
|
||||
return
|
||||
|
||||
if typeobj.code == TypeCode.Enum:
|
||||
#DumperBase.warn('ENUM VALUE: %s' % value.stringify())
|
||||
self.putType(typeobj.name)
|
||||
self.putValue(value.display())
|
||||
self.putNumChild(0)
|
||||
return
|
||||
|
||||
if typeobj.code == TypeCode.Array:
|
||||
#DumperBase.warn('ARRAY VALUE: %s' % value)
|
||||
self.putCStyleArray(value)
|
||||
return
|
||||
|
||||
if typeobj.code == TypeCode.Integral:
|
||||
#DumperBase.warn('INTEGER: %s %s' % (value.name, value))
|
||||
val = value.value()
|
||||
self.putNumChild(0)
|
||||
self.putValue(val)
|
||||
self.putType(typeName)
|
||||
return
|
||||
|
||||
if typeobj.code == TypeCode.Float:
|
||||
#DumperBase.warn('FLOAT VALUE: %s' % value)
|
||||
self.putValue(value.value())
|
||||
self.putNumChild(0)
|
||||
self.putType(typeobj.name)
|
||||
return
|
||||
|
||||
if typeobj.code in (TypeCode.Reference, TypeCode.RValueReference):
|
||||
#DumperBase.warn('REFERENCE VALUE: %s' % value)
|
||||
val = value.dereference()
|
||||
if val.laddress != 0:
|
||||
self.putItem(val)
|
||||
else:
|
||||
self.putSpecialValue('nullreference')
|
||||
self.putBetterType(typeName)
|
||||
return
|
||||
|
||||
if typeobj.code == TypeCode.Complex:
|
||||
self.putType(typeobj)
|
||||
self.putValue(value.display())
|
||||
self.putNumChild(0)
|
||||
return
|
||||
|
||||
self.putType(typeName)
|
||||
|
||||
if value.summary is not None and self.useFancy:
|
||||
self.putValue(self.hexencode(value.summary), 'utf8:1:0')
|
||||
self.putNumChild(0)
|
||||
return
|
||||
|
||||
self.putExpandable()
|
||||
self.putEmptyValue()
|
||||
#DumperBase.warn('STRUCT GUTS: %s ADDRESS: 0x%x ' % (value.name, value.address()))
|
||||
if self.showQObjectNames:
|
||||
#with self.timer(self.currentIName):
|
||||
self.putQObjectNameValue(value)
|
||||
if self.isExpanded():
|
||||
self.putField('sortable', 1)
|
||||
with Children(self):
|
||||
baseIndex = 0
|
||||
for item in self.listValueChildren(value):
|
||||
if item.name.startswith('__vfptr'):
|
||||
with SubItem(self, '[vptr]'):
|
||||
# int (**)(void)
|
||||
self.putType(' ')
|
||||
self.putSortGroup(20)
|
||||
self.putValue(item.name)
|
||||
n = 100
|
||||
if self.isExpanded():
|
||||
with Children(self):
|
||||
n = self.putVTableChildren(item, n)
|
||||
self.putNumChild(n)
|
||||
continue
|
||||
|
||||
if item.isBaseClass:
|
||||
baseIndex += 1
|
||||
# We cannot use nativeField.name as part of the iname as
|
||||
# it might contain spaces and other strange characters.
|
||||
with UnnamedSubItem(self, "@%d" % baseIndex):
|
||||
self.putField('iname', self.currentIName)
|
||||
self.putField('name', '[%s]' % item.name)
|
||||
self.putSortGroup(1000 - baseIndex)
|
||||
self.putAddress(item.address())
|
||||
self.putItem(item)
|
||||
continue
|
||||
|
||||
|
||||
with SubItem(self, item.name):
|
||||
self.putItem(item)
|
||||
if self.showQObjectNames:
|
||||
self.tryPutQObjectGuts(value)
|
||||
|
||||
|
||||
def putFormattedPointerX(self, value: DumperBase.Value):
|
||||
self.putOriginalAddress(value.address())
|
||||
pointer = value.pointer()
|
||||
self.putAddress(pointer)
|
||||
if pointer == 0:
|
||||
self.putType(value.type)
|
||||
self.putValue('0x0')
|
||||
return
|
||||
|
||||
typeName = value.type.name
|
||||
|
||||
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.putValue('0x%x' % pointer)
|
||||
self.putType(typeName)
|
||||
return
|
||||
|
||||
if self.currentIName.endswith('.this'):
|
||||
self.putDerefedPointer(value)
|
||||
return
|
||||
|
||||
displayFormat = self.currentItemFormat(value.type.name)
|
||||
|
||||
if value.type.targetName == 'void':
|
||||
#DumperBase.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.putValue('0x%x' % pointer)
|
||||
self.putExpandable()
|
||||
if self.currentIName in self.expandedINames:
|
||||
with Children(self):
|
||||
with SubItem(self, '*'):
|
||||
self.putItem(value.dereference())
|
||||
return
|
||||
|
||||
limit = self.displayStringLimit
|
||||
if displayFormat in (DisplayFormat.SeparateLatin1String, DisplayFormat.SeparateUtf8String):
|
||||
limit = 1000000
|
||||
if self.tryPutSimpleFormattedPointer(pointer, typeName,
|
||||
value.type.targetName, 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.putItemCount(n)
|
||||
self.putArrayData(value.pointer(), n, value.type.targetName)
|
||||
return
|
||||
|
||||
#DumperBase.warn('AUTODEREF: %s' % self.autoDerefPointers)
|
||||
#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 (
|
||||
'char',
|
||||
'signed char',
|
||||
'int8_t',
|
||||
'qint8',
|
||||
'unsigned char',
|
||||
'uint8_t',
|
||||
'quint8',
|
||||
'wchar_t',
|
||||
'CHAR',
|
||||
'WCHAR',
|
||||
'char8_t',
|
||||
'char16_t',
|
||||
'char32_t'
|
||||
):
|
||||
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.putSymbolValue(pointer)
|
||||
self.putExpandable()
|
||||
if self.currentIName in self.expandedINames:
|
||||
with Children(self):
|
||||
with SubItem(self, '*'):
|
||||
self.putItem(value.dereference())
|
||||
|
||||
|
||||
def putCStyleArray(self, value):
|
||||
arrayType = value.type
|
||||
innerType = arrayType.ltarget
|
||||
address = value.address()
|
||||
if address:
|
||||
self.putValue('@0x%x' % address, priority=-1)
|
||||
else:
|
||||
self.putEmptyValue()
|
||||
self.putType(arrayType)
|
||||
|
||||
displayFormat = self.currentItemFormat()
|
||||
arrayByteSize = arrayType.size()
|
||||
n = self.arrayItemCountFromTypeName(value.type.name, 100)
|
||||
|
||||
p = value.address()
|
||||
if displayFormat != DisplayFormat.Raw and p:
|
||||
if innerType.name in (
|
||||
'char',
|
||||
'int8_t',
|
||||
'qint8',
|
||||
'wchar_t',
|
||||
'unsigned char',
|
||||
'uint8_t',
|
||||
'quint8',
|
||||
'signed char',
|
||||
'CHAR',
|
||||
'WCHAR',
|
||||
'char8_t',
|
||||
'char16_t',
|
||||
'char32_t'
|
||||
):
|
||||
self.putCharArrayHelper(p, n, innerType, self.currentItemFormat(),
|
||||
makeExpandable=False)
|
||||
else:
|
||||
self.tryPutSimpleFormattedPointer(p, arrayType, innerType,
|
||||
displayFormat, arrayByteSize)
|
||||
self.putNumChild(n)
|
||||
|
||||
if self.isExpanded():
|
||||
if n > 100:
|
||||
addrStep = innerType.size()
|
||||
with Children(self, n, innerType, addrBase=address, addrStep=addrStep):
|
||||
for i in self.childRange():
|
||||
self.putSubItem(i, self.createValue(address + i * addrStep, innerType))
|
||||
else:
|
||||
with Children(self):
|
||||
n = 0
|
||||
for item in self.listValueChildren(value):
|
||||
with SubItem(self, n):
|
||||
n += 1
|
||||
self.putItem(item)
|
||||
|
||||
|
||||
def putArrayData(self, base, n, innerType, childNumChild=None):
|
||||
self.checkIntType(base)
|
||||
self.checkIntType(n)
|
||||
addrBase = base
|
||||
innerType = self.createType(innerType)
|
||||
innerSize = innerType.size()
|
||||
self.putNumChild(n)
|
||||
#DumperBase.warn('ADDRESS: 0x%x INNERSIZE: %s INNERTYPE: %s' % (addrBase, innerSize, innerType))
|
||||
enc = innerType.simpleEncoding()
|
||||
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('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('",')
|
||||
else:
|
||||
with Children(self, n, innerType, childNumChild, maxNumChild,
|
||||
addrBase=addrBase, addrStep=innerSize):
|
||||
for i in self.childRange():
|
||||
self.putSubItem(i, self.createValue(addrBase + i * innerSize, innerType))
|
||||
|
||||
def tryPutSimpleFormattedPointer(self, ptr, typeName, innerType, displayFormat, limit):
|
||||
if isinstance(innerType, self.Type):
|
||||
innerType = innerType.name
|
||||
if displayFormat == DisplayFormat.Automatic:
|
||||
if innerType in ('char', 'signed char', 'unsigned char', 'uint8_t', 'CHAR'):
|
||||
# Use UTF-8 as default for char *.
|
||||
self.putType(typeName)
|
||||
(length, shown, data) = self.readToFirstZero(ptr, 1, limit)
|
||||
self.putValue(data, 'utf8', length=length)
|
||||
if self.isExpanded():
|
||||
self.putArrayData(ptr, shown, innerType)
|
||||
return True
|
||||
|
||||
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)
|
||||
return True
|
||||
|
||||
if displayFormat == DisplayFormat.Latin1String:
|
||||
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)
|
||||
(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)
|
||||
(length, data) = self.encodeCArray(ptr, 1, limit)
|
||||
self.putValue(data, 'utf8', length=length)
|
||||
return True
|
||||
|
||||
if displayFormat == DisplayFormat.SeparateUtf8String:
|
||||
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)
|
||||
(length, data) = self.encodeCArray(ptr, 1, limit)
|
||||
self.putValue(data, 'local8bit', length=length)
|
||||
return True
|
||||
|
||||
if displayFormat == DisplayFormat.Utf16String:
|
||||
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)
|
||||
(length, data) = self.encodeCArray(ptr, 4, limit)
|
||||
self.putValue(data, 'ucs4', length=length)
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def putDerefedPointer(self, value):
|
||||
derefValue = value.dereference()
|
||||
savedCurrentChildType = self.currentChildType
|
||||
self.currentChildType = value.type.targetName
|
||||
self.putType(value.type.targetName)
|
||||
derefValue.name = '*'
|
||||
derefValue.autoDerefCount = value.autoDerefCount + 1
|
||||
|
||||
if derefValue.type.code == TypeCode.Pointer:
|
||||
self.putField('autoderefcount', '{}'.format(derefValue.autoDerefCount))
|
||||
|
||||
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.
|
||||
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)
|
||||
#DumperBase.warn('CREATING %s WITH DATA %s' % (val.type.name, self.hexencode(datish)))
|
||||
val.ldata = datish
|
||||
val.check()
|
||||
return val
|
||||
raise RuntimeError('EXPECTING ADDRESS OR BYTES, GOT %s' % type(datish))
|
||||
|
||||
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.laddress = address
|
||||
if self.useDynamicType:
|
||||
val._type = val.type.dynamicType(address)
|
||||
return val
|
||||
|
@@ -3041,7 +3041,7 @@ class DumperBase():
|
||||
or self.type.name.startswith('unsigned ') \
|
||||
or self.type.name.find(' unsigned ') != -1
|
||||
if bitsize is None:
|
||||
bitsize = self.type.bitsize()
|
||||
bitsize = self.type.lbitsize
|
||||
return self.extractInteger(bitsize, unsigned)
|
||||
|
||||
def floatingPoint(self):
|
||||
@@ -3512,26 +3512,40 @@ class DumperBase():
|
||||
tdata.moduleName = self.moduleName
|
||||
return tdata
|
||||
|
||||
@property
|
||||
def bitsize(self):
|
||||
if callable(self.lbitsize):
|
||||
self.lbitsize = self.lbitsize()
|
||||
return self.lbitsize
|
||||
|
||||
class Type():
|
||||
def __init__(self, dumper, typeId):
|
||||
self.typeId = typeId
|
||||
self.typeId = typeId.replace('@', dumper.qtNamespace())
|
||||
self.dumper = dumper
|
||||
self.tdata = dumper.typeData.get(typeId, None)
|
||||
if self.tdata is None:
|
||||
#DumperBase.warn('USING : %s' % self.typeId)
|
||||
self.dumper.lookupType(self.typeId)
|
||||
self.tdata = self.dumper.typeData.get(self.typeId)
|
||||
self.initialized = False
|
||||
|
||||
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
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
tdata = self.dumper.typeData.get(self.typeId)
|
||||
if tdata is None:
|
||||
return self.typeId
|
||||
return tdata.name
|
||||
return self.typeId if self.tdata is None else self.tdata.name
|
||||
|
||||
@property
|
||||
def code(self):
|
||||
@@ -3539,7 +3553,7 @@ class DumperBase():
|
||||
|
||||
@property
|
||||
def lbitsize(self):
|
||||
return self.tdata.lbitsize
|
||||
return self.tdata.bitsize
|
||||
|
||||
@property
|
||||
def lbitpos(self):
|
||||
@@ -3547,15 +3561,25 @@ class DumperBase():
|
||||
|
||||
@property
|
||||
def ltarget(self):
|
||||
if isinstance(self.tdata.ltarget, str):
|
||||
self.tdata.ltarget = self.dumper.createType(self.tdata.ltarget)
|
||||
return self.tdata.ltarget
|
||||
|
||||
@property
|
||||
def targetName(self):
|
||||
if self.tdata.ltarget is None:
|
||||
return ''
|
||||
return self.tdata.ltarget if isinstance(self.tdata.ltarget, str) else self.tdata.ltarget.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.tdata.lbitsize, self.tdata.code)
|
||||
% (self.tdata.name, self.lbitsize, self.tdata.code)
|
||||
|
||||
def __getitem__(self, index):
|
||||
if self.dumper.isInt(index):
|
||||
@@ -3659,7 +3683,7 @@ class DumperBase():
|
||||
|
||||
def alignment(self):
|
||||
if self.tdata.code == TypeCode.Typedef:
|
||||
return self.tdata.ltarget.alignment()
|
||||
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.
|
||||
@@ -3678,7 +3702,7 @@ class DumperBase():
|
||||
return self.dumper.createPointerType(self)
|
||||
|
||||
def target(self):
|
||||
return self.tdata.ltarget
|
||||
return self.ltarget
|
||||
|
||||
def stripTypedefs(self):
|
||||
if isinstance(self, self.dumper.Type) and self.code != TypeCode.Typedef:
|
||||
@@ -3687,7 +3711,7 @@ class DumperBase():
|
||||
return self.ltarget
|
||||
|
||||
def size(self):
|
||||
bs = self.bitsize()
|
||||
bs = self.lbitsize
|
||||
if bs % 8 != 0:
|
||||
DumperBase.warn('ODD SIZE: %s' % self)
|
||||
return (7 + bs) >> 3
|
||||
@@ -3797,12 +3821,12 @@ class DumperBase():
|
||||
return val
|
||||
|
||||
def createPointerType(self, targetType):
|
||||
if not isinstance(targetType, self.Type):
|
||||
raise RuntimeError('Expected type in createPointerType(), got %s'
|
||||
if not isinstance(targetType, (str, self.Type)):
|
||||
raise RuntimeError('Expected type or str in createPointerType(), got %s'
|
||||
% type(targetType))
|
||||
typeId = targetType.typeId + ' *'
|
||||
typeId = (targetType if isinstance(targetType, str) else targetType.typeId) + ' *'
|
||||
tdata = self.TypeData(self, typeId)
|
||||
tdata.name = targetType.name + '*'
|
||||
tdata.name = (targetType if isinstance(targetType, str) else targetType.name) + '*'
|
||||
tdata.lbitsize = 8 * self.ptrSize()
|
||||
tdata.code = TypeCode.Pointer
|
||||
tdata.ltarget = targetType
|
||||
@@ -3927,7 +3951,7 @@ class DumperBase():
|
||||
tdata = self.typeData.get(typish, None)
|
||||
if tdata is not None:
|
||||
if tdata.lbitsize is not None:
|
||||
if tdata.lbitsize > 0:
|
||||
if callable(tdata.lbitsize) or tdata.lbitsize > 0:
|
||||
return self.Type(self, typish)
|
||||
|
||||
knownType = self.lookupType(typish)
|
||||
@@ -3944,7 +3968,7 @@ class DumperBase():
|
||||
if typish.endswith('*'):
|
||||
tdata.code = TypeCode.Pointer
|
||||
tdata.lbitsize = 8 * self.ptrSize()
|
||||
tdata.ltarget = self.createType(typish[:-1].strip())
|
||||
tdata.ltarget = typish[:-1].strip()
|
||||
|
||||
typeobj = self.Type(self, tdata.typeId)
|
||||
#DumperBase.warn('CREATE TYPE: %s' % typeobj.stringify())
|
||||
|
@@ -419,7 +419,7 @@ class Dumper(DumperBase):
|
||||
targetTypeName = typeName[0:pos1].strip()
|
||||
#DumperBase.warn("TARGET TYPENAME: %s" % targetTypeName)
|
||||
targetType = self.fromNativeType(nativeTargetType)
|
||||
targetType.tdata = targetType.tdata.copy()
|
||||
targetType.setTdata(targetType.tdata.copy())
|
||||
targetType.tdata.name = targetTypeName
|
||||
return self.createArrayType(targetType, count)
|
||||
if hasattr(nativeType, 'GetVectorElementType'): # New in 3.8(?) / 350.x
|
||||
|
@@ -121,6 +121,9 @@ static std::string stripPointerType(const std::string &typeNameIn)
|
||||
std::string typeName = typeNameIn;
|
||||
if (typeName.back() == '*') {
|
||||
typeName.pop_back();
|
||||
trimBack(typeName);
|
||||
if (endsWith(typeName, "const"))
|
||||
typeName = typeName.erase(typeName.size() - 5, 5);
|
||||
} else {
|
||||
const auto arrayPosition = typeName.find_first_of('[');
|
||||
if (arrayPosition != std::string::npos
|
||||
@@ -296,35 +299,19 @@ int PyType::code() const
|
||||
return std::nullopt;
|
||||
};
|
||||
|
||||
if (!resolve())
|
||||
return parseTypeName(name()).value_or(TypeCodeUnresolvable);
|
||||
|
||||
if (m_tag < 0) {
|
||||
if (const std::optional<TypeCodes> typeCode = parseTypeName(name()))
|
||||
return *typeCode;
|
||||
|
||||
IDebugSymbolGroup2 *sg = 0;
|
||||
if (FAILED(ExtensionCommandContext::instance()->symbols()->CreateSymbolGroup2(&sg)))
|
||||
return TypeCodeStruct;
|
||||
|
||||
const std::string helperValueName = SymbolGroupValue::pointedToSymbolName(0, name(true));
|
||||
ULONG index = DEBUG_ANY_ID;
|
||||
if (SUCCEEDED(sg->AddSymbol(helperValueName.c_str(), &index)))
|
||||
m_tag = PyValue(index, sg).tag();
|
||||
sg->Release();
|
||||
if (m_tag >= 0) {
|
||||
switch (m_tag) {
|
||||
case SymTagUDT: return TypeCodeStruct;
|
||||
case SymTagEnum: return TypeCodeEnum;
|
||||
case SymTagTypedef: return TypeCodeTypedef;
|
||||
case SymTagFunctionType: return TypeCodeFunction;
|
||||
case SymTagPointerType: return TypeCodePointer;
|
||||
case SymTagArrayType: return TypeCodeArray;
|
||||
case SymTagBaseType: return isIntegralType(name()) ? TypeCodeIntegral : TypeCodeFloat;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
switch (m_tag) {
|
||||
case SymTagUDT: return TypeCodeStruct;
|
||||
case SymTagEnum: return TypeCodeEnum;
|
||||
case SymTagTypedef: return TypeCodeTypedef;
|
||||
case SymTagFunctionType: return TypeCodeFunction;
|
||||
case SymTagPointerType: return TypeCodePointer;
|
||||
case SymTagArrayType: return TypeCodeArray;
|
||||
case SymTagBaseType: return isIntegralType(name()) ? TypeCodeIntegral : TypeCodeFloat;
|
||||
default: break;
|
||||
}
|
||||
|
||||
return TypeCodeStruct;
|
||||
return parseTypeName(name()).value_or(TypeCodeStruct);
|
||||
}
|
||||
|
||||
PyType PyType::target() const
|
||||
@@ -533,6 +520,7 @@ PY_FUNC_RET_OBJECT_LIST(fields, PY_OBJ_NAME)
|
||||
PY_FUNC_RET_STD_STRING(module, PY_OBJ_NAME)
|
||||
PY_FUNC(moduleId, PY_OBJ_NAME, "K")
|
||||
PY_FUNC(arrayElements, PY_OBJ_NAME, "k")
|
||||
PY_FUNC_RET_BOOL(resolved, PY_OBJ_NAME)
|
||||
PY_FUNC_DECL(templateArguments, PY_OBJ_NAME)
|
||||
{
|
||||
PY_IMPL_GUARD;
|
||||
@@ -568,6 +556,8 @@ static PyMethodDef typeMethods[] = {
|
||||
"Returns the number of elements in an array or 0 for non array types"},
|
||||
{"templateArguments", PyCFunction(templateArguments), METH_NOARGS,
|
||||
"Returns all template arguments."},
|
||||
{"resolved", PyCFunction(resolved), METH_NOARGS,
|
||||
"Returns whether the type is resolved"},
|
||||
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
@@ -29,6 +29,7 @@ public:
|
||||
std::string module() const;
|
||||
ULONG64 moduleId() const;
|
||||
int arrayElements() const;
|
||||
bool resolved() const { return m_resolved.value_or(false); }
|
||||
|
||||
struct TemplateArgument
|
||||
{
|
||||
|
Reference in New Issue
Block a user