import re import gdb import sys import struct class CoordPrinter(object): def __init__(self, val): self.val = val def to_string(self): return self.val def display_hint(self): return 'array' class _iterator(object): def __init__(self, data): self.data = data def __iter__(self): indices = self.data.type.range() for i in range(indices[0], indices[1] + 1): res = (str(i), self.data[i]) yield res raise StopIteration() def children(self): return self._iterator(self.val['data']) class ViewPrinter(object): def __init__(self, val): self.val = val def to_string(self): end = int(self.val["m_end"]) begin = int(self.val["m_begin"]) size = end - begin return f"{size} elements" def display_hint(self): return 'array' def children(self): cursor = self.val["m_begin"] last = self.val["m_end"] index = 0 while cursor != last: val = cursor.dereference() res = ("[%d]" % index, val) cursor = cursor + 1 index = index + 1 val = cursor.dereference() yield res class EndianValuePrinter(object): val: gdb.Type def __init__(self, val: gdb.Value): self.val = val # The type should be something like: # "cruft::endian::value" order_name = str(val.type.template_argument(0)) # Fuck knows how to use the GDB API. It's easier to just search for a # differentiator that's unlikely to be present in anything else. if '::BIG' in order_name: self.order = '>' elif '::LITTLE' in order_name: self.order = '<' else: raise RuntimeError("Unknown endianness") # Find a format specifier for the size of the underlying value self.size = { 1: 'B', 2: 'H', 4: 'I', 8: 'Q', }[self.val.type.sizeof] def to_string (self): # Construct format specifiers for converting to bytes, then from # bytes, so that we can perform the byte reversal. to_bytes = f"{self.order}{self.size}" from_bytes = f"={self.size}" raw = int(self.val["raw"]) native = struct.unpack(from_bytes, struct.pack(to_bytes, raw))[0] # Print the value and some annotations so that the user isn't misled # about what value they're looking at. return f"{native} (0x{native:x}, from 0x{raw:x})" def build_cruft_dict(): pretty_printers_dict[re.compile('^cruft::point.*$') ] = lambda val: CoordPrinter(val) pretty_printers_dict[re.compile('^cruft::vector.*$')] = lambda val: CoordPrinter(val) pretty_printers_dict[re.compile('^cruft::extent.*$')] = lambda val: CoordPrinter(val) pretty_printers_dict[re.compile('^cruft::colour.*$')] = lambda val: CoordPrinter(val) pretty_printers_dict[re.compile('^cruft::view')] = lambda val: ViewPrinter(val) pretty_printers_dict[re.compile('^cruft::endian::value')] = lambda val: EndianValuePrinter(val) def lookup(val): type = val.type if type.code == gdb.TYPE_CODE_REF: type = type.target() type = type.unqualified().strip_typedefs() typename = type.tag if typename == None: return None for function in pretty_printers_dict: if function.search(typename): return pretty_printers_dict[function](val) return None def register_cruft_printers(): gdb.pretty_printers.append(lookup) pretty_printers_dict = {} build_cruft_dict()