]>
Commit | Line | Data |
---|---|---|
1 | from sys import version_info | |
2 | ||
3 | import gdb | |
4 | from gdb import lookup_type | |
5 | ||
6 | if version_info[0] >= 3: | |
7 | xrange = range | |
8 | ||
9 | ZERO_FIELD = "__0" | |
10 | FIRST_FIELD = "__1" | |
11 | ||
12 | ||
13 | def unwrap_unique_or_non_null(unique_or_nonnull): | |
14 | # BACKCOMPAT: rust 1.32 | |
15 | # https://github.com/rust-lang/rust/commit/7a0911528058e87d22ea305695f4047572c5e067 | |
16 | ptr = unique_or_nonnull["pointer"] | |
17 | return ptr if ptr.type.code == gdb.TYPE_CODE_PTR else ptr[ZERO_FIELD] | |
18 | ||
19 | ||
20 | class EnumProvider: | |
21 | def __init__(self, valobj): | |
22 | content = valobj[valobj.type.fields()[0]] | |
23 | fields = content.type.fields() | |
24 | self.empty = len(fields) == 0 | |
25 | if not self.empty: | |
26 | if len(fields) == 1: | |
27 | discriminant = 0 | |
28 | else: | |
29 | discriminant = int(content[fields[0]]) + 1 | |
30 | self.active_variant = content[fields[discriminant]] | |
31 | self.name = fields[discriminant].name | |
32 | self.full_name = "{}::{}".format(valobj.type.name, self.name) | |
33 | else: | |
34 | self.full_name = valobj.type.name | |
35 | ||
36 | def to_string(self): | |
37 | return self.full_name | |
38 | ||
39 | def children(self): | |
40 | if not self.empty: | |
41 | yield self.name, self.active_variant | |
42 | ||
43 | ||
44 | class StdStringProvider: | |
45 | def __init__(self, valobj): | |
46 | self.valobj = valobj | |
47 | vec = valobj["vec"] | |
48 | self.length = int(vec["len"]) | |
49 | self.data_ptr = unwrap_unique_or_non_null(vec["buf"]["ptr"]) | |
50 | ||
51 | def to_string(self): | |
52 | return self.data_ptr.lazy_string(encoding="utf-8", length=self.length) | |
53 | ||
54 | @staticmethod | |
55 | def display_hint(): | |
56 | return "string" | |
57 | ||
58 | ||
59 | class StdOsStringProvider: | |
60 | def __init__(self, valobj): | |
61 | self.valobj = valobj | |
62 | buf = self.valobj["inner"]["inner"] | |
63 | is_windows = "Wtf8Buf" in buf.type.name | |
64 | vec = buf[ZERO_FIELD] if is_windows else buf | |
65 | ||
66 | self.length = int(vec["len"]) | |
67 | self.data_ptr = unwrap_unique_or_non_null(vec["buf"]["ptr"]) | |
68 | ||
69 | def to_string(self): | |
70 | return self.data_ptr.lazy_string(encoding="utf-8", length=self.length) | |
71 | ||
72 | def display_hint(self): | |
73 | return "string" | |
74 | ||
75 | ||
76 | class StdStrProvider: | |
77 | def __init__(self, valobj): | |
78 | self.valobj = valobj | |
79 | self.length = int(valobj["length"]) | |
80 | self.data_ptr = valobj["data_ptr"] | |
81 | ||
82 | def to_string(self): | |
83 | return self.data_ptr.lazy_string(encoding="utf-8", length=self.length) | |
84 | ||
85 | @staticmethod | |
86 | def display_hint(): | |
87 | return "string" | |
88 | ||
89 | ||
90 | class StdVecProvider: | |
91 | def __init__(self, valobj): | |
92 | self.valobj = valobj | |
93 | self.length = int(valobj["len"]) | |
94 | self.data_ptr = unwrap_unique_or_non_null(valobj["buf"]["ptr"]) | |
95 | ||
96 | def to_string(self): | |
97 | return "Vec(size={})".format(self.length) | |
98 | ||
99 | def children(self): | |
100 | saw_inaccessible = False | |
101 | for index in xrange(self.length): | |
102 | element_ptr = self.data_ptr + index | |
103 | if saw_inaccessible: | |
104 | return | |
105 | try: | |
106 | # rust-lang/rust#64343: passing deref expr to `str` allows | |
107 | # catching exception on garbage pointer | |
108 | str(element_ptr.dereference()) | |
109 | yield "[{}]".format(index), element_ptr.dereference() | |
110 | except RuntimeError: | |
111 | saw_inaccessible = True | |
112 | yield str(index), "inaccessible" | |
113 | ||
114 | @staticmethod | |
115 | def display_hint(): | |
116 | return "array" | |
117 | ||
118 | ||
119 | class StdVecDequeProvider: | |
120 | def __init__(self, valobj): | |
121 | self.valobj = valobj | |
122 | self.head = int(valobj["head"]) | |
123 | self.tail = int(valobj["tail"]) | |
124 | self.cap = int(valobj["buf"]["cap"]) | |
125 | self.data_ptr = unwrap_unique_or_non_null(valobj["buf"]["ptr"]) | |
126 | if self.head >= self.tail: | |
127 | self.size = self.head - self.tail | |
128 | else: | |
129 | self.size = self.cap + self.head - self.tail | |
130 | ||
131 | def to_string(self): | |
132 | return "VecDeque(size={})".format(self.size) | |
133 | ||
134 | def children(self): | |
135 | for index in xrange(0, self.size): | |
136 | value = (self.data_ptr + ((self.tail + index) % self.cap)).dereference() | |
137 | yield "[{}]".format(index), value | |
138 | ||
139 | @staticmethod | |
140 | def display_hint(): | |
141 | return "array" | |
142 | ||
143 | ||
144 | class StdRcProvider: | |
145 | def __init__(self, valobj, is_atomic=False): | |
146 | self.valobj = valobj | |
147 | self.is_atomic = is_atomic | |
148 | self.ptr = unwrap_unique_or_non_null(valobj["ptr"]) | |
149 | self.value = self.ptr["data" if is_atomic else "value"] | |
150 | self.strong = self.ptr["strong"]["v" if is_atomic else "value"]["value"] | |
151 | self.weak = self.ptr["weak"]["v" if is_atomic else "value"]["value"] - 1 | |
152 | ||
153 | def to_string(self): | |
154 | if self.is_atomic: | |
155 | return "Arc(strong={}, weak={})".format(int(self.strong), int(self.weak)) | |
156 | else: | |
157 | return "Rc(strong={}, weak={})".format(int(self.strong), int(self.weak)) | |
158 | ||
159 | def children(self): | |
160 | yield "value", self.value | |
161 | yield "strong", self.strong | |
162 | yield "weak", self.weak | |
163 | ||
164 | ||
165 | class StdCellProvider: | |
166 | def __init__(self, valobj): | |
167 | self.value = valobj["value"]["value"] | |
168 | ||
169 | def to_string(self): | |
170 | return "Cell" | |
171 | ||
172 | def children(self): | |
173 | yield "value", self.value | |
174 | ||
175 | ||
176 | class StdRefProvider: | |
177 | def __init__(self, valobj): | |
178 | self.value = valobj["value"].dereference() | |
179 | self.borrow = valobj["borrow"]["borrow"]["value"]["value"] | |
180 | ||
181 | def to_string(self): | |
182 | borrow = int(self.borrow) | |
183 | if borrow >= 0: | |
184 | return "Ref(borrow={})".format(borrow) | |
185 | else: | |
186 | return "Ref(borrow_mut={})".format(-borrow) | |
187 | ||
188 | def children(self): | |
189 | yield "*value", self.value | |
190 | yield "borrow", self.borrow | |
191 | ||
192 | ||
193 | class StdRefCellProvider: | |
194 | def __init__(self, valobj): | |
195 | self.value = valobj["value"]["value"] | |
196 | self.borrow = valobj["borrow"]["value"]["value"] | |
197 | ||
198 | def to_string(self): | |
199 | borrow = int(self.borrow) | |
200 | if borrow >= 0: | |
201 | return "RefCell(borrow={})".format(borrow) | |
202 | else: | |
203 | return "RefCell(borrow_mut={})".format(-borrow) | |
204 | ||
205 | def children(self): | |
206 | yield "value", self.value | |
207 | yield "borrow", self.borrow | |
208 | ||
209 | ||
210 | # Yield each key (and optionally value) from a BoxedNode. | |
211 | def children_of_node(boxed_node, height, want_values): | |
212 | def cast_to_internal(node): | |
213 | internal_type_name = str(node.type.target()).replace("LeafNode", "InternalNode", 1) | |
214 | internal_type = lookup_type(internal_type_name) | |
215 | return node.cast(internal_type.pointer()) | |
216 | ||
217 | node_ptr = unwrap_unique_or_non_null(boxed_node["ptr"]) | |
218 | node_ptr = cast_to_internal(node_ptr) if height > 0 else node_ptr | |
219 | leaf = node_ptr["data"] if height > 0 else node_ptr.dereference() | |
220 | keys = leaf["keys"] | |
221 | values = leaf["vals"] | |
222 | length = int(leaf["len"]) | |
223 | ||
224 | for i in xrange(0, length + 1): | |
225 | if height > 0: | |
226 | child_ptr = node_ptr["edges"][i]["value"]["value"] | |
227 | for child in children_of_node(child_ptr, height - 1, want_values): | |
228 | yield child | |
229 | if i < length: | |
230 | if want_values: | |
231 | yield keys[i]["value"]["value"], values[i]["value"]["value"] | |
232 | else: | |
233 | yield keys[i]["value"]["value"] | |
234 | ||
235 | ||
236 | class StdBTreeSetProvider: | |
237 | def __init__(self, valobj): | |
238 | self.valobj = valobj | |
239 | ||
240 | def to_string(self): | |
241 | return "BTreeSet(size={})".format(self.valobj["map"]["length"]) | |
242 | ||
243 | def children(self): | |
244 | inner_map = self.valobj["map"] | |
245 | if inner_map["length"] > 0: | |
246 | root = inner_map["root"] | |
247 | if "core::option::Option<" in root.type.name: | |
248 | type_name = str(root.type.name).replace("core::option::Option<", "", 1)[:-1] | |
249 | root = root.cast(gdb.lookup_type(type_name)) | |
250 | ||
251 | node_ptr = root["node"] | |
252 | for i, child in enumerate(children_of_node(node_ptr, root["height"], False)): | |
253 | yield "[{}]".format(i), child | |
254 | ||
255 | @staticmethod | |
256 | def display_hint(): | |
257 | return "array" | |
258 | ||
259 | ||
260 | class StdBTreeMapProvider: | |
261 | def __init__(self, valobj): | |
262 | self.valobj = valobj | |
263 | ||
264 | def to_string(self): | |
265 | return "BTreeMap(size={})".format(self.valobj["length"]) | |
266 | ||
267 | def children(self): | |
268 | if self.valobj["length"] > 0: | |
269 | root = self.valobj["root"] | |
270 | if "core::option::Option<" in root.type.name: | |
271 | type_name = str(root.type.name).replace("core::option::Option<", "", 1)[:-1] | |
272 | root = root.cast(gdb.lookup_type(type_name)) | |
273 | ||
274 | node_ptr = root["node"] | |
275 | for i, child in enumerate(children_of_node(node_ptr, root["height"], True)): | |
276 | yield "key{}".format(i), child[0] | |
277 | yield "val{}".format(i), child[1] | |
278 | ||
279 | @staticmethod | |
280 | def display_hint(): | |
281 | return "map" | |
282 | ||
283 | ||
284 | # BACKCOMPAT: rust 1.35 | |
285 | class StdOldHashMapProvider: | |
286 | def __init__(self, valobj, show_values=True): | |
287 | self.valobj = valobj | |
288 | self.show_values = show_values | |
289 | ||
290 | self.table = self.valobj["table"] | |
291 | self.size = int(self.table["size"]) | |
292 | self.hashes = self.table["hashes"] | |
293 | self.hash_uint_type = self.hashes.type | |
294 | self.hash_uint_size = self.hashes.type.sizeof | |
295 | self.modulo = 2 ** self.hash_uint_size | |
296 | self.data_ptr = self.hashes[ZERO_FIELD]["pointer"] | |
297 | ||
298 | self.capacity_mask = int(self.table["capacity_mask"]) | |
299 | self.capacity = (self.capacity_mask + 1) % self.modulo | |
300 | ||
301 | marker = self.table["marker"].type | |
302 | self.pair_type = marker.template_argument(0) | |
303 | self.pair_type_size = self.pair_type.sizeof | |
304 | ||
305 | self.valid_indices = [] | |
306 | for idx in range(self.capacity): | |
307 | data_ptr = self.data_ptr.cast(self.hash_uint_type.pointer()) | |
308 | address = data_ptr + idx | |
309 | hash_uint = address.dereference() | |
310 | hash_ptr = hash_uint[ZERO_FIELD]["pointer"] | |
311 | if int(hash_ptr) != 0: | |
312 | self.valid_indices.append(idx) | |
313 | ||
314 | def to_string(self): | |
315 | if self.show_values: | |
316 | return "HashMap(size={})".format(self.size) | |
317 | else: | |
318 | return "HashSet(size={})".format(self.size) | |
319 | ||
320 | def children(self): | |
321 | start = int(self.data_ptr) & ~1 | |
322 | ||
323 | hashes = self.hash_uint_size * self.capacity | |
324 | align = self.pair_type_size | |
325 | len_rounded_up = (((((hashes + align) % self.modulo - 1) % self.modulo) & ~( | |
326 | (align - 1) % self.modulo)) % self.modulo - hashes) % self.modulo | |
327 | ||
328 | pairs_offset = hashes + len_rounded_up | |
329 | pairs_start = gdb.Value(start + pairs_offset).cast(self.pair_type.pointer()) | |
330 | ||
331 | for index in range(self.size): | |
332 | table_index = self.valid_indices[index] | |
333 | idx = table_index & self.capacity_mask | |
334 | element = (pairs_start + idx).dereference() | |
335 | if self.show_values: | |
336 | yield "key{}".format(index), element[ZERO_FIELD] | |
337 | yield "val{}".format(index), element[FIRST_FIELD] | |
338 | else: | |
339 | yield "[{}]".format(index), element[ZERO_FIELD] | |
340 | ||
341 | def display_hint(self): | |
342 | return "map" if self.show_values else "array" | |
343 | ||
344 | ||
345 | class StdHashMapProvider: | |
346 | def __init__(self, valobj, show_values=True): | |
347 | self.valobj = valobj | |
348 | self.show_values = show_values | |
349 | ||
350 | table = self.valobj["base"]["table"] | |
351 | capacity = int(table["bucket_mask"]) + 1 | |
352 | ctrl = table["ctrl"]["pointer"] | |
353 | ||
354 | self.size = int(table["items"]) | |
355 | self.pair_type = table.type.template_argument(0) | |
356 | ||
357 | self.new_layout = not table.type.has_key("data") | |
358 | if self.new_layout: | |
359 | self.data_ptr = ctrl.cast(self.pair_type.pointer()) | |
360 | else: | |
361 | self.data_ptr = table["data"]["pointer"] | |
362 | ||
363 | self.valid_indices = [] | |
364 | for idx in range(capacity): | |
365 | address = ctrl + idx | |
366 | value = address.dereference() | |
367 | is_presented = value & 128 == 0 | |
368 | if is_presented: | |
369 | self.valid_indices.append(idx) | |
370 | ||
371 | def to_string(self): | |
372 | if self.show_values: | |
373 | return "HashMap(size={})".format(self.size) | |
374 | else: | |
375 | return "HashSet(size={})".format(self.size) | |
376 | ||
377 | def children(self): | |
378 | pairs_start = self.data_ptr | |
379 | ||
380 | for index in range(self.size): | |
381 | idx = self.valid_indices[index] | |
382 | if self.new_layout: | |
383 | idx = -(idx + 1) | |
384 | element = (pairs_start + idx).dereference() | |
385 | if self.show_values: | |
386 | yield "key{}".format(index), element[ZERO_FIELD] | |
387 | yield "val{}".format(index), element[FIRST_FIELD] | |
388 | else: | |
389 | yield "[{}]".format(index), element[ZERO_FIELD] | |
390 | ||
391 | def display_hint(self): | |
392 | return "map" if self.show_values else "array" |