message_util.cc 5.8 KB

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