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
parseFuzzerCLOpts(int ArgC,char * ArgV[])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
handleExecNameEncodedBEOpts(StringRef ExecName)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
handleExecNameEncodedOptimizerOpts(StringRef ExecName)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
runFuzzerOnInputs(int ArgC,char * ArgV[],FuzzerTestFun TestOne,FuzzerInitFun Init)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
parseModule(const uint8_t * Data,size_t Size,LLVMContext & Context)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
writeModule(const Module & M,uint8_t * Dest,size_t MaxSize)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
parseAndVerify(const uint8_t * Data,size_t Size,LLVMContext & Context)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