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