Skip to content

Commit e23f9b3

Browse files
committed
add additional lookup path for ref/ptr/array template args
1 parent f957826 commit e23f9b3

File tree

1 file changed

+68
-17
lines changed

1 file changed

+68
-17
lines changed

src/etc/lldb_providers.py

Lines changed: 68 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from __future__ import annotations
22
import re
33
import sys
4-
from typing import List, TYPE_CHECKING
4+
from typing import List, TYPE_CHECKING, Generator
55

66
from lldb import (
77
SBData,
@@ -13,7 +13,7 @@
1313
)
1414

1515
if TYPE_CHECKING:
16-
from lldb import SBValue, SBType, SBTypeStaticField
16+
from lldb import SBValue, SBType, SBTypeStaticField, SBTarget
1717

1818
# from lldb.formatters import Logger
1919

@@ -133,19 +133,18 @@ def has_children(self) -> bool:
133133
return False
134134

135135

136-
def get_template_args(type_name: str) -> list[str]:
136+
def get_template_args(type_name: str) -> Generator[str, None, None]:
137137
"""
138138
Takes a type name `T<A, tuple$<B, C>, D>` and returns a list of its generic args
139139
`["A", "tuple$<B, C>", "D"]`.
140140
141141
String-based replacement for LLDB's `SBType.template_args`, as LLDB is currently unable to
142142
populate this field for targets with PDB debug info. Also useful for manually altering the type
143-
name of generics (e.g. `Vec<ref$<str$>` -> `Vec<&str>`).
143+
name of generics (e.g. `Vec<ref$<str$> >` -> `Vec<&str>`).
144144
145145
Each element of the returned list can be looked up for its `SBType` value via
146146
`SBTarget.FindFirstType()`
147147
"""
148-
params = []
149148
level = 0
150149
start = 0
151150
for i, c in enumerate(type_name):
@@ -156,11 +155,55 @@ def get_template_args(type_name: str) -> list[str]:
156155
elif c == ">":
157156
level -= 1
158157
if level == 0:
159-
params.append(type_name[start:i].strip())
158+
yield type_name[start:i].strip()
160159
elif c == "," and level == 1:
161-
params.append(type_name[start:i].strip())
160+
yield type_name[start:i].strip()
162161
start = i + 1
163-
return params
162+
163+
164+
MSVC_PTR_PREFIX: List[str] = ["ref$<", "ref_mut$<", "ptr_const$<", "ptr_mut$<"]
165+
166+
167+
def resolve_msvc_template_arg(arg_name: str, target: SBTarget) -> SBType:
168+
"""
169+
RECURSIVE when arrays or references are nested (e.g. `ref$<ref$<u8> >`, `array$<ref$<u8> >`)
170+
171+
Takes the template arg's name (likely from `get_template_args`) and finds/creates its
172+
corresponding SBType.
173+
174+
For non-reference/pointer/array types this is identical to calling
175+
`target.FindFirstType(arg_name)`
176+
177+
LLDB internally interprets refs, pointers, and arrays C-style (`&u8` -> `u8 *`,
178+
`*const u8` -> `u8 *`, `[u8; 5]` -> `u8 [5]`). Looking up these names still doesn't work in the
179+
current version of LLDB, so instead the types are generated via `base_type.GetPointerType()` and
180+
`base_type.GetArrayType()`, which bypass the PDB file and ask clang directly for the type node.
181+
"""
182+
result = target.FindFirstType(arg_name)
183+
184+
if result.IsValid():
185+
return result
186+
187+
for prefix in MSVC_PTR_PREFIX:
188+
if arg_name.startswith(prefix):
189+
arg_name = arg_name[len(prefix) : -1].strip()
190+
191+
result = resolve_msvc_template_arg(arg_name, target)
192+
return result.GetPointerType()
193+
194+
if arg_name.startswith("array$<"):
195+
arg_name = arg_name[7:-1].strip()
196+
197+
template_args = get_template_args(arg_name)
198+
199+
element_name = next(template_args)
200+
length = next(template_args)
201+
202+
result = resolve_msvc_template_arg(element_name, target)
203+
204+
return result.GetArrayType(int(length))
205+
206+
return result
164207

165208

166209
def SizeSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str:
@@ -808,6 +851,7 @@ def __init__(self, valobj: SBValue, _dict: LLDBOpaque):
808851
# logger = Logger.Logger()
809852
# logger >> "[StdVecSyntheticProvider] for " + str(valobj.GetName())
810853
self.valobj = valobj
854+
self.element_type = None
811855
self.update()
812856

813857
def num_children(self) -> int:
@@ -841,8 +885,9 @@ def update(self):
841885
self.element_type = self.valobj.GetType().GetTemplateArgumentType(0)
842886

843887
if not self.element_type.IsValid():
844-
element_name = get_template_args(self.valobj.GetTypeName())[0]
845-
self.element_type = self.valobj.target.FindFirstType(element_name)
888+
arg_name = next(get_template_args(self.valobj.GetTypeName()))
889+
890+
self.element_type = resolve_msvc_template_arg(arg_name, self.valobj.target)
846891

847892
self.element_type_size = self.element_type.GetByteSize()
848893

@@ -918,6 +963,7 @@ def __init__(self, valobj: SBValue, _dict: LLDBOpaque):
918963
# logger = Logger.Logger()
919964
# logger >> "[StdVecDequeSyntheticProvider] for " + str(valobj.GetName())
920965
self.valobj = valobj
966+
self.element_type = None
921967
self.update()
922968

923969
def num_children(self) -> int:
@@ -954,6 +1000,12 @@ def update(self):
9541000
)
9551001

9561002
self.element_type = self.valobj.GetType().GetTemplateArgumentType(0)
1003+
1004+
if not self.element_type.IsValid():
1005+
arg_name = next(get_template_args(self.valobj.GetTypeName()))
1006+
1007+
self.element_type = resolve_msvc_template_arg(arg_name, self.valobj.target)
1008+
9571009
self.element_type_size = self.element_type.GetByteSize()
9581010

9591011
def has_children(self) -> bool:
@@ -1081,6 +1133,7 @@ def get_child_at_index(self, index: int) -> SBValue:
10811133
element = self.data_ptr.CreateValueFromAddress(
10821134
"[%s]" % index, address, self.pair_type
10831135
)
1136+
10841137
if self.show_values:
10851138
return element
10861139
else:
@@ -1100,14 +1153,12 @@ def update(self):
11001153

11011154
self.size = inner_table.GetChildMemberWithName("items").GetValueAsUnsigned()
11021155

1103-
template_args = table.type.template_args
1156+
self.pair_type = table.GetType().GetTemplateArgumentType(0)
11041157

1105-
if template_args is None:
1106-
type_name = table.GetTypeName()
1107-
args = get_template_args(type_name)
1108-
self.pair_type = self.valobj.target.FindFirstType(args[0])
1109-
else:
1110-
self.pair_type = template_args[0]
1158+
if not self.pair_type.IsValid():
1159+
arg_name = next(get_template_args(table.GetTypeName()))
1160+
1161+
self.pair_type = resolve_msvc_template_arg(arg_name, self.valobj.target)
11111162

11121163
if self.pair_type.IsTypedefType():
11131164
self.pair_type = self.pair_type.GetTypedefedType()

0 commit comments

Comments
 (0)