Skip to content

Commit 9de4f0b

Browse files
[clang][DebugInfo] Add call site target information in DWARF.
Given the test case (CBase is a structure or class): int function(CBase *Input) { int Output = Input->foo(); return Output; } and using '-emit-call-site-info' with llc, the following DWARF debug information is produced for the indirect call 'Input->foo()': 0x51: DW_TAG_call_site DW_AT_call_target (DW_OP_reg0 RAX) DW_AT_call_return_pc (0x0e) This patch generates an extra 'DW_AT_call_origin' to identify the target call 'CBase::foo'. 0x51: DW_TAG_call_site DW_AT_call_target (DW_OP_reg0 RAX) DW_AT_call_return_pc (0x0e) ----------------------------------------------- DW_AT_call_origin (0x71 "_ZN5CBase3fooEb") ----------------------------------------------- 0x61: DW_TAG_class_type DW_AT_name ("CBase") ... 0x71: DW_TAG_subprogram DW_AT_linkage_name ("_ZN5CBase3fooEb") DW_AT_name ("foo") The extra call site information is generated only for the SCE debugger: '-Xclang -debugger-tuning=sce'
1 parent a664cad commit 9de4f0b

File tree

14 files changed

+514
-6
lines changed

14 files changed

+514
-6
lines changed

clang/lib/CodeGen/CGCall.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5958,6 +5958,9 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
59585958
}
59595959
}
59605960

5961+
if (CGDebugInfo *DI = CGM.getModuleDebugInfo())
5962+
DI->addCallTarget(CI->getCalledFunction(), CalleeDecl, CI);
5963+
59615964
// If this is within a function that has the guard(nocf) attribute and is an
59625965
// indirect call, add the "guard_nocf" attribute to this call to indicate that
59635966
// Control Flow Guard checks should not be added, even if the call is inlined.

clang/lib/CodeGen/CGDebugInfo.cpp

Lines changed: 112 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2430,6 +2430,9 @@ llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction(
24302430

24312431
SPCache[Method->getCanonicalDecl()].reset(SP);
24322432

2433+
// Add the method declaration as a call target.
2434+
addCallTarget(MethodLinkageName, SP, /*CI=*/nullptr);
2435+
24332436
return SP;
24342437
}
24352438

@@ -4955,6 +4958,99 @@ void CGDebugInfo::EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc,
49554958
Fn->setSubprogram(SP);
49564959
}
49574960

4961+
bool CGDebugInfo::generateCallSiteForPS() const {
4962+
// The added call target will be available only for SCE targets.
4963+
if (CGM.getCodeGenOpts().getDebuggerTuning() != llvm::DebuggerKind::SCE)
4964+
return false;
4965+
4966+
// Check general conditions for call site generation.
4967+
return (getCallSiteRelatedAttrs() != llvm::DINode::FlagZero);
4968+
}
4969+
4970+
// Set the 'call_target' metadata in the call instruction.
4971+
void CGDebugInfo::addCallTargetMetadata(llvm::MDNode *MD, llvm::CallBase *CI) {
4972+
if (!MD || !CI)
4973+
return;
4974+
CI->setMetadata(llvm::LLVMContext::MD_call_target, MD);
4975+
}
4976+
4977+
// Finalize call_target generation.
4978+
void CGDebugInfo::finalizeCallTarget() {
4979+
if (!generateCallSiteForPS())
4980+
return;
4981+
4982+
for (auto &E : CallTargetCache) {
4983+
for (const auto &WH : E.second.second) {
4984+
llvm::CallBase *CI = dyn_cast_or_null<llvm::CallBase>(WH);
4985+
addCallTargetMetadata(E.second.first, CI);
4986+
}
4987+
}
4988+
}
4989+
4990+
void CGDebugInfo::addCallTarget(StringRef Name, llvm::MDNode *MD,
4991+
llvm::CallBase *CI) {
4992+
if (!generateCallSiteForPS())
4993+
return;
4994+
4995+
// Record only indirect calls.
4996+
if (CI && !CI->isIndirectCall())
4997+
return;
4998+
4999+
// Nothing to do.
5000+
if (Name.empty())
5001+
return;
5002+
5003+
auto It = CallTargetCache.find(Name);
5004+
if (It == CallTargetCache.end()) {
5005+
// First time we see 'Name'. Insert record for later finalize.
5006+
InstrList List;
5007+
if (CI)
5008+
List.push_back(CI);
5009+
CallTargetCache.try_emplace(Name, MD, std::move(List));
5010+
} else {
5011+
if (MD)
5012+
It->second.first.reset(MD);
5013+
if (CI) {
5014+
InstrList &List = It->second.second;
5015+
List.push_back(CI);
5016+
}
5017+
}
5018+
}
5019+
5020+
void CGDebugInfo::addCallTarget(llvm::Function *F, const FunctionDecl *FD,
5021+
llvm::CallBase *CI) {
5022+
if (!generateCallSiteForPS())
5023+
return;
5024+
5025+
if (!F && !FD)
5026+
return;
5027+
5028+
// Ignore method types that never can be indirect calls.
5029+
if (!F && (isa<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD) ||
5030+
FD->hasAttr<CUDAGlobalAttr>()))
5031+
return;
5032+
5033+
StringRef Name = (F && F->hasName()) ? F->getName() : CGM.getMangledName(FD);
5034+
addCallTarget(Name, /*MD=*/nullptr, CI);
5035+
}
5036+
5037+
void CGDebugInfo::removeCallTarget(StringRef Name) {
5038+
if (!generateCallSiteForPS())
5039+
return;
5040+
5041+
auto It = CallTargetCache.find(Name);
5042+
if (It != CallTargetCache.end())
5043+
CallTargetCache.erase(It);
5044+
}
5045+
5046+
void CGDebugInfo::removeCallTarget(llvm::Function *F) {
5047+
if (!generateCallSiteForPS())
5048+
return;
5049+
5050+
if (F && F->hasName())
5051+
removeCallTarget(F->getName());
5052+
}
5053+
49585054
void CGDebugInfo::EmitFuncDeclForCallSite(llvm::CallBase *CallOrInvoke,
49595055
QualType CalleeType,
49605056
GlobalDecl CalleeGlobalDecl) {
@@ -4978,9 +5074,15 @@ void CGDebugInfo::EmitFuncDeclForCallSite(llvm::CallBase *CallOrInvoke,
49785074
// If there is no DISubprogram attached to the function being called,
49795075
// create the one describing the function in order to have complete
49805076
// call site debug info.
4981-
if (!CalleeDecl->isStatic() && !CalleeDecl->isInlined())
5077+
if (!CalleeDecl->isStatic() && !CalleeDecl->isInlined()) {
49825078
EmitFunctionDecl(CalleeGlobalDecl, CalleeDecl->getLocation(), CalleeType,
49835079
Func);
5080+
if (Func->getSubprogram()) {
5081+
// For each call instruction emitted, add the call site target metadata.
5082+
llvm::DISubprogram *SP = Func->getSubprogram();
5083+
addCallTarget(SP->getLinkageName(), SP, /*CI=*/nullptr);
5084+
}
5085+
}
49845086
}
49855087

49865088
void CGDebugInfo::EmitInlineFunctionStart(CGBuilderTy &Builder, GlobalDecl GD) {
@@ -5082,8 +5184,13 @@ void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder, llvm::Function *Fn) {
50825184
}
50835185
FnBeginRegionCount.pop_back();
50845186

5085-
if (Fn && Fn->getSubprogram())
5187+
if (Fn && Fn->getSubprogram()) {
5188+
// For each call instruction emitted, add the call site target metadata.
5189+
llvm::DISubprogram *SP = Fn->getSubprogram();
5190+
addCallTarget(SP->getLinkageName(), SP, /*CI=*/nullptr);
5191+
50865192
DBuilder.finalizeSubprogram(Fn->getSubprogram());
5193+
}
50875194
}
50885195

50895196
CGDebugInfo::BlockByRefType
@@ -6498,6 +6605,9 @@ void CGDebugInfo::finalize() {
64986605
if (auto MD = TypeCache[RT])
64996606
DBuilder.retainType(cast<llvm::DIType>(MD));
65006607

6608+
// Generate call_target information.
6609+
finalizeCallTarget();
6610+
65016611
DBuilder.finalize();
65026612
}
65036613

clang/lib/CodeGen/CGDebugInfo.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,15 @@ class CGDebugInfo {
682682
/// that it is supported and enabled.
683683
llvm::DINode::DIFlags getCallSiteRelatedAttrs() const;
684684

685+
/// Add call target information.
686+
void addCallTarget(StringRef Name, llvm::MDNode *MD, llvm::CallBase *CI);
687+
void addCallTarget(llvm::Function *F, const FunctionDecl *FD,
688+
llvm::CallBase *CI);
689+
690+
/// Remove a call target entry for the given name or function.
691+
void removeCallTarget(StringRef Name);
692+
void removeCallTarget(llvm::Function *F);
693+
685694
private:
686695
/// Amend \p I's DebugLoc with \p Group (its source atom group) and \p
687696
/// Rank (lower nonzero rank is higher precedence). Does nothing if \p I
@@ -903,6 +912,25 @@ class CGDebugInfo {
903912
/// If one exists, returns the linkage name of the specified \
904913
/// (non-null) \c Method. Returns empty string otherwise.
905914
llvm::StringRef GetMethodLinkageName(const CXXMethodDecl *Method) const;
915+
916+
/// For each 'DISuprogram' we store a list of call instructions 'CallBase'
917+
/// that indirectly call such 'DISuprogram'. We use its linkage name to
918+
/// update such list.
919+
/// The 'CallTargetCache' is updated in the following scenarios:
920+
/// - Both 'CallBase' and 'MDNode' are ready available.
921+
/// - If only the 'CallBase' or 'MDNode' are are available, the partial
922+
/// information is added and later is completed when the missing item
923+
/// ('CallBase' or 'MDNode') is available.
924+
using InstrList = llvm::SmallVector<llvm::WeakVH, 2>;
925+
using CallTargetEntry = std::pair<llvm::TrackingMDNodeRef, InstrList>;
926+
llvm::SmallDenseMap<StringRef, CallTargetEntry> CallTargetCache;
927+
928+
/// Generate call target information only for SIE debugger.
929+
bool generateCallSiteForPS() const;
930+
931+
/// Add 'call_target' metadata to the 'call' instruction.
932+
void addCallTargetMetadata(llvm::MDNode *MD, llvm::CallBase *CI);
933+
void finalizeCallTarget();
906934
};
907935

908936
/// A scoped helper to set the current debug location to the specified

clang/lib/CodeGen/CodeGenFunction.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1510,6 +1510,8 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
15101510
// Clear non-distinct debug info that was possibly attached to the function
15111511
// due to an earlier declaration without the nodebug attribute
15121512
Fn->setSubprogram(nullptr);
1513+
if (CGDebugInfo *DI = getDebugInfo())
1514+
DI->removeCallTarget(Fn);
15131515
// Disable debug info indefinitely for this function
15141516
DebugInfo = nullptr;
15151517
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Simple class with only virtual methods: inlined and not-inlined
2+
// We check for a generated 'call_target' for:
3+
// - 'one', 'two' and 'three'.
4+
5+
class CBase {
6+
public:
7+
virtual void one();
8+
virtual void two();
9+
virtual void three() {}
10+
};
11+
void CBase::one() {}
12+
13+
void bar(CBase *Base) {
14+
Base->one();
15+
Base->two();
16+
Base->three();
17+
18+
CBase B;
19+
B.one();
20+
}
21+
22+
// RUN: %clang_cc1 -debugger-tuning=sce -triple=x86_64-linux -disable-llvm-passes -emit-llvm -debug-info-kind=constructor -dwarf-version=5 -O1 %s -o - | FileCheck %s -check-prefix CHECK-BASE
23+
24+
// CHECK-BASE: define {{.*}} @_Z3barP5CBase{{.*}} {
25+
// CHECK-BASE-DAG: call void %1{{.*}} !dbg {{![0-9]+}}, !call_target [[BASE_ONE:![0-9]+]]
26+
// CHECK-BASE-DAG: call void %3{{.*}} !dbg {{![0-9]+}}, !call_target [[BASE_TWO:![0-9]+]]
27+
// CHECK-BASE-DAG: call void %5{{.*}} !dbg {{![0-9]+}}, !call_target [[BASE_THREE:![0-9]+]]
28+
// CHECK-BASE-DAG: call void @_ZN5CBaseC2Ev{{.*}} !dbg {{![0-9]+}}
29+
// CHECK-BASE-DAG: call void @_ZN5CBase3oneEv{{.*}} !dbg {{![0-9]+}}
30+
// CHECK-BASE: }
31+
32+
// CHECK-BASE-DAG: [[BASE_ONE]] = {{.*}}!DISubprogram(name: "one", linkageName: "_ZN5CBase3oneEv"
33+
// CHECK-BASE-DAG: [[BASE_TWO]] = {{.*}}!DISubprogram(name: "two", linkageName: "_ZN5CBase3twoEv"
34+
// CHECK-BASE-DAG: [[BASE_THREE]] = {{.*}}!DISubprogram(name: "three", linkageName: "_ZN5CBase5threeEv"
35+
36+
// RUN: %clang_cc1 -triple=x86_64-linux -disable-llvm-passes -emit-llvm -debug-info-kind=constructor -dwarf-version=5 -O1 %s -o - | FileCheck %s -check-prefix CHECK-BASE-NON
37+
38+
// CHECK-BASE-NON: define {{.*}} @_Z3barP5CBase{{.*}} {
39+
// CHECK-BASE-NON-DAG: call void %1{{.*}} !dbg {{![0-9]+}}
40+
// CHECK-BASE-NON-DAG: call void %3{{.*}} !dbg {{![0-9]+}}
41+
// CHECK-BASE-NON-DAG: call void %5{{.*}} !dbg {{![0-9]+}}
42+
// CHECK-BASE-NON: }
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Simple base and derived class with virtual and static methods:
2+
// We check for a generated 'call_target' for:
3+
// - 'one', 'two' and 'three'.
4+
5+
class CBase {
6+
public:
7+
virtual void one(bool Flag) {}
8+
virtual void two(int P1, char P2) {}
9+
static void three();
10+
};
11+
12+
void CBase::three() {
13+
}
14+
void bar(CBase *Base);
15+
16+
void foo(CBase *Base) {
17+
CBase::three();
18+
}
19+
20+
class CDerived : public CBase {
21+
public:
22+
void one(bool Flag) {}
23+
void two(int P1, char P2) {}
24+
};
25+
void foo(CDerived *Derived);
26+
27+
int main() {
28+
CBase B;
29+
bar(&B);
30+
31+
CDerived D;
32+
foo(&D);
33+
34+
return 0;
35+
}
36+
37+
void bar(CBase *Base) {
38+
Base->two(77, 'a');
39+
}
40+
41+
void foo(CDerived *Derived) {
42+
Derived->one(true);
43+
}
44+
45+
// RUN: %clang_cc1 -debugger-tuning=sce -triple=x86_64-linux -disable-llvm-passes -emit-llvm -debug-info-kind=constructor -dwarf-version=5 -O1 %s -o - | FileCheck %s -check-prefix CHECK-DERIVED
46+
47+
// CHECK-DERIVED: define {{.*}} @_Z3fooP5CBase{{.*}} {
48+
// CHECK-DERIVED-DAG: call void @_ZN5CBase5threeEv{{.*}} !dbg {{![0-9]+}}
49+
// CHECK-DERIVED: }
50+
51+
// CHECK-DERIVED: define {{.*}} @main{{.*}} {
52+
// CHECK-DERIVED-DAG: call void @_ZN5CBaseC1Ev{{.*}} !dbg {{![0-9]+}}
53+
// CHECK-DERIVED-DAG: call void @_Z3barP5CBase{{.*}} !dbg {{![0-9]+}}
54+
// CHECK-DERIVED-DAG: call void @_ZN8CDerivedC1Ev{{.*}} !dbg {{![0-9]+}}
55+
// CHECK-DERIVED-DAG: call void @_Z3fooP8CDerived{{.*}} !dbg {{![0-9]+}}
56+
// CHECK-DERIVED: }
57+
58+
// CHECK-DERIVED: define {{.*}} @_ZN5CBaseC1Ev{{.*}} {
59+
// CHECK-DERIVED-DAG: call void @_ZN5CBaseC2Ev{{.*}} !dbg {{![0-9]+}}
60+
// CHECK-DERIVED: }
61+
62+
// CHECK-DERIVED: define {{.*}} @_Z3barP5CBase{{.*}} {
63+
// CHECK-DERIVED-DAG: call void %1{{.*}} !dbg {{![0-9]+}}, !call_target [[BASE_TWO:![0-9]+]]
64+
// CHECK-DERIVED: }
65+
66+
// CHECK-DERIVED: define {{.*}} @_ZN8CDerivedC1Ev{{.*}} {
67+
// CHECK-DERIVED-DAG: call void @_ZN8CDerivedC2Ev{{.*}} !dbg {{![0-9]+}}
68+
// CHECK-DERIVED: }
69+
70+
// CHECK-DERIVED: define {{.*}} @_Z3fooP8CDerived{{.*}} {
71+
// CHECK-DERIVED-DAG: call void %1{{.*}} !dbg {{![0-9]+}}, !call_target [[DERIVED_ONE:![0-9]+]]
72+
// CHECK-DERIVED: }
73+
74+
// CHECK-DERIVED-DAG: [[BASE_TWO]] = {{.*}}!DISubprogram(name: "two", linkageName: "_ZN5CBase3twoEic"
75+
// CHECK-DERIVED-DAG: [[DERIVED_ONE]] = {{.*}}!DISubprogram(name: "one", linkageName: "_ZN8CDerived3oneEb"
76+
77+
// RUN: %clang_cc1 -triple=x86_64-linux -disable-llvm-passes -emit-llvm -debug-info-kind=constructor -dwarf-version=5 -O1 %s -o - | FileCheck %s -check-prefix CHECK-DERIVED-NON
78+
79+
// CHECK-DERIVED-NON: define {{.*}} @_Z3barP5CBase{{.*}} {
80+
// CHECK-DERIVED-NON-DAG: call void %1{{.*}} !dbg {{![0-9]+}}
81+
// CHECK-DERIVED-NON: }
82+
83+
// CHECK-DERIVED-NON: define {{.*}} @_Z3fooP8CDerived{{.*}} {
84+
// CHECK-DERIVED-NON-DAG: call void %1{{.*}} !dbg {{![0-9]+}}
85+
// CHECK-DERIVED-NON: }

0 commit comments

Comments
 (0)