xref: /aosp_15_r20/external/bcc/src/cc/frontends/clang/tp_frontend_action.cc (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1 /*
2  * Copyright (c) 2016 Sasha Goldshtein
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <linux/bpf.h>
17 #include <linux/version.h>
18 #include <sys/utsname.h>
19 #include <unistd.h>
20 
21 #include <fstream>
22 #include <regex>
23 
24 #include <clang/AST/ASTConsumer.h>
25 #include <clang/AST/ASTContext.h>
26 #include <clang/AST/RecordLayout.h>
27 #include <clang/Frontend/CompilerInstance.h>
28 #include <clang/Frontend/MultiplexConsumer.h>
29 #include <clang/Rewrite/Core/Rewriter.h>
30 
31 #include "frontend_action_common.h"
32 #include "tp_frontend_action.h"
33 #include "common.h"
34 
35 namespace ebpf {
36 
37 using std::map;
38 using std::set;
39 using std::string;
40 using std::to_string;
41 using std::unique_ptr;
42 using std::vector;
43 using std::regex;
44 using std::smatch;
45 using std::regex_search;
46 using std::istream;
47 using std::ifstream;
48 using namespace clang;
49 
TracepointTypeVisitor(ASTContext & C,Rewriter & rewriter)50 TracepointTypeVisitor::TracepointTypeVisitor(ASTContext &C, Rewriter &rewriter)
51     : diag_(C.getDiagnostics()), rewriter_(rewriter), out_(llvm::errs()) {
52 }
53 
GenerateTracepointStruct(SourceLocation loc,string const & category,string const & event)54 string TracepointTypeVisitor::GenerateTracepointStruct(
55     SourceLocation loc, string const& category, string const& event) {
56   string format_file = tracepoint_format_file(category, event);
57   ifstream input(format_file.c_str());
58   if (!input)
59     return "";
60 
61   return ebpf::parse_tracepoint(input, category, event);
62 }
63 
_is_tracepoint_struct_type(string const & type_name,string & tp_category,string & tp_event)64 static inline bool _is_tracepoint_struct_type(string const& type_name,
65                                               string& tp_category,
66                                               string& tp_event) {
67   // We are looking to roughly match the regex:
68   //    (?:struct|class)\s+tracepoint__(\S+)__(\S+)
69   // Not using std::regex because older versions of GCC don't support it yet.
70   // E.g., the libstdc++ that ships with Ubuntu 14.04.
71 
72   auto first_space_pos = type_name.find_first_of("\t ");
73   if (first_space_pos == string::npos)
74     return false;
75   auto first_tok = type_name.substr(0, first_space_pos);
76   if (first_tok != "struct" && first_tok != "class")
77     return false;
78 
79   auto non_space_pos = type_name.find_first_not_of("\t ", first_space_pos);
80   auto second_space_pos = type_name.find_first_of("\t ", non_space_pos);
81   auto second_tok = type_name.substr(non_space_pos,
82                                      second_space_pos - non_space_pos);
83   if (second_tok.find("tracepoint__") != 0)
84     return false;
85 
86   auto tp_event_pos = second_tok.rfind("__");
87   if (tp_event_pos == string::npos)
88     return false;
89   tp_event = second_tok.substr(tp_event_pos + 2);
90 
91   auto tp_category_pos = second_tok.find("__");
92   if (tp_category_pos == tp_event_pos)
93     return false;
94   tp_category = second_tok.substr(tp_category_pos + 2,
95                                   tp_event_pos - tp_category_pos - 2);
96   return true;
97 }
98 
99 
VisitFunctionDecl(FunctionDecl * D)100 bool TracepointTypeVisitor::VisitFunctionDecl(FunctionDecl *D) {
101   if (D->isExternallyVisible() && D->hasBody()) {
102     // If this function has a tracepoint structure as an argument,
103     // add that structure declaration based on the structure name.
104     for (auto it = D->param_begin(); it != D->param_end(); ++it) {
105       auto arg = *it;
106       auto type = arg->getType();
107       if (type->isPointerType() &&
108           type->getPointeeType()->isStructureOrClassType()) {
109         auto type_name = type->getPointeeType().getAsString();
110         string tp_cat, tp_evt;
111         if (_is_tracepoint_struct_type(type_name, tp_cat, tp_evt)) {
112           string tp_struct = GenerateTracepointStruct(
113               GET_BEGINLOC(D), tp_cat, tp_evt);
114           // Get the actual function declaration point (the macro instantiation
115           // point if using the TRACEPOINT_PROBE macro instead of the macro
116           // declaration point in bpf_helpers.h).
117           auto insert_loc = GET_BEGINLOC(D);
118           insert_loc = rewriter_.getSourceMgr().getFileLoc(insert_loc);
119           rewriter_.InsertText(insert_loc, tp_struct);
120         }
121       }
122     }
123   }
124   return true;
125 }
126 
TracepointTypeConsumer(ASTContext & C,Rewriter & rewriter)127 TracepointTypeConsumer::TracepointTypeConsumer(ASTContext &C, Rewriter &rewriter)
128     : visitor_(C, rewriter) {
129 }
130 
HandleTopLevelDecl(DeclGroupRef Group)131 bool TracepointTypeConsumer::HandleTopLevelDecl(DeclGroupRef Group) {
132   for (auto D : Group)
133     visitor_.TraverseDecl(D);
134   return true;
135 }
136 
TracepointFrontendAction(llvm::raw_ostream & os)137 TracepointFrontendAction::TracepointFrontendAction(llvm::raw_ostream &os)
138     : os_(os), rewriter_(new Rewriter) {
139 }
140 
EndSourceFileAction()141 void TracepointFrontendAction::EndSourceFileAction() {
142   rewriter_->getEditBuffer(rewriter_->getSourceMgr().getMainFileID()).write(os_);
143   os_.flush();
144 }
145 
CreateASTConsumer(CompilerInstance & Compiler,llvm::StringRef InFile)146 unique_ptr<ASTConsumer> TracepointFrontendAction::CreateASTConsumer(
147         CompilerInstance &Compiler, llvm::StringRef InFile) {
148   rewriter_->setSourceMgr(Compiler.getSourceManager(), Compiler.getLangOpts());
149   return unique_ptr<ASTConsumer>(new TracepointTypeConsumer(
150               Compiler.getASTContext(), *rewriter_));
151 }
152 
153 }
154