]> git.lizzy.rs Git - rust.git/blob - src/etc/debugger_pretty_printers_common.py
Rollup merge of #56214 - scalexm:unification, r=nikomatsakis
[rust.git] / src / etc / debugger_pretty_printers_common.py
1 # Copyright 2015 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 """
12 This module provides an abstraction layer over common Rust pretty printing
13 functionality needed by both GDB and LLDB.
14 """
15
16 import re
17
18 # Type codes that indicate the kind of type as it appears in DWARF debug
19 # information. This code alone is not sufficient to determine the Rust type.
20 # For example structs, tuples, fat pointers, or enum variants will all have
21 # DWARF_TYPE_CODE_STRUCT.
22 DWARF_TYPE_CODE_STRUCT = 1
23 DWARF_TYPE_CODE_UNION  = 2
24 DWARF_TYPE_CODE_PTR    = 3
25 DWARF_TYPE_CODE_ARRAY  = 4
26 DWARF_TYPE_CODE_ENUM   = 5
27
28 # These constants specify the most specific kind of type that could be
29 # determined for a given value.
30 TYPE_KIND_UNKNOWN           = -1
31 TYPE_KIND_EMPTY             = 0
32 TYPE_KIND_SLICE             = 1
33 TYPE_KIND_REGULAR_STRUCT    = 2
34 TYPE_KIND_TUPLE             = 3
35 TYPE_KIND_TUPLE_STRUCT      = 4
36 TYPE_KIND_CSTYLE_VARIANT    = 5
37 TYPE_KIND_TUPLE_VARIANT     = 6
38 TYPE_KIND_STRUCT_VARIANT    = 7
39 TYPE_KIND_STR_SLICE         = 8
40 TYPE_KIND_STD_VEC           = 9
41 TYPE_KIND_STD_STRING        = 10
42 TYPE_KIND_REGULAR_ENUM      = 11
43 TYPE_KIND_COMPRESSED_ENUM   = 12
44 TYPE_KIND_SINGLETON_ENUM    = 13
45 TYPE_KIND_CSTYLE_ENUM       = 14
46 TYPE_KIND_PTR               = 15
47 TYPE_KIND_FIXED_SIZE_VEC    = 16
48 TYPE_KIND_REGULAR_UNION     = 17
49 TYPE_KIND_OS_STRING         = 18
50 TYPE_KIND_STD_VECDEQUE      = 19
51 TYPE_KIND_STD_BTREESET      = 20
52 TYPE_KIND_STD_BTREEMAP      = 21
53
54 ENCODED_ENUM_PREFIX = "RUST$ENCODED$ENUM$"
55 ENUM_DISR_FIELD_NAME = "RUST$ENUM$DISR"
56
57 # Slice related constants
58 SLICE_FIELD_NAME_DATA_PTR = "data_ptr"
59 SLICE_FIELD_NAME_LENGTH = "length"
60 SLICE_FIELD_NAMES = [SLICE_FIELD_NAME_DATA_PTR, SLICE_FIELD_NAME_LENGTH]
61
62 # std::Vec<> related constants
63 STD_VEC_FIELD_NAME_LENGTH = "len"
64 STD_VEC_FIELD_NAME_BUF = "buf"
65 STD_VEC_FIELD_NAMES = [STD_VEC_FIELD_NAME_BUF,
66                        STD_VEC_FIELD_NAME_LENGTH]
67
68 # std::collections::VecDeque<> related constants
69 STD_VECDEQUE_FIELD_NAME_TAIL = "tail"
70 STD_VECDEQUE_FIELD_NAME_HEAD = "head"
71 STD_VECDEQUE_FIELD_NAME_BUF = "buf"
72 STD_VECDEQUE_FIELD_NAMES = [STD_VECDEQUE_FIELD_NAME_TAIL,
73                             STD_VECDEQUE_FIELD_NAME_HEAD,
74                             STD_VECDEQUE_FIELD_NAME_BUF]
75
76 # std::collections::BTreeSet<> related constants
77 STD_BTREESET_FIELD_NAMES = ["map"]
78
79 # std::collections::BTreeMap<> related constants
80 STD_BTREEMAP_FIELD_NAMES = ["root", "length"]
81
82 # std::String related constants
83 STD_STRING_FIELD_NAMES = ["vec"]
84
85 # std::ffi::OsString related constants
86 OS_STRING_FIELD_NAMES = ["inner"]
87
88
89 class Type(object):
90     """
91     This class provides a common interface for type-oriented operations.
92     Sub-classes are supposed to wrap a debugger-specific type-object and
93     provide implementations for the abstract methods in this class.
94     """
95
96     def __init__(self):
97         self.__type_kind = None
98
99     def get_unqualified_type_name(self):
100         """
101         Implementations of this method should return the unqualified name of the
102         type-object they are wrapping. Some examples:
103
104         'int' -> 'int'
105         'std::vec::Vec<std::string::String>' -> 'Vec<std::string::String>'
106         '&std::option::Option<std::string::String>' -> '&std::option::Option<std::string::String>'
107
108         As you can see, type arguments stay fully qualified.
109         """
110         raise NotImplementedError("Override this method")
111
112     def get_dwarf_type_kind(self):
113         """
114         Implementations of this method should return the correct
115         DWARF_TYPE_CODE_* value for the wrapped type-object.
116         """
117         raise NotImplementedError("Override this method")
118
119     def get_fields(self):
120         """
121         Implementations of this method should return a list of field-objects of
122         this type. For Rust-enums (i.e. with DWARF_TYPE_CODE_UNION) these field-
123         objects represent the variants of the enum. Field-objects must have a
124         `name` attribute that gives their name as specified in DWARF.
125         """
126         assert ((self.get_dwarf_type_kind() == DWARF_TYPE_CODE_STRUCT) or
127                 (self.get_dwarf_type_kind() == DWARF_TYPE_CODE_UNION))
128         raise NotImplementedError("Override this method")
129
130     def get_wrapped_value(self):
131         """
132         Returns the debugger-specific type-object wrapped by this object. This
133         is sometimes needed for doing things like pointer-arithmetic in GDB.
134         """
135         raise NotImplementedError("Override this method")
136
137     def get_type_kind(self):
138         """This method returns the TYPE_KIND_* value for this type-object."""
139         if self.__type_kind is None:
140             dwarf_type_code = self.get_dwarf_type_kind()
141
142             if dwarf_type_code == DWARF_TYPE_CODE_STRUCT:
143                 self.__type_kind = self.__classify_struct()
144             elif dwarf_type_code == DWARF_TYPE_CODE_UNION:
145                 self.__type_kind = self.__classify_union()
146             elif dwarf_type_code == DWARF_TYPE_CODE_PTR:
147                 self.__type_kind = TYPE_KIND_PTR
148             elif dwarf_type_code == DWARF_TYPE_CODE_ARRAY:
149                 self.__type_kind = TYPE_KIND_FIXED_SIZE_VEC
150             else:
151                 self.__type_kind = TYPE_KIND_UNKNOWN
152         return self.__type_kind
153
154     def __classify_struct(self):
155         assert self.get_dwarf_type_kind() == DWARF_TYPE_CODE_STRUCT
156
157         unqualified_type_name = self.get_unqualified_type_name()
158
159         # STR SLICE
160         if unqualified_type_name == "&str":
161             return TYPE_KIND_STR_SLICE
162
163         # REGULAR SLICE
164         if (unqualified_type_name.startswith(("&[", "&mut [")) and
165             unqualified_type_name.endswith("]") and
166             self.__conforms_to_field_layout(SLICE_FIELD_NAMES)):
167             return TYPE_KIND_SLICE
168
169         fields = self.get_fields()
170         field_count = len(fields)
171
172         # EMPTY STRUCT
173         if field_count == 0:
174             return TYPE_KIND_EMPTY
175
176         # STD VEC
177         if (unqualified_type_name.startswith("Vec<") and
178             self.__conforms_to_field_layout(STD_VEC_FIELD_NAMES)):
179             return TYPE_KIND_STD_VEC
180
181         # STD COLLECTION VECDEQUE
182         if (unqualified_type_name.startswith("VecDeque<") and
183             self.__conforms_to_field_layout(STD_VECDEQUE_FIELD_NAMES)):
184             return TYPE_KIND_STD_VECDEQUE
185
186         # STD COLLECTION BTREESET
187         if (unqualified_type_name.startswith("BTreeSet<") and
188                 self.__conforms_to_field_layout(STD_BTREESET_FIELD_NAMES)):
189             return TYPE_KIND_STD_BTREESET
190
191         # STD COLLECTION BTREEMAP
192         if (unqualified_type_name.startswith("BTreeMap<") and
193                 self.__conforms_to_field_layout(STD_BTREEMAP_FIELD_NAMES)):
194             return TYPE_KIND_STD_BTREEMAP
195
196         # STD STRING
197         if (unqualified_type_name.startswith("String") and
198             self.__conforms_to_field_layout(STD_STRING_FIELD_NAMES)):
199             return TYPE_KIND_STD_STRING
200
201         # OS STRING
202         if (unqualified_type_name == "OsString" and
203             self.__conforms_to_field_layout(OS_STRING_FIELD_NAMES)):
204             return TYPE_KIND_OS_STRING
205
206         # ENUM VARIANTS
207         if fields[0].name == ENUM_DISR_FIELD_NAME:
208             if field_count == 1:
209                 return TYPE_KIND_CSTYLE_VARIANT
210             elif self.__all_fields_conform_to_tuple_field_naming(1):
211                 return TYPE_KIND_TUPLE_VARIANT
212             else:
213                 return TYPE_KIND_STRUCT_VARIANT
214
215         # TUPLE
216         if self.__all_fields_conform_to_tuple_field_naming(0):
217             if unqualified_type_name.startswith("("):
218                 return TYPE_KIND_TUPLE
219             else:
220                 return TYPE_KIND_TUPLE_STRUCT
221
222         # REGULAR STRUCT
223         return TYPE_KIND_REGULAR_STRUCT
224
225
226     def __classify_union(self):
227         assert self.get_dwarf_type_kind() == DWARF_TYPE_CODE_UNION
228
229         union_members = self.get_fields()
230         union_member_count = len(union_members)
231         if union_member_count == 0:
232             return TYPE_KIND_EMPTY
233
234         first_variant_name = union_members[0].name
235         if first_variant_name is None:
236             if union_member_count == 1:
237                 return TYPE_KIND_SINGLETON_ENUM
238             else:
239                 return TYPE_KIND_REGULAR_ENUM
240         elif first_variant_name.startswith(ENCODED_ENUM_PREFIX):
241             assert union_member_count == 1
242             return TYPE_KIND_COMPRESSED_ENUM
243         else:
244             return TYPE_KIND_REGULAR_UNION
245
246
247     def __conforms_to_field_layout(self, expected_fields):
248         actual_fields = self.get_fields()
249         actual_field_count = len(actual_fields)
250
251         if actual_field_count != len(expected_fields):
252             return False
253
254         for i in range(0, actual_field_count):
255             if actual_fields[i].name != expected_fields[i]:
256                 return False
257
258         return True
259
260     def __all_fields_conform_to_tuple_field_naming(self, start_index):
261         fields = self.get_fields()
262         field_count = len(fields)
263
264         for i in range(start_index, field_count):
265             field_name = fields[i].name
266             if (field_name is None) or (re.match(r"__\d+$", field_name) is None):
267                 return False
268         return True
269
270
271 class Value(object):
272     """
273     This class provides a common interface for value-oriented operations.
274     Sub-classes are supposed to wrap a debugger-specific value-object and
275     provide implementations for the abstract methods in this class.
276     """
277     def __init__(self, ty):
278         self.type = ty
279
280     def get_child_at_index(self, index):
281         """Returns the value of the field, array element or variant at the given index"""
282         raise NotImplementedError("Override this method")
283
284     def as_integer(self):
285         """
286         Try to convert the wrapped value into a Python integer. This should
287         always succeed for values that are pointers or actual integers.
288         """
289         raise NotImplementedError("Override this method")
290
291     def get_wrapped_value(self):
292         """
293         Returns the debugger-specific value-object wrapped by this object. This
294         is sometimes needed for doing things like pointer-arithmetic in GDB.
295         """
296         raise NotImplementedError("Override this method")
297
298
299 class EncodedEnumInfo(object):
300     """
301     This class provides facilities for handling enum values with compressed
302     encoding where a non-null field in one variant doubles as the discriminant.
303     """
304
305     def __init__(self, enum_val):
306         assert enum_val.type.get_type_kind() == TYPE_KIND_COMPRESSED_ENUM
307         variant_name = enum_val.type.get_fields()[0].name
308         last_separator_index = variant_name.rfind("$")
309         start_index = len(ENCODED_ENUM_PREFIX)
310         indices_substring = variant_name[start_index:last_separator_index].split("$")
311         self.__enum_val = enum_val
312         self.__disr_field_indices = [int(index) for index in indices_substring]
313         self.__null_variant_name = variant_name[last_separator_index + 1:]
314
315     def is_null_variant(self):
316         ty = self.__enum_val.type
317         sole_variant_val = self.__enum_val.get_child_at_index(0)
318         discriminant_val = sole_variant_val
319         for disr_field_index in self.__disr_field_indices:
320             discriminant_val = discriminant_val.get_child_at_index(disr_field_index)
321
322         # If the discriminant field is a fat pointer we have to consider the
323         # first word as the true discriminant
324         if discriminant_val.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_STRUCT:
325             discriminant_val = discriminant_val.get_child_at_index(0)
326
327         return discriminant_val.as_integer() == 0
328
329     def get_non_null_variant_val(self):
330         return self.__enum_val.get_child_at_index(0)
331
332     def get_null_variant_name(self):
333         return self.__null_variant_name
334
335
336 def get_discriminant_value_as_integer(enum_val):
337     assert enum_val.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_UNION
338     # we can take any variant here because the discriminant has to be the same
339     # for all of them.
340     variant_val = enum_val.get_child_at_index(0)
341     disr_val = variant_val.get_child_at_index(0)
342     return disr_val.as_integer()
343
344
345 def extract_length_ptr_and_cap_from_std_vec(vec_val):
346     assert vec_val.type.get_type_kind() == TYPE_KIND_STD_VEC
347     length_field_index = STD_VEC_FIELD_NAMES.index(STD_VEC_FIELD_NAME_LENGTH)
348     buf_field_index = STD_VEC_FIELD_NAMES.index(STD_VEC_FIELD_NAME_BUF)
349
350     length = vec_val.get_child_at_index(length_field_index).as_integer()
351     buf = vec_val.get_child_at_index(buf_field_index)
352
353     vec_ptr_val = buf.get_child_at_index(0)
354     capacity = buf.get_child_at_index(1).as_integer()
355     unique_ptr_val = vec_ptr_val.get_child_at_index(0)
356     data_ptr = unique_ptr_val.get_child_at_index(0)
357     assert data_ptr.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR
358     return (length, data_ptr, capacity)
359
360
361 def extract_tail_head_ptr_and_cap_from_std_vecdeque(vec_val):
362     assert vec_val.type.get_type_kind() == TYPE_KIND_STD_VECDEQUE
363     tail_field_index = STD_VECDEQUE_FIELD_NAMES.index(STD_VECDEQUE_FIELD_NAME_TAIL)
364     head_field_index = STD_VECDEQUE_FIELD_NAMES.index(STD_VECDEQUE_FIELD_NAME_HEAD)
365     buf_field_index = STD_VECDEQUE_FIELD_NAMES.index(STD_VECDEQUE_FIELD_NAME_BUF)
366
367     tail = vec_val.get_child_at_index(tail_field_index).as_integer()
368     head = vec_val.get_child_at_index(head_field_index).as_integer()
369     buf = vec_val.get_child_at_index(buf_field_index)
370
371     vec_ptr_val = buf.get_child_at_index(0)
372     capacity = buf.get_child_at_index(1).as_integer()
373     unique_ptr_val = vec_ptr_val.get_child_at_index(0)
374     data_ptr = unique_ptr_val.get_child_at_index(0)
375     assert data_ptr.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR
376     return (tail, head, data_ptr, capacity)
377
378 def extract_length_and_ptr_from_slice(slice_val):
379     assert (slice_val.type.get_type_kind() == TYPE_KIND_SLICE or
380             slice_val.type.get_type_kind() == TYPE_KIND_STR_SLICE)
381
382     length_field_index = SLICE_FIELD_NAMES.index(SLICE_FIELD_NAME_LENGTH)
383     ptr_field_index = SLICE_FIELD_NAMES.index(SLICE_FIELD_NAME_DATA_PTR)
384
385     length = slice_val.get_child_at_index(length_field_index).as_integer()
386     data_ptr = slice_val.get_child_at_index(ptr_field_index)
387
388     assert data_ptr.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR
389     return (length, data_ptr)
390
391 UNQUALIFIED_TYPE_MARKERS = frozenset(["(", "[", "&", "*"])
392
393 def extract_type_name(qualified_type_name):
394     """Extracts the type name from a fully qualified path"""
395     if qualified_type_name[0] in UNQUALIFIED_TYPE_MARKERS:
396         return qualified_type_name
397
398     end_of_search = qualified_type_name.find("<")
399     if end_of_search < 0:
400         end_of_search = len(qualified_type_name)
401
402     index = qualified_type_name.rfind("::", 0, end_of_search)
403     if index < 0:
404         return qualified_type_name
405     else:
406         return qualified_type_name[index + 2:]
407
408 try:
409     compat_str = unicode  # Python 2
410 except NameError:
411     compat_str = str