| // SPDX-License-Identifier: GPL-2.0 |
| /* Copyright (c) 2020 Facebook */ |
| #define _GNU_SOURCE |
| #include <string.h> |
| #include <byteswap.h> |
| #include <test_progs.h> |
| #include <bpf/btf.h> |
| |
| void test_btf_endian() { |
| #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ |
| enum btf_endianness endian = BTF_LITTLE_ENDIAN; |
| #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ |
| enum btf_endianness endian = BTF_BIG_ENDIAN; |
| #else |
| #error "Unrecognized __BYTE_ORDER__" |
| #endif |
| enum btf_endianness swap_endian = 1 - endian; |
| struct btf *btf = NULL, *swap_btf = NULL; |
| const void *raw_data, *swap_raw_data; |
| const struct btf_type *t; |
| const struct btf_header *hdr; |
| __u32 raw_sz, swap_raw_sz; |
| int var_id; |
| |
| /* Load BTF in native endianness */ |
| btf = btf__parse_elf("btf_dump_test_case_syntax.bpf.o", NULL); |
| if (!ASSERT_OK_PTR(btf, "parse_native_btf")) |
| goto err_out; |
| |
| ASSERT_EQ(btf__endianness(btf), endian, "endian"); |
| btf__set_endianness(btf, swap_endian); |
| ASSERT_EQ(btf__endianness(btf), swap_endian, "endian"); |
| |
| /* Get raw BTF data in non-native endianness... */ |
| raw_data = btf__raw_data(btf, &raw_sz); |
| if (!ASSERT_OK_PTR(raw_data, "raw_data_inverted")) |
| goto err_out; |
| |
| /* ...and open it as a new BTF instance */ |
| swap_btf = btf__new(raw_data, raw_sz); |
| if (!ASSERT_OK_PTR(swap_btf, "parse_swap_btf")) |
| goto err_out; |
| |
| ASSERT_EQ(btf__endianness(swap_btf), swap_endian, "endian"); |
| ASSERT_EQ(btf__type_cnt(swap_btf), btf__type_cnt(btf), "nr_types"); |
| |
| swap_raw_data = btf__raw_data(swap_btf, &swap_raw_sz); |
| if (!ASSERT_OK_PTR(swap_raw_data, "swap_raw_data")) |
| goto err_out; |
| |
| /* both raw data should be identical (with non-native endianness) */ |
| ASSERT_OK(memcmp(raw_data, swap_raw_data, raw_sz), "mem_identical"); |
| |
| /* make sure that at least BTF header data is really swapped */ |
| hdr = swap_raw_data; |
| ASSERT_EQ(bswap_16(hdr->magic), BTF_MAGIC, "btf_magic_swapped"); |
| ASSERT_EQ(raw_sz, swap_raw_sz, "raw_sizes"); |
| |
| /* swap it back to native endianness */ |
| btf__set_endianness(swap_btf, endian); |
| swap_raw_data = btf__raw_data(swap_btf, &swap_raw_sz); |
| if (!ASSERT_OK_PTR(swap_raw_data, "swap_raw_data")) |
| goto err_out; |
| |
| /* now header should have native BTF_MAGIC */ |
| hdr = swap_raw_data; |
| ASSERT_EQ(hdr->magic, BTF_MAGIC, "btf_magic_native"); |
| ASSERT_EQ(raw_sz, swap_raw_sz, "raw_sizes"); |
| |
| /* now modify original BTF */ |
| var_id = btf__add_var(btf, "some_var", BTF_VAR_GLOBAL_ALLOCATED, 1); |
| ASSERT_GT(var_id, 0, "var_id"); |
| |
| btf__free(swap_btf); |
| swap_btf = NULL; |
| |
| btf__set_endianness(btf, swap_endian); |
| raw_data = btf__raw_data(btf, &raw_sz); |
| if (!ASSERT_OK_PTR(raw_data, "raw_data_inverted")) |
| goto err_out; |
| |
| /* and re-open swapped raw data again */ |
| swap_btf = btf__new(raw_data, raw_sz); |
| if (!ASSERT_OK_PTR(swap_btf, "parse_swap_btf")) |
| goto err_out; |
| |
| ASSERT_EQ(btf__endianness(swap_btf), swap_endian, "endian"); |
| ASSERT_EQ(btf__type_cnt(swap_btf), btf__type_cnt(btf), "nr_types"); |
| |
| /* the type should appear as if it was stored in native endianness */ |
| t = btf__type_by_id(swap_btf, var_id); |
| ASSERT_STREQ(btf__str_by_offset(swap_btf, t->name_off), "some_var", "var_name"); |
| ASSERT_EQ(btf_var(t)->linkage, BTF_VAR_GLOBAL_ALLOCATED, "var_linkage"); |
| ASSERT_EQ(t->type, 1, "var_type"); |
| |
| err_out: |
| btf__free(btf); |
| btf__free(swap_btf); |
| } |