Commit 94d15bc8 authored by Yonghong Song's avatar Yonghong Song Committed by Brenden Blanco

change frontend rewriter to better handle anonymous struct/union

Kernel Commit 29e48ce87f1e ("task_struct: Allow randomized layout")
(https://patchwork.kernel.org/patch/9797817/)
permits to randomize a section of kernel task_struct data
structure. This only takes effect when CONFIG_GCC_PLUGINS and
CONFIG_GCC_PLUGIN_RANDSTRUCT are set.

When randomization does not happen, an anonymous struct
is introduced in task_struct data structure by gcc when compiling
the kernel. To make field offset compatible, task_struct will
have the same anonymous struct. The patch is at
http://www.spinics.net/lists/kernel/msg2644958.html.
Otherwise, bpf program may get wrong data from the kernel.

Currently, bcc bpf_probe_read rewriter does not support
anonymous struct/union. For example, with the above
compiler-clang.h patch, examples/tracing/task_switch.py
will have the following error:
  /virtual/main.c:16:18: error: internal error: opLoc is invalid while preparing probe rewrite
    key.prev_pid = prev->pid;
                   ^

For anonymous structure, opcode source location ("->") is not available
and hence the above failure. We could use memberLoc ("pid") which is
available for anonymous struct/union. For example, for
  struct sock *skp; ...; u32 saddr = skp->__sk_common.skc_rcv_saddr;
The old way for bpf_probe_read rewrite:
  bpf_probe_read(&_val, sizeof(_val), (u64)skp + offsetof(struct sock, __sk_common.skc_rcv_saddr));
The new way:
  bpf_probe_read(&_val, sizeof(_val), (u64)&skp->__sk_common.skc_rcv_saddr);

The new way is similar to what typical bpf programs may do manually.
Signed-off-by: default avatarYonghong Song <yhs@fb.com>
parent 1d0f2925
......@@ -211,13 +211,13 @@ bool ProbeVisitor::VisitMemberExpr(MemberExpr *E) {
return true;
Expr *base;
SourceLocation rhs_start, op;
SourceLocation rhs_start, member;
bool found = false;
for (MemberExpr *M = E; M; M = dyn_cast<MemberExpr>(M->getBase())) {
memb_visited_.insert(M);
rhs_start = M->getLocEnd();
base = M->getBase();
op = M->getOperatorLoc();
member = M->getMemberLoc();
if (M->isArrow()) {
found = true;
break;
......@@ -225,19 +225,18 @@ bool ProbeVisitor::VisitMemberExpr(MemberExpr *E) {
}
if (!found)
return true;
if (op.isInvalid()) {
error(base->getLocEnd(), "internal error: opLoc is invalid while preparing probe rewrite");
if (member.isInvalid()) {
error(base->getLocEnd(), "internal error: MemberLoc is invalid while preparing probe rewrite");
return false;
}
string rhs = rewriter_.getRewrittenText(expansionRange(SourceRange(rhs_start, E->getLocEnd())));
string base_type = base->getType()->getPointeeType().getAsString();
string pre, post;
pre = "({ typeof(" + E->getType().getAsString() + ") _val; memset(&_val, 0, sizeof(_val));";
pre += " bpf_probe_read(&_val, sizeof(_val), (u64)";
post = " + offsetof(" + base_type + ", " + rhs + ")";
post += "); _val; })";
pre += " bpf_probe_read(&_val, sizeof(_val), (u64)&";
post = rhs + "); _val; })";
rewriter_.InsertText(E->getLocStart(), pre);
rewriter_.ReplaceText(expansionRange(SourceRange(op, E->getLocEnd())), post);
rewriter_.ReplaceText(expansionRange(SourceRange(member, E->getLocEnd())), post);
return true;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment