4 import debugger_pretty_printers_common as rustpp
6 # We want a version of `range` which doesn't allocate an intermediate list,
7 # specifically it should use a lazy iterator. In Python 2 this was `xrange`, but
8 # if we're running with Python 3 then we need to use `range` instead.
9 if sys.version_info[0] >= 3:
12 rust_enabled = 'set language rust' in gdb.execute('complete set language ru', to_string=True)
14 # The btree pretty-printers fail in a confusing way unless
15 # https://sourceware.org/bugzilla/show_bug.cgi?id=21763 is fixed.
16 # This fix went in 8.1, so check for that.
17 # See https://github.com/rust-lang/rust/issues/56730
19 _match = re.search('([0-9]+)\\.([0-9]+)', gdb.VERSION)
21 if int(_match.group(1)) > 8 or (int(_match.group(1)) == 8 and int(_match.group(2)) >= 1):
24 # ===============================================================================
25 # GDB Pretty Printing Module for Rust
26 # ===============================================================================
29 class GdbType(rustpp.Type):
31 def __init__(self, ty):
32 super(GdbType, self).__init__()
36 def get_unqualified_type_name(self):
42 return rustpp.extract_type_name(tag).replace("&'static ", "&")
44 def get_dwarf_type_kind(self):
45 if self.ty.code == gdb.TYPE_CODE_STRUCT:
46 return rustpp.DWARF_TYPE_CODE_STRUCT
48 if self.ty.code == gdb.TYPE_CODE_UNION:
49 return rustpp.DWARF_TYPE_CODE_UNION
51 if self.ty.code == gdb.TYPE_CODE_PTR:
52 return rustpp.DWARF_TYPE_CODE_PTR
54 if self.ty.code == gdb.TYPE_CODE_ENUM:
55 return rustpp.DWARF_TYPE_CODE_ENUM
58 assert ((self.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_STRUCT) or
59 (self.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_UNION))
60 if self.fields is None:
61 self.fields = list(self.ty.fields())
64 def get_wrapped_value(self):
68 class GdbValue(rustpp.Value):
69 def __init__(self, gdb_val):
70 super(GdbValue, self).__init__(GdbType(gdb_val.type))
71 self.gdb_val = gdb_val
74 def get_child_at_index(self, index):
75 child = self.children.get(index)
77 gdb_field = get_field_at_index(self.gdb_val, index)
78 child = GdbValue(self.gdb_val[gdb_field])
79 self.children[index] = child
83 if self.gdb_val.type.code == gdb.TYPE_CODE_PTR:
84 as_str = rustpp.compat_str(self.gdb_val).split()[0]
86 return int(self.gdb_val)
88 def get_wrapped_value(self):
92 def register_printers(objfile):
93 """Registers Rust pretty printers for the given objfile"""
94 objfile.pretty_printers.append(rust_pretty_printer_lookup_function)
97 def rust_pretty_printer_lookup_function(gdb_val):
99 Returns the correct Rust pretty printer for the given value
103 val = GdbValue(gdb_val)
104 type_kind = val.type.get_type_kind()
106 if type_kind == rustpp.TYPE_KIND_SLICE:
107 return RustSlicePrinter(val)
109 if type_kind == rustpp.TYPE_KIND_STD_VEC:
110 return RustStdVecPrinter(val)
112 if type_kind == rustpp.TYPE_KIND_STD_VECDEQUE:
113 return RustStdVecDequePrinter(val)
115 if type_kind == rustpp.TYPE_KIND_STD_BTREESET and gdb_81:
116 return RustStdBTreeSetPrinter(val)
118 if type_kind == rustpp.TYPE_KIND_STD_BTREEMAP and gdb_81:
119 return RustStdBTreeMapPrinter(val)
121 if type_kind == rustpp.TYPE_KIND_STD_STRING:
122 return RustStdStringPrinter(val)
124 if type_kind == rustpp.TYPE_KIND_OS_STRING:
125 return RustOsStringPrinter(val)
127 # Checks after this point should only be for "compiler" types --
128 # things that gdb's Rust language support knows about.
132 if type_kind == rustpp.TYPE_KIND_EMPTY:
133 return RustEmptyPrinter(val)
135 if type_kind == rustpp.TYPE_KIND_REGULAR_STRUCT:
136 return RustStructPrinter(val,
137 omit_first_field=False,
138 omit_type_name=False,
141 if type_kind == rustpp.TYPE_KIND_STRUCT_VARIANT:
142 return RustStructPrinter(val,
143 omit_first_field=True,
144 omit_type_name=False,
147 if type_kind == rustpp.TYPE_KIND_STR_SLICE:
148 return RustStringSlicePrinter(val)
150 if type_kind == rustpp.TYPE_KIND_TUPLE:
151 return RustStructPrinter(val,
152 omit_first_field=False,
156 if type_kind == rustpp.TYPE_KIND_TUPLE_STRUCT:
157 return RustStructPrinter(val,
158 omit_first_field=False,
159 omit_type_name=False,
162 if type_kind == rustpp.TYPE_KIND_CSTYLE_VARIANT:
163 return RustCStyleVariantPrinter(val.get_child_at_index(0))
165 if type_kind == rustpp.TYPE_KIND_TUPLE_VARIANT:
166 return RustStructPrinter(val,
167 omit_first_field=True,
168 omit_type_name=False,
171 if type_kind == rustpp.TYPE_KIND_SINGLETON_ENUM:
172 variant = get_field_at_index(gdb_val, 0)
173 return rust_pretty_printer_lookup_function(gdb_val[variant])
175 if type_kind == rustpp.TYPE_KIND_REGULAR_ENUM:
176 # This is a regular enum, extract the discriminant
177 discriminant_val = rustpp.get_discriminant_value_as_integer(val)
178 variant = get_field_at_index(gdb_val, discriminant_val)
179 return rust_pretty_printer_lookup_function(gdb_val[variant])
181 if type_kind == rustpp.TYPE_KIND_COMPRESSED_ENUM:
182 encoded_enum_info = rustpp.EncodedEnumInfo(val)
183 if encoded_enum_info.is_null_variant():
184 return IdentityPrinter(encoded_enum_info.get_null_variant_name())
186 non_null_val = encoded_enum_info.get_non_null_variant_val()
187 return rust_pretty_printer_lookup_function(non_null_val.get_wrapped_value())
189 # No pretty printer has been found
193 # =------------------------------------------------------------------------------
194 # Pretty Printer Classes
195 # =------------------------------------------------------------------------------
196 class RustEmptyPrinter(object):
197 def __init__(self, val):
201 return self.__val.type.get_unqualified_type_name()
204 class RustStructPrinter(object):
205 def __init__(self, val, omit_first_field, omit_type_name, is_tuple_like):
207 self.__omit_first_field = omit_first_field
208 self.__omit_type_name = omit_type_name
209 self.__is_tuple_like = is_tuple_like
212 if self.__omit_type_name:
214 return self.__val.type.get_unqualified_type_name()
218 wrapped_value = self.__val.get_wrapped_value()
220 for number, field in enumerate(self.__val.type.get_fields()):
221 field_value = wrapped_value[field.name]
222 if self.__is_tuple_like:
223 cs.append((str(number), field_value))
225 cs.append((field.name, field_value))
227 if self.__omit_first_field:
232 def display_hint(self):
233 if self.__is_tuple_like:
239 class RustSlicePrinter(object):
240 def __init__(self, val):
248 (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(self.__val)
249 return (self.__val.type.get_unqualified_type_name() +
250 ("(len: %i)" % length))
253 (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(self.__val)
254 assert data_ptr.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_PTR
255 raw_ptr = data_ptr.get_wrapped_value()
257 for index in xrange(0, length):
258 yield (str(index), (raw_ptr + index).dereference())
261 class RustStringSlicePrinter(object):
262 def __init__(self, val):
266 (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(self.__val)
267 raw_ptr = data_ptr.get_wrapped_value()
268 return raw_ptr.lazy_string(encoding="utf-8", length=length)
270 def display_hint(self):
274 class RustStdVecPrinter(object):
275 def __init__(self, val):
283 (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(self.__val)
284 return (self.__val.type.get_unqualified_type_name() +
285 ("(len: %i, cap: %i)" % (length, cap)))
288 saw_inaccessible = False
289 (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(self.__val)
290 gdb_ptr = data_ptr.get_wrapped_value()
291 for index in xrange(0, length):
295 # rust-lang/rust#64343: passing deref expr to `str` allows
296 # catching exception on garbage pointer
297 str((gdb_ptr + index).dereference())
298 yield (str(index), (gdb_ptr + index).dereference())
300 saw_inaccessible = True
301 yield (str(index), "inaccessible")
304 class RustStdVecDequePrinter(object):
305 def __init__(self, val):
313 (tail, head, data_ptr, cap) = \
314 rustpp.extract_tail_head_ptr_and_cap_from_std_vecdeque(self.__val)
318 size = cap + head - tail
319 return (self.__val.type.get_unqualified_type_name() +
320 ("(len: %i, cap: %i)" % (size, cap)))
323 (tail, head, data_ptr, cap) = \
324 rustpp.extract_tail_head_ptr_and_cap_from_std_vecdeque(self.__val)
325 gdb_ptr = data_ptr.get_wrapped_value()
329 size = cap + head - tail
330 for index in xrange(0, size):
331 yield (str(index), (gdb_ptr + ((tail + index) % cap)).dereference())
334 # Yield each key (and optionally value) from a BoxedNode.
335 def children_of_node(boxed_node, height, want_values):
336 node_ptr = boxed_node['ptr']['pointer']
338 type_name = str(node_ptr.type.target()).replace('LeafNode', 'InternalNode')
339 node_type = gdb.lookup_type(type_name)
340 node_ptr = node_ptr.cast(node_type.pointer())
341 leaf = node_ptr['data']
343 leaf = node_ptr.dereference()
346 values = leaf['vals']
347 length = int(leaf['len'])
348 for i in xrange(0, length + 1):
350 child_ptr = node_ptr['edges'][i]['value']['value']
351 for child in children_of_node(child_ptr, height - 1, want_values):
355 yield (keys[i]['value']['value'], values[i]['value']['value'])
357 yield keys[i]['value']['value']
360 class RustStdBTreeSetPrinter(object):
361 def __init__(self, val):
369 return (self.__val.type.get_unqualified_type_name() +
370 ("(len: %i)" % self.__val.get_wrapped_value()['map']['length']))
373 root = self.__val.get_wrapped_value()['map']['root']
374 node_ptr = root['node']
376 for child in children_of_node(node_ptr, root['height'], False):
377 yield (str(i), child)
381 class RustStdBTreeMapPrinter(object):
382 def __init__(self, val):
390 return (self.__val.type.get_unqualified_type_name() +
391 ("(len: %i)" % self.__val.get_wrapped_value()['length']))
394 root = self.__val.get_wrapped_value()['root']
395 node_ptr = root['node']
397 for child in children_of_node(node_ptr, root['height'], True):
398 yield (str(i), child[0])
399 yield (str(i), child[1])
403 class RustStdStringPrinter(object):
404 def __init__(self, val):
408 vec = self.__val.get_child_at_index(0)
409 (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(vec)
410 return data_ptr.get_wrapped_value().lazy_string(encoding="utf-8",
413 def display_hint(self):
417 class RustOsStringPrinter(object):
418 def __init__(self, val):
422 buf = self.__val.get_child_at_index(0)
423 vec = buf.get_child_at_index(0)
424 if vec.type.get_unqualified_type_name() == "Wtf8Buf":
425 vec = vec.get_child_at_index(0)
427 (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(
429 return data_ptr.get_wrapped_value().lazy_string(length=length)
431 def display_hint(self):
435 class RustCStyleVariantPrinter(object):
436 def __init__(self, val):
437 assert val.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_ENUM
441 return str(self.__val.get_wrapped_value())
444 class IdentityPrinter(object):
445 def __init__(self, string):
452 def get_field_at_index(gdb_val, index):
454 for field in gdb_val.type.fields():