[clang][DebugInfo] Add virtuality call-site target information in DWARF.#182510
Conversation
Given the test case:
struct CBase {
virtual void foo();
};
void bar(CBase *Base) {
Base->foo();
}
and using '-emit-call-site-info' with llc, the following DWARF
is produced for the indirect call 'Base->foo()':
1$: DW_TAG_structure_type "CBase"
...
2$: DW_TAG_subprogram "foo"
...
3$: DW_TAG_subprogram "bar"
...
4$: DW_TAG_call_site
...
We add DW_AT_LLVM_virtual_call_origin to existing call-site
information, linking indirect calls to the function-declaration
they correspond to.
4$: DW_TAG_call_site
...
DW_AT_LLVM_virtual_call_origin (2$ "_ZN5CBase3fooEv")
The new attribute DW_AT_LLVM_virtual_call_origin helps to
address the ambiguity to any consumer due to the usage of
DW_AT_call_origin.
The functionality is available to all supported debuggers.
|
@llvm/pr-subscribers-clang-codegen @llvm/pr-subscribers-backend-mips Author: Carlos Alberto Enciso (CarlosAlbertoEnciso) ChangesGiven the test case: and using '-emit-call-site-info' with 'llc', currently the following DWARF is produced for the indirect call 'Base->foo()': Initial context from the SCE debugger point of view: > We can detect when a function has been affected by Identical Code Folding (ICF) from DWARF call-site information. For example, This patch (available for all debuggers) helps in the identification of the intended target of a virtual call in the SCE debugger. By adding the
This is the added The extra call site information is available by default for all debuggers and it is generated only for DWARF 5 or greater. Patch is 32.70 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/182510.diff 25 Files Affected:
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 1d950ffed8a0b..b57802ebfced8 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -6438,6 +6438,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
DI->EmitFuncDeclForCallSite(
CI, DI->getFunctionType(CalleeDecl, ResTy, Args), CalleeGlobalDecl);
}
+ // Generate call site target information.
+ DI->addCallTargetIfVirtual(CalleeDecl, CI);
}
return Ret;
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 2b123631c526c..401d8bc16d290 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -2332,6 +2332,12 @@ CGDebugInfo::GetMethodLinkageName(const CXXMethodDecl *Method) const {
return CGM.getMangledName(Method);
}
+bool CGDebugInfo::shouldGenerateVirtualCallSite() const {
+ // Check general conditions for call site generation.
+ return ((getCallSiteRelatedAttrs() != llvm::DINode::FlagZero) &&
+ (CGM.getCodeGenOpts().DwarfVersion >= 5));
+}
+
llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction(
const CXXMethodDecl *Method, llvm::DIFile *Unit, llvm::DIType *RecordTy) {
assert(Method);
@@ -4985,6 +4991,23 @@ void CGDebugInfo::EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc,
Fn->setSubprogram(SP);
}
+void CGDebugInfo::addCallTargetIfVirtual(const FunctionDecl *FD,
+ llvm::CallBase *CI) {
+ if (!shouldGenerateVirtualCallSite())
+ return;
+
+ if (!FD)
+ return;
+
+ assert(CI && "Invalid Call Instruction.");
+ if (!CI->isIndirectCall())
+ return;
+
+ // Always get the method declaration.
+ if (llvm::DISubprogram *MD = getFunctionDeclaration(FD))
+ CI->setMetadata(llvm::LLVMContext::MD_call_target, MD);
+}
+
void CGDebugInfo::EmitFuncDeclForCallSite(llvm::CallBase *CallOrInvoke,
QualType CalleeType,
GlobalDecl CalleeGlobalDecl) {
diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h
index b36a597a80ede..8e1eda2d93ac0 100644
--- a/clang/lib/CodeGen/CGDebugInfo.h
+++ b/clang/lib/CodeGen/CGDebugInfo.h
@@ -683,6 +683,9 @@ class CGDebugInfo {
/// that it is supported and enabled.
llvm::DINode::DIFlags getCallSiteRelatedAttrs() const;
+ /// Add call target information.
+ void addCallTargetIfVirtual(const FunctionDecl *FD, llvm::CallBase *CI);
+
private:
/// Amend \p I's DebugLoc with \p Group (its source atom group) and \p
/// Rank (lower nonzero rank is higher precedence). Does nothing if \p I
@@ -907,6 +910,9 @@ class CGDebugInfo {
/// 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;
+
+ /// Returns true if we should generate call target information.
+ bool shouldGenerateVirtualCallSite() const;
};
/// A scoped helper to set the current debug location to the specified
diff --git a/clang/test/DebugInfo/CXX/callsite-base.cpp b/clang/test/DebugInfo/CXX/callsite-base.cpp
new file mode 100644
index 0000000000000..399e62ede0dec
--- /dev/null
+++ b/clang/test/DebugInfo/CXX/callsite-base.cpp
@@ -0,0 +1,70 @@
+// RUN: %clang_cc1 -triple=x86_64-linux -disable-llvm-passes -emit-llvm \
+// RUN: -debug-info-kind=standalone -dwarf-version=5 -O1 %s \
+// RUN: -o - | FileCheck %s -check-prefix CHECK-BASE
+
+// RUN: %clang_cc1 -triple=x86_64-linux -disable-llvm-passes -emit-llvm \
+// RUN: -debug-info-kind=standalone -dwarf-version=4 -O1 %s \
+// RUN: -o - | FileCheck %s -check-prefix CHECK-BASE-DW4
+
+// Simple class with only virtual methods: inlined and not-inlined
+//
+// The following three scenarios are considered:
+// - out-of-line defined virtual member function (f1)
+// - declared-but-not-defined virtual member function (f2)
+// - inline defined virtual member function (f3)
+//
+// 1) We check for a generated 'call_target' for: 'f1', 'f2' and 'f3'.
+// 2) Check that the 'CBase' type is defined.
+
+struct CBase {
+ virtual void f1();
+ virtual void f2();
+ virtual void f3() {}
+};
+void CBase::f1() {}
+
+void bar(CBase *Base) {
+ Base->f1();
+ Base->f2();
+ Base->f3();
+
+ // Because this will instantiate the ctor, the CBase type should be defined.
+ CBase B;
+ B.f1();
+}
+
+// CHECK-BASE: %struct.CBase = type { ptr }
+
+// CHECK-BASE: define {{.*}} @_Z3barP5CBase{{.*}} {
+// CHECK-BASE: alloca %struct.CBase
+// CHECK-BASE: call void %1{{.*}} !dbg {{![0-9]+}}, !call_target [[BASE_F1_DCL:![0-9]+]]
+// CHECK-BASE: call void %3{{.*}} !dbg {{![0-9]+}}, !call_target [[BASE_F2_DCL:![0-9]+]]
+// CHECK-BASE: call void %5{{.*}} !dbg {{![0-9]+}}, !call_target [[BASE_F3_DCL:![0-9]+]]
+// CHECK-BASE: call void @_ZN5CBaseC1Ev{{.*}} !dbg {{![0-9]+}}
+// CHECK-BASE: call void @_ZN5CBase2f1Ev{{.*}} !dbg {{![0-9]+}}
+// CHECK-BASE: }
+
+// CHECK-BASE: [[BASE_F1_DCL]] = {{.*}}!DISubprogram(name: "f1", linkageName: "_ZN5CBase2f1Ev", {{.*}}containingType
+// CHECK-BASE: [[BASE_F2_DCL]] = {{.*}}!DISubprogram(name: "f2", linkageName: "_ZN5CBase2f2Ev", {{.*}}containingType
+// CHECK-BASE: [[BASE_F3_DCL]] = {{.*}}!DISubprogram(name: "f3", linkageName: "_ZN5CBase2f3Ev", {{.*}}containingType
+
+// CHECK-BASE: [[BASE_F1_DEF:![0-9]+]] = {{.*}}!DISubprogram(name: "f1", linkageName: "_ZN5CBase2f1Ev", {{.*}}DISPFlagDefinition
+// CHECK-BASE: [[BASE_F3_DEF:![0-9]+]] = {{.*}}!DISubprogram(name: "f3", linkageName: "_ZN5CBase2f3Ev", {{.*}}DISPFlagDefinition
+
+// CHECK-BASE-DW4: %struct.CBase = type { ptr }
+
+// CHECK-BASE-DW4: define {{.*}} @_Z3barP5CBase{{.*}} {
+// CHECK-BASE-DW4: alloca %struct.CBase
+// CHECK-BASE-DW4: call void %1{{.*}} !dbg {{![0-9]+}}
+// CHECK-BASE-DW4: call void %3{{.*}} !dbg {{![0-9]+}}
+// CHECK-BASE-DW4: call void %5{{.*}} !dbg {{![0-9]+}}
+// CHECK-BASE-DW4: call void @_ZN5CBaseC1Ev{{.*}} !dbg {{![0-9]+}}
+// CHECK-BASE-DW4: call void @_ZN5CBase2f1Ev{{.*}} !dbg {{![0-9]+}}
+// CHECK-BASE-DW4: }
+
+// CHECK-BASE-DW4: {{.*}}!DISubprogram(name: "f1", linkageName: "_ZN5CBase2f1Ev", {{.*}}containingType
+// CHECK-BASE-DW4: {{.*}}!DISubprogram(name: "f2", linkageName: "_ZN5CBase2f2Ev", {{.*}}containingType
+// CHECK-BASE-DW4: {{.*}}!DISubprogram(name: "f3", linkageName: "_ZN5CBase2f3Ev", {{.*}}containingType
+
+// CHECK-BASE-DW4: {{.*}}!DISubprogram(name: "f1", linkageName: "_ZN5CBase2f1Ev", {{.*}}DISPFlagDefinition
+// CHECK-BASE-DW4: {{.*}}!DISubprogram(name: "f3", linkageName: "_ZN5CBase2f3Ev", {{.*}}DISPFlagDefinition
diff --git a/clang/test/DebugInfo/CXX/callsite-derived.cpp b/clang/test/DebugInfo/CXX/callsite-derived.cpp
new file mode 100644
index 0000000000000..3338290bdd829
--- /dev/null
+++ b/clang/test/DebugInfo/CXX/callsite-derived.cpp
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 -triple=x86_64-linux -disable-llvm-passes -emit-llvm \
+// RUN: -debug-info-kind=constructor -dwarf-version=5 -O1 %s \
+// RUN: -o - | FileCheck %s -check-prefix CHECK-DERIVED
+
+// Simple base and derived class with virtual and static methods:
+// We check for:
+// - a generated 'call_target' for 'f1'.
+// - not generated 'call_target' for 'f3'.
+
+struct CBase {
+ virtual void f1() {}
+ static void f3();
+};
+
+void CBase::f3() {
+}
+
+void foo(CBase *Base) {
+ CBase::f3();
+}
+
+struct CDerived : public CBase {
+ void f1() {}
+};
+void foo(CDerived *Derived);
+
+int main() {
+ CDerived D;
+ foo(&D);
+
+ return 0;
+}
+
+void foo(CDerived *Derived) {
+ Derived->f1();
+}
+
+// CHECK-DERIVED: define {{.*}} @_Z3fooP5CBase{{.*}} {
+// CHECK-DERIVED: call void @_ZN5CBase2f3Ev{{.*}} !dbg {{![0-9]+}}
+// CHECK-DERIVED: }
+
+// CHECK-DERIVED: define {{.*}} @main{{.*}} {
+// CHECK-DERIVED: call void @_ZN8CDerivedC1Ev{{.*}} !dbg {{![0-9]+}}
+// CHECK-DERIVED: call void @_Z3fooP8CDerived{{.*}} !dbg {{![0-9]+}}
+// CHECK-DERIVED: }
+
+// CHECK-DERIVED: define {{.*}} @_ZN8CDerivedC1Ev{{.*}} {
+// CHECK-DERIVED: call void @_ZN8CDerivedC2Ev{{.*}} !dbg {{![0-9]+}}
+// CHECK-DERIVED: }
+
+// CHECK-DERIVED: define {{.*}} @_Z3fooP8CDerived{{.*}} {
+// CHECK-DERIVED: call void %1{{.*}} !dbg {{![0-9]+}}, !call_target [[DERIVED_F1_DCL:![0-9]+]]
+// CHECK-DERIVED: }
+
+// CHECK-DERIVED: [[BASE_F1_DCL:![0-9]+]] = {{.*}}!DISubprogram(name: "f1", linkageName: "_ZN5CBase2f1Ev", {{.*}}containingType
+// CHECK-DERIVED: [[DERIVED_F1_DCL]] = {{.*}}!DISubprogram(name: "f1", linkageName: "_ZN8CDerived2f1Ev", {{.*}}containingType
+// CHECK-DERIVED: [[DERIVED_F1_DEF:![0-9]+]] = {{.*}}!DISubprogram(name: "f1", linkageName: "_ZN8CDerived2f1Ev", {{.*}}DISPFlagDefinition
+// CHECK-DERIVED: [[BASE_F1_DEF:![0-9]+]] = {{.*}}!DISubprogram(name: "f1", linkageName: "_ZN5CBase2f1Ev", {{.*}}DISPFlagDefinition
diff --git a/clang/test/DebugInfo/CXX/callsite-edges.cpp b/clang/test/DebugInfo/CXX/callsite-edges.cpp
new file mode 100644
index 0000000000000..812cfc1fb4cf2
--- /dev/null
+++ b/clang/test/DebugInfo/CXX/callsite-edges.cpp
@@ -0,0 +1,93 @@
+// RUN: %clang_cc1 -triple=x86_64-linux -disable-llvm-passes -emit-llvm \
+// RUN: -debug-info-kind=constructor -dwarf-version=5 -O1 %s \
+// RUN: -o - | FileCheck %s -check-prefix CHECK-EDGES
+
+// The following are identified edge cases involving the method being called:
+// 1) Method is declared but not defined in current CU.
+// 2) Pure virtual method but not defined in current CU.
+// 3) Virtual method defined in a deeply nested structure hierarchy.
+
+//---------------------------------------------------------------------
+// 1) Method is declared but not defined in current CU - Pass.
+// Generate 'call_target' metadata for 'f1' and 'f2'.
+//---------------------------------------------------------------------
+struct CEmpty {
+ virtual void f1();
+ virtual void f2();
+};
+
+void CEmpty::f2() {
+}
+
+void edge_a(CEmpty *Empty) {
+ Empty->f1();
+ Empty->f2();
+}
+
+//---------------------------------------------------------------------
+// 2) Pure virtual method but not defined in current CU - Pass.
+// Generate 'call_target' metadata for 'f1' and 'f2'.
+//---------------------------------------------------------------------
+struct CBase {
+ virtual void f1() = 0;
+ virtual void f2();
+};
+
+void CBase::f2() {
+}
+
+void edge_b(CBase *Base) {
+ Base->f1();
+ Base->f2();
+}
+
+//---------------------------------------------------------------------
+// 3) Virtual method defined in a deeply nested structure hierarchy - Pass.
+// Generate 'call_target' metadata for 'd0', 'd1', 'd2' and 'd3'.
+//---------------------------------------------------------------------
+struct CD0 {
+ struct CD1 {
+ virtual void d1();
+ };
+
+ CD1 D1;
+ virtual void d0();
+};
+
+void CD0::d0() {}
+void CD0::CD1::d1() {}
+
+void edge_c(CD0 *D0) {
+ D0->d0();
+
+ CD0::CD1 *D1 = &D0->D1;
+ D1->d1();
+}
+
+// CHECK-EDGES: define {{.*}} @_Z6edge_aP6CEmpty{{.*}} {
+// CHECK-EDGES: call void %1{{.*}} !dbg {{![0-9]+}}, !call_target [[CEMPTY_F1_DCL:![0-9]+]]
+// CHECK-EDGES: call void %3{{.*}} !dbg {{![0-9]+}}, !call_target [[CEMPTY_F2_DCL:![0-9]+]]
+// CHECK-EDGES: }
+
+// CHECK-EDGES: define {{.*}} @_Z6edge_bP5CBase{{.*}} {
+// CHECK-EDGES: call void %1{{.*}} !dbg {{![0-9]+}}, !call_target [[CBASE_F1_DCL:![0-9]+]]
+// CHECK-EDGES: call void %3{{.*}} !dbg {{![0-9]+}}, !call_target [[CBASE_F2_DCL:![0-9]+]]
+// CHECK-EDGES: }
+
+// CHECK-EDGES: define {{.*}} @_Z6edge_cP3CD0{{.*}} {
+// CHECK-EDGES: call void %1{{.*}} !dbg {{![0-9]+}}, !call_target [[CD0_D0_DCL:![0-9]+]]
+// CHECK-EDGES: call void %4{{.*}} !dbg {{![0-9]+}}, !call_target [[CD0_D1_DCL:![0-9]+]]
+// CHECK-EDGES: }
+
+// CHECK-EDGES: [[CD0_D1_DCL]] = {{.*}}!DISubprogram(name: "d1", linkageName: "_ZN3CD03CD12d1Ev", {{.*}}containingType
+// CHECK-EDGES: [[CD0_D0_DCL]] = {{.*}}!DISubprogram(name: "d0", linkageName: "_ZN3CD02d0Ev", {{.*}}containingType
+
+// CHECK-EDGES: [[CBASE_F1_DCL]] = {{.*}}!DISubprogram(name: "f1", linkageName: "_ZN5CBase2f1Ev", {{.*}}containingType
+// CHECK-EDGES: [[CBASE_F2_DCL]] = {{.*}}!DISubprogram(name: "f2", linkageName: "_ZN5CBase2f2Ev", {{.*}}containingType
+// CHECK-EDGES: [[CEMPTY_F2_DEF:![0-9]+]] = {{.*}}!DISubprogram(name: "f2", linkageName: "_ZN6CEmpty2f2Ev", {{.*}}DISPFlagDefinition
+// CHECK-EDGES: [[CEMPTY_F2_DCL]] = {{.*}}!DISubprogram(name: "f2", linkageName: "_ZN6CEmpty2f2Ev", {{.*}}containingType
+// CHECK-EDGES: [[CEMPTY_F1_DCL]] = {{.*}}!DISubprogram(name: "f1", linkageName: "_ZN6CEmpty2f1Ev", {{.*}}containingType
+// CHECK-EDGES: [[CBASE_F2_DEF:![0-9]+]] = {{.*}}!DISubprogram(name: "f2", linkageName: "_ZN5CBase2f2Ev", {{.*}}DISPFlagDefinition
+
+// CHECK-EDGES: [[CD0_D0_DEF:![0-9]+]] = {{.*}}!DISubprogram(name: "d0", linkageName: "_ZN3CD02d0Ev", {{.*}}DISPFlagDefinition
+// CHECK-EDGES: [[CD0_D1_DEF:![0-9]+]] = {{.*}}!DISubprogram(name: "d1", linkageName: "_ZN3CD03CD12d1Ev", {{.*}}DISPFlagDefinition
diff --git a/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/callsite-crash.cpp b/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/callsite-crash.cpp
new file mode 100644
index 0000000000000..745ac967528da
--- /dev/null
+++ b/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/callsite-crash.cpp
@@ -0,0 +1,20 @@
+// REQUIRES: aarch64-registered-target
+
+// RUN: %clang --target=aarch64-unknown-fuchsia -c -g -O1 -gdwarf-4 %s -o - | \
+// RUN: llvm-dwarfdump --debug-info - | FileCheck %s --check-prefix=CHECK
+
+struct Base {
+ virtual void foo();
+} *B;
+
+void bar() {
+ B->foo();
+}
+
+// CHECK: DW_TAG_compile_unit
+// CHECK: DW_TAG_subprogram
+// CHECK: DW_AT_GNU_all_call_sites (true)
+// CHECK: DW_AT_linkage_name ("_Z3barv")
+// CHECK: DW_TAG_GNU_call_site
+// CHECK: DW_AT_GNU_call_site_target_clobbered
+// CHECK: DW_AT_GNU_tail_call (true)
diff --git a/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/callsite-dwarf.cpp b/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/callsite-dwarf.cpp
new file mode 100644
index 0000000000000..9fe6df6a0f61d
--- /dev/null
+++ b/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/callsite-dwarf.cpp
@@ -0,0 +1,99 @@
+// REQUIRES: x86-registered-target
+
+// RUN: %clang --target=x86_64-linux -c -g -O1 -gdwarf-5 %s -o - | \
+// RUN: llvm-dwarfdump --debug-info - | FileCheck %s --check-prefix=CHECK
+
+// RUN: %clang --target=x86_64-linux -c -g -O1 -gdwarf-4 %s -o - | \
+// RUN: llvm-dwarfdump --debug-info - | FileCheck %s --check-prefix=CHECK-DW4
+
+// Simple base and derived class with virtual:
+// We check for a generated 'DW_AT_LLVM_virtual_call_origin' for 'foo', that
+// corresponds to the 'call_target' metadata added to the indirect call
+// instruction, when generating DWARF-5 or greater.
+
+// Note: We should add a test case inside LLDB that make use of the
+// virtuality call-site target information in DWARF.
+
+struct CBaseOne {
+ virtual void foo(int &);
+};
+
+struct CDerivedOne : CBaseOne {
+ void foo(int &);
+};
+
+void CDerivedOne::foo(int &) {}
+
+struct CBaseTwo {
+ CDerivedOne *DerivedOne;
+};
+
+struct CDerivedTwo : CBaseTwo {
+ void bar(int &);
+};
+
+void CDerivedTwo::bar(int &j) { DerivedOne->foo(j); }
+
+// The IR generated looks like:
+//
+// define dso_local void @_ZN11CDerivedTwo3barERi(...) !dbg !40 {
+// entry:
+// ..
+// %vtable = load ptr, ptr %0, align 8
+// %vfn = getelementptr inbounds ptr, ptr %vtable, i64 0
+// %2 = load ptr, ptr %vfn, align 8
+// call void %2(...), !dbg !65, !call_target !25
+// ret void
+// }
+//
+// !25 = !DISubprogram(name: "foo", linkageName: "_ZN11CDerivedOne3fooERi", ...)
+// !40 = !DISubprogram(name: "bar", linkageName: "_ZN11CDerivedTwo3barERi", ...)
+// !65 = !DILocation(line: 25, column: 15, scope: !40)
+
+// CHECK: DW_TAG_compile_unit
+// CHECK: DW_TAG_structure_type
+// CHECK: DW_AT_name ("CDerivedOne")
+// CHECK: [[FOO_DCL:0x[a-f0-9]+]]: DW_TAG_subprogram
+// CHECK: DW_AT_name ("foo")
+// CHECK: DW_TAG_structure_type
+// CHECK: DW_AT_name ("CBaseOne")
+// CHECK: [[FOO_DEF:0x[a-f0-9]+]]: DW_TAG_subprogram
+// CHECK: DW_AT_call_all_calls (true)
+// CHECK: DW_AT_specification ([[FOO_DCL]] "{{.*}}foo{{.*}}")
+// CHECK: DW_TAG_structure_type
+// CHECK: DW_AT_name ("CDerivedTwo")
+// CHECK: DW_TAG_subprogram
+// CHECK: DW_AT_name ("bar")
+// CHECK: DW_TAG_structure_type
+// CHECK: DW_AT_name ("CBaseTwo")
+// CHECK: DW_TAG_subprogram
+// CHECK: DW_AT_call_all_calls (true)
+// CHECK: DW_AT_specification (0x{{.*}} "{{.*}}bar{{.*}}")
+// CHECK: DW_TAG_call_site
+// CHECK: DW_AT_call_target_clobbered (DW_OP_reg0 RAX)
+// CHECK: DW_AT_call_tail_call (true)
+// CHECK: DW_AT_call_pc (0x{{.*}})
+// CHECK: DW_AT_LLVM_virtual_call_origin ([[FOO_DCL]] "{{.*}}foo{{.*}}")
+
+// CHECK-DW4: DW_TAG_compile_unit
+// CHECK-DW4: DW_TAG_structure_type
+// CHECK-DW4: DW_AT_name ("CDerivedOne")
+// CHECK-DW4: [[FOO_DCL:0x[a-f0-9]+]]: DW_TAG_subprogram
+// CHECK-DW4: DW_AT_name ("foo")
+// CHECK-DW4: DW_TAG_structure_type
+// CHECK-DW4: DW_AT_name ("CBaseOne")
+// CHECK-DW4: [[FOO_DEF:0x[a-f0-9]+]]: DW_TAG_subprogram
+// CHECK-DW4: DW_AT_GNU_all_call_sites (true)
+// CHECK-DW4: DW_AT_specification ([[FOO_DCL]] "{{.*}}foo{{.*}}")
+// CHECK-DW4: DW_TAG_structure_type
+// CHECK-DW4: DW_AT_name ("CDerivedTwo")
+// CHECK-DW4: DW_TAG_subprogram
+// CHECK-DW4: DW_AT_name ("bar")
+// CHECK-DW4: DW_TAG_structure_type
+// CHECK-DW4: DW_AT_name ("CBaseTwo")
+// CHECK-DW4: DW_TAG_subprogram
+// CHECK-DW4: DW_AT_GNU_all_call_sites (true)
+// CHECK-DW4: DW_AT_specification (0x{{.*}} "{{.*}}bar{{.*}}")
+// CHECK-DW4: DW_TAG_GNU_call_site
+// CHECK-DW4: DW_AT_GNU_call_site_target_clobbered (DW_OP_reg0 RAX)
+// CHECK-DW4: DW_AT_GNU_tail_call (true)
diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.def b/llvm/include/llvm/BinaryFormat/Dwarf.def
index 75f1061c471c6..50b83884c851a 100644
--- a/llvm/include/llvm/BinaryFormat/Dwarf.def
+++ b/llvm/include/llvm/BinaryFormat/Dwarf.def
@@ -647,6 +647,7 @@ HANDLE_DW_AT(0x3e10, LLVM_address_space, 0, LLVM)
HANDLE_DW_AT(0x3e11, LLVM_lanes, 0, LLVM)
HANDLE_DW_AT(0x3e12, LLVM_lane_pc, 0, LLVM)
HANDLE_DW_AT(0x3e13, LLVM_vector_size, 0, LLVM)
+HANDLE_DW_AT(0x3e14, LLVM_virtual_call_origin, 0, LLVM)
// https://llvm.org/docs/AMDGPUUsage.html#address-space-identifier
HANDLE_DW_ASPACE(0x0, none)
diff --git a/llvm/include/llvm/CodeGen/MachineFunction.h b/llvm/include/llvm/CodeGen/MachineFunction.h
index edb8963ce42b6..26b6c457a45ba 100644
--- a/llvm/include/llvm/CodeGen/MachineFunction.h
+++ b/llvm/include/llvm/CodeGen/MachineFunction.h
@@ -526,11 +526,17 @@ class LLVM_ABI MachineFunction {
/// Callee type ids.
SmallVector<ConstantInt *, 4> CalleeTypeIds;
+ /// 'call_target' metadata for the DISubprogram. It is the declaration
+ /// or definition of the target function and might be indirect.
+ MDNode *CallTarget = nullptr;
+
CallSiteInfo() = default;
/// Extracts the numeric type id from the CallBase's callee_type Metadata,
/// and sets CalleeTypeIds. This is used as type id for the indirect call in
/// the call graph section.
+ /// Extracts the MDNode from the CallBase's call_target Metadata to be used
+ /// during the construction of the debug info call site entries.
LLVM_ABI CallSiteInfo(const CallBase &CB);
};
diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h
index 37002d3bc227f..39699cb19a4b7 100644
--- a/llvm/include/llvm/CodeGen/TargetLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetLowering.h
@@ -5936,6 +5936,10 @@ class LLVM_ABI TargetLowering : public TargetLoweringBase {
LoadSDNode *OriginalLoad,
SelectionDAG &DAG) const;
+protected:
+ void setTypeIdForCallsiteInfo(const CallBase *CB, MachineFunction &MF,
+ MachineFunction::CallSiteInfo &CSInfo) const;
+
private:
SDValue foldSetCCWithAnd(EVT VT, SDValue N0, SDValue N1, ISD::CondCode Cond,
const SDLoc &DL, DAGCombinerInfo &DCI) const;
diff --git a/llvm/include/llvm/IR/FixedMetadataKinds.def b/llvm/include/llvm/IR/FixedMetadataKinds.def
index 98129985714b2..0d79677d...
[truncated]
|
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
|
There are 2 main commits:
|
464dd00 to
c379caa
Compare
The virtuality calls-site target information is NOT generated
if DWARF version less than 5 is requested.
Fixes issues discovered after the initial patch landed:
- Add missing 'REQUIRES: x86-registered-target'
to fix buildbot failure:
https://lab.llvm.org/buildbot/#/builders/190/builds/36803
- Crash when building Fuchsia code on arm platforms with DWARF 4 and -O2
c379caa to
6bd515a
Compare
🐧 Linux x64 Test Results
Failed Tests(click on a test name to see its output) lldb-apilldb-api.functionalities/data-formatter/data-formatter-stl/generic/list/TestDataFormatterGenericList.pyIf these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the |
ilovepi
left a comment
There was a problem hiding this comment.
LGTM. Do check with other reviewers, but it looks to me like this should fix the crash and there's a test case from our codebase, so I'm reasonably sure it should be fine.
Thanks again :)
|
@dwblaikie, @felipepiovezan Do you have any additional feedback on the commit that fixes the failed test case and crash? Thanks |
|
@dwblaikie Thanks for the review and approval. |
Given the test case:
and using '-emit-call-site-info' with 'llc', currently the following DWARF is produced for the indirect call 'Base->foo()':
Initial context from the SCE debugger point of view:
This patch (available for all debuggers) helps in the identification of the intended target of a virtual call in the SCE debugger.
By adding the
DW_AT_LLVM_virtual_call_originfor indirect calls, a debugger can identify the intended target of a call. These are the specific actions taking by the SCE debugger:The debugger can detect functions that have been folding by comparing whether the
DW_AT_call_originmatches the call frame function. If it does not, the debugger can assume the "true" target and the actual target have been code folded and add a frame annotation to the call stack to indicate this. That, or there is a tail call fromfootobar, but the debugger can disambiguate these cases by looking at theDW_AT_call_originreferenced subroutine DIE which has a tombstoneDW_AT_low_pcin the ICF case.For virtual calls such as the given test case, the existence of the
DW_AT_LLVM_virtual_call_originattribute tells the debugger that this is an indirect jump, and theDW_AT_LLVM_virtual_call_originattribute, pointing to the base class method DIE, will tell which method is being called.The debugger can confirm from the method's DIE that it is a virtual function call by looking at the attributes (
DW_AT_virtuality, andDW_AT_vtable_elem_location) and can look at the parent DIE to work out the type.This is the added
DW_AT_LLVM_virtual_call_originto identify the target callCBase::foo.The extra call site information is available by default for all debuggers and it is generated only for DWARF 5 or greater.