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