]> git.proxmox.com Git - rustc.git/blame - src/etc/gdb_rust_pretty_printing.py
New upstream version 1.45.0+dfsg1
[rustc.git] / src / etc / gdb_rust_pretty_printing.py
CommitLineData
1a4d82fc 1import gdb
0731742a 2import re
3157f602 3import sys
62682a34 4import 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 9if sys.version_info[0] >= 3:
3157f602
XL
10 xrange = range
11
74b04a01 12rust_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
18gdb_81 = False
9fa01778 19_match = re.search('([0-9]+)\\.([0-9]+)', gdb.VERSION)
0731742a
XL
20if _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 29class 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
68class 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
92def 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
97def 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
196class 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 204class 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 239class 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 261class 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 274class 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
304class 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.
335def 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
360class 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
386class 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 411class 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
425class 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 443class 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 452class 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 460def 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