Skip to content

Commit 58c5266

Browse files
committed
use direct providers when possible
1 parent 1dce926 commit 58c5266

File tree

4 files changed

+176
-149
lines changed

4 files changed

+176
-149
lines changed

src/etc/lldb_commands

Lines changed: 50 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,85 @@
1+
# LLDB iterates through these in reverse order to discover summaries/synthetics that means the top
2+
# of the list can be "overwritten" by items lower on the list. Be careful when reordering items.
3+
14
# Forces test-compliant formatting to all other types
25
type synthetic add -l lldb_lookup.synthetic_lookup -x ".*" --category Rust
36
# Std String
47
type synthetic add -l lldb_lookup.StdStringSyntheticProvider -x "^(alloc::([a-z_]+::)+)String$" --category Rust
5-
type summary add -F lldb_lookup.StdStringSummaryProvider -e -x -h "^(alloc::([a-z_]+::)+)String$" --category Rust
8+
type summary add -F lldb_lookup.StdStringSummaryProvider -e -x -h "^(alloc::([a-z_]+::)+)String$" --category Rust
9+
610
# Std str
7-
type synthetic add -l lldb_lookup.synthetic_lookup -x "^&(mut )?str$" --category Rust
8-
type summary add -F lldb_lookup.summary_lookup -e -x -h "^&(mut )?str$" --category Rust
11+
type synthetic add -l lldb_lookup.StdSliceSyntheticProvider -x "^&(mut )?str$" --category Rust
12+
type summary add -F lldb_lookup.StdStrSummaryProvider -e -x -h "^&(mut )?str$" --category Rust
13+
914
## MSVC
1015
type synthetic add -l lldb_lookup.MSVCStrSyntheticProvider -x "^ref(_mut)?\$<str\$>$" --category Rust
1116
type summary add -F lldb_lookup.StdStrSummaryProvider -e -h -x "^ref(_mut)?\$<str\$>$" --category Rust
12-
# Array
13-
type synthetic add -l lldb_lookup.synthetic_lookup -x "^&(mut )?\\[.+\\]$" --category Rust
14-
type summary add -F lldb_lookup.summary_lookup -e -x -h "^&(mut )?\\[.+\\]$" --category Rust
15-
# Slice
17+
18+
# Array/Slice
19+
type synthetic add -l lldb_lookup.StdSliceSyntheticProvider -x "^&(mut )?\\[.+\\]$" --category Rust
20+
type summary add -F lldb_lookup.SizeSummaryProvider -e -x -h "^&(mut )?\\[.+\\]$" --category Rust
21+
1622
## MSVC
1723
type synthetic add -l lldb_lookup.MSVCStdSliceSyntheticProvider -x "^ref(_mut)?\$<slice2\$<.+> >" --category Rust
1824
type summary add -F lldb_lookup.StdSliceSummaryProvider -e -x -h "^ref(_mut)?\$<slice2\$<.+> >" --category Rust
25+
1926
# OsString
20-
type synthetic add -l lldb_lookup.synthetic_lookup -x "^(std::ffi::([a-z_]+::)+)OsString$" --category Rust
21-
type summary add -F lldb_lookup.summary_lookup -e -x -h "^(std::ffi::([a-z_]+::)+)OsString$" --category Rust
27+
type summary add -F lldb_lookup.StdOsStringSummaryProvider -e -x -h "^(std::ffi::([a-z_]+::)+)OsString$" --category Rust
28+
2229
# Vec
23-
type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)Vec<.+>$" --category Rust
24-
type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)Vec<.+>$" --category Rust
30+
type synthetic add -l lldb_lookup.StdVecSyntheticProvider -x "^(alloc::([a-z_]+::)+)Vec<.+>$" --category Rust
31+
type summary add -F lldb_lookup.SizeSummaryProvider -e -x -h "^(alloc::([a-z_]+::)+)Vec<.+>$" --category Rust
32+
2533
# VecDeque
26-
type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)VecDeque<.+>$" --category Rust
27-
type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)VecDeque<.+>$" --category Rust
28-
# BTreeSet
29-
type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)BTreeSet<.+>$" --category Rust
30-
type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)BTreeSet<.+>$" --category Rust
31-
# BTreeMap
32-
type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)BTreeMap<.+>$" --category Rust
33-
type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)BTreeMap<.+>$" --category Rust
34+
type synthetic add -l lldb_lookup.StdVecDequeSyntheticProvider -x "^(alloc::([a-z_]+::)+)VecDeque<.+>$" --category Rust
35+
type summary add -F lldb_lookup.SizeSummaryProvider -e -x -h "^(alloc::([a-z_]+::)+)VecDeque<.+>$" --category Rust
36+
3437
# HashMap
35-
type synthetic add -l lldb_lookup.synthetic_lookup -x "^(std::collections::([a-z_]+::)+)HashMap<.+>$" --category Rust
36-
type summary add -F lldb_lookup.summary_lookup -e -x -h "^(std::collections::([a-z_]+::)+)HashMap<.+>$" --category Rust
38+
type synthetic add -l lldb_lookup.classify_hashmap -x "^(std::collections::([a-z_]+::)+)HashMap<.+>$" --category Rust
39+
type summary add -F lldb_lookup.SizeSummaryProvider -e -x -h "^(std::collections::([a-z_]+::)+)HashMap<.+>$" --category Rust
40+
3741
# HashSet
38-
type synthetic add -l lldb_lookup.synthetic_lookup -x "^(std::collections::([a-z_]+::)+)HashSet<.+>$" --category Rust
39-
type summary add -F lldb_lookup.summary_lookup -e -x -h "^(std::collections::([a-z_]+::)+)HashSet<.+>$" --category Rust
42+
type synthetic add -l lldb_lookup.classify_hashset -x "^(std::collections::([a-z_]+::)+)HashSet<.+>$" --category Rust
43+
type summary add -F lldb_lookup.SizeSummaryProvider -e -x -h "^(std::collections::([a-z_]+::)+)HashSet<.+>$" --category Rust
44+
4045
# Rc
41-
type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)Rc<.+>$" --category Rust
42-
type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)Rc<.+>$" --category Rust
46+
type synthetic add -l lldb_lookup.StdRcSyntheticProvider -x "^(alloc::([a-z_]+::)+)Rc<.+>$" --category Rust
47+
type summary add -F lldb_lookup.StdRcSummaryProvider -e -x -h "^(alloc::([a-z_]+::)+)Rc<.+>$" --category Rust
48+
4349
# Arc
44-
type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)Arc<.+>$" --category Rust
45-
type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)Arc<.+>$" --category Rust
50+
type synthetic add -l lldb_lookup.arc_synthetic -x "^(alloc::([a-z_]+::)+)Arc<.+>$" --category Rust
51+
type summary add -F lldb_lookup.StdRcSummaryProvider -e -x -h "^(alloc::([a-z_]+::)+)Arc<.+>$" --category Rust
52+
4653
# Cell
47-
type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)Cell<.+>$" --category Rust
48-
type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)Cell<.+>$" --category Rust
54+
type synthetic add -l lldb_lookup.StdCellSyntheticProvider -x "^(core::([a-z_]+::)+)Cell<.+>$" --category Rust
55+
4956
# RefCell
50-
type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)Ref<.+>$" --category Rust
51-
type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)RefMut<.+>$" --category Rust
52-
type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)RefCell<.+>$" --category Rust
53-
type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)Ref<.+>$" --category Rust
54-
type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)RefMut<.+>$" --category Rust
55-
type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)RefCell<.+>$" --category Rust
57+
type synthetic add -l lldb_lookup.StdRefSyntheticProvider -x "^(core::([a-z_]+::)+)Ref(Cell|Mut)?<.+>$" --category Rust
58+
type summary add -F lldb_lookup.StdRefSummaryProvider -e -x -h "^(core::([a-z_]+::)+)Ref(Cell|Mut)?<.+>$" --category Rust
59+
5660
# NonZero
57-
type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)NonZero<.+>$" --category Rust
58-
type synthetic add -l lldb_lookup.synthetic_lookup -x "^core::num::([a-z_]+::)*NonZero.+$" --category Rust
59-
type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)NonZero<.+>$" --category Rust
60-
type summary add -F lldb_lookup.summary_lookup -e -x -h "^core::num::([a-z_]+::)*NonZero.+$" --category Rust
61+
type summary add -F lldb_lookup.StdNonZeroNumberSummaryProvider -e -x -h "^(core::([a-z_]+::)+)NonZero(<.+>|I\d{0,3}|U\d{0,3})$" --category Rust
62+
6163
# PathBuf
62-
type synthetic add -l lldb_lookup.synthetic_lookup -x "^(std::([a-z_]+::)+)PathBuf$" --category Rust
63-
type summary add -F lldb_lookup.summary_lookup -e -x -h "^(std::([a-z_]+::)+)PathBuf$" --category Rust
64+
type summary add -F lldb_lookup.StdPathBufSummaryProvider -e -x -h "^(std::([a-z_]+::)+)PathBuf$" --category Rust
65+
6466
# Path
65-
type synthetic add -l lldb_lookup.synthetic_lookup -x "^&(mut )?(std::([a-z_]+::)+)Path$" --category Rust
66-
type summary add -F lldb_lookup.summary_lookup -e -x -h "^&(mut )?(std::([a-z_]+::)+)Path$" --category Rust
67+
type summary add -F lldb_lookup.StdPathSummaryProvider -e -x -h "^&(mut )?(std::([a-z_]+::)+)Path$" --category Rust
68+
6769
# Enum
6870
# type summary add -F lldb_lookup.ClangEncodedEnumSummaryProvider -e -h "lldb_lookup.is_sum_type_enum" --recognizer-function --category Rust
6971
## MSVC
7072
type synthetic add -l lldb_lookup.MSVCEnumSyntheticProvider -x "^enum2\$<.+>$" --category Rust
7173
type summary add -F lldb_lookup.MSVCEnumSummaryProvider -e -x -h "^enum2\$<.+>$" --category Rust
74+
7275
## MSVC Variants
7376
type synthetic add -l lldb_lookup.synthetic_lookup -x "^enum2\$<.+>::.*$" --category Rust
74-
type summary add -F lldb_lookup.summary_lookup -e -x -h "^enum2\$<.+>::.*$" --category Rust
77+
7578
# Tuple
76-
type synthetic add -l lldb_lookup.synthetic_lookup -x "^\(.*\)$" --category Rust
77-
type summary add -F lldb_lookup.TupleSummaryProvider -e -x -h "^\(.*\)$" --category Rust
79+
type synthetic add -l lldb_lookup.TupleSyntheticProvider -x "^\(.*\)$" --category Rust
80+
7881
## MSVC
7982
type synthetic add -l lldb_lookup.MSVCTupleSyntheticProvider -x "^tuple\$<.+>$" --category Rust
8083
type summary add -F lldb_lookup.TupleSummaryProvider -e -x -h "^tuple\$<.+>$" --category Rust
84+
8185
type category enable Rust

src/etc/lldb_lookup.py

Lines changed: 71 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,100 @@
11
from __future__ import annotations
2-
from typing import Dict
2+
from typing import List
3+
34

45
import lldb
56

67
from lldb_providers import *
7-
from rust_types import RustType, classify_struct, classify_union
8+
from rust_types import (
9+
ENUM_DISR_FIELD_NAME,
10+
ENUM_LLDB_ENCODED_VARIANTS,
11+
RustType,
12+
classify_union,
13+
is_tuple_fields,
14+
)
15+
16+
####################################################################################################
17+
# This file contains lookup functions that associate rust types with their synthetic/summary
18+
# providers.
19+
#
20+
# LLDB caches the results of the the commands in `lldb_commands`, but that caching is "shallow". It
21+
# purely associates the type with the function given, whether it is a regular function or a class
22+
# constructor. If the function makes decisions about what type of SyntheticProvider to return, that
23+
# processing is done **each time a value of that type is encountered**.
24+
#
25+
# To reiterate, inspecting a `vec![T; 100_000]` will call `T`'s lookup function/constructor 100,000
26+
# times. This can lead to significant delays in value visualization if the lookup logic is complex.
27+
#
28+
# As such, lookup functions should be kept as minimal as possible. LLDB technically expects a
29+
# SyntheticProvider class constructor. If you can provide just a class constructor, that should be
30+
# preferred. If extra processing must be done, try to keep it as minimal and as targeted as possible
31+
# (see: `classify_hashmap()` vs `classify_hashset()`).
32+
####################################################################################################
833

934

1035
# BACKCOMPAT: rust 1.35
1136
def is_hashbrown_hashmap(hash_map: lldb.SBValue) -> bool:
1237
return len(hash_map.type.fields) == 1
1338

1439

15-
def classify_rust_type(type: lldb.SBType) -> RustType:
16-
if type.IsPointerType():
17-
type = type.GetPointeeType()
18-
19-
type_class = type.GetTypeClass()
20-
if type_class == lldb.eTypeClassStruct:
21-
return classify_struct(type.name, type.fields)
22-
if type_class == lldb.eTypeClassUnion:
23-
return classify_union(type.fields)
40+
def classify_hashmap(valobj: lldb.SBValue, _dict: LLDBOpaque) -> object:
41+
if is_hashbrown_hashmap(valobj):
42+
return StdHashMapSyntheticProvider(valobj, _dict)
43+
else:
44+
return StdOldHashMapSyntheticProvider(valobj, _dict)
2445

25-
return RustType.Other
2646

47+
def classify_hashset(valobj: lldb.SBValue, _dict: LLDBOpaque) -> object:
48+
hash_map = valobj.GetChildAtIndex(0)
49+
if is_hashbrown_hashmap(hash_map):
50+
return StdHashMapSyntheticProvider(valobj, _dict, show_values=False)
51+
else:
52+
return StdOldHashMapSyntheticProvider(hash_map, _dict, show_values=False)
2753

28-
def summary_lookup(valobj: lldb.SBValue, _dict: LLDBOpaque) -> str:
29-
"""Returns the summary provider for the given value"""
30-
rust_type = classify_rust_type(valobj.GetType())
3154

32-
if rust_type == RustType.StdString:
33-
return StdStringSummaryProvider(valobj, _dict)
34-
if rust_type == RustType.StdOsString:
35-
return StdOsStringSummaryProvider(valobj, _dict)
36-
if rust_type == RustType.StdStr:
37-
return StdStrSummaryProvider(valobj, _dict)
55+
def arc_synthetic(valobj: lldb.SBValue, _dict: LLDBOpaque) -> object:
56+
return StdRcSyntheticProvider(valobj, _dict, is_atomic=True)
3857

39-
if rust_type == RustType.StdVec:
40-
return SizeSummaryProvider(valobj, _dict)
41-
if rust_type == RustType.StdVecDeque:
42-
return SizeSummaryProvider(valobj, _dict)
43-
if rust_type == RustType.StdSlice:
44-
return SizeSummaryProvider(valobj, _dict)
4558

46-
if rust_type == RustType.StdHashMap:
47-
return SizeSummaryProvider(valobj, _dict)
48-
if rust_type == RustType.StdHashSet:
49-
return SizeSummaryProvider(valobj, _dict)
59+
def classify_rust_type(type: lldb.SBType, is_msvc: bool) -> RustType:
60+
if type.IsPointerType():
61+
return RustType.Indirection
5062

51-
if rust_type == RustType.StdRc:
52-
return StdRcSummaryProvider(valobj, _dict)
53-
if rust_type == RustType.StdArc:
54-
return StdRcSummaryProvider(valobj, _dict)
63+
# there is a bit of code duplication here because we don't want to check all of the standard
64+
# library regexes since LLDB handles that for us
65+
type_class = type.GetTypeClass()
66+
if type_class == lldb.eTypeClassStruct:
67+
fields: List[lldb.SBTypeMember] = type.fields
68+
if len(fields) == 0:
69+
return RustType.Empty
5570

56-
if rust_type == RustType.StdRef:
57-
return StdRefSummaryProvider(valobj, _dict)
58-
if rust_type == RustType.StdRefMut:
59-
return StdRefSummaryProvider(valobj, _dict)
60-
if rust_type == RustType.StdRefCell:
61-
return StdRefSummaryProvider(valobj, _dict)
71+
# <<variant>> is emitted by GDB while LLDB(18.1+) emits "$variants$"
72+
if (
73+
fields[0].name == ENUM_DISR_FIELD_NAME
74+
or fields[0].name == ENUM_LLDB_ENCODED_VARIANTS
75+
):
76+
return RustType.Enum
6277

63-
if rust_type == RustType.StdNonZeroNumber:
64-
return StdNonZeroNumberSummaryProvider(valobj, _dict)
78+
if is_tuple_fields(fields):
79+
return RustType.Tuple
6580

66-
if rust_type == RustType.StdPathBuf:
67-
return StdPathBufSummaryProvider(valobj, _dict)
68-
if rust_type == RustType.StdPath:
69-
return StdPathSummaryProvider(valobj, _dict)
81+
return RustType.Struct
82+
if type_class == lldb.eTypeClassUnion:
83+
# If we're debugging msvc, sum-type enums should have been caught by the regex in lldb
84+
# commands since they all start with "enum2$<"
85+
if is_msvc:
86+
return RustType.Union
87+
return classify_union(type.fields)
7088

71-
return ""
89+
return RustType.Other
7290

7391

7492
def synthetic_lookup(valobj: lldb.SBValue, _dict: LLDBOpaque) -> object:
7593
"""Returns the synthetic provider for the given value"""
76-
rust_type = classify_rust_type(valobj.GetType())
94+
is_msvc = valobj.GetTarget().GetTriple().endswith("msvc")
95+
rust_type = classify_rust_type(valobj.GetType(), is_msvc)
7796

78-
if rust_type == RustType.Struct:
97+
if rust_type == RustType.Struct or rust_type == RustType.Union:
7998
return StructSyntheticProvider(valobj, _dict)
8099
if rust_type == RustType.StructVariant:
81100
return StructSyntheticProvider(valobj, _dict, is_variant=True)
@@ -112,37 +131,7 @@ def synthetic_lookup(valobj: lldb.SBValue, _dict: LLDBOpaque) -> object:
112131
)
113132

114133
return ClangEncodedEnumProvider(valobj, _dict)
115-
if rust_type == RustType.StdVec:
116-
return StdVecSyntheticProvider(valobj, _dict)
117-
if rust_type == RustType.StdVecDeque:
118-
return StdVecDequeSyntheticProvider(valobj, _dict)
119-
if rust_type == RustType.StdSlice or rust_type == RustType.StdStr:
120-
return StdSliceSyntheticProvider(valobj, _dict)
121-
122-
if rust_type == RustType.StdHashMap:
123-
if is_hashbrown_hashmap(valobj):
124-
return StdHashMapSyntheticProvider(valobj, _dict)
125-
else:
126-
return StdOldHashMapSyntheticProvider(valobj, _dict)
127-
if rust_type == RustType.StdHashSet:
128-
hash_map = valobj.GetChildAtIndex(0)
129-
if is_hashbrown_hashmap(hash_map):
130-
return StdHashMapSyntheticProvider(valobj, _dict, show_values=False)
131-
else:
132-
return StdOldHashMapSyntheticProvider(hash_map, _dict, show_values=False)
133-
134-
if rust_type == RustType.StdRc:
135-
return StdRcSyntheticProvider(valobj, _dict)
136-
if rust_type == RustType.StdArc:
137-
return StdRcSyntheticProvider(valobj, _dict, is_atomic=True)
138-
139-
if rust_type == RustType.StdCell:
140-
return StdCellSyntheticProvider(valobj, _dict)
141-
if rust_type == RustType.StdRef:
142-
return StdRefSyntheticProvider(valobj, _dict)
143-
if rust_type == RustType.StdRefMut:
144-
return StdRefSyntheticProvider(valobj, _dict)
145-
if rust_type == RustType.StdRefCell:
146-
return StdRefSyntheticProvider(valobj, _dict, is_cell=True)
134+
if rust_type == RustType.Indirection:
135+
return IndirectionSyntheticProvider(valobj, _dict)
147136

148137
return DefaultSyntheticProvider(valobj, _dict)

src/etc/lldb_providers.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,14 @@ def __init__(self, valobj: SBValue, _dict: LLDBOpaque):
9595
# logger = Logger.Logger()
9696
# logger >> "Default synthetic provider for " + str(valobj.GetName())
9797
self.valobj = valobj
98+
self.is_ptr = valobj.GetType().IsPointerType()
9899

99100
def num_children(self) -> int:
100101
return self.valobj.GetNumChildren()
101102

102103
def get_child_index(self, name: str) -> int:
104+
if self.is_ptr and name == "$$dereference$$":
105+
return self.valobj.Dereference().GetSyntheticValue()
103106
return self.valobj.GetIndexOfChildWithName(name)
104107

105108
def get_child_at_index(self, index: int) -> SBValue:
@@ -111,6 +114,36 @@ def update(self):
111114
def has_children(self) -> bool:
112115
return self.valobj.MightHaveChildren()
113116

117+
def get_value(self):
118+
return self.valobj.value
119+
120+
121+
class IndirectionSyntheticProvider:
122+
def __init__(self, valobj: SBValue, _dict: LLDBOpaque):
123+
self.valobj = valobj
124+
125+
def num_children(self) -> int:
126+
return 1
127+
128+
def get_child_index(self, name: str) -> int:
129+
if self.is_ptr and name == "$$dereference$$":
130+
return 0
131+
return -1
132+
133+
def get_child_at_index(self, index: int) -> SBValue:
134+
if index == 0:
135+
return self.valobj.Dereference().GetSyntheticValue()
136+
return None
137+
138+
def update(self):
139+
pass
140+
141+
def has_children(self) -> bool:
142+
return True
143+
144+
def get_value(self):
145+
return self.valobj.value
146+
114147

115148
class EmptySyntheticProvider:
116149
def __init__(self, valobj: SBValue, _dict: LLDBOpaque):

0 commit comments

Comments
 (0)