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