]> git.lizzy.rs Git - rust.git/blob - src/etc/gdb_rust_pretty_printing.py
auto merge of #17009 : kballard/rust/install_no_sudo, r=pnkfelix
[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       if enum_members[0].name == None:
58         # This is a singleton enum
59         return rust_pretty_printer_lookup_function(val[enum_members[0]])
60       else:
61         assert enum_members[0].name.startswith("RUST$ENCODED$ENUM$")
62         # This is a space-optimized enum
63         last_separator_index = enum_members[0].name.rfind("$")
64         second_last_separator_index = first_variant_name.rfind("$", 0, last_separator_index)
65         disr_field_index = first_variant_name[second_last_separator_index + 1 :
66                                               last_separator_index]
67         disr_field_index = int(disr_field_index)
68
69         sole_variant_val = val[enum_members[0]]
70         disr_field = get_field_at_index(sole_variant_val, disr_field_index)
71         discriminant = int(sole_variant_val[disr_field])
72
73         if discriminant == 0:
74           null_variant_name = first_variant_name[last_separator_index + 1:]
75           return IdentityPrinter(null_variant_name)
76
77         return rust_pretty_printer_lookup_function(sole_variant_val)
78
79     # This is a regular enum, extract the discriminant
80     discriminant_name, discriminant_val = extract_discriminant_value(val)
81     return rust_pretty_printer_lookup_function(val[enum_members[discriminant_val]])
82
83   # No pretty printer has been found
84   return None
85
86 #=------------------------------------------------------------------------------
87 # Pretty Printer Classes
88 #=------------------------------------------------------------------------------
89
90 class RustStructPrinter:
91   def __init__(self, val, hide_first_field):
92     self.val = val
93     self.hide_first_field = hide_first_field
94
95   def to_string(self):
96     return self.val.type.tag
97
98   def children(self):
99     cs = []
100     for field in self.val.type.fields():
101       field_name = field.name
102       # Normally the field name is used as a key to access the field value,
103       # because that's also supported in older versions of GDB...
104       field_key = field_name
105       if field_name == None:
106         field_name = ""
107         # ... but for fields without a name (as in tuples), we have to fall back
108         # to the newer method of using the field object directly as key. In
109         # older versions of GDB, this will just fail.
110         field_key = field
111       name_value_tuple = ( field_name, self.val[field_key] )
112       cs.append( name_value_tuple )
113
114     if self.hide_first_field:
115       cs = cs[1:]
116
117     return cs
118
119 class RustTuplePrinter:
120   def __init__(self, val):
121     self.val = val
122
123   def to_string(self):
124     return None
125
126   def children(self):
127     cs = []
128     for field in self.val.type.fields():
129       cs.append( ("", self.val[field]) )
130
131     return cs
132
133   def display_hint(self):
134     return "array"
135
136 class RustTupleStructPrinter:
137   def __init__(self, val, hide_first_field):
138     self.val = val
139     self.hide_first_field = hide_first_field
140
141   def to_string(self):
142     return self.val.type.tag
143
144   def children(self):
145     cs = []
146     for field in self.val.type.fields():
147       cs.append( ("", self.val[field]) )
148
149     if self.hide_first_field:
150       cs = cs[1:]
151
152     return cs
153
154   def display_hint(self):
155     return "array"
156
157 class RustStringSlicePrinter:
158   def __init__(self, val):
159     self.val = val
160
161   def to_string(self):
162     slice_byte_len = self.val["length"]
163     return '"%s"' % self.val["data_ptr"].string(encoding = "utf-8",
164                                                 length = slice_byte_len)
165
166 class RustCStyleEnumPrinter:
167   def __init__(self, val):
168     assert val.type.code == gdb.TYPE_CODE_ENUM
169     self.val = val
170
171   def to_string(self):
172     return str(self.val)
173
174 class IdentityPrinter:
175   def __init__(self, string):
176     self.string
177
178   def to_string(self):
179     return self.string
180
181 STRUCT_KIND_REGULAR_STRUCT  = 0
182 STRUCT_KIND_TUPLE_STRUCT    = 1
183 STRUCT_KIND_TUPLE           = 2
184 STRUCT_KIND_TUPLE_VARIANT   = 3
185 STRUCT_KIND_STRUCT_VARIANT  = 4
186 STRUCT_KIND_CSTYLE_VARIANT  = 5
187 STRUCT_KIND_STR_SLICE       = 6
188
189 def classify_struct(type):
190   if type.tag == "&str":
191     return STRUCT_KIND_STR_SLICE
192
193   fields = list(type.fields())
194   field_count = len(fields)
195
196   if field_count == 0:
197     return STRUCT_KIND_REGULAR_STRUCT
198
199   if fields[0].name == "RUST$ENUM$DISR":
200     if field_count == 1:
201       return STRUCT_KIND_CSTYLE_VARIANT
202     elif fields[1].name == None:
203       return STRUCT_KIND_TUPLE_VARIANT
204     else:
205       return STRUCT_KIND_STRUCT_VARIANT
206
207   if fields[0].name == None:
208     if type.tag.startswith("("):
209       return STRUCT_KIND_TUPLE
210     else:
211       return STRUCT_KIND_TUPLE_STRUCT
212
213   return STRUCT_KIND_REGULAR_STRUCT
214
215 def extract_discriminant_value(enum_val):
216   assert enum_val.type.code == gdb.TYPE_CODE_UNION
217   for variant_descriptor in enum_val.type.fields():
218     variant_val = enum_val[variant_descriptor]
219     for field in variant_val.type.fields():
220       return (field.name, int(variant_val[field]))
221
222 def first_field(val):
223   for field in val.type.fields():
224     return field
225
226 def get_field_at_index(val, index):
227   i = 0
228   for field in val.type.fields():
229     if i == index:
230       return field
231   return None