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