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/IRMutator.h" 20 #include "llvm/FuzzMutate/Operations.h" 21 #include "llvm/FuzzMutate/Random.h" 22 #include "llvm/IR/Constants.h" 23 #include "llvm/IR/LLVMContext.h" 24 #include "llvm/IR/LegacyPassManager.h" 25 #include "llvm/IR/Module.h" 26 #include "llvm/IR/Verifier.h" 27 #include "llvm/IRReader/IRReader.h" 28 #include "llvm/Support/DataTypes.h" 29 #include "llvm/Support/Debug.h" 30 #include "llvm/Support/SourceMgr.h" 31 #include "llvm/Support/TargetRegistry.h" 32 #include "llvm/Support/TargetSelect.h" 33 #include "llvm/Target/TargetMachine.h" 34 #include <random> 35 36 #define DEBUG_TYPE "isel-fuzzer" 37 38 using namespace llvm; 39 40 static cl::opt<char> 41 OptLevel("O", 42 cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] " 43 "(default = '-O2')"), 44 cl::Prefix, 45 cl::ZeroOrMore, 46 cl::init(' ')); 47 48 static cl::opt<std::string> 49 TargetTriple("mtriple", cl::desc("Override target triple for module")); 50 51 static std::unique_ptr<TargetMachine> TM; 52 static std::unique_ptr<IRMutator> Mutator; 53 54 static std::unique_ptr<Module> parseModule(const uint8_t *Data, size_t Size, 55 LLVMContext &Context) { 56 auto Buffer = MemoryBuffer::getMemBuffer( 57 StringRef(reinterpret_cast<const char *>(Data), Size), "Fuzzer input", 58 /*RequiresNullTerminator=*/false); 59 60 SMDiagnostic Err; 61 auto M = parseBitcodeFile(Buffer->getMemBufferRef(), Context); 62 if (Error E = M.takeError()) { 63 errs() << toString(std::move(E)) << "\n"; 64 return nullptr; 65 } 66 return std::move(M.get()); 67 } 68 69 static size_t writeModule(const Module &M, uint8_t *Dest, size_t MaxSize) { 70 std::string Buf; 71 { 72 raw_string_ostream OS(Buf); 73 WriteBitcodeToFile(&M, OS); 74 } 75 if (Buf.size() > MaxSize) 76 return 0; 77 memcpy(Dest, Buf.data(), Buf.size()); 78 return Buf.size(); 79 } 80 81 std::unique_ptr<IRMutator> createISelMutator() { 82 std::vector<TypeGetter> Types{ 83 Type::getInt1Ty, Type::getInt8Ty, Type::getInt16Ty, Type::getInt32Ty, 84 Type::getInt64Ty, Type::getFloatTy, Type::getDoubleTy}; 85 86 std::vector<std::unique_ptr<IRMutationStrategy>> Strategies; 87 Strategies.emplace_back( 88 new InjectorIRStrategy(InjectorIRStrategy::getDefaultOps())); 89 Strategies.emplace_back(new InstDeleterIRStrategy()); 90 91 return make_unique<IRMutator>(std::move(Types), std::move(Strategies)); 92 } 93 94 extern "C" LLVM_ATTRIBUTE_USED size_t LLVMFuzzerCustomMutator( 95 uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed) { 96 LLVMContext Context; 97 std::unique_ptr<Module> M; 98 if (Size <= 1) 99 // We get bogus data given an empty corpus - just create a new module. 100 M.reset(new Module("M", Context)); 101 else 102 M = parseModule(Data, Size, Context); 103 104 Mutator->mutateModule(*M, Seed, Size, MaxSize); 105 106 return writeModule(*M, Data, MaxSize); 107 } 108 109 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 110 if (Size <= 1) 111 // We get bogus data given an empty corpus - ignore it. 112 return 0; 113 114 LLVMContext Context; 115 auto M = parseModule(Data, Size, Context); 116 if (!M || verifyModule(*M, &errs())) { 117 errs() << "error: input module is broken!\n"; 118 return 1; 119 } 120 121 // Set up the module to build for our target. 122 M->setTargetTriple(TM->getTargetTriple().normalize()); 123 M->setDataLayout(TM->createDataLayout()); 124 125 // Build up a PM to do instruction selection. 126 legacy::PassManager PM; 127 TargetLibraryInfoImpl TLII(TM->getTargetTriple()); 128 PM.add(new TargetLibraryInfoWrapperPass(TLII)); 129 raw_null_ostream OS; 130 TM->addPassesToEmitFile(PM, OS, TargetMachine::CGFT_Null); 131 PM.run(*M); 132 133 return 0; 134 } 135 136 /// Parse command line options, but ignore anything before '--'. 137 static void parseCLOptsAfterDashDash(int argc, char *argv[]) { 138 std::vector<const char *> CLArgs; 139 CLArgs.push_back(argv[0]); 140 141 int I = 1; 142 while (I < argc) 143 if (StringRef(argv[I++]).equals("-ignore_remaining_args=1")) 144 break; 145 while (I < argc) 146 CLArgs.push_back(argv[I++]); 147 148 cl::ParseCommandLineOptions(CLArgs.size(), CLArgs.data()); 149 } 150 151 static void handleLLVMFatalError(void *, const std::string &Message, bool) { 152 // TODO: Would it be better to call into the fuzzer internals directly? 153 dbgs() << "LLVM ERROR: " << Message << "\n" 154 << "Aborting to trigger fuzzer exit handling.\n"; 155 abort(); 156 } 157 158 extern "C" LLVM_ATTRIBUTE_USED int LLVMFuzzerInitialize(int *argc, 159 char ***argv) { 160 EnableDebugBuffering = true; 161 162 InitializeAllTargets(); 163 InitializeAllTargetMCs(); 164 InitializeAllAsmPrinters(); 165 InitializeAllAsmParsers(); 166 167 parseCLOptsAfterDashDash(*argc, *argv); 168 169 if (TargetTriple.empty()) { 170 errs() << *argv[0] << ": -mtriple must be specified\n"; 171 return 1; 172 } 173 174 Triple TheTriple = Triple(Triple::normalize(TargetTriple)); 175 176 // Get the target specific parser. 177 std::string Error; 178 const Target *TheTarget = 179 TargetRegistry::lookupTarget(MArch, TheTriple, Error); 180 if (!TheTarget) { 181 errs() << argv[0] << ": " << Error; 182 return 1; 183 } 184 185 // Set up the pipeline like llc does. 186 std::string CPUStr = getCPUStr(), FeaturesStr = getFeaturesStr(); 187 188 CodeGenOpt::Level OLvl = CodeGenOpt::Default; 189 switch (OptLevel) { 190 default: 191 errs() << argv[0] << ": invalid optimization level.\n"; 192 return 1; 193 case ' ': break; 194 case '0': OLvl = CodeGenOpt::None; break; 195 case '1': OLvl = CodeGenOpt::Less; break; 196 case '2': OLvl = CodeGenOpt::Default; break; 197 case '3': OLvl = CodeGenOpt::Aggressive; break; 198 } 199 200 TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); 201 TM.reset(TheTarget->createTargetMachine(TheTriple.getTriple(), CPUStr, 202 FeaturesStr, Options, getRelocModel(), 203 getCodeModel(), OLvl)); 204 assert(TM && "Could not allocate target machine!"); 205 206 // Make sure we print the summary and the current unit when LLVM errors out. 207 install_fatal_error_handler(handleLLVMFatalError, nullptr); 208 209 // Finally, create our mutator. 210 Mutator = createISelMutator(); 211 return 0; 212 } 213