Ensure functions have docstrings for documentation
# def num_children(self)
1from __future__ import annotations23import sys4from enum import Flag, auto5from typing import TYPE_CHECKING, Dict, Generator, List, Optional67from lldb import (8 SBData,9 SBError,10 eBasicTypeChar32,11 eBasicTypeDouble,12 eBasicTypeFloat,13 eBasicTypeHalf,14 eBasicTypeLong,15 eBasicTypeLongLong,16 eBasicTypeShort,17 eBasicTypeSignedChar,18 eBasicTypeUnsignedChar,19 eBasicTypeUnsignedLong,20 eBasicTypeUnsignedLongLong,21 eBasicTypeUnsignedShort,22 eFormatChar,23 eTypeIsInteger,24)25from rust_types import is_tuple_fields2627if TYPE_CHECKING:28 from lldb import SBProcess, SBTarget, SBType, SBTypeStaticField, SBValue2930# from lldb.formatters import Logger3132####################################################################################################33# This file contains two kinds of pretty-printers: summary and synthetic.34#35# Important classes from LLDB module:36# SBValue: the value of a variable, a register, or an expression37# SBType: the data type; each SBValue has a corresponding SBType38#39# Summary provider is a function with the type `(SBValue, dict) -> str`.40# The first parameter is the object encapsulating the actual variable being displayed;41# The second parameter is an internal support parameter used by LLDB, and you should not touch it.42#43# Synthetic children is the way to provide a children-based representation of the object's value.44# Synthetic provider is a class that implements the following interface:45#46# class SyntheticChildrenProvider:47# def __init__(self, SBValue, dict)48# def num_children(self)49# def get_child_index(self, str)50# def get_child_at_index(self, int)51# def update(self)52# def has_children(self)53# def get_value(self)54#55#56# You can find more information and examples here:57# 1. https://lldb.llvm.org/varformats.html58# 2. https://lldb.llvm.org/use/python-reference.html59# 3. https://github.com/llvm/llvm-project/blob/llvmorg-8.0.1/lldb/www/python_reference/lldb.formatters.cpp-pysrc.html60# 4. https://github.com/llvm-mirror/lldb/tree/master/examples/summaries/cocoa61####################################################################################################6263PY3 = sys.version_info[0] == 3646566class LLDBFeature(Flag):67 """Used to track which features we rely on and whether or not we can access them. The global68 `lldb_providers.FEATURE_FLAGS` is initialized in `lldb_lookup.__lldb_init_module` and is69 expected not to change after that point.7071 This is used rather than `debugger.GetVersionString` because Apple's fork of LLDB (used for72 xcode) uses a non-standard versioning scheme that has no relation to LLVM's.73 """7475 StaticFields = auto()76 """Added in LLDB 18. Adds functions to `SBType` the inspection of a struct's static fields."""77 TypeRecognizers = auto()78 """Added in LLDB 19. Callback-based type matching for synthetic/summary providers."""79 Float128 = auto()80 """Added in LLDB 22.1. Adds builtin support for Float 128's, including an `eBasicTypeFloat128`,81 a formatter, and handlers in `TypeSystemClang`"""828384def detect_features() -> LLDBFeature:85 import lldb8687 features = LLDBFeature(0)8889 # Most feature checks should be possible via simple "does this API exist at all" checks.90 if getattr(lldb.SBType, "GetStaticFieldWithName", None) is not None:91 features |= LLDBFeature.StaticFields92 if getattr(lldb, "eFormatterMatchCallback", None) is not None:93 features |= LLDBFeature.TypeRecognizers94 if getattr(lldb, "eBasicTypeFloat128", None) is not None:95 features |= LLDBFeature.Float1289697 return features9899100FEATURE_FLAGS: LLDBFeature = detect_features()101102103class LLDBOpaque:104 """105 An marker type for use in type hints to denote LLDB bookkeeping variables. Values marked with106 this type should never be used except when passing as an argument to an LLDB function.107 """108109110class ValueBuilder:111 def __init__(self, valobj: SBValue):112 self.valobj = valobj113 process = valobj.GetProcess()114 self.endianness = process.GetByteOrder()115 self.pointer_size = process.GetAddressByteSize()116117 def from_int(self, name: str, value: int) -> SBValue:118 type = self.valobj.GetType().GetBasicType(eBasicTypeLong)119 data = SBData.CreateDataFromSInt64Array(120 self.endianness,121 self.pointer_size,122 [value],123 )124 return self.valobj.CreateValueFromData(name, data, type)125126 def from_uint(self, name: str, value: int) -> SBValue:127 type = self.valobj.GetType().GetBasicType(eBasicTypeUnsignedLong)128 data = SBData.CreateDataFromUInt64Array(129 self.endianness,130 self.pointer_size,131 [value],132 )133 return self.valobj.CreateValueFromData(name, data, type)134135136def unwrap_unique_or_non_null(unique_or_nonnull: SBValue) -> SBValue:137 # BACKCOMPAT: rust 1.32138 # https://github.com/rust-lang/rust/commit/7a0911528058e87d22ea305695f4047572c5e067139 # BACKCOMPAT: rust 1.60140 # https://github.com/rust-lang/rust/commit/2a91eeac1a2d27dd3de1bf55515d765da20fd86f141 ptr = unique_or_nonnull.GetChildMemberWithName("pointer")142 return ptr if ptr.TypeIsPointerType() else ptr.GetChildAtIndex(0)143144145def unwrap_scalar_wrappers(wrapper: SBValue) -> SBValue:146 while (wrapper.type.GetTypeFlags() & eTypeIsInteger) == 0:147 wrapper = wrapper.GetChildAtIndex(0)148 return wrapper149150151class DefaultSyntheticProvider:152 def __init__(self, valobj: SBValue, _dict: LLDBOpaque):153 # logger = Logger.Logger()154 # logger >> "Default synthetic provider for " + str(valobj.GetName())155 self.valobj = valobj156 self.is_ptr = valobj.GetType().IsPointerType()157158 def num_children(self) -> int:159 return self.valobj.GetNumChildren()160161 def get_child_index(self, name: str) -> int:162 return self.valobj.GetIndexOfChildWithName(name)163164 def get_child_at_index(self, index: int) -> Optional[SBValue]:165 return self.valobj.GetChildAtIndex(index)166167 def update(self):168 pass169170 def has_children(self) -> bool:171 return self.valobj.MightHaveChildren()172173 def get_value(self):174 return self.valobj.value175176177class EmptySyntheticProvider:178 def __init__(self, valobj: SBValue, _dict: LLDBOpaque):179 # logger = Logger.Logger()180 # logger >> "[EmptySyntheticProvider] for " + str(valobj.GetName())181 self.valobj = valobj182183 def num_children(self) -> int:184 return 0185186 def get_child_index(self, name: str) -> int:187 return -1188189 def get_child_at_index(self, index: int) -> Optional[SBValue]:190 return None191192 def update(self):193 pass194195 def has_children(self) -> bool:196 return False197198199MSVC_STR_NAMES: List[str] = [200 "ref$<str$>",201 "ref_mut$<str$>",202 "ptr_const$<str$>",203 "ptr_mut$<str$>",204]205206207def get_template_args(type_name: str) -> Generator[str, None, None]:208 """209 Takes a type name `T<A, tuple$<B, C>, D>` and returns a list of its generic args210 `["A", "tuple$<B, C>", "D"]`.211212 Always returns an empty generator for `&str`, `&mut str`, `*const str`, and `*mut str`213214 Strips off `enum2$<>` wrapper from enum types before checking for template args215216 String-based replacement for LLDB's `SBType.template_args`, as LLDB is currently unable to217 populate this field for targets with PDB debug info. Also useful for manually altering the type218 name of generics (e.g. `Vec<ref$<str$> >` -> `Vec<&str>`).219220 Each element of the returned list can be looked up for its `SBType` value via221 `SBTarget.FindFirstType()`222 """223 if type_name in MSVC_STR_NAMES:224 return225226 if type_name.startswith(("enum2$<", "slice2$<")):227 # remove the prefix and the trailing ">"228 type_name = type_name.split("<", 1)[0][:-1].strip()229230 level = 0231 start = 0232 for i, c in enumerate(type_name):233 if c == "<":234 level += 1235 if level == 1:236 start = i + 1237 elif c == ">":238 level -= 1239 if level == 0:240 yield type_name[start:i].strip()241 elif c == "," and level == 1:242 yield type_name[start:i].strip()243 start = i + 1244245246MSVC_PTR_PREFIX = ("ref$<", "ref_mut$<", "ptr_const$<", "ptr_mut$<")247248PRIMITIVE_TYPES: Dict[str, int] = {249 "u8": eBasicTypeUnsignedChar,250 "u16": eBasicTypeUnsignedShort,251 "u32": eBasicTypeUnsignedLong,252 "u64": eBasicTypeUnsignedLongLong,253 "i8": eBasicTypeSignedChar,254 "i16": eBasicTypeShort,255 "i32": eBasicTypeLong,256 "i64": eBasicTypeLongLong,257 "f16": eBasicTypeHalf,258 "f32": eBasicTypeFloat,259 "f64": eBasicTypeDouble,260 "char": eBasicTypeChar32,261}262263264def resolve_msvc_template_arg(arg_name: str, target: SBTarget) -> SBType:265 """266 RECURSIVE when arrays or references are nested (e.g. `ref$<ref$<u8> >`, `array$<ref$<u8> >`)267268 Takes the template arg's name (likely from `get_template_args`) and finds/creates its269 corresponding SBType.270271 For non-reference/pointer/array types this is identical to calling272 `target.FindFirstType(arg_name)`273274 LLDB internally interprets refs, pointers, and arrays C-style (`&u8` -> `u8 *`,275 `*const u8` -> `u8 *`, `[u8; 5]` -> `u8 [5]`). Looking up these names still doesn't work in the276 current version of LLDB, so instead the types are generated via `base_type.GetPointerType()` and277 `base_type.GetArrayType()`, which bypass the PDB file and ask clang directly for the type node.278 """279280 result = target.FindFirstType(arg_name)281282 if result.IsValid():283 return result284285 if arg_name in MSVC_STR_NAMES:286 return target.FindFirstType(arg_name)287288 # As of LLDB 22, finding primitives based on `FindFirstType` with their rust name no longer289 # works. Instead, we can look them up by their `eBasicType` equivalent. For usize and isize,290 # we convert them to their bit-sized counterpart before the lookup291 if arg_name == "isize" or arg_name == "usize":292 equivalent = f"{arg_name[0]}{target.GetAddressByteSize() * 8}"293 return target.GetBasicType(PRIMITIVE_TYPES[equivalent])294295 if (basic_type := PRIMITIVE_TYPES.get(arg_name)) is not None:296 return target.GetBasicType(basic_type)297298 if arg_name == "f128" and LLDBFeature.Float128 in FEATURE_FLAGS:299 from lldb import eBasicTypeFloat128300301 return target.GetBasicType(eBasicTypeFloat128)302303 for prefix in MSVC_PTR_PREFIX:304 if arg_name.startswith(prefix):305 arg_name = arg_name[len(prefix) : -1].strip()306307 result = resolve_msvc_template_arg(arg_name, target)308 return result.GetPointerType()309310 if arg_name.startswith("slice2$<"):311 arg_name = arg_name[len("slice2$<") : -1].strip()312 return resolve_msvc_template_arg(arg_name, target)313314 if arg_name.startswith("array$<"):315 template_args = get_template_args(arg_name)316317 element_name = next(template_args)318 length = next(template_args)319320 result = resolve_msvc_template_arg(element_name, target)321322 return result.GetArrayType(int(length))323324 return result325326327def StructSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str:328 # structs need the field name before the field value329 output = (330 f"{valobj.GetChildAtIndex(i).GetName()}:{child}"331 for i, child in enumerate(aggregate_field_summary(valobj, _dict))332 )333334 return "{" + ", ".join(output) + "}"335336337def TupleSummaryProvider(valobj: SBValue, _dict: LLDBOpaque):338 return "(" + ", ".join(aggregate_field_summary(valobj, _dict)) + ")"339340341def aggregate_field_summary(valobj: SBValue, _dict) -> Generator[str, None, None]:342 for i in range(0, valobj.GetNumChildren()):343 child: SBValue = valobj.GetChildAtIndex(i)344 summary = child.summary345 if summary is None:346 summary = child.value347 if summary is None:348 if is_tuple_fields(child.GetType().fields):349 summary = TupleSummaryProvider(child, _dict)350 else:351 summary = StructSummaryProvider(child, _dict)352 yield summary353354355def SizeSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str:356 return "size=" + str(valobj.GetNumChildren())357358359def vec_to_string(vec: SBValue) -> str:360 length = vec.GetNumChildren()361 chars = [vec.GetChildAtIndex(i).GetValueAsUnsigned() for i in range(length)]362 return (363 bytes(chars).decode(errors="replace")364 if PY3365 else "".join(chr(char) for char in chars)366 )367368369def read_string(370 process: SBProcess, address: int, length: int, error: Optional[SBError] = None371) -> str:372 """Reads a string from running process's memory. If `error` is passed in, it will be passed373 to the `SBProcess.ReadMemory` call, and will reflect any errors after the function is called.374375 If any error or exception occurs, a placeholder byte array of the form "<error: [reason]>" will376 be returned instead."""377378 if error is None:379 error = SBError()380 try:381 data = process.ReadMemory(address, length, error)382 if error.Success():383 return '"' + data.decode("utf-8", "replace") + '"'384 else:385 return f"<error: {error.GetCString()}>"386 except Exception as e:387 print(f"Unable to generate String summary: {e.__cause__}")388 return "<error: Unable to read memory>"389390391def StdStringSummaryProvider(valobj: SBValue, dict: LLDBOpaque):392 inner_vec = (393 valobj.GetNonSyntheticValue()394 .GetChildMemberWithName("vec")395 .GetNonSyntheticValue()396 )397398 pointer = (399 inner_vec.GetChildMemberWithName("buf")400 .GetChildMemberWithName("inner")401 .GetChildMemberWithName("ptr")402 .GetChildMemberWithName("pointer")403 .GetChildMemberWithName("pointer")404 )405406 length = inner_vec.GetChildMemberWithName("len").GetValueAsUnsigned()407 capacity = (408 inner_vec.GetChildMemberWithName("buf")409 .GetChildMemberWithName("cap")410 .GetValueAsUnsigned()411 )412413 if length <= 0:414 return '""'415416 no_hi_bit_max: int = 1 << ((pointer.GetByteSize() * 8) - 1)417 # technically length isn't a NoHighBit<usize>, but length should always be <= capacity418 if length >= no_hi_bit_max or capacity >= no_hi_bit_max:419 return "<error: invalid len/capacity>"420 if pointer.GetValueAsUnsigned() == 0:421 return "<error: String pointer is null>"422423 process = pointer.GetProcess()424425 return read_string(process, pointer.GetValueAsAddress(), length)426427428def StdOsStringSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str:429 inner_vec = valobj.GetNonSyntheticValue().GetChildAtIndex(0).GetChildAtIndex(0)430431 is_windows = inner_vec.GetTypeName().endswith("Wtf8Buf")432433 if is_windows:434 inner_vec = inner_vec.GetChildAtIndex(0)435436 pointer = (437 inner_vec.GetChildMemberWithName("buf")438 .GetChildMemberWithName("inner")439 .GetChildMemberWithName("ptr")440 .GetChildMemberWithName("pointer")441 .GetChildMemberWithName("pointer")442 )443444 length = inner_vec.GetChildMemberWithName("len").GetValueAsUnsigned()445 capacity = (446 inner_vec.GetChildMemberWithName("buf")447 .GetChildMemberWithName("cap")448 .GetValueAsUnsigned()449 )450451 if length <= 0:452 return '""'453454 no_hi_bit_max: int = 1 << ((pointer.GetByteSize() * 8) - 1)455 # technically length isn't a NoHighBit<usize>, but length should always be <= capacity456 if length >= no_hi_bit_max or capacity >= no_hi_bit_max:457 return "<error: invalid len/capacity>"458 if pointer.GetValueAsUnsigned() == 0:459 return "<error: OsString pointer is null>"460461 process = pointer.GetProcess()462463 return read_string(process, pointer.GetValueAsAddress(), length)464465466def StdStrSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str:467 # logger = Logger.Logger()468 # logger >> "[StdStrSummaryProvider] for " + str(valobj.GetName())469470 # the code below assumes non-synthetic value, this makes sure the assumption holds471 valobj = valobj.GetNonSyntheticValue()472473 length = valobj.GetChildMemberWithName("length").GetValueAsUnsigned()474 if length == 0:475 return '""'476477 data_ptr = valobj.GetChildMemberWithName("data_ptr")478479 start = data_ptr.GetValueAsUnsigned()480 error = SBError()481 process = data_ptr.GetProcess()482 data = process.ReadMemory(start, length, error)483 data = data.decode(encoding="UTF-8") if PY3 else data484 return '"%s"' % data485486487def StdPathBufSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str:488 # logger = Logger.Logger()489 # logger >> "[StdPathBufSummaryProvider] for " + str(valobj.GetName())490 return StdOsStringSummaryProvider(valobj.GetChildMemberWithName("inner"), _dict)491492493def StdPathSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str:494 # logger = Logger.Logger()495 # logger >> "[StdPathSummaryProvider] for " + str(valobj.GetName())496 length = valobj.GetChildMemberWithName("length").GetValueAsUnsigned()497 if length == 0:498 return '""'499500 data_ptr = valobj.GetChildMemberWithName("data_ptr")501502 start = data_ptr.GetValueAsUnsigned()503 process = data_ptr.GetProcess()504505 return read_string(process, start, length)506507508def sequence_formatter(output: str, valobj: SBValue, _dict: LLDBOpaque):509 length: int = valobj.GetNumChildren()510511 long: bool = False512 for i in range(0, length):513 if len(output) > 32:514 long = True515 break516517 child: SBValue = valobj.GetChildAtIndex(i)518519 summary = child.summary520 if summary is None:521 summary = child.value522 if summary is None:523 summary = "{...}"524 output += f"{summary}, "525 if long:526 output = f"(len: {length}) " + output + "..."527 else:528 output = output[:-2]529530 return output531532533class StructSyntheticProvider:534 """Pretty-printer for structs and struct enum variants"""535536 def __init__(self, valobj: SBValue, _dict: LLDBOpaque, is_variant: bool = False):537 # logger = Logger.Logger()538 self.valobj = valobj539 self.is_variant = is_variant540 self.type = valobj.GetType()541 self.fields = {}542543 if is_variant:544 self.fields_count = self.type.GetNumberOfFields() - 1545 real_fields = self.type.fields[1:]546 else:547 self.fields_count = self.type.GetNumberOfFields()548 real_fields = self.type.fields549550 for number, field in enumerate(real_fields):551 self.fields[field.name] = number552553 def num_children(self) -> int:554 return self.fields_count555556 def get_child_index(self, name: str) -> int:557 return self.fields.get(name, -1)558559 def get_child_at_index(self, index: int) -> Optional[SBValue]:560 if self.is_variant:561 field = self.type.GetFieldAtIndex(index + 1)562 else:563 field = self.type.GetFieldAtIndex(index)564 return self.valobj.GetChildMemberWithName(field.name)565566 def update(self):567 # type: () -> None568 pass569570 def has_children(self) -> bool:571 return True572573574class StdStringSyntheticProvider:575 def __init__(self, valobj: SBValue, _dict: LLDBOpaque):576 self.valobj = valobj577 ptr_size = valobj.GetTarget().GetAddressByteSize() * 8578 self.no_hi_bit_max = 1 << (ptr_size - 1)579580 self.update()581582 def update(self):583 inner_vec = self.valobj.GetChildMemberWithName("vec").GetNonSyntheticValue()584 self.data_ptr = (585 inner_vec.GetChildMemberWithName("buf")586 .GetChildMemberWithName("inner")587 .GetChildMemberWithName("ptr")588 .GetChildMemberWithName("pointer")589 .GetChildMemberWithName("pointer")590 )591592 self.capacity = (593 inner_vec.GetChildMemberWithName("buf")594 .GetChildMemberWithName("cap")595 .GetValueAsUnsigned()596 )597598 # As of 4/18/2026, LLDB cannot accurately determine the difference between Some("") and None599 # this just makes sure we're not trying to access data when the string is clearly in an600 # invalid state.601 if (602 self.capacity >= self.no_hi_bit_max603 or self.data_ptr.GetValueAsUnsigned() == 0604 ):605 self.capacity = 0606 self.length = 0607 else:608 self.length = inner_vec.GetChildMemberWithName("len").GetValueAsUnsigned()609610 self.element_type = self.data_ptr.GetType().GetPointeeType()611612 def has_children(self) -> bool:613 return True614615 def num_children(self) -> int:616 return self.length617618 def get_child_index(self, name: str) -> int:619 index = name.lstrip("[").rstrip("]")620 if index.isdigit():621 return int(index)622623 return -1624625 def get_child_at_index(self, index: int) -> Optional[SBValue]:626 if not 0 <= index < self.length:627 return None628 start = self.data_ptr.GetValueAsUnsigned()629 address = start + index630 element = self.data_ptr.CreateValueFromAddress(631 f"[{index}]", address, self.element_type632 )633 element.SetFormat(eFormatChar)634 return element635636637class MSVCStrSyntheticProvider:638 _name_map: Dict[str, str] = {639 "ref$<str$>": "&str",640 "ref_mut$<str$>": "&mut str",641 "ptr_const$<str$>": "*const str",642 "ptr_mut$<str$>": "*mut str",643 }644 __slots__ = ["data_ptr", "length", "valobj"]645646 def __init__(self, valobj: SBValue, _dict: LLDBOpaque):647 self.valobj = valobj648 self.update()649650 def update(self):651 self.data_ptr = self.valobj.GetChildMemberWithName("data_ptr")652 self.length = self.valobj.GetChildMemberWithName("length").GetValueAsUnsigned()653654 def has_children(self) -> bool:655 return True656657 def num_children(self) -> int:658 return self.length659660 def get_child_index(self, name: str) -> int:661 index = name.lstrip("[").rstrip("]")662 if index.isdigit():663 return int(index)664665 return -1666667 def get_child_at_index(self, index: int) -> Optional[SBValue]:668 if not 0 <= index < self.length:669 return None670 start = self.data_ptr.GetValueAsUnsigned()671 address = start + index672 element = self.data_ptr.CreateValueFromAddress(673 f"[{index}]", address, self.data_ptr.GetType().GetPointeeType()674 )675 return element676677 def get_type_name(self):678 name = self.valobj.GetTypeName()679680 if (type_name := self._name_map.get(name)) is not None:681 return type_name682 elif name.startswith("alloc::boxed::Box<str$"):683 return "Box<str>"684 else:685 return name686687688def _getVariantName(variant: SBValue) -> str:689 """690 Since the enum variant's type name is in the form `TheEnumName::TheVariantName$Variant`,691 we can extract `TheVariantName` from it for display purpose.692 """693 s = variant.GetType().GetName()694 if not s.endswith("$Variant"):695 return ""696697 # trim off path and "$Variant"698 # len("$Variant") == 8699 return s.rsplit("::", 1)[1][:-8]700701702class ClangEncodedEnumProvider:703 """Pretty-printer for 'clang-encoded' enums support implemented in LLDB"""704705 valobj: SBValue706 variant: SBValue707 value: SBValue708709 DISCRIMINANT_MEMBER_NAME = "$discr$"710 VALUE_MEMBER_NAME = "value"711712 __slots__ = ("valobj", "variant", "value")713714 def __init__(self, valobj: SBValue, _dict: LLDBOpaque):715 self.valobj = valobj716 self.update()717718 def has_children(self) -> bool:719 return self.value.MightHaveChildren()720721 def num_children(self) -> int:722 return self.value.GetNumChildren()723724 def get_child_index(self, name: str) -> int:725 return self.value.GetIndexOfChildWithName(name)726727 def get_child_at_index(self, index: int) -> Optional[SBValue]:728 return self.value.GetChildAtIndex(index)729730 def update(self):731 all_variants = self.valobj.GetChildAtIndex(0)732 index = self._getCurrentVariantIndex(all_variants)733 self.variant = all_variants.GetChildAtIndex(index)734 self.value = self.variant.GetChildMemberWithName(735 ClangEncodedEnumProvider.VALUE_MEMBER_NAME736 )737 if (synth := self.value.GetSyntheticValue()).IsValid():738 self.value = synth739740 def _getCurrentVariantIndex(self, all_variants: SBValue) -> int:741 default_index = 0742 for i in range(all_variants.GetNumChildren()):743 variant = all_variants.GetChildAtIndex(i)744 discr = variant.GetChildMemberWithName(745 ClangEncodedEnumProvider.DISCRIMINANT_MEMBER_NAME746 )747 if discr.IsValid():748 discr_unsigned_value = discr.GetValueAsUnsigned()749 if variant.GetName() == f"$variant${discr_unsigned_value}":750 return i751 else:752 default_index = i753 return default_index754755756def ClangEncodedEnumSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str:757 if valobj.TypeIsPointerType():758 valobj = valobj.Dereference()759 enum_synth = ClangEncodedEnumProvider(valobj.GetNonSyntheticValue(), _dict)760 variant = enum_synth.variant761 name = _getVariantName(variant)762763 if valobj.GetNumChildren() == 0:764 return name765766 child_name: str = valobj.GetChildAtIndex(0).name767 if child_name == "0" or child_name == "__0":768 # enum variant is a tuple struct769 return name + TupleSummaryProvider(valobj, _dict)770 else:771 # enum variant is a regular struct772 return name + StructSummaryProvider(valobj, _dict)773774775class MSVCEnumSyntheticProvider:776 """777 Synthetic provider for sum-type enums on MSVC. For a detailed explanation of the internals,778 see:779780 https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs781 """782783 valobj: SBValue784 variant: SBValue785 value: SBValue786787 __slots__ = ["valobj", "variant", "value"]788789 def __init__(self, valobj: SBValue, _dict: LLDBOpaque):790 self.valobj = valobj791 # This allows the summary provider to still print something792 # even if we can't find the variant for whatever reason793 self.variant = valobj794 self.value = valobj795 self.update()796797 def update(self):798 tag: SBValue = self.valobj.GetChildMemberWithName("tag")799800 if tag.IsValid():801 tag: int = tag.GetValueAsUnsigned()802 for child in self.valobj.GetNonSyntheticValue().children:803 if not child.name.startswith("variant"):804 continue805806 variant_type: SBType = child.GetType()807 try:808 exact: SBTypeStaticField = variant_type.GetStaticFieldWithName(809 "DISCR_EXACT"810 )811 except AttributeError:812 # LLDB versions prior to 19.0.0 do not have the `SBTypeGetStaticField` API.813 # With current DI generation there's not a great way to provide a "best effort"814 # evaluation either, so we just return the object itself with no further815 # attempts to inspect the type information816 self.variant = self.valobj817 self.value = self.valobj818 return819820 if exact.IsValid():821 discr: int = exact.GetConstantValue(822 self.valobj.target823 ).GetValueAsUnsigned()824 if tag == discr:825 self.variant = child826 self.value = child.GetChildMemberWithName("value")827 if (synth := self.value.GetSyntheticValue()).IsValid():828 self.value = synth829830 return831 else: # if invalid, DISCR must be a range832 begin: int = (833 variant_type.GetStaticFieldWithName("DISCR_BEGIN")834 .GetConstantValue(self.valobj.target)835 .GetValueAsUnsigned()836 )837 end: int = (838 variant_type.GetStaticFieldWithName("DISCR_END")839 .GetConstantValue(self.valobj.target)840 .GetValueAsUnsigned()841 )842843 # begin isn't necessarily smaller than end, so we must test for both cases844 if begin < end:845 if begin <= tag <= end:846 self.variant = child847 self.value = child.GetChildMemberWithName("value")848 if (synth := self.value.GetSyntheticValue()).IsValid():849 self.value = synth850851 return852 else:853 if tag >= begin or tag <= end:854 self.variant = child855 self.value = child.GetChildMemberWithName("value")856 if (synth := self.value.GetSyntheticValue()).IsValid():857 self.value = synth858859 return860 else: # if invalid, tag is a 128 bit value861 tag_lo: int = self.valobj.GetChildMemberWithName(862 "tag128_lo"863 ).GetValueAsUnsigned()864 tag_hi: int = self.valobj.GetChildMemberWithName(865 "tag128_hi"866 ).GetValueAsUnsigned()867868 tag: int = (tag_hi << 64) | tag_lo869870 for child in self.valobj.GetNonSyntheticValue().children:871 if not child.name.startswith("variant"):872 continue873874 variant_type: SBType = child.GetType()875 exact_lo: SBTypeStaticField = variant_type.GetStaticFieldWithName(876 "DISCR128_EXACT_LO"877 )878879 if exact_lo.IsValid():880 exact_lo: int = exact_lo.GetConstantValue(881 self.valobj.target882 ).GetValueAsUnsigned()883 exact_hi: int = (884 variant_type.GetStaticFieldWithName("DISCR128_EXACT_HI")885 .GetConstantValue(self.valobj.target)886 .GetValueAsUnsigned()887 )888889 discr: int = (exact_hi << 64) | exact_lo890 if tag == discr:891 self.variant = child892 self.value = child.GetChildMemberWithName("value")893 if (synth := self.value.GetSyntheticValue()).IsValid():894 self.value = synth895 return896 else: # if invalid, DISCR must be a range897 begin_lo: int = (898 variant_type.GetStaticFieldWithName("DISCR128_BEGIN_LO")899 .GetConstantValue(self.valobj.target)900 .GetValueAsUnsigned()901 )902 begin_hi: int = (903 variant_type.GetStaticFieldWithName("DISCR128_BEGIN_HI")904 .GetConstantValue(self.valobj.target)905 .GetValueAsUnsigned()906 )907908 end_lo: int = (909 variant_type.GetStaticFieldWithName("DISCR128_END_LO")910 .GetConstantValue(self.valobj.target)911 .GetValueAsUnsigned()912 )913 end_hi: int = (914 variant_type.GetStaticFieldWithName("DISCR128_END_HI")915 .GetConstantValue(self.valobj.target)916 .GetValueAsUnsigned()917 )918919 begin = (begin_hi << 64) | begin_lo920 end = (end_hi << 64) | end_lo921922 # begin isn't necessarily smaller than end, so we must test for both cases923 if begin < end:924 if begin <= tag <= end:925 self.variant = child926 self.value = child.GetChildMemberWithName("value")927 if (synth := self.value.GetSyntheticValue()).IsValid():928 self.value = synth929 return930 else:931 if tag >= begin or tag <= end:932 self.variant = child933 self.value = child.GetChildMemberWithName("value")934 if (synth := self.value.GetSyntheticValue()).IsValid():935 self.value = synth936 return937938 def num_children(self) -> int:939 return self.value.GetNumChildren()940941 def get_child_index(self, name: str) -> int:942 return self.value.GetIndexOfChildWithName(name)943944 def get_child_at_index(self, index: int) -> Optional[SBValue]:945 return self.value.GetChildAtIndex(index)946947 def has_children(self) -> bool:948 return self.value.MightHaveChildren()949950 def get_type_name(self) -> str:951 name = self.valobj.GetTypeName()952 # remove "enum2$<", str.removeprefix() is python 3.9+953 name = name[7:]954955 # MSVC misinterprets ">>" as a shift operator, so spaces are inserted by rust to956 # avoid that957 if name.endswith(" >"):958 name = name[:-2]959 elif name.endswith(">"):960 name = name[:-1]961962 return name963964965def MSVCEnumSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str:966 if valobj.TypeIsPointerType():967 valobj = valobj.Dereference()968 enum_synth = MSVCEnumSyntheticProvider(valobj.GetNonSyntheticValue(), _dict)969 variant_names: SBType = valobj.target.FindFirstType(970 f"{enum_synth.valobj.GetTypeName()}::VariantNames"971 )972 try:973 name_idx = (974 enum_synth.variant.GetType()975 .GetStaticFieldWithName("NAME")976 .GetConstantValue(valobj.target)977 .GetValueAsUnsigned()978 )979 except AttributeError:980 # LLDB versions prior to 19 do not have the `SBTypeGetStaticField` API, and have no way981 # to determine the value based on the tag field.982 tag: SBValue = valobj.GetChildMemberWithName("tag")983984 if tag.IsValid():985 discr: int = tag.GetValueAsUnsigned()986 return "".join(["{tag = ", str(tag.unsigned), "}"])987 else:988 tag_lo: int = valobj.GetChildMemberWithName(989 "tag128_lo"990 ).GetValueAsUnsigned()991 tag_hi: int = valobj.GetChildMemberWithName(992 "tag128_hi"993 ).GetValueAsUnsigned()994995 discr: int = (tag_hi << 64) | tag_lo996997 return "".join(["{tag = ", str(discr), "}"])998999 name: str = variant_names.enum_members[name_idx].name10001001 if enum_synth.num_children() == 0:1002 return name10031004 child_name: str = enum_synth.value.GetChildAtIndex(0).name1005 if child_name == "0" or child_name == "__0":1006 # enum variant is a tuple struct1007 return name + TupleSummaryProvider(enum_synth.value, _dict)1008 else:1009 # enum variant is a regular struct1010 return name + StructSummaryProvider(enum_synth.value, _dict)101110121013class TupleSyntheticProvider:1014 """Pretty-printer for tuples and tuple enum variants"""10151016 def __init__(self, valobj: SBValue, _dict: LLDBOpaque, is_variant: bool = False):1017 # logger = Logger.Logger()1018 self.valobj = valobj1019 self.is_variant = is_variant1020 self.type = valobj.GetType()10211022 if is_variant:1023 self.size = self.type.GetNumberOfFields() - 11024 else:1025 self.size = self.type.GetNumberOfFields()10261027 def num_children(self) -> int:1028 return self.size10291030 def get_child_index(self, name: str) -> int:1031 if name.isdigit():1032 return int(name)1033 else:1034 return -110351036 def get_child_at_index(self, index: int) -> Optional[SBValue]:1037 if self.is_variant:1038 field = self.type.GetFieldAtIndex(index + 1)1039 else:1040 field = self.type.GetFieldAtIndex(index)1041 element = self.valobj.GetChildMemberWithName(field.name)1042 return self.valobj.CreateValueFromData(1043 str(index), element.GetData(), element.GetType()1044 )10451046 def update(self):1047 pass10481049 def has_children(self) -> bool:1050 return True105110521053class MSVCTupleSyntheticProvider:1054 __slots__ = ["valobj"]10551056 def __init__(self, valobj: SBValue, _dict: LLDBOpaque):1057 self.valobj = valobj10581059 def num_children(self) -> int:1060 return self.valobj.GetNumChildren()10611062 def get_child_index(self, name: str) -> int:1063 return self.valobj.GetIndexOfChildWithName(name)10641065 def get_child_at_index(self, index: int) -> Optional[SBValue]:1066 child: SBValue = self.valobj.GetChildAtIndex(index)1067 offset = self.valobj.GetType().GetFieldAtIndex(index).byte_offset1068 return self.valobj.CreateChildAtOffset(str(index), offset, child.GetType())10691070 def update(self):1071 pass10721073 def has_children(self) -> bool:1074 return self.valobj.MightHaveChildren()10751076 def get_type_name(self) -> str:1077 name = self.valobj.GetTypeName()1078 # remove "tuple$<" and ">", str.removeprefix and str.removesuffix require python 3.9+1079 name = name[7:-1].strip()1080 return "(" + name + ")"108110821083class StdVecSyntheticProvider:1084 """Pretty-printer for alloc::vec::Vec<T>10851086 struct Vec<T> { buf: RawVec<T>, len: usize }1087 rust 1.75: struct RawVec<T> { ptr: Unique<T>, cap: usize, ... }1088 rust 1.76: struct RawVec<T> { ptr: Unique<T>, cap: Cap(usize), ... }1089 rust 1.31.1: struct Unique<T: ?Sized> { pointer: NonZero<*const T>, ... }1090 rust 1.33.0: struct Unique<T: ?Sized> { pointer: *const T, ... }1091 rust 1.62.0: struct Unique<T: ?Sized> { pointer: NonNull<T>, ... }1092 struct NonZero<T>(T)1093 struct NonNull<T> { pointer: *const T }1094 """10951096 def __init__(self, valobj: SBValue, _dict: LLDBOpaque):1097 # logger = Logger.Logger()1098 # logger >> "[StdVecSyntheticProvider] for " + str(valobj.GetName())1099 self.valobj = valobj1100 self.element_type = None1101 ptr_size = valobj.GetTarget().GetAddressByteSize() * 81102 self.no_hi_bit_max = 1 << (ptr_size - 1)1103 self.update()11041105 def num_children(self) -> int:1106 return self.length11071108 def get_child_index(self, name: str) -> int:1109 index = name.lstrip("[").rstrip("]")1110 if index.isdigit():1111 return int(index)1112 else:1113 return -111141115 def get_child_at_index(self, index: int) -> Optional[SBValue]:1116 start = self.data_ptr.GetValueAsUnsigned()1117 address = start + index * self.element_type_size1118 element = self.data_ptr.CreateValueFromAddress(1119 "[%s]" % index, address, self.element_type1120 )1121 return element11221123 def update(self):1124 buf: SBValue = self.valobj.GetChildMemberWithName("buf")1125 self.data_ptr = unwrap_unique_or_non_null(1126 buf.GetChildMemberWithName("inner").GetChildMemberWithName("ptr")1127 )11281129 capacity: int = buf.GetChildMemberWithName("cap").GetValueAsUnsigned()11301131 if capacity >= self.no_hi_bit_max or self.data_ptr.GetValueAsUnsigned() == 0:1132 self.capacity = 01133 self.length = 01134 else:1135 self.length = self.valobj.GetChildMemberWithName("len").GetValueAsUnsigned()11361137 self.element_type = self.valobj.GetType().GetTemplateArgumentType(0)11381139 if not self.element_type.IsValid():1140 arg_name = next(get_template_args(self.valobj.GetTypeName()))11411142 self.element_type = resolve_msvc_template_arg(arg_name, self.valobj.target)11431144 self.element_type_size = self.element_type.GetByteSize()11451146 def has_children(self) -> bool:1147 return True114811491150class StdSliceSyntheticProvider:1151 __slots__ = ["valobj", "length", "data_ptr", "element_type", "element_size"]11521153 def __init__(self, valobj: SBValue, _dict: LLDBOpaque):1154 self.valobj = valobj1155 self.update()11561157 def num_children(self) -> int:1158 return self.length11591160 def get_child_index(self, name: str) -> int:1161 index = name.lstrip("[").rstrip("]")1162 if index.isdigit():1163 return int(index)1164 else:1165 return -111661167 def get_child_at_index(self, index: int) -> Optional[SBValue]:1168 start = self.data_ptr.GetValueAsUnsigned()1169 address = start + index * self.element_size1170 element = self.data_ptr.CreateValueFromAddress(1171 "[%s]" % index, address, self.element_type1172 )1173 return element11741175 def update(self):1176 self.length = self.valobj.GetChildMemberWithName("length").GetValueAsUnsigned()1177 self.data_ptr = self.valobj.GetChildMemberWithName("data_ptr")11781179 self.element_type = self.data_ptr.GetType().GetPointeeType()1180 self.element_size = self.element_type.GetByteSize()11811182 def has_children(self) -> bool:1183 return True118411851186class MSVCStdSliceSyntheticProvider(StdSliceSyntheticProvider):1187 type_name: Optional[str] = None11881189 def get_type_name(self) -> str:1190 if self.type_name is not None:1191 return self.type_name11921193 name = self.valobj.GetTypeName()11941195 if name.startswith("ref_mut"):1196 name = name[len("ref_mut$<slice2$<") :].rstrip("> ")1197 self.type_name = f"&mut [{name}]"1198 elif name.startswith("ref"):1199 name = name[len("ref$<slice2$<") :].rstrip("> ")1200 self.type_name = f"&[{name}]"1201 elif name.startswith("ptr_mut"):1202 name = name[len("ptr_mut$<slice2$<") :].rstrip("> ")1203 self.type_name = f"*mut [{name}]"1204 elif name.startswith("ptr_const"):1205 name = name[len("ptr_const$<slice2$<") :].rstrip("> ")1206 self.type_name = f"*const [{name}]"1207 elif name.startswith("alloc::boxed::Box"):1208 prefix_len = len("alloc::boxed::Box<slice2$<")1209 suffix_len = len(">,alloc::alloc::Global>")1210 if name.endswith(",alloc::alloc::Global>"):1211 name = name[prefix_len : len(name) - suffix_len]12121213 self.type_name = f"Box<[{name}]>"1214 else:1215 [element_name, alloc_name] = name[prefix_len:].split(">", 1)12161217 name = f"{element_name}{alloc_name}"12181219 # alloc name contains the trailing ">", so we don't need to add it1220 self.type_name = f"Box<[{element_name}]{alloc_name}"1221 else:1222 self.type_name = name12231224 return self.type_name122512261227def StdSliceSummaryProvider(valobj, dict):1228 output = sequence_formatter("[", valobj, dict)1229 output += "]"1230 return output123112321233class StdVecDequeSyntheticProvider:1234 """Pretty-printer for alloc::collections::vec_deque::VecDeque<T>12351236 struct VecDeque<T> { head: WrappedIndex, len: usize, buf: RawVec<T> }1237 """12381239 def __init__(self, valobj: SBValue, _dict: LLDBOpaque):1240 # logger = Logger.Logger()1241 # logger >> "[StdVecDequeSyntheticProvider] for " + str(valobj.GetName())1242 self.valobj = valobj1243 self.element_type = None1244 self.update()12451246 def num_children(self) -> int:1247 return self.size12481249 def get_child_index(self, name: str) -> int:1250 index = name.lstrip("[").rstrip("]")1251 if index.isdigit() and int(index) < self.size:1252 return int(index)1253 else:1254 return -112551256 def get_child_at_index(self, index: int) -> Optional[SBValue]:1257 start = self.data_ptr.GetValueAsUnsigned()1258 address = start + ((index + self.head) % self.cap) * self.element_type_size1259 element = self.data_ptr.CreateValueFromAddress(1260 "[%s]" % index, address, self.element_type1261 )1262 return element12631264 def update(self):1265 head = self.valobj.GetChildMemberWithName("head")1266 # BACKCOMPAT: rust 1.951267 if head.GetType().num_fields == 1:1268 head = head.GetChildAtIndex(0)1269 self.head = head.GetValueAsUnsigned()1270 self.size = self.valobj.GetChildMemberWithName("len").GetValueAsUnsigned()1271 self.buf = self.valobj.GetChildMemberWithName("buf").GetChildMemberWithName(1272 "inner"1273 )1274 cap = self.buf.GetChildMemberWithName("cap")1275 if cap.GetType().num_fields == 1:1276 cap = cap.GetChildAtIndex(0)1277 self.cap = cap.GetValueAsUnsigned()12781279 self.data_ptr = unwrap_unique_or_non_null(1280 self.buf.GetChildMemberWithName("ptr")1281 )12821283 self.element_type = self.valobj.GetType().GetTemplateArgumentType(0)12841285 if not self.element_type.IsValid():1286 arg_name = next(get_template_args(self.valobj.GetTypeName()))12871288 self.element_type = resolve_msvc_template_arg(arg_name, self.valobj.target)12891290 self.element_type_size = self.element_type.GetByteSize()12911292 def has_children(self) -> bool:1293 return True129412951296# BACKCOMPAT: rust 1.351297class StdOldHashMapSyntheticProvider:1298 """Pretty-printer for std::collections::hash::map::HashMap<K, V, S>12991300 struct HashMap<K, V, S> {..., table: RawTable<K, V>, ... }1301 struct RawTable<K, V> { capacity_mask: usize, size: usize, hashes: TaggedHashUintPtr, ... }1302 """13031304 def __init__(self, valobj: SBValue, _dict: LLDBOpaque, show_values: bool = True):1305 self.valobj = valobj1306 self.show_values = show_values1307 self.update()13081309 def num_children(self) -> int:1310 return self.size13111312 def get_child_index(self, name: str) -> int:1313 index = name.lstrip("[").rstrip("]")1314 if index.isdigit():1315 return int(index)1316 else:1317 return -113181319 def get_child_at_index(self, index: int) -> Optional[SBValue]:1320 # logger = Logger.Logger()1321 start = self.data_ptr.GetValueAsUnsigned() & ~113221323 # See `libstd/collections/hash/table.rs:raw_bucket_at1324 hashes = self.hash_uint_size * self.capacity1325 align = self.pair_type_size1326 # See `libcore/alloc.rs:padding_needed_for`1327 len_rounded_up = (1328 (1329 (((hashes + align) % self.modulo - 1) % self.modulo)1330 & ~((align - 1) % self.modulo)1331 )1332 % self.modulo1333 - hashes1334 ) % self.modulo1335 # len_rounded_up = ((hashes + align - 1) & ~(align - 1)) - hashes13361337 pairs_offset = hashes + len_rounded_up1338 pairs_start = start + pairs_offset13391340 table_index = self.valid_indices[index]1341 idx = table_index & self.capacity_mask1342 address = pairs_start + idx * self.pair_type_size1343 element = self.data_ptr.CreateValueFromAddress(1344 "[%s]" % index, address, self.pair_type1345 )1346 if self.show_values:1347 return element1348 else:1349 key = element.GetChildAtIndex(0)1350 return self.valobj.CreateValueFromData(1351 "[%s]" % index, key.GetData(), key.GetType()1352 )13531354 def update(self):1355 # logger = Logger.Logger()13561357 self.table = self.valobj.GetChildMemberWithName("table") # type: SBValue1358 self.size = self.table.GetChildMemberWithName("size").GetValueAsUnsigned()1359 self.hashes = self.table.GetChildMemberWithName("hashes")1360 self.hash_uint_type = self.hashes.GetType()1361 self.hash_uint_size = self.hashes.GetType().GetByteSize()1362 self.modulo = 2**self.hash_uint_size1363 self.data_ptr = self.hashes.GetChildAtIndex(0).GetChildAtIndex(0)13641365 self.capacity_mask = self.table.GetChildMemberWithName(1366 "capacity_mask"1367 ).GetValueAsUnsigned()1368 self.capacity = (self.capacity_mask + 1) % self.modulo13691370 marker = self.table.GetChildMemberWithName("marker").GetType() # type: SBType1371 self.pair_type = marker.template_args[0]1372 self.pair_type_size = self.pair_type.GetByteSize()13731374 self.valid_indices = []1375 for idx in range(self.capacity):1376 address = self.data_ptr.GetValueAsUnsigned() + idx * self.hash_uint_size1377 hash_uint = self.data_ptr.CreateValueFromAddress(1378 "[%s]" % idx, address, self.hash_uint_type1379 )1380 hash_ptr = hash_uint.GetChildAtIndex(0).GetChildAtIndex(0)1381 if hash_ptr.GetValueAsUnsigned() != 0:1382 self.valid_indices.append(idx)13831384 # logger >> "Valid indices: {}".format(str(self.valid_indices))13851386 def has_children(self) -> bool:1387 return True138813891390class StdHashMapSyntheticProvider:1391 """Pretty-printer for hashbrown's HashMap"""13921393 def __init__(self, valobj: SBValue, _dict: LLDBOpaque, show_values: bool = True):1394 self.valobj = valobj1395 self.show_values = show_values1396 self.update()13971398 def num_children(self) -> int:1399 return self.size14001401 def get_child_index(self, name: str) -> int:1402 index = name.lstrip("[").rstrip("]")1403 if index.isdigit():1404 return int(index)1405 else:1406 return -114071408 def get_child_at_index(self, index: int) -> Optional[SBValue]:1409 pairs_start = self.data_ptr.GetValueAsUnsigned()1410 idx = self.valid_indices[index]1411 if self.new_layout:1412 idx = -(idx + 1)1413 address = pairs_start + idx * self.pair_type_size1414 element = self.data_ptr.CreateValueFromAddress(1415 "[%s]" % index, address, self.pair_type1416 )14171418 if self.show_values:1419 return element1420 else:1421 key = element.GetChildAtIndex(0)1422 return self.valobj.CreateValueFromData(1423 "[%s]" % index, key.GetData(), key.GetType()1424 )14251426 def update(self):1427 table = self.table()1428 inner_table = table.GetChildMemberWithName("table")14291430 capacity = (1431 inner_table.GetChildMemberWithName("bucket_mask").GetValueAsUnsigned() + 11432 )1433 ctrl = inner_table.GetChildMemberWithName("ctrl").GetChildAtIndex(0)14341435 self.size = inner_table.GetChildMemberWithName("items").GetValueAsUnsigned()14361437 self.pair_type = table.GetType().GetTemplateArgumentType(0)14381439 if not self.pair_type.IsValid():1440 arg_name = next(get_template_args(table.GetTypeName()))14411442 self.pair_type = resolve_msvc_template_arg(arg_name, self.valobj.target)14431444 if self.pair_type.IsTypedefType():1445 self.pair_type = self.pair_type.GetTypedefedType()1446 self.pair_type_size = self.pair_type.GetByteSize()14471448 self.new_layout = not inner_table.GetChildMemberWithName("data").IsValid()1449 if self.new_layout:1450 self.data_ptr = ctrl.Cast(self.pair_type.GetPointerType())1451 else:1452 self.data_ptr = inner_table.GetChildMemberWithName("data").GetChildAtIndex(1453 01454 )14551456 u8_type = self.valobj.GetTarget().GetBasicType(eBasicTypeUnsignedChar)1457 u8_type_size = (1458 self.valobj.GetTarget().GetBasicType(eBasicTypeUnsignedChar).GetByteSize()1459 )14601461 self.valid_indices = []1462 for idx in range(capacity):1463 address = ctrl.GetValueAsUnsigned() + idx * u8_type_size1464 value = ctrl.CreateValueFromAddress(1465 "ctrl[%s]" % idx, address, u8_type1466 ).GetValueAsUnsigned()1467 is_present = value & 128 == 01468 if is_present:1469 self.valid_indices.append(idx)14701471 def table(self) -> SBValue:1472 if self.show_values:1473 hashbrown_hashmap = self.valobj.GetChildMemberWithName("base")1474 else:1475 # BACKCOMPAT: rust 1.471476 # HashSet wraps either std HashMap or hashbrown::HashSet, which both1477 # wrap hashbrown::HashMap, so either way we "unwrap" twice.1478 hashbrown_hashmap = self.valobj.GetChildAtIndex(0).GetChildAtIndex(0)1479 return hashbrown_hashmap.GetChildMemberWithName("table")14801481 def has_children(self) -> bool:1482 return True148314841485def StdRcSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str:1486 strong = valobj.GetChildMemberWithName("strong").GetValueAsUnsigned()1487 weak = valobj.GetChildMemberWithName("weak").GetValueAsUnsigned()1488 return "strong={}, weak={}".format(strong, weak)148914901491class StdRcSyntheticProvider:1492 """Pretty-printer for alloc::rc::Rc<T> and alloc::sync::Arc<T>14931494 struct Rc<T> { ptr: NonNull<RcInner<T>>, ... }1495 rust 1.31.1: struct NonNull<T> { pointer: NonZero<*const T> }1496 rust 1.33.0: struct NonNull<T> { pointer: *const T }1497 struct NonZero<T>(T)1498 struct RcInner<T> { strong: Cell<usize>, weak: Cell<usize>, value: T }14991500 struct Arc<T> { ptr: NonNull<ArcInner<T>>, ... }1501 struct ArcInner<T> { strong: atomic::Atomic<usize>, weak: atomic::Atomic<usize>, data: T }1502 """15031504 def __init__(self, valobj: SBValue, _dict: LLDBOpaque, is_atomic: bool = False):1505 self.valobj = valobj15061507 self.ptr = unwrap_unique_or_non_null(self.valobj.GetChildMemberWithName("ptr"))15081509 self.value = self.ptr.GetChildMemberWithName("data" if is_atomic else "value")15101511 self.strong = unwrap_scalar_wrappers(self.ptr.GetChildMemberWithName("strong"))1512 self.weak = unwrap_scalar_wrappers(self.ptr.GetChildMemberWithName("weak"))15131514 self.value_builder = ValueBuilder(valobj)15151516 self.update()15171518 def num_children(self) -> int:1519 # Actually there are 3 children, but only the `value` should be shown as a child1520 return 115211522 def get_child_index(self, name: str) -> int:1523 if name == "value":1524 return 01525 if name == "strong":1526 return 11527 if name == "weak":1528 return 21529 return -115301531 def get_child_at_index(self, index: int) -> Optional[SBValue]:1532 if index == 0:1533 return self.value1534 if index == 1:1535 return self.value_builder.from_uint("strong", self.strong_count)1536 if index == 2:1537 return self.value_builder.from_uint("weak", self.weak_count)15381539 return None15401541 def update(self):1542 self.strong_count = self.strong.GetValueAsUnsigned()1543 self.weak_count = self.weak.GetValueAsUnsigned() - 115441545 def has_children(self) -> bool:1546 return True154715481549class StdCellSyntheticProvider:1550 """Pretty-printer for std::cell::Cell"""15511552 def __init__(self, valobj: SBValue, _dict: LLDBOpaque):1553 self.valobj = valobj1554 self.value = valobj.GetChildMemberWithName("value").GetChildAtIndex(0)15551556 def num_children(self) -> int:1557 return 115581559 def get_child_index(self, name: str) -> int:1560 if name == "value":1561 return 01562 return -115631564 def get_child_at_index(self, index: int) -> Optional[SBValue]:1565 if index == 0:1566 return self.value1567 return None15681569 def update(self):1570 pass15711572 def has_children(self) -> bool:1573 return True157415751576def StdRefSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str:1577 borrow = valobj.GetChildMemberWithName("borrow").GetValueAsSigned()1578 return (1579 "borrow={}".format(borrow) if borrow >= 0 else "borrow_mut={}".format(-borrow)1580 )158115821583class StdRefSyntheticProvider:1584 """Pretty-printer for std::cell::Ref, std::cell::RefMut, and std::cell::RefCell"""15851586 def __init__(self, valobj: SBValue, _dict: LLDBOpaque, is_cell: bool = False):1587 self.valobj = valobj15881589 borrow = valobj.GetChildMemberWithName("borrow")1590 value = valobj.GetChildMemberWithName("value")1591 if is_cell:1592 self.borrow = borrow.GetChildMemberWithName("value").GetChildMemberWithName(1593 "value"1594 )1595 self.value = value.GetChildMemberWithName("value")1596 else:1597 self.borrow = (1598 borrow.GetChildMemberWithName("borrow")1599 .GetChildMemberWithName("value")1600 .GetChildMemberWithName("value")1601 )1602 self.value = value.Dereference()16031604 self.value_builder = ValueBuilder(valobj)16051606 self.update()16071608 def num_children(self) -> int:1609 # Actually there are 2 children, but only the `value` should be shown as a child1610 return 116111612 def get_child_index(self, name: str) -> int:1613 if name == "value":1614 return 01615 if name == "borrow":1616 return 11617 return -116181619 def get_child_at_index(self, index: int) -> Optional[SBValue]:1620 if index == 0:1621 return self.value1622 if index == 1:1623 return self.value_builder.from_int("borrow", self.borrow_count)1624 return None16251626 def update(self):1627 self.borrow_count = self.borrow.GetValueAsSigned()16281629 def has_children(self) -> bool:1630 return True163116321633def StdNonZeroNumberSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str:1634 inner = valobj.GetChildAtIndex(0)1635 inner_inner = inner.GetChildAtIndex(0)16361637 # FIXME: Avoid printing as character literal,1638 # see https://github.com/llvm/llvm-project/issues/65076.1639 if inner_inner.GetTypeName() in ["char", "unsigned char"]:1640 return str(inner_inner.GetValueAsSigned())1641 else:1642 return inner_inner.GetValue()
Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.