Skip to content

Commit 1b4e191

Browse files
committed
[llvm][dsymutil] Use the DW_AT_name of the uniqued DIE for insertion into .debug_names
The root cause of the issue is that we have a DW_AT_subprogram definition whose DW_AT_specification DIE got deduplicated. But the DW_AT_name of the original specification is different than the one it got uniqued to. That’s technically fine because dsymutil uniques by linkage name, which uniquely identifies any function with non-internal linkage. But we insert the definition DIE into the debug-names table using the DW_AT_name of the original specification (we call getDIENames(InputDIE…)). But what we really want to do is use the name of the adjusted DW_AT_specifcation (i.e., the DW_AT_specification of the output DIE). That’s not as simple as it sounds because we can’t just get ahold of the DIE in the output CU. We have to grab the ODR DeclContext of the input DIE’s specification. That is the only link back to the canonical specification DIE. For that to be of any use, we have to stash the DW_AT_name into DeclContext so we can use it in getDIENames. We have to account for the possibility of multiple levels of DW_AT_specification/DW_AT_abstract_origin. So my proposed solution is to recursively scan the referenced DIE’s, grab the canonical DIE for those and get the name from the DeclContext (if none exists then use the DW_AT_name of the DIE itself).
1 parent f45bb98 commit 1b4e191

File tree

4 files changed

+85
-19
lines changed

4 files changed

+85
-19
lines changed

llvm/include/llvm/DWARFLinker/Classic/DWARFLinker.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -708,7 +708,9 @@ class LLVM_ABI DWARFLinker : public DWARFLinkerBase {
708708
/// already there.
709709
/// \returns is a name was found.
710710
bool getDIENames(const DWARFDie &Die, AttributesInfo &Info,
711-
OffsetsStringPool &StringPool, bool StripTemplate = false);
711+
OffsetsStringPool &StringPool,
712+
const DWARFFile &File, CompileUnit &Unit,
713+
bool StripTemplate = false);
712714

713715
uint32_t hashFullyQualifiedName(DWARFDie DIE, CompileUnit &U,
714716
const DWARFFile &File,
@@ -725,6 +727,8 @@ class LLVM_ABI DWARFLinker : public DWARFLinkerBase {
725727
/// Translate directories and file names if necessary.
726728
/// Relocate address ranges.
727729
void generateLineTableForUnit(CompileUnit &Unit);
730+
731+
llvm::StringRef getCanonicalDIEName(DWARFDie Die, const DWARFFile &File, CompileUnit *Unit);
728732
};
729733

730734
/// Assign an abbreviation number to \p Abbrev

llvm/include/llvm/DWARFLinker/Classic/DWARFLinkerDeclContext.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,10 @@ class DeclContext {
8484
DeclContext() : DefinedInClangModule(0), Parent(*this) {}
8585

8686
DeclContext(unsigned Hash, uint32_t Line, uint32_t ByteSize, uint16_t Tag,
87-
StringRef Name, StringRef File, const DeclContext &Parent,
87+
StringRef Name, StringRef NameForUniquing, StringRef File, const DeclContext &Parent,
8888
DWARFDie LastSeenDIE = DWARFDie(), unsigned CUId = 0)
8989
: QualifiedNameHash(Hash), Line(Line), ByteSize(ByteSize), Tag(Tag),
90-
DefinedInClangModule(0), Name(Name), File(File), Parent(Parent),
90+
DefinedInClangModule(0), Name(Name), NameForUniquing(NameForUniquing), File(File), Parent(Parent),
9191
LastSeenDIE(LastSeenDIE), LastSeenCompileUnitID(CUId) {}
9292

9393
uint32_t getQualifiedNameHash() const { return QualifiedNameHash; }
@@ -100,6 +100,7 @@ class DeclContext {
100100

101101
uint32_t getCanonicalDIEOffset() const { return CanonicalDIEOffset; }
102102
void setCanonicalDIEOffset(uint32_t Offset) { CanonicalDIEOffset = Offset; }
103+
llvm::StringRef getCanonicalName() const { return Name; }
103104

104105
bool isDefinedInClangModule() const { return DefinedInClangModule; }
105106
void setDefinedInClangModule(bool Val) { DefinedInClangModule = Val; }
@@ -115,6 +116,7 @@ class DeclContext {
115116
uint16_t Tag = dwarf::DW_TAG_compile_unit;
116117
unsigned DefinedInClangModule : 1;
117118
StringRef Name;
119+
StringRef NameForUniquing;
118120
StringRef File;
119121
const DeclContext &Parent;
120122
DWARFDie LastSeenDIE;
@@ -180,7 +182,7 @@ struct DeclMapInfo : private DenseMapInfo<DeclContext *> {
180182
return RHS == LHS;
181183
return LHS->QualifiedNameHash == RHS->QualifiedNameHash &&
182184
LHS->Line == RHS->Line && LHS->ByteSize == RHS->ByteSize &&
183-
LHS->Name.data() == RHS->Name.data() &&
185+
LHS->NameForUniquing.data() == RHS->NameForUniquing.data() &&
184186
LHS->File.data() == RHS->File.data() &&
185187
LHS->Parent.QualifiedNameHash == RHS->Parent.QualifiedNameHash;
186188
}

llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,22 +151,78 @@ static bool isTypeTag(uint16_t Tag) {
151151
return false;
152152
}
153153

154+
/// Recurse through the input DIE's canonical references until we find a
155+
/// DW_AT_name.
156+
llvm::StringRef DWARFLinker::DIECloner::getCanonicalDIEName(DWARFDie Die, const DWARFFile &File, CompileUnit *Unit) {
157+
std::optional<DWARFFormValue> Ref;
158+
159+
auto GetDieName = [](const DWARFDie &D) -> llvm::StringRef {
160+
auto NameForm = D.find(llvm::dwarf::DW_AT_name);
161+
if (!NameForm)
162+
return {};
163+
164+
auto NameOrErr = NameForm->getAsCString();
165+
if (!NameOrErr) {
166+
llvm::consumeError(NameOrErr.takeError());
167+
return {};
168+
}
169+
170+
return *NameOrErr;
171+
};
172+
173+
llvm::StringRef Name = GetDieName(Die);
174+
if (!Name.empty())
175+
return Name;
176+
177+
while (true) {
178+
if (!(Ref = Die.find(llvm::dwarf::DW_AT_specification))
179+
&& !(Ref = Die.find(llvm::dwarf::DW_AT_abstract_origin)))
180+
break;
181+
182+
Die = Linker.resolveDIEReference(File, CompileUnits, *Ref, Die, Unit);
183+
assert (Unit);
184+
185+
unsigned SpecIdx = Unit->getOrigUnit().getDIEIndex(Die);
186+
CompileUnit::DIEInfo &SpecInfo = Unit->getInfo(SpecIdx);
187+
if (SpecInfo.Ctxt && SpecInfo.Ctxt->hasCanonicalDIE()) {
188+
if (!SpecInfo.Ctxt->getCanonicalName().empty()) {
189+
Name = SpecInfo.Ctxt->getCanonicalName();
190+
break;
191+
}
192+
}
193+
194+
Name = GetDieName(Die);
195+
if (!Name.empty())
196+
break;
197+
}
198+
199+
return Name;
200+
}
201+
154202
bool DWARFLinker::DIECloner::getDIENames(const DWARFDie &Die,
155203
AttributesInfo &Info,
156204
OffsetsStringPool &StringPool,
205+
const DWARFFile &File, CompileUnit &Unit,
157206
bool StripTemplate) {
158207
// This function will be called on DIEs having low_pcs and
159208
// ranges. As getting the name might be more expansive, filter out
160209
// blocks directly.
161210
if (Die.getTag() == dwarf::DW_TAG_lexical_block)
162211
return false;
163212

213+
// The mangled name of an specification DIE will by virtue of the
214+
// uniquing algorithm be the same as the one it got uniqued into.
215+
// So just use the input DIE's linkage name.
164216
if (!Info.MangledName)
165217
if (const char *MangledName = Die.getLinkageName())
166218
Info.MangledName = StringPool.getEntry(MangledName);
167219

220+
// For subprograms with linkage names, we unique on the linkage name,
221+
// so DW_AT_name's may differ between the input and canonical DIEs.
222+
// Use the name of the canonical DIE.
168223
if (!Info.Name)
169-
if (const char *Name = Die.getShortName())
224+
if (llvm::StringRef Name = getCanonicalDIEName(Die, File, &Unit);
225+
!Name.empty())
170226
Info.Name = StringPool.getEntry(Name);
171227

172228
if (!Info.MangledName)
@@ -1939,7 +1995,7 @@ DIE *DWARFLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE,
19391995
// accelerator tables too. For now stick with dsymutil's behavior.
19401996
if ((Info.InDebugMap || AttrInfo.HasLowPc || AttrInfo.HasRanges) &&
19411997
Tag != dwarf::DW_TAG_compile_unit &&
1942-
getDIENames(InputDIE, AttrInfo, DebugStrPool,
1998+
getDIENames(InputDIE, AttrInfo, DebugStrPool, File, Unit,
19431999
Tag != dwarf::DW_TAG_inlined_subroutine)) {
19442000
if (AttrInfo.MangledName && AttrInfo.MangledName != AttrInfo.Name)
19452001
Unit.addNameAccelerator(Die, AttrInfo.MangledName,
@@ -1962,7 +2018,7 @@ DIE *DWARFLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE,
19622018
} else if (Tag == dwarf::DW_TAG_imported_declaration && AttrInfo.Name) {
19632019
Unit.addNamespaceAccelerator(Die, AttrInfo.Name);
19642020
} else if (isTypeTag(Tag) && !AttrInfo.IsDeclaration) {
1965-
bool Success = getDIENames(InputDIE, AttrInfo, DebugStrPool);
2021+
bool Success = getDIENames(InputDIE, AttrInfo, DebugStrPool, File, Unit);
19662022
uint64_t RuntimeLang =
19672023
dwarf::toUnsigned(InputDIE.find(dwarf::DW_AT_APPLE_runtime_class))
19682024
.value_or(0);

llvm/lib/DWARFLinker/Classic/DWARFLinkerDeclContext.cpp

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -84,24 +84,28 @@ DeclContextTree::getChildDeclContext(DeclContext &Context, const DWARFDie &DIE,
8484
break;
8585
}
8686

87-
StringRef NameRef;
87+
StringRef NameForUniquing;
88+
StringRef Name;
8889
StringRef FileRef;
8990

91+
if (const char *ShortName = DIE.getShortName())
92+
Name = StringPool.internString(ShortName);
93+
9094
if (const char *LinkageName = DIE.getLinkageName())
91-
NameRef = StringPool.internString(LinkageName);
92-
else if (const char *ShortName = DIE.getShortName())
93-
NameRef = StringPool.internString(ShortName);
95+
NameForUniquing = StringPool.internString(LinkageName);
96+
else if (!Name.empty())
97+
NameForUniquing = Name;
9498

95-
bool IsAnonymousNamespace = NameRef.empty() && Tag == dwarf::DW_TAG_namespace;
99+
bool IsAnonymousNamespace = NameForUniquing.empty() && Tag == dwarf::DW_TAG_namespace;
96100
if (IsAnonymousNamespace) {
97101
// FIXME: For dsymutil-classic compatibility. I think uniquing within
98102
// anonymous namespaces is wrong. There is no ODR guarantee there.
99-
NameRef = "(anonymous namespace)";
103+
NameForUniquing = "(anonymous namespace)";
100104
}
101105

102106
if (Tag != dwarf::DW_TAG_class_type && Tag != dwarf::DW_TAG_structure_type &&
103107
Tag != dwarf::DW_TAG_union_type &&
104-
Tag != dwarf::DW_TAG_enumeration_type && NameRef.empty())
108+
Tag != dwarf::DW_TAG_enumeration_type && NameForUniquing.empty())
105109
return PointerIntPair<DeclContext *, 1>(nullptr);
106110

107111
unsigned Line = 0;
@@ -140,10 +144,10 @@ DeclContextTree::getChildDeclContext(DeclContext &Context, const DWARFDie &DIE,
140144
}
141145
}
142146

143-
if (!Line && NameRef.empty())
147+
if (!Line && NameForUniquing.empty())
144148
return PointerIntPair<DeclContext *, 1>(nullptr);
145149

146-
// We hash NameRef, which is the mangled name, in order to get most
150+
// We hash NameForUniquing, which is the mangled name, in order to get most
147151
// overloaded functions resolve correctly.
148152
//
149153
// Strictly speaking, hashing the Tag is only necessary for a
@@ -153,22 +157,22 @@ DeclContextTree::getChildDeclContext(DeclContext &Context, const DWARFDie &DIE,
153157
// FIXME: dsymutil-classic won't unique the same type presented
154158
// once as a struct and once as a class. Using the Tag in the fully
155159
// qualified name hash to get the same effect.
156-
unsigned Hash = hash_combine(Context.getQualifiedNameHash(), Tag, NameRef);
160+
unsigned Hash = hash_combine(Context.getQualifiedNameHash(), Tag, NameForUniquing);
157161

158162
// FIXME: dsymutil-classic compatibility: when we don't have a name,
159163
// use the filename.
160164
if (IsAnonymousNamespace)
161165
Hash = hash_combine(Hash, FileRef);
162166

163167
// Now look if this context already exists.
164-
DeclContext Key(Hash, Line, ByteSize, Tag, NameRef, FileRef, Context);
168+
DeclContext Key(Hash, Line, ByteSize, Tag, Name, NameForUniquing, FileRef, Context);
165169
auto ContextIter = Contexts.find(&Key);
166170

167171
if (ContextIter == Contexts.end()) {
168172
// The context wasn't found.
169173
bool Inserted;
170174
DeclContext *NewContext =
171-
new (Allocator) DeclContext(Hash, Line, ByteSize, Tag, NameRef, FileRef,
175+
new (Allocator) DeclContext(Hash, Line, ByteSize, Tag, Name, NameForUniquing, FileRef,
172176
Context, DIE, U.getUniqueID());
173177
std::tie(ContextIter, Inserted) = Contexts.insert(NewContext);
174178
assert(Inserted && "Failed to insert DeclContext");

0 commit comments

Comments
 (0)