Skip to content

Commit 2f575f3

Browse files
authored
Rollup merge of #147179 - Walnut356:template_lookup, r=Mark-Simulacrum
[DebugInfo] Fix container types failing to find template args This is a less pervasive (but also less powerful) alternative to #144394. This change *only* provides benefits to container types on MSVC. The TL;DR is that nodes that don't populate/aren't discoverable in the PDB for various reasons are given an alternate lookup path that generates the nodes by acquiring the base-type via some gross string manipulation and then asking clang for the node it wants (e.g. `"ref$<i32>"` -> `"i32"` -> `target.FindFirstType("i32").GetPointerType()` -> `i32 *`, which is a valid type for the container to use) The before/afters are the same as in the above PR's `*-msvc` LLDB screenshots. This works as a stopgap while the above PR is evaluated, but I think that PR is still a much better solution.
2 parents 0a74011 + e23f9b3 commit 2f575f3

File tree

1 file changed

+68
-17
lines changed

1 file changed

+68
-17
lines changed

src/etc/lldb_providers.py

Lines changed: 68 additions & 17 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,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

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

Comments
 (0)