From ff66a72d7b19b47c2e609be4bf06349652bc33cb Mon Sep 17 00:00:00 2001 From: feliam Date: Wed, 9 Mar 2016 18:07:38 -0300 Subject: [PATCH 1/5] GDT/LDT/IDT/FPU access from python bingings --- bindings/python/unicorn/unicorn.py | 50 ++++++++++++++++++++++++++++-- qemu/target-i386/unicorn.c | 39 +++++++++++++++++++++++ 2 files changed, 86 insertions(+), 3 deletions(-) diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index 989d985f..28ba7e77 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -156,6 +156,23 @@ def uc_arch_supported(query): return _uc.uc_arch_supported(query) + +class uc_x86_mmr(ctypes.Structure): + '''Memory-Management Register for instructions IDTR, GDTR, LDTR, TR.''' + _fields_ = [ + ("selector", ctypes.c_uint16), # not used by GDTR and IDTR + ("base", ctypes.c_uint64), # handle 32 or 64 bit CPUs + ("limit", ctypes.c_uint32), + ("flags", ctypes.c_uint32), # not used by GDTR and IDTR + ] + +class uc_x86_float80(ctypes.Structure): + '''Float80''' + _fields_ = [ + ("mantissa", ctypes.c_uint64), + ("exponent", ctypes.c_uint16), + ] + class Uc(object): def __init__(self, arch, mode): # verify version compatibility with the core before doing anything @@ -188,7 +205,6 @@ class Uc(object): except: # _uc might be pulled from under our feet pass - # emulate from @begin, and stop when reaching address @until def emu_start(self, begin, until, timeout=0, count=0): status = _uc.uc_emu_start(self._uch, begin, until, timeout, count) @@ -205,6 +221,20 @@ class Uc(object): # return the value of a register def reg_read(self, reg_id): + if self._arch == UC_ARCH_X86: + if reg_id in [ x86_const.UC_X86_REG_IDTR, x86_const.UC_X86_REG_GDTR, x86_const.UC_X86_REG_LDTR, x86_const.UC_X86_REG_TR]: + reg = uc_x86_mmr() + status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg)) + if status != UC_ERR_OK: + raise UcError(status) + return (reg.selector,reg.base, reg.limits, reg.flags) + if reg_id in range(x86_const.UC_X86_REG_FP0,x86_const.UC_X86_REG_FP0+8): + reg = uc_x86_float80() + status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg)) + if status != UC_ERR_OK: + raise UcError(status) + return (reg.mantissa, reg.exponent) + # read to 64bit number to be safe reg = ctypes.c_int64(0) status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg)) @@ -215,8 +245,22 @@ class Uc(object): # write to a register def reg_write(self, reg_id, value): - # convert to 64bit number to be safe - reg = ctypes.c_int64(value) + if self._arch == UC_ARCH_X86: + if reg_id in [ x86_const.UC_X86_REG_IDTR, x86_const.UC_X86_REG_GDTR, x86_const.UC_X86_REG_LDTR, x86_const.UC_X86_REG_TR]: + assert isinstance(value, tuple) and len(value)==4 + reg = uc_x86_mmr() + reg.selector=value[0] + reg.base=value[1] + reg.limits=value[2] + reg.flags=value[3] + if reg_id in range(x86_const.UC_X86_REG_FP0, x86_const.UC_X86_REG_FP0+8): + reg = uc_x86_float80() + reg.mantissa = value[0] + reg.exponent = value[1] + else: + # convert to 64bit number to be safe + reg = ctypes.c_int64(value) + status = _uc.uc_reg_write(self._uch, reg_id, ctypes.byref(reg)) if status != UC_ERR_OK: raise UcError(status) diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index 7ec2d140..3ab525c3 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -140,6 +140,25 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) { CPUState *mycpu = first_cpu; + switch(regid) { + default: + break; + case UC_X86_REG_FP0 ... UC_X86_REG_FP7: + { + floatx80 reg = X86_CPU(uc, mycpu)->env.fpregs[regid - UC_X86_REG_FP0].d; + cpu_get_fp80(value, value+sizeof(uint64_t), reg); + } + break; + case UC_X86_REG_FPSW: + { + uint16_t fpus = X86_CPU(uc, mycpu)->env.fpus; + fpus = fpus & ~(7<<11); + fpus |= (X86_CPU(uc, mycpu)->env.fpstt&7)<<11; + *(uint16_t*) value = fpus; + } + break; + } + switch(uc->mode) { default: break; @@ -573,6 +592,26 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { CPUState *mycpu = first_cpu; + switch(regid) { + default: + break; + case UC_X86_REG_FP0 ... UC_X86_REG_FP7: + { + //floatx80 cpu_set_fp80(uint64_t mant, uint16_t upper); + uint64_t mant = *(uint64_t*) value; + uint16_t upper = *(uint16_t*) (value+sizeof(uint64_t)); + X86_CPU(uc, mycpu)->env.fpregs[regid - UC_X86_REG_FP0].d = cpu_set_fp80(mant, upper); + } + break; + case UC_X86_REG_FPSW: + { + uint16_t fpus = *(uint16_t*) value; + X86_CPU(uc, mycpu)->env.fpus = fpus; + X86_CPU(uc, mycpu)->env.fpstt = (fpus>>11)&7; + } + break; + } + switch(uc->mode) { default: break; From a5f2a64de52dfa1772cd8de0886292964fe32236 Mon Sep 17 00:00:00 2001 From: feliam Date: Wed, 9 Mar 2016 18:27:59 -0300 Subject: [PATCH 2/5] -spaces- --- bindings/python/unicorn/unicorn.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index 28ba7e77..01cbff13 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -156,7 +156,6 @@ def uc_arch_supported(query): return _uc.uc_arch_supported(query) - class uc_x86_mmr(ctypes.Structure): '''Memory-Management Register for instructions IDTR, GDTR, LDTR, TR.''' _fields_ = [ @@ -166,6 +165,7 @@ class uc_x86_mmr(ctypes.Structure): ("flags", ctypes.c_uint32), # not used by GDTR and IDTR ] + class uc_x86_float80(ctypes.Structure): '''Float80''' _fields_ = [ @@ -173,6 +173,7 @@ class uc_x86_float80(ctypes.Structure): ("exponent", ctypes.c_uint16), ] + class Uc(object): def __init__(self, arch, mode): # verify version compatibility with the core before doing anything From 0a3799eadac6ad335551d4fb30328a9e6c802e8e Mon Sep 17 00:00:00 2001 From: feliam Date: Wed, 9 Mar 2016 19:14:33 -0300 Subject: [PATCH 3/5] FPU control word and tags --- bindings/python/unicorn/x86_const.py | 4 ++- include/unicorn/x86.h | 3 +- qemu/target-i386/unicorn.c | 52 +++++++++++++++++++++++++--- 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/bindings/python/unicorn/x86_const.py b/bindings/python/unicorn/x86_const.py index a0cf0abc..8f93c0e0 100644 --- a/bindings/python/unicorn/x86_const.py +++ b/bindings/python/unicorn/x86_const.py @@ -248,7 +248,9 @@ UC_X86_REG_IDTR = 242 UC_X86_REG_GDTR = 243 UC_X86_REG_LDTR = 244 UC_X86_REG_TR = 245 -UC_X86_REG_ENDING = 246 +UC_X86_REG_FPTAGS = 246 +UC_X86_REG_FPCW = 247 +UC_X86_REG_ENDING = 248 # X86 instructions diff --git a/include/unicorn/x86.h b/include/unicorn/x86.h index 51401eba..88559730 100644 --- a/include/unicorn/x86.h +++ b/include/unicorn/x86.h @@ -73,7 +73,8 @@ typedef enum uc_x86_reg { UC_X86_REG_R9D, UC_X86_REG_R10D, UC_X86_REG_R11D, UC_X86_REG_R12D, UC_X86_REG_R13D, UC_X86_REG_R14D, UC_X86_REG_R15D, UC_X86_REG_R8W, UC_X86_REG_R9W, UC_X86_REG_R10W, UC_X86_REG_R11W, UC_X86_REG_R12W, UC_X86_REG_R13W, UC_X86_REG_R14W, UC_X86_REG_R15W, - UC_X86_REG_IDTR, UC_X86_REG_GDTR, UC_X86_REG_LDTR, UC_X86_REG_TR, + UC_X86_REG_IDTR, UC_X86_REG_GDTR, UC_X86_REG_LDTR, UC_X86_REG_TR, UC_X86_REG_FPCW, + UC_X86_REG_FPTAG, UC_X86_REG_ENDING // <-- mark the end of the list of registers } uc_x86_reg; diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index 3ab525c3..4b285f93 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -152,10 +152,42 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) case UC_X86_REG_FPSW: { uint16_t fpus = X86_CPU(uc, mycpu)->env.fpus; - fpus = fpus & ~(7<<11); - fpus |= (X86_CPU(uc, mycpu)->env.fpstt&7)<<11; + fpus = fpus & ~0x3800; + fpus |= ( X86_CPU(uc, mycpu)->env.fpstt & 0x7 ) << 11; *(uint16_t*) value = fpus; } + case UC_X86_REG_FPCW: + *(uint16_t*) value = X86_CPU(uc, mycpu)->env.fpuc; + break; + case UC_X86_REG_FPTAG: + { + #define EXPD(fp) (fp.l.upper & 0x7fff) + #define MANTD(fp) (fp.l.lower) + #define MAXEXPD 0x7fff + int fptag, exp, i; + uint64_t mant; + CPU_LDoubleU tmp; + fptag = 0; + for (i = 7; i >= 0; i--) { + fptag <<= 2; + if (X86_CPU(uc, mycpu)->env.fptags[i]) { + fptag |= 3; + } else { + tmp.d = X86_CPU(uc, mycpu)->env.fpregs[i].d; + exp = EXPD(tmp); + mant = MANTD(tmp); + if (exp == 0 && mant == 0) { + /* zero */ + fptag |= 1; + } else if (exp == 0 || exp == MAXEXPD + || (mant & (1LL << 63)) == 0) { + /* NaNs, infinity, denormal */ + fptag |= 2; + } + } + } + *(uint16_t*) value = fptag; + } break; } @@ -606,10 +638,22 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) case UC_X86_REG_FPSW: { uint16_t fpus = *(uint16_t*) value; - X86_CPU(uc, mycpu)->env.fpus = fpus; - X86_CPU(uc, mycpu)->env.fpstt = (fpus>>11)&7; + X86_CPU(uc, mycpu)->env.fpus = fpus & ~0x3800; + X86_CPU(uc, mycpu)->env.fpstt = (fpus >> 11) & 0x7; } break; + case UC_X86_REG_FPCW: + *(uint16_t*) value = X86_CPU(uc, mycpu)->env.fpuc; + break; + case UC_X86_REG_FPTAG: + { + int i; + uint16_t fptag = *(uint16_t*) value; + for (i = 0; i < 8; i++) { + X86_CPU(uc, mycpu)->env.fptags[i] = ((fptag & 3) == 3); + fptag >>= 2; + } + } } switch(uc->mode) { From 3038726a5b9fef12bb78b6ea5dd593c1fbe853b7 Mon Sep 17 00:00:00 2001 From: feliam Date: Wed, 9 Mar 2016 22:14:51 -0300 Subject: [PATCH 4/5] Fix --- bindings/python/unicorn/unicorn.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index 01cbff13..aef9d996 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -246,6 +246,8 @@ class Uc(object): # write to a register def reg_write(self, reg_id, value): + reg = None + if self._arch == UC_ARCH_X86: if reg_id in [ x86_const.UC_X86_REG_IDTR, x86_const.UC_X86_REG_GDTR, x86_const.UC_X86_REG_LDTR, x86_const.UC_X86_REG_TR]: assert isinstance(value, tuple) and len(value)==4 @@ -258,7 +260,8 @@ class Uc(object): reg = uc_x86_float80() reg.mantissa = value[0] reg.exponent = value[1] - else: + + if reg is None: # convert to 64bit number to be safe reg = ctypes.c_int64(value) From 23b3f651f910afb28a68fb1c2810d21aba9082f2 Mon Sep 17 00:00:00 2001 From: feliam Date: Thu, 10 Mar 2016 07:45:36 -0300 Subject: [PATCH 5/5] Indentation --- bindings/python/unicorn/unicorn.py | 1 + include/unicorn/x86.h | 2 +- qemu/target-i386/unicorn.c | 8 ++++---- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index aef9d996..7b592a7c 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -206,6 +206,7 @@ class Uc(object): except: # _uc might be pulled from under our feet pass + # emulate from @begin, and stop when reaching address @until def emu_start(self, begin, until, timeout=0, count=0): status = _uc.uc_emu_start(self._uch, begin, until, timeout, count) diff --git a/include/unicorn/x86.h b/include/unicorn/x86.h index 88559730..fe33c723 100644 --- a/include/unicorn/x86.h +++ b/include/unicorn/x86.h @@ -74,7 +74,7 @@ typedef enum uc_x86_reg { UC_X86_REG_R14D, UC_X86_REG_R15D, UC_X86_REG_R8W, UC_X86_REG_R9W, UC_X86_REG_R10W, UC_X86_REG_R11W, UC_X86_REG_R12W, UC_X86_REG_R13W, UC_X86_REG_R14W, UC_X86_REG_R15W, UC_X86_REG_IDTR, UC_X86_REG_GDTR, UC_X86_REG_LDTR, UC_X86_REG_TR, UC_X86_REG_FPCW, - UC_X86_REG_FPTAG, + UC_X86_REG_FPTAG, UC_X86_REG_ENDING // <-- mark the end of the list of registers } uc_x86_reg; diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index 4b285f93..106266f3 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -152,7 +152,7 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) case UC_X86_REG_FPSW: { uint16_t fpus = X86_CPU(uc, mycpu)->env.fpus; - fpus = fpus & ~0x3800; + fpus = fpus & ~0x3800; fpus |= ( X86_CPU(uc, mycpu)->env.fpstt & 0x7 ) << 11; *(uint16_t*) value = fpus; } @@ -629,9 +629,8 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) break; case UC_X86_REG_FP0 ... UC_X86_REG_FP7: { - //floatx80 cpu_set_fp80(uint64_t mant, uint16_t upper); uint64_t mant = *(uint64_t*) value; - uint16_t upper = *(uint16_t*) (value+sizeof(uint64_t)); + uint16_t upper = *(uint16_t*) (value + sizeof(uint64_t)); X86_CPU(uc, mycpu)->env.fpregs[regid - UC_X86_REG_FP0].d = cpu_set_fp80(mant, upper); } break; @@ -654,7 +653,8 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) fptag >>= 2; } } - } + break; + } switch(uc->mode) { default: