#
# Gil Dabah 2006
# Tests for diStorm3
#

import os
import random
import struct
import subprocess
import sys
import tempfile
import unittest
import ctypes

import distorm3
from distorm3._generated import Registers, Mnemonics

# We require YASM assembler to work.
# Set YASM_PATH envar to its full binary path.
YASM_PATH = os.environ.get("YASM_PATH", "yasm")

REG_NONE = 255

class _Registers(object):
	def __init__(self):
		for index, name in enumerate(distorm3.Registers):
			if name:
				setattr(_Registers, name, index)

Regs = _Registers()
fbin = []

def Assemble(text, mode):
	lines = text.replace("\n", "\r\n")
	lines = ("bits %d\r\n" % mode) + lines
	asm_name = ""
	with tempfile.NamedTemporaryFile(suffix=".asm", prefix="distorm3-test-", mode="wb+", delete=False) as asm_file:
		asm_file.write(lines.encode())
		asm_file.flush() # Doesn't work instantly on windows. :(
		asm_name = asm_file.name
		asm_file.close()
		out_name = asm_name + ".out"
		cmd = [YASM_PATH, "-m%s" % ("amd64" if mode == 64 else "x86"), asm_name, "-o%s" % out_name]
		subprocess.check_call(cmd, shell=(sys.platform == "win32"))
		with open(out_name, "rb") as out_file:
			s = out_file.read()
		os.unlink(out_name)
	if len(asm_name):
		os.unlink(asm_name)
	return s

class Test(unittest.TestCase):
	def __init__(self):
		unittest.TestCase.__init__(self, "test_dummy")
	def test_dummy(self):
		self.fail("dummy")

class InstBin(Test):
	def __init__(self, bin, mode, features, address):
		Test.__init__(self)
		try:
			bin = bin.decode("hex")
		except:
			bin = bytes.fromhex(bin)
		#fbin[mode].write(bin)
		self.insts = distorm3.Decompose(address, bin, mode, features)
		self.inst = self.insts[0]
	def check_valid(self, instsNo = 1):
		self.assertNotEqual(self.inst.rawFlags, 65535)
		self.assertEqual(len(self.insts), instsNo)
	def check_invalid(self):
		self.assertEqual(self.inst.rawFlags, 65535)
	def check_mnemonic(self, mnemonic, instNo = 0):
		self.assertNotEqual(self.inst.rawFlags, 65535)
		self.assertEqual(self.insts[instNo].mnemonic, mnemonic)

class Inst(Test):
	def __init__(self, instText, mode, instNo, features):
		Test.__init__(self)
		modeSize = [16, 32, 64][mode]
		bin = Assemble(instText, modeSize)
		#print map(lambda x: hex(ord(x)), bin)
		#fbin[mode].write(bin)
		self.insts = distorm3.Decompose(0, bin, mode, features)
		self.inst = self.insts[instNo]

	def check_mnemonic(self, mnemonic):
		self.assertEqual(self.inst.mnemonic, mnemonic)

	def check_imm(self, n, val, sz):
		self.assertEqual(self.inst.operands[n].type, distorm3.OPERAND_IMMEDIATE)
		self.assertEqual(self.inst.operands[n].size, sz)
		self.assertEqual(self.inst.operands[n].value, val)

	def check_reg(self, n, idx, sz):
		self.assertEqual(self.inst.operands[n].type, distorm3.OPERAND_REGISTER)
		self.assertEqual(self.inst.operands[n].index, idx)
		self.assertEqual(self.inst.operands[n].size, sz)

	def check_pc(self, val, sz):
		self.assertEqual(self.inst.operands[0].type, distorm3.OPERAND_IMMEDIATE)
		self.assertEqual(self.inst.operands[0].size, sz)
		self.assertEqual(self.inst.operands[0].value, val)

	def check_disp(self, n, val, dispSize, derefSize):
		self.assertEqual(self.inst.operands[n].type, distorm3.OPERAND_MEMORY)
		self.assertEqual(self.inst.operands[n].dispSize, dispSize)
		self.assertEqual(self.inst.operands[n].size, derefSize)
		self.assertEqual(self.inst.operands[n].disp, val)

	def check_abs_disp(self, n, val, dispSize, derefSize):
		self.assertEqual(self.inst.operands[n].type, distorm3.OPERAND_ABSOLUTE_ADDRESS)
		self.assertEqual(self.inst.operands[n].dispSize, dispSize)
		self.assertEqual(self.inst.operands[n].size, derefSize)
		self.assertEqual(self.inst.operands[n].disp, val)

	def check_simple_deref(self, n, idx, derefSize):
		""" Checks whether a (simple) memory dereference type is used, size of deref is in ops.size.
		Displacement is ignored in this check. """
		self.assertEqual(self.inst.operands[n].type, distorm3.OPERAND_MEMORY)
		self.assertEqual(self.inst.operands[n].size, derefSize)
		self.assertEqual(self.inst.operands[n].index, idx)

	def check_deref(self, n, idx, base, derefSize):
		""" Checks whether a memory dereference type is used, size of deref is in ops.size.
			Base registers is in inst.base.
			Displacement is ignored in this check. """
		self.assertEqual(self.inst.operands[n].type, distorm3.OPERAND_MEMORY)
		self.assertEqual(self.inst.operands[n].size, derefSize)
		self.assertEqual(self.inst.operands[n].index, idx)
		self.assertEqual(self.inst.operands[n].base, base)

	def check_type_size(self, n, t, sz):
		self.assertEqual(self.inst.operands[n].type, t)
		self.assertEqual(self.inst.operands[n].size, sz)

	def check_addr_size(self, sz):
		self.assertEqual({0: 16, 1: 32, 2: 64}[(self.inst.rawFlags >> 10) & 3], sz)

def I16(instText, instNo = 0, features = 0):
	return Inst(instText, distorm3.Decode16Bits, instNo, features)

def IB16(bin, features = 0, address = 0):
	return InstBin(bin, distorm3.Decode16Bits, features, address)

def I32(instText, features = 0):
	return Inst(instText, distorm3.Decode32Bits, 0, features)

def IB32(bin, features = 0, address = 0):
	return InstBin(bin, distorm3.Decode32Bits, features, address)

def I64(instText, features = 0):
	return Inst(instText, distorm3.Decode64Bits, 0, features)

def IB64(bin, features = 0, address = 0):
	return InstBin(bin, distorm3.Decode64Bits, features, address)

def ABS64(x):
	return x
	#return struct.unpack("q", struct.pack("Q", x))[0]

class TestMode16(unittest.TestCase):
	Derefs = ["BX + SI", "BX + DI", "BP + SI", "BP + DI", "SI", "DI", "BP", "BX"]
	DerefsInfo = [(Regs.BX, Regs.SI), (Regs.BX, Regs.DI), (Regs.BP, Regs.SI), (Regs.BP, Regs.DI),
				  (Regs.SI,), (Regs.DI,), (Regs.BP,), (Regs.BX,)]
	def test_none(self):
		self.assertFalse(len(I16("cbw").inst.operands) > 0)
	def test_imm8(self):
		I16("int 0x55").check_imm(0, 0x55, 8)
	def test_imm16(self):
		I16("ret 0x1122").check_imm(0, 0x1122, 16)
	def test_seimm32(self):
		I16("mov ax, 0xff80").check_imm(1, 0xff80, 16)
		self.assertTrue(str(IB16("BA8080").inst).find("0x8080") != -1)
	def test_imm_full(self):
		I16("push 0x1234").check_imm(0, 0x1234, 16)
	def test_imm_aadm(self):
		I16("aam").check_imm(0, 0xa, 8)
		I16("aam 0x15").check_imm(0, 0x15, 8)
		I16("aad").check_imm(0, 0xa, 8)
		I16("aad 0x51").check_imm(0, 0x51, 8)
	def test_seimm(self):
		I16("push 5").check_imm(0, 0x5, 8)
		a = I16("push -6")
		self.assertTrue(str(a.inst).find("-0x6") != -1)
		self.assertEqual(a.inst.size, 2)
		a.check_type_size(0, distorm3.OPERAND_IMMEDIATE, 8)
		self.assertFalse(ABS64(a.inst.operands[0].value) != -6)
		a = I16("db 0x66\n push -5")
		self.assertEqual(a.inst.size, 3)
		a.check_type_size(0, distorm3.OPERAND_IMMEDIATE, 32)
		self.assertFalse(ABS64(a.inst.operands[0].value) != -5)
	def test_imm16_1_imm8_2(self):
		a = I16("enter 0x1234, 0x40")
		a.check_imm(0, 0x1234, 16)
		a.check_imm(1, 0x40, 8)
	def test_imm8_1_imm8_2(self):
		a = I16("extrq xmm0, 0x55, 0xff")
		a.check_imm(1, 0x55, 8)
		a.check_imm(2, 0xff, 8)
	def test_reg8(self):
		I16("inc dh").check_reg(0, Regs.DH, 8)
	def test_reg16(self):
		I16("arpl ax, bp").check_reg(1, Regs.BP, 16)
	def test_reg_full(self):
		I16("dec di").check_reg(0, Regs.DI, 16)
	def test_reg32(self):
		I16("movmskps ebx, xmm6").check_reg(0, Regs.EBX, 32)
	def test_reg32_64(self):
		I16("cvttsd2si esp, xmm3").check_reg(0, Regs.ESP, 32)
	def test_freg32_64_rm(self):
		I16("mov cr0, eax").check_reg(1, Regs.EAX, 32)
	def test_rm8(self):
		I16("seto dh").check_reg(0, Regs.DH, 8)
	def test_rm16(self):
		I16("str di").check_reg(0, Regs.DI, 16)
	def test_rm_full(self):
		I16("push bp").check_reg(0, Regs.BP, 16)
	def test_rm32_64(self):
		I16("movd xmm0, ebx").check_reg(1, Regs.EBX, 32)
	def test_fpum16(self):
		I16("fiadd word [bx]").check_simple_deref(0, Regs.BX, 16)
	def test_fpum32(self):
		I16("fisttp dword [si]").check_simple_deref(0, Regs.SI, 32)
	def test_fpum64(self):
		I16("fadd qword [esp]").check_simple_deref(0, Regs.ESP, 64)
	def test_fpum80(self):
		I16("fbld [eax]").check_simple_deref(0, Regs.EAX, 80)
	def test_r32_m8(self):
		I16("pinsrb xmm4, eax, 0x55").check_reg(1, Regs.EAX, 32)
		I16("pinsrb xmm4, [bx], 0x55").check_simple_deref(1, Regs.BX, 8)
	def test_r32_m16(self):
		I16("pinsrw xmm4, edi, 0x55").check_reg(1, Regs.EDI, 32)
		I16("pinsrw xmm1, word [si], 0x55").check_simple_deref(1, Regs.SI, 16)
	def test_r32_64_m8(self):
		I16("pextrb eax, xmm4, 0xaa").check_reg(0, Regs.EAX, 32)
		I16("pextrb [bx], xmm2, 0xaa").check_simple_deref(0, Regs.BX, 8)
	def test_r32_64_m16(self):
		I16("pextrw esp, xmm7, 0x11").check_reg(0, Regs.ESP, 32)
		I16("pextrw [bp], xmm0, 0xbb").check_simple_deref(0, Regs.BP, 16)
	def test_rfull_m16(self):
		I16("smsw ax").check_reg(0, Regs.AX, 16)
		I16("smsw [bx]").check_simple_deref(0, Regs.BX, 16)
	def test_creg(self):
		I16("mov esp, cr3").check_reg(1, Regs.CR3, 32)
		#I16("mov esp, cr8").check_reg(1, Regs.CR8, 32)
	def test_dreg(self):
		I16("mov edi, dr7").check_reg(1, Regs.DR7, 32)
	def test_sreg(self):
		I16("mov ax, ds").check_reg(1, Regs.DS, 16)
		I16("mov ax, cs").check_reg(1, Regs.CS, 16)
	def test_seg(self):
		I16("push fs").check_reg(0, Regs.FS, 16)
		I16("db 0x66\n push es").check_reg(0, Regs.ES, 16)
	def test_acc8(self):
		I16("in al, 0x60").check_reg(0, Regs.AL, 8)
	def test_acc_full(self):
		I16("add ax, 0x100").check_reg(0, Regs.AX, 16)
	def test_acc_full_not64(self):
		I16("out 0x64, ax").check_reg(1, Regs.AX, 16)
	def test_mem16_full(self):
		I16("call far [bp]").check_simple_deref(0, Regs.BP, 16)
	def test_ptr16_full(self):
		a = I16("jmp 0xffff:0x1234").inst
		self.assertEqual(a.size, 5)
		self.assertEqual(a.operands[0].type, distorm3.OPERAND_FAR_MEMORY)
		self.assertEqual(a.operands[0].size, 16)
		self.assertEqual(a.operands[0].seg, 0xffff)
		self.assertEqual(a.operands[0].off, 0x1234)
	def test_mem16_3264(self):
		I16("sgdt [bx]").check_simple_deref(0, Regs.BX, 32)
	def test_relcb(self):
		a = I16("db 0xe9\ndw 0x00")
		a.check_pc(3, 16)
		a = I16("db 0xe2\ndb 0x50")
		a.check_pc(0x52, 8)
		a = I16("db 0xe2\ndb 0xfd")
		a.check_pc(-1, 8)
		a = I16("db 0x67\ndb 0xe2\ndb 0xf0")
		a.check_pc(-0xd, 8)
	def test_relc_full(self):
		a = I16("jmp 0x100")
		self.assertEqual(a.inst.size, 3)
		a.check_type_size(0, distorm3.OPERAND_IMMEDIATE, 16)
	def test_mem(self):
		I16("lea ax, [bx]").check_simple_deref(1, Regs.BX, 0)
	def test_mem32(self):
		I16("movntss [ebx], xmm5").check_simple_deref(0, Regs.EBX, 32)
	def test_mem32_64(self):
		I16("movnti [ebx], eax").check_simple_deref(0, Regs.EBX, 32)
	def test_mem64(self):
		I16("movlps [edi], xmm7").check_simple_deref(0, Regs.EDI, 64)
	def test_mem128(self):
		I16("movntps [eax], xmm3").check_simple_deref(0, Regs.EAX, 128)
	def test_mem64_128(self):
		I16("cmpxchg8b [edx]").check_simple_deref(0, Regs.EDX, 64)
	def test_moffs8(self):
		I16("mov al, [0x1234]").check_abs_disp(1, 0x1234, 16, 8)
		I16("mov [dword 0x11112222], al").check_abs_disp(0, 0x11112222, 32, 8)
	def test_moff_full(self):
		I16("mov [0x8765], ax").check_abs_disp(0, 0x8765, 16, 16)
		I16("mov ax, [dword 0x11112222]").check_abs_disp(1, 0x11112222, 32, 16)
	def test_const1(self):
		I16("shl si, 1").check_imm(1, 1, 8)
	def test_regcl(self):
		I16("rcl bp, cl").check_reg(1, Regs.CL, 8)
	def test_ib_rb(self):
		I16("mov dl, 0x88").check_reg(0, Regs.DL, 8)
	def test_ib_r_dw_qw(self):
		I16("bswap ecx").check_reg(0, Regs.ECX, 32)
	def test_ib_r_full(self):
		I16("inc si").check_reg(0, Regs.SI, 16)
	def test_regi_esi(self):
		I16("lodsb").check_simple_deref(1, Regs.SI, 8)
		I16("cmpsw").check_simple_deref(0, Regs.SI, 16)
		I16("lodsd").check_simple_deref(1, Regs.SI, 32)
	def test_regi_edi(self):
		I16("movsb").check_simple_deref(0, Regs.DI, 8)
		I16("scasw").check_simple_deref(0, Regs.DI, 16)
		I16("stosd").check_simple_deref(0, Regs.DI, 32)
	def test_regi_ebxal(self):
		a = I16("xlatb")
		a.check_type_size(0, distorm3.OPERAND_MEMORY, 8)
		self.assertFalse(a.inst.operands[0].index != Regs.AL)
		self.assertFalse(a.inst.operands[0].base != Regs.BX)
	def test_regi_eax(self):
		I16("vmrun [ax]").check_simple_deref(0, Regs.AX, 16)
	def test_regdx(self):
		I16("in ax, dx").check_reg(1, Regs.DX, 16)
	def test_regecx(self):
		I16("invlpga [eax], ecx").check_reg(1, Regs.ECX, 32)
	def test_fpu_si(self):
		I16("fxch st4").check_reg(0, Regs.ST4, 32)
	def test_fpu_ssi(self):
		a = I16("fcmovnbe st0, st3")
		a.check_reg(0, Regs.ST0, 32)
		a.check_reg(1, Regs.ST3, 32)
	def test_fpu_sis(self):
		a = I16("fadd st3, st0")
		a.check_reg(0, Regs.ST3, 32)
		a.check_reg(1, Regs.ST0, 32)
	def test_mm(self):
		I16("pand mm0, mm7").check_reg(0, Regs.MM0, 64)
	def test_mm_rm(self):
		I16("psllw mm0, 0x55").check_reg(0, Regs.MM0, 64)
	def test_mm32(self):
		I16("punpcklbw mm1, [si]").check_simple_deref(1, Regs.SI, 32)
	def test_mm64(self):
		I16("packsswb mm3, [bx]").check_simple_deref(1, Regs.BX, 64)
	def test_xmm(self):
		I16("orps xmm5, xmm4").check_reg(0, Regs.XMM5, 128)
	def test_xmm_rm(self):
		I16("psrlw xmm6, 0x12").check_reg(0, Regs.XMM6, 128)
	def test_xmm16(self):
		I16("pmovsxbq xmm3, [bp]").check_simple_deref(1, Regs.BP, 16)
	def test_xmm32(self):
		I16("pmovsxwq xmm5, [di]").check_simple_deref(1, Regs.DI, 32)
	def test_xmm64(self):
		I16("roundsd xmm6, [si], 0x55").check_simple_deref(1, Regs.SI, 64)
	def test_xmm128(self):
		I16("roundpd xmm7, [bx], 0xaa").check_simple_deref(1, Regs.BX, 128)
	def test_regxmm0(self):
		I16("blendvpd xmm1, xmm3, xmm0").check_reg(2, Regs.XMM0, 128)
	def test_disp_only(self):
		a = I16("add [0x1234], bx")
		a.check_type_size(0, distorm3.OPERAND_ABSOLUTE_ADDRESS, 16)
		self.assertFalse(a.inst.operands[0].dispSize != 16)
		self.assertFalse(a.inst.operands[0].disp != 0x1234)
	def test_modrm(self):
		texts = ["ADD [%s], AX" % i for i in self.Derefs]
		for i in enumerate(texts):
			a = I16(i[1])
			if len(self.DerefsInfo[i[0]]) == 2:
				a.check_deref(0, self.DerefsInfo[i[0]][1], self.DerefsInfo[i[0]][0], 16)
			else:
				a.check_simple_deref(0, self.DerefsInfo[i[0]][0], 16)
	def test_modrm_disp8(self):
		texts = ["ADD [%s + 0x55], AX" % i for i in self.Derefs]
		for i in enumerate(texts):
			a = I16(i[1])
			if len(self.DerefsInfo[i[0]]) == 2:
				a.check_deref(0, self.DerefsInfo[i[0]][1], self.DerefsInfo[i[0]][0], 16)
			else:
				a.check_simple_deref(0, self.DerefsInfo[i[0]][0], 16)
			self.assertFalse(a.inst.operands[0].dispSize != 8)
			self.assertFalse(a.inst.operands[0].disp != 0x55)
	def test_modrm_disp16(self):
		texts = ["ADD [%s + 0x3322], AX" % i for i in self.Derefs]
		for i in enumerate(texts):
			a = I16(i[1])
			if len(self.DerefsInfo[i[0]]) == 2:
				a.check_deref(0, self.DerefsInfo[i[0]][1], self.DerefsInfo[i[0]][0], 16)
			else:
				a.check_simple_deref(0, self.DerefsInfo[i[0]][0], 16)
			self.assertFalse(a.inst.operands[0].dispSize != 16)
			self.assertFalse(a.inst.operands[0].disp != 0x3322)

class TestMode32(unittest.TestCase):
	Derefs = ["EAX", "ECX", "EDX", "EBX", "EBP", "ESI", "EDI"]
	DerefsInfo = [Regs.EAX, Regs.ECX, Regs.EDX, Regs.EBX, Regs.EBP, Regs.ESI, Regs.EDI]
	def test_none(self):
		self.assertFalse(len(I32("cdq").inst.operands) > 0)
	def test_imm8(self):
		I32("int 0x55").check_imm(0, 0x55, 8)
	def test_imm16(self):
		I32("ret 0x1122").check_imm(0, 0x1122, 16)
	def test_seimm32(self):
		I32("mov eax, 0xff112233").check_imm(1, 0xff112233, 32)
		self.assertTrue(str(IB32("BA5F6038CE").inst).find("0xce38605f") != -1)
	def test_imm_full(self):
		I32("push 0x12345678").check_imm(0, 0x12345678, 32)
	def test_imm_aadm(self):
		I32("aam").check_imm(0, 0xa, 8)
		I32("aam 0x15").check_imm(0, 0x15, 8)
		I32("aad").check_imm(0, 0xa, 8)
		I32("aad 0x51").check_imm(0, 0x51, 8)
	def test_seimm(self):
		I32("push 6").check_imm(0, 0x6, 8)
		a = I32("push -7")
		self.assertEqual(a.inst.size, 2)
		self.assertTrue(str(a.inst).find("-0x7") != -1)
		a.check_type_size(0, distorm3.OPERAND_IMMEDIATE, 8)
		self.assertFalse(ABS64(a.inst.operands[0].value) != -7)
		a = I32("db 0x66\n push -5")
		self.assertEqual(a.inst.size, 3)
		a.check_type_size(0, distorm3.OPERAND_IMMEDIATE, 16)
		self.assertFalse(ABS64(a.inst.operands[0].value) != -5)
	def test_imm16_1_imm8_2(self):
		a = I32("enter 0x1234, 0x40")
		a.check_imm(0, 0x1234, 16)
		a.check_imm(1, 0x40, 8)
	def test_imm8_1_imm8_2(self):
		a = I32("extrq xmm0, 0x55, 0xff")
		a.check_imm(1, 0x55, 8)
		a.check_imm(2, 0xff, 8)
	def test_reg8(self):
		I32("inc dh").check_reg(0, Regs.DH, 8)
	def test_reg16(self):
		I32("arpl ax, bp").check_reg(1, Regs.BP, 16)
	def test_reg_full(self):
		I32("dec edi").check_reg(0, Regs.EDI, 32)
	def test_reg32(self):
		I32("movmskps ebx, xmm6").check_reg(0, Regs.EBX, 32)
	def test_reg32_64(self):
		I32("cvttsd2si esp, xmm3").check_reg(0, Regs.ESP, 32)
	def test_freg32_64_rm(self):
		I32("mov cr0, eax").check_reg(1, Regs.EAX, 32)
	def test_rm8(self):
		I32("seto dh").check_reg(0, Regs.DH, 8)
	def test_rm16(self):
		I32("verr di").check_reg(0, Regs.DI, 16)
	def test_rm_full(self):
		I32("push ebp").check_reg(0, Regs.EBP, 32)
	def test_rm32_64(self):
		I32("movd xmm0, ebx").check_reg(1, Regs.EBX, 32)
	def test_fpum16(self):
		I32("fiadd word [ebx]").check_simple_deref(0, Regs.EBX, 16)
	def test_fpum32(self):
		I32("fisttp dword [esi]").check_simple_deref(0, Regs.ESI, 32)
	def test_fpum64(self):
		I32("fadd qword [esp]").check_simple_deref(0, Regs.ESP, 64)
	def test_fpum80(self):
		I32("fbld [eax]").check_simple_deref(0, Regs.EAX, 80)
	def test_r32_m8(self):
		I32("pinsrb xmm4, eax, 0x55").check_reg(1, Regs.EAX, 32)
		I32("pinsrb xmm4, [ebx], 0x55").check_simple_deref(1, Regs.EBX, 8)
	def test_r32_m16(self):
		I32("pinsrw xmm4, edi, 0x55").check_reg(1, Regs.EDI, 32)
		I32("pinsrw xmm1, word [esi], 0x55").check_simple_deref(1, Regs.ESI, 16)
	def test_r32_64_m8(self):
		I32("pextrb eax, xmm4, 0xaa").check_reg(0, Regs.EAX, 32)
		I32("pextrb [ebx], xmm2, 0xaa").check_simple_deref(0, Regs.EBX, 8)
	def test_r32_64_m16(self):
		I32("pextrw esp, xmm7, 0x11").check_reg(0, Regs.ESP, 32)
		I32("pextrw [ebp], xmm0, 0xbb").check_simple_deref(0, Regs.EBP, 16)
	def test_rfull_m16(self):
		I32("smsw eax").check_reg(0, Regs.EAX, 32)
		I32("smsw [ebx]").check_simple_deref(0, Regs.EBX, 16)
	def test_creg(self):
		I32("mov esp, cr3").check_reg(1, Regs.CR3, 32)
	def test_dreg(self):
		I32("mov edi, dr7").check_reg(1, Regs.DR7, 32)
	def test_sreg(self):
		I32("mov ax, ds").check_reg(1, Regs.DS, 16)
		I32("mov ax, cs").check_reg(1, Regs.CS, 16)
	def test_seg(self):
		I32("push ss").check_reg(0, Regs.SS, 16)
		I32("db 0x66\n push ds").check_reg(0, Regs.DS, 16)
	def test_acc8(self):
		I32("in al, 0x60").check_reg(0, Regs.AL, 8)
	def test_acc_full(self):
		I32("add eax, 0x100").check_reg(0, Regs.EAX, 32)
	def test_acc_full_not64(self):
		I32("out 0x64, eax").check_reg(1, Regs.EAX, 32)
	def test_mem16_full(self):
		I32("call far [ebp]").check_simple_deref(0, Regs.EBP, 32)
	def test_ptr16_full(self):
		a = I32("jmp 0xffff:0x12345678").inst
		self.assertEqual(a.size, 7)
		self.assertEqual(a.operands[0].type, distorm3.OPERAND_FAR_MEMORY)
		self.assertEqual(a.operands[0].size, 32)
		self.assertEqual(a.operands[0].seg, 0xffff)
		self.assertEqual(a.operands[0].off, 0x12345678)
	def test_mem16_3264(self):
		I32("sgdt [ebx]").check_simple_deref(0, Regs.EBX, 32)
	def test_relcb(self):
		a = I32("db 0xe9\ndd 0x00")
		a.check_pc(5, 32)
		a = I32("db 0xe2\ndb 0x50")
		a.check_pc(0x52, 8)
		a = I32("db 0xe2\ndb 0xfd")
		a.check_pc(-1, 8)
		a = I32("db 0x67\ndb 0xe2\ndb 0xf0")
		a.check_pc(-0xd, 8)
	def test_relc_full(self):
		a = I32("jmp 0x100")
		self.assertEqual(a.inst.size, 5)
		a.check_type_size(0, distorm3.OPERAND_IMMEDIATE, 32)
	def test_mem(self):
		I32("lea ax, [ebx]").check_simple_deref(1, Regs.EBX, 0)
	def test_mem32(self):
		I32("movntss [ebx], xmm5").check_simple_deref(0, Regs.EBX, 32)
	def test_mem32_64(self):
		I32("movnti [edi], eax").check_simple_deref(0, Regs.EDI, 32)
	def test_mem64(self):
		I32("movlps [edi], xmm7").check_simple_deref(0, Regs.EDI, 64)
	def test_mem128(self):
		I32("movntps [eax], xmm3").check_simple_deref(0, Regs.EAX, 128)
	def test_mem64_128(self):
		I32("cmpxchg8b [edx]").check_simple_deref(0, Regs.EDX, 64)
	def test_moffs8(self):
		I32("mov al, [word 0x5678]").check_abs_disp(1, 0x5678, 16, 8)
		I32("mov [0x11112222], al").check_abs_disp(0, 0x11112222, 32, 8)
	def test_moff_full(self):
		I32("mov [word 0x4321], eax").check_abs_disp(0, 0x4321, 16, 32)
		I32("mov eax, [0x11112222]").check_abs_disp(1, 0x11112222, 32, 32)
	def test_const1(self):
		I32("shl esi, 1").check_imm(1, 1, 8)
	def test_regcl(self):
		I32("rcl ebp, cl").check_reg(1, Regs.CL, 8)
	def test_ib_rb(self):
		I32("mov dl, 0x88").check_reg(0, Regs.DL, 8)
	def test_ib_r_dw_qw(self):
		I32("bswap ecx").check_reg(0, Regs.ECX, 32)
	def test_ib_r_full(self):
		I32("inc esi").check_reg(0, Regs.ESI, 32)
	def test_regi_esi(self):
		I32("lodsb").check_simple_deref(1, Regs.ESI, 8)
		I32("cmpsw").check_simple_deref(0, Regs.ESI, 16)
		I32("lodsd").check_simple_deref(1, Regs.ESI, 32)
	def test_regi_edi(self):
		I32("movsb").check_simple_deref(0, Regs.EDI, 8)
		I32("scasw").check_simple_deref(0, Regs.EDI, 16)
		I32("stosd").check_simple_deref(0, Regs.EDI, 32)
	def test_regi_ebxal(self):
		a = I32("xlatb")
		a.check_type_size(0, distorm3.OPERAND_MEMORY, 8)
		self.assertFalse(a.inst.operands[0].index != Regs.AL)
		self.assertFalse(a.inst.operands[0].base != Regs.EBX)
	def test_regi_eax(self):
		I32("vmrun [eax]").check_simple_deref(0, Regs.EAX, 32)
	def test_regdx(self):
		I32("in eax, dx").check_reg(1, Regs.DX, 16)
	def test_regecx(self):
		I32("invlpga [eax], ecx").check_reg(1, Regs.ECX, 32)
	def test_fpu_si(self):
		I32("fxch st4").check_reg(0, Regs.ST4, 32)
	def test_fpu_ssi(self):
		a = I32("fcmovnbe st0, st3")
		a.check_reg(0, Regs.ST0, 32)
		a.check_reg(1, Regs.ST3, 32)
	def test_fpu_sis(self):
		a = I32("fadd st3, st0")
		a.check_reg(0, Regs.ST3, 32)
		a.check_reg(1, Regs.ST0, 32)
	def test_mm(self):
		I32("pand mm0, mm7").check_reg(0, Regs.MM0, 64)
	def test_mm_rm(self):
		I32("psllw mm0, 0x55").check_reg(0, Regs.MM0, 64)
	def test_mm32(self):
		I32("punpcklbw mm1, [esi]").check_simple_deref(1, Regs.ESI, 32)
	def test_mm64(self):
		I32("packsswb mm3, [ebx]").check_simple_deref(1, Regs.EBX, 64)
	def test_xmm(self):
		I32("orps xmm5, xmm4").check_reg(0, Regs.XMM5, 128)
	def test_xmm_rm(self):
		I32("psrlw xmm6, 0x12").check_reg(0, Regs.XMM6, 128)
	def test_xmm16(self):
		I32("pmovsxbq xmm3, [ebp]").check_simple_deref(1, Regs.EBP, 16)
	def test_xmm32(self):
		I32("pmovsxwq xmm5, [edi]").check_simple_deref(1, Regs.EDI, 32)
	def test_xmm64(self):
		I32("roundsd xmm6, [esi], 0x55").check_simple_deref(1, Regs.ESI, 64)
	def test_xmm128(self):
		I32("roundpd xmm7, [ebx], 0xaa").check_simple_deref(1, Regs.EBX, 128)
	def test_regxmm0(self):
		I32("blendvpd xmm1, xmm3, xmm0").check_reg(2, Regs.XMM0, 128)
	def test_cr8(self):
		I32("db 0xf0\n mov cr0, eax").check_reg(0, Regs.CR8, 32)
	def test_disp_only(self):
		a = I32("add [0x12345678], ebx")
		a.check_type_size(0, distorm3.OPERAND_ABSOLUTE_ADDRESS, 32)
		self.assertFalse(a.inst.operands[0].dispSize != 32)
		self.assertFalse(a.inst.operands[0].disp != 0x12345678)
	def test_modrm(self):
		texts = ["ADD [%s], EDI" % i for i in self.Derefs]
		for i in enumerate(texts):
			a = I32(i[1])
			a.check_simple_deref(0, self.DerefsInfo[i[0]], 32)
	def test_modrm_disp8(self):
		texts = ["ADD [%s + 0x55], ESI" % i for i in self.Derefs]
		for i in enumerate(texts):
			a = I32(i[1])
			a.check_simple_deref(0, self.DerefsInfo[i[0]], 32)
			self.assertFalse(a.inst.operands[0].dispSize != 8)
			self.assertFalse(a.inst.operands[0].disp != 0x55)
	def test_modrm_disp32(self):
		texts = ["ADD [%s + 0x33221144], EDX" % i for i in self.Derefs]
		for i in enumerate(texts):
			a = I32(i[1])
			a.check_simple_deref(0, self.DerefsInfo[i[0]], 32)
			self.assertFalse(a.inst.operands[0].dispSize != 32)
			self.assertFalse(a.inst.operands[0].disp != 0x33221144)
	def test_base_ebp(self):
		a = I32("mov [ebp+0x55], eax")
		a.check_simple_deref(0, Regs.EBP, 32)
		self.assertFalse(a.inst.operands[0].dispSize != 8)
		self.assertFalse(a.inst.operands[0].disp != 0x55)
		a = I32("mov [ebp+0x55+eax], eax")
		a.check_deref(0, Regs.EAX, Regs.EBP, 32)
		self.assertFalse(a.inst.operands[0].dispSize != 8)
		self.assertFalse(a.inst.operands[0].disp != 0x55)
		a = I32("mov [ebp+0x55443322], eax")
		a.check_simple_deref(0, Regs.EBP, 32)
		self.assertFalse(a.inst.operands[0].dispSize != 32)
		self.assertFalse(a.inst.operands[0].disp != 0x55443322)
	Bases = ["EAX", "ECX", "EDX", "EBX", "ESP", "ESI", "EDI"]
	BasesInfo = [Regs.EAX, Regs.ECX, Regs.EDX, Regs.EBX, Regs.ESP, Regs.ESI, Regs.EDI]
	Indices = ["EAX", "ECX", "EDX", "EBX", "EBP", "ESI", "EDI"]
	IndicesInfo = [Regs.EAX, Regs.ECX, Regs.EDX, Regs.EBX, Regs.EBP, Regs.ESI, Regs.EDI]
	def test_bases(self):
		for i in enumerate(self.Bases):
			a = I32("cmp ebp, [%s]" % (i[1]))
			a.check_simple_deref(1, self.BasesInfo[i[0]], 32)
	def test_bases_disp32(self):
		for i in enumerate(self.Bases):
			a = I32("cmp ebp, [%s+0x12345678]" % (i[1]))
			a.check_simple_deref(1, self.BasesInfo[i[0]], 32)
			self.assertFalse(a.inst.operands[1].dispSize != 32)
			self.assertFalse(a.inst.operands[1].disp != 0x12345678)
	def test_scales(self):
		for i in enumerate(self.Indices):
			# A scale of 2 causes the scale to be omitted and changed from reg*2 to reg+reg.
			for s in [4, 8]:
				a = I32("and bp, [%s*%d]" % (i[1], s))
				a.check_deref(1, self.IndicesInfo[i[0]], None, 16)
				self.assertFalse(a.inst.operands[1].scale != s)
	def test_sib(self):
		for i in enumerate(self.Indices):
			for j in enumerate(self.Bases):
				for s in [1, 2, 4, 8]:
					a = I32("or bp, [%s*%d + %s]" % (i[1], s, j[1]))
					a.check_deref(1, self.IndicesInfo[i[0]], self.BasesInfo[j[0]], 16)
					if s != 1:
						self.assertFalse(a.inst.operands[1].scale != s)
	def test_sib_disp8(self):
		for i in enumerate(self.Indices):
			for j in enumerate(self.Bases):
				for s in [1, 2, 4, 8]:
					a = I32("xor al, [%s*%d + %s + 0x55]" % (i[1], s, j[1]))
					a.check_deref(1, self.IndicesInfo[i[0]], self.BasesInfo[j[0]], 8)
					self.assertFalse(a.inst.operands[1].dispSize != 8)
					self.assertFalse(a.inst.operands[1].disp != 0x55)
					if s != 1:
						self.assertFalse(a.inst.operands[1].scale != s)
	def test_sib_disp32(self):
		for i in enumerate(self.Indices):
			for j in enumerate(self.Bases):
				for s in [1, 2, 4, 8]:
					a = I32("sub ebp, [%s*%d + %s + 0x55aabbcc]" % (i[1], s, j[1]))
					a.check_deref(1, self.IndicesInfo[i[0]], self.BasesInfo[j[0]], 32)
					self.assertFalse(a.inst.operands[1].dispSize != 32)
					self.assertFalse(a.inst.operands[1].disp != 0x55aabbcc)
					if s != 1:
						self.assertFalse(a.inst.operands[1].scale != s)

class TestMode64(unittest.TestCase):
	Derefs = ["RAX", "RCX", "RDX", "RBX", "RBP", "RSI", "RDI"]
	DerefsInfo = [Regs.RAX, Regs.RCX, Regs.RDX, Regs.RBX, Regs.RBP, Regs.RSI, Regs.RDI]
	def test_none(self):
		self.assertFalse(len(I64("cdq").inst.operands) > 0)
	def test_imm8(self):
		I64("int 0x55").check_imm(0, 0x55, 8)
	def test_imm16(self):
		I64("ret 0x1122").check_imm(0, 0x1122, 16)
	def test_seimm32(self):
		I64("mov eax, 0xff112233").check_imm(1, -15654349, 32)
		self.assertTrue(str(IB64("BA5F6038CE").inst).find("0xce38605f") != -1)
	def test_imm_full(self):
		I64("push 0x12345678").check_imm(0, 0x12345678, 32)
		I64("mov rax, 0x1234567812345678").check_imm(1, 0x1234567812345678, 64)
	def test_imm_aadm(self):
		#I64("aam").check_imm(0, 0xa, 8)
		#I64("aam 0x15").check_imm(0, 0x15, 8)
		#I64("aad").check_imm(0, 0xa, 8)
		#I64("aad 0x51").check_imm(0, 0x51, 8)
		pass
	def test_seimm(self):
		I64("push 6").check_imm(0, 0x6, 8)
		a = I64("push -7")
		self.assertEqual(a.inst.size, 2)
		self.assertTrue(str(a.inst).find("-0x7") != -1)
		a.check_type_size(0, distorm3.OPERAND_IMMEDIATE, 8)
		self.assertFalse(ABS64(a.inst.operands[0].value) != -7)
	def test_imm16_1_imm8_2(self):
		a = I64("enter 0x1234, 0x40")
		a.check_imm(0, 0x1234, 16)
		a.check_imm(1, 0x40, 8)
	def test_imm8_1_imm8_2(self):
		a = I64("extrq xmm0, 0x55, 0xff")
		a.check_imm(1, 0x55, 8)
		a.check_imm(2, 0xff, 8)
	def test_reg8(self):
		I64("inc dh").check_reg(0, Regs.DH, 8)
	def test_reg_full(self):
		I64("dec rdi").check_reg(0, Regs.RDI, 64)
		I64("cmp r15, r14").check_reg(0, Regs.R15, 64)
		I64("cmp r8d, r9d").check_reg(0, Regs.R8D, 32)
		I64("cmp r9w, r8w").check_reg(0, Regs.R9W, 16)
	def test_reg32(self):
		I64("movmskps ebx, xmm6").check_reg(0, Regs.EBX, 32)
		I64("movmskps r11d, xmm6").check_reg(0, Regs.R11D, 32)
	def test_reg32_64(self):
		I64("cvttsd2si rsp, xmm3").check_reg(0, Regs.RSP, 64)
		I64("cvttsd2si r14, xmm3").check_reg(0, Regs.R14, 64)
	def test_freg32_64_rm(self):
		I64("mov cr0, rax").check_reg(1, Regs.RAX, 64)
		I64("mov cr0, r14").check_reg(1, Regs.R14, 64)
	def test_rm8(self):
		I64("seto dh").check_reg(0, Regs.DH, 8)
	def test_rm16(self):
		I64("verr di").check_reg(0, Regs.DI, 16)
		I64("verr r8w").check_reg(0, Regs.R8W, 16)
	def test_rm_full(self):
		I64("push rbp").check_reg(0, Regs.RBP, 64)
	def test_rm32_64(self):
		I64("movq xmm0, rdx").check_reg(1, Regs.RDX, 64)
		I64("movq xmm0, r10").check_reg(1, Regs.R10, 64)
		I64("cvtsi2sd xmm0, rdx").check_reg(1, Regs.RDX, 64)
		I64("vmread rax, rax").check_reg(1, Regs.RAX, 64)
	def test_rm16_32(self):
		I64("movsxd rax, eax").check_reg(1, Regs.EAX, 32)
		I64("movzx rax, ax").check_reg(1, Regs.AX, 16)
	def test_fpum16(self):
		I64("fiadd word [rbx]").check_simple_deref(0, Regs.RBX, 16)
	def test_fpum32(self):
		I64("fisttp dword [rsi]").check_simple_deref(0, Regs.RSI, 32)
	def test_fpum64(self):
		I64("fadd qword [rsp]").check_simple_deref(0, Regs.RSP, 64)
	def test_fpum80(self):
		I64("fbld [rax]").check_simple_deref(0, Regs.RAX, 80)
	def test_r32_m8(self):
		I64("pinsrb xmm4, eax, 0x55").check_reg(1, Regs.EAX, 32)
		I64("pinsrb xmm4, [rbx], 0x55").check_simple_deref(1, Regs.RBX, 8)
	def test_r32_m16(self):
		I64("pinsrw xmm4, edi, 0x55").check_reg(1, Regs.EDI, 32)
		I64("pinsrw xmm1, word [rsi], 0x55").check_simple_deref(1, Regs.RSI, 16)
		I64("pinsrw xmm1, r8d, 0x55").check_reg(1, Regs.R8D, 32)
	def test_r32_64_m8(self):
		I64("pextrb eax, xmm4, 0xaa").check_reg(0, Regs.EAX, 32)
		I64("pextrb [rbx], xmm2, 0xaa").check_simple_deref(0, Regs.RBX, 8)
	def test_r32_64_m16(self):
		I64("pextrw esp, xmm7, 0x11").check_reg(0, Regs.ESP, 32)
		I64("pextrw [rbp], xmm0, 0xbb").check_simple_deref(0, Regs.RBP, 16)
	def test_rfull_m16(self):
		I64("smsw eax").check_reg(0, Regs.EAX, 32)
		I64("smsw [rbx]").check_simple_deref(0, Regs.RBX, 16)
	def test_creg(self):
		I64("mov rsp, cr3").check_reg(1, Regs.CR3, 64)
		I64("mov cr8, rdx").check_reg(0, Regs.CR8, 64)
	def test_dreg(self):
		I64("mov rdi, dr7").check_reg(1, Regs.DR7, 64)
	def test_sreg(self):
		I64("mov ax, fs").check_reg(1, Regs.FS, 16)
		I64("mov ax, cs").check_reg(1, Regs.CS, 16)
	def test_seg(self):
		I64("push gs").check_reg(0, Regs.GS, 16)
	def test_acc8(self):
		I64("in al, 0x60").check_reg(0, Regs.AL, 8)
	def test_acc_full(self):
		I64("add rax, 0x100").check_reg(0, Regs.RAX, 64)
	def test_acc_full_not64(self):
		I64("out 0x64, eax").check_reg(1, Regs.EAX, 32)
		I64("db 0x48\nout 0x64, eax").check_reg(1, Regs.EAX, 32)
	def test_mem16_full(self):
		I64("call far [rbp]").check_simple_deref(0, Regs.RBP, 32)
		I64("db 0x48\n call far [rbp]").check_simple_deref(0, Regs.RBP, 64)
	def test_mem16_3264(self):
		I64("sgdt [rbx]").check_simple_deref(0, Regs.RBX, 64)
	def test_relcb(self):
		a = I64("db 0xe9\ndd 0x00")
		a.check_pc(5, 32)
		a = I64("db 0xe2\ndb 0x50")
		a.check_pc(0x52, 8)
		a = I64("db 0xe2\ndb 0xfd")
		a.check_pc(-1, 8)
		a = I64("db 0x67\ndb 0xe2\ndb 0xf0")
		a.check_pc(-0xd, 8)
	def test_relc_full(self):
		a = I64("jmp 0x100")
		self.assertEqual(a.inst.size, 5)
		a.check_type_size(0, distorm3.OPERAND_IMMEDIATE, 32)
	def test_mem(self):
		I64("lea ax, [rbx]").check_simple_deref(1, Regs.RBX, 0)
	def test_mem32(self):
		I64("movntss [rbx], xmm5").check_simple_deref(0, Regs.RBX, 32)
	def test_mem32_64(self):
		I64("movnti [rdi], eax").check_simple_deref(0, Regs.RDI, 32)
		I64("movnti [rbp], rax").check_simple_deref(0, Regs.RBP, 64)
	def test_mem64(self):
		I64("movlps [rdi], xmm7").check_simple_deref(0, Regs.RDI, 64)
	def test_mem128(self):
		I64("movntps [rax], xmm3").check_simple_deref(0, Regs.RAX, 128)
	def test_mem64_128(self):
		I64("cmpxchg8b [rdx]").check_simple_deref(0, Regs.RDX, 64)
		I64("cmpxchg16b [rbx]").check_simple_deref(0, Regs.RBX, 128)
	def test_moffs8(self):
		I64("mov al, [dword 0x12345678]").check_abs_disp(1, 0x12345678, 32, 8)
		I64("mov [qword 0xaaaabbbbccccdddd], al").check_abs_disp(0, 0xaaaabbbbccccdddd, 64, 8)
	def test_moff_full(self):
		I64("mov [dword 0xaaaabbbb], rax").check_abs_disp(0, 0xffffffffaaaabbbb, 32, 64)
		I64("mov rax, [qword 0xaaaabbbbccccdddd]").check_abs_disp(1, 0xaaaabbbbccccdddd, 64, 64)
	def test_const1(self):
		I64("shl rsi, 1").check_imm(1, 1, 8)
	def test_regcl(self):
		I64("rcl rbp, cl").check_reg(1, Regs.CL, 8)
	def test_ib_rb(self):
		I64("mov dl, 0x88").check_reg(0, Regs.DL, 8)
		I64("mov spl, 0x88").check_reg(0, Regs.SPL, 8)
		I64("mov r10b, 0x88").check_reg(0, Regs.R10B, 8)
	def test_ib_r_dw_qw(self):
		I64("bswap rcx").check_reg(0, Regs.RCX, 64)
		I64("bswap r10").check_reg(0, Regs.R10, 64)
		I64("push r10").check_reg(0, Regs.R10, 64)
	def test_ib_r_full(self):
		I64("inc rsi").check_reg(0, Regs.RSI, 64)
		I64("inc r9").check_reg(0, Regs.R9, 64)
		I64("push r10w").check_reg(0, Regs.R10W, 16)
		I64("xchg r10d, eax").check_reg(0, Regs.R10D, 32)
	def test_regi_esi(self):
		I64("lodsb").check_simple_deref(1, Regs.RSI, 8)
		I64("cmpsw").check_simple_deref(0, Regs.RSI, 16)
		I64("lodsd").check_simple_deref(1, Regs.RSI, 32)
		I64("lodsq").check_simple_deref(1, Regs.RSI, 64)
	def test_regi_edi(self):
		I64("movsb").check_simple_deref(0, Regs.RDI, 8)
		I64("scasw").check_simple_deref(0, Regs.RDI, 16)
		I64("stosd").check_simple_deref(0, Regs.RDI, 32)
		I64("stosq").check_simple_deref(0, Regs.RDI, 64)
	def test_regi_ebxal(self):
		a = I64("xlatb")
		a.check_type_size(0, distorm3.OPERAND_MEMORY, 8)
		self.assertFalse(a.inst.operands[0].index != Regs.AL)
		self.assertFalse(a.inst.operands[0].base != Regs.RBX)
	def test_regi_eax(self):
		I64("vmrun [rax]").check_simple_deref(0, Regs.RAX, 64)
	def test_regdx(self):
		#I64("in eax, dx").check_reg(1, Regs.DX, 16)
		pass
	def test_regecx(self):
		I64("invlpga [rax], ecx").check_reg(1, Regs.ECX, 32)
	def test_fpu_si(self):
		I64("fxch st4").check_reg(0, Regs.ST4, 32)
	def test_fpu_ssi(self):
		a = I64("fcmovnbe st0, st3")
		a.check_reg(0, Regs.ST0, 32)
		a.check_reg(1, Regs.ST3, 32)
	def test_fpu_sis(self):
		a = I64("fadd st3, st0")
		a.check_reg(0, Regs.ST3, 32)
		a.check_reg(1, Regs.ST0, 32)
	def test_mm(self):
		I64("pand mm0, mm7").check_reg(0, Regs.MM0, 64)
	def test_mm_rm(self):
		I64("psllw mm0, 0x55").check_reg(0, Regs.MM0, 64)
	def test_mm32(self):
		I64("punpcklbw mm1, [rsi]").check_simple_deref(1, Regs.RSI, 32)
	def test_mm64(self):
		I64("packsswb mm3, [rbx]").check_simple_deref(1, Regs.RBX, 64)
	def test_xmm(self):
		I64("orps xmm5, xmm4").check_reg(0, Regs.XMM5, 128)
		I64("orps xmm15, xmm4").check_reg(0, Regs.XMM15, 128)
	def test_xmm_rm(self):
		I64("psrlw xmm6, 0x12").check_reg(0, Regs.XMM6, 128)
		I64("psrlw xmm13, 0x12").check_reg(0, Regs.XMM13, 128)
	def test_xmm16(self):
		I64("pmovsxbq xmm3, [rbp]").check_simple_deref(1, Regs.RBP, 16)
	def test_xmm32(self):
		I64("pmovsxwq xmm5, [rdi]").check_simple_deref(1, Regs.RDI, 32)
	def test_xmm64(self):
		I64("roundsd xmm6, [rsi], 0x55").check_simple_deref(1, Regs.RSI, 64)
	def test_xmm128(self):
		I64("roundpd xmm7, [rbx], 0xaa").check_simple_deref(1, Regs.RBX, 128)
		I64("roundpd xmm7, xmm15, 0xaa").check_reg(1, Regs.XMM15, 128)
	def test_regxmm0(self):
		I64("blendvpd xmm1, xmm3, xmm0").check_reg(2, Regs.XMM0, 128)
	def test_disp_only(self):
		a = I64("add [0x12345678], rbx")
		a.check_type_size(0, distorm3.OPERAND_ABSOLUTE_ADDRESS, 64)
		self.assertFalse(a.inst.operands[0].dispSize != 32)
		self.assertFalse(a.inst.operands[0].disp != 0x12345678)
	def test_modrm(self):
		texts = ["ADD [%s], RDI" % i for i in self.Derefs]
		for i in enumerate(texts):
			a = I64(i[1])
			a.check_simple_deref(0, self.DerefsInfo[i[0]], 64)
	def test_modrm_disp8(self):
		texts = ["ADD [%s + 0x55], RSI" % i for i in self.Derefs]
		for i in enumerate(texts):
			a = I64(i[1])
			a.check_simple_deref(0, self.DerefsInfo[i[0]], 64)
			self.assertFalse(a.inst.operands[0].dispSize != 8)
			self.assertFalse(a.inst.operands[0].disp != 0x55)
	def test_modrm_disp32(self):
		texts = ["ADD [%s + 0x33221144], RDX" % i for i in self.Derefs]
		for i in enumerate(texts):
			a = I64(i[1])
			a.check_simple_deref(0, self.DerefsInfo[i[0]], 64)
			self.assertFalse(a.inst.operands[0].dispSize != 32)
			self.assertFalse(a.inst.operands[0].disp != 0x33221144)
	def test_base_rbp(self):
		a = I64("mov [rbp+0x55], eax")
		a.check_simple_deref(0, Regs.RBP, 32)
		self.assertFalse(a.inst.operands[0].dispSize != 8)
		self.assertFalse(a.inst.operands[0].disp != 0x55)
		a = I64("mov [rbp+0x55443322], eax")
		a.check_simple_deref(0, Regs.RBP, 32)
		self.assertFalse(a.inst.operands[0].dispSize != 32)
		self.assertFalse(a.inst.operands[0].disp != 0x55443322)
	def test_base_rip(self):
		a = I64("mov [rip+0x12345678], rdx")
		a.check_simple_deref(0, Regs.RIP, 64)
		self.assertFalse(a.inst.operands[0].dispSize != 32)
		self.assertFalse(a.inst.operands[0].disp != 0x12345678)
	def test_reg8_rex(self):
		I64("mov sil, al").check_reg(0, Regs.SIL, 8)
		I64("inc bpl").check_reg(0, Regs.BPL, 8)
	def test_imm64(self):
		I64("mov rax, 0x1234567890abcdef").check_imm(1, 0x1234567890abcdef, 64)
	def test_reg64(self):
		I64("movsxd r10, eax").check_reg(0, Regs.R10, 64)
	def test_rm16_32_2(self):
		#MOVZXD RAX, [RAX]
		I64("db 0x63\n db 0x00").check_simple_deref(1, Regs.RAX, 32)
		#MOVZXDW RAX, [RAX]
		#I64("db 0x66\n db 0x63\n db 0x00").check_simple_deref(1, Regs.RAX, 16)
		#MOVZXD RAX, EAX
		I64("db 0x63\n db 0xc0").check_reg(1, Regs.EAX, 32)
		#MOVZXDW RAX, AX
		#I64("db 0x66\n db 0x63\n db 0xc0").check_reg(1, Regs.AX, 16)
		#MOVZXDW RAX, R8W
		#I64("db 0x66\n db 0x41\n db 0x63\n db 0xc0").check_reg(1, Regs.R8W, 16)
	Bases = ["RAX", "RCX", "RDX", "RBX", "RSP", "RSI", "RDI", "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15"]
	BasesInfo = [Regs.RAX, Regs.RCX, Regs.RDX, Regs.RBX, Regs.RSP, Regs.RSI, Regs.RDI, Regs.R8, Regs.R9, Regs.R10, Regs.R11, Regs.R12, Regs.R13, Regs.R14, Regs.R15]
	Indices = ["RAX", "RCX", "RDX", "RBX", "RBP", "RSI", "RDI", "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15"]
	IndicesInfo = [Regs.RAX, Regs.RCX, Regs.RDX, Regs.RBX, Regs.RBP, Regs.RSI, Regs.RDI, Regs.R8, Regs.R9, Regs.R10, Regs.R11, Regs.R12, Regs.R13, Regs.R14, Regs.R15]
	def test_bases(self):
		for i in enumerate(self.Bases):
			a = I64("cmp rbp, [%s]" % (i[1]))
			a.check_simple_deref(1, self.BasesInfo[i[0]], 64)
	def test_bases_disp32(self):
		for i in enumerate(self.Bases):
			a = I64("cmp rbp, [%s+0x12345678]" % (i[1]))
			a.check_simple_deref(1, self.BasesInfo[i[0]], 64)
			self.assertFalse(a.inst.operands[1].dispSize != 32)
			self.assertFalse(a.inst.operands[1].disp != 0x12345678)
	def test_scales(self):
		for i in enumerate(self.Indices):
			# A scale of 2 causes the scale to be omitted and changed from reg*2 to reg+reg.
			for s in [4, 8]:
				a = I64("and rbp, [%s*%d]" % (i[1], s))
				a.check_deref(1, self.IndicesInfo[i[0]], None, 64)
				self.assertFalse(a.inst.operands[1].scale != s)
	def test_sib(self):
		for i in enumerate(self.Indices):
			for j in enumerate(self.Bases):
				for s in [1, 2, 4, 8]:
					a = I64("or rbp, [%s*%d + %s]" % (i[1], s, j[1]))
					a.check_deref(1, self.IndicesInfo[i[0]], self.BasesInfo[j[0]], 64)
					if s != 1:
						self.assertFalse(a.inst.operands[1].scale != s)
	def test_sib_disp8(self):
		for i in enumerate(self.Indices):
			for j in enumerate(self.Bases):
				for s in [1, 2, 4, 8]:
					a = I64("xor al, [%s*%d + %s + 0x55]" % (i[1], s, j[1]))
					a.check_deref(1, self.IndicesInfo[i[0]], self.BasesInfo[j[0]], 8)
					self.assertFalse(a.inst.operands[1].dispSize != 8)
					self.assertFalse(a.inst.operands[1].disp != 0x55)
					if s != 1:
						self.assertFalse(a.inst.operands[1].scale != s)
	def test_sib_disp32(self):
		for i in enumerate(self.Indices):
			for j in enumerate(self.Bases):
				for s in [1, 2, 4, 8]:
					a = I64("sub rdx, [%s*%d + %s + 0x55aabbcc]" % (i[1], s, j[1]))
					a.check_deref(1, self.IndicesInfo[i[0]], self.BasesInfo[j[0]], 64)
					self.assertFalse(a.inst.operands[1].dispSize != 32)
					self.assertFalse(a.inst.operands[1].disp != 0x55aabbcc)
					if s != 1:
						self.assertFalse(a.inst.operands[1].scale != s)
	def test_base32(self):
		I64("mov eax, [ebx]").check_simple_deref(1, Regs.EBX, 32)

class TestInstTable(unittest.TestCase):
	""" Check that locate_inst algorithm covers all opcode-length (ol)
		for the varying sizes of opcodes.
		The bad tests should not find an instruction, so they should fail on purpose,
		to see we don't crash the diassembler.
		Also test for some end-cases with nop and wait. """
	def test_c7_opcode(self):
		IB32("c7f8aaaaaaaa").check_mnemonic("XBEGIN")
		IB64("c7f8aaaaaaaa").check_mnemonic("XBEGIN")
		IB32("C7C108000000").check_mnemonic("MOV")
		IB64("C7C108000000").check_mnemonic("MOV")
		IB64("48C7C000000000").check_mnemonic("MOV")
	def test_tx(self):
		IB64("0f01d5").check_mnemonic("XEND")
		IB64("c6f8bb").check_mnemonic("XABORT")
		IB64("c7f800000000").check_mnemonic("XBEGIN")
	def test_fuzz_9b_and_c7(self):
		for i in range(10000):
			s = "%02x%02x" % (i & 0xff, random.randint(0, 255))
			IB32("9b%sffffffff" % s)
			IB32("c7%sffffffff" % s)
	def test_ol1(self):
		IB32("00c0").check_mnemonic("ADD")
	def test_ol13(self):
		IB32("80c055").check_mnemonic("ADD")
	def test_ol1d(self):
		IB32("d900").check_mnemonic("FLD")
		IB32("d9c8").check_mnemonic("FXCH")
		IB32("d9e1").check_mnemonic("FABS")
	def test_ol2(self):
		IB32("0f06").check_mnemonic("CLTS")
	def test_ol23(self):
		IB32("0fbae055").check_mnemonic("BT")
	def test_ol2d(self):
		IB32("0f01e0").check_mnemonic("SMSW")
		IB32("0f0130").check_mnemonic("LMSW")
		IB32("0f01c9").check_mnemonic("MWAIT")
	def test_ol3(self):
		IB32("0f380000").check_mnemonic("PSHUFB")
	def test_ol1_bad(self):
		# There is no undefined instruction in the root, except a prefix, oh well.
		pass
	def test_ol13_bad(self):
		IB32("f780").check_invalid()
	def test_ol1d_bad(self):
		IB32("d908").check_invalid()
		IB32("d9d1").check_invalid()
		IB32("d9ef").check_invalid()
	def test_ol2_bad(self):
		IB32("0fff").check_invalid()
	def test_ol23_bad(self):
		IB32("0f0dff").check_invalid()
	def test_ol2d_bad(self):
		IB32("0f0128").check_invalid()
		IB32("0f01cc").check_invalid()
	def test_ol3_bad(self):
		IB32("0f0fff").check_invalid()
	def test_index63(self):
		# Test arpl, since it has a special treatment for 32/64 bits.
		a = IB32("63c0")
		a.check_mnemonic("ARPL")
		a = IB64("63c0")
		a.check_mnemonic("MOVSXD")
	def test_index90(self):
		# If nop is prefixed with f3, it is pause then. If it is prefixed with rex, it might be xchg.
		IB32("90").check_mnemonic("NOP")
		IB64("90").check_mnemonic("NOP")
		IB64("4890").check_mnemonic("NOP")
		IB64("4190").check_mnemonic("XCHG")
		IB64("f390").check_mnemonic("PAUSE")
	def test_wait(self):
		# Wait instruction is very tricky. It might be coalesced with the next bytes.
		# If the next bytes are 'waitable', otherwise it is a standalone instruction.
		IB32("9b90").check_mnemonic("WAIT", 0) # nop isn't waitable.
		IB32("9bdfe0").check_mnemonic("FSTSW") # waitable stsw
		IB32("dfe0").check_mnemonic("FNSTSW") # non-waitable stsw
		IB32("9b00c0").check_mnemonic("WAIT") # add isn't waitable
		IB32("9bd930").check_mnemonic("FSTENV") # waitable fstenv
		IB32("9b66dbe3").check_mnemonic("WAIT") # prefix breaks waiting
	def test_3dnow(self):
		IB32("0f0fc00d").check_mnemonic("PI2FD")
		IB32("0f0d00").check_mnemonic("PREFETCH")
	def test_mandatory(self):
		IB32("f30f10c0").check_mnemonic("MOVSS")
		IB32("660f10c0").check_mnemonic("MOVUPD")
		IB32("660f71d055").check_mnemonic("PSRLW")
		IB32("660ffec0").check_mnemonic("PADDD")
		IB32("f20f10c0").check_mnemonic("MOVSD")
		IB32("f20f11c0").check_mnemonic("MOVSD")
		IB32("660f3800c0").check_mnemonic("PSHUFB")
		IB32("f20f38f0c0").check_mnemonic("CRC32")
		IB32("660fc730").check_mnemonic("VMCLEAR")
		IB32("f30fc730").check_mnemonic("VMXON")
	def test_vex(self):
		I32("vaddpd ymm1, ymm2, ymm2").check_mnemonic("VADDPD") # pre encoding: 66, 0f, 58
		I32("vaddps ymm1, ymm2, ymm2").check_mnemonic("VADDPS") # pre encoding: 0f, 58
		I32("vaddsd xmm1, xmm2, qword [eax]").check_mnemonic("VADDSD") # pre encoding: f2, 0f, 58
		I32("vaddss xmm1, xmm2, dword [eax]").check_mnemonic("VADDSS") # pre encoding: f3, 0f, 58
		I32("vmovsd xmm1, xmm2, xmm3").check_mnemonic("VMOVSD") # pre encoding: f2, 0f, 10
		I32("vmovsd xmm1, qword [eax]").check_mnemonic("VMOVSD") # pre encoding: f2 0f 10 - but VEX.vvvv is not encoded!
		# Since in a VEX prefix you can encode the virtual prefix, we got three ways to get to 0xf 0x38
		# So see that both work well.
		IB32("c4e279dbc2").check_mnemonic("VAESIMC") # pre encoding: 66, 0f, 38, db, virtual prefix is 0f 38
		IB32("c4e17938dbc2").check_mnemonic("VAESIMC") # the virtual prefix is only 0f
		IB32("c5f938dbc2").check_mnemonic("VAESIMC") # the virtual prefix is only 0f, but short VEX
		# Same test as earlier, but for 0xf 0x3a, though this instruction doesn't have a short form.
		IB32("c4e3710dc255").check_mnemonic("VBLENDPD") # pre encoding: 66, 0f, 3a, 0d, virtual prefix is 0f 3a
		IB32("c4e1713a0dc255").check_mnemonic("VBLENDPD") # pre encoding: 66, 0f, 3a, 0d, virtual prefix is 0f
		I32("vldmxcsr dword [eax]").check_mnemonic("VLDMXCSR")
		I32("vzeroupper").check_mnemonic("VZEROUPPER")
		I32("vzeroall").check_mnemonic("VZEROALL")
		I32("vpslld xmm1, xmm2, xmm3").check_mnemonic("VPSLLD")
	def test_vex_special(self):
		# VVVV encoded, where there is not such an encoding for the VAESIMC instruction.
		IB32("c4e271dbca").check_invalid()
		IB32("c4e2791800").check_mnemonic("VBROADCASTSS") # just to make sure this instruction is fine.
		IB32("c4e279ff00").check_invalid() # pre encoding: 66, 0f, 38, ff
		IB32("c4e179ff00").check_invalid() # pre encoding: 66, 0f, 38, ff, mmmmm = 1
		IB32("c4e379ff00").check_invalid() # pre encoding: 66, 0f, 38, ff, mmmmm = 3
		IB32("c4e4791800").check_invalid() # pre encoding: 66, 0f, 38, 18, mmmmm = 4
		IB32("c5f8ae10").check_mnemonic("VLDMXCSR") # pre encoding: 0f, ae /02
		IB32("c4c178ae10").check_mnemonic("VLDMXCSR") # longer form of 0f, ae /02
		IB32("c4c179ae10").check_invalid() # longer form of 0f, ae /02, invalid pp=1
		IB32("c4c17aae10").check_invalid() # longer form of 0f, ae /02, invalid pp=2
		IB32("c4c17bae10").check_invalid() # longer form of 0f, ae /02, invalid pp=3
		IB32("c4c17877").check_mnemonic("VZEROUPPER") # longer form of 0f, 77
		IB32("c4c17c77").check_mnemonic("VZEROALL") # longer form of 0f, 77
		IB32("c4c97c77").check_invalid() # longer form of 0f, 77, invalid mmmmm
	def test_crc32(self):
		I32("crc32 eax, al").check_reg(0, Regs.EAX, 32)
	def test_lzcnt(self):
		# This is the only instruction that has a mandatory prefix and can have ALSO a valid operand size prefix!
		I32("lzcnt ax, bx").check_reg(0, Regs.AX, 16)
		I32("lzcnt eax, ebx").check_reg(0, Regs.EAX, 32)
		I64("lzcnt rax, rbx").check_reg(0, Regs.RAX, 64)

class TestAVXOperands(unittest.TestCase):
	def test_rm32(self):
		#I16("vextractps eax, xmm2, 3").check_reg(0, Regs.EAX, 32)
		I32("vextractps eax, xmm2, 3").check_reg(0, Regs.EAX, 32)
		I64("vextractps eax, xmm2, 3").check_reg(0, Regs.EAX, 32)
	def test_reg32_64_m8(self):
		#I16("vpextrb eax, xmm2, 3").check_reg(0, Regs.EAX, 32)
		I32("vpextrb eax, xmm2, 3").check_reg(0, Regs.EAX, 32)
		I64("vpextrb eax, xmm2, 3").check_reg(0, Regs.EAX, 32)
		I64("vpextrb rax, xmm2, 3").check_reg(0, Regs.RAX, 64)
		I32("vpextrb [ebx], xmm2, 3").check_simple_deref(0, Regs.EBX, 8)
		I64("vpextrb [rbx], xmm2, 3").check_simple_deref(0, Regs.RBX, 8)
	def test_reg32_64_m16(self):
		I32("vpextrw eax, xmm2, 3").check_reg(0, Regs.EAX, 32)
		I64("vpextrw rax, xmm2, 3").check_reg(0, Regs.RAX, 64)
		I64("vpextrw rax, xmm2, 3").check_reg(0, Regs.RAX, 64)
		I32("vpextrw [ebx], xmm2, 3").check_simple_deref(0, Regs.EBX, 16)
		I64("vpextrw [rbx], xmm2, 3").check_simple_deref(0, Regs.RBX, 16)
	def test_wreg32_64_WITH_wxmm32_64(self):
		a = I32("vcvtss2si eax, xmm1")
		a.check_reg(0, Regs.EAX, 32)
		a.check_reg(1, Regs.XMM1, 128)
		a = I64("vcvtss2si rax, [rbx]")
		a.check_reg(0, Regs.RAX, 64)
		a.check_simple_deref(1, Regs.RBX, 64)
		a = I64("vcvtss2si eax, [rbx]")
		a.check_reg(0, Regs.EAX, 32)
		a.check_simple_deref(1, Regs.RBX, 32)
	def test_vxmm(self):
		I32("vaddsd xmm1, xmm2, xmm3").check_reg(1, Regs.XMM2, 128)
		I64("vaddsd xmm2, xmm3, xmm4").check_reg(1, Regs.XMM3, 128)
	def test_xmm_imm(self):
		I32("vpblendvb xmm1, xmm2, xmm3, xmm4").check_reg(3, Regs.XMM4, 128)
		# Force XMM15, but high bit is ignored in 32bits.
		self.assertFalse(IB32("c4e3694ccbf0").inst.operands[3].index != Regs.XMM7)
		I64("vpblendvb xmm1, xmm2, xmm3, xmm15").check_reg(3, Regs.XMM15, 128)
	def test_yxmm(self):
		I32("vaddsubpd ymm2, ymm4, ymm6").check_reg(0, Regs.YMM2, 256)
		I32("vaddsubpd xmm7, xmm4, xmm6").check_reg(0, Regs.XMM7, 128)
		I64("vaddsubpd ymm12, ymm4, ymm6").check_reg(0, Regs.YMM12, 256)
		I64("vaddsubpd xmm14, xmm4, xmm6").check_reg(0, Regs.XMM14, 128)
	def test_yxmm_imm(self):
		I32("vblendvpd xmm1, xmm2, xmm3, xmm4").check_reg(3, Regs.XMM4, 128)
		I32("vblendvpd ymm1, ymm2, ymm3, ymm4").check_reg(3, Regs.YMM4, 256)
		# Force YMM15, but high bit is ignored in 32bits.
		self.assertFalse(IB32("c4e36d4bcbf0").inst.operands[3].index != Regs.YMM7)
		I64("vblendvpd xmm1, xmm2, xmm3, xmm14").check_reg(3, Regs.XMM14, 128)
		I64("vblendvpd ymm1, ymm2, ymm3, ymm9").check_reg(3, Regs.YMM9, 256)
	def test_ymm(self):
		I32("vbroadcastsd ymm5, [eax]").check_reg(0, Regs.YMM5, 256)
		I64("vbroadcastsd ymm13, [rax]").check_reg(0, Regs.YMM13, 256)
	def test_ymm256(self):
		I32("vperm2f128 ymm2, ymm4, [eax], 0x55").check_simple_deref(2, Regs.EAX, 256)
		I64("vperm2f128 ymm2, ymm14, [rax], 0x55").check_simple_deref(2, Regs.RAX, 256)
	def test_vymm(self):
		I32("vinsertf128 ymm1, ymm4, xmm4, 0xaa").check_reg(1, Regs.YMM4, 256)
		I64("vinsertf128 ymm1, ymm15, xmm4, 0xaa").check_reg(1, Regs.YMM15, 256)
	def test_vyxmm(self):
		I32("vmaxpd xmm1, xmm2, xmm3").check_reg(1, Regs.XMM2, 128)
		I32("vmaxpd ymm1, ymm2, ymm3").check_reg(1, Regs.YMM2, 256)
		I64("vmaxpd xmm1, xmm12, xmm3").check_reg(1, Regs.XMM12, 128)
		I64("vmaxpd ymm1, ymm12, ymm3").check_reg(1, Regs.YMM12, 256)
	def test_yxmm64_256(self):
		I32("vmovddup xmm1, xmm2").check_reg(1, Regs.XMM2, 128)
		I32("vmovddup ymm1, ymm2").check_reg(1, Regs.YMM2, 256)
		I32("vmovddup xmm1, [ecx]").check_simple_deref(1, Regs.ECX, 64)
		I32("vmovddup ymm1, [ebx]").check_simple_deref(1, Regs.EBX, 256)
		I64("vmovddup xmm1, xmm12").check_reg(1, Regs.XMM12, 128)
		I64("vmovddup ymm1, ymm12").check_reg(1, Regs.YMM12, 256)
		I64("vmovddup xmm1, [rcx]").check_simple_deref(1, Regs.RCX, 64)
		I64("vmovddup ymm1, [rbx]").check_simple_deref(1, Regs.RBX, 256)
	def test_yxmm128_256(self):
		I32("vandnpd xmm1, xmm2, xmm3").check_reg(2, Regs.XMM3, 128)
		I32("vandnpd ymm1, ymm2, ymm3").check_reg(2, Regs.YMM3, 256)
		I32("vandnpd xmm1, xmm2, [edi]").check_simple_deref(2, Regs.EDI, 128)
		I32("vandnpd ymm1, ymm2, [esi]").check_simple_deref(2, Regs.ESI, 256)
		I64("vandnpd xmm1, xmm2, xmm13").check_reg(2, Regs.XMM13, 128)
		I64("vandnpd ymm1, ymm2, ymm13").check_reg(2, Regs.YMM13, 256)
		I64("vandnpd xmm1, xmm2, [rdi]").check_simple_deref(2, Regs.RDI, 128)
		I64("vandnpd ymm1, ymm2, [rsi]").check_simple_deref(2, Regs.RSI, 256)
	def test_lxmm64_128(self):
		I32("vcvtdq2pd xmm1, xmm2").check_reg(1, Regs.XMM2, 128)
		I32("vcvtdq2pd xmm1, [eax]").check_simple_deref(1, Regs.EAX, 64)
		I32("vcvtdq2pd ymm1, [ebx]").check_simple_deref(1, Regs.EBX, 128)
		I64("vcvtdq2pd xmm1, xmm12").check_reg(1, Regs.XMM12, 128)
		I64("vcvtdq2pd xmm1, [rax]").check_simple_deref(1, Regs.RAX, 64)
		I64("vcvtdq2pd ymm1, [rbx]").check_simple_deref(1, Regs.RBX, 128)
	def test_lmem128_256(self):
		I32("vlddqu xmm1, [eax]").check_simple_deref(1, Regs.EAX, 128)
		I32("vlddqu ymm1, [eax]").check_simple_deref(1, Regs.EAX, 256)
		I64("vlddqu xmm1, [r14]").check_simple_deref(1, Regs.R14, 128)
		I64("vlddqu ymm1, [r13]").check_simple_deref(1, Regs.R13, 256)

class TestMisc(unittest.TestCase):
	def test_lods(self):
		a = I16("lodsb")
		a.check_reg(0, Regs.AL, 8)
		a.check_simple_deref(1, Regs.SI, 8)
		self.assertEqual(a.inst.isSegmentDefault, True)
		a = I32("lodsw")
		a.check_reg(0, Regs.AX, 16)
		a.check_simple_deref(1, Regs.ESI, 16)
		self.assertEqual(a.inst.isSegmentDefault, True)
		a = I32("lodsd")
		a.check_reg(0, Regs.EAX, 32)
		a.check_simple_deref(1, Regs.ESI, 32)
		self.assertEqual(a.inst.isSegmentDefault, True)
		a = I64("lodsq")
		a.check_reg(0, Regs.RAX, 64)
		a.check_simple_deref(1, Regs.RSI, 64)
		self.assertEqual(a.inst.isSegmentDefault, False)
		a = I16("db 0x2e\nlodsb")
		a.check_reg(0, Regs.AL, 8)
		a.check_simple_deref(1, Regs.SI, 8)
		self.assertEqual(a.inst.segment, Regs.CS)
		self.assertEqual(a.inst.isSegmentDefault, False)
		a = I32("db 0x2e\nlodsw")
		a.check_reg(0, Regs.AX, 16)
		a.check_simple_deref(1, Regs.ESI, 16)
		self.assertEqual(a.inst.segment, Regs.CS)
		self.assertEqual(a.inst.isSegmentDefault, False)
		a = I32("db 0x2e\nlodsd")
		a.check_reg(0, Regs.EAX, 32)
		a.check_simple_deref(1, Regs.ESI, 32)
		self.assertEqual(a.inst.segment, Regs.CS)
		self.assertEqual(a.inst.isSegmentDefault, False)
		a = I64("db 0x65\nlodsq")
		a.check_reg(0, Regs.RAX, 64)
		a.check_simple_deref(1, Regs.RSI, 64)
		self.assertEqual(a.inst.segment, Regs.GS)
		self.assertEqual(a.inst.isSegmentDefault, False)
	def test_stos(self):
		a = I16("stosb")
		a.check_simple_deref(0, Regs.DI, 8)
		a.check_reg(1, Regs.AL, 8)
		self.assertEqual(a.inst.isSegmentDefault, True)
		a = I32("stosw")
		a.check_simple_deref(0, Regs.EDI, 16)
		a.check_reg(1, Regs.AX, 16)
		self.assertEqual(a.inst.isSegmentDefault, True)
		a = I32("stosd")
		a.check_simple_deref(0, Regs.EDI, 32)
		a.check_reg(1, Regs.EAX, 32)
		self.assertEqual(a.inst.isSegmentDefault, True)
		a = I64("stosq")
		a.check_simple_deref(0, Regs.RDI, 64)
		a.check_reg(1, Regs.RAX, 64)
		self.assertEqual(a.inst.isSegmentDefault, False)
		a = I16("db 0x2e\nstosb")
		a.check_simple_deref(0, Regs.DI, 8)
		a.check_reg(1, Regs.AL, 8)
		self.assertEqual(a.inst.unusedPrefixesMask, 1)
		self.assertEqual(a.inst.segment, Regs.ES)
		self.assertEqual(a.inst.isSegmentDefault, True)
		a = I32("db 0x2e\nstosw")
		a.check_simple_deref(0, Regs.EDI, 16)
		a.check_reg(1, Regs.AX, 16)
		self.assertEqual(a.inst.unusedPrefixesMask, 1)
		self.assertEqual(a.inst.segment, Regs.ES)
		self.assertEqual(a.inst.isSegmentDefault, True)
		a = I32("db 0x2e\nstosd")
		a.check_simple_deref(0, Regs.EDI, 32)
		a.check_reg(1, Regs.EAX, 32)
		self.assertEqual(a.inst.unusedPrefixesMask, 1)
		self.assertEqual(a.inst.segment, Regs.ES)
		self.assertEqual(a.inst.isSegmentDefault, True)
		a = I64("db 0x65\nstosq")
		a.check_simple_deref(0, Regs.RDI, 64)
		a.check_reg(1, Regs.RAX, 64)
		self.assertEqual(a.inst.unusedPrefixesMask, 1)
		self.assertEqual(a.inst.segment, REG_NONE)
	def test_scas(self):
		a = I16("scasb")
		a.check_simple_deref(0, Regs.DI, 8)
		a.check_reg(1, Regs.AL, 8)
		self.assertEqual(a.inst.isSegmentDefault, True)
		a = I32("scasw")
		a.check_simple_deref(0, Regs.EDI, 16)
		a.check_reg(1, Regs.AX, 16)
		self.assertEqual(a.inst.isSegmentDefault, True)
		a = I32("scasd")
		a.check_simple_deref(0, Regs.EDI, 32)
		a.check_reg(1, Regs.EAX, 32)
		self.assertEqual(a.inst.isSegmentDefault, True)
		a = I64("scasq")
		a.check_simple_deref(0, Regs.RDI, 64)
		a.check_reg(1, Regs.RAX, 64)
		self.assertEqual(a.inst.isSegmentDefault, False)
		a = I16("db 0x2e\nscasb")
		a.check_simple_deref(0, Regs.DI, 8)
		a.check_reg(1, Regs.AL, 8)
		self.assertEqual(a.inst.unusedPrefixesMask, 1)
		self.assertEqual(a.inst.segment, Regs.ES)
		self.assertEqual(a.inst.isSegmentDefault, True)
		a = I32("db 0x2e\nscasw")
		a.check_simple_deref(0, Regs.EDI, 16)
		a.check_reg(1, Regs.AX, 16)
		self.assertEqual(a.inst.unusedPrefixesMask, 1)
		self.assertEqual(a.inst.segment, Regs.ES)
		self.assertEqual(a.inst.isSegmentDefault, True)
		a = I32("db 0x2e\nscasd")
		a.check_simple_deref(0, Regs.EDI, 32)
		a.check_reg(1, Regs.EAX, 32)
		self.assertEqual(a.inst.unusedPrefixesMask, 1)
		self.assertEqual(a.inst.segment, Regs.ES)
		self.assertEqual(a.inst.isSegmentDefault, True)
		a = I64("db 0x65\nscasq")
		a.check_simple_deref(0, Regs.RDI, 64)
		a.check_reg(1, Regs.RAX, 64)
		self.assertEqual(a.inst.unusedPrefixesMask, 1)
		self.assertEqual(a.inst.segment, REG_NONE)
	def test_cmps(self):
		a = I64("cmpsd")
		a.check_simple_deref(0, Regs.RSI, 32)
		a.check_simple_deref(1, Regs.RDI, 32)
		self.assertEqual(a.inst.unusedPrefixesMask, 0)
		self.assertEqual(a.inst.segment, REG_NONE)
		a = I16("db 0x2e\ncmpsb")
		a.check_simple_deref(0, Regs.SI, 8)
		a.check_simple_deref(1, Regs.DI, 8)
		self.assertEqual(a.inst.unusedPrefixesMask, 0)
		self.assertEqual(a.inst.segment, Regs.CS)
		self.assertEqual(a.inst.isSegmentDefault, False)
	def test_movs(self):
		a = I32("movsd")
		a.check_simple_deref(0, Regs.EDI, 32)
		a.check_simple_deref(1, Regs.ESI, 32)
		self.assertEqual(a.inst.unusedPrefixesMask, 0)
		self.assertEqual(a.inst.segment, Regs.DS)
		self.assertEqual(a.inst.isSegmentDefault, True)
		a = I32("db 0x2e\nmovsw")
		a.check_simple_deref(0, Regs.EDI, 16)
		a.check_simple_deref(1, Regs.ESI, 16)
		self.assertEqual(a.inst.unusedPrefixesMask, 0)
		self.assertEqual(a.inst.segment, Regs.CS)
		self.assertEqual(a.inst.isSegmentDefault, False)
	def test_ins(self):
		a = I32("db 0x65\ninsw")
		a.check_simple_deref(0, Regs.EDI, 16)
		a.check_reg(1, Regs.DX, 16)
		self.assertEqual(a.inst.unusedPrefixesMask, 1)
		self.assertEqual(a.inst.segment, Regs.ES)
		self.assertEqual(a.inst.isSegmentDefault, True)
	def test_outs(self):
		a = I64("db 0x65\noutsd")
		a.check_reg(0, Regs.DX, 16)
		a.check_simple_deref(1, Regs.RSI, 32)
		self.assertEqual(a.inst.segment, Regs.GS)
		self.assertEqual(a.inst.isSegmentDefault, False)
	def test_branch_hints(self):
		self.assertFalse("FLAG_HINT_TAKEN" not in I32("db 0x3e\n jnz 0x50").inst.flags)
		self.assertFalse("FLAG_HINT_NOT_TAKEN" not in I32("db 0x2e\n jp 0x55").inst.flags)
		self.assertFalse("FLAG_HINT_NOT_TAKEN" not in I32("db 0x2e\n jo 0x55000").inst.flags)
		self.assertFalse(I32("db 0x2e\n loop 0x55").inst.rawFlags & 0x1f, 0)
	def test_mnemonic_by_vexw(self):
		I32("vmovd xmm1, eax").check_mnemonic("VMOVD")
		I64("vmovd xmm1, eax").check_reg(1, Regs.EAX, 32)
		a = I64("vmovq xmm1, rax")
		a.check_mnemonic("VMOVQ")
		a.check_reg(1, Regs.RAX, 64)
	def test_vexl_ignored(self):
		I32("vaesdeclast xmm1, xmm2, xmm3").check_reg(0, Regs.XMM1, 128)
		IB32("c4e26ddfcb").check_mnemonic("VAESDECLAST")
		IB64("c4e26ddfcb").check_mnemonic("VAESDECLAST")
	def test_vexl_needed(self):
		I32("vinsertf128 ymm1, ymm2, xmm4, 0x42").check_mnemonic("VINSERTF128")
		IB32("c4e36918cc42").check_invalid() # Without VEX.L.
		IB64("c4e36918cc42").check_invalid() # Without VEX.L.
	def test_force_reg0(self):
		I32("extrq xmm1, 0x55, 0x66").check_mnemonic("EXTRQ")
		I64("extrq xmm14, 0x55, 0x66").check_reg(0, Regs.XMM14, 128)
	def test_pause(self):
		self.assertEqual(I16("pause").inst.size, 2)
		self.assertEqual(I32("pause").inst.size, 2)
		self.assertEqual(I64("pause").inst.size, 2)
	def test_nop(self):
		self.assertEqual(I16("db 0x90").inst.size, 1)
		self.assertEqual(I32("db 0x90").inst.size, 1)
		self.assertEqual(I64("db 0x90").inst.size, 1)
		self.assertEqual(I64("db 0x48, 0x90").inst.size, 2)
		# XCHG R8D, EAX
		a = I64("db 0x41, 0x90")
		a.check_reg(0, Regs.R8D, 32)
		a.check_reg(1, Regs.EAX, 32)
		# XCHG R8, RAX
		a = I64("db 0x49, 0x90")
		a.check_reg(0, Regs.R8, 64)
		a.check_reg(1, Regs.RAX, 64)
		a = I64("db 0x4f, 0x90")
		a.check_reg(0, Regs.R8, 64)
		a.check_reg(1, Regs.RAX, 64)
	def test_3dnow(self):
		I32("pfadd mm4, [eax]").check_reg(0, Regs.MM4, 64)
		I32("pfsub mm5, [eax]").check_reg(0, Regs.MM5, 64)
		I32("pfrcpit1 mm1, [ebx]").check_mnemonic("PFRCPIT1")
		I64("pavgusb mm1, mm2").check_mnemonic("PAVGUSB")
	def test_all_segs(self):
		I16("push fs").check_reg(0, Regs.FS, 16)
		I16("push gs").check_reg(0, Regs.GS, 16)
		I16("push ds").check_reg(0, Regs.DS, 16)
		I16("push cs").check_reg(0, Regs.CS, 16)
		I16("push ds").check_reg(0, Regs.DS, 16)
		I16("push es").check_reg(0, Regs.ES, 16)
	def test_op4(self):
		a = I32("insertq xmm2, xmm1, 0x55, 0xaa")
		a.check_reg(0, Regs.XMM2, 128)
		a.check_reg(1, Regs.XMM1, 128)
		a.check_type_size(2, distorm3.OPERAND_IMMEDIATE, 8)
		self.assertEqual(a.inst.operands[2].value, 0x55)
		a.check_type_size(3, distorm3.OPERAND_IMMEDIATE, 8)
		self.assertEqual(a.inst.operands[3].value, 0xaa)
	def test_pseudo_cmp(self):
		I32("cmpps xmm2, xmm3, 0x7")
		I64("cmpps xmm2, xmm4, 0x2")
	def test_jmp_counters(self):
		I16("jcxz 0x100")
		I32("jecxz 0x100")
		I64("jrcxz 0x100")
	def test_natives(self):
		self.assertEqual(I16("pusha").inst.size, 1)
		self.assertEqual(I16("pushad").inst.size, 2)
		self.assertEqual(I32("pusha").inst.size, 1)
		self.assertEqual(I32("pushaw").inst.size, 2)
		self.assertEqual(I16("CBW").inst.size, 1)
		self.assertEqual(I32("CWDE").inst.size, 1)
		self.assertEqual(I64("CDQE").inst.size, 2)
	def test_modrm_based(self):
		I32("movhlps xmm0, xmm1")
		I32("movhps xmm0, [eax]")
		I64("movhlps xmm0, xmm1")
		I64("movhps xmm0, [eax]")
		I64("movhlps xmm0, xmm1")
		I64("movlps xmm0, [eax]")
	def test_wait(self):
		self.assertEqual(I16("wait").inst.size, 1)
	def test_include_wait(self):
		self.assertEqual(I16("db 0x9b\n db 0xd9\n db 0x30").inst.size, 3)
	def test_loopxx_counters_size(self):
		a = I16("loopz 0x50")
		a.check_type_size(0,distorm3.OPERAND_IMMEDIATE, 8)
		a.check_addr_size(16)
		a = I32("loopz 0x50")
		a.check_type_size(0,distorm3.OPERAND_IMMEDIATE, 8)
		a.check_addr_size(32)
		a = I64("loopz 0x50")
		a.check_type_size(0,distorm3.OPERAND_IMMEDIATE, 8)
		a.check_addr_size(64)
		a = I16("db 0x67\n loopz 0x50")
		a.check_type_size(0,distorm3.OPERAND_IMMEDIATE, 8)
		a.check_addr_size(32)
		a = I32("db 0x67\n loopz 0x50")
		a.check_type_size(0,distorm3.OPERAND_IMMEDIATE, 8)
		a.check_addr_size(16)
		a = I64("db 0x67\n loopnz 0x50")
		a.check_type_size(0,distorm3.OPERAND_IMMEDIATE, 8)
		a.check_addr_size(32)
	def test_privileged(self):
		self.assertFalse(IB32("90").inst.privileged)
		self.assertTrue(I32("iret").inst.privileged)

def _hexlify(data):
	s = ""
	if type(data[0]) == str: # Python 2.x
		for i in data:
			s += "%02x" % ord(i)
	else:
		for i in data: # Python 3.x
			s += "%02x" % i
	return s

class TestMisc2(unittest.TestCase):
	def test_binary(self):
		# Generate 128kb of random bytes.
		# Disasm them, extract the returned hex,
		# And see that it matches the input.
		# This checks no bytes are skipped.
		data = "".join(["%02x" % random.randint(0, 255) for i in range(1 << 17)])
		insts = IB16(data).insts
		output = "".join([_hexlify(i.instructionBytes) for i in insts])
		self.assertTrue(data == output)
		insts = IB32(data).insts
		output = "".join([_hexlify(i.instructionBytes) for i in insts])
		self.assertTrue(data == output)
		insts = IB64(data).insts
		output = "".join([_hexlify(i.instructionBytes) for i in insts])
		self.assertTrue(data == output)
	def test_longest_mnemonic(self):
		# The longest mnemonic is VAESKEYGENASSIST and check it's null terminated.
		self.assertEqual(I32("VAESKEYGENASSIST xmm1, xmm2, 7").inst.mnemonic, "VAESKEYGENASSIST")

class TestPrefixes(unittest.TestCase):
	Derefs16 = ["BX + SI", "BX + DI", "BP + SI", "BP + DI", "SI", "DI", "BP", "BX"]
	Derefs32 = ["EAX", "ECX", "EDX", "EBX", "EBP", "ESI", "EDI"]
	Bases = ["EAX", "ECX", "EDX", "EBX", "ESP", "ESI", "EDI"]
	def test_without_seg(self):
		self.assertEqual(I64("and [rip+0X5247], ch").inst.segment, REG_NONE)
		self.assertEqual(I32("mov eax, [ebp*4]").inst.segment, Regs.DS)
		self.assertEqual(I32("mov eax, [eax*4+ebp]").inst.segment, Regs.SS)
	def test_default_seg16(self):
		a = I16("mov [ds:0x1234], ax")
		self.assertEqual(a.inst.segment, Regs.DS)
		self.assertEqual(a.inst.isSegmentDefault, 1)
		a = I16("mov [cs:0x1234], ax")
		self.assertEqual(a.inst.segment, Regs.CS)
		self.assertEqual(a.inst.isSegmentDefault, False)
	def test_default_seg16_all(self):
		for i in ["ADD [ds:%s], AX" % i for i in self.Derefs16]:
			a = I16(i)
			self.assertEqual(a.inst.segment, Regs.DS)
			if i[8:10] == "BP":
				self.assertEqual(a.inst.isSegmentDefault, False)
			else:
				self.assertEqual(a.inst.isSegmentDefault, True)
		# Test with disp8
		for i in ["ADD [ds:%s + 0x55], AX" % i for i in self.Derefs16]:
			a = I16(i)
			self.assertEqual(a.inst.segment, Regs.DS)
			if i[8:10] == "BP":
				self.assertEqual(a.inst.isSegmentDefault, False)
			else:
				self.assertEqual(a.inst.isSegmentDefault, True)
	def test_default_seg32(self):
		self.assertEqual(I32("mov [ds:0x12345678], eax").inst.segment, Regs.DS)
		self.assertEqual(I32("mov [cs:0x12345678], eax").inst.segment, Regs.CS)
		texts = ["ADD [ds:%s], EAX" % i for i in self.Derefs32]
		for i in enumerate(texts):
			a = I32(i[1])
			self.assertEqual(a.inst.segment, Regs.DS)
			if self.Derefs32[i[0]] == "EBP":
				self.assertEqual(a.inst.isSegmentDefault, False)
			else:
				self.assertEqual(a.inst.isSegmentDefault, True)
		# Test with disp8
		texts = ["ADD [ds:%s + 0x55], EAX" % i for i in self.Derefs32]
		for i in enumerate(texts):
			a = I32(i[1])
			self.assertEqual(a.inst.segment, Regs.DS)
			if self.Derefs32[i[0]] == "EBP":
				self.assertEqual(a.inst.isSegmentDefault, False)
			else:
				self.assertEqual(a.inst.isSegmentDefault, True)
	def test_sib(self):
		for i in enumerate(self.Derefs32):
			for j in enumerate(self.Bases):
				for s in [1, 2, 4, 8]:
					a = I32("cmp ebp, [ds:%s*%d + %s]" % (i[1], s, j[1]))
					a2 = I32("cmp ebp, [ds:%s*%d + %s + 0x55]" % (i[1], s, j[1]))
					self.assertEqual(a.inst.segment, Regs.DS)
					self.assertEqual(a2.inst.segment, Regs.DS)
					if (j[1] == "EBP" or j[1] == "ESP"):
						self.assertEqual(a.inst.isSegmentDefault, False)
						self.assertEqual(a2.inst.isSegmentDefault, False)
					else:
						self.assertEqual(a.inst.isSegmentDefault, True)
						self.assertEqual(a2.inst.isSegmentDefault, True)

	def test_seg64(self):
		self.assertEqual(I64("mov [gs:rip+0x12345678], eax").inst.segment, Regs.GS)
		self.assertEqual(I64("mov [fs:0x12345678], eax").inst.segment, Regs.FS)
	def test_lock(self):
		self.assertFalse("FLAG_LOCK" not in I32("lock inc dword [eax]").inst.flags)
	def test_repnz(self):
		self.assertFalse("FLAG_REPNZ" not in I32("repnz scasb").inst.flags)
	def test_rep(self):
		self.assertFalse("FLAG_REP" not in I32("rep movsb").inst.flags)
	def test_reps(self):
		""" Scas and cmps have different repZ prefix. """
		self.assertTrue(str(I32("rep scasb").inst).find("REPZ") != -1)
		self.assertTrue(str(I32("rep cmpsd").inst).find("REPZ") != -1)
		self.assertTrue(str(I32("rep stosb").inst).find("REP") != -1)
		self.assertTrue(str(I32("rep stosb").inst).find("REPZ") == -1)
		self.assertTrue(str(I16("repnz scasb").inst).find("REPNZ") != -1)
		self.assertTrue(str(I32("repnz cmpsd").inst).find("REPNZ") != -1)
		self.assertTrue(str(I64("repnz stosb").inst).find("REPNZ") != -1)
	def test_stos(self):
		""" STOS instruction is treated specially with certain prefixes, check all such cases. """
		# 16 bits
		self.assertEqual(str(IB16("aa").inst), "STOSB")
		self.assertEqual(str(IB16("ab").inst), "STOSW")
		self.assertEqual(str(IB16("66ab").inst), "STOSD")
		self.assertEqual(str(IB16("67ab").inst), "STOS [EDI], AX")
		self.assertEqual(str(IB16("6766ab").inst), "STOS [EDI], EAX")
		self.assertEqual(str(IB16("2eab").inst), "STOSW") # 1st op cannot be prefixed by segment!
		self.assertEqual(str(IB16("f3ab").inst), "REP STOSW")
		self.assertEqual(str(IB16("f2ab").inst), "REPNZ STOSW")
		# 32 bits
		self.assertEqual(str(IB32("aa").inst), "STOSB")
		self.assertEqual(str(IB32("ab").inst), "STOSD")
		self.assertEqual(str(IB32("66ab").inst), "STOSW")
		self.assertEqual(str(IB32("67ab").inst), "STOS [DI], EAX")
		self.assertEqual(str(IB32("6766ab").inst), "STOS [DI], AX")
		self.assertEqual(str(IB32("2eab").inst), "STOSD") # 1st op cannot be prefixed by segment!
		self.assertEqual(str(IB32("f3ab").inst), "REP STOSD")
		self.assertEqual(str(IB32("f2ab").inst), "REPNZ STOSD")
		# 64 bits
		self.assertEqual(str(IB64("aa").inst), "STOSB")
		self.assertEqual(str(IB64("ab").inst), "STOSD")
		self.assertEqual(str(IB64("48ab").inst), "STOSQ")
		self.assertEqual(str(IB64("66ab").inst), "STOSW")
		self.assertEqual(str(IB64("67ab").inst), "STOS [EDI], EAX")
		self.assertEqual(str(IB64("6766ab").inst), "STOS [EDI], AX")
		self.assertEqual(str(IB64("2eab").inst), "STOSD") # 1st op cannot be prefixed by segment!
		self.assertEqual(str(IB64("2e48ab").inst), "STOSQ") # 1st op cannot be prefixed by segment!
		self.assertEqual(str(IB64("f3ab").inst), "REP STOSD")
		self.assertEqual(str(IB64("f348ab").inst), "REP STOSQ")
		self.assertEqual(str(IB64("f2ab").inst), "REPNZ STOSD")
		self.assertEqual(str(IB64("f248ab").inst), "REPNZ STOSQ")
	def test_scas(self):
		""" SCAS instruction is treated specially with certain prefixes, check all such cases. """
		# 16 bits
		self.assertEqual(str(IB16("ae").inst), "SCASB")
		self.assertEqual(str(IB16("af").inst), "SCASW")
		self.assertEqual(str(IB16("66af").inst), "SCASD")
		self.assertEqual(str(IB16("67af").inst), "SCAS [EDI], AX")
		self.assertEqual(str(IB16("6766af").inst), "SCAS [EDI], EAX")
		self.assertEqual(str(IB16("2eaf").inst), "SCASW") # 1st op cannot be prefixed by segment!
		self.assertEqual(str(IB16("f3af").inst), "REPZ SCASW")
		self.assertEqual(str(IB16("f2af").inst), "REPNZ SCASW")
		# 32 bits
		self.assertEqual(str(IB32("ae").inst), "SCASB")
		self.assertEqual(str(IB32("af").inst), "SCASD")
		self.assertEqual(str(IB32("66af").inst), "SCASW")
		self.assertEqual(str(IB32("67af").inst), "SCAS [DI], EAX")
		self.assertEqual(str(IB32("6766af").inst), "SCAS [DI], AX")
		self.assertEqual(str(IB32("2eaf").inst), "SCASD") # 1st op cannot be prefixed by segment!
		self.assertEqual(str(IB32("f3af").inst), "REPZ SCASD")
		self.assertEqual(str(IB32("f2af").inst), "REPNZ SCASD")
		# 64 bits
		self.assertEqual(str(IB64("ae").inst), "SCASB")
		self.assertEqual(str(IB64("af").inst), "SCASD")
		self.assertEqual(str(IB64("48af").inst), "SCASQ")
		self.assertEqual(str(IB64("66af").inst), "SCASW")
		self.assertEqual(str(IB64("67af").inst), "SCAS [EDI], EAX")
		self.assertEqual(str(IB64("6766af").inst), "SCAS [EDI], AX")
		self.assertEqual(str(IB64("2eaf").inst), "SCASD") # 1st op cannot be prefixed by segment!
		self.assertEqual(str(IB64("2e48af").inst), "SCASQ") # 1st op cannot be prefixed by segment!
		self.assertEqual(str(IB64("f3af").inst), "REPZ SCASD")
		self.assertEqual(str(IB64("f348af").inst), "REPZ SCASQ")
		self.assertEqual(str(IB64("f2af").inst), "REPNZ SCASD")
		self.assertEqual(str(IB64("f248af").inst), "REPNZ SCASQ")
	def test_lods(self):
		""" LODS instruction is treated specially with certain prefixes, check all such cases. """
		# 16 bits
		self.assertEqual(str(IB16("ac").inst), "LODSB")
		self.assertEqual(str(IB16("ad").inst), "LODSW")
		self.assertEqual(str(IB16("66ad").inst), "LODSD")
		self.assertEqual(str(IB16("67ad").inst), "LODS AX, [ESI]")
		self.assertEqual(str(IB16("6766ad").inst), "LODS EAX, [ESI]")
		self.assertEqual(str(IB16("64ad").inst), "LODS AX, [FS:SI]")
		self.assertEqual(str(IB16("f364ad").inst), "REP LODS AX, [FS:SI]")
		self.assertEqual(str(IB16("f264ad").inst), "REPNZ LODS AX, [FS:SI]")
		# 32 bits
		self.assertEqual(str(IB32("ac").inst), "LODSB")
		self.assertEqual(str(IB32("66ad").inst), "LODSW")
		self.assertEqual(str(IB32("ad").inst), "LODSD")
		self.assertEqual(str(IB32("f3ac").inst), "REP LODSB")
		self.assertEqual(str(IB32("66f3ad").inst), "REP LODSW")
		self.assertEqual(str(IB32("f3ad").inst), "REP LODSD")
		self.assertEqual(str(IB32("65ad").inst), "LODS EAX, [GS:ESI]")
		self.assertEqual(str(IB32("f365ad").inst), "REP LODS EAX, [GS:ESI]")
		self.assertEqual(str(IB32("f36567ad").inst), "REP LODS EAX, [GS:SI]")
		self.assertEqual(str(IB32("f3656766ad").inst), "REP LODS AX, [GS:SI]")
		self.assertEqual(str(IB32("6667f365ad").inst), "REP LODS AX, [GS:SI]")
		self.assertEqual(str(IB32("67f3ac").inst), "REP LODS AL, [SI]")
		self.assertEqual(str(IB32("67f2ac").inst), "REPNZ LODS AL, [SI]")
		# 64 bits
		self.assertEqual(str(IB64("ac").inst), "LODSB")
		self.assertEqual(str(IB64("66ad").inst), "LODSW")
		self.assertEqual(str(IB64("ad").inst), "LODSD")
		self.assertEqual(str(IB64("48ad").inst), "LODSQ")
		self.assertEqual(str(IB64("f3ac").inst), "REP LODSB")
		self.assertEqual(str(IB64("66f3ad").inst), "REP LODSW")
		self.assertEqual(str(IB64("f3ad").inst), "REP LODSD")
		self.assertEqual(str(IB64("65ad").inst), "LODS EAX, [GS:RSI]")
		self.assertEqual(str(IB64("f365ad").inst), "REP LODS EAX, [GS:RSI]")
		self.assertEqual(str(IB64("f36567ad").inst), "REP LODS EAX, [GS:ESI]")
		self.assertEqual(str(IB64("f3656766ad").inst), "REP LODS AX, [GS:ESI]")
		self.assertEqual(str(IB64("6667f365ad").inst), "REP LODS AX, [GS:ESI]")
		self.assertEqual(str(IB64("6667f265ad").inst), "REPNZ LODS AX, [GS:ESI]")
		self.assertEqual(str(IB64("67f3ac").inst), "REP LODS AL, [ESI]")
	def test_movs(self):
		""" MOVS instruction is treated specially with certain prefixes, check all such cases. """
		# 16 bits
		self.assertEqual(str(IB16("a4").inst), "MOVSB")
		self.assertEqual(str(IB16("66a5").inst), "MOVSD")
		self.assertEqual(str(IB16("a5").inst), "MOVSW")
		self.assertEqual(str(IB16("f3a5").inst), "REP MOVSW")
		self.assertEqual(str(IB16("66f3a5").inst), "REP MOVSD")
		self.assertEqual(str(IB16("f366a5").inst), "REP MOVSD")
		self.assertEqual(str(IB16("f3a5").inst), "REP MOVSW")
		self.assertEqual(str(IB16("65a5").inst), "MOVS WORD [ES:DI], [GS:SI]")
		self.assertEqual(str(IB16("f365a5").inst), "REP MOVS WORD [ES:DI], [GS:SI]")
		self.assertEqual(str(IB16("f36567a5").inst), "REP MOVS WORD [ES:EDI], [GS:ESI]")
		self.assertEqual(str(IB16("f3656766a5").inst), "REP MOVS DWORD [ES:EDI], [GS:ESI]")
		self.assertEqual(str(IB16("6667f365a5").inst), "REP MOVS DWORD [ES:EDI], [GS:ESI]")
		self.assertEqual(str(IB16("6667f3a4").inst), "REP MOVS BYTE [ES:EDI], [DS:ESI]")
		self.assertEqual(str(IB16("6667f2a4").inst), "REPNZ MOVS BYTE [ES:EDI], [DS:ESI]")
		# 32 bits
		self.assertEqual(str(IB32("a4").inst), "MOVSB")
		self.assertEqual(str(IB32("66a5").inst), "MOVSW")
		self.assertEqual(str(IB32("a5").inst), "MOVSD")
		self.assertEqual(str(IB32("f3a5").inst), "REP MOVSD")
		self.assertEqual(str(IB32("66f3a5").inst), "REP MOVSW")
		self.assertEqual(str(IB32("f366a5").inst), "REP MOVSW")
		self.assertEqual(str(IB32("f3a5").inst), "REP MOVSD")
		self.assertEqual(str(IB32("f2a5").inst), "REPNZ MOVSD")
		self.assertEqual(str(IB32("65a5").inst), "MOVS DWORD [ES:EDI], [GS:ESI]")
		self.assertEqual(str(IB32("f365a5").inst), "REP MOVS DWORD [ES:EDI], [GS:ESI]")
		self.assertEqual(str(IB32("f36567a5").inst), "REP MOVS DWORD [ES:DI], [GS:SI]")
		self.assertEqual(str(IB32("f3656766a5").inst), "REP MOVS WORD [ES:DI], [GS:SI]")
		self.assertEqual(str(IB32("6667f365a5").inst), "REP MOVS WORD [ES:DI], [GS:SI]")
		self.assertEqual(str(IB32("6667f3a4").inst), "REP MOVS BYTE [ES:DI], [DS:SI]")
		self.assertEqual(str(IB32("6667f2a4").inst), "REPNZ MOVS BYTE [ES:DI], [DS:SI]")
		# 64 bits
		self.assertEqual(str(IB64("a4").inst), "MOVSB")
		self.assertEqual(str(IB64("66a5").inst), "MOVSW")
		self.assertEqual(str(IB64("a5").inst), "MOVSD")
		self.assertEqual(str(IB64("48a5").inst), "MOVSQ")
		self.assertEqual(str(IB64("4fa5").inst), "MOVSQ") # Set all REX bits, still MOVSQ.
		self.assertEqual(str(IB64("f3a5").inst), "REP MOVSD")
		self.assertEqual(str(IB64("f348a5").inst), "REP MOVSQ")
		self.assertEqual(str(IB64("f248a5").inst), "REPNZ MOVSQ")
		self.assertEqual(str(IB64("66f3a5").inst), "REP MOVSW")
		self.assertEqual(str(IB64("f366a5").inst), "REP MOVSW")
		self.assertEqual(str(IB64("f3a5").inst), "REP MOVSD")
		self.assertEqual(str(IB64("65a5").inst), "MOVS DWORD [RDI], [GS:RSI]")
		self.assertEqual(str(IB64("6548a5").inst), "MOVS QWORD [RDI], [GS:RSI]")
		self.assertEqual(str(IB64("f365a5").inst), "REP MOVS DWORD [RDI], [GS:RSI]")
		self.assertEqual(str(IB64("f367a5").inst), "REP MOVS DWORD [EDI], [ESI]")
		self.assertEqual(str(IB64("f3656766a5").inst), "REP MOVS WORD [EDI], [GS:ESI]")
		self.assertEqual(str(IB64("6667f365a5").inst), "REP MOVS WORD [EDI], [GS:ESI]")
		self.assertEqual(str(IB64("6667f36548a5").inst), "REP MOVS QWORD [EDI], [GS:ESI]")
		self.assertEqual(str(IB64("6667f3a4").inst), "REP MOVS BYTE [EDI], [ESI]")
	def test_cmps(self):
		""" CMPS instruction is treated specially with certain prefixes, check all such cases. """
		# 16 bits
		self.assertEqual(str(IB16("a6").inst), "CMPSB")
		self.assertEqual(str(IB16("66a7").inst), "CMPSD")
		self.assertEqual(str(IB16("a7").inst), "CMPSW")
		self.assertEqual(str(IB16("f3a7").inst), "REPZ CMPSW")
		self.assertEqual(str(IB16("66f3a7").inst), "REPZ CMPSD")
		self.assertEqual(str(IB16("f366a7").inst), "REPZ CMPSD")
		self.assertEqual(str(IB16("f3a7").inst), "REPZ CMPSW")
		self.assertEqual(str(IB16("65a7").inst), "CMPS WORD [GS:SI], [ES:DI]")
		self.assertEqual(str(IB16("f365a7").inst), "REPZ CMPS WORD [GS:SI], [ES:DI]")
		self.assertEqual(str(IB16("f36567a7").inst), "REPZ CMPS WORD [GS:ESI], [ES:EDI]")
		self.assertEqual(str(IB16("f3656766a7").inst), "REPZ CMPS DWORD [GS:ESI], [ES:EDI]")
		self.assertEqual(str(IB16("6667f365a7").inst), "REPZ CMPS DWORD [GS:ESI], [ES:EDI]")
		self.assertEqual(str(IB16("6667f3a6").inst), "REPZ CMPS BYTE [DS:ESI], [ES:EDI]")
		self.assertEqual(str(IB16("6667f2a6").inst), "REPNZ CMPS BYTE [DS:ESI], [ES:EDI]")
		# 32 bits
		self.assertEqual(str(IB32("a6").inst), "CMPSB")
		self.assertEqual(str(IB32("66a7").inst), "CMPSW")
		self.assertEqual(str(IB32("a7").inst), "CMPSD")
		self.assertEqual(str(IB32("f3a7").inst), "REPZ CMPSD")
		self.assertEqual(str(IB32("66f3a7").inst), "REPZ CMPSW")
		self.assertEqual(str(IB32("f366a7").inst), "REPZ CMPSW")
		self.assertEqual(str(IB32("f3a7").inst), "REPZ CMPSD")
		self.assertEqual(str(IB32("f2a7").inst), "REPNZ CMPSD")
		self.assertEqual(str(IB32("65a7").inst), "CMPS DWORD [GS:ESI], [ES:EDI]")
		self.assertEqual(str(IB32("f365a7").inst), "REPZ CMPS DWORD [GS:ESI], [ES:EDI]")
		self.assertEqual(str(IB32("f36567a7").inst), "REPZ CMPS DWORD [GS:SI], [ES:DI]")
		self.assertEqual(str(IB32("f3656766a7").inst), "REPZ CMPS WORD [GS:SI], [ES:DI]")
		self.assertEqual(str(IB32("6667f365a7").inst), "REPZ CMPS WORD [GS:SI], [ES:DI]")
		self.assertEqual(str(IB32("6667f3a6").inst), "REPZ CMPS BYTE [DS:SI], [ES:DI]")
		self.assertEqual(str(IB32("6667f2a6").inst), "REPNZ CMPS BYTE [DS:SI], [ES:DI]")
		# 64 bits
		self.assertEqual(str(IB64("a6").inst), "CMPSB")
		self.assertEqual(str(IB64("66a7").inst), "CMPSW")
		self.assertEqual(str(IB64("a7").inst), "CMPSD")
		self.assertEqual(str(IB64("48a7").inst), "CMPSQ")
		self.assertEqual(str(IB64("4fa7").inst), "CMPSQ") # Set all REX bits, still CMPSQ.
		self.assertEqual(str(IB64("f3a7").inst), "REPZ CMPSD")
		self.assertEqual(str(IB64("f348a7").inst), "REPZ CMPSQ")
		self.assertEqual(str(IB64("f248a7").inst), "REPNZ CMPSQ")
		self.assertEqual(str(IB64("66f3a7").inst), "REPZ CMPSW")
		self.assertEqual(str(IB64("f366a7").inst), "REPZ CMPSW")
		self.assertEqual(str(IB64("f3a7").inst), "REPZ CMPSD")
		self.assertEqual(str(IB64("65a7").inst), "CMPS DWORD [GS:RSI], [RDI]")
		self.assertEqual(str(IB64("6548a7").inst), "CMPS QWORD [GS:RSI], [RDI]")
		self.assertEqual(str(IB64("f365a7").inst), "REPZ CMPS DWORD [GS:RSI], [RDI]")
		self.assertEqual(str(IB64("f367a7").inst), "REPZ CMPS DWORD [ESI], [EDI]")
		self.assertEqual(str(IB64("f3656766a7").inst), "REPZ CMPS WORD [GS:ESI], [EDI]")
		self.assertEqual(str(IB64("6667f365a7").inst), "REPZ CMPS WORD [GS:ESI], [EDI]")
		self.assertEqual(str(IB64("6667f36548a7").inst), "REPZ CMPS QWORD [GS:ESI], [EDI]")
		self.assertEqual(str(IB64("6667f3a6").inst), "REPZ CMPS BYTE [ESI], [EDI]")
	def test_segment_override(self):
		self.assertEqual(I32("mov eax, [cs:eax]").inst.segment, Regs.CS)
		self.assertEqual(I32("mov eax, [ds:eax]").inst.segment, Regs.DS)
		self.assertEqual(I32("mov eax, [es:eax]").inst.segment, Regs.ES)
		self.assertEqual(I32("mov eax, [ss:eax]").inst.segment, Regs.SS)
		self.assertEqual(I32("mov eax, [fs:eax]").inst.segment, Regs.FS)
		self.assertEqual(I32("mov eax, [gs:eax]").inst.segment, Regs.GS)
	def test_unused_normal(self):
		self.assertEqual(IB64("4090").inst.unusedPrefixesMask, 1)
		self.assertEqual(IB64("6790").inst.unusedPrefixesMask, 1)
		self.assertEqual(IB64("6690").inst.unusedPrefixesMask, 1)
		self.assertEqual(IB64("f290").inst.unusedPrefixesMask, 1)
		self.assertEqual(IB64("f090").inst.unusedPrefixesMask, 1)
		self.assertEqual(IB64("f3c3").inst.unusedPrefixesMask, 1)
		self.assertEqual(IB64("64c3").inst.unusedPrefixesMask, 1)
	def test_unused_doubles(self):
		self.assertEqual(IB64("404090").inst.unusedPrefixesMask, 3)
		self.assertEqual(IB64("676790").inst.unusedPrefixesMask, 3)
		self.assertEqual(IB64("666690").inst.unusedPrefixesMask, 3)
		self.assertEqual(IB64("f2f290").inst.unusedPrefixesMask, 3)
		self.assertEqual(IB64("f0f090").inst.unusedPrefixesMask, 3)
		self.assertEqual(IB64("f3f3c3").inst.unusedPrefixesMask, 3)
		self.assertEqual(IB64("642ec3").inst.unusedPrefixesMask, 3)
	def test_unused_sequences(self):
		self.assertEqual(len(IB64("66"*15).insts), 15)
		r = int(random.random() * 14)
		self.assertEqual(IB64("66"*r + "90").inst.unusedPrefixesMask, (1 << r) - 1)
	def test_rexw_66(self):
		self.assertEqual(IB64("6648ffc0").inst.unusedPrefixesMask, 1)
		self.assertEqual(IB64("6640ffc0").inst.unusedPrefixesMask, 2)
		self.assertEqual(IB64("48660f10c0").inst.unusedPrefixesMask, 1)
		self.assertEqual(IB64("664f0f10c0").inst.unusedPrefixesMask, 0)
	def test_last_segment(self):
		""" Only last segment is used as a prefix.
		Check tricky 64 bits too for default overrides. """
		self.assertEqual(IB32("2e260000").inst.segment, Regs.ES)
		self.assertEqual(IB32("2e260000").inst.unusedPrefixesMask, 1)
		self.assertEqual(IB64("2e650000").inst.segment, Regs.GS)
		self.assertEqual(IB64("652e0000").inst.segment, REG_NONE)
		self.assertEqual(IB64("652e0000").inst.unusedPrefixesMask, 3)

class TestInvalid(unittest.TestCase):
	def align(self):
		for i in range(15):
			IB32("90")
	def test_filter_mem(self):
		#cmpxchg8b eax
		IB32("0fc7c8")
		self.align()
	def test_drop_prefixes(self):
		# Drop prefixes when we encountered an instruction that couldn't be decoded.
		IB32("666764ffff")
		self.align()
	def test_zzz_must_be_last_drop_prefixes(self):
		# Drop prefixes when the last byte in stream is a prefix.
		IB32("66")
	def test_CR4_regression(self):
		# Regression test to validate CR4 isn't used as invalid default segment (-1 maps to CR4) in 64 bits.
		self.assertEqual(str(IB64("f20f104c1860").inst), "MOVSD XMM1, [RAX+RBX+0x60]")
		self.assertEqual(str(IB64("4883241e00").inst), "AND QWORD [RSI+RBX], 0x0")
	def test_undefined_byte00(self):
		# This is a regression test for the decomposer wrapper.
		a = ""
		insts = IB32("c300").insts
		for i in insts:
			a += str(i)
		insts = IB32("33c0" *  2000 + "90", 0, 0x4000).insts
		self.assertEqual(insts[-1].mnemonic, "NOP")
		self.assertEqual(insts[-1].instructionBytes, b"\x90")
		self.assertEqual(insts[-1].address, 0x4000 + 2000 * 2)
		self.assertEqual(insts[1000].mnemonic, "XOR")
		self.assertEqual(insts[1000].instructionBytes, b"\x33\xc0")
		self.assertEqual(insts[1000].address, 0x4000 + 1000 * 2)
	def test_prefix_regression(self):
		# We had a temporary code with a prefix length bug that wouldn't return an instruction.
		# So make sure we get an instruction where stream ends with last code byte.
		self.assertEqual(IB32("66af").insts[0].mnemonic, "SCAS")

class TestFeatures(unittest.TestCase):
	def test_addr16(self):
		#I16("mov [-4], bx", 0, DF_MAXIMUM_ADDR16).check_disp(0, 0xfffc, 16, 16)
		pass
	def test_add32(self):
		pass
	def test_fc(self):
		pairs = [
			(["INT 5", "db 0xf1", "INT 3", "INTO", "UD2"], distorm3.FlowControl.INT),
			(["CALL 0x50", "CALL FAR [ebx]"], distorm3.FlowControl.CALL),
			(["RET", "IRET", "RETF"], distorm3.FlowControl.RET),
			(["HLT"], distorm3.FlowControl.HLT),
			(["SYSCALL", "SYSENTER", "SYSRET", "SYSEXIT"], distorm3.FlowControl.SYS),
			(["JMP 0x50", "JMP FAR [ebx]"], distorm3.FlowControl.UNC_BRANCH),
			(["JCXZ 0x50", "JO 0x50", "JNO 0x50", "JB 0x50", "JAE 0x50",
			"JZ 0x50", "JNZ 0x50", "JBE 0x50", "JA 0x50", "JS 0x50",
			"JNS 0x50", "JP 0x50", "JNP 0x50", "JL 0x50", "JGE 0x50",
			"JLE 0x50", "JG 0x50", "LOOP 0x50", "LOOPZ 0x50", "LOOPNZ 0x50"], distorm3.FlowControl.CND_BRANCH)
		]
		for i in pairs:
			for j in i[0]:
				a = I32(j + "\nnop", distorm3.DF_STOP_ON_FLOW_CONTROL)
				self.assertEqual(len(a.insts), 1)
				self.assertEqual(a.inst.meta & 0xf, i[1])
				a = I32("push eax\nnop\n" + j, distorm3.DF_RETURN_FC_ONLY)
				self.assertEqual(len(a.insts), 1)
				a = I32("nop\nxor eax, eax\n" + j + "\ninc eax", distorm3.DF_RETURN_FC_ONLY | distorm3.DF_STOP_ON_FLOW_CONTROL)
				self.assertEqual(len(a.insts), 1)
	def test_filter(self):
		a = IB32("33c0907e00" * 5, distorm3.DF_RETURN_FC_ONLY).insts
		self.assertEqual(len(a), 5)
		self.assertEqual(a[0].mnemonic[0], "J")
		self.assertEqual(a[0].address, 3)
		self.assertEqual(a[1].address, 8)
		self.assertEqual(a[2].address, 13)
		self.assertEqual(a[3].address, 18)
		self.assertEqual(a[4].address, 23)
	def test_stop_on_privileged(self):
		a = I32("nop\niret\nret", distorm3.DF_STOP_ON_PRIVILEGED)
		self.assertEqual(len(a.insts), 2)
		a = I64("mov eax, ebx\nnop\ncli\nnop", distorm3.DF_STOP_ON_PRIVILEGED)
		self.assertEqual(len(a.insts), 3)
	def test_step_byte(self):
		a = IB32("90b833c3eb48", distorm3.DF_SINGLE_BYTE_STEP).insts
		self.assertEqual(a[0].address, 0)
		self.assertEqual(a[0].mnemonic, "NOP")
		self.assertEqual(a[0].size, 1)
		self.assertEqual(a[1].address, 1)
		self.assertEqual(a[1].mnemonic, "MOV")
		self.assertEqual(a[1].size, 5)
		self.assertEqual(a[2].address, 2)
		self.assertEqual(a[2].mnemonic, "XOR")
		self.assertEqual(a[2].size, 2)
		self.assertEqual(a[3].address, 3)
		self.assertEqual(a[3].mnemonic, "RET")
		self.assertEqual(a[3].size, 1)
		self.assertEqual(a[4].address, 4)
		self.assertEqual(a[4].mnemonic, "JMP")
		self.assertEqual(a[4].size, 2)
		self.assertEqual(a[5].address, 5)
		self.assertEqual(a[5].mnemonic, "DEC")
		self.assertEqual(a[5].size, 1)
	def test_eflags_on(self):
		a = IB32("33c04890", distorm3.DF_FILL_EFLAGS).insts
		# XOR
		self.assertEqual(a[0].modifiedFlags, distorm3.D_SF | distorm3.D_ZF | distorm3.D_PF)
		self.assertEqual(a[0].testedFlags, 0)
		self.assertEqual(a[0].undefinedFlags, distorm3.D_AF)
		# INC
		self.assertEqual(a[1].modifiedFlags, distorm3.D_OF | distorm3.D_SF | distorm3.D_ZF | distorm3.D_AF | distorm3.D_PF)
		self.assertEqual(a[1].testedFlags, 0)
		self.assertEqual(a[1].undefinedFlags, 0)
		# NOP
		self.assertEqual(a[2].modifiedFlags, 0)
		self.assertEqual(a[2].testedFlags, 0)
		self.assertEqual(a[2].undefinedFlags, 0)
	def test_eflags_off(self):
		a = IB32("33c04890").insts
		# XOR
		self.assertEqual(a[0].modifiedFlags, 0)
		self.assertEqual(a[0].testedFlags, 0)
		self.assertEqual(a[0].undefinedFlags, 0)
		# INC
		self.assertEqual(a[1].modifiedFlags, 0)
		self.assertEqual(a[1].testedFlags, 0)
		self.assertEqual(a[1].undefinedFlags, 0)
		# NOP
		self.assertEqual(a[2].modifiedFlags, 0)
		self.assertEqual(a[2].testedFlags, 0)
		self.assertEqual(a[2].undefinedFlags, 0)
	def test_stop_undecodable(self):
		self.assertEqual(len(IB16("909033c0ffff90", distorm3.DF_STOP_ON_UNDECODEABLE).insts), 4)
		self.assertEqual(len(IB32("909033c090ffff90", distorm3.DF_STOP_ON_UNDECODEABLE).insts), 5)
		self.assertEqual(len(IB64("909033c09090ffff9090", distorm3.DF_STOP_ON_UNDECODEABLE).insts), 6)

class TestAPI(unittest.TestCase):
	def direct_decompose(self, code, codeOffset, dt, features, maxInstructions):
		codeLen         = len(code)
		code_buf        = ctypes.create_string_buffer(code)
		p_code          = ctypes.byref(code_buf)
		result          = (distorm3._DInst * maxInstructions)()
		p_result        = ctypes.byref(result)
		usedInstructionsCount = ctypes.c_uint(0)
		codeInfo = distorm3._CodeInfo(distorm3._OffsetType(codeOffset), distorm3._OffsetType(0), distorm3._OffsetType(0), ctypes.cast(p_code, ctypes.c_char_p), codeLen, dt, features)
		status = distorm3.internal_decompose(ctypes.byref(codeInfo), ctypes.byref(result), maxInstructions, ctypes.byref(usedInstructionsCount))
		return (status, usedInstructionsCount.value, result)
	def test_out_buf(self):
		s, count, results = self.direct_decompose(b"\x90\x90", 0, distorm3.Decode32Bits, 0, 0)
		self.assertEqual(s, distorm3.DECRES_INPUTERR)
		s, count, results = self.direct_decompose(b"\x90\x90", 0, distorm3.Decode32Bits, 0, 1)
		self.assertEqual(s, distorm3.DECRES_MEMORYERR)
		self.assertEqual(count, 1)
		s, count, results = self.direct_decompose(b"\x90\x90", 0, distorm3.Decode32Bits, 0, 2)
		self.assertEqual(s, distorm3.DECRES_SUCCESS)
		self.assertEqual(count, 2)
	def test_0_len(self):
		s, count, results = self.direct_decompose(b"", 0, distorm3.Decode32Bits, 0, 1)
		self.assertEqual(s, distorm3.DECRES_SUCCESS)
		s, count, results = self.direct_decompose(b"", 0x1234, distorm3.Decode64Bits, 0, 1)
		self.assertEqual(s, distorm3.DECRES_SUCCESS)
	def test_bad_features(self):
		s, count, results = self.direct_decompose(b"\x90", 0, distorm3.Decode32Bits, distorm3.DF_MAXIMUM_ADDR16 | distorm3.DF_MAXIMUM_ADDR32, 1)
		self.assertEqual(s, distorm3.DECRES_INPUTERR)
	def test_bad_decoding_type(self):
		s, count, results = self.direct_decompose(b"\x90", 0, -1, 0, 1)
		self.assertEqual(s, distorm3.DECRES_INPUTERR)
		s, count, results = self.direct_decompose(b"\x90", 0, 3, 0, 1)
		self.assertEqual(s, distorm3.DECRES_INPUTERR)
	def test_single_out_buf(self):
		s, count, results = self.direct_decompose(b"\x66\x90", 0, distorm3.Decode32Bits, 0, 1)
		self.assertEqual(s, distorm3.DECRES_SUCCESS)
		self.assertEqual(count, 1)
		self.assertEqual(Mnemonics.get(results[0].opcode, ""), "NOP")
		s, count, results = self.direct_decompose(b"\x66\x67", 0, distorm3.Decode32Bits, 0, 1)
		self.assertEqual(s, distorm3.DECRES_MEMORYERR)
		self.assertEqual(count, 1)
		self.assertEqual(results[0].imm.byte, 0x66)
		s, count, results = self.direct_decompose(b"\x66\x67", 0, distorm3.Decode32Bits, 0, 2)
		self.assertEqual(s, distorm3.DECRES_SUCCESS)
		self.assertEqual(count, 2)
		self.assertEqual(results[0].imm.byte, 0x66)
		self.assertEqual(results[1].imm.byte, 0x67)
		s, count, results = self.direct_decompose(b"\x66\x67", 0, distorm3.Decode32Bits, 0, 1)
		self.assertEqual(s, distorm3.DECRES_MEMORYERR)
		self.assertEqual(count, 1)
	def test_drop_skip(self):
		s, count, results = self.direct_decompose(b"\x05\x00\x01", 0, distorm3.Decode32Bits, 0, 1) # Skips 05, then returns add [ecx], al
		self.assertEqual(s, distorm3.DECRES_MEMORYERR)
		self.assertEqual(count, 1)
		s, count, results = self.direct_decompose(b"\x05\x00\x01", 0, distorm3.Decode32Bits, 0, 2)
		self.assertEqual(s, distorm3.DECRES_SUCCESS)
		self.assertEqual(count, 2)
		s, count, results = self.direct_decompose(b"\xc4\x01", 0, distorm3.Decode32Bits, 0, 1)
		self.assertEqual(s, distorm3.DECRES_SUCCESS)
		self.assertEqual(count, 1)
		self.assertEqual(Mnemonics.get(results[0].opcode, ""), "LES")
		s, count, results = self.direct_decompose(b"\xc5\xc5", 0, distorm3.Decode32Bits, 0, 2)
		self.assertEqual(s, distorm3.DECRES_SUCCESS)
		self.assertEqual(count, 2)
		self.assertEqual(results[0].imm.byte, 0xc5)
		self.assertEqual(results[1].imm.byte, 0xc5)
		s, count, results = self.direct_decompose(b"\xc5\xc5\xc5", 0, distorm3.Decode32Bits, 0, 3)
		self.assertEqual(s, distorm3.DECRES_SUCCESS)
		self.assertEqual(count, 3)
		self.assertEqual(results[0].imm.byte, 0xc5)
		self.assertEqual(results[1].imm.byte, 0xc5)
		self.assertEqual(results[2].imm.byte, 0xc5)
	def test_fc(self):
		s, count, results = self.direct_decompose(b"\x90", 0, distorm3.Decode32Bits, distorm3.DF_RETURN_FC_ONLY, 1)
		self.assertEqual(s, distorm3.DECRES_SUCCESS)
		self.assertEqual(count, 0)
		s, count, results = self.direct_decompose(b"\x90\x75\x00", 0, distorm3.Decode32Bits, distorm3.DF_RETURN_FC_ONLY, 1)
		self.assertEqual(s, distorm3.DECRES_SUCCESS)
		self.assertEqual(count, 1)
	def test_single_step(self):
		s, count, results = self.direct_decompose(b"\x33\xff\xc0", 0, distorm3.Decode32Bits, distorm3.DF_SINGLE_BYTE_STEP, 1)
		self.assertEqual(s, distorm3.DECRES_MEMORYERR)
		self.assertEqual(count, 1)
		self.assertEqual(Mnemonics.get(results[0].opcode, ""), "XOR")
		s, count, results = self.direct_decompose(b"\x33\xff\xc0", 0, distorm3.Decode32Bits, distorm3.DF_SINGLE_BYTE_STEP, 2)
		self.assertEqual(s, distorm3.DECRES_MEMORYERR)
		self.assertEqual(count, 2)
		self.assertEqual(Mnemonics.get(results[0].opcode, ""), "XOR")
		self.assertEqual(Mnemonics.get(results[1].opcode, ""), "INC")
		s, count, results = self.direct_decompose(b"\x33\xff\xc0", 0, distorm3.Decode32Bits, distorm3.DF_SINGLE_BYTE_STEP, 3)
		self.assertEqual(s, distorm3.DECRES_SUCCESS)
		self.assertEqual(count, 3)
		self.assertEqual(Mnemonics.get(results[0].opcode, ""), "XOR")
		self.assertEqual(Mnemonics.get(results[1].opcode, ""), "INC")
		self.assertEqual(results[2].imm.byte, 0xc0)
	def test_fc_and_single_step(self):
		s, count, results = self.direct_decompose(b"\x33\xc3", 0, distorm3.Decode32Bits, distorm3.DF_SINGLE_BYTE_STEP | distorm3.DF_RETURN_FC_ONLY, 1)
		self.assertEqual(s, distorm3.DECRES_SUCCESS)
		self.assertEqual(count, 1)
		self.assertEqual(Mnemonics.get(results[0].opcode, ""), "RET")
	def test_fc_dropped(self):
		s, count, results = self.direct_decompose(b"\x33\xc3", 0, distorm3.Decode64Bits, distorm3.DF_RETURN_FC_ONLY, 1)
		self.assertEqual(s, distorm3.DECRES_SUCCESS)
		self.assertEqual(count, 0)
		s, count, results = self.direct_decompose(b"\x66\x67\x90\xc3", 0, distorm3.Decode64Bits, distorm3.DF_RETURN_FC_ONLY, 1)
		self.assertEqual(s, distorm3.DECRES_SUCCESS)
		self.assertEqual(count, 1)
		s, count, results = self.direct_decompose(b"\x66\x67", 0, distorm3.Decode64Bits, distorm3.DF_RETURN_FC_ONLY, 1)
		self.assertEqual(s, distorm3.DECRES_SUCCESS)
		self.assertEqual(count, 0)

def GetNewSuite(className):
	suite = unittest.TestSuite()
	suite.addTest(unittest.makeSuite(className))
	return suite

def initfiles():
	for i in ["bin16", "bin32", "bin64"]:
		fbin.append(open("build\\linux\\"+i, "wb"))

if "pytest" in sys.modules:
    print("pytest isn't supported; this file uses Python's unittest, run: ./test_distorm3.py")
    sys.exit(-1)

if __name__ == "__main__":
	random.seed()
	#initfiles() # Used to emit the bytes of the tests - useful for code coverage input.
	suite = unittest.TestSuite()
	suite.addTest(GetNewSuite(TestMode16))
	suite.addTest(GetNewSuite(TestMode32))
	suite.addTest(GetNewSuite(TestMode64))
	suite.addTest(GetNewSuite(TestInstTable))
	suite.addTest(GetNewSuite(TestAVXOperands))
	suite.addTest(GetNewSuite(TestMisc))
	suite.addTest(GetNewSuite(TestMisc2))
	suite.addTest(GetNewSuite(TestPrefixes))
	suite.addTest(GetNewSuite(TestInvalid))
	suite.addTest(GetNewSuite(TestFeatures))
	suite.addTest(GetNewSuite(TestAPI))
	result = unittest.TextTestRunner(verbosity=1).run(suite)
	if result.wasSuccessful():
		exit(0)
	else:
		exit(1)
