Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(112)

Side by Side Diff: tools/traffic_annotation/traffic_annotation_auditor.cc

Issue 2448133006: Tool added to extract network traffic annotations. (Closed)
Patch Set: Comments addressed. Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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 // See README.txt for information and build instructions.
6
7 #include <cstdio>
8 #include <cstdlib>
9 #include <fstream>
10 #include <map>
11 #include <string>
12
13 #include "base/command_line.h"
14 #include "base/files/file_enumerator.h"
15 #include "base/files/file_path.h"
16 #include "base/files/scoped_temp_dir.h"
17 #include "base/strings/stringprintf.h"
18 #include "net/traffic_annotation/network_traffic_annotation.h"
19 #include "third_party/protobuf/src/google/protobuf/text_format.h"
20
21 #include "tools/traffic_annotation/traffic_annotation.pb.h"
22
23 // Holds an instance of network traffic annotation
24 struct Instance {
25 Instance() : hash_code(0), state(kOK) {}
26
27 traffic_annotation::NetworkTrafficAnnotation proto;
28 std::string unique_id;
29 std::string callee;
30 unsigned int hash_code;
31 enum { kOK, kDuplicate, kUndefined } state;
32 };
33
34 // Runs clang tool, returns true if all OK.
35 bool RunClangTool(const base::FilePath& src_dir,
36 const base::FilePath& build_dir,
37 const base::FilePath& output_dir,
38 const base::CommandLine::StringVector& path_filters) {
39 for (auto& path : path_filters) {
40 int result = system(
41 base::StringPrintf(
42 "%s traffic_annotation_extractor"
43 " --generate-compdb %s %s --tool-params 'output_dir=%s'",
44 src_dir.Append("tools/clang/scripts/run_tool.py").value().c_str(),
45 build_dir.value().c_str(), path.c_str(), output_dir.value().c_str())
46 .c_str());
47 if (result) {
48 printf(" Executing clang tool returned code: %i.\n", result);
49 return false;
50 }
51 }
52 return true;
53 }
54
55 // Reads an extrated annotation file. The first 6 lines of the file include:
56 // 0- File path and file name.
57 // 1- Name of the function that is called using annotation.
58 // 2- Line number.
59 // 3- Name of the function including this position.
60 // 4- Error text associated with this annotation.
61 // 5- Unique id of annotation.
62 // The rest of the file is the protobuf text.
63 bool ReadFile(const base::FilePath& file_path,
64 std::vector<std::string>* header_lines,
65 std::string* msg_text) {
66 std::ifstream input_file(file_path.value());
67 if (!input_file.is_open())
68 return false;
69
70 header_lines->clear();
71 msg_text->clear();
72
73 while (!input_file.eof()) {
74 std::string line;
75 getline(input_file, line);
76 if (header_lines->size() < 6)
77 header_lines->push_back(line);
78 else
79 *msg_text = *msg_text + "\n" + line;
80 }
81 input_file.close();
82 return true;
83 }
84
85 // Reads all extracted txt files form given input folder and populates instances
86 // and errors.
87 void ReadExtractedFiles(const base::FilePath& folder_name,
88 std::vector<Instance>* instances) {
89 base::FileEnumerator file_iter(folder_name, false,
90 base::FileEnumerator::FILES, "*.txt");
91 while (!file_iter.Next().empty()) {
92 std::string file_name = file_iter.GetInfo().GetName().AsUTF8Unsafe();
93 printf("\tReading %s...\n", file_name.c_str());
94
95 std::vector<std::string> header_lines;
96 std::string msg_text;
97 if (!ReadFile(folder_name.Append(file_iter.GetInfo().GetName()),
98 &header_lines, &msg_text)) {
99 fprintf(stderr, "Could not open file '%s'.", file_name.c_str());
100 continue;
101 }
102 if (header_lines.size() < 6) {
103 fprintf(stderr, "Header lines are not complete for file '%s'.",
104 file_name.c_str());
105 continue;
106 }
107 if (!header_lines[4].empty()) {
108 fprintf(stderr, "Error passed from extractor for file '%s': %s.",
109 file_name.c_str(), header_lines[4].c_str());
110 continue;
111 }
112
113 Instance new_instance;
114 if (header_lines[5] == "\"Undefined\"") {
115 new_instance.state = Instance::kUndefined;
116 } else if (!google::protobuf::TextFormat::ParseFromString(
117 msg_text, (google::protobuf::Message*)&new_instance)) {
118 fprintf(stderr, "Could not parse protobuf for file '%s'.",
119 file_name.c_str());
120 continue;
121 }
122
123 // Add header data to new instance.
124 traffic_annotation::NetworkTrafficAnnotation_TrafficSource* src =
125 new_instance.proto.mutable_source();
126 src->set_file(header_lines[0]);
127 src->set_function(header_lines[1]);
128 src->set_line(atoi(header_lines[2].c_str()));
129 new_instance.callee = header_lines[3];
130 new_instance.unique_id = header_lines[5];
131 new_instance.hash_code =
132 COMPUTE_STRING_HASH(new_instance.unique_id.c_str());
133 instances->push_back(new_instance);
134 }
135 printf("%i annotation instance(s) read.\n", (int)instances->size());
136 }
137
138 // Checks to see if unique ids have similar hash codes and marks them if so.
139 void MarkHashCollisions(std::vector<Instance>* instances) {
140 std::map<unsigned int, Instance*> hashed_ids;
141 for (auto& instance : *instances) {
142 if (instance.state == Instance::kOK) {
143 auto match = hashed_ids.find(instance.hash_code);
144 if (match != hashed_ids.end())
145 instance.state = match->second->state = Instance::kDuplicate;
146 else
147 hashed_ids.insert(std::make_pair(instance.hash_code, &instance));
148 }
149 }
150 }
151
152 // Writes summary of annotation instances to a file. Returns true if successful.
153 bool WriteSummaryFile(const std::vector<Instance>& instances,
154 const std::string& file_name) {
155 FILE* output_file = fopen(file_name.c_str(), "wt");
156 if (!output_file) {
157 printf(" Could not create output file: %s", file_name.c_str());
158 return false;
159 }
160 for (const auto& instance : instances) {
161 fprintf(output_file, "Unique ID: %s\tHash code:%u\n",
162 instance.unique_id.c_str(), instance.hash_code);
163 if (instance.state == Instance::kUndefined)
164 fprintf(output_file, "WARNING: Undefined annotation.\n");
165 else if (instance.state == Instance::kDuplicate)
166 fprintf(output_file, "WARNING: Duplicate hash code for unique id.\n");
167 fprintf(output_file, "Calling Function: %s\n", instance.callee.c_str());
168 std::string temp;
169 google::protobuf::TextFormat::PrintToString(instance.proto, &temp);
170 fprintf(output_file, "Content:\n%s\n", temp.c_str());
171 fprintf(output_file, "------------------------------------------------\n");
172 }
173 fclose(output_file);
174 printf("Output file %s written for %i instances.\n", file_name.c_str(),
175 (int)instances.size());
176 return true;
177 }
178
179 int main(int argc, char* argv[]) {
180 // Parse switches.
181 base::CommandLine command_line = base::CommandLine(argc, argv);
182 if (command_line.HasSwitch("help") || command_line.HasSwitch("h") ||
183 argc == 1) {
184 printf(
185 "Usage: traffic_annotation_auditor [OPTION]... [path_filter]...\n"
186 "Extracts network traffic annotations from source files. If path "
187 "filter(s) are specified, only those directories of the source "
188 "will be analyzed.\n"
189 "Options:\n"
190 " -h, --help Shows help.\n"
191 " --build_dir Path to the build directory from which the\n"
192 " annotations will be extracted.\n"
193 " --extractor_output_dir Path to the directory that extracted\n"
194 " partial files will be written to. Will\n"
195 " be automatically generated and deleted\n"
196 " if not specified.\n"
197 " --extracted_input_dir Path to a directory where extracted\n"
198 " partial annotations are already stored.\n"
199 " If specified, build directory will be\n"
200 " ignored.\n"
201 " --summary_file Path to an ouput file with summary of\n"
202 " extracted annotations.\n"
203 "Example:\n"
204 " traffic_annotation_auditor --build_dir=out/Debug\n"
205 " --summery_file=report.txt\n");
206 return 1;
207 }
208 base::FilePath extracted_files_dir =
209 command_line.GetSwitchValuePath("extracted_input_dir");
210 base::FilePath build_dir = command_line.GetSwitchValuePath("build_dir");
211 base::FilePath extractor_output_dir =
212 command_line.GetSwitchValuePath("extractor_output_dir");
213 base::FilePath summary_file = command_line.GetSwitchValuePath("summary_file");
214 base::ScopedTempDir temp_dir;
215
216 // Extract annotations.
217 if (extracted_files_dir.empty()) {
218 // Get build directory, if it is empty issue an error.
219 if (build_dir.empty()) {
220 fprintf(
221 stderr,
222 "You must either specify build directory to run clang "
223 "tool and extract annotations, or specify extracted files's input "
224 "directory where already extracted files exist.\n");
225 return 1;
226 }
227 // If output directory is not provided, create a temporary one.
228 if (extracted_files_dir.empty()) {
229 if (!temp_dir.CreateUniqueTempDirUnderPath(build_dir)) {
230 fprintf(stderr, "Could not create temporary directory in %s.",
231 build_dir.value().c_str());
232 return 1;
233 }
234 extracted_files_dir = temp_dir.GetPath();
235 } else {
236 // Ensure given directory is empty.
237 if (!base::FileEnumerator(extracted_files_dir, false,
238 base::FileEnumerator::FILES, "*.txt")
239 .Next()
240 .empty()) {
241 fprintf(stderr, "Ouput directory (%s) should be empty.",
242 extracted_files_dir.value().c_str());
243 return 1;
244 }
245 }
246
247 // Get path filters, if none is provided, just add all.
248 base::CommandLine::StringVector path_filters = command_line.GetArgs();
249 if (!path_filters.size())
250 path_filters.push_back("./");
251
252 if (!RunClangTool(command_line.GetProgram().DirName().Append("../.."),
253 build_dir, extracted_files_dir, path_filters)) {
254 return 1;
255 }
256 }
257
258 // Read all extracted files.
259 std::vector<Instance> instances;
260 ReadExtractedFiles(extracted_files_dir, &instances);
261
262 if (instances.empty()) {
263 fprintf(stderr, "Could not read any file.");
264 return 1;
265 } else {
266 MarkHashCollisions(&instances);
267 }
268
269 // Create Summary file if requested.
270 if (!summary_file.empty() &&
271 !WriteSummaryFile(instances,
272 command_line.GetSwitchValueASCII("summary_file"))) {
273 return 1;
274 }
275
276 return 0;
277 }
OLDNEW
« tools/traffic_annotation/README.txt ('K') | « tools/traffic_annotation/traffic_annotation.proto ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698