Skip to content

Commit 294b03e

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 d0149ac commit 294b03e

File tree

12 files changed

+139
-17
lines changed

12 files changed

+139
-17
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,11 @@ 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, const DWARFFile &File,
712+
CompileUnit &Unit, bool StripTemplate = false);
713+
714+
llvm::StringRef getCanonicalDIEName(DWARFDie Die, const DWARFFile &File,
715+
CompileUnit *Unit);
712716

713717
uint32_t hashFullyQualifiedName(DWARFDie DIE, CompileUnit &U,
714718
const DWARFFile &File,

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

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

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

9495
uint32_t getQualifiedNameHash() const { return QualifiedNameHash; }
9596

@@ -101,6 +102,7 @@ class DeclContext {
101102

102103
uint32_t getCanonicalDIEOffset() const { return CanonicalDIEOffset; }
103104
void setCanonicalDIEOffset(uint32_t Offset) { CanonicalDIEOffset = Offset; }
105+
llvm::StringRef getCanonicalName() const { return Name; }
104106

105107
bool isDefinedInClangModule() const { return DefinedInClangModule; }
106108
void setDefinedInClangModule(bool Val) { DefinedInClangModule = Val; }
@@ -115,6 +117,7 @@ class DeclContext {
115117
uint32_t ByteSize = 0;
116118
uint16_t Tag = dwarf::DW_TAG_compile_unit;
117119
unsigned DefinedInClangModule : 1;
120+
StringRef Name;
118121
StringRef NameForUniquing;
119122
StringRef File;
120123
const DeclContext &Parent;

llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp

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

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

219+
// The mangled name of an specification DIE will by virtue of the
220+
// uniquing algorithm be the same as the one it got uniqued into.
221+
// So just use the input DIE's linkage name.
164222
if (!Info.MangledName)
165223
if (const char *MangledName = Die.getLinkageName())
166224
Info.MangledName = StringPool.getEntry(MangledName);
167225

226+
// For subprograms with linkage names, we unique on the linkage name,
227+
// so DW_AT_name's may differ between the input and canonical DIEs.
228+
// Use the name of the canonical DIE.
168229
if (!Info.Name)
169-
if (const char *Name = Die.getShortName())
230+
if (llvm::StringRef Name = getCanonicalDIEName(Die, File, &Unit);
231+
!Name.empty())
170232
Info.Name = StringPool.getEntry(Name);
171233

172234
if (!Info.MangledName)
@@ -1939,7 +2001,7 @@ DIE *DWARFLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE,
19392001
// accelerator tables too. For now stick with dsymutil's behavior.
19402002
if ((Info.InDebugMap || AttrInfo.HasLowPc || AttrInfo.HasRanges) &&
19412003
Tag != dwarf::DW_TAG_compile_unit &&
1942-
getDIENames(InputDIE, AttrInfo, DebugStrPool,
2004+
getDIENames(InputDIE, AttrInfo, DebugStrPool, File, Unit,
19432005
Tag != dwarf::DW_TAG_inlined_subroutine)) {
19442006
if (AttrInfo.MangledName && AttrInfo.MangledName != AttrInfo.Name)
19452007
Unit.addNameAccelerator(Die, AttrInfo.MangledName,
@@ -1962,7 +2024,7 @@ DIE *DWARFLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE,
19622024
} else if (Tag == dwarf::DW_TAG_imported_declaration && AttrInfo.Name) {
19632025
Unit.addNamespaceAccelerator(Die, AttrInfo.Name);
19642026
} else if (isTypeTag(Tag) && !AttrInfo.IsDeclaration) {
1965-
bool Success = getDIENames(InputDIE, AttrInfo, DebugStrPool);
2027+
bool Success = getDIENames(InputDIE, AttrInfo, DebugStrPool, File, Unit);
19662028
uint64_t RuntimeLang =
19672029
dwarf::toUnsigned(InputDIE.find(dwarf::DW_AT_APPLE_runtime_class))
19682030
.value_or(0);

llvm/lib/DWARFLinker/Classic/DWARFLinkerDeclContext.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,14 @@ DeclContextTree::getChildDeclContext(DeclContext &Context, const DWARFDie &DIE,
8484
break;
8585
}
8686

87+
StringRef Name = DIE.getShortName();
8788
StringRef NameForUniquing;
8889
StringRef FileRef;
8990

9091
if (const char *LinkageName = DIE.getLinkageName())
9192
NameForUniquing = StringPool.internString(LinkageName);
92-
else if (const char *ShortName = DIE.getShortName())
93-
NameForUniquing = StringPool.internString(ShortName);
93+
else if (!Name.empty())
94+
NameForUniquing = StringPool.internString(Name);
9495

9596
bool IsAnonymousNamespace =
9697
NameForUniquing.empty() && Tag == dwarf::DW_TAG_namespace;
@@ -163,15 +164,16 @@ DeclContextTree::getChildDeclContext(DeclContext &Context, const DWARFDie &DIE,
163164
Hash = hash_combine(Hash, FileRef);
164165

165166
// Now look if this context already exists.
166-
DeclContext Key(Hash, Line, ByteSize, Tag, NameForUniquing, FileRef, Context);
167+
DeclContext Key(Hash, Line, ByteSize, Tag, Name, NameForUniquing, FileRef,
168+
Context);
167169
auto ContextIter = Contexts.find(&Key);
168170

169171
if (ContextIter == Contexts.end()) {
170172
// The context wasn't found.
171173
bool Inserted;
172-
DeclContext *NewContext =
173-
new (Allocator) DeclContext(Hash, Line, ByteSize, Tag, NameForUniquing,
174-
FileRef, Context, DIE, U.getUniqueID());
174+
DeclContext *NewContext = new (Allocator)
175+
DeclContext(Hash, Line, ByteSize, Tag, Name, NameForUniquing, FileRef,
176+
Context, DIE, U.getUniqueID());
175177
std::tie(ContextIter, Inserted) = Contexts.insert(NewContext);
176178
assert(Inserted && "Failed to insert DeclContext");
177179
(void)Inserted;

llvm/test/tools/dsymutil/AArch64/dummy-debug-map-arm64.map

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,13 @@ objects:
1111
- filename: 1.o
1212
symbols:
1313
- { sym: _bar, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }
14+
- { sym: __Z13lib1_internalv, objAddr: 0x0, binAddr: 0x10020, size: 0x20 }
15+
- { sym: __ZN3Foo4funcIZ13lib1_internalvE3$_0EEvv, objAddr: 0x0, binAddr: 0x10040, size: 0x20 }
1416
- filename: 2.o
1517
symbols:
1618
- { sym: __Z3foov, objAddr: 0x0, binAddr: 0x20000, size: 0x10 }
19+
- { sym: __Z13lib1_internalv, objAddr: 0x0, binAddr: 0x20020, size: 0x20 }
20+
- { sym: __ZN3Foo4funcIZ13lib1_internalvE3$_0EEvv, objAddr: 0x0, binAddr: 0x20040, size: 0x20 }
1721
- filename: 3.o
1822
symbols:
1923
- { sym: __Z3foov, objAddr: 0x0, binAddr: 0x30000, size: 0x10 }
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Tests the case where a DW_TAG_subprogram for a method declaration
2+
# got uniqued into a DW_TAG_subprogram with the same linkage name (but
3+
# different DW_AT_name). Make sure the DW_TAG_subprogram DIE for the
4+
# definition, which previously pointed to the now de-deduplicated declaration,
5+
# gets inserted into the .debug_names table using the DW_AT_name of the canonical
6+
# declaration DW_TAG_subprogram.
7+
#
8+
# Object files compiled as follows:
9+
# clang -g -c -o 1.o Inputs/odr-uniquing-DW_AT_name-conflict/lib1.cpp
10+
# clang -g -c -o 2.o Inputs/odr-uniquing-DW_AT_name-conflict/lib2.cpp
11+
12+
# RUN: dsymutil -f -oso-prepend-path=%p/../Inputs/odr-uniquing-DW_AT_name-conflict -y %p/dummy-debug-map-arm64.map -o - \
13+
# RUN: | llvm-dwarfdump --verify - | FileCheck %s
14+
15+
# RUN: dsymutil --linker parallel -f -oso-prepend-path=%p/../Inputs/odr-uniquing-DW_AT_name-conflict -y %p/dummy-debug-map-arm64.map -o - \
16+
# RUN: | not llvm-dwarfdump --verify - | FileCheck %s --check-prefix=PARALLEL-ODR
17+
18+
# RUN: dsymutil -f -oso-prepend-path=%p/../Inputs/odr-uniquing-DW_AT_name-conflict -y %p/dummy-debug-map-arm64.map -no-odr -o - \
19+
# RUN: | llvm-dwarfdump --verify - | FileCheck %s
20+
21+
# RUN: dsymutil --linker parallel -f -oso-prepend-path=%p/../Inputs/odr-uniquing-DW_AT_name-conflict -y %p/dummy-debug-map-arm64.map -no-odr -o - \
22+
# RUN: | llvm-dwarfdump --verify - | FileCheck %s
23+
24+
# CHECK: No errors.
25+
26+
# FIXME: parallel DWARFLinker uses wrong DW_AT_name when inserting uniqued subprogram into .debug_names
27+
# PARALLEL-ODR: Verifying .debug_names...
28+
# PARALLEL-ODR-NEXT: error: Name Index {{.*}} mismatched Name of DIE
Binary file not shown.
Binary file not shown.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#include "lib1.h"
2+
3+
[[gnu::weak]] void lib1_internal() {
4+
Foo{}.func<decltype([]{})>();
5+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
struct Foo {
2+
template<typename T> void func() {}
3+
};

0 commit comments

Comments
 (0)