brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.8 KiB · 66a1ba9 Raw
224 lines · cpp
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-exception6//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 15namespace llvm {16 17using namespace dwarf_linker;18using namespace dwarf_linker::classic;19 20/// Set the last DIE/CU a context was seen in and, possibly invalidate the21/// 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 the25/// DeclContext tree.26///27/// Some of this is mitigated byt using mangled names that do contain the28/// arguments types, but sometimes (e.g. with function templates) we don't have29/// that. In that case, just do not unique anything that refers to the contexts30/// we are not able to distinguish.31///32/// If a context that is not a namespace appears twice in the same CU, we know33/// it is ambiguous. Make it invalid.34bool 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 47PointerIntPair<DeclContext *, 1>48DeclContextTree::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 we53  // have a specification or an abstract_origin. We will get the54  // 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 on79    // demand. For example implicitly defined constructors are ambiguous80    // because of the way we identify contexts, and they won't be generated81    // 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 Name = DIE.getShortName();88  StringRef NameForUniquing;89  StringRef FileRef;90 91  if (const char *LinkageName = DIE.getLinkageName())92    NameForUniquing = StringPool.internString(LinkageName);93  else if (!Name.empty())94    NameForUniquing = StringPool.internString(Name);95 96  bool IsAnonymousNamespace =97      NameForUniquing.empty() && Tag == dwarf::DW_TAG_namespace;98  if (IsAnonymousNamespace) {99    // FIXME: For dsymutil-classic compatibility. I think uniquing within100    // anonymous namespaces is wrong. There is no ODR guarantee there.101    NameForUniquing = "(anonymous namespace)";102  }103 104  if (Tag != dwarf::DW_TAG_class_type && Tag != dwarf::DW_TAG_structure_type &&105      Tag != dwarf::DW_TAG_union_type &&106      Tag != dwarf::DW_TAG_enumeration_type && NameForUniquing.empty())107    return PointerIntPair<DeclContext *, 1>(nullptr);108 109  unsigned Line = 0;110  unsigned ByteSize = std::numeric_limits<uint32_t>::max();111 112  if (!InClangModule) {113    // Gather some discriminating data about the DeclContext we will be114    // creating: File, line number and byte size. This shouldn't be necessary,115    // because the ODR is just about names, but given that we do some116    // approximations with overloaded functions and anonymous namespaces, use117    // these additional data points to make the process safer.118    //119    // This is disabled for clang modules, because forward declarations of120    // module-defined types do not have a file and line.121    ByteSize = dwarf::toUnsigned(DIE.find(dwarf::DW_AT_byte_size),122                                 std::numeric_limits<uint64_t>::max());123    if (Tag != dwarf::DW_TAG_namespace || IsAnonymousNamespace) {124      if (unsigned FileNum =125              dwarf::toUnsigned(DIE.find(dwarf::DW_AT_decl_file), 0)) {126        if (const auto *LT = U.getOrigUnit().getContext().getLineTableForUnit(127                &U.getOrigUnit())) {128          // FIXME: dsymutil-classic compatibility. I'd rather not129          // unique anything in anonymous namespaces, but if we do, then130          // verify that the file and line correspond.131          if (IsAnonymousNamespace)132            FileNum = 1;133 134          if (LT->hasFileAtIndex(FileNum)) {135            Line = dwarf::toUnsigned(DIE.find(dwarf::DW_AT_decl_line), 0);136            // Cache the resolved paths based on the index in the line table,137            // because calling realpath is expensive.138            FileRef = getResolvedPath(U, FileNum, *LT);139          }140        }141      }142    }143  }144 145  if (!Line && NameForUniquing.empty())146    return PointerIntPair<DeclContext *, 1>(nullptr);147 148  // We hash NameForUniquing, which is the mangled name, in order to get most149  // overloaded functions resolve correctly.150  //151  // Strictly speaking, hashing the Tag is only necessary for a152  // DW_TAG_module, to prevent uniquing of a module and a namespace153  // with the same name.154  //155  // FIXME: dsymutil-classic won't unique the same type presented156  // once as a struct and once as a class. Using the Tag in the fully157  // qualified name hash to get the same effect.158  unsigned Hash =159      hash_combine(Context.getQualifiedNameHash(), Tag, NameForUniquing);160 161  // FIXME: dsymutil-classic compatibility: when we don't have a name,162  // use the filename.163  if (IsAnonymousNamespace)164    Hash = hash_combine(Hash, FileRef);165 166  // Now look if this context already exists.167  DeclContext Key(Hash, Line, ByteSize, Tag, Name, NameForUniquing, FileRef,168                  Context);169  auto ContextIter = Contexts.find(&Key);170 171  if (ContextIter == Contexts.end()) {172    // The context wasn't found.173    bool Inserted;174    DeclContext *NewContext = new (Allocator)175        DeclContext(Hash, Line, ByteSize, Tag, Name, NameForUniquing, FileRef,176                    Context, DIE, U.getUniqueID());177    std::tie(ContextIter, Inserted) = Contexts.insert(NewContext);178    assert(Inserted && "Failed to insert DeclContext");179    (void)Inserted;180  } else if (Tag != dwarf::DW_TAG_namespace &&181             !(*ContextIter)->setLastSeenDIE(U, DIE)) {182    // The context was found, but it is ambiguous with another context183    // in the same file. Mark it invalid.184    return PointerIntPair<DeclContext *, 1>(*ContextIter, /* IntVal= */ 1);185  }186 187  assert(ContextIter != Contexts.end());188  // FIXME: dsymutil-classic compatibility. Union types aren't189  // uniques, but their children might be.190  if ((Tag == dwarf::DW_TAG_subprogram &&191       Context.getTag() != dwarf::DW_TAG_structure_type &&192       Context.getTag() != dwarf::DW_TAG_class_type) ||193      (Tag == dwarf::DW_TAG_union_type))194    return PointerIntPair<DeclContext *, 1>(*ContextIter, /* IntVal= */ 1);195 196  return PointerIntPair<DeclContext *, 1>(*ContextIter);197}198 199StringRef200DeclContextTree::getResolvedPath(CompileUnit &CU, unsigned FileNum,201                                 const DWARFDebugLine::LineTable &LineTable) {202  std::pair<unsigned, unsigned> Key = {CU.getUniqueID(), FileNum};203 204  ResolvedPathsMap::const_iterator It = ResolvedPaths.find(Key);205  if (It == ResolvedPaths.end()) {206    std::string FileName;207    bool FoundFileName = LineTable.getFileNameByIndex(208        FileNum, CU.getOrigUnit().getCompilationDir(),209        DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FileName);210    (void)FoundFileName;211    assert(FoundFileName && "Must get file name from line table");212 213    // Second level of caching, this time based on the file's parent214    // path.215    StringRef ResolvedPath = PathResolver.resolve(FileName, StringPool);216 217    It = ResolvedPaths.insert(std::make_pair(Key, ResolvedPath)).first;218  }219 220  return It->second;221}222 223} // namespace llvm224