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
1083 // Open table FDs when bpf tables (as denoted by section("maps*") attribute)
1084 // are declared.
VisitVarDecl(VarDecl * Decl)1085 bool BTypeVisitor::VisitVarDecl(VarDecl *Decl) {
1086 const RecordType *R = Decl->getType()->getAs<RecordType>();
1087 if (SectionAttr *A = Decl->getAttr<SectionAttr>()) {
1088 if (!A->getName().startswith("maps"))
1089 return true;
1090 if (!R) {
1091 error(GET_ENDLOC(Decl), "invalid type for bpf_table, expect struct");
1092 return false;
1093 }
1094 const RecordDecl *RD = R->getDecl()->getDefinition();
1095
1096 TableDesc table;
1097 TableStorage::iterator table_it;
1098 table.name = Decl->getName();
1099 Path local_path({fe_.id(), table.name});
1100 Path maps_ns_path({"ns", fe_.maps_ns(), table.name});
1101 Path global_path({table.name});
1102 QualType key_type, leaf_type;
1103
1104 unsigned i = 0;
1105 for (auto F : RD->fields()) {
1106 if (F->getType().getTypePtr()->isIncompleteType()) {
1107 error(GET_BEGINLOC(F), "unknown type");
1108 return false;
1109 }
1110
1111 size_t sz = C.getTypeSize(F->getType()) >> 3;
1112 if (F->getName() == "key") {
1113 if (sz == 0) {
1114 error(GET_BEGINLOC(F), "invalid zero-sized leaf");
1115 return false;
1116 }
1117 table.key_size = sz;
1118 key_type = F->getType();
1119 } else if (F->getName() == "leaf") {
1120 if (sz == 0) {
1121 error(GET_BEGINLOC(F), "invalid zero-sized leaf");
1122 return false;
1123 }
1124 table.leaf_size = sz;
1125 leaf_type = F->getType();
1126 } else if (F->getName() == "max_entries") {
1127 unsigned idx = F->getFieldIndex();
1128 if (auto I = dyn_cast_or_null<InitListExpr>(Decl->getInit())) {
1129 llvm::APSInt res;
1130 if (I->getInit(idx)->EvaluateAsInt(res, C)) {
1131 table.max_entries = res.getExtValue();
1132 }
1133 }
1134 } else if (F->getName() == "flags") {
1135 unsigned idx = F->getFieldIndex();
1136 if (auto I = dyn_cast_or_null<InitListExpr>(Decl->getInit())) {
1137 llvm::APSInt res;
1138 if (I->getInit(idx)->EvaluateAsInt(res, C)) {
1139 table.flags = res.getExtValue();
1140 }
1141 }
1142 }
1143 ++i;
1144 }
1145
1146 bpf_map_type map_type = BPF_MAP_TYPE_UNSPEC;
1147 if (A->getName() == "maps/hash") {
1148 map_type = BPF_MAP_TYPE_HASH;
1149 } else if (A->getName() == "maps/array") {
1150 map_type = BPF_MAP_TYPE_ARRAY;
1151 } else if (A->getName() == "maps/percpu_hash") {
1152 map_type = BPF_MAP_TYPE_PERCPU_HASH;
1153 } else if (A->getName() == "maps/percpu_array") {
1154 map_type = BPF_MAP_TYPE_PERCPU_ARRAY;
1155 } else if (A->getName() == "maps/lru_hash") {
1156 map_type = BPF_MAP_TYPE_LRU_HASH;
1157 } else if (A->getName() == "maps/lru_percpu_hash") {
1158 map_type = BPF_MAP_TYPE_LRU_PERCPU_HASH;
1159 } else if (A->getName() == "maps/lpm_trie") {
1160 map_type = BPF_MAP_TYPE_LPM_TRIE;
1161 } else if (A->getName() == "maps/histogram") {
1162 map_type = BPF_MAP_TYPE_HASH;
1163 if (key_type->isSpecificBuiltinType(BuiltinType::Int))
1164 map_type = BPF_MAP_TYPE_ARRAY;
1165 if (!leaf_type->isSpecificBuiltinType(BuiltinType::ULongLong))
1166 error(GET_BEGINLOC(Decl), "histogram leaf type must be u64, got %0") << leaf_type;
1167 } else if (A->getName() == "maps/prog") {
1168 map_type = BPF_MAP_TYPE_PROG_ARRAY;
1169 } else if (A->getName() == "maps/perf_output") {
1170 map_type = BPF_MAP_TYPE_PERF_EVENT_ARRAY;
1171 int numcpu = get_possible_cpus().size();
1172 if (numcpu <= 0)
1173 numcpu = 1;
1174 table.max_entries = numcpu;
1175 } else if (A->getName() == "maps/perf_array") {
1176 map_type = BPF_MAP_TYPE_PERF_EVENT_ARRAY;
1177 } else if (A->getName() == "maps/cgroup_array") {
1178 map_type = BPF_MAP_TYPE_CGROUP_ARRAY;
1179 } else if (A->getName() == "maps/stacktrace") {
1180 map_type = BPF_MAP_TYPE_STACK_TRACE;
1181 } else if (A->getName() == "maps/devmap") {
1182 map_type = BPF_MAP_TYPE_DEVMAP;
1183 } else if (A->getName() == "maps/cpumap") {
1184 map_type = BPF_MAP_TYPE_CPUMAP;
1185 } else if (A->getName() == "maps/extern") {
1186 if (!fe_.table_storage().Find(maps_ns_path, table_it)) {
1187 if (!fe_.table_storage().Find(global_path, table_it)) {
1188 error(GET_BEGINLOC(Decl), "reference to undefined table");
1189 return false;
1190 }
1191 }
1192 table = table_it->second.dup();
1193 table.is_extern = true;
1194 } else if (A->getName() == "maps/export") {
1195 if (table.name.substr(0, 2) == "__")
1196 table.name = table.name.substr(2);
1197 Path local_path({fe_.id(), table.name});
1198 Path global_path({table.name});
1199 if (!fe_.table_storage().Find(local_path, table_it)) {
1200 error(GET_BEGINLOC(Decl), "reference to undefined table");
1201 return false;
1202 }
1203 fe_.table_storage().Insert(global_path, table_it->second.dup());
1204 return true;
1205 } else if(A->getName() == "maps/shared") {
1206 if (table.name.substr(0, 2) == "__")
1207 table.name = table.name.substr(2);
1208 Path local_path({fe_.id(), table.name});
1209 Path maps_ns_path({"ns", fe_.maps_ns(), table.name});
1210 if (!fe_.table_storage().Find(local_path, table_it)) {
1211 error(GET_BEGINLOC(Decl), "reference to undefined table");
1212 return false;
1213 }
1214 fe_.table_storage().Insert(maps_ns_path, table_it->second.dup());
1215 return true;
1216 }
1217
1218 if (!table.is_extern) {
1219 if (map_type == BPF_MAP_TYPE_UNSPEC) {
1220 error(GET_BEGINLOC(Decl), "unsupported map type: %0") << A->getName();
1221 return false;
1222 }
1223
1224 table.type = map_type;
1225 table.fd = bpf_create_map(map_type, table.name.c_str(),
1226 table.key_size, table.leaf_size,
1227 table.max_entries, table.flags);
1228 }
1229 if (table.fd < 0) {
1230 error(GET_BEGINLOC(Decl), "could not open bpf map: %0\nis %1 map type enabled in your kernel?") <<
1231 strerror(errno) << A->getName();
1232 return false;
1233 }
1234
1235 if (!table.is_extern)
1236 fe_.table_storage().VisitMapType(table, C, key_type, leaf_type);
1237 fe_.table_storage().Insert(local_path, move(table));
1238 } else if (const PointerType *P = Decl->getType()->getAs<PointerType>()) {
1239 // if var is a pointer to a packet type, clone the annotation into the var
1240 // decl so that the packet dext/dins rewriter can catch it
1241 if (const RecordType *RT = P->getPointeeType()->getAs<RecordType>()) {
1242 if (const RecordDecl *RD = RT->getDecl()->getDefinition()) {
1243 if (DeprecatedAttr *DA = RD->getAttr<DeprecatedAttr>()) {
1244 if (DA->getMessage() == "packet") {
1245 Decl->addAttr(DA->clone(C));
1246 }
1247 }
1248 }
1249 }
1250 }
1251 return true;
1252 }
1253
1254 // First traversal of AST to retrieve maps with external pointers.
BTypeConsumer(ASTContext & C,BFrontendAction & fe,Rewriter & rewriter,set<Decl * > & m)1255 BTypeConsumer::BTypeConsumer(ASTContext &C, BFrontendAction &fe,
1256 Rewriter &rewriter, set<Decl *> &m)
1257 : fe_(fe),
1258 map_visitor_(m),
1259 btype_visitor_(C, fe),
1260 probe_visitor1_(C, rewriter, m, true),
1261 probe_visitor2_(C, rewriter, m, false) {}
1262
HandleTranslationUnit(ASTContext & Context)1263 void BTypeConsumer::HandleTranslationUnit(ASTContext &Context) {
1264 DeclContext::decl_iterator it;
1265 DeclContext *DC = TranslationUnitDecl::castToDeclContext(Context.getTranslationUnitDecl());
1266
1267 /**
1268 * In a first traversal, ProbeVisitor tracks external pointers identified
1269 * through each function's arguments and replaces their dereferences with
1270 * calls to bpf_probe_read. It also passes all identified pointers to
1271 * external addresses to MapVisitor.
1272 */
1273 for (it = DC->decls_begin(); it != DC->decls_end(); it++) {
1274 Decl *D = *it;
1275 if (FunctionDecl *F = dyn_cast<FunctionDecl>(D)) {
1276 if (fe_.is_rewritable_ext_func(F)) {
1277 for (auto arg : F->parameters()) {
1278 if (arg == F->getParamDecl(0)) {
1279 /**
1280 * Limit tracing of pointers from context to tracing contexts.
1281 * We're whitelisting instead of blacklisting to avoid issues with
1282 * existing programs if new context types are added in the future.
1283 */
1284 string type = arg->getType().getAsString();
1285 if (type == "struct pt_regs *" ||
1286 type == "struct bpf_raw_tracepoint_args *" ||
1287 type.substr(0, 19) == "struct tracepoint__")
1288 probe_visitor1_.set_ctx(arg);
1289 } else if (!arg->getType()->isFundamentalType()) {
1290 tuple<Decl *, int> pt = make_tuple(arg, 0);
1291 probe_visitor1_.set_ptreg(pt);
1292 }
1293 }
1294
1295 probe_visitor1_.TraverseDecl(D);
1296 for (auto ptreg : probe_visitor1_.get_ptregs()) {
1297 map_visitor_.set_ptreg(ptreg);
1298 }
1299 }
1300 }
1301 }
1302
1303 /**
1304 * MapVisitor uses external pointers identified by the first ProbeVisitor
1305 * traversal to identify all maps with external pointers as values.
1306 * MapVisitor runs only after ProbeVisitor finished its traversal of the
1307 * whole translation unit to clearly separate the role of each ProbeVisitor's
1308 * traversal: the first tracks external pointers from function arguments,
1309 * whereas the second tracks external pointers from maps. Without this clear
1310 * separation, ProbeVisitor might attempt to replace several times the same
1311 * dereferences.
1312 */
1313 for (it = DC->decls_begin(); it != DC->decls_end(); it++) {
1314 Decl *D = *it;
1315 if (FunctionDecl *F = dyn_cast<FunctionDecl>(D)) {
1316 if (fe_.is_rewritable_ext_func(F)) {
1317 map_visitor_.TraverseDecl(D);
1318 }
1319 }
1320 }
1321
1322 /**
1323 * In a second traversal, ProbeVisitor tracks pointers passed through the
1324 * maps identified by MapVisitor and replaces their dereferences with calls
1325 * to bpf_probe_read.
1326 * This last traversal runs after MapVisitor went through an entire
1327 * translation unit, to ensure maps with external pointers have all been
1328 * identified.
1329 */
1330 for (it = DC->decls_begin(); it != DC->decls_end(); it++) {
1331 Decl *D = *it;
1332 if (FunctionDecl *F = dyn_cast<FunctionDecl>(D)) {
1333 if (fe_.is_rewritable_ext_func(F)) {
1334 probe_visitor2_.TraverseDecl(D);
1335 }
1336 }
1337
1338 btype_visitor_.TraverseDecl(D);
1339 }
1340 }
1341
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)1342 BFrontendAction::BFrontendAction(llvm::raw_ostream &os, unsigned flags,
1343 TableStorage &ts, const std::string &id,
1344 const std::string &main_path,
1345 FuncSource &func_src, std::string &mod_src,
1346 const std::string &maps_ns)
1347 : os_(os),
1348 flags_(flags),
1349 ts_(ts),
1350 id_(id),
1351 maps_ns_(maps_ns),
1352 rewriter_(new Rewriter),
1353 main_path_(main_path),
1354 func_src_(func_src),
1355 mod_src_(mod_src) {}
1356
is_rewritable_ext_func(FunctionDecl * D)1357 bool BFrontendAction::is_rewritable_ext_func(FunctionDecl *D) {
1358 StringRef file_name = rewriter_->getSourceMgr().getFilename(GET_BEGINLOC(D));
1359 return (D->isExternallyVisible() && D->hasBody() &&
1360 (file_name.empty() || file_name == main_path_));
1361 }
1362
DoMiscWorkAround()1363 void BFrontendAction::DoMiscWorkAround() {
1364 // In 4.16 and later, CONFIG_CC_STACKPROTECTOR is moved out of Kconfig and into
1365 // Makefile. It will be set depending on CONFIG_CC_STACKPROTECTOR_{AUTO|REGULAR|STRONG}.
1366 // CONFIG_CC_STACKPROTECTOR is still used in various places, e.g., struct task_struct,
1367 // to guard certain fields. The workaround here intends to define
1368 // CONFIG_CC_STACKPROTECTOR properly based on other configs, so it relieved any bpf
1369 // program (using task_struct, etc.) of patching the below code.
1370 rewriter_->getEditBuffer(rewriter_->getSourceMgr().getMainFileID()).InsertText(0,
1371 "#if defined(BPF_LICENSE)\n"
1372 "#error BPF_LICENSE cannot be specified through cflags\n"
1373 "#endif\n"
1374 "#if !defined(CONFIG_CC_STACKPROTECTOR)\n"
1375 "#if defined(CONFIG_CC_STACKPROTECTOR_AUTO) \\\n"
1376 " || defined(CONFIG_CC_STACKPROTECTOR_REGULAR) \\\n"
1377 " || defined(CONFIG_CC_STACKPROTECTOR_STRONG)\n"
1378 "#define CONFIG_CC_STACKPROTECTOR\n"
1379 "#endif\n"
1380 "#endif\n",
1381 false);
1382
1383 rewriter_->getEditBuffer(rewriter_->getSourceMgr().getMainFileID()).InsertTextAfter(
1384 rewriter_->getSourceMgr().getBuffer(rewriter_->getSourceMgr().getMainFileID())->getBufferSize(),
1385 "\n#include <bcc/footer.h>\n");
1386 }
1387
EndSourceFileAction()1388 void BFrontendAction::EndSourceFileAction() {
1389 // Additional misc rewrites
1390 DoMiscWorkAround();
1391
1392 if (flags_ & DEBUG_PREPROCESSOR)
1393 rewriter_->getEditBuffer(rewriter_->getSourceMgr().getMainFileID()).write(llvm::errs());
1394 if (flags_ & DEBUG_SOURCE) {
1395 llvm::raw_string_ostream tmp_os(mod_src_);
1396 rewriter_->getEditBuffer(rewriter_->getSourceMgr().getMainFileID())
1397 .write(tmp_os);
1398 }
1399
1400 for (auto func : func_range_) {
1401 auto f = func.first;
1402 string bd = rewriter_->getRewrittenText(func_range_[f]);
1403 func_src_.set_src_rewritten(f, bd);
1404 }
1405 rewriter_->getEditBuffer(rewriter_->getSourceMgr().getMainFileID()).write(os_);
1406 os_.flush();
1407 }
1408
CreateASTConsumer(CompilerInstance & Compiler,llvm::StringRef InFile)1409 unique_ptr<ASTConsumer> BFrontendAction::CreateASTConsumer(CompilerInstance &Compiler, llvm::StringRef InFile) {
1410 rewriter_->setSourceMgr(Compiler.getSourceManager(), Compiler.getLangOpts());
1411 vector<unique_ptr<ASTConsumer>> consumers;
1412 consumers.push_back(unique_ptr<ASTConsumer>(new BTypeConsumer(Compiler.getASTContext(), *this, *rewriter_, m_)));
1413 return unique_ptr<ASTConsumer>(new MultiplexConsumer(std::move(consumers)));
1414 }
1415
1416 }
1417