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

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

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

Powered by Google App Engine
This is Rietveld 408576698