Exemplo n.º 1
0
static int analop(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len, RAnalOpMask mask) {
	int n, ret, opsize = -1;
	static csh handle = 0;
	static int omode = -1;
	static int obits = 32;
	cs_insn* insn;
	cs_m68k *m68k;
	cs_detail *detail;

	int mode = a->big_endian? CS_MODE_BIG_ENDIAN: CS_MODE_LITTLE_ENDIAN;

	//mode |= (a->bits==64)? CS_MODE_64: CS_MODE_32;
	if (mode != omode || a->bits != obits) {
		cs_close (&handle);
		handle = 0;
		omode = mode;
		obits = a->bits;
	}
// XXX no arch->cpu ?!?! CS_MODE_MICRO, N64
	op->delay = 0;
	// replace this with the asm.features?
	if (a->cpu && strstr (a->cpu, "68000")) {
		mode |= CS_MODE_M68K_000;
	}
	if (a->cpu && strstr (a->cpu, "68010")) {
		mode |= CS_MODE_M68K_010;
	}
	if (a->cpu && strstr (a->cpu, "68020")) {
		mode |= CS_MODE_M68K_020;
	}
	if (a->cpu && strstr (a->cpu, "68030")) {
		mode |= CS_MODE_M68K_030;
	}
	if (a->cpu && strstr (a->cpu, "68040")) {
		mode |= CS_MODE_M68K_040;
	}
	if (a->cpu && strstr (a->cpu, "68060")) {
		mode |= CS_MODE_M68K_060;
	}
	op->size = 4;
	if (handle == 0) {
		ret = cs_open (CS_ARCH_M68K, mode, &handle);
		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) {
		op->type = R_ANAL_OP_TYPE_ILL;
		op->size = 2;
		opsize = -1;
		goto beach;
	}
	if (!memcmp (buf, "\xff\xff", R_MIN (len, 2))) {
		op->type = R_ANAL_OP_TYPE_ILL;
		op->size = 2;
		opsize = -1;
		goto beach;
	}
	detail = insn->detail;
	m68k = &detail->m68k;
	op->type = R_ANAL_OP_TYPE_NULL;
	op->delay = 0;
	op->id = insn->id;
	opsize = op->size = insn->size;
	if (mask & R_ANAL_OP_MASK_OPEX) {
		opex (&op->opex, handle, insn);
	}
	switch (insn->id) {
	case M68K_INS_INVALID:
		op->type  = R_ANAL_OP_TYPE_ILL;
		break;
	case M68K_INS_ADD:
	case M68K_INS_ADDA:
	case M68K_INS_ADDI:
	case M68K_INS_ADDQ:
	case M68K_INS_ADDX:
		op->type  = R_ANAL_OP_TYPE_ADD;
		break;
	case M68K_INS_AND:
	case M68K_INS_ANDI:
		op->type  = R_ANAL_OP_TYPE_AND;
		break;
	case M68K_INS_ASL:
		op->type  = R_ANAL_OP_TYPE_SHL;
		break;
	case M68K_INS_ASR:
		op->type  = R_ANAL_OP_TYPE_SHR;
		break;
	case M68K_INS_ABCD:
		break;
	case M68K_INS_BHS:
	case M68K_INS_BLO:
	case M68K_INS_BHI:
	case M68K_INS_BLS:
	case M68K_INS_BCC:
	case M68K_INS_BCS:
	case M68K_INS_BNE:
	case M68K_INS_BEQ:
	case M68K_INS_BVC:
	case M68K_INS_BVS:
	case M68K_INS_BPL:
	case M68K_INS_BMI:
	case M68K_INS_BGE:
	case M68K_INS_BLT:
	case M68K_INS_BGT:
	case M68K_INS_BLE:
		handle_branch_instruction (op, addr, m68k, R_ANAL_OP_TYPE_CJMP, 0);
		break;
	case M68K_INS_BRA:
		handle_branch_instruction (op, addr, m68k, R_ANAL_OP_TYPE_JMP, 0);
		break;
	case M68K_INS_BSR:
		handle_branch_instruction (op, addr, m68k, R_ANAL_OP_TYPE_CALL, 0);
		break;
	case M68K_INS_BCHG:
	case M68K_INS_BCLR:
	case M68K_INS_BSET:
	case M68K_INS_BTST:
	case M68K_INS_BFCHG:
	case M68K_INS_BFCLR:
	case M68K_INS_BFEXTS:
	case M68K_INS_BFEXTU:
	case M68K_INS_BFFFO:
	case M68K_INS_BFINS:
	case M68K_INS_BFSET:
	case M68K_INS_BFTST:
	case M68K_INS_BKPT:
	case M68K_INS_CALLM:
	case M68K_INS_CAS:
	case M68K_INS_CAS2:
	case M68K_INS_CHK:
	case M68K_INS_CHK2:
	case M68K_INS_CLR:
		// TODO:
		break;
	case M68K_INS_CMP:
	case M68K_INS_CMPA:
	case M68K_INS_CMPI:
	case M68K_INS_CMPM:
	case M68K_INS_CMP2:
		op->type = R_ANAL_OP_TYPE_CMP;
		break;
	case M68K_INS_CINVL:
	case M68K_INS_CINVP:
	case M68K_INS_CINVA:
		op->type = R_ANAL_OP_TYPE_ILL;
		break;
	case M68K_INS_CPUSHL:
	case M68K_INS_CPUSHP:
	case M68K_INS_CPUSHA:
		break;
	case M68K_INS_DBT:
	case M68K_INS_DBF:
	case M68K_INS_DBHI:
	case M68K_INS_DBLS:
	case M68K_INS_DBCC:
	case M68K_INS_DBCS:
	case M68K_INS_DBNE:
	case M68K_INS_DBEQ:
	case M68K_INS_DBVC:
	case M68K_INS_DBVS:
	case M68K_INS_DBPL:
	case M68K_INS_DBMI:
	case M68K_INS_DBGE:
	case M68K_INS_DBLT:
	case M68K_INS_DBGT:
	case M68K_INS_DBLE:
	case M68K_INS_DBRA:
		handle_branch_instruction (op, addr, m68k, R_ANAL_OP_TYPE_CJMP, 1);
		break;
	case M68K_INS_DIVS:
	case M68K_INS_DIVSL:
	case M68K_INS_DIVU:
	case M68K_INS_DIVUL:
		op->type = R_ANAL_OP_TYPE_DIV;
		break;
	case M68K_INS_EOR:
	case M68K_INS_EORI:
		op->type = R_ANAL_OP_TYPE_XOR;
		break;
	case M68K_INS_EXG:
		op->type = R_ANAL_OP_TYPE_MOV;
		break;
	case M68K_INS_EXT:
	case M68K_INS_EXTB:
		break;
	case M68K_INS_FABS:
	case M68K_INS_FSABS:
	case M68K_INS_FDABS:
	case M68K_INS_FACOS:
	case M68K_INS_FADD:
	case M68K_INS_FSADD:
	case M68K_INS_FDADD:
	case M68K_INS_FASIN:
	case M68K_INS_FATAN:
	case M68K_INS_FATANH:
	case M68K_INS_FBF:
	case M68K_INS_FBEQ:
	case M68K_INS_FBOGT:
	case M68K_INS_FBOGE:
	case M68K_INS_FBOLT:
	case M68K_INS_FBOLE:
	case M68K_INS_FBOGL:
	case M68K_INS_FBOR:
	case M68K_INS_FBUN:
	case M68K_INS_FBUEQ:
	case M68K_INS_FBUGT:
	case M68K_INS_FBUGE:
	case M68K_INS_FBULT:
	case M68K_INS_FBULE:
	case M68K_INS_FBNE:
	case M68K_INS_FBT:
	case M68K_INS_FBSF:
	case M68K_INS_FBSEQ:
	case M68K_INS_FBGT:
	case M68K_INS_FBGE:
	case M68K_INS_FBLT:
	case M68K_INS_FBLE:
	case M68K_INS_FBGL:
	case M68K_INS_FBGLE:
	case M68K_INS_FBNGLE:
	case M68K_INS_FBNGL:
	case M68K_INS_FBNLE:
	case M68K_INS_FBNLT:
	case M68K_INS_FBNGE:
	case M68K_INS_FBNGT:
	case M68K_INS_FBSNE:
	case M68K_INS_FBST:
	case M68K_INS_FCMP:
	case M68K_INS_FCOS:
	case M68K_INS_FCOSH:
	case M68K_INS_FDBF:
	case M68K_INS_FDBEQ:
	case M68K_INS_FDBOGT:
	case M68K_INS_FDBOGE:
	case M68K_INS_FDBOLT:
	case M68K_INS_FDBOLE:
	case M68K_INS_FDBOGL:
	case M68K_INS_FDBOR:
	case M68K_INS_FDBUN:
	case M68K_INS_FDBUEQ:
	case M68K_INS_FDBUGT:
	case M68K_INS_FDBUGE:
	case M68K_INS_FDBULT:
	case M68K_INS_FDBULE:
	case M68K_INS_FDBNE:
	case M68K_INS_FDBT:
	case M68K_INS_FDBSF:
	case M68K_INS_FDBSEQ:
	case M68K_INS_FDBGT:
	case M68K_INS_FDBGE:
	case M68K_INS_FDBLT:
	case M68K_INS_FDBLE:
	case M68K_INS_FDBGL:
	case M68K_INS_FDBGLE:
	case M68K_INS_FDBNGLE:
	case M68K_INS_FDBNGL:
	case M68K_INS_FDBNLE:
	case M68K_INS_FDBNLT:
	case M68K_INS_FDBNGE:
	case M68K_INS_FDBNGT:
	case M68K_INS_FDBSNE:
	case M68K_INS_FDBST:
	case M68K_INS_FDIV:
	case M68K_INS_FSDIV:
	case M68K_INS_FDDIV:
	case M68K_INS_FETOX:
	case M68K_INS_FETOXM1:
	case M68K_INS_FGETEXP:
	case M68K_INS_FGETMAN:
	case M68K_INS_FINT:
	case M68K_INS_FINTRZ:
	case M68K_INS_FLOG10:
	case M68K_INS_FLOG2:
	case M68K_INS_FLOGN:
	case M68K_INS_FLOGNP1:
	case M68K_INS_FMOD:
	case M68K_INS_FMOVE:
	case M68K_INS_FSMOVE:
	case M68K_INS_FDMOVE:
	case M68K_INS_FMOVECR:
	case M68K_INS_FMOVEM:
	case M68K_INS_FMUL:
	case M68K_INS_FSMUL:
	case M68K_INS_FDMUL:
	case M68K_INS_FNEG:
	case M68K_INS_FSNEG:
	case M68K_INS_FDNEG:
	case M68K_INS_FNOP:
	case M68K_INS_FREM:
	case M68K_INS_FRESTORE:
	case M68K_INS_FSAVE:
	case M68K_INS_FSCALE:
	case M68K_INS_FSGLDIV:
	case M68K_INS_FSGLMUL:
	case M68K_INS_FSIN:
	case M68K_INS_FSINCOS:
	case M68K_INS_FSINH:
	case M68K_INS_FSQRT:
	case M68K_INS_FSSQRT:
	case M68K_INS_FDSQRT:
	case M68K_INS_FSF:
	case M68K_INS_FSBEQ:
	case M68K_INS_FSOGT:
	case M68K_INS_FSOGE:
	case M68K_INS_FSOLT:
	case M68K_INS_FSOLE:
	case M68K_INS_FSOGL:
	case M68K_INS_FSOR:
	case M68K_INS_FSUN:
	case M68K_INS_FSUEQ:
	case M68K_INS_FSUGT:
	case M68K_INS_FSUGE:
	case M68K_INS_FSULT:
	case M68K_INS_FSULE:
	case M68K_INS_FSNE:
	case M68K_INS_FST:
	case M68K_INS_FSSF:
	case M68K_INS_FSSEQ:
	case M68K_INS_FSGT:
	case M68K_INS_FSGE:
	case M68K_INS_FSLT:
	case M68K_INS_FSLE:
	case M68K_INS_FSGL:
	case M68K_INS_FSGLE:
	case M68K_INS_FSNGLE:
	case M68K_INS_FSNGL:
	case M68K_INS_FSNLE:
	case M68K_INS_FSNLT:
	case M68K_INS_FSNGE:
	case M68K_INS_FSNGT:
	case M68K_INS_FSSNE:
	case M68K_INS_FSST:
	case M68K_INS_FSUB:
	case M68K_INS_FSSUB:
	case M68K_INS_FDSUB:
	case M68K_INS_FTAN:
	case M68K_INS_FTANH:
	case M68K_INS_FTENTOX:
	case M68K_INS_FTRAPF:
	case M68K_INS_FTRAPEQ:
	case M68K_INS_FTRAPOGT:
	case M68K_INS_FTRAPOGE:
	case M68K_INS_FTRAPOLT:
	case M68K_INS_FTRAPOLE:
	case M68K_INS_FTRAPOGL:
	case M68K_INS_FTRAPOR:
	case M68K_INS_FTRAPUN:
	case M68K_INS_FTRAPUEQ:
	case M68K_INS_FTRAPUGT:
	case M68K_INS_FTRAPUGE:
	case M68K_INS_FTRAPULT:
	case M68K_INS_FTRAPULE:
	case M68K_INS_FTRAPNE:
	case M68K_INS_FTRAPT:
	case M68K_INS_FTRAPSF:
	case M68K_INS_FTRAPSEQ:
	case M68K_INS_FTRAPGT:
	case M68K_INS_FTRAPGE:
	case M68K_INS_FTRAPLT:
	case M68K_INS_FTRAPLE:
	case M68K_INS_FTRAPGL:
	case M68K_INS_FTRAPGLE:
	case M68K_INS_FTRAPNGLE:
	case M68K_INS_FTRAPNGL:
	case M68K_INS_FTRAPNLE:
	case M68K_INS_FTRAPNLT:
	case M68K_INS_FTRAPNGE:
	case M68K_INS_FTRAPNGT:
	case M68K_INS_FTRAPSNE:
	case M68K_INS_FTRAPST:
	case M68K_INS_FTST:
	case M68K_INS_FTWOTOX:
		op->type = R_ANAL_OP_TYPE_UNK;
		op->family = R_ANAL_OP_FAMILY_FPU;
		break;
	case M68K_INS_HALT:
		op->type = R_ANAL_OP_TYPE_NOP;
		break;
	case M68K_INS_ILLEGAL:
		op->type = R_ANAL_OP_TYPE_ILL;
		break;
	case M68K_INS_JMP:
		handle_jump_instruction (op, addr, m68k, R_ANAL_OP_TYPE_JMP);
		break;
	case M68K_INS_JSR:
		handle_jump_instruction (op, addr, m68k, R_ANAL_OP_TYPE_CALL);
		break;
	case M68K_INS_LPSTOP:
		op->type = R_ANAL_OP_TYPE_NOP;
		break;
	case M68K_INS_LSL:
		op->type = R_ANAL_OP_TYPE_SHL;
		break;
	case M68K_INS_LINK:
		op->type = R_ANAL_OP_TYPE_PUSH;
		op->stackop = R_ANAL_STACK_INC;
		op->stackptr = -(st16)IMM(1);
		break;
	case M68K_INS_LSR:
		op->type = R_ANAL_OP_TYPE_SHR;
		break;
	case M68K_INS_PEA:
	case M68K_INS_LEA:
		op->type = R_ANAL_OP_TYPE_LEA;
		break;
	case M68K_INS_MOVE:
	case M68K_INS_MOVEA:
	case M68K_INS_MOVEC:
	case M68K_INS_MOVEM:
	case M68K_INS_MOVEP:
	case M68K_INS_MOVEQ:
	case M68K_INS_MOVES:
	case M68K_INS_MOVE16:
		op->type = R_ANAL_OP_TYPE_MOV;
		break;
	case M68K_INS_MULS:
	case M68K_INS_MULU:
		op->type = R_ANAL_OP_TYPE_MUL;
		break;
	case M68K_INS_NBCD:
	case M68K_INS_NEG:
	case M68K_INS_NEGX:
		break;
	case M68K_INS_NOP:
		op->type = R_ANAL_OP_TYPE_NOP;
		break;
	case M68K_INS_NOT:
		op->type = R_ANAL_OP_TYPE_NOT;
		break;
	case M68K_INS_OR:
	case M68K_INS_ORI:
		op->type = R_ANAL_OP_TYPE_OR;
		break;
	case M68K_INS_PACK:
	case M68K_INS_PFLUSH:
	case M68K_INS_PFLUSHA:
	case M68K_INS_PFLUSHAN:
	case M68K_INS_PFLUSHN:
	case M68K_INS_PLOADR:
	case M68K_INS_PLOADW:
	case M68K_INS_PLPAR:
	case M68K_INS_PLPAW:
	case M68K_INS_PMOVE:
	case M68K_INS_PMOVEFD:
	case M68K_INS_PTESTR:
	case M68K_INS_PTESTW:
	case M68K_INS_PULSE:
	case M68K_INS_REMS:
	case M68K_INS_REMU:
	case M68K_INS_RESET:
		break;
	case M68K_INS_ROL:
		op->type = R_ANAL_OP_TYPE_ROL;
		break;
	case M68K_INS_ROR:
		op->type = R_ANAL_OP_TYPE_ROR;
		break;
	case M68K_INS_ROXL:
	case M68K_INS_ROXR:
		break;
	case M68K_INS_RTD:
	case M68K_INS_RTE:
	case M68K_INS_RTM:
	case M68K_INS_RTR:
	case M68K_INS_RTS:
		op->type = R_ANAL_OP_TYPE_RET;
		break;
	case M68K_INS_SBCD:
	case M68K_INS_ST:
	case M68K_INS_SF:
	case M68K_INS_SHI:
	case M68K_INS_SLS:
	case M68K_INS_SCC:
	case M68K_INS_SHS:
	case M68K_INS_SCS:
	case M68K_INS_SLO:
	case M68K_INS_SNE:
	case M68K_INS_SEQ:
	case M68K_INS_SVC:
	case M68K_INS_SVS:
	case M68K_INS_SPL:
	case M68K_INS_SMI:
	case M68K_INS_SGE:
	case M68K_INS_SLT:
	case M68K_INS_SGT:
	case M68K_INS_SLE:
	case M68K_INS_STOP:
		break;
	case M68K_INS_SUB:
	case M68K_INS_SUBA:
	case M68K_INS_SUBI:
	case M68K_INS_SUBQ:
	case M68K_INS_SUBX:
		op->type = R_ANAL_OP_TYPE_SUB;
		break;
	case M68K_INS_SWAP:
		op->type = R_ANAL_OP_TYPE_MOV;
		break;
	case M68K_INS_TAS:
		break;
	case M68K_INS_TRAP:
	case M68K_INS_TRAPV:
	case M68K_INS_TRAPT:
	case M68K_INS_TRAPF:
	case M68K_INS_TRAPHI:
	case M68K_INS_TRAPLS:
	case M68K_INS_TRAPCC:
	case M68K_INS_TRAPHS:
	case M68K_INS_TRAPCS:
	case M68K_INS_TRAPLO:
	case M68K_INS_TRAPNE:
	case M68K_INS_TRAPEQ:
	case M68K_INS_TRAPVC:
	case M68K_INS_TRAPVS:
	case M68K_INS_TRAPPL:
	case M68K_INS_TRAPMI:
	case M68K_INS_TRAPGE:
	case M68K_INS_TRAPLT:
	case M68K_INS_TRAPGT:
	case M68K_INS_TRAPLE:
		op->type = R_ANAL_OP_TYPE_TRAP;
		break;
	case M68K_INS_TST:
		op->type = R_ANAL_OP_TYPE_CMP;
		break;
	case M68K_INS_UNPK: // unpack BCD
		op->type = R_ANAL_OP_TYPE_MOV;
		break;
	case M68K_INS_UNLK:
		op->type = R_ANAL_OP_TYPE_POP;
		// reset stackframe
		op->stackop = R_ANAL_STACK_SET;
		op->stackptr = 0;
		break;
	}
	if (mask & R_ANAL_OP_MASK_VAL) {
		op_fillval (op, handle, insn);
	}
beach:
	cs_free (insn, n);
	//cs_close (&handle);
fin:
	return opsize;
}
Exemplo n.º 2
0
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;
}
Exemplo n.º 3
0
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
};