From afecfee565db653588a5627e83710f8a20531b72 Mon Sep 17 00:00:00 2001 From: mothran Date: Thu, 10 Sep 2015 23:20:52 -0700 Subject: [PATCH 01/66] added SPARC sp / fp registers, also updated uint32_t's to uint64_t's in SPARC64 --- qemu/target-sparc/unicorn.c | 23 +++++++++++++++++------ qemu/target-sparc/unicorn64.c | 26 +++++++++++++++++++------- 2 files changed, 36 insertions(+), 13 deletions(-) diff --git a/qemu/target-sparc/unicorn.c b/qemu/target-sparc/unicorn.c index 9f00f340..19e3ab0e 100644 --- a/qemu/target-sparc/unicorn.c +++ b/qemu/target-sparc/unicorn.c @@ -54,8 +54,14 @@ int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value) switch(regid) { default: break; case UC_SPARC_REG_PC: - *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.pc; - break; + *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.pc; + break; + case UC_SPARC_REG_SP: + *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regbase[6]; + break; + case UC_SPARC_REG_FP: + *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regbase[22]; + break; } } @@ -78,13 +84,18 @@ int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) switch(regid) { default: break; case UC_SPARC_REG_PC: - SPARC_CPU(uc, mycpu)->env.pc = *(uint32_t *)value; - SPARC_CPU(uc, mycpu)->env.npc = *(uint32_t *)value + 4; - break; + SPARC_CPU(uc, mycpu)->env.pc = *(uint32_t *)value; + SPARC_CPU(uc, mycpu)->env.npc = *(uint32_t *)value + 4; + break; + case UC_SPARC_REG_SP: + SPARC_CPU(uc, mycpu)->env.regbase[6] = *(uint32_t *)value; + break; + case UC_SPARC_REG_FP: + SPARC_CPU(uc, mycpu)->env.regbase[22] = *(uint32_t *)value; + break; } } - return 0; } diff --git a/qemu/target-sparc/unicorn64.c b/qemu/target-sparc/unicorn64.c index aefef116..eb88c095 100644 --- a/qemu/target-sparc/unicorn64.c +++ b/qemu/target-sparc/unicorn64.c @@ -32,13 +32,19 @@ int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value) CPUState *mycpu = first_cpu; if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) - *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0]; + *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0]; else { switch(regid) { default: break; case UC_SPARC_REG_PC: - *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.pc; - break; + *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.pc; + break; + case UC_SPARC_REG_SP: + *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regbase[6]; + break; + case UC_SPARC_REG_FP: + *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regbase[22]; + break; } } @@ -56,14 +62,20 @@ int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) CPUState *mycpu = first_cpu; if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) - SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0] = *(uint32_t *)value; + SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0] = *(uint64_t *)value; else { switch(regid) { default: break; case UC_SPARC_REG_PC: - SPARC_CPU(uc, mycpu)->env.pc = *(uint32_t *)value; - SPARC_CPU(uc, mycpu)->env.npc = *(uint32_t *)value + 4; - break; + SPARC_CPU(uc, mycpu)->env.pc = *(uint64_t *)value; + SPARC_CPU(uc, mycpu)->env.npc = *(uint64_t *)value + 8; + break; + case UC_SPARC_REG_SP: + SPARC_CPU(uc, mycpu)->env.regbase[6] = *(uint64_t *)value; + break; + case UC_SPARC_REG_FP: + SPARC_CPU(uc, mycpu)->env.regbase[22] = *(uint64_t *)value; + break; } } From 657a6c3e256545297849aa56bbb9daf46375f9d8 Mon Sep 17 00:00:00 2001 From: mothran Date: Sat, 12 Sep 2015 10:29:35 -0700 Subject: [PATCH 02/66] modified the sparc reg get/set functions to use the current reg window ptr --- qemu/target-sparc/unicorn.c | 8 ++++---- qemu/target-sparc/unicorn64.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/qemu/target-sparc/unicorn.c b/qemu/target-sparc/unicorn.c index 19e3ab0e..f070d07d 100644 --- a/qemu/target-sparc/unicorn.c +++ b/qemu/target-sparc/unicorn.c @@ -57,10 +57,10 @@ int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value) *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.pc; break; case UC_SPARC_REG_SP: - *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regbase[6]; + *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[6]; break; case UC_SPARC_REG_FP: - *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regbase[22]; + *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[22]; break; } } @@ -88,10 +88,10 @@ int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) SPARC_CPU(uc, mycpu)->env.npc = *(uint32_t *)value + 4; break; case UC_SPARC_REG_SP: - SPARC_CPU(uc, mycpu)->env.regbase[6] = *(uint32_t *)value; + SPARC_CPU(uc, mycpu)->env.regwptr[6] = *(uint32_t *)value; break; case UC_SPARC_REG_FP: - SPARC_CPU(uc, mycpu)->env.regbase[22] = *(uint32_t *)value; + SPARC_CPU(uc, mycpu)->env.regwptr[22] = *(uint32_t *)value; break; } } diff --git a/qemu/target-sparc/unicorn64.c b/qemu/target-sparc/unicorn64.c index eb88c095..5def992e 100644 --- a/qemu/target-sparc/unicorn64.c +++ b/qemu/target-sparc/unicorn64.c @@ -40,10 +40,10 @@ int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value) *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.pc; break; case UC_SPARC_REG_SP: - *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regbase[6]; + *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[6]; break; case UC_SPARC_REG_FP: - *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regbase[22]; + *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[22]; break; } } @@ -71,10 +71,10 @@ int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) SPARC_CPU(uc, mycpu)->env.npc = *(uint64_t *)value + 8; break; case UC_SPARC_REG_SP: - SPARC_CPU(uc, mycpu)->env.regbase[6] = *(uint64_t *)value; + SPARC_CPU(uc, mycpu)->env.regwptr[6] = *(uint64_t *)value; break; case UC_SPARC_REG_FP: - SPARC_CPU(uc, mycpu)->env.regbase[22] = *(uint64_t *)value; + SPARC_CPU(uc, mycpu)->env.regwptr[22] = *(uint64_t *)value; break; } } From 2789e7951bf4475d9ed5ab2b19a664001fd55c21 Mon Sep 17 00:00:00 2001 From: mothran Date: Sat, 12 Sep 2015 10:35:50 -0700 Subject: [PATCH 03/66] added the sparc64 crash regression --- regress/sparc64.py | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 regress/sparc64.py diff --git a/regress/sparc64.py b/regress/sparc64.py new file mode 100644 index 00000000..e59412dc --- /dev/null +++ b/regress/sparc64.py @@ -0,0 +1,11 @@ +#!/usr/bin/python + +from unicorn import * +from unicorn.sparc_const import * + +uc = Uc(UC_ARCH_SPARC, UC_MODE_64) +uc.reg_write(UC_SPARC_REG_SP, 100) +uc.reg_write(UC_SPARC_REG_FP, 100) +print 'writing sp = 100, fp = 100' +print 'sp =', uc.reg_read(UC_SPARC_REG_SP) +print 'fp =', uc.reg_read(UC_SPARC_REG_FP) From 7dc41a8e4e5113753bf430f48d51df4c5a95897f Mon Sep 17 00:00:00 2001 From: mothran Date: Sun, 13 Sep 2015 18:10:28 -0700 Subject: [PATCH 04/66] update the regwptr upon reset --- qemu/target-sparc/unicorn.c | 1 + qemu/target-sparc/unicorn64.c | 1 + 2 files changed, 2 insertions(+) diff --git a/qemu/target-sparc/unicorn.c b/qemu/target-sparc/unicorn.c index f070d07d..02aadd7f 100644 --- a/qemu/target-sparc/unicorn.c +++ b/qemu/target-sparc/unicorn.c @@ -42,6 +42,7 @@ void sparc_reg_reset(struct uc_struct *uc) env->pc = 0; env->npc = 0; + env->regwptr = env->regbase; } int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value) diff --git a/qemu/target-sparc/unicorn64.c b/qemu/target-sparc/unicorn64.c index 5def992e..6b62695f 100644 --- a/qemu/target-sparc/unicorn64.c +++ b/qemu/target-sparc/unicorn64.c @@ -25,6 +25,7 @@ void sparc_reg_reset(struct uc_struct *uc) env->pc = 0; env->npc = 0; + env->regwptr = env->regbase; } int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value) From 3f726d1c5783eb46b356ba7a80bf2e569e569114 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Mon, 14 Sep 2015 09:46:05 +0700 Subject: [PATCH 05/66] chmod +x regress/sparc64.py --- regress/sparc64.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 regress/sparc64.py diff --git a/regress/sparc64.py b/regress/sparc64.py old mode 100644 new mode 100755 From 6b521e9e9b43928cdb2ea45bed4f233c90211dd2 Mon Sep 17 00:00:00 2001 From: mothran Date: Mon, 14 Sep 2015 20:03:32 -0700 Subject: [PATCH 06/66] update the sparc reg read/write to include o/l/i registers --- qemu/target-sparc/unicorn.c | 12 ++++++++++++ qemu/target-sparc/unicorn64.c | 12 ++++++++++++ regress/sparc_reg.py | 19 +++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/qemu/target-sparc/unicorn.c b/qemu/target-sparc/unicorn.c index 02aadd7f..93bdffdc 100644 --- a/qemu/target-sparc/unicorn.c +++ b/qemu/target-sparc/unicorn.c @@ -51,6 +51,12 @@ int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value) if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0]; + else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) + *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0]; + else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7) + *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0]; + else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7) + *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0]; else { switch(regid) { default: break; @@ -81,6 +87,12 @@ int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0] = *(uint32_t *)value; + else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) + SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0] = *(uint32_t *)value; + else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7) + SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0] = *(uint32_t *)value; + else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7) + SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0] = *(uint32_t *)value; else { switch(regid) { default: break; diff --git a/qemu/target-sparc/unicorn64.c b/qemu/target-sparc/unicorn64.c index 6b62695f..49428fa3 100644 --- a/qemu/target-sparc/unicorn64.c +++ b/qemu/target-sparc/unicorn64.c @@ -34,6 +34,12 @@ int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value) if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0]; + else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) + *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0]; + else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7) + *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0]; + else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7) + *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0]; else { switch(regid) { default: break; @@ -64,6 +70,12 @@ int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0] = *(uint64_t *)value; + else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) + SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0] = *(uint64_t *)value; + else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7) + SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0] = *(uint64_t *)value; + else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7) + SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0] = *(uint64_t *)value; else { switch(regid) { default: break; diff --git a/regress/sparc_reg.py b/regress/sparc_reg.py index 73858360..33bb03e0 100755 --- a/regress/sparc_reg.py +++ b/regress/sparc_reg.py @@ -6,6 +6,25 @@ from unicorn.sparc_const import * uc = Uc(UC_ARCH_SPARC, UC_MODE_32) uc.reg_write(UC_SPARC_REG_SP, 100) uc.reg_write(UC_SPARC_REG_FP, 100) +uc.reg_write(UC_SPARC_REG_G0, 200) +uc.reg_write(UC_SPARC_REG_O0, 201) +uc.reg_write(UC_SPARC_REG_L0, 202) +uc.reg_write(UC_SPARC_REG_L7, 203) +uc.reg_write(UC_SPARC_REG_I0, 204) + print 'writing sp = 100, fp = 100' print 'sp =', uc.reg_read(UC_SPARC_REG_SP) print 'fp =', uc.reg_read(UC_SPARC_REG_FP) +print 'g0 =', uc.reg_read(UC_SPARC_REG_G0) +print 'o0 =', uc.reg_read(UC_SPARC_REG_O0) +print 'l0 =', uc.reg_read(UC_SPARC_REG_L0) +print 'l7 =', uc.reg_read(UC_SPARC_REG_L7) +print 'i0 =', uc.reg_read(UC_SPARC_REG_I0) + +assert uc.reg_read(UC_SPARC_REG_SP) == 100 +assert uc.reg_read(UC_SPARC_REG_FP) == 100 +assert uc.reg_read(UC_SPARC_REG_G0) == 200 +assert uc.reg_read(UC_SPARC_REG_O0) == 201 +assert uc.reg_read(UC_SPARC_REG_L0) == 202 +assert uc.reg_read(UC_SPARC_REG_L7) == 203 +assert uc.reg_read(UC_SPARC_REG_I0) == 204 \ No newline at end of file From d4d563118106b509efb9730c45dc76d5a34b877e Mon Sep 17 00:00:00 2001 From: mothran Date: Mon, 14 Sep 2015 20:42:41 -0700 Subject: [PATCH 07/66] updated the sparc.h header so the alignment of certain registers was correct --- include/unicorn/sparc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/unicorn/sparc.h b/include/unicorn/sparc.h index 25a1140b..61f453d1 100644 --- a/include/unicorn/sparc.h +++ b/include/unicorn/sparc.h @@ -75,7 +75,6 @@ typedef enum uc_sparc_reg { UC_SPARC_REG_FCC1, UC_SPARC_REG_FCC2, UC_SPARC_REG_FCC3, - UC_SPARC_REG_FP, UC_SPARC_REG_G0, UC_SPARC_REG_G1, UC_SPARC_REG_G2, @@ -90,6 +89,7 @@ typedef enum uc_sparc_reg { UC_SPARC_REG_I3, UC_SPARC_REG_I4, UC_SPARC_REG_I5, + UC_SPARC_REG_FP, UC_SPARC_REG_I7, UC_SPARC_REG_ICC, // Integer condition codes UC_SPARC_REG_L0, @@ -106,8 +106,8 @@ typedef enum uc_sparc_reg { UC_SPARC_REG_O3, UC_SPARC_REG_O4, UC_SPARC_REG_O5, + UC_SPARC_REG_SP, UC_SPARC_REG_O7, - UC_SPARC_REG_SP, UC_SPARC_REG_Y, // special register From f4894a1c77d0568b4ddc08881b08f73cfd310b7e Mon Sep 17 00:00:00 2001 From: mothran Date: Mon, 14 Sep 2015 20:44:50 -0700 Subject: [PATCH 08/66] removed unneed cases in the switch statement --- qemu/target-sparc/unicorn.c | 12 ------------ qemu/target-sparc/unicorn64.c | 12 ------------ 2 files changed, 24 deletions(-) diff --git a/qemu/target-sparc/unicorn.c b/qemu/target-sparc/unicorn.c index 93bdffdc..b8ea29d8 100644 --- a/qemu/target-sparc/unicorn.c +++ b/qemu/target-sparc/unicorn.c @@ -63,12 +63,6 @@ int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value) case UC_SPARC_REG_PC: *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.pc; break; - case UC_SPARC_REG_SP: - *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[6]; - break; - case UC_SPARC_REG_FP: - *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[22]; - break; } } @@ -100,12 +94,6 @@ int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) SPARC_CPU(uc, mycpu)->env.pc = *(uint32_t *)value; SPARC_CPU(uc, mycpu)->env.npc = *(uint32_t *)value + 4; break; - case UC_SPARC_REG_SP: - SPARC_CPU(uc, mycpu)->env.regwptr[6] = *(uint32_t *)value; - break; - case UC_SPARC_REG_FP: - SPARC_CPU(uc, mycpu)->env.regwptr[22] = *(uint32_t *)value; - break; } } diff --git a/qemu/target-sparc/unicorn64.c b/qemu/target-sparc/unicorn64.c index 49428fa3..a3700db0 100644 --- a/qemu/target-sparc/unicorn64.c +++ b/qemu/target-sparc/unicorn64.c @@ -46,12 +46,6 @@ int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value) case UC_SPARC_REG_PC: *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.pc; break; - case UC_SPARC_REG_SP: - *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[6]; - break; - case UC_SPARC_REG_FP: - *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[22]; - break; } } @@ -83,12 +77,6 @@ int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) SPARC_CPU(uc, mycpu)->env.pc = *(uint64_t *)value; SPARC_CPU(uc, mycpu)->env.npc = *(uint64_t *)value + 8; break; - case UC_SPARC_REG_SP: - SPARC_CPU(uc, mycpu)->env.regwptr[6] = *(uint64_t *)value; - break; - case UC_SPARC_REG_FP: - SPARC_CPU(uc, mycpu)->env.regwptr[22] = *(uint64_t *)value; - break; } } From 1638372793df1f160f1994a9d5ae3bd86b6dc56c Mon Sep 17 00:00:00 2001 From: mothran Date: Mon, 14 Sep 2015 20:48:31 -0700 Subject: [PATCH 09/66] fix small whitespace issue --- include/unicorn/sparc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/unicorn/sparc.h b/include/unicorn/sparc.h index 61f453d1..353dbb34 100644 --- a/include/unicorn/sparc.h +++ b/include/unicorn/sparc.h @@ -106,14 +106,14 @@ typedef enum uc_sparc_reg { UC_SPARC_REG_O3, UC_SPARC_REG_O4, UC_SPARC_REG_O5, - UC_SPARC_REG_SP, + UC_SPARC_REG_SP, UC_SPARC_REG_O7, UC_SPARC_REG_Y, // special register UC_SPARC_REG_XCC, - // pseudo register + // pseudo register UC_SPARC_REG_PC, // program counter register UC_SPARC_REG_ENDING, // <-- mark the end of the list of registers From 69d73aa845aa3100a1064efe6b595928eaf93d11 Mon Sep 17 00:00:00 2001 From: mothran Date: Mon, 14 Sep 2015 21:23:42 -0700 Subject: [PATCH 10/66] added emulated SPARC code for regress/sparc_reg.py, appears to be a bug in G and I registers --- regress/sparc_reg.py | 139 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 119 insertions(+), 20 deletions(-) diff --git a/regress/sparc_reg.py b/regress/sparc_reg.py index 33bb03e0..1a2a16ae 100755 --- a/regress/sparc_reg.py +++ b/regress/sparc_reg.py @@ -3,28 +3,127 @@ from unicorn import * from unicorn.sparc_const import * +PAGE_SIZE = 1 * 1024 * 1024 + uc = Uc(UC_ARCH_SPARC, UC_MODE_32) uc.reg_write(UC_SPARC_REG_SP, 100) -uc.reg_write(UC_SPARC_REG_FP, 100) -uc.reg_write(UC_SPARC_REG_G0, 200) -uc.reg_write(UC_SPARC_REG_O0, 201) -uc.reg_write(UC_SPARC_REG_L0, 202) -uc.reg_write(UC_SPARC_REG_L7, 203) -uc.reg_write(UC_SPARC_REG_I0, 204) +uc.reg_write(UC_SPARC_REG_FP, 200) +uc.reg_write(UC_SPARC_REG_G0, 300) +uc.reg_write(UC_SPARC_REG_O0, 400) +uc.reg_write(UC_SPARC_REG_L0, 500) +uc.reg_write(UC_SPARC_REG_I0, 600) -print 'writing sp = 100, fp = 100' -print 'sp =', uc.reg_read(UC_SPARC_REG_SP) -print 'fp =', uc.reg_read(UC_SPARC_REG_FP) -print 'g0 =', uc.reg_read(UC_SPARC_REG_G0) -print 'o0 =', uc.reg_read(UC_SPARC_REG_O0) -print 'l0 =', uc.reg_read(UC_SPARC_REG_L0) -print 'l7 =', uc.reg_read(UC_SPARC_REG_L7) -print 'i0 =', uc.reg_read(UC_SPARC_REG_I0) + # 0x0: \x80\x00\x20\x01 inc %g0 + # 0x4: \x90\x02\x20\x01 inc %o0 + # 0x8: \xA0\x04\x20\x01 inc %l0 + # 0xc: \xB0\x06\x20\x01 inc %i0 +CODE = "\x80\x00\x20\x01" \ + "\x90\x02\x20\x01" \ + "\xA0\x04\x20\x01" \ + "\xB0\x06\x20\x01" + # 0x0: \x80\x00\x20\x01 add %g0, 1, %g0 + # 0x4: \x90\x02\x20\x01 add %o0, 1, %o0 + # 0x8: \xA0\x04\x20\x01 add %l0, 1, %l0 + # 0xc: \xB0\x06\x20\x01 add %i0, 1, %i0 +CODE2 = "\x80\x00\x20\x01" \ + "\x90\x02\x20\x01" \ + "\xA0\x04\x20\x01" \ + "\xB0\x06\x20\x01" + + +uc.mem_map(0, PAGE_SIZE) +uc.mem_write(0, CODE2) +uc.emu_start(0, len(CODE2), 0, 4) + +def print_registers(mu): + g0 = mu.reg_read(UC_SPARC_REG_G0) + g1 = mu.reg_read(UC_SPARC_REG_G1) + g2 = mu.reg_read(UC_SPARC_REG_G2) + g3 = mu.reg_read(UC_SPARC_REG_G3) + g4 = mu.reg_read(UC_SPARC_REG_G4) + g5 = mu.reg_read(UC_SPARC_REG_G5) + g6 = mu.reg_read(UC_SPARC_REG_G6) + g7 = mu.reg_read(UC_SPARC_REG_G7) + + o0 = mu.reg_read(UC_SPARC_REG_O0) + o1 = mu.reg_read(UC_SPARC_REG_O1) + o2 = mu.reg_read(UC_SPARC_REG_O2) + o3 = mu.reg_read(UC_SPARC_REG_O3) + o4 = mu.reg_read(UC_SPARC_REG_O4) + o5 = mu.reg_read(UC_SPARC_REG_O5) + o6 = mu.reg_read(UC_SPARC_REG_O6) + o7 = mu.reg_read(UC_SPARC_REG_O7) + + l0 = mu.reg_read(UC_SPARC_REG_L0) + l1 = mu.reg_read(UC_SPARC_REG_L1) + l2 = mu.reg_read(UC_SPARC_REG_L2) + l3 = mu.reg_read(UC_SPARC_REG_L3) + l4 = mu.reg_read(UC_SPARC_REG_L4) + l5 = mu.reg_read(UC_SPARC_REG_L5) + l6 = mu.reg_read(UC_SPARC_REG_L6) + l7 = mu.reg_read(UC_SPARC_REG_L7) + + i0 = mu.reg_read(UC_SPARC_REG_I0) + i1 = mu.reg_read(UC_SPARC_REG_I1) + i2 = mu.reg_read(UC_SPARC_REG_I2) + i3 = mu.reg_read(UC_SPARC_REG_I3) + i4 = mu.reg_read(UC_SPARC_REG_I4) + i5 = mu.reg_read(UC_SPARC_REG_I5) + i6 = mu.reg_read(UC_SPARC_REG_I6) + i7 = mu.reg_read(UC_SPARC_REG_I7) + + pc = mu.reg_read(UC_SPARC_REG_PC) + sp = mu.reg_read(UC_SPARC_REG_SP) + fp = mu.reg_read(UC_SPARC_REG_FP) + print(" G0 = %d" % g0) + print(" G1 = %d" % g1) + print(" G2 = %d" % g2) + print(" G3 = %d" % g3) + print(" G4 = %d" % g4) + print(" G5 = %d" % g5) + print(" G6 = %d" % g6) + print(" G7 = %d" % g7) + print("") + print(" O0 = %d" % o0) + print(" O1 = %d" % o1) + print(" O2 = %d" % o2) + print(" O3 = %d" % o3) + print(" O4 = %d" % o4) + print(" O5 = %d" % o5) + print(" O6 = %d" % o6) + print(" O7 = %d" % o7) + print("") + print(" L0 = %d" % l0) + print(" L1 = %d" % l1) + print(" L2 = %d" % l2) + print(" L3 = %d" % l3) + print(" L4 = %d" % l4) + print(" L5 = %d" % l5) + print(" L6 = %d" % l6) + print(" L7 = %d" % l7) + print("") + print(" I0 = %d" % i0) + print(" I1 = %d" % i1) + print(" I2 = %d" % i2) + print(" I3 = %d" % i3) + print(" I4 = %d" % i4) + print(" I5 = %d" % i5) + print(" I6 = %d" % i6) + print(" I7 = %d" % i7) + print("") + print(" PC = %d" % pc) + print(" SP = %d" % sp) + print(" FP = %d" % fp) + print("") + +print_registers(uc) + +assert uc.reg_read(UC_SPARC_REG_PC) == 16 # make sure we executed all 4 instructions assert uc.reg_read(UC_SPARC_REG_SP) == 100 -assert uc.reg_read(UC_SPARC_REG_FP) == 100 -assert uc.reg_read(UC_SPARC_REG_G0) == 200 -assert uc.reg_read(UC_SPARC_REG_O0) == 201 -assert uc.reg_read(UC_SPARC_REG_L0) == 202 -assert uc.reg_read(UC_SPARC_REG_L7) == 203 -assert uc.reg_read(UC_SPARC_REG_I0) == 204 \ No newline at end of file +assert uc.reg_read(UC_SPARC_REG_FP) == 200 + +assert uc.reg_read(UC_SPARC_REG_G0) == 301 +assert uc.reg_read(UC_SPARC_REG_O0) == 401 +assert uc.reg_read(UC_SPARC_REG_L0) == 501 +assert uc.reg_read(UC_SPARC_REG_I0) == 601 \ No newline at end of file From d1e19df64e7012beec0fa638b622976725153734 Mon Sep 17 00:00:00 2001 From: mothran Date: Mon, 14 Sep 2015 23:05:33 -0700 Subject: [PATCH 11/66] update the sparc_reg to test all g/o/l registers --- regress/sparc_reg.py | 108 ++++++++++++++++++++++++++++++++----------- 1 file changed, 80 insertions(+), 28 deletions(-) diff --git a/regress/sparc_reg.py b/regress/sparc_reg.py index 1a2a16ae..6442ebe8 100755 --- a/regress/sparc_reg.py +++ b/regress/sparc_reg.py @@ -8,33 +8,60 @@ PAGE_SIZE = 1 * 1024 * 1024 uc = Uc(UC_ARCH_SPARC, UC_MODE_32) uc.reg_write(UC_SPARC_REG_SP, 100) uc.reg_write(UC_SPARC_REG_FP, 200) -uc.reg_write(UC_SPARC_REG_G0, 300) -uc.reg_write(UC_SPARC_REG_O0, 400) -uc.reg_write(UC_SPARC_REG_L0, 500) -uc.reg_write(UC_SPARC_REG_I0, 600) - - # 0x0: \x80\x00\x20\x01 inc %g0 - # 0x4: \x90\x02\x20\x01 inc %o0 - # 0x8: \xA0\x04\x20\x01 inc %l0 - # 0xc: \xB0\x06\x20\x01 inc %i0 -CODE = "\x80\x00\x20\x01" \ - "\x90\x02\x20\x01" \ - "\xA0\x04\x20\x01" \ - "\xB0\x06\x20\x01" # 0x0: \x80\x00\x20\x01 add %g0, 1, %g0 - # 0x4: \x90\x02\x20\x01 add %o0, 1, %o0 - # 0x8: \xA0\x04\x20\x01 add %l0, 1, %l0 - # 0xc: \xB0\x06\x20\x01 add %i0, 1, %i0 -CODE2 = "\x80\x00\x20\x01" \ - "\x90\x02\x20\x01" \ - "\xA0\x04\x20\x01" \ - "\xB0\x06\x20\x01" + # 0x4: \x82\x00\x60\x01 add %g1, 1, %g1 + # 0x8: \x84\x00\xA0\x01 add %g2, 1, %g2 + # 0xc: \x86\x00\xE0\x01 add %g3, 1, %g3 + # 0x10: \x88\x01\x20\x01 add %g4, 1, %g4 + # 0x14: \x8A\x01\x60\x01 add %g5, 1, %g5 + # 0x18: \x8C\x01\xA0\x01 add %g6, 1, %g6 + # 0x1c: \x8E\x01\xE0\x01 add %g7, 1, %g7 + # 0x20: \x90\x02\x20\x01 add %o0, 1, %o0 + # 0x24: \x92\x02\x60\x01 add %o1, 1, %o1 + # 0x28: \x94\x02\xA0\x01 add %o2, 1, %o2 + # 0x2c: \x96\x02\xE0\x01 add %o3, 1, %o3 + # 0x30: \x98\x03\x20\x01 add %o4, 1, %o4 + # 0x34: \x9A\x03\x60\x01 add %o5, 1, %o5 + # 0x38: \x9C\x03\xA0\x01 add %sp, 1, %sp + # 0x3c: \x9E\x03\xE0\x01 add %o7, 1, %o7 + # 0x40: \xA0\x04\x20\x01 add %l0, 1, %l0 + # 0x44: \xA2\x04\x60\x01 add %l1, 1, %l1 + # 0x48: \xA4\x04\xA0\x01 add %l2, 1, %l2 + # 0x4c: \xA6\x04\xE0\x01 add %l3, 1, %l3 + # 0x50: \xA8\x05\x20\x01 add %l4, 1, %l4 + # 0x54: \xAA\x05\x60\x01 add %l5, 1, %l5 + # 0x58: \xAC\x05\xA0\x01 add %l6, 1, %l6 + # 0x5c: \xAE\x05\xE0\x01 add %l7, 1, %l7 +CODE = "\x80\x00\x20\x01" \ + "\x82\x00\x60\x01" \ + "\x84\x00\xA0\x01" \ + "\x86\x00\xE0\x01" \ + "\x88\x01\x20\x01" \ + "\x8A\x01\x60\x01" \ + "\x8C\x01\xA0\x01" \ + "\x8E\x01\xE0\x01" \ + "\x90\x02\x20\x01" \ + "\x92\x02\x60\x01" \ + "\x94\x02\xA0\x01" \ + "\x96\x02\xE0\x01" \ + "\x98\x03\x20\x01" \ + "\x9A\x03\x60\x01" \ + "\x9C\x03\xA0\x01" \ + "\x9E\x03\xE0\x01" \ + "\xA0\x04\x20\x01" \ + "\xA2\x04\x60\x01" \ + "\xA4\x04\xA0\x01" \ + "\xA6\x04\xE0\x01" \ + "\xA8\x05\x20\x01" \ + "\xAA\x05\x60\x01" \ + "\xAC\x05\xA0\x01" \ + "\xAE\x05\xE0\x01" uc.mem_map(0, PAGE_SIZE) -uc.mem_write(0, CODE2) -uc.emu_start(0, len(CODE2), 0, 4) +uc.mem_write(0, CODE) +uc.emu_start(0, len(CODE), 0, 24) def print_registers(mu): g0 = mu.reg_read(UC_SPARC_REG_G0) @@ -119,11 +146,36 @@ def print_registers(mu): print_registers(uc) -assert uc.reg_read(UC_SPARC_REG_PC) == 16 # make sure we executed all 4 instructions -assert uc.reg_read(UC_SPARC_REG_SP) == 100 +assert uc.reg_read(UC_SPARC_REG_PC) == 96 # make sure we executed all instructions +assert uc.reg_read(UC_SPARC_REG_SP) == 101 assert uc.reg_read(UC_SPARC_REG_FP) == 200 -assert uc.reg_read(UC_SPARC_REG_G0) == 301 -assert uc.reg_read(UC_SPARC_REG_O0) == 401 -assert uc.reg_read(UC_SPARC_REG_L0) == 501 -assert uc.reg_read(UC_SPARC_REG_I0) == 601 \ No newline at end of file +assert uc.reg_read(UC_SPARC_REG_G0) == 0 # G0 is always zero +assert uc.reg_read(UC_SPARC_REG_G1) == 1 +assert uc.reg_read(UC_SPARC_REG_G2) == 1 +assert uc.reg_read(UC_SPARC_REG_G3) == 1 +assert uc.reg_read(UC_SPARC_REG_G4) == 1 +assert uc.reg_read(UC_SPARC_REG_G5) == 1 +assert uc.reg_read(UC_SPARC_REG_G6) == 1 +assert uc.reg_read(UC_SPARC_REG_G7) == 1 + +assert uc.reg_read(UC_SPARC_REG_O0) == 1 +assert uc.reg_read(UC_SPARC_REG_O1) == 1 +assert uc.reg_read(UC_SPARC_REG_O2) == 1 +assert uc.reg_read(UC_SPARC_REG_O3) == 1 +assert uc.reg_read(UC_SPARC_REG_O4) == 1 +assert uc.reg_read(UC_SPARC_REG_O5) == 1 +assert uc.reg_read(UC_SPARC_REG_O6) == 101 +assert uc.reg_read(UC_SPARC_REG_O7) == 1 + +assert uc.reg_read(UC_SPARC_REG_L0) == 1 +assert uc.reg_read(UC_SPARC_REG_L1) == 1 +assert uc.reg_read(UC_SPARC_REG_L2) == 1 +assert uc.reg_read(UC_SPARC_REG_L3) == 1 +assert uc.reg_read(UC_SPARC_REG_L4) == 1 +assert uc.reg_read(UC_SPARC_REG_L5) == 1 +assert uc.reg_read(UC_SPARC_REG_L6) == 1 +assert uc.reg_read(UC_SPARC_REG_L7) == 1 + +assert uc.reg_read(UC_SPARC_REG_O0) == 1 +assert uc.reg_read(UC_SPARC_REG_L0) == 1 \ No newline at end of file From 6962126707a4bb015af22c80b32ac215dcc1e7bd Mon Sep 17 00:00:00 2001 From: mothran Date: Mon, 14 Sep 2015 23:28:09 -0700 Subject: [PATCH 12/66] update sparc_reg.py with %i registers --- regress/sparc_reg.py | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/regress/sparc_reg.py b/regress/sparc_reg.py index 6442ebe8..99c34cdc 100755 --- a/regress/sparc_reg.py +++ b/regress/sparc_reg.py @@ -33,6 +33,15 @@ uc.reg_write(UC_SPARC_REG_FP, 200) # 0x54: \xAA\x05\x60\x01 add %l5, 1, %l5 # 0x58: \xAC\x05\xA0\x01 add %l6, 1, %l6 # 0x5c: \xAE\x05\xE0\x01 add %l7, 1, %l7 + # 0x0: \xB0\x06\x20\x01 add %i0, 1, %i0 + # 0x4: \xB2\x06\x60\x01 add %i1, 1, %i1 + # 0x8: \xB4\x06\xA0\x01 add %i2, 1, %i2 + # 0xc: \xB6\x06\xE0\x01 add %i3, 1, %i3 + # 0x10: \xB8\x07\x20\x01 add %i4, 1, %i4 + # 0x14: \xBA\x07\x60\x01 add %i5, 1, %i5 + # 0x18: \xBC\x07\xA0\x01 add %fp, 1, %fp + # 0x1c: \xBE\x07\xE0\x01 add %i7, 1, %i7 + CODE = "\x80\x00\x20\x01" \ "\x82\x00\x60\x01" \ @@ -57,11 +66,20 @@ CODE = "\x80\x00\x20\x01" \ "\xA8\x05\x20\x01" \ "\xAA\x05\x60\x01" \ "\xAC\x05\xA0\x01" \ - "\xAE\x05\xE0\x01" + "\xAE\x05\xE0\x01" \ + "\xB0\x06\x20\x01" \ + "\xB2\x06\x60\x01" \ + "\xB4\x06\xA0\x01" \ + "\xB6\x06\xE0\x01" \ + "\xB8\x07\x20\x01" \ + "\xBA\x07\x60\x01" \ + "\xBC\x07\xA0\x01" \ + "\xBE\x07\xE0\x01" + uc.mem_map(0, PAGE_SIZE) uc.mem_write(0, CODE) -uc.emu_start(0, len(CODE), 0, 24) +uc.emu_start(0, len(CODE), 0, 32) def print_registers(mu): g0 = mu.reg_read(UC_SPARC_REG_G0) @@ -146,9 +164,9 @@ def print_registers(mu): print_registers(uc) -assert uc.reg_read(UC_SPARC_REG_PC) == 96 # make sure we executed all instructions +assert uc.reg_read(UC_SPARC_REG_PC) == 128 # make sure we executed all instructions assert uc.reg_read(UC_SPARC_REG_SP) == 101 -assert uc.reg_read(UC_SPARC_REG_FP) == 200 +assert uc.reg_read(UC_SPARC_REG_FP) == 201 assert uc.reg_read(UC_SPARC_REG_G0) == 0 # G0 is always zero assert uc.reg_read(UC_SPARC_REG_G1) == 1 @@ -177,5 +195,11 @@ assert uc.reg_read(UC_SPARC_REG_L5) == 1 assert uc.reg_read(UC_SPARC_REG_L6) == 1 assert uc.reg_read(UC_SPARC_REG_L7) == 1 -assert uc.reg_read(UC_SPARC_REG_O0) == 1 -assert uc.reg_read(UC_SPARC_REG_L0) == 1 \ No newline at end of file +assert uc.reg_read(UC_SPARC_REG_I0) == 1 +assert uc.reg_read(UC_SPARC_REG_I1) == 1 +assert uc.reg_read(UC_SPARC_REG_I2) == 1 +assert uc.reg_read(UC_SPARC_REG_I3) == 1 +assert uc.reg_read(UC_SPARC_REG_I4) == 1 +assert uc.reg_read(UC_SPARC_REG_I5) == 1 +assert uc.reg_read(UC_SPARC_REG_I6) == 201 +assert uc.reg_read(UC_SPARC_REG_I7) == 1 \ No newline at end of file From 7eaedc5c15563ab4092bb9583124b0e241dc93d8 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 15 Sep 2015 14:16:57 +0700 Subject: [PATCH 13/66] add a comment for Arm instruction in regress/arm_movr12_hang.py --- regress/arm_movr12_hang.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/regress/arm_movr12_hang.py b/regress/arm_movr12_hang.py index 8847694c..befa4889 100755 --- a/regress/arm_movr12_hang.py +++ b/regress/arm_movr12_hang.py @@ -5,7 +5,7 @@ from unicorn.arm_const import * uc = Uc(UC_ARCH_ARM, UC_MODE_ARM) uc.mem_map(0x1000, 0x1000) -uc.mem_write(0x1000, '00c000e3'.decode('hex')) +uc.mem_write(0x1000, '00c000e3'.decode('hex')) # movw r12, #0 def hook_block(uc, addr, *args): print 'enter block 0x%04x' % addr From fe807952d0c559ca9a6158136bfe35c27adba250 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 15 Sep 2015 14:17:57 +0700 Subject: [PATCH 14/66] bindings: update Sparc registers after the last core change --- bindings/go/unicorn/sparc_const.go | 38 +++++++++++++------------- bindings/java/unicorn/SparcConst.java | 38 +++++++++++++------------- bindings/python/unicorn/sparc_const.py | 38 +++++++++++++------------- 3 files changed, 57 insertions(+), 57 deletions(-) diff --git a/bindings/go/unicorn/sparc_const.go b/bindings/go/unicorn/sparc_const.go index 51e209f2..afd94f45 100644 --- a/bindings/go/unicorn/sparc_const.go +++ b/bindings/go/unicorn/sparc_const.go @@ -57,21 +57,21 @@ const ( SPARC_REG_FCC1 = 50 SPARC_REG_FCC2 = 51 SPARC_REG_FCC3 = 52 - SPARC_REG_FP = 53 - SPARC_REG_G0 = 54 - SPARC_REG_G1 = 55 - SPARC_REG_G2 = 56 - SPARC_REG_G3 = 57 - SPARC_REG_G4 = 58 - SPARC_REG_G5 = 59 - SPARC_REG_G6 = 60 - SPARC_REG_G7 = 61 - SPARC_REG_I0 = 62 - SPARC_REG_I1 = 63 - SPARC_REG_I2 = 64 - SPARC_REG_I3 = 65 - SPARC_REG_I4 = 66 - SPARC_REG_I5 = 67 + SPARC_REG_G0 = 53 + SPARC_REG_G1 = 54 + SPARC_REG_G2 = 55 + SPARC_REG_G3 = 56 + SPARC_REG_G4 = 57 + SPARC_REG_G5 = 58 + SPARC_REG_G6 = 59 + SPARC_REG_G7 = 60 + SPARC_REG_I0 = 61 + SPARC_REG_I1 = 62 + SPARC_REG_I2 = 63 + SPARC_REG_I3 = 64 + SPARC_REG_I4 = 65 + SPARC_REG_I5 = 66 + SPARC_REG_FP = 67 SPARC_REG_I7 = 68 SPARC_REG_ICC = 69 SPARC_REG_L0 = 70 @@ -88,12 +88,12 @@ const ( SPARC_REG_O3 = 81 SPARC_REG_O4 = 82 SPARC_REG_O5 = 83 - SPARC_REG_O7 = 84 - SPARC_REG_SP = 85 + SPARC_REG_SP = 84 + SPARC_REG_O7 = 85 SPARC_REG_Y = 86 SPARC_REG_XCC = 87 SPARC_REG_PC = 88 SPARC_REG_ENDING = 89 - SPARC_REG_O6 = 85 - SPARC_REG_I6 = 53 + SPARC_REG_O6 = 84 + SPARC_REG_I6 = 67 ) \ No newline at end of file diff --git a/bindings/java/unicorn/SparcConst.java b/bindings/java/unicorn/SparcConst.java index bd00c736..de0dc184 100644 --- a/bindings/java/unicorn/SparcConst.java +++ b/bindings/java/unicorn/SparcConst.java @@ -59,21 +59,21 @@ public interface SparcConst { public static final int UC_SPARC_REG_FCC1 = 50; public static final int UC_SPARC_REG_FCC2 = 51; public static final int UC_SPARC_REG_FCC3 = 52; - public static final int UC_SPARC_REG_FP = 53; - public static final int UC_SPARC_REG_G0 = 54; - public static final int UC_SPARC_REG_G1 = 55; - public static final int UC_SPARC_REG_G2 = 56; - public static final int UC_SPARC_REG_G3 = 57; - public static final int UC_SPARC_REG_G4 = 58; - public static final int UC_SPARC_REG_G5 = 59; - public static final int UC_SPARC_REG_G6 = 60; - public static final int UC_SPARC_REG_G7 = 61; - public static final int UC_SPARC_REG_I0 = 62; - public static final int UC_SPARC_REG_I1 = 63; - public static final int UC_SPARC_REG_I2 = 64; - public static final int UC_SPARC_REG_I3 = 65; - public static final int UC_SPARC_REG_I4 = 66; - public static final int UC_SPARC_REG_I5 = 67; + public static final int UC_SPARC_REG_G0 = 53; + public static final int UC_SPARC_REG_G1 = 54; + public static final int UC_SPARC_REG_G2 = 55; + public static final int UC_SPARC_REG_G3 = 56; + public static final int UC_SPARC_REG_G4 = 57; + public static final int UC_SPARC_REG_G5 = 58; + public static final int UC_SPARC_REG_G6 = 59; + public static final int UC_SPARC_REG_G7 = 60; + public static final int UC_SPARC_REG_I0 = 61; + public static final int UC_SPARC_REG_I1 = 62; + public static final int UC_SPARC_REG_I2 = 63; + public static final int UC_SPARC_REG_I3 = 64; + public static final int UC_SPARC_REG_I4 = 65; + public static final int UC_SPARC_REG_I5 = 66; + public static final int UC_SPARC_REG_FP = 67; public static final int UC_SPARC_REG_I7 = 68; public static final int UC_SPARC_REG_ICC = 69; public static final int UC_SPARC_REG_L0 = 70; @@ -90,13 +90,13 @@ public interface SparcConst { public static final int UC_SPARC_REG_O3 = 81; public static final int UC_SPARC_REG_O4 = 82; public static final int UC_SPARC_REG_O5 = 83; - public static final int UC_SPARC_REG_O7 = 84; - public static final int UC_SPARC_REG_SP = 85; + public static final int UC_SPARC_REG_SP = 84; + public static final int UC_SPARC_REG_O7 = 85; public static final int UC_SPARC_REG_Y = 86; public static final int UC_SPARC_REG_XCC = 87; public static final int UC_SPARC_REG_PC = 88; public static final int UC_SPARC_REG_ENDING = 89; - public static final int UC_SPARC_REG_O6 = 85; - public static final int UC_SPARC_REG_I6 = 53; + public static final int UC_SPARC_REG_O6 = 84; + public static final int UC_SPARC_REG_I6 = 67; } diff --git a/bindings/python/unicorn/sparc_const.py b/bindings/python/unicorn/sparc_const.py index cb66d89c..7bd326d0 100644 --- a/bindings/python/unicorn/sparc_const.py +++ b/bindings/python/unicorn/sparc_const.py @@ -55,21 +55,21 @@ UC_SPARC_REG_FCC0 = 49 UC_SPARC_REG_FCC1 = 50 UC_SPARC_REG_FCC2 = 51 UC_SPARC_REG_FCC3 = 52 -UC_SPARC_REG_FP = 53 -UC_SPARC_REG_G0 = 54 -UC_SPARC_REG_G1 = 55 -UC_SPARC_REG_G2 = 56 -UC_SPARC_REG_G3 = 57 -UC_SPARC_REG_G4 = 58 -UC_SPARC_REG_G5 = 59 -UC_SPARC_REG_G6 = 60 -UC_SPARC_REG_G7 = 61 -UC_SPARC_REG_I0 = 62 -UC_SPARC_REG_I1 = 63 -UC_SPARC_REG_I2 = 64 -UC_SPARC_REG_I3 = 65 -UC_SPARC_REG_I4 = 66 -UC_SPARC_REG_I5 = 67 +UC_SPARC_REG_G0 = 53 +UC_SPARC_REG_G1 = 54 +UC_SPARC_REG_G2 = 55 +UC_SPARC_REG_G3 = 56 +UC_SPARC_REG_G4 = 57 +UC_SPARC_REG_G5 = 58 +UC_SPARC_REG_G6 = 59 +UC_SPARC_REG_G7 = 60 +UC_SPARC_REG_I0 = 61 +UC_SPARC_REG_I1 = 62 +UC_SPARC_REG_I2 = 63 +UC_SPARC_REG_I3 = 64 +UC_SPARC_REG_I4 = 65 +UC_SPARC_REG_I5 = 66 +UC_SPARC_REG_FP = 67 UC_SPARC_REG_I7 = 68 UC_SPARC_REG_ICC = 69 UC_SPARC_REG_L0 = 70 @@ -86,11 +86,11 @@ UC_SPARC_REG_O2 = 80 UC_SPARC_REG_O3 = 81 UC_SPARC_REG_O4 = 82 UC_SPARC_REG_O5 = 83 -UC_SPARC_REG_O7 = 84 -UC_SPARC_REG_SP = 85 +UC_SPARC_REG_SP = 84 +UC_SPARC_REG_O7 = 85 UC_SPARC_REG_Y = 86 UC_SPARC_REG_XCC = 87 UC_SPARC_REG_PC = 88 UC_SPARC_REG_ENDING = 89 -UC_SPARC_REG_O6 = 85 -UC_SPARC_REG_I6 = 53 +UC_SPARC_REG_O6 = 84 +UC_SPARC_REG_I6 = 67 From 893e6abcbdb99fd4e4f9a89da65a17578f2a4c23 Mon Sep 17 00:00:00 2001 From: mothran Date: Tue, 15 Sep 2015 23:12:03 -0700 Subject: [PATCH 15/66] first atttempt at SPARC64 fixes, no longer SEGV's, set CPU model to: Sun UltraSparc IV --- qemu/hw/sparc64/sun4u.c | 10 +++++++--- qemu/target-sparc/unicorn64.c | 22 +++++++++++++++++++++- regress/sparc64.py | 19 ++++++++++++++++--- 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/qemu/hw/sparc64/sun4u.c b/qemu/hw/sparc64/sun4u.c index ccfea62e..e7d619f5 100644 --- a/qemu/hw/sparc64/sun4u.c +++ b/qemu/hw/sparc64/sun4u.c @@ -33,19 +33,23 @@ static void sun4u_init(struct uc_struct *uc, MachineState *machine) { const char *cpu_model = machine->cpu_model; + SPARCCPU *cpu; if (cpu_model == NULL) - cpu_model = "sun4uv"; + cpu_model = "Sun UltraSparc IV"; - if (cpu_sparc_init(uc, cpu_model) == NULL) { + cpu = cpu_sparc_init(uc, cpu_model); + if (cpu == NULL) { fprintf(stderr, "Unable to find Sparc CPU definition\n"); exit(1); } + + cpu_sparc_set_id(&cpu->env, 0); } void sun4u_machine_init(struct uc_struct *uc) { - QEMUMachine sun4u_machine = { + static QEMUMachine sun4u_machine = { .name = "sun4u", .init = sun4u_init, .max_cpus = 1, // XXX for now diff --git a/qemu/target-sparc/unicorn64.c b/qemu/target-sparc/unicorn64.c index a3700db0..a51272de 100644 --- a/qemu/target-sparc/unicorn64.c +++ b/qemu/target-sparc/unicorn64.c @@ -6,6 +6,7 @@ #include "sysemu/cpus.h" #include "unicorn.h" #include "cpu.h" +#include "unicorn_common.h" #define READ_QWORD(x) ((uint64)x) @@ -15,6 +16,22 @@ #define READ_BYTE_L(x) (x & 0xff) +static bool sparc_stop_interrupt(int intno) +{ + switch(intno) { + default: + return false; + case TT_ILL_INSN: + return true; + } +} + +static void sparc_set_pc(struct uc_struct *uc, uint64_t address) +{ + ((CPUSPARCState *)uc->current_cpu->env_ptr)->pc = address; + ((CPUSPARCState *)uc->current_cpu->env_ptr)->npc = address + 4; +} + void sparc_reg_reset(struct uc_struct *uc) { CPUArchState *env = first_cpu->env_ptr; @@ -75,7 +92,7 @@ int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) default: break; case UC_SPARC_REG_PC: SPARC_CPU(uc, mycpu)->env.pc = *(uint64_t *)value; - SPARC_CPU(uc, mycpu)->env.npc = *(uint64_t *)value + 8; + SPARC_CPU(uc, mycpu)->env.npc = *(uint64_t *)value + 4; break; } } @@ -93,4 +110,7 @@ void sparc64_uc_init(struct uc_struct* uc) uc->reg_read = sparc_reg_read; uc->reg_write = sparc_reg_write; uc->reg_reset = sparc_reg_reset; + uc->set_pc = sparc_set_pc; + uc->stop_interrupt = sparc_stop_interrupt; + uc_common_init(uc); } diff --git a/regress/sparc64.py b/regress/sparc64.py index e59412dc..f68e09a3 100755 --- a/regress/sparc64.py +++ b/regress/sparc64.py @@ -3,9 +3,22 @@ from unicorn import * from unicorn.sparc_const import * +PAGE_SIZE = 1 * 1024 * 1024 + uc = Uc(UC_ARCH_SPARC, UC_MODE_64) uc.reg_write(UC_SPARC_REG_SP, 100) -uc.reg_write(UC_SPARC_REG_FP, 100) -print 'writing sp = 100, fp = 100' +print 'writing sp = 100, %%i0 = 2000' + + # 0: b0 06 20 01 inc %i0 + # 4: b2 06 60 01 inc %i1 + +CODE = "\xb0\x06\x20\x01" \ + "\xb2\x06\x60\x01" + +uc.mem_map(0, PAGE_SIZE) +uc.mem_write(0, CODE) +uc.emu_start(0, len(CODE), 0, 2) + print 'sp =', uc.reg_read(UC_SPARC_REG_SP) -print 'fp =', uc.reg_read(UC_SPARC_REG_FP) +print 'i0 =', uc.reg_read(UC_SPARC_REG_I0) +print 'i1 =', uc.reg_read(UC_SPARC_REG_I1) From f36bd83f854640e595d3ece3e887190fe9fdcc60 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Wed, 16 Sep 2015 15:46:10 +0700 Subject: [PATCH 16/66] cleanup regress/sparc*.py --- regress/sparc64.py | 8 +- regress/sparc_reg.py | 278 +++++++++++++++++++++---------------------- 2 files changed, 143 insertions(+), 143 deletions(-) diff --git a/regress/sparc64.py b/regress/sparc64.py index f68e09a3..27210bd1 100755 --- a/regress/sparc64.py +++ b/regress/sparc64.py @@ -7,13 +7,13 @@ PAGE_SIZE = 1 * 1024 * 1024 uc = Uc(UC_ARCH_SPARC, UC_MODE_64) uc.reg_write(UC_SPARC_REG_SP, 100) -print 'writing sp = 100, %%i0 = 2000' +print 'writing sp = 100' - # 0: b0 06 20 01 inc %i0 - # 4: b2 06 60 01 inc %i1 + # 0: b0 06 20 01 inc %i0 + # 4: b2 06 60 01 inc %i1 CODE = "\xb0\x06\x20\x01" \ - "\xb2\x06\x60\x01" + "\xb2\x06\x60\x01" uc.mem_map(0, PAGE_SIZE) uc.mem_write(0, CODE) diff --git a/regress/sparc_reg.py b/regress/sparc_reg.py index 99c34cdc..326d00e4 100755 --- a/regress/sparc_reg.py +++ b/regress/sparc_reg.py @@ -9,72 +9,72 @@ uc = Uc(UC_ARCH_SPARC, UC_MODE_32) uc.reg_write(UC_SPARC_REG_SP, 100) uc.reg_write(UC_SPARC_REG_FP, 200) - # 0x0: \x80\x00\x20\x01 add %g0, 1, %g0 - # 0x4: \x82\x00\x60\x01 add %g1, 1, %g1 - # 0x8: \x84\x00\xA0\x01 add %g2, 1, %g2 - # 0xc: \x86\x00\xE0\x01 add %g3, 1, %g3 - # 0x10: \x88\x01\x20\x01 add %g4, 1, %g4 - # 0x14: \x8A\x01\x60\x01 add %g5, 1, %g5 - # 0x18: \x8C\x01\xA0\x01 add %g6, 1, %g6 - # 0x1c: \x8E\x01\xE0\x01 add %g7, 1, %g7 - # 0x20: \x90\x02\x20\x01 add %o0, 1, %o0 - # 0x24: \x92\x02\x60\x01 add %o1, 1, %o1 - # 0x28: \x94\x02\xA0\x01 add %o2, 1, %o2 - # 0x2c: \x96\x02\xE0\x01 add %o3, 1, %o3 - # 0x30: \x98\x03\x20\x01 add %o4, 1, %o4 - # 0x34: \x9A\x03\x60\x01 add %o5, 1, %o5 - # 0x38: \x9C\x03\xA0\x01 add %sp, 1, %sp - # 0x3c: \x9E\x03\xE0\x01 add %o7, 1, %o7 - # 0x40: \xA0\x04\x20\x01 add %l0, 1, %l0 - # 0x44: \xA2\x04\x60\x01 add %l1, 1, %l1 - # 0x48: \xA4\x04\xA0\x01 add %l2, 1, %l2 - # 0x4c: \xA6\x04\xE0\x01 add %l3, 1, %l3 - # 0x50: \xA8\x05\x20\x01 add %l4, 1, %l4 - # 0x54: \xAA\x05\x60\x01 add %l5, 1, %l5 - # 0x58: \xAC\x05\xA0\x01 add %l6, 1, %l6 - # 0x5c: \xAE\x05\xE0\x01 add %l7, 1, %l7 - # 0x0: \xB0\x06\x20\x01 add %i0, 1, %i0 - # 0x4: \xB2\x06\x60\x01 add %i1, 1, %i1 - # 0x8: \xB4\x06\xA0\x01 add %i2, 1, %i2 - # 0xc: \xB6\x06\xE0\x01 add %i3, 1, %i3 - # 0x10: \xB8\x07\x20\x01 add %i4, 1, %i4 - # 0x14: \xBA\x07\x60\x01 add %i5, 1, %i5 - # 0x18: \xBC\x07\xA0\x01 add %fp, 1, %fp - # 0x1c: \xBE\x07\xE0\x01 add %i7, 1, %i7 + # 0x0: \x80\x00\x20\x01 add %g0, 1, %g0 + # 0x4: \x82\x00\x60\x01 add %g1, 1, %g1 + # 0x8: \x84\x00\xA0\x01 add %g2, 1, %g2 + # 0xc: \x86\x00\xE0\x01 add %g3, 1, %g3 + # 0x10: \x88\x01\x20\x01 add %g4, 1, %g4 + # 0x14: \x8A\x01\x60\x01 add %g5, 1, %g5 + # 0x18: \x8C\x01\xA0\x01 add %g6, 1, %g6 + # 0x1c: \x8E\x01\xE0\x01 add %g7, 1, %g7 + # 0x20: \x90\x02\x20\x01 add %o0, 1, %o0 + # 0x24: \x92\x02\x60\x01 add %o1, 1, %o1 + # 0x28: \x94\x02\xA0\x01 add %o2, 1, %o2 + # 0x2c: \x96\x02\xE0\x01 add %o3, 1, %o3 + # 0x30: \x98\x03\x20\x01 add %o4, 1, %o4 + # 0x34: \x9A\x03\x60\x01 add %o5, 1, %o5 + # 0x38: \x9C\x03\xA0\x01 add %sp, 1, %sp + # 0x3c: \x9E\x03\xE0\x01 add %o7, 1, %o7 + # 0x40: \xA0\x04\x20\x01 add %l0, 1, %l0 + # 0x44: \xA2\x04\x60\x01 add %l1, 1, %l1 + # 0x48: \xA4\x04\xA0\x01 add %l2, 1, %l2 + # 0x4c: \xA6\x04\xE0\x01 add %l3, 1, %l3 + # 0x50: \xA8\x05\x20\x01 add %l4, 1, %l4 + # 0x54: \xAA\x05\x60\x01 add %l5, 1, %l5 + # 0x58: \xAC\x05\xA0\x01 add %l6, 1, %l6 + # 0x5c: \xAE\x05\xE0\x01 add %l7, 1, %l7 + # 0x0: \xB0\x06\x20\x01 add %i0, 1, %i0 + # 0x4: \xB2\x06\x60\x01 add %i1, 1, %i1 + # 0x8: \xB4\x06\xA0\x01 add %i2, 1, %i2 + # 0xc: \xB6\x06\xE0\x01 add %i3, 1, %i3 + # 0x10: \xB8\x07\x20\x01 add %i4, 1, %i4 + # 0x14: \xBA\x07\x60\x01 add %i5, 1, %i5 + # 0x18: \xBC\x07\xA0\x01 add %fp, 1, %fp + # 0x1c: \xBE\x07\xE0\x01 add %i7, 1, %i7 CODE = "\x80\x00\x20\x01" \ - "\x82\x00\x60\x01" \ - "\x84\x00\xA0\x01" \ - "\x86\x00\xE0\x01" \ - "\x88\x01\x20\x01" \ - "\x8A\x01\x60\x01" \ - "\x8C\x01\xA0\x01" \ - "\x8E\x01\xE0\x01" \ - "\x90\x02\x20\x01" \ - "\x92\x02\x60\x01" \ - "\x94\x02\xA0\x01" \ - "\x96\x02\xE0\x01" \ - "\x98\x03\x20\x01" \ - "\x9A\x03\x60\x01" \ - "\x9C\x03\xA0\x01" \ - "\x9E\x03\xE0\x01" \ - "\xA0\x04\x20\x01" \ - "\xA2\x04\x60\x01" \ - "\xA4\x04\xA0\x01" \ - "\xA6\x04\xE0\x01" \ - "\xA8\x05\x20\x01" \ - "\xAA\x05\x60\x01" \ - "\xAC\x05\xA0\x01" \ - "\xAE\x05\xE0\x01" \ - "\xB0\x06\x20\x01" \ - "\xB2\x06\x60\x01" \ - "\xB4\x06\xA0\x01" \ - "\xB6\x06\xE0\x01" \ - "\xB8\x07\x20\x01" \ - "\xBA\x07\x60\x01" \ - "\xBC\x07\xA0\x01" \ - "\xBE\x07\xE0\x01" + "\x82\x00\x60\x01" \ + "\x84\x00\xA0\x01" \ + "\x86\x00\xE0\x01" \ + "\x88\x01\x20\x01" \ + "\x8A\x01\x60\x01" \ + "\x8C\x01\xA0\x01" \ + "\x8E\x01\xE0\x01" \ + "\x90\x02\x20\x01" \ + "\x92\x02\x60\x01" \ + "\x94\x02\xA0\x01" \ + "\x96\x02\xE0\x01" \ + "\x98\x03\x20\x01" \ + "\x9A\x03\x60\x01" \ + "\x9C\x03\xA0\x01" \ + "\x9E\x03\xE0\x01" \ + "\xA0\x04\x20\x01" \ + "\xA2\x04\x60\x01" \ + "\xA4\x04\xA0\x01" \ + "\xA6\x04\xE0\x01" \ + "\xA8\x05\x20\x01" \ + "\xAA\x05\x60\x01" \ + "\xAC\x05\xA0\x01" \ + "\xAE\x05\xE0\x01" \ + "\xB0\x06\x20\x01" \ + "\xB2\x06\x60\x01" \ + "\xB4\x06\xA0\x01" \ + "\xB6\x06\xE0\x01" \ + "\xB8\x07\x20\x01" \ + "\xBA\x07\x60\x01" \ + "\xBC\x07\xA0\x01" \ + "\xBE\x07\xE0\x01" uc.mem_map(0, PAGE_SIZE) @@ -82,85 +82,85 @@ uc.mem_write(0, CODE) uc.emu_start(0, len(CODE), 0, 32) def print_registers(mu): - g0 = mu.reg_read(UC_SPARC_REG_G0) - g1 = mu.reg_read(UC_SPARC_REG_G1) - g2 = mu.reg_read(UC_SPARC_REG_G2) - g3 = mu.reg_read(UC_SPARC_REG_G3) - g4 = mu.reg_read(UC_SPARC_REG_G4) - g5 = mu.reg_read(UC_SPARC_REG_G5) - g6 = mu.reg_read(UC_SPARC_REG_G6) - g7 = mu.reg_read(UC_SPARC_REG_G7) + g0 = mu.reg_read(UC_SPARC_REG_G0) + g1 = mu.reg_read(UC_SPARC_REG_G1) + g2 = mu.reg_read(UC_SPARC_REG_G2) + g3 = mu.reg_read(UC_SPARC_REG_G3) + g4 = mu.reg_read(UC_SPARC_REG_G4) + g5 = mu.reg_read(UC_SPARC_REG_G5) + g6 = mu.reg_read(UC_SPARC_REG_G6) + g7 = mu.reg_read(UC_SPARC_REG_G7) - o0 = mu.reg_read(UC_SPARC_REG_O0) - o1 = mu.reg_read(UC_SPARC_REG_O1) - o2 = mu.reg_read(UC_SPARC_REG_O2) - o3 = mu.reg_read(UC_SPARC_REG_O3) - o4 = mu.reg_read(UC_SPARC_REG_O4) - o5 = mu.reg_read(UC_SPARC_REG_O5) - o6 = mu.reg_read(UC_SPARC_REG_O6) - o7 = mu.reg_read(UC_SPARC_REG_O7) + o0 = mu.reg_read(UC_SPARC_REG_O0) + o1 = mu.reg_read(UC_SPARC_REG_O1) + o2 = mu.reg_read(UC_SPARC_REG_O2) + o3 = mu.reg_read(UC_SPARC_REG_O3) + o4 = mu.reg_read(UC_SPARC_REG_O4) + o5 = mu.reg_read(UC_SPARC_REG_O5) + o6 = mu.reg_read(UC_SPARC_REG_O6) + o7 = mu.reg_read(UC_SPARC_REG_O7) - l0 = mu.reg_read(UC_SPARC_REG_L0) - l1 = mu.reg_read(UC_SPARC_REG_L1) - l2 = mu.reg_read(UC_SPARC_REG_L2) - l3 = mu.reg_read(UC_SPARC_REG_L3) - l4 = mu.reg_read(UC_SPARC_REG_L4) - l5 = mu.reg_read(UC_SPARC_REG_L5) - l6 = mu.reg_read(UC_SPARC_REG_L6) - l7 = mu.reg_read(UC_SPARC_REG_L7) + l0 = mu.reg_read(UC_SPARC_REG_L0) + l1 = mu.reg_read(UC_SPARC_REG_L1) + l2 = mu.reg_read(UC_SPARC_REG_L2) + l3 = mu.reg_read(UC_SPARC_REG_L3) + l4 = mu.reg_read(UC_SPARC_REG_L4) + l5 = mu.reg_read(UC_SPARC_REG_L5) + l6 = mu.reg_read(UC_SPARC_REG_L6) + l7 = mu.reg_read(UC_SPARC_REG_L7) - i0 = mu.reg_read(UC_SPARC_REG_I0) - i1 = mu.reg_read(UC_SPARC_REG_I1) - i2 = mu.reg_read(UC_SPARC_REG_I2) - i3 = mu.reg_read(UC_SPARC_REG_I3) - i4 = mu.reg_read(UC_SPARC_REG_I4) - i5 = mu.reg_read(UC_SPARC_REG_I5) - i6 = mu.reg_read(UC_SPARC_REG_I6) - i7 = mu.reg_read(UC_SPARC_REG_I7) + i0 = mu.reg_read(UC_SPARC_REG_I0) + i1 = mu.reg_read(UC_SPARC_REG_I1) + i2 = mu.reg_read(UC_SPARC_REG_I2) + i3 = mu.reg_read(UC_SPARC_REG_I3) + i4 = mu.reg_read(UC_SPARC_REG_I4) + i5 = mu.reg_read(UC_SPARC_REG_I5) + i6 = mu.reg_read(UC_SPARC_REG_I6) + i7 = mu.reg_read(UC_SPARC_REG_I7) - pc = mu.reg_read(UC_SPARC_REG_PC) - sp = mu.reg_read(UC_SPARC_REG_SP) - fp = mu.reg_read(UC_SPARC_REG_FP) - print(" G0 = %d" % g0) - print(" G1 = %d" % g1) - print(" G2 = %d" % g2) - print(" G3 = %d" % g3) - print(" G4 = %d" % g4) - print(" G5 = %d" % g5) - print(" G6 = %d" % g6) - print(" G7 = %d" % g7) - print("") - print(" O0 = %d" % o0) - print(" O1 = %d" % o1) - print(" O2 = %d" % o2) - print(" O3 = %d" % o3) - print(" O4 = %d" % o4) - print(" O5 = %d" % o5) - print(" O6 = %d" % o6) - print(" O7 = %d" % o7) - print("") - print(" L0 = %d" % l0) - print(" L1 = %d" % l1) - print(" L2 = %d" % l2) - print(" L3 = %d" % l3) - print(" L4 = %d" % l4) - print(" L5 = %d" % l5) - print(" L6 = %d" % l6) - print(" L7 = %d" % l7) - print("") - print(" I0 = %d" % i0) - print(" I1 = %d" % i1) - print(" I2 = %d" % i2) - print(" I3 = %d" % i3) - print(" I4 = %d" % i4) - print(" I5 = %d" % i5) - print(" I6 = %d" % i6) - print(" I7 = %d" % i7) - print("") - print(" PC = %d" % pc) - print(" SP = %d" % sp) - print(" FP = %d" % fp) - print("") + pc = mu.reg_read(UC_SPARC_REG_PC) + sp = mu.reg_read(UC_SPARC_REG_SP) + fp = mu.reg_read(UC_SPARC_REG_FP) + print(" G0 = %d" % g0) + print(" G1 = %d" % g1) + print(" G2 = %d" % g2) + print(" G3 = %d" % g3) + print(" G4 = %d" % g4) + print(" G5 = %d" % g5) + print(" G6 = %d" % g6) + print(" G7 = %d" % g7) + print("") + print(" O0 = %d" % o0) + print(" O1 = %d" % o1) + print(" O2 = %d" % o2) + print(" O3 = %d" % o3) + print(" O4 = %d" % o4) + print(" O5 = %d" % o5) + print(" O6 = %d" % o6) + print(" O7 = %d" % o7) + print("") + print(" L0 = %d" % l0) + print(" L1 = %d" % l1) + print(" L2 = %d" % l2) + print(" L3 = %d" % l3) + print(" L4 = %d" % l4) + print(" L5 = %d" % l5) + print(" L6 = %d" % l6) + print(" L7 = %d" % l7) + print("") + print(" I0 = %d" % i0) + print(" I1 = %d" % i1) + print(" I2 = %d" % i2) + print(" I3 = %d" % i3) + print(" I4 = %d" % i4) + print(" I5 = %d" % i5) + print(" I6 = %d" % i6) + print(" I7 = %d" % i7) + print("") + print(" PC = %d" % pc) + print(" SP = %d" % sp) + print(" FP = %d" % fp) + print("") print_registers(uc) @@ -202,4 +202,4 @@ assert uc.reg_read(UC_SPARC_REG_I3) == 1 assert uc.reg_read(UC_SPARC_REG_I4) == 1 assert uc.reg_read(UC_SPARC_REG_I5) == 1 assert uc.reg_read(UC_SPARC_REG_I6) == 201 -assert uc.reg_read(UC_SPARC_REG_I7) == 1 \ No newline at end of file +assert uc.reg_read(UC_SPARC_REG_I7) == 1 From d6b9c31dc9bc90f68ecf510b5b612949ac06c9fd Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Wed, 16 Sep 2015 16:04:12 +0700 Subject: [PATCH 17/66] sparc: more cleanup --- qemu/hw/sparc64/sun4u.c | 2 -- qemu/target-sparc/unicorn.c | 6 ------ qemu/target-sparc/unicorn64.c | 6 ------ 3 files changed, 14 deletions(-) diff --git a/qemu/hw/sparc64/sun4u.c b/qemu/hw/sparc64/sun4u.c index e7d619f5..7377a023 100644 --- a/qemu/hw/sparc64/sun4u.c +++ b/qemu/hw/sparc64/sun4u.c @@ -43,8 +43,6 @@ static void sun4u_init(struct uc_struct *uc, MachineState *machine) fprintf(stderr, "Unable to find Sparc CPU definition\n"); exit(1); } - - cpu_sparc_set_id(&cpu->env, 0); } void sun4u_machine_init(struct uc_struct *uc) diff --git a/qemu/target-sparc/unicorn.c b/qemu/target-sparc/unicorn.c index b8ea29d8..d86497b5 100644 --- a/qemu/target-sparc/unicorn.c +++ b/qemu/target-sparc/unicorn.c @@ -69,12 +69,6 @@ int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value) return 0; } - -#define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff)) -#define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff)) -#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff)) -#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) - int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { CPUState *mycpu = first_cpu; diff --git a/qemu/target-sparc/unicorn64.c b/qemu/target-sparc/unicorn64.c index a51272de..e9257b75 100644 --- a/qemu/target-sparc/unicorn64.c +++ b/qemu/target-sparc/unicorn64.c @@ -69,12 +69,6 @@ int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value) return 0; } - -#define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff)) -#define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff)) -#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff)) -#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) - int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { CPUState *mycpu = first_cpu; From 5005b4a6e2a4493d4cff435dcade4e9331b11659 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 17 Sep 2015 09:16:57 +0700 Subject: [PATCH 18/66] arm: early check to see if the address of this block is the until address --- qemu/target-arm/translate.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/qemu/target-arm/translate.c b/qemu/target-arm/translate.c index a3829ca2..8875b641 100644 --- a/qemu/target-arm/translate.c +++ b/qemu/target-arm/translate.c @@ -11228,6 +11228,13 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, tcg_clear_temp_count(); + // Unicorn: early check to see if the address of this block is the until address + if (tb->pc == env->uc->addr_end) { + gen_tb_start(tcg_ctx); + gen_exception_insn(dc, 0, EXCP_SWI, 0); + goto done_generating; + } + // Unicorn: trace this block on request // Only hook this block if it is not broken from previous translation due to // full translation cache From 8c163706e4d942ee858010a6902da95a7c75f2c3 Mon Sep 17 00:00:00 2001 From: danghvu Date: Wed, 16 Sep 2015 21:33:01 -0500 Subject: [PATCH 19/66] Fix issue #113, untracked reference --- bindings/python/unicorn/unicorn.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index 080481ce..f5e1c63e 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -141,6 +141,7 @@ class Uc(object): raise UcError(status) # internal mapping table to save callback & userdata self._callbacks = {} + self._ctype_cbs = {} self._callback_count = 0 @@ -261,6 +262,7 @@ class Uc(object): # save callback & user_data self._callback_count += 1 self._callbacks[self._callback_count] = (callback, user_data) + cb = None if htype in (UC_HOOK_BLOCK, UC_HOOK_CODE): begin = ctypes.c_uint64(arg1) @@ -293,6 +295,9 @@ class Uc(object): status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \ cb, ctypes.cast(self._callback_count, ctypes.c_void_p)) + # save the ctype function so gc will leave it alone. + self._ctype_cbs[self._callback_count] = cb + if status != UC_ERR_OK: raise UcError(status) From cbb2cf361824a82f1ab3f6eec1ceaa9ff09345b9 Mon Sep 17 00:00:00 2001 From: danghvu Date: Thu, 17 Sep 2015 15:45:15 -0500 Subject: [PATCH 20/66] Regress python testcases must define expected value via unittest --- regress/arm_bxeq_hang.py | 30 +++++++++---- regress/arm_movr12_hang.py | 37 +++++++++++----- regress/callback-pc.py | 54 +++++++++++++---------- regress/crash_tb.py | 33 ++++++++------ regress/deadlock_1.py | 17 ++++++-- regress/emu_stop_segfault.py | 21 ++++++--- regress/fpu_ip.py | 54 +++++++++++++---------- regress/fpu_ip64.py | 62 -------------------------- regress/fpu_mem_write.py | 37 +++++++++------- regress/hang.py | 36 +++++++++------- regress/jmp_ebx_hang.py | 56 ++++++++++++------------ regress/memmap.py | 38 +++++++++++++--- regress/memmap_assert.py | 8 ---- regress/memmap_segfault.py | 46 ++++++++++++-------- regress/memmap_segfault2.py | 8 ---- regress/memmap_weirdness.py | 12 ------ regress/mips_branch_delay.py | 44 +++++++++++-------- regress/mips_except.py | 53 ++++++++++++----------- regress/movsd.py | 19 +++++--- regress/pshufb.py | 19 +++++--- regress/reg_write_sign_extension.py | 22 +++++++--- regress/regress.py | 29 +++++++++++++ regress/wrong_rip.py | 67 +++++++++++++++++++++++------ regress/wrong_rip2.py | 32 -------------- regress/wrong_rip3.py | 23 ---------- regress/wrong_rip4.py | 32 -------------- regress/wrong_rip_arm.py | 35 ++++++++------- regress/wrong_sp_arm.py | 36 +++++++++------- regress/wrong_sp_arm64.py | 12 ------ 29 files changed, 501 insertions(+), 471 deletions(-) delete mode 100755 regress/fpu_ip64.py delete mode 100755 regress/memmap_assert.py delete mode 100755 regress/memmap_segfault2.py delete mode 100755 regress/memmap_weirdness.py create mode 100644 regress/regress.py delete mode 100755 regress/wrong_rip2.py delete mode 100755 regress/wrong_rip3.py delete mode 100755 regress/wrong_rip4.py delete mode 100755 regress/wrong_sp_arm64.py diff --git a/regress/arm_bxeq_hang.py b/regress/arm_bxeq_hang.py index 0e4a6116..b696112a 100755 --- a/regress/arm_bxeq_hang.py +++ b/regress/arm_bxeq_hang.py @@ -3,13 +3,25 @@ from unicorn import * from unicorn.arm_const import * -uc = Uc(UC_ARCH_ARM, UC_MODE_ARM) -uc.mem_map(0x1000, 0x1000) -uc.mem_write(0x1000, '1eff2f010000a0e1'.decode('hex')) -def hook_block(uc, addr, *args): - print 'enter block 0x%04x' % addr +import regress -uc.reg_write(UC_ARM_REG_LR, 0x1004) -uc.hook_add(UC_HOOK_BLOCK, hook_block) -print 'block should only run once' -uc.emu_start(0x1000, 0x1004, timeout=250) +class BxHang(regress.RegressTest): + + def runTest(self): + uc = Uc(UC_ARCH_ARM, UC_MODE_ARM) + uc.mem_map(0x1000, 0x1000) + uc.mem_write(0x1000, '1eff2f010000a0e1'.decode('hex')) + uc.count = 0 + def hook_block(uc, addr, *args): + print 'enter block 0x%04x' % addr + uc.count += 1 + + uc.reg_write(UC_ARM_REG_LR, 0x1004) + uc.hook_add(UC_HOOK_BLOCK, hook_block) + print 'block should only run once' + uc.emu_start(0x1000, 0x1004, timeout=500) + + self.assertEqual(uc.count, 1) + +if __name__ == '__main__': + regress.main() diff --git a/regress/arm_movr12_hang.py b/regress/arm_movr12_hang.py index befa4889..1bb276e0 100755 --- a/regress/arm_movr12_hang.py +++ b/regress/arm_movr12_hang.py @@ -3,15 +3,30 @@ from unicorn import * from unicorn.arm_const import * -uc = Uc(UC_ARCH_ARM, UC_MODE_ARM) -uc.mem_map(0x1000, 0x1000) -uc.mem_write(0x1000, '00c000e3'.decode('hex')) # movw r12, #0 -def hook_block(uc, addr, *args): - print 'enter block 0x%04x' % addr +import regress -uc.reg_write(UC_ARM_REG_R12, 0x123) -print 'r12 =', uc.reg_read(UC_ARM_REG_R12) -uc.hook_add(UC_HOOK_BLOCK, hook_block) -print 'block should only run once' -uc.emu_start(0x1000, 0x1004, timeout=250) -print 'r12 =', uc.reg_read(UC_ARM_REG_R12) +class MovHang(regress.RegressTest): + + def runTest(self): + uc = Uc(UC_ARCH_ARM, UC_MODE_ARM) + uc.mem_map(0x1000, 0x1000) + uc.mem_write(0x1000, '00c000e3'.decode('hex')) # movw r12, #0 + + def hook_block(uc, addr, *args): + print 'enter block 0x%04x' % addr + uc.count += 1 + + uc.reg_write(UC_ARM_REG_R12, 0x123) + self.assertEquals(uc.reg_read(UC_ARM_REG_R12), 0x123) + + uc.hook_add(UC_HOOK_BLOCK, hook_block) + uc.count = 0 + + #print 'block should only run once' + uc.emu_start(0x1000, 0x1004, timeout=500) + + self.assertEquals(uc.reg_read(UC_ARM_REG_R12), 0x0) + self.assertEquals(uc.count, 1) + +if __name__ == '__main__': + regress.main() diff --git a/regress/callback-pc.py b/regress/callback-pc.py index be35a244..3edc67e6 100755 --- a/regress/callback-pc.py +++ b/regress/callback-pc.py @@ -1,56 +1,64 @@ #!/usr/bin/env python # reg_write() can't modify PC from within trace callbacks +# Pull Request #4 from __future__ import print_function from unicorn import * from unicorn.arm_const import * +import regress + BASE_ADDRESS = 0x10000000 # sub sp, #0xc -THUMB_CODE = "\x83\xb0" * 5 +THUMB_CODE = "\x83\xb0" * 5 # callback for tracing instructions def hook_code(uc, address, size, user_data): print(">>> Tracing instruction at 0x%x, instruction size = %u" % (address, size)) mu = user_data print(">>> Setting PC to 0xffffffff") - mu.reg_write(ARM_REG_PC, 0xffffffff) + mu.reg_write(UC_ARM_REG_PC, 0xffffffff) # callback for tracing basic blocks def hook_block(uc, address, size, user_data): print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size)) mu = user_data print(">>> Setting PC to 0xffffffff") - mu.reg_write(ARM_REG_PC, 0xffffffff) + mu.reg_write(UC_ARM_REG_PC, 0xffffffff) -# set up emulation -def instruction_trace_test(): - try: - # initialize emulator in ARM's Thumb mode - mu = Uc(UC_ARCH_ARM, UC_MODE_THUMB) +class CallBackPCTest(regress.RegressTest): - # map some memory - mu.mem_map(BASE_ADDRESS, 2 * 1024 * 1024) + def runTest(self): + self.instruction_trace_test() - # write machine code to be emulated to memory - mu.mem_write(BASE_ADDRESS, THUMB_CODE) + # set up emulation + def instruction_trace_test(self): + try: + # initialize emulator in ARM's Thumb mode + mu = Uc(UC_ARCH_ARM, UC_MODE_THUMB) - # setup stack - mu.reg_write(UC_ARM_REG_SP, BASE_ADDRESS + 2 * 1024 * 1024) + # map some memory + mu.mem_map(BASE_ADDRESS, 2 * 1024 * 1024) - # tracing all instructions with customized callback - mu.hook_add(UC_HOOK_CODE, hook_code, user_data=mu) + # write machine code to be emulated to memory + mu.mem_write(BASE_ADDRESS, THUMB_CODE) - # tracing all basic blocks with customized callback - mu.hook_add(UC_HOOK_BLOCK, hook_block, user_data=mu) + # setup stack + mu.reg_write(UC_ARM_REG_SP, BASE_ADDRESS + 2 * 1024 * 1024) - # emulate machine code in infinite time - mu.emu_start(BASE_ADDRESS, BASE_ADDRESS + len(THUMB_CODE)) + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, hook_code, user_data=mu) - except UcError as e: - print("ERROR: %s" % e) + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, hook_block, user_data=mu) + + # emulate machine code in infinite time + mu.emu_start(BASE_ADDRESS, BASE_ADDRESS + len(THUMB_CODE)) + + except UcError as e: + assertFalse(0, "ERROR: %s" % e) if __name__ == '__main__': - instruction_trace_test() + regress.main() diff --git a/regress/crash_tb.py b/regress/crash_tb.py index d4f99723..9ecf61cd 100755 --- a/regress/crash_tb.py +++ b/regress/crash_tb.py @@ -3,30 +3,35 @@ from unicorn import * from unicorn.x86_const import * +import regress CODE_ADDR = 0x0 - - binary1 = b'\xb8\x02\x00\x00\x00' binary2 = b'\xb8\x01\x00\x00\x00' -mu = Uc(UC_ARCH_X86, UC_MODE_64) +class CrashTB(regress.RegressTest): -mu.mem_map(CODE_ADDR, 2 * 1024 * 1024) + def runTest(self): + mu = Uc(UC_ARCH_X86, UC_MODE_64) -# write machine code to be emulated to memory -mu.mem_write(CODE_ADDR, binary1) + mu.mem_map(CODE_ADDR, 2 * 1024 * 1024) -# emu for maximum 1 sec. -mu.emu_start(CODE_ADDR, len(binary1), UC_SECOND_SCALE) + # write machine code to be emulated to memory + mu.mem_write(CODE_ADDR, binary1) -print("RAX = %x" %mu.reg_read(UC_X86_REG_RAX)) + # emu for maximum 1 sec. + mu.emu_start(CODE_ADDR, len(binary1), UC_SECOND_SCALE) -# write machine code to be emulated to memory -mu.mem_write(CODE_ADDR, binary2) + self.assertEqual(0x2, mu.reg_read(UC_X86_REG_RAX)) -# emu for maximum 1 sec. -mu.emu_start(CODE_ADDR, len(binary2), UC_SECOND_SCALE) + # write machine code to be emulated to memory + mu.mem_write(CODE_ADDR, binary2) -print("RAX = %x" %mu.reg_read(UC_X86_REG_RAX)) + # emu for maximum 1 sec. + mu.emu_start(CODE_ADDR, len(binary2), UC_SECOND_SCALE) + + self.assertEqual(0x1, mu.reg_read(UC_X86_REG_RAX)) + +if __name__ == '__main__': + regress.main() diff --git a/regress/deadlock_1.py b/regress/deadlock_1.py index 702376a3..269a573f 100755 --- a/regress/deadlock_1.py +++ b/regress/deadlock_1.py @@ -2,10 +2,19 @@ # From issue #1 of Ryan Hileman from unicorn import * +import regress CODE = b"\x90\x91\x92" -mu = Uc(UC_ARCH_X86, UC_MODE_64) -mu.mem_map(0x100000, 4 * 1024) -mu.mem_write(0x100000, CODE) -mu.emu_start(0x100000, 0x1000 + len(CODE)) +class DeadLock(regress.RegressTest): + + def runTest(self): + mu = Uc(UC_ARCH_X86, UC_MODE_64) + mu.mem_map(0x100000, 4 * 1024) + mu.mem_write(0x100000, CODE) + + with self.assertRaises(UcError): + mu.emu_start(0x100000, 0x1000 + len(CODE)) + +if __name__ == '__main__': + regress.main() diff --git a/regress/emu_stop_segfault.py b/regress/emu_stop_segfault.py index 8021d86d..8c22e9de 100755 --- a/regress/emu_stop_segfault.py +++ b/regress/emu_stop_segfault.py @@ -3,11 +3,18 @@ """See https://github.com/unicorn-engine/unicorn/issues/65""" import unicorn -ADDR = 0x10101000 -mu = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32) -mu.mem_map(ADDR, 1024 * 4) -mu.mem_write(ADDR, b'\x41') -mu.emu_start(ADDR, ADDR + 1, count=1) -# The following should not trigger a null pointer dereference -mu.emu_stop() +import regress +class EmuStopSegFault(regress.RegressTest): + + def runTest(self): + ADDR = 0x10101000 + mu = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32) + mu.mem_map(ADDR, 1024 * 4) + mu.mem_write(ADDR, b'\x41') + mu.emu_start(ADDR, ADDR + 1, count=1) + # The following should not trigger a null pointer dereference + self.assertEqual(None, mu.emu_stop()) + +if __name__ == '__main__': + regress.main() diff --git a/regress/fpu_ip.py b/regress/fpu_ip.py index 77efa21b..3db6a8b5 100755 --- a/regress/fpu_ip.py +++ b/regress/fpu_ip.py @@ -2,6 +2,7 @@ from unicorn import * from unicorn.x86_const import * from capstone import * +import regress ESP = 0x2000 PAGE_SIZE = 2 * 1024 * 1024 @@ -29,33 +30,40 @@ def hook_code(uc, addr, size, user_data): print(" 0x%X:" % (addr)), disasm.disas_single(str(mem)) -def mem_reader(addr, size): - tmp = mu.mem_read(addr, size) +class FpuIP(regress.RegressTest): - for i in tmp: - print(" 0x%x" % i), - print("") + def mem_reader(self, mu, addr, size, expected): + tmp = mu.mem_read(addr, size) + for out, exp in zip(tmp, expected): + self.assertEqual(exp, out) + def test_32(self): + mu = Uc(UC_ARCH_X86, UC_MODE_32) -mu = Uc(UC_ARCH_X86, UC_MODE_32) + mu.mem_map(0x0, PAGE_SIZE) + mu.mem_write(0x4000, CODE) + mu.reg_write(UC_X86_REG_ESP, ESP) + mu.hook_add(UC_HOOK_CODE, hook_code) -mu.mem_map(0x0, PAGE_SIZE) -mu.mem_write(0x4000, CODE) -mu.reg_write(UC_X86_REG_ESP, ESP) -mu.hook_add(UC_HOOK_CODE, hook_code) + mu.emu_start(0x4000, 0, 0, 5) + esp = mu.reg_read(UC_X86_REG_ESP) + self.assertEqual(0x2004, esp) + expected = [0x0, 0x0, 0xa, 0x40] + self.mem_reader(mu, esp + 14, 4, expected) + def test_64(self): + mu = Uc(UC_ARCH_X86, UC_MODE_64) -mu.emu_start(0x4000, 0, 0, 5) -esp = mu.reg_read(UC_X86_REG_ESP) -print("value at ESP [0x%X - 4]: " % esp) -mem_reader(esp + 14, 4) + mu.mem_map(0x0, PAGE_SIZE) + mu.mem_write(0x4000, CODE) + mu.reg_write(UC_X86_REG_ESP, ESP) + mu.hook_add(UC_HOOK_CODE, hook_code) -# EXPECTED OUTPUT: -# 0x4000: mov dword ptr [esp], 0x37f -# 0x4007: fldcw word ptr [esp] -# 0x400A: fnop -# 0x400C: fnstenv dword ptr [esp + 8] -# 0x4010: pop ecx -# value at ESP [0x2004 - 4]: -# 0x0 0x0 0xa 0x40 -# ^ this value should match the fnop instuction addr \ No newline at end of file + mu.emu_start(0x4000, 0, 0, 5) + rsp = mu.reg_read(UC_X86_REG_RSP) + self.assertEqual(0x2012, rsp + 10) + expected = [0x0, 0x0, 0xa, 0x40, 0x0, 0x0, 0x0, 0x0] + self.mem_reader(mu, rsp + 10, 4, expected) + +if __name__ == '__main__': + regress.main() diff --git a/regress/fpu_ip64.py b/regress/fpu_ip64.py deleted file mode 100755 index dd0b5c1c..00000000 --- a/regress/fpu_ip64.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/python -from unicorn import * -from unicorn.x86_const import * -from capstone import * - -ESP = 0x2000 -PAGE_SIZE = 2 * 1024 * 1024 - -# mov [esp], DWORD 0x37f -# fldcw [esp] -# fnop -# fnstenv [esp + 8] -# pop ecx -CODE = "C704247F030000D92C24D9D0D974240859".decode('hex') - -class SimpleEngine: - def __init__(self): - self.capmd = Cs(CS_ARCH_X86, CS_MODE_64) - - def disas_single(self, data): - for i in self.capmd.disasm(data, 16): - print("\t%s\t%s" % (i.mnemonic, i.op_str)) - break - -disasm = SimpleEngine() - -def hook_code(uc, addr, size, user_data): - mem = uc.mem_read(addr, size) - print(" 0x%X:" % (addr)), - disasm.disas_single(str(mem)) - -def mem_reader(addr, size): - tmp = mu.mem_read(addr, size) - - for i in tmp: - print(" 0x%x" % i), - print("") - - -mu = Uc(UC_ARCH_X86, UC_MODE_64) - -mu.mem_map(0x0, PAGE_SIZE) -mu.mem_write(0x4000, CODE) -mu.reg_write(UC_X86_REG_RSP, ESP) -mu.hook_add(UC_HOOK_CODE, hook_code) - - -mu.emu_start(0x4000, 0, 0, 5) -rsp = mu.reg_read(UC_X86_REG_RSP) -print("Value of FPIP: [0x%X]" % (rsp + 10)) -mem_reader(rsp + 10, 8) -# EXPECTED OUTPUT: - -# 0x4000: mov dword ptr [rsp], 0x37f -# 0x4007: fldcw word ptr [rsp] -# 0x400A: fnop -# 0x400C: fnstenv dword ptr [rsp + 8] -# 0x4010: pop rcx -# Value of FPIP: [0x2012] -# 0x0 0x0 0xa 0x40 0x0 0x0 0x0 0x0 - -# WHERE: the value of FPIP should be the address of fnop \ No newline at end of file diff --git a/regress/fpu_mem_write.py b/regress/fpu_mem_write.py index 730914a6..226a139e 100755 --- a/regress/fpu_mem_write.py +++ b/regress/fpu_mem_write.py @@ -2,6 +2,8 @@ from unicorn import * from unicorn.x86_const import * +import regress + ESP = 0x2000 PAGE_SIZE = 1 * 1024 * 1024 @@ -9,24 +11,27 @@ PAGE_SIZE = 1 * 1024 * 1024 # pop ecx CODE = b'\x9B\xD9\x3C\x24\x59' -def mem_reader(addr, size): - tmp = mu.mem_read(addr, size) - - for i in tmp: - print(" 0x%x" % i), - print("") - def hook_mem_write(uc, access, address, size, value, user_data): print("mem WRITE: 0x%x, data size = %u, data value = 0x%x" % (address, size, value)) return True -mu = Uc(UC_ARCH_X86, UC_MODE_32) -mu.mem_map(0, PAGE_SIZE) -mu.mem_write(0, CODE) -mu.reg_write(UC_X86_REG_ESP, ESP) -mu.hook_add(UC_HOOK_MEM_WRITE, hook_mem_write) +class FpuWrite(regress.RegressTest): -mu.emu_start(0x0, 0, 0, 2) -esp = mu.reg_read(UC_X86_REG_ESP) -print("value at ESP [0x%X]: " % esp) -mem_reader(esp, 10) \ No newline at end of file + def mem_reader(self, mu, addr, size, expected): + tmp = mu.mem_read(addr, size) + for i, e in zip(tmp, expected): + self.assertEquals(e, i) + + def runTest(self): + mu = Uc(UC_ARCH_X86, UC_MODE_32) + mu.mem_map(0, PAGE_SIZE) + mu.mem_write(0, CODE) + mu.reg_write(UC_X86_REG_ESP, ESP) + + mu.hook_add(UC_HOOK_MEM_WRITE, hook_mem_write) + mu.emu_start(0x0, 0, 0, 2) + esp = mu.reg_read(UC_X86_REG_ESP) + self.mem_reader(mu, esp, 10, [0] * 10) + +if __name__ == '__main__': + regress.main() diff --git a/regress/hang.py b/regress/hang.py index 50edaf2c..9c8a3775 100755 --- a/regress/hang.py +++ b/regress/hang.py @@ -4,6 +4,7 @@ from __future__ import print_function from unicorn import * from unicorn.x86_const import * +import regress # callback for tracing instructions def hook_code(uc, address, size, user_data): @@ -13,7 +14,6 @@ def hook_code(uc, address, size, user_data): print(" %02x" %i, end="") print("") - # callback for tracing Linux interrupt def hook_intr(uc, intno, user_data): # only handle Linux syscall @@ -26,28 +26,32 @@ def hook_intr(uc, intno, user_data): eax = uc.reg_read(UC_X86_REG_EAX) print(">>> 0x%x: interrupt 0x%x, EAX = 0x%x" %(rip, intno, eax)) +class Hang(regress.RegressTest): -binary1 = b'\xeb\x1c\x5a\x89\xd6\x8b\x02\x66\x3d\xca\x7d\x75\x06\x66\x05\x03\x03\x89\x02\xfe\xc2\x3d\x41\x41\x41\x41\x75\xe9\xff\xe6\xe8\xdf\xff\xff\xff\x31\xd2\x6a\x0b\x58\x99\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xca\x7d\x41\x41\x41\x41\x41\x41\x41\x41' + def runTest(self): + binary1 = b'\xeb\x1c\x5a\x89\xd6\x8b\x02\x66\x3d\xca\x7d\x75\x06\x66\x05\x03\x03\x89\x02\xfe\xc2\x3d\x41\x41\x41\x41\x75\xe9\xff\xe6\xe8\xdf\xff\xff\xff\x31\xd2\x6a\x0b\x58\x99\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xca\x7d\x41\x41\x41\x41\x41\x41\x41\x41' -mu = Uc(UC_ARCH_X86, UC_MODE_64) + mu = Uc(UC_ARCH_X86, UC_MODE_64) -mu.mem_map(0, 2 * 1024 * 1024) + mu.mem_map(0, 2 * 1024 * 1024) -# tracing all instructions with customized callback -mu.hook_add(UC_HOOK_CODE, hook_code) + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, hook_code) -# handle interrupt ourself -mu.hook_add(UC_HOOK_INTR, hook_intr) + # handle interrupt ourself + mu.hook_add(UC_HOOK_INTR, hook_intr) -# setup stack -mu.reg_write(UC_X86_REG_RSP, 1024 * 1024) + # setup stack + mu.reg_write(UC_X86_REG_RSP, 1024 * 1024) -# fill in memory with 0xCC (software breakpoint int 3) -for i in xrange(1 * 1024): - mu.mem_write(0 + i, b'\xcc') + # fill in memory with 0xCC (software breakpoint int 3) + for i in xrange(1 * 1024): + mu.mem_write(0 + i, b'\xcc') -# write machine code to be emulated to memory -mu.mem_write(0, binary1) + # write machine code to be emulated to memory + mu.mem_write(0, binary1) -mu.emu_start(0, len(binary1)) + self.assertEqual(mu.emu_start(0, len(binary1)), None) +if __name__ == '__main__': + regress.main() diff --git a/regress/jmp_ebx_hang.py b/regress/jmp_ebx_hang.py index 5683de89..602c594f 100755 --- a/regress/jmp_ebx_hang.py +++ b/regress/jmp_ebx_hang.py @@ -3,35 +3,37 @@ """See https://github.com/unicorn-engine/unicorn/issues/82""" import unicorn +from unicorn import * +import regress + CODE_ADDR = 0x10101000 CODE = b'\xff\xe3' # jmp ebx -mu = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32) -mu.mem_map(CODE_ADDR, 1024 * 4) -mu.mem_write(CODE_ADDR, CODE) -# If EBX is zero then an exception is raised, as expected -mu.reg_write(unicorn.x86_const.UC_X86_REG_EBX, 0x0) -print(">>> jmp ebx (ebx = 0)"); -try: - mu.emu_start(CODE_ADDR, CODE_ADDR + 2, count=1) -except unicorn.UcError as e: - print("ERROR: %s" % e) - assert(e.errno == unicorn.UC_ERR_CODE_INVALID) -else: - assert(False) +class JumEbxHang(regress.RegressTest): -print(">>> jmp ebx (ebx = 0xaa96a47f)"); -mu = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32) -mu.mem_map(CODE_ADDR, 1024 * 4) -# If we write this address to EBX then the emulator hangs on emu_start -mu.reg_write(unicorn.x86_const.UC_X86_REG_EBX, 0xaa96a47f) -mu.mem_write(CODE_ADDR, CODE) -try: - mu.emu_start(CODE_ADDR, CODE_ADDR + 2, count=1) -except unicorn.UcError as e: - print("ERROR: %s" % e) - assert(e.errno == unicorn.UC_ERR_CODE_INVALID) -else: - assert(False) + def runTest(self): + mu = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32) + mu.mem_map(CODE_ADDR, 1024 * 4) + mu.mem_write(CODE_ADDR, CODE) + # If EBX is zero then an exception is raised, as expected + mu.reg_write(unicorn.x86_const.UC_X86_REG_EBX, 0x0) -print "Success" + print(">>> jmp ebx (ebx = 0)"); + with self.assertRaises(UcError) as m: + mu.emu_start(CODE_ADDR, CODE_ADDR + 2, count=1) + + self.assertEqual(m.exception.errno, unicorn.UC_ERR_CODE_INVALID) + + print(">>> jmp ebx (ebx = 0xaa96a47f)"); + mu = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32) + mu.mem_map(CODE_ADDR, 1024 * 4) + # If we write this address to EBX then the emulator hangs on emu_start + mu.reg_write(unicorn.x86_const.UC_X86_REG_EBX, 0xaa96a47f) + mu.mem_write(CODE_ADDR, CODE) + with self.assertRaises(UcError) as m: + mu.emu_start(CODE_ADDR, CODE_ADDR + 2, count=1) + + self.assertEqual(m.exception.errno, unicorn.UC_ERR_CODE_INVALID) + +if __name__ == '__main__': + regress.main() diff --git a/regress/memmap.py b/regress/memmap.py index 2ac3508e..3252d51f 100755 --- a/regress/memmap.py +++ b/regress/memmap.py @@ -4,11 +4,37 @@ # this prints out 2 lines and the contents must be the same from unicorn import * -uc = Uc(UC_ARCH_X86, UC_MODE_64) +import regress -uc.mem_map(0x8048000, 0x2000) -uc.mem_write(0x8048000, 'test') -print 1, str(uc.mem_read(0x8048000, 4)).encode('hex') +class MemMap(regress.RegressTest): -uc.mem_map(0x804a000, 0x8000) -print 2, str(uc.mem_read(0x8048000, 4)).encode('hex') + def test_mmap_write(self): + uc = Uc(UC_ARCH_X86, UC_MODE_64) + + uc.mem_map(0x8048000, 0x2000) + uc.mem_write(0x8048000, 'test') + s1 = str(uc.mem_read(0x8048000, 4)).encode('hex') + + self.assertEqual('test'.encode('hex'), s1) + + uc.mem_map(0x804a000, 0x8000) + s2 = str(uc.mem_read(0x8048000, 4)).encode('hex') + self.assertEqual(s1, s2) + + def test_mmap_invalid(self): + u = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32) + with self.assertRaises(UcError): + u.mem_map(0x2000, 0) + with self.assertRaises(UcError): + u.mem_map(0x4000, 1) + + def test_mmap_weird(self): + u = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32) + + for i in xrange(20): + with self.assertRaises(UcError): + u.mem_map(i*0x1000, 5) + u.mem_read(i*0x1000+6, 1) + +if __name__ == '__main__': + regress.main() diff --git a/regress/memmap_assert.py b/regress/memmap_assert.py deleted file mode 100755 index cebdb8e1..00000000 --- a/regress/memmap_assert.py +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env python - -import unicorn - -u = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32) -u.mem_map(0x2000, 0) -u.mem_map(0x4000, 1) -print "I am never reached" diff --git a/regress/memmap_segfault.py b/regress/memmap_segfault.py index 83aea625..5d012b8b 100755 --- a/regress/memmap_segfault.py +++ b/regress/memmap_segfault.py @@ -1,25 +1,35 @@ #!/usr/bin/env python import unicorn +from unicorn import * -u = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32) -u.mem_map(0x2000, 0x1000) -u.mem_read(0x2000, 1) +import regress -for i in range(20): - try: +class MmapSeg(regress.RegressTest): + + def test_seg1(self): u = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32) - u.mem_map(i*0x1000, 5) - u.mem_read(i*0x1000, 1) - print hex(i*0x1000) + " succeeeded" - except unicorn.UcError: - print hex(i*0x1000) + " failed" + u.mem_map(0x2000, 0x1000) + u.mem_read(0x2000, 1) -for i in range(20): - try: - u = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32) - u.mem_map(i*0x1000, 5) - u.mem_read(i*0x1000, 1) - print hex(i*0x1000) + " succeeeded" - except unicorn.UcError: - print hex(i*0x1000) + " failed" + for i in range(50): + u = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32) + u.mem_map(i*0x1000, 0x1000) + u.mem_read(i*0x1000, 1) + + for i in range(20): + with self.assertRaises(UcError): + u = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32) + u.mem_map(i*0x1000, 5) + u.mem_read(i*0x1000, 1) + + def test_seg2(self): + uc = Uc(UC_ARCH_X86, UC_MODE_32) + uc.mem_map(0x0000, 0x2000) + uc.mem_map(0x2000, 0x4000) + uc.mem_write(0x1000, 0x1004 * ' ') + self.assertTrue(1, + 'If not reached, then we have BUG (crash on x86_64 Linux).') + +if __name__ == '__main__': + regress.main() diff --git a/regress/memmap_segfault2.py b/regress/memmap_segfault2.py deleted file mode 100755 index bd3845b7..00000000 --- a/regress/memmap_segfault2.py +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/python - -from unicorn import * -uc = Uc(UC_ARCH_X86, UC_MODE_32) -uc.mem_map(0x0000, 0x2000) -uc.mem_map(0x2000, 0x4000) -uc.mem_write(0x1000, 0x1004 * ' ') -print 'If not reached, then we have BUG (crash on x86_64 Linux).' diff --git a/regress/memmap_weirdness.py b/regress/memmap_weirdness.py deleted file mode 100755 index d81eccd6..00000000 --- a/regress/memmap_weirdness.py +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python - -import unicorn - -for i in range(20): - #try: - u = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32) - u.mem_map(i*0x1000, 5) - u.mem_read(i*0x1000+6, 1) - print hex(i*0x1000) + " succeeeded" - #except unicorn.UcError as e: - # print hex(i*0x1000) + " failed:",e diff --git a/regress/mips_branch_delay.py b/regress/mips_branch_delay.py index 50a71a6f..db1bc2ac 100755 --- a/regress/mips_branch_delay.py +++ b/regress/mips_branch_delay.py @@ -3,27 +3,35 @@ from capstone import * from unicorn import * from unicorn.mips_const import * -md = Cs(CS_ARCH_MIPS, CS_MODE_MIPS32 + CS_MODE_LITTLE_ENDIAN) +import regress -def disas(code, addr): - for i in md.disasm(code, addr): - print '0x%x: %s %s' % (i.address, str(i.bytes).encode('hex'), i.op_str) +class MipsBranchDelay(regress.RegressTest): -def hook_code(uc, addr, size, _): - mem = str(uc.mem_read(addr, size)) - disas(mem, addr) + def runTest(self): + md = Cs(CS_ARCH_MIPS, CS_MODE_MIPS32 + CS_MODE_LITTLE_ENDIAN) -CODE = 0x400000 -asm = '0000a4126a00822800000000'.decode('hex') + def disas(code, addr): + for i in md.disasm(code, addr): + print '0x%x: %s %s' % (i.address, str(i.bytes).encode('hex'), i.op_str) -print 'Input instructions:' -disas(asm, CODE) -print + def hook_code(uc, addr, size, _): + mem = str(uc.mem_read(addr, size)) + disas(mem, addr) -print 'Hooked instructions:' + CODE = 0x400000 + asm = '0000a4126a00822800000000'.decode('hex') -uc = Uc(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_LITTLE_ENDIAN) -uc.hook_add(UC_HOOK_CODE, hook_code) -uc.mem_map(CODE, 0x1000) -uc.mem_write(CODE, asm) -uc.emu_start(CODE, CODE + len(asm)) + print 'Input instructions:' + disas(asm, CODE) + print + + print 'Hooked instructions:' + + uc = Uc(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_LITTLE_ENDIAN) + uc.hook_add(UC_HOOK_CODE, hook_code) + uc.mem_map(CODE, 0x1000) + uc.mem_write(CODE, asm) + self.assertEqual(None, uc.emu_start(CODE, CODE + len(asm))) + +if __name__ == '__main__': + regress.main() diff --git a/regress/mips_except.py b/regress/mips_except.py index 28c8001e..23969e9e 100755 --- a/regress/mips_except.py +++ b/regress/mips_except.py @@ -2,37 +2,40 @@ from unicorn import * from unicorn.mips_const import * +import regress + def hook_intr(uc, intno, _): print 'interrupt', intno CODE = 0x400000 asm = '0000a48f'.decode('hex') # lw $a0, ($sp) -uc = Uc(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_LITTLE_ENDIAN) -uc.hook_add(UC_HOOK_INTR, hook_intr) -uc.mem_map(CODE, 0x1000) -uc.mem_write(CODE, asm) +class MipsExcept(regress.RegressTest): -try: - print 'unaligned access (exc 12)' - uc.reg_write(UC_MIPS_REG_SP, 0x400001) - uc.emu_start(CODE, CODE + len(asm), 300) - print -except UcError as e: - print("ERROR: %s" % e) + def runTest(self): + uc = Uc(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_LITTLE_ENDIAN) + uc.hook_add(UC_HOOK_INTR, hook_intr) + uc.mem_map(CODE, 0x1000) + uc.mem_write(CODE, asm) -try: - print 'dunno (exc 26)' - uc.reg_write(UC_MIPS_REG_SP, 0xFFFFFFF0) - uc.emu_start(CODE, CODE + len(asm), 200) - print -except UcError as e: - print("ERROR: %s" % e) + with self.assertRaises(UcError) as m: + uc.reg_write(UC_MIPS_REG_SP, 0x400001) + uc.emu_start(CODE, CODE + len(asm), 300) + + self.assertEqual(UC_ERR_READ_UNALIGNED, m.exception.errno) + + with self.assertRaises(UcError) as m: + uc.reg_write(UC_MIPS_REG_SP, 0xFFFFFFF0) + uc.emu_start(CODE, CODE + len(asm), 200) + + self.assertEqual(UC_ERR_READ_INVALID, m.exception.errno) + + with self.assertRaises(UcError) as m: + uc.reg_write(UC_MIPS_REG_SP, 0x80000000) + uc.emu_start(CODE, CODE + len(asm), 100) + + self.assertEqual(UC_ERR_READ_INVALID, m.exception.errno) + +if __name__ == '__main__': + regress.main() -try: - print 'unassigned access (exc 28)' - uc.reg_write(UC_MIPS_REG_SP, 0x80000000) - uc.emu_start(CODE, CODE + len(asm), 100) - print -except UcError as e: - print("ERROR: %s" % e) diff --git a/regress/movsd.py b/regress/movsd.py index e873b1cd..28766139 100755 --- a/regress/movsd.py +++ b/regress/movsd.py @@ -5,6 +5,7 @@ from capstone import * from unicorn import * from unicorn.x86_const import * +import regress code = 'f20f1005aa120000'.decode('hex') def dis(mem, addr): @@ -20,9 +21,15 @@ def hook_code(uc, addr, size, user_data): print 'instruction:', str(mem).encode('hex'), dis(mem, addr) print 'reference: ', code.encode('hex'), dis(code, addr) -addr = 0x400000 -mu = Uc(UC_ARCH_X86, UC_MODE_64) -mu.hook_add(UC_HOOK_CODE, hook_code) -mu.mem_map(addr, 8 * 1024 * 1024) -mu.mem_write(addr, code) -mu.emu_start(addr, addr + len(code)) +class Movsd(regress.RegressTest): + + def runTest(self): + addr = 0x400000 + mu = Uc(UC_ARCH_X86, UC_MODE_64) + mu.hook_add(UC_HOOK_CODE, hook_code) + mu.mem_map(addr, 8 * 1024 * 1024) + mu.mem_write(addr, code) + mu.emu_start(addr, addr + len(code)) + +if __name__ == '__main__': + regress.main() diff --git a/regress/pshufb.py b/regress/pshufb.py index 432a2300..4e60b7dc 100755 --- a/regress/pshufb.py +++ b/regress/pshufb.py @@ -5,8 +5,17 @@ from unicorn import * from unicorn.x86_const import * -uc = Uc(UC_ARCH_X86, UC_MODE_64) -uc.mem_map(0x2000, 0x1000) -# pshufb xmm0, xmm1 -uc.mem_write(0x2000, '660f3800c1'.decode('hex')) -uc.emu_start(0x2000, 0x2005) + +import regress + +class Pshufb(regress.RegressTest): + + def runTest(self): + uc = Uc(UC_ARCH_X86, UC_MODE_64) + uc.mem_map(0x2000, 0x1000) + # pshufb xmm0, xmm1 + uc.mem_write(0x2000, '660f3800c1'.decode('hex')) + uc.emu_start(0x2000, 0x2005) + +if __name__ == '__main__': + regress.main() diff --git a/regress/reg_write_sign_extension.py b/regress/reg_write_sign_extension.py index 582e3ee5..e2838da2 100755 --- a/regress/reg_write_sign_extension.py +++ b/regress/reg_write_sign_extension.py @@ -3,6 +3,8 @@ """See https://github.com/unicorn-engine/unicorn/issues/98""" import unicorn +import regress + ADDR = 0xffaabbcc def hook_mem_invalid(mu, access, address, size, value, user_data): @@ -12,12 +14,18 @@ def hook_mem_invalid(mu, access, address, size, value, user_data): mu.mem_write(address, b'\xcc') return True -mu = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32) -mu.reg_write(unicorn.x86_const.UC_X86_REG_EBX, ADDR) +class RegWriteSignExt(regress.RegressTest): -mu.mem_map(0x10000000, 1024 * 4) -# jmp ebx -mu.mem_write(0x10000000, b'\xff\xe3') + def runTest(self): + mu = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32) + mu.reg_write(unicorn.x86_const.UC_X86_REG_EBX, ADDR) -mu.hook_add(unicorn.UC_HOOK_MEM_INVALID, hook_mem_invalid) -mu.emu_start(0x10000000, 0x10000000 + 2, count=1) + mu.mem_map(0x10000000, 1024 * 4) + # jmp ebx + mu.mem_write(0x10000000, b'\xff\xe3') + + mu.hook_add(unicorn.UC_HOOK_MEM_INVALID, hook_mem_invalid) + mu.emu_start(0x10000000, 0x10000000 + 2, count=1) + +if __name__ == '__main__': + regress.main() diff --git a/regress/regress.py b/regress/regress.py new file mode 100644 index 00000000..89aeef65 --- /dev/null +++ b/regress/regress.py @@ -0,0 +1,29 @@ +import unittest + +from os.path import dirname, basename, isfile +import glob + +# Find all unittest type in this directory and run it. + +class RegressTest(unittest.TestCase): + pass + +def main(): + unittest.main() + +if __name__ == '__main__': + modules = glob.glob(dirname(__file__)+"./*.py") + __all__ = [ basename(f)[:-3] for f in modules if isfile(f)] + suite = unittest.TestSuite() + + for module in __all__: + m = __import__(module) + for cl in dir(m): + try: + realcl = getattr(m,cl) + if issubclass(realcl, unittest.TestCase): + suite.addTest(realcl()) + except Exception as e: + pass + + unittest.TextTestRunner().run(suite) diff --git a/regress/wrong_rip.py b/regress/wrong_rip.py index 8c0b4c1f..87549806 100755 --- a/regress/wrong_rip.py +++ b/regress/wrong_rip.py @@ -3,30 +3,69 @@ from unicorn import * from unicorn.x86_const import * +import regress + binary1 = b'\xb8\x02\x00\x00\x00' # mov eax, 2 binary2 = b'\xb8\x01\x00\x00\x00' # mov eax, 1 -mu = Uc(UC_ARCH_X86, UC_MODE_64) +class WrongRIP(regress.RegressTest): -mu.mem_map(0, 2 * 1024 * 1024) + def test_step(self): + mu = Uc(UC_ARCH_X86, UC_MODE_64) + mu.mem_map(0, 2 * 1024 * 1024) + # write machine code to be emulated to memory + mu.mem_write(0, binary1 + binary2) + # emu for maximum 1 instruction. + mu.emu_start(0, 5, 0, 1) -# write machine code to be emulated to memory -mu.mem_write(0, binary1 + binary2) + self.assertEqual(0x2, mu.reg_read(UC_X86_REG_RAX)) + self.assertEqual(0x5, mu.reg_read(UC_X86_REG_RIP)) -# emu for maximum 1 instruction. -mu.emu_start(0, 5, 0, 1) + mu.emu_start(5, 10, 0, 1) + self.assertEqual(0xa, mu.reg_read(UC_X86_REG_RIP)) + self.assertEqual(0x1, mu.reg_read(UC_X86_REG_RAX)) -print("RAX = %u" %mu.reg_read(UC_X86_REG_RAX)) + def test_step2(self): + mu = Uc(UC_ARCH_X86, UC_MODE_64) + mu.mem_map(0, 2 * 1024 * 1024) + # write machine code to be emulated to memory + mu.mem_write(0, binary1 + binary2) + # emu for maximum 1 instruction. + mu.emu_start(0, 10, 0, 1) + self.assertEqual(0x2, mu.reg_read(UC_X86_REG_RAX)) + self.assertEqual(0x5, mu.reg_read(UC_X86_REG_RIP)) -pos = mu.reg_read(UC_X86_REG_RIP) + mu.emu_start(5, 10, 0, 1) + self.assertEqual(0x1, mu.reg_read(UC_X86_REG_RAX)) + self.assertEqual(0xa, mu.reg_read(UC_X86_REG_RIP)) -print("RIP = %x" %pos) + def test_step3(self): + bin3 = b'\x40\x01\xc1\x31\xf6' # inc eax; add ecx, eax; xor esi, esi + mu = Uc(UC_ARCH_X86, UC_MODE_32) + mu.mem_map(0, 2 * 1024 * 1024) + # write machine code to be emulated to memory + mu.mem_write(0, bin3) + # emu for maximum 1 instruction. + mu.emu_start(0, 10, 0, 1) + self.assertEqual(0x1, mu.reg_read(UC_X86_REG_EAX)) + self.assertEqual(0x1, mu.reg_read(UC_X86_REG_EIP)) -mu.emu_start(5, 10, 0, 1) + def test_step_then_fin(self): + bin4 = b'\x40\x01\xc1\x31\xf6\x90\x90\x90' # inc eax; add ecx, eax; xor esi, esi + mu = Uc(UC_ARCH_X86, UC_MODE_32) + mu.mem_map(0, 2 * 1024 * 1024) + # write machine code to be emulated to memory + mu.mem_write(0, bin4) + # emu for maximum 1 instruction. + mu.emu_start(0, len(binary1), 0, 1) -pos = mu.reg_read(UC_X86_REG_RIP) + self.assertEqual(0x1, mu.reg_read(UC_X86_REG_EAX)) + self.assertEqual(0x1, mu.reg_read(UC_X86_REG_EIP)) + # emu to the end + mu.emu_start(1, len(bin4)) + self.assertEqual(0x1, mu.reg_read(UC_X86_REG_EAX)) + self.assertEqual(len(bin4), mu.reg_read(UC_X86_REG_EIP)) -print("RIP = %x" %pos) - -print("RAX = %u" %mu.reg_read(UC_X86_REG_RAX)) +if __name__ == '__main__': + regress.main() diff --git a/regress/wrong_rip2.py b/regress/wrong_rip2.py deleted file mode 100755 index 24d028ce..00000000 --- a/regress/wrong_rip2.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/python - -from unicorn import * -from unicorn.x86_const import * - -binary1 = b'\xb8\x02\x00\x00\x00' # mov eax, 2 -binary2 = b'\xb8\x01\x00\x00\x00' # mov eax, 1 - -mu = Uc(UC_ARCH_X86, UC_MODE_64) - -mu.mem_map(0, 2 * 1024 * 1024) - -# write machine code to be emulated to memory -mu.mem_write(0, binary1 + binary2) - -# emu for maximum 1 instruction. -mu.emu_start(0, 10, 0, 1) - -print("RAX = %u" %mu.reg_read(UC_X86_REG_RAX)) - -pos = mu.reg_read(UC_X86_REG_RIP) - -print("RIP = %x" %pos) - -mu.emu_start(5, 10, 0, 1) - -pos = mu.reg_read(UC_X86_REG_RIP) - -print("RIP = %x" %pos) - -print("RAX = %u" %mu.reg_read(UC_X86_REG_RAX)) - diff --git a/regress/wrong_rip3.py b/regress/wrong_rip3.py deleted file mode 100755 index 77c90eef..00000000 --- a/regress/wrong_rip3.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/python - -from unicorn import * -from unicorn.x86_const import * - -binary1 = b'\x40\x01\xc1\x31\xf6' # inc eax; add ecx, eax; xor esi, esi - -mu = Uc(UC_ARCH_X86, UC_MODE_32) - -mu.mem_map(0, 2 * 1024 * 1024) - -# write machine code to be emulated to memory -mu.mem_write(0, binary1) - -# emu for maximum 1 instruction. -mu.emu_start(0, 10, 0, 1) - -print("EAX = %u" %mu.reg_read(UC_X86_REG_EAX)) - -pos = mu.reg_read(UC_X86_REG_EIP) - -print("EIP = %x" %pos) - diff --git a/regress/wrong_rip4.py b/regress/wrong_rip4.py deleted file mode 100755 index 9937483b..00000000 --- a/regress/wrong_rip4.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/python - -from unicorn import * -from unicorn.x86_const import * - -binary1 = b'\x40\x01\xc1\x31\xf6\x90\x90\x90' # inc eax; add ecx, eax; xor esi, esi - -mu = Uc(UC_ARCH_X86, UC_MODE_32) - -mu.mem_map(0, 2 * 1024 * 1024) - -# write machine code to be emulated to memory -mu.mem_write(0, binary1) - -pos = 0 -# emu for maximum 1 instruction. -mu.emu_start(pos, len(binary1), 0, 1) - -print("EAX = %u" %mu.reg_read(UC_X86_REG_EAX)) - -pos = mu.reg_read(UC_X86_REG_EIP) - -print("EIP = %x" %pos) - -# emu to the end -mu.emu_start(pos, len(binary1)) - -print("EAX = %u" %mu.reg_read(UC_X86_REG_EAX)) - -pos = mu.reg_read(UC_X86_REG_EIP) - -print("EIP = %x" %pos) diff --git a/regress/wrong_rip_arm.py b/regress/wrong_rip_arm.py index d10a47f3..de710d85 100755 --- a/regress/wrong_rip_arm.py +++ b/regress/wrong_rip_arm.py @@ -4,6 +4,8 @@ from unicorn import * from unicorn.x86_const import * from unicorn.arm_const import * +import regress + # adds r1, #0x48 # ldrsb r7, [r7, r7] # ldrsh r7, [r2, r1] @@ -14,26 +16,23 @@ from unicorn.arm_const import * # strb r7, [r5, #0xc] # ldr r0, [pc, #0x1a0] binary1 = b'\x48\x31\xff\x57\x57\x5e\x5a\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05' -binary1 = b'\x48\x31\xff\x57' +# binary1 = b'\x48\x31\xff\x57' #adds r1, #0x48 #ldrsb r7, [r7, r7] -mu = Uc(UC_ARCH_ARM, UC_MODE_THUMB) +class WrongRIPArm(regress.RegressTest): -mu.mem_map(0, 2 * 1024 * 1024) + def runTest(self): + mu = Uc(UC_ARCH_ARM, UC_MODE_THUMB) + mu.mem_map(0, 2 * 1024 * 1024) + # write machine code to be emulated to memory + mu.mem_write(0, binary1) + mu.reg_write(UC_ARM_REG_R13, 1 * 1024 * 1024) + # emu for maximum 1 instruction. + mu.emu_start(0, len(binary1), 0, 1) + self.assertEqual(0x48, mu.reg_read(UC_ARM_REG_R1)) + pos = mu.reg_read(UC_ARM_REG_R15) + self.assertEqual(0x2, pos) -# write machine code to be emulated to memory -mu.mem_write(0, binary1) - -mu.reg_write(ARM_REG_R13, 1*1024*1024) - -pos = 0 - -# emu for maximum 1 instruction. -mu.emu_start(pos, len(binary1), 0, 1) - -print("R1 = %x" % mu.reg_read(ARM_REG_R1)) - -pos = mu.reg_read(ARM_REG_R15) - -print("RIP = %x" %pos) +if __name__ == '__main__': + regress.main() diff --git a/regress/wrong_sp_arm.py b/regress/wrong_sp_arm.py index 762210f3..13dbd36c 100755 --- a/regress/wrong_sp_arm.py +++ b/regress/wrong_sp_arm.py @@ -3,20 +3,26 @@ from unicorn import * from unicorn.arm_const import * +from unicorn.arm64_const import * -try: - uc = Uc(UC_ARCH_ARM, UC_MODE_32) - uc.reg_write(UC_ARM_REG_SP, 4) - print 'Writing 4 to SP' - print 'SP =', uc.reg_read(UC_ARM_REG_SP) -except UcError as e: - print("ERROR: %s" % e) +import regress -try: - print "===========" - uc = Uc(UC_ARCH_ARM, UC_MODE_ARM) - uc.reg_write(UC_ARM_REG_SP, 4) - print 'Writing 4 to SP' - print 'SP =', uc.reg_read(UC_ARM_REG_SP) -except UcError as e: - print("ERROR: %s" % e) +class WrongSPArm(regress.RegressTest): + + def test_32(self): + with self.assertRaises(UcError): + uc = Uc(UC_ARCH_ARM, UC_MODE_32) + uc.reg_write(UC_ARM_REG_SP, 4) + + def test_64(self): + uc = Uc(UC_ARCH_ARM64, UC_MODE_ARM) + uc.reg_write(UC_ARM64_REG_SP, 4) + self.assertEqual(0x4, uc.reg_read(UC_ARM64_REG_SP)) + + def test_arm(self): + uc = Uc(UC_ARCH_ARM, UC_MODE_ARM) + uc.reg_write(UC_ARM_REG_SP, 4) + self.assertEqual(0x4, uc.reg_read(UC_ARM_REG_SP)) + +if __name__ == '__main__': + regress.main() diff --git a/regress/wrong_sp_arm64.py b/regress/wrong_sp_arm64.py deleted file mode 100755 index d63791e1..00000000 --- a/regress/wrong_sp_arm64.py +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/python - -from unicorn import * -from unicorn.arm64_const import * - -try: - uc = Uc(UC_ARCH_ARM64, UC_MODE_ARM) - uc.reg_write(UC_ARM64_REG_SP, 4) - print 'Writing 4 to SP' - print 'SP =', uc.reg_read(UC_ARM64_REG_SP) -except UcError as e: - print("ERROR: %s" % e) From 4d45f11a08d26a97622a7cfd4a224681a65c176a Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 19 Sep 2015 17:06:50 +0700 Subject: [PATCH 21/66] regress/regress.py can be run from inside regress/ --- regress/regress.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) mode change 100644 => 100755 regress/regress.py diff --git a/regress/regress.py b/regress/regress.py old mode 100644 new mode 100755 index 89aeef65..2e4f2536 --- a/regress/regress.py +++ b/regress/regress.py @@ -1,3 +1,5 @@ +#!/usr/bin/python + import unittest from os.path import dirname, basename, isfile @@ -12,7 +14,10 @@ def main(): unittest.main() if __name__ == '__main__': - modules = glob.glob(dirname(__file__)+"./*.py") + directory = dirname(__file__) + if directory == '': + directory = '.' + modules = glob.glob(directory+"/*.py") __all__ = [ basename(f)[:-3] for f in modules if isfile(f)] suite = unittest.TestSuite() From 7ab8d667fdabd6b48a3d00b76b1c18e80322727a Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 20 Sep 2015 00:02:30 +0700 Subject: [PATCH 22/66] fix regress/fpu_mem_write.py so it really emulates code --- regress/fpu_mem_write.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/regress/fpu_mem_write.py b/regress/fpu_mem_write.py index 730914a6..00e0b687 100755 --- a/regress/fpu_mem_write.py +++ b/regress/fpu_mem_write.py @@ -5,20 +5,21 @@ from unicorn.x86_const import * ESP = 0x2000 PAGE_SIZE = 1 * 1024 * 1024 -# fstcw [esp] -# pop ecx +# wait +# fnstcw word ptr [esp] +# pop ecx CODE = b'\x9B\xD9\x3C\x24\x59' def mem_reader(addr, size): - tmp = mu.mem_read(addr, size) + tmp = mu.mem_read(addr, size) - for i in tmp: - print(" 0x%x" % i), - print("") + for i in tmp: + print(" 0x%x" % i), + print("") def hook_mem_write(uc, access, address, size, value, user_data): - print("mem WRITE: 0x%x, data size = %u, data value = 0x%x" % (address, size, value)) - return True + print("mem WRITE: 0x%x, data size = %u, data value = 0x%x" % (address, size, value)) + return True mu = Uc(UC_ARCH_X86, UC_MODE_32) mu.mem_map(0, PAGE_SIZE) @@ -26,7 +27,7 @@ mu.mem_write(0, CODE) mu.reg_write(UC_X86_REG_ESP, ESP) mu.hook_add(UC_HOOK_MEM_WRITE, hook_mem_write) -mu.emu_start(0x0, 0, 0, 2) +mu.emu_start(0x0, 5, 0, 2) esp = mu.reg_read(UC_X86_REG_ESP) print("value at ESP [0x%X]: " % esp) -mem_reader(esp, 10) \ No newline at end of file +mem_reader(esp, 10) From 9aa04d9496a8d51b662a9fa485f46ef757ea1327 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 20 Sep 2015 00:05:17 +0700 Subject: [PATCH 23/66] tb_gen_code(): only check to link next page if tb->size > 0 (so we skip empty block) --- qemu/translate-all.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/qemu/translate-all.c b/qemu/translate-all.c index aaebee42..8f1c43eb 100644 --- a/qemu/translate-all.c +++ b/qemu/translate-all.c @@ -1073,7 +1073,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu, TCGContext *tcg_ctx = env->uc->tcg_ctx; TranslationBlock *tb; tb_page_addr_t phys_pc, phys_page2; - target_ulong virt_page2; int code_gen_size; phys_pc = get_page_addr_code(env, pc); @@ -1094,11 +1093,13 @@ TranslationBlock *tb_gen_code(CPUState *cpu, tcg_ctx->code_gen_ptr = (void *)(((uintptr_t)tcg_ctx->code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); - /* check next page if needed */ - virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK; phys_page2 = -1; - if ((pc & TARGET_PAGE_MASK) != virt_page2) { - phys_page2 = get_page_addr_code(env, virt_page2); + /* check next page if needed */ + if (tb->size) { + target_ulong virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK; + if ((pc & TARGET_PAGE_MASK) != virt_page2) { + phys_page2 = get_page_addr_code(env, virt_page2); + } } tb_link_page(cpu->uc, tb, phys_pc, phys_page2); return tb; From 12909e6a4ca03a5f50a10a44ac39be821b284faf Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Thu, 3 Sep 2015 21:52:41 -0400 Subject: [PATCH 24/66] add basic cmocka unit test --- test/unit/.gitignore | 1 + test/unit/Makefile | 13 ++++++ test/unit/test_x86.c | 99 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 test/unit/.gitignore create mode 100644 test/unit/Makefile create mode 100644 test/unit/test_x86.c diff --git a/test/unit/.gitignore b/test/unit/.gitignore new file mode 100644 index 00000000..b045baae --- /dev/null +++ b/test/unit/.gitignore @@ -0,0 +1 @@ +test_x86 diff --git a/test/unit/Makefile b/test/unit/Makefile new file mode 100644 index 00000000..9b5aed65 --- /dev/null +++ b/test/unit/Makefile @@ -0,0 +1,13 @@ +CFLAGS += -lcmocka -lunicorn + + +ALL_TESTS = test_x86 + +all: ${ALL_TESTS} + +clean: + rm ${ALL_TESTS} + + +test_x86: test_x86.c + gcc ${CFLAGS} -o $@ $^ diff --git a/test/unit/test_x86.c b/test/unit/test_x86.c new file mode 100644 index 00000000..a6b509bd --- /dev/null +++ b/test/unit/test_x86.c @@ -0,0 +1,99 @@ +#include +#include +#include +#include +#include +#include + +// callback for tracing basic blocks +static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + //printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); +} + +// callback for tracing instruction +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + int eflags; + //printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); + + //uc_reg_read(uc, UC_X86_REG_EFLAGS, &eflags); + //printf(">>> --- EFLAGS is 0x%x\n", eflags); + + // Uncomment below code to stop the emulation using uc_emu_stop() + // if (address == 0x1000009) + // uc_emu_stop(uc); +} + +static void uc_assert_success(uc_err err) +{ + assert_int_equal(err, 0); + // uc_strerror(err) +} + +static void test_i386(void **state) +{ + uc_engine *uc; + uc_err err; + uint32_t tmp; + uc_hook trace1, trace2; + + const uint8_t code[] = "\x41\x4a"; // INC ecx; DEC edx + const uint64_t address = 0x1000000; + + int r_ecx = 0x1234; // ECX register + int r_edx = 0x7890; // EDX register + + // Initialize emulator in X86-32bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); + uc_assert_success(err); + + // map 2MB memory for this emulation + err = uc_mem_map(uc, address, 2 * 1024 * 1024, UC_PROT_ALL); + uc_assert_success(err); + + // write machine code to be emulated to memory + err = uc_mem_write(uc, address, code, sizeof(code)-1); + uc_assert_success(err); + + // initialize machine registers + err = uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx); + uc_assert_success(err); + err = uc_reg_write(uc, UC_X86_REG_EDX, &r_edx); + uc_assert_success(err); + + // tracing all basic blocks with customized callback + err = uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_assert_success(err); + + // tracing all instruction by having @begin > @end + err = uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_assert_success(err); + + // emulate machine code in infinite time + err = uc_emu_start(uc, address, address+sizeof(code)-1, 0, 0); + uc_assert_success(err); + + // now print out some registers + //printf(">>> Emulation done. Below is the CPU context\n"); + + uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx); + uc_reg_read(uc, UC_X86_REG_EDX, &r_edx); + + assert_int_equal(r_ecx, 0x1235); + assert_int_equal(r_edx, 0x788F); + + // read from memory + err = uc_mem_read(uc, address, (uint8_t *)&tmp, 4); + uc_assert_success(err); + //printf(">>> Read 4 bytes from [0x%"PRIX64"] = 0x%x\n", address, tmp); + + uc_close(uc); +} + +int main(void) { + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_i386), + }; + return cmocka_run_group_tests(tests, NULL, NULL); +} From d4de54601d5dad35d3836604d6b73e4d3e42df2f Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Mon, 7 Sep 2015 15:05:55 -0400 Subject: [PATCH 25/66] add start of test_mem_map.c --- test/unit/Makefile | 24 ++++++++++++++++++++++-- test/unit/test_mem_map.c | 35 +++++++++++++++++++++++++++++++++++ test/unit/unicorn_test.h | 16 ++++++++++++++++ 3 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 test/unit/test_mem_map.c create mode 100644 test/unit/unicorn_test.h diff --git a/test/unit/Makefile b/test/unit/Makefile index 9b5aed65..0eac4063 100644 --- a/test/unit/Makefile +++ b/test/unit/Makefile @@ -1,13 +1,33 @@ + +CFLAGS += -L ../../ CFLAGS += -lcmocka -lunicorn +CFLAGS += -I ../../include +ALL_TESTS = test_x86 test_mem_map -ALL_TESTS = test_x86 - +.PHONY: all all: ${ALL_TESTS} +.PHONY: clean clean: rm ${ALL_TESTS} +.PHONY: test +test: export LD_LIBRARY_PATH=../../ +test: ${ALL_TESTS} + @#echo ${ALL_TESTS} | xargs -n1 | xargs -I CMD sh -c ./CMD + @for test in ${ALL_TESTS}; do \ + echo -e "\n--------------------------------------------------------------------------------"; \ + echo "TEST: $$test"; \ + ./$$test || break; \ + done + test_x86: test_x86.c +test_mem_map: test_mem_map.c + +${ALL_TESTS}: gcc ${CFLAGS} -o $@ $^ + + + diff --git a/test/unit/test_mem_map.c b/test/unit/test_mem_map.c new file mode 100644 index 00000000..58e2a779 --- /dev/null +++ b/test/unit/test_mem_map.c @@ -0,0 +1,35 @@ +#include "unicorn_test.h" +#include + +static int setup(void **state) +{ + fprintf(stderr, "~~~ setup() ~~~\n"); + + uc_engine *uc; + + uc_assert_success(uc_open(UC_ARCH_X86, UC_MODE_32, &uc)); + + *state = uc; + return 0; +} + +static int teardown(void **state) +{ + uc_engine *uc = *state; + fprintf(stderr, "~~~ teardown() ~~~\n"); + + uc_assert_success(uc_close(uc)); + return 0; +} + + +static void test_basic(void **state) +{ +} + +int main(void) { + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_basic), + }; + return cmocka_run_group_tests(tests, setup, teardown); +} diff --git a/test/unit/unicorn_test.h b/test/unit/unicorn_test.h new file mode 100644 index 00000000..03f9e556 --- /dev/null +++ b/test/unit/unicorn_test.h @@ -0,0 +1,16 @@ +#ifndef UNICORN_TEST_H +#define UNICORN_TEST_H + +#include +#include +#include +#include +#include + +static void uc_assert_success(uc_err err) +{ + assert_int_equal(err, 0); + // uc_strerror(err) +} + +#endif /* UNICORN_TEST_H */ From df3966a90ca971c661e139af2aa9673a51656294 Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Mon, 7 Sep 2015 16:07:48 -0400 Subject: [PATCH 26/66] continued work on test framework --- test/unit/.gitignore | 1 + test/unit/Makefile | 9 ++--- test/unit/test_mem_map.c | 77 +++++++++++++++++++++++++++++++++++++--- test/unit/test_x86.c | 2 +- test/unit/unicorn_test.h | 15 +++++--- 5 files changed, 87 insertions(+), 17 deletions(-) diff --git a/test/unit/.gitignore b/test/unit/.gitignore index b045baae..1a39afbc 100644 --- a/test/unit/.gitignore +++ b/test/unit/.gitignore @@ -1 +1,2 @@ test_x86 +test_mem_map diff --git a/test/unit/Makefile b/test/unit/Makefile index 0eac4063..707e9cd2 100644 --- a/test/unit/Makefile +++ b/test/unit/Makefile @@ -1,4 +1,5 @@ +CFLAGS += -Wall -Werror -Wno-unused-function -g CFLAGS += -L ../../ CFLAGS += -lcmocka -lunicorn CFLAGS += -I ../../include @@ -15,12 +16,8 @@ clean: .PHONY: test test: export LD_LIBRARY_PATH=../../ test: ${ALL_TESTS} - @#echo ${ALL_TESTS} | xargs -n1 | xargs -I CMD sh -c ./CMD - @for test in ${ALL_TESTS}; do \ - echo -e "\n--------------------------------------------------------------------------------"; \ - echo "TEST: $$test"; \ - ./$$test || break; \ - done + ./test_x86 + ./test_mem_map test_x86: test_x86.c diff --git a/test/unit/test_mem_map.c b/test/unit/test_mem_map.c index 58e2a779..08b46aef 100644 --- a/test/unit/test_mem_map.c +++ b/test/unit/test_mem_map.c @@ -1,10 +1,10 @@ #include "unicorn_test.h" #include +#include +/* Called before every test to set up a new instance */ static int setup(void **state) { - fprintf(stderr, "~~~ setup() ~~~\n"); - uc_engine *uc; uc_assert_success(uc_open(UC_ARCH_X86, UC_MODE_32, &uc)); @@ -13,23 +13,90 @@ static int setup(void **state) return 0; } +/* Called after every test to clean up */ static int teardown(void **state) { uc_engine *uc = *state; - fprintf(stderr, "~~~ teardown() ~~~\n"); uc_assert_success(uc_close(uc)); + + *state = NULL; return 0; } +/******************************************************************************/ + +/** + * A basic test showing mapping of memory, and reading/writing it + */ static void test_basic(void **state) { + uc_engine *uc = *state; + const uint64_t mem_start = 0x1000; + const uint64_t mem_len = 0x1000; + const uint64_t test_addr = mem_start + 0x100; + + /* Map a region */ + uc_assert_success(uc_mem_map(uc, mem_start, mem_len, UC_PROT_NONE)); + + /* Write some data to it */ + uc_assert_success(uc_mem_write(uc, test_addr, "test", 4)); + + uint8_t buf[4]; + memset(buf, 0xCC, sizeof(buf)); + + /* Read it back */ + uc_assert_success(uc_mem_read(uc, test_addr, buf, sizeof(buf))); + + /* And make sure it matches what we expect */ + assert_memory_equal(buf, "test", 4); + + /* Unmap the region */ + uc_assert_success(uc_mem_unmap(uc, mem_start, mem_len)); } +/** + * Verify that we can read/write across memory map region boundaries + */ +static void test_rw_across_boundaries(void **state) +{ + uc_engine *uc = *state; + + /* Map in two adjacent regions */ + uc_assert_success(uc_mem_map(uc, 0, 0x1000, 0)); /* 0x0000 - 0x1000 */ + uc_assert_success(uc_mem_map(uc, 0x1000, 0x1000, 0)); /* 0x1000 - 0x2000 */ + + const uint64_t addr = 0x1000 - 2; /* 2 bytes before end of block */ + + /* Write some data across the boundary */ + uc_assert_success(uc_mem_write(uc, addr, "test", 4)); + + uint8_t buf[4]; + memset(buf, 0xCC, sizeof(buf)); + + /* Read the data across the boundary */ + uc_assert_success(uc_mem_read(uc, addr, buf, sizeof(buf))); + + assert_memory_equal(buf, "test", 4); +} + +static void test_bad_unmap(void **state) +{ + uc_engine *uc = *state; + uc_err err; + + /* Try to unmap memory that has not been mapped */ + err = uc_mem_unmap(uc, 0x0, 0x1000); + assert_int_not_equal(err, UC_ERR_OK); +} + + int main(void) { const struct CMUnitTest tests[] = { - cmocka_unit_test(test_basic), + cmocka_unit_test_setup_teardown(test_basic, setup, teardown), + cmocka_unit_test_setup_teardown(test_bad_unmap, setup, teardown), + cmocka_unit_test_setup_teardown(test_rw_across_boundaries, setup, teardown), }; - return cmocka_run_group_tests(tests, setup, teardown); + return cmocka_run_group_tests(tests, NULL, NULL); } diff --git a/test/unit/test_x86.c b/test/unit/test_x86.c index a6b509bd..a56e332e 100644 --- a/test/unit/test_x86.c +++ b/test/unit/test_x86.c @@ -14,7 +14,7 @@ static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *use // callback for tracing instruction static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { - int eflags; + //int eflags; //printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); //uc_reg_read(uc, UC_X86_REG_EFLAGS, &eflags); diff --git a/test/unit/unicorn_test.h b/test/unit/unicorn_test.h index 03f9e556..a9dff775 100644 --- a/test/unit/unicorn_test.h +++ b/test/unit/unicorn_test.h @@ -7,10 +7,15 @@ #include #include -static void uc_assert_success(uc_err err) -{ - assert_int_equal(err, 0); - // uc_strerror(err) -} +#define uc_assert_success(err) \ +do { \ + uc_err __err = err; \ + if (__err != UC_ERR_OK) { \ + fail_msg("%s", uc_strerror(__err)); \ + } \ +} while (0) + + + #endif /* UNICORN_TEST_H */ From 4dae31b25ed8f049ef4e971c22d267e93ca625ee Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Sun, 13 Sep 2015 21:32:31 -0400 Subject: [PATCH 27/66] add uc_assert_(err|fail) macros --- test/unit/unicorn_test.h | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/test/unit/unicorn_test.h b/test/unit/unicorn_test.h index a9dff775..ccb53d75 100644 --- a/test/unit/unicorn_test.h +++ b/test/unit/unicorn_test.h @@ -7,15 +7,33 @@ #include #include -#define uc_assert_success(err) \ -do { \ - uc_err __err = err; \ - if (__err != UC_ERR_OK) { \ - fail_msg("%s", uc_strerror(__err)); \ - } \ -} while (0) - +#define UC_ASSERT_ERR_ANY 0xDEADBEEF +/** + * Assert that err matches expect + */ +#define uc_assert_err(expect, err) \ +do { \ + uc_err __err = err; \ + if ((__err != expect) \ + || (expect == UC_ASSERT_ERR_ANY && __err == UC_ERR_OK)) { \ + fail_msg("%s", uc_strerror(__err)); \ + } \ +} while (0) + +/** + * Assert that err is UC_ERR_OK + */ +#define uc_assert_success(err) uc_assert_err(UC_ERR_OK, err) + +/** + * Assert that err is anything but UC_ERR_OK + * + * Note: Better to use uc_assert_err(, err), + * as this serves to document which errors a function will return + * in various scenarios. + */ +#define uc_assert_fail(err) uc_assert_err(UC_ASSERT_ERR_ANY, err) #endif /* UNICORN_TEST_H */ From c026c23efbac342972fef5065f9b3ccf23fa3725 Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Sun, 13 Sep 2015 21:49:43 -0400 Subject: [PATCH 28/66] add more mem map API tests --- test/unit/test_mem_map.c | 57 ++++++++++++++++++++++++++++++++++------ 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/test/unit/test_mem_map.c b/test/unit/test_mem_map.c index 08b46aef..13b96d9d 100644 --- a/test/unit/test_mem_map.c +++ b/test/unit/test_mem_map.c @@ -1,3 +1,9 @@ +/** + * Unicorn memory API tests + * + * This tests memory read/write and map/unmap functionality. + * One is necessary for doing the other. + */ #include "unicorn_test.h" #include #include @@ -53,9 +59,41 @@ static void test_basic(void **state) assert_memory_equal(buf, "test", 4); /* Unmap the region */ - uc_assert_success(uc_mem_unmap(uc, mem_start, mem_len)); + //uc_assert_success(uc_mem_unmap(uc, mem_start, mem_len)); } +static void test_bad_read(void **state) +{ + uc_engine *uc = *state; + + uint8_t readbuf[0x10]; + memset(readbuf, 0xCC, sizeof(readbuf)); + + uint8_t checkbuf[0x10]; + memset(checkbuf, 0xCC, sizeof(checkbuf)); + + /* Reads to unmapped addresses should fail */ + /* TODO: Which error? */ + uc_assert_fail(uc_mem_read(uc, 0x1000, readbuf, sizeof(readbuf))); + + /* And our buffer should be unchanged */ + assert_memory_equal(readbuf, checkbuf, sizeof(checkbuf)); +} + +static void test_bad_write(void **state) +{ + uc_engine *uc = *state; + + uint8_t writebuf[0x10]; + memset(writebuf, 0xCC, sizeof(writebuf)); + + /* Writes to unmapped addresses should fail */ + /* TODO: Which error? */ + uc_assert_fail(uc_mem_write(uc, 0x1000, writebuf, sizeof(writebuf))); +} + + + /** * Verify that we can read/write across memory map region boundaries */ @@ -81,22 +119,25 @@ static void test_rw_across_boundaries(void **state) assert_memory_equal(buf, "test", 4); } +/* Try to unmap memory that has not been mapped */ static void test_bad_unmap(void **state) { uc_engine *uc = *state; - uc_err err; - /* Try to unmap memory that has not been mapped */ - err = uc_mem_unmap(uc, 0x0, 0x1000); - assert_int_not_equal(err, UC_ERR_OK); + /* TODO: Which error should this return? */ + uc_assert_fail(uc_mem_unmap(uc, 0x0, 0x1000)); } int main(void) { +#define test(x) cmocka_unit_test_setup_teardown(x, setup, teardown) const struct CMUnitTest tests[] = { - cmocka_unit_test_setup_teardown(test_basic, setup, teardown), - cmocka_unit_test_setup_teardown(test_bad_unmap, setup, teardown), - cmocka_unit_test_setup_teardown(test_rw_across_boundaries, setup, teardown), + test(test_basic), + //test(test_bad_read), + //test(test_bad_write), + test(test_bad_unmap), + test(test_rw_across_boundaries), }; +#undef test return cmocka_run_group_tests(tests, NULL, NULL); } From 7a98fc4e784d3a385118f012e3a0f21dd9d579ba Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Sun, 13 Sep 2015 22:26:00 -0400 Subject: [PATCH 29/66] add tests to test_x86.c from samples/ --- test/unit/test_x86.c | 580 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 569 insertions(+), 11 deletions(-) diff --git a/test/unit/test_x86.c b/test/unit/test_x86.c index a56e332e..d40e2902 100644 --- a/test/unit/test_x86.c +++ b/test/unit/test_x86.c @@ -1,9 +1,5 @@ -#include -#include -#include +#include "unicorn_test.h" #include -#include -#include // callback for tracing basic blocks static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) @@ -25,12 +21,6 @@ static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user // uc_emu_stop(uc); } -static void uc_assert_success(uc_err err) -{ - assert_int_equal(err, 0); - // uc_strerror(err) -} - static void test_i386(void **state) { uc_engine *uc; @@ -91,9 +81,577 @@ static void test_i386(void **state) uc_close(uc); } +static void test_i386_jump(void **state) +{ + uc_engine *uc; + uc_err err; + uc_hook trace1, trace2; + + const uint8_t code[] = "\xeb\x02\x90\x90\x90\x90\x90\x90"; // jmp 4; nop; nop; nop; nop; nop; nop + const uint64_t address = 0x1000000; + + // Initialize emulator in X86-32bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); + uc_assert_success(err); + + // map 2MB memory for this emulation + err = uc_mem_map(uc, address, 2 * 1024 * 1024, UC_PROT_ALL); + uc_assert_success(err); + + // write machine code to be emulated to memory + err = uc_mem_write(uc, address, code, sizeof(code)-1); + uc_assert_success(err); + + // tracing 1 basic block with customized callback + err = uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)address, (uint64_t)address); + uc_assert_success(err); + + // tracing 1 instruction at address + err = uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)address, (uint64_t)address); + uc_assert_success(err); + + // emulate machine code in infinite time + err = uc_emu_start(uc, address, address+sizeof(code)-1, 0, 0); + uc_assert_success(err); + + err = uc_close(uc); + uc_assert_success(err); +} + +/******************************************************************************/ + +// callback for IN instruction (X86). +// this returns the data read from the port +static uint32_t hook_in(uc_engine *uc, uint32_t port, int size, void *user_data) +{ + uint32_t eip; + + uc_reg_read(uc, UC_X86_REG_EIP, &eip); + + printf("--- reading from port 0x%x, size: %u, address: 0x%x\n", port, size, eip); + + switch(size) { + default: + return 0; // should never reach this + case 1: + // read 1 byte to AL + return 0xf1; + case 2: + // read 2 byte to AX + return 0xf2; + case 4: + // read 4 byte to EAX + return 0xf4; + } +} + +// callback for OUT instruction (X86). +static void hook_out(uc_engine *uc, uint32_t port, int size, uint32_t value, void *user_data) +{ + uint32_t tmp; + uint32_t eip; + + uc_reg_read(uc, UC_X86_REG_EIP, &eip); + + printf("--- writing to port 0x%x, size: %u, value: 0x%x, address: 0x%x\n", port, size, value, eip); + + // TODO: confirm that value is indeed the value of AL/AX/EAX + switch(size) { + default: + return; // should never reach this + case 1: + uc_reg_read(uc, UC_X86_REG_AL, &tmp); + break; + case 2: + uc_reg_read(uc, UC_X86_REG_AX, &tmp); + break; + case 4: + uc_reg_read(uc, UC_X86_REG_EAX, &tmp); + break; + } + + printf("--- register value = 0x%x\n", tmp); +} + +static void test_i386_inout(void **state) +{ + uc_engine *uc; + uc_err err; + uc_hook trace1, trace2, trace3, trace4; + + int r_eax = 0x1234; // EAX register + int r_ecx = 0x6789; // ECX register + + static const uint64_t address = 0x1000000; + static const uint8_t code[] = { + 0x41, // inc ecx + 0xE4, 0x3F, // in al, 0x3F + 0x4A, // dec edx + 0xE6, 0x46, // out 0x46, al + 0x43, // inc ebx + }; + + + // Initialize emulator in X86-32bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); + uc_assert_success(err); + + // map 2MB memory for this emulation + err = uc_mem_map(uc, address, 2 * 1024 * 1024, UC_PROT_ALL); + uc_assert_success(err); + + // write machine code to be emulated to memory + err = uc_mem_write(uc, address, code, sizeof(code)); + uc_assert_success(err); + + // initialize machine registers + err = uc_reg_write(uc, UC_X86_REG_EAX, &r_eax); + uc_assert_success(err); + err = uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx); + uc_assert_success(err); + + // tracing all basic blocks with customized callback + err = uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_assert_success(err); + + // tracing all instructions + err = uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_assert_success(err); + + // uc IN instruction + err = uc_hook_add(uc, &trace3, UC_HOOK_INSN, hook_in, NULL, UC_X86_INS_IN); + uc_assert_success(err); + + // uc OUT instruction + err = uc_hook_add(uc, &trace4, UC_HOOK_INSN, hook_out, NULL, UC_X86_INS_OUT); + uc_assert_success(err); + + // emulate machine code in infinite time + err = uc_emu_start(uc, address, address+sizeof(code), 0, 0); + uc_assert_success(err); + + uc_reg_read(uc, UC_X86_REG_EAX, &r_eax); + uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx); + printf(">>> EAX = 0x%x\n", r_eax); + printf(">>> ECX = 0x%x\n", r_ecx); + // TODO: Assert on the register values here + + uc_assert_success(uc_close(uc)); +} + +/******************************************************************************/ + +// emulate code that loop forever +static void test_i386_loop(void **state) +{ + uc_engine *uc; + uc_err err; + + int r_ecx = 0x1234; // ECX register + int r_edx = 0x7890; // EDX register + + static const uint64_t address = 0x1000000; + static const uint8_t code[] = { + 0x41, // inc ecx + 0x4a, // dec edx + 0xEB, 0xFE, // jmp $ + }; + + // Initialize emulator in X86-32bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); + uc_assert_success(err); + + // map 2MB memory for this emulation + err = uc_mem_map(uc, address, 2 * 1024 * 1024, UC_PROT_ALL); + uc_assert_success(err); + + // write machine code to be emulated to memory + err = uc_mem_write(uc, address, code, sizeof(code)); + uc_assert_success(err); + + // initialize machine registers + err = uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx); + uc_assert_success(err); + err = uc_reg_write(uc, UC_X86_REG_EDX, &r_edx); + uc_assert_success(err); + + // emulate machine code in 2 seconds, so we can quit even + // if the code loops + err = uc_emu_start(uc, address, address+sizeof(code), 2*UC_SECOND_SCALE, 0); + uc_assert_success(err); + + // verify register values + uc_assert_success(uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx)); + uc_assert_success(uc_reg_read(uc, UC_X86_REG_EDX, &r_edx)); + + assert_int_equal(r_ecx, 0x1235); + assert_int_equal(r_edx, 0x788F); + + uc_assert_success(uc_close(uc)); +} + +/******************************************************************************/ + +// emulate code that reads invalid memory +static void test_i386_invalid_mem_read(void **state) +{ + uc_engine *uc; + uc_err err; + + static const uint64_t address = 0x1000000; + static const uint8_t code[] = { + 0x88, 0x0D, 0xAA, 0xAA, 0xAA, 0xAA, // mov ecx, [0xAAAAAAAA] + }; + + // Initialize emulator in X86-32bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); + uc_assert_success(err); + + // map 2MB memory for this emulation + err = uc_mem_map(uc, address, 2 * 1024 * 1024, UC_PROT_ALL); + uc_assert_success(err); + + // write machine code to be emulated to memory + err = uc_mem_write(uc, address, code, sizeof(code)); + uc_assert_success(err); + + // emulate machine code in infinite time + err = uc_emu_start(uc, address, address+sizeof(code), 0, 0); + uc_assert_err(UC_ERR_MEM_READ, err); // TODO: Currently returns MEM_WRITE + + + uc_assert_success(uc_close(uc)); +} + +// emulate code that writes invalid memory +static void test_i386_invalid_mem_write(void **state) +{ + uc_engine *uc; + uc_err err; + + static const uint64_t address = 0x1000000; + static const uint8_t code[] = { + 0x89, 0x0D, 0xAA, 0xAA, 0xAA, 0xAA, // mov [0xAAAAAAAA], ecx + }; + + // Initialize emulator in X86-32bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); + uc_assert_success(err); + + // map 2MB memory for this emulation + err = uc_mem_map(uc, address, 2 * 1024 * 1024, UC_PROT_ALL); + uc_assert_success(err); + + // write machine code to be emulated to memory + err = uc_mem_write(uc, address, code, sizeof(code)); + uc_assert_success(err); + + // emulate machine code in infinite time + err = uc_emu_start(uc, address, address+sizeof(code), 0, 0); + uc_assert_err(UC_ERR_MEM_WRITE, err); + + + uc_assert_success(uc_close(uc)); +} + +// emulate code that jumps to invalid memory +static void test_i386_jump_invalid(void **state) +{ + uc_engine *uc; + uc_err err; + + static const uint64_t address = 0x1000000; + static const uint8_t code[] = { + 0xE9, 0xE9, 0xEE, 0xEE, 0xEE, // jmp 0xEEEEEEEE + }; + + // Initialize emulator in X86-32bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); + uc_assert_success(err); + + // map 2MB memory for this emulation + err = uc_mem_map(uc, address, 2 * 1024 * 1024, UC_PROT_ALL); + uc_assert_success(err); + + // write machine code to be emulated to memory + err = uc_mem_write(uc, address, code, sizeof(code)); + uc_assert_success(err); + + // emulate machine code in infinite time + err = uc_emu_start(uc, address, address+sizeof(code), 0, 0); + uc_assert_err(UC_ERR_CODE_INVALID, err); + + + uc_assert_success(uc_close(uc)); +} + + +/******************************************************************************/ + +static void hook_mem64(uc_engine *uc, uc_mem_type type, + uint64_t address, int size, int64_t value, void *user_data) +{ + switch(type) { + default: break; + case UC_MEM_READ: + printf(">>> Memory is being READ at 0x%"PRIx64 ", data size = %u\n", + address, size); + break; + case UC_MEM_WRITE: + printf(">>> Memory is being WRITE at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", + address, size, value); + break; + } +} + +// callback for tracing instruction +static void hook_code64(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + uint64_t rip; + + uc_reg_read(uc, UC_X86_REG_RIP, &rip); + printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); + printf(">>> RIP is 0x%"PRIx64 "\n", rip); + + // Uncomment below code to stop the emulation using uc_emu_stop() + // if (address == 0x1000009) + // uc_emu_stop(uc); +} + +static void test_x86_64(void **state) +{ + uc_engine *uc; + uc_err err; + uc_hook trace1, trace2, trace3, trace4; + + static const uint64_t address = 0x1000000; + static const uint8_t code[] = "\x41\xBC\x3B\xB0\x28\x2A\x49\x0F\xC9\x90\x4D\x0F\xAD\xCF\x49\x87\xFD\x90\x48\x81\xD2\x8A\xCE\x77\x35\x48\xF7\xD9\x4D\x29\xF4\x49\x81\xC9\xF6\x8A\xC6\x53\x4D\x87\xED\x48\x0F\xAD\xD2\x49\xF7\xD4\x48\xF7\xE1\x4D\x19\xC5\x4D\x89\xC5\x48\xF7\xD6\x41\xB8\x4F\x8D\x6B\x59\x4D\x87\xD0\x68\x6A\x1E\x09\x3C\x59"; + + int64_t rax = 0x71f3029efd49d41d; + int64_t rbx = 0xd87b45277f133ddb; + int64_t rcx = 0xab40d1ffd8afc461; + int64_t rdx = 0x919317b4a733f01; + int64_t rsi = 0x4c24e753a17ea358; + int64_t rdi = 0xe509a57d2571ce96; + int64_t r8 = 0xea5b108cc2b9ab1f; + int64_t r9 = 0x19ec097c8eb618c1; + int64_t r10 = 0xec45774f00c5f682; + int64_t r11 = 0xe17e9dbec8c074aa; + int64_t r12 = 0x80f86a8dc0f6d457; + int64_t r13 = 0x48288ca5671c5492; + int64_t r14 = 0x595f72f6e4017f6e; + int64_t r15 = 0x1efd97aea331cccc; + + int64_t rsp = address + 0x200000; + + + // Initialize emulator in X86-64bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc); + uc_assert_success(err); + + // map 2MB memory for this emulation + err = uc_mem_map(uc, address, 2 * 1024 * 1024, UC_PROT_ALL); + uc_assert_success(err); + + // write machine code to be emulated to memory + err = uc_mem_write(uc, address, code, sizeof(code)); + uc_assert_success(err); + + // initialize machine registers + uc_assert_success(uc_reg_write(uc, UC_X86_REG_RSP, &rsp)); + + uc_assert_success(uc_reg_write(uc, UC_X86_REG_RAX, &rax)); + uc_assert_success(uc_reg_write(uc, UC_X86_REG_RBX, &rbx)); + uc_assert_success(uc_reg_write(uc, UC_X86_REG_RCX, &rcx)); + uc_assert_success(uc_reg_write(uc, UC_X86_REG_RDX, &rdx)); + uc_assert_success(uc_reg_write(uc, UC_X86_REG_RSI, &rsi)); + uc_assert_success(uc_reg_write(uc, UC_X86_REG_RDI, &rdi)); + uc_assert_success(uc_reg_write(uc, UC_X86_REG_R8, &r8)); + uc_assert_success(uc_reg_write(uc, UC_X86_REG_R9, &r9)); + uc_assert_success(uc_reg_write(uc, UC_X86_REG_R10, &r10)); + uc_assert_success(uc_reg_write(uc, UC_X86_REG_R11, &r11)); + uc_assert_success(uc_reg_write(uc, UC_X86_REG_R12, &r12)); + uc_assert_success(uc_reg_write(uc, UC_X86_REG_R13, &r13)); + uc_assert_success(uc_reg_write(uc, UC_X86_REG_R14, &r14)); + uc_assert_success(uc_reg_write(uc, UC_X86_REG_R15, &r15)); + + // tracing all basic blocks with customized callback + err = uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_assert_success(err); + + // tracing all instructions in the range [address, address+20] + err = uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code64, NULL, (uint64_t)address, (uint64_t)(address+20)); + uc_assert_success(err); + + // tracing all memory WRITE access (with @begin > @end) + err = uc_hook_add(uc, &trace3, UC_HOOK_MEM_WRITE, hook_mem64, NULL, (uint64_t)1, (uint64_t)0); + uc_assert_success(err); + + // tracing all memory READ access (with @begin > @end) + err = uc_hook_add(uc, &trace4, UC_HOOK_MEM_READ, hook_mem64, NULL, (uint64_t)1, (uint64_t)0); + uc_assert_success(err); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + err = uc_emu_start(uc, address, address+sizeof(code), 0, 0); + uc_assert_success(err); + + // Read registers + uc_reg_read(uc, UC_X86_REG_RAX, &rax); + uc_reg_read(uc, UC_X86_REG_RBX, &rbx); + uc_reg_read(uc, UC_X86_REG_RCX, &rcx); + uc_reg_read(uc, UC_X86_REG_RDX, &rdx); + uc_reg_read(uc, UC_X86_REG_RSI, &rsi); + uc_reg_read(uc, UC_X86_REG_RDI, &rdi); + uc_reg_read(uc, UC_X86_REG_R8, &r8); + uc_reg_read(uc, UC_X86_REG_R9, &r9); + uc_reg_read(uc, UC_X86_REG_R10, &r10); + uc_reg_read(uc, UC_X86_REG_R11, &r11); + uc_reg_read(uc, UC_X86_REG_R12, &r12); + uc_reg_read(uc, UC_X86_REG_R13, &r13); + uc_reg_read(uc, UC_X86_REG_R14, &r14); + uc_reg_read(uc, UC_X86_REG_R15, &r15); + + printf(">>> RAX = 0x%" PRIx64 "\n", rax); + printf(">>> RBX = 0x%" PRIx64 "\n", rbx); + printf(">>> RCX = 0x%" PRIx64 "\n", rcx); + printf(">>> RDX = 0x%" PRIx64 "\n", rdx); + printf(">>> RSI = 0x%" PRIx64 "\n", rsi); + printf(">>> RDI = 0x%" PRIx64 "\n", rdi); + printf(">>> R8 = 0x%" PRIx64 "\n", r8); + printf(">>> R9 = 0x%" PRIx64 "\n", r9); + printf(">>> R10 = 0x%" PRIx64 "\n", r10); + printf(">>> R11 = 0x%" PRIx64 "\n", r11); + printf(">>> R12 = 0x%" PRIx64 "\n", r12); + printf(">>> R13 = 0x%" PRIx64 "\n", r13); + printf(">>> R14 = 0x%" PRIx64 "\n", r14); + printf(">>> R15 = 0x%" PRIx64 "\n", r15); + + uc_assert_success(uc_close(uc)); +} + +/******************************************************************************/ + +// callback for SYSCALL instruction (X86). +static void hook_syscall(uc_engine *uc, void *user_data) +{ + uint64_t rax; + + uc_assert_success(uc_reg_read(uc, UC_X86_REG_RAX, &rax)); + assert_int_equal(0x100, rax); + + rax = 0x200; + uc_assert_success(uc_reg_write(uc, UC_X86_REG_RAX, &rax)); +} + +static void test_x86_64_syscall(void **state) +{ + uc_engine *uc; + uc_hook trace1; + uc_err err; + + static const uint64_t address = 0x1000000; + static const uint8_t code[] = { + 0x0F, 0x05, // SYSCALL + }; + + int64_t rax = 0x100; + + // Initialize emulator in X86-64bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc); + uc_assert_success(err); + + // map 2MB memory for this emulation + err = uc_mem_map(uc, address, 2 * 1024 * 1024, UC_PROT_ALL); + uc_assert_success(err); + + // write machine code to be emulated to memory + err = uc_mem_write(uc, address, code, sizeof(code)); + uc_assert_success(err); + + // hook interrupts for syscall + err = uc_hook_add(uc, &trace1, UC_HOOK_INSN, hook_syscall, NULL, UC_X86_INS_SYSCALL); + uc_assert_success(err); + + // initialize machine registers + err = uc_reg_write(uc, UC_X86_REG_RAX, &rax); + uc_assert_success(err); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + err = uc_emu_start(uc, address, address + sizeof(code), 0, 0); + uc_assert_success(err); + + // verify register values + uc_assert_success(uc_reg_read(uc, UC_X86_REG_RAX, &rax)); + assert_int_equal(0x200, rax); + + uc_assert_success(uc_close(uc)); +} + +/******************************************************************************/ + +static void test_x86_16(void **state) +{ + uc_engine *uc; + uc_err err; + uint8_t tmp; + + static const uint64_t address = 0; + static const uint8_t code[] = { + 0x00, 0x00, // add byte ptr [bx + si], al + }; + + int32_t eax = 7; + int32_t ebx = 5; + int32_t esi = 6; + + // Initialize emulator in X86-16bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_16, &uc); + uc_assert_success(err); + + // map 8KB memory for this emulation + err = uc_mem_map(uc, address, 8 * 1024, UC_PROT_ALL); + uc_assert_success(err); + + // write machine code to be emulated to memory + err = uc_mem_write(uc, address, code, sizeof(code)); + uc_assert_success(err); + + // initialize machine registers + uc_assert_success(uc_reg_write(uc, UC_X86_REG_EAX, &eax)); + uc_assert_success(uc_reg_write(uc, UC_X86_REG_EBX, &ebx)); + uc_assert_success(uc_reg_write(uc, UC_X86_REG_ESI, &esi)); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + err = uc_emu_start(uc, address, address+sizeof(code), 0, 0); + uc_assert_success(err); + + // read from memory + uc_assert_success(uc_mem_read(uc, 11, &tmp, 1)); + assert_int_equal(7, tmp); + + uc_assert_success(uc_close(uc)); +} + +/******************************************************************************/ + int main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(test_i386), + cmocka_unit_test(test_i386_jump), + cmocka_unit_test(test_i386_inout), + cmocka_unit_test(test_i386_loop), + cmocka_unit_test(test_i386_invalid_mem_read), + cmocka_unit_test(test_i386_invalid_mem_write), + cmocka_unit_test(test_i386_jump_invalid), + + // TODO: Infinite loop, then segfault + //cmocka_unit_test(test_x86_64), + cmocka_unit_test(test_x86_64_syscall), + + cmocka_unit_test(test_x86_16), }; return cmocka_run_group_tests(tests, NULL, NULL); } From f225584f77b0fec7c91ddb5465da15531f15cc57 Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Sun, 20 Sep 2015 22:08:49 -0400 Subject: [PATCH 30/66] change README to markdown, minor edits --- README | 24 ------------------------ README.md | 30 ++++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 24 deletions(-) delete mode 100644 README create mode 100644 README.md diff --git a/README b/README deleted file mode 100644 index a2eb9d70..00000000 --- a/README +++ /dev/null @@ -1,24 +0,0 @@ -Unicorn is a lightweight multi-platform, multi-architecture CPU emulator framework. - -Unicorn offers some unparalleled features: - -- Multi-architectures: Arm, Arm64 (Armv8), M68K, Mips, Sparc, & X86 (include X86_64). -- Clean/simple/lightweight/intuitive architecture-neutral API. -- Implemented in pure C language, with bindings for Python available. -- Native support for Windows & *nix (with Mac OSX, Linux, *BSD & Solaris confirmed). -- High performace by using Just-In-Time compiler technique. -- Support fine-grained instrumentation at various levels. -- Thread-safe by design. -- Distributed under open source license GPL. - -Further information is available at http://www.unicorn-engine.org - - -[Compile] - -See COMPILE.TXT file for how to compile and install Unicorn. - - -[License] - -This project is released under the GPL license. diff --git a/README.md b/README.md new file mode 100644 index 00000000..0923581a --- /dev/null +++ b/README.md @@ -0,0 +1,30 @@ +Unicorn Engine +============== + +Unicorn is a lightweight, multi-platform, multi-architecture CPU emulator framework +based on [QEMU](http://qemu.org). + +Unicorn offers some unparalleled features: + +- Multi-architecture: ARM, AMM64 (ARMv8), m68k, MIPS, SPARC, and x86 (16, 32, 64-bit) +- Clean/simple/lightweight/intuitive architecture-neutral API +- Implemented in pure C language, with bindings for Python, Java, and Go +- Native support for Windows & *nix (with Mac OSX, Linux, *BSD & Solaris confirmed) +- High performace via Just-In-Time compilation +- Support for fine-grained instrumentation at various levels +- Thread-safety by design +- Distributed under open source license GPL + +Further information is available at http://www.unicorn-engine.org + + +Compilation +----------- + +See [COMPILE.TXT](COMPILE.TXT) file for how to compile and install Unicorn. + + +License +------- + +This project is released under the GPL license. From 46ee860084bcfc15621674642f2db12f84fced44 Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Sun, 20 Sep 2015 21:33:11 -0400 Subject: [PATCH 31/66] update to new error constants and silence printfs --- test/unit/test_x86.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/test/unit/test_x86.c b/test/unit/test_x86.c index d40e2902..1a31e432 100644 --- a/test/unit/test_x86.c +++ b/test/unit/test_x86.c @@ -128,7 +128,7 @@ static uint32_t hook_in(uc_engine *uc, uint32_t port, int size, void *user_data) uc_reg_read(uc, UC_X86_REG_EIP, &eip); - printf("--- reading from port 0x%x, size: %u, address: 0x%x\n", port, size, eip); + //printf("--- reading from port 0x%x, size: %u, address: 0x%x\n", port, size, eip); switch(size) { default: @@ -153,7 +153,7 @@ static void hook_out(uc_engine *uc, uint32_t port, int size, uint32_t value, voi uc_reg_read(uc, UC_X86_REG_EIP, &eip); - printf("--- writing to port 0x%x, size: %u, value: 0x%x, address: 0x%x\n", port, size, value, eip); + //printf("--- writing to port 0x%x, size: %u, value: 0x%x, address: 0x%x\n", port, size, value, eip); // TODO: confirm that value is indeed the value of AL/AX/EAX switch(size) { @@ -170,7 +170,7 @@ static void hook_out(uc_engine *uc, uint32_t port, int size, uint32_t value, voi break; } - printf("--- register value = 0x%x\n", tmp); + //printf("--- register value = 0x%x\n", tmp); } static void test_i386_inout(void **state) @@ -232,8 +232,8 @@ static void test_i386_inout(void **state) uc_reg_read(uc, UC_X86_REG_EAX, &r_eax); uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx); - printf(">>> EAX = 0x%x\n", r_eax); - printf(">>> ECX = 0x%x\n", r_ecx); + //printf(">>> EAX = 0x%x\n", r_eax); + //printf(">>> ECX = 0x%x\n", r_ecx); // TODO: Assert on the register values here uc_assert_success(uc_close(uc)); @@ -317,7 +317,7 @@ static void test_i386_invalid_mem_read(void **state) // emulate machine code in infinite time err = uc_emu_start(uc, address, address+sizeof(code), 0, 0); - uc_assert_err(UC_ERR_MEM_READ, err); // TODO: Currently returns MEM_WRITE + uc_assert_err(UC_ERR_READ_INVALID, err); // TODO: Currently returns WRITE_INVALID uc_assert_success(uc_close(uc)); @@ -348,7 +348,7 @@ static void test_i386_invalid_mem_write(void **state) // emulate machine code in infinite time err = uc_emu_start(uc, address, address+sizeof(code), 0, 0); - uc_assert_err(UC_ERR_MEM_WRITE, err); + uc_assert_err(UC_ERR_WRITE_INVALID, err); uc_assert_success(uc_close(uc)); @@ -394,12 +394,12 @@ static void hook_mem64(uc_engine *uc, uc_mem_type type, switch(type) { default: break; case UC_MEM_READ: - printf(">>> Memory is being READ at 0x%"PRIx64 ", data size = %u\n", - address, size); + //printf(">>> Memory is being READ at 0x%"PRIx64 ", data size = %u\n", + // address, size); break; case UC_MEM_WRITE: - printf(">>> Memory is being WRITE at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", - address, size, value); + //printf(">>> Memory is being WRITE at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", + // address, size, value); break; } } @@ -410,8 +410,8 @@ static void hook_code64(uc_engine *uc, uint64_t address, uint32_t size, void *us uint64_t rip; uc_reg_read(uc, UC_X86_REG_RIP, &rip); - printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); - printf(">>> RIP is 0x%"PRIx64 "\n", rip); + //printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); + //printf(">>> RIP is 0x%"PRIx64 "\n", rip); // Uncomment below code to stop the emulation using uc_emu_stop() // if (address == 0x1000009) @@ -512,6 +512,7 @@ static void test_x86_64(void **state) uc_reg_read(uc, UC_X86_REG_R14, &r14); uc_reg_read(uc, UC_X86_REG_R15, &r15); +#if 0 printf(">>> RAX = 0x%" PRIx64 "\n", rax); printf(">>> RBX = 0x%" PRIx64 "\n", rbx); printf(">>> RCX = 0x%" PRIx64 "\n", rcx); @@ -526,6 +527,7 @@ static void test_x86_64(void **state) printf(">>> R13 = 0x%" PRIx64 "\n", r13); printf(">>> R14 = 0x%" PRIx64 "\n", r14); printf(">>> R15 = 0x%" PRIx64 "\n", r15); +#endif uc_assert_success(uc_close(uc)); } From 1be8ef69c88c976a13cdbfa07e8a243b625fc947 Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Sun, 20 Sep 2015 21:39:35 -0400 Subject: [PATCH 32/66] add 'test' to main Makefile --- Makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Makefile b/Makefile index 148baa73..198ed266 100644 --- a/Makefile +++ b/Makefile @@ -249,6 +249,11 @@ else endif +.PHONY: test +test: all + $(MAKE) -C test/unit test + + install: all $(PKGCFGF) mkdir -p $(LIBDIR) ifeq ($(UNICORN_SHARED),yes) @@ -302,6 +307,7 @@ ifeq (,$(findstring yes,$(UNICORN_BUILD_CORE_ONLY))) cd samples && $(MAKE) clean rm -f $(BLDIR)/samples/lib$(LIBNAME).$(EXT) endif + $(MAKE) -C test/unit clean ifdef BUILDDIR rm -rf $(BUILDDIR) From cc1cfb9141f57d4faa04dd89650f730fe3f0cbaa Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Sun, 20 Sep 2015 22:16:04 -0400 Subject: [PATCH 33/66] add information about unit tests to COMPILE.txt --- COMPILE.TXT | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/COMPILE.TXT b/COMPILE.TXT index 53d6885f..bbcb96ca 100644 --- a/COMPILE.TXT +++ b/COMPILE.TXT @@ -246,3 +246,12 @@ Unicorn requires few dependent packages as followings So far, only Python is supported by bindings in the main code. Look for the bindings under directory bindings/, and refer to README file of corresponding languages. + + +[11] Unit tests + + Automated unit tests use the cmocka unit testing framework (https://cmocka.org/). + It can be installed in most Linux distros using the package manager, e.g. + `sudo yum install libcmocka libcmocka-devel`, or you can easily build and install it from source. + + You can run the tests by running `make test` in the project directory. From d7d4be25b1ed7de89432f4cb6d4c73d9ccd6801e Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Mon, 21 Sep 2015 10:26:33 +0800 Subject: [PATCH 34/66] arm64: early check to see if the address of this block is the until address --- qemu/target-arm/translate-a64.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/qemu/target-arm/translate-a64.c b/qemu/target-arm/translate-a64.c index 5dda2eba..d081fc49 100644 --- a/qemu/target-arm/translate-a64.c +++ b/qemu/target-arm/translate-a64.c @@ -11105,6 +11105,13 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu, tcg_clear_temp_count(); + // Unicorn: early check to see if the address of this block is the until address + if (tb->pc == env->uc->addr_end) { + gen_tb_start(tcg_ctx); + gen_exception_insn(dc, 0, EXCP_SWI, 0); + goto done_generating; + } + // Unicorn: trace this block on request // Only hook this block if it is not broken from previous translation due to // full translation cache From 07122809b5f7b2d14136a8ebf7af39ba3d59ab82 Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Sun, 20 Sep 2015 22:45:45 -0400 Subject: [PATCH 35/66] test/unit: add test_basic_blocks This verifies that the basic block callback is working as expected. --- test/unit/test_x86.c | 93 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/test/unit/test_x86.c b/test/unit/test_x86.c index 1a31e432..634201dc 100644 --- a/test/unit/test_x86.c +++ b/test/unit/test_x86.c @@ -1,6 +1,97 @@ #include "unicorn_test.h" #include +#define OK(x) uc_assert_success(x) + +/* Called before every test to set up a new instance */ +static int setup32(void **state) +{ + uc_engine *uc; + + OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc)); + + *state = uc; + return 0; +} + +/* Called after every test to clean up */ +static int teardown(void **state) +{ + uc_engine *uc = *state; + + OK(uc_close(uc)); + + *state = NULL; + return 0; +} + +/******************************************************************************/ + +struct bb { + uint64_t addr; + size_t size; +}; + +struct bbtest { + const struct bb *blocks; + unsigned int blocknum; +}; + + +static void test_basic_blocks_hook(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + struct bbtest *bbtest = user_data; + const struct bb *bb = &bbtest->blocks[bbtest->blocknum++]; + + assert_int_equal(address, bb->addr); + assert_int_equal((size_t)size, bb->size); +} + +static void test_basic_blocks(void **state) +{ + uc_engine *uc = *state; + uc_hook trace1; + +#define BASEADDR 0x1000000 + + uint64_t address = BASEADDR; + const uint8_t code[] = { + 0x33, 0xC0, // xor eax, eax + 0x90, // nop + 0x90, // nop + 0xEB, 0x00, // jmp $+2 + 0x90, // nop + 0x90, // nop + 0x90, // nop + }; + + static const struct bb blocks[] = { + {BASEADDR, 6}, + {BASEADDR+ 6, 3}, + }; + + struct bbtest bbtest = { + .blocks = blocks, + .blocknum = 0, + }; + + +#undef BASEADDR + + // map 2MB memory for this emulation + OK(uc_mem_map(uc, address, 2 * 1024 * 1024, UC_PROT_ALL)); + + // write machine code to be emulated to memory + OK(uc_mem_write(uc, address, code, sizeof(code))); + + // trace all basic blocks + OK(uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, test_basic_blocks_hook, &bbtest, (uint64_t)1, (uint64_t)0)); + + OK(uc_emu_start(uc, address, address+sizeof(code), 0, 0)); +} + +/******************************************************************************/ + // callback for tracing basic blocks static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { @@ -654,6 +745,8 @@ int main(void) { cmocka_unit_test(test_x86_64_syscall), cmocka_unit_test(test_x86_16), + + cmocka_unit_test_setup_teardown(test_basic_blocks, setup32, teardown), }; return cmocka_run_group_tests(tests, NULL, NULL); } From 02daa8df46c0be859a6802bd22aae5f7d0398881 Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Mon, 21 Sep 2015 07:56:02 -0400 Subject: [PATCH 36/66] test/unit: simplify uc_assert_fail() macro This removes the UC_ASSERT_ERR_ANY constant, which was causing a compilation error on OSX: error: comparison of constant 3735928559 with expression of type 'uc_err' (aka 'enum uc_err') is always true [-Werror,-Wtautological-constant-out-of-range-compare] I could have probably changed 0xDEADBEEF to a constant < 0x80000000 but this seems cleaner anyway. --- test/unit/unicorn_test.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/test/unit/unicorn_test.h b/test/unit/unicorn_test.h index ccb53d75..9342566d 100644 --- a/test/unit/unicorn_test.h +++ b/test/unit/unicorn_test.h @@ -7,16 +7,13 @@ #include #include -#define UC_ASSERT_ERR_ANY 0xDEADBEEF - /** * Assert that err matches expect */ #define uc_assert_err(expect, err) \ do { \ uc_err __err = err; \ - if ((__err != expect) \ - || (expect == UC_ASSERT_ERR_ANY && __err == UC_ERR_OK)) { \ + if (__err != expect) { \ fail_msg("%s", uc_strerror(__err)); \ } \ } while (0) @@ -33,7 +30,13 @@ do { \ * as this serves to document which errors a function will return * in various scenarios. */ -#define uc_assert_fail(err) uc_assert_err(UC_ASSERT_ERR_ANY, err) +#define uc_assert_fail(err) \ +do { \ + uc_err __err = err; \ + if (__err == UC_ERR_OK) { \ + fail_msg("%s", uc_strerror(__err)); \ + } \ +} while (0) #endif /* UNICORN_TEST_H */ From 163e9020c87d0fb15c188457a3f8e0e7b071336c Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Mon, 21 Sep 2015 08:35:59 -0400 Subject: [PATCH 37/66] test/unit: add test_sanity This test ensures that the custom uc_assert_xxx() macros are working as intended. --- test/unit/.gitignore | 1 + test/unit/Makefile | 5 ++- test/unit/test_sanity.c | 88 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 test/unit/test_sanity.c diff --git a/test/unit/.gitignore b/test/unit/.gitignore index 1a39afbc..39d66b15 100644 --- a/test/unit/.gitignore +++ b/test/unit/.gitignore @@ -1,2 +1,3 @@ test_x86 test_mem_map +test_sanity diff --git a/test/unit/Makefile b/test/unit/Makefile index 707e9cd2..499d1a5f 100644 --- a/test/unit/Makefile +++ b/test/unit/Makefile @@ -4,7 +4,7 @@ CFLAGS += -L ../../ CFLAGS += -lcmocka -lunicorn CFLAGS += -I ../../include -ALL_TESTS = test_x86 test_mem_map +ALL_TESTS = test_sanity test_x86 test_mem_map .PHONY: all all: ${ALL_TESTS} @@ -16,10 +16,11 @@ clean: .PHONY: test test: export LD_LIBRARY_PATH=../../ test: ${ALL_TESTS} + ./test_sanity ./test_x86 ./test_mem_map - +test_sanity: test_sanity.c test_x86: test_x86.c test_mem_map: test_mem_map.c diff --git a/test/unit/test_sanity.c b/test/unit/test_sanity.c new file mode 100644 index 00000000..9788658b --- /dev/null +++ b/test/unit/test_sanity.c @@ -0,0 +1,88 @@ +#include "unicorn_test.h" + +/* Make sure the uc_assert macros work with constants */ +static void test_uc_assert_macros_constants(void **state) +{ + const uc_err nomem = UC_ERR_NOMEM; + + uc_assert_success(UC_ERR_OK); + uc_assert_err(UC_ERR_NOMEM, nomem); + uc_assert_fail(UC_ERR_VERSION); +} + +/******************************************************************************/ + +static uc_err feedback(uc_err err, int *callcount) +{ + assert_int_equal(++(*callcount), 1); + return err; +} + +/** + * Make sure the uc_assert macros work with function calls + * and only evaluate them once! + */ +static void test_uc_assert_macros_func_calls(void **state) +{ + int callcount; + + callcount = 0; + uc_assert_success(feedback(UC_ERR_OK, &callcount)); + + callcount = 0; + uc_assert_err(UC_ERR_NOMEM, feedback(UC_ERR_NOMEM, &callcount)); + + callcount = 0; + uc_assert_fail(feedback(UC_ERR_VERSION, &callcount)); +} + +/******************************************************************************/ + +static void fail_uc_assert_success(void **state) +{ + uc_assert_success(UC_ERR_NOMEM); +} + +static void fail_uc_assert_err(void **state) +{ + const uc_err ok = UC_ERR_OK; + uc_assert_err(UC_ERR_VERSION, ok); +} + +static void fail_uc_assert_fail(void **state) +{ + uc_assert_fail(UC_ERR_OK); +} + +static void test_uc_assert_macros_fail(void **state) +{ + /* A test-inside-a-test */ + + const struct CMUnitTest tests[] = { + /* these should all fail */ + cmocka_unit_test(fail_uc_assert_success), + cmocka_unit_test(fail_uc_assert_err), + cmocka_unit_test(fail_uc_assert_fail), + }; + + print_message("\n\n--------------------------------------------------------------------------------\n"); + print_message("START: Failure of the following tests is expected.\n\n"); + + assert_int_not_equal(0, cmocka_run_group_tests(tests, NULL, NULL)); + + print_message("\n\nEND: Failure of the preceding tests was expected.\n"); + print_message("--------------------------------------------------------------------------------\n\n"); +} + +/******************************************************************************/ + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_uc_assert_macros_constants), + cmocka_unit_test(test_uc_assert_macros_func_calls), + cmocka_unit_test(test_uc_assert_macros_fail), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} From 441d15e314f189b8c90191674c78198bfc7d86a1 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Mon, 21 Sep 2015 21:45:32 +0800 Subject: [PATCH 38/66] test: correct the input code for test_i386_invalid_mem_read() --- test/unit/test_x86.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/unit/test_x86.c b/test/unit/test_x86.c index 634201dc..4adf1beb 100644 --- a/test/unit/test_x86.c +++ b/test/unit/test_x86.c @@ -391,7 +391,7 @@ static void test_i386_invalid_mem_read(void **state) static const uint64_t address = 0x1000000; static const uint8_t code[] = { - 0x88, 0x0D, 0xAA, 0xAA, 0xAA, 0xAA, // mov ecx, [0xAAAAAAAA] + 0x8b, 0x0D, 0xAA, 0xAA, 0xAA, 0xAA, // mov ecx, [0xAAAAAAAA] }; // Initialize emulator in X86-32bit mode @@ -408,8 +408,7 @@ static void test_i386_invalid_mem_read(void **state) // emulate machine code in infinite time err = uc_emu_start(uc, address, address+sizeof(code), 0, 0); - uc_assert_err(UC_ERR_READ_INVALID, err); // TODO: Currently returns WRITE_INVALID - + uc_assert_err(UC_ERR_READ_INVALID, err); uc_assert_success(uc_close(uc)); } From 26ee533303029d3a4b1b18cb21417b6b2e5d71ae Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Mon, 21 Sep 2015 22:17:26 +0800 Subject: [PATCH 39/66] return NULL in memory_mapping() if no memory is mapped. this fixes test_bad_unmap in test_x86.c --- uc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/uc.c b/uc.c index 76a3f5f7..2d97b7c9 100644 --- a/uc.c +++ b/uc.c @@ -809,6 +809,9 @@ MemoryRegion *memory_mapping(struct uc_struct* uc, uint64_t address) { unsigned int i; + if (uc->mapped_block_count == 0) + return NULL; + // try with the cache index first i = uc->mapped_block_cache_index; From f9dc4dcede846d05d48097a093bbc05d88a73de8 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Mon, 21 Sep 2015 22:56:53 +0800 Subject: [PATCH 40/66] test: fix test_x86_64() --- test/unit/test_x86.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/unit/test_x86.c b/test/unit/test_x86.c index 4adf1beb..e1d6856c 100644 --- a/test/unit/test_x86.c +++ b/test/unit/test_x86.c @@ -544,7 +544,7 @@ static void test_x86_64(void **state) uc_assert_success(err); // write machine code to be emulated to memory - err = uc_mem_write(uc, address, code, sizeof(code)); + err = uc_mem_write(uc, address, code, sizeof(code) - 1); uc_assert_success(err); // initialize machine registers @@ -583,7 +583,7 @@ static void test_x86_64(void **state) // emulate machine code in infinite time (last param = 0), or when // finishing all the code. - err = uc_emu_start(uc, address, address+sizeof(code), 0, 0); + err = uc_emu_start(uc, address, address+sizeof(code) - 1, 0, 0); uc_assert_success(err); // Read registers @@ -739,8 +739,7 @@ int main(void) { cmocka_unit_test(test_i386_invalid_mem_write), cmocka_unit_test(test_i386_jump_invalid), - // TODO: Infinite loop, then segfault - //cmocka_unit_test(test_x86_64), + cmocka_unit_test(test_x86_64), cmocka_unit_test(test_x86_64_syscall), cmocka_unit_test(test_x86_16), From 0c67f41ed9cdb18963571b5b87f284e38485a219 Mon Sep 17 00:00:00 2001 From: danghvu Date: Mon, 21 Sep 2015 20:30:05 -0500 Subject: [PATCH 41/66] Fix issue #118 --- qemu/tcg/tcg.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/qemu/tcg/tcg.c b/qemu/tcg/tcg.c index 4246504c..53460c63 100644 --- a/qemu/tcg/tcg.c +++ b/qemu/tcg/tcg.c @@ -1431,7 +1431,6 @@ static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps, memset(mem_temps + s->nb_globals, 0, s->nb_temps - s->nb_globals); } -#if 0 /* liveness analysis: end of basic block: all temps are dead, globals and local temps should be in memory. */ static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps, @@ -1445,7 +1444,6 @@ static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps, mem_temps[i] = s->temps[i].temp_local; } } -#endif /* Liveness analysis : update the opc_dead_args array to tell if a given input arguments is dead. Instructions updating dead @@ -1684,12 +1682,12 @@ static void tcg_liveness_analysis(TCGContext *s) } /* if end of basic block, update */ - if (def->flags & TCG_OPF_BB_END) { - // Unicorn: do not optimize dead temps. + if (def->flags & TCG_OPF_BB_END && op != INDEX_op_brcond_i32) { + // Unicorn: do not optimize dead temps on brcond, // this causes problem because check_exit_request() inserts // brcond instruction in the middle of the TB, // which incorrectly flags end-of-block - // tcg_la_bb_end(s, dead_temps, mem_temps); + tcg_la_bb_end(s, dead_temps, mem_temps); } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { /* globals should be synced to memory */ memset(mem_temps, 1, s->nb_globals); From 3c1d65ea66765534ab543fb0ee1597e63f966b34 Mon Sep 17 00:00:00 2001 From: danghvu Date: Mon, 21 Sep 2015 20:47:45 -0500 Subject: [PATCH 42/66] Reorganize test directories --- Makefile | 2 +- {regress => tests/regress}/Makefile | 0 {regress => tests/regress}/arm_bxeq_hang.py | 2 +- {regress => tests/regress}/arm_movr12_hang.py | 0 {regress => tests/regress}/block_test.c | 0 {regress => tests/regress}/callback-pc.py | 0 {regress => tests/regress}/crash_tb.py | 0 {regress => tests/regress}/deadlock_1.py | 0 {regress => tests/regress}/emu_stop_segfault.py | 0 {regress => tests/regress}/fpu_ip.py | 0 {regress => tests/regress}/fpu_mem_write.py | 0 {regress => tests/regress}/hang.py | 0 {regress => tests/regress}/jmp_ebx_hang.py | 0 {regress => tests/regress}/map_crash.c | 0 {regress => tests/regress}/map_write.c | 0 {regress => tests/regress}/mem_exec.c | 0 {regress => tests/regress}/mem_protect.c | 0 {regress => tests/regress}/mem_unmap.c | 0 {regress => tests/regress}/memmap.py | 0 {regress => tests/regress}/memmap_segfault.py | 0 {regress => tests/regress}/mips_branch_delay.py | 0 {regress => tests/regress}/mips_except.py | 0 {regress => tests/regress}/movsd.py | 0 {regress => tests/regress}/nr_mem_test.c | 0 {regress => tests/regress}/pshufb.py | 0 {regress => tests/regress}/reg_write_sign_extension.py | 0 {regress => tests/regress}/regress.py | 0 {regress => tests/regress}/rep_movsb.c | 0 {regress => tests/regress}/ro_mem_test.c | 0 {regress => tests/regress}/sigill.c | 0 {regress => tests/regress}/sigill2.c | 0 {regress => tests/regress}/sparc64.py | 0 {regress => tests/regress}/sparc_reg.py | 0 {regress => tests/regress}/timeout_segfault.c | 0 {regress => tests/regress}/wrong_rip.py | 0 {regress => tests/regress}/wrong_rip_arm.py | 0 {regress => tests/regress}/wrong_sp_arm.py | 0 {test => tests}/unit/.gitignore | 0 {test => tests}/unit/Makefile | 0 {test => tests}/unit/test_mem_map.c | 0 {test => tests}/unit/test_sanity.c | 0 {test => tests}/unit/test_x86.c | 0 {test => tests}/unit/unicorn_test.h | 0 43 files changed, 2 insertions(+), 2 deletions(-) rename {regress => tests/regress}/Makefile (100%) rename {regress => tests/regress}/arm_bxeq_hang.py (92%) rename {regress => tests/regress}/arm_movr12_hang.py (100%) rename {regress => tests/regress}/block_test.c (100%) rename {regress => tests/regress}/callback-pc.py (100%) rename {regress => tests/regress}/crash_tb.py (100%) rename {regress => tests/regress}/deadlock_1.py (100%) rename {regress => tests/regress}/emu_stop_segfault.py (100%) rename {regress => tests/regress}/fpu_ip.py (100%) rename {regress => tests/regress}/fpu_mem_write.py (100%) rename {regress => tests/regress}/hang.py (100%) rename {regress => tests/regress}/jmp_ebx_hang.py (100%) rename {regress => tests/regress}/map_crash.c (100%) rename {regress => tests/regress}/map_write.c (100%) rename {regress => tests/regress}/mem_exec.c (100%) rename {regress => tests/regress}/mem_protect.c (100%) rename {regress => tests/regress}/mem_unmap.c (100%) rename {regress => tests/regress}/memmap.py (100%) rename {regress => tests/regress}/memmap_segfault.py (100%) rename {regress => tests/regress}/mips_branch_delay.py (100%) rename {regress => tests/regress}/mips_except.py (100%) rename {regress => tests/regress}/movsd.py (100%) rename {regress => tests/regress}/nr_mem_test.c (100%) rename {regress => tests/regress}/pshufb.py (100%) rename {regress => tests/regress}/reg_write_sign_extension.py (100%) rename {regress => tests/regress}/regress.py (100%) rename {regress => tests/regress}/rep_movsb.c (100%) rename {regress => tests/regress}/ro_mem_test.c (100%) rename {regress => tests/regress}/sigill.c (100%) rename {regress => tests/regress}/sigill2.c (100%) rename {regress => tests/regress}/sparc64.py (100%) rename {regress => tests/regress}/sparc_reg.py (100%) rename {regress => tests/regress}/timeout_segfault.c (100%) rename {regress => tests/regress}/wrong_rip.py (100%) rename {regress => tests/regress}/wrong_rip_arm.py (100%) rename {regress => tests/regress}/wrong_sp_arm.py (100%) rename {test => tests}/unit/.gitignore (100%) rename {test => tests}/unit/Makefile (100%) rename {test => tests}/unit/test_mem_map.c (100%) rename {test => tests}/unit/test_sanity.c (100%) rename {test => tests}/unit/test_x86.c (100%) rename {test => tests}/unit/unicorn_test.h (100%) diff --git a/Makefile b/Makefile index 198ed266..ce4b0d94 100644 --- a/Makefile +++ b/Makefile @@ -251,7 +251,7 @@ endif .PHONY: test test: all - $(MAKE) -C test/unit test + $(MAKE) -C tests/unit test install: all $(PKGCFGF) diff --git a/regress/Makefile b/tests/regress/Makefile similarity index 100% rename from regress/Makefile rename to tests/regress/Makefile diff --git a/regress/arm_bxeq_hang.py b/tests/regress/arm_bxeq_hang.py similarity index 92% rename from regress/arm_bxeq_hang.py rename to tests/regress/arm_bxeq_hang.py index b696112a..12f4a2ae 100755 --- a/regress/arm_bxeq_hang.py +++ b/tests/regress/arm_bxeq_hang.py @@ -19,7 +19,7 @@ class BxHang(regress.RegressTest): uc.reg_write(UC_ARM_REG_LR, 0x1004) uc.hook_add(UC_HOOK_BLOCK, hook_block) print 'block should only run once' - uc.emu_start(0x1000, 0x1004, timeout=500) + uc.emu_start(0x1000, 0x1004) self.assertEqual(uc.count, 1) diff --git a/regress/arm_movr12_hang.py b/tests/regress/arm_movr12_hang.py similarity index 100% rename from regress/arm_movr12_hang.py rename to tests/regress/arm_movr12_hang.py diff --git a/regress/block_test.c b/tests/regress/block_test.c similarity index 100% rename from regress/block_test.c rename to tests/regress/block_test.c diff --git a/regress/callback-pc.py b/tests/regress/callback-pc.py similarity index 100% rename from regress/callback-pc.py rename to tests/regress/callback-pc.py diff --git a/regress/crash_tb.py b/tests/regress/crash_tb.py similarity index 100% rename from regress/crash_tb.py rename to tests/regress/crash_tb.py diff --git a/regress/deadlock_1.py b/tests/regress/deadlock_1.py similarity index 100% rename from regress/deadlock_1.py rename to tests/regress/deadlock_1.py diff --git a/regress/emu_stop_segfault.py b/tests/regress/emu_stop_segfault.py similarity index 100% rename from regress/emu_stop_segfault.py rename to tests/regress/emu_stop_segfault.py diff --git a/regress/fpu_ip.py b/tests/regress/fpu_ip.py similarity index 100% rename from regress/fpu_ip.py rename to tests/regress/fpu_ip.py diff --git a/regress/fpu_mem_write.py b/tests/regress/fpu_mem_write.py similarity index 100% rename from regress/fpu_mem_write.py rename to tests/regress/fpu_mem_write.py diff --git a/regress/hang.py b/tests/regress/hang.py similarity index 100% rename from regress/hang.py rename to tests/regress/hang.py diff --git a/regress/jmp_ebx_hang.py b/tests/regress/jmp_ebx_hang.py similarity index 100% rename from regress/jmp_ebx_hang.py rename to tests/regress/jmp_ebx_hang.py diff --git a/regress/map_crash.c b/tests/regress/map_crash.c similarity index 100% rename from regress/map_crash.c rename to tests/regress/map_crash.c diff --git a/regress/map_write.c b/tests/regress/map_write.c similarity index 100% rename from regress/map_write.c rename to tests/regress/map_write.c diff --git a/regress/mem_exec.c b/tests/regress/mem_exec.c similarity index 100% rename from regress/mem_exec.c rename to tests/regress/mem_exec.c diff --git a/regress/mem_protect.c b/tests/regress/mem_protect.c similarity index 100% rename from regress/mem_protect.c rename to tests/regress/mem_protect.c diff --git a/regress/mem_unmap.c b/tests/regress/mem_unmap.c similarity index 100% rename from regress/mem_unmap.c rename to tests/regress/mem_unmap.c diff --git a/regress/memmap.py b/tests/regress/memmap.py similarity index 100% rename from regress/memmap.py rename to tests/regress/memmap.py diff --git a/regress/memmap_segfault.py b/tests/regress/memmap_segfault.py similarity index 100% rename from regress/memmap_segfault.py rename to tests/regress/memmap_segfault.py diff --git a/regress/mips_branch_delay.py b/tests/regress/mips_branch_delay.py similarity index 100% rename from regress/mips_branch_delay.py rename to tests/regress/mips_branch_delay.py diff --git a/regress/mips_except.py b/tests/regress/mips_except.py similarity index 100% rename from regress/mips_except.py rename to tests/regress/mips_except.py diff --git a/regress/movsd.py b/tests/regress/movsd.py similarity index 100% rename from regress/movsd.py rename to tests/regress/movsd.py diff --git a/regress/nr_mem_test.c b/tests/regress/nr_mem_test.c similarity index 100% rename from regress/nr_mem_test.c rename to tests/regress/nr_mem_test.c diff --git a/regress/pshufb.py b/tests/regress/pshufb.py similarity index 100% rename from regress/pshufb.py rename to tests/regress/pshufb.py diff --git a/regress/reg_write_sign_extension.py b/tests/regress/reg_write_sign_extension.py similarity index 100% rename from regress/reg_write_sign_extension.py rename to tests/regress/reg_write_sign_extension.py diff --git a/regress/regress.py b/tests/regress/regress.py similarity index 100% rename from regress/regress.py rename to tests/regress/regress.py diff --git a/regress/rep_movsb.c b/tests/regress/rep_movsb.c similarity index 100% rename from regress/rep_movsb.c rename to tests/regress/rep_movsb.c diff --git a/regress/ro_mem_test.c b/tests/regress/ro_mem_test.c similarity index 100% rename from regress/ro_mem_test.c rename to tests/regress/ro_mem_test.c diff --git a/regress/sigill.c b/tests/regress/sigill.c similarity index 100% rename from regress/sigill.c rename to tests/regress/sigill.c diff --git a/regress/sigill2.c b/tests/regress/sigill2.c similarity index 100% rename from regress/sigill2.c rename to tests/regress/sigill2.c diff --git a/regress/sparc64.py b/tests/regress/sparc64.py similarity index 100% rename from regress/sparc64.py rename to tests/regress/sparc64.py diff --git a/regress/sparc_reg.py b/tests/regress/sparc_reg.py similarity index 100% rename from regress/sparc_reg.py rename to tests/regress/sparc_reg.py diff --git a/regress/timeout_segfault.c b/tests/regress/timeout_segfault.c similarity index 100% rename from regress/timeout_segfault.c rename to tests/regress/timeout_segfault.c diff --git a/regress/wrong_rip.py b/tests/regress/wrong_rip.py similarity index 100% rename from regress/wrong_rip.py rename to tests/regress/wrong_rip.py diff --git a/regress/wrong_rip_arm.py b/tests/regress/wrong_rip_arm.py similarity index 100% rename from regress/wrong_rip_arm.py rename to tests/regress/wrong_rip_arm.py diff --git a/regress/wrong_sp_arm.py b/tests/regress/wrong_sp_arm.py similarity index 100% rename from regress/wrong_sp_arm.py rename to tests/regress/wrong_sp_arm.py diff --git a/test/unit/.gitignore b/tests/unit/.gitignore similarity index 100% rename from test/unit/.gitignore rename to tests/unit/.gitignore diff --git a/test/unit/Makefile b/tests/unit/Makefile similarity index 100% rename from test/unit/Makefile rename to tests/unit/Makefile diff --git a/test/unit/test_mem_map.c b/tests/unit/test_mem_map.c similarity index 100% rename from test/unit/test_mem_map.c rename to tests/unit/test_mem_map.c diff --git a/test/unit/test_sanity.c b/tests/unit/test_sanity.c similarity index 100% rename from test/unit/test_sanity.c rename to tests/unit/test_sanity.c diff --git a/test/unit/test_x86.c b/tests/unit/test_x86.c similarity index 100% rename from test/unit/test_x86.c rename to tests/unit/test_x86.c diff --git a/test/unit/unicorn_test.h b/tests/unit/unicorn_test.h similarity index 100% rename from test/unit/unicorn_test.h rename to tests/unit/unicorn_test.h From 25342d71d12ba7e93044b6ef8be6e78590afbb0c Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 22 Sep 2015 10:00:05 +0800 Subject: [PATCH 43/66] m68k -> M68K, x86 -> X86 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0923581a..fd7a5639 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ based on [QEMU](http://qemu.org). Unicorn offers some unparalleled features: -- Multi-architecture: ARM, AMM64 (ARMv8), m68k, MIPS, SPARC, and x86 (16, 32, 64-bit) +- Multi-architecture: ARM, AMM64 (ARMv8), M68K, MIPS, SPARC, and X86 (16, 32, 64-bit) - Clean/simple/lightweight/intuitive architecture-neutral API - Implemented in pure C language, with bindings for Python, Java, and Go - Native support for Windows & *nix (with Mac OSX, Linux, *BSD & Solaris confirmed) From 242713ce64b44d48cf2cc0540b5c21bb5b40ac5c Mon Sep 17 00:00:00 2001 From: danghvu Date: Mon, 21 Sep 2015 21:04:20 -0500 Subject: [PATCH 44/66] Missing update on make test clean --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ce4b0d94..06be3fae 100644 --- a/Makefile +++ b/Makefile @@ -307,7 +307,7 @@ ifeq (,$(findstring yes,$(UNICORN_BUILD_CORE_ONLY))) cd samples && $(MAKE) clean rm -f $(BLDIR)/samples/lib$(LIBNAME).$(EXT) endif - $(MAKE) -C test/unit clean + $(MAKE) -C tests/unit clean ifdef BUILDDIR rm -rf $(BUILDDIR) From a853eb6363fc6638d767725d10c56711fe33b2f8 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 22 Sep 2015 10:24:26 +0800 Subject: [PATCH 45/66] mips, m68k: early check to see if the address of BB is the until address --- qemu/target-m68k/translate.c | 9 +++++++++ qemu/target-mips/translate.c | 7 +++++++ 2 files changed, 16 insertions(+) diff --git a/qemu/target-m68k/translate.c b/qemu/target-m68k/translate.c index 133957df..fedffecc 100644 --- a/qemu/target-m68k/translate.c +++ b/qemu/target-m68k/translate.c @@ -3101,6 +3101,13 @@ gen_intermediate_code_internal(M68kCPU *cpu, TranslationBlock *tb, if (max_insns == 0) max_insns = CF_COUNT_MASK; + // Unicorn: early check to see if the address of this block is the until address + if (tb->pc == env->uc->addr_end) { + gen_tb_start(tcg_ctx); + gen_exception(dc, dc->pc, EXCP_TRAP15); + goto done_generating; + } + // Unicorn: trace this block on request // Only hook this block if it is not broken from previous translation due to // full translation cache @@ -3179,6 +3186,8 @@ gen_intermediate_code_internal(M68kCPU *cpu, TranslationBlock *tb, break; } } + +done_generating: gen_tb_end(tcg_ctx, tb, num_insns); *tcg_ctx->gen_opc_ptr = INDEX_op_end; diff --git a/qemu/target-mips/translate.c b/qemu/target-mips/translate.c index 718d69aa..0d3c64bb 100644 --- a/qemu/target-mips/translate.c +++ b/qemu/target-mips/translate.c @@ -19207,6 +19207,13 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, max_insns = CF_COUNT_MASK; LOG_DISAS("\ntb %p idx %d hflags %04x\n", tb, ctx.mem_idx, ctx.hflags); + // Unicorn: early check to see if the address of this block is the until address + if (tb->pc == env->uc->addr_end) { + gen_tb_start(tcg_ctx); + generate_exception(&ctx, EXCP_SYSCALL); + goto done_generating; + } + // Unicorn: trace this block on request // Only hook this block if it is not broken from previous translation due to // full translation cache From 80c316026f06c0fa3ebecf6109cad327b82ef5f1 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 22 Sep 2015 11:05:38 +0800 Subject: [PATCH 46/66] update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 38d5bb7e..659cc24d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ *.d *.o *.a +*.dSYM qemu/config-all-devices.mak From 14a01b5186557bb7c2bfd29d9f1a67d541e0e524 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 22 Sep 2015 11:59:53 +0800 Subject: [PATCH 47/66] mips: handle delay slot so do not duplicate calling instruction handler. this fixes issue #133 --- qemu/target-mips/translate.c | 29 +++++++++++++++-------------- tests/regress/mips_branch_delay.py | 3 +-- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/qemu/target-mips/translate.c b/qemu/target-mips/translate.c index 0d3c64bb..e1ff51a7 100644 --- a/qemu/target-mips/translate.c +++ b/qemu/target-mips/translate.c @@ -1415,7 +1415,7 @@ enum { * exception condition */ BS_STOP = 1, /* We want to stop translation for any reason */ BS_BRANCH = 2, /* We reached a branch condition */ - BS_EXCP = 3, /* We reached an exception condition */ // qq + BS_EXCP = 3, /* We reached an exception condition */ }; static const char * const regnames[] = { @@ -11322,7 +11322,7 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx) return 4; } -static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) +static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, int is_slot) { TCGContext *tcg_ctx = ctx->uc->tcg_ctx; TCGv **cpu_gpr = (TCGv **)tcg_ctx->cpu_gpr; @@ -11343,7 +11343,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) n_bytes = 2; // Unicorn: trace this instruction on request - if (env->uc->hook_insn) { + if (!is_slot && env->uc->hook_insn) { struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, ctx->pc); if (trace) gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, ctx->pc, trace->user_data); @@ -13928,7 +13928,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, } } -static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx) +static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, int is_slot) { TCGContext *tcg_ctx = env->uc->tcg_ctx; TCGv **cpu_gpr = (TCGv **)tcg_ctx->cpu_gpr; @@ -13943,7 +13943,7 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx) } // Unicorn: trace this instruction on request - if (env->uc->hook_insn) { + if (!is_slot && env->uc->hook_insn) { struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, ctx->pc); if (trace) gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, ctx->pc, trace->user_data); @@ -18503,7 +18503,7 @@ static void gen_msa(CPUMIPSState *env, DisasContext *ctx) } } -static void decode_opc (CPUMIPSState *env, DisasContext *ctx) +static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int is_slot) { TCGContext *tcg_ctx = ctx->uc->tcg_ctx; #if defined(TARGET_MIPS64) @@ -18514,6 +18514,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) uint32_t op, op1; int16_t imm; + /* make sure instructions are on a word boundary */ if (ctx->pc & 0x3) { env->CP0_BadVAddr = ctx->pc; @@ -18522,7 +18523,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) } // Unicorn: trace this instruction on request - if (env->uc->hook_insn) { + if (!is_slot && env->uc->hook_insn) { struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, ctx->pc); if (trace) gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, ctx->pc, trace->user_data); @@ -19227,7 +19228,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, } gen_tb_start(tcg_ctx); - while (ctx.bstate == BS_NONE) { // qq + while (ctx.bstate == BS_NONE) { if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) { QTAILQ_FOREACH(bp, &cs->breakpoints, entry) { if (bp->pc == ctx.pc) { @@ -19268,16 +19269,16 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, save_opparam_ptr = tcg_ctx->gen_opparam_ptr; is_slot = ctx.hflags & MIPS_HFLAG_BMASK; - if (!(ctx.hflags & MIPS_HFLAG_M16)) { // qq + if (!(ctx.hflags & MIPS_HFLAG_M16)) { ctx.opcode = cpu_ldl_code(env, ctx.pc); insn_bytes = 4; - decode_opc(env, &ctx); - } else if (ctx.insn_flags & ASE_MICROMIPS) { // qq + decode_opc(env, &ctx, is_slot); + } else if (ctx.insn_flags & ASE_MICROMIPS) { ctx.opcode = cpu_lduw_code(env, ctx.pc); - insn_bytes = decode_micromips_opc(env, &ctx); - } else if (ctx.insn_flags & ASE_MIPS16) { // qq + insn_bytes = decode_micromips_opc(env, &ctx, is_slot); + } else if (ctx.insn_flags & ASE_MIPS16) { ctx.opcode = cpu_lduw_code(env, ctx.pc); - insn_bytes = decode_mips16_opc(env, &ctx); + insn_bytes = decode_mips16_opc(env, &ctx, is_slot); } else { generate_exception(&ctx, EXCP_RI); ctx.bstate = BS_STOP; diff --git a/tests/regress/mips_branch_delay.py b/tests/regress/mips_branch_delay.py index db1bc2ac..2f90ef14 100755 --- a/tests/regress/mips_branch_delay.py +++ b/tests/regress/mips_branch_delay.py @@ -1,7 +1,6 @@ #!/usr/bin/python from capstone import * from unicorn import * -from unicorn.mips_const import * import regress @@ -19,7 +18,7 @@ class MipsBranchDelay(regress.RegressTest): disas(mem, addr) CODE = 0x400000 - asm = '0000a4126a00822800000000'.decode('hex') + asm = '0000a4126a00822800000000'.decode('hex') # beq $a0, $s5, 0x4008a0; slti $v0, $a0, 0x6a; nop print 'Input instructions:' disas(asm, CODE) From 734aa15fa6bf10e6cf18f4b511313b71a072bf8a Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 22 Sep 2015 12:12:17 +0800 Subject: [PATCH 48/66] correct supported archs in COMPILE.TXT --- COMPILE.TXT | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/COMPILE.TXT b/COMPILE.TXT index bbcb96ca..9001cbfd 100644 --- a/COMPILE.TXT +++ b/COMPILE.TXT @@ -35,11 +35,11 @@ Unicorn requires few dependent packages as followings [1] Tailor Unicorn to your need. - Out of 8 archtitectures supported by Unicorn (Arm, Arm64, Mips, PPC, Sparc, - SystemZ, XCore & X86), if you just need several selected archs, choose which - ones you want to compile in by editing "config.mk" before going to next steps. + Out of 6 archtitectures supported by Unicorn (Arm, Arm64, M68K, Mips, Sparc, + & X86), if you just need several selected archs, choose which ones you want + to compile in by editing "config.mk" before going to next steps. - By default, all 8 architectures are compiled. + By default, all 6 architectures are compiled. The other way of customize Unicorn without having to edit config.mk is to pass the desired options on the commandline to ./make.sh. Currently, From 75c5904ec1110230efe73ee005356327631d3e99 Mon Sep 17 00:00:00 2001 From: Sean Heelan Date: Tue, 22 Sep 2015 12:26:01 +0700 Subject: [PATCH 49/66] Makes the hook types consistent, with a single indicator for each of read, write and fetch. This commit only adds the enum values. The functionality still has to be updated. As per issue #111 --- bindings/python/unicorn/unicorn_const.py | 19 ++++++++++--------- include/unicorn/unicorn.h | 23 ++++++++++++----------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/bindings/python/unicorn/unicorn_const.py b/bindings/python/unicorn/unicorn_const.py index 7999afc1..ec0896a6 100644 --- a/bindings/python/unicorn/unicorn_const.py +++ b/bindings/python/unicorn/unicorn_const.py @@ -53,19 +53,20 @@ UC_ERR_WRITE_UNALIGNED = 18 UC_ERR_FETCH_UNALIGNED = 19 UC_MEM_READ = 16 UC_MEM_WRITE = 17 -UC_MEM_READ_WRITE = 18 -UC_MEM_FETCH = 19 -UC_MEM_WRITE_PROT = 20 -UC_MEM_READ_PROT = 21 -UC_MEM_EXEC_PROT = 22 +UC_MEM_FETCH = 18 +UC_MEM_WRITE_PROT = 19 +UC_MEM_READ_PROT = 20 +UC_MEM_FETCH_PROT = 21 UC_HOOK_INTR = 32 UC_HOOK_INSN = 33 UC_HOOK_CODE = 34 UC_HOOK_BLOCK = 35 -UC_HOOK_MEM_INVALID = 36 -UC_HOOK_MEM_READ = 37 -UC_HOOK_MEM_WRITE = 38 -UC_HOOK_MEM_READ_WRITE = 39 +UC_HOOK_MEM_INVALID_READ = 36 +UC_HOOK_MEM_INVALID_WRITE = 37 +UC_HOOK_MEM_INVALID_FETCH = 38 +UC_HOOK_MEM_READ = 39 +UC_HOOK_MEM_WRITE = 40 +UC_HOOK_MEM_FETCH = 41 UC_PROT_NONE = 0 UC_PROT_READ = 1 diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 08e01028..6e5a49bb 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -155,23 +155,24 @@ typedef void (*uc_cb_insn_out_t)(uc_engine *uc, uint32_t port, int size, uint32_ typedef enum uc_mem_type { UC_MEM_READ = 16, // Unmapped memory is read from UC_MEM_WRITE, // Unmapped memory is written to - UC_MEM_READ_WRITE, // Unmapped memory is accessed (either READ or WRITE) - UC_MEM_FETCH, // Unmapped memory is fetched + UC_MEM_FETCH, // Unmapped memory is fetched UC_MEM_WRITE_PROT, // Write to write protected, but mapped, memory UC_MEM_READ_PROT, // Read from read protected, but mapped, memory - UC_MEM_EXEC_PROT, // Fetch from non-executable, but mapped, memory + UC_MEM_FETCH_PROT, // Fetch from non-executable, but mapped, memory } uc_mem_type; // All type of hooks for uc_hook_add() API. typedef enum uc_hook_type { - UC_HOOK_INTR = 32, // Hook all interrupt events - UC_HOOK_INSN, // Hook a particular instruction - UC_HOOK_CODE, // Hook a range of code - UC_HOOK_BLOCK, // Hook basic blocks - UC_HOOK_MEM_INVALID, // Hook for all invalid memory access events - UC_HOOK_MEM_READ, // Hook all memory read events. - UC_HOOK_MEM_WRITE, // Hook all memory write events. - UC_HOOK_MEM_READ_WRITE, // Hook all memory accesses (either READ or WRITE). + UC_HOOK_INTR = 32, // Hook all interrupt events + UC_HOOK_INSN, // Hook a particular instruction + UC_HOOK_CODE, // Hook a range of code + UC_HOOK_BLOCK, // Hook basic blocks + UC_HOOK_MEM_INVALID_READ, // Hook for invalid memory read events + UC_HOOK_MEM_INVALID_WRITE, // Hook for invalid memory write events + UC_HOOK_MEM_INVALID_FETCH, // Hook for invalid memory fetch for execution events + UC_HOOK_MEM_READ, // Hook all memory read events. + UC_HOOK_MEM_WRITE, // Hook all memory write events. + UC_HOOK_MEM_FETCH, // Hook all memory fetch for execution events } uc_hook_type; // Callback function for hooking memory (UC_HOOK_MEM_*) From cb2b97f26cc5e840ecd1ced8669d7f4102c35ff0 Mon Sep 17 00:00:00 2001 From: Sean Heelan Date: Tue, 22 Sep 2015 12:37:05 +0700 Subject: [PATCH 50/66] Remove uc_cb_eventmem_t as it is identical to uc_cb_hookmem_t, as per issue #111 --- include/unicorn/unicorn.h | 10 ---------- qemu/softmmu_template.h | 20 ++++++++++---------- uc.c | 2 +- 3 files changed, 11 insertions(+), 21 deletions(-) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 6e5a49bb..e3fbd36d 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -184,16 +184,6 @@ typedef enum uc_hook_type { typedef void (*uc_cb_hookmem_t)(uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data); -// Callback function for handling memory events (for UC_HOOK_MEM_INVALID) -// @type: this memory is being READ, or WRITE -// @address: address where the code is being executed -// @size: size of data being read or written -// @value: value of data being written to memory, or irrelevant if type = READ. -// @user_data: user data passed to tracing APIs -// @return: return true to continue, or false to stop program (due to invalid memory). -typedef bool (*uc_cb_eventmem_t)(uc_engine *uc, uc_mem_type type, - uint64_t address, int size, int64_t value, void *user_data); - /* Return combined API version & major and minor version numbers. diff --git a/qemu/softmmu_template.h b/qemu/softmmu_template.h index 9e8afd46..19addf35 100644 --- a/qemu/softmmu_template.h +++ b/qemu/softmmu_template.h @@ -191,7 +191,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, mem_access = UC_MEM_READ; error_code = UC_ERR_READ_INVALID; #endif - if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + if (uc->hook_mem_idx != 0 && ((uc_cb_hookmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( uc, mem_access, addr, DATA_SIZE, 0, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; @@ -208,7 +208,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, #if defined(SOFTMMU_CODE_ACCESS) // Unicorn: callback on fetch from NX if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { // non-executable - if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + if (uc->hook_mem_idx != 0 && ((uc_cb_hookmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( uc, UC_MEM_EXEC_PROT, addr, DATA_SIZE, 0, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; @@ -233,7 +233,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, // Unicorn: callback on non-readable memory if (READ_ACCESS_TYPE == MMU_DATA_LOAD && mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable - if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + if (uc->hook_mem_idx != 0 && ((uc_cb_hookmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; @@ -381,7 +381,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, mem_access = UC_MEM_READ; error_code = UC_ERR_READ_INVALID; #endif - if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + if (uc->hook_mem_idx != 0 && ((uc_cb_hookmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( uc, mem_access, addr, DATA_SIZE, 0, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; @@ -398,7 +398,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, #if defined(SOFTMMU_CODE_ACCESS) // Unicorn: callback on fetch from NX if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { // non-executable - if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + if (uc->hook_mem_idx != 0 && ((uc_cb_hookmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( uc, UC_MEM_EXEC_PROT, addr, DATA_SIZE, 0, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; @@ -423,7 +423,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, // Unicorn: callback on non-readable memory if (READ_ACCESS_TYPE == MMU_DATA_LOAD && mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable - if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + if (uc->hook_mem_idx != 0 && ((uc_cb_hookmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; @@ -609,7 +609,7 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, // Unicorn: callback on invalid memory if (uc->hook_mem_idx && mr == NULL) { - if (!((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + if (!((uc_cb_hookmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( uc, UC_MEM_WRITE, addr, DATA_SIZE, (int64_t)val, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { // save error & quit @@ -625,7 +625,7 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, // Unicorn: callback on non-writable memory if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //non-writable - if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + if (uc->hook_mem_idx != 0 && ((uc_cb_hookmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( uc, UC_MEM_WRITE_PROT, addr, DATA_SIZE, (int64_t)val, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; @@ -755,7 +755,7 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, // Unicorn: callback on invalid memory if (uc->hook_mem_idx && mr == NULL) { - if (!((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + if (!((uc_cb_hookmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( uc, UC_MEM_WRITE, addr, DATA_SIZE, (int64_t)val, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { // save error & quit @@ -771,7 +771,7 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, // Unicorn: callback on non-writable memory if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //non-writable - if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + if (uc->hook_mem_idx != 0 && ((uc_cb_hookmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( uc, UC_MEM_WRITE_PROT, addr, DATA_SIZE, (int64_t)val, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; diff --git a/uc.c b/uc.c index 2d97b7c9..4f34a6b4 100644 --- a/uc.c +++ b/uc.c @@ -830,7 +830,7 @@ MemoryRegion *memory_mapping(struct uc_struct* uc, uint64_t address) return NULL; } -static uc_err _hook_mem_invalid(struct uc_struct* uc, uc_cb_eventmem_t callback, +static uc_err _hook_mem_invalid(struct uc_struct* uc, uc_cb_hookmem_t callback, void *user_data, uc_hook *evh) { size_t i; From 2ef59e5727a9815eb48a7ddbe79e30fdeeb9fcfc Mon Sep 17 00:00:00 2001 From: Sean Heelan Date: Wed, 23 Sep 2015 12:48:13 +0700 Subject: [PATCH 51/66] Renamed UC_HOOK_MEM_INVALID_[READ/WRITE/FETCH] to UC_HOOK_MEM_[READ/WRITE/FETCH]_INVALID as per aquynh's feedback. --- include/unicorn/unicorn.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index e3fbd36d..ad2d551e 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -167,9 +167,9 @@ typedef enum uc_hook_type { UC_HOOK_INSN, // Hook a particular instruction UC_HOOK_CODE, // Hook a range of code UC_HOOK_BLOCK, // Hook basic blocks - UC_HOOK_MEM_INVALID_READ, // Hook for invalid memory read events - UC_HOOK_MEM_INVALID_WRITE, // Hook for invalid memory write events - UC_HOOK_MEM_INVALID_FETCH, // Hook for invalid memory fetch for execution events + UC_HOOK_MEM_READ_INVALID, // Hook for invalid memory read events + UC_HOOK_MEM_WRITE_INVALID, // Hook for invalid memory write events + UC_HOOK_MEM_FETCH_INVALID, // Hook for invalid memory fetch for execution events UC_HOOK_MEM_READ, // Hook all memory read events. UC_HOOK_MEM_WRITE, // Hook all memory write events. UC_HOOK_MEM_FETCH, // Hook all memory fetch for execution events From dfb4a9d9ade5719bea7f624ec21bbdb7081c711a Mon Sep 17 00:00:00 2001 From: Sean Heelan Date: Wed, 23 Sep 2015 12:51:47 +0700 Subject: [PATCH 52/66] Revert "Remove uc_cb_eventmem_t as it is identical to uc_cb_hookmem_t" As pointed out by aquynh the return types are actually different. A uc_cb_eventmem_t callback returns a bool, while uc_cb_hookmem_t has a void return type. This reverts commit cb2b97f26cc5e840ecd1ced8669d7f4102c35ff0. --- include/unicorn/unicorn.h | 10 ++++++++++ qemu/softmmu_template.h | 20 ++++++++++---------- uc.c | 2 +- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index ad2d551e..4947d199 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -184,6 +184,16 @@ typedef enum uc_hook_type { typedef void (*uc_cb_hookmem_t)(uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data); +// Callback function for handling memory events (for UC_HOOK_MEM_INVALID) +// @type: this memory is being READ, or WRITE +// @address: address where the code is being executed +// @size: size of data being read or written +// @value: value of data being written to memory, or irrelevant if type = READ. +// @user_data: user data passed to tracing APIs +// @return: return true to continue, or false to stop program (due to invalid memory). +typedef bool (*uc_cb_eventmem_t)(uc_engine *uc, uc_mem_type type, + uint64_t address, int size, int64_t value, void *user_data); + /* Return combined API version & major and minor version numbers. diff --git a/qemu/softmmu_template.h b/qemu/softmmu_template.h index 19addf35..9e8afd46 100644 --- a/qemu/softmmu_template.h +++ b/qemu/softmmu_template.h @@ -191,7 +191,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, mem_access = UC_MEM_READ; error_code = UC_ERR_READ_INVALID; #endif - if (uc->hook_mem_idx != 0 && ((uc_cb_hookmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( uc, mem_access, addr, DATA_SIZE, 0, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; @@ -208,7 +208,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, #if defined(SOFTMMU_CODE_ACCESS) // Unicorn: callback on fetch from NX if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { // non-executable - if (uc->hook_mem_idx != 0 && ((uc_cb_hookmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( uc, UC_MEM_EXEC_PROT, addr, DATA_SIZE, 0, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; @@ -233,7 +233,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, // Unicorn: callback on non-readable memory if (READ_ACCESS_TYPE == MMU_DATA_LOAD && mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable - if (uc->hook_mem_idx != 0 && ((uc_cb_hookmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; @@ -381,7 +381,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, mem_access = UC_MEM_READ; error_code = UC_ERR_READ_INVALID; #endif - if (uc->hook_mem_idx != 0 && ((uc_cb_hookmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( uc, mem_access, addr, DATA_SIZE, 0, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; @@ -398,7 +398,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, #if defined(SOFTMMU_CODE_ACCESS) // Unicorn: callback on fetch from NX if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { // non-executable - if (uc->hook_mem_idx != 0 && ((uc_cb_hookmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( uc, UC_MEM_EXEC_PROT, addr, DATA_SIZE, 0, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; @@ -423,7 +423,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, // Unicorn: callback on non-readable memory if (READ_ACCESS_TYPE == MMU_DATA_LOAD && mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable - if (uc->hook_mem_idx != 0 && ((uc_cb_hookmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; @@ -609,7 +609,7 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, // Unicorn: callback on invalid memory if (uc->hook_mem_idx && mr == NULL) { - if (!((uc_cb_hookmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + if (!((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( uc, UC_MEM_WRITE, addr, DATA_SIZE, (int64_t)val, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { // save error & quit @@ -625,7 +625,7 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, // Unicorn: callback on non-writable memory if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //non-writable - if (uc->hook_mem_idx != 0 && ((uc_cb_hookmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( uc, UC_MEM_WRITE_PROT, addr, DATA_SIZE, (int64_t)val, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; @@ -755,7 +755,7 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, // Unicorn: callback on invalid memory if (uc->hook_mem_idx && mr == NULL) { - if (!((uc_cb_hookmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + if (!((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( uc, UC_MEM_WRITE, addr, DATA_SIZE, (int64_t)val, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { // save error & quit @@ -771,7 +771,7 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, // Unicorn: callback on non-writable memory if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //non-writable - if (uc->hook_mem_idx != 0 && ((uc_cb_hookmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( uc, UC_MEM_WRITE_PROT, addr, DATA_SIZE, (int64_t)val, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; diff --git a/uc.c b/uc.c index 4f34a6b4..2d97b7c9 100644 --- a/uc.c +++ b/uc.c @@ -830,7 +830,7 @@ MemoryRegion *memory_mapping(struct uc_struct* uc, uint64_t address) return NULL; } -static uc_err _hook_mem_invalid(struct uc_struct* uc, uc_cb_hookmem_t callback, +static uc_err _hook_mem_invalid(struct uc_struct* uc, uc_cb_eventmem_t callback, void *user_data, uc_hook *evh) { size_t i; From e479f7240317e1232a19bf6c4454fc9f98256a08 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 24 Sep 2015 13:52:10 +0800 Subject: [PATCH 53/66] update .gitignore --- .gitignore | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 659cc24d..ed7c3e25 100644 --- a/.gitignore +++ b/.gitignore @@ -94,12 +94,12 @@ tmp/ bindings/python/build/ config.log -regress/map_crash -regress/sigill -regress/sigill2 -regress/block_test -regress/map_write -regress/ro_mem_test -regress/nr_mem_test -regress/timeout_segfault -regress/rep_movsb +map_crash +sigill +sigill2 +block_test +map_write +ro_mem_test +nr_mem_test +timeout_segfault +rep_movsb From 90eb8f2e72906c7f2b55c3d5f87e163700db93c8 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 24 Sep 2015 14:18:02 +0800 Subject: [PATCH 54/66] This commit continues the PR #111 - Allow to register handler separately for invalid memory access - Add new memory events for hooking: - UC_MEM_READ_INVALID, UC_MEM_WRITE_INVALID, UC_MEM_FETCH_INVALID - UC_HOOK_MEM_READ_PROT, UC_HOOK_MEM_WRITE_PROT, UC_HOOK_MEM_FETCH_PROT - Rename UC_ERR_EXEC_PROT to UC_ERR_FETCH_PROT - Change API uc_hook_add() so event type @type can be combined from hooking types --- bindings/go/unicorn/unicorn_const.go | 35 ++++++----- bindings/python/sample_x86.py | 6 +- bindings/python/unicorn/unicorn.py | 6 +- bindings/python/unicorn/unicorn_const.py | 34 +++++----- hook.c | 30 +++++++-- include/uc_priv.h | 8 ++- include/unicorn/unicorn.h | 36 ++++++----- qemu/cputlb.c | 2 +- qemu/softmmu_template.h | 76 ++++++++++++----------- samples/mem_apis.c | 18 ++++-- samples/sample_x86.c | 4 +- tests/regress/Makefile | 2 +- tests/regress/mem_exec.c | 10 +-- tests/regress/mem_protect.c | 8 +-- tests/regress/mem_unmap.c | 8 +-- tests/regress/nr_mem_test.c | 2 +- tests/regress/reg_write_sign_extension.py | 2 +- tests/regress/regress.sh | 13 ++++ tests/regress/ro_mem_test.c | 2 +- tests/unit/Makefile | 2 +- uc.c | 47 ++++++++++---- 21 files changed, 223 insertions(+), 128 deletions(-) create mode 100755 tests/regress/regress.sh diff --git a/bindings/go/unicorn/unicorn_const.go b/bindings/go/unicorn/unicorn_const.go index 20c42bc9..8bd35349 100644 --- a/bindings/go/unicorn/unicorn_const.go +++ b/bindings/go/unicorn/unicorn_const.go @@ -48,26 +48,33 @@ const ( ERR_MAP = 12 ERR_WRITE_PROT = 13 ERR_READ_PROT = 14 - ERR_EXEC_PROT = 15 + ERR_FETCH_PROT = 15 ERR_ARG = 16 ERR_READ_UNALIGNED = 17 ERR_WRITE_UNALIGNED = 18 ERR_FETCH_UNALIGNED = 19 MEM_READ = 16 MEM_WRITE = 17 - MEM_READ_WRITE = 18 - MEM_FETCH = 19 - MEM_WRITE_PROT = 20 - MEM_READ_PROT = 21 - MEM_EXEC_PROT = 22 - HOOK_INTR = 32 - HOOK_INSN = 33 - HOOK_CODE = 34 - HOOK_BLOCK = 35 - HOOK_MEM_INVALID = 36 - HOOK_MEM_READ = 37 - HOOK_MEM_WRITE = 38 - HOOK_MEM_READ_WRITE = 39 + MEM_FETCH = 18 + MEM_READ_INVALID = 19 + MEM_WRITE_INVALID = 20 + MEM_FETCH_INVALID = 21 + MEM_WRITE_PROT = 22 + MEM_READ_PROT = 23 + MEM_FETCH_PROT = 24 + HOOK_INTR = 1 + HOOK_INSN = 2 + HOOK_CODE = 4 + HOOK_BLOCK = 8 + HOOK_MEM_READ_INVALID = 16 + HOOK_MEM_WRITE_INVALID = 32 + HOOK_MEM_FETCH_INVALID = 64 + HOOK_MEM_READ_PROT = 128 + HOOK_MEM_WRITE_PROT = 256 + HOOK_MEM_FETCH_PROT = 512 + HOOK_MEM_READ = 1024 + HOOK_MEM_WRITE = 2048 + HOOK_MEM_FETCH = 4096 PROT_NONE = 0 PROT_READ = 1 diff --git a/bindings/python/sample_x86.py b/bindings/python/sample_x86.py index 24b82450..151ed73c 100755 --- a/bindings/python/sample_x86.py +++ b/bindings/python/sample_x86.py @@ -33,7 +33,7 @@ def hook_code(uc, address, size, user_data): # callback for tracing invalid memory access (READ or WRITE) def hook_mem_invalid(uc, access, address, size, value, user_data): - if access == UC_MEM_WRITE: + if access == UC_MEM_WRITE_INVALID: print(">>> Missing memory is being WRITE at 0x%x, data size = %u, data value = 0x%x" \ %(address, size, value)) # map this memory in with 2MB in size @@ -231,7 +231,7 @@ def test_i386_invalid_mem_write(): #mu.hook_add(UC_HOOK_CODE, hook_code) # intercept invalid memory events - mu.hook_add(UC_HOOK_MEM_INVALID, hook_mem_invalid) + mu.hook_add(UC_HOOK_MEM_READ_INVALID | UC_HOOK_MEM_WRITE_INVALID, hook_mem_invalid) try: # emulate machine code in infinite time @@ -349,7 +349,7 @@ def test_x86_64(): mu.hook_add(UC_HOOK_MEM_WRITE, hook_mem_access) mu.hook_add(UC_HOOK_MEM_READ, hook_mem_access) # actually you can also use READ_WRITE to trace all memory access - #mu.hook_add(UC_HOOK_MEM_READ_WRITE, hook_mem_access) + #mu.hook_add(UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, hook_mem_access) try: # emulate machine code in infinite time diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index f5e1c63e..dd67306a 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -272,11 +272,13 @@ class Uc(object): cb = ctypes.cast(UC_HOOK_CODE_CB(self._hookcode_cb), UC_HOOK_CODE_CB) status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, cb, \ ctypes.cast(self._callback_count, ctypes.c_void_p), begin, end) - elif htype == UC_HOOK_MEM_INVALID: + elif htype & UC_HOOK_MEM_READ_INVALID or htype & UC_HOOK_MEM_WRITE_INVALID or \ + htype & UC_HOOK_MEM_FETCH_INVALID or htype & UC_HOOK_MEM_READ_PROT or \ + htype & UC_HOOK_MEM_WRITE_PROT or htype & UC_HOOK_MEM_FETCH_PROT: cb = ctypes.cast(UC_HOOK_MEM_INVALID_CB(self._hook_mem_invalid_cb), UC_HOOK_MEM_INVALID_CB) status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \ cb, ctypes.cast(self._callback_count, ctypes.c_void_p)) - elif htype in (UC_HOOK_MEM_READ, UC_HOOK_MEM_WRITE, UC_HOOK_MEM_READ_WRITE): + elif htype in (UC_HOOK_MEM_READ, UC_HOOK_MEM_WRITE, UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE): cb = ctypes.cast(UC_HOOK_MEM_ACCESS_CB(self._hook_mem_access_cb), UC_HOOK_MEM_ACCESS_CB) status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \ cb, ctypes.cast(self._callback_count, ctypes.c_void_p)) diff --git a/bindings/python/unicorn/unicorn_const.py b/bindings/python/unicorn/unicorn_const.py index ec0896a6..467cdd29 100644 --- a/bindings/python/unicorn/unicorn_const.py +++ b/bindings/python/unicorn/unicorn_const.py @@ -46,7 +46,7 @@ UC_ERR_INSN_INVALID = 11 UC_ERR_MAP = 12 UC_ERR_WRITE_PROT = 13 UC_ERR_READ_PROT = 14 -UC_ERR_EXEC_PROT = 15 +UC_ERR_FETCH_PROT = 15 UC_ERR_ARG = 16 UC_ERR_READ_UNALIGNED = 17 UC_ERR_WRITE_UNALIGNED = 18 @@ -54,19 +54,25 @@ UC_ERR_FETCH_UNALIGNED = 19 UC_MEM_READ = 16 UC_MEM_WRITE = 17 UC_MEM_FETCH = 18 -UC_MEM_WRITE_PROT = 19 -UC_MEM_READ_PROT = 20 -UC_MEM_FETCH_PROT = 21 -UC_HOOK_INTR = 32 -UC_HOOK_INSN = 33 -UC_HOOK_CODE = 34 -UC_HOOK_BLOCK = 35 -UC_HOOK_MEM_INVALID_READ = 36 -UC_HOOK_MEM_INVALID_WRITE = 37 -UC_HOOK_MEM_INVALID_FETCH = 38 -UC_HOOK_MEM_READ = 39 -UC_HOOK_MEM_WRITE = 40 -UC_HOOK_MEM_FETCH = 41 +UC_MEM_READ_INVALID = 19 +UC_MEM_WRITE_INVALID = 20 +UC_MEM_FETCH_INVALID = 21 +UC_MEM_WRITE_PROT = 22 +UC_MEM_READ_PROT = 23 +UC_MEM_FETCH_PROT = 24 +UC_HOOK_INTR = 1 +UC_HOOK_INSN = 2 +UC_HOOK_CODE = 4 +UC_HOOK_BLOCK = 8 +UC_HOOK_MEM_READ_INVALID = 16 +UC_HOOK_MEM_WRITE_INVALID = 32 +UC_HOOK_MEM_FETCH_INVALID = 64 +UC_HOOK_MEM_READ_PROT = 128 +UC_HOOK_MEM_WRITE_PROT = 256 +UC_HOOK_MEM_FETCH_PROT = 512 +UC_HOOK_MEM_READ = 1024 +UC_HOOK_MEM_WRITE = 2048 +UC_HOOK_MEM_FETCH = 4096 UC_PROT_NONE = 0 UC_PROT_READ = 1 diff --git a/hook.c b/hook.c index c201c315..dbc61a78 100644 --- a/hook.c +++ b/hook.c @@ -73,7 +73,7 @@ size_t hook_add(struct uc_struct *uc, int type, uint64_t begin, uint64_t end, vo if (begin > end) uc->hook_write_idx = i; break; - case UC_HOOK_MEM_READ_WRITE: + case UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE: uc->hook_mem_read = true; uc->hook_mem_write = true; if (begin > end) { @@ -109,8 +109,28 @@ uc_err hook_del(struct uc_struct *uc, uc_hook hh) uc->hook_write_idx = 0; } - if (hh == uc->hook_mem_idx) { - uc->hook_mem_idx = 0; + if (hh == uc->hook_mem_read_idx) { + uc->hook_mem_read_idx = 0; + } + + if (hh == uc->hook_mem_write_idx) { + uc->hook_mem_write_idx = 0; + } + + if (hh == uc->hook_mem_fetch_idx) { + uc->hook_mem_fetch_idx = 0; + } + + if (hh == uc->hook_mem_read_prot_idx) { + uc->hook_mem_read_prot_idx = 0; + } + + if (hh == uc->hook_mem_write_prot_idx) { + uc->hook_mem_write_prot_idx = 0; + } + + if (hh == uc->hook_mem_fetch_prot_idx) { + uc->hook_mem_fetch_prot_idx = 0; } if (hh == uc->hook_intr_idx) { @@ -176,13 +196,13 @@ static struct hook_struct *_hook_find(struct uc_struct *uc, int type, uint64_t a } break; case UC_HOOK_MEM_READ: - if (uc->hook_callbacks[i].hook_type == UC_HOOK_MEM_READ || uc->hook_callbacks[i].hook_type == UC_HOOK_MEM_READ_WRITE) { + if (uc->hook_callbacks[i].hook_type & UC_HOOK_MEM_READ) { if (uc->hook_callbacks[i].begin <= address && address <= uc->hook_callbacks[i].end) return &uc->hook_callbacks[i]; } break; case UC_HOOK_MEM_WRITE: - if (uc->hook_callbacks[i].hook_type == UC_HOOK_MEM_WRITE || uc->hook_callbacks[i].hook_type == UC_HOOK_MEM_READ_WRITE) { + if (uc->hook_callbacks[i].hook_type & UC_HOOK_MEM_WRITE) { if (uc->hook_callbacks[i].begin <= address && address <= uc->hook_callbacks[i].end) return &uc->hook_callbacks[i]; } diff --git a/include/uc_priv.h b/include/uc_priv.h index c196291a..1f19a58a 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -152,7 +152,13 @@ struct uc_struct { bool hook_block, hook_insn, hook_mem_read, hook_mem_write; uint64_t block_addr; // save the last block address we hooked // indexes to event callbacks - int hook_mem_idx; // for handling invalid memory access + int hook_mem_read_idx; // for handling invalid memory read access on unmapped memory + int hook_mem_write_idx; // for handling invalid memory write access on unmapped memory + int hook_mem_fetch_idx; // for handling invalid memory fetch access on unmapped memory + int hook_mem_read_prot_idx; // for handling invalid memory read access on read-protected memory + int hook_mem_write_prot_idx; // for handling invalid memory write access on write-protected memory + int hook_mem_fetch_prot_idx; // for handling invalid memory fetch access on non-executable memory + int hook_intr_idx; // for handling interrupt int hook_out_idx; // for handling OUT instruction (X86) int hook_in_idx; // for handling IN instruction (X86) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 4947d199..21661f0c 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -120,7 +120,7 @@ typedef enum uc_err { UC_ERR_MAP, // Invalid memory mapping: uc_mem_map() UC_ERR_WRITE_PROT, // Quit emulation due to UC_MEM_WRITE_PROT violation: uc_emu_start() UC_ERR_READ_PROT, // Quit emulation due to UC_MEM_READ_PROT violation: uc_emu_start() - UC_ERR_EXEC_PROT, // Quit emulation due to UC_MEM_EXEC_PROT violation: uc_emu_start() + UC_ERR_FETCH_PROT, // Quit emulation due to UC_MEM_FETCH_PROT violation: uc_emu_start() UC_ERR_ARG, // Inavalid argument provided to uc_xxx function (See specific function API) UC_ERR_READ_UNALIGNED, // Unaligned read UC_ERR_WRITE_UNALIGNED, // Unaligned write @@ -153,9 +153,12 @@ typedef void (*uc_cb_insn_out_t)(uc_engine *uc, uint32_t port, int size, uint32_ // All type of memory accesses for UC_HOOK_MEM_* typedef enum uc_mem_type { - UC_MEM_READ = 16, // Unmapped memory is read from - UC_MEM_WRITE, // Unmapped memory is written to - UC_MEM_FETCH, // Unmapped memory is fetched + UC_MEM_READ = 16, // Memory is read from + UC_MEM_WRITE, // Memory is written to + UC_MEM_FETCH, // Memory is fetched + UC_MEM_READ_INVALID, // Unmapped memory is read from + UC_MEM_WRITE_INVALID, // Unmapped memory is written to + UC_MEM_FETCH_INVALID, // Unmapped memory is fetched UC_MEM_WRITE_PROT, // Write to write protected, but mapped, memory UC_MEM_READ_PROT, // Read from read protected, but mapped, memory UC_MEM_FETCH_PROT, // Fetch from non-executable, but mapped, memory @@ -163,16 +166,19 @@ typedef enum uc_mem_type { // All type of hooks for uc_hook_add() API. typedef enum uc_hook_type { - UC_HOOK_INTR = 32, // Hook all interrupt events - UC_HOOK_INSN, // Hook a particular instruction - UC_HOOK_CODE, // Hook a range of code - UC_HOOK_BLOCK, // Hook basic blocks - UC_HOOK_MEM_READ_INVALID, // Hook for invalid memory read events - UC_HOOK_MEM_WRITE_INVALID, // Hook for invalid memory write events - UC_HOOK_MEM_FETCH_INVALID, // Hook for invalid memory fetch for execution events - UC_HOOK_MEM_READ, // Hook all memory read events. - UC_HOOK_MEM_WRITE, // Hook all memory write events. - UC_HOOK_MEM_FETCH, // Hook all memory fetch for execution events + UC_HOOK_INTR = 1 << 0, // Hook all interrupt events + UC_HOOK_INSN = 1 << 1, // Hook a particular instruction + UC_HOOK_CODE = 1 << 2, // Hook a range of code + UC_HOOK_BLOCK = 1 << 3, // Hook basic blocks + UC_HOOK_MEM_READ_INVALID = 1 << 4, // Hook for invalid memory read events + UC_HOOK_MEM_WRITE_INVALID = 1 << 5, // Hook for invalid memory write events + UC_HOOK_MEM_FETCH_INVALID = 1 << 6, // Hook for invalid memory fetch for execution events + UC_HOOK_MEM_READ_PROT = 1 << 7, // Hook for memory read on read-protected memory + UC_HOOK_MEM_WRITE_PROT = 1 << 8, // Hook for memory write on write-protected memory + UC_HOOK_MEM_FETCH_PROT = 1 << 9, // Hook for memory fetch on non-executable memory + UC_HOOK_MEM_READ = 1 << 10, // Hook memory read events. + UC_HOOK_MEM_WRITE = 1 << 11, // Hook memory write events. + UC_HOOK_MEM_FETCH = 1 << 12, // Hook memory fetch for execution events } uc_hook_type; // Callback function for hooking memory (UC_HOOK_MEM_*) @@ -381,7 +387,7 @@ uc_err uc_emu_stop(uc_engine *uc); for detailed error). */ UNICORN_EXPORT -uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, uc_hook_type type, void *callback, void *user_data, ...); +uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, ...); /* Unregister (remove) a hook callback. diff --git a/qemu/cputlb.c b/qemu/cputlb.c index 30a0727b..b9b16e30 100644 --- a/qemu/cputlb.c +++ b/qemu/cputlb.c @@ -300,7 +300,7 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr) (addr & TARGET_PAGE_MASK))) { cpu_ldub_code(env1, addr); //check for NX related error from softmmu - if (env1->invalid_error == UC_ERR_EXEC_PROT) { + if (env1->invalid_error == UC_ERR_FETCH_PROT) { env1->invalid_error = UC_ERR_CODE_INVALID; return -1; } diff --git a/qemu/softmmu_template.h b/qemu/softmmu_template.h index 9e8afd46..9730c840 100644 --- a/qemu/softmmu_template.h +++ b/qemu/softmmu_template.h @@ -177,7 +177,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, target_ulong tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ; uintptr_t haddr; DATA_TYPE res; - int mem_access, error_code; + int error_code; struct uc_struct *uc = env->uc; MemoryRegion *mr = memory_mapping(uc, addr); @@ -185,15 +185,16 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, // memory can be unmapped while reading or fetching if (mr == NULL) { #if defined(SOFTMMU_CODE_ACCESS) - mem_access = UC_MEM_FETCH; error_code = UC_ERR_FETCH_INVALID; + if (uc->hook_mem_fetch_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_fetch_idx].callback)( + uc, UC_MEM_FETCH_INVALID, addr, DATA_SIZE, 0, + uc->hook_callbacks[uc->hook_mem_fetch_idx].user_data)) { #else - mem_access = UC_MEM_READ; error_code = UC_ERR_READ_INVALID; + if (uc->hook_mem_read_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_read_idx].callback)( + uc, UC_MEM_READ_INVALID, addr, DATA_SIZE, 0, + uc->hook_callbacks[uc->hook_mem_read_idx].user_data)) { #endif - if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( - uc, mem_access, addr, DATA_SIZE, 0, - uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; mr = memory_mapping(uc, addr); // FIXME: what if mr is still NULL at this time? } else { @@ -208,13 +209,13 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, #if defined(SOFTMMU_CODE_ACCESS) // Unicorn: callback on fetch from NX if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { // non-executable - if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( - uc, UC_MEM_EXEC_PROT, addr, DATA_SIZE, 0, - uc->hook_callbacks[uc->hook_mem_idx].user_data)) { + if (uc->hook_mem_fetch_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_fetch_prot_idx].callback)( + uc, UC_MEM_FETCH_PROT, addr, DATA_SIZE, 0, + uc->hook_callbacks[uc->hook_mem_fetch_prot_idx].user_data)) { env->invalid_error = UC_ERR_OK; } else { env->invalid_addr = addr; - env->invalid_error = UC_ERR_EXEC_PROT; + env->invalid_error = UC_ERR_FETCH_PROT; // printf("***** Invalid fetch (non-executable) at " TARGET_FMT_lx "\n", addr); cpu_exit(uc->current_cpu); return 0; @@ -233,9 +234,9 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, // Unicorn: callback on non-readable memory if (READ_ACCESS_TYPE == MMU_DATA_LOAD && mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable - if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + if (uc->hook_mem_read_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_read_prot_idx].callback)( uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0, - uc->hook_callbacks[uc->hook_mem_idx].user_data)) { + uc->hook_callbacks[uc->hook_mem_read_prot_idx].user_data)) { env->invalid_error = UC_ERR_OK; } else { @@ -367,7 +368,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, target_ulong tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ; uintptr_t haddr; DATA_TYPE res; - int mem_access, error_code; + int error_code; struct uc_struct *uc = env->uc; MemoryRegion *mr = memory_mapping(uc, addr); @@ -375,15 +376,16 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, // memory can be unmapped while reading or fetching if (mr == NULL) { #if defined(SOFTMMU_CODE_ACCESS) - mem_access = UC_MEM_FETCH; error_code = UC_ERR_FETCH_INVALID; + if (uc->hook_mem_fetch_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_fetch_idx].callback)( + uc, UC_MEM_FETCH_INVALID, addr, DATA_SIZE, 0, + uc->hook_callbacks[uc->hook_mem_fetch_idx].user_data)) { #else - mem_access = UC_MEM_READ; error_code = UC_ERR_READ_INVALID; + if (uc->hook_mem_read_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_read_idx].callback)( + uc, UC_MEM_READ_INVALID, addr, DATA_SIZE, 0, + uc->hook_callbacks[uc->hook_mem_read_idx].user_data)) { #endif - if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( - uc, mem_access, addr, DATA_SIZE, 0, - uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; mr = memory_mapping(uc, addr); // FIXME: what if mr is still NULL at this time? } else { @@ -398,13 +400,13 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, #if defined(SOFTMMU_CODE_ACCESS) // Unicorn: callback on fetch from NX if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { // non-executable - if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( - uc, UC_MEM_EXEC_PROT, addr, DATA_SIZE, 0, - uc->hook_callbacks[uc->hook_mem_idx].user_data)) { + if (uc->hook_mem_fetch_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_fetch_prot_idx].callback)( + uc, UC_MEM_FETCH_PROT, addr, DATA_SIZE, 0, + uc->hook_callbacks[uc->hook_mem_fetch_prot_idx].user_data)) { env->invalid_error = UC_ERR_OK; } else { env->invalid_addr = addr; - env->invalid_error = UC_ERR_EXEC_PROT; + env->invalid_error = UC_ERR_FETCH_PROT; // printf("***** Invalid fetch (non-executable) at " TARGET_FMT_lx "\n", addr); cpu_exit(uc->current_cpu); return 0; @@ -423,9 +425,9 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, // Unicorn: callback on non-readable memory if (READ_ACCESS_TYPE == MMU_DATA_LOAD && mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable - if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + if (uc->hook_mem_read_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_read_prot_idx].callback)( uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0, - uc->hook_callbacks[uc->hook_mem_idx].user_data)) { + uc->hook_callbacks[uc->hook_mem_read_prot_idx].user_data)) { env->invalid_error = UC_ERR_OK; } else { env->invalid_addr = addr; @@ -608,10 +610,10 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, } // Unicorn: callback on invalid memory - if (uc->hook_mem_idx && mr == NULL) { - if (!((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( - uc, UC_MEM_WRITE, addr, DATA_SIZE, (int64_t)val, - uc->hook_callbacks[uc->hook_mem_idx].user_data)) { + if (uc->hook_mem_write_idx && mr == NULL) { + if (!((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_write_idx].callback)( + uc, UC_MEM_WRITE_INVALID, addr, DATA_SIZE, (int64_t)val, + uc->hook_callbacks[uc->hook_mem_write_idx].user_data)) { // save error & quit env->invalid_addr = addr; env->invalid_error = UC_ERR_WRITE_INVALID; @@ -620,14 +622,15 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, return; } else { env->invalid_error = UC_ERR_OK; + mr = memory_mapping(uc, addr); // FIXME: what if mr is still NULL at this time? } } // Unicorn: callback on non-writable memory if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //non-writable - if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + if (uc->hook_mem_write_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_write_prot_idx].callback)( uc, UC_MEM_WRITE_PROT, addr, DATA_SIZE, (int64_t)val, - uc->hook_callbacks[uc->hook_mem_idx].user_data)) { + uc->hook_callbacks[uc->hook_mem_write_prot_idx].user_data)) { env->invalid_error = UC_ERR_OK; } else { @@ -754,10 +757,10 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, } // Unicorn: callback on invalid memory - if (uc->hook_mem_idx && mr == NULL) { - if (!((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( - uc, UC_MEM_WRITE, addr, DATA_SIZE, (int64_t)val, - uc->hook_callbacks[uc->hook_mem_idx].user_data)) { + if (uc->hook_mem_write_idx && mr == NULL) { + if (!((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_write_idx].callback)( + uc, UC_MEM_WRITE_INVALID, addr, DATA_SIZE, (int64_t)val, + uc->hook_callbacks[uc->hook_mem_write_idx].user_data)) { // save error & quit env->invalid_addr = addr; env->invalid_error = UC_ERR_WRITE_INVALID; @@ -766,14 +769,15 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, return; } else { env->invalid_error = UC_ERR_OK; + mr = memory_mapping(uc, addr); // FIXME: what if mr is still NULL at this time? } } // Unicorn: callback on non-writable memory if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //non-writable - if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + if (uc->hook_mem_write_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_write_prot_idx].callback)( uc, UC_MEM_WRITE_PROT, addr, DATA_SIZE, (int64_t)val, - uc->hook_callbacks[uc->hook_mem_idx].user_data)) { + uc->hook_callbacks[uc->hook_mem_write_prot_idx].user_data)) { env->invalid_error = UC_ERR_OK; } else { diff --git a/samples/mem_apis.c b/samples/mem_apis.c index 6237c578..fea1a834 100644 --- a/samples/mem_apis.c +++ b/samples/mem_apis.c @@ -79,13 +79,13 @@ static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type, default: printf("not ok - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", type, addr); return false; - case UC_MEM_READ: + case UC_MEM_READ_INVALID: printf("not ok - Read from invalid memory at 0x%"PRIx64 ", data size = %u\n", addr, size); return false; - case UC_MEM_WRITE: + case UC_MEM_WRITE_INVALID: printf("not ok - Write to invalid memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); return false; - case UC_MEM_EXEC_PROT: + case UC_MEM_FETCH_PROT: printf("not ok - Fetch from non-executable memory at 0x%"PRIx64 "\n", addr); return false; case UC_MEM_WRITE_PROT: @@ -147,7 +147,9 @@ static void do_nx_demo(bool cause_fault) // intercept code and invalid memory events if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK || - uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { + uc_hook_add(uc, &trace1, + UC_HOOK_MEM_READ_INVALID | UC_HOOK_MEM_WRITE_INVALID | UC_HOOK_MEM_FETCH_INVALID | UC_HOOK_MEM_FETCH_PROT | UC_HOOK_MEM_WRITE_PROT | UC_HOOK_MEM_READ_PROT, + hook_mem_invalid, NULL) != UC_ERR_OK) { printf("not ok - Failed to install hooks\n"); return; } @@ -226,7 +228,9 @@ static void do_perms_demo(bool change_perms) // intercept code and invalid memory events if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK || - uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { + uc_hook_add(uc, &trace1, + UC_HOOK_MEM_READ_INVALID | UC_HOOK_MEM_WRITE_INVALID | UC_HOOK_MEM_FETCH_INVALID | UC_HOOK_MEM_FETCH_PROT | UC_HOOK_MEM_WRITE_PROT | UC_HOOK_MEM_READ_PROT, + hook_mem_invalid, NULL) != UC_ERR_OK) { printf("not ok - Failed to install hooks\n"); return; } @@ -302,7 +306,9 @@ static void do_unmap_demo(bool do_unmap) // intercept code and invalid memory events if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK || - uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { + uc_hook_add(uc, &trace1, + UC_HOOK_MEM_READ_INVALID | UC_HOOK_MEM_WRITE_INVALID | UC_HOOK_MEM_FETCH_INVALID | UC_HOOK_MEM_FETCH_PROT | UC_HOOK_MEM_WRITE_PROT | UC_HOOK_MEM_READ_PROT, + hook_mem_invalid, NULL) != UC_ERR_OK) { printf("not ok - Failed to install hooks\n"); return; } diff --git a/samples/sample_x86.c b/samples/sample_x86.c index c6662dfe..f2a28916 100644 --- a/samples/sample_x86.c +++ b/samples/sample_x86.c @@ -73,7 +73,7 @@ static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type, default: // return false to indicate we want to stop emulation return false; - case UC_MEM_WRITE: + case UC_MEM_WRITE_INVALID: printf(">>> Missing memory is being WRITE at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", address, size, value); // map this memory in with 2MB in size @@ -421,7 +421,7 @@ static void test_i386_invalid_mem_write(void) uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); // intercept invalid memory events - uc_hook_add(uc, &trace3, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL); + uc_hook_add(uc, &trace3, UC_HOOK_MEM_READ_INVALID | UC_HOOK_MEM_WRITE_INVALID, hook_mem_invalid, NULL); // emulate machine code in infinite time err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_MEM_WRITE) - 1, 0, 0); diff --git a/tests/regress/Makefile b/tests/regress/Makefile index 09214579..e03c27e9 100644 --- a/tests/regress/Makefile +++ b/tests/regress/Makefile @@ -1,5 +1,5 @@ CFLAGS += -I../include -LDFLAGS += ../libunicorn.a $(shell pkg-config --libs glib-2.0) -lpthread -lm +LDFLAGS += ../../libunicorn.a $(shell pkg-config --libs glib-2.0) -lpthread -lm TESTS = map_crash map_write TESTS += sigill sigill2 diff --git a/tests/regress/mem_exec.c b/tests/regress/mem_exec.c index 28f7d7a0..db9a2bc1 100644 --- a/tests/regress/mem_exec.c +++ b/tests/regress/mem_exec.c @@ -116,9 +116,9 @@ static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type, { switch(type) { default: - printf("not ok %d - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", log_num++, type, addr); + printf("not ok %d - memory invalid type: %d at 0x%" PRIx64 "\n", log_num++, type, addr); return false; - case UC_MEM_EXEC_PROT: + case UC_MEM_FETCH_PROT: printf("# Fetch from non-executable memory at 0x%"PRIx64 "\n", addr); //make page executable @@ -221,11 +221,11 @@ int main(int argc, char **argv, char **envp) } // intercept invalid memory events - if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { - printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID ucr\n", log_num++); + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE_PROT | UC_HOOK_MEM_FETCH_PROT, hook_mem_invalid, NULL) != UC_ERR_OK) { + printf("not ok %d - Failed to install memory invalid handler\n", log_num++); return 8; } else { - printf("ok %d - UC_HOOK_MEM_INVALID installed\n", log_num++); + printf("ok %d - memory invalid handler installed\n", log_num++); } // emulate machine code until told to stop by hook_code diff --git a/tests/regress/mem_protect.c b/tests/regress/mem_protect.c index a9dcce9d..d29dc490 100644 --- a/tests/regress/mem_protect.c +++ b/tests/regress/mem_protect.c @@ -138,7 +138,7 @@ static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type, uint32_t testval; switch(type) { default: - printf("not ok %d - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", log_num++, type, addr); + printf("not ok %d - memory invalid type: %d at 0x%" PRIx64 "\n", log_num++, type, addr); return false; case UC_MEM_WRITE_PROT: printf("# write to non-writeable memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); @@ -229,11 +229,11 @@ int main(int argc, char **argv, char **envp) } // intercept invalid memory events - if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { - printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID ucr\n", log_num++); + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE_PROT, hook_mem_invalid, NULL) != UC_ERR_OK) { + printf("not ok %d - Failed to install memory invalid handler\n", log_num++); return 7; } else { - printf("ok %d - UC_HOOK_MEM_INVALID installed\n", log_num++); + printf("ok %d - memory invalid handler installed\n", log_num++); } // emulate machine code until told to stop by hook_code diff --git a/tests/regress/mem_unmap.c b/tests/regress/mem_unmap.c index 435d4665..06223bfa 100644 --- a/tests/regress/mem_unmap.c +++ b/tests/regress/mem_unmap.c @@ -133,7 +133,7 @@ static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type, uint32_t testval; switch(type) { default: - printf("not ok %d - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", log_num++, type, addr); + printf("not ok %d - memory invalid type: %d at 0x%" PRIx64 "\n", log_num++, type, addr); return false; case UC_MEM_WRITE: printf("# write to invalid memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); @@ -224,11 +224,11 @@ int main(int argc, char **argv, char **envp) } // intercept invalid memory events - if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { - printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID ucr\n", log_num++); + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { + printf("not ok %d - Failed to install memory invalid handler\n", log_num++); return 7; } else { - printf("ok %d - UC_HOOK_MEM_INVALID installed\n", log_num++); + printf("ok %d - memory invalid handler installed\n", log_num++); } // emulate machine code until told to stop by hook_code diff --git a/tests/regress/nr_mem_test.c b/tests/regress/nr_mem_test.c index 3fb1f0f4..60e97db7 100644 --- a/tests/regress/nr_mem_test.c +++ b/tests/regress/nr_mem_test.c @@ -86,7 +86,7 @@ int main(int argc, char **argv, char **envp) //uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)0x400000, (uint64_t)0x400fff); // intercept invalid memory events - uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL); + uc_hook_add(uc, &trace1, UC_MEM_READ_PROT, hook_mem_invalid, NULL); // emulate machine code in infinite time printf("BEGIN execution\n"); diff --git a/tests/regress/reg_write_sign_extension.py b/tests/regress/reg_write_sign_extension.py index e2838da2..34d65506 100755 --- a/tests/regress/reg_write_sign_extension.py +++ b/tests/regress/reg_write_sign_extension.py @@ -24,7 +24,7 @@ class RegWriteSignExt(regress.RegressTest): # jmp ebx mu.mem_write(0x10000000, b'\xff\xe3') - mu.hook_add(unicorn.UC_HOOK_MEM_INVALID, hook_mem_invalid) + mu.hook_add(unicorn.UC_HOOK_MEM_FETCH_INVALID | unicorn.UC_HOOK_MEM_FETCH_PROT, hook_mem_invalid) mu.emu_start(0x10000000, 0x10000000 + 2, count=1) if __name__ == '__main__': diff --git a/tests/regress/regress.sh b/tests/regress/regress.sh new file mode 100755 index 00000000..f0b79900 --- /dev/null +++ b/tests/regress/regress.sh @@ -0,0 +1,13 @@ +#!/bin/sh + + +./map_crash map_write +./sigill sigill2 +./block_test +./ro_mem_test nr_mem_test +./timeout_segfault +./rep_movsb +./mem_unmap +./mem_protect +./mem_exec + diff --git a/tests/regress/ro_mem_test.c b/tests/regress/ro_mem_test.c index 02e13bac..1e612033 100644 --- a/tests/regress/ro_mem_test.c +++ b/tests/regress/ro_mem_test.c @@ -142,7 +142,7 @@ int main(int argc, char **argv, char **envp) //uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)0x400000, (uint64_t)0x400fff); // intercept invalid memory events - uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL); + uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE_INVALID | UC_HOOK_MEM_WRITE_PROT, hook_mem_invalid, NULL); // emulate machine code in infinite time printf("BEGIN execution - 1\n"); diff --git a/tests/unit/Makefile b/tests/unit/Makefile index 499d1a5f..ae66d08e 100644 --- a/tests/unit/Makefile +++ b/tests/unit/Makefile @@ -11,7 +11,7 @@ all: ${ALL_TESTS} .PHONY: clean clean: - rm ${ALL_TESTS} + rm -rf ${ALL_TESTS} .PHONY: test test: export LD_LIBRARY_PATH=../../ diff --git a/uc.c b/uc.c index 2d97b7c9..d5219542 100644 --- a/uc.c +++ b/uc.c @@ -87,8 +87,8 @@ const char *uc_strerror(uc_err code) return "Write to write-protected memory (UC_ERR_WRITE_PROT)"; case UC_ERR_READ_PROT: return "Read from non-readable memory (UC_ERR_READ_PROT)"; - case UC_ERR_EXEC_PROT: - return "Fetch from non-executable memory (UC_ERR_EXEC_PROT)"; + case UC_ERR_FETCH_PROT: + return "Fetch from non-executable memory (UC_ERR_FETCH_PROT)"; case UC_ERR_ARG: return "Invalid argumet (UC_ERR_ARG)"; @@ -830,7 +830,7 @@ MemoryRegion *memory_mapping(struct uc_struct* uc, uint64_t address) return NULL; } -static uc_err _hook_mem_invalid(struct uc_struct* uc, uc_cb_eventmem_t callback, +static uc_err _hook_mem_invalid(struct uc_struct* uc, int type, uc_cb_eventmem_t callback, void *user_data, uc_hook *evh) { size_t i; @@ -842,7 +842,18 @@ static uc_err _hook_mem_invalid(struct uc_struct* uc, uc_cb_eventmem_t callback, uc->hook_callbacks[i].callback = callback; uc->hook_callbacks[i].user_data = user_data; *evh = i; - uc->hook_mem_idx = i; + if (type & UC_HOOK_MEM_READ_INVALID) + uc->hook_mem_read_idx = i; + if (type & UC_HOOK_MEM_READ_PROT) + uc->hook_mem_read_prot_idx = i; + if (type & UC_HOOK_MEM_WRITE_INVALID) + uc->hook_mem_write_idx = i; + if (type & UC_HOOK_MEM_WRITE_PROT) + uc->hook_mem_write_prot_idx = i; + if (type & UC_HOOK_MEM_FETCH_INVALID) + uc->hook_mem_fetch_idx = i; + if (type & UC_HOOK_MEM_FETCH_PROT) + uc->hook_mem_fetch_prot_idx = i; return UC_ERR_OK; } else return UC_ERR_NOMEM; @@ -920,7 +931,7 @@ static uc_err _hook_insn(struct uc_struct *uc, unsigned int insn_id, void *callb } UNICORN_EXPORT -uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, uc_hook_type type, void *callback, void *user_data, ...) +uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, ...) { va_list valist; int ret = UC_ERR_OK; @@ -929,9 +940,26 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, uc_hook_type type, void *callback va_start(valist, user_data); + if (type & UC_HOOK_MEM_READ_INVALID) + ret = _hook_mem_invalid(uc, UC_HOOK_MEM_READ_INVALID, callback, user_data, hh); + + if (type & UC_HOOK_MEM_WRITE_INVALID) + ret = _hook_mem_invalid(uc, UC_HOOK_MEM_WRITE_INVALID, callback, user_data, hh); + + if (type & UC_HOOK_MEM_FETCH_INVALID) + ret = _hook_mem_invalid(uc, UC_HOOK_MEM_FETCH_INVALID, callback, user_data, hh); + + if (type & UC_HOOK_MEM_READ_PROT) + ret = _hook_mem_invalid(uc, UC_HOOK_MEM_READ_PROT, callback, user_data, hh); + + if (type & UC_HOOK_MEM_WRITE_PROT) + ret = _hook_mem_invalid(uc, UC_HOOK_MEM_WRITE_PROT, callback, user_data, hh); + + if (type & UC_HOOK_MEM_FETCH_PROT) + ret = _hook_mem_invalid(uc, UC_HOOK_MEM_FETCH_PROT, callback, user_data, hh); + switch(type) { default: - ret = UC_ERR_HOOK; break; case UC_HOOK_INTR: ret = _hook_intr(uc, callback, user_data, hh); @@ -950,9 +978,6 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, uc_hook_type type, void *callback end = va_arg(valist, uint64_t); ret = _hook_code(uc, UC_HOOK_BLOCK, begin, end, callback, user_data, hh); break; - case UC_HOOK_MEM_INVALID: - ret = _hook_mem_invalid(uc, callback, user_data, hh); - break; case UC_HOOK_MEM_READ: begin = va_arg(valist, uint64_t); end = va_arg(valist, uint64_t); @@ -963,10 +988,10 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, uc_hook_type type, void *callback end = va_arg(valist, uint64_t); ret = _hook_mem_access(uc, UC_HOOK_MEM_WRITE, begin, end, callback, user_data, hh); break; - case UC_HOOK_MEM_READ_WRITE: + case UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE: begin = va_arg(valist, uint64_t); end = va_arg(valist, uint64_t); - ret = _hook_mem_access(uc, UC_HOOK_MEM_READ_WRITE, begin, end, callback, user_data, hh); + ret = _hook_mem_access(uc, UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, begin, end, callback, user_data, hh); break; } From eb19d9bff595830643b81d3a093675e6984dfa6b Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Thu, 24 Sep 2015 01:01:39 -0700 Subject: [PATCH 55/66] update Go bindings for #149 --- bindings/go/unicorn/hook.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/bindings/go/unicorn/hook.go b/bindings/go/unicorn/hook.go index bfa72c80..c286f08f 100644 --- a/bindings/go/unicorn/hook.go +++ b/bindings/go/unicorn/hook.go @@ -71,10 +71,7 @@ func (u *uc) HookAdd(htype int, cb interface{}, extra ...uint64) (Hook, error) { case HOOK_BLOCK, HOOK_CODE: rangeMode = true callback = C.hookCode_cgo - case HOOK_MEM_INVALID: - rangeMode = true - callback = C.hookMemInvalid_cgo - case HOOK_MEM_READ, HOOK_MEM_WRITE, HOOK_MEM_READ_WRITE: + case HOOK_MEM_READ, HOOK_MEM_WRITE, HOOK_MEM_READ | HOOK_MEM_WRITE: rangeMode = true callback = C.hookMemAccess_cgo case HOOK_INTR: @@ -92,7 +89,14 @@ func (u *uc) HookAdd(htype int, cb interface{}, extra ...uint64) (Hook, error) { return 0, errors.New("Unknown instruction type.") } default: - return 0, errors.New("Unknown hook type.") + // special case for mask + if htype&(HOOK_MEM_READ_INVALID|HOOK_MEM_WRITE_INVALID|HOOK_MEM_FETCH_INVALID| + HOOK_MEM_READ_PROT|HOOK_MEM_WRITE_PROT|HOOK_MEM_FETCH_PROT) != 0 { + rangeMode = true + callback = C.hookMemInvalid_cgo + } else { + return 0, errors.New("Unknown hook type.") + } } var h2 C.uc_hook data := &HookData{u, cb} From 738b8d89f915f8093ba5243ade6c03a3ba6d6dfa Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 24 Sep 2015 18:50:49 +0800 Subject: [PATCH 56/66] correct instructions for uc_cb_hookmem_t & uc_cb_eventmem_t. this fixes a part of issue #151 --- include/unicorn/unicorn.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 21661f0c..52f9cd1f 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -181,7 +181,7 @@ typedef enum uc_hook_type { UC_HOOK_MEM_FETCH = 1 << 12, // Hook memory fetch for execution events } uc_hook_type; -// Callback function for hooking memory (UC_HOOK_MEM_*) +// Callback function for hooking memory (UC_MEM_READ, UC_MEM_WRITE & UC_MEM_FETCH) // @type: this memory is being READ, or WRITE // @address: address where the code is being executed // @size: size of data being read or written @@ -190,7 +190,8 @@ typedef enum uc_hook_type { typedef void (*uc_cb_hookmem_t)(uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data); -// Callback function for handling memory events (for UC_HOOK_MEM_INVALID) +// Callback function for handling invalid memory access events (UC_MEM_*_INVALID and +// UC_MEM_*PROT events) // @type: this memory is being READ, or WRITE // @address: address where the code is being executed // @size: size of data being read or written From 2599d41404e10cfd53008e8242ab9f37e50f5289 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 24 Sep 2015 19:21:31 +0800 Subject: [PATCH 57/66] add some hooking macros for all kind of memory access events --- include/unicorn/unicorn.h | 19 +++++++++++++++++++ samples/mem_apis.c | 3 +-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 52f9cd1f..dd7e5536 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -181,6 +181,25 @@ typedef enum uc_hook_type { UC_HOOK_MEM_FETCH = 1 << 12, // Hook memory fetch for execution events } uc_hook_type; +// hook type for all events of unmapped memory access +#define UC_HOOK_MEM_INVALID (UC_HOOK_MEM_READ_INVALID + UC_HOOK_MEM_WRITE_INVALID + UC_HOOK_MEM_FETCH_INVALID) +// hook type for all events of illegal protected memory access +#define UC_HOOK_MEM_PROT (UC_HOOK_MEM_READ_PROT + UC_HOOK_MEM_WRITE_PROT + UC_HOOK_MEM_FETCH_PROT) +// hook type for all events of illegal read memory access +#define UC_HOOK_MEM_READ_ERR (UC_HOOK_MEM_READ_PROT + UC_HOOK_MEM_READ_INVALID) +// hook type for all events of illegal write memory access +#define UC_HOOK_MEM_WRITE_ERR (UC_HOOK_MEM_WRITE_PROT + UC_HOOK_MEM_WRITE_INVALID) +// hook type for all events of illegal fetch memory access +#define UC_HOOK_MEM_FETCH_ERR (UC_HOOK_MEM_FETCH_PROT + UC_HOOK_MEM_FETCH_INVALID) +// hook type for all events of illegal memory access +#define UC_HOOK_MEM_ERR (UC_HOOK_MEM_INVALID + UC_HOOK_MEM_PROT) +// hook type for all events of read memory access +#define UC_HOOK_MEM_READ_ALL (UC_HOOK_MEM_READ_ERR + UC_HOOK_MEM_READ) +// hook type for all events of write memory access +#define UC_HOOK_MEM_WRITE_ALL (UC_HOOK_MEM_WRITE_ERR + UC_HOOK_MEM_WRITE) +// hook type for all events of fetch memory access +#define UC_HOOK_MEM_FETCH_ALL (UC_HOOK_MEM_FETCH_ERR + UC_HOOK_MEM_FETCH) + // Callback function for hooking memory (UC_MEM_READ, UC_MEM_WRITE & UC_MEM_FETCH) // @type: this memory is being READ, or WRITE // @address: address where the code is being executed diff --git a/samples/mem_apis.c b/samples/mem_apis.c index fea1a834..28f2b60c 100644 --- a/samples/mem_apis.c +++ b/samples/mem_apis.c @@ -147,8 +147,7 @@ static void do_nx_demo(bool cause_fault) // intercept code and invalid memory events if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK || - uc_hook_add(uc, &trace1, - UC_HOOK_MEM_READ_INVALID | UC_HOOK_MEM_WRITE_INVALID | UC_HOOK_MEM_FETCH_INVALID | UC_HOOK_MEM_FETCH_PROT | UC_HOOK_MEM_WRITE_PROT | UC_HOOK_MEM_READ_PROT, + uc_hook_add(uc, &trace1, UC_HOOK_MEM_ERR, hook_mem_invalid, NULL) != UC_ERR_OK) { printf("not ok - Failed to install hooks\n"); return; From 14a71b5546881696ab75d604f7ff8e5d8a93bc83 Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Thu, 24 Sep 2015 04:33:02 -0700 Subject: [PATCH 58/66] update java bindings for new memory event hooking constants --- bindings/java/samples/Sample_x86.java | 22 ++-- .../{ReadWriteHook.java => EventMemHook.java} | 4 +- bindings/java/unicorn/MemoryInvalidHook.java | 29 ----- bindings/java/unicorn/Unicorn.java | 103 ++++++++---------- bindings/java/unicorn/UnicornConst.java | 38 ++++--- bindings/java/unicorn_Unicorn.c | 25 ++--- 6 files changed, 89 insertions(+), 132 deletions(-) rename bindings/java/unicorn/{ReadWriteHook.java => EventMemHook.java} (84%) delete mode 100644 bindings/java/unicorn/MemoryInvalidHook.java diff --git a/bindings/java/samples/Sample_x86.java b/bindings/java/samples/Sample_x86.java index 24985713..edda0e97 100644 --- a/bindings/java/samples/Sample_x86.java +++ b/bindings/java/samples/Sample_x86.java @@ -83,18 +83,14 @@ public class Sample_x86 { } } - private static class MyMemInvalidHook implements MemoryInvalidHook { - public boolean hook(Unicorn u, int type, long address, int size, long value, Object user) { - switch(type) { - case Unicorn.UC_MEM_WRITE: - System.out.printf(">>> Missing memory is being WRITE at 0x%x, data size = %d, data value = 0x%x\n", - address, size, value); - // map this memory in with 2MB in size - u.mem_map(0xaaaa0000, 2 * 1024*1024, Unicorn.UC_PROT_ALL); - // return true to indicate we want to continue - return true; - } - return false; + private static class MyWriteInvalidHook implements EventMemHook { + public boolean hook(Unicorn u, long address, int size, long value, Object user) { + System.out.printf(">>> Missing memory is being WRITE at 0x%x, data size = %d, data value = 0x%x\n", + address, size, value); + // map this memory in with 2MB in size + u.mem_map(0xaaaa0000, 2 * 1024*1024, Unicorn.UC_PROT_ALL); + // return true to indicate we want to continue + return true; } } @@ -423,7 +419,7 @@ public class Sample_x86 { u.hook_add(new MyCodeHook(), 1, 0, null); // intercept invalid memory events - u.hook_add(new MyMemInvalidHook(), null); + u.hook_add(new MyWriteInvalidHook(), Unicorn.UC_HOOK_MEM_WRITE_INVALID, null); // emulate machine code in infinite time try { diff --git a/bindings/java/unicorn/ReadWriteHook.java b/bindings/java/unicorn/EventMemHook.java similarity index 84% rename from bindings/java/unicorn/ReadWriteHook.java rename to bindings/java/unicorn/EventMemHook.java index 4514b483..db1f12d9 100644 --- a/bindings/java/unicorn/ReadWriteHook.java +++ b/bindings/java/unicorn/EventMemHook.java @@ -21,9 +21,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. package unicorn; -public interface ReadWriteHook extends Hook { +public interface EventMemHook extends Hook { - public void hook(Unicorn u, int type, long address, int size, long value, Object user); + public boolean hook(Unicorn u, long address, int size, long value, Object user); } diff --git a/bindings/java/unicorn/MemoryInvalidHook.java b/bindings/java/unicorn/MemoryInvalidHook.java deleted file mode 100644 index 8b0a02d5..00000000 --- a/bindings/java/unicorn/MemoryInvalidHook.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - -Java bindings for the Unicorn Emulator Engine - -Copyright(c) 2015 Chris Eagle - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -version 2 as published by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -*/ - -package unicorn; - -public interface MemoryInvalidHook extends Hook { - - public boolean hook(Unicorn u, int type, long address, int size, long value, Object user); - -} - diff --git a/bindings/java/unicorn/Unicorn.java b/bindings/java/unicorn/Unicorn.java index 40476ae0..c9ed1436 100644 --- a/bindings/java/unicorn/Unicorn.java +++ b/bindings/java/unicorn/Unicorn.java @@ -31,10 +31,15 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S private long interruptHandle = 0; private long codeHandle = 0; - private long memInvalidHandle = 0; + private Hashtable eventMemHandles = new Hashtable(); + private long readInvalidHandle = 0; + private long writeInvalidHandle = 0; + private long fetchProtHandle = 0; + private long readProtHandle = 0; + private long writeProtHandle = 0; + private long readHandle = 0; private long writeHandle = 0; - private long readWriteHandle = 0; private long inHandle = 0; private long outHandle = 0; private long syscallHandle = 0; @@ -51,21 +56,28 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S private ArrayList blockList = new ArrayList(); private ArrayList intrList = new ArrayList(); private ArrayList codeList = new ArrayList(); - private ArrayList memInvalidList = new ArrayList(); private ArrayList readList = new ArrayList(); private ArrayList writeList = new ArrayList(); - private ArrayList readWriteList = new ArrayList(); private ArrayList inList = new ArrayList(); private ArrayList outList = new ArrayList(); private ArrayList syscallList = new ArrayList(); + private Hashtable > eventMemLists = new Hashtable >(); + private ArrayList> allLists = new ArrayList>(); + private static Hashtable eventMemMap = new Hashtable(); private static Hashtable unicorns = new Hashtable(); //required to load native method implementations static { System.loadLibrary("unicorn_java"); //loads unicorn.dll or libunicorn.so + eventMemMap.put(UC_HOOK_MEM_READ_INVALID, UC_MEM_READ_INVALID); + eventMemMap.put(UC_HOOK_MEM_WRITE_INVALID, UC_MEM_WRITE_INVALID); + eventMemMap.put(UC_HOOK_MEM_FETCH_INVALID, UC_MEM_FETCH_INVALID); + eventMemMap.put(UC_HOOK_MEM_READ_PROT, UC_MEM_READ_PROT); + eventMemMap.put(UC_HOOK_MEM_WRITE_PROT, UC_MEM_WRITE_PROT); + eventMemMap.put(UC_HOOK_MEM_FETCH_PROT, UC_MEM_FETCH_PROT); } /** @@ -128,25 +140,29 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S } /** - * Invoke all UC_HOOK_MEM_INVALID callbacks registered for a specific Unicorn. + * Invoke all UC_HOOK_MEM_XXX_INVALID andor UC_HOOK_MEM_XXX_PROT callbacks registered + * for a specific Unicorn. * This function gets invoked from the native C callback registered for - * for UC_HOOK_MEM_INVALID + * for UC_HOOK_MEM_XXX_INVALID or UC_HOOK_MEM_XXX_PROT * * @param eng A Unicorn uc_engine* eng returned by uc_open - * @param type This memory is being read (UC_MEM_READ), or written (UC_MEM_WRITE) + * @param type The type of event that is taking place * @param address Address of instruction being executed * @param size Size of data being read or written * @param value Value of data being written to memory, or irrelevant if type = READ. * @return true to continue, or false to stop program (due to invalid memory). - * @see hook_add, unicorn.MemoryInvalidHook + * @see hook_add, unicorn.EventMemHook */ - private static boolean invokeMemInvalidCallbacks(long eng, int type, long address, int size, long value) { + private static boolean invokeEventMemCallbacks(long eng, int type, long address, int size, long value) { Unicorn u = unicorns.get(eng); boolean result = true; if (u != null) { - for (Tuple p : u.memInvalidList) { - MemoryInvalidHook mh = (MemoryInvalidHook)p.function; - result &= mh.hook(u, type, address, size, value, p.data); + ArrayList funcList = u.eventMemLists.get(type); + if (funcList != null) { + for (Tuple p : funcList) { + EventMemHook emh = (EventMemHook)p.function; + result &= emh.hook(u, address, size, value, p.data); + } } } return result; @@ -193,28 +209,6 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S } } -/** - * Invoke all UC_HOOK_MEM_READ_WRITE callbacks registered for a specific Unicorn. - * This function gets invoked from the native C callback registered for - * for UC_HOOK_MEM_READ_WRITE - * - * @param eng A Unicorn uc_engine* eng returned by uc_open - * @param type Type of access being performed (UC_MEM_READ, UC_MEM_WRITE, UC_MEM_READ_WRITE) - * @param address Address of instruction being executed - * @param size Size of data being read - * @param value value being written (if applicable) - * @see hook_add, unicorn.ReadWriteHook - */ - private static void invokeReadWriteCallbacks(long eng, int type, long address, int size, long value) { - Unicorn u = unicorns.get(eng); - if (u != null) { - for (Tuple p : u.readWriteList) { - ReadWriteHook rwh = (ReadWriteHook)p.function; - rwh.hook(u, type, address, size, value, p.data); - } - } - } - /** * Invoke all UC_HOOK_INSN callbacks registered for a specific Unicorn. * This is specifically for the x86 IN instruction. @@ -303,10 +297,8 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S allLists.add(blockList); allLists.add(intrList); allLists.add(codeList); - allLists.add(memInvalidList); allLists.add(readList); allLists.add(writeList); - allLists.add(readWriteList); allLists.add(inList); allLists.add(outList); allLists.add(syscallList); @@ -528,34 +520,27 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S } /** - * Hook registration for UC_HOOK_MEM_READ_WRITE hooks. The registered callback function will be - * invoked whenever a memory read or write is performed within the address range begin <= mem_addr <= end. For - * the special case in which begin > end, the callback will be invoked for ALL memory reads and writes. + * Hook registration for UC_HOOK_MEM_XXX_INVALID and UC_HOOK_MEM_XXX_PROT hooks. + * The registered callback function will be invoked whenever a read or write is + * attempted from an invalid or protected memory address. * - * @param callback Implementation of a ReadWriteHook interface - * @param begin Start address of memory read/write range - * @param end End address of memory read/write range + * @param callback Implementation of a EventMemHook interface + * @param type Type of memory event being hooked such as UC_HOOK_MEM_READ_INVALID or UC_HOOK_MEM_WRITE_PROT * @param user_data User data to be passed to the callback function each time the event is triggered */ - public void hook_add(ReadWriteHook callback, long begin, long end, Object user_data) throws UnicornException { - if (readWriteHandle == 0) { - readWriteHandle = registerHook(eng, UC_HOOK_MEM_READ_WRITE, begin, end); + public void hook_add(EventMemHook callback, int type, Object user_data) throws UnicornException { + Long handle = eventMemHandles.get(type); + if (handle == null) { + eventMemHandles.put(type, registerHook(eng, type)); } - readWriteList.add(new Tuple(callback, user_data)); - } - -/** - * Hook registration for UC_HOOK_MEM_INVALID hooks. The registered callback function will be - * invoked whenever a read or write is attempted from an unmapped memory address. - * - * @param callback Implementation of a MemoryInvalidHook interface - * @param user_data User data to be passed to the callback function each time the event is triggered - */ - public void hook_add(MemoryInvalidHook callback, Object user_data) throws UnicornException { - if (memInvalidHandle == 0) { - memInvalidHandle = registerHook(eng, UC_HOOK_MEM_INVALID); + int cbType = eventMemMap.get(type); + ArrayList flist = eventMemLists.get(cbType); + if (flist == null) { + flist = new ArrayList(); + allLists.add(flist); + eventMemLists.put(cbType, flist); } - memInvalidList.add(new Tuple(callback, user_data)); + flist.add(new Tuple(callback, user_data)); } /** diff --git a/bindings/java/unicorn/UnicornConst.java b/bindings/java/unicorn/UnicornConst.java index ba85074b..615a6906 100644 --- a/bindings/java/unicorn/UnicornConst.java +++ b/bindings/java/unicorn/UnicornConst.java @@ -50,23 +50,33 @@ public interface UnicornConst { public static final int UC_ERR_MAP = 12; public static final int UC_ERR_WRITE_PROT = 13; public static final int UC_ERR_READ_PROT = 14; - public static final int UC_ERR_EXEC_PROT = 15; + public static final int UC_ERR_FETCH_PROT = 15; public static final int UC_ERR_ARG = 16; + public static final int UC_ERR_READ_UNALIGNED = 17; + public static final int UC_ERR_WRITE_UNALIGNED = 18; + public static final int UC_ERR_FETCH_UNALIGNED = 19; public static final int UC_MEM_READ = 16; public static final int UC_MEM_WRITE = 17; - public static final int UC_MEM_READ_WRITE = 18; - public static final int UC_MEM_FETCH = 19; - public static final int UC_MEM_WRITE_PROT = 20; - public static final int UC_MEM_READ_PROT = 21; - public static final int UC_MEM_EXEC_PROT = 22; - public static final int UC_HOOK_INTR = 32; - public static final int UC_HOOK_INSN = 33; - public static final int UC_HOOK_CODE = 34; - public static final int UC_HOOK_BLOCK = 35; - public static final int UC_HOOK_MEM_INVALID = 36; - public static final int UC_HOOK_MEM_READ = 37; - public static final int UC_HOOK_MEM_WRITE = 38; - public static final int UC_HOOK_MEM_READ_WRITE = 39; + public static final int UC_MEM_FETCH = 18; + public static final int UC_MEM_READ_INVALID = 19; + public static final int UC_MEM_WRITE_INVALID = 20; + public static final int UC_MEM_FETCH_INVALID = 21; + public static final int UC_MEM_WRITE_PROT = 22; + public static final int UC_MEM_READ_PROT = 23; + public static final int UC_MEM_FETCH_PROT = 24; + public static final int UC_HOOK_INTR = 1; + public static final int UC_HOOK_INSN = 2; + public static final int UC_HOOK_CODE = 4; + public static final int UC_HOOK_BLOCK = 8; + public static final int UC_HOOK_MEM_READ_INVALID = 16; + public static final int UC_HOOK_MEM_WRITE_INVALID = 32; + public static final int UC_HOOK_MEM_FETCH_INVALID = 64; + public static final int UC_HOOK_MEM_READ_PROT = 128; + public static final int UC_HOOK_MEM_WRITE_PROT = 256; + public static final int UC_HOOK_MEM_FETCH_PROT = 512; + public static final int UC_HOOK_MEM_READ = 1024; + public static final int UC_HOOK_MEM_WRITE = 2048; + public static final int UC_HOOK_MEM_FETCH = 4096; public static final int UC_PROT_NONE = 0; public static final int UC_PROT_READ = 1; diff --git a/bindings/java/unicorn_Unicorn.c b/bindings/java/unicorn_Unicorn.c index 6a454a5a..470c6340 100644 --- a/bindings/java/unicorn_Unicorn.c +++ b/bindings/java/unicorn_Unicorn.c @@ -33,10 +33,9 @@ static jmethodID invokeBlockCallbacks = 0; static jmethodID invokeInterruptCallbacks = 0; static jmethodID invokeCodeCallbacks = 0; -static jmethodID invokeMemInvalidCallbacks = 0; +static jmethodID invokeEventMemCallbacks = 0; static jmethodID invokeReadCallbacks = 0; static jmethodID invokeWriteCallbacks = 0; -static jmethodID invokeReadWriteCallbacks = 0; static jmethodID invokeInCallbacks = 0; static jmethodID invokeOutCallbacks = 0; static jmethodID invokeSyscallCallbacks = 0; @@ -157,9 +156,6 @@ static void cb_hookmem(uc_engine *eng, uc_mem_type type, case UC_MEM_WRITE: (*env)->CallStaticVoidMethod(env, clz, invokeWriteCallbacks, (jlong)eng, (jlong)address, (int)size, (jlong)value); break; - case UC_MEM_READ_WRITE: - (*env)->CallStaticVoidMethod(env, clz, invokeReadWriteCallbacks, (jlong)eng, (int)type, (jlong)address, (int)size, (jlong)value); - break; } (*cachedJVM)->DetachCurrentThread(cachedJVM); } @@ -179,7 +175,7 @@ static bool cb_eventmem(uc_engine *eng, uc_mem_type type, if ((*env)->ExceptionCheck(env)) { return false; } - jboolean res = (*env)->CallStaticBooleanMethod(env, clz, invokeMemInvalidCallbacks, (jlong)eng, (int)type, (jlong)address, (int)size, (jlong)value); + jboolean res = (*env)->CallStaticBooleanMethod(env, clz, invokeEventMemCallbacks, (jlong)eng, (int)type, (jlong)address, (int)size, (jlong)value); (*cachedJVM)->DetachCurrentThread(cachedJVM); return res; } @@ -393,9 +389,14 @@ JNIEXPORT jlong JNICALL Java_unicorn_Unicorn_registerHook__JI } err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookintr, env); break; - case UC_HOOK_MEM_INVALID: // Hook for all invalid memory access events - if (invokeMemInvalidCallbacks == 0) { - invokeMemInvalidCallbacks = (*env)->GetStaticMethodID(env, clz, "invokeMemInvalidCallbacks", "(JIJIJ)Z"); + case UC_HOOK_MEM_FETCH_INVALID: // Hook for all invalid memory access events + case UC_HOOK_MEM_READ_INVALID: // Hook for all invalid memory access events + case UC_HOOK_MEM_WRITE_INVALID: // Hook for all invalid memory access events + case UC_HOOK_MEM_FETCH_PROT: // Hook for all invalid memory access events + case UC_HOOK_MEM_READ_PROT: // Hook for all invalid memory access events + case UC_HOOK_MEM_WRITE_PROT: // Hook for all invalid memory access events + if (invokeEventMemCallbacks == 0) { + invokeEventMemCallbacks = (*env)->GetStaticMethodID(env, clz, "invokeEventMemCallbacks", "(JIJIJ)Z"); } err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_eventmem, env); break; @@ -471,12 +472,6 @@ JNIEXPORT jlong JNICALL Java_unicorn_Unicorn_registerHook__JIJJ } err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookmem, env, arg1, arg2); break; - case UC_HOOK_MEM_READ_WRITE: // Hook all memory accesses (either READ or WRITE). - if (invokeReadWriteCallbacks == 0) { - invokeReadWriteCallbacks = (*env)->GetStaticMethodID(env, clz, "invokeReadWriteCallbacks", "(JIJIJ)V"); - } - err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookmem, env, arg1, arg2); - break; } return (jlong)hh; } From aa546ba7d6124ec1aac6a2dce36d7f3efbda443e Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 24 Sep 2015 20:59:45 +0800 Subject: [PATCH 59/66] add UC_HOOK_MEM_ALL macro to hook all kind of memory accesses --- include/unicorn/unicorn.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index dd7e5536..8fd36c9e 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -199,6 +199,8 @@ typedef enum uc_hook_type { #define UC_HOOK_MEM_WRITE_ALL (UC_HOOK_MEM_WRITE_ERR + UC_HOOK_MEM_WRITE) // hook type for all events of fetch memory access #define UC_HOOK_MEM_FETCH_ALL (UC_HOOK_MEM_FETCH_ERR + UC_HOOK_MEM_FETCH) +// hook type for all events of memory access +#define UC_HOOK_MEM_ALL (UC_HOOK_READ_ALL + UC_HOOK_WRITE_ALL + UC_HOOK_FETCH_ALL) // Callback function for hooking memory (UC_MEM_READ, UC_MEM_WRITE & UC_MEM_FETCH) // @type: this memory is being READ, or WRITE From dc1e9d36264d01cf332fd5e2e919db330f7a259c Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 24 Sep 2015 23:23:05 +0800 Subject: [PATCH 60/66] remove UC_HOOK_*_ALL hook types as they are not for same hook handlers --- include/unicorn/unicorn.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 8fd36c9e..75f47064 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -193,14 +193,6 @@ typedef enum uc_hook_type { #define UC_HOOK_MEM_FETCH_ERR (UC_HOOK_MEM_FETCH_PROT + UC_HOOK_MEM_FETCH_INVALID) // hook type for all events of illegal memory access #define UC_HOOK_MEM_ERR (UC_HOOK_MEM_INVALID + UC_HOOK_MEM_PROT) -// hook type for all events of read memory access -#define UC_HOOK_MEM_READ_ALL (UC_HOOK_MEM_READ_ERR + UC_HOOK_MEM_READ) -// hook type for all events of write memory access -#define UC_HOOK_MEM_WRITE_ALL (UC_HOOK_MEM_WRITE_ERR + UC_HOOK_MEM_WRITE) -// hook type for all events of fetch memory access -#define UC_HOOK_MEM_FETCH_ALL (UC_HOOK_MEM_FETCH_ERR + UC_HOOK_MEM_FETCH) -// hook type for all events of memory access -#define UC_HOOK_MEM_ALL (UC_HOOK_READ_ALL + UC_HOOK_WRITE_ALL + UC_HOOK_FETCH_ALL) // Callback function for hooking memory (UC_MEM_READ, UC_MEM_WRITE & UC_MEM_FETCH) // @type: this memory is being READ, or WRITE From 4297ba431019a9cc73b8bcf2161817b93062a0dc Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Thu, 24 Sep 2015 09:41:49 -0700 Subject: [PATCH 61/66] additional update to handle new hooking macros --- bindings/java/unicorn/MemHook.java | 27 +++++++++++++++++++ bindings/java/unicorn/Unicorn.java | 42 ++++++++++++++++++++++-------- 2 files changed, 58 insertions(+), 11 deletions(-) create mode 100755 bindings/java/unicorn/MemHook.java mode change 100644 => 100755 bindings/java/unicorn/Unicorn.java diff --git a/bindings/java/unicorn/MemHook.java b/bindings/java/unicorn/MemHook.java new file mode 100755 index 00000000..9f1a1889 --- /dev/null +++ b/bindings/java/unicorn/MemHook.java @@ -0,0 +1,27 @@ +/* + +Java bindings for the Unicorn Emulator Engine + +Copyright(c) 2015 Chris Eagle + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +version 2 as published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +package unicorn; + +public interface MemHook extends ReadHook,WriteHook { + +} + diff --git a/bindings/java/unicorn/Unicorn.java b/bindings/java/unicorn/Unicorn.java old mode 100644 new mode 100755 index c9ed1436..9abfeb60 --- a/bindings/java/unicorn/Unicorn.java +++ b/bindings/java/unicorn/Unicorn.java @@ -519,6 +519,21 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S writeList.add(new Tuple(callback, user_data)); } +/** + * Hook registration for UC_HOOK_MEM_WRITE | UC_HOOK_MEM_WRITE hooks. The registered callback function will be + * invoked whenever a memory write or read is performed within the address range begin <= addr <= end. For + * the special case in which begin > end, the callback will be invoked for ALL memory writes. + * + * @param callback Implementation of a MemHook interface + * @param begin Start address of memory range + * @param end End address of memory range + * @param user_data User data to be passed to the callback function each time the event is triggered + */ + public void hook_add(MemHook callback, long begin, long end, Object user_data) throws UnicornException { + hook_add((ReadHook)callback, begin, end, user_data); + hook_add((WriteHook)callback, begin, end, user_data); + } + /** * Hook registration for UC_HOOK_MEM_XXX_INVALID and UC_HOOK_MEM_XXX_PROT hooks. * The registered callback function will be invoked whenever a read or write is @@ -529,18 +544,23 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S * @param user_data User data to be passed to the callback function each time the event is triggered */ public void hook_add(EventMemHook callback, int type, Object user_data) throws UnicornException { - Long handle = eventMemHandles.get(type); - if (handle == null) { - eventMemHandles.put(type, registerHook(eng, type)); + //test all of the EventMem related bits in type + for (Integer htype : eventMemMap.keySet()) { + if ((type & htype) != 0) { //the 'htype' bit is set in type + Long handle = eventMemHandles.get(htype); + if (handle == null) { + eventMemHandles.put(htype, registerHook(eng, htype)); + } + int cbType = eventMemMap.get(htype); + ArrayList flist = eventMemLists.get(cbType); + if (flist == null) { + flist = new ArrayList(); + allLists.add(flist); + eventMemLists.put(cbType, flist); + } + flist.add(new Tuple(callback, user_data)); + } } - int cbType = eventMemMap.get(type); - ArrayList flist = eventMemLists.get(cbType); - if (flist == null) { - flist = new ArrayList(); - allLists.add(flist); - eventMemLists.put(cbType, flist); - } - flist.add(new Tuple(callback, user_data)); } /** From 4ebc876bd1d6dfb79c1096e0930d7bd22413b96d Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Thu, 24 Sep 2015 09:47:06 -0700 Subject: [PATCH 62/66] file permissions --- bindings/java/unicorn/MemHook.java | 0 bindings/java/unicorn/Unicorn.java | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 bindings/java/unicorn/MemHook.java mode change 100755 => 100644 bindings/java/unicorn/Unicorn.java diff --git a/bindings/java/unicorn/MemHook.java b/bindings/java/unicorn/MemHook.java old mode 100755 new mode 100644 diff --git a/bindings/java/unicorn/Unicorn.java b/bindings/java/unicorn/Unicorn.java old mode 100755 new mode 100644 From a21772ad3700912ce5238dc63f758f01b6c7bf4c Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Thu, 24 Sep 2015 21:26:54 -0700 Subject: [PATCH 63/66] Cause java constnats to get updated by bindings Makefile --- bindings/Makefile | 1 + 1 file changed, 1 insertion(+) mode change 100644 => 100755 bindings/Makefile diff --git a/bindings/Makefile b/bindings/Makefile old mode 100644 new mode 100755 index 5fa8e472..d004735a --- a/bindings/Makefile +++ b/bindings/Makefile @@ -16,6 +16,7 @@ SAMPLE_X86 = $(TMPDIR)/sample_x86 all: cd python && $(MAKE) gen_const cd go && $(MAKE) gen_const + cd java && $(MAKE) gen_const samples: expected python From 25f85ae1dd3c57ed918b0d5421c81204878dcc5a Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Thu, 24 Sep 2015 21:27:57 -0700 Subject: [PATCH 64/66] file permissions --- bindings/Makefile | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 bindings/Makefile diff --git a/bindings/Makefile b/bindings/Makefile old mode 100755 new mode 100644 From 0e680fbafaf4d4dc8a28857f96d9a36b4b4ba00a Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Thu, 24 Sep 2015 22:45:59 -0700 Subject: [PATCH 65/66] Hack to make gen_const work even if java not installed --- bindings/java/Makefile | 84 +++++++----------------------------- bindings/java/Makefile.build | 78 +++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 68 deletions(-) create mode 100644 bindings/java/Makefile.build diff --git a/bindings/java/Makefile b/bindings/java/Makefile index 4d3af3e5..6d274add 100644 --- a/bindings/java/Makefile +++ b/bindings/java/Makefile @@ -1,78 +1,26 @@ +.PHONY: gen_const clean jar all lib samples install -.PHONY: gen_const clean +all: gen_const + $(MAKE) -f Makefile.build all -JAVA_HOME := $(shell jrunscript -e 'java.lang.System.out.println(java.lang.System.getProperty("java.home"));') +lib: + $(MAKE) -f Makefile.build lib -JAVA_INC := $(shell realpath $(JAVA_HOME)/../include) +samples: + $(MAKE) -f Makefile.build samples -JAVA_PLATFORM_INC := $(shell dirname `find $(JAVA_INC) -name jni_md.h`) - -UNICORN_INC=../../include - -SAMPLES := $(shell ls samples/*.java) -SRC := $(shell ls unicorn/*.java) - -OS := $(shell uname) -ifeq ($(OS),Darwin) - LIB_EXT=.dylib -endif -ifeq ($(OS),Linux) - LIB_EXT=.so -else - LIB_EXT=.dll -endif - -CC=gcc -CFLAGS=-fPIC -LDFLAGS=-shared -fPIC -LIBS=-lunicorn -LIBDIR=-L../../ -INCS=-I$(JAVA_INC) -I$(JAVA_PLATFORM_INC) -I$(UNICORN_INC) - -JC=javac -CLASSPATH=./ - -.SUFFIXES: .java .class - -%.class: %.java - $(JC) $(JFLAGS) $< - -OBJS=unicorn_Unicorn.o - -JARFILE=unicorn.jar - -all: lib jar samples - -%.o: %.c - $(CC) -c $(CFLAGS) $(INCS) $< -o $@ - -unicorn_Unicorn.h: unicorn/Unicorn.java - javah unicorn.Unicorn - -unicorn_Unicorn.o: unicorn_Unicorn.c unicorn_Unicorn.h - $(CC) -c $(CFLAGS) $(INCS) $< -o $@ - -libunicorn_java$(LIB_EXT): unicorn_Unicorn.o - -lib: libunicorn_java$(LIB_EXT) unicorn_Unicorn.h - $(CC) -o $< $(LDFLAGS) $(OBJS) $(LIBDIR) $(LIBS) - -samples: $(SAMPLES:.java=.class) -jarfiles: $(SRC:.java=.class) - -jar: jarfiles - jar cf $(JARFILE) unicorn/*.class +jar: + $(MAKE) -f Makefile.build jar install: lib jar - cp libunicorn_java$(LIB_EXT) $(JAVA_HOME)/lib/ext - cp $(JARFILE) $(JAVA_HOME)/lib/ext + $(MAKE) -f Makefile.build install gen_const: - cd .. && python const_generator.py java + cd .. && python const_generator.py java clean: - rm unicorn/*.class - rm samples/*.class - rm *.so - rm *.dylib - rm *.dll \ No newline at end of file + rm -f unicorn/*.class + rm -f samples/*.class + rm -f *.so + rm -f *.dylib + rm -f *.dll diff --git a/bindings/java/Makefile.build b/bindings/java/Makefile.build new file mode 100644 index 00000000..4d3af3e5 --- /dev/null +++ b/bindings/java/Makefile.build @@ -0,0 +1,78 @@ + +.PHONY: gen_const clean + +JAVA_HOME := $(shell jrunscript -e 'java.lang.System.out.println(java.lang.System.getProperty("java.home"));') + +JAVA_INC := $(shell realpath $(JAVA_HOME)/../include) + +JAVA_PLATFORM_INC := $(shell dirname `find $(JAVA_INC) -name jni_md.h`) + +UNICORN_INC=../../include + +SAMPLES := $(shell ls samples/*.java) +SRC := $(shell ls unicorn/*.java) + +OS := $(shell uname) +ifeq ($(OS),Darwin) + LIB_EXT=.dylib +endif +ifeq ($(OS),Linux) + LIB_EXT=.so +else + LIB_EXT=.dll +endif + +CC=gcc +CFLAGS=-fPIC +LDFLAGS=-shared -fPIC +LIBS=-lunicorn +LIBDIR=-L../../ +INCS=-I$(JAVA_INC) -I$(JAVA_PLATFORM_INC) -I$(UNICORN_INC) + +JC=javac +CLASSPATH=./ + +.SUFFIXES: .java .class + +%.class: %.java + $(JC) $(JFLAGS) $< + +OBJS=unicorn_Unicorn.o + +JARFILE=unicorn.jar + +all: lib jar samples + +%.o: %.c + $(CC) -c $(CFLAGS) $(INCS) $< -o $@ + +unicorn_Unicorn.h: unicorn/Unicorn.java + javah unicorn.Unicorn + +unicorn_Unicorn.o: unicorn_Unicorn.c unicorn_Unicorn.h + $(CC) -c $(CFLAGS) $(INCS) $< -o $@ + +libunicorn_java$(LIB_EXT): unicorn_Unicorn.o + +lib: libunicorn_java$(LIB_EXT) unicorn_Unicorn.h + $(CC) -o $< $(LDFLAGS) $(OBJS) $(LIBDIR) $(LIBS) + +samples: $(SAMPLES:.java=.class) +jarfiles: $(SRC:.java=.class) + +jar: jarfiles + jar cf $(JARFILE) unicorn/*.class + +install: lib jar + cp libunicorn_java$(LIB_EXT) $(JAVA_HOME)/lib/ext + cp $(JARFILE) $(JAVA_HOME)/lib/ext + +gen_const: + cd .. && python const_generator.py java + +clean: + rm unicorn/*.class + rm samples/*.class + rm *.so + rm *.dylib + rm *.dll \ No newline at end of file From 347a01d6b570e0a593e179139d938b5d8595010d Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Fri, 25 Sep 2015 00:20:02 -0700 Subject: [PATCH 66/66] spaces to tabs in Makefile --- bindings/java/Makefile | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/bindings/java/Makefile b/bindings/java/Makefile index 6d274add..df1916be 100644 --- a/bindings/java/Makefile +++ b/bindings/java/Makefile @@ -1,26 +1,26 @@ .PHONY: gen_const clean jar all lib samples install all: gen_const - $(MAKE) -f Makefile.build all + $(MAKE) -f Makefile.build all lib: - $(MAKE) -f Makefile.build lib + $(MAKE) -f Makefile.build lib -samples: - $(MAKE) -f Makefile.build samples +samples: + $(MAKE) -f Makefile.build samples jar: - $(MAKE) -f Makefile.build jar + $(MAKE) -f Makefile.build jar install: lib jar - $(MAKE) -f Makefile.build install + $(MAKE) -f Makefile.build install gen_const: - cd .. && python const_generator.py java + cd .. && python const_generator.py java clean: - rm -f unicorn/*.class - rm -f samples/*.class - rm -f *.so - rm -f *.dylib - rm -f *.dll + rm -f unicorn/*.class + rm -f samples/*.class + rm -f *.so + rm -f *.dylib + rm -f *.dll