]> git.proxmox.com Git - rustc.git/blob - src/etc/lldb_rust_formatters.py
42c83b6a42ed6f6df6ad7ec765fa5eb5e809b897
[rustc.git] / src / etc / lldb_rust_formatters.py
1 # Copyright 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 lldb
12
13
14 def print_val(val, internal_dict):
15 '''Prints the given value with Rust syntax'''
16 type_class = val.GetType().GetTypeClass()
17
18 if type_class == lldb.eTypeClassStruct:
19 return print_struct_val(val, internal_dict)
20
21 if type_class == lldb.eTypeClassUnion:
22 return print_enum_val(val, internal_dict)
23
24 if type_class == lldb.eTypeClassPointer:
25 return print_pointer_val(val, internal_dict)
26
27 if type_class == lldb.eTypeClassArray:
28 return print_fixed_size_vec_val(val, internal_dict)
29
30 return val.GetValue()
31
32
33 #=--------------------------------------------------------------------------------------------------
34 # Type-Specialized Printing Functions
35 #=--------------------------------------------------------------------------------------------------
36
37 def print_struct_val(val, internal_dict):
38 '''Prints a struct, tuple, or tuple struct value with Rust syntax'''
39 assert val.GetType().GetTypeClass() == lldb.eTypeClassStruct
40
41 if is_vec_slice(val):
42 return print_vec_slice_val(val, internal_dict)
43 else:
44 return print_struct_val_starting_from(0, val, internal_dict)
45
46
47 def print_vec_slice_val(val, internal_dict):
48 length = val.GetChildAtIndex(1).GetValueAsUnsigned()
49
50 data_ptr_val = val.GetChildAtIndex(0)
51 data_ptr_type = data_ptr_val.GetType()
52 assert data_ptr_type.IsPointerType()
53
54 element_type = data_ptr_type.GetPointeeType()
55 element_type_size = element_type.GetByteSize()
56
57 start_address = data_ptr_val.GetValueAsUnsigned()
58
59 def render_element(i):
60 address = start_address + i * element_type_size
61 element_val = val.CreateValueFromAddress(val.GetName() +
62 ("[%s]" % i), address, element_type)
63 return print_val(element_val, internal_dict)
64
65 return "&[%s]" % (', '.join([render_element(i) for i in range(length)]))
66
67
68 def print_struct_val_starting_from(field_start_index, val, internal_dict):
69 '''
70 Prints a struct, tuple, or tuple struct value with Rust syntax.
71 Ignores any fields before field_start_index.
72 '''
73 assert val.GetType().GetTypeClass() == lldb.eTypeClassStruct
74
75 t = val.GetType()
76 type_name = extract_type_name(t.GetName())
77 num_children = val.num_children
78
79 if (num_children - field_start_index) == 0:
80 # The only field of this struct is the enum discriminant
81 return type_name
82
83 has_field_names = type_has_field_names(t)
84
85 if has_field_names:
86 template = "%(type_name)s {\n%(body)s\n}"
87 separator = ", \n"
88 else:
89 template = "%(type_name)s(%(body)s)"
90 separator = ", "
91
92 if type_name.startswith("("):
93 # this is a tuple, so don't print the type name
94 type_name = ""
95
96 def render_child(child_index):
97 this = ""
98 if has_field_names:
99 field_name = t.GetFieldAtIndex(child_index).GetName()
100 this += field_name + ": "
101
102 field_val = val.GetChildAtIndex(child_index)
103 return this + print_val(field_val, internal_dict)
104
105 body = separator.join([render_child(idx) for idx in range(field_start_index, num_children)])
106
107 return template % {"type_name": type_name,
108 "body": body}
109
110
111 def print_enum_val(val, internal_dict):
112 '''Prints an enum value with Rust syntax'''
113
114 assert val.GetType().GetTypeClass() == lldb.eTypeClassUnion
115
116 if val.num_children == 1:
117 # This is either an enum with just one variant, or it is an Option-like
118 # enum where the discriminant is encoded in a non-nullable pointer
119 # field. We find out which one it is by looking at the member name of
120 # the sole union variant. If it starts with "RUST$ENCODED$ENUM$" then
121 # we have an Option-like enum.
122 first_variant_name = val.GetChildAtIndex(0).GetName()
123 if first_variant_name and first_variant_name.startswith("RUST$ENCODED$ENUM$"):
124
125 # This is an Option-like enum. The position of the discriminator field is
126 # encoded in the name which has the format:
127 # RUST$ENCODED$ENUM$<index of discriminator field>$<name of null variant>
128 last_separator_index = first_variant_name.rfind("$")
129 if last_separator_index == -1:
130 return "<invalid enum encoding: %s>" % first_variant_name
131
132 start_index = len("RUST$ENCODED$ENUM$")
133
134 # Extract indices of the discriminator field
135 try:
136 disr_field_indices = first_variant_name[start_index:last_separator_index].split("$")
137 disr_field_indices = [int(index) for index in disr_field_indices]
138 except:
139 return "<invalid enum encoding: %s>" % first_variant_name
140
141 # Read the discriminant
142 disr_val = val.GetChildAtIndex(0)
143 for index in disr_field_indices:
144 disr_val = disr_val.GetChildAtIndex(index)
145
146 # If the discriminant field is a fat pointer we have to consider the
147 # first word as the true discriminant
148 if disr_val.GetType().GetTypeClass() == lldb.eTypeClassStruct:
149 disr_val = disr_val.GetChildAtIndex(0)
150
151 if disr_val.GetValueAsUnsigned() == 0:
152 # Null case: Print the name of the null-variant
153 null_variant_name = first_variant_name[last_separator_index + 1:]
154 return null_variant_name
155 else:
156 # Non-null case: Interpret the data as a value of the non-null variant type
157 return print_struct_val_starting_from(0, val.GetChildAtIndex(0), internal_dict)
158 else:
159 # This is just a regular uni-variant enum without discriminator field
160 return print_struct_val_starting_from(0, val.GetChildAtIndex(0), internal_dict)
161
162 # If we are here, this is a regular enum with more than one variant
163 disr_val = val.GetChildAtIndex(0).GetChildMemberWithName("RUST$ENUM$DISR")
164 disr_type = disr_val.GetType()
165
166 if disr_type.GetTypeClass() != lldb.eTypeClassEnumeration:
167 return "<Invalid enum value encountered: Discriminator is not an enum>"
168
169 variant_index = disr_val.GetValueAsUnsigned()
170 return print_struct_val_starting_from(1, val.GetChildAtIndex(variant_index), internal_dict)
171
172
173 def print_pointer_val(val, internal_dict):
174 '''Prints a pointer value with Rust syntax'''
175 assert val.GetType().IsPointerType()
176 sigil = "&"
177 type_name = extract_type_name(val.GetType().GetName())
178 if type_name and type_name[0:1] in ["&", "~", "*"]:
179 sigil = type_name[0:1]
180
181 return sigil + hex(val.GetValueAsUnsigned()) #print_val(val.Dereference(), internal_dict)
182
183
184 def print_fixed_size_vec_val(val, internal_dict):
185 assert val.GetType().GetTypeClass() == lldb.eTypeClassArray
186
187 output = "["
188
189 for i in range(val.num_children):
190 output += print_val(val.GetChildAtIndex(i), internal_dict)
191 if i != val.num_children - 1:
192 output += ", "
193
194 output += "]"
195 return output
196
197
198 #=--------------------------------------------------------------------------------------------------
199 # Helper Functions
200 #=--------------------------------------------------------------------------------------------------
201
202 unqualified_type_markers = frozenset(["(", "[", "&", "*"])
203
204
205 def extract_type_name(qualified_type_name):
206 '''Extracts the type name from a fully qualified path'''
207 if qualified_type_name[0] in unqualified_type_markers:
208 return qualified_type_name
209
210 end_of_search = qualified_type_name.find("<")
211 if end_of_search < 0:
212 end_of_search = len(qualified_type_name)
213
214 index = qualified_type_name.rfind("::", 0, end_of_search)
215 if index < 0:
216 return qualified_type_name
217 else:
218 return qualified_type_name[index + 2:]
219
220
221 def type_has_field_names(ty):
222 '''Returns true of this is a type with field names (struct, struct-like enum variant)'''
223 # This may also be an enum variant where the first field doesn't have a name but the rest has
224 if ty.GetNumberOfFields() > 1:
225 return ty.GetFieldAtIndex(1).GetName() is not None
226 else:
227 return ty.GetFieldAtIndex(0).GetName() is not None
228
229
230 def is_vec_slice(val):
231 ty = val.GetType()
232 if ty.GetTypeClass() != lldb.eTypeClassStruct:
233 return False
234
235 if ty.GetNumberOfFields() != 2:
236 return False
237
238 if ty.GetFieldAtIndex(0).GetName() != "data_ptr":
239 return False
240
241 if ty.GetFieldAtIndex(1).GetName() != "length":
242 return False
243
244 type_name = extract_type_name(ty.GetName()).replace("&'static", "&").replace(" ", "")
245 return type_name.startswith("&[") and type_name.endswith("]")