]> git.lizzy.rs Git - rust.git/blob - src/etc/gdb_rust_pretty_printing.py
Rollup merge of #53506 - phungleson:fix-from-docs-atomic, r=KodrAus
[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 rust_enabled = 'set language rust' in gdb.execute('complete set language ru', to_string = True)
23
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
28 gdb_81 = False
29 _match = re.match('([0-9]+)\\.([0-9]+)', gdb.VERSION)
30 if _match:
31     if int(_match.group(1)) > 8 or (int(_match.group(1)) == 8 and int(_match.group(2)) >= 1):
32         gdb_81 = True
33
34 #===============================================================================
35 # GDB Pretty Printing Module for Rust
36 #===============================================================================
37
38 class GdbType(rustpp.Type):
39
40     def __init__(self, ty):
41         super(GdbType, self).__init__()
42         self.ty = ty
43         self.fields = None
44
45     def get_unqualified_type_name(self):
46         tag = self.ty.tag
47
48         if tag is None:
49             return tag
50
51         return rustpp.extract_type_name(tag).replace("&'static ", "&")
52
53     def get_dwarf_type_kind(self):
54         if self.ty.code == gdb.TYPE_CODE_STRUCT:
55             return rustpp.DWARF_TYPE_CODE_STRUCT
56
57         if self.ty.code == gdb.TYPE_CODE_UNION:
58             return rustpp.DWARF_TYPE_CODE_UNION
59
60         if self.ty.code == gdb.TYPE_CODE_PTR:
61             return rustpp.DWARF_TYPE_CODE_PTR
62
63         if self.ty.code == gdb.TYPE_CODE_ENUM:
64             return rustpp.DWARF_TYPE_CODE_ENUM
65
66     def get_fields(self):
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())
71         return self.fields
72
73     def get_wrapped_value(self):
74         return self.ty
75
76
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
81         self.children = {}
82
83     def get_child_at_index(self, index):
84         child = self.children.get(index)
85         if child is None:
86             gdb_field = get_field_at_index(self.gdb_val, index)
87             child = GdbValue(self.gdb_val[gdb_field])
88             self.children[index] = child
89         return child
90
91     def as_integer(self):
92         if self.gdb_val.type.code == gdb.TYPE_CODE_PTR:
93             as_str = rustpp.compat_str(self.gdb_val).split()[0]
94             return int(as_str, 0)
95         return int(self.gdb_val)
96
97     def get_wrapped_value(self):
98         return self.gdb_val
99
100
101 def register_printers(objfile):
102     """Registers Rust pretty printers for the given objfile"""
103     objfile.pretty_printers.append(rust_pretty_printer_lookup_function)
104
105
106 def rust_pretty_printer_lookup_function(gdb_val):
107     """
108     Returns the correct Rust pretty printer for the given value
109     if there is one
110     """
111
112     val = GdbValue(gdb_val)
113     type_kind = val.type.get_type_kind()
114
115     if type_kind == rustpp.TYPE_KIND_SLICE:
116         return RustSlicePrinter(val)
117
118     if type_kind == rustpp.TYPE_KIND_STD_VEC:
119         return RustStdVecPrinter(val)
120
121     if type_kind == rustpp.TYPE_KIND_STD_VECDEQUE:
122         return RustStdVecDequePrinter(val)
123
124     if type_kind == rustpp.TYPE_KIND_STD_BTREESET and gdb_81:
125         return RustStdBTreeSetPrinter(val)
126
127     if type_kind == rustpp.TYPE_KIND_STD_BTREEMAP and gdb_81:
128         return RustStdBTreeMapPrinter(val)
129
130     if type_kind == rustpp.TYPE_KIND_STD_STRING:
131         return RustStdStringPrinter(val)
132
133     if type_kind == rustpp.TYPE_KIND_OS_STRING:
134         return RustOsStringPrinter(val)
135
136     # Checks after this point should only be for "compiler" types --
137     # things that gdb's Rust language support knows about.
138     if rust_enabled:
139         return None
140
141     if type_kind == rustpp.TYPE_KIND_EMPTY:
142         return RustEmptyPrinter(val)
143
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)
149
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)
155
156     if type_kind == rustpp.TYPE_KIND_STR_SLICE:
157         return RustStringSlicePrinter(val)
158
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)
164
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)
170
171     if type_kind == rustpp.TYPE_KIND_CSTYLE_VARIANT:
172         return RustCStyleVariantPrinter(val.get_child_at_index(0))
173
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)
179
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])
183
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])
189
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())
194
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())
197
198     # No pretty printer has been found
199     return None
200
201
202 #=------------------------------------------------------------------------------
203 # Pretty Printer Classes
204 #=------------------------------------------------------------------------------
205 class RustEmptyPrinter(object):
206     def __init__(self, val):
207         self.__val = val
208
209     def to_string(self):
210         return self.__val.type.get_unqualified_type_name()
211
212
213 class RustStructPrinter(object):
214     def __init__(self, val, omit_first_field, omit_type_name, is_tuple_like):
215         self.__val = val
216         self.__omit_first_field = omit_first_field
217         self.__omit_type_name = omit_type_name
218         self.__is_tuple_like = is_tuple_like
219
220     def to_string(self):
221         if self.__omit_type_name:
222             return None
223         return self.__val.type.get_unqualified_type_name()
224
225     def children(self):
226         cs = []
227         wrapped_value = self.__val.get_wrapped_value()
228
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))
233             else:
234                 cs.append((field.name, field_value))
235
236         if self.__omit_first_field:
237             cs = cs[1:]
238
239         return cs
240
241     def display_hint(self):
242         if self.__is_tuple_like:
243             return "array"
244         else:
245             return ""
246
247
248 class RustSlicePrinter(object):
249     def __init__(self, val):
250         self.__val = val
251
252     @staticmethod
253     def display_hint():
254         return "array"
255
256     def to_string(self):
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))
260
261     def children(self):
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()
265
266         for index in xrange(0, length):
267             yield (str(index), (raw_ptr + index).dereference())
268
269
270 class RustStringSlicePrinter(object):
271     def __init__(self, val):
272         self.__val = val
273
274     def to_string(self):
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)
278
279     def display_hint(self):
280         return "string"
281
282
283 class RustStdVecPrinter(object):
284     def __init__(self, val):
285         self.__val = val
286
287     @staticmethod
288     def display_hint():
289         return "array"
290
291     def to_string(self):
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)))
295
296     def children(self):
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())
301
302
303 class RustStdVecDequePrinter(object):
304     def __init__(self, val):
305         self.__val = val
306
307     @staticmethod
308     def display_hint():
309         return "array"
310
311     def to_string(self):
312         (tail, head, data_ptr, cap) = \
313             rustpp.extract_tail_head_ptr_and_cap_from_std_vecdeque(self.__val)
314         if head >= tail:
315             size = head - tail
316         else:
317             size = cap + head - tail
318         return (self.__val.type.get_unqualified_type_name() +
319                 ("(len: %i, cap: %i)" % (size, cap)))
320
321     def children(self):
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()
325         if head >= tail:
326             size = head - tail
327         else:
328             size = cap + head - tail
329         for index in xrange(0, size):
330             yield (str(index), (gdb_ptr + ((tail + index) % cap)).dereference())
331
332
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]]
338     if height > 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']
343     else:
344         leaf = node_ptr.dereference()
345     keys = leaf['keys']['value']['value']
346     if want_values:
347         values = leaf['vals']['value']['value']
348     length = int(leaf['len'])
349     for i in xrange(0, length + 1):
350         if height > 0:
351             for child in children_of_node(node_ptr['edges'][i], height - 1, want_values):
352                 yield child
353         if i < length:
354             if want_values:
355                 yield (keys[i], values[i])
356             else:
357                 yield keys[i]
358
359 class RustStdBTreeSetPrinter(object):
360     def __init__(self, val):
361         self.__val = val
362
363     @staticmethod
364     def display_hint():
365         return "array"
366
367     def to_string(self):
368         return (self.__val.type.get_unqualified_type_name() +
369                 ("(len: %i)" % self.__val.get_wrapped_value()['map']['length']))
370
371     def children(self):
372         root = self.__val.get_wrapped_value()['map']['root']
373         node_ptr = root['node']
374         i = 0
375         for child in children_of_node(node_ptr, root['height'], False):
376             yield (str(i), child)
377             i = i + 1
378
379
380 class RustStdBTreeMapPrinter(object):
381     def __init__(self, val):
382         self.__val = val
383
384     @staticmethod
385     def display_hint():
386         return "map"
387
388     def to_string(self):
389         return (self.__val.type.get_unqualified_type_name() +
390                 ("(len: %i)" % self.__val.get_wrapped_value()['length']))
391
392     def children(self):
393         root = self.__val.get_wrapped_value()['root']
394         node_ptr = root['node']
395         i = 0
396         for child in children_of_node(node_ptr, root['height'], True):
397             yield (str(i), child[0])
398             yield (str(i), child[1])
399             i = i + 1
400
401
402 class RustStdStringPrinter(object):
403     def __init__(self, val):
404         self.__val = val
405
406     def to_string(self):
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",
410                                                         length=length)
411
412     def display_hint(self):
413         return "string"
414
415
416 class RustOsStringPrinter(object):
417     def __init__(self, val):
418         self.__val = val
419
420     def to_string(self):
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)
425
426         (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(
427             vec)
428         return data_ptr.get_wrapped_value().lazy_string(length=length)
429
430     def display_hint(self):
431         return "string"
432
433 class RustCStyleVariantPrinter(object):
434     def __init__(self, val):
435         assert val.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_ENUM
436         self.__val = val
437
438     def to_string(self):
439         return str(self.__val.get_wrapped_value())
440
441
442 class IdentityPrinter(object):
443     def __init__(self, string):
444         self.string = string
445
446     def to_string(self):
447         return self.string
448
449
450 def get_field_at_index(gdb_val, index):
451     i = 0
452     for field in gdb_val.type.fields():
453         if i == index:
454             return field
455         i += 1
456     return None