perf trace: Raw augmented syscalls fix libbpf 1.0+ compatibility
authorIan Rogers <irogers@google.com>
Thu, 3 Nov 2022 04:54:31 +0000 (21:54 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Fri, 4 Nov 2022 14:33:40 +0000 (11:33 -0300)
Don't use deprecated and now broken map style. Avoid use of
tools/perf/include/bpf/bpf.h and use the more regular BPF headers.

Committer notes:

Add /usr/include to the include path so that bpf/bpf_helpers.h can be
found, remove sys/socket.h, adding the sockaddr_storage definition, also
remove stdbool.h, both were preventing building the
augmented_raw_syscalls.c file with clang, revisit later.

Testing it:

Asking for syscalls that have string arguments:

  # perf trace -e ~acme/git/perf/tools/perf/examples/bpf/augmented_raw_syscalls.c,string --max-events 10
     0.000 thermald/1144 openat(dfd: CWD, filename: "/sys/class/powercap/intel-rapl/intel-rapl:0/intel-rapl:0:2/energy_uj", flags: RDONLY) = 13
     0.158 thermald/1144 openat(dfd: CWD, filename: "/sys/class/powercap/intel-rapl/intel-rapl:0/energy_uj", flags: RDONLY) = 13
     0.215 thermald/1144 openat(dfd: CWD, filename: "/sys/class/thermal/thermal_zone3/temp", flags: RDONLY) = 13
    16.448 cgroupify/36478 openat(dfd: 4, filename: ".", flags: RDONLY|CLOEXEC|DIRECTORY|NONBLOCK) = 5
    16.468 cgroupify/36478 newfstatat(dfd: 5, filename: "", statbuf: 0x7fffca5b4130, flag: 4096) = 0
    16.473 systemd-oomd/972 openat(dfd: CWD, filename: "/proc/meminfo", flags: RDONLY|CLOEXEC) = 12
    16.499 systemd-oomd/972 newfstatat(dfd: 12, filename: "", statbuf: 0x7ffd2bc73cc0, flag: 4096) = 0
    16.516 abrt-dump-jour/1370 openat(dfd: CWD, filename: "/var/log/journal/d6a97235307247e09f13f326fb607e3c/system.journal", flags: RDONLY|CLOEXEC|NONBLOCK) = 21
    16.538 abrt-dump-jour/1370 newfstatat(dfd: 21, filename: "", statbuf: 0x7ffc651b8980, flag: 4096) = 0
    16.540 abrt-dump-jour/1371 openat(dfd: CWD, filename: "/var/log/journal/d6a97235307247e09f13f326fb607e3c/system.journal", flags: RDONLY|CLOEXEC|NONBLOCK) = 21
  #

Networking syscalls:

  # perf trace -e ~acme/git/perf/tools/perf/examples/bpf/augmented_raw_syscalls.c,sendto*,connect* --max-events 10
     0.000 isc-net-0005/1206 connect(fd: 512, uservaddr: { .family: INET, port: 53, addr: 23.211.132.65 }, addrlen: 16) = 0
     0.070 isc-net-0002/1203 connect(fd: 515, uservaddr: { .family: INET6, port: 53, addr: 2600:1401:2::43 }, addrlen: 28) = -1 ENETUNREACH (Network is unreachable)
     0.031 isc-net-0006/1207 connect(fd: 513, uservaddr: { .family: INET6, port: 53, addr: 2600:1401:2::43 }, addrlen: 28) = -1 ENETUNREACH (Network is unreachable)
     0.079 isc-net-0006/1207 sendto(fd: 3, buff: 0x7f73a40611b0, len: 106, flags: NOSIGNAL, addr: { .family: UNSPEC }, addr_len: NULL) = 106
     0.180 isc-net-0006/1207 connect(fd: 519, uservaddr: { .family: INET6, port: 53, addr: 2600:1401:1::43 }, addrlen: 28) = -1 ENETUNREACH (Network is unreachable)
     0.211 isc-net-0006/1207 sendto(fd: 3, buff: 0x7f73a4061230, len: 106, flags: NOSIGNAL, addr: { .family: UNSPEC }, addr_len: NULL) = 106
     0.298 isc-net-0006/1207 connect(fd: 515, uservaddr: { .family: INET, port: 53, addr: 96.7.49.67 }, addrlen: 16) = 0
     0.109 isc-net-0004/1205 connect(fd: 518, uservaddr: { .family: INET6, port: 53, addr: 2600:1401:2::43 }, addrlen: 28) = -1 ENETUNREACH (Network is unreachable)
     0.164 isc-net-0002/1203 sendto(fd: 3, buff: 0x7f73ac064300, len: 107, flags: NOSIGNAL, addr: { .family: UNSPEC }, addr_len: NULL) = 107
     0.247 isc-net-0002/1203 connect(fd: 522, uservaddr: { .family: INET6, port: 53, addr: 2600:1401:1::43 }, addrlen: 28) = -1 ENETUNREACH (Network is unreachable)
  #

Signed-off-by: Ian Rogers <irogers@google.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: https://lore.kernel.org/r/20221103045437.163510-2-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/Makefile.config
tools/perf/examples/bpf/augmented_raw_syscalls.c
tools/perf/util/llvm-utils.c

index d3d3c13..5942067 100644 (file)
@@ -1239,7 +1239,8 @@ includedir = $(abspath $(prefix)/$(includedir_relative))
 mandir = share/man
 infodir = share/info
 perfexecdir = libexec/perf-core
-perf_include_dir = lib/perf/include
+# FIXME: system's libbpf header directory, where we expect to find bpf/bpf_helpers.h, for instance
+perf_include_dir = /usr/include
 perf_examples_dir = lib/perf/examples
 sharedir = $(prefix)/share
 template_dir = share/perf-core/templates
index a262dcd..926238e 100644 (file)
  * code that will combine entry/exit in a strace like way.
  */
 
-#include <unistd.h>
+#include <linux/bpf.h>
+#include <bpf/bpf_helpers.h>
 #include <linux/limits.h>
-#include <linux/socket.h>
-#include <pid_filter.h>
+
+// FIXME: These should come from system headers
+typedef char bool;
+typedef int pid_t;
 
 /* bpf-output associated map */
-bpf_map(__augmented_syscalls__, PERF_EVENT_ARRAY, int, u32, __NR_CPUS__);
+struct __augmented_syscalls__ {
+       __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
+       __type(key, int);
+       __type(value, __u32);
+       __uint(max_entries, __NR_CPUS__);
+} __augmented_syscalls__ SEC(".maps");
 
 /*
  * string_args_len: one per syscall arg, 0 means not a string or don't copy it,
@@ -29,24 +37,39 @@ bpf_map(__augmented_syscalls__, PERF_EVENT_ARRAY, int, u32, __NR_CPUS__);
  */
 struct syscall {
        bool    enabled;
-       u16     string_args_len[6];
+       __u16   string_args_len[6];
 };
 
-bpf_map(syscalls, ARRAY, int, struct syscall, 512);
+struct syscalls {
+       __uint(type, BPF_MAP_TYPE_ARRAY);
+       __type(key, int);
+       __type(value, struct syscall);
+       __uint(max_entries, 512);
+} syscalls SEC(".maps");
 
 /*
  * What to augment at entry?
  *
  * Pointer arg payloads (filenames, etc) passed from userspace to the kernel
  */
-bpf_map(syscalls_sys_enter, PROG_ARRAY, u32, u32, 512);
+struct syscalls_sys_enter {
+       __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
+       __type(key, __u32);
+       __type(value, __u32);
+       __uint(max_entries, 512);
+} syscalls_sys_enter SEC(".maps");
 
 /*
  * What to augment at exit?
  *
  * Pointer arg payloads returned from the kernel (struct stat, etc) to userspace.
  */
-bpf_map(syscalls_sys_exit, PROG_ARRAY, u32, u32, 512);
+struct syscalls_sys_exit {
+       __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
+       __type(key, __u32);
+       __type(value, __u32);
+       __uint(max_entries, 512);
+} syscalls_sys_exit SEC(".maps");
 
 struct syscall_enter_args {
        unsigned long long common_tp_fields;
@@ -66,7 +89,38 @@ struct augmented_arg {
        char            value[PATH_MAX];
 };
 
-pid_filter(pids_filtered);
+struct pids_filtered {
+       __uint(type, BPF_MAP_TYPE_HASH);
+       __type(key, pid_t);
+       __type(value, bool);
+       __uint(max_entries, 64);
+} pids_filtered SEC(".maps");
+
+/*
+ * Desired design of maximum size and alignment (see RFC2553)
+ */
+#define SS_MAXSIZE   128     /* Implementation specific max size */
+
+typedef unsigned short sa_family_t;
+
+/*
+ * FIXME: Should come from system headers
+ *
+ * The definition uses anonymous union and struct in order to control the
+ * default alignment.
+ */
+struct sockaddr_storage {
+       union {
+               struct {
+                       sa_family_t    ss_family; /* address family */
+                       /* Following field(s) are implementation specific */
+                       char __data[SS_MAXSIZE - sizeof(unsigned short)];
+                               /* space to achieve desired size, */
+                               /* _SS_MAXSIZE value minus size of ss_family */
+               };
+               void *__align; /* implementation specific desired alignment */
+       };
+};
 
 struct augmented_args_payload {
        struct syscall_enter_args args;
@@ -79,7 +133,12 @@ struct augmented_args_payload {
 };
 
 // We need more tmp space than the BPF stack can give us
-bpf_map(augmented_args_tmp, PERCPU_ARRAY, int, struct augmented_args_payload, 1);
+struct augmented_args_tmp {
+       __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+       __type(key, int);
+       __type(value, struct augmented_args_payload);
+       __uint(max_entries, 1);
+} augmented_args_tmp SEC(".maps");
 
 static inline struct augmented_args_payload *augmented_args_payload(void)
 {
@@ -90,14 +149,14 @@ static inline struct augmented_args_payload *augmented_args_payload(void)
 static inline int augmented__output(void *ctx, struct augmented_args_payload *args, int len)
 {
        /* If perf_event_output fails, return non-zero so that it gets recorded unaugmented */
-       return perf_event_output(ctx, &__augmented_syscalls__, BPF_F_CURRENT_CPU, args, len);
+       return bpf_perf_event_output(ctx, &__augmented_syscalls__, BPF_F_CURRENT_CPU, args, len);
 }
 
 static inline
 unsigned int augmented_arg__read_str(struct augmented_arg *augmented_arg, const void *arg, unsigned int arg_len)
 {
        unsigned int augmented_len = sizeof(*augmented_arg);
-       int string_len = probe_read_str(&augmented_arg->value, arg_len, arg);
+       int string_len = bpf_probe_read_str(&augmented_arg->value, arg_len, arg);
 
        augmented_arg->size = augmented_arg->err = 0;
        /*
@@ -146,7 +205,7 @@ int sys_enter_connect(struct syscall_enter_args *args)
        if (socklen > sizeof(augmented_args->saddr))
                socklen = sizeof(augmented_args->saddr);
 
-       probe_read(&augmented_args->saddr, socklen, sockaddr_arg);
+       bpf_probe_read(&augmented_args->saddr, socklen, sockaddr_arg);
 
        return augmented__output(args, augmented_args, len + socklen);
 }
@@ -165,7 +224,7 @@ int sys_enter_sendto(struct syscall_enter_args *args)
        if (socklen > sizeof(augmented_args->saddr))
                socklen = sizeof(augmented_args->saddr);
 
-       probe_read(&augmented_args->saddr, socklen, sockaddr_arg);
+       bpf_probe_read(&augmented_args->saddr, socklen, sockaddr_arg);
 
        return augmented__output(args, augmented_args, len + socklen);
 }
@@ -234,6 +293,16 @@ int sys_enter_renameat(struct syscall_enter_args *args)
        return augmented__output(args, augmented_args, len);
 }
 
+static pid_t getpid(void)
+{
+       return bpf_get_current_pid_tgid();
+}
+
+static bool pid_filter__has(struct pids_filtered *pids, pid_t pid)
+{
+       return bpf_map_lookup_elem(pids, &pid) != NULL;
+}
+
 SEC("raw_syscalls:sys_enter")
 int sys_enter(struct syscall_enter_args *args)
 {
@@ -257,7 +326,7 @@ int sys_enter(struct syscall_enter_args *args)
        if (augmented_args == NULL)
                return 1;
 
-       probe_read(&augmented_args->args, sizeof(augmented_args->args), args);
+       bpf_probe_read(&augmented_args->args, sizeof(augmented_args->args), args);
 
        /*
         * Jump to syscall specific augmenter, even if the default one,
@@ -278,7 +347,7 @@ int sys_exit(struct syscall_exit_args *args)
        if (pid_filter__has(&pids_filtered, getpid()))
                return 0;
 
-       probe_read(&exit_args, sizeof(exit_args), args);
+       bpf_probe_read(&exit_args, sizeof(exit_args), args);
        /*
         * Jump to syscall specific return augmenter, even if the default one,
         * "!raw_syscalls:unaugmented" that will just return 1 to return the
@@ -291,4 +360,4 @@ int sys_exit(struct syscall_exit_args *args)
        return 0;
 }
 
-license(GPL);
+char _license[] SEC("license") = "GPL";
index 2dc7970..a5cac85 100644 (file)
@@ -495,7 +495,7 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
 
        snprintf(linux_version_code_str, sizeof(linux_version_code_str),
                 "0x%x", kernel_version);
-       if (asprintf(&perf_bpf_include_opts, "-I%s/bpf", perf_include_dir) < 0)
+       if (asprintf(&perf_bpf_include_opts, "-I%s/", perf_include_dir) < 0)
                goto errout;
        force_set_env("NR_CPUS", nr_cpus_avail_str);
        force_set_env("LINUX_VERSION_CODE", linux_version_code_str);