]>
Commit | Line | Data |
---|---|---|
62682a34 SL |
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 | |
62682a34 | 58 | STD_VEC_FIELD_NAME_LENGTH = "len" |
c1a9b12d SL |
59 | STD_VEC_FIELD_NAME_BUF = "buf" |
60 | STD_VEC_FIELD_NAMES = [STD_VEC_FIELD_NAME_BUF, | |
61 | STD_VEC_FIELD_NAME_LENGTH] | |
62682a34 SL |
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) | |
c1a9b12d | 303 | buf_field_index = STD_VEC_FIELD_NAMES.index(STD_VEC_FIELD_NAME_BUF) |
62682a34 SL |
304 | |
305 | length = vec_val.get_child_at_index(length_field_index).as_integer() | |
c1a9b12d | 306 | buf = vec_val.get_child_at_index(buf_field_index) |
62682a34 | 307 | |
c1a9b12d SL |
308 | vec_ptr_val = buf.get_child_at_index(0) |
309 | capacity = buf.get_child_at_index(1).as_integer() | |
62682a34 SL |
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) |