emmettneyman updated this revision to Diff 156362.
emmettneyman added a comment.
- Switched to JIT for compilation and execution
Repository:
rC Clang
https://reviews.llvm.org/D49526
Files:
clang/tools/clang-fuzzer/CMakeLists.txt
clang/tools/clang-fuzzer/ExampleClangLLVMProtoFuzzer.cpp
clang/tools/clang-fuzzer/handle-llvm/CMakeLists.txt
clang/tools/clang-fuzzer/handle-llvm/fuzzer_initialize.cpp
clang/tools/clang-fuzzer/handle-llvm/fuzzer_initialize.h
clang/tools/clang-fuzzer/handle-llvm/handle_llvm.cpp
clang/tools/clang-fuzzer/handle-llvm/handle_llvm.h
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,33 +7,53 @@
//
//===----------------------------------------------------------------------===//
//
-// 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.
//
//===----------------------------------------------------------------------===//
#include "handle_llvm.h"
#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/GenericValue.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 <cstdlib>
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/Transforms/IPO.h"
using namespace llvm;
+static cl::list<const PassInfo*, bool, PassNameParser>
+PassList(cl::desc("Optimizations available:"));
+
+static std::string OptIR;
+
+// Helper function to parse command line args and find the optimization level
static void getOptLevel(const std::vector<const char *> &ExtraArgs,
CodeGenOpt::Level &OLvl) {
// Find the optimization level from the command line args
@@ -53,59 +73,221 @@
}
}
-void clang_fuzzer::HandleLLVM(const std::string &S,
- const std::vector<const char *> &ExtraArgs) {
+// 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);
+}
+
+// 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
+void 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
+ char *args[2];
+ char t[18] = "llvm-proto-fuzzer";
+ char s[16] = "-loop-vectorize";
+ args[0] = t;
+ args[1] = s;
+ cl::ParseCommandLineOptions(2, args, "");
+
+ // Create a module that will run the optimization passes
+ SMDiagnostic Err;
+ LLVMContext Context;
+ std::unique_ptr<Module> M = parseIR(MemoryBufferRef(IR, "IR"), Err, Context);
+ if (!M || verifyModule(*M, &errs())) {
+ errs() << "error: could not parse IR!\n";
+ std::exit(1);
+ }
+
+ Triple ModuleTriple(M->getTargetTriple());
+ TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
+ std::string CPUStr;
+ std::string FeaturesStr;
+ TargetMachine *Machine = nullptr;
+ std::unique_ptr<TargetMachine> TM(Machine);
+ setFunctionAttributes(CPUStr, FeaturesStr, *M);
+
+ legacy::PassManager Passes;
+ TargetLibraryInfoImpl TLII(ModuleTriple);
+ Passes.add(new TargetLibraryInfoWrapperPass(TLII));
+ Passes.add(createTargetTransformInfoWrapperPass(TargetIRAnalysis()));
+
+ std::unique_ptr<legacy::FunctionPassManager> FPasses;
+ FPasses.reset(new legacy::FunctionPassManager(M.get()));
+ FPasses->add(createTargetTransformInfoWrapperPass(TargetIRAnalysis()));
+
+ AddOptimizationPasses(Passes, *FPasses, 3, 0);
+ const PassInfo *PassInf = PassList[0];
+ Pass *P = nullptr;
+
+ if (PassInf->getNormalCtor())
+ P = PassInf->getNormalCtor()();
+ else {
+ errs() << "cannot create pass: " << PassInf->getPassName() << "\n";
+ std::exit(1);
+ }
+
+ if (P)
+ Passes.add(P);
+
+ if (FPasses) {
+ 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);
+
+ // Save the resulting IR to OptIR
+ OptIR = outString;
+}
+
+// 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<const char *> &ExtraArgs,
+ char *m1, char *m2) {
// Parse ExtraArgs to set the optimization level
CodeGenOpt::Level OLvl;
getOptLevel(ExtraArgs, OLvl);
+
+ // First we optimize the IR by running a loop vectorizer pass
+ OptLLVM(IR, OLvl);
- // Set the Module to include the the IR code to be compiled
+ // Create and initialize two modules, one for the optimized code and one
+ // for the unoptimized code
SMDiagnostic Err;
-
LLVMContext Context;
- std::unique_ptr<Module> M = parseIR(MemoryBufferRef(S, "IR"), Err, Context);
- if (!M) {
+ std::unique_ptr<Module> Owner1 = parseIR(MemoryBufferRef(OptIR, "IR"), Err,
+ Context);
+ std::unique_ptr<Module> Owner2 = parseIR(MemoryBufferRef(IR, "IR"), Err,
+ Context);
+ Module *M1 = Owner1.get();
+ Module *M2 = Owner2.get();
+ if (!M1 || !M2) {
errs() << "error: could not parse IR!\n";
std::exit(1);
}
- // Create a new Target
- std::string Error;
- const Target *TheTarget = TargetRegistry::lookupTarget(
- sys::getDefaultTargetTriple(), Error);
- if (!TheTarget) {
- errs() << Error;
+ // Create and initialize two EngineBuilders from the Modules made above
+ TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
+
+ std::string ErrorMsg1;
+ EngineBuilder builder1(std::move(Owner1));
+ builder1.setMArch(MArch);
+ builder1.setMCPU(getCPUStr());
+ builder1.setMAttrs(getFeatureList());
+ builder1.setErrorStr(&ErrorMsg1);
+ builder1.setEngineKind(EngineKind::JIT);
+ builder1.setUseOrcMCJITReplacement(false);
+ RTDyldMemoryManager *RTDyldMM1 = nullptr;
+ RTDyldMM1 = new SectionMemoryManager();
+ builder1.setMCJITMemoryManager(
+ std::unique_ptr<RTDyldMemoryManager>(RTDyldMM1));
+ builder1.setOptLevel(OLvl);
+ builder1.setTargetOptions(Options);
+
+ std::string ErrorMsg2;
+ EngineBuilder builder2(std::move(Owner2));
+ builder2.setMArch(MArch);
+ builder2.setMCPU(getCPUStr());
+ builder2.setMAttrs(getFeatureList());
+ builder2.setErrorStr(&ErrorMsg1);
+ builder2.setEngineKind(EngineKind::JIT);
+ builder2.setUseOrcMCJITReplacement(false);
+ RTDyldMemoryManager *RTDyldMM2 = nullptr;
+ RTDyldMM2 = new SectionMemoryManager();
+ builder2.setMCJITMemoryManager(
+ std::unique_ptr<RTDyldMemoryManager>(RTDyldMM2));
+ builder2.setOptLevel(CodeGenOpt::None);
+ builder2.setTargetOptions(Options);
+
+ std::unique_ptr<ExecutionEngine> EE1(builder1.create());
+ if (!EE1) {
+ if (!ErrorMsg1.empty())
+ errs() << "error creating EE1: " << ErrorMsg1 << "\n";
+ else
+ errs() << "unknown error creating EE1!\n";
std::exit(1);
}
- TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
+ std::unique_ptr<ExecutionEngine> EE2(builder2.create());
+ if (!EE2) {
+ if (!ErrorMsg2.empty())
+ errs() << "error creating EE2: " << ErrorMsg2 << "\n";
+ else
+ errs() << "unknown error creating EE2!\n";
+ std::exit(1);
+ }
- // Create a new Machine
- std::string CPUStr = getCPUStr();
- std::string FeaturesStr = getFeaturesStr();
- std::unique_ptr<TargetMachine> 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";
+ //Specify the functions we want to call from the IR
+ Function *EntryFunc1 = M1->getFunction("foo");
+ Function *EntryFunc2 = M2->getFunction("foo");
+ if (!EntryFunc1 || !EntryFunc2) {
+ errs() << '\'' << EntryFunc1 << "\' function not found in module.\n";
std::exit(1);
- }
+ }
- setFunctionAttributes(CPUStr, FeaturesStr, *M);
-
- raw_null_ostream OS;
- Target->addPassesToEmitFile(PM, OS, nullptr, TargetMachine::CGFT_ObjectFile,
- false);
- PM.run(*M);
+ typedef void (*func)(int*, int*, int*, int);
+ EE1->finalizeObject();
+ EE1->runStaticConstructorsDestructors(false);
+ func f1 = (func) EE1->getPointerToFunction(EntryFunc1);
+
+ EE2->finalizeObject();
+ EE2->runStaticConstructorsDestructors(false);
+ func f2 = (func) EE2->getPointerToFunction(EntryFunc2);
+
+ // Clear instruction cache before code will be executed.
+ if(RTDyldMM1)
+ static_cast<SectionMemoryManager*>(RTDyldMM1)->invalidateInstructionCache();
+ if(RTDyldMM2)
+ static_cast<SectionMemoryManager*>(RTDyldMM2)->invalidateInstructionCache();
+
+ // Define some dummy arrays to use an input for now
+ int a[] = {1};
+ int b[] = {1};
+ int c[] = {1};
+
+ (*f1)(a, b, c, 1);
+ (*f2)(a, b, c, 1);
+
return;
}
-
Index: clang/tools/clang-fuzzer/handle-llvm/handle_llvm.h
===================================================================
--- clang/tools/clang-fuzzer/handle-llvm/handle_llvm.h
+++ clang/tools/clang-fuzzer/handle-llvm/handle_llvm.h
@@ -19,7 +19,8 @@
namespace clang_fuzzer {
void HandleLLVM(const std::string &S,
- const std::vector<const char *> &ExtraArgs);
+ const std::vector<const char *> &ExtraArgs,
+ char *m1, char *m2);
} // namespace clang_fuzzer
#endif
Index: clang/tools/clang-fuzzer/handle-llvm/fuzzer_initialize.h
===================================================================
--- clang/tools/clang-fuzzer/handle-llvm/fuzzer_initialize.h
+++ clang/tools/clang-fuzzer/handle-llvm/fuzzer_initialize.h
@@ -1,25 +1,21 @@
-//==-- handle_llvm.h - Helper function for Clang fuzzers -------------------==//
+//==-- fuzzer_initialize.h - Fuzz Clang ------------------------------------==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
-// Defines HandleLLVM for use by the Clang fuzzers.
+// Defines a function that returns the command line arguments for a specific
+// call to the fuzz target.
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TOOLS_CLANG_FUZZER_HANDLE_LLVM_HANDLELLVM_H
-#define LLVM_CLANG_TOOLS_CLANG_FUZZER_HANDLE_LLVM_HANDLELLVM_H
-
-#include <string>
#include <vector>
namespace clang_fuzzer {
-void HandleLLVM(const std::string &S,
- const std::vector<const char *> &ExtraArgs);
-} // namespace clang_fuzzer
-
-#endif
+const std::vector<const char *>& GetCLArgs();
+char *GetRegion1();
+char *GetRegion2();
+}
Index: clang/tools/clang-fuzzer/handle-llvm/fuzzer_initialize.cpp
===================================================================
--- /dev/null
+++ clang/tools/clang-fuzzer/handle-llvm/fuzzer_initialize.cpp
@@ -0,0 +1,69 @@
+//===-- fuzzer_initialize.cpp - Fuzz Clang --------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file implements a few functions: one that returns the command line
+/// arguments for a given call to the fuzz target and one that initializes
+/// the fuzzer with the correct command line arguments. It also initializes two
+/// regions in memory for the fuzzer to use to insert and execute generated
+/// code. Getter methods for those two regions are also included.
+///
+//===----------------------------------------------------------------------===//
+
+#include "fuzzer_initialize.h"
+
+#include "llvm/Support/TargetSelect.h"
+#include <cstring>
+#include <sys/mman.h>
+
+using namespace clang_fuzzer;
+
+
+namespace clang_fuzzer {
+
+static std::vector<const char *> CLArgs;
+static char *m1;
+static char *m2;
+
+const std::vector<const char *>& GetCLArgs() {
+ return CLArgs;
+}
+
+char *GetRegion1() {
+ return m1;
+}
+
+char *GetRegion2() {
+ return m2;
+}
+
+}
+
+extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) {
+ llvm::InitializeAllTargets();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllAsmPrinters();
+ llvm::InitializeAllAsmParsers();
+
+ CLArgs.push_back("-O2");
+ for (int I = 1; I < *argc; I++) {
+ if (strcmp((*argv)[I], "-ignore_remaining_args=1") == 0) {
+ for (I++; I < *argc; I++)
+ CLArgs.push_back((*argv)[I]);
+ break;
+ }
+ }
+
+ m1 = (char *) mmap(NULL, 1000000, PROT_WRITE | PROT_EXEC,
+ MAP_SHARED | MAP_ANON, -1, 0);
+ m2 = (char *) mmap(NULL, 1000000, PROT_WRITE | PROT_EXEC,
+ MAP_SHARED | MAP_ANON, -1, 0);
+
+ return 0;
+}
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,5 +1,29 @@
-set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} Support)
+set(LLVM_LINK_COMPONENTS
+ CodeGen
+ Core
+ ExecutionEngine
+ IRReader
+ MC
+ MCJIT
+ Object
+ RuntimeDyld
+ SelectionDAG
+ Support
+ Target
+ TransformUtils
+ native
+)
+
+# Depend on LLVM IR instrinsic generation.
+set(handle_llvm_deps intrinsics_gen)
+if (CLANG_BUILT_STANDALONE)
+ set(handle_llvm_deps)
+endif()
add_clang_library(clangHandleLLVM
handle_llvm.cpp
+ fuzzer_initialize.cpp
+
+ DEPENDS
+ ${handle_llvm_deps}
)
Index: clang/tools/clang-fuzzer/ExampleClangLLVMProtoFuzzer.cpp
===================================================================
--- clang/tools/clang-fuzzer/ExampleClangLLVMProtoFuzzer.cpp
+++ clang/tools/clang-fuzzer/ExampleClangLLVMProtoFuzzer.cpp
@@ -15,14 +15,14 @@
//===----------------------------------------------------------------------===//
#include "cxx_loop_proto.pb.h"
-#include "fuzzer-initialize/fuzzer_initialize.h"
+#include "handle-llvm/fuzzer_initialize.h"
#include "handle-llvm/handle_llvm.h"
#include "proto-to-llvm/loop_proto_to_llvm.h"
#include "src/libfuzzer/libfuzzer_macro.h"
using namespace clang_fuzzer;
DEFINE_BINARY_PROTO_FUZZER(const LoopFunction &input) {
auto S = LoopFunctionToLLVMString(input);
- HandleLLVM(S, GetCLArgs());
+ HandleLLVM(S, GetCLArgs(), GetRegion1(), GetRegion2());
}
Index: clang/tools/clang-fuzzer/CMakeLists.txt
===================================================================
--- clang/tools/clang-fuzzer/CMakeLists.txt
+++ clang/tools/clang-fuzzer/CMakeLists.txt
@@ -79,19 +79,20 @@
${ProtobufMutator_LIBRARIES}
${PROTOBUF_LIBRARIES}
${LLVM_LIB_FUZZING_ENGINE}
- clangFuzzerInitialize
)
target_link_libraries(clang-proto-fuzzer
PRIVATE
${COMMON_PROTO_FUZZ_LIBRARIES}
+ clangFuzzerInitialize
clangHandleCXX
clangCXXProto
clangProtoToCXX
)
target_link_libraries(clang-loop-proto-fuzzer
PRIVATE
${COMMON_PROTO_FUZZ_LIBRARIES}
+ clangFuzzerInitialize
clangHandleCXX
clangCXXLoopProto
clangLoopProtoToCXX
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits