xref: /linux/tools/testing/selftests/bpf/prog_tests/btf_permute.c (revision c17ee635fd3a482b2ad2bf5e269755c2eae5f25e)
1*a3acd7d4SDonglin Peng // SPDX-License-Identifier: GPL-2.0
2*a3acd7d4SDonglin Peng /* Copyright (c) 2026 Xiaomi */
3*a3acd7d4SDonglin Peng 
4*a3acd7d4SDonglin Peng #include <test_progs.h>
5*a3acd7d4SDonglin Peng #include <bpf/btf.h>
6*a3acd7d4SDonglin Peng #include "btf_helpers.h"
7*a3acd7d4SDonglin Peng 
8*a3acd7d4SDonglin Peng static void permute_base_check(struct btf *btf)
9*a3acd7d4SDonglin Peng {
10*a3acd7d4SDonglin Peng 	VALIDATE_RAW_BTF(
11*a3acd7d4SDonglin Peng 		btf,
12*a3acd7d4SDonglin Peng 		"[1] STRUCT 's2' size=4 vlen=1\n"
13*a3acd7d4SDonglin Peng 		"\t'm' type_id=4 bits_offset=0",
14*a3acd7d4SDonglin Peng 		"[2] FUNC 'f' type_id=6 linkage=static",
15*a3acd7d4SDonglin Peng 		"[3] PTR '(anon)' type_id=4",
16*a3acd7d4SDonglin Peng 		"[4] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
17*a3acd7d4SDonglin Peng 		"[5] STRUCT 's1' size=4 vlen=1\n"
18*a3acd7d4SDonglin Peng 		"\t'm' type_id=4 bits_offset=0",
19*a3acd7d4SDonglin Peng 		"[6] FUNC_PROTO '(anon)' ret_type_id=4 vlen=1\n"
20*a3acd7d4SDonglin Peng 		"\t'p' type_id=3");
21*a3acd7d4SDonglin Peng }
22*a3acd7d4SDonglin Peng 
23*a3acd7d4SDonglin Peng /* Ensure btf__permute works as expected in the base-BTF scenario */
24*a3acd7d4SDonglin Peng static void test_permute_base(void)
25*a3acd7d4SDonglin Peng {
26*a3acd7d4SDonglin Peng 	struct btf *btf;
27*a3acd7d4SDonglin Peng 	__u32 permute_ids[7];
28*a3acd7d4SDonglin Peng 	int err;
29*a3acd7d4SDonglin Peng 
30*a3acd7d4SDonglin Peng 	btf = btf__new_empty();
31*a3acd7d4SDonglin Peng 	if (!ASSERT_OK_PTR(btf, "empty_main_btf"))
32*a3acd7d4SDonglin Peng 		return;
33*a3acd7d4SDonglin Peng 
34*a3acd7d4SDonglin Peng 	btf__add_int(btf, "int", 4, BTF_INT_SIGNED);	/* [1] int */
35*a3acd7d4SDonglin Peng 	btf__add_ptr(btf, 1);				/* [2] ptr to int */
36*a3acd7d4SDonglin Peng 	btf__add_struct(btf, "s1", 4);			/* [3] struct s1 { */
37*a3acd7d4SDonglin Peng 	btf__add_field(btf, "m", 1, 0, 0);		/*       int m; */
38*a3acd7d4SDonglin Peng 							/* } */
39*a3acd7d4SDonglin Peng 	btf__add_struct(btf, "s2", 4);			/* [4] struct s2 { */
40*a3acd7d4SDonglin Peng 	btf__add_field(btf, "m", 1, 0, 0);		/*       int m; */
41*a3acd7d4SDonglin Peng 							/* } */
42*a3acd7d4SDonglin Peng 	btf__add_func_proto(btf, 1);			/* [5] int (*)(int *p); */
43*a3acd7d4SDonglin Peng 	btf__add_func_param(btf, "p", 2);
44*a3acd7d4SDonglin Peng 	btf__add_func(btf, "f", BTF_FUNC_STATIC, 5);	/* [6] int f(int *p); */
45*a3acd7d4SDonglin Peng 
46*a3acd7d4SDonglin Peng 	VALIDATE_RAW_BTF(
47*a3acd7d4SDonglin Peng 		btf,
48*a3acd7d4SDonglin Peng 		"[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
49*a3acd7d4SDonglin Peng 		"[2] PTR '(anon)' type_id=1",
50*a3acd7d4SDonglin Peng 		"[3] STRUCT 's1' size=4 vlen=1\n"
51*a3acd7d4SDonglin Peng 		"\t'm' type_id=1 bits_offset=0",
52*a3acd7d4SDonglin Peng 		"[4] STRUCT 's2' size=4 vlen=1\n"
53*a3acd7d4SDonglin Peng 		"\t'm' type_id=1 bits_offset=0",
54*a3acd7d4SDonglin Peng 		"[5] FUNC_PROTO '(anon)' ret_type_id=1 vlen=1\n"
55*a3acd7d4SDonglin Peng 		"\t'p' type_id=2",
56*a3acd7d4SDonglin Peng 		"[6] FUNC 'f' type_id=5 linkage=static");
57*a3acd7d4SDonglin Peng 
58*a3acd7d4SDonglin Peng 	permute_ids[0] = 0; /* [0] -> [0] */
59*a3acd7d4SDonglin Peng 	permute_ids[1] = 4; /* [1] -> [4] */
60*a3acd7d4SDonglin Peng 	permute_ids[2] = 3; /* [2] -> [3] */
61*a3acd7d4SDonglin Peng 	permute_ids[3] = 5; /* [3] -> [5] */
62*a3acd7d4SDonglin Peng 	permute_ids[4] = 1; /* [4] -> [1] */
63*a3acd7d4SDonglin Peng 	permute_ids[5] = 6; /* [5] -> [6] */
64*a3acd7d4SDonglin Peng 	permute_ids[6] = 2; /* [6] -> [2] */
65*a3acd7d4SDonglin Peng 	err = btf__permute(btf, permute_ids, ARRAY_SIZE(permute_ids), NULL);
66*a3acd7d4SDonglin Peng 	if (!ASSERT_OK(err, "btf__permute_base"))
67*a3acd7d4SDonglin Peng 		goto done;
68*a3acd7d4SDonglin Peng 	permute_base_check(btf);
69*a3acd7d4SDonglin Peng 
70*a3acd7d4SDonglin Peng 	/* ids[0] must be 0 for base BTF */
71*a3acd7d4SDonglin Peng 	permute_ids[0] = 4; /* [0] -> [0] */
72*a3acd7d4SDonglin Peng 	permute_ids[1] = 0; /* [1] -> [4] */
73*a3acd7d4SDonglin Peng 	permute_ids[2] = 3; /* [2] -> [3] */
74*a3acd7d4SDonglin Peng 	permute_ids[3] = 5; /* [3] -> [5] */
75*a3acd7d4SDonglin Peng 	permute_ids[4] = 1; /* [4] -> [1] */
76*a3acd7d4SDonglin Peng 	permute_ids[5] = 6; /* [5] -> [6] */
77*a3acd7d4SDonglin Peng 	permute_ids[6] = 2; /* [6] -> [2] */
78*a3acd7d4SDonglin Peng 	err = btf__permute(btf, permute_ids, ARRAY_SIZE(permute_ids), NULL);
79*a3acd7d4SDonglin Peng 	if (!ASSERT_ERR(err, "btf__permute_base"))
80*a3acd7d4SDonglin Peng 		goto done;
81*a3acd7d4SDonglin Peng 	/* BTF is not modified */
82*a3acd7d4SDonglin Peng 	permute_base_check(btf);
83*a3acd7d4SDonglin Peng 
84*a3acd7d4SDonglin Peng 	/* id_map_cnt is invalid */
85*a3acd7d4SDonglin Peng 	permute_ids[0] = 0; /* [0] -> [0] */
86*a3acd7d4SDonglin Peng 	permute_ids[1] = 4; /* [1] -> [4] */
87*a3acd7d4SDonglin Peng 	permute_ids[2] = 3; /* [2] -> [3] */
88*a3acd7d4SDonglin Peng 	permute_ids[3] = 5; /* [3] -> [5] */
89*a3acd7d4SDonglin Peng 	permute_ids[4] = 1; /* [4] -> [1] */
90*a3acd7d4SDonglin Peng 	permute_ids[5] = 6; /* [5] -> [6] */
91*a3acd7d4SDonglin Peng 	permute_ids[6] = 2; /* [6] -> [2] */
92*a3acd7d4SDonglin Peng 	err = btf__permute(btf, permute_ids, ARRAY_SIZE(permute_ids) - 1, NULL);
93*a3acd7d4SDonglin Peng 	if (!ASSERT_ERR(err, "btf__permute_base"))
94*a3acd7d4SDonglin Peng 		goto done;
95*a3acd7d4SDonglin Peng 	/* BTF is not modified */
96*a3acd7d4SDonglin Peng 	permute_base_check(btf);
97*a3acd7d4SDonglin Peng 
98*a3acd7d4SDonglin Peng 	/* Multiple types can not be mapped to the same ID */
99*a3acd7d4SDonglin Peng 	permute_ids[0] = 0;
100*a3acd7d4SDonglin Peng 	permute_ids[1] = 4;
101*a3acd7d4SDonglin Peng 	permute_ids[2] = 4;
102*a3acd7d4SDonglin Peng 	permute_ids[3] = 5;
103*a3acd7d4SDonglin Peng 	permute_ids[4] = 1;
104*a3acd7d4SDonglin Peng 	permute_ids[5] = 6;
105*a3acd7d4SDonglin Peng 	permute_ids[6] = 2;
106*a3acd7d4SDonglin Peng 	err = btf__permute(btf, permute_ids, ARRAY_SIZE(permute_ids), NULL);
107*a3acd7d4SDonglin Peng 	if (!ASSERT_ERR(err, "btf__permute_base"))
108*a3acd7d4SDonglin Peng 		goto done;
109*a3acd7d4SDonglin Peng 	/* BTF is not modified */
110*a3acd7d4SDonglin Peng 	permute_base_check(btf);
111*a3acd7d4SDonglin Peng 
112*a3acd7d4SDonglin Peng 	/* Type ID must be valid */
113*a3acd7d4SDonglin Peng 	permute_ids[0] = 0;
114*a3acd7d4SDonglin Peng 	permute_ids[1] = 4;
115*a3acd7d4SDonglin Peng 	permute_ids[2] = 3;
116*a3acd7d4SDonglin Peng 	permute_ids[3] = 5;
117*a3acd7d4SDonglin Peng 	permute_ids[4] = 1;
118*a3acd7d4SDonglin Peng 	permute_ids[5] = 7;
119*a3acd7d4SDonglin Peng 	permute_ids[6] = 2;
120*a3acd7d4SDonglin Peng 	err = btf__permute(btf, permute_ids, ARRAY_SIZE(permute_ids), NULL);
121*a3acd7d4SDonglin Peng 	if (!ASSERT_ERR(err, "btf__permute_base"))
122*a3acd7d4SDonglin Peng 		goto done;
123*a3acd7d4SDonglin Peng 	/* BTF is not modified */
124*a3acd7d4SDonglin Peng 	permute_base_check(btf);
125*a3acd7d4SDonglin Peng 
126*a3acd7d4SDonglin Peng done:
127*a3acd7d4SDonglin Peng 	btf__free(btf);
128*a3acd7d4SDonglin Peng }
129*a3acd7d4SDonglin Peng 
130*a3acd7d4SDonglin Peng static void permute_split_check(struct btf *btf)
131*a3acd7d4SDonglin Peng {
132*a3acd7d4SDonglin Peng 	VALIDATE_RAW_BTF(
133*a3acd7d4SDonglin Peng 		btf,
134*a3acd7d4SDonglin Peng 		"[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
135*a3acd7d4SDonglin Peng 		"[2] PTR '(anon)' type_id=1",
136*a3acd7d4SDonglin Peng 		"[3] STRUCT 's2' size=4 vlen=1\n"
137*a3acd7d4SDonglin Peng 		"\t'm' type_id=1 bits_offset=0",
138*a3acd7d4SDonglin Peng 		"[4] FUNC 'f' type_id=5 linkage=static",
139*a3acd7d4SDonglin Peng 		"[5] FUNC_PROTO '(anon)' ret_type_id=1 vlen=1\n"
140*a3acd7d4SDonglin Peng 		"\t'p' type_id=2",
141*a3acd7d4SDonglin Peng 		"[6] STRUCT 's1' size=4 vlen=1\n"
142*a3acd7d4SDonglin Peng 		"\t'm' type_id=1 bits_offset=0");
143*a3acd7d4SDonglin Peng }
144*a3acd7d4SDonglin Peng 
145*a3acd7d4SDonglin Peng /* Ensure btf__permute works as expected in the split-BTF scenario */
146*a3acd7d4SDonglin Peng static void test_permute_split(void)
147*a3acd7d4SDonglin Peng {
148*a3acd7d4SDonglin Peng 	struct btf *split_btf = NULL, *base_btf = NULL;
149*a3acd7d4SDonglin Peng 	__u32 permute_ids[4];
150*a3acd7d4SDonglin Peng 	int err, start_id;
151*a3acd7d4SDonglin Peng 
152*a3acd7d4SDonglin Peng 	base_btf = btf__new_empty();
153*a3acd7d4SDonglin Peng 	if (!ASSERT_OK_PTR(base_btf, "empty_main_btf"))
154*a3acd7d4SDonglin Peng 		return;
155*a3acd7d4SDonglin Peng 
156*a3acd7d4SDonglin Peng 	btf__add_int(base_btf, "int", 4, BTF_INT_SIGNED);	/* [1] int */
157*a3acd7d4SDonglin Peng 	btf__add_ptr(base_btf, 1);				/* [2] ptr to int */
158*a3acd7d4SDonglin Peng 	VALIDATE_RAW_BTF(
159*a3acd7d4SDonglin Peng 		base_btf,
160*a3acd7d4SDonglin Peng 		"[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
161*a3acd7d4SDonglin Peng 		"[2] PTR '(anon)' type_id=1");
162*a3acd7d4SDonglin Peng 	split_btf = btf__new_empty_split(base_btf);
163*a3acd7d4SDonglin Peng 	if (!ASSERT_OK_PTR(split_btf, "empty_split_btf"))
164*a3acd7d4SDonglin Peng 		goto cleanup;
165*a3acd7d4SDonglin Peng 	btf__add_struct(split_btf, "s1", 4);			/* [3] struct s1 { */
166*a3acd7d4SDonglin Peng 	btf__add_field(split_btf, "m", 1, 0, 0);		/*   int m; */
167*a3acd7d4SDonglin Peng 								/* } */
168*a3acd7d4SDonglin Peng 	btf__add_struct(split_btf, "s2", 4);			/* [4] struct s2 { */
169*a3acd7d4SDonglin Peng 	btf__add_field(split_btf, "m", 1, 0, 0);		/*   int m; */
170*a3acd7d4SDonglin Peng 								/* } */
171*a3acd7d4SDonglin Peng 	btf__add_func_proto(split_btf, 1);			/* [5] int (*)(int p); */
172*a3acd7d4SDonglin Peng 	btf__add_func_param(split_btf, "p", 2);
173*a3acd7d4SDonglin Peng 	btf__add_func(split_btf, "f", BTF_FUNC_STATIC, 5);	/* [6] int f(int *p); */
174*a3acd7d4SDonglin Peng 
175*a3acd7d4SDonglin Peng 	VALIDATE_RAW_BTF(
176*a3acd7d4SDonglin Peng 		split_btf,
177*a3acd7d4SDonglin Peng 		"[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
178*a3acd7d4SDonglin Peng 		"[2] PTR '(anon)' type_id=1",
179*a3acd7d4SDonglin Peng 		"[3] STRUCT 's1' size=4 vlen=1\n"
180*a3acd7d4SDonglin Peng 		"\t'm' type_id=1 bits_offset=0",
181*a3acd7d4SDonglin Peng 		"[4] STRUCT 's2' size=4 vlen=1\n"
182*a3acd7d4SDonglin Peng 		"\t'm' type_id=1 bits_offset=0",
183*a3acd7d4SDonglin Peng 		"[5] FUNC_PROTO '(anon)' ret_type_id=1 vlen=1\n"
184*a3acd7d4SDonglin Peng 		"\t'p' type_id=2",
185*a3acd7d4SDonglin Peng 		"[6] FUNC 'f' type_id=5 linkage=static");
186*a3acd7d4SDonglin Peng 
187*a3acd7d4SDonglin Peng 	start_id = btf__type_cnt(base_btf);
188*a3acd7d4SDonglin Peng 	permute_ids[3 - start_id] = 6; /* [3] -> [6] */
189*a3acd7d4SDonglin Peng 	permute_ids[4 - start_id] = 3; /* [4] -> [3] */
190*a3acd7d4SDonglin Peng 	permute_ids[5 - start_id] = 5; /* [5] -> [5] */
191*a3acd7d4SDonglin Peng 	permute_ids[6 - start_id] = 4; /* [6] -> [4] */
192*a3acd7d4SDonglin Peng 	err = btf__permute(split_btf, permute_ids, ARRAY_SIZE(permute_ids), NULL);
193*a3acd7d4SDonglin Peng 	if (!ASSERT_OK(err, "btf__permute_split"))
194*a3acd7d4SDonglin Peng 		goto cleanup;
195*a3acd7d4SDonglin Peng 	permute_split_check(split_btf);
196*a3acd7d4SDonglin Peng 
197*a3acd7d4SDonglin Peng 	/*
198*a3acd7d4SDonglin Peng 	 * For split BTF, id_map_cnt must equal to the number of types
199*a3acd7d4SDonglin Peng 	 * added on top of base BTF
200*a3acd7d4SDonglin Peng 	 */
201*a3acd7d4SDonglin Peng 	permute_ids[3 - start_id] = 4;
202*a3acd7d4SDonglin Peng 	permute_ids[4 - start_id] = 3;
203*a3acd7d4SDonglin Peng 	permute_ids[5 - start_id] = 5;
204*a3acd7d4SDonglin Peng 	permute_ids[6 - start_id] = 6;
205*a3acd7d4SDonglin Peng 	err = btf__permute(split_btf, permute_ids, ARRAY_SIZE(permute_ids) - 1, NULL);
206*a3acd7d4SDonglin Peng 	if (!ASSERT_ERR(err, "btf__permute_split"))
207*a3acd7d4SDonglin Peng 		goto cleanup;
208*a3acd7d4SDonglin Peng 	/* BTF is not modified */
209*a3acd7d4SDonglin Peng 	permute_split_check(split_btf);
210*a3acd7d4SDonglin Peng 
211*a3acd7d4SDonglin Peng 	/* Multiple types can not be mapped to the same ID */
212*a3acd7d4SDonglin Peng 	permute_ids[3 - start_id] = 4;
213*a3acd7d4SDonglin Peng 	permute_ids[4 - start_id] = 3;
214*a3acd7d4SDonglin Peng 	permute_ids[5 - start_id] = 3;
215*a3acd7d4SDonglin Peng 	permute_ids[6 - start_id] = 6;
216*a3acd7d4SDonglin Peng 	err = btf__permute(split_btf, permute_ids, ARRAY_SIZE(permute_ids), NULL);
217*a3acd7d4SDonglin Peng 	if (!ASSERT_ERR(err, "btf__permute_split"))
218*a3acd7d4SDonglin Peng 		goto cleanup;
219*a3acd7d4SDonglin Peng 	/* BTF is not modified */
220*a3acd7d4SDonglin Peng 	permute_split_check(split_btf);
221*a3acd7d4SDonglin Peng 
222*a3acd7d4SDonglin Peng 	/* Can not map to base ID */
223*a3acd7d4SDonglin Peng 	permute_ids[3 - start_id] = 4;
224*a3acd7d4SDonglin Peng 	permute_ids[4 - start_id] = 2;
225*a3acd7d4SDonglin Peng 	permute_ids[5 - start_id] = 5;
226*a3acd7d4SDonglin Peng 	permute_ids[6 - start_id] = 6;
227*a3acd7d4SDonglin Peng 	err = btf__permute(split_btf, permute_ids, ARRAY_SIZE(permute_ids), NULL);
228*a3acd7d4SDonglin Peng 	if (!ASSERT_ERR(err, "btf__permute_split"))
229*a3acd7d4SDonglin Peng 		goto cleanup;
230*a3acd7d4SDonglin Peng 	/* BTF is not modified */
231*a3acd7d4SDonglin Peng 	permute_split_check(split_btf);
232*a3acd7d4SDonglin Peng 
233*a3acd7d4SDonglin Peng cleanup:
234*a3acd7d4SDonglin Peng 	btf__free(split_btf);
235*a3acd7d4SDonglin Peng 	btf__free(base_btf);
236*a3acd7d4SDonglin Peng }
237*a3acd7d4SDonglin Peng 
238*a3acd7d4SDonglin Peng void test_btf_permute(void)
239*a3acd7d4SDonglin Peng {
240*a3acd7d4SDonglin Peng 	if (test__start_subtest("permute_base"))
241*a3acd7d4SDonglin Peng 		test_permute_base();
242*a3acd7d4SDonglin Peng 	if (test__start_subtest("permute_split"))
243*a3acd7d4SDonglin Peng 		test_permute_split();
244*a3acd7d4SDonglin Peng }
245