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
270 changes: 107 additions & 163 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp

Large diffs are not rendered by default.

103 changes: 101 additions & 2 deletions lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1631,13 +1631,19 @@ bool SymbolFileDWARF::CompleteType(CompilerType &compiler_type) {
return true;
}

DWARFDIE dwarf_die = GetDIE(die_it->getSecond());
DWARFDIE dwarf_die = FindDefinitionDIE(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);
// Need to get a new iterator because FindDefinitionDIE might add new
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would it be possible to erase the iterator before calling FindDefinitionDIE?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Now, we change m_forward_decl_compiler_type_to_die to be updated with definition DIE. So, we may need to erase twice, because the first erase is always necessary if we failed to find definition DIE for it. The second erase is because calling FindDefinitionDIE might add new entry to the definition DIE because the first one removed it.

// entries into the map and invalidate previous iterator.
auto die_it = GetForwardDeclCompilerTypeToDIE().find(
compiler_type_no_qualifiers.GetOpaqueQualType());
if (die_it != GetForwardDeclCompilerTypeToDIE().end()) {
GetForwardDeclCompilerTypeToDIE().erase(die_it);
}

Type *type = GetDIEToType().lookup(dwarf_die.GetDIE());

Expand All @@ -1654,6 +1660,99 @@ bool SymbolFileDWARF::CompleteType(CompilerType &compiler_type) {
return false;
}

DWARFDIE SymbolFileDWARF::FindDefinitionDIE(const DWARFDIE &die) {
auto def_die_it = GetDeclarationDIEToDefinitionDIE().find(die.GetDIE());
if (def_die_it != GetDeclarationDIEToDefinitionDIE().end())
return GetDIE(def_die_it->getSecond());

ParsedDWARFTypeAttributes attrs(die);
const dw_tag_t tag = die.Tag();
TypeSP type_sp;
Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups);
if (log) {
GetObjectFile()->GetModule()->LogMessage(
log,
"SymbolFileDWARF({0:p}) - {1:x16}: {2} type \"{3}\" is a "
"forward declaration DIE, trying to find definition DIE",
static_cast<void *>(this), die.GetOffset(), DW_TAG_value_to_name(tag),
attrs.name.GetCString());
}
// We haven't parse definition die for this type, starting to search for it.
// After we found the definition die, the GetDeclarationDIEToDefinitionDIE()
// map will have the new mapping from this declaration die to definition die.
if (attrs.class_language == eLanguageTypeObjC ||
ZequanWu marked this conversation as resolved.
Show resolved Hide resolved
attrs.class_language == eLanguageTypeObjC_plus_plus) {
if (!attrs.is_complete_objc_class &&
die.Supports_DW_AT_APPLE_objc_complete_type()) {
// We have a valid eSymbolTypeObjCClass class symbol whose name
// matches the current objective C class that we are trying to find
// and this DIE isn't the complete definition (we checked
// is_complete_objc_class above and know it is false), so the real
// definition is in here somewhere
type_sp = FindCompleteObjCDefinitionTypeForDIE(die, attrs.name, true);

if (!type_sp) {
SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile();
if (debug_map_symfile) {
// We weren't able to find a full declaration in this DWARF,
// see if we have a declaration anywhere else...
type_sp = debug_map_symfile->FindCompleteObjCDefinitionTypeForDIE(
die, attrs.name, true);
}
}

if (type_sp && log) {
GetObjectFile()->GetModule()->LogMessage(
log,
"SymbolFileDWARF({0:p}) - {1:x16}: {2} type "
"\"{3}\" is an "
"incomplete objc type, complete type is {4:x8}",
static_cast<void *>(this), die.GetOffset(),
DW_TAG_value_to_name(tag), attrs.name.GetCString(),
type_sp->GetID());
}
}
}
bool is_forward_declaration =
attrs.is_forward_declaration ||
(attrs.byte_size && *attrs.byte_size == 0 && attrs.name &&
!die.HasChildren() &&
SymbolFileDWARF::GetLanguage(*die.GetCU()) == eLanguageTypeObjC);
if (is_forward_declaration) {
type_sp = FindDefinitionTypeForDWARFDeclContext(die);
if (!type_sp) {
SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile();
if (debug_map_symfile) {
// We weren't able to find a full declaration in this DWARF, see
// if we have a declaration anywhere else...
type_sp = debug_map_symfile->FindDefinitionTypeForDWARFDeclContext(die);
}
if (type_sp && log) {
GetObjectFile()->GetModule()->LogMessage(
log,
"SymbolFileDWARF({0:p}) - {1:x16}: {2} type \"{3}\" is a "
"forward declaration, complete type is {4:x8}",
static_cast<void *>(this), die.GetOffset(),
DW_TAG_value_to_name(tag), attrs.name.GetCString(),
type_sp->GetID());
}
}
}
def_die_it = GetDeclarationDIEToDefinitionDIE().find(die.GetDIE());
if (def_die_it != GetDeclarationDIEToDefinitionDIE().end())
return GetDIE(def_die_it->getSecond());

if (log) {
GetObjectFile()->GetModule()->LogMessage(
log,
"SymbolFileDWARF({0:p}) - {1:x16}: {2} type \"{3}\" is a "
"forward declaration, unable to find definition DIE for it",
static_cast<void *>(this), die.GetOffset(), DW_TAG_value_to_name(tag),
attrs.name.GetCString());
}
return DWARFDIE();
}

Type *SymbolFileDWARF::ResolveType(const DWARFDIE &die,
bool assert_not_being_parsed,
bool resolve_function_context) {
Expand Down
14 changes: 14 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ class SymbolFileDWARF : public SymbolFileCommon {
void FindFunctions(const RegularExpression &regex, bool include_inlines,
SymbolContextList &sc_list) override;

DWARFDIE FindDefinitionDIE(const DWARFDIE &die);

void
GetMangledNamesForFunction(const std::string &scope_qualified_name,
std::vector<ConstString> &mangled_names) override;
Expand Down Expand Up @@ -342,6 +344,11 @@ class SymbolFileDWARF : public SymbolFileCommon {
return m_forward_decl_compiler_type_to_die;
}

typedef llvm::DenseMap<const DWARFDebugInfoEntry *, DIERef> DIEToDIE;
virtual DIEToDIE &GetDeclarationDIEToDefinitionDIE() {
return m_die_to_def_die;
}

typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb::VariableSP>
DIEToVariableSP;

Expand Down Expand Up @@ -533,9 +540,16 @@ 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;
// A map from a struct/class/union/enum DIE (might be a declaration or a
// definition) to its definition DIE.
DIEToDIE m_die_to_def_die;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would it be possible to avoid creating the extra map, for example by modifying the m_forward_decl_compiler_type_to_die to point to the definition DIE -- after that DIE has been located?

Copy link
Collaborator

Choose a reason for hiding this comment

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

(I also can't help but wonder why do we need that m_forward_decl_compiler_type_to_die in the first place, given that the ClangASTMetadata associated with the type already contains a user ID, which should allow us to retrieve original DIE. I know this isn't related to your patch, I'm just writing it in case you or someone has any thoughts on this.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

llvm::DenseMap<dw_offset_t, std::unique_ptr<SupportFileList>>
m_type_unit_support_files;
std::vector<uint32_t> m_lldb_cu_to_dwarf_unit;
Expand Down
5 changes: 5 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ SymbolFileDWARF::DIEToVariableSP &SymbolFileDWARFDwo::GetDIEToVariable() {
return GetBaseSymbolFile().GetDIEToVariable();
}

SymbolFileDWARF::DIEToDIE &
SymbolFileDWARFDwo::GetDeclarationDIEToDefinitionDIE() {
return GetBaseSymbolFile().GetDeclarationDIEToDefinitionDIE();
}

SymbolFileDWARF::CompilerTypeToDIE &
SymbolFileDWARFDwo::GetForwardDeclCompilerTypeToDIE() {
return GetBaseSymbolFile().GetForwardDeclCompilerTypeToDIE();
Expand Down
2 changes: 2 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ class SymbolFileDWARFDwo : public SymbolFileDWARF {

CompilerTypeToDIE &GetForwardDeclCompilerTypeToDIE() override;

DIEToDIE &GetDeclarationDIEToDefinitionDIE() override;

UniqueDWARFASTTypeMap &GetUniqueDWARFASTTypeMap() override;

lldb::TypeSP
Expand Down
95 changes: 50 additions & 45 deletions lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,60 +16,65 @@ 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
{
// 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) {
Copy link
Member

@Michael137 Michael137 May 3, 2024

Choose a reason for hiding this comment

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

For readability, can we do:

if (!matching_size_declaration)
  continue;

?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

// 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;
} 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;
}
} break;

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();
}
parent_arg_die = parent_arg_die.GetParent();
parent_pos_die = parent_pos_die.GetParent();
}

if (match) {
entry = udt;
return true;
}
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
Loading