Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[lldb] Add support for class info lookup from DWARF #8112

Merged
merged 1 commit into from
Feb 10, 2024
Merged
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
5 changes: 5 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwift.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,13 @@ class DWARFASTParserSwift : public lldb_private::plugin::dwarf::DWARFASTParser,
std::unique_ptr<swift::reflection::BuiltinTypeDescriptorBase>
getBuiltinTypeDescriptor(const swift::reflection::TypeRef *TR) override;

private:
/// Returns the canonical demangle tree of a die's type.
NodePointer GetCanonicalDemangleTree(DWARFDIE &die);

protected:
lldb_private::TypeSystemSwiftTypeRef &m_swift_typesystem;
swift::Demangle::Demangler m_dem;
};

#endif // SymbolFileDWARF_DWARFASTParserSwift_h_
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,19 @@
//
//===----------------------------------------------------------------------===//

#include <sstream>

#include "DWARFDebugInfo.h"
#include "DWARFASTParserSwift.h"

#include "DWARFDIE.h"
#include "DWARFDebugInfo.h"

#include "Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.h"
#include "Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h"

#include "swift/RemoteInspection/TypeLowering.h"

#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Target/Target.h"

using namespace lldb;
using namespace lldb_private;
Expand All @@ -38,30 +41,46 @@ getTypeAndDie(TypeSystemSwiftTypeRef &ts,
swift::Demangle::Demangler dem;
swift::Demangle::NodePointer node = TR->getDemangling(dem);
auto type = ts.RemangleAsType(dem, node);
if (!type)
if (!type) {
if (auto log = GetLog(LLDBLog::Types)) {
std::stringstream ss;
TR->dump(ss);
LLDB_LOG(log, "Could not find type for typeref: {0}", ss.str());
}
return {};
}

auto *dwarf = llvm::cast_or_null<SymbolFileDWARF>(ts.GetSymbolFile());
if (!dwarf)
return {};
auto lldb_type = ts.FindTypeInModule(type.GetOpaqueQualType());
if (!lldb_type)
if (!lldb_type) {
// 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 {};
}
auto die = dwarf->GetDIE(lldb_type->GetID());
return {{type, die}};
}

static std::optional<swift::reflection::FieldDescriptorKind>
getFieldDescriptorKindForDie(DWARFDIE &die) {
if (die.Tag() == DW_TAG_structure_type) {
if (die.HasChildren() && die.GetFirstChild().Tag() == llvm::dwarf::DW_TAG_variant_part)
return swift::reflection::FieldDescriptorKind::Enum;
getFieldDescriptorKindForDie(CompilerType type) {
auto type_class = type.GetTypeClass();
switch (type_class) {
case lldb::eTypeClassClass:
return swift::reflection::FieldDescriptorKind::Class;
case lldb::eTypeClassStruct:
return swift::reflection::FieldDescriptorKind::Struct;
case lldb::eTypeClassEnumeration:
return swift::reflection::FieldDescriptorKind::Enum;
augusto2112 marked this conversation as resolved.
Show resolved Hide resolved
default:
LLDB_LOG(GetLog(LLDBLog::Types),
"Could not determine file descriptor kind for type: {0}",
type.GetMangledTypeName());
return {};
}
// TODO: handle more cases, for now we only support structs and enums.
return {};
}

namespace {
Expand Down Expand Up @@ -108,20 +127,23 @@ class DWARFFieldDescriptorImpl : public swift::reflection::FieldDescriptorBase {
TypeSystemSwiftTypeRef &m_type_system;
ConstString m_mangled_name;
DIERef m_die_ref;
NodePointer m_superclass_node;

public:
DWARFFieldDescriptorImpl(swift::reflection::FieldDescriptorKind kind,
bool has_superclass,
NodePointer superclass_node,
TypeSystemSwiftTypeRef &type_system,
ConstString mangled_name, DIERef die_ref)
: swift::reflection::FieldDescriptorBase(kind, has_superclass),
: swift::reflection::FieldDescriptorBase(kind,
superclass_node != nullptr),
m_type_system(type_system), m_mangled_name(mangled_name),
m_die_ref(die_ref) {}
m_die_ref(die_ref), m_superclass_node(superclass_node) {}

~DWARFFieldDescriptorImpl() override = default;

// TODO: implement this.
swift::Demangle::NodePointer demangleSuperclass() override { return nullptr; }
swift::Demangle::NodePointer demangleSuperclass() override {
return m_superclass_node;
}

std::vector<std::unique_ptr<swift::reflection::FieldRecordBase>>
getFieldRecords() override {
Expand All @@ -139,17 +161,22 @@ class DWARFFieldDescriptorImpl : public swift::reflection::FieldDescriptorBase {

switch (Kind) {
case swift::reflection::FieldDescriptorKind::Struct:
return getFieldRecordsFromStruct(die, dwarf_parser);
case swift::reflection::FieldDescriptorKind::Class:
return getFieldRecordsFromStructOrClass(die, dwarf_parser);
case swift::reflection::FieldDescriptorKind::Enum:
return getFieldRecordsFromEnum(die, dwarf_parser);
default:
augusto2112 marked this conversation as resolved.
Show resolved Hide resolved
// TODO: handle more cases.
LLDB_LOG(GetLog(LLDBLog::Types),
"Trying to get field records of unexpected kind: {0}",
(uint8_t)Kind);
assert(false && "Trying to get field records of unexpected kind");
return {};
}
}

std::vector<std::unique_ptr<swift::reflection::FieldRecordBase>>
getFieldRecordsFromStruct(const DWARFDIE &die,
getFieldRecordsFromStructOrClass(const DWARFDIE &die,
plugin::dwarf::DWARFASTParser *dwarf_parser) {
std::vector<std::unique_ptr<swift::reflection::FieldRecordBase>> fields;
for (DWARFDIE child_die : die.children()) {
Expand Down Expand Up @@ -221,12 +248,14 @@ DWARFASTParserSwift::getBuiltinTypeDescriptor(
return nullptr;
auto &[type, die] = *pair;

if (die.Tag() == llvm::dwarf::DW_TAG_structure_type) {
auto child = die.GetFirstChild();
if (child.Tag() != llvm::dwarf::DW_TAG_variant_part)
if (!TypeSystemSwiftTypeRef::IsBuiltinType(type)) {
if (die.Tag() == llvm::dwarf::DW_TAG_structure_type) {
auto child = die.GetFirstChild();
if (child.Tag() != llvm::dwarf::DW_TAG_variant_part)
return nullptr;
} else if (die.Tag() != llvm::dwarf::DW_TAG_base_type)
return nullptr;
} else if (die.Tag() != llvm::dwarf::DW_TAG_base_type)
return nullptr;
}

auto byte_size =
die.GetAttributeValueAsUnsigned(DW_AT_byte_size, LLDB_INVALID_ADDRESS);
Expand All @@ -249,6 +278,35 @@ DWARFASTParserSwift::getBuiltinTypeDescriptor(
type.GetMangledTypeName());
}

namespace {
DWARFDIE FindSuperClassDIE(DWARFDIE &die) {
const auto inheritance_die_it =
llvm::find_if(die.children(), [&](const DWARFDIE &child_die) {
return child_die.Tag() == llvm::dwarf::DW_TAG_inheritance;
});

if (inheritance_die_it == die.children().end())
return {};

auto inheritance_die = *inheritance_die_it;
const auto superclass_type_die =
inheritance_die.GetAttributeValueAsReferenceDIE(llvm::dwarf::DW_AT_type);
augusto2112 marked this conversation as resolved.
Show resolved Hide resolved
return superclass_type_die;
}
} // namespace

NodePointer DWARFASTParserSwift::GetCanonicalDemangleTree(DWARFDIE &die) {
const auto name = StringRef(
die.GetAttributeValueAsString(llvm::dwarf::DW_AT_linkage_name, ""));

if (name.empty())
return nullptr;

auto *node =
m_swift_typesystem.GetCanonicalDemangleTree(m_dem, name);
return node;
}

std::unique_ptr<swift::reflection::FieldDescriptorBase>
DWARFASTParserSwift::getFieldDescriptor(const swift::reflection::TypeRef *TR) {
if (!Target::GetGlobalProperties().GetSwiftEnableFullDwarfDebugging())
Expand All @@ -260,12 +318,14 @@ DWARFASTParserSwift::getFieldDescriptor(const swift::reflection::TypeRef *TR) {
auto [type, die] = *pair;
if (!die)
return nullptr;
auto kind = getFieldDescriptorKindForDie(die);
auto kind = getFieldDescriptorKindForDie(type);
if (!kind)
return nullptr;
// TODO: encode this in DWARF, maybe as a DW_AT_containing_type?
bool has_superclass = false;

DWARFDIE superclass_die = FindSuperClassDIE(die);
NodePointer superclass_pointer = GetCanonicalDemangleTree(superclass_die);

return std::make_unique<DWARFFieldDescriptorImpl>(
*kind, has_superclass, m_swift_typesystem, type.GetMangledTypeName(),
*kind, superclass_pointer, m_swift_typesystem, type.GetMangledTypeName(),
*die.GetDIERef());
}
25 changes: 19 additions & 6 deletions lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,17 @@ GetNominal(swift::Demangle::Demangler &dem, swift::Demangle::NodePointer node) {
return {};
}

bool
TypeSystemSwiftTypeRef::IsBuiltinType(CompilerType type) {
assert(type.GetTypeSystem().isa_and_nonnull<TypeSystemSwift>() &&
"Unexpected type system!");
Demangler dem;
auto *node = GetDemangledType(dem, type.GetMangledTypeName());
if (!node)
return false;
return node->getKind() == Node::Kind::BuiltinTypeName;
}

/// Return a pair of module name and type name, given a mangled name.
static llvm::Optional<std::pair<StringRef, StringRef>>
GetNominal(llvm::StringRef mangled_name, swift::Demangle::Demangler &dem) {
Expand Down Expand Up @@ -1830,7 +1841,8 @@ TypeSystemSwiftTypeRef::FindTypeInModule(opaque_compiler_type_t opaque_type) {
ConstString module(module_type->first);
ConstString type(module_type->second);
llvm::SmallVector<CompilerContext, 2> decl_context;
decl_context.push_back({CompilerContextKind::Module, module});
if (!module.IsEmpty())
decl_context.push_back({CompilerContextKind::Module, module});
decl_context.push_back({CompilerContextKind::AnyType, type});

TypeQuery query(decl_context, TypeQueryOptions::e_find_one |
Expand Down Expand Up @@ -3329,6 +3341,12 @@ CompilerType TypeSystemSwiftTypeRef::GetChildCompilerTypeAtIndex(
return impl();
#ifndef NDEBUG
auto result = impl();
if (ShouldSkipValidation(type))
return result;

if (!ModuleList::GetGlobalModuleListProperties().GetSwiftValidateTypeSystem())
return result;

// FIXME:
// No point comparing the results if the reflection data has more
// information. There's a nasty chicken & egg problem buried here:
Expand All @@ -3339,8 +3357,6 @@ CompilerType TypeSystemSwiftTypeRef::GetChildCompilerTypeAtIndex(
runtime->GetNumChildren({weak_from_this(), type}, exe_scope)
.value_or(0))
return result;
if (ShouldSkipValidation(type))
return result;
// When the child compiler type is an anonymous clang type,
// GetChildCompilerTypeAtIndex will return the clang type directly. In this
// case validation will fail as it can't correctly compare the mangled
Expand All @@ -3359,9 +3375,6 @@ CompilerType TypeSystemSwiftTypeRef::GetChildCompilerTypeAtIndex(
bool ast_child_is_deref_of_parent = false;
uint64_t ast_language_flags = 0;
auto defer = llvm::make_scope_exit([&] {
if (!ModuleList::GetGlobalModuleListProperties()
.GetSwiftValidateTypeSystem())
return;
// Ignore if SwiftASTContext got no result.
if (ast_child_name.empty())
return;
Expand Down
4 changes: 4 additions & 0 deletions lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,10 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift {
llvm::Optional<TupleElement>
GetTupleElement(lldb::opaque_compiler_type_t type, size_t idx);

/// Returns true if the compiler type is a Builtin (belongs to the "Builtin
/// module").
static bool IsBuiltinType(CompilerType type);

/// Creates a GenericTypeParamType with the desired depth and index.
CompilerType CreateGenericTypeParamType(unsigned int depth,
unsigned int index) override;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,8 @@ def test(self):
)

# TODO: test enums when "rdar://119343683 (Embedded Swift trivial case enum fails to link)" is solved

self.expect("frame variable sup", substrs=["Sup) sup = ", "supField = 42"])

Choose a reason for hiding this comment

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

If you find the time, it would be neat to replace these with more accurate check_variable() calls

self.expect("frame variable sub", substrs=["Sub) sub = ", "Sup = {", "supField = 42", "subField = {", "a = (field = 4.2000000000000002", "b = 123456"])
self.expect("frame variable subSub", substrs=["SubSub) subSub =", "a.Sub = {", "a.Sup = {", "supField = 42", "subField = {", "a = (field = 4.2000000000000002", "b = 123456", "subSubField = (field = 4.2000000000000002)"])

16 changes: 16 additions & 0 deletions lldb/test/API/lang/swift/embedded/frame_variable/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,29 @@ struct B {
// case nonPayloadTwo
// }

class Sup {
var supField: Int8 = 42
}

class Sub: Sup {
var subField = B()
}

class SubSub: Sub {
var subSubField = A()
}

let varB = B()
let tuple = (A(), B())
// let trivial = TrivialEnum.theCase
// let nonPayload1 = NonPayloadEnum.one
// let nonPayload2 = NonPayloadEnum.two
// let singlePayload = SinglePayloadEnum.payload(B())
// let emptySinglePayload = SinglePayloadEnum.nonPayloadTwo
let sup = Sup()
let sub = Sub()
let subSub = SubSub()
let sup2: Sup = SubSub()

// Dummy statement to set breakpoint print can't be used in embedded Swift for now.
let dummy = A() // break here
Expand Down