/src/capstonenext/arch/BPF/BPFDisassembler.c
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | /* Capstone Disassembly Engine */ | 
| 2 |  | /* BPF Backend by david942j <david942j@gmail.com>, 2019 */ | 
| 3 |  |  | 
| 4 |  | #ifdef CAPSTONE_HAS_BPF | 
| 5 |  |  | 
| 6 |  | #include <string.h> | 
| 7 |  | #include <stddef.h> // offsetof macro | 
| 8 |  |  | 
| 9 |  | #include "BPFConstants.h" | 
| 10 |  | #include "BPFDisassembler.h" | 
| 11 |  | #include "BPFMapping.h" | 
| 12 |  | #include "../../cs_priv.h" | 
| 13 |  |  | 
| 14 |  | static uint16_t read_u16(cs_struct *ud, const uint8_t *code) | 
| 15 | 43.4k | { | 
| 16 | 43.4k |   if (MODE_IS_BIG_ENDIAN(ud->mode)) | 
| 17 | 26.1k |     return (((uint16_t)code[0] << 8) | code[1]); | 
| 18 | 17.3k |   else | 
| 19 | 17.3k |     return (((uint16_t)code[1] << 8) | code[0]); | 
| 20 | 43.4k | } | 
| 21 |  |  | 
| 22 |  | static uint32_t read_u32(cs_struct *ud, const uint8_t *code) | 
| 23 | 14.7k | { | 
| 24 | 14.7k |   if (MODE_IS_BIG_ENDIAN(ud->mode)) | 
| 25 | 8.84k |     return ((uint32_t)read_u16(ud, code) << 16) | read_u16(ud, code + 2); | 
| 26 | 5.93k |   else | 
| 27 | 5.93k |     return ((uint32_t)read_u16(ud, code + 2) << 16) | read_u16(ud, code); | 
| 28 | 14.7k | } | 
| 29 |  |  | 
| 30 |  | ///< Malloc bpf_internal, also checks if code_len is large enough. | 
| 31 |  | static bpf_internal *alloc_bpf_internal(size_t code_len) | 
| 32 | 14.5k | { | 
| 33 | 14.5k |   bpf_internal *bpf; | 
| 34 |  |  | 
| 35 | 14.5k |   if (code_len < 8) | 
| 36 | 148 |     return NULL; | 
| 37 | 14.3k |   bpf = cs_mem_malloc(sizeof(bpf_internal)); | 
| 38 | 14.3k |   if (bpf == NULL) | 
| 39 | 0 |     return NULL; | 
| 40 |  |   /* default value */ | 
| 41 | 14.3k |   bpf->insn_size = 8; | 
| 42 | 14.3k |   return bpf; | 
| 43 | 14.3k | } | 
| 44 |  |  | 
| 45 |  | ///< Fetch a cBPF structure from code | 
| 46 |  | static bpf_internal* fetch_cbpf(cs_struct *ud, const uint8_t *code, | 
| 47 |  |     size_t code_len) | 
| 48 | 5.21k | { | 
| 49 | 5.21k |   bpf_internal *bpf; | 
| 50 |  |  | 
| 51 | 5.21k |   bpf = alloc_bpf_internal(code_len); | 
| 52 | 5.21k |   if (bpf == NULL) | 
| 53 | 46 |     return NULL; | 
| 54 |  |  | 
| 55 | 5.16k |   bpf->op = read_u16(ud, code); | 
| 56 | 5.16k |   bpf->jt = code[2]; | 
| 57 | 5.16k |   bpf->jf = code[3]; | 
| 58 | 5.16k |   bpf->k = read_u32(ud, code + 4); | 
| 59 | 5.16k |   return bpf; | 
| 60 | 5.21k | } | 
| 61 |  |  | 
| 62 |  | ///< Fetch an eBPF structure from code | 
| 63 |  | static bpf_internal* fetch_ebpf(cs_struct *ud, const uint8_t *code, | 
| 64 |  |     size_t code_len) | 
| 65 | 9.30k | { | 
| 66 | 9.30k |   bpf_internal *bpf; | 
| 67 |  |  | 
| 68 | 9.30k |   bpf = alloc_bpf_internal(code_len); | 
| 69 | 9.30k |   if (bpf == NULL) | 
| 70 | 102 |     return NULL; | 
| 71 |  |  | 
| 72 | 9.20k |   bpf->op = (uint16_t)code[0]; | 
| 73 | 9.20k |   bpf->dst = code[1] & 0xf; | 
| 74 | 9.20k |   bpf->src = (code[1] & 0xf0) >> 4; | 
| 75 |  |  | 
| 76 |  |   // eBPF has one 16-byte instruction: BPF_LD | BPF_DW | BPF_IMM, | 
| 77 |  |   // in this case imm is combined with the next block's imm. | 
| 78 | 9.20k |   if (bpf->op == (BPF_CLASS_LD | BPF_SIZE_DW | BPF_MODE_IMM)) { | 
| 79 | 413 |     if (code_len < 16) { | 
| 80 | 4 |       cs_mem_free(bpf); | 
| 81 | 4 |       return NULL; | 
| 82 | 4 |     } | 
| 83 | 409 |     bpf->k = read_u32(ud, code + 4) | (((uint64_t)read_u32(ud, code + 12)) << 32); | 
| 84 | 409 |     bpf->insn_size = 16; | 
| 85 | 409 |   } | 
| 86 | 8.78k |   else { | 
| 87 | 8.78k |     bpf->offset = read_u16(ud, code + 2); | 
| 88 | 8.78k |     bpf->k = read_u32(ud, code + 4); | 
| 89 | 8.78k |   } | 
| 90 | 9.19k |   return bpf; | 
| 91 | 9.20k | } | 
| 92 |  |  | 
| 93 | 5.29k | #define CHECK_READABLE_REG(ud, reg) do { \ | 
| 94 | 5.29k |     if (! ((reg) >= BPF_REG_R0 && (reg) <= BPF_REG_R10)) \ | 
| 95 | 5.29k |       return false; \ | 
| 96 | 5.29k |   } while (0) | 
| 97 |  |  | 
| 98 | 3.95k | #define CHECK_WRITABLE_REG(ud, reg) do { \ | 
| 99 | 3.95k |     if (! ((reg) >= BPF_REG_R0 && (reg) < BPF_REG_R10)) \ | 
| 100 | 3.95k |       return false; \ | 
| 101 | 3.95k |   } while (0) | 
| 102 |  |  | 
| 103 | 5.29k | #define CHECK_READABLE_AND_PUSH(ud, MI, r) do { \ | 
| 104 | 5.29k |     CHECK_READABLE_REG(ud, r + BPF_REG_R0); \ | 
| 105 | 5.29k |     MCOperand_CreateReg0(MI, r + BPF_REG_R0); \ | 
| 106 | 5.24k |   } while (0) | 
| 107 |  |  | 
| 108 | 3.95k | #define CHECK_WRITABLE_AND_PUSH(ud, MI, r) do { \ | 
| 109 | 3.95k |     CHECK_WRITABLE_REG(ud, r + BPF_REG_R0); \ | 
| 110 | 3.95k |     MCOperand_CreateReg0(MI, r + BPF_REG_R0); \ | 
| 111 | 3.95k |   } while (0) | 
| 112 |  |  | 
| 113 |  | static bool decodeLoad(cs_struct *ud, MCInst *MI, bpf_internal *bpf) | 
| 114 | 4.23k | { | 
| 115 | 4.23k |   if (!EBPF_MODE(ud)) { | 
| 116 |  |     /* | 
| 117 |  |      *  +-----+-----------+--------------------+ | 
| 118 |  |      *  | ldb |    [k]    |       [x+k]        | | 
| 119 |  |      *  | ldh |    [k]    |       [x+k]        | | 
| 120 |  |      *  +-----+-----------+--------------------+ | 
| 121 |  |      */ | 
| 122 | 2.07k |     if (BPF_SIZE(bpf->op) == BPF_SIZE_DW) | 
| 123 | 2 |       return false; | 
| 124 | 2.07k |     if (BPF_SIZE(bpf->op) == BPF_SIZE_B || BPF_SIZE(bpf->op) == BPF_SIZE_H) { | 
| 125 |  |       /* no ldx */ | 
| 126 | 646 |       if (BPF_CLASS(bpf->op) != BPF_CLASS_LD) | 
| 127 | 2 |         return false; | 
| 128 |  |       /* can only be BPF_ABS and BPF_IND */ | 
| 129 | 644 |       if (BPF_MODE(bpf->op) == BPF_MODE_ABS) { | 
| 130 | 347 |         MCOperand_CreateImm0(MI, bpf->k); | 
| 131 | 347 |         return true; | 
| 132 | 347 |       } | 
| 133 | 297 |       else if (BPF_MODE(bpf->op) == BPF_MODE_IND) { | 
| 134 | 296 |         MCOperand_CreateReg0(MI, BPF_REG_X); | 
| 135 | 296 |         MCOperand_CreateImm0(MI, bpf->k); | 
| 136 | 296 |         return true; | 
| 137 | 296 |       } | 
| 138 | 1 |       return false; | 
| 139 | 644 |     } | 
| 140 |  |     /* | 
| 141 |  |      *  +-----+----+------+------+-----+-------+ | 
| 142 |  |      *  | ld  | #k | #len | M[k] | [k] | [x+k] | | 
| 143 |  |      *  +-----+----+------+------+-----+-------+ | 
| 144 |  |      *  | ldx | #k | #len | M[k] | 4*([k]&0xf) | | 
| 145 |  |      *  +-----+----+------+------+-------------+ | 
| 146 |  |      */ | 
| 147 | 1.43k |     switch (BPF_MODE(bpf->op)) { | 
| 148 | 612 |     default: | 
| 149 | 612 |       break; | 
| 150 | 612 |     case BPF_MODE_IMM: | 
| 151 | 358 |       MCOperand_CreateImm0(MI, bpf->k); | 
| 152 | 358 |       return true; | 
| 153 | 263 |     case BPF_MODE_LEN: | 
| 154 | 263 |       return true; | 
| 155 | 198 |     case BPF_MODE_MEM: | 
| 156 | 198 |       MCOperand_CreateImm0(MI, bpf->k); | 
| 157 | 198 |       return true; | 
| 158 | 1.43k |     } | 
| 159 | 612 |     if (BPF_CLASS(bpf->op) == BPF_CLASS_LD) { | 
| 160 | 412 |       if (BPF_MODE(bpf->op) == BPF_MODE_ABS) { | 
| 161 | 212 |         MCOperand_CreateImm0(MI, bpf->k); | 
| 162 | 212 |         return true; | 
| 163 | 212 |       } | 
| 164 | 200 |       else if (BPF_MODE(bpf->op) == BPF_MODE_IND) { | 
| 165 | 199 |         MCOperand_CreateReg0(MI, BPF_REG_X); | 
| 166 | 199 |         MCOperand_CreateImm0(MI, bpf->k); | 
| 167 | 199 |         return true; | 
| 168 | 199 |       } | 
| 169 | 412 |     } | 
| 170 | 200 |     else { /* LDX */ | 
| 171 | 200 |       if (BPF_MODE(bpf->op) == BPF_MODE_MSH) { | 
| 172 | 199 |         MCOperand_CreateImm0(MI, bpf->k); | 
| 173 | 199 |         return true; | 
| 174 | 199 |       } | 
| 175 | 200 |     } | 
| 176 | 2 |     return false; | 
| 177 | 612 |   } | 
| 178 |  |  | 
| 179 |  |   /* eBPF mode */ | 
| 180 |  |   /* | 
| 181 |  |    * - IMM: lddw dst, imm64 | 
| 182 |  |    * - ABS: ld{w,h,b,dw} [k] | 
| 183 |  |    * - IND: ld{w,h,b,dw} [src+k] | 
| 184 |  |    * - MEM: ldx{w,h,b,dw} dst, [src+off] | 
| 185 |  |    */ | 
| 186 | 2.15k |   if (BPF_CLASS(bpf->op) == BPF_CLASS_LD) { | 
| 187 | 1.64k |     switch (BPF_MODE(bpf->op)) { | 
| 188 | 417 |     case BPF_MODE_IMM: | 
| 189 | 417 |       if (bpf->op != (BPF_CLASS_LD | BPF_SIZE_DW | BPF_MODE_IMM)) | 
| 190 | 8 |         return false; | 
| 191 | 409 |       CHECK_WRITABLE_AND_PUSH(ud, MI, bpf->dst); | 
| 192 | 406 |       MCOperand_CreateImm0(MI, bpf->k); | 
| 193 | 406 |       return true; | 
| 194 | 780 |     case BPF_MODE_ABS: | 
| 195 | 780 |       MCOperand_CreateImm0(MI, bpf->k); | 
| 196 | 780 |       return true; | 
| 197 | 446 |     case BPF_MODE_IND: | 
| 198 | 446 |       CHECK_READABLE_AND_PUSH(ud, MI, bpf->src); | 
| 199 | 445 |       MCOperand_CreateImm0(MI, bpf->k); | 
| 200 | 445 |       return true; | 
| 201 | 1.64k |     } | 
| 202 | 3 |     return false; | 
| 203 |  |  | 
| 204 | 1.64k |   } | 
| 205 |  |   /* LDX */ | 
| 206 | 507 |   if (BPF_MODE(bpf->op) == BPF_MODE_MEM) { | 
| 207 | 505 |     CHECK_WRITABLE_AND_PUSH(ud, MI, bpf->dst); | 
| 208 | 504 |     CHECK_READABLE_AND_PUSH(ud, MI, bpf->src); | 
| 209 | 503 |     MCOperand_CreateImm0(MI, bpf->offset); | 
| 210 | 503 |     return true; | 
| 211 | 504 |   } | 
| 212 | 2 |   return false; | 
| 213 | 507 | } | 
| 214 |  |  | 
| 215 |  | static bool decodeStore(cs_struct *ud, MCInst *MI, bpf_internal *bpf) | 
| 216 | 1.79k | { | 
| 217 |  |   /* in cBPF, only BPF_ST* | BPF_MEM | BPF_W is valid | 
| 218 |  |    * while in eBPF: | 
| 219 |  |    * - BPF_STX | BPF_XADD | BPF_{W,DW} | 
| 220 |  |    * - BPF_ST* | BPF_MEM | BPF_{W,H,B,DW} | 
| 221 |  |    * are valid | 
| 222 |  |    */ | 
| 223 | 1.79k |   if (!EBPF_MODE(ud)) { | 
| 224 |  |     /* can only store to M[] */ | 
| 225 | 60 |     if (bpf->op != (BPF_CLASS(bpf->op) | BPF_MODE_MEM | BPF_SIZE_W)) | 
| 226 | 8 |       return false; | 
| 227 | 52 |     MCOperand_CreateImm0(MI, bpf->k); | 
| 228 | 52 |     return true; | 
| 229 | 60 |   } | 
| 230 |  |  | 
| 231 |  |   /* eBPF */ | 
| 232 |  |  | 
| 233 | 1.73k |   if (BPF_MODE(bpf->op) == BPF_MODE_XADD) { | 
| 234 | 103 |     if (BPF_CLASS(bpf->op) != BPF_CLASS_STX) | 
| 235 | 1 |       return false; | 
| 236 | 102 |     if (BPF_SIZE(bpf->op) != BPF_SIZE_W && BPF_SIZE(bpf->op) != BPF_SIZE_DW) | 
| 237 | 1 |       return false; | 
| 238 |  |     /* xadd [dst + off], src */ | 
| 239 | 101 |     CHECK_READABLE_AND_PUSH(ud, MI, bpf->dst); | 
| 240 | 100 |     MCOperand_CreateImm0(MI, bpf->offset); | 
| 241 | 100 |     CHECK_READABLE_AND_PUSH(ud, MI, bpf->src); | 
| 242 | 98 |     return true; | 
| 243 | 100 |   } | 
| 244 |  |  | 
| 245 | 1.63k |   if (BPF_MODE(bpf->op) != BPF_MODE_MEM) | 
| 246 | 3 |     return false; | 
| 247 |  |  | 
| 248 |  |   /* st [dst + off], src */ | 
| 249 | 1.63k |   CHECK_READABLE_AND_PUSH(ud, MI, bpf->dst); | 
| 250 | 1.62k |   MCOperand_CreateImm0(MI, bpf->offset); | 
| 251 | 1.62k |   if (BPF_CLASS(bpf->op) == BPF_CLASS_ST) | 
| 252 | 1.11k |     MCOperand_CreateImm0(MI, bpf->k); | 
| 253 | 519 |   else | 
| 254 | 519 |     CHECK_READABLE_AND_PUSH(ud, MI, bpf->src); | 
| 255 | 1.62k |   return true; | 
| 256 | 1.62k | } | 
| 257 |  |  | 
| 258 |  | static bool decodeALU(cs_struct *ud, MCInst *MI, bpf_internal *bpf) | 
| 259 | 4.44k | { | 
| 260 |  |   /* Set MI->Operands */ | 
| 261 |  |  | 
| 262 |  |   /* cBPF */ | 
| 263 | 4.44k |   if (!EBPF_MODE(ud)) { | 
| 264 | 1.35k |     if (BPF_OP(bpf->op) > BPF_ALU_XOR) | 
| 265 | 1 |       return false; | 
| 266 |  |     /* cBPF's NEG has no operands */ | 
| 267 | 1.34k |     if (BPF_OP(bpf->op) == BPF_ALU_NEG) | 
| 268 | 200 |       return true; | 
| 269 | 1.14k |     if (BPF_SRC(bpf->op) == BPF_SRC_K) | 
| 270 | 578 |       MCOperand_CreateImm0(MI, bpf->k); | 
| 271 | 571 |     else /* BPF_SRC_X */ | 
| 272 | 571 |       MCOperand_CreateReg0(MI, BPF_REG_X); | 
| 273 | 1.14k |     return true; | 
| 274 | 1.34k |   } | 
| 275 |  |  | 
| 276 |  |   /* eBPF */ | 
| 277 |  |  | 
| 278 | 3.09k |   if (BPF_OP(bpf->op) > BPF_ALU_END) | 
| 279 | 4 |     return false; | 
| 280 |  |   /* ALU64 class doesn't have ENDian */ | 
| 281 |  |   /* ENDian's imm must be one of 16, 32, 64 */ | 
| 282 | 3.08k |   if (BPF_OP(bpf->op) == BPF_ALU_END) { | 
| 283 | 282 |     if (BPF_CLASS(bpf->op) == BPF_CLASS_ALU64) | 
| 284 | 1 |       return false; | 
| 285 | 281 |     if (bpf->k != 16 && bpf->k != 32 && bpf->k != 64) | 
| 286 | 41 |       return false; | 
| 287 | 281 |   } | 
| 288 |  |  | 
| 289 |  |   /* - op dst, imm | 
| 290 |  |    * - op dst, src | 
| 291 |  |    * - neg dst | 
| 292 |  |    * - le<imm> dst | 
| 293 |  |    */ | 
| 294 |  |   /* every ALU instructions have dst op */ | 
| 295 | 3.04k |   CHECK_WRITABLE_AND_PUSH(ud, MI, bpf->dst); | 
| 296 |  |  | 
| 297 |  |   /* special cases */ | 
| 298 | 3.04k |   if (BPF_OP(bpf->op) == BPF_ALU_NEG) | 
| 299 | 346 |     return true; | 
| 300 | 2.69k |   if (BPF_OP(bpf->op) == BPF_ALU_END) { | 
| 301 |  |     /* bpf->k must be one of 16, 32, 64 */ | 
| 302 | 239 |     MCInst_setOpcode(MI, MCInst_getOpcode(MI) | ((uint32_t)bpf->k << 4)); | 
| 303 | 239 |     return true; | 
| 304 | 239 |   } | 
| 305 |  |  | 
| 306 |  |   /* normal cases */ | 
| 307 | 2.45k |   if (BPF_SRC(bpf->op) == BPF_SRC_K) { | 
| 308 | 2.16k |     MCOperand_CreateImm0(MI, bpf->k); | 
| 309 | 2.16k |   } | 
| 310 | 291 |   else { /* BPF_SRC_X */ | 
| 311 | 291 |     CHECK_READABLE_AND_PUSH(ud, MI, bpf->src); | 
| 312 | 291 |   } | 
| 313 | 2.45k |   return true; | 
| 314 | 2.45k | } | 
| 315 |  |  | 
| 316 |  | static bool decodeJump(cs_struct *ud, MCInst *MI, bpf_internal *bpf) | 
| 317 | 3.20k | { | 
| 318 |  |   /* cBPF and eBPF are very different in class jump */ | 
| 319 | 3.20k |   if (!EBPF_MODE(ud)) { | 
| 320 | 997 |     if (BPF_OP(bpf->op) > BPF_JUMP_JSET) | 
| 321 | 4 |       return false; | 
| 322 |  |  | 
| 323 |  |     /* ja is a special case of jumps */ | 
| 324 | 993 |     if (BPF_OP(bpf->op) == BPF_JUMP_JA) { | 
| 325 | 263 |       MCOperand_CreateImm0(MI, bpf->k); | 
| 326 | 263 |       return true; | 
| 327 | 263 |     } | 
| 328 |  |  | 
| 329 | 730 |     if (BPF_SRC(bpf->op) == BPF_SRC_K) | 
| 330 | 273 |       MCOperand_CreateImm0(MI, bpf->k); | 
| 331 | 457 |     else /* BPF_SRC_X */ | 
| 332 | 457 |       MCOperand_CreateReg0(MI, BPF_REG_X); | 
| 333 | 730 |     MCOperand_CreateImm0(MI, bpf->jt); | 
| 334 | 730 |     MCOperand_CreateImm0(MI, bpf->jf); | 
| 335 | 730 |   } | 
| 336 | 2.21k |   else { | 
| 337 | 2.21k |     if (BPF_OP(bpf->op) > BPF_JUMP_JSLE) | 
| 338 | 1 |       return false; | 
| 339 |  |  | 
| 340 |  |     /* No operands for exit */ | 
| 341 | 2.20k |     if (BPF_OP(bpf->op) == BPF_JUMP_EXIT) | 
| 342 | 277 |       return bpf->op == (BPF_CLASS_JMP | BPF_JUMP_EXIT); | 
| 343 | 1.93k |     if (BPF_OP(bpf->op) == BPF_JUMP_CALL) { | 
| 344 | 322 |       if (bpf->op == (BPF_CLASS_JMP | BPF_JUMP_CALL)) { | 
| 345 | 267 |         MCOperand_CreateImm0(MI, bpf->k); | 
| 346 | 267 |         return true; | 
| 347 | 267 |       } | 
| 348 | 55 |       if (bpf->op == (BPF_CLASS_JMP | BPF_JUMP_CALL | BPF_SRC_X)) { | 
| 349 | 55 |         CHECK_READABLE_AND_PUSH(ud, MI, bpf->k); | 
| 350 | 22 |         return true; | 
| 351 | 55 |       } | 
| 352 | 0 |       return false; | 
| 353 | 55 |     } | 
| 354 |  |  | 
| 355 |  |     /* ja is a special case of jumps */ | 
| 356 | 1.61k |     if (BPF_OP(bpf->op) == BPF_JUMP_JA) { | 
| 357 | 251 |       if (BPF_SRC(bpf->op) != BPF_SRC_K) | 
| 358 | 1 |         return false; | 
| 359 | 250 |       MCOperand_CreateImm0(MI, bpf->offset); | 
| 360 | 250 |       return true; | 
| 361 | 251 |     } | 
| 362 |  |  | 
| 363 |  |     /* <j>  dst, src, +off */ | 
| 364 | 1.35k |     CHECK_READABLE_AND_PUSH(ud, MI, bpf->dst); | 
| 365 | 1.35k |     if (BPF_SRC(bpf->op) == BPF_SRC_K) | 
| 366 | 1.07k |       MCOperand_CreateImm0(MI, bpf->k); | 
| 367 | 283 |     else | 
| 368 | 283 |       CHECK_READABLE_AND_PUSH(ud, MI, bpf->src); | 
| 369 | 1.35k |     MCOperand_CreateImm0(MI, bpf->offset); | 
| 370 | 1.35k |   } | 
| 371 | 2.08k |   return true; | 
| 372 | 3.20k | } | 
| 373 |  |  | 
| 374 |  | static bool decodeReturn(cs_struct *ud, MCInst *MI, bpf_internal *bpf) | 
| 375 | 626 | { | 
| 376 |  |   /* Here only handles the BPF_RET class in cBPF */ | 
| 377 | 626 |   switch (BPF_RVAL(bpf->op)) { | 
| 378 | 219 |   case BPF_SRC_K: | 
| 379 | 219 |     MCOperand_CreateImm0(MI, bpf->k); | 
| 380 | 219 |     return true; | 
| 381 | 206 |   case BPF_SRC_X: | 
| 382 | 206 |     MCOperand_CreateReg0(MI, BPF_REG_X); | 
| 383 | 206 |     return true; | 
| 384 | 200 |   case BPF_SRC_A: | 
| 385 | 200 |     MCOperand_CreateReg0(MI, BPF_REG_A); | 
| 386 | 200 |     return true; | 
| 387 | 626 |   } | 
| 388 | 1 |   return false; | 
| 389 | 626 | } | 
| 390 |  |  | 
| 391 |  | static bool decodeMISC(cs_struct *ud, MCInst *MI, bpf_internal *bpf) | 
| 392 | 55 | { | 
| 393 | 55 |   uint16_t op = bpf->op ^ BPF_CLASS_MISC; | 
| 394 | 55 |   return op == BPF_MISCOP_TAX || op == BPF_MISCOP_TXA; | 
| 395 | 55 | } | 
| 396 |  |  | 
| 397 |  | ///< 1. Check if the instruction is valid | 
| 398 |  | ///< 2. Set MI->opcode | 
| 399 |  | ///< 3. Set MI->Operands | 
| 400 |  | static bool getInstruction(cs_struct *ud, MCInst *MI, bpf_internal *bpf) | 
| 401 | 14.3k | { | 
| 402 | 14.3k |   cs_detail *detail; | 
| 403 |  |  | 
| 404 | 14.3k |   detail = MI->flat_insn->detail; | 
| 405 |  |   // initialize detail | 
| 406 | 14.3k |   if (detail) { | 
| 407 | 14.3k |     memset(detail, 0, offsetof(cs_detail, bpf) + sizeof(cs_bpf)); | 
| 408 | 14.3k |   } | 
| 409 |  |  | 
| 410 | 14.3k |   MCInst_clear(MI); | 
| 411 | 14.3k |   MCInst_setOpcode(MI, bpf->op); | 
| 412 |  |  | 
| 413 | 14.3k |   switch (BPF_CLASS(bpf->op)) { | 
| 414 | 0 |   default: /* should never happen */ | 
| 415 | 0 |     return false; | 
| 416 | 3.05k |   case BPF_CLASS_LD: | 
| 417 | 4.23k |   case BPF_CLASS_LDX: | 
| 418 | 4.23k |     return decodeLoad(ud, MI, bpf); | 
| 419 | 1.13k |   case BPF_CLASS_ST: | 
| 420 | 1.79k |   case BPF_CLASS_STX: | 
| 421 | 1.79k |     return decodeStore(ud, MI, bpf); | 
| 422 | 2.51k |   case BPF_CLASS_ALU: | 
| 423 | 2.51k |     return decodeALU(ud, MI, bpf); | 
| 424 | 3.20k |   case BPF_CLASS_JMP: | 
| 425 | 3.20k |     return decodeJump(ud, MI, bpf); | 
| 426 | 630 |   case BPF_CLASS_RET: | 
| 427 |  |     /* eBPF doesn't have this class */ | 
| 428 | 630 |     if (EBPF_MODE(ud)) | 
| 429 | 4 |       return false; | 
| 430 | 626 |     return decodeReturn(ud, MI, bpf); | 
| 431 | 1.98k |   case BPF_CLASS_MISC: | 
| 432 |  |   /* case BPF_CLASS_ALU64: */ | 
| 433 | 1.98k |     if (EBPF_MODE(ud)) | 
| 434 | 1.92k |       return decodeALU(ud, MI, bpf); | 
| 435 | 55 |     else | 
| 436 | 55 |       return decodeMISC(ud, MI, bpf); | 
| 437 | 14.3k |   } | 
| 438 | 14.3k | } | 
| 439 |  |  | 
| 440 |  | bool BPF_getInstruction(csh ud, const uint8_t *code, size_t code_len, | 
| 441 |  |     MCInst *instr, uint16_t *size, uint64_t address, void *info) | 
| 442 | 14.5k | { | 
| 443 | 14.5k |   cs_struct *cs; | 
| 444 | 14.5k |   bpf_internal *bpf; | 
| 445 |  |  | 
| 446 | 14.5k |   cs = (cs_struct*)ud; | 
| 447 | 14.5k |   if (EBPF_MODE(cs)) | 
| 448 | 9.30k |     bpf = fetch_ebpf(cs, code, code_len); | 
| 449 | 5.21k |   else | 
| 450 | 5.21k |     bpf = fetch_cbpf(cs, code, code_len); | 
| 451 | 14.5k |   if (bpf == NULL) | 
| 452 | 152 |     return false; | 
| 453 | 14.3k |   if (!getInstruction(cs, instr, bpf)) { | 
| 454 | 155 |     cs_mem_free(bpf); | 
| 455 | 155 |     return false; | 
| 456 | 155 |   } | 
| 457 |  |  | 
| 458 | 14.2k |   *size = bpf->insn_size; | 
| 459 | 14.2k |   cs_mem_free(bpf); | 
| 460 |  |  | 
| 461 | 14.2k |   return true; | 
| 462 | 14.3k | } | 
| 463 |  |  | 
| 464 |  | #endif |