diff --git a/phmap_gdb.py b/phmap_gdb.py new file mode 100644 index 0000000..344fcde --- /dev/null +++ b/phmap_gdb.py @@ -0,0 +1,201 @@ +# Python GDB formatters for parallel-hashmap +# tested with GCC 10.2 / GDB 9.2 +# to install it, ensure the script location is in the Python path +# and type the following command (or put it in $HOME/.gdbinit): + +# python +# import phmap_gdb +# end + + +import gdb.printing + + +def counter(): + i = 0 + while(True): + yield str(i) + i += 1 + + +def slot_iterator(base_obj): + index = -1 + n_items = 0 + size = int(base_obj["size_"]) + while n_items < size: + index += 1 + if int(base_obj["ctrl_"][index]) < 0: + continue + + n_items += 1 + yield base_obj["slots_"][index] + + +def parallel_slot_iterator(base_obj): + array = base_obj["sets_"] + array_len = int(array.type.template_argument(1)) + for index in range(array_len): + obj = array["_M_elems"][index]["set_"] + yield from slot_iterator(obj) + + +def flat_map_iterator(name, item): + yield (next(name), item["value"]["first"]) + yield (next(name), item["value"]["second"]) + + +def flat_set_iterator(name, item): + yield (next(name), item) + + +def node_map_iterator(name, item): + yield (next(name), item.dereference()["first"]) + yield (next(name), item.dereference()["second"]) + + +def node_set_iterator(name, item): + yield (next(name), item.dereference()) + + +def traverse(iterator, slot_type_iterator): + name = counter() + for item in iterator: + yield from slot_type_iterator(name, item) + + +def parallel_size(parallel_hash_obj): + array = parallel_hash_obj["sets_"] + array_len = int(array.type.template_argument(1)) + size = 0 + for index in range(array_len): + size += array["_M_elems"][index]["set_"]["size_"] + + return size + + +class FlatMapPrinter: + def __init__(self, val): + self.val = val + + def children(self): + return traverse(slot_iterator(self.val), flat_map_iterator) + + def to_string(self): + return f"phmap::flat_hash_map with {int(self.val['size_'])} elements" + + def display_hint(self): + return "map" + + +class FlatSetPrinter: + def __init__(self, val): + self.val = val + + def children(self): + return traverse(slot_iterator(self.val), flat_set_iterator) + + def to_string(self): + return f"phmap::flat_hash_set with {int(self.val['size_'])} elements" + + def display_hint(self): + return "array" + + +class NodeMapPrinter: + def __init__(self, val): + self.val = val + + def children(self): + return traverse(slot_iterator(self.val), node_map_iterator) + + def to_string(self): + return f"phmap::node_hash_map with {int(self.val['size_'])} elements" + + def display_hint(self): + return "map" + + +class NodeSetPrinter: + def __init__(self, val): + self.val = val + + def children(self): + return traverse(slot_iterator(self.val), node_set_iterator) + + def to_string(self): + return f"phmap::node_hash_set with {int(self.val['size_'])} elements" + + def display_hint(self): + return "array" + + +class ParallelFlatMapPrinter: + def __init__(self, val): + self.val = val + + def children(self): + return traverse(parallel_slot_iterator(self.val), flat_map_iterator) + + def to_string(self): + return f"phmap::parallel_flat_hash_map with {parallel_size(self.val)} elements" + + def display_hint(self): + return "map" + + +class ParallelFlatSetPrinter: + def __init__(self, val): + self.val = val + + def children(self): + return traverse(parallel_slot_iterator(self.val), flat_set_iterator) + + def to_string(self): + return f"phmap::parallel_flat_hash_set with {parallel_size(self.val)} elements" + + def display_hint(self): + return "array" + + +class ParallelNodeMapPrinter: + def __init__(self, val): + self.val = val + + def children(self): + return traverse(parallel_slot_iterator(self.val), node_map_iterator) + + def to_string(self): + return f"phmap::parallel_node_hash_map with {parallel_size(self.val)} elements" + + def display_hint(self): + return "map" + + +class ParallelNodeSetPrinter: + def __init__(self, val): + self.val = val + + def children(self): + return traverse(parallel_slot_iterator(self.val), node_set_iterator) + + def to_string(self): + return f"phmap::parallel_node_hash_set with {parallel_size(self.val)} elements" + + def display_hint(self): + return "array" + + +def build_pretty_printer(): + pp = gdb.printing.RegexpCollectionPrettyPrinter("phmap") + pp.add_printer('flat_hash_map', '^phmap::flat_hash_map<.*>$', FlatMapPrinter) + pp.add_printer('flat_hash_set', '^phmap::flat_hash_set<.*>$', FlatSetPrinter) + pp.add_printer('node_hash_map', '^phmap::node_hash_map<.*>$', NodeMapPrinter) + pp.add_printer('node_hash_set', '^phmap::node_hash_set<.*>$', NodeSetPrinter) + pp.add_printer('parallel_flat_hash_map', '^phmap::parallel_flat_hash_map<.*>$', ParallelFlatMapPrinter) + pp.add_printer('parallel_flat_hash_set', '^phmap::parallel_flat_hash_set<.*>$', ParallelFlatSetPrinter) + pp.add_printer('parallel_node_hash_map', '^phmap::parallel_node_hash_map<.*>$', ParallelNodeMapPrinter) + pp.add_printer('parallel_node_hash_set', '^phmap::parallel_node_hash_set<.*>$', ParallelNodeSetPrinter) + return pp + + +gdb.printing.register_pretty_printer(gdb.current_objfile(), build_pretty_printer())