1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2020 Facebook */
3 #define _GNU_SOURCE
4 #include <string.h>
5 #include <byteswap.h>
6 #include <test_progs.h>
7 #include <bpf/btf.h>
8 
9 static int duration = 0;
10 
11 void test_btf_endian() {
12 #if __BYTE_ORDER == __LITTLE_ENDIAN
13 	enum btf_endianness endian = BTF_LITTLE_ENDIAN;
14 #elif __BYTE_ORDER == __BIG_ENDIAN
15 	enum btf_endianness endian = BTF_BIG_ENDIAN;
16 #else
17 #error "Unrecognized __BYTE_ORDER"
18 #endif
19 	enum btf_endianness swap_endian = 1 - endian;
20 	struct btf *btf = NULL, *swap_btf = NULL;
21 	const void *raw_data, *swap_raw_data;
22 	const struct btf_type *t;
23 	const struct btf_header *hdr;
24 	__u32 raw_sz, swap_raw_sz;
25 	int var_id;
26 
27 	/* Load BTF in native endianness */
28 	btf = btf__parse_elf("btf_dump_test_case_syntax.o", NULL);
29 	if (!ASSERT_OK_PTR(btf, "parse_native_btf"))
30 		goto err_out;
31 
32 	ASSERT_EQ(btf__endianness(btf), endian, "endian");
33 	btf__set_endianness(btf, swap_endian);
34 	ASSERT_EQ(btf__endianness(btf), swap_endian, "endian");
35 
36 	/* Get raw BTF data in non-native endianness... */
37 	raw_data = btf__get_raw_data(btf, &raw_sz);
38 	if (!ASSERT_OK_PTR(raw_data, "raw_data_inverted"))
39 		goto err_out;
40 
41 	/* ...and open it as a new BTF instance */
42 	swap_btf = btf__new(raw_data, raw_sz);
43 	if (!ASSERT_OK_PTR(swap_btf, "parse_swap_btf"))
44 		goto err_out;
45 
46 	ASSERT_EQ(btf__endianness(swap_btf), swap_endian, "endian");
47 	ASSERT_EQ(btf__get_nr_types(swap_btf), btf__get_nr_types(btf), "nr_types");
48 
49 	swap_raw_data = btf__get_raw_data(swap_btf, &swap_raw_sz);
50 	if (!ASSERT_OK_PTR(swap_raw_data, "swap_raw_data"))
51 		goto err_out;
52 
53 	/* both raw data should be identical (with non-native endianness) */
54 	ASSERT_OK(memcmp(raw_data, swap_raw_data, raw_sz), "mem_identical");
55 
56 	/* make sure that at least BTF header data is really swapped */
57 	hdr = swap_raw_data;
58 	ASSERT_EQ(bswap_16(hdr->magic), BTF_MAGIC, "btf_magic_swapped");
59 	ASSERT_EQ(raw_sz, swap_raw_sz, "raw_sizes");
60 
61 	/* swap it back to native endianness */
62 	btf__set_endianness(swap_btf, endian);
63 	swap_raw_data = btf__get_raw_data(swap_btf, &swap_raw_sz);
64 	if (!ASSERT_OK_PTR(swap_raw_data, "swap_raw_data"))
65 		goto err_out;
66 
67 	/* now header should have native BTF_MAGIC */
68 	hdr = swap_raw_data;
69 	ASSERT_EQ(hdr->magic, BTF_MAGIC, "btf_magic_native");
70 	ASSERT_EQ(raw_sz, swap_raw_sz, "raw_sizes");
71 
72 	/* now modify original BTF */
73 	var_id = btf__add_var(btf, "some_var", BTF_VAR_GLOBAL_ALLOCATED, 1);
74 	CHECK(var_id <= 0, "var_id", "failed %d\n", var_id);
75 
76 	btf__free(swap_btf);
77 	swap_btf = NULL;
78 
79 	btf__set_endianness(btf, swap_endian);
80 	raw_data = btf__get_raw_data(btf, &raw_sz);
81 	if (!ASSERT_OK_PTR(raw_data, "raw_data_inverted"))
82 		goto err_out;
83 
84 	/* and re-open swapped raw data again */
85 	swap_btf = btf__new(raw_data, raw_sz);
86 	if (!ASSERT_OK_PTR(swap_btf, "parse_swap_btf"))
87 		goto err_out;
88 
89 	ASSERT_EQ(btf__endianness(swap_btf), swap_endian, "endian");
90 	ASSERT_EQ(btf__get_nr_types(swap_btf), btf__get_nr_types(btf), "nr_types");
91 
92 	/* the type should appear as if it was stored in native endianness */
93 	t = btf__type_by_id(swap_btf, var_id);
94 	ASSERT_STREQ(btf__str_by_offset(swap_btf, t->name_off), "some_var", "var_name");
95 	ASSERT_EQ(btf_var(t)->linkage, BTF_VAR_GLOBAL_ALLOCATED, "var_linkage");
96 	ASSERT_EQ(t->type, 1, "var_type");
97 
98 err_out:
99 	btf__free(btf);
100 	btf__free(swap_btf);
101 }
102