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