//===-- FuzzerCLI.cpp -----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "llvm/FuzzMutate/FuzzerCLI.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/IR/LLVMContext.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Error.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" #include "llvm/IR/Verifier.h" using namespace llvm; void llvm::parseFuzzerCLOpts(int ArgC, char *ArgV[]) { std::vector CLArgs; CLArgs.push_back(ArgV[0]); int I = 1; while (I < ArgC) if (StringRef(ArgV[I++]).equals("-ignore_remaining_args=1")) break; while (I < ArgC) CLArgs.push_back(ArgV[I++]); cl::ParseCommandLineOptions(CLArgs.size(), CLArgs.data()); } void llvm::handleExecNameEncodedBEOpts(StringRef ExecName) { std::vector Args{std::string(ExecName)}; auto NameAndArgs = ExecName.split("--"); if (NameAndArgs.second.empty()) return; SmallVector Opts; NameAndArgs.second.split(Opts, '-'); for (StringRef Opt : Opts) { if (Opt.equals("gisel")) { Args.push_back("-global-isel"); // For now we default GlobalISel to -O0 Args.push_back("-O0"); } else if (Opt.startswith("O")) { Args.push_back("-" + Opt.str()); } else if (Triple(Opt).getArch()) { Args.push_back("-mtriple=" + Opt.str()); } else { errs() << ExecName << ": Unknown option: " << Opt << ".\n"; exit(1); } } errs() << NameAndArgs.first << ": Injected args:"; for (int I = 1, E = Args.size(); I < E; ++I) errs() << " " << Args[I]; errs() << "\n"; std::vector CLArgs; CLArgs.reserve(Args.size()); for (std::string &S : Args) CLArgs.push_back(S.c_str()); cl::ParseCommandLineOptions(CLArgs.size(), CLArgs.data()); } void llvm::handleExecNameEncodedOptimizerOpts(StringRef ExecName) { // TODO: Refactor parts common with the 'handleExecNameEncodedBEOpts' std::vector Args{std::string(ExecName)}; auto NameAndArgs = ExecName.split("--"); if (NameAndArgs.second.empty()) return; SmallVector Opts; NameAndArgs.second.split(Opts, '-'); for (StringRef Opt : Opts) { if (Opt == "instcombine") { Args.push_back("-passes=instcombine"); } else if (Opt == "earlycse") { Args.push_back("-passes=early-cse"); } else if (Opt == "simplifycfg") { Args.push_back("-passes=simplify-cfg"); } else if (Opt == "gvn") { Args.push_back("-passes=gvn"); } else if (Opt == "sccp") { Args.push_back("-passes=sccp"); } else if (Opt == "loop_predication") { Args.push_back("-passes=loop-predication"); } else if (Opt == "guard_widening") { Args.push_back("-passes=guard-widening"); } else if (Opt == "loop_rotate") { Args.push_back("-passes=loop(rotate)"); } else if (Opt == "loop_unswitch") { Args.push_back("-passes=loop(unswitch)"); } else if (Opt == "loop_unroll") { Args.push_back("-passes=unroll"); } else if (Opt == "loop_vectorize") { Args.push_back("-passes=loop-vectorize"); } else if (Opt == "licm") { Args.push_back("-passes=licm"); } else if (Opt == "indvars") { Args.push_back("-passes=indvars"); } else if (Opt == "strength_reduce") { Args.push_back("-passes=loop-reduce"); } else if (Opt == "irce") { Args.push_back("-passes=irce"); } else if (Triple(Opt).getArch()) { Args.push_back("-mtriple=" + Opt.str()); } else { errs() << ExecName << ": Unknown option: " << Opt << ".\n"; exit(1); } } errs() << NameAndArgs.first << ": Injected args:"; for (int I = 1, E = Args.size(); I < E; ++I) errs() << " " << Args[I]; errs() << "\n"; std::vector CLArgs; CLArgs.reserve(Args.size()); for (std::string &S : Args) CLArgs.push_back(S.c_str()); cl::ParseCommandLineOptions(CLArgs.size(), CLArgs.data()); } int llvm::runFuzzerOnInputs(int ArgC, char *ArgV[], FuzzerTestFun TestOne, FuzzerInitFun Init) { errs() << "*** This tool was not linked to libFuzzer.\n" << "*** No fuzzing will be performed.\n"; if (int RC = Init(&ArgC, &ArgV)) { errs() << "Initialization failed\n"; return RC; } for (int I = 1; I < ArgC; ++I) { StringRef Arg(ArgV[I]); if (Arg.startswith("-")) { if (Arg.equals("-ignore_remaining_args=1")) break; continue; } auto BufOrErr = MemoryBuffer::getFile(Arg, /*FileSize-*/ -1, /*RequiresNullTerminator=*/false); if (std::error_code EC = BufOrErr.getError()) { errs() << "Error reading file: " << Arg << ": " << EC.message() << "\n"; return 1; } std::unique_ptr Buf = std::move(BufOrErr.get()); errs() << "Running: " << Arg << " (" << Buf->getBufferSize() << " bytes)\n"; TestOne(reinterpret_cast(Buf->getBufferStart()), Buf->getBufferSize()); } return 0; } std::unique_ptr llvm::parseModule( const uint8_t *Data, size_t Size, LLVMContext &Context) { if (Size <= 1) // We get bogus data given an empty corpus - just create a new module. return std::make_unique("M", Context); auto Buffer = MemoryBuffer::getMemBuffer( StringRef(reinterpret_cast(Data), Size), "Fuzzer input", /*RequiresNullTerminator=*/false); SMDiagnostic Err; auto M = parseBitcodeFile(Buffer->getMemBufferRef(), Context); if (Error E = M.takeError()) { errs() << toString(std::move(E)) << "\n"; return nullptr; } return std::move(M.get()); } size_t llvm::writeModule(const Module &M, uint8_t *Dest, size_t MaxSize) { std::string Buf; { raw_string_ostream OS(Buf); WriteBitcodeToFile(M, OS); } if (Buf.size() > MaxSize) return 0; memcpy(Dest, Buf.data(), Buf.size()); return Buf.size(); } std::unique_ptr llvm::parseAndVerify(const uint8_t *Data, size_t Size, LLVMContext &Context) { auto M = parseModule(Data, Size, Context); if (!M || verifyModule(*M, &errs())) return nullptr; return M; }