Skip to content

Commit 37b1b3e

Browse files
mykyta5anakryiko
authored andcommitted
selftests/bpf: Support struct/union presets in veristat
Extend commit e3c9abd ("selftests/bpf: Implement setting global variables in veristat") to support applying presets to members of the global structs or unions in veristat. For example: ``` ./veristat set_global_vars.bpf.o -G "union1.struct3.var_u8_h = 0xBB" ``` Signed-off-by: Mykyta Yatsenko <[email protected]> Signed-off-by: Andrii Nakryiko <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent c966139 commit 37b1b3e

File tree

4 files changed

+140
-8
lines changed

4 files changed

+140
-8
lines changed

tools/testing/selftests/bpf/prog_tests/test_veristat.c

+5
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ static void test_set_global_vars_succeeds(void)
6363
" -G \"var_eb = EB2\" "\
6464
" -G \"var_ec = EC2\" "\
6565
" -G \"var_b = 1\" "\
66+
" -G \"struct1.struct2.u.var_u8 = 170\" "\
67+
" -G \"union1.struct3.var_u8_l = 0xaa\" "\
68+
" -G \"union1.struct3.var_u8_h = 0xaa\" "\
6669
"-vl2 > %s", fix->veristat, fix->tmpfile);
6770

6871
read(fix->fd, fix->output, fix->sz);
@@ -78,6 +81,8 @@ static void test_set_global_vars_succeeds(void)
7881
__CHECK_STR("_w=12 ", "var_eb = EB2");
7982
__CHECK_STR("_w=13 ", "var_ec = EC2");
8083
__CHECK_STR("_w=1 ", "var_b = 1");
84+
__CHECK_STR("_w=170 ", "struct1.struct2.u.var_u8 = 170");
85+
__CHECK_STR("_w=0xaaaa ", "union1.var_u16 = 0xaaaa");
8186

8287
out:
8388
teardown_fixture(fix);

tools/testing/selftests/bpf/progs/prepare.c

-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
/* Copyright (c) 2025 Meta */
33
#include <vmlinux.h>
44
#include <bpf/bpf_helpers.h>
5-
//#include <bpf/bpf_tracing.h>
65

76
char _license[] SEC("license") = "GPL";
87

tools/testing/selftests/bpf/progs/set_global_vars.c

+41
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,44 @@ const volatile enum Enumu64 var_eb = EB1;
2424
const volatile enum Enums64 var_ec = EC1;
2525
const volatile bool var_b = false;
2626

27+
struct Struct {
28+
int:16;
29+
__u16 filler;
30+
struct {
31+
const __u16 filler2;
32+
};
33+
struct Struct2 {
34+
__u16 filler;
35+
volatile struct {
36+
const int:1;
37+
union {
38+
const volatile __u8 var_u8;
39+
const volatile __s16 filler3;
40+
const int:1;
41+
} u;
42+
};
43+
} struct2;
44+
};
45+
46+
const volatile __u32 stru = 0; /* same prefix as below */
47+
const volatile struct Struct struct1 = {.struct2 = {.u = {.var_u8 = 1}}};
48+
49+
union Union {
50+
__u16 var_u16;
51+
struct Struct3 {
52+
struct {
53+
__u8 var_u8_l;
54+
};
55+
struct {
56+
struct {
57+
__u8 var_u8_h;
58+
};
59+
};
60+
} struct3;
61+
};
62+
63+
const volatile union Union union1 = {.var_u16 = -1};
64+
2765
char arr[4] = {0};
2866

2967
SEC("socket")
@@ -43,5 +81,8 @@ int test_set_globals(void *ctx)
4381
a = var_eb;
4482
a = var_ec;
4583
a = var_b;
84+
a = struct1.struct2.u.var_u8;
85+
a = union1.var_u16;
86+
4687
return a;
4788
}

tools/testing/selftests/bpf/veristat.c

+94-7
Original file line numberDiff line numberDiff line change
@@ -1486,7 +1486,84 @@ static bool is_preset_supported(const struct btf_type *t)
14861486
return btf_is_int(t) || btf_is_enum(t) || btf_is_enum64(t);
14871487
}
14881488

1489-
static int set_global_var(struct bpf_object *obj, struct btf *btf, const struct btf_type *t,
1489+
const int btf_find_member(const struct btf *btf,
1490+
const struct btf_type *parent_type,
1491+
__u32 parent_offset,
1492+
const char *member_name,
1493+
int *member_tid,
1494+
__u32 *member_offset)
1495+
{
1496+
int i;
1497+
1498+
if (!btf_is_composite(parent_type))
1499+
return -EINVAL;
1500+
1501+
for (i = 0; i < btf_vlen(parent_type); ++i) {
1502+
const struct btf_member *member;
1503+
const struct btf_type *member_type;
1504+
int tid;
1505+
1506+
member = btf_members(parent_type) + i;
1507+
tid = btf__resolve_type(btf, member->type);
1508+
if (tid < 0)
1509+
return -EINVAL;
1510+
1511+
member_type = btf__type_by_id(btf, tid);
1512+
if (member->name_off) {
1513+
const char *name = btf__name_by_offset(btf, member->name_off);
1514+
1515+
if (strcmp(member_name, name) == 0) {
1516+
if (btf_member_bitfield_size(parent_type, i) != 0) {
1517+
fprintf(stderr, "Bitfield presets are not supported %s\n",
1518+
name);
1519+
return -EINVAL;
1520+
}
1521+
*member_offset = parent_offset + member->offset;
1522+
*member_tid = tid;
1523+
return 0;
1524+
}
1525+
} else if (btf_is_composite(member_type)) {
1526+
int err;
1527+
1528+
err = btf_find_member(btf, member_type, parent_offset + member->offset,
1529+
member_name, member_tid, member_offset);
1530+
if (!err)
1531+
return 0;
1532+
}
1533+
}
1534+
1535+
return -EINVAL;
1536+
}
1537+
1538+
static int adjust_var_secinfo(struct btf *btf, const struct btf_type *t,
1539+
struct btf_var_secinfo *sinfo, const char *var)
1540+
{
1541+
char expr[256], *saveptr;
1542+
const struct btf_type *base_type, *member_type;
1543+
int err, member_tid;
1544+
char *name;
1545+
__u32 member_offset = 0;
1546+
1547+
base_type = btf__type_by_id(btf, btf__resolve_type(btf, t->type));
1548+
snprintf(expr, sizeof(expr), "%s", var);
1549+
strtok_r(expr, ".", &saveptr);
1550+
1551+
while ((name = strtok_r(NULL, ".", &saveptr))) {
1552+
err = btf_find_member(btf, base_type, 0, name, &member_tid, &member_offset);
1553+
if (err) {
1554+
fprintf(stderr, "Could not find member %s for variable %s\n", name, var);
1555+
return err;
1556+
}
1557+
member_type = btf__type_by_id(btf, member_tid);
1558+
sinfo->offset += member_offset / 8;
1559+
sinfo->size = member_type->size;
1560+
sinfo->type = member_tid;
1561+
base_type = member_type;
1562+
}
1563+
return 0;
1564+
}
1565+
1566+
static int set_global_var(struct bpf_object *obj, struct btf *btf,
14901567
struct bpf_map *map, struct btf_var_secinfo *sinfo,
14911568
struct var_preset *preset)
14921569
{
@@ -1495,9 +1572,9 @@ static int set_global_var(struct bpf_object *obj, struct btf *btf, const struct
14951572
long long value = preset->ivalue;
14961573
size_t size;
14971574

1498-
base_type = btf__type_by_id(btf, btf__resolve_type(btf, t->type));
1575+
base_type = btf__type_by_id(btf, btf__resolve_type(btf, sinfo->type));
14991576
if (!base_type) {
1500-
fprintf(stderr, "Failed to resolve type %d\n", t->type);
1577+
fprintf(stderr, "Failed to resolve type %d\n", sinfo->type);
15011578
return -EINVAL;
15021579
}
15031580
if (!is_preset_supported(base_type)) {
@@ -1530,7 +1607,7 @@ static int set_global_var(struct bpf_object *obj, struct btf *btf, const struct
15301607
if (value >= max_val || value < -max_val) {
15311608
fprintf(stderr,
15321609
"Variable %s value %lld is out of range [%lld; %lld]\n",
1533-
btf__name_by_offset(btf, t->name_off), value,
1610+
btf__name_by_offset(btf, base_type->name_off), value,
15341611
is_signed ? -max_val : 0, max_val - 1);
15351612
return -EINVAL;
15361613
}
@@ -1583,28 +1660,38 @@ static int set_global_vars(struct bpf_object *obj, struct var_preset *presets, i
15831660
for (j = 0; j < n; ++j, ++sinfo) {
15841661
const struct btf_type *var_type = btf__type_by_id(btf, sinfo->type);
15851662
const char *var_name;
1663+
int var_len;
15861664

15871665
if (!btf_is_var(var_type))
15881666
continue;
15891667

15901668
var_name = btf__name_by_offset(btf, var_type->name_off);
1669+
var_len = strlen(var_name);
15911670

15921671
for (k = 0; k < npresets; ++k) {
1593-
if (strcmp(var_name, presets[k].name) != 0)
1672+
struct btf_var_secinfo tmp_sinfo;
1673+
1674+
if (strncmp(var_name, presets[k].name, var_len) != 0 ||
1675+
(presets[k].name[var_len] != '\0' &&
1676+
presets[k].name[var_len] != '.'))
15941677
continue;
15951678

15961679
if (presets[k].applied) {
15971680
fprintf(stderr, "Variable %s is set more than once",
15981681
var_name);
15991682
return -EINVAL;
16001683
}
1684+
tmp_sinfo = *sinfo;
1685+
err = adjust_var_secinfo(btf, var_type,
1686+
&tmp_sinfo, presets[k].name);
1687+
if (err)
1688+
return err;
16011689

1602-
err = set_global_var(obj, btf, var_type, map, sinfo, presets + k);
1690+
err = set_global_var(obj, btf, map, &tmp_sinfo, presets + k);
16031691
if (err)
16041692
return err;
16051693

16061694
presets[k].applied = true;
1607-
break;
16081695
}
16091696
}
16101697
}

0 commit comments

Comments
 (0)