|  | from sys import version_info | 
|  |  | 
|  | import gdb | 
|  |  | 
|  | if version_info[0] >= 3: | 
|  | xrange = range | 
|  |  | 
|  | ZERO_FIELD = "__0" | 
|  | FIRST_FIELD = "__1" | 
|  |  | 
|  |  | 
|  | def unwrap_unique_or_non_null(unique_or_nonnull): | 
|  | # BACKCOMPAT: rust 1.32 | 
|  | # https://github.com/rust-lang/rust/commit/7a0911528058e87d22ea305695f4047572c5e067 | 
|  | # BACKCOMPAT: rust 1.60 | 
|  | # https://github.com/rust-lang/rust/commit/2a91eeac1a2d27dd3de1bf55515d765da20fd86f | 
|  | ptr = unique_or_nonnull["pointer"] | 
|  | return ptr if ptr.type.code == gdb.TYPE_CODE_PTR else ptr[ptr.type.fields()[0]] | 
|  |  | 
|  |  | 
|  | # GDB 14 has a tag class that indicates that extension methods are ok | 
|  | # to call.  Use of this tag only requires that printers hide local | 
|  | # attributes and methods by prefixing them with "_". | 
|  | if hasattr(gdb, "ValuePrinter"): | 
|  | printer_base = gdb.ValuePrinter | 
|  | else: | 
|  | printer_base = object | 
|  |  | 
|  |  | 
|  | class EnumProvider(printer_base): | 
|  | def __init__(self, valobj): | 
|  | content = valobj[valobj.type.fields()[0]] | 
|  | fields = content.type.fields() | 
|  | self._empty = len(fields) == 0 | 
|  | if not self._empty: | 
|  | if len(fields) == 1: | 
|  | discriminant = 0 | 
|  | else: | 
|  | discriminant = int(content[fields[0]]) + 1 | 
|  | self._active_variant = content[fields[discriminant]] | 
|  | self._name = fields[discriminant].name | 
|  | self._full_name = "{}::{}".format(valobj.type.name, self._name) | 
|  | else: | 
|  | self._full_name = valobj.type.name | 
|  |  | 
|  | def to_string(self): | 
|  | return self._full_name | 
|  |  | 
|  | def children(self): | 
|  | if not self._empty: | 
|  | yield self._name, self._active_variant | 
|  |  | 
|  |  | 
|  | class StdStringProvider(printer_base): | 
|  | def __init__(self, valobj): | 
|  | self._valobj = valobj | 
|  | vec = valobj["vec"] | 
|  | self._length = int(vec["len"]) | 
|  | self._data_ptr = unwrap_unique_or_non_null(vec["buf"]["inner"]["ptr"]) | 
|  |  | 
|  | def to_string(self): | 
|  | return self._data_ptr.lazy_string(encoding="utf-8", length=self._length) | 
|  |  | 
|  | @staticmethod | 
|  | def display_hint(): | 
|  | return "string" | 
|  |  | 
|  |  | 
|  | class StdOsStringProvider(printer_base): | 
|  | def __init__(self, valobj): | 
|  | self._valobj = valobj | 
|  | buf = self._valobj["inner"]["inner"] | 
|  | is_windows = "Wtf8Buf" in buf.type.name | 
|  | vec = buf["bytes"] if is_windows else buf | 
|  |  | 
|  | self._length = int(vec["len"]) | 
|  | self._data_ptr = unwrap_unique_or_non_null(vec["buf"]["inner"]["ptr"]) | 
|  |  | 
|  | def to_string(self): | 
|  | return self._data_ptr.lazy_string(encoding="utf-8", length=self._length) | 
|  |  | 
|  | def display_hint(self): | 
|  | return "string" | 
|  |  | 
|  |  | 
|  | class StdStrProvider(printer_base): | 
|  | def __init__(self, valobj): | 
|  | self._valobj = valobj | 
|  | self._length = int(valobj["length"]) | 
|  | self._data_ptr = valobj["data_ptr"] | 
|  |  | 
|  | def to_string(self): | 
|  | return self._data_ptr.lazy_string(encoding="utf-8", length=self._length) | 
|  |  | 
|  | @staticmethod | 
|  | def display_hint(): | 
|  | return "string" | 
|  |  | 
|  |  | 
|  | def _enumerate_array_elements(element_ptrs): | 
|  | for i, element_ptr in enumerate(element_ptrs): | 
|  | key = "[{}]".format(i) | 
|  | element = element_ptr.dereference() | 
|  |  | 
|  | try: | 
|  | # rust-lang/rust#64343: passing deref expr to `str` allows | 
|  | # catching exception on garbage pointer | 
|  | str(element) | 
|  | except RuntimeError: | 
|  | yield key, "inaccessible" | 
|  |  | 
|  | break | 
|  |  | 
|  | yield key, element | 
|  |  | 
|  |  | 
|  | class StdSliceProvider(printer_base): | 
|  | def __init__(self, valobj): | 
|  | self._valobj = valobj | 
|  | self._length = int(valobj["length"]) | 
|  | self._data_ptr = valobj["data_ptr"] | 
|  |  | 
|  | def to_string(self): | 
|  | return "{}(size={})".format(self._valobj.type, self._length) | 
|  |  | 
|  | def children(self): | 
|  | return _enumerate_array_elements( | 
|  | self._data_ptr + index for index in xrange(self._length) | 
|  | ) | 
|  |  | 
|  | @staticmethod | 
|  | def display_hint(): | 
|  | return "array" | 
|  |  | 
|  |  | 
|  | class StdVecProvider(printer_base): | 
|  | def __init__(self, valobj): | 
|  | self._valobj = valobj | 
|  | self._length = int(valobj["len"]) | 
|  | self._data_ptr = unwrap_unique_or_non_null(valobj["buf"]["inner"]["ptr"]) | 
|  | ptr_ty = gdb.Type.pointer(valobj.type.template_argument(0)) | 
|  | self._data_ptr = self._data_ptr.reinterpret_cast(ptr_ty) | 
|  |  | 
|  | def to_string(self): | 
|  | return "Vec(size={})".format(self._length) | 
|  |  | 
|  | def children(self): | 
|  | return _enumerate_array_elements( | 
|  | self._data_ptr + index for index in xrange(self._length) | 
|  | ) | 
|  |  | 
|  | @staticmethod | 
|  | def display_hint(): | 
|  | return "array" | 
|  |  | 
|  |  | 
|  | class StdVecDequeProvider(printer_base): | 
|  | def __init__(self, valobj): | 
|  | self._valobj = valobj | 
|  | self._head = int(valobj["head"]) | 
|  | self._size = int(valobj["len"]) | 
|  | # BACKCOMPAT: rust 1.75 | 
|  | cap = valobj["buf"]["inner"]["cap"] | 
|  | if cap.type.code != gdb.TYPE_CODE_INT: | 
|  | cap = cap[ZERO_FIELD] | 
|  | self._cap = int(cap) | 
|  | self._data_ptr = unwrap_unique_or_non_null(valobj["buf"]["inner"]["ptr"]) | 
|  | ptr_ty = gdb.Type.pointer(valobj.type.template_argument(0)) | 
|  | self._data_ptr = self._data_ptr.reinterpret_cast(ptr_ty) | 
|  |  | 
|  | def to_string(self): | 
|  | return "VecDeque(size={})".format(self._size) | 
|  |  | 
|  | def children(self): | 
|  | return _enumerate_array_elements( | 
|  | (self._data_ptr + ((self._head + index) % self._cap)) | 
|  | for index in xrange(self._size) | 
|  | ) | 
|  |  | 
|  | @staticmethod | 
|  | def display_hint(): | 
|  | return "array" | 
|  |  | 
|  |  | 
|  | class StdRcProvider(printer_base): | 
|  | def __init__(self, valobj, is_atomic=False): | 
|  | self._valobj = valobj | 
|  | self._is_atomic = is_atomic | 
|  | self._ptr = unwrap_unique_or_non_null(valobj["ptr"]) | 
|  | self._value = self._ptr["data" if is_atomic else "value"] | 
|  | self._strong = self._ptr["strong"]["v" if is_atomic else "value"]["value"] | 
|  | self._weak = self._ptr["weak"]["v" if is_atomic else "value"]["value"] - 1 | 
|  |  | 
|  | def to_string(self): | 
|  | if self._is_atomic: | 
|  | return "Arc(strong={}, weak={})".format(int(self._strong), int(self._weak)) | 
|  | else: | 
|  | return "Rc(strong={}, weak={})".format(int(self._strong), int(self._weak)) | 
|  |  | 
|  | def children(self): | 
|  | yield "value", self._value | 
|  | yield "strong", self._strong | 
|  | yield "weak", self._weak | 
|  |  | 
|  |  | 
|  | class StdCellProvider(printer_base): | 
|  | def __init__(self, valobj): | 
|  | self._value = valobj["value"]["value"] | 
|  |  | 
|  | def to_string(self): | 
|  | return "Cell" | 
|  |  | 
|  | def children(self): | 
|  | yield "value", self._value | 
|  |  | 
|  |  | 
|  | class StdRefProvider(printer_base): | 
|  | def __init__(self, valobj): | 
|  | self._value = valobj["value"].dereference() | 
|  | self._borrow = valobj["borrow"]["borrow"]["value"]["value"] | 
|  |  | 
|  | def to_string(self): | 
|  | borrow = int(self._borrow) | 
|  | if borrow >= 0: | 
|  | return "Ref(borrow={})".format(borrow) | 
|  | else: | 
|  | return "Ref(borrow_mut={})".format(-borrow) | 
|  |  | 
|  | def children(self): | 
|  | yield "*value", self._value | 
|  | yield "borrow", self._borrow | 
|  |  | 
|  |  | 
|  | class StdRefCellProvider(printer_base): | 
|  | def __init__(self, valobj): | 
|  | self._value = valobj["value"]["value"] | 
|  | self._borrow = valobj["borrow"]["value"]["value"] | 
|  |  | 
|  | def to_string(self): | 
|  | borrow = int(self._borrow) | 
|  | if borrow >= 0: | 
|  | return "RefCell(borrow={})".format(borrow) | 
|  | else: | 
|  | return "RefCell(borrow_mut={})".format(-borrow) | 
|  |  | 
|  | def children(self): | 
|  | yield "value", self._value | 
|  | yield "borrow", self._borrow | 
|  |  | 
|  |  | 
|  | class StdNonZeroNumberProvider(printer_base): | 
|  | def __init__(self, valobj): | 
|  | fields = valobj.type.fields() | 
|  | assert len(fields) == 1 | 
|  | field = list(fields)[0] | 
|  |  | 
|  | inner_valobj = valobj[field.name] | 
|  |  | 
|  | inner_fields = inner_valobj.type.fields() | 
|  | assert len(inner_fields) == 1 | 
|  | inner_field = list(inner_fields)[0] | 
|  |  | 
|  | self._value = str(inner_valobj[inner_field.name]) | 
|  |  | 
|  | def to_string(self): | 
|  | return self._value | 
|  |  | 
|  |  | 
|  | # Yields children (in a provider's sense of the word) for a BTreeMap. | 
|  | def children_of_btree_map(map): | 
|  | # Yields each key/value pair in the node and in any child nodes. | 
|  | def children_of_node(node_ptr, height): | 
|  | def cast_to_internal(node): | 
|  | internal_type_name = node.type.target().name.replace( | 
|  | "LeafNode", "InternalNode", 1 | 
|  | ) | 
|  | internal_type = gdb.lookup_type(internal_type_name) | 
|  | return node.cast(internal_type.pointer()) | 
|  |  | 
|  | if node_ptr.type.name.startswith("alloc::collections::btree::node::BoxedNode<"): | 
|  | # BACKCOMPAT: rust 1.49 | 
|  | node_ptr = node_ptr["ptr"] | 
|  | node_ptr = unwrap_unique_or_non_null(node_ptr) | 
|  | leaf = node_ptr.dereference() | 
|  | keys = leaf["keys"] | 
|  | vals = leaf["vals"] | 
|  | edges = cast_to_internal(node_ptr)["edges"] if height > 0 else None | 
|  | length = leaf["len"] | 
|  |  | 
|  | for i in xrange(0, length + 1): | 
|  | if height > 0: | 
|  | child_ptr = edges[i]["value"]["value"] | 
|  | for child in children_of_node(child_ptr, height - 1): | 
|  | yield child | 
|  | if i < length: | 
|  | # Avoid "Cannot perform pointer math on incomplete type" on zero-sized arrays. | 
|  | key_type_size = keys.type.sizeof | 
|  | val_type_size = vals.type.sizeof | 
|  | key = ( | 
|  | keys[i]["value"]["value"] | 
|  | if key_type_size > 0 | 
|  | else gdb.parse_and_eval("()") | 
|  | ) | 
|  | val = ( | 
|  | vals[i]["value"]["value"] | 
|  | if val_type_size > 0 | 
|  | else gdb.parse_and_eval("()") | 
|  | ) | 
|  | yield key, val | 
|  |  | 
|  | if map["length"] > 0: | 
|  | root = map["root"] | 
|  | if root.type.name.startswith("core::option::Option<"): | 
|  | root = root.cast(gdb.lookup_type(root.type.name[21:-1])) | 
|  | node_ptr = root["node"] | 
|  | height = root["height"] | 
|  | for child in children_of_node(node_ptr, height): | 
|  | yield child | 
|  |  | 
|  |  | 
|  | class StdBTreeSetProvider(printer_base): | 
|  | def __init__(self, valobj): | 
|  | self._valobj = valobj | 
|  |  | 
|  | def to_string(self): | 
|  | return "BTreeSet(size={})".format(self._valobj["map"]["length"]) | 
|  |  | 
|  | def children(self): | 
|  | inner_map = self._valobj["map"] | 
|  | for i, (child, _) in enumerate(children_of_btree_map(inner_map)): | 
|  | yield "[{}]".format(i), child | 
|  |  | 
|  | @staticmethod | 
|  | def display_hint(): | 
|  | return "array" | 
|  |  | 
|  |  | 
|  | class StdBTreeMapProvider(printer_base): | 
|  | def __init__(self, valobj): | 
|  | self._valobj = valobj | 
|  |  | 
|  | def to_string(self): | 
|  | return "BTreeMap(size={})".format(self._valobj["length"]) | 
|  |  | 
|  | def children(self): | 
|  | for i, (key, val) in enumerate(children_of_btree_map(self._valobj)): | 
|  | yield "key{}".format(i), key | 
|  | yield "val{}".format(i), val | 
|  |  | 
|  | @staticmethod | 
|  | def display_hint(): | 
|  | return "map" | 
|  |  | 
|  |  | 
|  | # BACKCOMPAT: rust 1.35 | 
|  | class StdOldHashMapProvider(printer_base): | 
|  | def __init__(self, valobj, show_values=True): | 
|  | self._valobj = valobj | 
|  | self._show_values = show_values | 
|  |  | 
|  | self._table = self._valobj["table"] | 
|  | self._size = int(self._table["size"]) | 
|  | self._hashes = self._table["hashes"] | 
|  | self._hash_uint_type = self._hashes.type | 
|  | self._hash_uint_size = self._hashes.type.sizeof | 
|  | self._modulo = 2**self._hash_uint_size | 
|  | self._data_ptr = self._hashes[ZERO_FIELD]["pointer"] | 
|  |  | 
|  | self._capacity_mask = int(self._table["capacity_mask"]) | 
|  | self._capacity = (self._capacity_mask + 1) % self._modulo | 
|  |  | 
|  | marker = self._table["marker"].type | 
|  | self._pair_type = marker.template_argument(0) | 
|  | self._pair_type_size = self._pair_type.sizeof | 
|  |  | 
|  | self._valid_indices = [] | 
|  | for idx in range(self._capacity): | 
|  | data_ptr = self._data_ptr.cast(self._hash_uint_type.pointer()) | 
|  | address = data_ptr + idx | 
|  | hash_uint = address.dereference() | 
|  | hash_ptr = hash_uint[ZERO_FIELD]["pointer"] | 
|  | if int(hash_ptr) != 0: | 
|  | self._valid_indices.append(idx) | 
|  |  | 
|  | def to_string(self): | 
|  | if self._show_values: | 
|  | return "HashMap(size={})".format(self._size) | 
|  | else: | 
|  | return "HashSet(size={})".format(self._size) | 
|  |  | 
|  | def children(self): | 
|  | start = int(self._data_ptr) & ~1 | 
|  |  | 
|  | hashes = self._hash_uint_size * self._capacity | 
|  | align = self._pair_type_size | 
|  | len_rounded_up = ( | 
|  | ( | 
|  | (((hashes + align) % self._modulo - 1) % self._modulo) | 
|  | & ~((align - 1) % self._modulo) | 
|  | ) | 
|  | % self._modulo | 
|  | - hashes | 
|  | ) % self._modulo | 
|  |  | 
|  | pairs_offset = hashes + len_rounded_up | 
|  | pairs_start = gdb.Value(start + pairs_offset).cast(self._pair_type.pointer()) | 
|  |  | 
|  | for index in range(self._size): | 
|  | table_index = self._valid_indices[index] | 
|  | idx = table_index & self._capacity_mask | 
|  | element = (pairs_start + idx).dereference() | 
|  | if self._show_values: | 
|  | yield "key{}".format(index), element[ZERO_FIELD] | 
|  | yield "val{}".format(index), element[FIRST_FIELD] | 
|  | else: | 
|  | yield "[{}]".format(index), element[ZERO_FIELD] | 
|  |  | 
|  | def display_hint(self): | 
|  | return "map" if self._show_values else "array" | 
|  |  | 
|  |  | 
|  | class StdHashMapProvider(printer_base): | 
|  | def __init__(self, valobj, show_values=True): | 
|  | self._valobj = valobj | 
|  | self._show_values = show_values | 
|  |  | 
|  | table = self._table() | 
|  | table_inner = table["table"] | 
|  | capacity = int(table_inner["bucket_mask"]) + 1 | 
|  | ctrl = table_inner["ctrl"]["pointer"] | 
|  |  | 
|  | self._size = int(table_inner["items"]) | 
|  | self._pair_type = table.type.template_argument(0).strip_typedefs() | 
|  |  | 
|  | self._new_layout = not table_inner.type.has_key("data") | 
|  | if self._new_layout: | 
|  | self._data_ptr = ctrl.cast(self._pair_type.pointer()) | 
|  | else: | 
|  | self._data_ptr = table_inner["data"]["pointer"] | 
|  |  | 
|  | self._valid_indices = [] | 
|  | for idx in range(capacity): | 
|  | address = ctrl + idx | 
|  | value = address.dereference() | 
|  | is_presented = value & 128 == 0 | 
|  | if is_presented: | 
|  | self._valid_indices.append(idx) | 
|  |  | 
|  | def _table(self): | 
|  | if self._show_values: | 
|  | hashbrown_hashmap = self._valobj["base"] | 
|  | elif self._valobj.type.fields()[0].name == "map": | 
|  | # BACKCOMPAT: rust 1.47 | 
|  | # HashSet wraps std::collections::HashMap, which wraps hashbrown::HashMap | 
|  | hashbrown_hashmap = self._valobj["map"]["base"] | 
|  | else: | 
|  | # HashSet wraps hashbrown::HashSet, which wraps hashbrown::HashMap | 
|  | hashbrown_hashmap = self._valobj["base"]["map"] | 
|  | return hashbrown_hashmap["table"] | 
|  |  | 
|  | def to_string(self): | 
|  | if self._show_values: | 
|  | return "HashMap(size={})".format(self._size) | 
|  | else: | 
|  | return "HashSet(size={})".format(self._size) | 
|  |  | 
|  | def children(self): | 
|  | pairs_start = self._data_ptr | 
|  |  | 
|  | for index in range(self._size): | 
|  | idx = self._valid_indices[index] | 
|  | if self._new_layout: | 
|  | idx = -(idx + 1) | 
|  | element = (pairs_start + idx).dereference() | 
|  | if self._show_values: | 
|  | yield "key{}".format(index), element[ZERO_FIELD] | 
|  | yield "val{}".format(index), element[FIRST_FIELD] | 
|  | else: | 
|  | yield "[{}]".format(index), element[ZERO_FIELD] | 
|  |  | 
|  | def display_hint(self): | 
|  | return "map" if self._show_values else "array" |