# -*- 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""" 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""" 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$', DdsStringPrinter) pp.add_printer('dds::core::vector', '^rti::core::vector<.*>$', DdsVectorPrinter) pp.add_printer('dds::core::optional', '^rti::core::optional$', 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())