xref: /linux/tools/testing/selftests/bpf/prog_tests/btf_dedup_split.c (revision a1c3be890440a1769ed6f822376a3e3ab0d42994)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2020 Facebook */
3 #include <test_progs.h>
4 #include <bpf/btf.h>
5 #include "btf_helpers.h"
6 
7 static void test_split_simple() {
8 	const struct btf_type *t;
9 	struct btf *btf1, *btf2;
10 	int str_off, err;
11 
12 	btf1 = btf__new_empty();
13 	if (!ASSERT_OK_PTR(btf1, "empty_main_btf"))
14 		return;
15 
16 	btf__set_pointer_size(btf1, 8); /* enforce 64-bit arch */
17 
18 	btf__add_int(btf1, "int", 4, BTF_INT_SIGNED);	/* [1] int */
19 	btf__add_ptr(btf1, 1);				/* [2] ptr to int */
20 	btf__add_struct(btf1, "s1", 4);			/* [3] struct s1 { */
21 	btf__add_field(btf1, "f1", 1, 0, 0);		/*      int f1; */
22 							/* } */
23 
24 	VALIDATE_RAW_BTF(
25 		btf1,
26 		"[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
27 		"[2] PTR '(anon)' type_id=1",
28 		"[3] STRUCT 's1' size=4 vlen=1\n"
29 		"\t'f1' type_id=1 bits_offset=0");
30 
31 	ASSERT_STREQ(btf_type_c_dump(btf1), "\
32 struct s1 {\n\
33 	int f1;\n\
34 };\n\n", "c_dump");
35 
36 	btf2 = btf__new_empty_split(btf1);
37 	if (!ASSERT_OK_PTR(btf2, "empty_split_btf"))
38 		goto cleanup;
39 
40 	/* pointer size should be "inherited" from main BTF */
41 	ASSERT_EQ(btf__pointer_size(btf2), 8, "inherit_ptr_sz");
42 
43 	str_off = btf__find_str(btf2, "int");
44 	ASSERT_NEQ(str_off, -ENOENT, "str_int_missing");
45 
46 	t = btf__type_by_id(btf2, 1);
47 	if (!ASSERT_OK_PTR(t, "int_type"))
48 		goto cleanup;
49 	ASSERT_EQ(btf_is_int(t), true, "int_kind");
50 	ASSERT_STREQ(btf__str_by_offset(btf2, t->name_off), "int", "int_name");
51 
52 	btf__add_struct(btf2, "s2", 16);		/* [4] struct s2 {	*/
53 	btf__add_field(btf2, "f1", 6, 0, 0);		/*      struct s1 f1;	*/
54 	btf__add_field(btf2, "f2", 5, 32, 0);		/*      int f2;		*/
55 	btf__add_field(btf2, "f3", 2, 64, 0);		/*      int *f3;	*/
56 							/* } */
57 
58 	/* duplicated int */
59 	btf__add_int(btf2, "int", 4, BTF_INT_SIGNED);	/* [5] int */
60 
61 	/* duplicated struct s1 */
62 	btf__add_struct(btf2, "s1", 4);			/* [6] struct s1 { */
63 	btf__add_field(btf2, "f1", 5, 0, 0);		/*      int f1; */
64 							/* } */
65 
66 	VALIDATE_RAW_BTF(
67 		btf2,
68 		"[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
69 		"[2] PTR '(anon)' type_id=1",
70 		"[3] STRUCT 's1' size=4 vlen=1\n"
71 		"\t'f1' type_id=1 bits_offset=0",
72 		"[4] STRUCT 's2' size=16 vlen=3\n"
73 		"\t'f1' type_id=6 bits_offset=0\n"
74 		"\t'f2' type_id=5 bits_offset=32\n"
75 		"\t'f3' type_id=2 bits_offset=64",
76 		"[5] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
77 		"[6] STRUCT 's1' size=4 vlen=1\n"
78 		"\t'f1' type_id=5 bits_offset=0");
79 
80 	ASSERT_STREQ(btf_type_c_dump(btf2), "\
81 struct s1 {\n\
82 	int f1;\n\
83 };\n\
84 \n\
85 struct s1___2 {\n\
86 	int f1;\n\
87 };\n\
88 \n\
89 struct s2 {\n\
90 	struct s1___2 f1;\n\
91 	int f2;\n\
92 	int *f3;\n\
93 };\n\n", "c_dump");
94 
95 	err = btf__dedup(btf2, NULL, NULL);
96 	if (!ASSERT_OK(err, "btf_dedup"))
97 		goto cleanup;
98 
99 	VALIDATE_RAW_BTF(
100 		btf2,
101 		"[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
102 		"[2] PTR '(anon)' type_id=1",
103 		"[3] STRUCT 's1' size=4 vlen=1\n"
104 		"\t'f1' type_id=1 bits_offset=0",
105 		"[4] STRUCT 's2' size=16 vlen=3\n"
106 		"\t'f1' type_id=3 bits_offset=0\n"
107 		"\t'f2' type_id=1 bits_offset=32\n"
108 		"\t'f3' type_id=2 bits_offset=64");
109 
110 	ASSERT_STREQ(btf_type_c_dump(btf2), "\
111 struct s1 {\n\
112 	int f1;\n\
113 };\n\
114 \n\
115 struct s2 {\n\
116 	struct s1 f1;\n\
117 	int f2;\n\
118 	int *f3;\n\
119 };\n\n", "c_dump");
120 
121 cleanup:
122 	btf__free(btf2);
123 	btf__free(btf1);
124 }
125 
126 static void test_split_fwd_resolve() {
127 	struct btf *btf1, *btf2;
128 	int err;
129 
130 	btf1 = btf__new_empty();
131 	if (!ASSERT_OK_PTR(btf1, "empty_main_btf"))
132 		return;
133 
134 	btf__set_pointer_size(btf1, 8); /* enforce 64-bit arch */
135 
136 	btf__add_int(btf1, "int", 4, BTF_INT_SIGNED);	/* [1] int */
137 	btf__add_ptr(btf1, 4);				/* [2] ptr to struct s1 */
138 	btf__add_ptr(btf1, 5);				/* [3] ptr to struct s2 */
139 	btf__add_struct(btf1, "s1", 16);		/* [4] struct s1 { */
140 	btf__add_field(btf1, "f1", 2, 0, 0);		/*      struct s1 *f1; */
141 	btf__add_field(btf1, "f2", 3, 64, 0);		/*      struct s2 *f2; */
142 							/* } */
143 	btf__add_struct(btf1, "s2", 4);			/* [5] struct s2 { */
144 	btf__add_field(btf1, "f1", 1, 0, 0);		/*      int f1; */
145 							/* } */
146 
147 	VALIDATE_RAW_BTF(
148 		btf1,
149 		"[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
150 		"[2] PTR '(anon)' type_id=4",
151 		"[3] PTR '(anon)' type_id=5",
152 		"[4] STRUCT 's1' size=16 vlen=2\n"
153 		"\t'f1' type_id=2 bits_offset=0\n"
154 		"\t'f2' type_id=3 bits_offset=64",
155 		"[5] STRUCT 's2' size=4 vlen=1\n"
156 		"\t'f1' type_id=1 bits_offset=0");
157 
158 	btf2 = btf__new_empty_split(btf1);
159 	if (!ASSERT_OK_PTR(btf2, "empty_split_btf"))
160 		goto cleanup;
161 
162 	btf__add_int(btf2, "int", 4, BTF_INT_SIGNED);	/* [6] int */
163 	btf__add_ptr(btf2, 10);				/* [7] ptr to struct s1 */
164 	btf__add_fwd(btf2, "s2", BTF_FWD_STRUCT);	/* [8] fwd for struct s2 */
165 	btf__add_ptr(btf2, 8);				/* [9] ptr to fwd struct s2 */
166 	btf__add_struct(btf2, "s1", 16);		/* [10] struct s1 { */
167 	btf__add_field(btf2, "f1", 7, 0, 0);		/*      struct s1 *f1; */
168 	btf__add_field(btf2, "f2", 9, 64, 0);		/*      struct s2 *f2; */
169 							/* } */
170 
171 	VALIDATE_RAW_BTF(
172 		btf2,
173 		"[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
174 		"[2] PTR '(anon)' type_id=4",
175 		"[3] PTR '(anon)' type_id=5",
176 		"[4] STRUCT 's1' size=16 vlen=2\n"
177 		"\t'f1' type_id=2 bits_offset=0\n"
178 		"\t'f2' type_id=3 bits_offset=64",
179 		"[5] STRUCT 's2' size=4 vlen=1\n"
180 		"\t'f1' type_id=1 bits_offset=0",
181 		"[6] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
182 		"[7] PTR '(anon)' type_id=10",
183 		"[8] FWD 's2' fwd_kind=struct",
184 		"[9] PTR '(anon)' type_id=8",
185 		"[10] STRUCT 's1' size=16 vlen=2\n"
186 		"\t'f1' type_id=7 bits_offset=0\n"
187 		"\t'f2' type_id=9 bits_offset=64");
188 
189 	err = btf__dedup(btf2, NULL, NULL);
190 	if (!ASSERT_OK(err, "btf_dedup"))
191 		goto cleanup;
192 
193 	VALIDATE_RAW_BTF(
194 		btf2,
195 		"[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
196 		"[2] PTR '(anon)' type_id=4",
197 		"[3] PTR '(anon)' type_id=5",
198 		"[4] STRUCT 's1' size=16 vlen=2\n"
199 		"\t'f1' type_id=2 bits_offset=0\n"
200 		"\t'f2' type_id=3 bits_offset=64",
201 		"[5] STRUCT 's2' size=4 vlen=1\n"
202 		"\t'f1' type_id=1 bits_offset=0");
203 
204 cleanup:
205 	btf__free(btf2);
206 	btf__free(btf1);
207 }
208 
209 static void test_split_struct_duped() {
210 	struct btf *btf1, *btf2;
211 	int err;
212 
213 	btf1 = btf__new_empty();
214 	if (!ASSERT_OK_PTR(btf1, "empty_main_btf"))
215 		return;
216 
217 	btf__set_pointer_size(btf1, 8); /* enforce 64-bit arch */
218 
219 	btf__add_int(btf1, "int", 4, BTF_INT_SIGNED);	/* [1] int */
220 	btf__add_ptr(btf1, 5);				/* [2] ptr to struct s1 */
221 	btf__add_fwd(btf1, "s2", BTF_FWD_STRUCT);	/* [3] fwd for struct s2 */
222 	btf__add_ptr(btf1, 3);				/* [4] ptr to fwd struct s2 */
223 	btf__add_struct(btf1, "s1", 16);		/* [5] struct s1 { */
224 	btf__add_field(btf1, "f1", 2, 0, 0);		/*      struct s1 *f1; */
225 	btf__add_field(btf1, "f2", 4, 64, 0);		/*      struct s2 *f2; */
226 							/* } */
227 
228 	VALIDATE_RAW_BTF(
229 		btf1,
230 		"[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
231 		"[2] PTR '(anon)' type_id=5",
232 		"[3] FWD 's2' fwd_kind=struct",
233 		"[4] PTR '(anon)' type_id=3",
234 		"[5] STRUCT 's1' size=16 vlen=2\n"
235 		"\t'f1' type_id=2 bits_offset=0\n"
236 		"\t'f2' type_id=4 bits_offset=64");
237 
238 	btf2 = btf__new_empty_split(btf1);
239 	if (!ASSERT_OK_PTR(btf2, "empty_split_btf"))
240 		goto cleanup;
241 
242 	btf__add_int(btf2, "int", 4, BTF_INT_SIGNED);	/* [6] int */
243 	btf__add_ptr(btf2, 10);				/* [7] ptr to struct s1 */
244 	btf__add_fwd(btf2, "s2", BTF_FWD_STRUCT);	/* [8] fwd for struct s2 */
245 	btf__add_ptr(btf2, 11);				/* [9] ptr to struct s2 */
246 	btf__add_struct(btf2, "s1", 16);		/* [10] struct s1 { */
247 	btf__add_field(btf2, "f1", 7, 0, 0);		/*      struct s1 *f1; */
248 	btf__add_field(btf2, "f2", 9, 64, 0);		/*      struct s2 *f2; */
249 							/* } */
250 	btf__add_struct(btf2, "s2", 40);		/* [11] struct s2 {	*/
251 	btf__add_field(btf2, "f1", 7, 0, 0);		/*      struct s1 *f1;	*/
252 	btf__add_field(btf2, "f2", 9, 64, 0);		/*      struct s2 *f2;	*/
253 	btf__add_field(btf2, "f3", 6, 128, 0);		/*      int f3;		*/
254 	btf__add_field(btf2, "f4", 10, 192, 0);		/*      struct s1 f4;	*/
255 							/* } */
256 	btf__add_ptr(btf2, 8);				/* [12] ptr to fwd struct s2 */
257 	btf__add_struct(btf2, "s3", 8);			/* [13] struct s3 { */
258 	btf__add_field(btf2, "f1", 12, 0, 0);		/*      struct s2 *f1; (fwd) */
259 							/* } */
260 
261 	VALIDATE_RAW_BTF(
262 		btf2,
263 		"[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
264 		"[2] PTR '(anon)' type_id=5",
265 		"[3] FWD 's2' fwd_kind=struct",
266 		"[4] PTR '(anon)' type_id=3",
267 		"[5] STRUCT 's1' size=16 vlen=2\n"
268 		"\t'f1' type_id=2 bits_offset=0\n"
269 		"\t'f2' type_id=4 bits_offset=64",
270 		"[6] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
271 		"[7] PTR '(anon)' type_id=10",
272 		"[8] FWD 's2' fwd_kind=struct",
273 		"[9] PTR '(anon)' type_id=11",
274 		"[10] STRUCT 's1' size=16 vlen=2\n"
275 		"\t'f1' type_id=7 bits_offset=0\n"
276 		"\t'f2' type_id=9 bits_offset=64",
277 		"[11] STRUCT 's2' size=40 vlen=4\n"
278 		"\t'f1' type_id=7 bits_offset=0\n"
279 		"\t'f2' type_id=9 bits_offset=64\n"
280 		"\t'f3' type_id=6 bits_offset=128\n"
281 		"\t'f4' type_id=10 bits_offset=192",
282 		"[12] PTR '(anon)' type_id=8",
283 		"[13] STRUCT 's3' size=8 vlen=1\n"
284 		"\t'f1' type_id=12 bits_offset=0");
285 
286 	err = btf__dedup(btf2, NULL, NULL);
287 	if (!ASSERT_OK(err, "btf_dedup"))
288 		goto cleanup;
289 
290 	VALIDATE_RAW_BTF(
291 		btf2,
292 		"[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
293 		"[2] PTR '(anon)' type_id=5",
294 		"[3] FWD 's2' fwd_kind=struct",
295 		"[4] PTR '(anon)' type_id=3",
296 		"[5] STRUCT 's1' size=16 vlen=2\n"
297 		"\t'f1' type_id=2 bits_offset=0\n"
298 		"\t'f2' type_id=4 bits_offset=64",
299 		"[6] PTR '(anon)' type_id=8",
300 		"[7] PTR '(anon)' type_id=9",
301 		"[8] STRUCT 's1' size=16 vlen=2\n"
302 		"\t'f1' type_id=6 bits_offset=0\n"
303 		"\t'f2' type_id=7 bits_offset=64",
304 		"[9] STRUCT 's2' size=40 vlen=4\n"
305 		"\t'f1' type_id=6 bits_offset=0\n"
306 		"\t'f2' type_id=7 bits_offset=64\n"
307 		"\t'f3' type_id=1 bits_offset=128\n"
308 		"\t'f4' type_id=8 bits_offset=192",
309 		"[10] STRUCT 's3' size=8 vlen=1\n"
310 		"\t'f1' type_id=7 bits_offset=0");
311 
312 cleanup:
313 	btf__free(btf2);
314 	btf__free(btf1);
315 }
316 
317 void test_btf_dedup_split()
318 {
319 	if (test__start_subtest("split_simple"))
320 		test_split_simple();
321 	if (test__start_subtest("split_struct_duped"))
322 		test_split_struct_duped();
323 	if (test__start_subtest("split_fwd_resolve"))
324 		test_split_fwd_resolve();
325 }
326