1 //===--- llvm-isel-fuzzer.cpp - Fuzzer for instruction selection ----------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // Tool to fuzz instruction selection using libFuzzer. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/ADT/StringRef.h" 15 #include "llvm/Analysis/TargetLibraryInfo.h" 16 #include "llvm/Bitcode/BitcodeReader.h" 17 #include "llvm/Bitcode/BitcodeWriter.h" 18 #include "llvm/CodeGen/CommandFlags.h" 19 #include "llvm/FuzzMutate/FuzzerCLI.h" 20 #include "llvm/FuzzMutate/IRMutator.h" 21 #include "llvm/FuzzMutate/Operations.h" 22 #include "llvm/FuzzMutate/Random.h" 23 #include "llvm/IR/Constants.h" 24 #include "llvm/IR/LLVMContext.h" 25 #include "llvm/IR/LegacyPassManager.h" 26 #include "llvm/IR/Module.h" 27 #include "llvm/IR/Verifier.h" 28 #include "llvm/IRReader/IRReader.h" 29 #include "llvm/Support/DataTypes.h" 30 #include "llvm/Support/Debug.h" 31 #include "llvm/Support/SourceMgr.h" 32 #include "llvm/Support/TargetRegistry.h" 33 #include "llvm/Support/TargetSelect.h" 34 #include "llvm/Target/TargetMachine.h" 35 #include <random> 36 37 #define DEBUG_TYPE "isel-fuzzer" 38 39 using namespace llvm; 40 41 static cl::opt<char> 42 OptLevel("O", 43 cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] " 44 "(default = '-O2')"), 45 cl::Prefix, 46 cl::ZeroOrMore, 47 cl::init(' ')); 48 49 static cl::opt<std::string> 50 TargetTriple("mtriple", cl::desc("Override target triple for module")); 51 52 static std::unique_ptr<TargetMachine> TM; 53 static std::unique_ptr<IRMutator> Mutator; 54 55 std::unique_ptr<IRMutator> createISelMutator() { 56 std::vector<TypeGetter> Types{ 57 Type::getInt1Ty, Type::getInt8Ty, Type::getInt16Ty, Type::getInt32Ty, 58 Type::getInt64Ty, Type::getFloatTy, Type::getDoubleTy}; 59 60 std::vector<std::unique_ptr<IRMutationStrategy>> Strategies; 61 Strategies.emplace_back( 62 new InjectorIRStrategy(InjectorIRStrategy::getDefaultOps())); 63 Strategies.emplace_back(new InstDeleterIRStrategy()); 64 65 return llvm::make_unique<IRMutator>(std::move(Types), std::move(Strategies)); 66 } 67 68 extern "C" LLVM_ATTRIBUTE_USED size_t LLVMFuzzerCustomMutator( 69 uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed) { 70 LLVMContext Context; 71 std::unique_ptr<Module> M; 72 if (Size <= 1) 73 // We get bogus data given an empty corpus - just create a new module. 74 M.reset(new Module("M", Context)); 75 else 76 M = parseModule(Data, Size, Context); 77 78 Mutator->mutateModule(*M, Seed, Size, MaxSize); 79 80 return writeModule(*M, Data, MaxSize); 81 } 82 83 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 84 if (Size <= 1) 85 // We get bogus data given an empty corpus - ignore it. 86 return 0; 87 88 LLVMContext Context; 89 auto M = parseModule(Data, Size, Context); 90 if (!M || verifyModule(*M, &errs())) { 91 errs() << "error: input module is broken!\n"; 92 return 0; 93 } 94 95 // Set up the module to build for our target. 96 M->setTargetTriple(TM->getTargetTriple().normalize()); 97 M->setDataLayout(TM->createDataLayout()); 98 99 // Build up a PM to do instruction selection. 100 legacy::PassManager PM; 101 TargetLibraryInfoImpl TLII(TM->getTargetTriple()); 102 PM.add(new TargetLibraryInfoWrapperPass(TLII)); 103 raw_null_ostream OS; 104 TM->addPassesToEmitFile(PM, OS, TargetMachine::CGFT_Null); 105 PM.run(*M); 106 107 return 0; 108 } 109 110 static void handleLLVMFatalError(void *, const std::string &Message, bool) { 111 // TODO: Would it be better to call into the fuzzer internals directly? 112 dbgs() << "LLVM ERROR: " << Message << "\n" 113 << "Aborting to trigger fuzzer exit handling.\n"; 114 abort(); 115 } 116 117 extern "C" LLVM_ATTRIBUTE_USED int LLVMFuzzerInitialize(int *argc, 118 char ***argv) { 119 EnableDebugBuffering = true; 120 121 InitializeAllTargets(); 122 InitializeAllTargetMCs(); 123 InitializeAllAsmPrinters(); 124 InitializeAllAsmParsers(); 125 126 handleExecNameEncodedBEOpts(*argv[0]); 127 parseFuzzerCLOpts(*argc, *argv); 128 129 if (TargetTriple.empty()) { 130 errs() << *argv[0] << ": -mtriple must be specified\n"; 131 exit(1); 132 } 133 134 Triple TheTriple = Triple(Triple::normalize(TargetTriple)); 135 136 // Get the target specific parser. 137 std::string Error; 138 const Target *TheTarget = 139 TargetRegistry::lookupTarget(MArch, TheTriple, Error); 140 if (!TheTarget) { 141 errs() << argv[0] << ": " << Error; 142 return 1; 143 } 144 145 // Set up the pipeline like llc does. 146 std::string CPUStr = getCPUStr(), FeaturesStr = getFeaturesStr(); 147 148 CodeGenOpt::Level OLvl = CodeGenOpt::Default; 149 switch (OptLevel) { 150 default: 151 errs() << argv[0] << ": invalid optimization level.\n"; 152 return 1; 153 case ' ': break; 154 case '0': OLvl = CodeGenOpt::None; break; 155 case '1': OLvl = CodeGenOpt::Less; break; 156 case '2': OLvl = CodeGenOpt::Default; break; 157 case '3': OLvl = CodeGenOpt::Aggressive; break; 158 } 159 160 TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); 161 TM.reset(TheTarget->createTargetMachine(TheTriple.getTriple(), CPUStr, 162 FeaturesStr, Options, getRelocModel(), 163 getCodeModel(), OLvl)); 164 assert(TM && "Could not allocate target machine!"); 165 166 // Make sure we print the summary and the current unit when LLVM errors out. 167 install_fatal_error_handler(handleLLVMFatalError, nullptr); 168 169 // Finally, create our mutator. 170 Mutator = createISelMutator(); 171 return 0; 172 } 173