]>
Commit | Line | Data |
---|---|---|
1a4d82fc | 1 | import gdb |
0731742a | 2 | import re |
3157f602 | 3 | import sys |
62682a34 | 4 | import debugger_pretty_printers_common as rustpp |
1a4d82fc | 5 | |
5bcae85e SL |
6 | # We want a version of `range` which doesn't allocate an intermediate list, |
7 | # specifically it should use a lazy iterator. In Python 2 this was `xrange`, but | |
8 | # if we're running with Python 3 then we need to use `range` instead. | |
9e0c209e | 9 | if sys.version_info[0] >= 3: |
3157f602 XL |
10 | xrange = range |
11 | ||
74b04a01 | 12 | rust_enabled = 'set language rust' in gdb.execute('complete set language ru', to_string=True) |
a1dfa0c6 | 13 | |
0731742a XL |
14 | # The btree pretty-printers fail in a confusing way unless |
15 | # https://sourceware.org/bugzilla/show_bug.cgi?id=21763 is fixed. | |
16 | # This fix went in 8.1, so check for that. | |
17 | # See https://github.com/rust-lang/rust/issues/56730 | |
18 | gdb_81 = False | |
9fa01778 | 19 | _match = re.search('([0-9]+)\\.([0-9]+)', gdb.VERSION) |
0731742a XL |
20 | if _match: |
21 | if int(_match.group(1)) > 8 or (int(_match.group(1)) == 8 and int(_match.group(2)) >= 1): | |
22 | gdb_81 = True | |
23 | ||
74b04a01 | 24 | # =============================================================================== |
1a4d82fc | 25 | # GDB Pretty Printing Module for Rust |
74b04a01 XL |
26 | # =============================================================================== |
27 | ||
1a4d82fc | 28 | |
62682a34 | 29 | class GdbType(rustpp.Type): |
85aaf69f | 30 | |
62682a34 SL |
31 | def __init__(self, ty): |
32 | super(GdbType, self).__init__() | |
33 | self.ty = ty | |
34 | self.fields = None | |
85aaf69f | 35 | |
62682a34 SL |
36 | def get_unqualified_type_name(self): |
37 | tag = self.ty.tag | |
1a4d82fc | 38 | |
62682a34 SL |
39 | if tag is None: |
40 | return tag | |
85aaf69f | 41 | |
9e0c209e | 42 | return rustpp.extract_type_name(tag).replace("&'static ", "&") |
85aaf69f | 43 | |
62682a34 SL |
44 | def get_dwarf_type_kind(self): |
45 | if self.ty.code == gdb.TYPE_CODE_STRUCT: | |
46 | return rustpp.DWARF_TYPE_CODE_STRUCT | |
c34b1796 | 47 | |
62682a34 SL |
48 | if self.ty.code == gdb.TYPE_CODE_UNION: |
49 | return rustpp.DWARF_TYPE_CODE_UNION | |
85aaf69f | 50 | |
62682a34 SL |
51 | if self.ty.code == gdb.TYPE_CODE_PTR: |
52 | return rustpp.DWARF_TYPE_CODE_PTR | |
c34b1796 | 53 | |
62682a34 SL |
54 | if self.ty.code == gdb.TYPE_CODE_ENUM: |
55 | return rustpp.DWARF_TYPE_CODE_ENUM | |
c34b1796 | 56 | |
62682a34 SL |
57 | def get_fields(self): |
58 | assert ((self.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_STRUCT) or | |
59 | (self.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_UNION)) | |
60 | if self.fields is None: | |
61 | self.fields = list(self.ty.fields()) | |
62 | return self.fields | |
85aaf69f | 63 | |
62682a34 SL |
64 | def get_wrapped_value(self): |
65 | return self.ty | |
85aaf69f | 66 | |
85aaf69f | 67 | |
62682a34 SL |
68 | class GdbValue(rustpp.Value): |
69 | def __init__(self, gdb_val): | |
70 | super(GdbValue, self).__init__(GdbType(gdb_val.type)) | |
71 | self.gdb_val = gdb_val | |
72 | self.children = {} | |
85aaf69f | 73 | |
62682a34 SL |
74 | def get_child_at_index(self, index): |
75 | child = self.children.get(index) | |
76 | if child is None: | |
77 | gdb_field = get_field_at_index(self.gdb_val, index) | |
78 | child = GdbValue(self.gdb_val[gdb_field]) | |
79 | self.children[index] = child | |
80 | return child | |
85aaf69f | 81 | |
62682a34 | 82 | def as_integer(self): |
a7813a04 | 83 | if self.gdb_val.type.code == gdb.TYPE_CODE_PTR: |
041b39d2 XL |
84 | as_str = rustpp.compat_str(self.gdb_val).split()[0] |
85 | return int(as_str, 0) | |
62682a34 | 86 | return int(self.gdb_val) |
85aaf69f | 87 | |
62682a34 SL |
88 | def get_wrapped_value(self): |
89 | return self.gdb_val | |
85aaf69f | 90 | |
85aaf69f | 91 | |
62682a34 SL |
92 | def register_printers(objfile): |
93 | """Registers Rust pretty printers for the given objfile""" | |
94 | objfile.pretty_printers.append(rust_pretty_printer_lookup_function) | |
85aaf69f | 95 | |
85aaf69f | 96 | |
62682a34 SL |
97 | def rust_pretty_printer_lookup_function(gdb_val): |
98 | """ | |
99 | Returns the correct Rust pretty printer for the given value | |
100 | if there is one | |
101 | """ | |
1a4d82fc | 102 | |
62682a34 SL |
103 | val = GdbValue(gdb_val) |
104 | type_kind = val.type.get_type_kind() | |
1a4d82fc | 105 | |
62682a34 SL |
106 | if type_kind == rustpp.TYPE_KIND_SLICE: |
107 | return RustSlicePrinter(val) | |
85aaf69f | 108 | |
62682a34 SL |
109 | if type_kind == rustpp.TYPE_KIND_STD_VEC: |
110 | return RustStdVecPrinter(val) | |
85aaf69f | 111 | |
b7449926 XL |
112 | if type_kind == rustpp.TYPE_KIND_STD_VECDEQUE: |
113 | return RustStdVecDequePrinter(val) | |
114 | ||
0731742a | 115 | if type_kind == rustpp.TYPE_KIND_STD_BTREESET and gdb_81: |
b7449926 XL |
116 | return RustStdBTreeSetPrinter(val) |
117 | ||
0731742a | 118 | if type_kind == rustpp.TYPE_KIND_STD_BTREEMAP and gdb_81: |
b7449926 XL |
119 | return RustStdBTreeMapPrinter(val) |
120 | ||
62682a34 SL |
121 | if type_kind == rustpp.TYPE_KIND_STD_STRING: |
122 | return RustStdStringPrinter(val) | |
1a4d82fc | 123 | |
041b39d2 XL |
124 | if type_kind == rustpp.TYPE_KIND_OS_STRING: |
125 | return RustOsStringPrinter(val) | |
126 | ||
a1dfa0c6 XL |
127 | # Checks after this point should only be for "compiler" types -- |
128 | # things that gdb's Rust language support knows about. | |
129 | if rust_enabled: | |
130 | return None | |
131 | ||
132 | if type_kind == rustpp.TYPE_KIND_EMPTY: | |
133 | return RustEmptyPrinter(val) | |
134 | ||
135 | if type_kind == rustpp.TYPE_KIND_REGULAR_STRUCT: | |
136 | return RustStructPrinter(val, | |
74b04a01 XL |
137 | omit_first_field=False, |
138 | omit_type_name=False, | |
139 | is_tuple_like=False) | |
a1dfa0c6 XL |
140 | |
141 | if type_kind == rustpp.TYPE_KIND_STRUCT_VARIANT: | |
142 | return RustStructPrinter(val, | |
74b04a01 XL |
143 | omit_first_field=True, |
144 | omit_type_name=False, | |
145 | is_tuple_like=False) | |
a1dfa0c6 XL |
146 | |
147 | if type_kind == rustpp.TYPE_KIND_STR_SLICE: | |
148 | return RustStringSlicePrinter(val) | |
149 | ||
62682a34 SL |
150 | if type_kind == rustpp.TYPE_KIND_TUPLE: |
151 | return RustStructPrinter(val, | |
74b04a01 XL |
152 | omit_first_field=False, |
153 | omit_type_name=True, | |
154 | is_tuple_like=True) | |
1a4d82fc | 155 | |
62682a34 SL |
156 | if type_kind == rustpp.TYPE_KIND_TUPLE_STRUCT: |
157 | return RustStructPrinter(val, | |
74b04a01 XL |
158 | omit_first_field=False, |
159 | omit_type_name=False, | |
160 | is_tuple_like=True) | |
85aaf69f | 161 | |
62682a34 SL |
162 | if type_kind == rustpp.TYPE_KIND_CSTYLE_VARIANT: |
163 | return RustCStyleVariantPrinter(val.get_child_at_index(0)) | |
1a4d82fc | 164 | |
62682a34 SL |
165 | if type_kind == rustpp.TYPE_KIND_TUPLE_VARIANT: |
166 | return RustStructPrinter(val, | |
74b04a01 XL |
167 | omit_first_field=True, |
168 | omit_type_name=False, | |
169 | is_tuple_like=True) | |
1a4d82fc | 170 | |
62682a34 SL |
171 | if type_kind == rustpp.TYPE_KIND_SINGLETON_ENUM: |
172 | variant = get_field_at_index(gdb_val, 0) | |
173 | return rust_pretty_printer_lookup_function(gdb_val[variant]) | |
1a4d82fc | 174 | |
62682a34 SL |
175 | if type_kind == rustpp.TYPE_KIND_REGULAR_ENUM: |
176 | # This is a regular enum, extract the discriminant | |
177 | discriminant_val = rustpp.get_discriminant_value_as_integer(val) | |
178 | variant = get_field_at_index(gdb_val, discriminant_val) | |
179 | return rust_pretty_printer_lookup_function(gdb_val[variant]) | |
180 | ||
181 | if type_kind == rustpp.TYPE_KIND_COMPRESSED_ENUM: | |
182 | encoded_enum_info = rustpp.EncodedEnumInfo(val) | |
183 | if encoded_enum_info.is_null_variant(): | |
184 | return IdentityPrinter(encoded_enum_info.get_null_variant_name()) | |
1a4d82fc | 185 | |
62682a34 SL |
186 | non_null_val = encoded_enum_info.get_non_null_variant_val() |
187 | return rust_pretty_printer_lookup_function(non_null_val.get_wrapped_value()) | |
188 | ||
189 | # No pretty printer has been found | |
190 | return None | |
191 | ||
192 | ||
74b04a01 | 193 | # =------------------------------------------------------------------------------ |
62682a34 | 194 | # Pretty Printer Classes |
74b04a01 | 195 | # =------------------------------------------------------------------------------ |
041b39d2 XL |
196 | class RustEmptyPrinter(object): |
197 | def __init__(self, val): | |
198 | self.__val = val | |
199 | ||
200 | def to_string(self): | |
201 | return self.__val.type.get_unqualified_type_name() | |
202 | ||
203 | ||
9e0c209e | 204 | class RustStructPrinter(object): |
62682a34 SL |
205 | def __init__(self, val, omit_first_field, omit_type_name, is_tuple_like): |
206 | self.__val = val | |
207 | self.__omit_first_field = omit_first_field | |
208 | self.__omit_type_name = omit_type_name | |
209 | self.__is_tuple_like = is_tuple_like | |
1a4d82fc | 210 | |
85aaf69f | 211 | def to_string(self): |
62682a34 SL |
212 | if self.__omit_type_name: |
213 | return None | |
214 | return self.__val.type.get_unqualified_type_name() | |
1a4d82fc | 215 | |
85aaf69f SL |
216 | def children(self): |
217 | cs = [] | |
62682a34 SL |
218 | wrapped_value = self.__val.get_wrapped_value() |
219 | ||
041b39d2 | 220 | for number, field in enumerate(self.__val.type.get_fields()): |
62682a34 SL |
221 | field_value = wrapped_value[field.name] |
222 | if self.__is_tuple_like: | |
041b39d2 | 223 | cs.append((str(number), field_value)) |
62682a34 SL |
224 | else: |
225 | cs.append((field.name, field_value)) | |
1a4d82fc | 226 | |
62682a34 | 227 | if self.__omit_first_field: |
85aaf69f | 228 | cs = cs[1:] |
1a4d82fc | 229 | |
85aaf69f SL |
230 | return cs |
231 | ||
232 | def display_hint(self): | |
62682a34 SL |
233 | if self.__is_tuple_like: |
234 | return "array" | |
235 | else: | |
236 | return "" | |
237 | ||
1a4d82fc | 238 | |
9e0c209e | 239 | class RustSlicePrinter(object): |
c34b1796 | 240 | def __init__(self, val): |
62682a34 | 241 | self.__val = val |
c34b1796 | 242 | |
9e0c209e SL |
243 | @staticmethod |
244 | def display_hint(): | |
c34b1796 AL |
245 | return "array" |
246 | ||
247 | def to_string(self): | |
62682a34 SL |
248 | (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(self.__val) |
249 | return (self.__val.type.get_unqualified_type_name() + | |
250 | ("(len: %i)" % length)) | |
c34b1796 AL |
251 | |
252 | def children(self): | |
62682a34 SL |
253 | (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(self.__val) |
254 | assert data_ptr.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_PTR | |
255 | raw_ptr = data_ptr.get_wrapped_value() | |
c34b1796 | 256 | |
3157f602 XL |
257 | for index in xrange(0, length): |
258 | yield (str(index), (raw_ptr + index).dereference()) | |
1a4d82fc | 259 | |
62682a34 | 260 | |
9e0c209e | 261 | class RustStringSlicePrinter(object): |
85aaf69f | 262 | def __init__(self, val): |
62682a34 | 263 | self.__val = val |
85aaf69f SL |
264 | |
265 | def to_string(self): | |
62682a34 SL |
266 | (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(self.__val) |
267 | raw_ptr = data_ptr.get_wrapped_value() | |
abe05a73 XL |
268 | return raw_ptr.lazy_string(encoding="utf-8", length=length) |
269 | ||
270 | def display_hint(self): | |
271 | return "string" | |
62682a34 | 272 | |
1a4d82fc | 273 | |
9e0c209e | 274 | class RustStdVecPrinter(object): |
c34b1796 | 275 | def __init__(self, val): |
62682a34 | 276 | self.__val = val |
c34b1796 | 277 | |
9e0c209e SL |
278 | @staticmethod |
279 | def display_hint(): | |
c34b1796 AL |
280 | return "array" |
281 | ||
282 | def to_string(self): | |
62682a34 SL |
283 | (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(self.__val) |
284 | return (self.__val.type.get_unqualified_type_name() + | |
285 | ("(len: %i, cap: %i)" % (length, cap))) | |
c34b1796 AL |
286 | |
287 | def children(self): | |
60c5eb7d | 288 | saw_inaccessible = False |
62682a34 SL |
289 | (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(self.__val) |
290 | gdb_ptr = data_ptr.get_wrapped_value() | |
3157f602 | 291 | for index in xrange(0, length): |
60c5eb7d XL |
292 | if saw_inaccessible: |
293 | return | |
294 | try: | |
295 | # rust-lang/rust#64343: passing deref expr to `str` allows | |
296 | # catching exception on garbage pointer | |
297 | str((gdb_ptr + index).dereference()) | |
298 | yield (str(index), (gdb_ptr + index).dereference()) | |
299 | except RuntimeError: | |
300 | saw_inaccessible = True | |
301 | yield (str(index), "inaccessible") | |
c34b1796 | 302 | |
62682a34 | 303 | |
b7449926 XL |
304 | class RustStdVecDequePrinter(object): |
305 | def __init__(self, val): | |
306 | self.__val = val | |
307 | ||
308 | @staticmethod | |
309 | def display_hint(): | |
310 | return "array" | |
311 | ||
312 | def to_string(self): | |
313 | (tail, head, data_ptr, cap) = \ | |
314 | rustpp.extract_tail_head_ptr_and_cap_from_std_vecdeque(self.__val) | |
a1dfa0c6 XL |
315 | if head >= tail: |
316 | size = head - tail | |
317 | else: | |
318 | size = cap + head - tail | |
b7449926 | 319 | return (self.__val.type.get_unqualified_type_name() + |
a1dfa0c6 | 320 | ("(len: %i, cap: %i)" % (size, cap))) |
b7449926 XL |
321 | |
322 | def children(self): | |
323 | (tail, head, data_ptr, cap) = \ | |
324 | rustpp.extract_tail_head_ptr_and_cap_from_std_vecdeque(self.__val) | |
325 | gdb_ptr = data_ptr.get_wrapped_value() | |
a1dfa0c6 XL |
326 | if head >= tail: |
327 | size = head - tail | |
328 | else: | |
329 | size = cap + head - tail | |
330 | for index in xrange(0, size): | |
331 | yield (str(index), (gdb_ptr + ((tail + index) % cap)).dereference()) | |
332 | ||
333 | ||
334 | # Yield each key (and optionally value) from a BoxedNode. | |
335 | def children_of_node(boxed_node, height, want_values): | |
0731742a | 336 | node_ptr = boxed_node['ptr']['pointer'] |
a1dfa0c6 | 337 | if height > 0: |
ba9703b0 | 338 | type_name = str(node_ptr.type.target()).replace('LeafNode', 'InternalNode', 1) |
a1dfa0c6 XL |
339 | node_type = gdb.lookup_type(type_name) |
340 | node_ptr = node_ptr.cast(node_type.pointer()) | |
341 | leaf = node_ptr['data'] | |
342 | else: | |
343 | leaf = node_ptr.dereference() | |
9fa01778 | 344 | keys = leaf['keys'] |
a1dfa0c6 | 345 | if want_values: |
9fa01778 | 346 | values = leaf['vals'] |
a1dfa0c6 XL |
347 | length = int(leaf['len']) |
348 | for i in xrange(0, length + 1): | |
349 | if height > 0: | |
9fa01778 XL |
350 | child_ptr = node_ptr['edges'][i]['value']['value'] |
351 | for child in children_of_node(child_ptr, height - 1, want_values): | |
a1dfa0c6 XL |
352 | yield child |
353 | if i < length: | |
354 | if want_values: | |
9fa01778 | 355 | yield (keys[i]['value']['value'], values[i]['value']['value']) |
a1dfa0c6 | 356 | else: |
9fa01778 | 357 | yield keys[i]['value']['value'] |
b7449926 | 358 | |
74b04a01 | 359 | |
b7449926 XL |
360 | class RustStdBTreeSetPrinter(object): |
361 | def __init__(self, val): | |
362 | self.__val = val | |
363 | ||
364 | @staticmethod | |
365 | def display_hint(): | |
366 | return "array" | |
367 | ||
368 | def to_string(self): | |
b7449926 | 369 | return (self.__val.type.get_unqualified_type_name() + |
a1dfa0c6 | 370 | ("(len: %i)" % self.__val.get_wrapped_value()['map']['length'])) |
b7449926 XL |
371 | |
372 | def children(self): | |
ba9703b0 XL |
373 | prev_idx = None |
374 | innermap = GdbValue(self.__val.get_wrapped_value()['map']) | |
375 | if innermap.get_wrapped_value()['length'] > 0: | |
376 | root = GdbValue(innermap.get_wrapped_value()['root']) | |
377 | type_name = str(root.type.ty.name).replace('core::option::Option<', '', 1)[:-1] | |
378 | root = root.get_wrapped_value().cast(gdb.lookup_type(type_name)) | |
379 | node_ptr = root['node'] | |
380 | i = 0 | |
381 | for child in children_of_node(node_ptr, root['height'], False): | |
382 | yield (str(i), child) | |
383 | i = i + 1 | |
b7449926 XL |
384 | |
385 | ||
386 | class RustStdBTreeMapPrinter(object): | |
387 | def __init__(self, val): | |
388 | self.__val = val | |
389 | ||
390 | @staticmethod | |
391 | def display_hint(): | |
392 | return "map" | |
393 | ||
394 | def to_string(self): | |
b7449926 | 395 | return (self.__val.type.get_unqualified_type_name() + |
a1dfa0c6 | 396 | ("(len: %i)" % self.__val.get_wrapped_value()['length'])) |
b7449926 XL |
397 | |
398 | def children(self): | |
ba9703b0 XL |
399 | if self.__val.get_wrapped_value()['length'] > 0: |
400 | root = GdbValue(self.__val.get_wrapped_value()['root']) | |
401 | type_name = str(root.type.ty.name).replace('core::option::Option<', '', 1)[:-1] | |
402 | root = root.get_wrapped_value().cast(gdb.lookup_type(type_name)) | |
403 | node_ptr = root['node'] | |
404 | i = 0 | |
405 | for child in children_of_node(node_ptr, root['height'], True): | |
406 | yield (str(i), child[0]) | |
407 | yield (str(i), child[1]) | |
408 | i = i + 1 | |
b7449926 XL |
409 | |
410 | ||
9e0c209e | 411 | class RustStdStringPrinter(object): |
c34b1796 | 412 | def __init__(self, val): |
62682a34 | 413 | self.__val = val |
c34b1796 AL |
414 | |
415 | def to_string(self): | |
62682a34 SL |
416 | vec = self.__val.get_child_at_index(0) |
417 | (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(vec) | |
abe05a73 XL |
418 | return data_ptr.get_wrapped_value().lazy_string(encoding="utf-8", |
419 | length=length) | |
c34b1796 | 420 | |
abe05a73 XL |
421 | def display_hint(self): |
422 | return "string" | |
1a4d82fc | 423 | |
b7449926 | 424 | |
041b39d2 XL |
425 | class RustOsStringPrinter(object): |
426 | def __init__(self, val): | |
427 | self.__val = val | |
428 | ||
429 | def to_string(self): | |
430 | buf = self.__val.get_child_at_index(0) | |
431 | vec = buf.get_child_at_index(0) | |
432 | if vec.type.get_unqualified_type_name() == "Wtf8Buf": | |
433 | vec = vec.get_child_at_index(0) | |
434 | ||
435 | (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec( | |
436 | vec) | |
abe05a73 | 437 | return data_ptr.get_wrapped_value().lazy_string(length=length) |
041b39d2 | 438 | |
abe05a73 XL |
439 | def display_hint(self): |
440 | return "string" | |
041b39d2 | 441 | |
74b04a01 | 442 | |
9e0c209e | 443 | class RustCStyleVariantPrinter(object): |
85aaf69f | 444 | def __init__(self, val): |
62682a34 SL |
445 | assert val.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_ENUM |
446 | self.__val = val | |
85aaf69f SL |
447 | |
448 | def to_string(self): | |
62682a34 | 449 | return str(self.__val.get_wrapped_value()) |
1a4d82fc | 450 | |
1a4d82fc | 451 | |
9e0c209e | 452 | class IdentityPrinter(object): |
85aaf69f SL |
453 | def __init__(self, string): |
454 | self.string = string | |
1a4d82fc | 455 | |
85aaf69f SL |
456 | def to_string(self): |
457 | return self.string | |
1a4d82fc | 458 | |
1a4d82fc | 459 | |
62682a34 | 460 | def get_field_at_index(gdb_val, index): |
85aaf69f | 461 | i = 0 |
62682a34 | 462 | for field in gdb_val.type.fields(): |
85aaf69f SL |
463 | if i == index: |
464 | return field | |
465 | i += 1 | |
466 | return None |