Home | History | Annotate | Download | only in mutate
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <limits.h>
      6 #include <stdlib.h>
      7 #include <iostream>
      8 #include <string>
      9 #include <vector>
     10 
     11 #include "base/command_line.h"
     12 #include "base/strings/string_split.h"
     13 #include "third_party/re2/re2/re2.h"
     14 #include "tools/ipc_fuzzer/message_lib/message_file.h"
     15 #include "tools/ipc_fuzzer/message_lib/message_names.h"
     16 
     17 namespace {
     18 
     19 const char kDumpSwitch[] = "dump";
     20 const char kDumpSwitchHelp[] =
     21     "dump human-readable form to stdout instead of copying.";
     22 
     23 const char kEndSwitch[] = "end";
     24 const char kEndSwitchHelp[] =
     25     "output messages before |m|th message in file (exclusive).";
     26 
     27 const char kHelpSwitch[] = "help";
     28 const char kHelpSwitchHelp[] =
     29     "display this message.";
     30 
     31 const char kInvertSwitch[] = "invert";
     32 const char kInvertSwitchHelp[] =
     33     "output messages NOT meeting above criteria.";
     34 
     35 const char kRegexpSwitch[] = "regexp";
     36 const char kRegexpSwitchHelp[] =
     37     "output messages matching regular expression |x|.";
     38 
     39 const char kStartSwitch[] = "start";
     40 const char kStartSwitchHelp[] =
     41     "output messages after |n|th message in file (inclusive).";
     42 
     43 void usage() {
     44   std::cerr << "ipc_message_util: Concatenate all |infile| message files and "
     45             << "copy a subset of the result to |outfile|.\n";
     46 
     47   std::cerr << "Usage:\n"
     48             << "  ipc_message_util"
     49             << " [--" << kStartSwitch << "=n]"
     50             << " [--" << kEndSwitch << "=m]"
     51             << " [--" << kRegexpSwitch << "=x]"
     52             << " [--" << kInvertSwitch << "]"
     53             << " [--" << kDumpSwitch << "]"
     54             << " [--" << kHelpSwitch << "]"
     55             << " infile,infile,... [outfile]\n";
     56 
     57   std::cerr << "    --" << kStartSwitch << "  - " << kStartSwitchHelp << "\n"
     58             << "    --" << kEndSwitch << "    - " << kEndSwitchHelp << "\n"
     59             << "    --" << kRegexpSwitch << " - " << kRegexpSwitchHelp << "\n"
     60             << "    --" << kInvertSwitch << " - " << kInvertSwitchHelp << "\n"
     61             << "    --" << kDumpSwitch << "   - " << kDumpSwitchHelp << "\n"
     62             << "    --" << kHelpSwitch << "   - " << kHelpSwitchHelp << "\n";
     63 }
     64 
     65 std::string MessageName(const IPC::Message* msg) {
     66   return ipc_fuzzer::MessageNames::GetInstance()->TypeToName(msg->type());
     67 }
     68 
     69 bool MessageMatches(const IPC::Message* msg, const RE2& pattern) {
     70   return RE2::FullMatch(MessageName(msg), pattern);
     71 }
     72 
     73 }  // namespace
     74 
     75 int main(int argc, char** argv) {
     76   CommandLine::Init(argc, argv);
     77   CommandLine* cmd = CommandLine::ForCurrentProcess();
     78   CommandLine::StringVector args = cmd->GetArgs();
     79 
     80   if (args.size() < 1 || args.size() > 2 || cmd->HasSwitch(kHelpSwitch)) {
     81     usage();
     82     return EXIT_FAILURE;
     83   }
     84 
     85   size_t start_index = 0;
     86   if (cmd->HasSwitch(kStartSwitch)) {
     87     int temp = atoi(cmd->GetSwitchValueASCII(kStartSwitch).c_str());
     88     if (temp > 0 )
     89       start_index = static_cast<size_t>(temp);
     90   }
     91 
     92   size_t end_index = INT_MAX;
     93   if (cmd->HasSwitch(kEndSwitch)) {
     94     int temp = atoi(cmd->GetSwitchValueASCII(kEndSwitch).c_str());
     95     if (temp > 0)
     96       end_index = static_cast<size_t>(temp);
     97   }
     98 
     99   bool has_regexp = cmd->HasSwitch(kRegexpSwitch);
    100   RE2 filter_pattern(cmd->GetSwitchValueASCII(kRegexpSwitch));
    101 
    102   bool invert = cmd->HasSwitch(kInvertSwitch);
    103   bool perform_dump = cmd->HasSwitch(kDumpSwitch);
    104 
    105   std::vector<std::string> input_file_names;
    106   std::string output_file_name;
    107   base::SplitString(args[0], ',', &input_file_names);
    108 
    109   if (!perform_dump) {
    110     if (args.size() < 2) {
    111       usage();
    112       return EXIT_FAILURE;
    113     }
    114     output_file_name = args[1];
    115   }
    116 
    117   ipc_fuzzer::MessageVector input_message_vector;
    118   for (std::vector<std::string>::iterator it = input_file_names.begin();
    119       it != input_file_names.end(); ++it) {
    120     ipc_fuzzer::MessageVector message_vector;
    121     if (!ipc_fuzzer::MessageFile::Read(base::FilePath(*it), &message_vector))
    122       return EXIT_FAILURE;
    123     input_message_vector.insert(input_message_vector.end(),
    124                                 message_vector.begin(), message_vector.end());
    125     message_vector.weak_clear();
    126   }
    127 
    128   ipc_fuzzer::MessageVector output_message_vector;
    129   std::vector<size_t> remap_vector;
    130 
    131   for (size_t i = 0; i < input_message_vector.size(); ++i) {
    132     bool valid = (i >= start_index && i < end_index);
    133     if (valid && has_regexp) {
    134       valid = MessageMatches(input_message_vector[i], filter_pattern);
    135     }
    136     if (valid != invert) {
    137       output_message_vector.push_back(input_message_vector[i]);
    138       remap_vector.push_back(i);
    139       input_message_vector[i] = NULL;
    140     }
    141   }
    142 
    143   if (perform_dump) {
    144     for (size_t i = 0; i < output_message_vector.size(); ++i) {
    145       std::cout << remap_vector[i] << ". "
    146                 << MessageName(output_message_vector[i]) << "\n";
    147     }
    148   } else {
    149     if (!ipc_fuzzer::MessageFile::Write(
    150             base::FilePath(output_file_name), output_message_vector)) {
    151       return EXIT_FAILURE;
    152     }
    153   }
    154 
    155   return EXIT_SUCCESS;
    156 }
    157