Commit 35cba298 authored by Alexei Starovoitov's avatar Alexei Starovoitov
Browse files

Merge branch 'bpf: Add bpf_task_pt_regs() helper'

Daniel Xu says:

====================

The motivation behind this helper is to access userspace pt_regs in a
kprobe handler.

uprobe's ctx is the userspace pt_regs. kprobe's ctx is the kernelspace
pt_regs. bpf_task_pt_regs() allows accessing userspace pt_regs in a
kprobe handler. The final case (kernelspace pt_regs in uprobe) is
pretty rare (usermode helper) so I think that can be solved later if
necessary.

More concretely, this helper is useful in doing BPF-based DWARF stack
unwinding. Currently the kernel can only do framepointer based stack
unwinds for userspace code. This is because the DWARF state machines are
too fragile to be computed in kernelspace [0]. The idea behind
DWARF-based stack unwinds w/ BPF is to copy a chunk of the userspace
stack (while in prog context) and send it up to userspace for unwinding
(probably with libunwind) [1]. This would effectively enable profiling
applications with -fomit-frame-pointer using kprobes and uprobes.

[0]: https://lkml.org/lkml/2012/2/10/356
[1]: https://github.com/danobi/bpf-dwarf-walk



Changes from v1:
- Conwolidate BTF_ID decls for task_struct
- Enable bpf_get_current_task_btf() for all prog types
- Enable bpf_task_pt_regs() for all prog types
- Use ASSERT_* macros instead of CHECK
====================

Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parents 3bbc8ee7 576d47bb
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -82,6 +82,9 @@ __BTF_ID_LIST(name, globl)
#define BTF_ID_LIST_SINGLE(name, prefix, typename)	\
	BTF_ID_LIST(name) \
	BTF_ID(prefix, typename)
#define BTF_ID_LIST_GLOBAL_SINGLE(name, prefix, typename) \
	BTF_ID_LIST_GLOBAL(name) \
	BTF_ID(prefix, typename)

/*
 * The BTF_ID_UNUSED macro defines 4 zero bytes.
@@ -185,4 +188,6 @@ MAX_BTF_SOCK_TYPE,
extern u32 btf_sock_ids[];
#endif

extern u32 btf_task_struct_ids[];

#endif
+7 −0
Original line number Diff line number Diff line
@@ -4871,6 +4871,12 @@ union bpf_attr {
 * 	Return
 *		Value specified by user at BPF link creation/attachment time
 *		or 0, if it was not specified.
 *
 * long bpf_task_pt_regs(struct task_struct *task)
 *	Description
 *		Get the struct pt_regs associated with **task**.
 *	Return
 *		A pointer to struct pt_regs.
 */
#define __BPF_FUNC_MAPPER(FN)		\
	FN(unspec),			\
@@ -5048,6 +5054,7 @@ union bpf_attr {
	FN(timer_cancel),		\
	FN(get_func_ip),		\
	FN(get_attach_cookie),		\
	FN(task_pt_regs),		\
	/* */

/* integer value in 'imm' field of BPF_CALL instruction selects which helper
+2 −4
Original line number Diff line number Diff line
@@ -317,15 +317,13 @@ const struct bpf_map_ops task_storage_map_ops = {
	.map_owner_storage_ptr = task_storage_ptr,
};

BTF_ID_LIST_SINGLE(bpf_task_storage_btf_ids, struct, task_struct)

const struct bpf_func_proto bpf_task_storage_get_proto = {
	.func = bpf_task_storage_get,
	.gpl_only = false,
	.ret_type = RET_PTR_TO_MAP_VALUE_OR_NULL,
	.arg1_type = ARG_CONST_MAP_PTR,
	.arg2_type = ARG_PTR_TO_BTF_ID,
	.arg2_btf_id = &bpf_task_storage_btf_ids[0],
	.arg2_btf_id = &btf_task_struct_ids[0],
	.arg3_type = ARG_PTR_TO_MAP_VALUE_OR_NULL,
	.arg4_type = ARG_ANYTHING,
};
@@ -336,5 +334,5 @@ const struct bpf_func_proto bpf_task_storage_delete_proto = {
	.ret_type = RET_INTEGER,
	.arg1_type = ARG_CONST_MAP_PTR,
	.arg2_type = ARG_PTR_TO_BTF_ID,
	.arg2_btf_id = &bpf_task_storage_btf_ids[0],
	.arg2_btf_id = &btf_task_struct_ids[0],
};
+6 −0
Original line number Diff line number Diff line
@@ -1322,10 +1322,12 @@ void bpf_timer_cancel_and_free(void *val)
}

const struct bpf_func_proto bpf_get_current_task_proto __weak;
const struct bpf_func_proto bpf_get_current_task_btf_proto __weak;
const struct bpf_func_proto bpf_probe_read_user_proto __weak;
const struct bpf_func_proto bpf_probe_read_user_str_proto __weak;
const struct bpf_func_proto bpf_probe_read_kernel_proto __weak;
const struct bpf_func_proto bpf_probe_read_kernel_str_proto __weak;
const struct bpf_func_proto bpf_task_pt_regs_proto __weak;

const struct bpf_func_proto *
bpf_base_func_proto(enum bpf_func_id func_id)
@@ -1407,6 +1409,8 @@ bpf_base_func_proto(enum bpf_func_id func_id)
		return bpf_get_trace_printk_proto();
	case BPF_FUNC_get_current_task:
		return &bpf_get_current_task_proto;
	case BPF_FUNC_get_current_task_btf:
		return &bpf_get_current_task_btf_proto;
	case BPF_FUNC_probe_read_user:
		return &bpf_probe_read_user_proto;
	case BPF_FUNC_probe_read_kernel:
@@ -1421,6 +1425,8 @@ bpf_base_func_proto(enum bpf_func_id func_id)
		return &bpf_snprintf_btf_proto;
	case BPF_FUNC_snprintf:
		return &bpf_snprintf_proto;
	case BPF_FUNC_task_pt_regs:
		return &bpf_task_pt_regs_proto;
	default:
		return NULL;
	}
+1 −3
Original line number Diff line number Diff line
@@ -530,14 +530,12 @@ BPF_CALL_4(bpf_get_task_stack, struct task_struct *, task, void *, buf,
	return res;
}

BTF_ID_LIST_SINGLE(bpf_get_task_stack_btf_ids, struct, task_struct)

const struct bpf_func_proto bpf_get_task_stack_proto = {
	.func		= bpf_get_task_stack,
	.gpl_only	= false,
	.ret_type	= RET_INTEGER,
	.arg1_type	= ARG_PTR_TO_BTF_ID,
	.arg1_btf_id	= &bpf_get_task_stack_btf_ids[0],
	.arg1_btf_id	= &btf_task_struct_ids[0],
	.arg2_type	= ARG_PTR_TO_UNINIT_MEM,
	.arg3_type	= ARG_CONST_SIZE_OR_ZERO,
	.arg4_type	= ARG_ANYTHING,
Loading