xref: /freebsd/contrib/llvm-project/llvm/lib/FuzzMutate/FuzzerCLI.cpp (revision fe6060f10f634930ff71b7c50291ddc610da2475)
10b57cec5SDimitry Andric //===-- FuzzerCLI.cpp -----------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "llvm/FuzzMutate/FuzzerCLI.h"
105ffd83dbSDimitry Andric #include "llvm/ADT/StringRef.h"
110b57cec5SDimitry Andric #include "llvm/ADT/Triple.h"
120b57cec5SDimitry Andric #include "llvm/Bitcode/BitcodeReader.h"
130b57cec5SDimitry Andric #include "llvm/Bitcode/BitcodeWriter.h"
140b57cec5SDimitry Andric #include "llvm/IR/LLVMContext.h"
150b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
160b57cec5SDimitry Andric #include "llvm/Support/Compiler.h"
170b57cec5SDimitry Andric #include "llvm/Support/Error.h"
180b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
190b57cec5SDimitry Andric #include "llvm/Support/SourceMgr.h"
200b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
210b57cec5SDimitry Andric #include "llvm/IR/Verifier.h"
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric using namespace llvm;
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric void llvm::parseFuzzerCLOpts(int ArgC, char *ArgV[]) {
260b57cec5SDimitry Andric   std::vector<const char *> CLArgs;
270b57cec5SDimitry Andric   CLArgs.push_back(ArgV[0]);
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric   int I = 1;
300b57cec5SDimitry Andric   while (I < ArgC)
310b57cec5SDimitry Andric     if (StringRef(ArgV[I++]).equals("-ignore_remaining_args=1"))
320b57cec5SDimitry Andric       break;
330b57cec5SDimitry Andric   while (I < ArgC)
340b57cec5SDimitry Andric     CLArgs.push_back(ArgV[I++]);
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric   cl::ParseCommandLineOptions(CLArgs.size(), CLArgs.data());
370b57cec5SDimitry Andric }
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric void llvm::handleExecNameEncodedBEOpts(StringRef ExecName) {
405ffd83dbSDimitry Andric   std::vector<std::string> Args{std::string(ExecName)};
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric   auto NameAndArgs = ExecName.split("--");
430b57cec5SDimitry Andric   if (NameAndArgs.second.empty())
440b57cec5SDimitry Andric     return;
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric   SmallVector<StringRef, 4> Opts;
470b57cec5SDimitry Andric   NameAndArgs.second.split(Opts, '-');
480b57cec5SDimitry Andric   for (StringRef Opt : Opts) {
490b57cec5SDimitry Andric     if (Opt.equals("gisel")) {
500b57cec5SDimitry Andric       Args.push_back("-global-isel");
510b57cec5SDimitry Andric       // For now we default GlobalISel to -O0
520b57cec5SDimitry Andric       Args.push_back("-O0");
530b57cec5SDimitry Andric     } else if (Opt.startswith("O")) {
540b57cec5SDimitry Andric       Args.push_back("-" + Opt.str());
550b57cec5SDimitry Andric     } else if (Triple(Opt).getArch()) {
560b57cec5SDimitry Andric       Args.push_back("-mtriple=" + Opt.str());
570b57cec5SDimitry Andric     } else {
580b57cec5SDimitry Andric       errs() << ExecName << ": Unknown option: " << Opt << ".\n";
590b57cec5SDimitry Andric       exit(1);
600b57cec5SDimitry Andric     }
610b57cec5SDimitry Andric   }
620b57cec5SDimitry Andric   errs() << NameAndArgs.first << ": Injected args:";
630b57cec5SDimitry Andric   for (int I = 1, E = Args.size(); I < E; ++I)
640b57cec5SDimitry Andric     errs() << " " << Args[I];
650b57cec5SDimitry Andric   errs() << "\n";
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric   std::vector<const char *> CLArgs;
680b57cec5SDimitry Andric   CLArgs.reserve(Args.size());
690b57cec5SDimitry Andric   for (std::string &S : Args)
700b57cec5SDimitry Andric     CLArgs.push_back(S.c_str());
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric   cl::ParseCommandLineOptions(CLArgs.size(), CLArgs.data());
730b57cec5SDimitry Andric }
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric void llvm::handleExecNameEncodedOptimizerOpts(StringRef ExecName) {
760b57cec5SDimitry Andric   // TODO: Refactor parts common with the 'handleExecNameEncodedBEOpts'
775ffd83dbSDimitry Andric   std::vector<std::string> Args{std::string(ExecName)};
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric   auto NameAndArgs = ExecName.split("--");
800b57cec5SDimitry Andric   if (NameAndArgs.second.empty())
810b57cec5SDimitry Andric     return;
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric   SmallVector<StringRef, 4> Opts;
840b57cec5SDimitry Andric   NameAndArgs.second.split(Opts, '-');
850b57cec5SDimitry Andric   for (StringRef Opt : Opts) {
860b57cec5SDimitry Andric     if (Opt == "instcombine") {
870b57cec5SDimitry Andric       Args.push_back("-passes=instcombine");
880b57cec5SDimitry Andric     } else if (Opt == "earlycse") {
890b57cec5SDimitry Andric       Args.push_back("-passes=early-cse");
900b57cec5SDimitry Andric     } else if (Opt == "simplifycfg") {
91*fe6060f1SDimitry Andric       Args.push_back("-passes=simplifycfg");
920b57cec5SDimitry Andric     } else if (Opt == "gvn") {
930b57cec5SDimitry Andric       Args.push_back("-passes=gvn");
940b57cec5SDimitry Andric     } else if (Opt == "sccp") {
950b57cec5SDimitry Andric       Args.push_back("-passes=sccp");
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric     } else if (Opt == "loop_predication") {
980b57cec5SDimitry Andric       Args.push_back("-passes=loop-predication");
990b57cec5SDimitry Andric     } else if (Opt == "guard_widening") {
1000b57cec5SDimitry Andric       Args.push_back("-passes=guard-widening");
1010b57cec5SDimitry Andric     } else if (Opt == "loop_rotate") {
1020b57cec5SDimitry Andric       Args.push_back("-passes=loop(rotate)");
1030b57cec5SDimitry Andric     } else if (Opt == "loop_unswitch") {
104*fe6060f1SDimitry Andric       Args.push_back("-passes=loop(simple-loop-unswitch)");
1050b57cec5SDimitry Andric     } else if (Opt == "loop_unroll") {
1060b57cec5SDimitry Andric       Args.push_back("-passes=unroll");
1070b57cec5SDimitry Andric     } else if (Opt == "loop_vectorize") {
1080b57cec5SDimitry Andric       Args.push_back("-passes=loop-vectorize");
1090b57cec5SDimitry Andric     } else if (Opt == "licm") {
1100b57cec5SDimitry Andric       Args.push_back("-passes=licm");
1110b57cec5SDimitry Andric     } else if (Opt == "indvars") {
1120b57cec5SDimitry Andric       Args.push_back("-passes=indvars");
1130b57cec5SDimitry Andric     } else if (Opt == "strength_reduce") {
1145ffd83dbSDimitry Andric       Args.push_back("-passes=loop-reduce");
1150b57cec5SDimitry Andric     } else if (Opt == "irce") {
1160b57cec5SDimitry Andric       Args.push_back("-passes=irce");
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric     } else if (Triple(Opt).getArch()) {
1190b57cec5SDimitry Andric       Args.push_back("-mtriple=" + Opt.str());
1200b57cec5SDimitry Andric     } else {
1210b57cec5SDimitry Andric       errs() << ExecName << ": Unknown option: " << Opt << ".\n";
1220b57cec5SDimitry Andric       exit(1);
1230b57cec5SDimitry Andric     }
1240b57cec5SDimitry Andric   }
1250b57cec5SDimitry Andric 
1260b57cec5SDimitry Andric   errs() << NameAndArgs.first << ": Injected args:";
1270b57cec5SDimitry Andric   for (int I = 1, E = Args.size(); I < E; ++I)
1280b57cec5SDimitry Andric     errs() << " " << Args[I];
1290b57cec5SDimitry Andric   errs() << "\n";
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric   std::vector<const char *> CLArgs;
1320b57cec5SDimitry Andric   CLArgs.reserve(Args.size());
1330b57cec5SDimitry Andric   for (std::string &S : Args)
1340b57cec5SDimitry Andric     CLArgs.push_back(S.c_str());
1350b57cec5SDimitry Andric 
1360b57cec5SDimitry Andric   cl::ParseCommandLineOptions(CLArgs.size(), CLArgs.data());
1370b57cec5SDimitry Andric }
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric int llvm::runFuzzerOnInputs(int ArgC, char *ArgV[], FuzzerTestFun TestOne,
1400b57cec5SDimitry Andric                             FuzzerInitFun Init) {
1410b57cec5SDimitry Andric   errs() << "*** This tool was not linked to libFuzzer.\n"
1420b57cec5SDimitry Andric          << "*** No fuzzing will be performed.\n";
1430b57cec5SDimitry Andric   if (int RC = Init(&ArgC, &ArgV)) {
1440b57cec5SDimitry Andric     errs() << "Initialization failed\n";
1450b57cec5SDimitry Andric     return RC;
1460b57cec5SDimitry Andric   }
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric   for (int I = 1; I < ArgC; ++I) {
1490b57cec5SDimitry Andric     StringRef Arg(ArgV[I]);
1500b57cec5SDimitry Andric     if (Arg.startswith("-")) {
1510b57cec5SDimitry Andric       if (Arg.equals("-ignore_remaining_args=1"))
1520b57cec5SDimitry Andric         break;
1530b57cec5SDimitry Andric       continue;
1540b57cec5SDimitry Andric     }
1550b57cec5SDimitry Andric 
156*fe6060f1SDimitry Andric     auto BufOrErr = MemoryBuffer::getFile(Arg, /*IsText=*/false,
1570b57cec5SDimitry Andric                                           /*RequiresNullTerminator=*/false);
1580b57cec5SDimitry Andric     if (std::error_code EC = BufOrErr.getError()) {
1590b57cec5SDimitry Andric       errs() << "Error reading file: " << Arg << ": " << EC.message() << "\n";
1600b57cec5SDimitry Andric       return 1;
1610b57cec5SDimitry Andric     }
1620b57cec5SDimitry Andric     std::unique_ptr<MemoryBuffer> Buf = std::move(BufOrErr.get());
1630b57cec5SDimitry Andric     errs() << "Running: " << Arg << " (" << Buf->getBufferSize() << " bytes)\n";
1640b57cec5SDimitry Andric     TestOne(reinterpret_cast<const uint8_t *>(Buf->getBufferStart()),
1650b57cec5SDimitry Andric             Buf->getBufferSize());
1660b57cec5SDimitry Andric   }
1670b57cec5SDimitry Andric   return 0;
1680b57cec5SDimitry Andric }
1690b57cec5SDimitry Andric 
1700b57cec5SDimitry Andric std::unique_ptr<Module> llvm::parseModule(
1710b57cec5SDimitry Andric     const uint8_t *Data, size_t Size, LLVMContext &Context) {
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric   if (Size <= 1)
1740b57cec5SDimitry Andric     // We get bogus data given an empty corpus - just create a new module.
1758bcb0991SDimitry Andric     return std::make_unique<Module>("M", Context);
1760b57cec5SDimitry Andric 
1770b57cec5SDimitry Andric   auto Buffer = MemoryBuffer::getMemBuffer(
1780b57cec5SDimitry Andric       StringRef(reinterpret_cast<const char *>(Data), Size), "Fuzzer input",
1790b57cec5SDimitry Andric       /*RequiresNullTerminator=*/false);
1800b57cec5SDimitry Andric 
1810b57cec5SDimitry Andric   SMDiagnostic Err;
1820b57cec5SDimitry Andric   auto M = parseBitcodeFile(Buffer->getMemBufferRef(), Context);
1830b57cec5SDimitry Andric   if (Error E = M.takeError()) {
1840b57cec5SDimitry Andric     errs() << toString(std::move(E)) << "\n";
1850b57cec5SDimitry Andric     return nullptr;
1860b57cec5SDimitry Andric   }
1870b57cec5SDimitry Andric   return std::move(M.get());
1880b57cec5SDimitry Andric }
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric size_t llvm::writeModule(const Module &M, uint8_t *Dest, size_t MaxSize) {
1910b57cec5SDimitry Andric   std::string Buf;
1920b57cec5SDimitry Andric   {
1930b57cec5SDimitry Andric     raw_string_ostream OS(Buf);
1940b57cec5SDimitry Andric     WriteBitcodeToFile(M, OS);
1950b57cec5SDimitry Andric   }
1960b57cec5SDimitry Andric   if (Buf.size() > MaxSize)
1970b57cec5SDimitry Andric       return 0;
1980b57cec5SDimitry Andric   memcpy(Dest, Buf.data(), Buf.size());
1990b57cec5SDimitry Andric   return Buf.size();
2000b57cec5SDimitry Andric }
2010b57cec5SDimitry Andric 
2020b57cec5SDimitry Andric std::unique_ptr<Module> llvm::parseAndVerify(const uint8_t *Data, size_t Size,
2030b57cec5SDimitry Andric                                              LLVMContext &Context) {
2040b57cec5SDimitry Andric   auto M = parseModule(Data, Size, Context);
2050b57cec5SDimitry Andric   if (!M || verifyModule(*M, &errs()))
2060b57cec5SDimitry Andric     return nullptr;
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric   return M;
2090b57cec5SDimitry Andric }
210