https://github.com/CarlosAlbertoEnciso created 
https://github.com/llvm/llvm-project/pull/182510

Given the test case:
```
struct CBase {
  virtual void foo();
};

void bar(CBase *Base) {
  Base->foo();
}
```
and using '-emit-call-site-info' with 'llc', currently the following DWARF is 
produced for the indirect call 'Base->foo()':
```
0x10: DW_TAG_structure_type
        DW_AT_name      ("CBase")

0x20:   DW_TAG_subprogram
          DW_AT_linkage_name    ("_ZN5CBase3fooEv")
          DW_AT_name    ("foo")
          ...

0x30: DW_TAG_subprogram
        DW_AT_linkage_name      ("_Z3barP5CBase")
        DW_AT_name      ("bar")
        ...

0x40:   DW_TAG_call_site
          DW_AT_call_target_clobbered   (DW_OP_breg0 RAX+0)
          DW_AT_call_return_pc  (0x000000000000000a)
```
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,
> 
> 1. $RIP is currently in 'bar()'
> 2. The call-site information in the parent frame indicates we should have 
> called 'foo()'
> 
> If we see a situation like the above, we can infer that 'foo()' and 'bar()' 
> have been code folded. This technique breaks when dealing with virtual 
> functions because the call-site information only provides a way to find the 
> target function at runtime.
> 
> However, if the call-site information includes information on which virtual 
> function is being called, we can compare this against the $RIP location to 
> see if we are in an implementation of the virtual function. If we are not, 
> then we can assume we have been code folded.
> 
> For this to work we just to need to record which virtual function we are 
> calling. We do not need to know the type of the 'this' pointer at the 
> call-site.
> 

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_origin`` for 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_origin`` matches 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 from ``foo`` to ``bar``, but the debugger can disambiguate 
these cases by looking at the ``DW_AT_call_origin`` referenced subroutine DIE 
which has a tombstone ``DW_AT_low_pc`` in the ICF case.

- For virtual calls such as the given test case, the existence of the 
``DW_AT_LLVM_virtual_call_origin`` attribute tells the debugger that this is an 
indirect jump, and the ``DW_AT_LLVM_virtual_call_origin`` attribute, 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``, and 
``DW_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_origin`` to identify the target 
call ``CBase::foo``.
```
0x40:   DW_TAG_call_site
          DW_AT_call_target_clobbered   (DW_OP_breg0 RAX+0)
          DW_AT_call_return_pc  (0x000000000000000a)
          -----------------------------------------------
          DW_AT_LLVM_virtual_call_origin        (0x20 "_ZN5CBase3fooEv")
          -----------------------------------------------
```
The extra call site information is available by default for all debuggers and 
it is generated only for DWARF 5 or greater.

>From 6efff0c844494c0efcebecfc1ee902e96d64eb57 Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <[email protected]>
Date: Fri, 20 Feb 2026 12:52:12 +0000
Subject: [PATCH 1/2] [clang][DebugInfo] Add virtuality call-site target
 information in DWARF.

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.
---
 clang/lib/CodeGen/CGCall.cpp                  |  2 +
 clang/lib/CodeGen/CGDebugInfo.cpp             | 17 ++++
 clang/lib/CodeGen/CGDebugInfo.h               |  9 ++
 clang/test/DebugInfo/CXX/callsite-base.cpp    | 48 ++++++++++
 clang/test/DebugInfo/CXX/callsite-derived.cpp | 58 ++++++++++++
 clang/test/DebugInfo/CXX/callsite-edges.cpp   | 93 +++++++++++++++++++
 .../clang_llvm_roundtrip/callsite-dwarf.cpp   | 71 ++++++++++++++
 llvm/include/llvm/BinaryFormat/Dwarf.def      |  1 +
 llvm/include/llvm/CodeGen/MachineFunction.h   |  6 ++
 llvm/include/llvm/CodeGen/TargetLowering.h    |  4 +
 llvm/include/llvm/IR/FixedMetadataKinds.def   |  1 +
 .../CodeGen/AsmPrinter/DwarfCompileUnit.cpp   | 15 ++-
 .../lib/CodeGen/AsmPrinter/DwarfCompileUnit.h |  4 +
 llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp    | 29 +++++-
 llvm/lib/CodeGen/MIRPrinter.cpp               |  2 +-
 llvm/lib/CodeGen/MachineFunction.cpp          |  3 +
 .../CodeGen/SelectionDAG/TargetLowering.cpp   | 14 +++
 llvm/lib/DebugInfo/DWARF/DWARFDie.cpp         |  3 +-
 .../Target/AArch64/AArch64ISelLowering.cpp    |  3 +-
 llvm/lib/Target/ARM/ARMISelLowering.cpp       |  3 +-
 llvm/lib/Target/Mips/MipsISelLowering.cpp     |  3 +-
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp   |  3 +-
 llvm/lib/Target/X86/X86ISelLoweringCall.cpp   |  3 +-
 .../MIR/X86/callsite-emit-calleetypeid.ll     |  8 +-
 24 files changed, 380 insertions(+), 23 deletions(-)
 create mode 100644 clang/test/DebugInfo/CXX/callsite-base.cpp
 create mode 100644 clang/test/DebugInfo/CXX/callsite-derived.cpp
 create mode 100644 clang/test/DebugInfo/CXX/callsite-edges.cpp
 create mode 100644 
cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/callsite-dwarf.cpp

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..0a77e0037dac0 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -4985,6 +4985,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..928bc8fdd9c5d 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,12 @@ 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 {
+    // Check general conditions for call site generation.
+    return (getCallSiteRelatedAttrs() != llvm::DINode::FlagZero);
+  }
 };
 
 /// 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..cf26d62a03c0b
--- /dev/null
+++ b/clang/test/DebugInfo/CXX/callsite-base.cpp
@@ -0,0 +1,48 @@
+// 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
+
+// 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
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-dwarf.cpp 
b/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/callsite-dwarf.cpp
new file mode 100644
index 0000000000000..b2b2eae95c800
--- /dev/null
+++ 
b/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/callsite-dwarf.cpp
@@ -0,0 +1,71 @@
+// RUN: %clang --target=x86_64-unknown-linux -c -g -O1 %s -o - | \
+// RUN: llvm-dwarfdump --debug-info - | FileCheck %s --check-prefix=CHECK
+
+// 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.
+
+// 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{{.*}}")
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..0d79677d7079e 100644
--- a/llvm/include/llvm/IR/FixedMetadataKinds.def
+++ b/llvm/include/llvm/IR/FixedMetadataKinds.def
@@ -59,3 +59,4 @@ LLVM_FIXED_MD_KIND(MD_captures, "captures", 44)
 LLVM_FIXED_MD_KIND(MD_alloc_token, "alloc_token", 45)
 LLVM_FIXED_MD_KIND(MD_implicit_ref, "implicit.ref", 46)
 LLVM_FIXED_MD_KIND(MD_nofpclass, "nofpclass", 47)
+LLVM_FIXED_MD_KIND(MD_call_target, "call_target", 48)
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp 
b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
index e87d3f3ee02a0..eb55b47dfde2b 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
@@ -1349,11 +1349,7 @@ DIE &DwarfCompileUnit::constructCallSiteEntryDIE(
   } else if (CalleeSP) {
     DIE *CalleeDIE = getOrCreateSubprogramDIE(CalleeSP, CalleeF);
     assert(CalleeDIE && "Could not create DIE for call site entry origin");
-    if (AddLinkageNamesToDeclCallOriginsForTuning(DD) &&
-        !CalleeSP->isDefinition() &&
-        !CalleeDIE->findAttribute(dwarf::DW_AT_linkage_name)) {
-      addLinkageName(*CalleeDIE, CalleeSP->getLinkageName());
-    }
+    addLinkageNamesToDeclarations(*DD, *CalleeSP, *CalleeDIE);
 
     addDIEEntry(CallSiteDIE, getDwarf5OrGNUAttr(dwarf::DW_AT_call_origin),
                 *CalleeDIE);
@@ -1891,3 +1887,12 @@ DIE *DwarfCompileUnit::getOrCreateSubprogramDIE(const 
DISubprogram *SP,
 
   return DwarfUnit::getOrCreateSubprogramDIE(SP, F, Minimal);
 }
+
+void DwarfCompileUnit::addLinkageNamesToDeclarations(
+    const DwarfDebug &DD, const DISubprogram &CalleeSP, DIE &CalleeDIE) {
+  if (AddLinkageNamesToDeclCallOriginsForTuning(&DD) &&
+      !CalleeSP.isDefinition() &&
+      !CalleeDIE.findAttribute(dwarf::DW_AT_linkage_name)) {
+    addLinkageName(CalleeDIE, CalleeSP.getLinkageName());
+  }
+}
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h 
b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
index 04d4556c3ce52..ede02c169bffd 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
@@ -436,6 +436,10 @@ class DwarfCompileUnit final : public DwarfUnit {
   void addBaseTypeRef(DIEValueList &Die, int64_t Idx);
 
   MDNodeSetVector &getDeferredLocalDecls() { return DeferredLocalDecls; }
+
+  void addLinkageNamesToDeclarations(const DwarfDebug &DD,
+                                     const DISubprogram &CalleeSP,
+                                     DIE &CalleeDIE);
 };
 
 } // end namespace llvm
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp 
b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index f8c2c753b91ce..042c98fa1c02f 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -955,6 +955,30 @@ void DwarfDebug::constructCallSiteEntryDIEs(const 
DISubprogram &SP,
     return true;
   };
 
+  // Create call_target connections for indirect calls.
+  auto addCallSiteTargetForIndirectCalls = [&](const MachineInstr *MI,
+                                               DIE &CallSiteDIE) {
+    const MachineFunction *MF = MI->getMF();
+    const auto &CalleesMap = MF->getCallSitesInfo();
+    auto CSInfo = CalleesMap.find(MI);
+    // Get the information for the call instruction.
+    if (CSInfo == CalleesMap.end() || !CSInfo->second.CallTarget)
+      return;
+
+    MDNode *CallTarget = CSInfo->second.CallTarget;
+    // Add DW_AT_LLVM_virtual_call_origin with the 'call_target' metadata.
+    assert(!CallSiteDIE.findAttribute(dwarf::DW_AT_LLVM_virtual_call_origin) &&
+           "DW_AT_LLVM_virtual_call_origin already exists");
+    const DISubprogram *CalleeSP = dyn_cast<DISubprogram>(CallTarget);
+    DIE *CalleeDIE = CU.getOrCreateSubprogramDIE(CalleeSP, nullptr);
+    assert(CalleeDIE && "Could not create DIE for call site entry origin");
+    CU.addDIEEntry(CallSiteDIE,
+                   
CU.getDwarf5OrGNUAttr(dwarf::DW_AT_LLVM_virtual_call_origin),
+                   *CalleeDIE);
+    // Add DW_AT_linkage_name to the method declaration if needed.
+    CU.addLinkageNamesToDeclarations(*this, *CalleeSP, *CalleeDIE);
+  };
+
   // Emit call site entries for each call or tail call in the function.
   for (const MachineBasicBlock &MBB : MF) {
     for (const MachineInstr &MI : MBB.instrs()) {
@@ -1052,6 +1076,9 @@ void DwarfDebug::constructCallSiteEntryDIEs(const 
DISubprogram &SP,
           ScopeDIE, CalleeSP, CalleeDecl, IsTail, PCAddr, CallAddr, CallTarget,
           Offset, AllocSiteTy);
 
+      if (CallTarget.getReg())
+        addCallSiteTargetForIndirectCalls(TopLevelCallMI, CallSiteDIE);
+
       // Optionally emit call-site-param debug info.
       if (emitDebugEntryValues()) {
         ParamSet Params;
@@ -1460,7 +1487,7 @@ void DwarfDebug::finalizeModuleInfo() {
                             TLOF.getDwarfMacinfoSection()->getBeginSymbol());
       }
     }
-    }
+  }
 
   // Emit all frontend-produced Skeleton CUs, i.e., Clang modules.
   for (auto *CUNode : MMI->getModule()->debug_compile_units())
diff --git a/llvm/lib/CodeGen/MIRPrinter.cpp b/llvm/lib/CodeGen/MIRPrinter.cpp
index 9a48a0062549a..e5fa7da3d03b5 100644
--- a/llvm/lib/CodeGen/MIRPrinter.cpp
+++ b/llvm/lib/CodeGen/MIRPrinter.cpp
@@ -541,7 +541,7 @@ static void convertCallSiteObjects(yaml::MachineFunction 
&YMF,
         std::distance(CallI->getParent()->instr_begin(), CallI);
     YmlCS.CallLocation = CallLocation;
 
-    auto [ArgRegPairs, CalleeTypeIds] = CallSiteInfo;
+    auto [ArgRegPairs, CalleeTypeIds, _] = CallSiteInfo;
     // Construct call arguments and theirs forwarding register info.
     for (auto ArgReg : ArgRegPairs) {
       yaml::CallSiteInfo::ArgRegPair YmlArgReg;
diff --git a/llvm/lib/CodeGen/MachineFunction.cpp 
b/llvm/lib/CodeGen/MachineFunction.cpp
index fb35c7e62dad6..fe876fe4dc3e8 100644
--- a/llvm/lib/CodeGen/MachineFunction.cpp
+++ b/llvm/lib/CodeGen/MachineFunction.cpp
@@ -700,6 +700,9 @@ bool MachineFunction::needsFrameMoves() const {
 }
 
 MachineFunction::CallSiteInfo::CallSiteInfo(const CallBase &CB) {
+  if (MDNode *Node = CB.getMetadata(llvm::LLVMContext::MD_call_target))
+    CallTarget = Node;
+
   // Numeric callee_type ids are only for indirect calls.
   if (!CB.isIndirectCall())
     return;
diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp 
b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index 7d0f8c632ba18..9dacc28f439d6 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -12804,3 +12804,17 @@ SDValue 
TargetLowering::scalarizeExtractedVectorLoad(EVT ResultVT,
 
   return Load;
 }
+
+// Set type id for call site info and metadata 'call_target'.
+// We are filtering for:
+// a) The call-graph-section use case that wants to know about indirect
+//    calls, or
+// b) We want to annotate indirect calls.
+void TargetLowering::setTypeIdForCallsiteInfo(
+    const CallBase *CB, MachineFunction &MF,
+    MachineFunction::CallSiteInfo &CSInfo) const {
+  if (CB && CB->isIndirectCall() &&
+      (MF.getTarget().Options.EmitCallGraphSection ||
+       MF.getTarget().Options.EmitCallSiteInfo))
+    CSInfo = MachineFunction::CallSiteInfo(*CB);
+}
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp 
b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
index cd8a2b305a0f9..f8357ed216f5f 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
@@ -246,7 +246,8 @@ static void dumpAttribute(raw_ostream &OS, const DWARFDie 
&Die,
   // having both the raw value and the pretty-printed value is
   // interesting. These attributes are handled below.
   if (Attr == DW_AT_specification || Attr == DW_AT_abstract_origin ||
-      Attr == DW_AT_call_origin || Attr == DW_AT_import) {
+      Attr == DW_AT_call_origin || Attr == DW_AT_import ||
+      Attr == DW_AT_LLVM_virtual_call_origin) {
     if (const char *Name =
             Die.getAttributeValueAsReferencedDie(FormValue).getName(
                 DINameKind::LinkageName))
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp 
b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 7af6db793892b..98927e4d60595 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -9936,8 +9936,7 @@ AArch64TargetLowering::LowerCall(CallLoweringInfo &CLI,
   RetCCInfo.AnalyzeCallResult(Ins, RetCC);
 
   // Set type id for call site info.
-  if (MF.getTarget().Options.EmitCallGraphSection && CB && 
CB->isIndirectCall())
-    CSInfo = MachineFunction::CallSiteInfo(*CB);
+  setTypeIdForCallsiteInfo(CB, MF, CSInfo);
 
   // Check callee args/returns for SVE registers and set calling convention
   // accordingly.
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp 
b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index 4004ace444eff..270d2a12dcc55 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -2057,8 +2057,7 @@ 
ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
     GuardWithBTI = AFI->branchTargetEnforcement();
 
   // Set type id for call site info.
-  if (MF.getTarget().Options.EmitCallGraphSection && CB && 
CB->isIndirectCall())
-    CSInfo = MachineFunction::CallSiteInfo(*CB);
+  setTypeIdForCallsiteInfo(CB, MF, CSInfo);
 
   // Determine whether this is a non-secure function call.
   if (CLI.CB && CLI.CB->getAttributes().hasFnAttr("cmse_nonsecure_call"))
diff --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp 
b/llvm/lib/Target/Mips/MipsISelLowering.cpp
index c920e912f49ac..7e6b920e61b78 100644
--- a/llvm/lib/Target/Mips/MipsISelLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp
@@ -3343,8 +3343,7 @@ 
MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
   // Call site info for function parameters tracking and call base type info.
   MachineFunction::CallSiteInfo CSInfo;
   // Set type id for call site info.
-  if (MF.getTarget().Options.EmitCallGraphSection && CB && 
CB->isIndirectCall())
-    CSInfo = MachineFunction::CallSiteInfo(*CB);
+  setTypeIdForCallsiteInfo(CB, MF, CSInfo);
 
   // Check if it's really possible to do a tail call.
   // For non-musttail calls, restrict to functions that won't require $gp
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp 
b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 5f09ece63d3e5..c835821caf704 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -24554,8 +24554,7 @@ SDValue RISCVTargetLowering::LowerCall(CallLoweringInfo 
&CLI,
   MachineFunction::CallSiteInfo CSInfo;
 
   // Set type id for call site info.
-  if (MF.getTarget().Options.EmitCallGraphSection && CB && 
CB->isIndirectCall())
-    CSInfo = MachineFunction::CallSiteInfo(*CB);
+  setTypeIdForCallsiteInfo(CB, MF, CSInfo);
 
   // Analyze the operands of the call, assigning locations to each operand.
   SmallVector<CCValAssign, 16> ArgLocs;
diff --git a/llvm/lib/Target/X86/X86ISelLoweringCall.cpp 
b/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
index 92348689f57f0..c0e120dc30b86 100644
--- a/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
+++ b/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
@@ -2078,8 +2078,7 @@ 
X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
     report_fatal_error("X86 interrupts may not be called directly");
 
   // Set type id for call site info.
-  if (MF.getTarget().Options.EmitCallGraphSection && CB && 
CB->isIndirectCall())
-    CSInfo = MachineFunction::CallSiteInfo(*CB);
+  setTypeIdForCallsiteInfo(CB, MF, CSInfo);
 
   if (IsIndirectCall && !IsWin64 &&
       M->getModuleFlag("import-call-optimization"))
diff --git a/llvm/test/CodeGen/MIR/X86/callsite-emit-calleetypeid.ll 
b/llvm/test/CodeGen/MIR/X86/callsite-emit-calleetypeid.ll
index 3f7590adf9182..fe1980e3f5605 100644
--- a/llvm/test/CodeGen/MIR/X86/callsite-emit-calleetypeid.ll
+++ b/llvm/test/CodeGen/MIR/X86/callsite-emit-calleetypeid.ll
@@ -32,14 +32,13 @@
 ;; Test printer and parser with -emit-call-site-info only.
 
 ;; Test printer.
-;; Verify that fwdArgRegs is set, calleeTypeIds is not set.
+;; Verify that fwdArgRegs and calleeTypeIds are set.
 ; RUN: llc -mtriple=x86_64 -emit-call-site-info %s -stop-after=finalize-isel 
-o %t2.mir
 ; RUN: cat %t2.mir | FileCheck %s --check-prefix=PRINTER_CSI
 ; PRINTER_CSI: name: main
 ; PRINTER_CSI: callSites:
 ; PRINTER_CSI-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs:
-; PRINTER_CSI-NEXT: { arg: 0, reg: {{.*}} }
-; PRINTER_CSI-NOT: calleeTypeIds:
+; PRINTER_CSI-NEXT: { arg: 0, reg: {{.*}} }, calleeTypeIds:
 
 
 ;; Test parser.
@@ -49,8 +48,7 @@
 ; PARSER_CSI: name: main
 ; PARSER_CSI: callSites:
 ; PARSER_CSI-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs:
-; PARSER_CSI-NEXT: { arg: 0, reg: {{.*}} }
-; PARSER_CSI-NOT: calleeTypeIds:
+; PARSER_CSI-NEXT: { arg: 0, reg: {{.*}} }, calleeTypeIds:
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Test printer and parser with both -emit-call-site-info and 
--call-graph-section.

>From c4519d309b2907a340e2a0d0121eca59b216e5ea Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <[email protected]>
Date: Fri, 20 Feb 2026 15:04:15 +0000
Subject: [PATCH 2/2] [clang][DebugInfo] Add virtuality call-site target
 information in DWARF.

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
---
 clang/lib/CodeGen/CGDebugInfo.cpp             |  6 ++++
 clang/lib/CodeGen/CGDebugInfo.h               |  5 +--
 clang/test/DebugInfo/CXX/callsite-base.cpp    | 22 +++++++++++++
 .../clang_llvm_roundtrip/callsite-crash.cpp   | 20 ++++++++++++
 .../clang_llvm_roundtrip/callsite-dwarf.cpp   | 32 +++++++++++++++++--
 5 files changed, 79 insertions(+), 6 deletions(-)
 create mode 100644 
cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/callsite-crash.cpp

diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp 
b/clang/lib/CodeGen/CGDebugInfo.cpp
index 0a77e0037dac0..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);
diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h
index 928bc8fdd9c5d..8e1eda2d93ac0 100644
--- a/clang/lib/CodeGen/CGDebugInfo.h
+++ b/clang/lib/CodeGen/CGDebugInfo.h
@@ -912,10 +912,7 @@ class CGDebugInfo {
   llvm::StringRef GetMethodLinkageName(const CXXMethodDecl *Method) const;
 
   /// Returns true if we should generate call target information.
-  bool shouldGenerateVirtualCallSite() const {
-    // Check general conditions for call site generation.
-    return (getCallSiteRelatedAttrs() != llvm::DINode::FlagZero);
-  }
+  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
index cf26d62a03c0b..399e62ede0dec 100644
--- a/clang/test/DebugInfo/CXX/callsite-base.cpp
+++ b/clang/test/DebugInfo/CXX/callsite-base.cpp
@@ -2,6 +2,10 @@
 // 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:
@@ -46,3 +50,21 @@ void bar(CBase *Base) {
 
 // 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/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
index b2b2eae95c800..9fe6df6a0f61d 100644
--- 
a/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/callsite-dwarf.cpp
+++ 
b/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/callsite-dwarf.cpp
@@ -1,10 +1,15 @@
-// RUN: %clang --target=x86_64-unknown-linux -c -g -O1 %s -o - | \
+// 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.
+// 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.
@@ -69,3 +74,26 @@ void CDerivedTwo::bar(int &j) { DerivedOne->foo(j); }
 // 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)

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to