LLVM  10.0.0svn
FuzzerCLI.cpp
Go to the documentation of this file.
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 
10 #include "llvm/ADT/Triple.h"
13 #include "llvm/IR/LLVMContext.h"
15 #include "llvm/Support/Compiler.h"
16 #include "llvm/Support/Error.h"
18 #include "llvm/Support/SourceMgr.h"
20 #include "llvm/IR/Verifier.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 
39  std::vector<std::string> Args{ExecName};
40 
41  auto NameAndArgs = ExecName.split("--");
42  if (NameAndArgs.second.empty())
43  return;
44 
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 
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 
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 
138 int llvm::runFuzzerOnInputs(int ArgC, char *ArgV[], FuzzerTestFun TestOne,
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 
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 
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 
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 }
raw_ostream & errs()
This returns a reference to a raw_ostream for standard error.
LLVMContext & Context
int(*)(int *argc, char ***argv) FuzzerInitFun
Definition: FuzzerCLI.h:44
This class represents lattice values for constants.
Definition: AllocatorList.h:23
A Module instance is used to store all the information related to an LLVM module. ...
Definition: Module.h:65
LLVM_NODISCARD bool startswith(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition: StringRef.h:256
std::unique_ptr< Module > parseAndVerify(const uint8_t *Data, size_t Size, LLVMContext &Context)
Try to parse module and verify it.
Definition: FuzzerCLI.cpp:201
static std::unique_ptr< MemoryBuffer > getMemBuffer(StringRef InputData, StringRef BufferName="", bool RequiresNullTerminator=true)
Open the specified memory range as a MemoryBuffer.
size_t writeModule(const Module &M, uint8_t *Dest, size_t MaxSize)
Fuzzer friendly interface for the llvm bitcode printer.
Definition: FuzzerCLI.cpp:189
bool ParseCommandLineOptions(int argc, const char *const *argv, StringRef Overview="", raw_ostream *Errs=nullptr, const char *EnvVar=nullptr, bool LongOptionsUseDoubleDash=false)
void handleExecNameEncodedBEOpts(StringRef ExecName)
Handle backend options that are encoded in the executable name.
Definition: FuzzerCLI.cpp:38
std::string toString(Error E)
Write all error messages (if any) in E to a string.
Definition: Error.h:966
void parseFuzzerCLOpts(int ArgC, char *ArgV[])
Parse cl::opts from a fuzz target commandline.
Definition: FuzzerCLI.cpp:24
ArchType getArch() const
getArch - Get the parsed architecture type of this triple.
Definition: Triple.h:296
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:64
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
int runFuzzerOnInputs(int ArgC, char *ArgV[], FuzzerTestFun TestOne, FuzzerInitFun Init=[](int *, char ***) { return 0;})
Runs a fuzz target on the inputs specified on the command line.
Definition: FuzzerCLI.cpp:138
void WriteBitcodeToFile(const Module &M, raw_ostream &Out, bool ShouldPreserveUseListOrder=false, const ModuleSummaryIndex *Index=nullptr, bool GenerateHash=false, ModuleHash *ModHash=nullptr)
Write the specified module to the specified raw output stream.
amdgpu Simplify well known AMD library false FunctionCallee Value * Arg
int(*)(const uint8_t *Data, size_t Size) FuzzerTestFun
Definition: FuzzerCLI.h:43
std::unique_ptr< Module > parseModule(const uint8_t *Data, size_t Size, LLVMContext &Context)
Fuzzer friendly interface for the llvm bitcode parser.
Definition: FuzzerCLI.cpp:169
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:43
This is a &#39;vector&#39; (really, a variable-sized array), optimized for the case when the array is small...
Definition: SmallVector.h:837
LLVM_NODISCARD std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
Definition: StringRef.h:696
bool verifyModule(const Module &M, raw_ostream *OS=nullptr, bool *BrokenDebugInfo=nullptr)
Check a module for errors.
Definition: Verifier.cpp:5035
Expected< std::unique_ptr< Module > > parseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context)
Read the specified bitcode file, returning the module.
LLVM_NODISCARD bool equals(StringRef RHS) const
equals - Check for string equality, this is more efficient than compare() when the relative ordering ...
Definition: StringRef.h:160
#define I(x, y, z)
Definition: MD5.cpp:58
uint32_t Size
Definition: Profile.cpp:46
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, int64_t FileSize=-1, bool RequiresNullTerminator=true, bool IsVolatile=false)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful, otherwise returning null.
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:503
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
void handleExecNameEncodedOptimizerOpts(StringRef ExecName)
Handle optimizer options which are encoded in the executable name.
Definition: FuzzerCLI.cpp:74
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
Instances of this class encapsulate one diagnostic report, allowing printing to a raw_ostream as a ca...
Definition: SourceMgr.h:261