Adds rpm specs to migration repo
This commit is contained in:
1 parent
acee7b8766
commit
7f035543e2
145 files changed
+13982
No files matched your search
+45
@@ -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
@@ -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
@@ -0,0 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from .gdb_helper import registerPrettyPrinters
|
||||
+242
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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."""
|
||||
|
||||
Reference in new issue
Block a user