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 :
@@ -815,6 +858,7 @@ def __init__(self, valobj: SBValue, _dict: LLDBOpaque):
815858 # logger = Logger.Logger()
816859 # logger >> "[StdVecSyntheticProvider] for " + str(valobj.GetName())
817860 self .valobj = valobj
861+ self .element_type = None
818862 self .update ()
819863
820864 def num_children (self ) -> int :
@@ -848,8 +892,9 @@ def update(self):
848892 self .element_type = self .valobj .GetType ().GetTemplateArgumentType (0 )
849893
850894 if not self .element_type .IsValid ():
851- element_name = get_template_args (self .valobj .GetTypeName ())[0 ]
852- self .element_type = self .valobj .target .FindFirstType (element_name )
895+ arg_name = next (get_template_args (self .valobj .GetTypeName ()))
896+
897+ self .element_type = resolve_msvc_template_arg (arg_name , self .valobj .target )
853898
854899 self .element_type_size = self .element_type .GetByteSize ()
855900
@@ -925,6 +970,7 @@ def __init__(self, valobj: SBValue, _dict: LLDBOpaque):
925970 # logger = Logger.Logger()
926971 # logger >> "[StdVecDequeSyntheticProvider] for " + str(valobj.GetName())
927972 self .valobj = valobj
973+ self .element_type = None
928974 self .update ()
929975
930976 def num_children (self ) -> int :
@@ -961,6 +1007,12 @@ def update(self):
9611007 )
9621008
9631009 self .element_type = self .valobj .GetType ().GetTemplateArgumentType (0 )
1010+
1011+ if not self .element_type .IsValid ():
1012+ arg_name = next (get_template_args (self .valobj .GetTypeName ()))
1013+
1014+ self .element_type = resolve_msvc_template_arg (arg_name , self .valobj .target )
1015+
9641016 self .element_type_size = self .element_type .GetByteSize ()
9651017
9661018 def has_children (self ) -> bool :
@@ -1088,6 +1140,7 @@ def get_child_at_index(self, index: int) -> SBValue:
10881140 element = self .data_ptr .CreateValueFromAddress (
10891141 "[%s]" % index , address , self .pair_type
10901142 )
1143+
10911144 if self .show_values :
10921145 return element
10931146 else :
@@ -1107,14 +1160,12 @@ def update(self):
11071160
11081161 self .size = inner_table .GetChildMemberWithName ("items" ).GetValueAsUnsigned ()
11091162
1110- template_args = table .type . template_args
1163+ self . pair_type = table .GetType (). GetTemplateArgumentType ( 0 )
11111164
1112- if template_args is None :
1113- type_name = table .GetTypeName ()
1114- args = get_template_args (type_name )
1115- self .pair_type = self .valobj .target .FindFirstType (args [0 ])
1116- else :
1117- self .pair_type = template_args [0 ]
1165+ if not self .pair_type .IsValid ():
1166+ arg_name = next (get_template_args (table .GetTypeName ()))
1167+
1168+ self .pair_type = resolve_msvc_template_arg (arg_name , self .valobj .target )
11181169
11191170 if self .pair_type .IsTypedefType ():
11201171 self .pair_type = self .pair_type .GetTypedefedType ()
0 commit comments