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