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:
Родитель
31d0bc8163
Коммит
c4d0bfb450
|
@ -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__ */
|
||||
|
|
Загрузка…
Ссылка в новой задаче