LCOV - code coverage report
Current view: top level - kernel/bpf - disasm.c (source / functions) Hit Total Coverage
Test: Real Lines: 0 105 0.0 %
Date: 2020-10-17 15:46:43 Functions: 0 4 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           Branch data     Line data    Source code
       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                 :          0 : 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                 :          0 :         if (insn->src_reg != BPF_PSEUDO_CALL &&
      23                 :          0 :             insn->imm >= 0 && insn->imm < __BPF_FUNC_MAX_ID &&
      24                 :          0 :             func_id_str[insn->imm])
      25                 :            :                 return func_id_str[insn->imm];
      26                 :            : 
      27                 :          0 :         if (cbs && cbs->cb_call)
      28                 :          0 :                 return cbs->cb_call(cbs->private_data, insn);
      29                 :            : 
      30                 :          0 :         if (insn->src_reg == BPF_PSEUDO_CALL)
      31                 :          0 :                 snprintf(buff, len, "%+d", insn->imm);
      32                 :            : 
      33                 :          0 :         return buff;
      34                 :            : }
      35                 :            : 
      36                 :          0 : 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                 :          0 :         if (cbs && cbs->cb_imm)
      41                 :          0 :                 return cbs->cb_imm(cbs->private_data, insn, full_imm);
      42                 :            : 
      43                 :          0 :         snprintf(buff, len, "0x%llx", (unsigned long long)full_imm);
      44                 :          0 :         return buff;
      45                 :            : }
      46                 :            : 
      47                 :          0 : const char *func_id_name(int id)
      48                 :            : {
      49                 :          0 :         if (id >= 0 && id < __BPF_FUNC_MAX_ID && func_id_str[id])
      50                 :          0 :                 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                 :          0 :         verbose(private_data, "(%02x) r%d = %s%d r%d\n",
     112                 :            :                 insn->code, insn->dst_reg,
     113                 :          0 :                 BPF_SRC(insn->code) == BPF_TO_BE ? "be" : "le",
     114                 :          0 :                 insn->imm, insn->dst_reg);
     115                 :            : }
     116                 :            : 
     117                 :          0 : void print_bpf_insn(const struct bpf_insn_cbs *cbs,
     118                 :            :                     const struct bpf_insn *insn,
     119                 :            :                     bool allow_ptr_leaks)
     120                 :            : {
     121                 :          0 :         const bpf_insn_print_t verbose = cbs->cb_print;
     122                 :          0 :         u8 class = BPF_CLASS(insn->code);
     123                 :            : 
     124                 :          0 :         if (class == BPF_ALU || class == BPF_ALU64) {
     125                 :          0 :                 if (BPF_OP(insn->code) == BPF_END) {
     126                 :          0 :                         if (class == BPF_ALU64)
     127                 :          0 :                                 verbose(cbs->private_data, "BUG_alu64_%02x\n", insn->code);
     128                 :            :                         else
     129                 :          0 :                                 print_bpf_end_insn(verbose, cbs->private_data, insn);
     130                 :          0 :                 } else if (BPF_OP(insn->code) == BPF_NEG) {
     131                 :          0 :                         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                 :          0 :                                 insn->dst_reg);
     135                 :          0 :                 } else if (BPF_SRC(insn->code) == BPF_X) {
     136                 :          0 :                         verbose(cbs->private_data, "(%02x) %c%d %s %c%d\n",
     137                 :            :                                 insn->code, class == BPF_ALU ? 'w' : 'r',
     138                 :          0 :                                 insn->dst_reg,
     139                 :          0 :                                 bpf_alu_string[BPF_OP(insn->code) >> 4],
     140                 :            :                                 class == BPF_ALU ? 'w' : 'r',
     141                 :          0 :                                 insn->src_reg);
     142                 :            :                 } else {
     143                 :          0 :                         verbose(cbs->private_data, "(%02x) %c%d %s %d\n",
     144                 :            :                                 insn->code, class == BPF_ALU ? 'w' : 'r',
     145                 :          0 :                                 insn->dst_reg,
     146                 :          0 :                                 bpf_alu_string[BPF_OP(insn->code) >> 4],
     147                 :            :                                 insn->imm);
     148                 :            :                 }
     149                 :          0 :         } else if (class == BPF_STX) {
     150                 :          0 :                 if (BPF_MODE(insn->code) == BPF_MEM)
     151                 :          0 :                         verbose(cbs->private_data, "(%02x) *(%s *)(r%d %+d) = r%d\n",
     152                 :            :                                 insn->code,
     153                 :          0 :                                 bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
     154                 :          0 :                                 insn->dst_reg,
     155                 :          0 :                                 insn->off, insn->src_reg);
     156                 :          0 :                 else if (BPF_MODE(insn->code) == BPF_XADD)
     157                 :          0 :                         verbose(cbs->private_data, "(%02x) lock *(%s *)(r%d %+d) += r%d\n",
     158                 :            :                                 insn->code,
     159                 :          0 :                                 bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
     160                 :          0 :                                 insn->dst_reg, insn->off,
     161                 :          0 :                                 insn->src_reg);
     162                 :            :                 else
     163                 :          0 :                         verbose(cbs->private_data, "BUG_%02x\n", insn->code);
     164                 :          0 :         } else if (class == BPF_ST) {
     165                 :          0 :                 if (BPF_MODE(insn->code) != BPF_MEM) {
     166                 :          0 :                         verbose(cbs->private_data, "BUG_st_%02x\n", insn->code);
     167                 :          0 :                         return;
     168                 :            :                 }
     169                 :          0 :                 verbose(cbs->private_data, "(%02x) *(%s *)(r%d %+d) = %d\n",
     170                 :            :                         insn->code,
     171                 :          0 :                         bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
     172                 :          0 :                         insn->dst_reg,
     173                 :          0 :                         insn->off, insn->imm);
     174                 :          0 :         } else if (class == BPF_LDX) {
     175                 :          0 :                 if (BPF_MODE(insn->code) != BPF_MEM) {
     176                 :          0 :                         verbose(cbs->private_data, "BUG_ldx_%02x\n", insn->code);
     177                 :          0 :                         return;
     178                 :            :                 }
     179                 :          0 :                 verbose(cbs->private_data, "(%02x) r%d = *(%s *)(r%d %+d)\n",
     180                 :          0 :                         insn->code, insn->dst_reg,
     181                 :          0 :                         bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
     182                 :          0 :                         insn->src_reg, insn->off);
     183                 :          0 :         } else if (class == BPF_LD) {
     184                 :          0 :                 if (BPF_MODE(insn->code) == BPF_ABS) {
     185                 :          0 :                         verbose(cbs->private_data, "(%02x) r0 = *(%s *)skb[%d]\n",
     186                 :            :                                 insn->code,
     187                 :          0 :                                 bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
     188                 :            :                                 insn->imm);
     189                 :          0 :                 } else if (BPF_MODE(insn->code) == BPF_IND) {
     190                 :          0 :                         verbose(cbs->private_data, "(%02x) r0 = *(%s *)skb[r%d + %d]\n",
     191                 :            :                                 insn->code,
     192                 :          0 :                                 bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
     193                 :          0 :                                 insn->src_reg, insn->imm);
     194                 :          0 :                 } 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                 :          0 :                         u64 imm = ((u64)(insn + 1)->imm << 32) | (u32)insn->imm;
     200                 :          0 :                         bool is_ptr = insn->src_reg == BPF_PSEUDO_MAP_FD ||
     201                 :            :                                       insn->src_reg == BPF_PSEUDO_MAP_VALUE;
     202                 :            :                         char tmp[64];
     203                 :            : 
     204                 :          0 :                         if (is_ptr && !allow_ptr_leaks)
     205                 :            :                                 imm = 0;
     206                 :            : 
     207                 :          0 :                         verbose(cbs->private_data, "(%02x) r%d = %s\n",
     208                 :          0 :                                 insn->code, insn->dst_reg,
     209                 :            :                                 __func_imm_name(cbs, insn, imm,
     210                 :            :                                                 tmp, sizeof(tmp)));
     211                 :            :                 } else {
     212                 :          0 :                         verbose(cbs->private_data, "BUG_ld_%02x\n", insn->code);
     213                 :          0 :                         return;
     214                 :            :                 }
     215                 :          0 :         } else if (class == BPF_JMP32 || class == BPF_JMP) {
     216                 :          0 :                 u8 opcode = BPF_OP(insn->code);
     217                 :            : 
     218                 :          0 :                 if (opcode == BPF_CALL) {
     219                 :            :                         char tmp[64];
     220                 :            : 
     221                 :          0 :                         if (insn->src_reg == BPF_PSEUDO_CALL) {
     222                 :          0 :                                 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                 :          0 :                                 strcpy(tmp, "unknown");
     228                 :          0 :                                 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                 :          0 :                 } else if (insn->code == (BPF_JMP | BPF_JA)) {
     234                 :          0 :                         verbose(cbs->private_data, "(%02x) goto pc%+d\n",
     235                 :          0 :                                 insn->code, insn->off);
     236                 :          0 :                 } else if (insn->code == (BPF_JMP | BPF_EXIT)) {
     237                 :          0 :                         verbose(cbs->private_data, "(%02x) exit\n", insn->code);
     238                 :          0 :                 } else if (BPF_SRC(insn->code) == BPF_X) {
     239                 :          0 :                         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                 :          0 :                                 insn->dst_reg,
     243                 :          0 :                                 bpf_jmp_string[BPF_OP(insn->code) >> 4],
     244                 :            :                                 class == BPF_JMP32 ? 'w' : 'r',
     245                 :          0 :                                 insn->src_reg, insn->off);
     246                 :            :                 } else {
     247                 :          0 :                         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                 :          0 :                                 insn->dst_reg,
     251                 :          0 :                                 bpf_jmp_string[BPF_OP(insn->code) >> 4],
     252                 :          0 :                                 insn->imm, insn->off);
     253                 :            :                 }
     254                 :            :         } else {
     255                 :          0 :                 verbose(cbs->private_data, "(%02x) %s\n",
     256                 :            :                         insn->code, bpf_class_string[class]);
     257                 :            :         }
     258                 :            : }
    

Generated by: LCOV version 1.14