]> git.lizzy.rs Git - rust.git/blob - src/etc/gdb_rust_pretty_printing.py
Rollup merge of #53413 - eddyb:featured-in-the-latest-edition, r=varkor
[rust.git] / src / etc / gdb_rust_pretty_printing.py
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.
4 #
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.
10
11 import gdb
12 import re
13 import sys
14 import debugger_pretty_printers_common as rustpp
15
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:
20     xrange = range
21
22 #===============================================================================
23 # GDB Pretty Printing Module for Rust
24 #===============================================================================
25
26 class GdbType(rustpp.Type):
27
28     def __init__(self, ty):
29         super(GdbType, self).__init__()
30         self.ty = ty
31         self.fields = None
32
33     def get_unqualified_type_name(self):
34         tag = self.ty.tag
35
36         if tag is None:
37             return tag
38
39         return rustpp.extract_type_name(tag).replace("&'static ", "&")
40
41     def get_dwarf_type_kind(self):
42         if self.ty.code == gdb.TYPE_CODE_STRUCT:
43             return rustpp.DWARF_TYPE_CODE_STRUCT
44
45         if self.ty.code == gdb.TYPE_CODE_UNION:
46             return rustpp.DWARF_TYPE_CODE_UNION
47
48         if self.ty.code == gdb.TYPE_CODE_PTR:
49             return rustpp.DWARF_TYPE_CODE_PTR
50
51         if self.ty.code == gdb.TYPE_CODE_ENUM:
52             return rustpp.DWARF_TYPE_CODE_ENUM
53
54     def get_fields(self):
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())
59         return self.fields
60
61     def get_wrapped_value(self):
62         return self.ty
63
64
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
69         self.children = {}
70
71     def get_child_at_index(self, index):
72         child = self.children.get(index)
73         if child is None:
74             gdb_field = get_field_at_index(self.gdb_val, index)
75             child = GdbValue(self.gdb_val[gdb_field])
76             self.children[index] = child
77         return child
78
79     def as_integer(self):
80         if self.gdb_val.type.code == gdb.TYPE_CODE_PTR:
81             as_str = rustpp.compat_str(self.gdb_val).split()[0]
82             return int(as_str, 0)
83         return int(self.gdb_val)
84
85     def get_wrapped_value(self):
86         return self.gdb_val
87
88
89 def register_printers(objfile):
90     """Registers Rust pretty printers for the given objfile"""
91     objfile.pretty_printers.append(rust_pretty_printer_lookup_function)
92
93
94 def rust_pretty_printer_lookup_function(gdb_val):
95     """
96     Returns the correct Rust pretty printer for the given value
97     if there is one
98     """
99
100     val = GdbValue(gdb_val)
101     type_kind = val.type.get_type_kind()
102
103     if type_kind == rustpp.TYPE_KIND_EMPTY:
104         return RustEmptyPrinter(val)
105
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)
111
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)
117
118     if type_kind == rustpp.TYPE_KIND_SLICE:
119         return RustSlicePrinter(val)
120
121     if type_kind == rustpp.TYPE_KIND_STR_SLICE:
122         return RustStringSlicePrinter(val)
123
124     if type_kind == rustpp.TYPE_KIND_STD_VEC:
125         return RustStdVecPrinter(val)
126
127     if type_kind == rustpp.TYPE_KIND_STD_VECDEQUE:
128         return RustStdVecDequePrinter(val)
129
130     if type_kind == rustpp.TYPE_KIND_STD_BTREESET:
131         return RustStdBTreeSetPrinter(val)
132
133     if type_kind == rustpp.TYPE_KIND_STD_BTREEMAP:
134         return RustStdBTreeMapPrinter(val)
135
136     if type_kind == rustpp.TYPE_KIND_STD_STRING:
137         return RustStdStringPrinter(val)
138
139     if type_kind == rustpp.TYPE_KIND_OS_STRING:
140         return RustOsStringPrinter(val)
141
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)
147
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)
153
154     if type_kind == rustpp.TYPE_KIND_CSTYLE_VARIANT:
155         return RustCStyleVariantPrinter(val.get_child_at_index(0))
156
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)
162
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])
166
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])
172
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())
177
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())
180
181     # No pretty printer has been found
182     return None
183
184
185 #=------------------------------------------------------------------------------
186 # Pretty Printer Classes
187 #=------------------------------------------------------------------------------
188 class RustEmptyPrinter(object):
189     def __init__(self, val):
190         self.__val = val
191
192     def to_string(self):
193         return self.__val.type.get_unqualified_type_name()
194
195
196 class RustStructPrinter(object):
197     def __init__(self, val, omit_first_field, omit_type_name, is_tuple_like):
198         self.__val = val
199         self.__omit_first_field = omit_first_field
200         self.__omit_type_name = omit_type_name
201         self.__is_tuple_like = is_tuple_like
202
203     def to_string(self):
204         if self.__omit_type_name:
205             return None
206         return self.__val.type.get_unqualified_type_name()
207
208     def children(self):
209         cs = []
210         wrapped_value = self.__val.get_wrapped_value()
211
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))
216             else:
217                 cs.append((field.name, field_value))
218
219         if self.__omit_first_field:
220             cs = cs[1:]
221
222         return cs
223
224     def display_hint(self):
225         if self.__is_tuple_like:
226             return "array"
227         else:
228             return ""
229
230
231 class RustSlicePrinter(object):
232     def __init__(self, val):
233         self.__val = val
234
235     @staticmethod
236     def display_hint():
237         return "array"
238
239     def to_string(self):
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))
243
244     def children(self):
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()
248
249         for index in xrange(0, length):
250             yield (str(index), (raw_ptr + index).dereference())
251
252
253 class RustStringSlicePrinter(object):
254     def __init__(self, val):
255         self.__val = val
256
257     def to_string(self):
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)
261
262     def display_hint(self):
263         return "string"
264
265
266 class RustStdVecPrinter(object):
267     def __init__(self, val):
268         self.__val = val
269
270     @staticmethod
271     def display_hint():
272         return "array"
273
274     def to_string(self):
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)))
278
279     def children(self):
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())
284
285
286 class RustStdVecDequePrinter(object):
287     def __init__(self, val):
288         self.__val = val
289
290     @staticmethod
291     def display_hint():
292         return "array"
293
294     def to_string(self):
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)))
299
300     def children(self):
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())
306
307
308 class RustStdBTreeSetPrinter(object):
309     def __init__(self, val):
310         self.__val = val
311
312     @staticmethod
313     def display_hint():
314         return "array"
315
316     def to_string(self):
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))
321
322     def children(self):
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])
329
330
331 class RustStdBTreeMapPrinter(object):
332     def __init__(self, val):
333         self.__val = val
334
335     @staticmethod
336     def display_hint():
337         return "map"
338
339     def to_string(self):
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))
344
345     def children(self):
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])
355
356
357 class RustStdStringPrinter(object):
358     def __init__(self, val):
359         self.__val = val
360
361     def to_string(self):
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",
365                                                         length=length)
366
367     def display_hint(self):
368         return "string"
369
370
371 class RustOsStringPrinter(object):
372     def __init__(self, val):
373         self.__val = val
374
375     def to_string(self):
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)
380
381         (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(
382             vec)
383         return data_ptr.get_wrapped_value().lazy_string(length=length)
384
385     def display_hint(self):
386         return "string"
387
388 class RustCStyleVariantPrinter(object):
389     def __init__(self, val):
390         assert val.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_ENUM
391         self.__val = val
392
393     def to_string(self):
394         return str(self.__val.get_wrapped_value())
395
396
397 class IdentityPrinter(object):
398     def __init__(self, string):
399         self.string = string
400
401     def to_string(self):
402         return self.string
403
404
405 def get_field_at_index(gdb_val, index):
406     i = 0
407     for field in gdb_val.type.fields():
408         if i == index:
409             return field
410         i += 1
411     return None