From 9824022af77e3f53dd452e6de19c9b8087aadb0a Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Fri, 5 Oct 2018 20:37:17 +0000 Subject: [PATCH] [DebugInfo] Add support for DWARF5 call site-related attributes DWARF v5 introduces DW_AT_call_all_calls, a subprogram attribute which indicates that all calls (both regular and tail) within the subprogram have call site entries. The information within these call site entries can be used by a debugger to populate backtraces with synthetic tail call frames. Tail calling frames go missing in backtraces because the frame of the caller is reused by the callee. Call site entries allow a debugger to reconstruct a sequence of (tail) calls which led from one function to another. This improves backtrace quality. There are limitations: tail recursion isn't handled, variables within synthetic frames may not survive to be inspected, etc. This approach is not novel, see: https://gcc.gnu.org/wiki/summit2010?action=AttachFile&do=get&target=jelinek.pdf This patch adds an IR-level flag (DIFlagAllCallsDescribed) which lowers to DW_AT_call_all_calls. It adds the minimal amount of DWARF generation support needed to emit standards-compliant call site entries. For easier deployment, when the debugger tuning is LLDB, the DWARF requirement is adjusted to v4. Testing: Apart from check-{llvm, clang}, I built a stage2 RelWithDebInfo clang binary. Its dSYM passed verification and grew by 1.4% compared to the baseline. 151,879 call site entries were added. rdar://42001377 Differential Revision: https://reviews.llvm.org/D49887 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@343883 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGDebugInfo.cpp | 24 +++++++- lib/CodeGen/CGDebugInfo.h | 5 ++ .../dbg-info-all-calls-described.cpp | 61 +++++++++++++++++++ 3 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 test/CodeGenCXX/dbg-info-all-calls-described.cpp diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index c87d74657d..bcd5338ac0 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -3168,6 +3168,7 @@ llvm::DISubprogram *CGDebugInfo::getFunctionFwdDeclOrStub(GlobalDecl GD, QualType FnType = CGM.getContext().getFunctionType( FD->getReturnType(), ArgTypes, FunctionProtoType::ExtProtoInfo(CC)); if (Stub) { + Flags |= getCallSiteRelatedAttrs(); return DBuilder.createFunction( DContext, Name, LinkageName, Unit, Line, getOrCreateFunctionType(GD.getDecl(), FnType, Unit), @@ -3407,6 +3408,8 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc, if (CurFuncIsThunk) Flags |= llvm::DINode::FlagThunk; + llvm::DINode::DIFlags FlagsForDef = Flags | getCallSiteRelatedAttrs(); + unsigned LineNo = getLineNumber(Loc); unsigned ScopeLine = getLineNumber(ScopeLoc); @@ -3418,7 +3421,7 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc, llvm::DISubprogram *SP = DBuilder.createFunction( FDContext, Name, LinkageName, Unit, LineNo, getOrCreateFunctionType(D, FnType, Unit), Fn->hasLocalLinkage(), - true /*definition*/, ScopeLine, Flags, CGM.getLangOpts().Optimize, + true /*definition*/, ScopeLine, FlagsForDef, CGM.getLangOpts().Optimize, TParamsArray.get(), getFunctionDeclaration(D)); Fn->setSubprogram(SP); // We might get here with a VarDecl in the case we're generating @@ -4422,3 +4425,22 @@ llvm::DebugLoc CGDebugInfo::SourceLocToDebugLoc(SourceLocation Loc) { llvm::MDNode *Scope = LexicalBlockStack.back(); return llvm::DebugLoc::get(getLineNumber(Loc), getColumnNumber(Loc), Scope); } + +llvm::DINode::DIFlags CGDebugInfo::getCallSiteRelatedAttrs() const { + // Call site-related attributes are only useful in optimized programs, and + // when there's a possibility of debugging backtraces. + if (!CGM.getLangOpts().Optimize || DebugKind == codegenoptions::NoDebugInfo || + DebugKind == codegenoptions::LocTrackingOnly) + return llvm::DINode::FlagZero; + + // Call site-related attributes are available in DWARF v5. Some debuggers, + // while not fully DWARF v5-compliant, may accept these attributes as if they + // were part of DWARF v4. + bool SupportsDWARFv4Ext = + CGM.getCodeGenOpts().DwarfVersion == 4 && + CGM.getCodeGenOpts().getDebuggerTuning() == llvm::DebuggerKind::LLDB; + if (!SupportsDWARFv4Ext && CGM.getCodeGenOpts().DwarfVersion < 5) + return llvm::DINode::FlagZero; + + return llvm::DINode::FlagAllCallsDescribed; +} diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index b007621c72..aceb91de51 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -608,6 +608,11 @@ private: unsigned LineNo, StringRef LinkageName, llvm::GlobalVariable *Var, llvm::DIScope *DContext); + + /// Return flags which enable debug info emission for call sites, provided + /// that it is supported and enabled. + llvm::DINode::DIFlags getCallSiteRelatedAttrs() const; + /// Get the printing policy for producing names for debug info. PrintingPolicy getPrintingPolicy() const; diff --git a/test/CodeGenCXX/dbg-info-all-calls-described.cpp b/test/CodeGenCXX/dbg-info-all-calls-described.cpp new file mode 100644 index 0000000000..2fc6533fec --- /dev/null +++ b/test/CodeGenCXX/dbg-info-all-calls-described.cpp @@ -0,0 +1,61 @@ +// Test that call site debug info is (un)supported in various configurations. + +// Supported: DWARF5, -O1, standalone DI +// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple %s -o - \ +// RUN: -O1 -disable-llvm-passes \ +// RUN: -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: | FileCheck %s -check-prefix=HAS-ATTR \ +// RUN: -implicit-check-not=DISubprogram -implicit-check-not=DIFlagAllCallsDescribed + +// Supported: DWARF4 + LLDB tuning, -O1, limited DI +// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple %s -o - \ +// RUN: -O1 -disable-llvm-passes \ +// RUN: -debugger-tuning=lldb \ +// RUN: -debug-info-kind=standalone -dwarf-version=4 \ +// RUN: | FileCheck %s -check-prefix=HAS-ATTR \ +// RUN: -implicit-check-not=DISubprogram -implicit-check-not=DIFlagAllCallsDescribed + +// Supported: DWARF4 + LLDB tuning, -O1, line-tables only DI +// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple %s -o - \ +// RUN: -O1 -disable-llvm-passes \ +// RUN: -debugger-tuning=lldb \ +// RUN: -debug-info-kind=line-tables-only -dwarf-version=4 \ +// RUN: | FileCheck %s -check-prefix=LINE-TABLES-ONLY + +// Unsupported: -O0 +// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple %s -o - \ +// RUN: -O0 \ +// RUN: -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: | FileCheck %s -check-prefix=NO-ATTR + +// Unsupported: DWARF4 +// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple %s -o - \ +// RUN: -O1 -disable-llvm-passes \ +// RUN: -debug-info-kind=standalone -dwarf-version=4 \ +// RUN: | FileCheck %s -check-prefix=NO-ATTR + +// NO-ATTR-NOT: FlagAllCallsDescribed + +// HAS-ATTR-DAG: DISubprogram(name: "declaration2", {{.*}}, isDefinition: true, {{.*}}, flags: DIFlagPrototyped | DIFlagAllCallsDescribed +// HAS-ATTR-DAG: DISubprogram(name: "struct1", {{.*}}, isDefinition: false, {{.*}}, flags: DIFlagPrototyped +// HAS-ATTR-DAG: DISubprogram(name: "struct1", {{.*}}, isDefinition: true, {{.*}}, flags: DIFlagPrototyped | DIFlagAllCallsDescribed +// HAS-ATTR-DAG: DISubprogram(name: "method1", {{.*}}, isDefinition: true, {{.*}}, flags: DIFlagPrototyped | DIFlagAllCallsDescribed +// HAS-ATTR-DAG: DISubprogram(name: "force_irgen", {{.*}}, isDefinition: true, {{.*}}, flags: DIFlagPrototyped | DIFlagAllCallsDescribed + +// LINE-TABLES-ONLY: DISubprogram(name: "force_irgen", {{.*}}, isDefinition: true, {{.*}}, flags: DIFlagPrototyped | DIFlagAllCallsDescribed + +void declaration1(); + +void declaration2(); + +void declaration2() {} + +struct struct1 { + struct1() {} + void method1() {} +}; + +void __attribute__((optnone)) force_irgen() { + declaration1(); + struct1().method1(); +} -- 2.40.0