diff --git a/.gitignore b/.gitignore index ab9e546..9186af5 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ /0002-Use-libbpf-static-instead-of-libbpf-debugsource-for-.patch /bcc-src-with-submodule.tar.gz /bcc-0.20.0.tar.gz +/bcc-0.24.0.tar.gz diff --git a/bcc-0.20.0-Define-KERNEL_VERSION.patch b/bcc-0.20.0-Define-KERNEL_VERSION.patch deleted file mode 100644 index 959eae5..0000000 --- a/bcc-0.20.0-Define-KERNEL_VERSION.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 6516fb0d00208f05b29f320176204957b02b23e3 Mon Sep 17 00:00:00 2001 -From: Jerome Marchand -Date: Mon, 26 Jul 2021 12:05:57 +0200 -Subject: [PATCH] Define KERNEL_VERSION - -The libbpf version on RHEL9 doesn't define it. ---- - libbpf-tools/biolatency.bpf.c | 2 ++ - libbpf-tools/biosnoop.bpf.c | 2 ++ - libbpf-tools/bitesize.bpf.c | 2 ++ - 3 files changed, 6 insertions(+) - -diff --git a/libbpf-tools/biolatency.bpf.c b/libbpf-tools/biolatency.bpf.c -index 8d8fe584..8e6e81e2 100644 ---- a/libbpf-tools/biolatency.bpf.c -+++ b/libbpf-tools/biolatency.bpf.c -@@ -9,6 +9,8 @@ - - #define MAX_ENTRIES 10240 - -+#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c)) -+ - extern int LINUX_KERNEL_VERSION __kconfig; - - const volatile bool targ_per_disk = false; -diff --git a/libbpf-tools/biosnoop.bpf.c b/libbpf-tools/biosnoop.bpf.c -index 76697967..7b7cb1a4 100644 ---- a/libbpf-tools/biosnoop.bpf.c -+++ b/libbpf-tools/biosnoop.bpf.c -@@ -11,6 +11,8 @@ - const volatile bool targ_queued = false; - const volatile dev_t targ_dev = -1; - -+#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c)) -+ - extern __u32 LINUX_KERNEL_VERSION __kconfig; - - struct piddata { -diff --git a/libbpf-tools/bitesize.bpf.c b/libbpf-tools/bitesize.bpf.c -index 7b4d3f9d..5e7d9d97 100644 ---- a/libbpf-tools/bitesize.bpf.c -+++ b/libbpf-tools/bitesize.bpf.c -@@ -10,6 +10,8 @@ - const volatile char targ_comm[TASK_COMM_LEN] = {}; - const volatile dev_t targ_dev = -1; - -+#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c)) -+ - extern __u32 LINUX_KERNEL_VERSION __kconfig; - - struct { --- -2.31.1 - diff --git a/bcc-0.20.0-Fix-a-llvm-compilation-error.patch b/bcc-0.20.0-Fix-a-llvm-compilation-error.patch deleted file mode 100644 index 5c15817..0000000 --- a/bcc-0.20.0-Fix-a-llvm-compilation-error.patch +++ /dev/null @@ -1,46 +0,0 @@ -From e2a4a556755d3c5ae7538ba9bcb731f93b9f81c9 Mon Sep 17 00:00:00 2001 -From: Yonghong Song -Date: Tue, 25 May 2021 19:58:00 -0700 -Subject: [PATCH] Fix a llvm compilation error -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Current llvm trunk (https://github.com/llvm/llvm-project) -will cause the following compilation errors: - /home/yhs/work/bcc/src/cc/bcc_debug.cc: In member function ‘void ebpf::SourceDebugger::dump()’: - /home/yhs/work/bcc/src/cc/bcc_debug.cc:135:75: error: no matching function for call to - ‘llvm::MCContext::MCContext(llvm::Triple&, std::unique_ptr::pointer, - std::unique_ptr::pointer, llvm::MCObjectFileInfo*, - std::unique_ptr::pointer, std::nullptr_t)’ - MCContext Ctx(TheTriple, MAI.get(), MRI.get(), &MOFI, STI.get(), nullptr); - ^ - ...... - -This is because upstream patch https://reviews.llvm.org/D101921 -refactored MCObjectFileInfo initialization and changed MCContext -constructor signature. - -This patch fixed the issue by following the new code patterns -in https://reviews.llvm.org/D101921. ---- - src/cc/bcc_debug.cc | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/src/cc/bcc_debug.cc b/src/cc/bcc_debug.cc -index 775c9141..97d6d95b 100644 ---- a/src/cc/bcc_debug.cc -+++ b/src/cc/bcc_debug.cc -@@ -132,7 +132,8 @@ void SourceDebugger::dump() { - T->createMCSubtargetInfo(TripleStr, "", "")); - MCObjectFileInfo MOFI; - #if LLVM_MAJOR_VERSION >= 13 -- MCContext Ctx(TheTriple, MAI.get(), MRI.get(), &MOFI, STI.get(), nullptr); -+ MCContext Ctx(TheTriple, MAI.get(), MRI.get(), STI.get(), nullptr); -+ Ctx.setObjectFileInfo(&MOFI); - MOFI.initMCObjectFileInfo(Ctx, false, false); - #else - MCContext Ctx(MAI.get(), MRI.get(), &MOFI, nullptr); --- -2.31.1 - diff --git a/bcc-0.20.0-Handle-renaming-of-task_struct_-state-field-on-RHEL-.patch b/bcc-0.20.0-Handle-renaming-of-task_struct_-state-field-on-RHEL-.patch deleted file mode 100644 index 6a35839..0000000 --- a/bcc-0.20.0-Handle-renaming-of-task_struct_-state-field-on-RHEL-.patch +++ /dev/null @@ -1,96 +0,0 @@ -From 019615235458a9486d883a675a3ea16014ee597f Mon Sep 17 00:00:00 2001 -From: Jerome Marchand -Date: Thu, 14 Oct 2021 12:01:01 +0200 -Subject: [PATCH] Handle renaming of task_struct_>state field on RHEL 9 - -There has been some cleanup of task_struct's state field and to catch -any place that has been missed in the conversion, it has been renamed -__state. ---- - tools/offcputime.py | 4 ++-- - tools/offwaketime.py | 4 ++-- - tools/runqlat.py | 4 ++-- - tools/runqslower.py | 4 ++-- - 4 files changed, 8 insertions(+), 8 deletions(-) - -diff --git a/tools/offcputime.py b/tools/offcputime.py -index 128c6496..b93e78d2 100755 ---- a/tools/offcputime.py -+++ b/tools/offcputime.py -@@ -205,10 +205,10 @@ thread_context = "" - thread_context = "all threads" - thread_filter = '1' - if args.state == 0: -- state_filter = 'prev->state == 0' -+ state_filter = 'prev->__state == 0' - elif args.state: - # these states are sometimes bitmask checked -- state_filter = 'prev->state & %d' % args.state -+ state_filter = 'prev->__state & %d' % args.state - else: - state_filter = '1' - bpf_text = bpf_text.replace('THREAD_FILTER', thread_filter) -diff --git a/tools/offwaketime.py b/tools/offwaketime.py -index 753eee97..722c0381 100755 ---- a/tools/offwaketime.py -+++ b/tools/offwaketime.py -@@ -254,10 +254,10 @@ int oncpu(struct pt_regs *ctx, struct task_struct *p) { - else: - thread_filter = '1' - if args.state == 0: -- state_filter = 'p->state == 0' -+ state_filter = 'p->__state == 0' - elif args.state: - # these states are sometimes bitmask checked -- state_filter = 'p->state & %d' % args.state -+ state_filter = 'p->__state & %d' % args.state - else: - state_filter = '1' - bpf_text = bpf_text.replace('THREAD_FILTER', thread_filter) -diff --git a/tools/runqlat.py b/tools/runqlat.py -index b13ff2d1..8e443c3c 100755 ---- a/tools/runqlat.py -+++ b/tools/runqlat.py -@@ -116,7 +116,7 @@ int trace_run(struct pt_regs *ctx, struct task_struct *prev) - u32 pid, tgid; - - // ivcsw: treat like an enqueue event and store timestamp -- if (prev->state == TASK_RUNNING) { -+ if (prev->__state == TASK_RUNNING) { - tgid = prev->tgid; - pid = prev->pid; - if (!(FILTER || pid == 0)) { -@@ -170,7 +170,7 @@ RAW_TRACEPOINT_PROBE(sched_switch) - u32 pid, tgid; - - // ivcsw: treat like an enqueue event and store timestamp -- if (prev->state == TASK_RUNNING) { -+ if (prev->__state == TASK_RUNNING) { - tgid = prev->tgid; - pid = prev->pid; - if (!(FILTER || pid == 0)) { -diff --git a/tools/runqslower.py b/tools/runqslower.py -index 6df98d9f..ba71e5d3 100755 ---- a/tools/runqslower.py -+++ b/tools/runqslower.py -@@ -112,7 +112,7 @@ int trace_run(struct pt_regs *ctx, struct task_struct *prev) - u32 pid, tgid; - - // ivcsw: treat like an enqueue event and store timestamp -- if (prev->state == TASK_RUNNING) { -+ if (prev->__state == TASK_RUNNING) { - tgid = prev->tgid; - pid = prev->pid; - u64 ts = bpf_ktime_get_ns(); -@@ -178,7 +178,7 @@ RAW_TRACEPOINT_PROBE(sched_switch) - long state; - - // ivcsw: treat like an enqueue event and store timestamp -- bpf_probe_read_kernel(&state, sizeof(long), (const void *)&prev->state); -+ bpf_probe_read_kernel(&state, sizeof(long), (const void *)&prev->__state); - if (state == TASK_RUNNING) { - bpf_probe_read_kernel(&tgid, sizeof(prev->tgid), &prev->tgid); - bpf_probe_read_kernel(&pid, sizeof(prev->pid), &prev->pid); --- -2.31.1 - diff --git a/bcc-0.20.0-Remove-APInt-APSInt-toString-std-string-variants.patch b/bcc-0.20.0-Remove-APInt-APSInt-toString-std-string-variants.patch deleted file mode 100644 index 182209e..0000000 --- a/bcc-0.20.0-Remove-APInt-APSInt-toString-std-string-variants.patch +++ /dev/null @@ -1,41 +0,0 @@ -From fd0585d5d8a1a47912ae7a70721d3cab0c7d06f8 Mon Sep 17 00:00:00 2001 -From: Khem Raj -Date: Mon, 14 Jun 2021 12:49:43 -0700 -Subject: [PATCH] Remove APInt/APSInt toString() std::string variants - -clang 13+ has removed this in favour of a pair of llvm::toString -() helpers inside StringExtras.h to improve compile speed by avoiding -hits on header - -Signed-off-by: Khem Raj ---- - src/cc/json_map_decl_visitor.cc | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/src/cc/json_map_decl_visitor.cc b/src/cc/json_map_decl_visitor.cc -index eff4d067..53896199 100644 ---- a/src/cc/json_map_decl_visitor.cc -+++ b/src/cc/json_map_decl_visitor.cc -@@ -20,6 +20,7 @@ - #include - #include - #include -+#include - #include "common.h" - #include "table_desc.h" - -@@ -79,7 +80,11 @@ void BMapDeclVisitor::genJSONForField(FieldDecl *F) { - result_ += "["; - TraverseDecl(F); - if (const ConstantArrayType *T = dyn_cast(F->getType())) -+#if LLVM_MAJOR_VERSION >= 13 -+ result_ += ", [" + toString(T->getSize(), 10, false) + "]"; -+#else - result_ += ", [" + T->getSize().toString(10, false) + "]"; -+#endif - if (F->isBitField()) - result_ += ", " + to_string(F->getBitWidthValue(C)); - result_ += "], "; --- -2.31.1 - diff --git a/bcc-0.20.0-Revert-libbpf-tools-remove-unecessary-custom-NULL-de.patch b/bcc-0.20.0-Revert-libbpf-tools-remove-unecessary-custom-NULL-de.patch deleted file mode 100644 index 47cccef..0000000 --- a/bcc-0.20.0-Revert-libbpf-tools-remove-unecessary-custom-NULL-de.patch +++ /dev/null @@ -1,41 +0,0 @@ -From aaa39601b756074e9ba8b9a607102a1ae0cb4c94 Mon Sep 17 00:00:00 2001 -From: Jerome Marchand -Date: Mon, 26 Jul 2021 14:45:37 +0200 -Subject: [PATCH] Revert "libbpf-tools: remove unecessary custom NULL - definitions" - -Libbpf on RHEL does not define NULL -This reverts commit a9f461d74a84be2f96fd35c02cf98c7251bd4166. ---- - libbpf-tools/biostacks.bpf.c | 1 + - libbpf-tools/xfsslower.bpf.c | 2 ++ - 2 files changed, 3 insertions(+) - -diff --git a/libbpf-tools/biostacks.bpf.c b/libbpf-tools/biostacks.bpf.c -index f02a1ac5..6ed0bda6 100644 ---- a/libbpf-tools/biostacks.bpf.c -+++ b/libbpf-tools/biostacks.bpf.c -@@ -9,6 +9,7 @@ - #include "maps.bpf.h" - - #define MAX_ENTRIES 10240 -+#define NULL 0 - - const volatile bool targ_ms = false; - const volatile dev_t targ_dev = -1; -diff --git a/libbpf-tools/xfsslower.bpf.c b/libbpf-tools/xfsslower.bpf.c -index 05962f46..2b1c6e4b 100644 ---- a/libbpf-tools/xfsslower.bpf.c -+++ b/libbpf-tools/xfsslower.bpf.c -@@ -6,6 +6,8 @@ - #include - #include "xfsslower.h" - -+#define NULL 0 -+ - const volatile pid_t targ_tgid = 0; - const volatile __u64 min_lat = 0; - --- -2.31.1 - diff --git a/bcc-0.20.0-Update-cpudist.py.patch b/bcc-0.20.0-Update-cpudist.py.patch deleted file mode 100644 index 492c72f..0000000 --- a/bcc-0.20.0-Update-cpudist.py.patch +++ /dev/null @@ -1,41 +0,0 @@ -From ad56e8a5a722df2ac2a5b3ea0822fd78f9a6fe51 Mon Sep 17 00:00:00 2001 -From: Nick-nizhen <74173686+Nick-nizhen@users.noreply.github.com> -Date: Thu, 27 May 2021 13:21:59 +0800 -Subject: [PATCH] Update cpudist.py - -When calculating the ONCPU time, prev has left the CPU already. It is not necessary to judge whether the process state is TASK_RUNNING or not. ---- - tools/cpudist.py | 14 ++++---------- - 1 file changed, 4 insertions(+), 10 deletions(-) - -diff --git a/tools/cpudist.py b/tools/cpudist.py -index eb04f590..b5a6a978 100755 ---- a/tools/cpudist.py -+++ b/tools/cpudist.py -@@ -100,19 +100,13 @@ int sched_switch(struct pt_regs *ctx, struct task_struct *prev) - u64 pid_tgid = bpf_get_current_pid_tgid(); - u32 tgid = pid_tgid >> 32, pid = pid_tgid; - -+ u32 prev_pid = prev->pid; -+ u32 prev_tgid = prev->tgid; - #ifdef ONCPU -- if (prev->state == TASK_RUNNING) { -+ update_hist(prev_tgid, prev_pid, ts); - #else -- if (1) { -+ store_start(prev_tgid, prev_pid, ts); - #endif -- u32 prev_pid = prev->pid; -- u32 prev_tgid = prev->tgid; --#ifdef ONCPU -- update_hist(prev_tgid, prev_pid, ts); --#else -- store_start(prev_tgid, prev_pid, ts); --#endif -- } - - BAIL: - #ifdef ONCPU --- -2.31.1 - diff --git a/bcc-0.20.0-libbpf-tool-don-t-ignore-LDFLAGS.patch b/bcc-0.20.0-libbpf-tool-don-t-ignore-LDFLAGS.patch deleted file mode 100644 index 6f73a5c..0000000 --- a/bcc-0.20.0-libbpf-tool-don-t-ignore-LDFLAGS.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 657f1b2049f2c7751a9d2a13abb42c409da1bb6f Mon Sep 17 00:00:00 2001 -From: Jerome Marchand -Date: Wed, 2 Jun 2021 14:23:20 +0200 -Subject: [PATCH] libbpf-tool: don't ignore LDFLAGS - ---- - libbpf-tools/Makefile | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/libbpf-tools/Makefile b/libbpf-tools/Makefile -index 92dcf5a5..54288380 100644 ---- a/libbpf-tools/Makefile -+++ b/libbpf-tools/Makefile -@@ -77,7 +77,7 @@ endif - - $(APPS): %: $(OUTPUT)/%.o $(LIBBPF_OBJ) $(COMMON_OBJ) | $(OUTPUT) - $(call msg,BINARY,$@) -- $(Q)$(CC) $(CFLAGS) $^ -lelf -lz -o $@ -+ $(Q)$(CC) $(CFLAGS) $^ $(LDFLAGS) -lelf -lz -o $@ - - $(patsubst %,$(OUTPUT)/%.o,$(APPS)): %.o: %.skel.h - --- -2.31.1 - diff --git a/bcc-0.20.0-libbpf-tools-readahead-don-t-mark-struct-hist-as-sta.patch b/bcc-0.20.0-libbpf-tools-readahead-don-t-mark-struct-hist-as-sta.patch deleted file mode 100644 index 204865b..0000000 --- a/bcc-0.20.0-libbpf-tools-readahead-don-t-mark-struct-hist-as-sta.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 4e2851687904cff7ab4f8faa862b9046e5aaab09 Mon Sep 17 00:00:00 2001 -From: Jerome Marchand -Date: Fri, 30 Jul 2021 18:15:05 +0200 -Subject: [PATCH] libbpf-tools: readahead: don't mark struct hist as static - -Libbpf readahead tool does not compile with bpftool v5.14. Since -commit 31332ccb756 ("bpftool: Stop emitting static variables in BPF -skeleton"), bpftool gen skeleton does not include static variable into -the skeleton file anymore. - -Fixes the following compilation error: -readahead.c: In function 'main': -readahead.c:153:26: error: 'struct readahead_bpf__bss' has no member named 'hist' - 153 | histp = &obj->bss->hist; - | ^~ ---- - libbpf-tools/readahead.bpf.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/libbpf-tools/readahead.bpf.c b/libbpf-tools/readahead.bpf.c -index ba22e534..cfead704 100644 ---- a/libbpf-tools/readahead.bpf.c -+++ b/libbpf-tools/readahead.bpf.c -@@ -24,7 +24,7 @@ struct { - __uint(map_flags, BPF_F_NO_PREALLOC); - } birth SEC(".maps"); - --static struct hist hist; -+struct hist hist = {}; - - SEC("fentry/do_page_cache_ra") - int BPF_PROG(do_page_cache_ra) --- -2.31.1 - diff --git a/bcc-0.20.0-sync-with-latest-libbpf-repo-3529.patch b/bcc-0.20.0-sync-with-latest-libbpf-repo-3529.patch deleted file mode 100644 index 10765ef..0000000 --- a/bcc-0.20.0-sync-with-latest-libbpf-repo-3529.patch +++ /dev/null @@ -1,408 +0,0 @@ -From 0c12dfe26a362db181e6172cb56a39cd002a6892 Mon Sep 17 00:00:00 2001 -From: yonghong-song -Date: Sun, 18 Jul 2021 15:05:34 -0700 -Subject: [PATCH] sync with latest libbpf repo (#3529) - -sync with latest libbpf repo which is upto commit - 21f90f61b084 sync: latest libbpf changes from kernel - -Signed-off-by: Yonghong Song ---- - docs/kernel-versions.md | 8 ++ - introspection/bps.c | 1 + - src/cc/compat/linux/virtual_bpf.h | 167 ++++++++++++++++++++++++++++-- - src/cc/export/helpers.h | 17 +++ - src/cc/libbpf.c | 8 ++ - 5 files changed, 190 insertions(+), 11 deletions(-) - -diff --git a/docs/kernel-versions.md b/docs/kernel-versions.md -index 9192aa43..33318624 100644 ---- a/docs/kernel-versions.md -+++ b/docs/kernel-versions.md -@@ -208,6 +208,7 @@ Helper | Kernel version | License | Commit | - -------|----------------|---------|--------| - `BPF_FUNC_bind()` | 4.17 | | [`d74bad4e74ee`](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=d74bad4e74ee373787a9ae24197c17b7cdc428d5) | - `BPF_FUNC_bprm_opts_set()` | 5.11 | | [`3f6719c7b62f`](https://github.com/torvalds/linux/commit/3f6719c7b62f0327c9091e26d0da10e65668229e) -+`BPF_FUNC_btf_find_by_name_kind()` | 5.14 | | [`3d78417b60fb`](https://github.com/torvalds/linux/commit/3d78417b60fba249cc555468cb72d96f5cde2964) - `BPF_FUNC_check_mtu()` | 5.12 | | [`34b2021cc616`](https://github.com/torvalds/linux/commit/34b2021cc61642d61c3cf943d9e71925b827941b) - `BPF_FUNC_clone_redirect()` | 4.2 | | [`3896d655f4d4`](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=3896d655f4d491c67d669a15f275a39f713410f8) - `BPF_FUNC_copy_from_user()` | 5.10 | | [`07be4c4a3e7a`](https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/commit?id=07be4c4a3e7a0db148e44b16c5190e753d1c8569) -@@ -226,6 +227,7 @@ Helper | Kernel version | License | Commit | - `BPF_FUNC_get_current_task()` | 4.8 | GPL | [`606274c5abd8`](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=606274c5abd8e245add01bc7145a8cbb92b69ba8) - `BPF_FUNC_get_current_task_btf()` | 5.11 | GPL | [`3ca1032ab7ab`](https://github.com/torvalds/linux/commit/3ca1032ab7ab010eccb107aa515598788f7d93bb) - `BPF_FUNC_get_current_uid_gid()` | 4.2 | | [`ffeedafbf023`](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=ffeedafbf0236f03aeb2e8db273b3e5ae5f5bc89) -+`BPF_FUNC_get_func_ip()` | 5.15 | | [`5d8b583d04ae`](https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/commit/?id=5d8b583d04aedb3bd5f6d227a334c210c7d735f9) - `BPF_FUNC_get_hash_recalc()` | 4.8 | | [`13c5c240f789`](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=13c5c240f789bbd2bcacb14a23771491485ae61f) - `BPF_FUNC_get_listener_sock()` | 5.1 | | [`dbafd7ddd623`](https://kernel.googlesource.com/pub/scm/linux/kernel/git/davem/net-next/+/dbafd7ddd62369b2f3926ab847cbf8fc40e800b7) - `BPF_FUNC_get_local_storage()` | 4.19 | | [`cd3394317653`](https://github.com/torvalds/linux/commit/cd3394317653837e2eb5c5d0904a8996102af9fc) -@@ -352,6 +354,8 @@ Helper | Kernel version | License | Commit | - `BPF_FUNC_store_hdr_opt()` | 5.10 | | [`0813a841566f`](https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/commit?id=0813a841566f0962a5551be7749b43c45f0022a0) - `BPF_FUNC_strtol()` | 5.2 | | [`d7a4cb9b6705`](https://kernel.googlesource.com/pub/scm/linux/kernel/git/davem/net-next/+/d7a4cb9b6705a89937d12c8158a35a3145dc967a) - `BPF_FUNC_strtoul()` | 5.2 | | [`d7a4cb9b6705`](https://kernel.googlesource.com/pub/scm/linux/kernel/git/davem/net-next/+/d7a4cb9b6705a89937d12c8158a35a3145dc967a) -+`BPF_FUNC_sys_bpf()` | 5.14 | | [`79a7f8bdb159`](https://github.com/torvalds/linux/commit/79a7f8bdb159d9914b58740f3d31d602a6e4aca8) -+`BPF_FUNC_sys_close()` | 5.14 | | [`3abea089246f`](https://github.com/torvalds/linux/commit/3abea089246f76c1517b054ddb5946f3f1dbd2c0) - `BPF_FUNC_sysctl_get_current_value()` | 5.2 | | [`1d11b3016cec`](https://kernel.googlesource.com/pub/scm/linux/kernel/git/davem/net-next/+/1d11b3016cec4ed9770b98e82a61708c8f4926e7) - `BPF_FUNC_sysctl_get_name()` | 5.2 | | [`808649fb787d`](https://kernel.googlesource.com/pub/scm/linux/kernel/git/davem/net-next/+/808649fb787d918a48a360a668ee4ee9023f0c11) - `BPF_FUNC_sysctl_get_new_value()` | 5.2 | | [`4e63acdff864`](https://kernel.googlesource.com/pub/scm/linux/kernel/git/davem/net-next/+/4e63acdff864654cee0ac5aaeda3913798ee78f6) -@@ -364,6 +368,10 @@ Helper | Kernel version | License | Commit | - `BPF_FUNC_tcp_send_ack()` | 5.5 | | [`206057fe020a`](https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/commit/?id=206057fe020ac5c037d5e2dd6562a9bd216ec765) - `BPF_FUNC_tcp_sock()` | 5.1 | | [`655a51e536c0`](https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/commit/?id=655a51e536c09d15ffa3603b1b6fce2b45b85a1f) - `BPF_FUNC_this_cpu_ptr()` | 5.10 | | [`63d9b80dcf2c`](https://github.com/torvalds/linux/commit/63d9b80dcf2c67bc5ade61cbbaa09d7af21f43f1) | -+`BPF_FUNC_timer_init()` | 5.15 | | [`b00628b1c7d5`](https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/commit/?id=b00628b1c7d595ae5b544e059c27b1f5828314b4) -+`BPF_FUNC_timer_set_callback()` | 5.15 | | [`b00628b1c7d5`](https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/commit/?id=b00628b1c7d595ae5b544e059c27b1f5828314b4) -+`BPF_FUNC_timer_start()` | 5.15 | | [`b00628b1c7d5`](https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/commit/?id=b00628b1c7d595ae5b544e059c27b1f5828314b4) -+`BPF_FUNC_timer_cancel()` | 5.15 | | [`b00628b1c7d5`](https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/commit/?id=b00628b1c7d595ae5b544e059c27b1f5828314b4) - `BPF_FUNC_trace_printk()` | 4.1 | GPL | [`9c959c863f82`](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=9c959c863f8217a2ff3d7c296e8223654d240569) - `BPF_FUNC_xdp_adjust_head()` | 4.10 | | [`17bedab27231`](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=17bedab2723145d17b14084430743549e6943d03) - `BPF_FUNC_xdp_adjust_meta()` | 4.15 | | [`de8f3a83b0a0`](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=de8f3a83b0a0fddb2cf56e7a718127e9619ea3da) -diff --git a/introspection/bps.c b/introspection/bps.c -index e92da3f6..25a88cbd 100644 ---- a/introspection/bps.c -+++ b/introspection/bps.c -@@ -47,6 +47,7 @@ static const char * const prog_type_strings[] = { - [BPF_PROG_TYPE_EXT] = "ext", - [BPF_PROG_TYPE_LSM] = "lsm", - [BPF_PROG_TYPE_SK_LOOKUP] = "sk_lookup", -+ [BPF_PROG_TYPE_SYSCALL] = "syscall", - }; - - static const char * const map_type_strings[] = { -diff --git a/src/cc/compat/linux/virtual_bpf.h b/src/cc/compat/linux/virtual_bpf.h -index 3490bc14..bf4bc3a6 100644 ---- a/src/cc/compat/linux/virtual_bpf.h -+++ b/src/cc/compat/linux/virtual_bpf.h -@@ -325,9 +325,6 @@ union bpf_iter_link_info { - * **BPF_PROG_TYPE_SK_LOOKUP** - * *data_in* and *data_out* must be NULL. - * -- * **BPF_PROG_TYPE_XDP** -- * *ctx_in* and *ctx_out* must be NULL. -- * - * **BPF_PROG_TYPE_RAW_TRACEPOINT**, - * **BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE** - * -@@ -528,6 +525,15 @@ union bpf_iter_link_info { - * Look up an element with the given *key* in the map referred to - * by the file descriptor *fd*, and if found, delete the element. - * -+ * For **BPF_MAP_TYPE_QUEUE** and **BPF_MAP_TYPE_STACK** map -+ * types, the *flags* argument needs to be set to 0, but for other -+ * map types, it may be specified as: -+ * -+ * **BPF_F_LOCK** -+ * Look up and delete the value of a spin-locked map -+ * without returning the lock. This must be specified if -+ * the elements contain a spinlock. -+ * - * The **BPF_MAP_TYPE_QUEUE** and **BPF_MAP_TYPE_STACK** map types - * implement this command as a "pop" operation, deleting the top - * element rather than one corresponding to *key*. -@@ -537,6 +543,10 @@ union bpf_iter_link_info { - * This command is only valid for the following map types: - * * **BPF_MAP_TYPE_QUEUE** - * * **BPF_MAP_TYPE_STACK** -+ * * **BPF_MAP_TYPE_HASH** -+ * * **BPF_MAP_TYPE_PERCPU_HASH** -+ * * **BPF_MAP_TYPE_LRU_HASH** -+ * * **BPF_MAP_TYPE_LRU_PERCPU_HASH** - * - * Return - * Returns zero on success. On error, -1 is returned and *errno* -@@ -838,6 +848,7 @@ enum bpf_cmd { - BPF_PROG_ATTACH, - BPF_PROG_DETACH, - BPF_PROG_TEST_RUN, -+ BPF_PROG_RUN = BPF_PROG_TEST_RUN, - BPF_PROG_GET_NEXT_ID, - BPF_MAP_GET_NEXT_ID, - BPF_PROG_GET_FD_BY_ID, -@@ -938,6 +949,7 @@ enum bpf_prog_type { - BPF_PROG_TYPE_EXT, - BPF_PROG_TYPE_LSM, - BPF_PROG_TYPE_SK_LOOKUP, -+ BPF_PROG_TYPE_SYSCALL, /* a program that can execute syscalls */ - }; - - enum bpf_attach_type { -@@ -980,6 +992,8 @@ enum bpf_attach_type { - BPF_SK_LOOKUP, - BPF_XDP, - BPF_SK_SKB_VERDICT, -+ BPF_SK_REUSEPORT_SELECT, -+ BPF_SK_REUSEPORT_SELECT_OR_MIGRATE, - __MAX_BPF_ATTACH_TYPE - }; - -@@ -1098,8 +1112,8 @@ enum bpf_link_type { - /* When BPF ldimm64's insn[0].src_reg != 0 then this can have - * the following extensions: - * -- * insn[0].src_reg: BPF_PSEUDO_MAP_FD -- * insn[0].imm: map fd -+ * insn[0].src_reg: BPF_PSEUDO_MAP_[FD|IDX] -+ * insn[0].imm: map fd or fd_idx - * insn[1].imm: 0 - * insn[0].off: 0 - * insn[1].off: 0 -@@ -1107,15 +1121,19 @@ enum bpf_link_type { - * verifier type: CONST_PTR_TO_MAP - */ - #define BPF_PSEUDO_MAP_FD 1 --/* insn[0].src_reg: BPF_PSEUDO_MAP_VALUE -- * insn[0].imm: map fd -+#define BPF_PSEUDO_MAP_IDX 5 -+ -+/* insn[0].src_reg: BPF_PSEUDO_MAP_[IDX_]VALUE -+ * insn[0].imm: map fd or fd_idx - * insn[1].imm: offset into value - * insn[0].off: 0 - * insn[1].off: 0 - * ldimm64 rewrite: address of map[0]+offset - * verifier type: PTR_TO_MAP_VALUE - */ --#define BPF_PSEUDO_MAP_VALUE 2 -+#define BPF_PSEUDO_MAP_VALUE 2 -+#define BPF_PSEUDO_MAP_IDX_VALUE 6 -+ - /* insn[0].src_reg: BPF_PSEUDO_BTF_ID - * insn[0].imm: kernel btd id of VAR - * insn[1].imm: 0 -@@ -1315,6 +1333,8 @@ union bpf_attr { - /* or valid module BTF object fd or 0 to attach to vmlinux */ - __u32 attach_btf_obj_fd; - }; -+ __u32 :32; /* pad */ -+ __aligned_u64 fd_array; /* array of FDs */ - }; - - struct { /* anonymous struct used by BPF_OBJ_* commands */ -@@ -2535,8 +2555,12 @@ union bpf_attr { - * The lower two bits of *flags* are used as the return code if - * the map lookup fails. This is so that the return value can be - * one of the XDP program return codes up to **XDP_TX**, as chosen -- * by the caller. Any higher bits in the *flags* argument must be -- * unset. -+ * by the caller. The higher bits of *flags* can be set to -+ * BPF_F_BROADCAST or BPF_F_EXCLUDE_INGRESS as defined below. -+ * -+ * With BPF_F_BROADCAST the packet will be broadcasted to all the -+ * interfaces in the map, with BPF_F_EXCLUDE_INGRESS the ingress -+ * interface will be excluded when do broadcasting. - * - * See also **bpf_redirect**\ (), which only supports redirecting - * to an ifindex, but doesn't require a map to do so. -@@ -3223,7 +3247,7 @@ union bpf_attr { - * long bpf_sk_select_reuseport(struct sk_reuseport_md *reuse, struct bpf_map *map, void *key, u64 flags) - * Description - * Select a **SO_REUSEPORT** socket from a -- * **BPF_MAP_TYPE_REUSEPORT_ARRAY** *map*. -+ * **BPF_MAP_TYPE_REUSEPORT_SOCKARRAY** *map*. - * It checks the selected socket is matching the incoming - * request in the socket buffer. - * Return -@@ -4736,6 +4760,94 @@ union bpf_attr { - * be zero-terminated except when **str_size** is 0. - * - * Or **-EBUSY** if the per-CPU memory copy buffer is busy. -+ * -+ * long bpf_sys_bpf(u32 cmd, void *attr, u32 attr_size) -+ * Description -+ * Execute bpf syscall with given arguments. -+ * Return -+ * A syscall result. -+ * -+ * long bpf_btf_find_by_name_kind(char *name, int name_sz, u32 kind, int flags) -+ * Description -+ * Find BTF type with given name and kind in vmlinux BTF or in module's BTFs. -+ * Return -+ * Returns btf_id and btf_obj_fd in lower and upper 32 bits. -+ * -+ * long bpf_sys_close(u32 fd) -+ * Description -+ * Execute close syscall for given FD. -+ * Return -+ * A syscall result. -+ * -+ * long bpf_timer_init(struct bpf_timer *timer, struct bpf_map *map, u64 flags) -+ * Description -+ * Initialize the timer. -+ * First 4 bits of *flags* specify clockid. -+ * Only CLOCK_MONOTONIC, CLOCK_REALTIME, CLOCK_BOOTTIME are allowed. -+ * All other bits of *flags* are reserved. -+ * The verifier will reject the program if *timer* is not from -+ * the same *map*. -+ * Return -+ * 0 on success. -+ * **-EBUSY** if *timer* is already initialized. -+ * **-EINVAL** if invalid *flags* are passed. -+ * **-EPERM** if *timer* is in a map that doesn't have any user references. -+ * The user space should either hold a file descriptor to a map with timers -+ * or pin such map in bpffs. When map is unpinned or file descriptor is -+ * closed all timers in the map will be cancelled and freed. -+ * -+ * long bpf_timer_set_callback(struct bpf_timer *timer, void *callback_fn) -+ * Description -+ * Configure the timer to call *callback_fn* static function. -+ * Return -+ * 0 on success. -+ * **-EINVAL** if *timer* was not initialized with bpf_timer_init() earlier. -+ * **-EPERM** if *timer* is in a map that doesn't have any user references. -+ * The user space should either hold a file descriptor to a map with timers -+ * or pin such map in bpffs. When map is unpinned or file descriptor is -+ * closed all timers in the map will be cancelled and freed. -+ * -+ * long bpf_timer_start(struct bpf_timer *timer, u64 nsecs, u64 flags) -+ * Description -+ * Set timer expiration N nanoseconds from the current time. The -+ * configured callback will be invoked in soft irq context on some cpu -+ * and will not repeat unless another bpf_timer_start() is made. -+ * In such case the next invocation can migrate to a different cpu. -+ * Since struct bpf_timer is a field inside map element the map -+ * owns the timer. The bpf_timer_set_callback() will increment refcnt -+ * of BPF program to make sure that callback_fn code stays valid. -+ * When user space reference to a map reaches zero all timers -+ * in a map are cancelled and corresponding program's refcnts are -+ * decremented. This is done to make sure that Ctrl-C of a user -+ * process doesn't leave any timers running. If map is pinned in -+ * bpffs the callback_fn can re-arm itself indefinitely. -+ * bpf_map_update/delete_elem() helpers and user space sys_bpf commands -+ * cancel and free the timer in the given map element. -+ * The map can contain timers that invoke callback_fn-s from different -+ * programs. The same callback_fn can serve different timers from -+ * different maps if key/value layout matches across maps. -+ * Every bpf_timer_set_callback() can have different callback_fn. -+ * -+ * Return -+ * 0 on success. -+ * **-EINVAL** if *timer* was not initialized with bpf_timer_init() earlier -+ * or invalid *flags* are passed. -+ * -+ * long bpf_timer_cancel(struct bpf_timer *timer) -+ * Description -+ * Cancel the timer and wait for callback_fn to finish if it was running. -+ * Return -+ * 0 if the timer was not active. -+ * 1 if the timer was active. -+ * **-EINVAL** if *timer* was not initialized with bpf_timer_init() earlier. -+ * **-EDEADLK** if callback_fn tried to call bpf_timer_cancel() on its -+ * own timer which would have led to a deadlock otherwise. -+ * -+ * u64 bpf_get_func_ip(void *ctx) -+ * Description -+ * Get address of the traced function (for tracing and kprobe programs). -+ * Return -+ * Address of the traced function. - */ - #define __BPF_FUNC_MAPPER(FN) \ - FN(unspec), \ -@@ -4904,6 +5016,14 @@ union bpf_attr { - FN(check_mtu), \ - FN(for_each_map_elem), \ - FN(snprintf), \ -+ FN(sys_bpf), \ -+ FN(btf_find_by_name_kind), \ -+ FN(sys_close), \ -+ FN(timer_init), \ -+ FN(timer_set_callback), \ -+ FN(timer_start), \ -+ FN(timer_cancel), \ -+ FN(get_func_ip), \ - /* */ - - /* integer value in 'imm' field of BPF_CALL instruction selects which helper -@@ -5081,6 +5201,12 @@ enum { - BPF_F_BPRM_SECUREEXEC = (1ULL << 0), - }; - -+/* Flags for bpf_redirect_map helper */ -+enum { -+ BPF_F_BROADCAST = (1ULL << 3), -+ BPF_F_EXCLUDE_INGRESS = (1ULL << 4), -+}; -+ - #define __bpf_md_ptr(type, name) \ - union { \ - type name; \ -@@ -5365,6 +5491,20 @@ struct sk_reuseport_md { - __u32 ip_protocol; /* IP protocol. e.g. IPPROTO_TCP, IPPROTO_UDP */ - __u32 bind_inany; /* Is sock bound to an INANY address? */ - __u32 hash; /* A hash of the packet 4 tuples */ -+ /* When reuse->migrating_sk is NULL, it is selecting a sk for the -+ * new incoming connection request (e.g. selecting a listen sk for -+ * the received SYN in the TCP case). reuse->sk is one of the sk -+ * in the reuseport group. The bpf prog can use reuse->sk to learn -+ * the local listening ip/port without looking into the skb. -+ * -+ * When reuse->migrating_sk is not NULL, reuse->sk is closed and -+ * reuse->migrating_sk is the socket that needs to be migrated -+ * to another listening socket. migrating_sk could be a fullsock -+ * sk that is fully established or a reqsk that is in-the-middle -+ * of 3-way handshake. -+ */ -+ __bpf_md_ptr(struct bpf_sock *, sk); -+ __bpf_md_ptr(struct bpf_sock *, migrating_sk); - }; - - #define BPF_TAG_SIZE 8 -@@ -6010,6 +6150,11 @@ struct bpf_spin_lock { - __u32 val; - }; - -+struct bpf_timer { -+ __u64 :64; -+ __u64 :64; -+} __attribute__((aligned(8))); -+ - struct bpf_sysctl { - __u32 write; /* Sysctl is being read (= 0) or written (= 1). - * Allows 1,2,4-byte read, but no write. -diff --git a/src/cc/export/helpers.h b/src/cc/export/helpers.h -index e9137f7f..a4e9b705 100644 ---- a/src/cc/export/helpers.h -+++ b/src/cc/export/helpers.h -@@ -847,6 +847,23 @@ static long (*bpf_snprintf)(char *str, __u32 str_size, const char *fmt, - __u64 *data, __u32 data_len) = - (void *)BPF_FUNC_snprintf; - -+static long (*bpf_sys_bpf)(__u32 cmd, void *attr, __u32 attr_size) = -+ (void *)BPF_FUNC_sys_bpf; -+static long (*bpf_btf_find_by_name_kind)(char *name, int name_sz, __u32 kind, int flags) = -+ (void *)BPF_FUNC_btf_find_by_name_kind; -+static long (*bpf_sys_close)(__u32 fd) = (void *)BPF_FUNC_sys_close; -+ -+struct bpf_timer; -+static long (*bpf_timer_init)(struct bpf_timer *timer, void *map, __u64 flags) = -+ (void *)BPF_FUNC_timer_init; -+static long (*bpf_timer_set_callback)(struct bpf_timer *timer, void *callback_fn) = -+ (void *)BPF_FUNC_timer_set_callback; -+static long (*bpf_timer_start)(struct bpf_timer *timer, __u64 nsecs, __u64 flags) = -+ (void *)BPF_FUNC_timer_start; -+static long (*bpf_timer_cancel)(struct bpf_timer *timer) = (void *)BPF_FUNC_timer_cancel; -+ -+static __u64 (*bpf_get_func_ip)(void *ctx) = (void *)BPF_FUNC_get_func_ip; -+ - /* llvm builtin functions that eBPF C program may use to - * emit BPF_LD_ABS and BPF_LD_IND instructions - */ -diff --git a/src/cc/libbpf.c b/src/cc/libbpf.c -index b83d68fd..f3608cfe 100644 ---- a/src/cc/libbpf.c -+++ b/src/cc/libbpf.c -@@ -270,6 +270,14 @@ static struct bpf_helper helpers[] = { - {"check_mtu", "5.12"}, - {"for_each_map_elem", "5.13"}, - {"snprintf", "5.13"}, -+ {"sys_bpf", "5.14"}, -+ {"btf_find_by_name_kind", "5.14"}, -+ {"sys_close", "5.14"}, -+ {"timer_init", "5.15"}, -+ {"timer_set_callback", "5.15"}, -+ {"timer_start", "5.15"}, -+ {"timer_cancel", "5.15"}, -+ {"get_func_ip", "5.15"}, - }; - - static uint64_t ptr_to_u64(void *ptr) --- -2.31.1 - diff --git a/bcc-0.20.0-threadsnoop-look-for-pthread_create-in-libc-too.patch b/bcc-0.20.0-threadsnoop-look-for-pthread_create-in-libc-too.patch deleted file mode 100644 index 2170eb8..0000000 --- a/bcc-0.20.0-threadsnoop-look-for-pthread_create-in-libc-too.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 460a71ab24ad511318342077ac9ef57df543375f Mon Sep 17 00:00:00 2001 -From: Jerome Marchand -Date: Thu, 16 Sep 2021 14:44:23 +0200 -Subject: [PATCH] threadsnoop: look for pthread_create in libc too - -Since glibc 2.34, pthread features are integrated in libc directly. -Look for pthread_create there too when it is not found in libpthread. - -Fixes #3623 ---- - tools/threadsnoop.py | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/tools/threadsnoop.py b/tools/threadsnoop.py -index 04c5e680..471b0c3c 100755 ---- a/tools/threadsnoop.py -+++ b/tools/threadsnoop.py -@@ -38,7 +38,12 @@ void do_entry(struct pt_regs *ctx) { - events.perf_submit(ctx, &data, sizeof(data)); - }; - """) --b.attach_uprobe(name="pthread", sym="pthread_create", fn_name="do_entry") -+ -+# Since version 2.34, pthread features are integrated in libc -+try: -+ b.attach_uprobe(name="pthread", sym="pthread_create", fn_name="do_entry") -+except Exception: -+ b.attach_uprobe(name="c", sym="pthread_create", fn_name="do_entry") - - print("%-10s %-6s %-16s %s" % ("TIME(ms)", "PID", "COMM", "FUNC")) - --- -2.31.1 - diff --git a/bcc-0.20.0-tools-Fix-BCC-bio-tools-with-recent-kernel-change.patch b/bcc-0.20.0-tools-Fix-BCC-bio-tools-with-recent-kernel-change.patch deleted file mode 100644 index 428499d..0000000 --- a/bcc-0.20.0-tools-Fix-BCC-bio-tools-with-recent-kernel-change.patch +++ /dev/null @@ -1,119 +0,0 @@ -From 59a4e7ea490f78ba289c1ba461bfe1fce9e7ef19 Mon Sep 17 00:00:00 2001 -From: Hengqi Chen -Date: Sat, 11 Dec 2021 17:36:17 +0800 -Subject: [PATCH] tools: Fix BCC bio tools with recent kernel change - -Several BCC bio tools are broken due to kernel change ([0]). -blk_account_io_{start, done} were renamed to __blk_account_io_{start, done}, -and the symbols gone from /proc/kallsyms. Fix them by checking symbol existence. - - [0]: https://github.com/torvalds/linux/commit/be6bfe36db1795babe9d92178a47b2e02193cb0f - -Signed-off-by: Hengqi Chen ---- - tools/biolatency.py | 12 ++++++++---- - tools/biolatpcts.py | 5 ++++- - tools/biosnoop.py | 11 ++++++++--- - tools/biotop.py | 11 ++++++++--- - 4 files changed, 28 insertions(+), 11 deletions(-) - -diff --git a/tools/biolatency.py b/tools/biolatency.py -index 0599609b..2e75a5de 100755 ---- a/tools/biolatency.py -+++ b/tools/biolatency.py -@@ -168,13 +168,18 @@ bpf_text = bpf_text.replace("STORE", store_str) - # load BPF program - b = BPF(text=bpf_text) - if args.queued: -- b.attach_kprobe(event="blk_account_io_start", fn_name="trace_req_start") -+ if BPF.get_kprobe_functions(b'__blk_account_io_start'): -+ b.attach_kprobe(event="__blk_account_io_start", fn_name="trace_req_start") -+ else: -+ b.attach_kprobe(event="blk_account_io_start", fn_name="trace_req_start") - else: - if BPF.get_kprobe_functions(b'blk_start_request'): - b.attach_kprobe(event="blk_start_request", fn_name="trace_req_start") - b.attach_kprobe(event="blk_mq_start_request", fn_name="trace_req_start") --b.attach_kprobe(event="blk_account_io_done", -- fn_name="trace_req_done") -+if BPF.get_kprobe_functions(b'__blk_account_io_done'): -+ b.attach_kprobe(event="__blk_account_io_done", fn_name="trace_req_done") -+else: -+ b.attach_kprobe(event="blk_account_io_done", fn_name="trace_req_done") - - if not args.json: - print("Tracing block device I/O... Hit Ctrl-C to end.") -@@ -277,4 +282,3 @@ dist = b.get_table("dist") - countdown -= 1 - if exiting or countdown == 0: - exit() -- -diff --git a/tools/biolatpcts.py b/tools/biolatpcts.py -index 5ab8aa5f..a2f59592 100755 ---- a/tools/biolatpcts.py -+++ b/tools/biolatpcts.py -@@ -142,7 +142,10 @@ bpf_source = bpf_source.replace('__MAJOR__', str(major)) - bpf_source = bpf_source.replace('__MINOR__', str(minor)) - - bpf = BPF(text=bpf_source) --bpf.attach_kprobe(event="blk_account_io_done", fn_name="kprobe_blk_account_io_done") -+if BPF.get_kprobe_functions(b'__blk_account_io_done'): -+ bpf.attach_kprobe(event="__blk_account_io_done", fn_name="kprobe_blk_account_io_done") -+else: -+ bpf.attach_kprobe(event="blk_account_io_done", fn_name="kprobe_blk_account_io_done") - - # times are in usecs - MSEC = 1000 -diff --git a/tools/biosnoop.py b/tools/biosnoop.py -index 333949b5..2b954ac9 100755 ---- a/tools/biosnoop.py -+++ b/tools/biosnoop.py -@@ -163,12 +163,17 @@ int trace_req_completion(struct pt_regs *ctx, struct request *req) - - # initialize BPF - b = BPF(text=bpf_text) --b.attach_kprobe(event="blk_account_io_start", fn_name="trace_pid_start") -+if BPF.get_kprobe_functions(b'__blk_account_io_start'): -+ b.attach_kprobe(event="__blk_account_io_start", fn_name="trace_pid_start") -+else: -+ b.attach_kprobe(event="blk_account_io_start", fn_name="trace_pid_start") - if BPF.get_kprobe_functions(b'blk_start_request'): - b.attach_kprobe(event="blk_start_request", fn_name="trace_req_start") - b.attach_kprobe(event="blk_mq_start_request", fn_name="trace_req_start") --b.attach_kprobe(event="blk_account_io_done", -- fn_name="trace_req_completion") -+if BPF.get_kprobe_functions(b'__blk_account_io_done'): -+ b.attach_kprobe(event="__blk_account_io_done", fn_name="trace_req_completion") -+else: -+ b.attach_kprobe(event="blk_account_io_done", fn_name="trace_req_completion") - - # header - print("%-11s %-14s %-6s %-7s %-1s %-10s %-7s" % ("TIME(s)", "COMM", "PID", -diff --git a/tools/biotop.py b/tools/biotop.py -index 596f0076..0ebfef0e 100755 ---- a/tools/biotop.py -+++ b/tools/biotop.py -@@ -180,12 +180,17 @@ int trace_req_completion(struct pt_regs *ctx, struct request *req) - exit() - - b = BPF(text=bpf_text) --b.attach_kprobe(event="blk_account_io_start", fn_name="trace_pid_start") -+if BPF.get_kprobe_functions(b'__blk_account_io_start'): -+ b.attach_kprobe(event="__blk_account_io_start", fn_name="trace_pid_start") -+else: -+ b.attach_kprobe(event="blk_account_io_start", fn_name="trace_pid_start") - if BPF.get_kprobe_functions(b'blk_start_request'): - b.attach_kprobe(event="blk_start_request", fn_name="trace_req_start") - b.attach_kprobe(event="blk_mq_start_request", fn_name="trace_req_start") --b.attach_kprobe(event="blk_account_io_done", -- fn_name="trace_req_completion") -+if BPF.get_kprobe_functions(b'__blk_account_io_done'): -+ b.attach_kprobe(event="__blk_account_io_done", fn_name="trace_req_completion") -+else: -+ b.attach_kprobe(event="blk_account_io_done", fn_name="trace_req_completion") - - print('Tracing... Output every %d secs. Hit Ctrl-C to end' % interval) - --- -2.35.1 - diff --git a/bcc-0.20.0-tools-readahead-compatible-with-kernel-version-5.10-.patch b/bcc-0.20.0-tools-readahead-compatible-with-kernel-version-5.10-.patch deleted file mode 100644 index b658d56..0000000 --- a/bcc-0.20.0-tools-readahead-compatible-with-kernel-version-5.10-.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 6c9d91c2196e69682a611dbfc10a0731f86deada Mon Sep 17 00:00:00 2001 -From: zcy -Date: Fri, 25 Jun 2021 10:16:53 +0800 -Subject: [PATCH] tools/readahead compatible with kernel version >= 5.10 - (#3507) - -After kernel version 5.10, __do_page_cache_readahead() was renamed to do_page_cache_ra(), -let us try both in readahead.py. ---- - tools/readahead.py | 12 ++++++++---- - tools/readahead_example.txt | 22 +++++++++++----------- - 2 files changed, 19 insertions(+), 15 deletions(-) - -diff --git a/tools/readahead.py b/tools/readahead.py -index 14182d5a..b338261f 100755 ---- a/tools/readahead.py -+++ b/tools/readahead.py -@@ -20,7 +20,7 @@ import argparse - - # arguments - examples = """examples: -- ./readahead -d 20 # monitor for 10 seconds and generate stats -+ ./readahead -d 20 # monitor for 20 seconds and generate stats - """ - - parser = argparse.ArgumentParser( -@@ -95,15 +95,19 @@ int entry_mark_page_accessed(struct pt_regs *ctx) { - """ - - b = BPF(text=program) --b.attach_kprobe(event="__do_page_cache_readahead", fn_name="entry__do_page_cache_readahead") --b.attach_kretprobe(event="__do_page_cache_readahead", fn_name="exit__do_page_cache_readahead") -+if BPF.get_kprobe_functions(b"__do_page_cache_readahead"): -+ ra_event = "__do_page_cache_readahead" -+else: -+ ra_event = "do_page_cache_ra" -+b.attach_kprobe(event=ra_event, fn_name="entry__do_page_cache_readahead") -+b.attach_kretprobe(event=ra_event, fn_name="exit__do_page_cache_readahead") - b.attach_kretprobe(event="__page_cache_alloc", fn_name="exit__page_cache_alloc") - b.attach_kprobe(event="mark_page_accessed", fn_name="entry_mark_page_accessed") - - # header - print("Tracing... Hit Ctrl-C to end.") - --# print -+# print - def print_stats(): - print() - print("Read-ahead unused pages: %d" % (b["pages"][ct.c_ulong(0)].value)) -diff --git a/tools/readahead_example.txt b/tools/readahead_example.txt -index 079dbaae..6d675c13 100644 ---- a/tools/readahead_example.txt -+++ b/tools/readahead_example.txt -@@ -2,20 +2,20 @@ Demonstration of readahead, the Linux eBPF/bcc version - - Read-ahead mechanism is used by operation sytems to optimize sequential operations - by reading ahead some pages to avoid more expensive filesystem operations. This tool --shows the performance of the read-ahead caching on the system under a given load to -+shows the performance of the read-ahead caching on the system under a given load to - investigate any caching issues. It shows a count for unused pages in the cache and - also prints a histogram showing how long they have remianed there. - - Usage Scenario - ============== - --Consider that you are developing a React Native application which performs aggressive -+Consider that you are developing a React Native application which performs aggressive - reads while re-encoding a video in local-storage. Usually such an app would be multi- --layered and have transitional library dependencies. The actual read may be performed --by some unknown native library which may or may not be using hints to the OS, such as --madvise(p, LEN, MADV_SEQUENTIAL). If high IOPS is observed in such an app, running --readahead may pin the issue much faster in this case as the developer digs deeper --into what may be causing this. -+layered and have transitional library dependencies. The actual read may be performed -+by some unknown native library which may or may not be using hints to the OS, such as -+madvise(p, LEN, MADV_SEQUENTIAL). If high IOPS is observed in such an app, running -+readahead may pin the issue much faster in this case as the developer digs deeper -+into what may be causing this. - - An example where such an issue can surface is: https://github.com/boltdb/bolt/issues/691 - -@@ -40,7 +40,7 @@ Read-ahead unused pages: 6765 - 2048 -> 4095 : 439 |**** | - 4096 -> 8191 : 188 |* | - --In the example above, we recorded system-wide stats for 30 seconds. We can observe that -+In the example above, we recorded system-wide stats for 30 seconds. We can observe that - while most of the pages stayed in the readahead cache for quite less time, after 30 - seconds 6765 pages still remained in the cache, yet unaccessed. - -@@ -49,12 +49,12 @@ Note on Kprobes Usage - - This tool uses Kprobes on the following kernel functions: - --__do_page_cache_readahead() -+__do_page_cache_readahead()/do_page_cache_ra() (After kernel version 5.10 (include), __do_page_cache_readahead was renamed to do_page_cache_ra) - __page_cache_alloc() - mark_page_accessed() - --Since the tool uses Kprobes, depending on your linux kernel's compilation, these --functions may be inlined and hence not available for Kprobes. To see whether you have -+Since the tool uses Kprobes, depending on your linux kernel's compilation, these -+functions may be inlined and hence not available for Kprobes. To see whether you have - the functions available, check vmlinux source and binary to confirm whether inlining is - happening or not. You can also check /proc/kallsyms on the host and verify if the target - functions are present there before using this tool. --- -2.31.1 - diff --git a/bcc-0.20.0-Fix-mdflush-on-RHEL9.patch b/bcc-0.24.0-C9S-Fix-mdflush.patch similarity index 86% rename from bcc-0.20.0-Fix-mdflush-on-RHEL9.patch rename to bcc-0.24.0-C9S-Fix-mdflush.patch index b6b9e07..716789e 100644 --- a/bcc-0.20.0-Fix-mdflush-on-RHEL9.patch +++ b/bcc-0.24.0-C9S-Fix-mdflush.patch @@ -1,7 +1,7 @@ -From 8032bb4053ff8803371b038fc696b9fa682027f2 Mon Sep 17 00:00:00 2001 +From 5e7543d35596fabd9e5b02b58f8910bf572ca2fa Mon Sep 17 00:00:00 2001 From: Jerome Marchand Date: Thu, 7 Oct 2021 17:31:53 +0200 -Subject: [PATCH] Fix mdflush on RHEL9 +Subject: [PATCH] C9S: Fix mdflush Since kernel commit 309dca309fc ("block: store a block_device pointer in struct bio") struct bio points again to a block_device and not to a @@ -10,16 +10,18 @@ the bio_dev macro to check whether to get the gendisk directly from the bio or not, which doesn't work anymore since the bio_dev macro still exists. Since we don't have to deal other ekrnel kernel version but our own, just use the definition that we use in our kernels. + +Signed-off-by: Jerome Marchand --- tools/mdflush.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/tools/mdflush.py b/tools/mdflush.py -index 2abe15cf..df0f13c1 100755 +index 8a23520b..3581d1bf 100755 --- a/tools/mdflush.py +++ b/tools/mdflush.py @@ -35,18 +35,7 @@ int kprobe__md_flush_request(struct pt_regs *ctx, void *mddev, struct bio *bio) - u32 pid = bpf_get_current_pid_tgid(); + u32 pid = bpf_get_current_pid_tgid() >> 32; data.pid = pid; bpf_get_current_comm(&data.comm, sizeof(data.comm)); -/* @@ -38,5 +40,5 @@ index 2abe15cf..df0f13c1 100755 events.perf_submit(ctx, &data, sizeof(data)); return 0; -- -2.31.1 +2.35.1 diff --git a/bcc-0.24.0-C9S-libpbf-version-fixes.patch b/bcc-0.24.0-C9S-libpbf-version-fixes.patch new file mode 100644 index 0000000..1d94f93 --- /dev/null +++ b/bcc-0.24.0-C9S-libpbf-version-fixes.patch @@ -0,0 +1,324 @@ +From fcd43bfd82e52450c0beae0e0e87d39822366d32 Mon Sep 17 00:00:00 2001 +From: Jerome Marchand +Date: Thu, 24 Mar 2022 16:08:17 +0100 +Subject: [PATCH] C9S: libpbf version fixes + +Revert "bcc: Replace deprecated libbpf APIs" since the libbpf version +provided in C9S doesn't provide the new APIs. + +Remove BPF_MAP_TYPE_BLOOM_FILTER from bps since the libbpf version in +C9S, doesn't provide bloom filter map. + +Rename btf__load_vmlinux_btf into libbpf_find_kernel_btf. The function +has been renamed upstream for naming consistency, but C9S libbpf still +uses the old name. + +Add definition of struct bpf_core_relo. +--- + introspection/bps.c | 1 - + libbpf-tools/ksnoop.c | 2 +- + src/cc/bcc_btf.cc | 73 ++++++++++++++++++++++++++++++++++++- + src/cc/libbpf.c | 84 +++++++------------------------------------ + 4 files changed, 85 insertions(+), 75 deletions(-) + +diff --git a/introspection/bps.c b/introspection/bps.c +index 232b23d4..6ec02e6c 100644 +--- a/introspection/bps.c ++++ b/introspection/bps.c +@@ -80,7 +80,6 @@ static const char * const map_type_strings[] = { + [BPF_MAP_TYPE_RINGBUF] = "ringbuf", + [BPF_MAP_TYPE_INODE_STORAGE] = "inode_storage", + [BPF_MAP_TYPE_TASK_STORAGE] = "task_storage", +- [BPF_MAP_TYPE_BLOOM_FILTER] = "bloom_filter", + }; + + #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) +diff --git a/libbpf-tools/ksnoop.c b/libbpf-tools/ksnoop.c +index 69c58403..a6ea6107 100644 +--- a/libbpf-tools/ksnoop.c ++++ b/libbpf-tools/ksnoop.c +@@ -347,7 +347,7 @@ static struct btf *get_btf(const char *name) + name && strlen(name) > 0 ? name : "vmlinux"); + + if (!vmlinux_btf) { +- vmlinux_btf = btf__load_vmlinux_btf(); ++ vmlinux_btf = libbpf_find_kernel_btf(); + if (!vmlinux_btf) { + err = -errno; + p_err("No BTF, cannot determine type info: %s", strerror(-err)); +diff --git a/src/cc/bcc_btf.cc b/src/cc/bcc_btf.cc +index 7f551ae8..c78ba823 100644 +--- a/src/cc/bcc_btf.cc ++++ b/src/cc/bcc_btf.cc +@@ -170,6 +170,77 @@ static int btf_ext_setup_line_info(struct btf_ext *btf_ext) + return btf_ext_setup_info(btf_ext, ¶m); + } + ++/* bpf_core_relo_kind encodes which aspect of captured field/type/enum value ++ * has to be adjusted by relocations. ++ */ ++enum bpf_core_relo_kind { ++ BPF_FIELD_BYTE_OFFSET = 0, /* field byte offset */ ++ BPF_FIELD_BYTE_SIZE = 1, /* field size in bytes */ ++ BPF_FIELD_EXISTS = 2, /* field existence in target kernel */ ++ BPF_FIELD_SIGNED = 3, /* field signedness (0 - unsigned, 1 - signed) */ ++ BPF_FIELD_LSHIFT_U64 = 4, /* bitfield-specific left bitshift */ ++ BPF_FIELD_RSHIFT_U64 = 5, /* bitfield-specific right bitshift */ ++ BPF_TYPE_ID_LOCAL = 6, /* type ID in local BPF object */ ++ BPF_TYPE_ID_TARGET = 7, /* type ID in target kernel */ ++ BPF_TYPE_EXISTS = 8, /* type existence in target kernel */ ++ BPF_TYPE_SIZE = 9, /* type size in bytes */ ++ BPF_ENUMVAL_EXISTS = 10, /* enum value existence in target kernel */ ++ BPF_ENUMVAL_VALUE = 11, /* enum value integer value */ ++}; ++ ++/* The minimum bpf_core_relo checked by the loader ++ * ++ * CO-RE relocation captures the following data: ++ * - insn_off - instruction offset (in bytes) within a BPF program that needs ++ * its insn->imm field to be relocated with actual field info; ++ * - type_id - BTF type ID of the "root" (containing) entity of a relocatable ++ * type or field; ++ * - access_str_off - offset into corresponding .BTF string section. String ++ * interpretation depends on specific relocation kind: ++ * - for field-based relocations, string encodes an accessed field using ++ * a sequence of field and array indices, separated by colon (:). It's ++ * conceptually very close to LLVM's getelementptr ([0]) instruction's ++ * arguments for identifying offset to a field. ++ * - for type-based relocations, strings is expected to be just "0"; ++ * - for enum value-based relocations, string contains an index of enum ++ * value within its enum type; ++ * ++ * Example to provide a better feel. ++ * ++ * struct sample { ++ * int a; ++ * struct { ++ * int b[10]; ++ * }; ++ * }; ++ * ++ * struct sample *s = ...; ++ * int x = &s->a; // encoded as "0:0" (a is field #0) ++ * int y = &s->b[5]; // encoded as "0:1:0:5" (anon struct is field #1, ++ * // b is field #0 inside anon struct, accessing elem #5) ++ * int z = &s[10]->b; // encoded as "10:1" (ptr is used as an array) ++ * ++ * type_id for all relocs in this example will capture BTF type id of ++ * `struct sample`. ++ * ++ * Such relocation is emitted when using __builtin_preserve_access_index() ++ * Clang built-in, passing expression that captures field address, e.g.: ++ * ++ * bpf_probe_read(&dst, sizeof(dst), ++ * __builtin_preserve_access_index(&src->a.b.c)); ++ * ++ * In this case Clang will emit field relocation recording necessary data to ++ * be able to find offset of embedded `a.b.c` field within `src` struct. ++ * ++ * [0] https://llvm.org/docs/LangRef.html#getelementptr-instruction ++ */ ++struct bpf_core_relo { ++ __u32 insn_off; ++ __u32 type_id; ++ __u32 access_str_off; ++ enum bpf_core_relo_kind kind; ++}; ++ + static int btf_ext_setup_core_relos(struct btf_ext *btf_ext) + { + struct btf_ext_sec_setup_param param = { +@@ -597,7 +668,7 @@ int BTF::load(uint8_t *btf_sec, uintptr_t btf_sec_size, + return -1; + } + +- if (btf__load_into_kernel(btf)) { ++ if (btf__load(btf)) { + btf__free(btf); + warning("Loading .BTF section failed\n"); + return -1; +diff --git a/src/cc/libbpf.c b/src/cc/libbpf.c +index e6403299..7410ae1a 100644 +--- a/src/cc/libbpf.c ++++ b/src/cc/libbpf.c +@@ -297,25 +297,6 @@ static uint64_t ptr_to_u64(void *ptr) + return (uint64_t) (unsigned long) ptr; + } + +-static int libbpf_bpf_map_create(struct bpf_create_map_attr *create_attr) +-{ +- LIBBPF_OPTS(bpf_map_create_opts, p); +- +- p.map_flags = create_attr->map_flags; +- p.numa_node = create_attr->numa_node; +- p.btf_fd = create_attr->btf_fd; +- p.btf_key_type_id = create_attr->btf_key_type_id; +- p.btf_value_type_id = create_attr->btf_value_type_id; +- p.map_ifindex = create_attr->map_ifindex; +- if (create_attr->map_type == BPF_MAP_TYPE_STRUCT_OPS) +- p.btf_vmlinux_value_type_id = create_attr->btf_vmlinux_value_type_id; +- else +- p.inner_map_fd = create_attr->inner_map_fd; +- +- return bpf_map_create(create_attr->map_type, create_attr->name, create_attr->key_size, +- create_attr->value_size, create_attr->max_entries, &p); +-} +- + int bcc_create_map_xattr(struct bpf_create_map_attr *attr, bool allow_rlimit) + { + unsigned name_len = attr->name ? strlen(attr->name) : 0; +@@ -323,7 +304,7 @@ int bcc_create_map_xattr(struct bpf_create_map_attr *attr, bool allow_rlimit) + + memcpy(map_name, attr->name, min(name_len, BPF_OBJ_NAME_LEN - 1)); + attr->name = map_name; +- int ret = libbpf_bpf_map_create(attr); ++ int ret = bpf_create_map_xattr(attr); + + if (ret < 0 && errno == EPERM) { + if (!allow_rlimit) +@@ -335,7 +316,7 @@ int bcc_create_map_xattr(struct bpf_create_map_attr *attr, bool allow_rlimit) + rl.rlim_max = RLIM_INFINITY; + rl.rlim_cur = rl.rlim_max; + if (setrlimit(RLIMIT_MEMLOCK, &rl) == 0) +- ret = libbpf_bpf_map_create(attr); ++ ret = bpf_create_map_xattr(attr); + } + } + +@@ -345,12 +326,12 @@ int bcc_create_map_xattr(struct bpf_create_map_attr *attr, bool allow_rlimit) + attr->btf_fd = 0; + attr->btf_key_type_id = 0; + attr->btf_value_type_id = 0; +- ret = libbpf_bpf_map_create(attr); ++ ret = bpf_create_map_xattr(attr); + } + + if (ret < 0 && name_len && (errno == E2BIG || errno == EINVAL)) { + map_name[0] = '\0'; +- ret = libbpf_bpf_map_create(attr); ++ ret = bpf_create_map_xattr(attr); + } + + if (ret < 0 && errno == EPERM) { +@@ -363,7 +344,7 @@ int bcc_create_map_xattr(struct bpf_create_map_attr *attr, bool allow_rlimit) + rl.rlim_max = RLIM_INFINITY; + rl.rlim_cur = rl.rlim_max; + if (setrlimit(RLIMIT_MEMLOCK, &rl) == 0) +- ret = libbpf_bpf_map_create(attr); ++ ret = bpf_create_map_xattr(attr); + } + } + return ret; +@@ -627,47 +608,6 @@ int bpf_prog_get_tag(int fd, unsigned long long *ptag) + return 0; + } + +-static int libbpf_bpf_prog_load(const struct bpf_load_program_attr *load_attr, +- char *log_buf, size_t log_buf_sz) +-{ +- LIBBPF_OPTS(bpf_prog_load_opts, p); +- +- if (!load_attr || !log_buf != !log_buf_sz) { +- errno = EINVAL; +- return -EINVAL; +- } +- +- p.expected_attach_type = load_attr->expected_attach_type; +- switch (load_attr->prog_type) { +- case BPF_PROG_TYPE_STRUCT_OPS: +- case BPF_PROG_TYPE_LSM: +- p.attach_btf_id = load_attr->attach_btf_id; +- break; +- case BPF_PROG_TYPE_TRACING: +- case BPF_PROG_TYPE_EXT: +- p.attach_btf_id = load_attr->attach_btf_id; +- p.attach_prog_fd = load_attr->attach_prog_fd; +- break; +- default: +- p.prog_ifindex = load_attr->prog_ifindex; +- p.kern_version = load_attr->kern_version; +- } +- p.log_level = load_attr->log_level; +- p.log_buf = log_buf; +- p.log_size = log_buf_sz; +- p.prog_btf_fd = load_attr->prog_btf_fd; +- p.func_info_rec_size = load_attr->func_info_rec_size; +- p.func_info_cnt = load_attr->func_info_cnt; +- p.func_info = load_attr->func_info; +- p.line_info_rec_size = load_attr->line_info_rec_size; +- p.line_info_cnt = load_attr->line_info_cnt; +- p.line_info = load_attr->line_info; +- p.prog_flags = load_attr->prog_flags; +- +- return bpf_prog_load(load_attr->prog_type, load_attr->name, load_attr->license, +- load_attr->insns, load_attr->insns_cnt, &p); +-} +- + int bcc_prog_load_xattr(struct bpf_load_program_attr *attr, int prog_len, + char *log_buf, unsigned log_buf_size, bool allow_rlimit) + { +@@ -750,7 +690,7 @@ int bcc_prog_load_xattr(struct bpf_load_program_attr *attr, int prog_len, + attr->name = prog_name; + } + +- ret = libbpf_bpf_prog_load(attr, attr_log_buf, attr_log_buf_size); ++ ret = bpf_load_program_xattr(attr, attr_log_buf, attr_log_buf_size); + + // func_info/line_info may not be supported in old kernels. + if (ret < 0 && attr->func_info && errno == EINVAL) { +@@ -761,14 +701,14 @@ int bcc_prog_load_xattr(struct bpf_load_program_attr *attr, int prog_len, + attr->line_info = NULL; + attr->line_info_cnt = 0; + attr->line_info_rec_size = 0; +- ret = libbpf_bpf_prog_load(attr, attr_log_buf, attr_log_buf_size); ++ ret = bpf_load_program_xattr(attr, attr_log_buf, attr_log_buf_size); + } + + // BPF object name is not supported on older Kernels. + // If we failed due to this, clear the name and try again. + if (ret < 0 && name_len && (errno == E2BIG || errno == EINVAL)) { + prog_name[0] = '\0'; +- ret = libbpf_bpf_prog_load(attr, attr_log_buf, attr_log_buf_size); ++ ret = bpf_load_program_xattr(attr, attr_log_buf, attr_log_buf_size); + } + + if (ret < 0 && errno == EPERM) { +@@ -787,7 +727,7 @@ int bcc_prog_load_xattr(struct bpf_load_program_attr *attr, int prog_len, + rl.rlim_max = RLIM_INFINITY; + rl.rlim_cur = rl.rlim_max; + if (setrlimit(RLIMIT_MEMLOCK, &rl) == 0) +- ret = libbpf_bpf_prog_load(attr, attr_log_buf, attr_log_buf_size); ++ ret = bpf_load_program_xattr(attr, attr_log_buf, attr_log_buf_size); + } + } + +@@ -805,7 +745,7 @@ int bcc_prog_load_xattr(struct bpf_load_program_attr *attr, int prog_len, + // If logging is not already enabled, enable it and do the syscall again. + if (attr->log_level == 0) { + attr->log_level = 1; +- ret = libbpf_bpf_prog_load(attr, log_buf, log_buf_size); ++ ret = bpf_load_program_xattr(attr, log_buf, log_buf_size); + } + // Print the log message and return. + bpf_print_hints(ret, log_buf); +@@ -829,7 +769,7 @@ int bcc_prog_load_xattr(struct bpf_load_program_attr *attr, int prog_len, + goto return_result; + } + tmp_log_buf[0] = 0; +- ret = libbpf_bpf_prog_load(attr, tmp_log_buf, tmp_log_buf_size); ++ ret = bpf_load_program_xattr(attr, tmp_log_buf, tmp_log_buf_size); + if (ret < 0 && errno == ENOSPC) { + // Temporary buffer size is not enough. Double it and try again. + free(tmp_log_buf); +@@ -1369,7 +1309,7 @@ int kernel_struct_has_field(const char *struct_name, const char *field_name) + struct btf *btf; + int i, ret, btf_id; + +- btf = btf__load_vmlinux_btf(); ++ btf = libbpf_find_kernel_btf(); + ret = libbpf_get_error(btf); + if (ret) + return -1; +-- +2.35.1 + diff --git a/bcc-0.24.0-C9S-remove-ksnoop.patch b/bcc-0.24.0-C9S-remove-ksnoop.patch new file mode 100644 index 0000000..3965a3b --- /dev/null +++ b/bcc-0.24.0-C9S-remove-ksnoop.patch @@ -0,0 +1,1953 @@ +From 43a991ffa59acc3d941ef95bb1f20df451a484d8 Mon Sep 17 00:00:00 2001 +From: Jerome Marchand +Date: Wed, 20 Apr 2022 12:42:13 +0200 +Subject: [PATCH] C9S: remove ksnoop + +ksnoop need a more recent libbpf that currently provided on c9s/RHEL 9. + +Signed-off-by: Jerome Marchand +--- + libbpf-tools/Makefile | 1 - + libbpf-tools/ksnoop.bpf.c | 460 ----------------- + libbpf-tools/ksnoop.c | 1013 ------------------------------------- + libbpf-tools/ksnoop.h | 123 ----- + man/man8/ksnoop.8 | 298 ----------- + 5 files changed, 1895 deletions(-) + delete mode 100644 libbpf-tools/ksnoop.bpf.c + delete mode 100644 libbpf-tools/ksnoop.c + delete mode 100644 libbpf-tools/ksnoop.h + delete mode 100644 man/man8/ksnoop.8 + +diff --git a/libbpf-tools/Makefile b/libbpf-tools/Makefile +index 39af95ec..d84e4424 100644 +--- a/libbpf-tools/Makefile ++++ b/libbpf-tools/Makefile +@@ -38,7 +38,6 @@ APPS = \ + gethostlatency \ + hardirqs \ + klockstat \ +- ksnoop \ + llcstat \ + mountsnoop \ + numamove \ +diff --git a/libbpf-tools/ksnoop.bpf.c b/libbpf-tools/ksnoop.bpf.c +deleted file mode 100644 +index 51dfe572..00000000 +--- a/libbpf-tools/ksnoop.bpf.c ++++ /dev/null +@@ -1,460 +0,0 @@ +-/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ +-/* Copyright (c) 2021, Oracle and/or its affiliates. */ +- +-#include "vmlinux.h" +- +-#include +-#include +-#include +- +-#include "ksnoop.h" +- +-/* For kretprobes, the instruction pointer in the struct pt_regs context +- * is the kretprobe_trampoline. We derive the instruction pointer +- * by pushing it onto a function stack on entry and popping it on return. +- * +- * We could use bpf_get_func_ip(), but "stack mode" - where we +- * specify functions "a", "b and "c" and only want to see a trace if "a" +- * calls "b" and "b" calls "c" - utilizes this stack to determine if trace +- * data should be collected. +- */ +-#define FUNC_MAX_STACK_DEPTH 16 +-/* used to convince verifier we do not stray outside of array bounds */ +-#define FUNC_STACK_DEPTH_MASK (FUNC_MAX_STACK_DEPTH - 1) +- +-#ifndef ENOSPC +-#define ENOSPC 28 +-#endif +- +-struct func_stack { +- __u64 task; +- __u64 ips[FUNC_MAX_STACK_DEPTH]; +- __u8 stack_depth; +-}; +- +-#define MAX_TASKS 2048 +- +-/* function call stack hashed on a per-task key */ +-struct { +- __uint(type, BPF_MAP_TYPE_HASH); +- /* function call stack for functions we are tracing */ +- __uint(max_entries, MAX_TASKS); +- __type(key, __u64); +- __type(value, struct func_stack); +-} ksnoop_func_stack SEC(".maps"); +- +-/* per-cpu trace info hashed on function address */ +-struct { +- __uint(type, BPF_MAP_TYPE_PERCPU_HASH); +- __uint(max_entries, MAX_FUNC_TRACES); +- __type(key, __u64); +- __type(value, struct trace); +-} ksnoop_func_map SEC(".maps"); +- +-struct { +- __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); +- __uint(value_size, sizeof(int)); +- __uint(key_size, sizeof(int)); +-} ksnoop_perf_map SEC(".maps"); +- +-static void clear_trace(struct trace *trace) +-{ +- __builtin_memset(&trace->trace_data, 0, sizeof(trace->trace_data)); +- trace->data_flags = 0; +- trace->buf_len = 0; +-} +- +-static struct trace *get_trace(struct pt_regs *ctx, bool entry) +-{ +- __u8 stack_depth, last_stack_depth; +- struct func_stack *func_stack; +- __u64 ip, last_ip = 0, task; +- struct trace *trace; +- +- task = bpf_get_current_task(); +- +- func_stack = bpf_map_lookup_elem(&ksnoop_func_stack, &task); +- if (!func_stack) { +- struct func_stack new_stack = { .task = task }; +- +- bpf_map_update_elem(&ksnoop_func_stack, &task, &new_stack, +- BPF_NOEXIST); +- func_stack = bpf_map_lookup_elem(&ksnoop_func_stack, &task); +- if (!func_stack) +- return NULL; +- } +- +- stack_depth = func_stack->stack_depth; +- if (stack_depth > FUNC_MAX_STACK_DEPTH) +- return NULL; +- +- if (entry) { +- ip = KSNOOP_IP_FIX(PT_REGS_IP_CORE(ctx)); +- if (stack_depth >= FUNC_MAX_STACK_DEPTH - 1) +- return NULL; +- /* verifier doesn't like using "stack_depth - 1" as array index +- * directly. +- */ +- last_stack_depth = stack_depth - 1; +- /* get address of last function we called */ +- if (last_stack_depth >= 0 && +- last_stack_depth < FUNC_MAX_STACK_DEPTH) +- last_ip = func_stack->ips[last_stack_depth]; +- /* push ip onto stack. return will pop it. */ +- func_stack->ips[stack_depth] = ip; +- /* mask used in case bounds checks are optimized out */ +- stack_depth = (stack_depth + 1) & FUNC_STACK_DEPTH_MASK; +- func_stack->stack_depth = stack_depth; +- /* rather than zero stack entries on popping, we zero the +- * (stack_depth + 1)'th entry when pushing the current +- * entry. The reason we take this approach is that +- * when tracking the set of functions we returned from, +- * we want the history of functions we returned from to +- * be preserved. +- */ +- if (stack_depth < FUNC_MAX_STACK_DEPTH) +- func_stack->ips[stack_depth] = 0; +- } else { +- if (stack_depth == 0 || stack_depth >= FUNC_MAX_STACK_DEPTH) +- return NULL; +- last_stack_depth = stack_depth; +- /* get address of last function we returned from */ +- if (last_stack_depth >= 0 && +- last_stack_depth < FUNC_MAX_STACK_DEPTH) +- last_ip = func_stack->ips[last_stack_depth]; +- if (stack_depth > 0) { +- /* logical OR convinces verifier that we don't +- * end up with a < 0 value, translating to 0xff +- * and an outside of map element access. +- */ +- stack_depth = (stack_depth - 1) & FUNC_STACK_DEPTH_MASK; +- } +- /* retrieve ip from stack as IP in pt_regs is +- * bpf kretprobe trampoline address. +- */ +- if (stack_depth >= 0 && stack_depth < FUNC_MAX_STACK_DEPTH) +- ip = func_stack->ips[stack_depth]; +- if (stack_depth >= 0 && stack_depth < FUNC_MAX_STACK_DEPTH) +- func_stack->stack_depth = stack_depth; +- } +- +- trace = bpf_map_lookup_elem(&ksnoop_func_map, &ip); +- if (!trace) +- return NULL; +- +- /* we may stash data on entry since predicates are a mix +- * of entry/return; in such cases, trace->flags specifies +- * KSNOOP_F_STASH, and we will output stashed data on return. +- * If returning, make sure we don't clear our stashed data. +- */ +- if (!entry && (trace->flags & KSNOOP_F_STASH)) { +- /* skip clearing trace data */ +- if (!(trace->data_flags & KSNOOP_F_STASHED)) { +- /* predicate must have failed */ +- return NULL; +- } +- /* skip clearing trace data */ +- } else { +- /* clear trace data before starting. */ +- clear_trace(trace); +- } +- +- if (entry) { +- /* if in stack mode, check if previous fn matches */ +- if (trace->prev_ip && trace->prev_ip != last_ip) +- return NULL; +- /* if tracing intermediate fn in stack of fns, stash data. */ +- if (trace->next_ip) +- trace->data_flags |= KSNOOP_F_STASH; +- /* we may stash data on entry since predicates are a mix +- * of entry/return; in such cases, trace->flags specifies +- * KSNOOP_F_STASH, and we will output stashed data on return. +- */ +- if (trace->flags & KSNOOP_F_STASH) +- trace->data_flags |= KSNOOP_F_STASH; +- /* otherwise the data is outputted (because we've reached +- * the last fn in the set of fns specified). +- */ +- } else { +- /* In stack mode, check if next fn matches the last fn +- * we returned from; i.e. "a" called "b", and now +- * we're at "a", was the last fn we returned from "b"? +- * If so, stash data for later display (when we reach the +- * first fn in the set of stack fns). +- */ +- if (trace->next_ip && trace->next_ip != last_ip) +- return NULL; +- if (trace->prev_ip) +- trace->data_flags |= KSNOOP_F_STASH; +- /* If there is no "prev" function, i.e. we are at the +- * first function in a set of stack functions, the trace +- * info is shown (along with any stashed info associated +- * with callers). +- */ +- } +- trace->task = task; +- return trace; +-} +- +-static void output_trace(struct pt_regs *ctx, struct trace *trace) +-{ +- __u16 trace_len; +- +- if (trace->buf_len == 0) +- goto skip; +- +- /* we may be simply stashing values, and will report later */ +- if (trace->data_flags & KSNOOP_F_STASH) { +- trace->data_flags &= ~KSNOOP_F_STASH; +- trace->data_flags |= KSNOOP_F_STASHED; +- return; +- } +- /* we may be outputting earlier stashed data */ +- if (trace->data_flags & KSNOOP_F_STASHED) +- trace->data_flags &= ~KSNOOP_F_STASHED; +- +- /* trim perf event size to only contain data we've recorded. */ +- trace_len = sizeof(*trace) + trace->buf_len - MAX_TRACE_BUF; +- +- if (trace_len <= sizeof(*trace)) +- bpf_perf_event_output(ctx, &ksnoop_perf_map, +- BPF_F_CURRENT_CPU, +- trace, trace_len); +-skip: +- clear_trace(trace); +-} +- +-static void output_stashed_traces(struct pt_regs *ctx, +- struct trace *currtrace, +- bool entry) +-{ +- struct func_stack *func_stack; +- struct trace *trace = NULL; +- __u8 i; +- __u64 task = 0; +- +- task = bpf_get_current_task(); +- func_stack = bpf_map_lookup_elem(&ksnoop_func_stack, &task); +- if (!func_stack) +- return; +- +- if (entry) { +- /* iterate from bottom to top of stack, outputting stashed +- * data we find. This corresponds to the set of functions +- * we called before the current function. +- */ +- for (i = 0; +- i < func_stack->stack_depth - 1 && i < FUNC_MAX_STACK_DEPTH; +- i++) { +- trace = bpf_map_lookup_elem(&ksnoop_func_map, +- &func_stack->ips[i]); +- if (!trace || !(trace->data_flags & KSNOOP_F_STASHED)) +- break; +- if (trace->task != task) +- return; +- output_trace(ctx, trace); +- } +- } else { +- /* iterate from top to bottom of stack, outputting stashed +- * data we find. This corresponds to the set of functions +- * that returned prior to the current returning function. +- */ +- for (i = FUNC_MAX_STACK_DEPTH; i > 0; i--) { +- __u64 ip; +- +- ip = func_stack->ips[i]; +- if (!ip) +- continue; +- trace = bpf_map_lookup_elem(&ksnoop_func_map, &ip); +- if (!trace || !(trace->data_flags & KSNOOP_F_STASHED)) +- break; +- if (trace->task != task) +- return; +- output_trace(ctx, trace); +- } +- } +- /* finally output the current trace info */ +- output_trace(ctx, currtrace); +-} +- +-static __u64 get_arg(struct pt_regs *ctx, enum arg argnum) +-{ +- switch (argnum) { +- case KSNOOP_ARG1: +- return PT_REGS_PARM1_CORE(ctx); +- case KSNOOP_ARG2: +- return PT_REGS_PARM2_CORE(ctx); +- case KSNOOP_ARG3: +- return PT_REGS_PARM3_CORE(ctx); +- case KSNOOP_ARG4: +- return PT_REGS_PARM4_CORE(ctx); +- case KSNOOP_ARG5: +- return PT_REGS_PARM5_CORE(ctx); +- case KSNOOP_RETURN: +- return PT_REGS_RC_CORE(ctx); +- default: +- return 0; +- } +-} +- +-static int ksnoop(struct pt_regs *ctx, bool entry) +-{ +- void *data_ptr = NULL; +- struct trace *trace; +- __u64 data; +- __u32 currpid; +- int ret; +- __u8 i; +- +- trace = get_trace(ctx, entry); +- if (!trace) +- return 0; +- +- /* make sure we want events from this pid */ +- currpid = bpf_get_current_pid_tgid(); +- if (trace->filter_pid && trace->filter_pid != currpid) +- return 0; +- trace->pid = currpid; +- +- trace->cpu = bpf_get_smp_processor_id(); +- trace->time = bpf_ktime_get_ns(); +- +- trace->data_flags &= ~(KSNOOP_F_ENTRY | KSNOOP_F_RETURN); +- if (entry) +- trace->data_flags |= KSNOOP_F_ENTRY; +- else +- trace->data_flags |= KSNOOP_F_RETURN; +- +- +- for (i = 0; i < MAX_TRACES; i++) { +- struct trace_data *currdata; +- struct value *currtrace; +- char *buf_offset = NULL; +- __u32 tracesize; +- +- currdata = &trace->trace_data[i]; +- currtrace = &trace->traces[i]; +- +- if ((entry && !base_arg_is_entry(currtrace->base_arg)) || +- (!entry && base_arg_is_entry(currtrace->base_arg))) +- continue; +- +- /* skip void (unused) trace arguments, ensuring not to +- * skip "void *". +- */ +- if (currtrace->type_id == 0 && +- !(currtrace->flags & KSNOOP_F_PTR)) +- continue; +- +- data = get_arg(ctx, currtrace->base_arg); +- +- /* look up member value and read into data field. */ +- if (currtrace->flags & KSNOOP_F_MEMBER) { +- if (currtrace->offset) +- data += currtrace->offset; +- +- /* member is a pointer; read it in */ +- if (currtrace->flags & KSNOOP_F_PTR) { +- void *dataptr = (void *)data; +- +- ret = bpf_probe_read(&data, sizeof(data), +- dataptr); +- if (ret) { +- currdata->err_type_id = +- currtrace->type_id; +- currdata->err = ret; +- continue; +- } +- currdata->raw_value = data; +- } else if (currtrace->size <= +- sizeof(currdata->raw_value)) { +- /* read member value for predicate comparison */ +- bpf_probe_read(&currdata->raw_value, +- currtrace->size, +- (void*)data); +- } +- } else { +- currdata->raw_value = data; +- } +- +- /* simple predicate evaluation: if any predicate fails, +- * skip all tracing for this function. +- */ +- if (currtrace->flags & KSNOOP_F_PREDICATE_MASK) { +- bool ok = false; +- +- if (currtrace->flags & KSNOOP_F_PREDICATE_EQ && +- currdata->raw_value == currtrace->predicate_value) +- ok = true; +- +- if (currtrace->flags & KSNOOP_F_PREDICATE_NOTEQ && +- currdata->raw_value != currtrace->predicate_value) +- ok = true; +- +- if (currtrace->flags & KSNOOP_F_PREDICATE_GT && +- currdata->raw_value > currtrace->predicate_value) +- ok = true; +- +- if (currtrace->flags & KSNOOP_F_PREDICATE_LT && +- currdata->raw_value < currtrace->predicate_value) +- ok = true; +- +- if (!ok) { +- clear_trace(trace); +- return 0; +- } +- } +- +- if (currtrace->flags & (KSNOOP_F_PTR | KSNOOP_F_MEMBER)) +- data_ptr = (void *)data; +- else +- data_ptr = &data; +- +- if (trace->buf_len + MAX_TRACE_DATA >= MAX_TRACE_BUF) +- break; +- +- buf_offset = &trace->buf[trace->buf_len]; +- if (buf_offset > &trace->buf[MAX_TRACE_BUF]) { +- currdata->err_type_id = currtrace->type_id; +- currdata->err = -ENOSPC; +- continue; +- } +- currdata->buf_offset = trace->buf_len; +- +- tracesize = currtrace->size; +- if (tracesize > MAX_TRACE_DATA) +- tracesize = MAX_TRACE_DATA; +- ret = bpf_probe_read(buf_offset, tracesize, data_ptr); +- if (ret < 0) { +- currdata->err_type_id = currtrace->type_id; +- currdata->err = ret; +- continue; +- } else { +- currdata->buf_len = tracesize; +- trace->buf_len += tracesize; +- } +- } +- +- /* show accumulated stashed traces (if any) */ +- if ((entry && trace->prev_ip && !trace->next_ip) || +- (!entry && trace->next_ip && !trace->prev_ip)) +- output_stashed_traces(ctx, trace, entry); +- else +- output_trace(ctx, trace); +- +- return 0; +-} +- +-SEC("kprobe/foo") +-int kprobe_entry(struct pt_regs *ctx) +-{ +- return ksnoop(ctx, true); +-} +- +-SEC("kretprobe/foo") +-int kprobe_return(struct pt_regs *ctx) +-{ +- return ksnoop(ctx, false); +-} +- +-char _license[] SEC("license") = "Dual BSD/GPL"; +diff --git a/libbpf-tools/ksnoop.c b/libbpf-tools/ksnoop.c +deleted file mode 100644 +index a5f59a0f..00000000 +--- a/libbpf-tools/ksnoop.c ++++ /dev/null +@@ -1,1013 +0,0 @@ +-/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ +-/* Copyright (c) 2021, Oracle and/or its affiliates. */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include +-#include +-#include +- +-#include "ksnoop.h" +-#include "ksnoop.skel.h" +- +-#ifndef KSNOOP_VERSION +-#define KSNOOP_VERSION "0.1" +-#endif +- +-static volatile sig_atomic_t exiting = 0; +- +-static struct btf *vmlinux_btf; +-static const char *bin_name; +-static int pages = PAGES_DEFAULT; +- +-enum log_level { +- DEBUG, +- WARN, +- ERROR, +-}; +- +-static enum log_level log_level = WARN; +-static bool verbose = false; +- +-static __u32 filter_pid; +-static bool stack_mode; +- +-#define libbpf_errstr(val) strerror(-libbpf_get_error(val)) +- +-static void __p(enum log_level level, char *level_str, char *fmt, ...) +-{ +- va_list ap; +- +- if (level < log_level) +- return; +- va_start(ap, fmt); +- fprintf(stderr, "%s: ", level_str); +- vfprintf(stderr, fmt, ap); +- fprintf(stderr, "\n"); +- va_end(ap); +- fflush(stderr); +-} +- +-#define p_err(fmt, ...) __p(ERROR, "Error", fmt, ##__VA_ARGS__) +-#define p_warn(fmt, ...) __p(WARNING, "Warn", fmt, ##__VA_ARGS__) +-#define p_debug(fmt, ...) __p(DEBUG, "Debug", fmt, ##__VA_ARGS__) +- +-static int do_version(int argc, char **argv) +-{ +- printf("%s v%s\n", bin_name, KSNOOP_VERSION); +- return 0; +-} +- +-static int cmd_help(int argc, char **argv) +-{ +- fprintf(stderr, +- "Usage: %s [OPTIONS] [COMMAND | help] FUNC\n" +- " COMMAND := { trace | info }\n" +- " FUNC := { name | name(ARG[,ARG]*) }\n" +- " ARG := { arg | arg [PRED] | arg->member [PRED] }\n" +- " PRED := { == | != | > | >= | < | <= value }\n" +- " OPTIONS := { {-d|--debug} | {-v|--verbose} | {-V|--version} |\n" +- " {-p|--pid filter_pid}|\n" +- " {-P|--pages nr_pages} }\n" +- " {-s|--stack}\n", +- bin_name); +- fprintf(stderr, +- "Examples:\n" +- " %s info ip_send_skb\n" +- " %s trace ip_send_skb\n" +- " %s trace \"ip_send_skb(skb, return)\"\n" +- " %s trace \"ip_send_skb(skb->sk, return)\"\n" +- " %s trace \"ip_send_skb(skb->len > 128, skb)\"\n" +- " %s trace -s udp_sendmsg ip_send_skb\n", +- bin_name, bin_name, bin_name, bin_name, bin_name, bin_name); +- return 0; +-} +- +-static void usage(void) +-{ +- cmd_help(0, NULL); +- exit(1); +-} +- +-static void type_to_value(struct btf *btf, char *name, __u32 type_id, +- struct value *val) +-{ +- const struct btf_type *type; +- __s32 id = type_id; +- +- if (strlen(val->name) == 0) { +- if (name) +- strncpy(val->name, name, +- sizeof(val->name) - 1); +- else +- val->name[0] = '\0'; +- } +- do { +- type = btf__type_by_id(btf, id); +- +- switch (BTF_INFO_KIND(type->info)) { +- case BTF_KIND_CONST: +- case BTF_KIND_VOLATILE: +- case BTF_KIND_RESTRICT: +- id = type->type; +- break; +- case BTF_KIND_PTR: +- val->flags |= KSNOOP_F_PTR; +- id = type->type; +- break; +- default: +- val->type_id = id; +- goto done; +- } +- } while (id >= 0); +- +- val->type_id = KSNOOP_ID_UNKNOWN; +- return; +-done: +- val->size = btf__resolve_size(btf, val->type_id); +-} +- +-static int member_to_value(struct btf *btf, const char *name, __u32 type_id, +- struct value *val, int lvl) +-{ +- const struct btf_member *member; +- const struct btf_type *type; +- const char *pname; +- __s32 id = type_id; +- int i, nmembers; +- __u8 kind; +- +- /* type_to_value has already stripped qualifiers, so +- * we either have a base type, a struct, union, etc. +- * Only struct/unions have named members so anything +- * else is invalid. +- */ +- p_debug("Looking for member '%s' in type id %d", name, type_id); +- type = btf__type_by_id(btf, id); +- pname = btf__str_by_offset(btf, type->name_off); +- if (strlen(pname) == 0) +- pname = ""; +- +- kind = BTF_INFO_KIND(type->info); +- switch (kind) { +- case BTF_KIND_STRUCT: +- case BTF_KIND_UNION: +- nmembers = BTF_INFO_VLEN(type->info); +- p_debug("Checking %d members...", nmembers); +- for (member = (struct btf_member *)(type + 1), i = 0; +- i < nmembers; +- member++, i++) { +- const char *mname; +- __u16 offset; +- +- type = btf__type_by_id(btf, member->type); +- mname = btf__str_by_offset(btf, member->name_off); +- offset = member->offset / 8; +- +- p_debug("Checking member '%s' type %d offset %d", +- mname, member->type, offset); +- +- /* anonymous struct member? */ +- kind = BTF_INFO_KIND(type->info); +- if (strlen(mname) == 0 && +- (kind == BTF_KIND_STRUCT || +- kind == BTF_KIND_UNION)) { +- p_debug("Checking anon struct/union %d", +- member->type); +- val->offset += offset; +- if (!member_to_value(btf, name, member->type, +- val, lvl + 1)) +- return 0; +- val->offset -= offset; +- continue; +- } +- +- if (strcmp(mname, name) == 0) { +- val->offset += offset; +- val->flags |= KSNOOP_F_MEMBER; +- type_to_value(btf, NULL, member->type, val); +- p_debug("Member '%s', offset %d, flags %x size %d", +- mname, val->offset, val->flags, +- val->size); +- return 0; +- } +- } +- if (lvl > 0) +- break; +- p_err("No member '%s' found in %s [%d], offset %d", name, pname, +- id, val->offset); +- break; +- default: +- p_err("'%s' is not a struct/union", pname); +- break; +- } +- return -ENOENT; +-} +- +-static int get_func_btf(struct btf *btf, struct func *func) +-{ +- const struct btf_param *param; +- const struct btf_type *type; +- __u8 i; +- +- func->id = btf__find_by_name_kind(btf, func->name, BTF_KIND_FUNC); +- if (func->id <= 0) { +- p_err("Cannot find function '%s' in BTF: %s", +- func->name, strerror(-func->id)); +- return -ENOENT; +- } +- type = btf__type_by_id(btf, func->id); +- if (libbpf_get_error(type) || +- BTF_INFO_KIND(type->info) != BTF_KIND_FUNC) { +- p_err("Error looking up function type via id '%d'", func->id); +- return -EINVAL; +- } +- type = btf__type_by_id(btf, type->type); +- if (libbpf_get_error(type) || +- BTF_INFO_KIND(type->info) != BTF_KIND_FUNC_PROTO) { +- p_err("Error looking up function proto type via id '%d'", +- func->id); +- return -EINVAL; +- } +- for (param = (struct btf_param *)(type + 1), i = 0; +- i < BTF_INFO_VLEN(type->info) && i < MAX_ARGS; +- param++, i++) { +- type_to_value(btf, +- (char *)btf__str_by_offset(btf, param->name_off), +- param->type, &func->args[i]); +- p_debug("arg #%d: ", +- i + 1, func->args[i].name, func->args[i].type_id); +- } +- +- /* real number of args, even if it is > number we recorded. */ +- func->nr_args = BTF_INFO_VLEN(type->info); +- +- type_to_value(btf, KSNOOP_RETURN_NAME, type->type, +- &func->args[KSNOOP_RETURN]); +- p_debug("return value: type id '%u'>", +- func->args[KSNOOP_RETURN].type_id); +- return 0; +-} +- +-static int predicate_to_value(char *predicate, struct value *val) +-{ +- char pred[MAX_STR]; +- long v; +- +- if (!predicate) +- return 0; +- +- p_debug("checking predicate '%s' for '%s'", predicate, val->name); +- +- if (sscanf(predicate, "%[!=><]%li", pred, &v) != 2) { +- p_err("Invalid specification; expected predicate, not '%s'", +- predicate); +- return -EINVAL; +- } +- if (!(val->flags & KSNOOP_F_PTR) && +- (val->size == 0 || val->size > sizeof(__u64))) { +- p_err("'%s' (size %d) does not support predicate comparison", +- val->name, val->size); +- return -EINVAL; +- } +- val->predicate_value = (__u64)v; +- +- if (strcmp(pred, "==") == 0) { +- val->flags |= KSNOOP_F_PREDICATE_EQ; +- goto out; +- } else if (strcmp(pred, "!=") == 0) { +- val->flags |= KSNOOP_F_PREDICATE_NOTEQ; +- goto out; +- } +- if (pred[0] == '>') +- val->flags |= KSNOOP_F_PREDICATE_GT; +- else if (pred[0] == '<') +- val->flags |= KSNOOP_F_PREDICATE_LT; +- +- if (strlen(pred) == 1) +- goto out; +- +- if (pred[1] != '=') { +- p_err("Invalid predicate specification '%s'", predicate); +- return -EINVAL; +- } +- val->flags |= KSNOOP_F_PREDICATE_EQ; +- +-out: +- p_debug("predicate '%s', flags 0x%x value %x", +- pred, val->flags, val->predicate_value); +- +- return 0; +-} +- +-static int trace_to_value(struct btf *btf, struct func *func, char *argname, +- char *membername, char *predicate, struct value *val) +-{ +- __u8 i; +- +- if (strlen(membername) > 0) +- snprintf(val->name, sizeof(val->name), "%s->%s", +- argname, membername); +- else +- strncpy(val->name, argname, sizeof(val->name)); +- +- for (i = 0; i < MAX_TRACES; i++) { +- if (!func->args[i].name) +- continue; +- if (strcmp(argname, func->args[i].name) != 0) +- continue; +- p_debug("setting base arg for val %s to %d", val->name, i); +- val->base_arg = i; +- +- if (strlen(membername) > 0) { +- if (member_to_value(btf, membername, +- func->args[i].type_id, val, 0)) +- return -ENOENT; +- } else { +- val->type_id = func->args[i].type_id; +- val->flags |= func->args[i].flags; +- val->size = func->args[i].size; +- } +- return predicate_to_value(predicate, val); +- } +- p_err("Could not find '%s' in arguments/return value for '%s'", +- argname, func->name); +- return -ENOENT; +-} +- +-static struct btf *get_btf(const char *name) +-{ +- struct btf *mod_btf; +- +- p_debug("getting BTF for %s", +- name && strlen(name) > 0 ? name : "vmlinux"); +- +- if (!vmlinux_btf) { +- vmlinux_btf = libbpf_find_kernel_btf(); +- if (libbpf_get_error(vmlinux_btf)) { +- p_err("No BTF, cannot determine type info: %s", +- libbpf_errstr(vmlinux_btf)); +- return NULL; +- } +- } +- if (!name || strlen(name) == 0) +- return vmlinux_btf; +- +- mod_btf = btf__load_module_btf(name, vmlinux_btf); +- if (libbpf_get_error(mod_btf)) { +- p_err("No BTF for module '%s': %s", +- name, libbpf_errstr(mod_btf)); +- return NULL; +- } +- return mod_btf; +-} +- +-static void copy_without_spaces(char *target, char *src) +-{ +- for (; *src != '\0'; src++) +- if (!isspace(*src)) +- *(target++) = *src; +- *target = '\0'; +-} +- +-static char *type_id_to_str(struct btf *btf, __s32 type_id, char *str) +-{ +- const struct btf_type *type; +- const char *name = ""; +- char *prefix = ""; +- char *suffix = " "; +- char *ptr = ""; +- +- str[0] = '\0'; +- +- switch (type_id) { +- case 0: +- name = "void"; +- break; +- case KSNOOP_ID_UNKNOWN: +- name = "?"; +- break; +- default: +- do { +- type = btf__type_by_id(btf, type_id); +- +- if (libbpf_get_error(type)) { +- name = "?"; +- break; +- } +- switch (BTF_INFO_KIND(type->info)) { +- case BTF_KIND_CONST: +- case BTF_KIND_VOLATILE: +- case BTF_KIND_RESTRICT: +- type_id = type->type; +- break; +- case BTF_KIND_PTR: +- ptr = "* "; +- type_id = type->type; +- break; +- case BTF_KIND_ARRAY: +- suffix = "[]"; +- type_id = type->type; +- break; +- case BTF_KIND_STRUCT: +- prefix = "struct "; +- name = btf__str_by_offset(btf, type->name_off); +- break; +- case BTF_KIND_UNION: +- prefix = "union "; +- name = btf__str_by_offset(btf, type->name_off); +- break; +- case BTF_KIND_ENUM: +- prefix = "enum "; +- name = btf__str_by_offset(btf, type->name_off); +- break; +- case BTF_KIND_TYPEDEF: +- name = btf__str_by_offset(btf, type->name_off); +- break; +- default: +- name = btf__str_by_offset(btf, type->name_off); +- break; +- } +- } while (type_id >= 0 && strlen(name) == 0); +- break; +- } +- snprintf(str, MAX_STR, "%s%s%s%s", prefix, name, suffix, ptr); +- +- return str; +-} +- +-static char *value_to_str(struct btf *btf, struct value *val, char *str) +-{ +- +- str = type_id_to_str(btf, val->type_id, str); +- if (val->flags & KSNOOP_F_PTR) +- strncat(str, "*", MAX_STR); +- if (strlen(val->name) > 0 && +- strcmp(val->name, KSNOOP_RETURN_NAME) != 0) +- strncat(str, val->name, MAX_STR); +- +- return str; +-} +- +-/* based heavily on bpf_object__read_kallsyms_file() in libbpf.c */ +-static int get_func_ip_mod(struct func *func) +-{ +- char sym_type, sym_name[MAX_STR], mod_info[MAX_STR]; +- unsigned long long sym_addr; +- int ret, err = 0; +- FILE *f; +- +- f = fopen("/proc/kallsyms", "r"); +- if (!f) { +- err = errno; +- p_err("failed to open /proc/kallsyms: %d", strerror(err)); +- return err; +- } +- +- while (true) { +- ret = fscanf(f, "%llx %c %128s%[^\n]\n", +- &sym_addr, &sym_type, sym_name, mod_info); +- if (ret == EOF && feof(f)) +- break; +- if (ret < 3) { +- p_err("failed to read kallsyms entry: %d", ret); +- err = -EINVAL; +- goto out; +- } +- if (strcmp(func->name, sym_name) != 0) +- continue; +- func->ip = sym_addr; +- func->mod[0] = '\0'; +- /* get module name from [modname] */ +- if (ret == 4) { +- if (sscanf(mod_info, "%*[\t ][%[^]]", func->mod) < 1) { +- p_err("failed to read module name"); +- err = -EINVAL; +- goto out; +- } +- } +- p_debug("%s = ", func->name, func->ip, +- strlen(func->mod) > 0 ? func->mod : "vmlinux"); +- break; +- } +-out: +- fclose(f); +- return err; +-} +- +-static void trace_printf(void *ctx, const char *fmt, va_list args) +-{ +- vprintf(fmt, args); +-} +- +-#define VALID_NAME "%[A-Za-z0-9\\-_]" +-#define ARGDATA "%[^)]" +- +-static int parse_trace(char *str, struct trace *trace) +-{ +- __u8 i, nr_predicates = 0, nr_entry = 0, nr_return = 0; +- char argname[MAX_NAME], membername[MAX_NAME]; +- char tracestr[MAX_STR], argdata[MAX_STR]; +- struct func *func = &trace->func; +- struct btf_dump_opts opts = { }; +- char *arg, *saveptr; +- int ret; +- +- copy_without_spaces(tracestr, str); +- +- p_debug("Parsing trace '%s'", tracestr); +- +- trace->filter_pid = (__u32)filter_pid; +- if (filter_pid) +- p_debug("Using pid %lu as filter", trace->filter_pid); +- +- trace->btf = vmlinux_btf; +- +- ret = sscanf(tracestr, VALID_NAME "(" ARGDATA ")", func->name, argdata); +- if (ret <= 0) +- usage(); +- if (ret == 1) { +- if (strlen(tracestr) > strlen(func->name)) { +- p_err("Invalid function specification '%s'", tracestr); +- usage(); +- } +- argdata[0] = '\0'; +- p_debug("got func '%s'", func->name); +- } else { +- if (strlen(tracestr) > +- strlen(func->name) + strlen(argdata) + 2) { +- p_err("Invalid function specification '%s'", tracestr); +- usage(); +- } +- p_debug("got func '%s', args '%s'", func->name, argdata); +- trace->flags |= KSNOOP_F_CUSTOM; +- } +- +- ret = get_func_ip_mod(func); +- if (ret) { +- p_err("could not get address of '%s'", func->name); +- return ret; +- } +- trace->btf = get_btf(func->mod); +- if (libbpf_get_error(trace->btf)) { +- p_err("could not get BTF for '%s': %s", +- strlen(func->mod) ? func->mod : "vmlinux", +- libbpf_errstr(trace->btf)); +- return -ENOENT; +- } +- trace->dump = btf_dump__new(trace->btf, NULL, &opts, trace_printf); +- if (libbpf_get_error(trace->dump)) { +- p_err("could not create BTF dump : %n", +- libbpf_errstr(trace->btf)); +- return -EINVAL; +- } +- +- ret = get_func_btf(trace->btf, func); +- if (ret) { +- p_debug("unexpected return value '%d' getting function", ret); +- return ret; +- } +- +- for (arg = strtok_r(argdata, ",", &saveptr), i = 0; +- arg; +- arg = strtok_r(NULL, ",", &saveptr), i++) { +- char *predicate = NULL; +- +- ret = sscanf(arg, VALID_NAME "->" VALID_NAME, +- argname, membername); +- if (ret == 2) { +- if (strlen(arg) > +- strlen(argname) + strlen(membername) + 2) { +- predicate = arg + strlen(argname) + +- strlen(membername) + 2; +- } +- p_debug("'%s' dereferences '%s', predicate '%s'", +- argname, membername, predicate); +- } else { +- if (strlen(arg) > strlen(argname)) +- predicate = arg + strlen(argname); +- p_debug("'%s' arg, predcate '%s'", argname, predicate); +- membername[0] = '\0'; +- } +- +- if (i >= MAX_TRACES) { +- p_err("Too many arguments; up to %d are supported", +- MAX_TRACES); +- return -EINVAL; +- } +- if (trace_to_value(trace->btf, func, argname, membername, +- predicate, &trace->traces[i])) +- return -EINVAL; +- +- if (predicate) +- nr_predicates++; +- if (trace->traces[i].base_arg == KSNOOP_RETURN) +- nr_return++; +- else +- nr_entry++; +- trace->nr_traces++; +- } +- +- if (trace->nr_traces > 0) { +- trace->flags |= KSNOOP_F_CUSTOM; +- p_debug("custom trace with %d args", trace->nr_traces); +- +- /* If we have one or more predicates _and_ references to +- * entry and return values, we need to activate "stash" +- * mode where arg traces are stored on entry and not +- * sent until return to ensure predicates are satisfied. +- */ +- if (nr_predicates > 0 && nr_entry > 0 && nr_return > 0) { +- trace->flags |= KSNOOP_F_STASH; +- p_debug("activating stash mode on entry"); +- } +- } else { +- p_debug("Standard trace, function with %d arguments", +- func->nr_args); +- /* copy function arg/return value to trace specification. */ +- memcpy(trace->traces, func->args, sizeof(trace->traces)); +- for (i = 0; i < MAX_TRACES; i++) +- trace->traces[i].base_arg = i; +- trace->nr_traces = MAX_TRACES; +- } +- +- return 0; +-} +- +-static int parse_traces(int argc, char **argv, struct trace **traces) +-{ +- __u8 i; +- +- if (argc == 0) +- usage(); +- +- if (argc > MAX_FUNC_TRACES) { +- p_err("A maximum of %d traces are supported", MAX_FUNC_TRACES); +- return -EINVAL; +- } +- *traces = calloc(argc, sizeof(struct trace)); +- if (!*traces) { +- p_err("Could not allocate %d traces", argc); +- return -ENOMEM; +- } +- for (i = 0; i < argc; i++) { +- if (parse_trace(argv[i], &((*traces)[i]))) +- return -EINVAL; +- if (!stack_mode || i == 0) +- continue; +- /* tell stack mode trace which function to expect next */ +- (*traces)[i].prev_ip = (*traces)[i-1].func.ip; +- (*traces)[i-1].next_ip = (*traces)[i].func.ip; +- } +- return i; +-} +- +-static int cmd_info(int argc, char **argv) +-{ +- struct trace *traces = NULL; +- char str[MAX_STR]; +- int nr_traces; +- __u8 i, j; +- +- nr_traces = parse_traces(argc, argv, &traces); +- if (nr_traces < 0) +- return nr_traces; +- +- for (i = 0; i < nr_traces; i++) { +- struct func *func = &traces[i].func; +- +- printf("%s%s(", +- value_to_str(traces[i].btf, &func->args[KSNOOP_RETURN], +- str), +- func->name); +- for (j = 0; j < func->nr_args; j++) { +- if (j > 0) +- printf(", "); +- printf("%s", value_to_str(traces[i].btf, &func->args[j], +- str)); +- } +- if (func->nr_args > MAX_ARGS) +- printf(" /* and %d more args that are not traceable */", +- func->nr_args - MAX_ARGS); +- printf(");\n"); +- } +- free(traces); +- return 0; +-} +- +-static void trace_handler(void *ctx, int cpu, void *data, __u32 size) +-{ +- struct trace *trace = data; +- int i, shown, ret; +- +- p_debug("got trace, size %d", size); +- if (size < (sizeof(*trace) - MAX_TRACE_BUF)) { +- p_err("\t/* trace buffer size '%u' < min %ld */", +- size, sizeof(trace) - MAX_TRACE_BUF); +- return; +- } +- printf("%16lld %4d %8u %s(\n", trace->time, trace->cpu, trace->pid, +- trace->func.name); +- +- for (i = 0, shown = 0; i < trace->nr_traces; i++) { +- DECLARE_LIBBPF_OPTS(btf_dump_type_data_opts, opts); +- bool entry = trace->data_flags & KSNOOP_F_ENTRY; +- struct value *val = &trace->traces[i]; +- struct trace_data *data = &trace->trace_data[i]; +- +- opts.indent_level = 36; +- opts.indent_str = " "; +- +- /* skip if it's entry data and trace data is for return, or +- * if it's return and trace data is entry; only exception in +- * the latter case is if we stashed data; in such cases we +- * want to see it as it's a mix of entry/return data with +- * predicates. +- */ +- if ((entry && !base_arg_is_entry(val->base_arg)) || +- (!entry && base_arg_is_entry(val->base_arg) && +- !(trace->flags & KSNOOP_F_STASH))) +- continue; +- +- if (val->type_id == 0) +- continue; +- +- if (shown > 0) +- printf(",\n"); +- printf("%34s %s = ", "", val->name); +- if (val->flags & KSNOOP_F_PTR) +- printf("*(0x%llx)", data->raw_value); +- printf("\n"); +- +- if (data->err_type_id != 0) { +- char typestr[MAX_STR]; +- +- printf("%36s /* Cannot show '%s' as '%s%s'; invalid/userspace ptr? */\n", +- "", +- val->name, +- type_id_to_str(trace->btf, +- val->type_id, +- typestr), +- val->flags & KSNOOP_F_PTR ? +- " *" : ""); +- } else { +- ret = btf_dump__dump_type_data +- (trace->dump, val->type_id, +- trace->buf + data->buf_offset, +- data->buf_len, &opts); +- /* truncated? */ +- if (ret == -E2BIG) +- printf("%36s... /* %d bytes of %d */", "", +- data->buf_len, +- val->size); +- } +- shown++; +- +- } +- printf("\n%31s);\n\n", ""); +- fflush(stdout); +-} +- +-static void lost_handler(void *ctx, int cpu, __u64 cnt) +-{ +- p_err("\t/* lost %llu events */", cnt); +-} +- +-static void sig_int(int signo) +-{ +- exiting = 1; +-} +- +-static int add_traces(struct bpf_map *func_map, struct trace *traces, +- int nr_traces) +-{ +- int i, j, ret, nr_cpus = libbpf_num_possible_cpus(); +- struct trace *map_traces; +- +- map_traces = calloc(nr_cpus, sizeof(struct trace)); +- if (!map_traces) { +- p_err("Could not allocate memory for %d traces", nr_traces); +- return -ENOMEM; +- } +- for (i = 0; i < nr_traces; i++) { +- for (j = 0; j < nr_cpus; j++) +- memcpy(&map_traces[j], &traces[i], +- sizeof(map_traces[j])); +- +- ret = bpf_map_update_elem(bpf_map__fd(func_map), +- &traces[i].func.ip, +- map_traces, +- BPF_NOEXIST); +- if (ret) { +- p_err("Could not add map entry for '%s': %s", +- traces[i].func.name, strerror(-ret)); +- break; +- } +- } +- free(map_traces); +- return ret; +-} +- +-static int attach_traces(struct ksnoop_bpf *skel, struct trace *traces, +- int nr_traces) +-{ +- int i, ret; +- +- for (i = 0; i < nr_traces; i++) { +- traces[i].links[0] = +- bpf_program__attach_kprobe(skel->progs.kprobe_entry, +- false, +- traces[i].func.name); +- ret = libbpf_get_error(traces[i].links[0]); +- if (ret) { +- p_err("Could not attach kprobe to '%s': %s", +- traces[i].func.name, strerror(-ret)); +- return ret; +- } +- p_debug("Attached kprobe for '%s'", traces[i].func.name); +- +- traces[i].links[1] = +- bpf_program__attach_kprobe(skel->progs.kprobe_return, +- true, +- traces[i].func.name); +- ret = libbpf_get_error(traces[i].links[1]); +- if (ret) { +- p_err("Could not attach kretprobe to '%s': %s", +- traces[i].func.name, strerror(-ret)); +- return ret; +- } +- p_debug("Attached kretprobe for '%s'", traces[i].func.name); +- } +- return 0; +-} +- +-static int cmd_trace(int argc, char **argv) +-{ +- struct perf_buffer_opts pb_opts = {}; +- struct bpf_map *perf_map, *func_map; +- struct perf_buffer *pb = NULL; +- struct ksnoop_bpf *skel; +- int i, nr_traces, ret = -1; +- struct trace *traces = NULL; +- +- nr_traces = parse_traces(argc, argv, &traces); +- if (nr_traces < 0) +- return nr_traces; +- +- skel = ksnoop_bpf__open_and_load(); +- if (!skel) { +- p_err("Could not load ksnoop BPF: %s", libbpf_errstr(skel)); +- return 1; +- } +- +- perf_map = skel->maps.ksnoop_perf_map; +- if (!perf_map) { +- p_err("Could not find '%s'", "ksnoop_perf_map"); +- goto cleanup; +- } +- func_map = bpf_object__find_map_by_name(skel->obj, "ksnoop_func_map"); +- if (!func_map) { +- p_err("Could not find '%s'", "ksnoop_func_map"); +- goto cleanup; +- } +- +- if (add_traces(func_map, traces, nr_traces)) { +- p_err("Could not add traces to '%s'", "ksnoop_func_map"); +- goto cleanup; +- } +- +- if (attach_traces(skel, traces, nr_traces)) { +- p_err("Could not attach %d traces", nr_traces); +- goto cleanup; +- } +- +- pb_opts.sample_cb = trace_handler; +- pb_opts.lost_cb = lost_handler; +- pb = perf_buffer__new(bpf_map__fd(perf_map), pages, &pb_opts); +- if (libbpf_get_error(pb)) { +- p_err("Could not create perf buffer: %s", +- libbpf_errstr(pb)); +- goto cleanup; +- } +- +- printf("%16s %4s %8s %s\n", "TIME", "CPU", "PID", "FUNCTION/ARGS"); +- +- if (signal(SIGINT, sig_int) == SIG_ERR) { +- fprintf(stderr, "can't set signal handler: %s\n", strerror(errno)); +- ret = 1; +- goto cleanup; +- } +- +- while (!exiting) { +- ret = perf_buffer__poll(pb, 1); +- if (ret < 0 && errno != EINTR) { +- fprintf(stderr, "error polling perf buffer: %s\n", strerror(errno)); +- goto cleanup; +- } +- /* reset ret to return 0 if exiting */ +- ret = 0; +- } +- +-cleanup: +- for (i = 0; i < nr_traces; i++) { +- bpf_link__destroy(traces[i].links[0]); +- bpf_link__destroy(traces[i].links[1]); +- } +- free(traces); +- perf_buffer__free(pb); +- ksnoop_bpf__destroy(skel); +- +- return ret; +-} +- +-struct cmd { +- const char *cmd; +- int (*func)(int argc, char **argv); +-}; +- +-struct cmd cmds[] = { +- { "info", cmd_info }, +- { "trace", cmd_trace }, +- { "help", cmd_help }, +- { NULL, NULL } +-}; +- +-static int cmd_select(int argc, char **argv) +-{ +- int i; +- +- for (i = 0; cmds[i].cmd; i++) { +- if (strncmp(*argv, cmds[i].cmd, strlen(*argv)) == 0) +- return cmds[i].func(argc - 1, argv + 1); +- } +- return cmd_trace(argc, argv); +-} +- +-static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args) +-{ +- if (level == LIBBPF_DEBUG && !verbose) +- return 0; +- return vfprintf(stderr, format, args); +-} +- +-int main(int argc, char *argv[]) +-{ +- static const struct option options[] = { +- { "debug", no_argument, NULL, 'd' }, +- { "verbose", no_argument, NULL, 'v' }, +- { "help", no_argument, NULL, 'h' }, +- { "version", no_argument, NULL, 'V' }, +- { "pages", required_argument, NULL, 'P' }, +- { "pid", required_argument, NULL, 'p' }, +- { 0 } +- }; +- int opt; +- +- bin_name = argv[0]; +- +- while ((opt = getopt_long(argc, argv, "dvhp:P:sV", options, +- NULL)) >= 0) { +- switch (opt) { +- case 'd': +- verbose = true; +- log_level = DEBUG; +- break; +- case 'v': +- verbose = true; +- log_level = DEBUG; +- break; +- case 'h': +- return cmd_help(argc, argv); +- case 'V': +- return do_version(argc, argv); +- case 'p': +- filter_pid = atoi(optarg); +- break; +- case 'P': +- pages = atoi(optarg); +- break; +- case 's': +- stack_mode = true; +- break; +- default: +- p_err("unrecognized option '%s'", argv[optind - 1]); +- usage(); +- } +- } +- if (argc == 1) +- usage(); +- argc -= optind; +- argv += optind; +- if (argc < 0) +- usage(); +- +- libbpf_set_print(libbpf_print_fn); +- +- return cmd_select(argc, argv); +-} +diff --git a/libbpf-tools/ksnoop.h b/libbpf-tools/ksnoop.h +deleted file mode 100644 +index 6b33df4e..00000000 +--- a/libbpf-tools/ksnoop.h ++++ /dev/null +@@ -1,123 +0,0 @@ +-/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ +-/* Copyright (c) 2021, Oracle and/or its affiliates. */ +- +-/* maximum number of different functions we can trace at once */ +-#define MAX_FUNC_TRACES 64 +- +-enum arg { +- KSNOOP_ARG1, +- KSNOOP_ARG2, +- KSNOOP_ARG3, +- KSNOOP_ARG4, +- KSNOOP_ARG5, +- KSNOOP_RETURN +-}; +- +-/* we choose "return" as the name for the returned value because as +- * a C keyword it can't clash with a function entry parameter. +- */ +-#define KSNOOP_RETURN_NAME "return" +- +-/* if we can't get a type id for a type (such as module-specific type) +- * mark it as KSNOOP_ID_UNKNOWN since BTF lookup in bpf_snprintf_btf() +- * will fail and the data will be simply displayed as a __u64. +- */ +-#define KSNOOP_ID_UNKNOWN 0xffffffff +- +-#define MAX_NAME 96 +-#define MAX_STR 256 +-#define MAX_PATH 512 +-#define MAX_VALUES 6 +-#define MAX_ARGS (MAX_VALUES - 1) +-#define KSNOOP_F_PTR 0x1 /* value is a pointer */ +-#define KSNOOP_F_MEMBER 0x2 /* member reference */ +-#define KSNOOP_F_ENTRY 0x4 +-#define KSNOOP_F_RETURN 0x8 +-#define KSNOOP_F_CUSTOM 0x10 /* custom trace */ +-#define KSNOOP_F_STASH 0x20 /* store values on entry, +- * no perf events. +- */ +-#define KSNOOP_F_STASHED 0x40 /* values stored on entry */ +- +-#define KSNOOP_F_PREDICATE_EQ 0x100 +-#define KSNOOP_F_PREDICATE_NOTEQ 0x200 +-#define KSNOOP_F_PREDICATE_GT 0x400 +-#define KSNOOP_F_PREDICATE_LT 0x800 +- +-#define KSNOOP_F_PREDICATE_MASK (KSNOOP_F_PREDICATE_EQ | \ +- KSNOOP_F_PREDICATE_NOTEQ | \ +- KSNOOP_F_PREDICATE_GT | \ +- KSNOOP_F_PREDICATE_LT) +- +-/* for kprobes, entry is function IP + sizeof(kprobe_opcode_t), +- * subtract in BPF prog context to get fn address. +- */ +-#ifdef __TARGET_ARCH_x86 +-#define KSNOOP_IP_FIX(ip) (ip - sizeof(kprobe_opcode_t)) +-#else +-#define KSNOOP_IP_FIX(ip) ip +-#endif +- +-struct value { +- char name[MAX_STR]; +- enum arg base_arg; +- __u32 offset; +- __u32 size; +- __u64 type_id; +- __u64 flags; +- __u64 predicate_value; +-}; +- +-struct func { +- char name[MAX_NAME]; +- char mod[MAX_NAME]; +- __s32 id; +- __u8 nr_args; +- __u64 ip; +- struct value args[MAX_VALUES]; +-}; +- +-#define MAX_TRACES MAX_VALUES +- +-#define MAX_TRACE_DATA 2048 +- +-struct trace_data { +- __u64 raw_value; +- __u32 err_type_id; /* type id we can't dereference */ +- int err; +- __u32 buf_offset; +- __u16 buf_len; +-}; +- +-#define MAX_TRACE_BUF (MAX_TRACES * MAX_TRACE_DATA) +- +-struct trace { +- /* initial values are readonly in tracing context */ +- struct btf *btf; +- struct btf_dump *dump; +- struct func func; +- __u8 nr_traces; +- __u32 filter_pid; +- __u64 prev_ip; /* these are used in stack-mode tracing */ +- __u64 next_ip; +- struct value traces[MAX_TRACES]; +- __u64 flags; +- /* values below this point are set or modified in tracing context */ +- __u64 task; +- __u32 pid; +- __u32 cpu; +- __u64 time; +- __u64 data_flags; +- struct trace_data trace_data[MAX_TRACES]; +- __u16 buf_len; +- char buf[MAX_TRACE_BUF]; +- char buf_end[0]; +- struct bpf_link *links[2]; +-}; +- +-#define PAGES_DEFAULT 16 +- +-static inline int base_arg_is_entry(enum arg base_arg) +-{ +- return base_arg != KSNOOP_RETURN; +-} +diff --git a/man/man8/ksnoop.8 b/man/man8/ksnoop.8 +deleted file mode 100644 +index 8733cb73..00000000 +--- a/man/man8/ksnoop.8 ++++ /dev/null +@@ -1,298 +0,0 @@ +-.\" Man page generated from reStructuredText. +-. +-.TH KSNOOP 8 "" "" "" +-.SH NAME +-KSNOOP \- tool for tracing kernel function entry/return showing arguments/return values +-. +-.nr rst2man-indent-level 0 +-. +-.de1 rstReportMargin +-\\$1 \\n[an-margin] +-level \\n[rst2man-indent-level] +-level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +-- +-\\n[rst2man-indent0] +-\\n[rst2man-indent1] +-\\n[rst2man-indent2] +-.. +-.de1 INDENT +-.\" .rstReportMargin pre: +-. RS \\$1 +-. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +-. nr rst2man-indent-level +1 +-.\" .rstReportMargin post: +-.. +-.de UNINDENT +-. RE +-.\" indent \\n[an-margin] +-.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +-.nr rst2man-indent-level -1 +-.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +-.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +-.. +-.SH SYNOPSIS +-.INDENT 0.0 +-.INDENT 3.5 +-\fBksnoop\fP [\fIOPTIONS\fP] { \fICOMMAND\fP \fIFUNC\fP | \fBhelp\fP } +-.sp +-\fIOPTIONS\fP := { { \fB\-V\fP | \fB\-\-version\fP } | { \fB\-h\fP | \fB\-\-help\fP } +-| { [\fB\-P\fP | \fB\-\-pages\fP] nr_pages} | { [\fB\-p\fP | \fB\-\-pid\fP] pid} | +-[{ \fB\-s\fP | \fB\-\-stack\fP }] | [{ \fB\-d\fP | \fB\-\-debug\fP }] } +-.sp +-\fICOMMAND\fP := { \fBtrace\fP | \fBinfo\fP } +-.sp +-\fIFUNC\fP := { \fBname\fP | \fBname\fP(\fBarg\fP[,**arg]) } +-.UNINDENT +-.UNINDENT +-.SH DESCRIPTION +-.INDENT 0.0 +-.INDENT 3.5 +-\fIksnoop\fP allows for inspection of arguments and return values +-associated with function entry/return. +-.INDENT 0.0 +-.TP +-.B \fBksnoop info\fP \fIFUNC\fP +-Show function description, arguments and return value types. +-.TP +-.B \fBksnoop trace\fP \fIFUNC\fP [\fIFUNC\fP] +-Trace function entry and return, showing arguments and +-return values. A function name can simply be specified, +-or a function name along with named arguments, return values. +-\fBreturn\fP is used to specify the return value. +-.UNINDENT +-.sp +-\fIksnoop\fP requires the kernel to provide BTF for itself, and if +-tracing of module data is required, module BTF must be present also. +-Check /sys/kernel/btf to see if BTF is present. +-.sp +-\fBksnoop\fP requires \fICAP_BPF\fP and \fICAP_TRACING\fP capabilities. +-.UNINDENT +-.UNINDENT +-.SH OPTIONS +-.INDENT 0.0 +-.INDENT 3.5 +-.INDENT 0.0 +-.TP +-.B \-h\fP,\fB \-\-help +-Show help information +-.TP +-.B \-V\fP,\fB \-\-version +-Show version. +-.TP +-.B \-d\fP,\fB \-\-debug +-Show debug output. +-.TP +-.B \-p\fP,\fB \-\-pid +-Filter events by pid. +-.TP +-.B \-P\fP,\fB \-\-pages +-Specify number of pages used per\-CPU for perf event +-collection. Default is 8. +-.TP +-.B \-s\fP,\fB \-\-stack +-Specified set of functions are traced if and only +-if they are encountered in the order specified. +-.UNINDENT +-.UNINDENT +-.UNINDENT +-.SH EXAMPLES +-.sp +-\fB# ksnoop info ip_send_skb\fP +-.INDENT 0.0 +-.INDENT 3.5 +-.sp +-.nf +-.ft C +-int ip_send_skb(struct net * net, struct sk_buff * skb); +-.ft P +-.fi +-.UNINDENT +-.UNINDENT +-.sp +-Show function description. +-.sp +-\fB# ksnoop trace ip_send_skb\fP +-.INDENT 0.0 +-.INDENT 3.5 +-.sp +-.nf +-.ft C +- TIME CPU PID FUNCTION/ARGS +-78101668506811 1 2813 ip_send_skb( +- net = *(0xffffffffb5959840) +- (struct net){ +- .passive = (refcount_t){ +- .refs = (atomic_t){ +- .counter = (int)0x2, +- }, +- }, +- .dev_base_seq = (unsigned int)0x18, +- .ifindex = (int)0xf, +- .list = (struct list_head){ +- .next = (struct list_head *)0xffff9895440dc120, +- .prev = (struct list_head *)0xffffffffb595a8d0, +- }, +- ... +- +-79561322965250 1 2813 ip_send_skb( +- return = +- (int)0x0 +- ); +-.ft P +-.fi +-.UNINDENT +-.UNINDENT +-.sp +-Show entry/return for ip_send_skb() with arguments, return values. +-.sp +-\fB# ksnoop trace "ip_send_skb(skb)"\fP +-.INDENT 0.0 +-.INDENT 3.5 +-.sp +-.nf +-.ft C +- TIME CPU PID FUNCTION/ARGS +-78142420834537 1 2813 ip_send_skb( +- skb = *(0xffff989750797c00) +- (struct sk_buff){ +- (union){ +- .sk = (struct sock *)0xffff98966ce19200, +- .ip_defrag_offset = (int)0x6ce19200, +- }, +- (union){ +- (struct){ +- ._skb_refdst = (long unsigned int)0xffff98981dde2d80, +- .destructor = (void (*)(struct sk_buff *))0xffffffffb3e1beb0, +- }, +- ... +-.ft P +-.fi +-.UNINDENT +-.UNINDENT +-.sp +-Show entry argument \fBskb\fP\&. +-.sp +-\fB# ksnoop trace "ip_send_skb(return)"\fP +-.INDENT 0.0 +-.INDENT 3.5 +-.sp +-.nf +-.ft C +- TIME CPU PID FUNCTION/ARGS +-78178228354796 1 2813 ip_send_skb( +- return = +- (int)0x0 +- ); +-.ft P +-.fi +-.UNINDENT +-.UNINDENT +-.sp +-Show return value from ip_send_skb(). +-.sp +-\fB# ksnoop trace "ip_send_skb(skb\->sk)"\fP +-.INDENT 0.0 +-.INDENT 3.5 +-.sp +-.nf +-.ft C +- TIME CPU PID FUNCTION/ARGS +-78207649138829 2 2813 ip_send_skb( +- skb\->sk = *(0xffff98966ce19200) +- (struct sock){ +- .__sk_common = (struct sock_common){ +- (union){ +- .skc_addrpair = (__addrpair)0x1701a8c017d38f8d, +- (struct){ +- .skc_daddr = (__be32)0x17d38f8d, +- .skc_rcv_saddr = (__be32)0x1701a8c0, +- }, +- }, +- ... +-.ft P +-.fi +-.UNINDENT +-.UNINDENT +-.sp +-Trace member information associated with argument. Only one level of +-membership is supported. +-.sp +-\fB# ksnoop \-p 2813 "ip_rcv(dev)"\fP +-.INDENT 0.0 +-.INDENT 3.5 +-.sp +-.nf +-.ft C +- TIME CPU PID FUNCTION/ARGS +-78254803164920 1 2813 ip_rcv( +- dev = *(0xffff9895414cb000) +- (struct net_device){ +- .name = (char[16])[ +- \(aql\(aq, +- \(aqo\(aq, +- ], +- .name_node = (struct netdev_name_node *)0xffff989541515ec0, +- .state = (long unsigned int)0x3, +- ... +-.ft P +-.fi +-.UNINDENT +-.UNINDENT +-.sp +-Trace \fBdev\fP argument of \fBip_rcv()\fP\&. Specify process id 2813 for events +-for that process only. +-.sp +-\fB# ksnoop \-s tcp_sendmsg __tcp_transmit_skb ip_output\fP +-.INDENT 0.0 +-.INDENT 3.5 +-.sp +-.nf +-.ft C +- TIME CPU PID FUNCTION/ARGS +-71827770952903 1 4777 __tcp_transmit_skb( +- sk = *(0xffff9852460a2300) +- (struct sock){ +- .__sk_common = (struct sock_common){ +- (union){ +- .skc_addrpair = (__addrpair)0x61b2af0a35cbfe0a, +-.ft P +-.fi +-.UNINDENT +-.UNINDENT +-.sp +-Trace entry/return of tcp_sendmsg, __tcp_transmit_skb and ip_output when +-tcp_sendmsg leads to a call to __tcp_transmit_skb and that in turn +-leads to a call to ip_output; i.e. with a call graph matching the order +-specified. The order does not have to be direct calls, i.e. function A +-can call another function that calls function B. +-.sp +-\fB# ksnoop "ip_send_skb(skb\->len > 100, skb)"\fP +-.INDENT 0.0 +-.INDENT 3.5 +-.sp +-.nf +-.ft C +- TIME CPU PID FUNCTION/ARGS +-39267395709745 1 2955 ip_send_skb( +- skb\->len = +- (unsigned int)0x89, +- skb = *(0xffff89c8be81e500) +- (struct sk_buff){ +- (union){ +- .sk = (struct sock *)0xffff89c6c59e5580, +- .ip_defrag_offset = (int)0xc59e5580, +- }, +-.ft P +-.fi +-.UNINDENT +-.UNINDENT +-.sp +-Trace ip_send_skb() skbs which have len > 100. +-.SH SEE ALSO +-.INDENT 0.0 +-.INDENT 3.5 +-\fBbpf\fP(2), +-.UNINDENT +-.UNINDENT +-.\" Generated by docutils manpage writer. +-. +-- +2.35.1 + diff --git a/bcc-0.24.0-Revert-libbpf-1.0-changes.patch b/bcc-0.24.0-Revert-libbpf-1.0-changes.patch new file mode 100644 index 0000000..bbf77d5 --- /dev/null +++ b/bcc-0.24.0-Revert-libbpf-1.0-changes.patch @@ -0,0 +1,2331 @@ +From 09cee55c78fe5c165c7d7c21f596c23831f844e1 Mon Sep 17 00:00:00 2001 +From: Jerome Marchand +Date: Tue, 19 Apr 2022 18:02:13 +0200 +Subject: [PATCH] Revert libbpf 1.0 changes + +Revert "libbpf-tools: remove now unnecessary bump_memlock_rlimit()" + +This reverts commit 5d8f5c45b16c389bb342d2b80c9f5e13e4f3b112. + +Revert "libbpf-tools: update vfsstat for libbpf 1.0" + +This reverts commit f083d3dc37372e555133519cb417f893c431eef0. + +Revert "libbpf-tools: update tcprtt for libbpf 1.0" + +This reverts commit a5b6c3cb2d20718ef002e7447046fad877590b91. + +Revert "libbpf-tools: update tcpconnlat for libbpf 1.0" + +This reverts commit aae06012af8cc8c2b592340f8783a2873aad2023. + +Revert "libbpf-tools: update tcpconnect for libbpf 1.0" + +This reverts commit 4051a9e83cb68733af20ce263fcc41c8aadc2622. + +Revert "libbpf-tools: update syscount for libbpf 1.0" + +This reverts commit d2dc7bcd0d94ef54e336119a2a79113b87839820. + +Revert "libbpf-tools: update statsnoop for libbpf 1.0" + +This reverts commit 0e348e5ed66aabd0cd5c0c75932f245bd1385b3b. + +Revert "libbpf-tools: update solisten for libbpf 1.0" + +This reverts commit 60dd074e26e762727e685334999bec5851adaef9. + +Revert "libbpf-tools: update softirqs for libbpf 1.0" + +This reverts commit 92806a435c2e1b248acdb9d0dc5b3eedc86994b0. + +Revert "libbpf-tools: update runqslower for libbpf 1.0" + +This reverts commit e6477620ccfc9abe10f7e630e65381204daa5ba8. + +Revert "libbpf-tools: update runqlen for libbpf 1.0" + +This reverts commit a7f0148372018140940d66f8faf53cb5add1e858. + +Revert "libbpf-tools: update runqlat for libbpf 1.0" + +This reverts commit 865f990b7139dca166a43bbc8159f6acd4bfbee6. + +Revert "libbpf-tools: update readahead for libbpf 1.0" + +This reverts commit 3c5dae6380dcc2034a8746c648e3bb24ea61f886. + +Revert "libbpf-tools: update opensnoop for libbpf 1.0" + +This reverts commit 34a680ba8da7e61befad67ebccb69c5041e9e288. + +Revert "libbpf-tools: update offcputime for libbpf 1.0" + +This reverts commit 5ef6d9922841d7cfde1994c25ccbac53858ed99f. + +Revert "libbpf-tools: update numamove for libbpf 1.0" + +This reverts commit 824ffd2a1fbb527f5fd25e2caa4b43fbf1ee858b. + +Revert "libbpf-tools: update mountsnoop for libbpf 1.0" + +This reverts commit 08301e93e5cea8575d5dc4b66fb7a76cebd5969b. + +Revert "libbpf-tools: update llcstat for libbpf 1.0" + +This reverts commit dbee9ea8ede33166fa70ecc33af7d7721ef26280. + +Revert "libbpf-tools: update hardirqs for libbpf 1.0" + +This reverts commit 8fcf08c81d30d80f89f995f79ef3246ce99c72dd. + +Revert "libbpf-tools: update gethostlatency for libbpf 1.0" + +This reverts commit 54a239abd21df9d6fc5d8db7ae7a26c5d8db2440. + +Revert "libbpf-tools: update funclatency for libbpf 1.0" + +This reverts commit d7b3ed3a8b2169087534738670d108489711f2d1. + +Revert "libbpf-tools: update fsslower for libbpf 1.0" + +This reverts commit 511ab72f046848d6df3f7c6ec0411b1609e165fb. + +Revert "libbpf-tools: update fsdist for libbpf 1.0" + +This reverts commit 21586658c86e1a20e9195d8715d37d714be93bb6. + +Revert "libbpf-tools: update filetop for libbpf 1.0" + +This reverts commit e6d151227f56433a317790d56ba7875ccae00448. + +Revert "libbpf-tools: update filelife for libbpf 1.0" + +This reverts commit 4ca8dd95efb7c4f149b889b700beeda036ebe822. + +Revert "libbpf-tools: update exitsnoop for libbpf 1.0" + +This reverts commit 0a035be644cf818354f3faab25a74e005a66d954. + +Revert "libbpf-tools: update execsnoop for libbpf 1.0" + +This reverts commit 7da38aabbefa41b8553e9fdec7744a5e423b5119. + +Revert "libbpf-tools: update cpudist for libbpf 1.0" + +This reverts commit dab1d09ef49e74c4c95f933e97e16dfc074338c2. + +Revert "libbpf-tools: update drsnoop for libbpf 1.0" + +This reverts commit 9cfdf5e04b32ca079a634ff60de7c08e3c41ccf5. + +Revert "libbpf-tools: fix cpufreq.bpf.c and update cpufreq for libbpf 1.0" + +This reverts commit f2006eaa5901d6ccf51d24b18c644f2fb1d41757. + +Revert "libbpf-tools: update cachestat for libbpf 1.0" + +This reverts commit 4970d23f9ff308c5860612ad6395d7692b05104e. + +Revert "libbpf-tools: update bitesize for libbpf 1.0" + +This reverts commit 7bea6c4ad9a460fc34eb618e488e44ca014e8ac7. + +Revert "libbpf-tools: update biostacks for libbpf 1.0" + +This reverts commit 49bb367628500104411d42851194162bec5d1f4c. + +Revert "libbpf-tools: update biosnoop for libbpf 1.0" + +This reverts commit 519ed8cf9c0daff75ecb3f435a3efec2087945a6. + +Revert "libbpf-tools: update biopattern for libbpf 1.0" + +This reverts commit c5b17e65a6e59fae1223bf493648050643ad9179. + +Revert "libbpf-tools: update biolatency for libbpf 1.0" + +This reverts commit 24d723699fbeeb8686acabc09ecefcceb749b9e0. + +Revert "libbpf-tools: update bindsnoop for libbpf 1.0" + +This reverts commit 7f2f4c4123a55438754b1a29f7ad3d3cfdbc7373. + +Revert "libbpf-tools: update ksnoop for libbpf 1.0" + +This reverts commit 18dc2ac7d84a854e2f5ac9ce1b532a0c59acf49e. + +Revert "libbpf-tools: update bashreadline for libbpf 1.0" + +This reverts commit 2cf0ba491d16386529c50ff0a9ec3eb9f86a2493. + +Signed-off-by: Jerome Marchand +--- + libbpf-tools/bashreadline.c | 24 ++++++++----- + libbpf-tools/bindsnoop.c | 21 +++++++---- + libbpf-tools/biolatency.c | 28 +++++++++------ + libbpf-tools/biopattern.c | 7 +++- + libbpf-tools/biosnoop.c | 67 +++++++++++++++++++++-------------- + libbpf-tools/biostacks.c | 39 ++++++++++++-------- + libbpf-tools/bitesize.c | 7 +++- + libbpf-tools/cachestat.c | 7 +++- + libbpf-tools/cpudist.c | 7 +++- + libbpf-tools/cpufreq.bpf.c | 11 ------ + libbpf-tools/cpufreq.c | 15 +++++--- + libbpf-tools/drsnoop.c | 21 +++++++---- + libbpf-tools/execsnoop.c | 22 ++++++++---- + libbpf-tools/exitsnoop.c | 20 +++++++---- + libbpf-tools/filelife.c | 21 +++++++---- + libbpf-tools/filetop.c | 6 +++- + libbpf-tools/fsdist.c | 38 +++++++++++++------- + libbpf-tools/fsslower.c | 46 ++++++++++++++++-------- + libbpf-tools/funclatency.c | 32 ++++++++++------- + libbpf-tools/gethostlatency.c | 49 +++++++++++++++---------- + libbpf-tools/hardirqs.c | 34 +++++++++++------- + libbpf-tools/ksnoop.c | 65 ++++++++++++++++----------------- + libbpf-tools/llcstat.bpf.c | 4 +-- + libbpf-tools/llcstat.c | 13 +++++-- + libbpf-tools/mountsnoop.c | 20 +++++++---- + libbpf-tools/numamove.c | 16 ++++++--- + libbpf-tools/offcputime.c | 7 +++- + libbpf-tools/opensnoop.c | 21 +++++++---- + libbpf-tools/readahead.c | 7 +++- + libbpf-tools/runqlat.c | 7 +++- + libbpf-tools/runqlen.c | 13 +++++-- + libbpf-tools/runqslower.c | 22 ++++++++---- + libbpf-tools/softirqs.c | 7 +++- + libbpf-tools/solisten.c | 20 +++++++---- + libbpf-tools/statsnoop.c | 20 +++++++---- + libbpf-tools/syscount.c | 18 ++++++---- + libbpf-tools/tcpconnect.c | 25 ++++++++----- + libbpf-tools/tcpconnlat.c | 24 +++++++++---- + libbpf-tools/tcprtt.c | 7 +++- + libbpf-tools/trace_helpers.c | 22 ++++++++---- + libbpf-tools/trace_helpers.h | 1 + + libbpf-tools/vfsstat.c | 8 ++++- + 42 files changed, 576 insertions(+), 293 deletions(-) + +diff --git a/libbpf-tools/bashreadline.c b/libbpf-tools/bashreadline.c +index 2fcb2e2c..ab3b955e 100644 +--- a/libbpf-tools/bashreadline.c ++++ b/libbpf-tools/bashreadline.c +@@ -149,6 +149,7 @@ int main(int argc, char **argv) + .doc = argp_program_doc, + }; + struct bashreadline_bpf *obj = NULL; ++ struct perf_buffer_opts pb_opts; + struct perf_buffer *pb = NULL; + char *readline_so_path; + off_t func_off; +@@ -165,7 +166,11 @@ int main(int argc, char **argv) + return 1; + } + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); ++ err = bump_memlock_rlimit(); ++ if (err) { ++ warn("failed to increase rlimit: %d\n", err); ++ goto cleanup; ++ } + libbpf_set_print(libbpf_print_fn); + + obj = bashreadline_bpf__open_and_load(); +@@ -182,16 +187,17 @@ int main(int argc, char **argv) + + obj->links.printret = bpf_program__attach_uprobe(obj->progs.printret, true, -1, + readline_so_path, func_off); +- if (!obj->links.printret) { +- err = -errno; ++ err = libbpf_get_error(obj->links.printret); ++ if (err) { + warn("failed to attach readline: %d\n", err); + goto cleanup; + } + +- pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES, +- handle_event, handle_lost_events, NULL, NULL); +- if (!pb) { +- err = -errno; ++ pb_opts.sample_cb = handle_event; ++ pb_opts.lost_cb = handle_lost_events; ++ pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES, &pb_opts); ++ err = libbpf_get_error(pb); ++ if (err) { + warn("failed to open perf buffer: %d\n", err); + goto cleanup; + } +@@ -205,8 +211,8 @@ int main(int argc, char **argv) + printf("%-9s %-7s %s\n", "TIME", "PID", "COMMAND"); + while (!exiting) { + err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS); +- if (err < 0 && err != -EINTR) { +- warn("error polling perf buffer: %s\n", strerror(-err)); ++ if (err < 0 && errno != EINTR) { ++ warn("error polling perf buffer: %s\n", strerror(errno)); + goto cleanup; + } + err = 0; +diff --git a/libbpf-tools/bindsnoop.c b/libbpf-tools/bindsnoop.c +index 5d87d484..c75b57e0 100644 +--- a/libbpf-tools/bindsnoop.c ++++ b/libbpf-tools/bindsnoop.c +@@ -174,6 +174,7 @@ int main(int argc, char **argv) + .parser = parse_arg, + .doc = argp_program_doc, + }; ++ struct perf_buffer_opts pb_opts; + struct perf_buffer *pb = NULL; + struct bindsnoop_bpf *obj; + int err, port_map_fd; +@@ -184,7 +185,11 @@ int main(int argc, char **argv) + if (err) + return err; + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); ++ err = bump_memlock_rlimit(); ++ if (err) { ++ warn("failed to increase rlimit: %d\n", err); ++ return 1; ++ } + libbpf_set_print(libbpf_print_fn); + + obj = bindsnoop_bpf__open(); +@@ -219,10 +224,12 @@ int main(int argc, char **argv) + goto cleanup; + } + +- pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES, +- handle_event, handle_lost_events, NULL, NULL); +- if (!pb) { +- err = -errno; ++ pb_opts.sample_cb = handle_event; ++ pb_opts.lost_cb = handle_lost_events; ++ pb = perf_buffer__new(bpf_map__fd(obj->maps.events), ++ PERF_BUFFER_PAGES, &pb_opts); ++ err = libbpf_get_error(pb); ++ if (err) { + warn("failed to open perf buffer: %d\n", err); + goto cleanup; + } +@@ -240,8 +247,8 @@ int main(int argc, char **argv) + + while (!exiting) { + err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS); +- if (err < 0 && err != -EINTR) { +- warn("error polling perf buffer: %s\n", strerror(-err)); ++ if (err < 0 && errno != EINTR) { ++ warn("error polling perf buffer: %s\n", strerror(errno)); + goto cleanup; + } + /* reset err to return 0 if exiting */ +diff --git a/libbpf-tools/biolatency.c b/libbpf-tools/biolatency.c +index 51afa509..f2cf5ffd 100644 +--- a/libbpf-tools/biolatency.c ++++ b/libbpf-tools/biolatency.c +@@ -255,9 +255,14 @@ int main(int argc, char **argv) + if (err) + return err; + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + ++ err = bump_memlock_rlimit(); ++ if (err) { ++ fprintf(stderr, "failed to increase rlimit: %d\n", err); ++ return 1; ++ } ++ + obj = biolatency_bpf__open(); + if (!obj) { + fprintf(stderr, "failed to open BPF object\n"); +@@ -308,22 +313,25 @@ int main(int argc, char **argv) + } + + if (env.queued) { +- obj->links.block_rq_insert = bpf_program__attach(obj->progs.block_rq_insert); +- if (!obj->links.block_rq_insert) { +- err = -errno; ++ obj->links.block_rq_insert = ++ bpf_program__attach(obj->progs.block_rq_insert); ++ err = libbpf_get_error(obj->links.block_rq_insert); ++ if (err) { + fprintf(stderr, "failed to attach: %s\n", strerror(-err)); + goto cleanup; + } + } +- obj->links.block_rq_issue = bpf_program__attach(obj->progs.block_rq_issue); +- if (!obj->links.block_rq_issue) { +- err = -errno; ++ obj->links.block_rq_issue = ++ bpf_program__attach(obj->progs.block_rq_issue); ++ err = libbpf_get_error(obj->links.block_rq_issue); ++ if (err) { + fprintf(stderr, "failed to attach: %s\n", strerror(-err)); + goto cleanup; + } +- obj->links.block_rq_complete = bpf_program__attach(obj->progs.block_rq_complete); +- if (!obj->links.block_rq_complete) { +- err = -errno; ++ obj->links.block_rq_complete = ++ bpf_program__attach(obj->progs.block_rq_complete); ++ err = libbpf_get_error(obj->links.block_rq_complete); ++ if (err) { + fprintf(stderr, "failed to attach: %s\n", strerror(-err)); + goto cleanup; + } +diff --git a/libbpf-tools/biopattern.c b/libbpf-tools/biopattern.c +index 92324702..2cc0d9a3 100644 +--- a/libbpf-tools/biopattern.c ++++ b/libbpf-tools/biopattern.c +@@ -172,9 +172,14 @@ int main(int argc, char **argv) + if (err) + return err; + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + ++ err = bump_memlock_rlimit(); ++ if (err) { ++ fprintf(stderr, "failed to increase rlimit: %d\n", err); ++ return 1; ++ } ++ + obj = biopattern_bpf__open(); + if (!obj) { + fprintf(stderr, "failed to open BPF object\n"); +diff --git a/libbpf-tools/biosnoop.c b/libbpf-tools/biosnoop.c +index f0f665a6..618af38e 100644 +--- a/libbpf-tools/biosnoop.c ++++ b/libbpf-tools/biosnoop.c +@@ -190,6 +190,7 @@ int main(int argc, char **argv) + .parser = parse_arg, + .doc = argp_program_doc, + }; ++ struct perf_buffer_opts pb_opts; + struct perf_buffer *pb = NULL; + struct ksyms *ksyms = NULL; + struct biosnoop_bpf *obj; +@@ -202,9 +203,14 @@ int main(int argc, char **argv) + if (err) + return err; + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + ++ err = bump_memlock_rlimit(); ++ if (err) { ++ fprintf(stderr, "failed to increase rlimit: %d\n", err); ++ return 1; ++ } ++ + obj = biosnoop_bpf__open(); + if (!obj) { + fprintf(stderr, "failed to open BPF object\n"); +@@ -251,55 +257,64 @@ int main(int argc, char **argv) + } + } + +- obj->links.blk_account_io_start = bpf_program__attach(obj->progs.blk_account_io_start); +- if (!obj->links.blk_account_io_start) { +- err = -errno; ++ obj->links.blk_account_io_start = ++ bpf_program__attach(obj->progs.blk_account_io_start); ++ err = libbpf_get_error(obj->links.blk_account_io_start); ++ if (err) { + fprintf(stderr, "failed to attach blk_account_io_start: %s\n", +- strerror(-err)); ++ strerror(err)); + goto cleanup; + } + ksyms = ksyms__load(); + if (!ksyms) { +- err = -ENOMEM; + fprintf(stderr, "failed to load kallsyms\n"); + goto cleanup; + } + if (ksyms__get_symbol(ksyms, "blk_account_io_merge_bio")) { + obj->links.blk_account_io_merge_bio = + bpf_program__attach(obj->progs.blk_account_io_merge_bio); +- if (!obj->links.blk_account_io_merge_bio) { +- err = -errno; +- fprintf(stderr, "failed to attach blk_account_io_merge_bio: %s\n", +- strerror(-err)); ++ err = libbpf_get_error(obj->links.blk_account_io_merge_bio); ++ if (err) { ++ fprintf(stderr, "failed to attach " ++ "blk_account_io_merge_bio: %s\n", ++ strerror(err)); + goto cleanup; + } + } + if (env.queued) { + obj->links.block_rq_insert = + bpf_program__attach(obj->progs.block_rq_insert); +- if (!obj->links.block_rq_insert) { +- err = -errno; +- fprintf(stderr, "failed to attach block_rq_insert: %s\n", strerror(-err)); ++ err = libbpf_get_error(obj->links.block_rq_insert); ++ if (err) { ++ fprintf(stderr, "failed to attach block_rq_insert: %s\n", ++ strerror(err)); + goto cleanup; + } + } +- obj->links.block_rq_issue = bpf_program__attach(obj->progs.block_rq_issue); +- if (!obj->links.block_rq_issue) { +- err = -errno; +- fprintf(stderr, "failed to attach block_rq_issue: %s\n", strerror(-err)); ++ obj->links.block_rq_issue = ++ bpf_program__attach(obj->progs.block_rq_issue); ++ err = libbpf_get_error(obj->links.block_rq_issue); ++ if (err) { ++ fprintf(stderr, "failed to attach block_rq_issue: %s\n", ++ strerror(err)); + goto cleanup; + } +- obj->links.block_rq_complete = bpf_program__attach(obj->progs.block_rq_complete); +- if (!obj->links.block_rq_complete) { +- err = -errno; +- fprintf(stderr, "failed to attach block_rq_complete: %s\n", strerror(-err)); ++ obj->links.block_rq_complete = ++ bpf_program__attach(obj->progs.block_rq_complete); ++ err = libbpf_get_error(obj->links.block_rq_complete); ++ if (err) { ++ fprintf(stderr, "failed to attach block_rq_complete: %s\n", ++ strerror(err)); + goto cleanup; + } + ++ pb_opts.sample_cb = handle_event; ++ pb_opts.lost_cb = handle_lost_events; + pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES, +- handle_event, handle_lost_events, NULL, NULL); +- if (!pb) { +- err = -errno; ++ &pb_opts); ++ err = libbpf_get_error(pb); ++ if (err) { ++ pb = NULL; + fprintf(stderr, "failed to open perf buffer: %d\n", err); + goto cleanup; + } +@@ -323,8 +338,8 @@ int main(int argc, char **argv) + /* main: poll */ + while (!exiting) { + err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS); +- if (err < 0 && err != -EINTR) { +- fprintf(stderr, "error polling perf buffer: %s\n", strerror(-err)); ++ if (err < 0 && errno != EINTR) { ++ fprintf(stderr, "error polling perf buffer: %s\n", strerror(errno)); + goto cleanup; + } + if (env.duration && get_ktime_ns() > time_end) +diff --git a/libbpf-tools/biostacks.c b/libbpf-tools/biostacks.c +index 260bc235..c98fd532 100644 +--- a/libbpf-tools/biostacks.c ++++ b/libbpf-tools/biostacks.c +@@ -145,9 +145,14 @@ int main(int argc, char **argv) + if (err) + return err; + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + ++ err = bump_memlock_rlimit(); ++ if (err) { ++ fprintf(stderr, "failed to increase rlimit: %d\n", err); ++ return 1; ++ } ++ + obj = biostacks_bpf__open(); + if (!obj) { + fprintf(stderr, "failed to open BPF object\n"); +@@ -179,10 +184,12 @@ int main(int argc, char **argv) + goto cleanup; + } + +- obj->links.blk_account_io_start = bpf_program__attach(obj->progs.blk_account_io_start); +- if (!obj->links.blk_account_io_start) { +- err = -errno; +- fprintf(stderr, "failed to attach blk_account_io_start: %s\n", strerror(-err)); ++ obj->links.blk_account_io_start = ++ bpf_program__attach(obj->progs.blk_account_io_start); ++ err = libbpf_get_error(obj->links.blk_account_io_start); ++ if (err) { ++ fprintf(stderr, "failed to attach blk_account_io_start: %s\n", ++ strerror(err)); + goto cleanup; + } + ksyms = ksyms__load(); +@@ -192,19 +199,23 @@ int main(int argc, char **argv) + } + if (ksyms__get_symbol(ksyms, "blk_account_io_merge_bio")) { + obj->links.blk_account_io_merge_bio = +- bpf_program__attach(obj->progs.blk_account_io_merge_bio); +- if (!obj->links.blk_account_io_merge_bio) { +- err = -errno; +- fprintf(stderr, "failed to attach blk_account_io_merge_bio: %s\n", +- strerror(-err)); ++ bpf_program__attach(obj-> ++ progs.blk_account_io_merge_bio); ++ err = libbpf_get_error(obj-> ++ links.blk_account_io_merge_bio); ++ if (err) { ++ fprintf(stderr, "failed to attach " ++ "blk_account_io_merge_bio: %s\n", ++ strerror(err)); + goto cleanup; + } + } +- obj->links.blk_account_io_done = bpf_program__attach(obj->progs.blk_account_io_done); +- if (!obj->links.blk_account_io_done) { +- err = -errno; ++ obj->links.blk_account_io_done = ++ bpf_program__attach(obj->progs.blk_account_io_done); ++ err = libbpf_get_error(obj->links.blk_account_io_done); ++ if (err) { + fprintf(stderr, "failed to attach blk_account_io_done: %s\n", +- strerror(-err)); ++ strerror(err)); + goto cleanup; + } + +diff --git a/libbpf-tools/bitesize.c b/libbpf-tools/bitesize.c +index 4c371508..41b1a7db 100644 +--- a/libbpf-tools/bitesize.c ++++ b/libbpf-tools/bitesize.c +@@ -167,9 +167,14 @@ int main(int argc, char **argv) + if (err) + return err; + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + ++ err = bump_memlock_rlimit(); ++ if (err) { ++ fprintf(stderr, "failed to increase rlimit: %d\n", err); ++ return 1; ++ } ++ + obj = bitesize_bpf__open(); + if (!obj) { + fprintf(stderr, "failed to open BPF object\n"); +diff --git a/libbpf-tools/cachestat.c b/libbpf-tools/cachestat.c +index 05785251..abc81878 100644 +--- a/libbpf-tools/cachestat.c ++++ b/libbpf-tools/cachestat.c +@@ -139,9 +139,14 @@ int main(int argc, char **argv) + if (err) + return err; + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + ++ err = bump_memlock_rlimit(); ++ if (err) { ++ fprintf(stderr, "failed to increase rlimit: %d\n", err); ++ return 1; ++ } ++ + obj = cachestat_bpf__open_and_load(); + if (!obj) { + fprintf(stderr, "failed to open and/or load BPF object\n"); +diff --git a/libbpf-tools/cpudist.c b/libbpf-tools/cpudist.c +index f76d8a67..035100ea 100644 +--- a/libbpf-tools/cpudist.c ++++ b/libbpf-tools/cpudist.c +@@ -197,9 +197,14 @@ int main(int argc, char **argv) + if (err) + return err; + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + ++ err = bump_memlock_rlimit(); ++ if (err) { ++ fprintf(stderr, "failed to increase rlimit: %d\n", err); ++ return 1; ++ } ++ + obj = cpudist_bpf__open(); + if (!obj) { + fprintf(stderr, "failed to open BPF object\n"); +diff --git a/libbpf-tools/cpufreq.bpf.c b/libbpf-tools/cpufreq.bpf.c +index 88a1bd25..697620ba 100644 +--- a/libbpf-tools/cpufreq.bpf.c ++++ b/libbpf-tools/cpufreq.bpf.c +@@ -17,21 +17,11 @@ struct { + __type(value, struct hist); + } hists SEC(".maps"); + +-#define clamp_umax(VAR, UMAX) \ +- asm volatile ( \ +- "if %0 <= %[max] goto +1\n" \ +- "%0 = %[max]\n" \ +- : "+r"(VAR) \ +- : [max]"i"(UMAX) \ +- ) +- + SEC("tp_btf/cpu_frequency") + int BPF_PROG(cpu_frequency, unsigned int state, unsigned int cpu_id) + { + if (cpu_id >= MAX_CPU_NR) + return 0; +- +- clamp_umax(cpu_id, MAX_CPU_NR - 1); + freqs_mhz[cpu_id] = state / 1000; + return 0; + } +@@ -46,7 +36,6 @@ int do_sample(struct bpf_perf_event_data *ctx) + + if (cpu >= MAX_CPU_NR) + return 0; +- clamp_umax(cpu, MAX_CPU_NR - 1); + freq_mhz = freqs_mhz[cpu]; + if (!freq_mhz) + return 0; +diff --git a/libbpf-tools/cpufreq.c b/libbpf-tools/cpufreq.c +index c5839560..65876587 100644 +--- a/libbpf-tools/cpufreq.c ++++ b/libbpf-tools/cpufreq.c +@@ -102,8 +102,10 @@ static int open_and_attach_perf_event(int freq, struct bpf_program *prog, + return -1; + } + links[i] = bpf_program__attach_perf_event(prog, fd); +- if (!links[i]) { +- fprintf(stderr, "failed to attach perf event on cpu: %d\n", i); ++ if (libbpf_get_error(links[i])) { ++ fprintf(stderr, "failed to attach perf event on cpu: " ++ "%d\n", i); ++ links[i] = NULL; + close(fd); + return -1; + } +@@ -173,7 +175,7 @@ static void print_linear_hists(struct bpf_map *hists, + + printf("\n"); + print_linear_hist(bss->syswide.slots, MAX_SLOTS, 0, HIST_STEP_SIZE, +- "syswide"); ++ "syswide"); + } + + int main(int argc, char **argv) +@@ -191,9 +193,14 @@ int main(int argc, char **argv) + if (err) + return err; + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + ++ err = bump_memlock_rlimit(); ++ if (err) { ++ fprintf(stderr, "failed to increase rlimit: %d\n", err); ++ return 1; ++ } ++ + nr_cpus = libbpf_num_possible_cpus(); + if (nr_cpus < 0) { + fprintf(stderr, "failed to get # of possible cpus: '%s'!\n", +diff --git a/libbpf-tools/drsnoop.c b/libbpf-tools/drsnoop.c +index 705db9a4..89285871 100644 +--- a/libbpf-tools/drsnoop.c ++++ b/libbpf-tools/drsnoop.c +@@ -146,6 +146,7 @@ int main(int argc, char **argv) + .parser = parse_arg, + .doc = argp_program_doc, + }; ++ struct perf_buffer_opts pb_opts; + struct perf_buffer *pb = NULL; + struct ksyms *ksyms = NULL; + const struct ksym *ksym; +@@ -157,9 +158,14 @@ int main(int argc, char **argv) + if (err) + return err; + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + ++ err = bump_memlock_rlimit(); ++ if (err) { ++ fprintf(stderr, "failed to increase rlimit: %d\n", err); ++ return 1; ++ } ++ + obj = drsnoop_bpf__open(); + if (!obj) { + fprintf(stderr, "failed to open BPF object\n"); +@@ -207,10 +213,13 @@ int main(int argc, char **argv) + printf(" %8s", "FREE(KB)"); + printf("\n"); + ++ pb_opts.sample_cb = handle_event; ++ pb_opts.lost_cb = handle_lost_events; + pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES, +- handle_event, handle_lost_events, NULL, NULL); +- if (!pb) { +- err = -errno; ++ &pb_opts); ++ err = libbpf_get_error(pb); ++ if (err) { ++ pb = NULL; + fprintf(stderr, "failed to open perf buffer: %d\n", err); + goto cleanup; + } +@@ -228,8 +237,8 @@ int main(int argc, char **argv) + /* main: poll */ + while (!exiting) { + err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS); +- if (err < 0 && err != -EINTR) { +- fprintf(stderr, "error polling perf buffer: %s\n", strerror(-err)); ++ if (err < 0 && errno != EINTR) { ++ fprintf(stderr, "error polling perf buffer: %s\n", strerror(errno)); + goto cleanup; + } + if (env.duration && get_ktime_ns() > time_end) +diff --git a/libbpf-tools/execsnoop.c b/libbpf-tools/execsnoop.c +index 38294816..1fd573da 100644 +--- a/libbpf-tools/execsnoop.c ++++ b/libbpf-tools/execsnoop.c +@@ -263,6 +263,7 @@ int main(int argc, char **argv) + .parser = parse_arg, + .doc = argp_program_doc, + }; ++ struct perf_buffer_opts pb_opts; + struct perf_buffer *pb = NULL; + struct execsnoop_bpf *obj; + int err; +@@ -271,9 +272,14 @@ int main(int argc, char **argv) + if (err) + return err; + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + ++ err = bump_memlock_rlimit(); ++ if (err) { ++ fprintf(stderr, "failed to increase rlimit: %d\n", err); ++ return 1; ++ } ++ + obj = execsnoop_bpf__open(); + if (!obj) { + fprintf(stderr, "failed to open BPF object\n"); +@@ -311,10 +317,12 @@ int main(int argc, char **argv) + printf("%-16s %-6s %-6s %3s %s\n", "PCOMM", "PID", "PPID", "RET", "ARGS"); + + /* setup event callbacks */ +- pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES, +- handle_event, handle_lost_events, NULL, NULL); +- if (!pb) { +- err = -errno; ++ pb_opts.sample_cb = handle_event; ++ pb_opts.lost_cb = handle_lost_events; ++ pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES, &pb_opts); ++ err = libbpf_get_error(pb); ++ if (err) { ++ pb = NULL; + fprintf(stderr, "failed to open perf buffer: %d\n", err); + goto cleanup; + } +@@ -328,8 +336,8 @@ int main(int argc, char **argv) + /* main: poll */ + while (!exiting) { + err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS); +- if (err < 0 && err != -EINTR) { +- fprintf(stderr, "error polling perf buffer: %s\n", strerror(-err)); ++ if (err < 0 && errno != EINTR) { ++ fprintf(stderr, "error polling perf buffer: %s\n", strerror(errno)); + goto cleanup; + } + /* reset err to return 0 if exiting */ +diff --git a/libbpf-tools/exitsnoop.c b/libbpf-tools/exitsnoop.c +index bca9d4d3..410e00da 100644 +--- a/libbpf-tools/exitsnoop.c ++++ b/libbpf-tools/exitsnoop.c +@@ -152,6 +152,7 @@ int main(int argc, char **argv) + .parser = parse_arg, + .doc = argp_program_doc, + }; ++ struct perf_buffer_opts pb_opts; + struct perf_buffer *pb = NULL; + struct exitsnoop_bpf *obj; + int err; +@@ -160,7 +161,11 @@ int main(int argc, char **argv) + if (err) + return err; + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); ++ err = bump_memlock_rlimit(); ++ if (err) { ++ warn("failed to increase rlimit: %d\n", err); ++ return 1; ++ } + libbpf_set_print(libbpf_print_fn); + + obj = exitsnoop_bpf__open(); +@@ -185,10 +190,11 @@ int main(int argc, char **argv) + goto cleanup; + } + +- pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES, +- handle_event, handle_lost_events, NULL, NULL); +- if (!pb) { +- err = -errno; ++ pb_opts.sample_cb = handle_event; ++ pb_opts.lost_cb = handle_lost_events; ++ pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES, &pb_opts); ++ err = libbpf_get_error(pb); ++ if (err) { + warn("failed to open perf buffer: %d\n", err); + goto cleanup; + } +@@ -206,8 +212,8 @@ int main(int argc, char **argv) + + while (!exiting) { + err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS); +- if (err < 0 && err != -EINTR) { +- warn("error polling perf buffer: %s\n", strerror(-err)); ++ if (err < 0 && errno != EINTR) { ++ warn("error polling perf buffer: %s\n", strerror(errno)); + goto cleanup; + } + /* reset err to return 0 if exiting */ +diff --git a/libbpf-tools/filelife.c b/libbpf-tools/filelife.c +index ba6b9440..1f94039e 100644 +--- a/libbpf-tools/filelife.c ++++ b/libbpf-tools/filelife.c +@@ -110,6 +110,7 @@ int main(int argc, char **argv) + .parser = parse_arg, + .doc = argp_program_doc, + }; ++ struct perf_buffer_opts pb_opts; + struct perf_buffer *pb = NULL; + struct filelife_bpf *obj; + int err; +@@ -118,9 +119,14 @@ int main(int argc, char **argv) + if (err) + return err; + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + ++ err = bump_memlock_rlimit(); ++ if (err) { ++ fprintf(stderr, "failed to increase rlimit: %d\n", err); ++ return 1; ++ } ++ + obj = filelife_bpf__open(); + if (!obj) { + fprintf(stderr, "failed to open BPF object\n"); +@@ -145,10 +151,13 @@ int main(int argc, char **argv) + printf("Tracing the lifespan of short-lived files ... Hit Ctrl-C to end.\n"); + printf("%-8s %-6s %-16s %-7s %s\n", "TIME", "PID", "COMM", "AGE(s)", "FILE"); + ++ pb_opts.sample_cb = handle_event; ++ pb_opts.lost_cb = handle_lost_events; + pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES, +- handle_event, handle_lost_events, NULL, NULL); +- if (!pb) { +- err = -errno; ++ &pb_opts); ++ err = libbpf_get_error(pb); ++ if (err) { ++ pb = NULL; + fprintf(stderr, "failed to open perf buffer: %d\n", err); + goto cleanup; + } +@@ -161,8 +170,8 @@ int main(int argc, char **argv) + + while (!exiting) { + err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS); +- if (err < 0 && err != -EINTR) { +- fprintf(stderr, "error polling perf buffer: %s\n", strerror(-err)); ++ if (err < 0 && errno != EINTR) { ++ fprintf(stderr, "error polling perf buffer: %s\n", strerror(errno)); + goto cleanup; + } + /* reset err to return 0 if exiting */ +diff --git a/libbpf-tools/filetop.c b/libbpf-tools/filetop.c +index 70240d85..f1f7ba96 100644 +--- a/libbpf-tools/filetop.c ++++ b/libbpf-tools/filetop.c +@@ -268,7 +268,11 @@ int main(int argc, char **argv) + if (err) + return err; + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); ++ err = bump_memlock_rlimit(); ++ if (err) { ++ warn("failed to increase rlimit: %d\n", err); ++ return 1; ++ } + libbpf_set_print(libbpf_print_fn); + + obj = filetop_bpf__open(); +diff --git a/libbpf-tools/fsdist.c b/libbpf-tools/fsdist.c +index f411d162..782a0e6a 100644 +--- a/libbpf-tools/fsdist.c ++++ b/libbpf-tools/fsdist.c +@@ -299,44 +299,53 @@ static int attach_kprobes(struct fsdist_bpf *obj) + + /* READ */ + obj->links.file_read_entry = bpf_program__attach_kprobe(obj->progs.file_read_entry, false, cfg->op_funcs[READ]); +- if (!obj->links.file_read_entry) ++ err = libbpf_get_error(obj->links.file_read_entry); ++ if (err) + goto errout; + obj->links.file_read_exit = bpf_program__attach_kprobe(obj->progs.file_read_exit, true, cfg->op_funcs[READ]); +- if (!obj->links.file_read_exit) ++ err = libbpf_get_error(obj->links.file_read_exit); ++ if (err) + goto errout; + /* WRITE */ + obj->links.file_write_entry = bpf_program__attach_kprobe(obj->progs.file_write_entry, false, cfg->op_funcs[WRITE]); +- if (!obj->links.file_write_entry) ++ err = libbpf_get_error(obj->links.file_write_entry); ++ if (err) + goto errout; + obj->links.file_write_exit = bpf_program__attach_kprobe(obj->progs.file_write_exit, true, cfg->op_funcs[WRITE]); +- if (!obj->links.file_write_exit) ++ err = libbpf_get_error(obj->links.file_write_exit); ++ if (err) + goto errout; + /* OPEN */ + obj->links.file_open_entry = bpf_program__attach_kprobe(obj->progs.file_open_entry, false, cfg->op_funcs[OPEN]); +- if (!obj->links.file_open_entry) ++ err = libbpf_get_error(obj->links.file_open_entry); ++ if (err) + goto errout; + obj->links.file_open_exit = bpf_program__attach_kprobe(obj->progs.file_open_exit, true, cfg->op_funcs[OPEN]); +- if (!obj->links.file_open_exit) ++ err = libbpf_get_error(obj->links.file_open_exit); ++ if (err) + goto errout; + /* FSYNC */ + obj->links.file_sync_entry = bpf_program__attach_kprobe(obj->progs.file_sync_entry, false, cfg->op_funcs[FSYNC]); +- if (!obj->links.file_sync_entry) ++ err = libbpf_get_error(obj->links.file_sync_entry); ++ if (err) + goto errout; + obj->links.file_sync_exit = bpf_program__attach_kprobe(obj->progs.file_sync_exit, true, cfg->op_funcs[FSYNC]); +- if (!obj->links.file_sync_exit) ++ err = libbpf_get_error(obj->links.file_sync_exit); ++ if (err) + goto errout; + /* GETATTR */ + if (!cfg->op_funcs[GETATTR]) + return 0; + obj->links.getattr_entry = bpf_program__attach_kprobe(obj->progs.getattr_entry, false, cfg->op_funcs[GETATTR]); +- if (!obj->links.getattr_entry) ++ err = libbpf_get_error(obj->links.getattr_entry); ++ if (err) + goto errout; + obj->links.getattr_exit = bpf_program__attach_kprobe(obj->progs.getattr_exit, true, cfg->op_funcs[GETATTR]); +- if (!obj->links.getattr_exit) ++ err = libbpf_get_error(obj->links.getattr_exit); ++ if (err) + goto errout; + return 0; + errout: +- err = -errno; + warn("failed to attach kprobe: %ld\n", err); + return err; + } +@@ -364,9 +373,14 @@ int main(int argc, char **argv) + return 1; + } + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + ++ err = bump_memlock_rlimit(); ++ if (err) { ++ warn("failed to increase rlimit: %d\n", err); ++ return 1; ++ } ++ + skel = fsdist_bpf__open(); + if (!skel) { + warn("failed to open BPF object\n"); +diff --git a/libbpf-tools/fsslower.c b/libbpf-tools/fsslower.c +index e96c9efa..2975b493 100644 +--- a/libbpf-tools/fsslower.c ++++ b/libbpf-tools/fsslower.c +@@ -256,36 +256,43 @@ static int attach_kprobes(struct fsslower_bpf *obj) + + /* READ */ + obj->links.file_read_entry = bpf_program__attach_kprobe(obj->progs.file_read_entry, false, cfg->op_funcs[READ]); +- if (!obj->links.file_read_entry) ++ err = libbpf_get_error(obj->links.file_read_entry); ++ if (err) + goto errout; + obj->links.file_read_exit = bpf_program__attach_kprobe(obj->progs.file_read_exit, true, cfg->op_funcs[READ]); +- if (!obj->links.file_read_exit) ++ err = libbpf_get_error(obj->links.file_read_exit); ++ if (err) + goto errout; + /* WRITE */ + obj->links.file_write_entry = bpf_program__attach_kprobe(obj->progs.file_write_entry, false, cfg->op_funcs[WRITE]); +- if (!obj->links.file_write_entry) ++ err = libbpf_get_error(obj->links.file_write_entry); ++ if (err) + goto errout; + obj->links.file_write_exit = bpf_program__attach_kprobe(obj->progs.file_write_exit, true, cfg->op_funcs[WRITE]); +- if (!obj->links.file_write_exit) ++ err = libbpf_get_error(obj->links.file_write_exit); ++ if (err) + goto errout; + /* OPEN */ + obj->links.file_open_entry = bpf_program__attach_kprobe(obj->progs.file_open_entry, false, cfg->op_funcs[OPEN]); +- if (!obj->links.file_open_entry) ++ err = libbpf_get_error(obj->links.file_open_entry); ++ if (err) + goto errout; + obj->links.file_open_exit = bpf_program__attach_kprobe(obj->progs.file_open_exit, true, cfg->op_funcs[OPEN]); +- if (!obj->links.file_open_exit) ++ err = libbpf_get_error(obj->links.file_open_exit); ++ if (err) + goto errout; + /* FSYNC */ + obj->links.file_sync_entry = bpf_program__attach_kprobe(obj->progs.file_sync_entry, false, cfg->op_funcs[FSYNC]); +- if (!obj->links.file_sync_entry) ++ err = libbpf_get_error(obj->links.file_sync_entry); ++ if (err) + goto errout; + obj->links.file_sync_exit = bpf_program__attach_kprobe(obj->progs.file_sync_exit, true, cfg->op_funcs[FSYNC]); +- if (!obj->links.file_sync_exit) ++ err = libbpf_get_error(obj->links.file_sync_exit); ++ if (err) + goto errout; + return 0; + + errout: +- err = -errno; + warn("failed to attach kprobe: %ld\n", err); + return err; + } +@@ -354,6 +361,7 @@ int main(int argc, char **argv) + .parser = parse_arg, + .doc = argp_program_doc, + }; ++ struct perf_buffer_opts pb_opts; + struct perf_buffer *pb = NULL; + struct fsslower_bpf *skel; + __u64 time_end = 0; +@@ -369,9 +377,14 @@ int main(int argc, char **argv) + return 1; + } + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + ++ err = bump_memlock_rlimit(); ++ if (err) { ++ warn("failed to increase rlimit: %d\n", err); ++ return 1; ++ } ++ + skel = fsslower_bpf__open(); + if (!skel) { + warn("failed to open BPF object\n"); +@@ -415,10 +428,13 @@ int main(int argc, char **argv) + goto cleanup; + } + ++ pb_opts.sample_cb = handle_event; ++ pb_opts.lost_cb = handle_lost_events; + pb = perf_buffer__new(bpf_map__fd(skel->maps.events), PERF_BUFFER_PAGES, +- handle_event, handle_lost_events, NULL, NULL); +- if (!pb) { +- err = -errno; ++ &pb_opts); ++ err = libbpf_get_error(pb); ++ if (err) { ++ pb = NULL; + warn("failed to open perf buffer: %d\n", err); + goto cleanup; + } +@@ -437,8 +453,8 @@ int main(int argc, char **argv) + /* main: poll */ + while (!exiting) { + err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS); +- if (err < 0 && err != -EINTR) { +- fprintf(stderr, "error polling perf buffer: %s\n", strerror(-err)); ++ if (err < 0 && errno != EINTR) { ++ fprintf(stderr, "error polling perf buffer: %s\n", strerror(errno)); + goto cleanup; + } + if (duration && get_ktime_ns() > time_end) +diff --git a/libbpf-tools/funclatency.c b/libbpf-tools/funclatency.c +index 3ea0fec3..b079292e 100644 +--- a/libbpf-tools/funclatency.c ++++ b/libbpf-tools/funclatency.c +@@ -185,18 +185,20 @@ static int attach_kprobes(struct funclatency_bpf *obj) + { + long err; + +- obj->links.dummy_kprobe = bpf_program__attach_kprobe(obj->progs.dummy_kprobe, false, +- env.funcname); +- if (!obj->links.dummy_kprobe) { +- err = -errno; ++ obj->links.dummy_kprobe = ++ bpf_program__attach_kprobe(obj->progs.dummy_kprobe, false, ++ env.funcname); ++ err = libbpf_get_error(obj->links.dummy_kprobe); ++ if (err) { + warn("failed to attach kprobe: %ld\n", err); + return -1; + } + +- obj->links.dummy_kretprobe = bpf_program__attach_kprobe(obj->progs.dummy_kretprobe, true, +- env.funcname); +- if (!obj->links.dummy_kretprobe) { +- err = -errno; ++ obj->links.dummy_kretprobe = ++ bpf_program__attach_kprobe(obj->progs.dummy_kretprobe, true, ++ env.funcname); ++ err = libbpf_get_error(obj->links.dummy_kretprobe); ++ if (err) { + warn("failed to attach kretprobe: %ld\n", err); + return -1; + } +@@ -237,8 +239,8 @@ static int attach_uprobes(struct funclatency_bpf *obj) + obj->links.dummy_kprobe = + bpf_program__attach_uprobe(obj->progs.dummy_kprobe, false, + env.pid ?: -1, bin_path, func_off); +- if (!obj->links.dummy_kprobe) { +- err = -errno; ++ err = libbpf_get_error(obj->links.dummy_kprobe); ++ if (err) { + warn("Failed to attach uprobe: %ld\n", err); + goto out_binary; + } +@@ -246,8 +248,8 @@ static int attach_uprobes(struct funclatency_bpf *obj) + obj->links.dummy_kretprobe = + bpf_program__attach_uprobe(obj->progs.dummy_kretprobe, true, + env.pid ?: -1, bin_path, func_off); +- if (!obj->links.dummy_kretprobe) { +- err = -errno; ++ err = libbpf_get_error(obj->links.dummy_kretprobe); ++ if (err) { + warn("Failed to attach uretprobe: %ld\n", err); + goto out_binary; + } +@@ -296,7 +298,11 @@ int main(int argc, char **argv) + + sigaction(SIGINT, &sigact, 0); + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); ++ err = bump_memlock_rlimit(); ++ if (err) { ++ warn("failed to increase rlimit: %d\n", err); ++ return 1; ++ } + libbpf_set_print(libbpf_print_fn); + + obj = funclatency_bpf__open(); +diff --git a/libbpf-tools/gethostlatency.c b/libbpf-tools/gethostlatency.c +index 9b3ebc28..12076e6a 100644 +--- a/libbpf-tools/gethostlatency.c ++++ b/libbpf-tools/gethostlatency.c +@@ -164,14 +164,16 @@ static int attach_uprobes(struct gethostlatency_bpf *obj, struct bpf_link *links + } + links[0] = bpf_program__attach_uprobe(obj->progs.handle_entry, false, + target_pid ?: -1, libc_path, func_off); +- if (!links[0]) { +- warn("failed to attach getaddrinfo: %d\n", -errno); ++ err = libbpf_get_error(links[0]); ++ if (err) { ++ warn("failed to attach getaddrinfo: %d\n", err); + return -1; + } + links[1] = bpf_program__attach_uprobe(obj->progs.handle_return, true, + target_pid ?: -1, libc_path, func_off); +- if (!links[1]) { +- warn("failed to attach getaddrinfo: %d\n", -errno); ++ err = libbpf_get_error(links[1]); ++ if (err) { ++ warn("failed to attach getaddrinfo: %d\n", err); + return -1; + } + +@@ -182,14 +184,16 @@ static int attach_uprobes(struct gethostlatency_bpf *obj, struct bpf_link *links + } + links[2] = bpf_program__attach_uprobe(obj->progs.handle_entry, false, + target_pid ?: -1, libc_path, func_off); +- if (!links[2]) { +- warn("failed to attach gethostbyname: %d\n", -errno); ++ err = libbpf_get_error(links[2]); ++ if (err) { ++ warn("failed to attach gethostbyname: %d\n", err); + return -1; + } + links[3] = bpf_program__attach_uprobe(obj->progs.handle_return, true, + target_pid ?: -1, libc_path, func_off); +- if (!links[3]) { +- warn("failed to attach gethostbyname: %d\n", -errno); ++ err = libbpf_get_error(links[3]); ++ if (err) { ++ warn("failed to attach gethostbyname: %d\n", err); + return -1; + } + +@@ -200,14 +204,16 @@ static int attach_uprobes(struct gethostlatency_bpf *obj, struct bpf_link *links + } + links[4] = bpf_program__attach_uprobe(obj->progs.handle_entry, false, + target_pid ?: -1, libc_path, func_off); +- if (!links[4]) { +- warn("failed to attach gethostbyname2: %d\n", -errno); ++ err = libbpf_get_error(links[4]); ++ if (err) { ++ warn("failed to attach gethostbyname2: %d\n", err); + return -1; + } + links[5] = bpf_program__attach_uprobe(obj->progs.handle_return, true, + target_pid ?: -1, libc_path, func_off); +- if (!links[5]) { +- warn("failed to attach gethostbyname2: %d\n", -errno); ++ err = libbpf_get_error(links[5]); ++ if (err) { ++ warn("failed to attach gethostbyname2: %d\n", err); + return -1; + } + +@@ -221,6 +227,7 @@ int main(int argc, char **argv) + .parser = parse_arg, + .doc = argp_program_doc, + }; ++ struct perf_buffer_opts pb_opts; + struct perf_buffer *pb = NULL; + struct bpf_link *links[6] = {}; + struct gethostlatency_bpf *obj; +@@ -230,7 +237,11 @@ int main(int argc, char **argv) + if (err) + return err; + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); ++ err = bump_memlock_rlimit(); ++ if (err) { ++ warn("failed to increase rlimit: %d\n", err); ++ return 1; ++ } + libbpf_set_print(libbpf_print_fn); + + obj = gethostlatency_bpf__open(); +@@ -251,10 +262,12 @@ int main(int argc, char **argv) + if (err) + goto cleanup; + ++ pb_opts.sample_cb = handle_event; ++ pb_opts.lost_cb = handle_lost_events; + pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES, +- handle_event, handle_lost_events, NULL, NULL); +- if (!pb) { +- err = -errno; ++ &pb_opts); ++ err = libbpf_get_error(pb); ++ if (err) { + warn("failed to open perf buffer: %d\n", err); + goto cleanup; + } +@@ -270,8 +283,8 @@ int main(int argc, char **argv) + + while (!exiting) { + err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS); +- if (err < 0 && err != -EINTR) { +- warn("error polling perf buffer: %s\n", strerror(-err)); ++ if (err < 0 && errno != EINTR) { ++ warn("error polling perf buffer: %s\n", strerror(errno)); + goto cleanup; + } + /* reset err to return 0 if exiting */ +diff --git a/libbpf-tools/hardirqs.c b/libbpf-tools/hardirqs.c +index a2475ef1..759b3949 100644 +--- a/libbpf-tools/hardirqs.c ++++ b/libbpf-tools/hardirqs.c +@@ -185,9 +185,14 @@ int main(int argc, char **argv) + return 1; + } + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + ++ err = bump_memlock_rlimit(); ++ if (err) { ++ fprintf(stderr, "failed to increase rlimit: %d\n", err); ++ return 1; ++ } ++ + obj = hardirqs_bpf__open(); + if (!obj) { + fprintf(stderr, "failed to open BPF object\n"); +@@ -207,27 +212,30 @@ int main(int argc, char **argv) + } + + if (env.count) { +- obj->links.handle__irq_handler = bpf_program__attach(obj->progs.handle__irq_handler); +- if (!obj->links.handle__irq_handler) { +- err = -errno; ++ obj->links.handle__irq_handler = ++ bpf_program__attach(obj->progs.handle__irq_handler); ++ err = libbpf_get_error(obj->links.handle__irq_handler); ++ if (err) { + fprintf(stderr, + "failed to attach irq/irq_handler_entry: %s\n", +- strerror(-err)); ++ strerror(err)); + } + } else { +- obj->links.irq_handler_entry = bpf_program__attach(obj->progs.irq_handler_entry); +- if (!obj->links.irq_handler_entry) { +- err = -errno; ++ obj->links.irq_handler_entry = ++ bpf_program__attach(obj->progs.irq_handler_entry); ++ err = libbpf_get_error(obj->links.irq_handler_entry); ++ if (err) { + fprintf(stderr, + "failed to attach irq_handler_entry: %s\n", +- strerror(-err)); ++ strerror(err)); + } +- obj->links.irq_handler_exit_exit = bpf_program__attach(obj->progs.irq_handler_exit_exit); +- if (!obj->links.irq_handler_exit_exit) { +- err = -errno; ++ obj->links.irq_handler_exit_exit = ++ bpf_program__attach(obj->progs.irq_handler_exit_exit); ++ err = libbpf_get_error(obj->links.irq_handler_exit_exit); ++ if (err) { + fprintf(stderr, + "failed to attach irq_handler_exit: %s\n", +- strerror(-err)); ++ strerror(err)); + } + } + +diff --git a/libbpf-tools/ksnoop.c b/libbpf-tools/ksnoop.c +index a6ea6107..a5f59a0f 100644 +--- a/libbpf-tools/ksnoop.c ++++ b/libbpf-tools/ksnoop.c +@@ -38,6 +38,7 @@ static bool verbose = false; + static __u32 filter_pid; + static bool stack_mode; + ++#define libbpf_errstr(val) strerror(-libbpf_get_error(val)) + + static void __p(enum log_level level, char *level_str, char *fmt, ...) + { +@@ -222,12 +223,14 @@ static int get_func_btf(struct btf *btf, struct func *func) + return -ENOENT; + } + type = btf__type_by_id(btf, func->id); +- if (!type || BTF_INFO_KIND(type->info) != BTF_KIND_FUNC) { ++ if (libbpf_get_error(type) || ++ BTF_INFO_KIND(type->info) != BTF_KIND_FUNC) { + p_err("Error looking up function type via id '%d'", func->id); + return -EINVAL; + } + type = btf__type_by_id(btf, type->type); +- if (!type || BTF_INFO_KIND(type->info) != BTF_KIND_FUNC_PROTO) { ++ if (libbpf_get_error(type) || ++ BTF_INFO_KIND(type->info) != BTF_KIND_FUNC_PROTO) { + p_err("Error looking up function proto type via id '%d'", + func->id); + return -EINVAL; +@@ -341,16 +344,15 @@ static int trace_to_value(struct btf *btf, struct func *func, char *argname, + static struct btf *get_btf(const char *name) + { + struct btf *mod_btf; +- int err; + + p_debug("getting BTF for %s", + name && strlen(name) > 0 ? name : "vmlinux"); + + if (!vmlinux_btf) { + vmlinux_btf = libbpf_find_kernel_btf(); +- if (!vmlinux_btf) { +- err = -errno; +- p_err("No BTF, cannot determine type info: %s", strerror(-err)); ++ if (libbpf_get_error(vmlinux_btf)) { ++ p_err("No BTF, cannot determine type info: %s", ++ libbpf_errstr(vmlinux_btf)); + return NULL; + } + } +@@ -358,9 +360,9 @@ static struct btf *get_btf(const char *name) + return vmlinux_btf; + + mod_btf = btf__load_module_btf(name, vmlinux_btf); +- if (!mod_btf) { +- err = -errno; +- p_err("No BTF for module '%s': %s", name, strerror(-err)); ++ if (libbpf_get_error(mod_btf)) { ++ p_err("No BTF for module '%s': %s", ++ name, libbpf_errstr(mod_btf)); + return NULL; + } + return mod_btf; +@@ -394,11 +396,11 @@ static char *type_id_to_str(struct btf *btf, __s32 type_id, char *str) + default: + do { + type = btf__type_by_id(btf, type_id); +- if (!type) { ++ ++ if (libbpf_get_error(type)) { + name = "?"; + break; + } +- + switch (BTF_INFO_KIND(type->info)) { + case BTF_KIND_CONST: + case BTF_KIND_VOLATILE: +@@ -553,17 +555,16 @@ static int parse_trace(char *str, struct trace *trace) + return ret; + } + trace->btf = get_btf(func->mod); +- if (!trace->btf) { +- ret = -errno; ++ if (libbpf_get_error(trace->btf)) { + p_err("could not get BTF for '%s': %s", + strlen(func->mod) ? func->mod : "vmlinux", +- strerror(-ret)); ++ libbpf_errstr(trace->btf)); + return -ENOENT; + } + trace->dump = btf_dump__new(trace->btf, NULL, &opts, trace_printf); +- if (!trace->dump) { +- ret = -errno; +- p_err("could not create BTF dump : %n", strerror(-ret)); ++ if (libbpf_get_error(trace->dump)) { ++ p_err("could not create BTF dump : %n", ++ libbpf_errstr(trace->btf)); + return -EINVAL; + } + +@@ -823,20 +824,20 @@ static int attach_traces(struct ksnoop_bpf *skel, struct trace *traces, + bpf_program__attach_kprobe(skel->progs.kprobe_entry, + false, + traces[i].func.name); +- if (!traces[i].links[0]) { +- ret = -errno; ++ ret = libbpf_get_error(traces[i].links[0]); ++ if (ret) { + p_err("Could not attach kprobe to '%s': %s", + traces[i].func.name, strerror(-ret)); + return ret; +- } ++ } + p_debug("Attached kprobe for '%s'", traces[i].func.name); + + traces[i].links[1] = + bpf_program__attach_kprobe(skel->progs.kprobe_return, + true, + traces[i].func.name); +- if (!traces[i].links[1]) { +- ret = -errno; ++ ret = libbpf_get_error(traces[i].links[1]); ++ if (ret) { + p_err("Could not attach kretprobe to '%s': %s", + traces[i].func.name, strerror(-ret)); + return ret; +@@ -848,6 +849,7 @@ static int attach_traces(struct ksnoop_bpf *skel, struct trace *traces, + + static int cmd_trace(int argc, char **argv) + { ++ struct perf_buffer_opts pb_opts = {}; + struct bpf_map *perf_map, *func_map; + struct perf_buffer *pb = NULL; + struct ksnoop_bpf *skel; +@@ -860,8 +862,7 @@ static int cmd_trace(int argc, char **argv) + + skel = ksnoop_bpf__open_and_load(); + if (!skel) { +- ret = -errno; +- p_err("Could not load ksnoop BPF: %s", strerror(-ret)); ++ p_err("Could not load ksnoop BPF: %s", libbpf_errstr(skel)); + return 1; + } + +@@ -886,11 +887,12 @@ static int cmd_trace(int argc, char **argv) + goto cleanup; + } + +- pb = perf_buffer__new(bpf_map__fd(perf_map), pages, +- trace_handler, lost_handler, NULL, NULL); +- if (!pb) { +- ret = -errno; +- p_err("Could not create perf buffer: %s", strerror(-ret)); ++ pb_opts.sample_cb = trace_handler; ++ pb_opts.lost_cb = lost_handler; ++ pb = perf_buffer__new(bpf_map__fd(perf_map), pages, &pb_opts); ++ if (libbpf_get_error(pb)) { ++ p_err("Could not create perf buffer: %s", ++ libbpf_errstr(pb)); + goto cleanup; + } + +@@ -904,8 +906,8 @@ static int cmd_trace(int argc, char **argv) + + while (!exiting) { + ret = perf_buffer__poll(pb, 1); +- if (ret < 0 && ret != -EINTR) { +- fprintf(stderr, "error polling perf buffer: %s\n", strerror(-ret)); ++ if (ret < 0 && errno != EINTR) { ++ fprintf(stderr, "error polling perf buffer: %s\n", strerror(errno)); + goto cleanup; + } + /* reset ret to return 0 if exiting */ +@@ -1005,7 +1007,6 @@ int main(int argc, char *argv[]) + if (argc < 0) + usage(); + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + + return cmd_select(argc, argv); +diff --git a/libbpf-tools/llcstat.bpf.c b/libbpf-tools/llcstat.bpf.c +index a36fc2df..fbd5b6c4 100644 +--- a/libbpf-tools/llcstat.bpf.c ++++ b/libbpf-tools/llcstat.bpf.c +@@ -36,13 +36,13 @@ int trace_event(__u64 sample_period, bool miss) + return 0; + } + +-SEC("perf_event") ++SEC("perf_event/1") + int on_cache_miss(struct bpf_perf_event_data *ctx) + { + return trace_event(ctx->sample_period, true); + } + +-SEC("perf_event") ++SEC("perf_event/2") + int on_cache_ref(struct bpf_perf_event_data *ctx) + { + return trace_event(ctx->sample_period, false); +diff --git a/libbpf-tools/llcstat.c b/libbpf-tools/llcstat.c +index be437bc2..150dd38b 100644 +--- a/libbpf-tools/llcstat.c ++++ b/libbpf-tools/llcstat.c +@@ -106,8 +106,10 @@ static int open_and_attach_perf_event(__u64 config, int period, + return -1; + } + links[i] = bpf_program__attach_perf_event(prog, fd); +- if (!links[i]) { +- fprintf(stderr, "failed to attach perf event on cpu: %d\n", i); ++ if (libbpf_get_error(links[i])) { ++ fprintf(stderr, "failed to attach perf event on cpu: " ++ "%d\n", i); ++ links[i] = NULL; + close(fd); + return -1; + } +@@ -182,9 +184,14 @@ int main(int argc, char **argv) + if (err) + return err; + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + ++ err = bump_memlock_rlimit(); ++ if (err) { ++ fprintf(stderr, "failed to increase rlimit: %d\n", err); ++ return 1; ++ } ++ + nr_cpus = libbpf_num_possible_cpus(); + if (nr_cpus < 0) { + fprintf(stderr, "failed to get # of possible cpus: '%s'!\n", +diff --git a/libbpf-tools/mountsnoop.c b/libbpf-tools/mountsnoop.c +index ac2acc45..0955f59e 100644 +--- a/libbpf-tools/mountsnoop.c ++++ b/libbpf-tools/mountsnoop.c +@@ -249,6 +249,7 @@ int main(int argc, char **argv) + .parser = parse_arg, + .doc = argp_program_doc, + }; ++ struct perf_buffer_opts pb_opts; + struct perf_buffer *pb = NULL; + struct mountsnoop_bpf *obj; + int err; +@@ -257,7 +258,11 @@ int main(int argc, char **argv) + if (err) + return err; + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); ++ err = bump_memlock_rlimit(); ++ if (err) { ++ warn("failed to increase rlimit: %d\n", err); ++ return 1; ++ } + libbpf_set_print(libbpf_print_fn); + + obj = mountsnoop_bpf__open(); +@@ -280,10 +285,11 @@ int main(int argc, char **argv) + goto cleanup; + } + +- pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES, +- handle_event, handle_lost_events, NULL, NULL); +- if (!pb) { +- err = -errno; ++ pb_opts.sample_cb = handle_event; ++ pb_opts.lost_cb = handle_lost_events; ++ pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES, &pb_opts); ++ err = libbpf_get_error(pb); ++ if (err) { + warn("failed to open perf buffer: %d\n", err); + goto cleanup; + } +@@ -302,8 +308,8 @@ int main(int argc, char **argv) + + while (!exiting) { + err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS); +- if (err < 0 && err != -EINTR) { +- fprintf(stderr, "error polling perf buffer: %s\n", strerror(-err)); ++ if (err < 0 && errno != EINTR) { ++ fprintf(stderr, "error polling perf buffer: %s\n", strerror(errno)); + goto cleanup; + } + /* reset err to return 0 if exiting */ +diff --git a/libbpf-tools/numamove.c b/libbpf-tools/numamove.c +index 0747f841..66a53ed6 100644 +--- a/libbpf-tools/numamove.c ++++ b/libbpf-tools/numamove.c +@@ -80,9 +80,14 @@ int main(int argc, char **argv) + if (err) + return err; + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + ++ err = bump_memlock_rlimit(); ++ if (err) { ++ fprintf(stderr, "failed to increase rlimit: %d\n", err); ++ return 1; ++ } ++ + obj = numamove_bpf__open_and_load(); + if (!obj) { + fprintf(stderr, "failed to open and/or load BPF object\n"); +@@ -102,15 +107,18 @@ int main(int argc, char **argv) + + signal(SIGINT, sig_handler); + +- printf("%-10s %18s %18s\n", "TIME", "NUMA_migrations", "NUMA_migrations_ms"); ++ printf("%-10s %18s %18s\n", "TIME", "NUMA_migrations", ++ "NUMA_migrations_ms"); + while (!exiting) { + sleep(1); + time(&t); + tm = localtime(&t); + strftime(ts, sizeof(ts), "%H:%M:%S", tm); + printf("%-10s %18lld %18lld\n", ts, +- __atomic_exchange_n(&obj->bss->num, 0, __ATOMIC_RELAXED), +- __atomic_exchange_n(&obj->bss->latency, 0, __ATOMIC_RELAXED)); ++ __atomic_exchange_n(&obj->bss->num, 0, ++ __ATOMIC_RELAXED), ++ __atomic_exchange_n(&obj->bss->latency, 0, ++ __ATOMIC_RELAXED)); + } + + cleanup: +diff --git a/libbpf-tools/offcputime.c b/libbpf-tools/offcputime.c +index 37a8ec2c..0582b158 100644 +--- a/libbpf-tools/offcputime.c ++++ b/libbpf-tools/offcputime.c +@@ -279,9 +279,14 @@ int main(int argc, char **argv) + return 1; + } + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + ++ err = bump_memlock_rlimit(); ++ if (err) { ++ fprintf(stderr, "failed to increase rlimit: %d\n", err); ++ return 1; ++ } ++ + obj = offcputime_bpf__open(); + if (!obj) { + fprintf(stderr, "failed to open BPF object\n"); +diff --git a/libbpf-tools/opensnoop.c b/libbpf-tools/opensnoop.c +index 557a63cd..5cdac0e5 100644 +--- a/libbpf-tools/opensnoop.c ++++ b/libbpf-tools/opensnoop.c +@@ -219,6 +219,7 @@ int main(int argc, char **argv) + .parser = parse_arg, + .doc = argp_program_doc, + }; ++ struct perf_buffer_opts pb_opts; + struct perf_buffer *pb = NULL; + struct opensnoop_bpf *obj; + __u64 time_end = 0; +@@ -228,9 +229,14 @@ int main(int argc, char **argv) + if (err) + return err; + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + ++ err = bump_memlock_rlimit(); ++ if (err) { ++ fprintf(stderr, "failed to increase rlimit: %d\n", err); ++ return 1; ++ } ++ + obj = opensnoop_bpf__open(); + if (!obj) { + fprintf(stderr, "failed to open BPF object\n"); +@@ -276,10 +282,13 @@ int main(int argc, char **argv) + printf("%s\n", "PATH"); + + /* setup event callbacks */ ++ pb_opts.sample_cb = handle_event; ++ pb_opts.lost_cb = handle_lost_events; + pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES, +- handle_event, handle_lost_events, NULL, NULL); +- if (!pb) { +- err = -errno; ++ &pb_opts); ++ err = libbpf_get_error(pb); ++ if (err) { ++ pb = NULL; + fprintf(stderr, "failed to open perf buffer: %d\n", err); + goto cleanup; + } +@@ -297,8 +306,8 @@ int main(int argc, char **argv) + /* main: poll */ + while (!exiting) { + err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS); +- if (err < 0 && err != -EINTR) { +- fprintf(stderr, "error polling perf buffer: %s\n", strerror(-err)); ++ if (err < 0 && errno != EINTR) { ++ fprintf(stderr, "error polling perf buffer: %s\n", strerror(errno)); + goto cleanup; + } + if (env.duration && get_ktime_ns() > time_end) +diff --git a/libbpf-tools/readahead.c b/libbpf-tools/readahead.c +index 17079389..77986011 100644 +--- a/libbpf-tools/readahead.c ++++ b/libbpf-tools/readahead.c +@@ -109,9 +109,14 @@ int main(int argc, char **argv) + if (err) + return err; + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + ++ err = bump_memlock_rlimit(); ++ if (err) { ++ fprintf(stderr, "failed to increase rlimit: %d\n", err); ++ return 1; ++ } ++ + obj = readahead_bpf__open(); + if (!obj) { + fprintf(stderr, "failed to open BPF object\n"); +diff --git a/libbpf-tools/runqlat.c b/libbpf-tools/runqlat.c +index 5a60b874..249bf794 100644 +--- a/libbpf-tools/runqlat.c ++++ b/libbpf-tools/runqlat.c +@@ -193,9 +193,14 @@ int main(int argc, char **argv) + return 1; + } + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + ++ err = bump_memlock_rlimit(); ++ if (err) { ++ fprintf(stderr, "failed to increase rlimit: %d\n", err); ++ return 1; ++ } ++ + obj = runqlat_bpf__open(); + if (!obj) { + fprintf(stderr, "failed to open BPF object\n"); +diff --git a/libbpf-tools/runqlen.c b/libbpf-tools/runqlen.c +index 9cbbc739..2f6c5789 100644 +--- a/libbpf-tools/runqlen.c ++++ b/libbpf-tools/runqlen.c +@@ -145,8 +145,10 @@ static int open_and_attach_perf_event(int freq, struct bpf_program *prog, + return -1; + } + links[i] = bpf_program__attach_perf_event(prog, fd); +- if (!links[i]) { +- fprintf(stderr, "failed to attach perf event on cpu: %d\n", i); ++ if (libbpf_get_error(links[i])) { ++ fprintf(stderr, "failed to attach perf event on cpu: " ++ "%d\n", i); ++ links[i] = NULL; + close(fd); + return -1; + } +@@ -229,9 +231,14 @@ int main(int argc, char **argv) + if (err) + return err; + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + ++ err = bump_memlock_rlimit(); ++ if (err) { ++ fprintf(stderr, "failed to increase rlimit: %d\n", err); ++ return 1; ++ } ++ + nr_cpus = libbpf_num_possible_cpus(); + if (nr_cpus < 0) { + printf("failed to get # of possible cpus: '%s'!\n", +diff --git a/libbpf-tools/runqslower.c b/libbpf-tools/runqslower.c +index b038173e..b21894ca 100644 +--- a/libbpf-tools/runqslower.c ++++ b/libbpf-tools/runqslower.c +@@ -145,6 +145,7 @@ int main(int argc, char **argv) + .parser = parse_arg, + .doc = argp_program_doc, + }; ++ struct perf_buffer_opts pb_opts; + struct perf_buffer *pb = NULL; + struct runqslower_bpf *obj; + int err; +@@ -153,9 +154,14 @@ int main(int argc, char **argv) + if (err) + return err; + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + ++ err = bump_memlock_rlimit(); ++ if (err) { ++ fprintf(stderr, "failed to increase rlimit: %d\n", err); ++ return 1; ++ } ++ + obj = runqslower_bpf__open(); + if (!obj) { + fprintf(stderr, "failed to open BPF object\n"); +@@ -185,10 +191,12 @@ int main(int argc, char **argv) + else + printf("%-8s %-16s %-6s %14s\n", "TIME", "COMM", "TID", "LAT(us)"); + +- pb = perf_buffer__new(bpf_map__fd(obj->maps.events), 64, +- handle_event, handle_lost_events, NULL, NULL); +- if (!pb) { +- err = -errno; ++ pb_opts.sample_cb = handle_event; ++ pb_opts.lost_cb = handle_lost_events; ++ pb = perf_buffer__new(bpf_map__fd(obj->maps.events), 64, &pb_opts); ++ err = libbpf_get_error(pb); ++ if (err) { ++ pb = NULL; + fprintf(stderr, "failed to open perf buffer: %d\n", err); + goto cleanup; + } +@@ -201,8 +209,8 @@ int main(int argc, char **argv) + + while (!exiting) { + err = perf_buffer__poll(pb, 100); +- if (err < 0 && err != -EINTR) { +- fprintf(stderr, "error polling perf buffer: %s\n", strerror(-err)); ++ if (err < 0 && errno != EINTR) { ++ fprintf(stderr, "error polling perf buffer: %s\n", strerror(errno)); + goto cleanup; + } + /* reset err to return 0 if exiting */ +diff --git a/libbpf-tools/softirqs.c b/libbpf-tools/softirqs.c +index 34cfdb77..f1678d4c 100644 +--- a/libbpf-tools/softirqs.c ++++ b/libbpf-tools/softirqs.c +@@ -195,9 +195,14 @@ int main(int argc, char **argv) + if (err) + return err; + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + ++ err = bump_memlock_rlimit(); ++ if (err) { ++ fprintf(stderr, "failed to increase rlimit: %d\n", err); ++ return 1; ++ } ++ + obj = softirqs_bpf__open(); + if (!obj) { + fprintf(stderr, "failed to open BPF object\n"); +diff --git a/libbpf-tools/solisten.c b/libbpf-tools/solisten.c +index adaa668d..e5812f0c 100644 +--- a/libbpf-tools/solisten.c ++++ b/libbpf-tools/solisten.c +@@ -137,6 +137,7 @@ int main(int argc, char **argv) + .parser = parse_arg, + .doc = argp_program_doc, + }; ++ struct perf_buffer_opts pb_opts; + struct perf_buffer *pb = NULL; + struct solisten_bpf *obj; + int err; +@@ -145,7 +146,11 @@ int main(int argc, char **argv) + if (err) + return err; + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); ++ err = bump_memlock_rlimit(); ++ if (err) { ++ warn("failed to increase rlimit: %d\n", err); ++ return 1; ++ } + libbpf_set_print(libbpf_print_fn); + + obj = solisten_bpf__open(); +@@ -175,10 +180,11 @@ int main(int argc, char **argv) + goto cleanup; + } + +- pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES, +- handle_event, handle_lost_events, NULL, NULL); +- if (!pb) { +- err = -errno; ++ pb_opts.sample_cb = handle_event; ++ pb_opts.lost_cb = handle_lost_events; ++ pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES, &pb_opts); ++ err = libbpf_get_error(pb); ++ if (err) { + warn("failed to open perf buffer: %d\n", err); + goto cleanup; + } +@@ -196,8 +202,8 @@ int main(int argc, char **argv) + + while (!exiting) { + err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS); +- if (err < 0 && err != -EINTR) { +- warn("error polling perf buffer: %s\n", strerror(-err)); ++ if (err < 0 && errno != EINTR) { ++ warn("error polling perf buffer: %s\n", strerror(errno)); + goto cleanup; + } + /* reset err to return 0 if exiting */ +diff --git a/libbpf-tools/statsnoop.c b/libbpf-tools/statsnoop.c +index 3f8f5c58..76779da6 100644 +--- a/libbpf-tools/statsnoop.c ++++ b/libbpf-tools/statsnoop.c +@@ -127,6 +127,7 @@ int main(int argc, char **argv) + .parser = parse_arg, + .doc = argp_program_doc, + }; ++ struct perf_buffer_opts pb_opts; + struct perf_buffer *pb = NULL; + struct statsnoop_bpf *obj; + int err; +@@ -135,9 +136,14 @@ int main(int argc, char **argv) + if (err) + return err; + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); ++ err = bump_memlock_rlimit(); ++ if (err) { ++ warn("failed to increase rlimit: %d\n", err); ++ return 1; ++ } + libbpf_set_print(libbpf_print_fn); + ++ + obj = statsnoop_bpf__open(); + if (!obj) { + warn("failed to open BPF object\n"); +@@ -159,10 +165,12 @@ int main(int argc, char **argv) + goto cleanup; + } + ++ pb_opts.sample_cb = handle_event; ++ pb_opts.lost_cb = handle_lost_events; + pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES, +- handle_event, handle_lost_events, NULL, NULL); +- if (!pb) { +- err = -errno; ++ &pb_opts); ++ err = libbpf_get_error(pb); ++ if (err) { + warn("failed to open perf buffer: %d\n", err); + goto cleanup; + } +@@ -180,8 +188,8 @@ int main(int argc, char **argv) + + while (!exiting) { + err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS); +- if (err < 0 && err != -EINTR) { +- warn("error polling perf buffer: %s\n", strerror(-err)); ++ if (err < 0 && errno != EINTR) { ++ warn("error polling perf buffer: %s\n", strerror(errno)); + goto cleanup; + } + /* reset err to return 0 if exiting */ +diff --git a/libbpf-tools/syscount.c b/libbpf-tools/syscount.c +index 2d687573..35c0e095 100644 +--- a/libbpf-tools/syscount.c ++++ b/libbpf-tools/syscount.c +@@ -390,9 +390,14 @@ int main(int argc, char **argv) + goto free_names; + } + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + ++ err = bump_memlock_rlimit(); ++ if (err) { ++ warn("failed to increase rlimit: %s\n", strerror(errno)); ++ goto free_names; ++ } ++ + obj = syscount_bpf__open(); + if (!obj) { + warn("failed to open BPF object\n"); +@@ -418,15 +423,16 @@ int main(int argc, char **argv) + } + + obj->links.sys_exit = bpf_program__attach(obj->progs.sys_exit); +- if (!obj->links.sys_exit) { +- err = -errno; +- warn("failed to attach sys_exit program: %s\n", strerror(-err)); ++ err = libbpf_get_error(obj->links.sys_exit); ++ if (err) { ++ warn("failed to attach sys_exit program: %s\n", ++ strerror(-err)); + goto cleanup_obj; + } + if (env.latency) { + obj->links.sys_enter = bpf_program__attach(obj->progs.sys_enter); +- if (!obj->links.sys_enter) { +- err = -errno; ++ err = libbpf_get_error(obj->links.sys_enter); ++ if (err) { + warn("failed to attach sys_enter programs: %s\n", + strerror(-err)); + goto cleanup_obj; +diff --git a/libbpf-tools/tcpconnect.c b/libbpf-tools/tcpconnect.c +index 101cf72b..82b2bebb 100644 +--- a/libbpf-tools/tcpconnect.c ++++ b/libbpf-tools/tcpconnect.c +@@ -324,13 +324,17 @@ static void handle_lost_events(void *ctx, int cpu, __u64 lost_cnt) + + static void print_events(int perf_map_fd) + { +- struct perf_buffer *pb; ++ struct perf_buffer_opts pb_opts = { ++ .sample_cb = handle_event, ++ .lost_cb = handle_lost_events, ++ }; ++ struct perf_buffer *pb = NULL; + int err; + +- pb = perf_buffer__new(perf_map_fd, 128, +- handle_event, handle_lost_events, NULL, NULL); +- if (!pb) { +- err = -errno; ++ pb = perf_buffer__new(perf_map_fd, 128, &pb_opts); ++ err = libbpf_get_error(pb); ++ if (err) { ++ pb = NULL; + warn("failed to open perf buffer: %d\n", err); + goto cleanup; + } +@@ -338,8 +342,8 @@ static void print_events(int perf_map_fd) + print_events_header(); + while (!exiting) { + err = perf_buffer__poll(pb, 100); +- if (err < 0 && err != -EINTR) { +- warn("error polling perf buffer: %s\n", strerror(-err)); ++ if (err < 0 && errno != EINTR) { ++ warn("error polling perf buffer: %s\n", strerror(errno)); + goto cleanup; + } + /* reset err to return 0 if exiting */ +@@ -365,9 +369,14 @@ int main(int argc, char **argv) + if (err) + return err; + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + ++ err = bump_memlock_rlimit(); ++ if (err) { ++ warn("failed to increase rlimit: %s\n", strerror(errno)); ++ return 1; ++ } ++ + obj = tcpconnect_bpf__open(); + if (!obj) { + warn("failed to open BPF object\n"); +diff --git a/libbpf-tools/tcpconnlat.c b/libbpf-tools/tcpconnlat.c +index 8eae76ae..3cab2115 100644 +--- a/libbpf-tools/tcpconnlat.c ++++ b/libbpf-tools/tcpconnlat.c +@@ -161,6 +161,7 @@ int main(int argc, char **argv) + .parser = parse_arg, + .doc = argp_program_doc, + }; ++ struct perf_buffer_opts pb_opts; + struct perf_buffer *pb = NULL; + struct tcpconnlat_bpf *obj; + int err; +@@ -169,9 +170,14 @@ int main(int argc, char **argv) + if (err) + return err; + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + ++ err = bump_memlock_rlimit(); ++ if (err) { ++ fprintf(stderr, "failed to increase rlimit: %d\n", err); ++ return 1; ++ } ++ + obj = tcpconnlat_bpf__open(); + if (!obj) { + fprintf(stderr, "failed to open BPF object\n"); +@@ -193,10 +199,15 @@ int main(int argc, char **argv) + goto cleanup; + } + ++ pb_opts.sample_cb = handle_event; ++ ++ pb_opts.lost_cb = handle_lost_events; + pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES, +- handle_event, handle_lost_events, NULL, NULL); +- if (!pb) { +- fprintf(stderr, "failed to open perf buffer: %d\n", errno); ++ &pb_opts); ++ err = libbpf_get_error(pb); ++ if (err) { ++ pb = NULL; ++ fprintf(stderr, "failed to open perf buffer: %d\n", err); + goto cleanup; + } + +@@ -211,6 +222,7 @@ int main(int argc, char **argv) + "PID", "COMM", "IP", "SADDR", "DADDR", "DPORT", "LAT(ms)"); + } + ++ + if (signal(SIGINT, sig_int) == SIG_ERR) { + fprintf(stderr, "can't set signal handler: %s\n", strerror(errno)); + err = 1; +@@ -220,8 +232,8 @@ int main(int argc, char **argv) + /* main: poll */ + while (!exiting) { + err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS); +- if (err < 0 && err != -EINTR) { +- fprintf(stderr, "error polling perf buffer: %s\n", strerror(-err)); ++ if (err < 0 && errno != EINTR) { ++ fprintf(stderr, "error polling perf buffer: %s\n", strerror(errno)); + goto cleanup; + } + /* reset err to return 0 if exiting */ +diff --git a/libbpf-tools/tcprtt.c b/libbpf-tools/tcprtt.c +index bed6efa7..bdff55bb 100644 +--- a/libbpf-tools/tcprtt.c ++++ b/libbpf-tools/tcprtt.c +@@ -225,9 +225,14 @@ int main(int argc, char **argv) + if (err) + return err; + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + ++ err = bump_memlock_rlimit(); ++ if (err) { ++ fprintf(stderr, "failed to increase rlimit: %d\n", err); ++ return 1; ++ } ++ + obj = tcprtt_bpf__open(); + if (!obj) { + fprintf(stderr, "failed to open BPF object\n"); +diff --git a/libbpf-tools/trace_helpers.c b/libbpf-tools/trace_helpers.c +index 322b3c4f..f37015e7 100644 +--- a/libbpf-tools/trace_helpers.c ++++ b/libbpf-tools/trace_helpers.c +@@ -967,6 +967,16 @@ unsigned long long get_ktime_ns(void) + return ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec; + } + ++int bump_memlock_rlimit(void) ++{ ++ struct rlimit rlim_new = { ++ .rlim_cur = RLIM_INFINITY, ++ .rlim_max = RLIM_INFINITY, ++ }; ++ ++ return setrlimit(RLIMIT_MEMLOCK, &rlim_new); ++} ++ + bool is_kernel_module(const char *name) + { + bool found = false; +@@ -997,22 +1007,20 @@ bool fentry_exists(const char *name, const char *mod) + const struct btf_type *type; + const struct btf_enum *e; + char sysfs_mod[80]; +- int id = -1, i, err; ++ int id = -1, i; + + base = btf__parse(sysfs_vmlinux, NULL); +- if (!base) { +- err = -errno; ++ if (libbpf_get_error(base)) { + fprintf(stderr, "failed to parse vmlinux BTF at '%s': %s\n", +- sysfs_vmlinux, strerror(-err)); ++ sysfs_vmlinux, strerror(-libbpf_get_error(base))); + goto err_out; + } + if (mod && module_btf_exists(mod)) { + snprintf(sysfs_mod, sizeof(sysfs_mod), "/sys/kernel/btf/%s", mod); + btf = btf__parse_split(sysfs_mod, base); +- if (!btf) { +- err = -errno; ++ if (libbpf_get_error(btf)) { + fprintf(stderr, "failed to load BTF from %s: %s\n", +- sysfs_mod, strerror(-err)); ++ sysfs_mod, strerror(-libbpf_get_error(btf))); + btf = base; + base = NULL; + } +diff --git a/libbpf-tools/trace_helpers.h b/libbpf-tools/trace_helpers.h +index 98fd640f..61cbe433 100644 +--- a/libbpf-tools/trace_helpers.h ++++ b/libbpf-tools/trace_helpers.h +@@ -58,6 +58,7 @@ void print_linear_hist(unsigned int *vals, int vals_size, unsigned int base, + unsigned int step, const char *val_type); + + unsigned long long get_ktime_ns(void); ++int bump_memlock_rlimit(void); + + bool is_kernel_module(const char *name); + +diff --git a/libbpf-tools/vfsstat.c b/libbpf-tools/vfsstat.c +index 5519c366..3a8a51d8 100644 +--- a/libbpf-tools/vfsstat.c ++++ b/libbpf-tools/vfsstat.c +@@ -150,9 +150,15 @@ int main(int argc, char **argv) + if (err) + return err; + +- libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + ++ err = bump_memlock_rlimit(); ++ if (err) { ++ fprintf(stderr, "failed to increase rlimit: %s\n", ++ strerror(errno)); ++ return 1; ++ } ++ + skel = vfsstat_bpf__open(); + if (!skel) { + fprintf(stderr, "failed to open BPF skelect\n"); +-- +2.35.1 + diff --git a/bcc-0.24.0-biolatency-biolatpcts-biosnoop-biotop-Build-fix-for-.patch b/bcc-0.24.0-biolatency-biolatpcts-biosnoop-biotop-Build-fix-for-.patch new file mode 100644 index 0000000..da15c6e --- /dev/null +++ b/bcc-0.24.0-biolatency-biolatpcts-biosnoop-biotop-Build-fix-for-.patch @@ -0,0 +1,125 @@ +From 879792d2d47c1308e884fb59d92fe535f7bb8d71 Mon Sep 17 00:00:00 2001 +From: Tejun Heo +Date: Thu, 10 Mar 2022 08:37:21 -1000 +Subject: [PATCH 1/2] biolatency, biolatpcts, biosnoop, biotop: Build fix for + v5.17+ + +During 5.17 dev cycle, the kernel dropped request->rq_disk. It can now be +accessed through request->q->disk. Fix the python ones in tools/. There are +more usages in other places which need to be fixed too. + +Signed-off-by: Tejun Heo +Signed-off-by: Jerome Marchand +--- + tools/biolatency.py | 8 ++++++-- + tools/biolatpcts.py | 11 ++++++++--- + tools/biosnoop.py | 6 +++++- + tools/biotop.py | 9 +++++++-- + 4 files changed, 26 insertions(+), 8 deletions(-) + +diff --git a/tools/biolatency.py b/tools/biolatency.py +index 427cee47..10c852ac 100755 +--- a/tools/biolatency.py ++++ b/tools/biolatency.py +@@ -128,12 +128,16 @@ storage_str = "" + store_str = "" + if args.disks: + storage_str += "BPF_HISTOGRAM(dist, disk_key_t);" +- store_str += """ ++ disks_str = """ + disk_key_t key = {.slot = bpf_log2l(delta)}; +- void *__tmp = (void *)req->rq_disk->disk_name; ++ void *__tmp = (void *)req->__RQ_DISK__->disk_name; + bpf_probe_read(&key.disk, sizeof(key.disk), __tmp); + dist.atomic_increment(key); + """ ++ if BPF.kernel_struct_has_field(b'request', b'rq_disk'): ++ store_str += disks_str.replace('__RQ_DISK__', 'rq_disk') ++ else: ++ store_str += disks_str.replace('__RQ_DISK__', 'q->disk') + elif args.flags: + storage_str += "BPF_HISTOGRAM(dist, flag_key_t);" + store_str += """ +diff --git a/tools/biolatpcts.py b/tools/biolatpcts.py +index 0f334419..ea8b1ce6 100755 +--- a/tools/biolatpcts.py ++++ b/tools/biolatpcts.py +@@ -72,9 +72,9 @@ void kprobe_blk_account_io_done(struct pt_regs *ctx, struct request *rq, u64 now + if (!rq->__START_TIME_FIELD__) + return; + +- if (!rq->rq_disk || +- rq->rq_disk->major != __MAJOR__ || +- rq->rq_disk->first_minor != __MINOR__) ++ if (!rq->__RQ_DISK__ || ++ rq->__RQ_DISK__->major != __MAJOR__ || ++ rq->__RQ_DISK__->first_minor != __MINOR__) + return; + + cmd_flags = rq->cmd_flags; +@@ -142,6 +142,11 @@ bpf_source = bpf_source.replace('__START_TIME_FIELD__', start_time_field) + bpf_source = bpf_source.replace('__MAJOR__', str(major)) + bpf_source = bpf_source.replace('__MINOR__', str(minor)) + ++if BPF.kernel_struct_has_field(b'request', b'rq_disk'): ++ bpf_source = bpf_source.replace('__RQ_DISK__', 'rq_disk') ++else: ++ bpf_source = bpf_source.replace('__RQ_DISK__', 'q->disk') ++ + bpf = BPF(text=bpf_source) + if BPF.get_kprobe_functions(b'__blk_account_io_done'): + bpf.attach_kprobe(event="__blk_account_io_done", fn_name="kprobe_blk_account_io_done") +diff --git a/tools/biosnoop.py b/tools/biosnoop.py +index ae38e384..a2b636aa 100755 +--- a/tools/biosnoop.py ++++ b/tools/biosnoop.py +@@ -125,7 +125,7 @@ int trace_req_completion(struct pt_regs *ctx, struct request *req) + data.pid = valp->pid; + data.sector = req->__sector; + bpf_probe_read_kernel(&data.name, sizeof(data.name), valp->name); +- struct gendisk *rq_disk = req->rq_disk; ++ struct gendisk *rq_disk = req->__RQ_DISK__; + bpf_probe_read_kernel(&data.disk_name, sizeof(data.disk_name), + rq_disk->disk_name); + } +@@ -156,6 +156,10 @@ int trace_req_completion(struct pt_regs *ctx, struct request *req) + bpf_text = bpf_text.replace('##QUEUE##', '1') + else: + bpf_text = bpf_text.replace('##QUEUE##', '0') ++if BPF.kernel_struct_has_field(b'request', b'rq_disk'): ++ bpf_text = bpf_text.replace('__RQ_DISK__', 'rq_disk') ++else: ++ bpf_text = bpf_text.replace('__RQ_DISK__', 'q->disk') + if debug or args.ebpf: + print(bpf_text) + if args.ebpf: +diff --git a/tools/biotop.py b/tools/biotop.py +index b3e3ea00..882835f6 100755 +--- a/tools/biotop.py ++++ b/tools/biotop.py +@@ -129,8 +129,8 @@ int trace_req_completion(struct pt_regs *ctx, struct request *req) + + // setup info_t key + struct info_t info = {}; +- info.major = req->rq_disk->major; +- info.minor = req->rq_disk->first_minor; ++ info.major = req->__RQ_DISK__->major; ++ info.minor = req->__RQ_DISK__->first_minor; + /* + * The following deals with a kernel version change (in mainline 4.7, although + * it may be backported to earlier kernels) with how block request write flags +@@ -174,6 +174,11 @@ int trace_req_completion(struct pt_regs *ctx, struct request *req) + print(bpf_text) + exit() + ++if BPF.kernel_struct_has_field(b'request', b'rq_disk'): ++ bpf_text = bpf_text.replace('__RQ_DISK__', 'rq_disk') ++else: ++ bpf_text = bpf_text.replace('__RQ_DISK__', 'q->disk') ++ + b = BPF(text=bpf_text) + if BPF.get_kprobe_functions(b'__blk_account_io_start'): + b.attach_kprobe(event="__blk_account_io_start", fn_name="trace_pid_start") +-- +2.35.1 + diff --git a/bcc-0.20.0-biolatpcts-Build-fixes-on-recent-kernels.patch b/bcc-0.24.0-biolatpcts-Build-fixes-on-recent-kernels.patch similarity index 94% rename from bcc-0.20.0-biolatpcts-Build-fixes-on-recent-kernels.patch rename to bcc-0.24.0-biolatpcts-Build-fixes-on-recent-kernels.patch index 7eb8da6..e190cd5 100644 --- a/bcc-0.20.0-biolatpcts-Build-fixes-on-recent-kernels.patch +++ b/bcc-0.24.0-biolatpcts-Build-fixes-on-recent-kernels.patch @@ -1,7 +1,7 @@ -From 11614bcacdecd4d1f7015bb0f0311bb709207991 Mon Sep 17 00:00:00 2001 +From 2ada4cee035c4d07391faa870a5df1874d657b65 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 27 Jan 2022 06:25:31 -1000 -Subject: [PATCH] biolatpcts: Build fixes on recent kernels +Subject: [PATCH 2/3] biolatpcts: Build fixes on recent kernels * `struct request` definition recently moved from blkdev.h to blk-mq.h breaking both tools/biolatpcts and examples/tracing/biolatpcts. Fix them diff --git a/bcc-0.24.0-libbpf-tools-Allow-to-use-different-cflags-for-bpf-t.patch b/bcc-0.24.0-libbpf-tools-Allow-to-use-different-cflags-for-bpf-t.patch new file mode 100644 index 0000000..5d40363 --- /dev/null +++ b/bcc-0.24.0-libbpf-tools-Allow-to-use-different-cflags-for-bpf-t.patch @@ -0,0 +1,49 @@ +From a6a5dba23d19f6a900b0359a7390df4a6b9a42f4 Mon Sep 17 00:00:00 2001 +From: Jerome Marchand +Date: Tue, 15 Mar 2022 17:59:24 +0100 +Subject: [PATCH 1/3] libbpf-tools: Allow to use different cflags for bpf + targets + +commit 531b698cdc20 ("libbpf-tools: Enable compilation warnings for +BPF programs") applies CFLAGS to all targets. However, some of the c +flags typically used by distribution are not available to the bpf +target. Add a new BPFCFLAGS macro to take care of that. + +Fixes the following compilation error on fedora: + + BPF bashreadline.bpf.o +clang-13: warning: optimization flag '-ffat-lto-objects' is not supported [-Wignored-optimization-argument] +clang-13: warning: argument unused during compilation: '-specs=/usr/lib/rpm/redhat/redhat-hardened-cc1' [-Wunused-command-line-argument] +clang-13: warning: argument unused during compilation: '-specs=/usr/lib/rpm/redhat/redhat-annobin-cc1' [-Wunused-command-line-argument] +clang-13: warning: argument unused during compilation: '-fstack-clash-protection' [-Wunused-command-line-argument] +error: option 'cf-protection=return' cannot be specified on this target +error: option 'cf-protection=branch' cannot be specified on this target +2 errors generated. +--- + libbpf-tools/Makefile | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/libbpf-tools/Makefile b/libbpf-tools/Makefile +index 6bf1ed08..39af95ec 100644 +--- a/libbpf-tools/Makefile ++++ b/libbpf-tools/Makefile +@@ -7,6 +7,7 @@ LIBBPF_SRC := $(abspath ../src/cc/libbpf/src) + LIBBPF_OBJ := $(abspath $(OUTPUT)/libbpf.a) + INCLUDES := -I$(OUTPUT) -I../src/cc/libbpf/include/uapi + CFLAGS := -g -O2 -Wall ++BPFCFLAGS := -g -O2 -Wall + INSTALL ?= install + prefix ?= /usr/local + ARCH := $(shell uname -m | sed 's/x86_64/x86/' | sed 's/aarch64/arm64/' | sed 's/ppc64le/powerpc/' | sed 's/mips.*/mips/') +@@ -106,7 +107,7 @@ $(OUTPUT)/%.skel.h: $(OUTPUT)/%.bpf.o | $(OUTPUT) + + $(OUTPUT)/%.bpf.o: %.bpf.c $(LIBBPF_OBJ) $(wildcard %.h) $(ARCH)/vmlinux.h | $(OUTPUT) + $(call msg,BPF,$@) +- $(Q)$(CLANG) $(CFLAGS) -target bpf -D__TARGET_ARCH_$(ARCH) \ ++ $(Q)$(CLANG) $(BPFCFLAGS) -target bpf -D__TARGET_ARCH_$(ARCH) \ + -I$(ARCH)/ $(INCLUDES) -c $(filter %.c,$^) -o $@ && \ + $(LLVM_STRIP) -g $@ + +-- +2.35.1 + diff --git a/bcc-0.24.0-libbpf-tools-Fix-dropped-request-rq_disk-for-kernel-.patch b/bcc-0.24.0-libbpf-tools-Fix-dropped-request-rq_disk-for-kernel-.patch new file mode 100644 index 0000000..8134d1f --- /dev/null +++ b/bcc-0.24.0-libbpf-tools-Fix-dropped-request-rq_disk-for-kernel-.patch @@ -0,0 +1,158 @@ +From 50480835adf15a389267393674504551b68987a2 Mon Sep 17 00:00:00 2001 +From: xingfeng2510 +Date: Wed, 30 Mar 2022 16:10:51 +0800 +Subject: [PATCH 2/2] libbpf-tools: Fix dropped request->rq_disk for kernel + 5.17+ + +Signed-off-by: Jerome Marchand +--- + libbpf-tools/biolatency.bpf.c | 20 ++++++++++++++++++-- + libbpf-tools/biosnoop.bpf.c | 12 +++++++++++- + libbpf-tools/biostacks.bpf.c | 12 +++++++++++- + libbpf-tools/bitesize.bpf.c | 12 +++++++++++- + 4 files changed, 51 insertions(+), 5 deletions(-) + +diff --git a/libbpf-tools/biolatency.bpf.c b/libbpf-tools/biolatency.bpf.c +index 648dda78..8f325046 100644 +--- a/libbpf-tools/biolatency.bpf.c ++++ b/libbpf-tools/biolatency.bpf.c +@@ -19,6 +19,10 @@ const volatile bool targ_ms = false; + const volatile bool filter_dev = false; + const volatile __u32 targ_dev = 0; + ++struct request_queue___x { ++ struct gendisk *disk; ++} __attribute__((preserve_access_index)); ++ + struct { + __uint(type, BPF_MAP_TYPE_CGROUP_ARRAY); + __type(key, u32); +@@ -53,9 +57,15 @@ int trace_rq_start(struct request *rq, int issue) + u64 ts = bpf_ktime_get_ns(); + + if (filter_dev) { +- struct gendisk *disk = BPF_CORE_READ(rq, rq_disk); ++ struct request_queue___x *q = (void *)BPF_CORE_READ(rq, q); ++ struct gendisk *disk; + u32 dev; + ++ if (bpf_core_field_exists(q->disk)) ++ disk = BPF_CORE_READ(q, disk); ++ else ++ disk = BPF_CORE_READ(rq, rq_disk); ++ + dev = disk ? MKDEV(BPF_CORE_READ(disk, major), + BPF_CORE_READ(disk, first_minor)) : 0; + if (targ_dev != dev) +@@ -119,7 +129,13 @@ int BPF_PROG(block_rq_complete, struct request *rq, int error, + goto cleanup; + + if (targ_per_disk) { +- struct gendisk *disk = BPF_CORE_READ(rq, rq_disk); ++ struct request_queue___x *q = (void *)BPF_CORE_READ(rq, q); ++ struct gendisk *disk; ++ ++ if (bpf_core_field_exists(q->disk)) ++ disk = BPF_CORE_READ(q, disk); ++ else ++ disk = BPF_CORE_READ(rq, rq_disk); + + hkey.dev = disk ? MKDEV(BPF_CORE_READ(disk, major), + BPF_CORE_READ(disk, first_minor)) : 0; +diff --git a/libbpf-tools/biosnoop.bpf.c b/libbpf-tools/biosnoop.bpf.c +index 54226e43..05903473 100644 +--- a/libbpf-tools/biosnoop.bpf.c ++++ b/libbpf-tools/biosnoop.bpf.c +@@ -15,6 +15,10 @@ const volatile __u32 targ_dev = 0; + + extern __u32 LINUX_KERNEL_VERSION __kconfig; + ++struct request_queue___x { ++ struct gendisk *disk; ++} __attribute__((preserve_access_index)); ++ + struct { + __uint(type, BPF_MAP_TYPE_CGROUP_ARRAY); + __type(key, u32); +@@ -92,7 +96,13 @@ int trace_rq_start(struct request *rq, bool insert) + + stagep = bpf_map_lookup_elem(&start, &rq); + if (!stagep) { +- struct gendisk *disk = BPF_CORE_READ(rq, rq_disk); ++ struct request_queue___x *q = (void *)BPF_CORE_READ(rq, q); ++ struct gendisk *disk; ++ ++ if (bpf_core_field_exists(q->disk)) ++ disk = BPF_CORE_READ(q, disk); ++ else ++ disk = BPF_CORE_READ(rq, rq_disk); + + stage.dev = disk ? MKDEV(BPF_CORE_READ(disk, major), + BPF_CORE_READ(disk, first_minor)) : 0; +diff --git a/libbpf-tools/biostacks.bpf.c b/libbpf-tools/biostacks.bpf.c +index 01993737..c13975fa 100644 +--- a/libbpf-tools/biostacks.bpf.c ++++ b/libbpf-tools/biostacks.bpf.c +@@ -14,6 +14,10 @@ const volatile bool targ_ms = false; + const volatile bool filter_dev = false; + const volatile __u32 targ_dev = -1; + ++struct request_queue___x { ++ struct gendisk *disk; ++} __attribute__((preserve_access_index)); ++ + struct internal_rqinfo { + u64 start_ts; + struct rqinfo rqinfo; +@@ -41,9 +45,15 @@ static __always_inline + int trace_start(void *ctx, struct request *rq, bool merge_bio) + { + struct internal_rqinfo *i_rqinfop = NULL, i_rqinfo = {}; +- struct gendisk *disk = BPF_CORE_READ(rq, rq_disk); ++ struct request_queue___x *q = (void *)BPF_CORE_READ(rq, q); ++ struct gendisk *disk; + u32 dev; + ++ if (bpf_core_field_exists(q->disk)) ++ disk = BPF_CORE_READ(q, disk); ++ else ++ disk = BPF_CORE_READ(rq, rq_disk); ++ + dev = disk ? MKDEV(BPF_CORE_READ(disk, major), + BPF_CORE_READ(disk, first_minor)) : 0; + if (filter_dev && targ_dev != dev) +diff --git a/libbpf-tools/bitesize.bpf.c b/libbpf-tools/bitesize.bpf.c +index 80672c9b..5066ca33 100644 +--- a/libbpf-tools/bitesize.bpf.c ++++ b/libbpf-tools/bitesize.bpf.c +@@ -13,6 +13,10 @@ const volatile __u32 targ_dev = 0; + + extern __u32 LINUX_KERNEL_VERSION __kconfig; + ++struct request_queue___x { ++ struct gendisk *disk; ++} __attribute__((preserve_access_index)); ++ + struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 10240); +@@ -41,9 +45,15 @@ static int trace_rq_issue(struct request *rq) + u64 slot; + + if (filter_dev) { +- struct gendisk *disk = BPF_CORE_READ(rq, rq_disk); ++ struct request_queue___x *q = (void *)BPF_CORE_READ(rq, q); ++ struct gendisk *disk; + u32 dev; + ++ if (bpf_core_field_exists(q->disk)) ++ disk = BPF_CORE_READ(q, disk); ++ else ++ disk = BPF_CORE_READ(rq, rq_disk); ++ + dev = disk ? MKDEV(BPF_CORE_READ(disk, major), + BPF_CORE_READ(disk, first_minor)) : 0; + if (targ_dev != dev) +-- +2.35.1 + diff --git a/bcc-0.20.0-tools-include-blk-mq.h-in-bio-tools.patch b/bcc-0.24.0-tools-include-blk-mq.h-in-bio-tools.patch similarity index 93% rename from bcc-0.20.0-tools-include-blk-mq.h-in-bio-tools.patch rename to bcc-0.24.0-tools-include-blk-mq.h-in-bio-tools.patch index 03e703f..1f7ce06 100644 --- a/bcc-0.20.0-tools-include-blk-mq.h-in-bio-tools.patch +++ b/bcc-0.24.0-tools-include-blk-mq.h-in-bio-tools.patch @@ -1,7 +1,7 @@ -From ee81072e75bcc796b1154c315e2eb0371928a922 Mon Sep 17 00:00:00 2001 +From 1eafb1f5aa0d3a9f60f89aad0ea55ae93899baff Mon Sep 17 00:00:00 2001 From: Jerome Marchand Date: Wed, 23 Feb 2022 16:04:30 +0100 -Subject: [PATCH] tools: include blk-mq.h in bio tools +Subject: [PATCH 3/3] tools: include blk-mq.h in bio tools Kernel commit 24b83deb29b ("block: move struct request to blk-mq.h") has moved struct request from blkdev.h to blk-mq.h. It results in diff --git a/bcc.spec b/bcc.spec index ada1d4e..449541e 100644 --- a/bcc.spec +++ b/bcc.spec @@ -22,31 +22,23 @@ %global with_llvm_shared 1 %endif -# Force out of source build -%undefine __cmake_in_source_build Name: bcc -Version: 0.20.0 -Release: 10%{?dist} +Version: 0.24.0 +Release: 1%{?dist} Summary: BPF Compiler Collection (BCC) License: ASL 2.0 URL: https://github.com/iovisor/bcc Source0: %{url}/archive/v%{version}/%{name}-%{version}.tar.gz -Patch0: %{name}-%{version}-libbpf-tool-don-t-ignore-LDFLAGS.patch -Patch1: %{name}-%{version}-libbpf-tools-readahead-don-t-mark-struct-hist-as-sta.patch -Patch2: %{name}-%{version}-Define-KERNEL_VERSION.patch -Patch3: %{name}-%{version}-Revert-libbpf-tools-remove-unecessary-custom-NULL-de.patch -Patch4: %{name}-%{version}-sync-with-latest-libbpf-repo-3529.patch -Patch5: %{name}-%{version}-threadsnoop-look-for-pthread_create-in-libc-too.patch -Patch6: %{name}-%{version}-Update-cpudist.py.patch -Patch7: %{name}-%{version}-tools-readahead-compatible-with-kernel-version-5.10-.patch -Patch8: %{name}-%{version}-Fix-mdflush-on-RHEL9.patch -Patch9: %{name}-%{version}-Handle-renaming-of-task_struct_-state-field-on-RHEL-.patch -Patch10: %{name}-%{version}-Fix-a-llvm-compilation-error.patch -Patch11: %{name}-%{version}-Remove-APInt-APSInt-toString-std-string-variants.patch -Patch12: %{name}-%{version}-tools-Fix-BCC-bio-tools-with-recent-kernel-change.patch -Patch13: %{name}-%{version}-biolatpcts-Build-fixes-on-recent-kernels.patch -Patch14: %{name}-%{version}-tools-include-blk-mq.h-in-bio-tools.patch +Patch0: %{name}-%{version}-libbpf-tools-Allow-to-use-different-cflags-for-bpf-t.patch +Patch1: %{name}-%{version}-biolatpcts-Build-fixes-on-recent-kernels.patch +Patch2: %{name}-%{version}-tools-include-blk-mq.h-in-bio-tools.patch +Patch3: %{name}-%{version}-C9S-libpbf-version-fixes.patch +Patch4: %{name}-%{version}-Revert-libbpf-1.0-changes.patch +Patch5: %{name}-%{version}-C9S-remove-ksnoop.patch +Patch6: %{name}-%{version}-C9S-Fix-mdflush.patch +Patch7: %{name}-%{version}-biolatency-biolatpcts-biosnoop-biotop-Build-fix-for-.patch +Patch8: %{name}-%{version}-libbpf-tools-Fix-dropped-request-rq_disk-for-kernel-.patch # Arches will be included as upstream support is added and dependencies are # satisfied in the respective arches @@ -58,6 +50,7 @@ BuildRequires: flex BuildRequires: libxml2-devel BuildRequires: python3-devel BuildRequires: elfutils-libelf-devel +BuildRequires: elfutils-debuginfod-client-devel BuildRequires: llvm-devel BuildRequires: clang-devel %if %{with llvm_static} @@ -67,9 +60,9 @@ BuildRequires: ncurses-devel %if %{with lua} BuildRequires: pkgconfig(luajit) %endif -BuildRequires: libbpf-devel >= 0.0.5-3, libbpf-static >= 0.0.5-3 +BuildRequires: libbpf-devel >= 0.5.0, libbpf-static >= 0.5.0 -Requires: libbpf >= 0.0.5-3 +Requires: libbpf >= 0.5.0 Requires: tar Recommends: kernel-devel @@ -88,6 +81,7 @@ performance analysis and network traffic control. %package devel Summary: Shared library for BPF Compiler Collection (BCC) Requires: %{name}%{?_isa} = %{version}-%{release} +Suggests: elfutils-debuginfod-client %description devel The %{name}-devel package contains libraries and header files for developing @@ -135,7 +129,6 @@ Command line tools for BPF Compiler Collection (BCC) %if %{with libbpf_tools} %package -n libbpf-tools Summary: Command line libbpf tools for BPF Compiler Collection (BCC) -BuildRequires: libbpf-devel >= 0.0.5-3, libbpf-static >= 0.0.5-3 BuildRequires: bpftool %description -n libbpf-tools @@ -147,11 +140,10 @@ Command line libbpf tools for BPF Compiler Collection (BCC) %build -%cmake . \ - -DCMAKE_BUILD_TYPE=RelWithDebInfo \ - -DREVISION_LAST=%{version} -DREVISION=%{version} -DPYTHON_CMD=python3 \ - -DCMAKE_USE_LIBBPF_PACKAGE:BOOL=TRUE \ - %{?with_llvm_shared:-DENABLE_LLVM_SHARED=1} +%cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DREVISION_LAST=%{version} -DREVISION=%{version} -DPYTHON_CMD=python3 \ + -DCMAKE_USE_LIBBPF_PACKAGE:BOOL=TRUE \ + %{?with_llvm_shared:-DENABLE_LLVM_SHARED=1} %cmake_build # It was discussed and agreed to package libbpf-tools with @@ -163,7 +155,17 @@ Command line libbpf tools for BPF Compiler Collection (BCC) pushd libbpf-tools; make BPFTOOL=bpftool LIBBPF_OBJ=%{_libdir}/libbpf.a CFLAGS="%{optflags}" LDFLAGS="%{build_ldflags}" make DESTDIR=./tmp-install prefix= install -(cd tmp-install/bin; for file in *; do mv $file bpf-$file; done;) +( + cd tmp-install/bin + for file in *; do + mv $file bpf-$file + done + # now fix the broken symlinks + for file in `find . -type l`; do + dest=$(readlink "$file") + ln -s -f bpf-$dest $file + done +) popd %endif @@ -197,7 +199,10 @@ rm -rf %{buildroot}%{_datadir}/%{name}/tools/old/ %if %{with libbpf_tools} mkdir -p %{buildroot}/%{_sbindir} -install libbpf-tools/tmp-install/bin/* %{buildroot}/%{_sbindir} +# We cannot use `install` because some of the tools are symlinks and `install` +# follows those. Since all the tools already have the correct permissions set, +# we just need to copy them to the right place while preserving those +cp -a libbpf-tools/tmp-install/bin/* %{buildroot}/%{_sbindir}/ %endif %ldconfig_scriptlets @@ -257,6 +262,10 @@ install libbpf-tools/tmp-install/bin/* %{buildroot}/%{_sbindir} %endif %changelog +* Thu Mar 24 2022 Jerome Marchand - 0.24.0-1 +- Rebase to v0.24.0 +- Fix cmake build + * Fri Feb 25 2022 Jerome Marchand - 0.20.0-10 - Remove deprecated python_provides macro (needed for gating) diff --git a/sources b/sources index 3c845c8..8bb57c2 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (bcc-0.20.0.tar.gz) = fa7c50a4fc64846ad798b6652101aa414cda53d08779cf48bd505191189cb23da2838f7511e700d59e086d35216f4e3bc9867b614738061630984dff3c4576dc +SHA512 (bcc-0.24.0.tar.gz) = 951672e3a8e5ad56eedf513477317ec3d3b4cf2d594bbfce20f3d19ddf7ce255e9dcfc69d9b05bb765a16e769c8e42d7c57071ddb86fb32437f527d3d25d19b6