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,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
166209def 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