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