1 //===--- llvm-mc-fuzzer.cpp - Fuzzer for the MC layer ---------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 //===----------------------------------------------------------------------===//
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"
22 const unsigned AssemblyTextBufSize = 80;
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"),
38 static cl::opt<std::string>
39 TripleName("triple", cl::desc("Target triple to assemble for, "
40 "see -version for available targets"));
42 static cl::opt<std::string>
44 cl::desc("Target a specific cpu type (-mcpu=help for details)"),
45 cl::value_desc("cpu-name"), cl::init(""));
47 // This is useful for variable-length instruction sets.
48 static cl::opt<unsigned> InsnLimit(
50 cl::desc("Limit the number of instructions to process (0 for no limit)"),
51 cl::value_desc("count"), cl::init(0));
53 static cl::list<std::string>
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;
60 static cl::list<std::string>
61 FuzzerArgv("fuzzer-args", cl::Positional,
62 cl::desc("Options to pass to the fuzzer"), cl::ZeroOrMore,
63 cl::PositionalEatsArgs);
65 int DisassembleOneInput(const uint8_t *Data, size_t Size) {
66 char AssemblyText[AssemblyTextBufSize];
68 std::vector<uint8_t> DataCopy(Data, Data + Size);
70 LLVMDisasmContextRef Ctx = LLVMCreateDisasmCPUFeatures(
71 TripleName.c_str(), MCPU.c_str(), FeaturesStr.c_str(), nullptr, 0,
74 uint8_t *p = DataCopy.data();
76 unsigned InstructionsProcessed = 0;
78 Consumed = LLVMDisasmInstruction(Ctx, p, Size, 0, AssemblyText,
83 InstructionsProcessed ++;
84 if (InsnLimit != 0 && InstructionsProcessed < InsnLimit)
86 } while (Consumed != 0);
87 LLVMDisasmDispose(Ctx);
91 int main(int argc, char **argv) {
92 // The command line is unusual compared to other fuzzers due to the need to
93 // specify the target. Options like -triple, -mcpu, and -mattr work like
94 // their counterparts in llvm-mc, while -fuzzer-args collects options for the
99 // Fuzz the big-endian MIPS32R6 disassembler using 100,000 inputs of up to
100 // 4-bytes each and use the contents of ./corpus as the test corpus:
101 // llvm-mc-fuzzer -triple mips-linux-gnu -mcpu=mips32r6 -disassemble \
102 // -fuzzer-args -max_len=4 -runs=100000 ./corpus
104 // Infinitely fuzz the little-endian MIPS64R2 disassembler with the MSA
105 // feature enabled using up to 64-byte inputs:
106 // llvm-mc-fuzzer -triple mipsel-linux-gnu -mcpu=mips64r2 -mattr=msa \
107 // -disassemble -fuzzer-args ./corpus
109 // If your aim is to find instructions that are not tested, then it is
110 // advisable to constrain the maximum input size to a single instruction
111 // using -max_len as in the first example. This results in a test corpus of
112 // individual instructions that test unique paths. Without this constraint,
113 // there will be considerable redundancy in the corpus.
115 LLVMInitializeAllTargetInfos();
116 LLVMInitializeAllTargetMCs();
117 LLVMInitializeAllDisassemblers();
119 cl::ParseCommandLineOptions(argc, argv);
121 // Package up features to be passed to target/subtarget
122 // We have to pass it via a global since the callback doesn't
123 // permit any user data.
125 SubtargetFeatures Features;
126 for (unsigned i = 0; i != MAttrs.size(); ++i)
127 Features.AddFeature(MAttrs[i]);
128 FeaturesStr = Features.getString();
131 if (Action == AC_Assemble)
132 errs() << "error: -assemble is not implemented\n";
133 else if (Action == AC_Disassemble)
134 return fuzzer::FuzzerDriver(argc, argv, DisassembleOneInput);
136 llvm_unreachable("Unknown action");