1 //===- DWARFLinkerDeclContext.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 "llvm/DWARFLinker/DWARFLinkerDeclContext.h" 10 #include "llvm/DebugInfo/DWARF/DWARFContext.h" 11 #include "llvm/DebugInfo/DWARF/DWARFDie.h" 12 #include "llvm/DebugInfo/DWARF/DWARFUnit.h" 13 14 namespace llvm { 15 16 /// Set the last DIE/CU a context was seen in and, possibly invalidate the 17 /// context if it is ambiguous. 18 /// 19 /// In the current implementation, we don't handle overloaded functions well, 20 /// because the argument types are not taken into account when computing the 21 /// DeclContext tree. 22 /// 23 /// Some of this is mitigated byt using mangled names that do contain the 24 /// arguments types, but sometimes (e.g. with function templates) we don't have 25 /// that. In that case, just do not unique anything that refers to the contexts 26 /// we are not able to distinguish. 27 /// 28 /// If a context that is not a namespace appears twice in the same CU, we know 29 /// it is ambiguous. Make it invalid. 30 bool DeclContext::setLastSeenDIE(CompileUnit &U, const DWARFDie &Die) { 31 if (LastSeenCompileUnitID == U.getUniqueID()) { 32 DWARFUnit &OrigUnit = U.getOrigUnit(); 33 uint32_t FirstIdx = OrigUnit.getDIEIndex(LastSeenDIE); 34 U.getInfo(FirstIdx).Ctxt = nullptr; 35 return false; 36 } 37 38 LastSeenCompileUnitID = U.getUniqueID(); 39 LastSeenDIE = Die; 40 return true; 41 } 42 43 PointerIntPair<DeclContext *, 1> 44 DeclContextTree::getChildDeclContext(DeclContext &Context, const DWARFDie &DIE, 45 CompileUnit &U, bool InClangModule) { 46 unsigned Tag = DIE.getTag(); 47 48 // FIXME: dsymutil-classic compat: We should bail out here if we 49 // have a specification or an abstract_origin. We will get the 50 // parent context wrong here. 51 52 switch (Tag) { 53 default: 54 // By default stop gathering child contexts. 55 return PointerIntPair<DeclContext *, 1>(nullptr); 56 case dwarf::DW_TAG_module: 57 break; 58 case dwarf::DW_TAG_compile_unit: 59 return PointerIntPair<DeclContext *, 1>(&Context); 60 case dwarf::DW_TAG_subprogram: 61 // Do not unique anything inside CU local functions. 62 if ((Context.getTag() == dwarf::DW_TAG_namespace || 63 Context.getTag() == dwarf::DW_TAG_compile_unit) && 64 !dwarf::toUnsigned(DIE.find(dwarf::DW_AT_external), 0)) 65 return PointerIntPair<DeclContext *, 1>(nullptr); 66 LLVM_FALLTHROUGH; 67 case dwarf::DW_TAG_member: 68 case dwarf::DW_TAG_namespace: 69 case dwarf::DW_TAG_structure_type: 70 case dwarf::DW_TAG_class_type: 71 case dwarf::DW_TAG_union_type: 72 case dwarf::DW_TAG_enumeration_type: 73 case dwarf::DW_TAG_typedef: 74 // Artificial things might be ambiguous, because they might be created on 75 // demand. For example implicitly defined constructors are ambiguous 76 // because of the way we identify contexts, and they won't be generated 77 // every time everywhere. 78 if (dwarf::toUnsigned(DIE.find(dwarf::DW_AT_artificial), 0)) 79 return PointerIntPair<DeclContext *, 1>(nullptr); 80 break; 81 } 82 83 StringRef NameRef; 84 StringRef FileRef; 85 86 if (const char *LinkageName = DIE.getLinkageName()) 87 NameRef = StringPool.internString(LinkageName); 88 else if (const char *ShortName = DIE.getShortName()) 89 NameRef = StringPool.internString(ShortName); 90 91 bool IsAnonymousNamespace = NameRef.empty() && Tag == dwarf::DW_TAG_namespace; 92 if (IsAnonymousNamespace) { 93 // FIXME: For dsymutil-classic compatibility. I think uniquing within 94 // anonymous namespaces is wrong. There is no ODR guarantee there. 95 NameRef = "(anonymous namespace)"; 96 } 97 98 if (Tag != dwarf::DW_TAG_class_type && Tag != dwarf::DW_TAG_structure_type && 99 Tag != dwarf::DW_TAG_union_type && 100 Tag != dwarf::DW_TAG_enumeration_type && NameRef.empty()) 101 return PointerIntPair<DeclContext *, 1>(nullptr); 102 103 unsigned Line = 0; 104 unsigned ByteSize = std::numeric_limits<uint32_t>::max(); 105 106 if (!InClangModule) { 107 // Gather some discriminating data about the DeclContext we will be 108 // creating: File, line number and byte size. This shouldn't be necessary, 109 // because the ODR is just about names, but given that we do some 110 // approximations with overloaded functions and anonymous namespaces, use 111 // these additional data points to make the process safer. 112 // 113 // This is disabled for clang modules, because forward declarations of 114 // module-defined types do not have a file and line. 115 ByteSize = dwarf::toUnsigned(DIE.find(dwarf::DW_AT_byte_size), 116 std::numeric_limits<uint64_t>::max()); 117 if (Tag != dwarf::DW_TAG_namespace || IsAnonymousNamespace) { 118 if (unsigned FileNum = 119 dwarf::toUnsigned(DIE.find(dwarf::DW_AT_decl_file), 0)) { 120 if (const auto *LT = U.getOrigUnit().getContext().getLineTableForUnit( 121 &U.getOrigUnit())) { 122 // FIXME: dsymutil-classic compatibility. I'd rather not 123 // unique anything in anonymous namespaces, but if we do, then 124 // verify that the file and line correspond. 125 if (IsAnonymousNamespace) 126 FileNum = 1; 127 128 if (LT->hasFileAtIndex(FileNum)) { 129 Line = dwarf::toUnsigned(DIE.find(dwarf::DW_AT_decl_line), 0); 130 // Cache the resolved paths based on the index in the line table, 131 // because calling realpath is expensive. 132 FileRef = getResolvedPath(U, FileNum, *LT); 133 } 134 } 135 } 136 } 137 } 138 139 if (!Line && NameRef.empty()) 140 return PointerIntPair<DeclContext *, 1>(nullptr); 141 142 // We hash NameRef, which is the mangled name, in order to get most 143 // overloaded functions resolve correctly. 144 // 145 // Strictly speaking, hashing the Tag is only necessary for a 146 // DW_TAG_module, to prevent uniquing of a module and a namespace 147 // with the same name. 148 // 149 // FIXME: dsymutil-classic won't unique the same type presented 150 // once as a struct and once as a class. Using the Tag in the fully 151 // qualified name hash to get the same effect. 152 unsigned Hash = hash_combine(Context.getQualifiedNameHash(), Tag, NameRef); 153 154 // FIXME: dsymutil-classic compatibility: when we don't have a name, 155 // use the filename. 156 if (IsAnonymousNamespace) 157 Hash = hash_combine(Hash, FileRef); 158 159 // Now look if this context already exists. 160 DeclContext Key(Hash, Line, ByteSize, Tag, NameRef, FileRef, Context); 161 auto ContextIter = Contexts.find(&Key); 162 163 if (ContextIter == Contexts.end()) { 164 // The context wasn't found. 165 bool Inserted; 166 DeclContext *NewContext = 167 new (Allocator) DeclContext(Hash, Line, ByteSize, Tag, NameRef, FileRef, 168 Context, DIE, U.getUniqueID()); 169 std::tie(ContextIter, Inserted) = Contexts.insert(NewContext); 170 assert(Inserted && "Failed to insert DeclContext"); 171 (void)Inserted; 172 } else if (Tag != dwarf::DW_TAG_namespace && 173 !(*ContextIter)->setLastSeenDIE(U, DIE)) { 174 // The context was found, but it is ambiguous with another context 175 // in the same file. Mark it invalid. 176 return PointerIntPair<DeclContext *, 1>(*ContextIter, /* Invalid= */ 1); 177 } 178 179 assert(ContextIter != Contexts.end()); 180 // FIXME: dsymutil-classic compatibility. Union types aren't 181 // uniques, but their children might be. 182 if ((Tag == dwarf::DW_TAG_subprogram && 183 Context.getTag() != dwarf::DW_TAG_structure_type && 184 Context.getTag() != dwarf::DW_TAG_class_type) || 185 (Tag == dwarf::DW_TAG_union_type)) 186 return PointerIntPair<DeclContext *, 1>(*ContextIter, /* Invalid= */ 1); 187 188 return PointerIntPair<DeclContext *, 1>(*ContextIter); 189 } 190 191 StringRef 192 DeclContextTree::getResolvedPath(CompileUnit &CU, unsigned FileNum, 193 const DWARFDebugLine::LineTable &LineTable) { 194 std::pair<unsigned, unsigned> Key = {CU.getUniqueID(), FileNum}; 195 196 ResolvedPathsMap::const_iterator It = ResolvedPaths.find(Key); 197 if (It == ResolvedPaths.end()) { 198 std::string FileName; 199 bool FoundFileName = LineTable.getFileNameByIndex( 200 FileNum, CU.getOrigUnit().getCompilationDir(), 201 DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FileName); 202 (void)FoundFileName; 203 assert(FoundFileName && "Must get file name from line table"); 204 205 // Second level of caching, this time based on the file's parent 206 // path. 207 StringRef ResolvedPath = PathResolver.resolve(FileName, StringPool); 208 209 It = ResolvedPaths.insert(std::make_pair(Key, ResolvedPath)).first; 210 } 211 212 return It->second; 213 } 214 215 } // namespace llvm 216