Skip to content

Commit aa277c3

Browse files
committed
selftests/bpf: support array presets in veristat
Implement support for presetting values for array elements in veristat. For example: ``` sudo ./veristat set_global_vars.bpf.o -G "struct1[2].struct2[1].u.var_u8[2] = 3" -G "arr[3] = 9" ``` Arrays of structures and structure of arrays work, but each individual scalar value has to be set separately: `foo[1].bar[2] = value`. Signed-off-by: Mykyta Yatsenko <[email protected]>
1 parent bb1556e commit aa277c3

File tree

3 files changed

+70
-14
lines changed

3 files changed

+70
-14
lines changed

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,13 @@ static void test_set_global_vars_succeeds(void)
6060
" -G \"var_s8 = -128\" "\
6161
" -G \"var_u8 = 255\" "\
6262
" -G \"var_ea = EA2\" "\
63-
" -G \"var_eb = EB2\" "\
64-
" -G \"var_ec = EC2\" "\
63+
" -G \"var_eb = EB2\" "\
64+
" -G \"var_ec=EC2\" "\
6565
" -G \"var_b = 1\" "\
66-
" -G \"struct1.struct2.u.var_u8 = 170\" "\
66+
" -G \"struct1[2].struct2[1].u.var_u8[2]=170\" "\
6767
" -G \"union1.struct3.var_u8_l = 0xaa\" "\
6868
" -G \"union1.struct3.var_u8_h = 0xaa\" "\
69+
" -G \"arr[2] = 0xaa\" " \
6970
"-vl2 > %s", fix->veristat, fix->tmpfile);
7071

7172
read(fix->fd, fix->output, fix->sz);
@@ -81,7 +82,7 @@ static void test_set_global_vars_succeeds(void)
8182
__CHECK_STR("_w=12 ", "var_eb = EB2");
8283
__CHECK_STR("_w=13 ", "var_ec = EC2");
8384
__CHECK_STR("_w=1 ", "var_b = 1");
84-
__CHECK_STR("_w=170 ", "struct1.struct2.u.var_u8 = 170");
85+
__CHECK_STR("_w=170 ", "struct1.struct2[1].u.var_u8[2] = 170");
8586
__CHECK_STR("_w=0xaaaa ", "union1.var_u16 = 0xaaaa");
8687

8788
out:

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const volatile enum Enum var_ea = EA1;
2323
const volatile enum Enumu64 var_eb = EB1;
2424
const volatile enum Enums64 var_ec = EC1;
2525
const volatile bool var_b = false;
26+
const volatile __s32 arr[5];
2627

2728
struct Struct {
2829
int:16;
@@ -35,16 +36,16 @@ struct Struct {
3536
volatile struct {
3637
const int:1;
3738
union {
38-
const volatile __u8 var_u8;
39+
const volatile __u8 var_u8[3];
3940
const volatile __s16 filler3;
4041
const int:1;
4142
} u;
4243
};
43-
} struct2;
44+
} struct2[2];
4445
};
4546

4647
const volatile __u32 stru = 0; /* same prefix as below */
47-
const volatile struct Struct struct1 = {.struct2 = {.u = {.var_u8 = 1}}};
48+
const volatile struct Struct struct1[3] = {{.struct2 = {{}, {.u = {.var_u8 = {1}}}}}};
4849

4950
union Union {
5051
__u16 var_u16;
@@ -62,8 +63,6 @@ union Union {
6263

6364
const volatile union Union union1 = {.var_u16 = -1};
6465

65-
char arr[4] = {0};
66-
6766
SEC("socket")
6867
int test_set_globals(void *ctx)
6968
{
@@ -81,8 +80,9 @@ int test_set_globals(void *ctx)
8180
a = var_eb;
8281
a = var_ec;
8382
a = var_b;
84-
a = struct1.struct2.u.var_u8;
83+
a = struct1[2].struct2[1].u.var_u8[2];
8584
a = union1.var_u16;
85+
a = arr[3];
8686

8787
return a;
8888
}

tools/testing/selftests/bpf/veristat.c

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1379,7 +1379,7 @@ static int append_var_preset(struct var_preset **presets, int *cnt, const char *
13791379
memset(cur, 0, sizeof(*cur));
13801380
(*cnt)++;
13811381

1382-
if (sscanf(expr, "%s = %s %n", var, val, &n) != 2 || n != strlen(expr)) {
1382+
if (sscanf(expr, "%[][a-zA-Z0-9_.] = %s %n", var, val, &n) != 2 || n != strlen(expr)) {
13831383
fprintf(stderr, "Failed to parse expression '%s'\n", expr);
13841384
return -EINVAL;
13851385
}
@@ -1486,14 +1486,47 @@ 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 adjust_array_secinfo(const struct btf *btf, const struct btf_type *t,
1490+
struct btf_var_secinfo *sinfo, const char *var)
1491+
{
1492+
struct btf_array *barr;
1493+
const struct btf_type *type;
1494+
char arr[64], idx[64];
1495+
int i = 0, tid;
1496+
1497+
if (!btf_is_array(t))
1498+
return 0;
1499+
1500+
barr = btf_array(t);
1501+
tid = btf__resolve_type(btf, barr->type);
1502+
type = btf__type_by_id(btf, tid);
1503+
1504+
/* var may contain chained expression e.g.: foo[1].bar */
1505+
if (sscanf(var, "%[a-zA-Z0-9_][%[a-zA-Z0-9]]", arr, idx) != 2) {
1506+
fprintf(stderr, "Could not parse array expression %s\n", var);
1507+
return -EINVAL;
1508+
}
1509+
errno = 0;
1510+
i = strtol(idx, NULL, 0);
1511+
if (errno || i < 0 || i >= barr->nelems) {
1512+
fprintf(stderr, "Preset index %s is invalid or out of bounds [0, %d]\n",
1513+
idx, barr->nelems);
1514+
return -EINVAL;
1515+
}
1516+
sinfo->size = type->size;
1517+
sinfo->type = tid;
1518+
sinfo->offset += i * type->size;
1519+
return 0;
1520+
}
1521+
14891522
const int btf_find_member(const struct btf *btf,
14901523
const struct btf_type *parent_type,
14911524
__u32 parent_offset,
14921525
const char *member_name,
14931526
int *member_tid,
14941527
__u32 *member_offset)
14951528
{
1496-
int i;
1529+
int i, err;
14971530

14981531
if (!btf_is_composite(parent_type))
14991532
return -EINVAL;
@@ -1511,15 +1544,29 @@ const int btf_find_member(const struct btf *btf,
15111544
member_type = btf__type_by_id(btf, tid);
15121545
if (member->name_off) {
15131546
const char *name = btf__name_by_offset(btf, member->name_off);
1547+
int name_len = strlen(name);
15141548

1515-
if (strcmp(member_name, name) == 0) {
1549+
if (strcmp(member_name, name) == 0 ||
1550+
(btf_is_array(member_type) &&
1551+
strncmp(name, member_name, name_len) == 0 &&
1552+
member_name[name_len] == '[')) {
15161553
if (btf_member_bitfield_size(parent_type, i) != 0) {
15171554
fprintf(stderr, "Bitfield presets are not supported %s\n",
15181555
name);
15191556
return -EINVAL;
15201557
}
15211558
*member_offset = parent_offset + member->offset;
15221559
*member_tid = tid;
1560+
if (btf_is_array(member_type)) {
1561+
struct btf_var_secinfo sinfo = {.offset = 0};
1562+
1563+
err = adjust_array_secinfo(btf, member_type,
1564+
&sinfo, member_name);
1565+
if (err)
1566+
return err;
1567+
*member_tid = sinfo.type;
1568+
*member_offset += sinfo.offset * 8;
1569+
}
15231570
return 0;
15241571
}
15251572
} else if (btf_is_composite(member_type)) {
@@ -1548,6 +1595,13 @@ static int adjust_var_secinfo(struct btf *btf, const struct btf_type *t,
15481595
snprintf(expr, sizeof(expr), "%s", var);
15491596
strtok_r(expr, ".", &saveptr);
15501597

1598+
if (btf_is_array(base_type)) {
1599+
err = adjust_array_secinfo(btf, base_type, sinfo, var);
1600+
if (err)
1601+
return err;
1602+
base_type = btf__type_by_id(btf, sinfo->type);
1603+
}
1604+
15511605
while ((name = strtok_r(NULL, ".", &saveptr))) {
15521606
err = btf_find_member(btf, base_type, 0, name, &member_tid, &member_offset);
15531607
if (err) {
@@ -1673,7 +1727,8 @@ static int set_global_vars(struct bpf_object *obj, struct var_preset *presets, i
16731727

16741728
if (strncmp(var_name, presets[k].name, var_len) != 0 ||
16751729
(presets[k].name[var_len] != '\0' &&
1676-
presets[k].name[var_len] != '.'))
1730+
presets[k].name[var_len] != '.' &&
1731+
presets[k].name[var_len] != '['))
16771732
continue;
16781733

16791734
if (presets[k].applied) {

0 commit comments

Comments
 (0)