Index: clang/tools/clang-fuzzer/fuzzer-initialize/fuzzer_initialize.cpp =================================================================== --- clang/tools/clang-fuzzer/fuzzer-initialize/fuzzer_initialize.cpp +++ clang/tools/clang-fuzzer/fuzzer-initialize/fuzzer_initialize.cpp @@ -16,10 +16,13 @@ #include "fuzzer_initialize.h" +#include "llvm/InitializePasses.h" +#include "llvm/PassRegistry.h" #include "llvm/Support/TargetSelect.h" #include using namespace clang_fuzzer; +using namespace llvm; namespace clang_fuzzer { @@ -33,10 +36,22 @@ } extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) { - llvm::InitializeAllTargets(); - llvm::InitializeAllTargetMCs(); - llvm::InitializeAllAsmPrinters(); - llvm::InitializeAllAsmParsers(); + InitializeAllTargets(); + InitializeAllTargetMCs(); + InitializeAllAsmPrinters(); + InitializeAllAsmParsers(); + + PassRegistry &Registry = *PassRegistry::getPassRegistry(); + initializeCore(Registry); + initializeScalarOpts(Registry); + initializeVectorization(Registry); + initializeIPO(Registry); + initializeAnalysis(Registry); + initializeTransformUtils(Registry); + initializeInstCombine(Registry); + initializeAggressiveInstCombine(Registry); + initializeInstrumentation(Registry); + initializeTarget(Registry); CLArgs.push_back("-O2"); for (int I = 1; I < *argc; I++) { Index: clang/tools/clang-fuzzer/handle-llvm/CMakeLists.txt =================================================================== --- clang/tools/clang-fuzzer/handle-llvm/CMakeLists.txt +++ clang/tools/clang-fuzzer/handle-llvm/CMakeLists.txt @@ -1,10 +1,18 @@ set(LLVM_LINK_COMPONENTS + CodeGen Core + ExecutionEngine IRReader MC + MCJIT + Object + RuntimeDyld + SelectionDAG Support - Analysis - ) + Target + TransformUtils + native +) # Depend on LLVM IR intrinsic generation. set(handle_llvm_deps intrinsics_gen) Index: clang/tools/clang-fuzzer/handle-llvm/handle_llvm.cpp =================================================================== --- clang/tools/clang-fuzzer/handle-llvm/handle_llvm.cpp +++ clang/tools/clang-fuzzer/handle-llvm/handle_llvm.cpp @@ -7,8 +7,10 @@ // //===----------------------------------------------------------------------===// // -// Implements HandleLLVM for use by the Clang fuzzers. Mimics the llc tool to -// compile an LLVM IR file to X86_64 assembly. +// Implements HandleLLVM for use by the Clang fuzzers. First runs a loop +// vectorizer optimization pass over the given IR code. Then mimics lli on both +// versions to JIT the generated code and execute it. Currently, functions are +// executed on dummy inputs. // //===----------------------------------------------------------------------===// @@ -16,24 +18,37 @@ #include "llvm/ADT/Triple.h" #include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/CodeGen/CommandFlags.inc" #include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/TargetPassConfig.h" +#include "llvm/ExecutionEngine/JITEventListener.h" +#include "llvm/ExecutionEngine/JITSymbol.h" +#include "llvm/ExecutionEngine/MCJIT.h" +#include "llvm/ExecutionEngine/ObjectCache.h" +#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" +#include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/LegacyPassNameParser.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/Verifier.h" #include "llvm/IRReader/IRReader.h" +#include "llvm/Pass.h" #include "llvm/PassRegistry.h" -#include "llvm/Support/InitLLVM.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" #include "llvm/Target/TargetMachine.h" - -#include +#include "llvm/Transforms/IPO/PassManagerBuilder.h" +#include "llvm/Transforms/IPO.h" +#include "llvm/Transforms/Vectorize.h" using namespace llvm; +// Helper function to parse command line args and find the optimization level static void getOptLevel(const std::vector &ExtraArgs, CodeGenOpt::Level &OLvl) { // Find the optimization level from the command line args @@ -53,59 +68,123 @@ } } -void clang_fuzzer::HandleLLVM(const std::string &S, - const std::vector &ExtraArgs) { - // Parse ExtraArgs to set the optimization level - CodeGenOpt::Level OLvl; - getOptLevel(ExtraArgs, OLvl); +void ErrorAndExit(std::string message) { + errs()<< "ERROR: " << message << "\n"; + std::exit(1); +} + +// Helper function to add optimization passes to the TargetMachine at the +// specified optimization level, OptLevel +static void AddOptimizationPasses(legacy::PassManagerBase &MPM, + legacy::FunctionPassManager &FPM, + unsigned OptLevel, unsigned SizeLevel) { + // Create and initialize a PassManagerBuilder + PassManagerBuilder Builder; + Builder.OptLevel = OptLevel; + Builder.SizeLevel = SizeLevel; + Builder.Inliner = createFunctionInliningPass(OptLevel, SizeLevel, false); + Builder.LoopVectorize = true; + Builder.populateFunctionPassManager(FPM); + Builder.populateModulePassManager(MPM); +} - // Set the Module to include the the IR code to be compiled +// Mimics the opt tool to run an optimization pass over the provided IR +std::string OptLLVM(const std::string &IR) { + // Create a module that will run the optimization passes SMDiagnostic Err; + LLVMContext Context; + std::unique_ptr M = parseIR(MemoryBufferRef(IR, "IR"), Err, Context); + if (!M || verifyModule(*M, &errs())) + ErrorAndExit("Could not parse IR"); + + setFunctionAttributes(getCPUStr(), getFeaturesStr(), *M); + + legacy::PassManager Passes; + Triple ModuleTriple(M->getTargetTriple()); + + Passes.add(new TargetLibraryInfoWrapperPass(ModuleTriple)); + Passes.add(createTargetTransformInfoWrapperPass(TargetIRAnalysis())); + Passes.add(createVerifierPass()); + + std::unique_ptr FPasses = + make_unique(M.get()); + FPasses->add(createTargetTransformInfoWrapperPass(TargetIRAnalysis())); + FPasses->add(createVerifierPass()); + + AddOptimizationPasses(Passes, *FPasses, 3, 0); + + FPasses->doInitialization(); + for (Function &F : *M) + FPasses->run(F); + FPasses->doFinalization(); + + // Add a pass that writes the optimized IR to an output stream + std::string outString; + raw_string_ostream OS(outString); + Passes.add(createPrintModulePass(OS, "", false)); + + Passes.run(*M); + + return OS.str(); +} +void CreateAndRunJITFun(const std::string &IR, CodeGenOpt::Level OLvl) { + SMDiagnostic Err; LLVMContext Context; - std::unique_ptr M = parseIR(MemoryBufferRef(S, "IR"), Err, Context); - if (!M) { - errs() << "error: could not parse IR!\n"; - std::exit(1); - } + std::unique_ptr M = parseIR(MemoryBufferRef(IR, "IR"), Err, + Context); + if (!M) + ErrorAndExit("Could not parse IR"); - // Create a new Target - std::string Error; - const Target *TheTarget = TargetRegistry::lookupTarget( - sys::getDefaultTargetTriple(), Error); - if (!TheTarget) { - errs() << Error; - std::exit(1); - } + std::string ErrorMsg; + EngineBuilder builder(std::move(M)); + builder.setMArch(MArch); + builder.setMCPU(getCPUStr()); + builder.setMAttrs(getFeatureList()); + builder.setErrorStr(&ErrorMsg); + builder.setEngineKind(EngineKind::JIT); + builder.setUseOrcMCJITReplacement(false); + builder.setMCJITMemoryManager(make_unique()); + builder.setOptLevel(OLvl); + builder.setTargetOptions(InitTargetOptionsFromCodeGenFlags()); + + std::unique_ptr EE(builder.create()); + if (!EE) + ErrorAndExit("Could not create execution engine"); - TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); - - // Create a new Machine - std::string CPUStr = getCPUStr(); - std::string FeaturesStr = getFeaturesStr(); - std::unique_ptr Target(TheTarget->createTargetMachine( - sys::getDefaultTargetTriple(), CPUStr, FeaturesStr, Options, - getRelocModel(), getCodeModel(), OLvl)); - - // Create a new PassManager - legacy::PassManager PM; - TargetLibraryInfoImpl TLII(Triple(M->getTargetTriple())); - PM.add(new TargetLibraryInfoWrapperPass(TLII)); - M->setDataLayout(Target->createDataLayout()); - - // Make sure the Module has no errors - if (verifyModule(*M, &errs())) { - errs() << "error: input module is broken!\n"; - std::exit(1); - } - - setFunctionAttributes(CPUStr, FeaturesStr, *M); + EE->finalizeObject(); + EE->runStaticConstructorsDestructors(false); + + Function *EntryFunc = M->getFunction("foo"); + if (!EntryFunc) + ErrorAndExit("Function not found in module"); + + typedef void (*func)(int*, int*, int*, int); + func f = (func) EE->getPointerToFunction(EntryFunc); + + // Define some dummy arrays to use an input for now + int a[] = {1}; + int b[] = {1}; + int c[] = {1}; + + f(a, b, c, 1); - raw_null_ostream OS; - Target->addPassesToEmitFile(PM, OS, nullptr, TargetMachine::CGFT_ObjectFile, - false); - PM.run(*M); + EE->runStaticConstructorsDestructors(true); +} + +// Main fuzz target called by ExampleClangLLVMProtoFuzzer.cpp +// Mimics the lli tool to JIT the LLVM IR code and execute it +void clang_fuzzer::HandleLLVM(const std::string &IR, + const std::vector &ExtraArgs) { + // First we optimize the IR by running a loop vectorizer pass + std::string OptIR = OptLLVM(IR); + // Parse ExtraArgs to set the optimization level + CodeGenOpt::Level OLvl; + getOptLevel(ExtraArgs, OLvl); + + CreateAndRunJITFun(OptIR, OLvl); + CreateAndRunJITFun(IR, CodeGenOpt::None); + return; } -