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