class ProbeChecker : public RecursiveASTVisitor<ProbeChecker> {
public:
explicit ProbeChecker(Expr *arg, const set<Decl *> &ptregs)
- : needs_probe_(false), ptregs_(ptregs) {
- if (arg)
+ : needs_probe_(false), is_transitive_(false), ptregs_(ptregs) {
+ if (arg) {
TraverseStmt(arg);
+ if (arg->getType()->isPointerType())
+ is_transitive_ = needs_probe_;
+ }
}
bool VisitCallExpr(CallExpr *E) {
+ needs_probe_ = false;
return false;
}
bool VisitDeclRefExpr(DeclRefExpr *E) {
return true;
}
bool needs_probe() const { return needs_probe_; }
+ bool is_transitive() const { return is_transitive_; }
private:
bool needs_probe_;
+ bool is_transitive_;
const set<Decl *> &ptregs_;
};
bool ProbeVisitor::VisitVarDecl(VarDecl *Decl) {
if (Expr *E = Decl->getInit()) {
- if (ProbeChecker(E, ptregs_).needs_probe())
+ if (ProbeChecker(E, ptregs_).is_transitive())
set_ptreg(Decl);
}
return true;
if (!E->isAssignmentOp())
return true;
// copy probe attribute from RHS to LHS if present
- if (ProbeChecker(E->getRHS(), ptregs_).needs_probe()) {
+ if (ProbeChecker(E->getRHS(), ptregs_).is_transitive()) {
ProbeSetter setter(&ptregs_);
setter.TraverseStmt(E->getLHS());
}
if (FunctionDecl *F = dyn_cast<FunctionDecl>(D)) {
if (F->isExternallyVisible() && F->hasBody()) {
for (auto arg : F->parameters()) {
- if (arg != F->getParamDecl(0))
+ if (arg != F->getParamDecl(0) && !arg->getType()->isFundamentalType())
visitor_.set_ptreg(arg);
}
visitor_.TraverseDecl(D);
}
""")
+ def test_probe_simple_assign(self):
+ b = BPF(text="""
+#include <uapi/linux/ptrace.h>
+#include <linux/gfp.h>
+struct leaf { size_t size; };
+BPF_HASH(simple_map, u32, struct leaf);
+int kprobe____kmalloc(struct pt_regs *ctx, size_t size) {
+ u32 pid = bpf_get_current_pid_tgid();
+ struct leaf* leaf = simple_map.lookup(&pid);
+ if (leaf)
+ leaf->size += size;
+ return 0;
+}""", debug=4)
if __name__ == "__main__":
main()