perfebpfbpftracepoint

How to get bpftool to attach a program to a tracepoint?


I have the following simple eBPF program:

#include "vmlinux.h"
#include <bpf/bpf_helpers.h>

struct sys_enter_execve_ctx {
  unsigned short common_type;
  unsigned char common_flags;
  unsigned char common_preempt_count;
  int common_pid;
  int __syscall_nr;
  const char *filename;
  const char *const * argv;
  const char *const * envp;
};

SEC("tp/syscalls/sys_enter_execve")
int handle_execve(struct sys_enter_execve_ctx *ctx) {
  bpf_printk("%s\n", ctx->filename);
  return 0;
}

char LICENSE[] SEC("license") = "GPL";

and a main program:

#include <stdio.h>

#include "exec.skel.h"

int main(void)
{
    struct exec *skel = exec__open();

    exec__load(skel);
    exec__attach(skel);

    getchar();

    exec__detach(skel);
    exec__destroy(skel);

    return 0;
}

and a Makefile to build everything:

APP=exec

.PHONY: $(APP) vmlinux bpf skel run clean

$(APP): skel
    clang exec.c -lbpf -lelf -o $(APP)

vmlinux:
    bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h

bpf: vmlinux
    clang -g -O3 -target bpf -D__TARGET_ARCH_x86_64 -c exec.bpf.c -o exec.bpf.o

skel: bpf
    bpftool gen skeleton exec.bpf.o name exec > exec.skel.h

run: $(APP)
    sudo ./$(APP)

clean:
    -rm -rf *.o *.skel.h vmlinux.h $(APP)

When I run make and make run everything works fine. In another scenario I wanted to use bpftool to load and attach the program to a tracepoint. The loading works successfully with:

sudo bpftool prog load ./exec.bpf.o /sys/fs/bpf/exec type tracepoint

sudo bpftool prog list
[...]
44: tracepoint  name handle_execve  tag 08424f7d1079fa76  gpl
    loaded_at 2023-02-26T10:52:47+0100  uid 0
    xlated 48B  jited 36B  memlock 4096B  map_ids 11
    btf_id 144

From what I understand the loading is independent of the attaching. There are indeed attach subcommands like bpftool prog attach, bpftool net attach etc. but there are not for tracepoints. Also bpftool perf does not have an attach command:

bpftool perf help
Usage: bpftool perf { show | list }
       bpftool perf help }

       OPTIONS := { {-j|--json} [{-p|--pretty}] | {-d|--debug} | {-l|--legacy} }

When I trace the libbpf program from the beginning there are bpf(BPF_PROG_LOAD, {prog_type=BPF_PROG_TYPE_TRACEPOINT, ..., perf_open_event and bpf(BPF_LINK_CREATE, ...) system calls to set everything up:

sudo strace -e bpf,perf_event_open,ioctl ./exec
[...]
perf_event_open({type=PERF_TYPE_TRACEPOINT, size=PERF_ATTR_SIZE_VER7, config=733, sample_period=0, sample_type=0, read_format=0, precise_ip=0 /* arbitrary skid */, ...}, -1, 0, -1, PERF_FLAG_FD_CLOEXEC) = 6
bpf(BPF_PROG_LOAD, {prog_type=BPF_PROG_TYPE_TRACEPOINT, insn_cnt=2, insns=0x7ffd42bc8550, license="GPL", log_level=0, log_size=0, log_buf=NULL, kern_version=KERNEL_VERSION(0, 0, 0), prog_flags=0, prog_name="", prog_ifindex=0, expected_attach_type=BPF_CGROUP_INET_INGRESS, prog_btf_fd=0, func_info_rec_size=0, func_info=NULL, func_info_cnt=0, line_info_rec_size=0, line_info=NULL, line_info_cnt=0, attach_btf_id=0, attach_prog_fd=0, fd_array=NULL}, 128) = 7
bpf(BPF_LINK_CREATE, {link_create={prog_fd=7, target_fd=-1, attach_type=BPF_PERF_EVENT, flags=0, perf_event={bpf_cookie=0}}}, 48) = -1 EBADF (Bad file descriptor)
bpf(BPF_LINK_CREATE, {link_create={prog_fd=5, target_fd=6, attach_type=BPF_PERF_EVENT, flags=0, perf_event={bpf_cookie=0}}}, 48) = 7
ioctl(6, PERF_EVENT_IOC_ENABLE, 0)      = 0

What am I missing? How can I attach the program to a tracepoint (or kprobe etc.) with bpftool?


Solution

  • Bpftool has known how to attach networking or some cgroup-related programs for a while, but it has long been impossible to attach tracing programs with it. The reason is that tracing program would need a perf file descriptor to remain attached, and this file descriptor could not be pinned like for eBPF programs themselves, so attachment would have stopped as soon as bpftool would exit. This is why you haven't found a dedicated command with bpftool perf or bpftool prog attach.

    With the introduction of eBPF links, it's now possible to pin links representing the attachment of a program to a tracing hook. Then it took some more time, but eventually, version 7.1.0 of bpftool (the latest release as of this writing) got support for attaching tracing programs when loading them, via the autoattach keyword.

    The basic syntax for automatically attaching a tracing program on load is the following:

    # bpftool prog load <object_file> <pinned_path> autoattach
    

    See the docs for details. In particular, note that this only works if bpftool/libbpf is able to infer the relevant information from the ELF file to attach the program (in particular from the ELF section name, which should indicate the attach type and location - you should be good with your SEC("tp/syscalls/sys_enter_execve")).

    Attaching in two steps (something like bpftool perf attach <ref_to_loaded_program>) has not been implemented at this time, but we could add it in the future. Patchsets are welcome :)