Chromium Code Reviews| Index: tools/pnacl-bcfuzz/pnacl-bcfuzz.cpp |
| diff --git a/tools/pnacl-bcfuzz/pnacl-bcfuzz.cpp b/tools/pnacl-bcfuzz/pnacl-bcfuzz.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..75c0357c38e7d6e13c1a85659351672b31b2382a |
| --- /dev/null |
| +++ b/tools/pnacl-bcfuzz/pnacl-bcfuzz.cpp |
| @@ -0,0 +1,172 @@ |
| +//===-- pnacl-bcfuzz.cpp - Record fuzzer for PNaCl bitcode ----------------===// |
| +// |
| +//===----------------------------------------------------------------------===// |
| +// |
| +// Generates (record-level) fuzzed PNaCl bitcode files from an input |
| +// PNaCl bitcode file. |
| +// |
| +//===----------------------------------------------------------------------===// |
| + |
| +#include "llvm/Bitcode/NaCl/NaClFuzz.h" |
| +#include "llvm/Support/CommandLine.h" |
| +#include "llvm/Support/FileSystem.h" |
| +#include "llvm/Support/ManagedStatic.h" |
| +#include "llvm/Support/MemoryBuffer.h" |
| +#include "llvm/Support/PrettyStackTrace.h" |
| +#include "llvm/Support/Signals.h" |
| +#include "llvm/Support/ToolOutputFile.h" |
| + |
| +using namespace llvm; |
| +using namespace naclfuzz; |
| + |
| +static cl::opt<std::string> |
| +InputFilename(cl::Positional, cl::desc("<frozen file>"), cl::init("-")); |
| + |
| +static cl::opt<std::string> |
| +OutputPrefix("output", cl::desc("<output prefix>"), cl::init("")); |
| + |
| +static cl::opt<unsigned> |
| +FuzzCount("count", cl::desc("Number of fuzz results to generate"), |
| + cl::init(1)); |
| + |
| +static cl::opt<std::string> |
| +RandomSeed("random-seed", |
| + cl::desc("Use this value for seed of random number generator " |
| + "(rather than input)"), |
| + cl::init("")); |
| + |
| +static cl::opt<bool> |
| +ShowFuzzRecordDistribution( |
| + "record-distribution", |
| + cl::desc("Show distribution of record edits while fuzzing"), |
| + cl::init(false)); |
| + |
| +static cl::opt<bool> |
| +ShowFuzzEditDistribution( |
| + "edit-distribution", |
| + cl::desc("Show distribution of editing actions while fuzzing"), |
| + cl::init(false)); |
| + |
| +static cl::opt<unsigned> |
| +PercentageToEdit( |
| + "edit-percentage", |
| + cl::desc("Percentage of records to edit during fuzz (between 1 and" |
| + " '-percentage-base')"), |
| + cl::init(1)); |
| + |
| +static cl::opt<unsigned> |
| +PercentageBase( |
| + "percentage-base", |
| + cl::desc("Base that '-edit-precentage' is defined on (defaults to 100)"), |
| + cl::init(100)); |
| + |
| +static cl::opt<bool> |
| +Verbose("verbose", |
| + cl::desc("Show details of fuzzing/writing of bitcode files"), |
| + cl::init(false)); |
| + |
| +static void WriteOutputFile(SmallVectorImpl<char> &Buffer, |
| + std::string OutputFilename) { |
|
jvoung (off chromium)
2015/06/02 00:32:06
could be a StringRef or std::string &
Karl
2015/06/02 15:42:32
Done.
|
| + std::error_code EC; |
| + std::unique_ptr<tool_output_file> Out( |
| + new tool_output_file(OutputFilename, EC, sys::fs::F_None)); |
| + if (EC) { |
| + errs() << EC.message() << '\n'; |
| + exit(1); |
| + } |
| + |
| + for (SmallVectorImpl<char>::const_iterator |
| + Iter = Buffer.begin(), IterEnd = Buffer.end(); |
| + Iter != IterEnd; ++Iter) { |
| + Out->os() << *Iter; |
| + } |
| + |
| + // Declare success. |
| + Out->keep(); |
| +} |
| + |
| +int main(int argc, char **argv) { |
| + // Print a stack trace if we signal out. |
| + sys::PrintStackTraceOnErrorSignal(); |
| + PrettyStackTraceProgram X(argc, argv); |
| + |
| + cl::ParseCommandLineOptions(argc, argv, "Fuzz a PNaCl bitcode file\n"); |
| + |
| + if (!(0.0 <= PercentageToEdit && PercentageToEdit <= 1.0)) { |
|
jvoung (off chromium)
2015/06/02 00:32:06
no longer a float between 0 and 1... there's a bas
Karl
2015/06/02 15:42:32
Fixed.
|
| + errs() << "Edit percentage " << PercentageToEdit |
| + << " not between 0.0 and 1.0!\n"; |
| + return 1; |
| + } |
| + |
| + if (OutputPrefix.empty()) { |
| + errs() << "Output prefix not specified!\n"; |
| + return 1; |
| + } |
| + |
| + ErrorOr<std::unique_ptr<MemoryBuffer>> |
| + EC(MemoryBuffer::getFile(InputFilename)); |
|
jvoung (off chromium)
2015/06/02 00:32:06
Is there a better variable name than "EC" (EC is m
Karl
2015/06/02 15:42:32
Done.
|
| + if (!EC) { |
| + errs() << EC.getError().message() << "\n"; |
| + return 1; |
| + } |
| + |
| + // Stream to dump bitcode write errors to if not verbose. |
| + raw_null_ostream NullStrm; |
| + |
| + NaClMungedBitcode Bitcode(std::move(EC.get())); |
| + |
| + std::string RandSeed(RandomSeed); |
| + if (RandomSeed.empty()) |
| + RandSeed = InputFilename; |
| + |
| + DefaultRandomNumberGenerator Generator(RandomSeed); |
|
jvoung (off chromium)
2015/06/02 00:32:06
RandSeed
Karl
2015/06/02 15:42:32
Done.
|
| + |
| + std::unique_ptr<RecordFuzzer> Fuzzer( |
| + RecordFuzzer::createSimpleRecordFuzzer(Bitcode, Generator)); |
| + |
| + for (size_t i = 1; i <= FuzzCount; ++i) { |
| + Generator.saltSeed(i); |
| + std::string OutputFile; |
| + { |
| + raw_string_ostream StrBuf(OutputFile); |
| + StrBuf << OutputPrefix << "-" << i; |
| + StrBuf.flush(); |
| + } |
| + |
| + if (Verbose) |
| + errs() << "Generating " << OutputFile << "\n"; |
| + |
| + if (!Fuzzer->fuzz(PercentageToEdit, PercentageBase)) { |
| + errs() << "Error: Fuzzing failed: " << OutputFile << "\n"; |
| + continue; |
| + } |
| + |
| + if (Verbose) { |
| + errs() << "Records:\n"; |
| + for (const auto &Record : Bitcode) { |
| + errs() << " " << Record << "\n"; |
| + } |
| + } |
| + |
| + SmallVector<char, 100> Buffer; |
| + NaClMungedBitcode::WriteFlags WriteFlags; |
| + WriteFlags.setTryToRecover(true); |
| + if (!Verbose) { |
| + WriteFlags.setErrStream(NullStrm); |
| + } |
| + if (!Bitcode.write(Buffer, true, WriteFlags)) { |
| + errs() << "Error: Failed to write fuzzed code: " |
| + << OutputFile << "\n"; |
| + continue; |
| + } |
| + WriteOutputFile(Buffer, OutputFile); |
| + } |
| + |
| + |
| + if (ShowFuzzRecordDistribution) |
| + Fuzzer->showRecordDistribution(outs()); |
| + if (ShowFuzzEditDistribution) |
| + Fuzzer->showEditDistribution(outs()); |
| + |
| + return 0; |
| +} |