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
49 ENCODED_ENUM_PREFIX
= "RUST$ENCODED$ENUM$"
50 ENUM_DISR_FIELD_NAME
= "RUST$ENUM$DISR"
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
]
57 # std::Vec<> related constants
58 STD_VEC_FIELD_NAME_DATA_PTR
= "ptr"
59 STD_VEC_FIELD_NAME_LENGTH
= "len"
60 STD_VEC_FIELD_NAME_CAPACITY
= "cap"
61 STD_VEC_FIELD_NAMES
= [STD_VEC_FIELD_NAME_DATA_PTR
,
62 STD_VEC_FIELD_NAME_LENGTH
,
63 STD_VEC_FIELD_NAME_CAPACITY
]
65 # std::String related constants
66 STD_STRING_FIELD_NAMES
= ["vec"]
71 This class provides a common interface for type-oriented operations.
72 Sub-classes are supposed to wrap a debugger-specific type-object and
73 provide implementations for the abstract methods in this class.
77 self
.__type
_kind
= None
79 def get_unqualified_type_name(self
):
81 Implementations of this method should return the unqualified name of the
82 type-object they are wrapping. Some examples:
85 'std::vec::Vec<std::string::String>' -> 'Vec<std::string::String>'
86 '&std::option::Option<std::string::String>' -> '&std::option::Option<std::string::String>'
88 As you can see, type arguments stay fully qualified.
90 raise NotImplementedError("Override this method")
92 def get_dwarf_type_kind(self
):
94 Implementations of this method should return the correct
95 DWARF_TYPE_CODE_* value for the wrapped type-object.
97 raise NotImplementedError("Override this method")
101 Implementations of this method should return a list of field-objects of
102 this type. For Rust-enums (i.e. with DWARF_TYPE_CODE_UNION) these field-
103 objects represent the variants of the enum. Field-objects must have a
104 `name` attribute that gives their name as specified in DWARF.
106 assert ((self
.get_dwarf_type_kind() == DWARF_TYPE_CODE_STRUCT
) or
107 (self
.get_dwarf_type_kind() == DWARF_TYPE_CODE_UNION
))
108 raise NotImplementedError("Override this method")
110 def get_wrapped_value(self
):
112 Returns the debugger-specific type-object wrapped by this object. This
113 is sometimes needed for doing things like pointer-arithmetic in GDB.
115 raise NotImplementedError("Override this method")
117 def get_type_kind(self
):
118 """This method returns the TYPE_KIND_* value for this type-object."""
119 if self
.__type
_kind
is None:
120 dwarf_type_code
= self
.get_dwarf_type_kind()
122 if dwarf_type_code
== DWARF_TYPE_CODE_STRUCT
:
123 self
.__type
_kind
= self
.__classify
_struct
()
124 elif dwarf_type_code
== DWARF_TYPE_CODE_UNION
:
125 self
.__type
_kind
= self
.__classify
_union
()
126 elif dwarf_type_code
== DWARF_TYPE_CODE_PTR
:
127 self
.__type
_kind
= TYPE_KIND_PTR
128 elif dwarf_type_code
== DWARF_TYPE_CODE_ARRAY
:
129 self
.__type
_kind
= TYPE_KIND_FIXED_SIZE_VEC
131 self
.__type
_kind
= TYPE_KIND_UNKNOWN
132 return self
.__type
_kind
134 def __classify_struct(self
):
135 assert self
.get_dwarf_type_kind() == DWARF_TYPE_CODE_STRUCT
137 unqualified_type_name
= self
.get_unqualified_type_name()
140 if unqualified_type_name
== "&str":
141 return TYPE_KIND_STR_SLICE
144 if (unqualified_type_name
.startswith("&[") and
145 unqualified_type_name
.endswith("]") and
146 self
.__conforms
_to
_field
_layout
(SLICE_FIELD_NAMES
)):
147 return TYPE_KIND_SLICE
149 fields
= self
.get_fields()
150 field_count
= len(fields
)
154 return TYPE_KIND_EMPTY
157 if (unqualified_type_name
.startswith("Vec<") and
158 self
.__conforms
_to
_field
_layout
(STD_VEC_FIELD_NAMES
)):
159 return TYPE_KIND_STD_VEC
162 if (unqualified_type_name
.startswith("String") and
163 self
.__conforms
_to
_field
_layout
(STD_STRING_FIELD_NAMES
)):
164 return TYPE_KIND_STD_STRING
167 if fields
[0].name
== ENUM_DISR_FIELD_NAME
:
169 return TYPE_KIND_CSTYLE_VARIANT
170 elif self
.__all
_fields
_conform
_to
_tuple
_field
_naming
(1):
171 return TYPE_KIND_TUPLE_VARIANT
173 return TYPE_KIND_STRUCT_VARIANT
176 if self
.__all
_fields
_conform
_to
_tuple
_field
_naming
(0):
177 if unqualified_type_name
.startswith("("):
178 return TYPE_KIND_TUPLE
180 return TYPE_KIND_TUPLE_STRUCT
183 return TYPE_KIND_REGULAR_STRUCT
186 def __classify_union(self
):
187 assert self
.get_dwarf_type_kind() == DWARF_TYPE_CODE_UNION
189 union_members
= self
.get_fields()
190 union_member_count
= len(union_members
)
191 if union_member_count
== 0:
192 return TYPE_KIND_EMPTY
193 elif union_member_count
== 1:
194 first_variant_name
= union_members
[0].name
195 if first_variant_name
is None:
196 return TYPE_KIND_SINGLETON_ENUM
198 assert first_variant_name
.startswith(ENCODED_ENUM_PREFIX
)
199 return TYPE_KIND_COMPRESSED_ENUM
201 return TYPE_KIND_REGULAR_ENUM
204 def __conforms_to_field_layout(self
, expected_fields
):
205 actual_fields
= self
.get_fields()
206 actual_field_count
= len(actual_fields
)
208 if actual_field_count
!= len(expected_fields
):
211 for i
in range(0, actual_field_count
):
212 if actual_fields
[i
].name
!= expected_fields
[i
]:
217 def __all_fields_conform_to_tuple_field_naming(self
, start_index
):
218 fields
= self
.get_fields()
219 field_count
= len(fields
)
221 for i
in range(start_index
, field_count
):
222 field_name
= fields
[i
].name
223 if (field_name
is None) or (re
.match(r
"__\d+$", field_name
) is None):
230 This class provides a common interface for value-oriented operations.
231 Sub-classes are supposed to wrap a debugger-specific value-object and
232 provide implementations for the abstract methods in this class.
234 def __init__(self
, ty
):
237 def get_child_at_index(self
, index
):
238 """Returns the value of the field, array element or variant at the given index"""
239 raise NotImplementedError("Override this method")
241 def as_integer(self
):
243 Try to convert the wrapped value into a Python integer. This should
244 always succeed for values that are pointers or actual integers.
246 raise NotImplementedError("Override this method")
248 def get_wrapped_value(self
):
250 Returns the debugger-specific value-object wrapped by this object. This
251 is sometimes needed for doing things like pointer-arithmetic in GDB.
253 raise NotImplementedError("Override this method")
256 class EncodedEnumInfo(object):
258 This class provides facilities for handling enum values with compressed
259 encoding where a non-null field in one variant doubles as the discriminant.
262 def __init__(self
, enum_val
):
263 assert enum_val
.type.get_type_kind() == TYPE_KIND_COMPRESSED_ENUM
264 variant_name
= enum_val
.type.get_fields()[0].name
265 last_separator_index
= variant_name
.rfind("$")
266 start_index
= len(ENCODED_ENUM_PREFIX
)
267 indices_substring
= variant_name
[start_index
:last_separator_index
].split("$")
268 self
.__enum
_val
= enum_val
269 self
.__disr
_field
_indices
= [int(index
) for index
in indices_substring
]
270 self
.__null
_variant
_name
= variant_name
[last_separator_index
+ 1:]
272 def is_null_variant(self
):
273 ty
= self
.__enum
_val
.type
274 sole_variant_val
= self
.__enum
_val
.get_child_at_index(0)
275 discriminant_val
= sole_variant_val
276 for disr_field_index
in self
.__disr
_field
_indices
:
277 discriminant_val
= discriminant_val
.get_child_at_index(disr_field_index
)
279 # If the discriminant field is a fat pointer we have to consider the
280 # first word as the true discriminant
281 if discriminant_val
.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_STRUCT
:
282 discriminant_val
= discriminant_val
.get_child_at_index(0)
284 return discriminant_val
.as_integer() == 0
286 def get_non_null_variant_val(self
):
287 return self
.__enum
_val
.get_child_at_index(0)
289 def get_null_variant_name(self
):
290 return self
.__null
_variant
_name
293 def get_discriminant_value_as_integer(enum_val
):
294 assert enum_val
.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_UNION
295 # we can take any variant here because the discriminant has to be the same
297 variant_val
= enum_val
.get_child_at_index(0)
298 disr_val
= variant_val
.get_child_at_index(0)
299 return disr_val
.as_integer()
302 def extract_length_ptr_and_cap_from_std_vec(vec_val
):
303 assert vec_val
.type.get_type_kind() == TYPE_KIND_STD_VEC
304 length_field_index
= STD_VEC_FIELD_NAMES
.index(STD_VEC_FIELD_NAME_LENGTH
)
305 ptr_field_index
= STD_VEC_FIELD_NAMES
.index(STD_VEC_FIELD_NAME_DATA_PTR
)
306 cap_field_index
= STD_VEC_FIELD_NAMES
.index(STD_VEC_FIELD_NAME_CAPACITY
)
308 length
= vec_val
.get_child_at_index(length_field_index
).as_integer()
309 vec_ptr_val
= vec_val
.get_child_at_index(ptr_field_index
)
310 capacity
= vec_val
.get_child_at_index(cap_field_index
).as_integer()
312 unique_ptr_val
= vec_ptr_val
.get_child_at_index(0)
313 data_ptr
= unique_ptr_val
.get_child_at_index(0)
314 assert data_ptr
.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR
315 return (length
, data_ptr
, capacity
)
317 def extract_length_and_ptr_from_slice(slice_val
):
318 assert (slice_val
.type.get_type_kind() == TYPE_KIND_SLICE
or
319 slice_val
.type.get_type_kind() == TYPE_KIND_STR_SLICE
)
321 length_field_index
= SLICE_FIELD_NAMES
.index(SLICE_FIELD_NAME_LENGTH
)
322 ptr_field_index
= SLICE_FIELD_NAMES
.index(SLICE_FIELD_NAME_DATA_PTR
)
324 length
= slice_val
.get_child_at_index(length_field_index
).as_integer()
325 data_ptr
= slice_val
.get_child_at_index(ptr_field_index
)
327 assert data_ptr
.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR
328 return (length
, data_ptr
)