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