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