mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	bpf: Add bpf_snprintf_btf helper
A helper is added to support tracing kernel type information in BPF
using the BPF Type Format (BTF).  Its signature is
long bpf_snprintf_btf(char *str, u32 str_size, struct btf_ptr *ptr,
		      u32 btf_ptr_size, u64 flags);
struct btf_ptr * specifies
- a pointer to the data to be traced
- the BTF id of the type of data pointed to
- a flags field is provided for future use; these flags
  are not to be confused with the BTF_F_* flags
  below that control how the btf_ptr is displayed; the
  flags member of the struct btf_ptr may be used to
  disambiguate types in kernel versus module BTF, etc;
  the main distinction is the flags relate to the type
  and information needed in identifying it; not how it
  is displayed.
For example a BPF program with a struct sk_buff *skb
could do the following:
	static struct btf_ptr b = { };
	b.ptr = skb;
	b.type_id = __builtin_btf_type_id(struct sk_buff, 1);
	bpf_snprintf_btf(str, sizeof(str), &b, sizeof(b), 0, 0);
Default output looks like this:
(struct sk_buff){
 .transport_header = (__u16)65535,
 .mac_header = (__u16)65535,
 .end = (sk_buff_data_t)192,
 .head = (unsigned char *)0x000000007524fd8b,
 .data = (unsigned char *)0x000000007524fd8b,
 .truesize = (unsigned int)768,
 .users = (refcount_t){
  .refs = (atomic_t){
   .counter = (int)1,
  },
 },
}
Flags modifying display are as follows:
- BTF_F_COMPACT:	no formatting around type information
- BTF_F_NONAME:		no struct/union member names/types
- BTF_F_PTR_RAW:	show raw (unobfuscated) pointer values;
			equivalent to %px.
- BTF_F_ZERO:		show zero-valued struct/union members;
			they are not displayed by default
Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/1601292670-1616-4-git-send-email-alan.maguire@oracle.com
			
			
This commit is contained in:
		
							parent
							
								
									31d0bc8163
								
							
						
					
					
						commit
						c4d0bfb450
					
				
					 8 changed files with 212 additions and 4 deletions
				
			
		| 
						 | 
				
			
			@ -1822,6 +1822,7 @@ extern const struct bpf_func_proto bpf_skc_to_tcp_timewait_sock_proto;
 | 
			
		|||
extern const struct bpf_func_proto bpf_skc_to_tcp_request_sock_proto;
 | 
			
		||||
extern const struct bpf_func_proto bpf_skc_to_udp6_sock_proto;
 | 
			
		||||
extern const struct bpf_func_proto bpf_copy_from_user_proto;
 | 
			
		||||
extern const struct bpf_func_proto bpf_snprintf_btf_proto;
 | 
			
		||||
 | 
			
		||||
const struct bpf_func_proto *bpf_tracing_func_proto(
 | 
			
		||||
	enum bpf_func_id func_id, const struct bpf_prog *prog);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,7 @@
 | 
			
		|||
 | 
			
		||||
#include <linux/types.h>
 | 
			
		||||
#include <uapi/linux/btf.h>
 | 
			
		||||
#include <uapi/linux/bpf.h>
 | 
			
		||||
 | 
			
		||||
#define BTF_TYPE_EMIT(type) ((void)(type *)0)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -59,10 +60,10 @@ const struct btf_type *btf_type_id_size(const struct btf *btf,
 | 
			
		|||
 *	- BTF_SHOW_UNSAFE: skip use of bpf_probe_read() to safely read
 | 
			
		||||
 *	  data before displaying it.
 | 
			
		||||
 */
 | 
			
		||||
#define BTF_SHOW_COMPACT	(1ULL << 0)
 | 
			
		||||
#define BTF_SHOW_NONAME		(1ULL << 1)
 | 
			
		||||
#define BTF_SHOW_PTR_RAW	(1ULL << 2)
 | 
			
		||||
#define BTF_SHOW_ZERO		(1ULL << 3)
 | 
			
		||||
#define BTF_SHOW_COMPACT	BTF_F_COMPACT
 | 
			
		||||
#define BTF_SHOW_NONAME		BTF_F_NONAME
 | 
			
		||||
#define BTF_SHOW_PTR_RAW	BTF_F_PTR_RAW
 | 
			
		||||
#define BTF_SHOW_ZERO		BTF_F_ZERO
 | 
			
		||||
#define BTF_SHOW_UNSAFE		(1ULL << 4)
 | 
			
		||||
 | 
			
		||||
void btf_type_seq_show(const struct btf *btf, u32 type_id, void *obj,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3594,6 +3594,42 @@ union bpf_attr {
 | 
			
		|||
 * 		the data in *dst*. This is a wrapper of **copy_from_user**\ ().
 | 
			
		||||
 * 	Return
 | 
			
		||||
 * 		0 on success, or a negative error in case of failure.
 | 
			
		||||
 *
 | 
			
		||||
 * long bpf_snprintf_btf(char *str, u32 str_size, struct btf_ptr *ptr, u32 btf_ptr_size, u64 flags)
 | 
			
		||||
 *	Description
 | 
			
		||||
 *		Use BTF to store a string representation of *ptr*->ptr in *str*,
 | 
			
		||||
 *		using *ptr*->type_id.  This value should specify the type
 | 
			
		||||
 *		that *ptr*->ptr points to. LLVM __builtin_btf_type_id(type, 1)
 | 
			
		||||
 *		can be used to look up vmlinux BTF type ids. Traversing the
 | 
			
		||||
 *		data structure using BTF, the type information and values are
 | 
			
		||||
 *		stored in the first *str_size* - 1 bytes of *str*.  Safe copy of
 | 
			
		||||
 *		the pointer data is carried out to avoid kernel crashes during
 | 
			
		||||
 *		operation.  Smaller types can use string space on the stack;
 | 
			
		||||
 *		larger programs can use map data to store the string
 | 
			
		||||
 *		representation.
 | 
			
		||||
 *
 | 
			
		||||
 *		The string can be subsequently shared with userspace via
 | 
			
		||||
 *		bpf_perf_event_output() or ring buffer interfaces.
 | 
			
		||||
 *		bpf_trace_printk() is to be avoided as it places too small
 | 
			
		||||
 *		a limit on string size to be useful.
 | 
			
		||||
 *
 | 
			
		||||
 *		*flags* is a combination of
 | 
			
		||||
 *
 | 
			
		||||
 *		**BTF_F_COMPACT**
 | 
			
		||||
 *			no formatting around type information
 | 
			
		||||
 *		**BTF_F_NONAME**
 | 
			
		||||
 *			no struct/union member names/types
 | 
			
		||||
 *		**BTF_F_PTR_RAW**
 | 
			
		||||
 *			show raw (unobfuscated) pointer values;
 | 
			
		||||
 *			equivalent to printk specifier %px.
 | 
			
		||||
 *		**BTF_F_ZERO**
 | 
			
		||||
 *			show zero-valued struct/union members; they
 | 
			
		||||
 *			are not displayed by default
 | 
			
		||||
 *
 | 
			
		||||
 *	Return
 | 
			
		||||
 *		The number of bytes that were written (or would have been
 | 
			
		||||
 *		written if output had to be truncated due to string size),
 | 
			
		||||
 *		or a negative error in cases of failure.
 | 
			
		||||
 */
 | 
			
		||||
#define __BPF_FUNC_MAPPER(FN)		\
 | 
			
		||||
	FN(unspec),			\
 | 
			
		||||
| 
						 | 
				
			
			@ -3745,6 +3781,7 @@ union bpf_attr {
 | 
			
		|||
	FN(inode_storage_delete),	\
 | 
			
		||||
	FN(d_path),			\
 | 
			
		||||
	FN(copy_from_user),		\
 | 
			
		||||
	FN(snprintf_btf),		\
 | 
			
		||||
	/* */
 | 
			
		||||
 | 
			
		||||
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
 | 
			
		||||
| 
						 | 
				
			
			@ -4853,4 +4890,34 @@ struct bpf_sk_lookup {
 | 
			
		|||
	__u32 local_port;	/* Host byte order */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * struct btf_ptr is used for typed pointer representation; the
 | 
			
		||||
 * type id is used to render the pointer data as the appropriate type
 | 
			
		||||
 * via the bpf_snprintf_btf() helper described above.  A flags field -
 | 
			
		||||
 * potentially to specify additional details about the BTF pointer
 | 
			
		||||
 * (rather than its mode of display) - is included for future use.
 | 
			
		||||
 * Display flags - BTF_F_* - are passed to bpf_snprintf_btf separately.
 | 
			
		||||
 */
 | 
			
		||||
struct btf_ptr {
 | 
			
		||||
	void *ptr;
 | 
			
		||||
	__u32 type_id;
 | 
			
		||||
	__u32 flags;		/* BTF ptr flags; unused at present. */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Flags to control bpf_snprintf_btf() behaviour.
 | 
			
		||||
 *     - BTF_F_COMPACT: no formatting around type information
 | 
			
		||||
 *     - BTF_F_NONAME: no struct/union member names/types
 | 
			
		||||
 *     - BTF_F_PTR_RAW: show raw (unobfuscated) pointer values;
 | 
			
		||||
 *       equivalent to %px.
 | 
			
		||||
 *     - BTF_F_ZERO: show zero-valued struct/union members; they
 | 
			
		||||
 *       are not displayed by default
 | 
			
		||||
 */
 | 
			
		||||
enum {
 | 
			
		||||
	BTF_F_COMPACT	=	(1ULL << 0),
 | 
			
		||||
	BTF_F_NONAME	=	(1ULL << 1),
 | 
			
		||||
	BTF_F_PTR_RAW	=	(1ULL << 2),
 | 
			
		||||
	BTF_F_ZERO	=	(1ULL << 3),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif /* _UAPI__LINUX_BPF_H__ */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2216,6 +2216,7 @@ const struct bpf_func_proto bpf_get_current_cgroup_id_proto __weak;
 | 
			
		|||
const struct bpf_func_proto bpf_get_current_ancestor_cgroup_id_proto __weak;
 | 
			
		||||
const struct bpf_func_proto bpf_get_local_storage_proto __weak;
 | 
			
		||||
const struct bpf_func_proto bpf_get_ns_current_pid_tgid_proto __weak;
 | 
			
		||||
const struct bpf_func_proto bpf_snprintf_btf_proto __weak;
 | 
			
		||||
 | 
			
		||||
const struct bpf_func_proto * __weak bpf_get_trace_printk_proto(void)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -683,6 +683,10 @@ bpf_base_func_proto(enum bpf_func_id func_id)
 | 
			
		|||
		if (!perfmon_capable())
 | 
			
		||||
			return NULL;
 | 
			
		||||
		return bpf_get_trace_printk_proto();
 | 
			
		||||
	case BPF_FUNC_snprintf_btf:
 | 
			
		||||
		if (!perfmon_capable())
 | 
			
		||||
			return NULL;
 | 
			
		||||
		return &bpf_snprintf_btf_proto;
 | 
			
		||||
	case BPF_FUNC_jiffies64:
 | 
			
		||||
		return &bpf_jiffies64_proto;
 | 
			
		||||
	default:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,6 +7,7 @@
 | 
			
		|||
#include <linux/slab.h>
 | 
			
		||||
#include <linux/bpf.h>
 | 
			
		||||
#include <linux/bpf_perf_event.h>
 | 
			
		||||
#include <linux/btf.h>
 | 
			
		||||
#include <linux/filter.h>
 | 
			
		||||
#include <linux/uaccess.h>
 | 
			
		||||
#include <linux/ctype.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -16,6 +17,9 @@
 | 
			
		|||
#include <linux/error-injection.h>
 | 
			
		||||
#include <linux/btf_ids.h>
 | 
			
		||||
 | 
			
		||||
#include <uapi/linux/bpf.h>
 | 
			
		||||
#include <uapi/linux/btf.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/tlb.h>
 | 
			
		||||
 | 
			
		||||
#include "trace_probe.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -1147,6 +1151,65 @@ static const struct bpf_func_proto bpf_d_path_proto = {
 | 
			
		|||
	.allowed	= bpf_d_path_allowed,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define BTF_F_ALL	(BTF_F_COMPACT  | BTF_F_NONAME | \
 | 
			
		||||
			 BTF_F_PTR_RAW | BTF_F_ZERO)
 | 
			
		||||
 | 
			
		||||
static int bpf_btf_printf_prepare(struct btf_ptr *ptr, u32 btf_ptr_size,
 | 
			
		||||
				  u64 flags, const struct btf **btf,
 | 
			
		||||
				  s32 *btf_id)
 | 
			
		||||
{
 | 
			
		||||
	const struct btf_type *t;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(flags & ~(BTF_F_ALL)))
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	if (btf_ptr_size != sizeof(struct btf_ptr))
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	*btf = bpf_get_btf_vmlinux();
 | 
			
		||||
 | 
			
		||||
	if (IS_ERR_OR_NULL(*btf))
 | 
			
		||||
		return PTR_ERR(*btf);
 | 
			
		||||
 | 
			
		||||
	if (ptr->type_id > 0)
 | 
			
		||||
		*btf_id = ptr->type_id;
 | 
			
		||||
	else
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	if (*btf_id > 0)
 | 
			
		||||
		t = btf_type_by_id(*btf, *btf_id);
 | 
			
		||||
	if (*btf_id <= 0 || !t)
 | 
			
		||||
		return -ENOENT;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BPF_CALL_5(bpf_snprintf_btf, char *, str, u32, str_size, struct btf_ptr *, ptr,
 | 
			
		||||
	   u32, btf_ptr_size, u64, flags)
 | 
			
		||||
{
 | 
			
		||||
	const struct btf *btf;
 | 
			
		||||
	s32 btf_id;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = bpf_btf_printf_prepare(ptr, btf_ptr_size, flags, &btf, &btf_id);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	return btf_type_snprintf_show(btf, btf_id, ptr->ptr, str, str_size,
 | 
			
		||||
				      flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const struct bpf_func_proto bpf_snprintf_btf_proto = {
 | 
			
		||||
	.func		= bpf_snprintf_btf,
 | 
			
		||||
	.gpl_only	= false,
 | 
			
		||||
	.ret_type	= RET_INTEGER,
 | 
			
		||||
	.arg1_type	= ARG_PTR_TO_MEM,
 | 
			
		||||
	.arg2_type	= ARG_CONST_SIZE,
 | 
			
		||||
	.arg3_type	= ARG_PTR_TO_MEM,
 | 
			
		||||
	.arg4_type	= ARG_CONST_SIZE,
 | 
			
		||||
	.arg5_type	= ARG_ANYTHING,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const struct bpf_func_proto *
 | 
			
		||||
bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1233,6 +1296,8 @@ bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
 | 
			
		|||
		return &bpf_get_task_stack_proto;
 | 
			
		||||
	case BPF_FUNC_copy_from_user:
 | 
			
		||||
		return prog->aux->sleepable ? &bpf_copy_from_user_proto : NULL;
 | 
			
		||||
	case BPF_FUNC_snprintf_btf:
 | 
			
		||||
		return &bpf_snprintf_btf_proto;
 | 
			
		||||
	default:
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -433,6 +433,7 @@ class PrinterHelpers(Printer):
 | 
			
		|||
            'struct sk_msg_md',
 | 
			
		||||
            'struct xdp_md',
 | 
			
		||||
            'struct path',
 | 
			
		||||
            'struct btf_ptr',
 | 
			
		||||
    ]
 | 
			
		||||
    known_types = {
 | 
			
		||||
            '...',
 | 
			
		||||
| 
						 | 
				
			
			@ -474,6 +475,7 @@ class PrinterHelpers(Printer):
 | 
			
		|||
            'struct udp6_sock',
 | 
			
		||||
            'struct task_struct',
 | 
			
		||||
            'struct path',
 | 
			
		||||
            'struct btf_ptr',
 | 
			
		||||
    }
 | 
			
		||||
    mapped_types = {
 | 
			
		||||
            'u8': '__u8',
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3594,6 +3594,42 @@ union bpf_attr {
 | 
			
		|||
 * 		the data in *dst*. This is a wrapper of **copy_from_user**\ ().
 | 
			
		||||
 * 	Return
 | 
			
		||||
 * 		0 on success, or a negative error in case of failure.
 | 
			
		||||
 *
 | 
			
		||||
 * long bpf_snprintf_btf(char *str, u32 str_size, struct btf_ptr *ptr, u32 btf_ptr_size, u64 flags)
 | 
			
		||||
 *	Description
 | 
			
		||||
 *		Use BTF to store a string representation of *ptr*->ptr in *str*,
 | 
			
		||||
 *		using *ptr*->type_id.  This value should specify the type
 | 
			
		||||
 *		that *ptr*->ptr points to. LLVM __builtin_btf_type_id(type, 1)
 | 
			
		||||
 *		can be used to look up vmlinux BTF type ids. Traversing the
 | 
			
		||||
 *		data structure using BTF, the type information and values are
 | 
			
		||||
 *		stored in the first *str_size* - 1 bytes of *str*.  Safe copy of
 | 
			
		||||
 *		the pointer data is carried out to avoid kernel crashes during
 | 
			
		||||
 *		operation.  Smaller types can use string space on the stack;
 | 
			
		||||
 *		larger programs can use map data to store the string
 | 
			
		||||
 *		representation.
 | 
			
		||||
 *
 | 
			
		||||
 *		The string can be subsequently shared with userspace via
 | 
			
		||||
 *		bpf_perf_event_output() or ring buffer interfaces.
 | 
			
		||||
 *		bpf_trace_printk() is to be avoided as it places too small
 | 
			
		||||
 *		a limit on string size to be useful.
 | 
			
		||||
 *
 | 
			
		||||
 *		*flags* is a combination of
 | 
			
		||||
 *
 | 
			
		||||
 *		**BTF_F_COMPACT**
 | 
			
		||||
 *			no formatting around type information
 | 
			
		||||
 *		**BTF_F_NONAME**
 | 
			
		||||
 *			no struct/union member names/types
 | 
			
		||||
 *		**BTF_F_PTR_RAW**
 | 
			
		||||
 *			show raw (unobfuscated) pointer values;
 | 
			
		||||
 *			equivalent to printk specifier %px.
 | 
			
		||||
 *		**BTF_F_ZERO**
 | 
			
		||||
 *			show zero-valued struct/union members; they
 | 
			
		||||
 *			are not displayed by default
 | 
			
		||||
 *
 | 
			
		||||
 *	Return
 | 
			
		||||
 *		The number of bytes that were written (or would have been
 | 
			
		||||
 *		written if output had to be truncated due to string size),
 | 
			
		||||
 *		or a negative error in cases of failure.
 | 
			
		||||
 */
 | 
			
		||||
#define __BPF_FUNC_MAPPER(FN)		\
 | 
			
		||||
	FN(unspec),			\
 | 
			
		||||
| 
						 | 
				
			
			@ -3745,6 +3781,7 @@ union bpf_attr {
 | 
			
		|||
	FN(inode_storage_delete),	\
 | 
			
		||||
	FN(d_path),			\
 | 
			
		||||
	FN(copy_from_user),		\
 | 
			
		||||
	FN(snprintf_btf),		\
 | 
			
		||||
	/* */
 | 
			
		||||
 | 
			
		||||
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
 | 
			
		||||
| 
						 | 
				
			
			@ -4853,4 +4890,34 @@ struct bpf_sk_lookup {
 | 
			
		|||
	__u32 local_port;	/* Host byte order */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * struct btf_ptr is used for typed pointer representation; the
 | 
			
		||||
 * type id is used to render the pointer data as the appropriate type
 | 
			
		||||
 * via the bpf_snprintf_btf() helper described above.  A flags field -
 | 
			
		||||
 * potentially to specify additional details about the BTF pointer
 | 
			
		||||
 * (rather than its mode of display) - is included for future use.
 | 
			
		||||
 * Display flags - BTF_F_* - are passed to bpf_snprintf_btf separately.
 | 
			
		||||
 */
 | 
			
		||||
struct btf_ptr {
 | 
			
		||||
	void *ptr;
 | 
			
		||||
	__u32 type_id;
 | 
			
		||||
	__u32 flags;		/* BTF ptr flags; unused at present. */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Flags to control bpf_snprintf_btf() behaviour.
 | 
			
		||||
 *     - BTF_F_COMPACT: no formatting around type information
 | 
			
		||||
 *     - BTF_F_NONAME: no struct/union member names/types
 | 
			
		||||
 *     - BTF_F_PTR_RAW: show raw (unobfuscated) pointer values;
 | 
			
		||||
 *       equivalent to %px.
 | 
			
		||||
 *     - BTF_F_ZERO: show zero-valued struct/union members; they
 | 
			
		||||
 *       are not displayed by default
 | 
			
		||||
 */
 | 
			
		||||
enum {
 | 
			
		||||
	BTF_F_COMPACT	=	(1ULL << 0),
 | 
			
		||||
	BTF_F_NONAME	=	(1ULL << 1),
 | 
			
		||||
	BTF_F_PTR_RAW	=	(1ULL << 2),
 | 
			
		||||
	BTF_F_ZERO	=	(1ULL << 3),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif /* _UAPI__LINUX_BPF_H__ */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue