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 #===============================================================================
28 class GdbType(rustpp.Type):
30 def __init__(self, ty):
31 super(GdbType, self).__init__()
35 def get_unqualified_type_name(self):
41 return rustpp.extract_type_name(tag).replace("&'static ", "&")
43 def get_dwarf_type_kind(self):
44 if self.ty.code == gdb.TYPE_CODE_STRUCT:
45 return rustpp.DWARF_TYPE_CODE_STRUCT
47 if self.ty.code == gdb.TYPE_CODE_UNION:
48 return rustpp.DWARF_TYPE_CODE_UNION
50 if self.ty.code == gdb.TYPE_CODE_PTR:
51 return rustpp.DWARF_TYPE_CODE_PTR
53 if self.ty.code == gdb.TYPE_CODE_ENUM:
54 return rustpp.DWARF_TYPE_CODE_ENUM
57 assert ((self.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_STRUCT) or
58 (self.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_UNION))
59 if self.fields is None:
60 self.fields = list(self.ty.fields())
63 def get_wrapped_value(self):
67 class GdbValue(rustpp.Value):
68 def __init__(self, gdb_val):
69 super(GdbValue, self).__init__(GdbType(gdb_val.type))
70 self.gdb_val = gdb_val
73 def get_child_at_index(self, index):
74 child = self.children.get(index)
76 gdb_field = get_field_at_index(self.gdb_val, index)
77 child = GdbValue(self.gdb_val[gdb_field])
78 self.children[index] = child
82 if self.gdb_val.type.code == gdb.TYPE_CODE_PTR:
83 as_str = rustpp.compat_str(self.gdb_val).split()[0]
85 return int(self.gdb_val)
87 def get_wrapped_value(self):
91 def register_printers(objfile):
92 """Registers Rust pretty printers for the given objfile"""
93 objfile.pretty_printers.append(rust_pretty_printer_lookup_function)
96 def rust_pretty_printer_lookup_function(gdb_val):
98 Returns the correct Rust pretty printer for the given value
102 val = GdbValue(gdb_val)
103 type_kind = val.type.get_type_kind()
105 if type_kind == rustpp.TYPE_KIND_SLICE:
106 return RustSlicePrinter(val)
108 if type_kind == rustpp.TYPE_KIND_STD_VEC:
109 return RustStdVecPrinter(val)
111 if type_kind == rustpp.TYPE_KIND_STD_VECDEQUE:
112 return RustStdVecDequePrinter(val)
114 if type_kind == rustpp.TYPE_KIND_STD_BTREESET and gdb_81:
115 return RustStdBTreeSetPrinter(val)
117 if type_kind == rustpp.TYPE_KIND_STD_BTREEMAP and gdb_81:
118 return RustStdBTreeMapPrinter(val)
120 if type_kind == rustpp.TYPE_KIND_STD_STRING:
121 return RustStdStringPrinter(val)
123 if type_kind == rustpp.TYPE_KIND_OS_STRING:
124 return RustOsStringPrinter(val)
126 # Checks after this point should only be for "compiler" types --
127 # things that gdb's Rust language support knows about.
131 if type_kind == rustpp.TYPE_KIND_EMPTY:
132 return RustEmptyPrinter(val)
134 if type_kind == rustpp.TYPE_KIND_REGULAR_STRUCT:
135 return RustStructPrinter(val,
136 omit_first_field = False,
137 omit_type_name = False,
138 is_tuple_like = False)
140 if type_kind == rustpp.TYPE_KIND_STRUCT_VARIANT:
141 return RustStructPrinter(val,
142 omit_first_field = True,
143 omit_type_name = False,
144 is_tuple_like = False)
146 if type_kind == rustpp.TYPE_KIND_STR_SLICE:
147 return RustStringSlicePrinter(val)
149 if type_kind == rustpp.TYPE_KIND_TUPLE:
150 return RustStructPrinter(val,
151 omit_first_field = False,
152 omit_type_name = True,
153 is_tuple_like = True)
155 if type_kind == rustpp.TYPE_KIND_TUPLE_STRUCT:
156 return RustStructPrinter(val,
157 omit_first_field = False,
158 omit_type_name = False,
159 is_tuple_like = True)
161 if type_kind == rustpp.TYPE_KIND_CSTYLE_VARIANT:
162 return RustCStyleVariantPrinter(val.get_child_at_index(0))
164 if type_kind == rustpp.TYPE_KIND_TUPLE_VARIANT:
165 return RustStructPrinter(val,
166 omit_first_field = True,
167 omit_type_name = False,
168 is_tuple_like = True)
170 if type_kind == rustpp.TYPE_KIND_SINGLETON_ENUM:
171 variant = get_field_at_index(gdb_val, 0)
172 return rust_pretty_printer_lookup_function(gdb_val[variant])
174 if type_kind == rustpp.TYPE_KIND_REGULAR_ENUM:
175 # This is a regular enum, extract the discriminant
176 discriminant_val = rustpp.get_discriminant_value_as_integer(val)
177 variant = get_field_at_index(gdb_val, discriminant_val)
178 return rust_pretty_printer_lookup_function(gdb_val[variant])
180 if type_kind == rustpp.TYPE_KIND_COMPRESSED_ENUM:
181 encoded_enum_info = rustpp.EncodedEnumInfo(val)
182 if encoded_enum_info.is_null_variant():
183 return IdentityPrinter(encoded_enum_info.get_null_variant_name())
185 non_null_val = encoded_enum_info.get_non_null_variant_val()
186 return rust_pretty_printer_lookup_function(non_null_val.get_wrapped_value())
188 # No pretty printer has been found
192 #=------------------------------------------------------------------------------
193 # Pretty Printer Classes
194 #=------------------------------------------------------------------------------
195 class RustEmptyPrinter(object):
196 def __init__(self, val):
200 return self.__val.type.get_unqualified_type_name()
203 class RustStructPrinter(object):
204 def __init__(self, val, omit_first_field, omit_type_name, is_tuple_like):
206 self.__omit_first_field = omit_first_field
207 self.__omit_type_name = omit_type_name
208 self.__is_tuple_like = is_tuple_like
211 if self.__omit_type_name:
213 return self.__val.type.get_unqualified_type_name()
217 wrapped_value = self.__val.get_wrapped_value()
219 for number, field in enumerate(self.__val.type.get_fields()):
220 field_value = wrapped_value[field.name]
221 if self.__is_tuple_like:
222 cs.append((str(number), field_value))
224 cs.append((field.name, field_value))
226 if self.__omit_first_field:
231 def display_hint(self):
232 if self.__is_tuple_like:
238 class RustSlicePrinter(object):
239 def __init__(self, val):
247 (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(self.__val)
248 return (self.__val.type.get_unqualified_type_name() +
249 ("(len: %i)" % length))
252 (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(self.__val)
253 assert data_ptr.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_PTR
254 raw_ptr = data_ptr.get_wrapped_value()
256 for index in xrange(0, length):
257 yield (str(index), (raw_ptr + index).dereference())
260 class RustStringSlicePrinter(object):
261 def __init__(self, val):
265 (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(self.__val)
266 raw_ptr = data_ptr.get_wrapped_value()
267 return raw_ptr.lazy_string(encoding="utf-8", length=length)
269 def display_hint(self):
273 class RustStdVecPrinter(object):
274 def __init__(self, val):
282 (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(self.__val)
283 return (self.__val.type.get_unqualified_type_name() +
284 ("(len: %i, cap: %i)" % (length, cap)))
287 saw_inaccessible = False
288 (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(self.__val)
289 gdb_ptr = data_ptr.get_wrapped_value()
290 for index in xrange(0, length):
294 # rust-lang/rust#64343: passing deref expr to `str` allows
295 # catching exception on garbage pointer
296 str((gdb_ptr + index).dereference())
297 yield (str(index), (gdb_ptr + index).dereference())
299 saw_inaccessible = True
300 yield (str(index), "inaccessible")
303 class RustStdVecDequePrinter(object):
304 def __init__(self, val):
312 (tail, head, data_ptr, cap) = \
313 rustpp.extract_tail_head_ptr_and_cap_from_std_vecdeque(self.__val)
317 size = cap + head - tail
318 return (self.__val.type.get_unqualified_type_name() +
319 ("(len: %i, cap: %i)" % (size, cap)))
322 (tail, head, data_ptr, cap) = \
323 rustpp.extract_tail_head_ptr_and_cap_from_std_vecdeque(self.__val)
324 gdb_ptr = data_ptr.get_wrapped_value()
328 size = cap + head - tail
329 for index in xrange(0, size):
330 yield (str(index), (gdb_ptr + ((tail + index) % cap)).dereference())
333 # Yield each key (and optionally value) from a BoxedNode.
334 def children_of_node(boxed_node, height, want_values):
335 node_ptr = boxed_node['ptr']['pointer']
337 type_name = str(node_ptr.type.target()).replace('LeafNode', 'InternalNode')
338 node_type = gdb.lookup_type(type_name)
339 node_ptr = node_ptr.cast(node_type.pointer())
340 leaf = node_ptr['data']
342 leaf = node_ptr.dereference()
345 values = leaf['vals']
346 length = int(leaf['len'])
347 for i in xrange(0, length + 1):
349 child_ptr = node_ptr['edges'][i]['value']['value']
350 for child in children_of_node(child_ptr, height - 1, want_values):
354 yield (keys[i]['value']['value'], values[i]['value']['value'])
356 yield keys[i]['value']['value']
358 class RustStdBTreeSetPrinter(object):
359 def __init__(self, val):
367 return (self.__val.type.get_unqualified_type_name() +
368 ("(len: %i)" % self.__val.get_wrapped_value()['map']['length']))
371 root = self.__val.get_wrapped_value()['map']['root']
372 node_ptr = root['node']
374 for child in children_of_node(node_ptr, root['height'], False):
375 yield (str(i), child)
379 class RustStdBTreeMapPrinter(object):
380 def __init__(self, val):
388 return (self.__val.type.get_unqualified_type_name() +
389 ("(len: %i)" % self.__val.get_wrapped_value()['length']))
392 root = self.__val.get_wrapped_value()['root']
393 node_ptr = root['node']
395 for child in children_of_node(node_ptr, root['height'], True):
396 yield (str(i), child[0])
397 yield (str(i), child[1])
401 class RustStdStringPrinter(object):
402 def __init__(self, val):
406 vec = self.__val.get_child_at_index(0)
407 (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(vec)
408 return data_ptr.get_wrapped_value().lazy_string(encoding="utf-8",
411 def display_hint(self):
415 class RustOsStringPrinter(object):
416 def __init__(self, val):
420 buf = self.__val.get_child_at_index(0)
421 vec = buf.get_child_at_index(0)
422 if vec.type.get_unqualified_type_name() == "Wtf8Buf":
423 vec = vec.get_child_at_index(0)
425 (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(
427 return data_ptr.get_wrapped_value().lazy_string(length=length)
429 def display_hint(self):
432 class RustCStyleVariantPrinter(object):
433 def __init__(self, val):
434 assert val.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_ENUM
438 return str(self.__val.get_wrapped_value())
441 class IdentityPrinter(object):
442 def __init__(self, string):
449 def get_field_at_index(gdb_val, index):
451 for field in gdb_val.type.fields():