R_API bool r_anal_op_fini(RAnalOp *op) { if (!op) { return false; } if (((ut64)(size_t)op) == UT64_MAX) { return false; } if (((ut64)(size_t)op->mnemonic) == UT64_MAX) { return false; } r_anal_var_free (op->var); r_anal_value_free (op->src[0]); r_anal_value_free (op->src[1]); r_anal_value_free (op->src[2]); r_anal_value_free (op->dst); r_strbuf_fini (&op->esil); r_anal_switch_op_free (op->switch_op); op->src[0] = NULL; op->src[1] = NULL; op->src[2] = NULL; op->dst = NULL; op->var = NULL; op->switch_op = NULL; R_FREE (op->mnemonic); R_FREE (op->reg); return true; }
R_API bool r_anal_op_fini(RAnalOp *op) { if (!op) { return false; } r_anal_var_free (op->var); op->var = NULL; r_anal_value_free (op->src[0]); r_anal_value_free (op->src[1]); r_anal_value_free (op->src[2]); op->src[0] = NULL; op->src[1] = NULL; op->src[2] = NULL; r_anal_value_free (op->dst); op->dst = NULL; r_strbuf_fini (&op->opex); r_strbuf_fini (&op->esil); r_anal_switch_op_free (op->switch_op); R_FREE (op->mnemonic); return true; }
static int analop(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len) { int n, ret, opsize = -1; static csh hndl = 0; static csh *handle = &hndl; static int omode = -1; static int obits = 32; cs_insn* insn; int mode = anal->big_endian? CS_MODE_BIG_ENDIAN: CS_MODE_LITTLE_ENDIAN; mode |= (anal->bits==64)? CS_MODE_64: CS_MODE_32; if (mode != omode || anal->bits != obits) { cs_close (&hndl); hndl = 0; omode = mode; obits = anal->bits; } // XXX no arch->cpu ?!?! CS_MODE_MICRO, N64 op->delay = 0; op->type = R_ANAL_OP_TYPE_ILL; if (len<4) return -1; op->size = 4; if (hndl == 0) { ret = cs_open (CS_ARCH_MIPS, mode, &hndl); if (ret != CS_ERR_OK) goto fin; cs_option (hndl, CS_OPT_DETAIL, CS_OPT_ON); } n = cs_disasm (hndl, (ut8*)buf, len, addr, 1, &insn); if (n<1 || insn->size<1) goto beach; op->type = R_ANAL_OP_TYPE_NULL; op->delay = 0; op->jump = UT64_MAX; op->fail = UT64_MAX; opsize = op->size = insn->size; switch (insn->id) { case MIPS_INS_INVALID: op->type = R_ANAL_OP_TYPE_ILL; break; case MIPS_INS_LB: case MIPS_INS_LBU: case MIPS_INS_LBUX: case MIPS_INS_LW: case MIPS_INS_LWC1: case MIPS_INS_LWC2: case MIPS_INS_LWL: case MIPS_INS_LWR: case MIPS_INS_LWXC1: case MIPS_INS_LD: case MIPS_INS_LDC1: case MIPS_INS_LDC2: case MIPS_INS_LDL: case MIPS_INS_LDR: case MIPS_INS_LDXC1: op->type = R_ANAL_OP_TYPE_LOAD; op->refptr = 4; switch (OPERAND(1).type) { case MIPS_OP_MEM: if (OPERAND(1).mem.base == MIPS_REG_GP) { op->ptr = anal->gp + OPERAND(1).mem.disp; op->refptr = 4; } break; case MIPS_OP_IMM: op->ptr = OPERAND(1).imm; break; case MIPS_OP_REG: // wtf? break; default: break; } // TODO: fill break; case MIPS_INS_SW: case MIPS_INS_SWC1: case MIPS_INS_SWC2: case MIPS_INS_SWL: case MIPS_INS_SWR: case MIPS_INS_SWXC1: op->type = R_ANAL_OP_TYPE_STORE; break; case MIPS_INS_NOP: op->type = R_ANAL_OP_TYPE_NOP; break; case MIPS_INS_SYSCALL: case MIPS_INS_BREAK: op->type = R_ANAL_OP_TYPE_TRAP; break; case MIPS_INS_JALR: op->type = R_ANAL_OP_TYPE_UCALL; op->delay = 1; break; case MIPS_INS_JAL: case MIPS_INS_JALS: case MIPS_INS_JALX: case MIPS_INS_JRADDIUSP: case MIPS_INS_BAL: // (no blezal/bgtzal or blezall/bgtzall, only blezalc/bgtzalc) case MIPS_INS_BLTZAL: // Branch on <0 and link case MIPS_INS_BGEZAL: // Branch on >=0 and link case MIPS_INS_BLTZALL: // "likely" versions case MIPS_INS_BGEZALL: case MIPS_INS_BLTZALC: // compact versions case MIPS_INS_BLEZALC: case MIPS_INS_BGEZALC: case MIPS_INS_BGTZALC: case MIPS_INS_JIALC: case MIPS_INS_JIC: op->type = R_ANAL_OP_TYPE_CALL; op->jump = IMM(0); switch (insn->id) { case MIPS_INS_JIALC: case MIPS_INS_JIC: case MIPS_INS_BLTZALC: case MIPS_INS_BLEZALC: case MIPS_INS_BGEZALC: case MIPS_INS_BGTZALC: // compact vesions (no delay) op->delay = 0; op->fail = addr+4; break; default: op->delay = 1; op->fail = addr+8; break; } break; case MIPS_INS_LUI: case MIPS_INS_MOVE: op->type = R_ANAL_OP_TYPE_MOV; SET_SRC_DST_2_REGS (op); break; case MIPS_INS_ADD: case MIPS_INS_ADDI: case MIPS_INS_ADDU: case MIPS_INS_ADDIU: case MIPS_INS_DADD: case MIPS_INS_DADDI: case MIPS_INS_DADDIU: SET_VAL (op, 2); SET_SRC_DST_3_REG_OR_IMM (op); op->type = R_ANAL_OP_TYPE_ADD; break; case MIPS_INS_SUB: case MIPS_INS_SUBV: case MIPS_INS_SUBVI: case MIPS_INS_DSUBU: case MIPS_INS_FSUB: case MIPS_INS_FMSUB: case MIPS_INS_SUBU: case MIPS_INS_DSUB: case MIPS_INS_SUBS_S: case MIPS_INS_SUBS_U: case MIPS_INS_SUBUH: case MIPS_INS_SUBUH_R: SET_VAL (op,2); SET_SRC_DST_3_REG_OR_IMM (op); op->type = R_ANAL_OP_TYPE_SUB; break; case MIPS_INS_MULV: case MIPS_INS_MULT: case MIPS_INS_MULSA: case MIPS_INS_FMUL: case MIPS_INS_MUL: case MIPS_INS_DMULT: case MIPS_INS_DMULTU: op->type = R_ANAL_OP_TYPE_MUL; break; case MIPS_INS_XOR: case MIPS_INS_XORI: SET_VAL (op,2); SET_SRC_DST_3_REG_OR_IMM (op); op->type = R_ANAL_OP_TYPE_XOR; break; case MIPS_INS_AND: case MIPS_INS_ANDI: SET_VAL (op,2); SET_SRC_DST_3_REG_OR_IMM (op); op->type = R_ANAL_OP_TYPE_AND; break; case MIPS_INS_NOT: op->type = R_ANAL_OP_TYPE_NOT; break; case MIPS_INS_OR: case MIPS_INS_ORI: SET_VAL (op,2); SET_SRC_DST_3_REG_OR_IMM (op); op->type = R_ANAL_OP_TYPE_OR; break; case MIPS_INS_DIV: case MIPS_INS_DIVU: case MIPS_INS_DDIV: case MIPS_INS_DDIVU: case MIPS_INS_FDIV: case MIPS_INS_DIV_S: case MIPS_INS_DIV_U: SET_SRC_DST_3_REGS (op); op->type = R_ANAL_OP_TYPE_DIV; break; case MIPS_INS_CMPGDU: case MIPS_INS_CMPGU: case MIPS_INS_CMPU: case MIPS_INS_CMPI: op->type = R_ANAL_OP_TYPE_CMP; break; case MIPS_INS_J: case MIPS_INS_B: case MIPS_INS_BZ: case MIPS_INS_BEQ: case MIPS_INS_BNZ: case MIPS_INS_BNE: case MIPS_INS_BEQZ: case MIPS_INS_BNEG: case MIPS_INS_BNEGI: case MIPS_INS_BNEZ: case MIPS_INS_BTEQZ: case MIPS_INS_BTNEZ: case MIPS_INS_BLTZ: case MIPS_INS_BLTZL: case MIPS_INS_BLEZ: case MIPS_INS_BLEZL: case MIPS_INS_BGEZ: case MIPS_INS_BGEZL: case MIPS_INS_BGTZ: case MIPS_INS_BGTZL: case MIPS_INS_BLEZC: case MIPS_INS_BGEZC: case MIPS_INS_BLTZC: case MIPS_INS_BGTZC: if (insn->id == MIPS_INS_J || insn->id == MIPS_INS_B ) { op->type = R_ANAL_OP_TYPE_JMP; } else { op->type = R_ANAL_OP_TYPE_CJMP; } if (OPERAND(0).type == MIPS_OP_IMM) { op->jump = IMM(0); } else if (OPERAND(1).type == MIPS_OP_IMM) { op->jump = IMM(1); } else if (OPERAND(2).type == MIPS_OP_IMM) { op->jump = IMM(2); } switch (insn->id) { case MIPS_INS_BLEZC: case MIPS_INS_BGEZC: case MIPS_INS_BLTZC: case MIPS_INS_BGTZC: // compact vesions (no delay) op->delay = 0; op->fail = addr+4; break; default: op->delay = 1; op->fail = addr+8; break; } break; case MIPS_INS_JR: case MIPS_INS_JRC: op->type = R_ANAL_OP_TYPE_JMP; op->delay = 1; // register is $ra, so jmp is a return if (insn->detail->mips.operands[0].reg == MIPS_REG_RA) { op->type = R_ANAL_OP_TYPE_RET; } break; case MIPS_INS_SLTI: case MIPS_INS_SLTIU: SET_SRC_DST_3_IMM (op); SET_VAL (op,2); break; case MIPS_INS_SHRAV: case MIPS_INS_SHRAV_R: case MIPS_INS_SHRA: case MIPS_INS_SHRA_R: case MIPS_INS_SRA: op->type = R_ANAL_OP_TYPE_SAR; SET_SRC_DST_3_REG_OR_IMM (op); SET_VAL (op,2); break; case MIPS_INS_SHRL: case MIPS_INS_SRLV: case MIPS_INS_SRL: op->type = R_ANAL_OP_TYPE_SHR; SET_SRC_DST_3_REG_OR_IMM (op); SET_VAL (op,2); break; case MIPS_INS_SLLV: case MIPS_INS_SLL: op->type = R_ANAL_OP_TYPE_SHL; SET_SRC_DST_3_REG_OR_IMM (op); SET_VAL (op,2); break; } beach: if (anal->decode) { if (analop_esil (anal, op, addr, buf, len, &hndl, insn) != 0) r_strbuf_fini (&op->esil); } cs_free (insn, n); //cs_close (&handle); fin: return opsize; }
R_API void r_strbuf_free(RStrBuf *sb) { r_strbuf_fini (sb); free (sb); }
static int analop(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len) { csh handle; cs_insn *insn; int mode = (a->bits==16)? CS_MODE_THUMB: CS_MODE_ARM; int i, n, ret = (a->bits==64)? cs_open (CS_ARCH_ARM64, mode, &handle): cs_open (CS_ARCH_ARM, mode, &handle); cs_option (handle, CS_OPT_DETAIL, CS_OPT_ON); op->type = R_ANAL_OP_TYPE_NULL; op->size = (a->bits==16)? 2: 4; op->delay = 0; r_strbuf_init (&op->esil); if (ret == CS_ERR_OK) { n = cs_disasm_ex (handle, (ut8*)buf, len, addr, 1, &insn); if (n<1) { op->type = R_ANAL_OP_TYPE_ILL; } else { op->size = insn->size; switch (insn->id) { case ARM_INS_POP: case ARM_INS_LDM: op->type = R_ANAL_OP_TYPE_POP; for (i = 0; i < insn->detail->arm.op_count; i++) { if (insn->detail->arm.operands[i].type == ARM_OP_REG && insn->detail->arm.operands[i].reg == ARM_REG_PC) { if (insn->detail->arm.cc == ARM_CC_AL) op->type = R_ANAL_OP_TYPE_RET; else op->type = R_ANAL_OP_TYPE_CRET; break; } } break; case ARM_INS_SUB: op->type = R_ANAL_OP_TYPE_SUB; break; case ARM_INS_ADD: op->type = R_ANAL_OP_TYPE_ADD; break; case ARM_INS_MOV: case ARM_INS_MOVS: case ARM_INS_MOVT: case ARM_INS_MOVW: case ARM_INS_VMOVL: case ARM_INS_VMOVN: case ARM_INS_VQMOVUN: case ARM_INS_VQMOVN: op->type = R_ANAL_OP_TYPE_MOV; break; case ARM_INS_CMP: case ARM_INS_TST: op->type = R_ANAL_OP_TYPE_CMP; break; case ARM_INS_ROR: case ARM_INS_ORN: case ARM_INS_LSL: case ARM_INS_LSR: break; case ARM_INS_PUSH: case ARM_INS_STR: //case ARM_INS_POP: case ARM_INS_LDR: op->type = R_ANAL_OP_TYPE_LOAD; break; case ARM_INS_BL: case ARM_INS_BLX: op->type = R_ANAL_OP_TYPE_CALL; op->jump = IMM(0); break; case ARM_INS_B: case ARM_INS_BX: case ARM_INS_BXJ: if (insn->detail->arm.cc) { op->type = R_ANAL_OP_TYPE_CJMP; op->jump = IMM(0); op->fail = addr+op->size; } else { op->type = R_ANAL_OP_TYPE_JMP; op->jump = IMM(0); } break; } if (a->decode) { if (!analop_esil (a, op, addr, buf, len, &handle, insn)) r_strbuf_fini (&op->esil); } cs_free (insn, n); } } cs_close (&handle); return op->size; }
R_API void r_asm_op_fini(RAsmOp *op) { r_strbuf_fini (&op->buf); r_strbuf_fini (&op->buf_asm); r_strbuf_fini (&op->buf_hex); r_buf_fini (op->buf_inc); }
static int analop(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len) { int n, ret, opsize = -1; csh handle; cs_insn* insn; int mode = a->big_endian? CS_MODE_BIG_ENDIAN: CS_MODE_LITTLE_ENDIAN; mode |= (a->bits==64)? CS_MODE_64: CS_MODE_32; // XXX no arch->cpu ?!?! CS_MODE_MICRO, N64 ret = cs_open (CS_ARCH_MIPS, mode, &handle); op->delay = 0; op->type = R_ANAL_OP_TYPE_ILL; op->size = 4; if (ret != CS_ERR_OK) goto fin; cs_option (handle, CS_OPT_DETAIL, CS_OPT_ON); n = cs_disasm (handle, (ut8*)buf, len, addr, 1, &insn); if (n<1 || insn->size<1) goto beach; op->type = R_ANAL_OP_TYPE_NULL; op->delay = 0; opsize = op->size = insn->size; switch (insn->id) { case MIPS_INS_INVALID: op->type = R_ANAL_OP_TYPE_ILL; break; case MIPS_INS_LB: case MIPS_INS_LBU: case MIPS_INS_LBUX: case MIPS_INS_LW: case MIPS_INS_LWC1: case MIPS_INS_LWC2: case MIPS_INS_LWL: case MIPS_INS_LWR: case MIPS_INS_LWXC1: case MIPS_INS_LD: case MIPS_INS_LDC1: case MIPS_INS_LDC2: case MIPS_INS_LDL: case MIPS_INS_LDR: case MIPS_INS_LDXC1: op->type = R_ANAL_OP_TYPE_LOAD; op->refptr = 4; switch (OPERAND(1).type) { case MIPS_OP_MEM: if (OPERAND(1).mem.base == MIPS_REG_GP) { op->ptr = a->gp + OPERAND(1).mem.disp; op->refptr = 4; } break; case MIPS_OP_IMM: op->ptr = OPERAND(1).imm; break; case MIPS_OP_REG: // wtf? break; default: break; } // TODO: fill break; case MIPS_INS_SW: case MIPS_INS_SWC1: case MIPS_INS_SWC2: case MIPS_INS_SWL: case MIPS_INS_SWR: case MIPS_INS_SWXC1: op->type = R_ANAL_OP_TYPE_STORE; break; case MIPS_INS_NOP: op->type = R_ANAL_OP_TYPE_NOP; break; case MIPS_INS_SYSCALL: case MIPS_INS_BREAK: op->type = R_ANAL_OP_TYPE_TRAP; break; case MIPS_INS_JALR: op->type = R_ANAL_OP_TYPE_UCALL; op->delay = 1; break; case MIPS_INS_JAL: case MIPS_INS_JALS: case MIPS_INS_JALX: case MIPS_INS_JIALC: case MIPS_INS_JIC: case MIPS_INS_JRADDIUSP: case MIPS_INS_BAL: case MIPS_INS_BGEZAL: // Branch on less than zero and link op->type = R_ANAL_OP_TYPE_CALL; op->delay = 1; op->jump = IMM(0); op->fail = addr+4; break; case MIPS_INS_MOVE: op->type = R_ANAL_OP_TYPE_MOV; break; case MIPS_INS_ADD: case MIPS_INS_ADDI: case MIPS_INS_ADDIU: case MIPS_INS_DADD: case MIPS_INS_DADDI: case MIPS_INS_DADDIU: op->type = R_ANAL_OP_TYPE_ADD; break; case MIPS_INS_SUB: case MIPS_INS_SUBV: case MIPS_INS_SUBVI: case MIPS_INS_DSUBU: case MIPS_INS_FSUB: case MIPS_INS_FMSUB: case MIPS_INS_SUBU: case MIPS_INS_DSUB: case MIPS_INS_SUBS_S: case MIPS_INS_SUBS_U: case MIPS_INS_SUBUH: case MIPS_INS_SUBUH_R: op->type = R_ANAL_OP_TYPE_SUB; break; case MIPS_INS_MULV: case MIPS_INS_MULT: case MIPS_INS_MULSA: case MIPS_INS_FMUL: case MIPS_INS_MUL: case MIPS_INS_DMULT: case MIPS_INS_DMULTU: op->type = R_ANAL_OP_TYPE_MUL; break; case MIPS_INS_XOR: case MIPS_INS_XORI: op->type = R_ANAL_OP_TYPE_XOR; break; case MIPS_INS_AND: case MIPS_INS_ANDI: op->type = R_ANAL_OP_TYPE_AND; break; case MIPS_INS_NOT: op->type = R_ANAL_OP_TYPE_NOT; break; case MIPS_INS_OR: case MIPS_INS_ORI: op->type = R_ANAL_OP_TYPE_OR; break; case MIPS_INS_DIV: case MIPS_INS_DIVU: case MIPS_INS_DDIV: case MIPS_INS_DDIVU: case MIPS_INS_FDIV: case MIPS_INS_DIV_S: case MIPS_INS_DIV_U: op->type = R_ANAL_OP_TYPE_DIV; break; case MIPS_INS_CMPGDU: case MIPS_INS_CMPGU: case MIPS_INS_CMPU: case MIPS_INS_CMPI: op->type = R_ANAL_OP_TYPE_CMP; break; case MIPS_INS_J: case MIPS_INS_B: case MIPS_INS_BZ: case MIPS_INS_BEQ: case MIPS_INS_BNZ: case MIPS_INS_BNE: case MIPS_INS_BEQZ: case MIPS_INS_BNEG: case MIPS_INS_BNEGI: case MIPS_INS_BNEZ: case MIPS_INS_BTEQZ: case MIPS_INS_BTNEZ: case MIPS_INS_BLTZ: case MIPS_INS_BGEZ: case MIPS_INS_BGEZC: case MIPS_INS_BGEZALC: op->type = R_ANAL_OP_TYPE_JMP; op->delay = 1; if (OPERAND(0).type == MIPS_OP_IMM) { op->jump = IMM(0); } else if (OPERAND(1).type == MIPS_OP_IMM) { op->jump = IMM(1); } else if (OPERAND(2).type == MIPS_OP_IMM) { op->jump = IMM(2); } break; case MIPS_INS_JR: case MIPS_INS_JRC: op->type = R_ANAL_OP_TYPE_JMP; op->delay = 1; // register 32 is $ra, so jmp is a return if (insn->detail->mips.operands[0].reg == 32) { op->type = R_ANAL_OP_TYPE_RET; } break; } beach: if (a->decode) { if (!analop_esil (a, op, addr, buf, len, &handle, insn)) r_strbuf_fini (&op->esil); } cs_free (insn, n); cs_close (&handle); fin: return opsize; }
static int analop(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len) { static csh handle = 0; static int omode = -1, obits = -1; int n, ret; cs_insn *insn; int mode = (a->bits == 64) ? CS_MODE_64 : (a->bits == 32) ? CS_MODE_32 : 0; mode |= a->big_endian ? CS_MODE_BIG_ENDIAN : CS_MODE_LITTLE_ENDIAN; op->delay = 0; op->type = R_ANAL_OP_TYPE_NULL; op->jump = UT64_MAX; op->fail = UT64_MAX; op->ptr = op->val = UT64_MAX; if (a->cpu && strncmp (a->cpu, "vle", 3) == 0) { // vle is big-endian only if (!a->big_endian) { return -1; } ret = analop_vle (a, op, addr, buf, len); if (ret >= 0) { return op->size; } } if (mode != omode || a->bits != obits) { cs_close (&handle); handle = 0; omode = mode; obits = a->bits; } if (handle == 0) { ret = cs_open (CS_ARCH_PPC, mode, &handle); if (ret != CS_ERR_OK) { return -1; } cs_option (handle, CS_OPT_DETAIL, CS_OPT_ON); } op->size = 4; r_strbuf_init (&op->esil); r_strbuf_set (&op->esil, ""); // capstone-next n = cs_disasm (handle, (const ut8*)buf, len, addr, 1, &insn); if (n < 1) { op->type = R_ANAL_OP_TYPE_ILL; } else { opex (&op->opex, handle, insn); struct Getarg gop = { .handle = handle, .insn = insn, .bits = a->bits }; op->size = insn->size; op->id = insn->id; switch (insn->id) { #if CS_API_MAJOR >= 4 case PPC_INS_CMPB: #endif case PPC_INS_CMPD: case PPC_INS_CMPDI: case PPC_INS_CMPLD: case PPC_INS_CMPLDI: case PPC_INS_CMPLW: case PPC_INS_CMPLWI: case PPC_INS_CMPW: case PPC_INS_CMPWI: op->type = R_ANAL_OP_TYPE_CMP; op->sign = true; if (ARG (2)[0] == '\0') esilprintf (op, "%s,%s,-,0xff,&,cr0,=", ARG (1), ARG (0)); else esilprintf (op, "%s,%s,-,0xff,&,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_MFLR: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "lr,%s,=", ARG (0)); break; case PPC_INS_MTLR: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "%s,lr,=", ARG (0)); break; case PPC_INS_MR: case PPC_INS_LI: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "%s,%s,=", ARG (1), ARG (0)); break; case PPC_INS_LIS: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "%s0000,%s,=", ARG (1), ARG (0)); break; case PPC_INS_CLRLWI: op->type = R_ANAL_OP_TYPE_AND; esilprintf (op, "%s,%s,&,%s,=", ARG (1), cmask32 (ARG (2), "0x1F"), ARG (0)); break; case PPC_INS_RLWINM: op->type = R_ANAL_OP_TYPE_ROL; esilprintf (op, "%s,%s,<<<,%s,&,%s,=", ARG (2), ARG (1), cmask32 (ARG (3), ARG (4)), ARG (0)); break; case PPC_INS_SC: op->type = R_ANAL_OP_TYPE_SWI; esilprintf (op, "0,$"); break; case PPC_INS_EXTSB: op->sign = true; op->type = R_ANAL_OP_TYPE_MOV; if (a->bits == 64) esilprintf (op, "%s,0x80,&,?{,0xFFFFFFFFFFFFFF00,%s,|,%s,=,}", ARG (1), ARG (1), ARG (0)); else esilprintf (op, "%s,0x80,&,?{,0xFFFFFF00,%s,|,%s,=,}", ARG (1), ARG (1), ARG (0)); break; case PPC_INS_EXTSH: op->sign = true; if (a->bits == 64) esilprintf (op, "%s,0x8000,&,?{,0xFFFFFFFFFFFF0000,%s,|,%s,=,}", ARG (1), ARG (1), ARG (0)); else esilprintf (op, "%s,0x8000,&,?{,0xFFFF0000,%s,|,%s,=,}", ARG (1), ARG (1), ARG (0)); break; case PPC_INS_EXTSW: op->sign = true; esilprintf (op, "%s,0x80000000,&,?{,0xFFFFFFFF00000000,%s,|,%s,=,}", ARG (1), ARG (1), ARG (0)); break; case PPC_INS_SYNC: case PPC_INS_ISYNC: case PPC_INS_LWSYNC: case PPC_INS_MSYNC: case PPC_INS_PTESYNC: case PPC_INS_TLBSYNC: case PPC_INS_SLBIA: case PPC_INS_SLBIE: case PPC_INS_SLBMFEE: case PPC_INS_SLBMTE: case PPC_INS_EIEIO: case PPC_INS_NOP: op->type = R_ANAL_OP_TYPE_NOP; esilprintf (op, ","); break; case PPC_INS_STW: case PPC_INS_STWU: case PPC_INS_STWUX: case PPC_INS_STWX: case PPC_INS_STWCX: op->type = R_ANAL_OP_TYPE_STORE; esilprintf (op, "%s,%s", ARG (0), ARG2 (1, "=[4]")); break; case PPC_INS_STWBRX: op->type = R_ANAL_OP_TYPE_STORE; break; case PPC_INS_STB: case PPC_INS_STBU: op->type = R_ANAL_OP_TYPE_STORE; esilprintf (op, "%s,%s", ARG (0), ARG2 (1, "=[1]")); break; case PPC_INS_STH: case PPC_INS_STHU: op->type = R_ANAL_OP_TYPE_STORE; esilprintf (op, "%s,%s", ARG (0), ARG2 (1, "=[2]")); break; case PPC_INS_STD: case PPC_INS_STDU: op->type = R_ANAL_OP_TYPE_STORE; esilprintf (op, "%s,%s", ARG (0), ARG2 (1, "=[8]")); break; case PPC_INS_LBZ: #if CS_API_MAJOR >= 4 case PPC_INS_LBZCIX: #endif case PPC_INS_LBZU: case PPC_INS_LBZUX: case PPC_INS_LBZX: op->type = R_ANAL_OP_TYPE_LOAD; esilprintf (op, "%s,%s,=", ARG2 (1, "[1]"), ARG (0)); break; case PPC_INS_LD: case PPC_INS_LDARX: #if CS_API_MAJOR >= 4 case PPC_INS_LDCIX: #endif case PPC_INS_LDU: case PPC_INS_LDUX: case PPC_INS_LDX: op->type = R_ANAL_OP_TYPE_LOAD; esilprintf (op, "%s,%s,=", ARG2 (1, "[8]"), ARG (0)); break; case PPC_INS_LDBRX: op->type = R_ANAL_OP_TYPE_LOAD; break; case PPC_INS_LFD: case PPC_INS_LFDU: case PPC_INS_LFDUX: case PPC_INS_LFDX: case PPC_INS_LFIWAX: case PPC_INS_LFIWZX: case PPC_INS_LFS: case PPC_INS_LFSU: case PPC_INS_LFSUX: case PPC_INS_LFSX: op->type = R_ANAL_OP_TYPE_LOAD; esilprintf (op, "%s,%s,=", ARG2 (1, "[4]"), ARG (0)); break; case PPC_INS_LHA: case PPC_INS_LHAU: case PPC_INS_LHAUX: case PPC_INS_LHAX: case PPC_INS_LHZ: case PPC_INS_LHZU: op->type = R_ANAL_OP_TYPE_LOAD; esilprintf (op, "%s,%s,=", ARG2 (1, "[2]"), ARG (0)); break; case PPC_INS_LHBRX: op->type = R_ANAL_OP_TYPE_LOAD; break; case PPC_INS_LWA: case PPC_INS_LWARX: case PPC_INS_LWAUX: case PPC_INS_LWAX: case PPC_INS_LWZ: #if CS_API_MAJOR >= 4 case PPC_INS_LWZCIX: #endif case PPC_INS_LWZU: case PPC_INS_LWZUX: case PPC_INS_LWZX: op->type = R_ANAL_OP_TYPE_LOAD; esilprintf (op, "%s,%s,=", ARG2 (1, "[4]"), ARG (0)); break; case PPC_INS_LWBRX: op->type = R_ANAL_OP_TYPE_LOAD; break; case PPC_INS_SLW: case PPC_INS_SLWI: op->type = R_ANAL_OP_TYPE_SHL; esilprintf (op, "%s,%s,<<,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_SRW: case PPC_INS_SRWI: op->type = R_ANAL_OP_TYPE_SHR; esilprintf (op, "%s,%s,>>,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_MULLI: op->sign = true; case PPC_INS_MULLW: case PPC_INS_MULLD: op->type = R_ANAL_OP_TYPE_MUL; esilprintf (op, "%s,%s,*,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_SUB: case PPC_INS_SUBC: case PPC_INS_SUBF: case PPC_INS_SUBFIC: case PPC_INS_SUBFZE: op->type = R_ANAL_OP_TYPE_SUB; esilprintf (op, "%s,%s,-,%s,=", ARG (1), ARG (2), ARG (0)); break; case PPC_INS_ADD: case PPC_INS_ADDI: op->sign = true; op->type = R_ANAL_OP_TYPE_ADD; esilprintf (op, "%s,%s,+,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_ADDC: case PPC_INS_ADDIC: op->type = R_ANAL_OP_TYPE_ADD; esilprintf (op, "%s,%s,+,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_ADDE: case PPC_INS_ADDIS: case PPC_INS_ADDME: case PPC_INS_ADDZE: op->type = R_ANAL_OP_TYPE_ADD; esilprintf (op, "%s,%s,+,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_MTSPR: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "%s,%s,=", ARG (1), PPCSPR (0)); break; case PPC_INS_BCTR: // switch table here op->type = R_ANAL_OP_TYPE_UJMP; esilprintf (op, "ctr,pc,="); break; case PPC_INS_BCTRL: // switch table here op->type = R_ANAL_OP_TYPE_CALL; esilprintf (op, "pc,lr,=,ctr,pc,="); break; case PPC_INS_B: case PPC_INS_BC: op->jump = ARG (1)[0] == '\0' ? IMM (0) : IMM (1); op->type = R_ANAL_OP_TYPE_CJMP; op->fail = addr + op->size; switch (insn->detail->ppc.bc) { case PPC_BC_LT: if (ARG (1)[0] == '\0') { esilprintf (op, "0,cr0,<,?{,%s,pc,=,},", ARG (0)); } else { esilprintf (op, "0,%s,<,?{,%s,pc,=,},", ARG (0), ARG (1)); } break; case PPC_BC_LE: if (ARG (1)[0] == '\0') { esilprintf (op, "0,cr0,<=,?{,%s,pc,=,},", ARG (0)); } else { esilprintf (op, "0,%s,<=,?{,%s,pc,=,},", ARG (0), ARG (1)); } break; case PPC_BC_EQ: if (ARG (1)[0] == '\0') { esilprintf (op, "0,cr0,==,?{,%s,pc,=,},", ARG (0)); } else { esilprintf (op, "0,%s,==,?{,%s,pc,=,},", ARG (0), ARG (1)); } break; case PPC_BC_GE: if (ARG (1)[0] == '\0') { esilprintf (op, "0,cr0,>=,?{,%s,pc,=,},", ARG (0)); } else { esilprintf (op, "0,%s,>=,?{,%s,pc,=,},", ARG (0), ARG (1)); } break; case PPC_BC_GT: if (ARG (1)[0] == '\0') { esilprintf (op, "0,cr0,>,?{,%s,pc,=,},", ARG (0)); } else { esilprintf (op, "0,%s,>,?{,%s,pc,=,},", ARG (0), ARG (1)); } break; case PPC_BC_NE: if (ARG (1)[0] == '\0') { esilprintf (op, "cr0,?{,%s,pc,=,},", ARG (0)); } else { esilprintf (op, "%s,?{,%s,pc,=,},", ARG (0), ARG (1)); } break; case PPC_BC_INVALID: op->type = R_ANAL_OP_TYPE_JMP; esilprintf (op, "%s,pc,=", ARG (0)); case PPC_BC_UN: // unordered case PPC_BC_NU: // not unordered case PPC_BC_SO: // summary overflow case PPC_BC_NS: // not summary overflow default: break; } break; case PPC_INS_BA: switch (insn->detail->ppc.operands[0].type) { case PPC_OP_CRX: op->type = R_ANAL_OP_TYPE_CJMP; op->fail = addr + op->size; break; case PPC_OP_REG: if (op->type == R_ANAL_OP_TYPE_CJMP) { op->type = R_ANAL_OP_TYPE_UCJMP; } else { op->type = R_ANAL_OP_TYPE_CJMP; } op->jump = IMM (1); op->fail = addr + op->size; //op->type = R_ANAL_OP_TYPE_UJMP; default: break; } break; case PPC_INS_BDNZ: op->type = R_ANAL_OP_TYPE_CJMP; op->jump = IMM (0); op->fail = addr + op->size; esilprintf (op, "1,ctr,-=,ctr,?{,%s,pc,=,}", ARG (0)); break; case PPC_INS_BDNZA: op->type = R_ANAL_OP_TYPE_CJMP; op->jump = IMM (0); op->fail = addr + op->size; break; case PPC_INS_BDNZL: op->type = R_ANAL_OP_TYPE_CJMP; op->jump = IMM (0); op->fail = addr + op->size; break; case PPC_INS_BDNZLA: op->type = R_ANAL_OP_TYPE_CJMP; op->jump = IMM (0); op->fail = addr + op->size; break; case PPC_INS_BDNZLR: op->type = R_ANAL_OP_TYPE_CJMP; op->fail = addr + op->size; esilprintf (op, "1,ctr,-=,ctr,?{,lr,pc,=,},"); break; case PPC_INS_BDNZLRL: op->fail = addr + op->size; op->type = R_ANAL_OP_TYPE_CJMP; break; case PPC_INS_BDZ: op->type = R_ANAL_OP_TYPE_CJMP; op->jump = IMM (0); op->fail = addr + op->size; esilprintf (op, "1,ctr,-=,ctr,0,==,?{,%s,pc,=,}", ARG (0)); break; case PPC_INS_BDZA: op->type = R_ANAL_OP_TYPE_CJMP; op->jump = IMM (0); op->fail = addr + op->size; break; case PPC_INS_BDZL: op->type = R_ANAL_OP_TYPE_CJMP; op->jump = IMM (0); op->fail = addr + op->size; break; case PPC_INS_BDZLA: op->type = R_ANAL_OP_TYPE_CJMP; op->jump = IMM (0); op->fail = addr + op->size; break; case PPC_INS_BDZLR: op->type = R_ANAL_OP_TYPE_CJMP; op->fail = addr + op->size; esilprintf (op, "1,ctr,-=,ctr,0,==,?{,lr,pc,=,}"); break; case PPC_INS_BDZLRL: op->type = R_ANAL_OP_TYPE_CJMP; op->fail = addr + op->size; break; case PPC_INS_BLR: case PPC_INS_BLRL: case PPC_INS_BCLR: case PPC_INS_BCLRL: op->type = R_ANAL_OP_TYPE_CRET; op->fail = addr + op->size; switch (insn->detail->ppc.bc) { case PPC_BC_INVALID: op->type = R_ANAL_OP_TYPE_RET; esilprintf (op, "lr,pc,="); break; case PPC_BC_LT: if (ARG (0)[0] == '\0') { esilprintf (op, "0,cr0,<,?{,lr,pc,=,},"); } else { esilprintf (op, "0,%s,<,?{,lr,pc,=,},", ARG (0)); } break; case PPC_BC_LE: if (ARG (0)[0] == '\0') { esilprintf (op, "0,cr0,<=,?{,lr,pc,=,},"); } else { esilprintf (op, "0,%s,<=,?{,lr,pc,=,},", ARG (0)); } break; case PPC_BC_EQ: if (ARG (0)[0] == '\0') { esilprintf (op, "0,cr0,==,?{,lr,pc,=,},"); } else { esilprintf (op, "0,%s,==,?{,lr,pc,=,},", ARG (0)); } break; case PPC_BC_GE: if (ARG (0)[0] == '\0') { esilprintf (op, "0,cr0,>=,?{,lr,pc,=,},"); } else { esilprintf (op, "0,%s,>=,?{,lr,pc,=,},", ARG (0)); } break; case PPC_BC_GT: if (ARG (0)[0] == '\0') { esilprintf (op, "0,cr0,>,?{,lr,pc,=,},"); } else { esilprintf (op, "0,%s,>,?{,lr,pc,=,},", ARG (0)); } break; case PPC_BC_NE: if (ARG (0)[0] == '\0') { esilprintf (op, "cr0,?{,lr,pc,=,},"); } else { esilprintf (op, "%s,?{,lr,pc,=,},", ARG (0)); } break; case PPC_BC_UN: // unordered case PPC_BC_NU: // not unordered case PPC_BC_SO: // summary overflow case PPC_BC_NS: // not summary overflow default: break; } break; case PPC_INS_NOR: op->type = R_ANAL_OP_TYPE_NOR; esilprintf (op, "%s,%s,|,!,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_XOR: case PPC_INS_XORI: op->type = R_ANAL_OP_TYPE_XOR; esilprintf (op, "%s,%s,^,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_XORIS: op->type = R_ANAL_OP_TYPE_XOR; esilprintf (op, "16,%s,<<,%s,^,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_DIVD: case PPC_INS_DIVW: op->sign = true; op->type = R_ANAL_OP_TYPE_DIV; esilprintf (op, "%s,%s,/,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_DIVDU: case PPC_INS_DIVWU: op->type = R_ANAL_OP_TYPE_DIV; esilprintf (op, "%s,%s,/,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_BL: case PPC_INS_BLA: op->type = R_ANAL_OP_TYPE_CALL; op->jump = IMM (0); op->fail = addr + op->size; esilprintf (op, "pc,lr,=,%s,pc,=", ARG (0)); break; case PPC_INS_TRAP: op->sign = true; op->type = R_ANAL_OP_TYPE_TRAP; break; case PPC_INS_AND: case PPC_INS_NAND: case PPC_INS_ANDI: op->type = R_ANAL_OP_TYPE_AND; esilprintf (op, "%s,%s,&,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_ANDIS: op->type = R_ANAL_OP_TYPE_AND; esilprintf (op, "16,%s,<<,%s,&,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_OR: case PPC_INS_ORI: op->type = R_ANAL_OP_TYPE_OR; esilprintf (op, "%s,%s,|,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_ORIS: op->type = R_ANAL_OP_TYPE_OR; esilprintf (op, "16,%s,<<,%s,|,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_MFPVR: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "pvr,%s,=", ARG (0)); break; case PPC_INS_MFSPR: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "%s,%s,=", PPCSPR (1), ARG (0)); break; case PPC_INS_MFCTR: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "ctr,%s,=", ARG (0)); break; case PPC_INS_MFDCCR: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "dccr,%s,=", ARG (0)); break; case PPC_INS_MFICCR: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "iccr,%s,=", ARG (0)); break; case PPC_INS_MFDEAR: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "dear,%s,=", ARG (0)); break; case PPC_INS_MFMSR: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "msr,%s,=", ARG (0)); break; case PPC_INS_MTCTR: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "%s,ctr,=", ARG (0)); break; case PPC_INS_MTDCCR: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "%s,dccr,=", ARG (0)); break; case PPC_INS_MTICCR: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "%s,iccr,=", ARG (0)); break; case PPC_INS_MTDEAR: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "%s,dear,=", ARG (0)); break; case PPC_INS_MTMSR: case PPC_INS_MTMSRD: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "%s,msr,=", ARG (0)); break; // Data Cache Block Zero case PPC_INS_DCBZ: op->type = R_ANAL_OP_TYPE_STORE; esilprintf (op, "%s,%s", ARG (0), ARG2 (1, ",=[128]")); break; case PPC_INS_CLRLDI: op->type = R_ANAL_OP_TYPE_AND; esilprintf (op, "%s,%s,&,%s,=", ARG (1), cmask64 (ARG (2), "0x3F"), ARG (0)); break; case PPC_INS_ROTLDI: op->type = R_ANAL_OP_TYPE_ROL; esilprintf (op, "%s,%s,<<<,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_RLDCL: case PPC_INS_RLDICL: op->type = R_ANAL_OP_TYPE_ROL; esilprintf (op, "%s,%s,<<<,%s,&,%s,=", ARG (2), ARG (1), cmask64 (ARG (3), "0x3F"), ARG (0)); break; case PPC_INS_RLDCR: case PPC_INS_RLDICR: op->type = R_ANAL_OP_TYPE_ROL; esilprintf (op, "%s,%s,<<<,%s,&,%s,=", ARG (2), ARG (1), cmask64 (0, ARG (3)), ARG (0)); break; } if (a->fillval) { op_fillval (op, handle, insn); } r_strbuf_fini (&op->esil); cs_free (insn, n); //cs_close (&handle); } return op->size; } static int archinfo(RAnal *a, int q) { if (a->cpu && !strncmp (a->cpu, "vle", 3)) { return 2; } return 4; } RAnalPlugin r_anal_plugin_ppc_cs = { .name = "ppc", .desc = "Capstone PowerPC analysis", .license = "BSD", .esil = true, .arch = "ppc", .bits = 32 | 64, .archinfo = archinfo, .op = &analop, .set_reg_profile = &set_reg_profile, }; #ifndef CORELIB RLibStruct radare_plugin = { .type = R_LIB_TYPE_ANAL, .data = &r_anal_plugin_ppc_cs, .version = R2_VERSION };