Add PCMPXSTRX Instructions (#507)

* Add PCMPXSTRX Instructions

* bug fixes

* unittest related fixes

* Full test of pcmpxstrx

* Move tests
This commit is contained in:
HighW4y2H3ll
2017-11-14 14:39:51 -05:00
committed by feliam
parent 94d2e94bf1
commit 8002a1d682
6 changed files with 34497 additions and 5 deletions

View File

@@ -13,7 +13,7 @@ from .abstractcpu import (
from ..smtlib import Operators, BitVec, Bool, BitVecConstant, operator, visitors
from ..memory import MemoryException
from ..memory import MemoryException, ConcretizeMemory
from ...utils.helpers import issymbolic
logger = logging.getLogger(__name__)
@@ -597,6 +597,9 @@ class AMD64RegFile(RegisterFile):
self._cache[name] = value
return value
def sizeof(self, reg):
return self._table[reg].size
###########################
# Operand Wrapper
class AMD64Operand(Operand):
@@ -4880,6 +4883,224 @@ class X86Cpu(Cpu):
# res = res | (0xff << i)
op0.write(res)
############################################################################
# Implementation of PCMPxSTRx Instructions:
# + PCMPESTRM, PCMPESTRI, PCMPISTRM, PCMPISTRI
##
# '''
# See Ref: https://software.intel.com/sites/default/files/m/8/b/8/D9156103.pdf
# :param cpu: current CPU.
# :param op0: compare oprand 1
# :param op1: compare oprand 2
# :param op2: control byte
# - op2[3:2] :
# + 00: Equal Any
# + 01: Ranges
# + 10: Equal Each
# + 11: Equal Ordered
# '''
#############################################################################
def _pcmpxstrx_srcdat_format(self, ctlbyte):
# Parse CTL Byte
## Source Data Format
if ((Operators.EXTRACT(ctlbyte, 0, 2) & 1) == 0 ):
stepsize = 8
else:
stepsize = 16
return stepsize
def _pcmpxstri_output_selection(self, ctlbyte, res):
## Output Selection
### PCMPESTRI/PCMPISTRI
stepsize = self._pcmpxstrx_srcdat_format(ctlbyte)
if (Operators.EXTRACT(ctlbyte, 6, 1) == 0):
oecx = 0
tres = res
while ((tres & 1) == 0):
oecx += 1
tres >>= 1
return oecx
else:
oecx = 128/stepsize - 1
tres = res
msbmask = (1 << (128/stepsize - 1))
while ((tres & msbmask) == 0):
oecx -= 1
tres = (tres << 1) & ((msbmask << 1) - 1)
return oecx
def _pcmpxstrm_output_selection(self, ctlbyte, res):
## Output Selection
### PCMPESTRM/PCMPISTRM
if (Operators.EXTRACT(ctlbyte, 6, 1) == 0):
return res
else:
stepsize = self._pcmpxstrx_srcdat_format(ctlbyte)
xmmres = 0
for i in range(0, 128, stepsize):
if (res&1 == 1):
xmmres |= (((1 << stepsize) - 1) << i)
res >>= 1
return xmmres
def _pcmpistrx_varg(self, arg, ctlbyte):
step = self._pcmpxstrx_srcdat_format(ctlbyte)
result = []
for i in range(0, 128, step):
uc = Operators.EXTRACT(arg, i, step)
if uc == 0:
break
result.append(uc)
return result
def _pcmpestrx_varg(self, arg, regname, ctlbyte):
reg = self.read_register(regname)
if (issymbolic(reg)):
raise ConcretizeRegister(self, regname, "Concretize PCMPESTRx ECX/EDX")
smask = 1 << (self.regfile.sizeof(regname) - 1)
step = self._pcmpxstrx_srcdat_format(ctlbyte)
if (reg & smask == 1):
val = Operators.NOT(reg - 1)
else:
val = reg
if (val > 128/step):
val = 128/step
result = []
for i in range(val):
uc = Operators.EXTRACT(arg, i*step, step)
result.append(uc)
return result
def _pcmpxstrx_aggregation_operation(self, varg0, varg1, ctlbyte):
##
needle = [e for e in varg0]
haystack = [e for e in varg1]
## Aggregation Operation
res = 0
stepsize = self._pcmpxstrx_srcdat_format(ctlbyte)
xmmsize = 128
if (Operators.EXTRACT(ctlbyte, 2, 2) == 0):
#raise NotImplementedError("pcmpistrx Equal any")
for i in range(len(haystack)):
if haystack[i] in needle:
res |= (1 << i)
elif (Operators.EXTRACT(ctlbyte, 2, 2) == 1):
#raise NotImplementedError("pcmpistrx Ranges")
assert len(needle)%2 == 0
for i in range(len(haystack)):
for j in range(0, len(needle), 2):
if haystack[i] >= needle[j] and haystack[i] <= needle[j+1]:
res |= (1 << i)
break
elif (Operators.EXTRACT(ctlbyte, 2, 2) == 2):
#raise NotImplementedError("pcmpistrx Equal each")
# Equal Each requires Null Byte Comparison Here
while len(needle) < xmmsize/stepsize:
needle.append('\x00')
while len(haystack) < xmmsize/stepsize:
haystack.append('\x00')
for i in range(xmmsize/stepsize):
res = Operators.ITEBV(xmmsize, needle[i] == haystack[i], res|(1 << i), res)
elif (Operators.EXTRACT(ctlbyte, 2, 2) == 3):
#raise NotImplementedError("pcmpistrx Equal ordered")
if len(haystack) < len(needle):
return 0
for i in range(len(haystack)):
subneedle = needle[: (xmmsize/stepsize - i) if len(needle)+i > xmmsize/stepsize else len(needle)]
res = Operators.ITEBV(xmmsize, haystack[i:i+len(subneedle)] == subneedle, res|(1 << i), res)
return res
def _pcmpxstrx_polarity(self, res1, ctlbyte, arg2len):
## Polarity
stepsize = self._pcmpxstrx_srcdat_format(ctlbyte)
if (Operators.EXTRACT(ctlbyte, 4, 2) == 0):
res2 = res1
pass
if (Operators.EXTRACT(ctlbyte, 4, 2) == 1):
res2 = ((1 << (128/stepsize)) - 1) ^ res1
if (Operators.EXTRACT(ctlbyte, 4, 2) == 2):
res2 = res1
pass
if (Operators.EXTRACT(ctlbyte, 4, 2) == 3):
res2 = ((1 << arg2len) - 1) ^ res1
pass
return res2
def _pcmpxstrx_setflags(self, res, varg0, varg1, ctlbyte):
stepsize = self._pcmpxstrx_srcdat_format(ctlbyte)
self.ZF = len(varg1) < 128/stepsize
self.SF = len(varg0) < 128/stepsize
self.CF = res != 0
self.OF = res & 1
self.AF = False
self.PF = False
def _pcmpxstrx_operands(self, op0, op1, op2):
arg0 = op0.read()
arg1 = op1.read()
ctlbyte = op2.read()
if (issymbolic(arg0)):
# XMM Register
assert op0.type == 'register'
raise ConcretizeRegister(self, op0.reg, "Concretize for PCMPXSTRX")
if (issymbolic(arg1)):
if (op1.type == 'register'):
# XMM Register
raise ConcretizeRegister(self, op1.reg, "Concretize for PCMPXSTRX")
else:
# Memory
raise ConcretizeMemory(self.memory, op1.address(), op0.size)
assert(not issymbolic(ctlbyte))
return (arg0, arg1, ctlbyte)
@instruction
def PCMPISTRI(cpu, op0, op1, op2):
arg0, arg1, ctlbyte = cpu._pcmpxstrx_operands(op0, op1, op2)
varg0 = cpu._pcmpistrx_varg(arg0, ctlbyte)
varg1 = cpu._pcmpistrx_varg(arg1, ctlbyte)
res = cpu._pcmpxstrx_aggregation_operation(varg0, varg1, ctlbyte)
res = cpu._pcmpxstrx_polarity(res, ctlbyte, len(varg1))
if (res == 0):
cpu.ECX = 128/cpu._pcmpxstrx_srcdat_format(ctlbyte)
else:
cpu.ECX = cpu._pcmpxstri_output_selection(ctlbyte, res)
cpu._pcmpxstrx_setflags(res, varg0, varg1, ctlbyte)
@instruction
def PCMPISTRM(cpu, op0, op1, op2):
arg0, arg1, ctlbyte = cpu._pcmpxstrx_operands(op0, op1, op2)
varg0 = cpu._pcmpistrx_varg(arg0, ctlbyte)
varg1 = cpu._pcmpistrx_varg(arg1, ctlbyte)
res = cpu._pcmpxstrx_aggregation_operation(varg0, varg1, ctlbyte)
res = cpu._pcmpxstrx_polarity(res, ctlbyte, len(varg1))
cpu.XMM0 = cpu._pcmpxstrm_output_selection(ctlbyte, res)
cpu._pcmpxstrx_setflags(res, varg0, varg1, ctlbyte)
@instruction
def PCMPESTRI(cpu, op0, op1, op2):
arg0, arg1, ctlbyte = cpu._pcmpxstrx_operands(op0, op1, op2)
varg0 = cpu._pcmpestrx_varg(arg0, 'EAX', ctlbyte)
varg1 = cpu._pcmpestrx_varg(arg1, 'EDX', ctlbyte)
res = cpu._pcmpxstrx_aggregation_operation(varg0, varg1, ctlbyte)
res = cpu._pcmpxstrx_polarity(res, ctlbyte, len(varg1))
if (res == 0):
cpu.ECX = 128/cpu._pcmpxstrx_srcdat_format(ctlbyte)
else:
cpu.ECX = cpu._pcmpxstri_output_selection(ctlbyte, res)
cpu._pcmpxstrx_setflags(res, varg0, varg1, ctlbyte)
@instruction
def PCMPESTRM(cpu, op0, op1, op2):
arg0, arg1, ctlbyte = cpu._pcmpxstrx_operands(op0, op1, op2)
varg0 = cpu._pcmpestrx_varg(arg0, 'EAX', ctlbyte)
varg1 = cpu._pcmpestrx_varg(arg1, 'EDX', ctlbyte)
res = cpu._pcmpxstrx_aggregation_operation(varg0, varg1, ctlbyte)
res = cpu._pcmpxstrx_polarity(res, ctlbyte, len(varg1))
cpu.XMM0 = cpu._pcmpxstrm_output_selection(ctlbyte, res)
cpu._pcmpxstrx_setflags(res, varg0, varg1, ctlbyte)
@instruction
def PMOVMSKB(cpu, op0, op1):
'''

View File

@@ -139,7 +139,7 @@ class State(Eventful):
except ConcretizeMemory as e:
expression = self.cpu.read_int(e.address, e.size)
def setstate(state, value):
state.cpu.write_int(e.reg_name, value, e.size)
state.cpu.write_int(e.address, value, e.size)
raise Concretize(e.message,
expression=expression,
setstate=setstate,

View File

@@ -16,6 +16,8 @@ for test in tests:
cnt = op_count.get(test['mnemonic'],0)
if cnt > 1000: #No more than 1000 instructions of each kind
continue
if test['mnemonic'] != 'PCMPISTRI' and test['mnemonic'] != 'PCMPISTRM' and test['mnemonic'] != 'PCMPESTRI' and test['mnemonic'] != 'PCMPESTRM':
continue
op_count[test['mnemonic']] = cnt+1
test_dic["%s_%d"%(test['mnemonic'], op_count[test['mnemonic']])] = test
except Exception,e:
@@ -216,6 +218,7 @@ for test_name in sorted(test_dic.keys()):
print """ cs.add(cpu.%s == 0x%x)"""%(reg_name, value)
pc_reg = 'RIP' if 'RIP' in test['pre']['registers'] else 'EIP'
print """
done = False
while not done:
@@ -226,8 +229,27 @@ for test_name in sorted(test_dic.keys()):
symbol = getattr(cpu, e.reg_name)
values = solver.get_all_values(cs, symbol)
self.assertEqual(len(values), 1)
setattr(cpu, e.reg_name, values[0])"""
setattr(cpu, e.reg_name, values[0])
setattr(cpu, '{PC}', {PC_VAL})""".format(
PC=pc_reg,
PC_VAL=hex(test['pre']['registers'][pc_reg]))
print """
except ConcretizeMemory,e:
symbol = getattr(cpu, '{FRAME_BASE}')
if isinstance(symbol, Expression):
values = solver.get_all_values(cs, symbol)
self.assertEqual(len(values), 1)
setattr(cpu, '{FRAME_BASE}', values[0])
for i in range(e.size):
symbol = mem[e.address+i]
if isinstance(symbol, Expression):
values = solver.get_all_values(cs, symbol)
self.assertEqual(len(values), 1)
mem[e.address+i] = values[0]
setattr(cpu, '{PC}', {PC_VAL})""".format(
FRAME_BASE='RBP' if 'RBP' in test['pre']['registers'] else 'EBP',
PC=pc_reg,
PC_VAL=hex(test['pre']['registers'][pc_reg]))
print """

View File

@@ -121,7 +121,7 @@ while True:
pc = gdb.getR({'i386': 'EIP', 'amd64': 'RIP'}[arch])
print hex(pc)
gdb.stepi()
print gdb.correspond('info registers')
print gdb.correspond('info registers\n')
except Exception,e:
print e
print "# Processed %d instructions." % count

34249
tests/test_x86_pcmpxstrx.py Normal file

File diff suppressed because it is too large Load Diff