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