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/Support/CommandLine.h"
12 #include "llvm/Support/MemoryBuffer.h"
13 #include "llvm/Support/raw_ostream.h"
14 #include "llvm/TargetParser/Triple.h"
15 
16 using namespace llvm;
17 
18 void llvm::parseFuzzerCLOpts(int ArgC, char *ArgV[]) {
19   std::vector<const char *> CLArgs;
20   CLArgs.push_back(ArgV[0]);
21 
22   int I = 1;
23   while (I < ArgC)
24     if (StringRef(ArgV[I++]).equals("-ignore_remaining_args=1"))
25       break;
26   while (I < ArgC)
27     CLArgs.push_back(ArgV[I++]);
28 
29   cl::ParseCommandLineOptions(CLArgs.size(), CLArgs.data());
30 }
31 
32 void llvm::handleExecNameEncodedBEOpts(StringRef ExecName) {
33   std::vector<std::string> Args{std::string(ExecName)};
34 
35   auto NameAndArgs = ExecName.split("--");
36   if (NameAndArgs.second.empty())
37     return;
38 
39   SmallVector<StringRef, 4> Opts;
40   NameAndArgs.second.split(Opts, '-');
41   for (StringRef Opt : Opts) {
42     if (Opt.equals("gisel")) {
43       Args.push_back("-global-isel");
44       // For now we default GlobalISel to -O0
45       Args.push_back("-O0");
46     } else if (Opt.startswith("O")) {
47       Args.push_back("-" + Opt.str());
48     } else if (Triple(Opt).getArch()) {
49       Args.push_back("-mtriple=" + Opt.str());
50     } else {
51       errs() << ExecName << ": Unknown option: " << Opt << ".\n";
52       exit(1);
53     }
54   }
55   errs() << NameAndArgs.first << ": Injected args:";
56   for (int I = 1, E = Args.size(); I < E; ++I)
57     errs() << " " << Args[I];
58   errs() << "\n";
59 
60   std::vector<const char *> CLArgs;
61   CLArgs.reserve(Args.size());
62   for (std::string &S : Args)
63     CLArgs.push_back(S.c_str());
64 
65   cl::ParseCommandLineOptions(CLArgs.size(), CLArgs.data());
66 }
67 
68 void llvm::handleExecNameEncodedOptimizerOpts(StringRef ExecName) {
69   // TODO: Refactor parts common with the 'handleExecNameEncodedBEOpts'
70   std::vector<std::string> Args{std::string(ExecName)};
71 
72   auto NameAndArgs = ExecName.split("--");
73   if (NameAndArgs.second.empty())
74     return;
75 
76   SmallVector<StringRef, 4> Opts;
77   NameAndArgs.second.split(Opts, '-');
78   for (StringRef Opt : Opts) {
79     if (Opt == "instcombine") {
80       Args.push_back("-passes=instcombine");
81     } else if (Opt == "earlycse") {
82       Args.push_back("-passes=early-cse");
83     } else if (Opt == "simplifycfg") {
84       Args.push_back("-passes=simplifycfg");
85     } else if (Opt == "gvn") {
86       Args.push_back("-passes=gvn");
87     } else if (Opt == "sccp") {
88       Args.push_back("-passes=sccp");
89 
90     } else if (Opt == "loop_predication") {
91       Args.push_back("-passes=loop-predication");
92     } else if (Opt == "guard_widening") {
93       Args.push_back("-passes=guard-widening");
94     } else if (Opt == "loop_rotate") {
95       Args.push_back("-passes=loop(rotate)");
96     } else if (Opt == "loop_unswitch") {
97       Args.push_back("-passes=loop(simple-loop-unswitch)");
98     } else if (Opt == "loop_unroll") {
99       Args.push_back("-passes=unroll");
100     } else if (Opt == "loop_vectorize") {
101       Args.push_back("-passes=loop-vectorize");
102     } else if (Opt == "licm") {
103       Args.push_back("-passes=licm");
104     } else if (Opt == "indvars") {
105       Args.push_back("-passes=indvars");
106     } else if (Opt == "strength_reduce") {
107       Args.push_back("-passes=loop-reduce");
108     } else if (Opt == "irce") {
109       Args.push_back("-passes=irce");
110 
111     } else if (Triple(Opt).getArch()) {
112       Args.push_back("-mtriple=" + Opt.str());
113     } else {
114       errs() << ExecName << ": Unknown option: " << Opt << ".\n";
115       exit(1);
116     }
117   }
118 
119   errs() << NameAndArgs.first << ": Injected args:";
120   for (int I = 1, E = Args.size(); I < E; ++I)
121     errs() << " " << Args[I];
122   errs() << "\n";
123 
124   std::vector<const char *> CLArgs;
125   CLArgs.reserve(Args.size());
126   for (std::string &S : Args)
127     CLArgs.push_back(S.c_str());
128 
129   cl::ParseCommandLineOptions(CLArgs.size(), CLArgs.data());
130 }
131 
132 int llvm::runFuzzerOnInputs(int ArgC, char *ArgV[], FuzzerTestFun TestOne,
133                             FuzzerInitFun Init) {
134   errs() << "*** This tool was not linked to libFuzzer.\n"
135          << "*** No fuzzing will be performed.\n";
136   if (int RC = Init(&ArgC, &ArgV)) {
137     errs() << "Initialization failed\n";
138     return RC;
139   }
140 
141   for (int I = 1; I < ArgC; ++I) {
142     StringRef Arg(ArgV[I]);
143     if (Arg.startswith("-")) {
144       if (Arg.equals("-ignore_remaining_args=1"))
145         break;
146       continue;
147     }
148 
149     auto BufOrErr = MemoryBuffer::getFile(Arg, /*IsText=*/false,
150                                           /*RequiresNullTerminator=*/false);
151     if (std::error_code EC = BufOrErr.getError()) {
152       errs() << "Error reading file: " << Arg << ": " << EC.message() << "\n";
153       return 1;
154     }
155     std::unique_ptr<MemoryBuffer> Buf = std::move(BufOrErr.get());
156     errs() << "Running: " << Arg << " (" << Buf->getBufferSize() << " bytes)\n";
157     TestOne(reinterpret_cast<const uint8_t *>(Buf->getBufferStart()),
158             Buf->getBufferSize());
159   }
160   return 0;
161 }
162