OLD | NEW |
---|---|
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // This clang tool finds all instances of the following functions: | 5 // This clang tool finds all instances of the following functions: |
6 // - net::DefineNetworkTrafficAnnotation | 6 // - net::DefineNetworkTrafficAnnotation |
7 // - net::DefinePartialNetworkTrafficAnnotation | 7 // - net::DefinePartialNetworkTrafficAnnotation |
8 // - net::CompleteNetworkTrafficAnnotation | 8 // - net::CompleteNetworkTrafficAnnotation |
9 // - net::BranchedCompleteNetworkTrafficAnnotation | 9 // - net::BranchedCompleteNetworkTrafficAnnotation |
10 // It extracts the location info and content of annotation tags, and outputs | 10 // It extracts the location info and content of annotation tags, and outputs |
11 // them to llvm::outs. Please refer to README.md for build and usage | 11 // them to llvm::outs. It also extracts all calls the following network request |
12 // instructions. | 12 // creation functions and returns their source location and availability of a |
13 // net::[Partial]NetworkTrafficAnnotation parameter in them: | |
14 // - SSLClientSocket::SSLClientSocket | |
15 // - TCPClientSocket::TCPClientSocket | |
16 // - UDPClientSocket::UDPClientSocket | |
17 // - URLFetcher::Create | |
18 // - ClientSocketFactory::CreateDatagramClientSocket | |
19 // - ClientSocketFactory::CreateSSLClientSocket | |
20 // - ClientSocketFactory::CreateTransportClientSocket | |
21 // - URLRequestContext::CreateRequest | |
22 // Please refer to README.md for build and usage instructions. | |
13 | 23 |
14 #include <memory> | 24 #include <memory> |
15 #include <vector> | 25 #include <vector> |
16 | 26 |
17 #include "clang/ASTMatchers/ASTMatchFinder.h" | 27 #include "clang/ASTMatchers/ASTMatchFinder.h" |
18 #include "clang/ASTMatchers/ASTMatchers.h" | 28 #include "clang/ASTMatchers/ASTMatchers.h" |
19 #include "clang/Basic/SourceManager.h" | 29 #include "clang/Basic/SourceManager.h" |
20 #include "clang/Frontend/FrontendActions.h" | 30 #include "clang/Frontend/FrontendActions.h" |
21 #include "clang/Lex/Lexer.h" | 31 #include "clang/Lex/Lexer.h" |
22 #include "clang/Tooling/CommonOptionsParser.h" | 32 #include "clang/Tooling/CommonOptionsParser.h" |
23 #include "clang/Tooling/Refactoring.h" | 33 #include "clang/Tooling/Refactoring.h" |
24 #include "clang/Tooling/Tooling.h" | 34 #include "clang/Tooling/Tooling.h" |
25 #include "llvm/Support/CommandLine.h" | 35 #include "llvm/Support/CommandLine.h" |
26 | 36 |
27 using namespace clang::ast_matchers; | 37 using namespace clang::ast_matchers; |
28 | 38 |
29 namespace { | 39 namespace { |
30 | 40 |
41 // Information about location of a line of code. | |
42 struct Location { | |
43 std::string file_path; | |
44 int line_number = -1; | |
45 | |
46 // Name of the function including this line. E.g., in the following code, | |
47 // |function_name| will be 'foo' for all |line_number| values 101-103. | |
48 // | |
49 // 100 void foo() { | |
50 // 101 NetworkTrafficAnnotationTag baz = | |
51 // 102 net::DefineNetworkTrafficAnnotation(...); } | |
52 // 103 bar(baz); | |
53 // 104 } | |
54 // If no function is found, 'Global Namespace' will be returned. | |
55 std::string function_name; | |
56 }; | |
57 | |
31 // An instance of a call to either of the 4 network traffic annotation | 58 // An instance of a call to either of the 4 network traffic annotation |
32 // definition functions. | 59 // definition functions. |
33 struct NetworkAnnotationInstance { | 60 struct NetworkAnnotationInstance { |
34 // Information about where the call has happened. | |
35 struct Location { | |
36 std::string file_path; | |
37 int line_number = -1; | |
38 | |
39 // Name of the function including this line. E.g., in the following code, | |
40 // |function_name| will be 'foo' for all |line_number| values 101-103. | |
41 // | |
42 // 100 void foo() { | |
43 // 101 NetworkTrafficAnnotationTag baz = | |
44 // 102 net::DefineNetworkTrafficAnnotation(...); } | |
45 // 103 bar(baz); | |
46 // 104 } | |
47 // If no function is found, 'Global Namespace' will be returned. | |
48 std::string function_name; | |
49 }; | |
50 | |
51 // Annotation content. These are the arguments of the call to either of the 4 | 61 // Annotation content. These are the arguments of the call to either of the 4 |
52 // network traffic annotation definition functions. | 62 // network traffic annotation definition functions. |
53 struct Annotation { | 63 struct Annotation { |
54 std::string unique_id; | 64 std::string unique_id; |
55 std::string text; | 65 std::string text; |
56 | 66 |
57 // |extra_id| will have |completing_id| for | 67 // |extra_id| will have |completing_id| for |
58 // net::DefinePartialNetworkTrafficAnnotation and |group_id| for | 68 // net::DefinePartialNetworkTrafficAnnotation and |group_id| for |
59 // net::BranchedCompleteNetworkTrafficAnnotation. It will be empty in other | 69 // net::BranchedCompleteNetworkTrafficAnnotation. It will be empty in other |
60 // cases. | 70 // cases. |
(...skipping 22 matching lines...) Expand all Loading... | |
83 case kCompleting: | 93 case kCompleting: |
84 return "Completing"; | 94 return "Completing"; |
85 case kBranchedCompleting: | 95 case kBranchedCompleting: |
86 return "BranchedCompleting"; | 96 return "BranchedCompleting"; |
87 } | 97 } |
88 assert(false); | 98 assert(false); |
89 return ""; | 99 return ""; |
90 } | 100 } |
91 }; | 101 }; |
92 | 102 |
93 using Collector = std::vector<NetworkAnnotationInstance>; | 103 // An instance of a call to one of the monitored function. |
104 struct CallInstance { | |
105 CallInstance() : has_annotation(false) {} | |
dcheng
2017/05/27 08:27:46
Or just use an in-class initializer to be consiste
Ramin Halavati
2017/05/29 08:13:28
Done.
| |
106 | |
107 // Location of the call. | |
108 Location location; | |
109 | |
110 // Whether the function is annotated. | |
111 bool has_annotation; | |
112 | |
113 // Name of the called function. | |
114 std::string called_function_name; | |
115 }; | |
116 | |
117 // A structure to keep detected annotation and call instances. | |
118 struct Collector { | |
119 std::vector<NetworkAnnotationInstance> annotations; | |
120 std::vector<CallInstance> calls; | |
121 }; | |
94 | 122 |
95 // This class implements the call back functions for AST Matchers. The matchers | 123 // This class implements the call back functions for AST Matchers. The matchers |
96 // are defined in RunMatchers function. When a pattern is found there, | 124 // are defined in RunMatchers function. When a pattern is found there, |
97 // the run function in this class is called back with information on the matched | 125 // the run function in this class is called back with information on the matched |
98 // location and description of the matched pattern. | 126 // location and description of the matched pattern. |
99 class NetworkAnnotationTagCallback : public MatchFinder::MatchCallback { | 127 class NetworkAnnotationTagCallback : public MatchFinder::MatchCallback { |
100 public: | 128 public: |
101 explicit NetworkAnnotationTagCallback(Collector* collector) | 129 explicit NetworkAnnotationTagCallback(Collector* collector) |
102 : collector_(collector) {} | 130 : collector_(collector) {} |
103 ~NetworkAnnotationTagCallback() override = default; | 131 ~NetworkAnnotationTagCallback() override = default; |
104 | 132 |
105 // Is called on any pattern found by ASTMathers that are defined in RunMathers | 133 // Is called on any pattern found by ASTMathers that are defined in RunMathers |
106 // function. | 134 // function. |
107 virtual void run(const MatchFinder::MatchResult& result) override { | 135 virtual void run(const MatchFinder::MatchResult& result) override { |
136 if (const clang::CallExpr* call_expr = | |
137 result.Nodes.getNodeAs<clang::CallExpr>("monitored_function")) { | |
138 AddFunction(call_expr, result); | |
139 } else { | |
140 AddAnnotation(result); | |
141 } | |
142 } | |
143 | |
144 void GetInstanceLocation(const MatchFinder::MatchResult& result, | |
145 const clang::CallExpr* call_expr, | |
146 const clang::FunctionDecl* ancestor, | |
147 Location* instance_location) { | |
148 clang::SourceLocation source_location = call_expr->getLocStart(); | |
149 if (source_location.isMacroID()) { | |
150 source_location = | |
151 result.SourceManager->getImmediateMacroCallerLoc(source_location); | |
152 } | |
153 instance_location->file_path = | |
154 result.SourceManager->getFilename(source_location); | |
155 instance_location->line_number = | |
156 result.SourceManager->getSpellingLineNumber(source_location); | |
157 if (ancestor) | |
158 instance_location->function_name = ancestor->getQualifiedNameAsString(); | |
159 else | |
160 instance_location->function_name = "Global Namespace"; | |
161 | |
162 // Trim leading "../"s from file path. | |
dcheng
2017/05/27 08:27:46
Nit: this comment probably before line 165, or it
Ramin Halavati
2017/05/29 08:13:28
Done.
| |
163 std::replace(instance_location->file_path.begin(), | |
164 instance_location->file_path.end(), '\\', '/'); | |
165 while (instance_location->file_path.length() > 3 && | |
166 instance_location->file_path.substr(0, 3) == "../") { | |
167 instance_location->file_path = instance_location->file_path.substr( | |
168 3, instance_location->file_path.length() - 3); | |
169 } | |
170 } | |
171 | |
172 // Stores a function call that should be monitored. | |
173 void AddFunction(const clang::CallExpr* call_expr, | |
174 const MatchFinder::MatchResult& result) { | |
175 CallInstance instance; | |
176 | |
177 const clang::FunctionDecl* ancestor = | |
178 result.Nodes.getNodeAs<clang::FunctionDecl>("function_context"); | |
179 | |
180 GetInstanceLocation(result, call_expr, ancestor, &instance.location); | |
181 | |
182 instance.called_function_name = | |
183 call_expr->getDirectCallee()->getQualifiedNameAsString(); | |
184 | |
185 // Check if it is annotated. | |
186 // TODO: Daniel, any sugestion on how to change this into an ASTMatcher? I | |
187 // couldn't do it. | |
dcheng
2017/05/27 08:27:46
hasAnyParameter(hasType(recordDecl(anyOf(hasName("
Ramin Halavati
2017/05/29 08:13:28
Thank you very much.
| |
188 const clang::FunctionDecl* function_decl = call_expr->getDirectCallee(); | |
189 unsigned params_count = function_decl->getNumParams(); | |
190 | |
191 for (unsigned i = 0; i < params_count; i++) { | |
192 std::string arg_type = clang::QualType::getAsString( | |
193 function_decl->getParamDecl(i)->getType().split()); | |
194 if (arg_type == "struct net::NetworkTrafficAnnotationTag" || | |
195 arg_type == "struct net::PartialNetworkTrafficAnnotationTag") { | |
196 instance.has_annotation = true; | |
197 break; | |
198 } | |
199 } | |
200 collector_->calls.push_back(instance); | |
201 } | |
202 | |
203 // Stores an annotation. | |
204 void AddAnnotation(const MatchFinder::MatchResult& result) { | |
108 NetworkAnnotationInstance instance; | 205 NetworkAnnotationInstance instance; |
109 | 206 |
110 const clang::StringLiteral* unique_id = | 207 const clang::StringLiteral* unique_id = |
111 result.Nodes.getNodeAs<clang::StringLiteral>("unique_id"); | 208 result.Nodes.getNodeAs<clang::StringLiteral>("unique_id"); |
112 const clang::StringLiteral* annotation_text = | 209 const clang::StringLiteral* annotation_text = |
113 result.Nodes.getNodeAs<clang::StringLiteral>("annotation_text"); | 210 result.Nodes.getNodeAs<clang::StringLiteral>("annotation_text"); |
114 const clang::FunctionDecl* ancestor = | 211 const clang::FunctionDecl* ancestor = |
115 result.Nodes.getNodeAs<clang::FunctionDecl>("function_context"); | 212 result.Nodes.getNodeAs<clang::FunctionDecl>("function_context"); |
116 const clang::StringLiteral* group_id = | 213 const clang::StringLiteral* group_id = |
117 result.Nodes.getNodeAs<clang::StringLiteral>("group_id"); | 214 result.Nodes.getNodeAs<clang::StringLiteral>("group_id"); |
(...skipping 18 matching lines...) Expand all Loading... | |
136 assert(group_id); | 233 assert(group_id); |
137 instance.annotation.extra_id = group_id->getString(); | 234 instance.annotation.extra_id = group_id->getString(); |
138 } else { | 235 } else { |
139 assert(false); | 236 assert(false); |
140 } | 237 } |
141 | 238 |
142 assert(unique_id && annotation_text); | 239 assert(unique_id && annotation_text); |
143 instance.annotation.unique_id = unique_id->getString(); | 240 instance.annotation.unique_id = unique_id->getString(); |
144 instance.annotation.text = annotation_text->getString(); | 241 instance.annotation.text = annotation_text->getString(); |
145 | 242 |
146 // Get annotation location. | 243 GetInstanceLocation(result, call_expr, ancestor, &instance.location); |
147 clang::SourceLocation source_location = call_expr->getLocStart(); | |
148 if (source_location.isMacroID()) { | |
149 source_location = | |
150 result.SourceManager->getImmediateMacroCallerLoc(source_location); | |
151 } | |
152 instance.location.file_path = | |
153 result.SourceManager->getFilename(source_location); | |
154 instance.location.line_number = | |
155 result.SourceManager->getSpellingLineNumber(source_location); | |
156 if (ancestor) | |
157 instance.location.function_name = ancestor->getQualifiedNameAsString(); | |
158 else | |
159 instance.location.function_name = "Global Namespace"; | |
160 | 244 |
161 // Trim leading "../"s from file path. | 245 collector_->annotations.push_back(instance); |
162 std::replace(instance.location.file_path.begin(), | |
163 instance.location.file_path.end(), '\\', '/'); | |
164 while (instance.location.file_path.length() > 3 && | |
165 instance.location.file_path.substr(0, 3) == "../") { | |
166 instance.location.file_path = instance.location.file_path.substr( | |
167 3, instance.location.file_path.length() - 3); | |
168 } | |
169 | |
170 collector_->push_back(instance); | |
171 } | 246 } |
172 | 247 |
173 private: | 248 private: |
174 Collector* collector_; | 249 Collector* collector_; |
175 }; | 250 }; |
176 | 251 |
177 // Sets up an ASTMatcher and runs clang tool to populate collector. Returns the | 252 // Sets up an ASTMatcher and runs clang tool to populate collector. Returns the |
178 // result of running the clang tool. | 253 // result of running the clang tool. |
179 int RunMatchers(clang::tooling::ClangTool* clang_tool, Collector* collector) { | 254 int RunMatchers(clang::tooling::ClangTool* clang_tool, Collector* collector) { |
180 NetworkAnnotationTagCallback callback(collector); | 255 NetworkAnnotationTagCallback callback(collector); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
217 callExpr(hasDeclaration(functionDecl(anyOf( | 292 callExpr(hasDeclaration(functionDecl(anyOf( |
218 hasName("BranchedCompleteNetworkTrafficAnnotation"), | 293 hasName("BranchedCompleteNetworkTrafficAnnotation"), |
219 hasName("net::BranchedCompleteNetworkTrafficAnnotation")))), | 294 hasName("net::BranchedCompleteNetworkTrafficAnnotation")))), |
220 hasArgument(0, stringLiteral().bind("unique_id")), | 295 hasArgument(0, stringLiteral().bind("unique_id")), |
221 hasArgument(1, stringLiteral().bind("group_id")), | 296 hasArgument(1, stringLiteral().bind("group_id")), |
222 hasArgument(3, stringLiteral().bind("annotation_text")), | 297 hasArgument(3, stringLiteral().bind("annotation_text")), |
223 anyOf(hasAncestor(functionDecl().bind("function_context")), | 298 anyOf(hasAncestor(functionDecl().bind("function_context")), |
224 unless(hasAncestor(functionDecl())))) | 299 unless(hasAncestor(functionDecl())))) |
225 .bind("branched_completing_function"), | 300 .bind("branched_completing_function"), |
226 &callback); | 301 &callback); |
302 | |
303 // Setup patterns to find functions that should be monitored. | |
304 match_finder.addMatcher( | |
305 callExpr(hasDeclaration(functionDecl(anyOf( | |
306 hasName("SSLClientSocket::SSLClientSocket"), | |
307 hasName("TCPClientSocket::TCPClientSocket"), | |
308 hasName("UDPClientSocket::UDPClientSocket"), | |
309 hasName("URLFetcher::Create"), | |
310 hasName("ClientSocketFactory::CreateDatagramClientSocket"), | |
311 hasName("ClientSocketFactory::CreateSSLClientSocket"), | |
312 hasName("ClientSocketFactory::CreateTransportClientSocket"), | |
313 hasName("URLRequestContext::CreateRequest")))), | |
314 anyOf(hasAncestor(functionDecl().bind("function_context")), | |
315 unless(hasAncestor(functionDecl())))) | |
316 .bind("monitored_function"), | |
317 &callback); | |
318 | |
227 std::unique_ptr<clang::tooling::FrontendActionFactory> frontend_factory = | 319 std::unique_ptr<clang::tooling::FrontendActionFactory> frontend_factory = |
228 clang::tooling::newFrontendActionFactory(&match_finder); | 320 clang::tooling::newFrontendActionFactory(&match_finder); |
229 return clang_tool->run(frontend_factory.get()); | 321 return clang_tool->run(frontend_factory.get()); |
230 } | 322 } |
231 | 323 |
232 } // namespace | 324 } // namespace |
233 | 325 |
234 static llvm::cl::OptionCategory ToolCategory( | 326 static llvm::cl::OptionCategory ToolCategory( |
235 "traffic_annotation_extractor: Extract traffic annotation texts"); | 327 "traffic_annotation_extractor: Extract traffic annotation texts"); |
236 static llvm::cl::extrahelp CommonHelp( | 328 static llvm::cl::extrahelp CommonHelp( |
237 clang::tooling::CommonOptionsParser::HelpMessage); | 329 clang::tooling::CommonOptionsParser::HelpMessage); |
238 | 330 |
239 int main(int argc, const char* argv[]) { | 331 int main(int argc, const char* argv[]) { |
240 clang::tooling::CommonOptionsParser options(argc, argv, ToolCategory); | 332 clang::tooling::CommonOptionsParser options(argc, argv, ToolCategory); |
241 clang::tooling::ClangTool tool(options.getCompilations(), | 333 clang::tooling::ClangTool tool(options.getCompilations(), |
242 options.getSourcePathList()); | 334 options.getSourcePathList()); |
243 Collector collector; | 335 Collector collector; |
244 | 336 |
245 int result = RunMatchers(&tool, &collector); | 337 int result = RunMatchers(&tool, &collector); |
246 | 338 |
247 if (result != 0) | 339 if (result != 0) |
248 return result; | 340 return result; |
249 | 341 |
250 // For each call to any of the functions that define a network traffic | 342 // For each call to any of the functions that define a network traffic |
251 // annotation, write annotation text and relevant meta data into llvm::outs(). | 343 // annotation, write annotation text and relevant meta data into llvm::outs(). |
252 for (const NetworkAnnotationInstance& call : collector) { | 344 for (const NetworkAnnotationInstance& instance : collector.annotations) { |
253 llvm::outs() << "==== NEW ANNOTATION ====\n"; | 345 llvm::outs() << "==== NEW ANNOTATION ====\n"; |
254 llvm::outs() << call.location.file_path << "\n"; | 346 llvm::outs() << instance.location.file_path << "\n"; |
255 llvm::outs() << call.location.function_name << "\n"; | 347 llvm::outs() << instance.location.function_name << "\n"; |
256 llvm::outs() << call.location.line_number << "\n"; | 348 llvm::outs() << instance.location.line_number << "\n"; |
257 llvm::outs() << call.GetTypeName() << "\n"; | 349 llvm::outs() << instance.GetTypeName() << "\n"; |
258 llvm::outs() << call.annotation.unique_id << "\n"; | 350 llvm::outs() << instance.annotation.unique_id << "\n"; |
259 llvm::outs() << call.annotation.extra_id << "\n"; | 351 llvm::outs() << instance.annotation.extra_id << "\n"; |
260 llvm::outs() << call.annotation.text << "\n"; | 352 llvm::outs() << instance.annotation.text << "\n"; |
261 llvm::outs() << "==== ANNOTATION ENDS ====\n"; | 353 llvm::outs() << "==== ANNOTATION ENDS ====\n"; |
262 } | 354 } |
263 | 355 |
356 // For each call, write annotation text and relevant meta data. | |
357 for (const CallInstance& instance : collector.calls) { | |
358 llvm::outs() << "==== NEW CALL ====\n"; | |
359 llvm::outs() << instance.location.file_path << "\n"; | |
360 llvm::outs() << instance.location.function_name << "\n"; | |
361 llvm::outs() << instance.location.line_number << "\n"; | |
362 llvm::outs() << instance.called_function_name << "\n"; | |
363 llvm::outs() << instance.has_annotation << "\n"; | |
364 llvm::outs() << "==== CALL ENDS ====\n"; | |
365 } | |
366 | |
264 return 0; | 367 return 0; |
265 } | 368 } |
OLD | NEW |