Debugger: defer type look up

Change-Id: I425c2bfc3c88ebf46af161c5434c0c05a3bb9c97
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
David Schulz
2024-02-12 14:03:00 +01:00
parent 5152a35048
commit a57a925b76
5 changed files with 533 additions and 77 deletions

View File

@@ -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.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

View File

@@ -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())

View File

@@ -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

View File

@@ -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,23 +299,7 @@ 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;
@@ -323,8 +310,8 @@ int PyType::code() const
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 */
};

View File

@@ -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
{