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.h" 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/MC/TargetRegistry.h" 28 #include "llvm/Support/CommandLine.h" 29 #include "llvm/Support/DataTypes.h" 30 #include "llvm/Support/Debug.h" 31 #include "llvm/Support/SourceMgr.h" 32 #include "llvm/Support/TargetSelect.h" 33 #include "llvm/Target/TargetMachine.h" 34 35 #define DEBUG_TYPE "isel-fuzzer" 36 37 using namespace llvm; 38 39 static codegen::RegisterCodeGenFlags CGF; 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, cl::init('2')); 46 47 static cl::opt<std::string> 48 TargetTriple("mtriple", cl::desc("Override target triple for module")); 49 50 static std::unique_ptr<TargetMachine> TM; 51 static std::unique_ptr<IRMutator> Mutator; 52 53 std::unique_ptr<IRMutator> createISelMutator() { 54 std::vector<TypeGetter> Types{ 55 Type::getInt1Ty, Type::getInt8Ty, Type::getInt16Ty, Type::getInt32Ty, 56 Type::getInt64Ty, Type::getFloatTy, Type::getDoubleTy}; 57 58 std::vector<std::unique_ptr<IRMutationStrategy>> Strategies; 59 Strategies.emplace_back( 60 new InjectorIRStrategy(InjectorIRStrategy::getDefaultOps())); 61 Strategies.emplace_back(new InstDeleterIRStrategy()); 62 63 return std::make_unique<IRMutator>(std::move(Types), std::move(Strategies)); 64 } 65 66 extern "C" LLVM_ATTRIBUTE_USED size_t LLVMFuzzerCustomMutator( 67 uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed) { 68 LLVMContext Context; 69 std::unique_ptr<Module> M; 70 if (Size <= 1) 71 // We get bogus data given an empty corpus - just create a new module. 72 M.reset(new Module("M", Context)); 73 else 74 M = parseModule(Data, Size, Context); 75 76 Mutator->mutateModule(*M, Seed, Size, MaxSize); 77 78 return writeModule(*M, Data, MaxSize); 79 } 80 81 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 82 if (Size <= 1) 83 // We get bogus data given an empty corpus - ignore it. 84 return 0; 85 86 LLVMContext Context; 87 auto M = parseAndVerify(Data, Size, Context); 88 if (!M) { 89 errs() << "error: input module is broken!\n"; 90 return 0; 91 } 92 93 // Set up the module to build for our target. 94 M->setTargetTriple(TM->getTargetTriple().normalize()); 95 M->setDataLayout(TM->createDataLayout()); 96 97 // Build up a PM to do instruction selection. 98 legacy::PassManager PM; 99 TargetLibraryInfoImpl TLII(TM->getTargetTriple()); 100 PM.add(new TargetLibraryInfoWrapperPass(TLII)); 101 raw_null_ostream OS; 102 TM->addPassesToEmitFile(PM, OS, nullptr, CGFT_Null); 103 PM.run(*M); 104 105 return 0; 106 } 107 108 static void handleLLVMFatalError(void *, const char *Message, bool) { 109 // TODO: Would it be better to call into the fuzzer internals directly? 110 dbgs() << "LLVM ERROR: " << Message << "\n" 111 << "Aborting to trigger fuzzer exit handling.\n"; 112 abort(); 113 } 114 115 extern "C" LLVM_ATTRIBUTE_USED int LLVMFuzzerInitialize(int *argc, 116 char ***argv) { 117 EnableDebugBuffering = true; 118 119 InitializeAllTargets(); 120 InitializeAllTargetMCs(); 121 InitializeAllAsmPrinters(); 122 InitializeAllAsmParsers(); 123 124 handleExecNameEncodedBEOpts(*argv[0]); 125 parseFuzzerCLOpts(*argc, *argv); 126 127 if (TargetTriple.empty()) { 128 errs() << *argv[0] << ": -mtriple must be specified\n"; 129 exit(1); 130 } 131 132 Triple TheTriple = Triple(Triple::normalize(TargetTriple)); 133 134 // Get the target specific parser. 135 std::string Error; 136 const Target *TheTarget = 137 TargetRegistry::lookupTarget(codegen::getMArch(), TheTriple, Error); 138 if (!TheTarget) { 139 errs() << argv[0] << ": " << Error; 140 return 1; 141 } 142 143 // Set up the pipeline like llc does. 144 std::string CPUStr = codegen::getCPUStr(), 145 FeaturesStr = codegen::getFeaturesStr(); 146 147 CodeGenOpt::Level OLvl; 148 if (auto Level = CodeGenOpt::parseLevel(OptLevel)) { 149 OLvl = *Level; 150 } else { 151 errs() << argv[0] << ": invalid optimization level.\n"; 152 return 1; 153 } 154 155 TargetOptions Options = codegen::InitTargetOptionsFromCodeGenFlags(TheTriple); 156 TM.reset(TheTarget->createTargetMachine( 157 TheTriple.getTriple(), CPUStr, FeaturesStr, Options, 158 codegen::getExplicitRelocModel(), codegen::getExplicitCodeModel(), OLvl)); 159 assert(TM && "Could not allocate target machine!"); 160 161 // Make sure we print the summary and the current unit when LLVM errors out. 162 install_fatal_error_handler(handleLLVMFatalError, nullptr); 163 164 // Finally, create our mutator. 165 Mutator = createISelMutator(); 166 return 0; 167 } 168