1 # Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
2 # file at the top-level directory of this distribution and at
3 # http://rust-lang.org/COPYRIGHT.
5 # Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 # http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 # <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 # option. This file may not be copied, modified, or distributed
9 # except according to those terms.
14 import debugger_pretty_printers_common as rustpp
16 # We want a version of `range` which doesn't allocate an intermediate list,
17 # specifically it should use a lazy iterator. In Python 2 this was `xrange`, but
18 # if we're running with Python 3 then we need to use `range` instead.
19 if sys.version_info[0] >= 3:
22 rust_enabled = 'set language rust' in gdb.execute('complete set language ru', to_string = True)
24 # The btree pretty-printers fail in a confusing way unless
25 # https://sourceware.org/bugzilla/show_bug.cgi?id=21763 is fixed.
26 # This fix went in 8.1, so check for that.
27 # See https://github.com/rust-lang/rust/issues/56730
29 _match = re.match('([0-9]+)\\.([0-9]+)', gdb.VERSION)
31 if int(_match.group(1)) > 8 or (int(_match.group(1)) == 8 and int(_match.group(2)) >= 1):
34 #===============================================================================
35 # GDB Pretty Printing Module for Rust
36 #===============================================================================
38 class GdbType(rustpp.Type):
40 def __init__(self, ty):
41 super(GdbType, self).__init__()
45 def get_unqualified_type_name(self):
51 return rustpp.extract_type_name(tag).replace("&'static ", "&")
53 def get_dwarf_type_kind(self):
54 if self.ty.code == gdb.TYPE_CODE_STRUCT:
55 return rustpp.DWARF_TYPE_CODE_STRUCT
57 if self.ty.code == gdb.TYPE_CODE_UNION:
58 return rustpp.DWARF_TYPE_CODE_UNION
60 if self.ty.code == gdb.TYPE_CODE_PTR:
61 return rustpp.DWARF_TYPE_CODE_PTR
63 if self.ty.code == gdb.TYPE_CODE_ENUM:
64 return rustpp.DWARF_TYPE_CODE_ENUM
67 assert ((self.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_STRUCT) or
68 (self.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_UNION))
69 if self.fields is None:
70 self.fields = list(self.ty.fields())
73 def get_wrapped_value(self):
77 class GdbValue(rustpp.Value):
78 def __init__(self, gdb_val):
79 super(GdbValue, self).__init__(GdbType(gdb_val.type))
80 self.gdb_val = gdb_val
83 def get_child_at_index(self, index):
84 child = self.children.get(index)
86 gdb_field = get_field_at_index(self.gdb_val, index)
87 child = GdbValue(self.gdb_val[gdb_field])
88 self.children[index] = child
92 if self.gdb_val.type.code == gdb.TYPE_CODE_PTR:
93 as_str = rustpp.compat_str(self.gdb_val).split()[0]
95 return int(self.gdb_val)
97 def get_wrapped_value(self):
101 def register_printers(objfile):
102 """Registers Rust pretty printers for the given objfile"""
103 objfile.pretty_printers.append(rust_pretty_printer_lookup_function)
106 def rust_pretty_printer_lookup_function(gdb_val):
108 Returns the correct Rust pretty printer for the given value
112 val = GdbValue(gdb_val)
113 type_kind = val.type.get_type_kind()
115 if type_kind == rustpp.TYPE_KIND_SLICE:
116 return RustSlicePrinter(val)
118 if type_kind == rustpp.TYPE_KIND_STD_VEC:
119 return RustStdVecPrinter(val)
121 if type_kind == rustpp.TYPE_KIND_STD_VECDEQUE:
122 return RustStdVecDequePrinter(val)
124 if type_kind == rustpp.TYPE_KIND_STD_BTREESET and gdb_81:
125 return RustStdBTreeSetPrinter(val)
127 if type_kind == rustpp.TYPE_KIND_STD_BTREEMAP and gdb_81:
128 return RustStdBTreeMapPrinter(val)
130 if type_kind == rustpp.TYPE_KIND_STD_STRING:
131 return RustStdStringPrinter(val)
133 if type_kind == rustpp.TYPE_KIND_OS_STRING:
134 return RustOsStringPrinter(val)
136 # Checks after this point should only be for "compiler" types --
137 # things that gdb's Rust language support knows about.
141 if type_kind == rustpp.TYPE_KIND_EMPTY:
142 return RustEmptyPrinter(val)
144 if type_kind == rustpp.TYPE_KIND_REGULAR_STRUCT:
145 return RustStructPrinter(val,
146 omit_first_field = False,
147 omit_type_name = False,
148 is_tuple_like = False)
150 if type_kind == rustpp.TYPE_KIND_STRUCT_VARIANT:
151 return RustStructPrinter(val,
152 omit_first_field = True,
153 omit_type_name = False,
154 is_tuple_like = False)
156 if type_kind == rustpp.TYPE_KIND_STR_SLICE:
157 return RustStringSlicePrinter(val)
159 if type_kind == rustpp.TYPE_KIND_TUPLE:
160 return RustStructPrinter(val,
161 omit_first_field = False,
162 omit_type_name = True,
163 is_tuple_like = True)
165 if type_kind == rustpp.TYPE_KIND_TUPLE_STRUCT:
166 return RustStructPrinter(val,
167 omit_first_field = False,
168 omit_type_name = False,
169 is_tuple_like = True)
171 if type_kind == rustpp.TYPE_KIND_CSTYLE_VARIANT:
172 return RustCStyleVariantPrinter(val.get_child_at_index(0))
174 if type_kind == rustpp.TYPE_KIND_TUPLE_VARIANT:
175 return RustStructPrinter(val,
176 omit_first_field = True,
177 omit_type_name = False,
178 is_tuple_like = True)
180 if type_kind == rustpp.TYPE_KIND_SINGLETON_ENUM:
181 variant = get_field_at_index(gdb_val, 0)
182 return rust_pretty_printer_lookup_function(gdb_val[variant])
184 if type_kind == rustpp.TYPE_KIND_REGULAR_ENUM:
185 # This is a regular enum, extract the discriminant
186 discriminant_val = rustpp.get_discriminant_value_as_integer(val)
187 variant = get_field_at_index(gdb_val, discriminant_val)
188 return rust_pretty_printer_lookup_function(gdb_val[variant])
190 if type_kind == rustpp.TYPE_KIND_COMPRESSED_ENUM:
191 encoded_enum_info = rustpp.EncodedEnumInfo(val)
192 if encoded_enum_info.is_null_variant():
193 return IdentityPrinter(encoded_enum_info.get_null_variant_name())
195 non_null_val = encoded_enum_info.get_non_null_variant_val()
196 return rust_pretty_printer_lookup_function(non_null_val.get_wrapped_value())
198 # No pretty printer has been found
202 #=------------------------------------------------------------------------------
203 # Pretty Printer Classes
204 #=------------------------------------------------------------------------------
205 class RustEmptyPrinter(object):
206 def __init__(self, val):
210 return self.__val.type.get_unqualified_type_name()
213 class RustStructPrinter(object):
214 def __init__(self, val, omit_first_field, omit_type_name, is_tuple_like):
216 self.__omit_first_field = omit_first_field
217 self.__omit_type_name = omit_type_name
218 self.__is_tuple_like = is_tuple_like
221 if self.__omit_type_name:
223 return self.__val.type.get_unqualified_type_name()
227 wrapped_value = self.__val.get_wrapped_value()
229 for number, field in enumerate(self.__val.type.get_fields()):
230 field_value = wrapped_value[field.name]
231 if self.__is_tuple_like:
232 cs.append((str(number), field_value))
234 cs.append((field.name, field_value))
236 if self.__omit_first_field:
241 def display_hint(self):
242 if self.__is_tuple_like:
248 class RustSlicePrinter(object):
249 def __init__(self, val):
257 (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(self.__val)
258 return (self.__val.type.get_unqualified_type_name() +
259 ("(len: %i)" % length))
262 (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(self.__val)
263 assert data_ptr.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_PTR
264 raw_ptr = data_ptr.get_wrapped_value()
266 for index in xrange(0, length):
267 yield (str(index), (raw_ptr + index).dereference())
270 class RustStringSlicePrinter(object):
271 def __init__(self, val):
275 (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(self.__val)
276 raw_ptr = data_ptr.get_wrapped_value()
277 return raw_ptr.lazy_string(encoding="utf-8", length=length)
279 def display_hint(self):
283 class RustStdVecPrinter(object):
284 def __init__(self, val):
292 (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(self.__val)
293 return (self.__val.type.get_unqualified_type_name() +
294 ("(len: %i, cap: %i)" % (length, cap)))
297 (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(self.__val)
298 gdb_ptr = data_ptr.get_wrapped_value()
299 for index in xrange(0, length):
300 yield (str(index), (gdb_ptr + index).dereference())
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 ptr = boxed_node['ptr']['pointer']
336 # This is written oddly because we don't want to rely on the field name being `__0`.
337 node_ptr = ptr[ptr.type.fields()[0]]
339 type_name = str(node_ptr.type.target()).replace('LeafNode', 'InternalNode')
340 node_type = gdb.lookup_type(type_name)
341 node_ptr = node_ptr.cast(node_type.pointer())
342 leaf = node_ptr['data']
344 leaf = node_ptr.dereference()
345 keys = leaf['keys']['value']['value']
347 values = leaf['vals']['value']['value']
348 length = int(leaf['len'])
349 for i in xrange(0, length + 1):
351 for child in children_of_node(node_ptr['edges'][i], height - 1, want_values):
355 yield (keys[i], values[i])
359 class RustStdBTreeSetPrinter(object):
360 def __init__(self, val):
368 return (self.__val.type.get_unqualified_type_name() +
369 ("(len: %i)" % self.__val.get_wrapped_value()['map']['length']))
372 root = self.__val.get_wrapped_value()['map']['root']
373 node_ptr = root['node']
375 for child in children_of_node(node_ptr, root['height'], False):
376 yield (str(i), child)
380 class RustStdBTreeMapPrinter(object):
381 def __init__(self, val):
389 return (self.__val.type.get_unqualified_type_name() +
390 ("(len: %i)" % self.__val.get_wrapped_value()['length']))
393 root = self.__val.get_wrapped_value()['root']
394 node_ptr = root['node']
396 for child in children_of_node(node_ptr, root['height'], True):
397 yield (str(i), child[0])
398 yield (str(i), child[1])
402 class RustStdStringPrinter(object):
403 def __init__(self, val):
407 vec = self.__val.get_child_at_index(0)
408 (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(vec)
409 return data_ptr.get_wrapped_value().lazy_string(encoding="utf-8",
412 def display_hint(self):
416 class RustOsStringPrinter(object):
417 def __init__(self, val):
421 buf = self.__val.get_child_at_index(0)
422 vec = buf.get_child_at_index(0)
423 if vec.type.get_unqualified_type_name() == "Wtf8Buf":
424 vec = vec.get_child_at_index(0)
426 (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(
428 return data_ptr.get_wrapped_value().lazy_string(length=length)
430 def display_hint(self):
433 class RustCStyleVariantPrinter(object):
434 def __init__(self, val):
435 assert val.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_ENUM
439 return str(self.__val.get_wrapped_value())
442 class IdentityPrinter(object):
443 def __init__(self, string):
450 def get_field_at_index(gdb_val, index):
452 for field in gdb_val.type.fields():