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,12 +1,20 @@ set(LLVM_LINK_COMPONENTS + CodeGen Core + ExecutionEngine IRReader MC + MCJIT + Object + RuntimeDyld + SelectionDAG Support - Analysis - ) + Target + TransformUtils + native +) -# Depend on LLVM IR intrinsic generation. +# Depend on LLVM IR instrinsic generation. set(handle_llvm_deps intrinsics_gen) if (CLANG_BUILT_STANDALONE) set(handle_llvm_deps) @@ -14,7 +22,7 @@ add_clang_library(clangHandleLLVM handle_llvm.cpp - + DEPENDS ${handle_llvm_deps} ) 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 an 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,39 @@ #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" using namespace llvm; +static cl::list +PassList(cl::desc("Optimizations available:")); + +// 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 +70,164 @@ } } -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); +// Helper function to call pass initialization functions +void InitEverything() { + PassRegistry &Registry = *PassRegistry::getPassRegistry(); + initializeCore(Registry); + initializeScalarOpts(Registry); + initializeVectorization(Registry); + initializeIPO(Registry); + initializeAnalysis(Registry); + initializeTransformUtils(Registry); + initializeInstCombine(Registry); + initializeAggressiveInstCombine(Registry); + initializeInstrumentation(Registry); + initializeTarget(Registry); +} + +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) { + // Verify that input is correct by adding a verifier pass + FPM.add(createVerifierPass()); + + // Create and initializa 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); +} + +// Mimics the opt tool to run an optimization pass over the provided IR +std::string OptLLVM(const std::string IR, CodeGenOpt::Level &OLvl) { + InitEverything(); + + // Mimic argc and argv and pass them to ParseCommandLineOptions to initilize + // PassList, ie which optimizations we want to run on the IR + // TODO: Find a better way of doing this + const char *args[2]; + std::string arg0 = "llvm-proto-fuzzer"; + std::string arg1 = "-loop-vectorize"; + args[0] = arg0.c_str(); + args[1] = arg1.c_str(); + cl::ParseCommandLineOptions(2, args); - // Set the Module to include the the IR code to be compiled + // 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"); + + Triple ModuleTriple(M->getTargetTriple()); + TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); + std::string CPUStr; + std::string FeaturesStr; + std::unique_ptr TM(nullptr); + setFunctionAttributes(CPUStr, FeaturesStr, *M); + + legacy::PassManager Passes; + TargetLibraryInfoImpl TLII(ModuleTriple); + Passes.add(new TargetLibraryInfoWrapperPass(TLII)); + Passes.add(createTargetTransformInfoWrapperPass(TargetIRAnalysis())); + + std::unique_ptr FPasses; + FPasses.reset(new legacy::FunctionPassManager(M.get())); + FPasses->add(createTargetTransformInfoWrapperPass(TargetIRAnalysis())); + + AddOptimizationPasses(Passes, *FPasses, 3, 0); + const PassInfo *PassInf = PassList[0]; + Pass *P = PassInf->getNormalCtor()(); + if (!P) + ErrorAndExit("Cannot create IR pass"); + Passes.add(P); + + FPasses->doInitialization(); + for (Function &F : *M) + FPasses->run(F); + FPasses->doFinalization(); + Passes.add(createVerifierPass()); + + // 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(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 Owner = parseIR(MemoryBufferRef(IR, "IR"), Err, + Context); + Module *M = Owner.get(); + 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(Owner)); + builder.setMArch(MArch); + builder.setMCPU(getCPUStr()); + builder.setMAttrs(getFeatureList()); + builder.setErrorStr(&ErrorMsg); + builder.setEngineKind(EngineKind::JIT); + builder.setUseOrcMCJITReplacement(false); + RTDyldMemoryManager *RTDyldMM = new SectionMemoryManager(); + builder.setMCJITMemoryManager( + std::unique_ptr(RTDyldMM)); + builder.setOptLevel(OLvl); + builder.setTargetOptions(InitTargetOptionsFromCodeGenFlags()); - TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); + std::unique_ptr EE(builder.create()); + if (!EE) + ErrorAndExit("Could not create execution engine"); - // 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); - } + Function *EntryFunc = M->getFunction("foo"); + if (!EntryFunc) + ErrorAndExit("Function not found in module"); - setFunctionAttributes(CPUStr, FeaturesStr, *M); + EE->finalizeObject(); + EE->runStaticConstructorsDestructors(false); + + typedef void (*func)(int*, int*, int*, int); + func f = (func) EE->getPointerToFunction(EntryFunc); + + static_cast(RTDyldMM)->invalidateInstructionCache(); + + // Define some dummy arrays to use an input for now + int a[] = {1}; + int b[] = {1}; + int c[] = {1}; - raw_null_ostream OS; - Target->addPassesToEmitFile(PM, OS, nullptr, TargetMachine::CGFT_ObjectFile, - false); - PM.run(*M); + (*f)(a, b, c, 1); +} +// 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) { + // Parse ExtraArgs to set the optimization level + CodeGenOpt::Level OLvl; + getOptLevel(ExtraArgs, OLvl); + + // First we optimize the IR by running a loop vectorizer pass + std::string OptIR = OptLLVM(IR, OLvl); + + CreateAndRunJITFun(OptIR, OLvl); + CreateAndRunJITFun(IR, CodeGenOpt::None); + return; } -