summaryrefslogtreecommitdiffstats
path: root/src/etc/gdb_providers.py
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
commit698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch)
tree173a775858bd501c378080a10dca74132f05bc50 /src/etc/gdb_providers.py
parentInitial commit. (diff)
downloadrustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz
rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/etc/gdb_providers.py')
-rw-r--r--src/etc/gdb_providers.py431
1 files changed, 431 insertions, 0 deletions
diff --git a/src/etc/gdb_providers.py b/src/etc/gdb_providers.py
new file mode 100644
index 000000000..0a52b8c97
--- /dev/null
+++ b/src/etc/gdb_providers.py
@@ -0,0 +1,431 @@
+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]]
+
+
+class EnumProvider:
+ 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:
+ 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"]["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:
+ def __init__(self, valobj):
+ self.valobj = valobj
+ buf = self.valobj["inner"]["inner"]
+ is_windows = "Wtf8Buf" in buf.type.name
+ vec = buf[ZERO_FIELD] if is_windows else buf
+
+ self.length = int(vec["len"])
+ self.data_ptr = unwrap_unique_or_non_null(vec["buf"]["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:
+ 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:
+ 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:
+ def __init__(self, valobj):
+ self.valobj = valobj
+ self.length = int(valobj["len"])
+ self.data_ptr = unwrap_unique_or_non_null(valobj["buf"]["ptr"])
+
+ 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:
+ def __init__(self, valobj):
+ self.valobj = valobj
+ self.head = int(valobj["head"])
+ self.tail = int(valobj["tail"])
+ self.cap = int(valobj["buf"]["cap"])
+ self.data_ptr = unwrap_unique_or_non_null(valobj["buf"]["ptr"])
+ if self.head >= self.tail:
+ self.size = self.head - self.tail
+ else:
+ self.size = self.cap + self.head - self.tail
+
+ def to_string(self):
+ return "VecDeque(size={})".format(self.size)
+
+ def children(self):
+ return _enumerate_array_elements(
+ (self.data_ptr + ((self.tail + index) % self.cap)) for index in xrange(self.size)
+ )
+
+ @staticmethod
+ def display_hint():
+ return "array"
+
+
+class StdRcProvider:
+ 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:
+ def __init__(self, valobj):
+ self.value = valobj["value"]["value"]
+
+ def to_string(self):
+ return "Cell"
+
+ def children(self):
+ yield "value", self.value
+
+
+class StdRefProvider:
+ 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:
+ 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
+
+
+# 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:
+ 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:
+ 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:
+ 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:
+ 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"