llvm.org GIT mirror llvm / f54e7aa
llvm-mc-fuzzer: add support for assembly This creates an llvm-mc-disassemble-fuzzer from the existing llvm-mc-fuzzer and finishing the assemble support in llvm-mc-assemble-fuzzer. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@296323 91177308-0d34-0410-b5e6-96231b3b80d8 Brian Cain 2 years ago
6 changed file(s) with 496 addition(s) and 177 deletion(s). Raw diff Collapse all Expand all
0 if( LLVM_USE_SANITIZE_COVERAGE )
1 include_directories(BEFORE
2 ${CMAKE_CURRENT_SOURCE_DIR}/../../lib/Fuzzer)
3
4 set(LLVM_LINK_COMPONENTS
5 AllTargetsAsmPrinters
6 AllTargetsAsmParsers
7 AllTargetsDescs
8 AllTargetsInfos
9 MC
10 MCParser
11 Support
12 )
13 add_llvm_tool(llvm-mc-assemble-fuzzer
14 llvm-mc-assemble-fuzzer.cpp)
15 target_link_libraries(llvm-mc-assemble-fuzzer
16 LLVMFuzzer
17 )
18 endif()
0 //===--- llvm-mc-fuzzer.cpp - Fuzzer for the MC layer ---------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 //===----------------------------------------------------------------------===//
10
11 #include "FuzzerInterface.h"
12 #include "llvm-c/Target.h"
13 #include "llvm/MC/SubtargetFeature.h"
14 #include "llvm/MC/MCAsmBackend.h"
15 #include "llvm/MC/MCAsmInfo.h"
16 #include "llvm/MC/MCContext.h"
17 #include "llvm/MC/MCInstPrinter.h"
18 #include "llvm/MC/MCInstrInfo.h"
19 #include "llvm/MC/MCObjectFileInfo.h"
20 #include "llvm/MC/MCParser/AsmLexer.h"
21 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
22 #include "llvm/MC/MCRegisterInfo.h"
23 #include "llvm/MC/MCSectionMachO.h"
24 #include "llvm/MC/MCStreamer.h"
25 #include "llvm/MC/MCSubtargetInfo.h"
26 #include "llvm/MC/MCTargetOptionsCommandFlags.h"
27 #include "llvm/Support/MemoryBuffer.h"
28 #include "llvm/Support/CommandLine.h"
29 #include "llvm/Support/FileUtilities.h"
30 #include "llvm/Support/raw_ostream.h"
31 #include "llvm/Support/SourceMgr.h"
32 #include "llvm/Support/TargetSelect.h"
33 #include "llvm/Support/TargetRegistry.h"
34 #include "llvm/Support/ToolOutputFile.h"
35
36 using namespace llvm;
37
38 static cl::opt
39 TripleName("triple", cl::desc("Target triple to assemble for, "
40 "see -version for available targets"));
41
42 static cl::opt
43 MCPU("mcpu",
44 cl::desc("Target a specific cpu type (-mcpu=help for details)"),
45 cl::value_desc("cpu-name"), cl::init(""));
46
47 // This is useful for variable-length instruction sets.
48 static cl::opt InsnLimit(
49 "insn-limit",
50 cl::desc("Limit the number of instructions to process (0 for no limit)"),
51 cl::value_desc("count"), cl::init(0));
52
53 static cl::list
54 MAttrs("mattr", cl::CommaSeparated,
55 cl::desc("Target specific attributes (-mattr=help for details)"),
56 cl::value_desc("a1,+a2,-a3,..."));
57 // The feature string derived from -mattr's values.
58 std::string FeaturesStr;
59
60 static cl::list
61 FuzzerArgs("fuzzer-args", cl::Positional,
62 cl::desc("Options to pass to the fuzzer"), cl::ZeroOrMore,
63 cl::PositionalEatsArgs);
64 static std::vector ModifiedArgv;
65
66 enum OutputFileType {
67 OFT_Null,
68 OFT_AssemblyFile,
69 OFT_ObjectFile
70 };
71 static cl::opt
72 FileType("filetype", cl::init(OFT_AssemblyFile),
73 cl::desc("Choose an output file type:"),
74 cl::values(
75 clEnumValN(OFT_AssemblyFile, "asm",
76 "Emit an assembly ('.s') file"),
77 clEnumValN(OFT_Null, "null",
78 "Don't emit anything (for timing purposes)"),
79 clEnumValN(OFT_ObjectFile, "obj",
80 "Emit a native object ('.o') file")));
81
82
83 class LLVMFuzzerInputBuffer : public MemoryBuffer
84 {
85 public:
86 LLVMFuzzerInputBuffer(const uint8_t *data_, size_t size_)
87 : Data(reinterpret_cast(data_)),
88 Size(size_) {
89 init(Data, Data+Size, false);
90 }
91
92
93 virtual BufferKind getBufferKind() const {
94 return MemoryBuffer_Malloc; // it's not disk-backed so I think that's
95 // the intent ... though AFAIK it
96 // probably came from an mmap or sbrk
97 }
98
99 private:
100 const char *Data;
101 size_t Size;
102 };
103
104 static int AssembleInput(const char *ProgName, const Target *TheTarget,
105 SourceMgr &SrcMgr, MCContext &Ctx, MCStreamer &Str,
106 MCAsmInfo &MAI, MCSubtargetInfo &STI,
107 MCInstrInfo &MCII, MCTargetOptions &MCOptions) {
108 static const bool NoInitialTextSection = false;
109
110 std::unique_ptr Parser(
111 createMCAsmParser(SrcMgr, Ctx, Str, MAI));
112
113 std::unique_ptr TAP(
114 TheTarget->createMCAsmParser(STI, *Parser, MCII, MCOptions));
115
116 if (!TAP) {
117 errs() << ProgName
118 << ": error: this target '" << TripleName
119 << "', does not support assembly parsing.\n";
120 abort();
121 }
122
123 Parser->setTargetParser(*TAP);
124
125 return Parser->Run(NoInitialTextSection);
126 }
127
128
129 int AssembleOneInput(const uint8_t *Data, size_t Size) {
130 const bool ShowInst = false;
131 const bool AsmVerbose = false;
132 const bool UseDwarfDirectory = true;
133
134 Triple TheTriple(Triple::normalize(TripleName));
135
136 SourceMgr SrcMgr;
137
138 std::unique_ptr BufferPtr(new LLVMFuzzerInputBuffer(Data, Size));
139
140 // Tell SrcMgr about this buffer, which is what the parser will pick up.
141 SrcMgr.AddNewSourceBuffer(std::move(BufferPtr), SMLoc());
142
143 static const std::vector NoIncludeDirs;
144 SrcMgr.setIncludeDirs(NoIncludeDirs);
145
146 static std::string ArchName;
147 std::string Error;
148 const Target *TheTarget = TargetRegistry::lookupTarget(ArchName, TheTriple,
149 Error);
150 if (!TheTarget) {
151 errs() << "error: this target '" << TheTriple.normalize()
152 << "/" << ArchName << "', was not found: '" << Error << "'\n";
153
154 abort();
155 }
156
157 std::unique_ptr MRI(TheTarget->createMCRegInfo(TripleName));
158 if (!MRI) {
159 errs() << "Unable to create target register info!";
160 abort();
161 }
162
163 std::unique_ptr MAI(TheTarget->createMCAsmInfo(*MRI, TripleName));
164 if (!MAI) {
165 errs() << "Unable to create target asm info!";
166 abort();
167 }
168
169
170 MCObjectFileInfo MOFI;
171 MCContext Ctx(MAI.get(), MRI.get(), &MOFI, &SrcMgr);
172
173 static const bool UsePIC = false;
174 static const CodeModel::Model CMModel = CodeModel::Default;
175 MOFI.InitMCObjectFileInfo(TheTriple, UsePIC, CMModel, Ctx);
176
177 const unsigned OutputAsmVariant = 0;
178 std::unique_ptr MCII(TheTarget->createMCInstrInfo());
179 MCInstPrinter *IP = TheTarget->createMCInstPrinter(Triple(TripleName), OutputAsmVariant,
180 *MAI, *MCII, *MRI);
181 if (!IP) {
182 errs()
183 << "error: unable to create instruction printer for target triple '"
184 << TheTriple.normalize() << "' with assembly variant "
185 << OutputAsmVariant << ".\n";
186
187 abort();
188 }
189
190 const char *ProgName = "llvm-mc-fuzzer";
191 std::unique_ptr STI(
192 TheTarget->createMCSubtargetInfo(TripleName, MCPU, FeaturesStr));
193 MCCodeEmitter *CE = nullptr;
194 MCAsmBackend *MAB = nullptr;
195
196 MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags();
197
198 std::string OutputString;
199 raw_string_ostream Out(OutputString);
200 auto FOut = llvm::make_unique(Out);
201
202 std::unique_ptr Str;
203
204 if (FileType == OFT_AssemblyFile) {
205 Str.reset(TheTarget->createAsmStreamer(
206 Ctx, std::move(FOut), AsmVerbose,
207 UseDwarfDirectory, IP, CE, MAB, ShowInst));
208 } else {
209 assert(FileType == OFT_ObjectFile && "Invalid file type!");
210
211 std::error_code EC;
212 const std::string OutputFilename = "-";
213 auto Out = llvm::make_unique(OutputFilename, EC,
214 sys::fs::F_None);
215 if (EC) {
216 errs() << EC.message() << '\n';
217 abort();
218 }
219
220 // Don't waste memory on names of temp labels.
221 Ctx.setUseNamesOnTempLabels(false);
222
223 std::unique_ptr BOS;
224 raw_pwrite_stream *OS = &Out->os();
225 if (!Out->os().supportsSeeking()) {
226 BOS = make_unique(Out->os());
227 OS = BOS.get();
228 }
229
230 MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx);
231 MCAsmBackend *MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, MCPU,
232 MCOptions);
233 Str.reset(TheTarget->createMCObjectStreamer(
234 TheTriple, Ctx, *MAB, *OS, CE, *STI, MCOptions.MCRelaxAll,
235 MCOptions.MCIncrementalLinkerCompatible,
236 /*DWARFMustBeAtTheEnd*/ false));
237 }
238 const int Res = AssembleInput(ProgName, TheTarget, SrcMgr, Ctx, *Str, *MAI, *STI,
239 *MCII, MCOptions);
240
241 (void) Res;
242
243 return 0;
244 }
245
246 int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
247 return AssembleOneInput(Data, Size);
248 }
249
250 int LLVMFuzzerInitialize(int *argc, char ***argv) {
251 // The command line is unusual compared to other fuzzers due to the need to
252 // specify the target. Options like -triple, -mcpu, and -mattr work like
253 // their counterparts in llvm-mc, while -fuzzer-args collects options for the
254 // fuzzer itself.
255 //
256 // Examples:
257 //
258 // Fuzz the big-endian MIPS32R6 disassembler using 100,000 inputs of up to
259 // 4-bytes each and use the contents of ./corpus as the test corpus:
260 // llvm-mc-fuzzer -triple mips-linux-gnu -mcpu=mips32r6 -disassemble \
261 // -fuzzer-args -max_len=4 -runs=100000 ./corpus
262 //
263 // Infinitely fuzz the little-endian MIPS64R2 disassembler with the MSA
264 // feature enabled using up to 64-byte inputs:
265 // llvm-mc-fuzzer -triple mipsel-linux-gnu -mcpu=mips64r2 -mattr=msa \
266 // -disassemble -fuzzer-args ./corpus
267 //
268 // If your aim is to find instructions that are not tested, then it is
269 // advisable to constrain the maximum input size to a single instruction
270 // using -max_len as in the first example. This results in a test corpus of
271 // individual instructions that test unique paths. Without this constraint,
272 // there will be considerable redundancy in the corpus.
273
274 char **OriginalArgv = *argv;
275
276 LLVMInitializeAllTargetInfos();
277 LLVMInitializeAllTargetMCs();
278 LLVMInitializeAllAsmParsers();
279
280 cl::ParseCommandLineOptions(*argc, OriginalArgv);
281
282 // Rebuild the argv without the arguments llvm-mc-fuzzer consumed so that
283 // the driver can parse its arguments.
284 //
285 // FuzzerArgs cannot provide the non-const pointer that OriginalArgv needs.
286 // Re-use the strings from OriginalArgv instead of copying FuzzerArg to a
287 // non-const buffer to avoid the need to clean up when the fuzzer terminates.
288 ModifiedArgv.push_back(OriginalArgv[0]);
289 for (const auto &FuzzerArg : FuzzerArgs) {
290 for (int i = 1; i < *argc; ++i) {
291 if (FuzzerArg == OriginalArgv[i])
292 ModifiedArgv.push_back(OriginalArgv[i]);
293 }
294 }
295 *argc = ModifiedArgv.size();
296 *argv = ModifiedArgv.data();
297
298 // Package up features to be passed to target/subtarget
299 // We have to pass it via a global since the callback doesn't
300 // permit any user data.
301 if (MAttrs.size()) {
302 SubtargetFeatures Features;
303 for (unsigned i = 0; i != MAttrs.size(); ++i)
304 Features.AddFeature(MAttrs[i]);
305 FeaturesStr = Features.getString();
306 }
307
308 if (TripleName.empty())
309 TripleName = sys::getDefaultTargetTriple();
310
311 return 0;
312 }
0 if( LLVM_USE_SANITIZE_COVERAGE )
1 include_directories(BEFORE
2 ${CMAKE_CURRENT_SOURCE_DIR}/../../lib/Fuzzer)
3
4 set(LLVM_LINK_COMPONENTS
5 AllTargetsAsmPrinters
6 AllTargetsDescs
7 AllTargetsDisassemblers
8 AllTargetsInfos
9 MC
10 MCDisassembler
11 MCParser
12 Support
13 )
14 add_llvm_tool(llvm-mc-disassemble-fuzzer
15 llvm-mc-disassemble-fuzzer.cpp)
16
17 target_link_libraries(llvm-mc-disassemble-fuzzer
18 LLVMFuzzer
19 )
20 endif()
0 //===--- llvm-mc-fuzzer.cpp - Fuzzer for the MC layer ---------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 //===----------------------------------------------------------------------===//
10
11 #include "FuzzerInterface.h"
12 #include "llvm-c/Disassembler.h"
13 #include "llvm-c/Target.h"
14 #include "llvm/MC/SubtargetFeature.h"
15 #include "llvm/Support/CommandLine.h"
16 #include "llvm/Support/raw_ostream.h"
17
18 using namespace llvm;
19
20 const unsigned AssemblyTextBufSize = 80;
21
22 static cl::opt
23 TripleName("triple", cl::desc("Target triple to assemble for, "
24 "see -version for available targets"));
25
26 static cl::opt
27 MCPU("mcpu",
28 cl::desc("Target a specific cpu type (-mcpu=help for details)"),
29 cl::value_desc("cpu-name"), cl::init(""));
30
31 // This is useful for variable-length instruction sets.
32 static cl::opt InsnLimit(
33 "insn-limit",
34 cl::desc("Limit the number of instructions to process (0 for no limit)"),
35 cl::value_desc("count"), cl::init(0));
36
37 static cl::list
38 MAttrs("mattr", cl::CommaSeparated,
39 cl::desc("Target specific attributes (-mattr=help for details)"),
40 cl::value_desc("a1,+a2,-a3,..."));
41 // The feature string derived from -mattr's values.
42 std::string FeaturesStr;
43
44 static cl::list
45 FuzzerArgs("fuzzer-args", cl::Positional,
46 cl::desc("Options to pass to the fuzzer"), cl::ZeroOrMore,
47 cl::PositionalEatsArgs);
48 static std::vector ModifiedArgv;
49
50 int DisassembleOneInput(const uint8_t *Data, size_t Size) {
51 char AssemblyText[AssemblyTextBufSize];
52
53 std::vector DataCopy(Data, Data + Size);
54
55 LLVMDisasmContextRef Ctx = LLVMCreateDisasmCPUFeatures(
56 TripleName.c_str(), MCPU.c_str(), FeaturesStr.c_str(), nullptr, 0,
57 nullptr, nullptr);
58 assert(Ctx);
59 uint8_t *p = DataCopy.data();
60 unsigned Consumed;
61 unsigned InstructionsProcessed = 0;
62 do {
63 Consumed = LLVMDisasmInstruction(Ctx, p, Size, 0, AssemblyText,
64 AssemblyTextBufSize);
65 Size -= Consumed;
66 p += Consumed;
67
68 InstructionsProcessed ++;
69 if (InsnLimit != 0 && InstructionsProcessed < InsnLimit)
70 break;
71 } while (Consumed != 0);
72 LLVMDisasmDispose(Ctx);
73 return 0;
74 }
75
76 int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
77 return DisassembleOneInput(Data, Size);
78 }
79
80 int LLVMFuzzerInitialize(int *argc, char ***argv) {
81 // The command line is unusual compared to other fuzzers due to the need to
82 // specify the target. Options like -triple, -mcpu, and -mattr work like
83 // their counterparts in llvm-mc, while -fuzzer-args collects options for the
84 // fuzzer itself.
85 //
86 // Examples:
87 //
88 // Fuzz the big-endian MIPS32R6 disassembler using 100,000 inputs of up to
89 // 4-bytes each and use the contents of ./corpus as the test corpus:
90 // llvm-mc-fuzzer -triple mips-linux-gnu -mcpu=mips32r6 -disassemble \
91 // -fuzzer-args -max_len=4 -runs=100000 ./corpus
92 //
93 // Infinitely fuzz the little-endian MIPS64R2 disassembler with the MSA
94 // feature enabled using up to 64-byte inputs:
95 // llvm-mc-fuzzer -triple mipsel-linux-gnu -mcpu=mips64r2 -mattr=msa \
96 // -disassemble -fuzzer-args ./corpus
97 //
98 // If your aim is to find instructions that are not tested, then it is
99 // advisable to constrain the maximum input size to a single instruction
100 // using -max_len as in the first example. This results in a test corpus of
101 // individual instructions that test unique paths. Without this constraint,
102 // there will be considerable redundancy in the corpus.
103
104 char **OriginalArgv = *argv;
105
106 LLVMInitializeAllTargetInfos();
107 LLVMInitializeAllTargetMCs();
108 LLVMInitializeAllDisassemblers();
109
110 cl::ParseCommandLineOptions(*argc, OriginalArgv);
111
112 // Rebuild the argv without the arguments llvm-mc-fuzzer consumed so that
113 // the driver can parse its arguments.
114 //
115 // FuzzerArgs cannot provide the non-const pointer that OriginalArgv needs.
116 // Re-use the strings from OriginalArgv instead of copying FuzzerArg to a
117 // non-const buffer to avoid the need to clean up when the fuzzer terminates.
118 ModifiedArgv.push_back(OriginalArgv[0]);
119 for (const auto &FuzzerArg : FuzzerArgs) {
120 for (int i = 1; i < *argc; ++i) {
121 if (FuzzerArg == OriginalArgv[i])
122 ModifiedArgv.push_back(OriginalArgv[i]);
123 }
124 }
125 *argc = ModifiedArgv.size();
126 *argv = ModifiedArgv.data();
127
128 // Package up features to be passed to target/subtarget
129 // We have to pass it via a global since the callback doesn't
130 // permit any user data.
131 if (MAttrs.size()) {
132 SubtargetFeatures Features;
133 for (unsigned i = 0; i != MAttrs.size(); ++i)
134 Features.AddFeature(MAttrs[i]);
135 FeaturesStr = Features.getString();
136 }
137
138 if (TripleName.empty())
139 TripleName = sys::getDefaultTargetTriple();
140
141 return 0;
142 }
+0
-18
tools/llvm-mc-fuzzer/CMakeLists.txt less more
None if( LLVM_USE_SANITIZE_COVERAGE )
1 include_directories(BEFORE
2 ${CMAKE_CURRENT_SOURCE_DIR}/../../lib/Fuzzer)
3
4 set(LLVM_LINK_COMPONENTS
5 AllTargetsDescs
6 AllTargetsDisassemblers
7 AllTargetsInfos
8 MC
9 MCDisassembler
10 Support
11 )
12 add_llvm_tool(llvm-mc-fuzzer
13 llvm-mc-fuzzer.cpp)
14 target_link_libraries(llvm-mc-fuzzer
15 LLVMFuzzer
16 )
17 endif()
+0
-159
tools/llvm-mc-fuzzer/llvm-mc-fuzzer.cpp less more
None //===--- llvm-mc-fuzzer.cpp - Fuzzer for the MC layer ---------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 //===----------------------------------------------------------------------===//
10
11 #include "FuzzerInterface.h"
12 #include "llvm-c/Disassembler.h"
13 #include "llvm-c/Target.h"
14 #include "llvm/MC/SubtargetFeature.h"
15 #include "llvm/Support/CommandLine.h"
16 #include "llvm/Support/raw_ostream.h"
17
18 using namespace llvm;
19
20 const unsigned AssemblyTextBufSize = 80;
21
22 enum ActionType {
23 AC_Assemble,
24 AC_Disassemble
25 };
26
27 static cl::opt
28 Action(cl::desc("Action to perform:"),
29 cl::init(AC_Assemble),
30 cl::values(clEnumValN(AC_Assemble, "assemble",
31 "Assemble a .s file (default)"),
32 clEnumValN(AC_Disassemble, "disassemble",
33 "Disassemble strings of hex bytes")));
34
35 static cl::opt
36 TripleName("triple", cl::desc("Target triple to assemble for, "
37 "see -version for available targets"));
38
39 static cl::opt
40 MCPU("mcpu",
41 cl::desc("Target a specific cpu type (-mcpu=help for details)"),
42 cl::value_desc("cpu-name"), cl::init(""));
43
44 // This is useful for variable-length instruction sets.
45 static cl::opt InsnLimit(
46 "insn-limit",
47 cl::desc("Limit the number of instructions to process (0 for no limit)"),
48 cl::value_desc("count"), cl::init(0));
49
50 static cl::list
51 MAttrs("mattr", cl::CommaSeparated,
52 cl::desc("Target specific attributes (-mattr=help for details)"),
53 cl::value_desc("a1,+a2,-a3,..."));
54 // The feature string derived from -mattr's values.
55 std::string FeaturesStr;
56
57 static cl::list
58 FuzzerArgs("fuzzer-args", cl::Positional,
59 cl::desc("Options to pass to the fuzzer"), cl::ZeroOrMore,
60 cl::PositionalEatsArgs);
61 static std::vector ModifiedArgv;
62
63 int DisassembleOneInput(const uint8_t *Data, size_t Size) {
64 char AssemblyText[AssemblyTextBufSize];
65
66 std::vector DataCopy(Data, Data + Size);
67
68 LLVMDisasmContextRef Ctx = LLVMCreateDisasmCPUFeatures(
69 TripleName.c_str(), MCPU.c_str(), FeaturesStr.c_str(), nullptr, 0,
70 nullptr, nullptr);
71 assert(Ctx);
72 uint8_t *p = DataCopy.data();
73 unsigned Consumed;
74 unsigned InstructionsProcessed = 0;
75 do {
76 Consumed = LLVMDisasmInstruction(Ctx, p, Size, 0, AssemblyText,
77 AssemblyTextBufSize);
78 Size -= Consumed;
79 p += Consumed;
80
81 InstructionsProcessed ++;
82 if (InsnLimit != 0 && InstructionsProcessed < InsnLimit)
83 break;
84 } while (Consumed != 0);
85 LLVMDisasmDispose(Ctx);
86 return 0;
87 }
88
89 int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
90 if (Action == AC_Assemble)
91 errs() << "error: -assemble is not implemented\n";
92 else if (Action == AC_Disassemble)
93 return DisassembleOneInput(Data, Size);
94
95 llvm_unreachable("Unknown action");
96 return 0;
97 }
98
99 int LLVMFuzzerInitialize(int *argc, char ***argv) {
100 // The command line is unusual compared to other fuzzers due to the need to
101 // specify the target. Options like -triple, -mcpu, and -mattr work like
102 // their counterparts in llvm-mc, while -fuzzer-args collects options for the
103 // fuzzer itself.
104 //
105 // Examples:
106 //
107 // Fuzz the big-endian MIPS32R6 disassembler using 100,000 inputs of up to
108 // 4-bytes each and use the contents of ./corpus as the test corpus:
109 // llvm-mc-fuzzer -triple mips-linux-gnu -mcpu=mips32r6 -disassemble \
110 // -fuzzer-args -max_len=4 -runs=100000 ./corpus
111 //
112 // Infinitely fuzz the little-endian MIPS64R2 disassembler with the MSA
113 // feature enabled using up to 64-byte inputs:
114 // llvm-mc-fuzzer -triple mipsel-linux-gnu -mcpu=mips64r2 -mattr=msa \
115 // -disassemble -fuzzer-args ./corpus
116 //
117 // If your aim is to find instructions that are not tested, then it is
118 // advisable to constrain the maximum input size to a single instruction
119 // using -max_len as in the first example. This results in a test corpus of
120 // individual instructions that test unique paths. Without this constraint,
121 // there will be considerable redundancy in the corpus.
122
123 char **OriginalArgv = *argv;
124
125 LLVMInitializeAllTargetInfos();
126 LLVMInitializeAllTargetMCs();
127 LLVMInitializeAllDisassemblers();
128
129 cl::ParseCommandLineOptions(*argc, OriginalArgv);
130
131 // Rebuild the argv without the arguments llvm-mc-fuzzer consumed so that
132 // the driver can parse its arguments.
133 //
134 // FuzzerArgs cannot provide the non-const pointer that OriginalArgv needs.
135 // Re-use the strings from OriginalArgv instead of copying FuzzerArg to a
136 // non-const buffer to avoid the need to clean up when the fuzzer terminates.
137 ModifiedArgv.push_back(OriginalArgv[0]);
138 for (const auto &FuzzerArg : FuzzerArgs) {
139 for (int i = 1; i < *argc; ++i) {
140 if (FuzzerArg == OriginalArgv[i])
141 ModifiedArgv.push_back(OriginalArgv[i]);
142 }
143 }
144 *argc = ModifiedArgv.size();
145 *argv = ModifiedArgv.data();
146
147 // Package up features to be passed to target/subtarget
148 // We have to pass it via a global since the callback doesn't
149 // permit any user data.
150 if (MAttrs.size()) {
151 SubtargetFeatures Features;
152 for (unsigned i = 0; i != MAttrs.size(); ++i)
153 Features.AddFeature(MAttrs[i]);
154 FeaturesStr = Features.getString();
155 }
156
157 return 0;
158 }