1 //===-- FuzzerCLI.cpp -----------------------------------------------------===// 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 #include "llvm/FuzzMutate/FuzzerCLI.h" 10 #include "llvm/ADT/Triple.h" 11 #include "llvm/Bitcode/BitcodeReader.h" 12 #include "llvm/Bitcode/BitcodeWriter.h" 13 #include "llvm/IR/LLVMContext.h" 14 #include "llvm/Support/CommandLine.h" 15 #include "llvm/Support/Compiler.h" 16 #include "llvm/Support/Error.h" 17 #include "llvm/Support/MemoryBuffer.h" 18 #include "llvm/Support/SourceMgr.h" 19 #include "llvm/Support/raw_ostream.h" 20 #include "llvm/IR/Verifier.h" 21 22 using namespace llvm; 23 24 void llvm::parseFuzzerCLOpts(int ArgC, char *ArgV[]) { 25 std::vector<const char *> CLArgs; 26 CLArgs.push_back(ArgV[0]); 27 28 int I = 1; 29 while (I < ArgC) 30 if (StringRef(ArgV[I++]).equals("-ignore_remaining_args=1")) 31 break; 32 while (I < ArgC) 33 CLArgs.push_back(ArgV[I++]); 34 35 cl::ParseCommandLineOptions(CLArgs.size(), CLArgs.data()); 36 } 37 38 void llvm::handleExecNameEncodedBEOpts(StringRef ExecName) { 39 std::vector<std::string> Args{ExecName}; 40 41 auto NameAndArgs = ExecName.split("--"); 42 if (NameAndArgs.second.empty()) 43 return; 44 45 SmallVector<StringRef, 4> Opts; 46 NameAndArgs.second.split(Opts, '-'); 47 for (StringRef Opt : Opts) { 48 if (Opt.equals("gisel")) { 49 Args.push_back("-global-isel"); 50 // For now we default GlobalISel to -O0 51 Args.push_back("-O0"); 52 } else if (Opt.startswith("O")) { 53 Args.push_back("-" + Opt.str()); 54 } else if (Triple(Opt).getArch()) { 55 Args.push_back("-mtriple=" + Opt.str()); 56 } else { 57 errs() << ExecName << ": Unknown option: " << Opt << ".\n"; 58 exit(1); 59 } 60 } 61 errs() << NameAndArgs.first << ": Injected args:"; 62 for (int I = 1, E = Args.size(); I < E; ++I) 63 errs() << " " << Args[I]; 64 errs() << "\n"; 65 66 std::vector<const char *> CLArgs; 67 CLArgs.reserve(Args.size()); 68 for (std::string &S : Args) 69 CLArgs.push_back(S.c_str()); 70 71 cl::ParseCommandLineOptions(CLArgs.size(), CLArgs.data()); 72 } 73 74 void llvm::handleExecNameEncodedOptimizerOpts(StringRef ExecName) { 75 // TODO: Refactor parts common with the 'handleExecNameEncodedBEOpts' 76 std::vector<std::string> Args{ExecName}; 77 78 auto NameAndArgs = ExecName.split("--"); 79 if (NameAndArgs.second.empty()) 80 return; 81 82 SmallVector<StringRef, 4> Opts; 83 NameAndArgs.second.split(Opts, '-'); 84 for (StringRef Opt : Opts) { 85 if (Opt == "instcombine") { 86 Args.push_back("-passes=instcombine"); 87 } else if (Opt == "earlycse") { 88 Args.push_back("-passes=early-cse"); 89 } else if (Opt == "simplifycfg") { 90 Args.push_back("-passes=simplify-cfg"); 91 } else if (Opt == "gvn") { 92 Args.push_back("-passes=gvn"); 93 } else if (Opt == "sccp") { 94 Args.push_back("-passes=sccp"); 95 96 } else if (Opt == "loop_predication") { 97 Args.push_back("-passes=loop-predication"); 98 } else if (Opt == "guard_widening") { 99 Args.push_back("-passes=guard-widening"); 100 } else if (Opt == "loop_rotate") { 101 Args.push_back("-passes=loop(rotate)"); 102 } else if (Opt == "loop_unswitch") { 103 Args.push_back("-passes=loop(unswitch)"); 104 } else if (Opt == "loop_unroll") { 105 Args.push_back("-passes=unroll"); 106 } else if (Opt == "loop_vectorize") { 107 Args.push_back("-passes=loop-vectorize"); 108 } else if (Opt == "licm") { 109 Args.push_back("-passes=licm"); 110 } else if (Opt == "indvars") { 111 Args.push_back("-passes=indvars"); 112 } else if (Opt == "strength_reduce") { 113 Args.push_back("-passes=strength-reduce"); 114 } else if (Opt == "irce") { 115 Args.push_back("-passes=irce"); 116 117 } else if (Triple(Opt).getArch()) { 118 Args.push_back("-mtriple=" + Opt.str()); 119 } else { 120 errs() << ExecName << ": Unknown option: " << Opt << ".\n"; 121 exit(1); 122 } 123 } 124 125 errs() << NameAndArgs.first << ": Injected args:"; 126 for (int I = 1, E = Args.size(); I < E; ++I) 127 errs() << " " << Args[I]; 128 errs() << "\n"; 129 130 std::vector<const char *> CLArgs; 131 CLArgs.reserve(Args.size()); 132 for (std::string &S : Args) 133 CLArgs.push_back(S.c_str()); 134 135 cl::ParseCommandLineOptions(CLArgs.size(), CLArgs.data()); 136 } 137 138 int llvm::runFuzzerOnInputs(int ArgC, char *ArgV[], FuzzerTestFun TestOne, 139 FuzzerInitFun Init) { 140 errs() << "*** This tool was not linked to libFuzzer.\n" 141 << "*** No fuzzing will be performed.\n"; 142 if (int RC = Init(&ArgC, &ArgV)) { 143 errs() << "Initialization failed\n"; 144 return RC; 145 } 146 147 for (int I = 1; I < ArgC; ++I) { 148 StringRef Arg(ArgV[I]); 149 if (Arg.startswith("-")) { 150 if (Arg.equals("-ignore_remaining_args=1")) 151 break; 152 continue; 153 } 154 155 auto BufOrErr = MemoryBuffer::getFile(Arg, /*FileSize-*/ -1, 156 /*RequiresNullTerminator=*/false); 157 if (std::error_code EC = BufOrErr.getError()) { 158 errs() << "Error reading file: " << Arg << ": " << EC.message() << "\n"; 159 return 1; 160 } 161 std::unique_ptr<MemoryBuffer> Buf = std::move(BufOrErr.get()); 162 errs() << "Running: " << Arg << " (" << Buf->getBufferSize() << " bytes)\n"; 163 TestOne(reinterpret_cast<const uint8_t *>(Buf->getBufferStart()), 164 Buf->getBufferSize()); 165 } 166 return 0; 167 } 168 169 std::unique_ptr<Module> llvm::parseModule( 170 const uint8_t *Data, size_t Size, LLVMContext &Context) { 171 172 if (Size <= 1) 173 // We get bogus data given an empty corpus - just create a new module. 174 return std::make_unique<Module>("M", Context); 175 176 auto Buffer = MemoryBuffer::getMemBuffer( 177 StringRef(reinterpret_cast<const char *>(Data), Size), "Fuzzer input", 178 /*RequiresNullTerminator=*/false); 179 180 SMDiagnostic Err; 181 auto M = parseBitcodeFile(Buffer->getMemBufferRef(), Context); 182 if (Error E = M.takeError()) { 183 errs() << toString(std::move(E)) << "\n"; 184 return nullptr; 185 } 186 return std::move(M.get()); 187 } 188 189 size_t llvm::writeModule(const Module &M, uint8_t *Dest, size_t MaxSize) { 190 std::string Buf; 191 { 192 raw_string_ostream OS(Buf); 193 WriteBitcodeToFile(M, OS); 194 } 195 if (Buf.size() > MaxSize) 196 return 0; 197 memcpy(Dest, Buf.data(), Buf.size()); 198 return Buf.size(); 199 } 200 201 std::unique_ptr<Module> llvm::parseAndVerify(const uint8_t *Data, size_t Size, 202 LLVMContext &Context) { 203 auto M = parseModule(Data, Size, Context); 204 if (!M || verifyModule(*M, &errs())) 205 return nullptr; 206 207 return M; 208 } 209