blob: 1d16376bb874688806407cc2db54b5e251de2c16 [file] [log] [blame]
Justin Bogner2ebcca22017-08-29 00:22:08 +00001//===--- llvm-isel-fuzzer.cpp - Fuzzer for instruction selection ----------===//
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// Tool to fuzz instruction selection using libFuzzer.
11//
12//===----------------------------------------------------------------------===//
13
Justin Bogner2ebcca22017-08-29 00:22:08 +000014#include "llvm/ADT/StringRef.h"
15#include "llvm/Analysis/TargetLibraryInfo.h"
16#include "llvm/Bitcode/BitcodeReader.h"
17#include "llvm/Bitcode/BitcodeWriter.h"
18#include "llvm/CodeGen/CommandFlags.h"
19#include "llvm/FuzzMutate/IRMutator.h"
20#include "llvm/FuzzMutate/Operations.h"
21#include "llvm/FuzzMutate/Random.h"
22#include "llvm/IR/Constants.h"
23#include "llvm/IR/LLVMContext.h"
24#include "llvm/IR/LegacyPassManager.h"
25#include "llvm/IR/Module.h"
26#include "llvm/IR/Verifier.h"
27#include "llvm/IRReader/IRReader.h"
28#include "llvm/Support/DataTypes.h"
29#include "llvm/Support/Debug.h"
30#include "llvm/Support/SourceMgr.h"
31#include "llvm/Support/TargetRegistry.h"
32#include "llvm/Support/TargetSelect.h"
33#include "llvm/Target/TargetMachine.h"
34#include <random>
35
36#define DEBUG_TYPE "isel-fuzzer"
37
38using namespace llvm;
39
40static cl::opt<char>
41OptLevel("O",
42 cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
43 "(default = '-O2')"),
44 cl::Prefix,
45 cl::ZeroOrMore,
46 cl::init(' '));
47
48static cl::opt<std::string>
49TargetTriple("mtriple", cl::desc("Override target triple for module"));
50
51static std::unique_ptr<TargetMachine> TM;
52static std::unique_ptr<IRMutator> Mutator;
53
54static std::unique_ptr<Module> parseModule(const uint8_t *Data, size_t Size,
55 LLVMContext &Context) {
56 auto Buffer = MemoryBuffer::getMemBuffer(
57 StringRef(reinterpret_cast<const char *>(Data), Size), "Fuzzer input",
58 /*RequiresNullTerminator=*/false);
59
60 SMDiagnostic Err;
61 auto M = parseBitcodeFile(Buffer->getMemBufferRef(), Context);
62 if (Error E = M.takeError()) {
63 errs() << toString(std::move(E)) << "\n";
64 return nullptr;
65 }
66 return std::move(M.get());
67}
68
69static size_t writeModule(const Module &M, uint8_t *Dest, size_t MaxSize) {
70 std::string Buf;
71 {
72 raw_string_ostream OS(Buf);
73 WriteBitcodeToFile(&M, OS);
74 }
75 if (Buf.size() > MaxSize)
76 return 0;
77 memcpy(Dest, Buf.data(), Buf.size());
78 return Buf.size();
79}
80
81std::unique_ptr<IRMutator> createISelMutator() {
82 std::vector<TypeGetter> Types{
83 Type::getInt1Ty, Type::getInt8Ty, Type::getInt16Ty, Type::getInt32Ty,
84 Type::getInt64Ty, Type::getFloatTy, Type::getDoubleTy};
85
86 std::vector<std::unique_ptr<IRMutationStrategy>> Strategies;
87 Strategies.emplace_back(
88 new InjectorIRStrategy(InjectorIRStrategy::getDefaultOps()));
89 Strategies.emplace_back(new InstDeleterIRStrategy());
90
Justin Bognerf4838172017-09-01 17:26:24 +000091 return llvm::make_unique<IRMutator>(std::move(Types), std::move(Strategies));
Justin Bogner2ebcca22017-08-29 00:22:08 +000092}
93
94extern "C" LLVM_ATTRIBUTE_USED size_t LLVMFuzzerCustomMutator(
95 uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed) {
96 LLVMContext Context;
97 std::unique_ptr<Module> M;
98 if (Size <= 1)
99 // We get bogus data given an empty corpus - just create a new module.
100 M.reset(new Module("M", Context));
101 else
102 M = parseModule(Data, Size, Context);
103
104 Mutator->mutateModule(*M, Seed, Size, MaxSize);
105
106 return writeModule(*M, Data, MaxSize);
107}
108
109extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
110 if (Size <= 1)
111 // We get bogus data given an empty corpus - ignore it.
112 return 0;
113
114 LLVMContext Context;
115 auto M = parseModule(Data, Size, Context);
116 if (!M || verifyModule(*M, &errs())) {
117 errs() << "error: input module is broken!\n";
118 return 1;
119 }
120
121 // Set up the module to build for our target.
122 M->setTargetTriple(TM->getTargetTriple().normalize());
123 M->setDataLayout(TM->createDataLayout());
124
125 // Build up a PM to do instruction selection.
126 legacy::PassManager PM;
127 TargetLibraryInfoImpl TLII(TM->getTargetTriple());
128 PM.add(new TargetLibraryInfoWrapperPass(TLII));
129 raw_null_ostream OS;
130 TM->addPassesToEmitFile(PM, OS, TargetMachine::CGFT_Null);
131 PM.run(*M);
132
133 return 0;
134}
135
136/// Parse command line options, but ignore anything before '--'.
137static void parseCLOptsAfterDashDash(int argc, char *argv[]) {
138 std::vector<const char *> CLArgs;
139 CLArgs.push_back(argv[0]);
140
141 int I = 1;
142 while (I < argc)
143 if (StringRef(argv[I++]).equals("-ignore_remaining_args=1"))
144 break;
145 while (I < argc)
146 CLArgs.push_back(argv[I++]);
147
148 cl::ParseCommandLineOptions(CLArgs.size(), CLArgs.data());
149}
150
151static void handleLLVMFatalError(void *, const std::string &Message, bool) {
152 // TODO: Would it be better to call into the fuzzer internals directly?
153 dbgs() << "LLVM ERROR: " << Message << "\n"
154 << "Aborting to trigger fuzzer exit handling.\n";
155 abort();
156}
157
158extern "C" LLVM_ATTRIBUTE_USED int LLVMFuzzerInitialize(int *argc,
159 char ***argv) {
160 EnableDebugBuffering = true;
161
162 InitializeAllTargets();
163 InitializeAllTargetMCs();
164 InitializeAllAsmPrinters();
165 InitializeAllAsmParsers();
166
167 parseCLOptsAfterDashDash(*argc, *argv);
168
169 if (TargetTriple.empty()) {
170 errs() << *argv[0] << ": -mtriple must be specified\n";
171 return 1;
172 }
173
174 Triple TheTriple = Triple(Triple::normalize(TargetTriple));
175
176 // Get the target specific parser.
177 std::string Error;
178 const Target *TheTarget =
179 TargetRegistry::lookupTarget(MArch, TheTriple, Error);
180 if (!TheTarget) {
181 errs() << argv[0] << ": " << Error;
182 return 1;
183 }
184
185 // Set up the pipeline like llc does.
186 std::string CPUStr = getCPUStr(), FeaturesStr = getFeaturesStr();
187
188 CodeGenOpt::Level OLvl = CodeGenOpt::Default;
189 switch (OptLevel) {
190 default:
191 errs() << argv[0] << ": invalid optimization level.\n";
192 return 1;
193 case ' ': break;
194 case '0': OLvl = CodeGenOpt::None; break;
195 case '1': OLvl = CodeGenOpt::Less; break;
196 case '2': OLvl = CodeGenOpt::Default; break;
197 case '3': OLvl = CodeGenOpt::Aggressive; break;
198 }
199
200 TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
201 TM.reset(TheTarget->createTargetMachine(TheTriple.getTriple(), CPUStr,
202 FeaturesStr, Options, getRelocModel(),
203 getCodeModel(), OLvl));
204 assert(TM && "Could not allocate target machine!");
205
206 // Make sure we print the summary and the current unit when LLVM errors out.
207 install_fatal_error_handler(handleLLVMFatalError, nullptr);
208
209 // Finally, create our mutator.
210 Mutator = createISelMutator();
211 return 0;
212}