Exemple #1
0
static int dalvik_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int len) {
	int sz = dalvik_opcodes[data[0]].len;
	if (op == NULL)
		return sz;

	memset (op, '\0', sizeof (RAnalOp));
	op->type = R_ANAL_OP_TYPE_UNK;
	op->ptr = UT64_MAX;
	op->val = UT64_MAX;
	op->jump = UT64_MAX;
	op->fail = UT64_MAX;
	op->refptr = 0;
	op->size = sz;
	op->nopcode = 1; // Necessary??

	switch (data[0]) {
		case 0xca: // rem-float:
			op->family = R_ANAL_OP_FAMILY_FPU;
			/* pass thru */
		case 0x1b: // const-string/jumbo
		case 0x01: // move
		case 0x02: // move
		case 0x03: // move/16
		case 0x04: // mov-wide
		case 0x05: // mov-wide
		case 0x06: // mov-wide
		case 0x07: //
		case 0x08: //
		case 0x09: //
		case 0x0a: //
		case 0x0d: // move-exception
		case 0x12: // const/4
		case 0x13: // const/16
		case 0x14: // const
		case 0x15: // const
		case 0x16: // const
		case 0x17: // const
		case 0x42: // const
		case 0x18: // const-wide
		case 0x19: // const-wide
		case 0x0c: // move-result-object // TODO: add MOVRET OP TYPE ??
		case 0x0b: // move-result-wide
			op->type = R_ANAL_OP_TYPE_MOV;
			break;
		case 0x1a: // const-string
		case 0x1c: // const-class
			op->type = R_ANAL_OP_TYPE_MOV;
			{
				ut32 vB = (data[3]<<8) | data[2];
				ut64 offset = R_ANAL_GET_OFFSET(anal, 's', vB);
				op->ptr = offset;
			}
			break;
		case 0x85: // long-to-float
		case 0x8e: // double-to-int
		case 0x89: // float-to-double
		case 0x8a: // double-to-int
		case 0x87: // double-to-int
		case 0x8c: // double-to-float
		case 0x8b: // double-to-long
		case 0x88: // float-to-long
			op->family = R_ANAL_OP_FAMILY_FPU;
			/* pass thru */
		case 0x81: // int-to-long
		case 0x82: // 
		case 0x83: // 
		case 0x84: // 
		case 0x8d: // int-to-byte
		case 0x8f: // int-to-short
		case 0x20: // instance-of
			op->type = R_ANAL_OP_TYPE_CAST;
			break;
		case 0x21: // array-length
			op->type = R_ANAL_OP_TYPE_LENGTH;
			break;
		case 0x44: // aget
		case 0x45: //aget-bool
		case 0x46:
		case 0x47: //aget-bool
		case 0x48: //aget-byte
		case 0x49: //aget-char
		case 0x4a: //aget-short
		case 0x52: //iget
		case 0x58: //iget-short
		case 0x53: //iget-wide
		case 0x56: //iget-byte
		case 0x57: //iget-char
		case 0xea: //sget-wide-volatile
		case 0x63: //sget-boolean
		case 0xf4: //iget-byte
		case 0x66: //sget-short
		case 0xfd: //sget-object
		case 0x55: //iget-bool
		case 0x60: // sget
		case 0x61: // 
		case 0x62: //
		case 0x64: // sget-byte
		case 0x65: // sget-char
		case 0xe3: //iget-volatile
		case 0xe4: //
		case 0xe5: // sget
		case 0xe6: // sget
		case 0x54: // iget-object
		case 0xe7: // iget-object-volatile
		case 0xe8: //iget-bool
		case 0xf3: //iget-bool
		case 0xf8: //iget-bool
		case 0xf2: //iget-quick
			op->type = R_ANAL_OP_TYPE_LOAD;
			break;
		case 0x6b: //sput-byte
		case 0x6d: //sput-short
		case 0xeb: //sput-wide-volatile
		case 0x4b: //aput
		case 0x4c: //aput-wide
		case 0x4d: // aput-object
		case 0x4e: // aput-bool
		case 0x4f: // 
		case 0x5e: //iput-char
		case 0xfc: //iput-object-volatile
		case 0xf5: //iput-quick
		case 0x5c: //iput-bool
		case 0x69: //sput-object
		case 0x5f: //iput-wide
		case 0xe9: //iput-wide-volatile
		case 0xf6: //iput-wide
		case 0xf7: //iput-wide
		case 0x67: //iput-wide
		case 0x59: //iput-wide
		case 0x5a: //iput-wide
		case 0x5b: //iput-wide
		case 0x5d: //iput-wide
		case 0x50: //
		case 0x51: // aput-short
		case 0x68: // sput-wide
		case 0x6c: // sput-wide
		case 0xfe: // sput
			op->type = R_ANAL_OP_TYPE_STORE;
			break;
		case 0x9d:
		case 0xad: // mul-double
		case 0xc8: // mul-float
			op->family = R_ANAL_OP_FAMILY_FPU;
			/* fall through */
		case 0xcd:
		case 0xd2:
		case 0x92:
		case 0xb2:
			op->type = R_ANAL_OP_TYPE_MUL;
			break;
		case 0x7c: // not-int
		case 0x7e: // not-long
			op->type = R_ANAL_OP_TYPE_NOT;
			break;
		case 0xa4: // shr-long
		case 0xba: // ushr-int/2addr
		case 0xe2: // ushr-int
		case 0xa5: // ushr-long
		case 0x9a: // ushr-long
		case 0xc5: // ushr-long/2addr
		case 0xc4: // shr-long/2addr
		case 0xe1: // shr-int/lit8
		case 0x99: // shr-int
			op->type = R_ANAL_OP_TYPE_SHR;
			break;
		case 0xaa: // rem-float
		case 0xcf: // rem-double
		case 0xaf: // rem-double
			op->family = R_ANAL_OP_FAMILY_FPU;
			/* pass thru */
		case 0xb4: // rem-int/2addr
		case 0xdc: // rem-int/lit8
		case 0xd4: // rem-int
		case 0xbf: // rem-long/2addr
		case 0x9f: // rem-long
		case 0x94: // rem-int
			op->type = R_ANAL_OP_TYPE_MOD; // mod = rem
			break;
		case 0xd7:
		case 0xd9:
		case 0xda:
		case 0xde:
		case 0xdf:
		case 0x96:
		case 0xc2: // xor-long
		case 0x97: // xor-int
		case 0xa2: // xor-long
			op->type = R_ANAL_OP_TYPE_XOR;
			break;
		case 0xc9: // div-float
			op->family = R_ANAL_OP_FAMILY_FPU;
			/* pass thru */
		case 0x93: // div-int
		case 0xd3: // div-int/lit16
		case 0xdb: // div-int/lit8
		case 0xce: // div-double
		case 0x9e: // div-double
		case 0xbe: // div-double
		case 0xae: // div-double
		case 0xa9: // div-float
		case 0xb3: // div-int/2addr
			op->type = R_ANAL_OP_TYPE_DIV;
			break;
		case 0x0e: // return-void
		case 0x0f: // return
		case 0x10: // return-wide
		case 0x11: // return-object
		case 0xf1: // return-void-barrier
			op->type = R_ANAL_OP_TYPE_RET;
			op->eob = true;
			break;
		case 0x28: // goto
			op->jump = addr + ((char)data[1])*2;
			op->type = R_ANAL_OP_TYPE_JMP;
			op->eob = true;
			break;
		case 0x29: // goto/16
			op->jump = addr + (short)(data[2]|data[3]<<8)*2;
			op->type = R_ANAL_OP_TYPE_JMP;
			op->eob = true;
			break;
		case 0x2a: // goto/32
			op->jump = addr + (int)(data[2]|(data[3]<<8)|(data[4]<<16)|(data[5]<<24))*2;
			op->type = R_ANAL_OP_TYPE_JMP;
			op->eob = true;
			break;
		case 0x2c:
		case 0x2b:
			op->type = R_ANAL_OP_TYPE_SWITCH;
			break;
		case 0x2d: // cmpl-float
		case 0x2e: // cmpg-float
		case 0x3f: // cmpg-float // ???? wrong disasm imho 2e0f12003f0f
		case 0x2f: // cmpl-double
		case 0x30: // cmlg-double
		case 0x31: // cmp-long
		case 0x1f: // check-cast
			op->type = R_ANAL_OP_TYPE_CMP;
			break;
		case 0x32: // if-eq
		case 0x33: // if-ne
		case 0x34: // if-lt
		case 0x35: // if-ge
		case 0x36: // if-gt
		case 0x37: // if-le
		case 0x38: // if-eqz
		case 0x39: // if-nez
		case 0x3a: // if-ltz
		case 0x3b: // if-gez
		case 0x3c: // if-gtz
		case 0x3d: // if-lez
			op->type = R_ANAL_OP_TYPE_CJMP;
			//XXX fix this better the check is to avoid an oob
			op->jump = addr + (len>3?(short)(data[2]|data[3]<<8)*2 : 0);
			op->fail = addr + sz;
			op->eob = true;
			break;
		case 0xec: // breakpoint
		case 0x1d: // monitor-enter
			op->type = R_ANAL_OP_TYPE_UPUSH;
			break;
		case 0x1e: // monitor-exit /// wrong type?
			op->type = R_ANAL_OP_TYPE_POP;
			break;
		case 0x6f: // invoke-super
		case 0xfa: // invoke-super-quick
		case 0x70: // invoke-direct
		case 0x71: // invoke-static
		case 0x72: // invoke-interface
		case 0x73: //
		case 0x74: //
		case 0x75: //
		case 0x76: // invoke-direct
		case 0x77: //
		case 0x78: // invokeinterface/range
		case 0xb9: // invokeinterface
		case 0xb7: // invokespecial
		case 0xb8: // invokestatic
		case 0xb6: // invokevirtual
		case 0x6e: // invoke-virtual
		case 0xf0: // invoke-object-init-range
		case 0xf9: // invoke-virtual-quick/range
		case 0xfb: // invoke-super-quick/range
			{
			//XXX fix this better since the check avoid an oob
			//but the jump will be incorrect
			ut32 vB = len > 3?(data[3] << 8) | data[2] : 0;
			op->jump = anal->binb.get_offset (
				anal->binb.bin, 'm', vB);
			op->fail = addr + sz;
			op->type = R_ANAL_OP_TYPE_CALL;
			}
			break;
		case 0x27: // throw
		case 0xee: // execute-inline
		case 0xef: // execute-inline/range
		case 0xed: // throw-verification-error
			op->type = R_ANAL_OP_TYPE_SWI;
			break;
#if 0
		case 0xbb: // new
		case 0xbc: // newarray
		case 0xc5: // multi new array
#endif
		case 0x22: // new-instance
		case 0x23: // new-array
		case 0x24: // filled-new-array
		case 0x25: // filled-new-array-range
		case 0x26: // filled-new-array-data
			op->type = R_ANAL_OP_TYPE_NEW;
			break;
		case 0x00: // nop
			op->type = R_ANAL_OP_TYPE_NOP;
			break;
		case 0x90: // add-int
		case 0x9b: // add-long
		case 0xa6: // add-float
		case 0xac: // add-double
		case 0xb0: // add-int/2addr
		case 0xbb: // add-long/2addr
		case 0xc6: // add-float/2addr
		case 0xcb: // add-double/2addr
		case 0xd0: // add-int/lit16
		case 0xd8: // add-int/lit8
			op->type = R_ANAL_OP_TYPE_ADD;
			break;
		case 0xa7: // sub-float
		case 0xcc: //sub-double
			op->family = R_ANAL_OP_FAMILY_FPU;
			/* fall thru */
		case 0xc7:
		case 0xbc:
		case 0x91:
		case 0xb1: //sub-int/2addr
		case 0xd1: //sub-int/2addr
		case 0x9c: //sub-long
			op->type = R_ANAL_OP_TYPE_SUB;
			break;
		case 0x7b: // neg-int
		case 0x7d: // neg-long
		case 0x7f: // neg-float
		case 0x80: // neg-double
			op->type = R_ANAL_OP_TYPE_NOT;
			break;
		case 0xa0: // and-long
		case 0xc0: // and-long
		case 0xdd: // and-long
		case 0xd5: // and-long
		case 0x95:
		case 0xb5: // and-int
			op->type = R_ANAL_OP_TYPE_AND;
			break;
		case 0xd6: // orint/lit16
		case 0xc1: // or-long/2addr
		case 0xa1: // or-long
			op->type = R_ANAL_OP_TYPE_OR;
			break;
		case 0xe0: //lshl
		case 0xc3: //lshl
		case 0xa3: // shl-long
		case 0x98: // shl-long
			op->type = R_ANAL_OP_TYPE_SHL;
			break;
	}

	return sz;
}
Exemple #2
0
static int dalvik_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int len) {
	int sz = dalvik_opcodes[data[0]].len;
	if (!op || sz >= len) {
		return sz;
	}
	memset (op, '\0', sizeof (RAnalOp));
	op->type = R_ANAL_OP_TYPE_UNK;
	op->ptr = UT64_MAX;
	op->val = UT64_MAX;
	op->jump = UT64_MAX;
	op->fail = UT64_MAX;
	op->refptr = 0;
	op->size = sz;
	op->nopcode = 1; // Necessary??
	op->id = data[0];

	ut32 vA = 0;
	ut32 vB = 0;
	ut32 vC = 0;
	if (len > 3) {
		vA = data[1];
		vB = data[2];
		vC = data[3];
	}
	switch (data[0]) {
	case 0xca: // rem-float:
		op->family = R_ANAL_OP_FAMILY_FPU;
		/* pass thru */
	case 0x1b: // const-string/jumbo
	case 0x14: // const
	case 0x15: // const
	case 0x16: // const
	case 0x17: // const
	case 0x42: // const
	case 0x12: // const/4
		op->type = R_ANAL_OP_TYPE_MOV;
		{
			ut32 vB = (data[1] & 0x0f);
			ut32 vA = (data[1] & 0xf0) >> 4;
			// op->stackop = R_ANAL_STACK_SET;
			op->ptr = -vA; // why
			op->val = vA;
			esilprintf (op, "0x%"PFMT64x",v%d,=", vA, vB);
		}
		break;
	case 0x01: // move
	case 0x07: // move-object
	case 0x04: // mov-wide
		{
			ut32 vB = (data[1] & 0x0f);
			ut32 vA = (data[1] & 0xf0) >> 4;
			if (vA == vB) {
				op->type = R_ANAL_OP_TYPE_NOP;
				esilprintf (op, ",");
			} else {
				op->type = R_ANAL_OP_TYPE_MOV;
				op->stackop = R_ANAL_STACK_SET;
				op->ptr = -vA;
				esilprintf (op, "v%d,v%d,=", vA, vB);
			}
		}
		break;
	case 0x02: // move/from16
	case 0x03: // move/16
	case 0x05: // move-wide/from16
	case 0x06: // mov-wide&17
	case 0x08: // move-object/from16
	case 0x09: // move-object/16
	case 0x13: // const/16
		op->type = R_ANAL_OP_TYPE_MOV;
		if (len > 2) {
			int vA = (int) data[1];
			ut32 vB = (data[3] << 8) | data[2];
			esilprintf (op, "v%d,v%d,=", vA, vB);
			op->val = vB;
		}
		break;
	case 0x18: // const-wide
	case 0x19: // const-wide
		// 180001000101.  const-wide v0:v1, 0x18201cd01010001
		op->type = R_ANAL_OP_TYPE_MOV;
		break;
	case 0x0a: // move-result
	case 0x0d: // move-exception
	case 0x0c: // move-result-object
	case 0x0b: // move-result-wide
	 	// TODO: add MOVRET OP TYPE ??
		op->type = R_ANAL_OP_TYPE_MOV;
		{
			ut32 vA = data[1];
			esilprintf (op, "sp,v%d,=[8],8,sp,+=,8", vA);
		}
		break;
	case 0x1a: // const-string
		op->type = R_ANAL_OP_TYPE_MOV;
		op->datatype = R_ANAL_DATATYPE_STRING;
		if (len > 2) {
			ut32 vA = data[1];
			ut32 vB = (data[3]<<8) | data[2];
			ut64 offset = R_ANAL_GET_OFFSET (anal, 's', vB);
			op->ptr = offset;
			op->refptr = 0;
			esilprintf (op, "0x%"PFMT64x",v%d,=", offset, vA);
		}
		break;
	case 0x1c: // const-class
		op->type = R_ANAL_OP_TYPE_MOV;
		op->datatype = R_ANAL_DATATYPE_CLASS;
		break;
	case 0x89: // float-to-double
	case 0x8a: // double-to-int
	case 0x87: // double-to-int
	case 0x8c: // double-to-float
	case 0x8b: // double-to-long
	case 0x88: // float-to-long
	case 0x86: // long-to-double
		op->family = R_ANAL_OP_FAMILY_FPU;
		/* pass thru */
	case 0x81: // int-to-long
	case 0x82: // int-to-float
	case 0x85: // long-to-float
	case 0x83: // int-to-double
	case 0x8d: // int-to-byte
	case 0x8e: // int-to-char
		op->type = R_ANAL_OP_TYPE_CAST;
		{
		ut32 vA = (data[1] & 0x0f);
		ut32 vB = (data[1] & 0xf0) >> 4;
		esilprintf (op, "v%d,0xff,&,v%d,=", vB, vA);
		}
		break;
	case 0x8f: // int-to-short
		op->type = R_ANAL_OP_TYPE_CAST;
		// op->datatype = R_ANAL_DATATYPE_INT32 | R_ANAL_DATATYPE_INT16;
		{
		ut32 vA = (data[1] & 0x0f);
		ut32 vB = (data[1] & 0xf0) >> 4;
		esilprintf (op, "v%d,0xffff,&,v%d,=", vB, vA);
		}
		break;
	case 0x84: // long-to-int
		op->type = R_ANAL_OP_TYPE_CAST;
		{
		ut32 vA = (data[1] & 0x0f);
		ut32 vB = (data[1] & 0xf0) >> 4;
		esilprintf (op, "v%d,0xffffffff,&,v%d,=", vB, vA);
		}
		break;
	case 0x20: // instance-of
		{
		op->type = R_ANAL_OP_TYPE_CMP;
		esilprintf (op, "%d,instanceof,%d,-,!,v%d,=", vC, vB, vA);
		}
		break;
	case 0x21: // array-length
		op->type = R_ANAL_OP_TYPE_LENGTH;
		op->datatype = R_ANAL_DATATYPE_ARRAY;
		break;
	case 0x44: // aget
	case 0x45: //aget-bool
	case 0x46:
	case 0x47: //aget-bool
	case 0x48: //aget-byte
	case 0x49: //aget-char
	case 0x4a: //aget-short
	case 0x52: //iget
	case 0x58: //iget-short
	case 0x53: //iget-wide
	case 0x56: //iget-byte
	case 0x57: //iget-char
	case 0xea: //sget-wide-volatile
	case 0xf4: //iget-byte
	case 0x66: //sget-short
	case 0xfd: //sget-object
	case 0x55: //iget-bool
	case 0x60: // sget
	case 0x61: //
	case 0x64: // sget-byte
	case 0x65: // sget-char
	case 0xe3: //iget-volatile
	case 0xe4: //
	case 0xe5: // sget
	case 0xe6: // sget
	case 0xe7: // iget-object-volatile
	case 0xe8: //iget-bool
	case 0xf3: //iget-bool
	case 0xf8: //iget-bool
	case 0xf2: //iget-quick
		op->type = R_ANAL_OP_TYPE_LOAD;
		break;
	case 0x54: // iget-object
		{
		op->type = R_ANAL_OP_TYPE_LOAD;
		ut32 vA = (data[1] & 0x0f);
		ut32 vB = (data[1] & 0xf0) >> 4;
		ut32 vC = (data[2] & 0x0f);
		esilprintf (op, "%d,v%d,iget,v%d,=", vC, vB, vA);
		}
		break;
	case 0x63: // sget-boolean
		{
		const char *vT = "-boolean";
		op->datatype = R_ANAL_DATATYPE_BOOLEAN;
		op->type = R_ANAL_OP_TYPE_LOAD;
		ut32 vA = (data[1] & 0x0f);
		ut32 vB = (data[1] & 0xf0) >> 4;
		ut32 vC = (data[2] & 0x0f);
		esilprintf (op, "%d,%d,sget%s,v%d,=", vC, vB, vT, vA);
		}
		break;
	case 0x62: // sget-object
		{
		const char *vT = "-object";
		op->datatype = R_ANAL_DATATYPE_OBJECT;
		op->type = R_ANAL_OP_TYPE_LOAD;
		ut32 vA = (data[1] & 0x0f);
		ut32 vB = (data[1] & 0xf0) >> 4;
		ut32 vC = (data[2] & 0x0f);
		esilprintf (op, "%d,%d,sget%s,v%d,=", vC, vB, vT, vA);
		}
		break;
	case 0x6b: //sput-byte
	case 0x6d: //sput-short
	case 0xeb: //sput-wide-volatile
	case 0x4b: //aput
	case 0x4c: //aput-wide
	case 0x4d: // aput-object
	case 0x4e: // aput-bool
	case 0x4f: //
	case 0x5e: //iput-char
	case 0xfc: //iput-object-volatile
	case 0xf5: //iput-quick
	case 0x5c: //iput-bool
	case 0x69: //sput-object
	case 0x5f: //iput-wide
	case 0xe9: //iput-wide-volatile
	case 0xf6: //iput-wide
	case 0xf7: //iput-wide
	case 0x67: //iput-wide
	case 0x59: //iput-wide
	case 0x5a: //iput-wide
	case 0x5b: //iput-wide
	case 0x5d: //iput-wide
	case 0x50: //
	case 0x51: // aput-short
	case 0x68: // sput-wide
	case 0x6a: // sput-boolean
	case 0x6c: // sput-wide
	case 0xfe: // sput
		op->type = R_ANAL_OP_TYPE_STORE;
		{
			ut32 vA = (data[1] & 0x0f);
			ut32 vB = (data[1] & 0xf0) >> 4;
			esilprintf (op, "TODO,v%d,v%d,=", vA, vB);
		}
		break;
	case 0xad: // mul-double
		op->family = R_ANAL_OP_FAMILY_FPU;
		op->type = R_ANAL_OP_TYPE_MUL;
		esilprintf (op, "v%d,v%d,*,v%d,=", vC, vB, vA);
		break;
	case 0x9d:
	case 0xc8: // mul-float
		op->family = R_ANAL_OP_FAMILY_FPU;
		/* fall through */
	case 0xcd:
	case 0xd2:
	case 0x92:
	case 0xb2:
		op->type = R_ANAL_OP_TYPE_MUL;
		break;
	case 0x7c: // not-int
	case 0x7e: // not-long
		op->type = R_ANAL_OP_TYPE_NOT;
		break;
	case 0xa4: // shr-long
	case 0xba: // ushr-int/2addr
	case 0xe2: // ushr-int
	case 0xa5: // ushr-long
	case 0x9a: // ushr-long
	case 0xc5: // ushr-long/2addr
	case 0xc4: // shr-long/2addr
	case 0xe1: // shr-int/lit8
	case 0x99: // shr-int
		op->type = R_ANAL_OP_TYPE_SHR;
		break;
	case 0xaa: // rem-float
	case 0xcf: // rem-double
	case 0xaf: // rem-double
		op->family = R_ANAL_OP_FAMILY_FPU;
		/* pass thru */
	case 0xb4: // rem-int/2addr
	case 0xdc: // rem-int/lit8
	case 0xd4: // rem-int
	case 0xbf: // rem-long/2addr
	case 0x9f: // rem-long
	case 0x94: // rem-int
		op->type = R_ANAL_OP_TYPE_MOD; // mod = rem
		break;
	case 0xd7:
	case 0xd9:
	case 0xda:
	case 0xde:

	case 0x95: // and-int
	case 0x96: // or-int
		op->type = R_ANAL_OP_TYPE_OR;
		break;
	case 0xc2: // xor-long
	case 0x97: // xor-int
	case 0xdf: // xor-int/lit16
	case 0xa2: // xor-long
		op->type = R_ANAL_OP_TYPE_XOR;
		break;
	case 0xc9: // div-float
		op->family = R_ANAL_OP_FAMILY_FPU;
		/* pass thru */
	case 0x93: // div-int
	case 0xd3: // div-int/lit16
	case 0xdb: // div-int/lit8
	case 0xce: // div-double
	case 0x9e: // div-double
	case 0xbe: // div-double
	case 0xae: // div-double
	case 0xa9: // div-float
	case 0xb3: // div-int/2addr
		op->type = R_ANAL_OP_TYPE_DIV;
		break;
	case 0x0e: // return-void
	case 0x0f: // return
	case 0x10: // return-wide
	case 0x11: // return-object
	case 0xf1: // return-void-barrier
		op->type = R_ANAL_OP_TYPE_RET;
		op->eob = true;
		//TODO: handle return if(0x0e) {} else {}
		if (data[0] == 0x0e) {// return-void
			esilprintf (op, "sp,[8],ip,=,8,sp,+=");
		} else {
			ut32 vA = data[1];
			esilprintf (op, "sp,[8],ip,=,8,sp,+=,8,sp,-=,v%d,sp,=[8]", vA);
		}
		break;
	case 0x28: // goto
		op->jump = addr + ((char)data[1])*2;
		op->type = R_ANAL_OP_TYPE_JMP;
		op->eob = true;
		esilprintf (op, "0x%"PFMT64x",ip,=", op->jump);
		break;
	case 0x29: // goto/16
		if (len > 3) {
			op->jump = addr + (short)(data[2]|data[3]<<8)*2;
			op->type = R_ANAL_OP_TYPE_JMP;
			op->eob = true;
			esilprintf (op, "0x%"PFMT64x",ip,=", op->jump);
		}
		break;
	case 0x2a: // goto/32
		if (len > 5) {
			op->jump = addr + (int)(data[2]|(data[3]<<8)|(data[4]<<16)|(data[5]<<24))*2;
			op->type = R_ANAL_OP_TYPE_JMP;
			op->eob = true;
			esilprintf (op, "0x%"PFMT64x",ip,=", op->jump);
		}
		break;
	case 0x2c:
	case 0x2b:
		op->type = R_ANAL_OP_TYPE_SWITCH;
		break;
	case 0x3e: // glitch 0 width instruction .. invalid instruction
	case 0x43:
		op->type = R_ANAL_OP_TYPE_ILL;
		esilprintf (op, ",");
		op->size = 1;
		op->eob = true;
		break;
	case 0x2d: // cmpl-float
	case 0x2e: // cmpg-float
	case 0x3f: // cmpg-float // ???? wrong disasm imho 2e0f12003f0f
	case 0x2f: // cmpl-double
	case 0x30: // cmlg-double
	case 0x31: // cmp-long
	case 0x1f: // check-cast
		op->type = R_ANAL_OP_TYPE_CMP;
		break;
	case 0x32: // if-eq
	case 0x33: // if-ne
	case 0x34: // if-lt
	case 0x35: // if-ge
	case 0x36: // if-gt
	case 0x37: // if-le
		op->type = R_ANAL_OP_TYPE_CJMP;
		//XXX fix this better the check is to avoid an oob
		if (len > 2) {
			op->jump = addr + (len>3?(short)(data[2]|data[3]<<8)*2 : 0);
			op->fail = addr + sz;
			op->eob = true;
			ut32 vA = data[1];
			ut32 vB = data[2];
			const char *cond = getCond (data[0]);
			esilprintf (op, "v%d,v%d,==,%s,?{,%"PFMT64d",ip,=}", vB, vA, cond, op->jump);
		}
		break;
	case 0x38: // if-eqz
	case 0x39: // if-nez
	case 0x3a: // if-ltz
	case 0x3b: // if-gez
	case 0x3c: // if-gtz
	case 0x3d: // if-lez
		op->type = R_ANAL_OP_TYPE_CJMP;
		//XXX fix this better the check is to avoid an oob
		if (len > 2) {
			op->jump = addr + (len>3?(short)(data[2]|data[3]<<8)*2 : 0);
			op->fail = addr + sz;
			op->eob = true;
			ut32 vA = data[1];
			const char *cond = getCondz (data[0]);
			esilprintf (op, "v%d,%s,?{,%"PFMT64d",ip,=}", vA, cond, op->jump);
		}
		break;
	case 0xec: // breakpoint
		op->type = R_ANAL_OP_TYPE_TRAP;
		esilprintf (op, "TRAP");
		break;
	case 0x1d: // monitor-enter
		op->type = R_ANAL_OP_TYPE_PUSH;
		op->stackop = R_ANAL_STACK_INC;
		op->stackptr = 1;
		esilprintf (op, ",");
		break;
	case 0x1e: // monitor-exit /// wrong type?
		op->type = R_ANAL_OP_TYPE_POP;
		op->stackop = R_ANAL_STACK_INC;
		op->stackptr = -1;
		esilprintf (op, ",");
		break;
	case 0x6f: // invoke-super
	case 0xfa: // invoke-super-quick
	case 0x70: // invoke-direct
	case 0x71: // invoke-static
	case 0x72: // invoke-interface
	case 0x73: //
	case 0x74: //
	case 0x75: //
	case 0x76: // invoke-direct
	case 0x77: //
	case 0x78: // invokeinterface/range
	case 0xb9: // invokeinterface
	case 0xb7: // invokespecial
	case 0xb8: // invokestatic
	case 0xb6: // invokevirtual
	case 0x6e: // invoke-virtual
	case 0xf0: // invoke-object-init-range
	case 0xf9: // invoke-virtual-quick/range
	case 0xfb: // invoke-super-quick/range
		if (len > 2) {
			//XXX fix this better since the check avoid an oob
			//but the jump will be incorrect
			ut32 vB = len > 3?(data[3] << 8) | data[2] : 0;
			op->jump = anal->binb.get_offset (anal->binb.bin, 'm', vB);
			op->fail = addr + sz;
			op->type = R_ANAL_OP_TYPE_CALL;
			// TODO: handle /range instructions
			esilprintf (op, "8,sp,-=,0x%"PFMT64x",sp,=[8],0x%"PFMT64x",ip,=", addr);
		}
		break;
	case 0x27: // throw
		{
			ut32 vA = data[1];
			op->type = R_ANAL_OP_TYPE_TRAP;
			esilprintf (op, "v%d,TRAP", vA);
		}
		break;
	case 0xee: // execute-inline
	case 0xef: // execute-inline/range
		op->type = R_ANAL_OP_TYPE_SWI;
		break;
	case 0xed: // throw-verification-error
		op->type = R_ANAL_OP_TYPE_TRAP;
		break;
	case 0x22: // new-instance
		op->type = R_ANAL_OP_TYPE_NEW;
		if (len > 2) {
			int vA = (int) data[1];
			int vB = (data[3] << 8) | data[2];
			// resolve class name for vB
			ut64 off = R_ANAL_GET_OFFSET (anal, 't', vB);
			op->ptr = off;
			esilprintf (op, "%d,new,v%d,=", off, vA);
		}
		break;
	case 0x23: // new-array
		op->type = R_ANAL_OP_TYPE_NEW;
		// 0x1c, 0x1f, 0x22
		if (len > 2) {
			ut32 vA = (data[1] & 0x0f);
			ut32 vB = (data[1] & 0xf0) >> 4;
			ut32 vC = (int) data[2] | (data[3]<<8);
			esilprintf (op, "%d,%d,new-array,v%d,=",vC, vB, vA);
		}
		break;
	case 0x24: // filled-new-array
	case 0x25: // filled-new-array-range
	case 0x26: // filled-new-array-data
		op->type = R_ANAL_OP_TYPE_NEW;
		// 0x1c, 0x1f, 0x22
		if (len > 2) {
			//int vA = (int) data[1];
			int vB = (data[3] << 8) | data[2];
			// resolve class name for vB
			ut64 off = R_ANAL_GET_OFFSET (anal, 't', vB);
			op->ptr = off;
		}
		break;
	case 0x00: // nop
		op->type = R_ANAL_OP_TYPE_NOP;
		esilprintf (op, ",");
		break;
	case 0x90: // add-int
	case 0x9b: // add-long
	case 0xa6: // add-float
	case 0xac: // add-double
	case 0xb0: // add-int/2addr
	case 0xbb: // add-long/2addr
	case 0xc6: // add-float/2addr
	case 0xcb: // add-double/2addr
	case 0xd0: // add-int/lit16
	case 0xd8: // add-int/lit8
		{
			op->type = R_ANAL_OP_TYPE_ADD;
			ut32 vB = (data[1] & 0x0f);
			ut32 vA = (data[1] & 0xf0) >> 4;
			esilprintf (op, "v%d,v%d,+=", vB, vA);
		}
		break;
	case 0xa7: // sub-float
	case 0xcc: // sub-double
		op->family = R_ANAL_OP_FAMILY_FPU;
		/* fall thru */
	case 0xc7:
	case 0xbc:
	case 0x91:
	case 0xb1: //sub-int/2addr
	case 0xd1: //sub-int/2addr
	case 0x9c: //sub-long
		op->type = R_ANAL_OP_TYPE_SUB;
		esilprintf (op, "v%d,v%d,-,v%d,=", vC, vB, vA);
		break;
	case 0x7b: // neg-int
	case 0x7d: // neg-long
	case 0x7f: // neg-float
	case 0x80: // neg-double
		op->type = R_ANAL_OP_TYPE_NOT;
		break;
	case 0xa0: // and-long
	case 0xc0: // and-long
	case 0xdd: // and-long
	case 0xd5: // and-long
	case 0xb5: // and-int
		op->type = R_ANAL_OP_TYPE_AND;
		break;
	case 0xd6: // orint/lit16
	case 0xc1: // or-long/2addr
	case 0xa1: // or-long
		op->type = R_ANAL_OP_TYPE_OR;
		break;
	case 0xe0: //lshl
	case 0xc3: //lshl
	case 0xa3: // shl-long
	case 0x98: // shl-long
		op->type = R_ANAL_OP_TYPE_SHL;
		break;
	}