// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <stdlib.h>

#include <algorithm>
#include <iostream>
#include <ostream>
#include <set>
#include <string>
#include <vector>

#include "base/command_line.h"
#include "base/pickle.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_message_utils.h"
#include "ipc/ipc_switches.h"
#include "ipc/ipc_sync_channel.h"
#include "ipc/ipc_sync_message.h"
#include "tools/ipc_fuzzer/message_lib/all_messages.h"
#include "tools/ipc_fuzzer/message_lib/message_cracker.h"
#include "tools/ipc_fuzzer/message_lib/message_file.h"
#include "tools/ipc_fuzzer/mutate/rand_util.h"

#if defined(OS_POSIX)
#include <unistd.h>
#endif

namespace IPC {
class Message;
}  // namespace IPC

namespace ipc_fuzzer {

// Interface implemented by those who fuzz basic types.  The types all
// correspond to the types which a pickle from base/pickle.h can pickle,
// plus the floating point types.
class Fuzzer {
 public:
  // Tweak individual values within a message.
  virtual void FuzzBool(bool* value) = 0;
  virtual void FuzzInt(int* value) = 0;
  virtual void FuzzLong(long* value) = 0;
  virtual void FuzzSize(size_t* value) = 0;
  virtual void FuzzUChar(unsigned char *value) = 0;
  virtual void FuzzUInt16(uint16* value) = 0;
  virtual void FuzzUInt32(uint32* value) = 0;
  virtual void FuzzInt64(int64* value) = 0;
  virtual void FuzzUInt64(uint64* value) = 0;
  virtual void FuzzFloat(float *value) = 0;
  virtual void FuzzDouble(double *value) = 0;
  virtual void FuzzString(std::string* value) = 0;
  virtual void FuzzString16(base::string16* value) = 0;
  virtual void FuzzData(char* data, int length) = 0;
  virtual void FuzzBytes(void* data, int data_len) = 0;
};

template <typename T>
void FuzzIntegralType(T* value, unsigned int frequency) {
  if (RandEvent(frequency)) {
    switch (RandInRange(4)) {
      case 0: (*value) = 0; break;
      case 1: (*value)--; break;
      case 2: (*value)++; break;
      case 3: (*value) = RandU64(); break;
    }
  }
}

template <typename T>
void FuzzStringType(T* value, unsigned int frequency,
                    const T& literal1, const T& literal2) {
  if (RandEvent(frequency)) {
    switch (RandInRange(5)) {
      case 4: (*value) = (*value) + (*value);   // FALLTHROUGH
      case 3: (*value) = (*value) + (*value);   // FALLTHROUGH
      case 2: (*value) = (*value) + (*value); break;
      case 1: (*value) += literal1; break;
      case 0: (*value) = literal2; break;
    }
  }
}

// One such fuzzer implementation.
class DefaultFuzzer : public Fuzzer {
 public:
  DefaultFuzzer(int frequency) : frequency_(frequency) {
  }

  virtual ~DefaultFuzzer() {}

  virtual void FuzzBool(bool* value) OVERRIDE {
    if (RandEvent(frequency_))
      (*value) = !(*value);
  }

  virtual void FuzzInt(int* value) OVERRIDE {
    FuzzIntegralType<int>(value, frequency_);
  }

  virtual void FuzzLong(long* value) OVERRIDE {
    FuzzIntegralType<long>(value, frequency_);
  }

  virtual void FuzzSize(size_t* value) OVERRIDE {
    FuzzIntegralType<size_t>(value, frequency_);
  }

  virtual void FuzzUChar(unsigned char* value) OVERRIDE {
    FuzzIntegralType<unsigned char>(value, frequency_);
  }

  virtual void FuzzUInt16(uint16* value) OVERRIDE {
    FuzzIntegralType<uint16>(value, frequency_);
  }

  virtual void FuzzUInt32(uint32* value) OVERRIDE {
    FuzzIntegralType<uint32>(value, frequency_);
  }

  virtual void FuzzInt64(int64* value) OVERRIDE {
    FuzzIntegralType<int64>(value, frequency_);
  }

  virtual void FuzzUInt64(uint64* value) OVERRIDE {
    FuzzIntegralType<uint64>(value, frequency_);
  }

  virtual void FuzzFloat(float* value) OVERRIDE {
    if (RandEvent(frequency_))
      *value = RandDouble();
  }

  virtual void FuzzDouble(double* value) OVERRIDE {
    if (RandEvent(frequency_))
      *value = RandDouble();
  }

  virtual void FuzzString(std::string* value) OVERRIDE {
    FuzzStringType<std::string>(value, frequency_, "BORKED", std::string());
  }

  virtual void FuzzString16(base::string16* value) OVERRIDE {
    FuzzStringType<base::string16>(value, frequency_,
                                   base::WideToUTF16(L"BORKED"),
                                   base::WideToUTF16(L""));
  }

  virtual void FuzzData(char* data, int length) OVERRIDE {
    if (RandEvent(frequency_)) {
      for (int i = 0; i < length; ++i) {
        FuzzIntegralType<char>(&data[i], frequency_);
      }
    }
  }

  virtual void FuzzBytes(void* data, int data_len) OVERRIDE {
    FuzzData(static_cast<char*>(data), data_len);
  }

 private:
  unsigned int frequency_;
};


// No-op fuzzer.  Rewrites each message unchanged to check if the message
// re-assembly is legit.
class NoOpFuzzer : public Fuzzer {
 public:
  NoOpFuzzer() {}
  virtual ~NoOpFuzzer() {}

  virtual void FuzzBool(bool* value) OVERRIDE {}
  virtual void FuzzInt(int* value) OVERRIDE {}
  virtual void FuzzLong(long* value) OVERRIDE {}
  virtual void FuzzSize(size_t* value) OVERRIDE {}
  virtual void FuzzUChar(unsigned char* value) OVERRIDE {}
  virtual void FuzzUInt16(uint16* value) OVERRIDE {}
  virtual void FuzzUInt32(uint32* value) OVERRIDE {}
  virtual void FuzzInt64(int64* value) OVERRIDE {}
  virtual void FuzzUInt64(uint64* value) OVERRIDE {}
  virtual void FuzzFloat(float* value) OVERRIDE {}
  virtual void FuzzDouble(double* value) OVERRIDE {}
  virtual void FuzzString(std::string* value) OVERRIDE {}
  virtual void FuzzString16(base::string16* value) OVERRIDE {}
  virtual void FuzzData(char* data, int length) OVERRIDE {}
  virtual void FuzzBytes(void* data, int data_len) OVERRIDE {}
};

class FuzzerFactory {
 public:
  static Fuzzer *Create(const std::string& name, int frequency) {
    if (name == "no-op")
      return new NoOpFuzzer();

    if (name == "default")
      return new DefaultFuzzer(frequency);

    std::cerr << "No such fuzzer: " << name << "\n";
    return 0;
  }
};

// Partially-specialized class that knows how to fuzz a given type.
template <class P>
struct FuzzTraits {
  static void Fuzz(P* p, Fuzzer *fuzzer) {
    // This is the catch-all for types we don't have enough information
    // to fuzz. It simply does nothing to the type. We might want to
    // change it to randomly flip a bit in the range (p, p+sizeof(P)).
  }
};

// Template function to invoke partially-specialized class method.
template <class P>
static void FuzzParam(P* p, Fuzzer* fuzzer) {
  FuzzTraits<P>::Fuzz(p, fuzzer);
}

// Specializations to fuzz primitive types.
template <>
struct FuzzTraits<bool> {
  static void Fuzz(bool* p, Fuzzer* fuzzer) {
    fuzzer->FuzzBool(p);
  }
};

template <>
struct FuzzTraits<int> {
  static void Fuzz(int* p, Fuzzer* fuzzer) {
    fuzzer->FuzzInt(p);
  }
};

template <>
struct FuzzTraits<unsigned int> {
  static void Fuzz(unsigned int* p, Fuzzer* fuzzer) {
    fuzzer->FuzzInt(reinterpret_cast<int*>(p));
  }
};

template <>
struct FuzzTraits<long> {
  static void Fuzz(long* p, Fuzzer* fuzzer) {
    fuzzer->FuzzLong(p);
  }
};

template <>
struct FuzzTraits<unsigned long> {
  static void Fuzz(unsigned long* p, Fuzzer* fuzzer) {
    fuzzer->FuzzLong(reinterpret_cast<long*>(p));
  }
};

template <>
struct FuzzTraits<long long> {
  static void Fuzz(long long* p, Fuzzer* fuzzer) {
    fuzzer->FuzzInt64(reinterpret_cast<int64*>(p));
  }
};

template <>
struct FuzzTraits<unsigned long long> {
  static void Fuzz(unsigned long long* p, Fuzzer* fuzzer) {
    fuzzer->FuzzInt64(reinterpret_cast<int64*>(p));
  }
};

template <>
struct FuzzTraits<short> {
  static void Fuzz(short* p, Fuzzer* fuzzer) {
    fuzzer->FuzzUInt16(reinterpret_cast<uint16*>(p));
  }
};

template <>
struct FuzzTraits<unsigned short> {
  static void Fuzz(unsigned short* p, Fuzzer* fuzzer) {
    fuzzer->FuzzUInt16(reinterpret_cast<uint16*>(p));
  }
};

template <>
struct FuzzTraits<char> {
  static void Fuzz(char* p, Fuzzer* fuzzer) {
    fuzzer->FuzzUChar(reinterpret_cast<unsigned char*>(p));
  }
};

template <>
struct FuzzTraits<unsigned char> {
  static void Fuzz(unsigned char* p, Fuzzer* fuzzer) {
    fuzzer->FuzzUChar(p);
  }
};

template <>
struct FuzzTraits<float> {
  static void Fuzz(float* p, Fuzzer* fuzzer) {
    fuzzer->FuzzFloat(p);
  }
};

template <>
struct FuzzTraits<double> {
  static void Fuzz(double* p, Fuzzer* fuzzer) {
    fuzzer->FuzzDouble(p);
  }
};

template <>
struct FuzzTraits<std::string> {
  static void Fuzz(std::string* p, Fuzzer* fuzzer) {
    fuzzer->FuzzString(p);
  }
};

template <>
struct FuzzTraits<base::string16> {
  static void Fuzz(base::string16* p, Fuzzer* fuzzer) {
    fuzzer->FuzzString16(p);
  }
};

// Specializations to fuzz tuples.
template <class A>
struct FuzzTraits<Tuple1<A> > {
  static void Fuzz(Tuple1<A>* p, Fuzzer* fuzzer) {
    FuzzParam(&p->a, fuzzer);
  }
};

template <class A, class B>
struct FuzzTraits<Tuple2<A, B> > {
  static void Fuzz(Tuple2<A, B>* p, Fuzzer* fuzzer) {
    FuzzParam(&p->a, fuzzer);
    FuzzParam(&p->b, fuzzer);
  }
};

template <class A, class B, class C>
struct FuzzTraits<Tuple3<A, B, C> > {
  static void Fuzz(Tuple3<A, B, C>* p, Fuzzer* fuzzer) {
    FuzzParam(&p->a, fuzzer);
    FuzzParam(&p->b, fuzzer);
    FuzzParam(&p->c, fuzzer);
  }
};

template <class A, class B, class C, class D>
struct FuzzTraits<Tuple4<A, B, C, D> > {
  static void Fuzz(Tuple4<A, B, C, D>* p, Fuzzer* fuzzer) {
    FuzzParam(&p->a, fuzzer);
    FuzzParam(&p->b, fuzzer);
    FuzzParam(&p->c, fuzzer);
    FuzzParam(&p->d, fuzzer);
  }
};

template <class A, class B, class C, class D, class E>
struct FuzzTraits<Tuple5<A, B, C, D, E> > {
  static void Fuzz(Tuple5<A, B, C, D, E>* p, Fuzzer* fuzzer) {
    FuzzParam(&p->a, fuzzer);
    FuzzParam(&p->b, fuzzer);
    FuzzParam(&p->c, fuzzer);
    FuzzParam(&p->d, fuzzer);
    FuzzParam(&p->e, fuzzer);
  }
};

// Specializations to fuzz containers.
template <class A>
struct FuzzTraits<std::vector<A> > {
  static void Fuzz(std::vector<A>* p, Fuzzer* fuzzer) {
    for (size_t i = 0; i < p->size(); ++i) {
      FuzzParam(&p->at(i), fuzzer);
    }
  }
};

template <class A, class B>
struct FuzzTraits<std::map<A, B> > {
  static void Fuzz(std::map<A, B>* p, Fuzzer* fuzzer) {
    typename std::map<A, B>::iterator it;
    for (it = p->begin(); it != p->end(); ++it) {
      FuzzParam(&it->second, fuzzer);
    }
  }
};

template <class A, class B>
struct FuzzTraits<std::pair<A, B> > {
  static void Fuzz(std::pair<A, B>* p, Fuzzer* fuzzer) {
    FuzzParam(&p->second, fuzzer);
  }
};

// Specializations to fuzz hand-coded tyoes
template <>
struct FuzzTraits<base::FileDescriptor> {
  static void Fuzz(base::FileDescriptor* p, Fuzzer* fuzzer) {
    FuzzParam(&p->fd, fuzzer);
  }
};

template <>
struct FuzzTraits<GURL> {
  static void Fuzz(GURL *p, Fuzzer* fuzzer) {
    FuzzParam(&p->possibly_invalid_spec(), fuzzer);
  }
};

template <>
struct FuzzTraits<gfx::Point> {
  static void Fuzz(gfx::Point *p, Fuzzer* fuzzer) {
    int x = p->x();
    int y = p->y();
    FuzzParam(&x, fuzzer);
    FuzzParam(&y, fuzzer);
    p->SetPoint(x, y);
  }
};

template <>
struct FuzzTraits<gfx::Size> {
  static void Fuzz(gfx::Size *p, Fuzzer* fuzzer) {
    int w = p->width();
    int h = p->height();
    FuzzParam(&w, fuzzer);
    FuzzParam(&h, fuzzer);
    p->SetSize(w, h);
  }
};

template <>
struct FuzzTraits<gfx::Rect> {
  static void Fuzz(gfx::Rect *p, Fuzzer* fuzzer) {
    gfx::Point origin = p->origin();
    gfx::Size  size = p->size();
    FuzzParam(&origin, fuzzer);
    FuzzParam(&size, fuzzer);
    p->set_origin(origin);
    p->set_size(size);
  }
};

// Redefine macros to generate fuzzing from traits declarations.
// Null out all the macros that need nulling.
#include "ipc/ipc_message_null_macros.h"

// STRUCT declarations cause corresponding STRUCT_TRAITS declarations to occur.
#undef IPC_STRUCT_BEGIN
#undef IPC_STRUCT_BEGIN_WITH_PARENT
#undef IPC_STRUCT_MEMBER
#undef IPC_STRUCT_END
#define IPC_STRUCT_BEGIN_WITH_PARENT(struct_name, parent) \
  IPC_STRUCT_BEGIN(struct_name)
#define IPC_STRUCT_BEGIN(struct_name) IPC_STRUCT_TRAITS_BEGIN(struct_name)
#define IPC_STRUCT_MEMBER(type, name, ...) IPC_STRUCT_TRAITS_MEMBER(name)
#define IPC_STRUCT_END() IPC_STRUCT_TRAITS_END()

// Set up so next include will generate fuzz trait classes.
#undef IPC_STRUCT_TRAITS_BEGIN
#undef IPC_STRUCT_TRAITS_MEMBER
#undef IPC_STRUCT_TRAITS_PARENT
#undef IPC_STRUCT_TRAITS_END
#define IPC_STRUCT_TRAITS_BEGIN(struct_name) \
  template <> \
  struct FuzzTraits<struct_name> { \
    static void Fuzz(struct_name *p, Fuzzer* fuzzer) {

#define IPC_STRUCT_TRAITS_MEMBER(name) \
      FuzzParam(&p->name, fuzzer);

#define IPC_STRUCT_TRAITS_PARENT(type) \
      FuzzParam(static_cast<type*>(p), fuzzer);

#define IPC_STRUCT_TRAITS_END() \
    } \
  };

// TODO(tsepez): Make sure to end up with an enum that meets |condition|.
#undef IPC_ENUM_TRAITS_VALIDATE
#define IPC_ENUM_TRAITS_VALIDATE(enum_name, conditon) \
  template <> \
  struct FuzzTraits<enum_name> { \
    static void Fuzz(enum_name* p, Fuzzer* fuzzer) { \
      FuzzParam(reinterpret_cast<int*>(p), fuzzer); \
    } \
  };

// Bring them into existence.
#include "tools/ipc_fuzzer/message_lib/all_messages.h"

// Redefine macros to generate fuzzing funtions
#include "ipc/ipc_message_null_macros.h"
#undef IPC_MESSAGE_DECL
#define IPC_MESSAGE_DECL(kind, type, name, in, out, ilist, olist)           \
  IPC_##kind##_##type##_FUZZ(name, in, out, ilist, olist)

#define IPC_EMPTY_CONTROL_FUZZ(name, in, out, ilist, olist)                 \
  IPC::Message* fuzzer_for_##name(IPC::Message *msg, Fuzzer* fuzzer) {      \
    return NULL;                                                            \
  }

#define IPC_EMPTY_ROUTED_FUZZ(name, in, out, ilist, olist)                  \
  IPC::Message* fuzzer_for_##name(IPC::Message *msg, Fuzzer* fuzzer) {      \
    return NULL;                                                            \
  }

#define IPC_ASYNC_CONTROL_FUZZ(name, in, out, ilist, olist)                 \
  IPC::Message* fuzzer_for_##name(IPC::Message *msg, Fuzzer* fuzzer) {      \
    name* real_msg = static_cast<name*>(msg);                               \
    IPC_TUPLE_IN_##in ilist p;                                              \
    name::Read(real_msg, &p);                                               \
    FuzzParam(&p, fuzzer);                                                  \
    return new name(IPC_MEMBERS_IN_##in(p));                                \
  }

#define IPC_ASYNC_ROUTED_FUZZ(name, in, out, ilist, olist)                  \
  IPC::Message* fuzzer_for_##name(IPC::Message *msg, Fuzzer* fuzzer) {      \
    name* real_msg = static_cast<name*>(msg);                               \
    IPC_TUPLE_IN_##in ilist p;                                              \
    name::Read(real_msg, &p);                                               \
    FuzzParam(&p, fuzzer);                                                  \
    return new name(msg->routing_id()                                       \
                    IPC_COMMA_##in                                          \
                    IPC_MEMBERS_IN_##in(p));                                \
  }

#define IPC_SYNC_CONTROL_FUZZ(name, in, out, ilist, olist)                  \
  IPC::Message* fuzzer_for_##name(IPC::Message *msg, Fuzzer* fuzzer) {      \
    name* real_msg = static_cast<name*>(msg);                               \
    IPC_TUPLE_IN_##in ilist p;                                              \
    name::ReadSendParam(real_msg, &p);                                      \
    FuzzParam(&p, fuzzer);                                                  \
    name* new_msg = new name(IPC_MEMBERS_IN_##in(p)                         \
                             IPC_COMMA_AND_##out(IPC_COMMA_##in)            \
                             IPC_MEMBERS_OUT_##out());                      \
    MessageCracker::CopyMessageID(new_msg, real_msg);                       \
    return new_msg;                                                         \
  }


#define IPC_SYNC_ROUTED_FUZZ(name, in, out, ilist, olist)                   \
  IPC::Message* fuzzer_for_##name(IPC::Message *msg, Fuzzer* fuzzer) {      \
    name* real_msg = static_cast<name*>(msg);                               \
    IPC_TUPLE_IN_##in ilist p;                                              \
    name::ReadSendParam(real_msg, &p);                                      \
    FuzzParam(&p, fuzzer);                                                  \
    name* new_msg = new name(msg->routing_id()                              \
                             IPC_COMMA_OR_##out(IPC_COMMA_##in)             \
                             IPC_MEMBERS_IN_##in(p)                         \
                             IPC_COMMA_AND_##out(IPC_COMMA_##in)            \
                             IPC_MEMBERS_OUT_##out());                      \
    MessageCracker::CopyMessageID(new_msg, real_msg);                       \
    return new_msg;                                                         \
  }

#define IPC_MEMBERS_IN_0(p)
#define IPC_MEMBERS_IN_1(p) p.a
#define IPC_MEMBERS_IN_2(p) p.a, p.b
#define IPC_MEMBERS_IN_3(p) p.a, p.b, p.c
#define IPC_MEMBERS_IN_4(p) p.a, p.b, p.c, p.d
#define IPC_MEMBERS_IN_5(p) p.a, p.b, p.c, p.d, p.e

#define IPC_MEMBERS_OUT_0()
#define IPC_MEMBERS_OUT_1() NULL
#define IPC_MEMBERS_OUT_2() NULL, NULL
#define IPC_MEMBERS_OUT_3() NULL, NULL, NULL
#define IPC_MEMBERS_OUT_4() NULL, NULL, NULL, NULL
#define IPC_MEMBERS_OUT_5() NULL, NULL, NULL, NULL, NULL

#include "tools/ipc_fuzzer/message_lib/all_messages.h"

typedef IPC::Message* (*FuzzFunction)(IPC::Message*, Fuzzer*);
typedef base::hash_map<uint32, FuzzFunction> FuzzFunctionMap;

// Redefine macros to register fuzzing functions into map.
#include "ipc/ipc_message_null_macros.h"
#undef IPC_MESSAGE_DECL
#define IPC_MESSAGE_DECL(kind, type, name, in, out, ilist, olist) \
  (*map)[static_cast<uint32>(name::ID)] = fuzzer_for_##name;

void PopulateFuzzFunctionMap(FuzzFunctionMap *map) {
#include "tools/ipc_fuzzer/message_lib/all_messages.h"
}

static IPC::Message* RewriteMessage(
    IPC::Message* message,
    Fuzzer* fuzzer,
    FuzzFunctionMap* map) {
  FuzzFunctionMap::iterator it = map->find(message->type());
  if (it == map->end()) {
    // This usually indicates a missing message file in all_messages.h, or
    // that the message dump file is taken from a different revision of
    // chromium from this executable.
    std::cerr << "Unknown message type: ["
              << IPC_MESSAGE_ID_CLASS(message->type()) << ", "
              << IPC_MESSAGE_ID_LINE(message->type()) << "].\n";
    return 0;
  }

  return (*it->second)(message, fuzzer);
}

namespace {

const char kHelpSwitch[] = "help";
const char kHelpSwitchHelp[] =
    "show this message";

const char kFrequencySwitch[] = "frequency";
const char kFrequencySwitchHelp[] =
    "probability of mutation; tweak every 1/|q| times.";

const char kFuzzerNameSwitch[] = "fuzzer-name";
const char kFuzzerNameSwitchHelp[] =
    "select default or no-op fuzzer.";

const char kPermuteSwitch[] = "permute";
const char kPermuteSwitchHelp[] =
    "Randomly shuffle the order of all messages.";

const char kTypeListSwitch[] = "type-list";
const char kTypeListSwitchHelp[] =
    "explicit list of the only message-ids to mutate.";

void usage() {
  std::cerr << "Mutate messages from an exiting message file.\n";

  std::cerr << "Usage:\n"
            << "  ipc_fuzzer_mutate"
            << " [--" << kHelpSwitch << "]"
            << " [--" << kFuzzerNameSwitch << "=f]"
            << " [--" << kFrequencySwitch << "=q]"
            << " [--" << kTypeListSwitch << "=x,y,z...]"
            << " [--" << kPermuteSwitch << "]"
            << " infile outfile\n";

  std::cerr
      << " --" << kHelpSwitch << "         - " << kHelpSwitchHelp << "\n"
      << " --" << kFuzzerNameSwitch <<  "  - " << kFuzzerNameSwitchHelp << "\n"
      << " --" << kFrequencySwitch << "    - " << kFrequencySwitchHelp << "\n"
      << " --" << kTypeListSwitch <<  "    - " << kTypeListSwitchHelp << "\n"
      << " --" << kPermuteSwitch << "      - " << kPermuteSwitchHelp << "\n";
}

}  // namespace

int MutateMain(int argc, char** argv) {
  CommandLine::Init(argc, argv);
  CommandLine* cmd = CommandLine::ForCurrentProcess();
  CommandLine::StringVector args = cmd->GetArgs();

  if (args.size() != 2 || cmd->HasSwitch(kHelpSwitch)) {
    usage();
    return EXIT_FAILURE;
  }

  std::string input_file_name = args[0];
  std::string output_file_name = args[1];

  bool permute = cmd->HasSwitch(kPermuteSwitch);

  std::string fuzzer_name = "default";
  if (cmd->HasSwitch(kFuzzerNameSwitch))
    fuzzer_name = cmd->GetSwitchValueASCII(kFuzzerNameSwitch);

  int frequency = 23;
  if (cmd->HasSwitch(kFrequencySwitch))
    frequency = atoi(cmd->GetSwitchValueASCII(kFrequencySwitch).c_str());

  std::string type_string_list = cmd->GetSwitchValueASCII(kTypeListSwitch);
  std::vector<std::string> type_string_vector;
  base::SplitString(type_string_list, ',', &type_string_vector);
  std::set<int> type_set;
  for (size_t i = 0; i < type_string_vector.size(); ++i) {
    type_set.insert(atoi(type_string_vector[i].c_str()));
  }

  InitRand();

  Fuzzer* fuzzer = FuzzerFactory::Create(fuzzer_name, frequency);
  if (!fuzzer)
    return EXIT_FAILURE;

  FuzzFunctionMap fuzz_function_map;
  PopulateFuzzFunctionMap(&fuzz_function_map);

  MessageVector message_vector;
  if (!MessageFile::Read(base::FilePath(input_file_name), &message_vector))
    return EXIT_FAILURE;

  for (size_t i = 0; i < message_vector.size(); ++i) {
    IPC::Message* msg = message_vector[i];
    if (!type_set.empty() && type_set.end() == std::find(
            type_set.begin(), type_set.end(), msg->type())) {
      continue;
    }
    IPC::Message* new_message = RewriteMessage(msg, fuzzer, &fuzz_function_map);
    if (new_message) {
      delete message_vector[i];
      message_vector[i] = new_message;
    }
  }

  if (permute) {
    std::random_shuffle(message_vector.begin(), message_vector.end(),
                        RandInRange);
  }

  if (!MessageFile::Write(base::FilePath(output_file_name), message_vector))
    return EXIT_FAILURE;

  return EXIT_SUCCESS;
}

}  // namespace ipc_fuzzer

int main(int argc, char** argv) {
  return ipc_fuzzer::MutateMain(argc, argv);
}