"""
Home for the i386 emulation code.
"""
import struct
import envi
import envi.bits as e_bits
import envi.memory as e_mem
from envi.archs.i386.regs import *
from envi.archs.i386.disasm import *
from envi.archs.i386 import i386Module
[docs]def shiftMask(val, size):
if size == 1:
return (val & 0x1f) % 9
elif size == 2:
return (val & 0x1f) % 17
elif size == 4:
return val & 0x1f
elif size == 8:
return val & 0x3f
else:
raise Exception("shiftMask is broke in envi/intel.py")
# The indexes for the list of segments in the emulator
SEG_CS = 0
SEG_DS = 1
SEG_ES = 2
SEG_FS = 3
SEG_GS = 4
SEG_SS = 5
# The general purpose register indexes
# (for use in _emu_setGpReg / _emu_getGpReg)
# NOTE: These *must* stay in sync with i386regs first row.
GPR_A = 0
GPR_C = 1
GPR_D = 2
GPR_B = 3
GPR_SP = 4
GPR_BP = 5
GPR_SI = 6
GPR_DI = 7
[docs]class IntelCall(envi.CallingConvention):
[docs] def getCallArgs(self, emu, count):
"""
Standard intel stack arg parsing
"""
esp = emu.getRegister(REG_ESP)
esp += 4 # For the saved eip
return struct.unpack("<%dI" % count, emu.readMemory(esp, 4*count))
[docs] def setReturnValue(self, emu, value, argc):
"""
A return routine which cleans up it's stack args.
"""
esp = emu.getRegister(REG_ESP)
eip = emu.readMemoryFormat(esp, '<I')[0]
esp += 4 # For the saved eip
esp += (4 * argc) # Cleanup saved args
emu.setRegister(REG_ESP, esp)
emu.setRegister(REG_EAX, value)
emu.setProgramCounter(eip)
[docs]class StdCall(IntelCall): pass
[docs]class Cdecl(IntelCall):
[docs] def setReturnValue(self, emu, value, argc):
"""
A base non-cleanup stackarg return
"""
esp = emu.getRegister(REG_ESP)
eip = struct.unpack("<I", emu.readMemory(esp, 4))[0]
esp += 4 # For the saved eip
emu.setRegister(REG_EAX, value)
emu.setStackCounter(esp)
emu.setProgramCounter(eip)
[docs]class ThisCall(StdCall):
[docs] def getCallArgs(self, emu, count):
ret = [emu.getRegister(REG_ECX),]
count -= 1
esp = emu.getRegister(REG_ESP)
esp += 4 # For the saved eip
if count:
ret.extend(struct.unpack("<%dI" % count, emu.readMemory(esp, 4*count)))
return ret
[docs] def setReturnValue(self, emu, value, argc):
argc -= 1 # One for the ECX...
return StdCall.setReturnValue(self, emu, value, argc)
[docs]class FastCall(envi.CallingConvention):
def __init__(self, reglist):
self.reglist = reglist
[docs] def getCallArgs(self, emu, count):
ret = []
for i in xrange(count):
if len(self.reglist) <= i:
break
regid = self.reglist[i]
ret.append(emu.getRegister(regid))
count -= 1
if count > 0:
esp = emu.getRegister(REG_ESP)
esp += 4 # For the saved eip
ret.extend(struct.unpack("<%dI" % count, emu.readMemory(esp, 4*count)))
return ret
[docs] def setReturnValue(self, emu, value, argc):
esp = emu.getRegister(REG_ESP)
eip = emu.readMemoryFormat(esp, '<I')[0]
esp += 4
if argc > len(self.reglist):
cbytes = (argc - len(self.reglist)) * 4
esp += cbytes
emu.setRegister(REG_EAX, value)
emu.setStackCounter(esp)
emu.setProgramCounter(eip)
[docs]class MsFastCall(FastCall):
def __init__(self):
FastCall.__init__(self, (REG_ECX, REG_EDX))
[docs]class BFastCall(FastCall):
def __init__(self):
FastCall.__init__(self, (REG_EAX, REG_EDX, REG_ECX))
stdcall = StdCall()
thiscall = ThisCall()
cdecl = Cdecl()
msfastcall = MsFastCall()
bfastcall = BFastCall()
[docs]class IntelEmulator(i386RegisterContext, envi.Emulator):
def __init__(self):
# Set ourself up as an arch module *and* register context
#i386Module.__init__(self)
archmod = i386Module()
envi.Emulator.__init__(self, archmod=archmod)
for i in xrange(6):
self.setSegmentInfo(i, 0, 0xffffffff)
i386RegisterContext.__init__(self)
# Add our known calling conventions
self.addCallingConvention('stdcall', stdcall)
self.addCallingConvention('thiscall', thiscall)
self.addCallingConvention('cdecl', cdecl)
self.addCallingConvention('msfastcall', msfastcall)
self.addCallingConvention('bfastcall', bfastcall)
[docs] def getSegmentIndex(self, op):
# FIXME this needs to account for push/pop/etc
if op.prefixes == 0:
return SEG_DS
if op.prefixes & PREFIX_ES:
return SEG_ES
elif op.prefixes & PREFIX_CS:
return SEG_CS
elif op.prefixes & PREFIX_SS:
return SEG_SS
elif op.prefixes & PREFIX_DS:
return SEG_DS
elif op.prefixes & PREFIX_FS:
return SEG_FS
elif op.prefixes & PREFIX_GS:
return SEG_GS
return SEG_DS
[docs] def setFlag(self, which, state):
flags = self.getRegister(REG_EFLAGS)
if state:
flags |= which
else:
flags &= ~which
self.setRegister(REG_EFLAGS, flags)
[docs] def getFlag(self, which):
flags = self.getRegister(REG_EFLAGS)
return bool(flags & which)
[docs] def readMemValue(self, addr, size):
bytes = self.readMemory(addr, size)
if bytes == None:
return None
#FIXME change this (and all uses of it) to passing in format...
if len(bytes) != size:
raise Exception("Read Gave Wrong Length At 0x%.8x (va: 0x%.8x wanted %d got %d)" % (self.getProgramCounter(),addr, size, len(bytes)))
if size == 1:
return struct.unpack("B", bytes)[0]
elif size == 2:
return struct.unpack("<H", bytes)[0]
elif size == 4:
return struct.unpack("<I", bytes)[0]
elif size == 8:
return struct.unpack("<Q", bytes)[0]
[docs] def writeMemValue(self, addr, value, size):
#FIXME change this (and all uses of it) to passing in format...
if size == 1:
bytes = struct.pack("B",value & 0xff)
elif size == 2:
bytes = struct.pack("<H",value & 0xffff)
elif size == 4:
bytes = struct.pack("<I", value & 0xffffffff)
elif size == 8:
bytes = struct.pack("<Q", value & 0xffffffffffffffff)
self.writeMemory(addr, bytes)
[docs] def readMemSignedValue(self, addr, size):
bytes = self.readMemory(addr, size)
if bytes == None:
return None
if size == 1:
return struct.unpack("b", bytes)[0]
elif size == 2:
return struct.unpack("<h", bytes)[0]
elif size == 4:
return struct.unpack("<l", bytes)[0]
[docs] def executeOpcode(self, op):
# NOTE: If an opcode method returns
# other than None, that is the new eip
meth = self.op_methods.get(op.mnem, None)
if meth == None:
raise envi.UnsupportedInstruction(self, op)
if op.prefixes & PREFIX_REP:
x = self.doRepPrefix(meth, op)
else:
x = meth(op)
if x == None:
pc = self.getProgramCounter()
x = pc+op.size
self.setProgramCounter(x)
###### Conditional Callbacks #####
# NOTE: for ease of validation, these are in the same order as the Jcc
# page in the intel manual. However, duplicate conditions (be/na) are
# reduced to their earliest (in the manual) form.
[docs] def cond_a(self):
return self.getFlag(EFLAGS_CF) == 0 and self.getFlag(EFLAGS_ZF) == 0
[docs] def cond_ae(self):
return self.getFlag(EFLAGS_CF) == 0
[docs] def cond_b(self):
return self.getFlag(EFLAGS_CF) == 1
[docs] def cond_be(self):
return self.getFlag(EFLAGS_CF) == 1 or self.getFlag(EFLAGS_ZF) == 1
[docs] def cond_c(self):
return self.getFlag(EFLAGS_CF) == 1
[docs] def cond_ecxz(self):
return self.getRegister(REG_ECX) == 0
[docs] def cond_e(self):
return self.getFlag(EFLAGS_ZF) == 1
[docs] def cond_g(self):
return self.getFlag(EFLAGS_ZF) == 0 and (self.getFlag(EFLAGS_SF) == self.getFlag(EFLAGS_OF))
[docs] def cond_ge(self):
return self.getFlag(EFLAGS_SF) == self.getFlag(EFLAGS_OF)
[docs] def cond_l(self):
return self.getFlag(EFLAGS_SF) != self.getFlag(EFLAGS_OF)
[docs] def cond_le(self):
return (self.getFlag(EFLAGS_SF) != self.getFlag(EFLAGS_OF) or
(self.getFlag(EFLAGS_ZF) == 1))
# Some duplicates
cond_na = cond_be
cond_nae = cond_b
cond_nb = cond_ae
cond_nbe = cond_a
cond_nc = cond_ae
[docs] def cond_ne(self):
return self.getFlag(EFLAGS_ZF) == 0
# A few more
cond_ng = cond_le
cond_nge = cond_l
cond_nl = cond_ge
cond_nle = cond_g
[docs] def cond_no(self):
return self.getFlag(EFLAGS_OF) == 0
[docs] def cond_np(self):
return self.getFlag(EFLAGS_PF) == 0
[docs] def cond_ns(self):
return self.getFlag(EFLAGS_SF) == 0
cond_nz = cond_ne
[docs] def cond_o(self):
return self.getFlag(EFLAGS_OF) == 1
[docs] def cond_p(self):
return self.getFlag(EFLAGS_PF) == 1
cond_pe = cond_p
cond_po = cond_np
[docs] def cond_s(self):
return self.getFlag(EFLAGS_SF) == 1
cond_z = cond_e
# FROM OTHER INSTRUCTIONS
cond_nc = cond_ae
cond_nl = cond_ge
###### End Conditional Callbacks #####
[docs] def doPush(self, val):
esp = self.getRegister(REG_ESP)
esp -= 4
self.writeMemValue(esp, val, 4)
self.setRegister(REG_ESP, esp)
[docs] def doPop(self):
esp = self.getRegister(REG_ESP)
val = self.readMemValue(esp, 4)
self.setRegister(REG_ESP, esp+4)
return val
[docs] def integerSubtraction(self, op):
"""
Do the core of integer subtraction but only *return* the
resulting value rather than assigning it.
(allows cmp and sub to use the same code)
"""
# Src op gets sign extended to dst
dst = self.getOperValue(op, 0)
src = self.getOperValue(op, 1)
# So we can either do a BUNCH of crazyness with xor and shifting to
# get the necissary flags here, *or* we can just do both a signed and
# unsigned sub and use the results.
dsize = op.opers[0].tsize
ssize = op.opers[1].tsize
# Sign extend immediates where the sizes don't match
if dsize != ssize:
src = e_bits.sign_extend(src, ssize, dsize)
ssize = dsize
return self.intSubBase(src, dst, ssize, dsize)
[docs] def intSubBase(self, src, dst, ssize, dsize):
usrc = e_bits.unsigned(src, ssize)
udst = e_bits.unsigned(dst, dsize)
ssrc = e_bits.signed(src, ssize)
sdst = e_bits.signed(dst, dsize)
ures = udst - usrc
sres = sdst - ssrc
#print "dsize/ssize: %d %d" % (dsize, ssize)
#print "unsigned: %d %d %d" % (usrc, udst, ures)
#print "signed: %d %d %d" % (ssrc, sdst, sres)
self.setFlag(EFLAGS_OF, e_bits.is_signed_overflow(sres, dsize))
self.setFlag(EFLAGS_AF, e_bits.is_aux_carry(usrc, udst))
self.setFlag(EFLAGS_CF, e_bits.is_unsigned_carry(ures, dsize))
self.setFlag(EFLAGS_SF, e_bits.is_signed(ures, dsize))
self.setFlag(EFLAGS_ZF, not sres)
self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(ures))
return ures
[docs] def logicalAnd(self, op):
dst = self.getOperValue(op, 0)
src = self.getOperValue(op, 1)
dsize = op.opers[0].tsize
ssize = op.opers[1].tsize
# sign-extend an immediate if needed
if dsize != ssize:
src = e_bits.sign_extend(src, ssize, dsize)
ssize = dsize
# Make sure everybody's on the same bit page.
dst = e_bits.unsigned(dst, dsize)
src = e_bits.unsigned(src, ssize)
res = src & dst
self.setFlag(EFLAGS_AF, 0) # AF is undefined, but it seems like it is zeroed
self.setFlag(EFLAGS_OF, 0)
self.setFlag(EFLAGS_CF, 0)
self.setFlag(EFLAGS_SF, e_bits.is_signed(res, dsize))
self.setFlag(EFLAGS_ZF, not res)
self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(res))
return res
[docs] def doRepPrefix(self, meth, op):
#FIXME check for opcode family valid to rep
ret = None
ecx = self.getRegister(REG_ECX)
while ecx != 0:
ret = meth(op)
ecx -= 1
self.setRegister(REG_ECX, 0)
return ret
[docs] def doRepzPrefix(self, meth, op):
pass
# Beginning of Instruction methods
[docs] def i_adc(self, op):
dst = self.getOperValue(op, 0)
src = self.getOperValue(op, 1)
cf = 0
if self.getFlag(EFLAGS_CF):
cf = 1
dstsize = op.opers[0].tsize
srcsize = op.opers[1].tsize
if (isinstance(op.opers[1], i386ImmOper) and
srcsize < dstsize):
src = e_bits.sign_extend(src, srcsize, dstsize)
srcsize = dstsize
#FIXME perhaps unify the add/adc flags/arith code
res = dst + src + cf
tsize = op.opers[0].tsize
self.setFlag(EFLAGS_CF, e_bits.is_unsigned_carry(res, tsize))
self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(res))
self.setFlag(EFLAGS_AF, e_bits.is_aux_carry(src, dst))
self.setFlag(EFLAGS_ZF, not res)
self.setFlag(EFLAGS_SF, e_bits.is_signed(res, tsize))
self.setFlag(EFLAGS_OF, e_bits.is_signed_overflow(res, tsize))
self.setOperValue(op, 0, res)
[docs] def i_add(self, op):
dst = self.getOperValue(op, 0)
src = self.getOperValue(op, 1)
dsize = op.opers[0].tsize
ssize = op.opers[1].tsize
if dsize > ssize:
src = e_bits.sign_extend(src, ssize, dsize)
ssize = dsize
udst = e_bits.unsigned(dst, dsize)
usrc = e_bits.unsigned(src, ssize)
sdst = e_bits.signed(dst, dsize)
ssrc = e_bits.signed(src, ssize)
ures = udst + usrc
sres = sdst + ssrc
self.setFlag(EFLAGS_CF, e_bits.is_unsigned_carry(ures, dsize))
self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(ures))
self.setFlag(EFLAGS_AF, e_bits.is_aux_carry(src, dst))
self.setFlag(EFLAGS_ZF, not ures)
self.setFlag(EFLAGS_SF, e_bits.is_signed(ures, dsize))
self.setFlag(EFLAGS_OF, e_bits.is_signed_overflow(sres, dsize))
self.setOperValue(op, 0, ures)
[docs] def i_and(self, op):
#FIXME 24 and 25 opcodes should *not* get sign-extended.
res = self.logicalAnd(op)
self.setOperValue(op, 0, res)
[docs] def i_arpl(self, op):
v1 = self.getOperValue(op, 0)
v2 = self.getOperValue(op, 1)
# Mask off the rpl
r1 = v1 & 3
r2 = v2 & 3
if r1 < r2: # If dest rpl < src rpl
self.setFlag(EFLAGS_ZF, True)
# Bump 2 bits off the bottom and add r2
self.setOperValue(op, 0, ((v1 >> 2) << 2) | r2)
else:
self.setFlag(EFLAGS_ZF, False)
[docs] def i_bswap(self, op):
val = self.getOperValue(op, 0)
tsize = op.opers[0].tsize
self.setOperValue(op, 0, e_bits.byteswap(val, tsize))
[docs] def i_bsr(self, op):
val = self.getOperValue(op, 0)
if val == 0:
# If the src is 0, set ZF and get out
self.setFlag(EFLAGS_ZF, True)
return
self.setFlag(EFLAGS_ZF, False)
tsize = op.opers[0].tsize
rmax = (tsize*8) - 1
while rmax >= 0:
if val & (1<<rmax):
self.setOperValue(op, 1, rmax)
return
rmax -= 1
[docs] def doBitTest(self, op):
val = self.getOperValue(op, 0)
shift = self.getOperValue(op, 1)
mask = 1 << shift
self.setFlag(EFLAGS_CF, val & mask)
# Return the source and mask for btc/btr
return val,mask
[docs] def i_bt(self, op):
self.doBitTest(op)
[docs] def i_btc(self, op):
# bit test and toggle bit in source
val, mask = self.doBitTest(op)
self.setOperValue(op, 0, val ^ mask)
[docs] def i_btr(self, op):
# bit test (and clear in the source)
val, mask = self.doBitTest(op)
mask = e_bits.unsigned(~val, op.opers[0].tsize)
self.setOperValue(op, 0, val & mask)
[docs] def i_bts(self, op):
# bit test (and set in the source)
val, mask = self.doBitTest(op)
self.setOperValue(op, 0, val | mask)
[docs] def i_call(self, op):
eip = self.getProgramCounter()
saved = eip + op.size
self.doPush(saved)
return self.getOperValue(op, 0)
[docs] def i_clc(self, op):
self.setFlag(EFLAGS_CF, False)
[docs] def i_cld(self, op):
self.setFlag(EFLAGS_DF, False)
[docs] def i_cli(self, op):
self.setFlag(EFLAGS_IF, False)
# We include all the possible CMOVcc names just in case somebody
# gets hinkey with the disassembler.
[docs] def i_cmova(self, op):
if self.cond_a(): return self.i_mov(op)
[docs] def i_cmovae(self, op):
if self.cond_ae(): return self.i_mov(op)
[docs] def i_cmovb(self, op):
if self.cond_b(): return self.i_mov(op)
[docs] def i_cmovbe(self, op):
if self.cond_be(): return self.i_mov(op)
[docs] def i_cmovc(self, op):
if self.cond_c(): return self.i_mov(op)
[docs] def i_cmovecxz(self, op):
if self.cond_ecxz(): return self.i_mov(op)
[docs] def i_cmove(self, op):
if self.cond_e(): return self.i_mov(op)
[docs] def i_cmovg(self, op):
if self.cond_g(): return self.i_mov(op)
[docs] def i_cmovge(self, op):
if self.cond_ge(): return self.i_mov(op)
[docs] def i_cmovl(self, op):
if self.cond_l(): return self.i_mov(op)
[docs] def i_cmovle(self, op):
if self.cond_le(): return self.i_mov(op)
i_cmovna = i_cmovbe
i_cmovnae = i_cmovb
i_cmovnb = i_cmovae
i_cmovnbe = i_cmova
i_cmovnc = i_cmovae
[docs] def i_cmovne(self, op):
if self.cond_ne(): return self.i_mov(op)
i_cmovng = i_cmovle
i_cmovnge = i_cmovl
i_cmovnl = i_cmovge
i_cmovnle = i_cmovg
[docs] def i_cmovno(self, op):
if self.cond_no(): return self.i_mov(op)
[docs] def i_cmovnp(self, op):
if self.cond_np(): return self.i_mov(op)
[docs] def i_cmovns(self, op):
if self.cond_ns(): return self.i_mov(op)
i_cmovnz = i_cmovne
[docs] def i_cmovo(self, op):
if self.cond_o(): return self.i_mov(op)
[docs] def i_cmovp(self, op):
if self.cond_p(): return self.i_mov(op)
i_cmovpe = i_cmovp
i_cmovpo = i_cmovnp
[docs] def i_cmovs(self, op):
if self.cond_s(): return self.i_mov(op)
i_cmovz = i_cmove
[docs] def i_cmp(self, op):
self.integerSubtraction(op)
[docs] def doCmps(self, width):
esi = self.getRegister(REG_ESI)
edi = self.getRegister(REG_EDI)
# FIXME che
sval = self.readMemValue(esi, width)
dval = self.readMemValue(edi, width)
self.intSubBase(sval, dval, width, width)
if self.getFlag(EFLAGS_ZF):
if self.getFlag(EFLAGS_DF): # decrement
esi -= width
edi -= width
else:
esi += width
edi += width
self.setRegister(REG_ESI, esi)
self.setRegister(REG_EDI, edi)
[docs] def i_cmpsb(self, op):
self.doCmps(1)
[docs] def i_cmpsd(self, op):
"""
Compare the dword pointed at by ds:esi to ds:edi.
(if equal, update esi/edi by one acording to DF)
"""
width = 4
if op.prefixes & PREFIX_OP_SIZE:
width = 2
self.doCmps(width)
[docs] def i_cmpxchg(self, op):
tsize = op.opers[0].tsize
if tsize == 4:
areg = REG_EAX
elif tsize == 1:
areg = REG_AL
else:
areg = REG_AX
aval = self.getRegister(areg)
tval = self.getOperValue(op, 0)
vval = self.getOperValue(op, 1)
#FIXME eflags... is this supposed to be a real cmp?
if aval == tval:
self.setFlag(EFLAGS_ZF, True)
self.setOperValue(op, 0, vval)
else:
self.setFlag(EFLAGS_ZF, False)
self.setRegister(areg, tval)
[docs] def twoRegCompound(self, topreg, botreg, size):
"""
Build a compound value where the value of the top reg is shifted and
or'd with the value of the bot reg ( assuming they are size
bytes in length). The return is size * 2 wide (and unsigned).
"""
top = e_bits.unsigned(self.getRegister(topreg), size)
bot = e_bits.unsigned(self.getRegister(botreg), size)
return ((top << (size *8)) | bot)
[docs] def regsFromCompound(self, val, size):
top = e_bits.unsigned(val >> (size * 8), size)
bot = e_bits.unsigned(val, size)
return (top, bot)
[docs] def i_cmpxch8b(self, op):
size = 4
dsize = 8
if op.prefixes & PREFIX_OP_SIZE:
size = 2
dsize = 4
bignum = self.twoRegCompound(REG_EDX, REG_EAX, size)
testnum = self.getOperValue(op, 0)
if bignum == testnum:
self.setFlag(EFLAGS_ZF, 1)
resval = self.twoRegCompound(REG_ECX, REG_EBX, size)
self.setOperValue(op, 0, resval)
else:
self.setFlag(EFLAGS_ZF, 0)
edx,eax = self.regsFromCompound(testnum, dsize)
self.setRegister(REG_EDX, edx)
self.setRegister(REG_EAX, eax)
[docs] def i_cdq(self, op):
return self.i_cwd(op)
[docs] def i_cpuid(self, op):
eax = self.getRegister(REG_EAX)
print "FIXME: cpuid() returns NONSENSE (eax:0x%.8x)" % eax
self.setRegister(REG_EAX, 0)
self.setRegister(REG_EBX, 0)
self.setRegister(REG_ECX, 0)
self.setRegister(REG_EDX, 0)
[docs] def i_cwd(self, op):
#FIXME handle 16 bit variant
eax = self.getRegister(REG_EAX)
if e_bits.is_signed(eax, 4):
self.setRegister(REG_EDX, 0xffffffff)
else:
self.setRegister(REG_EDX, 0)
[docs] def i_dec(self, op):
val = self.getOperValue(op, 0)
if val == None:
self.undefFlags()
return
val -= 1
self.setOperValue(op, 0, val)
#FIXME change over to integer subtraction
self.setFlag(EFLAGS_OF, 0) #FIXME OF
self.setFlag(EFLAGS_SF, e_bits.is_signed(val, op.opers[0].tsize))
self.setFlag(EFLAGS_ZF, not val)
self.setFlag(EFLAGS_AF, 0) #FIXME AF...
self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(val))
[docs] def i_div(self, op):
#FIXME this is probably broke
oper = op.opers[0]
val = self.getOperValue(op, 1)
if val == 0: raise envi.DivideByZero(self)
if oper.tsize == 1:
ax = self.getRegister(REG_AX)
quot = ax / val
rem = ax % val
if quot > 255:
#FIXME stuff
print "FIXME: division exception"
self.setRegister(REG_EAX, (quot << 8) + rem)
elif oper.tsize == 4:
#FIXME 16 bit over-ride
eax = self.getRegister(REG_EAX)
edx = self.getRegister(REG_EDX)
tot = (edx << 32) + eax
quot = tot / val
rem = tot % val
if quot > 0xffffffff:
print "FIXME: division exception"
self.setRegister(REG_EAX, quot)
self.setRegister(REG_EDX, rem)
else:
raise envi.UnsupportedInstruction(self, op)
[docs] def i_enter(self, op):
locsize = self.getOperValue(op, 0)
depth = self.getOperValue(op, 1)
if depth != 0:
raise envi.UnsupportedInstruction(self, op)
esp = self.getRegister(REG_ESP)
ebp = self.getRegister(REG_EBP)
esp -= 4 # Room for the base pointer
self.writeMemValue(esp, ebp, 4)
self.setRegister(REG_EBP, esp)
esp -= locsize
self.setRegister(REG_ESP, esp)
# FIXME a whole bunch of float instructions whose
# processing is essentially ignored:
[docs] def i_fldz(self, op):
pass
[docs] def i_fild(self, op):
pass
[docs] def i_fstp(self, op):
pass
[docs] def i_idiv(self, op):
#FIXME this needs emulation testing!
tsize = op.opers[0].tsize
if tsize == 1:
ax = self.getRegister(REG_AX)
ax = e_bits.signed(ax, 2)
d = self.getOperValue(op, 0)
d = e_bits.signed(d, 1)
if d == 0: raise envi.DivideByZero(self)
q = ax / d
r = ax % d
res = ((r & 0xff) << 8) | (q & 0xff)
self.setRegister(REG_AX, res)
elif tsize == 2:
val = self.twoRegCompound(REG_DX, REG_AX, 2)
val = e_bits.signed(val, 4)
d = self.getOperValue(op, 0)
d = e_bits.signed(d, 2)
if d == 0: raise envi.DivideByZero(self)
q = val / d
r = val % d
self.setRegister(REG_AX, q)
self.setRegister(REG_DX, r)
elif tsize == 4:
val = self.twoRegCompound(REG_EDX, REG_EAX, 4)
val = e_bits.signed(val, 8)
d = self.getOperValue(op, 0)
d = e_bits.signed(d, 4)
if d == 0: raise envi.DivideByZero(self)
q = val / d
r = val % d
self.setRegister(REG_EAX, q)
self.setRegister(REG_EDX, r)
else:
raise envi.UnsupportedInstruction(self, op)
[docs] def i_imul(self, op):
#FIXME eflags
# FIXME imul bugs
ocount = len(op.opers)
if ocount == 2:
dst = self.getOperValue(op, 0)
src = self.getOperValue(op, 1)
dsize = op.opers[0].tsize
ssize = op.opers[1].tsize
# FIXME all these are taken care of in disasm now...
if dsize > ssize:
src = e_bits.sign_extend(src, ssize, dsize)
ssize = dsize
res = dst * src
sof = e_bits.is_unsigned_carry(res, dsize)
self.setFlag(EFLAGS_CF, sof)
self.setFlag(EFLAGS_OF, sof)
self.setOperValue(op, 0, res)
elif ocount == 3:
dst = self.getOperValue(op, 0)
src1 = self.getOperValue(op, 1)
src2 = self.getOperValue(op, 2)
dsize = op.opers[0].tsize
ssize1 = op.opers[1].tsize
ssize2 = op.opers[2].tsize
if dsize > ssize2: # Only the last operand may be shorter imm
src2 = e_bits.sign_extend(src2, ssize2, dsize)
ssize2 = dsize
res = src1 * src2
sof = e_bits.is_unsigned_carry(res, dsize)
self.setFlag(EFLAGS_CF, sof)
self.setFlag(EFLAGS_OF, sof)
self.setOperValue(op, 0, res)
else:
raise envi.UnsupportedInstruction(self, op)
[docs] def i_in(self, op):
raise envi.UnsupportedInstruction(self, op)
[docs] def i_inc(self, op):
size = op.opers[0].tsize
val = self.getOperValue(op, 0)
sval = e_bits.signed(val, size)
sval += 1
self.setOperValue(op, 0, sval)
# Another arithmetic op where doing signed and unsigned is easier ;)
self.setFlag(EFLAGS_OF, e_bits.is_signed_overflow(sval, size))
self.setFlag(EFLAGS_SF, e_bits.is_signed(sval, size))
self.setFlag(EFLAGS_ZF, not sval)
self.setFlag(EFLAGS_AF, (sval & 0xf == 0))
self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(sval))
[docs] def i_int(self, op):
raise envi.UnsupportedInstruction(self, op)
[docs] def i_int3(self, op):
raise envi.BreakpointHit(self)
[docs] def i_lea(self, op):
base = self.getOperAddr(op, 1)
self.setOperValue(op, 0, base)
[docs] def decCounter(self):
"""
A helper to decrement and return the counter
"""
ecx = self.getRegister(REG_ECX)
ecx -= 1
self.setRegister(REG_ECX, ecx)
return ecx
[docs] def i_lodsb(self, op):
esi = self.getRegister(REG_ESI)
newal = self.readMemoryFormat(esi, "<B")[0]
self.setRegister(REG_AL, newal)
if not self.getFlag(EFLAGS_DF):
esi += 1
else:
esi -= 1
self.setRegister(REG_ESI, esi)
[docs] def i_lodsd(self, op):
esi = self.getRegister(REG_ESI)
neweax = self.readMemoryFormat(esi, "<L")[0]
#FIXME figgure out ADDR_SIZE vs OP_SIZE and which is which
self.setRegister(REG_EAX, neweax)
if not self.getFlag(EFLAGS_DF):
esi += 4
else:
esi -= 4
self.setRegister(REG_ESI, esi)
[docs] def i_loop(self, op):
if self.decCounter() != 0:
return self.getOperValue(op, 0)
[docs] def i_loopz(self, op):
if self.decCounter() != 0 and self.cond_e():
return self.getOperValue(op, 0)
[docs] def i_loopnz(self, op):
if self.decCounter() != 0 and self.cond_ne():
return self.getOperValue(op, 0)
i_loope = i_loopz
i_loopne = i_loopnz
[docs] def i_leave(self, op):
ebp = self.getRegister(REG_EBP)
self.setRegister(REG_ESP, ebp)
self.setRegister(REG_EBP, self.doPop())
[docs] def i_mov(self, op):
val = self.getOperValue(op, 1)
self.setOperValue(op, 0, val)
[docs] def i_movq(self, op):
val = self.getOperValue(op, 1)
self.setOperValue(op, 0, val)
[docs] def i_movsb(self, op):
esi = self.getRegister(REG_ESI)
edi = self.getRegister(REG_EDI)
bytes = self.readMemory(esi, 1)
self.writeMemory(edi, bytes)
if self.getFlag(EFLAGS_DF):
self.setRegister(REG_ESI, esi-1)
self.setRegister(REG_EDI, edi-1)
else:
self.setRegister(REG_ESI, esi+1)
self.setRegister(REG_EDI, edi+1)
[docs] def i_movsd(self, op):
esi = self.getRegister(REG_ESI)
edi = self.getRegister(REG_EDI)
bytes = self.readMemory(esi, 4)
self.writeMemory(edi, bytes)
if self.getFlag(EFLAGS_DF):
self.setRegister(REG_ESI, esi-4)
self.setRegister(REG_EDI, edi-4)
else:
self.setRegister(REG_ESI, esi+4)
self.setRegister(REG_EDI, edi+4)
[docs] def i_movsx(self, op):
osize = op.opers[1].tsize
nsize = op.opers[0].tsize
val = self.getOperValue(op, 1)
val = e_bits.sign_extend(val, osize, nsize)
self.setOperValue(op, 0, val)
[docs] def i_movzx(self, op):
val = self.getOperValue(op, 1)
self.setOperValue(op, 0, val)
[docs] def i_mul(self, op):
#FIXME make sure these work right
tsize = op.opers[0].tsize
val = self.getOperValue(op, 0)
# Return al/ax/eax as needed...
a = self._emu_getGpReg(GPR_A, tsize)
res = a * val
if tsize == 1:
self.setRegister(REG_AX, res)
elif tsize == 2:
d,a = self.regsFromCompound(res, tsize)
self._emu_setGpReg(GPR_A, a, tsize)
self._emu_setGpReg(GPR_D, d, tsize)
# If the high order stuff was used, set CF/OF
if res >> (tsize * 8):
self.setFlag(EFLAGS_CF, True)
self.setFlag(EFLAGS_OF, True)
else:
self.setFlag(EFLAGS_CF, False)
self.setFlag(EFLAGS_OF, False)
def _emu_setGpReg(self, reg, val, tsize):
"""
Automagically map all general purpose register accesses
to their tsize equiv. Helps clean up a lot of code
(and makes a nice place for AMD64 to hook ;) )
"""
if tsize == 1:
reg += 0x00080000
elif tsize == 2:
reg += 0x00100000
self.setRegister(reg, value)
def _emu_getGpReg(self, reg, tsize):
"""
Automagically map all general purpose register accesses
to their tsize equiv. Helps clean up a lot of code
(and makes a nice place for AMD64 to hook ;) )
"""
if tsize == 1:
reg += 0x00080000
elif tsize == 2:
reg += 0x00100000
return self.getRegister(reg)
[docs] def i_neg(self, op):
tsize = op.opers[0].tsize
val = self.getOperValue(op, 0)
res = 0 - val
self.setOperValue(op, 0, res)
self.setFlag(EFLAGS_CF, val != 0)
self.setFlag(EFLAGS_ZF, not res)
self.setFlag(EFLAGS_SF, e_bits.is_signed(res, tsize))
#FIXME how does neg cause/not cause a carry?
self.setFlag(EFLAGS_AF, 0) # FIXME EFLAGS_AF
[docs] def i_nop(self, op):
pass
[docs] def i_not(self, op):
val = self.getOperValue(op, 0)
val ^= e_bits.u_maxes[op.opers[0].tsize]
self.setOperValue(op, 0, val)
[docs] def i_or(self, op):
dst = self.getOperValue(op, 0)
dsize = op.opers[0].tsize
src = self.getOperValue(op, 1)
ssize = op.opers[1].tsize
if dsize != ssize:
src = e_bits.sign_extend(src, ssize, dsize)
ssize = dsize
res = dst | src
self.setOperValue(op, 0, res)
self.setFlag(EFLAGS_OF, 0)
self.setFlag(EFLAGS_CF, 0)
self.setFlag(EFLAGS_SF, e_bits.is_signed(res, dsize))
self.setFlag(EFLAGS_ZF, not res)
self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(res))
[docs] def i_pop(self, op):
val = self.doPop()
self.setOperValue(op, 0, val)
[docs] def i_popad(self, op):
#FIXME 16 bit?
self.setRegister(REG_EDI, self.doPop())
self.setRegister(REG_ESI, self.doPop())
self.setRegister(REG_EBP, self.doPop())
self.doPop() # skip one
self.setRegister(REG_EBX, self.doPop())
self.setRegister(REG_EDX, self.doPop())
self.setRegister(REG_ECX, self.doPop())
self.setRegister(REG_EAX, self.doPop())
[docs] def i_popfd(self, op):
eflags = self.doPop()
self.setRegister(REG_EFLAGS, eflags)
[docs] def i_push(self, op):
val = self.getOperValue(op, 0)
if isinstance(op.opers[0], i386ImmOper):
val = e_bits.sign_extend(val, op.opers[0].tsize, 4) #FIXME 64bit
self.doPush(val)
[docs] def i_pushad(self, op):
tmp = self.getRegister(REG_ESP)
self.doPush(self.getRegister(REG_EAX))
self.doPush(self.getRegister(REG_ECX))
self.doPush(self.getRegister(REG_EDX))
self.doPush(self.getRegister(REG_EBX))
self.doPush(tmp)
self.doPush(self.getRegister(REG_EBP))
self.doPush(self.getRegister(REG_ESI))
self.doPush(self.getRegister(REG_EDI))
[docs] def i_pushfd(self, op):
eflags = self.getRegister(REG_EFLAGS)
self.doPush(eflags)
[docs] def i_jmp(self, op):
return self.getOperValue(op, 0)
# We include all the possible Jcc names just in case somebody
# gets hinkey with the disassembler.
[docs] def i_ja(self, op):
if self.cond_a(): return self.getOperValue(op, 0)
[docs] def i_jae(self, op):
if self.cond_ae(): return self.getOperValue(op, 0)
[docs] def i_jb(self, op):
if self.cond_b(): return self.getOperValue(op, 0)
[docs] def i_jbe(self, op):
if self.cond_be(): return self.getOperValue(op, 0)
[docs] def i_jc(self, op):
if self.cond_c(): return self.getOperValue(op, 0)
[docs] def i_jecxz(self, op):
if self.cond_ecxz(): return self.getOperValue(op, 0)
[docs] def i_je(self, op):
if self.cond_e(): return self.getOperValue(op, 0)
[docs] def i_jg(self, op):
if self.cond_g(): return self.getOperValue(op, 0)
[docs] def i_jge(self, op):
if self.cond_ge(): return self.getOperValue(op, 0)
[docs] def i_jl(self, op):
if self.cond_l(): return self.getOperValue(op, 0)
[docs] def i_jle(self, op):
if self.cond_le(): return self.getOperValue(op, 0)
i_jna = i_jbe
i_jnae = i_jb
i_jnb = i_jae
i_jnbe = i_ja
i_jnc = i_jae
[docs] def i_jne(self, op):
if self.cond_ne(): return self.getOperValue(op, 0)
i_jng = i_jle
i_jnge = i_jl
i_jnl = i_jge
i_jnle = i_jg
[docs] def i_jno(self, op):
if self.cond_no(): return self.getOperValue(op, 0)
[docs] def i_jnp(self, op):
if self.cond_np(): return self.getOperValue(op, 0)
[docs] def i_jns(self, op):
if self.cond_ns(): return self.getOperValue(op, 0)
i_jnz = i_jne
[docs] def i_jo(self, op):
if self.cond_o(): return self.getOperValue(op, 0)
[docs] def i_jp(self, op):
if self.cond_p(): return self.getOperValue(op, 0)
i_jpe = i_jp
i_jpo = i_jnp
[docs] def i_js(self, op):
if self.cond_s(): return self.getOperValue(op, 0)
i_jz = i_je
[docs] def i_rcl(self, op):
dsize = op.opers[0].tsize
dst = self.getOperValue(op, 0)
src = self.getOperValue(op, 1)
src = src & 0x1f
# Put that carry bit up there.
if self.getFlag(EFLAGS_CF):
dst = dst | (1 << (8 * dsize))
# Add one to account for carry
x = ((8*dsize) - src) + 1
#FIXME is this the one that can end up negative?
res = (dst << src) | (dst >> x)
cf = (res >> (8*dsize)) & 1
res = e_bits.unsigned(res, dsize)
self.setFlag(EFLAGS_CF, cf)
if src == 1:
m1 = e_bits.msb(res, dsize)
m2 = e_bits.msb(res << 1, dsize)
self.setFlag(EFLAGS_OF, m1 ^ m2)
self.setOperValue(op, 0, res)
[docs] def i_rcr(self, op):
dsize = op.opers[0].tsize
dst = self.getOperValue(op, 0)
src = self.getOperValue(op, 1)
src = src & 0x1f
# Put that carry bit up there.
if self.getFlag(EFLAGS_CF):
dst = dst | (1 << (8 * dsize))
# Add one to account for carry
x = ((8*dsize) - src) + 1
res = (dst >> src) | (dst << x)
cf = (res >> (8*dsize)) & 1
res = e_bits.unsigned(res, dsize)
self.setFlag(EFLAGS_CF, cf)
if src == 1:
m1 = e_bits.msb(res, dsize)
m2 = e_bits.msb(res << 1, dsize)
self.setFlag(EFLAGS_OF, m1 ^ m2)
self.setOperValue(op, 0, res)
[docs] def i_rdtsc(self, op):
"""
Read the clock cycle counter into edx:eax
"""
self.setRegister(REG_EDX, 0)
self.setRegister(REG_EAX, 0x414141)
[docs] def i_rol(self, op):
dstSize = op.opers[0].tsize
count = self.getOperValue(op, 1)
tempCount = shiftMask(count, dstSize)
if tempCount > 0: # Yeah, i know...weird. See the intel manual
while tempCount:
val = self.getOperValue(op, 0)
tempCf = e_bits.msb(val, dstSize)
self.setOperValue(op, 0, (val * 2) + tempCf)
tempCount -= 1
val = self.getOperValue(op, 0)
self.setFlag(EFLAGS_CF, e_bits.lsb(val))
if count == 1:
val = self.getOperValue(op, 0)
cf = self.getFlag(EFLAGS_CF)
self.setFlag(EFLAGS_OF, e_bits.msb(val, dstSize) ^ cf)
else:
self.setFlag(EFLAGS_OF, False)
[docs] def i_ror(self, op):
dstSize = op.opers[0].tsize
count = self.getOperValue(op, 1)
tempCount = shiftMask(count, dstSize)
if tempCount > 0: # Yeah, i know...weird. See the intel manual
while tempCount:
val = self.getOperValue(op, 0)
tempCf = e_bits.lsb(val)
self.setOperValue(op, 0, (val / 2) + (tempCf * (2 ** dstSize)))
tempCount -= 1
val = self.getOperValue(op, 0)
self.setFlag(EFLAGS_CF, e_bits.msb(val, dstSize))
if count == 1:
val = self.getOperValue(op, 0)
cf = self.getFlag(EFLAGS_CF)
# FIXME: This may be broke...the manual is kinda flaky here
self.setFlag(EFLAGS_OF, e_bits.msb(val, dstSize) ^ (e_bits.msb(val, dstSize) - 1))
else:
self.setFlag(EFLAGS_OF, False)
[docs] def i_ret(self, op):
ret = self.doPop()
if len(op.opers):
esp = self.getRegister(REG_ESP)
ival = self.getOperValue(op, 0)
self.setRegister(REG_ESP, esp+ival)
return ret
[docs] def i_sal(self, op):
dsize = op.opers[0].tsize
dst = self.getOperValue(op, 0)
src = self.getOperValue(op, 1)
src = src & 0x1f
# According to intel manual, if src == 0 eflags are not changed
if src == 0:
return
res = dst << src
cf = (res >> 8*dsize) & 1
res = e_bits.unsigned(res, dsize)
self.setFlag(EFLAGS_CF, cf)
self.setFlag(EFLAGS_SF, e_bits.is_signed(res, dsize))
self.setFlag(EFLAGS_ZF, not res)
self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(res))
if src == 1:
self.setFlag(EFLAGS_OF, not e_bits.msb(res, dsize) == cf)
else:
self.setFlag(EFLAGS_OF, 0) # Undefined, but zero'd on core2 duo
self.setOperValue(op, 0, res)
[docs] def i_sar(self, op):
dsize = op.opers[0].tsize
dst = self.getOperValue(op, 0)
src = self.getOperValue(op, 1)
src = src & 0x1f
# According to intel manual, if src == 0 eflags are not changed
if src == 0:
return
signed = e_bits.msb(dst, dsize)
res = dst >> src
cf = (dst >> (src-1)) & 1
# If it was signed, we need to fill in all those bits we
# shifted off with ones.
if signed:
x = (8*dsize) - src
umax = e_bits.u_maxes[dsize]
res |= (umax >> x) << x
res = e_bits.unsigned(res, dsize)
self.setFlag(EFLAGS_CF, cf)
self.setFlag(EFLAGS_SF, e_bits.is_signed(res, dsize))
self.setFlag(EFLAGS_ZF, not res)
self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(res))
if src == 1:
self.setFlag(EFLAGS_OF, False)
else:
self.setFlag(EFLAGS_OF, 0) # Undefined, but zero'd on core2 duo
self.setOperValue(op, 0, res)
[docs] def i_shl(self, op):
return self.i_sal(op)
[docs] def i_shr(self, op):
dsize = op.opers[0].tsize
dst = self.getOperValue(op, 0)
src = self.getOperValue(op, 1)
src = src & 0x1f
# According to intel manual, if src == 0 eflags are not changed
if src == 0:
return
res = dst >> src
cf = (dst >> (src-1)) & 1
res = e_bits.unsigned(res, dsize)
self.setFlag(EFLAGS_CF, cf)
self.setFlag(EFLAGS_SF, e_bits.is_signed(res, dsize))
self.setFlag(EFLAGS_ZF, not res)
self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(res))
if src == 1:
self.setFlag(EFLAGS_OF, False)
else:
self.setFlag(EFLAGS_OF, 0) # Undefined, but zero'd on core2 duo
self.setOperValue(op, 0, res)
[docs] def i_shrd(self, op):
dsize = op.opers[0].tsize
bsize = dsize * 8
dst = self.getOperValue(op, 0)
src = self.getOperValue(op, 1)
cnt = self.getOperValue(op, 2)
cnt &= 0x1f # Reg gets masked down
if cnt == 0:
return
if cnt > bsize:
# result is "undfined"
return
res = dst >> cnt
res |= src << (bsize - cnt)
# We now have the bits masked into res, but it has become
# wider than the original operand.
# Ret is masked down to size
ret = e_bits.unsigned(res, dsize)
if cnt == 1: # Set OF on sign change
dsign = e_bits.is_signed(dst, dsize)
rsign = e_bits.is_signed(ret, dsize)
self.setFlag(EFLAGS_OF, dsign != rsign)
# set carry to last shifted bit
self.setFlag(EFLAGS_CF, (res << bsize) & 1)
self.setFlag(EFLAGS_SF, e_bits.is_signed(ret, dsize))
self.setFlag(EFLAGS_ZF, not ret)
self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(ret))
self.setOperValue(op, 0, ret)
[docs] def i_shld(self, op):
dsize = op.opers[0].tsize
bsize = dsize * 8
dst = self.getOperValue(op, 0)
src = self.getOperValue(op, 1)
cnt = self.getOperValue(op, 2)
cnt &= 0x1f # Reg gets masked down
if cnt == 0:
return
if cnt > bsize:
return
res = dst << cnt
res |= src >> (bsize - cnt)
ret = e_bits.unsigned(res, dsize)
if cnt == 1: # Set OF on sign change
dsign = e_bits.is_signed(dst, dsize)
rsign = e_bits.is_signed(ret, dsize)
self.setFlag(EFLAGS_OF, dsign != rsign)
# set carry to last shifted bit
self.setFlag(EFLAGS_CF, (dst << (cnt-1)) & 1)
self.setFlag(EFLAGS_SF, e_bits.is_signed(ret, dsize))
self.setFlag(EFLAGS_ZF, not ret)
self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(ret))
self.setOperValue(op, 0, ret)
[docs] def i_scasb(self, op):
al = self.getRegister(REG_AL)
edi = self.getRegister(REG_EDI)
base,size = self._emu_segments[SEG_ES]
memval = ord(self.readMemory(base+edi, 1))
self.intSubBase(al, memval, 1, 1)
if self.getFlag(EFLAGS_DF):
edi -= 1
else:
edi += 1
self.setRegister(REG_EDI, edi)
[docs] def i_scasd(self, op):
#FIXME probably need to handle oper prefix by hand here...
eax = self.getRegister(REG_EAX)
edi = self.getRegister(REG_EDI)
base,size = self._emu_segments[SEG_ES]
memval = struct.unpack("<L",self.readMemory(base+edi, 4))[0]
self.intSubBase(eax, memval, 4, 4)
if self.getFlag(EFLAGS_DF):
edi -= 4
else:
edi += 4
self.setRegister(REG_EDI, edi)
[docs] def i_stosb(self, op):
al = self.getRegister(REG_AL)
edi = self.getRegister(REG_EDI)
base,size = self._emu_segments[SEG_ES]
self.writeMemory(base+edi, chr(al))
if self.getFlag(EFLAGS_DF):
edi -= 1
else:
edi += 1
self.setRegister(REG_EDI, edi)
def i_stosd(self, op):
eax = self.getRegister(REG_EAX)
edi = self.getRegister(REG_EDI)
base,size = self._emu_segments[SEG_ES]
self.writeMemory(base+edi, struct.pack("<L", eax))
if self.getFlag(EFLAGS_DF):
edi -= 4
else:
edi += 4
self.setRegister(REG_EDI, edi)
# We include all the possible SETcc names just in case somebody
# gets hinkey with the disassembler.
[docs] def i_seta(self, op): self.setOperValue(op, 0, int(self.cond_a()))
[docs] def i_setae(self, op): self.setOperValue(op, 0, int(self.cond_ae()))
[docs] def i_setb(self, op): self.setOperValue(op, 0, int(self.cond_b()))
[docs] def i_setbe(self, op): self.setOperValue(op, 0, int(self.cond_be()))
[docs] def i_setc(self, op): self.setOperValue(op, 0, int(self.cond_c()))
[docs] def i_setecxz(self, op): self.setOperValue(op, 0, int(self.cond_ecxz()))
[docs] def i_sete(self, op): self.setOperValue(op, 0, int(self.cond_e()))
[docs] def i_setg(self, op): self.setOperValue(op, 0, int(self.cond_g()))
[docs] def i_setge(self, op): self.setOperValue(op, 0, int(self.cond_ge()))
[docs] def i_setl(self, op): self.setOperValue(op, 0, int(self.cond_l()))
[docs] def i_setle(self, op): self.setOperValue(op, 0, int(self.cond_le()))
i_setna = i_setbe
i_setnae = i_setb
i_setnb = i_setae
i_setnbe = i_seta
i_setnc = i_setae
[docs] def i_setne(self, op): self.setOperValue(op, 0, int(self.cond_ne()))
i_setng = i_setle
i_setnge = i_setl
i_setnl = i_setge
i_setnle = i_setg
[docs] def i_setno(self, op): self.setOperValue(op, 0, int(self.cond_no()))
[docs] def i_setnp(self, op): self.setOperValue(op, 0, int(self.cond_np()))
[docs] def i_setns(self, op): self.setOperValue(op, 0, int(self.cond_ns()))
i_setnz = i_setne
[docs] def i_seto(self, op): self.setOperValue(op, 0, int(self.cond_o()))
[docs] def i_setp(self, op): self.setOperValue(op, 0, int(self.cond_p()))
i_setpe = i_setp
i_setpo = i_setnp
[docs] def i_sets(self, op): self.setOperValue(op, 0, int(self.cond_s()))
i_setz = i_sete
[docs] def i_sbb(self, op):
dst = self.getOperValue(op, 0)
src = self.getOperValue(op, 1)
# Much like "integer subtraction" but we need
# too add in the carry flag
if src == None or dst == None:
self.undefFlags()
return None
dsize = op.opers[0].tsize
ssize = op.opers[1].tsize
# Sign extend immediates where the sizes don't match
if dsize != ssize:
src = e_bits.sign_extend(src, ssize, dsize)
ssize = dsize
src += self.getFlag(EFLAGS_CF)
res = self.intSubBase(src, dst, ssize, dsize)
self.setOperValue(op, 0, res)
# FIXME scas stuff goes here
# FIXME conditional byte set goes here
[docs] def i_stc(self, op):
self.setFlag(EFLAGS_CF, True)
[docs] def i_std(self, op):
self.setFlag(EFLAGS_DF, True)
[docs] def i_sti(self, op):
self.setFlag(EFLAGS_IF, True)
# FIXME stos variants go here
[docs] def i_stosd(self, op):
eax = self.getRegister(REG_EAX)
edi = self.getRegister(REG_EDI)
# FIXME shouldn't have to do this directly
# FIXME this needs a 32/16 bit mode check
base,size = self._emu_segments[SEG_ES]
self.writeMemValue(base+edi, eax, 4)
# FIXME edi inc must be by oper len
self.setRegister(REG_EDI, edi+4)
[docs] def i_sub(self, op):
x = self.integerSubtraction(op)
if x != None:
self.setOperValue(op, 0, x)
[docs] def i_test(self, op):
self.logicalAnd(op)
[docs] def i_wait(self, op):
print "i_wait() is a stub..."
[docs] def i_xadd(self, op):
val1 = self.getOperValue(op, 0)
val2 = self.getOperValue(op, 1)
temp = val1 + val2
self.setOperValue(op, 1, val1)
self.setOperValue(op, 0, temp)
[docs] def i_xchg(self, op):
temp = self.getOperValue(op, 0)
self.setOperValue(op, 0, self.getOperValue(op, 1))
self.setOperValue(op, 1, temp)
[docs] def i_xor(self, op):
dsize = op.opers[0].tsize
ssize = op.opers[1].tsize
dst = self.getOperValue(op, 0)
src = self.getOperValue(op, 1)
ret = src ^ dst
self.setOperValue(op, 0, ret)
self.setFlag(EFLAGS_CF, 0)
self.setFlag(EFLAGS_OF, 0)
self.setFlag(EFLAGS_SF, e_bits.is_signed(ret, dsize))
self.setFlag(EFLAGS_ZF, not ret)
self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(ret))
self.setFlag(EFLAGS_AF, False) # Undefined but actually cleared on amd64 X2
[docs] def i_pxor(self, op):
return self.i_xor(op)