LLVM 24.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
17
18namespace llvm {
19
20static std::optional<std::string>
22 std::string Result = Name.str();
23 raw_string_ostream OS(Result);
25 Printer.appendAndTerminateTemplateParameters(DIE);
26 if (Result == Name)
27 return std::nullopt;
28 return Result;
29}
30
31/// Bounds walks along DW_AT_type, which malformed input can make cyclic.
32static constexpr unsigned MaxTypeReferenceDepth = 256;
33
35 unsigned Depth);
36
37/// Appends the type \p DIE refers to, through unnamed types up to a named one.
39 unsigned Depth) {
40 for (; Depth < MaxTypeReferenceDepth; ++Depth) {
41 DWARFDie Type = DIE.getAttributeValueAsReferencedDie(dwarf::DW_AT_type);
42 if (!Type)
43 return;
44 OS << '\0' << dwarf::TagString(Type.getTag());
45 if (const char *Name = Type.getShortName()) {
46 OS << '\0' << Name;
47 return;
48 }
50 DIE = Type;
51 }
52}
53
55 unsigned Depth) {
57 return;
58
59 OS << '\0' << '(';
60 for (const DWARFDie &Child : DIE.children()) {
62 continue;
63
64 OS << '\0' << dwarf::TagString(Child.getTag());
65 if (const char *Name = Child.getShortName())
66 OS << '\0' << Name;
68 }
69 OS << '\0' << ')';
70}
71
72using namespace dwarf_linker;
73using namespace dwarf_linker::classic;
74
75/// Set the last DIE/CU a context was seen in and, possibly invalidate the
76/// context if it is ambiguous.
77///
78/// In the current implementation, we don't handle overloaded functions well,
79/// because the argument types are not taken into account when computing the
80/// DeclContext tree.
81///
82/// Some of this is mitigated byt using mangled names that do contain the
83/// arguments types, but sometimes (e.g. with function templates) we don't have
84/// that. In that case, just do not unique anything that refers to the contexts
85/// we are not able to distinguish.
86///
87/// If a context that is not a namespace appears twice in the same CU, we know
88/// it is ambiguous. Make it invalid.
90 if (LastSeenCompileUnitID == U.getUniqueID()) {
91 DWARFUnit &OrigUnit = U.getOrigUnit();
92 uint32_t FirstIdx = OrigUnit.getDIEIndex(LastSeenDIE);
93 U.getInfo(FirstIdx).Ctxt = nullptr;
94 return false;
95 }
96
97 LastSeenCompileUnitID = U.getUniqueID();
98 LastSeenDIE = Die;
99 return true;
100}
101
104 CompileUnit &U, bool InClangModule) {
105 unsigned Tag = DIE.getTag();
106
107 // FIXME: dsymutil-classic compat: We should bail out here if we
108 // have a specification or an abstract_origin. We will get the
109 // parent context wrong here.
110
111 switch (Tag) {
112 default:
113 // By default stop gathering child contexts.
114 return PointerIntPair<DeclContext *, 1>(nullptr);
115 case dwarf::DW_TAG_module:
116 break;
117 case dwarf::DW_TAG_compile_unit:
118 return PointerIntPair<DeclContext *, 1>(&Context);
119 case dwarf::DW_TAG_subprogram:
120 // Do not unique anything inside CU local functions.
121 if ((Context.getTag() == dwarf::DW_TAG_namespace ||
122 Context.getTag() == dwarf::DW_TAG_compile_unit) &&
123 !dwarf::toUnsigned(DIE.find(dwarf::DW_AT_external), 0))
124 return PointerIntPair<DeclContext *, 1>(nullptr);
125 [[fallthrough]];
126 case dwarf::DW_TAG_member:
127 case dwarf::DW_TAG_namespace:
128 case dwarf::DW_TAG_structure_type:
129 case dwarf::DW_TAG_class_type:
130 case dwarf::DW_TAG_union_type:
131 case dwarf::DW_TAG_enumeration_type:
132 case dwarf::DW_TAG_typedef:
133 // Artificial things might be ambiguous, because they might be created on
134 // demand. For example implicitly defined constructors are ambiguous
135 // because of the way we identify contexts, and they won't be generated
136 // every time everywhere.
137 if (dwarf::toUnsigned(DIE.find(dwarf::DW_AT_artificial), 0))
138 return PointerIntPair<DeclContext *, 1>(nullptr);
139 break;
140 }
141
142 StringRef Name = DIE.getShortName();
143 StringRef NameForUniquing;
144 StringRef FileRef;
145
146 if (const char *LinkageName = DIE.getLinkageName()) {
147 NameForUniquing = StringPool.internString(LinkageName);
148 } else if (!Name.empty()) {
149 // With -gsimple-template-names, DW_AT_name omits template parameters
150 // ("vector" instead of "vector<int>"). Reconstruct them from child
151 // DW_TAG_template_*_parameter DIEs so different specializations get
152 // distinct uniquing names.
153 bool HasTemplateParamsInName =
154 Name.ends_with(">") && !Name.ends_with("<=>") && Name.contains('<');
155 std::optional<std::string> FullName;
156 if (!HasTemplateParamsInName)
157 FullName = makeSimpleTemplateNameWithParams(Name, DIE);
158 NameForUniquing = StringPool.internString(FullName ? *FullName : Name);
159 }
160
161 // For typedefs, include the referenced type chain in the uniquing key. Two
162 // typedefs with the same name (e.g. from preferred_name) but different
163 // DW_AT_type targets must get different DeclContexts, otherwise ODR
164 // deduplication can create self-referencing typedef cycles in the output
165 // DWARF. Walk through unnamed wrapper types (pointers, references, const,
166 // etc.) to find a named type for disambiguation. This mirrors the parallel
167 // linker's behavior in SyntheticTypeNameBuilder::addTypeName.
168 if (Tag == dwarf::DW_TAG_typedef && !NameForUniquing.empty()) {
169 SmallString<128> Combined(NameForUniquing);
170 DWARFDie CurDie = DIE;
171 // Guard against malformed input DWARF with cycles in DW_AT_type references;
172 // the parallel linker uses a similar guard in addReferencedODRDies.
173 for (unsigned Depth = 0; Depth < MaxTypeReferenceDepth; ++Depth) {
174 auto TypeAttr = CurDie.find(dwarf::DW_AT_type);
175 if (!TypeAttr)
176 break;
177 auto RefDie = CurDie.getAttributeValueAsReferencedDie(*TypeAttr);
178 if (!RefDie)
179 break;
180 // Use null bytes as separators since they cannot appear in type names
181 // or tag strings, preventing accidental collisions.
182 Combined.push_back('\0');
183 Combined.append(dwarf::TagString(RefDie.getTag()));
184 StringRef RefName = RefDie.getShortName();
185 if (!RefName.empty()) {
186 Combined.push_back('\0');
187 Combined.append(RefName);
188 break;
189 }
190 CurDie = RefDie;
191 }
192 if (Combined.size() != NameForUniquing.size())
193 NameForUniquing = StringPool.internString(Combined);
194 }
195
196 bool IsAnonymousNamespace =
197 NameForUniquing.empty() && Tag == dwarf::DW_TAG_namespace;
198 if (IsAnonymousNamespace) {
199 // FIXME: For dsymutil-classic compatibility. I think uniquing within
200 // anonymous namespaces is wrong. There is no ODR guarantee there.
201 NameForUniquing = "(anonymous namespace)";
202 }
203
204 if (Tag != dwarf::DW_TAG_class_type && Tag != dwarf::DW_TAG_structure_type &&
205 Tag != dwarf::DW_TAG_union_type &&
206 Tag != dwarf::DW_TAG_enumeration_type && NameForUniquing.empty())
207 return PointerIntPair<DeclContext *, 1>(nullptr);
208
209 unsigned Line = 0;
210 unsigned ByteSize = std::numeric_limits<uint32_t>::max();
211
212 if (!InClangModule) {
213 // Gather some discriminating data about the DeclContext we will be
214 // creating: File, line number and byte size. This shouldn't be necessary,
215 // because the ODR is just about names, but given that we do some
216 // approximations with overloaded functions and anonymous namespaces, use
217 // these additional data points to make the process safer.
218 //
219 // This is disabled for clang modules, because forward declarations of
220 // module-defined types do not have a file and line.
221 ByteSize = dwarf::toUnsigned(DIE.find(dwarf::DW_AT_byte_size),
222 std::numeric_limits<uint64_t>::max());
223 if (Tag != dwarf::DW_TAG_namespace || IsAnonymousNamespace) {
224 if (unsigned FileNum =
225 dwarf::toUnsigned(DIE.find(dwarf::DW_AT_decl_file), 0)) {
226 if (const auto *LT = U.getOrigUnit().getContext().getLineTableForUnit(
227 &U.getOrigUnit())) {
228 // FIXME: dsymutil-classic compatibility. I'd rather not
229 // unique anything in anonymous namespaces, but if we do, then
230 // verify that the file and line correspond.
231 if (IsAnonymousNamespace)
232 FileNum = 1;
233
234 if (LT->hasFileAtIndex(FileNum)) {
235 Line = dwarf::toUnsigned(DIE.find(dwarf::DW_AT_decl_line), 0);
236 // Cache the resolved paths based on the index in the line table,
237 // because calling realpath is expensive.
238 FileRef = getResolvedPath(U, FileNum, *LT);
239 }
240 }
241 }
242 }
243 }
244
245 // Unnamed types declared on one line differ only in their contents.
246 if (NameForUniquing.empty() && Line) {
247 SmallString<128> Contents;
248 raw_svector_ostream OS(Contents);
249 appendUnnamedTypeContents(DIE, OS, /*Depth=*/0);
250 NameForUniquing = StringPool.internString(Contents);
251 }
252
253 if (!Line && NameForUniquing.empty())
254 return PointerIntPair<DeclContext *, 1>(nullptr);
255
256 // We hash NameForUniquing, which is the mangled name, in order to get most
257 // overloaded functions resolve correctly.
258 //
259 // Strictly speaking, hashing the Tag is only necessary for a
260 // DW_TAG_module, to prevent uniquing of a module and a namespace
261 // with the same name.
262 //
263 // FIXME: dsymutil-classic won't unique the same type presented
264 // once as a struct and once as a class. Using the Tag in the fully
265 // qualified name hash to get the same effect.
266 unsigned Hash =
267 hash_combine(Context.getQualifiedNameHash(), Tag, NameForUniquing);
268
269 // FIXME: dsymutil-classic compatibility: when we don't have a name,
270 // use the filename.
271 if (IsAnonymousNamespace)
272 Hash = hash_combine(Hash, FileRef);
273
274 // Now look if this context already exists.
275 DeclContext Key(Hash, Line, ByteSize, Tag, Name, NameForUniquing, FileRef,
276 Context);
277 auto ContextIter = Contexts.find(&Key);
278
279 if (ContextIter == Contexts.end()) {
280 // The context wasn't found.
281 bool Inserted;
282 DeclContext *NewContext = new (Allocator)
283 DeclContext(Hash, Line, ByteSize, Tag, Name, NameForUniquing, FileRef,
284 Context, DIE, U.getUniqueID());
285 std::tie(ContextIter, Inserted) = Contexts.insert(NewContext);
286 assert(Inserted && "Failed to insert DeclContext");
287 (void)Inserted;
288 } else if (Tag != dwarf::DW_TAG_namespace &&
289 !(*ContextIter)->setLastSeenDIE(U, DIE)) {
290 // The context was found, but it is ambiguous with another context
291 // in the same file. Mark it invalid.
292 return PointerIntPair<DeclContext *, 1>(*ContextIter, /* IntVal= */ 1);
293 }
294
295 assert(ContextIter != Contexts.end());
296 // FIXME: dsymutil-classic compatibility. Union types aren't
297 // uniques, but their children might be.
298 if ((Tag == dwarf::DW_TAG_subprogram &&
299 Context.getTag() != dwarf::DW_TAG_structure_type &&
300 Context.getTag() != dwarf::DW_TAG_class_type) ||
301 (Tag == dwarf::DW_TAG_union_type))
302 return PointerIntPair<DeclContext *, 1>(*ContextIter, /* IntVal= */ 1);
303
304 return PointerIntPair<DeclContext *, 1>(*ContextIter);
305}
306
308DeclContextTree::getResolvedPath(CompileUnit &CU, unsigned FileNum,
309 const DWARFDebugLine::LineTable &LineTable) {
310 std::pair<unsigned, unsigned> Key = {CU.getUniqueID(), FileNum};
311
312 ResolvedPathsMap::const_iterator It = ResolvedPaths.find(Key);
313 if (It == ResolvedPaths.end()) {
314 std::string FileName;
315 bool FoundFileName = LineTable.getFileNameByIndex(
316 FileNum, CU.getOrigUnit().getCompilationDir(),
318 (void)FoundFileName;
319 assert(FoundFileName && "Must get file name from line table");
320
321 // Second level of caching, this time based on the file's parent
322 // path.
323 StringRef ResolvedPath = PathResolver.resolve(FileName, StringPool);
324
325 It = ResolvedPaths.insert(std::make_pair(Key, ResolvedPath)).first;
326 }
327
328 return It->second;
329}
330
331} // namespace llvm
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
amdgpu next use AMDGPU Next Use Analysis Printer
static dwarf::Attribute TypeAttr[]
A structured debug information entry.
Definition DIE.h:835
child_range children()
Definition DIE.h:887
dwarf::Tag getTag() const
Definition DIE.h:868
Utility class that carries the DWARF compile/type unit and the debug info entry in an object.
Definition DWARFDie.h:43
LLVM_ABI DWARFDie getAttributeValueAsReferencedDie(dwarf::Attribute Attr) const
Extract the specified attribute from this DIE as the referenced DIE.
Definition DWARFDie.cpp:391
LLVM_ABI std::optional< DWARFFormValue > find(dwarf::Attribute Attr) const
Extract the specified attribute from this DIE.
Definition DWARFDie.cpp:335
uint32_t getDIEIndex(const DWARFDebugInfoEntry *Die) const
Return the index of a Die entry inside the unit's DIE vector.
Definition DWARFUnit.h:276
PointerIntPair - This class implements a pair of a pointer and small integer.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition SmallString.h:26
void append(StringRef RHS)
Append from a StringRef.
Definition SmallString.h:68
void push_back(const T &Elt)
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
constexpr bool empty() const
Check if the string is empty.
Definition StringRef.h:141
constexpr size_t size() const
Get the string size.
Definition StringRef.h:144
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
StringRef resolve(const std::string &Path, NonRelocatableStringpool &StringPool)
Resolve a path by calling realpath and cache its result.
Stores all information relating to a compile unit, be it in its original instance in the object file ...
LLVM_ABI PointerIntPair< DeclContext *, 1 > getChildDeclContext(DeclContext &Context, const DWARFDie &DIE, CompileUnit &Unit, bool InClangModule)
Get the child of Context described by DIE in Unit.
A DeclContext is a named program scope that is used for ODR uniquing of types.
LLVM_ABI 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.
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
A raw_ostream that writes to an std::string.
A raw_ostream that writes to an SmallVector or SmallString.
LLVM_ABI StringRef TagString(unsigned Tag)
Definition Dwarf.cpp:21
LLVM_ABI bool isIdentifiedByChildren(dwarf::Tag Tag)
Test if an unnamed type with tag Tag is identified by its children, which tell it apart from other un...
Definition Utils.cpp:55
LLVM_ABI bool isIdentifyingChild(const DWARFDie &Die)
Test if Die is a child that identifies its unnamed parent type.
Definition Utils.cpp:68
std::optional< uint64_t > toUnsigned(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract an unsigned constant.
This is an optimization pass for GlobalISel generic memory operations.
static std::optional< std::string > makeSimpleTemplateNameWithParams(StringRef Name, const DWARFDie &DIE)
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
static void appendUnqualifiedTypeName(DWARFDie DIE, raw_ostream &OS, unsigned Depth)
Appends the type DIE refers to, through unnamed types up to a named one.
static void appendUnnamedTypeContents(const DWARFDie &DIE, raw_ostream &OS, unsigned Depth)
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
Definition Hashing.h:307
static constexpr unsigned MaxTypeReferenceDepth
Bounds walks along DW_AT_type, which malformed input can make cyclic.
bool getFileNameByIndex(uint64_t FileIndex, StringRef CompDir, DILineInfoSpecifier::FileLineInfoKind Kind, std::string &Result) const
Extracts filename by its index in filename table in prologue.