Adds rpm specs to migration repo

This commit is contained in:
torsten committed 2026-07-18 17:22:25 +02:00
1 parent acee7b8766
commit 7f035543e2
145 files changed
+13982

No files matched your search

+45
View File
@@ -0,0 +1,45 @@
# Loads pretty printers for Qt5.
#
# Source this from gdb, like:
# source /path/to/kde-dev-scripts/gdb/load-qt5printers.py
#
# Note that, unless you work exclusively with Qt5-based software, you
# probably do not want to load this in your .gdbinit, as if you debug
# a Qt4-based piece of software, the pretty printers will just break.
#
# See the create-qt5-autoloaders.py script for an alternative loading
# mechanism.
#
# Copyright 2014 Alex Merry <alex.merry@kde.org>
#
# Permission to use, copy, modify, and distribute this software
# and its documentation for any purpose and without fee is hereby
# granted, provided that the above copyright notice appear in all
# copies and that both that the copyright notice and this
# permission notice and warranty disclaimer appear in supporting
# documentation, and that the name of the author not be used in
# advertising or publicity pertaining to distribution of the
# software without specific, written prior permission.
#
# The author disclaims all warranties with regard to this
# software, including all implied warranties of merchantability
# and fitness. In no event shall the author be liable for any
# special, indirect or consequential damages or any damages
# whatsoever resulting from loss of use, data or profits, whether
# in an action of contract, negligence or other tortious action,
# arising out of or in connection with the use or performance of
# this software.
import sys
import os.path
moddir = os.path.dirname(__file__)
if not moddir in sys.path:
sys.path.insert(0, moddir)
import qt5printers
qt5printers.register_printers(gdb.current_objfile())
+9
View File
@@ -0,0 +1,9 @@
import sys
import os.path
moddir = os.path.dirname(__file__)
if not moddir in sys.path:
sys.path.insert(0, moddir)
import lts_printers
lts_printers.registerPrettyPrinters()
+3
View File
@@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from .gdb_helper import registerPrettyPrinters
+242
View File
@@ -0,0 +1,242 @@
# -*- coding: utf-8 -*-
"""
Pretty Printer for use with pain gdb.
To activate, put this section into your ~/.gdbinit:
@code
set python print-stack full
python
import sys
sys.path.insert(0, '/shd/CTC/TOOLS/TDS/TDS-source/Lts/Tools/DebuggingHelpers/')
import gdb_helper
gdb_helper.registerPrettyPrinters()
end
@endcode
@author Christian Fröbel
"""
import gdb
import gdb.printing
import gdb.types
from datetime import datetime
import sys
if sys.version_info[0] >= 3:
long = int
class DdsStringPrinter(object):
def __init__(self, val):
self._val = val
def to_string(self):
return '"{}"'.format(self._val['str_'].string())
class DdsVectorPrinter(object):
def __init__(self, val):
self._val = val
def to_string(self):
capacity = self._val['seq_']['_maximum']
size = self._val['seq_']['_length']
formatted = 'dds::core::vector of length {}, capacity {} = {{'.format(capacity, size)
containedType = self._val.type.template_argument(0)
rawBuffer = self._val['seq_']['_contiguous_buffer'] # unsigned char*
typedBuffer = rawBuffer.cast(containedType.pointer())
for i in range(size):
if i > 0:
formatted += ', '
formatted += str(typedBuffer.dereference())
typedBuffer = typedBuffer+1
formatted += '}'
return formatted
class DdsOptionalPrinter(object):
"""Default implementation for dds::core::optional<T>"""
def __init__(self, value):
self._val = value
def to_string(self):
ptrToValue = self._val['value_']
isInitialized = _targetAddress(ptrToValue) != 0
if isInitialized:
return str(ptrToValue.dereference())
else:
return '{uninitialized}'
class DdsOptionalStringPrinter(object):
"""Specialization for dds::core::optional<dds::core::string>"""
def __init__(self, value):
self._val = value
def to_string(self):
strValue = self._val['value_']
isInitialized = _targetAddress(strValue['str_']) != 0
if isInitialized:
return str(strValue)
else:
return '{uninitialized}'
class StdChronoDurationPrinter(object):
def __init__(self, value):
self._val = value
def to_string(self):
seconds = _createSecondsFromDuration(self._val)
ms = long(seconds*1000)
formatted = 'std::chrono::duration, {}ms'.format(ms)
return formatted
def children(self):
return _namedChildren(self._val)
class StdChronoTimePointPrinter(object):
def __init__(self, value):
self._val = value
def to_string(self):
#
# Somehow registering a printer directly for AudioVideoManagement::AvaTimePoint does not work.
# As a workaround we simply query the type here.
#
if self._val.type.name == 'AudioVideoManagement::AvaTimePoint':
return AvaTimePointPrinter(self._val).to_string()
dt = _createDateTimeFromTimePoint(self._val)
formatted = 'std::chrono::time_point, {}'.format(_isoFormat(dt, nachkommaStellen=6))
return formatted
def children(self):
return _namedChildren(self._val)
class AvaTimePointPrinter(object):
def __init__(self, value):
self._val = value
def to_string(self):
dt = _createDateTimeFromTimePoint(self._val)
formatted = 'AudioVideoManagement::AvaTimePoint, {}'.format(_isoFormat(dt, nachkommaStellen=2))
return formatted
class AvsNtpTimestampPrinter(object):
"""Printer for AVS NTPTimestamp"""
def __init__(self, value):
self._val = value
def to_string(self):
dt = _createDateTimeFromNtpTimestamp(self._val)
formatted = _isoFormat(dt, nachkommaStellen=3)
return formatted
def children(self):
return _namedChildren(self._val)
class AvsNtpRangePrinter(object):
"""Printer for AVS NTPRange"""
def __init__(self, value):
self._val = value
def to_string(self):
dtBegin = _createDateTimeFromNtpTimestamp(self._val['m_begin'])
dtEnd = _createDateTimeFromNtpTimestamp(self._val['m_end'])
delta = dtEnd - dtBegin
seconds = delta.total_seconds() # float
fractionInMilli = long(seconds * 1000 + 0.5) % 1000
formatted = '{} - {}, {:d}.{:03d}s'.format(_isoFormat(dtBegin, nachkommaStellen=3), _isoFormat(dtEnd, nachkommaStellen=3), long(seconds), fractionInMilli)
return formatted
def children(self):
return _namedChildren(self._val)
def _createDateTimeFromTimePoint(value):
"""Create a datatime from a std::chrono::timepoint value"""
sSinceEpoch = _createSecondsFromDuration(value['__d'])
return datetime.utcfromtimestamp(sSinceEpoch)
def _createSecondsFromDuration(value):
"""Create seconds as float from a std::chrono::duration value"""
durationType = value.type
ratioType = durationType.template_argument(1)
dividend = long(ratioType.template_argument(0))
divisor = long(ratioType.template_argument(1))
duration = long(value['__r'])
seconds = duration * dividend / float(divisor)
return seconds
NTP_OFFSET = 2208988800 # in s; NTP starts at 1900-01-01 where unix epoch is 1970-01-01; difference is 70 years plus 17 leap years
def _createSecondsFromNtpTimestamp(value):
"""Create seconds as float from AVS NTPTimestamp. The format is a fixed 64 bit floating point number
where the upper 32 bit denote the seconds and the lower 32 bit denote the fraction of a second."""
fixedFloatValue = long(value['m_data'])
seconds = fixedFloatValue >> 32
fract = fixedFloatValue & 0xffffffff
return seconds + float(fract) / (1 << 32) - NTP_OFFSET
def _createDateTimeFromNtpTimestamp(value):
"""Create a datetime from AVS NTPTimestamp"""
sSinceEpoch = _createSecondsFromNtpTimestamp(value)
return datetime.utcfromtimestamp(sSinceEpoch)
def _isoFormat(dt, nachkommaStellen):
"""Return the ISO-representation for a given datetime instance with the requested number of Nachkommastellen"""
assert nachkommaStellen >= 0 and nachkommaStellen <= 6
s = dt.isoformat(' ')
if dt.microsecond > 0:
if nachkommaStellen == 6:
return s
return s[:-(6-nachkommaStellen)]
return s + '.' + nachkommaStellen * '0'
def _namedChildren(value):
"""Helper function; the result can directly be used in a Printer.children()."""
return ((f.name, value[f]) for f in value.type.fields())
#
# ptr must be a gdb.Value of pointer type.
# @return The address the pointer is pointing to as int.
#
def _targetAddress(ptr):
assert ptr.type.code == gdb.TYPE_CODE_PTR
return long(ptr)
def _buildPrettyPrinters():
pp = gdb.printing.RegexpCollectionPrettyPrinter("Excon")
pp.add_printer('dds::core::string', '^dds::core::basic_string<char,.*>$', DdsStringPrinter)
pp.add_printer('dds::core::vector', '^rti::core::vector<.*>$', DdsVectorPrinter)
pp.add_printer('dds::core::optional<dds::core::string>', '^rti::core::optional<dds::core::basic_string<.*>$', DdsOptionalStringPrinter)
pp.add_printer('dds::core::optional', '^rti::core::optional<.*>$', DdsOptionalPrinter)
# pp.add_printer('AudioVideoManagement::AvaTimePoint', '^AudioVideoManagement::AvaTimePoint$', AvaTimePointPrinter) # somehow doesn't work
pp.add_printer('std::chrono::duration', '^std::chrono::duration<.*>$', StdChronoDurationPrinter)
pp.add_printer('std::chrono::time_point', '^std::chrono::time_point<.*>$', StdChronoTimePointPrinter)
pp.add_printer('NTPTimestamp', '^NTPTimestamp$', AvsNtpTimestampPrinter)
pp.add_printer('NTPRange', '^NTPRange$', AvsNtpRangePrinter)
return pp
def registerPrettyPrinters():
gdb.printing.register_pretty_printer(gdb.current_objfile(), _buildPrettyPrinters())
+167
View File
@@ -0,0 +1,167 @@
# -*- coding: utf-8 -*-
"""
Debugging Helpers for use with QtCreator.
To activate, in QtCreator open Tools -> Options... -> Debugger -> Locals & Expressions
and put the absolut path to this file into the "Extra Debugging Helpers" field.
@author Christian Fröbel
"""
from dumper import *
from datetime import datetime
def qdump__dds__core__basic_string(d, value):
d.putItem(value['str_'])
d.putBetterType('dds::core::string')
def qdump__rti__core__vector(d, value):
innerType = value.type[0]
capacity = value['seq_']['_maximum'].integer()
size = value['seq_']['_length'].integer()
d.putItemCount(size)
d.putNumChild(size)
if d.isExpanded():
with Children(d):
with SubItem(d, 'capacity'):
d.putValue(capacity)
with SubItem(d, 'values'):
d.putItemCount(size)
if d.isExpanded():
rawBuffer = value['seq_']['_contiguous_buffer']
d.putArrayData(rawBuffer.integer(), size, innerType)
def qdump__rti__core__optional(d, value):
innerType = value.type[0]
stringType = d.createType('dds::core::string')
# Kann man Types direkt vergleichen, auch wenn innerType ein Alias ist?
if innerType.name == 'dds::core::basic_string<char, rti::core::memory::OsapiAllocator<char> >':
_dumpOptionalString(d, value)
else:
_dumpOptionalCommon(d, value)
def _dumpOptionalCommon(d, value):
"""Default implementation for dds::core::optional<T>"""
ptrToValue = value['value_']
isInitialized = ptrToValue.integer() != 0
if isInitialized:
innerType = value.type[0]
d.putItem(ptrToValue.dereference())
d.putBetterType(innerType)
else:
d.putValue("uninitialized")
d.putNumChild(0)
def _dumpOptionalString(d, value):
"""Specialization for dds::core::optional<dds::core::string>"""
strValue = value['value_']
isInitialized = strValue['str_'].integer() != 0
if isInitialized:
d.putItem(strValue)
d.putBetterType('dds::core::string')
else:
d.putValue("uninitialized")
d.putBetterType('dds::core::optional<dds::core::string>')
d.putNumChild(0)
def qdump__Core__BaseEntity(d, value):
name = d.extractCString(value['m_name_']['str_'].integer())
d.putValue('{}: \\"{}\\"'.format(value['m_id_'].integer(), name))
d.putNumChild(5)
if d.isExpanded():
with Children(d):
for member in 'm_id_ m_name_ m_isDeleted_ m_isUsed_ m_isBlockedForEdit_'.split():
with SubItem(d, member):
d.putItem(value[member])
def qdump__dds__core__safe_enum(d, value):
d.putItem(value['val'])
def qdump__std__chrono__duration(d, value):
seconds = _createSecondsFromDuration(value)
ms = int(seconds*1000)
d.putValue('{}ms'.format(ms))
d.putPlainChildren(value)
def qdump__AudioVideoManagement__AvaTimePoint(d, value):
dt = _createDateTimeFromTimePoint(value)
d.putValue(_isoFormat(dt, nachkommaStellen=2))
d.putPlainChildren(value)
def qdump__std__chrono__time_point(d, value):
dt = _createDateTimeFromTimePoint(value)
d.putValue(_isoFormat(dt, nachkommaStellen=6))
d.putPlainChildren(value)
def qdump__NTPTimestamp(d, value):
dt = _createDateTimeFromNtpTimestamp(value)
d.putValue(_isoFormat(dt, nachkommaStellen=3))
d.putPlainChildren(value)
def qdump__NTPRange(d, value):
dtBegin = _createDateTimeFromNtpTimestamp(value['m_begin'])
dtEnd = _createDateTimeFromNtpTimestamp(value['m_end'])
delta = dtEnd - dtBegin
seconds = delta.total_seconds() # float
fractionInMilli = int(seconds * 1000 + 0.5) % 1000
d.putValue('{} - {}, {:d}.{:03d}s'.format(_isoFormat(dtBegin, nachkommaStellen=3), _isoFormat(dtEnd, nachkommaStellen=3), int(seconds), fractionInMilli))
d.putPlainChildren(value)
def _createSecondsFromDuration(value):
"""Create seconds as float from a std::chrono::duration value"""
durationType = value.type
if durationType.code == TypeCodeTypedef:
durationType = durationType.stripTypedefs()
ratioType = durationType[1]
dividend = ratioType[0]
divisor = ratioType[1]
duration = int(value['__r'])
seconds = duration * dividend / float(divisor)
return seconds
def _createDateTimeFromTimePoint(value):
"""Create a datatime from a std::chrono::timepoint value"""
sSinceEpoch = _createSecondsFromDuration(value['__d'])
return datetime.utcfromtimestamp(sSinceEpoch)
NTP_OFFSET = 2208988800 # in s; NTP starts at 1900-01-01 where unix epoch is 1970-01-01; difference is 70 years plus 17 leap years
def _createSecondsFromNtpTimestamp(value):
"""Create seconds as float from AVS NTPTimestamp. The format is a fixed 64 bit floating point number
where the upper 32 bit denote the seconds and the lower 32 bit denote the fraction of a second."""
fixedFloatValue = int(value['m_data'])
seconds = fixedFloatValue >> 32
fract = fixedFloatValue & 0xffffffff
return seconds + float(fract) / (1 << 32) - NTP_OFFSET
def _createDateTimeFromNtpTimestamp(value):
"""Create a datetime from AVS NTPTimestamp"""
sSinceEpoch = _createSecondsFromNtpTimestamp(value)
return datetime.utcfromtimestamp(sSinceEpoch)
def _isoFormat(dt, nachkommaStellen):
"""Return the ISO-representation for a given datetime instance with the requested number of Nachkommastellen"""
assert nachkommaStellen >= 0 and nachkommaStellen <= 6
s = dt.isoformat(' ')
if dt.microsecond > 0:
if nachkommaStellen == 6:
return s
return s[:-(6-nachkommaStellen)]
return s + '.' + nachkommaStellen * '0'
+34
View File
@@ -0,0 +1,34 @@
# Copyright 2014 Alex Merry <alex.merry@kde.org>
#
# Permission to use, copy, modify, and distribute this software
# and its documentation for any purpose and without fee is hereby
# granted, provided that the above copyright notice appear in all
# copies and that both that the copyright notice and this
# permission notice and warranty disclaimer appear in supporting
# documentation, and that the name of the author not be used in
# advertising or publicity pertaining to distribution of the
# software without specific, written prior permission.
#
# The author disclaims all warranties with regard to this
# software, including all implied warranties of merchantability
# and fitness. In no event shall the author be liable for any
# special, indirect or consequential damages or any damages
# whatsoever resulting from loss of use, data or profits, whether
# in an action of contract, negligence or other tortious action,
# arising out of or in connection with the use or performance of
# this software.
import gdb.printing
from . import core
"""Qt5 Pretty Printers for GDB.
The printers are split into submodules, one for each Qt library. Each
submodule has a "printer" attribute that contains a pretty-printer for
that library.
"""
def register_printers(obj):
"""Registers all known Qt5 pretty-printers."""
gdb.printing.register_pretty_printer(obj, core.printer)
+901
View File
@@ -0,0 +1,901 @@
# Copyright 2014 Alex Merry <alex.merry@kde.org>
#
# Permission to use, copy, modify, and distribute this software
# and its documentation for any purpose and without fee is hereby
# granted, provided that the above copyright notice appear in all
# copies and that both that the copyright notice and this
# permission notice and warranty disclaimer appear in supporting
# documentation, and that the name of the author not be used in
# advertising or publicity pertaining to distribution of the
# software without specific, written prior permission.
#
# The author disclaims all warranties with regard to this
# software, including all implied warranties of merchantability
# and fitness. In no event shall the author be liable for any
# special, indirect or consequential damages or any damages
# whatsoever resulting from loss of use, data or profits, whether
# in an action of contract, negligence or other tortious action,
# arising out of or in connection with the use or performance of
# this software.
import gdb.printing
import itertools
from . import typeinfo
try:
import urlparse
except ImportError:
# Python 3
import urllib.parse as urlparse
"""Qt5Core pretty printer for GDB."""
# NB: no QPair printer: the default should be fine
def _format_jd(jd):
"""Format a Julian Day in YYYY-MM-DD format."""
# maths from http://www.tondering.dk/claus/cal/julperiod.php
a = jd + 32044
b = (4 * a + 3) // 146097
c = a - ( (146097 * b) // 4 )
d = (4 * c + 3) // 1461
e = c - ( (1461 * d) // 4 )
m = (5 * e + 2) // 153
day = e - ( (153 * m + 2) // 5 ) + 1
month = m + 3 - 12 * ( m // 10 )
year = 100 * b + d - 4800 + ( m // 10 )
return '{:0=4}-{:0=2}-{:0=2}'.format(year, month, day)
def _jd_is_valid(jd):
"""Return whether QDate would consider a given Julian Day valid."""
return jd >= -784350574879 and jd <= 784354017364
def _format_time_ms(msecs):
"""Format a number of milliseconds since midnight in HH:MM:SS.ssss format."""
secs = msecs // 1000
mins = secs // 60
hours = mins // 60
return '{:0=2}:{:0=2}:{:0=2}.{:0=3}'.format(
hours % 24, mins % 60, secs % 60, msecs % 1000)
def _ms_is_valid(msecs):
"""Return whether QTime would consider a ms since midnight valid."""
return msecs >= 0 and msecs <= 86400000
class ArrayIter:
"""Iterates over a fixed-size array."""
def __init__(self, array, size):
self.array = array
self.i = -1
self.size = size
def __iter__(self):
return self
def __next__(self):
if self.i + 1 >= self.size:
raise StopIteration
self.i += 1
return ('[%d]' % self.i, self.array[self.i])
def next(self):
return self.__next__()
class StructReader:
"""Reads entries from a struct."""
def __init__(self, data):
self.data = data.reinterpret_cast(gdb.lookup_type('char').pointer())
self.ptr_t = gdb.lookup_type('void').pointer()
def next_aligned_val(self, typ):
ptr_val = int(str(self.data.reinterpret_cast(self.ptr_t)), 16)
misalignment = ptr_val % self.ptr_t.sizeof
if misalignment > 0:
self.data += self.ptr_t.sizeof - misalignment
val = self.data.reinterpret_cast(typ.pointer())
self.data += typ.sizeof
return val.referenced_value()
def next_val(self, typ):
val = self.data.reinterpret_cast(typ.pointer())
self.data += typ.sizeof
return val.referenced_value()
class QBitArrayPrinter:
"""Print a Qt5 QBitArray"""
class Iter:
def __init__(self, data, size):
self.data = data
self.i = -1
self.size = size
def __iter__(self):
return self
def __next__(self):
if self.i + 1 >= self.size:
raise StopIteration
self.i += 1
if self.data[1 + (self.i >> 3)] & (1 << (self.i&7)):
return (str(self.i), 1)
else:
return (str(self.i), 0)
def next(self):
return self.__next__()
def __init__(self, val):
self.val = val
def children(self):
d = self.val['d']['d']
data = d.reinterpret_cast(gdb.lookup_type('char').pointer()) + d['offset']
size = (int(d['size']) << 3) - int(data[0])
return self.Iter(data, size)
def to_string(self):
d = self.val['d']['d']
data = d.reinterpret_cast(gdb.lookup_type('char').pointer()) + d['offset']
size = (int(d['size']) << 3) - int(data[0])
if size == 0:
return '<empty>'
return None
def display_hint(self):
return 'array'
class QByteArrayPrinter:
"""Print a Qt5 QByteArray"""
def __init__(self, val):
self.val = val
def children(self):
d = self.val['d']
data = d.reinterpret_cast(gdb.lookup_type('char').pointer()) + d['offset']
return ArrayIter(data, d['size'])
def to_string(self):
d = self.val['d']
data = d.reinterpret_cast(gdb.lookup_type('char').pointer()) + d['offset']
return data.string('', 'replace', d['size'])
def display_hint(self):
return 'string'
class QCharPrinter:
"""Print a Qt5 QChar"""
def __init__(self, val):
self.val = val
def to_string(self):
ucs = self.val['ucs']
data = ucs.address.reinterpret_cast(gdb.lookup_type('char').pointer())
unicode_str = data.string('utf-16', 'replace', 2)
uch = unicode_str[0]
if uch == unichr(0x27):
return "'\\''"
# this actually gives us Python escapes, but they should all be
# valid C escapes as well
return "'" + uch.encode('unicode_escape') + "'"
def display_hint(self):
# this is not recognized by gdb, hence the manual escaping and quoting
# we do above
return 'char'
class QDatePrinter:
"""Print a Qt5 QDate"""
def __init__(self, val):
self.val = val
def to_string(self):
jd = int(self.val['jd'])
if not _jd_is_valid(jd):
return '<invalid>'
return _format_jd(jd)
def display_hint(self):
return 'date'
class QDateTimePrinter:
"""Print a Qt5 QDateTime"""
def __init__(self, val):
self.val = val
_unix_epoch_jd = 2440588
_ms_per_day = 86400000
# status field
_validDate = 0x04
_validTime = 0x08
_validDateTime = 0x10
_timeZoneCached = 0x20
# time spec
_localTime = 0
_UTC = 1
_offsetFromUTC = 2
_timeZone = 3
def to_string(self):
d = self.val['d']['d']
if not d:
return '<invalid>'
try:
qshareddata_t = gdb.lookup_type('QSharedData')
except gdb.error:
try:
# well, it only has a QAtomicInt in it
qshareddata_t = gdb.lookup_type('QAtomicInt')
except gdb.error:
# let's hope it's the same size as an int
qshareddata_t = gdb.lookup_type('int')
try:
timespec_t = gdb.lookup_type('Qt::TimeSpec')
except gdb.error:
# probably an int
timespec_t = gdb.lookup_type('int')
reader = StructReader(d)
reader.next_val(qshareddata_t)
m_msecs = reader.next_aligned_val(gdb.lookup_type('qint64'))
spec = int(reader.next_val(timespec_t))
m_offsetFromUtc = reader.next_val(gdb.lookup_type('int'))
m_timeZone = reader.next_val(gdb.lookup_type('QTimeZone'))
status = int(reader.next_val(gdb.lookup_type('int')))
if spec == self._timeZone:
timeZoneStr = QTimeZonePrinter(m_timeZone).to_string()
if timeZoneStr == '':
return '<invalid>'
if spec == self._localTime or (spec == self._timeZone and
not status & self._timeZoneCached):
# Because QDateTime delays timezone calculations as far as
# possible, the ValidDateTime flag may not be set even if
# it is a valid DateTime.
if not status & self._validDate or not status & self._validTime:
return '<invalid>'
elif not (status & self._validDateTime):
return '<invalid>'
# actually fetch:
m_msecs = int(m_msecs)
jd = self._unix_epoch_jd # UNIX epoch
jd += m_msecs // self._ms_per_day
msecs = m_msecs % self._ms_per_day
if msecs < 0:
# need to adjust back to the previous day
jd -= 1
msecs += self._ms_per_day
result = _format_jd(jd) + ' ' + _format_time_ms(msecs)
if spec == self._localTime:
result += ' (Local)'
elif spec == self._UTC:
result += ' (UTC)'
elif spec == self._offsetFromUTC:
offset = int(m_offsetFromUtc)
if offset == 0:
diffstr = ''
else:
hours = abs(offset // 3600)
mins = abs((offset % 3600) // 60)
secs = abs(offset % 60)
sign = '+' if offset > 0 else '-'
diffstr = '{:}{:0=2d}:{:0=2d}'.format(sign, hours, mins)
if secs > 0:
diffstr += ':{:0=2d}'.format(secs)
result += ' (UTC{:})'.format(diffstr)
elif spec == self._timeZone:
result += ' ({:})'.format(timeZoneStr)
return result
def display_hint(self):
return 'datetime'
class QHashPrinter:
"""Print a Qt5 QHash"""
class Iter:
def __init__(self, d, e):
self.buckets_left = d['numBuckets']
self.node_type = e.type
# set us up at the end of a "dummy bucket"
self.current_bucket = d['buckets'] - 1
self.current_node = None
self.i = -1
self.waiting_for_value = False
def __iter__(self):
return self
def __next__(self):
if self.waiting_for_value:
self.waiting_for_value = False
node = self.current_node.reinterpret_cast(self.node_type)
return ('value' + str(self.i), node['value'])
if self.current_node:
self.current_node = self.current_node['next']
# the dummy node that terminates a bucket is distinguishable
# by not having its 'next' value set
if not self.current_node or not self.current_node['next']:
while self.buckets_left:
self.current_bucket += 1
self.buckets_left -= 1
self.current_node = self.current_bucket.referenced_value()
if self.current_node['next']:
break
else:
raise StopIteration
self.i += 1
self.waiting_for_value = True
node = self.current_node.reinterpret_cast(self.node_type)
return ('key' + str(self.i), node['key'])
def next(self):
return self.__next__()
def __init__(self, val):
self.val = val
def children(self):
d = self.val['d']
if d['size'] == 0:
return []
return self.Iter(d, self.val['e'])
def to_string(self):
# if we return an empty list from children, gdb doesn't print anything
if self.val['d']['size'] == 0:
return '<empty>'
return None
def display_hint(self):
return 'map'
class QLatin1StringPrinter:
"""Print a Qt5 QLatin1String"""
def __init__(self, val):
self.val = val
def to_string(self):
return self.val['m_data'].string('', 'replace', self.val['m_size'])
def display_hint(self):
return 'string'
class QLinkedListPrinter:
"""Print a Qt5 QLinkedList"""
class Iter:
def __init__(self, tail, size):
self.current = tail
self.i = -1
self.size = size
def __iter__(self):
return self
def __next__(self):
if self.i + 1 >= self.size:
raise StopIteration
self.i += 1
self.current = self.current['n']
return (str(self.i), self.current['t'])
def next(self):
return self.__next__()
def __init__(self, val):
self.val = val
def children(self):
size = int(self.val['d']['size'])
if size == 0:
return []
return self.Iter(self.val['e'], size)
def to_string(self):
# if we return an empty list from children, gdb doesn't print anything
if self.val['d']['size'] == 0:
return '<empty>'
return None
def display_hint(self):
return 'array'
class QListPrinter:
"""Print a Qt5 QList"""
class Iter:
def __init__(self, array, begin, end, typ):
self.array = array
self.end = end
self.begin = begin
self.offset = 0
if typ.name == 'QStringList':
self.el_type = gdb.lookup_type('QString')
else:
self.el_type = typ.template_argument(0)
if ((self.el_type.sizeof > gdb.lookup_type('void').pointer().sizeof)
or typeinfo.type_is_known_static(self.el_type)):
self.is_pointer = True
elif (typeinfo.type_is_known_movable(self.el_type) or
typeinfo.type_is_known_primitive(self.el_type)):
self.is_pointer = False
else:
raise ValueError("Could not determine whether QList stores " +
self.el_type.name + " directly or as a pointer: to fix " +
"this, add it to one of the variables in the "+
"qt5printers.typeinfo module")
self.node_type = gdb.lookup_type(typ.name + '::Node').pointer()
def __iter__(self):
return self
def __next__(self):
if self.begin + self.offset >= self.end:
raise StopIteration
node = self.array[self.begin + self.offset].reinterpret_cast(self.node_type)
if self.is_pointer:
p = node['v']
else:
p = node
self.offset += 1
return ((str(self.offset), p.cast(self.el_type)))
def next(self):
return self.__next__()
def __init__(self, val):
self.val = val
def children(self):
d = self.val['d']
begin = int(d['begin'])
end = int(d['end'])
if begin == end:
return []
return self.Iter(d['array'], begin, end, self.val.type.strip_typedefs())
def to_string(self):
# if we return an empty list from children, gdb doesn't print anything
if self.val['d']['begin'] == self.val['d']['end']:
return '<empty>'
return None
def display_hint(self):
return 'array'
class QMapPrinter:
"""Print a Qt5 QMap"""
class Iter:
def __init__(self, root, node_p_type):
self.root = root
self.current = None
self.node_p_type = node_p_type
self.next_is_key = True
self.i = -1
# we store the path here to avoid keeping re-fetching
# values from the inferior (also, skips the pointer
# arithmetic involved in using the parent pointer)
self.path = []
def __iter__(self):
return self
def moveToNextNode(self):
if self.current is None:
# find the leftmost node
if not self.root['left']:
return False
self.current = self.root
while self.current['left']:
self.path.append(self.current)
self.current = self.current['left']
elif self.current['right']:
self.path.append(self.current)
self.current = self.current['right']
while self.current['left']:
self.path.append(self.current)
self.current = self.current['left']
else:
last = self.current
self.current = self.path.pop()
while self.current['right'] == last:
last = self.current
self.current = self.path.pop()
# if there are no more parents, we are at the root
if len(self.path) == 0:
return False
return True
def __next__(self):
if self.next_is_key:
if not self.moveToNextNode():
raise StopIteration
self.current_typed = self.current.reinterpret_cast(self.node_p_type)
self.next_is_key = False
self.i += 1
return ('key' + str(self.i), self.current_typed['key'])
else:
self.next_is_key = True
return ('value' + str(self.i), self.current_typed['value'])
def next(self):
return self.__next__()
def __init__(self, val):
self.val = val
def children(self):
d = self.val['d']
size = int(d['size'])
if size == 0:
return []
realtype = self.val.type.strip_typedefs()
keytype = realtype.template_argument(0)
valtype = realtype.template_argument(1)
node_type = gdb.lookup_type('QMapData<' + keytype.name + ',' + valtype.name + '>::Node')
return self.Iter(d['header'], node_type.pointer())
def to_string(self):
# if we return an empty list from children, gdb doesn't print anything
if self.val['d']['size'] == 0:
return '<empty>'
return None
def display_hint(self):
return 'map'
class QSetPrinter:
"""Print a Qt5 QSet"""
def __init__(self, val):
self.val = val
def children(self):
hashPrinter = QHashPrinter(self.val['q_hash'])
# the keys of the hash are the elements of the set, so select
# every other item (starting with the first)
return itertools.islice(hashPrinter.children(), 0, None, 2)
def to_string(self):
# if we return an empty list from children, gdb doesn't print anything
if self.val['q_hash']['d']['size'] == 0:
return '<empty>'
return None
def display_hint(self):
return 'array'
class QStringPrinter:
"""Print a Qt5 QString"""
def __init__(self, val):
self.val = val
def to_string(self):
d = self.val['d']
data = d.reinterpret_cast(gdb.lookup_type('char').pointer()) + d['offset']
data_len = d['size'] * gdb.lookup_type('unsigned short').sizeof
return data.string('utf-16', 'replace', data_len)
def display_hint(self):
return 'string'
class QTimePrinter:
"""Print a Qt5 QTime"""
def __init__(self, val):
self.val = val
def to_string(self):
msecs = int(self.val['mds'])
if not _ms_is_valid(msecs):
return '<invalid>'
return _format_time_ms(msecs)
def display_hint(self):
return 'time'
class QTimeZonePrinter:
"""Print a Qt5 QTimeZone"""
def __init__(self, val):
self.val = val
def to_string(self):
d = self.val['d']['d']
if not d:
return ''
try:
# Accessing the private data is error-prone,
# so try just calling the id() method.
# This should be reasonably safe, as all it will
# do is create a QByteArray that references the
# same internal data as the stored one. However,
# it will only work with an attached process.
m_id = gdb.parse_and_eval('((QTimeZone*){:})->id()'.format(self.val.address))
except:
ptr_size = gdb.lookup_type('void').pointer().sizeof
try:
qshareddata_t = gdb.lookup_type('QSharedData')
except gdb.error:
try:
# well, it only has a QAtomicInt in it
qshareddata_t = gdb.lookup_type('QAtomicInt')
except gdb.error:
# let's hope it's the same size as an int
qshareddata_t = gdb.lookup_type('int')
reader = StructReader(d)
reader.next_val(gdb.lookup_type('void').pointer()) # vtable
reader.next_val(qshareddata_t)
m_id = reader.next_aligned_val(gdb.lookup_type('QByteArray'))
return QByteArrayPrinter(m_id).to_string()
def display_hint(self):
return 'string'
class QVariantPrinter:
"""Print a Qt5 QVariant"""
_varmap = {
'char': 'c',
'uchar': 'uc',
'short': 's',
'signed char': 'sc',
'ushort': 'us',
'int': 'i',
'uint': 'u',
'long': 'l',
'ulong': 'ul',
'bool': 'b',
'double': 'd',
'float': 'f',
'qreal': 'real',
'qlonglong': 'll',
'qulonglong': 'ull',
'QObject*': 'o',
'void*': 'ptr'
}
def __init__(self, val):
self.val = val
def children(self):
d = self.val['d']
typ = int(d['type'])
if typ == typeinfo.meta_type_unknown:
return [('type', 'invalid')]
data = d['data']
if typ in typeinfo.meta_type_names:
typename = typeinfo.meta_type_names[typ]
if typename in self._varmap:
field = self._varmap[typename]
return [('type', typename), ('data', data[field])]
try:
if typename.endswith('*'):
gdb_type = gdb.lookup_type(typename[0:-1]).pointer()
else:
gdb_type = gdb.lookup_type(typename)
except gdb.error:
# couldn't find any type information
return [('type', typename), ('data', data)]
if gdb_type.sizeof > data.type.sizeof:
is_pointer = True
elif (typeinfo.type_is_known_movable(gdb_type) or
typeinfo.type_is_known_primitive(gdb_type)):
is_pointer = False
elif gdb_type.tag == 'enum':
is_pointer = False
else:
# couldn't figure out how the type is stored
return [('type', typename), ('data', data)]
if is_pointer:
value = data['shared']['ptr'].reinterpret_cast(gdb_type.pointer())
else:
void_star = gdb.lookup_type('void').pointer()
data_void = data['c'].address.reinterpret_cast(void_star)
value = data_void.reinterpret_cast(gdb_type.pointer())
return [('type', typename), ('data', value.referenced_value())]
else:
# custom type?
return [('type', typ), ('data', data)]
def to_string(self):
return None
class QVarLengthArrayPrinter:
"""Print a Qt5 QVarLengthArray"""
def __init__(self, val):
self.val = val
def children(self):
size = int(self.val['s'])
if size == 0:
return []
return ArrayIter(self.val['ptr'], size)
def to_string(self):
# if we return an empty list from children, gdb doesn't print anything
if self.val['s'] == 0:
return '<empty>'
return None
def display_hint(self):
return 'array'
class QVectorPrinter:
"""Print a Qt5 QVector"""
def __init__(self, val):
self.val = val
def children(self):
d = self.val['d']
el_type = self.val.type.template_argument(0)
data_len = int(d['size'])
if data_len == 0:
return []
data_char = d.reinterpret_cast(gdb.lookup_type('char').pointer()) + d['offset']
data = data_char.reinterpret_cast(el_type.pointer())
return ArrayIter(data, data_len)
def to_string(self):
# if we return an empty list from children, gdb doesn't print anything
if self.val['d']['size'] == 0:
return '<empty>'
return None
def display_hint(self):
return 'array'
class QUrlPrinter:
"""Print a Qt5 QUrl"""
def __init__(self, val):
self.val = val
def to_string(self):
d = self.val['d']
if not d:
return '<empty>'
int_t = gdb.lookup_type('int')
try:
atomicint_t = gdb.lookup_type('QAtomicInt')
except gdb.error:
# let's hope it's the same size as an int
atomicint_t = int_t
qstring_t = gdb.lookup_type('QString')
uchar_t = gdb.lookup_type('uchar')
reader = StructReader(d)
# These fields (including order) are unstable, and
# may change between even patch-level Qt releases
reader.next_val(atomicint_t)
port = int(reader.next_val(int_t))
scheme = reader.next_val(qstring_t)
userName = reader.next_val(qstring_t)
password = reader.next_val(qstring_t)
host = reader.next_val(qstring_t)
path = reader.next_val(qstring_t)
query = reader.next_val(qstring_t)
fragment = reader.next_val(qstring_t)
reader.next_val(gdb.lookup_type('void').pointer())
sections = int(reader.next_val(uchar_t))
flags = int(reader.next_val(uchar_t))
# isLocalFile and no query and no fragment
if flags & 0x01 and not (sections & 0x40) and not (sections & 0x80):
# local file
return path
def qs_to_s(qstring):
return QStringPrinter(qstring).to_string()
# QUrl::toString() is way more complicated than what we do here,
# but this is good enough for debugging
result = ''
if sections & 0x01:
result += qs_to_s(scheme) + ':'
if sections & (0x02 | 0x04 | 0x08 | 0x10) or flags & 0x01:
result += '//'
if sections & 0x02 or sections & 0x04:
result += qs_to_s(userName)
if sections & 0x04:
# this may appear in backtraces that will be sent to other
# people
result += ':<omitted>'
result += '@'
if sections & 0x08:
result += qs_to_s(host)
if port != -1:
result += ':' + str(port)
result += qs_to_s(path)
if sections & 0x40:
result += '?' + qs_to_s(query)
if sections & 0x80:
result += '#' + qs_to_s(fragment)
return result
def display_hint(self):
return 'string'
def build_pretty_printer():
"""Builds the pretty printer for Qt5Core."""
pp = gdb.printing.RegexpCollectionPrettyPrinter("Qt5Core")
pp.add_printer('QBitArray', '^QBitArray$', QBitArrayPrinter)
pp.add_printer('QByteArray', '^QByteArray$', QByteArrayPrinter)
pp.add_printer('QChar', '^QChar$', QCharPrinter)
pp.add_printer('QDate', '^QDate$', QDatePrinter)
pp.add_printer('QDateTime', '^QDateTime$', QDateTimePrinter)
pp.add_printer('QLatin1String', '^QLatin1String$', QLatin1StringPrinter)
pp.add_printer('QLinkedList', '^QLinkedList<.*>$', QLinkedListPrinter)
pp.add_printer('QList', '^QList<.*>$', QListPrinter)
pp.add_printer('QMap', '^QMap<.*>$', QMapPrinter)
pp.add_printer('QHash', '^QHash<.*>$', QHashPrinter)
pp.add_printer('QQueue', '^QQueue<.*>$', QListPrinter)
pp.add_printer('QSet', '^QSet<.*>$', QSetPrinter)
pp.add_printer('QStack', '^QStack<.*>$', QVectorPrinter)
pp.add_printer('QString', '^QString$', QStringPrinter)
pp.add_printer('QStringList', '^QStringList$', QListPrinter)
pp.add_printer('QTime', '^QTime$', QTimePrinter)
pp.add_printer('QTimeZone', '^QTimeZone$', QTimeZonePrinter)
pp.add_printer('QVariant', '^QVariant$', QVariantPrinter)
pp.add_printer('QVariantList', '^QVariantList$', QListPrinter)
pp.add_printer('QVariantMap', '^QVariantMap$', QMapPrinter)
pp.add_printer('QVector', '^QVector<.*>$', QVectorPrinter)
pp.add_printer('QVarLengthArray', '^QVarLengthArray<.*>$', QVarLengthArrayPrinter)
pp.add_printer('QUrl', '^QUrl$', QUrlPrinter)
return pp
printer = build_pretty_printer()
"""The pretty printer for Qt5Core.
This can be registered using gdb.printing.register_pretty_printer().
"""
+355
View File
@@ -0,0 +1,355 @@
# Copyright 2014 Alex Merry <alex.merry@kde.org>
#
# Permission to use, copy, modify, and distribute this software
# and its documentation for any purpose and without fee is hereby
# granted, provided that the above copyright notice appear in all
# copies and that both that the copyright notice and this
# permission notice and warranty disclaimer appear in supporting
# documentation, and that the name of the author not be used in
# advertising or publicity pertaining to distribution of the
# software without specific, written prior permission.
#
# The author disclaims all warranties with regard to this
# software, including all implied warranties of merchantability
# and fitness. In no event shall the author be liable for any
# special, indirect or consequential damages or any damages
# whatsoever resulting from loss of use, data or profits, whether
# in an action of contract, negligence or other tortious action,
# arising out of or in connection with the use or performance of
# this software.
import gdb.printing
"""Qt5 Type Information
Since the QTypeInfo information is not necessarily available at debug time, this
module contains useful type information about standard and Qt types (such as
whether a type is movable) that is necessary for the operation of the printers.
This information allows the QList printer, for example, to determine how the
elements are stored in the list.
"""
primitive_types = set([
'HB_FixedPoint',
'HB_GlyphAttributes',
'QCharAttributes',
'QFlag',
'QIncompatibleFlag',
'QRegExpAnchorAlternation',
'QRegExpAtom',
'QRegExpCharClassRange',
'QStaticPlugin',
'QStringRef',
'QTzType',
'QUuid'
])
"""Primitive (non-template) types.
This does not need to include compiler-primitive types (like int).
If you use the Q_DECLARE_TYPEINFO macro with Q_PRIMITIVE_TYPE flag, you
should add the type to this set. This is particularly important for
types that are the same size as a pointer or smaller.
"""
primitive_tpl_types = set(['QFlags'])
"""Primitive template types.
If you use the Q_DECLARE_TYPEINFO_BODY macro with Q_PRIMITIVE_TYPE flag
on a type with template parameters, you should add the type to this
set. This is particularly important for types that are the same size as
a pointer or smaller.
Entries should just be the base typename, without any template
parameters (eg: "QFlags", rather than "QFlags<T>").
"""
movable_types = set([
'QBasicTimer',
'QBitArray',
'QByteArray',
'QChar',
'QCharRef',
'QCustomTypeInfo',
'QDate',
'QDateTime',
'QFileInfo',
'QEasingCurve',
'QFileSystemWatcherPathKey',
'QHashDummyValue',
'QItemSelectionRange',
'QLatin1String',
'QLine',
'QLineF',
'QLocale',
'QLoggingRule',
'QMargins',
'QMarginsF',
'QMetaClassInfo',
'QMetaEnum',
'QMetaMethod',
'QMimeMagicRule',
'QModelIndex',
'QPersistentModelIndex',
'QObjectPrivate::Connection',
'QObjectPrivate::Sender',
'QPoint',
'QPointF',
'QPostEvent',
'QProcEnvKey',
'QProcEnvValue',
'QRect',
'QRectF',
'QRegExp',
'QRegExpAutomatonState',
'QRegExpCharClass',
'QResourceRoot',
'QSize',
'QSizeF',
'QString',
'QStringList',
'QTime',
'QTimeZone::OffsetData',
'QUrl',
'QVariant',
'QXmlStreamAttribute',
'QXmlStreamEntityDeclaration',
'QXmlStreamNamespaceDeclaration',
'QXmlStreamNotationDeclaration'
])
"""Movable (non-template) types.
If you use the Q_DECLARE_TYPEINFO macro with Q_MOVABLE_TYPE flag, you
should add the type to this set. This is particularly important for
types that are the same size as a pointer or smaller.
"""
movable_tpl_types = set([
'QExplicitlySharedDataPointer',
'QLinkedList',
'QList',
'QPointer',
'QQueue',
'QSet',
'QSharedDataPointer',
'QSharedPointer',
'QStack',
'QVector',
'QWeakPointer'
])
"""Movable template types.
If you use the Q_DECLARE_TYPEINFO_BODY macro with Q_MOVABLE_TYPE flag
on a type with template parameters, you should add the type to this
set. This is particularly important for types that are the same size as
a pointer or smaller.
Entries should just be the base typename, without any template
parameters (eg: "QFlags", rather than "QFlags<T>").
"""
static_types = set()
"""Static (non-template) types.
If you define a custom type that is neither primitive nor movable, you
can add the type to this set to indicate this. This is particularly
important for types that are the same size as a pointer or smaller.
"""
static_tpl_types = set()
"""Static template types.
If you define a custom type with template parameters that is neither
primitive nor movable, you can add the type to this set to indicate
this. This is particularly important for types that are the same size as
a pointer or smaller.
Entries should just be the base typename, without any template
parameters (eg: "QFlags", rather than "QFlags<T>").
"""
def type_is_known_primitive(typ):
"""Returns True if the given gdb type is known to be primitive."""
if typ.code == gdb.TYPE_CODE_PTR or typ.code == gdb.TYPE_CODE_INT or typ.code == gdb.TYPE_CODE_FLT or typ.code == gdb.TYPE_CODE_CHAR or typ.code == gdb.TYPE_CODE_BOOL:
return True
pos = typ.name.find('<')
if pos > 0:
return typ.name[0:pos] in primitive_tpl_types
else:
return typ.name in primitive_types
def type_is_known_movable(typ):
"""Returns True if the given gdb type is known to be movable."""
if not typ.name:
return False
pos = typ.name.find('<')
if pos > 0:
return typ.name[0:pos] in movable_tpl_types
else:
return typ.name in movable_types
def type_is_known_static(typ):
"""Returns True if the given gdb type is known to be neither primitive nor movable."""
if not typ.name:
return False
pos = typ.name.find('<')
if pos > 0:
return typ.name[0:pos] in static_tpl_types
else:
return typ.name in static_types
meta_type_unknown = 0
"""The unknown/invalid meta type ID."""
meta_type_user = 1024
"""The starting value for custom type IDs."""
meta_type_ids = {
'bool': 1,
'int': 2,
'uint': 3,
'qlonglong': 4,
'qulonglong': 5,
'double': 6,
'QChar': 7,
'QVariantMap': 8,
'QVariantList': 9,
'QString': 10,
'QStringList': 11,
'QByteArray': 12,
'QBitArray': 13,
'QDate': 14,
'QTime': 15,
'QDateTime': 16,
'QUrl': 17,
'QLocale': 18,
'QRect': 19,
'QRectF': 20,
'QSize': 21,
'QSizeF': 22,
'QLine': 23,
'QLineF': 24,
'QPoint': 25,
'QPointF': 26,
'QRegExp': 27,
'QVariantHash': 28,
'QEasingCurve': 29,
'QUuid': 30,
'void*': 31,
'long': 32,
'short': 33,
'char': 34,
'ulong': 35,
'ushort': 36,
'uchar': 37,
'float': 38,
'QObject*': 39,
'signed char': 40,
'QVariant': 41,
'QModelIndex': 42,
'void': 43,
'QRegularExpression': 44,
'QJsonValue': 45,
'QJsonObject': 46,
'QJsonArray': 47,
'QJsonDocument': 48,
'QFont': 64,
'QPixmap': 65,
'QBrush': 66,
'QColor': 67,
'QPalette': 68,
'QIcon': 69,
'QImage': 70,
'QPolygon': 71,
'QRegion': 72,
'QBitmap': 73,
'QCursor': 74,
'QKeySequence': 75,
'QPen': 76,
'QTextLength': 77,
'QTextFormat': 78,
'QMatrix': 79,
'QTransform': 80,
'QMatrix4x4': 81,
'QVector2D': 82,
'QVector3D': 83,
'QVector4D': 84,
'QQuaternion': 85,
'QPolygonF': 86,
'QSizePolicy': 121
}
"""Map from type names to meta type IDs."""
meta_type_names = {
1: 'bool',
2: 'int',
3: 'uint',
4: 'qlonglong',
5: 'qulonglong',
6: 'double',
7: 'QChar',
8: 'QVariantMap',
9: 'QVariantList',
10: 'QString',
11: 'QStringList',
12: 'QByteArray',
13: 'QBitArray',
14: 'QDate',
15: 'QTime',
16: 'QDateTime',
17: 'QUrl',
18: 'QLocale',
19: 'QRect',
20: 'QRectF',
21: 'QSize',
22: 'QSizeF',
23: 'QLine',
24: 'QLineF',
25: 'QPoint',
26: 'QPointF',
27: 'QRegExp',
28: 'QVariantHash',
29: 'QEasingCurve',
30: 'QUuid',
31: 'void*',
32: 'long',
33: 'short',
34: 'char',
35: 'ulong',
36: 'ushort',
37: 'uchar',
38: 'float',
39: 'QObject*',
40: 'signed char',
41: 'QVariant',
42: 'QModelIndex',
43: 'void',
44: 'QRegularExpression',
45: 'QJsonValue',
46: 'QJsonObject',
47: 'QJsonArray',
48: 'QJsonDocument',
64: 'QFont',
65: 'QPixmap',
66: 'QBrush',
67: 'QColor',
68: 'QPalette',
69: 'QIcon',
70: 'QImage',
71: 'QPolygon',
72: 'QRegion',
73: 'QBitmap',
74: 'QCursor',
75: 'QKeySequence',
76: 'QPen',
77: 'QTextLength',
78: 'QTextFormat',
79: 'QMatrix',
80: 'QTransform',
81: 'QMatrix4x4',
82: 'QVector2D',
83: 'QVector3D',
84: 'QVector4D',
85: 'QQuaternion',
86: 'QPolygonF',
121: 'QSizePolicy'
}
"""Map from meta type IDs to type names."""