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+
84+
85+ return None
86+
87+ #=------------------------------------------------------------------------------
88+ # Pretty Printer Classes
89+ #=------------------------------------------------------------------------------
90+
91+ class RustStructPrinter :
92+ def __init__ (self , val , hide_first_field ):
93+ self .val = val
94+ self .hide_first_field = hide_first_field
95+
96+ def to_string (self ):
97+ return self .val .type .tag
98+
99+ def children (self ):
100+ cs = []
101+ for field in self .val .type .fields ():
102+ field_name = field .name ;
103+ if field_name == None :
104+ field_name = ""
105+ name_value_tuple = ( field_name , self .val [field ] )
106+ cs .append ( name_value_tuple )
107+
108+ if self .hide_first_field :
109+ cs = cs [1 :]
110+
111+ return cs
112+
113+ class RustTuplePrinter :
114+ def __init__ (self , val ):
115+ self .val = val
116+
117+ def to_string (self ):
118+ return None
119+
120+ def children (self ):
121+ cs = []
122+ for field in self .val .type .fields ():
123+ cs .append ( ("" , self .val [field ]) )
124+
125+ return cs
126+
127+ def display_hint (self ):
128+ return "array"
129+
130+ class RustTupleStructPrinter :
131+ def __init__ (self , val , hide_first_field ):
132+ self .val = val
133+ self .hide_first_field = hide_first_field
134+
135+ def to_string (self ):
136+ return self .val .type .tag
137+
138+ def children (self ):
139+ cs = []
140+ for field in self .val .type .fields ():
141+ cs .append ( ("" , self .val [field ]) )
142+
143+ if self .hide_first_field :
144+ cs = cs [1 :]
145+
146+ return cs
147+
148+ def display_hint (self ):
149+ return "array"
150+
151+ class RustStringSlicePrinter :
152+ def __init__ (self , val ):
153+ self .val = val
154+
155+ def to_string (self ):
156+ slice_byte_len = self .val ["length" ]
157+ return '"%s"' % self .val ["data_ptr" ].string (encoding = "utf-8" ,
158+ length = slice_byte_len )
159+
160+ class RustCStyleEnumPrinter :
161+ def __init__ (self , val ):
162+ assert val .type .code == gdb .TYPE_CODE_ENUM
163+ self .val = val
164+
165+ def to_string (self ):
166+ return str (self .val )
167+
168+ class IdentityPrinter :
169+ def __init__ (self , string ):
170+ self .string
171+
172+ def to_string (self ):
173+ return self .string
174+
175+ STRUCT_KIND_REGULAR_STRUCT = 0
176+ STRUCT_KIND_TUPLE_STRUCT = 1
177+ STRUCT_KIND_TUPLE = 2
178+ STRUCT_KIND_TUPLE_VARIANT = 3
179+ STRUCT_KIND_STRUCT_VARIANT = 4
180+ STRUCT_KIND_CSTYLE_VARIANT = 5
181+ STRUCT_KIND_STR_SLICE = 6
182+
183+ def classify_struct (type ):
184+ if type .tag == "&str" :
185+ return STRUCT_KIND_STR_SLICE
186+
187+ fields = list (type .fields ())
188+ field_count = len (fields )
189+
190+ if field_count == 0 :
191+ return STRUCT_KIND_REGULAR_STRUCT
192+
193+ if fields [0 ].artificial :
194+ if field_count == 1 :
195+ return STRUCT_KIND_CSTYLE_VARIANT
196+ elif fields [1 ].name == None :
197+ return STRUCT_KIND_TUPLE_VARIANT
198+ else :
199+ return STRUCT_KIND_STRUCT_VARIANT
200+
201+ if fields [0 ].name == None :
202+ if type .tag .startswith ("(" ):
203+ return STRUCT_KIND_TUPLE
204+ else :
205+ return STRUCT_KIND_TUPLE_STRUCT
206+
207+ return STRUCT_KIND_REGULAR_STRUCT
208+
209+ def extract_discriminant_value (enum_val ):
210+ assert enum_val .type .code == gdb .TYPE_CODE_UNION
211+ for variant_descriptor in enum_val .type .fields ():
212+ variant_val = enum_val [variant_descriptor ]
213+ for field in variant_val .type .fields ():
214+ return (field .name , int (variant_val [field ]))
215+
216+ def first_field (val ):
217+ for field in val .type .fields ():
218+ return field
219+
220+ def get_field_at_index (val , index ):
221+ i = 0
222+ for field in val .type .fields ():
223+ if i == index :
224+ return field
225+ return None
0 commit comments