LLVM 23.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
16
17namespace llvm {
18
19static std::optional<std::string>
21 std::string Result = Name.str();
22 raw_string_ostream OS(Result);
24 Printer.appendAndTerminateTemplateParameters(DIE);
25 if (Result == Name)
26 return std::nullopt;
27 return Result;
28}
29
30using namespace dwarf_linker;
31using namespace dwarf_linker::classic;
32
33/// Set the last DIE/CU a context was seen in and, possibly invalidate the
34/// context if it is ambiguous.
35///
36/// In the current implementation, we don't handle overloaded functions well,
37/// because the argument types are not taken into account when computing the
38/// DeclContext tree.
39///
40/// Some of this is mitigated byt using mangled names that do contain the
41/// arguments types, but sometimes (e.g. with function templates) we don't have
42/// that. In that case, just do not unique anything that refers to the contexts
43/// we are not able to distinguish.
44///
45/// If a context that is not a namespace appears twice in the same CU, we know
46/// it is ambiguous. Make it invalid.
48 if (LastSeenCompileUnitID == U.getUniqueID()) {
49 DWARFUnit &OrigUnit = U.getOrigUnit();
50 uint32_t FirstIdx = OrigUnit.getDIEIndex(LastSeenDIE);
51 U.getInfo(FirstIdx).Ctxt = nullptr;
52 return false;
53 }
54
55 LastSeenCompileUnitID = U.getUniqueID();
56 LastSeenDIE = Die;
57 return true;
58}
59
62 CompileUnit &U, bool InClangModule) {
63 unsigned Tag = DIE.getTag();
64
65 // FIXME: dsymutil-classic compat: We should bail out here if we
66 // have a specification or an abstract_origin. We will get the
67 // parent context wrong here.
68
69 switch (Tag) {
70 default:
71 // By default stop gathering child contexts.
73 case dwarf::DW_TAG_module:
74 break;
75 case dwarf::DW_TAG_compile_unit:
76 return PointerIntPair<DeclContext *, 1>(&Context);
77 case dwarf::DW_TAG_subprogram:
78 // Do not unique anything inside CU local functions.
79 if ((Context.getTag() == dwarf::DW_TAG_namespace ||
80 Context.getTag() == dwarf::DW_TAG_compile_unit) &&
81 !dwarf::toUnsigned(DIE.find(dwarf::DW_AT_external), 0))
83 [[fallthrough]];
84 case dwarf::DW_TAG_member:
85 case dwarf::DW_TAG_namespace:
86 case dwarf::DW_TAG_structure_type:
87 case dwarf::DW_TAG_class_type:
88 case dwarf::DW_TAG_union_type:
89 case dwarf::DW_TAG_enumeration_type:
90 case dwarf::DW_TAG_typedef:
91 // Artificial things might be ambiguous, because they might be created on
92 // demand. For example implicitly defined constructors are ambiguous
93 // because of the way we identify contexts, and they won't be generated
94 // every time everywhere.
95 if (dwarf::toUnsigned(DIE.find(dwarf::DW_AT_artificial), 0))
97 break;
98 }
99
100 StringRef Name = DIE.getShortName();
101 StringRef NameForUniquing;
102 StringRef FileRef;
103
104 if (const char *LinkageName = DIE.getLinkageName()) {
105 NameForUniquing = StringPool.internString(LinkageName);
106 } else if (!Name.empty()) {
107 // With -gsimple-template-names, DW_AT_name omits template parameters
108 // ("vector" instead of "vector<int>"). Reconstruct them from child
109 // DW_TAG_template_*_parameter DIEs so different specializations get
110 // distinct uniquing names.
111 bool HasTemplateParamsInName =
112 Name.ends_with(">") && !Name.ends_with("<=>") && Name.contains('<');
113 std::optional<std::string> FullName;
114 if (!HasTemplateParamsInName)
115 FullName = makeSimpleTemplateNameWithParams(Name, DIE);
116 NameForUniquing = StringPool.internString(FullName ? *FullName : Name);
117 }
118
119 // For typedefs, include the referenced type chain in the uniquing key. Two
120 // typedefs with the same name (e.g. from preferred_name) but different
121 // DW_AT_type targets must get different DeclContexts, otherwise ODR
122 // deduplication can create self-referencing typedef cycles in the output
123 // DWARF. Walk through unnamed wrapper types (pointers, references, const,
124 // etc.) to find a named type for disambiguation. This mirrors the parallel
125 // linker's behavior in SyntheticTypeNameBuilder::addTypeName.
126 if (Tag == dwarf::DW_TAG_typedef && !NameForUniquing.empty()) {
127 SmallString<128> Combined(NameForUniquing);
128 DWARFDie CurDie = DIE;
129 // Guard against malformed input DWARF with cycles in DW_AT_type references;
130 // the parallel linker uses a similar guard in addReferencedODRDies.
131 for (unsigned Depth = 0; Depth < 256; ++Depth) {
132 auto TypeAttr = CurDie.find(dwarf::DW_AT_type);
133 if (!TypeAttr)
134 break;
135 auto RefDie = CurDie.getAttributeValueAsReferencedDie(*TypeAttr);
136 if (!RefDie)
137 break;
138 // Use null bytes as separators since they cannot appear in type names
139 // or tag strings, preventing accidental collisions.
140 Combined.push_back('\0');
141 Combined.append(dwarf::TagString(RefDie.getTag()));
142 StringRef RefName = RefDie.getShortName();
143 if (!RefName.empty()) {
144 Combined.push_back('\0');
145 Combined.append(RefName);
146 break;
147 }
148 CurDie = RefDie;
149 }
150 if (Combined.size() != NameForUniquing.size())
151 NameForUniquing = StringPool.internString(Combined);
152 }
153
154 bool IsAnonymousNamespace =
155 NameForUniquing.empty() && Tag == dwarf::DW_TAG_namespace;
156 if (IsAnonymousNamespace) {
157 // FIXME: For dsymutil-classic compatibility. I think uniquing within
158 // anonymous namespaces is wrong. There is no ODR guarantee there.
159 NameForUniquing = "(anonymous namespace)";
160 }
161
162 if (Tag != dwarf::DW_TAG_class_type && Tag != dwarf::DW_TAG_structure_type &&
163 Tag != dwarf::DW_TAG_union_type &&
164 Tag != dwarf::DW_TAG_enumeration_type && NameForUniquing.empty())
165 return PointerIntPair<DeclContext *, 1>(nullptr);
166
167 unsigned Line = 0;
168 unsigned ByteSize = std::numeric_limits<uint32_t>::max();
169
170 if (!InClangModule) {
171 // Gather some discriminating data about the DeclContext we will be
172 // creating: File, line number and byte size. This shouldn't be necessary,
173 // because the ODR is just about names, but given that we do some
174 // approximations with overloaded functions and anonymous namespaces, use
175 // these additional data points to make the process safer.
176 //
177 // This is disabled for clang modules, because forward declarations of
178 // module-defined types do not have a file and line.
179 ByteSize = dwarf::toUnsigned(DIE.find(dwarf::DW_AT_byte_size),
180 std::numeric_limits<uint64_t>::max());
181 if (Tag != dwarf::DW_TAG_namespace || IsAnonymousNamespace) {
182 if (unsigned FileNum =
183 dwarf::toUnsigned(DIE.find(dwarf::DW_AT_decl_file), 0)) {
184 if (const auto *LT = U.getOrigUnit().getContext().getLineTableForUnit(
185 &U.getOrigUnit())) {
186 // FIXME: dsymutil-classic compatibility. I'd rather not
187 // unique anything in anonymous namespaces, but if we do, then
188 // verify that the file and line correspond.
189 if (IsAnonymousNamespace)
190 FileNum = 1;
191
192 if (LT->hasFileAtIndex(FileNum)) {
193 Line = dwarf::toUnsigned(DIE.find(dwarf::DW_AT_decl_line), 0);
194 // Cache the resolved paths based on the index in the line table,
195 // because calling realpath is expensive.
196 FileRef = getResolvedPath(U, FileNum, *LT);
197 }
198 }
199 }
200 }
201 }
202
203 if (!Line && NameForUniquing.empty())
204 return PointerIntPair<DeclContext *, 1>(nullptr);
205
206 // We hash NameForUniquing, which is the mangled name, in order to get most
207 // overloaded functions resolve correctly.
208 //
209 // Strictly speaking, hashing the Tag is only necessary for a
210 // DW_TAG_module, to prevent uniquing of a module and a namespace
211 // with the same name.
212 //
213 // FIXME: dsymutil-classic won't unique the same type presented
214 // once as a struct and once as a class. Using the Tag in the fully
215 // qualified name hash to get the same effect.
216 unsigned Hash =
217 hash_combine(Context.getQualifiedNameHash(), Tag, NameForUniquing);
218
219 // FIXME: dsymutil-classic compatibility: when we don't have a name,
220 // use the filename.
221 if (IsAnonymousNamespace)
222 Hash = hash_combine(Hash, FileRef);
223
224 // Now look if this context already exists.
225 DeclContext Key(Hash, Line, ByteSize, Tag, Name, NameForUniquing, FileRef,
226 Context);
227 auto ContextIter = Contexts.find(&Key);
228
229 if (ContextIter == Contexts.end()) {
230 // The context wasn't found.
231 bool Inserted;
232 DeclContext *NewContext = new (Allocator)
233 DeclContext(Hash, Line, ByteSize, Tag, Name, NameForUniquing, FileRef,
234 Context, DIE, U.getUniqueID());
235 std::tie(ContextIter, Inserted) = Contexts.insert(NewContext);
236 assert(Inserted && "Failed to insert DeclContext");
237 (void)Inserted;
238 } else if (Tag != dwarf::DW_TAG_namespace &&
239 !(*ContextIter)->setLastSeenDIE(U, DIE)) {
240 // The context was found, but it is ambiguous with another context
241 // in the same file. Mark it invalid.
242 return PointerIntPair<DeclContext *, 1>(*ContextIter, /* IntVal= */ 1);
243 }
244
245 assert(ContextIter != Contexts.end());
246 // FIXME: dsymutil-classic compatibility. Union types aren't
247 // uniques, but their children might be.
248 if ((Tag == dwarf::DW_TAG_subprogram &&
249 Context.getTag() != dwarf::DW_TAG_structure_type &&
250 Context.getTag() != dwarf::DW_TAG_class_type) ||
251 (Tag == dwarf::DW_TAG_union_type))
252 return PointerIntPair<DeclContext *, 1>(*ContextIter, /* IntVal= */ 1);
253
254 return PointerIntPair<DeclContext *, 1>(*ContextIter);
255}
256
258DeclContextTree::getResolvedPath(CompileUnit &CU, unsigned FileNum,
259 const DWARFDebugLine::LineTable &LineTable) {
260 std::pair<unsigned, unsigned> Key = {CU.getUniqueID(), FileNum};
261
262 ResolvedPathsMap::const_iterator It = ResolvedPaths.find(Key);
263 if (It == ResolvedPaths.end()) {
264 std::string FileName;
265 bool FoundFileName = LineTable.getFileNameByIndex(
266 FileNum, CU.getOrigUnit().getCompilationDir(),
268 (void)FoundFileName;
269 assert(FoundFileName && "Must get file name from line table");
270
271 // Second level of caching, this time based on the file's parent
272 // path.
273 StringRef ResolvedPath = PathResolver.resolve(FileName, StringPool);
274
275 It = ResolvedPaths.insert(std::make_pair(Key, ResolvedPath)).first;
276 }
277
278 return It->second;
279}
280
281} // 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:828
dwarf::Tag getTag() const
Definition DIE.h:864
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:373
LLVM_ABI std::optional< DWARFFormValue > find(dwarf::Attribute Attr) const
Extract the specified attribute from this DIE.
Definition DWARFDie.cpp:317
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
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 ...
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.
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.
A raw_ostream that writes to an std::string.
LLVM_ABI StringRef TagString(unsigned Tag)
Definition Dwarf.cpp:21
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
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
Definition Hashing.h:325
bool getFileNameByIndex(uint64_t FileIndex, StringRef CompDir, DILineInfoSpecifier::FileLineInfoKind Kind, std::string &Result) const
Extracts filename by its index in filename table in prologue.