-
-
Notifications
You must be signed in to change notification settings - Fork 396
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
374 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
.vscode | ||
package.json | ||
*.o | ||
*.skel.json | ||
*.skel.yaml | ||
package.yaml | ||
ecli | ||
user_ringbuf |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) | ||
OUTPUT := .output | ||
CLANG ?= clang | ||
LIBBPF_SRC := $(abspath ../third_party/libbpf/src) | ||
BPFTOOL_SRC := $(abspath ../third_party/bpftool/src) | ||
LIBBPF_OBJ := $(abspath $(OUTPUT)/libbpf.a) | ||
BPFTOOL_OUTPUT ?= $(abspath $(OUTPUT)/bpftool) | ||
BPFTOOL ?= $(BPFTOOL_OUTPUT)/bootstrap/bpftool | ||
LIBBLAZESYM_SRC := $(abspath ../third_party/blazesym/) | ||
LIBBLAZESYM_OBJ := $(abspath $(OUTPUT)/libblazesym.a) | ||
LIBBLAZESYM_HEADER := $(abspath $(OUTPUT)/blazesym.h) | ||
ARCH ?= $(shell uname -m | sed 's/x86_64/x86/' \ | ||
| sed 's/arm.*/arm/' \ | ||
| sed 's/aarch64/arm64/' \ | ||
| sed 's/ppc64le/powerpc/' \ | ||
| sed 's/mips.*/mips/' \ | ||
| sed 's/riscv64/riscv/' \ | ||
| sed 's/loongarch64/loongarch/') | ||
VMLINUX := ../third_party/vmlinux/$(ARCH)/vmlinux.h | ||
# Use our own libbpf API headers and Linux UAPI headers distributed with | ||
# libbpf to avoid dependency on system-wide headers, which could be missing or | ||
# outdated | ||
INCLUDES := -I$(OUTPUT) -I../third_party/libbpf/include/uapi -I$(dir $(VMLINUX)) | ||
CFLAGS := -g -Wall | ||
ALL_LDFLAGS := $(LDFLAGS) $(EXTRA_LDFLAGS) | ||
|
||
APPS = user_ringbuf # minimal minimal_legacy uprobe kprobe fentry usdt sockfilter tc ksyscall | ||
|
||
CARGO ?= $(shell which cargo) | ||
ifeq ($(strip $(CARGO)),) | ||
BZS_APPS := | ||
else | ||
BZS_APPS := # profile | ||
APPS += $(BZS_APPS) | ||
# Required by libblazesym | ||
ALL_LDFLAGS += -lrt -ldl -lpthread -lm | ||
endif | ||
|
||
# Get Clang's default includes on this system. We'll explicitly add these dirs | ||
# to the includes list when compiling with `-target bpf` because otherwise some | ||
# architecture-specific dirs will be "missing" on some architectures/distros - | ||
# headers such as asm/types.h, asm/byteorder.h, asm/socket.h, asm/sockios.h, | ||
# sys/cdefs.h etc. might be missing. | ||
# | ||
# Use '-idirafter': Don't interfere with include mechanics except where the | ||
# build would have failed anyways. | ||
CLANG_BPF_SYS_INCLUDES ?= $(shell $(CLANG) -v -E - </dev/null 2>&1 \ | ||
| sed -n '/<...> search starts here:/,/End of search list./{ s| \(/.*\)|-idirafter \1|p }') | ||
|
||
ifeq ($(V),1) | ||
Q = | ||
msg = | ||
else | ||
Q = @ | ||
msg = @printf ' %-8s %s%s\n' \ | ||
"$(1)" \ | ||
"$(patsubst $(abspath $(OUTPUT))/%,%,$(2))" \ | ||
"$(if $(3), $(3))"; | ||
MAKEFLAGS += --no-print-directory | ||
endif | ||
|
||
define allow-override | ||
$(if $(or $(findstring environment,$(origin $(1))),\ | ||
$(findstring command line,$(origin $(1)))),,\ | ||
$(eval $(1) = $(2))) | ||
endef | ||
|
||
$(call allow-override,CC,$(CROSS_COMPILE)cc) | ||
$(call allow-override,LD,$(CROSS_COMPILE)ld) | ||
|
||
.PHONY: all | ||
all: $(APPS) | ||
|
||
.PHONY: clean | ||
clean: | ||
$(call msg,CLEAN) | ||
$(Q)rm -rf $(OUTPUT) $(APPS) | ||
|
||
$(OUTPUT) $(OUTPUT)/libbpf $(BPFTOOL_OUTPUT): | ||
$(call msg,MKDIR,$@) | ||
$(Q)mkdir -p $@ | ||
|
||
# Build libbpf | ||
$(LIBBPF_OBJ): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(OUTPUT)/libbpf | ||
$(call msg,LIB,$@) | ||
$(Q)$(MAKE) -C $(LIBBPF_SRC) BUILD_STATIC_ONLY=1 \ | ||
OBJDIR=$(dir $@)/libbpf DESTDIR=$(dir $@) \ | ||
INCLUDEDIR= LIBDIR= UAPIDIR= \ | ||
install | ||
|
||
# Build bpftool | ||
$(BPFTOOL): | $(BPFTOOL_OUTPUT) | ||
$(call msg,BPFTOOL,$@) | ||
$(Q)$(MAKE) ARCH= CROSS_COMPILE= OUTPUT=$(BPFTOOL_OUTPUT)/ -C $(BPFTOOL_SRC) bootstrap | ||
|
||
|
||
$(LIBBLAZESYM_SRC)/target/release/libblazesym.a:: | ||
$(Q)cd $(LIBBLAZESYM_SRC) && $(CARGO) build --features=cheader,dont-generate-test-files --release | ||
|
||
$(LIBBLAZESYM_OBJ): $(LIBBLAZESYM_SRC)/target/release/libblazesym.a | $(OUTPUT) | ||
$(call msg,LIB, $@) | ||
$(Q)cp $(LIBBLAZESYM_SRC)/target/release/libblazesym.a $@ | ||
|
||
$(LIBBLAZESYM_HEADER): $(LIBBLAZESYM_SRC)/target/release/libblazesym.a | $(OUTPUT) | ||
$(call msg,LIB,$@) | ||
$(Q)cp $(LIBBLAZESYM_SRC)/target/release/blazesym.h $@ | ||
|
||
# Build BPF code | ||
$(OUTPUT)/%.bpf.o: %.bpf.c $(LIBBPF_OBJ) $(wildcard %.h) $(VMLINUX) | $(OUTPUT) $(BPFTOOL) | ||
$(call msg,BPF,$@) | ||
$(Q)$(CLANG) -g -O2 -target bpf -D__TARGET_ARCH_$(ARCH) \ | ||
$(INCLUDES) $(CLANG_BPF_SYS_INCLUDES) \ | ||
-c $(filter %.c,$^) -o $(patsubst %.bpf.o,%.tmp.bpf.o,$@) | ||
$(Q)$(BPFTOOL) gen object $@ $(patsubst %.bpf.o,%.tmp.bpf.o,$@) | ||
|
||
# Generate BPF skeletons | ||
$(OUTPUT)/%.skel.h: $(OUTPUT)/%.bpf.o | $(OUTPUT) $(BPFTOOL) | ||
$(call msg,GEN-SKEL,$@) | ||
$(Q)$(BPFTOOL) gen skeleton $< > $@ | ||
|
||
# Build user-space code | ||
$(patsubst %,$(OUTPUT)/%.o,$(APPS)): %.o: %.skel.h | ||
|
||
$(OUTPUT)/%.o: %.c $(wildcard %.h) | $(OUTPUT) | ||
$(call msg,CC,$@) | ||
$(Q)$(CC) $(CFLAGS) $(INCLUDES) -c $(filter %.c,$^) -o $@ | ||
|
||
$(patsubst %,$(OUTPUT)/%.o,$(BZS_APPS)): $(LIBBLAZESYM_HEADER) | ||
|
||
$(BZS_APPS): $(LIBBLAZESYM_OBJ) | ||
|
||
# Build application binary | ||
$(APPS): %: $(OUTPUT)/%.o $(LIBBPF_OBJ) | $(OUTPUT) | ||
$(call msg,BINARY,$@) | ||
$(Q)$(CC) $(CFLAGS) $^ $(ALL_LDFLAGS) -lelf -lz -o $@ | ||
|
||
# delete failed targets | ||
.DELETE_ON_ERROR: | ||
|
||
# keep intermediate (.skel.h, .bpf.o, etc) targets | ||
.SECONDARY: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */ | ||
|
||
#include "vmlinux.h" | ||
#include <bpf/bpf_helpers.h> | ||
#include <bpf/bpf_tracing.h> | ||
#include <bpf/bpf_core_read.h> | ||
#include "user_ringbuf.h" | ||
|
||
char _license[] SEC("license") = "GPL"; | ||
|
||
struct { | ||
__uint(type, BPF_MAP_TYPE_USER_RINGBUF); | ||
__uint(max_entries, 256 * 1024); | ||
} user_ringbuf SEC(".maps"); | ||
|
||
struct { | ||
__uint(type, BPF_MAP_TYPE_RINGBUF); | ||
__uint(max_entries, 256 * 1024); | ||
} kernel_ringbuf SEC(".maps"); | ||
|
||
int read = 0; | ||
|
||
static long | ||
do_nothing_cb(struct bpf_dynptr *dynptr, void *context) | ||
{ | ||
struct event *e; | ||
pid_t pid; | ||
/* get PID and TID of exiting thread/process */ | ||
pid = bpf_get_current_pid_tgid() >> 32; | ||
|
||
/* reserve sample from BPF ringbuf */ | ||
e = bpf_ringbuf_reserve(&kernel_ringbuf, sizeof(*e), 0); | ||
if (!e) | ||
return 0; | ||
|
||
e->pid = pid; | ||
bpf_get_current_comm(&e->comm, sizeof(e->comm)); | ||
|
||
/* send data to user-space for post-processing */ | ||
bpf_ringbuf_submit(e, 0); | ||
__sync_fetch_and_add(&read, 1); | ||
return 0; | ||
} | ||
|
||
SEC("tracepoint/syscalls/sys_exit_kill") | ||
int kill_exit(struct trace_event_raw_sys_exit *ctx) | ||
{ | ||
long num_samples; | ||
int err = 0; | ||
|
||
num_samples = bpf_user_ringbuf_drain(&user_ringbuf, do_nothing_cb, NULL, 0); | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) | ||
/* Copyright (c) 2020 Facebook */ | ||
#include <argp.h> | ||
#include <signal.h> | ||
#include <stdio.h> | ||
#include <time.h> | ||
#include <sys/resource.h> | ||
#include <bpf/libbpf.h> | ||
#include "user_ringbuf.h" | ||
#include "user_ringbuf.skel.h" | ||
|
||
static void drain_current_samples(void) | ||
{ | ||
printf("Draining current samples...\n"); | ||
} | ||
|
||
static int write_samples(struct user_ring_buffer *ringbuf) | ||
{ | ||
int i, err = 0; | ||
struct user_sample *entry; | ||
|
||
entry = user_ring_buffer__reserve(ringbuf, sizeof(*entry)); | ||
if (!entry) { | ||
err = -errno; | ||
goto done; | ||
} | ||
|
||
entry->i = getpid(); | ||
strcpy(entry->comm, "hello"); | ||
|
||
int read = snprintf(entry->comm, sizeof(entry->comm), "%u", i); | ||
if (read <= 0) { | ||
/* Assert on the error path to avoid spamming logs with | ||
* mostly success messages. | ||
*/ | ||
err = read; | ||
user_ring_buffer__discard(ringbuf, entry); | ||
goto done; | ||
} | ||
|
||
user_ring_buffer__submit(ringbuf, entry); | ||
|
||
done: | ||
drain_current_samples(); | ||
|
||
return err; | ||
} | ||
|
||
static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args) | ||
{ | ||
return vfprintf(stderr, format, args); | ||
} | ||
|
||
static volatile bool exiting = false; | ||
|
||
static void sig_handler(int sig) | ||
{ | ||
exiting = true; | ||
} | ||
|
||
struct user_ring_buffer *user_ringbuf = NULL; | ||
|
||
static int handle_event(void *ctx, void *data, size_t data_sz) | ||
{ | ||
const struct event *e = data; | ||
struct tm *tm; | ||
char ts[32]; | ||
time_t t; | ||
|
||
time(&t); | ||
tm = localtime(&t); | ||
strftime(ts, sizeof(ts), "%H:%M:%S", tm); | ||
|
||
printf("%-8s %-5s %-16s %-7d\n", | ||
ts, "SIGN", e->comm, e->pid); | ||
write_samples(user_ringbuf); | ||
return 0; | ||
} | ||
|
||
int main(int argc, char **argv) | ||
{ | ||
struct ring_buffer *rb = NULL; | ||
struct user_ringbuf_bpf *skel; | ||
int err; | ||
|
||
/* Set up libbpf errors and debug info callback */ | ||
libbpf_set_print(libbpf_print_fn); | ||
|
||
/* Cleaner handling of Ctrl-C */ | ||
signal(SIGINT, sig_handler); | ||
signal(SIGTERM, sig_handler); | ||
|
||
/* Load and verify BPF application */ | ||
skel = user_ringbuf_bpf__open(); | ||
if (!skel) { | ||
fprintf(stderr, "Failed to open and load BPF skeleton\n"); | ||
return 1; | ||
} | ||
|
||
/* Parameterize BPF code with minimum duration parameter */ | ||
skel->bss->read = 0; | ||
|
||
/* Load & verify BPF programs */ | ||
err = user_ringbuf_bpf__load(skel); | ||
if (err) { | ||
fprintf(stderr, "Failed to load and verify BPF skeleton\n"); | ||
goto cleanup; | ||
} | ||
|
||
/* Attach tracepoints */ | ||
err = user_ringbuf_bpf__attach(skel); | ||
if (err) { | ||
fprintf(stderr, "Failed to attach BPF skeleton\n"); | ||
goto cleanup; | ||
} | ||
|
||
/* Set up ring buffer polling */ | ||
rb = ring_buffer__new(bpf_map__fd(skel->maps.kernel_ringbuf), handle_event, NULL, NULL); | ||
if (!rb) { | ||
err = -1; | ||
fprintf(stderr, "Failed to create ring buffer\n"); | ||
goto cleanup; | ||
} | ||
user_ringbuf = user_ring_buffer__new(bpf_map__fd(skel->maps.user_ringbuf), NULL); | ||
|
||
write_samples(user_ringbuf); | ||
|
||
/* Process events */ | ||
printf("%-8s %-5s %-16s %-7s %-7s %s\n", | ||
"TIME", "EVENT", "COMM", "PID", "PPID", "FILENAME/EXIT CODE"); | ||
while (!exiting) { | ||
err = ring_buffer__poll(rb, 100 /* timeout, ms */); | ||
/* Ctrl-C will cause -EINTR */ | ||
if (err == -EINTR) { | ||
err = 0; | ||
break; | ||
} | ||
if (err < 0) { | ||
printf("Error polling perf buffer: %d\n", err); | ||
break; | ||
} | ||
} | ||
|
||
cleanup: | ||
/* Clean up */ | ||
ring_buffer__free(rb); | ||
user_ringbuf_bpf__destroy(skel); | ||
user_ring_buffer__free(user_ringbuf); | ||
|
||
return err < 0 ? -err : 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ | ||
/* Copyright (c) 2020 Facebook */ | ||
#ifndef __BOOTSTRAP_H | ||
#define __BOOTSTRAP_H | ||
|
||
#define TASK_COMM_LEN 16 | ||
#define MAX_FILENAME_LEN 127 | ||
|
||
struct event { | ||
int pid; | ||
char comm[TASK_COMM_LEN]; | ||
}; | ||
|
||
struct user_sample { | ||
int i; | ||
char comm[TASK_COMM_LEN]; | ||
}; | ||
|
||
#endif /* __BOOTSTRAP_H */ |