mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 22:21:42 +00:00
perf trace: Raw augmented syscalls fix libbpf 1.0+ compatibility
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>
This commit is contained in:
parent
92ea0720ba
commit
14e4b9f428
@ -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
|
||||
|
@ -14,13 +14,21 @@
|
||||
* 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";
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user