blob: 26aaa8cfe067f6728f9e4183075d2a31447be70a [file] [log] [blame]
Brenden Blanco246b9422015-06-05 11:15:27 -07001/*
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 */
Brenden Blanco7009b552015-05-26 11:48:17 -070016#include <linux/bpf.h>
Brenden Blancof275d3d2015-07-06 23:41:23 -070017#include <linux/version.h>
Yonghong Songab21dcd2015-07-16 20:20:22 -070018#include <sys/utsname.h>
Brenden Blancoaeca6bf2015-11-06 13:03:05 -080019#include <unistd.h>
Joel Fernandes10869522018-02-01 21:23:24 -050020#include <stdlib.h>
Brenden Blanco7009b552015-05-26 11:48:17 -070021
22#include <clang/AST/ASTConsumer.h>
23#include <clang/AST/ASTContext.h>
24#include <clang/AST/RecordLayout.h>
25#include <clang/Frontend/CompilerInstance.h>
Brenden Blanco8ed57a22015-09-16 14:59:35 -070026#include <clang/Frontend/MultiplexConsumer.h>
Brenden Blanco7009b552015-05-26 11:48:17 -070027#include <clang/Rewrite/Core/Rewriter.h>
28
29#include "b_frontend_action.h"
Teng Qin73e2f2d2017-11-09 13:53:39 -080030#include "bpf_module.h"
Andreas Gerstmayr7e0784d2017-01-16 16:35:58 +010031#include "common.h"
Teng Qin73e2f2d2017-11-09 13:53:39 -080032#include "loader.h"
Brenden Blancofaea8c82017-03-29 09:58:31 -070033#include "table_storage.h"
Joel Fernandes10869522018-02-01 21:23:24 -050034#include "arch_helper.h"
Brenden Blanco7009b552015-05-26 11:48:17 -070035
Brenden Blanco32109bf2015-07-28 12:29:36 -070036#include "libbpf.h"
Brenden Blanco7009b552015-05-26 11:48:17 -070037
38namespace ebpf {
Brenden Blancob711d452015-07-01 15:23:18 -070039
Brenden Blanco977091e2016-05-05 11:37:59 -070040constexpr int MAX_CALLING_CONV_REGS = 6;
Brenden Blancob711d452015-07-01 15:23:18 -070041const char *calling_conv_regs_x86[] = {
42 "di", "si", "dx", "cx", "r8", "r9"
43};
Naveen N. Rao0006ad12016-04-29 16:42:58 +053044const char *calling_conv_regs_ppc[] = {"gpr[3]", "gpr[4]", "gpr[5]",
45 "gpr[6]", "gpr[7]", "gpr[8]"};
Zvonko Kosic98121a32017-03-07 07:30:25 +010046
47const char *calling_conv_regs_s390x[] = {"gprs[2]", "gprs[3]", "gprs[4]",
48 "gprs[5]", "gprs[6]" };
49
Zhiyi Sun8e434b72016-12-06 16:21:37 +080050const char *calling_conv_regs_arm64[] = {"regs[0]", "regs[1]", "regs[2]",
51 "regs[3]", "regs[4]", "regs[5]"};
Joel Fernandes10869522018-02-01 21:23:24 -050052
53void *get_call_conv_cb(bcc_arch_t arch)
54{
55 const char **ret;
56
57 switch(arch) {
58 case BCC_ARCH_PPC:
59 case BCC_ARCH_PPC_LE:
60 ret = calling_conv_regs_ppc;
61 break;
62 case BCC_ARCH_S390X:
63 ret = calling_conv_regs_s390x;
64 break;
65 case BCC_ARCH_ARM64:
66 ret = calling_conv_regs_arm64;
67 break;
68 default:
69 ret = calling_conv_regs_x86;
70 }
71
72 return (void *)ret;
73}
74
75const char **get_call_conv(void) {
76 const char **ret;
77
78 ret = (const char **)run_arch_callback(get_call_conv_cb);
79 return ret;
80}
Brenden Blancob711d452015-07-01 15:23:18 -070081
Brenden Blanco7009b552015-05-26 11:48:17 -070082using std::map;
Brenden Blancofaea8c82017-03-29 09:58:31 -070083using std::move;
Brenden Blanco8ed57a22015-09-16 14:59:35 -070084using std::set;
Paul Chaignon471f1ea2018-05-11 09:36:37 +020085using std::tuple;
86using std::make_tuple;
Brenden Blanco7009b552015-05-26 11:48:17 -070087using std::string;
Brenden Blanco28333862015-05-28 18:19:38 -070088using std::to_string;
Brenden Blanco7009b552015-05-26 11:48:17 -070089using std::unique_ptr;
Brenden Blanco561dafc2015-06-29 11:09:00 -070090using std::vector;
Brenden Blanco7009b552015-05-26 11:48:17 -070091using namespace clang;
92
Brenden Blanco74adb732015-09-29 13:44:19 -070093class ProbeChecker : public RecursiveASTVisitor<ProbeChecker> {
Brenden Blanco70fa0a12015-09-15 15:46:26 -070094 public:
Paul Chaignon471f1ea2018-05-11 09:36:37 +020095 explicit ProbeChecker(Expr *arg, const set<tuple<Decl *, int>> &ptregs,
96 bool track_helpers, bool is_assign)
Paul Chaignonad2d0d92018-05-08 22:02:55 +020097 : needs_probe_(false), is_transitive_(false), ptregs_(ptregs),
Paul Chaignon471f1ea2018-05-11 09:36:37 +020098 track_helpers_(track_helpers), nb_derefs_(0), is_assign_(is_assign) {
Brenden Blancoc48ab4b2015-10-01 11:18:07 -070099 if (arg) {
Brenden Blanco8ed57a22015-09-16 14:59:35 -0700100 TraverseStmt(arg);
Brenden Blancoc48ab4b2015-10-01 11:18:07 -0700101 if (arg->getType()->isPointerType())
102 is_transitive_ = needs_probe_;
103 }
Brenden Blanco8ed57a22015-09-16 14:59:35 -0700104 }
Paul Chaignon471f1ea2018-05-11 09:36:37 +0200105 explicit ProbeChecker(Expr *arg, const set<tuple<Decl *, int>> &ptregs,
106 bool is_transitive)
107 : ProbeChecker(arg, ptregs, is_transitive, false) {}
Brenden Blanco74adb732015-09-29 13:44:19 -0700108 bool VisitCallExpr(CallExpr *E) {
Brenden Blancoc48ab4b2015-10-01 11:18:07 -0700109 needs_probe_ = false;
Paul Chaignonfe779f32018-06-14 03:51:55 +0200110
111 if (is_assign_) {
112 // We're looking for a function that returns an external pointer,
113 // regardless of the number of dereferences.
114 for(auto p : ptregs_) {
115 if (std::get<0>(p) == E->getDirectCallee()) {
116 needs_probe_ = true;
117 nb_derefs_ += std::get<1>(p);
118 return false;
119 }
120 }
121 } else {
122 tuple<Decl *, int> pt = make_tuple(E->getDirectCallee(), nb_derefs_);
123 if (ptregs_.find(pt) != ptregs_.end())
124 needs_probe_ = true;
125 }
126
Paul Chaignonad2d0d92018-05-08 22:02:55 +0200127 if (!track_helpers_)
128 return false;
129 if (VarDecl *V = dyn_cast<VarDecl>(E->getCalleeDecl()))
Paul Chaignon719e1002017-08-06 14:33:20 +0200130 needs_probe_ = V->getName() == "bpf_get_current_task";
Brenden Blanco74adb732015-09-29 13:44:19 -0700131 return false;
132 }
Paul Chaignonc2b87ba2018-05-05 10:39:39 +0200133 bool VisitMemberExpr(MemberExpr *M) {
Paul Chaignon471f1ea2018-05-11 09:36:37 +0200134 tuple<Decl *, int> pt = make_tuple(M->getMemberDecl(), nb_derefs_);
135 if (ptregs_.find(pt) != ptregs_.end()) {
Paul Chaignonc2b87ba2018-05-05 10:39:39 +0200136 needs_probe_ = true;
137 return false;
138 }
139 return true;
140 }
Paul Chaignon471f1ea2018-05-11 09:36:37 +0200141 bool VisitUnaryOperator(UnaryOperator *E) {
142 if (E->getOpcode() == UO_Deref)
143 nb_derefs_++;
144 else if (E->getOpcode() == UO_AddrOf)
145 nb_derefs_--;
146 return true;
147 }
Brenden Blanco74adb732015-09-29 13:44:19 -0700148 bool VisitDeclRefExpr(DeclRefExpr *E) {
Paul Chaignon471f1ea2018-05-11 09:36:37 +0200149 if (is_assign_) {
150 // We're looking for an external pointer, regardless of the number of
151 // dereferences.
152 for(auto p : ptregs_) {
153 if (std::get<0>(p) == E->getDecl()) {
154 needs_probe_ = true;
155 nb_derefs_ += std::get<1>(p);
156 return false;
157 }
158 }
159 } else {
160 tuple<Decl *, int> pt = make_tuple(E->getDecl(), nb_derefs_);
161 if (ptregs_.find(pt) != ptregs_.end())
162 needs_probe_ = true;
163 }
Brenden Blanco70fa0a12015-09-15 15:46:26 -0700164 return true;
165 }
Brenden Blanco8ed57a22015-09-16 14:59:35 -0700166 bool needs_probe() const { return needs_probe_; }
Brenden Blancoc48ab4b2015-10-01 11:18:07 -0700167 bool is_transitive() const { return is_transitive_; }
Paul Chaignon471f1ea2018-05-11 09:36:37 +0200168 int get_nb_derefs() const { return nb_derefs_; }
Brenden Blanco8ed57a22015-09-16 14:59:35 -0700169 private:
170 bool needs_probe_;
Brenden Blancoc48ab4b2015-10-01 11:18:07 -0700171 bool is_transitive_;
Paul Chaignon471f1ea2018-05-11 09:36:37 +0200172 const set<tuple<Decl *, int>> &ptregs_;
Paul Chaignonad2d0d92018-05-08 22:02:55 +0200173 bool track_helpers_;
Paul Chaignon471f1ea2018-05-11 09:36:37 +0200174 // Nb of dereferences we go through before finding the external pointer.
175 // A negative number counts the number of addrof.
176 int nb_derefs_;
177 bool is_assign_;
Brenden Blanco70fa0a12015-09-15 15:46:26 -0700178};
179
180// Visit a piece of the AST and mark it as needing probe reads
Brenden Blanco74adb732015-09-29 13:44:19 -0700181class ProbeSetter : public RecursiveASTVisitor<ProbeSetter> {
Brenden Blanco70fa0a12015-09-15 15:46:26 -0700182 public:
Paul Chaignon471f1ea2018-05-11 09:36:37 +0200183 explicit ProbeSetter(set<tuple<Decl *, int>> *ptregs, int nb_addrof)
184 : ptregs_(ptregs), nb_derefs_(-nb_addrof) {}
Brenden Blanco74adb732015-09-29 13:44:19 -0700185 bool VisitDeclRefExpr(DeclRefExpr *E) {
Paul Chaignon471f1ea2018-05-11 09:36:37 +0200186 tuple<Decl *, int> pt = make_tuple(E->getDecl(), nb_derefs_);
187 ptregs_->insert(pt);
188 return true;
189 }
190 explicit ProbeSetter(set<tuple<Decl *, int>> *ptregs)
191 : ProbeSetter(ptregs, 0) {}
192 bool VisitUnaryOperator(UnaryOperator *E) {
193 if (E->getOpcode() == UO_Deref)
194 nb_derefs_++;
Brenden Blanco70fa0a12015-09-15 15:46:26 -0700195 return true;
196 }
Paul Chaignonc2b87ba2018-05-05 10:39:39 +0200197 bool VisitMemberExpr(MemberExpr *M) {
Paul Chaignon471f1ea2018-05-11 09:36:37 +0200198 tuple<Decl *, int> pt = make_tuple(M->getMemberDecl(), nb_derefs_);
199 ptregs_->insert(pt);
Paul Chaignonc2b87ba2018-05-05 10:39:39 +0200200 return false;
201 }
Brenden Blanco70fa0a12015-09-15 15:46:26 -0700202 private:
Paul Chaignon471f1ea2018-05-11 09:36:37 +0200203 set<tuple<Decl *, int>> *ptregs_;
204 // Nb of dereferences we go through before getting to the actual variable.
205 int nb_derefs_;
Brenden Blanco70fa0a12015-09-15 15:46:26 -0700206};
207
Paul Chaignone67cb562017-10-26 08:43:13 +0200208MapVisitor::MapVisitor(set<Decl *> &m) : m_(m) {}
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200209
Paul Chaignone67cb562017-10-26 08:43:13 +0200210bool MapVisitor::VisitCallExpr(CallExpr *Call) {
211 if (MemberExpr *Memb = dyn_cast<MemberExpr>(Call->getCallee()->IgnoreImplicit())) {
212 StringRef memb_name = Memb->getMemberDecl()->getName();
213 if (DeclRefExpr *Ref = dyn_cast<DeclRefExpr>(Memb->getBase())) {
214 if (SectionAttr *A = Ref->getDecl()->getAttr<SectionAttr>()) {
215 if (!A->getName().startswith("maps"))
216 return true;
217
218 if (memb_name == "update" || memb_name == "insert") {
Paul Chaignon471f1ea2018-05-11 09:36:37 +0200219 ProbeChecker checker = ProbeChecker(Call->getArg(1), ptregs_, true,
220 true);
221 if (checker.needs_probe())
Paul Chaignone67cb562017-10-26 08:43:13 +0200222 m_.insert(Ref->getDecl());
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200223 }
224 }
225 }
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200226 }
Paul Chaignone67cb562017-10-26 08:43:13 +0200227 return true;
228}
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200229
Paul Chaignon471f1ea2018-05-11 09:36:37 +0200230ProbeVisitor::ProbeVisitor(ASTContext &C, Rewriter &rewriter,
231 set<Decl *> &m, bool track_helpers) :
yonghong-song24581962018-06-17 15:55:12 -0700232 C(C), rewriter_(rewriter), m_(m), track_helpers_(track_helpers),
233 addrof_stmt_(nullptr), is_addrof_(false) {}
Brenden Blanco8ed57a22015-09-16 14:59:35 -0700234
Paul Chaignon8d7e26d2018-05-31 12:47:44 +0200235bool ProbeVisitor::assignsExtPtr(Expr *E, int *nbAddrOf) {
236 if (IsContextMemberExpr(E)) {
237 *nbAddrOf = 0;
238 return true;
239 }
240
Paul Chaignonfe779f32018-06-14 03:51:55 +0200241 /* If the expression contains a call to another function, we need to visit
242 * that function first to know if a rewrite is necessary (i.e., if the
243 * function returns an external pointer). */
244 if (!TraverseStmt(E))
245 return false;
246
Paul Chaignon8d7e26d2018-05-31 12:47:44 +0200247 ProbeChecker checker = ProbeChecker(E, ptregs_, track_helpers_,
248 true);
249 if (checker.is_transitive()) {
250 // The negative of the number of dereferences is the number of addrof. In
251 // an assignment, if we went through n addrof before getting the external
252 // pointer, then we'll need n dereferences on the left-hand side variable
253 // to get to the external pointer.
254 *nbAddrOf = -checker.get_nb_derefs();
255 return true;
256 }
257
Paul Chaignonfe779f32018-06-14 03:51:55 +0200258 if (E->IgnoreParenCasts()->getStmtClass() == Stmt::CallExprClass) {
259 CallExpr *Call = dyn_cast<CallExpr>(E->IgnoreParenCasts());
Paul Chaignon8d7e26d2018-05-31 12:47:44 +0200260 if (MemberExpr *Memb = dyn_cast<MemberExpr>(Call->getCallee()->IgnoreImplicit())) {
261 StringRef memb_name = Memb->getMemberDecl()->getName();
262 if (DeclRefExpr *Ref = dyn_cast<DeclRefExpr>(Memb->getBase())) {
263 if (SectionAttr *A = Ref->getDecl()->getAttr<SectionAttr>()) {
264 if (!A->getName().startswith("maps"))
265 return false;
266
267 if (memb_name == "lookup" || memb_name == "lookup_or_init") {
268 if (m_.find(Ref->getDecl()) != m_.end()) {
Yonghong Song20fb64c2018-06-02 00:28:38 -0700269 // Retrieved an ext. pointer from a map, mark LHS as ext. pointer.
Paul Chaignon8d7e26d2018-05-31 12:47:44 +0200270 // Pointers from maps always need a single dereference to get the
271 // actual value. The value may be an external pointer but cannot
272 // be a pointer to an external pointer as the verifier prohibits
273 // storing known pointers (to map values, context, the stack, or
274 // the packet) in maps.
275 *nbAddrOf = 1;
276 return true;
277 }
278 }
279 }
280 }
281 }
282 }
283 return false;
284}
Paul Chaignon471f1ea2018-05-11 09:36:37 +0200285bool ProbeVisitor::VisitVarDecl(VarDecl *D) {
286 if (Expr *E = D->getInit()) {
Paul Chaignon8d7e26d2018-05-31 12:47:44 +0200287 int nbAddrOf;
288 if (assignsExtPtr(E, &nbAddrOf)) {
289 // The negative of the number of addrof is the number of dereferences.
290 tuple<Decl *, int> pt = make_tuple(D, -nbAddrOf);
Paul Chaignon471f1ea2018-05-11 09:36:37 +0200291 set_ptreg(pt);
Paul Chaignonb66a9c92018-05-01 22:10:28 +0200292 }
Brenden Blanco8ed57a22015-09-16 14:59:35 -0700293 }
294 return true;
295}
Yonghong Song20fb64c2018-06-02 00:28:38 -0700296
Paul Chaignoneebd4852018-06-13 03:55:52 +0200297bool ProbeVisitor::TraverseStmt(Stmt *S) {
298 if (whitelist_.find(S) != whitelist_.end())
299 return true;
yonghong-song24581962018-06-17 15:55:12 -0700300 auto ret = RecursiveASTVisitor<ProbeVisitor>::TraverseStmt(S);
301 if (addrof_stmt_ == S) {
302 addrof_stmt_ = nullptr;
303 is_addrof_ = false;
304 }
305 return ret;
Paul Chaignoneebd4852018-06-13 03:55:52 +0200306}
307
Brenden Blanco8ed57a22015-09-16 14:59:35 -0700308bool ProbeVisitor::VisitCallExpr(CallExpr *Call) {
Yonghong Song20fb64c2018-06-02 00:28:38 -0700309 // Skip bpf_probe_read for the third argument if it is an AddrOf.
310 if (VarDecl *V = dyn_cast<VarDecl>(Call->getCalleeDecl())) {
311 if (V->getName() == "bpf_probe_read" && Call->getNumArgs() >= 3) {
312 const Expr *E = Call->getArg(2)->IgnoreParenCasts();
Paul Chaignonf86f7e82018-06-14 02:20:03 +0200313 whitelist_.insert(E);
Yonghong Song20fb64c2018-06-02 00:28:38 -0700314 return true;
315 }
316 }
317
Brenden Blanco8ed57a22015-09-16 14:59:35 -0700318 if (FunctionDecl *F = dyn_cast<FunctionDecl>(Call->getCalleeDecl())) {
319 if (F->hasBody()) {
320 unsigned i = 0;
321 for (auto arg : Call->arguments()) {
Paul Chaignon471f1ea2018-05-11 09:36:37 +0200322 ProbeChecker checker = ProbeChecker(arg, ptregs_, track_helpers_,
323 true);
324 if (checker.needs_probe()) {
325 tuple<Decl *, int> pt = make_tuple(F->getParamDecl(i),
326 checker.get_nb_derefs());
327 ptregs_.insert(pt);
328 }
Brenden Blanco8ed57a22015-09-16 14:59:35 -0700329 ++i;
330 }
331 if (fn_visited_.find(F) == fn_visited_.end()) {
332 fn_visited_.insert(F);
Paul Chaignonfe779f32018-06-14 03:51:55 +0200333 /* Maintains a stack of the number of dereferences for the external
334 * pointers returned by each function in the call stack or -1 if the
335 * function didn't return an external pointer. */
336 ptregs_returned_.push_back(-1);
Brenden Blanco8ed57a22015-09-16 14:59:35 -0700337 TraverseDecl(F);
Paul Chaignonfe779f32018-06-14 03:51:55 +0200338 int nb_derefs = ptregs_returned_.back();
339 ptregs_returned_.pop_back();
340 if (nb_derefs != -1) {
341 tuple<Decl *, int> pt = make_tuple(F, nb_derefs);
342 ptregs_.insert(pt);
343 }
Brenden Blanco8ed57a22015-09-16 14:59:35 -0700344 }
345 }
346 }
347 return true;
348}
Paul Chaignonfe779f32018-06-14 03:51:55 +0200349bool ProbeVisitor::VisitReturnStmt(ReturnStmt *R) {
350 /* If this function wasn't called by another, there's no need to check the
351 * return statement for external pointers. */
352 if (ptregs_returned_.size() == 0)
353 return true;
354
355 /* Reverse order of traversals. This is needed if, in the return statement,
356 * we're calling a function that's returning an external pointer: we need to
357 * know what the function is returning to decide what this function is
358 * returning. */
359 if (!TraverseStmt(R->getRetValue()))
360 return false;
361
362 ProbeChecker checker = ProbeChecker(R->getRetValue(), ptregs_,
363 track_helpers_, true);
364 if (checker.needs_probe()) {
365 int curr_nb_derefs = ptregs_returned_.back();
366 /* If the function returns external pointers with different levels of
367 * indirection, we handle the case with the highest level of indirection
368 * and leave it to the user to manually handle other cases. */
369 if (checker.get_nb_derefs() > curr_nb_derefs) {
370 ptregs_returned_.pop_back();
371 ptregs_returned_.push_back(checker.get_nb_derefs());
372 }
373 }
374 return true;
375}
Brenden Blanco8ed57a22015-09-16 14:59:35 -0700376bool ProbeVisitor::VisitBinaryOperator(BinaryOperator *E) {
377 if (!E->isAssignmentOp())
378 return true;
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200379
Paul Chaignon8d7e26d2018-05-31 12:47:44 +0200380 // copy probe attribute from RHS to LHS if present
381 int nbAddrOf;
382 if (assignsExtPtr(E->getRHS(), &nbAddrOf)) {
383 ProbeSetter setter(&ptregs_, nbAddrOf);
Paul Chaignonb66a9c92018-05-01 22:10:28 +0200384 setter.TraverseStmt(E->getLHS());
Brenden Blanco8ed57a22015-09-16 14:59:35 -0700385 }
386 return true;
387}
Brenden Blancoea5023a2015-09-24 06:52:08 -0700388bool ProbeVisitor::VisitUnaryOperator(UnaryOperator *E) {
yonghong-song24581962018-06-17 15:55:12 -0700389 if (E->getOpcode() == UO_AddrOf) {
390 addrof_stmt_ = E;
391 is_addrof_ = true;
392 }
Paul Chaignon4c6ecb42017-02-23 10:03:58 +0100393 if (E->getOpcode() != UO_Deref)
Brenden Blancoea5023a2015-09-24 06:52:08 -0700394 return true;
395 if (memb_visited_.find(E) != memb_visited_.end())
396 return true;
Paul Chaignon471f1ea2018-05-11 09:36:37 +0200397 Expr *sub = E->getSubExpr();
398 if (!ProbeChecker(sub, ptregs_, track_helpers_).needs_probe())
Brenden Blancoea5023a2015-09-24 06:52:08 -0700399 return true;
400 memb_visited_.insert(E);
Paul Chaignonfa7508d2018-06-17 17:47:18 +0200401 string pre, post;
402 pre = "({ typeof(" + E->getType().getAsString() + ") _val; __builtin_memset(&_val, 0, sizeof(_val));";
403 pre += " bpf_probe_read(&_val, sizeof(_val), (u64)";
404 post = "); _val; })";
405 rewriter_.ReplaceText(expansionLoc(E->getOperatorLoc()), 1, pre);
406 rewriter_.InsertTextAfterToken(expansionLoc(sub->getLocEnd()), post);
Brenden Blancoea5023a2015-09-24 06:52:08 -0700407 return true;
408}
yonghong-song24581962018-06-17 15:55:12 -0700409bool ProbeVisitor::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
410 // &({..._val; bpf_probe_read(&_val, ...); _val;})[0] is permitted
411 // by C standard.
412 if (is_addrof_)
413 is_addrof_ = false;
414 return true;
415}
Brenden Blanco8ed57a22015-09-16 14:59:35 -0700416bool ProbeVisitor::VisitMemberExpr(MemberExpr *E) {
417 if (memb_visited_.find(E) != memb_visited_.end()) return true;
418
Brenden Blanco8ed57a22015-09-16 14:59:35 -0700419 Expr *base;
Yonghong Song94d15bc2017-11-08 20:38:30 -0800420 SourceLocation rhs_start, member;
Brenden Blanco8ed57a22015-09-16 14:59:35 -0700421 bool found = false;
422 for (MemberExpr *M = E; M; M = dyn_cast<MemberExpr>(M->getBase())) {
423 memb_visited_.insert(M);
424 rhs_start = M->getLocEnd();
425 base = M->getBase();
Yonghong Song94d15bc2017-11-08 20:38:30 -0800426 member = M->getMemberLoc();
Brenden Blanco8ed57a22015-09-16 14:59:35 -0700427 if (M->isArrow()) {
428 found = true;
429 break;
430 }
431 }
432 if (!found)
433 return true;
Yonghong Song94d15bc2017-11-08 20:38:30 -0800434 if (member.isInvalid()) {
435 error(base->getLocEnd(), "internal error: MemberLoc is invalid while preparing probe rewrite");
Brenden Blanco545008a2016-08-18 14:33:29 -0700436 return false;
437 }
Paul Chaignonc2b87ba2018-05-05 10:39:39 +0200438
yonghong-song66d28632018-06-14 07:11:42 -0700439 if (!rewriter_.isRewritable(E->getLocStart()))
Paul Chaignona9f96c02018-06-15 00:27:08 +0200440 return true;
yonghong-song66d28632018-06-14 07:11:42 -0700441
yonghong-song24581962018-06-17 15:55:12 -0700442 // parent expr has addrof, skip the rewrite, set is_addrof_ to flase so
443 // it won't affect next level of indirect address
444 if (is_addrof_) {
445 is_addrof_ = false;
446 return true;
447 }
448
Paul Chaignonfe779f32018-06-14 03:51:55 +0200449 /* If the base of the dereference is a call to another function, we need to
450 * visit that function first to know if a rewrite is necessary (i.e., if the
451 * function returns an external pointer). */
452 if (base->IgnoreParenCasts()->getStmtClass() == Stmt::CallExprClass) {
453 CallExpr *Call = dyn_cast<CallExpr>(base->IgnoreParenCasts());
454 if (!TraverseStmt(Call))
455 return false;
456 }
457
Paul Chaignonc2b87ba2018-05-05 10:39:39 +0200458 // Checks to see if the expression references something that needs to be run
459 // through bpf_probe_read.
Paul Chaignonad2d0d92018-05-08 22:02:55 +0200460 if (!ProbeChecker(base, ptregs_, track_helpers_).needs_probe())
Paul Chaignonc2b87ba2018-05-05 10:39:39 +0200461 return true;
462
Paul Chaignonc5c3b992017-02-26 12:22:03 +0100463 string rhs = rewriter_.getRewrittenText(expansionRange(SourceRange(rhs_start, E->getLocEnd())));
Brenden Blanco8ed57a22015-09-16 14:59:35 -0700464 string base_type = base->getType()->getPointeeType().getAsString();
465 string pre, post;
Yonghong Song1ab5f662018-01-24 16:42:53 -0800466 pre = "({ typeof(" + E->getType().getAsString() + ") _val; __builtin_memset(&_val, 0, sizeof(_val));";
Yonghong Song94d15bc2017-11-08 20:38:30 -0800467 pre += " bpf_probe_read(&_val, sizeof(_val), (u64)&";
468 post = rhs + "); _val; })";
Paul Chaignonfa7508d2018-06-17 17:47:18 +0200469 rewriter_.InsertText(expansionLoc(E->getLocStart()), pre);
Yonghong Song94d15bc2017-11-08 20:38:30 -0800470 rewriter_.ReplaceText(expansionRange(SourceRange(member, E->getLocEnd())), post);
Brenden Blanco8ed57a22015-09-16 14:59:35 -0700471 return true;
472}
473
Paul Chaignonb66a9c92018-05-01 22:10:28 +0200474bool ProbeVisitor::IsContextMemberExpr(Expr *E) {
475 if (!E->getType()->isPointerType())
476 return false;
477
Paul Chaignonb66a9c92018-05-01 22:10:28 +0200478 Expr *base;
Paul Chaignona9f96c02018-06-15 00:27:08 +0200479 SourceLocation member;
Paul Chaignonb66a9c92018-05-01 22:10:28 +0200480 bool found = false;
481 MemberExpr *M;
Paul Chaignona9f96c02018-06-15 00:27:08 +0200482 Expr *Ex = E->IgnoreParenCasts();
483 while (Ex->getStmtClass() == Stmt::ArraySubscriptExprClass
484 || Ex->getStmtClass() == Stmt::MemberExprClass) {
485 if (Ex->getStmtClass() == Stmt::ArraySubscriptExprClass) {
486 Ex = dyn_cast<ArraySubscriptExpr>(Ex)->getBase()->IgnoreParenCasts();
487 } else if (Ex->getStmtClass() == Stmt::MemberExprClass) {
488 M = dyn_cast<MemberExpr>(Ex);
489 base = M->getBase()->IgnoreParenCasts();
490 member = M->getMemberLoc();
491 if (M->isArrow()) {
492 found = true;
493 break;
494 }
495 Ex = base;
Paul Chaignonb66a9c92018-05-01 22:10:28 +0200496 }
497 }
498 if (!found) {
499 return false;
500 }
501 if (member.isInvalid()) {
502 return false;
503 }
504
Paul Chaignona9f96c02018-06-15 00:27:08 +0200505 if (DeclRefExpr *base_expr = dyn_cast<DeclRefExpr>(base)) {
Paul Chaignonb66a9c92018-05-01 22:10:28 +0200506 if (base_expr->getDecl() == ctx_) {
507 return true;
508 }
509 }
510 return false;
511}
512
Paul Chaignonc5c3b992017-02-26 12:22:03 +0100513SourceRange
514ProbeVisitor::expansionRange(SourceRange range) {
Yonghong Song806627e2018-05-02 10:32:31 -0700515#if LLVM_MAJOR_VERSION >= 7
516 return rewriter_.getSourceMgr().getExpansionRange(range).getAsRange();
517#else
Paul Chaignonc5c3b992017-02-26 12:22:03 +0100518 return rewriter_.getSourceMgr().getExpansionRange(range);
Yonghong Song806627e2018-05-02 10:32:31 -0700519#endif
Paul Chaignonc5c3b992017-02-26 12:22:03 +0100520}
521
Paul Chaignonfa7508d2018-06-17 17:47:18 +0200522SourceLocation
523ProbeVisitor::expansionLoc(SourceLocation loc) {
524 return rewriter_.getSourceMgr().getExpansionLoc(loc);
525}
526
Brenden Blanco545008a2016-08-18 14:33:29 -0700527template <unsigned N>
528DiagnosticBuilder ProbeVisitor::error(SourceLocation loc, const char (&fmt)[N]) {
529 unsigned int diag_id = C.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error, fmt);
530 return C.getDiagnostics().Report(loc, diag_id);
531}
532
Brenden Blancofaea8c82017-03-29 09:58:31 -0700533BTypeVisitor::BTypeVisitor(ASTContext &C, BFrontendAction &fe)
534 : C(C), diag_(C.getDiagnostics()), fe_(fe), rewriter_(fe.rewriter()), out_(llvm::errs()) {}
Brenden Blanco7009b552015-05-26 11:48:17 -0700535
yonghong-song2da34262018-06-13 06:12:22 -0700536void BTypeVisitor::genParamDirectAssign(FunctionDecl *D, string& preamble,
537 const char **calling_conv_regs) {
538 for (size_t idx = 0; idx < fn_args_.size(); idx++) {
539 ParmVarDecl *arg = fn_args_[idx];
540
541 if (idx >= 1) {
542 // Move the args into a preamble section where the same params are
543 // declared and initialized from pt_regs.
544 // Todo: this init should be done only when the program requests it.
545 string text = rewriter_.getRewrittenText(expansionRange(arg->getSourceRange()));
546 arg->addAttr(UnavailableAttr::CreateImplicit(C, "ptregs"));
547 size_t d = idx - 1;
548 const char *reg = calling_conv_regs[d];
549 preamble += " " + text + " = " + fn_args_[0]->getName().str() + "->" +
550 string(reg) + ";";
551 }
552 }
553}
554
555void BTypeVisitor::genParamIndirectAssign(FunctionDecl *D, string& preamble,
556 const char **calling_conv_regs) {
557 string new_ctx;
558
559 for (size_t idx = 0; idx < fn_args_.size(); idx++) {
560 ParmVarDecl *arg = fn_args_[idx];
561
562 if (idx == 0) {
563 new_ctx = "__" + arg->getName().str();
564 preamble += " struct pt_regs * " + new_ctx + " = " +
565 arg->getName().str() + "->" +
566 string(calling_conv_regs[0]) + ";";
567 } else {
568 // Move the args into a preamble section where the same params are
569 // declared and initialized from pt_regs.
570 // Todo: this init should be done only when the program requests it.
571 string text = rewriter_.getRewrittenText(expansionRange(arg->getSourceRange()));
572 size_t d = idx - 1;
573 const char *reg = calling_conv_regs[d];
574 preamble += "\n " + text + ";";
575 preamble += " bpf_probe_read(&" + arg->getName().str() + ", sizeof(" +
576 arg->getName().str() + "), &" + new_ctx + "->" +
577 string(reg) + ");";
578 }
579 }
580}
581
582void BTypeVisitor::rewriteFuncParam(FunctionDecl *D) {
Joel Fernandes10869522018-02-01 21:23:24 -0500583 const char **calling_conv_regs = get_call_conv();
584
yonghong-song2da34262018-06-13 06:12:22 -0700585 string preamble = "{\n";
586 if (D->param_size() > 1) {
587 // If function prefix is "syscall__" or "kprobe____x64_sys_",
588 // the function will attach to a kprobe syscall function.
589 // Guard parameter assiggnment with CONFIG_ARCH_HAS_SYSCALL_WRAPPER.
590 // For __x64_sys_* syscalls, this is always true, but we guard
591 // it in case of "syscall__" for other architectures.
592 if (strncmp(D->getName().str().c_str(), "syscall__", 9) == 0 ||
593 strncmp(D->getName().str().c_str(), "kprobe____x64_sys_", 18) == 0) {
594 preamble += "#ifdef CONFIG_ARCH_HAS_SYSCALL_WRAPPER\n";
595 genParamIndirectAssign(D, preamble, calling_conv_regs);
596 preamble += "\n#else\n";
597 genParamDirectAssign(D, preamble, calling_conv_regs);
598 preamble += "\n#endif\n";
599 } else {
600 genParamDirectAssign(D, preamble, calling_conv_regs);
601 }
602 rewriter_.ReplaceText(
603 expansionRange(SourceRange(D->getParamDecl(0)->getLocEnd(),
604 D->getParamDecl(D->getNumParams() - 1)->getLocEnd())),
605 fn_args_[0]->getName());
606 }
607 // for each trace argument, convert the variable from ptregs to something on stack
608 if (CompoundStmt *S = dyn_cast<CompoundStmt>(D->getBody()))
609 rewriter_.ReplaceText(S->getLBracLoc(), 1, preamble);
610}
611
612bool BTypeVisitor::VisitFunctionDecl(FunctionDecl *D) {
Brenden Blanco004f0052015-06-11 14:31:31 -0700613 // put each non-static non-inline function decl in its own section, to be
614 // extracted by the MemoryManager
Sasha Goldshteinfab68e32016-07-05 09:34:56 -0700615 auto real_start_loc = rewriter_.getSourceMgr().getFileLoc(D->getLocStart());
Yonghong Song6fc8d152017-11-03 15:04:24 -0700616 if (fe_.is_rewritable_ext_func(D)) {
Vicent Marti4ea4af42016-05-04 13:01:55 +0200617 current_fn_ = D->getName();
Alexei Starovoitov4f47e3b2017-09-06 19:57:21 -0700618 string bd = rewriter_.getRewrittenText(expansionRange(D->getSourceRange()));
619 fe_.func_src_.set_src(current_fn_, bd);
620 fe_.func_range_[current_fn_] = expansionRange(D->getSourceRange());
Brenden Blanco32109bf2015-07-28 12:29:36 -0700621 string attr = string("__attribute__((section(\"") + BPF_FN_PREFIX + D->getName().str() + "\")))\n";
Sasha Goldshteinfab68e32016-07-05 09:34:56 -0700622 rewriter_.InsertText(real_start_loc, attr);
Brenden Blanco977091e2016-05-05 11:37:59 -0700623 if (D->param_size() > MAX_CALLING_CONV_REGS + 1) {
624 error(D->getParamDecl(MAX_CALLING_CONV_REGS + 1)->getLocStart(),
625 "too many arguments, bcc only supports in-register parameters");
626 return false;
627 }
yonghong-song2da34262018-06-13 06:12:22 -0700628
Brenden Blanco561dafc2015-06-29 11:09:00 -0700629 fn_args_.clear();
Brenden Blanco52561542016-07-07 17:56:03 -0700630 for (auto arg_it = D->param_begin(); arg_it != D->param_end(); arg_it++) {
yonghong-song2da34262018-06-13 06:12:22 -0700631 auto *arg = *arg_it;
Brenden Blanco561dafc2015-06-29 11:09:00 -0700632 if (arg->getName() == "") {
Brenden Blancoc98ffd62016-04-09 18:41:42 -0700633 error(arg->getLocEnd(), "arguments to BPF program definition must be named");
Brenden Blanco561dafc2015-06-29 11:09:00 -0700634 return false;
635 }
Brenden Blancob711d452015-07-01 15:23:18 -0700636 fn_args_.push_back(arg);
Brenden Blanco561dafc2015-06-29 11:09:00 -0700637 }
yonghong-song2da34262018-06-13 06:12:22 -0700638 rewriteFuncParam(D);
Brenden Blanco8ed57a22015-09-16 14:59:35 -0700639 } else if (D->hasBody() &&
Sasha Goldshteinfab68e32016-07-05 09:34:56 -0700640 rewriter_.getSourceMgr().getFileID(real_start_loc)
Brenden Blanco8ed57a22015-09-16 14:59:35 -0700641 == rewriter_.getSourceMgr().getMainFileID()) {
642 // rewritable functions that are static should be always treated as helper
Sasha Goldshteinfab68e32016-07-05 09:34:56 -0700643 rewriter_.InsertText(real_start_loc, "__attribute__((always_inline))\n");
Brenden Blanco004f0052015-06-11 14:31:31 -0700644 }
Brenden Blanco7009b552015-05-26 11:48:17 -0700645 return true;
646}
647
Brenden Blanco561dafc2015-06-29 11:09:00 -0700648// Reverse the order of call traversal so that parameters inside of
649// function calls will get rewritten before the call itself, otherwise
650// text mangling will result.
651bool BTypeVisitor::TraverseCallExpr(CallExpr *Call) {
652 for (auto child : Call->children())
653 if (!TraverseStmt(child))
654 return false;
655 if (!WalkUpFromCallExpr(Call))
656 return false;
657 return true;
658}
659
Brenden Blanco7009b552015-05-26 11:48:17 -0700660// convert calls of the type:
661// table.foo(&key)
662// to:
663// bpf_table_foo_elem(bpf_pseudo_fd(table), &key [,&leaf])
664bool BTypeVisitor::VisitCallExpr(CallExpr *Call) {
665 // make sure node is a reference to a bpf table, which is assured by the
666 // presence of the section("maps/<typename>") GNU __attribute__
667 if (MemberExpr *Memb = dyn_cast<MemberExpr>(Call->getCallee()->IgnoreImplicit())) {
668 StringRef memb_name = Memb->getMemberDecl()->getName();
669 if (DeclRefExpr *Ref = dyn_cast<DeclRefExpr>(Memb->getBase())) {
670 if (SectionAttr *A = Ref->getDecl()->getAttr<SectionAttr>()) {
671 if (!A->getName().startswith("maps"))
672 return true;
Brenden Blanco28333862015-05-28 18:19:38 -0700673
Paul Chaignonc5c3b992017-02-26 12:22:03 +0100674 string args = rewriter_.getRewrittenText(expansionRange(SourceRange(Call->getArg(0)->getLocStart(),
675 Call->getArg(Call->getNumArgs() - 1)->getLocEnd())));
Brenden Blanco28333862015-05-28 18:19:38 -0700676
Brenden Blanco7009b552015-05-26 11:48:17 -0700677 // find the table fd, which was opened at declaration time
Brenden Blancofaea8c82017-03-29 09:58:31 -0700678 TableStorage::iterator desc;
679 Path local_path({fe_.id(), Ref->getDecl()->getName()});
680 Path global_path({Ref->getDecl()->getName()});
681 if (!fe_.table_storage().Find(local_path, desc)) {
682 if (!fe_.table_storage().Find(global_path, desc)) {
683 error(Ref->getLocEnd(), "bpf_table %0 failed to open") << Ref->getDecl()->getName();
684 return false;
685 }
Brenden Blanco7009b552015-05-26 11:48:17 -0700686 }
Brenden Blancofaea8c82017-03-29 09:58:31 -0700687 string fd = to_string(desc->second.fd);
Brenden Blanco7009b552015-05-26 11:48:17 -0700688 string prefix, suffix;
Brenden Blanco28333862015-05-28 18:19:38 -0700689 string txt;
Brenden Blancoef6bb802016-03-04 15:13:13 -0800690 auto rewrite_start = Call->getLocStart();
691 auto rewrite_end = Call->getLocEnd();
Brenden Blanco28333862015-05-28 18:19:38 -0700692 if (memb_name == "lookup_or_init") {
Brenden Blanco28333862015-05-28 18:19:38 -0700693 string name = Ref->getDecl()->getName();
Paul Chaignonc5c3b992017-02-26 12:22:03 +0100694 string arg0 = rewriter_.getRewrittenText(expansionRange(Call->getArg(0)->getSourceRange()));
695 string arg1 = rewriter_.getRewrittenText(expansionRange(Call->getArg(1)->getSourceRange()));
Brenden Blanco28333862015-05-28 18:19:38 -0700696 string lookup = "bpf_map_lookup_elem_(bpf_pseudo_fd(1, " + fd + ")";
697 string update = "bpf_map_update_elem_(bpf_pseudo_fd(1, " + fd + ")";
698 txt = "({typeof(" + name + ".leaf) *leaf = " + lookup + ", " + arg0 + "); ";
699 txt += "if (!leaf) {";
Paul Chaignon6ceb3292017-04-01 18:23:58 +0200700 txt += " " + update + ", " + arg0 + ", " + arg1 + ", BPF_NOEXIST);";
Brenden Blanco28333862015-05-28 18:19:38 -0700701 txt += " leaf = " + lookup + ", " + arg0 + ");";
Brenden Blancod23d6992015-05-28 18:40:09 -0700702 txt += " if (!leaf) return 0;";
Brenden Blanco28333862015-05-28 18:19:38 -0700703 txt += "}";
704 txt += "leaf;})";
Brenden Blancof0b15c42015-09-23 21:36:05 -0700705 } else if (memb_name == "increment") {
706 string name = Ref->getDecl()->getName();
Paul Chaignonc5c3b992017-02-26 12:22:03 +0100707 string arg0 = rewriter_.getRewrittenText(expansionRange(Call->getArg(0)->getSourceRange()));
Brenden Blancof0b15c42015-09-23 21:36:05 -0700708 string lookup = "bpf_map_lookup_elem_(bpf_pseudo_fd(1, " + fd + ")";
709 string update = "bpf_map_update_elem_(bpf_pseudo_fd(1, " + fd + ")";
710 txt = "({ typeof(" + name + ".key) _key = " + arg0 + "; ";
Brenden Blancof0b15c42015-09-23 21:36:05 -0700711 txt += "typeof(" + name + ".leaf) *_leaf = " + lookup + ", &_key); ";
Brenden Blanco23fc5892017-08-23 15:15:32 -0700712 txt += "if (_leaf) (*_leaf)++; ";
713 if (desc->second.type == BPF_MAP_TYPE_HASH) {
Yonghong Song1ab5f662018-01-24 16:42:53 -0800714 txt += "else { typeof(" + name + ".leaf) _zleaf; __builtin_memset(&_zleaf, 0, sizeof(_zleaf)); ";
Brenden Blanco23fc5892017-08-23 15:15:32 -0700715 txt += "_zleaf++; ";
716 txt += update + ", &_key, &_zleaf, BPF_NOEXIST); } ";
717 }
718 txt += "})";
Brenden Blancoaeca6bf2015-11-06 13:03:05 -0800719 } else if (memb_name == "perf_submit") {
Brenden Blancod0daf6a2015-11-05 23:31:22 -0800720 string name = Ref->getDecl()->getName();
Paul Chaignonc5c3b992017-02-26 12:22:03 +0100721 string arg0 = rewriter_.getRewrittenText(expansionRange(Call->getArg(0)->getSourceRange()));
722 string args_other = rewriter_.getRewrittenText(expansionRange(SourceRange(Call->getArg(1)->getLocStart(),
723 Call->getArg(2)->getLocEnd())));
Brenden Blancoaeca6bf2015-11-06 13:03:05 -0800724 txt = "bpf_perf_event_output(" + arg0 + ", bpf_pseudo_fd(1, " + fd + ")";
Teng Qin204df9e2017-05-23 11:57:44 -0700725 txt += ", CUR_CPU_IDENTIFIER, " + args_other + ")";
Martin KaFai Laubdad3842016-08-19 15:34:18 -0700726 } else if (memb_name == "perf_submit_skb") {
Paul Chaignonc5c3b992017-02-26 12:22:03 +0100727 string skb = rewriter_.getRewrittenText(expansionRange(Call->getArg(0)->getSourceRange()));
728 string skb_len = rewriter_.getRewrittenText(expansionRange(Call->getArg(1)->getSourceRange()));
729 string meta = rewriter_.getRewrittenText(expansionRange(Call->getArg(2)->getSourceRange()));
730 string meta_len = rewriter_.getRewrittenText(expansionRange(Call->getArg(3)->getSourceRange()));
Martin KaFai Laubdad3842016-08-19 15:34:18 -0700731 txt = "bpf_perf_event_output(" +
732 skb + ", " +
733 "bpf_pseudo_fd(1, " + fd + "), " +
734 "((__u64)" + skb_len + " << 32) | BPF_F_CURRENT_CPU, " +
735 meta + ", " +
736 meta_len + ");";
Brenden Blancoad0e8832016-03-04 13:58:44 -0800737 } else if (memb_name == "get_stackid") {
Brenden Blancofaea8c82017-03-29 09:58:31 -0700738 if (desc->second.type == BPF_MAP_TYPE_STACK_TRACE) {
739 string arg0 =
740 rewriter_.getRewrittenText(expansionRange(Call->getArg(0)->getSourceRange()));
Yonghong Songd0492522017-10-17 22:46:02 -0700741 txt = "bcc_get_stackid(";
Brenden Blancofaea8c82017-03-29 09:58:31 -0700742 txt += "bpf_pseudo_fd(1, " + fd + "), " + arg0;
743 rewrite_end = Call->getArg(0)->getLocEnd();
Brenden Blancoad0e8832016-03-04 13:58:44 -0800744 } else {
Brenden Blancoc98ffd62016-04-09 18:41:42 -0700745 error(Call->getLocStart(), "get_stackid only available on stacktrace maps");
Brenden Blancoad0e8832016-03-04 13:58:44 -0800746 return false;
747 }
Brenden Blanco7009b552015-05-26 11:48:17 -0700748 } else {
Brenden Blanco28333862015-05-28 18:19:38 -0700749 if (memb_name == "lookup") {
Brenden Blancoad0e8832016-03-04 13:58:44 -0800750 prefix = "bpf_map_lookup_elem";
751 suffix = ")";
Brenden Blanco28333862015-05-28 18:19:38 -0700752 } else if (memb_name == "update") {
753 prefix = "bpf_map_update_elem";
Paul Chaignon6ceb3292017-04-01 18:23:58 +0200754 suffix = ", BPF_ANY)";
755 } else if (memb_name == "insert") {
Brenden Blancofaea8c82017-03-29 09:58:31 -0700756 if (desc->second.type == BPF_MAP_TYPE_ARRAY) {
Paul Chaignon6ceb3292017-04-01 18:23:58 +0200757 warning(Call->getLocStart(), "all element of an array already exist; insert() will have no effect");
758 }
759 prefix = "bpf_map_update_elem";
760 suffix = ", BPF_NOEXIST)";
Brenden Blanco28333862015-05-28 18:19:38 -0700761 } else if (memb_name == "delete") {
762 prefix = "bpf_map_delete_elem";
763 suffix = ")";
764 } else if (memb_name == "call") {
765 prefix = "bpf_tail_call_";
766 suffix = ")";
Brenden Blancod0daf6a2015-11-05 23:31:22 -0800767 } else if (memb_name == "perf_read") {
768 prefix = "bpf_perf_event_read";
769 suffix = ")";
Teng Qin4186f5e2017-12-15 00:22:18 -0800770 } else if (memb_name == "perf_counter_value") {
771 prefix = "bpf_perf_event_read_value";
772 suffix = ")";
Teng Qine5e9b1f2018-04-25 13:49:37 -0700773 } else if (memb_name == "check_current_task") {
774 prefix = "bpf_current_task_under_cgroup";
775 suffix = ")";
Gary Lindb410bf2018-06-07 16:08:46 +0800776 } else if (memb_name == "redirect_map") {
777 prefix = "bpf_redirect_map";
778 suffix = ")";
Brenden Blanco28333862015-05-28 18:19:38 -0700779 } else {
Vicent Marticc3a4322016-04-30 14:57:52 +0200780 error(Call->getLocStart(), "invalid bpf_table operation %0") << memb_name;
Brenden Blanco28333862015-05-28 18:19:38 -0700781 return false;
782 }
783 prefix += "((void *)bpf_pseudo_fd(1, " + fd + "), ";
Brenden Blanco7009b552015-05-26 11:48:17 -0700784
Brenden Blanco28333862015-05-28 18:19:38 -0700785 txt = prefix + args + suffix;
786 }
Brenden Blancoef6bb802016-03-04 15:13:13 -0800787 if (!rewriter_.isRewritable(rewrite_start) || !rewriter_.isRewritable(rewrite_end)) {
Brenden Blancoc98ffd62016-04-09 18:41:42 -0700788 error(Call->getLocStart(), "cannot use map function inside a macro");
Brenden Blanco561dafc2015-06-29 11:09:00 -0700789 return false;
790 }
Paul Chaignonc5c3b992017-02-26 12:22:03 +0100791 rewriter_.ReplaceText(expansionRange(SourceRange(rewrite_start, rewrite_end)), txt);
Brenden Blanco7009b552015-05-26 11:48:17 -0700792 return true;
793 }
794 }
Brenden Blanco561dafc2015-06-29 11:09:00 -0700795 } else if (Call->getCalleeDecl()) {
796 NamedDecl *Decl = dyn_cast<NamedDecl>(Call->getCalleeDecl());
797 if (!Decl) return true;
798 if (AsmLabelAttr *A = Decl->getAttr<AsmLabelAttr>()) {
799 // Functions with the tag asm("llvm.bpf.extra") are implemented in the
800 // rewriter rather than as a macro since they may also include nested
801 // rewrites, and clang::Rewriter does not support rewrites in macros,
802 // unless one preprocesses the entire source file.
803 if (A->getLabel() == "llvm.bpf.extra") {
804 if (!rewriter_.isRewritable(Call->getLocStart())) {
Brenden Blancoc98ffd62016-04-09 18:41:42 -0700805 error(Call->getLocStart(), "cannot use builtin inside a macro");
Brenden Blanco561dafc2015-06-29 11:09:00 -0700806 return false;
807 }
808
809 vector<string> args;
810 for (auto arg : Call->arguments())
Paul Chaignonc5c3b992017-02-26 12:22:03 +0100811 args.push_back(rewriter_.getRewrittenText(expansionRange(arg->getSourceRange())));
Brenden Blanco561dafc2015-06-29 11:09:00 -0700812
813 string text;
814 if (Decl->getName() == "incr_cksum_l3") {
Brenden Blancob711d452015-07-01 15:23:18 -0700815 text = "bpf_l3_csum_replace_(" + fn_args_[0]->getName().str() + ", (u64)";
Brenden Blanco561dafc2015-06-29 11:09:00 -0700816 text += args[0] + ", " + args[1] + ", " + args[2] + ", sizeof(" + args[2] + "))";
Paul Chaignonc5c3b992017-02-26 12:22:03 +0100817 rewriter_.ReplaceText(expansionRange(Call->getSourceRange()), text);
Brenden Blanco561dafc2015-06-29 11:09:00 -0700818 } else if (Decl->getName() == "incr_cksum_l4") {
Brenden Blancob711d452015-07-01 15:23:18 -0700819 text = "bpf_l4_csum_replace_(" + fn_args_[0]->getName().str() + ", (u64)";
Brenden Blanco561dafc2015-06-29 11:09:00 -0700820 text += args[0] + ", " + args[1] + ", " + args[2];
821 text += ", ((" + args[3] + " & 0x1) << 4) | sizeof(" + args[2] + "))";
Paul Chaignonc5c3b992017-02-26 12:22:03 +0100822 rewriter_.ReplaceText(expansionRange(Call->getSourceRange()), text);
Brenden Blanco561dafc2015-06-29 11:09:00 -0700823 } else if (Decl->getName() == "bpf_trace_printk") {
Paul Chaignon93419422017-03-12 14:49:01 +0100824 checkFormatSpecifiers(args[0], Call->getArg(0)->getLocStart());
Brenden Blanco561dafc2015-06-29 11:09:00 -0700825 // #define bpf_trace_printk(fmt, args...)
826 // ({ char _fmt[] = fmt; bpf_trace_printk_(_fmt, sizeof(_fmt), args...); })
Brenden Blanco46176a12015-07-07 13:05:22 -0700827 text = "({ char _fmt[] = " + args[0] + "; bpf_trace_printk_(_fmt, sizeof(_fmt)";
Brenden Blancoa328d232015-08-11 18:33:49 -0700828 if (args.size() <= 1) {
829 text += "); })";
Paul Chaignonc5c3b992017-02-26 12:22:03 +0100830 rewriter_.ReplaceText(expansionRange(Call->getSourceRange()), text);
Brenden Blancoa328d232015-08-11 18:33:49 -0700831 } else {
Paul Chaignonc5c3b992017-02-26 12:22:03 +0100832 rewriter_.ReplaceText(expansionRange(SourceRange(Call->getLocStart(), Call->getArg(0)->getLocEnd())), text);
Brenden Blancoa328d232015-08-11 18:33:49 -0700833 rewriter_.InsertTextAfter(Call->getLocEnd(), "); }");
Brenden Blanco561dafc2015-06-29 11:09:00 -0700834 }
Brenden Blancoaeca6bf2015-11-06 13:03:05 -0800835 } else if (Decl->getName() == "bpf_num_cpus") {
836 int numcpu = sysconf(_SC_NPROCESSORS_ONLN);
837 if (numcpu <= 0)
838 numcpu = 1;
839 text = to_string(numcpu);
Paul Chaignonc5c3b992017-02-26 12:22:03 +0100840 rewriter_.ReplaceText(expansionRange(Call->getSourceRange()), text);
Vicent Marti4ea4af42016-05-04 13:01:55 +0200841 } else if (Decl->getName() == "bpf_usdt_readarg_p") {
Vicent Marti040df7d2016-05-04 16:59:57 +0200842 text = "({ u64 __addr = 0x0; ";
843 text += "_bpf_readarg_" + current_fn_ + "_" + args[0] + "(" +
844 args[1] + ", &__addr, sizeof(__addr));";
845 text += "bpf_probe_read(" + args[2] + ", " + args[3] +
846 ", (void *)__addr);";
847 text += "})";
Paul Chaignonc5c3b992017-02-26 12:22:03 +0100848 rewriter_.ReplaceText(expansionRange(Call->getSourceRange()), text);
Vicent Marti4ea4af42016-05-04 13:01:55 +0200849 } else if (Decl->getName() == "bpf_usdt_readarg") {
Vicent Marti040df7d2016-05-04 16:59:57 +0200850 text = "_bpf_readarg_" + current_fn_ + "_" + args[0] + "(" + args[1] +
851 ", " + args[2] + ", sizeof(*(" + args[2] + ")))";
Paul Chaignonc5c3b992017-02-26 12:22:03 +0100852 rewriter_.ReplaceText(expansionRange(Call->getSourceRange()), text);
Vicent Marti040df7d2016-05-04 16:59:57 +0200853 }
Brenden Blanco561dafc2015-06-29 11:09:00 -0700854 }
Brenden Blanco3f28e7b2017-04-20 09:33:44 -0700855 } else if (FunctionDecl *F = dyn_cast<FunctionDecl>(Decl)) {
856 if (F->isExternallyVisible() && !F->getBuiltinID()) {
857 auto start_loc = rewriter_.getSourceMgr().getFileLoc(Decl->getLocStart());
858 if (rewriter_.getSourceMgr().getFileID(start_loc)
859 == rewriter_.getSourceMgr().getMainFileID()) {
860 error(Call->getLocStart(), "cannot call non-static helper function");
861 return false;
862 }
863 }
Brenden Blanco561dafc2015-06-29 11:09:00 -0700864 }
Brenden Blanco7009b552015-05-26 11:48:17 -0700865 }
866 return true;
867}
868
Paul Chaignon93419422017-03-12 14:49:01 +0100869bool BTypeVisitor::checkFormatSpecifiers(const string& fmt, SourceLocation loc) {
870 unsigned nb_specifiers = 0, i, j;
871 bool has_s = false;
872 for (i = 0; i < fmt.length(); i++) {
873 if (!isascii(fmt[i]) || (!isprint(fmt[i]) && !isspace(fmt[i]))) {
874 warning(loc.getLocWithOffset(i), "unrecognized character");
875 return false;
876 }
877 if (fmt[i] != '%')
878 continue;
879 if (nb_specifiers >= 3) {
880 warning(loc.getLocWithOffset(i), "cannot use more than 3 conversion specifiers");
881 return false;
882 }
883 nb_specifiers++;
884 i++;
885 if (fmt[i] == 'l') {
886 i++;
887 } else if (fmt[i] == 'p' || fmt[i] == 's') {
888 i++;
889 if (!isspace(fmt[i]) && !ispunct(fmt[i]) && fmt[i] != 0) {
890 warning(loc.getLocWithOffset(i - 2),
891 "only %%d %%u %%x %%ld %%lu %%lx %%lld %%llu %%llx %%p %%s conversion specifiers allowed");
892 return false;
893 }
894 if (fmt[i - 1] == 's') {
895 if (has_s) {
896 warning(loc.getLocWithOffset(i - 2), "cannot use several %%s conversion specifiers");
897 return false;
898 }
899 has_s = true;
900 }
901 continue;
902 }
903 j = 1;
904 if (fmt[i] == 'l') {
905 i++;
906 j++;
907 }
908 if (fmt[i] != 'd' && fmt[i] != 'u' && fmt[i] != 'x') {
909 warning(loc.getLocWithOffset(i - j),
910 "only %%d %%u %%x %%ld %%lu %%lx %%lld %%llu %%llx %%p %%s conversion specifiers allowed");
911 return false;
912 }
913 }
914 return true;
915}
916
Brenden Blanco22a419b2015-05-29 11:14:20 -0700917bool BTypeVisitor::VisitBinaryOperator(BinaryOperator *E) {
918 if (!E->isAssignmentOp())
919 return true;
920 Expr *LHS = E->getLHS()->IgnoreImplicit();
Brenden Blanco22a419b2015-05-29 11:14:20 -0700921 if (MemberExpr *Memb = dyn_cast<MemberExpr>(LHS)) {
922 if (DeclRefExpr *Base = dyn_cast<DeclRefExpr>(Memb->getBase()->IgnoreImplicit())) {
923 if (DeprecatedAttr *A = Base->getDecl()->getAttr<DeprecatedAttr>()) {
924 if (A->getMessage() == "packet") {
925 if (FieldDecl *F = dyn_cast<FieldDecl>(Memb->getMemberDecl())) {
Brenden Blanco561dafc2015-06-29 11:09:00 -0700926 if (!rewriter_.isRewritable(E->getLocStart())) {
Brenden Blancoc98ffd62016-04-09 18:41:42 -0700927 error(E->getLocStart(), "cannot use \"packet\" header type inside a macro");
Brenden Blanco561dafc2015-06-29 11:09:00 -0700928 return false;
929 }
Brenden Blanco22a419b2015-05-29 11:14:20 -0700930 uint64_t ofs = C.getFieldOffset(F);
931 uint64_t sz = F->isBitField() ? F->getBitWidthValue(C) : C.getTypeSize(F->getType());
Paul Chaignonc5c3b992017-02-26 12:22:03 +0100932 string base = rewriter_.getRewrittenText(expansionRange(Base->getSourceRange()));
Brenden Blancob711d452015-07-01 15:23:18 -0700933 string text = "bpf_dins_pkt(" + fn_args_[0]->getName().str() + ", (u64)" + base + "+" + to_string(ofs >> 3)
Paul Chaignon47b74fe2017-02-23 20:06:03 +0100934 + ", " + to_string(ofs & 0x7) + ", " + to_string(sz) + ",";
935 rewriter_.ReplaceText(expansionRange(SourceRange(E->getLocStart(), E->getOperatorLoc())), text);
936 rewriter_.InsertTextAfterToken(E->getLocEnd(), ")");
Brenden Blanco22a419b2015-05-29 11:14:20 -0700937 }
938 }
939 }
940 }
941 }
942 return true;
943}
944bool BTypeVisitor::VisitImplicitCastExpr(ImplicitCastExpr *E) {
945 // use dext only for RValues
946 if (E->getCastKind() != CK_LValueToRValue)
947 return true;
948 MemberExpr *Memb = dyn_cast<MemberExpr>(E->IgnoreImplicit());
949 if (!Memb)
950 return true;
951 Expr *Base = Memb->getBase()->IgnoreImplicit();
Brenden Blanco28333862015-05-28 18:19:38 -0700952 if (DeclRefExpr *Ref = dyn_cast<DeclRefExpr>(Base)) {
953 if (DeprecatedAttr *A = Ref->getDecl()->getAttr<DeprecatedAttr>()) {
954 if (A->getMessage() == "packet") {
Brenden Blanco22a419b2015-05-29 11:14:20 -0700955 if (FieldDecl *F = dyn_cast<FieldDecl>(Memb->getMemberDecl())) {
Brenden Blanco561dafc2015-06-29 11:09:00 -0700956 if (!rewriter_.isRewritable(E->getLocStart())) {
Brenden Blancoc98ffd62016-04-09 18:41:42 -0700957 error(E->getLocStart(), "cannot use \"packet\" header type inside a macro");
Brenden Blanco561dafc2015-06-29 11:09:00 -0700958 return false;
959 }
Brenden Blanco28333862015-05-28 18:19:38 -0700960 uint64_t ofs = C.getFieldOffset(F);
961 uint64_t sz = F->isBitField() ? F->getBitWidthValue(C) : C.getTypeSize(F->getType());
Brenden Blancob711d452015-07-01 15:23:18 -0700962 string text = "bpf_dext_pkt(" + fn_args_[0]->getName().str() + ", (u64)" + Ref->getDecl()->getName().str() + "+"
Brenden Blanco561dafc2015-06-29 11:09:00 -0700963 + to_string(ofs >> 3) + ", " + to_string(ofs & 0x7) + ", " + to_string(sz) + ")";
Paul Chaignonc5c3b992017-02-26 12:22:03 +0100964 rewriter_.ReplaceText(expansionRange(E->getSourceRange()), text);
Brenden Blanco28333862015-05-28 18:19:38 -0700965 }
966 }
967 }
968 }
969 return true;
970}
971
Paul Chaignonc5c3b992017-02-26 12:22:03 +0100972SourceRange
973BTypeVisitor::expansionRange(SourceRange range) {
Yonghong Song806627e2018-05-02 10:32:31 -0700974#if LLVM_MAJOR_VERSION >= 7
975 return rewriter_.getSourceMgr().getExpansionRange(range).getAsRange();
976#else
Paul Chaignonc5c3b992017-02-26 12:22:03 +0100977 return rewriter_.getSourceMgr().getExpansionRange(range);
Yonghong Song806627e2018-05-02 10:32:31 -0700978#endif
Paul Chaignonc5c3b992017-02-26 12:22:03 +0100979}
980
Brenden Blancoc98ffd62016-04-09 18:41:42 -0700981template <unsigned N>
982DiagnosticBuilder BTypeVisitor::error(SourceLocation loc, const char (&fmt)[N]) {
983 unsigned int diag_id = C.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error, fmt);
984 return C.getDiagnostics().Report(loc, diag_id);
985}
986
Paul Chaignon93419422017-03-12 14:49:01 +0100987template <unsigned N>
988DiagnosticBuilder BTypeVisitor::warning(SourceLocation loc, const char (&fmt)[N]) {
989 unsigned int diag_id = C.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Warning, fmt);
990 return C.getDiagnostics().Report(loc, diag_id);
991}
992
Brenden Blanco7009b552015-05-26 11:48:17 -0700993// Open table FDs when bpf tables (as denoted by section("maps*") attribute)
994// are declared.
995bool BTypeVisitor::VisitVarDecl(VarDecl *Decl) {
996 const RecordType *R = Decl->getType()->getAs<RecordType>();
997 if (SectionAttr *A = Decl->getAttr<SectionAttr>()) {
998 if (!A->getName().startswith("maps"))
999 return true;
1000 if (!R) {
Brenden Blancoc98ffd62016-04-09 18:41:42 -07001001 error(Decl->getLocEnd(), "invalid type for bpf_table, expect struct");
Brenden Blanco7009b552015-05-26 11:48:17 -07001002 return false;
1003 }
1004 const RecordDecl *RD = R->getDecl()->getDefinition();
Brenden Blanco8ac3ea72015-08-07 22:04:56 -07001005
Brenden Blancofaea8c82017-03-29 09:58:31 -07001006 TableDesc table;
1007 TableStorage::iterator table_it;
Brenden Blanco8ac3ea72015-08-07 22:04:56 -07001008 table.name = Decl->getName();
Brenden Blancofaea8c82017-03-29 09:58:31 -07001009 Path local_path({fe_.id(), table.name});
1010 Path global_path({table.name});
1011 QualType key_type, leaf_type;
Brenden Blanco8ac3ea72015-08-07 22:04:56 -07001012
Brenden Blanco7009b552015-05-26 11:48:17 -07001013 unsigned i = 0;
1014 for (auto F : RD->fields()) {
Paul Chaignond32a61b2017-08-23 07:25:30 +02001015 if (F->getType().getTypePtr()->isIncompleteType()) {
1016 error(F->getLocStart(), "unknown type");
1017 return false;
1018 }
1019
Brenden Blanco7009b552015-05-26 11:48:17 -07001020 size_t sz = C.getTypeSize(F->getType()) >> 3;
1021 if (F->getName() == "key") {
Brenden Blancofe88e5a2015-12-06 19:58:38 -08001022 if (sz == 0) {
Brenden Blancoc98ffd62016-04-09 18:41:42 -07001023 error(F->getLocStart(), "invalid zero-sized leaf");
Brenden Blancofe88e5a2015-12-06 19:58:38 -08001024 return false;
1025 }
Brenden Blanco7009b552015-05-26 11:48:17 -07001026 table.key_size = sz;
Brenden Blancofaea8c82017-03-29 09:58:31 -07001027 key_type = F->getType();
Brenden Blanco7009b552015-05-26 11:48:17 -07001028 } else if (F->getName() == "leaf") {
Brenden Blancofe88e5a2015-12-06 19:58:38 -08001029 if (sz == 0) {
Brenden Blancoc98ffd62016-04-09 18:41:42 -07001030 error(F->getLocStart(), "invalid zero-sized leaf");
Brenden Blancofe88e5a2015-12-06 19:58:38 -08001031 return false;
1032 }
Brenden Blanco7009b552015-05-26 11:48:17 -07001033 table.leaf_size = sz;
Brenden Blancofaea8c82017-03-29 09:58:31 -07001034 leaf_type = F->getType();
Yonghong Song067219b2017-08-16 16:18:22 -07001035 } else if (F->getName() == "max_entries") {
1036 unsigned idx = F->getFieldIndex();
1037 if (auto I = dyn_cast_or_null<InitListExpr>(Decl->getInit())) {
1038 llvm::APSInt res;
1039 if (I->getInit(idx)->EvaluateAsInt(res, C)) {
1040 table.max_entries = res.getExtValue();
1041 }
1042 }
Huapeng Zhoude11d072016-12-06 18:10:38 -08001043 } else if (F->getName() == "flags") {
1044 unsigned idx = F->getFieldIndex();
1045 if (auto I = dyn_cast_or_null<InitListExpr>(Decl->getInit())) {
1046 llvm::APSInt res;
1047 if (I->getInit(idx)->EvaluateAsInt(res, C)) {
1048 table.flags = res.getExtValue();
1049 }
1050 }
Brenden Blanco7009b552015-05-26 11:48:17 -07001051 }
1052 ++i;
1053 }
Huapeng Zhoude11d072016-12-06 18:10:38 -08001054
Brenden Blanco7009b552015-05-26 11:48:17 -07001055 bpf_map_type map_type = BPF_MAP_TYPE_UNSPEC;
Brenden Blancof0b15c42015-09-23 21:36:05 -07001056 if (A->getName() == "maps/hash") {
Brenden Blanco7009b552015-05-26 11:48:17 -07001057 map_type = BPF_MAP_TYPE_HASH;
Brenden Blancof0b15c42015-09-23 21:36:05 -07001058 } else if (A->getName() == "maps/array") {
Brenden Blanco7009b552015-05-26 11:48:17 -07001059 map_type = BPF_MAP_TYPE_ARRAY;
Zaafar Ahmedf8228362016-03-30 17:59:54 +05001060 } else if (A->getName() == "maps/percpu_hash") {
Zaafar Ahmed64258252016-03-29 22:13:50 +05001061 map_type = BPF_MAP_TYPE_PERCPU_HASH;
Zaafar Ahmedf8228362016-03-30 17:59:54 +05001062 } else if (A->getName() == "maps/percpu_array") {
Zaafar Ahmed64258252016-03-29 22:13:50 +05001063 map_type = BPF_MAP_TYPE_PERCPU_ARRAY;
Huapeng Zhoue69f7642016-12-01 10:56:36 -08001064 } else if (A->getName() == "maps/lru_hash") {
1065 map_type = BPF_MAP_TYPE_LRU_HASH;
1066 } else if (A->getName() == "maps/lru_percpu_hash") {
1067 map_type = BPF_MAP_TYPE_LRU_PERCPU_HASH;
Huapeng Zhoufcd936c2017-02-07 15:03:32 -08001068 } else if (A->getName() == "maps/lpm_trie") {
1069 map_type = BPF_MAP_TYPE_LPM_TRIE;
Brenden Blancof0b15c42015-09-23 21:36:05 -07001070 } else if (A->getName() == "maps/histogram") {
Brenden Blancofaea8c82017-03-29 09:58:31 -07001071 map_type = BPF_MAP_TYPE_HASH;
1072 if (key_type->isSpecificBuiltinType(BuiltinType::Int))
Brenden Blancof0b15c42015-09-23 21:36:05 -07001073 map_type = BPF_MAP_TYPE_ARRAY;
Brenden Blancofaea8c82017-03-29 09:58:31 -07001074 if (!leaf_type->isSpecificBuiltinType(BuiltinType::ULongLong))
1075 error(Decl->getLocStart(), "histogram leaf type must be u64, got %0") << leaf_type;
Brenden Blancof0b15c42015-09-23 21:36:05 -07001076 } else if (A->getName() == "maps/prog") {
Alexei Starovoitovf09b5b82016-03-31 13:37:04 -07001077 map_type = BPF_MAP_TYPE_PROG_ARRAY;
Brenden Blancoaeca6bf2015-11-06 13:03:05 -08001078 } else if (A->getName() == "maps/perf_output") {
Alexei Starovoitovf09b5b82016-03-31 13:37:04 -07001079 map_type = BPF_MAP_TYPE_PERF_EVENT_ARRAY;
Andreas Gerstmayr7e0784d2017-01-16 16:35:58 +01001080 int numcpu = get_possible_cpus().size();
Brenden Blancoaeca6bf2015-11-06 13:03:05 -08001081 if (numcpu <= 0)
1082 numcpu = 1;
1083 table.max_entries = numcpu;
Brenden Blancod0daf6a2015-11-05 23:31:22 -08001084 } else if (A->getName() == "maps/perf_array") {
Alexei Starovoitovf09b5b82016-03-31 13:37:04 -07001085 map_type = BPF_MAP_TYPE_PERF_EVENT_ARRAY;
Teng Qine5e9b1f2018-04-25 13:49:37 -07001086 } else if (A->getName() == "maps/cgroup_array") {
1087 map_type = BPF_MAP_TYPE_CGROUP_ARRAY;
Brenden Blanco9cafce22016-03-04 12:02:10 -08001088 } else if (A->getName() == "maps/stacktrace") {
1089 map_type = BPF_MAP_TYPE_STACK_TRACE;
Gary Lindb410bf2018-06-07 16:08:46 +08001090 } else if (A->getName() == "maps/devmap") {
1091 map_type = BPF_MAP_TYPE_DEVMAP;
1092 } else if (A->getName() == "maps/cpumap") {
1093 map_type = BPF_MAP_TYPE_CPUMAP;
Brenden Blanco89978ba2015-12-15 16:39:35 -08001094 } else if (A->getName() == "maps/extern") {
Brenden Blancofaea8c82017-03-29 09:58:31 -07001095 if (!fe_.table_storage().Find(global_path, table_it)) {
Brenden Blancoc98ffd62016-04-09 18:41:42 -07001096 error(Decl->getLocStart(), "reference to undefined table");
Brenden Blanco89978ba2015-12-15 16:39:35 -08001097 return false;
1098 }
Brenden Blancofaea8c82017-03-29 09:58:31 -07001099 table = table_it->second.dup();
1100 table.is_extern = true;
1101 } else if (A->getName() == "maps/export") {
1102 if (table.name.substr(0, 2) == "__")
1103 table.name = table.name.substr(2);
1104 Path local_path({fe_.id(), table.name});
1105 Path global_path({table.name});
1106 if (!fe_.table_storage().Find(local_path, table_it)) {
1107 error(Decl->getLocStart(), "reference to undefined table");
Brenden Blanco89978ba2015-12-15 16:39:35 -08001108 return false;
1109 }
Brenden Blancofaea8c82017-03-29 09:58:31 -07001110 fe_.table_storage().Insert(global_path, table_it->second.dup());
Brenden Blanco89978ba2015-12-15 16:39:35 -08001111 return true;
Yonghong Songab21dcd2015-07-16 20:20:22 -07001112 }
Brenden Blancod0daf6a2015-11-05 23:31:22 -08001113
Huapeng Zhoud4a3baf2016-12-20 13:10:12 -08001114 if (!table.is_extern) {
Brenden Blanco89978ba2015-12-15 16:39:35 -08001115 if (map_type == BPF_MAP_TYPE_UNSPEC) {
Brenden Blancoc98ffd62016-04-09 18:41:42 -07001116 error(Decl->getLocStart(), "unsupported map type: %0") << A->getName();
Brenden Blanco89978ba2015-12-15 16:39:35 -08001117 return false;
1118 }
Brenden Blancod0daf6a2015-11-05 23:31:22 -08001119
Brenden Blanco89978ba2015-12-15 16:39:35 -08001120 table.type = map_type;
Martin KaFai Laudf368162017-10-19 12:46:48 -07001121 table.fd = bpf_create_map(map_type, table.name.c_str(),
1122 table.key_size, table.leaf_size,
1123 table.max_entries, table.flags);
Brenden Blanco89978ba2015-12-15 16:39:35 -08001124 }
Brenden Blanco7009b552015-05-26 11:48:17 -07001125 if (table.fd < 0) {
Vicent Marticc3a4322016-04-30 14:57:52 +02001126 error(Decl->getLocStart(), "could not open bpf map: %0\nis %1 map type enabled in your kernel?") <<
Brenden Blancoc98ffd62016-04-09 18:41:42 -07001127 strerror(errno) << A->getName();
Brenden Blanco7009b552015-05-26 11:48:17 -07001128 return false;
1129 }
Brenden Blanco89978ba2015-12-15 16:39:35 -08001130
Yonghong Song96354c62018-01-28 22:39:48 -08001131 if (!table.is_extern)
1132 fe_.table_storage().VisitMapType(table, C, key_type, leaf_type);
Brenden Blancofaea8c82017-03-29 09:58:31 -07001133 fe_.table_storage().Insert(local_path, move(table));
Brenden Blanco6ec65e42015-07-02 10:02:04 -07001134 } else if (const PointerType *P = Decl->getType()->getAs<PointerType>()) {
1135 // if var is a pointer to a packet type, clone the annotation into the var
1136 // decl so that the packet dext/dins rewriter can catch it
1137 if (const RecordType *RT = P->getPointeeType()->getAs<RecordType>()) {
1138 if (const RecordDecl *RD = RT->getDecl()->getDefinition()) {
1139 if (DeprecatedAttr *DA = RD->getAttr<DeprecatedAttr>()) {
1140 if (DA->getMessage() == "packet") {
1141 Decl->addAttr(DA->clone(C));
1142 }
1143 }
1144 }
1145 }
Brenden Blanco7009b552015-05-26 11:48:17 -07001146 }
1147 return true;
1148}
Brenden Blanco7009b552015-05-26 11:48:17 -07001149
Paul Chaignoneae0acf2017-08-05 23:04:41 +02001150// First traversal of AST to retrieve maps with external pointers.
Paul Chaignone67cb562017-10-26 08:43:13 +02001151BTypeConsumer::BTypeConsumer(ASTContext &C, BFrontendAction &fe,
Yonghong Song6fc8d152017-11-03 15:04:24 -07001152 Rewriter &rewriter, set<Decl *> &m)
1153 : fe_(fe),
1154 map_visitor_(m),
1155 btype_visitor_(C, fe),
Paul Chaignonad2d0d92018-05-08 22:02:55 +02001156 probe_visitor1_(C, rewriter, m, true),
1157 probe_visitor2_(C, rewriter, m, false) {}
Brenden Blanco7009b552015-05-26 11:48:17 -07001158
Paul Chaignoneae0acf2017-08-05 23:04:41 +02001159void BTypeConsumer::HandleTranslationUnit(ASTContext &Context) {
1160 DeclContext::decl_iterator it;
1161 DeclContext *DC = TranslationUnitDecl::castToDeclContext(Context.getTranslationUnitDecl());
Brenden Blanco8ed57a22015-09-16 14:59:35 -07001162
Paul Chaignone67cb562017-10-26 08:43:13 +02001163 /**
Paul Chaignonad2d0d92018-05-08 22:02:55 +02001164 * In a first traversal, ProbeVisitor tracks external pointers identified
1165 * through each function's arguments and replaces their dereferences with
1166 * calls to bpf_probe_read. It also passes all identified pointers to
1167 * external addresses to MapVisitor.
Paul Chaignone67cb562017-10-26 08:43:13 +02001168 */
Paul Chaignoneae0acf2017-08-05 23:04:41 +02001169 for (it = DC->decls_begin(); it != DC->decls_end(); it++) {
1170 Decl *D = *it;
Brenden Blanco8ed57a22015-09-16 14:59:35 -07001171 if (FunctionDecl *F = dyn_cast<FunctionDecl>(D)) {
Yonghong Song6fc8d152017-11-03 15:04:24 -07001172 if (fe_.is_rewritable_ext_func(F)) {
Brenden Blanco8ed57a22015-09-16 14:59:35 -07001173 for (auto arg : F->parameters()) {
Paul Chaignonb66a9c92018-05-01 22:10:28 +02001174 if (arg == F->getParamDecl(0)) {
Paul Chaignon05b20832018-05-19 14:31:13 +02001175 /**
1176 * Limit tracing of pointers from context to tracing contexts.
1177 * We're whitelisting instead of blacklisting to avoid issues with
1178 * existing programs if new context types are added in the future.
1179 */
1180 string type = arg->getType().getAsString();
1181 if (type == "struct pt_regs *" ||
1182 type == "struct bpf_raw_tracepoint_args *" ||
1183 type.substr(0, 19) == "struct tracepoint__")
1184 probe_visitor1_.set_ctx(arg);
Paul Chaignonb66a9c92018-05-01 22:10:28 +02001185 } else if (!arg->getType()->isFundamentalType()) {
Paul Chaignon471f1ea2018-05-11 09:36:37 +02001186 tuple<Decl *, int> pt = make_tuple(arg, 0);
1187 probe_visitor1_.set_ptreg(pt);
Paul Chaignonb66a9c92018-05-01 22:10:28 +02001188 }
Brenden Blanco8ed57a22015-09-16 14:59:35 -07001189 }
Paul Chaignonad2d0d92018-05-08 22:02:55 +02001190
1191 probe_visitor1_.TraverseDecl(D);
1192 for (auto ptreg : probe_visitor1_.get_ptregs()) {
1193 map_visitor_.set_ptreg(ptreg);
1194 }
1195 }
1196 }
1197 }
1198
1199 /**
1200 * MapVisitor uses external pointers identified by the first ProbeVisitor
1201 * traversal to identify all maps with external pointers as values.
1202 * MapVisitor runs only after ProbeVisitor finished its traversal of the
1203 * whole translation unit to clearly separate the role of each ProbeVisitor's
1204 * traversal: the first tracks external pointers from function arguments,
1205 * whereas the second tracks external pointers from maps. Without this clear
1206 * separation, ProbeVisitor might attempt to replace several times the same
1207 * dereferences.
1208 */
1209 for (it = DC->decls_begin(); it != DC->decls_end(); it++) {
1210 Decl *D = *it;
1211 if (FunctionDecl *F = dyn_cast<FunctionDecl>(D)) {
1212 if (fe_.is_rewritable_ext_func(F)) {
1213 map_visitor_.TraverseDecl(D);
1214 }
1215 }
1216 }
1217
1218 /**
1219 * In a second traversal, ProbeVisitor tracks pointers passed through the
1220 * maps identified by MapVisitor and replaces their dereferences with calls
1221 * to bpf_probe_read.
1222 * This last traversal runs after MapVisitor went through an entire
1223 * translation unit, to ensure maps with external pointers have all been
1224 * identified.
1225 */
1226 for (it = DC->decls_begin(); it != DC->decls_end(); it++) {
1227 Decl *D = *it;
1228 if (FunctionDecl *F = dyn_cast<FunctionDecl>(D)) {
1229 if (fe_.is_rewritable_ext_func(F)) {
1230 probe_visitor2_.TraverseDecl(D);
Brenden Blanco8ed57a22015-09-16 14:59:35 -07001231 }
1232 }
Paul Chaignone67cb562017-10-26 08:43:13 +02001233
1234 btype_visitor_.TraverseDecl(D);
Brenden Blanco8ed57a22015-09-16 14:59:35 -07001235 }
Brenden Blanco7009b552015-05-26 11:48:17 -07001236}
1237
Yonghong Song91837ca2017-09-28 09:40:13 -07001238BFrontendAction::BFrontendAction(llvm::raw_ostream &os, unsigned flags,
1239 TableStorage &ts, const std::string &id,
Yonghong Song6fc8d152017-11-03 15:04:24 -07001240 const std::string &main_path,
Yonghong Song91837ca2017-09-28 09:40:13 -07001241 FuncSource &func_src, std::string &mod_src)
1242 : os_(os),
1243 flags_(flags),
1244 ts_(ts),
1245 id_(id),
1246 rewriter_(new Rewriter),
Yonghong Song6fc8d152017-11-03 15:04:24 -07001247 main_path_(main_path),
Yonghong Song91837ca2017-09-28 09:40:13 -07001248 func_src_(func_src),
1249 mod_src_(mod_src) {}
Brenden Blanco7009b552015-05-26 11:48:17 -07001250
Yonghong Song6fc8d152017-11-03 15:04:24 -07001251bool BFrontendAction::is_rewritable_ext_func(FunctionDecl *D) {
1252 StringRef file_name = rewriter_->getSourceMgr().getFilename(D->getLocStart());
1253 return (D->isExternallyVisible() && D->hasBody() &&
1254 (file_name.empty() || file_name == main_path_));
1255}
1256
Yonghong Songbace5f22018-05-27 11:52:03 -07001257void BFrontendAction::DoMiscWorkAround() {
1258 // In 4.16 and later, CONFIG_CC_STACKPROTECTOR is moved out of Kconfig and into
1259 // Makefile. It will be set depending on CONFIG_CC_STACKPROTECTOR_{AUTO|REGULAR|STRONG}.
1260 // CONFIG_CC_STACKPROTECTOR is still used in various places, e.g., struct task_struct,
1261 // to guard certain fields. The workaround here intends to define
1262 // CONFIG_CC_STACKPROTECTOR properly based on other configs, so it relieved any bpf
1263 // program (using task_struct, etc.) of patching the below code.
1264 rewriter_->getEditBuffer(rewriter_->getSourceMgr().getMainFileID()).InsertText(0,
1265 "#if !defined(CONFIG_CC_STACKPROTECTOR)\n"
1266 "#if defined(CONFIG_CC_STACKPROTECTOR_AUTO) \\\n"
1267 " || defined(CONFIG_CC_STACKPROTECTOR_REGULAR) \\\n"
1268 " || defined(CONFIG_CC_STACKPROTECTOR_STRONG)\n"
1269 "#define CONFIG_CC_STACKPROTECTOR\n"
1270 "#endif\n"
1271 "#endif\n",
1272 false);
1273}
1274
Brenden Blanco7009b552015-05-26 11:48:17 -07001275void BFrontendAction::EndSourceFileAction() {
Yonghong Songbace5f22018-05-27 11:52:03 -07001276 // Additional misc rewrites
1277 DoMiscWorkAround();
1278
Jean-Tiare Le Bigot7d37bf42016-03-29 12:48:02 +00001279 if (flags_ & DEBUG_PREPROCESSOR)
Brenden Blancob13426c2015-09-08 22:11:46 -07001280 rewriter_->getEditBuffer(rewriter_->getSourceMgr().getMainFileID()).write(llvm::errs());
Yonghong Song91837ca2017-09-28 09:40:13 -07001281 if (flags_ & DEBUG_SOURCE) {
1282 llvm::raw_string_ostream tmp_os(mod_src_);
1283 rewriter_->getEditBuffer(rewriter_->getSourceMgr().getMainFileID())
1284 .write(tmp_os);
1285 }
Alexei Starovoitov4f47e3b2017-09-06 19:57:21 -07001286
1287 for (auto func : func_range_) {
1288 auto f = func.first;
1289 string bd = rewriter_->getRewrittenText(func_range_[f]);
1290 func_src_.set_src_rewritten(f, bd);
1291 }
Brenden Blanco7009b552015-05-26 11:48:17 -07001292 rewriter_->getEditBuffer(rewriter_->getSourceMgr().getMainFileID()).write(os_);
1293 os_.flush();
1294}
1295
1296unique_ptr<ASTConsumer> BFrontendAction::CreateASTConsumer(CompilerInstance &Compiler, llvm::StringRef InFile) {
1297 rewriter_->setSourceMgr(Compiler.getSourceManager(), Compiler.getLangOpts());
Brenden Blanco8ed57a22015-09-16 14:59:35 -07001298 vector<unique_ptr<ASTConsumer>> consumers;
Paul Chaignone67cb562017-10-26 08:43:13 +02001299 consumers.push_back(unique_ptr<ASTConsumer>(new BTypeConsumer(Compiler.getASTContext(), *this, *rewriter_, m_)));
Brenden Blancofaea8c82017-03-29 09:58:31 -07001300 return unique_ptr<ASTConsumer>(new MultiplexConsumer(std::move(consumers)));
Brenden Blanco7009b552015-05-26 11:48:17 -07001301}
1302
1303}