// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2020, Oracle and/or its affiliates. */
#include "btf_ptr.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>
#include "bpf_misc.h"
#include <errno.h>
long ret = 0 ;
int num_subtests = 0 ;
int ran_subtests = 0 ;
bool skip = false ;
#define STRSIZE 2048
#define EXPECTED_STRSIZE 256
#if defined (bpf_target_s390)
/* NULL points to a readable struct lowcore on s390, so take the last page */
#define BADPTR ((void *)0 xFFFFFFFFFFFFF000ULL)
#else
#define BADPTR 0
#endif
struct {
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
__uint(max_entries, 1 );
__type(key, __u32);
__type(value, char [STRSIZE]);
} strdata SEC(".maps" );
static int __strncmp(const void *m1, const void *m2, size_t len)
{
const unsigned char *s1 = m1;
const unsigned char *s2 = m2;
int i, delta = 0 ;
for (i = 0 ; i < len; i++) {
delta = s1[i] - s2[i];
if (delta || s1[i] == 0 || s2[i] == 0 )
break ;
}
return delta;
}
#if __has_builtin(__builtin_btf_type_id)
#define TEST_BTF(_str, _type, _flags, _expected, ...) \
do { \
static const char _expectedval[EXPECTED_STRSIZE] = \
_expected; \
__u64 _hflags = _flags | BTF_F_COMPACT; \
static _type _ptrdata = __VA_ARGS__; \
static struct btf_ptr _ptr = { }; \
int _cmp; \
\
++num_subtests; \
if (ret < 0 ) \
break ; \
++ran_subtests; \
_ptr.ptr = &_ptrdata; \
_ptr.type_id = bpf_core_type_id_kernel(_type); \
if (_ptr.type_id <= 0 ) { \
ret = -EINVAL; \
break ; \
} \
ret = bpf_snprintf_btf(_str, STRSIZE, \
&_ptr, sizeof (_ptr), _hflags); \
if (ret) \
break ; \
_cmp = __strncmp(_str, _expectedval, EXPECTED_STRSIZE); \
if (_cmp != 0 ) { \
bpf_printk("(%d) got %s" , _cmp, _str); \
bpf_printk("(%d) expected %s" , _cmp, \
_expectedval); \
ret = -EBADMSG; \
break ; \
} \
} while (0 )
#endif
/* Use where expected data string matches its stringified declaration */
#define TEST_BTF_C(_str, _type, _flags, ...) \
TEST_BTF(_str, _type, _flags, "(" #_ type ")" #_ _VA_ARGS__, \
__VA_ARGS__)
/* TRACE_EVENT(netif_receive_skb,
* TP_PROTO(struct sk_buff *skb),
*/
SEC("tp_btf/netif_receive_skb" )
int BPF_PROG(trace_netif_receive_skb, struct sk_buff *skb)
{
static __u64 flags[] = { 0 , BTF_F_COMPACT, BTF_F_ZERO, BTF_F_PTR_RAW,
BTF_F_NONAME, BTF_F_COMPACT | BTF_F_ZERO |
BTF_F_PTR_RAW | BTF_F_NONAME };
static struct btf_ptr p = { };
__u32 key = 0 ;
int i, __ret;
char *str;
#if __has_builtin(__builtin_btf_type_id)
str = bpf_map_lookup_elem(&strdata, &key);
if (!str)
return 0 ;
/* Ensure we can write skb string representation */
p.type_id = bpf_core_type_id_kernel(struct sk_buff);
p.ptr = skb;
for (i = 0 ; i < ARRAY_SIZE(flags); i++) {
++num_subtests;
ret = bpf_snprintf_btf(str, STRSIZE, &p, sizeof (p), 0 );
if (ret < 0 )
bpf_printk("returned %d when writing skb" , ret);
++ran_subtests;
}
/* Check invalid ptr value */
p.ptr = BADPTR;
__ret = bpf_snprintf_btf(str, STRSIZE, &p, sizeof (p), 0 );
if (__ret >= 0 ) {
bpf_printk("printing %llx should generate error, got (%d)" ,
(unsigned long long )BADPTR, __ret);
ret = -ERANGE;
}
/* Verify type display for various types. */
/* simple int */
TEST_BTF_C(str, int , 0 , 1234 );
TEST_BTF(str, int , BTF_F_NONAME, "1234" , 1234 );
/* zero value should be printed at toplevel */
TEST_BTF(str, int , 0 , "(int)0" , 0 );
TEST_BTF(str, int , BTF_F_NONAME, "0" , 0 );
TEST_BTF(str, int , BTF_F_ZERO, "(int)0" , 0 );
TEST_BTF(str, int , BTF_F_NONAME | BTF_F_ZERO, "0" , 0 );
TEST_BTF_C(str, int , 0 , -4567 );
TEST_BTF(str, int , BTF_F_NONAME, "-4567" , -4567 );
/* simple char */
TEST_BTF_C(str, char , 0 , 100 );
TEST_BTF(str, char , BTF_F_NONAME, "100" , 100 );
/* zero value should be printed at toplevel */
TEST_BTF(str, char , 0 , "(char)0" , 0 );
TEST_BTF(str, char , BTF_F_NONAME, "0" , 0 );
TEST_BTF(str, char , BTF_F_ZERO, "(char)0" , 0 );
TEST_BTF(str, char , BTF_F_NONAME | BTF_F_ZERO, "0" , 0 );
/* simple typedef */
TEST_BTF_C(str, uint64_t, 0 , 100 );
TEST_BTF(str, u64, BTF_F_NONAME, "1" , 1 );
/* zero value should be printed at toplevel */
TEST_BTF(str, u64, 0 , "(u64)0" , 0 );
TEST_BTF(str, u64, BTF_F_NONAME, "0" , 0 );
TEST_BTF(str, u64, BTF_F_ZERO, "(u64)0" , 0 );
TEST_BTF(str, u64, BTF_F_NONAME|BTF_F_ZERO, "0" , 0 );
/* typedef struct */
TEST_BTF_C(str, atomic_t, 0 , {.counter = (int )1 ,});
TEST_BTF(str, atomic_t, BTF_F_NONAME, "{1,}" , {.counter = 1 ,});
/* typedef with 0 value should be printed at toplevel */
TEST_BTF(str, atomic_t, 0 , "(atomic_t){}" , {.counter = 0 ,});
TEST_BTF(str, atomic_t, BTF_F_NONAME, "{}" , {.counter = 0 ,});
TEST_BTF(str, atomic_t, BTF_F_ZERO, "(atomic_t){.counter = (int)0,}" ,
{.counter = 0 ,});
TEST_BTF(str, atomic_t, BTF_F_NONAME|BTF_F_ZERO,
"{0,}" , {.counter = 0 ,});
/* enum where enum value does (and does not) exist */
TEST_BTF_C(str, enum bpf_cmd, 0 , BPF_MAP_CREATE);
TEST_BTF(str, enum bpf_cmd, 0 , "(enum bpf_cmd)BPF_MAP_CREATE" , 0 );
TEST_BTF(str, enum bpf_cmd, BTF_F_NONAME, "BPF_MAP_CREATE" ,
BPF_MAP_CREATE);
TEST_BTF(str, enum bpf_cmd, BTF_F_NONAME|BTF_F_ZERO,
"BPF_MAP_CREATE" , 0 );
TEST_BTF(str, enum bpf_cmd, BTF_F_ZERO, "(enum bpf_cmd)BPF_MAP_CREATE" ,
BPF_MAP_CREATE);
TEST_BTF(str, enum bpf_cmd, BTF_F_NONAME|BTF_F_ZERO,
"BPF_MAP_CREATE" , BPF_MAP_CREATE);
TEST_BTF_C(str, enum bpf_cmd, 0 , 2000 );
TEST_BTF(str, enum bpf_cmd, BTF_F_NONAME, "2000" , 2000 );
/* simple struct */
TEST_BTF_C(str, struct btf_enum, 0 ,
{.name_off = (__u32)3 ,.val = (__s32)-1 ,});
TEST_BTF(str, struct btf_enum, BTF_F_NONAME, "{3,-1,}" ,
{ .name_off = 3 , .val = -1 ,});
TEST_BTF(str, struct btf_enum, BTF_F_NONAME, "{-1,}" ,
{ .name_off = 0 , .val = -1 ,});
TEST_BTF(str, struct btf_enum, BTF_F_NONAME|BTF_F_ZERO, "{0,-1,}" ,
{ .name_off = 0 , .val = -1 ,});
/* empty struct should be printed */
TEST_BTF(str, struct btf_enum, 0 , "(struct btf_enum){}" ,
{ .name_off = 0 , .val = 0 ,});
TEST_BTF(str, struct btf_enum, BTF_F_NONAME, "{}" ,
{ .name_off = 0 , .val = 0 ,});
TEST_BTF(str, struct btf_enum, BTF_F_ZERO,
"(struct btf_enum){.name_off = (__u32)0,.val = (__s32)0,}" ,
{ .name_off = 0 , .val = 0 ,});
/* struct with pointers */
TEST_BTF(str, struct list_head, BTF_F_PTR_RAW,
"(struct list_head){.next = (struct list_head *)0x0000000000000001,}" ,
{ .next = (struct list_head *)1 });
/* NULL pointer should not be displayed */
TEST_BTF(str, struct list_head, BTF_F_PTR_RAW,
"(struct list_head){}" ,
{ .next = (struct list_head *)0 });
/* struct with char array */
TEST_BTF(str, struct bpf_prog_info, 0 ,
"(struct bpf_prog_info){.name = (char[])['f','o','o',],}" ,
{ .name = "foo" ,});
TEST_BTF(str, struct bpf_prog_info, BTF_F_NONAME,
"{['f','o','o',],}" ,
{.name = "foo" ,});
/* leading null char means do not display string */
TEST_BTF(str, struct bpf_prog_info, 0 ,
"(struct bpf_prog_info){}" ,
{.name = {'\0' , 'f' , 'o' , 'o' }});
/* handle non-printable characters */
TEST_BTF(str, struct bpf_prog_info, 0 ,
"(struct bpf_prog_info){.name = (char[])[1,2,3,],}" ,
{ .name = {1 , 2 , 3 , 0 }});
/* struct with non-char array */
TEST_BTF(str, struct __sk_buff, 0 ,
"(struct __sk_buff){.cb = (__u32[])[1,2,3,4,5,],}" ,
{ .cb = {1 , 2 , 3 , 4 , 5 ,},});
TEST_BTF(str, struct __sk_buff, BTF_F_NONAME,
"{[1,2,3,4,5,],}" ,
{ .cb = { 1 , 2 , 3 , 4 , 5 },});
/* For non-char, arrays, show non-zero values only */
TEST_BTF(str, struct __sk_buff, 0 ,
"(struct __sk_buff){.cb = (__u32[])[1,],}" ,
{ .cb = { 0 , 0 , 1 , 0 , 0 },});
/* struct with bitfields */
TEST_BTF_C(str, struct bpf_insn, 0 ,
{.code = (__u8)1 ,.dst_reg = (__u8)0 x2,.src_reg = (__u8)0 x3,.off = (__s16)4 ,.imm = (__s32)5 ,});
TEST_BTF(str, struct bpf_insn, BTF_F_NONAME, "{1,0x2,0x3,4,5,}" ,
{.code = 1 , .dst_reg = 0 x2, .src_reg = 0 x3, .off = 4 ,
.imm = 5 ,});
#else
skip = true ;
#endif
return 0 ;
}
char _license[] SEC("license" ) = "GPL" ;
Messung V0.5 in Prozent C=96 H=88 G=91
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet am 2026-06-08)
¤
*© Formatika GbR, Deutschland