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.
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.
12 This module provides an abstraction layer over common Rust pretty printing
13 functionality needed by both GDB and LLDB.
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
28 # These constants specify the most specific kind of type that could be
29 # determined for a given value.
30 TYPE_KIND_UNKNOWN = -1
33 TYPE_KIND_REGULAR_STRUCT = 2
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
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
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 TYPE_KIND_STD_BTREESET = 20
53 ENCODED_ENUM_PREFIX = "RUST$ENCODED$ENUM$"
54 ENUM_DISR_FIELD_NAME = "RUST$ENUM$DISR"
56 # Slice related constants
57 SLICE_FIELD_NAME_DATA_PTR = "data_ptr"
58 SLICE_FIELD_NAME_LENGTH = "length"
59 SLICE_FIELD_NAMES = [SLICE_FIELD_NAME_DATA_PTR, SLICE_FIELD_NAME_LENGTH]
61 # std::Vec<> related constants
62 STD_VEC_FIELD_NAME_LENGTH = "len"
63 STD_VEC_FIELD_NAME_BUF = "buf"
64 STD_VEC_FIELD_NAMES = [STD_VEC_FIELD_NAME_BUF,
65 STD_VEC_FIELD_NAME_LENGTH]
67 # std::collections::VecDeque<> related constants
68 STD_VECDEQUE_FIELD_NAME_TAIL = "tail"
69 STD_VECDEQUE_FIELD_NAME_HEAD = "head"
70 STD_VECDEQUE_FIELD_NAME_BUF = "buf"
71 STD_VECDEQUE_FIELD_NAMES = [STD_VECDEQUE_FIELD_NAME_TAIL,
72 STD_VECDEQUE_FIELD_NAME_HEAD,
73 STD_VECDEQUE_FIELD_NAME_BUF]
75 # std::collections::BTreeSet<> related constants
76 STD_BTREESET_FIELD_NAMES = ["map"]
78 # std::String related constants
79 STD_STRING_FIELD_NAMES = ["vec"]
81 # std::ffi::OsString related constants
82 OS_STRING_FIELD_NAMES = ["inner"]
87 This class provides a common interface for type-oriented operations.
88 Sub-classes are supposed to wrap a debugger-specific type-object and
89 provide implementations for the abstract methods in this class.
93 self.__type_kind = None
95 def get_unqualified_type_name(self):
97 Implementations of this method should return the unqualified name of the
98 type-object they are wrapping. Some examples:
101 'std::vec::Vec<std::string::String>' -> 'Vec<std::string::String>'
102 '&std::option::Option<std::string::String>' -> '&std::option::Option<std::string::String>'
104 As you can see, type arguments stay fully qualified.
106 raise NotImplementedError("Override this method")
108 def get_dwarf_type_kind(self):
110 Implementations of this method should return the correct
111 DWARF_TYPE_CODE_* value for the wrapped type-object.
113 raise NotImplementedError("Override this method")
115 def get_fields(self):
117 Implementations of this method should return a list of field-objects of
118 this type. For Rust-enums (i.e. with DWARF_TYPE_CODE_UNION) these field-
119 objects represent the variants of the enum. Field-objects must have a
120 `name` attribute that gives their name as specified in DWARF.
122 assert ((self.get_dwarf_type_kind() == DWARF_TYPE_CODE_STRUCT) or
123 (self.get_dwarf_type_kind() == DWARF_TYPE_CODE_UNION))
124 raise NotImplementedError("Override this method")
126 def get_wrapped_value(self):
128 Returns the debugger-specific type-object wrapped by this object. This
129 is sometimes needed for doing things like pointer-arithmetic in GDB.
131 raise NotImplementedError("Override this method")
133 def get_type_kind(self):
134 """This method returns the TYPE_KIND_* value for this type-object."""
135 if self.__type_kind is None:
136 dwarf_type_code = self.get_dwarf_type_kind()
138 if dwarf_type_code == DWARF_TYPE_CODE_STRUCT:
139 self.__type_kind = self.__classify_struct()
140 elif dwarf_type_code == DWARF_TYPE_CODE_UNION:
141 self.__type_kind = self.__classify_union()
142 elif dwarf_type_code == DWARF_TYPE_CODE_PTR:
143 self.__type_kind = TYPE_KIND_PTR
144 elif dwarf_type_code == DWARF_TYPE_CODE_ARRAY:
145 self.__type_kind = TYPE_KIND_FIXED_SIZE_VEC
147 self.__type_kind = TYPE_KIND_UNKNOWN
148 return self.__type_kind
150 def __classify_struct(self):
151 assert self.get_dwarf_type_kind() == DWARF_TYPE_CODE_STRUCT
153 unqualified_type_name = self.get_unqualified_type_name()
156 if unqualified_type_name == "&str":
157 return TYPE_KIND_STR_SLICE
160 if (unqualified_type_name.startswith(("&[", "&mut [")) and
161 unqualified_type_name.endswith("]") and
162 self.__conforms_to_field_layout(SLICE_FIELD_NAMES)):
163 return TYPE_KIND_SLICE
165 fields = self.get_fields()
166 field_count = len(fields)
170 return TYPE_KIND_EMPTY
173 if (unqualified_type_name.startswith("Vec<") and
174 self.__conforms_to_field_layout(STD_VEC_FIELD_NAMES)):
175 return TYPE_KIND_STD_VEC
177 # STD COLLECTION VECDEQUE
178 if (unqualified_type_name.startswith("VecDeque<") and
179 self.__conforms_to_field_layout(STD_VECDEQUE_FIELD_NAMES)):
180 return TYPE_KIND_STD_VECDEQUE
182 # STD COLLECTION BTREESET
183 if (unqualified_type_name.startswith("BTreeSet<") and
184 self.__conforms_to_field_layout(STD_BTREESET_FIELD_NAMES)):
185 return TYPE_KIND_STD_BTREESET
188 if (unqualified_type_name.startswith("String") and
189 self.__conforms_to_field_layout(STD_STRING_FIELD_NAMES)):
190 return TYPE_KIND_STD_STRING
193 if (unqualified_type_name == "OsString" and
194 self.__conforms_to_field_layout(OS_STRING_FIELD_NAMES)):
195 return TYPE_KIND_OS_STRING
198 if fields[0].name == ENUM_DISR_FIELD_NAME:
200 return TYPE_KIND_CSTYLE_VARIANT
201 elif self.__all_fields_conform_to_tuple_field_naming(1):
202 return TYPE_KIND_TUPLE_VARIANT
204 return TYPE_KIND_STRUCT_VARIANT
207 if self.__all_fields_conform_to_tuple_field_naming(0):
208 if unqualified_type_name.startswith("("):
209 return TYPE_KIND_TUPLE
211 return TYPE_KIND_TUPLE_STRUCT
214 return TYPE_KIND_REGULAR_STRUCT
217 def __classify_union(self):
218 assert self.get_dwarf_type_kind() == DWARF_TYPE_CODE_UNION
220 union_members = self.get_fields()
221 union_member_count = len(union_members)
222 if union_member_count == 0:
223 return TYPE_KIND_EMPTY
225 first_variant_name = union_members[0].name
226 if first_variant_name is None:
227 if union_member_count == 1:
228 return TYPE_KIND_SINGLETON_ENUM
230 return TYPE_KIND_REGULAR_ENUM
231 elif first_variant_name.startswith(ENCODED_ENUM_PREFIX):
232 assert union_member_count == 1
233 return TYPE_KIND_COMPRESSED_ENUM
235 return TYPE_KIND_REGULAR_UNION
238 def __conforms_to_field_layout(self, expected_fields):
239 actual_fields = self.get_fields()
240 actual_field_count = len(actual_fields)
242 if actual_field_count != len(expected_fields):
245 for i in range(0, actual_field_count):
246 if actual_fields[i].name != expected_fields[i]:
251 def __all_fields_conform_to_tuple_field_naming(self, start_index):
252 fields = self.get_fields()
253 field_count = len(fields)
255 for i in range(start_index, field_count):
256 field_name = fields[i].name
257 if (field_name is None) or (re.match(r"__\d+$", field_name) is None):
264 This class provides a common interface for value-oriented operations.
265 Sub-classes are supposed to wrap a debugger-specific value-object and
266 provide implementations for the abstract methods in this class.
268 def __init__(self, ty):
271 def get_child_at_index(self, index):
272 """Returns the value of the field, array element or variant at the given index"""
273 raise NotImplementedError("Override this method")
275 def as_integer(self):
277 Try to convert the wrapped value into a Python integer. This should
278 always succeed for values that are pointers or actual integers.
280 raise NotImplementedError("Override this method")
282 def get_wrapped_value(self):
284 Returns the debugger-specific value-object wrapped by this object. This
285 is sometimes needed for doing things like pointer-arithmetic in GDB.
287 raise NotImplementedError("Override this method")
290 class EncodedEnumInfo(object):
292 This class provides facilities for handling enum values with compressed
293 encoding where a non-null field in one variant doubles as the discriminant.
296 def __init__(self, enum_val):
297 assert enum_val.type.get_type_kind() == TYPE_KIND_COMPRESSED_ENUM
298 variant_name = enum_val.type.get_fields()[0].name
299 last_separator_index = variant_name.rfind("$")
300 start_index = len(ENCODED_ENUM_PREFIX)
301 indices_substring = variant_name[start_index:last_separator_index].split("$")
302 self.__enum_val = enum_val
303 self.__disr_field_indices = [int(index) for index in indices_substring]
304 self.__null_variant_name = variant_name[last_separator_index + 1:]
306 def is_null_variant(self):
307 ty = self.__enum_val.type
308 sole_variant_val = self.__enum_val.get_child_at_index(0)
309 discriminant_val = sole_variant_val
310 for disr_field_index in self.__disr_field_indices:
311 discriminant_val = discriminant_val.get_child_at_index(disr_field_index)
313 # If the discriminant field is a fat pointer we have to consider the
314 # first word as the true discriminant
315 if discriminant_val.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_STRUCT:
316 discriminant_val = discriminant_val.get_child_at_index(0)
318 return discriminant_val.as_integer() == 0
320 def get_non_null_variant_val(self):
321 return self.__enum_val.get_child_at_index(0)
323 def get_null_variant_name(self):
324 return self.__null_variant_name
327 def get_discriminant_value_as_integer(enum_val):
328 assert enum_val.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_UNION
329 # we can take any variant here because the discriminant has to be the same
331 variant_val = enum_val.get_child_at_index(0)
332 disr_val = variant_val.get_child_at_index(0)
333 return disr_val.as_integer()
336 def extract_length_ptr_and_cap_from_std_vec(vec_val):
337 assert vec_val.type.get_type_kind() == TYPE_KIND_STD_VEC
338 length_field_index = STD_VEC_FIELD_NAMES.index(STD_VEC_FIELD_NAME_LENGTH)
339 buf_field_index = STD_VEC_FIELD_NAMES.index(STD_VEC_FIELD_NAME_BUF)
341 length = vec_val.get_child_at_index(length_field_index).as_integer()
342 buf = vec_val.get_child_at_index(buf_field_index)
344 vec_ptr_val = buf.get_child_at_index(0)
345 capacity = buf.get_child_at_index(1).as_integer()
346 unique_ptr_val = vec_ptr_val.get_child_at_index(0)
347 data_ptr = unique_ptr_val.get_child_at_index(0)
348 assert data_ptr.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR
349 return (length, data_ptr, capacity)
352 def extract_tail_head_ptr_and_cap_from_std_vecdeque(vec_val):
353 assert vec_val.type.get_type_kind() == TYPE_KIND_STD_VECDEQUE
354 tail_field_index = STD_VECDEQUE_FIELD_NAMES.index(STD_VECDEQUE_FIELD_NAME_TAIL)
355 head_field_index = STD_VECDEQUE_FIELD_NAMES.index(STD_VECDEQUE_FIELD_NAME_HEAD)
356 buf_field_index = STD_VECDEQUE_FIELD_NAMES.index(STD_VECDEQUE_FIELD_NAME_BUF)
358 tail = vec_val.get_child_at_index(tail_field_index).as_integer()
359 head = vec_val.get_child_at_index(head_field_index).as_integer()
360 buf = vec_val.get_child_at_index(buf_field_index)
362 vec_ptr_val = buf.get_child_at_index(0)
363 capacity = buf.get_child_at_index(1).as_integer()
364 unique_ptr_val = vec_ptr_val.get_child_at_index(0)
365 data_ptr = unique_ptr_val.get_child_at_index(0)
366 assert data_ptr.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR
367 return (tail, head, data_ptr, capacity)
370 def extract_length_and_ptr_from_std_btreeset(vec_val):
371 assert vec_val.type.get_type_kind() == TYPE_KIND_STD_BTREESET
372 map = vec_val.get_child_at_index(0)
373 root = map.get_child_at_index(0)
374 length = map.get_child_at_index(1).as_integer()
375 node = root.get_child_at_index(0)
376 ptr = node.get_child_at_index(0)
377 unique_ptr_val = ptr.get_child_at_index(0)
378 data_ptr = unique_ptr_val.get_child_at_index(0)
379 assert data_ptr.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR
380 return (length, data_ptr)
383 def extract_length_and_ptr_from_slice(slice_val):
384 assert (slice_val.type.get_type_kind() == TYPE_KIND_SLICE or
385 slice_val.type.get_type_kind() == TYPE_KIND_STR_SLICE)
387 length_field_index = SLICE_FIELD_NAMES.index(SLICE_FIELD_NAME_LENGTH)
388 ptr_field_index = SLICE_FIELD_NAMES.index(SLICE_FIELD_NAME_DATA_PTR)
390 length = slice_val.get_child_at_index(length_field_index).as_integer()
391 data_ptr = slice_val.get_child_at_index(ptr_field_index)
393 assert data_ptr.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR
394 return (length, data_ptr)
396 UNQUALIFIED_TYPE_MARKERS = frozenset(["(", "[", "&", "*"])
398 def extract_type_name(qualified_type_name):
399 """Extracts the type name from a fully qualified path"""
400 if qualified_type_name[0] in UNQUALIFIED_TYPE_MARKERS:
401 return qualified_type_name
403 end_of_search = qualified_type_name.find("<")
404 if end_of_search < 0:
405 end_of_search = len(qualified_type_name)
407 index = qualified_type_name.rfind("::", 0, end_of_search)
409 return qualified_type_name
411 return qualified_type_name[index + 2:]
414 compat_str = unicode # Python 2