LLVM 22.0.0git
IRMutator.h
Go to the documentation of this file.
1//===-- IRMutator.h - Mutation engine for fuzzing IR ------------*- C++ -*-===//
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//
9// Provides the IRMutator class, which drives mutations on IR based on a
10// configurable set of strategies. Some common strategies are also included
11// here.
12//
13// Fuzzer-friendly (de)serialization functions are also provided, as these
14// are usually needed when mutating IR.
15//
16//===----------------------------------------------------------------------===//
17
18#ifndef LLVM_FUZZMUTATE_IRMUTATOR_H
19#define LLVM_FUZZMUTATE_IRMUTATOR_H
20
24#include <optional>
25
26namespace llvm {
27class BasicBlock;
28class Function;
29class Instruction;
30class Module;
31
32struct RandomIRBuilder;
33
34/// Base class for describing how to mutate a module. mutation functions for
35/// each IR unit forward to the contained unit.
37public:
38 virtual ~IRMutationStrategy() = default;
39
40 /// Provide a weight to bias towards choosing this strategy for a mutation.
41 ///
42 /// The value of the weight is arbitrary, but a good default is "the number of
43 /// distinct ways in which this strategy can mutate a unit". This can also be
44 /// used to prefer strategies that shrink the overall size of the result when
45 /// we start getting close to \c MaxSize.
46 virtual uint64_t getWeight(size_t CurrentSize, size_t MaxSize,
47 uint64_t CurrentWeight) = 0;
48
49 /// @{
50 /// Mutators for each IR unit. By default these forward to a contained
51 /// instance of the next smaller unit.
52 virtual void mutate(Module &M, RandomIRBuilder &IB);
53 virtual void mutate(Function &F, RandomIRBuilder &IB);
54 virtual void mutate(BasicBlock &BB, RandomIRBuilder &IB);
55 virtual void mutate(Instruction &I, RandomIRBuilder &IB) {
56 llvm_unreachable("Strategy does not implement any mutators");
57 }
58 /// @}
59};
60
61using TypeGetter = std::function<Type *(LLVMContext &)>;
62
63/// Entry point for configuring and running IR mutations.
64class IRMutator {
65 std::vector<TypeGetter> AllowedTypes;
66 std::vector<std::unique_ptr<IRMutationStrategy>> Strategies;
67
68public:
69 IRMutator(std::vector<TypeGetter> &&AllowedTypes,
70 std::vector<std::unique_ptr<IRMutationStrategy>> &&Strategies)
71 : AllowedTypes(std::move(AllowedTypes)),
72 Strategies(std::move(Strategies)) {}
73
74 /// Calculate the size of module as the number of objects in it, i.e.
75 /// instructions, basic blocks, functions, and aliases.
76 ///
77 /// \param M module
78 /// \return number of objects in module
79 LLVM_ABI static size_t getModuleSize(const Module &M);
80
81 /// Mutate given module. No change will be made if no strategy is selected.
82 ///
83 /// \param M module to mutate
84 /// \param Seed seed for random mutation
85 /// \param MaxSize max module size (see getModuleSize)
86 LLVM_ABI void mutateModule(Module &M, int Seed, size_t MaxSize);
87};
88
89/// Strategy that injects operations into the function.
91 std::vector<fuzzerop::OpDescriptor> Operations;
92
93 std::optional<fuzzerop::OpDescriptor> chooseOperation(Value *Src,
94 RandomIRBuilder &IB);
95
96public:
97 InjectorIRStrategy() : Operations(getDefaultOps()) {}
98 InjectorIRStrategy(std::vector<fuzzerop::OpDescriptor> &&Operations)
99 : Operations(std::move(Operations)) {}
100 static std::vector<fuzzerop::OpDescriptor> getDefaultOps();
101
102 uint64_t getWeight(size_t CurrentSize, size_t MaxSize,
103 uint64_t CurrentWeight) override {
104 return Operations.size();
105 }
106
107 using IRMutationStrategy::mutate;
108 void mutate(Function &F, RandomIRBuilder &IB) override;
109 void mutate(BasicBlock &BB, RandomIRBuilder &IB) override;
110};
111
112/// Strategy that deletes instructions when the Module is too large.
114public:
115 uint64_t getWeight(size_t CurrentSize, size_t MaxSize,
116 uint64_t CurrentWeight) override;
117
118 using IRMutationStrategy::mutate;
119 void mutate(Function &F, RandomIRBuilder &IB) override;
120 void mutate(Instruction &Inst, RandomIRBuilder &IB) override;
121};
122
123/// Strategy that modifies instruction attributes and operands.
125public:
126 uint64_t getWeight(size_t CurrentSize, size_t MaxSize,
127 uint64_t CurrentWeight) override {
128 return 4;
129 }
130
131 using IRMutationStrategy::mutate;
132 void mutate(Instruction &Inst, RandomIRBuilder &IB) override;
133};
134
135/// Strategy that generates new function calls and inserts function signatures
136/// to the modules. If any signatures are present in the module it will be
137/// called.
139public:
140 uint64_t getWeight(size_t CurrentSize, size_t MaxSize,
141 uint64_t CurrentWeight) override {
142 return 10;
143 }
144
145 using IRMutationStrategy::mutate;
146 void mutate(BasicBlock &BB, RandomIRBuilder &IB) override;
147};
148
149/// Strategy to split a random block and insert a random CFG in between.
151private:
152 uint64_t MaxNumCases;
153 enum CFGToSink { Return, DirectSink, SinkOrSelfLoop, EndOfCFGToLink };
154
155public:
156 InsertCFGStrategy(uint64_t MNC = 8) : MaxNumCases(MNC){};
157 uint64_t getWeight(size_t CurrentSize, size_t MaxSize,
158 uint64_t CurrentWeight) override {
159 return 5;
160 }
161
162 void mutate(BasicBlock &BB, RandomIRBuilder &IB) override;
163
164private:
165 void connectBlocksToSink(ArrayRef<BasicBlock *> Blocks, BasicBlock *Sink,
166 RandomIRBuilder &IB);
167};
168
169/// Strategy to insert PHI Nodes at the head of each basic block.
171public:
172 uint64_t getWeight(size_t CurrentSize, size_t MaxSize,
173 uint64_t CurrentWeight) override {
174 return 2;
175 }
176
177 void mutate(BasicBlock &BB, RandomIRBuilder &IB) override;
178};
179
180/// Strategy to select a random instruction and add a new sink (user) to it to
181/// increate data dependency.
183public:
184 uint64_t getWeight(size_t CurrentSize, size_t MaxSize,
185 uint64_t CurrentWeight) override {
186 return 2;
187 }
188
189 void mutate(Function &F, RandomIRBuilder &IB) override;
190 void mutate(BasicBlock &BB, RandomIRBuilder &IB) override;
191};
192
193/// Strategy to randomly select a block and shuffle the operations without
194/// affecting data dependency.
196public:
197 uint64_t getWeight(size_t CurrentSize, size_t MaxSize,
198 uint64_t CurrentWeight) override {
199 return 2;
200 }
201
202 void mutate(BasicBlock &BB, RandomIRBuilder &IB) override;
203};
204
205/// Fuzzer friendly interface for the llvm bitcode parser.
206///
207/// \param Data Bitcode we are going to parse
208/// \param Size Size of the 'Data' in bytes
209/// \return New module or nullptr in case of error
210LLVM_ABI std::unique_ptr<Module> parseModule(const uint8_t *Data, size_t Size,
211 LLVMContext &Context);
212
213/// Fuzzer friendly interface for the llvm bitcode printer.
214///
215/// \param M Module to print
216/// \param Dest Location to store serialized module
217/// \param MaxSize Size of the destination buffer
218/// \return Number of bytes that were written. When module size exceeds MaxSize
219/// returns 0 and leaves Dest unchanged.
220LLVM_ABI size_t writeModule(const Module &M, uint8_t *Dest, size_t MaxSize);
221
222/// Try to parse module and verify it. May output verification errors to the
223/// errs().
224/// \return New module or nullptr in case of error.
225LLVM_ABI std::unique_ptr<Module>
226parseAndVerify(const uint8_t *Data, size_t Size, LLVMContext &Context);
227
228} // namespace llvm
229
230#endif // LLVM_FUZZMUTATE_IRMUTATOR_H
#define LLVM_ABI
Definition: Compiler.h:213
uint64_t Size
DenseMap< Block *, BlockRelaxAux > Blocks
Definition: ELF_riscv.cpp:507
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
Machine Check Debug Module
static ManagedStatic< cl::opt< uint64_t >, CreateSeed > Seed
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
LLVM Basic Block Representation.
Definition: BasicBlock.h:62
Base class for describing how to mutate a module.
Definition: IRMutator.h:36
virtual void mutate(Instruction &I, RandomIRBuilder &IB)
Definition: IRMutator.h:55
virtual uint64_t getWeight(size_t CurrentSize, size_t MaxSize, uint64_t CurrentWeight)=0
Provide a weight to bias towards choosing this strategy for a mutation.
virtual ~IRMutationStrategy()=default
Entry point for configuring and running IR mutations.
Definition: IRMutator.h:64
IRMutator(std::vector< TypeGetter > &&AllowedTypes, std::vector< std::unique_ptr< IRMutationStrategy > > &&Strategies)
Definition: IRMutator.h:69
LLVM_ABI void mutateModule(Module &M, int Seed, size_t MaxSize)
Mutate given module.
Definition: IRMutator.cpp:66
static LLVM_ABI size_t getModuleSize(const Module &M)
Calculate the size of module as the number of objects in it, i.e.
Definition: IRMutator.cpp:62
Strategy that injects operations into the function.
Definition: IRMutator.h:90
uint64_t getWeight(size_t CurrentSize, size_t MaxSize, uint64_t CurrentWeight) override
Provide a weight to bias towards choosing this strategy for a mutation.
Definition: IRMutator.h:102
InjectorIRStrategy(std::vector< fuzzerop::OpDescriptor > &&Operations)
Definition: IRMutator.h:98
Strategy to split a random block and insert a random CFG in between.
Definition: IRMutator.h:150
uint64_t getWeight(size_t CurrentSize, size_t MaxSize, uint64_t CurrentWeight) override
Provide a weight to bias towards choosing this strategy for a mutation.
Definition: IRMutator.h:157
InsertCFGStrategy(uint64_t MNC=8)
Definition: IRMutator.h:156
Strategy that generates new function calls and inserts function signatures to the modules.
Definition: IRMutator.h:138
uint64_t getWeight(size_t CurrentSize, size_t MaxSize, uint64_t CurrentWeight) override
Provide a weight to bias towards choosing this strategy for a mutation.
Definition: IRMutator.h:140
Strategy to insert PHI Nodes at the head of each basic block.
Definition: IRMutator.h:170
uint64_t getWeight(size_t CurrentSize, size_t MaxSize, uint64_t CurrentWeight) override
Provide a weight to bias towards choosing this strategy for a mutation.
Definition: IRMutator.h:172
Strategy that deletes instructions when the Module is too large.
Definition: IRMutator.h:113
Strategy that modifies instruction attributes and operands.
Definition: IRMutator.h:124
uint64_t getWeight(size_t CurrentSize, size_t MaxSize, uint64_t CurrentWeight) override
Provide a weight to bias towards choosing this strategy for a mutation.
Definition: IRMutator.h:126
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:68
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:67
Strategy to randomly select a block and shuffle the operations without affecting data dependency.
Definition: IRMutator.h:195
uint64_t getWeight(size_t CurrentSize, size_t MaxSize, uint64_t CurrentWeight) override
Provide a weight to bias towards choosing this strategy for a mutation.
Definition: IRMutator.h:197
Strategy to select a random instruction and add a new sink (user) to it to increate data dependency.
Definition: IRMutator.h:182
uint64_t getWeight(size_t CurrentSize, size_t MaxSize, uint64_t CurrentWeight) override
Provide a weight to bias towards choosing this strategy for a mutation.
Definition: IRMutator.h:184
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
LLVM Value Representation.
Definition: Value.h:75
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ BasicBlock
Various leaf nodes.
Definition: ISDOpcodes.h:81
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
LLVM_ABI std::unique_ptr< Module > parseAndVerify(const uint8_t *Data, size_t Size, LLVMContext &Context)
Try to parse module and verify it.
Definition: IRMutator.cpp:785
std::function< Type *(LLVMContext &)> TypeGetter
Definition: IRMutator.h:61
LLVM_ABI std::unique_ptr< Module > parseModule(const uint8_t *Data, size_t Size, LLVMContext &Context)
Fuzzer friendly interface for the llvm bitcode parser.
Definition: IRMutator.cpp:753
LLVM_ABI size_t writeModule(const Module &M, uint8_t *Dest, size_t MaxSize)
Fuzzer friendly interface for the llvm bitcode printer.
Definition: IRMutator.cpp:773
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1886
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:856