LLVM  14.0.0git
DWARFLinkerDeclContext.cpp
Go to the documentation of this file.
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 
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.
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 
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:
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);
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),
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(),
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
llvm::DWARFContext::getLineTableForUnit
const DWARFDebugLine::LineTable * getLineTableForUnit(DWARFUnit *U)
Get a pointer to a parsed line table corresponding to a compile unit.
Definition: DWARFContext.cpp:929
llvm::CompileUnit::getOrigUnit
DWARFUnit & getOrigUnit() const
Definition: DWARFLinkerCompileUnit.h:100
llvm::CompileUnit::DIEInfo::Ctxt
DeclContext * Ctxt
ODR Declaration context.
Definition: DWARFLinkerCompileUnit.h:58
llvm
---------------------— PointerInfo ------------------------------------—
Definition: AllocatorList.h:23
llvm::StringRef::empty
LLVM_NODISCARD bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:153
llvm::CompileUnit::getInfo
DIEInfo & getInfo(unsigned Idx)
Definition: DWARFLinkerCompileUnit.h:120
llvm::DeclContext
A DeclContext is a named program scope that is used for ODR uniquing of types.
Definition: DWARFLinkerDeclContext.h:77
llvm::detail::DenseSetImpl::find
iterator find(const_arg_type_t< ValueT > V)
Definition: DenseSet.h:179
DWARFContext.h
llvm::CachedPathResolver::resolve
StringRef resolve(const std::string &Path, NonRelocatableStringpool &StringPool)
Resolve a path by calling realpath and cache its result.
Definition: DWARFLinkerDeclContext.h:35
llvm::DIE
A structured debug information entry.
Definition: DIE.h:739
llvm::DIE::getTag
dwarf::Tag getTag() const
Definition: DIE.h:775
llvm::DINameKind::LinkageName
@ LinkageName
llvm::detail::DenseSetImpl::insert
std::pair< iterator, bool > insert(const ValueT &V)
Definition: DenseSet.h:206
llvm::AArch64CC::LT
@ LT
Definition: AArch64BaseInfo.h:266
Context
LLVMContext & Context
Definition: NVVMIntrRange.cpp:66
llvm::DenseMapBase< DenseMap< std::pair< unsigned, unsigned >, StringRef, DenseMapInfo< std::pair< unsigned, unsigned > >, llvm::detail::DenseMapPair< std::pair< unsigned, unsigned >, StringRef > >, std::pair< unsigned, unsigned >, StringRef, DenseMapInfo< std::pair< unsigned, unsigned > >, llvm::detail::DenseMapPair< std::pair< unsigned, unsigned >, StringRef > >::const_iterator
DenseMapIterator< std::pair< unsigned, unsigned >, StringRef, DenseMapInfo< std::pair< unsigned, unsigned > >, llvm::detail::DenseMapPair< std::pair< unsigned, unsigned >, StringRef >, true > const_iterator
Definition: DenseMap.h:72
llvm::detail::DenseSetImpl::end
iterator end()
Definition: DenseSet.h:174
llvm::AMDGPU::PALMD::Key
Key
PAL metadata keys.
Definition: AMDGPUMetadata.h:481
DWARFDie.h
llvm::DeclContext::setLastSeenDIE
bool setLastSeenDIE(CompileUnit &U, const DWARFDie &Die)
Set the last DIE/CU a context was seen in and, possibly invalidate the context if it is ambiguous.
Definition: DWARFLinkerDeclContext.cpp:30
llvm::CompileUnit::getUniqueID
unsigned getUniqueID() const
Definition: DWARFLinkerCompileUnit.h:102
llvm::NonRelocatableStringpool::internString
StringRef internString(StringRef S)
Get permanent storage for S (but do not necessarily emit S in the output section).
Definition: NonRelocatableStringpool.cpp:30
llvm::DeclContextTree::getChildDeclContext
PointerIntPair< DeclContext *, 1 > getChildDeclContext(DeclContext &Context, const DWARFDie &DIE, CompileUnit &Unit, bool InClangModule)
Get the child of Context described by DIE in Unit.
Definition: DWARFLinkerDeclContext.cpp:44
llvm::DINameKind::ShortName
@ ShortName
llvm::DWARFDebugLine::LineTable::getFileNameByIndex
bool getFileNameByIndex(uint64_t FileIndex, StringRef CompDir, DILineInfoSpecifier::FileLineInfoKind Kind, std::string &Result) const
Extracts filename by its index in filename table in prologue.
Definition: DWARFDebugLine.h:261
llvm::CompileUnit
Stores all information relating to a compile unit, be it in its original instance in the object file ...
Definition: DWARFLinkerCompileUnit.h:50
DWARFUnit.h
llvm::DenseMapBase::find
iterator find(const_arg_type_t< KeyT > Val)
Definition: DenseMap.h:150
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:58
llvm::DWARFUnit::getContext
DWARFContext & getContext() const
Definition: DWARFUnit.h:279
uint32_t
LLVM_FALLTHROUGH
#define LLVM_FALLTHROUGH
LLVM_FALLTHROUGH - Mark fallthrough cases in switch statements.
Definition: Compiler.h:273
llvm::DenseMapBase::insert
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition: DenseMap.h:207
llvm::DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath
@ AbsoluteFilePath
llvm::DenseMapBase::end
iterator end()
Definition: DenseMap.h:83
llvm::DWARFUnit
Definition: DWARFUnit.h:203
llvm::dwarf::toUnsigned
Optional< uint64_t > toUnsigned(const Optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract an unsigned constant.
Definition: DWARFFormValue.h:210
llvm::PointerIntPair
PointerIntPair - This class implements a pair of a pointer and small integer.
Definition: PointerIntPair.h:45
llvm::hash_combine
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
Definition: Hashing.h:604
DWARFLinkerDeclContext.h
llvm::max
Align max(MaybeAlign Lhs, Align Rhs)
Definition: Alignment.h:340
llvm::DWARFDebugLine::LineTable
Definition: DWARFDebugLine.h:229
llvm::DWARFDie
Utility class that carries the DWARF compile/type unit and the debug info entry in an object.
Definition: DWARFDie.h:43
CU
Definition: AArch64AsmBackend.cpp:501