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 #===============================================================================
23 # GDB Pretty Printing Module for Rust
24 #===============================================================================
26 class GdbType(rustpp.Type):
28 def __init__(self, ty):
29 super(GdbType, self).__init__()
33 def get_unqualified_type_name(self):
39 return rustpp.extract_type_name(tag).replace("&'static ", "&")
41 def get_dwarf_type_kind(self):
42 if self.ty.code == gdb.TYPE_CODE_STRUCT:
43 return rustpp.DWARF_TYPE_CODE_STRUCT
45 if self.ty.code == gdb.TYPE_CODE_UNION:
46 return rustpp.DWARF_TYPE_CODE_UNION
48 if self.ty.code == gdb.TYPE_CODE_PTR:
49 return rustpp.DWARF_TYPE_CODE_PTR
51 if self.ty.code == gdb.TYPE_CODE_ENUM:
52 return rustpp.DWARF_TYPE_CODE_ENUM
55 assert ((self.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_STRUCT) or
56 (self.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_UNION))
57 if self.fields is None:
58 self.fields = list(self.ty.fields())
61 def get_wrapped_value(self):
65 class GdbValue(rustpp.Value):
66 def __init__(self, gdb_val):
67 super(GdbValue, self).__init__(GdbType(gdb_val.type))
68 self.gdb_val = gdb_val
71 def get_child_at_index(self, index):
72 child = self.children.get(index)
74 gdb_field = get_field_at_index(self.gdb_val, index)
75 child = GdbValue(self.gdb_val[gdb_field])
76 self.children[index] = child
80 if self.gdb_val.type.code == gdb.TYPE_CODE_PTR:
81 as_str = rustpp.compat_str(self.gdb_val).split()[0]
83 return int(self.gdb_val)
85 def get_wrapped_value(self):
89 def register_printers(objfile):
90 """Registers Rust pretty printers for the given objfile"""
91 objfile.pretty_printers.append(rust_pretty_printer_lookup_function)
94 def rust_pretty_printer_lookup_function(gdb_val):
96 Returns the correct Rust pretty printer for the given value
100 val = GdbValue(gdb_val)
101 type_kind = val.type.get_type_kind()
103 if type_kind == rustpp.TYPE_KIND_EMPTY:
104 return RustEmptyPrinter(val)
106 if type_kind == rustpp.TYPE_KIND_REGULAR_STRUCT:
107 return RustStructPrinter(val,
108 omit_first_field = False,
109 omit_type_name = False,
110 is_tuple_like = False)
112 if type_kind == rustpp.TYPE_KIND_STRUCT_VARIANT:
113 return RustStructPrinter(val,
114 omit_first_field = True,
115 omit_type_name = False,
116 is_tuple_like = False)
118 if type_kind == rustpp.TYPE_KIND_SLICE:
119 return RustSlicePrinter(val)
121 if type_kind == rustpp.TYPE_KIND_STR_SLICE:
122 return RustStringSlicePrinter(val)
124 if type_kind == rustpp.TYPE_KIND_STD_VEC:
125 return RustStdVecPrinter(val)
127 if type_kind == rustpp.TYPE_KIND_STD_VECDEQUE:
128 return RustStdVecDequePrinter(val)
130 if type_kind == rustpp.TYPE_KIND_STD_BTREESET:
131 return RustStdBTreeSetPrinter(val)
133 if type_kind == rustpp.TYPE_KIND_STD_BTREEMAP:
134 return RustStdBTreeMapPrinter(val)
136 if type_kind == rustpp.TYPE_KIND_STD_STRING:
137 return RustStdStringPrinter(val)
139 if type_kind == rustpp.TYPE_KIND_OS_STRING:
140 return RustOsStringPrinter(val)
142 if type_kind == rustpp.TYPE_KIND_TUPLE:
143 return RustStructPrinter(val,
144 omit_first_field = False,
145 omit_type_name = True,
146 is_tuple_like = True)
148 if type_kind == rustpp.TYPE_KIND_TUPLE_STRUCT:
149 return RustStructPrinter(val,
150 omit_first_field = False,
151 omit_type_name = False,
152 is_tuple_like = True)
154 if type_kind == rustpp.TYPE_KIND_CSTYLE_VARIANT:
155 return RustCStyleVariantPrinter(val.get_child_at_index(0))
157 if type_kind == rustpp.TYPE_KIND_TUPLE_VARIANT:
158 return RustStructPrinter(val,
159 omit_first_field = True,
160 omit_type_name = False,
161 is_tuple_like = True)
163 if type_kind == rustpp.TYPE_KIND_SINGLETON_ENUM:
164 variant = get_field_at_index(gdb_val, 0)
165 return rust_pretty_printer_lookup_function(gdb_val[variant])
167 if type_kind == rustpp.TYPE_KIND_REGULAR_ENUM:
168 # This is a regular enum, extract the discriminant
169 discriminant_val = rustpp.get_discriminant_value_as_integer(val)
170 variant = get_field_at_index(gdb_val, discriminant_val)
171 return rust_pretty_printer_lookup_function(gdb_val[variant])
173 if type_kind == rustpp.TYPE_KIND_COMPRESSED_ENUM:
174 encoded_enum_info = rustpp.EncodedEnumInfo(val)
175 if encoded_enum_info.is_null_variant():
176 return IdentityPrinter(encoded_enum_info.get_null_variant_name())
178 non_null_val = encoded_enum_info.get_non_null_variant_val()
179 return rust_pretty_printer_lookup_function(non_null_val.get_wrapped_value())
181 # No pretty printer has been found
185 #=------------------------------------------------------------------------------
186 # Pretty Printer Classes
187 #=------------------------------------------------------------------------------
188 class RustEmptyPrinter(object):
189 def __init__(self, val):
193 return self.__val.type.get_unqualified_type_name()
196 class RustStructPrinter(object):
197 def __init__(self, val, omit_first_field, omit_type_name, is_tuple_like):
199 self.__omit_first_field = omit_first_field
200 self.__omit_type_name = omit_type_name
201 self.__is_tuple_like = is_tuple_like
204 if self.__omit_type_name:
206 return self.__val.type.get_unqualified_type_name()
210 wrapped_value = self.__val.get_wrapped_value()
212 for number, field in enumerate(self.__val.type.get_fields()):
213 field_value = wrapped_value[field.name]
214 if self.__is_tuple_like:
215 cs.append((str(number), field_value))
217 cs.append((field.name, field_value))
219 if self.__omit_first_field:
224 def display_hint(self):
225 if self.__is_tuple_like:
231 class RustSlicePrinter(object):
232 def __init__(self, val):
240 (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(self.__val)
241 return (self.__val.type.get_unqualified_type_name() +
242 ("(len: %i)" % length))
245 (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(self.__val)
246 assert data_ptr.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_PTR
247 raw_ptr = data_ptr.get_wrapped_value()
249 for index in xrange(0, length):
250 yield (str(index), (raw_ptr + index).dereference())
253 class RustStringSlicePrinter(object):
254 def __init__(self, val):
258 (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(self.__val)
259 raw_ptr = data_ptr.get_wrapped_value()
260 return raw_ptr.lazy_string(encoding="utf-8", length=length)
262 def display_hint(self):
266 class RustStdVecPrinter(object):
267 def __init__(self, val):
275 (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(self.__val)
276 return (self.__val.type.get_unqualified_type_name() +
277 ("(len: %i, cap: %i)" % (length, cap)))
280 (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(self.__val)
281 gdb_ptr = data_ptr.get_wrapped_value()
282 for index in xrange(0, length):
283 yield (str(index), (gdb_ptr + index).dereference())
286 class RustStdVecDequePrinter(object):
287 def __init__(self, val):
295 (tail, head, data_ptr, cap) = \
296 rustpp.extract_tail_head_ptr_and_cap_from_std_vecdeque(self.__val)
297 return (self.__val.type.get_unqualified_type_name() +
298 ("(len: %i, cap: %i)" % (head - tail, cap)))
301 (tail, head, data_ptr, cap) = \
302 rustpp.extract_tail_head_ptr_and_cap_from_std_vecdeque(self.__val)
303 gdb_ptr = data_ptr.get_wrapped_value()
304 for index in xrange(tail, head):
305 yield (str(index), (gdb_ptr + index).dereference())
308 class RustStdBTreeSetPrinter(object):
309 def __init__(self, val):
317 (length, data_ptr) = \
318 rustpp.extract_length_and_ptr_from_std_btreeset(self.__val)
319 return (self.__val.type.get_unqualified_type_name() +
320 ("(len: %i)" % length))
323 (length, data_ptr) = \
324 rustpp.extract_length_and_ptr_from_std_btreeset(self.__val)
325 val = GdbValue(data_ptr.get_wrapped_value().dereference()).get_child_at_index(3)
326 gdb_ptr = val.get_wrapped_value()
327 for index in xrange(length):
328 yield (str(index), gdb_ptr[index])
331 class RustStdBTreeMapPrinter(object):
332 def __init__(self, val):
340 (length, data_ptr) = \
341 rustpp.extract_length_and_ptr_from_std_btreemap(self.__val)
342 return (self.__val.type.get_unqualified_type_name() +
343 ("(len: %i)" % length))
346 (length, data_ptr) = \
347 rustpp.extract_length_and_ptr_from_std_btreemap(self.__val)
348 keys = GdbValue(data_ptr.get_wrapped_value().dereference()).get_child_at_index(3)
349 keys_ptr = keys.get_wrapped_value()
350 vals = GdbValue(data_ptr.get_wrapped_value().dereference()).get_child_at_index(4)
351 vals_ptr = vals.get_wrapped_value()
352 for index in xrange(length):
353 yield (str(index), keys_ptr[index])
354 yield (str(index), vals_ptr[index])
357 class RustStdStringPrinter(object):
358 def __init__(self, val):
362 vec = self.__val.get_child_at_index(0)
363 (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(vec)
364 return data_ptr.get_wrapped_value().lazy_string(encoding="utf-8",
367 def display_hint(self):
371 class RustOsStringPrinter(object):
372 def __init__(self, val):
376 buf = self.__val.get_child_at_index(0)
377 vec = buf.get_child_at_index(0)
378 if vec.type.get_unqualified_type_name() == "Wtf8Buf":
379 vec = vec.get_child_at_index(0)
381 (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(
383 return data_ptr.get_wrapped_value().lazy_string(length=length)
385 def display_hint(self):
388 class RustCStyleVariantPrinter(object):
389 def __init__(self, val):
390 assert val.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_ENUM
394 return str(self.__val.get_wrapped_value())
397 class IdentityPrinter(object):
398 def __init__(self, string):
405 def get_field_at_index(gdb_val, index):
407 for field in gdb_val.type.fields():