static int analop(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len) { int n, ret, opsize = -1; static csh hndl = 0; static int omode = -1; static int obits = 32; cs_insn* insn; int mode = anal->big_endian? CS_MODE_BIG_ENDIAN: CS_MODE_LITTLE_ENDIAN; if (anal->cpu && *anal->cpu) { if (!strcmp (anal->cpu, "micro")) { mode |= CS_MODE_MICRO; } else if (!strcmp (anal->cpu, "r6")) { mode |= CS_MODE_MIPS32R6; } else if (!strcmp (anal->cpu, "v3")) { mode |= CS_MODE_MIPS3; } else if (!strcmp (anal->cpu, "v2")) { #if CS_API_MAJOR > 3 mode |= CS_MODE_MIPS2; #endif } } mode |= (anal->bits==64)? CS_MODE_MIPS64: CS_MODE_MIPS32; 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; op->id = insn->id; 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_SD: case MIPS_INS_SW: case MIPS_INS_SB: case MIPS_INS_SH: 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: op->type = R_ANAL_OP_TYPE_SWI; break; 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_LI: case MIPS_INS_LUI: SET_VAL (op, 1); op->type = R_ANAL_OP_TYPE_MOV; break; case MIPS_INS_MOVE: op->type = R_ANAL_OP_TYPE_MOV; 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); op->sign = (insn->id == MIPS_INS_ADDI || insn->id == MIPS_INS_ADD); op->type = R_ANAL_OP_TYPE_ADD; if (REGID(0) == MIPS_REG_SP) { op->stackop = R_ANAL_STACK_INC; op->stackptr = -IMM(2); } 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); op->sign = insn->id == MIPS_INS_SUB; 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); op->type = R_ANAL_OP_TYPE_XOR; break; case MIPS_INS_AND: case MIPS_INS_ANDI: SET_VAL (op,2); op->type = R_ANAL_OP_TYPE_AND; if (REGID(0) == MIPS_REG_SP) { op->stackop = R_ANAL_STACK_ALIGN; } 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); 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_BNEL: case MIPS_INS_BEQL: 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 versions (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_RJMP; 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_SLT: case MIPS_INS_SLTI: op->sign = true; SET_VAL (op, 2); break; case MIPS_INS_SLTIU: 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_VAL (op,2); break; case MIPS_INS_SHRL: case MIPS_INS_SRLV: case MIPS_INS_SRL: op->type = R_ANAL_OP_TYPE_SHR; SET_VAL (op,2); break; case MIPS_INS_SLLV: case MIPS_INS_SLL: op->type = R_ANAL_OP_TYPE_SHL; SET_VAL (op,2); break; } beach: set_opdir (op); if (anal->decode) { if (analop_esil (anal, op, addr, buf, len, &hndl, insn) != 0) r_strbuf_fini (&op->esil); } if (anal->fillval) { op_fillval (anal, op, &hndl, insn); } cs_free (insn, n); //cs_close (&handle); fin: return opsize; }
static void anop32 (RAnalOp *op, cs_insn *insn) { ut64 addr = op->addr; int i; switch (insn->id) { case ARM_INS_NOP: op->type = R_ANAL_OP_TYPE_NOP; break; 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; if (ISREG(0)) { if (REGID(0) == ARM_REG_SP) { // 0x00008254 10d04de2 sub sp, sp, 0x10 op->stackop = R_ANAL_STACK_INC; op->stackptr = IMM (2); } } break; case ARM_INS_ADD: op->type = R_ANAL_OP_TYPE_ADD; if (REGID(1)==ARM_REG_PC) { op->ptr = addr + 8 + IMM(2); op->refptr = 0; } 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_AND: op->type = R_ANAL_OP_TYPE_AND; 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_POP: case ARM_INS_PUSH: case ARM64_INS_STRB: case ARM_INS_STR: op->type = R_ANAL_OP_TYPE_STORE; // 0x00008160 04202de5 str r2, [sp, -4]! // 0x000082a0 28000be5 str r0, [fp, -0x28] if (REGBASE(1) == ARM_REG_FP) { op->stackop = R_ANAL_STACK_SET; op->stackptr = 0; op->ptr = MEMDISP(1); } break; case ARM_INS_LDR: case ARM_INS_LDRD: case ARM_INS_LDRB: // 0x000082a8 28301be5 ldr r3, [fp, -0x28] if (insn->detail->arm.operands[0].reg == ARM_REG_PC) { op->type = R_ANAL_OP_TYPE_UJMP; } else { op->type = R_ANAL_OP_TYPE_LOAD; } if (REGBASE(1) == ARM_REG_FP) { op->stackop = R_ANAL_STACK_GET; op->stackptr = 0; op->ptr = MEMDISP(1); } 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: // BX LR == RET if (insn->detail->arm.operands[0].reg == ARM_REG_LR) { op->type = R_ANAL_OP_TYPE_RET; } else if (insn->detail->arm.cc) { op->type = R_ANAL_OP_TYPE_CJMP; op->jump = (ut64) (ut32)IMM(0); op->fail = addr+op->size; } else { op->type = R_ANAL_OP_TYPE_JMP; op->jump = IMM(0); } break; default: break; } }