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

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: Clang tool updated. 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 // Location of the call.
106 Location location;
107
108 // Whether the function is annotated.
109 bool has_annotation = false;
110
111 // Name of the called function.
112 std::string called_function_name;
113 };
114
115 // A structure to keep detected annotation and call instances.
116 struct Collector {
117 std::vector<NetworkAnnotationInstance> annotations;
118 std::vector<CallInstance> calls;
119 };
94 120
95 // This class implements the call back functions for AST Matchers. The matchers 121 // This class implements the call back functions for AST Matchers. The matchers
96 // are defined in RunMatchers function. When a pattern is found there, 122 // 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 123 // the run function in this class is called back with information on the matched
98 // location and description of the matched pattern. 124 // location and description of the matched pattern.
99 class NetworkAnnotationTagCallback : public MatchFinder::MatchCallback { 125 class NetworkAnnotationTagCallback : public MatchFinder::MatchCallback {
100 public: 126 public:
101 explicit NetworkAnnotationTagCallback(Collector* collector) 127 explicit NetworkAnnotationTagCallback(Collector* collector)
102 : collector_(collector) {} 128 : collector_(collector) {}
103 ~NetworkAnnotationTagCallback() override = default; 129 ~NetworkAnnotationTagCallback() override = default;
104 130
105 // Is called on any pattern found by ASTMathers that are defined in RunMathers 131 // Is called on any pattern found by ASTMathers that are defined in RunMathers
106 // function. 132 // function.
107 virtual void run(const MatchFinder::MatchResult& result) override { 133 virtual void run(const MatchFinder::MatchResult& result) override {
134 if (const clang::CallExpr* call_expr =
135 result.Nodes.getNodeAs<clang::CallExpr>("monitored_function")) {
136 AddFunction(call_expr, result);
137 } else {
138 AddAnnotation(result);
139 }
140 }
141
142 void GetInstanceLocation(const MatchFinder::MatchResult& result,
143 const clang::CallExpr* call_expr,
144 const clang::FunctionDecl* ancestor,
145 Location* instance_location) {
146 clang::SourceLocation source_location = call_expr->getLocStart();
147 if (source_location.isMacroID()) {
148 source_location =
149 result.SourceManager->getImmediateMacroCallerLoc(source_location);
150 }
151 instance_location->file_path =
152 result.SourceManager->getFilename(source_location);
153 instance_location->line_number =
154 result.SourceManager->getSpellingLineNumber(source_location);
155 if (ancestor)
156 instance_location->function_name = ancestor->getQualifiedNameAsString();
157 else
158 instance_location->function_name = "Global Namespace";
159
160 std::replace(instance_location->file_path.begin(),
161 instance_location->file_path.end(), '\\', '/');
162
163 // Trim leading "../"s from file path.
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
171 // Stores a function call that should be monitored.
172 void AddFunction(const clang::CallExpr* call_expr,
173 const MatchFinder::MatchResult& result) {
174 CallInstance instance;
175
176 const clang::FunctionDecl* ancestor =
177 result.Nodes.getNodeAs<clang::FunctionDecl>("function_context");
178 GetInstanceLocation(result, call_expr, ancestor, &instance.location);
179 instance.called_function_name =
180 call_expr->getDirectCallee()->getQualifiedNameAsString();
181 instance.has_annotation =
182 (result.Nodes.getNodeAs<clang::RecordDecl>("annotation") != NULL);
dcheng 2017/05/29 08:28:00 Nit: nullptr instead of NULL
Ramin Halavati 2017/05/29 09:14:02 Done.
183 collector_->calls.push_back(instance);
184 }
185
186 // Stores an annotation.
187 void AddAnnotation(const MatchFinder::MatchResult& result) {
108 NetworkAnnotationInstance instance; 188 NetworkAnnotationInstance instance;
109 189
110 const clang::StringLiteral* unique_id = 190 const clang::StringLiteral* unique_id =
111 result.Nodes.getNodeAs<clang::StringLiteral>("unique_id"); 191 result.Nodes.getNodeAs<clang::StringLiteral>("unique_id");
112 const clang::StringLiteral* annotation_text = 192 const clang::StringLiteral* annotation_text =
113 result.Nodes.getNodeAs<clang::StringLiteral>("annotation_text"); 193 result.Nodes.getNodeAs<clang::StringLiteral>("annotation_text");
114 const clang::FunctionDecl* ancestor = 194 const clang::FunctionDecl* ancestor =
115 result.Nodes.getNodeAs<clang::FunctionDecl>("function_context"); 195 result.Nodes.getNodeAs<clang::FunctionDecl>("function_context");
116 const clang::StringLiteral* group_id = 196 const clang::StringLiteral* group_id =
117 result.Nodes.getNodeAs<clang::StringLiteral>("group_id"); 197 result.Nodes.getNodeAs<clang::StringLiteral>("group_id");
(...skipping 18 matching lines...) Expand all
136 assert(group_id); 216 assert(group_id);
137 instance.annotation.extra_id = group_id->getString(); 217 instance.annotation.extra_id = group_id->getString();
138 } else { 218 } else {
139 assert(false); 219 assert(false);
140 } 220 }
141 221
142 assert(unique_id && annotation_text); 222 assert(unique_id && annotation_text);
143 instance.annotation.unique_id = unique_id->getString(); 223 instance.annotation.unique_id = unique_id->getString();
144 instance.annotation.text = annotation_text->getString(); 224 instance.annotation.text = annotation_text->getString();
145 225
146 // Get annotation location. 226 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 227
161 // Trim leading "../"s from file path. 228 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 } 229 }
172 230
173 private: 231 private:
174 Collector* collector_; 232 Collector* collector_;
175 }; 233 };
176 234
177 // Sets up an ASTMatcher and runs clang tool to populate collector. Returns the 235 // Sets up an ASTMatcher and runs clang tool to populate collector. Returns the
178 // result of running the clang tool. 236 // result of running the clang tool.
179 int RunMatchers(clang::tooling::ClangTool* clang_tool, Collector* collector) { 237 int RunMatchers(clang::tooling::ClangTool* clang_tool, Collector* collector) {
180 NetworkAnnotationTagCallback callback(collector); 238 NetworkAnnotationTagCallback callback(collector);
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
217 callExpr(hasDeclaration(functionDecl(anyOf( 275 callExpr(hasDeclaration(functionDecl(anyOf(
218 hasName("BranchedCompleteNetworkTrafficAnnotation"), 276 hasName("BranchedCompleteNetworkTrafficAnnotation"),
219 hasName("net::BranchedCompleteNetworkTrafficAnnotation")))), 277 hasName("net::BranchedCompleteNetworkTrafficAnnotation")))),
220 hasArgument(0, stringLiteral().bind("unique_id")), 278 hasArgument(0, stringLiteral().bind("unique_id")),
221 hasArgument(1, stringLiteral().bind("group_id")), 279 hasArgument(1, stringLiteral().bind("group_id")),
222 hasArgument(3, stringLiteral().bind("annotation_text")), 280 hasArgument(3, stringLiteral().bind("annotation_text")),
223 anyOf(hasAncestor(functionDecl().bind("function_context")), 281 anyOf(hasAncestor(functionDecl().bind("function_context")),
224 unless(hasAncestor(functionDecl())))) 282 unless(hasAncestor(functionDecl()))))
225 .bind("branched_completing_function"), 283 .bind("branched_completing_function"),
226 &callback); 284 &callback);
285
286 // Setup patterns to find functions that should be monitored.
287 match_finder.addMatcher(
288 callExpr(
289 hasDeclaration(functionDecl(
290 anyOf(hasName("SSLClientSocket::SSLClientSocket"),
291 hasName("TCPClientSocket::TCPClientSocket"),
292 hasName("UDPClientSocket::UDPClientSocket"),
293 hasName("URLFetcher::Create"),
294 hasName("ClientSocketFactory::CreateDatagramClientSocket"),
295 hasName("ClientSocketFactory::CreateSSLClientSocket"),
296 hasName("ClientSocketFactory::CreateTransportClientSocket"),
297 hasName("URLRequestContext::CreateRequest")),
298 anyOf(
299 hasAnyParameter(hasType(
300 recordDecl(
301 anyOf(hasName("net::NetworkTrafficAnnotationTag"),
302 hasName(
303 "net::PartialNetworkTrafficAnnotationTag")))
304 .bind("annotation"))),
305 unless(hasAnyParameter(hasType(recordDecl(anyOf(
306 hasName("net::NetworkTrafficAnnotationTag"),
307 hasName(
308 "net::PartialNetworkTrafficAnnotationTag"))))))))),
309 anyOf(hasAncestor(functionDecl().bind("function_context")),
310 unless(hasAncestor(functionDecl()))))
dcheng 2017/05/29 08:28:00 One thing to consider is to move some of these exp
Ramin Halavati 2017/05/29 09:14:02 Thank you very much, Done.
311 .bind("monitored_function"),
312 &callback);
313
227 std::unique_ptr<clang::tooling::FrontendActionFactory> frontend_factory = 314 std::unique_ptr<clang::tooling::FrontendActionFactory> frontend_factory =
228 clang::tooling::newFrontendActionFactory(&match_finder); 315 clang::tooling::newFrontendActionFactory(&match_finder);
229 return clang_tool->run(frontend_factory.get()); 316 return clang_tool->run(frontend_factory.get());
230 } 317 }
231 318
232 } // namespace 319 } // namespace
233 320
234 static llvm::cl::OptionCategory ToolCategory( 321 static llvm::cl::OptionCategory ToolCategory(
235 "traffic_annotation_extractor: Extract traffic annotation texts"); 322 "traffic_annotation_extractor: Extract traffic annotation texts");
236 static llvm::cl::extrahelp CommonHelp( 323 static llvm::cl::extrahelp CommonHelp(
237 clang::tooling::CommonOptionsParser::HelpMessage); 324 clang::tooling::CommonOptionsParser::HelpMessage);
238 325
239 int main(int argc, const char* argv[]) { 326 int main(int argc, const char* argv[]) {
240 clang::tooling::CommonOptionsParser options(argc, argv, ToolCategory); 327 clang::tooling::CommonOptionsParser options(argc, argv, ToolCategory);
241 clang::tooling::ClangTool tool(options.getCompilations(), 328 clang::tooling::ClangTool tool(options.getCompilations(),
242 options.getSourcePathList()); 329 options.getSourcePathList());
243 Collector collector; 330 Collector collector;
244 331
245 int result = RunMatchers(&tool, &collector); 332 int result = RunMatchers(&tool, &collector);
246 333
247 if (result != 0) 334 if (result != 0)
248 return result; 335 return result;
249 336
250 // For each call to any of the functions that define a network traffic 337 // 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(). 338 // annotation, write annotation text and relevant meta data into llvm::outs().
252 for (const NetworkAnnotationInstance& call : collector) { 339 for (const NetworkAnnotationInstance& instance : collector.annotations) {
253 llvm::outs() << "==== NEW ANNOTATION ====\n"; 340 llvm::outs() << "==== NEW ANNOTATION ====\n";
254 llvm::outs() << call.location.file_path << "\n"; 341 llvm::outs() << instance.location.file_path << "\n";
255 llvm::outs() << call.location.function_name << "\n"; 342 llvm::outs() << instance.location.function_name << "\n";
256 llvm::outs() << call.location.line_number << "\n"; 343 llvm::outs() << instance.location.line_number << "\n";
257 llvm::outs() << call.GetTypeName() << "\n"; 344 llvm::outs() << instance.GetTypeName() << "\n";
258 llvm::outs() << call.annotation.unique_id << "\n"; 345 llvm::outs() << instance.annotation.unique_id << "\n";
259 llvm::outs() << call.annotation.extra_id << "\n"; 346 llvm::outs() << instance.annotation.extra_id << "\n";
260 llvm::outs() << call.annotation.text << "\n"; 347 llvm::outs() << instance.annotation.text << "\n";
261 llvm::outs() << "==== ANNOTATION ENDS ====\n"; 348 llvm::outs() << "==== ANNOTATION ENDS ====\n";
262 } 349 }
263 350
351 // For each call, write annotation text and relevant meta data.
352 for (const CallInstance& instance : collector.calls) {
353 llvm::outs() << "==== NEW CALL ====\n";
354 llvm::outs() << instance.location.file_path << "\n";
355 llvm::outs() << instance.location.function_name << "\n";
356 llvm::outs() << instance.location.line_number << "\n";
357 llvm::outs() << instance.called_function_name << "\n";
358 llvm::outs() << instance.has_annotation << "\n";
359 llvm::outs() << "==== CALL ENDS ====\n";
360 }
361
264 return 0; 362 return 0;
265 } 363 }
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