/src/capstonenext/arch/BPF/BPFInstPrinter.c
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | /* Capstone Disassembly Engine */ | 
| 2 |  | /* BPF Backend by david942j <david942j@gmail.com>, 2019 */ | 
| 3 |  |  | 
| 4 |  | #include <capstone/platform.h> | 
| 5 |  |  | 
| 6 |  | #include "BPFConstants.h" | 
| 7 |  | #include "BPFInstPrinter.h" | 
| 8 |  | #include "BPFMapping.h" | 
| 9 |  |  | 
| 10 |  | static cs_bpf_op *expand_bpf_operands(cs_bpf *bpf) | 
| 11 | 31.4k | { | 
| 12 |  |   /* assert(bpf->op_count < 3); */ | 
| 13 | 31.4k |   return &bpf->operands[bpf->op_count++]; | 
| 14 | 31.4k | } | 
| 15 |  |  | 
| 16 |  | static void push_op_reg(cs_bpf *bpf, bpf_op_type val, uint8_t ac_mode) | 
| 17 | 11.0k | { | 
| 18 | 11.0k |   cs_bpf_op *op = expand_bpf_operands(bpf); | 
| 19 |  |  | 
| 20 | 11.0k |   op->type = BPF_OP_REG; | 
| 21 | 11.0k |   op->reg = val; | 
| 22 | 11.0k |   op->access = ac_mode; | 
| 23 | 11.0k | } | 
| 24 |  |  | 
| 25 |  | static void push_op_imm(cs_bpf *bpf, uint64_t val) | 
| 26 | 9.11k | { | 
| 27 | 9.11k |   cs_bpf_op *op = expand_bpf_operands(bpf); | 
| 28 |  |  | 
| 29 | 9.11k |   op->type = BPF_OP_IMM; | 
| 30 | 9.11k |   op->imm = val; | 
| 31 | 9.11k | } | 
| 32 |  |  | 
| 33 |  | static void push_op_off(cs_bpf *bpf, uint32_t val) | 
| 34 | 4.52k | { | 
| 35 | 4.52k |   cs_bpf_op *op = expand_bpf_operands(bpf); | 
| 36 |  |  | 
| 37 | 4.52k |   op->type = BPF_OP_OFF; | 
| 38 | 4.52k |   op->off = val; | 
| 39 | 4.52k | } | 
| 40 |  |  | 
| 41 |  | static void push_op_mem(cs_bpf *bpf, bpf_reg reg, uint32_t val) | 
| 42 | 5.73k | { | 
| 43 | 5.73k |   cs_bpf_op *op = expand_bpf_operands(bpf); | 
| 44 |  |  | 
| 45 | 5.73k |   op->type = BPF_OP_MEM; | 
| 46 | 5.73k |   op->mem.base = reg; | 
| 47 | 5.73k |   op->mem.disp = val; | 
| 48 | 5.73k | } | 
| 49 |  |  | 
| 50 |  | static void push_op_mmem(cs_bpf *bpf, uint32_t val) | 
| 51 | 313 | { | 
| 52 | 313 |   cs_bpf_op *op = expand_bpf_operands(bpf); | 
| 53 |  |  | 
| 54 | 313 |   op->type = BPF_OP_MMEM; | 
| 55 | 313 |   op->mmem = val; | 
| 56 | 313 | } | 
| 57 |  |  | 
| 58 |  | static void push_op_msh(cs_bpf *bpf, uint32_t val) | 
| 59 | 221 | { | 
| 60 | 221 |   cs_bpf_op *op = expand_bpf_operands(bpf); | 
| 61 |  |  | 
| 62 | 221 |   op->type = BPF_OP_MSH; | 
| 63 | 221 |   op->msh = val; | 
| 64 | 221 | } | 
| 65 |  |  | 
| 66 |  | static void push_op_ext(cs_bpf *bpf, bpf_ext_type val) | 
| 67 | 414 | { | 
| 68 | 414 |   cs_bpf_op *op = expand_bpf_operands(bpf); | 
| 69 |  |  | 
| 70 | 414 |   op->type = BPF_OP_EXT; | 
| 71 | 414 |   op->ext = val; | 
| 72 | 414 | } | 
| 73 |  |  | 
| 74 |  | static void convert_operands(MCInst *MI, cs_bpf *bpf) | 
| 75 | 19.7k | { | 
| 76 | 19.7k |   unsigned opcode = MCInst_getOpcode(MI); | 
| 77 | 19.7k |   unsigned mc_op_count = MCInst_getNumOperands(MI); | 
| 78 | 19.7k |   MCOperand *op; | 
| 79 | 19.7k |   MCOperand *op2; | 
| 80 | 19.7k |   unsigned i; | 
| 81 |  |  | 
| 82 | 19.7k |   bpf->op_count = 0; | 
| 83 | 19.7k |   if (BPF_CLASS(opcode) == BPF_CLASS_LD || BPF_CLASS(opcode) == BPF_CLASS_LDX) { | 
| 84 | 5.76k |     switch (BPF_MODE(opcode)) { | 
| 85 | 1.38k |     case BPF_MODE_IMM: | 
| 86 | 1.38k |       if (EBPF_MODE(MI->csh)) { | 
| 87 | 708 |         push_op_reg(bpf, MCOperand_getReg(MCInst_getOperand(MI, 0)), CS_AC_WRITE); | 
| 88 | 708 |         push_op_imm(bpf, MCOperand_getImm(MCInst_getOperand(MI, 1))); | 
| 89 | 708 |       } else { | 
| 90 | 673 |         push_op_imm(bpf, MCOperand_getImm(MCInst_getOperand(MI, 0))); | 
| 91 | 673 |       } | 
| 92 | 1.38k |       break; | 
| 93 | 1.69k |     case BPF_MODE_ABS: | 
| 94 | 1.69k |       op = MCInst_getOperand(MI, 0); | 
| 95 | 1.69k |       push_op_mem(bpf, BPF_REG_INVALID, (uint32_t)MCOperand_getImm(op)); | 
| 96 | 1.69k |       break; | 
| 97 | 1.16k |     case BPF_MODE_IND: | 
| 98 | 1.16k |       op = MCInst_getOperand(MI, 0); | 
| 99 | 1.16k |       op2 = MCInst_getOperand(MI, 1); | 
| 100 | 1.16k |       push_op_mem(bpf, MCOperand_getReg(op), (uint32_t)MCOperand_getImm(op2)); | 
| 101 | 1.16k |       break; | 
| 102 | 891 |     case BPF_MODE_MEM: | 
| 103 | 891 |       if (EBPF_MODE(MI->csh)) { | 
| 104 |  |         /* ldx{w,h,b,dw} dst, [src+off] */ | 
| 105 | 641 |         push_op_reg(bpf, MCOperand_getReg(MCInst_getOperand(MI, 0)), CS_AC_WRITE); | 
| 106 | 641 |         op = MCInst_getOperand(MI, 1); | 
| 107 | 641 |         op2 = MCInst_getOperand(MI, 2); | 
| 108 | 641 |         push_op_mem(bpf, MCOperand_getReg(op), (uint32_t)MCOperand_getImm(op2)); | 
| 109 | 641 |       } | 
| 110 | 250 |       else { | 
| 111 | 250 |         push_op_mmem(bpf, (uint32_t)MCOperand_getImm(MCInst_getOperand(MI, 0))); | 
| 112 | 250 |       } | 
| 113 | 891 |       break; | 
| 114 | 414 |     case BPF_MODE_LEN: | 
| 115 | 414 |       push_op_ext(bpf, BPF_EXT_LEN); | 
| 116 | 414 |       break; | 
| 117 | 221 |     case BPF_MODE_MSH: | 
| 118 | 221 |       op = MCInst_getOperand(MI, 0); | 
| 119 | 221 |       push_op_msh(bpf, (uint32_t)MCOperand_getImm(op)); | 
| 120 | 221 |       break; | 
| 121 |  |     /* case BPF_MODE_XADD: // not exists */ | 
| 122 | 5.76k |     } | 
| 123 | 5.76k |     return; | 
| 124 | 5.76k |   } | 
| 125 | 13.9k |   if (BPF_CLASS(opcode) == BPF_CLASS_ST || BPF_CLASS(opcode) == BPF_CLASS_STX) { | 
| 126 | 2.30k |     if (!EBPF_MODE(MI->csh)) { | 
| 127 |  |       // cBPF has only one case - st* M[k] | 
| 128 | 63 |       push_op_mmem(bpf, (uint32_t)MCOperand_getImm(MCInst_getOperand(MI, 0))); | 
| 129 | 63 |       return; | 
| 130 | 63 |     } | 
| 131 |  |     /* eBPF has two cases: | 
| 132 |  |      * - st [dst + off], src | 
| 133 |  |      * - xadd [dst + off], src | 
| 134 |  |      * they have same form of operands. | 
| 135 |  |      */ | 
| 136 | 2.24k |     op = MCInst_getOperand(MI, 0); | 
| 137 | 2.24k |     op2 = MCInst_getOperand(MI, 1); | 
| 138 | 2.24k |     push_op_mem(bpf, MCOperand_getReg(op), (uint32_t)MCOperand_getImm(op2)); | 
| 139 | 2.24k |     op = MCInst_getOperand(MI, 2); | 
| 140 | 2.24k |     if (MCOperand_isImm(op)) | 
| 141 | 1.38k |       push_op_imm(bpf, MCOperand_getImm(op)); | 
| 142 | 857 |     else if (MCOperand_isReg(op)) | 
| 143 | 857 |       push_op_reg(bpf, MCOperand_getReg(op), CS_AC_READ); | 
| 144 | 2.24k |     return; | 
| 145 | 2.30k |   } | 
| 146 |  |  | 
| 147 | 11.6k |   if (BPF_CLASS(opcode) == BPF_CLASS_JMP) { | 
| 148 | 13.9k |     for (i = 0; i < mc_op_count; i++) { | 
| 149 | 9.48k |       op = MCInst_getOperand(MI, i); | 
| 150 | 9.48k |       if (MCOperand_isImm(op)) { | 
| 151 |  |         /* decide the imm is BPF_OP_IMM or BPF_OP_OFF type here */ | 
| 152 |  |         /* | 
| 153 |  |          * 1. ja +off | 
| 154 |  |          * 2. j {x,k}, +jt, +jf // cBPF | 
| 155 |  |          * 3. j dst_reg, {src_reg, k}, +off // eBPF | 
| 156 |  |          */ | 
| 157 | 6.76k |         if (BPF_OP(opcode) == BPF_JUMP_JA || | 
| 158 | 6.76k |             (!EBPF_MODE(MI->csh) && i >= 1) || | 
| 159 | 6.76k |             (EBPF_MODE(MI->csh) && i == 2)) | 
| 160 | 4.52k |           push_op_off(bpf, (uint32_t)MCOperand_getImm(op)); | 
| 161 | 2.23k |         else | 
| 162 | 2.23k |           push_op_imm(bpf, MCOperand_getImm(op)); | 
| 163 | 6.76k |       } | 
| 164 | 2.72k |       else if (MCOperand_isReg(op)) { | 
| 165 | 2.72k |         push_op_reg(bpf, MCOperand_getReg(op), CS_AC_READ); | 
| 166 | 2.72k |       } | 
| 167 | 9.48k |     } | 
| 168 | 4.44k |     return; | 
| 169 | 4.44k |   } | 
| 170 |  |  | 
| 171 | 7.19k |   if (!EBPF_MODE(MI->csh)) { | 
| 172 |  |     /* In cBPF mode, all registers in operands are accessed as read */ | 
| 173 | 5.21k |     for (i = 0; i < mc_op_count; i++) { | 
| 174 | 2.40k |       op = MCInst_getOperand(MI, i); | 
| 175 | 2.40k |       if (MCOperand_isImm(op)) | 
| 176 | 1.02k |         push_op_imm(bpf, MCOperand_getImm(op)); | 
| 177 | 1.37k |       else if (MCOperand_isReg(op)) | 
| 178 | 1.37k |         push_op_reg(bpf, MCOperand_getReg(op), CS_AC_READ); | 
| 179 | 2.40k |     } | 
| 180 | 2.81k |     return; | 
| 181 | 2.81k |   } | 
| 182 |  |  | 
| 183 |  |   /* remain cases are: eBPF mode && ALU */ | 
| 184 |  |   /* if (BPF_CLASS(opcode) == BPF_CLASS_ALU || BPF_CLASS(opcode) == BPF_CLASS_ALU64) */ | 
| 185 |  |  | 
| 186 |  |   /* We have three types: | 
| 187 |  |    * 1. {l,b}e dst               // dst = byteswap(dst) | 
| 188 |  |    * 2. neg dst                  // dst = -dst | 
| 189 |  |    * 3. <op> dst, {src_reg, imm} // dst = dst <op> src | 
| 190 |  |    * so we can simply check the number of operands, | 
| 191 |  |    * exactly one operand means we are in case 1. and 2., | 
| 192 |  |    * otherwise in case 3. | 
| 193 |  |    */ | 
| 194 | 4.38k |   if (mc_op_count == 1) { | 
| 195 | 889 |     op = MCInst_getOperand(MI, 0); | 
| 196 | 889 |     push_op_reg(bpf, MCOperand_getReg(op), CS_AC_READ | CS_AC_WRITE); | 
| 197 | 889 |   } | 
| 198 | 3.49k |   else { // if (mc_op_count == 2) | 
| 199 | 3.49k |     op = MCInst_getOperand(MI, 0); | 
| 200 | 3.49k |     push_op_reg(bpf, MCOperand_getReg(op), CS_AC_READ | CS_AC_WRITE); | 
| 201 |  |  | 
| 202 | 3.49k |     op = MCInst_getOperand(MI, 1); | 
| 203 | 3.49k |     if (MCOperand_isImm(op)) | 
| 204 | 3.08k |       push_op_imm(bpf, MCOperand_getImm(op)); | 
| 205 | 402 |     else if (MCOperand_isReg(op)) | 
| 206 | 402 |       push_op_reg(bpf, MCOperand_getReg(op), CS_AC_READ); | 
| 207 | 3.49k |   } | 
| 208 | 4.38k | } | 
| 209 |  |  | 
| 210 |  | static void print_operand(MCInst *MI, struct SStream *O, const cs_bpf_op *op) | 
| 211 | 31.4k | { | 
| 212 | 31.4k |   switch (op->type) { | 
| 213 | 0 |   case BPF_OP_INVALID: | 
| 214 | 0 |     SStream_concat(O, "invalid"); | 
| 215 | 0 |     break; | 
| 216 | 11.0k |   case BPF_OP_REG: | 
| 217 | 11.0k |     SStream_concat(O, BPF_reg_name((csh)MI->csh, op->reg)); | 
| 218 | 11.0k |     break; | 
| 219 | 9.11k |   case BPF_OP_IMM: | 
| 220 | 9.11k |     SStream_concat(O, "0x%" PRIx64, op->imm); | 
| 221 | 9.11k |     break; | 
| 222 | 4.52k |   case BPF_OP_OFF: | 
| 223 | 4.52k |     SStream_concat(O, "+0x%x", op->off); | 
| 224 | 4.52k |     break; | 
| 225 | 5.73k |   case BPF_OP_MEM: | 
| 226 | 5.73k |     SStream_concat(O, "["); | 
| 227 | 5.73k |     if (op->mem.base != BPF_REG_INVALID) | 
| 228 | 4.04k |       SStream_concat(O, BPF_reg_name((csh)MI->csh, op->mem.base)); | 
| 229 | 5.73k |     if (op->mem.disp != 0) { | 
| 230 | 5.61k |       if (op->mem.base != BPF_REG_INVALID) | 
| 231 | 4.00k |         SStream_concat(O, "+"); | 
| 232 | 5.61k |       SStream_concat(O, "0x%x", op->mem.disp); | 
| 233 | 5.61k |     } | 
| 234 | 5.73k |     if (op->mem.base == BPF_REG_INVALID && op->mem.disp == 0) // special case | 
| 235 | 79 |       SStream_concat(O, "0x0"); | 
| 236 | 5.73k |     SStream_concat(O, "]"); | 
| 237 | 5.73k |     break; | 
| 238 | 313 |   case BPF_OP_MMEM: | 
| 239 | 313 |     SStream_concat(O, "m[0x%x]", op->mmem); | 
| 240 | 313 |     break; | 
| 241 | 221 |   case BPF_OP_MSH: | 
| 242 | 221 |     SStream_concat(O, "4*([0x%x]&0xf)", op->msh); | 
| 243 | 221 |     break; | 
| 244 | 414 |   case BPF_OP_EXT: | 
| 245 | 414 |     switch (op->ext) { | 
| 246 | 414 |     case BPF_EXT_LEN: | 
| 247 | 414 |       SStream_concat(O, "#len"); | 
| 248 | 414 |       break; | 
| 249 | 414 |     } | 
| 250 | 414 |     break; | 
| 251 | 31.4k |   } | 
| 252 | 31.4k | } | 
| 253 |  |  | 
| 254 |  | /* | 
| 255 |  |  * 1. human readable mnemonic | 
| 256 |  |  * 2. set pubOpcode (BPF_INSN_*) | 
| 257 |  |  * 3. set detail->bpf.operands | 
| 258 |  |  * */ | 
| 259 |  | void BPF_printInst(MCInst *MI, struct SStream *O, void *PrinterInfo) | 
| 260 | 19.7k | { | 
| 261 | 19.7k |   int i; | 
| 262 | 19.7k |   cs_insn insn; | 
| 263 | 19.7k |   cs_bpf bpf; | 
| 264 |  |  | 
| 265 | 19.7k |   insn.detail = NULL; | 
| 266 |  |   /* set pubOpcode as instruction id */ | 
| 267 | 19.7k |   BPF_get_insn_id((cs_struct*)MI->csh, &insn, MCInst_getOpcode(MI)); | 
| 268 | 19.7k |   MCInst_setOpcodePub(MI, insn.id); | 
| 269 |  |  | 
| 270 | 19.7k |   SStream_concat(O, BPF_insn_name((csh)MI->csh, insn.id)); | 
| 271 | 19.7k |   convert_operands(MI, &bpf); | 
| 272 | 51.1k |   for (i = 0; i < bpf.op_count; i++) { | 
| 273 | 31.4k |     if (i == 0) | 
| 274 | 18.7k |       SStream_concat(O, "\t"); | 
| 275 | 12.6k |     else | 
| 276 | 12.6k |       SStream_concat(O, ", "); | 
| 277 | 31.4k |     print_operand(MI, O, &bpf.operands[i]); | 
| 278 | 31.4k |   } | 
| 279 |  |  | 
| 280 | 19.7k | #ifndef CAPSTONE_DIET | 
| 281 | 19.7k |   if (MI->flat_insn->detail) { | 
| 282 | 19.7k |     MI->flat_insn->detail->bpf = bpf; | 
| 283 | 19.7k |   } | 
| 284 | 19.7k | #endif | 
| 285 | 19.7k | } |