xref: /llvm-project/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp (revision c660b281b60085cbe40d73d692badd43d7708d20)
1 //===-- UniqueDWARFASTType.cpp --------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "UniqueDWARFASTType.h"
10 #include "SymbolFileDWARF.h"
11 
12 #include "lldb/Core/Declaration.h"
13 #include "lldb/Target/Language.h"
14 
15 using namespace lldb_private::dwarf;
16 using namespace lldb_private::plugin::dwarf;
17 
18 static bool IsStructOrClassTag(llvm::dwarf::Tag Tag) {
19   return Tag == llvm::dwarf::Tag::DW_TAG_class_type ||
20          Tag == llvm::dwarf::Tag::DW_TAG_structure_type;
21 }
22 
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 
50 UniqueDWARFASTType *UniqueDWARFASTTypeList::Find(
51     const DWARFDIE &die, const lldb_private::Declaration &decl,
52     const int32_t byte_size, bool is_forward_declaration) {
53   for (UniqueDWARFASTType &udt : m_collection) {
54     // Make sure the tags match
55     if (udt.m_die.Tag() == die.Tag() || (IsStructOrClassTag(udt.m_die.Tag()) &&
56                                          IsStructOrClassTag(die.Tag()))) {
57 
58       if (!IsSizeAndDeclarationMatching(udt, die, decl, byte_size,
59                                         is_forward_declaration))
60         continue;
61 
62       // The type has the same name, and was defined on the same file and
63       // line. Now verify all of the parent DIEs match.
64       DWARFDIE parent_arg_die = die.GetParent();
65       DWARFDIE parent_pos_die = udt.m_die.GetParent();
66       bool match = true;
67       bool done = false;
68       while (!done && match && parent_arg_die && parent_pos_die) {
69         const dw_tag_t parent_arg_tag = parent_arg_die.Tag();
70         const dw_tag_t parent_pos_tag = parent_pos_die.Tag();
71         if (parent_arg_tag == parent_pos_tag ||
72             (IsStructOrClassTag(parent_arg_tag) &&
73              IsStructOrClassTag(parent_pos_tag))) {
74           switch (parent_arg_tag) {
75           case DW_TAG_class_type:
76           case DW_TAG_structure_type:
77           case DW_TAG_union_type:
78           case DW_TAG_namespace: {
79             const char *parent_arg_die_name = parent_arg_die.GetName();
80             if (parent_arg_die_name == nullptr) {
81               // Anonymous (i.e. no-name) struct
82               match = false;
83             } else {
84               const char *parent_pos_die_name = parent_pos_die.GetName();
85               if (parent_pos_die_name == nullptr ||
86                   ((parent_arg_die_name != parent_pos_die_name) &&
87                    strcmp(parent_arg_die_name, parent_pos_die_name)))
88                 match = false;
89             }
90           } break;
91 
92           case DW_TAG_compile_unit:
93           case DW_TAG_partial_unit:
94             done = true;
95             break;
96           default:
97             break;
98           }
99         }
100         parent_arg_die = parent_arg_die.GetParent();
101         parent_pos_die = parent_pos_die.GetParent();
102       }
103 
104       if (match) {
105         return &udt;
106       }
107     }
108   }
109   return nullptr;
110 }
111