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