root/kernel/bpf/disasm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. __func_get_name
  2. __func_imm_name
  3. func_id_name
  4. print_bpf_end_insn
  5. print_bpf_insn

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com
   3  * Copyright (c) 2016 Facebook
   4  */
   5 
   6 #include <linux/bpf.h>
   7 
   8 #include "disasm.h"
   9 
  10 #define __BPF_FUNC_STR_FN(x) [BPF_FUNC_ ## x] = __stringify(bpf_ ## x)
  11 static const char * const func_id_str[] = {
  12         __BPF_FUNC_MAPPER(__BPF_FUNC_STR_FN)
  13 };
  14 #undef __BPF_FUNC_STR_FN
  15 
  16 static const char *__func_get_name(const struct bpf_insn_cbs *cbs,
  17                                    const struct bpf_insn *insn,
  18                                    char *buff, size_t len)
  19 {
  20         BUILD_BUG_ON(ARRAY_SIZE(func_id_str) != __BPF_FUNC_MAX_ID);
  21 
  22         if (insn->src_reg != BPF_PSEUDO_CALL &&
  23             insn->imm >= 0 && insn->imm < __BPF_FUNC_MAX_ID &&
  24             func_id_str[insn->imm])
  25                 return func_id_str[insn->imm];
  26 
  27         if (cbs && cbs->cb_call)
  28                 return cbs->cb_call(cbs->private_data, insn);
  29 
  30         if (insn->src_reg == BPF_PSEUDO_CALL)
  31                 snprintf(buff, len, "%+d", insn->imm);
  32 
  33         return buff;
  34 }
  35 
  36 static const char *__func_imm_name(const struct bpf_insn_cbs *cbs,
  37                                    const struct bpf_insn *insn,
  38                                    u64 full_imm, char *buff, size_t len)
  39 {
  40         if (cbs && cbs->cb_imm)
  41                 return cbs->cb_imm(cbs->private_data, insn, full_imm);
  42 
  43         snprintf(buff, len, "0x%llx", (unsigned long long)full_imm);
  44         return buff;
  45 }
  46 
  47 const char *func_id_name(int id)
  48 {
  49         if (id >= 0 && id < __BPF_FUNC_MAX_ID && func_id_str[id])
  50                 return func_id_str[id];
  51         else
  52                 return "unknown";
  53 }
  54 
  55 const char *const bpf_class_string[8] = {
  56         [BPF_LD]    = "ld",
  57         [BPF_LDX]   = "ldx",
  58         [BPF_ST]    = "st",
  59         [BPF_STX]   = "stx",
  60         [BPF_ALU]   = "alu",
  61         [BPF_JMP]   = "jmp",
  62         [BPF_JMP32] = "jmp32",
  63         [BPF_ALU64] = "alu64",
  64 };
  65 
  66 const char *const bpf_alu_string[16] = {
  67         [BPF_ADD >> 4]  = "+=",
  68         [BPF_SUB >> 4]  = "-=",
  69         [BPF_MUL >> 4]  = "*=",
  70         [BPF_DIV >> 4]  = "/=",
  71         [BPF_OR  >> 4]  = "|=",
  72         [BPF_AND >> 4]  = "&=",
  73         [BPF_LSH >> 4]  = "<<=",
  74         [BPF_RSH >> 4]  = ">>=",
  75         [BPF_NEG >> 4]  = "neg",
  76         [BPF_MOD >> 4]  = "%=",
  77         [BPF_XOR >> 4]  = "^=",
  78         [BPF_MOV >> 4]  = "=",
  79         [BPF_ARSH >> 4] = "s>>=",
  80         [BPF_END >> 4]  = "endian",
  81 };
  82 
  83 static const char *const bpf_ldst_string[] = {
  84         [BPF_W >> 3]  = "u32",
  85         [BPF_H >> 3]  = "u16",
  86         [BPF_B >> 3]  = "u8",
  87         [BPF_DW >> 3] = "u64",
  88 };
  89 
  90 static const char *const bpf_jmp_string[16] = {
  91         [BPF_JA >> 4]   = "jmp",
  92         [BPF_JEQ >> 4]  = "==",
  93         [BPF_JGT >> 4]  = ">",
  94         [BPF_JLT >> 4]  = "<",
  95         [BPF_JGE >> 4]  = ">=",
  96         [BPF_JLE >> 4]  = "<=",
  97         [BPF_JSET >> 4] = "&",
  98         [BPF_JNE >> 4]  = "!=",
  99         [BPF_JSGT >> 4] = "s>",
 100         [BPF_JSLT >> 4] = "s<",
 101         [BPF_JSGE >> 4] = "s>=",
 102         [BPF_JSLE >> 4] = "s<=",
 103         [BPF_CALL >> 4] = "call",
 104         [BPF_EXIT >> 4] = "exit",
 105 };
 106 
 107 static void print_bpf_end_insn(bpf_insn_print_t verbose,
 108                                void *private_data,
 109                                const struct bpf_insn *insn)
 110 {
 111         verbose(private_data, "(%02x) r%d = %s%d r%d\n",
 112                 insn->code, insn->dst_reg,
 113                 BPF_SRC(insn->code) == BPF_TO_BE ? "be" : "le",
 114                 insn->imm, insn->dst_reg);
 115 }
 116 
 117 void print_bpf_insn(const struct bpf_insn_cbs *cbs,
 118                     const struct bpf_insn *insn,
 119                     bool allow_ptr_leaks)
 120 {
 121         const bpf_insn_print_t verbose = cbs->cb_print;
 122         u8 class = BPF_CLASS(insn->code);
 123 
 124         if (class == BPF_ALU || class == BPF_ALU64) {
 125                 if (BPF_OP(insn->code) == BPF_END) {
 126                         if (class == BPF_ALU64)
 127                                 verbose(cbs->private_data, "BUG_alu64_%02x\n", insn->code);
 128                         else
 129                                 print_bpf_end_insn(verbose, cbs->private_data, insn);
 130                 } else if (BPF_OP(insn->code) == BPF_NEG) {
 131                         verbose(cbs->private_data, "(%02x) %c%d = -%c%d\n",
 132                                 insn->code, class == BPF_ALU ? 'w' : 'r',
 133                                 insn->dst_reg, class == BPF_ALU ? 'w' : 'r',
 134                                 insn->dst_reg);
 135                 } else if (BPF_SRC(insn->code) == BPF_X) {
 136                         verbose(cbs->private_data, "(%02x) %c%d %s %c%d\n",
 137                                 insn->code, class == BPF_ALU ? 'w' : 'r',
 138                                 insn->dst_reg,
 139                                 bpf_alu_string[BPF_OP(insn->code) >> 4],
 140                                 class == BPF_ALU ? 'w' : 'r',
 141                                 insn->src_reg);
 142                 } else {
 143                         verbose(cbs->private_data, "(%02x) %c%d %s %d\n",
 144                                 insn->code, class == BPF_ALU ? 'w' : 'r',
 145                                 insn->dst_reg,
 146                                 bpf_alu_string[BPF_OP(insn->code) >> 4],
 147                                 insn->imm);
 148                 }
 149         } else if (class == BPF_STX) {
 150                 if (BPF_MODE(insn->code) == BPF_MEM)
 151                         verbose(cbs->private_data, "(%02x) *(%s *)(r%d %+d) = r%d\n",
 152                                 insn->code,
 153                                 bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
 154                                 insn->dst_reg,
 155                                 insn->off, insn->src_reg);
 156                 else if (BPF_MODE(insn->code) == BPF_XADD)
 157                         verbose(cbs->private_data, "(%02x) lock *(%s *)(r%d %+d) += r%d\n",
 158                                 insn->code,
 159                                 bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
 160                                 insn->dst_reg, insn->off,
 161                                 insn->src_reg);
 162                 else
 163                         verbose(cbs->private_data, "BUG_%02x\n", insn->code);
 164         } else if (class == BPF_ST) {
 165                 if (BPF_MODE(insn->code) != BPF_MEM) {
 166                         verbose(cbs->private_data, "BUG_st_%02x\n", insn->code);
 167                         return;
 168                 }
 169                 verbose(cbs->private_data, "(%02x) *(%s *)(r%d %+d) = %d\n",
 170                         insn->code,
 171                         bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
 172                         insn->dst_reg,
 173                         insn->off, insn->imm);
 174         } else if (class == BPF_LDX) {
 175                 if (BPF_MODE(insn->code) != BPF_MEM) {
 176                         verbose(cbs->private_data, "BUG_ldx_%02x\n", insn->code);
 177                         return;
 178                 }
 179                 verbose(cbs->private_data, "(%02x) r%d = *(%s *)(r%d %+d)\n",
 180                         insn->code, insn->dst_reg,
 181                         bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
 182                         insn->src_reg, insn->off);
 183         } else if (class == BPF_LD) {
 184                 if (BPF_MODE(insn->code) == BPF_ABS) {
 185                         verbose(cbs->private_data, "(%02x) r0 = *(%s *)skb[%d]\n",
 186                                 insn->code,
 187                                 bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
 188                                 insn->imm);
 189                 } else if (BPF_MODE(insn->code) == BPF_IND) {
 190                         verbose(cbs->private_data, "(%02x) r0 = *(%s *)skb[r%d + %d]\n",
 191                                 insn->code,
 192                                 bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
 193                                 insn->src_reg, insn->imm);
 194                 } else if (BPF_MODE(insn->code) == BPF_IMM &&
 195                            BPF_SIZE(insn->code) == BPF_DW) {
 196                         /* At this point, we already made sure that the second
 197                          * part of the ldimm64 insn is accessible.
 198                          */
 199                         u64 imm = ((u64)(insn + 1)->imm << 32) | (u32)insn->imm;
 200                         bool is_ptr = insn->src_reg == BPF_PSEUDO_MAP_FD ||
 201                                       insn->src_reg == BPF_PSEUDO_MAP_VALUE;
 202                         char tmp[64];
 203 
 204                         if (is_ptr && !allow_ptr_leaks)
 205                                 imm = 0;
 206 
 207                         verbose(cbs->private_data, "(%02x) r%d = %s\n",
 208                                 insn->code, insn->dst_reg,
 209                                 __func_imm_name(cbs, insn, imm,
 210                                                 tmp, sizeof(tmp)));
 211                 } else {
 212                         verbose(cbs->private_data, "BUG_ld_%02x\n", insn->code);
 213                         return;
 214                 }
 215         } else if (class == BPF_JMP32 || class == BPF_JMP) {
 216                 u8 opcode = BPF_OP(insn->code);
 217 
 218                 if (opcode == BPF_CALL) {
 219                         char tmp[64];
 220 
 221                         if (insn->src_reg == BPF_PSEUDO_CALL) {
 222                                 verbose(cbs->private_data, "(%02x) call pc%s\n",
 223                                         insn->code,
 224                                         __func_get_name(cbs, insn,
 225                                                         tmp, sizeof(tmp)));
 226                         } else {
 227                                 strcpy(tmp, "unknown");
 228                                 verbose(cbs->private_data, "(%02x) call %s#%d\n", insn->code,
 229                                         __func_get_name(cbs, insn,
 230                                                         tmp, sizeof(tmp)),
 231                                         insn->imm);
 232                         }
 233                 } else if (insn->code == (BPF_JMP | BPF_JA)) {
 234                         verbose(cbs->private_data, "(%02x) goto pc%+d\n",
 235                                 insn->code, insn->off);
 236                 } else if (insn->code == (BPF_JMP | BPF_EXIT)) {
 237                         verbose(cbs->private_data, "(%02x) exit\n", insn->code);
 238                 } else if (BPF_SRC(insn->code) == BPF_X) {
 239                         verbose(cbs->private_data,
 240                                 "(%02x) if %c%d %s %c%d goto pc%+d\n",
 241                                 insn->code, class == BPF_JMP32 ? 'w' : 'r',
 242                                 insn->dst_reg,
 243                                 bpf_jmp_string[BPF_OP(insn->code) >> 4],
 244                                 class == BPF_JMP32 ? 'w' : 'r',
 245                                 insn->src_reg, insn->off);
 246                 } else {
 247                         verbose(cbs->private_data,
 248                                 "(%02x) if %c%d %s 0x%x goto pc%+d\n",
 249                                 insn->code, class == BPF_JMP32 ? 'w' : 'r',
 250                                 insn->dst_reg,
 251                                 bpf_jmp_string[BPF_OP(insn->code) >> 4],
 252                                 insn->imm, insn->off);
 253                 }
 254         } else {
 255                 verbose(cbs->private_data, "(%02x) %s\n",
 256                         insn->code, bpf_class_string[class]);
 257         }
 258 }

/* [<][>][^][v][top][bottom][index][help] */