Skip to content

Commit 7f11b15

Browse files
authored
Merge pull request #10204 from augusto2112/dyn-res-embed
[lldb] Implement dynamic type resolution for embedded Swift classes
2 parents a301157 + 5aab3e8 commit 7f11b15

File tree

9 files changed

+201
-55
lines changed

9 files changed

+201
-55
lines changed

lldb/source/Plugins/LanguageRuntime/Swift/ReflectionContext.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,12 @@ class TargetReflectionContext : public ReflectionContextInterface {
363363
return llvm::createStringError("could not read type from metadata");
364364
}
365365

366+
std::optional<swift::remote::RemoteAbsolutePointer>
367+
ReadPointer(lldb::addr_t instance_address) override {
368+
auto ptr = m_reflection_ctx.readPointer(instance_address);
369+
return ptr;
370+
}
371+
366372
std::optional<bool> IsValueInlinedInExistentialContainer(
367373
swift::remote::RemoteAddress existential_address) override {
368374
return m_reflection_ctx.isValueInlinedInExistentialContainer(

lldb/source/Plugins/LanguageRuntime/Swift/ReflectionContextInterface.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,8 @@ class ReflectionContextInterface {
146146
ReadTypeFromInstance(lldb::addr_t instance_address,
147147
swift::reflection::DescriptorFinder *descriptor_finder,
148148
bool skip_artificial_subclasses = false) = 0;
149+
virtual std::optional<swift::remote::RemoteAbsolutePointer>
150+
ReadPointer(lldb::addr_t instance_address) = 0;
149151
virtual std::optional<bool> IsValueInlinedInExistentialContainer(
150152
swift::remote::RemoteAddress existential_address) = 0;
151153
virtual llvm::Expected<const swift::reflection::TypeRef &> ApplySubstitutions(

lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,10 @@ class SwiftLanguageRuntime : public LanguageRuntime {
624624
TypeAndOrName &class_type_or_name, Address &address,
625625
Value::ValueType &value_type, llvm::ArrayRef<uint8_t> &local_buffer);
626626

627+
/// Resolves the dynamic type of an embedded Swift class type.
628+
CompilerType GetDynamicTypeAndAddress_EmbeddedClass(uint64_t instance_ptr,
629+
CompilerType class_type);
630+
627631
/// Dynamic type resolution tends to want to generate scalar data -
628632
/// but there are caveats Per original comment here "Our address is
629633
/// the location of the dynamic type stored in memory. It isn't a

lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntimeDynamicTypeResolution.cpp

Lines changed: 132 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1962,6 +1962,41 @@ static bool IsPrivateNSClass(NodePointer node) {
19621962
return false;
19631963
}
19641964

1965+
CompilerType SwiftLanguageRuntime::GetDynamicTypeAndAddress_EmbeddedClass(
1966+
uint64_t instance_ptr, CompilerType class_type) {
1967+
ThreadSafeReflectionContext reflection_ctx = GetReflectionContext();
1968+
if (!reflection_ctx)
1969+
return {};
1970+
/// If this is an embedded Swift type, there is no metadata, and the
1971+
/// pointer points to the type's vtable. We can still resolve the type by
1972+
/// reading the vtable's symbol name.
1973+
auto pointer = reflection_ctx->ReadPointer(instance_ptr);
1974+
if (!pointer)
1975+
return {};
1976+
llvm::StringRef symbol_name;
1977+
if (pointer->isResolved()) {
1978+
// Find the symbol name at this address.
1979+
Address address;
1980+
address.SetLoadAddress(pointer->getOffset(), &GetProcess().GetTarget());
1981+
Symbol *symbol = address.CalculateSymbolContextSymbol();
1982+
if (!symbol)
1983+
return {};
1984+
Mangled mangled = symbol->GetMangled();
1985+
if (!mangled)
1986+
return {};
1987+
symbol_name = symbol->GetMangled().GetMangledName().GetStringRef();
1988+
} else {
1989+
symbol_name = pointer->getSymbol();
1990+
}
1991+
TypeSystemSwiftTypeRefSP ts = class_type.GetTypeSystem()
1992+
.dyn_cast_or_null<TypeSystemSwift>()
1993+
->GetTypeSystemSwiftTypeRef();
1994+
// The symbol name will be something like "type metadata for Class", extract
1995+
// "Class" from that name.
1996+
auto dynamic_type = ts->GetTypeFromTypeMetadataNode(symbol_name);
1997+
return dynamic_type;
1998+
}
1999+
19652000
bool SwiftLanguageRuntime::GetDynamicTypeAndAddress_Class(
19662001
ValueObject &in_value, CompilerType class_type,
19672002
lldb::DynamicValueType use_dynamic, TypeAndOrName &class_type_or_name,
@@ -2023,42 +2058,46 @@ bool SwiftLanguageRuntime::GetDynamicTypeAndAddress_Class(
20232058
if (!reflection_ctx)
20242059
return false;
20252060

2026-
const swift::reflection::TypeRef *typeref = nullptr;
2027-
{
2028-
auto typeref_or_err = reflection_ctx->ReadTypeFromInstance(
2029-
instance_ptr, ts->GetDescriptorFinder(), true);
2030-
if (typeref_or_err)
2031-
typeref = &*typeref_or_err;
2032-
else
2033-
LLDB_LOG_ERRORV(GetLog(LLDBLog::Types), typeref_or_err.takeError(),
2034-
"{0}");
2035-
}
2061+
CompilerType dynamic_type;
2062+
if (SwiftLanguageRuntime::GetManglingFlavor(
2063+
class_type.GetMangledTypeName()) ==
2064+
swift::Mangle::ManglingFlavor::Default) {
20362065

2037-
// If we couldn't find the typeref from the instance, the best we can do is
2038-
// use the static type. This is a valid use case when the binary doesn't
2039-
// contain any metadata (for example, embedded Swift).
2040-
if (!typeref) {
2041-
auto typeref_or_err = reflection_ctx->GetTypeRef(
2042-
class_type.GetMangledTypeName(), ts->GetDescriptorFinder());
2043-
if (typeref_or_err)
2044-
typeref = &*typeref_or_err;
2045-
else
2046-
LLDB_LOG_ERRORV(GetLog(LLDBLog::Types), typeref_or_err.takeError(),
2047-
"{0}");
2048-
}
2066+
const swift::reflection::TypeRef *typeref = nullptr;
2067+
{
2068+
auto typeref_or_err = reflection_ctx->ReadTypeFromInstance(
2069+
instance_ptr, ts->GetDescriptorFinder(), true);
2070+
if (typeref_or_err)
2071+
typeref = &*typeref_or_err;
2072+
else
2073+
LLDB_LOG_ERRORV(GetLog(LLDBLog::Types), typeref_or_err.takeError(),
2074+
"{0}");
2075+
}
20492076

2050-
if (!typeref) {
2051-
HEALTH_LOG("could not read typeref for type: {0} (instance_ptr = {0:x})",
2052-
class_type.GetMangledTypeName(), instance_ptr);
2053-
return false;
2054-
}
2077+
if (!typeref) {
2078+
HEALTH_LOG(
2079+
"could not read typeref for type: {0} (instance_ptr = {1:x})",
2080+
class_type.GetMangledTypeName(), instance_ptr);
2081+
return false;
2082+
}
20552083

2056-
auto flavor = SwiftLanguageRuntime::GetManglingFlavor(
2057-
class_type.GetMangledTypeName());
2084+
auto flavor = SwiftLanguageRuntime::GetManglingFlavor(
2085+
class_type.GetMangledTypeName());
2086+
2087+
swift::Demangle::Demangler dem;
2088+
swift::Demangle::NodePointer node = typeref->getDemangling(dem);
2089+
dynamic_type = ts->RemangleAsType(dem, node, flavor);
2090+
} else {
2091+
dynamic_type =
2092+
GetDynamicTypeAndAddress_EmbeddedClass(instance_ptr, class_type);
2093+
if (!dynamic_type) {
2094+
HEALTH_LOG("could not resolve dynamic type of embedded swift class: "
2095+
"{0} (instance_ptr = {1:x})",
2096+
class_type.GetMangledTypeName(), instance_ptr);
2097+
return false;
2098+
}
2099+
}
20582100

2059-
swift::Demangle::Demangler dem;
2060-
swift::Demangle::NodePointer node = typeref->getDemangling(dem);
2061-
CompilerType dynamic_type = ts->RemangleAsType(dem, node, flavor);
20622101
LLDB_LOG(log, "dynamic type of instance_ptr {0:x} is {1}", instance_ptr,
20632102
class_type.GetMangledTypeName());
20642103
class_type_or_name.SetCompilerType(dynamic_type);
@@ -2207,39 +2246,77 @@ bool SwiftLanguageRuntime::GetDynamicTypeAndAddress_Existential(
22072246
auto tr_ts = tss->GetTypeSystemSwiftTypeRef();
22082247
if (!tr_ts)
22092248
return false;
2210-
auto pair = reflection_ctx->ProjectExistentialAndUnwrapClass(
2211-
remote_existential, *existential_typeref,
2212-
tr_ts->GetDescriptorFinder());
2213-
if (use_local_buffer)
2214-
PopLocalBuffer();
2215-
2216-
if (!pair) {
2217-
if (log)
2218-
log->Printf("Runtime failed to get dynamic type of existential");
2219-
return false;
2220-
}
22212249

2222-
const swift::reflection::TypeRef *typeref;
2223-
swift::remote::RemoteAddress out_address(nullptr);
2224-
std::tie(typeref, out_address) = *pair;
2225-
auto ts = tss->GetTypeSystemSwiftTypeRef();
2226-
if (!ts)
2227-
return false;
2228-
swift::Demangle::Demangler dem;
2229-
swift::Demangle::NodePointer node = typeref->getDemangling(dem);
22302250
auto flavor = SwiftLanguageRuntime::GetManglingFlavor(
22312251
existential_type.GetMangledTypeName());
2252+
CompilerType dynamic_type;
2253+
uint64_t dynamic_address = 0;
2254+
if (flavor == swift::Mangle::ManglingFlavor::Default) {
2255+
auto pair = reflection_ctx->ProjectExistentialAndUnwrapClass(
2256+
remote_existential, *existential_typeref, tr_ts->GetDescriptorFinder());
2257+
2258+
if (!pair) {
2259+
if (log)
2260+
log->Printf("Runtime failed to get dynamic type of existential");
2261+
return false;
2262+
}
2263+
2264+
const swift::reflection::TypeRef *typeref;
2265+
swift::remote::RemoteAddress out_address(nullptr);
2266+
std::tie(typeref, out_address) = *pair;
2267+
2268+
auto ts = tss->GetTypeSystemSwiftTypeRef();
2269+
if (!ts)
2270+
return false;
2271+
swift::Demangle::Demangler dem;
2272+
swift::Demangle::NodePointer node = typeref->getDemangling(dem);
2273+
dynamic_type = ts->RemangleAsType(dem, node, flavor);
2274+
dynamic_address = out_address.getAddressData();
2275+
} else {
2276+
// In the embedded Swift case, the existential container just points to the
2277+
// instance.
2278+
auto reflection_ctx = GetReflectionContext();
2279+
if (!reflection_ctx)
2280+
return false;
2281+
auto maybe_addr_or_symbol =
2282+
reflection_ctx->ReadPointer(existential_address);
2283+
if (!maybe_addr_or_symbol)
2284+
return false;
2285+
2286+
uint64_t address = 0;
2287+
if (maybe_addr_or_symbol->isResolved()) {
2288+
address = maybe_addr_or_symbol->getOffset();
2289+
} else {
2290+
SymbolContextList sc_list;
2291+
auto &module_list = GetProcess().GetTarget().GetImages();
2292+
module_list.FindSymbolsWithNameAndType(
2293+
ConstString(maybe_addr_or_symbol->getSymbol()), eSymbolTypeAny,
2294+
sc_list);
2295+
if (sc_list.GetSize() != 1)
2296+
return false;
2297+
2298+
SymbolContext sc = sc_list[0];
2299+
Symbol *symbol = sc.symbol;
2300+
address = symbol->GetLoadAddress(&GetProcess().GetTarget());
2301+
}
2302+
2303+
dynamic_type =
2304+
GetDynamicTypeAndAddress_EmbeddedClass(address, existential_type);
2305+
if (!dynamic_type)
2306+
return false;
2307+
dynamic_address = maybe_addr_or_symbol->getOffset();
2308+
}
2309+
if (use_local_buffer)
2310+
PopLocalBuffer();
22322311

2233-
class_type_or_name.SetCompilerType(ts->RemangleAsType(dem, node, flavor));
2234-
address.SetRawAddress(out_address.getAddressData());
2312+
class_type_or_name.SetCompilerType(dynamic_type);
2313+
address.SetRawAddress(dynamic_address);
22352314

22362315
#ifndef NDEBUG
22372316
if (ModuleList::GetGlobalModuleListProperties()
22382317
.GetSwiftValidateTypeSystem()) {
22392318
auto reference_pair = GetDynamicTypeAndAddress_ExistentialRemoteAST(
22402319
in_value, existential_type, use_local_buffer, existential_address);
2241-
assert(pair.has_value() >= reference_pair.has_value() &&
2242-
"RemoteAST and runtime diverge");
22432320

22442321
if (reference_pair) {
22452322
CompilerType ref_type = std::get<CompilerType>(*reference_pair);

lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,18 @@ TypeSystemSwiftTypeRef::GetBaseName(swift::Demangle::NodePointer node) {
375375
}
376376
}
377377

378+
CompilerType TypeSystemSwiftTypeRef::GetTypeFromTypeMetadataNode(
379+
llvm::StringRef mangled_name) {
380+
Demangler dem;
381+
NodePointer node = dem.demangleSymbol(mangled_name);
382+
NodePointer type = swift_demangle::NodeAtPath(
383+
node, {Node::Kind::Global, Node::Kind::TypeMetadata, Node::Kind::Type});
384+
if (!type)
385+
return {};
386+
auto flavor = SwiftLanguageRuntime::GetManglingFlavor(mangled_name);
387+
return RemangleAsType(dem, type, flavor);
388+
}
389+
378390
TypeSP TypeSystemSwiftTypeRef::LookupClangType(StringRef name_ref) {
379391
llvm::SmallVector<CompilerContext, 2> decl_context;
380392
// Make up a decl context for non-nested types.

lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,10 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift {
401401
/// Return the base name of the topmost nominal type.
402402
static llvm::StringRef GetBaseName(swift::Demangle::NodePointer node);
403403

404+
/// Given a mangled name that mangles a "type metadata for Type", return a
405+
/// CompilerType with that Type.
406+
CompilerType GetTypeFromTypeMetadataNode(llvm::StringRef mangled_name);
407+
404408
/// Use API notes to determine the swiftified name of \p clang_decl.
405409
std::string GetSwiftName(const clang::Decl *clang_decl,
406410
TypeSystemClang &clang_typesystem) override;
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
SWIFT_SOURCES := main.swift
2+
SWIFT_EMBEDDED_MODE := 1
3+
4+
include Makefile.rules
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import lldb
2+
from lldbsuite.test.lldbtest import *
3+
from lldbsuite.test.decorators import *
4+
import lldbsuite.test.lldbutil as lldbutil
5+
6+
7+
class TestSwiftEmbeddedClassTypeResolution(TestBase):
8+
@skipUnlessDarwin
9+
@swiftTest
10+
def test(self):
11+
self.build()
12+
self.runCmd("setting set symbols.swift-enable-ast-context false")
13+
14+
target, process, thread, _ = lldbutil.run_to_source_breakpoint(
15+
self, "break here", lldb.SBFileSpec("main.swift")
16+
)
17+
self.expect('frame variable s', substrs=['a.Sub', 'a.Super', 'superField = 42', 'subField = 100'])
18+
self.expect('frame variable p', substrs=['a.Sub', 'a.Super', 'superField = 42', 'subField = 100'])
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
protocol P: AnyObject {
2+
3+
}
4+
5+
class Super: P {
6+
let superField = 42
7+
}
8+
9+
class Sub: Super {
10+
let subField = 100
11+
}
12+
13+
func f() {
14+
let s: Super = Sub()
15+
let p: P = Sub()
16+
print("break here")
17+
}
18+
19+
f()

0 commit comments

Comments
 (0)