1 //===-- FuzzerCLI.cpp -----------------------------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "llvm/FuzzMutate/FuzzerCLI.h"
11 #include "llvm/ADT/Triple.h"
12 #include "llvm/Bitcode/BitcodeReader.h"
13 #include "llvm/Bitcode/BitcodeWriter.h"
14 #include "llvm/IR/LLVMContext.h"
15 #include "llvm/Support/CommandLine.h"
16 #include "llvm/Support/Compiler.h"
17 #include "llvm/Support/Error.h"
18 #include "llvm/Support/MemoryBuffer.h"
19 #include "llvm/Support/SourceMgr.h"
20 #include "llvm/Support/raw_ostream.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.startswith("instcombine")) {
86       Args.push_back("-passes=instcombine");
87     } else if (Opt.startswith("earlycse")) {
88       Args.push_back("-passes=early-cse");
89     } else if (Opt.startswith("simplifycfg")) {
90       Args.push_back("-passes=simplify-cfg");
91     } else if (Opt.startswith("gvn")) {
92       Args.push_back("-passes=gvn");
93     } else if (Opt.startswith("sccp")) {
94       Args.push_back("-passes=sccp");
95     } else if (Triple(Opt).getArch()) {
96       Args.push_back("-mtriple=" + Opt.str());
97     } else {
98       errs() << ExecName << ": Unknown option: " << Opt << ".\n";
99       exit(1);
100     }
101   }
102 
103   errs() << NameAndArgs.first << ": Injected args:";
104   for (int I = 1, E = Args.size(); I < E; ++I)
105     errs() << " " << Args[I];
106   errs() << "\n";
107 
108   std::vector<const char *> CLArgs;
109   CLArgs.reserve(Args.size());
110   for (std::string &S : Args)
111     CLArgs.push_back(S.c_str());
112 
113   cl::ParseCommandLineOptions(CLArgs.size(), CLArgs.data());
114 }
115 
116 int llvm::runFuzzerOnInputs(int ArgC, char *ArgV[], FuzzerTestFun TestOne,
117                             FuzzerInitFun Init) {
118   errs() << "*** This tool was not linked to libFuzzer.\n"
119          << "*** No fuzzing will be performed.\n";
120   if (int RC = Init(&ArgC, &ArgV)) {
121     errs() << "Initialization failed\n";
122     return RC;
123   }
124 
125   for (int I = 1; I < ArgC; ++I) {
126     StringRef Arg(ArgV[I]);
127     if (Arg.startswith("-")) {
128       if (Arg.equals("-ignore_remaining_args=1"))
129         break;
130       continue;
131     }
132 
133     auto BufOrErr = MemoryBuffer::getFile(Arg, /*FileSize-*/ -1,
134                                           /*RequiresNullTerminator=*/false);
135     if (std::error_code EC = BufOrErr.getError()) {
136       errs() << "Error reading file: " << Arg << ": " << EC.message() << "\n";
137       return 1;
138     }
139     std::unique_ptr<MemoryBuffer> Buf = std::move(BufOrErr.get());
140     errs() << "Running: " << Arg << " (" << Buf->getBufferSize() << " bytes)\n";
141     TestOne(reinterpret_cast<const uint8_t *>(Buf->getBufferStart()),
142             Buf->getBufferSize());
143   }
144   return 0;
145 }
146 
147 std::unique_ptr<Module> llvm::parseModule(
148     const uint8_t *Data, size_t Size, LLVMContext &Context) {
149 
150   if (Size <= 1)
151     // We get bogus data given an empty corpus - just create a new module.
152     return llvm::make_unique<Module>("M", Context);
153 
154   auto Buffer = MemoryBuffer::getMemBuffer(
155       StringRef(reinterpret_cast<const char *>(Data), Size), "Fuzzer input",
156       /*RequiresNullTerminator=*/false);
157 
158   SMDiagnostic Err;
159   auto M = parseBitcodeFile(Buffer->getMemBufferRef(), Context);
160   if (Error E = M.takeError()) {
161     errs() << toString(std::move(E)) << "\n";
162     return nullptr;
163   }
164   return std::move(M.get());
165 }
166 
167 size_t llvm::writeModule(const Module &M, uint8_t *Dest, size_t MaxSize) {
168   std::string Buf;
169   {
170     raw_string_ostream OS(Buf);
171     WriteBitcodeToFile(&M, OS);
172   }
173   if (Buf.size() > MaxSize)
174       return 0;
175   memcpy(Dest, Buf.data(), Buf.size());
176   return Buf.size();
177 }
178