1*a3acd7d4SDonglin Peng // SPDX-License-Identifier: GPL-2.0 2*a3acd7d4SDonglin Peng /* Copyright (c) 2026 Xiaomi */ 3*a3acd7d4SDonglin Peng 4*a3acd7d4SDonglin Peng #include <test_progs.h> 5*a3acd7d4SDonglin Peng #include <bpf/btf.h> 6*a3acd7d4SDonglin Peng #include "btf_helpers.h" 7*a3acd7d4SDonglin Peng 8*a3acd7d4SDonglin Peng static void permute_base_check(struct btf *btf) 9*a3acd7d4SDonglin Peng { 10*a3acd7d4SDonglin Peng VALIDATE_RAW_BTF( 11*a3acd7d4SDonglin Peng btf, 12*a3acd7d4SDonglin Peng "[1] STRUCT 's2' size=4 vlen=1\n" 13*a3acd7d4SDonglin Peng "\t'm' type_id=4 bits_offset=0", 14*a3acd7d4SDonglin Peng "[2] FUNC 'f' type_id=6 linkage=static", 15*a3acd7d4SDonglin Peng "[3] PTR '(anon)' type_id=4", 16*a3acd7d4SDonglin Peng "[4] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED", 17*a3acd7d4SDonglin Peng "[5] STRUCT 's1' size=4 vlen=1\n" 18*a3acd7d4SDonglin Peng "\t'm' type_id=4 bits_offset=0", 19*a3acd7d4SDonglin Peng "[6] FUNC_PROTO '(anon)' ret_type_id=4 vlen=1\n" 20*a3acd7d4SDonglin Peng "\t'p' type_id=3"); 21*a3acd7d4SDonglin Peng } 22*a3acd7d4SDonglin Peng 23*a3acd7d4SDonglin Peng /* Ensure btf__permute works as expected in the base-BTF scenario */ 24*a3acd7d4SDonglin Peng static void test_permute_base(void) 25*a3acd7d4SDonglin Peng { 26*a3acd7d4SDonglin Peng struct btf *btf; 27*a3acd7d4SDonglin Peng __u32 permute_ids[7]; 28*a3acd7d4SDonglin Peng int err; 29*a3acd7d4SDonglin Peng 30*a3acd7d4SDonglin Peng btf = btf__new_empty(); 31*a3acd7d4SDonglin Peng if (!ASSERT_OK_PTR(btf, "empty_main_btf")) 32*a3acd7d4SDonglin Peng return; 33*a3acd7d4SDonglin Peng 34*a3acd7d4SDonglin Peng btf__add_int(btf, "int", 4, BTF_INT_SIGNED); /* [1] int */ 35*a3acd7d4SDonglin Peng btf__add_ptr(btf, 1); /* [2] ptr to int */ 36*a3acd7d4SDonglin Peng btf__add_struct(btf, "s1", 4); /* [3] struct s1 { */ 37*a3acd7d4SDonglin Peng btf__add_field(btf, "m", 1, 0, 0); /* int m; */ 38*a3acd7d4SDonglin Peng /* } */ 39*a3acd7d4SDonglin Peng btf__add_struct(btf, "s2", 4); /* [4] struct s2 { */ 40*a3acd7d4SDonglin Peng btf__add_field(btf, "m", 1, 0, 0); /* int m; */ 41*a3acd7d4SDonglin Peng /* } */ 42*a3acd7d4SDonglin Peng btf__add_func_proto(btf, 1); /* [5] int (*)(int *p); */ 43*a3acd7d4SDonglin Peng btf__add_func_param(btf, "p", 2); 44*a3acd7d4SDonglin Peng btf__add_func(btf, "f", BTF_FUNC_STATIC, 5); /* [6] int f(int *p); */ 45*a3acd7d4SDonglin Peng 46*a3acd7d4SDonglin Peng VALIDATE_RAW_BTF( 47*a3acd7d4SDonglin Peng btf, 48*a3acd7d4SDonglin Peng "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED", 49*a3acd7d4SDonglin Peng "[2] PTR '(anon)' type_id=1", 50*a3acd7d4SDonglin Peng "[3] STRUCT 's1' size=4 vlen=1\n" 51*a3acd7d4SDonglin Peng "\t'm' type_id=1 bits_offset=0", 52*a3acd7d4SDonglin Peng "[4] STRUCT 's2' size=4 vlen=1\n" 53*a3acd7d4SDonglin Peng "\t'm' type_id=1 bits_offset=0", 54*a3acd7d4SDonglin Peng "[5] FUNC_PROTO '(anon)' ret_type_id=1 vlen=1\n" 55*a3acd7d4SDonglin Peng "\t'p' type_id=2", 56*a3acd7d4SDonglin Peng "[6] FUNC 'f' type_id=5 linkage=static"); 57*a3acd7d4SDonglin Peng 58*a3acd7d4SDonglin Peng permute_ids[0] = 0; /* [0] -> [0] */ 59*a3acd7d4SDonglin Peng permute_ids[1] = 4; /* [1] -> [4] */ 60*a3acd7d4SDonglin Peng permute_ids[2] = 3; /* [2] -> [3] */ 61*a3acd7d4SDonglin Peng permute_ids[3] = 5; /* [3] -> [5] */ 62*a3acd7d4SDonglin Peng permute_ids[4] = 1; /* [4] -> [1] */ 63*a3acd7d4SDonglin Peng permute_ids[5] = 6; /* [5] -> [6] */ 64*a3acd7d4SDonglin Peng permute_ids[6] = 2; /* [6] -> [2] */ 65*a3acd7d4SDonglin Peng err = btf__permute(btf, permute_ids, ARRAY_SIZE(permute_ids), NULL); 66*a3acd7d4SDonglin Peng if (!ASSERT_OK(err, "btf__permute_base")) 67*a3acd7d4SDonglin Peng goto done; 68*a3acd7d4SDonglin Peng permute_base_check(btf); 69*a3acd7d4SDonglin Peng 70*a3acd7d4SDonglin Peng /* ids[0] must be 0 for base BTF */ 71*a3acd7d4SDonglin Peng permute_ids[0] = 4; /* [0] -> [0] */ 72*a3acd7d4SDonglin Peng permute_ids[1] = 0; /* [1] -> [4] */ 73*a3acd7d4SDonglin Peng permute_ids[2] = 3; /* [2] -> [3] */ 74*a3acd7d4SDonglin Peng permute_ids[3] = 5; /* [3] -> [5] */ 75*a3acd7d4SDonglin Peng permute_ids[4] = 1; /* [4] -> [1] */ 76*a3acd7d4SDonglin Peng permute_ids[5] = 6; /* [5] -> [6] */ 77*a3acd7d4SDonglin Peng permute_ids[6] = 2; /* [6] -> [2] */ 78*a3acd7d4SDonglin Peng err = btf__permute(btf, permute_ids, ARRAY_SIZE(permute_ids), NULL); 79*a3acd7d4SDonglin Peng if (!ASSERT_ERR(err, "btf__permute_base")) 80*a3acd7d4SDonglin Peng goto done; 81*a3acd7d4SDonglin Peng /* BTF is not modified */ 82*a3acd7d4SDonglin Peng permute_base_check(btf); 83*a3acd7d4SDonglin Peng 84*a3acd7d4SDonglin Peng /* id_map_cnt is invalid */ 85*a3acd7d4SDonglin Peng permute_ids[0] = 0; /* [0] -> [0] */ 86*a3acd7d4SDonglin Peng permute_ids[1] = 4; /* [1] -> [4] */ 87*a3acd7d4SDonglin Peng permute_ids[2] = 3; /* [2] -> [3] */ 88*a3acd7d4SDonglin Peng permute_ids[3] = 5; /* [3] -> [5] */ 89*a3acd7d4SDonglin Peng permute_ids[4] = 1; /* [4] -> [1] */ 90*a3acd7d4SDonglin Peng permute_ids[5] = 6; /* [5] -> [6] */ 91*a3acd7d4SDonglin Peng permute_ids[6] = 2; /* [6] -> [2] */ 92*a3acd7d4SDonglin Peng err = btf__permute(btf, permute_ids, ARRAY_SIZE(permute_ids) - 1, NULL); 93*a3acd7d4SDonglin Peng if (!ASSERT_ERR(err, "btf__permute_base")) 94*a3acd7d4SDonglin Peng goto done; 95*a3acd7d4SDonglin Peng /* BTF is not modified */ 96*a3acd7d4SDonglin Peng permute_base_check(btf); 97*a3acd7d4SDonglin Peng 98*a3acd7d4SDonglin Peng /* Multiple types can not be mapped to the same ID */ 99*a3acd7d4SDonglin Peng permute_ids[0] = 0; 100*a3acd7d4SDonglin Peng permute_ids[1] = 4; 101*a3acd7d4SDonglin Peng permute_ids[2] = 4; 102*a3acd7d4SDonglin Peng permute_ids[3] = 5; 103*a3acd7d4SDonglin Peng permute_ids[4] = 1; 104*a3acd7d4SDonglin Peng permute_ids[5] = 6; 105*a3acd7d4SDonglin Peng permute_ids[6] = 2; 106*a3acd7d4SDonglin Peng err = btf__permute(btf, permute_ids, ARRAY_SIZE(permute_ids), NULL); 107*a3acd7d4SDonglin Peng if (!ASSERT_ERR(err, "btf__permute_base")) 108*a3acd7d4SDonglin Peng goto done; 109*a3acd7d4SDonglin Peng /* BTF is not modified */ 110*a3acd7d4SDonglin Peng permute_base_check(btf); 111*a3acd7d4SDonglin Peng 112*a3acd7d4SDonglin Peng /* Type ID must be valid */ 113*a3acd7d4SDonglin Peng permute_ids[0] = 0; 114*a3acd7d4SDonglin Peng permute_ids[1] = 4; 115*a3acd7d4SDonglin Peng permute_ids[2] = 3; 116*a3acd7d4SDonglin Peng permute_ids[3] = 5; 117*a3acd7d4SDonglin Peng permute_ids[4] = 1; 118*a3acd7d4SDonglin Peng permute_ids[5] = 7; 119*a3acd7d4SDonglin Peng permute_ids[6] = 2; 120*a3acd7d4SDonglin Peng err = btf__permute(btf, permute_ids, ARRAY_SIZE(permute_ids), NULL); 121*a3acd7d4SDonglin Peng if (!ASSERT_ERR(err, "btf__permute_base")) 122*a3acd7d4SDonglin Peng goto done; 123*a3acd7d4SDonglin Peng /* BTF is not modified */ 124*a3acd7d4SDonglin Peng permute_base_check(btf); 125*a3acd7d4SDonglin Peng 126*a3acd7d4SDonglin Peng done: 127*a3acd7d4SDonglin Peng btf__free(btf); 128*a3acd7d4SDonglin Peng } 129*a3acd7d4SDonglin Peng 130*a3acd7d4SDonglin Peng static void permute_split_check(struct btf *btf) 131*a3acd7d4SDonglin Peng { 132*a3acd7d4SDonglin Peng VALIDATE_RAW_BTF( 133*a3acd7d4SDonglin Peng btf, 134*a3acd7d4SDonglin Peng "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED", 135*a3acd7d4SDonglin Peng "[2] PTR '(anon)' type_id=1", 136*a3acd7d4SDonglin Peng "[3] STRUCT 's2' size=4 vlen=1\n" 137*a3acd7d4SDonglin Peng "\t'm' type_id=1 bits_offset=0", 138*a3acd7d4SDonglin Peng "[4] FUNC 'f' type_id=5 linkage=static", 139*a3acd7d4SDonglin Peng "[5] FUNC_PROTO '(anon)' ret_type_id=1 vlen=1\n" 140*a3acd7d4SDonglin Peng "\t'p' type_id=2", 141*a3acd7d4SDonglin Peng "[6] STRUCT 's1' size=4 vlen=1\n" 142*a3acd7d4SDonglin Peng "\t'm' type_id=1 bits_offset=0"); 143*a3acd7d4SDonglin Peng } 144*a3acd7d4SDonglin Peng 145*a3acd7d4SDonglin Peng /* Ensure btf__permute works as expected in the split-BTF scenario */ 146*a3acd7d4SDonglin Peng static void test_permute_split(void) 147*a3acd7d4SDonglin Peng { 148*a3acd7d4SDonglin Peng struct btf *split_btf = NULL, *base_btf = NULL; 149*a3acd7d4SDonglin Peng __u32 permute_ids[4]; 150*a3acd7d4SDonglin Peng int err, start_id; 151*a3acd7d4SDonglin Peng 152*a3acd7d4SDonglin Peng base_btf = btf__new_empty(); 153*a3acd7d4SDonglin Peng if (!ASSERT_OK_PTR(base_btf, "empty_main_btf")) 154*a3acd7d4SDonglin Peng return; 155*a3acd7d4SDonglin Peng 156*a3acd7d4SDonglin Peng btf__add_int(base_btf, "int", 4, BTF_INT_SIGNED); /* [1] int */ 157*a3acd7d4SDonglin Peng btf__add_ptr(base_btf, 1); /* [2] ptr to int */ 158*a3acd7d4SDonglin Peng VALIDATE_RAW_BTF( 159*a3acd7d4SDonglin Peng base_btf, 160*a3acd7d4SDonglin Peng "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED", 161*a3acd7d4SDonglin Peng "[2] PTR '(anon)' type_id=1"); 162*a3acd7d4SDonglin Peng split_btf = btf__new_empty_split(base_btf); 163*a3acd7d4SDonglin Peng if (!ASSERT_OK_PTR(split_btf, "empty_split_btf")) 164*a3acd7d4SDonglin Peng goto cleanup; 165*a3acd7d4SDonglin Peng btf__add_struct(split_btf, "s1", 4); /* [3] struct s1 { */ 166*a3acd7d4SDonglin Peng btf__add_field(split_btf, "m", 1, 0, 0); /* int m; */ 167*a3acd7d4SDonglin Peng /* } */ 168*a3acd7d4SDonglin Peng btf__add_struct(split_btf, "s2", 4); /* [4] struct s2 { */ 169*a3acd7d4SDonglin Peng btf__add_field(split_btf, "m", 1, 0, 0); /* int m; */ 170*a3acd7d4SDonglin Peng /* } */ 171*a3acd7d4SDonglin Peng btf__add_func_proto(split_btf, 1); /* [5] int (*)(int p); */ 172*a3acd7d4SDonglin Peng btf__add_func_param(split_btf, "p", 2); 173*a3acd7d4SDonglin Peng btf__add_func(split_btf, "f", BTF_FUNC_STATIC, 5); /* [6] int f(int *p); */ 174*a3acd7d4SDonglin Peng 175*a3acd7d4SDonglin Peng VALIDATE_RAW_BTF( 176*a3acd7d4SDonglin Peng split_btf, 177*a3acd7d4SDonglin Peng "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED", 178*a3acd7d4SDonglin Peng "[2] PTR '(anon)' type_id=1", 179*a3acd7d4SDonglin Peng "[3] STRUCT 's1' size=4 vlen=1\n" 180*a3acd7d4SDonglin Peng "\t'm' type_id=1 bits_offset=0", 181*a3acd7d4SDonglin Peng "[4] STRUCT 's2' size=4 vlen=1\n" 182*a3acd7d4SDonglin Peng "\t'm' type_id=1 bits_offset=0", 183*a3acd7d4SDonglin Peng "[5] FUNC_PROTO '(anon)' ret_type_id=1 vlen=1\n" 184*a3acd7d4SDonglin Peng "\t'p' type_id=2", 185*a3acd7d4SDonglin Peng "[6] FUNC 'f' type_id=5 linkage=static"); 186*a3acd7d4SDonglin Peng 187*a3acd7d4SDonglin Peng start_id = btf__type_cnt(base_btf); 188*a3acd7d4SDonglin Peng permute_ids[3 - start_id] = 6; /* [3] -> [6] */ 189*a3acd7d4SDonglin Peng permute_ids[4 - start_id] = 3; /* [4] -> [3] */ 190*a3acd7d4SDonglin Peng permute_ids[5 - start_id] = 5; /* [5] -> [5] */ 191*a3acd7d4SDonglin Peng permute_ids[6 - start_id] = 4; /* [6] -> [4] */ 192*a3acd7d4SDonglin Peng err = btf__permute(split_btf, permute_ids, ARRAY_SIZE(permute_ids), NULL); 193*a3acd7d4SDonglin Peng if (!ASSERT_OK(err, "btf__permute_split")) 194*a3acd7d4SDonglin Peng goto cleanup; 195*a3acd7d4SDonglin Peng permute_split_check(split_btf); 196*a3acd7d4SDonglin Peng 197*a3acd7d4SDonglin Peng /* 198*a3acd7d4SDonglin Peng * For split BTF, id_map_cnt must equal to the number of types 199*a3acd7d4SDonglin Peng * added on top of base BTF 200*a3acd7d4SDonglin Peng */ 201*a3acd7d4SDonglin Peng permute_ids[3 - start_id] = 4; 202*a3acd7d4SDonglin Peng permute_ids[4 - start_id] = 3; 203*a3acd7d4SDonglin Peng permute_ids[5 - start_id] = 5; 204*a3acd7d4SDonglin Peng permute_ids[6 - start_id] = 6; 205*a3acd7d4SDonglin Peng err = btf__permute(split_btf, permute_ids, ARRAY_SIZE(permute_ids) - 1, NULL); 206*a3acd7d4SDonglin Peng if (!ASSERT_ERR(err, "btf__permute_split")) 207*a3acd7d4SDonglin Peng goto cleanup; 208*a3acd7d4SDonglin Peng /* BTF is not modified */ 209*a3acd7d4SDonglin Peng permute_split_check(split_btf); 210*a3acd7d4SDonglin Peng 211*a3acd7d4SDonglin Peng /* Multiple types can not be mapped to the same ID */ 212*a3acd7d4SDonglin Peng permute_ids[3 - start_id] = 4; 213*a3acd7d4SDonglin Peng permute_ids[4 - start_id] = 3; 214*a3acd7d4SDonglin Peng permute_ids[5 - start_id] = 3; 215*a3acd7d4SDonglin Peng permute_ids[6 - start_id] = 6; 216*a3acd7d4SDonglin Peng err = btf__permute(split_btf, permute_ids, ARRAY_SIZE(permute_ids), NULL); 217*a3acd7d4SDonglin Peng if (!ASSERT_ERR(err, "btf__permute_split")) 218*a3acd7d4SDonglin Peng goto cleanup; 219*a3acd7d4SDonglin Peng /* BTF is not modified */ 220*a3acd7d4SDonglin Peng permute_split_check(split_btf); 221*a3acd7d4SDonglin Peng 222*a3acd7d4SDonglin Peng /* Can not map to base ID */ 223*a3acd7d4SDonglin Peng permute_ids[3 - start_id] = 4; 224*a3acd7d4SDonglin Peng permute_ids[4 - start_id] = 2; 225*a3acd7d4SDonglin Peng permute_ids[5 - start_id] = 5; 226*a3acd7d4SDonglin Peng permute_ids[6 - start_id] = 6; 227*a3acd7d4SDonglin Peng err = btf__permute(split_btf, permute_ids, ARRAY_SIZE(permute_ids), NULL); 228*a3acd7d4SDonglin Peng if (!ASSERT_ERR(err, "btf__permute_split")) 229*a3acd7d4SDonglin Peng goto cleanup; 230*a3acd7d4SDonglin Peng /* BTF is not modified */ 231*a3acd7d4SDonglin Peng permute_split_check(split_btf); 232*a3acd7d4SDonglin Peng 233*a3acd7d4SDonglin Peng cleanup: 234*a3acd7d4SDonglin Peng btf__free(split_btf); 235*a3acd7d4SDonglin Peng btf__free(base_btf); 236*a3acd7d4SDonglin Peng } 237*a3acd7d4SDonglin Peng 238*a3acd7d4SDonglin Peng void test_btf_permute(void) 239*a3acd7d4SDonglin Peng { 240*a3acd7d4SDonglin Peng if (test__start_subtest("permute_base")) 241*a3acd7d4SDonglin Peng test_permute_base(); 242*a3acd7d4SDonglin Peng if (test__start_subtest("permute_split")) 243*a3acd7d4SDonglin Peng test_permute_split(); 244*a3acd7d4SDonglin Peng } 245