llvm-mc-fuzzer: A fuzzing tool for the MC layer.
[oota-llvm.git] / tools / llvm-mc-fuzzer / llvm-mc-fuzzer.cpp
1 //===--- llvm-mc-fuzzer.cpp - Fuzzer for the MC layer ---------------------===//
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 //===----------------------------------------------------------------------===//
11
12 #include "llvm-c/Disassembler.h"
13 #include "llvm-c/Target.h"
14 #include "llvm/ADT/ArrayRef.h"
15 #include "llvm/MC/SubtargetFeature.h"
16 #include "llvm/Support/CommandLine.h"
17 #include "llvm/Support/raw_ostream.h"
18 #include "FuzzerInterface.h"
19
20 using namespace llvm;
21
22 const unsigned AssemblyTextBufSize = 80;
23
24 enum ActionType {
25   AC_Assemble,
26   AC_Disassemble
27 };
28
29 static cl::opt<ActionType>
30 Action(cl::desc("Action to perform:"),
31        cl::init(AC_Assemble),
32        cl::values(clEnumValN(AC_Assemble, "assemble",
33                              "Assemble a .s file (default)"),
34                   clEnumValN(AC_Disassemble, "disassemble",
35                              "Disassemble strings of hex bytes"),
36                   clEnumValEnd));
37
38 static cl::opt<std::string>
39     TripleName("triple", cl::desc("Target triple to assemble for, "
40                                   "see -version for available targets"));
41
42 static cl::opt<std::string>
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 static cl::list<std::string>
48     MAttrs("mattr", cl::CommaSeparated,
49            cl::desc("Target specific attributes (-mattr=help for details)"),
50            cl::value_desc("a1,+a2,-a3,..."));
51 // The feature string derived from -mattr's values.
52 std::string FeaturesStr;
53
54 static cl::list<std::string>
55     FuzzerArgv("fuzzer-args", cl::Positional,
56                cl::desc("Options to pass to the fuzzer"), cl::ZeroOrMore,
57                cl::PositionalEatsArgs);
58
59 void DisassembleOneInput(const uint8_t *Data, size_t Size) {
60   char AssemblyText[AssemblyTextBufSize];
61
62   std::vector<uint8_t> DataCopy(Data, Data + Size);
63
64   LLVMDisasmContextRef Ctx = LLVMCreateDisasmCPUFeatures(
65       TripleName.c_str(), MCPU.c_str(), FeaturesStr.c_str(), nullptr, 0,
66       nullptr, nullptr);
67   assert(Ctx);
68   uint8_t *p = DataCopy.data();
69   unsigned Consumed;
70   do {
71     Consumed = LLVMDisasmInstruction(Ctx, p, Size, 0, AssemblyText,
72                                      AssemblyTextBufSize);
73     Size -= Consumed;
74     p += Consumed;
75   } while (Consumed != 0);
76   LLVMDisasmDispose(Ctx);
77 }
78
79 int main(int argc, char **argv) {
80   // The command line is unusual compared to other fuzzers due to the need to
81   // specify the target. Options like -triple, -mcpu, and -mattr work like
82   // their counterparts in llvm-mc, while -fuzzer-args collects options for the
83   // fuzzer itself.
84   //
85   // Examples:
86   //
87   // Fuzz the big-endian MIPS32R6 disassembler using 100,000 inputs of up to
88   // 4-bytes each and use the contents of ./corpus as the test corpus:
89   //   llvm-mc-fuzzer -triple mips-linux-gnu -mcpu=mips32r6 -disassemble \
90   //       -fuzzer-args -max_len=4 -runs=100000 ./corpus
91   //
92   // Infinitely fuzz the little-endian MIPS64R2 disassembler with the MSA
93   // feature enabled using up to 64-byte inputs:
94   //   llvm-mc-fuzzer -triple mipsel-linux-gnu -mcpu=mips64r2 -mattr=msa \
95   //       -disassemble -fuzzer-args ./corpus
96   //
97   // If your aim is to find instructions that are not tested, then it is
98   // advisable to constrain the maximum input size to a single instruction
99   // using -max_len as in the first example. This results in a test corpus of
100   // individual instructions that test unique paths. Without this constraint,
101   // there will be considerable redundancy in the corpus.
102
103   LLVMInitializeAllTargetInfos();
104   LLVMInitializeAllTargetMCs();
105   LLVMInitializeAllDisassemblers();
106
107   cl::ParseCommandLineOptions(argc, argv);
108
109   // Package up features to be passed to target/subtarget
110   // We have to pass it via a global since the callback doesn't
111   // permit any user data.
112   if (MAttrs.size()) {
113     SubtargetFeatures Features;
114     for (unsigned i = 0; i != MAttrs.size(); ++i)
115       Features.AddFeature(MAttrs[i]);
116     FeaturesStr = Features.getString();
117   }
118
119   // Insert the program name into the FuzzerArgv.
120   FuzzerArgv.insert(FuzzerArgv.begin(), argv[0]);
121
122   if (Action == AC_Assemble)
123     errs() << "error: -assemble is not implemented\n";
124   else if (Action == AC_Disassemble)
125     return fuzzer::FuzzerDriver(FuzzerArgv, DisassembleOneInput);
126
127   llvm_unreachable("Unknown action");
128   return 1;
129 }