Skip to content

Commit

Permalink
Merge pull request #8112 from augusto2112/class-dwarf
Browse files Browse the repository at this point in the history
[lldb] Add support for class info lookup from DWARF
  • Loading branch information
augusto2112 authored Feb 10, 2024
2 parents d70bd0e + ff077c5 commit 96e8d7c
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 33 deletions.
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;
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:
// 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);
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"])
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

0 comments on commit 96e8d7c

Please sign in to comment.