static void decode_bpf_code(uint16_t code) { uint16_t i = code & ~BPF_CLASS(code); printxval(bpf_class, BPF_CLASS(code), "BPF_???"); switch (BPF_CLASS(code)) { case BPF_LD: case BPF_LDX: tprints(" | "); printxval(bpf_size, BPF_SIZE(code), "BPF_???"); tprints(" | "); printxval(bpf_mode, BPF_MODE(code), "BPF_???"); break; case BPF_ST: case BPF_STX: if (i) tprintf(" | %#x /* %s */", i, "BPF_???"); break; case BPF_ALU: tprints(" | "); printxval(bpf_src, BPF_SRC(code), "BPF_???"); tprints(" | "); printxval(bpf_op_alu, BPF_OP(code), "BPF_???"); break; case BPF_JMP: tprints(" | "); printxval(bpf_src, BPF_SRC(code), "BPF_???"); tprints(" | "); printxval(bpf_op_jmp, BPF_OP(code), "BPF_???"); break; case BPF_RET: tprints(" | "); printxval(bpf_rval, BPF_RVAL(code), "BPF_???"); i &= ~BPF_RVAL(code); if (i) tprintf(" | %#x /* %s */", i, "BPF_???"); break; case BPF_MISC: tprints(" | "); printxval(bpf_miscop, BPF_MISCOP(code), "BPF_???"); i &= ~BPF_MISCOP(code); if (i) tprintf(" | %#x /* %s */", i, "BPF_???"); break; } }
/* * Return the register number that is used by s. If A and X are both * used, return AX_ATOM. If no register is used, return -1. * * The implementation should probably change to an array access. */ static int atomuse(struct stmt *s) { register int c = s->code; if (c == NOP) return -1; switch (BPF_CLASS(c)) { case BPF_RET: return (BPF_RVAL(c) == BPF_A) ? A_ATOM : (BPF_RVAL(c) == BPF_X) ? X_ATOM : -1; case BPF_LD: case BPF_LDX: return (BPF_MODE(c) == BPF_IND) ? X_ATOM : (BPF_MODE(c) == BPF_MEM) ? s->k : -1; case BPF_ST: return A_ATOM; case BPF_STX: return X_ATOM; case BPF_JMP: case BPF_ALU: if (BPF_SRC(c) == BPF_X) return AX_ATOM; return A_ATOM; case BPF_MISC: return BPF_MISCOP(c) == BPF_TXA ? X_ATOM : A_ATOM; } abort(); /* NOTREACHED */ }
/* * Return the register number that is defined by 's'. We assume that * a single stmt cannot define more than one register. If no register * is defined, return -1. * * The implementation should probably change to an array access. */ static int atomdef(struct stmt *s) { if (s->code == NOP) return -1; switch (BPF_CLASS(s->code)) { case BPF_LD: case BPF_ALU: return A_ATOM; case BPF_LDX: return X_ATOM; case BPF_ST: case BPF_STX: return s->k; case BPF_MISC: return BPF_MISCOP(s->code) == BPF_TAX ? X_ATOM : A_ATOM; } return -1; }
/* * 1. Convert opcode(id) to BPF_INS_* * 2. Set regs_read/regs_write/groups */ void BPF_get_insn_id(cs_struct *ud, cs_insn *insn, unsigned int opcode) { // No need to care the mode (cBPF or eBPF) since all checks has be done in // BPF_getInstruction, we can simply map opcode to BPF_INS_*. cs_detail *detail; bpf_insn id = BPF_INS_INVALID; bpf_insn_group grp; detail = insn->detail; #ifndef CAPSTONE_DIET #define PUSH_GROUP(grp) do { \ if (detail) { \ detail->groups[detail->groups_count] = grp; \ detail->groups_count++; \ } \ } while(0) #else #define PUSH_GROUP #endif switch (BPF_CLASS(opcode)) { default: // will never happen break; case BPF_CLASS_LD: case BPF_CLASS_LDX: id = op2insn_ld(opcode); PUSH_GROUP(BPF_GRP_LOAD); break; case BPF_CLASS_ST: case BPF_CLASS_STX: id = op2insn_st(opcode); PUSH_GROUP(BPF_GRP_STORE); break; case BPF_CLASS_ALU: id = op2insn_alu(opcode); PUSH_GROUP(BPF_GRP_ALU); break; case BPF_CLASS_JMP: grp = BPF_GRP_JUMP; id = op2insn_jmp(opcode); if (id == BPF_INS_CALL) grp = BPF_GRP_CALL; else if (id == BPF_INS_EXIT) grp = BPF_GRP_RETURN; PUSH_GROUP(grp); break; case BPF_CLASS_RET: id = BPF_INS_RET; PUSH_GROUP(BPF_GRP_RETURN); break; // BPF_CLASS_MISC and BPF_CLASS_ALU64 have exactly same value case BPF_CLASS_MISC: /* case BPF_CLASS_ALU64: */ if (EBPF_MODE(ud)) { // ALU64 in eBPF id = op2insn_alu(opcode); PUSH_GROUP(BPF_GRP_ALU); } else { if (BPF_MISCOP(opcode) == BPF_MISCOP_TXA) id = BPF_INS_TXA; else id = BPF_INS_TAX; PUSH_GROUP(BPF_GRP_MISC); } break; } insn->id = id; #undef PUSH_GROUP #ifndef CAPSTONE_DIET if (detail) { update_regs_access(ud, detail, id, opcode); } #endif }