Summary: When building with libFuzzer, converting control flow to selects or obscuring the original operands of CMPs reduces the effectiveness of libFuzzer's heuristics. This patch provides an attribute to disable or modify certain optimizations for optimal fuzzing signal. Provides a less aggressive alternative to https://reviews.llvm.org/D44057. Reviewers: vitalybuka, davide, arsenm, hfinkel Reviewed By: vitalybuka Subscribers: junbuml, mehdi_amini, wdng, javed.absar, hiraditya, llvm-commits, kcc Differential Revision: https://reviews.llvm.org/D44232 llvm-svn: 328214
127 lines
4.5 KiB
C++
127 lines
4.5 KiB
C++
//===- ForceFunctionAttrs.cpp - Force function attrs for debugging --------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/Transforms/IPO/ForceFunctionAttrs.h"
|
|
#include "llvm/ADT/StringSwitch.h"
|
|
#include "llvm/IR/Function.h"
|
|
#include "llvm/IR/LLVMContext.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
using namespace llvm;
|
|
|
|
#define DEBUG_TYPE "forceattrs"
|
|
|
|
static cl::list<std::string>
|
|
ForceAttributes("force-attribute", cl::Hidden,
|
|
cl::desc("Add an attribute to a function. This should be a "
|
|
"pair of 'function-name:attribute-name', for "
|
|
"example -force-attribute=foo:noinline. This "
|
|
"option can be specified multiple times."));
|
|
|
|
static Attribute::AttrKind parseAttrKind(StringRef Kind) {
|
|
return StringSwitch<Attribute::AttrKind>(Kind)
|
|
.Case("alwaysinline", Attribute::AlwaysInline)
|
|
.Case("builtin", Attribute::Builtin)
|
|
.Case("cold", Attribute::Cold)
|
|
.Case("convergent", Attribute::Convergent)
|
|
.Case("inlinehint", Attribute::InlineHint)
|
|
.Case("jumptable", Attribute::JumpTable)
|
|
.Case("minsize", Attribute::MinSize)
|
|
.Case("naked", Attribute::Naked)
|
|
.Case("nobuiltin", Attribute::NoBuiltin)
|
|
.Case("noduplicate", Attribute::NoDuplicate)
|
|
.Case("noimplicitfloat", Attribute::NoImplicitFloat)
|
|
.Case("noinline", Attribute::NoInline)
|
|
.Case("nonlazybind", Attribute::NonLazyBind)
|
|
.Case("noredzone", Attribute::NoRedZone)
|
|
.Case("noreturn", Attribute::NoReturn)
|
|
.Case("nocf_check", Attribute::NoCfCheck)
|
|
.Case("norecurse", Attribute::NoRecurse)
|
|
.Case("nounwind", Attribute::NoUnwind)
|
|
.Case("optforfuzzing", Attribute::OptForFuzzing)
|
|
.Case("optnone", Attribute::OptimizeNone)
|
|
.Case("optsize", Attribute::OptimizeForSize)
|
|
.Case("readnone", Attribute::ReadNone)
|
|
.Case("readonly", Attribute::ReadOnly)
|
|
.Case("argmemonly", Attribute::ArgMemOnly)
|
|
.Case("returns_twice", Attribute::ReturnsTwice)
|
|
.Case("safestack", Attribute::SafeStack)
|
|
.Case("sanitize_address", Attribute::SanitizeAddress)
|
|
.Case("sanitize_hwaddress", Attribute::SanitizeHWAddress)
|
|
.Case("sanitize_memory", Attribute::SanitizeMemory)
|
|
.Case("sanitize_thread", Attribute::SanitizeThread)
|
|
.Case("ssp", Attribute::StackProtect)
|
|
.Case("sspreq", Attribute::StackProtectReq)
|
|
.Case("sspstrong", Attribute::StackProtectStrong)
|
|
.Case("strictfp", Attribute::StrictFP)
|
|
.Case("uwtable", Attribute::UWTable)
|
|
.Default(Attribute::None);
|
|
}
|
|
|
|
/// If F has any forced attributes given on the command line, add them.
|
|
static void addForcedAttributes(Function &F) {
|
|
for (auto &S : ForceAttributes) {
|
|
auto KV = StringRef(S).split(':');
|
|
if (KV.first != F.getName())
|
|
continue;
|
|
|
|
auto Kind = parseAttrKind(KV.second);
|
|
if (Kind == Attribute::None) {
|
|
DEBUG(dbgs() << "ForcedAttribute: " << KV.second
|
|
<< " unknown or not handled!\n");
|
|
continue;
|
|
}
|
|
if (F.hasFnAttribute(Kind))
|
|
continue;
|
|
F.addFnAttr(Kind);
|
|
}
|
|
}
|
|
|
|
PreservedAnalyses ForceFunctionAttrsPass::run(Module &M,
|
|
ModuleAnalysisManager &) {
|
|
if (ForceAttributes.empty())
|
|
return PreservedAnalyses::all();
|
|
|
|
for (Function &F : M.functions())
|
|
addForcedAttributes(F);
|
|
|
|
// Just conservatively invalidate analyses, this isn't likely to be important.
|
|
return PreservedAnalyses::none();
|
|
}
|
|
|
|
namespace {
|
|
struct ForceFunctionAttrsLegacyPass : public ModulePass {
|
|
static char ID; // Pass identification, replacement for typeid
|
|
ForceFunctionAttrsLegacyPass() : ModulePass(ID) {
|
|
initializeForceFunctionAttrsLegacyPassPass(
|
|
*PassRegistry::getPassRegistry());
|
|
}
|
|
|
|
bool runOnModule(Module &M) override {
|
|
if (ForceAttributes.empty())
|
|
return false;
|
|
|
|
for (Function &F : M.functions())
|
|
addForcedAttributes(F);
|
|
|
|
// Conservatively assume we changed something.
|
|
return true;
|
|
}
|
|
};
|
|
}
|
|
|
|
char ForceFunctionAttrsLegacyPass::ID = 0;
|
|
INITIALIZE_PASS(ForceFunctionAttrsLegacyPass, "forceattrs",
|
|
"Force set function attributes", false, false)
|
|
|
|
Pass *llvm::createForceFunctionAttrsLegacyPass() {
|
|
return new ForceFunctionAttrsLegacyPass();
|
|
}
|