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

Side by Side Diff: tools/clang/traffic_annotation_extractor/traffic_annotation_extractor.cpp

Issue 2911633002: Expanding traffic_annotation_extractor clang tool to extract network calls. (Closed)
Patch Set: Created 3 years, 6 months 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
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
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
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
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 }
OLDNEW
« no previous file with comments | « tools/clang/traffic_annotation_extractor/README.md ('k') | tools/traffic_annotation/auditor/traffic_annotation_auditor.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698