Brenden Blanco | 246b942 | 2015-06-05 11:15:27 -0700 | [diff] [blame] | 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 | */ |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 16 | #include <linux/bpf.h> |
Brenden Blanco | f275d3d | 2015-07-06 23:41:23 -0700 | [diff] [blame] | 17 | #include <linux/version.h> |
Yonghong Song | ab21dcd | 2015-07-16 20:20:22 -0700 | [diff] [blame] | 18 | #include <sys/utsname.h> |
Brenden Blanco | aeca6bf | 2015-11-06 13:03:05 -0800 | [diff] [blame] | 19 | #include <unistd.h> |
Joel Fernandes | 1086952 | 2018-02-01 21:23:24 -0500 | [diff] [blame] | 20 | #include <stdlib.h> |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 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> |
Brenden Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 26 | #include <clang/Frontend/MultiplexConsumer.h> |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 27 | #include <clang/Rewrite/Core/Rewriter.h> |
| 28 | |
| 29 | #include "b_frontend_action.h" |
Teng Qin | 73e2f2d | 2017-11-09 13:53:39 -0800 | [diff] [blame] | 30 | #include "bpf_module.h" |
Andreas Gerstmayr | 7e0784d | 2017-01-16 16:35:58 +0100 | [diff] [blame] | 31 | #include "common.h" |
Teng Qin | 73e2f2d | 2017-11-09 13:53:39 -0800 | [diff] [blame] | 32 | #include "loader.h" |
Brenden Blanco | faea8c8 | 2017-03-29 09:58:31 -0700 | [diff] [blame] | 33 | #include "table_storage.h" |
Joel Fernandes | 1086952 | 2018-02-01 21:23:24 -0500 | [diff] [blame] | 34 | #include "arch_helper.h" |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 35 | |
Brenden Blanco | 32109bf | 2015-07-28 12:29:36 -0700 | [diff] [blame] | 36 | #include "libbpf.h" |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 37 | |
| 38 | namespace ebpf { |
Brenden Blanco | b711d45 | 2015-07-01 15:23:18 -0700 | [diff] [blame] | 39 | |
Brenden Blanco | 977091e | 2016-05-05 11:37:59 -0700 | [diff] [blame] | 40 | constexpr int MAX_CALLING_CONV_REGS = 6; |
Brenden Blanco | b711d45 | 2015-07-01 15:23:18 -0700 | [diff] [blame] | 41 | const char *calling_conv_regs_x86[] = { |
| 42 | "di", "si", "dx", "cx", "r8", "r9" |
| 43 | }; |
Naveen N. Rao | 0006ad1 | 2016-04-29 16:42:58 +0530 | [diff] [blame] | 44 | const char *calling_conv_regs_ppc[] = {"gpr[3]", "gpr[4]", "gpr[5]", |
| 45 | "gpr[6]", "gpr[7]", "gpr[8]"}; |
Zvonko Kosic | 98121a3 | 2017-03-07 07:30:25 +0100 | [diff] [blame] | 46 | |
| 47 | const char *calling_conv_regs_s390x[] = {"gprs[2]", "gprs[3]", "gprs[4]", |
| 48 | "gprs[5]", "gprs[6]" }; |
| 49 | |
Zhiyi Sun | 8e434b7 | 2016-12-06 16:21:37 +0800 | [diff] [blame] | 50 | const char *calling_conv_regs_arm64[] = {"regs[0]", "regs[1]", "regs[2]", |
| 51 | "regs[3]", "regs[4]", "regs[5]"}; |
Joel Fernandes | 1086952 | 2018-02-01 21:23:24 -0500 | [diff] [blame] | 52 | |
| 53 | void *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 | |
| 75 | const 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 Blanco | b711d45 | 2015-07-01 15:23:18 -0700 | [diff] [blame] | 81 | |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 82 | using std::map; |
Brenden Blanco | faea8c8 | 2017-03-29 09:58:31 -0700 | [diff] [blame] | 83 | using std::move; |
Brenden Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 84 | using std::set; |
Paul Chaignon | 471f1ea | 2018-05-11 09:36:37 +0200 | [diff] [blame] | 85 | using std::tuple; |
| 86 | using std::make_tuple; |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 87 | using std::string; |
Brenden Blanco | 2833386 | 2015-05-28 18:19:38 -0700 | [diff] [blame] | 88 | using std::to_string; |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 89 | using std::unique_ptr; |
Brenden Blanco | 561dafc | 2015-06-29 11:09:00 -0700 | [diff] [blame] | 90 | using std::vector; |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 91 | using namespace clang; |
| 92 | |
Brenden Blanco | 74adb73 | 2015-09-29 13:44:19 -0700 | [diff] [blame] | 93 | class ProbeChecker : public RecursiveASTVisitor<ProbeChecker> { |
Brenden Blanco | 70fa0a1 | 2015-09-15 15:46:26 -0700 | [diff] [blame] | 94 | public: |
Paul Chaignon | 471f1ea | 2018-05-11 09:36:37 +0200 | [diff] [blame] | 95 | explicit ProbeChecker(Expr *arg, const set<tuple<Decl *, int>> &ptregs, |
| 96 | bool track_helpers, bool is_assign) |
Paul Chaignon | ad2d0d9 | 2018-05-08 22:02:55 +0200 | [diff] [blame] | 97 | : needs_probe_(false), is_transitive_(false), ptregs_(ptregs), |
Paul Chaignon | 471f1ea | 2018-05-11 09:36:37 +0200 | [diff] [blame] | 98 | track_helpers_(track_helpers), nb_derefs_(0), is_assign_(is_assign) { |
Brenden Blanco | c48ab4b | 2015-10-01 11:18:07 -0700 | [diff] [blame] | 99 | if (arg) { |
Brenden Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 100 | TraverseStmt(arg); |
Brenden Blanco | c48ab4b | 2015-10-01 11:18:07 -0700 | [diff] [blame] | 101 | if (arg->getType()->isPointerType()) |
| 102 | is_transitive_ = needs_probe_; |
| 103 | } |
Brenden Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 104 | } |
Paul Chaignon | 471f1ea | 2018-05-11 09:36:37 +0200 | [diff] [blame] | 105 | explicit ProbeChecker(Expr *arg, const set<tuple<Decl *, int>> &ptregs, |
| 106 | bool is_transitive) |
| 107 | : ProbeChecker(arg, ptregs, is_transitive, false) {} |
Brenden Blanco | 74adb73 | 2015-09-29 13:44:19 -0700 | [diff] [blame] | 108 | bool VisitCallExpr(CallExpr *E) { |
Brenden Blanco | c48ab4b | 2015-10-01 11:18:07 -0700 | [diff] [blame] | 109 | needs_probe_ = false; |
Paul Chaignon | fe779f3 | 2018-06-14 03:51:55 +0200 | [diff] [blame] | 110 | |
| 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 Chaignon | ad2d0d9 | 2018-05-08 22:02:55 +0200 | [diff] [blame] | 127 | if (!track_helpers_) |
| 128 | return false; |
| 129 | if (VarDecl *V = dyn_cast<VarDecl>(E->getCalleeDecl())) |
Paul Chaignon | 719e100 | 2017-08-06 14:33:20 +0200 | [diff] [blame] | 130 | needs_probe_ = V->getName() == "bpf_get_current_task"; |
Brenden Blanco | 74adb73 | 2015-09-29 13:44:19 -0700 | [diff] [blame] | 131 | return false; |
| 132 | } |
Paul Chaignon | c2b87ba | 2018-05-05 10:39:39 +0200 | [diff] [blame] | 133 | bool VisitMemberExpr(MemberExpr *M) { |
Paul Chaignon | 471f1ea | 2018-05-11 09:36:37 +0200 | [diff] [blame] | 134 | tuple<Decl *, int> pt = make_tuple(M->getMemberDecl(), nb_derefs_); |
| 135 | if (ptregs_.find(pt) != ptregs_.end()) { |
Paul Chaignon | c2b87ba | 2018-05-05 10:39:39 +0200 | [diff] [blame] | 136 | needs_probe_ = true; |
| 137 | return false; |
| 138 | } |
| 139 | return true; |
| 140 | } |
Paul Chaignon | 471f1ea | 2018-05-11 09:36:37 +0200 | [diff] [blame] | 141 | 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 Blanco | 74adb73 | 2015-09-29 13:44:19 -0700 | [diff] [blame] | 148 | bool VisitDeclRefExpr(DeclRefExpr *E) { |
Paul Chaignon | 471f1ea | 2018-05-11 09:36:37 +0200 | [diff] [blame] | 149 | 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 Blanco | 70fa0a1 | 2015-09-15 15:46:26 -0700 | [diff] [blame] | 164 | return true; |
| 165 | } |
Brenden Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 166 | bool needs_probe() const { return needs_probe_; } |
Brenden Blanco | c48ab4b | 2015-10-01 11:18:07 -0700 | [diff] [blame] | 167 | bool is_transitive() const { return is_transitive_; } |
Paul Chaignon | 471f1ea | 2018-05-11 09:36:37 +0200 | [diff] [blame] | 168 | int get_nb_derefs() const { return nb_derefs_; } |
Brenden Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 169 | private: |
| 170 | bool needs_probe_; |
Brenden Blanco | c48ab4b | 2015-10-01 11:18:07 -0700 | [diff] [blame] | 171 | bool is_transitive_; |
Paul Chaignon | 471f1ea | 2018-05-11 09:36:37 +0200 | [diff] [blame] | 172 | const set<tuple<Decl *, int>> &ptregs_; |
Paul Chaignon | ad2d0d9 | 2018-05-08 22:02:55 +0200 | [diff] [blame] | 173 | bool track_helpers_; |
Paul Chaignon | 471f1ea | 2018-05-11 09:36:37 +0200 | [diff] [blame] | 174 | // 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 Blanco | 70fa0a1 | 2015-09-15 15:46:26 -0700 | [diff] [blame] | 178 | }; |
| 179 | |
| 180 | // Visit a piece of the AST and mark it as needing probe reads |
Brenden Blanco | 74adb73 | 2015-09-29 13:44:19 -0700 | [diff] [blame] | 181 | class ProbeSetter : public RecursiveASTVisitor<ProbeSetter> { |
Brenden Blanco | 70fa0a1 | 2015-09-15 15:46:26 -0700 | [diff] [blame] | 182 | public: |
Paul Chaignon | 471f1ea | 2018-05-11 09:36:37 +0200 | [diff] [blame] | 183 | explicit ProbeSetter(set<tuple<Decl *, int>> *ptregs, int nb_addrof) |
| 184 | : ptregs_(ptregs), nb_derefs_(-nb_addrof) {} |
Brenden Blanco | 74adb73 | 2015-09-29 13:44:19 -0700 | [diff] [blame] | 185 | bool VisitDeclRefExpr(DeclRefExpr *E) { |
Paul Chaignon | 471f1ea | 2018-05-11 09:36:37 +0200 | [diff] [blame] | 186 | 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 Blanco | 70fa0a1 | 2015-09-15 15:46:26 -0700 | [diff] [blame] | 195 | return true; |
| 196 | } |
Paul Chaignon | c2b87ba | 2018-05-05 10:39:39 +0200 | [diff] [blame] | 197 | bool VisitMemberExpr(MemberExpr *M) { |
Paul Chaignon | 471f1ea | 2018-05-11 09:36:37 +0200 | [diff] [blame] | 198 | tuple<Decl *, int> pt = make_tuple(M->getMemberDecl(), nb_derefs_); |
| 199 | ptregs_->insert(pt); |
Paul Chaignon | c2b87ba | 2018-05-05 10:39:39 +0200 | [diff] [blame] | 200 | return false; |
| 201 | } |
Brenden Blanco | 70fa0a1 | 2015-09-15 15:46:26 -0700 | [diff] [blame] | 202 | private: |
Paul Chaignon | 471f1ea | 2018-05-11 09:36:37 +0200 | [diff] [blame] | 203 | set<tuple<Decl *, int>> *ptregs_; |
| 204 | // Nb of dereferences we go through before getting to the actual variable. |
| 205 | int nb_derefs_; |
Brenden Blanco | 70fa0a1 | 2015-09-15 15:46:26 -0700 | [diff] [blame] | 206 | }; |
| 207 | |
Paul Chaignon | e67cb56 | 2017-10-26 08:43:13 +0200 | [diff] [blame] | 208 | MapVisitor::MapVisitor(set<Decl *> &m) : m_(m) {} |
Paul Chaignon | eae0acf | 2017-08-05 23:04:41 +0200 | [diff] [blame] | 209 | |
Paul Chaignon | e67cb56 | 2017-10-26 08:43:13 +0200 | [diff] [blame] | 210 | bool 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 Chaignon | 471f1ea | 2018-05-11 09:36:37 +0200 | [diff] [blame] | 219 | ProbeChecker checker = ProbeChecker(Call->getArg(1), ptregs_, true, |
| 220 | true); |
| 221 | if (checker.needs_probe()) |
Paul Chaignon | e67cb56 | 2017-10-26 08:43:13 +0200 | [diff] [blame] | 222 | m_.insert(Ref->getDecl()); |
Paul Chaignon | eae0acf | 2017-08-05 23:04:41 +0200 | [diff] [blame] | 223 | } |
| 224 | } |
| 225 | } |
Paul Chaignon | eae0acf | 2017-08-05 23:04:41 +0200 | [diff] [blame] | 226 | } |
Paul Chaignon | e67cb56 | 2017-10-26 08:43:13 +0200 | [diff] [blame] | 227 | return true; |
| 228 | } |
Paul Chaignon | eae0acf | 2017-08-05 23:04:41 +0200 | [diff] [blame] | 229 | |
Paul Chaignon | 471f1ea | 2018-05-11 09:36:37 +0200 | [diff] [blame] | 230 | ProbeVisitor::ProbeVisitor(ASTContext &C, Rewriter &rewriter, |
| 231 | set<Decl *> &m, bool track_helpers) : |
yonghong-song | 2458196 | 2018-06-17 15:55:12 -0700 | [diff] [blame^] | 232 | C(C), rewriter_(rewriter), m_(m), track_helpers_(track_helpers), |
| 233 | addrof_stmt_(nullptr), is_addrof_(false) {} |
Brenden Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 234 | |
Paul Chaignon | 8d7e26d | 2018-05-31 12:47:44 +0200 | [diff] [blame] | 235 | bool ProbeVisitor::assignsExtPtr(Expr *E, int *nbAddrOf) { |
| 236 | if (IsContextMemberExpr(E)) { |
| 237 | *nbAddrOf = 0; |
| 238 | return true; |
| 239 | } |
| 240 | |
Paul Chaignon | fe779f3 | 2018-06-14 03:51:55 +0200 | [diff] [blame] | 241 | /* 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 Chaignon | 8d7e26d | 2018-05-31 12:47:44 +0200 | [diff] [blame] | 247 | 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 Chaignon | fe779f3 | 2018-06-14 03:51:55 +0200 | [diff] [blame] | 258 | if (E->IgnoreParenCasts()->getStmtClass() == Stmt::CallExprClass) { |
| 259 | CallExpr *Call = dyn_cast<CallExpr>(E->IgnoreParenCasts()); |
Paul Chaignon | 8d7e26d | 2018-05-31 12:47:44 +0200 | [diff] [blame] | 260 | 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 Song | 20fb64c | 2018-06-02 00:28:38 -0700 | [diff] [blame] | 269 | // Retrieved an ext. pointer from a map, mark LHS as ext. pointer. |
Paul Chaignon | 8d7e26d | 2018-05-31 12:47:44 +0200 | [diff] [blame] | 270 | // 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 Chaignon | 471f1ea | 2018-05-11 09:36:37 +0200 | [diff] [blame] | 285 | bool ProbeVisitor::VisitVarDecl(VarDecl *D) { |
| 286 | if (Expr *E = D->getInit()) { |
Paul Chaignon | 8d7e26d | 2018-05-31 12:47:44 +0200 | [diff] [blame] | 287 | 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 Chaignon | 471f1ea | 2018-05-11 09:36:37 +0200 | [diff] [blame] | 291 | set_ptreg(pt); |
Paul Chaignon | b66a9c9 | 2018-05-01 22:10:28 +0200 | [diff] [blame] | 292 | } |
Brenden Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 293 | } |
| 294 | return true; |
| 295 | } |
Yonghong Song | 20fb64c | 2018-06-02 00:28:38 -0700 | [diff] [blame] | 296 | |
Paul Chaignon | eebd485 | 2018-06-13 03:55:52 +0200 | [diff] [blame] | 297 | bool ProbeVisitor::TraverseStmt(Stmt *S) { |
| 298 | if (whitelist_.find(S) != whitelist_.end()) |
| 299 | return true; |
yonghong-song | 2458196 | 2018-06-17 15:55:12 -0700 | [diff] [blame^] | 300 | auto ret = RecursiveASTVisitor<ProbeVisitor>::TraverseStmt(S); |
| 301 | if (addrof_stmt_ == S) { |
| 302 | addrof_stmt_ = nullptr; |
| 303 | is_addrof_ = false; |
| 304 | } |
| 305 | return ret; |
Paul Chaignon | eebd485 | 2018-06-13 03:55:52 +0200 | [diff] [blame] | 306 | } |
| 307 | |
Brenden Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 308 | bool ProbeVisitor::VisitCallExpr(CallExpr *Call) { |
Yonghong Song | 20fb64c | 2018-06-02 00:28:38 -0700 | [diff] [blame] | 309 | // 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 Chaignon | f86f7e8 | 2018-06-14 02:20:03 +0200 | [diff] [blame] | 313 | whitelist_.insert(E); |
Yonghong Song | 20fb64c | 2018-06-02 00:28:38 -0700 | [diff] [blame] | 314 | return true; |
| 315 | } |
| 316 | } |
| 317 | |
Brenden Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 318 | if (FunctionDecl *F = dyn_cast<FunctionDecl>(Call->getCalleeDecl())) { |
| 319 | if (F->hasBody()) { |
| 320 | unsigned i = 0; |
| 321 | for (auto arg : Call->arguments()) { |
Paul Chaignon | 471f1ea | 2018-05-11 09:36:37 +0200 | [diff] [blame] | 322 | 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 Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 329 | ++i; |
| 330 | } |
| 331 | if (fn_visited_.find(F) == fn_visited_.end()) { |
| 332 | fn_visited_.insert(F); |
Paul Chaignon | fe779f3 | 2018-06-14 03:51:55 +0200 | [diff] [blame] | 333 | /* 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 Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 337 | TraverseDecl(F); |
Paul Chaignon | fe779f3 | 2018-06-14 03:51:55 +0200 | [diff] [blame] | 338 | 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 Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 344 | } |
| 345 | } |
| 346 | } |
| 347 | return true; |
| 348 | } |
Paul Chaignon | fe779f3 | 2018-06-14 03:51:55 +0200 | [diff] [blame] | 349 | bool 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 Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 376 | bool ProbeVisitor::VisitBinaryOperator(BinaryOperator *E) { |
| 377 | if (!E->isAssignmentOp()) |
| 378 | return true; |
Paul Chaignon | eae0acf | 2017-08-05 23:04:41 +0200 | [diff] [blame] | 379 | |
Paul Chaignon | 8d7e26d | 2018-05-31 12:47:44 +0200 | [diff] [blame] | 380 | // copy probe attribute from RHS to LHS if present |
| 381 | int nbAddrOf; |
| 382 | if (assignsExtPtr(E->getRHS(), &nbAddrOf)) { |
| 383 | ProbeSetter setter(&ptregs_, nbAddrOf); |
Paul Chaignon | b66a9c9 | 2018-05-01 22:10:28 +0200 | [diff] [blame] | 384 | setter.TraverseStmt(E->getLHS()); |
Brenden Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 385 | } |
| 386 | return true; |
| 387 | } |
Brenden Blanco | ea5023a | 2015-09-24 06:52:08 -0700 | [diff] [blame] | 388 | bool ProbeVisitor::VisitUnaryOperator(UnaryOperator *E) { |
yonghong-song | 2458196 | 2018-06-17 15:55:12 -0700 | [diff] [blame^] | 389 | if (E->getOpcode() == UO_AddrOf) { |
| 390 | addrof_stmt_ = E; |
| 391 | is_addrof_ = true; |
| 392 | } |
Paul Chaignon | 4c6ecb4 | 2017-02-23 10:03:58 +0100 | [diff] [blame] | 393 | if (E->getOpcode() != UO_Deref) |
Brenden Blanco | ea5023a | 2015-09-24 06:52:08 -0700 | [diff] [blame] | 394 | return true; |
| 395 | if (memb_visited_.find(E) != memb_visited_.end()) |
| 396 | return true; |
Paul Chaignon | 471f1ea | 2018-05-11 09:36:37 +0200 | [diff] [blame] | 397 | Expr *sub = E->getSubExpr(); |
| 398 | if (!ProbeChecker(sub, ptregs_, track_helpers_).needs_probe()) |
Brenden Blanco | ea5023a | 2015-09-24 06:52:08 -0700 | [diff] [blame] | 399 | return true; |
| 400 | memb_visited_.insert(E); |
Paul Chaignon | fa7508d | 2018-06-17 17:47:18 +0200 | [diff] [blame] | 401 | 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 Blanco | ea5023a | 2015-09-24 06:52:08 -0700 | [diff] [blame] | 407 | return true; |
| 408 | } |
yonghong-song | 2458196 | 2018-06-17 15:55:12 -0700 | [diff] [blame^] | 409 | bool 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 Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 416 | bool ProbeVisitor::VisitMemberExpr(MemberExpr *E) { |
| 417 | if (memb_visited_.find(E) != memb_visited_.end()) return true; |
| 418 | |
Brenden Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 419 | Expr *base; |
Yonghong Song | 94d15bc | 2017-11-08 20:38:30 -0800 | [diff] [blame] | 420 | SourceLocation rhs_start, member; |
Brenden Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 421 | 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 Song | 94d15bc | 2017-11-08 20:38:30 -0800 | [diff] [blame] | 426 | member = M->getMemberLoc(); |
Brenden Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 427 | if (M->isArrow()) { |
| 428 | found = true; |
| 429 | break; |
| 430 | } |
| 431 | } |
| 432 | if (!found) |
| 433 | return true; |
Yonghong Song | 94d15bc | 2017-11-08 20:38:30 -0800 | [diff] [blame] | 434 | if (member.isInvalid()) { |
| 435 | error(base->getLocEnd(), "internal error: MemberLoc is invalid while preparing probe rewrite"); |
Brenden Blanco | 545008a | 2016-08-18 14:33:29 -0700 | [diff] [blame] | 436 | return false; |
| 437 | } |
Paul Chaignon | c2b87ba | 2018-05-05 10:39:39 +0200 | [diff] [blame] | 438 | |
yonghong-song | 66d2863 | 2018-06-14 07:11:42 -0700 | [diff] [blame] | 439 | if (!rewriter_.isRewritable(E->getLocStart())) |
Paul Chaignon | a9f96c0 | 2018-06-15 00:27:08 +0200 | [diff] [blame] | 440 | return true; |
yonghong-song | 66d2863 | 2018-06-14 07:11:42 -0700 | [diff] [blame] | 441 | |
yonghong-song | 2458196 | 2018-06-17 15:55:12 -0700 | [diff] [blame^] | 442 | // 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 Chaignon | fe779f3 | 2018-06-14 03:51:55 +0200 | [diff] [blame] | 449 | /* 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 Chaignon | c2b87ba | 2018-05-05 10:39:39 +0200 | [diff] [blame] | 458 | // Checks to see if the expression references something that needs to be run |
| 459 | // through bpf_probe_read. |
Paul Chaignon | ad2d0d9 | 2018-05-08 22:02:55 +0200 | [diff] [blame] | 460 | if (!ProbeChecker(base, ptregs_, track_helpers_).needs_probe()) |
Paul Chaignon | c2b87ba | 2018-05-05 10:39:39 +0200 | [diff] [blame] | 461 | return true; |
| 462 | |
Paul Chaignon | c5c3b99 | 2017-02-26 12:22:03 +0100 | [diff] [blame] | 463 | string rhs = rewriter_.getRewrittenText(expansionRange(SourceRange(rhs_start, E->getLocEnd()))); |
Brenden Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 464 | string base_type = base->getType()->getPointeeType().getAsString(); |
| 465 | string pre, post; |
Yonghong Song | 1ab5f66 | 2018-01-24 16:42:53 -0800 | [diff] [blame] | 466 | pre = "({ typeof(" + E->getType().getAsString() + ") _val; __builtin_memset(&_val, 0, sizeof(_val));"; |
Yonghong Song | 94d15bc | 2017-11-08 20:38:30 -0800 | [diff] [blame] | 467 | pre += " bpf_probe_read(&_val, sizeof(_val), (u64)&"; |
| 468 | post = rhs + "); _val; })"; |
Paul Chaignon | fa7508d | 2018-06-17 17:47:18 +0200 | [diff] [blame] | 469 | rewriter_.InsertText(expansionLoc(E->getLocStart()), pre); |
Yonghong Song | 94d15bc | 2017-11-08 20:38:30 -0800 | [diff] [blame] | 470 | rewriter_.ReplaceText(expansionRange(SourceRange(member, E->getLocEnd())), post); |
Brenden Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 471 | return true; |
| 472 | } |
| 473 | |
Paul Chaignon | b66a9c9 | 2018-05-01 22:10:28 +0200 | [diff] [blame] | 474 | bool ProbeVisitor::IsContextMemberExpr(Expr *E) { |
| 475 | if (!E->getType()->isPointerType()) |
| 476 | return false; |
| 477 | |
Paul Chaignon | b66a9c9 | 2018-05-01 22:10:28 +0200 | [diff] [blame] | 478 | Expr *base; |
Paul Chaignon | a9f96c0 | 2018-06-15 00:27:08 +0200 | [diff] [blame] | 479 | SourceLocation member; |
Paul Chaignon | b66a9c9 | 2018-05-01 22:10:28 +0200 | [diff] [blame] | 480 | bool found = false; |
| 481 | MemberExpr *M; |
Paul Chaignon | a9f96c0 | 2018-06-15 00:27:08 +0200 | [diff] [blame] | 482 | 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 Chaignon | b66a9c9 | 2018-05-01 22:10:28 +0200 | [diff] [blame] | 496 | } |
| 497 | } |
| 498 | if (!found) { |
| 499 | return false; |
| 500 | } |
| 501 | if (member.isInvalid()) { |
| 502 | return false; |
| 503 | } |
| 504 | |
Paul Chaignon | a9f96c0 | 2018-06-15 00:27:08 +0200 | [diff] [blame] | 505 | if (DeclRefExpr *base_expr = dyn_cast<DeclRefExpr>(base)) { |
Paul Chaignon | b66a9c9 | 2018-05-01 22:10:28 +0200 | [diff] [blame] | 506 | if (base_expr->getDecl() == ctx_) { |
| 507 | return true; |
| 508 | } |
| 509 | } |
| 510 | return false; |
| 511 | } |
| 512 | |
Paul Chaignon | c5c3b99 | 2017-02-26 12:22:03 +0100 | [diff] [blame] | 513 | SourceRange |
| 514 | ProbeVisitor::expansionRange(SourceRange range) { |
Yonghong Song | 806627e | 2018-05-02 10:32:31 -0700 | [diff] [blame] | 515 | #if LLVM_MAJOR_VERSION >= 7 |
| 516 | return rewriter_.getSourceMgr().getExpansionRange(range).getAsRange(); |
| 517 | #else |
Paul Chaignon | c5c3b99 | 2017-02-26 12:22:03 +0100 | [diff] [blame] | 518 | return rewriter_.getSourceMgr().getExpansionRange(range); |
Yonghong Song | 806627e | 2018-05-02 10:32:31 -0700 | [diff] [blame] | 519 | #endif |
Paul Chaignon | c5c3b99 | 2017-02-26 12:22:03 +0100 | [diff] [blame] | 520 | } |
| 521 | |
Paul Chaignon | fa7508d | 2018-06-17 17:47:18 +0200 | [diff] [blame] | 522 | SourceLocation |
| 523 | ProbeVisitor::expansionLoc(SourceLocation loc) { |
| 524 | return rewriter_.getSourceMgr().getExpansionLoc(loc); |
| 525 | } |
| 526 | |
Brenden Blanco | 545008a | 2016-08-18 14:33:29 -0700 | [diff] [blame] | 527 | template <unsigned N> |
| 528 | DiagnosticBuilder 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 Blanco | faea8c8 | 2017-03-29 09:58:31 -0700 | [diff] [blame] | 533 | BTypeVisitor::BTypeVisitor(ASTContext &C, BFrontendAction &fe) |
| 534 | : C(C), diag_(C.getDiagnostics()), fe_(fe), rewriter_(fe.rewriter()), out_(llvm::errs()) {} |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 535 | |
yonghong-song | 2da3426 | 2018-06-13 06:12:22 -0700 | [diff] [blame] | 536 | void 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 | |
| 555 | void 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 | |
| 582 | void BTypeVisitor::rewriteFuncParam(FunctionDecl *D) { |
Joel Fernandes | 1086952 | 2018-02-01 21:23:24 -0500 | [diff] [blame] | 583 | const char **calling_conv_regs = get_call_conv(); |
| 584 | |
yonghong-song | 2da3426 | 2018-06-13 06:12:22 -0700 | [diff] [blame] | 585 | 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 | |
| 612 | bool BTypeVisitor::VisitFunctionDecl(FunctionDecl *D) { |
Brenden Blanco | 004f005 | 2015-06-11 14:31:31 -0700 | [diff] [blame] | 613 | // put each non-static non-inline function decl in its own section, to be |
| 614 | // extracted by the MemoryManager |
Sasha Goldshtein | fab68e3 | 2016-07-05 09:34:56 -0700 | [diff] [blame] | 615 | auto real_start_loc = rewriter_.getSourceMgr().getFileLoc(D->getLocStart()); |
Yonghong Song | 6fc8d15 | 2017-11-03 15:04:24 -0700 | [diff] [blame] | 616 | if (fe_.is_rewritable_ext_func(D)) { |
Vicent Marti | 4ea4af4 | 2016-05-04 13:01:55 +0200 | [diff] [blame] | 617 | current_fn_ = D->getName(); |
Alexei Starovoitov | 4f47e3b | 2017-09-06 19:57:21 -0700 | [diff] [blame] | 618 | 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 Blanco | 32109bf | 2015-07-28 12:29:36 -0700 | [diff] [blame] | 621 | string attr = string("__attribute__((section(\"") + BPF_FN_PREFIX + D->getName().str() + "\")))\n"; |
Sasha Goldshtein | fab68e3 | 2016-07-05 09:34:56 -0700 | [diff] [blame] | 622 | rewriter_.InsertText(real_start_loc, attr); |
Brenden Blanco | 977091e | 2016-05-05 11:37:59 -0700 | [diff] [blame] | 623 | 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-song | 2da3426 | 2018-06-13 06:12:22 -0700 | [diff] [blame] | 628 | |
Brenden Blanco | 561dafc | 2015-06-29 11:09:00 -0700 | [diff] [blame] | 629 | fn_args_.clear(); |
Brenden Blanco | 5256154 | 2016-07-07 17:56:03 -0700 | [diff] [blame] | 630 | for (auto arg_it = D->param_begin(); arg_it != D->param_end(); arg_it++) { |
yonghong-song | 2da3426 | 2018-06-13 06:12:22 -0700 | [diff] [blame] | 631 | auto *arg = *arg_it; |
Brenden Blanco | 561dafc | 2015-06-29 11:09:00 -0700 | [diff] [blame] | 632 | if (arg->getName() == "") { |
Brenden Blanco | c98ffd6 | 2016-04-09 18:41:42 -0700 | [diff] [blame] | 633 | error(arg->getLocEnd(), "arguments to BPF program definition must be named"); |
Brenden Blanco | 561dafc | 2015-06-29 11:09:00 -0700 | [diff] [blame] | 634 | return false; |
| 635 | } |
Brenden Blanco | b711d45 | 2015-07-01 15:23:18 -0700 | [diff] [blame] | 636 | fn_args_.push_back(arg); |
Brenden Blanco | 561dafc | 2015-06-29 11:09:00 -0700 | [diff] [blame] | 637 | } |
yonghong-song | 2da3426 | 2018-06-13 06:12:22 -0700 | [diff] [blame] | 638 | rewriteFuncParam(D); |
Brenden Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 639 | } else if (D->hasBody() && |
Sasha Goldshtein | fab68e3 | 2016-07-05 09:34:56 -0700 | [diff] [blame] | 640 | rewriter_.getSourceMgr().getFileID(real_start_loc) |
Brenden Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 641 | == rewriter_.getSourceMgr().getMainFileID()) { |
| 642 | // rewritable functions that are static should be always treated as helper |
Sasha Goldshtein | fab68e3 | 2016-07-05 09:34:56 -0700 | [diff] [blame] | 643 | rewriter_.InsertText(real_start_loc, "__attribute__((always_inline))\n"); |
Brenden Blanco | 004f005 | 2015-06-11 14:31:31 -0700 | [diff] [blame] | 644 | } |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 645 | return true; |
| 646 | } |
| 647 | |
Brenden Blanco | 561dafc | 2015-06-29 11:09:00 -0700 | [diff] [blame] | 648 | // 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. |
| 651 | bool 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 Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 660 | // convert calls of the type: |
| 661 | // table.foo(&key) |
| 662 | // to: |
| 663 | // bpf_table_foo_elem(bpf_pseudo_fd(table), &key [,&leaf]) |
| 664 | bool 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 Blanco | 2833386 | 2015-05-28 18:19:38 -0700 | [diff] [blame] | 673 | |
Paul Chaignon | c5c3b99 | 2017-02-26 12:22:03 +0100 | [diff] [blame] | 674 | string args = rewriter_.getRewrittenText(expansionRange(SourceRange(Call->getArg(0)->getLocStart(), |
| 675 | Call->getArg(Call->getNumArgs() - 1)->getLocEnd()))); |
Brenden Blanco | 2833386 | 2015-05-28 18:19:38 -0700 | [diff] [blame] | 676 | |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 677 | // find the table fd, which was opened at declaration time |
Brenden Blanco | faea8c8 | 2017-03-29 09:58:31 -0700 | [diff] [blame] | 678 | 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 Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 686 | } |
Brenden Blanco | faea8c8 | 2017-03-29 09:58:31 -0700 | [diff] [blame] | 687 | string fd = to_string(desc->second.fd); |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 688 | string prefix, suffix; |
Brenden Blanco | 2833386 | 2015-05-28 18:19:38 -0700 | [diff] [blame] | 689 | string txt; |
Brenden Blanco | ef6bb80 | 2016-03-04 15:13:13 -0800 | [diff] [blame] | 690 | auto rewrite_start = Call->getLocStart(); |
| 691 | auto rewrite_end = Call->getLocEnd(); |
Brenden Blanco | 2833386 | 2015-05-28 18:19:38 -0700 | [diff] [blame] | 692 | if (memb_name == "lookup_or_init") { |
Brenden Blanco | 2833386 | 2015-05-28 18:19:38 -0700 | [diff] [blame] | 693 | string name = Ref->getDecl()->getName(); |
Paul Chaignon | c5c3b99 | 2017-02-26 12:22:03 +0100 | [diff] [blame] | 694 | string arg0 = rewriter_.getRewrittenText(expansionRange(Call->getArg(0)->getSourceRange())); |
| 695 | string arg1 = rewriter_.getRewrittenText(expansionRange(Call->getArg(1)->getSourceRange())); |
Brenden Blanco | 2833386 | 2015-05-28 18:19:38 -0700 | [diff] [blame] | 696 | 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 Chaignon | 6ceb329 | 2017-04-01 18:23:58 +0200 | [diff] [blame] | 700 | txt += " " + update + ", " + arg0 + ", " + arg1 + ", BPF_NOEXIST);"; |
Brenden Blanco | 2833386 | 2015-05-28 18:19:38 -0700 | [diff] [blame] | 701 | txt += " leaf = " + lookup + ", " + arg0 + ");"; |
Brenden Blanco | d23d699 | 2015-05-28 18:40:09 -0700 | [diff] [blame] | 702 | txt += " if (!leaf) return 0;"; |
Brenden Blanco | 2833386 | 2015-05-28 18:19:38 -0700 | [diff] [blame] | 703 | txt += "}"; |
| 704 | txt += "leaf;})"; |
Brenden Blanco | f0b15c4 | 2015-09-23 21:36:05 -0700 | [diff] [blame] | 705 | } else if (memb_name == "increment") { |
| 706 | string name = Ref->getDecl()->getName(); |
Paul Chaignon | c5c3b99 | 2017-02-26 12:22:03 +0100 | [diff] [blame] | 707 | string arg0 = rewriter_.getRewrittenText(expansionRange(Call->getArg(0)->getSourceRange())); |
Brenden Blanco | f0b15c4 | 2015-09-23 21:36:05 -0700 | [diff] [blame] | 708 | 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 Blanco | f0b15c4 | 2015-09-23 21:36:05 -0700 | [diff] [blame] | 711 | txt += "typeof(" + name + ".leaf) *_leaf = " + lookup + ", &_key); "; |
Brenden Blanco | 23fc589 | 2017-08-23 15:15:32 -0700 | [diff] [blame] | 712 | txt += "if (_leaf) (*_leaf)++; "; |
| 713 | if (desc->second.type == BPF_MAP_TYPE_HASH) { |
Yonghong Song | 1ab5f66 | 2018-01-24 16:42:53 -0800 | [diff] [blame] | 714 | txt += "else { typeof(" + name + ".leaf) _zleaf; __builtin_memset(&_zleaf, 0, sizeof(_zleaf)); "; |
Brenden Blanco | 23fc589 | 2017-08-23 15:15:32 -0700 | [diff] [blame] | 715 | txt += "_zleaf++; "; |
| 716 | txt += update + ", &_key, &_zleaf, BPF_NOEXIST); } "; |
| 717 | } |
| 718 | txt += "})"; |
Brenden Blanco | aeca6bf | 2015-11-06 13:03:05 -0800 | [diff] [blame] | 719 | } else if (memb_name == "perf_submit") { |
Brenden Blanco | d0daf6a | 2015-11-05 23:31:22 -0800 | [diff] [blame] | 720 | string name = Ref->getDecl()->getName(); |
Paul Chaignon | c5c3b99 | 2017-02-26 12:22:03 +0100 | [diff] [blame] | 721 | 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 Blanco | aeca6bf | 2015-11-06 13:03:05 -0800 | [diff] [blame] | 724 | txt = "bpf_perf_event_output(" + arg0 + ", bpf_pseudo_fd(1, " + fd + ")"; |
Teng Qin | 204df9e | 2017-05-23 11:57:44 -0700 | [diff] [blame] | 725 | txt += ", CUR_CPU_IDENTIFIER, " + args_other + ")"; |
Martin KaFai Lau | bdad384 | 2016-08-19 15:34:18 -0700 | [diff] [blame] | 726 | } else if (memb_name == "perf_submit_skb") { |
Paul Chaignon | c5c3b99 | 2017-02-26 12:22:03 +0100 | [diff] [blame] | 727 | 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 Lau | bdad384 | 2016-08-19 15:34:18 -0700 | [diff] [blame] | 731 | 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 Blanco | ad0e883 | 2016-03-04 13:58:44 -0800 | [diff] [blame] | 737 | } else if (memb_name == "get_stackid") { |
Brenden Blanco | faea8c8 | 2017-03-29 09:58:31 -0700 | [diff] [blame] | 738 | if (desc->second.type == BPF_MAP_TYPE_STACK_TRACE) { |
| 739 | string arg0 = |
| 740 | rewriter_.getRewrittenText(expansionRange(Call->getArg(0)->getSourceRange())); |
Yonghong Song | d049252 | 2017-10-17 22:46:02 -0700 | [diff] [blame] | 741 | txt = "bcc_get_stackid("; |
Brenden Blanco | faea8c8 | 2017-03-29 09:58:31 -0700 | [diff] [blame] | 742 | txt += "bpf_pseudo_fd(1, " + fd + "), " + arg0; |
| 743 | rewrite_end = Call->getArg(0)->getLocEnd(); |
Brenden Blanco | ad0e883 | 2016-03-04 13:58:44 -0800 | [diff] [blame] | 744 | } else { |
Brenden Blanco | c98ffd6 | 2016-04-09 18:41:42 -0700 | [diff] [blame] | 745 | error(Call->getLocStart(), "get_stackid only available on stacktrace maps"); |
Brenden Blanco | ad0e883 | 2016-03-04 13:58:44 -0800 | [diff] [blame] | 746 | return false; |
| 747 | } |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 748 | } else { |
Brenden Blanco | 2833386 | 2015-05-28 18:19:38 -0700 | [diff] [blame] | 749 | if (memb_name == "lookup") { |
Brenden Blanco | ad0e883 | 2016-03-04 13:58:44 -0800 | [diff] [blame] | 750 | prefix = "bpf_map_lookup_elem"; |
| 751 | suffix = ")"; |
Brenden Blanco | 2833386 | 2015-05-28 18:19:38 -0700 | [diff] [blame] | 752 | } else if (memb_name == "update") { |
| 753 | prefix = "bpf_map_update_elem"; |
Paul Chaignon | 6ceb329 | 2017-04-01 18:23:58 +0200 | [diff] [blame] | 754 | suffix = ", BPF_ANY)"; |
| 755 | } else if (memb_name == "insert") { |
Brenden Blanco | faea8c8 | 2017-03-29 09:58:31 -0700 | [diff] [blame] | 756 | if (desc->second.type == BPF_MAP_TYPE_ARRAY) { |
Paul Chaignon | 6ceb329 | 2017-04-01 18:23:58 +0200 | [diff] [blame] | 757 | 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 Blanco | 2833386 | 2015-05-28 18:19:38 -0700 | [diff] [blame] | 761 | } 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 Blanco | d0daf6a | 2015-11-05 23:31:22 -0800 | [diff] [blame] | 767 | } else if (memb_name == "perf_read") { |
| 768 | prefix = "bpf_perf_event_read"; |
| 769 | suffix = ")"; |
Teng Qin | 4186f5e | 2017-12-15 00:22:18 -0800 | [diff] [blame] | 770 | } else if (memb_name == "perf_counter_value") { |
| 771 | prefix = "bpf_perf_event_read_value"; |
| 772 | suffix = ")"; |
Teng Qin | e5e9b1f | 2018-04-25 13:49:37 -0700 | [diff] [blame] | 773 | } else if (memb_name == "check_current_task") { |
| 774 | prefix = "bpf_current_task_under_cgroup"; |
| 775 | suffix = ")"; |
Gary Lin | db410bf | 2018-06-07 16:08:46 +0800 | [diff] [blame] | 776 | } else if (memb_name == "redirect_map") { |
| 777 | prefix = "bpf_redirect_map"; |
| 778 | suffix = ")"; |
Brenden Blanco | 2833386 | 2015-05-28 18:19:38 -0700 | [diff] [blame] | 779 | } else { |
Vicent Marti | cc3a432 | 2016-04-30 14:57:52 +0200 | [diff] [blame] | 780 | error(Call->getLocStart(), "invalid bpf_table operation %0") << memb_name; |
Brenden Blanco | 2833386 | 2015-05-28 18:19:38 -0700 | [diff] [blame] | 781 | return false; |
| 782 | } |
| 783 | prefix += "((void *)bpf_pseudo_fd(1, " + fd + "), "; |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 784 | |
Brenden Blanco | 2833386 | 2015-05-28 18:19:38 -0700 | [diff] [blame] | 785 | txt = prefix + args + suffix; |
| 786 | } |
Brenden Blanco | ef6bb80 | 2016-03-04 15:13:13 -0800 | [diff] [blame] | 787 | if (!rewriter_.isRewritable(rewrite_start) || !rewriter_.isRewritable(rewrite_end)) { |
Brenden Blanco | c98ffd6 | 2016-04-09 18:41:42 -0700 | [diff] [blame] | 788 | error(Call->getLocStart(), "cannot use map function inside a macro"); |
Brenden Blanco | 561dafc | 2015-06-29 11:09:00 -0700 | [diff] [blame] | 789 | return false; |
| 790 | } |
Paul Chaignon | c5c3b99 | 2017-02-26 12:22:03 +0100 | [diff] [blame] | 791 | rewriter_.ReplaceText(expansionRange(SourceRange(rewrite_start, rewrite_end)), txt); |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 792 | return true; |
| 793 | } |
| 794 | } |
Brenden Blanco | 561dafc | 2015-06-29 11:09:00 -0700 | [diff] [blame] | 795 | } 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 Blanco | c98ffd6 | 2016-04-09 18:41:42 -0700 | [diff] [blame] | 805 | error(Call->getLocStart(), "cannot use builtin inside a macro"); |
Brenden Blanco | 561dafc | 2015-06-29 11:09:00 -0700 | [diff] [blame] | 806 | return false; |
| 807 | } |
| 808 | |
| 809 | vector<string> args; |
| 810 | for (auto arg : Call->arguments()) |
Paul Chaignon | c5c3b99 | 2017-02-26 12:22:03 +0100 | [diff] [blame] | 811 | args.push_back(rewriter_.getRewrittenText(expansionRange(arg->getSourceRange()))); |
Brenden Blanco | 561dafc | 2015-06-29 11:09:00 -0700 | [diff] [blame] | 812 | |
| 813 | string text; |
| 814 | if (Decl->getName() == "incr_cksum_l3") { |
Brenden Blanco | b711d45 | 2015-07-01 15:23:18 -0700 | [diff] [blame] | 815 | text = "bpf_l3_csum_replace_(" + fn_args_[0]->getName().str() + ", (u64)"; |
Brenden Blanco | 561dafc | 2015-06-29 11:09:00 -0700 | [diff] [blame] | 816 | text += args[0] + ", " + args[1] + ", " + args[2] + ", sizeof(" + args[2] + "))"; |
Paul Chaignon | c5c3b99 | 2017-02-26 12:22:03 +0100 | [diff] [blame] | 817 | rewriter_.ReplaceText(expansionRange(Call->getSourceRange()), text); |
Brenden Blanco | 561dafc | 2015-06-29 11:09:00 -0700 | [diff] [blame] | 818 | } else if (Decl->getName() == "incr_cksum_l4") { |
Brenden Blanco | b711d45 | 2015-07-01 15:23:18 -0700 | [diff] [blame] | 819 | text = "bpf_l4_csum_replace_(" + fn_args_[0]->getName().str() + ", (u64)"; |
Brenden Blanco | 561dafc | 2015-06-29 11:09:00 -0700 | [diff] [blame] | 820 | text += args[0] + ", " + args[1] + ", " + args[2]; |
| 821 | text += ", ((" + args[3] + " & 0x1) << 4) | sizeof(" + args[2] + "))"; |
Paul Chaignon | c5c3b99 | 2017-02-26 12:22:03 +0100 | [diff] [blame] | 822 | rewriter_.ReplaceText(expansionRange(Call->getSourceRange()), text); |
Brenden Blanco | 561dafc | 2015-06-29 11:09:00 -0700 | [diff] [blame] | 823 | } else if (Decl->getName() == "bpf_trace_printk") { |
Paul Chaignon | 9341942 | 2017-03-12 14:49:01 +0100 | [diff] [blame] | 824 | checkFormatSpecifiers(args[0], Call->getArg(0)->getLocStart()); |
Brenden Blanco | 561dafc | 2015-06-29 11:09:00 -0700 | [diff] [blame] | 825 | // #define bpf_trace_printk(fmt, args...) |
| 826 | // ({ char _fmt[] = fmt; bpf_trace_printk_(_fmt, sizeof(_fmt), args...); }) |
Brenden Blanco | 46176a1 | 2015-07-07 13:05:22 -0700 | [diff] [blame] | 827 | text = "({ char _fmt[] = " + args[0] + "; bpf_trace_printk_(_fmt, sizeof(_fmt)"; |
Brenden Blanco | a328d23 | 2015-08-11 18:33:49 -0700 | [diff] [blame] | 828 | if (args.size() <= 1) { |
| 829 | text += "); })"; |
Paul Chaignon | c5c3b99 | 2017-02-26 12:22:03 +0100 | [diff] [blame] | 830 | rewriter_.ReplaceText(expansionRange(Call->getSourceRange()), text); |
Brenden Blanco | a328d23 | 2015-08-11 18:33:49 -0700 | [diff] [blame] | 831 | } else { |
Paul Chaignon | c5c3b99 | 2017-02-26 12:22:03 +0100 | [diff] [blame] | 832 | rewriter_.ReplaceText(expansionRange(SourceRange(Call->getLocStart(), Call->getArg(0)->getLocEnd())), text); |
Brenden Blanco | a328d23 | 2015-08-11 18:33:49 -0700 | [diff] [blame] | 833 | rewriter_.InsertTextAfter(Call->getLocEnd(), "); }"); |
Brenden Blanco | 561dafc | 2015-06-29 11:09:00 -0700 | [diff] [blame] | 834 | } |
Brenden Blanco | aeca6bf | 2015-11-06 13:03:05 -0800 | [diff] [blame] | 835 | } 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 Chaignon | c5c3b99 | 2017-02-26 12:22:03 +0100 | [diff] [blame] | 840 | rewriter_.ReplaceText(expansionRange(Call->getSourceRange()), text); |
Vicent Marti | 4ea4af4 | 2016-05-04 13:01:55 +0200 | [diff] [blame] | 841 | } else if (Decl->getName() == "bpf_usdt_readarg_p") { |
Vicent Marti | 040df7d | 2016-05-04 16:59:57 +0200 | [diff] [blame] | 842 | 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 Chaignon | c5c3b99 | 2017-02-26 12:22:03 +0100 | [diff] [blame] | 848 | rewriter_.ReplaceText(expansionRange(Call->getSourceRange()), text); |
Vicent Marti | 4ea4af4 | 2016-05-04 13:01:55 +0200 | [diff] [blame] | 849 | } else if (Decl->getName() == "bpf_usdt_readarg") { |
Vicent Marti | 040df7d | 2016-05-04 16:59:57 +0200 | [diff] [blame] | 850 | text = "_bpf_readarg_" + current_fn_ + "_" + args[0] + "(" + args[1] + |
| 851 | ", " + args[2] + ", sizeof(*(" + args[2] + ")))"; |
Paul Chaignon | c5c3b99 | 2017-02-26 12:22:03 +0100 | [diff] [blame] | 852 | rewriter_.ReplaceText(expansionRange(Call->getSourceRange()), text); |
Vicent Marti | 040df7d | 2016-05-04 16:59:57 +0200 | [diff] [blame] | 853 | } |
Brenden Blanco | 561dafc | 2015-06-29 11:09:00 -0700 | [diff] [blame] | 854 | } |
Brenden Blanco | 3f28e7b | 2017-04-20 09:33:44 -0700 | [diff] [blame] | 855 | } 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 Blanco | 561dafc | 2015-06-29 11:09:00 -0700 | [diff] [blame] | 864 | } |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 865 | } |
| 866 | return true; |
| 867 | } |
| 868 | |
Paul Chaignon | 9341942 | 2017-03-12 14:49:01 +0100 | [diff] [blame] | 869 | bool 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 Blanco | 22a419b | 2015-05-29 11:14:20 -0700 | [diff] [blame] | 917 | bool BTypeVisitor::VisitBinaryOperator(BinaryOperator *E) { |
| 918 | if (!E->isAssignmentOp()) |
| 919 | return true; |
| 920 | Expr *LHS = E->getLHS()->IgnoreImplicit(); |
Brenden Blanco | 22a419b | 2015-05-29 11:14:20 -0700 | [diff] [blame] | 921 | 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 Blanco | 561dafc | 2015-06-29 11:09:00 -0700 | [diff] [blame] | 926 | if (!rewriter_.isRewritable(E->getLocStart())) { |
Brenden Blanco | c98ffd6 | 2016-04-09 18:41:42 -0700 | [diff] [blame] | 927 | error(E->getLocStart(), "cannot use \"packet\" header type inside a macro"); |
Brenden Blanco | 561dafc | 2015-06-29 11:09:00 -0700 | [diff] [blame] | 928 | return false; |
| 929 | } |
Brenden Blanco | 22a419b | 2015-05-29 11:14:20 -0700 | [diff] [blame] | 930 | uint64_t ofs = C.getFieldOffset(F); |
| 931 | uint64_t sz = F->isBitField() ? F->getBitWidthValue(C) : C.getTypeSize(F->getType()); |
Paul Chaignon | c5c3b99 | 2017-02-26 12:22:03 +0100 | [diff] [blame] | 932 | string base = rewriter_.getRewrittenText(expansionRange(Base->getSourceRange())); |
Brenden Blanco | b711d45 | 2015-07-01 15:23:18 -0700 | [diff] [blame] | 933 | string text = "bpf_dins_pkt(" + fn_args_[0]->getName().str() + ", (u64)" + base + "+" + to_string(ofs >> 3) |
Paul Chaignon | 47b74fe | 2017-02-23 20:06:03 +0100 | [diff] [blame] | 934 | + ", " + to_string(ofs & 0x7) + ", " + to_string(sz) + ","; |
| 935 | rewriter_.ReplaceText(expansionRange(SourceRange(E->getLocStart(), E->getOperatorLoc())), text); |
| 936 | rewriter_.InsertTextAfterToken(E->getLocEnd(), ")"); |
Brenden Blanco | 22a419b | 2015-05-29 11:14:20 -0700 | [diff] [blame] | 937 | } |
| 938 | } |
| 939 | } |
| 940 | } |
| 941 | } |
| 942 | return true; |
| 943 | } |
| 944 | bool 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 Blanco | 2833386 | 2015-05-28 18:19:38 -0700 | [diff] [blame] | 952 | if (DeclRefExpr *Ref = dyn_cast<DeclRefExpr>(Base)) { |
| 953 | if (DeprecatedAttr *A = Ref->getDecl()->getAttr<DeprecatedAttr>()) { |
| 954 | if (A->getMessage() == "packet") { |
Brenden Blanco | 22a419b | 2015-05-29 11:14:20 -0700 | [diff] [blame] | 955 | if (FieldDecl *F = dyn_cast<FieldDecl>(Memb->getMemberDecl())) { |
Brenden Blanco | 561dafc | 2015-06-29 11:09:00 -0700 | [diff] [blame] | 956 | if (!rewriter_.isRewritable(E->getLocStart())) { |
Brenden Blanco | c98ffd6 | 2016-04-09 18:41:42 -0700 | [diff] [blame] | 957 | error(E->getLocStart(), "cannot use \"packet\" header type inside a macro"); |
Brenden Blanco | 561dafc | 2015-06-29 11:09:00 -0700 | [diff] [blame] | 958 | return false; |
| 959 | } |
Brenden Blanco | 2833386 | 2015-05-28 18:19:38 -0700 | [diff] [blame] | 960 | uint64_t ofs = C.getFieldOffset(F); |
| 961 | uint64_t sz = F->isBitField() ? F->getBitWidthValue(C) : C.getTypeSize(F->getType()); |
Brenden Blanco | b711d45 | 2015-07-01 15:23:18 -0700 | [diff] [blame] | 962 | string text = "bpf_dext_pkt(" + fn_args_[0]->getName().str() + ", (u64)" + Ref->getDecl()->getName().str() + "+" |
Brenden Blanco | 561dafc | 2015-06-29 11:09:00 -0700 | [diff] [blame] | 963 | + to_string(ofs >> 3) + ", " + to_string(ofs & 0x7) + ", " + to_string(sz) + ")"; |
Paul Chaignon | c5c3b99 | 2017-02-26 12:22:03 +0100 | [diff] [blame] | 964 | rewriter_.ReplaceText(expansionRange(E->getSourceRange()), text); |
Brenden Blanco | 2833386 | 2015-05-28 18:19:38 -0700 | [diff] [blame] | 965 | } |
| 966 | } |
| 967 | } |
| 968 | } |
| 969 | return true; |
| 970 | } |
| 971 | |
Paul Chaignon | c5c3b99 | 2017-02-26 12:22:03 +0100 | [diff] [blame] | 972 | SourceRange |
| 973 | BTypeVisitor::expansionRange(SourceRange range) { |
Yonghong Song | 806627e | 2018-05-02 10:32:31 -0700 | [diff] [blame] | 974 | #if LLVM_MAJOR_VERSION >= 7 |
| 975 | return rewriter_.getSourceMgr().getExpansionRange(range).getAsRange(); |
| 976 | #else |
Paul Chaignon | c5c3b99 | 2017-02-26 12:22:03 +0100 | [diff] [blame] | 977 | return rewriter_.getSourceMgr().getExpansionRange(range); |
Yonghong Song | 806627e | 2018-05-02 10:32:31 -0700 | [diff] [blame] | 978 | #endif |
Paul Chaignon | c5c3b99 | 2017-02-26 12:22:03 +0100 | [diff] [blame] | 979 | } |
| 980 | |
Brenden Blanco | c98ffd6 | 2016-04-09 18:41:42 -0700 | [diff] [blame] | 981 | template <unsigned N> |
| 982 | DiagnosticBuilder 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 Chaignon | 9341942 | 2017-03-12 14:49:01 +0100 | [diff] [blame] | 987 | template <unsigned N> |
| 988 | DiagnosticBuilder 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 Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 993 | // Open table FDs when bpf tables (as denoted by section("maps*") attribute) |
| 994 | // are declared. |
| 995 | bool 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 Blanco | c98ffd6 | 2016-04-09 18:41:42 -0700 | [diff] [blame] | 1001 | error(Decl->getLocEnd(), "invalid type for bpf_table, expect struct"); |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 1002 | return false; |
| 1003 | } |
| 1004 | const RecordDecl *RD = R->getDecl()->getDefinition(); |
Brenden Blanco | 8ac3ea7 | 2015-08-07 22:04:56 -0700 | [diff] [blame] | 1005 | |
Brenden Blanco | faea8c8 | 2017-03-29 09:58:31 -0700 | [diff] [blame] | 1006 | TableDesc table; |
| 1007 | TableStorage::iterator table_it; |
Brenden Blanco | 8ac3ea7 | 2015-08-07 22:04:56 -0700 | [diff] [blame] | 1008 | table.name = Decl->getName(); |
Brenden Blanco | faea8c8 | 2017-03-29 09:58:31 -0700 | [diff] [blame] | 1009 | Path local_path({fe_.id(), table.name}); |
| 1010 | Path global_path({table.name}); |
| 1011 | QualType key_type, leaf_type; |
Brenden Blanco | 8ac3ea7 | 2015-08-07 22:04:56 -0700 | [diff] [blame] | 1012 | |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 1013 | unsigned i = 0; |
| 1014 | for (auto F : RD->fields()) { |
Paul Chaignon | d32a61b | 2017-08-23 07:25:30 +0200 | [diff] [blame] | 1015 | if (F->getType().getTypePtr()->isIncompleteType()) { |
| 1016 | error(F->getLocStart(), "unknown type"); |
| 1017 | return false; |
| 1018 | } |
| 1019 | |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 1020 | size_t sz = C.getTypeSize(F->getType()) >> 3; |
| 1021 | if (F->getName() == "key") { |
Brenden Blanco | fe88e5a | 2015-12-06 19:58:38 -0800 | [diff] [blame] | 1022 | if (sz == 0) { |
Brenden Blanco | c98ffd6 | 2016-04-09 18:41:42 -0700 | [diff] [blame] | 1023 | error(F->getLocStart(), "invalid zero-sized leaf"); |
Brenden Blanco | fe88e5a | 2015-12-06 19:58:38 -0800 | [diff] [blame] | 1024 | return false; |
| 1025 | } |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 1026 | table.key_size = sz; |
Brenden Blanco | faea8c8 | 2017-03-29 09:58:31 -0700 | [diff] [blame] | 1027 | key_type = F->getType(); |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 1028 | } else if (F->getName() == "leaf") { |
Brenden Blanco | fe88e5a | 2015-12-06 19:58:38 -0800 | [diff] [blame] | 1029 | if (sz == 0) { |
Brenden Blanco | c98ffd6 | 2016-04-09 18:41:42 -0700 | [diff] [blame] | 1030 | error(F->getLocStart(), "invalid zero-sized leaf"); |
Brenden Blanco | fe88e5a | 2015-12-06 19:58:38 -0800 | [diff] [blame] | 1031 | return false; |
| 1032 | } |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 1033 | table.leaf_size = sz; |
Brenden Blanco | faea8c8 | 2017-03-29 09:58:31 -0700 | [diff] [blame] | 1034 | leaf_type = F->getType(); |
Yonghong Song | 067219b | 2017-08-16 16:18:22 -0700 | [diff] [blame] | 1035 | } 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 Zhou | de11d07 | 2016-12-06 18:10:38 -0800 | [diff] [blame] | 1043 | } 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 Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 1051 | } |
| 1052 | ++i; |
| 1053 | } |
Huapeng Zhou | de11d07 | 2016-12-06 18:10:38 -0800 | [diff] [blame] | 1054 | |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 1055 | bpf_map_type map_type = BPF_MAP_TYPE_UNSPEC; |
Brenden Blanco | f0b15c4 | 2015-09-23 21:36:05 -0700 | [diff] [blame] | 1056 | if (A->getName() == "maps/hash") { |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 1057 | map_type = BPF_MAP_TYPE_HASH; |
Brenden Blanco | f0b15c4 | 2015-09-23 21:36:05 -0700 | [diff] [blame] | 1058 | } else if (A->getName() == "maps/array") { |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 1059 | map_type = BPF_MAP_TYPE_ARRAY; |
Zaafar Ahmed | f822836 | 2016-03-30 17:59:54 +0500 | [diff] [blame] | 1060 | } else if (A->getName() == "maps/percpu_hash") { |
Zaafar Ahmed | 6425825 | 2016-03-29 22:13:50 +0500 | [diff] [blame] | 1061 | map_type = BPF_MAP_TYPE_PERCPU_HASH; |
Zaafar Ahmed | f822836 | 2016-03-30 17:59:54 +0500 | [diff] [blame] | 1062 | } else if (A->getName() == "maps/percpu_array") { |
Zaafar Ahmed | 6425825 | 2016-03-29 22:13:50 +0500 | [diff] [blame] | 1063 | map_type = BPF_MAP_TYPE_PERCPU_ARRAY; |
Huapeng Zhou | e69f764 | 2016-12-01 10:56:36 -0800 | [diff] [blame] | 1064 | } 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 Zhou | fcd936c | 2017-02-07 15:03:32 -0800 | [diff] [blame] | 1068 | } else if (A->getName() == "maps/lpm_trie") { |
| 1069 | map_type = BPF_MAP_TYPE_LPM_TRIE; |
Brenden Blanco | f0b15c4 | 2015-09-23 21:36:05 -0700 | [diff] [blame] | 1070 | } else if (A->getName() == "maps/histogram") { |
Brenden Blanco | faea8c8 | 2017-03-29 09:58:31 -0700 | [diff] [blame] | 1071 | map_type = BPF_MAP_TYPE_HASH; |
| 1072 | if (key_type->isSpecificBuiltinType(BuiltinType::Int)) |
Brenden Blanco | f0b15c4 | 2015-09-23 21:36:05 -0700 | [diff] [blame] | 1073 | map_type = BPF_MAP_TYPE_ARRAY; |
Brenden Blanco | faea8c8 | 2017-03-29 09:58:31 -0700 | [diff] [blame] | 1074 | if (!leaf_type->isSpecificBuiltinType(BuiltinType::ULongLong)) |
| 1075 | error(Decl->getLocStart(), "histogram leaf type must be u64, got %0") << leaf_type; |
Brenden Blanco | f0b15c4 | 2015-09-23 21:36:05 -0700 | [diff] [blame] | 1076 | } else if (A->getName() == "maps/prog") { |
Alexei Starovoitov | f09b5b8 | 2016-03-31 13:37:04 -0700 | [diff] [blame] | 1077 | map_type = BPF_MAP_TYPE_PROG_ARRAY; |
Brenden Blanco | aeca6bf | 2015-11-06 13:03:05 -0800 | [diff] [blame] | 1078 | } else if (A->getName() == "maps/perf_output") { |
Alexei Starovoitov | f09b5b8 | 2016-03-31 13:37:04 -0700 | [diff] [blame] | 1079 | map_type = BPF_MAP_TYPE_PERF_EVENT_ARRAY; |
Andreas Gerstmayr | 7e0784d | 2017-01-16 16:35:58 +0100 | [diff] [blame] | 1080 | int numcpu = get_possible_cpus().size(); |
Brenden Blanco | aeca6bf | 2015-11-06 13:03:05 -0800 | [diff] [blame] | 1081 | if (numcpu <= 0) |
| 1082 | numcpu = 1; |
| 1083 | table.max_entries = numcpu; |
Brenden Blanco | d0daf6a | 2015-11-05 23:31:22 -0800 | [diff] [blame] | 1084 | } else if (A->getName() == "maps/perf_array") { |
Alexei Starovoitov | f09b5b8 | 2016-03-31 13:37:04 -0700 | [diff] [blame] | 1085 | map_type = BPF_MAP_TYPE_PERF_EVENT_ARRAY; |
Teng Qin | e5e9b1f | 2018-04-25 13:49:37 -0700 | [diff] [blame] | 1086 | } else if (A->getName() == "maps/cgroup_array") { |
| 1087 | map_type = BPF_MAP_TYPE_CGROUP_ARRAY; |
Brenden Blanco | 9cafce2 | 2016-03-04 12:02:10 -0800 | [diff] [blame] | 1088 | } else if (A->getName() == "maps/stacktrace") { |
| 1089 | map_type = BPF_MAP_TYPE_STACK_TRACE; |
Gary Lin | db410bf | 2018-06-07 16:08:46 +0800 | [diff] [blame] | 1090 | } 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 Blanco | 89978ba | 2015-12-15 16:39:35 -0800 | [diff] [blame] | 1094 | } else if (A->getName() == "maps/extern") { |
Brenden Blanco | faea8c8 | 2017-03-29 09:58:31 -0700 | [diff] [blame] | 1095 | if (!fe_.table_storage().Find(global_path, table_it)) { |
Brenden Blanco | c98ffd6 | 2016-04-09 18:41:42 -0700 | [diff] [blame] | 1096 | error(Decl->getLocStart(), "reference to undefined table"); |
Brenden Blanco | 89978ba | 2015-12-15 16:39:35 -0800 | [diff] [blame] | 1097 | return false; |
| 1098 | } |
Brenden Blanco | faea8c8 | 2017-03-29 09:58:31 -0700 | [diff] [blame] | 1099 | 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 Blanco | 89978ba | 2015-12-15 16:39:35 -0800 | [diff] [blame] | 1108 | return false; |
| 1109 | } |
Brenden Blanco | faea8c8 | 2017-03-29 09:58:31 -0700 | [diff] [blame] | 1110 | fe_.table_storage().Insert(global_path, table_it->second.dup()); |
Brenden Blanco | 89978ba | 2015-12-15 16:39:35 -0800 | [diff] [blame] | 1111 | return true; |
Yonghong Song | ab21dcd | 2015-07-16 20:20:22 -0700 | [diff] [blame] | 1112 | } |
Brenden Blanco | d0daf6a | 2015-11-05 23:31:22 -0800 | [diff] [blame] | 1113 | |
Huapeng Zhou | d4a3baf | 2016-12-20 13:10:12 -0800 | [diff] [blame] | 1114 | if (!table.is_extern) { |
Brenden Blanco | 89978ba | 2015-12-15 16:39:35 -0800 | [diff] [blame] | 1115 | if (map_type == BPF_MAP_TYPE_UNSPEC) { |
Brenden Blanco | c98ffd6 | 2016-04-09 18:41:42 -0700 | [diff] [blame] | 1116 | error(Decl->getLocStart(), "unsupported map type: %0") << A->getName(); |
Brenden Blanco | 89978ba | 2015-12-15 16:39:35 -0800 | [diff] [blame] | 1117 | return false; |
| 1118 | } |
Brenden Blanco | d0daf6a | 2015-11-05 23:31:22 -0800 | [diff] [blame] | 1119 | |
Brenden Blanco | 89978ba | 2015-12-15 16:39:35 -0800 | [diff] [blame] | 1120 | table.type = map_type; |
Martin KaFai Lau | df36816 | 2017-10-19 12:46:48 -0700 | [diff] [blame] | 1121 | 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 Blanco | 89978ba | 2015-12-15 16:39:35 -0800 | [diff] [blame] | 1124 | } |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 1125 | if (table.fd < 0) { |
Vicent Marti | cc3a432 | 2016-04-30 14:57:52 +0200 | [diff] [blame] | 1126 | error(Decl->getLocStart(), "could not open bpf map: %0\nis %1 map type enabled in your kernel?") << |
Brenden Blanco | c98ffd6 | 2016-04-09 18:41:42 -0700 | [diff] [blame] | 1127 | strerror(errno) << A->getName(); |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 1128 | return false; |
| 1129 | } |
Brenden Blanco | 89978ba | 2015-12-15 16:39:35 -0800 | [diff] [blame] | 1130 | |
Yonghong Song | 96354c6 | 2018-01-28 22:39:48 -0800 | [diff] [blame] | 1131 | if (!table.is_extern) |
| 1132 | fe_.table_storage().VisitMapType(table, C, key_type, leaf_type); |
Brenden Blanco | faea8c8 | 2017-03-29 09:58:31 -0700 | [diff] [blame] | 1133 | fe_.table_storage().Insert(local_path, move(table)); |
Brenden Blanco | 6ec65e4 | 2015-07-02 10:02:04 -0700 | [diff] [blame] | 1134 | } 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 Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 1146 | } |
| 1147 | return true; |
| 1148 | } |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 1149 | |
Paul Chaignon | eae0acf | 2017-08-05 23:04:41 +0200 | [diff] [blame] | 1150 | // First traversal of AST to retrieve maps with external pointers. |
Paul Chaignon | e67cb56 | 2017-10-26 08:43:13 +0200 | [diff] [blame] | 1151 | BTypeConsumer::BTypeConsumer(ASTContext &C, BFrontendAction &fe, |
Yonghong Song | 6fc8d15 | 2017-11-03 15:04:24 -0700 | [diff] [blame] | 1152 | Rewriter &rewriter, set<Decl *> &m) |
| 1153 | : fe_(fe), |
| 1154 | map_visitor_(m), |
| 1155 | btype_visitor_(C, fe), |
Paul Chaignon | ad2d0d9 | 2018-05-08 22:02:55 +0200 | [diff] [blame] | 1156 | probe_visitor1_(C, rewriter, m, true), |
| 1157 | probe_visitor2_(C, rewriter, m, false) {} |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 1158 | |
Paul Chaignon | eae0acf | 2017-08-05 23:04:41 +0200 | [diff] [blame] | 1159 | void BTypeConsumer::HandleTranslationUnit(ASTContext &Context) { |
| 1160 | DeclContext::decl_iterator it; |
| 1161 | DeclContext *DC = TranslationUnitDecl::castToDeclContext(Context.getTranslationUnitDecl()); |
Brenden Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 1162 | |
Paul Chaignon | e67cb56 | 2017-10-26 08:43:13 +0200 | [diff] [blame] | 1163 | /** |
Paul Chaignon | ad2d0d9 | 2018-05-08 22:02:55 +0200 | [diff] [blame] | 1164 | * 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 Chaignon | e67cb56 | 2017-10-26 08:43:13 +0200 | [diff] [blame] | 1168 | */ |
Paul Chaignon | eae0acf | 2017-08-05 23:04:41 +0200 | [diff] [blame] | 1169 | for (it = DC->decls_begin(); it != DC->decls_end(); it++) { |
| 1170 | Decl *D = *it; |
Brenden Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 1171 | if (FunctionDecl *F = dyn_cast<FunctionDecl>(D)) { |
Yonghong Song | 6fc8d15 | 2017-11-03 15:04:24 -0700 | [diff] [blame] | 1172 | if (fe_.is_rewritable_ext_func(F)) { |
Brenden Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 1173 | for (auto arg : F->parameters()) { |
Paul Chaignon | b66a9c9 | 2018-05-01 22:10:28 +0200 | [diff] [blame] | 1174 | if (arg == F->getParamDecl(0)) { |
Paul Chaignon | 05b2083 | 2018-05-19 14:31:13 +0200 | [diff] [blame] | 1175 | /** |
| 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 Chaignon | b66a9c9 | 2018-05-01 22:10:28 +0200 | [diff] [blame] | 1185 | } else if (!arg->getType()->isFundamentalType()) { |
Paul Chaignon | 471f1ea | 2018-05-11 09:36:37 +0200 | [diff] [blame] | 1186 | tuple<Decl *, int> pt = make_tuple(arg, 0); |
| 1187 | probe_visitor1_.set_ptreg(pt); |
Paul Chaignon | b66a9c9 | 2018-05-01 22:10:28 +0200 | [diff] [blame] | 1188 | } |
Brenden Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 1189 | } |
Paul Chaignon | ad2d0d9 | 2018-05-08 22:02:55 +0200 | [diff] [blame] | 1190 | |
| 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 Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 1231 | } |
| 1232 | } |
Paul Chaignon | e67cb56 | 2017-10-26 08:43:13 +0200 | [diff] [blame] | 1233 | |
| 1234 | btype_visitor_.TraverseDecl(D); |
Brenden Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 1235 | } |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 1236 | } |
| 1237 | |
Yonghong Song | 91837ca | 2017-09-28 09:40:13 -0700 | [diff] [blame] | 1238 | BFrontendAction::BFrontendAction(llvm::raw_ostream &os, unsigned flags, |
| 1239 | TableStorage &ts, const std::string &id, |
Yonghong Song | 6fc8d15 | 2017-11-03 15:04:24 -0700 | [diff] [blame] | 1240 | const std::string &main_path, |
Yonghong Song | 91837ca | 2017-09-28 09:40:13 -0700 | [diff] [blame] | 1241 | FuncSource &func_src, std::string &mod_src) |
| 1242 | : os_(os), |
| 1243 | flags_(flags), |
| 1244 | ts_(ts), |
| 1245 | id_(id), |
| 1246 | rewriter_(new Rewriter), |
Yonghong Song | 6fc8d15 | 2017-11-03 15:04:24 -0700 | [diff] [blame] | 1247 | main_path_(main_path), |
Yonghong Song | 91837ca | 2017-09-28 09:40:13 -0700 | [diff] [blame] | 1248 | func_src_(func_src), |
| 1249 | mod_src_(mod_src) {} |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 1250 | |
Yonghong Song | 6fc8d15 | 2017-11-03 15:04:24 -0700 | [diff] [blame] | 1251 | bool 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 Song | bace5f2 | 2018-05-27 11:52:03 -0700 | [diff] [blame] | 1257 | void 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 Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 1275 | void BFrontendAction::EndSourceFileAction() { |
Yonghong Song | bace5f2 | 2018-05-27 11:52:03 -0700 | [diff] [blame] | 1276 | // Additional misc rewrites |
| 1277 | DoMiscWorkAround(); |
| 1278 | |
Jean-Tiare Le Bigot | 7d37bf4 | 2016-03-29 12:48:02 +0000 | [diff] [blame] | 1279 | if (flags_ & DEBUG_PREPROCESSOR) |
Brenden Blanco | b13426c | 2015-09-08 22:11:46 -0700 | [diff] [blame] | 1280 | rewriter_->getEditBuffer(rewriter_->getSourceMgr().getMainFileID()).write(llvm::errs()); |
Yonghong Song | 91837ca | 2017-09-28 09:40:13 -0700 | [diff] [blame] | 1281 | 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 Starovoitov | 4f47e3b | 2017-09-06 19:57:21 -0700 | [diff] [blame] | 1286 | |
| 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 Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 1292 | rewriter_->getEditBuffer(rewriter_->getSourceMgr().getMainFileID()).write(os_); |
| 1293 | os_.flush(); |
| 1294 | } |
| 1295 | |
| 1296 | unique_ptr<ASTConsumer> BFrontendAction::CreateASTConsumer(CompilerInstance &Compiler, llvm::StringRef InFile) { |
| 1297 | rewriter_->setSourceMgr(Compiler.getSourceManager(), Compiler.getLangOpts()); |
Brenden Blanco | 8ed57a2 | 2015-09-16 14:59:35 -0700 | [diff] [blame] | 1298 | vector<unique_ptr<ASTConsumer>> consumers; |
Paul Chaignon | e67cb56 | 2017-10-26 08:43:13 +0200 | [diff] [blame] | 1299 | consumers.push_back(unique_ptr<ASTConsumer>(new BTypeConsumer(Compiler.getASTContext(), *this, *rewriter_, m_))); |
Brenden Blanco | faea8c8 | 2017-03-29 09:58:31 -0700 | [diff] [blame] | 1300 | return unique_ptr<ASTConsumer>(new MultiplexConsumer(std::move(consumers))); |
Brenden Blanco | 7009b55 | 2015-05-26 11:48:17 -0700 | [diff] [blame] | 1301 | } |
| 1302 | |
| 1303 | } |