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