[RFC PATCH bpf-next/net v1 08/13] bpf: Add dump_stack() analogue to print to BPF stderr

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 PC 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.

Signed-off-by: Kumar Kartikeya Dwivedi <memxor@xxxxxxxxx>
---
 include/linux/bpf.h |  2 +
 kernel/bpf/stream.c | 99 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 101 insertions(+)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index ae2ddd3bdea1..d4687da63645 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -3588,6 +3588,8 @@ void bpf_prog_stream_init(struct bpf_prog *prog);
 void bpf_prog_stream_free(struct bpf_prog *prog);
 __printf(2, 3)
 int bpf_prog_stderr_printk(struct bpf_prog *prog, const char *fmt, ...);
+struct bpf_prog *bpf_prog_find_from_stack(void);
+void bpf_prog_stderr_dump_stack(struct bpf_prog *prog);
 
 #ifdef CONFIG_BPF_LSM
 void bpf_cgroup_atype_get(u32 attach_btf_id, int cgroup_atype);
diff --git a/kernel/bpf/stream.c b/kernel/bpf/stream.c
index 2019ce134310..f5d8d2841a13 100644
--- a/kernel/bpf/stream.c
+++ b/kernel/bpf/stream.c
@@ -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>
@@ -494,3 +495,101 @@ int bpf_prog_stderr_printk(struct bpf_prog *prog, const char *fmt, ...)
 	bpf_put_buffers();
 	return ret;
 }
+
+struct walk_stack_ctx {
+	struct bpf_prog *prog;
+};
+
+static bool find_from_stack_cb(void *cookie, u64 ip, u64 sp, u64 bp)
+{
+	struct walk_stack_ctx *ctxp = cookie;
+	struct bpf_prog *prog;
+
+	if (!is_bpf_text_address(ip))
+		return true;
+	prog = bpf_prog_ksym_find(ip);
+	if (bpf_is_subprog(prog))
+		return true;
+	ctxp->prog = prog;
+	return false;
+}
+
+struct bpf_prog *bpf_prog_find_from_stack(void)
+{
+	struct walk_stack_ctx ctx = {};
+
+	arch_bpf_stack_walk(find_from_stack_cb, &ctx);
+	return ctx.prog;
+}
+
+struct dump_stack_ctx {
+	struct bpf_prog *prog;
+};
+
+static int dump_stack_bpf_linfo(u64 ip, const char **filep)
+{
+	struct bpf_prog *prog = bpf_prog_ksym_find(ip);
+	int idx = -1, insn_start, insn_end, len;
+	struct bpf_line_info *linfo;
+	void **jited_linfo;
+	struct btf *btf;
+
+	btf = prog->aux->btf;
+	linfo = prog->aux->linfo;
+	jited_linfo = prog->aux->jited_linfo;
+
+	if (!btf || !linfo || !prog->aux->jited_linfo)
+		return -1;
+	len = prog->aux->func ? prog->aux->func[prog->aux->func_idx]->len : prog->len;
+
+	linfo = &prog->aux->linfo[prog->aux->linfo_idx];
+	jited_linfo = &prog->aux->jited_linfo[prog->aux->linfo_idx];
+
+	insn_start = linfo[0].insn_off;
+	insn_end = insn_start + len;
+
+	for (int i = 0; linfo[i].insn_off >= insn_start && linfo[i].insn_off < insn_end; i++) {
+		if (jited_linfo[i] >= (void *)ip)
+			break;
+		idx = i;
+	}
+
+	if (idx == -1)
+		return -1;
+
+	*filep = btf_name_by_offset(btf, linfo[idx].file_name_off);
+	*filep = strrchr(*filep, '/') ?: *filep;
+	*filep += 1;
+
+	return BPF_LINE_INFO_LINE_NUM(linfo[idx].line_col);
+}
+
+static bool dump_stack_cb(void *cookie, u64 ip, u64 sp, u64 bp)
+{
+	struct dump_stack_ctx *ctxp = cookie;
+	const char *file = "";
+	int num;
+
+	if (is_bpf_text_address(ip)) {
+		num = dump_stack_bpf_linfo(ip, &file);
+		if (num == -1)
+			goto end;
+		bpf_prog_stderr_printk(ctxp->prog, " %pS: [%s:%d]\n", (void *)ip, file, num);
+		return true;
+	}
+end:
+	bpf_prog_stderr_printk(ctxp->prog, " %pS\n", (void *)ip);
+	return true;
+}
+
+void bpf_prog_stderr_dump_stack(struct bpf_prog *prog)
+{
+	struct dump_stack_ctx ctx = { .prog = prog };
+
+	bpf_prog_stderr_printk(prog, "CPU: %d UID: %d PID: %d Comm: %s\n",
+			       raw_smp_processor_id(), __kuid_val(current_real_cred()->euid),
+			       current->pid, current->comm);
+	bpf_prog_stderr_printk(prog, "Call trace:\n");
+	arch_bpf_stack_walk(dump_stack_cb, &ctx);
+	bpf_prog_stderr_printk(prog, "\n");
+}
-- 
2.47.1





[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux