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 17namespace { 18 19const char kDumpSwitch[] = "dump"; 20const char kDumpSwitchHelp[] = 21 "dump human-readable form to stdout instead of copying."; 22 23const char kEndSwitch[] = "end"; 24const char kEndSwitchHelp[] = 25 "output messages before |m|th message in file (exclusive)."; 26 27const char kHelpSwitch[] = "help"; 28const char kHelpSwitchHelp[] = 29 "display this message."; 30 31const char kInvertSwitch[] = "invert"; 32const char kInvertSwitchHelp[] = 33 "output messages NOT meeting above criteria."; 34 35const char kRegexpSwitch[] = "regexp"; 36const char kRegexpSwitchHelp[] = 37 "output messages matching regular expression |x|."; 38 39const char kStartSwitch[] = "start"; 40const char kStartSwitchHelp[] = 41 "output messages after |n|th message in file (inclusive)."; 42 43void 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 65std::string MessageName(const IPC::Message* msg) { 66 return ipc_fuzzer::MessageNames::GetInstance()->TypeToName(msg->type()); 67} 68 69bool MessageMatches(const IPC::Message* msg, const RE2& pattern) { 70 return RE2::FullMatch(MessageName(msg), pattern); 71} 72 73} // namespace 74 75int 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