xref: /linux/tools/testing/selftests/bpf/prog_tests/btf_kind.c (revision 0fc8f6200d2313278fbf4539bbab74677c685531)
1*04674916SAlan Maguire // SPDX-License-Identifier: GPL-2.0
2*04674916SAlan Maguire /* Copyright (c) 2026, Oracle and/or its affiliates. */
3*04674916SAlan Maguire 
4*04674916SAlan Maguire #include <test_progs.h>
5*04674916SAlan Maguire #include <bpf/btf.h>
6*04674916SAlan Maguire #include <bpf/libbpf.h>
7*04674916SAlan Maguire 
8*04674916SAlan Maguire /* Verify kind encoding exists for each kind */
9*04674916SAlan Maguire static void test_btf_kind_encoding(void)
10*04674916SAlan Maguire {
11*04674916SAlan Maguire 	LIBBPF_OPTS(btf_new_opts, opts);
12*04674916SAlan Maguire 	const struct btf_header *hdr;
13*04674916SAlan Maguire 	const void *raw_btf;
14*04674916SAlan Maguire 	struct btf *btf;
15*04674916SAlan Maguire 	__u32 raw_size;
16*04674916SAlan Maguire 
17*04674916SAlan Maguire 	opts.add_layout = true;
18*04674916SAlan Maguire 	btf = btf__new_empty_opts(&opts);
19*04674916SAlan Maguire 	if (!ASSERT_OK_PTR(btf, "btf_new"))
20*04674916SAlan Maguire 		return;
21*04674916SAlan Maguire 
22*04674916SAlan Maguire 	raw_btf = btf__raw_data(btf, &raw_size);
23*04674916SAlan Maguire 	if (!ASSERT_OK_PTR(raw_btf, "btf__raw_data"))
24*04674916SAlan Maguire 		return;
25*04674916SAlan Maguire 
26*04674916SAlan Maguire 	hdr = raw_btf;
27*04674916SAlan Maguire 
28*04674916SAlan Maguire 	ASSERT_EQ(hdr->layout_off % 4, 0, "layout_aligned");
29*04674916SAlan Maguire 	ASSERT_EQ(hdr->layout_len, sizeof(struct btf_layout) * NR_BTF_KINDS,
30*04674916SAlan Maguire 		  "layout_len");
31*04674916SAlan Maguire 	ASSERT_EQ(hdr->str_off, hdr->layout_off + hdr->layout_len, "str_after_layout");
32*04674916SAlan Maguire 	btf__free(btf);
33*04674916SAlan Maguire 
34*04674916SAlan Maguire 	opts.add_layout = false;
35*04674916SAlan Maguire 	btf = btf__new_empty_opts(&opts);
36*04674916SAlan Maguire 	if (!ASSERT_OK_PTR(btf, "btf_new"))
37*04674916SAlan Maguire 		return;
38*04674916SAlan Maguire 
39*04674916SAlan Maguire 	raw_btf = btf__raw_data(btf, &raw_size);
40*04674916SAlan Maguire 	if (!ASSERT_OK_PTR(raw_btf, "btf__raw_data"))
41*04674916SAlan Maguire 		return;
42*04674916SAlan Maguire 
43*04674916SAlan Maguire 	hdr = raw_btf;
44*04674916SAlan Maguire 
45*04674916SAlan Maguire 	ASSERT_EQ(hdr->layout_off, 0, "no_layout_off");
46*04674916SAlan Maguire 	ASSERT_EQ(hdr->layout_len, 0, "no_layout_len");
47*04674916SAlan Maguire 	ASSERT_EQ(hdr->str_off, hdr->type_off + hdr->type_len, "strs_after_types");
48*04674916SAlan Maguire 	btf__free(btf);
49*04674916SAlan Maguire }
50*04674916SAlan Maguire 
51*04674916SAlan Maguire static int write_raw_btf(void *raw_btf, size_t raw_size, char *file)
52*04674916SAlan Maguire {
53*04674916SAlan Maguire 	int fd = mkstemp(file);
54*04674916SAlan Maguire 	ssize_t n;
55*04674916SAlan Maguire 
56*04674916SAlan Maguire 	if (!ASSERT_OK_FD(fd, "open_raw_btf"))
57*04674916SAlan Maguire 		return -1;
58*04674916SAlan Maguire 	n = write(fd, raw_btf, raw_size);
59*04674916SAlan Maguire 	close(fd);
60*04674916SAlan Maguire 	if (!ASSERT_EQ(n, (ssize_t)raw_size, "write_raw_btf"))
61*04674916SAlan Maguire 		return -1;
62*04674916SAlan Maguire 	return 0;
63*04674916SAlan Maguire }
64*04674916SAlan Maguire 
65*04674916SAlan Maguire /*
66*04674916SAlan Maguire  * Fabricate an unrecognized kind at BTF_KIND_MAX + 1, and after adding
67*04674916SAlan Maguire  * the appropriate struct/typedefs to the BTF such that it recognizes
68*04674916SAlan Maguire  * this kind, ensure that parsing of BTF containing the unrecognized kind
69*04674916SAlan Maguire  * can succeed.
70*04674916SAlan Maguire  */
71*04674916SAlan Maguire void test_btf_kind_decoding(void)
72*04674916SAlan Maguire {
73*04674916SAlan Maguire 	char btf_kind_file1[] = "/tmp/test_btf_kind.XXXXXX";
74*04674916SAlan Maguire 	char btf_kind_file2[] = "/tmp/test_btf_kind.XXXXXX";
75*04674916SAlan Maguire 	char btf_kind_file3[] = "/tmp/test_btf_kind.XXXXXX";
76*04674916SAlan Maguire 	struct btf *btf = NULL, *new_btf = NULL;
77*04674916SAlan Maguire 	__s32 int_id, unrec_id, id, id2;
78*04674916SAlan Maguire 	LIBBPF_OPTS(btf_new_opts, opts);
79*04674916SAlan Maguire 	struct btf_layout *l;
80*04674916SAlan Maguire 	struct btf_header *hdr;
81*04674916SAlan Maguire 	const void *raw_btf;
82*04674916SAlan Maguire 	struct btf_type *t;
83*04674916SAlan Maguire 	void *new_raw_btf;
84*04674916SAlan Maguire 	void *str_data;
85*04674916SAlan Maguire 	__u32 raw_size;
86*04674916SAlan Maguire 
87*04674916SAlan Maguire 	opts.add_layout = true;
88*04674916SAlan Maguire 	btf = btf__new_empty_opts(&opts);
89*04674916SAlan Maguire 	if (!ASSERT_OK_PTR(btf, "btf_new"))
90*04674916SAlan Maguire 		return;
91*04674916SAlan Maguire 
92*04674916SAlan Maguire 	int_id = btf__add_int(btf, "test_char", 1, BTF_INT_CHAR);
93*04674916SAlan Maguire 	if (!ASSERT_GT(int_id, 0, "add_int_id"))
94*04674916SAlan Maguire 		return;
95*04674916SAlan Maguire 
96*04674916SAlan Maguire 	/*
97*04674916SAlan Maguire 	 * Create our type with unrecognized kind by adding a typedef kind
98*04674916SAlan Maguire 	 * we will overwrite it with our unrecognized kind value.
99*04674916SAlan Maguire 	 */
100*04674916SAlan Maguire 	unrec_id = btf__add_typedef(btf, "unrec_kind", int_id);
101*04674916SAlan Maguire 	if (!ASSERT_GT(unrec_id, 0, "add_unrec_id"))
102*04674916SAlan Maguire 		return;
103*04674916SAlan Maguire 
104*04674916SAlan Maguire 	/*
105*04674916SAlan Maguire 	 * Add an id after it that we will look up to verify we can parse
106*04674916SAlan Maguire 	 * beyond unrecognized kinds.
107*04674916SAlan Maguire 	 */
108*04674916SAlan Maguire 	id = btf__add_typedef(btf, "test_lookup", int_id);
109*04674916SAlan Maguire 	if (!ASSERT_GT(id, 0, "add_test_lookup_id"))
110*04674916SAlan Maguire 		return;
111*04674916SAlan Maguire 	id2 = btf__add_typedef(btf, "test_lookup2", int_id);
112*04674916SAlan Maguire 	if (!ASSERT_GT(id2, 0, "add_test_lookup_id2"))
113*04674916SAlan Maguire 		return;
114*04674916SAlan Maguire 
115*04674916SAlan Maguire 	raw_btf = (void *)btf__raw_data(btf, &raw_size);
116*04674916SAlan Maguire 	if (!ASSERT_OK_PTR(raw_btf, "btf__raw_data"))
117*04674916SAlan Maguire 		return;
118*04674916SAlan Maguire 
119*04674916SAlan Maguire 	new_raw_btf = calloc(1, raw_size + sizeof(*l));
120*04674916SAlan Maguire 	if (!ASSERT_OK_PTR(new_raw_btf, "calloc_raw_btf"))
121*04674916SAlan Maguire 		return;
122*04674916SAlan Maguire 	memcpy(new_raw_btf, raw_btf, raw_size);
123*04674916SAlan Maguire 
124*04674916SAlan Maguire 	hdr = new_raw_btf;
125*04674916SAlan Maguire 
126*04674916SAlan Maguire 	/* Move strings to make space for one new layout description */
127*04674916SAlan Maguire 	raw_size += sizeof(*l);
128*04674916SAlan Maguire 	str_data = new_raw_btf + hdr->hdr_len + hdr->str_off;
129*04674916SAlan Maguire 	memmove(str_data + sizeof(*l), str_data, hdr->str_len);
130*04674916SAlan Maguire 	hdr->str_off += sizeof(*l);
131*04674916SAlan Maguire 
132*04674916SAlan Maguire 	/* Add new layout description */
133*04674916SAlan Maguire 	hdr->layout_len += sizeof(*l);
134*04674916SAlan Maguire 	l = new_raw_btf + hdr->hdr_len + hdr->layout_off;
135*04674916SAlan Maguire 	l[NR_BTF_KINDS].info_sz = 0;
136*04674916SAlan Maguire 	l[NR_BTF_KINDS].elem_sz = 0;
137*04674916SAlan Maguire 	l[NR_BTF_KINDS].flags = 0;
138*04674916SAlan Maguire 
139*04674916SAlan Maguire 	/* Now modify typedef added above to be an unrecognized kind. */
140*04674916SAlan Maguire 	t = (void *)hdr + hdr->hdr_len + hdr->type_off + sizeof(struct btf_type) +
141*04674916SAlan Maguire 		sizeof(__u32);
142*04674916SAlan Maguire 	t->info = (NR_BTF_KINDS << 24);
143*04674916SAlan Maguire 
144*04674916SAlan Maguire 	/* Write BTF to a raw file, ready for parsing. */
145*04674916SAlan Maguire 	if (write_raw_btf(new_raw_btf, raw_size, btf_kind_file1))
146*04674916SAlan Maguire 		goto out;
147*04674916SAlan Maguire 
148*04674916SAlan Maguire 	/*
149*04674916SAlan Maguire 	 * Verify parsing succeeds, and that we can read type info past
150*04674916SAlan Maguire 	 * the unrecognized kind.
151*04674916SAlan Maguire 	 */
152*04674916SAlan Maguire 	new_btf = btf__parse_raw(btf_kind_file1);
153*04674916SAlan Maguire 	if (ASSERT_OK_PTR(new_btf, "btf__parse_raw")) {
154*04674916SAlan Maguire 		ASSERT_EQ(btf__find_by_name(new_btf, "unrec_kind"), unrec_id,
155*04674916SAlan Maguire 			  "unrec_kind_found");
156*04674916SAlan Maguire 		ASSERT_EQ(btf__find_by_name_kind(new_btf, "test_lookup",
157*04674916SAlan Maguire 						 BTF_KIND_TYPEDEF), id,
158*04674916SAlan Maguire 			  "verify_id_lookup");
159*04674916SAlan Maguire 		ASSERT_EQ(btf__find_by_name_kind(new_btf, "test_lookup2",
160*04674916SAlan Maguire 						 BTF_KIND_TYPEDEF), id2,
161*04674916SAlan Maguire 			  "verify_id2_lookup");
162*04674916SAlan Maguire 	}
163*04674916SAlan Maguire 	btf__free(new_btf);
164*04674916SAlan Maguire 	new_btf = NULL;
165*04674916SAlan Maguire 
166*04674916SAlan Maguire 	/*
167*04674916SAlan Maguire 	 * Next, change info_sz to equal sizeof(struct btf_type); this means the
168*04674916SAlan Maguire 	 * "test_lookup" kind will be reinterpreted as a singular info element
169*04674916SAlan Maguire 	 * following the unrecognized kind.
170*04674916SAlan Maguire 	 */
171*04674916SAlan Maguire 	l[NR_BTF_KINDS].info_sz = sizeof(struct btf_type);
172*04674916SAlan Maguire 	if (write_raw_btf(new_raw_btf, raw_size, btf_kind_file2))
173*04674916SAlan Maguire 		goto out;
174*04674916SAlan Maguire 
175*04674916SAlan Maguire 	new_btf = btf__parse_raw(btf_kind_file2);
176*04674916SAlan Maguire 	if (ASSERT_OK_PTR(new_btf, "btf__parse_raw")) {
177*04674916SAlan Maguire 		ASSERT_EQ(btf__find_by_name_kind(new_btf, "test_lookup",
178*04674916SAlan Maguire 						 BTF_KIND_TYPEDEF), -ENOENT,
179*04674916SAlan Maguire 			  "verify_id_not_found");
180*04674916SAlan Maguire 		/* id of "test_lookup2" will be id2 -1 as we have removed one type */
181*04674916SAlan Maguire 		ASSERT_EQ(btf__find_by_name_kind(new_btf, "test_lookup2",
182*04674916SAlan Maguire 						 BTF_KIND_TYPEDEF), id2 - 1,
183*04674916SAlan Maguire 			  "verify_id_lookup2");
184*04674916SAlan Maguire 
185*04674916SAlan Maguire 	}
186*04674916SAlan Maguire 	btf__free(new_btf);
187*04674916SAlan Maguire 	new_btf = NULL;
188*04674916SAlan Maguire 
189*04674916SAlan Maguire 	/*
190*04674916SAlan Maguire 	 * Change elem_sz to equal sizeof(struct btf_type) and set vlen
191*04674916SAlan Maguire 	 * associated with unrecognized type to 1; this allows us to verify
192*04674916SAlan Maguire 	 * vlen-specified BTF can still be parsed.
193*04674916SAlan Maguire 	 */
194*04674916SAlan Maguire 	l[NR_BTF_KINDS].info_sz = 0;
195*04674916SAlan Maguire 	l[NR_BTF_KINDS].elem_sz = sizeof(struct btf_type);
196*04674916SAlan Maguire 	t->info |= 1;
197*04674916SAlan Maguire 	if (write_raw_btf(new_raw_btf, raw_size, btf_kind_file3))
198*04674916SAlan Maguire 		goto out;
199*04674916SAlan Maguire 
200*04674916SAlan Maguire 	new_btf = btf__parse_raw(btf_kind_file3);
201*04674916SAlan Maguire 	if (ASSERT_OK_PTR(new_btf, "btf__parse_raw")) {
202*04674916SAlan Maguire 		ASSERT_EQ(btf__find_by_name_kind(new_btf, "test_lookup",
203*04674916SAlan Maguire 						 BTF_KIND_TYPEDEF), -ENOENT,
204*04674916SAlan Maguire 			  "verify_id_not_found");
205*04674916SAlan Maguire 		/* id of "test_lookup2" will be id2 -1 as we have removed one type */
206*04674916SAlan Maguire 		ASSERT_EQ(btf__find_by_name_kind(new_btf, "test_lookup2",
207*04674916SAlan Maguire 						 BTF_KIND_TYPEDEF), id2 - 1,
208*04674916SAlan Maguire 			  "verify_id_lookup2");
209*04674916SAlan Maguire 
210*04674916SAlan Maguire 	}
211*04674916SAlan Maguire out:
212*04674916SAlan Maguire 	btf__free(new_btf);
213*04674916SAlan Maguire 	free(new_raw_btf);
214*04674916SAlan Maguire 	unlink(btf_kind_file1);
215*04674916SAlan Maguire 	unlink(btf_kind_file2);
216*04674916SAlan Maguire 	unlink(btf_kind_file3);
217*04674916SAlan Maguire 	btf__free(btf);
218*04674916SAlan Maguire }
219*04674916SAlan Maguire 
220*04674916SAlan Maguire void test_btf_kind(void)
221*04674916SAlan Maguire {
222*04674916SAlan Maguire 	if (test__start_subtest("btf_kind_encoding"))
223*04674916SAlan Maguire 		test_btf_kind_encoding();
224*04674916SAlan Maguire 	if (test__start_subtest("btf_kind_decoding"))
225*04674916SAlan Maguire 		test_btf_kind_decoding();
226*04674916SAlan Maguire }
227