import gdb import gdb.printing import re from gdb_providers import * from rust_types import * _gdb_version_matched = re.search('([0-9]+)\\.([0-9]+)', gdb.VERSION) gdb_version = [int(num) for num in _gdb_version_matched.groups()] if _gdb_version_matched else [] def register_printers(objfile): objfile.pretty_printers.append(printer) # BACKCOMPAT: rust 1.35 def is_hashbrown_hashmap(hash_map): return len(hash_map.type.fields()) == 1 def classify_rust_type(type): type_class = type.code if type_class == gdb.TYPE_CODE_STRUCT: return classify_struct(type.tag, type.fields()) if type_class == gdb.TYPE_CODE_UNION: return classify_union(type.fields()) return RustType.OTHER def check_enum_discriminant(valobj): content = valobj[valobj.type.fields()[0]] fields = content.type.fields() if len(fields) > 1: discriminant = int(content[fields[0]]) + 1 if discriminant > len(fields): # invalid discriminant return False return True # Helper for enum printing that checks the discriminant. Only used in # older gdb. def enum_provider(valobj): if check_enum_discriminant(valobj): return EnumProvider(valobj) return None # Helper to handle both old and new hash maps. def hashmap_provider(valobj): if is_hashbrown_hashmap(valobj): return StdHashMapProvider(valobj) else: return StdOldHashMapProvider(valobj) # Helper to handle both old and new hash sets. def hashset_provider(valobj): hash_map = valobj[valobj.type.fields()[0]] if is_hashbrown_hashmap(hash_map): return StdHashMapProvider(valobj, show_values=False) else: return StdOldHashMapProvider(hash_map, show_values=False) class PrintByRustType(gdb.printing.SubPrettyPrinter): def __init__(self, name, provider): super(PrintByRustType, self).__init__(name) self.provider = provider def __call__(self, val): if self.enabled: return self.provider(val) return None class RustPrettyPrinter(gdb.printing.PrettyPrinter): def __init__(self, name): super(RustPrettyPrinter, self).__init__(name, []) self.type_map = {} def add(self, rust_type, provider): # Just use the rust_type as the name. printer = PrintByRustType(rust_type, provider) self.type_map[rust_type] = printer self.subprinters.append(printer) def __call__(self, valobj): rust_type = classify_rust_type(valobj.type) if rust_type in self.type_map: return self.type_map[rust_type](valobj) return None printer = RustPrettyPrinter("rust") # use enum provider only for GDB <7.12 if gdb_version[0] < 7 or (gdb_version[0] == 7 and gdb_version[1] < 12): printer.add(RustType.ENUM, enum_provider) printer.add(RustType.STD_STRING, StdStringProvider) printer.add(RustType.STD_OS_STRING, StdOsStringProvider) printer.add(RustType.STD_STR, StdStrProvider) printer.add(RustType.STD_SLICE, StdSliceProvider) printer.add(RustType.STD_VEC, StdVecProvider) printer.add(RustType.STD_VEC_DEQUE, StdVecDequeProvider) printer.add(RustType.STD_BTREE_SET, StdBTreeSetProvider) printer.add(RustType.STD_BTREE_MAP, StdBTreeMapProvider) printer.add(RustType.STD_HASH_MAP, hashmap_provider) printer.add(RustType.STD_HASH_SET, hashset_provider) printer.add(RustType.STD_RC, StdRcProvider) printer.add(RustType.STD_ARC, lambda valobj: StdRcProvider(valobj, is_atomic=True)) printer.add(RustType.STD_CELL, StdCellProvider) printer.add(RustType.STD_REF, StdRefProvider) printer.add(RustType.STD_REF_MUT, StdRefProvider) printer.add(RustType.STD_REF_CELL, StdRefCellProvider) printer.add(RustType.STD_NONZERO_NUMBER, StdNonZeroNumberProvider)