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
test_split_simple()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);
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
test_split_fwd_resolve()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 /* keep this not a part of type the graph to test btf_dedup_resolve_fwds */
147 btf__add_struct(btf1, "s3", 4); /* [6] struct s3 { */
148 btf__add_field(btf1, "f1", 1, 0, 0); /* int f1; */
149 /* } */
150
151 VALIDATE_RAW_BTF(
152 btf1,
153 "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
154 "[2] PTR '(anon)' type_id=4",
155 "[3] PTR '(anon)' type_id=5",
156 "[4] STRUCT 's1' size=16 vlen=2\n"
157 "\t'f1' type_id=2 bits_offset=0\n"
158 "\t'f2' type_id=3 bits_offset=64",
159 "[5] STRUCT 's2' size=4 vlen=1\n"
160 "\t'f1' type_id=1 bits_offset=0",
161 "[6] STRUCT 's3' size=4 vlen=1\n"
162 "\t'f1' type_id=1 bits_offset=0");
163
164 btf2 = btf__new_empty_split(btf1);
165 if (!ASSERT_OK_PTR(btf2, "empty_split_btf"))
166 goto cleanup;
167
168 btf__add_int(btf2, "int", 4, BTF_INT_SIGNED); /* [7] int */
169 btf__add_ptr(btf2, 11); /* [8] ptr to struct s1 */
170 btf__add_fwd(btf2, "s2", BTF_FWD_STRUCT); /* [9] fwd for struct s2 */
171 btf__add_ptr(btf2, 9); /* [10] ptr to fwd struct s2 */
172 btf__add_struct(btf2, "s1", 16); /* [11] struct s1 { */
173 btf__add_field(btf2, "f1", 8, 0, 0); /* struct s1 *f1; */
174 btf__add_field(btf2, "f2", 10, 64, 0); /* struct s2 *f2; */
175 /* } */
176 btf__add_fwd(btf2, "s3", BTF_FWD_STRUCT); /* [12] fwd for struct s3 */
177 btf__add_ptr(btf2, 12); /* [13] ptr to struct s1 */
178
179 VALIDATE_RAW_BTF(
180 btf2,
181 "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
182 "[2] PTR '(anon)' type_id=4",
183 "[3] PTR '(anon)' type_id=5",
184 "[4] STRUCT 's1' size=16 vlen=2\n"
185 "\t'f1' type_id=2 bits_offset=0\n"
186 "\t'f2' type_id=3 bits_offset=64",
187 "[5] STRUCT 's2' size=4 vlen=1\n"
188 "\t'f1' type_id=1 bits_offset=0",
189 "[6] STRUCT 's3' size=4 vlen=1\n"
190 "\t'f1' type_id=1 bits_offset=0",
191 "[7] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
192 "[8] PTR '(anon)' type_id=11",
193 "[9] FWD 's2' fwd_kind=struct",
194 "[10] PTR '(anon)' type_id=9",
195 "[11] STRUCT 's1' size=16 vlen=2\n"
196 "\t'f1' type_id=8 bits_offset=0\n"
197 "\t'f2' type_id=10 bits_offset=64",
198 "[12] FWD 's3' fwd_kind=struct",
199 "[13] PTR '(anon)' type_id=12");
200
201 err = btf__dedup(btf2, NULL);
202 if (!ASSERT_OK(err, "btf_dedup"))
203 goto cleanup;
204
205 VALIDATE_RAW_BTF(
206 btf2,
207 "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
208 "[2] PTR '(anon)' type_id=4",
209 "[3] PTR '(anon)' type_id=5",
210 "[4] STRUCT 's1' size=16 vlen=2\n"
211 "\t'f1' type_id=2 bits_offset=0\n"
212 "\t'f2' type_id=3 bits_offset=64",
213 "[5] STRUCT 's2' size=4 vlen=1\n"
214 "\t'f1' type_id=1 bits_offset=0",
215 "[6] STRUCT 's3' size=4 vlen=1\n"
216 "\t'f1' type_id=1 bits_offset=0",
217 "[7] PTR '(anon)' type_id=6");
218
219 cleanup:
220 btf__free(btf2);
221 btf__free(btf1);
222 }
223
test_split_struct_duped()224 static void test_split_struct_duped() {
225 struct btf *btf1, *btf2;
226 int err;
227
228 btf1 = btf__new_empty();
229 if (!ASSERT_OK_PTR(btf1, "empty_main_btf"))
230 return;
231
232 btf__set_pointer_size(btf1, 8); /* enforce 64-bit arch */
233
234 btf__add_int(btf1, "int", 4, BTF_INT_SIGNED); /* [1] int */
235 btf__add_ptr(btf1, 5); /* [2] ptr to struct s1 */
236 btf__add_fwd(btf1, "s2", BTF_FWD_STRUCT); /* [3] fwd for struct s2 */
237 btf__add_ptr(btf1, 3); /* [4] ptr to fwd struct s2 */
238 btf__add_struct(btf1, "s1", 16); /* [5] struct s1 { */
239 btf__add_field(btf1, "f1", 2, 0, 0); /* struct s1 *f1; */
240 btf__add_field(btf1, "f2", 4, 64, 0); /* struct s2 *f2; */
241 /* } */
242
243 VALIDATE_RAW_BTF(
244 btf1,
245 "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
246 "[2] PTR '(anon)' type_id=5",
247 "[3] FWD 's2' fwd_kind=struct",
248 "[4] PTR '(anon)' type_id=3",
249 "[5] STRUCT 's1' size=16 vlen=2\n"
250 "\t'f1' type_id=2 bits_offset=0\n"
251 "\t'f2' type_id=4 bits_offset=64");
252
253 btf2 = btf__new_empty_split(btf1);
254 if (!ASSERT_OK_PTR(btf2, "empty_split_btf"))
255 goto cleanup;
256
257 btf__add_int(btf2, "int", 4, BTF_INT_SIGNED); /* [6] int */
258 btf__add_ptr(btf2, 10); /* [7] ptr to struct s1 */
259 btf__add_fwd(btf2, "s2", BTF_FWD_STRUCT); /* [8] fwd for struct s2 */
260 btf__add_ptr(btf2, 11); /* [9] ptr to struct s2 */
261 btf__add_struct(btf2, "s1", 16); /* [10] struct s1 { */
262 btf__add_field(btf2, "f1", 7, 0, 0); /* struct s1 *f1; */
263 btf__add_field(btf2, "f2", 9, 64, 0); /* struct s2 *f2; */
264 /* } */
265 btf__add_struct(btf2, "s2", 40); /* [11] struct s2 { */
266 btf__add_field(btf2, "f1", 7, 0, 0); /* struct s1 *f1; */
267 btf__add_field(btf2, "f2", 9, 64, 0); /* struct s2 *f2; */
268 btf__add_field(btf2, "f3", 6, 128, 0); /* int f3; */
269 btf__add_field(btf2, "f4", 10, 192, 0); /* struct s1 f4; */
270 /* } */
271 btf__add_ptr(btf2, 8); /* [12] ptr to fwd struct s2 */
272 btf__add_struct(btf2, "s3", 8); /* [13] struct s3 { */
273 btf__add_field(btf2, "f1", 12, 0, 0); /* struct s2 *f1; (fwd) */
274 /* } */
275
276 VALIDATE_RAW_BTF(
277 btf2,
278 "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
279 "[2] PTR '(anon)' type_id=5",
280 "[3] FWD 's2' fwd_kind=struct",
281 "[4] PTR '(anon)' type_id=3",
282 "[5] STRUCT 's1' size=16 vlen=2\n"
283 "\t'f1' type_id=2 bits_offset=0\n"
284 "\t'f2' type_id=4 bits_offset=64",
285 "[6] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
286 "[7] PTR '(anon)' type_id=10",
287 "[8] FWD 's2' fwd_kind=struct",
288 "[9] PTR '(anon)' type_id=11",
289 "[10] STRUCT 's1' size=16 vlen=2\n"
290 "\t'f1' type_id=7 bits_offset=0\n"
291 "\t'f2' type_id=9 bits_offset=64",
292 "[11] STRUCT 's2' size=40 vlen=4\n"
293 "\t'f1' type_id=7 bits_offset=0\n"
294 "\t'f2' type_id=9 bits_offset=64\n"
295 "\t'f3' type_id=6 bits_offset=128\n"
296 "\t'f4' type_id=10 bits_offset=192",
297 "[12] PTR '(anon)' type_id=8",
298 "[13] STRUCT 's3' size=8 vlen=1\n"
299 "\t'f1' type_id=12 bits_offset=0");
300
301 err = btf__dedup(btf2, NULL);
302 if (!ASSERT_OK(err, "btf_dedup"))
303 goto cleanup;
304
305 VALIDATE_RAW_BTF(
306 btf2,
307 "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
308 "[2] PTR '(anon)' type_id=5",
309 "[3] FWD 's2' fwd_kind=struct",
310 "[4] PTR '(anon)' type_id=3",
311 "[5] STRUCT 's1' size=16 vlen=2\n"
312 "\t'f1' type_id=2 bits_offset=0\n"
313 "\t'f2' type_id=4 bits_offset=64",
314 "[6] PTR '(anon)' type_id=8",
315 "[7] PTR '(anon)' type_id=9",
316 "[8] STRUCT 's1' size=16 vlen=2\n"
317 "\t'f1' type_id=6 bits_offset=0\n"
318 "\t'f2' type_id=7 bits_offset=64",
319 "[9] STRUCT 's2' size=40 vlen=4\n"
320 "\t'f1' type_id=6 bits_offset=0\n"
321 "\t'f2' type_id=7 bits_offset=64\n"
322 "\t'f3' type_id=1 bits_offset=128\n"
323 "\t'f4' type_id=8 bits_offset=192",
324 "[10] STRUCT 's3' size=8 vlen=1\n"
325 "\t'f1' type_id=7 bits_offset=0");
326
327 cleanup:
328 btf__free(btf2);
329 btf__free(btf1);
330 }
331
btf_add_dup_struct_in_cu(struct btf * btf,int start_id)332 static void btf_add_dup_struct_in_cu(struct btf *btf, int start_id)
333 {
334 #define ID(n) (start_id + n)
335 btf__set_pointer_size(btf, 8); /* enforce 64-bit arch */
336
337 btf__add_int(btf, "int", 4, BTF_INT_SIGNED); /* [1] int */
338
339 btf__add_struct(btf, "s", 8); /* [2] struct s { */
340 btf__add_field(btf, "a", ID(3), 0, 0); /* struct anon a; */
341 btf__add_field(btf, "b", ID(4), 0, 0); /* struct anon b; */
342 /* } */
343
344 btf__add_struct(btf, "(anon)", 8); /* [3] struct anon { */
345 btf__add_field(btf, "f1", ID(1), 0, 0); /* int f1; */
346 btf__add_field(btf, "f2", ID(1), 32, 0); /* int f2; */
347 /* } */
348
349 btf__add_struct(btf, "(anon)", 8); /* [4] struct anon { */
350 btf__add_field(btf, "f1", ID(1), 0, 0); /* int f1; */
351 btf__add_field(btf, "f2", ID(1), 32, 0); /* int f2; */
352 /* } */
353 #undef ID
354 }
355
test_split_dup_struct_in_cu()356 static void test_split_dup_struct_in_cu()
357 {
358 struct btf *btf1, *btf2 = NULL;
359 int err;
360
361 /* generate the base data.. */
362 btf1 = btf__new_empty();
363 if (!ASSERT_OK_PTR(btf1, "empty_main_btf"))
364 return;
365
366 btf_add_dup_struct_in_cu(btf1, 0);
367
368 VALIDATE_RAW_BTF(
369 btf1,
370 "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
371 "[2] STRUCT 's' size=8 vlen=2\n"
372 "\t'a' type_id=3 bits_offset=0\n"
373 "\t'b' type_id=4 bits_offset=0",
374 "[3] STRUCT '(anon)' size=8 vlen=2\n"
375 "\t'f1' type_id=1 bits_offset=0\n"
376 "\t'f2' type_id=1 bits_offset=32",
377 "[4] STRUCT '(anon)' size=8 vlen=2\n"
378 "\t'f1' type_id=1 bits_offset=0\n"
379 "\t'f2' type_id=1 bits_offset=32");
380
381 /* ..dedup them... */
382 err = btf__dedup(btf1, NULL);
383 if (!ASSERT_OK(err, "btf_dedup"))
384 goto cleanup;
385
386 VALIDATE_RAW_BTF(
387 btf1,
388 "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
389 "[2] STRUCT 's' size=8 vlen=2\n"
390 "\t'a' type_id=3 bits_offset=0\n"
391 "\t'b' type_id=3 bits_offset=0",
392 "[3] STRUCT '(anon)' size=8 vlen=2\n"
393 "\t'f1' type_id=1 bits_offset=0\n"
394 "\t'f2' type_id=1 bits_offset=32");
395
396 /* and add the same data on top of it */
397 btf2 = btf__new_empty_split(btf1);
398 if (!ASSERT_OK_PTR(btf2, "empty_split_btf"))
399 goto cleanup;
400
401 btf_add_dup_struct_in_cu(btf2, 3);
402
403 VALIDATE_RAW_BTF(
404 btf2,
405 "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
406 "[2] STRUCT 's' size=8 vlen=2\n"
407 "\t'a' type_id=3 bits_offset=0\n"
408 "\t'b' type_id=3 bits_offset=0",
409 "[3] STRUCT '(anon)' size=8 vlen=2\n"
410 "\t'f1' type_id=1 bits_offset=0\n"
411 "\t'f2' type_id=1 bits_offset=32",
412 "[4] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
413 "[5] STRUCT 's' size=8 vlen=2\n"
414 "\t'a' type_id=6 bits_offset=0\n"
415 "\t'b' type_id=7 bits_offset=0",
416 "[6] STRUCT '(anon)' size=8 vlen=2\n"
417 "\t'f1' type_id=4 bits_offset=0\n"
418 "\t'f2' type_id=4 bits_offset=32",
419 "[7] STRUCT '(anon)' size=8 vlen=2\n"
420 "\t'f1' type_id=4 bits_offset=0\n"
421 "\t'f2' type_id=4 bits_offset=32");
422
423 err = btf__dedup(btf2, NULL);
424 if (!ASSERT_OK(err, "btf_dedup"))
425 goto cleanup;
426
427 /* after dedup it should match the original data */
428 VALIDATE_RAW_BTF(
429 btf2,
430 "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
431 "[2] STRUCT 's' size=8 vlen=2\n"
432 "\t'a' type_id=3 bits_offset=0\n"
433 "\t'b' type_id=3 bits_offset=0",
434 "[3] STRUCT '(anon)' size=8 vlen=2\n"
435 "\t'f1' type_id=1 bits_offset=0\n"
436 "\t'f2' type_id=1 bits_offset=32");
437
438 cleanup:
439 btf__free(btf2);
440 btf__free(btf1);
441 }
442
test_btf_dedup_split()443 void test_btf_dedup_split()
444 {
445 if (test__start_subtest("split_simple"))
446 test_split_simple();
447 if (test__start_subtest("split_struct_duped"))
448 test_split_struct_duped();
449 if (test__start_subtest("split_fwd_resolve"))
450 test_split_fwd_resolve();
451 if (test__start_subtest("split_dup_struct_in_cu"))
452 test_split_dup_struct_in_cu();
453 }
454