xref: /aosp_15_r20/external/bcc/src/cc/frontends/clang/b_frontend_action.h (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1 /*
2  * Copyright (c) 2015 PLUMgrid, Inc.
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 
17 #include <map>
18 #include <memory>
19 #include <set>
20 #include <string>
21 #include <vector>
22 
23 #include <clang/AST/RecursiveASTVisitor.h>
24 #include <clang/Frontend/FrontendAction.h>
25 #include <clang/Rewrite/Core/Rewriter.h>
26 
27 #include "table_storage.h"
28 
29 namespace clang {
30 class ASTConsumer;
31 class ASTContext;
32 class CompilerInstance;
33 }
34 
35 namespace llvm {
36 class raw_ostream;
37 class StringRef;
38 }
39 
40 namespace ebpf {
41 
42 class BFrontendAction;
43 class ProgFuncInfo;
44 
45 // Traces maps with external pointers as values.
46 class MapVisitor : public clang::RecursiveASTVisitor<MapVisitor> {
47  public:
48   explicit MapVisitor(std::set<clang::Decl *> &m);
49   bool VisitCallExpr(clang::CallExpr *Call);
set_ptreg(std::tuple<clang::Decl *,int> & pt)50   void set_ptreg(std::tuple<clang::Decl *, int> &pt) { ptregs_.insert(pt); }
51  private:
52   std::set<clang::Decl *> &m_;
53   std::set<std::tuple<clang::Decl *, int>> ptregs_;
54 };
55 
56 // Type visitor and rewriter for B programs.
57 // It will look for B-specific features and rewrite them into a valid
58 // C program. As part of the processing, open the necessary BPF tables
59 // and store the open handles in a map of table-to-fd's.
60 class BTypeVisitor : public clang::RecursiveASTVisitor<BTypeVisitor> {
61  public:
62   explicit BTypeVisitor(clang::ASTContext &C, BFrontendAction &fe);
63   bool TraverseCallExpr(clang::CallExpr *Call);
64   bool VisitFunctionDecl(clang::FunctionDecl *D);
65   bool VisitCallExpr(clang::CallExpr *Call);
66   bool VisitVarDecl(clang::VarDecl *Decl);
67   bool VisitBinaryOperator(clang::BinaryOperator *E);
68   bool VisitImplicitCastExpr(clang::ImplicitCastExpr *E);
69 
70  private:
71   clang::SourceRange expansionRange(clang::SourceRange range);
72   bool checkFormatSpecifiers(const std::string& fmt, clang::SourceLocation loc);
73   void genParamDirectAssign(clang::FunctionDecl *D, std::string& preamble,
74                             const char **calling_conv_regs);
75   void genParamIndirectAssign(clang::FunctionDecl *D, std::string& preamble,
76                               const char **calling_conv_regs);
77   void rewriteFuncParam(clang::FunctionDecl *D);
78   int64_t getFieldValue(clang::VarDecl *Decl, clang::FieldDecl *FDecl,
79                         int64_t OrigFValue);
80   template <unsigned N>
81   clang::DiagnosticBuilder error(clang::SourceLocation loc, const char (&fmt)[N]);
82   template <unsigned N>
83   clang::DiagnosticBuilder warning(clang::SourceLocation loc, const char (&fmt)[N]);
84 
85   clang::ASTContext &C;
86   clang::DiagnosticsEngine &diag_;
87   BFrontendAction &fe_;
88   clang::Rewriter &rewriter_;  /// modifications to the source go into this class
89   llvm::raw_ostream &out_;  /// for debugging
90   std::vector<clang::ParmVarDecl *> fn_args_;
91   std::set<clang::Expr *> visited_;
92   std::string current_fn_;
93   bool cannot_fall_back_safely;
94 };
95 
96 // Do a depth-first search to rewrite all pointers that need to be probed
97 class ProbeVisitor : public clang::RecursiveASTVisitor<ProbeVisitor> {
98  public:
99   explicit ProbeVisitor(clang::ASTContext &C, clang::Rewriter &rewriter,
100                         std::set<clang::Decl *> &m, bool track_helpers);
101   bool VisitVarDecl(clang::VarDecl *Decl);
102   bool TraverseStmt(clang::Stmt *S);
103   bool VisitCallExpr(clang::CallExpr *Call);
104   bool VisitReturnStmt(clang::ReturnStmt *R);
105   bool VisitBinaryOperator(clang::BinaryOperator *E);
106   bool VisitUnaryOperator(clang::UnaryOperator *E);
107   bool VisitMemberExpr(clang::MemberExpr *E);
108   bool VisitArraySubscriptExpr(clang::ArraySubscriptExpr *E);
set_ptreg(std::tuple<clang::Decl *,int> & pt)109   void set_ptreg(std::tuple<clang::Decl *, int> &pt) { ptregs_.insert(pt); }
set_ctx(clang::Decl * D)110   void set_ctx(clang::Decl *D) { ctx_ = D; }
get_ptregs()111   std::set<std::tuple<clang::Decl *, int>> get_ptregs() { return ptregs_; }
112  private:
113   bool assignsExtPtr(clang::Expr *E, int *nbAddrOf);
114   bool isMemberDereference(clang::Expr *E);
115   bool IsContextMemberExpr(clang::Expr *E);
116   clang::SourceRange expansionRange(clang::SourceRange range);
117   clang::SourceLocation expansionLoc(clang::SourceLocation loc);
118   template <unsigned N>
119   clang::DiagnosticBuilder error(clang::SourceLocation loc, const char (&fmt)[N]);
120 
121   clang::ASTContext &C;
122   clang::Rewriter &rewriter_;
123   std::set<clang::Decl *> fn_visited_;
124   std::set<clang::Expr *> memb_visited_;
125   std::set<const clang::Stmt *> whitelist_;
126   std::set<std::tuple<clang::Decl *, int>> ptregs_;
127   std::set<clang::Decl *> &m_;
128   clang::Decl *ctx_;
129   bool track_helpers_;
130   std::list<int> ptregs_returned_;
131   const clang::Stmt *addrof_stmt_;
132   bool is_addrof_;
133   bool cannot_fall_back_safely;
134 };
135 
136 // A helper class to the frontend action, walks the decls
137 class BTypeConsumer : public clang::ASTConsumer {
138  public:
139   explicit BTypeConsumer(clang::ASTContext &C, BFrontendAction &fe,
140                          clang::Rewriter &rewriter, std::set<clang::Decl *> &m);
141   void HandleTranslationUnit(clang::ASTContext &Context) override;
142  private:
143   BFrontendAction &fe_;
144   MapVisitor map_visitor_;
145   BTypeVisitor btype_visitor_;
146   ProbeVisitor probe_visitor1_;
147   ProbeVisitor probe_visitor2_;
148 };
149 
150 // Create a B program in 2 phases (everything else is normal C frontend):
151 // 1. Catch the map declarations and open the fd's
152 // 2. Capture the IR
153 class BFrontendAction : public clang::ASTFrontendAction {
154  public:
155   // Initialize with the output stream where the new source file contents
156   // should be written.
157   BFrontendAction(llvm::raw_ostream &os, unsigned flags, TableStorage &ts,
158                   const std::string &id, const std::string &main_path,
159                   ProgFuncInfo &prog_func_info, std::string &mod_src,
160                   const std::string &maps_ns, fake_fd_map_def &fake_fd_map,
161                   std::map<std::string, std::vector<std::string>> &perf_events);
162 
163   // Called by clang when the AST has been completed, here the output stream
164   // will be flushed.
165   void EndSourceFileAction() override;
166 
167   std::unique_ptr<clang::ASTConsumer>
168       CreateASTConsumer(clang::CompilerInstance &Compiler, llvm::StringRef InFile) override;
169 
rewriter()170   clang::Rewriter &rewriter() const { return *rewriter_; }
table_storage()171   TableStorage &table_storage() const { return ts_; }
id()172   std::string id() const { return id_; }
maps_ns()173   std::string maps_ns() const { return maps_ns_; }
174   bool is_rewritable_ext_func(clang::FunctionDecl *D);
175   void DoMiscWorkAround();
176   // negative fake_fd to be different from real fd in bpf_pseudo_fd.
get_next_fake_fd()177   int get_next_fake_fd() { return next_fake_fd_--; }
add_map_def(int fd,std::tuple<int,std::string,int,int,int,int,int,std::string,std::string> map_def)178   void add_map_def(int fd,
179     std::tuple<int, std::string, int, int, int, int, int, std::string,
180                std::string> map_def) {
181     fake_fd_map_[fd] = move(map_def);
182   }
183 
184  private:
185   llvm::raw_ostream &os_;
186   unsigned flags_;
187   TableStorage &ts_;
188   std::string id_;
189   std::string maps_ns_;
190   std::unique_ptr<clang::Rewriter> rewriter_;
191   friend class BTypeVisitor;
192   std::map<std::string, clang::SourceRange> func_range_;
193   const std::string &main_path_;
194   ProgFuncInfo &prog_func_info_;
195   std::string &mod_src_;
196   std::set<clang::Decl *> m_;
197   int next_fake_fd_;
198   fake_fd_map_def &fake_fd_map_;
199   std::map<std::string, std::vector<std::string>> &perf_events_;
200 };
201 
202 }  // namespace visitor
203