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
51 ENCODED_ENUM_PREFIX
= "RUST$ENCODED$ENUM$"
52 ENUM_DISR_FIELD_NAME
= "RUST$ENUM$DISR"
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
]
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
]
65 # std::String related constants
66 STD_STRING_FIELD_NAMES
= ["vec"]
68 # std::ffi::OsString related constants
69 OS_STRING_FIELD_NAMES
= ["inner"]
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.
80 self
.__type
_kind
= None
82 def get_unqualified_type_name(self
):
84 Implementations of this method should return the unqualified name of the
85 type-object they are wrapping. Some examples:
88 'std::vec::Vec<std::string::String>' -> 'Vec<std::string::String>'
89 '&std::option::Option<std::string::String>' -> '&std::option::Option<std::string::String>'
91 As you can see, type arguments stay fully qualified.
93 raise NotImplementedError("Override this method")
95 def get_dwarf_type_kind(self
):
97 Implementations of this method should return the correct
98 DWARF_TYPE_CODE_* value for the wrapped type-object.
100 raise NotImplementedError("Override this method")
102 def get_fields(self
):
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.
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")
113 def get_wrapped_value(self
):
115 Returns the debugger-specific type-object wrapped by this object. This
116 is sometimes needed for doing things like pointer-arithmetic in GDB.
118 raise NotImplementedError("Override this method")
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()
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
134 self
.__type
_kind
= TYPE_KIND_UNKNOWN
135 return self
.__type
_kind
137 def __classify_struct(self
):
138 assert self
.get_dwarf_type_kind() == DWARF_TYPE_CODE_STRUCT
140 unqualified_type_name
= self
.get_unqualified_type_name()
143 if unqualified_type_name
== "&str":
144 return TYPE_KIND_STR_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
152 fields
= self
.get_fields()
153 field_count
= len(fields
)
157 return TYPE_KIND_EMPTY
160 if (unqualified_type_name
.startswith("Vec<") and
161 self
.__conforms
_to
_field
_layout
(STD_VEC_FIELD_NAMES
)):
162 return TYPE_KIND_STD_VEC
165 if (unqualified_type_name
.startswith("String") and
166 self
.__conforms
_to
_field
_layout
(STD_STRING_FIELD_NAMES
)):
167 return TYPE_KIND_STD_STRING
170 if (unqualified_type_name
== "OsString" and
171 self
.__conforms
_to
_field
_layout
(OS_STRING_FIELD_NAMES
)):
172 return TYPE_KIND_OS_STRING
175 if fields
[0].name
== ENUM_DISR_FIELD_NAME
:
177 return TYPE_KIND_CSTYLE_VARIANT
178 elif self
.__all
_fields
_conform
_to
_tuple
_field
_naming
(1):
179 return TYPE_KIND_TUPLE_VARIANT
181 return TYPE_KIND_STRUCT_VARIANT
184 if self
.__all
_fields
_conform
_to
_tuple
_field
_naming
(0):
185 if unqualified_type_name
.startswith("("):
186 return TYPE_KIND_TUPLE
188 return TYPE_KIND_TUPLE_STRUCT
191 return TYPE_KIND_REGULAR_STRUCT
194 def __classify_union(self
):
195 assert self
.get_dwarf_type_kind() == DWARF_TYPE_CODE_UNION
197 union_members
= self
.get_fields()
198 union_member_count
= len(union_members
)
199 if union_member_count
== 0:
200 return TYPE_KIND_EMPTY
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
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
212 return TYPE_KIND_REGULAR_UNION
215 def __conforms_to_field_layout(self
, expected_fields
):
216 actual_fields
= self
.get_fields()
217 actual_field_count
= len(actual_fields
)
219 if actual_field_count
!= len(expected_fields
):
222 for i
in range(0, actual_field_count
):
223 if actual_fields
[i
].name
!= expected_fields
[i
]:
228 def __all_fields_conform_to_tuple_field_naming(self
, start_index
):
229 fields
= self
.get_fields()
230 field_count
= len(fields
)
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):
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.
245 def __init__(self
, ty
):
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")
252 def as_integer(self
):
254 Try to convert the wrapped value into a Python integer. This should
255 always succeed for values that are pointers or actual integers.
257 raise NotImplementedError("Override this method")
259 def get_wrapped_value(self
):
261 Returns the debugger-specific value-object wrapped by this object. This
262 is sometimes needed for doing things like pointer-arithmetic in GDB.
264 raise NotImplementedError("Override this method")
267 class EncodedEnumInfo(object):
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.
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:]
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
)
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)
295 return discriminant_val
.as_integer() == 0
297 def get_non_null_variant_val(self
):
298 return self
.__enum
_val
.get_child_at_index(0)
300 def get_null_variant_name(self
):
301 return self
.__null
_variant
_name
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
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()
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
)
318 length
= vec_val
.get_child_at_index(length_field_index
).as_integer()
319 buf
= vec_val
.get_child_at_index(buf_field_index
)
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
)
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
)
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
)
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
)
338 assert data_ptr
.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR
339 return (length
, data_ptr
)
341 UNQUALIFIED_TYPE_MARKERS
= frozenset(["(", "[", "&", "*"])
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
348 end_of_search
= qualified_type_name
.find("<")
349 if end_of_search
< 0:
350 end_of_search
= len(qualified_type_name
)
352 index
= qualified_type_name
.rfind("::", 0, end_of_search
)
354 return qualified_type_name
356 return qualified_type_name
[index
+ 2:]
359 compat_str
= unicode # Python 2