Index: tools/llvm-mc-fuzzer/CMakeLists.txt =================================================================== --- /dev/null +++ tools/llvm-mc-fuzzer/CMakeLists.txt @@ -0,0 +1,18 @@ +if( LLVM_USE_SANITIZE_COVERAGE ) + include_directories(BEFORE + ${CMAKE_CURRENT_SOURCE_DIR}/../../lib/Fuzzer) + + set(LLVM_LINK_COMPONENTS + AllTargetsDescs + AllTargetsDisassemblers + AllTargetsInfos + MC + MCDisassembler + Support + ) + add_llvm_tool(llvm-mc-fuzzer + llvm-mc-fuzzer.cpp) + target_link_libraries(llvm-mc-fuzzer + LLVMFuzzerNoMain + ) +endif() Index: tools/llvm-mc-fuzzer/llvm-mc-fuzzer.cpp =================================================================== --- /dev/null +++ tools/llvm-mc-fuzzer/llvm-mc-fuzzer.cpp @@ -0,0 +1,124 @@ +//===--- 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; + +#define CHAR_BUF_SIZE 80 + +enum ActionType { + AC_Assemble, + AC_Disassemble +}; + +static cl::opt +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 + TripleName("triple", cl::desc("Target triple to assemble for, " + "see -version for available targets")); + +static cl::opt + MCPU("mcpu", + cl::desc("Target a specific cpu type (-mcpu=help for details)"), + cl::value_desc("cpu-name"), cl::init("")); + +static cl::list + 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 + FuzzerOptions("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 s[CHAR_BUF_SIZE]; + + uint8_t *DataCopy = new uint8_t[Size]; + memcpy(DataCopy, Data, Size); + + LLVMDisasmContextRef Ctx = LLVMCreateDisasmCPUFeatures( + TripleName.c_str(), MCPU.c_str(), FeaturesStr.c_str(), nullptr, 0, + nullptr, nullptr); + assert(Ctx); + uint8_t *p = DataCopy; + unsigned Consumed; + do { + Consumed = LLVMDisasmInstruction(Ctx, p, Size, 0, s, CHAR_BUF_SIZE); + Size -= Consumed; + p += Consumed; + } while (Consumed != 0); + LLVMDisasmDispose(Ctx); + + delete[] DataCopy; +} + +int main(int argc, char **argv) { + 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(); + } + + // Build an argv for libFuzzer to parse. + std::vector FuzzerArgv = { argv[0] }; + for (const auto &I : FuzzerOptions) { + char *Arg = new char[I.size()+1]; + strcpy(Arg, I.c_str()); + FuzzerArgv.push_back(Arg); + } + + void (*TestOneInput)(const uint8_t *, size_t) = nullptr; + + if (Action == AC_Assemble) + errs() << "error: -assemble is not implemented\n"; + else if (Action == AC_Disassemble) + TestOneInput = DisassembleOneInput; + else + llvm_unreachable("Unknown action"); + + auto Result = fuzzer::FuzzerDriver(FuzzerArgv.size(), FuzzerArgv.data(), + TestOneInput); + + // Clean up the temporary argv. + FuzzerArgv.erase(FuzzerArgv.begin()); + for (const auto &I : FuzzerArgv) + delete[] I; + + return Result; +}