1import gdb 2import gdb.printing 3import re 4 5from gdb_providers import * 6from rust_types import * 7 8 9_gdb_version_matched = re.search('([0-9]+)\\.([0-9]+)', gdb.VERSION) 10gdb_version = [int(num) for num in _gdb_version_matched.groups()] if _gdb_version_matched else [] 11 12def register_printers(objfile): 13 objfile.pretty_printers.append(printer) 14 15 16# BACKCOMPAT: rust 1.35 17def is_hashbrown_hashmap(hash_map): 18 return len(hash_map.type.fields()) == 1 19 20 21def classify_rust_type(type): 22 type_class = type.code 23 if type_class == gdb.TYPE_CODE_STRUCT: 24 return classify_struct(type.tag, type.fields()) 25 if type_class == gdb.TYPE_CODE_UNION: 26 return classify_union(type.fields()) 27 28 return RustType.OTHER 29 30 31def check_enum_discriminant(valobj): 32 content = valobj[valobj.type.fields()[0]] 33 fields = content.type.fields() 34 if len(fields) > 1: 35 discriminant = int(content[fields[0]]) + 1 36 if discriminant > len(fields): 37 # invalid discriminant 38 return False 39 return True 40 41 42# Helper for enum printing that checks the discriminant. Only used in 43# older gdb. 44def enum_provider(valobj): 45 if check_enum_discriminant(valobj): 46 return EnumProvider(valobj) 47 return None 48 49 50# Helper to handle both old and new hash maps. 51def hashmap_provider(valobj): 52 if is_hashbrown_hashmap(valobj): 53 return StdHashMapProvider(valobj) 54 else: 55 return StdOldHashMapProvider(valobj) 56 57 58# Helper to handle both old and new hash sets. 59def hashset_provider(valobj): 60 hash_map = valobj[valobj.type.fields()[0]] 61 if is_hashbrown_hashmap(hash_map): 62 return StdHashMapProvider(valobj, show_values=False) 63 else: 64 return StdOldHashMapProvider(hash_map, show_values=False) 65 66 67class PrintByRustType(gdb.printing.SubPrettyPrinter): 68 def __init__(self, name, provider): 69 super(PrintByRustType, self).__init__(name) 70 self.provider = provider 71 72 def __call__(self, val): 73 if self.enabled: 74 return self.provider(val) 75 return None 76 77 78class RustPrettyPrinter(gdb.printing.PrettyPrinter): 79 def __init__(self, name): 80 super(RustPrettyPrinter, self).__init__(name, []) 81 self.type_map = {} 82 83 def add(self, rust_type, provider): 84 # Just use the rust_type as the name. 85 printer = PrintByRustType(rust_type, provider) 86 self.type_map[rust_type] = printer 87 self.subprinters.append(printer) 88 89 def __call__(self, valobj): 90 rust_type = classify_rust_type(valobj.type) 91 if rust_type in self.type_map: 92 return self.type_map[rust_type](valobj) 93 return None 94 95 96printer = RustPrettyPrinter("rust") 97# use enum provider only for GDB <7.12 98if gdb_version[0] < 7 or (gdb_version[0] == 7 and gdb_version[1] < 12): 99 printer.add(RustType.ENUM, enum_provider) 100printer.add(RustType.STD_STRING, StdStringProvider) 101printer.add(RustType.STD_OS_STRING, StdOsStringProvider) 102printer.add(RustType.STD_STR, StdStrProvider) 103printer.add(RustType.STD_SLICE, StdSliceProvider) 104printer.add(RustType.STD_VEC, StdVecProvider) 105printer.add(RustType.STD_VEC_DEQUE, StdVecDequeProvider) 106printer.add(RustType.STD_BTREE_SET, StdBTreeSetProvider) 107printer.add(RustType.STD_BTREE_MAP, StdBTreeMapProvider) 108printer.add(RustType.STD_HASH_MAP, hashmap_provider) 109printer.add(RustType.STD_HASH_SET, hashset_provider) 110printer.add(RustType.STD_RC, StdRcProvider) 111printer.add(RustType.STD_ARC, lambda valobj: StdRcProvider(valobj, is_atomic=True)) 112 113printer.add(RustType.STD_CELL, StdCellProvider) 114printer.add(RustType.STD_REF, StdRefProvider) 115printer.add(RustType.STD_REF_MUT, StdRefProvider) 116printer.add(RustType.STD_REF_CELL, StdRefCellProvider) 117 118printer.add(RustType.STD_NONZERO_NUMBER, StdNonZeroNumberProvider) 119