Skip to content

Commit a098c18

Browse files
committed
[lldb] Resolve typealias information for assiciated types via reflection
In this testcase there is an associated type for which no debug info is generated, since there is neither function nor a variable holding on to it. However, the associated type information is stored in the Witness Table, which we can query in the runtime. rdar://140940434
1 parent 66350c2 commit a098c18

File tree

12 files changed

+345
-49
lines changed

12 files changed

+345
-49
lines changed

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

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ struct DescriptorFinderForwarder : public swift::reflection::DescriptorFinder {
8989
/// An implementation of the generic ReflectionContextInterface that
9090
/// is templatized on target pointer width and specialized to either
9191
/// 32-bit or 64-bit pointers, with and without ObjC interoperability.
92-
template <typename ReflectionContext>
92+
template <typename ReflectionContext, bool ObjCEnabled, unsigned PointerSize>
9393
class TargetReflectionContext : public ReflectionContextInterface {
9494
DescriptorFinderForwarder m_forwader;
9595
ReflectionContext m_reflection_ctx;
@@ -313,7 +313,7 @@ class TargetReflectionContext : public ReflectionContextInterface {
313313
}
314314

315315
std::optional<std::pair<const swift::reflection::TypeRef *,
316-
swift::reflection::RemoteAddress>>
316+
swift::reflection::RemoteAddress>>
317317
ProjectExistentialAndUnwrapClass(
318318
swift::reflection::RemoteAddress existential_address,
319319
const swift::reflection::TypeRef &existential_tr,
@@ -323,6 +323,19 @@ class TargetReflectionContext : public ReflectionContextInterface {
323323
existential_address, existential_tr);
324324
}
325325

326+
const swift::reflection::TypeRef *
327+
LookupTypeWitness(const std::string &MangledTypeName,
328+
const std::string &Member, StringRef Protocol) override {
329+
return m_type_converter.getBuilder().lookupTypeWitness(MangledTypeName,
330+
Member, Protocol);
331+
}
332+
swift::reflection::ConformanceCollectionResult GetAllConformances() override {
333+
swift::reflection::TypeRefBuilder &b = m_type_converter.getBuilder();
334+
if (ObjCEnabled)
335+
return b.collectAllConformances<swift::WithObjCInterop, PointerSize>();
336+
return b.collectAllConformances<swift::NoObjCInterop, PointerSize>();
337+
}
338+
326339
const swift::reflection::TypeRef *
327340
ReadTypeFromMetadata(lldb::addr_t metadata_address,
328341
swift::reflection::DescriptorFinder *descriptor_finder,
@@ -420,18 +433,22 @@ std::unique_ptr<ReflectionContextInterface>
420433
ReflectionContextInterface::CreateReflectionContext(
421434
uint8_t ptr_size, std::shared_ptr<swift::remote::MemoryReader> reader,
422435
bool ObjCInterop, SwiftMetadataCache *swift_metadata_cache) {
423-
using ReflectionContext32ObjCInterop =
424-
TargetReflectionContext<swift::reflection::ReflectionContext<
425-
swift::External<swift::WithObjCInterop<swift::RuntimeTarget<4>>>>>;
426-
using ReflectionContext32NoObjCInterop =
427-
TargetReflectionContext<swift::reflection::ReflectionContext<
428-
swift::External<swift::NoObjCInterop<swift::RuntimeTarget<4>>>>>;
429-
using ReflectionContext64ObjCInterop =
430-
TargetReflectionContext<swift::reflection::ReflectionContext<
431-
swift::External<swift::WithObjCInterop<swift::RuntimeTarget<8>>>>>;
432-
using ReflectionContext64NoObjCInterop =
433-
TargetReflectionContext<swift::reflection::ReflectionContext<
434-
swift::External<swift::NoObjCInterop<swift::RuntimeTarget<8>>>>>;
436+
using ReflectionContext32ObjCInterop = TargetReflectionContext<
437+
swift::reflection::ReflectionContext<
438+
swift::External<swift::WithObjCInterop<swift::RuntimeTarget<4>>>>,
439+
true, 4>;
440+
using ReflectionContext32NoObjCInterop = TargetReflectionContext<
441+
swift::reflection::ReflectionContext<
442+
swift::External<swift::NoObjCInterop<swift::RuntimeTarget<4>>>>,
443+
false, 4>;
444+
using ReflectionContext64ObjCInterop = TargetReflectionContext<
445+
swift::reflection::ReflectionContext<
446+
swift::External<swift::WithObjCInterop<swift::RuntimeTarget<8>>>>,
447+
true, 8>;
448+
using ReflectionContext64NoObjCInterop = TargetReflectionContext<
449+
swift::reflection::ReflectionContext<
450+
swift::External<swift::NoObjCInterop<swift::RuntimeTarget<8>>>>,
451+
false, 8>;
435452
if (ptr_size == 4) {
436453
if (ObjCInterop)
437454
return std::make_unique<ReflectionContext32ObjCInterop>(

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,11 @@ class ReflectionContextInterface {
130130
const swift::reflection::TypeRef *enum_type_ref,
131131
swift::remote::TypeInfoProvider *provider,
132132
swift::reflection::DescriptorFinder *descriptor_finder) = 0;
133+
virtual const swift::reflection::TypeRef *
134+
LookupTypeWitness(const std::string &MangledTypeName,
135+
const std::string &Member, StringRef Protocol) = 0;
136+
virtual swift::reflection::ConformanceCollectionResult
137+
GetAllConformances() = 0;
133138
virtual const swift::reflection::TypeRef *ReadTypeFromMetadata(
134139
lldb::addr_t metadata_address,
135140
swift::reflection::DescriptorFinder *descriptor_finder,

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

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "Plugins/ExpressionParser/Swift/SwiftPersistentExpressionState.h"
2020
#include "Plugins/Process/Utility/RegisterContext_x86.h"
2121
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
22+
#include "Plugins/TypeSystem/Swift/SwiftDemangle.h"
2223
#include "Utility/ARM64_DWARF_Registers.h"
2324
#include "lldb/Breakpoint/StoppointCallbackContext.h"
2425
#include "lldb/Core/Debugger.h"
@@ -282,6 +283,11 @@ class SwiftLanguageRuntimeStub {
282283
return false;
283284
}
284285

286+
CompilerType ResolveTypeAlias(CompilerType alias) {
287+
STUB_LOG();
288+
return {};
289+
}
290+
285291
void DumpTyperef(CompilerType type, TypeSystemSwiftTypeRef *module_holder,
286292
Stream *s) {
287293
STUB_LOG();
@@ -523,6 +529,36 @@ SwiftLanguageRuntimeImpl::GetSwiftMetadataCache() {
523529
return &m_swift_metadata_cache;
524530
}
525531

532+
std::vector<std::string>
533+
SwiftLanguageRuntimeImpl::GetConformances(llvm::StringRef mangled_name) {
534+
if (m_conformances.empty()) {
535+
using namespace swift::Demangle;
536+
Demangler dem;
537+
538+
ThreadSafeReflectionContext reflection_ctx = GetReflectionContext();
539+
if (!reflection_ctx)
540+
return {};
541+
542+
Progress progress("Parsing Swift conformances");
543+
swift::reflection::ConformanceCollectionResult conformances =
544+
reflection_ctx->GetAllConformances();
545+
546+
for (auto &conformance : conformances.Conformances) {
547+
auto [mod, proto] = StringRef(conformance.ProtocolName).split('.');
548+
NodePointer n =
549+
swift_demangle::CreateNominal(dem, Node::Kind::Protocol, mod, proto);
550+
auto mangling = mangleNode(n);
551+
if (!mangling.isSuccess())
552+
return {};
553+
llvm::StringRef protocol =
554+
swift::Demangle::dropSwiftManglingPrefix(mangling.result());
555+
556+
m_conformances[mangled_name].push_back(protocol.str());
557+
}
558+
}
559+
return m_conformances.lookup(mangled_name);
560+
}
561+
526562
void SwiftLanguageRuntimeImpl::SetupReflection() {
527563
LLDB_SCOPED_TIMER();
528564

@@ -943,6 +979,9 @@ void SwiftLanguageRuntimeImpl::ModulesDidLoad(const ModuleList &module_list) {
943979
// The modules will be lazily processed on the next call to
944980
// GetReflectionContext.
945981
m_modules_to_add.AppendIfNeeded(module_list);
982+
983+
// This could be done more efficiently with a better reflection API.
984+
m_conformances.clear();
946985
}
947986

948987
std::string
@@ -2399,6 +2438,11 @@ bool SwiftLanguageRuntime::IsStoredInlineInBuffer(CompilerType type) {
23992438
FORWARD(IsStoredInlineInBuffer, type);
24002439
}
24012440

2441+
llvm::Expected<CompilerType>
2442+
SwiftLanguageRuntime::ResolveTypeAlias(CompilerType alias) {
2443+
FORWARD(ResolveTypeAlias, alias);
2444+
}
2445+
24022446
std::optional<uint64_t> SwiftLanguageRuntime::GetMemberVariableOffset(
24032447
CompilerType instance_type, ValueObject *instance,
24042448
llvm::StringRef member_name, Status *error) {

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,9 @@ class SwiftLanguageRuntime : public LanguageRuntime {
329329

330330
bool IsStoredInlineInBuffer(CompilerType type) override;
331331

332+
/// Check if this type alias is listed in any witness tables and resolve it.
333+
llvm::Expected<CompilerType> ResolveTypeAlias(CompilerType alias);
334+
332335
/// Retrieve the offset of the named member variable within an instance
333336
/// of the given type.
334337
///

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

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ class LLDBTypeInfoProvider : public swift::remote::TypeInfoProvider {
318318
auto *node = dem.demangleSymbol(wrapped);
319319
if (!node) {
320320
// Try `mangledName` as plain ObjC class name. Ex: NSObject, NSView, etc.
321-
auto maybeMangled = swift_demangle::mangleClass(
321+
auto maybeMangled = swift_demangle::MangleClass(
322322
dem, swift::MANGLING_MODULE_OBJC, mangledName);
323323
if (!maybeMangled.isSuccess()) {
324324
LLDB_LOG(GetLog(LLDBLog::Types),
@@ -3034,6 +3034,117 @@ bool SwiftLanguageRuntimeImpl::IsStoredInlineInBuffer(CompilerType type) {
30343034
return true;
30353035
}
30363036

3037+
llvm::Expected<CompilerType>
3038+
SwiftLanguageRuntimeImpl::ResolveTypeAlias(CompilerType alias) {
3039+
using namespace swift::Demangle;
3040+
Demangler dem;
3041+
3042+
auto tss = alias.GetTypeSystem().dyn_cast_or_null<TypeSystemSwift>();
3043+
if (!tss)
3044+
return llvm::createStringError("not a Swift type");
3045+
auto tr_ts = tss->GetTypeSystemSwiftTypeRef();
3046+
if (!tr_ts)
3047+
return llvm::createStringError("could not get typesystem");
3048+
3049+
// Extract the mangling of the alias type's parent type and its
3050+
// generic substitutions if any.
3051+
auto mangled = alias.GetMangledTypeName().GetStringRef();
3052+
NodePointer type = swift_demangle::GetDemangledType(dem, mangled);
3053+
if (!type || type->getKind() != Node::Kind::TypeAlias ||
3054+
type->getNumChildren() != 2)
3055+
return llvm::createStringError("not a type alias");
3056+
3057+
NodePointer alias_node = type->getChild(1);
3058+
if (!alias_node || alias_node->getKind() != Node::Kind::Identifier ||
3059+
!alias_node->hasText())
3060+
return llvm::createStringError("type alias has no name");
3061+
std::string member = alias_node->getText().str();
3062+
3063+
NodePointer parent_node = type->getChild(0);
3064+
if (!parent_node)
3065+
return llvm::createStringError("top-level type alias");
3066+
NodePointer subst_node = nullptr;
3067+
3068+
switch (parent_node->getKind()) {
3069+
case Node::Kind::Class:
3070+
case Node::Kind::Structure:
3071+
case Node::Kind::Enum:
3072+
break;
3073+
// For the lookup, get the unbound type.
3074+
case Node::Kind::BoundGenericClass:
3075+
subst_node =
3076+
swift_demangle::ChildAtPath(parent_node, {Node::Kind::TypeList});
3077+
parent_node = swift_demangle::ChildAtPath(
3078+
parent_node, {Node::Kind::Type, Node::Kind::Class});
3079+
break;
3080+
case Node::Kind::BoundGenericStructure:
3081+
subst_node =
3082+
swift_demangle::ChildAtPath(parent_node, {Node::Kind::TypeList});
3083+
parent_node = swift_demangle::ChildAtPath(
3084+
parent_node, {Node::Kind::Type, Node::Kind::Structure});
3085+
break;
3086+
case Node::Kind::BoundGenericEnum:
3087+
subst_node =
3088+
swift_demangle::ChildAtPath(parent_node, {Node::Kind::TypeList});
3089+
parent_node = swift_demangle::ChildAtPath(
3090+
parent_node, {Node::Kind::Type, Node::Kind::Enum});
3091+
break;
3092+
default:
3093+
return llvm::createStringError("unsupported parent kind");
3094+
}
3095+
if (!parent_node)
3096+
return llvm::createStringError("unsupported generic parent kind");
3097+
3098+
NodePointer global = dem.createNode(Node::Kind::Global);
3099+
global->addChild(parent_node, dem);
3100+
auto mangling = swift::Demangle::mangleNode(global);
3101+
if (!mangling.isSuccess())
3102+
return llvm::createStringError("mangling error");
3103+
std::string in_type =
3104+
swift::Demangle::dropSwiftManglingPrefix(mangling.result()).str();
3105+
3106+
// `in_type` now holds the type alias' parent type.
3107+
// `member` is the name of the type alias.
3108+
// Scan through the witness tables of all of the parent's conformances.
3109+
ThreadSafeReflectionContext reflection_ctx = GetReflectionContext();
3110+
if (!reflection_ctx)
3111+
return llvm::createStringError("no reflection context");
3112+
for (const std::string &protocol : GetConformances(in_type)) {
3113+
auto *type_ref =
3114+
reflection_ctx->LookupTypeWitness(in_type, member, protocol);
3115+
if (!type_ref)
3116+
continue;
3117+
3118+
// Success, we found an associated type in the conformance. If
3119+
// the parent type was generic, the type alias could point to a
3120+
// type parameter. Reapply any substitutions from the parent type.
3121+
if (subst_node) {
3122+
swift::reflection::GenericArgumentMap substitutions;
3123+
unsigned idx = 0;
3124+
for (auto &child : *subst_node) {
3125+
auto mangling = swift_demangle::GetMangledName(dem, child);
3126+
if (!mangling.isSuccess())
3127+
continue;
3128+
const auto *type_ref = reflection_ctx->GetTypeRefOrNull(
3129+
mangling.result(), tr_ts->GetDescriptorFinder());
3130+
if (!type_ref)
3131+
continue;
3132+
3133+
substitutions.insert({{0, idx++}, type_ref});
3134+
}
3135+
type_ref = reflection_ctx->ApplySubstitutions(
3136+
type_ref, substitutions, tr_ts->GetDescriptorFinder());
3137+
}
3138+
3139+
CompilerType resolved = GetTypeFromTypeRef(*tr_ts, type_ref);
3140+
LLDB_LOG(GetLog(LLDBLog::Types),
3141+
"Resolved type alias {0} = {1} using reflection metadata.",
3142+
alias.GetMangledTypeName(), resolved.GetMangledTypeName());
3143+
return resolved;
3144+
}
3145+
return llvm::createStringError("cannot resolve type alias via reflection");
3146+
}
3147+
30373148
std::optional<uint64_t>
30383149
SwiftLanguageRuntimeImpl::GetBitSize(CompilerType type,
30393150
ExecutionContextScope *exe_scope) {

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ class SwiftLanguageRuntimeImpl {
102102
llvm::ArrayRef<swift::reflection::FieldInfo> fields);
103103

104104
bool IsStoredInlineInBuffer(CompilerType type);
105+
llvm::Expected<CompilerType> ResolveTypeAlias(CompilerType alias);
105106

106107
/// Ask Remote Mirrors for the size of a Swift type.
107108
std::optional<uint64_t> GetBitSize(CompilerType type,
@@ -357,6 +358,8 @@ class SwiftLanguageRuntimeImpl {
357358

358359
CompilerType m_box_metadata_type;
359360

361+
llvm::StringMap<std::vector<std::string>> m_conformances;
362+
360363
private:
361364
/// Don't call these directly.
362365
/// \{
@@ -385,6 +388,9 @@ class SwiftLanguageRuntimeImpl {
385388

386389
SwiftMetadataCache *GetSwiftMetadataCache();
387390

391+
/// Find all conformances for a nominal type in the reflection metadata.
392+
std::vector<std::string> GetConformances(llvm::StringRef mangled_name);
393+
388394
/// These members are used to track and toggle the state of the "dynamic
389395
/// exclusivity enforcement flag" in the swift runtime. This flag is set to
390396
/// true when an LLDB expression starts running, and reset to its original

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

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -81,30 +81,48 @@ GetDemangledType(swift::Demangle::Demangler &dem, llvm::StringRef name) {
8181
}
8282

8383
/// Wrap node in Global/TypeMangling/Type.
84-
static swift::Demangle::NodePointer
85-
mangleType(swift::Demangle::Demangler &dem,
86-
swift::Demangle::NodePointer typeNode) {
84+
inline swift::Demangle::NodePointer
85+
MangleType(swift::Demangle::Demangler &dem,
86+
swift::Demangle::NodePointer type_node) {
8787
auto *global = dem.createNode(Node::Kind::Global);
88-
auto *typeMangling = dem.createNode(Node::Kind::TypeMangling);
89-
global->addChild(typeMangling, dem);
88+
auto *type_mangling = dem.createNode(Node::Kind::TypeMangling);
89+
global->addChild(type_mangling, dem);
9090
auto *type = dem.createNode(Node::Kind::Type);
91-
typeMangling->addChild(type, dem);
92-
type->addChild(typeNode, dem);
91+
type_mangling->addChild(type, dem);
92+
type->addChild(type_node, dem);
9393
return global;
9494
}
9595

96+
/// Produce a type mangle tree for a nominal type.
97+
inline swift::Demangle::NodePointer
98+
CreateNominal(swift::Demangle::Demangler &dem, swift::Demangle::Node::Kind kind,
99+
llvm::StringRef module_name, llvm::StringRef type_name) {
100+
auto *nominal = dem.createNode(kind);
101+
auto *m = dem.createNodeWithAllocatedText(Node::Kind::Module, module_name);
102+
auto *id = dem.createNodeWithAllocatedText(Node::Kind::Identifier, type_name);
103+
nominal->addChild(m, dem);
104+
nominal->addChild(id, dem);
105+
return nominal;
106+
}
107+
96108
/// Produce a type mangling for a class.
97-
inline ManglingErrorOr<std::string> mangleClass(swift::Demangle::Demangler &dem,
98-
llvm::StringRef moduleName,
99-
llvm::StringRef className) {
100-
auto *classNode = dem.createNode(Node::Kind::Class);
101-
auto *module =
102-
dem.createNodeWithAllocatedText(Node::Kind::Module, moduleName);
103-
auto *identifier =
104-
dem.createNodeWithAllocatedText(Node::Kind::Identifier, className);
105-
classNode->addChild(module, dem);
106-
classNode->addChild(identifier, dem);
107-
return mangleNode(mangleType(dem, classNode));
109+
inline ManglingErrorOr<std::string> MangleClass(swift::Demangle::Demangler &dem,
110+
llvm::StringRef module_name,
111+
llvm::StringRef class_name) {
112+
auto *node = CreateNominal(dem, Node::Kind::Class, module_name, class_name);
113+
return mangleNode(MangleType(dem, node));
114+
}
115+
116+
/// Create a mangled name for a type node.
117+
inline swift::Demangle::ManglingErrorOr<std::string>
118+
GetMangledName(swift::Demangle::Demangler &dem,
119+
swift::Demangle::NodePointer node) {
120+
using namespace swift::Demangle;
121+
auto global = dem.createNode(Node::Kind::Global);
122+
auto type_mangling = dem.createNode(Node::Kind::TypeMangling);
123+
global->addChild(type_mangling, dem);
124+
type_mangling->addChild(node, dem);
125+
return mangleNode(global);
108126
}
109127

110128
} // namespace swift_demangle

0 commit comments

Comments
 (0)