// Copyright 2014 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 #include #include #include #include #include #include "base/command_line.h" #include "base/strings/string_split.h" #include "third_party/re2/src/re2/re2.h" #include "tools/ipc_fuzzer/message_lib/message_file.h" #include "tools/ipc_fuzzer/message_lib/message_names.h" namespace { const char kDumpSwitch[] = "dump"; const char kDumpSwitchHelp[] = "dump human-readable form to stdout instead of copying."; const char kEndSwitch[] = "end"; const char kEndSwitchHelp[] = "output messages before |m|th message in file (exclusive)."; const char kHelpSwitch[] = "help"; const char kHelpSwitchHelp[] = "display this message."; const char kInSwitch[] = "in"; const char kInSwitchHelp[] = "output only the messages at the specified positions in the file."; const char kInvertSwitch[] = "invert"; const char kInvertSwitchHelp[] = "output messages NOT meeting above criteria."; const char kRegexpSwitch[] = "regexp"; const char kRegexpSwitchHelp[] = "output messages matching regular expression |x|."; const char kStartSwitch[] = "start"; const char kStartSwitchHelp[] = "output messages after |n|th message in file (inclusive)."; void usage() { std::cerr << "ipc_message_util: Concatenate all |infile| message files and " << "copy a subset of the result to |outfile|.\n"; std::cerr << "Usage:\n" << " ipc_message_util" << " [--" << kStartSwitch << "=n]" << " [--" << kEndSwitch << "=m]" << " [--" << kInSwitch << "=i[,j,...]]" << " [--" << kRegexpSwitch << "=x]" << " [--" << kInvertSwitch << "]" << " [--" << kDumpSwitch << "]" << " [--" << kHelpSwitch << "]" << " infile,infile,... [outfile]\n"; std::cerr << " --" << kStartSwitch << " - " << kStartSwitchHelp << "\n" << " --" << kEndSwitch << " - " << kEndSwitchHelp << "\n" << " --" << kInSwitch << " - " << kInSwitchHelp << "\n" << " --" << kRegexpSwitch << " - " << kRegexpSwitchHelp << "\n" << " --" << kInvertSwitch << " - " << kInvertSwitchHelp << "\n" << " --" << kDumpSwitch << " - " << kDumpSwitchHelp << "\n" << " --" << kHelpSwitch << " - " << kHelpSwitchHelp << "\n"; } std::string MessageName(const IPC::Message* msg) { return ipc_fuzzer::MessageNames::GetInstance()->TypeToName(msg->type()); } bool MessageMatches(const IPC::Message* msg, const RE2& pattern) { return RE2::FullMatch(MessageName(msg), pattern); } } // namespace int main(int argc, char** argv) { base::CommandLine::Init(argc, argv); base::CommandLine* cmd = base::CommandLine::ForCurrentProcess(); base::CommandLine::StringVector args = cmd->GetArgs(); if (args.size() < 1 || args.size() > 2 || cmd->HasSwitch(kHelpSwitch)) { usage(); return EXIT_FAILURE; } size_t start_index = 0; if (cmd->HasSwitch(kStartSwitch)) { int temp = atoi(cmd->GetSwitchValueASCII(kStartSwitch).c_str()); if (temp > 0) start_index = static_cast(temp); } size_t end_index = INT_MAX; if (cmd->HasSwitch(kEndSwitch)) { int temp = atoi(cmd->GetSwitchValueASCII(kEndSwitch).c_str()); if (temp > 0) end_index = static_cast(temp); } bool has_regexp = cmd->HasSwitch(kRegexpSwitch); RE2 filter_pattern(cmd->GetSwitchValueASCII(kRegexpSwitch)); bool invert = cmd->HasSwitch(kInvertSwitch); bool perform_dump = cmd->HasSwitch(kDumpSwitch); base::FilePath::StringType output_file_name; if (!perform_dump) { if (args.size() < 2) { usage(); return EXIT_FAILURE; } output_file_name = args[1]; } ipc_fuzzer::MessageVector input_message_vector; for (const base::FilePath::StringType& name : base::SplitString( args[0], base::FilePath::StringType(1, ','), base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) { ipc_fuzzer::MessageVector message_vector; if (!ipc_fuzzer::MessageFile::Read(base::FilePath(name), &message_vector)) return EXIT_FAILURE; input_message_vector.insert(input_message_vector.end(), message_vector.begin(), message_vector.end()); message_vector.weak_clear(); } bool has_indices = cmd->HasSwitch(kInSwitch); std::vector indices; if (has_indices) { indices.resize(input_message_vector.size(), false); for (const std::string& cur : base::SplitString( cmd->GetSwitchValueASCII(kInSwitch), ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) { int index = atoi(cur.c_str()); if (index >= 0 && static_cast(index) < indices.size()) indices[index] = true; } } ipc_fuzzer::MessageVector output_message_vector; std::vector remap_vector; for (size_t i = 0; i < input_message_vector.size(); ++i) { bool valid = (i >= start_index && i < end_index); if (valid && has_regexp) { valid = MessageMatches(input_message_vector[i], filter_pattern); } if (valid && has_indices) { valid = indices[i]; } if (valid != invert) { output_message_vector.push_back(input_message_vector[i]); remap_vector.push_back(i); input_message_vector[i] = NULL; } } if (perform_dump) { for (size_t i = 0; i < output_message_vector.size(); ++i) { std::cout << remap_vector[i] << ". " << MessageName(output_message_vector[i]) << "\n"; } } else { if (!ipc_fuzzer::MessageFile::Write( base::FilePath(output_file_name), output_message_vector)) { return EXIT_FAILURE; } } return EXIT_SUCCESS; }