]> git.proxmox.com Git - rustc.git/blob - src/etc/debugger_pretty_printers_common.py
Imported Upstream version 1.3.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
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("&[") 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)