]>
git.proxmox.com Git - rustc.git/blob - 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.
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.
14 def print_val(val
, internal_dict
):
15 '''Prints the given value with Rust syntax'''
16 type_class
= val
.GetType().GetTypeClass()
18 if type_class
== lldb
.eTypeClassStruct
:
19 return print_struct_val(val
, internal_dict
)
21 if type_class
== lldb
.eTypeClassUnion
:
22 return print_enum_val(val
, internal_dict
)
24 if type_class
== lldb
.eTypeClassPointer
:
25 return print_pointer_val(val
, internal_dict
)
27 if type_class
== lldb
.eTypeClassArray
:
28 return print_fixed_size_vec_val(val
, internal_dict
)
33 #=--------------------------------------------------------------------------------------------------
34 # Type-Specialized Printing Functions
35 #=--------------------------------------------------------------------------------------------------
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
42 return print_vec_slice_val(val
, internal_dict
)
44 return print_std_vec_val(val
, internal_dict
)
46 return print_struct_val_starting_from(0, val
, internal_dict
)
49 def print_struct_val_starting_from(field_start_index
, val
, internal_dict
):
51 Prints a struct, tuple, or tuple struct value with Rust syntax.
52 Ignores any fields before field_start_index.
54 assert val
.GetType().GetTypeClass() == lldb
.eTypeClassStruct
57 type_name
= extract_type_name(t
.GetName())
58 num_children
= val
.num_children
60 if (num_children
- field_start_index
) == 0:
61 # The only field of this struct is the enum discriminant
64 is_tuple_like
= type_is_tuple_like(t
)
67 template
= "%(type_name)s(%(body)s)"
70 template
= "%(type_name)s {\n%(body)s\n}"
73 if type_name
.startswith("("):
74 # this is a tuple, so don't print the type name
77 def render_child(child_index
):
80 field_name
= t
.GetFieldAtIndex(child_index
).GetName()
81 this
+= field_name
+ ": "
83 field_val
= val
.GetChildAtIndex(child_index
)
85 if not field_val
.IsValid():
86 field
= t
.GetFieldAtIndex(child_index
)
87 # LLDB is not good at handling zero-sized values, so we have to help
89 if field
.GetType().GetByteSize() == 0:
90 return this
+ extract_type_name(field
.GetType().GetName())
92 return this
+ "<invalid value>"
94 return this
+ print_val(field_val
, internal_dict
)
96 body
= separator
.join([render_child(idx
) for idx
in range(field_start_index
, num_children
)])
98 return template
% {"type_name": type_name
,
102 def print_enum_val(val
, internal_dict
):
103 '''Prints an enum value with Rust syntax'''
105 assert val
.GetType().GetTypeClass() == lldb
.eTypeClassUnion
107 if val
.num_children
== 1:
108 # This is either an enum with just one variant, or it is an Option-like
109 # enum where the discriminant is encoded in a non-nullable pointer
110 # field. We find out which one it is by looking at the member name of
111 # the sole union variant. If it starts with "RUST$ENCODED$ENUM$" then
112 # we have an Option-like enum.
113 first_variant_name
= val
.GetChildAtIndex(0).GetName()
114 if first_variant_name
and first_variant_name
.startswith("RUST$ENCODED$ENUM$"):
116 # This is an Option-like enum. The position of the discriminator field is
117 # encoded in the name which has the format:
118 # RUST$ENCODED$ENUM$<index of discriminator field>$<name of null variant>
119 last_separator_index
= first_variant_name
.rfind("$")
120 if last_separator_index
== -1:
121 return "<invalid enum encoding: %s>" % first_variant_name
123 start_index
= len("RUST$ENCODED$ENUM$")
125 # Extract indices of the discriminator field
127 disr_field_indices
= first_variant_name
[start_index
:last_separator_index
].split("$")
128 disr_field_indices
= [int(index
) for index
in disr_field_indices
]
130 return "<invalid enum encoding: %s>" % first_variant_name
132 # Read the discriminant
133 disr_val
= val
.GetChildAtIndex(0)
134 for index
in disr_field_indices
:
135 disr_val
= disr_val
.GetChildAtIndex(index
)
137 # If the discriminant field is a fat pointer we have to consider the
138 # first word as the true discriminant
139 if disr_val
.GetType().GetTypeClass() == lldb
.eTypeClassStruct
:
140 disr_val
= disr_val
.GetChildAtIndex(0)
142 if disr_val
.GetValueAsUnsigned() == 0:
143 # Null case: Print the name of the null-variant
144 null_variant_name
= first_variant_name
[last_separator_index
+ 1:]
145 return null_variant_name
147 # Non-null case: Interpret the data as a value of the non-null variant type
148 return print_struct_val_starting_from(0, val
.GetChildAtIndex(0), internal_dict
)
150 # This is just a regular uni-variant enum without discriminator field
151 return print_struct_val_starting_from(0, val
.GetChildAtIndex(0), internal_dict
)
153 # If we are here, this is a regular enum with more than one variant
154 disr_val
= val
.GetChildAtIndex(0).GetChildMemberWithName("RUST$ENUM$DISR")
155 disr_type
= disr_val
.GetType()
157 if disr_type
.GetTypeClass() != lldb
.eTypeClassEnumeration
:
158 return "<Invalid enum value encountered: Discriminator is not an enum>"
160 variant_index
= disr_val
.GetValueAsUnsigned()
161 return print_struct_val_starting_from(1, val
.GetChildAtIndex(variant_index
), internal_dict
)
164 def print_pointer_val(val
, internal_dict
):
165 '''Prints a pointer value with Rust syntax'''
166 assert val
.GetType().IsPointerType()
168 type_name
= extract_type_name(val
.GetType().GetName())
169 if type_name
and type_name
[0:1] in ["&", "~", "*"]:
170 sigil
= type_name
[0:1]
172 return sigil
+ hex(val
.GetValueAsUnsigned()) #print_val(val.Dereference(), internal_dict)
175 def print_fixed_size_vec_val(val
, internal_dict
):
176 assert val
.GetType().GetTypeClass() == lldb
.eTypeClassArray
180 for i
in range(val
.num_children
):
181 output
+= print_val(val
.GetChildAtIndex(i
), internal_dict
)
182 if i
!= val
.num_children
- 1:
189 def print_vec_slice_val(val
, internal_dict
):
190 length
= val
.GetChildAtIndex(1).GetValueAsUnsigned()
192 data_ptr_val
= val
.GetChildAtIndex(0)
193 data_ptr_type
= data_ptr_val
.GetType()
195 return "&[%s]" % print_array_of_values(val
.GetName(),
201 def print_std_vec_val(val
, internal_dict
):
202 length
= val
.GetChildAtIndex(1).GetValueAsUnsigned()
204 # Vec<> -> Unique<> -> NonZero<> -> *T
205 data_ptr_val
= val
.GetChildAtIndex(0).GetChildAtIndex(0).GetChildAtIndex(0)
206 data_ptr_type
= data_ptr_val
.GetType()
208 return "vec![%s]" % print_array_of_values(val
.GetName(),
213 #=--------------------------------------------------------------------------------------------------
215 #=--------------------------------------------------------------------------------------------------
217 unqualified_type_markers
= frozenset(["(", "[", "&", "*"])
220 def extract_type_name(qualified_type_name
):
221 '''Extracts the type name from a fully qualified path'''
222 if qualified_type_name
[0] in unqualified_type_markers
:
223 return qualified_type_name
225 end_of_search
= qualified_type_name
.find("<")
226 if end_of_search
< 0:
227 end_of_search
= len(qualified_type_name
)
229 index
= qualified_type_name
.rfind("::", 0, end_of_search
)
231 return qualified_type_name
233 return qualified_type_name
[index
+ 2:]
236 def type_is_tuple_like(ty
):
237 '''Returns true of this is a type with field names (struct, struct-like enum variant)'''
238 for field
in ty
.fields
:
239 if field
.GetName() == "RUST$ENUM$DISR":
240 # Ignore the enum discriminant field if there is one.
242 if (field
.GetName() is None) or (re
.match(r
"__\d+$", field
.GetName()) is None):
247 def is_vec_slice(val
):
249 if ty
.GetTypeClass() != lldb
.eTypeClassStruct
:
252 if ty
.GetNumberOfFields() != 2:
255 if ty
.GetFieldAtIndex(0).GetName() != "data_ptr":
258 if ty
.GetFieldAtIndex(1).GetName() != "length":
261 type_name
= extract_type_name(ty
.GetName()).replace("&'static", "&").replace(" ", "")
262 return type_name
.startswith("&[") and type_name
.endswith("]")
266 if ty
.GetTypeClass() != lldb
.eTypeClassStruct
:
269 if ty
.GetNumberOfFields() != 3:
272 if ty
.GetFieldAtIndex(0).GetName() != "ptr":
275 if ty
.GetFieldAtIndex(1).GetName() != "len":
278 if ty
.GetFieldAtIndex(2).GetName() != "cap":
281 return ty
.GetName().startswith("collections::vec::Vec<")
284 def print_array_of_values(array_name
, data_ptr_val
, length
, internal_dict
):
285 '''Prints a contigous memory range, interpreting it as values of the
286 pointee-type of data_ptr_val.'''
288 data_ptr_type
= data_ptr_val
.GetType()
289 assert data_ptr_type
.IsPointerType()
291 element_type
= data_ptr_type
.GetPointeeType()
292 element_type_size
= element_type
.GetByteSize()
294 start_address
= data_ptr_val
.GetValueAsUnsigned()
296 def render_element(i
):
297 address
= start_address
+ i
* element_type_size
298 element_val
= data_ptr_val
.CreateValueFromAddress(array_name
+ ("[%s]" % i
),
301 return print_val(element_val
, internal_dict
)
303 return ', '.join([render_element(i
) for i
in range(length
)])