Skip to content

Commit 06d202b

Browse files
authored
[clang][DebugInfo] Emit unified (Itanium) mangled name to structor declarations (#154142)
Depends on #154137 This patch is motivated by #149827, where we plan on using mangled names on structor declarations to find the exact structor definition that LLDB's expression evaluator should call. Given a `DW_TAG_subprogram` for a function declaration, the most convenient way for a debugger to find the corresponding definition is to use the `DW_AT_linkage_name` (i.e., the mangled name). However, we currently can't do that for constructors/destructors because Clang doesn't attach linkage names to them. This is because, depending on ABI, there can be multiple definitions for a single constructor/destructor declaration. The way GCC works around this is by producing a `C4`/`D4` "unified" mangling for structor declarations (see [godbolt](https://godbolt.org/z/Wds6cja9K)). GDB uses this to locate the relevant definitions. This patch aligns Clang with GCC's DWARF output and allows us to implement the same lookup scheme in LLDB.
1 parent 9b1b937 commit 06d202b

File tree

15 files changed

+207
-13
lines changed

15 files changed

+207
-13
lines changed

clang/include/clang/Basic/ABI.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,16 @@ enum CXXCtorType {
2727
Ctor_Comdat, ///< The COMDAT used for ctors
2828
Ctor_CopyingClosure, ///< Copying closure variant of a ctor
2929
Ctor_DefaultClosure, ///< Default closure variant of a ctor
30+
Ctor_Unified, ///< GCC-style unified dtor
3031
};
3132

3233
/// C++ destructor types.
3334
enum CXXDtorType {
34-
Dtor_Deleting, ///< Deleting dtor
35-
Dtor_Complete, ///< Complete object dtor
36-
Dtor_Base, ///< Base object dtor
37-
Dtor_Comdat ///< The COMDAT used for dtors
35+
Dtor_Deleting, ///< Deleting dtor
36+
Dtor_Complete, ///< Complete object dtor
37+
Dtor_Base, ///< Base object dtor
38+
Dtor_Comdat, ///< The COMDAT used for dtors
39+
Dtor_Unified, ///< GCC-style unified dtor
3840
};
3941

4042
} // end namespace clang

clang/include/clang/Basic/DebugOptions.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,12 @@ DEBUGOPT(DebugNameTable, 2, 0, Compatible)
125125
/// Whether to use DWARF base address specifiers in .debug_ranges.
126126
DEBUGOPT(DebugRangesBaseAddress, 1, 0, Compatible)
127127

128+
/// Whether to add linkage names to constructor/destructor declarations.
129+
/// This is an escape hatch for cases where attaching the additional linkage
130+
/// names would increase debug-info size (particularly the .debug_str section)
131+
/// too much.
132+
DEBUGOPT(DebugStructorDeclLinkageNames, 1, 0, Benign)
133+
128134
/// Whether to embed source in DWARF debug line section.
129135
DEBUGOPT(EmbedSource, 1, 0, Compatible)
130136

clang/include/clang/Driver/Options.td

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4789,6 +4789,18 @@ def gembed_source : Flag<["-"], "gembed-source">, Group<g_flags_Group>,
47894789
def gno_embed_source : Flag<["-"], "gno-embed-source">, Group<g_flags_Group>,
47904790
Flags<[NoXarchOption]>,
47914791
HelpText<"Restore the default behavior of not embedding source text in DWARF debug sections">;
4792+
defm structor_decl_linkage_names
4793+
: BoolGOption<"structor-decl-linkage-names",
4794+
CodeGenOpts<"DebugStructorDeclLinkageNames">, DefaultTrue,
4795+
NegFlag<SetFalse>,
4796+
PosFlag<SetTrue, [], [],
4797+
"Attach linkage names to C++ constructor/destructor "
4798+
"declarations in DWARF."
4799+
"Implies -g.">,
4800+
BothFlags<[], [ClangOption, CLOption, CC1Option]>>,
4801+
DocBrief<[{On some ABIs (e.g., Itanium), constructors and destructors may have multiple variants. Historically, when generating DWARF, Clang did not attach ``DW_AT_linkage_name``s to structor DIEs because there were multiple possible manglings (depending on the structor variant) that could be used. With ``-gstructor-decl-linkage-names``, for ABIs with structor variants, we attach a "unified" mangled name to structor declarations DIEs which debuggers can use to look up all the definitions for a structor declaration. E.g., a "unified" mangled name ``_ZN3FooC4Ev`` may have multiple definitions associated with it such as ``_ZN3FooC1Ev`` and ``_ZN3FooC2Ev``.
4802+
4803+
Enabling this flag results in a better interactive debugging experience (both GDB and LLDB have support for understanding these "unified" linkage names). However, it comes with a significant increase in debug-info size (particularly the `.debug_str` section). As an escape hatch, users can disable this feature using ``-gno-structor-decl-linkage-names``.}]>;
47924804
defm key_instructions : BoolGOption<"key-instructions",
47934805
CodeGenOpts<"DebugKeyInstructions">, DefaultFalse,
47944806
NegFlag<SetFalse>, PosFlag<SetTrue, [], [],

clang/lib/AST/ItaniumMangle.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6026,6 +6026,8 @@ void CXXNameMangler::mangleCXXCtorType(CXXCtorType T,
60266026
// ::= CI2 <type> # base inheriting constructor
60276027
//
60286028
// In addition, C5 is a comdat name with C1 and C2 in it.
6029+
// C4 represents a ctor declaration and is used by debuggers to look up
6030+
// the various ctor variants.
60296031
Out << 'C';
60306032
if (InheritedFrom)
60316033
Out << 'I';
@@ -6036,6 +6038,9 @@ void CXXNameMangler::mangleCXXCtorType(CXXCtorType T,
60366038
case Ctor_Base:
60376039
Out << '2';
60386040
break;
6041+
case Ctor_Unified:
6042+
Out << '4';
6043+
break;
60396044
case Ctor_Comdat:
60406045
Out << '5';
60416046
break;
@@ -6053,6 +6058,8 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
60536058
// ::= D2 # base object destructor
60546059
//
60556060
// In addition, D5 is a comdat name with D1, D2 and, if virtual, D0 in it.
6061+
// D4 represents a dtor declaration and is used by debuggers to look up
6062+
// the various dtor variants.
60566063
switch (T) {
60576064
case Dtor_Deleting:
60586065
Out << "D0";
@@ -6063,6 +6070,9 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
60636070
case Dtor_Base:
60646071
Out << "D2";
60656072
break;
6073+
case Dtor_Unified:
6074+
Out << "D4";
6075+
break;
60666076
case Dtor_Comdat:
60676077
Out << "D5";
60686078
break;

clang/lib/AST/MicrosoftMangle.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1496,6 +1496,8 @@ void MicrosoftCXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
14961496
// it.
14971497
case Dtor_Comdat:
14981498
llvm_unreachable("not expecting a COMDAT");
1499+
case Dtor_Unified:
1500+
llvm_unreachable("not expecting a unified dtor type");
14991501
}
15001502
llvm_unreachable("Unsupported dtor type?");
15011503
}

clang/lib/CodeGen/CGClass.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1481,6 +1481,8 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
14811481
// we'd introduce *two* handler blocks. In the Microsoft ABI, we
14821482
// always delegate because we might not have a definition in this TU.
14831483
switch (DtorType) {
1484+
case Dtor_Unified:
1485+
llvm_unreachable("not expecting a unified dtor");
14841486
case Dtor_Comdat: llvm_unreachable("not expecting a COMDAT");
14851487
case Dtor_Deleting: llvm_unreachable("already handled deleting case");
14861488

clang/lib/CodeGen/CGDebugInfo.cpp

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2177,24 +2177,47 @@ static bool isFunctionLocalClass(const CXXRecordDecl *RD) {
21772177
return false;
21782178
}
21792179

2180+
llvm::StringRef
2181+
CGDebugInfo::GetMethodLinkageName(const CXXMethodDecl *Method) const {
2182+
assert(Method);
2183+
2184+
const bool IsCtorOrDtor =
2185+
isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method);
2186+
2187+
if (IsCtorOrDtor && !CGM.getCodeGenOpts().DebugStructorDeclLinkageNames)
2188+
return {};
2189+
2190+
// In some ABIs (particularly Itanium) a single ctor/dtor
2191+
// corresponds to multiple functions. Attach a "unified"
2192+
// linkage name for those (which is the convention GCC uses).
2193+
// Otherwise, attach no linkage name.
2194+
if (IsCtorOrDtor && !CGM.getTarget().getCXXABI().hasConstructorVariants())
2195+
return {};
2196+
2197+
if (const auto *Ctor = llvm::dyn_cast<CXXConstructorDecl>(Method))
2198+
return CGM.getMangledName(GlobalDecl(Ctor, CXXCtorType::Ctor_Unified));
2199+
2200+
if (const auto *Dtor = llvm::dyn_cast<CXXDestructorDecl>(Method))
2201+
return CGM.getMangledName(GlobalDecl(Dtor, CXXDtorType::Dtor_Unified));
2202+
2203+
return CGM.getMangledName(Method);
2204+
}
2205+
21802206
llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction(
21812207
const CXXMethodDecl *Method, llvm::DIFile *Unit, llvm::DIType *RecordTy) {
2182-
bool IsCtorOrDtor =
2183-
isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method);
2208+
assert(Method);
21842209

21852210
StringRef MethodName = getFunctionName(Method);
21862211
llvm::DISubroutineType *MethodTy = getOrCreateMethodType(Method, Unit);
21872212

2188-
// Since a single ctor/dtor corresponds to multiple functions, it doesn't
2189-
// make sense to give a single ctor/dtor a linkage name.
21902213
StringRef MethodLinkageName;
21912214
// FIXME: 'isFunctionLocalClass' seems like an arbitrary/unintentional
21922215
// property to use here. It may've been intended to model "is non-external
21932216
// type" but misses cases of non-function-local but non-external classes such
21942217
// as those in anonymous namespaces as well as the reverse - external types
21952218
// that are function local, such as those in (non-local) inline functions.
2196-
if (!IsCtorOrDtor && !isFunctionLocalClass(Method->getParent()))
2197-
MethodLinkageName = CGM.getMangledName(Method);
2219+
if (!isFunctionLocalClass(Method->getParent()))
2220+
MethodLinkageName = GetMethodLinkageName(Method);
21982221

21992222
// Get the location for the method.
22002223
llvm::DIFile *MethodDefUnit = nullptr;

clang/lib/CodeGen/CGDebugInfo.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -899,6 +899,10 @@ class CGDebugInfo {
899899
std::memcpy(Data + A.size(), B.data(), B.size());
900900
return StringRef(Data, A.size() + B.size());
901901
}
902+
903+
/// If one exists, returns the linkage name of the specified \
904+
/// (non-null) \c Method. Returns empty string otherwise.
905+
llvm::StringRef GetMethodLinkageName(const CXXMethodDecl *Method) const;
902906
};
903907

904908
/// A scoped helper to set the current debug location to the specified

clang/lib/CodeGen/ItaniumCXXABI.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {
9191

9292
case Dtor_Comdat:
9393
llvm_unreachable("emitting dtor comdat as function?");
94+
case Dtor_Unified:
95+
llvm_unreachable("emitting unified dtor as function?");
9496
}
9597
llvm_unreachable("bad dtor kind");
9698
}
@@ -108,6 +110,9 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {
108110

109111
case Ctor_Comdat:
110112
llvm_unreachable("emitting ctor comdat as function?");
113+
114+
case Ctor_Unified:
115+
llvm_unreachable("emitting unified ctor as function?");
111116
}
112117
llvm_unreachable("bad dtor kind");
113118
}

clang/lib/CodeGen/MicrosoftCXXABI.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ class MicrosoftCXXABI : public CGCXXABI {
7777
return false;
7878

7979
case Dtor_Comdat: llvm_unreachable("emitting dtor comdat as function?");
80+
case Dtor_Unified:
81+
llvm_unreachable("unexpected unified dtor type");
8082
}
8183
llvm_unreachable("bad dtor kind");
8284
}
@@ -1417,6 +1419,8 @@ llvm::GlobalValue::LinkageTypes MicrosoftCXXABI::getCXXDestructorLinkage(
14171419
// and are emitted everywhere they are used. They are internal if the class
14181420
// is internal.
14191421
return llvm::GlobalValue::LinkOnceODRLinkage;
1422+
case Dtor_Unified:
1423+
llvm_unreachable("MS C++ ABI does not support unified dtors");
14201424
case Dtor_Comdat:
14211425
llvm_unreachable("MS C++ ABI does not support comdat dtors");
14221426
}

0 commit comments

Comments
 (0)