]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
bpf: Add dump_stack() analogue to print to BPF stderr
authorKumar Kartikeya Dwivedi <memxor@gmail.com>
Thu, 3 Jul 2025 20:48:12 +0000 (13:48 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Fri, 4 Jul 2025 02:30:07 +0000 (19:30 -0700)
Introduce a kernel function which is the analogue of dump_stack()
printing some useful information and the stack trace. This is not
exposed to BPF programs yet, but can be made available in the future.

When we have a program counter for a BPF program in the stack trace,
also additionally output the filename and line number to make the trace
helpful. The rest of the trace can be passed into ./decode_stacktrace.sh
to obtain the line numbers for kernel symbols.

Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://lore.kernel.org/r/20250703204818.925464-7-memxor@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
include/linux/bpf.h
kernel/bpf/stream.c

index b267c378d884564ed9730e8385fd913d849b85eb..34dd90ec7fad7aabf8778b3b54a08d4ae2f3fd97 100644 (file)
@@ -3616,8 +3616,10 @@ __printf(2, 3)
 int bpf_stream_stage_printk(struct bpf_stream_stage *ss, const char *fmt, ...);
 int bpf_stream_stage_commit(struct bpf_stream_stage *ss, struct bpf_prog *prog,
                            enum bpf_stream_id stream_id);
+int bpf_stream_stage_dump_stack(struct bpf_stream_stage *ss);
 
 #define bpf_stream_printk(ss, ...) bpf_stream_stage_printk(&ss, __VA_ARGS__)
+#define bpf_stream_dump_stack(ss) bpf_stream_stage_dump_stack(&ss)
 
 #define bpf_stream_stage(ss, prog, stream_id, expr)            \
        ({                                                     \
index e434541358db8ef5332e577a84ff483e39ff9342..8c842f845245ac07fb834bc0555f431423cc2395 100644 (file)
@@ -2,6 +2,7 @@
 /* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */
 
 #include <linux/bpf.h>
+#include <linux/filter.h>
 #include <linux/bpf_mem_alloc.h>
 #include <linux/percpu.h>
 #include <linux/refcount.h>
@@ -476,3 +477,50 @@ int bpf_stream_stage_commit(struct bpf_stream_stage *ss, struct bpf_prog *prog,
        llist_add_batch(head, tail, &stream->log);
        return 0;
 }
+
+struct dump_stack_ctx {
+       struct bpf_stream_stage *ss;
+       int err;
+};
+
+static bool dump_stack_cb(void *cookie, u64 ip, u64 sp, u64 bp)
+{
+       struct dump_stack_ctx *ctxp = cookie;
+       const char *file = "", *line = "";
+       struct bpf_prog *prog;
+       int num, ret;
+
+       rcu_read_lock();
+       prog = bpf_prog_ksym_find(ip);
+       rcu_read_unlock();
+       if (prog) {
+               ret = bpf_prog_get_file_line(prog, ip, &file, &line, &num);
+               if (ret < 0)
+                       goto end;
+               ctxp->err = bpf_stream_stage_printk(ctxp->ss, "%pS\n  %s @ %s:%d\n",
+                                                   (void *)ip, line, file, num);
+               return !ctxp->err;
+       }
+end:
+       ctxp->err = bpf_stream_stage_printk(ctxp->ss, "%pS\n", (void *)ip);
+       return !ctxp->err;
+}
+
+int bpf_stream_stage_dump_stack(struct bpf_stream_stage *ss)
+{
+       struct dump_stack_ctx ctx = { .ss = ss };
+       int ret;
+
+       ret = bpf_stream_stage_printk(ss, "CPU: %d UID: %d PID: %d Comm: %s\n",
+                                     raw_smp_processor_id(), __kuid_val(current_real_cred()->euid),
+                                     current->pid, current->comm);
+       if (ret)
+               return ret;
+       ret = bpf_stream_stage_printk(ss, "Call trace:\n");
+       if (ret)
+               return ret;
+       arch_bpf_stack_walk(dump_stack_cb, &ctx);
+       if (ctx.err)
+               return ctx.err;
+       return bpf_stream_stage_printk(ss, "\n");
+}