Skip to content

Commit c4d0bfb

Browse files
alan-maguireAlexei Starovoitov
authored and
Alexei Starovoitov
committed
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 <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 31d0bc8 commit c4d0bfb

File tree

8 files changed

+212
-4
lines changed

8 files changed

+212
-4
lines changed

Diff for: include/linux/bpf.h

+1
Original file line numberDiff line numberDiff line change
@@ -1822,6 +1822,7 @@ extern const struct bpf_func_proto bpf_skc_to_tcp_timewait_sock_proto;
18221822
extern const struct bpf_func_proto bpf_skc_to_tcp_request_sock_proto;
18231823
extern const struct bpf_func_proto bpf_skc_to_udp6_sock_proto;
18241824
extern const struct bpf_func_proto bpf_copy_from_user_proto;
1825+
extern const struct bpf_func_proto bpf_snprintf_btf_proto;
18251826

18261827
const struct bpf_func_proto *bpf_tracing_func_proto(
18271828
enum bpf_func_id func_id, const struct bpf_prog *prog);

Diff for: include/linux/btf.h

+5-4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <linux/types.h>
88
#include <uapi/linux/btf.h>
9+
#include <uapi/linux/bpf.h>
910

1011
#define BTF_TYPE_EMIT(type) ((void)(type *)0)
1112

@@ -59,10 +60,10 @@ const struct btf_type *btf_type_id_size(const struct btf *btf,
5960
* - BTF_SHOW_UNSAFE: skip use of bpf_probe_read() to safely read
6061
* data before displaying it.
6162
*/
62-
#define BTF_SHOW_COMPACT (1ULL << 0)
63-
#define BTF_SHOW_NONAME (1ULL << 1)
64-
#define BTF_SHOW_PTR_RAW (1ULL << 2)
65-
#define BTF_SHOW_ZERO (1ULL << 3)
63+
#define BTF_SHOW_COMPACT BTF_F_COMPACT
64+
#define BTF_SHOW_NONAME BTF_F_NONAME
65+
#define BTF_SHOW_PTR_RAW BTF_F_PTR_RAW
66+
#define BTF_SHOW_ZERO BTF_F_ZERO
6667
#define BTF_SHOW_UNSAFE (1ULL << 4)
6768

6869
void btf_type_seq_show(const struct btf *btf, u32 type_id, void *obj,

Diff for: include/uapi/linux/bpf.h

+67
Original file line numberDiff line numberDiff line change
@@ -3594,6 +3594,42 @@ union bpf_attr {
35943594
* the data in *dst*. This is a wrapper of **copy_from_user**\ ().
35953595
* Return
35963596
* 0 on success, or a negative error in case of failure.
3597+
*
3598+
* long bpf_snprintf_btf(char *str, u32 str_size, struct btf_ptr *ptr, u32 btf_ptr_size, u64 flags)
3599+
* Description
3600+
* Use BTF to store a string representation of *ptr*->ptr in *str*,
3601+
* using *ptr*->type_id. This value should specify the type
3602+
* that *ptr*->ptr points to. LLVM __builtin_btf_type_id(type, 1)
3603+
* can be used to look up vmlinux BTF type ids. Traversing the
3604+
* data structure using BTF, the type information and values are
3605+
* stored in the first *str_size* - 1 bytes of *str*. Safe copy of
3606+
* the pointer data is carried out to avoid kernel crashes during
3607+
* operation. Smaller types can use string space on the stack;
3608+
* larger programs can use map data to store the string
3609+
* representation.
3610+
*
3611+
* The string can be subsequently shared with userspace via
3612+
* bpf_perf_event_output() or ring buffer interfaces.
3613+
* bpf_trace_printk() is to be avoided as it places too small
3614+
* a limit on string size to be useful.
3615+
*
3616+
* *flags* is a combination of
3617+
*
3618+
* **BTF_F_COMPACT**
3619+
* no formatting around type information
3620+
* **BTF_F_NONAME**
3621+
* no struct/union member names/types
3622+
* **BTF_F_PTR_RAW**
3623+
* show raw (unobfuscated) pointer values;
3624+
* equivalent to printk specifier %px.
3625+
* **BTF_F_ZERO**
3626+
* show zero-valued struct/union members; they
3627+
* are not displayed by default
3628+
*
3629+
* Return
3630+
* The number of bytes that were written (or would have been
3631+
* written if output had to be truncated due to string size),
3632+
* or a negative error in cases of failure.
35973633
*/
35983634
#define __BPF_FUNC_MAPPER(FN) \
35993635
FN(unspec), \
@@ -3745,6 +3781,7 @@ union bpf_attr {
37453781
FN(inode_storage_delete), \
37463782
FN(d_path), \
37473783
FN(copy_from_user), \
3784+
FN(snprintf_btf), \
37483785
/* */
37493786

37503787
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
@@ -4853,4 +4890,34 @@ struct bpf_sk_lookup {
48534890
__u32 local_port; /* Host byte order */
48544891
};
48554892

4893+
/*
4894+
* struct btf_ptr is used for typed pointer representation; the
4895+
* type id is used to render the pointer data as the appropriate type
4896+
* via the bpf_snprintf_btf() helper described above. A flags field -
4897+
* potentially to specify additional details about the BTF pointer
4898+
* (rather than its mode of display) - is included for future use.
4899+
* Display flags - BTF_F_* - are passed to bpf_snprintf_btf separately.
4900+
*/
4901+
struct btf_ptr {
4902+
void *ptr;
4903+
__u32 type_id;
4904+
__u32 flags; /* BTF ptr flags; unused at present. */
4905+
};
4906+
4907+
/*
4908+
* Flags to control bpf_snprintf_btf() behaviour.
4909+
* - BTF_F_COMPACT: no formatting around type information
4910+
* - BTF_F_NONAME: no struct/union member names/types
4911+
* - BTF_F_PTR_RAW: show raw (unobfuscated) pointer values;
4912+
* equivalent to %px.
4913+
* - BTF_F_ZERO: show zero-valued struct/union members; they
4914+
* are not displayed by default
4915+
*/
4916+
enum {
4917+
BTF_F_COMPACT = (1ULL << 0),
4918+
BTF_F_NONAME = (1ULL << 1),
4919+
BTF_F_PTR_RAW = (1ULL << 2),
4920+
BTF_F_ZERO = (1ULL << 3),
4921+
};
4922+
48564923
#endif /* _UAPI__LINUX_BPF_H__ */

Diff for: kernel/bpf/core.c

+1
Original file line numberDiff line numberDiff line change
@@ -2216,6 +2216,7 @@ const struct bpf_func_proto bpf_get_current_cgroup_id_proto __weak;
22162216
const struct bpf_func_proto bpf_get_current_ancestor_cgroup_id_proto __weak;
22172217
const struct bpf_func_proto bpf_get_local_storage_proto __weak;
22182218
const struct bpf_func_proto bpf_get_ns_current_pid_tgid_proto __weak;
2219+
const struct bpf_func_proto bpf_snprintf_btf_proto __weak;
22192220

22202221
const struct bpf_func_proto * __weak bpf_get_trace_printk_proto(void)
22212222
{

Diff for: kernel/bpf/helpers.c

+4
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,10 @@ bpf_base_func_proto(enum bpf_func_id func_id)
683683
if (!perfmon_capable())
684684
return NULL;
685685
return bpf_get_trace_printk_proto();
686+
case BPF_FUNC_snprintf_btf:
687+
if (!perfmon_capable())
688+
return NULL;
689+
return &bpf_snprintf_btf_proto;
686690
case BPF_FUNC_jiffies64:
687691
return &bpf_jiffies64_proto;
688692
default:

Diff for: kernel/trace/bpf_trace.c

+65
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <linux/slab.h>
88
#include <linux/bpf.h>
99
#include <linux/bpf_perf_event.h>
10+
#include <linux/btf.h>
1011
#include <linux/filter.h>
1112
#include <linux/uaccess.h>
1213
#include <linux/ctype.h>
@@ -16,6 +17,9 @@
1617
#include <linux/error-injection.h>
1718
#include <linux/btf_ids.h>
1819

20+
#include <uapi/linux/bpf.h>
21+
#include <uapi/linux/btf.h>
22+
1923
#include <asm/tlb.h>
2024

2125
#include "trace_probe.h"
@@ -1147,6 +1151,65 @@ static const struct bpf_func_proto bpf_d_path_proto = {
11471151
.allowed = bpf_d_path_allowed,
11481152
};
11491153

1154+
#define BTF_F_ALL (BTF_F_COMPACT | BTF_F_NONAME | \
1155+
BTF_F_PTR_RAW | BTF_F_ZERO)
1156+
1157+
static int bpf_btf_printf_prepare(struct btf_ptr *ptr, u32 btf_ptr_size,
1158+
u64 flags, const struct btf **btf,
1159+
s32 *btf_id)
1160+
{
1161+
const struct btf_type *t;
1162+
1163+
if (unlikely(flags & ~(BTF_F_ALL)))
1164+
return -EINVAL;
1165+
1166+
if (btf_ptr_size != sizeof(struct btf_ptr))
1167+
return -EINVAL;
1168+
1169+
*btf = bpf_get_btf_vmlinux();
1170+
1171+
if (IS_ERR_OR_NULL(*btf))
1172+
return PTR_ERR(*btf);
1173+
1174+
if (ptr->type_id > 0)
1175+
*btf_id = ptr->type_id;
1176+
else
1177+
return -EINVAL;
1178+
1179+
if (*btf_id > 0)
1180+
t = btf_type_by_id(*btf, *btf_id);
1181+
if (*btf_id <= 0 || !t)
1182+
return -ENOENT;
1183+
1184+
return 0;
1185+
}
1186+
1187+
BPF_CALL_5(bpf_snprintf_btf, char *, str, u32, str_size, struct btf_ptr *, ptr,
1188+
u32, btf_ptr_size, u64, flags)
1189+
{
1190+
const struct btf *btf;
1191+
s32 btf_id;
1192+
int ret;
1193+
1194+
ret = bpf_btf_printf_prepare(ptr, btf_ptr_size, flags, &btf, &btf_id);
1195+
if (ret)
1196+
return ret;
1197+
1198+
return btf_type_snprintf_show(btf, btf_id, ptr->ptr, str, str_size,
1199+
flags);
1200+
}
1201+
1202+
const struct bpf_func_proto bpf_snprintf_btf_proto = {
1203+
.func = bpf_snprintf_btf,
1204+
.gpl_only = false,
1205+
.ret_type = RET_INTEGER,
1206+
.arg1_type = ARG_PTR_TO_MEM,
1207+
.arg2_type = ARG_CONST_SIZE,
1208+
.arg3_type = ARG_PTR_TO_MEM,
1209+
.arg4_type = ARG_CONST_SIZE,
1210+
.arg5_type = ARG_ANYTHING,
1211+
};
1212+
11501213
const struct bpf_func_proto *
11511214
bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
11521215
{
@@ -1233,6 +1296,8 @@ bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
12331296
return &bpf_get_task_stack_proto;
12341297
case BPF_FUNC_copy_from_user:
12351298
return prog->aux->sleepable ? &bpf_copy_from_user_proto : NULL;
1299+
case BPF_FUNC_snprintf_btf:
1300+
return &bpf_snprintf_btf_proto;
12361301
default:
12371302
return NULL;
12381303
}

Diff for: scripts/bpf_helpers_doc.py

+2
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,7 @@ class PrinterHelpers(Printer):
433433
'struct sk_msg_md',
434434
'struct xdp_md',
435435
'struct path',
436+
'struct btf_ptr',
436437
]
437438
known_types = {
438439
'...',
@@ -474,6 +475,7 @@ class PrinterHelpers(Printer):
474475
'struct udp6_sock',
475476
'struct task_struct',
476477
'struct path',
478+
'struct btf_ptr',
477479
}
478480
mapped_types = {
479481
'u8': '__u8',

Diff for: tools/include/uapi/linux/bpf.h

+67
Original file line numberDiff line numberDiff line change
@@ -3594,6 +3594,42 @@ union bpf_attr {
35943594
* the data in *dst*. This is a wrapper of **copy_from_user**\ ().
35953595
* Return
35963596
* 0 on success, or a negative error in case of failure.
3597+
*
3598+
* long bpf_snprintf_btf(char *str, u32 str_size, struct btf_ptr *ptr, u32 btf_ptr_size, u64 flags)
3599+
* Description
3600+
* Use BTF to store a string representation of *ptr*->ptr in *str*,
3601+
* using *ptr*->type_id. This value should specify the type
3602+
* that *ptr*->ptr points to. LLVM __builtin_btf_type_id(type, 1)
3603+
* can be used to look up vmlinux BTF type ids. Traversing the
3604+
* data structure using BTF, the type information and values are
3605+
* stored in the first *str_size* - 1 bytes of *str*. Safe copy of
3606+
* the pointer data is carried out to avoid kernel crashes during
3607+
* operation. Smaller types can use string space on the stack;
3608+
* larger programs can use map data to store the string
3609+
* representation.
3610+
*
3611+
* The string can be subsequently shared with userspace via
3612+
* bpf_perf_event_output() or ring buffer interfaces.
3613+
* bpf_trace_printk() is to be avoided as it places too small
3614+
* a limit on string size to be useful.
3615+
*
3616+
* *flags* is a combination of
3617+
*
3618+
* **BTF_F_COMPACT**
3619+
* no formatting around type information
3620+
* **BTF_F_NONAME**
3621+
* no struct/union member names/types
3622+
* **BTF_F_PTR_RAW**
3623+
* show raw (unobfuscated) pointer values;
3624+
* equivalent to printk specifier %px.
3625+
* **BTF_F_ZERO**
3626+
* show zero-valued struct/union members; they
3627+
* are not displayed by default
3628+
*
3629+
* Return
3630+
* The number of bytes that were written (or would have been
3631+
* written if output had to be truncated due to string size),
3632+
* or a negative error in cases of failure.
35973633
*/
35983634
#define __BPF_FUNC_MAPPER(FN) \
35993635
FN(unspec), \
@@ -3745,6 +3781,7 @@ union bpf_attr {
37453781
FN(inode_storage_delete), \
37463782
FN(d_path), \
37473783
FN(copy_from_user), \
3784+
FN(snprintf_btf), \
37483785
/* */
37493786

37503787
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
@@ -4853,4 +4890,34 @@ struct bpf_sk_lookup {
48534890
__u32 local_port; /* Host byte order */
48544891
};
48554892

4893+
/*
4894+
* struct btf_ptr is used for typed pointer representation; the
4895+
* type id is used to render the pointer data as the appropriate type
4896+
* via the bpf_snprintf_btf() helper described above. A flags field -
4897+
* potentially to specify additional details about the BTF pointer
4898+
* (rather than its mode of display) - is included for future use.
4899+
* Display flags - BTF_F_* - are passed to bpf_snprintf_btf separately.
4900+
*/
4901+
struct btf_ptr {
4902+
void *ptr;
4903+
__u32 type_id;
4904+
__u32 flags; /* BTF ptr flags; unused at present. */
4905+
};
4906+
4907+
/*
4908+
* Flags to control bpf_snprintf_btf() behaviour.
4909+
* - BTF_F_COMPACT: no formatting around type information
4910+
* - BTF_F_NONAME: no struct/union member names/types
4911+
* - BTF_F_PTR_RAW: show raw (unobfuscated) pointer values;
4912+
* equivalent to %px.
4913+
* - BTF_F_ZERO: show zero-valued struct/union members; they
4914+
* are not displayed by default
4915+
*/
4916+
enum {
4917+
BTF_F_COMPACT = (1ULL << 0),
4918+
BTF_F_NONAME = (1ULL << 1),
4919+
BTF_F_PTR_RAW = (1ULL << 2),
4920+
BTF_F_ZERO = (1ULL << 3),
4921+
};
4922+
48564923
#endif /* _UAPI__LINUX_BPF_H__ */

0 commit comments

Comments
 (0)