xref: /freebsd/contrib/llvm-project/llvm/lib/FuzzMutate/FuzzerCLI.cpp (revision e40139ff33b48b56a24c808b166b04b8ee6f5b21)
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