1
1
from __future__ import annotations
2
2
import re
3
3
import sys
4
- from typing import List , TYPE_CHECKING
4
+ from typing import List , TYPE_CHECKING , Generator
5
5
6
6
from lldb import (
7
7
SBData ,
13
13
)
14
14
15
15
if TYPE_CHECKING :
16
- from lldb import SBValue , SBType , SBTypeStaticField
16
+ from lldb import SBValue , SBType , SBTypeStaticField , SBTarget
17
17
18
18
# from lldb.formatters import Logger
19
19
@@ -133,19 +133,18 @@ def has_children(self) -> bool:
133
133
return False
134
134
135
135
136
- def get_template_args (type_name : str ) -> list [str ]:
136
+ def get_template_args (type_name : str ) -> Generator [str , None , None ]:
137
137
"""
138
138
Takes a type name `T<A, tuple$<B, C>, D>` and returns a list of its generic args
139
139
`["A", "tuple$<B, C>", "D"]`.
140
140
141
141
String-based replacement for LLDB's `SBType.template_args`, as LLDB is currently unable to
142
142
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>`).
144
144
145
145
Each element of the returned list can be looked up for its `SBType` value via
146
146
`SBTarget.FindFirstType()`
147
147
"""
148
- params = []
149
148
level = 0
150
149
start = 0
151
150
for i , c in enumerate (type_name ):
@@ -156,11 +155,55 @@ def get_template_args(type_name: str) -> list[str]:
156
155
elif c == ">" :
157
156
level -= 1
158
157
if level == 0 :
159
- params . append ( type_name [start :i ].strip () )
158
+ yield type_name [start :i ].strip ()
160
159
elif c == "," and level == 1 :
161
- params . append ( type_name [start :i ].strip () )
160
+ yield type_name [start :i ].strip ()
162
161
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
164
207
165
208
166
209
def SizeSummaryProvider (valobj : SBValue , _dict : LLDBOpaque ) -> str :
@@ -808,6 +851,7 @@ def __init__(self, valobj: SBValue, _dict: LLDBOpaque):
808
851
# logger = Logger.Logger()
809
852
# logger >> "[StdVecSyntheticProvider] for " + str(valobj.GetName())
810
853
self .valobj = valobj
854
+ self .element_type = None
811
855
self .update ()
812
856
813
857
def num_children (self ) -> int :
@@ -841,8 +885,9 @@ def update(self):
841
885
self .element_type = self .valobj .GetType ().GetTemplateArgumentType (0 )
842
886
843
887
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 )
846
891
847
892
self .element_type_size = self .element_type .GetByteSize ()
848
893
@@ -918,6 +963,7 @@ def __init__(self, valobj: SBValue, _dict: LLDBOpaque):
918
963
# logger = Logger.Logger()
919
964
# logger >> "[StdVecDequeSyntheticProvider] for " + str(valobj.GetName())
920
965
self .valobj = valobj
966
+ self .element_type = None
921
967
self .update ()
922
968
923
969
def num_children (self ) -> int :
@@ -954,6 +1000,12 @@ def update(self):
954
1000
)
955
1001
956
1002
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
+
957
1009
self .element_type_size = self .element_type .GetByteSize ()
958
1010
959
1011
def has_children (self ) -> bool :
@@ -1081,6 +1133,7 @@ def get_child_at_index(self, index: int) -> SBValue:
1081
1133
element = self .data_ptr .CreateValueFromAddress (
1082
1134
"[%s]" % index , address , self .pair_type
1083
1135
)
1136
+
1084
1137
if self .show_values :
1085
1138
return element
1086
1139
else :
@@ -1100,14 +1153,12 @@ def update(self):
1100
1153
1101
1154
self .size = inner_table .GetChildMemberWithName ("items" ).GetValueAsUnsigned ()
1102
1155
1103
- template_args = table .type . template_args
1156
+ self . pair_type = table .GetType (). GetTemplateArgumentType ( 0 )
1104
1157
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 )
1111
1162
1112
1163
if self .pair_type .IsTypedefType ():
1113
1164
self .pair_type = self .pair_type .GetTypedefedType ()
0 commit comments