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.
13 def print_val(val, internal_dict):
14 '''Prints the given value with Rust syntax'''
15 type_class = val.GetType().GetTypeClass()
17 if type_class == lldb.eTypeClassStruct:
18 return print_struct_val(val, internal_dict)
20 if type_class == lldb.eTypeClassUnion:
21 return print_enum_val(val, internal_dict)
23 if type_class == lldb.eTypeClassPointer:
24 return print_pointer_val(val, internal_dict)
26 if type_class == lldb.eTypeClassArray:
27 return print_fixed_size_vec_val(val, internal_dict)
32 #=--------------------------------------------------------------------------------------------------
33 # Type-Specialized Printing Functions
34 #=--------------------------------------------------------------------------------------------------
36 def print_struct_val(val, internal_dict):
37 '''Prints a struct, tuple, or tuple struct value with Rust syntax'''
38 assert val.GetType().GetTypeClass() == lldb.eTypeClassStruct
41 return print_vec_slice_val(val, internal_dict)
43 return print_struct_val_starting_from(0, val, internal_dict)
45 def print_vec_slice_val(val, internal_dict):
46 length = val.GetChildAtIndex(1).GetValueAsUnsigned()
48 data_ptr_val = val.GetChildAtIndex(0)
49 data_ptr_type = data_ptr_val.GetType()
50 assert data_ptr_type.IsPointerType()
52 element_type = data_ptr_type.GetPointeeType()
53 element_type_size = element_type.GetByteSize()
55 start_address = data_ptr_val.GetValueAsUnsigned()
57 def render_element(i):
58 address = start_address + i * element_type_size
59 element_val = val.CreateValueFromAddress( val.GetName() + ("[%s]" % i), address, element_type)
60 return print_val(element_val, internal_dict)
62 return "&[%s]" % (', '.join([render_element(i) for i in range(length)]))
64 def print_struct_val_starting_from(field_start_index, val, internal_dict):
66 Prints a struct, tuple, or tuple struct value with Rust syntax.
67 Ignores any fields before field_start_index.
69 assert val.GetType().GetTypeClass() == lldb.eTypeClassStruct
72 type_name = extract_type_name(t.GetName())
73 num_children = val.num_children
75 if (num_children - field_start_index) == 0:
76 # The only field of this struct is the enum discriminant
79 has_field_names = type_has_field_names(t)
82 template = "%(type_name)s {\n%(body)s\n}"
85 template = "%(type_name)s(%(body)s)"
88 if type_name.startswith("("):
89 # this is a tuple, so don't print the type name
92 def render_child(child_index):
95 field_name = t.GetFieldAtIndex(child_index).GetName()
96 this += field_name + ": "
98 field_val = val.GetChildAtIndex(child_index)
99 return this + print_val(field_val, internal_dict)
101 body = separator.join([render_child(idx) for idx in range(field_start_index, num_children)])
103 return template % {"type_name": type_name,
107 def print_enum_val(val, internal_dict):
108 '''Prints an enum value with Rust syntax'''
110 assert val.GetType().GetTypeClass() == lldb.eTypeClassUnion
112 if val.num_children == 1:
113 # This is either an enum with just one variant, or it is an Option-like enum
114 # where the discriminant is encoded in a non-nullable pointer field. We find
115 # out which one it is by looking at the member name of the sole union
116 # variant. If it starts with "RUST$ENCODED$ENUM$" then we have an
118 first_variant_name = val.GetChildAtIndex(0).GetName()
119 if first_variant_name and first_variant_name.startswith("RUST$ENCODED$ENUM$"):
121 # This is an Option-like enum. The position of the discriminator field is
122 # encoded in the name which has the format:
123 # RUST$ENCODED$ENUM$<index of discriminator field>$<name of null variant>
124 last_separator_index = first_variant_name.rfind("$")
125 if last_separator_index == -1:
126 return "<invalid enum encoding: %s>" % first_variant_name
128 start_index = len("RUST$ENCODED$ENUM$")
130 # Extract indices of the discriminator field
132 disr_field_indices = first_variant_name[start_index :
133 last_separator_index].split("$")
134 disr_field_indices = [int(index) for index in disr_field_indices]
136 return "<invalid enum encoding: %s>" % first_variant_name
138 # Read the discriminant
139 disr_val = val.GetChildAtIndex(0)
140 for index in disr_field_indices:
141 disr_val = disr_val.GetChildAtIndex(index)
143 # If the discriminant field is a fat pointer we have to consider the
144 # first word as the true discriminant
145 if disr_val.GetType().GetTypeClass() == lldb.eTypeClassStruct:
146 disr_val = disr_val.GetChildAtIndex(0)
148 if disr_val.GetValueAsUnsigned() == 0:
149 # Null case: Print the name of the null-variant
150 null_variant_name = first_variant_name[last_separator_index + 1:]
151 return null_variant_name
153 # Non-null case: Interpret the data as a value of the non-null variant type
154 return print_struct_val_starting_from(0, val.GetChildAtIndex(0), internal_dict)
156 # This is just a regular uni-variant enum without discriminator field
157 return print_struct_val_starting_from(0, val.GetChildAtIndex(0), internal_dict)
159 # If we are here, this is a regular enum with more than one variant
160 disr_val = val.GetChildAtIndex(0).GetChildMemberWithName("RUST$ENUM$DISR")
161 disr_type = disr_val.GetType()
163 if disr_type.GetTypeClass() != lldb.eTypeClassEnumeration:
164 return "<Invalid enum value encountered: Discriminator is not an enum>"
166 variant_index = disr_val.GetValueAsUnsigned()
167 return print_struct_val_starting_from(1, val.GetChildAtIndex(variant_index), internal_dict)
170 def print_pointer_val(val, internal_dict):
171 '''Prints a pointer value with Rust syntax'''
172 assert val.GetType().IsPointerType()
174 type_name = extract_type_name(val.GetType().GetName())
175 if type_name and type_name[0:1] in ["&", "~", "*"]:
176 sigil = type_name[0:1]
178 return sigil + hex(val.GetValueAsUnsigned()) #print_val(val.Dereference(), internal_dict)
181 def print_fixed_size_vec_val(val, internal_dict):
182 assert val.GetType().GetTypeClass() == lldb.eTypeClassArray
186 for i in range(val.num_children):
187 output += print_val(val.GetChildAtIndex(i), internal_dict)
188 if i != val.num_children - 1:
195 #=--------------------------------------------------------------------------------------------------
197 #=--------------------------------------------------------------------------------------------------
199 unqualified_type_markers = frozenset(["(", "[", "&", "*"])
201 def extract_type_name(qualified_type_name):
202 '''Extracts the type name from a fully qualified path'''
203 if qualified_type_name[0] in unqualified_type_markers:
204 return qualified_type_name
206 end_of_search = qualified_type_name.find("<")
207 if end_of_search < 0:
208 end_of_search = len(qualified_type_name)
210 index = qualified_type_name.rfind("::", 0, end_of_search)
212 return qualified_type_name
214 return qualified_type_name[index + 2:]
217 def type_has_field_names(ty):
218 '''Returns true of this is a type with field names (struct, struct-like enum variant)'''
219 # This may also be an enum variant where the first field doesn't have a name but the rest has
220 if ty.GetNumberOfFields() > 1:
221 return ty.GetFieldAtIndex(1).GetName() != None
223 return ty.GetFieldAtIndex(0).GetName() != None
226 def is_vec_slice(val):
228 if ty.GetTypeClass() != lldb.eTypeClassStruct:
231 if ty.GetNumberOfFields() != 2:
234 if ty.GetFieldAtIndex(0).GetName() != "data_ptr":
237 if ty.GetFieldAtIndex(1).GetName() != "length":
240 type_name = extract_type_name(ty.GetName()).replace("&'static", "&").replace(" ", "")
241 return type_name.startswith("&[") and type_name.endswith("]")