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