Skip to content

Commit 95f26e2

Browse files
committed
[clang][DebugInfo] Emit unified (Itanium) mangled name to structor declarations (llvm#154142)
Depends on llvm#154137 This patch is motivated by llvm#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. (cherry picked from commit 06d202b)
1 parent 88e1c04 commit 95f26e2

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
@@ -128,6 +128,12 @@ DEBUGOPT(DebugNameTable, 2, 0, Affecting)
128128
/// Whether to use DWARF base address specifiers in .debug_ranges.
129129
DEBUGOPT(DebugRangesBaseAddress, 1, 0, Affecting)
130130

131+
/// Whether to add linkage names to constructor/destructor declarations.
132+
/// This is an escape hatch for cases where attaching the additional linkage
133+
/// names would increase debug-info size (particularly the .debug_str section)
134+
/// too much.
135+
DEBUGOPT(DebugStructorDeclLinkageNames, 1, 0, Benign)
136+
131137
/// Whether to embed source in DWARF debug line section.
132138
DEBUGOPT(EmbedSource, 1, 0, Affecting)
133139

clang/include/clang/Driver/Options.td

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4899,6 +4899,18 @@ def gembed_source : Flag<["-"], "gembed-source">, Group<g_flags_Group>,
48994899
def gno_embed_source : Flag<["-"], "gno-embed-source">, Group<g_flags_Group>,
49004900
Flags<[NoXarchOption]>,
49014901
HelpText<"Restore the default behavior of not embedding source text in DWARF debug sections">;
4902+
defm structor_decl_linkage_names
4903+
: BoolGOption<"structor-decl-linkage-names",
4904+
CodeGenOpts<"DebugStructorDeclLinkageNames">, DefaultTrue,
4905+
NegFlag<SetFalse>,
4906+
PosFlag<SetTrue, [], [],
4907+
"Attach linkage names to C++ constructor/destructor "
4908+
"declarations in DWARF."
4909+
"Implies -g.">,
4910+
BothFlags<[], [ClangOption, CLOption, CC1Option]>>,
4911+
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``.
4912+
4913+
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``.}]>;
49024914
defm key_instructions : BoolGOption<"key-instructions",
49034915
CodeGenOpts<"DebugKeyInstructions">, DefaultFalse,
49044916
NegFlag<SetFalse>, PosFlag<SetTrue, [], [],

clang/lib/AST/ItaniumMangle.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6068,6 +6068,8 @@ void CXXNameMangler::mangleCXXCtorType(CXXCtorType T,
60686068
// ::= CI2 <type> # base inheriting constructor
60696069
//
60706070
// In addition, C5 is a comdat name with C1 and C2 in it.
6071+
// C4 represents a ctor declaration and is used by debuggers to look up
6072+
// the various ctor variants.
60716073
Out << 'C';
60726074
if (InheritedFrom)
60736075
Out << 'I';
@@ -6078,6 +6080,9 @@ void CXXNameMangler::mangleCXXCtorType(CXXCtorType T,
60786080
case Ctor_Base:
60796081
Out << '2';
60806082
break;
6083+
case Ctor_Unified:
6084+
Out << '4';
6085+
break;
60816086
case Ctor_Comdat:
60826087
Out << '5';
60836088
break;
@@ -6095,6 +6100,8 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
60956100
// ::= D2 # base object destructor
60966101
//
60976102
// In addition, D5 is a comdat name with D1, D2 and, if virtual, D0 in it.
6103+
// D4 represents a dtor declaration and is used by debuggers to look up
6104+
// the various dtor variants.
60986105
switch (T) {
60996106
case Dtor_Deleting:
61006107
Out << "D0";
@@ -6105,6 +6112,9 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
61056112
case Dtor_Base:
61066113
Out << "D2";
61076114
break;
6115+
case Dtor_Unified:
6116+
Out << "D4";
6117+
break;
61086118
case Dtor_Comdat:
61096119
Out << "D5";
61106120
break;

clang/lib/AST/MicrosoftMangle.cpp

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

clang/lib/CodeGen/CGClass.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1493,6 +1493,8 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
14931493
// we'd introduce *two* handler blocks. In the Microsoft ABI, we
14941494
// always delegate because we might not have a definition in this TU.
14951495
switch (DtorType) {
1496+
case Dtor_Unified:
1497+
llvm_unreachable("not expecting a unified dtor");
14961498
case Dtor_Comdat: llvm_unreachable("not expecting a COMDAT");
14971499
case Dtor_Deleting: llvm_unreachable("already handled deleting case");
14981500

clang/lib/CodeGen/CGDebugInfo.cpp

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

2261+
llvm::StringRef
2262+
CGDebugInfo::GetMethodLinkageName(const CXXMethodDecl *Method) const {
2263+
assert(Method);
2264+
2265+
const bool IsCtorOrDtor =
2266+
isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method);
2267+
2268+
if (IsCtorOrDtor && !CGM.getCodeGenOpts().DebugStructorDeclLinkageNames)
2269+
return {};
2270+
2271+
// In some ABIs (particularly Itanium) a single ctor/dtor
2272+
// corresponds to multiple functions. Attach a "unified"
2273+
// linkage name for those (which is the convention GCC uses).
2274+
// Otherwise, attach no linkage name.
2275+
if (IsCtorOrDtor && !CGM.getTarget().getCXXABI().hasConstructorVariants())
2276+
return {};
2277+
2278+
if (const auto *Ctor = llvm::dyn_cast<CXXConstructorDecl>(Method))
2279+
return CGM.getMangledName(GlobalDecl(Ctor, CXXCtorType::Ctor_Unified));
2280+
2281+
if (const auto *Dtor = llvm::dyn_cast<CXXDestructorDecl>(Method))
2282+
return CGM.getMangledName(GlobalDecl(Dtor, CXXDtorType::Dtor_Unified));
2283+
2284+
return CGM.getMangledName(Method);
2285+
}
2286+
22612287
llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction(
22622288
const CXXMethodDecl *Method, llvm::DIFile *Unit, llvm::DIType *RecordTy) {
2263-
bool IsCtorOrDtor =
2264-
isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method);
2289+
assert(Method);
22652290

22662291
StringRef MethodName = getFunctionName(Method);
22672292
llvm::DISubroutineType *MethodTy = getOrCreateMethodType(Method, Unit);
22682293

2269-
// Since a single ctor/dtor corresponds to multiple functions, it doesn't
2270-
// make sense to give a single ctor/dtor a linkage name.
22712294
StringRef MethodLinkageName;
22722295
// FIXME: 'isFunctionLocalClass' seems like an arbitrary/unintentional
22732296
// property to use here. It may've been intended to model "is non-external
22742297
// type" but misses cases of non-function-local but non-external classes such
22752298
// as those in anonymous namespaces as well as the reverse - external types
22762299
// that are function local, such as those in (non-local) inline functions.
2277-
if (!IsCtorOrDtor && !isFunctionLocalClass(Method->getParent()))
2278-
MethodLinkageName = CGM.getMangledName(Method);
2300+
if (!isFunctionLocalClass(Method->getParent()))
2301+
MethodLinkageName = GetMethodLinkageName(Method);
22792302

22802303
// Get the location for the method.
22812304
llvm::DIFile *MethodDefUnit = nullptr;

clang/lib/CodeGen/CGDebugInfo.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -903,6 +903,10 @@ class CGDebugInfo {
903903
std::memcpy(Data + A.size(), B.data(), B.size());
904904
return StringRef(Data, A.size() + B.size());
905905
}
906+
907+
/// If one exists, returns the linkage name of the specified \
908+
/// (non-null) \c Method. Returns empty string otherwise.
909+
llvm::StringRef GetMethodLinkageName(const CXXMethodDecl *Method) const;
906910
};
907911

908912
/// 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
@@ -92,6 +92,8 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {
9292

9393
case Dtor_Comdat:
9494
llvm_unreachable("emitting dtor comdat as function?");
95+
case Dtor_Unified:
96+
llvm_unreachable("emitting unified dtor as function?");
9597
}
9698
llvm_unreachable("bad dtor kind");
9799
}
@@ -109,6 +111,9 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {
109111

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

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
}
@@ -1410,6 +1412,8 @@ llvm::GlobalValue::LinkageTypes MicrosoftCXXABI::getCXXDestructorLinkage(
14101412
// and are emitted everywhere they are used. They are internal if the class
14111413
// is internal.
14121414
return llvm::GlobalValue::LinkOnceODRLinkage;
1415+
case Dtor_Unified:
1416+
llvm_unreachable("MS C++ ABI does not support unified dtors");
14131417
case Dtor_Comdat:
14141418
llvm_unreachable("MS C++ ABI does not support comdat dtors");
14151419
}

0 commit comments

Comments
 (0)