Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpf: Add kernel/bpftool asm support for new instructions

Add asm support for new instructions so kernel verifier and bpftool
xlated insn dumps can have proper asm syntax for new instructions.

Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Acked-by: Quentin Monnet <quentin@isovalent.com>
Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Yonghong Song and committed by
Alexei Starovoitov
f835bb62 4cd58e9a

+51 -6
+51 -6
kernel/bpf/disasm.c
··· 87 87 [BPF_END >> 4] = "endian", 88 88 }; 89 89 90 + const char *const bpf_alu_sign_string[16] = { 91 + [BPF_DIV >> 4] = "s/=", 92 + [BPF_MOD >> 4] = "s%=", 93 + }; 94 + 95 + const char *const bpf_movsx_string[4] = { 96 + [0] = "(s8)", 97 + [1] = "(s16)", 98 + [3] = "(s32)", 99 + }; 100 + 90 101 static const char *const bpf_atomic_alu_string[16] = { 91 102 [BPF_ADD >> 4] = "add", 92 103 [BPF_AND >> 4] = "and", ··· 110 99 [BPF_H >> 3] = "u16", 111 100 [BPF_B >> 3] = "u8", 112 101 [BPF_DW >> 3] = "u64", 102 + }; 103 + 104 + static const char *const bpf_ldsx_string[] = { 105 + [BPF_W >> 3] = "s32", 106 + [BPF_H >> 3] = "s16", 107 + [BPF_B >> 3] = "s8", 113 108 }; 114 109 115 110 static const char *const bpf_jmp_string[16] = { ··· 145 128 insn->imm, insn->dst_reg); 146 129 } 147 130 131 + static void print_bpf_bswap_insn(bpf_insn_print_t verbose, 132 + void *private_data, 133 + const struct bpf_insn *insn) 134 + { 135 + verbose(private_data, "(%02x) r%d = bswap%d r%d\n", 136 + insn->code, insn->dst_reg, 137 + insn->imm, insn->dst_reg); 138 + } 139 + 140 + static bool is_sdiv_smod(const struct bpf_insn *insn) 141 + { 142 + return (BPF_OP(insn->code) == BPF_DIV || BPF_OP(insn->code) == BPF_MOD) && 143 + insn->off == 1; 144 + } 145 + 146 + static bool is_movsx(const struct bpf_insn *insn) 147 + { 148 + return BPF_OP(insn->code) == BPF_MOV && insn->off != 0; 149 + } 150 + 148 151 void print_bpf_insn(const struct bpf_insn_cbs *cbs, 149 152 const struct bpf_insn *insn, 150 153 bool allow_ptr_leaks) ··· 175 138 if (class == BPF_ALU || class == BPF_ALU64) { 176 139 if (BPF_OP(insn->code) == BPF_END) { 177 140 if (class == BPF_ALU64) 178 - verbose(cbs->private_data, "BUG_alu64_%02x\n", insn->code); 141 + print_bpf_bswap_insn(verbose, cbs->private_data, insn); 179 142 else 180 143 print_bpf_end_insn(verbose, cbs->private_data, insn); 181 144 } else if (BPF_OP(insn->code) == BPF_NEG) { ··· 184 147 insn->dst_reg, class == BPF_ALU ? 'w' : 'r', 185 148 insn->dst_reg); 186 149 } else if (BPF_SRC(insn->code) == BPF_X) { 187 - verbose(cbs->private_data, "(%02x) %c%d %s %c%d\n", 150 + verbose(cbs->private_data, "(%02x) %c%d %s %s%c%d\n", 188 151 insn->code, class == BPF_ALU ? 'w' : 'r', 189 152 insn->dst_reg, 190 - bpf_alu_string[BPF_OP(insn->code) >> 4], 153 + is_sdiv_smod(insn) ? bpf_alu_sign_string[BPF_OP(insn->code) >> 4] 154 + : bpf_alu_string[BPF_OP(insn->code) >> 4], 155 + is_movsx(insn) ? bpf_movsx_string[(insn->off >> 3) - 1] : "", 191 156 class == BPF_ALU ? 'w' : 'r', 192 157 insn->src_reg); 193 158 } else { 194 159 verbose(cbs->private_data, "(%02x) %c%d %s %d\n", 195 160 insn->code, class == BPF_ALU ? 'w' : 'r', 196 161 insn->dst_reg, 197 - bpf_alu_string[BPF_OP(insn->code) >> 4], 162 + is_sdiv_smod(insn) ? bpf_alu_sign_string[BPF_OP(insn->code) >> 4] 163 + : bpf_alu_string[BPF_OP(insn->code) >> 4], 198 164 insn->imm); 199 165 } 200 166 } else if (class == BPF_STX) { ··· 258 218 verbose(cbs->private_data, "BUG_st_%02x\n", insn->code); 259 219 } 260 220 } else if (class == BPF_LDX) { 261 - if (BPF_MODE(insn->code) != BPF_MEM) { 221 + if (BPF_MODE(insn->code) != BPF_MEM && BPF_MODE(insn->code) != BPF_MEMSX) { 262 222 verbose(cbs->private_data, "BUG_ldx_%02x\n", insn->code); 263 223 return; 264 224 } 265 225 verbose(cbs->private_data, "(%02x) r%d = *(%s *)(r%d %+d)\n", 266 226 insn->code, insn->dst_reg, 267 - bpf_ldst_string[BPF_SIZE(insn->code) >> 3], 227 + BPF_MODE(insn->code) == BPF_MEM ? 228 + bpf_ldst_string[BPF_SIZE(insn->code) >> 3] : 229 + bpf_ldsx_string[BPF_SIZE(insn->code) >> 3], 268 230 insn->src_reg, insn->off); 269 231 } else if (class == BPF_LD) { 270 232 if (BPF_MODE(insn->code) == BPF_ABS) { ··· 321 279 } else if (insn->code == (BPF_JMP | BPF_JA)) { 322 280 verbose(cbs->private_data, "(%02x) goto pc%+d\n", 323 281 insn->code, insn->off); 282 + } else if (insn->code == (BPF_JMP32 | BPF_JA)) { 283 + verbose(cbs->private_data, "(%02x) gotol pc%+d\n", 284 + insn->code, insn->imm); 324 285 } else if (insn->code == (BPF_JMP | BPF_EXIT)) { 325 286 verbose(cbs->private_data, "(%02x) exit\n", insn->code); 326 287 } else if (BPF_SRC(insn->code) == BPF_X) {