diff options
author | Daniel Sanders <daniel.sanders@imgtec.com> | 2015-09-16 11:49:49 +0000 |
---|---|---|
committer | Daniel Sanders <daniel.sanders@imgtec.com> | 2015-09-16 11:49:49 +0000 |
commit | 205d1993bbdf311ae9fefd295b3c5760b69f86c0 (patch) | |
tree | 2c2e734286d3e29dbcde78f9e7883507ef0784aa /llvm/tools/llvm-mc-fuzzer/llvm-mc-fuzzer.cpp | |
parent | d926465342497afef60cc7f191bf23d0bbd7a448 (diff) | |
download | bcm5719-llvm-205d1993bbdf311ae9fefd295b3c5760b69f86c0.tar.gz bcm5719-llvm-205d1993bbdf311ae9fefd295b3c5760b69f86c0.zip |
llvm-mc-fuzzer: A fuzzing tool for the MC layer.
Summary:
Only the disassembler is supported in this patch but it has already found a few
issues in the Mips disassembler (mostly invalid instructions being successfully
disassembled).
Reviewers: kcc
Subscribers: russell.gallop, silvas, kcc, llvm-commits
Differential Revision: http://reviews.llvm.org/D12723
llvm-svn: 247786
Diffstat (limited to 'llvm/tools/llvm-mc-fuzzer/llvm-mc-fuzzer.cpp')
-rw-r--r-- | llvm/tools/llvm-mc-fuzzer/llvm-mc-fuzzer.cpp | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/llvm/tools/llvm-mc-fuzzer/llvm-mc-fuzzer.cpp b/llvm/tools/llvm-mc-fuzzer/llvm-mc-fuzzer.cpp new file mode 100644 index 00000000000..7b891325571 --- /dev/null +++ b/llvm/tools/llvm-mc-fuzzer/llvm-mc-fuzzer.cpp @@ -0,0 +1,129 @@ +//===--- llvm-mc-fuzzer.cpp - Fuzzer for the MC layer ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +//===----------------------------------------------------------------------===// + +#include "llvm-c/Disassembler.h" +#include "llvm-c/Target.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/MC/SubtargetFeature.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/raw_ostream.h" +#include "FuzzerInterface.h" + +using namespace llvm; + +const unsigned AssemblyTextBufSize = 80; + +enum ActionType { + AC_Assemble, + AC_Disassemble +}; + +static cl::opt<ActionType> +Action(cl::desc("Action to perform:"), + cl::init(AC_Assemble), + cl::values(clEnumValN(AC_Assemble, "assemble", + "Assemble a .s file (default)"), + clEnumValN(AC_Disassemble, "disassemble", + "Disassemble strings of hex bytes"), + clEnumValEnd)); + +static cl::opt<std::string> + TripleName("triple", cl::desc("Target triple to assemble for, " + "see -version for available targets")); + +static cl::opt<std::string> + MCPU("mcpu", + cl::desc("Target a specific cpu type (-mcpu=help for details)"), + cl::value_desc("cpu-name"), cl::init("")); + +static cl::list<std::string> + MAttrs("mattr", cl::CommaSeparated, + cl::desc("Target specific attributes (-mattr=help for details)"), + cl::value_desc("a1,+a2,-a3,...")); +// The feature string derived from -mattr's values. +std::string FeaturesStr; + +static cl::list<std::string> + FuzzerArgv("fuzzer-args", cl::Positional, + cl::desc("Options to pass to the fuzzer"), cl::ZeroOrMore, + cl::PositionalEatsArgs); + +void DisassembleOneInput(const uint8_t *Data, size_t Size) { + char AssemblyText[AssemblyTextBufSize]; + + std::vector<uint8_t> DataCopy(Data, Data + Size); + + LLVMDisasmContextRef Ctx = LLVMCreateDisasmCPUFeatures( + TripleName.c_str(), MCPU.c_str(), FeaturesStr.c_str(), nullptr, 0, + nullptr, nullptr); + assert(Ctx); + uint8_t *p = DataCopy.data(); + unsigned Consumed; + do { + Consumed = LLVMDisasmInstruction(Ctx, p, Size, 0, AssemblyText, + AssemblyTextBufSize); + Size -= Consumed; + p += Consumed; + } while (Consumed != 0); + LLVMDisasmDispose(Ctx); +} + +int main(int argc, char **argv) { + // The command line is unusual compared to other fuzzers due to the need to + // specify the target. Options like -triple, -mcpu, and -mattr work like + // their counterparts in llvm-mc, while -fuzzer-args collects options for the + // fuzzer itself. + // + // Examples: + // + // Fuzz the big-endian MIPS32R6 disassembler using 100,000 inputs of up to + // 4-bytes each and use the contents of ./corpus as the test corpus: + // llvm-mc-fuzzer -triple mips-linux-gnu -mcpu=mips32r6 -disassemble \ + // -fuzzer-args -max_len=4 -runs=100000 ./corpus + // + // Infinitely fuzz the little-endian MIPS64R2 disassembler with the MSA + // feature enabled using up to 64-byte inputs: + // llvm-mc-fuzzer -triple mipsel-linux-gnu -mcpu=mips64r2 -mattr=msa \ + // -disassemble -fuzzer-args ./corpus + // + // If your aim is to find instructions that are not tested, then it is + // advisable to constrain the maximum input size to a single instruction + // using -max_len as in the first example. This results in a test corpus of + // individual instructions that test unique paths. Without this constraint, + // there will be considerable redundancy in the corpus. + + LLVMInitializeAllTargetInfos(); + LLVMInitializeAllTargetMCs(); + LLVMInitializeAllDisassemblers(); + + cl::ParseCommandLineOptions(argc, argv); + + // Package up features to be passed to target/subtarget + // We have to pass it via a global since the callback doesn't + // permit any user data. + if (MAttrs.size()) { + SubtargetFeatures Features; + for (unsigned i = 0; i != MAttrs.size(); ++i) + Features.AddFeature(MAttrs[i]); + FeaturesStr = Features.getString(); + } + + // Insert the program name into the FuzzerArgv. + FuzzerArgv.insert(FuzzerArgv.begin(), argv[0]); + + if (Action == AC_Assemble) + errs() << "error: -assemble is not implemented\n"; + else if (Action == AC_Disassemble) + return fuzzer::FuzzerDriver(FuzzerArgv, DisassembleOneInput); + + llvm_unreachable("Unknown action"); + return 1; +} |