11from __future__ import annotations
22import re
33import sys
4- from typing import List , TYPE_CHECKING
4+ from typing import List , TYPE_CHECKING , Generator
55
66from lldb import (
77 SBData ,
1313)
1414
1515if 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
166210def 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