From ca625809c46f054b9debf149cff79e65fc3564ea Mon Sep 17 00:00:00 2001 From: Walnut <39544927+Walnut356@users.noreply.github.com> Date: Sat, 4 Oct 2025 20:32:53 -0500 Subject: [PATCH 1/3] change RustType from string literals to enum --- src/etc/gdb_lookup.py | 46 +++++++------- src/etc/lldb_lookup.py | 77 ++++++++++++----------- src/etc/lldb_providers.py | 2 +- src/etc/rust_types.py | 127 +++++++++++++++++++------------------- 4 files changed, 128 insertions(+), 124 deletions(-) diff --git a/src/etc/gdb_lookup.py b/src/etc/gdb_lookup.py index d368f7ed1ec5c..c70944790d2b5 100644 --- a/src/etc/gdb_lookup.py +++ b/src/etc/gdb_lookup.py @@ -3,7 +3,7 @@ import re from gdb_providers import * -from rust_types import * +from rust_types import RustType, classify_struct, classify_union _gdb_version_matched = re.search("([0-9]+)\\.([0-9]+)", gdb.VERSION) @@ -28,7 +28,7 @@ def classify_rust_type(type): if type_class == gdb.TYPE_CODE_UNION: return classify_union(type.fields()) - return RustType.OTHER + return RustType.Other def check_enum_discriminant(valobj): @@ -85,7 +85,7 @@ def __init__(self, name): def add(self, rust_type, provider): # Just use the rust_type as the name. - printer = PrintByRustType(rust_type, provider) + printer = PrintByRustType(rust_type.name, provider) self.type_map[rust_type] = printer self.subprinters.append(printer) @@ -99,23 +99,23 @@ def __call__(self, valobj): printer = RustPrettyPrinter("rust") # use enum provider only for GDB <7.12 if gdb_version[0] < 7 or (gdb_version[0] == 7 and gdb_version[1] < 12): - printer.add(RustType.ENUM, enum_provider) -printer.add(RustType.STD_STRING, StdStringProvider) -printer.add(RustType.STD_OS_STRING, StdOsStringProvider) -printer.add(RustType.STD_STR, StdStrProvider) -printer.add(RustType.STD_SLICE, StdSliceProvider) -printer.add(RustType.STD_VEC, StdVecProvider) -printer.add(RustType.STD_VEC_DEQUE, StdVecDequeProvider) -printer.add(RustType.STD_BTREE_SET, StdBTreeSetProvider) -printer.add(RustType.STD_BTREE_MAP, StdBTreeMapProvider) -printer.add(RustType.STD_HASH_MAP, hashmap_provider) -printer.add(RustType.STD_HASH_SET, hashset_provider) -printer.add(RustType.STD_RC, StdRcProvider) -printer.add(RustType.STD_ARC, lambda valobj: StdRcProvider(valobj, is_atomic=True)) - -printer.add(RustType.STD_CELL, StdCellProvider) -printer.add(RustType.STD_REF, StdRefProvider) -printer.add(RustType.STD_REF_MUT, StdRefProvider) -printer.add(RustType.STD_REF_CELL, StdRefCellProvider) - -printer.add(RustType.STD_NONZERO_NUMBER, StdNonZeroNumberProvider) + printer.add(RustType.Enum, enum_provider) +printer.add(RustType.StdString, StdStringProvider) +printer.add(RustType.StdOsString, StdOsStringProvider) +printer.add(RustType.StdStr, StdStrProvider) +printer.add(RustType.StdSlice, StdSliceProvider) +printer.add(RustType.StdVec, StdVecProvider) +printer.add(RustType.StdVecDeque, StdVecDequeProvider) +printer.add(RustType.StdBTreeSet, StdBTreeSetProvider) +printer.add(RustType.StdBTreeMap, StdBTreeMapProvider) +printer.add(RustType.StdHashMap, hashmap_provider) +printer.add(RustType.StdHashSet, hashset_provider) +printer.add(RustType.StdRc, StdRcProvider) +printer.add(RustType.StdArc, lambda valobj: StdRcProvider(valobj, is_atomic=True)) + +printer.add(RustType.StdCell, StdCellProvider) +printer.add(RustType.StdRef, StdRefProvider) +printer.add(RustType.StdRefMut, StdRefProvider) +printer.add(RustType.StdRefCell, StdRefCellProvider) + +printer.add(RustType.StdNonZeroNumber, StdNonZeroNumberProvider) diff --git a/src/etc/lldb_lookup.py b/src/etc/lldb_lookup.py index f43d2c6a7252e..3c10e4a4d2b4e 100644 --- a/src/etc/lldb_lookup.py +++ b/src/etc/lldb_lookup.py @@ -1,3 +1,6 @@ +from __future__ import annotations +from typing import Dict + import lldb from lldb_providers import * @@ -9,7 +12,7 @@ def is_hashbrown_hashmap(hash_map: lldb.SBValue) -> bool: return len(hash_map.type.fields) == 1 -def classify_rust_type(type: lldb.SBType) -> str: +def classify_rust_type(type: lldb.SBType) -> RustType: if type.IsPointerType(): type = type.GetPointeeType() @@ -19,50 +22,50 @@ def classify_rust_type(type: lldb.SBType) -> str: if type_class == lldb.eTypeClassUnion: return classify_union(type.fields) - return RustType.OTHER + return RustType.Other def summary_lookup(valobj: lldb.SBValue, _dict: LLDBOpaque) -> str: """Returns the summary provider for the given value""" rust_type = classify_rust_type(valobj.GetType()) - if rust_type == RustType.STD_STRING: + if rust_type == RustType.StdString: return StdStringSummaryProvider(valobj, _dict) - if rust_type == RustType.STD_OS_STRING: + if rust_type == RustType.StdOsString: return StdOsStringSummaryProvider(valobj, _dict) - if rust_type == RustType.STD_STR: + if rust_type == RustType.StdStr: return StdStrSummaryProvider(valobj, _dict) - if rust_type == RustType.STD_VEC: + if rust_type == RustType.StdVec: return SizeSummaryProvider(valobj, _dict) - if rust_type == RustType.STD_VEC_DEQUE: + if rust_type == RustType.StdVecDeque: return SizeSummaryProvider(valobj, _dict) - if rust_type == RustType.STD_SLICE: + if rust_type == RustType.StdSlice: return SizeSummaryProvider(valobj, _dict) - if rust_type == RustType.STD_HASH_MAP: + if rust_type == RustType.StdHashMap: return SizeSummaryProvider(valobj, _dict) - if rust_type == RustType.STD_HASH_SET: + if rust_type == RustType.StdHashSet: return SizeSummaryProvider(valobj, _dict) - if rust_type == RustType.STD_RC: + if rust_type == RustType.StdRc: return StdRcSummaryProvider(valobj, _dict) - if rust_type == RustType.STD_ARC: + if rust_type == RustType.StdArc: return StdRcSummaryProvider(valobj, _dict) - if rust_type == RustType.STD_REF: + if rust_type == RustType.StdRef: return StdRefSummaryProvider(valobj, _dict) - if rust_type == RustType.STD_REF_MUT: + if rust_type == RustType.StdRefMut: return StdRefSummaryProvider(valobj, _dict) - if rust_type == RustType.STD_REF_CELL: + if rust_type == RustType.StdRefCell: return StdRefSummaryProvider(valobj, _dict) - if rust_type == RustType.STD_NONZERO_NUMBER: + if rust_type == RustType.StdNonZeroNumber: return StdNonZeroNumberSummaryProvider(valobj, _dict) - if rust_type == RustType.STD_PATHBUF: + if rust_type == RustType.StdPathBuf: return StdPathBufSummaryProvider(valobj, _dict) - if rust_type == RustType.STD_PATH: + if rust_type == RustType.StdPath: return StdPathSummaryProvider(valobj, _dict) return "" @@ -72,54 +75,54 @@ def synthetic_lookup(valobj: lldb.SBValue, _dict: LLDBOpaque) -> object: """Returns the synthetic provider for the given value""" rust_type = classify_rust_type(valobj.GetType()) - if rust_type == RustType.STRUCT: + if rust_type == RustType.Struct: return StructSyntheticProvider(valobj, _dict) - if rust_type == RustType.STRUCT_VARIANT: + if rust_type == RustType.StructVariant: return StructSyntheticProvider(valobj, _dict, is_variant=True) - if rust_type == RustType.TUPLE: + if rust_type == RustType.Tuple: return TupleSyntheticProvider(valobj, _dict) - if rust_type == RustType.TUPLE_VARIANT: + if rust_type == RustType.TupleVariant: return TupleSyntheticProvider(valobj, _dict, is_variant=True) - if rust_type == RustType.EMPTY: + if rust_type == RustType.Empty: return EmptySyntheticProvider(valobj, _dict) - if rust_type == RustType.REGULAR_ENUM: + if rust_type == RustType.RegularEnum: discriminant = valobj.GetChildAtIndex(0).GetChildAtIndex(0).GetValueAsUnsigned() return synthetic_lookup(valobj.GetChildAtIndex(discriminant), _dict) - if rust_type == RustType.SINGLETON_ENUM: + if rust_type == RustType.SingletonEnum: return synthetic_lookup(valobj.GetChildAtIndex(0), _dict) - if rust_type == RustType.ENUM: + if rust_type == RustType.Enum: return ClangEncodedEnumProvider(valobj, _dict) - if rust_type == RustType.STD_VEC: + if rust_type == RustType.StdVec: return StdVecSyntheticProvider(valobj, _dict) - if rust_type == RustType.STD_VEC_DEQUE: + if rust_type == RustType.StdVecDeque: return StdVecDequeSyntheticProvider(valobj, _dict) - if rust_type == RustType.STD_SLICE or rust_type == RustType.STD_STR: + if rust_type == RustType.StdSlice or rust_type == RustType.StdStr: return StdSliceSyntheticProvider(valobj, _dict) - if rust_type == RustType.STD_HASH_MAP: + if rust_type == RustType.StdHashMap: if is_hashbrown_hashmap(valobj): return StdHashMapSyntheticProvider(valobj, _dict) else: return StdOldHashMapSyntheticProvider(valobj, _dict) - if rust_type == RustType.STD_HASH_SET: + if rust_type == RustType.StdHashSet: hash_map = valobj.GetChildAtIndex(0) if is_hashbrown_hashmap(hash_map): return StdHashMapSyntheticProvider(valobj, _dict, show_values=False) else: return StdOldHashMapSyntheticProvider(hash_map, _dict, show_values=False) - if rust_type == RustType.STD_RC: + if rust_type == RustType.StdRc: return StdRcSyntheticProvider(valobj, _dict) - if rust_type == RustType.STD_ARC: + if rust_type == RustType.StdArc: return StdRcSyntheticProvider(valobj, _dict, is_atomic=True) - if rust_type == RustType.STD_CELL: + if rust_type == RustType.StdCell: return StdCellSyntheticProvider(valobj, _dict) - if rust_type == RustType.STD_REF: + if rust_type == RustType.StdRef: return StdRefSyntheticProvider(valobj, _dict) - if rust_type == RustType.STD_REF_MUT: + if rust_type == RustType.StdRefMut: return StdRefSyntheticProvider(valobj, _dict) - if rust_type == RustType.STD_REF_CELL: + if rust_type == RustType.StdRefCell: return StdRefSyntheticProvider(valobj, _dict, is_cell=True) return DefaultSyntheticProvider(valobj, _dict) diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py index 3eb964d2fbab9..7ea79447d21ba 100644 --- a/src/etc/lldb_providers.py +++ b/src/etc/lldb_providers.py @@ -177,7 +177,7 @@ def vec_to_string(vec: SBValue) -> str: ) -def StdStringSummaryProvider(valobj, dict): +def StdStringSummaryProvider(valobj: SBValue, dict: LLDBOpaque): inner_vec = ( valobj.GetNonSyntheticValue() .GetChildMemberWithName("vec") diff --git a/src/etc/rust_types.py b/src/etc/rust_types.py index af03e8ede9c3f..74e0a83c3f599 100644 --- a/src/etc/rust_types.py +++ b/src/etc/rust_types.py @@ -1,40 +1,41 @@ +from enum import Enum from typing import List import re -class RustType(object): - OTHER = "Other" - STRUCT = "Struct" - TUPLE = "Tuple" - CSTYLE_VARIANT = "CStyleVariant" - TUPLE_VARIANT = "TupleVariant" - STRUCT_VARIANT = "StructVariant" - ENUM = "Enum" - EMPTY = "Empty" - SINGLETON_ENUM = "SingletonEnum" - REGULAR_ENUM = "RegularEnum" - COMPRESSED_ENUM = "CompressedEnum" - REGULAR_UNION = "RegularUnion" - - STD_STRING = "StdString" - STD_OS_STRING = "StdOsString" - STD_STR = "StdStr" - STD_SLICE = "StdSlice" - STD_VEC = "StdVec" - STD_VEC_DEQUE = "StdVecDeque" - STD_BTREE_SET = "StdBTreeSet" - STD_BTREE_MAP = "StdBTreeMap" - STD_HASH_MAP = "StdHashMap" - STD_HASH_SET = "StdHashSet" - STD_RC = "StdRc" - STD_ARC = "StdArc" - STD_CELL = "StdCell" - STD_REF = "StdRef" - STD_REF_MUT = "StdRefMut" - STD_REF_CELL = "StdRefCell" - STD_NONZERO_NUMBER = "StdNonZeroNumber" - STD_PATH = "StdPath" - STD_PATHBUF = "StdPathBuf" +class RustType(Enum): + Other = 0 + Struct = 1 + Tuple = 2 + CStyleVariant = 3 + TupleVariant = 4 + StructVariant = 5 + Enum = 6 + Empty = 7 + SingletonEnum = 8 + RegularEnum = 9 + CompressedEnum = 10 + RegularUnion = 11 + + StdString = 12 + StdOsString = 13 + StdStr = 14 + StdSlice = 15 + StdVec = 16 + StdVecDeque = 17 + StdBTreeSet = 18 + StdBTreeMap = 19 + StdHashMap = 20 + StdHashSet = 21 + StdRc = 22 + StdArc = 23 + StdCell = 24 + StdRef = 25 + StdRefMut = 26 + StdRefCell = 27 + StdNonZeroNumber = 28 + StdPath = 29 + StdPathBuf = 30 STD_STRING_REGEX = re.compile(r"^(alloc::([a-z_]+::)+)String$") @@ -64,25 +65,25 @@ class RustType(object): ENUM_LLDB_ENCODED_VARIANTS = "$variants$" STD_TYPE_TO_REGEX = { - RustType.STD_STRING: STD_STRING_REGEX, - RustType.STD_OS_STRING: STD_OS_STRING_REGEX, - RustType.STD_STR: STD_STR_REGEX, - RustType.STD_SLICE: STD_SLICE_REGEX, - RustType.STD_VEC: STD_VEC_REGEX, - RustType.STD_VEC_DEQUE: STD_VEC_DEQUE_REGEX, - RustType.STD_HASH_MAP: STD_HASH_MAP_REGEX, - RustType.STD_HASH_SET: STD_HASH_SET_REGEX, - RustType.STD_BTREE_SET: STD_BTREE_SET_REGEX, - RustType.STD_BTREE_MAP: STD_BTREE_MAP_REGEX, - RustType.STD_RC: STD_RC_REGEX, - RustType.STD_ARC: STD_ARC_REGEX, - RustType.STD_REF: STD_REF_REGEX, - RustType.STD_REF_MUT: STD_REF_MUT_REGEX, - RustType.STD_REF_CELL: STD_REF_CELL_REGEX, - RustType.STD_CELL: STD_CELL_REGEX, - RustType.STD_NONZERO_NUMBER: STD_NONZERO_NUMBER_REGEX, - RustType.STD_PATHBUF: STD_PATHBUF_REGEX, - RustType.STD_PATH: STD_PATH_REGEX, + RustType.StdString: STD_STRING_REGEX, + RustType.StdOsString: STD_OS_STRING_REGEX, + RustType.StdStr: STD_STR_REGEX, + RustType.StdSlice: STD_SLICE_REGEX, + RustType.StdVec: STD_VEC_REGEX, + RustType.StdVecDeque: STD_VEC_DEQUE_REGEX, + RustType.StdHashMap: STD_HASH_MAP_REGEX, + RustType.StdHashSet: STD_HASH_SET_REGEX, + RustType.StdBTreeSet: STD_BTREE_SET_REGEX, + RustType.StdBTreeMap: STD_BTREE_MAP_REGEX, + RustType.StdRc: STD_RC_REGEX, + RustType.StdArc: STD_ARC_REGEX, + RustType.StdRef: STD_REF_REGEX, + RustType.StdRefMut: STD_REF_MUT_REGEX, + RustType.StdRefCell: STD_REF_CELL_REGEX, + RustType.StdCell: STD_CELL_REGEX, + RustType.StdNonZeroNumber: STD_NONZERO_NUMBER_REGEX, + RustType.StdPath: STD_PATH_REGEX, + RustType.StdPathBuf: STD_PATHBUF_REGEX, } @@ -90,9 +91,9 @@ def is_tuple_fields(fields: List) -> bool: return all(TUPLE_ITEM_REGEX.match(str(field.name)) for field in fields) -def classify_struct(name: str, fields: List) -> str: +def classify_struct(name: str, fields: List) -> RustType: if len(fields) == 0: - return RustType.EMPTY + return RustType.Empty for ty, regex in STD_TYPE_TO_REGEX.items(): if regex.match(name): @@ -103,26 +104,26 @@ def classify_struct(name: str, fields: List) -> str: fields[0].name == ENUM_DISR_FIELD_NAME or fields[0].name == ENUM_LLDB_ENCODED_VARIANTS ): - return RustType.ENUM + return RustType.Enum if is_tuple_fields(fields): - return RustType.TUPLE + return RustType.Tuple - return RustType.STRUCT + return RustType.Struct -def classify_union(fields: List) -> str: +def classify_union(fields: List) -> RustType: if len(fields) == 0: - return RustType.EMPTY + return RustType.Empty first_variant_name = fields[0].name if first_variant_name is None: if len(fields) == 1: - return RustType.SINGLETON_ENUM + return RustType.SingletonEnum else: - return RustType.REGULAR_ENUM + return RustType.RegularEnum elif first_variant_name.startswith(ENCODED_ENUM_PREFIX): assert len(fields) == 1 - return RustType.COMPRESSED_ENUM + return RustType.CompressedEnum else: - return RustType.REGULAR_UNION + return RustType.RegularEnum From ca24813d7b7a957bf0b388fbe8c9236683897df9 Mon Sep 17 00:00:00 2001 From: Walnut <39544927+Walnut356@users.noreply.github.com> Date: Mon, 6 Oct 2025 03:20:39 -0500 Subject: [PATCH 2/3] remove unnecessary regex usage --- src/etc/lldb_providers.py | 9 ++++++--- src/etc/rust_types.py | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py index 7ea79447d21ba..4024386b77e34 100644 --- a/src/etc/lldb_providers.py +++ b/src/etc/lldb_providers.py @@ -1,5 +1,4 @@ from __future__ import annotations -import re import sys from typing import List, TYPE_CHECKING @@ -417,8 +416,12 @@ def _getVariantName(variant) -> str: we can extract `TheVariantName` from it for display purpose. """ s = variant.GetType().GetName() - match = re.search(r"::([^:]+)\$Variant$", s) - return match.group(1) if match else "" + if not s.endswith("$Variant"): + return "" + + # trim off path and "$Variant" + # len("$Variant") == 8 + return s.rsplit("::", 1)[1][:-8] class ClangEncodedEnumProvider: diff --git a/src/etc/rust_types.py b/src/etc/rust_types.py index 74e0a83c3f599..926f4b42956ee 100644 --- a/src/etc/rust_types.py +++ b/src/etc/rust_types.py @@ -58,8 +58,6 @@ class RustType(Enum): STD_PATHBUF_REGEX = re.compile(r"^(std::([a-z_]+::)+)PathBuf$") STD_PATH_REGEX = re.compile(r"^&(mut )?(std::([a-z_]+::)+)Path$") -TUPLE_ITEM_REGEX = re.compile(r"__\d+$") - ENCODED_ENUM_PREFIX = "RUST$ENCODED$ENUM$" ENUM_DISR_FIELD_NAME = "<>" ENUM_LLDB_ENCODED_VARIANTS = "$variants$" @@ -88,7 +86,12 @@ class RustType(Enum): def is_tuple_fields(fields: List) -> bool: - return all(TUPLE_ITEM_REGEX.match(str(field.name)) for field in fields) + for f in fields: + name = str(f.name) + if not name.startswith("__") or not name[2:].isdigit(): + return False + + return True def classify_struct(name: str, fields: List) -> RustType: From 2e8e6181111dcbfd926886fc9f8e5188aeba3572 Mon Sep 17 00:00:00 2001 From: Walnut <39544927+Walnut356@users.noreply.github.com> Date: Fri, 10 Oct 2025 05:42:40 -0500 Subject: [PATCH 3/3] use direct providers when possible --- src/etc/lldb_commands | 97 ++++++++++++------------ src/etc/lldb_lookup.py | 153 ++++++++++++++++++-------------------- src/etc/lldb_providers.py | 33 ++++++++ src/etc/rust_types.py | 43 +++++------ 4 files changed, 177 insertions(+), 149 deletions(-) diff --git a/src/etc/lldb_commands b/src/etc/lldb_commands index 508296c3a5aec..9b5d1eae52822 100644 --- a/src/etc/lldb_commands +++ b/src/etc/lldb_commands @@ -1,80 +1,85 @@ +# LLDB iterates through these in reverse order to discover summaries/synthetics that means the top +# of the list can be "overwritten" by items lower on the list. Be careful when reordering items. + # Forces test-compliant formatting to all other types type synthetic add -l lldb_lookup.synthetic_lookup -x ".*" --category Rust -type summary add -F _ -e -x -h "^.*$" --category Rust + # Std String type synthetic add -l lldb_lookup.StdStringSyntheticProvider -x "^(alloc::([a-z_]+::)+)String$" --category Rust -type summary add -F lldb_lookup.StdStringSummaryProvider -e -x -h "^(alloc::([a-z_]+::)+)String$" --category Rust +type summary add -F lldb_lookup.StdStringSummaryProvider -e -x -h "^(alloc::([a-z_]+::)+)String$" --category Rust + # Std str -type synthetic add -l lldb_lookup.synthetic_lookup -x "^&(mut )?str$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^&(mut )?str$" --category Rust +type synthetic add -l lldb_lookup.StdSliceSyntheticProvider -x "^&(mut )?str$" --category Rust +type summary add -F lldb_lookup.StdStrSummaryProvider -e -x -h "^&(mut )?str$" --category Rust + ## MSVC type synthetic add -l lldb_lookup.MSVCStrSyntheticProvider -x "^ref(_mut)?\$$" --category Rust type summary add -F lldb_lookup.StdStrSummaryProvider -e -h -x "^ref(_mut)?\$$" --category Rust -# Array -type synthetic add -l lldb_lookup.synthetic_lookup -x "^&(mut )?\\[.+\\]$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^&(mut )?\\[.+\\]$" --category Rust -# Slice + +# Array/Slice +type synthetic add -l lldb_lookup.StdSliceSyntheticProvider -x "^&(mut )?\\[.+\\]$" --category Rust +type summary add -F lldb_lookup.SizeSummaryProvider -e -x -h "^&(mut )?\\[.+\\]$" --category Rust + ## MSVC type synthetic add -l lldb_lookup.MSVCStdSliceSyntheticProvider -x "^ref(_mut)?\$ >" --category Rust type summary add -F lldb_lookup.StdSliceSummaryProvider -e -x -h "^ref(_mut)?\$ >" --category Rust + # OsString -type synthetic add -l lldb_lookup.synthetic_lookup -x "^(std::ffi::([a-z_]+::)+)OsString$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^(std::ffi::([a-z_]+::)+)OsString$" --category Rust +type summary add -F lldb_lookup.StdOsStringSummaryProvider -e -x -h "^(std::ffi::([a-z_]+::)+)OsString$" --category Rust + # Vec -type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)Vec<.+>$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)Vec<.+>$" --category Rust +type synthetic add -l lldb_lookup.StdVecSyntheticProvider -x "^(alloc::([a-z_]+::)+)Vec<.+>$" --category Rust +type summary add -F lldb_lookup.SizeSummaryProvider -e -x -h "^(alloc::([a-z_]+::)+)Vec<.+>$" --category Rust + # VecDeque -type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)VecDeque<.+>$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)VecDeque<.+>$" --category Rust -# BTreeSet -type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)BTreeSet<.+>$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)BTreeSet<.+>$" --category Rust -# BTreeMap -type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)BTreeMap<.+>$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)BTreeMap<.+>$" --category Rust +type synthetic add -l lldb_lookup.StdVecDequeSyntheticProvider -x "^(alloc::([a-z_]+::)+)VecDeque<.+>$" --category Rust +type summary add -F lldb_lookup.SizeSummaryProvider -e -x -h "^(alloc::([a-z_]+::)+)VecDeque<.+>$" --category Rust + # HashMap -type synthetic add -l lldb_lookup.synthetic_lookup -x "^(std::collections::([a-z_]+::)+)HashMap<.+>$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^(std::collections::([a-z_]+::)+)HashMap<.+>$" --category Rust +type synthetic add -l lldb_lookup.classify_hashmap -x "^(std::collections::([a-z_]+::)+)HashMap<.+>$" --category Rust +type summary add -F lldb_lookup.SizeSummaryProvider -e -x -h "^(std::collections::([a-z_]+::)+)HashMap<.+>$" --category Rust + # HashSet -type synthetic add -l lldb_lookup.synthetic_lookup -x "^(std::collections::([a-z_]+::)+)HashSet<.+>$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^(std::collections::([a-z_]+::)+)HashSet<.+>$" --category Rust +type synthetic add -l lldb_lookup.classify_hashset -x "^(std::collections::([a-z_]+::)+)HashSet<.+>$" --category Rust +type summary add -F lldb_lookup.SizeSummaryProvider -e -x -h "^(std::collections::([a-z_]+::)+)HashSet<.+>$" --category Rust + # Rc -type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)Rc<.+>$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)Rc<.+>$" --category Rust +type synthetic add -l lldb_lookup.StdRcSyntheticProvider -x "^(alloc::([a-z_]+::)+)Rc<.+>$" --category Rust +type summary add -F lldb_lookup.StdRcSummaryProvider -e -x -h "^(alloc::([a-z_]+::)+)Rc<.+>$" --category Rust + # Arc -type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)Arc<.+>$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)Arc<.+>$" --category Rust +type synthetic add -l lldb_lookup.arc_synthetic -x "^(alloc::([a-z_]+::)+)Arc<.+>$" --category Rust +type summary add -F lldb_lookup.StdRcSummaryProvider -e -x -h "^(alloc::([a-z_]+::)+)Arc<.+>$" --category Rust + # Cell -type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)Cell<.+>$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)Cell<.+>$" --category Rust +type synthetic add -l lldb_lookup.StdCellSyntheticProvider -x "^(core::([a-z_]+::)+)Cell<.+>$" --category Rust + # RefCell -type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)Ref<.+>$" --category Rust -type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)RefMut<.+>$" --category Rust -type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)RefCell<.+>$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)Ref<.+>$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)RefMut<.+>$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)RefCell<.+>$" --category Rust +type synthetic add -l lldb_lookup.StdRefSyntheticProvider -x "^(core::([a-z_]+::)+)Ref(Cell|Mut)?<.+>$" --category Rust +type summary add -F lldb_lookup.StdRefSummaryProvider -e -x -h "^(core::([a-z_]+::)+)Ref(Cell|Mut)?<.+>$" --category Rust + # NonZero -type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)NonZero<.+>$" --category Rust -type synthetic add -l lldb_lookup.synthetic_lookup -x "^core::num::([a-z_]+::)*NonZero.+$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)NonZero<.+>$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^core::num::([a-z_]+::)*NonZero.+$" --category Rust +type summary add -F lldb_lookup.StdNonZeroNumberSummaryProvider -e -x -h "^(core::([a-z_]+::)+)NonZero(<.+>|I\d{0,3}|U\d{0,3})$" --category Rust + # PathBuf -type synthetic add -l lldb_lookup.synthetic_lookup -x "^(std::([a-z_]+::)+)PathBuf$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^(std::([a-z_]+::)+)PathBuf$" --category Rust +type summary add -F lldb_lookup.StdPathBufSummaryProvider -e -x -h "^(std::([a-z_]+::)+)PathBuf$" --category Rust + # Path -type synthetic add -l lldb_lookup.synthetic_lookup -x "^&(mut )?(std::([a-z_]+::)+)Path$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^&(mut )?(std::([a-z_]+::)+)Path$" --category Rust +type summary add -F lldb_lookup.StdPathSummaryProvider -e -x -h "^&(mut )?(std::([a-z_]+::)+)Path$" --category Rust + # Enum ## MSVC type synthetic add -l lldb_lookup.MSVCEnumSyntheticProvider -x "^enum2\$<.+>$" --category Rust type summary add -F lldb_lookup.MSVCEnumSummaryProvider -e -x -h "^enum2\$<.+>$" --category Rust + ## MSVC Variants type synthetic add -l lldb_lookup.synthetic_lookup -x "^enum2\$<.+>::.*$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^enum2\$<.+>::.*$" --category Rust + # Tuple -type synthetic add -l lldb_lookup.synthetic_lookup -x "^\(.*\)$" --category Rust +type synthetic add -l lldb_lookup.TupleSyntheticProvider -x "^\(.*\)$" --category Rust + ## MSVC type synthetic add -l lldb_lookup.MSVCTupleSyntheticProvider -x "^tuple\$<.+>$" --category Rust type summary add -F lldb_lookup.TupleSummaryProvider -e -x -h "^tuple\$<.+>$" --category Rust + type category enable Rust diff --git a/src/etc/lldb_lookup.py b/src/etc/lldb_lookup.py index 3c10e4a4d2b4e..e0d1a258200ea 100644 --- a/src/etc/lldb_lookup.py +++ b/src/etc/lldb_lookup.py @@ -1,10 +1,35 @@ from __future__ import annotations -from typing import Dict +from typing import List + import lldb from lldb_providers import * -from rust_types import RustType, classify_struct, classify_union +from rust_types import ( + ENUM_DISR_FIELD_NAME, + ENUM_LLDB_ENCODED_VARIANTS, + RustType, + classify_union, + is_tuple_fields, +) + +#################################################################################################### +# This file contains lookup functions that associate rust types with their synthetic/summary +# providers. +# +# LLDB caches the results of the the commands in `lldb_commands`, but that caching is "shallow". It +# purely associates the type with the function given, whether it is a regular function or a class +# constructor. If the function makes decisions about what type of SyntheticProvider to return, that +# processing is done **each time a value of that type is encountered**. +# +# To reiterate, inspecting a `vec![T; 100_000]` will call `T`'s lookup function/constructor 100,000 +# times. This can lead to significant delays in value visualization if the lookup logic is complex. +# +# As such, lookup functions should be kept as minimal as possible. LLDB technically expects a +# SyntheticProvider class constructor. If you can provide just a class constructor, that should be +# preferred. If extra processing must be done, try to keep it as minimal and as targeted as possible +# (see: `classify_hashmap()` vs `classify_hashset()`). +#################################################################################################### # BACKCOMPAT: rust 1.35 @@ -12,70 +37,64 @@ def is_hashbrown_hashmap(hash_map: lldb.SBValue) -> bool: return len(hash_map.type.fields) == 1 -def classify_rust_type(type: lldb.SBType) -> RustType: - if type.IsPointerType(): - type = type.GetPointeeType() - - type_class = type.GetTypeClass() - if type_class == lldb.eTypeClassStruct: - return classify_struct(type.name, type.fields) - if type_class == lldb.eTypeClassUnion: - return classify_union(type.fields) +def classify_hashmap(valobj: lldb.SBValue, _dict: LLDBOpaque) -> object: + if is_hashbrown_hashmap(valobj): + return StdHashMapSyntheticProvider(valobj, _dict) + else: + return StdOldHashMapSyntheticProvider(valobj, _dict) - return RustType.Other +def classify_hashset(valobj: lldb.SBValue, _dict: LLDBOpaque) -> object: + hash_map = valobj.GetChildAtIndex(0) + if is_hashbrown_hashmap(hash_map): + return StdHashMapSyntheticProvider(valobj, _dict, show_values=False) + else: + return StdOldHashMapSyntheticProvider(hash_map, _dict, show_values=False) -def summary_lookup(valobj: lldb.SBValue, _dict: LLDBOpaque) -> str: - """Returns the summary provider for the given value""" - rust_type = classify_rust_type(valobj.GetType()) - if rust_type == RustType.StdString: - return StdStringSummaryProvider(valobj, _dict) - if rust_type == RustType.StdOsString: - return StdOsStringSummaryProvider(valobj, _dict) - if rust_type == RustType.StdStr: - return StdStrSummaryProvider(valobj, _dict) +def arc_synthetic(valobj: lldb.SBValue, _dict: LLDBOpaque) -> object: + return StdRcSyntheticProvider(valobj, _dict, is_atomic=True) - if rust_type == RustType.StdVec: - return SizeSummaryProvider(valobj, _dict) - if rust_type == RustType.StdVecDeque: - return SizeSummaryProvider(valobj, _dict) - if rust_type == RustType.StdSlice: - return SizeSummaryProvider(valobj, _dict) - if rust_type == RustType.StdHashMap: - return SizeSummaryProvider(valobj, _dict) - if rust_type == RustType.StdHashSet: - return SizeSummaryProvider(valobj, _dict) +def classify_rust_type(type: lldb.SBType, is_msvc: bool) -> RustType: + if type.IsPointerType(): + return RustType.Indirection - if rust_type == RustType.StdRc: - return StdRcSummaryProvider(valobj, _dict) - if rust_type == RustType.StdArc: - return StdRcSummaryProvider(valobj, _dict) + # there is a bit of code duplication here because we don't want to check all of the standard + # library regexes since LLDB handles that for us + type_class = type.GetTypeClass() + if type_class == lldb.eTypeClassStruct: + fields: List[lldb.SBTypeMember] = type.fields + if len(fields) == 0: + return RustType.Empty - if rust_type == RustType.StdRef: - return StdRefSummaryProvider(valobj, _dict) - if rust_type == RustType.StdRefMut: - return StdRefSummaryProvider(valobj, _dict) - if rust_type == RustType.StdRefCell: - return StdRefSummaryProvider(valobj, _dict) + # <> is emitted by GDB while LLDB(18.1+) emits "$variants$" + if ( + fields[0].name == ENUM_DISR_FIELD_NAME + or fields[0].name == ENUM_LLDB_ENCODED_VARIANTS + ): + return RustType.Enum - if rust_type == RustType.StdNonZeroNumber: - return StdNonZeroNumberSummaryProvider(valobj, _dict) + if is_tuple_fields(fields): + return RustType.Tuple - if rust_type == RustType.StdPathBuf: - return StdPathBufSummaryProvider(valobj, _dict) - if rust_type == RustType.StdPath: - return StdPathSummaryProvider(valobj, _dict) + return RustType.Struct + if type_class == lldb.eTypeClassUnion: + # If we're debugging msvc, sum-type enums should have been caught by the regex in lldb + # commands since they all start with "enum2$<" + if is_msvc: + return RustType.Union + return classify_union(type.fields) - return "" + return RustType.Other def synthetic_lookup(valobj: lldb.SBValue, _dict: LLDBOpaque) -> object: """Returns the synthetic provider for the given value""" - rust_type = classify_rust_type(valobj.GetType()) + is_msvc = valobj.GetTarget().GetTriple().endswith("msvc") + rust_type = classify_rust_type(valobj.GetType(), is_msvc) - if rust_type == RustType.Struct: + if rust_type == RustType.Struct or rust_type == RustType.Union: return StructSyntheticProvider(valobj, _dict) if rust_type == RustType.StructVariant: return StructSyntheticProvider(valobj, _dict, is_variant=True) @@ -92,37 +111,7 @@ def synthetic_lookup(valobj: lldb.SBValue, _dict: LLDBOpaque) -> object: return synthetic_lookup(valobj.GetChildAtIndex(0), _dict) if rust_type == RustType.Enum: return ClangEncodedEnumProvider(valobj, _dict) - if rust_type == RustType.StdVec: - return StdVecSyntheticProvider(valobj, _dict) - if rust_type == RustType.StdVecDeque: - return StdVecDequeSyntheticProvider(valobj, _dict) - if rust_type == RustType.StdSlice or rust_type == RustType.StdStr: - return StdSliceSyntheticProvider(valobj, _dict) - - if rust_type == RustType.StdHashMap: - if is_hashbrown_hashmap(valobj): - return StdHashMapSyntheticProvider(valobj, _dict) - else: - return StdOldHashMapSyntheticProvider(valobj, _dict) - if rust_type == RustType.StdHashSet: - hash_map = valobj.GetChildAtIndex(0) - if is_hashbrown_hashmap(hash_map): - return StdHashMapSyntheticProvider(valobj, _dict, show_values=False) - else: - return StdOldHashMapSyntheticProvider(hash_map, _dict, show_values=False) - - if rust_type == RustType.StdRc: - return StdRcSyntheticProvider(valobj, _dict) - if rust_type == RustType.StdArc: - return StdRcSyntheticProvider(valobj, _dict, is_atomic=True) - - if rust_type == RustType.StdCell: - return StdCellSyntheticProvider(valobj, _dict) - if rust_type == RustType.StdRef: - return StdRefSyntheticProvider(valobj, _dict) - if rust_type == RustType.StdRefMut: - return StdRefSyntheticProvider(valobj, _dict) - if rust_type == RustType.StdRefCell: - return StdRefSyntheticProvider(valobj, _dict, is_cell=True) + if rust_type == RustType.Indirection: + return IndirectionSyntheticProvider(valobj, _dict) return DefaultSyntheticProvider(valobj, _dict) diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py index 4024386b77e34..3b291f3056148 100644 --- a/src/etc/lldb_providers.py +++ b/src/etc/lldb_providers.py @@ -93,11 +93,14 @@ def __init__(self, valobj: SBValue, _dict: LLDBOpaque): # logger = Logger.Logger() # logger >> "Default synthetic provider for " + str(valobj.GetName()) self.valobj = valobj + self.is_ptr = valobj.GetType().IsPointerType() def num_children(self) -> int: return self.valobj.GetNumChildren() def get_child_index(self, name: str) -> int: + if self.is_ptr and name == "$$dereference$$": + return self.valobj.Dereference().GetSyntheticValue() return self.valobj.GetIndexOfChildWithName(name) def get_child_at_index(self, index: int) -> SBValue: @@ -109,6 +112,36 @@ def update(self): def has_children(self) -> bool: return self.valobj.MightHaveChildren() + def get_value(self): + return self.valobj.value + + +class IndirectionSyntheticProvider: + def __init__(self, valobj: SBValue, _dict: LLDBOpaque): + self.valobj = valobj + + def num_children(self) -> int: + return 1 + + def get_child_index(self, name: str) -> int: + if self.is_ptr and name == "$$dereference$$": + return 0 + return -1 + + def get_child_at_index(self, index: int) -> SBValue: + if index == 0: + return self.valobj.Dereference().GetSyntheticValue() + return None + + def update(self): + pass + + def has_children(self) -> bool: + return True + + def get_value(self): + return self.valobj.value + class EmptySyntheticProvider: def __init__(self, valobj: SBValue, _dict: LLDBOpaque): diff --git a/src/etc/rust_types.py b/src/etc/rust_types.py index 926f4b42956ee..1ed68458ae3a5 100644 --- a/src/etc/rust_types.py +++ b/src/etc/rust_types.py @@ -15,27 +15,28 @@ class RustType(Enum): SingletonEnum = 8 RegularEnum = 9 CompressedEnum = 10 - RegularUnion = 11 - - StdString = 12 - StdOsString = 13 - StdStr = 14 - StdSlice = 15 - StdVec = 16 - StdVecDeque = 17 - StdBTreeSet = 18 - StdBTreeMap = 19 - StdHashMap = 20 - StdHashSet = 21 - StdRc = 22 - StdArc = 23 - StdCell = 24 - StdRef = 25 - StdRefMut = 26 - StdRefCell = 27 - StdNonZeroNumber = 28 - StdPath = 29 - StdPathBuf = 30 + Union = 11 + Indirection = 12 + + StdString = 13 + StdOsString = 14 + StdStr = 15 + StdSlice = 16 + StdVec = 17 + StdVecDeque = 18 + StdBTreeSet = 19 + StdBTreeMap = 20 + StdHashMap = 21 + StdHashSet = 22 + StdRc = 23 + StdArc = 24 + StdCell = 25 + StdRef = 26 + StdRefMut = 27 + StdRefCell = 28 + StdNonZeroNumber = 29 + StdPath = 30 + StdPathBuf = 31 STD_STRING_REGEX = re.compile(r"^(alloc::([a-z_]+::)+)String$")