diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index e2cb6a5d..fa50ad1f 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -9,7 +9,7 @@ import os.path import sys import weakref -from . import x86_const, unicorn_const as uc +from . import x86_const, arm64_const, unicorn_const as uc if not hasattr(sys.modules[__name__], "__file__"): __file__ = inspect.getfile(inspect.currentframe()) @@ -223,6 +223,13 @@ class uc_x86_xmm(ctypes.Structure): ("high_qword", ctypes.c_uint64), ] +class uc_arm64_neon128(ctypes.Structure): + """128-bit neon register""" + _fields_ = [ + ("low_qword", ctypes.c_uint64), + ("high_qword", ctypes.c_uint64), + ] + # Subclassing ref to allow property assignment. class UcRef(weakref.ref): pass @@ -317,6 +324,14 @@ class Uc(object): raise UcError(status) return reg.value + if self._arch == uc.UC_ARCH_ARM64: + if reg_id in range(arm64_const.UC_ARM64_REG_Q0, arm64_const.UC_ARM64_REG_Q31+1) or range(arm64_const.UC_ARM64_REG_V0, arm64_const.UC_ARM64_REG_V31+1): + reg = uc_arm64_neon128() + status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg)) + if status != uc.UC_ERR_OK: + raise UcError(status) + return reg.low_qword | (reg.high_qword << 64) + # read to 64bit number to be safe reg = ctypes.c_uint64(0) status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg)) @@ -349,6 +364,12 @@ class Uc(object): reg.rid = value[0] reg.value = value[1] + if self._arch == uc.UC_ARCH_ARM64: + if reg_id in range(arm64_const.UC_ARM64_REG_Q0, arm64_const.UC_ARM64_REG_Q31+1) or range(arm64_const.UC_ARM64_REG_V0, arm64_const.UC_ARM64_REG_V31+1): + reg = uc_arm64_neon128() + reg.low_qword = value & 0xffffffffffffffff + reg.high_qword = value >> 64 + if reg is None: # convert to 64bit number to be safe reg = ctypes.c_uint64(value) @@ -364,7 +385,7 @@ class Uc(object): # write to MSR - X86 only def msr_write(self, msr_id, value): return self.reg_write(x86_const.UC_X86_REG_MSR, (msr_id, value)) - + # read data from memory def mem_read(self, address, size): data = ctypes.create_string_buffer(size) diff --git a/qemu/target-arm/unicorn_aarch64.c b/qemu/target-arm/unicorn_aarch64.c index 9955b42e..5b9980f1 100644 --- a/qemu/target-arm/unicorn_aarch64.c +++ b/qemu/target-arm/unicorn_aarch64.c @@ -50,10 +50,27 @@ int arm64_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int co for (i = 0; i < count; i++) { unsigned int regid = regs[i]; void *value = vals[i]; + // V & Q registers are the same + if (regid >= UC_ARM64_REG_V0 && regid <= UC_ARM64_REG_V31) { + regid += UC_ARM64_REG_Q0 - UC_ARM64_REG_V0; + } if (regid >= UC_ARM64_REG_X0 && regid <= UC_ARM64_REG_X28) { *(int64_t *)value = ARM_CPU(uc, mycpu)->env.xregs[regid - UC_ARM64_REG_X0]; } else if (regid >= UC_ARM64_REG_W0 && regid <= UC_ARM64_REG_W30) { *(int32_t *)value = READ_DWORD(ARM_CPU(uc, mycpu)->env.xregs[regid - UC_ARM64_REG_W0]); + } else if (regid >= UC_ARM64_REG_Q0 && regid <= UC_ARM64_REG_Q31) { + float64 *dst = (float64*) value; + uint32_t reg_index = 2*(regid - UC_ARM64_REG_Q0); + dst[0] = ARM_CPU(uc, mycpu)->env.vfp.regs[reg_index]; + dst[1] = ARM_CPU(uc, mycpu)->env.vfp.regs[reg_index+1]; + } else if (regid >= UC_ARM64_REG_D0 && regid <= UC_ARM64_REG_D31) { + *(float64*)value = ARM_CPU(uc, mycpu)->env.vfp.regs[2*(regid - UC_ARM64_REG_D0)]; + } else if (regid >= UC_ARM64_REG_S0 && regid <= UC_ARM64_REG_S31) { + *(int32_t*)value = READ_DWORD(ARM_CPU(uc, mycpu)->env.vfp.regs[2*(regid - UC_ARM64_REG_S0)]); + } else if (regid >= UC_ARM64_REG_H0 && regid <= UC_ARM64_REG_H31) { + *(int16_t*)value = READ_WORD(ARM_CPU(uc, mycpu)->env.vfp.regs[2*(regid - UC_ARM64_REG_H0)]); + } else if (regid >= UC_ARM64_REG_B0 && regid <= UC_ARM64_REG_B31) { + *(int8_t*)value = READ_BYTE_L(ARM_CPU(uc, mycpu)->env.vfp.regs[2*(regid - UC_ARM64_REG_B0)]); } else { switch(regid) { default: break; @@ -84,10 +101,26 @@ int arm64_reg_write(struct uc_struct *uc, unsigned int *regs, void* const* vals, for (i = 0; i < count; i++) { unsigned int regid = regs[i]; const void *value = vals[i]; + if (regid >= UC_ARM64_REG_V0 && regid <= UC_ARM64_REG_V31) { + regid += UC_ARM64_REG_Q0 - UC_ARM64_REG_V0; + } if (regid >= UC_ARM64_REG_X0 && regid <= UC_ARM64_REG_X28) { ARM_CPU(uc, mycpu)->env.xregs[regid - UC_ARM64_REG_X0] = *(uint64_t *)value; } else if (regid >= UC_ARM64_REG_W0 && regid <= UC_ARM64_REG_W30) { WRITE_DWORD(ARM_CPU(uc, mycpu)->env.xregs[regid - UC_ARM64_REG_W0], *(uint32_t *)value); + } else if (regid >= UC_ARM64_REG_Q0 && regid <= UC_ARM64_REG_Q31) { + float64 *src = (float64*) value; + uint32_t reg_index = 2*(regid - UC_ARM64_REG_Q0); + ARM_CPU(uc, mycpu)->env.vfp.regs[reg_index] = src[0]; + ARM_CPU(uc, mycpu)->env.vfp.regs[reg_index+1] = src[1]; + } else if (regid >= UC_ARM64_REG_D0 && regid <= UC_ARM64_REG_D31) { + ARM_CPU(uc, mycpu)->env.vfp.regs[2*(regid - UC_ARM64_REG_D0)] = * (float64*) value; + } else if (regid >= UC_ARM64_REG_S0 && regid <= UC_ARM64_REG_S31) { + WRITE_DWORD(ARM_CPU(uc, mycpu)->env.vfp.regs[2*(regid - UC_ARM64_REG_S0)], *(int32_t*) value); + } else if (regid >= UC_ARM64_REG_H0 && regid <= UC_ARM64_REG_H31) { + WRITE_WORD(ARM_CPU(uc, mycpu)->env.vfp.regs[2*(regid - UC_ARM64_REG_H0)], *(int16_t*) value); + } else if (regid >= UC_ARM64_REG_B0 && regid <= UC_ARM64_REG_B31) { + WRITE_BYTE_L(ARM_CPU(uc, mycpu)->env.vfp.regs[2*(regid - UC_ARM64_REG_B0)], *(int8_t*) value); } else { switch(regid) { default: break;