xref: /aosp_15_r20/prebuilts/rust/linux-x86/1.80.1/lib/rustlib/etc/lldb_providers.py (revision b40554a23088fb75aa6945dfe8e65169c8484da3)
1import sys
2
3from lldb import SBData, SBError, eBasicTypeLong, eBasicTypeUnsignedLong, \
4    eBasicTypeUnsignedChar
5
6# from lldb.formatters import Logger
7
8####################################################################################################
9# This file contains two kinds of pretty-printers: summary and synthetic.
10#
11# Important classes from LLDB module:
12#   SBValue: the value of a variable, a register, or an expression
13#   SBType:  the data type; each SBValue has a corresponding SBType
14#
15# Summary provider is a function with the type `(SBValue, dict) -> str`.
16#   The first parameter is the object encapsulating the actual variable being displayed;
17#   The second parameter is an internal support parameter used by LLDB, and you should not touch it.
18#
19# Synthetic children is the way to provide a children-based representation of the object's value.
20# Synthetic provider is a class that implements the following interface:
21#
22#     class SyntheticChildrenProvider:
23#         def __init__(self, SBValue, dict)
24#         def num_children(self)
25#         def get_child_index(self, str)
26#         def get_child_at_index(self, int)
27#         def update(self)
28#         def has_children(self)
29#         def get_value(self)
30#
31#
32# You can find more information and examples here:
33#   1. https://lldb.llvm.org/varformats.html
34#   2. https://lldb.llvm.org/use/python-reference.html
35#   3. https://lldb.llvm.org/python_reference/lldb.formatters.cpp.libcxx-pysrc.html
36#   4. https://github.com/llvm-mirror/lldb/tree/master/examples/summaries/cocoa
37####################################################################################################
38
39PY3 = sys.version_info[0] == 3
40
41
42class ValueBuilder:
43    def __init__(self, valobj):
44        # type: (SBValue) -> ValueBuilder
45        self.valobj = valobj
46        process = valobj.GetProcess()
47        self.endianness = process.GetByteOrder()
48        self.pointer_size = process.GetAddressByteSize()
49
50    def from_int(self, name, value):
51        # type: (str, int) -> SBValue
52        type = self.valobj.GetType().GetBasicType(eBasicTypeLong)
53        data = SBData.CreateDataFromSInt64Array(self.endianness, self.pointer_size, [value])
54        return self.valobj.CreateValueFromData(name, data, type)
55
56    def from_uint(self, name, value):
57        # type: (str, int) -> SBValue
58        type = self.valobj.GetType().GetBasicType(eBasicTypeUnsignedLong)
59        data = SBData.CreateDataFromUInt64Array(self.endianness, self.pointer_size, [value])
60        return self.valobj.CreateValueFromData(name, data, type)
61
62
63def unwrap_unique_or_non_null(unique_or_nonnull):
64    # BACKCOMPAT: rust 1.32
65    # https://github.com/rust-lang/rust/commit/7a0911528058e87d22ea305695f4047572c5e067
66    # BACKCOMPAT: rust 1.60
67    # https://github.com/rust-lang/rust/commit/2a91eeac1a2d27dd3de1bf55515d765da20fd86f
68    ptr = unique_or_nonnull.GetChildMemberWithName("pointer")
69    return ptr if ptr.TypeIsPointerType() else ptr.GetChildAtIndex(0)
70
71
72class DefaultSyntheticProvider:
73    def __init__(self, valobj, dict):
74        # type: (SBValue, dict) -> DefaultSyntheticProvider
75        # logger = Logger.Logger()
76        # logger >> "Default synthetic provider for " + str(valobj.GetName())
77        self.valobj = valobj
78
79    def num_children(self):
80        # type: () -> int
81        return self.valobj.GetNumChildren()
82
83    def get_child_index(self, name):
84        # type: (str) -> int
85        return self.valobj.GetIndexOfChildWithName(name)
86
87    def get_child_at_index(self, index):
88        # type: (int) -> SBValue
89        return self.valobj.GetChildAtIndex(index)
90
91    def update(self):
92        # type: () -> None
93        pass
94
95    def has_children(self):
96        # type: () -> bool
97        return self.valobj.MightHaveChildren()
98
99
100class EmptySyntheticProvider:
101    def __init__(self, valobj, dict):
102        # type: (SBValue, dict) -> EmptySyntheticProvider
103        # logger = Logger.Logger()
104        # logger >> "[EmptySyntheticProvider] for " + str(valobj.GetName())
105        self.valobj = valobj
106
107    def num_children(self):
108        # type: () -> int
109        return 0
110
111    def get_child_index(self, name):
112        # type: (str) -> int
113        return None
114
115    def get_child_at_index(self, index):
116        # type: (int) -> SBValue
117        return None
118
119    def update(self):
120        # type: () -> None
121        pass
122
123    def has_children(self):
124        # type: () -> bool
125        return False
126
127
128def SizeSummaryProvider(valobj, dict):
129    # type: (SBValue, dict) -> str
130    return 'size=' + str(valobj.GetNumChildren())
131
132
133def vec_to_string(vec):
134    length = vec.GetNumChildren()
135    chars = [vec.GetChildAtIndex(i).GetValueAsUnsigned() for i in range(length)]
136    return bytes(chars).decode(errors='replace') if PY3 else "".join(chr(char) for char in chars)
137
138
139def StdStringSummaryProvider(valobj, dict):
140    # type: (SBValue, dict) -> str
141    # logger = Logger.Logger()
142    # logger >> "[StdStringSummaryProvider] for " + str(valobj.GetName())
143    vec = valobj.GetChildAtIndex(0)
144    return '"%s"' % vec_to_string(vec)
145
146
147def StdOsStringSummaryProvider(valobj, dict):
148    # type: (SBValue, dict) -> str
149    # logger = Logger.Logger()
150    # logger >> "[StdOsStringSummaryProvider] for " + str(valobj.GetName())
151    buf = valobj.GetChildAtIndex(0).GetChildAtIndex(0)
152    is_windows = "Wtf8Buf" in buf.type.name
153    vec = buf.GetChildAtIndex(0) if is_windows else buf
154    return '"%s"' % vec_to_string(vec)
155
156
157def StdStrSummaryProvider(valobj, dict):
158    # type: (SBValue, dict) -> str
159    # logger = Logger.Logger()
160    # logger >> "[StdStrSummaryProvider] for " + str(valobj.GetName())
161
162    # the code below assumes non-synthetic value, this makes sure the assumption holds
163    valobj = valobj.GetNonSyntheticValue()
164
165    length = valobj.GetChildMemberWithName("length").GetValueAsUnsigned()
166    if length == 0:
167        return '""'
168
169    data_ptr = valobj.GetChildMemberWithName("data_ptr")
170
171    start = data_ptr.GetValueAsUnsigned()
172    error = SBError()
173    process = data_ptr.GetProcess()
174    data = process.ReadMemory(start, length, error)
175    data = data.decode(encoding='UTF-8') if PY3 else data
176    return '"%s"' % data
177
178
179def StdPathBufSummaryProvider(valobj, dict):
180    # type: (SBValue, dict) -> str
181    # logger = Logger.Logger()
182    # logger >> "[StdPathBufSummaryProvider] for " + str(valobj.GetName())
183    return StdOsStringSummaryProvider(valobj.GetChildMemberWithName("inner"), dict)
184
185
186def StdPathSummaryProvider(valobj, dict):
187    # type: (SBValue, dict) -> str
188    # logger = Logger.Logger()
189    # logger >> "[StdPathSummaryProvider] for " + str(valobj.GetName())
190    length = valobj.GetChildMemberWithName("length").GetValueAsUnsigned()
191    if length == 0:
192        return '""'
193
194    data_ptr = valobj.GetChildMemberWithName("data_ptr")
195
196    start = data_ptr.GetValueAsUnsigned()
197    error = SBError()
198    process = data_ptr.GetProcess()
199    data = process.ReadMemory(start, length, error)
200    if PY3:
201        try:
202            data = data.decode(encoding='UTF-8')
203        except UnicodeDecodeError:
204            return '%r' % data
205    return '"%s"' % data
206
207
208class StructSyntheticProvider:
209    """Pretty-printer for structs and struct enum variants"""
210
211    def __init__(self, valobj, dict, is_variant=False):
212        # type: (SBValue, dict, bool) -> StructSyntheticProvider
213        # logger = Logger.Logger()
214        self.valobj = valobj
215        self.is_variant = is_variant
216        self.type = valobj.GetType()
217        self.fields = {}
218
219        if is_variant:
220            self.fields_count = self.type.GetNumberOfFields() - 1
221            real_fields = self.type.fields[1:]
222        else:
223            self.fields_count = self.type.GetNumberOfFields()
224            real_fields = self.type.fields
225
226        for number, field in enumerate(real_fields):
227            self.fields[field.name] = number
228
229    def num_children(self):
230        # type: () -> int
231        return self.fields_count
232
233    def get_child_index(self, name):
234        # type: (str) -> int
235        return self.fields.get(name, -1)
236
237    def get_child_at_index(self, index):
238        # type: (int) -> SBValue
239        if self.is_variant:
240            field = self.type.GetFieldAtIndex(index + 1)
241        else:
242            field = self.type.GetFieldAtIndex(index)
243        return self.valobj.GetChildMemberWithName(field.name)
244
245    def update(self):
246        # type: () -> None
247        pass
248
249    def has_children(self):
250        # type: () -> bool
251        return True
252
253class ClangEncodedEnumProvider:
254    """Pretty-printer for 'clang-encoded' enums support implemented in LLDB"""
255    DISCRIMINANT_MEMBER_NAME = "$discr$"
256    VALUE_MEMBER_NAME = "value"
257
258    def __init__(self, valobj, dict):
259        self.valobj = valobj
260        self.update()
261
262    def has_children(self):
263       return True
264
265    def num_children(self):
266        if self.is_default:
267            return 1
268        return 2
269
270    def get_child_index(self, name):
271        if name == ClangEncodedEnumProvider.VALUE_MEMBER_NAME:
272            return 0
273        if name == ClangEncodedEnumProvider.DISCRIMINANT_MEMBER_NAME:
274            return 1
275        return -1
276
277    def get_child_at_index(self, index):
278        if index == 0:
279            return self.variant.GetChildMemberWithName(ClangEncodedEnumProvider.VALUE_MEMBER_NAME)
280        if index == 1:
281            return self.variant.GetChildMemberWithName(
282                ClangEncodedEnumProvider.DISCRIMINANT_MEMBER_NAME)
283
284
285    def update(self):
286        all_variants = self.valobj.GetChildAtIndex(0)
287        index = self._getCurrentVariantIndex(all_variants)
288        self.variant = all_variants.GetChildAtIndex(index)
289        self.is_default = self.variant.GetIndexOfChildWithName(
290            ClangEncodedEnumProvider.DISCRIMINANT_MEMBER_NAME) == -1
291
292    def _getCurrentVariantIndex(self, all_variants):
293        default_index = 0
294        for i in range(all_variants.GetNumChildren()):
295            variant = all_variants.GetChildAtIndex(i)
296            discr = variant.GetChildMemberWithName(
297                ClangEncodedEnumProvider.DISCRIMINANT_MEMBER_NAME)
298            if discr.IsValid():
299                discr_unsigned_value = discr.GetValueAsUnsigned()
300                if variant.GetName() == f"$variant${discr_unsigned_value}":
301                    return i
302            else:
303                default_index = i
304        return default_index
305
306class TupleSyntheticProvider:
307    """Pretty-printer for tuples and tuple enum variants"""
308
309    def __init__(self, valobj, dict, is_variant=False):
310        # type: (SBValue, dict, bool) -> TupleSyntheticProvider
311        # logger = Logger.Logger()
312        self.valobj = valobj
313        self.is_variant = is_variant
314        self.type = valobj.GetType()
315
316        if is_variant:
317            self.size = self.type.GetNumberOfFields() - 1
318        else:
319            self.size = self.type.GetNumberOfFields()
320
321    def num_children(self):
322        # type: () -> int
323        return self.size
324
325    def get_child_index(self, name):
326        # type: (str) -> int
327        if name.isdigit():
328            return int(name)
329        else:
330            return -1
331
332    def get_child_at_index(self, index):
333        # type: (int) -> SBValue
334        if self.is_variant:
335            field = self.type.GetFieldAtIndex(index + 1)
336        else:
337            field = self.type.GetFieldAtIndex(index)
338        element = self.valobj.GetChildMemberWithName(field.name)
339        return self.valobj.CreateValueFromData(str(index), element.GetData(), element.GetType())
340
341    def update(self):
342        # type: () -> None
343        pass
344
345    def has_children(self):
346        # type: () -> bool
347        return True
348
349
350class StdVecSyntheticProvider:
351    """Pretty-printer for alloc::vec::Vec<T>
352
353    struct Vec<T> { buf: RawVec<T>, len: usize }
354    rust 1.75: struct RawVec<T> { ptr: Unique<T>, cap: usize, ... }
355    rust 1.76: struct RawVec<T> { ptr: Unique<T>, cap: Cap(usize), ... }
356    rust 1.31.1: struct Unique<T: ?Sized> { pointer: NonZero<*const T>, ... }
357    rust 1.33.0: struct Unique<T: ?Sized> { pointer: *const T, ... }
358    rust 1.62.0: struct Unique<T: ?Sized> { pointer: NonNull<T>, ... }
359    struct NonZero<T>(T)
360    struct NonNull<T> { pointer: *const T }
361    """
362
363    def __init__(self, valobj, dict):
364        # type: (SBValue, dict) -> StdVecSyntheticProvider
365        # logger = Logger.Logger()
366        # logger >> "[StdVecSyntheticProvider] for " + str(valobj.GetName())
367        self.valobj = valobj
368        self.update()
369
370    def num_children(self):
371        # type: () -> int
372        return self.length
373
374    def get_child_index(self, name):
375        # type: (str) -> int
376        index = name.lstrip('[').rstrip(']')
377        if index.isdigit():
378            return int(index)
379        else:
380            return -1
381
382    def get_child_at_index(self, index):
383        # type: (int) -> SBValue
384        start = self.data_ptr.GetValueAsUnsigned()
385        address = start + index * self.element_type_size
386        element = self.data_ptr.CreateValueFromAddress("[%s]" % index, address, self.element_type)
387        return element
388
389    def update(self):
390        # type: () -> None
391        self.length = self.valobj.GetChildMemberWithName("len").GetValueAsUnsigned()
392        self.buf = self.valobj.GetChildMemberWithName("buf")
393
394        self.data_ptr = unwrap_unique_or_non_null(self.buf.GetChildMemberWithName("ptr"))
395
396        self.element_type = self.data_ptr.GetType().GetPointeeType()
397        self.element_type_size = self.element_type.GetByteSize()
398
399    def has_children(self):
400        # type: () -> bool
401        return True
402
403
404class StdSliceSyntheticProvider:
405    def __init__(self, valobj, dict):
406        self.valobj = valobj
407        self.update()
408
409    def num_children(self):
410        # type: () -> int
411        return self.length
412
413    def get_child_index(self, name):
414        # type: (str) -> int
415        index = name.lstrip('[').rstrip(']')
416        if index.isdigit():
417            return int(index)
418        else:
419            return -1
420
421    def get_child_at_index(self, index):
422        # type: (int) -> SBValue
423        start = self.data_ptr.GetValueAsUnsigned()
424        address = start + index * self.element_type_size
425        element = self.data_ptr.CreateValueFromAddress("[%s]" % index, address, self.element_type)
426        return element
427
428    def update(self):
429        # type: () -> None
430        self.length = self.valobj.GetChildMemberWithName("length").GetValueAsUnsigned()
431        self.data_ptr = self.valobj.GetChildMemberWithName("data_ptr")
432
433        self.element_type = self.data_ptr.GetType().GetPointeeType()
434        self.element_type_size = self.element_type.GetByteSize()
435
436    def has_children(self):
437        # type: () -> bool
438        return True
439
440
441class StdVecDequeSyntheticProvider:
442    """Pretty-printer for alloc::collections::vec_deque::VecDeque<T>
443
444    struct VecDeque<T> { head: usize, len: usize, buf: RawVec<T> }
445    """
446
447    def __init__(self, valobj, dict):
448        # type: (SBValue, dict) -> StdVecDequeSyntheticProvider
449        # logger = Logger.Logger()
450        # logger >> "[StdVecDequeSyntheticProvider] for " + str(valobj.GetName())
451        self.valobj = valobj
452        self.update()
453
454    def num_children(self):
455        # type: () -> int
456        return self.size
457
458    def get_child_index(self, name):
459        # type: (str) -> int
460        index = name.lstrip('[').rstrip(']')
461        if index.isdigit() and int(index) < self.size:
462            return int(index)
463        else:
464            return -1
465
466    def get_child_at_index(self, index):
467        # type: (int) -> SBValue
468        start = self.data_ptr.GetValueAsUnsigned()
469        address = start + ((index + self.head) % self.cap) * self.element_type_size
470        element = self.data_ptr.CreateValueFromAddress("[%s]" % index, address, self.element_type)
471        return element
472
473    def update(self):
474        # type: () -> None
475        self.head = self.valobj.GetChildMemberWithName("head").GetValueAsUnsigned()
476        self.size = self.valobj.GetChildMemberWithName("len").GetValueAsUnsigned()
477        self.buf = self.valobj.GetChildMemberWithName("buf")
478        cap = self.buf.GetChildMemberWithName("cap")
479        if cap.GetType().num_fields == 1:
480            cap = cap.GetChildAtIndex(0)
481        self.cap = cap.GetValueAsUnsigned()
482
483        self.data_ptr = unwrap_unique_or_non_null(self.buf.GetChildMemberWithName("ptr"))
484
485        self.element_type = self.data_ptr.GetType().GetPointeeType()
486        self.element_type_size = self.element_type.GetByteSize()
487
488    def has_children(self):
489        # type: () -> bool
490        return True
491
492
493# BACKCOMPAT: rust 1.35
494class StdOldHashMapSyntheticProvider:
495    """Pretty-printer for std::collections::hash::map::HashMap<K, V, S>
496
497    struct HashMap<K, V, S> {..., table: RawTable<K, V>, ... }
498    struct RawTable<K, V> { capacity_mask: usize, size: usize, hashes: TaggedHashUintPtr, ... }
499    """
500
501    def __init__(self, valobj, dict, show_values=True):
502        # type: (SBValue, dict, bool) -> StdOldHashMapSyntheticProvider
503        self.valobj = valobj
504        self.show_values = show_values
505        self.update()
506
507    def num_children(self):
508        # type: () -> int
509        return self.size
510
511    def get_child_index(self, name):
512        # type: (str) -> int
513        index = name.lstrip('[').rstrip(']')
514        if index.isdigit():
515            return int(index)
516        else:
517            return -1
518
519    def get_child_at_index(self, index):
520        # type: (int) -> SBValue
521        # logger = Logger.Logger()
522        start = self.data_ptr.GetValueAsUnsigned() & ~1
523
524        # See `libstd/collections/hash/table.rs:raw_bucket_at
525        hashes = self.hash_uint_size * self.capacity
526        align = self.pair_type_size
527        # See `libcore/alloc.rs:padding_needed_for`
528        len_rounded_up = (((((hashes + align) % self.modulo - 1) % self.modulo) & ~(
529                (align - 1) % self.modulo)) % self.modulo - hashes) % self.modulo
530        # len_rounded_up = ((hashes + align - 1) & ~(align - 1)) - hashes
531
532        pairs_offset = hashes + len_rounded_up
533        pairs_start = start + pairs_offset
534
535        table_index = self.valid_indices[index]
536        idx = table_index & self.capacity_mask
537        address = pairs_start + idx * self.pair_type_size
538        element = self.data_ptr.CreateValueFromAddress("[%s]" % index, address, self.pair_type)
539        if self.show_values:
540            return element
541        else:
542            key = element.GetChildAtIndex(0)
543            return self.valobj.CreateValueFromData("[%s]" % index, key.GetData(), key.GetType())
544
545    def update(self):
546        # type: () -> None
547        # logger = Logger.Logger()
548
549        self.table = self.valobj.GetChildMemberWithName("table")  # type: SBValue
550        self.size = self.table.GetChildMemberWithName("size").GetValueAsUnsigned()
551        self.hashes = self.table.GetChildMemberWithName("hashes")
552        self.hash_uint_type = self.hashes.GetType()
553        self.hash_uint_size = self.hashes.GetType().GetByteSize()
554        self.modulo = 2 ** self.hash_uint_size
555        self.data_ptr = self.hashes.GetChildAtIndex(0).GetChildAtIndex(0)
556
557        self.capacity_mask = self.table.GetChildMemberWithName("capacity_mask").GetValueAsUnsigned()
558        self.capacity = (self.capacity_mask + 1) % self.modulo
559
560        marker = self.table.GetChildMemberWithName("marker").GetType()  # type: SBType
561        self.pair_type = marker.template_args[0]
562        self.pair_type_size = self.pair_type.GetByteSize()
563
564        self.valid_indices = []
565        for idx in range(self.capacity):
566            address = self.data_ptr.GetValueAsUnsigned() + idx * self.hash_uint_size
567            hash_uint = self.data_ptr.CreateValueFromAddress("[%s]" % idx, address,
568                                                             self.hash_uint_type)
569            hash_ptr = hash_uint.GetChildAtIndex(0).GetChildAtIndex(0)
570            if hash_ptr.GetValueAsUnsigned() != 0:
571                self.valid_indices.append(idx)
572
573        # logger >> "Valid indices: {}".format(str(self.valid_indices))
574
575    def has_children(self):
576        # type: () -> bool
577        return True
578
579
580class StdHashMapSyntheticProvider:
581    """Pretty-printer for hashbrown's HashMap"""
582
583    def __init__(self, valobj, dict, show_values=True):
584        # type: (SBValue, dict, bool) -> StdHashMapSyntheticProvider
585        self.valobj = valobj
586        self.show_values = show_values
587        self.update()
588
589    def num_children(self):
590        # type: () -> int
591        return self.size
592
593    def get_child_index(self, name):
594        # type: (str) -> int
595        index = name.lstrip('[').rstrip(']')
596        if index.isdigit():
597            return int(index)
598        else:
599            return -1
600
601    def get_child_at_index(self, index):
602        # type: (int) -> SBValue
603        pairs_start = self.data_ptr.GetValueAsUnsigned()
604        idx = self.valid_indices[index]
605        if self.new_layout:
606            idx = -(idx + 1)
607        address = pairs_start + idx * self.pair_type_size
608        element = self.data_ptr.CreateValueFromAddress("[%s]" % index, address, self.pair_type)
609        if self.show_values:
610            return element
611        else:
612            key = element.GetChildAtIndex(0)
613            return self.valobj.CreateValueFromData("[%s]" % index, key.GetData(), key.GetType())
614
615    def update(self):
616        # type: () -> None
617        table = self.table()
618        inner_table = table.GetChildMemberWithName("table")
619
620        capacity = inner_table.GetChildMemberWithName("bucket_mask").GetValueAsUnsigned() + 1
621        ctrl = inner_table.GetChildMemberWithName("ctrl").GetChildAtIndex(0)
622
623        self.size = inner_table.GetChildMemberWithName("items").GetValueAsUnsigned()
624        self.pair_type = table.type.template_args[0]
625        if self.pair_type.IsTypedefType():
626            self.pair_type = self.pair_type.GetTypedefedType()
627        self.pair_type_size = self.pair_type.GetByteSize()
628
629        self.new_layout = not inner_table.GetChildMemberWithName("data").IsValid()
630        if self.new_layout:
631            self.data_ptr = ctrl.Cast(self.pair_type.GetPointerType())
632        else:
633            self.data_ptr = inner_table.GetChildMemberWithName("data").GetChildAtIndex(0)
634
635        u8_type = self.valobj.GetTarget().GetBasicType(eBasicTypeUnsignedChar)
636        u8_type_size = self.valobj.GetTarget().GetBasicType(eBasicTypeUnsignedChar).GetByteSize()
637
638        self.valid_indices = []
639        for idx in range(capacity):
640            address = ctrl.GetValueAsUnsigned() + idx * u8_type_size
641            value = ctrl.CreateValueFromAddress("ctrl[%s]" % idx, address,
642                                                u8_type).GetValueAsUnsigned()
643            is_present = value & 128 == 0
644            if is_present:
645                self.valid_indices.append(idx)
646
647    def table(self):
648        # type: () -> SBValue
649        if self.show_values:
650            hashbrown_hashmap = self.valobj.GetChildMemberWithName("base")
651        else:
652            # BACKCOMPAT: rust 1.47
653            # HashSet wraps either std HashMap or hashbrown::HashSet, which both
654            # wrap hashbrown::HashMap, so either way we "unwrap" twice.
655            hashbrown_hashmap = self.valobj.GetChildAtIndex(0).GetChildAtIndex(0)
656        return hashbrown_hashmap.GetChildMemberWithName("table")
657
658    def has_children(self):
659        # type: () -> bool
660        return True
661
662
663def StdRcSummaryProvider(valobj, dict):
664    # type: (SBValue, dict) -> str
665    strong = valobj.GetChildMemberWithName("strong").GetValueAsUnsigned()
666    weak = valobj.GetChildMemberWithName("weak").GetValueAsUnsigned()
667    return "strong={}, weak={}".format(strong, weak)
668
669
670class StdRcSyntheticProvider:
671    """Pretty-printer for alloc::rc::Rc<T> and alloc::sync::Arc<T>
672
673    struct Rc<T> { ptr: NonNull<RcBox<T>>, ... }
674    rust 1.31.1: struct NonNull<T> { pointer: NonZero<*const T> }
675    rust 1.33.0: struct NonNull<T> { pointer: *const T }
676    struct NonZero<T>(T)
677    struct RcBox<T> { strong: Cell<usize>, weak: Cell<usize>, value: T }
678    struct Cell<T> { value: UnsafeCell<T> }
679    struct UnsafeCell<T> { value: T }
680
681    struct Arc<T> { ptr: NonNull<ArcInner<T>>, ... }
682    struct ArcInner<T> { strong: atomic::AtomicUsize, weak: atomic::AtomicUsize, data: T }
683    struct AtomicUsize { v: UnsafeCell<usize> }
684    """
685
686    def __init__(self, valobj, dict, is_atomic=False):
687        # type: (SBValue, dict, bool) -> StdRcSyntheticProvider
688        self.valobj = valobj
689
690        self.ptr = unwrap_unique_or_non_null(self.valobj.GetChildMemberWithName("ptr"))
691
692        self.value = self.ptr.GetChildMemberWithName("data" if is_atomic else "value")
693
694        self.strong = self.ptr.GetChildMemberWithName("strong").GetChildAtIndex(
695            0).GetChildMemberWithName("value")
696        self.weak = self.ptr.GetChildMemberWithName("weak").GetChildAtIndex(
697            0).GetChildMemberWithName("value")
698
699        self.value_builder = ValueBuilder(valobj)
700
701        self.update()
702
703    def num_children(self):
704        # type: () -> int
705        # Actually there are 3 children, but only the `value` should be shown as a child
706        return 1
707
708    def get_child_index(self, name):
709        # type: (str) -> int
710        if name == "value":
711            return 0
712        if name == "strong":
713            return 1
714        if name == "weak":
715            return 2
716        return -1
717
718    def get_child_at_index(self, index):
719        # type: (int) -> SBValue
720        if index == 0:
721            return self.value
722        if index == 1:
723            return self.value_builder.from_uint("strong", self.strong_count)
724        if index == 2:
725            return self.value_builder.from_uint("weak", self.weak_count)
726
727        return None
728
729    def update(self):
730        # type: () -> None
731        self.strong_count = self.strong.GetValueAsUnsigned()
732        self.weak_count = self.weak.GetValueAsUnsigned() - 1
733
734    def has_children(self):
735        # type: () -> bool
736        return True
737
738
739class StdCellSyntheticProvider:
740    """Pretty-printer for std::cell::Cell"""
741
742    def __init__(self, valobj, dict):
743        # type: (SBValue, dict) -> StdCellSyntheticProvider
744        self.valobj = valobj
745        self.value = valobj.GetChildMemberWithName("value").GetChildAtIndex(0)
746
747    def num_children(self):
748        # type: () -> int
749        return 1
750
751    def get_child_index(self, name):
752        # type: (str) -> int
753        if name == "value":
754            return 0
755        return -1
756
757    def get_child_at_index(self, index):
758        # type: (int) -> SBValue
759        if index == 0:
760            return self.value
761        return None
762
763    def update(self):
764        # type: () -> None
765        pass
766
767    def has_children(self):
768        # type: () -> bool
769        return True
770
771
772def StdRefSummaryProvider(valobj, dict):
773    # type: (SBValue, dict) -> str
774    borrow = valobj.GetChildMemberWithName("borrow").GetValueAsSigned()
775    return "borrow={}".format(borrow) if borrow >= 0 else "borrow_mut={}".format(-borrow)
776
777
778class StdRefSyntheticProvider:
779    """Pretty-printer for std::cell::Ref, std::cell::RefMut, and std::cell::RefCell"""
780
781    def __init__(self, valobj, dict, is_cell=False):
782        # type: (SBValue, dict, bool) -> StdRefSyntheticProvider
783        self.valobj = valobj
784
785        borrow = valobj.GetChildMemberWithName("borrow")
786        value = valobj.GetChildMemberWithName("value")
787        if is_cell:
788            self.borrow = borrow.GetChildMemberWithName("value").GetChildMemberWithName("value")
789            self.value = value.GetChildMemberWithName("value")
790        else:
791            self.borrow = borrow.GetChildMemberWithName("borrow").GetChildMemberWithName(
792                "value").GetChildMemberWithName("value")
793            self.value = value.Dereference()
794
795        self.value_builder = ValueBuilder(valobj)
796
797        self.update()
798
799    def num_children(self):
800        # type: () -> int
801        # Actually there are 2 children, but only the `value` should be shown as a child
802        return 1
803
804    def get_child_index(self, name):
805        if name == "value":
806            return 0
807        if name == "borrow":
808            return 1
809        return -1
810
811    def get_child_at_index(self, index):
812        # type: (int) -> SBValue
813        if index == 0:
814            return self.value
815        if index == 1:
816            return self.value_builder.from_int("borrow", self.borrow_count)
817        return None
818
819    def update(self):
820        # type: () -> None
821        self.borrow_count = self.borrow.GetValueAsSigned()
822
823    def has_children(self):
824        # type: () -> bool
825        return True
826
827
828def StdNonZeroNumberSummaryProvider(valobj, _dict):
829    # type: (SBValue, dict) -> str
830    inner = valobj.GetChildAtIndex(0)
831    inner_inner = inner.GetChildAtIndex(0)
832
833    # FIXME: Avoid printing as character literal,
834    #        see https://github.com/llvm/llvm-project/issues/65076.
835    if inner_inner.GetTypeName() in ['char', 'unsigned char']:
836      return str(inner_inner.GetValueAsSigned())
837    else:
838      return inner_inner.GetValue()
839