]> git.lizzy.rs Git - rust.git/blob - src/etc/gdb_rust_pretty_printing.py
rollup merge of #19503: lifthrasiir/xenophobic-rustdoc
[rust.git] / src / etc / gdb_rust_pretty_printing.py
1 # Copyright 2013-2014 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 import gdb
12
13 #===============================================================================
14 # GDB Pretty Printing Module for Rust
15 #===============================================================================
16
17 def register_printers(objfile):
18   "Registers Rust pretty printers for the given objfile"
19   objfile.pretty_printers.append(rust_pretty_printer_lookup_function)
20
21 def rust_pretty_printer_lookup_function(val):
22   "Returns the correct Rust pretty printer for the given value if there is one"
23   type_code = val.type.code
24
25   if type_code == gdb.TYPE_CODE_STRUCT:
26     struct_kind = classify_struct(val.type)
27
28     if struct_kind == STRUCT_KIND_STR_SLICE:
29       return RustStringSlicePrinter(val)
30
31     if struct_kind == STRUCT_KIND_TUPLE:
32       return RustTuplePrinter(val)
33
34     if struct_kind == STRUCT_KIND_TUPLE_STRUCT:
35       return RustTupleStructPrinter(val, False)
36
37     if struct_kind == STRUCT_KIND_CSTYLE_VARIANT:
38       return RustCStyleEnumPrinter(val[get_field_at_index(val, 0)])
39
40     if struct_kind == STRUCT_KIND_TUPLE_VARIANT:
41       return RustTupleStructPrinter(val, True)
42
43     if struct_kind == STRUCT_KIND_STRUCT_VARIANT:
44       return RustStructPrinter(val, True)
45
46     return RustStructPrinter(val, False)
47
48   # Enum handling
49   if type_code == gdb.TYPE_CODE_UNION:
50     enum_members = list(val.type.fields())
51     enum_member_count = len(enum_members)
52
53     if enum_member_count == 0:
54       return RustStructPrinter(val, false)
55
56     if enum_member_count == 1:
57       first_variant_name = enum_members[0].name
58       if first_variant_name == None:
59         # This is a singleton enum
60         return rust_pretty_printer_lookup_function(val[enum_members[0]])
61       else:
62         assert first_variant_name.startswith("RUST$ENCODED$ENUM$")
63         # This is a space-optimized enum
64         last_separator_index = first_variant_name.rfind("$")
65         second_last_separator_index = first_variant_name.rfind("$", 0, last_separator_index)
66         disr_field_index = first_variant_name[second_last_separator_index + 1 :
67                                               last_separator_index]
68         disr_field_index = int(disr_field_index)
69
70         sole_variant_val = val[enum_members[0]]
71         disr_field = get_field_at_index(sole_variant_val, disr_field_index)
72         discriminant = sole_variant_val[disr_field]
73
74         # If the discriminant field is a fat pointer we have to consider the
75         # first word as the true discriminant
76         if discriminant.type.code == gdb.TYPE_CODE_STRUCT:
77             discriminant = discriminant[get_field_at_index(discriminant, 0)]
78
79         if discriminant == 0:
80           null_variant_name = first_variant_name[last_separator_index + 1:]
81           return IdentityPrinter(null_variant_name)
82
83         return rust_pretty_printer_lookup_function(sole_variant_val)
84
85     # This is a regular enum, extract the discriminant
86     discriminant_name, discriminant_val = extract_discriminant_value(val)
87     return rust_pretty_printer_lookup_function(val[enum_members[discriminant_val]])
88
89   # No pretty printer has been found
90   return None
91
92 #=------------------------------------------------------------------------------
93 # Pretty Printer Classes
94 #=------------------------------------------------------------------------------
95
96 class RustStructPrinter:
97   def __init__(self, val, hide_first_field):
98     self.val = val
99     self.hide_first_field = hide_first_field
100
101   def to_string(self):
102     return self.val.type.tag
103
104   def children(self):
105     cs = []
106     for field in self.val.type.fields():
107       field_name = field.name
108       # Normally the field name is used as a key to access the field value,
109       # because that's also supported in older versions of GDB...
110       field_key = field_name
111       if field_name == None:
112         field_name = ""
113         # ... but for fields without a name (as in tuples), we have to fall back
114         # to the newer method of using the field object directly as key. In
115         # older versions of GDB, this will just fail.
116         field_key = field
117       name_value_tuple = ( field_name, self.val[field_key] )
118       cs.append( name_value_tuple )
119
120     if self.hide_first_field:
121       cs = cs[1:]
122
123     return cs
124
125 class RustTuplePrinter:
126   def __init__(self, val):
127     self.val = val
128
129   def to_string(self):
130     return None
131
132   def children(self):
133     cs = []
134     for field in self.val.type.fields():
135       cs.append( ("", self.val[field]) )
136
137     return cs
138
139   def display_hint(self):
140     return "array"
141
142 class RustTupleStructPrinter:
143   def __init__(self, val, hide_first_field):
144     self.val = val
145     self.hide_first_field = hide_first_field
146
147   def to_string(self):
148     return self.val.type.tag
149
150   def children(self):
151     cs = []
152     for field in self.val.type.fields():
153       cs.append( ("", self.val[field]) )
154
155     if self.hide_first_field:
156       cs = cs[1:]
157
158     return cs
159
160   def display_hint(self):
161     return "array"
162
163 class RustStringSlicePrinter:
164   def __init__(self, val):
165     self.val = val
166
167   def to_string(self):
168     slice_byte_len = self.val["length"]
169     return '"%s"' % self.val["data_ptr"].string(encoding = "utf-8",
170                                                 length = slice_byte_len)
171
172 class RustCStyleEnumPrinter:
173   def __init__(self, val):
174     assert val.type.code == gdb.TYPE_CODE_ENUM
175     self.val = val
176
177   def to_string(self):
178     return str(self.val)
179
180 class IdentityPrinter:
181   def __init__(self, string):
182     self.string = string
183
184   def to_string(self):
185     return self.string
186
187 STRUCT_KIND_REGULAR_STRUCT  = 0
188 STRUCT_KIND_TUPLE_STRUCT    = 1
189 STRUCT_KIND_TUPLE           = 2
190 STRUCT_KIND_TUPLE_VARIANT   = 3
191 STRUCT_KIND_STRUCT_VARIANT  = 4
192 STRUCT_KIND_CSTYLE_VARIANT  = 5
193 STRUCT_KIND_STR_SLICE       = 6
194
195 def classify_struct(type):
196   if type.tag == "&str":
197     return STRUCT_KIND_STR_SLICE
198
199   fields = list(type.fields())
200   field_count = len(fields)
201
202   if field_count == 0:
203     return STRUCT_KIND_REGULAR_STRUCT
204
205   if fields[0].name == "RUST$ENUM$DISR":
206     if field_count == 1:
207       return STRUCT_KIND_CSTYLE_VARIANT
208     elif fields[1].name == None:
209       return STRUCT_KIND_TUPLE_VARIANT
210     else:
211       return STRUCT_KIND_STRUCT_VARIANT
212
213   if fields[0].name == None:
214     if type.tag.startswith("("):
215       return STRUCT_KIND_TUPLE
216     else:
217       return STRUCT_KIND_TUPLE_STRUCT
218
219   return STRUCT_KIND_REGULAR_STRUCT
220
221 def extract_discriminant_value(enum_val):
222   assert enum_val.type.code == gdb.TYPE_CODE_UNION
223   for variant_descriptor in enum_val.type.fields():
224     variant_val = enum_val[variant_descriptor]
225     for field in variant_val.type.fields():
226       return (field.name, int(variant_val[field]))
227
228 def first_field(val):
229   for field in val.type.fields():
230     return field
231
232 def get_field_at_index(val, index):
233   i = 0
234   for field in val.type.fields():
235     if i == index:
236       return field
237   return None