summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/CodeGen/StackProtector.h31
-rw-r--r--llvm/include/llvm/IR/DiagnosticInfo.h1
-rw-r--r--llvm/lib/CodeGen/StackProtector.cpp42
-rw-r--r--llvm/test/CodeGen/X86/stack-protector-remarks.ll87
4 files changed, 160 insertions, 1 deletions
diff --git a/llvm/include/llvm/CodeGen/StackProtector.h b/llvm/include/llvm/CodeGen/StackProtector.h
index 1b3c0eb4a4d..44044e6cf16 100644
--- a/llvm/include/llvm/CodeGen/StackProtector.h
+++ b/llvm/include/llvm/CodeGen/StackProtector.h
@@ -19,6 +19,7 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/ValueMap.h"
#include "llvm/Pass.h"
@@ -134,6 +135,36 @@ public:
bool runOnFunction(Function &Fn) override;
};
+
+/// Diagnostic information for why SSP was applied.
+class DiagnosticInfoSSP : public DiagnosticInfoWithDebugLocBase {
+public:
+ enum SSPReason {
+ Alloca = 0,
+ BufferOrStruct = 1,
+ AddressTaken = 2,
+ Attribute = 3,
+ LastUsedValue = 3
+ };
+
+ /// \p Fn is the function where the diagnostic is being emitted. \p Reason is
+ /// an enum value representing why the function has stack protection.
+ DiagnosticInfoSSP(const Function &Fn, SSPReason Reason)
+ : DiagnosticInfoWithDebugLocBase(DK_SSPReason, DS_Remark, Fn, DebugLoc()),
+ Func(Fn), Why(Reason) {}
+
+ static bool classof(const DiagnosticInfo *DI) {
+ return DI->getKind() == DK_SSPReason;
+ }
+
+ void print(DiagnosticPrinter &DP) const override;
+
+ SSPReason Reason() const { return Why; }
+
+private:
+ const Function &Func;
+ const SSPReason Why;
+};
} // end namespace llvm
#endif // LLVM_CODEGEN_STACKPROTECTOR_H
diff --git a/llvm/include/llvm/IR/DiagnosticInfo.h b/llvm/include/llvm/IR/DiagnosticInfo.h
index 1a5770c8632..9fc1175ea1d 100644
--- a/llvm/include/llvm/IR/DiagnosticInfo.h
+++ b/llvm/include/llvm/IR/DiagnosticInfo.h
@@ -77,6 +77,7 @@ enum DiagnosticKind {
DK_MIRParser,
DK_PGOProfile,
DK_Unsupported,
+ DK_SSPReason,
DK_FirstPluginKind
};
diff --git a/llvm/lib/CodeGen/StackProtector.cpp b/llvm/lib/CodeGen/StackProtector.cpp
index c2c010a29d4..ac747a44567 100644
--- a/llvm/lib/CodeGen/StackProtector.cpp
+++ b/llvm/lib/CodeGen/StackProtector.cpp
@@ -26,6 +26,7 @@
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/GlobalVariable.h"
@@ -51,7 +52,7 @@ static cl::opt<bool> EnableSelectionDAGSP("enable-selectiondag-sp",
char StackProtector::ID = 0;
INITIALIZE_TM_PASS(StackProtector, "stack-protector", "Insert stack protectors",
- false, true)
+ false, true)
FunctionPass *llvm::createStackProtectorPass(const TargetMachine *TM) {
return new StackProtector(TM);
@@ -223,6 +224,8 @@ bool StackProtector::RequiresStackProtector() {
return false;
if (F->hasFnAttribute(Attribute::StackProtectReq)) {
+ F->getContext().diagnose(
+ DiagnosticInfoSSP(*F, DiagnosticInfoSSP::SSPReason::Attribute));
NeedsProtector = true;
Strong = true; // Use the same heuristic as strong to determine SSPLayout
} else if (F->hasFnAttribute(Attribute::StackProtectStrong))
@@ -241,15 +244,21 @@ bool StackProtector::RequiresStackProtector() {
// A call to alloca with size >= SSPBufferSize requires
// stack protectors.
Layout.insert(std::make_pair(AI, SSPLK_LargeArray));
+ F->getContext().diagnose(
+ DiagnosticInfoSSP(*F, DiagnosticInfoSSP::SSPReason::Alloca));
NeedsProtector = true;
} else if (Strong) {
// Require protectors for all alloca calls in strong mode.
Layout.insert(std::make_pair(AI, SSPLK_SmallArray));
+ F->getContext().diagnose(
+ DiagnosticInfoSSP(*F, DiagnosticInfoSSP::SSPReason::Alloca));
NeedsProtector = true;
}
} else {
// A call to alloca with a variable size requires protectors.
Layout.insert(std::make_pair(AI, SSPLK_LargeArray));
+ F->getContext().diagnose(
+ DiagnosticInfoSSP(*F, DiagnosticInfoSSP::SSPReason::Alloca));
NeedsProtector = true;
}
continue;
@@ -259,6 +268,8 @@ bool StackProtector::RequiresStackProtector() {
if (ContainsProtectableArray(AI->getAllocatedType(), IsLarge, Strong)) {
Layout.insert(std::make_pair(AI, IsLarge ? SSPLK_LargeArray
: SSPLK_SmallArray));
+ F->getContext().diagnose(DiagnosticInfoSSP(
+ *F, DiagnosticInfoSSP::SSPReason::BufferOrStruct));
NeedsProtector = true;
continue;
}
@@ -266,6 +277,8 @@ bool StackProtector::RequiresStackProtector() {
if (Strong && HasAddressTaken(AI)) {
++NumAddrTaken;
Layout.insert(std::make_pair(AI, SSPLK_AddrOf));
+ F->getContext().diagnose(DiagnosticInfoSSP(
+ *F, DiagnosticInfoSSP::SSPReason::AddressTaken));
NeedsProtector = true;
}
}
@@ -464,3 +477,30 @@ BasicBlock *StackProtector::CreateFailBB() {
bool StackProtector::shouldEmitSDCheck(const BasicBlock &BB) const {
return HasPrologue && !HasIRCheck && dyn_cast<ReturnInst>(BB.getTerminator());
}
+
+void DiagnosticInfoSSP::print(DiagnosticPrinter &DP) const {
+ std::string Str;
+ raw_string_ostream OS(Str);
+
+ StringRef ReasonStr;
+ switch (Reason())
+ {
+ case Alloca:
+ ReasonStr = "a call to alloca or use of a variable length array";
+ break;
+ case BufferOrStruct:
+ ReasonStr = "a stack allocated buffer or struct containing a buffer";
+ break;
+ case AddressTaken:
+ ReasonStr = "the address of a local variable being taken";
+ break;
+ case Attribute:
+ ReasonStr = "a function attribute or command-line switch";
+ break;
+ }
+
+ OS << getLocationStr() << ": SSP applied to function " << Func.getName()
+ << " due to " << ReasonStr << '\n';
+ OS.flush();
+ DP << Str;
+}
diff --git a/llvm/test/CodeGen/X86/stack-protector-remarks.ll b/llvm/test/CodeGen/X86/stack-protector-remarks.ll
new file mode 100644
index 00000000000..f02384a6daa
--- /dev/null
+++ b/llvm/test/CodeGen/X86/stack-protector-remarks.ll
@@ -0,0 +1,87 @@
+; RUN: llc %s -o /dev/null 2>&1 | FileCheck %s
+; CHECK-NOT: nossp
+; CHECK-NOT: alloca_fixed_small_nossp
+; CHECK: function attribute_ssp
+; CHECK-SAME: a function attribute or command-line switch
+; CHECK: function alloca_fixed_small_ssp
+; CHECK-SAME: a call to alloca or use of a variable length array
+; CHECK: function alloca_fixed_large_ssp
+; CHECK-SAME: a call to alloca or use of a variable length array
+; CHECK: function alloca_variable_ssp
+; CHECK-SAME: a call to alloca or use of a variable length array
+; CHECK: function buffer_ssp
+; CHECK-SAME: a stack allocated buffer or struct containing a buffer
+; CHECK: function struct_ssp
+; CHECK-SAME: a stack allocated buffer or struct containing a buffer
+; CHECK: function address_ssp
+; CHECK-SAME: the address of a local variable being taken
+; CHECK: function multiple_ssp
+; CHECK-SAME: a function attribute or command-line switch
+; CHECK: function multiple_ssp
+; CHECK-SAME: a stack allocated buffer or struct containing a buffer
+; CHECK: function multiple_ssp
+; CHECK-SAME: a stack allocated buffer or struct containing a buffer
+; CHECK: function multiple_ssp
+; CHECK-SAME: the address of a local variable being taken
+; CHECK: function multiple_ssp
+; CHECK-SAME: a call to alloca or use of a variable length array
+
+define void @nossp() sspstrong {
+ ret void
+}
+
+define void @attribute_ssp() sspreq {
+ ret void
+}
+
+define void @alloca_fixed_small_nossp() ssp {
+ %1 = alloca i8, i64 2, align 16
+ ret void
+}
+
+define void @alloca_fixed_small_ssp() sspstrong {
+ %1 = alloca i8, i64 2, align 16
+ ret void
+}
+
+define void @alloca_fixed_large_ssp() ssp {
+ %1 = alloca i8, i64 64, align 16
+ ret void
+}
+
+define void @alloca_variable_ssp(i64 %x) ssp {
+ %1 = alloca i8, i64 %x, align 16
+ ret void
+}
+
+define void @buffer_ssp() sspstrong {
+ %x = alloca [64 x i32], align 16
+ ret void
+}
+
+%struct.X = type { [64 x i32] }
+define void @struct_ssp() sspstrong {
+ %x = alloca %struct.X, align 4
+ ret void
+}
+
+define void @address_ssp() sspstrong {
+entry:
+ %x = alloca i32, align 4
+ %y = alloca i32*, align 8
+ store i32 32, i32* %x, align 4
+ store i32* %x, i32** %y, align 8
+ ret void
+}
+
+define void @multiple_ssp() sspreq {
+entry:
+ %x = alloca %struct.X, align 4
+ %y = alloca [64 x i32], align 16
+ %a = alloca i32, align 4
+ %b = alloca i32*, align 8
+ %0 = alloca i8, i64 2, align 16
+ store i32 32, i32* %a, align 4
+ store i32* %a, i32** %b, align 8
+ ret void
+}
OpenPOWER on IntegriCloud