forked from qt-creator/qt-creator
Debugger: add cdbext stub file
... and add some typing infos to the cdbbridge Change-Id: If85bc75976c869332ef658c32615f6b110459048 Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -19,6 +19,7 @@ set(resource_files
|
|||||||
debugger/.pylintrc
|
debugger/.pylintrc
|
||||||
debugger/boosttypes.py
|
debugger/boosttypes.py
|
||||||
debugger/cdbbridge.py
|
debugger/cdbbridge.py
|
||||||
|
debugger/cdbext.pyi
|
||||||
debugger/creatortypes.py
|
debugger/creatortypes.py
|
||||||
debugger/dumper.py
|
debugger/dumper.py
|
||||||
debugger/gdbbridge.py
|
debugger/gdbbridge.py
|
||||||
|
@@ -85,12 +85,12 @@ class Dumper(DumperBase):
|
|||||||
del self.type_size_cache[typeid]
|
del self.type_size_cache[typeid]
|
||||||
del self.type_alignment_cache[typeid]
|
del self.type_alignment_cache[typeid]
|
||||||
|
|
||||||
def enumValue(self, nativeValue):
|
def enumValue(self, nativeValue: cdbext.Value) -> str:
|
||||||
val = nativeValue.nativeDebuggerValue()
|
val = nativeValue.nativeDebuggerValue()
|
||||||
# remove '0n' decimal prefix of the native cdb value output
|
# remove '0n' decimal prefix of the native cdb value output
|
||||||
return val.replace('(0n', '(')
|
return val.replace('(0n', '(')
|
||||||
|
|
||||||
def fromNativeValue(self, nativeValue):
|
def fromNativeValue(self, nativeValue: cdbext.Value) -> DumperBase.Value:
|
||||||
self.check(isinstance(nativeValue, cdbext.Value))
|
self.check(isinstance(nativeValue, cdbext.Value))
|
||||||
val = self.Value(self)
|
val = self.Value(self)
|
||||||
val.name = nativeValue.name()
|
val.name = nativeValue.name()
|
||||||
@@ -133,7 +133,7 @@ class Dumper(DumperBase):
|
|||||||
val.lbitsize = nativeValue.bitsize()
|
val.lbitsize = nativeValue.bitsize()
|
||||||
return val
|
return val
|
||||||
|
|
||||||
def nativeTypeId(self, nativeType):
|
def nativeTypeId(self, nativeType: cdbext.Type) -> str:
|
||||||
self.check(isinstance(nativeType, cdbext.Type))
|
self.check(isinstance(nativeType, cdbext.Type))
|
||||||
name = nativeType.name()
|
name = nativeType.name()
|
||||||
if name is None or len(name) == 0:
|
if name is None or len(name) == 0:
|
||||||
@@ -148,7 +148,7 @@ class Dumper(DumperBase):
|
|||||||
for f in nativeType.fields()])
|
for f in nativeType.fields()])
|
||||||
return typeId
|
return typeId
|
||||||
|
|
||||||
def from_native_type(self, nativeType):
|
def from_native_type(self, nativeType: cdbext.Type) -> str:
|
||||||
self.check(isinstance(nativeType, cdbext.Type))
|
self.check(isinstance(nativeType, cdbext.Type))
|
||||||
typeid = self.typeid_for_string(self.nativeTypeId(nativeType))
|
typeid = self.typeid_for_string(self.nativeTypeId(nativeType))
|
||||||
self.type_nativetype_cache[typeid] = nativeType
|
self.type_nativetype_cache[typeid] = nativeType
|
||||||
@@ -187,7 +187,7 @@ class Dumper(DumperBase):
|
|||||||
self.nativeTypeEnumDisplay(nativeType, intval, form)
|
self.nativeTypeEnumDisplay(nativeType, intval, form)
|
||||||
return typeid
|
return typeid
|
||||||
|
|
||||||
def listNativeValueChildren(self, nativeValue, include_bases):
|
def listNativeValueChildren(self, nativeValue: cdbext.Value, include_bases: bool) -> list[DumperBase.Value]:
|
||||||
fields = []
|
fields = []
|
||||||
index = 0
|
index = 0
|
||||||
nativeMember = nativeValue.childFromIndex(index)
|
nativeMember = nativeValue.childFromIndex(index)
|
||||||
@@ -202,19 +202,19 @@ class Dumper(DumperBase):
|
|||||||
nativeMember = nativeValue.childFromIndex(index)
|
nativeMember = nativeValue.childFromIndex(index)
|
||||||
return fields
|
return fields
|
||||||
|
|
||||||
def listValueChildren(self, value, include_bases=True):
|
def listValueChildren(self, value: DumperBase.Value, include_bases=True) -> list[DumperBase.Value]:
|
||||||
nativeValue = value.nativeValue
|
nativeValue = value.nativeValue
|
||||||
if nativeValue is None:
|
if nativeValue is None:
|
||||||
nativeValue = cdbext.createValue(value.address(), self.lookupNativeType(value.type.name, 0))
|
nativeValue = cdbext.createValue(value.address(), self.lookupNativeType(value.type.name, 0))
|
||||||
return self.listNativeValueChildren(nativeValue, include_bases)
|
return self.listNativeValueChildren(nativeValue, include_bases)
|
||||||
|
|
||||||
def nativeListMembers(self, value, native_type, include_bases):
|
def nativeListMembers(self, value: DumperBase.Value, native_type: cdbext.Type, include_bases: bool) -> list[DumperBase.Value]:
|
||||||
nativeValue = value.nativeValue
|
nativeValue = value.nativeValue
|
||||||
if nativeValue is None:
|
if nativeValue is None:
|
||||||
nativeValue = cdbext.createValue(value.address(), native_type)
|
nativeValue = cdbext.createValue(value.address(), native_type)
|
||||||
return self.listNativeValueChildren(nativeValue, include_bases)
|
return self.listNativeValueChildren(nativeValue, include_bases)
|
||||||
|
|
||||||
def nativeStructAlignment(self, nativeType):
|
def nativeStructAlignment(self, nativeType: cdbext.Type) -> int:
|
||||||
#DumperBase.warn("NATIVE ALIGN FOR %s" % nativeType.name)
|
#DumperBase.warn("NATIVE ALIGN FOR %s" % nativeType.name)
|
||||||
def handleItem(nativeFieldType, align):
|
def handleItem(nativeFieldType, align):
|
||||||
a = self.type_alignment(self.from_native_type(nativeFieldType))
|
a = self.type_alignment(self.from_native_type(nativeFieldType))
|
||||||
@@ -224,13 +224,13 @@ class Dumper(DumperBase):
|
|||||||
align = handleItem(f.type(), align)
|
align = handleItem(f.type(), align)
|
||||||
return align
|
return align
|
||||||
|
|
||||||
def nativeTypeEnumDisplay(self, nativeType, intval, form):
|
def nativeTypeEnumDisplay(self, nativeType: cdbext.Type, intval: int, form) -> str:
|
||||||
value = self.nativeParseAndEvaluate('(%s)%d' % (nativeType.name(), intval))
|
value = self.nativeParseAndEvaluate('(%s)%d' % (nativeType.name(), intval))
|
||||||
if value is None:
|
if value is None:
|
||||||
return ''
|
return ''
|
||||||
return self.enumValue(value)
|
return self.enumValue(value)
|
||||||
|
|
||||||
def enumExpression(self, enumType, enumValue):
|
def enumExpression(self, enumType: str, enumValue: str) -> str:
|
||||||
ns = self.qtNamespace()
|
ns = self.qtNamespace()
|
||||||
return ns + "Qt::" + enumType + "(" \
|
return ns + "Qt::" + enumType + "(" \
|
||||||
+ ns + "Qt::" + enumType + "::" + enumValue + ")"
|
+ ns + "Qt::" + enumType + "::" + enumValue + ")"
|
||||||
@@ -238,25 +238,25 @@ class Dumper(DumperBase):
|
|||||||
def pokeValue(self, typeName, *args):
|
def pokeValue(self, typeName, *args):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def parseAndEvaluate(self, exp):
|
def parseAndEvaluate(self, exp: str) -> DumperBase.Value:
|
||||||
return self.fromNativeValue(self.nativeParseAndEvaluate(exp))
|
return self.fromNativeValue(self.nativeParseAndEvaluate(exp))
|
||||||
|
|
||||||
def nativeParseAndEvaluate(self, exp):
|
def nativeParseAndEvaluate(self, exp: str) -> cdbext.Value:
|
||||||
return cdbext.parseAndEvaluate(exp)
|
return cdbext.parseAndEvaluate(exp)
|
||||||
|
|
||||||
def isWindowsTarget(self):
|
def isWindowsTarget(self) -> bool:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def isQnxTarget(self):
|
def isQnxTarget(self) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def isArmArchitecture(self):
|
def isArmArchitecture(self) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def isMsvcTarget(self):
|
def isMsvcTarget(self) -> bool:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def qtCoreModuleName(self):
|
def qtCoreModuleName(self) -> str:
|
||||||
modules = cdbext.listOfModules()
|
modules = cdbext.listOfModules()
|
||||||
# first check for an exact module name match
|
# first check for an exact module name match
|
||||||
for coreName in ['Qt6Core', 'Qt6Cored', 'Qt5Cored', 'Qt5Core', 'QtCored4', 'QtCore4']:
|
for coreName in ['Qt6Core', 'Qt6Cored', 'Qt5Cored', 'Qt5Core', 'QtCored4', 'QtCore4']:
|
||||||
@@ -272,7 +272,7 @@ class Dumper(DumperBase):
|
|||||||
return coreName
|
return coreName
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def qtDeclarativeModuleName(self):
|
def qtDeclarativeModuleName(self) -> str:
|
||||||
modules = cdbext.listOfModules()
|
modules = cdbext.listOfModules()
|
||||||
for declarativeModuleName in ['Qt6Qmld', 'Qt6Qml', 'Qt5Qmld', 'Qt5Qml']:
|
for declarativeModuleName in ['Qt6Qmld', 'Qt6Qml', 'Qt5Qmld', 'Qt5Qml']:
|
||||||
if declarativeModuleName in modules:
|
if declarativeModuleName in modules:
|
||||||
@@ -285,7 +285,7 @@ class Dumper(DumperBase):
|
|||||||
return declarativeModuleName
|
return declarativeModuleName
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def qtHookDataSymbolName(self):
|
def qtHookDataSymbolName(self) -> str:
|
||||||
hookSymbolName = 'qtHookData'
|
hookSymbolName = 'qtHookData'
|
||||||
coreModuleName = self.qtCoreModuleName()
|
coreModuleName = self.qtCoreModuleName()
|
||||||
if coreModuleName is not None:
|
if coreModuleName is not None:
|
||||||
@@ -299,7 +299,7 @@ class Dumper(DumperBase):
|
|||||||
self.qtHookDataSymbolName = lambda: hookSymbolName
|
self.qtHookDataSymbolName = lambda: hookSymbolName
|
||||||
return hookSymbolName
|
return hookSymbolName
|
||||||
|
|
||||||
def qtDeclarativeHookDataSymbolName(self):
|
def qtDeclarativeHookDataSymbolName(self) -> str:
|
||||||
hookSymbolName = 'qtDeclarativeHookData'
|
hookSymbolName = 'qtDeclarativeHookData'
|
||||||
declarativeModuleName = self.qtDeclarativeModuleName()
|
declarativeModuleName = self.qtDeclarativeModuleName()
|
||||||
if declarativeModuleName is not None:
|
if declarativeModuleName is not None:
|
||||||
@@ -314,7 +314,7 @@ class Dumper(DumperBase):
|
|||||||
self.qtDeclarativeHookDataSymbolName = lambda: hookSymbolName
|
self.qtDeclarativeHookDataSymbolName = lambda: hookSymbolName
|
||||||
return hookSymbolName
|
return hookSymbolName
|
||||||
|
|
||||||
def extractQtVersion(self):
|
def extractQtVersion(self) -> int:
|
||||||
try:
|
try:
|
||||||
qtVersion = self.parseAndEvaluate(
|
qtVersion = self.parseAndEvaluate(
|
||||||
'((void**)&%s)[2]' % self.qtHookDataSymbolName()).integer()
|
'((void**)&%s)[2]' % self.qtHookDataSymbolName()).integer()
|
||||||
@@ -329,7 +329,7 @@ class Dumper(DumperBase):
|
|||||||
return None
|
return None
|
||||||
return qtVersion
|
return qtVersion
|
||||||
|
|
||||||
def putVtableItem(self, address):
|
def putVtableItem(self, address: int):
|
||||||
funcName = cdbext.getNameByAddress(address)
|
funcName = cdbext.getNameByAddress(address)
|
||||||
if funcName is None:
|
if funcName is None:
|
||||||
self.putItem(self.createPointerValue(address, 'void'))
|
self.putItem(self.createPointerValue(address, 'void'))
|
||||||
@@ -338,7 +338,7 @@ class Dumper(DumperBase):
|
|||||||
self.putType('void*')
|
self.putType('void*')
|
||||||
self.putAddress(address)
|
self.putAddress(address)
|
||||||
|
|
||||||
def putVTableChildren(self, item, itemCount):
|
def putVTableChildren(self, item: DumperBase.Value, itemCount: int) -> int:
|
||||||
p = item.address()
|
p = item.address()
|
||||||
for i in range(itemCount):
|
for i in range(itemCount):
|
||||||
deref = self.extractPointer(p)
|
deref = self.extractPointer(p)
|
||||||
@@ -350,12 +350,12 @@ class Dumper(DumperBase):
|
|||||||
p += self.ptrSize()
|
p += self.ptrSize()
|
||||||
return itemCount
|
return itemCount
|
||||||
|
|
||||||
def ptrSize(self):
|
def ptrSize(self) -> int:
|
||||||
size = cdbext.pointerSize()
|
size = cdbext.pointerSize()
|
||||||
self.ptrSize = lambda: size
|
self.ptrSize = lambda: size
|
||||||
return size
|
return size
|
||||||
|
|
||||||
def stripQintTypedefs(self, typeName):
|
def stripQintTypedefs(self, typeName: str) -> str:
|
||||||
if typeName.startswith('qint'):
|
if typeName.startswith('qint'):
|
||||||
prefix = ''
|
prefix = ''
|
||||||
size = typeName[4:]
|
size = typeName[4:]
|
||||||
@@ -375,7 +375,7 @@ class Dumper(DumperBase):
|
|||||||
else:
|
else:
|
||||||
return typeName
|
return typeName
|
||||||
|
|
||||||
def lookupNativeType(self, name, module=0):
|
def lookupNativeType(self, name: str, module=0) -> cdbext.Type:
|
||||||
if name.startswith('void'):
|
if name.startswith('void'):
|
||||||
return FakeVoidType(name, self)
|
return FakeVoidType(name, self)
|
||||||
return cdbext.lookupType(name, module)
|
return cdbext.lookupType(name, module)
|
||||||
@@ -383,13 +383,13 @@ class Dumper(DumperBase):
|
|||||||
def reportResult(self, result, args):
|
def reportResult(self, result, args):
|
||||||
cdbext.reportResult('result={%s}' % result)
|
cdbext.reportResult('result={%s}' % result)
|
||||||
|
|
||||||
def readRawMemory(self, address, size):
|
def readRawMemory(self, address: int, size: int) -> int:
|
||||||
mem = cdbext.readRawMemory(address, size)
|
mem = cdbext.readRawMemory(address, size)
|
||||||
if len(mem) != size:
|
if len(mem) != size:
|
||||||
raise Exception("Invalid memory request: %d bytes from 0x%x" % (size, address))
|
raise Exception("Invalid memory request: %d bytes from 0x%x" % (size, address))
|
||||||
return mem
|
return mem
|
||||||
|
|
||||||
def findStaticMetaObject(self, type):
|
def findStaticMetaObject(self, type: DumperBase.Type) -> int:
|
||||||
ptr = 0
|
ptr = 0
|
||||||
if type.moduleName is not None:
|
if type.moduleName is not None:
|
||||||
# Try to find the static meta object in the same module as the type definition. This is
|
# Try to find the static meta object in the same module as the type definition. This is
|
||||||
@@ -449,13 +449,10 @@ class Dumper(DumperBase):
|
|||||||
def report(self, stuff):
|
def report(self, stuff):
|
||||||
sys.stdout.write(stuff + "\n")
|
sys.stdout.write(stuff + "\n")
|
||||||
|
|
||||||
def findValueByExpression(self, exp):
|
def nativeValueDereferenceReference(self, value: DumperBase.Value) -> DumperBase.Value:
|
||||||
return cdbext.parseAndEvaluate(exp)
|
|
||||||
|
|
||||||
def nativeValueDereferenceReference(self, value):
|
|
||||||
return self.nativeValueDereferencePointer(value)
|
return self.nativeValueDereferencePointer(value)
|
||||||
|
|
||||||
def nativeValueDereferencePointer(self, value):
|
def nativeValueDereferencePointer(self, value: DumperBase.Value) -> DumperBase.Value:
|
||||||
def nativeVtCastValue(nativeValue):
|
def nativeVtCastValue(nativeValue):
|
||||||
# If we have a pointer to a derived instance of the pointer type cdb adds a
|
# 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
|
# synthetic '__vtcast_<derived type name>' member as the first child
|
||||||
@@ -490,7 +487,7 @@ class Dumper(DumperBase):
|
|||||||
def callHelper(self, rettype, value, function, args):
|
def callHelper(self, rettype, value, function, args):
|
||||||
raise Exception("cdb does not support calling functions")
|
raise Exception("cdb does not support calling functions")
|
||||||
|
|
||||||
def nameForCoreId(self, id):
|
def nameForCoreId(self, id: int) -> DumperBase.Value:
|
||||||
for dll in ['Utilsd', 'Utils']:
|
for dll in ['Utilsd', 'Utils']:
|
||||||
idName = cdbext.call('%s!Utils::nameForId(%d)' % (dll, id))
|
idName = cdbext.call('%s!Utils::nameForId(%d)' % (dll, id))
|
||||||
if idName is not None:
|
if idName is not None:
|
||||||
@@ -500,7 +497,7 @@ class Dumper(DumperBase):
|
|||||||
def putCallItem(self, name, rettype, value, func, *args):
|
def putCallItem(self, name, rettype, value, func, *args):
|
||||||
return
|
return
|
||||||
|
|
||||||
def symbolAddress(self, symbolName):
|
def symbolAddress(self, symbolName: str) -> int:
|
||||||
res = self.nativeParseAndEvaluate(symbolName)
|
res = self.nativeParseAndEvaluate(symbolName)
|
||||||
return None if res is None else res.address()
|
return None if res is None else res.address()
|
||||||
|
|
||||||
@@ -726,7 +723,7 @@ class Dumper(DumperBase):
|
|||||||
self.putItem(value.dereference())
|
self.putItem(value.dereference())
|
||||||
|
|
||||||
|
|
||||||
def putCStyleArray(self, value):
|
def putCStyleArray(self, value: DumperBase.Value):
|
||||||
arrayType = value.type
|
arrayType = value.type
|
||||||
innerType = arrayType.target()
|
innerType = arrayType.target()
|
||||||
address = value.address()
|
address = value.address()
|
||||||
|
51
share/qtcreator/debugger/cdbext.pyi
Normal file
51
share/qtcreator/debugger/cdbext.pyi
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
class Type: ...
|
||||||
|
|
||||||
|
class Field:
|
||||||
|
def name(self) -> str : ...
|
||||||
|
def isBaseClass(self) -> bool : ...
|
||||||
|
def type(self) -> Type : ...
|
||||||
|
def parentType(self) -> Type : ...
|
||||||
|
def bitsize(self) -> int : ...
|
||||||
|
def bitpos(self) -> int : ...
|
||||||
|
|
||||||
|
class Type:
|
||||||
|
def name(self) -> str: ...
|
||||||
|
def bitsize(self) -> int : ...
|
||||||
|
def code(self) -> int : ...
|
||||||
|
def unqualified(self) -> bool : ...
|
||||||
|
def target(self) -> Type : ...
|
||||||
|
def targetName(self) -> str : ...
|
||||||
|
def stripTypedef(self) -> Type : ...
|
||||||
|
def fields(self) -> Field : ...
|
||||||
|
def module(self) -> str : ...
|
||||||
|
def moduleId(self) -> int : ...
|
||||||
|
def arrayElements(self) -> int : ...
|
||||||
|
def templateArguments(self) -> list[int | str] : ...
|
||||||
|
def resolved(self) -> bool : ...
|
||||||
|
|
||||||
|
class Value: ...
|
||||||
|
class Value:
|
||||||
|
def name(self) -> str : ...
|
||||||
|
def type(self) -> Type : ...
|
||||||
|
def bitsize(self) -> int : ...
|
||||||
|
def asBytes(self) -> bytes : ...
|
||||||
|
def address(self) -> int : ...
|
||||||
|
def hasChildren(self) -> bool : ...
|
||||||
|
def expand(self) -> bool : ...
|
||||||
|
def nativeDebuggerValue(self) -> str : ...
|
||||||
|
def childFromName(self) -> Value : ...
|
||||||
|
def childFromField(self) -> Value : ...
|
||||||
|
def childFromIndex(self) -> Value : ...
|
||||||
|
|
||||||
|
def parseAndEvaluate() -> Value : ...
|
||||||
|
def resolveSymbol() -> list[str] : ...
|
||||||
|
def getNameByAddress() -> str : ...
|
||||||
|
def getAddressByName() -> int : ...
|
||||||
|
def lookupType() -> Type | None : ...
|
||||||
|
def listOfLocals() -> list[Value] : ...
|
||||||
|
def listOfModules() -> list[str] : ...
|
||||||
|
def pointerSize() -> int : ...
|
||||||
|
def readRawMemory() -> bytes : ...
|
||||||
|
def createValue() -> Value | None : ...
|
||||||
|
def call() -> Value | None : ...
|
||||||
|
def reportResult() -> None : ...
|
Reference in New Issue
Block a user