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 FuncSource; 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 }; 94 95 // Do a depth-first search to rewrite all pointers that need to be probed 96 class ProbeVisitor : public clang::RecursiveASTVisitor<ProbeVisitor> { 97 public: 98 explicit ProbeVisitor(clang::ASTContext &C, clang::Rewriter &rewriter, 99 std::set<clang::Decl *> &m, bool track_helpers); 100 bool VisitVarDecl(clang::VarDecl *Decl); 101 bool TraverseStmt(clang::Stmt *S); 102 bool VisitCallExpr(clang::CallExpr *Call); 103 bool VisitReturnStmt(clang::ReturnStmt *R); 104 bool VisitBinaryOperator(clang::BinaryOperator *E); 105 bool VisitUnaryOperator(clang::UnaryOperator *E); 106 bool VisitMemberExpr(clang::MemberExpr *E); 107 bool VisitArraySubscriptExpr(clang::ArraySubscriptExpr *E); set_ptreg(std::tuple<clang::Decl *,int> & pt)108 void set_ptreg(std::tuple<clang::Decl *, int> &pt) { ptregs_.insert(pt); } set_ctx(clang::Decl * D)109 void set_ctx(clang::Decl *D) { ctx_ = D; } get_ptregs()110 std::set<std::tuple<clang::Decl *, int>> get_ptregs() { return ptregs_; } 111 private: 112 bool assignsExtPtr(clang::Expr *E, int *nbAddrOf); 113 bool isMemberDereference(clang::Expr *E); 114 bool IsContextMemberExpr(clang::Expr *E); 115 clang::SourceRange expansionRange(clang::SourceRange range); 116 clang::SourceLocation expansionLoc(clang::SourceLocation loc); 117 template <unsigned N> 118 clang::DiagnosticBuilder error(clang::SourceLocation loc, const char (&fmt)[N]); 119 120 clang::ASTContext &C; 121 clang::Rewriter &rewriter_; 122 std::set<clang::Decl *> fn_visited_; 123 std::set<clang::Expr *> memb_visited_; 124 std::set<const clang::Stmt *> whitelist_; 125 std::set<std::tuple<clang::Decl *, int>> ptregs_; 126 std::set<clang::Decl *> &m_; 127 clang::Decl *ctx_; 128 bool track_helpers_; 129 std::list<int> ptregs_returned_; 130 const clang::Stmt *addrof_stmt_; 131 bool is_addrof_; 132 }; 133 134 // A helper class to the frontend action, walks the decls 135 class BTypeConsumer : public clang::ASTConsumer { 136 public: 137 explicit BTypeConsumer(clang::ASTContext &C, BFrontendAction &fe, 138 clang::Rewriter &rewriter, std::set<clang::Decl *> &m); 139 void HandleTranslationUnit(clang::ASTContext &Context) override; 140 private: 141 BFrontendAction &fe_; 142 MapVisitor map_visitor_; 143 BTypeVisitor btype_visitor_; 144 ProbeVisitor probe_visitor1_; 145 ProbeVisitor probe_visitor2_; 146 }; 147 148 // Create a B program in 2 phases (everything else is normal C frontend): 149 // 1. Catch the map declarations and open the fd's 150 // 2. Capture the IR 151 class BFrontendAction : public clang::ASTFrontendAction { 152 public: 153 // Initialize with the output stream where the new source file contents 154 // should be written. 155 BFrontendAction(llvm::raw_ostream &os, unsigned flags, TableStorage &ts, 156 const std::string &id, const std::string &main_path, 157 FuncSource &func_src, std::string &mod_src, 158 const std::string &maps_ns); 159 160 // Called by clang when the AST has been completed, here the output stream 161 // will be flushed. 162 void EndSourceFileAction() override; 163 164 std::unique_ptr<clang::ASTConsumer> 165 CreateASTConsumer(clang::CompilerInstance &Compiler, llvm::StringRef InFile) override; 166 rewriter()167 clang::Rewriter &rewriter() const { return *rewriter_; } table_storage()168 TableStorage &table_storage() const { return ts_; } id()169 std::string id() const { return id_; } maps_ns()170 std::string maps_ns() const { return maps_ns_; } 171 bool is_rewritable_ext_func(clang::FunctionDecl *D); 172 void DoMiscWorkAround(); 173 174 private: 175 llvm::raw_ostream &os_; 176 unsigned flags_; 177 TableStorage &ts_; 178 std::string id_; 179 std::string maps_ns_; 180 std::unique_ptr<clang::Rewriter> rewriter_; 181 friend class BTypeVisitor; 182 std::map<std::string, clang::SourceRange> func_range_; 183 const std::string &main_path_; 184 FuncSource &func_src_; 185 std::string &mod_src_; 186 std::set<clang::Decl *> m_; 187 }; 188 189 } // namespace visitor 190