Skip to content

Commit 6d2beaf

Browse files
committed
[𝘀𝗽𝗿] initial version
Created using spr 1.3.6-beta.1
2 parents 17ccb84 + 90f1325 commit 6d2beaf

22 files changed

+814
-6
lines changed

clang/include/clang/Basic/CodeGenOptions.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ CODEGENOPT(EnableNoundefAttrs, 1, 0, Benign) ///< Enable emitting `noundef` attr
7272
CODEGENOPT(DebugPassManager, 1, 0, Benign) ///< Prints debug information for the new
7373
///< pass manager.
7474
CODEGENOPT(DisableRedZone , 1, 0, Benign) ///< Set when -mno-red-zone is enabled.
75+
CODEGENOPT(CallGraphSection, 1, 0, Benign) ///< Emit a call graph section into the
76+
///< object file.
7577
CODEGENOPT(EmitCallSiteInfo, 1, 0, Benign) ///< Emit call site info only in the case of
7678
///< '-g' + 'O>0' level.
7779
CODEGENOPT(IndirectTlsSegRefs, 1, 0, Benign) ///< Set when -mno-tls-direct-seg-refs

clang/include/clang/Driver/Options.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4440,6 +4440,12 @@ defm data_sections : BoolFOption<"data-sections",
44404440
PosFlag<SetTrue, [], [ClangOption, CC1Option],
44414441
"Place each data in its own section">,
44424442
NegFlag<SetFalse>>;
4443+
defm experimental_call_graph_section
4444+
: BoolFOption<"experimental-call-graph-section",
4445+
CodeGenOpts<"CallGraphSection">, DefaultFalse,
4446+
PosFlag<SetTrue, [], [ClangOption, CC1Option],
4447+
"Emit a call graph section">,
4448+
NegFlag<SetFalse>>;
44434449
defm stack_size_section : BoolFOption<"stack-size-section",
44444450
CodeGenOpts<"StackSizeSection">, DefaultFalse,
44454451
PosFlag<SetTrue, [], [ClangOption, CC1Option],

clang/lib/CodeGen/BackendUtil.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,7 @@ static bool initTargetOptions(const CompilerInstance &CI,
462462
Options.StackUsageOutput = CodeGenOpts.StackUsageOutput;
463463
Options.EmitAddrsig = CodeGenOpts.Addrsig;
464464
Options.ForceDwarfFrameSection = CodeGenOpts.ForceDwarfFrameSection;
465+
Options.EmitCallGraphSection = CodeGenOpts.CallGraphSection;
465466
Options.EmitCallSiteInfo = CodeGenOpts.EmitCallSiteInfo;
466467
Options.EnableAIXExtendedAltivecABI = LangOpts.EnableAIXExtendedAltivecABI;
467468
Options.XRayFunctionIndex = CodeGenOpts.XRayFunctionIndex;

clang/lib/CodeGen/CGCall.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5912,8 +5912,24 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
59125912
CI->getCalledFunction()->getName().starts_with("_Z4sqrt")) {
59135913
SetSqrtFPAccuracy(CI);
59145914
}
5915-
if (callOrInvoke)
5915+
if (callOrInvoke) {
59165916
*callOrInvoke = CI;
5917+
if (CGM.getCodeGenOpts().CallGraphSection) {
5918+
QualType CST;
5919+
if (TargetDecl && TargetDecl->getFunctionType())
5920+
CST = QualType(TargetDecl->getFunctionType(), 0);
5921+
else if (const auto *FPT =
5922+
Callee.getAbstractInfo().getCalleeFunctionProtoType())
5923+
CST = QualType(FPT, 0);
5924+
else
5925+
llvm_unreachable(
5926+
"Cannot find the callee type to generate callee_type metadata.");
5927+
5928+
// Set type identifier metadata of indirect calls for call graph section.
5929+
if (!CST.isNull())
5930+
CGM.createCalleeTypeMetadataForIcall(CST, *callOrInvoke);
5931+
}
5932+
}
59175933

59185934
// If this is within a function that has the guard(nocf) attribute and is an
59195935
// indirect call, add the "guard_nocf" attribute to this call to indicate that

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2775,8 +2775,9 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
27752775

27762776
// In the cross-dso CFI mode with canonical jump tables, we want !type
27772777
// attributes on definitions only.
2778-
if (CodeGenOpts.SanitizeCfiCrossDso &&
2779-
CodeGenOpts.SanitizeCfiCanonicalJumpTables) {
2778+
if ((CodeGenOpts.SanitizeCfiCrossDso &&
2779+
CodeGenOpts.SanitizeCfiCanonicalJumpTables) ||
2780+
CodeGenOpts.CallGraphSection) {
27802781
if (auto *FD = dyn_cast<FunctionDecl>(D)) {
27812782
// Skip available_externally functions. They won't be codegen'ed in the
27822783
// current module anyway.
@@ -2988,9 +2989,21 @@ static void setLinkageForGV(llvm::GlobalValue *GV, const NamedDecl *ND) {
29882989
GV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
29892990
}
29902991

2992+
static bool hasExistingGeneralizedTypeMD(llvm::Function *F) {
2993+
llvm::MDNode *MD = F->getMetadata(llvm::LLVMContext::MD_type);
2994+
return MD && MD->hasGeneralizedMDString();
2995+
}
2996+
29912997
void CodeGenModule::createFunctionTypeMetadataForIcall(const FunctionDecl *FD,
29922998
llvm::Function *F) {
2993-
// Only if we are checking indirect calls.
2999+
if (CodeGenOpts.CallGraphSection && !hasExistingGeneralizedTypeMD(F) &&
3000+
(!F->hasLocalLinkage() ||
3001+
F->getFunction().hasAddressTaken(nullptr, /*IgnoreCallbackUses=*/true,
3002+
/*IgnoreAssumeLikeCalls=*/true,
3003+
/*IgnoreLLVMUsed=*/false)))
3004+
F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(FD->getType()));
3005+
3006+
// Add additional metadata only if we are checking indirect calls with CFI.
29943007
if (!LangOpts.Sanitize.has(SanitizerKind::CFIICall))
29953008
return;
29963009

@@ -3001,14 +3014,31 @@ void CodeGenModule::createFunctionTypeMetadataForIcall(const FunctionDecl *FD,
30013014

30023015
llvm::Metadata *MD = CreateMetadataIdentifierForType(FD->getType());
30033016
F->addTypeMetadata(0, MD);
3004-
F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(FD->getType()));
3017+
// Add the generalized identifier if not added already.
3018+
if (!hasExistingGeneralizedTypeMD(F))
3019+
F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(FD->getType()));
30053020

30063021
// Emit a hash-based bit set entry for cross-DSO calls.
30073022
if (CodeGenOpts.SanitizeCfiCrossDso)
30083023
if (auto CrossDsoTypeId = CreateCrossDsoCfiTypeId(MD))
30093024
F->addTypeMetadata(0, llvm::ConstantAsMetadata::get(CrossDsoTypeId));
30103025
}
30113026

3027+
void CodeGenModule::createCalleeTypeMetadataForIcall(const QualType &QT,
3028+
llvm::CallBase *CB) {
3029+
// Only if needed for call graph section and only for indirect calls.
3030+
if (!CodeGenOpts.CallGraphSection || !CB->isIndirectCall())
3031+
return;
3032+
3033+
llvm::Metadata *TypeIdMD = CreateMetadataIdentifierGeneralized(QT);
3034+
llvm::MDTuple *TypeTuple = llvm::MDTuple::get(
3035+
getLLVMContext(), {llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
3036+
llvm::Type::getInt64Ty(getLLVMContext()), 0)),
3037+
TypeIdMD});
3038+
llvm::MDTuple *MDN = llvm::MDNode::get(getLLVMContext(), {TypeTuple});
3039+
CB->setMetadata(llvm::LLVMContext::MD_callee_type, MDN);
3040+
}
3041+
30123042
void CodeGenModule::setKCFIType(const FunctionDecl *FD, llvm::Function *F) {
30133043
llvm::LLVMContext &Ctx = F->getContext();
30143044
llvm::MDBuilder MDB(Ctx);

clang/lib/CodeGen/CodeGenModule.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1641,6 +1641,9 @@ class CodeGenModule : public CodeGenTypeCache {
16411641
void createFunctionTypeMetadataForIcall(const FunctionDecl *FD,
16421642
llvm::Function *F);
16431643

1644+
/// Create and attach type metadata to the given call.
1645+
void createCalleeTypeMetadataForIcall(const QualType &QT, llvm::CallBase *CB);
1646+
16441647
/// Set type metadata to the given function.
16451648
void setKCFIType(const FunctionDecl *FD, llvm::Function *F);
16461649

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6476,6 +6476,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
64766476
CmdArgs.push_back(A->getValue());
64776477
}
64786478

6479+
if (Args.hasFlag(options::OPT_fexperimental_call_graph_section,
6480+
options::OPT_fno_experimental_call_graph_section, false))
6481+
CmdArgs.push_back("-fexperimental-call-graph-section");
6482+
64796483
Args.addOptInFlag(CmdArgs, options::OPT_fstack_size_section,
64806484
options::OPT_fno_stack_size_section);
64816485

clang/lib/Driver/ToolChains/CommonArgs.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1269,6 +1269,11 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
12691269
CmdArgs.push_back(
12701270
Args.MakeArgString(Twine(PluginOptPrefix) + "-stack-size-section"));
12711271

1272+
if (Args.hasFlag(options::OPT_fexperimental_call_graph_section,
1273+
options::OPT_fno_experimental_call_graph_section, false))
1274+
CmdArgs.push_back(
1275+
Args.MakeArgString(Twine(PluginOptPrefix) + "-call-graph-section"));
1276+
12721277
// Setup statistics file output.
12731278
SmallString<128> StatsFile = getStatsFileName(Args, Output, *Input, D);
12741279
if (!StatsFile.empty())
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// Tests that we assign appropriate identifiers to indirect calls and targets
2+
// specifically for C++ templates.
3+
4+
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fexperimental-call-graph-section \
5+
// RUN: -emit-llvm -o %t %s
6+
// RUN: FileCheck --check-prefix=FT %s < %t
7+
// RUN: FileCheck --check-prefix=CST %s < %t
8+
9+
////////////////////////////////////////////////////////////////////////////////
10+
// Class definitions and template classes (check for indirect target metadata)
11+
12+
class Cls1 {};
13+
14+
// Cls2 is instantiated with T=Cls1 in foo(). Following checks are for this
15+
// instantiation.
16+
template <class T>
17+
class Cls2 {
18+
public:
19+
// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f1Ev({{.*}} !type [[F_TCLS2F1:![0-9]+]]
20+
void f1() {}
21+
22+
// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f2ES0_({{.*}} !type [[F_TCLS2F2:![0-9]+]]
23+
void f2(T a) {}
24+
25+
// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f3EPS0_({{.*}} !type [[F_TCLS2F3:![0-9]+]]
26+
void f3(T *a) {}
27+
28+
// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f4EPKS0_({{.*}} !type [[F_TCLS2F4:![0-9]+]]
29+
void f4(const T *a) {}
30+
31+
// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f5ERS0_({{.*}} !type [[F_TCLS2F5:![0-9]+]]
32+
void f5(T &a) {}
33+
34+
// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f6ERKS0_({{.*}} !type [[F_TCLS2F6:![0-9]+]]
35+
void f6(const T &a) {}
36+
37+
// Mixed type function pointer member
38+
T *(*fp)(T a, T *b, const T *c, T &d, const T &e);
39+
};
40+
41+
// FT-DAG: [[F_TCLS2F1]] = !{i64 0, !"_ZTSFvvE.generalized"}
42+
// FT-DAG: [[F_TCLS2F2]] = !{i64 0, !"_ZTSFv4Cls1E.generalized"}
43+
// FT-DAG: [[F_TCLS2F3]] = !{i64 0, !"_ZTSFvPvE.generalized"}
44+
// FT-DAG: [[F_TCLS2F4]] = !{i64 0, !"_ZTSFvPKvE.generalized"}
45+
// FT-DAG: [[F_TCLS2F5]] = !{i64 0, !"_ZTSFvR4Cls1E.generalized"}
46+
// FT-DAG: [[F_TCLS2F6]] = !{i64 0, !"_ZTSFvRK4Cls1E.generalized"}
47+
48+
////////////////////////////////////////////////////////////////////////////////
49+
// Callsites (check for indirect callsite operand bundles)
50+
51+
template <class T>
52+
T *T_func(T a, T *b, const T *c, T &d, const T &e) { return b; }
53+
54+
// CST-LABEL: define {{.*}} @_Z3foov
55+
void foo() {
56+
// Methods for Cls2<Cls1> is checked above within the template description.
57+
Cls2<Cls1> Obj;
58+
59+
Obj.fp = T_func<Cls1>;
60+
Cls1 Cls1Obj;
61+
62+
// CST: call noundef ptr %{{.*}}, !callee_type [[F_TFUNC_CLS1_CT:![0-9]+]]
63+
Obj.fp(Cls1Obj, &Cls1Obj, &Cls1Obj, Cls1Obj, Cls1Obj);
64+
65+
// Make indirect calls to Cls2's member methods
66+
auto fp_f1 = &Cls2<Cls1>::f1;
67+
auto fp_f2 = &Cls2<Cls1>::f2;
68+
auto fp_f3 = &Cls2<Cls1>::f3;
69+
auto fp_f4 = &Cls2<Cls1>::f4;
70+
auto fp_f5 = &Cls2<Cls1>::f5;
71+
auto fp_f6 = &Cls2<Cls1>::f6;
72+
73+
auto *Obj2Ptr = &Obj;
74+
75+
// CST: call void %{{.*}}, !callee_type [[F_TCLS2F1_CT:![0-9]+]]
76+
(Obj2Ptr->*fp_f1)();
77+
78+
// CST: call void %{{.*}}, !callee_type [[F_TCLS2F2_CT:![0-9]+]]
79+
(Obj2Ptr->*fp_f2)(Cls1Obj);
80+
81+
// CST: call void %{{.*}}, !callee_type [[F_TCLS2F3_CT:![0-9]+]]
82+
(Obj2Ptr->*fp_f3)(&Cls1Obj);
83+
84+
// CST: call void %{{.*}}, !callee_type [[F_TCLS2F4_CT:![0-9]+]]
85+
(Obj2Ptr->*fp_f4)(&Cls1Obj);
86+
87+
// CST: call void %{{.*}}, !callee_type [[F_TCLS2F5_CT:![0-9]+]]
88+
(Obj2Ptr->*fp_f5)(Cls1Obj);
89+
90+
// CST: call void %{{.*}}, !callee_type [[F_TCLS2F6_CT:![0-9]+]]
91+
(Obj2Ptr->*fp_f6)(Cls1Obj);
92+
}
93+
94+
// CST: define {{.*}} @_Z6T_funcI4Cls1EPT_S1_S2_PKS1_RS1_RS3_({{.*}} !type [[F_TFUNC_CLS1:![0-9]+]]
95+
// CST-DAG: [[F_TFUNC_CLS1_CT]] = !{[[F_TFUNC_CLS1:![0-9]+]]}
96+
// CST-DAG: [[F_TFUNC_CLS1]] = !{i64 0, !"_ZTSFPv4Cls1S_PKvRS0_RKS0_E.generalized"}
97+
98+
// CST-DAG: [[F_TCLS2F1_CT]] = !{[[F_TCLS2F1:![0-9]+]]}
99+
// CST-DAG: [[F_TCLS2F1]] = !{i64 0, !"_ZTSFvvE.generalized"}
100+
101+
// CST-DAG: [[F_TCLS2F2_CT]] = !{[[F_TCLS2F2:![0-9]+]]}
102+
// CST-DAG: [[F_TCLS2F2]] = !{i64 0, !"_ZTSFv4Cls1E.generalized"}
103+
104+
// CST-DAG: [[F_TCLS2F3_CT]] = !{[[F_TCLS2F3:![0-9]+]]}
105+
// CST-DAG: [[F_TCLS2F3]] = !{i64 0, !"_ZTSFvPvE.generalized"}
106+
107+
// CST-DAG: [[F_TCLS2F4_CT]] = !{[[F_TCLS2F4:![0-9]+]]}
108+
// CST-DAG: [[F_TCLS2F4]] = !{i64 0, !"_ZTSFvPKvE.generalized"}
109+
110+
// CST-DAG: [[F_TCLS2F5_CT]] = !{[[F_TCLS2F5:![0-9]+]]}
111+
// CST-DAG: [[F_TCLS2F5]] = !{i64 0, !"_ZTSFvR4Cls1E.generalized"}
112+
113+
// CST-DAG: [[F_TCLS2F6_CT]] = !{[[F_TCLS2F6:![0-9]+]]}
114+
// CST-DAG: [[F_TCLS2F6]] = !{i64 0, !"_ZTSFvRK4Cls1E.generalized"}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Tests that we assign appropriate identifiers to indirect calls and targets
2+
// specifically for virtual methods.
3+
4+
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fexperimental-call-graph-section \
5+
// RUN: -emit-llvm -o %t %s
6+
// RUN: FileCheck --check-prefix=FT %s < %t
7+
// RUN: FileCheck --check-prefix=CST %s < %t
8+
9+
////////////////////////////////////////////////////////////////////////////////
10+
// Class definitions (check for indirect target metadata)
11+
12+
class Base {
13+
public:
14+
// FT-DAG: define {{.*}} @_ZN4Base2vfEPc({{.*}} !type [[F_TVF:![0-9]+]]
15+
virtual int vf(char *a) { return 0; };
16+
};
17+
18+
class Derived : public Base {
19+
public:
20+
// FT-DAG: define {{.*}} @_ZN7Derived2vfEPc({{.*}} !type [[F_TVF]]
21+
int vf(char *a) override { return 1; };
22+
};
23+
24+
// FT-DAG: [[F_TVF]] = !{i64 0, !"_ZTSFiPvE.generalized"}
25+
26+
////////////////////////////////////////////////////////////////////////////////
27+
// Callsites (check for indirect callsite operand bundles)
28+
29+
// CST-LABEL: define {{.*}} @_Z3foov
30+
void foo() {
31+
auto B = Base();
32+
auto D = Derived();
33+
34+
Base *Bptr = &B;
35+
Base *BptrToD = &D;
36+
Derived *Dptr = &D;
37+
38+
auto FpBaseVf = &Base::vf;
39+
auto FpDerivedVf = &Derived::vf;
40+
41+
// CST: call noundef i32 %{{.*}}, !callee_type [[F_TVF_CT:![0-9]+]]
42+
(Bptr->*FpBaseVf)(0);
43+
44+
// CST: call noundef i32 %{{.*}}, !callee_type [[F_TVF_CT:![0-9]+]]
45+
(BptrToD->*FpBaseVf)(0);
46+
47+
// CST: call noundef i32 %{{.*}}, !callee_type [[F_TVF_CT:![0-9]+]]
48+
(Dptr->*FpBaseVf)(0);
49+
50+
// CST: call noundef i32 %{{.*}}, !callee_type [[F_TVF_CT:![0-9]+]]
51+
(Dptr->*FpDerivedVf)(0);
52+
}
53+
54+
// CST-DAG: [[F_TVF_CT]] = !{[[F_TVF:![0-9]+]]}
55+
// CST-DAG: [[F_TVF]] = !{i64 0, !"_ZTSFiPvE.generalized"}

0 commit comments

Comments
 (0)