• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <linux/bpf.h>
17 #include <linux/version.h>
18 #include <sys/utsname.h>
19 #include <unistd.h>
20 #include <stdlib.h>
21 
22 #include <clang/AST/ASTConsumer.h>
23 #include <clang/AST/ASTContext.h>
24 #include <clang/AST/RecordLayout.h>
25 #include <clang/Frontend/CompilerInstance.h>
26 #include <clang/Frontend/MultiplexConsumer.h>
27 #include <clang/Rewrite/Core/Rewriter.h>
28 #include <clang/Lex/Lexer.h>
29 
30 #include "frontend_action_common.h"
31 #include "b_frontend_action.h"
32 #include "bpf_module.h"
33 #include "common.h"
34 #include "loader.h"
35 #include "table_storage.h"
36 #include "arch_helper.h"
37 
38 #include "libbpf.h"
39 
40 namespace ebpf {
41 
42 constexpr int MAX_CALLING_CONV_REGS = 6;
43 const char *calling_conv_regs_x86[] = {
44   "di", "si", "dx", "cx", "r8", "r9"
45 };
46 const char *calling_conv_regs_ppc[] = {"gpr[3]", "gpr[4]", "gpr[5]",
47                                        "gpr[6]", "gpr[7]", "gpr[8]"};
48 
49 const char *calling_conv_regs_s390x[] = {"gprs[2]", "gprs[3]", "gprs[4]",
50 					 "gprs[5]", "gprs[6]" };
51 
52 const char *calling_conv_regs_arm64[] = {"regs[0]", "regs[1]", "regs[2]",
53                                        "regs[3]", "regs[4]", "regs[5]"};
54 
get_call_conv_cb(bcc_arch_t arch)55 void *get_call_conv_cb(bcc_arch_t arch)
56 {
57   const char **ret;
58 
59   switch(arch) {
60     case BCC_ARCH_PPC:
61     case BCC_ARCH_PPC_LE:
62       ret = calling_conv_regs_ppc;
63       break;
64     case BCC_ARCH_S390X:
65       ret = calling_conv_regs_s390x;
66       break;
67     case BCC_ARCH_ARM64:
68       ret = calling_conv_regs_arm64;
69       break;
70     default:
71       ret = calling_conv_regs_x86;
72   }
73 
74   return (void *)ret;
75 }
76 
get_call_conv(void)77 const char **get_call_conv(void) {
78   const char **ret;
79 
80   ret = (const char **)run_arch_callback(get_call_conv_cb);
81   return ret;
82 }
83 
84 using std::map;
85 using std::move;
86 using std::set;
87 using std::tuple;
88 using std::make_tuple;
89 using std::string;
90 using std::to_string;
91 using std::unique_ptr;
92 using std::vector;
93 using namespace clang;
94 
95 class ProbeChecker : public RecursiveASTVisitor<ProbeChecker> {
96  public:
ProbeChecker(Expr * arg,const set<tuple<Decl *,int>> & ptregs,bool track_helpers,bool is_assign)97   explicit ProbeChecker(Expr *arg, const set<tuple<Decl *, int>> &ptregs,
98                         bool track_helpers, bool is_assign)
99       : needs_probe_(false), is_transitive_(false), ptregs_(ptregs),
100         track_helpers_(track_helpers), nb_derefs_(0), is_assign_(is_assign) {
101     if (arg) {
102       TraverseStmt(arg);
103       if (arg->getType()->isPointerType())
104         is_transitive_ = needs_probe_;
105     }
106   }
ProbeChecker(Expr * arg,const set<tuple<Decl *,int>> & ptregs,bool is_transitive)107   explicit ProbeChecker(Expr *arg, const set<tuple<Decl *, int>> &ptregs,
108                         bool is_transitive)
109       : ProbeChecker(arg, ptregs, is_transitive, false) {}
VisitCallExpr(CallExpr * E)110   bool VisitCallExpr(CallExpr *E) {
111     needs_probe_ = false;
112 
113     if (is_assign_) {
114       // We're looking for a function that returns an external pointer,
115       // regardless of the number of dereferences.
116       for(auto p : ptregs_) {
117         if (std::get<0>(p) == E->getDirectCallee()) {
118           needs_probe_ = true;
119           nb_derefs_ += std::get<1>(p);
120           return false;
121         }
122       }
123     } else {
124       tuple<Decl *, int> pt = make_tuple(E->getDirectCallee(), nb_derefs_);
125       if (ptregs_.find(pt) != ptregs_.end())
126         needs_probe_ = true;
127     }
128 
129     if (!track_helpers_)
130       return false;
131     if (VarDecl *V = dyn_cast<VarDecl>(E->getCalleeDecl()))
132       needs_probe_ = V->getName() == "bpf_get_current_task";
133     return false;
134   }
VisitMemberExpr(MemberExpr * M)135   bool VisitMemberExpr(MemberExpr *M) {
136     tuple<Decl *, int> pt = make_tuple(M->getMemberDecl(), nb_derefs_);
137     if (ptregs_.find(pt) != ptregs_.end()) {
138       needs_probe_ = true;
139       return false;
140     }
141     if (M->isArrow()) {
142       /* In A->b, if A is an external pointer, then A->b should be considered
143        * one too.  However, if we're taking the address of A->b
144        * (nb_derefs_ < 0), we should take it into account for the number of
145        * indirections; &A->b is a pointer to A with an offset. */
146       if (nb_derefs_ >= 0) {
147         ProbeChecker checker = ProbeChecker(M->getBase(), ptregs_,
148                                             track_helpers_, is_assign_);
149         if (checker.needs_probe() && checker.get_nb_derefs() == 0) {
150           needs_probe_ = true;
151           return false;
152         }
153       }
154       nb_derefs_++;
155     }
156     return true;
157   }
VisitUnaryOperator(UnaryOperator * E)158   bool VisitUnaryOperator(UnaryOperator *E) {
159     if (E->getOpcode() == UO_Deref) {
160       /* In *A, if A is an external pointer, then *A should be considered one
161        * too. */
162       ProbeChecker checker = ProbeChecker(E->getSubExpr(), ptregs_,
163                                           track_helpers_, is_assign_);
164       if (checker.needs_probe() && checker.get_nb_derefs() == 0) {
165         needs_probe_ = true;
166         return false;
167       }
168       nb_derefs_++;
169     } else if (E->getOpcode() == UO_AddrOf) {
170       nb_derefs_--;
171     }
172     return true;
173   }
VisitDeclRefExpr(DeclRefExpr * E)174   bool VisitDeclRefExpr(DeclRefExpr *E) {
175     if (is_assign_) {
176       // We're looking for an external pointer, regardless of the number of
177       // dereferences.
178       for(auto p : ptregs_) {
179         if (std::get<0>(p) == E->getDecl()) {
180           needs_probe_ = true;
181           nb_derefs_ += std::get<1>(p);
182           return false;
183         }
184       }
185     } else {
186       tuple<Decl *, int> pt = make_tuple(E->getDecl(), nb_derefs_);
187       if (ptregs_.find(pt) != ptregs_.end())
188         needs_probe_ = true;
189     }
190     return true;
191   }
needs_probe() const192   bool needs_probe() const { return needs_probe_; }
is_transitive() const193   bool is_transitive() const { return is_transitive_; }
get_nb_derefs() const194   int get_nb_derefs() const { return nb_derefs_; }
195  private:
196   bool needs_probe_;
197   bool is_transitive_;
198   const set<tuple<Decl *, int>> &ptregs_;
199   bool track_helpers_;
200   // Nb of dereferences we go through before finding the external pointer.
201   // A negative number counts the number of addrof.
202   int nb_derefs_;
203   bool is_assign_;
204 };
205 
206 // Visit a piece of the AST and mark it as needing probe reads
207 class ProbeSetter : public RecursiveASTVisitor<ProbeSetter> {
208  public:
ProbeSetter(set<tuple<Decl *,int>> * ptregs,int nb_addrof)209   explicit ProbeSetter(set<tuple<Decl *, int>> *ptregs, int nb_addrof)
210       : ptregs_(ptregs), nb_derefs_(-nb_addrof) {}
VisitDeclRefExpr(DeclRefExpr * E)211   bool VisitDeclRefExpr(DeclRefExpr *E) {
212     tuple<Decl *, int> pt = make_tuple(E->getDecl(), nb_derefs_);
213     ptregs_->insert(pt);
214     return true;
215   }
ProbeSetter(set<tuple<Decl *,int>> * ptregs)216   explicit ProbeSetter(set<tuple<Decl *, int>> *ptregs)
217       : ProbeSetter(ptregs, 0) {}
VisitUnaryOperator(UnaryOperator * E)218   bool VisitUnaryOperator(UnaryOperator *E) {
219     if (E->getOpcode() == UO_Deref)
220       nb_derefs_++;
221     return true;
222   }
VisitMemberExpr(MemberExpr * M)223   bool VisitMemberExpr(MemberExpr *M) {
224     tuple<Decl *, int> pt = make_tuple(M->getMemberDecl(), nb_derefs_);
225     ptregs_->insert(pt);
226     return false;
227   }
228  private:
229   set<tuple<Decl *, int>> *ptregs_;
230   // Nb of dereferences we go through before getting to the actual variable.
231   int nb_derefs_;
232 };
233 
MapVisitor(set<Decl * > & m)234 MapVisitor::MapVisitor(set<Decl *> &m) : m_(m) {}
235 
VisitCallExpr(CallExpr * Call)236 bool MapVisitor::VisitCallExpr(CallExpr *Call) {
237   if (MemberExpr *Memb = dyn_cast<MemberExpr>(Call->getCallee()->IgnoreImplicit())) {
238     StringRef memb_name = Memb->getMemberDecl()->getName();
239     if (DeclRefExpr *Ref = dyn_cast<DeclRefExpr>(Memb->getBase())) {
240       if (SectionAttr *A = Ref->getDecl()->getAttr<SectionAttr>()) {
241         if (!A->getName().startswith("maps"))
242           return true;
243 
244         if (memb_name == "update" || memb_name == "insert") {
245           ProbeChecker checker = ProbeChecker(Call->getArg(1), ptregs_, true,
246                                               true);
247           if (checker.needs_probe())
248             m_.insert(Ref->getDecl());
249         }
250       }
251     }
252   }
253   return true;
254 }
255 
ProbeVisitor(ASTContext & C,Rewriter & rewriter,set<Decl * > & m,bool track_helpers)256 ProbeVisitor::ProbeVisitor(ASTContext &C, Rewriter &rewriter,
257                            set<Decl *> &m, bool track_helpers) :
258   C(C), rewriter_(rewriter), m_(m), track_helpers_(track_helpers),
259   addrof_stmt_(nullptr), is_addrof_(false) {}
260 
assignsExtPtr(Expr * E,int * nbAddrOf)261 bool ProbeVisitor::assignsExtPtr(Expr *E, int *nbAddrOf) {
262   if (IsContextMemberExpr(E)) {
263     *nbAddrOf = 0;
264     return true;
265   }
266 
267   /* If the expression contains a call to another function, we need to visit
268   * that function first to know if a rewrite is necessary (i.e., if the
269   * function returns an external pointer). */
270   if (!TraverseStmt(E))
271     return false;
272 
273   ProbeChecker checker = ProbeChecker(E, ptregs_, track_helpers_,
274                                       true);
275   if (checker.is_transitive()) {
276     // The negative of the number of dereferences is the number of addrof.  In
277     // an assignment, if we went through n addrof before getting the external
278     // pointer, then we'll need n dereferences on the left-hand side variable
279     // to get to the external pointer.
280     *nbAddrOf = -checker.get_nb_derefs();
281     return true;
282   }
283 
284   if (E->IgnoreParenCasts()->getStmtClass() == Stmt::CallExprClass) {
285     CallExpr *Call = dyn_cast<CallExpr>(E->IgnoreParenCasts());
286     if (MemberExpr *Memb = dyn_cast<MemberExpr>(Call->getCallee()->IgnoreImplicit())) {
287       StringRef memb_name = Memb->getMemberDecl()->getName();
288       if (DeclRefExpr *Ref = dyn_cast<DeclRefExpr>(Memb->getBase())) {
289         if (SectionAttr *A = Ref->getDecl()->getAttr<SectionAttr>()) {
290           if (!A->getName().startswith("maps"))
291             return false;
292 
293           if (memb_name == "lookup" || memb_name == "lookup_or_init") {
294             if (m_.find(Ref->getDecl()) != m_.end()) {
295               // Retrieved an ext. pointer from a map, mark LHS as ext. pointer.
296               // Pointers from maps always need a single dereference to get the
297               // actual value.  The value may be an external pointer but cannot
298               // be a pointer to an external pointer as the verifier prohibits
299               // storing known pointers (to map values, context, the stack, or
300               // the packet) in maps.
301               *nbAddrOf = 1;
302               return true;
303             }
304           }
305         }
306       }
307     }
308   }
309   return false;
310 }
VisitVarDecl(VarDecl * D)311 bool ProbeVisitor::VisitVarDecl(VarDecl *D) {
312   if (Expr *E = D->getInit()) {
313     int nbAddrOf;
314     if (assignsExtPtr(E, &nbAddrOf)) {
315       // The negative of the number of addrof is the number of dereferences.
316       tuple<Decl *, int> pt = make_tuple(D, -nbAddrOf);
317       set_ptreg(pt);
318     }
319   }
320   return true;
321 }
322 
TraverseStmt(Stmt * S)323 bool ProbeVisitor::TraverseStmt(Stmt *S) {
324   if (whitelist_.find(S) != whitelist_.end())
325     return true;
326   auto ret = RecursiveASTVisitor<ProbeVisitor>::TraverseStmt(S);
327   if (addrof_stmt_ == S) {
328     addrof_stmt_ = nullptr;
329     is_addrof_ = false;
330   }
331   return ret;
332 }
333 
VisitCallExpr(CallExpr * Call)334 bool ProbeVisitor::VisitCallExpr(CallExpr *Call) {
335   // Skip bpf_probe_read for the third argument if it is an AddrOf.
336   if (VarDecl *V = dyn_cast<VarDecl>(Call->getCalleeDecl())) {
337     if (V->getName() == "bpf_probe_read" && Call->getNumArgs() >= 3) {
338       const Expr *E = Call->getArg(2)->IgnoreParenCasts();
339       whitelist_.insert(E);
340       return true;
341     }
342   }
343 
344   if (FunctionDecl *F = dyn_cast<FunctionDecl>(Call->getCalleeDecl())) {
345     if (F->hasBody()) {
346       unsigned i = 0;
347       for (auto arg : Call->arguments()) {
348         ProbeChecker checker = ProbeChecker(arg, ptregs_, track_helpers_,
349                                             true);
350         if (checker.needs_probe()) {
351           tuple<Decl *, int> pt = make_tuple(F->getParamDecl(i),
352                                              checker.get_nb_derefs());
353           ptregs_.insert(pt);
354         }
355         ++i;
356       }
357       if (fn_visited_.find(F) == fn_visited_.end()) {
358         fn_visited_.insert(F);
359         /* Maintains a stack of the number of dereferences for the external
360          * pointers returned by each function in the call stack or -1 if the
361          * function didn't return an external pointer. */
362         ptregs_returned_.push_back(-1);
363         TraverseDecl(F);
364         int nb_derefs = ptregs_returned_.back();
365         ptregs_returned_.pop_back();
366         if (nb_derefs != -1) {
367           tuple<Decl *, int> pt = make_tuple(F, nb_derefs);
368           ptregs_.insert(pt);
369         }
370       }
371     }
372   }
373   return true;
374 }
VisitReturnStmt(ReturnStmt * R)375 bool ProbeVisitor::VisitReturnStmt(ReturnStmt *R) {
376   /* If this function wasn't called by another, there's no need to check the
377    * return statement for external pointers. */
378   if (ptregs_returned_.size() == 0)
379     return true;
380 
381   /* Reverse order of traversals.  This is needed if, in the return statement,
382    * we're calling a function that's returning an external pointer: we need to
383    * know what the function is returning to decide what this function is
384    * returning. */
385   if (!TraverseStmt(R->getRetValue()))
386     return false;
387 
388   ProbeChecker checker = ProbeChecker(R->getRetValue(), ptregs_,
389                                       track_helpers_, true);
390   if (checker.needs_probe()) {
391     int curr_nb_derefs = ptregs_returned_.back();
392     /* If the function returns external pointers with different levels of
393      * indirection, we handle the case with the highest level of indirection
394      * and leave it to the user to manually handle other cases. */
395     if (checker.get_nb_derefs() > curr_nb_derefs) {
396       ptregs_returned_.pop_back();
397       ptregs_returned_.push_back(checker.get_nb_derefs());
398     }
399   }
400   return true;
401 }
VisitBinaryOperator(BinaryOperator * E)402 bool ProbeVisitor::VisitBinaryOperator(BinaryOperator *E) {
403   if (!E->isAssignmentOp())
404     return true;
405 
406   // copy probe attribute from RHS to LHS if present
407   int nbAddrOf;
408   if (assignsExtPtr(E->getRHS(), &nbAddrOf)) {
409     ProbeSetter setter(&ptregs_, nbAddrOf);
410     setter.TraverseStmt(E->getLHS());
411   }
412   return true;
413 }
VisitUnaryOperator(UnaryOperator * E)414 bool ProbeVisitor::VisitUnaryOperator(UnaryOperator *E) {
415   if (E->getOpcode() == UO_AddrOf) {
416     addrof_stmt_ = E;
417     is_addrof_ = true;
418   }
419   if (E->getOpcode() != UO_Deref)
420     return true;
421   if (memb_visited_.find(E) != memb_visited_.end())
422     return true;
423   Expr *sub = E->getSubExpr();
424   if (!ProbeChecker(sub, ptregs_, track_helpers_).needs_probe())
425     return true;
426   memb_visited_.insert(E);
427   string pre, post;
428   pre = "({ typeof(" + E->getType().getAsString() + ") _val; __builtin_memset(&_val, 0, sizeof(_val));";
429   pre += " bpf_probe_read(&_val, sizeof(_val), (u64)";
430   post = "); _val; })";
431   rewriter_.ReplaceText(expansionLoc(E->getOperatorLoc()), 1, pre);
432   rewriter_.InsertTextAfterToken(expansionLoc(GET_ENDLOC(sub)), post);
433   return true;
434 }
VisitMemberExpr(MemberExpr * E)435 bool ProbeVisitor::VisitMemberExpr(MemberExpr *E) {
436   if (memb_visited_.find(E) != memb_visited_.end()) return true;
437 
438   Expr *base;
439   SourceLocation rhs_start, member;
440   bool found = false;
441   for (MemberExpr *M = E; M; M = dyn_cast<MemberExpr>(M->getBase())) {
442     memb_visited_.insert(M);
443     rhs_start = GET_ENDLOC(M);
444     base = M->getBase();
445     member = M->getMemberLoc();
446     if (M->isArrow()) {
447       found = true;
448       break;
449     }
450   }
451   if (!found)
452     return true;
453   if (member.isInvalid()) {
454     error(GET_ENDLOC(base), "internal error: MemberLoc is invalid while preparing probe rewrite");
455     return false;
456   }
457 
458   if (!rewriter_.isRewritable(GET_BEGINLOC(E)))
459     return true;
460 
461   // parent expr has addrof, skip the rewrite, set is_addrof_ to flase so
462   // it won't affect next level of indirect address
463   if (is_addrof_) {
464     is_addrof_ = false;
465     return true;
466   }
467 
468   /* If the base of the dereference is a call to another function, we need to
469    * visit that function first to know if a rewrite is necessary (i.e., if the
470    * function returns an external pointer). */
471   if (base->IgnoreParenCasts()->getStmtClass() == Stmt::CallExprClass) {
472     CallExpr *Call = dyn_cast<CallExpr>(base->IgnoreParenCasts());
473     if (!TraverseStmt(Call))
474       return false;
475   }
476 
477   // Checks to see if the expression references something that needs to be run
478   // through bpf_probe_read.
479   if (!ProbeChecker(base, ptregs_, track_helpers_).needs_probe())
480     return true;
481 
482   string rhs = rewriter_.getRewrittenText(expansionRange(SourceRange(rhs_start, GET_ENDLOC(E))));
483   string base_type = base->getType()->getPointeeType().getAsString();
484   string pre, post;
485   pre = "({ typeof(" + E->getType().getAsString() + ") _val; __builtin_memset(&_val, 0, sizeof(_val));";
486   pre += " bpf_probe_read(&_val, sizeof(_val), (u64)&";
487   post = rhs + "); _val; })";
488   rewriter_.InsertText(expansionLoc(GET_BEGINLOC(E)), pre);
489   rewriter_.ReplaceText(expansionRange(SourceRange(member, GET_ENDLOC(E))), post);
490   return true;
491 }
VisitArraySubscriptExpr(ArraySubscriptExpr * E)492 bool ProbeVisitor::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
493   if (memb_visited_.find(E) != memb_visited_.end()) return true;
494   if (!ProbeChecker(E, ptregs_, track_helpers_).needs_probe())
495     return true;
496 
497   // Parent expr has addrof, skip the rewrite.
498   if (is_addrof_)
499     return true;
500 
501   if (!rewriter_.isRewritable(GET_BEGINLOC(E)))
502     return true;
503 
504   Expr *base = E->getBase();
505   Expr *idx = E->getIdx();
506   memb_visited_.insert(E);
507 
508   if (!rewriter_.isRewritable(GET_BEGINLOC(base)))
509     return true;
510   if (!rewriter_.isRewritable(GET_BEGINLOC(idx)))
511     return true;
512 
513 
514   string pre, lbracket, rbracket;
515   LangOptions opts;
516   SourceLocation lbracket_start, lbracket_end;
517   SourceRange lbracket_range;
518   pre = "({ typeof(" + E->getType().getAsString() + ") _val; __builtin_memset(&_val, 0, sizeof(_val));";
519   pre += " bpf_probe_read(&_val, sizeof(_val), (u64)((";
520   if (isMemberDereference(base)) {
521     pre += "&";
522     // If the base of the array subscript is a member dereference, we'll rewrite
523     // both at the same time.
524     addrof_stmt_ = base;
525     is_addrof_ = true;
526   }
527   rewriter_.InsertText(expansionLoc(GET_BEGINLOC(base)), pre);
528 
529   /* Replace left bracket and any space around it.  Since Clang doesn't provide
530    * a method to retrieve the left bracket, replace everything from the end of
531    * the base to the start of the index. */
532   lbracket = ") + (";
533   lbracket_start = Lexer::getLocForEndOfToken(GET_ENDLOC(base), 1,
534                                               rewriter_.getSourceMgr(),
535                                               opts).getLocWithOffset(1);
536   lbracket_end = GET_BEGINLOC(idx).getLocWithOffset(-1);
537   lbracket_range = expansionRange(SourceRange(lbracket_start, lbracket_end));
538   rewriter_.ReplaceText(lbracket_range, lbracket);
539 
540   rbracket = "))); _val; })";
541   rewriter_.ReplaceText(expansionLoc(E->getRBracketLoc()), 1, rbracket);
542 
543   return true;
544 }
545 
isMemberDereference(Expr * E)546 bool ProbeVisitor::isMemberDereference(Expr *E) {
547   if (E->IgnoreParenCasts()->getStmtClass() != Stmt::MemberExprClass)
548     return false;
549   for (MemberExpr *M = dyn_cast<MemberExpr>(E->IgnoreParenCasts()); M;
550        M = dyn_cast<MemberExpr>(M->getBase()->IgnoreParenCasts())) {
551     if (M->isArrow())
552       return true;
553   }
554   return false;
555 }
IsContextMemberExpr(Expr * E)556 bool ProbeVisitor::IsContextMemberExpr(Expr *E) {
557   if (!E->getType()->isPointerType())
558     return false;
559 
560   Expr *base;
561   SourceLocation member;
562   bool found = false;
563   MemberExpr *M;
564   Expr *Ex = E->IgnoreParenCasts();
565   while (Ex->getStmtClass() == Stmt::ArraySubscriptExprClass
566          || Ex->getStmtClass() == Stmt::MemberExprClass) {
567     if (Ex->getStmtClass() == Stmt::ArraySubscriptExprClass) {
568       Ex = dyn_cast<ArraySubscriptExpr>(Ex)->getBase()->IgnoreParenCasts();
569     } else if (Ex->getStmtClass() == Stmt::MemberExprClass) {
570       M = dyn_cast<MemberExpr>(Ex);
571       base = M->getBase()->IgnoreParenCasts();
572       member = M->getMemberLoc();
573       if (M->isArrow()) {
574         found = true;
575         break;
576       }
577       Ex = base;
578     }
579   }
580   if (!found) {
581     return false;
582   }
583   if (member.isInvalid()) {
584     return false;
585   }
586 
587   if (DeclRefExpr *base_expr = dyn_cast<DeclRefExpr>(base)) {
588     if (base_expr->getDecl() == ctx_) {
589       return true;
590     }
591   }
592   return false;
593 }
594 
595 SourceRange
expansionRange(SourceRange range)596 ProbeVisitor::expansionRange(SourceRange range) {
597 #if LLVM_MAJOR_VERSION >= 7
598   return rewriter_.getSourceMgr().getExpansionRange(range).getAsRange();
599 #else
600   return rewriter_.getSourceMgr().getExpansionRange(range);
601 #endif
602 }
603 
604 SourceLocation
expansionLoc(SourceLocation loc)605 ProbeVisitor::expansionLoc(SourceLocation loc) {
606   return rewriter_.getSourceMgr().getExpansionLoc(loc);
607 }
608 
609 template <unsigned N>
error(SourceLocation loc,const char (& fmt)[N])610 DiagnosticBuilder ProbeVisitor::error(SourceLocation loc, const char (&fmt)[N]) {
611   unsigned int diag_id = C.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error, fmt);
612   return C.getDiagnostics().Report(loc, diag_id);
613 }
614 
BTypeVisitor(ASTContext & C,BFrontendAction & fe)615 BTypeVisitor::BTypeVisitor(ASTContext &C, BFrontendAction &fe)
616     : C(C), diag_(C.getDiagnostics()), fe_(fe), rewriter_(fe.rewriter()), out_(llvm::errs()) {}
617 
genParamDirectAssign(FunctionDecl * D,string & preamble,const char ** calling_conv_regs)618 void BTypeVisitor::genParamDirectAssign(FunctionDecl *D, string& preamble,
619                                         const char **calling_conv_regs) {
620   for (size_t idx = 0; idx < fn_args_.size(); idx++) {
621     ParmVarDecl *arg = fn_args_[idx];
622 
623     if (idx >= 1) {
624       // Move the args into a preamble section where the same params are
625       // declared and initialized from pt_regs.
626       // Todo: this init should be done only when the program requests it.
627       string text = rewriter_.getRewrittenText(expansionRange(arg->getSourceRange()));
628       arg->addAttr(UnavailableAttr::CreateImplicit(C, "ptregs"));
629       size_t d = idx - 1;
630       const char *reg = calling_conv_regs[d];
631       preamble += " " + text + " = " + fn_args_[0]->getName().str() + "->" +
632                   string(reg) + ";";
633     }
634   }
635 }
636 
genParamIndirectAssign(FunctionDecl * D,string & preamble,const char ** calling_conv_regs)637 void BTypeVisitor::genParamIndirectAssign(FunctionDecl *D, string& preamble,
638                                           const char **calling_conv_regs) {
639   string new_ctx;
640 
641   for (size_t idx = 0; idx < fn_args_.size(); idx++) {
642     ParmVarDecl *arg = fn_args_[idx];
643 
644     if (idx == 0) {
645       new_ctx = "__" + arg->getName().str();
646       preamble += " struct pt_regs * " + new_ctx + " = " +
647                   arg->getName().str() + "->" +
648                   string(calling_conv_regs[0]) + ";";
649     } else {
650       // Move the args into a preamble section where the same params are
651       // declared and initialized from pt_regs.
652       // Todo: this init should be done only when the program requests it.
653       string text = rewriter_.getRewrittenText(expansionRange(arg->getSourceRange()));
654       size_t d = idx - 1;
655       const char *reg = calling_conv_regs[d];
656       preamble += "\n " + text + ";";
657       preamble += " bpf_probe_read(&" + arg->getName().str() + ", sizeof(" +
658                   arg->getName().str() + "), &" + new_ctx + "->" +
659                   string(reg) + ");";
660     }
661   }
662 }
663 
rewriteFuncParam(FunctionDecl * D)664 void BTypeVisitor::rewriteFuncParam(FunctionDecl *D) {
665   const char **calling_conv_regs = get_call_conv();
666 
667   string preamble = "{\n";
668   if (D->param_size() > 1) {
669     // If function prefix is "syscall__" or "kprobe____x64_sys_",
670     // the function will attach to a kprobe syscall function.
671     // Guard parameter assiggnment with CONFIG_ARCH_HAS_SYSCALL_WRAPPER.
672     // For __x64_sys_* syscalls, this is always true, but we guard
673     // it in case of "syscall__" for other architectures.
674     if (strncmp(D->getName().str().c_str(), "syscall__", 9) == 0 ||
675         strncmp(D->getName().str().c_str(), "kprobe____x64_sys_", 18) == 0) {
676       preamble += "#ifdef CONFIG_ARCH_HAS_SYSCALL_WRAPPER\n";
677       genParamIndirectAssign(D, preamble, calling_conv_regs);
678       preamble += "\n#else\n";
679       genParamDirectAssign(D, preamble, calling_conv_regs);
680       preamble += "\n#endif\n";
681     } else {
682       genParamDirectAssign(D, preamble, calling_conv_regs);
683     }
684     rewriter_.ReplaceText(
685         expansionRange(SourceRange(GET_ENDLOC(D->getParamDecl(0)),
686                     GET_ENDLOC(D->getParamDecl(D->getNumParams() - 1)))),
687         fn_args_[0]->getName());
688   }
689   // for each trace argument, convert the variable from ptregs to something on stack
690   if (CompoundStmt *S = dyn_cast<CompoundStmt>(D->getBody()))
691     rewriter_.ReplaceText(S->getLBracLoc(), 1, preamble);
692 }
693 
VisitFunctionDecl(FunctionDecl * D)694 bool BTypeVisitor::VisitFunctionDecl(FunctionDecl *D) {
695   // put each non-static non-inline function decl in its own section, to be
696   // extracted by the MemoryManager
697   auto real_start_loc = rewriter_.getSourceMgr().getFileLoc(GET_BEGINLOC(D));
698   if (fe_.is_rewritable_ext_func(D)) {
699     current_fn_ = D->getName();
700     string bd = rewriter_.getRewrittenText(expansionRange(D->getSourceRange()));
701     fe_.func_src_.set_src(current_fn_, bd);
702     fe_.func_range_[current_fn_] = expansionRange(D->getSourceRange());
703     string attr = string("__attribute__((section(\"") + BPF_FN_PREFIX + D->getName().str() + "\")))\n";
704     rewriter_.InsertText(real_start_loc, attr);
705     if (D->param_size() > MAX_CALLING_CONV_REGS + 1) {
706       error(GET_BEGINLOC(D->getParamDecl(MAX_CALLING_CONV_REGS + 1)),
707             "too many arguments, bcc only supports in-register parameters");
708       return false;
709     }
710 
711     fn_args_.clear();
712     for (auto arg_it = D->param_begin(); arg_it != D->param_end(); arg_it++) {
713       auto *arg = *arg_it;
714       if (arg->getName() == "") {
715         error(GET_ENDLOC(arg), "arguments to BPF program definition must be named");
716         return false;
717       }
718       fn_args_.push_back(arg);
719     }
720     rewriteFuncParam(D);
721   } else if (D->hasBody() &&
722              rewriter_.getSourceMgr().getFileID(real_start_loc)
723                == rewriter_.getSourceMgr().getMainFileID()) {
724     // rewritable functions that are static should be always treated as helper
725     rewriter_.InsertText(real_start_loc, "__attribute__((always_inline))\n");
726   }
727   return true;
728 }
729 
730 // Reverse the order of call traversal so that parameters inside of
731 // function calls will get rewritten before the call itself, otherwise
732 // text mangling will result.
TraverseCallExpr(CallExpr * Call)733 bool BTypeVisitor::TraverseCallExpr(CallExpr *Call) {
734   for (auto child : Call->children())
735     if (!TraverseStmt(child))
736       return false;
737   if (!WalkUpFromCallExpr(Call))
738     return false;
739   return true;
740 }
741 
742 // convert calls of the type:
743 //  table.foo(&key)
744 // to:
745 //  bpf_table_foo_elem(bpf_pseudo_fd(table), &key [,&leaf])
VisitCallExpr(CallExpr * Call)746 bool BTypeVisitor::VisitCallExpr(CallExpr *Call) {
747   // make sure node is a reference to a bpf table, which is assured by the
748   // presence of the section("maps/<typename>") GNU __attribute__
749   if (MemberExpr *Memb = dyn_cast<MemberExpr>(Call->getCallee()->IgnoreImplicit())) {
750     StringRef memb_name = Memb->getMemberDecl()->getName();
751     if (DeclRefExpr *Ref = dyn_cast<DeclRefExpr>(Memb->getBase())) {
752       if (SectionAttr *A = Ref->getDecl()->getAttr<SectionAttr>()) {
753         if (!A->getName().startswith("maps"))
754           return true;
755 
756         string args = rewriter_.getRewrittenText(expansionRange(SourceRange(GET_BEGINLOC(Call->getArg(0)),
757                                                    GET_ENDLOC(Call->getArg(Call->getNumArgs() - 1)))));
758 
759         // find the table fd, which was opened at declaration time
760         TableStorage::iterator desc;
761         Path local_path({fe_.id(), Ref->getDecl()->getName()});
762         Path global_path({Ref->getDecl()->getName()});
763         if (!fe_.table_storage().Find(local_path, desc)) {
764           if (!fe_.table_storage().Find(global_path, desc)) {
765             error(GET_ENDLOC(Ref), "bpf_table %0 failed to open") << Ref->getDecl()->getName();
766             return false;
767           }
768         }
769         string fd = to_string(desc->second.fd);
770         string prefix, suffix;
771         string txt;
772         auto rewrite_start = GET_BEGINLOC(Call);
773         auto rewrite_end = GET_ENDLOC(Call);
774         if (memb_name == "lookup_or_init") {
775           string name = Ref->getDecl()->getName();
776           string arg0 = rewriter_.getRewrittenText(expansionRange(Call->getArg(0)->getSourceRange()));
777           string arg1 = rewriter_.getRewrittenText(expansionRange(Call->getArg(1)->getSourceRange()));
778           string lookup = "bpf_map_lookup_elem_(bpf_pseudo_fd(1, " + fd + ")";
779           string update = "bpf_map_update_elem_(bpf_pseudo_fd(1, " + fd + ")";
780           txt  = "({typeof(" + name + ".leaf) *leaf = " + lookup + ", " + arg0 + "); ";
781           txt += "if (!leaf) {";
782           txt += " " + update + ", " + arg0 + ", " + arg1 + ", BPF_NOEXIST);";
783           txt += " leaf = " + lookup + ", " + arg0 + ");";
784           txt += " if (!leaf) return 0;";
785           txt += "}";
786           txt += "leaf;})";
787         } else if (memb_name == "increment") {
788           string name = Ref->getDecl()->getName();
789           string arg0 = rewriter_.getRewrittenText(expansionRange(Call->getArg(0)->getSourceRange()));
790 
791           string increment_value = "1";
792           if (Call->getNumArgs() == 2) {
793             increment_value = rewriter_.getRewrittenText(expansionRange(Call->getArg(1)->getSourceRange()));
794 
795           }
796 
797           string lookup = "bpf_map_lookup_elem_(bpf_pseudo_fd(1, " + fd + ")";
798           string update = "bpf_map_update_elem_(bpf_pseudo_fd(1, " + fd + ")";
799           txt  = "({ typeof(" + name + ".key) _key = " + arg0 + "; ";
800           txt += "typeof(" + name + ".leaf) *_leaf = " + lookup + ", &_key); ";
801 
802           txt += "if (_leaf) (*_leaf) += " + increment_value + ";";
803           if (desc->second.type == BPF_MAP_TYPE_HASH) {
804             txt += "else { typeof(" + name + ".leaf) _zleaf; __builtin_memset(&_zleaf, 0, sizeof(_zleaf)); ";
805             txt += "_zleaf += " + increment_value + ";";
806             txt += update + ", &_key, &_zleaf, BPF_NOEXIST); } ";
807           }
808           txt += "})";
809         } else if (memb_name == "perf_submit") {
810           string name = Ref->getDecl()->getName();
811           string arg0 = rewriter_.getRewrittenText(expansionRange(Call->getArg(0)->getSourceRange()));
812           string args_other = rewriter_.getRewrittenText(expansionRange(SourceRange(GET_BEGINLOC(Call->getArg(1)),
813                                                            GET_ENDLOC(Call->getArg(2)))));
814           txt = "bpf_perf_event_output(" + arg0 + ", bpf_pseudo_fd(1, " + fd + ")";
815           txt += ", CUR_CPU_IDENTIFIER, " + args_other + ")";
816         } else if (memb_name == "perf_submit_skb") {
817           string skb = rewriter_.getRewrittenText(expansionRange(Call->getArg(0)->getSourceRange()));
818           string skb_len = rewriter_.getRewrittenText(expansionRange(Call->getArg(1)->getSourceRange()));
819           string meta = rewriter_.getRewrittenText(expansionRange(Call->getArg(2)->getSourceRange()));
820           string meta_len = rewriter_.getRewrittenText(expansionRange(Call->getArg(3)->getSourceRange()));
821           txt = "bpf_perf_event_output(" +
822             skb + ", " +
823             "bpf_pseudo_fd(1, " + fd + "), " +
824             "((__u64)" + skb_len + " << 32) | BPF_F_CURRENT_CPU, " +
825             meta + ", " +
826             meta_len + ");";
827         } else if (memb_name == "get_stackid") {
828           if (desc->second.type == BPF_MAP_TYPE_STACK_TRACE) {
829             string arg0 =
830                 rewriter_.getRewrittenText(expansionRange(Call->getArg(0)->getSourceRange()));
831             txt = "bcc_get_stackid(";
832             txt += "bpf_pseudo_fd(1, " + fd + "), " + arg0;
833             rewrite_end = GET_ENDLOC(Call->getArg(0));
834             } else {
835               error(GET_BEGINLOC(Call), "get_stackid only available on stacktrace maps");
836               return false;
837             }
838         } else {
839           if (memb_name == "lookup") {
840             prefix = "bpf_map_lookup_elem";
841             suffix = ")";
842           } else if (memb_name == "update") {
843             prefix = "bpf_map_update_elem";
844             suffix = ", BPF_ANY)";
845           } else if (memb_name == "insert") {
846             if (desc->second.type == BPF_MAP_TYPE_ARRAY) {
847               warning(GET_BEGINLOC(Call), "all element of an array already exist; insert() will have no effect");
848             }
849             prefix = "bpf_map_update_elem";
850             suffix = ", BPF_NOEXIST)";
851           } else if (memb_name == "delete") {
852             prefix = "bpf_map_delete_elem";
853             suffix = ")";
854           } else if (memb_name == "call") {
855             prefix = "bpf_tail_call_";
856             suffix = ")";
857           } else if (memb_name == "perf_read") {
858             prefix = "bpf_perf_event_read";
859             suffix = ")";
860           } else if (memb_name == "perf_counter_value") {
861             prefix = "bpf_perf_event_read_value";
862             suffix = ")";
863           } else if (memb_name == "check_current_task") {
864             prefix = "bpf_current_task_under_cgroup";
865             suffix = ")";
866           } else if (memb_name == "redirect_map") {
867             prefix = "bpf_redirect_map";
868             suffix = ")";
869           } else {
870             error(GET_BEGINLOC(Call), "invalid bpf_table operation %0") << memb_name;
871             return false;
872           }
873           prefix += "((void *)bpf_pseudo_fd(1, " + fd + "), ";
874 
875           txt = prefix + args + suffix;
876         }
877         if (!rewriter_.isRewritable(rewrite_start) || !rewriter_.isRewritable(rewrite_end)) {
878           error(GET_BEGINLOC(Call), "cannot use map function inside a macro");
879           return false;
880         }
881         rewriter_.ReplaceText(expansionRange(SourceRange(rewrite_start, rewrite_end)), txt);
882         return true;
883       }
884     }
885   } else if (Call->getCalleeDecl()) {
886     NamedDecl *Decl = dyn_cast<NamedDecl>(Call->getCalleeDecl());
887     if (!Decl) return true;
888     if (AsmLabelAttr *A = Decl->getAttr<AsmLabelAttr>()) {
889       // Functions with the tag asm("llvm.bpf.extra") are implemented in the
890       // rewriter rather than as a macro since they may also include nested
891       // rewrites, and clang::Rewriter does not support rewrites in macros,
892       // unless one preprocesses the entire source file.
893       if (A->getLabel() == "llvm.bpf.extra") {
894         if (!rewriter_.isRewritable(GET_BEGINLOC(Call))) {
895           error(GET_BEGINLOC(Call), "cannot use builtin inside a macro");
896           return false;
897         }
898 
899         vector<string> args;
900         for (auto arg : Call->arguments())
901           args.push_back(rewriter_.getRewrittenText(expansionRange(arg->getSourceRange())));
902 
903         string text;
904         if (Decl->getName() == "incr_cksum_l3") {
905           text = "bpf_l3_csum_replace_(" + fn_args_[0]->getName().str() + ", (u64)";
906           text += args[0] + ", " + args[1] + ", " + args[2] + ", sizeof(" + args[2] + "))";
907           rewriter_.ReplaceText(expansionRange(Call->getSourceRange()), text);
908         } else if (Decl->getName() == "incr_cksum_l4") {
909           text = "bpf_l4_csum_replace_(" + fn_args_[0]->getName().str() + ", (u64)";
910           text += args[0] + ", " + args[1] + ", " + args[2];
911           text += ", ((" + args[3] + " & 0x1) << 4) | sizeof(" + args[2] + "))";
912           rewriter_.ReplaceText(expansionRange(Call->getSourceRange()), text);
913         } else if (Decl->getName() == "bpf_trace_printk") {
914           checkFormatSpecifiers(args[0], GET_BEGINLOC(Call->getArg(0)));
915           //  #define bpf_trace_printk(fmt, args...)
916           //    ({ char _fmt[] = fmt; bpf_trace_printk_(_fmt, sizeof(_fmt), args...); })
917           text = "({ char _fmt[] = " + args[0] + "; bpf_trace_printk_(_fmt, sizeof(_fmt)";
918           if (args.size() <= 1) {
919             text += "); })";
920             rewriter_.ReplaceText(expansionRange(Call->getSourceRange()), text);
921           } else {
922             rewriter_.ReplaceText(expansionRange(SourceRange(GET_BEGINLOC(Call), GET_ENDLOC(Call->getArg(0)))), text);
923             rewriter_.InsertTextAfter(GET_ENDLOC(Call), "); }");
924           }
925         } else if (Decl->getName() == "bpf_num_cpus") {
926           int numcpu = sysconf(_SC_NPROCESSORS_ONLN);
927           if (numcpu <= 0)
928             numcpu = 1;
929           text = to_string(numcpu);
930           rewriter_.ReplaceText(expansionRange(Call->getSourceRange()), text);
931         } else if (Decl->getName() == "bpf_usdt_readarg_p") {
932           text = "({ u64 __addr = 0x0; ";
933           text += "_bpf_readarg_" + current_fn_ + "_" + args[0] + "(" +
934                   args[1] + ", &__addr, sizeof(__addr));";
935           text += "bpf_probe_read(" + args[2] + ", " + args[3] +
936                   ", (void *)__addr);";
937           text += "})";
938           rewriter_.ReplaceText(expansionRange(Call->getSourceRange()), text);
939         } else if (Decl->getName() == "bpf_usdt_readarg") {
940           text = "_bpf_readarg_" + current_fn_ + "_" + args[0] + "(" + args[1] +
941                  ", " + args[2] + ", sizeof(*(" + args[2] + ")))";
942           rewriter_.ReplaceText(expansionRange(Call->getSourceRange()), text);
943         }
944       }
945     } else if (FunctionDecl *F = dyn_cast<FunctionDecl>(Decl)) {
946       if (F->isExternallyVisible() && !F->getBuiltinID()) {
947         auto start_loc = rewriter_.getSourceMgr().getFileLoc(GET_BEGINLOC(Decl));
948         if (rewriter_.getSourceMgr().getFileID(start_loc)
949             == rewriter_.getSourceMgr().getMainFileID()) {
950           error(GET_BEGINLOC(Call), "cannot call non-static helper function");
951           return false;
952         }
953       }
954     }
955   }
956   return true;
957 }
958 
checkFormatSpecifiers(const string & fmt,SourceLocation loc)959 bool BTypeVisitor::checkFormatSpecifiers(const string& fmt, SourceLocation loc) {
960   unsigned nb_specifiers = 0, i, j;
961   bool has_s = false;
962   for (i = 0; i < fmt.length(); i++) {
963     if (!isascii(fmt[i]) || (!isprint(fmt[i]) && !isspace(fmt[i]))) {
964       warning(loc.getLocWithOffset(i), "unrecognized character");
965       return false;
966     }
967     if (fmt[i] != '%')
968       continue;
969     if (nb_specifiers >= 3) {
970       warning(loc.getLocWithOffset(i), "cannot use more than 3 conversion specifiers");
971       return false;
972     }
973     nb_specifiers++;
974     i++;
975     if (fmt[i] == 'l') {
976       i++;
977     } else if (fmt[i] == 'p' || fmt[i] == 's') {
978       i++;
979       if (!isspace(fmt[i]) && !ispunct(fmt[i]) && fmt[i] != 0) {
980         warning(loc.getLocWithOffset(i - 2),
981                 "only %%d %%u %%x %%ld %%lu %%lx %%lld %%llu %%llx %%p %%s conversion specifiers allowed");
982         return false;
983       }
984       if (fmt[i - 1] == 's') {
985         if (has_s) {
986           warning(loc.getLocWithOffset(i - 2), "cannot use several %%s conversion specifiers");
987           return false;
988         }
989         has_s = true;
990       }
991       continue;
992     }
993     j = 1;
994     if (fmt[i] == 'l') {
995       i++;
996       j++;
997     }
998     if (fmt[i] != 'd' && fmt[i] != 'u' && fmt[i] != 'x') {
999       warning(loc.getLocWithOffset(i - j),
1000               "only %%d %%u %%x %%ld %%lu %%lx %%lld %%llu %%llx %%p %%s conversion specifiers allowed");
1001       return false;
1002     }
1003   }
1004   return true;
1005 }
1006 
VisitBinaryOperator(BinaryOperator * E)1007 bool BTypeVisitor::VisitBinaryOperator(BinaryOperator *E) {
1008   if (!E->isAssignmentOp())
1009     return true;
1010   Expr *LHS = E->getLHS()->IgnoreImplicit();
1011   if (MemberExpr *Memb = dyn_cast<MemberExpr>(LHS)) {
1012     if (DeclRefExpr *Base = dyn_cast<DeclRefExpr>(Memb->getBase()->IgnoreImplicit())) {
1013       if (DeprecatedAttr *A = Base->getDecl()->getAttr<DeprecatedAttr>()) {
1014         if (A->getMessage() == "packet") {
1015           if (FieldDecl *F = dyn_cast<FieldDecl>(Memb->getMemberDecl())) {
1016             if (!rewriter_.isRewritable(GET_BEGINLOC(E))) {
1017               error(GET_BEGINLOC(E), "cannot use \"packet\" header type inside a macro");
1018               return false;
1019             }
1020             uint64_t ofs = C.getFieldOffset(F);
1021             uint64_t sz = F->isBitField() ? F->getBitWidthValue(C) : C.getTypeSize(F->getType());
1022             string base = rewriter_.getRewrittenText(expansionRange(Base->getSourceRange()));
1023             string text = "bpf_dins_pkt(" + fn_args_[0]->getName().str() + ", (u64)" + base + "+" + to_string(ofs >> 3)
1024                 + ", " + to_string(ofs & 0x7) + ", " + to_string(sz) + ",";
1025             rewriter_.ReplaceText(expansionRange(SourceRange(GET_BEGINLOC(E), E->getOperatorLoc())), text);
1026             rewriter_.InsertTextAfterToken(GET_ENDLOC(E), ")");
1027           }
1028         }
1029       }
1030     }
1031   }
1032   return true;
1033 }
VisitImplicitCastExpr(ImplicitCastExpr * E)1034 bool BTypeVisitor::VisitImplicitCastExpr(ImplicitCastExpr *E) {
1035   // use dext only for RValues
1036   if (E->getCastKind() != CK_LValueToRValue)
1037     return true;
1038   MemberExpr *Memb = dyn_cast<MemberExpr>(E->IgnoreImplicit());
1039   if (!Memb)
1040     return true;
1041   Expr *Base = Memb->getBase()->IgnoreImplicit();
1042   if (DeclRefExpr *Ref = dyn_cast<DeclRefExpr>(Base)) {
1043     if (DeprecatedAttr *A = Ref->getDecl()->getAttr<DeprecatedAttr>()) {
1044       if (A->getMessage() == "packet") {
1045         if (FieldDecl *F = dyn_cast<FieldDecl>(Memb->getMemberDecl())) {
1046           if (!rewriter_.isRewritable(GET_BEGINLOC(E))) {
1047             error(GET_BEGINLOC(E), "cannot use \"packet\" header type inside a macro");
1048             return false;
1049           }
1050           uint64_t ofs = C.getFieldOffset(F);
1051           uint64_t sz = F->isBitField() ? F->getBitWidthValue(C) : C.getTypeSize(F->getType());
1052           string text = "bpf_dext_pkt(" + fn_args_[0]->getName().str() + ", (u64)" + Ref->getDecl()->getName().str() + "+"
1053               + to_string(ofs >> 3) + ", " + to_string(ofs & 0x7) + ", " + to_string(sz) + ")";
1054           rewriter_.ReplaceText(expansionRange(E->getSourceRange()), text);
1055         }
1056       }
1057     }
1058   }
1059   return true;
1060 }
1061 
1062 SourceRange
expansionRange(SourceRange range)1063 BTypeVisitor::expansionRange(SourceRange range) {
1064 #if LLVM_MAJOR_VERSION >= 7
1065   return rewriter_.getSourceMgr().getExpansionRange(range).getAsRange();
1066 #else
1067   return rewriter_.getSourceMgr().getExpansionRange(range);
1068 #endif
1069 }
1070 
1071 template <unsigned N>
error(SourceLocation loc,const char (& fmt)[N])1072 DiagnosticBuilder BTypeVisitor::error(SourceLocation loc, const char (&fmt)[N]) {
1073   unsigned int diag_id = C.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error, fmt);
1074   return C.getDiagnostics().Report(loc, diag_id);
1075 }
1076 
1077 template <unsigned N>
warning(SourceLocation loc,const char (& fmt)[N])1078 DiagnosticBuilder BTypeVisitor::warning(SourceLocation loc, const char (&fmt)[N]) {
1079   unsigned int diag_id = C.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Warning, fmt);
1080   return C.getDiagnostics().Report(loc, diag_id);
1081 }
1082 
getFieldValue(VarDecl * Decl,FieldDecl * FDecl,int64_t OrigFValue)1083 int64_t BTypeVisitor::getFieldValue(VarDecl *Decl, FieldDecl *FDecl, int64_t OrigFValue) {
1084   unsigned idx = FDecl->getFieldIndex();
1085 
1086   if (auto I = dyn_cast_or_null<InitListExpr>(Decl->getInit())) {
1087 #if LLVM_MAJOR_VERSION >= 8
1088     Expr::EvalResult res;
1089     if (I->getInit(idx)->EvaluateAsInt(res, C)) {
1090       return res.Val.getInt().getExtValue();
1091     }
1092 #else
1093     llvm::APSInt res;
1094     if (I->getInit(idx)->EvaluateAsInt(res, C)) {
1095       return res.getExtValue();
1096     }
1097 #endif
1098   }
1099 
1100   return OrigFValue;
1101 }
1102 
1103 // Open table FDs when bpf tables (as denoted by section("maps*") attribute)
1104 // are declared.
VisitVarDecl(VarDecl * Decl)1105 bool BTypeVisitor::VisitVarDecl(VarDecl *Decl) {
1106   const RecordType *R = Decl->getType()->getAs<RecordType>();
1107   if (SectionAttr *A = Decl->getAttr<SectionAttr>()) {
1108     if (!A->getName().startswith("maps"))
1109       return true;
1110     if (!R) {
1111       error(GET_ENDLOC(Decl), "invalid type for bpf_table, expect struct");
1112       return false;
1113     }
1114     const RecordDecl *RD = R->getDecl()->getDefinition();
1115 
1116     TableDesc table;
1117     TableStorage::iterator table_it;
1118     table.name = Decl->getName();
1119     Path local_path({fe_.id(), table.name});
1120     Path maps_ns_path({"ns", fe_.maps_ns(), table.name});
1121     Path global_path({table.name});
1122     QualType key_type, leaf_type;
1123 
1124     unsigned i = 0;
1125     for (auto F : RD->fields()) {
1126       if (F->getType().getTypePtr()->isIncompleteType()) {
1127         error(GET_BEGINLOC(F), "unknown type");
1128         return false;
1129       }
1130 
1131       size_t sz = C.getTypeSize(F->getType()) >> 3;
1132       if (F->getName() == "key") {
1133         if (sz == 0) {
1134           error(GET_BEGINLOC(F), "invalid zero-sized leaf");
1135           return false;
1136         }
1137         table.key_size = sz;
1138         key_type = F->getType();
1139       } else if (F->getName() == "leaf") {
1140         if (sz == 0) {
1141           error(GET_BEGINLOC(F), "invalid zero-sized leaf");
1142           return false;
1143         }
1144         table.leaf_size = sz;
1145         leaf_type = F->getType();
1146       } else if (F->getName() == "max_entries") {
1147             table.max_entries = getFieldValue(Decl, F, table.max_entries);
1148       } else if (F->getName() == "flags") {
1149             table.flags = getFieldValue(Decl, F, table.flags);
1150       }
1151       ++i;
1152     }
1153 
1154     bpf_map_type map_type = BPF_MAP_TYPE_UNSPEC;
1155     if (A->getName() == "maps/hash") {
1156       map_type = BPF_MAP_TYPE_HASH;
1157     } else if (A->getName() == "maps/array") {
1158       map_type = BPF_MAP_TYPE_ARRAY;
1159     } else if (A->getName() == "maps/percpu_hash") {
1160       map_type = BPF_MAP_TYPE_PERCPU_HASH;
1161     } else if (A->getName() == "maps/percpu_array") {
1162       map_type = BPF_MAP_TYPE_PERCPU_ARRAY;
1163     } else if (A->getName() == "maps/lru_hash") {
1164       map_type = BPF_MAP_TYPE_LRU_HASH;
1165     } else if (A->getName() == "maps/lru_percpu_hash") {
1166       map_type = BPF_MAP_TYPE_LRU_PERCPU_HASH;
1167     } else if (A->getName() == "maps/lpm_trie") {
1168       map_type = BPF_MAP_TYPE_LPM_TRIE;
1169     } else if (A->getName() == "maps/histogram") {
1170       map_type = BPF_MAP_TYPE_HASH;
1171       if (key_type->isSpecificBuiltinType(BuiltinType::Int))
1172         map_type = BPF_MAP_TYPE_ARRAY;
1173       if (!leaf_type->isSpecificBuiltinType(BuiltinType::ULongLong))
1174         error(GET_BEGINLOC(Decl), "histogram leaf type must be u64, got %0") << leaf_type;
1175     } else if (A->getName() == "maps/prog") {
1176       map_type = BPF_MAP_TYPE_PROG_ARRAY;
1177     } else if (A->getName() == "maps/perf_output") {
1178       map_type = BPF_MAP_TYPE_PERF_EVENT_ARRAY;
1179       int numcpu = get_possible_cpus().size();
1180       if (numcpu <= 0)
1181         numcpu = 1;
1182       table.max_entries = numcpu;
1183     } else if (A->getName() == "maps/perf_array") {
1184       map_type = BPF_MAP_TYPE_PERF_EVENT_ARRAY;
1185     } else if (A->getName() == "maps/cgroup_array") {
1186       map_type = BPF_MAP_TYPE_CGROUP_ARRAY;
1187     } else if (A->getName() == "maps/stacktrace") {
1188       map_type = BPF_MAP_TYPE_STACK_TRACE;
1189     } else if (A->getName() == "maps/devmap") {
1190       map_type = BPF_MAP_TYPE_DEVMAP;
1191     } else if (A->getName() == "maps/cpumap") {
1192       map_type = BPF_MAP_TYPE_CPUMAP;
1193     } else if (A->getName() == "maps/extern") {
1194       if (!fe_.table_storage().Find(maps_ns_path, table_it)) {
1195         if (!fe_.table_storage().Find(global_path, table_it)) {
1196           error(GET_BEGINLOC(Decl), "reference to undefined table");
1197           return false;
1198         }
1199       }
1200       table = table_it->second.dup();
1201       table.is_extern = true;
1202     } else if (A->getName() == "maps/export") {
1203       if (table.name.substr(0, 2) == "__")
1204         table.name = table.name.substr(2);
1205       Path local_path({fe_.id(), table.name});
1206       Path global_path({table.name});
1207       if (!fe_.table_storage().Find(local_path, table_it)) {
1208         error(GET_BEGINLOC(Decl), "reference to undefined table");
1209         return false;
1210       }
1211       fe_.table_storage().Insert(global_path, table_it->second.dup());
1212       return true;
1213     } else if(A->getName() == "maps/shared") {
1214       if (table.name.substr(0, 2) == "__")
1215         table.name = table.name.substr(2);
1216       Path local_path({fe_.id(), table.name});
1217       Path maps_ns_path({"ns", fe_.maps_ns(), table.name});
1218       if (!fe_.table_storage().Find(local_path, table_it)) {
1219         error(GET_BEGINLOC(Decl), "reference to undefined table");
1220         return false;
1221       }
1222       fe_.table_storage().Insert(maps_ns_path, table_it->second.dup());
1223       return true;
1224     }
1225 
1226     if (!table.is_extern) {
1227       if (map_type == BPF_MAP_TYPE_UNSPEC) {
1228         error(GET_BEGINLOC(Decl), "unsupported map type: %0") << A->getName();
1229         return false;
1230       }
1231 
1232       table.type = map_type;
1233       table.fd = bpf_create_map(map_type, table.name.c_str(),
1234                                 table.key_size, table.leaf_size,
1235                                 table.max_entries, table.flags);
1236     }
1237     if (table.fd < 0) {
1238       error(GET_BEGINLOC(Decl), "could not open bpf map: %0\nis %1 map type enabled in your kernel?") <<
1239           strerror(errno) << A->getName();
1240       return false;
1241     }
1242 
1243     if (!table.is_extern)
1244       fe_.table_storage().VisitMapType(table, C, key_type, leaf_type);
1245     fe_.table_storage().Insert(local_path, move(table));
1246   } else if (const PointerType *P = Decl->getType()->getAs<PointerType>()) {
1247     // if var is a pointer to a packet type, clone the annotation into the var
1248     // decl so that the packet dext/dins rewriter can catch it
1249     if (const RecordType *RT = P->getPointeeType()->getAs<RecordType>()) {
1250       if (const RecordDecl *RD = RT->getDecl()->getDefinition()) {
1251         if (DeprecatedAttr *DA = RD->getAttr<DeprecatedAttr>()) {
1252           if (DA->getMessage() == "packet") {
1253             Decl->addAttr(DA->clone(C));
1254           }
1255         }
1256       }
1257     }
1258   }
1259   return true;
1260 }
1261 
1262 // First traversal of AST to retrieve maps with external pointers.
BTypeConsumer(ASTContext & C,BFrontendAction & fe,Rewriter & rewriter,set<Decl * > & m)1263 BTypeConsumer::BTypeConsumer(ASTContext &C, BFrontendAction &fe,
1264                              Rewriter &rewriter, set<Decl *> &m)
1265     : fe_(fe),
1266       map_visitor_(m),
1267       btype_visitor_(C, fe),
1268       probe_visitor1_(C, rewriter, m, true),
1269       probe_visitor2_(C, rewriter, m, false) {}
1270 
HandleTranslationUnit(ASTContext & Context)1271 void BTypeConsumer::HandleTranslationUnit(ASTContext &Context) {
1272   DeclContext::decl_iterator it;
1273   DeclContext *DC = TranslationUnitDecl::castToDeclContext(Context.getTranslationUnitDecl());
1274 
1275   /**
1276    * In a first traversal, ProbeVisitor tracks external pointers identified
1277    * through each function's arguments and replaces their dereferences with
1278    * calls to bpf_probe_read. It also passes all identified pointers to
1279    * external addresses to MapVisitor.
1280    */
1281   for (it = DC->decls_begin(); it != DC->decls_end(); it++) {
1282     Decl *D = *it;
1283     if (FunctionDecl *F = dyn_cast<FunctionDecl>(D)) {
1284       if (fe_.is_rewritable_ext_func(F)) {
1285         for (auto arg : F->parameters()) {
1286           if (arg == F->getParamDecl(0)) {
1287             /**
1288              * Limit tracing of pointers from context to tracing contexts.
1289              * We're whitelisting instead of blacklisting to avoid issues with
1290              * existing programs if new context types are added in the future.
1291              */
1292             string type = arg->getType().getAsString();
1293             if (type == "struct pt_regs *" ||
1294                 type == "struct bpf_raw_tracepoint_args *" ||
1295                 type.substr(0, 19) == "struct tracepoint__")
1296               probe_visitor1_.set_ctx(arg);
1297           } else if (!arg->getType()->isFundamentalType()) {
1298             tuple<Decl *, int> pt = make_tuple(arg, 0);
1299             probe_visitor1_.set_ptreg(pt);
1300           }
1301         }
1302 
1303         probe_visitor1_.TraverseDecl(D);
1304         for (auto ptreg : probe_visitor1_.get_ptregs()) {
1305           map_visitor_.set_ptreg(ptreg);
1306         }
1307       }
1308     }
1309   }
1310 
1311   /**
1312    * MapVisitor uses external pointers identified by the first ProbeVisitor
1313    * traversal to identify all maps with external pointers as values.
1314    * MapVisitor runs only after ProbeVisitor finished its traversal of the
1315    * whole translation unit to clearly separate the role of each ProbeVisitor's
1316    * traversal: the first tracks external pointers from function arguments,
1317    * whereas the second tracks external pointers from maps. Without this clear
1318    * separation, ProbeVisitor might attempt to replace several times the same
1319    * dereferences.
1320    */
1321   for (it = DC->decls_begin(); it != DC->decls_end(); it++) {
1322     Decl *D = *it;
1323     if (FunctionDecl *F = dyn_cast<FunctionDecl>(D)) {
1324       if (fe_.is_rewritable_ext_func(F)) {
1325         map_visitor_.TraverseDecl(D);
1326       }
1327     }
1328   }
1329 
1330   /**
1331    * In a second traversal, ProbeVisitor tracks pointers passed through the
1332    * maps identified by MapVisitor and replaces their dereferences with calls
1333    * to bpf_probe_read.
1334    * This last traversal runs after MapVisitor went through an entire
1335    * translation unit, to ensure maps with external pointers have all been
1336    * identified.
1337    */
1338   for (it = DC->decls_begin(); it != DC->decls_end(); it++) {
1339     Decl *D = *it;
1340     if (FunctionDecl *F = dyn_cast<FunctionDecl>(D)) {
1341       if (fe_.is_rewritable_ext_func(F)) {
1342         probe_visitor2_.TraverseDecl(D);
1343       }
1344     }
1345 
1346     btype_visitor_.TraverseDecl(D);
1347   }
1348 }
1349 
BFrontendAction(llvm::raw_ostream & os,unsigned flags,TableStorage & ts,const std::string & id,const std::string & main_path,FuncSource & func_src,std::string & mod_src,const std::string & maps_ns)1350 BFrontendAction::BFrontendAction(llvm::raw_ostream &os, unsigned flags,
1351                                  TableStorage &ts, const std::string &id,
1352                                  const std::string &main_path,
1353                                  FuncSource &func_src, std::string &mod_src,
1354                                  const std::string &maps_ns)
1355     : os_(os),
1356       flags_(flags),
1357       ts_(ts),
1358       id_(id),
1359       maps_ns_(maps_ns),
1360       rewriter_(new Rewriter),
1361       main_path_(main_path),
1362       func_src_(func_src),
1363       mod_src_(mod_src) {}
1364 
is_rewritable_ext_func(FunctionDecl * D)1365 bool BFrontendAction::is_rewritable_ext_func(FunctionDecl *D) {
1366   StringRef file_name = rewriter_->getSourceMgr().getFilename(GET_BEGINLOC(D));
1367   return (D->isExternallyVisible() && D->hasBody() &&
1368           (file_name.empty() || file_name == main_path_));
1369 }
1370 
DoMiscWorkAround()1371 void BFrontendAction::DoMiscWorkAround() {
1372   // In 4.16 and later, CONFIG_CC_STACKPROTECTOR is moved out of Kconfig and into
1373   // Makefile. It will be set depending on CONFIG_CC_STACKPROTECTOR_{AUTO|REGULAR|STRONG}.
1374   // CONFIG_CC_STACKPROTECTOR is still used in various places, e.g., struct task_struct,
1375   // to guard certain fields. The workaround here intends to define
1376   // CONFIG_CC_STACKPROTECTOR properly based on other configs, so it relieved any bpf
1377   // program (using task_struct, etc.) of patching the below code.
1378   rewriter_->getEditBuffer(rewriter_->getSourceMgr().getMainFileID()).InsertText(0,
1379     "#if defined(BPF_LICENSE)\n"
1380     "#error BPF_LICENSE cannot be specified through cflags\n"
1381     "#endif\n"
1382     "#if !defined(CONFIG_CC_STACKPROTECTOR)\n"
1383     "#if defined(CONFIG_CC_STACKPROTECTOR_AUTO) \\\n"
1384     "    || defined(CONFIG_CC_STACKPROTECTOR_REGULAR) \\\n"
1385     "    || defined(CONFIG_CC_STACKPROTECTOR_STRONG)\n"
1386     "#define CONFIG_CC_STACKPROTECTOR\n"
1387     "#endif\n"
1388     "#endif\n",
1389     false);
1390 
1391   rewriter_->getEditBuffer(rewriter_->getSourceMgr().getMainFileID()).InsertTextAfter(
1392     rewriter_->getSourceMgr().getBuffer(rewriter_->getSourceMgr().getMainFileID())->getBufferSize(),
1393     "\n#include <bcc/footer.h>\n");
1394 }
1395 
EndSourceFileAction()1396 void BFrontendAction::EndSourceFileAction() {
1397   // Additional misc rewrites
1398   DoMiscWorkAround();
1399 
1400   if (flags_ & DEBUG_PREPROCESSOR)
1401     rewriter_->getEditBuffer(rewriter_->getSourceMgr().getMainFileID()).write(llvm::errs());
1402   if (flags_ & DEBUG_SOURCE) {
1403     llvm::raw_string_ostream tmp_os(mod_src_);
1404     rewriter_->getEditBuffer(rewriter_->getSourceMgr().getMainFileID())
1405         .write(tmp_os);
1406   }
1407 
1408   for (auto func : func_range_) {
1409     auto f = func.first;
1410     string bd = rewriter_->getRewrittenText(func_range_[f]);
1411     func_src_.set_src_rewritten(f, bd);
1412   }
1413   rewriter_->getEditBuffer(rewriter_->getSourceMgr().getMainFileID()).write(os_);
1414   os_.flush();
1415 }
1416 
CreateASTConsumer(CompilerInstance & Compiler,llvm::StringRef InFile)1417 unique_ptr<ASTConsumer> BFrontendAction::CreateASTConsumer(CompilerInstance &Compiler, llvm::StringRef InFile) {
1418   rewriter_->setSourceMgr(Compiler.getSourceManager(), Compiler.getLangOpts());
1419   vector<unique_ptr<ASTConsumer>> consumers;
1420   consumers.push_back(unique_ptr<ASTConsumer>(new BTypeConsumer(Compiler.getASTContext(), *this, *rewriter_, m_)));
1421   return unique_ptr<ASTConsumer>(new MultiplexConsumer(std::move(consumers)));
1422 }
1423 
1424 }
1425