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