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 14namespace 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. 30bool 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 43PointerIntPair<DeclContext *, 1> DeclContextTree::getChildDeclContext( 44 DeclContext &Context, const DWARFDie &DIE, CompileUnit &U, 45 UniquingStringPool &StringPool, 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 const char *Name = DIE.getLinkageName(); 84 const char *ShortName = DIE.getShortName(); 85 86 if (!Name) 87 Name = ShortName; 88 89 StringRef NameRef; 90 StringRef ShortNameRef; 91 StringRef FileRef; 92 93 if (Name) 94 NameRef = StringPool.internString(Name); 95 else if (Tag == dwarf::DW_TAG_namespace) 96 // FIXME: For dsymutil-classic compatibility. I think uniquing within 97 // anonymous namespaces is wrong. There is no ODR guarantee there. 98 NameRef = StringPool.internString("(anonymous namespace)"); 99 100 if (ShortName && ShortName != Name) 101 ShortNameRef = StringPool.internString(ShortName); 102 else 103 ShortNameRef = NameRef; 104 105 if (Tag != dwarf::DW_TAG_class_type && Tag != dwarf::DW_TAG_structure_type && 106 Tag != dwarf::DW_TAG_union_type && 107 Tag != dwarf::DW_TAG_enumeration_type && NameRef.empty()) 108 return PointerIntPair<DeclContext *, 1>(nullptr); 109 110 unsigned Line = 0; 111 unsigned ByteSize = std::numeric_limits<uint32_t>::max(); 112 113 if (!InClangModule) { 114 // Gather some discriminating data about the DeclContext we will be 115 // creating: File, line number and byte size. This shouldn't be necessary, 116 // because the ODR is just about names, but given that we do some 117 // approximations with overloaded functions and anonymous namespaces, use 118 // these additional data points to make the process safer. 119 // 120 // This is disabled for clang modules, because forward declarations of 121 // module-defined types do not have a file and line. 122 ByteSize = dwarf::toUnsigned(DIE.find(dwarf::DW_AT_byte_size), 123 std::numeric_limits<uint64_t>::max()); 124 if (Tag != dwarf::DW_TAG_namespace || !Name) { 125 if (unsigned FileNum = 126 dwarf::toUnsigned(DIE.find(dwarf::DW_AT_decl_file), 0)) { 127 if (const auto *LT = U.getOrigUnit().getContext().getLineTableForUnit( 128 &U.getOrigUnit())) { 129 // FIXME: dsymutil-classic compatibility. I'd rather not 130 // unique anything in anonymous namespaces, but if we do, then 131 // verify that the file and line correspond. 132 if (!Name && Tag == dwarf::DW_TAG_namespace) 133 FileNum = 1; 134 135 if (LT->hasFileAtIndex(FileNum)) { 136 Line = dwarf::toUnsigned(DIE.find(dwarf::DW_AT_decl_line), 0); 137 // Cache the resolved paths based on the index in the line table, 138 // because calling realpath is expansive. 139 StringRef ResolvedPath = U.getResolvedPath(FileNum); 140 if (!ResolvedPath.empty()) { 141 FileRef = ResolvedPath; 142 } else { 143 std::string File; 144 bool FoundFileName = LT->getFileNameByIndex( 145 FileNum, U.getOrigUnit().getCompilationDir(), 146 DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, 147 File); 148 (void)FoundFileName; 149 assert(FoundFileName && "Must get file name from line table"); 150 // Second level of caching, this time based on the file's parent 151 // path. 152 FileRef = PathResolver.resolve(File, StringPool); 153 U.setResolvedPath(FileNum, FileRef); 154 } 155 } 156 } 157 } 158 } 159 } 160 161 if (!Line && NameRef.empty()) 162 return PointerIntPair<DeclContext *, 1>(nullptr); 163 164 // We hash NameRef, which is the mangled name, in order to get most 165 // overloaded functions resolve correctly. 166 // 167 // Strictly speaking, hashing the Tag is only necessary for a 168 // DW_TAG_module, to prevent uniquing of a module and a namespace 169 // with the same name. 170 // 171 // FIXME: dsymutil-classic won't unique the same type presented 172 // once as a struct and once as a class. Using the Tag in the fully 173 // qualified name hash to get the same effect. 174 unsigned Hash = hash_combine(Context.getQualifiedNameHash(), Tag, NameRef); 175 176 // FIXME: dsymutil-classic compatibility: when we don't have a name, 177 // use the filename. 178 if (Tag == dwarf::DW_TAG_namespace && NameRef == "(anonymous namespace)") 179 Hash = hash_combine(Hash, FileRef); 180 181 // Now look if this context already exists. 182 DeclContext Key(Hash, Line, ByteSize, Tag, NameRef, FileRef, Context); 183 auto ContextIter = Contexts.find(&Key); 184 185 if (ContextIter == Contexts.end()) { 186 // The context wasn't found. 187 bool Inserted; 188 DeclContext *NewContext = 189 new (Allocator) DeclContext(Hash, Line, ByteSize, Tag, NameRef, FileRef, 190 Context, DIE, U.getUniqueID()); 191 std::tie(ContextIter, Inserted) = Contexts.insert(NewContext); 192 assert(Inserted && "Failed to insert DeclContext"); 193 (void)Inserted; 194 } else if (Tag != dwarf::DW_TAG_namespace && 195 !(*ContextIter)->setLastSeenDIE(U, DIE)) { 196 // The context was found, but it is ambiguous with another context 197 // in the same file. Mark it invalid. 198 return PointerIntPair<DeclContext *, 1>(*ContextIter, /* Invalid= */ 1); 199 } 200 201 assert(ContextIter != Contexts.end()); 202 // FIXME: dsymutil-classic compatibility. Union types aren't 203 // uniques, but their children might be. 204 if ((Tag == dwarf::DW_TAG_subprogram && 205 Context.getTag() != dwarf::DW_TAG_structure_type && 206 Context.getTag() != dwarf::DW_TAG_class_type) || 207 (Tag == dwarf::DW_TAG_union_type)) 208 return PointerIntPair<DeclContext *, 1>(*ContextIter, /* Invalid= */ 1); 209 210 return PointerIntPair<DeclContext *, 1>(*ContextIter); 211} 212 213} // namespace llvm 214