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
52 ENCODED_ENUM_PREFIX = "RUST$ENCODED$ENUM$"
53 ENUM_DISR_FIELD_NAME = "RUST$ENUM$DISR"
55 # Slice related constants
56 SLICE_FIELD_NAME_DATA_PTR = "data_ptr"
57 SLICE_FIELD_NAME_LENGTH = "length"
58 SLICE_FIELD_NAMES = [SLICE_FIELD_NAME_DATA_PTR, SLICE_FIELD_NAME_LENGTH]
60 # std::Vec<> related constants
61 STD_VEC_FIELD_NAME_LENGTH = "len"
62 STD_VEC_FIELD_NAME_BUF = "buf"
63 STD_VEC_FIELD_NAMES = [STD_VEC_FIELD_NAME_BUF,
64 STD_VEC_FIELD_NAME_LENGTH]
66 # std::collections::VecDeque<> related constants
67 STD_VECDEQUE_FIELD_NAME_TAIL = "tail"
68 STD_VECDEQUE_FIELD_NAME_HEAD = "head"
69 STD_VECDEQUE_FIELD_NAME_BUF = "buf"
70 STD_VECDEQUE_FIELD_NAMES = [STD_VECDEQUE_FIELD_NAME_TAIL,
71 STD_VECDEQUE_FIELD_NAME_HEAD,
72 STD_VECDEQUE_FIELD_NAME_BUF]
74 # std::String related constants
75 STD_STRING_FIELD_NAMES = ["vec"]
77 # std::ffi::OsString related constants
78 OS_STRING_FIELD_NAMES = ["inner"]
83 This class provides a common interface for type-oriented operations.
84 Sub-classes are supposed to wrap a debugger-specific type-object and
85 provide implementations for the abstract methods in this class.
89 self.__type_kind = None
91 def get_unqualified_type_name(self):
93 Implementations of this method should return the unqualified name of the
94 type-object they are wrapping. Some examples:
97 'std::vec::Vec<std::string::String>' -> 'Vec<std::string::String>'
98 '&std::option::Option<std::string::String>' -> '&std::option::Option<std::string::String>'
100 As you can see, type arguments stay fully qualified.
102 raise NotImplementedError("Override this method")
104 def get_dwarf_type_kind(self):
106 Implementations of this method should return the correct
107 DWARF_TYPE_CODE_* value for the wrapped type-object.
109 raise NotImplementedError("Override this method")
111 def get_fields(self):
113 Implementations of this method should return a list of field-objects of
114 this type. For Rust-enums (i.e. with DWARF_TYPE_CODE_UNION) these field-
115 objects represent the variants of the enum. Field-objects must have a
116 `name` attribute that gives their name as specified in DWARF.
118 assert ((self.get_dwarf_type_kind() == DWARF_TYPE_CODE_STRUCT) or
119 (self.get_dwarf_type_kind() == DWARF_TYPE_CODE_UNION))
120 raise NotImplementedError("Override this method")
122 def get_wrapped_value(self):
124 Returns the debugger-specific type-object wrapped by this object. This
125 is sometimes needed for doing things like pointer-arithmetic in GDB.
127 raise NotImplementedError("Override this method")
129 def get_type_kind(self):
130 """This method returns the TYPE_KIND_* value for this type-object."""
131 if self.__type_kind is None:
132 dwarf_type_code = self.get_dwarf_type_kind()
134 if dwarf_type_code == DWARF_TYPE_CODE_STRUCT:
135 self.__type_kind = self.__classify_struct()
136 elif dwarf_type_code == DWARF_TYPE_CODE_UNION:
137 self.__type_kind = self.__classify_union()
138 elif dwarf_type_code == DWARF_TYPE_CODE_PTR:
139 self.__type_kind = TYPE_KIND_PTR
140 elif dwarf_type_code == DWARF_TYPE_CODE_ARRAY:
141 self.__type_kind = TYPE_KIND_FIXED_SIZE_VEC
143 self.__type_kind = TYPE_KIND_UNKNOWN
144 return self.__type_kind
146 def __classify_struct(self):
147 assert self.get_dwarf_type_kind() == DWARF_TYPE_CODE_STRUCT
149 unqualified_type_name = self.get_unqualified_type_name()
152 if unqualified_type_name == "&str":
153 return TYPE_KIND_STR_SLICE
156 if (unqualified_type_name.startswith(("&[", "&mut [")) and
157 unqualified_type_name.endswith("]") and
158 self.__conforms_to_field_layout(SLICE_FIELD_NAMES)):
159 return TYPE_KIND_SLICE
161 fields = self.get_fields()
162 field_count = len(fields)
166 return TYPE_KIND_EMPTY
169 if (unqualified_type_name.startswith("Vec<") and
170 self.__conforms_to_field_layout(STD_VEC_FIELD_NAMES)):
171 return TYPE_KIND_STD_VEC
173 # STD COLLECTION VECDEQUE
174 if (unqualified_type_name.startswith("VecDeque<") and
175 self.__conforms_to_field_layout(STD_VECDEQUE_FIELD_NAMES)):
176 return TYPE_KIND_STD_VECDEQUE
179 if (unqualified_type_name.startswith("String") and
180 self.__conforms_to_field_layout(STD_STRING_FIELD_NAMES)):
181 return TYPE_KIND_STD_STRING
184 if (unqualified_type_name == "OsString" and
185 self.__conforms_to_field_layout(OS_STRING_FIELD_NAMES)):
186 return TYPE_KIND_OS_STRING
189 if fields[0].name == ENUM_DISR_FIELD_NAME:
191 return TYPE_KIND_CSTYLE_VARIANT
192 elif self.__all_fields_conform_to_tuple_field_naming(1):
193 return TYPE_KIND_TUPLE_VARIANT
195 return TYPE_KIND_STRUCT_VARIANT
198 if self.__all_fields_conform_to_tuple_field_naming(0):
199 if unqualified_type_name.startswith("("):
200 return TYPE_KIND_TUPLE
202 return TYPE_KIND_TUPLE_STRUCT
205 return TYPE_KIND_REGULAR_STRUCT
208 def __classify_union(self):
209 assert self.get_dwarf_type_kind() == DWARF_TYPE_CODE_UNION
211 union_members = self.get_fields()
212 union_member_count = len(union_members)
213 if union_member_count == 0:
214 return TYPE_KIND_EMPTY
216 first_variant_name = union_members[0].name
217 if first_variant_name is None:
218 if union_member_count == 1:
219 return TYPE_KIND_SINGLETON_ENUM
221 return TYPE_KIND_REGULAR_ENUM
222 elif first_variant_name.startswith(ENCODED_ENUM_PREFIX):
223 assert union_member_count == 1
224 return TYPE_KIND_COMPRESSED_ENUM
226 return TYPE_KIND_REGULAR_UNION
229 def __conforms_to_field_layout(self, expected_fields):
230 actual_fields = self.get_fields()
231 actual_field_count = len(actual_fields)
233 if actual_field_count != len(expected_fields):
236 for i in range(0, actual_field_count):
237 if actual_fields[i].name != expected_fields[i]:
242 def __all_fields_conform_to_tuple_field_naming(self, start_index):
243 fields = self.get_fields()
244 field_count = len(fields)
246 for i in range(start_index, field_count):
247 field_name = fields[i].name
248 if (field_name is None) or (re.match(r"__\d+$", field_name) is None):
255 This class provides a common interface for value-oriented operations.
256 Sub-classes are supposed to wrap a debugger-specific value-object and
257 provide implementations for the abstract methods in this class.
259 def __init__(self, ty):
262 def get_child_at_index(self, index):
263 """Returns the value of the field, array element or variant at the given index"""
264 raise NotImplementedError("Override this method")
266 def as_integer(self):
268 Try to convert the wrapped value into a Python integer. This should
269 always succeed for values that are pointers or actual integers.
271 raise NotImplementedError("Override this method")
273 def get_wrapped_value(self):
275 Returns the debugger-specific value-object wrapped by this object. This
276 is sometimes needed for doing things like pointer-arithmetic in GDB.
278 raise NotImplementedError("Override this method")
281 class EncodedEnumInfo(object):
283 This class provides facilities for handling enum values with compressed
284 encoding where a non-null field in one variant doubles as the discriminant.
287 def __init__(self, enum_val):
288 assert enum_val.type.get_type_kind() == TYPE_KIND_COMPRESSED_ENUM
289 variant_name = enum_val.type.get_fields()[0].name
290 last_separator_index = variant_name.rfind("$")
291 start_index = len(ENCODED_ENUM_PREFIX)
292 indices_substring = variant_name[start_index:last_separator_index].split("$")
293 self.__enum_val = enum_val
294 self.__disr_field_indices = [int(index) for index in indices_substring]
295 self.__null_variant_name = variant_name[last_separator_index + 1:]
297 def is_null_variant(self):
298 ty = self.__enum_val.type
299 sole_variant_val = self.__enum_val.get_child_at_index(0)
300 discriminant_val = sole_variant_val
301 for disr_field_index in self.__disr_field_indices:
302 discriminant_val = discriminant_val.get_child_at_index(disr_field_index)
304 # If the discriminant field is a fat pointer we have to consider the
305 # first word as the true discriminant
306 if discriminant_val.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_STRUCT:
307 discriminant_val = discriminant_val.get_child_at_index(0)
309 return discriminant_val.as_integer() == 0
311 def get_non_null_variant_val(self):
312 return self.__enum_val.get_child_at_index(0)
314 def get_null_variant_name(self):
315 return self.__null_variant_name
318 def get_discriminant_value_as_integer(enum_val):
319 assert enum_val.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_UNION
320 # we can take any variant here because the discriminant has to be the same
322 variant_val = enum_val.get_child_at_index(0)
323 disr_val = variant_val.get_child_at_index(0)
324 return disr_val.as_integer()
327 def extract_length_ptr_and_cap_from_std_vec(vec_val):
328 assert vec_val.type.get_type_kind() == TYPE_KIND_STD_VEC
329 length_field_index = STD_VEC_FIELD_NAMES.index(STD_VEC_FIELD_NAME_LENGTH)
330 buf_field_index = STD_VEC_FIELD_NAMES.index(STD_VEC_FIELD_NAME_BUF)
332 length = vec_val.get_child_at_index(length_field_index).as_integer()
333 buf = vec_val.get_child_at_index(buf_field_index)
335 vec_ptr_val = buf.get_child_at_index(0)
336 capacity = buf.get_child_at_index(1).as_integer()
337 unique_ptr_val = vec_ptr_val.get_child_at_index(0)
338 data_ptr = unique_ptr_val.get_child_at_index(0)
339 assert data_ptr.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR
340 return (length, data_ptr, capacity)
343 def extract_tail_head_ptr_and_cap_from_std_vecdeque(vec_val):
344 assert vec_val.type.get_type_kind() == TYPE_KIND_STD_VECDEQUE
345 tail_field_index = STD_VECDEQUE_FIELD_NAMES.index(STD_VECDEQUE_FIELD_NAME_TAIL)
346 head_field_index = STD_VECDEQUE_FIELD_NAMES.index(STD_VECDEQUE_FIELD_NAME_HEAD)
347 buf_field_index = STD_VECDEQUE_FIELD_NAMES.index(STD_VECDEQUE_FIELD_NAME_BUF)
349 tail = vec_val.get_child_at_index(tail_field_index).as_integer()
350 head = vec_val.get_child_at_index(head_field_index).as_integer()
351 buf = vec_val.get_child_at_index(buf_field_index)
353 vec_ptr_val = buf.get_child_at_index(0)
354 capacity = buf.get_child_at_index(1).as_integer()
355 unique_ptr_val = vec_ptr_val.get_child_at_index(0)
356 data_ptr = unique_ptr_val.get_child_at_index(0)
357 assert data_ptr.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR
358 return (tail, head, data_ptr, capacity)
361 def extract_length_and_ptr_from_slice(slice_val):
362 assert (slice_val.type.get_type_kind() == TYPE_KIND_SLICE or
363 slice_val.type.get_type_kind() == TYPE_KIND_STR_SLICE)
365 length_field_index = SLICE_FIELD_NAMES.index(SLICE_FIELD_NAME_LENGTH)
366 ptr_field_index = SLICE_FIELD_NAMES.index(SLICE_FIELD_NAME_DATA_PTR)
368 length = slice_val.get_child_at_index(length_field_index).as_integer()
369 data_ptr = slice_val.get_child_at_index(ptr_field_index)
371 assert data_ptr.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR
372 return (length, data_ptr)
374 UNQUALIFIED_TYPE_MARKERS = frozenset(["(", "[", "&", "*"])
376 def extract_type_name(qualified_type_name):
377 """Extracts the type name from a fully qualified path"""
378 if qualified_type_name[0] in UNQUALIFIED_TYPE_MARKERS:
379 return qualified_type_name
381 end_of_search = qualified_type_name.find("<")
382 if end_of_search < 0:
383 end_of_search = len(qualified_type_name)
385 index = qualified_type_name.rfind("::", 0, end_of_search)
387 return qualified_type_name
389 return qualified_type_name[index + 2:]
392 compat_str = unicode # Python 2