Debugger: Create a copy of the current dumper code

The current code supports Python 2 and Python 3 based debugger backends
(gdb, lldb) at the same time, but we'd like to drop Python 2 support
so we can take advantage of some of Python 3's goodies.

This copy here is not meant to be used in general but could perhaps be
used to replace the main code in situations that cannot use Python 3 yet.

Change-Id: I62273bc41b5a1e3a24720e167e64e4eac2e0c056
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
hjk
2023-12-04 16:18:00 +01:00
parent ee4493ffa4
commit 311c95cfcc
17 changed files with 17653 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
This is a copy of a previous version of share/qtcreator/debugger/*.py
which supported Python 2 and Python 3 based debugger backends (gdb,
lldb) at the same time.
The code there is now Python-3-only. This copy here is not meant to be
used in general but could perhaps be used to replace the main code
in situations that cannot use Python 3 yet.

View File

@@ -0,0 +1,133 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
from dumper import DumperBase
from utils import DisplayFormat
import stdtypes
import libcpp_stdtypes
def qform__std____ndk1__array():
return [DisplayFormat.ArrayPlot]
def qdump__std____ndk1__array(d, value):
stdtypes.qdump__std__array(d, value)
def qdump__std____ndk1__complex(d, value):
stdtypes.qdump__std__complex(d, value)
def qdump__std____ndk1__deque(d, value):
stdtypes.qdumpHelper__std__deque__libcxx(d, value)
def qdump__std____ndk1__list(d, value):
return libcpp_stdtypes.qdump__std____1__list(d, value)
def qdump__std____ndk1__set(d, value):
return libcpp_stdtypes.qdump__std____1__set(d, value)
def qdump__std____ndk1__multiset(d, value):
qdump__std____ndk1__set(d, value)
def qform__std____ndk1__map():
return [DisplayFormat.CompactMap]
def qdump__std____ndk1__map(d, value):
return libcpp_stdtypes.qdump__std____1__map(d, value)
def qform__std____ndk1__multimap():
return [DisplayFormat.CompactMap]
def qdump__std____ndk1__multimap(d, value):
qdump__std____ndk1__map(d, value)
def qdump__std____ndk1__map__iterator(d, value):
return libcpp_stdtypes.qdump__std____1__map__iterator(d, value)
def qdump__std____ndk1__map__const_iterator(d, value):
qdump__std____ndk1__map__iterator(d, value)
def qdump__std____ndk1__set__iterator(d, value):
return libcpp_stdtypes.qdump__std____1__set__iterator(d, value)
def qdump__std____ndk1__set_const_iterator(d, value):
qdump__std____ndk1__set__iterator(d, value)
def qdump__std____ndk1__stack(d, value):
return libcpp_stdtypes.qdump__std____1__stack(d, value)
def qdump__std____ndk1__string(d, value):
return libcpp_stdtypes.qdump__std____1__string(d, value)
def qdump__std____ndk1__wstring(d, value):
return libcpp_stdtypes.qdump__std____1__wstring(d, value)
def qdump__std____ndk1__basic_string(d, value):
return libcpp_stdtypes.qdump__std____1__basic_string(d, value)
def qdump__std____ndk1__shared_ptr(d, value):
return libcpp_stdtypes.qdump__std____1__shared_ptr(d, value)
def qdump__std____ndk1__weak_ptr(d, value):
return qdump__std____ndk1__shared_ptr(d, value)
def qdump__std____ndk1__unique_ptr(d, value):
stdtypes.qdump__std__unique_ptr(d, value)
def qform__std____ndk1__unordered_map():
return [DisplayFormat.CompactMap]
def qdump__std____ndk1__unordered_map(d, value):
libcpp_stdtypes.qdump__std____1__unordered_map(d, value)
def qdump__std____ndk1__unordered_set(d, value):
return libcpp_stdtypes.qdump__std____1__unordered_set(d, value)
def qdump__std____ndk1__unordered_multiset(d, value):
qdump__std____ndk1__unordered_set(d, value)
def qform__std____ndk1__valarray():
return [DisplayFormat.ArrayPlot]
def qdump__std____ndk1__valarray(d, value):
return libcpp_stdtypes.qdump__std____1__valarray(d, value)
def qform__std____ndk1__vector():
return [DisplayFormat.ArrayPlot]
def qdump__std____ndk1__vector(d, value):
stdtypes.qdumpHelper__std__vector__libcxx(d, value)
def qdump__std____ndk1__once_flag(d, value):
stdtypes.qdump__std__once_flag(d, value)

View File

@@ -0,0 +1,184 @@
# Copyright (C) 2016 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
from utils import DisplayFormat
from dumper import Children
def qdump__boost__bimaps__bimap(d, value):
#leftType = value.type[0]
#rightType = value.type[1]
size = value["core"]["node_count"].integer()
d.putItemCount(size)
if d.isExpanded():
d.putPlainChildren(value)
def qdump__boost__optional(d, value):
innerType = value.type[0]
(initialized, pad, payload) = d.split('b@{%s}' % innerType.name, value)
if initialized:
d.putItem(payload)
d.putBetterType(value.type)
else:
d.putSpecialValue("uninitialized")
def qdump__boost__shared_ptr(d, value):
# s boost::shared_ptr<int>
# px 0x0 int *
# pn boost::detail::shared_count
# pi_ 0x0 boost::detail::sp_counted_base *
(px, pi) = value.split("pp")
if pi == 0:
d.putValue("(null)")
return
if px == 0:
d.putValue("(null)")
return
(vptr, usecount, weakcount) = d.split('pii', pi)
d.check(weakcount >= 0)
d.check(weakcount <= usecount)
d.check(usecount <= 10 * 1000 * 1000)
d.putItem(d.createValue(px, value.type[0]))
d.putBetterType(value.type)
def qdump__boost__container__list(d, value):
try:
m_icont = value["m_icont"]
except:
m_icont = value["members_"]["m_icont"]
r = m_icont["data_"]["root_plus_size_"]
n = r["size_"].integer()
d.putItemCount(n)
if d.isExpanded():
innerType = value.type[0]
offset = 2 * d.ptrSize()
with Children(d, n):
try:
root = r["root_"]
except:
root = r["m_header"]
p = root["next_"].extractPointer()
for i in d.childRange():
d.putSubItem(i, d.createValue(p + offset, innerType))
p = d.extractPointer(p)
def qform__boost__container__vector():
return [DisplayFormat.ArrayPlot]
def qdump__boost__container__vector(d, value):
holder = value["m_holder"]
size = holder["m_size"].integer()
d.putItemCount(size)
if d.isExpanded():
T = value.type[0]
try:
start = holder["m_start"].pointer()
except:
start = holder["storage"].address()
d.putPlotData(start, size, T)
def qform__boost__container__static_vector():
return [DisplayFormat.ArrayPlot]
def qdump__boost__container__static_vector(d, value):
qdump__boost__container__vector(d, value)
def qform__boost__container__small_vector():
return [DisplayFormat.ArrayPlot]
def qdump__boost__container__small_vector(d, value):
qdump__boost__container__vector(d, value)
def qdump__boost__gregorian__date(d, value):
d.putValue(value.integer(), "juliandate")
def qdump__boost__posix_time__ptime(d, value):
ms = int(value.integer() / 1000)
d.putValue("%s/%s" % divmod(ms, 86400000), "juliandateandmillisecondssincemidnight")
def qdump__boost__posix_time__time_duration(d, value):
d.putValue(int(value.integer() / 1000), "millisecondssincemidnight")
def qdump__boost__unordered__unordered_set(d, value):
innerType = value.type[0]
if value.type.size() == 7 * d.ptrSize(): # 56 for boost 1.79+
bases, bucketCount, bcountLog2, size, mlf, maxload, buckets = value.split('ttttttp')
forward = True
elif value.type.size() == 6 * d.ptrSize(): # 48 for boost 1.55+
# boost 1.58 or 1.55
# bases are 3? bytes, and mlf is actually a float, but since
# its followed by size_t maxload, it's # effectively padded to a size_t
bases, bucketCount, size, mlf, maxload, buckets = value.split('tttttp')
# Distinguish 1.58 and 1.55. 1.58 used one template argument, 1.55 two.
try:
ittype = d.lookupType(value.type.name + '::iterator').target()
forward = len(ittype.templateArguments()) == 1
except:
forward = True
elif value.type.size() == 5 * d.ptrSize(): # 40 for boost 1.48
# boost 1.48
# Values are stored before the next pointers. Determine the offset.
buckets, bucketCount, size, mlf, maxload = value.split('ptttt')
forward = False
else:
raise Exception("Unknown boost::unordered_set layout")
if forward:
# boost >= 1.58
code = 'pp{%s}' % innerType.name
def children(p):
while True:
p, dummy, val = d.split(code, p)
yield val
else:
# boost 1.48 or 1.55
code = '{%s}@p' % innerType.name
(pp, ssize, fields) = d.describeStruct(code)
offset = fields[2].offset()
def children(p):
while True:
val, pad, p = d.split(code, p - offset)
yield val
p = d.extractPointer(buckets + bucketCount * d.ptrSize())
d.putItems(size, children(p), maxNumChild=10000)
def qdump__boost__variant(d, value):
allTypes = value.type.templateArguments()
realType = allTypes[value.split('i')[0]]
alignment = max([t.alignment() for t in allTypes])
dummy, val = value.split('%is{%s}' % (max(4, alignment), realType.name))
d.putItem(val)
d.putBetterType(value.type)
def qdump__boost__container__devector(d, value):
inner_type = value.type[0]
buffer = value["m_"]["buffer"].pointer()
front_idx = value["m_"]["front_idx"].integer()
back_idx = value["m_"]["back_idx"].integer()
start = buffer + (front_idx * inner_type.size())
size = int(back_idx - front_idx)
if size > 0:
d.checkPointer(start)
d.putItemCount(size)
d.putPlotData(start, size, inner_type)

View File

@@ -0,0 +1,514 @@
# Copyright (C) 2016 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import inspect
import os
import sys
import cdbext
import re
import threading
from utils import TypeCode
sys.path.insert(1, os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))))
from dumper import DumperBase, SubItem
class FakeVoidType(cdbext.Type):
def __init__(self, name, dumper):
cdbext.Type.__init__(self)
self.typeName = name.strip()
self.dumper = dumper
def name(self):
return self.typeName
def bitsize(self):
return self.dumper.ptrSize() * 8
def code(self):
if self.typeName.endswith('*'):
return TypeCode.Pointer
if self.typeName.endswith(']'):
return TypeCode.Array
return TypeCode.Void
def unqualified(self):
return self
def target(self):
code = self.code()
if code == TypeCode.Pointer:
return FakeVoidType(self.typeName[:-1], self.dumper)
if code == TypeCode.Void:
return self
try:
return FakeVoidType(self.typeName[:self.typeName.rindex('[')], self.dumper)
except:
return FakeVoidType('void', self.dumper)
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
def stripTypedef(self):
return self
def fields(self):
return []
def templateArgument(self, pos, numeric):
return None
def templateArguments(self):
return []
class Dumper(DumperBase):
def __init__(self):
DumperBase.__init__(self)
self.outputLock = threading.Lock()
self.isCdb = True
def enumValue(self, nativeValue):
val = nativeValue.nativeDebuggerValue()
# remove '0n' decimal prefix of the native cdb value output
return val.replace('(0n', '(')
def fromNativeValue(self, nativeValue):
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:
try:
integerString = nativeValue.nativeDebuggerValue()
except UnicodeDecodeError:
integerString = '' # cannot decode - read raw
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:
integerString = integerString.replace('`', '')
integerString = integerString.split(' ')[0]
if integerString.startswith('0n'):
integerString = integerString[2:]
base = 10
elif integerString.startswith('0x'):
base = 16
else:
base = 10
signed = not val._type.name.startswith('unsigned')
try:
val.ldata = int(integerString, base).to_bytes(val._type.size(),
byteorder='little', signed=signed)
except:
# read raw memory in case the integerString can not be interpreted
pass
if val._type.code == TypeCode.Enum:
val.ldisplay = self.enumValue(nativeValue)
val.isBaseClass = val.name == val._type.name
val.nativeValue = nativeValue
val.laddress = nativeValue.address()
val.lbitsize = nativeValue.bitsize()
return val
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
typeId = c + ''.join(['{%s:%s}' % (f.name(), self.nativeTypeId(f.type()))
for f in nativeType.fields()])
return typeId
def fromNativeType(self, nativeType):
self.check(isinstance(nativeType, cdbext.Type))
typeId = self.nativeTypeId(nativeType)
if self.typeData.get(typeId, None) is not None:
return self.Type(self, typeId)
if nativeType.name().startswith('void'):
nativeType = FakeVoidType(nativeType.name(), self)
code = nativeType.code()
if code == TypeCode.Pointer:
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)
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())
code = TypeCode.Struct
tdata = self.TypeData(self, typeId)
tdata.name = nativeType.name()
tdata.lbitsize = nativeType.bitsize()
tdata.code = code
tdata.moduleName = 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)
index = 0
nativeMember = nativeValue.childFromIndex(index)
while nativeMember is not None:
yield self.fromNativeValue(nativeMember)
index += 1
nativeMember = nativeValue.childFromIndex(index)
def nativeStructAlignment(self, nativeType):
#DumperBase.warn("NATIVE ALIGN FOR %s" % nativeType.name)
def handleItem(nativeFieldType, align):
a = self.fromNativeType(nativeFieldType).alignment()
return a if a > align else align
align = 1
for f in nativeType.fields():
align = handleItem(f.type(), align)
return align
def nativeTypeEnumDisplay(self, nativeType, intval, form):
value = self.nativeParseAndEvaluate('(%s)%d' % (nativeType.name(), intval))
if value is None:
return ''
return self.enumValue(value)
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):
return self.fromNativeValue(self.nativeParseAndEvaluate(exp))
def nativeParseAndEvaluate(self, exp):
return cdbext.parseAndEvaluate(exp)
def isWindowsTarget(self):
return True
def isQnxTarget(self):
return False
def isArmArchitecture(self):
return False
def isMsvcTarget(self):
return True
def qtCoreModuleName(self):
modules = cdbext.listOfModules()
# first check for an exact module name match
for coreName in ['Qt6Core', 'Qt6Cored', 'Qt5Cored', 'Qt5Core', 'QtCored4', 'QtCore4']:
if coreName in modules:
self.qtCoreModuleName = lambda: coreName
return coreName
# maybe we have a libinfix build.
for pattern in ['Qt6Core.*', 'Qt5Core.*', 'QtCore.*']:
matches = [module for module in modules if re.match(pattern, module)]
if matches:
coreName = matches[0]
self.qtCoreModuleName = lambda: coreName
return coreName
return None
def qtDeclarativeModuleName(self):
modules = cdbext.listOfModules()
for declarativeModuleName in ['Qt6Qmld', 'Qt6Qml', 'Qt5Qmld', 'Qt5Qml']:
if declarativeModuleName in modules:
self.qtDeclarativeModuleName = lambda: declarativeModuleName
return declarativeModuleName
matches = [module for module in modules if re.match('Qt[56]Qml.*', module)]
if matches:
declarativeModuleName = matches[0]
self.qtDeclarativeModuleName = lambda: declarativeModuleName
return declarativeModuleName
return None
def qtHookDataSymbolName(self):
hookSymbolName = 'qtHookData'
coreModuleName = self.qtCoreModuleName()
if coreModuleName is not None:
hookSymbolName = '%s!%s%s' % (coreModuleName, self.qtNamespace(), hookSymbolName)
else:
resolved = cdbext.resolveSymbol('*' + hookSymbolName)
if resolved:
hookSymbolName = resolved[0]
else:
hookSymbolName = '*%s' % hookSymbolName
self.qtHookDataSymbolName = lambda: hookSymbolName
return hookSymbolName
def qtDeclarativeHookDataSymbolName(self):
hookSymbolName = 'qtDeclarativeHookData'
declarativeModuleName = self.qtDeclarativeModuleName()
if declarativeModuleName is not None:
hookSymbolName = '%s!%s%s' % (declarativeModuleName, self.qtNamespace(), hookSymbolName)
else:
resolved = cdbext.resolveSymbol('*' + hookSymbolName)
if resolved:
hookSymbolName = resolved[0]
else:
hookSymbolName = '*%s' % hookSymbolName
self.qtDeclarativeHookDataSymbolName = lambda: hookSymbolName
return hookSymbolName
def qtNamespace(self):
namespace = ''
qstrdupSymbolName = '*qstrdup'
coreModuleName = self.qtCoreModuleName()
if coreModuleName is not None:
qstrdupSymbolName = '%s!%s' % (coreModuleName, qstrdupSymbolName)
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()
self.qtNamespace = lambda: namespace
return namespace
def qtVersion(self):
qtVersion = None
try:
qtVersion = self.parseAndEvaluate(
'((void**)&%s)[2]' % self.qtHookDataSymbolName()).integer()
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
if qtVersion is None:
qtVersion = self.fallbackQtVersion
self.qtVersion = lambda: qtVersion
return qtVersion
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()
for i in range(itemCount):
deref = self.extractPointer(p)
if deref == 0:
n = i
break
with SubItem(self, i):
self.putVtableItem(deref)
p += self.ptrSize()
return itemCount
def ptrSize(self):
size = cdbext.pointerSize()
self.ptrSize = lambda: size
return size
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
def lookupType(self, typeNameIn, module=0):
if len(typeNameIn) == 0:
return None
typeName = self.stripQintTypedefs(typeNameIn)
if self.typeData.get(typeName, None) is None:
nativeType = self.lookupNativeType(typeName, module)
if nativeType is None:
return None
_type = self.fromNativeType(nativeType)
if _type.typeId != typeName:
self.registerTypeAlias(_type.typeId, typeName)
return _type
return self.Type(self, typeName)
def lookupNativeType(self, name, module=0):
if name.startswith('void'):
return FakeVoidType(name, self)
return cdbext.lookupType(name, module)
def reportResult(self, result, args):
cdbext.reportResult('result={%s}' % result)
def readRawMemory(self, address, size):
mem = cdbext.readRawMemory(address, size)
if len(mem) != size:
raise Exception("Invalid memory request: %d bytes from 0x%x" % (size, address))
return mem
def findStaticMetaObject(self, type):
typeName = type.name
if type.moduleName is not None:
typeName = type.moduleName + '!' + typeName
ptr = cdbext.getAddressByName(typeName + '::staticMetaObject')
return ptr
def warn(self, msg):
self.put('{name="%s",value="",type="",numchild="0"},' % msg)
def fetchVariables(self, args):
self.resetStats()
(ok, res) = self.tryFetchInterpreterVariables(args)
if ok:
self.reportResult(res, args)
return
self.setVariableFetchingOptions(args)
self.output = []
self.currentIName = 'local'
self.put('data=[')
self.anonNumber = 0
variables = []
for val in cdbext.listOfLocals(self.partialVariable):
dumperVal = self.fromNativeValue(val)
dumperVal.lIsInScope = dumperVal.name not in self.uninitialized
variables.append(dumperVal)
self.handleLocals(variables)
self.handleWatches(args)
self.put('],partial="%d"' % (len(self.partialVariable) > 0))
self.put(',timings=%s' % self.timings)
if self.forceQtNamespace:
self.qtNamespaceToReport = self.qtNamespace()
if self.qtNamespaceToReport:
self.put(',qtnamespace="%s"' % self.qtNamespaceToReport)
self.qtNamespaceToReport = None
self.reportResult(''.join(self.output), args)
self.output = []
def report(self, stuff):
sys.stdout.write(stuff + "\n")
def findValueByExpression(self, exp):
return cdbext.parseAndEvaluate(exp)
def nativeDynamicTypeName(self, address, baseType):
return None # Does not work with cdb
def nativeValueDereferenceReference(self, value):
return self.nativeValueDereferencePointer(value)
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
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()))
castVal = nativeVtCastValue(nativeValue)
if castVal is not None:
val = self.fromNativeValue(castVal)
else:
val = self.Value(self)
val.laddress = value.pointer()
val._type = value.type.dereference()
val.nativeValue = value.nativeValue
return val
def callHelper(self, rettype, value, function, args):
raise Exception("cdb does not support calling functions")
def nameForCoreId(self, id):
for dll in ['Utilsd', 'Utils']:
idName = cdbext.call('%s!Utils::nameForId(%d)' % (dll, id))
if idName is not None:
break
return self.fromNativeValue(idName)
def putCallItem(self, name, rettype, value, func, *args):
return
def symbolAddress(self, symbolName):
res = self.nativeParseAndEvaluate(symbolName)
return None if res is None else res.address()

View File

@@ -0,0 +1,371 @@
# Copyright (C) 2016 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
from dumper import Children
def typeTarget(type):
target = type.target()
if target:
return target
return type
def stripTypeName(value):
return typeTarget(value.type).unqualified().name
def extractPointerType(d, value):
postfix = ""
while stripTypeName(value) == "CPlusPlus::PointerType":
postfix += "*"
value = value["_elementType"]["_type"]
try:
return readLiteral(d, value["_name"]) + postfix
except:
typeName = typeTarget(value.type.unqualified()).name
if typeName == "CPlusPlus::IntegerType":
return "int" + postfix
elif typeName == "CPlusPlus::VoidType":
return "void" + postfix
return "<unsupported>"
def readTemplateName(d, value):
name = readLiteral(d, value["_identifier"]) + "<"
args = value["_templateArguments"]
impl = args["_M_impl"]
start = impl["_M_start"]
size = impl["_M_finish"] - start
try:
d.check(0 <= size and size <= 100)
d.checkPointer(start)
for i in range(int(size)):
if i > 0:
name += ", "
name += extractPointerType(d, start[i]["_type"])
except:
return "<not accessible>"
name += ">"
return name
def readLiteral(d, value):
if not value.integer():
return "<null>"
type = typeTarget(value.type.unqualified())
if type and (type.name == "CPlusPlus::TemplateNameId"):
return readTemplateName(d, value)
elif type and (type.name == "CPlusPlus::QualifiedNameId"):
return readLiteral(d, value["_base"]) + "::" + readLiteral(d, value["_name"])
try:
return bytes(d.readRawMemory(value["_chars"], value["_size"])).decode('latin1')
except:
return "<unsupported>"
def dumpLiteral(d, value):
d.putValue(d.hexencode(readLiteral(d, value)), "latin1")
def qdump__Utils__Id(d, value):
val = value.extractPointer()
if True:
if d.isMsvcTarget():
name = d.nameForCoreId(val).address()
else:
name = d.parseAndEvaluate("Utils::nameForId(0x%x)" % val).pointer()
d.putSimpleCharArray(name)
else:
d.putValue(val)
d.putPlainChildren(value)
def qdump__Utils__Key(d, value):
d.putByteArrayValue(value["data"])
d.putBetterType(value.type)
def qdump__Debugger__Internal__GdbMi(d, value):
val = d.encodeString(value["m_name"]) + "3a002000" \
+ d.encodeString(value["m_data"])
d.putValue(val, "utf16")
d.putPlainChildren(value)
def qdump__Debugger__Internal__DisassemblerLine(d, value):
d.putByteArrayValue(value["m_data"])
d.putPlainChildren(value)
def qdump__Debugger__Internal__WatchData(d, value):
d.putStringValue(value["iname"])
d.putPlainChildren(value)
def qdump__Debugger__Internal__WatchItem(d, value):
d.putStringValue(value["iname"])
d.putPlainChildren(value)
def qdump__Debugger__Internal__BreakpointModelId(d, value):
d.putValue("%s.%s" % (value["m_majorPart"].integer(), value["m_minorPart"].integer()))
d.putPlainChildren(value)
def qdump__Debugger__Internal__ThreadId(d, value):
d.putValue("%s" % value["m_id"])
d.putPlainChildren(value)
def qdump__CPlusPlus__ByteArrayRef(d, value):
d.putSimpleCharArray(value["m_start"], value["m_length"])
d.putPlainChildren(value)
def qdump__CPlusPlus__Identifier(d, value):
try:
d.putSimpleCharArray(value["_chars"], value["_size"])
except:
pass
d.putPlainChildren(value)
def qdump__CPlusPlus__Symbol(d, value):
dumpLiteral(d, value["_name"])
d.putBetterType(value.type)
d.putPlainChildren(value)
def qdump__CPlusPlus__Class(d, value):
qdump__CPlusPlus__Symbol(d, value)
def kindName(d, value):
e = value.integer()
if e:
kindType = d.lookupType("CPlusPlus::Kind")
return kindType.tdata.enumDisplay(e, value.address(), '%d')[11:]
else:
return ''
def qdump__CPlusPlus__IntegerType(d, value):
d.putValue(kindName(d, value["_kind"]))
d.putPlainChildren(value)
def qdump__CPlusPlus__FullySpecifiedType(d, value):
type = value["_type"]
typeName = stripTypeName(type)
if typeName == "CPlusPlus::NamedType":
dumpLiteral(d, type["_name"])
elif typeName == "CPlusPlus::PointerType":
d.putValue(d.hexencode(extractPointerType(d, type)), "latin1")
d.putPlainChildren(value)
def qdump__CPlusPlus__NamedType(d, value):
dumpLiteral(d, value["_name"])
d.putBetterType(value.type)
d.putPlainChildren(value)
def qdump__CPlusPlus__PointerType(d, value):
d.putValue(d.hexencode(extractPointerType(d, value)), "latin1")
d.putPlainChildren(value)
def qdump__CPlusPlus__TemplateNameId(d, value):
dumpLiteral(d, value)
d.putBetterType(value.type)
d.putPlainChildren(value)
def qdump__CPlusPlus__QualifiedNameId(d, value):
dumpLiteral(d, value)
d.putPlainChildren(value)
def qdump__CPlusPlus__Literal(d, value):
dumpLiteral(d, value)
d.putPlainChildren(value)
def qdump__CPlusPlus__StringLiteral(d, value):
d.putSimpleCharArray(value["_chars"], value["_size"])
d.putPlainChildren(value)
def qdump__CPlusPlus__Internal__Value(d, value):
d.putValue(value["l"])
d.putPlainChildren(value)
def qdump__Utils__FilePath(d, value):
data, path_len, scheme_len, host_len = d.split("{@QString}IHH", value)
elided, enc = d.encodeStringHelper(data, d.displayStringLimit)
# enc is concatenated path + scheme + host
if scheme_len:
scheme_pos = path_len * 4
host_pos = scheme_pos + scheme_len * 4
path_enc = enc[0 : path_len * 4]
scheme_enc = enc[scheme_pos : scheme_pos + scheme_len * 4]
host_enc = enc[host_pos : host_pos + host_len * 4]
slash = "2F00"
dot = "2E00"
colon = "3A00"
val = scheme_enc + colon + slash + slash + host_enc
if not path_enc.startswith(slash):
val += slash + dot + slash
val += path_enc
else:
val = enc
d.putValue(val, "utf16", elided=elided)
d.putPlainChildren(value)
def qdump__Utils__FileName(d, value):
qdump__Utils__FilePath(d, value)
def qdump__Utils__ElfSection(d, value):
d.putByteArrayValue(value["name"])
d.putPlainChildren(value)
def qdump__Utils__Port(d, value):
d.putValue(d.extractInt(value))
d.putPlainChildren(value)
def x_qdump__Utils__Environment(d, value):
qdump__Utils__NameValueDictionary(d, value)
def qdump__Utils__DictKey(d, value):
d.putStringValue(value["name"])
def x_qdump__Utils__NameValueDictionary(d, value):
dptr = d.extractPointer(value)
if d.qtVersion() >= 0x60000:
if dptr == 0:
d.putItemCount(0)
return
m = value['d']['d']['m']
d.putItem(m)
d.putBetterType('Utils::NameValueDictionary')
else: # Qt5
(ref, n) = d.split('ii', dptr)
d.check(0 <= n and n <= 100 * 1000 * 1000)
d.check(-1 <= ref and ref < 100000)
d.putItemCount(n)
if d.isExpanded():
if n > 10000:
n = 10000
typeCode = 'ppp@{%s}@{%s}' % ("Utils::DictKey", "@QPair<@QString,bool>")
def helper(node):
(p, left, right, padding1, key, padding2, value) = d.split(typeCode, node)
if left:
for res in helper(left):
yield res
yield (key["name"], value)
if right:
for res in helper(right):
yield res
with Children(d, n):
for (pair, i) in zip(helper(dptr + 8), range(n)):
d.putPairItem(i, pair, 'key', 'value')
def qdump__Utf8String(d, value):
d.putByteArrayValue(value['byteArray'])
d.putPlainChildren(value)
def qdump__CPlusPlus__Token(d, value):
k = value["f"]["kind"]
e = k.lvalue
type = kindName(d, k)
try:
if e == 6:
type = readLiteral(d, value["identifier"]) + " (%s)" % type
elif e >= 7 and e <= 23:
type = readLiteral(d, value["literal"]) + " (%s)" % type
except:
pass
d.putValue(type)
d.putPlainChildren(value)
def qdump__CPlusPlus__Internal__PPToken(d, value):
data, size, alloc = d.qArrayData(value["m_src"])
length = value["f"]["utf16chars"].integer()
offset = value["utf16charOffset"].integer()
#DumperBase.warn("size: %s, alloc: %s, offset: %s, length: %s, data: %s"
# % (size, alloc, offset, length, data))
d.putValue(d.readMemory(data + offset, min(100, length)), "latin1")
d.putPlainChildren(value)
def qdump__ProString(d, value):
try:
s = value["m_string"]
data, size, alloc = d.stringData(s)
data += 2 * value["m_offset"].integer()
size = value["m_length"].integer()
s = d.readMemory(data, 2 * size)
d.putValue(s, "utf16")
except:
d.putEmptyValue()
d.putPlainChildren(value)
def qdump__ProKey(d, value):
qdump__ProString(d, value)
d.putBetterType(value.type)
def qdump__Core__GeneratedFile(d, value):
d.putStringValue(value["m_d"]["d"]["path"])
d.putPlainChildren(value)
#def qdump__ProjectExplorer__Node(d, value):
# d.putStringValue(value["m_filePath"])
# d.putPlainChildren(value)
#
#def qdump__ProjectExplorer__FolderNode(d, value):
# d.putStringValue(value["m_displayName"])
# d.putPlainChildren(value)
# Broke when moving to unique_ptr
#def qdump__ProjectExplorer__ToolChain(d, value):
# d.putStringValue(value["d"]["m_displayName"])
# d.putPlainChildren(value)
# Broke when moving to unique_ptr
#def qdump__ProjectExplorer__Kit(d, value):
# d.putStringValue(value["d"]["m_unexpandedDisplayName"])
# d.putPlainChildren(value)
def qdump__ProjectExplorer__ProjectNode(d, value):
qdump__ProjectExplorer__FolderNode(d, value)
def qdump__CMakeProjectManager__Internal__CMakeProjectNode(d, value):
qdump__ProjectExplorer__FolderNode(d, value)
def qdump__QmakeProjectManager__QmakePriFileNode(d, value):
qdump__ProjectExplorer__FolderNode(d, value)
def qdump__QmakeProjectManager__QmakeProFileNode(d, value):
qdump__ProjectExplorer__FolderNode(d, value)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,377 @@
# Copyright (C) 2021 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import gdb
import sys
import time
# for ProcessName capture
try:
import psutil
except:
psutil = None
# Caps types
Address, \
Caller, \
Callstack, \
FilePos, \
Function, \
Pid, \
ProcessName, \
Tick, \
Tid, \
ThreadName, \
Expression, \
= range(0, 11)
class GDBTracepoint(gdb.Breakpoint):
"""
Python Breakpoint extension for "tracepoints", breakpoints that do not stop the inferior
"""
@staticmethod
def create(args, onModified, onHit, onExpression):
"""
Static creator function
"""
tp_kwargs = {}
if 'temporary' in args.keys():
tp_kwargs['temporary'] = args['temporary']
spec = args['spec']
tp = GDBTracepoint(spec, **tp_kwargs)
tp.onModified = onModified
tp.onHit = onHit
tp.onExpression = onExpression
if 'ignore_count' in args.keys():
tp.ignore_count = args['ignore_count']
if 'enabled' in args.keys():
tp.enabled = args['enabled']
if 'thread' in args.keys():
tp.thread = args['thread']
if 'condition' in args.keys():
tp.condition = args['condition']
if 'caps' in args.keys():
for ce in args['caps']:
tp.addCaps(ce[0], ce[1])
return tp
def __init__(self, spec, **kwargs):
"""
Constructor
"""
kwargs['internal'] = True
super(GDBTracepoint, self).__init__(spec, **kwargs)
self.caps = []
_hexSize = 8 if sys.maxsize > 2**32 else 4
_hasMonotonicTime = False if sys.version_info[0] <= 2 or (sys.version_info[0] == 3 and sys.version_info[1] < 3) else True
def dicts(self):
"""
Returns dictionareis for mi representation
"""
results = []
result = {}
result['number'] = str(self.number)
result['enabled'] = 'y' if self.enabled else 'n'
result['type'] = 'pseudo_tracepoint'
result['disp'] = 'del' if self.temporary else 'keep'
result['times'] = str(self.hit_count)
result['original-location'] = self.location
try:
d = gdb.decode_line(self.location)
if d[1] is None:
result['addr'] = '<PENDING>'
result['pending'] = self.location
results.append(result)
else:
if len(d[1]) > 1:
result['addr'] = '<MULTIPLE>'
results.append(result)
for i, sl in enumerate(d[1]):
result_ = {}
result_['number'] = result['number'] + "." + str(i + 1)
result_['enabled'] = 'y' if self.enabled else 'n'
if sl.pc is None:
result_['addr'] = '<no address>'
else:
result_['addr'] = '{0:#0{1}x}'.format(sl.pc, self._hexSize + 2)
if sl.symtab and sl.symtab.is_valid():
func = self._getFunctionFromAddr(sl.pc)
if func:
result_['func'] = func.print_name
result_['file'] = sl.symtab.filename
result_['fullname'] = sl.symtab.fullname()
result_['line'] = sl.line
results.append(result_)
else:
sl = d[1][0]
if sl.pc is None:
result['addr'] = '<no address>'
else:
result['addr'] = '{0:#0{1}x}'.format(sl.pc, self._hexSize + 2)
if sl.symtab and sl.symtab.is_valid():
func = self._getFunctionFromAddr(sl.pc)
if func:
result['func'] = func.print_name
result['file'] = sl.symtab.filename
result['fullname'] = sl.symtab.fullname()
result['line'] = sl.line
results.append(result)
except Exception as e:
import traceback
traceback.print_exc()
result['addr'] = '<PENDING>'
result['pending'] = self.location
results.append(result)
return results
def addCaps(self, capsType, expression=None):
"""
Adds capture expressions for a tracepoint
:param caps_type: Type of capture
:param expression: Expression for Expression caps type
"""
if capsType != Expression:
expression = None
else:
if expression is None:
expression = ''
self.caps.append((self.capsMap[capsType], expression))
def stop(self):
"""
Overridden stop function, this evaluates conditions and captures data from the inferior
:return: Always False
"""
try:
self.onModified(self)
result = {}
result['number'] = self.number
try:
if self.condition:
try:
result = gdb.parse_and_eval(self.condition)
if result.type.code == gdb.TYPE_CODE_BOOL and str(result) == 'false':
return False
except:
pass
if self.ignore_count > 0:
return False
if self.thread and gdb.selected_thread().global_num != self.thread:
return False
except Exception as e:
result['warning'] = str(e)
self.onHit(self, result)
return False
if len(self.caps) > 0:
caps = []
try:
for func, expr in self.caps:
if expr is None:
caps.append(func(self))
else:
caps.append(func(self, expr))
except Exception as e:
result['warning'] = str(e)
self.onHit(self, result)
return False
result['caps'] = caps
self.onHit(self, result)
return False
except:
# Always return false, regardless...
return False
def _getFunctionFromAddr(self, addr):
try:
block = gdb.block_for_pc(addr)
while block and not block.function:
block = block.superblock
if block is None:
return None
return block.function
except:
return None
def _getAddress(self):
"""
Capture function for Address
"""
try:
frame = gdb.selected_frame()
if not (frame is None) and (frame.is_valid()):
return '{0:#0{1}x}'.format(frame.pc(), self._hexSize + 2)
except Exception as e:
return str(e)
return '<null address>'
def _getCaller(self):
"""
Capture function for Caller
"""
try:
frame = gdb.selected_frame()
if not (frame is None) and (frame.is_valid()):
frame = frame.older()
if not (frame is None) and (frame.is_valid()):
name = frame.name()
if name is None:
return '<unknown caller>'
return name
except Exception as e:
return str(e)
return '<unknown caller>'
def _getCallstack(self):
"""
Capture function for Callstack
"""
try:
frames = []
frame = gdb.selected_frame()
if (frame is None) or (not frame.is_valid()):
frames.append('<unknown frame>')
return str(frames)
while not (frame is None):
func = frame.function()
if func is None:
frames.append('{0:#0{1}x}'.format(frame.pc(), self._hexSize + 2))
else:
sl = frame.find_sal()
if sl is None:
frames.append(func.symtab.filename)
else:
frames.append(func.symtab.filename + ':' + str(sl.line))
frame = frame.older()
return frames
except Exception as e:
return str(e)
def _getFilePos(self):
"""
Capture function for FilePos
"""
try:
frame = gdb.selected_frame()
if (frame is None) or (not frame.is_valid()):
return '<unknown file pos>'
sl = frame.find_sal()
if sl is None:
return '<unknown file pos>'
return sl.symtab.filename + ':' + str(sl.line)
except Exception as e:
return str(e)
def _getFunction(self):
"""
Capture function for Function
"""
try:
frame = gdb.selected_frame()
if not (frame is None):
return str(frame.name())
except Exception as e:
return str(e)
return '<unknown function>'
def _getPid(self):
"""
Capture function for Pid
"""
try:
thread = gdb.selected_thread()
if not (thread is None):
(pid, lwpid, tid) = thread.ptid
return str(pid)
except Exception as e:
return str(e)
return '<unknown pid>'
def _getProcessName(slef):
"""
Capture for ProcessName
"""
# gdb does not expose process name, neither does (standard) python
# You can use for example psutil, but it might not be present.
# Default to name of thread with ID 1
inf = gdb.selected_inferior()
if psutil is None:
try:
if inf is None:
return '<unknown process name>'
threads = filter(lambda t: t.num == 1, list(inf.threads()))
if len(threads) < 1:
return '<unknown process name>'
thread = threads[0]
# use thread name
return thread.name
except Exception as e:
return str(e)
else:
return psutil.Process(inf.pid).name()
def _getTick(self):
"""
Capture function for Tick
"""
if self._hasMonotonicTime:
return str(int(time.monotonic() * 1000))
else:
return '<monotonic time not available>'
def _getTid(self):
"""
Capture function for Tid
"""
try:
thread = gdb.selected_thread()
if not (thread is None):
(pid, lwpid, tid) = thread.ptid
if tid == 0:
return str(lwpid)
else:
return str(tid)
except Exception as e:
return str(e)
return '<unknown tid>'
def _getThreadName(self):
"""
Capture function for ThreadName
"""
try:
thread = gdb.selected_thread()
if not (thread is None):
return str(thread.name)
except Exception as e:
return str(e)
return '<unknown thread name>'
def _getExpression(self, expression):
"""
Capture function for Expression
:param expr: The expression to evaluate
"""
try:
value = gdb.parse_and_eval(expression)
if value:
return self.onExpression(self, expression, value)
except Exception as e:
return self.onExpression(self, expression, e)
capsMap = {Address: _getAddress,
Caller: _getCaller,
Callstack: _getCallstack,
FilePos: _getFilePos,
Function: _getFunction,
Pid: _getPid,
ProcessName: _getProcessName,
Tid: _getTid,
Tick: _getTick,
ThreadName: _getThreadName,
Expression: _getExpression}

View File

@@ -0,0 +1,527 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
from stdtypes import qdump__std__array, qdump__std__complex, qdump__std__once_flag, qdump__std__unique_ptr, qdumpHelper__std__deque__libcxx, qdumpHelper__std__vector__libcxx
from utils import DisplayFormat
from dumper import Children, DumperBase
def qform__std____1__array():
return [DisplayFormat.ArrayPlot]
def qdump__std____1__array(d, value):
qdump__std__array(d, value)
def qdump__std____1__complex(d, value):
qdump__std__complex(d, value)
def qdump__std____1__deque(d, value):
qdumpHelper__std__deque__libcxx(d, value)
def qdump__std____1__list(d, value):
if value.type.size() == 3 * d.ptrSize():
# C++11 only.
(dummy1, dummy2, size) = value.split("ppp")
d.putItemCount(size)
else:
# Need to count manually.
p = d.extractPointer(value)
head = value.address()
size = 0
while head != p and size < 1001:
size += 1
p = d.extractPointer(p)
d.putItemCount(size, 1000)
if d.isExpanded():
(prev, p) = value.split("pp")
innerType = value.type[0]
typeCode = "pp{%s}" % innerType.name
with Children(d, size, maxNumChild=1000, childType=innerType):
for i in d.childRange():
(prev, p, val) = d.split(typeCode, p)
d.putSubItem(i, val)
def qdump__std____1__set(d, value):
(proxy, head, size) = value.split("ppp")
d.check(0 <= size and size <= 100 * 1000 * 1000)
d.putItemCount(size)
if d.isExpanded():
valueType = value.type[0]
def in_order_traversal(node):
(left, right, parent, color, pad, data) = d.split("pppB@{%s}" % (valueType.name), node)
if left:
for res in in_order_traversal(left):
yield res
yield data
if right:
for res in in_order_traversal(right):
yield res
with Children(d, size, maxNumChild=1000):
for (i, data) in zip(d.childRange(), in_order_traversal(head)):
d.putSubItem(i, data)
def qdump__std____1__multiset(d, value):
qdump__std____1__set(d, value)
def qform__std____1__map():
return [DisplayFormat.CompactMap]
def qdump__std____1__map(d, value):
try:
(proxy, head, size) = value.split("ppp")
d.check(0 <= size and size <= 100 * 1000 * 1000)
# Sometimes there is extra data at the front. Don't know why at the moment.
except RuntimeError:
(junk, proxy, head, size) = value.split("pppp")
d.check(0 <= size and size <= 100 * 1000 * 1000)
d.putItemCount(size)
if d.isExpanded():
keyType = value.type[0]
valueType = value.type[1]
pairType = value.type[3][0]
def in_order_traversal(node):
(left, right, parent, color, pad, pair) = d.split("pppB@{%s}" % (pairType.name), node)
if left:
for res in in_order_traversal(left):
yield res
yield pair.split("{%s}@{%s}" % (keyType.name, valueType.name))[::2]
if right:
for res in in_order_traversal(right):
yield res
with Children(d, size, maxNumChild=1000):
for (i, pair) in zip(d.childRange(), in_order_traversal(head)):
d.putPairItem(i, pair)
def qform__std____1__multimap():
return [DisplayFormat.CompactMap]
def qdump__std____1__multimap(d, value):
qdump__std____1__map(d, value)
def qdump__std____1__map__iterator(d, value):
d.putEmptyValue()
if d.isExpanded():
with Children(d):
node = value['__i_']['__ptr_'].dereference()['__value_']['__cc']
d.putSubItem('first', node['first'])
d.putSubItem('second', node['second'])
def qdump__std____1__map__const_iterator(d, value):
qdump__std____1__map__iterator(d, value)
def qdump__std____1__set__iterator(d, value):
d.putEmptyValue()
d.putExpandable()
if value.type.name.endswith("::iterator"):
treeTypeName = value.type.name[:-len("::iterator")]
elif value.type.name.endswith("::const_iterator"):
treeTypeName = value.type.name[:-len("::const_iterator")]
treeType = d.lookupType(treeTypeName)
keyType = treeType[0]
if d.isExpanded():
with Children(d):
node = value['__ptr_'].dereference()['__value_']
node = node.cast(keyType)
d.putSubItem('value', node)
def qdump__std____1__set_const_iterator(d, value):
qdump__std____1__set__iterator(d, value)
def qdump__std____1__stack(d, value):
d.putItem(value["c"])
d.putBetterType(value.type)
def GetChildMemberWithName(value, name):
members = value.members(True)
for member in members:
if member.name == name:
return member
return None
def GetIndexOfChildWithName(value, name):
members = value.members(True)
for i, member in enumerate(members):
if member.name == name:
return i
return None
class StringLayout:
CSD = 0
DSC = 1
def std_1_string_dumper_v2(d, value):
charType = value['__l']['__data_'].dereference().type
R = GetChildMemberWithName(value, "__r_")
if not R:
raise Exception("Could not find __r_")
# __r_ is a compressed_pair of the actual data and the allocator. The data we
# want is in the first base class.
R_Base_SP = R[0]
if not R_Base_SP:
raise Exception("Could not find R_Base_SP")
Rep_Sp = GetChildMemberWithName(R_Base_SP, "__value_")
if not Rep_Sp:
raise Exception("Could not find __value_")
# Our layout seems a little different
Rep_Sp = Rep_Sp[0]
if not Rep_Sp:
raise Exception("Could not find Rep_Sp")
L = GetChildMemberWithName(Rep_Sp, "__l")
if not L:
raise Exception("Could not find __l")
layout = StringLayout.CSD
if GetIndexOfChildWithName(L, "__data_") == 0:
layout = StringLayout.DSC
short_mode = False
using_bitmasks = True
size = 0
size_mode_value = 0
Short_Sp = GetChildMemberWithName(Rep_Sp, "__s")
if not Short_Sp:
raise Exception("Could not find __s")
Is_Long = GetChildMemberWithName(Short_Sp, "__is_long_")
Size_Sp = GetChildMemberWithName(Short_Sp, "__size_")
if not Size_Sp:
raise Exception("Could not find __size_")
if Is_Long:
using_bitmasks = False
short_mode = Is_Long.integer() == 0
size = Size_Sp.integer()
else:
size_mode_value = Size_Sp.integer()
mode_mask = 1
if layout == StringLayout.DSC:
mode_mask = 0x80
short_mode = (size_mode_value & mode_mask) == 0
if short_mode:
Location_Sp = GetChildMemberWithName(Short_Sp, "__data_")
if using_bitmasks:
size = ((size_mode_value >> 1) % 256)
if layout == StringLayout.DSC:
size = size_mode_value
# The string is most likely not initialized yet
if size > 100 or not Location_Sp:
raise Exception("Probably not initialized yet")
d.putCharArrayHelper(d.extractPointer(Location_Sp), size,
charType, d.currentItemFormat())
return
Location_Sp = GetChildMemberWithName(L, "__data_")
Size_Vo = GetChildMemberWithName(L, "__size_")
Capacity_Vo = GetChildMemberWithName(L, "__cap_")
if not Location_Sp or not Size_Vo or not Capacity_Vo:
raise Exception("Could not find Location_Sp, Size_Vo or Capacity_Vo")
size = Size_Vo.integer()
capacity = Capacity_Vo.integer()
if not using_bitmasks and layout == StringLayout.CSD:
capacity *= 2
if capacity < size:
raise Exception("Capacity is less than size")
d.putCharArrayHelper(d.extractPointer(Location_Sp), size,
charType, d.currentItemFormat())
def std_1_string_dumper_v1(d, value):
charType = value['__l']['__data_'].dereference().type
D = None
if d.isLldb:
D = value[0][0][0][0]
elif d.isGdb:
D = value["__r_"].members(True)[0][0][0]
else:
raise Exception("Unknown debugger (neither gdb nor lldb)")
layoutDecider = D[0][0]
if not layoutDecider:
raise Exception("Could not find layoutDecider")
size = 0
size_mode_value = 0
short_mode = False
libcxx_version = 14
layoutModeIsDSC = layoutDecider.name == '__data_'
if (layoutModeIsDSC):
size_mode = D[1][1][0]
if not size_mode:
raise Exception("Could not find size_mode")
if not size_mode.name == '__size_':
size_mode = D[1][1][1]
if not size_mode:
raise Exception("Could not find size_mode")
size_mode_value = size_mode.integer()
short_mode = ((size_mode_value & 0x80) == 0)
else:
size_mode = D[1][0][0]
if not size_mode:
raise Exception("Could not find size_mode")
if size_mode.name == '__is_long_':
libcxx_version = 15
short_mode = (size_mode.integer() == 0)
size_mode = D[1][0][1]
size_mode_value = size_mode.integer()
else:
size_mode_value = size_mode.integer()
short_mode = ((size_mode_value & 1) == 0)
if short_mode:
s = D[1]
if not s:
raise Exception("Could not find s")
if libcxx_version == 14:
location_sp = s[0] if layoutModeIsDSC else s[1]
size = size_mode_value if layoutModeIsDSC else ((size_mode_value >> 1) % 256)
elif libcxx_version == 15:
location_sp = s[0] if layoutModeIsDSC else s[2]
size = size_mode_value
else:
l = D[0]
if not l:
raise Exception("Could not find l")
# we can use the layout_decider object as the data pointer
location_sp = layoutDecider if layoutModeIsDSC else l[2]
size_vo = l[1]
if not size_vo or not location_sp:
raise Exception("Could not find size_vo or location_sp")
size = size_vo.integer()
if short_mode and location_sp:
d.putCharArrayHelper(d.extractPointer(location_sp), size,
charType, d.currentItemFormat())
else:
d.putCharArrayHelper(location_sp.integer(),
size, charType, d.currentItemFormat())
return
def qdump__std____1__string(d, value):
try:
std_1_string_dumper_v2(d, value)
except Exception as eV2:
try:
std_1_string_dumper_v1(d, value)
except Exception as eV1:
d.putValue("Could not parse: %s, %s" % (eV1, eV2))
def qdump__std____1__wstring(d, value):
try:
std_1_string_dumper_v2(d, value)
except Exception as eV2:
try:
std_1_string_dumper_v1(d, value)
except Exception as eV1:
d.putValue("Could not parse: %s, %s" % (eV1, eV2))
def qdump__std____1__basic_string(d, value):
innerType = value.type[0].name
if innerType in ("char", "char8_t", "char16_t"):
qdump__std____1__string(d, value)
elif innerType in ("wchar_t", "char32_t"):
qdump__std____1__wstring(d, value)
else:
d.warn("UNKNOWN INNER TYPE %s" % innerType)
def qdump__std____1__shared_ptr(d, value):
i = value["__ptr_"]
if i.pointer() == 0:
d.putValue("(null)")
else:
d.putItem(i.dereference())
d.putBetterType(value.type)
def qdump__std____1__weak_ptr(d, value):
return qdump__std____1__shared_ptr(d, value)
def qdump__std____1__unique_ptr(d, value):
if value.type.size() == d.ptrSize():
p = d.extractPointer(value)
else:
_, p = value.split("pp"); # For custom deleters.
if p == 0:
d.putValue("(null)")
else:
try:
d.putItem(value["__value_"])
d.putValue(d.currentValue.value, d.currentValue.encoding)
except:
d.putItem(d.createValue(p, value.type[0]))
d.putBetterType(value.type)
def qform__std____1__unordered_map():
return [DisplayFormat.CompactMap]
def qdump__std____1__unordered_map(d, value):
(size, _) = value["__table_"]["__p2_"].split("pp")
d.putItemCount(size)
keyType = value.type[0]
valueType = value.type[1]
pairType = value.type[4][0]
if d.isExpanded():
curr = value["__table_"]["__p1_"].split("pp")[0]
def traverse_list(node):
while node:
(next_, _, pad, pair) = d.split("pp@{%s}" % (pairType.name), node)
yield pair.split("{%s}@{%s}" % (keyType.name, valueType.name))[::2]
node = next_
with Children(d, size, childType=value.type[0], maxNumChild=1000):
for (i, value) in zip(d.childRange(), traverse_list(curr)):
d.putPairItem(i, value, 'key', 'value')
def qdump__std____1__unordered_set(d, value):
(size, _) = value["__table_"]["__p2_"].split("pp")
d.putItemCount(size)
valueType = value.type[0]
if d.isExpanded():
curr = value["__table_"]["__p1_"].split("pp")[0]
def traverse_list(node):
while node:
(next_, _, pad, val) = d.split("pp@{%s}" % (valueType.name), node)
yield val
node = next_
with Children(d, size, childType=value.type[0], maxNumChild=1000):
for (i, value) in zip(d.childRange(), traverse_list(curr)):
d.putSubItem(i, value)
def qdump__std____1__unordered_multiset(d, value):
qdump__std____1__unordered_set(d, value)
def qform__std____1__valarray():
return [DisplayFormat.ArrayPlot]
def qdump__std____1__valarray(d, value):
innerType = value.type[0]
(begin, end) = value.split('pp')
size = int((end - begin) / innerType.size())
d.putItemCount(size)
d.putPlotData(begin, size, innerType)
def qform__std____1__vector():
return [DisplayFormat.ArrayPlot]
def qdump__std____1__vector(d, value):
qdumpHelper__std__vector__libcxx(d, value)
def qdump__std____1__once_flag(d, value):
qdump__std__once_flag(d, value)
def qdump__std____1__variant(d, value):
index = value['__impl']['__index']
index_num = int(index)
value_type = d.templateArgument(value.type, index_num)
d.putValue("<%s:%s>" % (index_num, value_type.name))
d.putNumChild(2)
if d.isExpanded():
with Children(d):
d.putSubItem("index", index)
d.putSubItem("value", value.cast(value_type))
def qdump__std____1__optional(d, value):
if value['__engaged_'].integer() == 0:
d.putSpecialValue("empty")
else:
d.putItem(value['#1']['__val_'])
def qdump__std____1__tuple(d, value):
values = []
for member in value['__base_'].members(False):
values.append(member['__value_'])
d.putItemCount(len(values))
d.putNumChild(len(values))
if d.isExpanded():
with Children(d):
count = 0
for internal_value in values:
d.putSubItem("[%i]" % count, internal_value)
count += 1

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,588 @@
# Copyright (C) 2016 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
from dumper import Children, SubItem
from utils import TypeCode, DisplayFormat
import re
#######################################################################
#
# SSE
#
#######################################################################
def qdump____m128(d, value):
d.putEmptyValue()
d.putExpandable()
if d.isExpanded():
d.putArrayData(value.address(), 4, d.lookupType('float'))
def qdump____m256(d, value):
d.putEmptyValue()
d.putExpandable()
if d.isExpanded():
d.putArrayData(value.address(), 8, d.lookupType('float'))
def qdump____m512(d, value):
d.putEmptyValue()
d.putExpandable()
if d.isExpanded():
d.putArrayData(value.address(), 16, d.lookupType('float'))
def qdump____m128d(d, value):
d.putEmptyValue()
d.putExpandable()
if d.isExpanded():
d.putArrayData(value.address(), 2, d.lookupType('double'))
def qdump____m256d(d, value):
d.putEmptyValue()
d.putExpandable()
if d.isExpanded():
d.putArrayData(value.address(), 4, d.lookupType('double'))
def qdump____m512d(d, value):
d.putEmptyValue()
d.putExpandable()
if d.isExpanded():
d.putArrayData(value.address(), 8, d.lookupType('double'))
def qdump____m128i(d, value):
data = d.hexencode(value.data(16))
d.putValue(':'.join('%04x' % int(data[i:i + 4], 16) for i in range(0, 32, 4)))
d.putExpandable()
if d.isExpanded():
with Children(d):
addr = value.address()
d.putArrayItem('uint8x16', addr, 16, 'unsigned char')
d.putArrayItem('uint16x8', addr, 8, 'unsigned short')
d.putArrayItem('uint32x4', addr, 4, 'unsigned int')
d.putArrayItem('uint64x2', addr, 2, 'unsigned long long')
def qdump____m256i(d, value):
data = d.hexencode(value.data(32))
d.putValue(':'.join('%04x' % int(data[i:i + 4], 16) for i in range(0, 64, 4)))
d.putExpandable()
if d.isExpanded():
with Children(d):
addr = value.address()
d.putArrayItem('uint8x32', addr, 32, 'unsigned char')
d.putArrayItem('uint16x16', addr, 16, 'unsigned short')
d.putArrayItem('uint32x8', addr, 8, 'unsigned int')
d.putArrayItem('uint64x4', addr, 4, 'unsigned long long')
def qdump____m512i(d, value):
data = d.hexencode(value.data(64))
d.putValue(':'.join('%04x' % int(data[i:i + 4], 16) for i in range(0, 64, 4))
+ ', ' + ':'.join('%04x' % int(data[i:i + 4], 16) for i in range(64, 128, 4)))
d.putExpandable()
if d.isExpanded():
with Children(d):
d.putArrayItem('uint32x16', value.address(), 16, 'unsigned int')
d.putArrayItem('uint64x8', value.address(), 8, 'unsigned long long')
#######################################################################
#
# GSL
#
#######################################################################
def qform__std__array():
return [DisplayFormat.ArrayPlot]
def qdump__gsl__span(d, value):
size, pointer = value.split('pp')
d.putItemCount(size)
if d.isExpanded():
d.putPlotData(pointer, size, value.type[0])
def qdump__gsl__byte(d, value):
d.putValue(value.integer())
#######################################################################
#
# Eigen
#
#######################################################################
#def qform__Eigen__Matrix():
# return 'Transposed'
def qdump__Eigen__Matrix(d, value):
innerType = value.type[0]
argRow = value.type[1]
argCol = value.type[2]
options = value.type[3]
rowMajor = (int(options) & 0x1)
# The magic dimension value is -1 in Eigen3, but 10000 in Eigen2.
# 10000 x 10000 matrices are rare, vectors of dim 10000 less so.
# So 'fix' only the matrix case:
if argCol == 10000 and argRow == 10000:
argCol = -1
argRow = -1
if argCol != -1 and argRow != -1:
nrows = argRow
ncols = argCol
p = value.address()
else:
storage = value['m_storage']
nrows = storage['m_rows'].integer() if argRow == -1 else argRow
ncols = storage['m_cols'].integer() if argCol == -1 else argCol
p = storage['m_data'].pointer()
innerSize = innerType.size()
d.putValue('(%s x %s), %s' % (nrows, ncols, ['ColumnMajor', 'RowMajor'][rowMajor]))
d.putField('keeporder', '1')
d.putNumChild(nrows * ncols)
limit = 10000
nncols = min(ncols, limit)
nnrows = min(nrows, limit * limit / nncols)
if d.isExpanded():
#format = d.currentItemFormat() # format == 1 is 'Transposed'
with Children(d, nrows * ncols, childType=innerType):
if ncols == 1 or nrows == 1:
for i in range(0, min(nrows * ncols, 10000)):
d.putSubItem(i, d.createValue(p + i * innerSize, innerType))
elif rowMajor == 1:
s = 0
for i in range(0, nnrows):
for j in range(0, nncols):
v = d.createValue(p + (i * ncols + j) * innerSize, innerType)
d.putNamedSubItem(s, v, '[%d,%d]' % (i, j))
s = s + 1
else:
s = 0
for j in range(0, nncols):
for i in range(0, nnrows):
v = d.createValue(p + (i + j * nrows) * innerSize, innerType)
d.putNamedSubItem(s, v, '[%d,%d]' % (i, j))
s = s + 1
#######################################################################
#
# Nim
#
#######################################################################
def qdump__NimStringDesc(d, value):
size, reserved = value.split('pp')
data = value.address() + 2 * d.ptrSize()
d.putBetterType('string')
d.putCharArrayHelper(data, size, d.createType('char'), 'utf8')
def qdump__NimGenericSequence__(d, value, regex=r'^TY[\d]+$'):
code = value.type.stripTypedefs().code
if code == TypeCode.Struct:
size, reserved = d.split('pp', value)
data = value.address() + 2 * d.ptrSize()
typeobj = value['data'].type.dereference()
d.putItemCount(size)
d.putArrayData(data, size, typeobj)
d.putBetterType('%s (%s[%s])' % (value.type.name, typeobj.name, size))
else:
d.putEmptyValue()
d.putPlainChildren(value)
def qdump__TNimNode(d, value):
name = value['name'].pointer()
d.putSimpleCharArray(name) if name != 0 else d.putEmptyValue()
if d.isExpanded():
with Children(d):
sons = value['sons'].pointer()
size = value['len'].integer()
for i in range(size):
val = d.createValue(d.extractPointer(sons + i * d.ptrSize()), value.type)
with SubItem(d, '[%d]' % i):
d.putItem(val)
with SubItem(d, '[raw]'):
d.putPlainChildren(value)
#######################################################################
#
# D
#
#######################################################################
def cleanDType(type):
return str(type).replace('uns long long', 'string')
def qdump_Array(d, value):
n = value['length']
p = value['ptr']
t = cleanDType(value.type)[7:]
d.putType('%s[%d]' % (t, n))
if t == 'char':
d.putValue(encodeCharArray(p, 100), 'local8bit')
else:
d.putEmptyValue()
d.putNumChild(n)
innerType = p.type
if d.isExpanded():
with Children(d, n, childType=innerType):
for i in range(0, n):
d.putSubItem(i, p.dereference())
p = p + 1
def qdump_AArray(d, value):
#n = value['length']
# This ends up as _AArray_<key>_<value> with a single .ptr
# member of type void *. Not much that can be done here.
p = value['ptr']
t = cleanDType(value.type)[8:]
d.putType('%s]' % t.replace('_', '['))
d.putEmptyValue()
if d.isExpanded():
with Children(d, 1):
d.putSubItem('ptr', p)
#######################################################################
#
# MPI
#
#######################################################################
if False:
def qdump__tree_entry(d, value):
d.putValue('len: %s, offset: %s, type: %s' %
(value['blocklength'], value['offset'], value['type']))
def qdump__tree(d, value):
count = value['count']
entries = value['entries']
base = value['base'].pointer()
d.putItemCount(count)
if d.isExpanded():
with Children(d):
with SubItem(d, 'tree'):
d.putEmptyValue()
d.putNoType()
if d.isExpanded():
with Children(d):
for i in range(count):
d.putSubItem(Item(entries[i], iname))
with SubItem(d, 'data'):
d.putEmptyValue()
d.putNoType()
if d.isExpanded():
with Children(d):
for i in range(count):
with SubItem(d, i):
entry = entries[i]
mpitype = str(entry['type'])
d.putType(mpitype)
length = int(entry['blocklength'])
offset = int(entry['offset'])
d.putValue('%s items at %s' % (length, offset))
if mpitype == 'MPI_INT':
innerType = 'int'
elif mpitype == 'MPI_CHAR':
innerType = 'char'
elif mpitype == 'MPI_DOUBLE':
innerType = 'double'
else:
length = 0
d.putNumChild(length)
if d.isExpanded():
with Children(d):
t = d.lookupType(innerType).pointer()
p = (base + offset).cast(t)
for j in range(length):
d.putSubItem(j, p.dereference())
#######################################################################
#
# KDSoap
#
#######################################################################
def qdump__KDSoapValue1(d, value):
inner = value['d']['d'].dereference()
d.putStringValue(inner['m_name'])
d.putPlainChildren(inner)
def qdump__KDSoapValue(d, value):
p = (value.cast(d.lookupType('char*')) + 4).dereference().cast(d.lookupType('QString'))
d.putStringValue(p)
d.putPlainChildren(value['d']['d'].dereference())
#######################################################################
#
# Webkit
#
#######################################################################
def qdump__WTF__String(d, value):
# WTF::String -> WTF::RefPtr<WTF::StringImpl> -> WTF::StringImpl*
data = value['m_impl']['m_ptr']
d.checkPointer(data)
stringLength = int(data['m_length'])
d.check(0 <= stringLength and stringLength <= 100000000)
# WTF::StringImpl* -> WTF::StringImpl -> sizeof(WTF::StringImpl)
offsetToData = data.type.target().size()
bufferPtr = data.pointer() + offsetToData
is8Bit = data['m_is8Bit']
charSize = 1
if not is8Bit:
charSize = 2
d.putCharArrayHelper(bufferPtr, stringLength, charSize)
#######################################################################
#
# Python
#
#######################################################################
def get_python_interpreter_major_version(d):
key = 'python_interpreter_major_version'
if key in d.generalCache:
return d.generalCache[key]
e = "(char*)Py_GetVersion()"
result = d.nativeParseAndEvaluate(e)
result_str = str(result)
matches = re.search(r'(\d+?)\.(\d+?)\.(\d+?)', result_str)
if matches:
result_str = matches.group(1)
d.generalCache[key] = result_str
return result_str
def is_python_3(d):
return get_python_interpreter_major_version(d) == '3'
def repr_cache_decorator(namespace):
def real_decorator(func_to_decorate):
def wrapper(d, address):
if namespace in d.perStepCache and address in d.perStepCache[namespace]:
return d.perStepCache[namespace][address]
if namespace not in d.perStepCache:
d.perStepCache[namespace] = {}
if address == 0:
result_str = d.perStepCache[namespace][address] = "<nullptr>"
return result_str
result = func_to_decorate(d, address)
d.perStepCache[namespace][address] = result
return result
return wrapper
return real_decorator
@repr_cache_decorator('py_object')
def get_py_object_repr_helper(d, address):
# The code below is a long way to evaluate:
# ((PyBytesObject *)PyUnicode_AsEncodedString(PyObject_Repr(
# (PyObject*){}), \"utf-8\", \"backslashreplace\"))->ob_sval"
# But with proper object cleanup.
e_decref = "Py_DecRef((PyObject *){})"
e = "PyObject_Repr((PyObject*){})"
repr_object_value = d.parseAndEvaluate(e.format(address))
repr_object_address = d.fromPointerData(repr_object_value.ldata)[0]
if is_python_3(d):
# Try to get a UTF-8 encoded string from the repr object.
e = "PyUnicode_AsEncodedString((PyObject*){}, \"utf-8\", \"backslashreplace\")"
string_object_value = d.parseAndEvaluate(e.format(repr_object_address))
string_object_address = d.fromPointerData(string_object_value.ldata)[0]
e = "(char*)(((PyBytesObject *){})->ob_sval)"
result = d.nativeParseAndEvaluate(e.format(string_object_address))
# It's important to stringify the result before any other evaluations happen.
result_str = str(result)
# Clean up.
d.nativeParseAndEvaluate(e_decref.format(string_object_address))
else:
# Retrieve non-unicode string.
e = "(char*)(PyString_AsString((PyObject*){}))"
result = d.nativeParseAndEvaluate(e.format(repr_object_address))
# It's important to stringify the result before any other evaluations happen.
result_str = str(result)
# Do some string stripping.
# FIXME when using cdb engine.
matches = re.search(r'.+?"(.+)"$', result_str)
if matches:
result_str = matches.group(1)
# Clean up.
d.nativeParseAndEvaluate(e_decref.format(repr_object_address))
return result_str
@repr_cache_decorator('py_object_type')
def get_py_object_type(d, object_address):
e = "((PyObject *){})->ob_type"
type_value = d.parseAndEvaluate(e.format(object_address))
type_address = d.fromPointerData(type_value.ldata)[0]
type_repr = get_py_object_repr_helper(d, type_address)
return type_repr
@repr_cache_decorator('py_object_meta_type')
def get_py_object_meta_type(d, object_address):
# The python3 object layout has a few more indirections.
if is_python_3(d):
e = "((PyObject *){})->ob_type->ob_base->ob_base->ob_type"
else:
e = "((PyObject *){})->ob_type->ob_type"
type_value = d.parseAndEvaluate(e.format(object_address))
type_address = d.fromPointerData(type_value.ldata)[0]
type_repr = get_py_object_repr_helper(d, type_address)
return type_repr
@repr_cache_decorator('py_object_base_class')
def get_py_object_base_class(d, object_address):
e = "((PyObject *){})->ob_type->tp_base"
base_value = d.parseAndEvaluate(e.format(object_address))
base_address = d.fromPointerData(base_value.ldata)[0]
base_repr = get_py_object_repr_helper(d, base_address)
return base_repr
def get_py_object_repr(d, value):
address = value.address()
repr_available = False
try:
result = get_py_object_repr_helper(d, address)
d.putValue(d.hexencode(result), encoding='utf8')
repr_available = True
except:
d.putEmptyValue()
def sub_item(name, functor, address):
with SubItem(d, '[{}]'.format(name)):
sub_value = functor(d, address)
d.putValue(d.hexencode(sub_value), encoding='utf8')
d.putExpandable()
if d.isExpanded():
with Children(d):
if repr_available:
sub_item('class', get_py_object_type, address)
sub_item('super class', get_py_object_base_class, address)
sub_item('meta type', get_py_object_meta_type, address)
d.putFields(value)
def qdump__PyTypeObject(d, value):
get_py_object_repr(d, value)
def qdump___typeobject(d, value):
get_py_object_repr(d, value)
def qdump__PyObject(d, value):
get_py_object_repr(d, value)
def qdump__PyVarObject(d, value):
get_py_object_repr(d, value)
#######################################################################
#
# Internal test
#
#######################################################################
def qdump__QtcDumperTest_FieldAccessByIndex(d, value):
d.putValue(value["d"][2].integer())
def qdump__QtcDumperTest_PointerArray(d, value):
foos = value["foos"]
d.putItemCount(10)
if d.isExpanded():
with Children(d, 10):
for i in d.childRange():
d.putSubItem(i, foos[i])
def qdump__QtcDumperTest_BufArray(d, value):
maxItems = 1000
buffer = value['buffer']
count = int(value['count'])
objsize = int(value['objSize'])
valueType = value.type.templateArgument(0)
d.putItemCount(count, maxItems)
d.putNumChild(count)
if d.isExpanded():
with Children(d, count, maxNumChild=maxItems, childType=valueType):
for i in d.childRange():
d.putSubItem(i, (buffer + (i * objsize)).dereference().cast(valueType))
def qdump__QtcDumperTest_List__NodeX(d, value):
typename = value.type.unqualified().name
pos0 = typename.find('<')
pos1 = typename.find('>')
tName = typename[pos0 + 1:pos1]
d.putBetterType('QtcDumperTest_List<' + tName + '>::Node')
d.putExpandable()
if d.isExpanded():
obj_type = d.lookupType(tName)
with Children(d):
d.putSubItem("this", value.cast(obj_type))
d.putFields(value)
#d.putPlainChildren(value)
def qdump__QtcDumperTest_List(d, value):
innerType = value.type[0]
d.putExpandable()
p = value['root']
if d.isExpanded():
with Children(d):
d.putSubItem("[p]", p)
d.putSubItem("[root]", value["root"].cast(innerType))
d.putFields(value)
#d.putPlainChildren(value)
def qdump__QtcDumperTest_String(d, value):
with Children(d):
first = d.hexdecode(d.putSubItem('first', value['first']).value)
second = d.hexdecode(d.putSubItem('second', value['second']).value)
third = d.hexdecode(d.putSubItem('third', value['third']).value)[:-1]
d.putValue(first + ', ' + second + ', ' + third)

View File

@@ -0,0 +1,44 @@
# Copyright (C) 2016 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
from dumper import Children, SubItem
from utils import TypeCode, DisplayFormat
def qdump__cv__Size_(d, value):
d.putValue('(%s, %s)' % (value[0].display(), value[1].display()))
d.putPlainChildren(value)
def qform__cv__Mat():
return [DisplayFormat.Separate]
def qdump__cv__Mat(d, value):
(flag, dims, rows, cols, data, refcount, datastart, dataend,
datalimit, allocator, size, stepp) \
= value.split('iiiipppppppp')
steps = d.split('p' * dims, stepp)
innerSize = 0 if dims == 0 else steps[dims - 1]
if dims != 2:
d.putEmptyValue()
d.putPlainChildren(value)
return
if d.currentItemFormat() == DisplayFormat.Separate:
rs = steps[0] * innerSize
cs = cols * innerSize
dform = 'arraydata:separate:int:%d::2:%d:%d' % (innerSize, cols, rows)
out = ''.join(d.readMemory(data + i * rs, cs) for i in range(rows))
d.putDisplay(dform, out)
d.putValue('(%s x %s)' % (rows, cols))
if d.isExpanded():
with Children(d):
innerType = d.createType(TypeCode.Integral, innerSize)
for i in range(rows):
for j in range(cols):
with SubItem(d, None):
d.putName('[%d,%d]' % (i, j))
addr = data + (i * steps[0] + j) * innerSize
d.putItem(d.createValue(addr, innerType))

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,40 @@
# Copyright (C) 2016 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
# This is a place to add your own dumpers for testing purposes.
# Any contents here will be picked up by GDB, LLDB, and CDB based
# debugging in Qt Creator automatically.
# NOTE: This file will get overwritten when updating Qt Creator.
#
# To add dumpers that don't get overwritten, copy this file here
# to a safe location outside the Qt Creator installation and
# make this location known to Qt Creator using the Debugger >
# Locals & Expressions > Extra Debugging Helpers setting.
# Example to display a simple type
# template<typename U, typename V> struct MapNode
# {
# U key;
# V data;
# }
#
# def qdump__MapNode(d, value):
# d.putValue("This is the value column contents")
# d.putExpandable()
# if d.isExpanded():
# with Children(d):
# # Compact simple case.
# d.putSubItem("key", value["key"])
# # Same effect, with more customization possibilities.
# with SubItem(d, "data")
# d.putItem("data", value["data"])
# Check http://doc.qt.io/qtcreator/creator-debugging-helpers.html
# for more details or look at qttypes.py, stdtypes.py, boosttypes.py
# for more complex examples.
from dumper import Children, SubItem, UnnamedSubItem, DumperBase
from utils import DisplayFormat, TypeCode
######################## Your code below #######################

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,129 @@
# Copyright (C) 2016 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
# Debugger start modes. Keep in sync with DebuggerStartMode in debuggerconstants.h
# MT: Why does this not match (anymore?) to debuggerconstants.h : DebuggerStartMode ?
class DebuggerStartMode():
(
NoStartMode,
StartInternal,
StartExternal,
AttachExternal,
AttachCrashedExternal,
AttachCore,
AttachToRemoteServer,
AttachToRemoteProcess,
StartRemoteProcess,
) = range(0, 9)
# Known special formats. Keep in sync with DisplayFormat in debuggerprotocol.h
class DisplayFormat():
(
Automatic,
Raw,
Simple,
Enhanced,
Separate,
Latin1String,
SeparateLatin1String,
Utf8String,
SeparateUtf8String,
Local8BitString,
Utf16String,
Ucs4String,
Array10,
Array100,
Array1000,
Array10000,
ArrayPlot,
CompactMap,
DirectQListStorage,
IndirectQListStorage,
) = range(0, 20)
# Breakpoints. Keep synchronized with BreakpointType in breakpoint.h
class BreakpointType():
(
UnknownType,
BreakpointByFileAndLine,
BreakpointByFunction,
BreakpointByAddress,
BreakpointAtThrow,
BreakpointAtCatch,
BreakpointAtMain,
BreakpointAtFork,
BreakpointAtExec,
BreakpointAtSysCall,
WatchpointAtAddress,
WatchpointAtExpression,
BreakpointOnQmlSignalEmit,
BreakpointAtJavaScriptThrow,
) = range(0, 14)
# Internal codes for types. Keep in sync with cdbextensions pytype.cpp
class TypeCode():
(
Typedef,
Struct,
Void,
Integral,
Float,
Enum,
Pointer,
Array,
Complex,
Reference,
Function,
MemberPointer,
FortranString,
Unresolvable,
Bitfield,
RValueReference,
) = range(0, 16)
# Internal codes for logging channels. Keep in sync woth debuggerconstants.h
class LogChannel():
(
LogInput, # Used for user input
LogMiscInput, # Used for misc stuff in the input pane
LogOutput,
LogWarning,
LogError,
LogStatus, # Used for status changed messages
LogTime, # Used for time stamp messages
LogDebug,
LogMisc,
AppOutput, # stdout
AppError, # stderr
AppStuff, # (possibly) windows debug channel
StatusBar, # LogStatus and also put to the status bar
ConsoleOutput # Used to output to console
) = range(0, 14)
def isIntegralTypeName(name):
return name in (
"int",
"unsigned int",
"signed int",
"short",
"unsigned short",
"long",
"unsigned long",
"long long",
"unsigned long long",
"char",
"signed char",
"unsigned char",
"bool",
)
def isFloatingPointTypeName(name):
return name in ("float", "double", "long double")