Home | History | Annotate | Line # | Download | only in DWARFLinker
      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