3 from lldb
import SBValue
, SBData
, SBError
, eBasicTypeLong
, eBasicTypeUnsignedLong
, \
6 # from lldb.formatters import Logger
8 ####################################################################################################
9 # This file contains two kinds of pretty-printers: summary and synthetic.
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
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.
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:
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)
28 # def has_children(self)
32 # You can find more information and examples here:
33 # 1. https://lldb.llvm.org/varformats.html
34 # 2. https://lldb.llvm.org/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 ####################################################################################################
39 PY3
= sys
.version_info
[0] == 3
43 def __init__(self
, valobj
):
44 # type: (SBValue) -> ValueBuilder
46 process
= valobj
.GetProcess()
47 self
.endianness
= process
.GetByteOrder()
48 self
.pointer_size
= process
.GetAddressByteSize()
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)
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)
63 def unwrap_unique_or_non_null(unique_or_nonnull
):
64 # BACKCOMPAT: rust 1.32
65 # https://github.com/rust-lang/rust/commit/7a0911528058e87d22ea305695f4047572c5e067
66 ptr
= unique_or_nonnull
.GetChildMemberWithName("pointer")
67 return ptr
if ptr
.TypeIsPointerType() else ptr
.GetChildAtIndex(0)
70 class DefaultSynthteticProvider
:
71 def __init__(self
, valobj
, dict):
72 # type: (SBValue, dict) -> DefaultSynthteticProvider
73 # logger = Logger.Logger()
74 # logger >> "Default synthetic provider for " + str(valobj.GetName())
77 def num_children(self
):
79 return self
.valobj
.GetNumChildren()
81 def get_child_index(self
, name
):
83 return self
.valobj
.GetIndexOfChildWithName(name
)
85 def get_child_at_index(self
, index
):
86 # type: (int) -> SBValue
87 return self
.valobj
.GetChildAtIndex(index
)
93 def has_children(self
):
95 return self
.valobj
.MightHaveChildren()
98 class EmptySyntheticProvider
:
99 def __init__(self
, valobj
, dict):
100 # type: (SBValue, dict) -> EmptySyntheticProvider
101 # logger = Logger.Logger()
102 # logger >> "[EmptySyntheticProvider] for " + str(valobj.GetName())
105 def num_children(self
):
109 def get_child_index(self
, name
):
113 def get_child_at_index(self
, index
):
114 # type: (int) -> SBValue
121 def has_children(self
):
126 def SizeSummaryProvider(valobj
, dict):
127 # type: (SBValue, dict) -> str
128 return 'size=' + str(valobj
.GetNumChildren())
131 def vec_to_string(vec
):
132 length
= vec
.GetNumChildren()
133 chars
= [vec
.GetChildAtIndex(i
).GetValueAsUnsigned() for i
in range(length
)]
134 return bytes(chars
).decode(errors
='replace') if PY3
else "".join(chr(char
) for char
in chars
)
137 def StdStringSummaryProvider(valobj
, dict):
138 # type: (SBValue, dict) -> str
139 # logger = Logger.Logger()
140 # logger >> "[StdStringSummaryProvider] for " + str(valobj.GetName())
141 vec
= valobj
.GetChildAtIndex(0)
142 return '"%s"' % vec_to_string(vec
)
145 def StdOsStringSummaryProvider(valobj
, dict):
146 # type: (SBValue, dict) -> str
147 # logger = Logger.Logger()
148 # logger >> "[StdOsStringSummaryProvider] for " + str(valobj.GetName())
149 buf
= valobj
.GetChildAtIndex(0).GetChildAtIndex(0)
150 is_windows
= "Wtf8Buf" in buf
.type.name
151 vec
= buf
.GetChildAtIndex(0) if is_windows
else buf
152 return '"%s"' % vec_to_string(vec
)
155 def StdStrSummaryProvider(valobj
, dict):
156 # type: (SBValue, dict) -> str
157 # logger = Logger.Logger()
158 # logger >> "[StdStrSummaryProvider] for " + str(valobj.GetName())
160 length
= valobj
.GetChildMemberWithName("length").GetValueAsUnsigned()
164 data_ptr
= valobj
.GetChildMemberWithName("data_ptr")
166 start
= data_ptr
.GetValueAsUnsigned()
168 process
= data_ptr
.GetProcess()
169 data
= process
.ReadMemory(start
, length
, error
)
170 data
= data
.decode(encoding
='UTF-8') if PY3
else data
174 class StructSyntheticProvider
:
175 """Pretty-printer for structs and struct enum variants"""
177 def __init__(self
, valobj
, dict, is_variant
=False):
178 # type: (SBValue, dict, bool) -> StructSyntheticProvider
179 # logger = Logger.Logger()
181 self
.is_variant
= is_variant
182 self
.type = valobj
.GetType()
186 self
.fields_count
= self
.type.GetNumberOfFields() - 1
187 real_fields
= self
.type.fields
[1:]
189 self
.fields_count
= self
.type.GetNumberOfFields()
190 real_fields
= self
.type.fields
192 for number
, field
in enumerate(real_fields
):
193 self
.fields
[field
.name
] = number
195 def num_children(self
):
197 return self
.fields_count
199 def get_child_index(self
, name
):
201 return self
.fields
.get(name
, -1)
203 def get_child_at_index(self
, index
):
204 # type: (int) -> SBValue
206 field
= self
.type.GetFieldAtIndex(index
+ 1)
208 field
= self
.type.GetFieldAtIndex(index
)
209 return self
.valobj
.GetChildMemberWithName(field
.name
)
215 def has_children(self
):
220 class TupleSyntheticProvider
:
221 """Pretty-printer for tuples and tuple enum variants"""
223 def __init__(self
, valobj
, dict, is_variant
=False):
224 # type: (SBValue, dict, bool) -> TupleSyntheticProvider
225 # logger = Logger.Logger()
227 self
.is_variant
= is_variant
228 self
.type = valobj
.GetType()
231 self
.size
= self
.type.GetNumberOfFields() - 1
233 self
.size
= self
.type.GetNumberOfFields()
235 def num_children(self
):
239 def get_child_index(self
, name
):
246 def get_child_at_index(self
, index
):
247 # type: (int) -> SBValue
249 field
= self
.type.GetFieldAtIndex(index
+ 1)
251 field
= self
.type.GetFieldAtIndex(index
)
252 element
= self
.valobj
.GetChildMemberWithName(field
.name
)
253 return self
.valobj
.CreateValueFromData(str(index
), element
.GetData(), element
.GetType())
259 def has_children(self
):
264 class StdVecSyntheticProvider
:
265 """Pretty-printer for alloc::vec::Vec<T>
267 struct Vec<T> { buf: RawVec<T>, len: usize }
268 struct RawVec<T> { ptr: Unique<T>, cap: usize, ... }
269 rust 1.31.1: struct Unique<T: ?Sized> { pointer: NonZero<*const T>, ... }
270 rust 1.33.0: struct Unique<T: ?Sized> { pointer: *const T, ... }
274 def __init__(self
, valobj
, dict):
275 # type: (SBValue, dict) -> StdVecSyntheticProvider
276 # logger = Logger.Logger()
277 # logger >> "[StdVecSyntheticProvider] for " + str(valobj.GetName())
281 def num_children(self
):
285 def get_child_index(self
, name
):
287 index
= name
.lstrip('[').rstrip(']')
293 def get_child_at_index(self
, index
):
294 # type: (int) -> SBValue
295 start
= self
.data_ptr
.GetValueAsUnsigned()
296 address
= start
+ index
* self
.element_type_size
297 element
= self
.data_ptr
.CreateValueFromAddress("[%s]" % index
, address
, self
.element_type
)
302 self
.length
= self
.valobj
.GetChildMemberWithName("len").GetValueAsUnsigned()
303 self
.buf
= self
.valobj
.GetChildMemberWithName("buf")
305 self
.data_ptr
= unwrap_unique_or_non_null(self
.buf
.GetChildMemberWithName("ptr"))
307 self
.element_type
= self
.data_ptr
.GetType().GetPointeeType()
308 self
.element_type_size
= self
.element_type
.GetByteSize()
310 def has_children(self
):
315 class StdSliceSyntheticProvider
:
316 def __init__(self
, valobj
, dict):
320 def num_children(self
):
324 def get_child_index(self
, name
):
326 index
= name
.lstrip('[').rstrip(']')
332 def get_child_at_index(self
, index
):
333 # type: (int) -> SBValue
334 start
= self
.data_ptr
.GetValueAsUnsigned()
335 address
= start
+ index
* self
.element_type_size
336 element
= self
.data_ptr
.CreateValueFromAddress("[%s]" % index
, address
, self
.element_type
)
341 self
.length
= self
.valobj
.GetChildMemberWithName("length").GetValueAsUnsigned()
342 self
.data_ptr
= self
.valobj
.GetChildMemberWithName("data_ptr")
344 self
.element_type
= self
.data_ptr
.GetType().GetPointeeType()
345 self
.element_type_size
= self
.element_type
.GetByteSize()
347 def has_children(self
):
352 class StdVecDequeSyntheticProvider
:
353 """Pretty-printer for alloc::collections::vec_deque::VecDeque<T>
355 struct VecDeque<T> { tail: usize, head: usize, buf: RawVec<T> }
358 def __init__(self
, valobj
, dict):
359 # type: (SBValue, dict) -> StdVecDequeSyntheticProvider
360 # logger = Logger.Logger()
361 # logger >> "[StdVecDequeSyntheticProvider] for " + str(valobj.GetName())
365 def num_children(self
):
369 def get_child_index(self
, name
):
371 index
= name
.lstrip('[').rstrip(']')
372 if index
.isdigit() and self
.tail
<= index
and (self
.tail
+ index
) % self
.cap
< self
.head
:
377 def get_child_at_index(self
, index
):
378 # type: (int) -> SBValue
379 start
= self
.data_ptr
.GetValueAsUnsigned()
380 address
= start
+ ((index
+ self
.tail
) % self
.cap
) * self
.element_type_size
381 element
= self
.data_ptr
.CreateValueFromAddress("[%s]" % index
, address
, self
.element_type
)
386 self
.head
= self
.valobj
.GetChildMemberWithName("head").GetValueAsUnsigned()
387 self
.tail
= self
.valobj
.GetChildMemberWithName("tail").GetValueAsUnsigned()
388 self
.buf
= self
.valobj
.GetChildMemberWithName("buf")
389 self
.cap
= self
.buf
.GetChildMemberWithName("cap").GetValueAsUnsigned()
390 if self
.head
>= self
.tail
:
391 self
.size
= self
.head
- self
.tail
393 self
.size
= self
.cap
+ self
.head
- self
.tail
395 self
.data_ptr
= unwrap_unique_or_non_null(self
.buf
.GetChildMemberWithName("ptr"))
397 self
.element_type
= self
.data_ptr
.GetType().GetPointeeType()
398 self
.element_type_size
= self
.element_type
.GetByteSize()
400 def has_children(self
):
405 # BACKCOMPAT: rust 1.35
406 class StdOldHashMapSyntheticProvider
:
407 """Pretty-printer for std::collections::hash::map::HashMap<K, V, S>
409 struct HashMap<K, V, S> {..., table: RawTable<K, V>, ... }
410 struct RawTable<K, V> { capacity_mask: usize, size: usize, hashes: TaggedHashUintPtr, ... }
413 def __init__(self
, valobj
, dict, show_values
=True):
414 # type: (SBValue, dict, bool) -> StdOldHashMapSyntheticProvider
416 self
.show_values
= show_values
419 def num_children(self
):
423 def get_child_index(self
, name
):
425 index
= name
.lstrip('[').rstrip(']')
431 def get_child_at_index(self
, index
):
432 # type: (int) -> SBValue
433 # logger = Logger.Logger()
434 start
= self
.data_ptr
.GetValueAsUnsigned() & ~
1
436 # See `libstd/collections/hash/table.rs:raw_bucket_at
437 hashes
= self
.hash_uint_size
* self
.capacity
438 align
= self
.pair_type_size
439 # See `libcore/alloc.rs:padding_needed_for`
440 len_rounded_up
= (((((hashes
+ align
) % self
.modulo
- 1) % self
.modulo
) & ~
(
441 (align
- 1) % self
.modulo
)) % self
.modulo
- hashes
) % self
.modulo
442 # len_rounded_up = ((hashes + align - 1) & ~(align - 1)) - hashes
444 pairs_offset
= hashes
+ len_rounded_up
445 pairs_start
= start
+ pairs_offset
447 table_index
= self
.valid_indices
[index
]
448 idx
= table_index
& self
.capacity_mask
449 address
= pairs_start
+ idx
* self
.pair_type_size
450 element
= self
.data_ptr
.CreateValueFromAddress("[%s]" % index
, address
, self
.pair_type
)
454 key
= element
.GetChildAtIndex(0)
455 return self
.valobj
.CreateValueFromData("[%s]" % index
, key
.GetData(), key
.GetType())
459 # logger = Logger.Logger()
461 self
.table
= self
.valobj
.GetChildMemberWithName("table") # type: SBValue
462 self
.size
= self
.table
.GetChildMemberWithName("size").GetValueAsUnsigned()
463 self
.hashes
= self
.table
.GetChildMemberWithName("hashes")
464 self
.hash_uint_type
= self
.hashes
.GetType()
465 self
.hash_uint_size
= self
.hashes
.GetType().GetByteSize()
466 self
.modulo
= 2 ** self
.hash_uint_size
467 self
.data_ptr
= self
.hashes
.GetChildAtIndex(0).GetChildAtIndex(0)
469 self
.capacity_mask
= self
.table
.GetChildMemberWithName("capacity_mask").GetValueAsUnsigned()
470 self
.capacity
= (self
.capacity_mask
+ 1) % self
.modulo
472 marker
= self
.table
.GetChildMemberWithName("marker").GetType() # type: SBType
473 self
.pair_type
= marker
.template_args
[0]
474 self
.pair_type_size
= self
.pair_type
.GetByteSize()
476 self
.valid_indices
= []
477 for idx
in range(self
.capacity
):
478 address
= self
.data_ptr
.GetValueAsUnsigned() + idx
* self
.hash_uint_size
479 hash_uint
= self
.data_ptr
.CreateValueFromAddress("[%s]" % idx
, address
,
481 hash_ptr
= hash_uint
.GetChildAtIndex(0).GetChildAtIndex(0)
482 if hash_ptr
.GetValueAsUnsigned() != 0:
483 self
.valid_indices
.append(idx
)
485 # logger >> "Valid indices: {}".format(str(self.valid_indices))
487 def has_children(self
):
492 class StdHashMapSyntheticProvider
:
493 """Pretty-printer for hashbrown's HashMap"""
495 def __init__(self
, valobj
, dict, show_values
=True):
496 # type: (SBValue, dict, bool) -> StdHashMapSyntheticProvider
498 self
.show_values
= show_values
501 def num_children(self
):
505 def get_child_index(self
, name
):
507 index
= name
.lstrip('[').rstrip(']')
513 def get_child_at_index(self
, index
):
514 # type: (int) -> SBValue
515 pairs_start
= self
.data_ptr
.GetValueAsUnsigned()
516 idx
= self
.valid_indices
[index
]
519 address
= pairs_start
+ idx
* self
.pair_type_size
520 element
= self
.data_ptr
.CreateValueFromAddress("[%s]" % index
, address
, self
.pair_type
)
524 key
= element
.GetChildAtIndex(0)
525 return self
.valobj
.CreateValueFromData("[%s]" % index
, key
.GetData(), key
.GetType())
530 capacity
= table
.GetChildMemberWithName("bucket_mask").GetValueAsUnsigned() + 1
531 ctrl
= table
.GetChildMemberWithName("ctrl").GetChildAtIndex(0)
533 self
.size
= table
.GetChildMemberWithName("items").GetValueAsUnsigned()
534 self
.pair_type
= table
.type.template_args
[0]
535 self
.pair_type_size
= self
.pair_type
.GetByteSize()
537 self
.new_layout
= not table
.GetChildMemberWithName("data").IsValid()
539 self
.data_ptr
= ctrl
.Cast(self
.pair_type
.GetPointerType())
541 self
.data_ptr
= table
.GetChildMemberWithName("data").GetChildAtIndex(0)
543 u8_type
= self
.valobj
.GetTarget().GetBasicType(eBasicTypeUnsignedChar
)
544 u8_type_size
= self
.valobj
.GetTarget().GetBasicType(eBasicTypeUnsignedChar
).GetByteSize()
546 self
.valid_indices
= []
547 for idx
in range(capacity
):
548 address
= ctrl
.GetValueAsUnsigned() + idx
* u8_type_size
549 value
= ctrl
.CreateValueFromAddress("ctrl[%s]" % idx
, address
,
550 u8_type
).GetValueAsUnsigned()
551 is_present
= value
& 128 == 0
553 self
.valid_indices
.append(idx
)
556 # type: () -> SBValue
558 hashbrown_hashmap
= self
.valobj
.GetChildMemberWithName("base")
560 # BACKCOMPAT: rust 1.47
561 # HashSet wraps either std HashMap or hashbrown::HashSet, which both
562 # wrap hashbrown::HashMap, so either way we "unwrap" twice.
563 hashbrown_hashmap
= self
.valobj
.GetChildAtIndex(0).GetChildAtIndex(0)
564 return hashbrown_hashmap
.GetChildMemberWithName("table")
566 def has_children(self
):
571 def StdRcSummaryProvider(valobj
, dict):
572 # type: (SBValue, dict) -> str
573 strong
= valobj
.GetChildMemberWithName("strong").GetValueAsUnsigned()
574 weak
= valobj
.GetChildMemberWithName("weak").GetValueAsUnsigned()
575 return "strong={}, weak={}".format(strong
, weak
)
578 class StdRcSyntheticProvider
:
579 """Pretty-printer for alloc::rc::Rc<T> and alloc::sync::Arc<T>
581 struct Rc<T> { ptr: NonNull<RcBox<T>>, ... }
582 rust 1.31.1: struct NonNull<T> { pointer: NonZero<*const T> }
583 rust 1.33.0: struct NonNull<T> { pointer: *const T }
585 struct RcBox<T> { strong: Cell<usize>, weak: Cell<usize>, value: T }
586 struct Cell<T> { value: UnsafeCell<T> }
587 struct UnsafeCell<T> { value: T }
589 struct Arc<T> { ptr: NonNull<ArcInner<T>>, ... }
590 struct ArcInner<T> { strong: atomic::AtomicUsize, weak: atomic::AtomicUsize, data: T }
591 struct AtomicUsize { v: UnsafeCell<usize> }
594 def __init__(self
, valobj
, dict, is_atomic
=False):
595 # type: (SBValue, dict, bool) -> StdRcSyntheticProvider
598 self
.ptr
= unwrap_unique_or_non_null(self
.valobj
.GetChildMemberWithName("ptr"))
600 self
.value
= self
.ptr
.GetChildMemberWithName("data" if is_atomic
else "value")
602 self
.strong
= self
.ptr
.GetChildMemberWithName("strong").GetChildAtIndex(
603 0).GetChildMemberWithName("value")
604 self
.weak
= self
.ptr
.GetChildMemberWithName("weak").GetChildAtIndex(
605 0).GetChildMemberWithName("value")
607 self
.value_builder
= ValueBuilder(valobj
)
611 def num_children(self
):
613 # Actually there are 3 children, but only the `value` should be shown as a child
616 def get_child_index(self
, name
):
626 def get_child_at_index(self
, index
):
627 # type: (int) -> SBValue
631 return self
.value_builder
.from_uint("strong", self
.strong_count
)
633 return self
.value_builder
.from_uint("weak", self
.weak_count
)
639 self
.strong_count
= self
.strong
.GetValueAsUnsigned()
640 self
.weak_count
= self
.weak
.GetValueAsUnsigned() - 1
642 def has_children(self
):
647 class StdCellSyntheticProvider
:
648 """Pretty-printer for std::cell::Cell"""
650 def __init__(self
, valobj
, dict):
651 # type: (SBValue, dict) -> StdCellSyntheticProvider
653 self
.value
= valobj
.GetChildMemberWithName("value").GetChildAtIndex(0)
655 def num_children(self
):
659 def get_child_index(self
, name
):
665 def get_child_at_index(self
, index
):
666 # type: (int) -> SBValue
675 def has_children(self
):
680 def StdRefSummaryProvider(valobj
, dict):
681 # type: (SBValue, dict) -> str
682 borrow
= valobj
.GetChildMemberWithName("borrow").GetValueAsSigned()
683 return "borrow={}".format(borrow
) if borrow
>= 0 else "borrow_mut={}".format(-borrow
)
686 class StdRefSyntheticProvider
:
687 """Pretty-printer for std::cell::Ref, std::cell::RefMut, and std::cell::RefCell"""
689 def __init__(self
, valobj
, dict, is_cell
=False):
690 # type: (SBValue, dict, bool) -> StdRefSyntheticProvider
693 borrow
= valobj
.GetChildMemberWithName("borrow")
694 value
= valobj
.GetChildMemberWithName("value")
696 self
.borrow
= borrow
.GetChildMemberWithName("value").GetChildMemberWithName("value")
697 self
.value
= value
.GetChildMemberWithName("value")
699 self
.borrow
= borrow
.GetChildMemberWithName("borrow").GetChildMemberWithName(
700 "value").GetChildMemberWithName("value")
701 self
.value
= value
.Dereference()
703 self
.value_builder
= ValueBuilder(valobj
)
707 def num_children(self
):
709 # Actually there are 2 children, but only the `value` should be shown as a child
712 def get_child_index(self
, name
):
719 def get_child_at_index(self
, index
):
720 # type: (int) -> SBValue
724 return self
.value_builder
.from_int("borrow", self
.borrow_count
)
729 self
.borrow_count
= self
.borrow
.GetValueAsSigned()
731 def has_children(self
):