Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//

#include "LLDBMemoryReader.h"
#include "Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h"
#include "ReflectionContextInterface.h"
#include "SwiftLanguageRuntime.h"
#include "SwiftMetadataCache.h"
Expand Down Expand Up @@ -607,13 +608,14 @@ std::optional<uint64_t> SwiftLanguageRuntime::GetMemberVariableOffset(
namespace {

CompilerType GetTypeFromTypeRef(TypeSystemSwiftTypeRef &ts,
const swift::reflection::TypeRef *type_ref) {
const swift::reflection::TypeRef *type_ref,
swift::Mangle::ManglingFlavor flavor) {
if (!type_ref)
return {};
swift::Demangle::Demangler dem;
swift::Demangle::NodePointer node = type_ref->getDemangling(dem);
// TODO: the mangling flavor should come from the TypeRef.
return ts.RemangleAsType(dem, node, ts.GetManglingFlavor());
return ts.RemangleAsType(dem, node, flavor);
}

struct ExistentialSyntheticChild {
Expand All @@ -627,7 +629,8 @@ struct ExistentialSyntheticChild {
llvm::SmallVector<ExistentialSyntheticChild, 4>
GetExistentialSyntheticChildren(TypeSystemSwiftTypeRef &ts,
const swift::reflection::TypeRef *tr,
const swift::reflection::TypeInfo *ti) {
const swift::reflection::TypeInfo *ti,
swift::Mangle::ManglingFlavor flavor) {
llvm::SmallVector<ExistentialSyntheticChild, 4> children;
auto *protocol_composition_tr =
llvm::dyn_cast<swift::reflection::ProtocolCompositionTypeRef>(tr);
Expand All @@ -641,7 +644,8 @@ GetExistentialSyntheticChildren(TypeSystemSwiftTypeRef &ts,
children.push_back({"object", [=]() {
if (auto *super_class_tr =
protocol_composition_tr->getSuperclass())
return GetTypeFromTypeRef(*ts_sp, super_class_tr);
return GetTypeFromTypeRef(*ts_sp, super_class_tr,
flavor);
else
return rti ? ts_sp->GetBuiltinUnknownObjectType()
: ts_sp->GetBuiltinRawPointerType();
Expand All @@ -652,9 +656,9 @@ GetExistentialSyntheticChildren(TypeSystemSwiftTypeRef &ts,
for (unsigned i = 1; i < fields.size(); ++i) {
TypeSystemSwiftTypeRefSP ts_sp = ts.GetTypeSystemSwiftTypeRef();
auto *type_ref = fields[i].TR;
children.push_back({fields[i].Name, [=]() {
return GetTypeFromTypeRef(*ts_sp, type_ref);
}});
children.push_back(
{fields[i].Name,
[=]() { return GetTypeFromTypeRef(*ts_sp, type_ref, flavor); }});
}
}
}
Expand Down Expand Up @@ -702,12 +706,20 @@ CompilerType GetTypedefedTypeRecursive(CompilerType type) {
class SwiftRuntimeTypeVisitor {
SwiftLanguageRuntime &m_runtime;
ExecutionContext m_exe_ctx;
swift::Mangle::ManglingFlavor m_flavor =
swift::Mangle::ManglingFlavor::Default;
CompilerType m_type;
ValueObject *m_valobj = nullptr;
bool m_hide_superclass = false;
bool m_include_clang_types = false;
bool m_visit_superclass = false;

void SetFlavor() {
if (auto ts_sp =
m_type.GetTypeSystem().dyn_cast_or_null<TypeSystemSwiftTypeRef>())
m_flavor = ts_sp->GetManglingFlavor(&m_exe_ctx);
}

public:
struct ChildInfo {
uint32_t byte_size = 0;
Expand All @@ -732,6 +744,7 @@ class SwiftRuntimeTypeVisitor {
: m_runtime(runtime), m_type(type), m_valobj(valobj) {
if (valobj)
m_exe_ctx = valobj->GetExecutionContextRef();
SetFlavor();
}
SwiftRuntimeTypeVisitor(SwiftLanguageRuntime &runtime, CompilerType type,
ExecutionContextScope *exe_scope,
Expand All @@ -740,6 +753,7 @@ class SwiftRuntimeTypeVisitor {
m_include_clang_types(include_clang_types) {
if (exe_scope)
exe_scope->CalculateExecutionContext(m_exe_ctx);
SetFlavor();
}
SwiftRuntimeTypeVisitor(SwiftLanguageRuntime &runtime, CompilerType type,
ExecutionContext *exe_ctx, bool hide_superclass,
Expand All @@ -749,6 +763,7 @@ class SwiftRuntimeTypeVisitor {
m_visit_superclass(visit_superclass) {
if (exe_ctx)
m_exe_ctx = *exe_ctx;
SetFlavor();
}
llvm::Error VisitAllChildren(VisitCallback callback) {
return VisitImpl({}, callback).takeError();
Expand Down Expand Up @@ -871,7 +886,7 @@ SwiftRuntimeTypeVisitor::VisitImpl(std::optional<unsigned> visit_only,
field_type = tuple->element_type;
else {
if (!field_type)
field_type = GetTypeFromTypeRef(ts, field.TR);
field_type = GetTypeFromTypeRef(ts, field.TR, m_flavor);
}
auto get_info = [&]() -> llvm::Expected<ChildInfo> {
ChildInfo child;
Expand Down Expand Up @@ -968,7 +983,7 @@ SwiftRuntimeTypeVisitor::VisitImpl(std::optional<unsigned> visit_only,
if (rti->getRecordKind() ==
swift::reflection::RecordKind::ClassExistential) {
// Compatibility with SwiftASTContext.
auto children = GetExistentialSyntheticChildren(ts, tr, ti);
auto children = GetExistentialSyntheticChildren(ts, tr, ti, m_flavor);
if (count_only)
return children.size();
auto visit_existential = [&](ExistentialSyntheticChild c, unsigned idx) {
Expand Down Expand Up @@ -1019,7 +1034,7 @@ SwiftRuntimeTypeVisitor::VisitImpl(std::optional<unsigned> visit_only,
llvm::dyn_cast_or_null<swift::reflection::ReferenceTypeInfo>(ti)) {
// Is this an Existential?
unsigned i = 0;
auto children = GetExistentialSyntheticChildren(ts, tr, ti);
auto children = GetExistentialSyntheticChildren(ts, tr, ti, m_flavor);
if (children.size()) {
if (count_only)
return children.size();
Expand Down Expand Up @@ -1109,7 +1124,7 @@ SwiftRuntimeTypeVisitor::VisitImpl(std::optional<unsigned> visit_only,
if (auto *super_tr = reflection_ctx->LookupSuperclass(
*tr, ts.GetDescriptorFinder()))
if (auto error = visit_callback(
GetTypeFromTypeRef(ts, super_tr), depth,
GetTypeFromTypeRef(ts, super_tr, m_flavor), depth,
[]() -> std::string { return "<base class>"; },
[]() -> llvm::Expected<ChildInfo> {
return ChildInfo();
Expand Down Expand Up @@ -1143,8 +1158,9 @@ SwiftRuntimeTypeVisitor::VisitImpl(std::optional<unsigned> visit_only,
return ChildInfo();
};

if (auto error = visit_callback(GetTypeFromTypeRef(ts, super_tr), 0,
get_name, get_info))
if (auto error =
visit_callback(GetTypeFromTypeRef(ts, super_tr, m_flavor), 0,
get_name, get_info))
return error;
}

Expand Down Expand Up @@ -1263,7 +1279,7 @@ SwiftRuntimeTypeVisitor::VisitImpl(std::optional<unsigned> visit_only,
return success;
}

CompilerType super_type = GetTypeFromTypeRef(ts, type_ref);
CompilerType super_type = GetTypeFromTypeRef(ts, type_ref, m_flavor);
auto get_name = [&]() -> std::string {
auto child_name = super_type.GetTypeName().GetStringRef().str();
// FIXME: This should be fixed in GetDisplayTypeName instead!
Expand Down Expand Up @@ -1471,6 +1487,8 @@ SwiftLanguageRuntime::ProjectEnum(ValueObject &valobj) {
if (!ti_or_err)
return ti_or_err.takeError();
auto *ti = &*ti_or_err;
auto flavor =
SwiftLanguageRuntime::GetManglingFlavor(enum_type.GetMangledTypeName());

auto project_indirect_enum =
[&](uint64_t offset, std::string name) -> llvm::Expected<ValueObjectSP> {
Expand All @@ -1496,13 +1514,14 @@ SwiftLanguageRuntime::ProjectEnum(ValueObject &valobj) {
auto &field = rti->getFields()[0];
auto *type_ref = field.TR;
payload += field.Offset;
payload_type = GetTypeFromTypeRef(ts, type_ref);
payload_type = GetTypeFromTypeRef(ts, type_ref, flavor);
break;
}
case swift::reflection::RecordKind::Tuple: {
std::vector<TypeSystemSwift::TupleElement> elts;
for (auto &field : rti->getFields())
elts.emplace_back(ConstString(), GetTypeFromTypeRef(ts, field.TR));
elts.emplace_back(ConstString(),
GetTypeFromTypeRef(ts, field.TR, flavor));
payload_type = ts.CreateTupleType(elts);
break;
}
Expand Down Expand Up @@ -1571,7 +1590,7 @@ SwiftLanguageRuntime::ProjectEnum(ValueObject &valobj) {
if (is_indirect_enum)
return project_indirect_enum(field_info.Offset, field_info.Name);

CompilerType projected_type = GetTypeFromTypeRef(ts, field_info.TR);
CompilerType projected_type = GetTypeFromTypeRef(ts, field_info.TR, flavor);
if (field_info.Offset != 0) {
assert(false);
return llvm::createStringError("enum with unexpected offset");
Expand Down Expand Up @@ -1679,7 +1698,9 @@ CompilerType SwiftLanguageRuntime::GetBaseClass(CompilerType class_ty) {
}
auto *super_tr = reflection_ctx->LookupSuperclass(
*type_ref_or_err, tr_ts->GetDescriptorFinder());
return GetTypeFromTypeRef(*tr_ts, super_tr);
auto flavor =
SwiftLanguageRuntime::GetManglingFlavor(class_ty.GetMangledTypeName());
return GetTypeFromTypeRef(*tr_ts, super_tr, flavor);
}

bool SwiftLanguageRuntime::ForEachSuperClassType(
Expand Down Expand Up @@ -3399,9 +3420,9 @@ SwiftLanguageRuntime::GetSwiftRuntimeTypeInfo(
// Resolve all generic type parameters in the type for the current
// frame. Generic parameter binding has to happen in the scratch
// context.
ExecutionContext exe_ctx;
if (exe_scope)
if (StackFrame *frame = exe_scope->CalculateStackFrame().get()) {
ExecutionContext exe_ctx;
frame->CalculateExecutionContext(exe_ctx);
auto bound_type_or_err = BindGenericTypeParameters(*frame, type);
if (!bound_type_or_err)
Expand All @@ -3423,6 +3444,30 @@ SwiftLanguageRuntime::GetSwiftRuntimeTypeInfo(
if (!reflection_ctx)
return llvm::createStringError("no reflection context");

// The TypeSystemSwiftTypeRefForExpressions doesn't ve a SymbolFile,
// so any DWARF lookups for Embedded Swift fail.
//
// FIXME: It's unclear whether this is safe to do in a non-LTO Swift program.
if (llvm::isa<TypeSystemSwiftTypeRefForExpressions>(tr_ts.get()) &&
tr_ts->GetManglingFlavor(&exe_ctx) ==
swift::Mangle::ManglingFlavor::Embedded) {
if (auto frame_sp = exe_ctx.GetFrameSP()) {
auto &sc = frame_sp->GetSymbolContext(eSymbolContextModule);
if (sc.module_sp) {
auto ts_or_err =
sc.module_sp->GetTypeSystemForLanguage(eLanguageTypeSwift);
if (!ts_or_err)
return ts_or_err.takeError();
if (auto *tr_ts = llvm::dyn_cast_or_null<TypeSystemSwiftTypeRef>(
ts_or_err->get())) {
LLDBTypeInfoProvider provider(*this, *tr_ts);
return reflection_ctx->GetTypeInfo(*type_ref_or_err, &provider,
tr_ts->GetDescriptorFinder());
}
}
}
}

LLDBTypeInfoProvider provider(*this, ts);
return reflection_ctx->GetTypeInfo(*type_ref_or_err, &provider,
tr_ts->GetDescriptorFinder());
Expand Down Expand Up @@ -3561,7 +3606,7 @@ SwiftLanguageRuntime::ResolveTypeAlias(CompilerType alias) {
type_ref = &*type_ref_or_err;
}

CompilerType resolved = GetTypeFromTypeRef(*tr_ts, type_ref);
CompilerType resolved = GetTypeFromTypeRef(*tr_ts, type_ref, flavor);
LLDB_LOG(GetLog(LLDBLog::Types),
"Resolved type alias {0} = {1} using reflection metadata.",
alias.GetMangledTypeName(), resolved.GetMangledTypeName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,10 +173,9 @@ lldb::TypeSP DWARFASTParserSwift::ParseTypeFromDWARF(const SymbolContext &sc,
if (TypeSP desugared_type = get_type(die)) {
// For a typedef, store the once desugared type as the name.
CompilerType type = desugared_type->GetForwardCompilerType();
if (auto swift_ast_ctx =
if (auto ts =
type.GetTypeSystem().dyn_cast_or_null<TypeSystemSwift>())
preferred_name =
swift_ast_ctx->GetMangledTypeName(type.GetOpaqueQualType());
preferred_name = ts->GetMangledTypeName(type.GetOpaqueQualType());
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwift.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ class DWARFASTParserSwift : public lldb_private::plugin::dwarf::DWARFASTParser,

virtual ~DWARFASTParserSwift();

static std::pair<lldb::TypeSP, lldb_private::CompilerType>
ResolveTypeAlias(lldb_private::CompilerType alias);
lldb::TypeSP ParseTypeFromDWARF(const lldb_private::SymbolContext &sc,
const DWARFDIE &die,
bool *type_is_new_ptr) override;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,87 @@ findUnsubstitutedGenericTypeAndDIE(TypeSystemSwiftTypeRef &ts,
ts.GetTypeFromMangledTypename(ConstString(mangled_name));
return {{unsubstituted_type, unsubstituted_die}};
}

lldb_private::CompilerType static MapTypeIntoContext(
TypeSystemSwiftTypeRef &ts, lldb_private::CompilerType context,
lldb_private::CompilerType type) {
return ts.ApplySubstitutions(
type.GetOpaqueQualType(),
ts.GetSubstitutions(context.GetOpaqueQualType()));
}

std::pair<lldb::TypeSP, lldb_private::CompilerType>
DWARFASTParserSwift::ResolveTypeAlias(lldb_private::CompilerType alias) {
if (!alias)
return {};
auto ts_sp = alias.GetTypeSystem().dyn_cast_or_null<TypeSystemSwiftTypeRef>();
if (!ts_sp)
return {};
auto &ts = *ts_sp;
auto *dwarf = llvm::dyn_cast_or_null<SymbolFileDWARF>(ts.GetSymbolFile());
if (!dwarf)
return {};

// Type aliases are (for LLVM implementation reasons) using the
// DW_AT_name as linkage name, so they can't be looked up by base
// name. This should be fixed.
// Meanwhile, instead find them inside their parent type.
CompilerType parent_ctx = ts.GetParentType(alias.GetOpaqueQualType());
if (!parent_ctx)
return {};

DWARFDIE parent_die;
if (TypeSP parent_type =
ts.FindTypeInModule(parent_ctx.GetOpaqueQualType())) {
parent_die = dwarf->GetDIE(parent_type->GetID());
auto unsubstituted_pair =
findUnsubstitutedGenericTypeAndDIE(ts, parent_die);
if (unsubstituted_pair)
parent_die = unsubstituted_pair->second;
}
if (!parent_die)
return {};
std::string alias_name = ts.GetBaseName(alias.GetOpaqueQualType());
for (DWARFDIE child_die : parent_die.children()) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that you need this because we might not have debug info for a typealias declared inside a substituted generic type.

But instead of finding the parent and looking for the typealias as one of it's children, would it be possible instead to:

  • Map the generic typealias out of context first (we'd need to add a new function for this).
  • Look up the mapped out typealias directly.

So if we're looking for the typealias [Int]._Buffer (mangled name $eSa7_BufferaySi_GD), we'd first map that out of context [τ_0_0]._Buffer (mangled name $eSa7_Bufferayx_GD), and FindTypes should be able to find this in DWARF directly.

This would support typealias declared at greater depths than 1.

We could do it as a follow up patch though since this one is already quite big.

Copy link
Author

@adrian-prantl adrian-prantl Sep 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Map the generic typealias out of context first (we'd need to add a new function for this).

Do we have enough info to do this? We know what the linearization of the substitutions is, but we don't know the depth of any of the parameters. Is that something we could reconstruct from what we have in DWARF today?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think so. I'm looking at the debug info for this program:

struct A<T> {
    struct B<U, V> {
        struct C<W> {
                let t: T
                let u: U
                let v: V
                let w: W
        }
    }
}

func f() {
    let c = A<Int>.B<Double, Float>.C<String>(t: 4, u: 4.2, v: 4.2, w: "Hi")
}
f()

The specification of C for c is:

0x00000736:         DW_TAG_structure_type
    DW_AT_specification	(0x000006f4 "$e1a1AV1BV1CVyx_qd__qd_0__qd0__GD")
    0x0000073f:           DW_TAG_member
        DW_AT_type	(0x00000746 "a::$e1a1AVyxGD::$e1a1AV1BVyx_qd__qd_0_GD::$e1a1AV1BV1CVySi_SdSf_SSGD<Swift::String, Swift::Double, Swift::Float, Swift::Int>")

(This debug info looks pretty odd and very redundant, we should change what the compiler emits to cut down on the useless information).

$e1a1AV1BV1CVySi_SdSf_SSGD demangles to:

➜  lldb-macosx-arm64 xcrun swift-demangle e1a1AV1BV1CVySi_SdSf_SSGD
$e1a1AV1BV1CVySi_SdSf_SSGD ---> a.A<Swift.Int>.B<Swift.Double, Swift.Float>.C<Swift.String>

The debug info for C (unsubstituted is):

0x000006f4:         DW_TAG_structure_type
                      DW_AT_name	("C")
                      DW_AT_linkage_name	("$e1a1AV1BV1CVyx_qd__qd_0__qd0__GD")

$e1a1AV1BV1CVyx_qd__qd_0__qd0__GD demangles to:

➜  lldb-macosx-arm64 xcrun swift-demangle e1a1AV1BV1CVyx_qd__qd_0__qd0__GD
$e1a1AV1BV1CVyx_qd__qd_0__qd0__GD ---> a.A<A>.B<A1, B1>.C<A2>

So it should be doable.

auto tag = child_die.Tag();
if (tag == DW_TAG_member)
continue;
std::string base_name;
const auto *name =
child_die.GetAttributeValueAsString(llvm::dwarf::DW_AT_name, "");
if (name && *name == '$') {
CompilerType candidate = ts.GetTypeFromMangledTypename(ConstString(name));
base_name = ts.GetBaseName(candidate.GetOpaqueQualType());
} else {
base_name = name;
}
if (base_name != alias_name)
continue;

// Follow the typedef.
auto *dwarf_parser = ts.GetDWARFParser();
if (!dwarf_parser)
return {};
Type *t = dwarf_parser->GetTypeForDIE(child_die);
if (!t)
return {};
CompilerType cty = t->GetForwardCompilerType();
if (ts.IsMeaninglessWithoutDynamicResolution(cty.GetOpaqueQualType())) {
// Substitute the parameters in the LHS of the BGTAT.
if (ts.IsBoundGenericAliasType(alias.GetOpaqueQualType())) {
auto subs = ts.GetSubstitutions(alias.GetOpaqueQualType());
while (subs.size() > 1)
subs.erase(subs.begin());
cty = ts.ApplySubstitutions(cty.GetOpaqueQualType(), subs);
}
// Substitute the parameters of the RHS of the (BGT)AT.
return {t->shared_from_this(), MapTypeIntoContext(ts, parent_ctx, cty)};
}
return {t->shared_from_this(), cty};
}
return {};
}

/// Given a type system and a typeref, return the compiler type and die of the
/// type that matches that mangled name, looking up the in the type system's
/// module's debug information.
Expand All @@ -79,10 +160,17 @@ getTypeAndDie(TypeSystemSwiftTypeRef &ts,
auto *dwarf = llvm::cast_or_null<SymbolFileDWARF>(ts.GetSymbolFile());
if (!dwarf)
return {};
auto lldb_type = ts.FindTypeInModule(type.GetOpaqueQualType());
TypeSP lldb_type = ts.FindTypeInModule(type.GetOpaqueQualType());
if (!lldb_type) {
std::tie(lldb_type, type) = DWARFASTParserSwift::ResolveTypeAlias(type);
if (lldb_type) {
auto die = dwarf->GetDIE(lldb_type->GetID());
return {{type, die}};
}
}
if (!lldb_type) {
// TODO: for embedded Swift this is fine but consult other modules here for
// general case?
// TODO: for embedded Swift this is fine but consult other modules
// here for general case?
LLDB_LOGV(GetLog(LLDBLog::Types), "Could not find type {0} in module",
type.GetMangledTypeName());
return {};
Expand Down Expand Up @@ -375,7 +463,6 @@ DWARFASTParserSwift::getFieldDescriptor(const swift::reflection::TypeRef *TR) {
lldb_private::AutoBool::False &&
"Full DWARF debugging for Swift is disabled!");


auto pair = getTypeAndDie(m_swift_typesystem, TR);
if (!pair)
return nullptr;
Expand Down
Loading