| 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 | language: SymbolFileDWARF::GetLanguage(unit&: *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(Tag: udt.m_die.Tag()) && |
| 56 | IsStructOrClassTag(Tag: 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(Tag: parent_arg_tag) && |
| 73 | IsStructOrClassTag(Tag: 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(s1: parent_arg_die_name, s2: 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 | |