Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions clang/include/clang/Basic/ABI.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,16 @@ enum CXXCtorType {
Ctor_Comdat, ///< The COMDAT used for ctors
Ctor_CopyingClosure, ///< Copying closure variant of a ctor
Ctor_DefaultClosure, ///< Default closure variant of a ctor
Ctor_Unified, ///< GCC-style unified dtor
};

/// C++ destructor types.
enum CXXDtorType {
Dtor_Deleting, ///< Deleting dtor
Dtor_Complete, ///< Complete object dtor
Dtor_Base, ///< Base object dtor
Dtor_Comdat ///< The COMDAT used for dtors
Dtor_Deleting, ///< Deleting dtor
Dtor_Complete, ///< Complete object dtor
Dtor_Base, ///< Base object dtor
Dtor_Comdat, ///< The COMDAT used for dtors
Dtor_Unified, ///< GCC-style unified dtor
};

} // end namespace clang
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/DebugOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,12 @@ DEBUGOPT(DebugNameTable, 2, 0, Affecting)
/// Whether to use DWARF base address specifiers in .debug_ranges.
DEBUGOPT(DebugRangesBaseAddress, 1, 0, Affecting)

/// Whether to add linkage names to constructor/destructor declarations.
/// This is an escape hatch for cases where attaching the additional linkage
/// names would increase debug-info size (particularly the .debug_str section)
/// too much.
DEBUGOPT(DebugStructorDeclLinkageNames, 1, 0, Benign)

/// Whether to embed source in DWARF debug line section.
DEBUGOPT(EmbedSource, 1, 0, Affecting)

Expand Down
12 changes: 12 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -4899,6 +4899,18 @@ def gembed_source : Flag<["-"], "gembed-source">, Group<g_flags_Group>,
def gno_embed_source : Flag<["-"], "gno-embed-source">, Group<g_flags_Group>,
Flags<[NoXarchOption]>,
HelpText<"Restore the default behavior of not embedding source text in DWARF debug sections">;
defm structor_decl_linkage_names
: BoolGOption<"structor-decl-linkage-names",
CodeGenOpts<"DebugStructorDeclLinkageNames">, DefaultTrue,
NegFlag<SetFalse>,
PosFlag<SetTrue, [], [],
"Attach linkage names to C++ constructor/destructor "
"declarations in DWARF."
"Implies -g.">,
BothFlags<[], [ClangOption, CLOption, CC1Option]>>,
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``.

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``.}]>;
defm key_instructions : BoolGOption<"key-instructions",
CodeGenOpts<"DebugKeyInstructions">, DefaultFalse,
NegFlag<SetFalse>, PosFlag<SetTrue, [], [],
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6068,6 +6068,8 @@ void CXXNameMangler::mangleCXXCtorType(CXXCtorType T,
// ::= CI2 <type> # base inheriting constructor
//
// In addition, C5 is a comdat name with C1 and C2 in it.
// C4 represents a ctor declaration and is used by debuggers to look up
// the various ctor variants.
Out << 'C';
if (InheritedFrom)
Out << 'I';
Expand All @@ -6078,6 +6080,9 @@ void CXXNameMangler::mangleCXXCtorType(CXXCtorType T,
case Ctor_Base:
Out << '2';
break;
case Ctor_Unified:
Out << '4';
break;
case Ctor_Comdat:
Out << '5';
break;
Expand All @@ -6095,6 +6100,8 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
// ::= D2 # base object destructor
//
// In addition, D5 is a comdat name with D1, D2 and, if virtual, D0 in it.
// D4 represents a dtor declaration and is used by debuggers to look up
// the various dtor variants.
switch (T) {
case Dtor_Deleting:
Out << "D0";
Expand All @@ -6105,6 +6112,9 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
case Dtor_Base:
Out << "D2";
break;
case Dtor_Unified:
Out << "D4";
break;
case Dtor_Comdat:
Out << "D5";
break;
Expand Down
37 changes: 36 additions & 1 deletion clang/lib/AST/Mangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,37 @@ bool MangleContext::shouldMangleDeclName(const NamedDecl *D) {
return shouldMangleCXXName(D);
}

static llvm::StringRef g_lldb_func_call_label_prefix = "$__lldb_func:";

/// Given an LLDB function call label, this function prints the label
/// into \c Out, together with the structor type of \c GD (if the
/// decl is a constructor/destructor). LLDB knows how to handle mangled
/// names with this encoding.
///
/// Example input label:
/// $__lldb_func::123:456:~Foo
///
/// Example output:
/// $__lldb_func:D1:123:456:~Foo
///
static void emitLLDBAsmLabel(llvm::StringRef label, GlobalDecl GD,
llvm::raw_ostream &Out) {
assert(label.starts_with(g_lldb_func_call_label_prefix));

Out << g_lldb_func_call_label_prefix;

if (auto *Ctor = llvm::dyn_cast<clang::CXXConstructorDecl>(GD.getDecl())) {
Out << "C";
if (Ctor->getInheritedConstructor().getConstructor())
Out << "I";
Out << GD.getCtorType();
} else if (llvm::isa<clang::CXXDestructorDecl>(GD.getDecl())) {
Out << "D" << GD.getDtorType();
}

Out << label.substr(g_lldb_func_call_label_prefix.size());
}

void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
const ASTContext &ASTContext = getASTContext();
const NamedDecl *D = cast<NamedDecl>(GD.getDecl());
Expand Down Expand Up @@ -185,7 +216,11 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
if (!UserLabelPrefix.empty())
Out << '\01'; // LLVM IR Marker for __asm("foo")

Out << ALA->getLabel();
if (ALA->getLabel().starts_with(g_lldb_func_call_label_prefix))
emitLLDBAsmLabel(ALA->getLabel(), GD, Out);
else
Out << ALA->getLabel();

return;
}

Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/MicrosoftMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1497,6 +1497,8 @@ void MicrosoftCXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
// it.
case Dtor_Comdat:
llvm_unreachable("not expecting a COMDAT");
case Dtor_Unified:
llvm_unreachable("not expecting a unified dtor type");
}
llvm_unreachable("Unsupported dtor type?");
}
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CGClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1493,6 +1493,8 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
// we'd introduce *two* handler blocks. In the Microsoft ABI, we
// always delegate because we might not have a definition in this TU.
switch (DtorType) {
case Dtor_Unified:
llvm_unreachable("not expecting a unified dtor");
case Dtor_Comdat: llvm_unreachable("not expecting a COMDAT");
case Dtor_Deleting: llvm_unreachable("already handled deleting case");

Expand Down
35 changes: 29 additions & 6 deletions clang/lib/CodeGen/CGDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2258,24 +2258,47 @@ static bool isFunctionLocalClass(const CXXRecordDecl *RD) {
return false;
}

llvm::StringRef
CGDebugInfo::GetMethodLinkageName(const CXXMethodDecl *Method) const {
assert(Method);

const bool IsCtorOrDtor =
isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method);

if (IsCtorOrDtor && !CGM.getCodeGenOpts().DebugStructorDeclLinkageNames)
return {};

// In some ABIs (particularly Itanium) a single ctor/dtor
// corresponds to multiple functions. Attach a "unified"
// linkage name for those (which is the convention GCC uses).
// Otherwise, attach no linkage name.
if (IsCtorOrDtor && !CGM.getTarget().getCXXABI().hasConstructorVariants())
return {};

if (const auto *Ctor = llvm::dyn_cast<CXXConstructorDecl>(Method))
return CGM.getMangledName(GlobalDecl(Ctor, CXXCtorType::Ctor_Unified));

if (const auto *Dtor = llvm::dyn_cast<CXXDestructorDecl>(Method))
return CGM.getMangledName(GlobalDecl(Dtor, CXXDtorType::Dtor_Unified));

return CGM.getMangledName(Method);
}

llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction(
const CXXMethodDecl *Method, llvm::DIFile *Unit, llvm::DIType *RecordTy) {
bool IsCtorOrDtor =
isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method);
assert(Method);

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

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

// Get the location for the method.
llvm::DIFile *MethodDefUnit = nullptr;
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/CodeGen/CGDebugInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -903,6 +903,10 @@ class CGDebugInfo {
std::memcpy(Data + A.size(), B.data(), B.size());
return StringRef(Data, A.size() + B.size());
}

/// If one exists, returns the linkage name of the specified \
/// (non-null) \c Method. Returns empty string otherwise.
llvm::StringRef GetMethodLinkageName(const CXXMethodDecl *Method) const;
};

/// A scoped helper to set the current debug location to the specified
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/CodeGen/ItaniumCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {

case Dtor_Comdat:
llvm_unreachable("emitting dtor comdat as function?");
case Dtor_Unified:
llvm_unreachable("emitting unified dtor as function?");
}
llvm_unreachable("bad dtor kind");
}
Expand All @@ -109,6 +111,9 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {

case Ctor_Comdat:
llvm_unreachable("emitting ctor comdat as function?");

case Ctor_Unified:
llvm_unreachable("emitting unified ctor as function?");
}
llvm_unreachable("bad dtor kind");
}
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/CodeGen/MicrosoftCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ class MicrosoftCXXABI : public CGCXXABI {
return false;

case Dtor_Comdat: llvm_unreachable("emitting dtor comdat as function?");
case Dtor_Unified:
llvm_unreachable("unexpected unified dtor type");
}
llvm_unreachable("bad dtor kind");
}
Expand Down Expand Up @@ -1410,6 +1412,8 @@ llvm::GlobalValue::LinkageTypes MicrosoftCXXABI::getCXXDestructorLinkage(
// and are emitted everywhere they are used. They are internal if the class
// is internal.
return llvm::GlobalValue::LinkOnceODRLinkage;
case Dtor_Unified:
llvm_unreachable("MS C++ ABI does not support unified dtors");
case Dtor_Comdat:
llvm_unreachable("MS C++ ABI does not support comdat dtors");
}
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4634,6 +4634,10 @@ renderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T,
options::OPT_gno_key_instructions, false))
CmdArgs.push_back("-gkey-instructions");

if (!Args.hasFlag(options::OPT_gstructor_decl_linkage_names,
options::OPT_gno_structor_decl_linkage_names, true))
CmdArgs.push_back("-gno-structor-decl-linkage-names");

if (EmitCodeView) {
CmdArgs.push_back("-gcodeview");

Expand Down
3 changes: 2 additions & 1 deletion clang/test/CodeGenCXX/debug-info-artificial-arg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ int main(int argc, char **argv) {
// CHECK: ![[CLASSTYPE:.*]] = distinct !DICompositeType(tag: DW_TAG_class_type, name: "A",
// CHECK-SAME: identifier: "_ZTS1A"
// CHECK: ![[ARTARG:.*]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[CLASSTYPE]],{{.*}} DIFlagArtificial
// CHECK: !DISubprogram(name: "A", scope: ![[CLASSTYPE]]
// CHECK: !DISubprogram(name: "A"
// CHECK-SAME: scope: ![[CLASSTYPE]]
// CHECK-SAME: line: 12
// CHECK-SAME: DIFlagPublic
// CHECK: !DISubroutineType(types: [[FUNCTYPE:![0-9]*]])
Expand Down
29 changes: 29 additions & 0 deletions clang/test/CodeGenCXX/local-structor-linkage-names.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Tests that we emit don't emit unified constructor/destructor linkage names
// for function-local constructors.

// Check with -gstructor-decl-linkage-names.
// RUN: %clang_cc1 -triple aarch64-apple-macosx -emit-llvm -debug-info-kind=standalone \
// RUN: -gstructor-decl-linkage-names %s -o - | FileCheck %s --check-prefixes=CHECK
//
// Check with -gno-structor-decl-linkage-names.
// RUN: %clang_cc1 -triple aarch64-apple-macosx -emit-llvm -debug-info-kind=standalone \
// RUN: -gno-structor-decl-linkage-names %s -o - | FileCheck %s --check-prefixes=CHECK

struct HasNestedCtor {
HasNestedCtor();
};

HasNestedCtor::HasNestedCtor() {
struct Local {
Local() {}
~Local() {}
} l;
}

// CHECK: !DISubprogram(name: "Local"
// CHECK-NOT: linkageName
// CHECK-SAME: )

// CHECK: !DISubprogram(name: "~Local"
// CHECK-NOT: linkageName
// CHECK-SAME: )
Loading