2016-10-06 13:36:02 +02:00
|
|
|
# Copyright (C) 2016 The Qt Company Ltd.
|
2023-01-04 08:52:22 +01:00
|
|
|
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
2016-10-06 13:36:02 +02:00
|
|
|
|
|
|
|
import inspect
|
|
|
|
import os
|
|
|
|
import sys
|
|
|
|
import cdbext
|
2017-01-13 09:08:17 +01:00
|
|
|
import re
|
2020-02-24 10:14:27 +01:00
|
|
|
import threading
|
2020-02-21 10:10:00 +01:00
|
|
|
from utils import TypeCode
|
2016-10-06 13:36:02 +02:00
|
|
|
|
|
|
|
sys.path.insert(1, os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))))
|
|
|
|
|
2020-02-24 10:14:27 +01:00
|
|
|
from dumper import DumperBase, SubItem
|
2016-10-06 13:36:02 +02:00
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
|
2016-10-28 14:50:10 +02:00
|
|
|
class FakeVoidType(cdbext.Type):
|
2020-02-24 14:37:56 +01:00
|
|
|
def __init__(self, name, dumper):
|
2016-10-28 14:50:10 +02:00
|
|
|
cdbext.Type.__init__(self)
|
|
|
|
self.typeName = name.strip()
|
|
|
|
self.dumper = dumper
|
|
|
|
|
|
|
|
def name(self):
|
|
|
|
return self.typeName
|
|
|
|
|
|
|
|
def bitsize(self):
|
2016-11-07 07:48:02 +01:00
|
|
|
return self.dumper.ptrSize() * 8
|
2016-10-28 14:50:10 +02:00
|
|
|
|
|
|
|
def code(self):
|
|
|
|
if self.typeName.endswith('*'):
|
2020-02-24 15:10:47 +01:00
|
|
|
return TypeCode.Pointer
|
2016-10-28 14:50:10 +02:00
|
|
|
if self.typeName.endswith(']'):
|
2020-02-24 15:10:47 +01:00
|
|
|
return TypeCode.Array
|
|
|
|
return TypeCode.Void
|
2016-10-28 14:50:10 +02:00
|
|
|
|
|
|
|
def unqualified(self):
|
|
|
|
return self
|
|
|
|
|
|
|
|
def target(self):
|
|
|
|
code = self.code()
|
2020-02-24 15:10:47 +01:00
|
|
|
if code == TypeCode.Pointer:
|
2016-10-28 14:50:10 +02:00
|
|
|
return FakeVoidType(self.typeName[:-1], self.dumper)
|
2020-02-24 15:10:47 +01:00
|
|
|
if code == TypeCode.Void:
|
2016-10-28 14:50:10 +02:00
|
|
|
return self
|
|
|
|
try:
|
|
|
|
return FakeVoidType(self.typeName[:self.typeName.rindex('[')], self.dumper)
|
|
|
|
except:
|
|
|
|
return FakeVoidType('void', self.dumper)
|
|
|
|
|
2017-01-31 09:14:47 +01:00
|
|
|
def targetName(self):
|
|
|
|
return self.target().name()
|
|
|
|
|
|
|
|
def arrayElements(self):
|
|
|
|
try:
|
|
|
|
return int(self.typeName[self.typeName.rindex('[') + 1:self.typeName.rindex(']')])
|
|
|
|
except:
|
|
|
|
return 0
|
|
|
|
|
2016-10-28 14:50:10 +02:00
|
|
|
def stripTypedef(self):
|
|
|
|
return self
|
|
|
|
|
|
|
|
def fields(self):
|
|
|
|
return []
|
|
|
|
|
|
|
|
def templateArgument(self, pos, numeric):
|
|
|
|
return None
|
|
|
|
|
|
|
|
def templateArguments(self):
|
|
|
|
return []
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
|
2016-10-06 13:36:02 +02:00
|
|
|
class Dumper(DumperBase):
|
|
|
|
def __init__(self):
|
|
|
|
DumperBase.__init__(self)
|
|
|
|
self.outputLock = threading.Lock()
|
|
|
|
self.isCdb = True
|
|
|
|
|
2018-08-08 12:11:04 +02:00
|
|
|
def enumValue(self, nativeValue):
|
|
|
|
val = nativeValue.nativeDebuggerValue()
|
|
|
|
# remove '0n' decimal prefix of the native cdb value output
|
|
|
|
return val.replace('(0n', '(')
|
|
|
|
|
2016-10-06 13:36:02 +02:00
|
|
|
def fromNativeValue(self, nativeValue):
|
2017-01-11 13:29:18 +01:00
|
|
|
self.check(isinstance(nativeValue, cdbext.Value))
|
2016-10-06 13:36:02 +02:00
|
|
|
val = self.Value(self)
|
2016-11-03 15:29:06 +01:00
|
|
|
val.name = nativeValue.name()
|
2021-01-19 16:02:48 +01:00
|
|
|
val._type = self.fromNativeType(nativeValue.type())
|
2016-12-19 12:32:22 +01:00
|
|
|
# There is no cdb api for the size of bitfields.
|
|
|
|
# Workaround this issue by parsing the native debugger text for integral types.
|
2021-01-19 16:02:48 +01:00
|
|
|
if val._type.code == TypeCode.Integral:
|
2020-07-31 14:59:56 +02:00
|
|
|
try:
|
|
|
|
integerString = nativeValue.nativeDebuggerValue()
|
|
|
|
except UnicodeDecodeError:
|
|
|
|
integerString = '' # cannot decode - read raw
|
2016-12-19 12:32:22 +01:00
|
|
|
if integerString == 'true':
|
|
|
|
val.ldata = int(1).to_bytes(1, byteorder='little')
|
|
|
|
elif integerString == 'false':
|
|
|
|
val.ldata = int(0).to_bytes(1, byteorder='little')
|
|
|
|
else:
|
2020-02-24 14:37:56 +01:00
|
|
|
integerString = integerString.replace('`', '')
|
2016-12-19 12:32:22 +01:00
|
|
|
integerString = integerString.split(' ')[0]
|
|
|
|
if integerString.startswith('0n'):
|
|
|
|
integerString = integerString[2:]
|
|
|
|
base = 10
|
|
|
|
elif integerString.startswith('0x'):
|
|
|
|
base = 16
|
|
|
|
else:
|
|
|
|
base = 10
|
2021-01-19 16:02:48 +01:00
|
|
|
signed = not val._type.name.startswith('unsigned')
|
2017-03-02 10:40:30 +01:00
|
|
|
try:
|
2021-01-19 16:02:48 +01:00
|
|
|
val.ldata = int(integerString, base).to_bytes(val._type.size(),
|
2020-02-24 14:37:56 +01:00
|
|
|
byteorder='little', signed=signed)
|
2017-03-02 10:40:30 +01:00
|
|
|
except:
|
|
|
|
# read raw memory in case the integerString can not be interpreted
|
|
|
|
pass
|
2021-01-19 16:02:48 +01:00
|
|
|
if val._type.code == TypeCode.Enum:
|
2018-08-09 14:52:50 +02:00
|
|
|
val.ldisplay = self.enumValue(nativeValue)
|
2021-01-19 16:02:48 +01:00
|
|
|
val.isBaseClass = val.name == val._type.name
|
2017-03-22 14:19:50 +01:00
|
|
|
val.nativeValue = nativeValue
|
2016-10-06 13:36:02 +02:00
|
|
|
val.laddress = nativeValue.address()
|
2023-03-01 12:29:03 +01:00
|
|
|
val.lbitsize = nativeValue.bitsize()
|
2016-10-06 13:36:02 +02:00
|
|
|
return val
|
|
|
|
|
2016-10-31 10:54:51 +01:00
|
|
|
def nativeTypeId(self, nativeType):
|
|
|
|
self.check(isinstance(nativeType, cdbext.Type))
|
|
|
|
name = nativeType.name()
|
|
|
|
if name is None or len(name) == 0:
|
|
|
|
c = '0'
|
|
|
|
elif name == 'struct {...}':
|
|
|
|
c = 's'
|
|
|
|
elif name == 'union {...}':
|
|
|
|
c = 'u'
|
|
|
|
else:
|
|
|
|
return name
|
2020-02-24 14:37:56 +01:00
|
|
|
typeId = c + ''.join(['{%s:%s}' % (f.name(), self.nativeTypeId(f.type()))
|
|
|
|
for f in nativeType.fields()])
|
2016-10-31 10:54:51 +01:00
|
|
|
return typeId
|
|
|
|
|
2016-10-06 13:36:02 +02:00
|
|
|
def fromNativeType(self, nativeType):
|
2016-10-31 10:54:51 +01:00
|
|
|
self.check(isinstance(nativeType, cdbext.Type))
|
2017-02-27 12:36:48 +01:00
|
|
|
typeId = self.nativeTypeId(nativeType)
|
|
|
|
if self.typeData.get(typeId, None) is not None:
|
|
|
|
return self.Type(self, typeId)
|
2016-10-31 10:54:51 +01:00
|
|
|
|
2016-11-07 07:50:07 +01:00
|
|
|
if nativeType.name().startswith('void'):
|
|
|
|
nativeType = FakeVoidType(nativeType.name(), self)
|
|
|
|
|
2017-02-27 12:36:48 +01:00
|
|
|
code = nativeType.code()
|
2020-02-24 15:10:47 +01:00
|
|
|
if code == TypeCode.Pointer:
|
2023-06-19 14:54:30 +02:00
|
|
|
if nativeType.name().startswith('<function>'):
|
|
|
|
code = TypeCode.Function
|
|
|
|
elif nativeType.targetName() != nativeType.name():
|
2017-02-27 14:04:32 +01:00
|
|
|
targetType = self.lookupType(nativeType.targetName(), nativeType.moduleId())
|
2023-06-19 14:54:30 +02:00
|
|
|
if targetType is not None and targetType is not nativeType:
|
2017-03-27 07:59:18 +02:00
|
|
|
return self.createPointerType(targetType)
|
2016-10-31 10:54:51 +01:00
|
|
|
|
2020-02-24 15:10:47 +01:00
|
|
|
if code == TypeCode.Array:
|
2017-03-22 14:16:38 +01:00
|
|
|
# cdb reports virtual function tables as arrays those ar handled separetly by
|
2020-02-24 14:37:56 +01:00
|
|
|
# the DumperBase. Declare those types as structs prevents a lookup to a
|
|
|
|
# none existing type
|
2017-03-27 07:59:18 +02:00
|
|
|
if not nativeType.name().startswith('__fptr()') and not nativeType.name().startswith('<gentype '):
|
2017-02-27 14:04:32 +01:00
|
|
|
targetType = self.lookupType(nativeType.targetName(), nativeType.moduleId())
|
2017-03-27 07:59:18 +02:00
|
|
|
if targetType is not None:
|
|
|
|
return self.createArrayType(targetType, nativeType.arrayElements())
|
2020-02-24 15:10:47 +01:00
|
|
|
code = TypeCode.Struct
|
2016-10-31 10:54:51 +01:00
|
|
|
|
2022-08-23 17:49:31 +02:00
|
|
|
tdata = self.TypeData(self, typeId)
|
2017-02-27 12:36:48 +01:00
|
|
|
tdata.name = nativeType.name()
|
|
|
|
tdata.lbitsize = nativeType.bitsize()
|
|
|
|
tdata.code = code
|
2017-03-07 08:40:43 +01:00
|
|
|
tdata.moduleName = nativeType.module()
|
2020-02-24 15:10:47 +01:00
|
|
|
if code == TypeCode.Struct:
|
2020-02-24 14:37:56 +01:00
|
|
|
tdata.lfields = lambda value: \
|
2017-02-27 12:36:48 +01:00
|
|
|
self.listFields(nativeType, value)
|
2020-02-24 14:37:56 +01:00
|
|
|
tdata.lalignment = lambda: \
|
2017-02-27 12:36:48 +01:00
|
|
|
self.nativeStructAlignment(nativeType)
|
2020-02-24 15:10:47 +01:00
|
|
|
if code == TypeCode.Enum:
|
2020-02-24 14:37:56 +01:00
|
|
|
tdata.enumDisplay = lambda intval, addr, form: \
|
2018-12-17 10:57:48 +01:00
|
|
|
self.nativeTypeEnumDisplay(nativeType, intval, form)
|
2022-08-12 12:34:32 +02:00
|
|
|
tdata.templateArguments = lambda: \
|
|
|
|
self.listTemplateParameters(nativeType.name())
|
2016-10-31 10:54:51 +01:00
|
|
|
return self.Type(self, typeId)
|
|
|
|
|
2016-11-03 15:34:37 +01:00
|
|
|
def listFields(self, nativeType, value):
|
|
|
|
if value.address() is None or value.address() == 0:
|
|
|
|
raise Exception("")
|
2023-02-14 09:56:22 +01:00
|
|
|
nativeValue = value.nativeValue
|
|
|
|
if nativeValue is None:
|
|
|
|
nativeValue = cdbext.createValue(value.address(), nativeType)
|
2016-11-03 15:34:37 +01:00
|
|
|
index = 0
|
|
|
|
nativeMember = nativeValue.childFromIndex(index)
|
|
|
|
while nativeMember is not None:
|
2024-02-01 07:24:17 +01:00
|
|
|
if nativeMember.address() != 0:
|
|
|
|
yield self.fromNativeValue(nativeMember)
|
2016-11-03 15:34:37 +01:00
|
|
|
index += 1
|
|
|
|
nativeMember = nativeValue.childFromIndex(index)
|
|
|
|
|
|
|
|
def nativeStructAlignment(self, nativeType):
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn("NATIVE ALIGN FOR %s" % nativeType.name)
|
2016-11-03 15:34:37 +01:00
|
|
|
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
|
2016-10-06 13:36:02 +02:00
|
|
|
|
2018-12-17 10:57:48 +01:00
|
|
|
def nativeTypeEnumDisplay(self, nativeType, intval, form):
|
|
|
|
value = self.nativeParseAndEvaluate('(%s)%d' % (nativeType.name(), intval))
|
2017-02-27 14:29:07 +01:00
|
|
|
if value is None:
|
|
|
|
return ''
|
2018-12-17 10:57:48 +01:00
|
|
|
return self.enumValue(value)
|
2016-10-06 13:36:02 +02:00
|
|
|
|
|
|
|
def enumExpression(self, enumType, enumValue):
|
|
|
|
ns = self.qtNamespace()
|
|
|
|
return ns + "Qt::" + enumType + "(" \
|
|
|
|
+ ns + "Qt::" + enumType + "::" + enumValue + ")"
|
|
|
|
|
|
|
|
def pokeValue(self, typeName, *args):
|
|
|
|
return None
|
|
|
|
|
|
|
|
def parseAndEvaluate(self, exp):
|
2018-10-17 16:05:14 +02:00
|
|
|
return self.fromNativeValue(self.nativeParseAndEvaluate(exp))
|
|
|
|
|
|
|
|
def nativeParseAndEvaluate(self, exp):
|
|
|
|
return cdbext.parseAndEvaluate(exp)
|
2016-10-06 13:36:02 +02:00
|
|
|
|
|
|
|
def isWindowsTarget(self):
|
|
|
|
return True
|
|
|
|
|
|
|
|
def isQnxTarget(self):
|
|
|
|
return False
|
|
|
|
|
|
|
|
def isArmArchitecture(self):
|
|
|
|
return False
|
|
|
|
|
|
|
|
def isMsvcTarget(self):
|
|
|
|
return True
|
|
|
|
|
2016-12-20 13:24:07 +01:00
|
|
|
def qtCoreModuleName(self):
|
|
|
|
modules = cdbext.listOfModules()
|
2017-01-13 09:08:17 +01:00
|
|
|
# first check for an exact module name match
|
2020-11-30 15:24:09 +01:00
|
|
|
for coreName in ['Qt6Core', 'Qt6Cored', 'Qt5Cored', 'Qt5Core', 'QtCored4', 'QtCore4']:
|
2016-12-20 13:24:07 +01:00
|
|
|
if coreName in modules:
|
|
|
|
self.qtCoreModuleName = lambda: coreName
|
|
|
|
return coreName
|
2017-01-13 09:08:17 +01:00
|
|
|
# maybe we have a libinfix build.
|
2020-11-30 15:24:09 +01:00
|
|
|
for pattern in ['Qt6Core.*', 'Qt5Core.*', 'QtCore.*']:
|
2017-01-13 09:08:17 +01:00
|
|
|
matches = [module for module in modules if re.match(pattern, module)]
|
|
|
|
if matches:
|
|
|
|
coreName = matches[0]
|
|
|
|
self.qtCoreModuleName = lambda: coreName
|
|
|
|
return coreName
|
2016-12-20 13:24:07 +01:00
|
|
|
return None
|
2016-11-02 08:31:22 +01:00
|
|
|
|
2017-01-12 09:33:36 +01:00
|
|
|
def qtDeclarativeModuleName(self):
|
|
|
|
modules = cdbext.listOfModules()
|
2020-11-30 15:24:09 +01:00
|
|
|
for declarativeModuleName in ['Qt6Qmld', 'Qt6Qml', 'Qt5Qmld', 'Qt5Qml']:
|
2017-01-12 09:33:36 +01:00
|
|
|
if declarativeModuleName in modules:
|
|
|
|
self.qtDeclarativeModuleName = lambda: declarativeModuleName
|
|
|
|
return declarativeModuleName
|
2020-11-30 15:24:09 +01:00
|
|
|
matches = [module for module in modules if re.match('Qt[56]Qml.*', module)]
|
2017-01-13 09:08:17 +01:00
|
|
|
if matches:
|
|
|
|
declarativeModuleName = matches[0]
|
|
|
|
self.qtDeclarativeModuleName = lambda: declarativeModuleName
|
|
|
|
return declarativeModuleName
|
2017-01-12 09:33:36 +01:00
|
|
|
return None
|
|
|
|
|
2016-12-20 13:24:07 +01:00
|
|
|
def qtHookDataSymbolName(self):
|
|
|
|
hookSymbolName = 'qtHookData'
|
|
|
|
coreModuleName = self.qtCoreModuleName()
|
|
|
|
if coreModuleName is not None:
|
2017-01-13 09:08:17 +01:00
|
|
|
hookSymbolName = '%s!%s%s' % (coreModuleName, self.qtNamespace(), hookSymbolName)
|
|
|
|
else:
|
|
|
|
resolved = cdbext.resolveSymbol('*' + hookSymbolName)
|
|
|
|
if resolved:
|
|
|
|
hookSymbolName = resolved[0]
|
|
|
|
else:
|
|
|
|
hookSymbolName = '*%s' % hookSymbolName
|
2016-12-20 13:24:07 +01:00
|
|
|
self.qtHookDataSymbolName = lambda: hookSymbolName
|
|
|
|
return hookSymbolName
|
2016-10-06 13:36:02 +02:00
|
|
|
|
2017-01-12 09:33:36 +01:00
|
|
|
def qtDeclarativeHookDataSymbolName(self):
|
|
|
|
hookSymbolName = 'qtDeclarativeHookData'
|
|
|
|
declarativeModuleName = self.qtDeclarativeModuleName()
|
|
|
|
if declarativeModuleName is not None:
|
2017-01-13 09:08:17 +01:00
|
|
|
hookSymbolName = '%s!%s%s' % (declarativeModuleName, self.qtNamespace(), hookSymbolName)
|
|
|
|
else:
|
|
|
|
resolved = cdbext.resolveSymbol('*' + hookSymbolName)
|
|
|
|
if resolved:
|
|
|
|
hookSymbolName = resolved[0]
|
|
|
|
else:
|
|
|
|
hookSymbolName = '*%s' % hookSymbolName
|
|
|
|
|
2017-01-12 09:33:36 +01:00
|
|
|
self.qtDeclarativeHookDataSymbolName = lambda: hookSymbolName
|
|
|
|
return hookSymbolName
|
|
|
|
|
2016-10-06 13:36:02 +02:00
|
|
|
def qtNamespace(self):
|
2017-01-18 15:04:06 +01:00
|
|
|
namespace = ''
|
2017-01-13 09:08:17 +01:00
|
|
|
qstrdupSymbolName = '*qstrdup'
|
|
|
|
coreModuleName = self.qtCoreModuleName()
|
|
|
|
if coreModuleName is not None:
|
|
|
|
qstrdupSymbolName = '%s!%s' % (coreModuleName, qstrdupSymbolName)
|
2023-02-27 15:56:50 +01:00
|
|
|
resolved = cdbext.resolveSymbol(qstrdupSymbolName)
|
|
|
|
if resolved:
|
|
|
|
name = resolved[0].split('!')[1]
|
|
|
|
namespaceIndex = name.find('::')
|
|
|
|
if namespaceIndex > 0:
|
|
|
|
namespace = name[:namespaceIndex + 2]
|
|
|
|
self.qtCustomEventFunc = self.parseAndEvaluate(
|
|
|
|
'%s!%sQObject::customEvent' %
|
|
|
|
(self.qtCoreModuleName(), namespace)).address()
|
2017-01-13 09:08:17 +01:00
|
|
|
self.qtNamespace = lambda: namespace
|
|
|
|
return namespace
|
2016-10-06 13:36:02 +02:00
|
|
|
|
|
|
|
def qtVersion(self):
|
2018-11-12 14:52:18 +01:00
|
|
|
qtVersion = None
|
|
|
|
try:
|
2020-02-24 14:37:56 +01:00
|
|
|
qtVersion = self.parseAndEvaluate(
|
|
|
|
'((void**)&%s)[2]' % self.qtHookDataSymbolName()).integer()
|
2018-11-12 14:52:18 +01:00
|
|
|
except:
|
|
|
|
if self.qtCoreModuleName() is not None:
|
|
|
|
try:
|
|
|
|
versionValue = cdbext.call(self.qtCoreModuleName() + '!qVersion()')
|
|
|
|
version = self.extractCString(self.fromNativeValue(versionValue).address())
|
|
|
|
(major, minor, patch) = version.decode('latin1').split('.')
|
|
|
|
qtVersion = 0x10000 * int(major) + 0x100 * int(minor) + int(patch)
|
|
|
|
except:
|
|
|
|
pass
|
2016-12-20 13:24:07 +01:00
|
|
|
if qtVersion is None:
|
|
|
|
qtVersion = self.fallbackQtVersion
|
|
|
|
self.qtVersion = lambda: qtVersion
|
|
|
|
return qtVersion
|
2016-10-06 13:36:02 +02:00
|
|
|
|
2017-01-20 09:05:23 +01:00
|
|
|
def putVtableItem(self, address):
|
|
|
|
funcName = cdbext.getNameByAddress(address)
|
|
|
|
if funcName is None:
|
|
|
|
self.putItem(self.createPointerValue(address, 'void'))
|
|
|
|
else:
|
|
|
|
self.putValue(funcName)
|
|
|
|
self.putType('void*')
|
|
|
|
self.putAddress(address)
|
|
|
|
|
|
|
|
def putVTableChildren(self, item, itemCount):
|
|
|
|
p = item.address()
|
2020-02-24 10:37:40 +01:00
|
|
|
for i in range(itemCount):
|
2017-01-20 09:05:23 +01:00
|
|
|
deref = self.extractPointer(p)
|
|
|
|
if deref == 0:
|
|
|
|
n = i
|
|
|
|
break
|
|
|
|
with SubItem(self, i):
|
|
|
|
self.putVtableItem(deref)
|
|
|
|
p += self.ptrSize()
|
|
|
|
return itemCount
|
|
|
|
|
2016-10-06 13:36:02 +02:00
|
|
|
def ptrSize(self):
|
2016-12-23 07:47:34 +01:00
|
|
|
size = cdbext.pointerSize()
|
|
|
|
self.ptrSize = lambda: size
|
|
|
|
return size
|
2016-10-06 13:36:02 +02:00
|
|
|
|
2017-01-27 13:50:29 +01:00
|
|
|
def stripQintTypedefs(self, typeName):
|
|
|
|
if typeName.startswith('qint'):
|
|
|
|
prefix = ''
|
|
|
|
size = typeName[4:]
|
|
|
|
elif typeName.startswith('quint'):
|
|
|
|
prefix = 'unsigned '
|
|
|
|
size = typeName[5:]
|
|
|
|
else:
|
|
|
|
return typeName
|
|
|
|
if size == '8':
|
|
|
|
return '%schar' % prefix
|
|
|
|
elif size == '16':
|
|
|
|
return '%sshort' % prefix
|
|
|
|
elif size == '32':
|
|
|
|
return '%sint' % prefix
|
|
|
|
elif size == '64':
|
|
|
|
return '%sint64' % prefix
|
|
|
|
else:
|
|
|
|
return typeName
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
def lookupType(self, typeNameIn, module=0):
|
2017-01-27 13:50:29 +01:00
|
|
|
if len(typeNameIn) == 0:
|
2016-10-31 10:54:51 +01:00
|
|
|
return None
|
2017-01-27 13:50:29 +01:00
|
|
|
typeName = self.stripQintTypedefs(typeNameIn)
|
2016-10-31 10:54:51 +01:00
|
|
|
if self.typeData.get(typeName, None) is None:
|
2017-01-31 09:14:47 +01:00
|
|
|
nativeType = self.lookupNativeType(typeName, module)
|
2017-02-22 11:56:49 +01:00
|
|
|
if nativeType is None:
|
|
|
|
return None
|
2021-01-19 16:02:48 +01:00
|
|
|
_type = self.fromNativeType(nativeType)
|
2022-08-23 17:49:31 +02:00
|
|
|
if _type.typeId != typeName:
|
|
|
|
self.registerTypeAlias(_type.typeId, typeName)
|
2021-01-19 16:02:48 +01:00
|
|
|
return _type
|
2016-10-31 10:54:51 +01:00
|
|
|
return self.Type(self, typeName)
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
def lookupNativeType(self, name, module=0):
|
2016-10-28 14:50:10 +02:00
|
|
|
if name.startswith('void'):
|
|
|
|
return FakeVoidType(name, self)
|
2017-01-31 09:14:47 +01:00
|
|
|
return cdbext.lookupType(name, module)
|
2016-10-06 13:36:02 +02:00
|
|
|
|
|
|
|
def reportResult(self, result, args):
|
2017-03-31 10:57:23 +02:00
|
|
|
cdbext.reportResult('result={%s}' % result)
|
2016-10-06 13:36:02 +02:00
|
|
|
|
|
|
|
def readRawMemory(self, address, size):
|
2016-11-25 13:00:03 +01:00
|
|
|
mem = cdbext.readRawMemory(address, size)
|
|
|
|
if len(mem) != size:
|
2017-03-31 10:40:47 +02:00
|
|
|
raise Exception("Invalid memory request: %d bytes from 0x%x" % (size, address))
|
2016-11-25 13:00:03 +01:00
|
|
|
return mem
|
2016-10-06 13:36:02 +02:00
|
|
|
|
2017-03-07 08:40:43 +01:00
|
|
|
def findStaticMetaObject(self, type):
|
|
|
|
typeName = type.name
|
|
|
|
if type.moduleName is not None:
|
|
|
|
typeName = type.moduleName + '!' + typeName
|
2017-02-01 12:14:06 +01:00
|
|
|
ptr = cdbext.getAddressByName(typeName + '::staticMetaObject')
|
2016-11-01 08:32:58 +01:00
|
|
|
return ptr
|
2016-10-06 13:36:02 +02:00
|
|
|
|
|
|
|
def warn(self, msg):
|
|
|
|
self.put('{name="%s",value="",type="",numchild="0"},' % msg)
|
|
|
|
|
|
|
|
def fetchVariables(self, args):
|
2017-01-05 10:52:20 +01:00
|
|
|
self.resetStats()
|
2016-10-06 13:36:02 +02:00
|
|
|
(ok, res) = self.tryFetchInterpreterVariables(args)
|
|
|
|
if ok:
|
|
|
|
self.reportResult(res, args)
|
|
|
|
return
|
|
|
|
|
2016-10-07 12:23:35 +02:00
|
|
|
self.setVariableFetchingOptions(args)
|
2016-10-06 13:36:02 +02:00
|
|
|
|
2022-11-08 12:42:04 +01:00
|
|
|
self.output = []
|
2016-10-06 13:36:02 +02:00
|
|
|
|
|
|
|
self.currentIName = 'local'
|
|
|
|
self.put('data=[')
|
|
|
|
self.anonNumber = 0
|
|
|
|
|
|
|
|
variables = []
|
2016-12-08 15:51:49 +01:00
|
|
|
for val in cdbext.listOfLocals(self.partialVariable):
|
2017-03-30 09:15:48 +02:00
|
|
|
dumperVal = self.fromNativeValue(val)
|
2020-02-24 14:37:56 +01:00
|
|
|
dumperVal.lIsInScope = dumperVal.name not in self.uninitialized
|
2017-03-30 09:15:48 +02:00
|
|
|
variables.append(dumperVal)
|
2016-10-06 13:36:02 +02:00
|
|
|
|
|
|
|
self.handleLocals(variables)
|
|
|
|
self.handleWatches(args)
|
|
|
|
|
2016-10-07 12:23:35 +02:00
|
|
|
self.put('],partial="%d"' % (len(self.partialVariable) > 0))
|
2017-01-05 10:52:20 +01:00
|
|
|
self.put(',timings=%s' % self.timings)
|
2019-07-08 10:53:30 +02:00
|
|
|
|
|
|
|
if self.forceQtNamespace:
|
|
|
|
self.qtNamespaceToReport = self.qtNamespace()
|
|
|
|
|
|
|
|
if self.qtNamespaceToReport:
|
2022-11-08 12:42:04 +01:00
|
|
|
self.put(',qtnamespace="%s"' % self.qtNamespaceToReport)
|
2019-07-08 10:53:30 +02:00
|
|
|
self.qtNamespaceToReport = None
|
|
|
|
|
2022-11-08 12:42:04 +01:00
|
|
|
self.reportResult(''.join(self.output), args)
|
|
|
|
self.output = []
|
2016-10-06 13:36:02 +02:00
|
|
|
|
|
|
|
def report(self, stuff):
|
2016-10-07 11:13:11 +02:00
|
|
|
sys.stdout.write(stuff + "\n")
|
2016-10-06 13:36:02 +02:00
|
|
|
|
|
|
|
def findValueByExpression(self, exp):
|
|
|
|
return cdbext.parseAndEvaluate(exp)
|
|
|
|
|
|
|
|
def nativeDynamicTypeName(self, address, baseType):
|
2020-02-24 14:37:56 +01:00
|
|
|
return None # Does not work with cdb
|
2017-03-22 14:19:50 +01:00
|
|
|
|
|
|
|
def nativeValueDereferenceReference(self, value):
|
|
|
|
return self.nativeValueDereferencePointer(value)
|
|
|
|
|
|
|
|
def nativeValueDereferencePointer(self, value):
|
|
|
|
def nativeVtCastValue(nativeValue):
|
|
|
|
# If we have a pointer to a derived instance of the pointer type cdb adds a
|
|
|
|
# synthetic '__vtcast_<derived type name>' member as the first child
|
|
|
|
if nativeValue.hasChildren():
|
|
|
|
vtcastCandidate = nativeValue.childFromIndex(0)
|
|
|
|
vtcastCandidateName = vtcastCandidate.name()
|
|
|
|
if vtcastCandidateName.startswith('__vtcast_'):
|
|
|
|
# found a __vtcast member
|
|
|
|
# make sure that it is not an actual field
|
|
|
|
for field in nativeValue.type().fields():
|
|
|
|
if field.name() == vtcastCandidateName:
|
|
|
|
return None
|
|
|
|
return vtcastCandidate
|
|
|
|
return None
|
|
|
|
|
|
|
|
nativeValue = value.nativeValue
|
2023-02-17 14:29:53 +01:00
|
|
|
if nativeValue is None:
|
|
|
|
if not self.isExpanded():
|
|
|
|
raise Exception("Casting not expanded values is to expensive")
|
|
|
|
nativeValue = self.nativeParseAndEvaluate('(%s)0x%x' % (value.type.name, value.pointer()))
|
2017-03-22 14:19:50 +01:00
|
|
|
castVal = nativeVtCastValue(nativeValue)
|
|
|
|
if castVal is not None:
|
|
|
|
val = self.fromNativeValue(castVal)
|
|
|
|
else:
|
|
|
|
val = self.Value(self)
|
|
|
|
val.laddress = value.pointer()
|
2021-01-19 16:02:48 +01:00
|
|
|
val._type = value.type.dereference()
|
2023-02-14 09:56:22 +01:00
|
|
|
val.nativeValue = value.nativeValue
|
2017-03-22 14:19:50 +01:00
|
|
|
|
|
|
|
return val
|
2016-10-12 14:38:24 +02:00
|
|
|
|
|
|
|
def callHelper(self, rettype, value, function, args):
|
|
|
|
raise Exception("cdb does not support calling functions")
|
|
|
|
|
2017-01-31 15:30:35 +01:00
|
|
|
def nameForCoreId(self, id):
|
2023-02-10 10:20:10 +01:00
|
|
|
for dll in ['Utilsd', 'Utils']:
|
2020-07-03 11:36:55 +03:00
|
|
|
idName = cdbext.call('%s!Utils::nameForId(%d)' % (dll, id))
|
|
|
|
if idName is not None:
|
|
|
|
break
|
2017-01-31 15:30:35 +01:00
|
|
|
return self.fromNativeValue(idName)
|
|
|
|
|
2016-10-12 14:38:24 +02:00
|
|
|
def putCallItem(self, name, rettype, value, func, *args):
|
|
|
|
return
|
2019-01-22 10:56:08 +01:00
|
|
|
|
|
|
|
def symbolAddress(self, symbolName):
|
|
|
|
res = self.nativeParseAndEvaluate(symbolName)
|
|
|
|
return None if res is None else res.address()
|