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