File Index
Files and directories
Sign in
FILE

btf_dump.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/bpf/prog_tests/btf_dump.c C
   1// SPDX-License-Identifier: GPL-2.0
   2#include <test_progs.h>
   3#include <bpf/btf.h>
   4
   5static int duration = 0;
   6
   7void btf_dump_printf(void *ctx, const char *fmt, va_list args)
   8{
   9	vfprintf(ctx, fmt, args);
  10}
  11
  12static 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
  26static 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
  43done:
  44	btf_dump__free(d);
  45	return err;
  46}
  47
  48static 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.bpf.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, because 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
 124done:
 125	btf__free(btf);
 126	return err;
 127}
 128
 129struct test_ctx {
 130	struct btf *btf;
 131	struct btf_dump *d;
 132	char *dump_buf;
 133	size_t dump_buf_sz;
 134	FILE *dump_buf_file;
 135};
 136
 137static void test_ctx__free(struct test_ctx *t)
 138{
 139	fclose(t->dump_buf_file);
 140	free(t->dump_buf);
 141	btf_dump__free(t->d);
 142	btf__free(t->btf);
 143}
 144
 145static int test_ctx__init(struct test_ctx *t)
 146{
 147	t->dump_buf_file = open_memstream(&t->dump_buf, &t->dump_buf_sz);
 148	if (!ASSERT_OK_PTR(t->dump_buf_file, "dump_memstream"))
 149		return -1;
 150	t->btf = btf__new_empty();
 151	if (!ASSERT_OK_PTR(t->btf, "new_empty"))
 152		goto err_out;
 153	t->d = btf_dump__new(t->btf, btf_dump_printf, t->dump_buf_file, NULL);
 154	if (!ASSERT_OK(libbpf_get_error(t->d), "btf_dump__new"))
 155		goto err_out;
 156
 157	return 0;
 158
 159err_out:
 160	test_ctx__free(t);
 161	return -1;
 162}
 163
 164static void test_ctx__dump_and_compare(struct test_ctx *t,
 165				       const char *expected_output,
 166				       const char *message)
 167{
 168	int i, err;
 169
 170	for (i = 1; i < btf__type_cnt(t->btf); i++) {
 171		err = btf_dump__dump_type(t->d, i);
 172		ASSERT_OK(err, "dump_type_ok");
 173	}
 174
 175	fflush(t->dump_buf_file);
 176	t->dump_buf[t->dump_buf_sz] = 0; /* some libc implementations don't do this */
 177
 178	ASSERT_STREQ(t->dump_buf, expected_output, message);
 179}
 180
 181static void test_btf_dump_incremental(void)
 182{
 183	struct test_ctx t = {};
 184	struct btf *btf;
 185	int id, err;
 186
 187	if (test_ctx__init(&t))
 188		return;
 189
 190	btf = t.btf;
 191
 192	/* First, generate BTF corresponding to the following C code:
 193	 *
 194	 * enum x;
 195	 *
 196	 * enum x { X = 1 };
 197	 *
 198	 * enum { Y = 1 };
 199	 *
 200	 * struct s;
 201	 *
 202	 * struct s { int x; };
 203	 *
 204	 */
 205	id = btf__add_enum(btf, "x", 4);
 206	ASSERT_EQ(id, 1, "enum_declaration_id");
 207	id = btf__add_enum(btf, "x", 4);
 208	ASSERT_EQ(id, 2, "named_enum_id");
 209	err = btf__add_enum_value(btf, "X", 1);
 210	ASSERT_OK(err, "named_enum_val_ok");
 211
 212	id = btf__add_enum(btf, NULL, 4);
 213	ASSERT_EQ(id, 3, "anon_enum_id");
 214	err = btf__add_enum_value(btf, "Y", 1);
 215	ASSERT_OK(err, "anon_enum_val_ok");
 216
 217	id = btf__add_int(btf, "int", 4, BTF_INT_SIGNED);
 218	ASSERT_EQ(id, 4, "int_id");
 219
 220	id = btf__add_fwd(btf, "s", BTF_FWD_STRUCT);
 221	ASSERT_EQ(id, 5, "fwd_id");
 222
 223	id = btf__add_struct(btf, "s", 4);
 224	ASSERT_EQ(id, 6, "struct_id");
 225	err = btf__add_field(btf, "x", 4, 0, 0);
 226	ASSERT_OK(err, "field_ok");
 227
 228	test_ctx__dump_and_compare(&t,
 229"enum x;\n"
 230"\n"
 231"enum x {\n"
 232"	X = 1,\n"
 233"};\n"
 234"\n"
 235"enum {\n"
 236"	Y = 1,\n"
 237"};\n"
 238"\n"
 239"struct s;\n"
 240"\n"
 241"struct s {\n"
 242"	int x;\n"
 243"};\n\n", "c_dump1");
 244
 245	/* Now, after dumping original BTF, append another struct that embeds
 246	 * anonymous enum. It also has a name conflict with the first struct:
 247	 *
 248	 * struct s___2 {
 249	 *     enum { VAL___2 = 1 } x;
 250	 *     struct s s;
 251	 * };
 252	 *
 253	 * This will test that btf_dump'er maintains internal state properly.
 254	 * Note that VAL___2 enum value. It's because we've already emitted
 255	 * that enum as a global anonymous enum, so btf_dump will ensure that
 256	 * enum values don't conflict;
 257	 *
 258	 */
 259	fseek(t.dump_buf_file, 0, SEEK_SET);
 260
 261	id = btf__add_struct(btf, "s", 4);
 262	ASSERT_EQ(id, 7, "struct_id");
 263	err = btf__add_field(btf, "x", 2, 0, 0);
 264	ASSERT_OK(err, "field_ok");
 265	err = btf__add_field(btf, "y", 3, 32, 0);
 266	ASSERT_OK(err, "field_ok");
 267	err = btf__add_field(btf, "s", 6, 64, 0);
 268	ASSERT_OK(err, "field_ok");
 269
 270	test_ctx__dump_and_compare(&t,
 271"struct s___2 {\n"
 272"	enum x x;\n"
 273"	enum {\n"
 274"		Y___2 = 1,\n"
 275"	} y;\n"
 276"	struct s s;\n"
 277"};\n\n" , "c_dump1");
 278
 279	test_ctx__free(&t);
 280}
 281
 282static void test_btf_dump_type_tags(void)
 283{
 284	struct test_ctx t = {};
 285	struct btf *btf;
 286	int id, err;
 287
 288	if (test_ctx__init(&t))
 289		return;
 290
 291	btf = t.btf;
 292
 293	/* Generate BTF corresponding to the following C code:
 294	 *
 295	 * struct s {
 296	 *   void __attribute__((btf_type_tag(\"void_tag\"))) *p1;
 297	 *   void __attribute__((void_attr)) *p2;
 298	 * };
 299	 *
 300	 */
 301
 302	id = btf__add_type_tag(btf, "void_tag", 0);
 303	ASSERT_EQ(id, 1, "type_tag_id");
 304	id = btf__add_ptr(btf, id);
 305	ASSERT_EQ(id, 2, "void_ptr_id1");
 306
 307	id = btf__add_type_attr(btf, "void_attr", 0);
 308	ASSERT_EQ(id, 3, "type_attr_id");
 309	id = btf__add_ptr(btf, id);
 310	ASSERT_EQ(id, 4, "void_ptr_id2");
 311
 312	id = btf__add_struct(btf, "s", 8);
 313	ASSERT_EQ(id, 5, "struct_id");
 314	err = btf__add_field(btf, "p1", 2, 0, 0);
 315	ASSERT_OK(err, "field_ok1");
 316	err = btf__add_field(btf, "p2", 4, 0, 0);
 317	ASSERT_OK(err, "field_ok2");
 318
 319	test_ctx__dump_and_compare(&t,
 320"struct s {\n"
 321"	void __attribute__((btf_type_tag(\"void_tag\"))) *p1;\n"
 322"	void __attribute__((void_attr)) *p2;\n"
 323"};\n\n", "dump_and_compare");
 324
 325	test_ctx__free(&t);
 326}
 327
 328#define STRSIZE				4096
 329
 330static void btf_dump_snprintf(void *ctx, const char *fmt, va_list args)
 331{
 332	char *s = ctx, new[STRSIZE];
 333
 334	vsnprintf(new, STRSIZE, fmt, args);
 335	if (strlen(s) < STRSIZE)
 336		strncat(s, new, STRSIZE - strlen(s) - 1);
 337}
 338
 339static int btf_dump_data(struct btf *btf, struct btf_dump *d,
 340			 char *name, char *prefix, __u64 flags, void *ptr,
 341			 size_t ptr_sz, char *str, const char *expected_val)
 342{
 343	DECLARE_LIBBPF_OPTS(btf_dump_type_data_opts, opts);
 344	size_t type_sz;
 345	__s32 type_id;
 346	int ret = 0;
 347
 348	if (flags & BTF_F_COMPACT)
 349		opts.compact = true;
 350	if (flags & BTF_F_NONAME)
 351		opts.skip_names = true;
 352	if (flags & BTF_F_ZERO)
 353		opts.emit_zeroes = true;
 354	if (prefix) {
 355		ASSERT_STRNEQ(name, prefix, strlen(prefix),
 356			      "verify prefix match");
 357		name += strlen(prefix) + 1;
 358	}
 359	type_id = btf__find_by_name(btf, name);
 360	if (!ASSERT_GE(type_id, 0, "find type id"))
 361		return -ENOENT;
 362	type_sz = btf__resolve_size(btf, type_id);
 363	str[0] = '\0';
 364	ret = btf_dump__dump_type_data(d, type_id, ptr, ptr_sz, &opts);
 365	if (type_sz <= ptr_sz) {
 366		if (!ASSERT_EQ(ret, type_sz, "failed/unexpected type_sz"))
 367			return -EINVAL;
 368	} else {
 369		if (!ASSERT_EQ(ret, -E2BIG, "failed to return -E2BIG"))
 370			return -EINVAL;
 371	}
 372	if (!ASSERT_STREQ(str, expected_val, "ensure expected/actual match"))
 373		return -EFAULT;
 374	return 0;
 375}
 376
 377#define TEST_BTF_DUMP_DATA(_b, _d, _prefix, _str, _type, _flags,	\
 378			   _expected, ...)				\
 379	do {								\
 380		char __ptrtype[64] = #_type;				\
 381		char *_ptrtype = (char *)__ptrtype;			\
 382		_type _ptrdata = __VA_ARGS__;				\
 383		void *_ptr = &_ptrdata;					\
 384									\
 385		(void) btf_dump_data(_b, _d, _ptrtype, _prefix, _flags,	\
 386				     _ptr, sizeof(_type), _str,		\
 387				     _expected);			\
 388	} while (0)
 389
 390/* Use where expected data string matches its stringified declaration */
 391#define TEST_BTF_DUMP_DATA_C(_b, _d, _prefix,  _str, _type, _flags,	\
 392			     ...)					\
 393	TEST_BTF_DUMP_DATA(_b, _d, _prefix, _str, _type, _flags,	\
 394			   "(" #_type ")" #__VA_ARGS__,	__VA_ARGS__)
 395
 396/* overflow test; pass typesize < expected type size, ensure E2BIG returned */
 397#define TEST_BTF_DUMP_DATA_OVER(_b, _d, _prefix, _str, _type, _type_sz,	\
 398				_expected, ...)				\
 399	do {								\
 400		char __ptrtype[64] = #_type;				\
 401		char *_ptrtype = (char *)__ptrtype;			\
 402		_type _ptrdata = __VA_ARGS__;				\
 403		void *_ptr = &_ptrdata;					\
 404									\
 405		(void) btf_dump_data(_b, _d, _ptrtype, _prefix, 0,	\
 406				     _ptr, _type_sz, _str, _expected);	\
 407	} while (0)
 408
 409#define TEST_BTF_DUMP_VAR(_b, _d, _prefix, _str, _var, _type, _flags,	\
 410			  _expected, ...)				\
 411	do {								\
 412		_type _ptrdata = __VA_ARGS__;				\
 413		void *_ptr = &_ptrdata;					\
 414									\
 415		(void) btf_dump_data(_b, _d, _var, _prefix, _flags,	\
 416				     _ptr, sizeof(_type), _str,		\
 417				     _expected);			\
 418	} while (0)
 419
 420static void test_btf_dump_int_data(struct btf *btf, struct btf_dump *d,
 421				   char *str)
 422{
 423#ifdef __SIZEOF_INT128__
 424	unsigned __int128 i = 0xffffffffffffffff;
 425
 426	/* this dance is required because we cannot directly initialize
 427	 * a 128-bit value to anything larger than a 64-bit value.
 428	 */
 429	i = (i << 64) | (i - 1);
 430#endif
 431	/* simple int */
 432	TEST_BTF_DUMP_DATA_C(btf, d, NULL, str, int, BTF_F_COMPACT, 1234);
 433	TEST_BTF_DUMP_DATA(btf, d, NULL, str, int, BTF_F_COMPACT | BTF_F_NONAME,
 434			   "1234", 1234);
 435	TEST_BTF_DUMP_DATA(btf, d, NULL, str, int, 0, "(int)1234", 1234);
 436
 437	/* zero value should be printed at toplevel */
 438	TEST_BTF_DUMP_DATA(btf, d, NULL, str, int, BTF_F_COMPACT, "(int)0", 0);
 439	TEST_BTF_DUMP_DATA(btf, d, NULL, str, int, BTF_F_COMPACT | BTF_F_NONAME,
 440			   "0", 0);
 441	TEST_BTF_DUMP_DATA(btf, d, NULL, str, int, BTF_F_COMPACT | BTF_F_ZERO,
 442			   "(int)0", 0);
 443	TEST_BTF_DUMP_DATA(btf, d, NULL, str, int,
 444			   BTF_F_COMPACT | BTF_F_NONAME | BTF_F_ZERO,
 445			   "0", 0);
 446	TEST_BTF_DUMP_DATA_C(btf, d, NULL, str, int, BTF_F_COMPACT, -4567);
 447	TEST_BTF_DUMP_DATA(btf, d, NULL, str, int, BTF_F_COMPACT | BTF_F_NONAME,
 448			   "-4567", -4567);
 449	TEST_BTF_DUMP_DATA(btf, d, NULL, str, int, 0, "(int)-4567", -4567);
 450
 451	TEST_BTF_DUMP_DATA_OVER(btf, d, NULL, str, int, sizeof(int)-1, "", 1);
 452
 453#ifdef __SIZEOF_INT128__
 454	/* gcc encode unsigned __int128 type with name "__int128 unsigned" in dwarf,
 455	 * and clang encode it with name "unsigned __int128" in dwarf.
 456	 * Do an availability test for either variant before doing actual test.
 457	 */
 458	if (btf__find_by_name(btf, "unsigned __int128") > 0) {
 459		TEST_BTF_DUMP_DATA(btf, d, NULL, str, unsigned __int128, BTF_F_COMPACT,
 460				   "(unsigned __int128)0xffffffffffffffff",
 461				   0xffffffffffffffff);
 462		ASSERT_OK(btf_dump_data(btf, d, "unsigned __int128", NULL, 0, &i, 16, str,
 463					"(unsigned __int128)0xfffffffffffffffffffffffffffffffe"),
 464			  "dump unsigned __int128");
 465	} else if (btf__find_by_name(btf, "__int128 unsigned") > 0) {
 466		TEST_BTF_DUMP_DATA(btf, d, NULL, str, __int128 unsigned, BTF_F_COMPACT,
 467				   "(__int128 unsigned)0xffffffffffffffff",
 468				   0xffffffffffffffff);
 469		ASSERT_OK(btf_dump_data(btf, d, "__int128 unsigned", NULL, 0, &i, 16, str,
 470					"(__int128 unsigned)0xfffffffffffffffffffffffffffffffe"),
 471			  "dump unsigned __int128");
 472	} else {
 473		ASSERT_TRUE(false, "unsigned_int128_not_found");
 474	}
 475#endif
 476}
 477
 478static void test_btf_dump_float_data(struct btf *btf, struct btf_dump *d,
 479				     char *str)
 480{
 481	float t1 = 1.234567;
 482	float t2 = -1.234567;
 483	float t3 = 0.0;
 484	double t4 = 5.678912;
 485	double t5 = -5.678912;
 486	double t6 = 0.0;
 487	long double t7 = 9.876543;
 488	long double t8 = -9.876543;
 489	long double t9 = 0.0;
 490
 491	/* since the kernel does not likely have any float types in its BTF, we
 492	 * will need to add some of various sizes.
 493	 */
 494
 495	ASSERT_GT(btf__add_float(btf, "test_float", 4), 0, "add float");
 496	ASSERT_OK(btf_dump_data(btf, d, "test_float", NULL, 0, &t1, 4, str,
 497				"(test_float)1.234567"), "dump float");
 498	ASSERT_OK(btf_dump_data(btf, d, "test_float", NULL, 0, &t2, 4, str,
 499				"(test_float)-1.234567"), "dump float");
 500	ASSERT_OK(btf_dump_data(btf, d, "test_float", NULL, 0, &t3, 4, str,
 501				"(test_float)0.000000"), "dump float");
 502
 503	ASSERT_GT(btf__add_float(btf, "test_double", 8), 0, "add_double");
 504	ASSERT_OK(btf_dump_data(btf, d, "test_double", NULL, 0, &t4, 8, str,
 505		  "(test_double)5.678912"), "dump double");
 506	ASSERT_OK(btf_dump_data(btf, d, "test_double", NULL, 0, &t5, 8, str,
 507		  "(test_double)-5.678912"), "dump double");
 508	ASSERT_OK(btf_dump_data(btf, d, "test_double", NULL, 0, &t6, 8, str,
 509				"(test_double)0.000000"), "dump double");
 510
 511	ASSERT_GT(btf__add_float(btf, "test_long_double", 16), 0, "add long double");
 512	ASSERT_OK(btf_dump_data(btf, d, "test_long_double", NULL, 0, &t7, 16,
 513				str, "(test_long_double)9.876543"),
 514				"dump long_double");
 515	ASSERT_OK(btf_dump_data(btf, d, "test_long_double", NULL, 0, &t8, 16,
 516				str, "(test_long_double)-9.876543"),
 517				"dump long_double");
 518	ASSERT_OK(btf_dump_data(btf, d, "test_long_double", NULL, 0, &t9, 16,
 519				str, "(test_long_double)0.000000"),
 520				"dump long_double");
 521}
 522
 523static void test_btf_dump_char_data(struct btf *btf, struct btf_dump *d,
 524				    char *str)
 525{
 526	/* simple char */
 527	TEST_BTF_DUMP_DATA_C(btf, d, NULL, str, char, BTF_F_COMPACT, 100);
 528	TEST_BTF_DUMP_DATA(btf, d, NULL, str, char, BTF_F_COMPACT | BTF_F_NONAME,
 529			   "100", 100);
 530	TEST_BTF_DUMP_DATA(btf, d, NULL, str, char, 0, "(char)100", 100);
 531	/* zero value should be printed at toplevel */
 532	TEST_BTF_DUMP_DATA(btf, d, NULL, str, char, BTF_F_COMPACT,
 533			   "(char)0", 0);
 534	TEST_BTF_DUMP_DATA(btf, d, NULL, str, char, BTF_F_COMPACT | BTF_F_NONAME,
 535			   "0", 0);
 536	TEST_BTF_DUMP_DATA(btf, d, NULL, str, char, BTF_F_COMPACT | BTF_F_ZERO,
 537			   "(char)0", 0);
 538	TEST_BTF_DUMP_DATA(btf, d, NULL, str, char, BTF_F_COMPACT | BTF_F_NONAME | BTF_F_ZERO,
 539			   "0", 0);
 540	TEST_BTF_DUMP_DATA(btf, d, NULL, str, char, 0, "(char)0", 0);
 541
 542	TEST_BTF_DUMP_DATA_OVER(btf, d, NULL, str, char, sizeof(char)-1, "", 100);
 543}
 544
 545static void test_btf_dump_typedef_data(struct btf *btf, struct btf_dump *d,
 546				       char *str)
 547{
 548	/* simple typedef */
 549	TEST_BTF_DUMP_DATA_C(btf, d, NULL, str, uint64_t, BTF_F_COMPACT, 100);
 550	TEST_BTF_DUMP_DATA(btf, d, NULL, str, u64, BTF_F_COMPACT | BTF_F_NONAME,
 551			   "1", 1);
 552	TEST_BTF_DUMP_DATA(btf, d, NULL, str, u64, 0, "(u64)1", 1);
 553	/* zero value should be printed at toplevel */
 554	TEST_BTF_DUMP_DATA(btf, d, NULL, str, u64, BTF_F_COMPACT, "(u64)0", 0);
 555	TEST_BTF_DUMP_DATA(btf, d, NULL, str, u64, BTF_F_COMPACT | BTF_F_NONAME,
 556			   "0", 0);
 557	TEST_BTF_DUMP_DATA(btf, d, NULL, str, u64, BTF_F_COMPACT | BTF_F_ZERO,
 558			   "(u64)0", 0);
 559	TEST_BTF_DUMP_DATA(btf, d, NULL, str, u64,
 560			   BTF_F_COMPACT | BTF_F_NONAME | BTF_F_ZERO,
 561			   "0", 0);
 562	TEST_BTF_DUMP_DATA(btf, d, NULL, str, u64, 0, "(u64)0", 0);
 563
 564	/* typedef struct */
 565	TEST_BTF_DUMP_DATA_C(btf, d, NULL, str, atomic_t, BTF_F_COMPACT,
 566			     {.counter = (int)1,});
 567	TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t, BTF_F_COMPACT | BTF_F_NONAME,
 568			   "{1,}", { .counter = 1 });
 569	TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t, 0,
 570"(atomic_t){\n"
 571"	.counter = (int)1,\n"
 572"}",
 573			   {.counter = 1,});
 574	/* typedef with 0 value should be printed at toplevel */
 575	TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t, BTF_F_COMPACT, "(atomic_t){}",
 576			   {.counter = 0,});
 577	TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t, BTF_F_COMPACT | BTF_F_NONAME,
 578			   "{}", {.counter = 0,});
 579	TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t, 0,
 580"(atomic_t){\n"
 581"}",
 582			   {.counter = 0,});
 583	TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t, BTF_F_COMPACT | BTF_F_ZERO,
 584			   "(atomic_t){.counter = (int)0,}",
 585			   {.counter = 0,});
 586	TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t,
 587			   BTF_F_COMPACT | BTF_F_NONAME | BTF_F_ZERO,
 588			   "{0,}", {.counter = 0,});
 589	TEST_BTF_DUMP_DATA(btf, d, NULL, str, atomic_t, BTF_F_ZERO,
 590"(atomic_t){\n"
 591"	.counter = (int)0,\n"
 592"}",
 593			   { .counter = 0,});
 594
 595	/* overflow should show type but not value since it overflows */
 596	TEST_BTF_DUMP_DATA_OVER(btf, d, NULL, str, atomic_t, sizeof(atomic_t)-1,
 597				"(atomic_t){\n", { .counter = 1});
 598}
 599
 600static void test_btf_dump_enum_data(struct btf *btf, struct btf_dump *d,
 601				    char *str)
 602{
 603	/* enum where enum value does (and does not) exist */
 604	TEST_BTF_DUMP_DATA_C(btf, d, "enum", str, enum bpf_cmd, BTF_F_COMPACT,
 605			     BPF_MAP_CREATE);
 606	TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd, BTF_F_COMPACT,
 607			   "(enum bpf_cmd)BPF_MAP_CREATE", 0);
 608	TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd,
 609			   BTF_F_COMPACT | BTF_F_NONAME,
 610			   "BPF_MAP_CREATE",
 611			   BPF_MAP_CREATE);
 612	TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd, 0,
 613			   "(enum bpf_cmd)BPF_MAP_CREATE",
 614			   BPF_MAP_CREATE);
 615	TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd,
 616			   BTF_F_COMPACT | BTF_F_NONAME | BTF_F_ZERO,
 617			   "BPF_MAP_CREATE", 0);
 618	TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd,
 619			   BTF_F_COMPACT | BTF_F_ZERO,
 620			   "(enum bpf_cmd)BPF_MAP_CREATE",
 621			   BPF_MAP_CREATE);
 622	TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd,
 623			   BTF_F_COMPACT | BTF_F_NONAME | BTF_F_ZERO,
 624			   "BPF_MAP_CREATE", BPF_MAP_CREATE);
 625	TEST_BTF_DUMP_DATA_C(btf, d, "enum", str, enum bpf_cmd, BTF_F_COMPACT, 2000);
 626	TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd,
 627			   BTF_F_COMPACT | BTF_F_NONAME,
 628			   "2000", 2000);
 629	TEST_BTF_DUMP_DATA(btf, d, "enum", str, enum bpf_cmd, 0,
 630			   "(enum bpf_cmd)2000", 2000);
 631
 632	TEST_BTF_DUMP_DATA_OVER(btf, d, "enum", str, enum bpf_cmd,
 633				sizeof(enum bpf_cmd) - 1, "", BPF_MAP_CREATE);
 634}
 635
 636static void test_btf_dump_struct_data(struct btf *btf, struct btf_dump *d,
 637				      char *str)
 638{
 639	DECLARE_LIBBPF_OPTS(btf_dump_type_data_opts, opts);
 640	char zero_data[512] = { };
 641	char type_data[512];
 642	void *fops = type_data;
 643	void *skb = type_data;
 644	size_t type_sz;
 645	__s32 type_id;
 646	char *cmpstr;
 647	int ret;
 648
 649	memset(type_data, 255, sizeof(type_data));
 650
 651	/* simple struct */
 652	TEST_BTF_DUMP_DATA_C(btf, d, "struct", str, struct btf_enum, BTF_F_COMPACT,
 653			     {.name_off = (__u32)3,.val = (__s32)-1,});
 654	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum,
 655			   BTF_F_COMPACT | BTF_F_NONAME,
 656			   "{3,-1,}",
 657			   { .name_off = 3, .val = -1,});
 658	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum, 0,
 659"(struct btf_enum){\n"
 660"	.name_off = (__u32)3,\n"
 661"	.val = (__s32)-1,\n"
 662"}",
 663			   { .name_off = 3, .val = -1,});
 664	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum,
 665			   BTF_F_COMPACT | BTF_F_NONAME,
 666			   "{-1,}",
 667			   { .name_off = 0, .val = -1,});
 668	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum,
 669			   BTF_F_COMPACT | BTF_F_NONAME | BTF_F_ZERO,
 670			   "{0,-1,}",
 671			   { .name_off = 0, .val = -1,});
 672	/* empty struct should be printed */
 673	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum, BTF_F_COMPACT,
 674			   "(struct btf_enum){}",
 675			   { .name_off = 0, .val = 0,});
 676	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum,
 677			   BTF_F_COMPACT | BTF_F_NONAME,
 678			   "{}",
 679			   { .name_off = 0, .val = 0,});
 680	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum, 0,
 681"(struct btf_enum){\n"
 682"}",
 683			   { .name_off = 0, .val = 0,});
 684	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum,
 685			   BTF_F_COMPACT | BTF_F_ZERO,
 686			   "(struct btf_enum){.name_off = (__u32)0,.val = (__s32)0,}",
 687			   { .name_off = 0, .val = 0,});
 688	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct btf_enum,
 689			   BTF_F_ZERO,
 690"(struct btf_enum){\n"
 691"	.name_off = (__u32)0,\n"
 692"	.val = (__s32)0,\n"
 693"}",
 694			   { .name_off = 0, .val = 0,});
 695
 696	/* struct with pointers */
 697	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct list_head, BTF_F_COMPACT,
 698			   "(struct list_head){.next = (struct list_head *)0x1,}",
 699			   { .next = (struct list_head *)1 });
 700	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct list_head, 0,
 701"(struct list_head){\n"
 702"	.next = (struct list_head *)0x1,\n"
 703"}",
 704			   { .next = (struct list_head *)1 });
 705	/* NULL pointer should not be displayed */
 706	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct list_head, BTF_F_COMPACT,
 707			   "(struct list_head){}",
 708			   { .next = (struct list_head *)0 });
 709	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct list_head, 0,
 710"(struct list_head){\n"
 711"}",
 712			   { .next = (struct list_head *)0 });
 713
 714	/* struct with function pointers */
 715	type_id = btf__find_by_name(btf, "file_operations");
 716	if (ASSERT_GT(type_id, 0, "find type id")) {
 717		type_sz = btf__resolve_size(btf, type_id);
 718		str[0] = '\0';
 719
 720		ret = btf_dump__dump_type_data(d, type_id, fops, type_sz, &opts);
 721		ASSERT_EQ(ret, type_sz,
 722			  "unexpected return value dumping file_operations");
 723		cmpstr =
 724"(struct file_operations){\n"
 725"	.owner = (struct module *)0xffffffffffffffff,\n"
 726"	.fop_flags = (fop_flags_t)4294967295,";
 727
 728		ASSERT_STRNEQ(str, cmpstr, strlen(cmpstr), "file_operations");
 729	}
 730
 731	/* struct with char array */
 732	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_prog_info, BTF_F_COMPACT,
 733			   "(struct bpf_prog_info){.name = (char[16])['f','o','o',],}",
 734			   { .name = "foo",});
 735	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_prog_info,
 736			   BTF_F_COMPACT | BTF_F_NONAME,
 737			   "{['f','o','o',],}",
 738			   {.name = "foo",});
 739	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_prog_info, 0,
 740"(struct bpf_prog_info){\n"
 741"	.name = (char[16])[\n"
 742"		'f',\n"
 743"		'o',\n"
 744"		'o',\n"
 745"	],\n"
 746"}",
 747			   {.name = "foo",});
 748	/* leading null char means do not display string */
 749	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_prog_info, BTF_F_COMPACT,
 750			   "(struct bpf_prog_info){}",
 751			   {.name = {'\0', 'f', 'o', 'o'}});
 752	/* handle non-printable characters */
 753	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_prog_info, BTF_F_COMPACT,
 754			   "(struct bpf_prog_info){.name = (char[16])[1,2,3,],}",
 755			   { .name = {1, 2, 3, 0}});
 756
 757	/* struct with non-char array */
 758	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct __sk_buff, BTF_F_COMPACT,
 759			   "(struct __sk_buff){.cb = (__u32[5])[1,2,3,4,5,],}",
 760			   { .cb = {1, 2, 3, 4, 5,},});
 761	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct __sk_buff,
 762			   BTF_F_COMPACT | BTF_F_NONAME,
 763			   "{[1,2,3,4,5,],}",
 764			   { .cb = { 1, 2, 3, 4, 5},});
 765	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct __sk_buff, 0,
 766"(struct __sk_buff){\n"
 767"	.cb = (__u32[5])[\n"
 768"		1,\n"
 769"		2,\n"
 770"		3,\n"
 771"		4,\n"
 772"		5,\n"
 773"	],\n"
 774"}",
 775			   { .cb = { 1, 2, 3, 4, 5},});
 776	/* For non-char, arrays, show non-zero values only */
 777	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct __sk_buff, BTF_F_COMPACT,
 778			   "(struct __sk_buff){.cb = (__u32[5])[0,0,1,0,0,],}",
 779			   { .cb = { 0, 0, 1, 0, 0},});
 780	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct __sk_buff, 0,
 781"(struct __sk_buff){\n"
 782"	.cb = (__u32[5])[\n"
 783"		0,\n"
 784"		0,\n"
 785"		1,\n"
 786"		0,\n"
 787"		0,\n"
 788"	],\n"
 789"}",
 790			   { .cb = { 0, 0, 1, 0, 0},});
 791
 792	/* struct with bitfields */
 793	TEST_BTF_DUMP_DATA_C(btf, d, "struct", str, struct bpf_insn, BTF_F_COMPACT,
 794		{.code = (__u8)1,.dst_reg = (__u8)0x2,.src_reg = (__u8)0x3,.off = (__s16)4,.imm = (__s32)5,});
 795	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_insn,
 796			   BTF_F_COMPACT | BTF_F_NONAME,
 797			   "{1,0x2,0x3,4,5,}",
 798			   { .code = 1, .dst_reg = 0x2, .src_reg = 0x3, .off = 4,
 799			     .imm = 5,});
 800	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_insn, 0,
 801"(struct bpf_insn){\n"
 802"	.code = (__u8)1,\n"
 803"	.dst_reg = (__u8)0x2,\n"
 804"	.src_reg = (__u8)0x3,\n"
 805"	.off = (__s16)4,\n"
 806"	.imm = (__s32)5,\n"
 807"}",
 808			   {.code = 1, .dst_reg = 2, .src_reg = 3, .off = 4, .imm = 5});
 809
 810	/* zeroed bitfields should not be displayed */
 811	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_insn, BTF_F_COMPACT,
 812			   "(struct bpf_insn){.dst_reg = (__u8)0x1,}",
 813			   { .code = 0, .dst_reg = 1});
 814
 815	/* struct with enum bitfield */
 816	type_id = btf__find_by_name(btf, "fs_context");
 817	if (ASSERT_GT(type_id,  0, "find fs_context")) {
 818		type_sz = btf__resolve_size(btf, type_id);
 819		str[0] = '\0';
 820
 821		opts.emit_zeroes = true;
 822		ret = btf_dump__dump_type_data(d, type_id, zero_data, type_sz, &opts);
 823		ASSERT_EQ(ret, type_sz,
 824			  "unexpected return value dumping fs_context");
 825
 826		ASSERT_NEQ(strstr(str, "FS_CONTEXT_FOR_MOUNT"), NULL,
 827				  "bitfield value not present");
 828	}
 829
 830	/* struct with nested anon union */
 831	TEST_BTF_DUMP_DATA(btf, d, "struct", str, struct bpf_sock_ops, BTF_F_COMPACT,
 832			   "(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,],},}",
 833			   { .op = 1, .args = { 1, 2, 3, 4}});
 834
 835	/* union with nested struct */
 836	TEST_BTF_DUMP_DATA(btf, d, "union", str, union bpf_iter_link_info, BTF_F_COMPACT,
 837			   "(union bpf_iter_link_info){.map = (struct){.map_fd = (__u32)1,},.cgroup = (struct){.order = (enum bpf_cgroup_iter_order)BPF_CGROUP_ITER_SELF_ONLY,.cgroup_fd = (__u32)1,},.task = (struct){.tid = (__u32)1,.pid = (__u32)1,},}",
 838			   { .cgroup = { .order = 1, .cgroup_fd = 1, }});
 839
 840	/* struct skb with nested structs/unions; because type output is so
 841	 * complex, we don't do a string comparison, just verify we return
 842	 * the type size as the amount of data displayed.
 843	 */
 844	type_id = btf__find_by_name(btf, "sk_buff");
 845	if (ASSERT_GT(type_id, 0, "find struct sk_buff")) {
 846		type_sz = btf__resolve_size(btf, type_id);
 847		str[0] = '\0';
 848
 849		ret = btf_dump__dump_type_data(d, type_id, skb, type_sz, &opts);
 850		ASSERT_EQ(ret, type_sz,
 851			  "unexpected return value dumping sk_buff");
 852	}
 853
 854	/* overflow bpf_sock_ops struct with final element nonzero/zero.
 855	 * Regardless of the value of the final field, we don't have all the
 856	 * data we need to display it, so we should trigger an overflow.
 857	 * In other words overflow checking should trump "is field zero?"
 858	 * checks because if we've overflowed, it shouldn't matter what the
 859	 * field is - we can't trust its value so shouldn't display it.
 860	 */
 861	TEST_BTF_DUMP_DATA_OVER(btf, d, "struct", str, struct bpf_sock_ops,
 862				sizeof(struct bpf_sock_ops) - 1,
 863				"(struct bpf_sock_ops){\n\t.op = (__u32)1,\n",
 864				{ .op = 1, .skb_hwtstamp = 2});
 865	TEST_BTF_DUMP_DATA_OVER(btf, d, "struct", str, struct bpf_sock_ops,
 866				sizeof(struct bpf_sock_ops) - 1,
 867				"(struct bpf_sock_ops){\n\t.op = (__u32)1,\n",
 868				{ .op = 1, .skb_hwtstamp = 0});
 869}
 870
 871static void test_btf_dump_var_data(struct btf *btf, struct btf_dump *d,
 872				   char *str)
 873{
 874#if 0
 875	TEST_BTF_DUMP_VAR(btf, d, NULL, str, "cpu_number", int, BTF_F_COMPACT,
 876			  "int cpu_number = (int)100", 100);
 877#endif
 878	TEST_BTF_DUMP_VAR(btf, d, NULL, str, "bpf_cgrp_storage_busy", int, BTF_F_COMPACT,
 879			  "static int bpf_cgrp_storage_busy = (int)2", 2);
 880}
 881
 882struct btf_dump_string_ctx {
 883	struct btf *btf;
 884	struct btf_dump *d;
 885	char *str;
 886	struct btf_dump_type_data_opts *opts;
 887	int array_id;
 888};
 889
 890static int btf_dump_one_string(struct btf_dump_string_ctx *ctx,
 891			       char *ptr, size_t ptr_sz,
 892			       const char *expected_val)
 893{
 894	size_t type_sz;
 895	int ret;
 896
 897	ctx->str[0] = '\0';
 898	type_sz = btf__resolve_size(ctx->btf, ctx->array_id);
 899	ret = btf_dump__dump_type_data(ctx->d, ctx->array_id, ptr, ptr_sz, ctx->opts);
 900	if (type_sz <= ptr_sz) {
 901		if (!ASSERT_EQ(ret, type_sz, "failed/unexpected type_sz"))
 902			return -EINVAL;
 903	}
 904	if (!ASSERT_STREQ(ctx->str, expected_val, "ensure expected/actual match"))
 905		return -EFAULT;
 906	return 0;
 907}
 908
 909static void btf_dump_strings(struct btf_dump_string_ctx *ctx)
 910{
 911	struct btf_dump_type_data_opts *opts = ctx->opts;
 912
 913	opts->emit_strings = true;
 914
 915	opts->compact = true;
 916	opts->emit_zeroes = false;
 917
 918	opts->skip_names = false;
 919	btf_dump_one_string(ctx, "foo", 4, "(char[4])\"foo\"");
 920
 921	opts->skip_names = true;
 922	btf_dump_one_string(ctx, "foo", 4, "\"foo\"");
 923
 924	/* This should have no effect. */
 925	opts->emit_zeroes = false;
 926	btf_dump_one_string(ctx, "foo", 4, "\"foo\"");
 927
 928	/* This should have no effect. */
 929	opts->compact = false;
 930	btf_dump_one_string(ctx, "foo", 4, "\"foo\"");
 931
 932	/* Non-printable characters come out as hex. */
 933	btf_dump_one_string(ctx, "fo\xff", 4, "\"fo\\xff\"");
 934	btf_dump_one_string(ctx, "fo\x7", 4, "\"fo\\x07\"");
 935
 936	/*
 937	 * Strings that are too long for the specified type ("char[4]")
 938	 * should fall back to the current behavior.
 939	 */
 940	opts->compact = true;
 941	btf_dump_one_string(ctx, "abcde", 6, "['a','b','c','d',]");
 942
 943	/*
 944	 * Strings that are too short for the specified type ("char[4]")
 945	 * should work normally.
 946	 */
 947	btf_dump_one_string(ctx, "ab", 3, "\"ab\"");
 948
 949	/* Non-NUL-terminated arrays don't get printed as strings. */
 950	char food[4] = { 'f', 'o', 'o', 'd' };
 951	char bye[3] = { 'b', 'y', 'e' };
 952
 953	btf_dump_one_string(ctx, food, 4, "['f','o','o','d',]");
 954	btf_dump_one_string(ctx, bye, 3, "['b','y','e',]");
 955
 956	/* The embedded NUL should terminate the string. */
 957	char embed[4] = { 'f', 'o', '\0', 'd' };
 958
 959	btf_dump_one_string(ctx, embed, 4, "\"fo\"");
 960}
 961
 962static void test_btf_dump_string_data(void)
 963{
 964	struct test_ctx t = {};
 965	char str[STRSIZE];
 966	struct btf_dump *d;
 967	DECLARE_LIBBPF_OPTS(btf_dump_type_data_opts, opts);
 968	struct btf_dump_string_ctx ctx;
 969	int char_id, int_id, array_id;
 970
 971	if (test_ctx__init(&t))
 972		return;
 973
 974	d = btf_dump__new(t.btf, btf_dump_snprintf, str, NULL);
 975	if (!ASSERT_OK_PTR(d, "could not create BTF dump"))
 976		return;
 977
 978	/* Generate BTF for a four-element char array. */
 979	char_id = btf__add_int(t.btf, "char", 1, BTF_INT_CHAR);
 980	ASSERT_EQ(char_id, 1, "char_id");
 981	int_id = btf__add_int(t.btf, "int", 4, BTF_INT_SIGNED);
 982	ASSERT_EQ(int_id, 2, "int_id");
 983	array_id = btf__add_array(t.btf, int_id, char_id, 4);
 984	ASSERT_EQ(array_id, 3, "array_id");
 985
 986	ctx.btf = t.btf;
 987	ctx.d = d;
 988	ctx.str = str;
 989	ctx.opts = &opts;
 990	ctx.array_id = array_id;
 991
 992	btf_dump_strings(&ctx);
 993
 994	btf_dump__free(d);
 995	test_ctx__free(&t);
 996}
 997
 998static void test_btf_datasec(struct btf *btf, struct btf_dump *d, char *str,
 999			     const char *name, const char *expected_val,
1000			     void *data, size_t data_sz)
1001{
1002	DECLARE_LIBBPF_OPTS(btf_dump_type_data_opts, opts);
1003	int ret = 0, cmp;
1004	size_t secsize;
1005	__s32 type_id;
1006
1007	opts.compact = true;
1008
1009	type_id = btf__find_by_name(btf, name);
1010	if (!ASSERT_GT(type_id, 0, "find type id"))
1011		return;
1012
1013	secsize = btf__resolve_size(btf, type_id);
1014	ASSERT_EQ(secsize,  0, "verify section size");
1015
1016	str[0] = '\0';
1017	ret = btf_dump__dump_type_data(d, type_id, data, data_sz, &opts);
1018	ASSERT_EQ(ret, 0, "unexpected return value");
1019
1020	cmp = strcmp(str, expected_val);
1021	ASSERT_EQ(cmp, 0, "ensure expected/actual match");
1022}
1023
1024static void test_btf_dump_datasec_data(char *str)
1025{
1026	struct btf *btf;
1027	char license[4] = "GPL";
1028	struct btf_dump *d;
1029
1030	btf = btf__parse("xdping_kern.bpf.o", NULL);
1031	if (!ASSERT_OK_PTR(btf, "xdping_kern.bpf.o BTF not found"))
1032		return;
1033
1034	d = btf_dump__new(btf, btf_dump_snprintf, str, NULL);
1035	if (!ASSERT_OK_PTR(d, "could not create BTF dump"))
1036		goto out;
1037
1038	test_btf_datasec(btf, d, str, "license",
1039			 "SEC(\"license\") char[4] _license = (char[4])['G','P','L',];",
1040			 license, sizeof(license));
1041out:
1042	btf_dump__free(d);
1043	btf__free(btf);
1044}
1045
1046void test_btf_dump() {
1047	char str[STRSIZE];
1048	struct btf_dump *d;
1049	struct btf *btf;
1050	int i;
1051
1052	for (i = 0; i < ARRAY_SIZE(btf_dump_test_cases); i++) {
1053		struct btf_dump_test_case *t = &btf_dump_test_cases[i];
1054
1055		if (!test__start_subtest(t->name))
1056			continue;
1057
1058		test_btf_dump_case(i, &btf_dump_test_cases[i]);
1059	}
1060	if (test__start_subtest("btf_dump: incremental"))
1061		test_btf_dump_incremental();
1062
1063	if (test__start_subtest("btf_dump: type_tags"))
1064		test_btf_dump_type_tags();
1065
1066	btf = libbpf_find_kernel_btf();
1067	if (!ASSERT_OK_PTR(btf, "no kernel BTF found"))
1068		return;
1069
1070	d = btf_dump__new(btf, btf_dump_snprintf, str, NULL);
1071	if (!ASSERT_OK_PTR(d, "could not create BTF dump"))
1072		return;
1073
1074	/* Verify type display for various types. */
1075	if (test__start_subtest("btf_dump: int_data"))
1076		test_btf_dump_int_data(btf, d, str);
1077	if (test__start_subtest("btf_dump: float_data"))
1078		test_btf_dump_float_data(btf, d, str);
1079	if (test__start_subtest("btf_dump: char_data"))
1080		test_btf_dump_char_data(btf, d, str);
1081	if (test__start_subtest("btf_dump: typedef_data"))
1082		test_btf_dump_typedef_data(btf, d, str);
1083	if (test__start_subtest("btf_dump: enum_data"))
1084		test_btf_dump_enum_data(btf, d, str);
1085	if (test__start_subtest("btf_dump: struct_data"))
1086		test_btf_dump_struct_data(btf, d, str);
1087	if (test__start_subtest("btf_dump: var_data"))
1088		test_btf_dump_var_data(btf, d, str);
1089	if (test__start_subtest("btf_dump: string_data"))
1090		test_btf_dump_string_data();
1091	btf_dump__free(d);
1092	btf__free(btf);
1093
1094	if (test__start_subtest("btf_dump: datasec_data"))
1095		test_btf_dump_datasec_data(str);
1096}
~/ Read-only file preview.