Skip to content

Commit c660b28

Browse files
authored
[lldb][SymbolFileDWARF] Ignore Declaration when searching through UniqueDWARFASTTypeList in C++ (llvm#120809)
This addresses an issue encountered when investigating llvm#120569. In `ParseTypeFromDWARF`, we insert the parsed type into `UniqueDWARFASTTypeMap` using the typename and `Declaration` obtained with `GetUniqueTypeNameAndDeclaration`. For C++ `GetUniqueTypeNameAndDeclaration` will zero the `Declaration` info (presumably because forward declaration may not have it, and for C++, ODR means we can rely on fully qualified typenames for uniqueing). When we then called `CompleteType`, we would first `MapDeclDIEToDefDIE`, updating the `UniqueDWARFASTType` we inserted previously with the `Declaration` of the definition DIE (without zeroing it). We would then call into `ParseTypeFromDWARF` for the same type again, and search the `UniqueDWARFASTTypeMap`. But we do the search using a zeroed declaration we get from `GetUniqueTypeNameAndDeclaration`. This particular example was fixed by llvm#120569 but this still feels a little inconsistent. I'm not entirely sure we can get into that situation after that patch anymore. So the only test-case I could come up with was the unit-test which calls `MapDeclDIEToDefDIE` directly.
1 parent 28d1490 commit c660b28

File tree

2 files changed

+176
-10
lines changed

2 files changed

+176
-10
lines changed

lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "UniqueDWARFASTType.h"
10+
#include "SymbolFileDWARF.h"
1011

1112
#include "lldb/Core/Declaration.h"
13+
#include "lldb/Target/Language.h"
1214

1315
using namespace lldb_private::dwarf;
1416
using namespace lldb_private::plugin::dwarf;
@@ -18,24 +20,45 @@ static bool IsStructOrClassTag(llvm::dwarf::Tag Tag) {
1820
Tag == llvm::dwarf::Tag::DW_TAG_structure_type;
1921
}
2022

23+
static bool IsSizeAndDeclarationMatching(UniqueDWARFASTType const &udt,
24+
DWARFDIE const &die,
25+
const lldb_private::Declaration &decl,
26+
const int32_t byte_size,
27+
bool is_forward_declaration) {
28+
29+
// If they are not both definition DIEs or both declaration DIEs, then
30+
// don't check for byte size and declaration location, because declaration
31+
// DIEs usually don't have those info.
32+
if (udt.m_is_forward_declaration != is_forward_declaration)
33+
return true;
34+
35+
if (udt.m_byte_size > 0 && byte_size > 0 && udt.m_byte_size != byte_size)
36+
return false;
37+
38+
// For C++, we match the behaviour of
39+
// DWARFASTParserClang::GetUniqueTypeNameAndDeclaration. We rely on the
40+
// one-definition-rule: for a given fully qualified name there exists only one
41+
// definition, and there should only be one entry for such name, so ignore
42+
// location of where it was declared vs. defined.
43+
if (lldb_private::Language::LanguageIsCPlusPlus(
44+
SymbolFileDWARF::GetLanguage(*die.GetCU())))
45+
return true;
46+
47+
return udt.m_declaration == decl;
48+
}
49+
2150
UniqueDWARFASTType *UniqueDWARFASTTypeList::Find(
2251
const DWARFDIE &die, const lldb_private::Declaration &decl,
2352
const int32_t byte_size, bool is_forward_declaration) {
2453
for (UniqueDWARFASTType &udt : m_collection) {
2554
// Make sure the tags match
2655
if (udt.m_die.Tag() == die.Tag() || (IsStructOrClassTag(udt.m_die.Tag()) &&
2756
IsStructOrClassTag(die.Tag()))) {
28-
// If they are not both definition DIEs or both declaration DIEs, then
29-
// don't check for byte size and declaration location, because declaration
30-
// DIEs usually don't have those info.
31-
bool matching_size_declaration =
32-
udt.m_is_forward_declaration != is_forward_declaration
33-
? true
34-
: (udt.m_byte_size < 0 || byte_size < 0 ||
35-
udt.m_byte_size == byte_size) &&
36-
udt.m_declaration == decl;
37-
if (!matching_size_declaration)
57+
58+
if (!IsSizeAndDeclarationMatching(udt, die, decl, byte_size,
59+
is_forward_declaration))
3860
continue;
61+
3962
// The type has the same name, and was defined on the same file and
4063
// line. Now verify all of the parent DIEs match.
4164
DWARFDIE parent_arg_die = die.GetParent();

lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,3 +598,146 @@ TEST_F(DWARFASTParserClangTests, TestDefaultTemplateParamParsing) {
598598
}
599599
}
600600
}
601+
602+
TEST_F(DWARFASTParserClangTests, TestUniqueDWARFASTTypeMap_CppInsertMapFind) {
603+
// This tests the behaviour of UniqueDWARFASTTypeMap under
604+
// following scenario:
605+
// 1. DWARFASTParserClang parses a forward declaration and
606+
// inserts it into the UniqueDWARFASTTypeMap.
607+
// 2. We then MapDeclDIEToDefDIE which updates the map
608+
// entry with the line number/file information of the definition.
609+
// 3. Parse the definition DIE, which should return the previously
610+
// parsed type from the UniqueDWARFASTTypeMap.
611+
612+
const char *yamldata = R"(
613+
--- !ELF
614+
FileHeader:
615+
Class: ELFCLASS64
616+
Data: ELFDATA2LSB
617+
Type: ET_EXEC
618+
Machine: EM_AARCH64
619+
DWARF:
620+
debug_str:
621+
- Foo
622+
623+
debug_line:
624+
- Version: 4
625+
MinInstLength: 1
626+
MaxOpsPerInst: 1
627+
DefaultIsStmt: 1
628+
LineBase: 0
629+
LineRange: 0
630+
Files:
631+
- Name: main.cpp
632+
DirIdx: 0
633+
ModTime: 0
634+
Length: 0
635+
636+
debug_abbrev:
637+
- ID: 0
638+
Table:
639+
- Code: 0x01
640+
Tag: DW_TAG_compile_unit
641+
Children: DW_CHILDREN_yes
642+
Attributes:
643+
- Attribute: DW_AT_language
644+
Form: DW_FORM_data2
645+
- Attribute: DW_AT_stmt_list
646+
Form: DW_FORM_sec_offset
647+
- Code: 0x02
648+
Tag: DW_TAG_structure_type
649+
Children: DW_CHILDREN_no
650+
Attributes:
651+
- Attribute: DW_AT_name
652+
Form: DW_FORM_strp
653+
- Attribute: DW_AT_declaration
654+
Form: DW_FORM_flag_present
655+
- Code: 0x03
656+
Tag: DW_TAG_structure_type
657+
Children: DW_CHILDREN_no
658+
Attributes:
659+
- Attribute: DW_AT_name
660+
Form: DW_FORM_strp
661+
- Attribute: DW_AT_decl_file
662+
Form: DW_FORM_data1
663+
- Attribute: DW_AT_decl_line
664+
Form: DW_FORM_data1
665+
666+
debug_info:
667+
- Version: 5
668+
UnitType: DW_UT_compile
669+
AddrSize: 8
670+
Entries:
671+
# 0x0c: DW_TAG_compile_unit
672+
# DW_AT_language [DW_FORM_data2] (DW_LANG_C_plus_plus)
673+
# DW_AT_stmt_list [DW_FORM_sec_offset]
674+
- AbbrCode: 0x01
675+
Values:
676+
- Value: 0x04
677+
- Value: 0x0000000000000000
678+
679+
# 0x0d: DW_TAG_structure_type
680+
# DW_AT_name [DW_FORM_strp] (\"Foo\")
681+
# DW_AT_declaration [DW_FORM_flag_present] (true)
682+
- AbbrCode: 0x02
683+
Values:
684+
- Value: 0x00
685+
686+
# 0x0f: DW_TAG_structure_type
687+
# DW_AT_name [DW_FORM_strp] (\"Foo\")
688+
# DW_AT_decl_file [DW_FORM_data1] (main.cpp)
689+
# DW_AT_decl_line [DW_FORM_data1] (3)
690+
- AbbrCode: 0x03
691+
Values:
692+
- Value: 0x00
693+
- Value: 0x01
694+
- Value: 0x03
695+
696+
- AbbrCode: 0x00 # end of child tags of 0x0c
697+
...
698+
)";
699+
YAMLModuleTester t(yamldata);
700+
701+
DWARFUnit *unit = t.GetDwarfUnit();
702+
ASSERT_NE(unit, nullptr);
703+
const DWARFDebugInfoEntry *cu_entry = unit->DIE().GetDIE();
704+
ASSERT_EQ(cu_entry->Tag(), DW_TAG_compile_unit);
705+
ASSERT_EQ(unit->GetDWARFLanguageType(), DW_LANG_C_plus_plus);
706+
DWARFDIE cu_die(unit, cu_entry);
707+
708+
auto holder = std::make_unique<clang_utils::TypeSystemClangHolder>("ast");
709+
auto &ast_ctx = *holder->GetAST();
710+
DWARFASTParserClangStub ast_parser(ast_ctx);
711+
712+
DWARFDIE decl_die;
713+
DWARFDIE def_die;
714+
for (auto const &die : cu_die.children()) {
715+
if (die.Tag() != DW_TAG_structure_type)
716+
continue;
717+
718+
if (die.GetAttributeValueAsOptionalUnsigned(llvm::dwarf::DW_AT_declaration))
719+
decl_die = die;
720+
else
721+
def_die = die;
722+
}
723+
724+
ASSERT_TRUE(decl_die.IsValid());
725+
ASSERT_TRUE(def_die.IsValid());
726+
ASSERT_NE(decl_die, def_die);
727+
728+
ParsedDWARFTypeAttributes attrs(def_die);
729+
ASSERT_TRUE(attrs.decl.IsValid());
730+
731+
SymbolContext sc;
732+
bool new_type = false;
733+
lldb::TypeSP type_sp = ast_parser.ParseTypeFromDWARF(sc, decl_die, &new_type);
734+
ASSERT_NE(type_sp, nullptr);
735+
736+
ast_parser.MapDeclDIEToDefDIE(decl_die, def_die);
737+
738+
lldb::TypeSP reparsed_type_sp =
739+
ast_parser.ParseTypeFromDWARF(sc, def_die, &new_type);
740+
ASSERT_NE(reparsed_type_sp, nullptr);
741+
742+
ASSERT_EQ(type_sp, reparsed_type_sp);
743+
}

0 commit comments

Comments
 (0)