1 // SPDX-License-Identifier: GPL-2.0
2 #include <test_progs.h>
3 #include <bpf/btf.h>
4 
5 static int duration = 0;
6 
7 void btf_dump_printf(void *ctx, const char *fmt, va_list args)
8 {
9 	vfprintf(ctx, fmt, args);
10 }
11 
12 static struct btf_dump_test_case {
13 	const char *name;
14 	const char *file;
15 	bool known_ptr_sz;
16 } btf_dump_test_cases[] = {
17 	{"btf_dump: syntax", "btf_dump_test_case_syntax", true},
18 	{"btf_dump: ordering", "btf_dump_test_case_ordering", false},
19 	{"btf_dump: padding", "btf_dump_test_case_padding", true},
20 	{"btf_dump: packing", "btf_dump_test_case_packing", true},
21 	{"btf_dump: bitfields", "btf_dump_test_case_bitfields", true},
22 	{"btf_dump: multidim", "btf_dump_test_case_multidim", false},
23 	{"btf_dump: namespacing", "btf_dump_test_case_namespacing", false},
24 };
25 
26 static int btf_dump_all_types(const struct btf *btf, void *ctx)
27 {
28 	size_t type_cnt = btf__type_cnt(btf);
29 	struct btf_dump *d;
30 	int err = 0, id;
31 
32 	d = btf_dump__new(btf, btf_dump_printf, ctx, NULL);
33 	err = libbpf_get_error(d);
34 	if (err)
35 		return err;
36 
37 	for (id = 1; id < type_cnt; id++) {
38 		err = btf_dump__dump_type(d, id);
39 		if (err)
40 			goto done;
41 	}
42 
43 done:
44 	btf_dump__free(d);
45 	return err;
46 }
47 
48 static int test_btf_dump_case(int n, struct btf_dump_test_case *t)
49 {
50 	char test_file[256], out_file[256], diff_cmd[1024];
51 	struct btf *btf = NULL;
52 	int err = 0, fd = -1;
53 	FILE *f = NULL;
54 
55 	snprintf(test_file, sizeof(test_file), "%s.o", t->file);
56 
57 	btf = btf__parse_elf(test_file, NULL);
58 	if (!ASSERT_OK_PTR(btf, "btf_parse_elf")) {
59 		err = -PTR_ERR(btf);
60 		btf = NULL;
61 		goto done;
62 	}
63 
64 	/* tests with t->known_ptr_sz have no "long" or "unsigned long" type,
65 	 * so it's impossible to determine correct pointer size; but if they
66 	 * do, it should be 8 regardless of host architecture, becaues BPF
67 	 * target is always 64-bit
68 	 */
69 	if (!t->known_ptr_sz) {
70 		btf__set_pointer_size(btf, 8);
71 	} else {
72 		CHECK(btf__pointer_size(btf) != 8, "ptr_sz", "exp %d, got %zu\n",
73 		      8, btf__pointer_size(btf));
74 	}
75 
76 	snprintf(out_file, sizeof(out_file), "/tmp/%s.output.XXXXXX", t->file);
77 	fd = mkstemp(out_file);
78 	if (!ASSERT_GE(fd, 0, "create_tmp")) {
79 		err = fd;
80 		goto done;
81 	}
82 	f = fdopen(fd, "w");
83 	if (CHECK(f == NULL, "open_tmp",  "failed to open file: %s(%d)\n",
84 		  strerror(errno), errno)) {
85 		close(fd);
86 		goto done;
87 	}
88 
89 	err = btf_dump_all_types(btf, f);
90 	fclose(f);
91 	close(fd);
92 	if (CHECK(err, "btf_dump", "failure during C dumping: %d\n", err)) {
93 		goto done;
94 	}
95 
96 	snprintf(test_file, sizeof(test_file), "progs/%s.c", t->file);
97 	if (access(test_file, R_OK) == -1)
98 		/*
99 		 * When the test is run with O=, kselftest copies TEST_FILES
100 		 * without preserving the directory structure.
101 		 */
102 		snprintf(test_file, sizeof(test_file), "%s.c", t->file);
103 	/*
104 	 * Diff test output and expected test output, contained between
105 	 * START-EXPECTED-OUTPUT and END-EXPECTED-OUTPUT lines in test case.
106 	 * For expected output lines, everything before '*' is stripped out.
107 	 * Also lines containing comment start and comment end markers are
108 	 * ignored.
109 	 */
110 	snprintf(diff_cmd, sizeof(diff_cmd),
111 		 "awk '/START-EXPECTED-OUTPUT/{out=1;next} "
112 		 "/END-EXPECTED-OUTPUT/{out=0} "
113 		 "/\\/\\*|\\*\\//{next} " /* ignore comment start/end lines */
114 		 "out {sub(/^[ \\t]*\\*/, \"\"); print}' '%s' | diff -u - '%s'",
115 		 test_file, out_file);
116 	err = system(diff_cmd);
117 	if (CHECK(err, "diff",
118 		  "differing test output, output=%s, err=%d, diff cmd:\n%s\n",
119 		  out_file, err, diff_cmd))
120 		goto done;
121 
122 	remove(out_file);
123 
124 done:
125 	btf__free(btf);
126 	return err;
127 }
128 
129 static char *dump_buf;
130 static size_t dump_buf_sz;
131 static FILE *dump_buf_file;
132 
133 static void test_btf_dump_incremental(void)
134 {
135 	struct btf *btf = NULL;
136 	struct btf_dump *d = NULL;
137 	int id, err, i;
138 
139 	dump_buf_file = open_memstream(&dump_buf, &dump_buf_sz);
140 	if (!ASSERT_OK_PTR(dump_buf_file, "dump_memstream"))
141 		return;
142 	btf = btf__new_empty();
143 	if (!ASSERT_OK_PTR(btf, "new_empty"))
144 		goto err_out;
145 	d = btf_dump__new(btf, btf_dump_printf, dump_buf_file, NULL);
146 	if (!ASSERT_OK(libbpf_get_error(d), "btf_dump__new"))
147 		goto err_out;
148 
149 	/* First, generate BTF corresponding to the following C code:
150 	 *
151 	 * enum { VAL = 1 };
152 	 *
153 	 * struct s { int x; };
154 	 *
155 	 */
156 	id = btf__add_enum(btf, NULL, 4);
157 	ASSERT_EQ(id, 1, "enum_id");
158 	err = btf__add_enum_value(btf, "VAL", 1);
159 	ASSERT_OK(err, "enum_val_ok");
160 
161 	id = btf__add_int(btf, "int", 4, BTF_INT_SIGNED);
162 	ASSERT_EQ(id, 2, "int_id");
163 
164 	id = btf__add_struct(btf, "s", 4);
165 	ASSERT_EQ(id, 3, "struct_id");
166 	err = btf__add_field(btf, "x", 2, 0, 0);
167 	ASSERT_OK(err, "field_ok");
168 
169 	for (i = 1; i < btf__type_cnt(btf); i++) {
170 		err = btf_dump__dump_type(d, i);
171 		ASSERT_OK(err, "dump_type_ok");
172 	}
173 
174 	fflush(dump_buf_file);
175 	dump_buf[dump_buf_sz] = 0; /* some libc implementations don't do this */
176 	ASSERT_STREQ(dump_buf,
177 "enum {\n"
178 "	VAL = 1,\n"
179 "};\n"
180 "\n"
181 "struct s {\n"
182 "	int x;\n"
183 "};\n\n", "c_dump1");
184 
185 	/* Now, after dumping original BTF, append another struct that embeds
186 	 * anonymous enum. It also has a name conflict with the first struct:
187 	 *
188 	 * struct s___2 {
189 	 *     enum { VAL___2 = 1 } x;
190 	 *     struct s s;
191 	 * };
192 	 *
193 	 * This will test that btf_dump'er maintains internal state properly.
194 	 * Note that VAL___2 enum value. It's because we've already emitted
195 	 * that enum as a global anonymous enum, so btf_dump will ensure that
196 	 * enum values don't conflict;
197 	 *
198 	 */
199 	fseek(dump_buf_file, 0, SEEK_SET);
200 
201 	id = btf__add_struct(btf, "s", 4);
202 	ASSERT_EQ(id, 4, "struct_id");
203 	err = btf__add_field(btf, "x", 1, 0, 0);
204 	ASSERT_OK(err, "field_ok");
205 	err = btf__add_field(btf, "s", 3, 32, 0);
206 	ASSERT_OK(err, "field_ok");
207 
208 	for (i = 1; i < btf__type_cnt(btf); i++) {
209 		err = btf_dump__dump_type(d, i);
210 		ASSERT_OK(err, "dump_type_ok");
211 	}
212 
213 	fflush(dump_buf_file);
214 	dump_buf[dump_buf_sz] = 0; /* some libc implementations don't do this */
215 	ASSERT_STREQ(dump_buf,
216 "struct s___2 {\n"
217 "	enum {\n"
218 "		VAL___2 = 1,\n"
219 "	} x;\n"
220 "	struct s s;\n"
221 "};\n\n" , "c_dump1");
222 
223 err_out:
224 	fclose(dump_buf_file);
225 	free(dump_buf);
226 	btf_dump__free(d);
227 	btf__free(btf);
228 }
229 
230 #define STRSIZE				4096
231 
232 static void btf_dump_snprintf(void *ctx, const char *fmt, va_list args)
233 {
234 	char *s = ctx, new[STRSIZE];
235 
236 	vsnprintf(new, STRSIZE, fmt, args);
237 	if (strlen(s) < STRSIZE)
238 		strncat(s, new, STRSIZE - strlen(s) - 1);
239 }
240 
241 static int btf_dump_data(struct btf *btf, struct btf_dump *d,
242 			 char *name, char *prefix, __u64 flags, void *ptr,
243 			 size_t ptr_sz, char *str, const char *expected_val)
244 {
245 	DECLARE_LIBBPF_OPTS(btf_dump_type_data_opts, opts);
246 	size_t type_sz;
247 	__s32 type_id;
248 	int ret = 0;
249 
250 	if (flags & BTF_F_COMPACT)
251 		opts.compact = true;
252 	if (flags & BTF_F_NONAME)
253 		opts.skip_names = true;
254 	if (flags & BTF_F_ZERO)
255 		opts.emit_zeroes = true;
256 	if (prefix) {
257 		ASSERT_STRNEQ(name, prefix, strlen(prefix),
258 			      "verify prefix match");
259 		name += strlen(prefix) + 1;
260 	}
261 	type_id = btf__find_by_name(btf, name);
262 	if (!ASSERT_GE(type_id, 0, "find type id"))
263 		return -ENOENT;
264 	type_sz = btf__resolve_size(btf, type_id);
265 	str[0] = '\0';
266 	ret = btf_dump__dump_type_data(d, type_id, ptr, ptr_sz, &opts);
267 	if (type_sz <= ptr_sz) {
268 		if (!ASSERT_EQ(ret, type_sz, "failed/unexpected type_sz"))
269 			return -EINVAL;
270 	} else {
271 		if (!ASSERT_EQ(ret, -E2BIG, "failed to return -E2BIG"))
272 			return -EINVAL;
273 	}
274 	if (!ASSERT_STREQ(str, expected_val, "ensure expected/actual match"))
275 		return -EFAULT;
276 	return 0;
277 }
278 
279 #define TEST_BTF_DUMP_DATA(_b, _d, _prefix, _str, _type, _flags,	\
280 			   _expected, ...)				\
281 	do {								\
282 		char __ptrtype[64] = #_type;				\
283 		char *_ptrtype = (char *)__ptrtype;			\
284 		_type _ptrdata = __VA_ARGS__;				\
285 		void *_ptr = &_ptrdata;					\
286 									\
287 		(void) btf_dump_data(_b, _d, _ptrtype, _prefix, _flags,	\
288 				     _ptr, sizeof(_type), _str,		\
289 				     _expected);			\
290 	} while (0)
291 
292 /* Use where expected data string matches its stringified declaration */
293 #define TEST_BTF_DUMP_DATA_C(_b, _d, _prefix,  _str, _type, _flags,	\
294 			     ...)					\
295 	TEST_BTF_DUMP_DATA(_b, _d, _prefix, _str, _type, _flags,	\
296 			   "(" #_type ")" #__VA_ARGS__,	__VA_ARGS__)
297 
298 /* overflow test; pass typesize < expected type size, ensure E2BIG returned */
299 #define TEST_BTF_DUMP_DATA_OVER(_b, _d, _prefix, _str, _type, _type_sz,	\
300 				_expected, ...)				\
301 	do {								\
302 		char __ptrtype[64] = #_type;				\
303 		char *_ptrtype = (char *)__ptrtype;			\
304 		_type _ptrdata = __VA_ARGS__;				\
305 		void *_ptr = &_ptrdata;					\
306 									\
307 		(void) btf_dump_data(_b, _d, _ptrtype, _prefix, 0,	\
308 				     _ptr, _type_sz, _str, _expected);	\
309 	} while (0)
310 
311 #define TEST_BTF_DUMP_VAR(_b, _d, _prefix, _str, _var, _type, _flags,	\
312 			  _expected, ...)				\
313 	do {								\
314 		_type _ptrdata = __VA_ARGS__;				\
315 		void *_ptr = &_ptrdata;					\
316 									\
317 		(void) btf_dump_data(_b, _d, _var, _prefix, _flags,	\
318 				     _ptr, sizeof(_type), _str,		\
319 				     _expected);			\
320 	} while (0)
321 
322 static void test_btf_dump_int_data(struct btf *btf, struct btf_dump *d,
323 				   char *str)
324 {
325 #ifdef __SIZEOF_INT128__
326 	unsigned __int128 i = 0xffffffffffffffff;
327 
328 	/* this dance is required because we cannot directly initialize
329 	 * a 128-bit value to anything larger than a 64-bit value.
330 	 */
331 	i = (i << 64) | (i - 1);
332 #endif
333 	/* simple int */
334 	TEST_BTF_DUMP_DATA_C(btf, d, NULL, str, int, BTF_F_COMPACT, 1234);
335 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, int, BTF_F_COMPACT | BTF_F_NONAME,
336 			   "1234", 1234);
337 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, int, 0, "(int)1234", 1234);
338 
339 	/* zero value should be printed at toplevel */
340 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, int, BTF_F_COMPACT, "(int)0", 0);
341 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, int, BTF_F_COMPACT | BTF_F_NONAME,
342 			   "0", 0);
343 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, int, BTF_F_COMPACT | BTF_F_ZERO,
344 			   "(int)0", 0);
345 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, int,
346 			   BTF_F_COMPACT | BTF_F_NONAME | BTF_F_ZERO,
347 			   "0", 0);
348 	TEST_BTF_DUMP_DATA_C(btf, d, NULL, str, int, BTF_F_COMPACT, -4567);
349 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, int, BTF_F_COMPACT | BTF_F_NONAME,
350 			   "-4567", -4567);
351 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, int, 0, "(int)-4567", -4567);
352 
353 	TEST_BTF_DUMP_DATA_OVER(btf, d, NULL, str, int, sizeof(int)-1, "", 1);
354 
355 #ifdef __SIZEOF_INT128__
356 	/* gcc encode unsigned __int128 type with name "__int128 unsigned" in dwarf,
357 	 * and clang encode it with name "unsigned __int128" in dwarf.
358 	 * Do an availability test for either variant before doing actual test.
359 	 */
360 	if (btf__find_by_name(btf, "unsigned __int128") > 0) {
361 		TEST_BTF_DUMP_DATA(btf, d, NULL, str, unsigned __int128, BTF_F_COMPACT,
362 				   "(unsigned __int128)0xffffffffffffffff",
363 				   0xffffffffffffffff);
364 		ASSERT_OK(btf_dump_data(btf, d, "unsigned __int128", NULL, 0, &i, 16, str,
365 					"(unsigned __int128)0xfffffffffffffffffffffffffffffffe"),
366 			  "dump unsigned __int128");
367 	} else if (btf__find_by_name(btf, "__int128 unsigned") > 0) {
368 		TEST_BTF_DUMP_DATA(btf, d, NULL, str, __int128 unsigned, BTF_F_COMPACT,
369 				   "(__int128 unsigned)0xffffffffffffffff",
370 				   0xffffffffffffffff);
371 		ASSERT_OK(btf_dump_data(btf, d, "__int128 unsigned", NULL, 0, &i, 16, str,
372 					"(__int128 unsigned)0xfffffffffffffffffffffffffffffffe"),
373 			  "dump unsigned __int128");
374 	} else {
375 		ASSERT_TRUE(false, "unsigned_int128_not_found");
376 	}
377 #endif
378 }
379 
380 static void test_btf_dump_float_data(struct btf *btf, struct btf_dump *d,
381 				     char *str)
382 {
383 	float t1 = 1.234567;
384 	float t2 = -1.234567;
385 	float t3 = 0.0;
386 	double t4 = 5.678912;
387 	double t5 = -5.678912;
388 	double t6 = 0.0;
389 	long double t7 = 9.876543;
390 	long double t8 = -9.876543;
391 	long double t9 = 0.0;
392 
393 	/* since the kernel does not likely have any float types in its BTF, we
394 	 * will need to add some of various sizes.
395 	 */
396 
397 	ASSERT_GT(btf__add_float(btf, "test_float", 4), 0, "add float");
398 	ASSERT_OK(btf_dump_data(btf, d, "test_float", NULL, 0, &t1, 4, str,
399 				"(test_float)1.234567"), "dump float");
400 	ASSERT_OK(btf_dump_data(btf, d, "test_float", NULL, 0, &t2, 4, str,
401 				"(test_float)-1.234567"), "dump float");
402 	ASSERT_OK(btf_dump_data(btf, d, "test_float", NULL, 0, &t3, 4, str,
403 				"(test_float)0.000000"), "dump float");
404 
405 	ASSERT_GT(btf__add_float(btf, "test_double", 8), 0, "add_double");
406 	ASSERT_OK(btf_dump_data(btf, d, "test_double", NULL, 0, &t4, 8, str,
407 		  "(test_double)5.678912"), "dump double");
408 	ASSERT_OK(btf_dump_data(btf, d, "test_double", NULL, 0, &t5, 8, str,
409 		  "(test_double)-5.678912"), "dump double");
410 	ASSERT_OK(btf_dump_data(btf, d, "test_double", NULL, 0, &t6, 8, str,
411 				"(test_double)0.000000"), "dump double");
412 
413 	ASSERT_GT(btf__add_float(btf, "test_long_double", 16), 0, "add long double");
414 	ASSERT_OK(btf_dump_data(btf, d, "test_long_double", NULL, 0, &t7, 16,
415 				str, "(test_long_double)9.876543"),
416 				"dump long_double");
417 	ASSERT_OK(btf_dump_data(btf, d, "test_long_double", NULL, 0, &t8, 16,
418 				str, "(test_long_double)-9.876543"),
419 				"dump long_double");
420 	ASSERT_OK(btf_dump_data(btf, d, "test_long_double", NULL, 0, &t9, 16,
421 				str, "(test_long_double)0.000000"),
422 				"dump long_double");
423 }
424 
425 static void test_btf_dump_char_data(struct btf *btf, struct btf_dump *d,
426 				    char *str)
427 {
428 	/* simple char */
429 	TEST_BTF_DUMP_DATA_C(btf, d, NULL, str, char, BTF_F_COMPACT, 100);
430 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, char, BTF_F_COMPACT | BTF_F_NONAME,
431 			   "100", 100);
432 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, char, 0, "(char)100", 100);
433 	/* zero value should be printed at toplevel */
434 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, char, BTF_F_COMPACT,
435 			   "(char)0", 0);
436 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, char, BTF_F_COMPACT | BTF_F_NONAME,
437 			   "0", 0);
438 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, char, BTF_F_COMPACT | BTF_F_ZERO,
439 			   "(char)0", 0);
440 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, char, BTF_F_COMPACT | BTF_F_NONAME | BTF_F_ZERO,
441 			   "0", 0);
442 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, char, 0, "(char)0", 0);
443 
444 	TEST_BTF_DUMP_DATA_OVER(btf, d, NULL, str, char, sizeof(char)-1, "", 100);
445 }
446 
447 static void test_btf_dump_typedef_data(struct btf *btf, struct btf_dump *d,
448 				       char *str)
449 {
450 	/* simple typedef */
451 	TEST_BTF_DUMP_DATA_C(btf, d, NULL, str, uint64_t, BTF_F_COMPACT, 100);
452 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, u64, BTF_F_COMPACT | BTF_F_NONAME,
453 			   "1", 1);
454 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, u64, 0, "(u64)1", 1);
455 	/* zero value should be printed at toplevel */
456 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, u64, BTF_F_COMPACT, "(u64)0", 0);
457 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, u64, BTF_F_COMPACT | BTF_F_NONAME,
458 			   "0", 0);
459 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, u64, BTF_F_COMPACT | BTF_F_ZERO,
460 			   "(u64)0", 0);
461 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, u64,
462 			   BTF_F_COMPACT | BTF_F_NONAME | BTF_F_ZERO,
463 			   "0", 0);
464 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, u64, 0, "(u64)0", 0);
465 
466 	/* typedef struct */
467 	TEST_BTF_DUMP_DATA_C(btf, d, NULL, str, atomic_t, BTF_F_COMPACT,
468 			     {.counter = (int)1,});
469 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t, BTF_F_COMPACT | BTF_F_NONAME,
470 			   "{1,}", { .counter = 1 });
471 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t, 0,
472 "(atomic_t){\n"
473 "	.counter = (int)1,\n"
474 "}",
475 			   {.counter = 1,});
476 	/* typedef with 0 value should be printed at toplevel */
477 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t, BTF_F_COMPACT, "(atomic_t){}",
478 			   {.counter = 0,});
479 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t, BTF_F_COMPACT | BTF_F_NONAME,
480 			   "{}", {.counter = 0,});
481 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t, 0,
482 "(atomic_t){\n"
483 "}",
484 			   {.counter = 0,});
485 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t, BTF_F_COMPACT | BTF_F_ZERO,
486 			   "(atomic_t){.counter = (int)0,}",
487 			   {.counter = 0,});
488 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t,
489 			   BTF_F_COMPACT | BTF_F_NONAME | BTF_F_ZERO,
490 			   "{0,}", {.counter = 0,});
491 	TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t, BTF_F_ZERO,
492 "(atomic_t){\n"
493 "	.counter = (int)0,\n"
494 "}",
495 			   { .counter = 0,});
496 
497 	/* overflow should show type but not value since it overflows */
498 	TEST_BTF_DUMP_DATA_OVER(btf, d, NULL, str, atomic_t, sizeof(atomic_t)-1,
499 				"(atomic_t){\n", { .counter = 1});
500 }
501 
502 static void test_btf_dump_enum_data(struct btf *btf, struct btf_dump *d,
503 				    char *str)
504 {
505 	/* enum where enum value does (and does not) exist */
506 	TEST_BTF_DUMP_DATA_C(btf, d, "enum", str, enum bpf_cmd, BTF_F_COMPACT,
507 			     BPF_MAP_CREATE);
508 	TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd, BTF_F_COMPACT,
509 			   "(enum bpf_cmd)BPF_MAP_CREATE", 0);
510 	TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd,
511 			   BTF_F_COMPACT | BTF_F_NONAME,
512 			   "BPF_MAP_CREATE",
513 			   BPF_MAP_CREATE);
514 	TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd, 0,
515 			   "(enum bpf_cmd)BPF_MAP_CREATE",
516 			   BPF_MAP_CREATE);
517 	TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd,
518 			   BTF_F_COMPACT | BTF_F_NONAME | BTF_F_ZERO,
519 			   "BPF_MAP_CREATE", 0);
520 	TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd,
521 			   BTF_F_COMPACT | BTF_F_ZERO,
522 			   "(enum bpf_cmd)BPF_MAP_CREATE",
523 			   BPF_MAP_CREATE);
524 	TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd,
525 			   BTF_F_COMPACT | BTF_F_NONAME | BTF_F_ZERO,
526 			   "BPF_MAP_CREATE", BPF_MAP_CREATE);
527 	TEST_BTF_DUMP_DATA_C(btf, d, "enum", str, enum bpf_cmd, BTF_F_COMPACT, 2000);
528 	TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd,
529 			   BTF_F_COMPACT | BTF_F_NONAME,
530 			   "2000", 2000);
531 	TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd, 0,
532 			   "(enum bpf_cmd)2000", 2000);
533 
534 	TEST_BTF_DUMP_DATA_OVER(btf, d, "enum", str, enum bpf_cmd,
535 				sizeof(enum bpf_cmd) - 1, "", BPF_MAP_CREATE);
536 }
537 
538 static void test_btf_dump_struct_data(struct btf *btf, struct btf_dump *d,
539 				      char *str)
540 {
541 	DECLARE_LIBBPF_OPTS(btf_dump_type_data_opts, opts);
542 	char zero_data[512] = { };
543 	char type_data[512];
544 	void *fops = type_data;
545 	void *skb = type_data;
546 	size_t type_sz;
547 	__s32 type_id;
548 	char *cmpstr;
549 	int ret;
550 
551 	memset(type_data, 255, sizeof(type_data));
552 
553 	/* simple struct */
554 	TEST_BTF_DUMP_DATA_C(btf, d, "struct", str, struct btf_enum, BTF_F_COMPACT,
555 			     {.name_off = (__u32)3,.val = (__s32)-1,});
556 	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum,
557 			   BTF_F_COMPACT | BTF_F_NONAME,
558 			   "{3,-1,}",
559 			   { .name_off = 3, .val = -1,});
560 	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum, 0,
561 "(struct btf_enum){\n"
562 "	.name_off = (__u32)3,\n"
563 "	.val = (__s32)-1,\n"
564 "}",
565 			   { .name_off = 3, .val = -1,});
566 	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum,
567 			   BTF_F_COMPACT | BTF_F_NONAME,
568 			   "{-1,}",
569 			   { .name_off = 0, .val = -1,});
570 	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum,
571 			   BTF_F_COMPACT | BTF_F_NONAME | BTF_F_ZERO,
572 			   "{0,-1,}",
573 			   { .name_off = 0, .val = -1,});
574 	/* empty struct should be printed */
575 	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum, BTF_F_COMPACT,
576 			   "(struct btf_enum){}",
577 			   { .name_off = 0, .val = 0,});
578 	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum,
579 			   BTF_F_COMPACT | BTF_F_NONAME,
580 			   "{}",
581 			   { .name_off = 0, .val = 0,});
582 	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum, 0,
583 "(struct btf_enum){\n"
584 "}",
585 			   { .name_off = 0, .val = 0,});
586 	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum,
587 			   BTF_F_COMPACT | BTF_F_ZERO,
588 			   "(struct btf_enum){.name_off = (__u32)0,.val = (__s32)0,}",
589 			   { .name_off = 0, .val = 0,});
590 	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum,
591 			   BTF_F_ZERO,
592 "(struct btf_enum){\n"
593 "	.name_off = (__u32)0,\n"
594 "	.val = (__s32)0,\n"
595 "}",
596 			   { .name_off = 0, .val = 0,});
597 
598 	/* struct with pointers */
599 	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct list_head, BTF_F_COMPACT,
600 			   "(struct list_head){.next = (struct list_head *)0x1,}",
601 			   { .next = (struct list_head *)1 });
602 	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct list_head, 0,
603 "(struct list_head){\n"
604 "	.next = (struct list_head *)0x1,\n"
605 "}",
606 			   { .next = (struct list_head *)1 });
607 	/* NULL pointer should not be displayed */
608 	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct list_head, BTF_F_COMPACT,
609 			   "(struct list_head){}",
610 			   { .next = (struct list_head *)0 });
611 	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct list_head, 0,
612 "(struct list_head){\n"
613 "}",
614 			   { .next = (struct list_head *)0 });
615 
616 	/* struct with function pointers */
617 	type_id = btf__find_by_name(btf, "file_operations");
618 	if (ASSERT_GT(type_id, 0, "find type id")) {
619 		type_sz = btf__resolve_size(btf, type_id);
620 		str[0] = '\0';
621 
622 		ret = btf_dump__dump_type_data(d, type_id, fops, type_sz, &opts);
623 		ASSERT_EQ(ret, type_sz,
624 			  "unexpected return value dumping file_operations");
625 		cmpstr =
626 "(struct file_operations){\n"
627 "	.owner = (struct module *)0xffffffffffffffff,\n"
628 "	.llseek = (loff_t (*)(struct file *, loff_t, int))0xffffffffffffffff,";
629 
630 		ASSERT_STRNEQ(str, cmpstr, strlen(cmpstr), "file_operations");
631 	}
632 
633 	/* struct with char array */
634 	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_prog_info, BTF_F_COMPACT,
635 			   "(struct bpf_prog_info){.name = (char[16])['f','o','o',],}",
636 			   { .name = "foo",});
637 	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_prog_info,
638 			   BTF_F_COMPACT | BTF_F_NONAME,
639 			   "{['f','o','o',],}",
640 			   {.name = "foo",});
641 	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_prog_info, 0,
642 "(struct bpf_prog_info){\n"
643 "	.name = (char[16])[\n"
644 "		'f',\n"
645 "		'o',\n"
646 "		'o',\n"
647 "	],\n"
648 "}",
649 			   {.name = "foo",});
650 	/* leading null char means do not display string */
651 	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_prog_info, BTF_F_COMPACT,
652 			   "(struct bpf_prog_info){}",
653 			   {.name = {'\0', 'f', 'o', 'o'}});
654 	/* handle non-printable characters */
655 	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_prog_info, BTF_F_COMPACT,
656 			   "(struct bpf_prog_info){.name = (char[16])[1,2,3,],}",
657 			   { .name = {1, 2, 3, 0}});
658 
659 	/* struct with non-char array */
660 	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct __sk_buff, BTF_F_COMPACT,
661 			   "(struct __sk_buff){.cb = (__u32[5])[1,2,3,4,5,],}",
662 			   { .cb = {1, 2, 3, 4, 5,},});
663 	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct __sk_buff,
664 			   BTF_F_COMPACT | BTF_F_NONAME,
665 			   "{[1,2,3,4,5,],}",
666 			   { .cb = { 1, 2, 3, 4, 5},});
667 	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct __sk_buff, 0,
668 "(struct __sk_buff){\n"
669 "	.cb = (__u32[5])[\n"
670 "		1,\n"
671 "		2,\n"
672 "		3,\n"
673 "		4,\n"
674 "		5,\n"
675 "	],\n"
676 "}",
677 			   { .cb = { 1, 2, 3, 4, 5},});
678 	/* For non-char, arrays, show non-zero values only */
679 	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct __sk_buff, BTF_F_COMPACT,
680 			   "(struct __sk_buff){.cb = (__u32[5])[0,0,1,0,0,],}",
681 			   { .cb = { 0, 0, 1, 0, 0},});
682 	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct __sk_buff, 0,
683 "(struct __sk_buff){\n"
684 "	.cb = (__u32[5])[\n"
685 "		0,\n"
686 "		0,\n"
687 "		1,\n"
688 "		0,\n"
689 "		0,\n"
690 "	],\n"
691 "}",
692 			   { .cb = { 0, 0, 1, 0, 0},});
693 
694 	/* struct with bitfields */
695 	TEST_BTF_DUMP_DATA_C(btf, d, "struct", str, struct bpf_insn, BTF_F_COMPACT,
696 		{.code = (__u8)1,.dst_reg = (__u8)0x2,.src_reg = (__u8)0x3,.off = (__s16)4,.imm = (__s32)5,});
697 	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_insn,
698 			   BTF_F_COMPACT | BTF_F_NONAME,
699 			   "{1,0x2,0x3,4,5,}",
700 			   { .code = 1, .dst_reg = 0x2, .src_reg = 0x3, .off = 4,
701 			     .imm = 5,});
702 	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_insn, 0,
703 "(struct bpf_insn){\n"
704 "	.code = (__u8)1,\n"
705 "	.dst_reg = (__u8)0x2,\n"
706 "	.src_reg = (__u8)0x3,\n"
707 "	.off = (__s16)4,\n"
708 "	.imm = (__s32)5,\n"
709 "}",
710 			   {.code = 1, .dst_reg = 2, .src_reg = 3, .off = 4, .imm = 5});
711 
712 	/* zeroed bitfields should not be displayed */
713 	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_insn, BTF_F_COMPACT,
714 			   "(struct bpf_insn){.dst_reg = (__u8)0x1,}",
715 			   { .code = 0, .dst_reg = 1});
716 
717 	/* struct with enum bitfield */
718 	type_id = btf__find_by_name(btf, "fs_context");
719 	if (ASSERT_GT(type_id,  0, "find fs_context")) {
720 		type_sz = btf__resolve_size(btf, type_id);
721 		str[0] = '\0';
722 
723 		opts.emit_zeroes = true;
724 		ret = btf_dump__dump_type_data(d, type_id, zero_data, type_sz, &opts);
725 		ASSERT_EQ(ret, type_sz,
726 			  "unexpected return value dumping fs_context");
727 
728 		ASSERT_NEQ(strstr(str, "FS_CONTEXT_FOR_MOUNT"), NULL,
729 				  "bitfield value not present");
730 	}
731 
732 	/* struct with nested anon union */
733 	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_sock_ops, BTF_F_COMPACT,
734 			   "(struct bpf_sock_ops){.op = (__u32)1,(union){.args = (__u32[4])[1,2,3,4,],.reply = (__u32)1,.replylong = (__u32[4])[1,2,3,4,],},}",
735 			   { .op = 1, .args = { 1, 2, 3, 4}});
736 
737 	/* union with nested struct */
738 	TEST_BTF_DUMP_DATA(btf, d, "union", str, union bpf_iter_link_info, BTF_F_COMPACT,
739 			   "(union bpf_iter_link_info){.map = (struct){.map_fd = (__u32)1,},}",
740 			   { .map = { .map_fd = 1 }});
741 
742 	/* struct skb with nested structs/unions; because type output is so
743 	 * complex, we don't do a string comparison, just verify we return
744 	 * the type size as the amount of data displayed.
745 	 */
746 	type_id = btf__find_by_name(btf, "sk_buff");
747 	if (ASSERT_GT(type_id, 0, "find struct sk_buff")) {
748 		type_sz = btf__resolve_size(btf, type_id);
749 		str[0] = '\0';
750 
751 		ret = btf_dump__dump_type_data(d, type_id, skb, type_sz, &opts);
752 		ASSERT_EQ(ret, type_sz,
753 			  "unexpected return value dumping sk_buff");
754 	}
755 
756 	/* overflow bpf_sock_ops struct with final element nonzero/zero.
757 	 * Regardless of the value of the final field, we don't have all the
758 	 * data we need to display it, so we should trigger an overflow.
759 	 * In other words overflow checking should trump "is field zero?"
760 	 * checks because if we've overflowed, it shouldn't matter what the
761 	 * field is - we can't trust its value so shouldn't display it.
762 	 */
763 	TEST_BTF_DUMP_DATA_OVER(btf, d, "struct", str, struct bpf_sock_ops,
764 				sizeof(struct bpf_sock_ops) - 1,
765 				"(struct bpf_sock_ops){\n\t.op = (__u32)1,\n",
766 				{ .op = 1, .skb_tcp_flags = 2});
767 	TEST_BTF_DUMP_DATA_OVER(btf, d, "struct", str, struct bpf_sock_ops,
768 				sizeof(struct bpf_sock_ops) - 1,
769 				"(struct bpf_sock_ops){\n\t.op = (__u32)1,\n",
770 				{ .op = 1, .skb_tcp_flags = 0});
771 }
772 
773 static void test_btf_dump_var_data(struct btf *btf, struct btf_dump *d,
774 				   char *str)
775 {
776 #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
777 	TEST_BTF_DUMP_VAR(btf, d, NULL, str, "cpu_number", int, BTF_F_COMPACT,
778 			  "int cpu_number = (int)100", 100);
779 #endif
780 	TEST_BTF_DUMP_VAR(btf, d, NULL, str, "cpu_profile_flip", int, BTF_F_COMPACT,
781 			  "static int cpu_profile_flip = (int)2", 2);
782 }
783 
784 static void test_btf_datasec(struct btf *btf, struct btf_dump *d, char *str,
785 			     const char *name, const char *expected_val,
786 			     void *data, size_t data_sz)
787 {
788 	DECLARE_LIBBPF_OPTS(btf_dump_type_data_opts, opts);
789 	int ret = 0, cmp;
790 	size_t secsize;
791 	__s32 type_id;
792 
793 	opts.compact = true;
794 
795 	type_id = btf__find_by_name(btf, name);
796 	if (!ASSERT_GT(type_id, 0, "find type id"))
797 		return;
798 
799 	secsize = btf__resolve_size(btf, type_id);
800 	ASSERT_EQ(secsize,  0, "verify section size");
801 
802 	str[0] = '\0';
803 	ret = btf_dump__dump_type_data(d, type_id, data, data_sz, &opts);
804 	ASSERT_EQ(ret, 0, "unexpected return value");
805 
806 	cmp = strcmp(str, expected_val);
807 	ASSERT_EQ(cmp, 0, "ensure expected/actual match");
808 }
809 
810 static void test_btf_dump_datasec_data(char *str)
811 {
812 	struct btf *btf;
813 	char license[4] = "GPL";
814 	struct btf_dump *d;
815 
816 	btf = btf__parse("xdping_kern.o", NULL);
817 	if (!ASSERT_OK_PTR(btf, "xdping_kern.o BTF not found"))
818 		return;
819 
820 	d = btf_dump__new(btf, btf_dump_snprintf, str, NULL);
821 	if (!ASSERT_OK_PTR(d, "could not create BTF dump"))
822 		goto out;
823 
824 	test_btf_datasec(btf, d, str, "license",
825 			 "SEC(\"license\") char[4] _license = (char[4])['G','P','L',];",
826 			 license, sizeof(license));
827 out:
828 	btf_dump__free(d);
829 	btf__free(btf);
830 }
831 
832 void test_btf_dump() {
833 	char str[STRSIZE];
834 	struct btf_dump *d;
835 	struct btf *btf;
836 	int i;
837 
838 	for (i = 0; i < ARRAY_SIZE(btf_dump_test_cases); i++) {
839 		struct btf_dump_test_case *t = &btf_dump_test_cases[i];
840 
841 		if (!test__start_subtest(t->name))
842 			continue;
843 
844 		test_btf_dump_case(i, &btf_dump_test_cases[i]);
845 	}
846 	if (test__start_subtest("btf_dump: incremental"))
847 		test_btf_dump_incremental();
848 
849 	btf = libbpf_find_kernel_btf();
850 	if (!ASSERT_OK_PTR(btf, "no kernel BTF found"))
851 		return;
852 
853 	d = btf_dump__new(btf, btf_dump_snprintf, str, NULL);
854 	if (!ASSERT_OK_PTR(d, "could not create BTF dump"))
855 		return;
856 
857 	/* Verify type display for various types. */
858 	if (test__start_subtest("btf_dump: int_data"))
859 		test_btf_dump_int_data(btf, d, str);
860 	if (test__start_subtest("btf_dump: float_data"))
861 		test_btf_dump_float_data(btf, d, str);
862 	if (test__start_subtest("btf_dump: char_data"))
863 		test_btf_dump_char_data(btf, d, str);
864 	if (test__start_subtest("btf_dump: typedef_data"))
865 		test_btf_dump_typedef_data(btf, d, str);
866 	if (test__start_subtest("btf_dump: enum_data"))
867 		test_btf_dump_enum_data(btf, d, str);
868 	if (test__start_subtest("btf_dump: struct_data"))
869 		test_btf_dump_struct_data(btf, d, str);
870 	if (test__start_subtest("btf_dump: var_data"))
871 		test_btf_dump_var_data(btf, d, str);
872 	btf_dump__free(d);
873 	btf__free(btf);
874 
875 	if (test__start_subtest("btf_dump: datasec_data"))
876 		test_btf_dump_datasec_data(str);
877 }
878