import sys sys.path.insert(0, '/usr/share/gdb/python/') import gdb.printing def _base_cast(val): for field in val.type.strip_typedefs().fields(): if getattr(field, 'is_base_class', False): return val.cast(field.type) return None def _member(val, name): """Find a member by name on a value, searching base classes if needed.""" current = val while current is not None: t = current.type.strip_typedefs() for field in t.fields(): if field.name == name: return current[name] current = _base_cast(current) raise gdb.error(f"Member '{name}' not found on {val.type}") class ArrayPrinter: def __init__(self, val): self.val = val def to_string(self): return f"Array(size={int(self.val['arraySize'])})" def children(self): data = self.val['_data'] size = int(self.val['arraySize']) allocated = int(self.val['allocated']) yield f"[size]", size yield f"[allocated]", allocated for i in range(size): elem_val = (data + i).dereference() yield f"[{i}]", elem_val def display_hint(self): return "array" class ListPrinter: def __init__(self, val): self.val = val def to_string(self): size = int(_member(self.val, '_size')) return f"List(size={size})" def children(self): size = int(_member(self.val, '_size')) root = _member(self.val, 'root') tail = _member(self.val, 'tail') yield "[size]", size node = root idx = 0 # Bound traversal by logical size to avoid walking corrupted links forever. while idx < size and node != tail: yield f"[{idx}]", node['data'] node = node['next'] idx += 1 def display_hint(self): return "array" class MapPrinter: def __init__(self, val): self.val = val def to_string(self): size = int(_member(self.val, '_size')) return f"Map(size={size})" def children(self): size = int(_member(self.val, '_size')) root = _member(self.val, 'root') stack = [] node = root idx = 0 # In-order traversal of Tree nodes yields map entries sorted by key. while (node or stack) and idx < size: while node: stack.append(node) node = node['leftChild'] node = stack.pop() pair = node['data'] yield f"[{idx}].key", pair['key'] yield f"[{idx}].value", pair['value'] idx += 1 node = node['rightChild'] def display_hint(self): return "map" class VectorPrinter: def __init__(self, val): self.val = val t = val.type.strip_typedefs() self.length = int(t.template_argument(0)) self.value_type = t.template_argument(1) def to_string(self): comps = [float(self.val['x']), float(self.val['y'])] if self.length >= 3: comps.append(float(self.val['z'])) if self.length == 4: comps.append(float(self.val['w'])) return "(" + ", ".join(map(str, comps)) + ")" def display_hint(self): return "string" def _children(self): comps = {'x': self.val['x'], 'y': self.val['y']} if self.length >= 3: comps['z'] = self.val['z'] if self.length == 4: comps['w'] = self.val['w'] for key, value in comps.items(): yield key, value def build_pretty_printer(): pp = gdb.printing.RegexpCollectionPrettyPrinter("Seele") pp.add_printer("Array", r'^Seele::Array<.*>$', ArrayPrinter) pp.add_printer("List", r'^Seele::List<.*>$', ListPrinter) pp.add_printer("Map", r'^Seele::Map<.*>$', MapPrinter) pp.add_printer("Vector", r"^glm::(detail::)?t?vec(\d)?<[^<>]*>$", VectorPrinter) return pp gdb.printing.register_pretty_printer(gdb.current_objfile(), build_pretty_printer())