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