1 from sys import version_info
5 if version_info[0] >= 3:
12 def unwrap_unique_or_non_null(unique_or_nonnull):
13 # BACKCOMPAT: rust 1.32
14 # https://github.com/rust-lang/rust/commit/7a0911528058e87d22ea305695f4047572c5e067
15 ptr = unique_or_nonnull["pointer"]
16 return ptr if ptr.type.code == gdb.TYPE_CODE_PTR else ptr[ZERO_FIELD]
20 def __init__(self, valobj):
21 content = valobj[valobj.type.fields()[0]]
22 fields = content.type.fields()
23 self.empty = len(fields) == 0
28 discriminant = int(content[fields[0]]) + 1
29 self.active_variant = content[fields[discriminant]]
30 self.name = fields[discriminant].name
31 self.full_name = "{}::{}".format(valobj.type.name, self.name)
33 self.full_name = valobj.type.name
40 yield self.name, self.active_variant
43 class StdStringProvider:
44 def __init__(self, valobj):
47 self.length = int(vec["len"])
48 self.data_ptr = unwrap_unique_or_non_null(vec["buf"]["ptr"])
51 return self.data_ptr.lazy_string(encoding="utf-8", length=self.length)
58 class StdOsStringProvider:
59 def __init__(self, valobj):
61 buf = self.valobj["inner"]["inner"]
62 is_windows = "Wtf8Buf" in buf.type.name
63 vec = buf[ZERO_FIELD] if is_windows else buf
65 self.length = int(vec["len"])
66 self.data_ptr = unwrap_unique_or_non_null(vec["buf"]["ptr"])
69 return self.data_ptr.lazy_string(encoding="utf-8", length=self.length)
71 def display_hint(self):
76 def __init__(self, valobj):
78 self.length = int(valobj["length"])
79 self.data_ptr = valobj["data_ptr"]
82 return self.data_ptr.lazy_string(encoding="utf-8", length=self.length)
90 def __init__(self, valobj):
92 self.length = int(valobj["len"])
93 self.data_ptr = unwrap_unique_or_non_null(valobj["buf"]["ptr"])
96 return "Vec(size={})".format(self.length)
99 saw_inaccessible = False
100 for index in xrange(self.length):
101 element_ptr = self.data_ptr + index
105 # rust-lang/rust#64343: passing deref expr to `str` allows
106 # catching exception on garbage pointer
107 str(element_ptr.dereference())
108 yield "[{}]".format(index), element_ptr.dereference()
110 saw_inaccessible = True
111 yield str(index), "inaccessible"
118 class StdVecDequeProvider:
119 def __init__(self, valobj):
121 self.head = int(valobj["head"])
122 self.tail = int(valobj["tail"])
123 self.cap = int(valobj["buf"]["cap"])
124 self.data_ptr = unwrap_unique_or_non_null(valobj["buf"]["ptr"])
125 if self.head >= self.tail:
126 self.size = self.head - self.tail
128 self.size = self.cap + self.head - self.tail
131 return "VecDeque(size={})".format(self.size)
134 for index in xrange(0, self.size):
135 value = (self.data_ptr + ((self.tail + index) % self.cap)).dereference()
136 yield "[{}]".format(index), value
144 def __init__(self, valobj, is_atomic=False):
146 self.is_atomic = is_atomic
147 self.ptr = unwrap_unique_or_non_null(valobj["ptr"])
148 self.value = self.ptr["data" if is_atomic else "value"]
149 self.strong = self.ptr["strong"]["v" if is_atomic else "value"]["value"]
150 self.weak = self.ptr["weak"]["v" if is_atomic else "value"]["value"] - 1
154 return "Arc(strong={}, weak={})".format(int(self.strong), int(self.weak))
156 return "Rc(strong={}, weak={})".format(int(self.strong), int(self.weak))
159 yield "value", self.value
160 yield "strong", self.strong
161 yield "weak", self.weak
164 class StdCellProvider:
165 def __init__(self, valobj):
166 self.value = valobj["value"]["value"]
172 yield "value", self.value
175 class StdRefProvider:
176 def __init__(self, valobj):
177 self.value = valobj["value"].dereference()
178 self.borrow = valobj["borrow"]["borrow"]["value"]["value"]
181 borrow = int(self.borrow)
183 return "Ref(borrow={})".format(borrow)
185 return "Ref(borrow_mut={})".format(-borrow)
188 yield "*value", self.value
189 yield "borrow", self.borrow
192 class StdRefCellProvider:
193 def __init__(self, valobj):
194 self.value = valobj["value"]["value"]
195 self.borrow = valobj["borrow"]["value"]["value"]
198 borrow = int(self.borrow)
200 return "RefCell(borrow={})".format(borrow)
202 return "RefCell(borrow_mut={})".format(-borrow)
205 yield "value", self.value
206 yield "borrow", self.borrow
209 # Yields children (in a provider's sense of the word) for a BTreeMap.
210 def children_of_btree_map(map):
211 # Yields each key/value pair in the node and in any child nodes.
212 def children_of_node(node_ptr, height):
213 def cast_to_internal(node):
214 internal_type_name = node.type.target().name.replace("LeafNode", "InternalNode", 1)
215 internal_type = gdb.lookup_type(internal_type_name)
216 return node.cast(internal_type.pointer())
218 if node_ptr.type.name.startswith("alloc::collections::btree::node::BoxedNode<"):
219 # BACKCOMPAT: rust 1.49
220 node_ptr = node_ptr["ptr"]
221 node_ptr = unwrap_unique_or_non_null(node_ptr)
222 leaf = node_ptr.dereference()
225 edges = cast_to_internal(node_ptr)["edges"] if height > 0 else None
228 for i in xrange(0, length + 1):
230 child_ptr = edges[i]["value"]["value"]
231 for child in children_of_node(child_ptr, height - 1):
234 # Avoid "Cannot perform pointer math on incomplete type" on zero-sized arrays.
235 key_type_size = keys.type.sizeof
236 val_type_size = vals.type.sizeof
237 key = keys[i]["value"]["value"] if key_type_size > 0 else gdb.parse_and_eval("()")
238 val = vals[i]["value"]["value"] if val_type_size > 0 else gdb.parse_and_eval("()")
241 if map["length"] > 0:
243 if root.type.name.startswith("core::option::Option<"):
244 root = root.cast(gdb.lookup_type(root.type.name[21:-1]))
245 node_ptr = root["node"]
246 height = root["height"]
247 for child in children_of_node(node_ptr, height):
251 class StdBTreeSetProvider:
252 def __init__(self, valobj):
256 return "BTreeSet(size={})".format(self.valobj["map"]["length"])
259 inner_map = self.valobj["map"]
260 for i, (child, _) in enumerate(children_of_btree_map(inner_map)):
261 yield "[{}]".format(i), child
268 class StdBTreeMapProvider:
269 def __init__(self, valobj):
273 return "BTreeMap(size={})".format(self.valobj["length"])
276 for i, (key, val) in enumerate(children_of_btree_map(self.valobj)):
277 yield "key{}".format(i), key
278 yield "val{}".format(i), val
285 # BACKCOMPAT: rust 1.35
286 class StdOldHashMapProvider:
287 def __init__(self, valobj, show_values=True):
289 self.show_values = show_values
291 self.table = self.valobj["table"]
292 self.size = int(self.table["size"])
293 self.hashes = self.table["hashes"]
294 self.hash_uint_type = self.hashes.type
295 self.hash_uint_size = self.hashes.type.sizeof
296 self.modulo = 2 ** self.hash_uint_size
297 self.data_ptr = self.hashes[ZERO_FIELD]["pointer"]
299 self.capacity_mask = int(self.table["capacity_mask"])
300 self.capacity = (self.capacity_mask + 1) % self.modulo
302 marker = self.table["marker"].type
303 self.pair_type = marker.template_argument(0)
304 self.pair_type_size = self.pair_type.sizeof
306 self.valid_indices = []
307 for idx in range(self.capacity):
308 data_ptr = self.data_ptr.cast(self.hash_uint_type.pointer())
309 address = data_ptr + idx
310 hash_uint = address.dereference()
311 hash_ptr = hash_uint[ZERO_FIELD]["pointer"]
312 if int(hash_ptr) != 0:
313 self.valid_indices.append(idx)
317 return "HashMap(size={})".format(self.size)
319 return "HashSet(size={})".format(self.size)
322 start = int(self.data_ptr) & ~1
324 hashes = self.hash_uint_size * self.capacity
325 align = self.pair_type_size
326 len_rounded_up = (((((hashes + align) % self.modulo - 1) % self.modulo) & ~(
327 (align - 1) % self.modulo)) % self.modulo - hashes) % self.modulo
329 pairs_offset = hashes + len_rounded_up
330 pairs_start = gdb.Value(start + pairs_offset).cast(self.pair_type.pointer())
332 for index in range(self.size):
333 table_index = self.valid_indices[index]
334 idx = table_index & self.capacity_mask
335 element = (pairs_start + idx).dereference()
337 yield "key{}".format(index), element[ZERO_FIELD]
338 yield "val{}".format(index), element[FIRST_FIELD]
340 yield "[{}]".format(index), element[ZERO_FIELD]
342 def display_hint(self):
343 return "map" if self.show_values else "array"
346 class StdHashMapProvider:
347 def __init__(self, valobj, show_values=True):
349 self.show_values = show_values
352 table_inner = table["table"]
353 capacity = int(table_inner["bucket_mask"]) + 1
354 ctrl = table_inner["ctrl"]["pointer"]
356 self.size = int(table_inner["items"])
357 self.pair_type = table.type.template_argument(0).strip_typedefs()
359 self.new_layout = not table_inner.type.has_key("data")
361 self.data_ptr = ctrl.cast(self.pair_type.pointer())
363 self.data_ptr = table_inner["data"]["pointer"]
365 self.valid_indices = []
366 for idx in range(capacity):
368 value = address.dereference()
369 is_presented = value & 128 == 0
371 self.valid_indices.append(idx)
375 hashbrown_hashmap = self.valobj["base"]
376 elif self.valobj.type.fields()[0].name == "map":
377 # BACKCOMPAT: rust 1.47
378 # HashSet wraps std::collections::HashMap, which wraps hashbrown::HashMap
379 hashbrown_hashmap = self.valobj["map"]["base"]
381 # HashSet wraps hashbrown::HashSet, which wraps hashbrown::HashMap
382 hashbrown_hashmap = self.valobj["base"]["map"]
383 return hashbrown_hashmap["table"]
387 return "HashMap(size={})".format(self.size)
389 return "HashSet(size={})".format(self.size)
392 pairs_start = self.data_ptr
394 for index in range(self.size):
395 idx = self.valid_indices[index]
398 element = (pairs_start + idx).dereference()
400 yield "key{}".format(index), element[ZERO_FIELD]
401 yield "val{}".format(index), element[FIRST_FIELD]
403 yield "[{}]".format(index), element[ZERO_FIELD]
405 def display_hint(self):
406 return "map" if self.show_values else "array"