OLD | NEW |
---|---|
(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 } | |
OLD | NEW |