summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/CodeGen/CGDebugInfo.cpp24
-rw-r--r--clang/lib/CodeGen/CGDebugInfo.h5
-rw-r--r--clang/test/CodeGenCXX/dbg-info-all-calls-described.cpp61
-rw-r--r--llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h8
-rw-r--r--llvm/include/llvm/IR/DebugInfoFlags.def3
-rw-r--r--llvm/include/llvm/IR/DebugInfoMetadata.h3
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp31
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h10
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp68
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h4
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp33
-rw-r--r--llvm/lib/IR/Verifier.cpp4
-rw-r--r--llvm/test/DebugInfo/Generic/callsite-attr-invalid.ll48
-rw-r--r--llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs.ll133
-rw-r--r--llvm/test/tools/llvm-dwarfdump/X86/callsite-invalid.s376
-rw-r--r--llvm/tools/llvm-dwarfdump/Statistics.cpp8
16 files changed, 814 insertions, 5 deletions
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index c87d74657d7..bcd5338ac05 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/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/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h
index b007621c723..aceb91de510 100644
--- a/clang/lib/CodeGen/CGDebugInfo.h
+++ b/clang/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/clang/test/CodeGenCXX/dbg-info-all-calls-described.cpp b/clang/test/CodeGenCXX/dbg-info-all-calls-described.cpp
new file mode 100644
index 00000000000..2fc6533fece
--- /dev/null
+++ b/clang/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();
+}
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h
index 6de7fc7e2be..3ad65cf51b1 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h
@@ -148,6 +148,8 @@ private:
/// - That the root DIE is a unit DIE.
/// - If a unit type is provided, that the unit DIE matches the unit type.
/// - The DIE ranges.
+ /// - That call site entries are only nested within subprograms with a
+ /// DW_AT_call attribute.
///
/// \param Unit The DWARF Unit to verify.
///
@@ -164,6 +166,12 @@ private:
unsigned verifyUnitSection(const DWARFSection &S,
DWARFSectionKind SectionKind);
+ /// Verifies that a call site entry is nested within a subprogram with a
+ /// DW_AT_call attribute.
+ ///
+ /// \returns Number of errors that occurred during verification.
+ unsigned verifyDebugInfoCallSite(const DWARFDie &Die);
+
/// Verify that all Die ranges are valid.
///
/// This function currently checks for:
diff --git a/llvm/include/llvm/IR/DebugInfoFlags.def b/llvm/include/llvm/IR/DebugInfoFlags.def
index 53fa32d177d..a3c3430768f 100644
--- a/llvm/include/llvm/IR/DebugInfoFlags.def
+++ b/llvm/include/llvm/IR/DebugInfoFlags.def
@@ -50,6 +50,7 @@ HANDLE_DI_FLAG((1 << 25), Thunk)
HANDLE_DI_FLAG((1 << 26), Trivial)
HANDLE_DI_FLAG((1 << 27), BigEndian)
HANDLE_DI_FLAG((1 << 28), LittleEndian)
+HANDLE_DI_FLAG((1 << 29), AllCallsDescribed)
// To avoid needing a dedicated value for IndirectVirtualBase, we use
// the bitwise or of Virtual and FwdDecl, which does not otherwise
@@ -59,7 +60,7 @@ HANDLE_DI_FLAG((1 << 2) | (1 << 5), IndirectVirtualBase)
#ifdef DI_FLAG_LARGEST_NEEDED
// intended to be used with ADT/BitmaskEnum.h
// NOTE: always must be equal to largest flag, check this when adding new flag
-HANDLE_DI_FLAG((1 << 28), Largest)
+HANDLE_DI_FLAG((1 << 29), Largest)
#undef DI_FLAG_LARGEST_NEEDED
#endif
diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h
index e512e43476e..2a9181e17c6 100644
--- a/llvm/include/llvm/IR/DebugInfoMetadata.h
+++ b/llvm/include/llvm/IR/DebugInfoMetadata.h
@@ -1736,6 +1736,9 @@ public:
}
bool isExplicit() const { return getFlags() & FlagExplicit; }
bool isPrototyped() const { return getFlags() & FlagPrototyped; }
+ bool areAllCallsDescribed() const {
+ return getFlags() & FlagAllCallsDescribed;
+ }
bool isMainSubprogram() const { return getFlags() & FlagMainSubprogram; }
/// Check if this is reference-qualified.
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
index d8d6f76d71e..443c8879f13 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
@@ -730,7 +730,8 @@ DIE *DwarfCompileUnit::createScopeChildrenDIE(LexicalScope *Scope,
return ObjectPointer;
}
-void DwarfCompileUnit::constructSubprogramScopeDIE(const DISubprogram *Sub, LexicalScope *Scope) {
+DIE &DwarfCompileUnit::constructSubprogramScopeDIE(const DISubprogram *Sub,
+ LexicalScope *Scope) {
DIE &ScopeDIE = updateSubprogramScopeDIE(Sub);
if (Scope) {
@@ -753,6 +754,8 @@ void DwarfCompileUnit::constructSubprogramScopeDIE(const DISubprogram *Sub, Lexi
!includeMinimalInlineScopes())
ScopeDIE.addChild(
DIE::get(DIEValueAllocator, dwarf::DW_TAG_unspecified_parameters));
+
+ return ScopeDIE;
}
DIE *DwarfCompileUnit::createAndAddScopeChildren(LexicalScope *Scope,
@@ -807,6 +810,32 @@ void DwarfCompileUnit::constructAbstractSubprogramScopeDIE(
ContextCU->addDIEEntry(*AbsDef, dwarf::DW_AT_object_pointer, *ObjectPointer);
}
+DIE &DwarfCompileUnit::constructCallSiteEntryDIE(DIE &ScopeDIE,
+ const DISubprogram &CalleeSP,
+ bool IsTail,
+ const MCSymbol *ReturnPC) {
+ // Insert a call site entry DIE within ScopeDIE.
+ DIE &CallSiteDIE =
+ createAndAddDIE(dwarf::DW_TAG_call_site, ScopeDIE, nullptr);
+
+ // For the purposes of showing tail call frames in backtraces, a key piece of
+ // information is DW_AT_call_origin, a pointer to the callee DIE.
+ DIE *CalleeDIE = getOrCreateSubprogramDIE(&CalleeSP);
+ assert(CalleeDIE && "Could not create DIE for call site entry origin");
+ addDIEEntry(CallSiteDIE, dwarf::DW_AT_call_origin, *CalleeDIE);
+
+ if (IsTail) {
+ // Attach DW_AT_call_tail_call to tail calls for standards compliance.
+ addFlag(CallSiteDIE, dwarf::DW_AT_call_tail_call);
+ } else {
+ // Attach the return PC to allow the debugger to disambiguate call paths
+ // from one function to another.
+ assert(ReturnPC && "Missing return PC information for a call");
+ addLabelAddress(CallSiteDIE, dwarf::DW_AT_call_return_pc, ReturnPC);
+ }
+ return CallSiteDIE;
+}
+
DIE *DwarfCompileUnit::constructImportedEntityDIE(
const DIImportedEntity *Module) {
DIE *IMDie = DIE::get(DIEValueAllocator, (dwarf::Tag)Module->getTag());
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
index 9bf1ce18b3a..6389ccd686d 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
@@ -203,12 +203,20 @@ public:
bool *HasNonScopeChildren = nullptr);
/// Construct a DIE for this subprogram scope.
- void constructSubprogramScopeDIE(const DISubprogram *Sub, LexicalScope *Scope);
+ DIE &constructSubprogramScopeDIE(const DISubprogram *Sub,
+ LexicalScope *Scope);
DIE *createAndAddScopeChildren(LexicalScope *Scope, DIE &ScopeDIE);
void constructAbstractSubprogramScopeDIE(LexicalScope *Scope);
+ /// Construct a call site entry DIE describing a call within \p Scope to a
+ /// callee described by \p CalleeSP. \p IsTail specifies whether the call is
+ /// a tail call. \p ReturnPC must be non-null for non-tail calls and point
+ /// to the PC value after the call returns.
+ DIE &constructCallSiteEntryDIE(DIE &ScopeDIE, const DISubprogram &CalleeSP,
+ bool IsTail, const MCSymbol *ReturnPC);
+
/// Construct import_module DIE.
DIE *constructImportedEntityDIE(const DIImportedEntity *Module);
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index ede606131ff..ab3559d63cc 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -39,6 +39,7 @@
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineOperand.h"
+#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/IR/Constants.h"
@@ -502,6 +503,63 @@ void DwarfDebug::constructAbstractSubprogramScopeDIE(DwarfCompileUnit &SrcCU,
}
}
+void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP,
+ DwarfCompileUnit &CU, DIE &ScopeDIE,
+ const MachineFunction &MF) {
+ // Add a call site-related attribute (DWARF5, Sec. 3.3.1.3). Do this only if
+ // the subprogram is required to have one.
+ if (!SP.areAllCallsDescribed() || !SP.isDefinition())
+ return;
+
+ // Use DW_AT_call_all_calls to express that call site entries are present
+ // for both tail and non-tail calls. Don't use DW_AT_call_all_source_calls
+ // because one of its requirements is not met: call site entries for
+ // optimized-out calls are elided.
+ CU.addFlag(ScopeDIE, dwarf::DW_AT_call_all_calls);
+
+ const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
+ assert(TII && "TargetInstrInfo not found: cannot label tail calls");
+
+ // Emit call site entries for each call or tail call in the function.
+ for (const MachineBasicBlock &MBB : MF) {
+ for (const MachineInstr &MI : MBB.instrs()) {
+ // Skip instructions which aren't calls. Both calls and tail-calling jump
+ // instructions (e.g TAILJMPd64) are classified correctly here.
+ if (!MI.isCall())
+ continue;
+
+ // TODO: Add support for targets with delay slots (see: beginInstruction).
+ if (MI.hasDelaySlot())
+ return;
+
+ // If this is a direct call, find the callee's subprogram.
+ const MachineOperand &CalleeOp = MI.getOperand(0);
+ if (!CalleeOp.isGlobal())
+ continue;
+ const Function *CalleeDecl = dyn_cast<Function>(CalleeOp.getGlobal());
+ if (!CalleeDecl || !CalleeDecl->getSubprogram())
+ continue;
+
+ // TODO: Omit call site entries for runtime calls (objc_msgSend, etc).
+ // TODO: Add support for indirect calls.
+
+ bool IsTail = TII->isTailCall(MI);
+
+ // For tail calls, no return PC information is needed. For regular calls,
+ // the return PC is needed to disambiguate paths in the call graph which
+ // could lead to some target function.
+ const MCSymbol *ReturnPC = IsTail ? nullptr : getLabelAfterInsn(&MI);
+
+ assert((IsTail || ReturnPC) && "Call without return PC information");
+ LLVM_DEBUG(dbgs() << "CallSiteEntry: " << MF.getName() << " -> "
+ << CalleeDecl->getName() << (IsTail ? " [tail]" : "")
+ << "\n");
+ CU.constructCallSiteEntryDIE(ScopeDIE, *CalleeDecl->getSubprogram(),
+ IsTail, ReturnPC);
+ }
+ }
+}
+
void DwarfDebug::addGnuPubAttributes(DwarfCompileUnit &U, DIE &D) const {
if (!U.hasDwarfPubSections())
return;
@@ -1376,6 +1434,11 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) {
unsigned LastAsmLine =
Asm->OutStreamer->getContext().getCurrentDwarfLoc().getLine();
+ // Request a label after the call in order to emit AT_return_pc information
+ // in call site entries. TODO: Add support for targets with delay slots.
+ if (SP->areAllCallsDescribed() && MI->isCall() && !MI->hasDelaySlot())
+ requestLabelAfterInsn(MI);
+
if (DL == PrevInstLoc) {
// If we have an ongoing unspecified location, nothing to do here.
if (!DL)
@@ -1546,12 +1609,15 @@ void DwarfDebug::endFunctionImpl(const MachineFunction *MF) {
}
ProcessedSPNodes.insert(SP);
- TheCU.constructSubprogramScopeDIE(SP, FnScope);
+ DIE &ScopeDIE = TheCU.constructSubprogramScopeDIE(SP, FnScope);
if (auto *SkelCU = TheCU.getSkeleton())
if (!LScopes.getAbstractScopesList().empty() &&
TheCU.getCUNode()->getSplitDebugInlining())
SkelCU->constructSubprogramScopeDIE(SP, FnScope);
+ // Construct call site entries.
+ constructCallSiteEntryDIEs(*SP, TheCU, ScopeDIE, *MF);
+
// Clear debug info
// Ownership of DbgVariables is a bit subtle - ScopeVariables owns all the
// DbgVariables except those that are also in AbstractVariables (since they
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
index ba40ad28eb7..e115eb771fb 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
@@ -424,6 +424,10 @@ class DwarfDebug : public DebugHandlerBase {
/// Construct a DIE for this abstract scope.
void constructAbstractSubprogramScopeDIE(DwarfCompileUnit &SrcCU, LexicalScope *Scope);
+ /// Construct DIEs for call site entries describing the calls in \p MF.
+ void constructCallSiteEntryDIEs(const DISubprogram &SP, DwarfCompileUnit &CU,
+ DIE &ScopeDIE, const MachineFunction &MF);
+
template <typename DataT>
void addAccelNameImpl(const DICompileUnit &CU, AccelTable<DataT> &AppleAccel,
StringRef Name, const DIE &Die);
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
index 20259db7e47..c433fe470cb 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
@@ -194,6 +194,7 @@ unsigned DWARFVerifier::verifyUnitContents(DWARFUnit &Unit) {
dump(Die) << '\n';
NumUnitErrors++;
}
+ NumUnitErrors += verifyDebugInfoCallSite(Die);
}
DWARFDie Die = Unit.getUnitDIE(/* ExtractUnitDIEOnly = */ false);
@@ -223,6 +224,38 @@ unsigned DWARFVerifier::verifyUnitContents(DWARFUnit &Unit) {
return NumUnitErrors;
}
+unsigned DWARFVerifier::verifyDebugInfoCallSite(const DWARFDie &Die) {
+ if (Die.getTag() != DW_TAG_call_site)
+ return 0;
+
+ DWARFDie Curr = Die.getParent();
+ for (; Curr.isValid() && !Curr.isSubprogramDIE(); Curr = Die.getParent()) {
+ if (Curr.getTag() == DW_TAG_inlined_subroutine) {
+ error() << "Call site entry nested within inlined subroutine:";
+ Curr.dump(OS);
+ return 1;
+ }
+ }
+
+ if (!Curr.isValid()) {
+ error() << "Call site entry not nested within a valid subprogram:";
+ Die.dump(OS);
+ return 1;
+ }
+
+ Optional<DWARFFormValue> CallAttr =
+ Curr.find({DW_AT_call_all_calls, DW_AT_call_all_source_calls,
+ DW_AT_call_all_tail_calls});
+ if (!CallAttr) {
+ error() << "Subprogram with call site entry has no DW_AT_call attribute:";
+ Curr.dump(OS);
+ Die.dump(OS, /*indent*/ 1);
+ return 1;
+ }
+
+ return 0;
+}
+
unsigned DWARFVerifier::verifyAbbrevSection(const DWARFDebugAbbrev *Abbrev) {
unsigned NumErrors = 0;
if (Abbrev) {
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index cd032a840b0..84e9c6f9100 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -1119,6 +1119,10 @@ void Verifier::visitDISubprogram(const DISubprogram &N) {
AssertDI(Op && isa<DIType>(Op), "invalid thrown type", &N, ThrownTypes,
Op);
}
+
+ if (N.areAllCallsDescribed())
+ AssertDI(N.isDefinition(),
+ "DIFlagAllCallsDescribed must be attached to a definition");
}
void Verifier::visitDILexicalBlockBase(const DILexicalBlockBase &N) {
diff --git a/llvm/test/DebugInfo/Generic/callsite-attr-invalid.ll b/llvm/test/DebugInfo/Generic/callsite-attr-invalid.ll
new file mode 100644
index 00000000000..b8ddd8d609b
--- /dev/null
+++ b/llvm/test/DebugInfo/Generic/callsite-attr-invalid.ll
@@ -0,0 +1,48 @@
+; RUN: opt -verify < %s 2>&1 | FileCheck %s
+
+; CHECK: DIFlagAllCallsDescribed must be attached to a definition
+; CHECK: warning: ignoring invalid debug info
+
+; Source:
+; struct A { ~A(); };
+; void foo() { A x; }
+
+%struct.A = type { i8 }
+
+define void @_Z3foov() !dbg !8 {
+entry:
+ %x = alloca %struct.A, align 1
+ call void @llvm.dbg.declare(metadata %struct.A* %x, metadata !12, metadata !DIExpression()), !dbg !19
+ call void @_ZN1AD1Ev(%struct.A* %x) #3, !dbg !20
+ ret void, !dbg !20
+}
+
+declare void @llvm.dbg.declare(metadata, metadata, metadata)
+
+declare void @_ZN1AD1Ev(%struct.A*)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5, !6}
+!llvm.ident = !{!7}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 8.0.0 ", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "-", directory: "/Users/vsk/src/builds/llvm-project-tailcall-RA")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{i32 7, !"PIC Level", i32 2}
+!7 = !{!"clang version 8.0.0 "}
+!8 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !9, file: !9, line: 1, type: !10, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)
+!9 = !DIFile(filename: "<stdin>", directory: "/Users/vsk/src/builds/llvm-project-tailcall-RA")
+!10 = !DISubroutineType(types: !11)
+!11 = !{null}
+!12 = !DILocalVariable(name: "x", scope: !8, file: !9, line: 1, type: !13)
+!13 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "A", file: !9, line: 1, size: 8, flags: DIFlagTypePassByReference, elements: !14, identifier: "_ZTS1A")
+!14 = !{!15}
+!15 = !DISubprogram(name: "~A", scope: !13, file: !9, line: 1, type: !16, isLocal: false, isDefinition: false, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, isOptimized: false)
+!16 = !DISubroutineType(types: !17)
+!17 = !{null, !18}
+!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!19 = !DILocation(line: 1, column: 36, scope: !8)
+!20 = !DILocation(line: 1, column: 39, scope: !8)
diff --git a/llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs.ll b/llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs.ll
new file mode 100644
index 00000000000..5fb78e42372
--- /dev/null
+++ b/llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs.ll
@@ -0,0 +1,133 @@
+; $ clang++ -S -emit-llvm -o - -gdwarf-5 -o - -O1 tail2.cc
+; volatile int sink;
+; void __attribute__((noinline)) bat() { sink++; }
+; void __attribute__((noinline)) bar() { sink++; }
+; void __attribute__((noinline)) foo() {
+; bar(); bat();
+; bar(); bat();
+; }
+; int __attribute__((disable_tail_calls)) main() { foo(); }
+
+; REQUIRES: object-emission
+; RUN: %llc_dwarf < %s -o - | FileCheck %s -check-prefix=ASM
+; RUN: %llc_dwarf < %s -filetype=obj -o %t.o
+; RUN: llvm-dwarfdump %t.o -o - | FileCheck %s -check-prefix=OBJ -implicit-check-not=DW_TAG_call_site
+; RUN: llvm-dwarfdump -verify %t.o 2>&1 | FileCheck %s -check-prefix=VERIFY
+; RUN: llvm-dwarfdump -statistics %t.o | FileCheck %s -check-prefix=STATS
+; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis -o /dev/null
+
+; VERIFY: No errors.
+; STATS: "call site entries":5
+
+@sink = global i32 0, align 4, !dbg !0
+
+; ASM: DW_TAG_subprogram
+; ASM: DW_AT_call_all_calls
+; OBJ: [[bat_sp:.*]]: DW_TAG_subprogram
+; OBJ: DW_AT_call_all_calls (true)
+; OBJ: DW_AT_name ("bat")
+define void @_Z3batv() !dbg !13 {
+entry:
+ %0 = load volatile i32, i32* @sink, align 4, !dbg !16, !tbaa !17
+ %inc = add nsw i32 %0, 1, !dbg !16
+ store volatile i32 %inc, i32* @sink, align 4, !dbg !16, !tbaa !17
+ ret void, !dbg !21
+}
+
+; ASM: DW_TAG_subprogram
+; ASM: DW_AT_call_all_calls
+; OBJ: [[bar_sp:.*]]: DW_TAG_subprogram
+; OBJ: DW_AT_call_all_calls (true)
+; OBJ: DW_AT_name ("bar")
+define void @_Z3barv() !dbg !22 {
+entry:
+ %0 = load volatile i32, i32* @sink, align 4, !dbg !23, !tbaa !17
+ %inc = add nsw i32 %0, 1, !dbg !23
+ store volatile i32 %inc, i32* @sink, align 4, !dbg !23, !tbaa !17
+ ret void, !dbg !24
+}
+
+; ASM: DW_TAG_subprogram
+; ASM: DW_AT_call_all_calls
+; OBJ: [[foo_sp:.*]]: DW_TAG_subprogram
+; OBJ: DW_AT_call_all_calls (true)
+; OBJ: DW_AT_name ("foo")
+; OBJ: DW_TAG_call_site
+; OBJ: DW_AT_call_origin ([[bar_sp]])
+; OBJ: DW_AT_call_return_pc ({{[0x]+}}26)
+; OBJ: DW_TAG_call_site
+; OBJ: DW_AT_call_origin ([[bat_sp]])
+; OBJ: DW_AT_call_return_pc ({{[0x]+}}2b)
+; OBJ: DW_TAG_call_site
+; OBJ: DW_AT_call_origin ([[bar_sp]])
+; OBJ: DW_AT_call_return_pc ({{[0x]+}}30)
+; OBJ: DW_TAG_call_site
+; OBJ: DW_AT_call_origin ([[bat_sp]])
+; OBJ: DW_AT_call_tail_call
+define void @_Z3foov() !dbg !25 {
+entry:
+ tail call void @_Z3barv(), !dbg !26
+ tail call void @_Z3batv(), !dbg !27
+ tail call void @_Z3barv(), !dbg !26
+ tail call void @_Z3batv(), !dbg !27
+ ret void, !dbg !28
+}
+
+; ASM: DW_TAG_subprogram
+; ASM: DW_AT_call_all_calls
+; OBJ: DW_TAG_subprogram
+; OBJ: DW_AT_call_all_calls (true)
+; OBJ: DW_AT_name ("main")
+; OBJ: DW_TAG_call_site
+; OBJ: DW_AT_call_origin ([[foo_sp]])
+; OBJ: DW_AT_call_return_pc ({{[0x]+}}46)
+define i32 @main() !dbg !29 {
+entry:
+ call void @_Z3foov(), !dbg !32
+
+ %indirect_target = load void ()*, void ()** undef
+ call void %indirect_target()
+
+ call void asm sideeffect "", "~{dirflag},~{fpsr},~{flags}"()
+
+ ret i32 0, !dbg !33
+}
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!8, !9, !10, !11}
+!llvm.ident = !{!12}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "sink", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 7.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5)
+!3 = !DIFile(filename: "/Users/vsk/src/llvm.org-tailcall/tail2.cc", directory: "/Users/vsk/src/builds/llvm-project-tailcall-RA", checksumkind: CSK_MD5, checksum: "3b61952c21b7f657ddb7c0ad44cf5529")
+!4 = !{}
+!5 = !{!0}
+!6 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !7)
+!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!8 = !{i32 2, !"Dwarf Version", i32 5}
+!9 = !{i32 2, !"Debug Info Version", i32 3}
+!10 = !{i32 1, !"wchar_size", i32 4}
+!11 = !{i32 7, !"PIC Level", i32 2}
+!12 = !{!"clang version 7.0.0 "}
+!13 = distinct !DISubprogram(name: "bat", linkageName: "_Z3batv", scope: !3, file: !3, line: 2, type: !14, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, isOptimized: true, unit: !2, retainedNodes: !4)
+!14 = !DISubroutineType(types: !15)
+!15 = !{null}
+!16 = !DILocation(line: 2, column: 44, scope: !13)
+!17 = !{!18, !18, i64 0}
+!18 = !{!"int", !19, i64 0}
+!19 = !{!"omnipotent char", !20, i64 0}
+!20 = !{!"Simple C++ TBAA"}
+!21 = !DILocation(line: 2, column: 48, scope: !13)
+!22 = distinct !DISubprogram(name: "bar", linkageName: "_Z3barv", scope: !3, file: !3, line: 3, type: !14, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, isOptimized: true, unit: !2, retainedNodes: !4)
+!23 = !DILocation(line: 3, column: 44, scope: !22)
+!24 = !DILocation(line: 3, column: 48, scope: !22)
+!25 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !3, file: !3, line: 4, type: !14, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, isOptimized: true, unit: !2, retainedNodes: !4)
+!26 = !DILocation(line: 5, column: 3, scope: !25)
+!27 = !DILocation(line: 6, column: 3, scope: !25)
+!28 = !DILocation(line: 7, column: 1, scope: !25)
+!29 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 8, type: !30, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, isOptimized: true, unit: !2, retainedNodes: !4)
+!30 = !DISubroutineType(types: !31)
+!31 = !{!7}
+!32 = !DILocation(line: 8, column: 50, scope: !29)
+!33 = !DILocation(line: 8, column: 57, scope: !29)
diff --git a/llvm/test/tools/llvm-dwarfdump/X86/callsite-invalid.s b/llvm/test/tools/llvm-dwarfdump/X86/callsite-invalid.s
new file mode 100644
index 00000000000..dcb5ac55e97
--- /dev/null
+++ b/llvm/test/tools/llvm-dwarfdump/X86/callsite-invalid.s
@@ -0,0 +1,376 @@
+# RUN: llvm-mc -triple x86_64-apple-darwin %s -filetype=obj -o %t.o
+# RUN: not llvm-dwarfdump -verify %t.o 2>&1 | FileCheck %s
+
+# CHECK: error: Subprogram with call site entry has no DW_AT_call attribute:
+# CHECK: DW_TAG_subprogram
+# CHECK: DW_AT_name ("main")
+# CHECK: DW_TAG_call_site
+# CHECK: DW_AT_call_origin
+# CHECK: Errors detected.
+
+# Source:
+## define void @foo() !dbg !25 {
+## ret void, !dbg !28
+## }
+##
+## define i32 @main() !dbg !29 {
+## call void @foo(), !dbg !32
+## ret i32 0, !dbg !33
+## }
+##
+## !llvm.dbg.cu = !{!2}
+## !llvm.module.flags = !{!8, !9, !10, !11}
+## !llvm.ident = !{!12}
+##
+## !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+## !1 = distinct !DIGlobalVariable(name: "sink", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true)
+## !2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 7.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5)
+## !3 = !DIFile(filename: "/Users/vsk/src/llvm.org-tailcall/tail2.cc", directory: "/Users/vsk/src/builds/llvm-project-tailcall-RA", checksumkind: CSK_MD5, checksum: "3b61952c21b7f657ddb7c0ad44cf5529")
+## !4 = !{}
+## !5 = !{!0}
+## !6 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !7)
+## !7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+## !8 = !{i32 2, !"Dwarf Version", i32 5}
+## !9 = !{i32 2, !"Debug Info Version", i32 3}
+## !10 = !{i32 1, !"wchar_size", i32 4}
+## !11 = !{i32 7, !"PIC Level", i32 2}
+## !12 = !{!"clang version 7.0.0 "}
+## !13 = distinct !DISubprogram(name: "bat", linkageName: "_Z3batv", scope: !3, file: !3, line: 2, type: !14, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, isOptimized: true, unit: !2, retainedNodes: !4)
+## !14 = !DISubroutineType(types: !15)
+## !15 = !{null}
+## !16 = !DILocation(line: 2, column: 44, scope: !13)
+## !17 = !{!18, !18, i64 0}
+## !18 = !{!"int", !19, i64 0}
+## !19 = !{!"omnipotent char", !20, i64 0}
+## !20 = !{!"Simple C++ TBAA"}
+## !21 = !DILocation(line: 2, column: 48, scope: !13)
+## !22 = distinct !DISubprogram(name: "bar", linkageName: "_Z3barv", scope: !3, file: !3, line: 3, type: !14, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, isOptimized: true, unit: !2, retainedNodes: !4)
+## !23 = !DILocation(line: 3, column: 44, scope: !22)
+## !24 = !DILocation(line: 3, column: 48, scope: !22)
+## !25 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !3, file: !3, line: 4, type: !14, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, isOptimized: true, unit: !2, retainedNodes: !4)
+## !26 = !DILocation(line: 5, column: 3, scope: !25)
+## !27 = !DILocation(line: 6, column: 3, scope: !25)
+## !28 = !DILocation(line: 7, column: 1, scope: !25)
+## !29 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 8, type: !30, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, isOptimized: true, unit: !2, retainedNodes: !4)
+## !30 = !DISubroutineType(types: !31)
+## !31 = !{!7}
+## !32 = !DILocation(line: 8, column: 50, scope: !29)
+## !33 = !DILocation(line: 8, column: 57, scope: !29)
+
+ .section __TEXT,__text,regular,pure_instructions
+ .globl _foo ## -- Begin function foo
+_foo: ## @foo
+Lfunc_begin0:
+ .cfi_startproc
+## %bb.0:
+ retq
+Ltmp0:
+Lfunc_end0:
+ .cfi_endproc
+ ## -- End function
+ .globl _main ## -- Begin function main
+_main: ## @main
+Lfunc_begin1:
+ .cfi_startproc
+## %bb.0:
+ pushq %rax
+ .cfi_def_cfa_offset 16
+Ltmp1:
+ callq _foo
+ xorl %eax, %eax
+ popq %rcx
+ retq
+Ltmp2:
+Lfunc_end1:
+ .cfi_endproc
+ ## -- End function
+ .section __DWARF,__debug_str_offs,regular,debug
+Lsection_str_off:
+ .long 36
+ .short 5
+ .short 0
+Lstr_offsets_base0:
+ .section __DWARF,__debug_str,regular,debug
+Linfo_string:
+ .asciz "clang version 7.0.0 " ## string offset=0
+ .asciz "/Users/vsk/src/llvm.org-tailcall/tail2.cc" ## string offset=21
+ .asciz "/Users/vsk/src/builds/llvm-project-tailcall-RA" ## string offset=63
+ .asciz "sink" ## string offset=110
+ .asciz "int" ## string offset=115
+ .asciz "foo" ## string offset=119
+ .asciz "_Z3foov" ## string offset=123
+ .asciz "main" ## string offset=131
+ .section __DWARF,__debug_str_offs,regular,debug
+ .long 0
+ .long 21
+ .long 63
+ .long 110
+ .long 115
+ .long 119
+ .long 123
+ .long 131
+ .section __DWARF,__debug_abbrev,regular,debug
+Lsection_abbrev:
+ .byte 1 ## Abbreviation Code
+ .byte 17 ## DW_TAG_compile_unit
+ .byte 1 ## DW_CHILDREN_yes
+ .byte 37 ## DW_AT_producer
+ .byte 37 ## DW_FORM_strx1
+ .byte 19 ## DW_AT_language
+ .byte 5 ## DW_FORM_data2
+ .byte 3 ## DW_AT_name
+ .byte 37 ## DW_FORM_strx1
+ .byte 114 ## DW_AT_str_offsets_base
+ .byte 23 ## DW_FORM_sec_offset
+ .byte 16 ## DW_AT_stmt_list
+ .byte 23 ## DW_FORM_sec_offset
+ .byte 27 ## DW_AT_comp_dir
+ .byte 37 ## DW_FORM_strx1
+ .ascii "\341\177" ## DW_AT_APPLE_optimized
+ .byte 25 ## DW_FORM_flag_present
+ .byte 17 ## DW_AT_low_pc
+ .byte 1 ## DW_FORM_addr
+ .byte 18 ## DW_AT_high_pc
+ .byte 6 ## DW_FORM_data4
+ .byte 0 ## EOM(1)
+ .byte 0 ## EOM(2)
+ .byte 2 ## Abbreviation Code
+ .byte 52 ## DW_TAG_variable
+ .byte 0 ## DW_CHILDREN_no
+ .byte 3 ## DW_AT_name
+ .byte 37 ## DW_FORM_strx1
+ .byte 73 ## DW_AT_type
+ .byte 19 ## DW_FORM_ref4
+ .byte 63 ## DW_AT_external
+ .byte 25 ## DW_FORM_flag_present
+ .byte 58 ## DW_AT_decl_file
+ .byte 11 ## DW_FORM_data1
+ .byte 59 ## DW_AT_decl_line
+ .byte 11 ## DW_FORM_data1
+ .byte 0 ## EOM(1)
+ .byte 0 ## EOM(2)
+ .byte 3 ## Abbreviation Code
+ .byte 53 ## DW_TAG_volatile_type
+ .byte 0 ## DW_CHILDREN_no
+ .byte 73 ## DW_AT_type
+ .byte 19 ## DW_FORM_ref4
+ .byte 0 ## EOM(1)
+ .byte 0 ## EOM(2)
+ .byte 4 ## Abbreviation Code
+ .byte 36 ## DW_TAG_base_type
+ .byte 0 ## DW_CHILDREN_no
+ .byte 3 ## DW_AT_name
+ .byte 37 ## DW_FORM_strx1
+ .byte 62 ## DW_AT_encoding
+ .byte 11 ## DW_FORM_data1
+ .byte 11 ## DW_AT_byte_size
+ .byte 11 ## DW_FORM_data1
+ .byte 0 ## EOM(1)
+ .byte 0 ## EOM(2)
+ .byte 5 ## Abbreviation Code
+ .byte 46 ## DW_TAG_subprogram
+ .byte 0 ## DW_CHILDREN_no
+ .byte 17 ## DW_AT_low_pc
+ .byte 1 ## DW_FORM_addr
+ .byte 18 ## DW_AT_high_pc
+ .byte 6 ## DW_FORM_data4
+ .ascii "\347\177" ## DW_AT_APPLE_omit_frame_ptr
+ .byte 25 ## DW_FORM_flag_present
+ .byte 64 ## DW_AT_frame_base
+ .byte 24 ## DW_FORM_exprloc
+## .byte 122 ## DW_AT_call_all_calls
+## .byte 25 ## DW_FORM_flag_present
+ .byte 110 ## DW_AT_linkage_name
+ .byte 37 ## DW_FORM_strx1
+ .byte 3 ## DW_AT_name
+ .byte 37 ## DW_FORM_strx1
+ .byte 58 ## DW_AT_decl_file
+ .byte 11 ## DW_FORM_data1
+ .byte 59 ## DW_AT_decl_line
+ .byte 11 ## DW_FORM_data1
+ .byte 63 ## DW_AT_external
+ .byte 25 ## DW_FORM_flag_present
+ .ascii "\341\177" ## DW_AT_APPLE_optimized
+ .byte 25 ## DW_FORM_flag_present
+ .byte 0 ## EOM(1)
+ .byte 0 ## EOM(2)
+ .byte 6 ## Abbreviation Code
+ .byte 46 ## DW_TAG_subprogram
+ .byte 1 ## DW_CHILDREN_yes
+ .byte 17 ## DW_AT_low_pc
+ .byte 1 ## DW_FORM_addr
+ .byte 18 ## DW_AT_high_pc
+ .byte 6 ## DW_FORM_data4
+ .ascii "\347\177" ## DW_AT_APPLE_omit_frame_ptr
+ .byte 25 ## DW_FORM_flag_present
+ .byte 64 ## DW_AT_frame_base
+ .byte 24 ## DW_FORM_exprloc
+## .byte 122 ## DW_AT_call_all_calls
+## .byte 25 ## DW_FORM_flag_present
+ .byte 3 ## DW_AT_name
+ .byte 37 ## DW_FORM_strx1
+ .byte 58 ## DW_AT_decl_file
+ .byte 11 ## DW_FORM_data1
+ .byte 59 ## DW_AT_decl_line
+ .byte 11 ## DW_FORM_data1
+ .byte 73 ## DW_AT_type
+ .byte 19 ## DW_FORM_ref4
+ .byte 63 ## DW_AT_external
+ .byte 25 ## DW_FORM_flag_present
+ .ascii "\341\177" ## DW_AT_APPLE_optimized
+ .byte 25 ## DW_FORM_flag_present
+ .byte 0 ## EOM(1)
+ .byte 0 ## EOM(2)
+ .byte 7 ## Abbreviation Code
+ .byte 72 ## DW_TAG_call_site
+ .byte 0 ## DW_CHILDREN_no
+ .byte 127 ## DW_AT_call_origin
+ .byte 19 ## DW_FORM_ref4
+ .byte 0 ## EOM(1)
+ .byte 0 ## EOM(2)
+ .byte 0 ## EOM(3)
+ .section __DWARF,__debug_info,regular,debug
+Lsection_info:
+Lcu_begin0:
+ .long 99 ## Length of Unit
+ .short 5 ## DWARF version number
+ .byte 1 ## DWARF Unit Type
+ .byte 8 ## Address Size (in bytes)
+.set Lset0, Lsection_abbrev-Lsection_abbrev ## Offset Into Abbrev. Section
+ .long Lset0
+ .byte 1 ## Abbrev [1] 0xc:0x5b DW_TAG_compile_unit
+ .byte 0 ## DW_AT_producer
+ .short 4 ## DW_AT_language
+ .byte 1 ## DW_AT_name
+.set Lset1, Lstr_offsets_base0-Lsection_str_off ## DW_AT_str_offsets_base
+ .long Lset1
+.set Lset2, Lline_table_start0-Lsection_line ## DW_AT_stmt_list
+ .long Lset2
+ .byte 2 ## DW_AT_comp_dir
+ ## DW_AT_APPLE_optimized
+ .quad Lfunc_begin0 ## DW_AT_low_pc
+.set Lset3, Lfunc_end1-Lfunc_begin0 ## DW_AT_high_pc
+ .long Lset3
+ .byte 2 ## Abbrev [2] 0x26:0x8 DW_TAG_variable
+ .byte 3 ## DW_AT_name
+ .long 46 ## DW_AT_type
+ ## DW_AT_external
+ .byte 1 ## DW_AT_decl_file
+ .byte 1 ## DW_AT_decl_line
+ .byte 3 ## Abbrev [3] 0x2e:0x5 DW_TAG_volatile_type
+ .long 51 ## DW_AT_type
+ .byte 4 ## Abbrev [4] 0x33:0x4 DW_TAG_base_type
+ .byte 4 ## DW_AT_name
+ .byte 5 ## DW_AT_encoding
+ .byte 4 ## DW_AT_byte_size
+ .byte 5 ## Abbrev [5] 0x37:0x13 DW_TAG_subprogram
+ .quad Lfunc_begin0 ## DW_AT_low_pc
+.set Lset4, Lfunc_end0-Lfunc_begin0 ## DW_AT_high_pc
+ .long Lset4
+ ## DW_AT_APPLE_omit_frame_ptr
+ .byte 1 ## DW_AT_frame_base
+ .byte 87
+ ## DW_AT_call_all_calls
+ .byte 6 ## DW_AT_linkage_name
+ .byte 5 ## DW_AT_name
+ .byte 1 ## DW_AT_decl_file
+ .byte 4 ## DW_AT_decl_line
+ ## DW_AT_external
+ ## DW_AT_APPLE_optimized
+ .byte 6 ## Abbrev [6] 0x4a:0x1c DW_TAG_subprogram
+ .quad Lfunc_begin1 ## DW_AT_low_pc
+.set Lset5, Lfunc_end1-Lfunc_begin1 ## DW_AT_high_pc
+ .long Lset5
+ ## DW_AT_APPLE_omit_frame_ptr
+ .byte 1 ## DW_AT_frame_base
+ .byte 87
+ ## DW_AT_call_all_calls
+ .byte 7 ## DW_AT_name
+ .byte 1 ## DW_AT_decl_file
+ .byte 8 ## DW_AT_decl_line
+ .long 51 ## DW_AT_type
+ ## DW_AT_external
+ ## DW_AT_APPLE_optimized
+ .byte 7 ## Abbrev [7] 0x60:0x5 DW_TAG_call_site
+ .long 55 ## DW_AT_call_origin
+ .byte 0 ## End Of Children Mark
+ .byte 0 ## End Of Children Mark
+ .section __DWARF,__debug_macinfo,regular,debug
+Ldebug_macinfo:
+ .byte 0 ## End Of Macro List Mark
+ .section __DWARF,__debug_names,regular,debug
+Ldebug_names_begin:
+.set Lset6, Lnames_end0-Lnames_start0 ## Header: unit length
+ .long Lset6
+Lnames_start0:
+ .short 5 ## Header: version
+ .short 0 ## Header: padding
+ .long 1 ## Header: compilation unit count
+ .long 0 ## Header: local type unit count
+ .long 0 ## Header: foreign type unit count
+ .long 4 ## Header: bucket count
+ .long 4 ## Header: name count
+.set Lset7, Lnames_abbrev_end0-Lnames_abbrev_start0 ## Header: abbreviation table size
+ .long Lset7
+ .long 8 ## Header: augmentation string size
+ .ascii "LLVM0700" ## Header: augmentation string
+.set Lset8, Lcu_begin0-Lsection_info ## Compilation unit 0
+ .long Lset8
+ .long 1 ## Bucket 0
+ .long 2 ## Bucket 1
+ .long 3 ## Bucket 2
+ .long 4 ## Bucket 3
+ .long 193495088 ## Hash in Bucket 0
+ .long 193491849 ## Hash in Bucket 1
+ .long 2090499946 ## Hash in Bucket 2
+ .long -1257882357 ## Hash in Bucket 3
+ .long 115 ## String in Bucket 0: int
+ .long 119 ## String in Bucket 1: foo
+ .long 131 ## String in Bucket 2: main
+ .long 123 ## String in Bucket 3: _Z3foov
+.set Lset9, Lnames3-Lnames_entries0 ## Offset in Bucket 0
+ .long Lset9
+.set Lset10, Lnames0-Lnames_entries0 ## Offset in Bucket 1
+ .long Lset10
+.set Lset11, Lnames1-Lnames_entries0 ## Offset in Bucket 2
+ .long Lset11
+.set Lset12, Lnames2-Lnames_entries0 ## Offset in Bucket 3
+ .long Lset12
+Lnames_abbrev_start0:
+ .byte 46 ## Abbrev code
+ .byte 46 ## DW_TAG_subprogram
+ .byte 3 ## DW_IDX_die_offset
+ .byte 19 ## DW_FORM_ref4
+ .byte 0 ## End of abbrev
+ .byte 0 ## End of abbrev
+ .byte 36 ## Abbrev code
+ .byte 36 ## DW_TAG_base_type
+ .byte 3 ## DW_IDX_die_offset
+ .byte 19 ## DW_FORM_ref4
+ .byte 0 ## End of abbrev
+ .byte 0 ## End of abbrev
+ .byte 0 ## End of abbrev list
+Lnames_abbrev_end0:
+Lnames_entries0:
+Lnames3:
+ .byte 36 ## Abbreviation code
+ .long 51 ## DW_IDX_die_offset
+ .long 0 ## End of list: int
+Lnames0:
+ .byte 46 ## Abbreviation code
+ .long 55 ## DW_IDX_die_offset
+ .long 0 ## End of list: foo
+Lnames1:
+ .byte 46 ## Abbreviation code
+ .long 74 ## DW_IDX_die_offset
+ .long 0 ## End of list: main
+Lnames2:
+ .byte 46 ## Abbreviation code
+ .long 55 ## DW_IDX_die_offset
+ .long 0 ## End of list: _Z3foov
+Lnames_end0:
+
+.subsections_via_symbols
+ .section __DWARF,__debug_line,regular,debug
+Lsection_line:
+Lline_table_start0:
diff --git a/llvm/tools/llvm-dwarfdump/Statistics.cpp b/llvm/tools/llvm-dwarfdump/Statistics.cpp
index 45e96d5ca93..4119dbf1b3c 100644
--- a/llvm/tools/llvm-dwarfdump/Statistics.cpp
+++ b/llvm/tools/llvm-dwarfdump/Statistics.cpp
@@ -32,6 +32,8 @@ struct GlobalStats {
/// Total number of PC range bytes in each variable's enclosing scope,
/// starting from the first definition of the variable.
unsigned ScopeBytesFromFirstDefinition = 0;
+ /// Total number of call site entries (DW_TAG_call_site).
+ unsigned CallSiteEntries = 0;
};
/// Extract the low pc from a Die.
@@ -57,6 +59,11 @@ static void collectStatsForDie(DWARFDie Die, std::string FnPrefix,
uint64_t BytesCovered = 0;
uint64_t OffsetToFirstDefinition = 0;
+ if (Die.getTag() == dwarf::DW_TAG_call_site) {
+ GlobalStats.CallSiteEntries++;
+ return;
+ }
+
if (Die.getTag() != dwarf::DW_TAG_formal_parameter &&
Die.getTag() != dwarf::DW_TAG_variable &&
Die.getTag() != dwarf::DW_TAG_member) {
@@ -260,6 +267,7 @@ bool collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
printDatum(OS, "unique source variables", VarUnique);
printDatum(OS, "source variables", VarTotal);
printDatum(OS, "variables with location", VarWithLoc);
+ printDatum(OS, "call site entries", GlobalStats.CallSiteEntries);
printDatum(OS, "scope bytes total",
GlobalStats.ScopeBytesFromFirstDefinition);
printDatum(OS, "scope bytes covered", GlobalStats.ScopeBytesCovered);
OpenPOWER on IntegriCloud