Skip to content

Commit 08543b6

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

File tree

1 file changed

+68
-16
lines changed

1 file changed

+68
-16
lines changed

src/etc/lldb_providers.py

Lines changed: 68 additions & 16 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,14 +133,14 @@ 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()`
@@ -156,11 +156,55 @@ def get_template_args(type_name: str) -> list[str]:
156156
elif c == ">":
157157
level -= 1
158158
if level == 0:
159-
params.append(type_name[start:i].strip())
159+
yield type_name[start:i].strip()
160160
elif c == "," and level == 1:
161-
params.append(type_name[start:i].strip())
161+
yield type_name[start:i].strip()
162162
start = i + 1
163-
return params
163+
164+
165+
MSVC_PTR_PREFIX: List[str] = ["ref$<", "ref_mut$<", "ptr_const$<", "ptr_mut$<"]
166+
167+
168+
def resolve_msvc_template_arg(arg_name: str, target: SBTarget) -> SBType:
169+
"""
170+
RECURSIVE when arrays or references are nested (e.g. `ref$<ref$<u8> >`, `array$<ref$<u8> >`)
171+
172+
Takes the template arg's name (likely from `get_template_args`) and finds/creates its
173+
corresponding SBType.
174+
175+
For non-reference/pointer/array types this is identical to calling
176+
`target.FindFirstType(arg_name)`
177+
178+
LLDB internally interprets refs, pointers, and arrays C-style (`&u8` -> `u8 *`,
179+
`*const u8` -> `u8 *`, `[u8; 5]` -> `u8 [5]`). Looking up these names still doesn't work in the
180+
current version of LLDB, so instead the types are generated via `base_type.GetPointerType()` and
181+
`base_type.GetArrayType()`, which bypass the PDB file and ask clang directly for the type node.
182+
"""
183+
result = target.FindFirstType(arg_name)
184+
185+
if result.IsValid():
186+
return result
187+
188+
for prefix in MSVC_PTR_PREFIX:
189+
if arg_name.startswith(prefix):
190+
arg_name = arg_name[len(prefix) : -1].strip()
191+
192+
result = resolve_msvc_template_arg(arg_name, target)
193+
return result.GetPointerType()
194+
195+
if arg_name.startswith("array$<"):
196+
arg_name = arg_name[7:-1].strip()
197+
198+
template_args = get_template_args(arg_name)
199+
200+
element_name = next(template_args)
201+
length = next(template_args)
202+
203+
result = resolve_msvc_template_arg(element_name, target)
204+
205+
return result.GetArrayType(int(length))
206+
207+
return result
164208

165209

166210
def SizeSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str:
@@ -808,6 +852,7 @@ def __init__(self, valobj: SBValue, _dict: LLDBOpaque):
808852
# logger = Logger.Logger()
809853
# logger >> "[StdVecSyntheticProvider] for " + str(valobj.GetName())
810854
self.valobj = valobj
855+
self.element_type = None
811856
self.update()
812857

813858
def num_children(self) -> int:
@@ -841,8 +886,9 @@ def update(self):
841886
self.element_type = self.valobj.GetType().GetTemplateArgumentType(0)
842887

843888
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)
889+
arg_name = next(get_template_args(self.valobj.GetTypeName()))
890+
891+
self.element_type = resolve_msvc_template_arg(arg_name, self.valobj.target)
846892

847893
self.element_type_size = self.element_type.GetByteSize()
848894

@@ -918,6 +964,7 @@ def __init__(self, valobj: SBValue, _dict: LLDBOpaque):
918964
# logger = Logger.Logger()
919965
# logger >> "[StdVecDequeSyntheticProvider] for " + str(valobj.GetName())
920966
self.valobj = valobj
967+
self.element_type = None
921968
self.update()
922969

923970
def num_children(self) -> int:
@@ -954,6 +1001,12 @@ def update(self):
9541001
)
9551002

9561003
self.element_type = self.valobj.GetType().GetTemplateArgumentType(0)
1004+
1005+
if not self.element_type.IsValid():
1006+
arg_name = next(get_template_args(self.valobj.GetTypeName()))
1007+
1008+
self.element_type = resolve_msvc_template_arg(arg_name, self.valobj.target)
1009+
9571010
self.element_type_size = self.element_type.GetByteSize()
9581011

9591012
def has_children(self) -> bool:
@@ -1081,6 +1134,7 @@ def get_child_at_index(self, index: int) -> SBValue:
10811134
element = self.data_ptr.CreateValueFromAddress(
10821135
"[%s]" % index, address, self.pair_type
10831136
)
1137+
10841138
if self.show_values:
10851139
return element
10861140
else:
@@ -1100,14 +1154,12 @@ def update(self):
11001154

11011155
self.size = inner_table.GetChildMemberWithName("items").GetValueAsUnsigned()
11021156

1103-
template_args = table.type.template_args
1157+
self.pair_type = table.GetType().GetTemplateArgumentType(0)
11041158

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]
1159+
if not self.pair_type.IsValid():
1160+
arg_name = next(get_template_args(table.GetTypeName()))
1161+
1162+
self.pair_type = resolve_msvc_template_arg(arg_name, self.valobj.target)
11111163

11121164
if self.pair_type.IsTypedefType():
11131165
self.pair_type = self.pair_type.GetTypedefedType()

0 commit comments

Comments
 (0)