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][DWARF] Delay struct/class/union definition DIE searching when parsing declaration DIEs. #90663

Merged
merged 11 commits into from
May 10, 2024
2 changes: 2 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ class DWARFASTParser {

virtual ConstString GetDIEClassTemplateParams(const DWARFDIE &die) = 0;

virtual lldb_private::Type *FindDefinitionTypeForDIE(const DWARFDIE &die) = 0;

static std::optional<SymbolFile::ArrayInfo>
ParseChildArrayInfo(const DWARFDIE &parent_die,
const ExecutionContext *exe_ctx = nullptr);
Expand Down
379 changes: 209 additions & 170 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp

Large diffs are not rendered by default.

197 changes: 88 additions & 109 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h

Large diffs are not rendered by default.

45 changes: 26 additions & 19 deletions lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1632,27 +1632,34 @@ bool SymbolFileDWARF::CompleteType(CompilerType &compiler_type) {
return true;
}

DWARFDIE dwarf_die = GetDIE(die_it->getSecond());
if (dwarf_die) {
// Once we start resolving this type, remove it from the forward
// declaration map in case anyone child members or other types require this
// type to get resolved. The type will get resolved when all of the calls
// to SymbolFileDWARF::ResolveClangOpaqueTypeDefinition are done.
GetForwardDeclCompilerTypeToDIE().erase(die_it);

Type *type = GetDIEToType().lookup(dwarf_die.GetDIE());
// Once we start resolving this type, remove it from the forward
// declaration map in case anyone's child members or other types require this
// type to get resolved.
DWARFDIE dwarf_die = GetDIE(die_it->second);
GetForwardDeclCompilerTypeToDIE().erase(die_it);
Type *type = nullptr;
if (DWARFASTParser *dwarf_ast = GetDWARFParser(*dwarf_die.GetCU()))
type = dwarf_ast->FindDefinitionTypeForDIE(dwarf_die);
if (!type)
return false;

Log *log = GetLog(DWARFLog::DebugInfo | DWARFLog::TypeCompletion);
if (log)
GetObjectFile()->GetModule()->LogMessageVerboseBacktrace(
log, "{0:x8}: {1} ({2}) '{3}' resolving forward declaration...",
dwarf_die.GetID(), DW_TAG_value_to_name(dwarf_die.Tag()),
dwarf_die.Tag(), type->GetName().AsCString());
assert(compiler_type);
if (DWARFASTParser *dwarf_ast = GetDWARFParser(*dwarf_die.GetCU()))
return dwarf_ast->CompleteTypeFromDWARF(dwarf_die, type, compiler_type);
die_it = GetForwardDeclCompilerTypeToDIE().find(
compiler_type_no_qualifiers.GetOpaqueQualType());
if (die_it != GetForwardDeclCompilerTypeToDIE().end()) {
dwarf_die = GetDIE(die_it->getSecond());
GetForwardDeclCompilerTypeToDIE().erase(die_it);
}
return false;

Log *log = GetLog(DWARFLog::DebugInfo | DWARFLog::TypeCompletion);
if (log)
ZequanWu marked this conversation as resolved.
Show resolved Hide resolved
GetObjectFile()->GetModule()->LogMessageVerboseBacktrace(
log, "{0:x8}: {1} ({2}) '{3}' resolving forward declaration...",
dwarf_die.GetID(), DW_TAG_value_to_name(dwarf_die.Tag()),
dwarf_die.Tag(), type->GetName().AsCString());
assert(compiler_type);
if (DWARFASTParser *dwarf_ast = GetDWARFParser(*dwarf_die.GetCU()))
return dwarf_ast->CompleteTypeFromDWARF(dwarf_die, type, compiler_type);
return true;
}

Type *SymbolFileDWARF::ResolveType(const DWARFDIE &die,
Expand Down
4 changes: 4 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
Original file line number Diff line number Diff line change
Expand Up @@ -533,8 +533,12 @@ class SymbolFileDWARF : public SymbolFileCommon {
NameToOffsetMap m_function_scope_qualified_name_map;
std::unique_ptr<DWARFDebugRanges> m_ranges;
UniqueDWARFASTTypeMap m_unique_ast_type_map;
// A map from DIE to lldb_private::Type. For record type, the key might be
// either declaration DIE or definition DIE.
DIEToTypePtr m_die_to_type;
DIEToVariableSP m_die_to_variable_sp;
// A map from CompilerType to the struct/class/union/enum DIE (might be a
// declaration or a definition) that is used to construct it.
CompilerTypeToDIE m_forward_decl_compiler_type_to_die;
llvm::DenseMap<dw_offset_t, std::unique_ptr<SupportFileList>>
m_type_unit_support_files;
Expand Down
99 changes: 52 additions & 47 deletions lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,61 +16,66 @@ using namespace lldb_private::plugin::dwarf;
bool UniqueDWARFASTTypeList::Find(const DWARFDIE &die,
const lldb_private::Declaration &decl,
const int32_t byte_size,
bool is_forward_declaration,
UniqueDWARFASTType &entry) const {
for (const UniqueDWARFASTType &udt : m_collection) {
// Make sure the tags match
if (udt.m_die.Tag() == die.Tag()) {
// Validate byte sizes of both types only if both are valid.
if (udt.m_byte_size < 0 || byte_size < 0 ||
udt.m_byte_size == byte_size) {
// Make sure the file and line match
if (udt.m_declaration == decl) {
// The type has the same name, and was defined on the same file and
// line. Now verify all of the parent DIEs match.
DWARFDIE parent_arg_die = die.GetParent();
DWARFDIE parent_pos_die = udt.m_die.GetParent();
bool match = true;
bool done = false;
while (!done && match && parent_arg_die && parent_pos_die) {
const dw_tag_t parent_arg_tag = parent_arg_die.Tag();
const dw_tag_t parent_pos_tag = parent_pos_die.Tag();
if (parent_arg_tag == parent_pos_tag) {
switch (parent_arg_tag) {
case DW_TAG_class_type:
case DW_TAG_structure_type:
case DW_TAG_union_type:
case DW_TAG_namespace: {
const char *parent_arg_die_name = parent_arg_die.GetName();
if (parent_arg_die_name ==
nullptr) // Anonymous (i.e. no-name) struct
{
match = false;
} else {
const char *parent_pos_die_name = parent_pos_die.GetName();
if (parent_pos_die_name == nullptr ||
((parent_arg_die_name != parent_pos_die_name) &&
strcmp(parent_arg_die_name, parent_pos_die_name)))
match = false;
}
} break;

case DW_TAG_compile_unit:
case DW_TAG_partial_unit:
done = true;
break;
default:
break;
}
// If they are not both definition DIEs or both declaration DIEs, then
// don't check for byte size and declaration location, because declaration
// DIEs usually don't have those info.
bool matching_size_declaration =
udt.m_is_forward_declaration != is_forward_declaration
? true
: (udt.m_byte_size < 0 || byte_size < 0 ||
udt.m_byte_size == byte_size) &&
udt.m_declaration == decl;
if (!matching_size_declaration)
continue;
// The type has the same name, and was defined on the same file and
// line. Now verify all of the parent DIEs match.
DWARFDIE parent_arg_die = die.GetParent();
DWARFDIE parent_pos_die = udt.m_die.GetParent();
bool match = true;
bool done = false;
while (!done && match && parent_arg_die && parent_pos_die) {
const dw_tag_t parent_arg_tag = parent_arg_die.Tag();
const dw_tag_t parent_pos_tag = parent_pos_die.Tag();
if (parent_arg_tag == parent_pos_tag) {
switch (parent_arg_tag) {
case DW_TAG_class_type:
case DW_TAG_structure_type:
case DW_TAG_union_type:
case DW_TAG_namespace: {
const char *parent_arg_die_name = parent_arg_die.GetName();
if (parent_arg_die_name ==
nullptr) // Anonymous (i.e. no-name) struct
{
ZequanWu marked this conversation as resolved.
Show resolved Hide resolved
match = false;
} else {
const char *parent_pos_die_name = parent_pos_die.GetName();
if (parent_pos_die_name == nullptr ||
((parent_arg_die_name != parent_pos_die_name) &&
strcmp(parent_arg_die_name, parent_pos_die_name)))
match = false;
}
parent_arg_die = parent_arg_die.GetParent();
parent_pos_die = parent_pos_die.GetParent();
}
} break;

if (match) {
entry = udt;
return true;
case DW_TAG_compile_unit:
case DW_TAG_partial_unit:
done = true;
break;
default:
break;
}
}
parent_arg_die = parent_arg_die.GetParent();
parent_pos_die = parent_pos_die.GetParent();
}

if (match) {
entry = udt;
return true;
}
}
}
Expand Down
21 changes: 15 additions & 6 deletions lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,16 @@ class UniqueDWARFASTType {
UniqueDWARFASTType() : m_type_sp(), m_die(), m_declaration() {}

UniqueDWARFASTType(lldb::TypeSP &type_sp, const DWARFDIE &die,
const Declaration &decl, int32_t byte_size)
const Declaration &decl, int32_t byte_size,
bool is_forward_declaration)
: m_type_sp(type_sp), m_die(die), m_declaration(decl),
m_byte_size(byte_size) {}
m_byte_size(byte_size),
m_is_forward_declaration(is_forward_declaration) {}
ZequanWu marked this conversation as resolved.
Show resolved Hide resolved

UniqueDWARFASTType(const UniqueDWARFASTType &rhs)
: m_type_sp(rhs.m_type_sp), m_die(rhs.m_die),
m_declaration(rhs.m_declaration), m_byte_size(rhs.m_byte_size) {}
m_declaration(rhs.m_declaration), m_byte_size(rhs.m_byte_size),
m_is_forward_declaration(rhs.m_is_forward_declaration) {}

~UniqueDWARFASTType() = default;

Expand All @@ -40,6 +43,7 @@ class UniqueDWARFASTType {
m_die = rhs.m_die;
m_declaration = rhs.m_declaration;
m_byte_size = rhs.m_byte_size;
m_is_forward_declaration = rhs.m_is_forward_declaration;
}
return *this;
}
Expand All @@ -48,6 +52,8 @@ class UniqueDWARFASTType {
DWARFDIE m_die;
Declaration m_declaration;
int32_t m_byte_size = -1;
// True if the m_die is a forward declaration DIE.
bool m_is_forward_declaration = true;
};

class UniqueDWARFASTTypeList {
Expand All @@ -63,7 +69,8 @@ class UniqueDWARFASTTypeList {
}

bool Find(const DWARFDIE &die, const Declaration &decl,
const int32_t byte_size, UniqueDWARFASTType &entry) const;
const int32_t byte_size, bool is_forward_declaration,
UniqueDWARFASTType &entry) const;

protected:
typedef std::vector<UniqueDWARFASTType> collection;
Expand All @@ -81,11 +88,13 @@ class UniqueDWARFASTTypeMap {
}

bool Find(ConstString name, const DWARFDIE &die, const Declaration &decl,
const int32_t byte_size, UniqueDWARFASTType &entry) const {
const int32_t byte_size, bool is_forward_declaration,
UniqueDWARFASTType &entry) const {
const char *unique_name_cstr = name.GetCString();
collection::const_iterator pos = m_collection.find(unique_name_cstr);
if (pos != m_collection.end()) {
return pos->second.Find(die, decl, byte_size, entry);
return pos->second.Find(die, decl, byte_size, is_forward_declaration,
entry);
}
return false;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Test definition DIE searching is delayed until complete type is required.

# RUN: split-file %s %t
# RUN: %clangxx_host %t/main.cpp %t/t1_def.cpp -g -gsimple-template-names -o %t.out
# RUN: %lldb -b %t.out -s %t/lldb.cmd | FileCheck %s

# CHECK: (lldb) p v1
# CHECK-NEXT: DWARFASTParserClang::ParseTypeFromDWARF{{.*}}DW_TAG_structure_type (DW_TAG_structure_type) name = 't2'
labath marked this conversation as resolved.
Show resolved Hide resolved
# CHECK-NEXT: DWARFASTParserClang::ParseTypeFromDWARF{{.*}}DW_TAG_structure_type (DW_TAG_structure_type) name = 't1'
# CHECK-NEXT: DWARFASTParserClang::ParseTypeFromDWARF{{.*}}DW_TAG_base_type (DW_TAG_base_type) name = 'int'
# CHECK-NEXT: DW_TAG_structure_type (DW_TAG_structure_type) 't2' resolving forward declaration...
# CHECK-NEXT: (t2<t1<int> >) {}
# CHECK-NEXT: (lldb) p v2
# CHECK-NEXT: DWARFASTParserClang::ParseTypeFromDWARF{{.*}}DW_TAG_structure_type (DW_TAG_structure_type) name = 't1'
# CHECK-NEXT: DWARFASTParserClang::ParseTypeFromDWARF{{.*}}DW_TAG_base_type (DW_TAG_base_type) name = 'int'
# CHECK-NEXT: DW_TAG_structure_type (DW_TAG_structure_type) 't1' resolving forward declaration...
# CHECK-NEXT: (t1<int>) {}

#--- lldb.cmd
log enable dwarf comp
p v1
p v2

#--- template.h
template<typename T>
struct t1 {
};
template<typename T>
struct t2 {
};

#--- main.cpp
#include "template.h"
t2<t1<int>> v1; // this CU doesn't have definition DIE for t1<int>, but only declaration DIE for it.
int main() {
}

#--- t1_def.cpp
#include "template.h"
t1<int> v2; // this CU contains definition DIE for t1<int>.
Loading