Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/CodeGenOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ CODEGENOPT(EnableNoundefAttrs, 1, 0, Benign) ///< Enable emitting `noundef` attr
CODEGENOPT(DebugPassManager, 1, 0, Benign) ///< Prints debug information for the new
///< pass manager.
CODEGENOPT(DisableRedZone , 1, 0, Benign) ///< Set when -mno-red-zone is enabled.
CODEGENOPT(CallGraphSection, 1, 0, Benign) ///< Emit a call graph section into the
///< object file.
CODEGENOPT(EmitCallSiteInfo, 1, 0, Benign) ///< Emit call site info only in the case of
///< '-g' + 'O>0' level.
CODEGENOPT(IndirectTlsSegRefs, 1, 0, Benign) ///< Set when -mno-tls-direct-seg-refs
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -4512,6 +4512,12 @@ defm data_sections : BoolFOption<"data-sections",
PosFlag<SetTrue, [], [ClangOption, CC1Option],
"Place each data in its own section">,
NegFlag<SetFalse>>;
defm experimental_call_graph_section
: BoolFOption<"experimental-call-graph-section", CodeGenOpts<"CallGraphSection">,
DefaultFalse,
PosFlag<SetTrue, [], [ClangOption, CC1Option],
"Emit a call graph section">,
NegFlag<SetFalse>>;
defm stack_size_section : BoolFOption<"stack-size-section",
CodeGenOpts<"StackSizeSection">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption, CC1Option],
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/BackendUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,7 @@ static bool initTargetOptions(const CompilerInstance &CI,
Options.StackUsageOutput = CodeGenOpts.StackUsageOutput;
Options.EmitAddrsig = CodeGenOpts.Addrsig;
Options.ForceDwarfFrameSection = CodeGenOpts.ForceDwarfFrameSection;
Options.EmitCallGraphSection = CodeGenOpts.CallGraphSection;
Options.EmitCallSiteInfo = CodeGenOpts.EmitCallSiteInfo;
Options.EnableAIXExtendedAltivecABI = LangOpts.EnableAIXExtendedAltivecABI;
Options.XRayFunctionIndex = CodeGenOpts.XRayFunctionIndex;
Expand Down
18 changes: 17 additions & 1 deletion clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5945,8 +5945,24 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
CI->getCalledFunction()->getName().starts_with("_Z4sqrt")) {
SetSqrtFPAccuracy(CI);
}
if (callOrInvoke)
if (callOrInvoke) {
*callOrInvoke = CI;
if (CGM.getCodeGenOpts().CallGraphSection) {
QualType CST;
if (TargetDecl && TargetDecl->getFunctionType())
CST = QualType(TargetDecl->getFunctionType(), 0);
else if (const auto *FPT =
Callee.getAbstractInfo().getCalleeFunctionProtoType())
CST = QualType(FPT, 0);
else
llvm_unreachable(
"Cannot find the callee type to generate callee_type metadata.");

// Set type identifier metadata of indirect calls for call graph section.
if (!CST.isNull())
CGM.createCalleeTypeMetadataForIcall(CST, *callOrInvoke);
}
}

// If this is within a function that has the guard(nocf) attribute and is an
// indirect call, add the "guard_nocf" attribute to this call to indicate that
Expand Down
44 changes: 37 additions & 7 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2836,8 +2836,9 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,

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

static bool hasExistingGeneralizedTypeMD(llvm::Function *F) {
llvm::MDNode *MD = F->getMetadata(llvm::LLVMContext::MD_type);
return MD && MD->hasGeneralizedMDString();
}

void CodeGenModule::createFunctionTypeMetadataForIcall(const FunctionDecl *FD,
llvm::Function *F) {
// Only if we are checking indirect calls.
if (CodeGenOpts.CallGraphSection && !hasExistingGeneralizedTypeMD(F) &&
(!F->hasLocalLinkage() ||
F->getFunction().hasAddressTaken(nullptr, /*IgnoreCallbackUses=*/true,
/*IgnoreAssumeLikeCalls=*/true,
/*IgnoreLLVMUsed=*/false)))
F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(FD->getType()));

// Add additional metadata only if we are checking indirect calls with CFI.
if (!LangOpts.Sanitize.has(SanitizerKind::CFIICall))
return;

Expand All @@ -3064,17 +3077,34 @@ void CodeGenModule::createFunctionTypeMetadataForIcall(const FunctionDecl *FD,
/*GeneralizePointers=*/false);
llvm::Metadata *MD = CreateMetadataIdentifierForType(FnType);
F->addTypeMetadata(0, MD);

QualType GenPtrFnType = GeneralizeFunctionType(getContext(), FD->getType(),
/*GeneralizePointers=*/true);
F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(GenPtrFnType));
// Add the generalized identifier if not added already.
if (!hasExistingGeneralizedTypeMD(F)) {
QualType GenPtrFnType = GeneralizeFunctionType(getContext(), FD->getType(),
/*GeneralizePointers=*/true);
F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(GenPtrFnType));
}

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

void CodeGenModule::createCalleeTypeMetadataForIcall(const QualType &QT,
llvm::CallBase *CB) {
// Only if needed for call graph section and only for indirect calls.
if (!CodeGenOpts.CallGraphSection || !CB->isIndirectCall())
return;

llvm::Metadata *TypeIdMD = CreateMetadataIdentifierGeneralized(QT);
llvm::MDTuple *TypeTuple = llvm::MDTuple::get(
getLLVMContext(), {llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
llvm::Type::getInt64Ty(getLLVMContext()), 0)),
TypeIdMD});
llvm::MDTuple *MDN = llvm::MDNode::get(getLLVMContext(), {TypeTuple});
CB->setMetadata(llvm::LLVMContext::MD_callee_type, MDN);
}

void CodeGenModule::setKCFIType(const FunctionDecl *FD, llvm::Function *F) {
llvm::LLVMContext &Ctx = F->getContext();
llvm::MDBuilder MDB(Ctx);
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -1644,6 +1644,9 @@ class CodeGenModule : public CodeGenTypeCache {
void createFunctionTypeMetadataForIcall(const FunctionDecl *FD,
llvm::Function *F);

/// Create and attach type metadata to the given call.
void createCalleeTypeMetadataForIcall(const QualType &QT, llvm::CallBase *CB);

/// Set type metadata to the given function.
void setKCFIType(const FunctionDecl *FD, llvm::Function *F);

Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6447,6 +6447,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue());
}

if (Args.hasFlag(options::OPT_fexperimental_call_graph_section,
options::OPT_fno_experimental_call_graph_section, false))
CmdArgs.push_back("-fexperimental-call-graph-section");

Args.addOptInFlag(CmdArgs, options::OPT_fstack_size_section,
options::OPT_fno_stack_size_section);

Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Driver/ToolChains/CommonArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1272,6 +1272,11 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
CmdArgs.push_back(
Args.MakeArgString(Twine(PluginOptPrefix) + "-stack-size-section"));

if (Args.hasFlag(options::OPT_fexperimental_call_graph_section,
options::OPT_fno_experimental_call_graph_section, false))
CmdArgs.push_back(
Args.MakeArgString(Twine(PluginOptPrefix) + "-call-graph-section"));

// Setup statistics file output.
SmallString<128> StatsFile = getStatsFileName(Args, Output, *Input, D);
if (!StatsFile.empty())
Expand Down
114 changes: 114 additions & 0 deletions clang/test/CodeGen/call-graph-section-templates.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Tests that we assign appropriate identifiers to indirect calls and targets
// specifically for C++ templates.

// RUN: %clang_cc1 -triple x86_64-unknown-linux -fexperimental-call-graph-section \
// RUN: -emit-llvm -o %t %s
// RUN: FileCheck --check-prefix=FT %s < %t
// RUN: FileCheck --check-prefix=CST %s < %t

////////////////////////////////////////////////////////////////////////////////
// Class definitions and template classes (check for indirect target metadata)

class Cls1 {};

// Cls2 is instantiated with T=Cls1 in foo(). Following checks are for this
// instantiation.
template <class T>
class Cls2 {
public:
// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f1Ev({{.*}} !type [[F_TCLS2F1:![0-9]+]]
void f1() {}

// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f2ES0_({{.*}} !type [[F_TCLS2F2:![0-9]+]]
void f2(T a) {}

// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f3EPS0_({{.*}} !type [[F_TCLS2F3:![0-9]+]]
void f3(T *a) {}

// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f4EPKS0_({{.*}} !type [[F_TCLS2F4:![0-9]+]]
void f4(const T *a) {}

// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f5ERS0_({{.*}} !type [[F_TCLS2F5:![0-9]+]]
void f5(T &a) {}

// FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f6ERKS0_({{.*}} !type [[F_TCLS2F6:![0-9]+]]
void f6(const T &a) {}

// Mixed type function pointer member
T *(*fp)(T a, T *b, const T *c, T &d, const T &e);
};

// FT-DAG: [[F_TCLS2F1]] = !{i64 0, !"_ZTSFvvE.generalized"}
// FT-DAG: [[F_TCLS2F2]] = !{i64 0, !"_ZTSFv4Cls1E.generalized"}
// FT-DAG: [[F_TCLS2F3]] = !{i64 0, !"_ZTSFvPvE.generalized"}
// FT-DAG: [[F_TCLS2F4]] = !{i64 0, !"_ZTSFvPKvE.generalized"}
// FT-DAG: [[F_TCLS2F5]] = !{i64 0, !"_ZTSFvR4Cls1E.generalized"}
// FT-DAG: [[F_TCLS2F6]] = !{i64 0, !"_ZTSFvRK4Cls1E.generalized"}

////////////////////////////////////////////////////////////////////////////////
// Callsites (check for indirect callsite operand bundles)

template <class T>
T *T_func(T a, T *b, const T *c, T &d, const T &e) { return b; }

// CST-LABEL: define {{.*}} @_Z3foov
void foo() {
// Methods for Cls2<Cls1> is checked above within the template description.
Cls2<Cls1> Obj;

Obj.fp = T_func<Cls1>;
Cls1 Cls1Obj;

// CST: call noundef ptr %{{.*}}, !callee_type [[F_TFUNC_CLS1_CT:![0-9]+]]
Obj.fp(Cls1Obj, &Cls1Obj, &Cls1Obj, Cls1Obj, Cls1Obj);

// Make indirect calls to Cls2's member methods
auto fp_f1 = &Cls2<Cls1>::f1;
auto fp_f2 = &Cls2<Cls1>::f2;
auto fp_f3 = &Cls2<Cls1>::f3;
auto fp_f4 = &Cls2<Cls1>::f4;
auto fp_f5 = &Cls2<Cls1>::f5;
auto fp_f6 = &Cls2<Cls1>::f6;

auto *Obj2Ptr = &Obj;

// CST: call void %{{.*}}, !callee_type [[F_TCLS2F1_CT:![0-9]+]]
(Obj2Ptr->*fp_f1)();

// CST: call void %{{.*}}, !callee_type [[F_TCLS2F2_CT:![0-9]+]]
(Obj2Ptr->*fp_f2)(Cls1Obj);

// CST: call void %{{.*}}, !callee_type [[F_TCLS2F3_CT:![0-9]+]]
(Obj2Ptr->*fp_f3)(&Cls1Obj);

// CST: call void %{{.*}}, !callee_type [[F_TCLS2F4_CT:![0-9]+]]
(Obj2Ptr->*fp_f4)(&Cls1Obj);

// CST: call void %{{.*}}, !callee_type [[F_TCLS2F5_CT:![0-9]+]]
(Obj2Ptr->*fp_f5)(Cls1Obj);

// CST: call void %{{.*}}, !callee_type [[F_TCLS2F6_CT:![0-9]+]]
(Obj2Ptr->*fp_f6)(Cls1Obj);
}

// CST: define {{.*}} @_Z6T_funcI4Cls1EPT_S1_S2_PKS1_RS1_RS3_({{.*}} !type [[F_TFUNC_CLS1:![0-9]+]]
// CST-DAG: [[F_TFUNC_CLS1_CT]] = !{[[F_TFUNC_CLS1:![0-9]+]]}
// CST-DAG: [[F_TFUNC_CLS1]] = !{i64 0, !"_ZTSFPv4Cls1S_PKvRS0_RKS0_E.generalized"}

// CST-DAG: [[F_TCLS2F1_CT]] = !{[[F_TCLS2F1:![0-9]+]]}
// CST-DAG: [[F_TCLS2F1]] = !{i64 0, !"_ZTSFvvE.generalized"}

// CST-DAG: [[F_TCLS2F2_CT]] = !{[[F_TCLS2F2:![0-9]+]]}
// CST-DAG: [[F_TCLS2F2]] = !{i64 0, !"_ZTSFv4Cls1E.generalized"}

// CST-DAG: [[F_TCLS2F3_CT]] = !{[[F_TCLS2F3:![0-9]+]]}
// CST-DAG: [[F_TCLS2F3]] = !{i64 0, !"_ZTSFvPvE.generalized"}

// CST-DAG: [[F_TCLS2F4_CT]] = !{[[F_TCLS2F4:![0-9]+]]}
// CST-DAG: [[F_TCLS2F4]] = !{i64 0, !"_ZTSFvPKvE.generalized"}

// CST-DAG: [[F_TCLS2F5_CT]] = !{[[F_TCLS2F5:![0-9]+]]}
// CST-DAG: [[F_TCLS2F5]] = !{i64 0, !"_ZTSFvR4Cls1E.generalized"}

// CST-DAG: [[F_TCLS2F6_CT]] = !{[[F_TCLS2F6:![0-9]+]]}
// CST-DAG: [[F_TCLS2F6]] = !{i64 0, !"_ZTSFvRK4Cls1E.generalized"}
55 changes: 55 additions & 0 deletions clang/test/CodeGen/call-graph-section-virtual-methods.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Tests that we assign appropriate identifiers to indirect calls and targets
// specifically for virtual methods.

// RUN: %clang_cc1 -triple x86_64-unknown-linux -fexperimental-call-graph-section \
// RUN: -emit-llvm -o %t %s
// RUN: FileCheck --check-prefix=FT %s < %t
// RUN: FileCheck --check-prefix=CST %s < %t

////////////////////////////////////////////////////////////////////////////////
// Class definitions (check for indirect target metadata)

class Base {
public:
// FT-DAG: define {{.*}} @_ZN4Base2vfEPc({{.*}} !type [[F_TVF:![0-9]+]]
virtual int vf(char *a) { return 0; };
};

class Derived : public Base {
public:
// FT-DAG: define {{.*}} @_ZN7Derived2vfEPc({{.*}} !type [[F_TVF]]
int vf(char *a) override { return 1; };
};

// FT-DAG: [[F_TVF]] = !{i64 0, !"_ZTSFiPvE.generalized"}

////////////////////////////////////////////////////////////////////////////////
// Callsites (check for indirect callsite operand bundles)

// CST-LABEL: define {{.*}} @_Z3foov
void foo() {
auto B = Base();
auto D = Derived();

Base *Bptr = &B;
Base *BptrToD = &D;
Derived *Dptr = &D;

auto FpBaseVf = &Base::vf;
auto FpDerivedVf = &Derived::vf;

// CST: call noundef i32 %{{.*}}, !callee_type [[F_TVF_CT:![0-9]+]]
(Bptr->*FpBaseVf)(0);

// CST: call noundef i32 %{{.*}}, !callee_type [[F_TVF_CT:![0-9]+]]
(BptrToD->*FpBaseVf)(0);

// CST: call noundef i32 %{{.*}}, !callee_type [[F_TVF_CT:![0-9]+]]
(Dptr->*FpBaseVf)(0);

// CST: call noundef i32 %{{.*}}, !callee_type [[F_TVF_CT:![0-9]+]]
(Dptr->*FpDerivedVf)(0);
}

// CST-DAG: [[F_TVF_CT]] = !{[[F_TVF:![0-9]+]]}
// CST-DAG: [[F_TVF]] = !{i64 0, !"_ZTSFiPvE.generalized"}
Loading
Loading