From 789971eeb9acbad7bd46251740f1b93374f2fe1c Mon Sep 17 00:00:00 2001 From: xorstream Date: Sat, 23 Jan 2016 00:53:34 +1100 Subject: [PATCH 001/126] Sorted uc_modes by CPU and added masks --- include/unicorn/unicorn.h | 45 +++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 48fd1891..bc2e1d29 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -86,22 +86,35 @@ typedef enum uc_arch { // Mode type typedef enum uc_mode { - UC_MODE_LITTLE_ENDIAN = 0, // little-endian mode (default mode) - UC_MODE_ARM = 0, // 32-bit ARM - UC_MODE_16 = 1 << 1, // 16-bit mode (X86) - UC_MODE_32 = 1 << 2, // 32-bit mode (X86) - UC_MODE_64 = 1 << 3, // 64-bit mode (X86, PPC) - UC_MODE_THUMB = 1 << 4, // ARM's Thumb mode, including Thumb-2 - UC_MODE_MCLASS = 1 << 5, // ARM's Cortex-M series - UC_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM - UC_MODE_MICRO = 1 << 4, // MicroMips mode (MIPS) - UC_MODE_MIPS3 = 1 << 5, // Mips III ISA - UC_MODE_MIPS32R6 = 1 << 6, // Mips32r6 ISA - UC_MODE_V9 = 1 << 4, // SparcV9 mode (Sparc) - UC_MODE_QPX = 1 << 4, // Quad Processing eXtensions mode (PPC) - UC_MODE_BIG_ENDIAN = 1 << 30, // big-endian mode - UC_MODE_MIPS32 = UC_MODE_32, // Mips32 ISA (Mips) - UC_MODE_MIPS64 = UC_MODE_64, // Mips64 ISA (Mips) + UC_MODE_LITTLE_ENDIAN = 0, // little-endian mode (default mode) + UC_MODE_BIG_ENDIAN = 1 << 30, // big-endian mode (currently only supported by MIPS) + // arm / arm64 + UC_MODE_ARM = 0, // 32-bit ARM + UC_MODE_THUMB = 1 << 4, // ARM's Thumb mode, including Thumb-2 + UC_MODE_MCLASS = 1 << 5, // ARM's Cortex-M series (currently unsupported) + UC_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM (currently unsupported) + UC_MODE_ARM_MASK = UC_MODE_ARM|UC_MODE_THUMB|UC_MODE_MCLASS|UC_MODE_MCLASS|UC_MODE_LITTLE_ENDIAN|UC_MODE_BIG_ENDIAN, + // mips + UC_MODE_MICRO = 1 << 4, // MicroMips mode + UC_MODE_MIPS3 = 1 << 5, // Mips III ISA + UC_MODE_MIPS32R6 = 1 << 6, // Mips32r6 ISA + UC_MODE_MIPS32 = 1 << 2, // Mips32 ISA + UC_MODE_MIPS64 = 1 << 3, // Mips64 ISA + UC_MODE_MIPS_MASK = UC_MODE_MICRO|UC_MODE_MIPS3|UC_MODE_MIPS32R6|UC_MODE_MIPS32|UC_MODE_MIPS64|UC_MODE_LITTLE_ENDIAN|UC_MODE_BIG_ENDIAN, + // x86 / x64 + UC_MODE_16 = 1 << 1, // 16-bit mode + UC_MODE_32 = 1 << 2, // 32-bit mode + UC_MODE_64 = 1 << 3, // 64-bit mode + UC_MODE_X86_MASK = UC_MODE_16|UC_MODE_32|UC_MODE_64|UC_MODE_LITTLE_ENDIAN|UC_MODE_BIG_ENDIAN, + // ppc + UC_MODE_PPC64 = 1 << 3, // 64-bit mode + UC_MODE_QPX = 1 << 4, // Quad Processing eXtensions mode + UC_MODE_PPC_MASK = UC_MODE_PPC64|UC_MODE_QPX|UC_MODE_LITTLE_ENDIAN|UC_MODE_BIG_ENDIAN, + // sparc + UC_MODE_V9 = 1 << 4, // SparcV9 mode + UC_MODE_SPARC_MASK = UC_MODE_V9|UC_MODE_LITTLE_ENDIAN|UC_MODE_BIG_ENDIAN, + // m68k + UC_MODE_M68K_MASK = UC_MODE_LITTLE_ENDIAN|UC_MODE_BIG_ENDIAN, } uc_mode; // All type of errors encountered by Unicorn API. From b48fbf752002956d1311bf0e528038bcf3254cd4 Mon Sep 17 00:00:00 2001 From: xorstream Date: Sat, 23 Jan 2016 00:55:31 +1100 Subject: [PATCH 002/126] Sorted uc_modes by CPU and added masks --- include/unicorn/unicorn.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index bc2e1d29..ab1e65bb 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -93,7 +93,7 @@ typedef enum uc_mode { UC_MODE_THUMB = 1 << 4, // ARM's Thumb mode, including Thumb-2 UC_MODE_MCLASS = 1 << 5, // ARM's Cortex-M series (currently unsupported) UC_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM (currently unsupported) - UC_MODE_ARM_MASK = UC_MODE_ARM|UC_MODE_THUMB|UC_MODE_MCLASS|UC_MODE_MCLASS|UC_MODE_LITTLE_ENDIAN|UC_MODE_BIG_ENDIAN, + UC_MODE_ARM_MASK = UC_MODE_ARM|UC_MODE_THUMB|UC_MODE_LITTLE_ENDIAN, // mips UC_MODE_MICRO = 1 << 4, // MicroMips mode UC_MODE_MIPS3 = 1 << 5, // Mips III ISA @@ -105,16 +105,16 @@ typedef enum uc_mode { UC_MODE_16 = 1 << 1, // 16-bit mode UC_MODE_32 = 1 << 2, // 32-bit mode UC_MODE_64 = 1 << 3, // 64-bit mode - UC_MODE_X86_MASK = UC_MODE_16|UC_MODE_32|UC_MODE_64|UC_MODE_LITTLE_ENDIAN|UC_MODE_BIG_ENDIAN, + UC_MODE_X86_MASK = UC_MODE_16|UC_MODE_32|UC_MODE_64|UC_MODE_LITTLE_ENDIAN, // ppc UC_MODE_PPC64 = 1 << 3, // 64-bit mode UC_MODE_QPX = 1 << 4, // Quad Processing eXtensions mode - UC_MODE_PPC_MASK = UC_MODE_PPC64|UC_MODE_QPX|UC_MODE_LITTLE_ENDIAN|UC_MODE_BIG_ENDIAN, + UC_MODE_PPC_MASK = UC_MODE_PPC64|UC_MODE_QPX|UC_MODE_LITTLE_ENDIAN, // sparc UC_MODE_V9 = 1 << 4, // SparcV9 mode - UC_MODE_SPARC_MASK = UC_MODE_V9|UC_MODE_LITTLE_ENDIAN|UC_MODE_BIG_ENDIAN, + UC_MODE_SPARC_MASK = UC_MODE_V9|UC_MODE_LITTLE_ENDIAN, // m68k - UC_MODE_M68K_MASK = UC_MODE_LITTLE_ENDIAN|UC_MODE_BIG_ENDIAN, + UC_MODE_M68K_MASK = UC_MODE_LITTLE_ENDIAN, } uc_mode; // All type of errors encountered by Unicorn API. From 6490b4f2a993a1d2ab07d5a5b9c9a88eb2465f3a Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Fri, 22 Jan 2016 22:44:18 +0800 Subject: [PATCH 003/126] arm64: fix the issue of multiple definition of aarch64_tb_set_jmp_target (issue #387) --- qemu/aarch64.h | 1 + qemu/arm.h | 1 + qemu/header_gen.py | 1 + qemu/m68k.h | 1 + qemu/mips.h | 1 + qemu/mips64.h | 1 + qemu/mips64el.h | 1 + qemu/mipsel.h | 1 + qemu/powerpc.h | 1 + qemu/sparc.h | 1 + qemu/sparc64.h | 1 + qemu/x86_64.h | 1 + 12 files changed, 12 insertions(+) diff --git a/qemu/aarch64.h b/qemu/aarch64.h index af24351f..d75c06e1 100644 --- a/qemu/aarch64.h +++ b/qemu/aarch64.h @@ -1,6 +1,7 @@ /* Autogen header for Unicorn Engine - DONOT MODIFY */ #ifndef UNICORN_AUTOGEN_AARCH64_H #define UNICORN_AUTOGEN_AARCH64_H +#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_aarch64 #define use_idiv_instructions_rt use_idiv_instructions_rt_aarch64 #define tcg_target_deposit_valid tcg_target_deposit_valid_aarch64 #define helper_power_down helper_power_down_aarch64 diff --git a/qemu/arm.h b/qemu/arm.h index ad95d316..ef850c24 100644 --- a/qemu/arm.h +++ b/qemu/arm.h @@ -1,6 +1,7 @@ /* Autogen header for Unicorn Engine - DONOT MODIFY */ #ifndef UNICORN_AUTOGEN_ARM_H #define UNICORN_AUTOGEN_ARM_H +#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_arm #define use_idiv_instructions_rt use_idiv_instructions_rt_arm #define tcg_target_deposit_valid tcg_target_deposit_valid_arm #define helper_power_down helper_power_down_arm diff --git a/qemu/header_gen.py b/qemu/header_gen.py index e9442ecb..46bab7c9 100644 --- a/qemu/header_gen.py +++ b/qemu/header_gen.py @@ -7,6 +7,7 @@ import sys symbols = ( + 'aarch64_tb_set_jmp_target', 'use_idiv_instructions_rt', 'tcg_target_deposit_valid', 'helper_power_down', diff --git a/qemu/m68k.h b/qemu/m68k.h index 47420bd2..8e41d569 100644 --- a/qemu/m68k.h +++ b/qemu/m68k.h @@ -1,6 +1,7 @@ /* Autogen header for Unicorn Engine - DONOT MODIFY */ #ifndef UNICORN_AUTOGEN_M68K_H #define UNICORN_AUTOGEN_M68K_H +#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_m68k #define use_idiv_instructions_rt use_idiv_instructions_rt_m68k #define tcg_target_deposit_valid tcg_target_deposit_valid_m68k #define helper_power_down helper_power_down_m68k diff --git a/qemu/mips.h b/qemu/mips.h index b3c31bbb..0861ed05 100644 --- a/qemu/mips.h +++ b/qemu/mips.h @@ -1,6 +1,7 @@ /* Autogen header for Unicorn Engine - DONOT MODIFY */ #ifndef UNICORN_AUTOGEN_MIPS_H #define UNICORN_AUTOGEN_MIPS_H +#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_mips #define use_idiv_instructions_rt use_idiv_instructions_rt_mips #define tcg_target_deposit_valid tcg_target_deposit_valid_mips #define helper_power_down helper_power_down_mips diff --git a/qemu/mips64.h b/qemu/mips64.h index d3938116..be1a4b4c 100644 --- a/qemu/mips64.h +++ b/qemu/mips64.h @@ -1,6 +1,7 @@ /* Autogen header for Unicorn Engine - DONOT MODIFY */ #ifndef UNICORN_AUTOGEN_MIPS64_H #define UNICORN_AUTOGEN_MIPS64_H +#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_mips64 #define use_idiv_instructions_rt use_idiv_instructions_rt_mips64 #define tcg_target_deposit_valid tcg_target_deposit_valid_mips64 #define helper_power_down helper_power_down_mips64 diff --git a/qemu/mips64el.h b/qemu/mips64el.h index 362bb30d..9e144d9b 100644 --- a/qemu/mips64el.h +++ b/qemu/mips64el.h @@ -1,6 +1,7 @@ /* Autogen header for Unicorn Engine - DONOT MODIFY */ #ifndef UNICORN_AUTOGEN_MIPS64EL_H #define UNICORN_AUTOGEN_MIPS64EL_H +#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_mips64el #define use_idiv_instructions_rt use_idiv_instructions_rt_mips64el #define tcg_target_deposit_valid tcg_target_deposit_valid_mips64el #define helper_power_down helper_power_down_mips64el diff --git a/qemu/mipsel.h b/qemu/mipsel.h index 5e71bef9..8fb00f62 100644 --- a/qemu/mipsel.h +++ b/qemu/mipsel.h @@ -1,6 +1,7 @@ /* Autogen header for Unicorn Engine - DONOT MODIFY */ #ifndef UNICORN_AUTOGEN_MIPSEL_H #define UNICORN_AUTOGEN_MIPSEL_H +#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_mipsel #define use_idiv_instructions_rt use_idiv_instructions_rt_mipsel #define tcg_target_deposit_valid tcg_target_deposit_valid_mipsel #define helper_power_down helper_power_down_mipsel diff --git a/qemu/powerpc.h b/qemu/powerpc.h index 22dad739..5d2f53f2 100644 --- a/qemu/powerpc.h +++ b/qemu/powerpc.h @@ -1,6 +1,7 @@ /* Autogen header for Unicorn Engine - DONOT MODIFY */ #ifndef UNICORN_AUTOGEN_POWERPC_H #define UNICORN_AUTOGEN_POWERPC_H +#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_powerpc #define use_idiv_instructions_rt use_idiv_instructions_rt_powerpc #define tcg_target_deposit_valid tcg_target_deposit_valid_powerpc #define helper_power_down helper_power_down_powerpc diff --git a/qemu/sparc.h b/qemu/sparc.h index 7c78c2e2..cf04547f 100644 --- a/qemu/sparc.h +++ b/qemu/sparc.h @@ -1,6 +1,7 @@ /* Autogen header for Unicorn Engine - DONOT MODIFY */ #ifndef UNICORN_AUTOGEN_SPARC_H #define UNICORN_AUTOGEN_SPARC_H +#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_sparc #define use_idiv_instructions_rt use_idiv_instructions_rt_sparc #define tcg_target_deposit_valid tcg_target_deposit_valid_sparc #define helper_power_down helper_power_down_sparc diff --git a/qemu/sparc64.h b/qemu/sparc64.h index 681a7086..2195b1d6 100644 --- a/qemu/sparc64.h +++ b/qemu/sparc64.h @@ -1,6 +1,7 @@ /* Autogen header for Unicorn Engine - DONOT MODIFY */ #ifndef UNICORN_AUTOGEN_SPARC64_H #define UNICORN_AUTOGEN_SPARC64_H +#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_sparc64 #define use_idiv_instructions_rt use_idiv_instructions_rt_sparc64 #define tcg_target_deposit_valid tcg_target_deposit_valid_sparc64 #define helper_power_down helper_power_down_sparc64 diff --git a/qemu/x86_64.h b/qemu/x86_64.h index 7f00e8b4..bbb695e5 100644 --- a/qemu/x86_64.h +++ b/qemu/x86_64.h @@ -1,6 +1,7 @@ /* Autogen header for Unicorn Engine - DONOT MODIFY */ #ifndef UNICORN_AUTOGEN_X86_64_H #define UNICORN_AUTOGEN_X86_64_H +#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_x86_64 #define use_idiv_instructions_rt use_idiv_instructions_rt_x86_64 #define tcg_target_deposit_valid tcg_target_deposit_valid_x86_64 #define helper_power_down helper_power_down_x86_64 From 82b7599e15757fbb1990dea476233cca05a1f32a Mon Sep 17 00:00:00 2001 From: xorstream Date: Sat, 23 Jan 2016 09:47:29 +1100 Subject: [PATCH 004/126] Sorted uc_modes by CPU and added masks --- include/uc_priv.h | 9 +++++++++ include/unicorn/unicorn.h | 6 ------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/include/uc_priv.h b/include/uc_priv.h index 5cdf6557..6c7362bc 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -11,6 +11,15 @@ #include "unicorn/unicorn.h" #include "hook.h" +// These are masks of supported modes for each cpu/arch. +// They should be updated when changes are made to the uc_mode enum typedef. +#define UC_MODE_ARM_MASK (UC_MODE_ARM|UC_MODE_THUMB|UC_MODE_LITTLE_ENDIAN) +#define UC_MODE_MIPS_MASK (UC_MODE_MICRO|UC_MODE_MIPS3|UC_MODE_MIPS32R6|UC_MODE_MIPS32|UC_MODE_MIPS64|UC_MODE_LITTLE_ENDIAN|UC_MODE_BIG_ENDIAN) +#define UC_MODE_X86_MASK (UC_MODE_16|UC_MODE_32|UC_MODE_64|UC_MODE_LITTLE_ENDIAN) +#define UC_MODE_PPC_MASK (UC_MODE_PPC64|UC_MODE_QPX|UC_MODE_LITTLE_ENDIAN) +#define UC_MODE_SPARC_MASK (UC_MODE_V9|UC_MODE_LITTLE_ENDIAN) +#define UC_MODE_M68K_MASK (UC_MODE_LITTLE_ENDIAN) + #define ARR_SIZE(a) (sizeof(a)/sizeof(a[0])) QTAILQ_HEAD(CPUTailQ, CPUState); diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index ab1e65bb..5150d003 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -93,28 +93,22 @@ typedef enum uc_mode { UC_MODE_THUMB = 1 << 4, // ARM's Thumb mode, including Thumb-2 UC_MODE_MCLASS = 1 << 5, // ARM's Cortex-M series (currently unsupported) UC_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM (currently unsupported) - UC_MODE_ARM_MASK = UC_MODE_ARM|UC_MODE_THUMB|UC_MODE_LITTLE_ENDIAN, // mips UC_MODE_MICRO = 1 << 4, // MicroMips mode UC_MODE_MIPS3 = 1 << 5, // Mips III ISA UC_MODE_MIPS32R6 = 1 << 6, // Mips32r6 ISA UC_MODE_MIPS32 = 1 << 2, // Mips32 ISA UC_MODE_MIPS64 = 1 << 3, // Mips64 ISA - UC_MODE_MIPS_MASK = UC_MODE_MICRO|UC_MODE_MIPS3|UC_MODE_MIPS32R6|UC_MODE_MIPS32|UC_MODE_MIPS64|UC_MODE_LITTLE_ENDIAN|UC_MODE_BIG_ENDIAN, // x86 / x64 UC_MODE_16 = 1 << 1, // 16-bit mode UC_MODE_32 = 1 << 2, // 32-bit mode UC_MODE_64 = 1 << 3, // 64-bit mode - UC_MODE_X86_MASK = UC_MODE_16|UC_MODE_32|UC_MODE_64|UC_MODE_LITTLE_ENDIAN, // ppc UC_MODE_PPC64 = 1 << 3, // 64-bit mode UC_MODE_QPX = 1 << 4, // Quad Processing eXtensions mode - UC_MODE_PPC_MASK = UC_MODE_PPC64|UC_MODE_QPX|UC_MODE_LITTLE_ENDIAN, // sparc UC_MODE_V9 = 1 << 4, // SparcV9 mode - UC_MODE_SPARC_MASK = UC_MODE_V9|UC_MODE_LITTLE_ENDIAN, // m68k - UC_MODE_M68K_MASK = UC_MODE_LITTLE_ENDIAN, } uc_mode; // All type of errors encountered by Unicorn API. From b7c43108bdc7dcb77dee7488c4ca0b3ffb53b26c Mon Sep 17 00:00:00 2001 From: xorstream Date: Sat, 23 Jan 2016 10:45:58 +1100 Subject: [PATCH 005/126] Started fixing uc_mode flag usage --- uc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uc.c b/uc.c index ee7d5549..195f626d 100644 --- a/uc.c +++ b/uc.c @@ -185,7 +185,7 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) // verify mode // TODO: support Big endian, MCLASS & V8 - if (mode & (~(UC_MODE_ARM | UC_MODE_THUMB | UC_MODE_BIG_ENDIAN | UC_MODE_LITTLE_ENDIAN))) { + if (mode & ~UC_MODE_ARM_MASK) { free(uc); return UC_ERR_MODE; } From 8763d426c2fcfa2e72050a927d85843f80dc4758 Mon Sep 17 00:00:00 2001 From: xorstream Date: Sat, 23 Jan 2016 12:08:49 +1100 Subject: [PATCH 006/126] Fix uc_mode usage in source code --- bindings/msvc/samples/main.c | 2 +- include/uc_priv.h | 8 +-- include/unicorn/unicorn.h | 19 ++++--- qemu/target-arm/unicorn_arm.c | 90 +++++++++++++----------------- samples/sample_mips.c | 2 +- samples/sample_sparc.c | 2 +- tests/regress/sparc_jump_to_zero.c | 2 +- uc.c | 4 +- 8 files changed, 59 insertions(+), 70 deletions(-) diff --git a/bindings/msvc/samples/main.c b/bindings/msvc/samples/main.c index c9a24001..1539d68c 100644 --- a/bindings/msvc/samples/main.c +++ b/bindings/msvc/samples/main.c @@ -75,7 +75,7 @@ int main(int argc, char **argv, char **envp) #endif // Initialize emulator in MIPS 32bit little endian mode - err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32, &uc); + err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32 | UC_MODE_LITTLE_ENDIAN, &uc); if (err) { printf("Failed on uc_open() with error returned: %u\n", err); diff --git a/include/uc_priv.h b/include/uc_priv.h index 6c7362bc..12f0b8bc 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -14,11 +14,11 @@ // These are masks of supported modes for each cpu/arch. // They should be updated when changes are made to the uc_mode enum typedef. #define UC_MODE_ARM_MASK (UC_MODE_ARM|UC_MODE_THUMB|UC_MODE_LITTLE_ENDIAN) -#define UC_MODE_MIPS_MASK (UC_MODE_MICRO|UC_MODE_MIPS3|UC_MODE_MIPS32R6|UC_MODE_MIPS32|UC_MODE_MIPS64|UC_MODE_LITTLE_ENDIAN|UC_MODE_BIG_ENDIAN) +#define UC_MODE_MIPS_MASK (UC_MODE_MIPS32|UC_MODE_MIPS64|UC_MODE_LITTLE_ENDIAN|UC_MODE_BIG_ENDIAN) #define UC_MODE_X86_MASK (UC_MODE_16|UC_MODE_32|UC_MODE_64|UC_MODE_LITTLE_ENDIAN) -#define UC_MODE_PPC_MASK (UC_MODE_PPC64|UC_MODE_QPX|UC_MODE_LITTLE_ENDIAN) -#define UC_MODE_SPARC_MASK (UC_MODE_V9|UC_MODE_LITTLE_ENDIAN) -#define UC_MODE_M68K_MASK (UC_MODE_LITTLE_ENDIAN) +#define UC_MODE_PPC_MASK (UC_MODE_PPC64|UC_MODE_BIG_ENDIAN) +#define UC_MODE_SPARC_MASK (UC_MODE_SPARC64|UC_MODE_BIG_ENDIAN) +#define UC_MODE_M68K_MASK (UC_MODE_BIG_ENDIAN) #define ARR_SIZE(a) (sizeof(a)/sizeof(a[0])) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 5150d003..27bb325b 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -87,16 +87,16 @@ typedef enum uc_arch { // Mode type typedef enum uc_mode { UC_MODE_LITTLE_ENDIAN = 0, // little-endian mode (default mode) - UC_MODE_BIG_ENDIAN = 1 << 30, // big-endian mode (currently only supported by MIPS) + UC_MODE_BIG_ENDIAN = 1 << 30, // big-endian mode // arm / arm64 - UC_MODE_ARM = 0, // 32-bit ARM - UC_MODE_THUMB = 1 << 4, // ARM's Thumb mode, including Thumb-2 + UC_MODE_ARM = 0, // Start executing in ARM mode + UC_MODE_THUMB = 1 << 4, // Start executing in THUMB mode (including Thumb-2) UC_MODE_MCLASS = 1 << 5, // ARM's Cortex-M series (currently unsupported) UC_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM (currently unsupported) // mips - UC_MODE_MICRO = 1 << 4, // MicroMips mode - UC_MODE_MIPS3 = 1 << 5, // Mips III ISA - UC_MODE_MIPS32R6 = 1 << 6, // Mips32r6 ISA + UC_MODE_MICRO = 1 << 4, // MicroMips mode (currently unsupported) + UC_MODE_MIPS3 = 1 << 5, // Mips III ISA (currently unsupported) + UC_MODE_MIPS32R6 = 1 << 6, // Mips32r6 ISA (currently unsupported) UC_MODE_MIPS32 = 1 << 2, // Mips32 ISA UC_MODE_MIPS64 = 1 << 3, // Mips64 ISA // x86 / x64 @@ -104,10 +104,11 @@ typedef enum uc_mode { UC_MODE_32 = 1 << 2, // 32-bit mode UC_MODE_64 = 1 << 3, // 64-bit mode // ppc - UC_MODE_PPC64 = 1 << 3, // 64-bit mode - UC_MODE_QPX = 1 << 4, // Quad Processing eXtensions mode + UC_MODE_PPC64 = 1 << 3, // 64-bit mode (currently unsupported) + UC_MODE_QPX = 1 << 4, // Quad Processing eXtensions mode (currently unsupported) // sparc - UC_MODE_V9 = 1 << 4, // SparcV9 mode + UC_MODE_SPARC64 = 1 << 3, // 64-bit mode + UC_MODE_V9 = 1 << 4, // SparcV9 mode (currently unsupported) // m68k } uc_mode; diff --git a/qemu/target-arm/unicorn_arm.c b/qemu/target-arm/unicorn_arm.c index 1c4004af..8c3c8f04 100644 --- a/qemu/target-arm/unicorn_arm.c +++ b/qemu/target-arm/unicorn_arm.c @@ -42,36 +42,30 @@ int arm_reg_read(struct uc_struct *uc, unsigned int regid, void *value) mycpu = first_cpu; - switch(uc->mode) { - default: - break; - case UC_MODE_ARM: - case UC_MODE_THUMB: - if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12) - *(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0]; - else { - switch(regid) { - case UC_ARM_REG_CPSR: - *(int32_t *)value = cpsr_read(&ARM_CPU(uc, mycpu)->env); - break; - //case UC_ARM_REG_SP: - case UC_ARM_REG_R13: - *(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[13]; - break; - //case UC_ARM_REG_LR: - case UC_ARM_REG_R14: - *(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[14]; - break; - //case UC_ARM_REG_PC: - case UC_ARM_REG_R15: - *(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[15]; - break; - } + if (mode & ~UC_MODE_ARM_MASK) { + if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12) + *(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0]; + else { + switch(regid) { + case UC_ARM_REG_CPSR: + *(int32_t *)value = cpsr_read(&ARM_CPU(uc, mycpu)->env); + break; + //case UC_ARM_REG_SP: + case UC_ARM_REG_R13: + *(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[13]; + break; + //case UC_ARM_REG_LR: + case UC_ARM_REG_R14: + *(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[14]; + break; + //case UC_ARM_REG_PC: + case UC_ARM_REG_R15: + *(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[15]; + break; } - break; + } } - return 0; } @@ -84,31 +78,25 @@ int arm_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { CPUState *mycpu = first_cpu; - switch(uc->mode) { - default: - break; - - case UC_MODE_ARM: - case UC_MODE_THUMB: - if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12) - ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0] = *(uint32_t *)value; - else { - switch(regid) { - //case UC_ARM_REG_SP: - case UC_ARM_REG_R13: - ARM_CPU(uc, mycpu)->env.regs[13] = *(uint32_t *)value; - break; - //case UC_ARM_REG_LR: - case UC_ARM_REG_R14: - ARM_CPU(uc, mycpu)->env.regs[14] = *(uint32_t *)value; - break; - //case UC_ARM_REG_PC: - case UC_ARM_REG_R15: - ARM_CPU(uc, mycpu)->env.regs[15] = *(uint32_t *)value; - break; - } + if (mode & ~UC_MODE_ARM_MASK) { + if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12) + ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0] = *(uint32_t *)value; + else { + switch(regid) { + //case UC_ARM_REG_SP: + case UC_ARM_REG_R13: + ARM_CPU(uc, mycpu)->env.regs[13] = *(uint32_t *)value; + break; + //case UC_ARM_REG_LR: + case UC_ARM_REG_R14: + ARM_CPU(uc, mycpu)->env.regs[14] = *(uint32_t *)value; + break; + //case UC_ARM_REG_PC: + case UC_ARM_REG_R15: + ARM_CPU(uc, mycpu)->env.regs[15] = *(uint32_t *)value; + break; } - break; + } } return 0; diff --git a/samples/sample_mips.c b/samples/sample_mips.c index 3f37b189..b27a02b1 100644 --- a/samples/sample_mips.c +++ b/samples/sample_mips.c @@ -105,7 +105,7 @@ static void test_mips_el(void) printf("Emulate MIPS code (little-endian)\n"); // Initialize emulator in MIPS mode - err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32, &uc); + err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_LITTLE_ENDIAN, &uc); if (err) { printf("Failed on uc_open() with error returned: %u (%s)\n", err, uc_strerror(err)); diff --git a/samples/sample_sparc.c b/samples/sample_sparc.c index e966f5af..c361232f 100644 --- a/samples/sample_sparc.c +++ b/samples/sample_sparc.c @@ -57,7 +57,7 @@ static void test_sparc(void) printf("Emulate SPARC code\n"); // Initialize emulator in Sparc mode - err = uc_open(UC_ARCH_SPARC, UC_MODE_32, &uc); + err = uc_open(UC_ARCH_SPARC, 0, &uc); if (err) { printf("Failed on uc_open() with error returned: %u (%s)\n", err, uc_strerror(err)); diff --git a/tests/regress/sparc_jump_to_zero.c b/tests/regress/sparc_jump_to_zero.c index 99148f2f..96392f41 100644 --- a/tests/regress/sparc_jump_to_zero.c +++ b/tests/regress/sparc_jump_to_zero.c @@ -1,7 +1,7 @@ #include #define HARDWARE_ARCHITECTURE UC_ARCH_SPARC -#define HARDWARE_MODE UC_MODE_32 +#define HARDWARE_MODE 0 #define MEMORY_STARTING_ADDRESS 0x1000000 #define MEMORY_SIZE 2 * 1024 * 1024 diff --git a/uc.c b/uc.c index 195f626d..8507a862 100644 --- a/uc.c +++ b/uc.c @@ -190,7 +190,7 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) return UC_ERR_MODE; } - if (mode == UC_MODE_THUMB) + if (mode & UC_MODE_THUMB) uc->thumb = 1; break; #endif @@ -226,7 +226,7 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) #ifdef UNICORN_HAS_SPARC case UC_ARCH_SPARC: - if (mode & UC_MODE_64) + if (mode & UC_MODE_SPARC64) uc->init_arch = sparc64_uc_init; else uc->init_arch = sparc_uc_init; From 288ef1df0aa82868b1c5c022d39131e84016e8db Mon Sep 17 00:00:00 2001 From: xorstream Date: Sat, 23 Jan 2016 12:10:12 +1100 Subject: [PATCH 007/126] Fix uc_mode usage in source code --- include/unicorn/unicorn.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 27bb325b..f3468ab6 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -78,7 +78,7 @@ typedef enum uc_arch { UC_ARCH_ARM64, // ARM-64, also called AArch64 UC_ARCH_MIPS, // Mips architecture UC_ARCH_X86, // X86 architecture (including x86 & x86-64) - UC_ARCH_PPC, // PowerPC architecture + UC_ARCH_PPC, // PowerPC architecture (currently unsupported) UC_ARCH_SPARC, // Sparc architecture UC_ARCH_M68K, // M68K architecture UC_ARCH_MAX, From e9ba6ed804fa92b250337aa587597ff164960b67 Mon Sep 17 00:00:00 2001 From: xorstream Date: Sat, 23 Jan 2016 12:17:59 +1100 Subject: [PATCH 008/126] Fix uc_mode usage in source code --- uc.c | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/uc.c b/uc.c index 8507a862..0fdf25b0 100644 --- a/uc.c +++ b/uc.c @@ -171,24 +171,33 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) break; #ifdef UNICORN_HAS_M68K case UC_ARCH_M68K: + if ((mode & ~UC_MODE_M68K_MASK) || + !(mode & UC_MODE_BIG_ENDIAN)) { + free(uc); + return UC_ERR_MODE; + } uc->init_arch = m68k_uc_init; break; #endif #ifdef UNICORN_HAS_X86 case UC_ARCH_X86: + if ((mode & ~UC_MODE_X86_MASK) || + (mode & UC_MODE_BIG_ENDIAN) || + !(mode & (UC_MODE_16|UC_MODE_32|UC_MODE_64)) { + free(uc); + return UC_ERR_MODE; + } uc->init_arch = x86_uc_init; break; #endif #ifdef UNICORN_HAS_ARM case UC_ARCH_ARM: - uc->init_arch = arm_uc_init; - - // verify mode - // TODO: support Big endian, MCLASS & V8 - if (mode & ~UC_MODE_ARM_MASK) { + if ((mode & ~UC_MODE_ARM_MASK) || + (mode & UC_MODE_BIG_ENDIAN)) { free(uc); return UC_ERR_MODE; } + uc->init_arch = arm_uc_init; if (mode & UC_MODE_THUMB) uc->thumb = 1; @@ -196,12 +205,22 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) #endif #ifdef UNICORN_HAS_ARM64 case UC_ARCH_ARM64: + if ((mode & ~UC_MODE_ARM_MASK) || + (mode & UC_MODE_BIG_ENDIAN)) { + free(uc); + return UC_ERR_MODE; + } uc->init_arch = arm64_uc_init; break; #endif #if defined(UNICORN_HAS_MIPS) || defined(UNICORN_HAS_MIPSEL) || defined(UNICORN_HAS_MIPS64) || defined(UNICORN_HAS_MIPS64EL) case UC_ARCH_MIPS: + if ((mode & ~UC_MODE_MIPS_MASK) || + !(mode & (UC_MODE_MIPS32|UC_MODE_MIPS64)) { + free(uc); + return UC_ERR_MODE; + } if (mode & UC_MODE_BIG_ENDIAN) { #ifdef UNICORN_HAS_MIPS if (mode & UC_MODE_MIPS32) @@ -226,6 +245,10 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) #ifdef UNICORN_HAS_SPARC case UC_ARCH_SPARC: + if (mode & ~UC_MODE_SPARC_MASK) { + free(uc); + return UC_ERR_MODE; + } if (mode & UC_MODE_SPARC64) uc->init_arch = sparc64_uc_init; else From 678d645b801e6c13671ba93291602440e412fe97 Mon Sep 17 00:00:00 2001 From: xorstream Date: Sat, 23 Jan 2016 12:29:22 +1100 Subject: [PATCH 009/126] Fix uc_mode usage in source code --- qemu/target-arm/unicorn_arm.c | 4 ++-- uc.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/qemu/target-arm/unicorn_arm.c b/qemu/target-arm/unicorn_arm.c index 8c3c8f04..6e6417b6 100644 --- a/qemu/target-arm/unicorn_arm.c +++ b/qemu/target-arm/unicorn_arm.c @@ -42,7 +42,7 @@ int arm_reg_read(struct uc_struct *uc, unsigned int regid, void *value) mycpu = first_cpu; - if (mode & ~UC_MODE_ARM_MASK) { + if (uc->mode & ~UC_MODE_ARM_MASK) { if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12) *(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0]; else { @@ -78,7 +78,7 @@ int arm_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { CPUState *mycpu = first_cpu; - if (mode & ~UC_MODE_ARM_MASK) { + if (uc->mode & ~UC_MODE_ARM_MASK) { if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12) ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0] = *(uint32_t *)value; else { diff --git a/uc.c b/uc.c index 0fdf25b0..5ec5e48a 100644 --- a/uc.c +++ b/uc.c @@ -183,7 +183,7 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) case UC_ARCH_X86: if ((mode & ~UC_MODE_X86_MASK) || (mode & UC_MODE_BIG_ENDIAN) || - !(mode & (UC_MODE_16|UC_MODE_32|UC_MODE_64)) { + !(mode & (UC_MODE_16|UC_MODE_32|UC_MODE_64))) { free(uc); return UC_ERR_MODE; } @@ -217,7 +217,7 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) #if defined(UNICORN_HAS_MIPS) || defined(UNICORN_HAS_MIPSEL) || defined(UNICORN_HAS_MIPS64) || defined(UNICORN_HAS_MIPS64EL) case UC_ARCH_MIPS: if ((mode & ~UC_MODE_MIPS_MASK) || - !(mode & (UC_MODE_MIPS32|UC_MODE_MIPS64)) { + !(mode & (UC_MODE_MIPS32|UC_MODE_MIPS64))) { free(uc); return UC_ERR_MODE; } From b6e9121f4879a587848d93106f5d1f897727d6f4 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 23 Jan 2016 09:34:02 +0800 Subject: [PATCH 010/126] use spaces, but not tabs, for indentation --- uc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/uc.c b/uc.c index 5ec5e48a..95a9c48e 100644 --- a/uc.c +++ b/uc.c @@ -172,7 +172,7 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) #ifdef UNICORN_HAS_M68K case UC_ARCH_M68K: if ((mode & ~UC_MODE_M68K_MASK) || - !(mode & UC_MODE_BIG_ENDIAN)) { + !(mode & UC_MODE_BIG_ENDIAN)) { free(uc); return UC_ERR_MODE; } @@ -182,8 +182,8 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) #ifdef UNICORN_HAS_X86 case UC_ARCH_X86: if ((mode & ~UC_MODE_X86_MASK) || - (mode & UC_MODE_BIG_ENDIAN) || - !(mode & (UC_MODE_16|UC_MODE_32|UC_MODE_64))) { + (mode & UC_MODE_BIG_ENDIAN) || + !(mode & (UC_MODE_16|UC_MODE_32|UC_MODE_64))) { free(uc); return UC_ERR_MODE; } @@ -193,7 +193,7 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) #ifdef UNICORN_HAS_ARM case UC_ARCH_ARM: if ((mode & ~UC_MODE_ARM_MASK) || - (mode & UC_MODE_BIG_ENDIAN)) { + (mode & UC_MODE_BIG_ENDIAN)) { free(uc); return UC_ERR_MODE; } @@ -206,7 +206,7 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) #ifdef UNICORN_HAS_ARM64 case UC_ARCH_ARM64: if ((mode & ~UC_MODE_ARM_MASK) || - (mode & UC_MODE_BIG_ENDIAN)) { + (mode & UC_MODE_BIG_ENDIAN)) { free(uc); return UC_ERR_MODE; } @@ -217,7 +217,7 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) #if defined(UNICORN_HAS_MIPS) || defined(UNICORN_HAS_MIPSEL) || defined(UNICORN_HAS_MIPS64) || defined(UNICORN_HAS_MIPS64EL) case UC_ARCH_MIPS: if ((mode & ~UC_MODE_MIPS_MASK) || - !(mode & (UC_MODE_MIPS32|UC_MODE_MIPS64))) { + !(mode & (UC_MODE_MIPS32|UC_MODE_MIPS64))) { free(uc); return UC_ERR_MODE; } From d8aaa2f44caaba092a35987239a20f97dffac5b1 Mon Sep 17 00:00:00 2001 From: xorstream Date: Sat, 23 Jan 2016 12:44:12 +1100 Subject: [PATCH 011/126] Fixes to runtime arm mask checks --- qemu/target-arm/unicorn_arm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qemu/target-arm/unicorn_arm.c b/qemu/target-arm/unicorn_arm.c index 6e6417b6..c75c0244 100644 --- a/qemu/target-arm/unicorn_arm.c +++ b/qemu/target-arm/unicorn_arm.c @@ -42,7 +42,7 @@ int arm_reg_read(struct uc_struct *uc, unsigned int regid, void *value) mycpu = first_cpu; - if (uc->mode & ~UC_MODE_ARM_MASK) { + if (!(uc->mode & ~UC_MODE_ARM_MASK) { if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12) *(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0]; else { @@ -78,7 +78,7 @@ int arm_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { CPUState *mycpu = first_cpu; - if (uc->mode & ~UC_MODE_ARM_MASK) { + if (!(uc->mode & ~UC_MODE_ARM_MASK) { if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12) ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0] = *(uint32_t *)value; else { From b4b83ff207c7e4b848b19b7fe2cc114cc4ab4d43 Mon Sep 17 00:00:00 2001 From: xorstream Date: Sat, 23 Jan 2016 12:56:47 +1100 Subject: [PATCH 012/126] moar fixes --- qemu/target-arm/unicorn_arm.c | 74 +++++++++++++++++------------------ 1 file changed, 35 insertions(+), 39 deletions(-) diff --git a/qemu/target-arm/unicorn_arm.c b/qemu/target-arm/unicorn_arm.c index c75c0244..5065c0f3 100644 --- a/qemu/target-arm/unicorn_arm.c +++ b/qemu/target-arm/unicorn_arm.c @@ -42,27 +42,25 @@ int arm_reg_read(struct uc_struct *uc, unsigned int regid, void *value) mycpu = first_cpu; - if (!(uc->mode & ~UC_MODE_ARM_MASK) { - if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12) - *(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0]; - else { - switch(regid) { - case UC_ARM_REG_CPSR: - *(int32_t *)value = cpsr_read(&ARM_CPU(uc, mycpu)->env); - break; - //case UC_ARM_REG_SP: - case UC_ARM_REG_R13: - *(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[13]; - break; - //case UC_ARM_REG_LR: - case UC_ARM_REG_R14: - *(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[14]; - break; - //case UC_ARM_REG_PC: - case UC_ARM_REG_R15: - *(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[15]; - break; - } + if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12) + *(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0]; + else { + switch(regid) { + case UC_ARM_REG_CPSR: + *(int32_t *)value = cpsr_read(&ARM_CPU(uc, mycpu)->env); + break; + //case UC_ARM_REG_SP: + case UC_ARM_REG_R13: + *(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[13]; + break; + //case UC_ARM_REG_LR: + case UC_ARM_REG_R14: + *(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[14]; + break; + //case UC_ARM_REG_PC: + case UC_ARM_REG_R15: + *(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[15]; + break; } } @@ -78,24 +76,22 @@ int arm_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { CPUState *mycpu = first_cpu; - if (!(uc->mode & ~UC_MODE_ARM_MASK) { - if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12) - ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0] = *(uint32_t *)value; - else { - switch(regid) { - //case UC_ARM_REG_SP: - case UC_ARM_REG_R13: - ARM_CPU(uc, mycpu)->env.regs[13] = *(uint32_t *)value; - break; - //case UC_ARM_REG_LR: - case UC_ARM_REG_R14: - ARM_CPU(uc, mycpu)->env.regs[14] = *(uint32_t *)value; - break; - //case UC_ARM_REG_PC: - case UC_ARM_REG_R15: - ARM_CPU(uc, mycpu)->env.regs[15] = *(uint32_t *)value; - break; - } + if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12) + ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0] = *(uint32_t *)value; + else { + switch(regid) { + //case UC_ARM_REG_SP: + case UC_ARM_REG_R13: + ARM_CPU(uc, mycpu)->env.regs[13] = *(uint32_t *)value; + break; + //case UC_ARM_REG_LR: + case UC_ARM_REG_R14: + ARM_CPU(uc, mycpu)->env.regs[14] = *(uint32_t *)value; + break; + //case UC_ARM_REG_PC: + case UC_ARM_REG_R15: + ARM_CPU(uc, mycpu)->env.regs[15] = *(uint32_t *)value; + break; } } From 5c6c67bb3a2a01bbad09a67df487d5244ad7c474 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 23 Jan 2016 10:17:42 +0800 Subject: [PATCH 013/126] regress: fix Sparc mode for sparc_reg.py --- tests/regress/sparc_reg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regress/sparc_reg.py b/tests/regress/sparc_reg.py index 03832de9..4508efab 100755 --- a/tests/regress/sparc_reg.py +++ b/tests/regress/sparc_reg.py @@ -5,7 +5,7 @@ from unicorn.sparc_const import * PAGE_SIZE = 1 * 1024 * 1024 -uc = Uc(UC_ARCH_SPARC, UC_MODE_32) +uc = Uc(UC_ARCH_SPARC, 0) uc.reg_write(UC_SPARC_REG_SP, 100) uc.reg_write(UC_SPARC_REG_FP, 200) From ca79d11211dc5fe86226ad377630c06887d17df1 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 23 Jan 2016 10:31:16 +0800 Subject: [PATCH 014/126] bindings: update constants after recent changes in unicorn.h --- bindings/const_generator.py | 3 ++- bindings/dotnet/UnicornManaged/Const/Common.fs | 14 ++++++++------ bindings/go/unicorn/unicorn_const.go | 14 ++++++++------ bindings/java/unicorn/UnicornConst.java | 14 ++++++++------ bindings/python/unicorn/unicorn_const.py | 14 ++++++++------ 5 files changed, 34 insertions(+), 25 deletions(-) diff --git a/bindings/const_generator.py b/bindings/const_generator.py index 7adafe33..826340b2 100644 --- a/bindings/const_generator.py +++ b/bindings/const_generator.py @@ -116,7 +116,8 @@ def gen(lang): if f[0].startswith("UC_" + prefix.upper()): if len(f) > 1 and f[1] not in ('//', '='): - print("Error: Unable to convert %s" % f) + print("WARNING: Unable to convert %s" % f) + print(" Line =", line) continue elif len(f) > 1 and f[1] == '=': rhs = ''.join(f[2:]) diff --git a/bindings/dotnet/UnicornManaged/Const/Common.fs b/bindings/dotnet/UnicornManaged/Const/Common.fs index 936b6d90..f5c2230c 100644 --- a/bindings/dotnet/UnicornManaged/Const/Common.fs +++ b/bindings/dotnet/UnicornManaged/Const/Common.fs @@ -21,22 +21,24 @@ module Common = let UC_ARCH_MAX = 8 let UC_MODE_LITTLE_ENDIAN = 0 + let UC_MODE_BIG_ENDIAN = 1073741824 let UC_MODE_ARM = 0 - let UC_MODE_16 = 2 - let UC_MODE_32 = 4 - let UC_MODE_64 = 8 let UC_MODE_THUMB = 16 let UC_MODE_MCLASS = 32 let UC_MODE_V8 = 64 let UC_MODE_MICRO = 16 let UC_MODE_MIPS3 = 32 let UC_MODE_MIPS32R6 = 64 - let UC_MODE_V9 = 16 - let UC_MODE_QPX = 16 - let UC_MODE_BIG_ENDIAN = 1073741824 let UC_MODE_MIPS32 = 4 let UC_MODE_MIPS64 = 8 + let UC_MODE_16 = 2 + let UC_MODE_32 = 4 + let UC_MODE_64 = 8 + let UC_MODE_PPC64 = 8 + let UC_MODE_QPX = 16 + let UC_MODE_SPARC64 = 8 + let UC_MODE_V9 = 16 let UC_ERR_OK = 0 let UC_ERR_NOMEM = 1 diff --git a/bindings/go/unicorn/unicorn_const.go b/bindings/go/unicorn/unicorn_const.go index 38ba0c8b..fb44acd0 100644 --- a/bindings/go/unicorn/unicorn_const.go +++ b/bindings/go/unicorn/unicorn_const.go @@ -16,22 +16,24 @@ const ( ARCH_MAX = 8 MODE_LITTLE_ENDIAN = 0 + MODE_BIG_ENDIAN = 1073741824 MODE_ARM = 0 - MODE_16 = 2 - MODE_32 = 4 - MODE_64 = 8 MODE_THUMB = 16 MODE_MCLASS = 32 MODE_V8 = 64 MODE_MICRO = 16 MODE_MIPS3 = 32 MODE_MIPS32R6 = 64 - MODE_V9 = 16 - MODE_QPX = 16 - MODE_BIG_ENDIAN = 1073741824 MODE_MIPS32 = 4 MODE_MIPS64 = 8 + MODE_16 = 2 + MODE_32 = 4 + MODE_64 = 8 + MODE_PPC64 = 8 + MODE_QPX = 16 + MODE_SPARC64 = 8 + MODE_V9 = 16 ERR_OK = 0 ERR_NOMEM = 1 diff --git a/bindings/java/unicorn/UnicornConst.java b/bindings/java/unicorn/UnicornConst.java index 2bd8eabe..614326b3 100644 --- a/bindings/java/unicorn/UnicornConst.java +++ b/bindings/java/unicorn/UnicornConst.java @@ -18,22 +18,24 @@ public interface UnicornConst { public static final int UC_ARCH_MAX = 8; public static final int UC_MODE_LITTLE_ENDIAN = 0; + public static final int UC_MODE_BIG_ENDIAN = 1073741824; public static final int UC_MODE_ARM = 0; - public static final int UC_MODE_16 = 2; - public static final int UC_MODE_32 = 4; - public static final int UC_MODE_64 = 8; public static final int UC_MODE_THUMB = 16; public static final int UC_MODE_MCLASS = 32; public static final int UC_MODE_V8 = 64; public static final int UC_MODE_MICRO = 16; public static final int UC_MODE_MIPS3 = 32; public static final int UC_MODE_MIPS32R6 = 64; - public static final int UC_MODE_V9 = 16; - public static final int UC_MODE_QPX = 16; - public static final int UC_MODE_BIG_ENDIAN = 1073741824; public static final int UC_MODE_MIPS32 = 4; public static final int UC_MODE_MIPS64 = 8; + public static final int UC_MODE_16 = 2; + public static final int UC_MODE_32 = 4; + public static final int UC_MODE_64 = 8; + public static final int UC_MODE_PPC64 = 8; + public static final int UC_MODE_QPX = 16; + public static final int UC_MODE_SPARC64 = 8; + public static final int UC_MODE_V9 = 16; public static final int UC_ERR_OK = 0; public static final int UC_ERR_NOMEM = 1; diff --git a/bindings/python/unicorn/unicorn_const.py b/bindings/python/unicorn/unicorn_const.py index 01cde40c..c99cb816 100644 --- a/bindings/python/unicorn/unicorn_const.py +++ b/bindings/python/unicorn/unicorn_const.py @@ -14,22 +14,24 @@ UC_ARCH_M68K = 7 UC_ARCH_MAX = 8 UC_MODE_LITTLE_ENDIAN = 0 +UC_MODE_BIG_ENDIAN = 1073741824 UC_MODE_ARM = 0 -UC_MODE_16 = 2 -UC_MODE_32 = 4 -UC_MODE_64 = 8 UC_MODE_THUMB = 16 UC_MODE_MCLASS = 32 UC_MODE_V8 = 64 UC_MODE_MICRO = 16 UC_MODE_MIPS3 = 32 UC_MODE_MIPS32R6 = 64 -UC_MODE_V9 = 16 -UC_MODE_QPX = 16 -UC_MODE_BIG_ENDIAN = 1073741824 UC_MODE_MIPS32 = 4 UC_MODE_MIPS64 = 8 +UC_MODE_16 = 2 +UC_MODE_32 = 4 +UC_MODE_64 = 8 +UC_MODE_PPC64 = 8 +UC_MODE_QPX = 16 +UC_MODE_SPARC64 = 8 +UC_MODE_V9 = 16 UC_ERR_OK = 0 UC_ERR_NOMEM = 1 From 93052f6566f6ab849712ee80d6e2e04ce7cb8e0e Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Sat, 16 Jan 2016 00:44:02 -0800 Subject: [PATCH 015/126] refactor to allow multiple hooks for one type --- Makefile | 4 +- hook.c | 279 --------------------------- include/hook.h | 20 -- include/list.h | 20 ++ include/uc_priv.h | 87 ++++++--- list.c | 66 +++++++ qemu/Makefile.objs | 2 +- qemu/cpu-exec.c | 10 +- qemu/ioport.c | 62 +++--- qemu/softmmu_template.h | 194 ++++++++++++------- qemu/target-arm/translate-a64.c | 19 +- qemu/target-arm/translate.c | 35 ++-- qemu/target-i386/seg_helper.c | 28 +-- qemu/target-i386/translate.c | 38 ++-- qemu/target-m68k/translate.c | 20 +- qemu/target-mips/translate.c | 50 ++--- qemu/target-sparc/translate.c | 26 +-- qemu/tcg/i386/tcg-target.c | 2 +- qemu/translate-all.c | 2 +- uc.c | 329 ++++++++++---------------------- 20 files changed, 542 insertions(+), 751 deletions(-) delete mode 100644 hook.c delete mode 100644 include/hook.h create mode 100644 include/list.h create mode 100644 list.c diff --git a/Makefile b/Makefile index 4d7e4e73..103dd531 100644 --- a/Makefile +++ b/Makefile @@ -228,7 +228,7 @@ compile_lib: config qemu/config-host.h-timestamp unicorn: $(LIBRARY) $(ARCHIVE) -$(LIBRARY): $(UC_TARGET_OBJ) uc.o hook.o +$(LIBRARY): $(UC_TARGET_OBJ) uc.o list.o ifeq ($(UNICORN_SHARED),yes) ifeq ($(V),0) $(call log,GEN,$(LIBRARY)) @@ -241,7 +241,7 @@ ifneq (,$(LIBRARY_SYMLINK)) endif endif -$(ARCHIVE): $(UC_TARGET_OBJ) uc.o hook.o +$(ARCHIVE): $(UC_TARGET_OBJ) uc.o list.o ifeq ($(UNICORN_STATIC),yes) ifeq ($(V),0) $(call log,GEN,$(ARCHIVE)) diff --git a/hook.c b/hook.c deleted file mode 100644 index 6e575d83..00000000 --- a/hook.c +++ /dev/null @@ -1,279 +0,0 @@ -/* Unicorn Emulator Engine */ -/* By Nguyen Anh Quynh , 2015 */ - -#include "uc_priv.h" -#include "hook.h" - - -// return index for a new hook entry in hook_callbacks[] array. -// this realloc memory if needed. -size_t hook_find_new(struct uc_struct *uc) -{ - size_t i; - struct hook_struct *new; - - // find the first free slot. skip slot 0, so index > 0 - for(i = 1; i < uc->hook_size; i++) { - if (uc->hook_callbacks[i].callback == NULL) { - return i; - } - } - - // not found, so the array is full. - // we have to realloc hook_callbacks[] to contain new hooks - new = realloc(uc->hook_callbacks, - (uc->hook_size + HOOK_SIZE) * sizeof(uc->hook_callbacks[0])); - if (!new) // OOM ? - return 0; - - // reset the newly added slots - memset(new + uc->hook_size, 0, HOOK_SIZE * sizeof(uc->hook_callbacks[0])); - - uc->hook_callbacks = new; - uc->hook_size += HOOK_SIZE; - - // return the first newly allocated slot - return uc->hook_size - HOOK_SIZE; -} - -// return -1 on failure, index to hook_callbacks[] on success. -size_t hook_add(struct uc_struct *uc, int type, uint64_t begin, uint64_t end, void *callback, void *user_data) -{ - int i; - - // find the first free slot. skip slot 0, so index > 0 - i = hook_find_new(uc); - if (i) { - uc->hook_callbacks[i].hook_type = type; - uc->hook_callbacks[i].begin = begin; - uc->hook_callbacks[i].end = end; - uc->hook_callbacks[i].callback = callback; - uc->hook_callbacks[i].user_data = user_data; - - switch(type) { - default: break; - case UC_HOOK_BLOCK: - uc->hook_block = true; - if (begin > end) - uc->hook_block_idx = i; - break; - case UC_HOOK_CODE: - uc->hook_insn = true; - if (begin > end) - uc->hook_insn_idx = i; - break; - case UC_HOOK_MEM_READ: - uc->hook_mem_read = true; - if (begin > end) - uc->hook_read_idx = i; - break; - case UC_HOOK_MEM_WRITE: - uc->hook_mem_write = true; - if (begin > end) - uc->hook_write_idx = i; - break; - case UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE: - uc->hook_mem_read = true; - uc->hook_mem_write = true; - if (begin > end) { - uc->hook_read_idx = i; - uc->hook_write_idx = i; - } - break; - } - - return i; - } - - // not found - return 0; -} - -// return 0 on success, -1 on failure -uc_err hook_del(struct uc_struct *uc, uc_hook hh) -{ - if (hh == uc->hook_block_idx) { - uc->hook_block_idx = 0; - } - - if (hh == uc->hook_insn_idx) { - uc->hook_insn_idx = 0; - } - - if (hh == uc->hook_read_idx) { - uc->hook_read_idx = 0; - } - - if (hh == uc->hook_write_idx) { - uc->hook_write_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) { - uc->hook_intr_idx = 0; - } - - if (hh == uc->hook_out_idx) { - uc->hook_out_idx = 0; - } - - if (hh == uc->hook_in_idx) { - uc->hook_in_idx = 0; - } - - if(hh == uc->hook_syscall_idx) { - uc->hook_syscall_idx = 0; - } - - uc->hook_callbacks[hh].callback = NULL; - uc->hook_callbacks[hh].user_data = NULL; - uc->hook_callbacks[hh].hook_type = 0; - uc->hook_callbacks[hh].begin = 0; - uc->hook_callbacks[hh].end = 0; - - return UC_ERR_OK; -} - -// return NULL on failure -static struct hook_struct *_hook_find(struct uc_struct *uc, int type, uint64_t address) -{ - int i; - - switch(type) { - default: break; - case UC_HOOK_BLOCK: - // already hooked all blocks? - if (uc->hook_block_idx) - return &uc->hook_callbacks[uc->hook_block_idx]; - break; - case UC_HOOK_CODE: - // already hooked all the code? - if (uc->hook_insn_idx) - return &uc->hook_callbacks[uc->hook_insn_idx]; - break; - case UC_HOOK_MEM_READ: - // already hooked all memory read? - if (uc->hook_read_idx) { - return &uc->hook_callbacks[uc->hook_read_idx]; - } - break; - case UC_HOOK_MEM_WRITE: - // already hooked all memory write? - if (uc->hook_write_idx) - return &uc->hook_callbacks[uc->hook_write_idx]; - break; - } - - // no trace-all callback - for(i = 1; i < uc->hook_size; i++) { - switch(type) { - default: break; - case UC_HOOK_BLOCK: - case UC_HOOK_CODE: - if (uc->hook_callbacks[i].hook_type == type) { - if (uc->hook_callbacks[i].begin <= address && address <= uc->hook_callbacks[i].end) - return &uc->hook_callbacks[i]; - } - break; - case UC_HOOK_MEM_READ: - 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) { - if (uc->hook_callbacks[i].begin <= address && address <= uc->hook_callbacks[i].end) - return &uc->hook_callbacks[i]; - } - break; - } - } - - // not found - return NULL; -} - - -static void hook_count_cb(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) -{ - // count this instruction - uc->emu_counter++; - - if (uc->emu_counter > uc->emu_count) - uc_emu_stop(uc); - else if (uc->hook_count_callback) - uc->hook_count_callback(uc, address, size, user_data); -} - -struct hook_struct *hook_find(struct uc_struct *uc, int type, uint64_t address) -{ - // stop executing callbacks if we already got stop request - if (uc->stop_request) - return NULL; - - // UC_HOOK_CODE is special because we may need to count instructions - if (type == UC_HOOK_CODE && uc->emu_count > 0) { - struct hook_struct *st = _hook_find(uc, type, address); - if (st) { - // prepare this struct to pass back to caller - uc->hook_count.hook_type = UC_HOOK_CODE; - uc->hook_count.begin = st->begin; - uc->hook_count.end = st->end; - uc->hook_count.callback = hook_count_cb; - uc->hook_count.user_data = st->user_data; - // save this hook callback so we can call it later - uc->hook_count_callback = st->callback; - } else { - // there is no callback, but we still need to - // handle instruction count - uc->hook_count.hook_type = UC_HOOK_CODE; - uc->hook_count.begin = 1; - uc->hook_count.end = 0; - uc->hook_count.callback = hook_count_cb; - uc->hook_count.user_data = NULL; - uc->hook_count_callback = NULL; // no callback - } - - return &(uc->hook_count); - } else - return _hook_find(uc, type, address); -} - - -// TCG helper -void helper_uc_tracecode(int32_t size, void *callback, void *handle, int64_t address, void *user_data); -void helper_uc_tracecode(int32_t size, void *callback, void *handle, int64_t address, void *user_data) -{ - struct uc_struct *uc = handle; - - // sync PC in CPUArchState with address - if (uc->set_pc) { - uc->set_pc(uc, address); - } - - ((uc_cb_hookcode_t)callback)(uc, address, size, user_data); -} diff --git a/include/hook.h b/include/hook.h deleted file mode 100644 index 6fbdf509..00000000 --- a/include/hook.h +++ /dev/null @@ -1,20 +0,0 @@ -/* Unicorn Emulator Engine */ -/* By Nguyen Anh Quynh , 2015 */ - -#ifndef UC_HOOK_H -#define UC_HOOK_H - -// return -1 on failure, index to traces[] on success. -size_t hook_add(struct uc_struct *uc, int type, uint64_t begin, uint64_t end, void *callback, void *user_data); - -// return 0 on success, -1 on failure -uc_err hook_del(struct uc_struct *uc, uc_hook hh); - -// return NULL on failure -struct hook_struct *hook_find(struct uc_struct *uc, int type, uint64_t address); - -// return index of an free hook entry in hook_callbacks[] array. -// this realloc memory if needed. -size_t hook_find_new(struct uc_struct *uc); - -#endif diff --git a/include/list.h b/include/list.h new file mode 100644 index 00000000..75ec13e2 --- /dev/null +++ b/include/list.h @@ -0,0 +1,20 @@ +#ifndef UC_LLIST_H +#define UC_LLIST_H + +#include + +struct list_item { + struct list_item *next; + void *data; +}; + +struct list { + struct list_item *head, *tail; +}; + +struct list *list_new(void); +void list_clear(struct list *list); +void *list_append(struct list *list, void *data); +bool list_remove(struct list *list, void *data); + +#endif diff --git a/include/uc_priv.h b/include/uc_priv.h index 5cdf6557..a55c847e 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -9,7 +9,7 @@ #include "qemu.h" #include "unicorn/unicorn.h" -#include "hook.h" +#include "list.h" #define ARR_SIZE(a) (sizeof(a)/sizeof(a[0])) @@ -60,16 +60,62 @@ typedef bool (*uc_args_int_t)(int intno); // some architecture redirect virtual memory to physical memory like Mips typedef uint64_t (*uc_mem_redirect_t)(uint64_t address); - -struct hook_struct { - int hook_type; // uc_tracecode_type & uc_tracemem_type - uint64_t begin, end; // range of address to be monitored - void *callback; // either uc_cb_tracecode_t or uc_cb_tracemem_t +struct hook { + int type; // UC_HOOK_* + int insn; // instruction for HOOK_INSN + int refs; // reference count to free hook stored in multiple lists + uint64_t begin, end; // only trigger if PC or memory access is in this address (depends on hook type) + void *callback; // a uc_cb_* type void *user_data; }; -// extend memory to keep 32 more hooks each time -#define HOOK_SIZE 32 +// hook list offsets +// mirrors the order of uc_hook_type from include/unicorn/unicorn.h +enum uc_hook_idx { + UC_HOOK_INTR_IDX, + UC_HOOK_INSN_IDX, + UC_HOOK_CODE_IDX, + UC_HOOK_BLOCK_IDX, + UC_HOOK_MEM_READ_UNMAPPED_IDX, + UC_HOOK_MEM_WRITE_UNMAPPED_IDX, + UC_HOOK_MEM_FETCH_UNMAPPED_IDX, + UC_HOOK_MEM_READ_PROT_IDX, + UC_HOOK_MEM_WRITE_PROT_IDX, + UC_HOOK_MEM_FETCH_PROT_IDX, + UC_HOOK_MEM_READ_IDX, + UC_HOOK_MEM_WRITE_IDX, + UC_HOOK_MEM_FETCH_IDX, + + UC_HOOK_MAX, +}; + +// for loop macro to loop over hook lists +#define HOOK_FOREACH(uc, hh, idx) \ + struct list_item *cur; \ + for ( \ + cur = (uc)->hook[idx##_IDX].head; \ + cur != NULL && ((hh) = (struct hook *)cur->data) \ + /* stop excuting callbacks on stop request */ \ + && !uc->stop_request; \ + cur = cur->next) + +// if statement to check hook bounds +#define HOOK_BOUND_CHECK(hh, addr) \ + ((((addr) >= (hh)->begin && (addr) < (hh)->end) \ + || (hh)->begin > (hh)->end)) + +#define HOOK_EXISTS(uc, idx) ((uc)->hook[idx##_IDX].head != NULL) +#define HOOK_EXISTS_BOUNDED(uc, idx, addr) _hook_exists_bounded((uc)->hook[idx##_IDX].head, addr) + +static inline bool _hook_exists_bounded(struct list_item *cur, uint64_t addr) +{ + while (cur != NULL) { + if (HOOK_BOUND_CHECK((struct hook *)cur->data, addr)) + return true; + cur = cur->next; + } + return false; +} //relloc increment, KEEP THIS A POWER OF 2! #define MEM_BLOCK_INCR 32 @@ -144,35 +190,16 @@ struct uc_struct { bool apic_report_tpr_access; CPUState *current_cpu; - // all the hook callbacks - size_t hook_size; - struct hook_struct *hook_callbacks; + // linked lists containing hooks per type + struct list hook[UC_HOOK_MAX]; // hook to count number of instructions for uc_emu_start() - struct hook_struct hook_count; - uc_cb_hookcode_t hook_count_callback; + uc_hook count_hook; size_t emu_counter; // current counter of uc_emu_start() size_t emu_count; // save counter of uc_emu_start() - // indexes if hooking ALL block/code/read/write events - unsigned int hook_block_idx, hook_insn_idx, hook_read_idx, hook_write_idx; - // boolean variables for quick check on hooking block, code, memory accesses - 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_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) - int hook_syscall_idx; // for handling SYSCALL/SYSENTER (X86) - bool init_tcg; // already initialized local TCGv variables? bool stop_request; // request to immediately stop emulation - for uc_emu_stop() diff --git a/list.c b/list.c new file mode 100644 index 00000000..695f5a24 --- /dev/null +++ b/list.c @@ -0,0 +1,66 @@ +#include +#include +#include "list.h" + +// simple linked list implementation + +struct list *list_new(void) +{ + return calloc(1, sizeof(struct list)); +} + +// removed linked list nodes but does not free their content +void list_clear(struct list *list) +{ + struct list_item *next, *cur = list->head; + while (cur != NULL) { + next = cur->next; + free(cur); + cur = next; + } +} + +// returns generated linked list node, or NULL on failure +void *list_append(struct list *list, void *data) +{ + struct list_item *item = malloc(sizeof(struct list_item)); + if (item == NULL) { + return NULL; + } + item->next = NULL; + item->data = data; + if (list->head == NULL) { + list->head = item; + } else { + list->tail->next = item; + } + list->tail = item; + return item; +} + +// returns true if entry was removed, false otherwise +bool list_remove(struct list *list, void *data) +{ + struct list_item *next, *cur, *prev = NULL; + // is list empty? + if (list->head == NULL) { + return false; + } + cur = list->head; + while (cur != NULL) { + next = cur->next; + if (cur->data == data) { + if (cur == list->head) { + list->head = next; + } + if (cur == list->tail) { + list->tail = prev; + } + free(cur); + return true; + } + prev = cur; + cur = next; + } + return false; +} diff --git a/qemu/Makefile.objs b/qemu/Makefile.objs index 4e7cc899..d309d2a4 100644 --- a/qemu/Makefile.objs +++ b/qemu/Makefile.objs @@ -6,7 +6,7 @@ util-obj-y = util/ qobject/ qapi/ qapi-types.o qapi-visit.o # block-obj-y is code used by both qemu system emulation and qemu-img block-obj-y = -block-obj-y += ../uc.o ../hook.o +block-obj-y += ../uc.o ../list.o #block-obj-$(CONFIG_POSIX) += aio-posix.o #block-obj-$(CONFIG_WIN32) += aio-win32.o diff --git a/qemu/cpu-exec.c b/qemu/cpu-exec.c index 5a1f3798..33246009 100644 --- a/qemu/cpu-exec.c +++ b/qemu/cpu-exec.c @@ -64,6 +64,7 @@ int cpu_exec(struct uc_struct *uc, CPUArchState *env) // qq TranslationBlock *tb; uint8_t *tc_ptr; uintptr_t next_tb; + struct hook *hook; /* This must be volatile so it is not trashed by longjmp() */ volatile bool have_tb_lock = false; @@ -127,11 +128,10 @@ int cpu_exec(struct uc_struct *uc, CPUArchState *env) // qq ret = cpu->exception_index; break; #else - // Unicorn: call interrupt callback if registered - if (uc->hook_intr_idx) - ((uc_cb_hookintr_t)uc->hook_callbacks[uc->hook_intr_idx].callback)( - uc, cpu->exception_index, - uc->hook_callbacks[uc->hook_intr_idx].user_data); + // Unicorn: call registered interrupt callbacks + HOOK_FOREACH(uc, hook, UC_HOOK_INTR) { + ((uc_cb_hookintr_t)hook->callback)(uc, cpu->exception_index, hook->user_data); + } cpu->exception_index = -1; #if defined(TARGET_X86_64) // point EIP to the next instruction after INT diff --git a/qemu/ioport.c b/qemu/ioport.c index 338a296a..c7ac6b85 100644 --- a/qemu/ioport.c +++ b/qemu/ioport.c @@ -66,39 +66,45 @@ const MemoryRegionOps unassigned_io_ops = { void cpu_outb(struct uc_struct *uc, pio_addr_t addr, uint8_t val) { //LOG_IOPORT("outb: %04"FMT_pioaddr" %02"PRIx8"\n", addr, val); - // Unicorn: call interrupt callback if registered - if (uc->hook_out_idx) - ((uc_cb_insn_out_t)uc->hook_callbacks[uc->hook_out_idx].callback)( - uc, addr, 1, val, - uc->hook_callbacks[uc->hook_out_idx].user_data); + // Unicorn: call registered OUT callbacks + struct hook *hook; + HOOK_FOREACH(uc, hook, UC_HOOK_INSN) { + if (hook->insn == UC_X86_INS_OUT) + ((uc_cb_insn_out_t)hook->callback)(uc, addr, 1, val, hook->user_data); + } } void cpu_outw(struct uc_struct *uc, pio_addr_t addr, uint16_t val) { //LOG_IOPORT("outw: %04"FMT_pioaddr" %04"PRIx16"\n", addr, val); - // Unicorn: call interrupt callback if registered - if (uc->hook_out_idx) - ((uc_cb_insn_out_t)uc->hook_callbacks[uc->hook_out_idx].callback)( - uc, addr, 2, val, - uc->hook_callbacks[uc->hook_out_idx].user_data); + // Unicorn: call registered OUT callbacks + struct hook *hook; + HOOK_FOREACH(uc, hook, UC_HOOK_INSN) { + if (hook->insn == UC_X86_INS_OUT) + ((uc_cb_insn_out_t)hook->callback)(uc, addr, 2, val, hook->user_data); + } } void cpu_outl(struct uc_struct *uc, pio_addr_t addr, uint32_t val) { //LOG_IOPORT("outl: %04"FMT_pioaddr" %08"PRIx32"\n", addr, val); - if (uc->hook_out_idx) - ((uc_cb_insn_out_t)uc->hook_callbacks[uc->hook_out_idx].callback)( - uc, addr, 4, val, - uc->hook_callbacks[uc->hook_out_idx].user_data); + // Unicorn: call registered OUT callbacks + struct hook *hook; + HOOK_FOREACH(uc, hook, UC_HOOK_INSN) { + if (hook->insn == UC_X86_INS_OUT) + ((uc_cb_insn_out_t)hook->callback)(uc, addr, 4, val, hook->user_data); + } } uint8_t cpu_inb(struct uc_struct *uc, pio_addr_t addr) { //LOG_IOPORT("inb : %04"FMT_pioaddr" %02"PRIx8"\n", addr, val); - if (uc->hook_in_idx) - return ((uc_cb_insn_in_t)uc->hook_callbacks[uc->hook_in_idx].callback)( - uc, addr, 1, - uc->hook_callbacks[uc->hook_in_idx].user_data); + // Unicorn: call registered IN callbacks + struct hook *hook; + HOOK_FOREACH(uc, hook, UC_HOOK_INSN) { + if (hook->insn == UC_X86_INS_IN) + return ((uc_cb_insn_in_t)hook->callback)(uc, addr, 1, hook->user_data); + } return 0; } @@ -106,10 +112,12 @@ uint8_t cpu_inb(struct uc_struct *uc, pio_addr_t addr) uint16_t cpu_inw(struct uc_struct *uc, pio_addr_t addr) { //LOG_IOPORT("inw : %04"FMT_pioaddr" %04"PRIx16"\n", addr, val); - if (uc->hook_in_idx) - return ((uc_cb_insn_in_t)uc->hook_callbacks[uc->hook_in_idx].callback)( - uc, addr, 2, - uc->hook_callbacks[uc->hook_in_idx].user_data); + // Unicorn: call registered IN callbacks + struct hook *hook; + HOOK_FOREACH(uc, hook, UC_HOOK_INSN) { + if (hook->insn == UC_X86_INS_IN) + return ((uc_cb_insn_in_t)hook->callback)(uc, addr, 2, hook->user_data); + } return 0; } @@ -117,10 +125,12 @@ uint16_t cpu_inw(struct uc_struct *uc, pio_addr_t addr) uint32_t cpu_inl(struct uc_struct *uc, pio_addr_t addr) { //LOG_IOPORT("inl : %04"FMT_pioaddr" %08"PRIx32"\n", addr, val); - if (uc->hook_in_idx) - return ((uc_cb_insn_in_t)uc->hook_callbacks[uc->hook_in_idx].callback)( - uc, addr, 4, - uc->hook_callbacks[uc->hook_in_idx].user_data); + // Unicorn: call registered IN callbacks + struct hook *hook; + HOOK_FOREACH(uc, hook, UC_HOOK_INSN) { + if (hook->insn == UC_X86_INS_IN) + return ((uc_cb_insn_in_t)hook->callback)(uc, addr, 4, hook->user_data); + } return 0; } diff --git a/qemu/softmmu_template.h b/qemu/softmmu_template.h index e3100fcd..1f636055 100644 --- a/qemu/softmmu_template.h +++ b/qemu/softmmu_template.h @@ -178,23 +178,33 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, uintptr_t haddr; DATA_TYPE res; int error_code; + struct hook *hook; + bool handled; struct uc_struct *uc = env->uc; MemoryRegion *mr = memory_mapping(uc, addr); // memory might be still unmapped while reading or fetching if (mr == NULL) { + handled = false; #if defined(SOFTMMU_CODE_ACCESS) error_code = UC_ERR_FETCH_UNMAPPED; - if (uc->hook_mem_fetch_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_fetch_idx].callback)( - uc, UC_MEM_FETCH_UNMAPPED, addr, DATA_SIZE, 0, - uc->hook_callbacks[uc->hook_mem_fetch_idx].user_data)) { + HOOK_FOREACH(uc, hook, UC_HOOK_MEM_FETCH_UNMAPPED) { + if (! HOOK_BOUND_CHECK(hook, addr)) + continue; + if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_UNMAPPED, addr, DATA_SIZE, 0, hook->user_data))) + break; + } #else error_code = UC_ERR_READ_UNMAPPED; - if (uc->hook_mem_read_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_read_idx].callback)( - uc, UC_MEM_READ_UNMAPPED, addr, DATA_SIZE, 0, - uc->hook_callbacks[uc->hook_mem_read_idx].user_data)) { + HOOK_FOREACH(uc, hook, UC_HOOK_MEM_READ_UNMAPPED) { + if (! HOOK_BOUND_CHECK(hook, addr)) + continue; + if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_UNMAPPED, addr, DATA_SIZE, 0, hook->user_data))) + break; + } #endif + if (handled) { env->invalid_error = UC_ERR_OK; mr = memory_mapping(uc, addr); // FIXME: what if mr is still NULL at this time? } else { @@ -209,9 +219,15 @@ 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_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)) { + handled = false; + HOOK_FOREACH(uc, hook, UC_HOOK_MEM_FETCH_PROT) { + if (! HOOK_BOUND_CHECK(hook, addr)) + continue; + if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_PROT, addr, DATA_SIZE, 0, hook->user_data))) + break; + } + + if (handled) { env->invalid_error = UC_ERR_OK; } else { env->invalid_addr = addr; @@ -224,19 +240,25 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, #endif // Unicorn: callback on memory read - if (READ_ACCESS_TYPE == MMU_DATA_LOAD && env->uc->hook_mem_read) { - struct hook_struct *trace = hook_find(env->uc, UC_HOOK_MEM_READ, addr); - if (trace) { - ((uc_cb_hookmem_t)trace->callback)(env->uc, UC_MEM_READ, - (uint64_t)addr, (int)DATA_SIZE, (int64_t)0, trace->user_data); + if (READ_ACCESS_TYPE == MMU_DATA_LOAD) { + HOOK_FOREACH(uc, hook, UC_HOOK_MEM_READ) { + if (! HOOK_BOUND_CHECK(hook, addr)) + continue; + ((uc_cb_hookmem_t)hook->callback)(env->uc, UC_MEM_READ, addr, DATA_SIZE, 0, hook->user_data); } } // 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_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_read_prot_idx].user_data)) { + handled = false; + HOOK_FOREACH(uc, hook, UC_HOOK_MEM_READ_PROT) { + if (! HOOK_BOUND_CHECK(hook, addr)) + continue; + if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0, hook->user_data))) + break; + } + + if (handled) { env->invalid_error = UC_ERR_OK; } else { env->invalid_addr = addr; @@ -368,23 +390,33 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, uintptr_t haddr; DATA_TYPE res; int error_code; + struct hook *hook; + bool handled; struct uc_struct *uc = env->uc; MemoryRegion *mr = memory_mapping(uc, addr); // memory can be unmapped while reading or fetching if (mr == NULL) { + handled = false; #if defined(SOFTMMU_CODE_ACCESS) error_code = UC_ERR_FETCH_UNMAPPED; - if (uc->hook_mem_fetch_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_fetch_idx].callback)( - uc, UC_MEM_FETCH_UNMAPPED, addr, DATA_SIZE, 0, - uc->hook_callbacks[uc->hook_mem_fetch_idx].user_data)) { + HOOK_FOREACH(uc, hook, UC_HOOK_MEM_FETCH_UNMAPPED) { + if (! HOOK_BOUND_CHECK(hook, addr)) + continue; + if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_UNMAPPED, addr, DATA_SIZE, 0, hook->user_data))) + break; + } #else error_code = UC_ERR_READ_UNMAPPED; - if (uc->hook_mem_read_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_read_idx].callback)( - uc, UC_MEM_READ_UNMAPPED, addr, DATA_SIZE, 0, - uc->hook_callbacks[uc->hook_mem_read_idx].user_data)) { + HOOK_FOREACH(uc, hook, UC_HOOK_MEM_READ_UNMAPPED) { + if (! HOOK_BOUND_CHECK(hook, addr)) + continue; + if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_UNMAPPED, addr, DATA_SIZE, 0, hook->user_data))) + break; + } #endif + if (handled) { env->invalid_error = UC_ERR_OK; mr = memory_mapping(uc, addr); // FIXME: what if mr is still NULL at this time? } else { @@ -399,9 +431,15 @@ 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_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)) { + handled = false; + HOOK_FOREACH(uc, hook, UC_HOOK_MEM_FETCH_PROT) { + if (! HOOK_BOUND_CHECK(hook, addr)) + continue; + if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_PROT, addr, DATA_SIZE, 0, hook->user_data))) + break; + } + + if (handled) { env->invalid_error = UC_ERR_OK; } else { env->invalid_addr = addr; @@ -414,19 +452,25 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, #endif // Unicorn: callback on memory read - if (READ_ACCESS_TYPE == MMU_DATA_LOAD && env->uc->hook_mem_read) { - struct hook_struct *trace = hook_find(env->uc, UC_HOOK_MEM_READ, addr); - if (trace) { - ((uc_cb_hookmem_t)trace->callback)(env->uc, UC_MEM_READ, - (uint64_t)addr, (int)DATA_SIZE, (int64_t)0, trace->user_data); + if (READ_ACCESS_TYPE == MMU_DATA_LOAD) { + HOOK_FOREACH(uc, hook, UC_HOOK_MEM_READ) { + if (! HOOK_BOUND_CHECK(hook, addr)) + continue; + ((uc_cb_hookmem_t)hook->callback)(env->uc, UC_MEM_READ, addr, DATA_SIZE, 0, hook->user_data); } } // 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_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_read_prot_idx].user_data)) { + handled = false; + HOOK_FOREACH(uc, hook, UC_HOOK_MEM_READ_PROT) { + if (! HOOK_BOUND_CHECK(hook, addr)) + continue; + if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0, hook->user_data))) + break; + } + + if (handled) { env->invalid_error = UC_ERR_OK; } else { env->invalid_addr = addr; @@ -595,24 +639,30 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); target_ulong tlb_addr = env->tlb_table[mmu_idx][index].addr_write; uintptr_t haddr; + struct hook *hook; + bool handled; struct uc_struct *uc = env->uc; MemoryRegion *mr = memory_mapping(uc, addr); // Unicorn: callback on memory write - if (uc->hook_mem_write) { - struct hook_struct *trace = hook_find(uc, UC_HOOK_MEM_WRITE, addr); - if (trace) { - ((uc_cb_hookmem_t)trace->callback)(uc, UC_MEM_WRITE, - (uint64_t)addr, (int)DATA_SIZE, (int64_t)val, trace->user_data); - } + HOOK_FOREACH(uc, hook, UC_HOOK_MEM_WRITE) { + if (! HOOK_BOUND_CHECK(hook, addr)) + continue; + ((uc_cb_hookmem_t)hook->callback)(uc, UC_MEM_WRITE, addr, DATA_SIZE, val, hook->user_data); } // Unicorn: callback on invalid memory - 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_UNMAPPED, addr, DATA_SIZE, (int64_t)val, - uc->hook_callbacks[uc->hook_mem_write_idx].user_data)) { + if (mr == NULL) { + handled = false; + HOOK_FOREACH(uc, hook, UC_HOOK_MEM_WRITE_UNMAPPED) { + if (! HOOK_BOUND_CHECK(hook, addr)) + continue; + if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_WRITE_UNMAPPED, addr, DATA_SIZE, val, hook->user_data))) + break; + } + + if (! handled) { // save error & quit env->invalid_addr = addr; env->invalid_error = UC_ERR_WRITE_UNMAPPED; @@ -627,12 +677,17 @@ 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_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_write_prot_idx].user_data)) { - env->invalid_error = UC_ERR_OK; + handled = false; + HOOK_FOREACH(uc, hook, UC_HOOK_MEM_WRITE_PROT) { + if (! HOOK_BOUND_CHECK(hook, addr)) + continue; + if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_WRITE_PROT, addr, DATA_SIZE, val, hook->user_data))) + break; } - else { + + if (handled) { + env->invalid_error = UC_ERR_OK; + } else { env->invalid_addr = addr; env->invalid_error = UC_ERR_WRITE_PROT; // printf("***** Invalid memory write (ro) at " TARGET_FMT_lx "\n", addr); @@ -742,24 +797,30 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); target_ulong tlb_addr = env->tlb_table[mmu_idx][index].addr_write; uintptr_t haddr; + struct hook *hook; + bool handled; struct uc_struct *uc = env->uc; MemoryRegion *mr = memory_mapping(uc, addr); // Unicorn: callback on memory write - if (uc->hook_mem_write) { - struct hook_struct *trace = hook_find(uc, UC_HOOK_MEM_WRITE, addr); - if (trace) { - ((uc_cb_hookmem_t)trace->callback)(uc, UC_MEM_WRITE, - (uint64_t)addr, (int)DATA_SIZE, (int64_t)val, trace->user_data); - } + HOOK_FOREACH(uc, hook, UC_HOOK_MEM_WRITE) { + if (! HOOK_BOUND_CHECK(hook, addr)) + continue; + ((uc_cb_hookmem_t)hook->callback)(uc, UC_MEM_WRITE, addr, DATA_SIZE, val, hook->user_data); } // Unicorn: callback on invalid memory - 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_UNMAPPED, addr, DATA_SIZE, (int64_t)val, - uc->hook_callbacks[uc->hook_mem_write_idx].user_data)) { + if (mr == NULL) { + handled = false; + HOOK_FOREACH(uc, hook, UC_HOOK_MEM_WRITE_UNMAPPED) { + if (! HOOK_BOUND_CHECK(hook, addr)) + continue; + if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_WRITE_UNMAPPED, addr, DATA_SIZE, val, hook->user_data))) + break; + } + + if (!handled) { // save error & quit env->invalid_addr = addr; env->invalid_error = UC_ERR_WRITE_UNMAPPED; @@ -774,12 +835,17 @@ 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_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_write_prot_idx].user_data)) { - env->invalid_error = UC_ERR_OK; + handled = false; + HOOK_FOREACH(uc, hook, UC_HOOK_MEM_WRITE_PROT) { + if (! HOOK_BOUND_CHECK(hook, addr)) + continue; + if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_WRITE_PROT, addr, DATA_SIZE, val, hook->user_data))) + break; } - else { + + if (handled) { + env->invalid_error = UC_ERR_OK; + } else { env->invalid_addr = addr; env->invalid_error = UC_ERR_WRITE_PROT; // printf("***** Invalid memory write (ro) at " TARGET_FMT_lx "\n", addr); diff --git a/qemu/target-arm/translate-a64.c b/qemu/target-arm/translate-a64.c index c76de8e0..28d57681 100644 --- a/qemu/target-arm/translate-a64.c +++ b/qemu/target-arm/translate-a64.c @@ -10970,6 +10970,7 @@ static void disas_data_proc_simd_fp(DisasContext *s, uint32_t insn) static void disas_a64_insn(CPUARMState *env, DisasContext *s) { uint32_t insn; + struct hook *hook; TCGContext *tcg_ctx = env->uc->tcg_ctx; // Unicorn: end address tells us to stop emulation @@ -10984,10 +10985,10 @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s) s->pc += 4; // Unicorn: trace this instruction on request - if (env->uc->hook_insn) { - struct hook_struct *trace = hook_find(s->uc, UC_HOOK_CODE, s->pc - 4); - if (trace) - gen_uc_tracecode(tcg_ctx, 4, trace->callback, env->uc, s->pc - 4, trace->user_data); + HOOK_FOREACH(env->uc, hook, UC_HOOK_CODE) { + if (! HOOK_BOUND_CHECK(hook, s->pc - 4)) + continue; + gen_uc_tracecode(tcg_ctx, 4, hook->callback, env->uc, s->pc - 4, hook->user_data); // the callback might want to stop emulation immediately check_exit_request(tcg_ctx); } @@ -11043,6 +11044,7 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu, int max_insns; TCGContext *tcg_ctx = env->uc->tcg_ctx; bool block_full = false; + struct hook *hook; pc_start = tb->pc; @@ -11114,12 +11116,13 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu, // Unicorn: trace this block on request // Only hook this block if it is not broken from previous translation due to // full translation cache - if (env->uc->hook_block && !env->uc->block_full) { - struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start); - if (trace) { + if (! env->uc->block_full) { + HOOK_FOREACH(env->uc, hook, UC_HOOK_BLOCK) { + if (! HOOK_BOUND_CHECK(hook, pc_start)) + continue; // save block address to see if we need to patch block size later env->uc->block_addr = pc_start; - gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, pc_start, trace->user_data); + gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, hook->callback, env->uc, pc_start, hook->user_data); } } diff --git a/qemu/target-arm/translate.c b/qemu/target-arm/translate.c index 3560e6ed..bf190452 100644 --- a/qemu/target-arm/translate.c +++ b/qemu/target-arm/translate.c @@ -7680,6 +7680,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) // qq TCGv_i32 tmp3; TCGv_i32 addr; TCGv_i64 tmp64; + struct hook *hook; /* M variants do not implement ARM mode. */ if (arm_dc_feature(s, ARM_FEATURE_M)) { @@ -7687,10 +7688,10 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) // qq } // Unicorn: trace this instruction on request - if (s->uc->hook_insn) { - struct hook_struct *trace = hook_find(s->uc, UC_HOOK_CODE, s->pc - 4); - if (trace) - gen_uc_tracecode(tcg_ctx, 4, trace->callback, s->uc, s->pc - 4, trace->user_data); + HOOK_FOREACH(s->uc, hook, UC_HOOK_CODE) { + if (! HOOK_BOUND_CHECK(hook, s->pc - 4)) + continue; + gen_uc_tracecode(tcg_ctx, 4, hook->callback, s->uc, s->pc - 4, hook->user_data); // the callback might want to stop emulation immediately check_exit_request(tcg_ctx); } @@ -10390,6 +10391,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) // qq TCGv_i32 tmp; TCGv_i32 tmp2; TCGv_i32 addr; + struct hook *hook; // Unicorn: end address tells us to stop emulation if (s->pc == s->uc->addr_end) { @@ -10408,15 +10410,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) // qq } // Unicorn: trace this instruction on request - if (env->uc->hook_insn) { - struct hook_struct *trace = hook_find(s->uc, UC_HOOK_CODE, s->pc); - if (trace) - gen_uc_tracecode(tcg_ctx, 2, trace->callback, env->uc, s->pc, trace->user_data); - // if requested to emulate only some instructions, check to see - // if we need to exit immediately - if (env->uc->emu_count > 0) { - check_exit_request(tcg_ctx); - } + HOOK_FOREACH(env->uc, hook, UC_HOOK_CODE) { + if (! HOOK_BOUND_CHECK(hook, s->pc)) + continue; + gen_uc_tracecode(tcg_ctx, 2, hook->callback, env->uc, s->pc, hook->user_data); + // check to see if we need to exit immediately + check_exit_request(tcg_ctx); } insn = arm_lduw_code(env, s->pc, s->bswap_code); @@ -11148,6 +11147,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, int max_insns; TCGContext *tcg_ctx = env->uc->tcg_ctx; bool block_full = false; + struct hook *hook; /* generate intermediate code */ @@ -11237,12 +11237,13 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, // Unicorn: trace this block on request // Only hook this block if it is not broken from previous translation due to // full translation cache - if (env->uc->hook_block && !env->uc->block_full) { - struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start); - if (trace) { + if (!env->uc->block_full) { + HOOK_FOREACH(env->uc, hook, UC_HOOK_BLOCK) { + if (! HOOK_BOUND_CHECK(hook, pc_start)) + continue; // save block address to see if we need to patch block size later env->uc->block_addr = pc_start; - gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, pc_start, trace->user_data); + gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, hook->callback, env->uc, pc_start, hook->user_data); } } diff --git a/qemu/target-i386/seg_helper.c b/qemu/target-i386/seg_helper.c index 42b0f37c..4cf6e41a 100644 --- a/qemu/target-i386/seg_helper.c +++ b/qemu/target-i386/seg_helper.c @@ -945,14 +945,16 @@ void helper_syscall(CPUX86State *env, int next_eip_addend) #else void helper_syscall(CPUX86State *env, int next_eip_addend) { - // Unicorn: call interrupt callback if registered - struct uc_struct *uc = env->uc; - if (uc->hook_syscall_idx) { - ((uc_cb_insn_syscall_t)uc->hook_callbacks[uc->hook_syscall_idx].callback)( - uc, uc->hook_callbacks[uc->hook_syscall_idx].user_data); + // Unicorn: call registered syscall hooks + struct hook *hook; + HOOK_FOREACH(env->uc, hook, UC_HOOK_INSN) { + if (! HOOK_BOUND_CHECK(hook, env->eip)) + continue; + if (hook->insn == UC_X86_INS_SYSCALL) + ((uc_cb_insn_syscall_t)hook->callback)(env->uc, hook->user_data); } - env->eip += next_eip_addend; + env->eip += next_eip_addend; return; int selector; @@ -2303,14 +2305,16 @@ void helper_lret_protected(CPUX86State *env, int shift, int addend) void helper_sysenter(CPUX86State *env, int next_eip_addend) { - // Unicorn: call interrupt callback if registered - struct uc_struct *uc = env->uc; - if (uc->hook_syscall_idx) { - ((uc_cb_insn_syscall_t)uc->hook_callbacks[uc->hook_syscall_idx].callback)( - uc, uc->hook_callbacks[uc->hook_syscall_idx].user_data); + // Unicorn: call registered SYSENTER hooks + struct hook *hook; + HOOK_FOREACH(env->uc, hook, UC_HOOK_INSN) { + if (! HOOK_BOUND_CHECK(hook, env->eip)) + continue; + if (hook->insn == UC_X86_INS_SYSENTER) + ((uc_cb_insn_syscall_t)hook->callback)(env->uc, hook->user_data); } - env->eip += next_eip_addend; + env->eip += next_eip_addend; return; if (env->sysenter_cs == 0) { diff --git a/qemu/target-i386/translate.c b/qemu/target-i386/translate.c index 285ba32c..0d83f4bd 100644 --- a/qemu/target-i386/translate.c +++ b/qemu/target-i386/translate.c @@ -516,14 +516,14 @@ static inline void gen_op_addq_A0_reg_sN(TCGContext *s, int shift, int reg) static inline void gen_op_ld_v(DisasContext *s, int idx, TCGv t0, TCGv a0) { - if (s->uc->hook_mem_read) + if (HOOK_EXISTS(s->uc, UC_HOOK_MEM_READ)) gen_jmp_im(s, s->prev_pc); // Unicorn: sync EIP tcg_gen_qemu_ld_tl(s->uc, t0, a0, s->mem_index, idx | MO_LE); } static inline void gen_op_st_v(DisasContext *s, int idx, TCGv t0, TCGv a0) { - if (s->uc->hook_mem_write) + if (HOOK_EXISTS(s->uc, UC_HOOK_MEM_WRITE)) gen_jmp_im(s, s->prev_pc); // Unicorn: sync EIP tcg_gen_qemu_st_tl(s->uc, t0, a0, s->mem_index, idx | MO_LE); } @@ -4745,12 +4745,11 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, TCGv cpu_tmp4 = *(TCGv *)tcg_ctx->cpu_tmp4; TCGv **cpu_T = (TCGv **)tcg_ctx->cpu_T; TCGv **cpu_regs = (TCGv **)tcg_ctx->cpu_regs; - struct hook_struct *trace = NULL; + struct hook *hook = NULL; TCGArg *save_opparam_ptr = tcg_ctx->gen_opparam_ptr; bool cc_op_dirty = s->cc_op_dirty; bool changed_cc_op = false; - s->pc = pc_start; // end address tells us to stop emulation @@ -4768,16 +4767,17 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, } // Unicorn: trace this instruction on request - if (env->uc->hook_insn) { - trace = hook_find(env->uc, UC_HOOK_CODE, pc_start); - if (trace) { - if (s->last_cc_op != s->cc_op) { - sync_eflags(s, tcg_ctx); - s->last_cc_op = s->cc_op; - changed_cc_op = true; - } + if (HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_CODE, pc_start)) { + if (s->last_cc_op != s->cc_op) { + sync_eflags(s, tcg_ctx); + s->last_cc_op = s->cc_op; + changed_cc_op = true; + } + HOOK_FOREACH(env->uc, hook, UC_HOOK_CODE) { + if (! HOOK_BOUND_CHECK(hook, pc_start)) + continue; // generate code to call callback - gen_uc_tracecode(tcg_ctx, 0xf1f1f1f1, trace->callback, env->uc, pc_start, trace->user_data); + gen_uc_tracecode(tcg_ctx, 0xf1f1f1f1, hook->callback, env->uc, pc_start, hook->user_data); // the callback might want to stop emulation immediately check_exit_request(tcg_ctx); } @@ -8173,7 +8173,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_helper_unlock(tcg_ctx, cpu_env); // Unicorn: patch the callback for the instruction size - if (trace) { + if (hook) { // int i; // for(i = 0; i < 20; i++) // printf("=== [%u] = %x\n", i, *(save_opparam_ptr + i)); @@ -8282,6 +8282,7 @@ static inline void gen_intermediate_code_internal(uint8_t *gen_opc_cc_op, int num_insns = 0; int max_insns; bool block_full = false; + struct hook *hook; /* generate intermediate code */ pc_start = tb->pc; @@ -8387,11 +8388,12 @@ static inline void gen_intermediate_code_internal(uint8_t *gen_opc_cc_op, // Unicorn: trace this block on request // Only hook this block if it is not broken from previous translation due to // full translation cache - if (env->uc->hook_block && !env->uc->block_full) { - struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start); - if (trace) { + if (!env->uc->block_full) { + HOOK_FOREACH(env->uc, hook, UC_HOOK_BLOCK) { + if (! HOOK_BOUND_CHECK(hook, pc_start)) + continue; env->uc->block_addr = pc_start; - gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, pc_start, trace->user_data); + gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, hook->callback, env->uc, pc_start, hook->user_data); } } diff --git a/qemu/target-m68k/translate.c b/qemu/target-m68k/translate.c index 8c2951d9..0f685d8e 100644 --- a/qemu/target-m68k/translate.c +++ b/qemu/target-m68k/translate.c @@ -3031,6 +3031,7 @@ static void disas_m68k_insn(CPUM68KState * env, DisasContext *s) { TCGContext *tcg_ctx = s->uc->tcg_ctx; uint16_t insn; + struct hook *hook; if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) { tcg_gen_debug_insn_start(tcg_ctx, s->pc); @@ -3043,11 +3044,10 @@ static void disas_m68k_insn(CPUM68KState * env, DisasContext *s) } // Unicorn: trace this instruction on request - if (env->uc->hook_insn) { - struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, s->pc); - if (trace) - gen_uc_tracecode(tcg_ctx, 2, trace->callback, env->uc, s->pc, trace->user_data); - + HOOK_FOREACH(env->uc, hook, UC_HOOK_CODE) { + if (! HOOK_BOUND_CHECK(hook, s->pc)) + continue; + gen_uc_tracecode(tcg_ctx, 2, hook->callback, env->uc, s->pc, hook->user_data); // the callback might want to stop emulation immediately check_exit_request(tcg_ctx); } @@ -3075,6 +3075,7 @@ gen_intermediate_code_internal(M68kCPU *cpu, TranslationBlock *tb, int max_insns; TCGContext *tcg_ctx = env->uc->tcg_ctx; bool block_full = false; + struct hook *hook; /* generate intermediate code */ pc_start = tb->pc; @@ -3109,12 +3110,13 @@ gen_intermediate_code_internal(M68kCPU *cpu, TranslationBlock *tb, // Unicorn: trace this block on request // Only hook this block if it is not broken from previous translation due to // full translation cache - if (env->uc->hook_block && !env->uc->block_full) { - struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start); - if (trace) { + if (!env->uc->block_full) { + HOOK_FOREACH(env->uc, hook, UC_HOOK_BLOCK) { + if (! HOOK_BOUND_CHECK(hook, pc_start)) + continue; // save block address to see if we need to patch block size later env->uc->block_addr = pc_start; - gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, pc_start, trace->user_data); + gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, hook->callback, env->uc, pc_start, hook->user_data); } } diff --git a/qemu/target-mips/translate.c b/qemu/target-mips/translate.c index 75465915..fadbaeb0 100644 --- a/qemu/target-mips/translate.c +++ b/qemu/target-mips/translate.c @@ -11331,6 +11331,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, bool *insn_n int op, cnvt_op, op1, offset; int funct; int n_bytes; + struct hook *hook; op = (ctx->opcode >> 11) & 0x1f; sa = (ctx->opcode >> 2) & 0x7; @@ -11343,12 +11344,11 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, bool *insn_n n_bytes = 2; // Unicorn: trace this instruction on request - if (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); - *insn_need_patch = true; - } + HOOK_FOREACH(env->uc, hook, UC_HOOK_CODE) { + if (! HOOK_BOUND_CHECK(hook, ctx->pc)) + continue; + gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, hook->callback, env->uc, ctx->pc, hook->user_data); + *insn_need_patch = true; // the callback might want to stop emulation immediately check_exit_request(tcg_ctx); } @@ -13932,6 +13932,7 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, bool *ins TCGContext *tcg_ctx = env->uc->tcg_ctx; TCGv **cpu_gpr = (TCGv **)tcg_ctx->cpu_gpr; uint32_t op; + struct hook *hook; /* make sure instructions are on a halfword boundary */ if (ctx->pc & 0x1) { @@ -13942,12 +13943,11 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, bool *ins } // Unicorn: trace this instruction on request - if (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); - *insn_need_patch = true; - } + HOOK_FOREACH(env->uc, hook, UC_HOOK_CODE) { + if (! HOOK_BOUND_CHECK(hook, ctx->pc)) + continue; + gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, hook->callback, env->uc, ctx->pc, hook->user_data); + *insn_need_patch = true; // the callback might want to stop emulation immediately check_exit_request(tcg_ctx); } @@ -18504,13 +18504,13 @@ static void gen_msa(CPUMIPSState *env, DisasContext *ctx) // Unicorn: trace this instruction on request static void hook_insn(CPUMIPSState *env, DisasContext *ctx, bool *insn_need_patch, int *insn_patch_offset, int offset_value) { - if (env->uc->hook_insn) { - TCGContext *tcg_ctx = ctx->uc->tcg_ctx; - 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); - *insn_need_patch = true; - } + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + struct hook *hook; + HOOK_FOREACH(env->uc, hook, UC_HOOK_CODE) { + if (! HOOK_BOUND_CHECK(hook, ctx->pc)) + continue; + gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, hook->callback, env->uc, ctx->pc, hook->user_data); + *insn_need_patch = true; // the callback might want to stop emulation immediately check_exit_request(tcg_ctx); *insn_patch_offset = offset_value; @@ -19178,6 +19178,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, TCGContext *tcg_ctx = env->uc->tcg_ctx; TCGArg *save_opparam_ptr = NULL; bool block_full = false; + struct hook *hook; if (search_pc) qemu_log("search pc %d\n", search_pc); @@ -19223,12 +19224,13 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, // Unicorn: trace this block on request // Only hook this block if it is not broken from previous translation due to // full translation cache - if (env->uc->hook_block && !env->uc->block_full) { - struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start); - if (trace) { + if (! env->uc->block_full) { + HOOK_FOREACH(env->uc, hook, UC_HOOK_BLOCK) { + if (! HOOK_BOUND_CHECK(hook, pc_start)) + continue; // save block address to see if we need to patch block size later env->uc->block_addr = pc_start; - gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, pc_start, trace->user_data); + gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, hook->callback, env->uc, pc_start, hook->user_data); } } @@ -19275,7 +19277,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, int insn_patch_offset = 1; // Unicorn: save param buffer - if (env->uc->hook_insn) + if (HOOK_EXISTS(env->uc, UC_HOOK_CODE)) save_opparam_ptr = tcg_ctx->gen_opparam_ptr; is_slot = ctx.hflags & MIPS_HFLAG_BMASK; diff --git a/qemu/target-sparc/translate.c b/qemu/target-sparc/translate.c index fc71e88b..8caba2b7 100644 --- a/qemu/target-sparc/translate.c +++ b/qemu/target-sparc/translate.c @@ -2625,6 +2625,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn, bool hook_ins TCGv_i32 cpu_src1_32, cpu_src2_32, cpu_dst_32; TCGv_i64 cpu_src1_64, cpu_src2_64, cpu_dst_64; target_long simm; + struct hook *hook; if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) { tcg_gen_debug_insn_start(tcg_ctx, dc->pc); @@ -2637,13 +2638,14 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn, bool hook_ins } // Unicorn: trace this instruction on request - if (hook_insn && dc->uc->hook_insn) { - struct hook_struct *trace = hook_find(dc->uc, UC_HOOK_CODE, dc->pc); - if (trace) - gen_uc_tracecode(tcg_ctx, 4, trace->callback, dc->uc, dc->pc, trace->user_data); - - // the callback might want to stop emulation immediately - check_exit_request(tcg_ctx); + if (hook_insn) { + HOOK_FOREACH(dc->uc, hook, UC_HOOK_CODE) { + if (! HOOK_BOUND_CHECK(hook, dc->pc)) + continue; + gen_uc_tracecode(tcg_ctx, 4, hook->callback, dc->uc, dc->pc, hook->user_data); + // the callback might want to stop emulation immediately + check_exit_request(tcg_ctx); + } } opc = GET_FIELD(insn, 0, 1); @@ -5388,6 +5390,7 @@ static inline void gen_intermediate_code_internal(SPARCCPU *cpu, unsigned int insn; TCGContext *tcg_ctx = env->uc->tcg_ctx; bool block_full = false; + struct hook *hook; memset(dc, 0, sizeof(DisasContext)); dc->uc = env->uc; @@ -5428,12 +5431,13 @@ static inline void gen_intermediate_code_internal(SPARCCPU *cpu, // Unicorn: trace this block on request // Only hook this block if it is not broken from previous translation due to // full translation cache - if (env->uc->hook_block && !env->uc->block_full) { - struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start); - if (trace) { + if (!env->uc->block_full) { + HOOK_FOREACH(env->uc, hook, UC_HOOK_BLOCK) { + if (! HOOK_BOUND_CHECK(hook, pc_start)) + continue; // save block address to see if we need to patch block size later env->uc->block_addr = pc_start; - gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, pc_start, trace->user_data); + gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, hook->callback, env->uc, pc_start, hook->user_data); } } diff --git a/qemu/tcg/i386/tcg-target.c b/qemu/tcg/i386/tcg-target.c index aa06cc18..414c4a72 100644 --- a/qemu/tcg/i386/tcg-target.c +++ b/qemu/tcg/i386/tcg-target.c @@ -1209,7 +1209,7 @@ static inline void tcg_out_tlb_load(TCGContext *s, TCGReg addrlo, TCGReg addrhi, tcg_out_mov(s, ttype, r1, addrlo); // Unicorn: fast path if hookmem is not enable - if (!s->uc->hook_mem_read && !s->uc->hook_mem_write) + if (!HOOK_EXISTS(s->uc, UC_HOOK_MEM_READ) && !HOOK_EXISTS(s->uc, UC_HOOK_MEM_WRITE)) tcg_out_opc(s, OPC_JCC_long + JCC_JNE, 0, 0, 0); else tcg_out_opc(s, OPC_JMP_long, 0, 0, 0); /* slow_path */ diff --git a/qemu/translate-all.c b/qemu/translate-all.c index 11bbb07b..72e1b60f 100644 --- a/qemu/translate-all.c +++ b/qemu/translate-all.c @@ -179,7 +179,7 @@ static int cpu_gen_code(CPUArchState *env, TranslationBlock *tb, int *gen_code_s gen_intermediate_code(env, tb); // Unicorn: when tracing block, patch 1st operand for block size - if (env->uc->hook_block && env->uc->block_addr == tb->pc) { + if (HOOK_EXISTS(env->uc, UC_HOOK_BLOCK) && env->uc->block_addr == tb->pc) { if (env->uc->block_full) // block size is unknown *(s->gen_opparam_buf + 1) = 0; else diff --git a/uc.c b/uc.c index b354a5fa..f7f40853 100644 --- a/uc.c +++ b/uc.c @@ -20,7 +20,6 @@ #endif #include "uc_priv.h" -#include "hook.h" // target specific headers #include "qemu/target-m68k/unicorn.h" @@ -95,8 +94,6 @@ const char *uc_strerror(uc_err code) return "Write to unaligned memory (UC_ERR_WRITE_UNALIGNED)"; case UC_ERR_FETCH_UNALIGNED: return "Fetch from unaligned memory (UC_ERR_FETCH_UNALIGNED)"; - case UC_ERR_HOOK_EXIST: - return "Hook for this type event already exists (UC_ERR_HOOK_EXIST)"; case UC_ERR_RESOURCE: return "Insufficient resource (UC_ERR_RESOURCE)"; } @@ -245,9 +242,6 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) if (uc->reg_reset) uc->reg_reset(uc); - uc->hook_size = HOOK_SIZE; - uc->hook_callbacks = calloc(1, sizeof(uc->hook_callbacks[0]) * HOOK_SIZE); - return UC_ERR_OK; } else { return UC_ERR_ARCH; @@ -259,6 +253,8 @@ UNICORN_EXPORT uc_err uc_close(uc_engine *uc) { int i; + struct list_item *cur; + struct hook *hook; if (uc->release) uc->release(uc->tcg_ctx); @@ -284,7 +280,20 @@ uc_err uc_close(uc_engine *uc) // TODO: remove uc->root (created with object_new()) uc->root->free(uc->root); - free(uc->hook_callbacks); + // free hooks and hook lists + for (i = 0; i < UC_HOOK_MAX; i++) { + cur = uc->hook[i].head; + // hook can be in more than one list + // so we refcount to know when to free + while (cur) { + hook = (struct hook *)cur->data; + if (--hook->refs == 0) { + free(hook); + } + cur = cur->next; + } + list_clear(&uc->hook[i]); + } free(uc->mapped_blocks); @@ -445,6 +454,15 @@ static void enable_emu_timer(uc_engine *uc, uint64_t timeout) uc, QEMU_THREAD_JOINABLE); } +static void hook_count_cb(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) +{ + // count this instruction. ah ah ah. + uc->emu_counter++; + + if (uc->emu_counter > uc->emu_count) + uc_emu_stop(uc); +} + UNICORN_EXPORT uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count) { @@ -506,8 +524,17 @@ uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t time } uc->emu_count = count; - if (count > 0) { - uc->hook_insn = true; + // remove count hook if counting isn't necessary + if (count <= 0 && uc->count_hook != 0) { + uc_hook_del(uc, uc->count_hook); + uc->count_hook = 0; + } + // set up count hook to count instructions. + if (count > 0 && uc->count_hook == 0) { + uc_err err = uc_hook_add(uc, &uc->count_hook, UC_HOOK_CODE, hook_count_cb, NULL); + if (err != UC_ERR_OK) { + return err; + } } uc->addr_end = until; @@ -546,37 +573,6 @@ uc_err uc_emu_stop(uc_engine *uc) return UC_ERR_OK; } - -static int _hook_code(uc_engine *uc, int type, uint64_t begin, uint64_t end, - void *callback, void *user_data, uc_hook *hh) -{ - int i; - - i = hook_add(uc, type, begin, end, callback, user_data); - if (i == 0) - return UC_ERR_NOMEM; - - *hh = i; - - return UC_ERR_OK; -} - - -static uc_err _hook_mem_access(uc_engine *uc, uc_hook_type type, - uint64_t begin, uint64_t end, - void *callback, void *user_data, uc_hook *hh) -{ - int i; - - i = hook_add(uc, type, begin, end, callback, user_data); - if (i == 0) - return UC_ERR_NOMEM; - - *hh = i; - - return UC_ERR_OK; -} - // find if a memory range overlaps with existing mapped regions static bool memory_overlap(struct uc_struct *uc, uint64_t begin, size_t size) { @@ -935,208 +931,95 @@ MemoryRegion *memory_mapping(struct uc_struct* uc, uint64_t address) return NULL; } -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; - - // only one event handler at the same time - if ((type & UC_HOOK_MEM_READ_UNMAPPED) != 0 && (uc->hook_mem_read_idx != 0)) - return UC_ERR_HOOK_EXIST; - - if ((type & UC_HOOK_MEM_READ_PROT) != 0 && (uc->hook_mem_read_prot_idx != 0)) - return UC_ERR_HOOK_EXIST; - - if ((type & UC_HOOK_MEM_WRITE_UNMAPPED) != 0 && (uc->hook_mem_write_idx != 0)) - return UC_ERR_HOOK_EXIST; - - if ((type & UC_HOOK_MEM_WRITE_PROT) != 0 && (uc->hook_mem_write_prot_idx != 0)) - return UC_ERR_HOOK_EXIST; - - if ((type & UC_HOOK_MEM_FETCH_UNMAPPED) != 0 && (uc->hook_mem_fetch_idx != 0)) - return UC_ERR_HOOK_EXIST; - - if ((type & UC_HOOK_MEM_FETCH_PROT) != 0 && (uc->hook_mem_fetch_prot_idx != 0)) - return UC_ERR_HOOK_EXIST; - - i = hook_find_new(uc); - if (i) { - uc->hook_callbacks[i].callback = callback; - uc->hook_callbacks[i].user_data = user_data; - *evh = i; - if (type & UC_HOOK_MEM_READ_UNMAPPED) - 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_UNMAPPED) - 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_UNMAPPED) - 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; -} - - -static uc_err _hook_intr(struct uc_struct* uc, void *callback, - void *user_data, uc_hook *evh) -{ - size_t i; - - // only one event handler at the same time - if (uc->hook_intr_idx) - return UC_ERR_HOOK_EXIST; - - i = hook_find_new(uc); - if (i) { - uc->hook_callbacks[i].callback = callback; - uc->hook_callbacks[i].user_data = user_data; - *evh = i; - uc->hook_intr_idx = i; - return UC_ERR_OK; - } else - return UC_ERR_NOMEM; -} - - -static uc_err _hook_insn(struct uc_struct *uc, unsigned int insn_id, void *callback, - void *user_data, uc_hook *evh) -{ - size_t i; - - switch(uc->arch) { - default: break; - case UC_ARCH_X86: - switch(insn_id) { - default: break; - case UC_X86_INS_OUT: - // only one event handler at the same time - if (uc->hook_out_idx) - return UC_ERR_HOOK_EXIST; - - i = hook_find_new(uc); - if (i) { - uc->hook_callbacks[i].callback = callback; - uc->hook_callbacks[i].user_data = user_data; - *evh = i; - uc->hook_out_idx = i; - return UC_ERR_OK; - } else - return UC_ERR_NOMEM; - case UC_X86_INS_IN: - // only one event handler at the same time - if (uc->hook_in_idx) - return UC_ERR_HOOK_EXIST; - - i = hook_find_new(uc); - if (i) { - uc->hook_callbacks[i].callback = callback; - uc->hook_callbacks[i].user_data = user_data; - *evh = i; - uc->hook_in_idx = i; - return UC_ERR_OK; - } else - return UC_ERR_NOMEM; - case UC_X86_INS_SYSCALL: - case UC_X86_INS_SYSENTER: - // only one event handler at the same time - if (uc->hook_syscall_idx) - return UC_ERR_HOOK_EXIST; - - i = hook_find_new(uc); - if (i) { - uc->hook_callbacks[i].callback = callback; - uc->hook_callbacks[i].user_data = user_data; - *evh = i; - uc->hook_syscall_idx = i; - return UC_ERR_OK; - } else - return UC_ERR_NOMEM; - } - break; - } - - return UC_ERR_OK; -} - UNICORN_EXPORT 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; - int id; - uint64_t begin, end; va_start(valist, user_data); - if (type & UC_HOOK_MEM_READ_UNMAPPED) - ret = _hook_mem_invalid(uc, UC_HOOK_MEM_READ_UNMAPPED, callback, user_data, hh); + struct hook *hook = calloc(1, sizeof(struct hook)); + if (hook == NULL) { + return UC_ERR_NOMEM; + } + hook->type = type; + hook->callback = callback; + hook->user_data = user_data; + hook->refs = 0; + *hh = (uc_hook)hook; - if (type & UC_HOOK_MEM_WRITE_UNMAPPED) - ret = _hook_mem_invalid(uc, UC_HOOK_MEM_WRITE_UNMAPPED, callback, user_data, hh); - - if (type & UC_HOOK_MEM_FETCH_UNMAPPED) - ret = _hook_mem_invalid(uc, UC_HOOK_MEM_FETCH_UNMAPPED, 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: - break; - case UC_HOOK_INTR: - ret = _hook_intr(uc, callback, user_data, hh); - break; - case UC_HOOK_INSN: - id = va_arg(valist, int); - ret = _hook_insn(uc, id, callback, user_data, hh); - break; - case UC_HOOK_CODE: - begin = va_arg(valist, uint64_t); - end = va_arg(valist, uint64_t); - ret = _hook_code(uc, UC_HOOK_CODE, begin, end, callback, user_data, hh); - break; - case UC_HOOK_BLOCK: - begin = va_arg(valist, uint64_t); - end = va_arg(valist, uint64_t); - ret = _hook_code(uc, UC_HOOK_BLOCK, begin, end, callback, user_data, hh); - break; - case UC_HOOK_MEM_READ: - begin = va_arg(valist, uint64_t); - end = va_arg(valist, uint64_t); - ret = _hook_mem_access(uc, UC_HOOK_MEM_READ, begin, end, callback, user_data, hh); - break; - case UC_HOOK_MEM_WRITE: - begin = va_arg(valist, uint64_t); - 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 | 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 | UC_HOOK_MEM_WRITE, begin, end, callback, user_data, hh); - break; + // everybody but HOOK_INSN gets begin/end, so exit early here. + if (type & UC_HOOK_INSN) { + hook->insn = va_arg(valist, int); + hook->begin = 1; + hook->end = 0; + if (list_append(&uc->hook[UC_HOOK_INSN_IDX], hook) == NULL) { + free(hook); + return UC_ERR_NOMEM; + } + hook->refs++; + return UC_ERR_OK; } + hook->begin = va_arg(valist, uint64_t); + hook->end = va_arg(valist, uint64_t); va_end(valist); + int i = 0; + while ((type >> i) > 0) { + if ((type >> i) & 1) { + // TODO: invalid hook error? + if (i < UC_HOOK_MAX) { + if (list_append(&uc->hook[i], hook) == NULL) { + if (hook->refs == 0) { + free(hook); + } + return UC_ERR_NOMEM; + } + hook->refs++; + } + } + i++; + } + + // we didn't use the hook + // TODO: return an error? + if (hook->refs == 0) { + free(hook); + } + return ret; } UNICORN_EXPORT uc_err uc_hook_del(uc_engine *uc, uc_hook hh) { - return hook_del(uc, hh); + int i; + struct hook *hook; + for (i = 0; i < UC_HOOK_MAX; i++) { + if (list_remove(&uc->hook[i], (void *)hh)) { + hook = (struct hook *)hh; + if (--hook->refs == 0) { + free(hook); + } + } + } + return UC_ERR_OK; +} + +// TCG helper +void helper_uc_tracecode(int32_t size, void *callback, void *handle, int64_t address, void *user_data); +void helper_uc_tracecode(int32_t size, void *callback, void *handle, int64_t address, void *user_data) +{ + struct uc_struct *uc = handle; + + // sync PC in CPUArchState with address + if (uc->set_pc) { + uc->set_pc(uc, address); + } + + ((uc_cb_hookcode_t)callback)(uc, address, size, user_data); } UNICORN_EXPORT From 33180b5afac6acc9f06ad9cc6e753693fa8ad9bf Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Thu, 21 Jan 2016 20:58:21 -0800 Subject: [PATCH 016/126] add test for multiple basic block hooks --- tests/unit/Makefile | 4 +- tests/unit/test_multihook.c | 111 ++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 tests/unit/test_multihook.c diff --git a/tests/unit/Makefile b/tests/unit/Makefile index b261da4d..cd0e46eb 100644 --- a/tests/unit/Makefile +++ b/tests/unit/Makefile @@ -5,7 +5,7 @@ CFLAGS += -lcmocka -lunicorn CFLAGS += -I ../../include ALL_TESTS = test_sanity test_x86 test_mem_map test_mem_high test_mem_map_ptr \ - test_tb_x86 + test_tb_x86 test_multihook .PHONY: all all: ${ALL_TESTS} @@ -23,6 +23,7 @@ test: ${ALL_TESTS} ./test_mem_map_ptr ./test_mem_high ./test_tb_x86 + ./test_multihook test_sanity: test_sanity.c test_x86: test_x86.c @@ -30,6 +31,7 @@ test_mem_map: test_mem_map.c test_mem_map_ptr: test_mem_map_ptr.c test_mem_high: test_mem_high.c test_tb_x86: test_tb_x86.c +test_multihook: test_multihook.c ${ALL_TESTS}: ${CC} ${CFLAGS} -o $@ $^ diff --git a/tests/unit/test_multihook.c b/tests/unit/test_multihook.c new file mode 100644 index 00000000..eb831865 --- /dev/null +++ b/tests/unit/test_multihook.c @@ -0,0 +1,111 @@ +#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]; + + printf("block hook 1: %d == %zu\n", size, bb->size); + assert_int_equal(address, bb->addr); + assert_int_equal((size_t)size, bb->size); +} + +static void test_basic_blocks_hook2(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++]; + + printf("block hook 2: %d == %zu\n", size, bb->size); + 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, trace2; + +#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_hook_add(uc, &trace2, UC_HOOK_BLOCK, test_basic_blocks_hook2, &bbtest, (uint64_t)1, (uint64_t)0)); + + OK(uc_emu_start(uc, address, address+sizeof(code), 0, 0)); +} + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_basic_blocks, setup32, teardown), + }; + return cmocka_run_group_tests(tests, NULL, NULL); +} From 0886ae8ede5208f56e08415e1869e995f15ca986 Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Fri, 22 Jan 2016 18:28:17 -0800 Subject: [PATCH 017/126] rework code/block tracing --- list.c | 2 ++ qemu/target-arm/helper.h | 2 +- qemu/target-arm/translate-a64.c | 18 ++++++----------- qemu/target-arm/translate.c | 29 +++++++++------------------- qemu/target-i386/helper.h | 2 +- qemu/target-i386/translate.c | 25 +++++++----------------- qemu/target-m68k/helper.h | 2 +- qemu/target-m68k/translate.c | 20 ++++++------------- qemu/target-mips/helper.h | 2 +- qemu/target-mips/translate.c | 34 ++++++++++----------------------- qemu/target-sparc/helper.h | 2 +- qemu/target-sparc/translate.c | 26 ++++++++----------------- qemu/tcg/tcg-op.h | 7 +++---- qemu/translate-all.c | 2 +- uc.c | 12 +++++++++--- 15 files changed, 66 insertions(+), 119 deletions(-) diff --git a/list.c b/list.c index 695f5a24..6dbe4782 100644 --- a/list.c +++ b/list.c @@ -18,6 +18,8 @@ void list_clear(struct list *list) free(cur); cur = next; } + list->head = NULL; + list->tail = NULL; } // returns generated linked list node, or NULL on failure diff --git a/qemu/target-arm/helper.h b/qemu/target-arm/helper.h index d2de58d6..6427c18c 100644 --- a/qemu/target-arm/helper.h +++ b/qemu/target-arm/helper.h @@ -1,4 +1,4 @@ -DEF_HELPER_5(uc_tracecode, void, i32, ptr, ptr, i64, ptr) +DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64) DEF_HELPER_FLAGS_1(clz_arm, TCG_CALL_NO_RWG_SE, i32, i32) diff --git a/qemu/target-arm/translate-a64.c b/qemu/target-arm/translate-a64.c index 28d57681..4079a61c 100644 --- a/qemu/target-arm/translate-a64.c +++ b/qemu/target-arm/translate-a64.c @@ -10985,10 +10985,8 @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s) s->pc += 4; // Unicorn: trace this instruction on request - HOOK_FOREACH(env->uc, hook, UC_HOOK_CODE) { - if (! HOOK_BOUND_CHECK(hook, s->pc - 4)) - continue; - gen_uc_tracecode(tcg_ctx, 4, hook->callback, env->uc, s->pc - 4, hook->user_data); + if (HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_CODE, s->pc - 4)) { + gen_uc_tracecode(tcg_ctx, 4, UC_HOOK_CODE_IDX, env->uc, s->pc - 4); // the callback might want to stop emulation immediately check_exit_request(tcg_ctx); } @@ -11116,14 +11114,10 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu, // Unicorn: trace this block on request // Only hook this block if it is not broken from previous translation due to // full translation cache - if (! env->uc->block_full) { - HOOK_FOREACH(env->uc, hook, UC_HOOK_BLOCK) { - if (! HOOK_BOUND_CHECK(hook, pc_start)) - continue; - // save block address to see if we need to patch block size later - env->uc->block_addr = pc_start; - gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, hook->callback, env->uc, pc_start, hook->user_data); - } + if (! env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) { + // save block address to see if we need to patch block size later + env->uc->block_addr = pc_start; + gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start); } gen_tb_start(tcg_ctx); diff --git a/qemu/target-arm/translate.c b/qemu/target-arm/translate.c index bf190452..d097c236 100644 --- a/qemu/target-arm/translate.c +++ b/qemu/target-arm/translate.c @@ -7680,7 +7680,6 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) // qq TCGv_i32 tmp3; TCGv_i32 addr; TCGv_i64 tmp64; - struct hook *hook; /* M variants do not implement ARM mode. */ if (arm_dc_feature(s, ARM_FEATURE_M)) { @@ -7688,10 +7687,8 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) // qq } // Unicorn: trace this instruction on request - HOOK_FOREACH(s->uc, hook, UC_HOOK_CODE) { - if (! HOOK_BOUND_CHECK(hook, s->pc - 4)) - continue; - gen_uc_tracecode(tcg_ctx, 4, hook->callback, s->uc, s->pc - 4, hook->user_data); + if (HOOK_EXISTS_BOUNDED(s->uc, UC_HOOK_CODE, s->pc - 4)) { + gen_uc_tracecode(tcg_ctx, 4, UC_HOOK_CODE_IDX, s->uc, s->pc - 4); // the callback might want to stop emulation immediately check_exit_request(tcg_ctx); } @@ -10391,7 +10388,6 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) // qq TCGv_i32 tmp; TCGv_i32 tmp2; TCGv_i32 addr; - struct hook *hook; // Unicorn: end address tells us to stop emulation if (s->pc == s->uc->addr_end) { @@ -10410,11 +10406,9 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) // qq } // Unicorn: trace this instruction on request - HOOK_FOREACH(env->uc, hook, UC_HOOK_CODE) { - if (! HOOK_BOUND_CHECK(hook, s->pc)) - continue; - gen_uc_tracecode(tcg_ctx, 2, hook->callback, env->uc, s->pc, hook->user_data); - // check to see if we need to exit immediately + if (HOOK_EXISTS_BOUNDED(s->uc, UC_HOOK_CODE, s->pc)) { + gen_uc_tracecode(tcg_ctx, 2, UC_HOOK_CODE_IDX, s->uc, s->pc); + // the callback might want to stop emulation immediately check_exit_request(tcg_ctx); } @@ -11147,7 +11141,6 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, int max_insns; TCGContext *tcg_ctx = env->uc->tcg_ctx; bool block_full = false; - struct hook *hook; /* generate intermediate code */ @@ -11237,14 +11230,10 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, // Unicorn: trace this block on request // Only hook this block if it is not broken from previous translation due to // full translation cache - if (!env->uc->block_full) { - HOOK_FOREACH(env->uc, hook, UC_HOOK_BLOCK) { - if (! HOOK_BOUND_CHECK(hook, pc_start)) - continue; - // save block address to see if we need to patch block size later - env->uc->block_addr = pc_start; - gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, hook->callback, env->uc, pc_start, hook->user_data); - } + if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) { + // save block address to see if we need to patch block size later + env->uc->block_addr = pc_start; + gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start); } gen_tb_start(tcg_ctx); diff --git a/qemu/target-i386/helper.h b/qemu/target-i386/helper.h index 8ab196ac..d3b52d1f 100644 --- a/qemu/target-i386/helper.h +++ b/qemu/target-i386/helper.h @@ -1,4 +1,4 @@ -DEF_HELPER_5(uc_tracecode, void, i32, ptr, ptr, i64, ptr) +DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64) DEF_HELPER_FLAGS_4(cc_compute_all, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl, int) DEF_HELPER_FLAGS_4(cc_compute_c, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl, int) diff --git a/qemu/target-i386/translate.c b/qemu/target-i386/translate.c index 0d83f4bd..d68cb516 100644 --- a/qemu/target-i386/translate.c +++ b/qemu/target-i386/translate.c @@ -4745,7 +4745,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, TCGv cpu_tmp4 = *(TCGv *)tcg_ctx->cpu_tmp4; TCGv **cpu_T = (TCGv **)tcg_ctx->cpu_T; TCGv **cpu_regs = (TCGv **)tcg_ctx->cpu_regs; - struct hook *hook = NULL; TCGArg *save_opparam_ptr = tcg_ctx->gen_opparam_ptr; bool cc_op_dirty = s->cc_op_dirty; bool changed_cc_op = false; @@ -4773,14 +4772,9 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, s->last_cc_op = s->cc_op; changed_cc_op = true; } - HOOK_FOREACH(env->uc, hook, UC_HOOK_CODE) { - if (! HOOK_BOUND_CHECK(hook, pc_start)) - continue; - // generate code to call callback - gen_uc_tracecode(tcg_ctx, 0xf1f1f1f1, hook->callback, env->uc, pc_start, hook->user_data); - // the callback might want to stop emulation immediately - check_exit_request(tcg_ctx); - } + gen_uc_tracecode(tcg_ctx, 0xf1f1f1f1, UC_HOOK_CODE_IDX, env->uc, pc_start); + // the callback might want to stop emulation immediately + check_exit_request(tcg_ctx); } prefixes = 0; @@ -8173,7 +8167,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_helper_unlock(tcg_ctx, cpu_env); // Unicorn: patch the callback for the instruction size - if (hook) { + if (HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_CODE, pc_start)) { // int i; // for(i = 0; i < 20; i++) // printf("=== [%u] = %x\n", i, *(save_opparam_ptr + i)); @@ -8282,7 +8276,6 @@ static inline void gen_intermediate_code_internal(uint8_t *gen_opc_cc_op, int num_insns = 0; int max_insns; bool block_full = false; - struct hook *hook; /* generate intermediate code */ pc_start = tb->pc; @@ -8388,13 +8381,9 @@ static inline void gen_intermediate_code_internal(uint8_t *gen_opc_cc_op, // Unicorn: trace this block on request // Only hook this block if it is not broken from previous translation due to // full translation cache - if (!env->uc->block_full) { - HOOK_FOREACH(env->uc, hook, UC_HOOK_BLOCK) { - if (! HOOK_BOUND_CHECK(hook, pc_start)) - continue; - env->uc->block_addr = pc_start; - gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, hook->callback, env->uc, pc_start, hook->user_data); - } + if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) { + env->uc->block_addr = pc_start; + gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start); } gen_tb_start(tcg_ctx); diff --git a/qemu/target-m68k/helper.h b/qemu/target-m68k/helper.h index 865cf95d..caaadb3a 100644 --- a/qemu/target-m68k/helper.h +++ b/qemu/target-m68k/helper.h @@ -1,4 +1,4 @@ -DEF_HELPER_5(uc_tracecode, void, i32, ptr, ptr, i64, ptr) +DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64) DEF_HELPER_1(bitrev, i32, i32) DEF_HELPER_1(ff1, i32, i32) diff --git a/qemu/target-m68k/translate.c b/qemu/target-m68k/translate.c index 0f685d8e..bf45a66a 100644 --- a/qemu/target-m68k/translate.c +++ b/qemu/target-m68k/translate.c @@ -3031,7 +3031,6 @@ static void disas_m68k_insn(CPUM68KState * env, DisasContext *s) { TCGContext *tcg_ctx = s->uc->tcg_ctx; uint16_t insn; - struct hook *hook; if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) { tcg_gen_debug_insn_start(tcg_ctx, s->pc); @@ -3044,10 +3043,8 @@ static void disas_m68k_insn(CPUM68KState * env, DisasContext *s) } // Unicorn: trace this instruction on request - HOOK_FOREACH(env->uc, hook, UC_HOOK_CODE) { - if (! HOOK_BOUND_CHECK(hook, s->pc)) - continue; - gen_uc_tracecode(tcg_ctx, 2, hook->callback, env->uc, s->pc, hook->user_data); + if (HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_CODE, s->pc)) { + gen_uc_tracecode(tcg_ctx, 2, UC_HOOK_CODE_IDX, env->uc, s->pc); // the callback might want to stop emulation immediately check_exit_request(tcg_ctx); } @@ -3075,7 +3072,6 @@ gen_intermediate_code_internal(M68kCPU *cpu, TranslationBlock *tb, int max_insns; TCGContext *tcg_ctx = env->uc->tcg_ctx; bool block_full = false; - struct hook *hook; /* generate intermediate code */ pc_start = tb->pc; @@ -3110,14 +3106,10 @@ gen_intermediate_code_internal(M68kCPU *cpu, TranslationBlock *tb, // Unicorn: trace this block on request // Only hook this block if it is not broken from previous translation due to // full translation cache - if (!env->uc->block_full) { - HOOK_FOREACH(env->uc, hook, UC_HOOK_BLOCK) { - if (! HOOK_BOUND_CHECK(hook, pc_start)) - continue; - // save block address to see if we need to patch block size later - env->uc->block_addr = pc_start; - gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, hook->callback, env->uc, pc_start, hook->user_data); - } + if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) { + // save block address to see if we need to patch block size later + env->uc->block_addr = pc_start; + gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start); } gen_tb_start(tcg_ctx); diff --git a/qemu/target-mips/helper.h b/qemu/target-mips/helper.h index 81f733c2..1924bf6f 100644 --- a/qemu/target-mips/helper.h +++ b/qemu/target-mips/helper.h @@ -1,4 +1,4 @@ -DEF_HELPER_5(uc_tracecode, void, i32, ptr, ptr, i64, ptr) +DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64) DEF_HELPER_3(raise_exception_err, noreturn, env, i32, int) DEF_HELPER_2(raise_exception, noreturn, env, i32) diff --git a/qemu/target-mips/translate.c b/qemu/target-mips/translate.c index fadbaeb0..8802c221 100644 --- a/qemu/target-mips/translate.c +++ b/qemu/target-mips/translate.c @@ -11331,7 +11331,6 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, bool *insn_n int op, cnvt_op, op1, offset; int funct; int n_bytes; - struct hook *hook; op = (ctx->opcode >> 11) & 0x1f; sa = (ctx->opcode >> 2) & 0x7; @@ -11344,10 +11343,8 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, bool *insn_n n_bytes = 2; // Unicorn: trace this instruction on request - HOOK_FOREACH(env->uc, hook, UC_HOOK_CODE) { - if (! HOOK_BOUND_CHECK(hook, ctx->pc)) - continue; - gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, hook->callback, env->uc, ctx->pc, hook->user_data); + if (HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_CODE, ctx->pc)) { + gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_CODE_IDX, env->uc, ctx->pc); *insn_need_patch = true; // the callback might want to stop emulation immediately check_exit_request(tcg_ctx); @@ -13932,7 +13929,6 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, bool *ins TCGContext *tcg_ctx = env->uc->tcg_ctx; TCGv **cpu_gpr = (TCGv **)tcg_ctx->cpu_gpr; uint32_t op; - struct hook *hook; /* make sure instructions are on a halfword boundary */ if (ctx->pc & 0x1) { @@ -13943,10 +13939,8 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, bool *ins } // Unicorn: trace this instruction on request - HOOK_FOREACH(env->uc, hook, UC_HOOK_CODE) { - if (! HOOK_BOUND_CHECK(hook, ctx->pc)) - continue; - gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, hook->callback, env->uc, ctx->pc, hook->user_data); + if (HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_CODE, ctx->pc)) { + gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_CODE_IDX, env->uc, ctx->pc); *insn_need_patch = true; // the callback might want to stop emulation immediately check_exit_request(tcg_ctx); @@ -18505,11 +18499,8 @@ static void gen_msa(CPUMIPSState *env, DisasContext *ctx) static void hook_insn(CPUMIPSState *env, DisasContext *ctx, bool *insn_need_patch, int *insn_patch_offset, int offset_value) { TCGContext *tcg_ctx = ctx->uc->tcg_ctx; - struct hook *hook; - HOOK_FOREACH(env->uc, hook, UC_HOOK_CODE) { - if (! HOOK_BOUND_CHECK(hook, ctx->pc)) - continue; - gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, hook->callback, env->uc, ctx->pc, hook->user_data); + if (HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_CODE, ctx->pc)) { + gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_CODE_IDX, env->uc, ctx->pc); *insn_need_patch = true; // the callback might want to stop emulation immediately check_exit_request(tcg_ctx); @@ -19178,7 +19169,6 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, TCGContext *tcg_ctx = env->uc->tcg_ctx; TCGArg *save_opparam_ptr = NULL; bool block_full = false; - struct hook *hook; if (search_pc) qemu_log("search pc %d\n", search_pc); @@ -19224,14 +19214,10 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, // Unicorn: trace this block on request // Only hook this block if it is not broken from previous translation due to // full translation cache - if (! env->uc->block_full) { - HOOK_FOREACH(env->uc, hook, UC_HOOK_BLOCK) { - if (! HOOK_BOUND_CHECK(hook, pc_start)) - continue; - // save block address to see if we need to patch block size later - env->uc->block_addr = pc_start; - gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, hook->callback, env->uc, pc_start, hook->user_data); - } + if (! env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) { + // save block address to see if we need to patch block size later + env->uc->block_addr = pc_start; + gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start); } gen_tb_start(tcg_ctx); diff --git a/qemu/target-sparc/helper.h b/qemu/target-sparc/helper.h index 2557dd08..503e1e5c 100644 --- a/qemu/target-sparc/helper.h +++ b/qemu/target-sparc/helper.h @@ -1,4 +1,4 @@ -DEF_HELPER_5(uc_tracecode, void, i32, ptr, ptr, i64, ptr) +DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64) DEF_HELPER_1(power_down, void, env) #ifndef TARGET_SPARC64 diff --git a/qemu/target-sparc/translate.c b/qemu/target-sparc/translate.c index 8caba2b7..a7f067cf 100644 --- a/qemu/target-sparc/translate.c +++ b/qemu/target-sparc/translate.c @@ -2625,7 +2625,6 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn, bool hook_ins TCGv_i32 cpu_src1_32, cpu_src2_32, cpu_dst_32; TCGv_i64 cpu_src1_64, cpu_src2_64, cpu_dst_64; target_long simm; - struct hook *hook; if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) { tcg_gen_debug_insn_start(tcg_ctx, dc->pc); @@ -2638,14 +2637,10 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn, bool hook_ins } // Unicorn: trace this instruction on request - if (hook_insn) { - HOOK_FOREACH(dc->uc, hook, UC_HOOK_CODE) { - if (! HOOK_BOUND_CHECK(hook, dc->pc)) - continue; - gen_uc_tracecode(tcg_ctx, 4, hook->callback, dc->uc, dc->pc, hook->user_data); - // the callback might want to stop emulation immediately - check_exit_request(tcg_ctx); - } + if (hook_insn && HOOK_EXISTS_BOUNDED(dc->uc, UC_HOOK_CODE, dc->pc)) { + gen_uc_tracecode(tcg_ctx, 4, UC_HOOK_CODE_IDX, dc->uc, dc->pc); + // the callback might want to stop emulation immediately + check_exit_request(tcg_ctx); } opc = GET_FIELD(insn, 0, 1); @@ -5390,7 +5385,6 @@ static inline void gen_intermediate_code_internal(SPARCCPU *cpu, unsigned int insn; TCGContext *tcg_ctx = env->uc->tcg_ctx; bool block_full = false; - struct hook *hook; memset(dc, 0, sizeof(DisasContext)); dc->uc = env->uc; @@ -5431,14 +5425,10 @@ static inline void gen_intermediate_code_internal(SPARCCPU *cpu, // Unicorn: trace this block on request // Only hook this block if it is not broken from previous translation due to // full translation cache - if (!env->uc->block_full) { - HOOK_FOREACH(env->uc, hook, UC_HOOK_BLOCK) { - if (! HOOK_BOUND_CHECK(hook, pc_start)) - continue; - // save block address to see if we need to patch block size later - env->uc->block_addr = pc_start; - gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, hook->callback, env->uc, pc_start, hook->user_data); - } + if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) { + // save block address to see if we need to patch block size later + env->uc->block_addr = pc_start; + gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start); } gen_tb_start(tcg_ctx); diff --git a/qemu/tcg/tcg-op.h b/qemu/tcg/tcg-op.h index 9f096a3d..87358240 100644 --- a/qemu/tcg/tcg-op.h +++ b/qemu/tcg/tcg-op.h @@ -27,14 +27,13 @@ int gen_new_label(TCGContext *); -static inline void gen_uc_tracecode(TCGContext *tcg_ctx, int32_t size, void *callback, void *uc, uint64_t pc, void *data) +static inline void gen_uc_tracecode(TCGContext *tcg_ctx, int32_t size, int32_t type, void *uc, uint64_t pc) { TCGv_i32 tsize = tcg_const_i32(tcg_ctx, size); - TCGv_ptr tcallback = tcg_const_ptr(tcg_ctx, callback); + TCGv_i32 ttype = tcg_const_i32(tcg_ctx, type); TCGv_ptr tuc = tcg_const_ptr(tcg_ctx, uc); TCGv_i64 tpc = tcg_const_i64(tcg_ctx, pc); - TCGv_ptr tdata = tcg_const_ptr(tcg_ctx, data); - gen_helper_uc_tracecode(tcg_ctx, tsize, tcallback, tuc, tpc, tdata); + gen_helper_uc_tracecode(tcg_ctx, tsize, ttype, tuc, tpc); } static inline void tcg_gen_op0(TCGContext *s, TCGOpcode opc) diff --git a/qemu/translate-all.c b/qemu/translate-all.c index 72e1b60f..aec38c7c 100644 --- a/qemu/translate-all.c +++ b/qemu/translate-all.c @@ -179,7 +179,7 @@ static int cpu_gen_code(CPUArchState *env, TranslationBlock *tb, int *gen_code_s gen_intermediate_code(env, tb); // Unicorn: when tracing block, patch 1st operand for block size - if (HOOK_EXISTS(env->uc, UC_HOOK_BLOCK) && env->uc->block_addr == tb->pc) { + if (env->uc->block_addr == tb->pc && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, tb->pc)) { if (env->uc->block_full) // block size is unknown *(s->gen_opparam_buf + 1) = 0; else diff --git a/uc.c b/uc.c index f7f40853..b0f8a976 100644 --- a/uc.c +++ b/uc.c @@ -1009,17 +1009,23 @@ uc_err uc_hook_del(uc_engine *uc, uc_hook hh) } // TCG helper -void helper_uc_tracecode(int32_t size, void *callback, void *handle, int64_t address, void *user_data); -void helper_uc_tracecode(int32_t size, void *callback, void *handle, int64_t address, void *user_data) +void helper_uc_tracecode(int32_t size, uc_hook_type type, void *handle, int64_t address); +void helper_uc_tracecode(int32_t size, uc_hook_type type, void *handle, int64_t address) { struct uc_struct *uc = handle; + struct list_item *cur = uc->hook[type].head; + struct hook *hook; // sync PC in CPUArchState with address if (uc->set_pc) { uc->set_pc(uc, address); } - ((uc_cb_hookcode_t)callback)(uc, address, size, user_data); + while (cur != NULL && !uc->stop_request) { + hook = (struct hook *)cur->data; + ((uc_cb_hookcode_t)hook->callback)(uc, address, size, hook->user_data); + cur = cur->next; + } } UNICORN_EXPORT From d79925f477abb00659c99f08c948ee606a558b46 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 23 Jan 2016 10:48:18 +0800 Subject: [PATCH 018/126] sparc: add SPARC32 mode (= UC_MODE_32) --- bindings/dotnet/UnicornManaged/Const/Common.fs | 1 + bindings/go/unicorn/unicorn_const.go | 1 + bindings/java/unicorn/UnicornConst.java | 1 + bindings/python/sample_sparc.py | 2 +- bindings/python/unicorn/unicorn_const.py | 1 + include/uc_priv.h | 2 +- include/unicorn/unicorn.h | 5 +++-- samples/sample_sparc.c | 2 +- tests/regress/sparc64.py | 2 +- tests/regress/sparc_jump_to_zero.c | 2 +- tests/regress/sparc_reg.py | 2 +- 11 files changed, 13 insertions(+), 8 deletions(-) diff --git a/bindings/dotnet/UnicornManaged/Const/Common.fs b/bindings/dotnet/UnicornManaged/Const/Common.fs index f5c2230c..3ec03c74 100644 --- a/bindings/dotnet/UnicornManaged/Const/Common.fs +++ b/bindings/dotnet/UnicornManaged/Const/Common.fs @@ -37,6 +37,7 @@ module Common = let UC_MODE_64 = 8 let UC_MODE_PPC64 = 8 let UC_MODE_QPX = 16 + let UC_MODE_SPARC32 = 4 let UC_MODE_SPARC64 = 8 let UC_MODE_V9 = 16 diff --git a/bindings/go/unicorn/unicorn_const.go b/bindings/go/unicorn/unicorn_const.go index fb44acd0..2d8d2c1a 100644 --- a/bindings/go/unicorn/unicorn_const.go +++ b/bindings/go/unicorn/unicorn_const.go @@ -32,6 +32,7 @@ const ( MODE_64 = 8 MODE_PPC64 = 8 MODE_QPX = 16 + MODE_SPARC32 = 4 MODE_SPARC64 = 8 MODE_V9 = 16 diff --git a/bindings/java/unicorn/UnicornConst.java b/bindings/java/unicorn/UnicornConst.java index 614326b3..5967d26b 100644 --- a/bindings/java/unicorn/UnicornConst.java +++ b/bindings/java/unicorn/UnicornConst.java @@ -34,6 +34,7 @@ public interface UnicornConst { public static final int UC_MODE_64 = 8; public static final int UC_MODE_PPC64 = 8; public static final int UC_MODE_QPX = 16; + public static final int UC_MODE_SPARC32 = 4; public static final int UC_MODE_SPARC64 = 8; public static final int UC_MODE_V9 = 16; diff --git a/bindings/python/sample_sparc.py b/bindings/python/sample_sparc.py index 307ba936..a8bdd586 100755 --- a/bindings/python/sample_sparc.py +++ b/bindings/python/sample_sparc.py @@ -28,7 +28,7 @@ def test_sparc(): print("Emulate SPARC code") try: # Initialize emulator in SPARC EB mode - mu = Uc(UC_ARCH_SPARC, UC_MODE_32) + mu = Uc(UC_ARCH_SPARC, UC_MODE_SPARC32) # map 2MB memory for this emulation mu.mem_map(ADDRESS, 2 * 1024 * 1024) diff --git a/bindings/python/unicorn/unicorn_const.py b/bindings/python/unicorn/unicorn_const.py index c99cb816..a1967684 100644 --- a/bindings/python/unicorn/unicorn_const.py +++ b/bindings/python/unicorn/unicorn_const.py @@ -30,6 +30,7 @@ UC_MODE_32 = 4 UC_MODE_64 = 8 UC_MODE_PPC64 = 8 UC_MODE_QPX = 16 +UC_MODE_SPARC32 = 4 UC_MODE_SPARC64 = 8 UC_MODE_V9 = 16 diff --git a/include/uc_priv.h b/include/uc_priv.h index 12f0b8bc..589a655f 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -17,7 +17,7 @@ #define UC_MODE_MIPS_MASK (UC_MODE_MIPS32|UC_MODE_MIPS64|UC_MODE_LITTLE_ENDIAN|UC_MODE_BIG_ENDIAN) #define UC_MODE_X86_MASK (UC_MODE_16|UC_MODE_32|UC_MODE_64|UC_MODE_LITTLE_ENDIAN) #define UC_MODE_PPC_MASK (UC_MODE_PPC64|UC_MODE_BIG_ENDIAN) -#define UC_MODE_SPARC_MASK (UC_MODE_SPARC64|UC_MODE_BIG_ENDIAN) +#define UC_MODE_SPARC_MASK (UC_MODE_SPARC32|UC_MODE_SPARC64|UC_MODE_BIG_ENDIAN) #define UC_MODE_M68K_MASK (UC_MODE_BIG_ENDIAN) #define ARR_SIZE(a) (sizeof(a)/sizeof(a[0])) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index f3468ab6..a6bedfaf 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -89,8 +89,8 @@ typedef enum uc_mode { UC_MODE_LITTLE_ENDIAN = 0, // little-endian mode (default mode) UC_MODE_BIG_ENDIAN = 1 << 30, // big-endian mode // arm / arm64 - UC_MODE_ARM = 0, // Start executing in ARM mode - UC_MODE_THUMB = 1 << 4, // Start executing in THUMB mode (including Thumb-2) + UC_MODE_ARM = 0, // ARM mode + UC_MODE_THUMB = 1 << 4, // THUMB mode (including Thumb-2) UC_MODE_MCLASS = 1 << 5, // ARM's Cortex-M series (currently unsupported) UC_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM (currently unsupported) // mips @@ -107,6 +107,7 @@ typedef enum uc_mode { UC_MODE_PPC64 = 1 << 3, // 64-bit mode (currently unsupported) UC_MODE_QPX = 1 << 4, // Quad Processing eXtensions mode (currently unsupported) // sparc + UC_MODE_SPARC32 = 1 << 2, // 32-bit mode UC_MODE_SPARC64 = 1 << 3, // 64-bit mode UC_MODE_V9 = 1 << 4, // SparcV9 mode (currently unsupported) // m68k diff --git a/samples/sample_sparc.c b/samples/sample_sparc.c index c361232f..88bbd01e 100644 --- a/samples/sample_sparc.c +++ b/samples/sample_sparc.c @@ -57,7 +57,7 @@ static void test_sparc(void) printf("Emulate SPARC code\n"); // Initialize emulator in Sparc mode - err = uc_open(UC_ARCH_SPARC, 0, &uc); + err = uc_open(UC_ARCH_SPARC, UC_MODE_SPARC32, &uc); if (err) { printf("Failed on uc_open() with error returned: %u (%s)\n", err, uc_strerror(err)); diff --git a/tests/regress/sparc64.py b/tests/regress/sparc64.py index 27210bd1..12d3f547 100755 --- a/tests/regress/sparc64.py +++ b/tests/regress/sparc64.py @@ -5,7 +5,7 @@ from unicorn.sparc_const import * PAGE_SIZE = 1 * 1024 * 1024 -uc = Uc(UC_ARCH_SPARC, UC_MODE_64) +uc = Uc(UC_ARCH_SPARC, UC_MODE_SPARC64) uc.reg_write(UC_SPARC_REG_SP, 100) print 'writing sp = 100' diff --git a/tests/regress/sparc_jump_to_zero.c b/tests/regress/sparc_jump_to_zero.c index 96392f41..c816b700 100644 --- a/tests/regress/sparc_jump_to_zero.c +++ b/tests/regress/sparc_jump_to_zero.c @@ -1,7 +1,7 @@ #include #define HARDWARE_ARCHITECTURE UC_ARCH_SPARC -#define HARDWARE_MODE 0 +#define HARDWARE_MODE UC_ARCH_SPARC32 #define MEMORY_STARTING_ADDRESS 0x1000000 #define MEMORY_SIZE 2 * 1024 * 1024 diff --git a/tests/regress/sparc_reg.py b/tests/regress/sparc_reg.py index 4508efab..da6987d1 100755 --- a/tests/regress/sparc_reg.py +++ b/tests/regress/sparc_reg.py @@ -5,7 +5,7 @@ from unicorn.sparc_const import * PAGE_SIZE = 1 * 1024 * 1024 -uc = Uc(UC_ARCH_SPARC, 0) +uc = Uc(UC_ARCH_SPARC, UC_MODE_SPARC32) uc.reg_write(UC_SPARC_REG_SP, 100) uc.reg_write(UC_SPARC_REG_FP, 200) From 2ac1281f82314d4f49b213583c37213ff710a737 Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Fri, 22 Jan 2016 18:28:17 -0800 Subject: [PATCH 019/126] rework code/block tracing --- list.c | 2 ++ qemu/target-arm/helper.h | 2 +- qemu/target-arm/translate-a64.c | 20 ++++++------------- qemu/target-arm/translate.c | 29 +++++++++------------------- qemu/target-i386/helper.h | 2 +- qemu/target-i386/translate.c | 25 +++++++----------------- qemu/target-m68k/helper.h | 2 +- qemu/target-m68k/translate.c | 20 ++++++------------- qemu/target-mips/helper.h | 2 +- qemu/target-mips/translate.c | 34 ++++++++++----------------------- qemu/target-sparc/helper.h | 2 +- qemu/target-sparc/translate.c | 26 ++++++++----------------- qemu/tcg/tcg-op.h | 7 +++---- qemu/translate-all.c | 2 +- uc.c | 12 +++++++++--- 15 files changed, 66 insertions(+), 121 deletions(-) diff --git a/list.c b/list.c index 695f5a24..6dbe4782 100644 --- a/list.c +++ b/list.c @@ -18,6 +18,8 @@ void list_clear(struct list *list) free(cur); cur = next; } + list->head = NULL; + list->tail = NULL; } // returns generated linked list node, or NULL on failure diff --git a/qemu/target-arm/helper.h b/qemu/target-arm/helper.h index d2de58d6..6427c18c 100644 --- a/qemu/target-arm/helper.h +++ b/qemu/target-arm/helper.h @@ -1,4 +1,4 @@ -DEF_HELPER_5(uc_tracecode, void, i32, ptr, ptr, i64, ptr) +DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64) DEF_HELPER_FLAGS_1(clz_arm, TCG_CALL_NO_RWG_SE, i32, i32) diff --git a/qemu/target-arm/translate-a64.c b/qemu/target-arm/translate-a64.c index 28d57681..06378453 100644 --- a/qemu/target-arm/translate-a64.c +++ b/qemu/target-arm/translate-a64.c @@ -10970,7 +10970,6 @@ static void disas_data_proc_simd_fp(DisasContext *s, uint32_t insn) static void disas_a64_insn(CPUARMState *env, DisasContext *s) { uint32_t insn; - struct hook *hook; TCGContext *tcg_ctx = env->uc->tcg_ctx; // Unicorn: end address tells us to stop emulation @@ -10985,10 +10984,8 @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s) s->pc += 4; // Unicorn: trace this instruction on request - HOOK_FOREACH(env->uc, hook, UC_HOOK_CODE) { - if (! HOOK_BOUND_CHECK(hook, s->pc - 4)) - continue; - gen_uc_tracecode(tcg_ctx, 4, hook->callback, env->uc, s->pc - 4, hook->user_data); + if (HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_CODE, s->pc - 4)) { + gen_uc_tracecode(tcg_ctx, 4, UC_HOOK_CODE_IDX, env->uc, s->pc - 4); // the callback might want to stop emulation immediately check_exit_request(tcg_ctx); } @@ -11044,7 +11041,6 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu, int max_insns; TCGContext *tcg_ctx = env->uc->tcg_ctx; bool block_full = false; - struct hook *hook; pc_start = tb->pc; @@ -11116,14 +11112,10 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu, // Unicorn: trace this block on request // Only hook this block if it is not broken from previous translation due to // full translation cache - if (! env->uc->block_full) { - HOOK_FOREACH(env->uc, hook, UC_HOOK_BLOCK) { - if (! HOOK_BOUND_CHECK(hook, pc_start)) - continue; - // save block address to see if we need to patch block size later - env->uc->block_addr = pc_start; - gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, hook->callback, env->uc, pc_start, hook->user_data); - } + if (! env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) { + // save block address to see if we need to patch block size later + env->uc->block_addr = pc_start; + gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start); } gen_tb_start(tcg_ctx); diff --git a/qemu/target-arm/translate.c b/qemu/target-arm/translate.c index bf190452..d097c236 100644 --- a/qemu/target-arm/translate.c +++ b/qemu/target-arm/translate.c @@ -7680,7 +7680,6 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) // qq TCGv_i32 tmp3; TCGv_i32 addr; TCGv_i64 tmp64; - struct hook *hook; /* M variants do not implement ARM mode. */ if (arm_dc_feature(s, ARM_FEATURE_M)) { @@ -7688,10 +7687,8 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) // qq } // Unicorn: trace this instruction on request - HOOK_FOREACH(s->uc, hook, UC_HOOK_CODE) { - if (! HOOK_BOUND_CHECK(hook, s->pc - 4)) - continue; - gen_uc_tracecode(tcg_ctx, 4, hook->callback, s->uc, s->pc - 4, hook->user_data); + if (HOOK_EXISTS_BOUNDED(s->uc, UC_HOOK_CODE, s->pc - 4)) { + gen_uc_tracecode(tcg_ctx, 4, UC_HOOK_CODE_IDX, s->uc, s->pc - 4); // the callback might want to stop emulation immediately check_exit_request(tcg_ctx); } @@ -10391,7 +10388,6 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) // qq TCGv_i32 tmp; TCGv_i32 tmp2; TCGv_i32 addr; - struct hook *hook; // Unicorn: end address tells us to stop emulation if (s->pc == s->uc->addr_end) { @@ -10410,11 +10406,9 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) // qq } // Unicorn: trace this instruction on request - HOOK_FOREACH(env->uc, hook, UC_HOOK_CODE) { - if (! HOOK_BOUND_CHECK(hook, s->pc)) - continue; - gen_uc_tracecode(tcg_ctx, 2, hook->callback, env->uc, s->pc, hook->user_data); - // check to see if we need to exit immediately + if (HOOK_EXISTS_BOUNDED(s->uc, UC_HOOK_CODE, s->pc)) { + gen_uc_tracecode(tcg_ctx, 2, UC_HOOK_CODE_IDX, s->uc, s->pc); + // the callback might want to stop emulation immediately check_exit_request(tcg_ctx); } @@ -11147,7 +11141,6 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, int max_insns; TCGContext *tcg_ctx = env->uc->tcg_ctx; bool block_full = false; - struct hook *hook; /* generate intermediate code */ @@ -11237,14 +11230,10 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, // Unicorn: trace this block on request // Only hook this block if it is not broken from previous translation due to // full translation cache - if (!env->uc->block_full) { - HOOK_FOREACH(env->uc, hook, UC_HOOK_BLOCK) { - if (! HOOK_BOUND_CHECK(hook, pc_start)) - continue; - // save block address to see if we need to patch block size later - env->uc->block_addr = pc_start; - gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, hook->callback, env->uc, pc_start, hook->user_data); - } + if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) { + // save block address to see if we need to patch block size later + env->uc->block_addr = pc_start; + gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start); } gen_tb_start(tcg_ctx); diff --git a/qemu/target-i386/helper.h b/qemu/target-i386/helper.h index 8ab196ac..d3b52d1f 100644 --- a/qemu/target-i386/helper.h +++ b/qemu/target-i386/helper.h @@ -1,4 +1,4 @@ -DEF_HELPER_5(uc_tracecode, void, i32, ptr, ptr, i64, ptr) +DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64) DEF_HELPER_FLAGS_4(cc_compute_all, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl, int) DEF_HELPER_FLAGS_4(cc_compute_c, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl, int) diff --git a/qemu/target-i386/translate.c b/qemu/target-i386/translate.c index 0d83f4bd..d68cb516 100644 --- a/qemu/target-i386/translate.c +++ b/qemu/target-i386/translate.c @@ -4745,7 +4745,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, TCGv cpu_tmp4 = *(TCGv *)tcg_ctx->cpu_tmp4; TCGv **cpu_T = (TCGv **)tcg_ctx->cpu_T; TCGv **cpu_regs = (TCGv **)tcg_ctx->cpu_regs; - struct hook *hook = NULL; TCGArg *save_opparam_ptr = tcg_ctx->gen_opparam_ptr; bool cc_op_dirty = s->cc_op_dirty; bool changed_cc_op = false; @@ -4773,14 +4772,9 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, s->last_cc_op = s->cc_op; changed_cc_op = true; } - HOOK_FOREACH(env->uc, hook, UC_HOOK_CODE) { - if (! HOOK_BOUND_CHECK(hook, pc_start)) - continue; - // generate code to call callback - gen_uc_tracecode(tcg_ctx, 0xf1f1f1f1, hook->callback, env->uc, pc_start, hook->user_data); - // the callback might want to stop emulation immediately - check_exit_request(tcg_ctx); - } + gen_uc_tracecode(tcg_ctx, 0xf1f1f1f1, UC_HOOK_CODE_IDX, env->uc, pc_start); + // the callback might want to stop emulation immediately + check_exit_request(tcg_ctx); } prefixes = 0; @@ -8173,7 +8167,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_helper_unlock(tcg_ctx, cpu_env); // Unicorn: patch the callback for the instruction size - if (hook) { + if (HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_CODE, pc_start)) { // int i; // for(i = 0; i < 20; i++) // printf("=== [%u] = %x\n", i, *(save_opparam_ptr + i)); @@ -8282,7 +8276,6 @@ static inline void gen_intermediate_code_internal(uint8_t *gen_opc_cc_op, int num_insns = 0; int max_insns; bool block_full = false; - struct hook *hook; /* generate intermediate code */ pc_start = tb->pc; @@ -8388,13 +8381,9 @@ static inline void gen_intermediate_code_internal(uint8_t *gen_opc_cc_op, // Unicorn: trace this block on request // Only hook this block if it is not broken from previous translation due to // full translation cache - if (!env->uc->block_full) { - HOOK_FOREACH(env->uc, hook, UC_HOOK_BLOCK) { - if (! HOOK_BOUND_CHECK(hook, pc_start)) - continue; - env->uc->block_addr = pc_start; - gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, hook->callback, env->uc, pc_start, hook->user_data); - } + if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) { + env->uc->block_addr = pc_start; + gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start); } gen_tb_start(tcg_ctx); diff --git a/qemu/target-m68k/helper.h b/qemu/target-m68k/helper.h index 865cf95d..caaadb3a 100644 --- a/qemu/target-m68k/helper.h +++ b/qemu/target-m68k/helper.h @@ -1,4 +1,4 @@ -DEF_HELPER_5(uc_tracecode, void, i32, ptr, ptr, i64, ptr) +DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64) DEF_HELPER_1(bitrev, i32, i32) DEF_HELPER_1(ff1, i32, i32) diff --git a/qemu/target-m68k/translate.c b/qemu/target-m68k/translate.c index 0f685d8e..bf45a66a 100644 --- a/qemu/target-m68k/translate.c +++ b/qemu/target-m68k/translate.c @@ -3031,7 +3031,6 @@ static void disas_m68k_insn(CPUM68KState * env, DisasContext *s) { TCGContext *tcg_ctx = s->uc->tcg_ctx; uint16_t insn; - struct hook *hook; if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) { tcg_gen_debug_insn_start(tcg_ctx, s->pc); @@ -3044,10 +3043,8 @@ static void disas_m68k_insn(CPUM68KState * env, DisasContext *s) } // Unicorn: trace this instruction on request - HOOK_FOREACH(env->uc, hook, UC_HOOK_CODE) { - if (! HOOK_BOUND_CHECK(hook, s->pc)) - continue; - gen_uc_tracecode(tcg_ctx, 2, hook->callback, env->uc, s->pc, hook->user_data); + if (HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_CODE, s->pc)) { + gen_uc_tracecode(tcg_ctx, 2, UC_HOOK_CODE_IDX, env->uc, s->pc); // the callback might want to stop emulation immediately check_exit_request(tcg_ctx); } @@ -3075,7 +3072,6 @@ gen_intermediate_code_internal(M68kCPU *cpu, TranslationBlock *tb, int max_insns; TCGContext *tcg_ctx = env->uc->tcg_ctx; bool block_full = false; - struct hook *hook; /* generate intermediate code */ pc_start = tb->pc; @@ -3110,14 +3106,10 @@ gen_intermediate_code_internal(M68kCPU *cpu, TranslationBlock *tb, // Unicorn: trace this block on request // Only hook this block if it is not broken from previous translation due to // full translation cache - if (!env->uc->block_full) { - HOOK_FOREACH(env->uc, hook, UC_HOOK_BLOCK) { - if (! HOOK_BOUND_CHECK(hook, pc_start)) - continue; - // save block address to see if we need to patch block size later - env->uc->block_addr = pc_start; - gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, hook->callback, env->uc, pc_start, hook->user_data); - } + if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) { + // save block address to see if we need to patch block size later + env->uc->block_addr = pc_start; + gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start); } gen_tb_start(tcg_ctx); diff --git a/qemu/target-mips/helper.h b/qemu/target-mips/helper.h index 81f733c2..1924bf6f 100644 --- a/qemu/target-mips/helper.h +++ b/qemu/target-mips/helper.h @@ -1,4 +1,4 @@ -DEF_HELPER_5(uc_tracecode, void, i32, ptr, ptr, i64, ptr) +DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64) DEF_HELPER_3(raise_exception_err, noreturn, env, i32, int) DEF_HELPER_2(raise_exception, noreturn, env, i32) diff --git a/qemu/target-mips/translate.c b/qemu/target-mips/translate.c index fadbaeb0..8802c221 100644 --- a/qemu/target-mips/translate.c +++ b/qemu/target-mips/translate.c @@ -11331,7 +11331,6 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, bool *insn_n int op, cnvt_op, op1, offset; int funct; int n_bytes; - struct hook *hook; op = (ctx->opcode >> 11) & 0x1f; sa = (ctx->opcode >> 2) & 0x7; @@ -11344,10 +11343,8 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, bool *insn_n n_bytes = 2; // Unicorn: trace this instruction on request - HOOK_FOREACH(env->uc, hook, UC_HOOK_CODE) { - if (! HOOK_BOUND_CHECK(hook, ctx->pc)) - continue; - gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, hook->callback, env->uc, ctx->pc, hook->user_data); + if (HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_CODE, ctx->pc)) { + gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_CODE_IDX, env->uc, ctx->pc); *insn_need_patch = true; // the callback might want to stop emulation immediately check_exit_request(tcg_ctx); @@ -13932,7 +13929,6 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, bool *ins TCGContext *tcg_ctx = env->uc->tcg_ctx; TCGv **cpu_gpr = (TCGv **)tcg_ctx->cpu_gpr; uint32_t op; - struct hook *hook; /* make sure instructions are on a halfword boundary */ if (ctx->pc & 0x1) { @@ -13943,10 +13939,8 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, bool *ins } // Unicorn: trace this instruction on request - HOOK_FOREACH(env->uc, hook, UC_HOOK_CODE) { - if (! HOOK_BOUND_CHECK(hook, ctx->pc)) - continue; - gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, hook->callback, env->uc, ctx->pc, hook->user_data); + if (HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_CODE, ctx->pc)) { + gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_CODE_IDX, env->uc, ctx->pc); *insn_need_patch = true; // the callback might want to stop emulation immediately check_exit_request(tcg_ctx); @@ -18505,11 +18499,8 @@ static void gen_msa(CPUMIPSState *env, DisasContext *ctx) static void hook_insn(CPUMIPSState *env, DisasContext *ctx, bool *insn_need_patch, int *insn_patch_offset, int offset_value) { TCGContext *tcg_ctx = ctx->uc->tcg_ctx; - struct hook *hook; - HOOK_FOREACH(env->uc, hook, UC_HOOK_CODE) { - if (! HOOK_BOUND_CHECK(hook, ctx->pc)) - continue; - gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, hook->callback, env->uc, ctx->pc, hook->user_data); + if (HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_CODE, ctx->pc)) { + gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_CODE_IDX, env->uc, ctx->pc); *insn_need_patch = true; // the callback might want to stop emulation immediately check_exit_request(tcg_ctx); @@ -19178,7 +19169,6 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, TCGContext *tcg_ctx = env->uc->tcg_ctx; TCGArg *save_opparam_ptr = NULL; bool block_full = false; - struct hook *hook; if (search_pc) qemu_log("search pc %d\n", search_pc); @@ -19224,14 +19214,10 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, // Unicorn: trace this block on request // Only hook this block if it is not broken from previous translation due to // full translation cache - if (! env->uc->block_full) { - HOOK_FOREACH(env->uc, hook, UC_HOOK_BLOCK) { - if (! HOOK_BOUND_CHECK(hook, pc_start)) - continue; - // save block address to see if we need to patch block size later - env->uc->block_addr = pc_start; - gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, hook->callback, env->uc, pc_start, hook->user_data); - } + if (! env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) { + // save block address to see if we need to patch block size later + env->uc->block_addr = pc_start; + gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start); } gen_tb_start(tcg_ctx); diff --git a/qemu/target-sparc/helper.h b/qemu/target-sparc/helper.h index 2557dd08..503e1e5c 100644 --- a/qemu/target-sparc/helper.h +++ b/qemu/target-sparc/helper.h @@ -1,4 +1,4 @@ -DEF_HELPER_5(uc_tracecode, void, i32, ptr, ptr, i64, ptr) +DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64) DEF_HELPER_1(power_down, void, env) #ifndef TARGET_SPARC64 diff --git a/qemu/target-sparc/translate.c b/qemu/target-sparc/translate.c index 8caba2b7..a7f067cf 100644 --- a/qemu/target-sparc/translate.c +++ b/qemu/target-sparc/translate.c @@ -2625,7 +2625,6 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn, bool hook_ins TCGv_i32 cpu_src1_32, cpu_src2_32, cpu_dst_32; TCGv_i64 cpu_src1_64, cpu_src2_64, cpu_dst_64; target_long simm; - struct hook *hook; if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) { tcg_gen_debug_insn_start(tcg_ctx, dc->pc); @@ -2638,14 +2637,10 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn, bool hook_ins } // Unicorn: trace this instruction on request - if (hook_insn) { - HOOK_FOREACH(dc->uc, hook, UC_HOOK_CODE) { - if (! HOOK_BOUND_CHECK(hook, dc->pc)) - continue; - gen_uc_tracecode(tcg_ctx, 4, hook->callback, dc->uc, dc->pc, hook->user_data); - // the callback might want to stop emulation immediately - check_exit_request(tcg_ctx); - } + if (hook_insn && HOOK_EXISTS_BOUNDED(dc->uc, UC_HOOK_CODE, dc->pc)) { + gen_uc_tracecode(tcg_ctx, 4, UC_HOOK_CODE_IDX, dc->uc, dc->pc); + // the callback might want to stop emulation immediately + check_exit_request(tcg_ctx); } opc = GET_FIELD(insn, 0, 1); @@ -5390,7 +5385,6 @@ static inline void gen_intermediate_code_internal(SPARCCPU *cpu, unsigned int insn; TCGContext *tcg_ctx = env->uc->tcg_ctx; bool block_full = false; - struct hook *hook; memset(dc, 0, sizeof(DisasContext)); dc->uc = env->uc; @@ -5431,14 +5425,10 @@ static inline void gen_intermediate_code_internal(SPARCCPU *cpu, // Unicorn: trace this block on request // Only hook this block if it is not broken from previous translation due to // full translation cache - if (!env->uc->block_full) { - HOOK_FOREACH(env->uc, hook, UC_HOOK_BLOCK) { - if (! HOOK_BOUND_CHECK(hook, pc_start)) - continue; - // save block address to see if we need to patch block size later - env->uc->block_addr = pc_start; - gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, hook->callback, env->uc, pc_start, hook->user_data); - } + if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) { + // save block address to see if we need to patch block size later + env->uc->block_addr = pc_start; + gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start); } gen_tb_start(tcg_ctx); diff --git a/qemu/tcg/tcg-op.h b/qemu/tcg/tcg-op.h index 9f096a3d..87358240 100644 --- a/qemu/tcg/tcg-op.h +++ b/qemu/tcg/tcg-op.h @@ -27,14 +27,13 @@ int gen_new_label(TCGContext *); -static inline void gen_uc_tracecode(TCGContext *tcg_ctx, int32_t size, void *callback, void *uc, uint64_t pc, void *data) +static inline void gen_uc_tracecode(TCGContext *tcg_ctx, int32_t size, int32_t type, void *uc, uint64_t pc) { TCGv_i32 tsize = tcg_const_i32(tcg_ctx, size); - TCGv_ptr tcallback = tcg_const_ptr(tcg_ctx, callback); + TCGv_i32 ttype = tcg_const_i32(tcg_ctx, type); TCGv_ptr tuc = tcg_const_ptr(tcg_ctx, uc); TCGv_i64 tpc = tcg_const_i64(tcg_ctx, pc); - TCGv_ptr tdata = tcg_const_ptr(tcg_ctx, data); - gen_helper_uc_tracecode(tcg_ctx, tsize, tcallback, tuc, tpc, tdata); + gen_helper_uc_tracecode(tcg_ctx, tsize, ttype, tuc, tpc); } static inline void tcg_gen_op0(TCGContext *s, TCGOpcode opc) diff --git a/qemu/translate-all.c b/qemu/translate-all.c index 72e1b60f..aec38c7c 100644 --- a/qemu/translate-all.c +++ b/qemu/translate-all.c @@ -179,7 +179,7 @@ static int cpu_gen_code(CPUArchState *env, TranslationBlock *tb, int *gen_code_s gen_intermediate_code(env, tb); // Unicorn: when tracing block, patch 1st operand for block size - if (HOOK_EXISTS(env->uc, UC_HOOK_BLOCK) && env->uc->block_addr == tb->pc) { + if (env->uc->block_addr == tb->pc && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, tb->pc)) { if (env->uc->block_full) // block size is unknown *(s->gen_opparam_buf + 1) = 0; else diff --git a/uc.c b/uc.c index f7f40853..b0f8a976 100644 --- a/uc.c +++ b/uc.c @@ -1009,17 +1009,23 @@ uc_err uc_hook_del(uc_engine *uc, uc_hook hh) } // TCG helper -void helper_uc_tracecode(int32_t size, void *callback, void *handle, int64_t address, void *user_data); -void helper_uc_tracecode(int32_t size, void *callback, void *handle, int64_t address, void *user_data) +void helper_uc_tracecode(int32_t size, uc_hook_type type, void *handle, int64_t address); +void helper_uc_tracecode(int32_t size, uc_hook_type type, void *handle, int64_t address) { struct uc_struct *uc = handle; + struct list_item *cur = uc->hook[type].head; + struct hook *hook; // sync PC in CPUArchState with address if (uc->set_pc) { uc->set_pc(uc, address); } - ((uc_cb_hookcode_t)callback)(uc, address, size, user_data); + while (cur != NULL && !uc->stop_request) { + hook = (struct hook *)cur->data; + ((uc_cb_hookcode_t)hook->callback)(uc, address, size, hook->user_data); + cur = cur->next; + } } UNICORN_EXPORT From 9f9bd7098baa30e83975a56d5cfc87b38f3a0bd1 Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Fri, 22 Jan 2016 19:24:45 -0800 Subject: [PATCH 020/126] patch hook bounds to be inclusive --- include/uc_priv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uc_priv.h b/include/uc_priv.h index a55c847e..902f9c47 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -101,7 +101,7 @@ enum uc_hook_idx { // if statement to check hook bounds #define HOOK_BOUND_CHECK(hh, addr) \ - ((((addr) >= (hh)->begin && (addr) < (hh)->end) \ + ((((addr) >= (hh)->begin && (addr) <= (hh)->end) \ || (hh)->begin > (hh)->end)) #define HOOK_EXISTS(uc, idx) ((uc)->hook[idx##_IDX].head != NULL) From 1974b23164b287505307a62acf046c3306ef7a5a Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Fri, 22 Jan 2016 19:55:31 -0800 Subject: [PATCH 021/126] add begin>end to samples/mem_apis --- samples/mem_apis.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/mem_apis.c b/samples/mem_apis.c index 50554eeb..bd0d81ba 100644 --- a/samples/mem_apis.c +++ b/samples/mem_apis.c @@ -170,7 +170,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_INVALID, - hook_mem_invalid, NULL) != UC_ERR_OK) { + hook_mem_invalid, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { printf("not ok - Failed to install hooks\n"); return; } @@ -251,7 +251,7 @@ static void do_perms_demo(bool change_perms) 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) { + hook_mem_invalid, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { printf("not ok - Failed to install hooks\n"); return; } @@ -329,7 +329,7 @@ static void do_unmap_demo(bool do_unmap) 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) { + hook_mem_invalid, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { printf("not ok - Failed to install hooks\n"); return; } From 9c2017e115caf4b417b6f27f3cc3299a4317bf7a Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 23 Jan 2016 17:08:40 +0800 Subject: [PATCH 022/126] update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4f82c74a..e0d13af9 100644 --- a/.gitignore +++ b/.gitignore @@ -134,6 +134,7 @@ test_mem_high rw_hookstack hook_extrainvoke sysenter_hook_x86 +test_tb_x86 ################# From 4dbad9aa9b97be57a2c1bd84cab48d3d9b683cb8 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 23 Jan 2016 17:14:44 +0800 Subject: [PATCH 023/126] add new API uc_query() to query internal status of emulator at runtime --- include/uc_priv.h | 3 +++ include/unicorn/unicorn.h | 18 ++++++++++++++++++ qemu/target-arm/unicorn_arm.c | 14 ++++++++++++++ uc.c | 12 ++++++++++++ 4 files changed, 47 insertions(+) diff --git a/include/uc_priv.h b/include/uc_priv.h index 589a655f..c4e0e176 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -32,6 +32,8 @@ typedef struct ModuleEntry { typedef QTAILQ_HEAD(, ModuleEntry) ModuleTypeList; +typedef uc_err (*query_t)(struct uc_struct *uc, uc_query_type type, size_t *result); + // return 0 on success, -1 on failure typedef int (*reg_read_t)(struct uc_struct *uc, unsigned int regid, void *value); typedef int (*reg_write_t)(struct uc_struct *uc, unsigned int regid, const void *value); @@ -93,6 +95,7 @@ struct uc_struct { struct CPUTailQ cpus; // qemu/cpu-exec.c uc_err errnum; // qemu/cpu-exec.c AddressSpace as; + query_t query; reg_read_t reg_read; reg_write_t reg_write; reg_reset_t reg_reset; diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index a6bedfaf..d5cd1422 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -255,6 +255,12 @@ typedef struct uc_mem_region { uint32_t perms; // memory permissions of the region } uc_mem_region; +// All type of queries for uc_query() API. +typedef enum uc_query_type { + // Query current hardware mode for ARM. Return 1 for Thumb, 0 for ARM + UC_QUERY_ARM_MODE = 1, +} uc_query_type; + /* Return combined API version & major and minor version numbers. @@ -315,6 +321,18 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **uc); UNICORN_EXPORT uc_err uc_close(uc_engine *uc); +/* + Query internal status of engine. + + @uc: handle returned by uc_open() + @type: query type + @result: status retrieved + + @return: error code of uc_err enum type (UC_ERR_*, see above) +*/ +UNICORN_EXPORT +uc_err uc_query(uc_engine *uc, uc_query_type type, size_t *result); + /* Report the last error number when some API function fail. Like glibc's errno, uc_errno might not retain its old value once accessed. diff --git a/qemu/target-arm/unicorn_arm.c b/qemu/target-arm/unicorn_arm.c index 5065c0f3..0a64d151 100644 --- a/qemu/target-arm/unicorn_arm.c +++ b/qemu/target-arm/unicorn_arm.c @@ -108,6 +108,19 @@ static bool arm_stop_interrupt(int intno) } } +static uc_err arm_query(struct uc_struct *uc, uc_query_type type, size_t *result) +{ + CPUState *mycpu = first_cpu; + + switch(type) { + case UC_QUERY_ARM_MODE: + *result = (ARM_CPU(uc, mycpu)->env.thumb != 0); + return UC_ERR_OK; + default: + return UC_ERR_ARG; + } +} + void arm_uc_init(struct uc_struct* uc) { register_accel_types(uc); @@ -118,5 +131,6 @@ void arm_uc_init(struct uc_struct* uc) uc->reg_reset = arm_reg_reset; uc->set_pc = arm_set_pc; uc->stop_interrupt = arm_stop_interrupt; + uc->query = arm_query; uc_common_init(uc); } diff --git a/uc.c b/uc.c index 95a9c48e..d93fa4e5 100644 --- a/uc.c +++ b/uc.c @@ -1190,3 +1190,15 @@ uint32_t uc_mem_regions(uc_engine *uc, uc_mem_region **regions, uint32_t *count) return UC_ERR_OK; } +UNICORN_EXPORT +uc_err uc_query(uc_engine *uc, uc_query_type type, size_t *result) +{ + switch(uc->arch) { + case UC_ARCH_ARM: + return uc->query(uc, type, result); + default: + return UC_ERR_ARG; + } + + return UC_ERR_OK; +} From 6f3d48077ef0c3cfa2c083ac0ad5f84706613442 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 24 Jan 2016 01:08:23 +0800 Subject: [PATCH 024/126] rename UC_QUERY_ARM_MODE to a more generic name UC_QUERY_MODE. make all bindings support this new constant --- bindings/dotnet/UnicornManaged/Const/Common.fs | 1 + bindings/go/unicorn/unicorn_const.go | 1 + bindings/java/unicorn/UnicornConst.java | 1 + bindings/python/unicorn/unicorn_const.py | 1 + include/unicorn/unicorn.h | 10 ++++++---- qemu/target-arm/unicorn_arm.c | 2 +- 6 files changed, 11 insertions(+), 5 deletions(-) diff --git a/bindings/dotnet/UnicornManaged/Const/Common.fs b/bindings/dotnet/UnicornManaged/Const/Common.fs index 3ec03c74..4dce96df 100644 --- a/bindings/dotnet/UnicornManaged/Const/Common.fs +++ b/bindings/dotnet/UnicornManaged/Const/Common.fs @@ -90,6 +90,7 @@ module Common = let UC_HOOK_MEM_WRITE_INVALID = 288 let UC_HOOK_MEM_FETCH_INVALID = 576 let UC_HOOK_MEM_INVALID = 1008 + let UC_QUERY_MODE = 1 let UC_PROT_NONE = 0 let UC_PROT_READ = 1 diff --git a/bindings/go/unicorn/unicorn_const.go b/bindings/go/unicorn/unicorn_const.go index 2d8d2c1a..8fb6d3f4 100644 --- a/bindings/go/unicorn/unicorn_const.go +++ b/bindings/go/unicorn/unicorn_const.go @@ -85,6 +85,7 @@ const ( HOOK_MEM_WRITE_INVALID = 288 HOOK_MEM_FETCH_INVALID = 576 HOOK_MEM_INVALID = 1008 + QUERY_MODE = 1 PROT_NONE = 0 PROT_READ = 1 diff --git a/bindings/java/unicorn/UnicornConst.java b/bindings/java/unicorn/UnicornConst.java index 5967d26b..7203fbd0 100644 --- a/bindings/java/unicorn/UnicornConst.java +++ b/bindings/java/unicorn/UnicornConst.java @@ -87,6 +87,7 @@ public interface UnicornConst { public static final int UC_HOOK_MEM_WRITE_INVALID = 288; public static final int UC_HOOK_MEM_FETCH_INVALID = 576; public static final int UC_HOOK_MEM_INVALID = 1008; + public static final int UC_QUERY_MODE = 1; public static final int UC_PROT_NONE = 0; public static final int UC_PROT_READ = 1; diff --git a/bindings/python/unicorn/unicorn_const.py b/bindings/python/unicorn/unicorn_const.py index a1967684..dd4c6d16 100644 --- a/bindings/python/unicorn/unicorn_const.py +++ b/bindings/python/unicorn/unicorn_const.py @@ -83,6 +83,7 @@ UC_HOOK_MEM_READ_INVALID = 144 UC_HOOK_MEM_WRITE_INVALID = 288 UC_HOOK_MEM_FETCH_INVALID = 576 UC_HOOK_MEM_INVALID = 1008 +UC_QUERY_MODE = 1 UC_PROT_NONE = 0 UC_PROT_READ = 1 diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index d5cd1422..6ecd6dc2 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -257,8 +257,9 @@ typedef struct uc_mem_region { // All type of queries for uc_query() API. typedef enum uc_query_type { - // Query current hardware mode for ARM. Return 1 for Thumb, 0 for ARM - UC_QUERY_ARM_MODE = 1, + // Dynamically query current hardware mode. + // For ARM, uc_query() return 1 for Thumb mode, and 0 for Arm mode + UC_QUERY_MODE = 1, } uc_query_type; /* @@ -325,8 +326,9 @@ uc_err uc_close(uc_engine *uc); Query internal status of engine. @uc: handle returned by uc_open() - @type: query type - @result: status retrieved + @type: query type. See uc_query_type + + @result: save the internal status queried @return: error code of uc_err enum type (UC_ERR_*, see above) */ diff --git a/qemu/target-arm/unicorn_arm.c b/qemu/target-arm/unicorn_arm.c index 0a64d151..15906deb 100644 --- a/qemu/target-arm/unicorn_arm.c +++ b/qemu/target-arm/unicorn_arm.c @@ -113,7 +113,7 @@ static uc_err arm_query(struct uc_struct *uc, uc_query_type type, size_t *result CPUState *mycpu = first_cpu; switch(type) { - case UC_QUERY_ARM_MODE: + case UC_QUERY_MODE: *result = (ARM_CPU(uc, mycpu)->env.thumb != 0); return UC_ERR_OK; default: From 26d3b1e7d6a1372cbaf72375b55d95bc41757816 Mon Sep 17 00:00:00 2001 From: xorstream Date: Sun, 24 Jan 2016 22:27:33 +1100 Subject: [PATCH 025/126] Added ppc 32bit mode and added sparc mode checks to bring it in line with other archs --- include/unicorn/unicorn.h | 1 + samples/sample_sparc.c | 2 +- tests/regress/sparc_jump_to_zero.c | 2 +- uc.c | 4 +++- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 6ecd6dc2..11772b9a 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -104,6 +104,7 @@ typedef enum uc_mode { UC_MODE_32 = 1 << 2, // 32-bit mode UC_MODE_64 = 1 << 3, // 64-bit mode // ppc + UC_MODE_PPC32 = 1 << 2, // 32-bit mode (currently unsupported) UC_MODE_PPC64 = 1 << 3, // 64-bit mode (currently unsupported) UC_MODE_QPX = 1 << 4, // Quad Processing eXtensions mode (currently unsupported) // sparc diff --git a/samples/sample_sparc.c b/samples/sample_sparc.c index 88bbd01e..e6276b14 100644 --- a/samples/sample_sparc.c +++ b/samples/sample_sparc.c @@ -57,7 +57,7 @@ static void test_sparc(void) printf("Emulate SPARC code\n"); // Initialize emulator in Sparc mode - err = uc_open(UC_ARCH_SPARC, UC_MODE_SPARC32, &uc); + err = uc_open(UC_ARCH_SPARC, UC_MODE_SPARC32|UC_MODE_BIG_ENDIAN, &uc); if (err) { printf("Failed on uc_open() with error returned: %u (%s)\n", err, uc_strerror(err)); diff --git a/tests/regress/sparc_jump_to_zero.c b/tests/regress/sparc_jump_to_zero.c index c816b700..2baaa69f 100644 --- a/tests/regress/sparc_jump_to_zero.c +++ b/tests/regress/sparc_jump_to_zero.c @@ -1,7 +1,7 @@ #include #define HARDWARE_ARCHITECTURE UC_ARCH_SPARC -#define HARDWARE_MODE UC_ARCH_SPARC32 +#define HARDWARE_MODE UC_ARCH_SPARC32|UC_MODE_BIG_ENDIAN #define MEMORY_STARTING_ADDRESS 0x1000000 #define MEMORY_SIZE 2 * 1024 * 1024 diff --git a/uc.c b/uc.c index d93fa4e5..1a419e8c 100644 --- a/uc.c +++ b/uc.c @@ -245,7 +245,9 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) #ifdef UNICORN_HAS_SPARC case UC_ARCH_SPARC: - if (mode & ~UC_MODE_SPARC_MASK) { + if ((mode & ~UC_MODE_SPARC_MASK) || + !(mode & UC_MODE_BIG_ENDIAN) || + !(mode & (UC_MODE_SPARC32|UC_MODE_SPARC64))) { free(uc); return UC_ERR_MODE; } From ec6d4d9ae016a884682f3fe31476a287d457782f Mon Sep 17 00:00:00 2001 From: xorstream Date: Sun, 24 Jan 2016 22:36:37 +1100 Subject: [PATCH 026/126] Removed unneeded arm mode check --- uc.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/uc.c b/uc.c index 1a419e8c..06c15f7e 100644 --- a/uc.c +++ b/uc.c @@ -506,14 +506,7 @@ uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t time break; case UC_ARCH_ARM: - switch(uc->mode) { - default: - break; - case UC_MODE_THUMB: - case UC_MODE_ARM: - uc_reg_write(uc, UC_ARM_REG_R15, &begin); - break; - } + uc_reg_write(uc, UC_ARM_REG_R15, &begin); break; case UC_ARCH_ARM64: From 9ec216357137e6d03532488d9b617784a6940b84 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 24 Jan 2016 20:50:26 +0800 Subject: [PATCH 027/126] bindings: add UC_MODE_PPC32 constant after recent update on unicorn.h --- bindings/dotnet/UnicornManaged/Const/Common.fs | 1 + bindings/go/unicorn/unicorn_const.go | 1 + bindings/java/unicorn/UnicornConst.java | 1 + bindings/python/unicorn/unicorn_const.py | 1 + 4 files changed, 4 insertions(+) diff --git a/bindings/dotnet/UnicornManaged/Const/Common.fs b/bindings/dotnet/UnicornManaged/Const/Common.fs index 4dce96df..5c5d5a2e 100644 --- a/bindings/dotnet/UnicornManaged/Const/Common.fs +++ b/bindings/dotnet/UnicornManaged/Const/Common.fs @@ -35,6 +35,7 @@ module Common = let UC_MODE_16 = 2 let UC_MODE_32 = 4 let UC_MODE_64 = 8 + let UC_MODE_PPC32 = 4 let UC_MODE_PPC64 = 8 let UC_MODE_QPX = 16 let UC_MODE_SPARC32 = 4 diff --git a/bindings/go/unicorn/unicorn_const.go b/bindings/go/unicorn/unicorn_const.go index 8fb6d3f4..ef08e0c5 100644 --- a/bindings/go/unicorn/unicorn_const.go +++ b/bindings/go/unicorn/unicorn_const.go @@ -30,6 +30,7 @@ const ( MODE_16 = 2 MODE_32 = 4 MODE_64 = 8 + MODE_PPC32 = 4 MODE_PPC64 = 8 MODE_QPX = 16 MODE_SPARC32 = 4 diff --git a/bindings/java/unicorn/UnicornConst.java b/bindings/java/unicorn/UnicornConst.java index 7203fbd0..d68a5f04 100644 --- a/bindings/java/unicorn/UnicornConst.java +++ b/bindings/java/unicorn/UnicornConst.java @@ -32,6 +32,7 @@ public interface UnicornConst { public static final int UC_MODE_16 = 2; public static final int UC_MODE_32 = 4; public static final int UC_MODE_64 = 8; + public static final int UC_MODE_PPC32 = 4; public static final int UC_MODE_PPC64 = 8; public static final int UC_MODE_QPX = 16; public static final int UC_MODE_SPARC32 = 4; diff --git a/bindings/python/unicorn/unicorn_const.py b/bindings/python/unicorn/unicorn_const.py index dd4c6d16..fa635b15 100644 --- a/bindings/python/unicorn/unicorn_const.py +++ b/bindings/python/unicorn/unicorn_const.py @@ -28,6 +28,7 @@ UC_MODE_MIPS64 = 8 UC_MODE_16 = 2 UC_MODE_32 = 4 UC_MODE_64 = 8 +UC_MODE_PPC32 = 4 UC_MODE_PPC64 = 8 UC_MODE_QPX = 16 UC_MODE_SPARC32 = 4 From 7973f6b4c9642ef86b54c1904b9d29c7091a615b Mon Sep 17 00:00:00 2001 From: xorstream Date: Mon, 25 Jan 2016 13:50:26 +1100 Subject: [PATCH 028/126] Added mode endian flags for sparc tests and fixed mode in sparc_jump_to_zero.c --- tests/regress/sparc64.py | 2 +- tests/regress/sparc_jump_to_zero.c | 2 +- tests/regress/sparc_reg.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/regress/sparc64.py b/tests/regress/sparc64.py index 12d3f547..34307639 100755 --- a/tests/regress/sparc64.py +++ b/tests/regress/sparc64.py @@ -5,7 +5,7 @@ from unicorn.sparc_const import * PAGE_SIZE = 1 * 1024 * 1024 -uc = Uc(UC_ARCH_SPARC, UC_MODE_SPARC64) +uc = Uc(UC_ARCH_SPARC, UC_MODE_SPARC64|UC_MODE_BIG_ENDIAN) uc.reg_write(UC_SPARC_REG_SP, 100) print 'writing sp = 100' diff --git a/tests/regress/sparc_jump_to_zero.c b/tests/regress/sparc_jump_to_zero.c index 2baaa69f..538405f3 100644 --- a/tests/regress/sparc_jump_to_zero.c +++ b/tests/regress/sparc_jump_to_zero.c @@ -1,7 +1,7 @@ #include #define HARDWARE_ARCHITECTURE UC_ARCH_SPARC -#define HARDWARE_MODE UC_ARCH_SPARC32|UC_MODE_BIG_ENDIAN +#define HARDWARE_MODE UC_MODE_SPARC32|UC_MODE_BIG_ENDIAN #define MEMORY_STARTING_ADDRESS 0x1000000 #define MEMORY_SIZE 2 * 1024 * 1024 diff --git a/tests/regress/sparc_reg.py b/tests/regress/sparc_reg.py index da6987d1..3d55065f 100755 --- a/tests/regress/sparc_reg.py +++ b/tests/regress/sparc_reg.py @@ -5,7 +5,7 @@ from unicorn.sparc_const import * PAGE_SIZE = 1 * 1024 * 1024 -uc = Uc(UC_ARCH_SPARC, UC_MODE_SPARC32) +uc = Uc(UC_ARCH_SPARC, UC_MODE_SPARC32|UC_MODE_BIG_ENDIAN) uc.reg_write(UC_SPARC_REG_SP, 100) uc.reg_write(UC_SPARC_REG_FP, 200) From a640b76b94e71613c40394d1ee9d87b2afdece34 Mon Sep 17 00:00:00 2001 From: Willi Ballenthin Date: Sun, 24 Jan 2016 22:46:13 -0500 Subject: [PATCH 029/126] qemu-thread-posix: bail on mutex errors partially addresses #400 --- qemu/util/qemu-thread-posix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qemu/util/qemu-thread-posix.c b/qemu/util/qemu-thread-posix.c index 26cba2da..6430f929 100644 --- a/qemu/util/qemu-thread-posix.c +++ b/qemu/util/qemu-thread-posix.c @@ -29,8 +29,8 @@ static void error_exit(int err, const char *msg) { - // fprintf(stderr, "qemu: %s: %s\n", msg, strerror(err)); - // abort(); + fprintf(stderr, "qemu: %s: %s\n", msg, strerror(err)); + abort(); } void qemu_mutex_init(QemuMutex *mutex) From bc0003188e51ccc84ddec2a9c62bd579304851ef Mon Sep 17 00:00:00 2001 From: xorstream Date: Mon, 25 Jan 2016 17:42:51 +1100 Subject: [PATCH 030/126] uc_mode fixes for bindings --- bindings/java/samples/Sample_mips.java | 2 +- bindings/java/samples/Sample_sparc.java | 2 +- bindings/python/sample_sparc.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bindings/java/samples/Sample_mips.java b/bindings/java/samples/Sample_mips.java index 58191acd..8220c42c 100644 --- a/bindings/java/samples/Sample_mips.java +++ b/bindings/java/samples/Sample_mips.java @@ -113,7 +113,7 @@ public class Sample_mips { System.out.print("Emulate MIPS code (little-endian)\n"); // Initialize emulator in MIPS mode - Unicorn u = new Unicorn(Unicorn.UC_ARCH_MIPS, Unicorn.UC_MODE_MIPS32); + Unicorn u = new Unicorn(Unicorn.UC_ARCH_MIPS, Unicorn.UC_MODE_MIPS32 + Unicorn.UC_MODE_LITTLE_ENDIAN); // map 2MB memory for this emulation u.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL); diff --git a/bindings/java/samples/Sample_sparc.java b/bindings/java/samples/Sample_sparc.java index 60298979..71ebdb3f 100644 --- a/bindings/java/samples/Sample_sparc.java +++ b/bindings/java/samples/Sample_sparc.java @@ -76,7 +76,7 @@ public class Sample_sparc { System.out.print("Emulate SPARC code\n"); // Initialize emulator in Sparc mode - Unicorn u = new Unicorn(Unicorn.UC_ARCH_SPARC, Unicorn.UC_MODE_32); + Unicorn u = new Unicorn(Unicorn.UC_ARCH_SPARC, Unicorn.UC_MODE_32 + Unicorn.UC_MODE_BIG_ENDIAN); // map 2MB memory for this emulation u.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL); diff --git a/bindings/python/sample_sparc.py b/bindings/python/sample_sparc.py index a8bdd586..ad47d387 100755 --- a/bindings/python/sample_sparc.py +++ b/bindings/python/sample_sparc.py @@ -28,7 +28,7 @@ def test_sparc(): print("Emulate SPARC code") try: # Initialize emulator in SPARC EB mode - mu = Uc(UC_ARCH_SPARC, UC_MODE_SPARC32) + mu = Uc(UC_ARCH_SPARC, UC_MODE_SPARC32|UC_MODE_BIG_ENDIAN) # map 2MB memory for this emulation mu.mem_map(ADDRESS, 2 * 1024 * 1024) From cee9a7d01111de7c70f2881656139576db021d67 Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Mon, 25 Jan 2016 03:51:35 -0800 Subject: [PATCH 031/126] fix missing HOOK_CODE bound check --- uc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/uc.c b/uc.c index b0f8a976..1d1ed539 100644 --- a/uc.c +++ b/uc.c @@ -1023,7 +1023,9 @@ void helper_uc_tracecode(int32_t size, uc_hook_type type, void *handle, int64_t while (cur != NULL && !uc->stop_request) { hook = (struct hook *)cur->data; - ((uc_cb_hookcode_t)hook->callback)(uc, address, size, hook->user_data); + if (HOOK_BOUND_CHECK(hook, address)) { + ((uc_cb_hookcode_t)hook->callback)(uc, address, size, hook->user_data); + } cur = cur->next; } } From 2341f5dd1aab8a0cdd20128b47535f07f16f613a Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 26 Jan 2016 17:37:48 +0800 Subject: [PATCH 032/126] code style --- qemu/softmmu_template.h | 34 ++++++++++++++++----------------- qemu/target-arm/translate-a64.c | 2 +- qemu/target-i386/seg_helper.c | 4 ++-- qemu/target-mips/translate.c | 2 +- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/qemu/softmmu_template.h b/qemu/softmmu_template.h index 1f636055..f58065b9 100644 --- a/qemu/softmmu_template.h +++ b/qemu/softmmu_template.h @@ -190,7 +190,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, #if defined(SOFTMMU_CODE_ACCESS) error_code = UC_ERR_FETCH_UNMAPPED; HOOK_FOREACH(uc, hook, UC_HOOK_MEM_FETCH_UNMAPPED) { - if (! HOOK_BOUND_CHECK(hook, addr)) + if (!HOOK_BOUND_CHECK(hook, addr)) continue; if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_UNMAPPED, addr, DATA_SIZE, 0, hook->user_data))) break; @@ -198,7 +198,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, #else error_code = UC_ERR_READ_UNMAPPED; HOOK_FOREACH(uc, hook, UC_HOOK_MEM_READ_UNMAPPED) { - if (! HOOK_BOUND_CHECK(hook, addr)) + if (!HOOK_BOUND_CHECK(hook, addr)) continue; if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_UNMAPPED, addr, DATA_SIZE, 0, hook->user_data))) break; @@ -221,7 +221,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { // non-executable handled = false; HOOK_FOREACH(uc, hook, UC_HOOK_MEM_FETCH_PROT) { - if (! HOOK_BOUND_CHECK(hook, addr)) + if (!HOOK_BOUND_CHECK(hook, addr)) continue; if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_PROT, addr, DATA_SIZE, 0, hook->user_data))) break; @@ -242,7 +242,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, // Unicorn: callback on memory read if (READ_ACCESS_TYPE == MMU_DATA_LOAD) { HOOK_FOREACH(uc, hook, UC_HOOK_MEM_READ) { - if (! HOOK_BOUND_CHECK(hook, addr)) + if (!HOOK_BOUND_CHECK(hook, addr)) continue; ((uc_cb_hookmem_t)hook->callback)(env->uc, UC_MEM_READ, addr, DATA_SIZE, 0, hook->user_data); } @@ -252,7 +252,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, if (READ_ACCESS_TYPE == MMU_DATA_LOAD && mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable handled = false; HOOK_FOREACH(uc, hook, UC_HOOK_MEM_READ_PROT) { - if (! HOOK_BOUND_CHECK(hook, addr)) + if (!HOOK_BOUND_CHECK(hook, addr)) continue; if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0, hook->user_data))) break; @@ -402,7 +402,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, #if defined(SOFTMMU_CODE_ACCESS) error_code = UC_ERR_FETCH_UNMAPPED; HOOK_FOREACH(uc, hook, UC_HOOK_MEM_FETCH_UNMAPPED) { - if (! HOOK_BOUND_CHECK(hook, addr)) + if (!HOOK_BOUND_CHECK(hook, addr)) continue; if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_UNMAPPED, addr, DATA_SIZE, 0, hook->user_data))) break; @@ -410,7 +410,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, #else error_code = UC_ERR_READ_UNMAPPED; HOOK_FOREACH(uc, hook, UC_HOOK_MEM_READ_UNMAPPED) { - if (! HOOK_BOUND_CHECK(hook, addr)) + if (!HOOK_BOUND_CHECK(hook, addr)) continue; if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_UNMAPPED, addr, DATA_SIZE, 0, hook->user_data))) break; @@ -433,7 +433,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { // non-executable handled = false; HOOK_FOREACH(uc, hook, UC_HOOK_MEM_FETCH_PROT) { - if (! HOOK_BOUND_CHECK(hook, addr)) + if (!HOOK_BOUND_CHECK(hook, addr)) continue; if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_PROT, addr, DATA_SIZE, 0, hook->user_data))) break; @@ -454,7 +454,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, // Unicorn: callback on memory read if (READ_ACCESS_TYPE == MMU_DATA_LOAD) { HOOK_FOREACH(uc, hook, UC_HOOK_MEM_READ) { - if (! HOOK_BOUND_CHECK(hook, addr)) + if (!HOOK_BOUND_CHECK(hook, addr)) continue; ((uc_cb_hookmem_t)hook->callback)(env->uc, UC_MEM_READ, addr, DATA_SIZE, 0, hook->user_data); } @@ -464,7 +464,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, if (READ_ACCESS_TYPE == MMU_DATA_LOAD && mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable handled = false; HOOK_FOREACH(uc, hook, UC_HOOK_MEM_READ_PROT) { - if (! HOOK_BOUND_CHECK(hook, addr)) + if (!HOOK_BOUND_CHECK(hook, addr)) continue; if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0, hook->user_data))) break; @@ -647,7 +647,7 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, // Unicorn: callback on memory write HOOK_FOREACH(uc, hook, UC_HOOK_MEM_WRITE) { - if (! HOOK_BOUND_CHECK(hook, addr)) + if (!HOOK_BOUND_CHECK(hook, addr)) continue; ((uc_cb_hookmem_t)hook->callback)(uc, UC_MEM_WRITE, addr, DATA_SIZE, val, hook->user_data); } @@ -656,13 +656,13 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, if (mr == NULL) { handled = false; HOOK_FOREACH(uc, hook, UC_HOOK_MEM_WRITE_UNMAPPED) { - if (! HOOK_BOUND_CHECK(hook, addr)) + if (!HOOK_BOUND_CHECK(hook, addr)) continue; if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_WRITE_UNMAPPED, addr, DATA_SIZE, val, hook->user_data))) break; } - if (! handled) { + if (!handled) { // save error & quit env->invalid_addr = addr; env->invalid_error = UC_ERR_WRITE_UNMAPPED; @@ -679,7 +679,7 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //non-writable handled = false; HOOK_FOREACH(uc, hook, UC_HOOK_MEM_WRITE_PROT) { - if (! HOOK_BOUND_CHECK(hook, addr)) + if (!HOOK_BOUND_CHECK(hook, addr)) continue; if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_WRITE_PROT, addr, DATA_SIZE, val, hook->user_data))) break; @@ -805,7 +805,7 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, // Unicorn: callback on memory write HOOK_FOREACH(uc, hook, UC_HOOK_MEM_WRITE) { - if (! HOOK_BOUND_CHECK(hook, addr)) + if (!HOOK_BOUND_CHECK(hook, addr)) continue; ((uc_cb_hookmem_t)hook->callback)(uc, UC_MEM_WRITE, addr, DATA_SIZE, val, hook->user_data); } @@ -814,7 +814,7 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, if (mr == NULL) { handled = false; HOOK_FOREACH(uc, hook, UC_HOOK_MEM_WRITE_UNMAPPED) { - if (! HOOK_BOUND_CHECK(hook, addr)) + if (!HOOK_BOUND_CHECK(hook, addr)) continue; if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_WRITE_UNMAPPED, addr, DATA_SIZE, val, hook->user_data))) break; @@ -837,7 +837,7 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //non-writable handled = false; HOOK_FOREACH(uc, hook, UC_HOOK_MEM_WRITE_PROT) { - if (! HOOK_BOUND_CHECK(hook, addr)) + if (!HOOK_BOUND_CHECK(hook, addr)) continue; if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_WRITE_PROT, addr, DATA_SIZE, val, hook->user_data))) break; diff --git a/qemu/target-arm/translate-a64.c b/qemu/target-arm/translate-a64.c index 06378453..e869da01 100644 --- a/qemu/target-arm/translate-a64.c +++ b/qemu/target-arm/translate-a64.c @@ -11112,7 +11112,7 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu, // Unicorn: trace this block on request // Only hook this block if it is not broken from previous translation due to // full translation cache - if (! env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) { + if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) { // save block address to see if we need to patch block size later env->uc->block_addr = pc_start; gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start); diff --git a/qemu/target-i386/seg_helper.c b/qemu/target-i386/seg_helper.c index 4cf6e41a..4702dfcc 100644 --- a/qemu/target-i386/seg_helper.c +++ b/qemu/target-i386/seg_helper.c @@ -948,7 +948,7 @@ void helper_syscall(CPUX86State *env, int next_eip_addend) // Unicorn: call registered syscall hooks struct hook *hook; HOOK_FOREACH(env->uc, hook, UC_HOOK_INSN) { - if (! HOOK_BOUND_CHECK(hook, env->eip)) + if (!HOOK_BOUND_CHECK(hook, env->eip)) continue; if (hook->insn == UC_X86_INS_SYSCALL) ((uc_cb_insn_syscall_t)hook->callback)(env->uc, hook->user_data); @@ -2308,7 +2308,7 @@ void helper_sysenter(CPUX86State *env, int next_eip_addend) // Unicorn: call registered SYSENTER hooks struct hook *hook; HOOK_FOREACH(env->uc, hook, UC_HOOK_INSN) { - if (! HOOK_BOUND_CHECK(hook, env->eip)) + if (!HOOK_BOUND_CHECK(hook, env->eip)) continue; if (hook->insn == UC_X86_INS_SYSENTER) ((uc_cb_insn_syscall_t)hook->callback)(env->uc, hook->user_data); diff --git a/qemu/target-mips/translate.c b/qemu/target-mips/translate.c index 8802c221..ea9aa453 100644 --- a/qemu/target-mips/translate.c +++ b/qemu/target-mips/translate.c @@ -19214,7 +19214,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, // Unicorn: trace this block on request // Only hook this block if it is not broken from previous translation due to // full translation cache - if (! env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) { + if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) { // save block address to see if we need to patch block size later env->uc->block_addr = pc_start; gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start); From 235bf0950b6ac6e75dee3c9094d1917eeb0181b2 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 26 Jan 2016 22:50:35 +0800 Subject: [PATCH 033/126] cosmetic change for mem_apis.c --- samples/mem_apis.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/samples/mem_apis.c b/samples/mem_apis.c index bd0d81ba..008f077d 100644 --- a/samples/mem_apis.c +++ b/samples/mem_apis.c @@ -142,13 +142,13 @@ static void do_nx_demo(bool cause_fault) /* bits 32 - page0: + page0: @0 times 4091 inc eax jmp page2 - page1: - times 4095 inc eax + page1: @1000 + times 4095 inc eax (or INC ECX) hlt - page2: + page2: @2000 jmp page1 */ memset(code_buf, 0x40, sizeof(code_buf)); // fill with inc eax From 876c423dd0d7db85db7e48be0955c09922245e4b Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 26 Jan 2016 23:12:35 +0800 Subject: [PATCH 034/126] python: support recent change on uc_hook_add() with begin/end params --- bindings/python/unicorn/unicorn.py | 39 +++++++++++++++--------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index 08be9632..9fd9a896 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -314,25 +314,7 @@ class Uc(object): self._callbacks[self._callback_count] = (callback, user_data) cb = None - if htype in (UC_HOOK_BLOCK, UC_HOOK_CODE): - begin = ctypes.c_uint64(arg1) - end = ctypes.c_uint64(arg2) - # set callback with wrapper, so it can be called - # with this object as param - 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_READ_UNMAPPED or htype & UC_HOOK_MEM_WRITE_UNMAPPED or \ - htype & UC_HOOK_MEM_FETCH_UNMAPPED 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 | 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)) - elif htype == UC_HOOK_INSN: + if htype == UC_HOOK_INSN: insn = ctypes.c_int(arg1) if arg1 == x86_const.UC_X86_INS_IN: # IN instruction cb = ctypes.cast(UC_HOOK_INSN_IN_CB(self._hook_insn_in_cb), UC_HOOK_INSN_IN_CB) @@ -346,6 +328,25 @@ class Uc(object): cb = ctypes.cast(UC_HOOK_INTR_CB(self._hook_intr_cb), UC_HOOK_INTR_CB) status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \ cb, ctypes.cast(self._callback_count, ctypes.c_void_p)) + else: + begin = ctypes.c_uint64(arg1) + end = ctypes.c_uint64(arg2) + if htype in (UC_HOOK_BLOCK, UC_HOOK_CODE): + # set callback with wrapper, so it can be called + # with this object as param + 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_READ_UNMAPPED or htype & UC_HOOK_MEM_WRITE_UNMAPPED or \ + htype & UC_HOOK_MEM_FETCH_UNMAPPED 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)) + else: + 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)) # save the ctype function so gc will leave it alone. self._ctype_cbs[self._callback_count] = cb From e750a4e97c4db33aa00866eb4875098b871ce4a8 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 28 Jan 2016 00:56:55 +0800 Subject: [PATCH 035/126] when uc_mem_exec() remove EXE permission, quit current TB & continue emulating with TB flushed. this fixes issue in PR #378 --- include/uc_priv.h | 1 + qemu/cpus.c | 8 +++++++- uc.c | 11 +++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/include/uc_priv.h b/include/uc_priv.h index 44c116ea..0ef5a3dd 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -215,6 +215,7 @@ struct uc_struct { bool init_tcg; // already initialized local TCGv variables? bool stop_request; // request to immediately stop emulation - for uc_emu_stop() + bool quit_request; // request to quit the current TB, but continue to emulate - for uc_mem_protect() bool emulation_done; // emulation is done by uc_emu_start() QemuThread timer; // timer for emulation timeout uint64_t timeout; // timeout for uc_emu_start() diff --git a/qemu/cpus.c b/qemu/cpus.c index 98ee07c1..64c73b0b 100644 --- a/qemu/cpus.c +++ b/qemu/cpus.c @@ -231,8 +231,14 @@ static bool tcg_exec_all(struct uc_struct* uc) //qemu_clock_enable(QEMU_CLOCK_VIRTUAL, // (cpu->singlestep_enabled & SSTEP_NOTIMER) == 0); if (cpu_can_run(cpu)) { + uc->quit_request = false; r = tcg_cpu_exec(uc, env); - if (uc->stop_request) { + + // quit current TB but continue emulating? + if (uc->quit_request) { + // reset stop_request + uc->stop_request = false; + } else if (uc->stop_request) { //printf(">>> got STOP request!!!\n"); finish = true; break; diff --git a/uc.c b/uc.c index e66b9f82..06b08fca 100644 --- a/uc.c +++ b/uc.c @@ -826,6 +826,7 @@ uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size, uint3 MemoryRegion *mr; uint64_t addr = address; size_t count, len; + bool remove_exec = false; if (size == 0) // trivial case, no change @@ -862,12 +863,22 @@ uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size, uint3 return UC_ERR_NOMEM; mr = memory_mapping(uc, addr); + // will this remove EXEC permission? + if (((mr->perms & UC_PROT_EXEC) != 0) && ((perms & UC_PROT_EXEC) == 0)) + remove_exec = true; mr->perms = perms; uc->readonly_mem(mr, (perms & UC_PROT_WRITE) == 0); count += len; addr += len; } + + // if EXEC permission is removed, then quit TB and continue at the same place + if (remove_exec) { + uc->quit_request = true; + uc_emu_stop(uc); + } + return UC_ERR_OK; } From 5a04bcb115052835c680a5466ef1cc475bfc2e4d Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 28 Jan 2016 14:06:17 +0800 Subject: [PATCH 036/126] allow to change PC during callback. this solves issue #210 --- .gitignore | 2 + qemu/cpu-exec.c | 2 + qemu/target-arm/unicorn_aarch64.c | 3 + qemu/target-arm/unicorn_arm.c | 3 + qemu/target-i386/unicorn.c | 15 +++++ qemu/target-m68k/unicorn.c | 3 + qemu/target-mips/unicorn.c | 3 + qemu/target-sparc/unicorn.c | 3 + tests/unit/Makefile | 4 +- tests/unit/test_pc_change.c | 104 ++++++++++++++++++++++++++++++ uc.c | 3 +- 11 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 tests/unit/test_pc_change.c diff --git a/.gitignore b/.gitignore index e0d13af9..d3ddf440 100644 --- a/.gitignore +++ b/.gitignore @@ -135,6 +135,8 @@ rw_hookstack hook_extrainvoke sysenter_hook_x86 test_tb_x86 +test_multihook +test_pc_change ################# diff --git a/qemu/cpu-exec.c b/qemu/cpu-exec.c index 33246009..6fd497bf 100644 --- a/qemu/cpu-exec.c +++ b/qemu/cpu-exec.c @@ -66,6 +66,7 @@ int cpu_exec(struct uc_struct *uc, CPUArchState *env) // qq uintptr_t next_tb; struct hook *hook; + /* This must be volatile so it is not trashed by longjmp() */ volatile bool have_tb_lock = false; @@ -100,6 +101,7 @@ int cpu_exec(struct uc_struct *uc, CPUArchState *env) // qq if (sigsetjmp(cpu->jmp_env, 0) == 0) { if (uc->stop_request || uc->invalid_error) break; + /* if an exception is pending, we execute it here */ if (cpu->exception_index >= 0) { //printf(">>> GOT INTERRUPT. exception idx = %x\n", cpu->exception_index); // qq diff --git a/qemu/target-arm/unicorn_aarch64.c b/qemu/target-arm/unicorn_aarch64.c index 0123b5cb..1ce9d6eb 100644 --- a/qemu/target-arm/unicorn_aarch64.c +++ b/qemu/target-arm/unicorn_aarch64.c @@ -82,6 +82,9 @@ int arm64_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) break; case UC_ARM64_REG_PC: ARM_CPU(uc, mycpu)->env.pc = *(uint64_t *)value; + // force to quit execution and flush TB + uc->quit_request = true; + uc_emu_stop(uc); break; case UC_ARM64_REG_SP: ARM_CPU(uc, mycpu)->env.xregs[31] = *(uint64_t *)value; diff --git a/qemu/target-arm/unicorn_arm.c b/qemu/target-arm/unicorn_arm.c index 15906deb..63f2c3f5 100644 --- a/qemu/target-arm/unicorn_arm.c +++ b/qemu/target-arm/unicorn_arm.c @@ -91,6 +91,9 @@ int arm_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) //case UC_ARM_REG_PC: case UC_ARM_REG_R15: ARM_CPU(uc, mycpu)->env.regs[15] = *(uint32_t *)value; + // force to quit execution and flush TB + uc->quit_request = true; + uc_emu_stop(uc); break; } } diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index 11bb8232..0af5763e 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -656,9 +656,15 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) break; case UC_X86_REG_EIP: X86_CPU(uc, mycpu)->env.eip = *(uint32_t *)value; + // force to quit execution and flush TB + uc->quit_request = true; + uc_emu_stop(uc); break; case UC_X86_REG_IP: WRITE_WORD(X86_CPU(uc, mycpu)->env.eip, *(uint16_t *)value); + // force to quit execution and flush TB + uc->quit_request = true; + uc_emu_stop(uc); break; case UC_X86_REG_CS: X86_CPU(uc, mycpu)->env.segs[R_CS].base = *(uint32_t *)value; @@ -806,12 +812,21 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) break; case UC_X86_REG_RIP: X86_CPU(uc, mycpu)->env.eip = *(uint64_t *)value; + // force to quit execution and flush TB + uc->quit_request = true; + uc_emu_stop(uc); break; case UC_X86_REG_EIP: WRITE_DWORD(X86_CPU(uc, mycpu)->env.eip, *(uint32_t *)value); + // force to quit execution and flush TB + uc->quit_request = true; + uc_emu_stop(uc); break; case UC_X86_REG_IP: WRITE_WORD(X86_CPU(uc, mycpu)->env.eip, *(uint16_t *)value); + // force to quit execution and flush TB + uc->quit_request = true; + uc_emu_stop(uc); break; case UC_X86_REG_CS: X86_CPU(uc, mycpu)->env.segs[R_CS].base = *(uint64_t *)value; diff --git a/qemu/target-m68k/unicorn.c b/qemu/target-m68k/unicorn.c index df732405..0055d4a1 100644 --- a/qemu/target-m68k/unicorn.c +++ b/qemu/target-m68k/unicorn.c @@ -70,6 +70,9 @@ int m68k_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) default: break; case UC_M68K_REG_PC: M68K_CPU(uc, mycpu)->env.pc = *(uint32_t *)value; + // force to quit execution and flush TB + uc->quit_request = true; + uc_emu_stop(uc); break; } } diff --git a/qemu/target-mips/unicorn.c b/qemu/target-mips/unicorn.c index 3885d02d..6af98dce 100644 --- a/qemu/target-mips/unicorn.c +++ b/qemu/target-mips/unicorn.c @@ -81,6 +81,9 @@ int mips_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) default: break; case UC_MIPS_REG_PC: MIPS_CPU(uc, mycpu)->env.active_tc.PC = *(uint32_t *)value; + // force to quit execution and flush TB + uc->quit_request = true; + uc_emu_stop(uc); break; } } diff --git a/qemu/target-sparc/unicorn.c b/qemu/target-sparc/unicorn.c index d86497b5..e612457b 100644 --- a/qemu/target-sparc/unicorn.c +++ b/qemu/target-sparc/unicorn.c @@ -87,6 +87,9 @@ int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) case UC_SPARC_REG_PC: SPARC_CPU(uc, mycpu)->env.pc = *(uint32_t *)value; SPARC_CPU(uc, mycpu)->env.npc = *(uint32_t *)value + 4; + // force to quit execution and flush TB + uc->quit_request = true; + uc_emu_stop(uc); break; } } diff --git a/tests/unit/Makefile b/tests/unit/Makefile index cd0e46eb..67376fd2 100644 --- a/tests/unit/Makefile +++ b/tests/unit/Makefile @@ -5,7 +5,7 @@ CFLAGS += -lcmocka -lunicorn CFLAGS += -I ../../include ALL_TESTS = test_sanity test_x86 test_mem_map test_mem_high test_mem_map_ptr \ - test_tb_x86 test_multihook + test_tb_x86 test_multihook test_pc_change .PHONY: all all: ${ALL_TESTS} @@ -24,6 +24,7 @@ test: ${ALL_TESTS} ./test_mem_high ./test_tb_x86 ./test_multihook + ./test_pc_change test_sanity: test_sanity.c test_x86: test_x86.c @@ -32,6 +33,7 @@ test_mem_map_ptr: test_mem_map_ptr.c test_mem_high: test_mem_high.c test_tb_x86: test_tb_x86.c test_multihook: test_multihook.c +test_pc_change: test_pc_change.c ${ALL_TESTS}: ${CC} ${CFLAGS} -o $@ $^ diff --git a/tests/unit/test_pc_change.c b/tests/unit/test_pc_change.c new file mode 100644 index 00000000..7994e772 --- /dev/null +++ b/tests/unit/test_pc_change.c @@ -0,0 +1,104 @@ +// Test PC change during the callback. by Nguyen Anh Quynh, 2016 +#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; +} + +/******************************************************************************/ + +static void test_code_hook(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + uint8_t tmp[256]; + int32_t r_eip = 0x1000006; + printf("instruction at 0x%"PRIx64": ", address); + + if (!uc_mem_read(uc, address, tmp, size)) { + uint32_t i; + + for (i = 0; i < size; i++) { + printf("0x%x ", tmp[i]); + } + printf("\n"); + } + + if (address == 0x1000003) { + // change the PC to "inc EDX" + uc_reg_write(uc, UC_X86_REG_EIP, &r_eip); + } +} + +static void test_pc_change(void **state) +{ + uc_engine *uc = *state; + uc_hook trace1; + int32_t r_ecx = 3, r_edx = 15; + +#define BASEADDR 0x1000000 + + uint64_t address = BASEADDR; + const uint8_t code[] = { + 0x41, // inc ECX @0x1000000 + 0x41, // inc ECX + 0x41, // inc ECX + 0x41, // inc ECX @0x1000003 + 0x41, // inc ECX + 0x41, // inc ECX + + 0x42, // inc EDX @0x1000006 + 0x42, // inc EDX + }; + +#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))); + + uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx); + uc_reg_write(uc, UC_X86_REG_EDX, &r_edx); + printf("ECX = %u, EDX = %u\n", r_ecx, r_edx); + + // trace all instructions + OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, test_code_hook, NULL, (uint64_t)1, (uint64_t)0)); + + OK(uc_emu_start(uc, address, address+sizeof(code), 0, 0)); + + uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx); + uc_reg_read(uc, UC_X86_REG_EDX, &r_edx); + + printf("ECX = %u, EDX = %u\n", r_ecx, r_edx); + assert_int_equal(r_ecx, 6); + assert_int_equal(r_edx, 17); +} + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_pc_change, setup32, teardown), + }; + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/uc.c b/uc.c index 06b08fca..ab466601 100644 --- a/uc.c +++ b/uc.c @@ -494,7 +494,6 @@ uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t time { // reset the counter uc->emu_counter = 0; - uc->stop_request = false; uc->invalid_error = UC_ERR_OK; uc->block_full = false; uc->emulation_done = false; @@ -542,6 +541,8 @@ uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t time break; } + uc->stop_request = false; + uc->emu_count = count; // remove count hook if counting isn't necessary if (count <= 0 && uc->count_hook != 0) { From c8569d8128ca2f90956576aa88a9fc7e574bedc6 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 28 Jan 2016 16:03:19 +0800 Subject: [PATCH 037/126] arm: fix change PC feature. now tests/regress/callback-pc.py passes --- qemu/cpu-exec.c | 6 ++++-- qemu/target-arm/unicorn_arm.c | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/qemu/cpu-exec.c b/qemu/cpu-exec.c index 6fd497bf..b9eb9067 100644 --- a/qemu/cpu-exec.c +++ b/qemu/cpu-exec.c @@ -236,6 +236,7 @@ int cpu_exec(struct uc_struct *uc, CPUArchState *env) // qq tc_ptr = tb->tc_ptr; /* execute the generated code */ next_tb = cpu_tb_exec(cpu, tc_ptr); // qq + switch (next_tb & TB_EXIT_MASK) { case TB_EXIT_REQUESTED: /* Something asked us to stop executing @@ -302,12 +303,13 @@ static tcg_target_ulong cpu_tb_exec(CPUState *cpu, uint8_t *tb_ptr) TranslationBlock *tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK); if (cc->synchronize_from_tb) { // avoid sync twice when helper_uc_tracecode() already did this. - if (env->uc->emu_counter <= env->uc->emu_count && !env->uc->stop_request) + if (env->uc->emu_counter <= env->uc->emu_count && + !env->uc->stop_request && !env->uc->quit_request) cc->synchronize_from_tb(cpu, tb); } else { assert(cc->set_pc); // avoid sync twice when helper_uc_tracecode() already did this. - if (env->uc->emu_counter <= env->uc->emu_count) + if (env->uc->emu_counter <= env->uc->emu_count && !env->uc->quit_request) cc->set_pc(cpu, tb->pc); } } diff --git a/qemu/target-arm/unicorn_arm.c b/qemu/target-arm/unicorn_arm.c index 63f2c3f5..c8349806 100644 --- a/qemu/target-arm/unicorn_arm.c +++ b/qemu/target-arm/unicorn_arm.c @@ -90,10 +90,12 @@ int arm_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) break; //case UC_ARM_REG_PC: case UC_ARM_REG_R15: + ARM_CPU(uc, mycpu)->env.pc = *(uint32_t *)value; ARM_CPU(uc, mycpu)->env.regs[15] = *(uint32_t *)value; // force to quit execution and flush TB uc->quit_request = true; uc_emu_stop(uc); + break; } } From 1fb5416f4ae63b9a367bd7c201da5dda741de22a Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 31 Jan 2016 13:06:42 +0800 Subject: [PATCH 038/126] unit: simplify test_tb_x86.c --- tests/unit/test_tb_x86.c | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/tests/unit/test_tb_x86.c b/tests/unit/test_tb_x86.c index 3abbd16e..f28d7617 100644 --- a/tests/unit/test_tb_x86.c +++ b/tests/unit/test_tb_x86.c @@ -206,8 +206,8 @@ static void hook_mem32(uc_engine *uc, //uint32_t tmp[1]; ctype = '?'; - if (type == 16) ctype = 'R'; - if (type == 17) ctype = 'W'; + if (type == UC_MEM_READ) ctype = 'R'; + if (type == UC_MEM_WRITE) ctype = 'W'; printf("hook_mem32(%c): Address: 0x%"PRIx64", Size: %d, Value:0x%"PRIx64"\n", ctype, address, size, value); // if (!uc_mem_read(uc, 0x6000003a, tmp, 4)) @@ -221,7 +221,7 @@ static void hook_mem32(uc_engine *uc, static void test_tb_x86_64_32_imul_Gv_Ev_Ib(void **state) { uc_engine *uc = *state; - uc_hook trace1, trace2, trace3, trace4; + uc_hook trace1, trace2; void *mem; #ifdef RIP_NEXT_TO_THE_SELFMODIFY_OPCODE // These values assumes just before PC = 0x60000021 @@ -278,23 +278,7 @@ static void test_tb_x86_64_32_imul_Gv_Ev_Ib(void **state) uc_assert_success(uc_hook_add(uc, &trace2, - UC_HOOK_MEM_READ, - hook_mem32, - NULL, - (uint64_t)1, - (uint64_t)0)); - - uc_assert_success(uc_hook_add(uc, - &trace3, - UC_HOOK_MEM_WRITE, - hook_mem32, - NULL, - (uint64_t)1, - (uint64_t)0)); - - uc_assert_success(uc_hook_add(uc, - &trace4, - UC_HOOK_MEM_FETCH, + UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE | UC_HOOK_MEM_FETCH, hook_mem32, NULL, (uint64_t)1, From a2ef52172c512dfbbdf0cde9316bbf33a56b9cb2 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 31 Jan 2016 13:12:34 +0800 Subject: [PATCH 039/126] add combination hook type UC_HOOK_MEM_VALID to intercept all valid memory access --- bindings/dotnet/UnicornManaged/Const/Common.fs | 1 + bindings/go/unicorn/unicorn_const.go | 1 + bindings/java/unicorn/UnicornConst.java | 1 + bindings/python/unicorn/unicorn_const.py | 1 + include/unicorn/unicorn.h | 2 ++ 5 files changed, 6 insertions(+) diff --git a/bindings/dotnet/UnicornManaged/Const/Common.fs b/bindings/dotnet/UnicornManaged/Const/Common.fs index 5c5d5a2e..6f106a3e 100644 --- a/bindings/dotnet/UnicornManaged/Const/Common.fs +++ b/bindings/dotnet/UnicornManaged/Const/Common.fs @@ -91,6 +91,7 @@ module Common = let UC_HOOK_MEM_WRITE_INVALID = 288 let UC_HOOK_MEM_FETCH_INVALID = 576 let UC_HOOK_MEM_INVALID = 1008 + let UC_HOOK_MEM_VALID = 7168 let UC_QUERY_MODE = 1 let UC_PROT_NONE = 0 diff --git a/bindings/go/unicorn/unicorn_const.go b/bindings/go/unicorn/unicorn_const.go index ef08e0c5..8d634be9 100644 --- a/bindings/go/unicorn/unicorn_const.go +++ b/bindings/go/unicorn/unicorn_const.go @@ -86,6 +86,7 @@ const ( HOOK_MEM_WRITE_INVALID = 288 HOOK_MEM_FETCH_INVALID = 576 HOOK_MEM_INVALID = 1008 + HOOK_MEM_VALID = 7168 QUERY_MODE = 1 PROT_NONE = 0 diff --git a/bindings/java/unicorn/UnicornConst.java b/bindings/java/unicorn/UnicornConst.java index d68a5f04..0fe4f193 100644 --- a/bindings/java/unicorn/UnicornConst.java +++ b/bindings/java/unicorn/UnicornConst.java @@ -88,6 +88,7 @@ public interface UnicornConst { public static final int UC_HOOK_MEM_WRITE_INVALID = 288; public static final int UC_HOOK_MEM_FETCH_INVALID = 576; public static final int UC_HOOK_MEM_INVALID = 1008; + public static final int UC_HOOK_MEM_VALID = 7168; public static final int UC_QUERY_MODE = 1; public static final int UC_PROT_NONE = 0; diff --git a/bindings/python/unicorn/unicorn_const.py b/bindings/python/unicorn/unicorn_const.py index fa635b15..4e942ef5 100644 --- a/bindings/python/unicorn/unicorn_const.py +++ b/bindings/python/unicorn/unicorn_const.py @@ -84,6 +84,7 @@ UC_HOOK_MEM_READ_INVALID = 144 UC_HOOK_MEM_WRITE_INVALID = 288 UC_HOOK_MEM_FETCH_INVALID = 576 UC_HOOK_MEM_INVALID = 1008 +UC_HOOK_MEM_VALID = 7168 UC_QUERY_MODE = 1 UC_PROT_NONE = 0 diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 11772b9a..2a556841 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -218,6 +218,8 @@ typedef enum uc_hook_type { #define UC_HOOK_MEM_FETCH_INVALID (UC_HOOK_MEM_FETCH_PROT + UC_HOOK_MEM_FETCH_UNMAPPED) // hook type for all events of illegal memory access #define UC_HOOK_MEM_INVALID (UC_HOOK_MEM_UNMAPPED + UC_HOOK_MEM_PROT) +// hook type for all events of valid memory access +#define UC_HOOK_MEM_VALID (UC_HOOK_MEM_READ + UC_HOOK_MEM_WRITE + UC_HOOK_MEM_FETCH) /* Callback function for hooking memory (UC_MEM_READ, UC_MEM_WRITE & UC_MEM_FETCH) From 32b9deca04c2d0a98d3fb553abaa57aa97fa372c Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 31 Jan 2016 13:14:11 +0800 Subject: [PATCH 040/126] unit: use UC_HOOK_MEM_VALID for test_tb_x86.c --- tests/unit/test_tb_x86.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/test_tb_x86.c b/tests/unit/test_tb_x86.c index f28d7617..187e5a69 100644 --- a/tests/unit/test_tb_x86.c +++ b/tests/unit/test_tb_x86.c @@ -278,7 +278,7 @@ static void test_tb_x86_64_32_imul_Gv_Ev_Ib(void **state) uc_assert_success(uc_hook_add(uc, &trace2, - UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE | UC_HOOK_MEM_FETCH, + UC_HOOK_MEM_VALID, hook_mem32, NULL, (uint64_t)1, From e42aba760f47d1ab2deb7061f6212610d89d4890 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 31 Jan 2016 14:07:35 +0800 Subject: [PATCH 041/126] fix a typo in test_tb_x86.c --- tests/unit/test_tb_x86.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/test_tb_x86.c b/tests/unit/test_tb_x86.c index 187e5a69..bf691e8b 100644 --- a/tests/unit/test_tb_x86.c +++ b/tests/unit/test_tb_x86.c @@ -150,7 +150,7 @@ static void hook_code32(uc_engine *uc, printf("FAILED EAX register not having 0x5ffffff9\n"); exit(-1); } - printf("EAX = %8.8x\n", ecx); + printf("ECX = %8.8x\n", ecx); printf("%8.8x + 0x41 = %8.8x\n", 0x5ffffff9, 0x5ffffff9 + 0x41); From 44fa4e29e70743a98d67a800feed596f4909fd12 Mon Sep 17 00:00:00 2001 From: cforgeron Date: Sun, 31 Jan 2016 15:09:20 -0400 Subject: [PATCH 042/126] - Added detect for Python 2/3 so the correct iteritems()/iter is called. - Renamed 'id' variable use (which is a built-in) to my_id. - Small formatting changes to make it more PEP compliant. --- bindings/python/sample_network_auditing.py | 150 +++++++++++++-------- 1 file changed, 92 insertions(+), 58 deletions(-) diff --git a/bindings/python/sample_network_auditing.py b/bindings/python/sample_network_auditing.py index 66e575ce..ccd279cd 100755 --- a/bindings/python/sample_network_auditing.py +++ b/bindings/python/sample_network_auditing.py @@ -7,7 +7,14 @@ from unicorn import * from unicorn.x86_const import * import struct import uuid -import random + +# Python 2/3 Compat without installing six +DEAD_PYTHON = False +import sys + +if sys.version_info[0] < 3: + DEAD_PYTHON = True + print("Python 2.x is dead. Start thinking about migrating to 3.x. https://wiki.python.org/moin/Python2orPython3") SIZE_REG = 4 SOCKETCALL_MAX_ARGS = 3 @@ -51,10 +58,11 @@ X86_REVERSE_TCP_2 = b"\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x66\xb3\x01\x51\x6a\x # memory address where emulation starts ADDRESS = 0x1000000 + # supported classes class IdGenerator: def __init__(self): - self.__next_id = 3 # exclude sdtin, stdout, stderr + self.__next_id = 3 # exclude sdtin, stdout, stderr def next(self): next_id = self.__next_id @@ -63,6 +71,7 @@ class IdGenerator: return next_id + class LogChain: def __init__(self): self.__chains = {} @@ -72,11 +81,11 @@ class LogChain: self.__chains = {} self.__linking_fds = {} - def create_chain(self, id): - if not self.__chains.has_key(id): - self.__chains[id] = [] + def create_chain(self, my_id): + if not my_id in self.__chains: + self.__chains[my_id] = [] else: - print("LogChain: id %d existed" % id) + print("LogChain: id %d existed" % my_id) def add_log(self, id, msg): fd = self.get_original_fd(id) @@ -87,20 +96,25 @@ class LogChain: print("LogChain: id %d doesn't exist" % id) def link_fd(self, from_fd, to_fd): - if not self.__linking_fds.has_key(to_fd): + if not to_fd in self.__linking_fds: self.__linking_fds[to_fd] = [] self.__linking_fds[to_fd].append(from_fd) def get_original_fd(self, fd): - if self.__chains.has_key(fd): + if fd in self.__chains: return fd - for orig_fd, links in self.__linking_fds.iteritems(): - if fd in links: - return orig_fd + if DEAD_PYTHON: + for orig_fd, links in self.__linking_fds.iteritems(): + if fd in links: + return orig_fd + else: + for orig_fd, links in self.__linking_fds.items(): + if fd in links: + return orig_fd - return None + return None def print_report(self): print(""" @@ -108,10 +122,16 @@ class LogChain: | START REPORT | ---------------- """) - for id, logs in self.__chains.iteritems(): - print("---- START FD(%d) ----" % id) - print("\n".join(logs)) - print("---- END FD(%d) ----" % id) + if DEAD_PYTHON: + for my_id, logs in self.__chains.iteritems(): + print("---- START FD(%d) ----" % my_id) + print("\n".join(logs)) + print("---- END FD(%d) ----" % my_id) + else: + for my_id, logs in self.__chains.items(): + print("---- START FD(%d) ----" % my_id) + print("\n".join(logs)) + print("---- END FD(%d) ----" % my_id) print(""" -------------- @@ -119,10 +139,9 @@ class LogChain: -------------- """) + # end supported classes -id_gen = IdGenerator() -fd_chains = LogChain() # utilities def bin_to_ipv4(ip): @@ -132,6 +151,7 @@ def bin_to_ipv4(ip): (ip & 0xff00) >> 8, (ip & 0xff)) + def read_string(uc, addr): ret = "" @@ -140,36 +160,43 @@ def read_string(uc, addr): while c != 0x0: ret += chr(c) - c = uc.mem_read(addr+read_bytes, 1)[0] + c = uc.mem_read(addr + read_bytes, 1)[0] read_bytes += 1 return ret + def parse_sock_address(sock_addr): sin_family, = struct.unpack("HI", sock_addr[2:8]) + + if sin_family == 2: # AF_INET + port, host = struct.unpack(">HI", sock_addr[2:8]) return "%s:%d" % (bin_to_ipv4(host), port) - elif sin_family == 6: # AF_INET6 + elif sin_family == 6: # AF_INET6 return "" + def print_sockcall(msg): print(">>> SOCKCALL %s" % msg) + + # end utilities # callback for tracing instructions def hook_code(uc, address, size, user_data): - print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size)) + print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" % (address, size)) # read this instruction code from memory tmp = uc.mem_read(address, size) - print(">>> Instruction code at [0x%x] =" %(address), end="") + print(">>> Instruction code at [0x%x] =" % (address), end="") for i in tmp: - print(" %x" %i, end="") + print(" %x" % i, end="") print("") + # callback for tracing Linux interrupt def hook_intr(uc, intno, user_data): + global id_gen + # only handle Linux syscall if intno != 0x80: return @@ -182,17 +209,17 @@ def hook_intr(uc, intno, user_data): # print(">>> INTERRUPT %d" % eax) - if eax == 1: # sys_exit + if eax == 1: # sys_exit print(">>> SYS_EXIT") uc.emu_stop() - elif eax == 3: # sys_read + elif eax == 3: # sys_read fd = ebx buf = ecx count = edx dummy_content = str(uuid.uuid1())[:32] if len(dummy_content) > count: - dummy_content = dummy_content[:count] + dummy_content = dummy_content[:count] uc.mem_write(buf, dummy_content) @@ -200,7 +227,7 @@ def hook_intr(uc, intno, user_data): fd_chains.add_log(fd, msg) print(">>> %s" % msg) - elif eax == 4: # sys_write + elif eax == 4: # sys_write fd = ebx buf = ecx count = edx @@ -211,13 +238,13 @@ def hook_intr(uc, intno, user_data): print(">>> %s" % msg) fd_chains.add_log(fd, msg) - elif eax == 5: # sys_open + elif eax == 5: # sys_open filename_addr = ebx flags = ecx mode = edx filename = read_string(uc, filename_addr) - dummy_fd = id_gen.next() + dummy_fd = id_gen.next() uc.reg_write(UC_X86_REG_EAX, dummy_fd) msg = "open file (filename=%s flags=%d mode=%d) with fd(%d)" % (filename, flags, mode, dummy_fd) @@ -225,42 +252,42 @@ def hook_intr(uc, intno, user_data): fd_chains.create_chain(dummy_fd) fd_chains.add_log(dummy_fd, msg) print(">>> %s" % msg) - elif eax == 11: # sys_execv + elif eax == 11: # sys_execv # print(">>> ebx=0x%x, ecx=0x%x, edx=0x%x" % (ebx, ecx, edx)) filename = read_string(uc, ebx) print(">>> SYS_EXECV filename=%s" % filename) - elif eax == 63: # sys_dup2 + elif eax == 63: # sys_dup2 fd_chains.link_fd(ecx, ebx) print(">>> SYS_DUP2 oldfd=%d newfd=%d" % (ebx, ecx)) - elif eax == 102: # sys_socketcall + elif eax == 102: # sys_socketcall # ref: http://www.skyfree.org/linux/kernel_network/socket.html call = uc.reg_read(UC_X86_REG_EBX) args = uc.reg_read(UC_X86_REG_ECX) SOCKETCALL_NUM_ARGS = { - 1: 3, # sys_socket - 2: 3, # sys_bind - 3: 3, # sys_connect - 4: 2, # sys_listen - 5: 3, # sys_accept - 9: 4, # sys_send + 1: 3, # sys_socket + 2: 3, # sys_bind + 3: 3, # sys_connect + 4: 2, # sys_listen + 5: 3, # sys_accept + 9: 4, # sys_send 11: 4, # sys_receive - 13: 2 # sys_shutdown + 13: 2 # sys_shutdown } - buf = uc.mem_read(args, SOCKETCALL_NUM_ARGS[call]*SIZE_REG) - args = struct.unpack("<" + "I"*SOCKETCALL_NUM_ARGS[call], buf) + buf = uc.mem_read(args, SOCKETCALL_NUM_ARGS[call] * SIZE_REG) + args = struct.unpack("<" + "I" * SOCKETCALL_NUM_ARGS[call], buf) # int sys_socketcall(int call, unsigned long *args) - if call == 1: # sys_socket + if call == 1: # sys_socket # err = sys_socket(a0,a1,a[2]) # int sys_socket(int family, int type, int protocol) family = args[0] sock_type = args[1] protocol = args[2] - dummy_fd = id_gen.next() + dummy_fd = id_gen.next() uc.reg_write(UC_X86_REG_EAX, dummy_fd) if family == 2: # AF_INET @@ -269,10 +296,10 @@ def hook_intr(uc, intno, user_data): fd_chains.create_chain(dummy_fd) fd_chains.add_log(dummy_fd, msg) print_sockcall(msg) - elif family == 3: # AF_INET6 + elif family == 3: # AF_INET6 pass - elif call == 2: # sys_bind + elif call == 2: # sys_bind fd = args[0] umyaddr = args[1] addrlen = args[2] @@ -283,19 +310,19 @@ def hook_intr(uc, intno, user_data): fd_chains.add_log(fd, msg) print_sockcall(msg) - elif call == 3: # sys_connect + elif call == 3: # sys_connect # err = sys_connect(a0, (struct sockaddr *)a1, a[2]) # int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen) fd = args[0] uservaddr = args[1] addrlen = args[2] - sock_addr = uc.mem_read(uservaddr, addrlen) + sock_addr = uc.mem_read(uservaddr, addrlen) msg = "fd(%d) connect to %s" % (fd, parse_sock_address(sock_addr)) fd_chains.add_log(fd, msg) print_sockcall(msg) - elif call == 4: # sys_listen + elif call == 4: # sys_listen fd = args[0] backlog = args[1] @@ -303,7 +330,7 @@ def hook_intr(uc, intno, user_data): fd_chains.add_log(fd, msg) print_sockcall(msg) - elif call == 5: # sys_accept + elif call == 5: # sys_accept fd = args[0] upeer_sockaddr = args[1] upeer_addrlen = args[2] @@ -321,7 +348,7 @@ def hook_intr(uc, intno, user_data): fd_chains.add_log(fd, msg) print_sockcall(msg) - elif call == 9: # sys_send + elif call == 9: # sys_send fd = args[0] buff = args[1] length = args[2] @@ -332,7 +359,7 @@ def hook_intr(uc, intno, user_data): fd_chains.add_log(fd, msg) print_sockcall(msg) - elif call == 11: # sys_receive + elif call == 11: # sys_receive fd = args[0] ubuf = args[1] size = args[2] @@ -342,7 +369,7 @@ def hook_intr(uc, intno, user_data): fd_chains.add_log(fd, msg) print_sockcall(msg) - elif call == 13: # sys_shutdown + elif call == 13: # sys_shutdown fd = args[0] how = args[1] @@ -350,8 +377,11 @@ def hook_intr(uc, intno, user_data): fd_chains.add_log(fd, msg) print_sockcall(msg) + # Test X86 32 bit def test_i386(code): + global fd_chains + fd_chains.clean() print("Emulate i386 code") try: @@ -366,7 +396,7 @@ def test_i386(code): # initialize stack mu.reg_write(UC_X86_REG_ESP, ADDRESS + 0x200000) - + # tracing all instructions with customized callback # mu.hook_add(UC_HOOK_CODE, hook_code) @@ -384,9 +414,13 @@ def test_i386(code): fd_chains.print_report() + +# Globals +fd_chains = LogChain() +id_gen = IdGenerator() + if __name__ == '__main__': - test_i386(X86_SEND_ETCPASSWD) + test_i386(X86_SEND_ETCPASSWD) test_i386(X86_BIND_TCP) test_i386(X86_REVERSE_TCP) test_i386(X86_REVERSE_TCP_2) - From de224f1573357acc84cda6a1efbc9104c31210c3 Mon Sep 17 00:00:00 2001 From: cforgeron Date: Sun, 31 Jan 2016 17:01:14 -0400 Subject: [PATCH 043/126] - Switch to 'in' which works in 2/3 instead of legacy '.has_key()' - Renamed 'id' variable use (which is a built-in) to my_id. - Small formatting changes to make it more PEP compliant. --- bindings/python/sample_network_auditing.py | 34 +++++----------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/bindings/python/sample_network_auditing.py b/bindings/python/sample_network_auditing.py index ccd279cd..69a2d2d7 100755 --- a/bindings/python/sample_network_auditing.py +++ b/bindings/python/sample_network_auditing.py @@ -8,14 +8,6 @@ from unicorn.x86_const import * import struct import uuid -# Python 2/3 Compat without installing six -DEAD_PYTHON = False -import sys - -if sys.version_info[0] < 3: - DEAD_PYTHON = True - print("Python 2.x is dead. Start thinking about migrating to 3.x. https://wiki.python.org/moin/Python2orPython3") - SIZE_REG = 4 SOCKETCALL_MAX_ARGS = 3 @@ -105,14 +97,9 @@ class LogChain: if fd in self.__chains: return fd - if DEAD_PYTHON: - for orig_fd, links in self.__linking_fds.iteritems(): - if fd in links: - return orig_fd - else: - for orig_fd, links in self.__linking_fds.items(): - if fd in links: - return orig_fd + for orig_fd, links in self.__linking_fds.items(): + if fd in links: + return orig_fd return None @@ -122,16 +109,11 @@ class LogChain: | START REPORT | ---------------- """) - if DEAD_PYTHON: - for my_id, logs in self.__chains.iteritems(): - print("---- START FD(%d) ----" % my_id) - print("\n".join(logs)) - print("---- END FD(%d) ----" % my_id) - else: - for my_id, logs in self.__chains.items(): - print("---- START FD(%d) ----" % my_id) - print("\n".join(logs)) - print("---- END FD(%d) ----" % my_id) + + for my_id, logs in self.__chains.items(): + print("---- START FD(%d) ----" % my_id) + print("\n".join(logs)) + print("---- END FD(%d) ----" % my_id) print(""" -------------- From ac806d3bfb2ac1ea84440af4cf56876970eb0dc8 Mon Sep 17 00:00:00 2001 From: McLovi9 Date: Tue, 2 Feb 2016 20:36:36 +0100 Subject: [PATCH 044/126] Create arm_init_input_crash.py --- tests/regress/arm_init_input_crash.py | 109 ++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 tests/regress/arm_init_input_crash.py diff --git a/tests/regress/arm_init_input_crash.py b/tests/regress/arm_init_input_crash.py new file mode 100644 index 00000000..ecafbfd2 --- /dev/null +++ b/tests/regress/arm_init_input_crash.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python +# Sample code for ARM of Unicorn. Nguyen Anh Quynh +# Python sample ported by Loi Anh Tuan +# + + +from __future__ import print_function +from unicorn import * +from unicorn.arm_const import * + + +# code to be emulated +ARM_CODE = "\x37\x00\xa0\xe3\x03\x10\x42\xe0" # mov r0, #0x37; sub r1, r2, r3 +THUMB_CODE = "\x83\xb0" # sub sp, #0xc +# memory address where emulation starts +ADDRESS = 0xF0000000 + + +# 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)) + + +# callback for tracing instructions +def hook_code(uc, address, size, user_data): + print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size)) + + +# Test ARM +def test_arm(): + print("Emulate ARM code") + try: + # Initialize emulator in ARM mode + mu = Uc(UC_ARCH_ARM, UC_MODE_ARM) + + mem_size = 2 * (1024 * 1024) + mu.mem_map(ADDRESS, mem_size) + + stack_address = ADDRESS + mem_size + stack_size = stack_address # >>> here huge memory size + mu.mem_map(stack_address, stack_size) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, ARM_CODE) + + # initialize machine registers + mu.reg_write(UC_ARM_REG_R0, 0x1234) + mu.reg_write(UC_ARM_REG_R2, 0x6789) + mu.reg_write(UC_ARM_REG_R3, 0x3333) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, hook_block) + + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, hook_code) + + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + len(ARM_CODE)) + + # now print out some registers + print(">>> Emulation done. Below is the CPU context") + + r0 = mu.reg_read(UC_ARM_REG_R0) + r1 = mu.reg_read(UC_ARM_REG_R1) + print(">>> R0 = 0x%x" %r0) + print(">>> R1 = 0x%x" %r1) + + except UcError as e: + print("ERROR: %s" % e) + + +def test_thumb(): + print("Emulate THUMB code") + try: + # Initialize emulator in thumb mode + mu = Uc(UC_ARCH_ARM, UC_MODE_THUMB) + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, THUMB_CODE) + + # initialize machine registers + mu.reg_write(UC_ARM_REG_SP, 0x1234) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, hook_block) + + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, hook_code) + + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + len(THUMB_CODE)) + + # now print out some registers + print(">>> Emulation done. Below is the CPU context") + + sp = mu.reg_read(UC_ARM_REG_SP) + print(">>> SP = 0x%x" %sp) + + except UcError as e: + print("ERROR: %s" % e) + + +if __name__ == '__main__': + test_arm() + print("=" * 20) + test_thumb() From 101f14285ae94070b20bdb47204351dd8f19ddb4 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Wed, 3 Feb 2016 09:20:15 +0800 Subject: [PATCH 045/126] chmod +x arm_init_input_crash.py --- tests/regress/arm_init_input_crash.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 tests/regress/arm_init_input_crash.py diff --git a/tests/regress/arm_init_input_crash.py b/tests/regress/arm_init_input_crash.py old mode 100644 new mode 100755 From 9977054a15419fba5541c0d224ed08bd07b84ed0 Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Wed, 3 Feb 2016 09:22:29 -0800 Subject: [PATCH 046/126] add support for setting gdtr, idtr, ldtr, and tr programatically --- include/unicorn/x86.h | 3 + qemu/target-i386/unicorn.c | 144 ++++++++++++++++++++++++++++++++++ tests/unit/test_gdt_idt_x86.c | 137 ++++++++++++++++++++++++++++++++ 3 files changed, 284 insertions(+) create mode 100755 tests/unit/test_gdt_idt_x86.c diff --git a/include/unicorn/x86.h b/include/unicorn/x86.h index b279de58..7d18c96d 100644 --- a/include/unicorn/x86.h +++ b/include/unicorn/x86.h @@ -64,6 +64,9 @@ typedef enum uc_x86_reg { UC_X86_REG_R9D, UC_X86_REG_R10D, UC_X86_REG_R11D, UC_X86_REG_R12D, UC_X86_REG_R13D, UC_X86_REG_R14D, UC_X86_REG_R15D, UC_X86_REG_R8W, UC_X86_REG_R9W, UC_X86_REG_R10W, UC_X86_REG_R11W, UC_X86_REG_R12W, UC_X86_REG_R13W, UC_X86_REG_R14W, UC_X86_REG_R15W, + UC_X86_REG_IDTR_LIMIT, UC_X86_REG_IDTR_BASE, UC_X86_REG_GDTR_LIMIT, UC_X86_REG_GDTR_BASE, + UC_X86_REG_LDTR_SS, UC_X86_REG_LDTR_LIMIT, UC_X86_REG_LDTR_BASE, UC_X86_REG_LDTR_ATTR, + UC_X86_REG_TR_SS, UC_X86_REG_TR_LIMIT, UC_X86_REG_TR_BASE, UC_X86_REG_TR_ATTR, UC_X86_REG_ENDING // <-- mark the end of the list of registers } uc_x86_reg; diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index 0af5763e..ce495c36 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -277,6 +277,42 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) case UC_X86_REG_GS: *(int32_t *)value = X86_CPU(uc, mycpu)->env.segs[R_GS].base; break; + case UC_X86_REG_IDTR_LIMIT: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.idt.limit); + break; + case UC_X86_REG_IDTR_BASE: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.idt.base; + break; + case UC_X86_REG_GDTR_LIMIT: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.gdt.limit); + break; + case UC_X86_REG_GDTR_BASE: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.gdt.base; + break; + case UC_X86_REG_LDTR_SS: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.ldt.selector); + break; + case UC_X86_REG_LDTR_LIMIT: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.ldt.limit; + break; + case UC_X86_REG_LDTR_BASE: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.ldt.base; + break; + case UC_X86_REG_LDTR_ATTR: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.ldt.flags; + break; + case UC_X86_REG_TR_SS: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.tr.selector); + break; + case UC_X86_REG_TR_LIMIT: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.tr.limit; + break; + case UC_X86_REG_TR_BASE: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.tr.base; + break; + case UC_X86_REG_TR_ATTR: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.tr.flags; + break; } break; @@ -525,6 +561,42 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) case UC_X86_REG_R15B: *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[15]); break; + case UC_X86_REG_IDTR_LIMIT: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.idt.limit); + break; + case UC_X86_REG_IDTR_BASE: + *(int64_t *)value = X86_CPU(uc, mycpu)->env.idt.base; + break; + case UC_X86_REG_GDTR_LIMIT: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.gdt.limit); + break; + case UC_X86_REG_GDTR_BASE: + *(int64_t *)value = X86_CPU(uc, mycpu)->env.gdt.base; + break; + case UC_X86_REG_LDTR_SS: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.ldt.selector); + break; + case UC_X86_REG_LDTR_LIMIT: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.ldt.limit; + break; + case UC_X86_REG_LDTR_BASE: + *(int64_t *)value = X86_CPU(uc, mycpu)->env.ldt.base; + break; + case UC_X86_REG_LDTR_ATTR: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.ldt.flags; + break; + case UC_X86_REG_TR_SS: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.tr.selector); + break; + case UC_X86_REG_TR_LIMIT: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.tr.limit; + break; + case UC_X86_REG_TR_BASE: + *(int64_t *)value = X86_CPU(uc, mycpu)->env.tr.base; + break; + case UC_X86_REG_TR_ATTR: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.tr.flags; + break; } break; #endif @@ -684,6 +756,42 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) case UC_X86_REG_GS: X86_CPU(uc, mycpu)->env.segs[R_GS].base = *(uint32_t *)value; break; + case UC_X86_REG_IDTR_LIMIT: + WRITE_WORD(X86_CPU(uc, mycpu)->env.idt.limit, *(uint16_t *)value); + break; + case UC_X86_REG_IDTR_BASE: + X86_CPU(uc, mycpu)->env.idt.base = *(uint32_t *)value; + break; + case UC_X86_REG_GDTR_LIMIT: + WRITE_WORD(X86_CPU(uc, mycpu)->env.gdt.limit, *(uint16_t *)value); + break; + case UC_X86_REG_GDTR_BASE: + X86_CPU(uc, mycpu)->env.gdt.base = *(uint32_t *)value; + break; + case UC_X86_REG_LDTR_SS: + WRITE_WORD(X86_CPU(uc, mycpu)->env.ldt.selector, *(uint16_t *)value); + break; + case UC_X86_REG_LDTR_LIMIT: + X86_CPU(uc, mycpu)->env.ldt.limit = *(uint32_t *)value; + break; + case UC_X86_REG_LDTR_BASE: + X86_CPU(uc, mycpu)->env.ldt.base = *(uint32_t *)value; + break; + case UC_X86_REG_LDTR_ATTR: + X86_CPU(uc, mycpu)->env.ldt.flags = *(uint32_t *)value; + break; + case UC_X86_REG_TR_SS: + WRITE_WORD(X86_CPU(uc, mycpu)->env.tr.selector, *(uint16_t *)value); + break; + case UC_X86_REG_TR_LIMIT: + X86_CPU(uc, mycpu)->env.tr.limit = *(uint32_t *)value; + break; + case UC_X86_REG_TR_BASE: + X86_CPU(uc, mycpu)->env.tr.base = *(uint32_t *)value; + break; + case UC_X86_REG_TR_ATTR: + X86_CPU(uc, mycpu)->env.tr.flags = *(uint32_t *)value; + break; } break; @@ -942,6 +1050,42 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) case UC_X86_REG_R15B: WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[15], *(uint8_t *)value); break; + case UC_X86_REG_IDTR_LIMIT: + WRITE_WORD(X86_CPU(uc, mycpu)->env.idt.limit, *(uint16_t *)value); + break; + case UC_X86_REG_IDTR_BASE: + X86_CPU(uc, mycpu)->env.idt.base = *(uint64_t *)value; + break; + case UC_X86_REG_GDTR_LIMIT: + WRITE_WORD(X86_CPU(uc, mycpu)->env.gdt.limit, *(uint16_t *)value); + break; + case UC_X86_REG_GDTR_BASE: + X86_CPU(uc, mycpu)->env.gdt.base = *(uint64_t *)value; + break; + case UC_X86_REG_LDTR_SS: + WRITE_WORD(X86_CPU(uc, mycpu)->env.ldt.selector, *(uint16_t *)value); + break; + case UC_X86_REG_LDTR_LIMIT: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.ldt.limit, *(uint32_t *)value); + break; + case UC_X86_REG_LDTR_BASE: + X86_CPU(uc, mycpu)->env.ldt.base = *(uint64_t *)value; + break; + case UC_X86_REG_LDTR_ATTR: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.ldt.flags, *(uint32_t *)value); + break; + case UC_X86_REG_TR_SS: + WRITE_WORD(X86_CPU(uc, mycpu)->env.tr.selector, *(uint16_t *)value); + break; + case UC_X86_REG_TR_LIMIT: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.tr.limit, *(uint32_t *)value); + break; + case UC_X86_REG_TR_BASE: + X86_CPU(uc, mycpu)->env.tr.base = *(uint64_t *)value; + break; + case UC_X86_REG_TR_ATTR: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.tr.flags, *(uint32_t *)value); + break; } break; #endif diff --git a/tests/unit/test_gdt_idt_x86.c b/tests/unit/test_gdt_idt_x86.c new file mode 100755 index 00000000..03c66bb9 --- /dev/null +++ b/tests/unit/test_gdt_idt_x86.c @@ -0,0 +1,137 @@ +#include +#include +#include +#include +#include +#include + +/** + * Assert that err matches expect + */ +#define uc_assert_err(expect, err) \ +do { \ + uc_err __err = err; \ + if (__err != expect) { \ + fprintf(stderr, "%s", uc_strerror(__err)); \ + exit(1); \ + } \ +} 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) \ +do { \ + uc_err __err = err; \ + if (__err == UC_ERR_OK) { \ + fprintf(stderr, "%s", uc_strerror(__err)); \ + exit(1); \ + } \ +} while (0) + +#define OK(x) uc_assert_success(x) + +/******************************************************************************/ + +static void test_idt_gdt_i386(/*void **state*/) +{ + uc_engine *uc; + uc_err err; + uint8_t buf[6]; + + const uint8_t code[] = "\x0f\x01\x0c\x24\x0f\x01\x44\x24\x06"; // sidt [esp]; sgdt [esp+6] + const uint64_t address = 0x1000000; + + int r_esp = address + 0x1000 - 0x100; // initial esp + + int idt_base = 0x12345678; + int idt_limit = 0xabcd; + int gdt_base = 0x87654321; + int gdt_limit = 0xdcba; + + // Initialize emulator in X86-32bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); + uc_assert_success(err); + + // map 1 page memory for this emulation + err = uc_mem_map(uc, address, 0x1000, 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_ESP, &r_esp); + uc_assert_success(err); + err = uc_reg_write(uc, UC_X86_REG_IDTR_BASE, &idt_base); + uc_assert_success(err); + err = uc_reg_write(uc, UC_X86_REG_IDTR_LIMIT, &idt_limit); + uc_assert_success(err); + err = uc_reg_write(uc, UC_X86_REG_GDTR_BASE, &gdt_base); + uc_assert_success(err); + err = uc_reg_write(uc, UC_X86_REG_GDTR_LIMIT, &gdt_limit); + uc_assert_success(err); + + idt_base = 0; + idt_limit = 0; + gdt_base = 0; + gdt_limit = 0; + + // emulate machine code in infinite time + err = uc_emu_start(uc, address, address+sizeof(code)-1, 0, 0); + uc_assert_success(err); + + + uc_reg_read(uc, UC_X86_REG_IDTR_BASE, &idt_base); + assert(idt_base == 0x12345678); + + uc_reg_read(uc, UC_X86_REG_IDTR_LIMIT, &idt_limit); + assert(idt_limit == 0xabcd); + + uc_reg_read(uc, UC_X86_REG_GDTR_BASE, &gdt_base); + assert(gdt_base == 0x87654321); + + uc_reg_read(uc, UC_X86_REG_GDTR_LIMIT, &gdt_limit); + assert(gdt_limit == 0xdcba); + + // read from memory + err = uc_mem_read(uc, r_esp, buf, 6); + uc_assert_success(err); + + assert(memcmp(buf, "\xcd\xab\x78\x56\x34\x12", 6) == 0); + + // read from memory + err = uc_mem_read(uc, r_esp + 6, buf, 6); + uc_assert_success(err); + + assert(memcmp(buf, "\xba\xdc\x21\x43\x65\x87", 6) == 0); + + uc_close(uc); + +} + +/******************************************************************************/ + +int main(void) { +/* + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_idt_gdt_i386) + }; + return cmocka_run_group_tests(tests, NULL, NULL); +*/ + test_idt_gdt_i386(); + + fprintf(stderr, "success\n"); + + return 0; +} From 1e13777c914ca73b38eee365b11c127d26f9fe2e Mon Sep 17 00:00:00 2001 From: coco Date: Thu, 4 Feb 2016 19:57:20 +0100 Subject: [PATCH 047/126] added memory fuzzer and 2 resulting testcases --- tests/regress/Makefile | 1 + tests/regress/mem_fuzz.c | 119 ++++++++++++++++++++++++++++++++++++++ tests/unit/test_mem_map.c | 25 ++++++++ 3 files changed, 145 insertions(+) create mode 100644 tests/regress/mem_fuzz.c diff --git a/tests/regress/Makefile b/tests/regress/Makefile index 3de87998..6b8381a9 100644 --- a/tests/regress/Makefile +++ b/tests/regress/Makefile @@ -37,6 +37,7 @@ TESTS += mips_branch_likely_issue TESTS += hook_extrainvoke TESTS += sysenter_hook_x86 TESTS += emu_clear_errors +TESTS += mem_fuzz all: $(TESTS) diff --git a/tests/regress/mem_fuzz.c b/tests/regress/mem_fuzz.c new file mode 100644 index 00000000..a1e080cf --- /dev/null +++ b/tests/regress/mem_fuzz.c @@ -0,0 +1,119 @@ +#define __STDC_FORMAT_MACROS +#include +#include +#include +#include +#include +#include + +#include + + +uint64_t baseranges[] = {0,0,0,0}; +int step =0; + +uint64_t urnd(){ + uint64_t rnd = rand(); + rnd = rnd << 32; + rnd += rand(); + return rnd; +} +uint64_t get_addr(){ + uint64_t base = ((uint64_t)urnd())%4; + uint64_t addr= baseranges[base] + urnd()%(4096*10); + return addr; +} + +uint64_t get_aligned_addr(){ + uint64_t addr = get_addr(); + return addr - (addr % 4096); +} + +uint64_t get_len(){ + uint64_t len = (urnd() % (4096*5))+1; + return len; +} + +uint64_t get_aligned_len(){ + uint64_t len = get_len(); + len = len - (len %4096); + len = ((len == 0) ? 4096 : len); + return len; +} + +void perform_map_step(uc_engine *uc){ + uint64_t addr = get_aligned_addr(); + uint64_t len = get_aligned_len(); + printf("map(0x%lx,0x%lx); //%d\n", addr, len, step); + uc_mem_map(uc, addr, len, UC_PROT_READ | UC_PROT_WRITE); +} + +void perform_unmap_step(uc_engine *uc){ + uint64_t addr = get_aligned_addr(); + uint64_t len = get_aligned_len(); + printf("unmap(0x%lx,0x%lx); //%d\n", addr, len, step); + uc_mem_unmap(uc, addr, len); +} + +void perform_write_step(uc_engine *uc){ + char* buff[4096*4]; + memset(buff, 0, 4096*4); + uint64_t addr = get_addr(); + uint64_t len = get_len()%(4096*3); + printf("write(0x%lx,0x%lx); //%d\n", addr, len, step); + uc_mem_write(uc, addr, buff, len); +} + +void perform_read_step(uc_engine *uc){ + char* buff[4096*4]; + uint64_t addr = get_addr(); + uint64_t len = get_len()%(4096*3); + printf("read(0x%lx,0x%lx); //%d\n", addr, len, step); + uc_mem_read(uc, addr, buff, len); +} + +void perform_fuzz_step(uc_engine *uc){ + switch( ((uint32_t)rand())%2 ){ + case 0: perform_map_step(uc); break; + case 1: perform_unmap_step(uc); break; + //case 2: perform_read_step(uc); break; + //case 3: perform_write_step(uc); break; + } +} + +int main(int argc, char **argv, char **envp) +{ + uc_engine *uc; + uc_hook trace1, trace2; + uc_err err; + if(argc<2){ + printf("usage: mem_fuzz $seed\n"); + return 1; + } + int seed = atoi(argv[1]); + int i = 0; + + //don't really care about quality of randomness + srand(seed); + printf("running with seed %d\n",seed); + + // Initialize emulator in X86-32bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc); + if (err) { + printf("Failed on uc_open() with error returned: %u\n", err); + return 1; + } + + for(i = 0; i < 2048; i++){ + step++; + perform_fuzz_step(uc); + } + // fill in sections that shouldn't get touched + + if (uc_close(uc) != UC_ERR_OK) { + printf("Failed on uc_close\n"); + return 1; + } + + return 0; +} diff --git a/tests/unit/test_mem_map.c b/tests/unit/test_mem_map.c index 210d4790..6b743f0c 100644 --- a/tests/unit/test_mem_map.c +++ b/tests/unit/test_mem_map.c @@ -138,6 +138,29 @@ static void test_unmap_double_map(void **state) uc_assert_fail(uc_mem_map(uc, 0x0000, 0x1000, 0)); /* 0x1000 - 0x1000 */ } +static void test_overlap_unmap_double_map(void **state) +{ + uc_engine *uc = *state; + uc_mem_map( uc, 0x1000, 0x2000, 0); + uc_mem_map( uc, 0x1000, 0x1000, 0); + uc_mem_unmap(uc, 0x2000, 0x1000); +} + +static void test_strange_map(void **state) +{ + uc_engine *uc = *state; + uc_mem_map( uc, 0x0,0x3000,0); + uc_mem_unmap(uc, 0x1000,0x1000); + uc_mem_map( uc, 0x3000,0x1000,0); + uc_mem_map( uc, 0x4000,0x1000,0); + uc_mem_map( uc, 0x1000,0x1000,0); + uc_mem_map( uc, 0x5000,0x1000,0); + uc_mem_unmap(uc, 0x0,0x1000); +} + + + + int main(void) { #define test(x) cmocka_unit_test_setup_teardown(x, setup, teardown) const struct CMUnitTest tests[] = { @@ -147,6 +170,8 @@ int main(void) { test(test_bad_unmap), test(test_rw_across_boundaries), test(test_unmap_double_map), + test(test_overlap_unmap_double_map), + test(test_strange_map), }; #undef test return cmocka_run_group_tests(tests, NULL, NULL); From e59382e030aa14e62ebd3fd867889fffb5d64a07 Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Thu, 4 Feb 2016 16:44:52 -0800 Subject: [PATCH 048/126] updated gdtr/idtr/ldtr/tr read/write code --- include/unicorn/x86.h | 13 ++- qemu/target-i386/cpu.h | 2 +- qemu/target-i386/unicorn.c | 192 ++++++++++++---------------------- tests/unit/test_gdt_idt_x86.c | 68 ++++++++---- 4 files changed, 120 insertions(+), 155 deletions(-) mode change 100644 => 100755 include/unicorn/x86.h mode change 100644 => 100755 qemu/target-i386/cpu.h mode change 100644 => 100755 qemu/target-i386/unicorn.c diff --git a/include/unicorn/x86.h b/include/unicorn/x86.h old mode 100644 new mode 100755 index 7d18c96d..ab5a0481 --- a/include/unicorn/x86.h +++ b/include/unicorn/x86.h @@ -8,6 +8,15 @@ extern "C" { #endif +//Memory-Management Register fields (idtr, gdtr, ldtr, tr) +//borrow from SegmentCache in qemu/target-i386/cpu.h +typedef struct x86_mmr { + uint32_t selector; + uint64_t base; /* handle 32 or 64 bit CPUs */ + uint32_t limit; + uint32_t flags; +} x86_mmr; + // Callback function for tracing SYSCALL/SYSENTER (for uc_hook_intr()) // @user_data: user data passed to tracing APIs. typedef void (*uc_cb_insn_syscall_t)(struct uc_struct *uc, void *user_data); @@ -64,9 +73,7 @@ typedef enum uc_x86_reg { UC_X86_REG_R9D, UC_X86_REG_R10D, UC_X86_REG_R11D, UC_X86_REG_R12D, UC_X86_REG_R13D, UC_X86_REG_R14D, UC_X86_REG_R15D, UC_X86_REG_R8W, UC_X86_REG_R9W, UC_X86_REG_R10W, UC_X86_REG_R11W, UC_X86_REG_R12W, UC_X86_REG_R13W, UC_X86_REG_R14W, UC_X86_REG_R15W, - UC_X86_REG_IDTR_LIMIT, UC_X86_REG_IDTR_BASE, UC_X86_REG_GDTR_LIMIT, UC_X86_REG_GDTR_BASE, - UC_X86_REG_LDTR_SS, UC_X86_REG_LDTR_LIMIT, UC_X86_REG_LDTR_BASE, UC_X86_REG_LDTR_ATTR, - UC_X86_REG_TR_SS, UC_X86_REG_TR_LIMIT, UC_X86_REG_TR_BASE, UC_X86_REG_TR_ATTR, + UC_X86_REG_IDTR, UC_X86_REG_GDTR, UC_X86_REG_LDTR, UC_X86_REG_TR, UC_X86_REG_ENDING // <-- mark the end of the list of registers } uc_x86_reg; diff --git a/qemu/target-i386/cpu.h b/qemu/target-i386/cpu.h old mode 100644 new mode 100755 index 4628a8df..68f802f9 --- a/qemu/target-i386/cpu.h +++ b/qemu/target-i386/cpu.h @@ -699,7 +699,7 @@ typedef enum { typedef struct SegmentCache { uint32_t selector; - target_ulong base; + uint64_t base; /* handle 32 or 64 bit CPUs */ uint32_t limit; uint32_t flags; } SegmentCache; diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c old mode 100644 new mode 100755 index ce495c36..89ccdb6d --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -277,41 +277,25 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) case UC_X86_REG_GS: *(int32_t *)value = X86_CPU(uc, mycpu)->env.segs[R_GS].base; break; - case UC_X86_REG_IDTR_LIMIT: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.idt.limit); + case UC_X86_REG_IDTR: + ((SegmentCache *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.idt.limit; + ((SegmentCache *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.idt.base; break; - case UC_X86_REG_IDTR_BASE: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.idt.base; + case UC_X86_REG_GDTR: + ((SegmentCache *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.gdt.limit; + ((SegmentCache *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.gdt.base; break; - case UC_X86_REG_GDTR_LIMIT: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.gdt.limit); + case UC_X86_REG_LDTR: + ((SegmentCache *)value)->limit = X86_CPU(uc, mycpu)->env.ldt.limit; + ((SegmentCache *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.ldt.base; + ((SegmentCache *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.ldt.selector; + ((SegmentCache *)value)->flags = X86_CPU(uc, mycpu)->env.ldt.flags; break; - case UC_X86_REG_GDTR_BASE: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.gdt.base; - break; - case UC_X86_REG_LDTR_SS: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.ldt.selector); - break; - case UC_X86_REG_LDTR_LIMIT: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.ldt.limit; - break; - case UC_X86_REG_LDTR_BASE: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.ldt.base; - break; - case UC_X86_REG_LDTR_ATTR: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.ldt.flags; - break; - case UC_X86_REG_TR_SS: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.tr.selector); - break; - case UC_X86_REG_TR_LIMIT: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.tr.limit; - break; - case UC_X86_REG_TR_BASE: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.tr.base; - break; - case UC_X86_REG_TR_ATTR: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.tr.flags; + case UC_X86_REG_TR: + ((SegmentCache *)value)->limit = X86_CPU(uc, mycpu)->env.tr.limit; + ((SegmentCache *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.tr.base; + ((SegmentCache *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.tr.selector; + ((SegmentCache *)value)->flags = X86_CPU(uc, mycpu)->env.tr.flags; break; } break; @@ -561,41 +545,25 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) case UC_X86_REG_R15B: *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[15]); break; - case UC_X86_REG_IDTR_LIMIT: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.idt.limit); + case UC_X86_REG_IDTR: + ((SegmentCache *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.idt.limit; + ((SegmentCache *)value)->base = X86_CPU(uc, mycpu)->env.idt.base; break; - case UC_X86_REG_IDTR_BASE: - *(int64_t *)value = X86_CPU(uc, mycpu)->env.idt.base; + case UC_X86_REG_GDTR: + ((SegmentCache *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.gdt.limit; + ((SegmentCache *)value)->base = X86_CPU(uc, mycpu)->env.gdt.base; break; - case UC_X86_REG_GDTR_LIMIT: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.gdt.limit); + case UC_X86_REG_LDTR: + ((SegmentCache *)value)->limit = X86_CPU(uc, mycpu)->env.ldt.limit; + ((SegmentCache *)value)->base = X86_CPU(uc, mycpu)->env.ldt.base; + ((SegmentCache *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.ldt.selector; + ((SegmentCache *)value)->flags = X86_CPU(uc, mycpu)->env.ldt.flags; break; - case UC_X86_REG_GDTR_BASE: - *(int64_t *)value = X86_CPU(uc, mycpu)->env.gdt.base; - break; - case UC_X86_REG_LDTR_SS: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.ldt.selector); - break; - case UC_X86_REG_LDTR_LIMIT: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.ldt.limit; - break; - case UC_X86_REG_LDTR_BASE: - *(int64_t *)value = X86_CPU(uc, mycpu)->env.ldt.base; - break; - case UC_X86_REG_LDTR_ATTR: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.ldt.flags; - break; - case UC_X86_REG_TR_SS: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.tr.selector); - break; - case UC_X86_REG_TR_LIMIT: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.tr.limit; - break; - case UC_X86_REG_TR_BASE: - *(int64_t *)value = X86_CPU(uc, mycpu)->env.tr.base; - break; - case UC_X86_REG_TR_ATTR: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.tr.flags; + case UC_X86_REG_TR: + ((SegmentCache *)value)->limit = X86_CPU(uc, mycpu)->env.tr.limit; + ((SegmentCache *)value)->base = X86_CPU(uc, mycpu)->env.tr.base; + ((SegmentCache *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.tr.selector; + ((SegmentCache *)value)->flags = X86_CPU(uc, mycpu)->env.tr.flags; break; } break; @@ -756,41 +724,25 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) case UC_X86_REG_GS: X86_CPU(uc, mycpu)->env.segs[R_GS].base = *(uint32_t *)value; break; - case UC_X86_REG_IDTR_LIMIT: - WRITE_WORD(X86_CPU(uc, mycpu)->env.idt.limit, *(uint16_t *)value); + case UC_X86_REG_IDTR: + X86_CPU(uc, mycpu)->env.idt.limit = (uint16_t)((SegmentCache *)value)->limit; + X86_CPU(uc, mycpu)->env.idt.base = (uint32_t)((SegmentCache *)value)->base; break; - case UC_X86_REG_IDTR_BASE: - X86_CPU(uc, mycpu)->env.idt.base = *(uint32_t *)value; + case UC_X86_REG_GDTR: + X86_CPU(uc, mycpu)->env.gdt.limit = (uint16_t)((SegmentCache *)value)->limit; + X86_CPU(uc, mycpu)->env.gdt.base = (uint32_t)((SegmentCache *)value)->base; break; - case UC_X86_REG_GDTR_LIMIT: - WRITE_WORD(X86_CPU(uc, mycpu)->env.gdt.limit, *(uint16_t *)value); + case UC_X86_REG_LDTR: + X86_CPU(uc, mycpu)->env.ldt.limit = ((SegmentCache *)value)->limit; + X86_CPU(uc, mycpu)->env.ldt.base = (uint32_t)((SegmentCache *)value)->base; + X86_CPU(uc, mycpu)->env.ldt.selector = (uint16_t)((SegmentCache *)value)->selector; + X86_CPU(uc, mycpu)->env.ldt.flags = ((SegmentCache *)value)->flags; break; - case UC_X86_REG_GDTR_BASE: - X86_CPU(uc, mycpu)->env.gdt.base = *(uint32_t *)value; - break; - case UC_X86_REG_LDTR_SS: - WRITE_WORD(X86_CPU(uc, mycpu)->env.ldt.selector, *(uint16_t *)value); - break; - case UC_X86_REG_LDTR_LIMIT: - X86_CPU(uc, mycpu)->env.ldt.limit = *(uint32_t *)value; - break; - case UC_X86_REG_LDTR_BASE: - X86_CPU(uc, mycpu)->env.ldt.base = *(uint32_t *)value; - break; - case UC_X86_REG_LDTR_ATTR: - X86_CPU(uc, mycpu)->env.ldt.flags = *(uint32_t *)value; - break; - case UC_X86_REG_TR_SS: - WRITE_WORD(X86_CPU(uc, mycpu)->env.tr.selector, *(uint16_t *)value); - break; - case UC_X86_REG_TR_LIMIT: - X86_CPU(uc, mycpu)->env.tr.limit = *(uint32_t *)value; - break; - case UC_X86_REG_TR_BASE: - X86_CPU(uc, mycpu)->env.tr.base = *(uint32_t *)value; - break; - case UC_X86_REG_TR_ATTR: - X86_CPU(uc, mycpu)->env.tr.flags = *(uint32_t *)value; + case UC_X86_REG_TR: + X86_CPU(uc, mycpu)->env.tr.limit = ((SegmentCache *)value)->limit; + X86_CPU(uc, mycpu)->env.tr.base = (uint32_t)((SegmentCache *)value)->base; + X86_CPU(uc, mycpu)->env.tr.selector = (uint16_t)((SegmentCache *)value)->selector; + X86_CPU(uc, mycpu)->env.tr.flags = ((SegmentCache *)value)->flags; break; } break; @@ -1050,41 +1002,25 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) case UC_X86_REG_R15B: WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[15], *(uint8_t *)value); break; - case UC_X86_REG_IDTR_LIMIT: - WRITE_WORD(X86_CPU(uc, mycpu)->env.idt.limit, *(uint16_t *)value); + case UC_X86_REG_IDTR: + X86_CPU(uc, mycpu)->env.idt.limit = (uint16_t)((SegmentCache *)value)->limit; + X86_CPU(uc, mycpu)->env.idt.base = ((SegmentCache *)value)->base; break; - case UC_X86_REG_IDTR_BASE: - X86_CPU(uc, mycpu)->env.idt.base = *(uint64_t *)value; + case UC_X86_REG_GDTR: + X86_CPU(uc, mycpu)->env.gdt.limit = (uint16_t)((SegmentCache *)value)->limit; + X86_CPU(uc, mycpu)->env.gdt.base = ((SegmentCache *)value)->base; break; - case UC_X86_REG_GDTR_LIMIT: - WRITE_WORD(X86_CPU(uc, mycpu)->env.gdt.limit, *(uint16_t *)value); + case UC_X86_REG_LDTR: + X86_CPU(uc, mycpu)->env.ldt.limit = ((SegmentCache *)value)->limit; + X86_CPU(uc, mycpu)->env.ldt.base = ((SegmentCache *)value)->base; + X86_CPU(uc, mycpu)->env.ldt.selector = (uint16_t)((SegmentCache *)value)->selector; + X86_CPU(uc, mycpu)->env.ldt.flags = ((SegmentCache *)value)->flags; break; - case UC_X86_REG_GDTR_BASE: - X86_CPU(uc, mycpu)->env.gdt.base = *(uint64_t *)value; - break; - case UC_X86_REG_LDTR_SS: - WRITE_WORD(X86_CPU(uc, mycpu)->env.ldt.selector, *(uint16_t *)value); - break; - case UC_X86_REG_LDTR_LIMIT: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.ldt.limit, *(uint32_t *)value); - break; - case UC_X86_REG_LDTR_BASE: - X86_CPU(uc, mycpu)->env.ldt.base = *(uint64_t *)value; - break; - case UC_X86_REG_LDTR_ATTR: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.ldt.flags, *(uint32_t *)value); - break; - case UC_X86_REG_TR_SS: - WRITE_WORD(X86_CPU(uc, mycpu)->env.tr.selector, *(uint16_t *)value); - break; - case UC_X86_REG_TR_LIMIT: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.tr.limit, *(uint32_t *)value); - break; - case UC_X86_REG_TR_BASE: - X86_CPU(uc, mycpu)->env.tr.base = *(uint64_t *)value; - break; - case UC_X86_REG_TR_ATTR: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.tr.flags, *(uint32_t *)value); + case UC_X86_REG_TR: + X86_CPU(uc, mycpu)->env.tr.limit = ((SegmentCache *)value)->limit; + X86_CPU(uc, mycpu)->env.tr.base = ((SegmentCache *)value)->base; + X86_CPU(uc, mycpu)->env.tr.selector = (uint16_t)((SegmentCache *)value)->selector; + X86_CPU(uc, mycpu)->env.tr.flags = ((SegmentCache *)value)->flags; break; } break; diff --git a/tests/unit/test_gdt_idt_x86.c b/tests/unit/test_gdt_idt_x86.c index 03c66bb9..27183f0e 100755 --- a/tests/unit/test_gdt_idt_x86.c +++ b/tests/unit/test_gdt_idt_x86.c @@ -47,16 +47,30 @@ static void test_idt_gdt_i386(/*void **state*/) uc_engine *uc; uc_err err; uint8_t buf[6]; + x86_mmr idt; + x86_mmr gdt; + x86_mmr ldt; + x86_mmr tr; const uint8_t code[] = "\x0f\x01\x0c\x24\x0f\x01\x44\x24\x06"; // sidt [esp]; sgdt [esp+6] const uint64_t address = 0x1000000; int r_esp = address + 0x1000 - 0x100; // initial esp - int idt_base = 0x12345678; - int idt_limit = 0xabcd; - int gdt_base = 0x87654321; - int gdt_limit = 0xdcba; + idt.base = 0x12345678; + idt.limit = 0xabcd; + gdt.base = 0x87654321; + gdt.limit = 0xdcba; + + ldt.base = 0xfedcba98; + ldt.limit = 0x11111111; + ldt.selector = 0x3333; + ldt.flags = 0x55555555; + + tr.base = 0x22222222; + tr.limit = 0x33333333; + tr.selector = 0x4444; + tr.flags = 0x66666666; // Initialize emulator in X86-32bit mode err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); @@ -73,36 +87,44 @@ static void test_idt_gdt_i386(/*void **state*/) // initialize machine registers err = uc_reg_write(uc, UC_X86_REG_ESP, &r_esp); uc_assert_success(err); - err = uc_reg_write(uc, UC_X86_REG_IDTR_BASE, &idt_base); + err = uc_reg_write(uc, UC_X86_REG_IDTR, &idt); uc_assert_success(err); - err = uc_reg_write(uc, UC_X86_REG_IDTR_LIMIT, &idt_limit); - uc_assert_success(err); - err = uc_reg_write(uc, UC_X86_REG_GDTR_BASE, &gdt_base); - uc_assert_success(err); - err = uc_reg_write(uc, UC_X86_REG_GDTR_LIMIT, &gdt_limit); + err = uc_reg_write(uc, UC_X86_REG_GDTR, &gdt); uc_assert_success(err); - idt_base = 0; - idt_limit = 0; - gdt_base = 0; - gdt_limit = 0; + idt.base = 0; + idt.limit = 0; + gdt.base = 0; + gdt.limit = 0; // emulate machine code in infinite time err = uc_emu_start(uc, address, address+sizeof(code)-1, 0, 0); uc_assert_success(err); - uc_reg_read(uc, UC_X86_REG_IDTR_BASE, &idt_base); - assert(idt_base == 0x12345678); - - uc_reg_read(uc, UC_X86_REG_IDTR_LIMIT, &idt_limit); - assert(idt_limit == 0xabcd); + uc_reg_read(uc, UC_X86_REG_IDTR, &idt); + assert(idt.base == 0x12345678); + assert(idt.limit == 0xabcd); - uc_reg_read(uc, UC_X86_REG_GDTR_BASE, &gdt_base); - assert(gdt_base == 0x87654321); + uc_reg_read(uc, UC_X86_REG_GDTR, &gdt); + assert(gdt.base == 0x87654321); + assert(gdt.limit == 0xdcba); - uc_reg_read(uc, UC_X86_REG_GDTR_LIMIT, &gdt_limit); - assert(gdt_limit == 0xdcba); + //userspace can only set ldt selector, remainder are loaded from + //GDT/LDT, but we allow all to emulator user + uc_reg_read(uc, UC_X86_REG_LDTR, &ldt); + assert(ldt.base == 0xfedcba98); + assert(ldt.limit == 0x11111111); + assert(ldt.selector == 0x3333); + assert(ldt.flags = 0x55555555); + + //userspace can only set tr selector, remainder are loaded from + //GDT/LDT, but we allow all to emulator user + uc_reg_read(uc, UC_X86_REG_TR, &tr); + assert(tr.base == 0x22222222); + assert(tr.limit == 0x33333333); + assert(tr.selector == 0x4444); + assert(tr.flags = 0x66666666); // read from memory err = uc_mem_read(uc, r_esp, buf, 6); From 59f7bf3be733b0b08bfca02eec40b48cfccbaf13 Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Thu, 4 Feb 2016 16:48:27 -0800 Subject: [PATCH 049/126] file perms --- include/unicorn/x86.h | 0 qemu/target-i386/cpu.h | 0 qemu/target-i386/unicorn.c | 0 tests/unit/test_gdt_idt_x86.c | 12 ++++++++---- 4 files changed, 8 insertions(+), 4 deletions(-) mode change 100755 => 100644 include/unicorn/x86.h mode change 100755 => 100644 qemu/target-i386/cpu.h mode change 100755 => 100644 qemu/target-i386/unicorn.c mode change 100755 => 100644 tests/unit/test_gdt_idt_x86.c diff --git a/include/unicorn/x86.h b/include/unicorn/x86.h old mode 100755 new mode 100644 diff --git a/qemu/target-i386/cpu.h b/qemu/target-i386/cpu.h old mode 100755 new mode 100644 diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c old mode 100755 new mode 100644 diff --git a/tests/unit/test_gdt_idt_x86.c b/tests/unit/test_gdt_idt_x86.c old mode 100755 new mode 100644 index 27183f0e..0ee0c9bc --- a/tests/unit/test_gdt_idt_x86.c +++ b/tests/unit/test_gdt_idt_x86.c @@ -91,11 +91,15 @@ static void test_idt_gdt_i386(/*void **state*/) uc_assert_success(err); err = uc_reg_write(uc, UC_X86_REG_GDTR, &gdt); uc_assert_success(err); + err = uc_reg_write(uc, UC_X86_REG_LDTR, &ldt); + uc_assert_success(err); + err = uc_reg_write(uc, UC_X86_REG_TR, &tr); + uc_assert_success(err); - idt.base = 0; - idt.limit = 0; - gdt.base = 0; - gdt.limit = 0; + memset(&idt, 0, sizeof(idt)); + memset(&gdt, 0, sizeof(gdt)); + memset(&ldt, 0, sizeof(ldt)); + memset(&tr, 0, sizeof(tr)); // emulate machine code in infinite time err = uc_emu_start(uc, address, address+sizeof(code)-1, 0, 0); From 9b6d1bf324fd6725f45de3518fa2b4c55de80a49 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Fri, 5 Feb 2016 08:54:52 +0800 Subject: [PATCH 050/126] regress: fix compilation warning for mem_fuzz.c --- .gitignore | 1 + tests/regress/mem_fuzz.c | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index d3ddf440..8d291285 100644 --- a/.gitignore +++ b/.gitignore @@ -137,6 +137,7 @@ sysenter_hook_x86 test_tb_x86 test_multihook test_pc_change +mem_fuzz ################# diff --git a/tests/regress/mem_fuzz.c b/tests/regress/mem_fuzz.c index a1e080cf..aee3cdb0 100644 --- a/tests/regress/mem_fuzz.c +++ b/tests/regress/mem_fuzz.c @@ -44,14 +44,14 @@ uint64_t get_aligned_len(){ void perform_map_step(uc_engine *uc){ uint64_t addr = get_aligned_addr(); uint64_t len = get_aligned_len(); - printf("map(0x%lx,0x%lx); //%d\n", addr, len, step); + printf("map(0x%"PRIx64",0x%"PRIx64"); //%d\n", addr, len, step); uc_mem_map(uc, addr, len, UC_PROT_READ | UC_PROT_WRITE); } void perform_unmap_step(uc_engine *uc){ uint64_t addr = get_aligned_addr(); uint64_t len = get_aligned_len(); - printf("unmap(0x%lx,0x%lx); //%d\n", addr, len, step); + printf("unmap(0x%"PRIx64",0x%"PRIx64"); //%d\n", addr, len, step); uc_mem_unmap(uc, addr, len); } @@ -60,7 +60,7 @@ void perform_write_step(uc_engine *uc){ memset(buff, 0, 4096*4); uint64_t addr = get_addr(); uint64_t len = get_len()%(4096*3); - printf("write(0x%lx,0x%lx); //%d\n", addr, len, step); + printf("write(0x%"PRIx64",0x%"PRIx64"); //%d\n", addr, len, step); uc_mem_write(uc, addr, buff, len); } @@ -68,7 +68,7 @@ void perform_read_step(uc_engine *uc){ char* buff[4096*4]; uint64_t addr = get_addr(); uint64_t len = get_len()%(4096*3); - printf("read(0x%lx,0x%lx); //%d\n", addr, len, step); + printf("read(0x%"PRIx64",0x%"PRIx64"); //%d\n", addr, len, step); uc_mem_read(uc, addr, buff, len); } From f3dc2522a090e1f8467f5a67571dc3e1bef49786 Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Thu, 4 Feb 2016 17:17:40 -0800 Subject: [PATCH 051/126] read/write of x86 segment registers should modify selector field not base field --- qemu/target-i386/unicorn.c | 48 +++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 24 deletions(-) mode change 100644 => 100755 qemu/target-i386/unicorn.c diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c old mode 100644 new mode 100755 index 0af5763e..e6705133 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -260,22 +260,22 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.eip); break; case UC_X86_REG_CS: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.segs[R_CS].base; + *(int32_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_CS].selector; break; case UC_X86_REG_DS: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.segs[R_DS].base; + *(int32_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_DS].selector; break; case UC_X86_REG_SS: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.segs[R_SS].base; + *(int32_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_SS].selector; break; case UC_X86_REG_ES: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.segs[R_ES].base; + *(int32_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_ES].selector; break; case UC_X86_REG_FS: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.segs[R_FS].base; + *(int32_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_FS].selector; break; case UC_X86_REG_GS: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.segs[R_GS].base; + *(int32_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_GS].selector; break; } break; @@ -412,22 +412,22 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.eip); break; case UC_X86_REG_CS: - *(int64_t *)value = X86_CPU(uc, mycpu)->env.segs[R_CS].base; + *(int64_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_CS].selector; break; case UC_X86_REG_DS: - *(int64_t *)value = X86_CPU(uc, mycpu)->env.segs[R_DS].base; + *(int64_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_DS].selector; break; case UC_X86_REG_SS: - *(int64_t *)value = X86_CPU(uc, mycpu)->env.segs[R_SS].base; + *(int64_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_SS].selector; break; case UC_X86_REG_ES: - *(int64_t *)value = X86_CPU(uc, mycpu)->env.segs[R_ES].base; + *(int64_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_ES].selector; break; case UC_X86_REG_FS: - *(int64_t *)value = X86_CPU(uc, mycpu)->env.segs[R_FS].base; + *(int64_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_FS].selector; break; case UC_X86_REG_GS: - *(int64_t *)value = X86_CPU(uc, mycpu)->env.segs[R_GS].base; + *(int64_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_GS].selector; break; case UC_X86_REG_R8: *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[8]); @@ -667,22 +667,22 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) uc_emu_stop(uc); break; case UC_X86_REG_CS: - X86_CPU(uc, mycpu)->env.segs[R_CS].base = *(uint32_t *)value; + X86_CPU(uc, mycpu)->env.segs[R_CS].selector = *(uint16_t *)value; break; case UC_X86_REG_DS: - X86_CPU(uc, mycpu)->env.segs[R_DS].base = *(uint32_t *)value; + X86_CPU(uc, mycpu)->env.segs[R_DS].selector = *(uint16_t *)value; break; case UC_X86_REG_SS: - X86_CPU(uc, mycpu)->env.segs[R_SS].base = *(uint32_t *)value; + X86_CPU(uc, mycpu)->env.segs[R_SS].selector = *(uint16_t *)value; break; case UC_X86_REG_ES: - X86_CPU(uc, mycpu)->env.segs[R_ES].base = *(uint32_t *)value; + X86_CPU(uc, mycpu)->env.segs[R_ES].selector = *(uint16_t *)value; break; case UC_X86_REG_FS: - X86_CPU(uc, mycpu)->env.segs[R_FS].base = *(uint32_t *)value; + X86_CPU(uc, mycpu)->env.segs[R_FS].selector = *(uint16_t *)value; break; case UC_X86_REG_GS: - X86_CPU(uc, mycpu)->env.segs[R_GS].base = *(uint32_t *)value; + X86_CPU(uc, mycpu)->env.segs[R_GS].selector = *(uint16_t *)value; break; } break; @@ -829,22 +829,22 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) uc_emu_stop(uc); break; case UC_X86_REG_CS: - X86_CPU(uc, mycpu)->env.segs[R_CS].base = *(uint64_t *)value; + X86_CPU(uc, mycpu)->env.segs[R_CS].selector = *(uint16_t *)value; break; case UC_X86_REG_DS: - X86_CPU(uc, mycpu)->env.segs[R_DS].base = *(uint64_t *)value; + X86_CPU(uc, mycpu)->env.segs[R_DS].selector = *(uint16_t *)value; break; case UC_X86_REG_SS: - X86_CPU(uc, mycpu)->env.segs[R_SS].base = *(uint64_t *)value; + X86_CPU(uc, mycpu)->env.segs[R_SS].selector = *(uint16_t *)value; break; case UC_X86_REG_ES: - X86_CPU(uc, mycpu)->env.segs[R_ES].base = *(uint64_t *)value; + X86_CPU(uc, mycpu)->env.segs[R_ES].selector = *(uint16_t *)value; break; case UC_X86_REG_FS: - X86_CPU(uc, mycpu)->env.segs[R_FS].base = *(uint64_t *)value; + X86_CPU(uc, mycpu)->env.segs[R_FS].selector = *(uint16_t *)value; break; case UC_X86_REG_GS: - X86_CPU(uc, mycpu)->env.segs[R_GS].base = *(uint64_t *)value; + X86_CPU(uc, mycpu)->env.segs[R_GS].selector = *(uint16_t *)value; break; case UC_X86_REG_R8: X86_CPU(uc, mycpu)->env.regs[8] = *(uint64_t *)value; From c339ced21863745be7fa49a14d17d51dd5a89509 Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Thu, 4 Feb 2016 17:18:24 -0800 Subject: [PATCH 052/126] file perms --- qemu/target-i386/unicorn.c | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 qemu/target-i386/unicorn.c diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c old mode 100755 new mode 100644 From bcfa41c90de34071b4b176151c72e98bf9ad76fd Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Fri, 5 Feb 2016 02:35:17 +0100 Subject: [PATCH 053/126] add regress for #421 --- tests/regress/mov_gs_eax.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100755 tests/regress/mov_gs_eax.py diff --git a/tests/regress/mov_gs_eax.py b/tests/regress/mov_gs_eax.py new file mode 100755 index 00000000..73fd6306 --- /dev/null +++ b/tests/regress/mov_gs_eax.py @@ -0,0 +1,27 @@ +#!/usr/bin/python + +from unicorn import * +from unicorn.x86_const import * + +import regress + +class VldrPcInsn(regress.RegressTest): + + def runTest(self): + uc = Uc(UC_ARCH_X86, UC_MODE_32) + uc.mem_map(0x1000, 0x1000) + # mov gs, eax; mov eax, 1 + code = '8ee8b801000000'.decode('hex') + uc.mem_write(0x1000, code) + + uc.reg_write(UC_X86_REG_EAX, 0xFFFFFFFF) + # this should throw an error + # the eax test is just to prove the second instruction doesn't execute + try: + uc.emu_start(0x1000, len(code)) + except UcError: + return + self.assertEqual(uc.reg_read(UC_X86_REG_EAX), 1) + +if __name__ == '__main__': + regress.main() From 49b9f4f8da637cb1aebe3184ec8a5e46a1272e9f Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Thu, 4 Feb 2016 19:09:41 -0800 Subject: [PATCH 054/126] uc_x86_mmr type available in qemu/target-i386/unicorn.c --- include/unicorn/x86.h | 10 ++-- qemu/target-i386/cpu.h | 2 +- qemu/target-i386/unicorn.c | 97 ++++++++++++++++++----------------- tests/unit/test_gdt_idt_x86.c | 8 +-- 4 files changed, 59 insertions(+), 58 deletions(-) diff --git a/include/unicorn/x86.h b/include/unicorn/x86.h index ab5a0481..37667cfc 100644 --- a/include/unicorn/x86.h +++ b/include/unicorn/x86.h @@ -10,12 +10,12 @@ extern "C" { //Memory-Management Register fields (idtr, gdtr, ldtr, tr) //borrow from SegmentCache in qemu/target-i386/cpu.h -typedef struct x86_mmr { - uint32_t selector; - uint64_t base; /* handle 32 or 64 bit CPUs */ +typedef struct uc_x86_mmr { + uint16_t selector; /* not used by gdtr and idtr */ + uint64_t base; /* handle 32 or 64 bit CPUs */ uint32_t limit; - uint32_t flags; -} x86_mmr; + uint32_t flags; /* not used by gdtr and idtr */ +} uc_x86_mmr; // Callback function for tracing SYSCALL/SYSENTER (for uc_hook_intr()) // @user_data: user data passed to tracing APIs. diff --git a/qemu/target-i386/cpu.h b/qemu/target-i386/cpu.h index 68f802f9..4628a8df 100644 --- a/qemu/target-i386/cpu.h +++ b/qemu/target-i386/cpu.h @@ -699,7 +699,7 @@ typedef enum { typedef struct SegmentCache { uint32_t selector; - uint64_t base; /* handle 32 or 64 bit CPUs */ + target_ulong base; uint32_t limit; uint32_t flags; } SegmentCache; diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index 89ccdb6d..19b3dfcf 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -9,6 +9,7 @@ #include "tcg.h" #include "unicorn_common.h" +#include /* needed for uc_x86_mmr */ #define READ_QWORD(x) ((uint64)x) #define READ_DWORD(x) (x & 0xffffffff) @@ -278,24 +279,24 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) *(int32_t *)value = X86_CPU(uc, mycpu)->env.segs[R_GS].base; break; case UC_X86_REG_IDTR: - ((SegmentCache *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.idt.limit; - ((SegmentCache *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.idt.base; + ((uc_x86_mmr *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.idt.limit; + ((uc_x86_mmr *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.idt.base; break; case UC_X86_REG_GDTR: - ((SegmentCache *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.gdt.limit; - ((SegmentCache *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.gdt.base; + ((uc_x86_mmr *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.gdt.limit; + ((uc_x86_mmr *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.gdt.base; break; case UC_X86_REG_LDTR: - ((SegmentCache *)value)->limit = X86_CPU(uc, mycpu)->env.ldt.limit; - ((SegmentCache *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.ldt.base; - ((SegmentCache *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.ldt.selector; - ((SegmentCache *)value)->flags = X86_CPU(uc, mycpu)->env.ldt.flags; + ((uc_x86_mmr *)value)->limit = X86_CPU(uc, mycpu)->env.ldt.limit; + ((uc_x86_mmr *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.ldt.base; + ((uc_x86_mmr *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.ldt.selector; + ((uc_x86_mmr *)value)->flags = X86_CPU(uc, mycpu)->env.ldt.flags; break; case UC_X86_REG_TR: - ((SegmentCache *)value)->limit = X86_CPU(uc, mycpu)->env.tr.limit; - ((SegmentCache *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.tr.base; - ((SegmentCache *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.tr.selector; - ((SegmentCache *)value)->flags = X86_CPU(uc, mycpu)->env.tr.flags; + ((uc_x86_mmr *)value)->limit = X86_CPU(uc, mycpu)->env.tr.limit; + ((uc_x86_mmr *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.tr.base; + ((uc_x86_mmr *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.tr.selector; + ((uc_x86_mmr *)value)->flags = X86_CPU(uc, mycpu)->env.tr.flags; break; } break; @@ -546,24 +547,24 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[15]); break; case UC_X86_REG_IDTR: - ((SegmentCache *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.idt.limit; - ((SegmentCache *)value)->base = X86_CPU(uc, mycpu)->env.idt.base; + ((uc_x86_mmr *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.idt.limit; + ((uc_x86_mmr *)value)->base = X86_CPU(uc, mycpu)->env.idt.base; break; case UC_X86_REG_GDTR: - ((SegmentCache *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.gdt.limit; - ((SegmentCache *)value)->base = X86_CPU(uc, mycpu)->env.gdt.base; + ((uc_x86_mmr *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.gdt.limit; + ((uc_x86_mmr *)value)->base = X86_CPU(uc, mycpu)->env.gdt.base; break; case UC_X86_REG_LDTR: - ((SegmentCache *)value)->limit = X86_CPU(uc, mycpu)->env.ldt.limit; - ((SegmentCache *)value)->base = X86_CPU(uc, mycpu)->env.ldt.base; - ((SegmentCache *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.ldt.selector; - ((SegmentCache *)value)->flags = X86_CPU(uc, mycpu)->env.ldt.flags; + ((uc_x86_mmr *)value)->limit = X86_CPU(uc, mycpu)->env.ldt.limit; + ((uc_x86_mmr *)value)->base = X86_CPU(uc, mycpu)->env.ldt.base; + ((uc_x86_mmr *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.ldt.selector; + ((uc_x86_mmr *)value)->flags = X86_CPU(uc, mycpu)->env.ldt.flags; break; case UC_X86_REG_TR: - ((SegmentCache *)value)->limit = X86_CPU(uc, mycpu)->env.tr.limit; - ((SegmentCache *)value)->base = X86_CPU(uc, mycpu)->env.tr.base; - ((SegmentCache *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.tr.selector; - ((SegmentCache *)value)->flags = X86_CPU(uc, mycpu)->env.tr.flags; + ((uc_x86_mmr *)value)->limit = X86_CPU(uc, mycpu)->env.tr.limit; + ((uc_x86_mmr *)value)->base = X86_CPU(uc, mycpu)->env.tr.base; + ((uc_x86_mmr *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.tr.selector; + ((uc_x86_mmr *)value)->flags = X86_CPU(uc, mycpu)->env.tr.flags; break; } break; @@ -725,24 +726,24 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) X86_CPU(uc, mycpu)->env.segs[R_GS].base = *(uint32_t *)value; break; case UC_X86_REG_IDTR: - X86_CPU(uc, mycpu)->env.idt.limit = (uint16_t)((SegmentCache *)value)->limit; - X86_CPU(uc, mycpu)->env.idt.base = (uint32_t)((SegmentCache *)value)->base; + X86_CPU(uc, mycpu)->env.idt.limit = (uint16_t)((uc_x86_mmr *)value)->limit; + X86_CPU(uc, mycpu)->env.idt.base = (uint32_t)((uc_x86_mmr *)value)->base; break; case UC_X86_REG_GDTR: - X86_CPU(uc, mycpu)->env.gdt.limit = (uint16_t)((SegmentCache *)value)->limit; - X86_CPU(uc, mycpu)->env.gdt.base = (uint32_t)((SegmentCache *)value)->base; + X86_CPU(uc, mycpu)->env.gdt.limit = (uint16_t)((uc_x86_mmr *)value)->limit; + X86_CPU(uc, mycpu)->env.gdt.base = (uint32_t)((uc_x86_mmr *)value)->base; break; case UC_X86_REG_LDTR: - X86_CPU(uc, mycpu)->env.ldt.limit = ((SegmentCache *)value)->limit; - X86_CPU(uc, mycpu)->env.ldt.base = (uint32_t)((SegmentCache *)value)->base; - X86_CPU(uc, mycpu)->env.ldt.selector = (uint16_t)((SegmentCache *)value)->selector; - X86_CPU(uc, mycpu)->env.ldt.flags = ((SegmentCache *)value)->flags; + X86_CPU(uc, mycpu)->env.ldt.limit = (uint16_t)((uc_x86_mmr *)value)->limit; + X86_CPU(uc, mycpu)->env.ldt.base = (uint32_t)((uc_x86_mmr *)value)->base; + X86_CPU(uc, mycpu)->env.ldt.selector = (uint16_t)((uc_x86_mmr *)value)->selector; + X86_CPU(uc, mycpu)->env.ldt.flags = ((uc_x86_mmr *)value)->flags; break; case UC_X86_REG_TR: - X86_CPU(uc, mycpu)->env.tr.limit = ((SegmentCache *)value)->limit; - X86_CPU(uc, mycpu)->env.tr.base = (uint32_t)((SegmentCache *)value)->base; - X86_CPU(uc, mycpu)->env.tr.selector = (uint16_t)((SegmentCache *)value)->selector; - X86_CPU(uc, mycpu)->env.tr.flags = ((SegmentCache *)value)->flags; + X86_CPU(uc, mycpu)->env.tr.limit = (uint16_t)((uc_x86_mmr *)value)->limit; + X86_CPU(uc, mycpu)->env.tr.base = (uint32_t)((uc_x86_mmr *)value)->base; + X86_CPU(uc, mycpu)->env.tr.selector = (uint16_t)((uc_x86_mmr *)value)->selector; + X86_CPU(uc, mycpu)->env.tr.flags = ((uc_x86_mmr *)value)->flags; break; } break; @@ -1003,24 +1004,24 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[15], *(uint8_t *)value); break; case UC_X86_REG_IDTR: - X86_CPU(uc, mycpu)->env.idt.limit = (uint16_t)((SegmentCache *)value)->limit; - X86_CPU(uc, mycpu)->env.idt.base = ((SegmentCache *)value)->base; + X86_CPU(uc, mycpu)->env.idt.limit = (uint16_t)((uc_x86_mmr *)value)->limit; + X86_CPU(uc, mycpu)->env.idt.base = ((uc_x86_mmr *)value)->base; break; case UC_X86_REG_GDTR: - X86_CPU(uc, mycpu)->env.gdt.limit = (uint16_t)((SegmentCache *)value)->limit; - X86_CPU(uc, mycpu)->env.gdt.base = ((SegmentCache *)value)->base; + X86_CPU(uc, mycpu)->env.gdt.limit = (uint16_t)((uc_x86_mmr *)value)->limit; + X86_CPU(uc, mycpu)->env.gdt.base = ((uc_x86_mmr *)value)->base; break; case UC_X86_REG_LDTR: - X86_CPU(uc, mycpu)->env.ldt.limit = ((SegmentCache *)value)->limit; - X86_CPU(uc, mycpu)->env.ldt.base = ((SegmentCache *)value)->base; - X86_CPU(uc, mycpu)->env.ldt.selector = (uint16_t)((SegmentCache *)value)->selector; - X86_CPU(uc, mycpu)->env.ldt.flags = ((SegmentCache *)value)->flags; + X86_CPU(uc, mycpu)->env.ldt.limit = ((uc_x86_mmr *)value)->limit; + X86_CPU(uc, mycpu)->env.ldt.base = ((uc_x86_mmr *)value)->base; + X86_CPU(uc, mycpu)->env.ldt.selector = (uint16_t)((uc_x86_mmr *)value)->selector; + X86_CPU(uc, mycpu)->env.ldt.flags = ((uc_x86_mmr *)value)->flags; break; case UC_X86_REG_TR: - X86_CPU(uc, mycpu)->env.tr.limit = ((SegmentCache *)value)->limit; - X86_CPU(uc, mycpu)->env.tr.base = ((SegmentCache *)value)->base; - X86_CPU(uc, mycpu)->env.tr.selector = (uint16_t)((SegmentCache *)value)->selector; - X86_CPU(uc, mycpu)->env.tr.flags = ((SegmentCache *)value)->flags; + X86_CPU(uc, mycpu)->env.tr.limit = ((uc_x86_mmr *)value)->limit; + X86_CPU(uc, mycpu)->env.tr.base = ((uc_x86_mmr *)value)->base; + X86_CPU(uc, mycpu)->env.tr.selector = (uint16_t)((uc_x86_mmr *)value)->selector; + X86_CPU(uc, mycpu)->env.tr.flags = ((uc_x86_mmr *)value)->flags; break; } break; diff --git a/tests/unit/test_gdt_idt_x86.c b/tests/unit/test_gdt_idt_x86.c index 0ee0c9bc..5344d7a5 100644 --- a/tests/unit/test_gdt_idt_x86.c +++ b/tests/unit/test_gdt_idt_x86.c @@ -47,10 +47,10 @@ static void test_idt_gdt_i386(/*void **state*/) uc_engine *uc; uc_err err; uint8_t buf[6]; - x86_mmr idt; - x86_mmr gdt; - x86_mmr ldt; - x86_mmr tr; + uc_x86_mmr idt; + uc_x86_mmr gdt; + uc_x86_mmr ldt; + uc_x86_mmr tr; const uint8_t code[] = "\x0f\x01\x0c\x24\x0f\x01\x44\x24\x06"; // sidt [esp]; sgdt [esp+6] const uint64_t address = 0x1000000; From 4cb43be5bf5a7dee090a6c0c337e1ae0573a679f Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Thu, 4 Feb 2016 19:20:59 -0800 Subject: [PATCH 055/126] fix reg_read casting for x86 segment registers --- qemu/target-i386/unicorn.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) mode change 100644 => 100755 qemu/target-i386/unicorn.c diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c old mode 100644 new mode 100755 index e6705133..3da1c94d --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -260,22 +260,22 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.eip); break; case UC_X86_REG_CS: - *(int32_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_CS].selector; + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_CS].selector; break; case UC_X86_REG_DS: - *(int32_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_DS].selector; + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_DS].selector; break; case UC_X86_REG_SS: - *(int32_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_SS].selector; + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_SS].selector; break; case UC_X86_REG_ES: - *(int32_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_ES].selector; + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_ES].selector; break; case UC_X86_REG_FS: - *(int32_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_FS].selector; + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_FS].selector; break; case UC_X86_REG_GS: - *(int32_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_GS].selector; + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_GS].selector; break; } break; @@ -412,22 +412,22 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.eip); break; case UC_X86_REG_CS: - *(int64_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_CS].selector; + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_CS].selector; break; case UC_X86_REG_DS: - *(int64_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_DS].selector; + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_DS].selector; break; case UC_X86_REG_SS: - *(int64_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_SS].selector; + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_SS].selector; break; case UC_X86_REG_ES: - *(int64_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_ES].selector; + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_ES].selector; break; case UC_X86_REG_FS: - *(int64_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_FS].selector; + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_FS].selector; break; case UC_X86_REG_GS: - *(int64_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_GS].selector; + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_GS].selector; break; case UC_X86_REG_R8: *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[8]); From b49358524f2f6f0b019943aabc8cc719176c5d35 Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Thu, 4 Feb 2016 19:22:39 -0800 Subject: [PATCH 056/126] fix reg_read casting for x86 segment registers --- qemu/target-i386/unicorn.c | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 qemu/target-i386/unicorn.c diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c old mode 100755 new mode 100644 From dec3615d1208a388c60a39beb27cd2ea75b3a6b0 Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Thu, 4 Feb 2016 19:26:47 -0800 Subject: [PATCH 057/126] ldtr and tr limit is 20 bits, not 16 bits --- qemu/target-i386/unicorn.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) mode change 100644 => 100755 qemu/target-i386/unicorn.c diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c old mode 100644 new mode 100755 index 19b3dfcf..cf03faa0 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -734,13 +734,13 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) X86_CPU(uc, mycpu)->env.gdt.base = (uint32_t)((uc_x86_mmr *)value)->base; break; case UC_X86_REG_LDTR: - X86_CPU(uc, mycpu)->env.ldt.limit = (uint16_t)((uc_x86_mmr *)value)->limit; + X86_CPU(uc, mycpu)->env.ldt.limit = ((uc_x86_mmr *)value)->limit; X86_CPU(uc, mycpu)->env.ldt.base = (uint32_t)((uc_x86_mmr *)value)->base; X86_CPU(uc, mycpu)->env.ldt.selector = (uint16_t)((uc_x86_mmr *)value)->selector; X86_CPU(uc, mycpu)->env.ldt.flags = ((uc_x86_mmr *)value)->flags; break; case UC_X86_REG_TR: - X86_CPU(uc, mycpu)->env.tr.limit = (uint16_t)((uc_x86_mmr *)value)->limit; + X86_CPU(uc, mycpu)->env.tr.limit = ((uc_x86_mmr *)value)->limit; X86_CPU(uc, mycpu)->env.tr.base = (uint32_t)((uc_x86_mmr *)value)->base; X86_CPU(uc, mycpu)->env.tr.selector = (uint16_t)((uc_x86_mmr *)value)->selector; X86_CPU(uc, mycpu)->env.tr.flags = ((uc_x86_mmr *)value)->flags; From e73cbf1c88b333bbe3551855f44cab610ea204ce Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 6 Feb 2016 09:47:57 +0800 Subject: [PATCH 058/126] arm: UC_QUERY_MODE return hardware mode (see issue #397) --- qemu/target-arm/unicorn_arm.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/qemu/target-arm/unicorn_arm.c b/qemu/target-arm/unicorn_arm.c index c8349806..95ea812d 100644 --- a/qemu/target-arm/unicorn_arm.c +++ b/qemu/target-arm/unicorn_arm.c @@ -116,10 +116,15 @@ static bool arm_stop_interrupt(int intno) static uc_err arm_query(struct uc_struct *uc, uc_query_type type, size_t *result) { CPUState *mycpu = first_cpu; + uint32_t mode; switch(type) { case UC_QUERY_MODE: - *result = (ARM_CPU(uc, mycpu)->env.thumb != 0); + // zero out ARM/THUMB mode + mode = uc->mode & ~(UC_MODE_ARM | UC_MODE_THUMB); + // THUMB mode or ARM MOde + mode += ((ARM_CPU(uc, mycpu)->env.thumb != 0)? UC_MODE_THUMB : UC_MODE_ARM); + *result = mode; return UC_ERR_OK; default: return UC_ERR_ARG; From ed77cacbf3398c880a7ca34e72ca9ca55601a932 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 6 Feb 2016 17:34:19 +0800 Subject: [PATCH 059/126] cosmetic change for uc_x86_mmr --- include/unicorn/x86.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/unicorn/x86.h b/include/unicorn/x86.h index 37667cfc..51401eba 100644 --- a/include/unicorn/x86.h +++ b/include/unicorn/x86.h @@ -8,13 +8,13 @@ extern "C" { #endif -//Memory-Management Register fields (idtr, gdtr, ldtr, tr) -//borrow from SegmentCache in qemu/target-i386/cpu.h +// Memory-Management Register for instructions IDTR, GDTR, LDTR, TR. +// Borrow from SegmentCache in qemu/target-i386/cpu.h typedef struct uc_x86_mmr { - uint16_t selector; /* not used by gdtr and idtr */ + uint16_t selector; /* not used by GDTR and IDTR */ uint64_t base; /* handle 32 or 64 bit CPUs */ uint32_t limit; - uint32_t flags; /* not used by gdtr and idtr */ + uint32_t flags; /* not used by GDTR and IDTR */ } uc_x86_mmr; // Callback function for tracing SYSCALL/SYSENTER (for uc_hook_intr()) From 6986fa39475313e3b55294e99ca9439e397f8e40 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 6 Feb 2016 17:35:45 +0800 Subject: [PATCH 060/126] x86: add new register enums for IDT, LDT, GDT & TR --- bindings/dotnet/UnicornManaged/Const/X86.fs | 6 +++++- bindings/go/unicorn/x86_const.go | 6 +++++- bindings/java/unicorn/X86Const.java | 6 +++++- bindings/python/unicorn/x86_const.py | 6 +++++- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/bindings/dotnet/UnicornManaged/Const/X86.fs b/bindings/dotnet/UnicornManaged/Const/X86.fs index 01fca68e..e293d5a1 100644 --- a/bindings/dotnet/UnicornManaged/Const/X86.fs +++ b/bindings/dotnet/UnicornManaged/Const/X86.fs @@ -251,7 +251,11 @@ module X86 = let UC_X86_REG_R13W = 239 let UC_X86_REG_R14W = 240 let UC_X86_REG_R15W = 241 - let UC_X86_REG_ENDING = 242 + let UC_X86_REG_IDTR = 242 + let UC_X86_REG_GDTR = 243 + let UC_X86_REG_LDTR = 244 + let UC_X86_REG_TR = 245 + let UC_X86_REG_ENDING = 246 // X86 instructions diff --git a/bindings/go/unicorn/x86_const.go b/bindings/go/unicorn/x86_const.go index 74b87e62..49e2310f 100644 --- a/bindings/go/unicorn/x86_const.go +++ b/bindings/go/unicorn/x86_const.go @@ -246,7 +246,11 @@ const ( X86_REG_R13W = 239 X86_REG_R14W = 240 X86_REG_R15W = 241 - X86_REG_ENDING = 242 + X86_REG_IDTR = 242 + X86_REG_GDTR = 243 + X86_REG_LDTR = 244 + X86_REG_TR = 245 + X86_REG_ENDING = 246 // X86 instructions diff --git a/bindings/java/unicorn/X86Const.java b/bindings/java/unicorn/X86Const.java index 1a558a63..9c6d93ee 100644 --- a/bindings/java/unicorn/X86Const.java +++ b/bindings/java/unicorn/X86Const.java @@ -248,7 +248,11 @@ public interface X86Const { public static final int UC_X86_REG_R13W = 239; public static final int UC_X86_REG_R14W = 240; public static final int UC_X86_REG_R15W = 241; - public static final int UC_X86_REG_ENDING = 242; + public static final int UC_X86_REG_IDTR = 242; + public static final int UC_X86_REG_GDTR = 243; + public static final int UC_X86_REG_LDTR = 244; + public static final int UC_X86_REG_TR = 245; + public static final int UC_X86_REG_ENDING = 246; // X86 instructions diff --git a/bindings/python/unicorn/x86_const.py b/bindings/python/unicorn/x86_const.py index 124da17b..a0cf0abc 100644 --- a/bindings/python/unicorn/x86_const.py +++ b/bindings/python/unicorn/x86_const.py @@ -244,7 +244,11 @@ UC_X86_REG_R12W = 238 UC_X86_REG_R13W = 239 UC_X86_REG_R14W = 240 UC_X86_REG_R15W = 241 -UC_X86_REG_ENDING = 242 +UC_X86_REG_IDTR = 242 +UC_X86_REG_GDTR = 243 +UC_X86_REG_LDTR = 244 +UC_X86_REG_TR = 245 +UC_X86_REG_ENDING = 246 # X86 instructions From 7394a9ba30fc1005520f40c78c27ebd467a71379 Mon Sep 17 00:00:00 2001 From: McLovi9 Date: Sat, 6 Feb 2016 14:35:31 +0100 Subject: [PATCH 061/126] Add query mode bind --- bindings/python/unicorn/unicorn.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index 9fd9a896..476ac552 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -107,6 +107,7 @@ _setup_prototype(_uc, "uc_mem_map", ucerr, uc_engine, ctypes.c_uint64, ctypes.c_ _setup_prototype(_uc, "uc_mem_map_ptr", ucerr, uc_engine, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_uint32, ctypes.c_void_p) _setup_prototype(_uc, "uc_mem_unmap", ucerr, uc_engine, ctypes.c_uint64, ctypes.c_size_t) _setup_prototype(_uc, "uc_mem_protect", ucerr, uc_engine, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_uint32) +_setup_prototype(_uc, "uc_query", ucerr, uc_engine, ctypes.c_uint32, ctypes.POINTER(ctypes.c_size_t)) # uc_hook_add is special due to variable number of arguments _uc.uc_hook_add = getattr(_uc, "uc_hook_add") @@ -262,6 +263,14 @@ class Uc(object): if status != UC_ERR_OK: raise UcError(status) + # return CPU mode at runtime + def query(self, query_mode): + result = ctypes.c_size_t(0) + status = _uc.uc_query(self._uch, query_mode, ctypes.byref(result)) + if status != UC_ERR_OK: + raise UcError(status) + return result.value + def _hookcode_cb(self, handle, address, size, user_data): # call user's callback with self object @@ -381,3 +390,4 @@ def debug(): (major, minor, _combined) = uc_version() return "python-%s-c%u.%u-b%u.%u" % (all_archs, major, minor, UC_API_MAJOR, UC_API_MINOR) + From aa1657006b3c2beedfdc7f484e2c1cb19ba113c9 Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Sat, 6 Feb 2016 15:16:44 -0800 Subject: [PATCH 062/126] implement missing APIs (uc_query, uc_mem_map_ptr, uc_mem_regions) in java binding --- bindings/java/unicorn/MemRegion.java | 37 ++++++++++++++ bindings/java/unicorn/Unicorn.java | 40 +++++++++++++-- bindings/java/unicorn_Unicorn.c | 76 +++++++++++++++++++++++++++- 3 files changed, 148 insertions(+), 5 deletions(-) create mode 100755 bindings/java/unicorn/MemRegion.java mode change 100644 => 100755 bindings/java/unicorn/Unicorn.java mode change 100644 => 100755 bindings/java/unicorn_Unicorn.c diff --git a/bindings/java/unicorn/MemRegion.java b/bindings/java/unicorn/MemRegion.java new file mode 100755 index 00000000..b729b3a9 --- /dev/null +++ b/bindings/java/unicorn/MemRegion.java @@ -0,0 +1,37 @@ +/* + +Java bindings for the Unicorn Emulator Engine + +Copyright(c) 2016 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 class MemRegion { + + public long begin; + public long end; + public int perms; + + public MemRegion(long begin, long end, int perms) { + this.begin = begin; + this.end = end; + this.perms = perms; + } + +} + diff --git a/bindings/java/unicorn/Unicorn.java b/bindings/java/unicorn/Unicorn.java old mode 100644 new mode 100755 index 5a28c267..f1a5d15f --- a/bindings/java/unicorn/Unicorn.java +++ b/bindings/java/unicorn/Unicorn.java @@ -288,7 +288,7 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S * * @param arch Architecture type (UC_ARCH_*) * @param mode Hardware mode. This is combined of UC_MODE_* - * @see unicorn.UnicornArchs, unicorn.UnicornModes + * @see unicorn.UnicornConst * */ public Unicorn(int arch, int mode) throws UnicornException { @@ -327,7 +327,7 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S * * @param arch Architecture type (UC_ARCH_*) * @return true if this library supports the given arch. - * @see unicorn.UnicornArchs + * @see unicorn.UnicornConst */ public native static boolean arch_supported(int arch); @@ -337,12 +337,23 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S */ public native void close() throws UnicornException; +/** + * Query internal status of engine. + * + * @param type query type. See UC_QUERY_* + * @param result save the internal status queried + * + * @return: error code. see UC_ERR_* + * @see unicorn.UnicornConst + */ + public native int query(int type) throws UnicornException; + /** * Report the last error number when some API function fail. * Like glibc's errno, uc_errno might not retain its old value once accessed. * * @return Error code of uc_err enum type (UC_ERR_*, see above) - * @see unicorn.UnicornErrors + * @see unicorn.UnicornConst */ public native int errno(); @@ -351,7 +362,7 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S * * @param code Error code (see UC_ERR_* above) * @return Returns a String that describes the error code - * @see unicorn.UnicornErrors + * @see unicorn.UnicornConst */ public native static String strerror(int code); @@ -625,6 +636,19 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S */ public native void mem_map(long address, long size, int perms) throws UnicornException; +/** + * Map existing host memory in for emulation. + * This API adds a memory region that can be used by emulation. + * + * @param address Base address of the memory range + * @param size Size of the memory block. + * @param perms Permissions on the memory block. A combination of UC_PROT_READ, UC_PROT_WRITE, UC_PROT_EXEC + * @param ptr Block of host memory backing the newly mapped memory. This block is + * expected to be an equal or larger size than provided, and be mapped with at + * least PROT_READ | PROT_WRITE. If it is not, the resulting behavior is undefined. + */ + public native void mem_map_ptr(long address, long size, int perms, byte[] block) throws UnicornException; + /** * Unmap a range of memory. * @@ -642,5 +666,13 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S */ public native void mem_protect(long address, long size, int perms) throws UnicornException; +/** + * Retrieve all memory regions mapped by mem_map() and mem_map_ptr() + * NOTE: memory regions may be split by mem_unmap() + * + * @return list of mapped regions. +*/ + public native MemRegion[] mem_regions() throws UnicornException; + } diff --git a/bindings/java/unicorn_Unicorn.c b/bindings/java/unicorn_Unicorn.c old mode 100644 new mode 100755 index a14bd9e4..01af31ee --- a/bindings/java/unicorn_Unicorn.c +++ b/bindings/java/unicorn_Unicorn.c @@ -244,7 +244,28 @@ JNIEXPORT jboolean JNICALL Java_unicorn_Unicorn_arch_1supported JNIEXPORT void JNICALL Java_unicorn_Unicorn_close (JNIEnv *env, jobject self) { uc_engine *eng = getEngine(env, self); - uc_close(eng); + uc_err err = uc_close(eng); + if (err != UC_ERR_OK) { + throwException(env, err); + } + //We also need to ReleaseByteArrayElements for any regions that + //were mapped with uc_mem_map_ptr +} + +/* + * Class: unicorn_Unicorn + * Method: query + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_unicorn_Unicorn_query + (JNIEnv *env, jobject self, jint type) { + uc_engine *eng = getEngine(env, self); + size_t result; + uc_err err = uc_query(eng, type, &result); + if (err != UC_ERR_OK) { + throwException(env, err); + } + return (jint)result; } /* @@ -508,6 +529,24 @@ JNIEXPORT void JNICALL Java_unicorn_Unicorn_mem_1map } } +/* + * Class: unicorn_Unicorn + * Method: mem_map_ptr + * Signature: (JJI[B)V + */ +JNIEXPORT void JNICALL Java_unicorn_Unicorn_mem_1map_1ptr + (JNIEnv *env, jobject self, jlong address, jlong size, jint perms, jbyteArray block) { + uc_engine *eng = getEngine(env, self); + jbyte *array = (*env)->GetByteArrayElements(env, block, NULL); + uc_err err = uc_mem_map_ptr(eng, (uint64_t)address, (size_t)size, (uint32_t)perms, (void*)array); + if (err != UC_ERR_OK) { + throwException(env, err); + } + //Need to track address/block/array so that we can ReleaseByteArrayElements when the + //block gets unmapped or when uc_close gets called + //(*env)->ReleaseByteArrayElements(env, block, array, JNI_ABORT); +} + /* * Class: unicorn_Unicorn * Method: mem_unmap @@ -521,6 +560,9 @@ JNIEXPORT void JNICALL Java_unicorn_Unicorn_mem_1unmap if (err != UC_ERR_OK) { throwException(env, err); } + + //If a region was mapped using uc_mem_map_ptr, we also need to + //ReleaseByteArrayElements for that region } /* @@ -537,3 +579,35 @@ JNIEXPORT void JNICALL Java_unicorn_Unicorn_mem_1protect throwException(env, err); } } + +/* + * Class: unicorn_Unicorn + * Method: mem_regions + * Signature: ()[Lunicorn/MemRegion; + */ +JNIEXPORT jobjectArray JNICALL Java_unicorn_Unicorn_mem_1regions + (JNIEnv *env, jobject self) { + uc_engine *eng = getEngine(env, self); + + uc_mem_region *regions = NULL; + uint32_t count = 0; + uint32_t i; + + uc_err err = uc_mem_regions(eng, ®ions, &count); + if (err != UC_ERR_OK) { + throwException(env, err); + } + jclass clz = (*env)->FindClass(env, "unicorn/MemRegion"); + if ((*env)->ExceptionCheck(env)) { + return NULL; + } + jobjectArray result = (*env)->NewObjectArray(env, (jsize)count, clz, NULL); + jmethodID cons = (*env)->GetMethodID(env, clz, "", "(JJI)V"); + for (i = 0; i < count; i++) { + jobject mr = (*env)->NewObject(env, clz, cons, regions[i].begin, regions[i].end, regions[i].perms); + (*env)->SetObjectArrayElement(env, result, (jsize)i, mr); + } + free(regions); + + return result; +} From 21b9fa860bb8a11d50bbb71e96c2f4e7fc88b85f Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Sat, 6 Feb 2016 15:18:03 -0800 Subject: [PATCH 063/126] fix file perms --- bindings/java/unicorn/MemRegion.java | 0 bindings/java/unicorn_Unicorn.c | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 bindings/java/unicorn/MemRegion.java mode change 100755 => 100644 bindings/java/unicorn_Unicorn.c diff --git a/bindings/java/unicorn/MemRegion.java b/bindings/java/unicorn/MemRegion.java old mode 100755 new mode 100644 diff --git a/bindings/java/unicorn_Unicorn.c b/bindings/java/unicorn_Unicorn.c old mode 100755 new mode 100644 From ec5998bd027af61646f6f61c985e3a061f72cdef Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Sat, 6 Feb 2016 15:18:44 -0800 Subject: [PATCH 064/126] fix file perms --- bindings/java/unicorn/Unicorn.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 bindings/java/unicorn/Unicorn.java diff --git a/bindings/java/unicorn/Unicorn.java b/bindings/java/unicorn/Unicorn.java old mode 100755 new mode 100644 From a5b1ae47c3ee82f6f8a1d6ce746d63114e51b688 Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Sat, 6 Feb 2016 19:19:55 -0800 Subject: [PATCH 065/126] remove unnecessary file --- bindings/java/unicorn/UnicornErrors.java | 38 ------------------------ 1 file changed, 38 deletions(-) delete mode 100644 bindings/java/unicorn/UnicornErrors.java diff --git a/bindings/java/unicorn/UnicornErrors.java b/bindings/java/unicorn/UnicornErrors.java deleted file mode 100644 index d3f376f5..00000000 --- a/bindings/java/unicorn/UnicornErrors.java +++ /dev/null @@ -1,38 +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 UnicornErrors { - public static final int UC_ERR_OK = 0; // No error: everything was fine - public static final int UC_ERR_OOM = 1; // Out-Of-Memory error: uc_open(), uc_emulate() - public static final int UC_ERR_ARCH = 2; // Unsupported architecture: uc_open() - public static final int UC_ERR_HANDLE = 3; // Invalid handle - public static final int UC_ERR_UCH = 4; // Invalid handle (uch) - public static final int UC_ERR_MODE = 5; // Invalid/unsupported mode: uc_open() - public static final int UC_ERR_VERSION = 6; // Unsupported version (bindings) - public static final int UC_ERR_MEM_READ = 7; // Quit emulation due to invalid memory READ: uc_emu_start() - public static final int UC_ERR_MEM_WRITE = 8; // Quit emulation due to invalid memory WRITE: uc_emu_start() - public static final int UC_ERR_HOOK = 9; // Invalid hook type: uc_hook_add() - public static final int UC_ERR_INSN_INVALID = 10; // Quit emulation due to invalid instruction: uc_emu_start() - public static final int UC_ERR_MAP = 11; // Invalid memory mapping: uc_mem_map() -} - From 84fbe5aa5ddfa5ad6e92a49197f731e03171cfb3 Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Sun, 7 Feb 2016 07:23:07 -0800 Subject: [PATCH 066/126] add x86 mmr handling to java binding --- bindings/java/samples/Sample_x86_mmr.java | 77 +++++++++++++++ bindings/java/unicorn/Unicorn.java | 84 +++++++++++++++- bindings/java/unicorn/X86_MMR.java | 46 +++++++++ bindings/java/unicorn_Unicorn.c | 113 +++++++++++++++++++++- 4 files changed, 316 insertions(+), 4 deletions(-) create mode 100644 bindings/java/samples/Sample_x86_mmr.java create mode 100644 bindings/java/unicorn/X86_MMR.java mode change 100644 => 100755 bindings/java/unicorn_Unicorn.c diff --git a/bindings/java/samples/Sample_x86_mmr.java b/bindings/java/samples/Sample_x86_mmr.java new file mode 100644 index 00000000..87bd8a0a --- /dev/null +++ b/bindings/java/samples/Sample_x86_mmr.java @@ -0,0 +1,77 @@ +/* + +Java bindings for the Unicorn Emulator Engine + +Copyright(c) 2016 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. + +*/ + +/* Sample code to demonstrate how to register read/write API */ + +import unicorn.*; + +public class Sample_x86_mmr { + + static void test_x86_mmr() { + // Initialize emulator in X86-32bit mode + Unicorn uc; + try { + uc = new Unicorn(Unicorn.UC_ARCH_X86, Unicorn.UC_MODE_32); + } catch (UnicornException uex) { + System.out.println("Failed on uc_open() with error returned: " + uex); + return; + } + + // map 4k + uc.mem_map(ADDRESS, 0x1000, Unicorn.UC_PROT_ALL); + + X86_MMR ldtr1 = new X86_MMR(0x1111111122222222L, 0x33333333, 0x44444444, (short)0x5555); + X86_MMR ldtr2; + X86_MMR gdtr1 = new X86_MMR(0x6666666677777777L, 0x88888888, 0x99999999, (short)0xaaaa); + X86_MMR gdtr2, gdtr3, gdtr4; + + int eax; + + // initialize machine registers + + uc.reg_write(Unicorn.UC_X86_REG_LDTR, ldtr1); + uc.reg_write(Unicorn.UC_X86_REG_GDTR, gdtr1); + uc.reg_write(Unicorn.UC_X86_REG_EAX, new Long(0xdddddddd)); + + // read the registers back out + eax = (int)((Long)uc.reg_read(Unicorn.UC_X86_REG_EAX)).longValue(); + ldtr2 = (X86_MMR)uc.reg_read(Unicorn.UC_X86_REG_LDTR); + gdtr2 = (X86_MMR)uc.reg_read(Unicorn.UC_X86_REG_GDTR); + + System.out.printf(">>> EAX = 0x%x\n", eax); + + System.out.printf(">>> LDTR.base = 0x%x\n", ldtr2.base); + System.out.printf(">>> LDTR.limit = 0x%x\n", ldtr2.limit); + System.out.printf(">>> LDTR.flags = 0x%x\n", ldtr2.flags); + System.out.printf(">>> LDTR.selector = 0x%x\n\n", ldtr2.selector); + + System.out.printf(">>> GDTR.base = 0x%x\n", gdtr2.base); + System.out.printf(">>> GDTR.limit = 0x%x\n", gdtr2.limit); + + uc.close(); + } + + public static void main(String args[]) + { + test_x86_mmr(); + } + +} diff --git a/bindings/java/unicorn/Unicorn.java b/bindings/java/unicorn/Unicorn.java index f1a5d15f..edf43a29 100644 --- a/bindings/java/unicorn/Unicorn.java +++ b/bindings/java/unicorn/Unicorn.java @@ -26,6 +26,8 @@ import java.util.*; public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, SparcConst, MipsConst, X86Const { private long eng; + private int arch; + private int mode; private long blockHandle = 0; private long interruptHandle = 0; @@ -275,6 +277,38 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S } } +/** + * Write to register. + * + * @param regid Register ID that is to be modified. + * @param value Number containing the new register value + */ + private native void reg_write_num(int regid, Number value) throws UnicornException; + +/** + * Write to register. + * + * @param regid Register ID that is to be modified. + * @param value X86 specific memory management register containing the new register value + */ + private native void reg_write_mmr(int regid, X86_MMR value) throws UnicornException; + +/** + * Read register value. + * + * @param regid Register ID that is to be retrieved. + * @return Number containing the requested register value. + */ + private native Number reg_read_num(int regid) throws UnicornException; + +/** + * Read register value. + * + * @param regid Register ID that is to be retrieved. + * @return X86_MMR containing the requested register value. + */ + private native Number reg_read_mmr(int regid) throws UnicornException; + /** * Native access to uc_open * @@ -292,6 +326,9 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S * */ public Unicorn(int arch, int mode) throws UnicornException { + //remember these in case we need arch specific code + this.arch = arch; + this.mode = mode; eng = open(arch, mode); unicorns.put(eng, this); allLists.add(blockList); @@ -369,19 +406,60 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S /** * Write to register. * + * @deprecated use reg_write(int regid, Object value) instead * @param regid Register ID that is to be modified. * @param value Array containing value that will be written into register @regid */ +@Deprecated public native void reg_write(int regid, byte[] value) throws UnicornException; +/** + * Write to register. + * + * @param regid Register ID that is to be modified. + * @param value Object containing the new register value. Long, BigInteger, or + * other custom class used to represent register values + */ + public void reg_write(int regid, Object value) throws UnicornException { + if (value instanceof Number) { + reg_write_num(regid, (Number)value); + } + else if (arch == UC_ARCH_X86 && value instanceof X86_MMR) { + if (regid >= UC_X86_REG_IDTR && regid <= UC_X86_REG_TR) { + reg_write_mmr(regid, (X86_MMR)value); + } + } + else { + throw new ClassCastException("Invalid value type"); + } + } + +/** + * Read register value. + * + * @deprecated use Object reg_write(int regid) instead + * @param regid Register ID that is to be retrieved. + * @param regsz Size of the register being retrieved. + * @return Byte array containing the requested register value. + */ +@Deprecated + public native byte[] reg_read(int regid, int regsz) throws UnicornException; + /** * Read register value. * * @param regid Register ID that is to be retrieved. - * @param regsz Size of the register being retrieved. - * @return Byte array containing the requested register value. + * @return Object containing the requested register value. Long, BigInteger, or + * other custom class used to represent register values */ - public native byte[] reg_read(int regid, int regsz) throws UnicornException; + public Object reg_read(int regid) throws UnicornException { + if (arch == UC_ARCH_X86 && regid >= UC_X86_REG_IDTR && regid <= UC_X86_REG_TR) { + return reg_read_mmr(regid); + } + else { + return reg_read_num(regid); + } + } /** * Write to memory. diff --git a/bindings/java/unicorn/X86_MMR.java b/bindings/java/unicorn/X86_MMR.java new file mode 100644 index 00000000..1c3db2bc --- /dev/null +++ b/bindings/java/unicorn/X86_MMR.java @@ -0,0 +1,46 @@ +/* + +Java bindings for the Unicorn Emulator Engine + +Copyright(c) 2016 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 class X86_MMR { + + public long base; + public int limit; + public int flags; + public short selector; + + public X86_MMR(long base, int limit, int flags, short selector) { + this.base = base; + this.limit = limit; + this.flags = flags; + this.selector = selector; + } + + public X86_MMR(long base, int limit) { + this.base = base; + this.limit = limit; + selector = 0; + flags = 0; + } + +} + diff --git a/bindings/java/unicorn_Unicorn.c b/bindings/java/unicorn_Unicorn.c old mode 100644 new mode 100755 index 01af31ee..8b3bcfe2 --- a/bindings/java/unicorn_Unicorn.c +++ b/bindings/java/unicorn_Unicorn.c @@ -24,8 +24,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include - #include +#include #include "unicorn_Unicorn.h" //cache jmethodID values as we look them up @@ -201,6 +201,117 @@ static uc_engine *getEngine(JNIEnv *env, jobject self) { return (uc_engine *)(*env)->GetLongField(env, self, fid); } +/* + * Class: unicorn_Unicorn + * Method: reg_write_num + * Signature: (ILjava/lang/Number;)V + */ +JNIEXPORT void JNICALL Java_unicorn_Unicorn_reg_1write_1num + (JNIEnv *env, jobject self, jint regid, jobject value) { + uc_engine *eng = getEngine(env, self); + + jclass clz = (*env)->FindClass(env, "java/lang/Number"); + if ((*env)->ExceptionCheck(env)) { + return; + } + + jmethodID longValue = (*env)->GetMethodID(env, clz, "longValue", "()J"); + jlong longVal = (*env)->CallLongMethod(env, value, longValue); + uc_err err = uc_reg_write(eng, regid, &longVal); + if (err != UC_ERR_OK) { + throwException(env, err); + } +} + +/* + * Class: unicorn_Unicorn + * Method: reg_write_mmr + * Signature: (ILunicorn/X86_MMR;)V + */ +JNIEXPORT void JNICALL Java_unicorn_Unicorn_reg_1write_1mmr + (JNIEnv *env, jobject self, jint regid, jobject value) { + uc_engine *eng = getEngine(env, self); + uc_x86_mmr mmr; + + jclass clz = (*env)->FindClass(env, "unicorn/X86_MMR"); + if ((*env)->ExceptionCheck(env)) { + return; + } + + jfieldID fid = (*env)->GetFieldID(env, clz, "base", "J"); + mmr.base = (uint64_t)(*env)->GetLongField(env, value, fid); + + fid = (*env)->GetFieldID(env, clz, "limit", "I"); + mmr.limit = (uint32_t)(*env)->GetLongField(env, value, fid); + + fid = (*env)->GetFieldID(env, clz, "flags", "I"); + mmr.flags = (uint32_t)(*env)->GetLongField(env, value, fid); + + fid = (*env)->GetFieldID(env, clz, "selector", "S"); + mmr.selector = (uint16_t)(*env)->GetLongField(env, value, fid); + + uc_err err = uc_reg_write(eng, regid, &mmr); + if (err != UC_ERR_OK) { + throwException(env, err); + } +} + +/* + * Class: unicorn_Unicorn + * Method: reg_read_num + * Signature: (I)Ljava/lang/Number; + */ +JNIEXPORT jobject JNICALL Java_unicorn_Unicorn_reg_1read_1num + (JNIEnv *env, jobject self, jint regid) { + uc_engine *eng = getEngine(env, self); + + jclass clz = (*env)->FindClass(env, "java/lang/Long"); + if ((*env)->ExceptionCheck(env)) { + return NULL; + } + + jlong longVal; + uc_err err = uc_reg_read(eng, regid, &longVal); + if (err != UC_ERR_OK) { + throwException(env, err); + } + + jmethodID cons = (*env)->GetMethodID(env, clz, "", "(J)V"); + jobject result = (*env)->NewObject(env, clz, cons, longVal); + if ((*env)->ExceptionCheck(env)) { + return NULL; + } + return result; +} + +/* + * Class: unicorn_Unicorn + * Method: reg_read_mmr + * Signature: (I)Ljava/lang/Number; + */ +JNIEXPORT jobject JNICALL Java_unicorn_Unicorn_reg_1read_1mmr + (JNIEnv *env, jobject self, jint regid) { + uc_engine *eng = getEngine(env, self); + + jclass clz = (*env)->FindClass(env, "unicorn/X86_MMR"); + if ((*env)->ExceptionCheck(env)) { + return NULL; + } + + uc_x86_mmr mmr; + uc_err err = uc_reg_read(eng, regid, &mmr); + if (err != UC_ERR_OK) { + throwException(env, err); + } + + jmethodID cons = (*env)->GetMethodID(env, clz, "", "(JIIS)V"); + jobject result = (*env)->NewObject(env, clz, cons, mmr.base, mmr.limit, mmr.flags, mmr.selector); + if ((*env)->ExceptionCheck(env)) { + return NULL; + } + return result; +} + /* * Class: unicorn_Unicorn * Method: open From 9b8098bf634d6739ae9600f785e6176b8bb9d8e0 Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Sun, 7 Feb 2016 07:24:34 -0800 Subject: [PATCH 067/126] file perms --- bindings/java/unicorn_Unicorn.c | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 bindings/java/unicorn_Unicorn.c diff --git a/bindings/java/unicorn_Unicorn.c b/bindings/java/unicorn_Unicorn.c old mode 100755 new mode 100644 From a7a1dcc66128801d1ef82e992a6cc4ff10fcce5d Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 11 Feb 2016 08:02:13 +0800 Subject: [PATCH 068/126] uc_hook_add(): add begin & end arguments for all hook types. also update Python binding after this change --- bindings/python/sample_x86.py | 6 ++-- bindings/python/shellcode.py | 2 +- bindings/python/unicorn/unicorn.py | 14 ++++------ include/unicorn/unicorn.h | 8 +++++- samples/mem_apis.c | 12 ++++---- samples/sample_arm.c | 8 +++--- samples/sample_arm64.c | 4 +-- samples/sample_m68k.c | 4 +-- samples/sample_mips.c | 8 +++--- samples/sample_sparc.c | 4 +-- samples/sample_x86.c | 44 +++++++++++++++--------------- samples/shellcode.c | 2 +- tests/unit/test_mem_high.c | 2 +- tests/unit/test_multihook.c | 4 +-- tests/unit/test_pc_change.c | 2 +- tests/unit/test_tb_x86.c | 8 +++--- tests/unit/test_x86.c | 28 +++++++++---------- uc.c | 26 ++++++++++-------- 18 files changed, 96 insertions(+), 90 deletions(-) diff --git a/bindings/python/sample_x86.py b/bindings/python/sample_x86.py index b470f4ce..32947a3c 100755 --- a/bindings/python/sample_x86.py +++ b/bindings/python/sample_x86.py @@ -291,8 +291,8 @@ def test_i386_inout(): mu.hook_add(UC_HOOK_CODE, hook_code) # handle IN & OUT instruction - mu.hook_add(UC_HOOK_INSN, hook_in, None, UC_X86_INS_IN) - mu.hook_add(UC_HOOK_INSN, hook_out, None, UC_X86_INS_OUT) + mu.hook_add(UC_HOOK_INSN, hook_in, None, 1, 0, UC_X86_INS_IN) + mu.hook_add(UC_HOOK_INSN, hook_out, None, 1, 0, UC_X86_INS_OUT) # emulate machine code in infinite time mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32_INOUT)) @@ -417,7 +417,7 @@ def test_x86_64_syscall(): print('ERROR: was not expecting rax=%d in syscall' % rax) # hook interrupts for syscall - mu.hook_add(UC_HOOK_INSN, hook_syscall, None, UC_X86_INS_SYSCALL) + mu.hook_add(UC_HOOK_INSN, hook_syscall, None, 1, 0, UC_X86_INS_SYSCALL) # syscall handler is expecting rax=0x100 mu.reg_write(UC_X86_REG_RAX, 0x100) diff --git a/bindings/python/shellcode.py b/bindings/python/shellcode.py index a4a473b0..898ada7b 100755 --- a/bindings/python/shellcode.py +++ b/bindings/python/shellcode.py @@ -97,7 +97,7 @@ def test_i386(mode, code): mu.hook_add(UC_HOOK_INTR, hook_intr) # handle SYSCALL - mu.hook_add(UC_HOOK_INSN, hook_syscall, None, UC_X86_INS_SYSCALL) + mu.hook_add(UC_HOOK_INSN, hook_syscall, None, 1, 0, UC_X86_INS_SYSCALL) # emulate machine code in infinite time mu.emu_start(ADDRESS, ADDRESS + len(code)) diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index 476ac552..3d784368 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -315,7 +315,7 @@ class Uc(object): # add a hook - def hook_add(self, htype, callback, user_data=None, arg1=1, arg2=0): + def hook_add(self, htype, callback, user_data=None, begin=1, end=0, arg1=0): _h2 = uc_hook_h() # save callback & user_data @@ -332,30 +332,28 @@ class Uc(object): if arg1 in (x86_const.UC_X86_INS_SYSCALL, x86_const.UC_X86_INS_SYSENTER): # SYSCALL/SYSENTER instruction cb = ctypes.cast(UC_HOOK_INSN_SYSCALL_CB(self._hook_insn_syscall_cb), UC_HOOK_INSN_SYSCALL_CB) status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \ - cb, ctypes.cast(self._callback_count, ctypes.c_void_p), insn) + cb, ctypes.cast(self._callback_count, ctypes.c_void_p), ctypes.c_uint64(begin), ctypes.c_uint64(end), insn) elif htype == UC_HOOK_INTR: cb = ctypes.cast(UC_HOOK_INTR_CB(self._hook_intr_cb), UC_HOOK_INTR_CB) status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \ - cb, ctypes.cast(self._callback_count, ctypes.c_void_p)) + cb, ctypes.cast(self._callback_count, ctypes.c_void_p), ctypes.c_uint64(begin), ctypes.c_uint64(end)) else: - begin = ctypes.c_uint64(arg1) - end = ctypes.c_uint64(arg2) if htype in (UC_HOOK_BLOCK, UC_HOOK_CODE): # set callback with wrapper, so it can be called # with this object as param 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) + ctypes.cast(self._callback_count, ctypes.c_void_p), ctypes.c_uint64(begin), ctypes.c_uint64(end)) elif htype & UC_HOOK_MEM_READ_UNMAPPED or htype & UC_HOOK_MEM_WRITE_UNMAPPED or \ htype & UC_HOOK_MEM_FETCH_UNMAPPED 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)) + cb, ctypes.cast(self._callback_count, ctypes.c_void_p), ctypes.c_uint64(begin), ctypes.c_uint64(end)) else: 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)) + cb, ctypes.cast(self._callback_count, ctypes.c_void_p), ctypes.c_uint64(begin), ctypes.c_uint64(end)) # save the ctype function so gc will leave it alone. self._ctype_cbs[self._callback_count] = cb diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 2a556841..bf26b741 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -458,13 +458,19 @@ uc_err uc_emu_stop(uc_engine *uc); @callback: callback to be run when instruction is hit @user_data: user-defined data. This will be passed to callback function in its last argument @user_data + @begin: start address of the area where the callback is effect (inclusive) + @begin: end address of the area where the callback is effect (inclusive) + NOTE 1: the callback is called only if related address is in range [@begin, @end] + NOTE 2: if @begin > @end, callback is called whenever this hook type is triggered @...: variable arguments (depending on @type) + NOTE: if @type = UC_HOOK_INSN, this is the instruction ID (ex: UC_X86_INS_OUT) @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum for detailed error). */ UNICORN_EXPORT -uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, ...); +uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, + void *user_data, uint64_t begin, uint64_t end, ...); /* Unregister (remove) a hook callback. diff --git a/samples/mem_apis.c b/samples/mem_apis.c index 008f077d..dc1c2481 100644 --- a/samples/mem_apis.c +++ b/samples/mem_apis.c @@ -168,9 +168,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 || + if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK || uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, - hook_mem_invalid, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + hook_mem_invalid, NULL, 1, 0) != UC_ERR_OK) { printf("not ok - Failed to install hooks\n"); return; } @@ -248,10 +248,10 @@ 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 || + if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK || uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, - hook_mem_invalid, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + hook_mem_invalid, NULL, 1, 0) != UC_ERR_OK) { printf("not ok - Failed to install hooks\n"); return; } @@ -326,10 +326,10 @@ 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 || + if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK || uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, - hook_mem_invalid, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + hook_mem_invalid, NULL, 1, 0) != UC_ERR_OK) { printf("not ok - Failed to install hooks\n"); return; } diff --git a/samples/sample_arm.c b/samples/sample_arm.c index 8a5067db..2c69ce6a 100644 --- a/samples/sample_arm.c +++ b/samples/sample_arm.c @@ -77,10 +77,10 @@ static void test_arm(void) uc_reg_write(uc, UC_ARM_REG_R3, &r3); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing one instruction at ADDRESS with customized callback - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, ADDRESS, ADDRESS); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. @@ -128,10 +128,10 @@ static void test_thumb(void) uc_reg_write(uc, UC_ARM_REG_SP, &sp); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing one instruction at ADDRESS with customized callback - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, ADDRESS, ADDRESS); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. diff --git a/samples/sample_arm64.c b/samples/sample_arm64.c index 39d500aa..785708d0 100644 --- a/samples/sample_arm64.c +++ b/samples/sample_arm64.c @@ -75,10 +75,10 @@ static void test_arm64(void) uc_reg_write(uc, UC_ARM64_REG_X15, &x15); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing one instruction at ADDRESS with customized callback - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, ADDRESS, ADDRESS); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. diff --git a/samples/sample_m68k.c b/samples/sample_m68k.c index efda5294..4bbf1cce 100644 --- a/samples/sample_m68k.c +++ b/samples/sample_m68k.c @@ -108,10 +108,10 @@ static void test_m68k(void) uc_reg_write(uc, UC_M68K_REG_SR, &sr); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing all instruction - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. diff --git a/samples/sample_mips.c b/samples/sample_mips.c index b27a02b1..994047c2 100644 --- a/samples/sample_mips.c +++ b/samples/sample_mips.c @@ -72,10 +72,10 @@ static void test_mips_eb(void) uc_reg_write(uc, UC_MIPS_REG_1, &r1); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing one instruction at ADDRESS with customized callback - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, ADDRESS, ADDRESS); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. @@ -122,10 +122,10 @@ static void test_mips_el(void) uc_reg_write(uc, UC_MIPS_REG_1, &r1); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing one instruction at ADDRESS with customized callback - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, ADDRESS, ADDRESS); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. diff --git a/samples/sample_sparc.c b/samples/sample_sparc.c index e6276b14..649a6dec 100644 --- a/samples/sample_sparc.c +++ b/samples/sample_sparc.c @@ -76,10 +76,10 @@ static void test_sparc(void) uc_reg_write(uc, UC_SPARC_REG_G3, &g3); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing all instructions with customized callback - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. diff --git a/samples/sample_x86.c b/samples/sample_x86.c index c57043d2..264015f2 100644 --- a/samples/sample_x86.c +++ b/samples/sample_x86.c @@ -219,10 +219,10 @@ static void test_i386(void) uc_reg_write(uc, UC_X86_REG_EDX, &r_edx); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing all instruction by having @begin > @end - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0); // emulate machine code in infinite time err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32) - 1, 0, 0); @@ -289,10 +289,10 @@ static void test_i386_map_ptr(void) uc_reg_write(uc, UC_X86_REG_EDX, &r_edx); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing all instruction by having @begin > @end - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0); // emulate machine code in infinite time err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32) - 1, 0, 0); @@ -345,10 +345,10 @@ static void test_i386_jump(void) } // tracing 1 basic block with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, ADDRESS, ADDRESS); // tracing 1 instruction at ADDRESS - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, ADDRESS, ADDRESS); // emulate machine code in infinite time err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_JUMP) - 1, 0, 0); @@ -447,10 +447,10 @@ static void test_i386_invalid_mem_read(void) uc_reg_write(uc, UC_X86_REG_EDX, &r_edx); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing all instruction by having @begin > @end - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0); // emulate machine code in infinite time err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_MEM_READ) - 1, 0, 0); @@ -505,13 +505,13 @@ static void test_i386_invalid_mem_write(void) uc_reg_write(uc, UC_X86_REG_EDX, &r_edx); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing all instruction by having @begin > @end - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0); // intercept invalid memory events - uc_hook_add(uc, &trace3, UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, hook_mem_invalid, NULL); + uc_hook_add(uc, &trace3, UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, hook_mem_invalid, NULL, 1, 0); // emulate machine code in infinite time err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_MEM_WRITE) - 1, 0, 0); @@ -576,10 +576,10 @@ static void test_i386_jump_invalid(void) uc_reg_write(uc, UC_X86_REG_EDX, &r_edx); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing all instructions by having @begin > @end - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0); // emulate machine code in infinite time err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_JMP_INVALID) - 1, 0, 0); @@ -632,15 +632,15 @@ static void test_i386_inout(void) uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing all instructions - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0); // uc IN instruction - uc_hook_add(uc, &trace3, UC_HOOK_INSN, hook_in, NULL, UC_X86_INS_IN); + uc_hook_add(uc, &trace3, UC_HOOK_INSN, hook_in, NULL, 1, 0, UC_X86_INS_IN); // uc OUT instruction - uc_hook_add(uc, &trace4, UC_HOOK_INSN, hook_out, NULL, UC_X86_INS_OUT); + uc_hook_add(uc, &trace4, UC_HOOK_INSN, hook_out, NULL, 1, 0, UC_X86_INS_OUT); // emulate machine code in infinite time err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_INOUT) - 1, 0, 0); @@ -721,16 +721,16 @@ static void test_x86_64(void) uc_reg_write(uc, UC_X86_REG_R15, &r15); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing all instructions in the range [ADDRESS, ADDRESS+20] - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code64, NULL, (uint64_t)ADDRESS, (uint64_t)(ADDRESS+20)); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code64, NULL, ADDRESS, ADDRESS+20); // tracing all memory WRITE access (with @begin > @end) - uc_hook_add(uc, &trace3, UC_HOOK_MEM_WRITE, hook_mem64, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace3, UC_HOOK_MEM_WRITE, hook_mem64, NULL, 1, 0); // tracing all memory READ access (with @begin > @end) - uc_hook_add(uc, &trace4, UC_HOOK_MEM_READ, hook_mem64, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace4, UC_HOOK_MEM_READ, hook_mem64, NULL, 1, 0); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. @@ -804,7 +804,7 @@ static void test_x86_64_syscall(void) } // hook interrupts for syscall - uc_hook_add(uc, &trace1, UC_HOOK_INSN, hook_syscall, NULL, UC_X86_INS_SYSCALL); + uc_hook_add(uc, &trace1, UC_HOOK_INSN, hook_syscall, NULL, 1, 0, UC_X86_INS_SYSCALL); // initialize machine registers uc_reg_write(uc, UC_X86_REG_RAX, &rax); diff --git a/samples/shellcode.c b/samples/shellcode.c index a6fd5221..8ad0c69b 100644 --- a/samples/shellcode.c +++ b/samples/shellcode.c @@ -138,7 +138,7 @@ static void test_i386(void) uc_hook_add(uc, &trace1, UC_HOOK_CODE, hook_code, NULL, 1, 0); // handle interrupt ourself - uc_hook_add(uc, &trace2, UC_HOOK_INTR, hook_intr, NULL); + uc_hook_add(uc, &trace2, UC_HOOK_INTR, hook_intr, NULL, 1, 0); printf("\n>>> Start tracing this Linux code\n"); diff --git a/tests/unit/test_mem_high.c b/tests/unit/test_mem_high.c index 5e2244e5..c8e58288 100644 --- a/tests/unit/test_mem_high.c +++ b/tests/unit/test_mem_high.c @@ -79,7 +79,7 @@ static void test_high_address_reads(void **state) uint8_t code[] = {0x48,0x8b,0x00,0x90,0x90,0x90,0x90}; // mov rax, [rax], nops uc_assert_success(uc_mem_map(uc, base_addr, 4096, UC_PROT_ALL)); uc_assert_success(uc_mem_write(uc, base_addr, code, 7)); - uc_assert_success(uc_hook_add(uc, &trace2, UC_HOOK_MEM_READ, hook_mem64, NULL, (uint64_t)1, (uint64_t)0)); + uc_assert_success(uc_hook_add(uc, &trace2, UC_HOOK_MEM_READ, hook_mem64, NULL, 1, 0)); uc_assert_success(uc_emu_start(uc, base_addr, base_addr + 3, 0, 0)); if(number_of_memory_reads != 1) { fail_msg("wrong number of memory reads for instruction %i", number_of_memory_reads); diff --git a/tests/unit/test_multihook.c b/tests/unit/test_multihook.c index eb831865..c131481d 100644 --- a/tests/unit/test_multihook.c +++ b/tests/unit/test_multihook.c @@ -96,8 +96,8 @@ static void test_basic_blocks(void **state) 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_hook_add(uc, &trace2, UC_HOOK_BLOCK, test_basic_blocks_hook2, &bbtest, (uint64_t)1, (uint64_t)0)); + OK(uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, test_basic_blocks_hook, &bbtest, 1, 0)); + OK(uc_hook_add(uc, &trace2, UC_HOOK_BLOCK, test_basic_blocks_hook2, &bbtest, 1, 0)); OK(uc_emu_start(uc, address, address+sizeof(code), 0, 0)); } diff --git a/tests/unit/test_pc_change.c b/tests/unit/test_pc_change.c index 7994e772..c2ec73a8 100644 --- a/tests/unit/test_pc_change.c +++ b/tests/unit/test_pc_change.c @@ -83,7 +83,7 @@ static void test_pc_change(void **state) printf("ECX = %u, EDX = %u\n", r_ecx, r_edx); // trace all instructions - OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, test_code_hook, NULL, (uint64_t)1, (uint64_t)0)); + OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, test_code_hook, NULL, 1, 0)); OK(uc_emu_start(uc, address, address+sizeof(code), 0, 0)); diff --git a/tests/unit/test_tb_x86.c b/tests/unit/test_tb_x86.c index bf691e8b..1d6ba7a0 100644 --- a/tests/unit/test_tb_x86.c +++ b/tests/unit/test_tb_x86.c @@ -273,16 +273,16 @@ static void test_tb_x86_64_32_imul_Gv_Ev_Ib(void **state) UC_HOOK_CODE, hook_code32, NULL, - (uint64_t)1, - (uint64_t)0)); + 1, + 0)); uc_assert_success(uc_hook_add(uc, &trace2, UC_HOOK_MEM_VALID, hook_mem32, NULL, - (uint64_t)1, - (uint64_t)0)); + 1, + 0)); uc_assert_success(uc_emu_start(uc, #ifdef RIP_NEXT_TO_THE_SELFMODIFY_OPCODE diff --git a/tests/unit/test_x86.c b/tests/unit/test_x86.c index 04441123..348cd5cd 100644 --- a/tests/unit/test_x86.c +++ b/tests/unit/test_x86.c @@ -85,7 +85,7 @@ static void test_basic_blocks(void **state) 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_hook_add(uc, &trace1, UC_HOOK_BLOCK, test_basic_blocks_hook, &bbtest, 1, 0)); OK(uc_emu_start(uc, address, address+sizeof(code), 0, 0)); } @@ -144,11 +144,11 @@ static void test_i386(void **state) 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); + err = uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 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); + err = uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0); uc_assert_success(err); // emulate machine code in infinite time @@ -194,11 +194,11 @@ static void test_i386_jump(void **state) 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); + err = uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, address, 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); + err = uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, address, address); uc_assert_success(err); // emulate machine code in infinite time @@ -302,19 +302,19 @@ static void test_i386_inout(void **state) 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); + err = uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 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); + err = uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0); uc_assert_success(err); // uc IN instruction - err = uc_hook_add(uc, &trace3, UC_HOOK_INSN, hook_in, NULL, UC_X86_INS_IN); + err = uc_hook_add(uc, &trace3, UC_HOOK_INSN, hook_in, NULL, 1, 0, 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); + err = uc_hook_add(uc, &trace4, UC_HOOK_INSN, hook_out, NULL, 1, 0, UC_X86_INS_OUT); uc_assert_success(err); // emulate machine code in infinite time @@ -566,19 +566,19 @@ static void test_x86_64(void **state) 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); + err = uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 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)); + err = uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code64, NULL, address, 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); + err = uc_hook_add(uc, &trace3, UC_HOOK_MEM_WRITE, hook_mem64, NULL, 1, 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); + err = uc_hook_add(uc, &trace4, UC_HOOK_MEM_READ, hook_mem64, NULL, 1, 0); uc_assert_success(err); // emulate machine code in infinite time (last param = 0), or when @@ -662,7 +662,7 @@ static void test_x86_64_syscall(void **state) uc_assert_success(err); // hook interrupts for syscall - err = uc_hook_add(uc, &trace1, UC_HOOK_INSN, hook_syscall, NULL, UC_X86_INS_SYSCALL); + err = uc_hook_add(uc, &trace1, UC_HOOK_INSN, hook_syscall, NULL, 1, 0, UC_X86_INS_SYSCALL); uc_assert_success(err); // initialize machine registers diff --git a/uc.c b/uc.c index ab466601..169da7b6 100644 --- a/uc.c +++ b/uc.c @@ -551,7 +551,7 @@ uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t time } // set up count hook to count instructions. if (count > 0 && uc->count_hook == 0) { - uc_err err = uc_hook_add(uc, &uc->count_hook, UC_HOOK_CODE, hook_count_cb, NULL); + uc_err err = uc_hook_add(uc, &uc->count_hook, UC_HOOK_CODE, hook_count_cb, NULL, 1, 0); if (err != UC_ERR_OK) { return err; } @@ -565,6 +565,7 @@ uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t time if (timeout) enable_emu_timer(uc, timeout * 1000); // microseconds -> nanoseconds + uc->pause_all_vcpus(uc); // emulation is done uc->emulation_done = true; @@ -963,17 +964,19 @@ MemoryRegion *memory_mapping(struct uc_struct* uc, uint64_t address) } UNICORN_EXPORT -uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, ...) +uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, + void *user_data, uint64_t begin, uint64_t end, ...) { - va_list valist; int ret = UC_ERR_OK; - - va_start(valist, user_data); + int i = 0; struct hook *hook = calloc(1, sizeof(struct hook)); if (hook == NULL) { return UC_ERR_NOMEM; } + + hook->begin = begin; + hook->end = end; hook->type = type; hook->callback = callback; hook->user_data = user_data; @@ -982,22 +985,21 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *u // everybody but HOOK_INSN gets begin/end, so exit early here. if (type & UC_HOOK_INSN) { + va_list valist; + + va_start(valist, end); hook->insn = va_arg(valist, int); - hook->begin = 1; - hook->end = 0; + va_end(valist); + if (list_append(&uc->hook[UC_HOOK_INSN_IDX], hook) == NULL) { free(hook); return UC_ERR_NOMEM; } + hook->refs++; return UC_ERR_OK; } - hook->begin = va_arg(valist, uint64_t); - hook->end = va_arg(valist, uint64_t); - va_end(valist); - - int i = 0; while ((type >> i) > 0) { if ((type >> i) & 1) { // TODO: invalid hook error? From 0822c0af85c6623a4c905a3673c233c0ccfbf98a Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 11 Feb 2016 08:05:15 +0800 Subject: [PATCH 069/126] bump API version to 1.0 --- bindings/dotnet/UnicornManaged/Const/Common.fs | 4 ++-- bindings/go/unicorn/unicorn_const.go | 4 ++-- bindings/java/unicorn/UnicornConst.java | 4 ++-- bindings/python/unicorn/unicorn_const.py | 4 ++-- include/unicorn/unicorn.h | 4 ++-- pkgconfig.mk | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/bindings/dotnet/UnicornManaged/Const/Common.fs b/bindings/dotnet/UnicornManaged/Const/Common.fs index 6f106a3e..0f42d3d7 100644 --- a/bindings/dotnet/UnicornManaged/Const/Common.fs +++ b/bindings/dotnet/UnicornManaged/Const/Common.fs @@ -6,9 +6,9 @@ open System [] module Common = + let UC_API_MAJOR = 1 - let UC_API_MAJOR = 0 - let UC_API_MINOR = 9 + let UC_API_MINOR = 0 let UC_SECOND_SCALE = 1000000 let UC_MILISECOND_SCALE = 1000 let UC_ARCH_ARM = 1 diff --git a/bindings/go/unicorn/unicorn_const.go b/bindings/go/unicorn/unicorn_const.go index 8d634be9..1faff075 100644 --- a/bindings/go/unicorn/unicorn_const.go +++ b/bindings/go/unicorn/unicorn_const.go @@ -1,9 +1,9 @@ package unicorn // For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [unicorn_const.go] const ( + API_MAJOR = 1 - API_MAJOR = 0 - API_MINOR = 9 + API_MINOR = 0 SECOND_SCALE = 1000000 MILISECOND_SCALE = 1000 ARCH_ARM = 1 diff --git a/bindings/java/unicorn/UnicornConst.java b/bindings/java/unicorn/UnicornConst.java index 0fe4f193..64b52236 100644 --- a/bindings/java/unicorn/UnicornConst.java +++ b/bindings/java/unicorn/UnicornConst.java @@ -3,9 +3,9 @@ package unicorn; public interface UnicornConst { + public static final int UC_API_MAJOR = 1; - public static final int UC_API_MAJOR = 0; - public static final int UC_API_MINOR = 9; + public static final int UC_API_MINOR = 0; public static final int UC_SECOND_SCALE = 1000000; public static final int UC_MILISECOND_SCALE = 1000; public static final int UC_ARCH_ARM = 1; diff --git a/bindings/python/unicorn/unicorn_const.py b/bindings/python/unicorn/unicorn_const.py index 4e942ef5..bdb8ed01 100644 --- a/bindings/python/unicorn/unicorn_const.py +++ b/bindings/python/unicorn/unicorn_const.py @@ -1,7 +1,7 @@ # For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [unicorn_const.py] +UC_API_MAJOR = 1 -UC_API_MAJOR = 0 -UC_API_MINOR = 9 +UC_API_MINOR = 0 UC_SECOND_SCALE = 1000000 UC_MILISECOND_SCALE = 1000 UC_ARCH_ARM = 1 diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index bf26b741..3762cecd 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -57,8 +57,8 @@ typedef size_t uc_hook; #endif // Unicorn API version -#define UC_API_MAJOR 0 -#define UC_API_MINOR 9 +#define UC_API_MAJOR 1 +#define UC_API_MINOR 0 /* Macro to create combined version which can be compared to diff --git a/pkgconfig.mk b/pkgconfig.mk index 125322eb..e4374b15 100644 --- a/pkgconfig.mk +++ b/pkgconfig.mk @@ -2,8 +2,8 @@ # To be used to generate unicorn.pc for pkg-config # version major & minor -PKG_MAJOR = 0 -PKG_MINOR = 9 +PKG_MAJOR = 1 +PKG_MINOR = 0 # version bugfix level. Example: PKG_EXTRA = 1 PKG_EXTRA = From 17684086371a1f131b63dc0d113ef40ec6bba7b0 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 11 Feb 2016 09:13:45 +0800 Subject: [PATCH 070/126] update CREDITS.TXT --- CREDITS.TXT | 1 + 1 file changed, 1 insertion(+) diff --git a/CREDITS.TXT b/CREDITS.TXT index 5d6cd88e..049e9b56 100644 --- a/CREDITS.TXT +++ b/CREDITS.TXT @@ -54,3 +54,4 @@ Nguyen Tan Cong Loi Anh Tuan Shaun Wheelhouse: Homebrew package Kamil Rytarowski: Pkgsrc package +Zak Escano: MSVC binding From 80b0356a86ce0a6bd2fca8563f5c6aa8cd048f00 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 11 Feb 2016 09:27:30 +0800 Subject: [PATCH 071/126] fix a comment in uc_hook_add() for UC_HOOK_INSN --- uc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uc.c b/uc.c index 169da7b6..d7492bae 100644 --- a/uc.c +++ b/uc.c @@ -983,7 +983,7 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, hook->refs = 0; *hh = (uc_hook)hook; - // everybody but HOOK_INSN gets begin/end, so exit early here. + // UC_HOOK_INSN has an extra argument for instruction ID if (type & UC_HOOK_INSN) { va_list valist; From 5719481e3ffa66e7b9829f25dc693dd9fc0caf04 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 11 Feb 2016 17:53:51 +0800 Subject: [PATCH 072/126] move memory_overlap() around from mem_map() to mem_map_check(). this fixes test_mem_map.c in issue #420 --- uc.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/uc.c b/uc.c index ab466601..4eb04f8f 100644 --- a/uc.c +++ b/uc.c @@ -622,10 +622,6 @@ static uc_err mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t per { MemoryRegion **regions; - // this area overlaps existing mapped regions? - if (memory_overlap(uc, address, size)) - return UC_ERR_MAP; - if (block == NULL) return UC_ERR_NOMEM; @@ -666,6 +662,11 @@ static uc_err mem_map_check(uc_engine *uc, uint64_t address, size_t size, uint32 if ((perms & ~UC_PROT_ALL) != 0) return UC_ERR_ARG; + // this area overlaps existing mapped regions? + if (memory_overlap(uc, address, size)) { + return UC_ERR_MAP; + } + return UC_ERR_OK; } From bfbe91834e411700bc321852b83dfe279467a1d1 Mon Sep 17 00:00:00 2001 From: coco Date: Thu, 11 Feb 2016 15:02:14 +0100 Subject: [PATCH 073/126] two more testcases --- tests/regress/mem_fuzz.c | 14 ++++++------ tests/unit/test_mem_map.c | 48 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/tests/regress/mem_fuzz.c b/tests/regress/mem_fuzz.c index aee3cdb0..bbf37eec 100644 --- a/tests/regress/mem_fuzz.c +++ b/tests/regress/mem_fuzz.c @@ -44,14 +44,14 @@ uint64_t get_aligned_len(){ void perform_map_step(uc_engine *uc){ uint64_t addr = get_aligned_addr(); uint64_t len = get_aligned_len(); - printf("map(0x%"PRIx64",0x%"PRIx64"); //%d\n", addr, len, step); + printf("map(uc,0x%"PRIx64",0x%"PRIx64"); //%d\n", addr, len, step); uc_mem_map(uc, addr, len, UC_PROT_READ | UC_PROT_WRITE); } void perform_unmap_step(uc_engine *uc){ uint64_t addr = get_aligned_addr(); uint64_t len = get_aligned_len(); - printf("unmap(0x%"PRIx64",0x%"PRIx64"); //%d\n", addr, len, step); + printf("unmap(uc,0x%"PRIx64",0x%"PRIx64"); //%d\n", addr, len, step); uc_mem_unmap(uc, addr, len); } @@ -60,7 +60,7 @@ void perform_write_step(uc_engine *uc){ memset(buff, 0, 4096*4); uint64_t addr = get_addr(); uint64_t len = get_len()%(4096*3); - printf("write(0x%"PRIx64",0x%"PRIx64"); //%d\n", addr, len, step); + printf("write(uc,0x%"PRIx64",0x%"PRIx64"); //%d\n", addr, len, step); uc_mem_write(uc, addr, buff, len); } @@ -68,16 +68,16 @@ void perform_read_step(uc_engine *uc){ char* buff[4096*4]; uint64_t addr = get_addr(); uint64_t len = get_len()%(4096*3); - printf("read(0x%"PRIx64",0x%"PRIx64"); //%d\n", addr, len, step); + printf("read(uc,0x%"PRIx64",0x%"PRIx64"); //%d\n", addr, len, step); uc_mem_read(uc, addr, buff, len); } void perform_fuzz_step(uc_engine *uc){ - switch( ((uint32_t)rand())%2 ){ + switch( ((uint32_t)rand())%4 ){ case 0: perform_map_step(uc); break; case 1: perform_unmap_step(uc); break; - //case 2: perform_read_step(uc); break; - //case 3: perform_write_step(uc); break; + case 2: perform_read_step(uc); break; + case 3: perform_write_step(uc); break; } } diff --git a/tests/unit/test_mem_map.c b/tests/unit/test_mem_map.c index 6b743f0c..303a370b 100644 --- a/tests/unit/test_mem_map.c +++ b/tests/unit/test_mem_map.c @@ -158,6 +158,52 @@ static void test_strange_map(void **state) uc_mem_unmap(uc, 0x0,0x1000); } +void write(uc_engine* uc, uint64_t addr, uint64_t len){ + uint8_t* buff = alloca(len); + memset(buff,0,len); + uc_mem_write(uc, addr, buff, len); + +} + +void read(uc_engine* uc, uint64_t addr, uint64_t len){ + uint8_t* buff = alloca(len); + uc_mem_read(uc, addr, buff, len); +} + +void map(uc_engine* uc, uint64_t addr, uint64_t len){ + uc_mem_map(uc, addr, len, UC_PROT_READ | UC_PROT_WRITE); +} + +void unmap(uc_engine* uc, uint64_t addr, uint64_t len){ + uc_mem_unmap(uc, addr, len); +} + +//most likely same bug as in test_strange_map, but looked different in fuzzer (sefault instead of assertion fail) +static void test_assertion_fail(void **state){ + uc_engine *uc = *state; + + map(uc,0x2000,0x4000); //5 + unmap(uc,0x3000,0x2000); //11 + map(uc,0x0,0x2000); //23 + map(uc,0x3000,0x2000); //24 + map(uc,0x9000,0x4000); //32 + map(uc,0x8000,0x1000); //34 + unmap(uc,0x1000,0x4000); //35 +} + +static void test_bad_offset(void **state){ + uc_engine *uc = *state; + map(uc,0x9000,0x4000); //17 + map(uc,0x4000,0x2000); //32 + unmap(uc,0x5000,0x1000); //35 + map(uc,0x0,0x1000); //42 + map(uc,0x5000,0x4000); //51 + map(uc,0x2000,0x1000); //53 + map(uc,0x1000,0x1000); //55 + unmap(uc,0x7000,0x3000); //58 + unmap(uc,0x5000,0x1000); //59 + unmap(uc,0x4000,0x2000); //70 +} @@ -167,6 +213,8 @@ int main(void) { test(test_basic), //test(test_bad_read), //test(test_bad_write), + test(test_bad_offset), + test(test_assertion_fail), test(test_bad_unmap), test(test_rw_across_boundaries), test(test_unmap_double_map), From 95beec805cbe3275788709c3b468a8c73f8e1297 Mon Sep 17 00:00:00 2001 From: coco Date: Thu, 11 Feb 2016 16:38:50 +0100 Subject: [PATCH 074/126] fixed memcpy that should be memmove --- qemu/memory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu/memory.c b/qemu/memory.c index 26683230..af38155f 100644 --- a/qemu/memory.c +++ b/qemu/memory.c @@ -85,7 +85,7 @@ void memory_unmap(struct uc_struct *uc, MemoryRegion *mr) if (uc->mapped_blocks[i] == mr) { uc->mapped_block_count--; //shift remainder of array down over deleted pointer - memcpy(&uc->mapped_blocks[i], &uc->mapped_blocks[i + 1], sizeof(MemoryRegion*) * (uc->mapped_block_count - i)); + memmove(&uc->mapped_blocks[i], &uc->mapped_blocks[i + 1], sizeof(MemoryRegion*) * (uc->mapped_block_count - i)); mr->destructor(mr); g_free((char *)mr->name); g_free(mr->ioeventfds); From 3bd7fa4bfe37b276714f2ca2dcc1e291066f85c6 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Fri, 12 Feb 2016 13:48:58 +0800 Subject: [PATCH 075/126] chmod -x qemu/target-i386/unicorn.c --- qemu/target-i386/unicorn.c | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 qemu/target-i386/unicorn.c diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c old mode 100755 new mode 100644 From f267ff2b17235c925dce02b3aa025304837d8983 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Mon, 15 Feb 2016 10:27:20 +0800 Subject: [PATCH 076/126] Update unicorn.h remove an outdated line on UC_QUERY_MODE --- include/unicorn/unicorn.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 2a556841..ae8cd736 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -261,7 +261,6 @@ typedef struct uc_mem_region { // All type of queries for uc_query() API. typedef enum uc_query_type { // Dynamically query current hardware mode. - // For ARM, uc_query() return 1 for Thumb mode, and 0 for Arm mode UC_QUERY_MODE = 1, } uc_query_type; From 8962adc9c5d1f8dfd4db9460989943a0e665a99b Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Mon, 15 Feb 2016 15:51:14 +0800 Subject: [PATCH 077/126] sparc: use power_down to terminate emulation, rather than using trap. this fix hangup issue of tests/regress/sparc_reg.py --- qemu/target-sparc/translate.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/qemu/target-sparc/translate.c b/qemu/target-sparc/translate.c index a7f067cf..77dc4cb8 100644 --- a/qemu/target-sparc/translate.c +++ b/qemu/target-sparc/translate.c @@ -2630,12 +2630,6 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn, bool hook_ins tcg_gen_debug_insn_start(tcg_ctx, dc->pc); } - // end address tells us to stop emulation - if (dc->pc == dc->uc->addr_end) { - insn = 0x91d02000; // generate TRAP to end this TB - hook_insn = false; // do not hook this instruction - } - // Unicorn: trace this instruction on request if (hook_insn && HOOK_EXISTS_BOUNDED(dc->uc, UC_HOOK_CODE, dc->pc)) { gen_uc_tracecode(tcg_ctx, 4, UC_HOOK_CODE_IDX, dc->uc, dc->pc); @@ -5405,9 +5399,8 @@ static inline void gen_intermediate_code_internal(SPARCCPU *cpu, // early check to see if the address of this block is the until address if (pc_start == env->uc->addr_end) { gen_tb_start(tcg_ctx); - insn = 0x91d02000; // generate TRAP to end this TB - disas_sparc_insn(dc, insn, false); - goto exit_gen_loop; + gen_helper_power_down(tcg_ctx, tcg_ctx->cpu_env); + goto done_generating; } max_insns = tb->cflags & CF_COUNT_MASK; From 8bf1257ac756b21067b975c30a55b6b33b4d7973 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Wed, 17 Feb 2016 23:24:10 +0800 Subject: [PATCH 078/126] update CREDITS.TXT --- CREDITS.TXT | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CREDITS.TXT b/CREDITS.TXT index 049e9b56..695b73d5 100644 --- a/CREDITS.TXT +++ b/CREDITS.TXT @@ -55,3 +55,6 @@ Loi Anh Tuan Shaun Wheelhouse: Homebrew package Kamil Rytarowski: Pkgsrc package Zak Escano: MSVC binding +Chris Eagle: Java binding +Ryan Hileman: Go binding +Antonio Parata: .NET binding From de5a887ed299caa62bf040da130ec628a145ce39 Mon Sep 17 00:00:00 2001 From: emdel Date: Wed, 17 Feb 2016 13:56:20 -0800 Subject: [PATCH 079/126] testcase to set ZF and modify eflags --- tests/regress/jumping.py | 167 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 tests/regress/jumping.py diff --git a/tests/regress/jumping.py b/tests/regress/jumping.py new file mode 100644 index 00000000..39172a5a --- /dev/null +++ b/tests/regress/jumping.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python +# Mariano Graziano + +from unicorn import * +from unicorn.x86_const import * + +import regress + +#echo -ne "\x48\x31\xc0\x48\xb8\x04\x00\x00\x00\x00\x00\x00\x00\x48\x3d\x05\x00\x00\x00\x74\x05\xe9\x0f\x00\x00\x00\x48\xba\xbe\xba\x00\x00\x00\x00\x00\x00\xe9\x0f\x00\x00\x00\x48\xba\xca\xc0\x00\x00\x00\x00\x00\x00\xe9\x00\x00\x00\x00\x90" | ndisasm - -b64 +#00000000 4831C0 xor rax,rax +#00000003 48B8040000000000 mov rax,0x4 +# -0000 +#0000000D 483D05000000 cmp rax,0x5 +#00000013 7405 jz 0x1a +#00000015 E90F000000 jmp qword 0x29 +#0000001A 48BABEBA00000000 mov rdx,0xbabe +# -0000 +#00000024 E90F000000 jmp qword 0x38 +#00000029 48BACAC000000000 mov rdx,0xc0ca +# -0000 +#00000033 E900000000 jmp qword 0x38 +#00000038 90 nop + + +mu = 0 +zf = 1 # (0:clear, 1:set) + + +class Init(regress.RegressTest): + def clear_zf(self): + eflags_cur = mu.reg_read(UC_X86_REG_EFLAGS) + eflags = eflags_cur & ~(1 << 6) + #eflags = 0x0 + print "[clear_zf] - eflags from %x to %x" % (eflags_cur, eflags) + if eflags != eflags_cur: + print "[clear_zf] - writing new eflags..." + mu.reg_write(UC_X86_REG_EFLAGS, eflags) + + def set_zf(self): + eflags_cur = mu.reg_read(UC_X86_REG_EFLAGS) + eflags = eflags_cur | (1 << 6) + #eflags = 0xFFFFFFFF + print "[set_zf] - eflags from %x to %x" % (eflags_cur, eflags) + if eflags != eflags_cur: + print "[set_zf] - writing new eflags..." + mu.reg_write(UC_X86_REG_EFLAGS, eflags) + + def handle_zf(self, zf): + print "[handle_zf] - eflags " , zf + if zf == 0: self.clear_zf() + else: self.set_zf() + + def multipath(self): + print "[multipath] - handling ZF (%s) - default" % zf + self.handle_zf(zf) + + # callback for tracing basic blocks + def hook_block(self, uc, address, size, user_data): + print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size)) + + # callback for tracing instructions + def hook_code(self, uc, address, size, user_data): + print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size)) + rax = mu.reg_read(UC_X86_REG_RAX) + rbx = mu.reg_read(UC_X86_REG_RBX) + rcx = mu.reg_read(UC_X86_REG_RCX) + rdx = mu.reg_read(UC_X86_REG_RDX) + rsi = mu.reg_read(UC_X86_REG_RSI) + rdi = mu.reg_read(UC_X86_REG_RDI) + r8 = mu.reg_read(UC_X86_REG_R8) + r9 = mu.reg_read(UC_X86_REG_R9) + r10 = mu.reg_read(UC_X86_REG_R10) + r11 = mu.reg_read(UC_X86_REG_R11) + r12 = mu.reg_read(UC_X86_REG_R12) + r13 = mu.reg_read(UC_X86_REG_R13) + r14 = mu.reg_read(UC_X86_REG_R14) + r15 = mu.reg_read(UC_X86_REG_R15) + eflags = mu.reg_read(UC_X86_REG_EFLAGS) + + print(">>> RAX = %x" %rax) + print(">>> RBX = %x" %rbx) + print(">>> RCX = %x" %rcx) + print(">>> RDX = %x" %rdx) + print(">>> RSI = %x" %rsi) + print(">>> RDI = %x" %rdi) + print(">>> R8 = %x" %r8) + print(">>> R9 = %x" %r9) + print(">>> R10 = %x" %r10) + print(">>> R11 = %x" %r11) + print(">>> R12 = %x" %r12) + print(">>> R13 = %x" %r13) + print(">>> R14 = %x" %r14) + print(">>> R15 = %x" %r15) + print(">>> ELAGS = %x" %eflags) + print "-"*11 + self.multipath() + print "-"*11 + + # callback for tracing memory access (READ or WRITE) + def hook_mem_access(self, uc, access, address, size, value, user_data): + if access == UC_MEM_WRITE: + print(">>> Memory is being WRITE at 0x%x, data size = %u, data value = 0x%x" \ + %(address, size, value)) + else: # READ + print(">>> Memory is being READ at 0x%x, data size = %u" \ + %(address, size)) + + # callback for tracing invalid memory access (READ or WRITE) + def hook_mem_invalid(self, uc, access, address, size, value, user_data): + print("[ HOOK_MEM_INVALID - Address: %s ]" % hex(address)) + if access == UC_MEM_WRITE_UNMAPPED: + print(">>> Missing memory is being WRITE at 0x%x, data size = %u, data value = 0x%x" %(address, size, value)) + return True + else: + print(">>> Missing memory is being READ at 0x%x, data size = %u, data value = 0x%x" %(address, size, value)) + return True + + + def hook_mem_fetch_unmapped(self, uc, access, address, size, value, user_data): + print("[ HOOK_MEM_FETCH - Address: %s ]" % hex(address)) + print("[ mem_fetch_unmapped: faulting address at %s ]" % hex(address).strip("L")) + return True + + def runTest(self): + global mu + + JUMP = "\x48\x31\xc0\x48\xb8\x04\x00\x00\x00\x00\x00\x00\x00\x48\x3d\x05\x00\x00\x00\x74\x05\xe9\x0f\x00\x00\x00\x48\xba\xbe\xba\x00\x00\x00\x00\x00\x00\xe9\x0f\x00\x00\x00\x48\xba\xca\xc0\x00\x00\x00\x00\x00\x00\xe9\x00\x00\x00\x00\x90" + + ADDRESS = 0x1000000 + + print("Emulate x86_64 code") + # Initialize emulator in X86-64bit mode + mu = Uc(UC_ARCH_X86, UC_MODE_64) + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, JUMP) + + # setup stack + mu.reg_write(UC_X86_REG_RSP, ADDRESS + 0x200000) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, self.hook_block) + + # tracing all instructions in range [ADDRESS, ADDRESS+0x60] + mu.hook_add(UC_HOOK_CODE, self.hook_code, None, ADDRESS, ADDRESS+0x60) + + # tracing all memory READ & WRITE access + mu.hook_add(UC_HOOK_MEM_WRITE, self.hook_mem_access) + mu.hook_add(UC_HOOK_MEM_READ, self.hook_mem_access) + mu.hook_add(UC_HOOK_MEM_FETCH_UNMAPPED, self.hook_mem_fetch_unmapped) + mu.hook_add(UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, self.hook_mem_invalid) + + try: + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + len(JUMP)) + except UcError as e: + print("ERROR: %s" % e) + + # now print out some registers + print(">>> Emulation done. Below is the CPU context") + + +if __name__ == '__main__': + regress.main() From 6e5a3a6d5b5dd3e945545d2d7b1c413abe4c8f20 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 18 Feb 2016 21:58:48 +0800 Subject: [PATCH 080/126] regress: chmod +x jumping.py --- tests/regress/jumping.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 tests/regress/jumping.py diff --git a/tests/regress/jumping.py b/tests/regress/jumping.py old mode 100644 new mode 100755 From 0383db9d279658a9bc1d992fbeff35db0cae887e Mon Sep 17 00:00:00 2001 From: emdel Date: Thu, 18 Feb 2016 06:21:04 -0800 Subject: [PATCH 081/126] Added assert --- tests/regress/jumping.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/regress/jumping.py b/tests/regress/jumping.py index 39172a5a..fdddc424 100755 --- a/tests/regress/jumping.py +++ b/tests/regress/jumping.py @@ -23,7 +23,7 @@ import regress mu = 0 -zf = 1 # (0:clear, 1:set) +zf = 0 # (0:clear, 1:set) class Init(regress.RegressTest): @@ -159,8 +159,8 @@ class Init(regress.RegressTest): except UcError as e: print("ERROR: %s" % e) - # now print out some registers - print(">>> Emulation done. Below is the CPU context") + rdx = mu.reg_read(UC_X86_REG_RDX) + self.assertEqual(rdx, 0xbabe, "RDX contains the wrong value. Eflags modification failed.") if __name__ == '__main__': From f010219a0febd7bad1521a658d2e3e8a072147cc Mon Sep 17 00:00:00 2001 From: emdel Date: Thu, 18 Feb 2016 06:29:59 -0800 Subject: [PATCH 082/126] zf set to 1 --- tests/regress/jumping.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regress/jumping.py b/tests/regress/jumping.py index fdddc424..265ec075 100755 --- a/tests/regress/jumping.py +++ b/tests/regress/jumping.py @@ -23,7 +23,7 @@ import regress mu = 0 -zf = 0 # (0:clear, 1:set) +zf = 1 # (0:clear, 1:set) class Init(regress.RegressTest): From b7d55e2d67daf88e5c74257ec65f619099e70674 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 21 Feb 2016 21:21:15 +0800 Subject: [PATCH 083/126] update CREDITS.TXT --- CREDITS.TXT | 1 + 1 file changed, 1 insertion(+) diff --git a/CREDITS.TXT b/CREDITS.TXT index 695b73d5..e4319580 100644 --- a/CREDITS.TXT +++ b/CREDITS.TXT @@ -58,3 +58,4 @@ Zak Escano: MSVC binding Chris Eagle: Java binding Ryan Hileman: Go binding Antonio Parata: .NET binding +Jonathon Reinhart: C unit test From 2ab2b229ce1d6c158fa09fea474d69e6b647c69a Mon Sep 17 00:00:00 2001 From: Ramirez57 Date: Mon, 22 Feb 2016 00:03:14 -0500 Subject: [PATCH 084/126] test case: x86 guest paging Test case for x86 paging using virtual addresses mapped by Unicorn, as well as unmapped. Attempting to read/write from virtual address ranges unmapped by Unicorn wrongly causes protection faults, even when the virtual address points to read/write regions of Unicorn memory. --- tests/unit/Makefile | 4 +- tests/unit/test_x86_soft_paging.c | 210 ++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 tests/unit/test_x86_soft_paging.c diff --git a/tests/unit/Makefile b/tests/unit/Makefile index 67376fd2..d08671d1 100644 --- a/tests/unit/Makefile +++ b/tests/unit/Makefile @@ -5,7 +5,7 @@ CFLAGS += -lcmocka -lunicorn CFLAGS += -I ../../include ALL_TESTS = test_sanity test_x86 test_mem_map test_mem_high test_mem_map_ptr \ - test_tb_x86 test_multihook test_pc_change + test_tb_x86 test_multihook test_pc_change test_x86_soft_paging .PHONY: all all: ${ALL_TESTS} @@ -25,6 +25,7 @@ test: ${ALL_TESTS} ./test_tb_x86 ./test_multihook ./test_pc_change + ./test_x86_soft_paging test_sanity: test_sanity.c test_x86: test_x86.c @@ -34,6 +35,7 @@ test_mem_high: test_mem_high.c test_tb_x86: test_tb_x86.c test_multihook: test_multihook.c test_pc_change: test_pc_change.c +test_x86_soft_paging: test_x86_soft_paging.c ${ALL_TESTS}: ${CC} ${CFLAGS} -o $@ $^ diff --git a/tests/unit/test_x86_soft_paging.c b/tests/unit/test_x86_soft_paging.c new file mode 100644 index 00000000..b3a931fc --- /dev/null +++ b/tests/unit/test_x86_soft_paging.c @@ -0,0 +1,210 @@ +#include "unicorn_test.h" +#include + +/* + Two tests here for software paging + Low paging: Test paging using virtual addresses already mapped by Unicorn + High paging: Test paging using virtual addresses not mapped by Unicorn +*/ + +static void test_low_paging(void **state) { + uc_engine *uc; + uc_err err; + int r_eax; + + /* The following x86 code will map emulated physical memory + to virtual memory using pages and attempt + to read/write from virtual memory + + Specifically, the virtual memory address range + has been mapped by Unicorn (0x7FF000 - 0x7FFFFF) + + Memory area purposes: + 0x1000 = page directory + 0x2000 = page table (identity map first 4 MiB) + 0x3000 = page table (0x007FF000 -> 0x00004000) + 0x4000 = data area (0xBEEF) + */ + const uint8_t code[] = { + /* Zero memory for page directories and page tables */ + 0xBF, 0x00, 0x10, 0x00, 0x00, /* MOV EDI, 0x1000 */ + 0xB9, 0x00, 0x10, 0x00, 0x00, /* MOV ECX, 0x1000 */ + 0x31, 0xC0, /* XOR EAX, EAX */ + 0xF3, 0xAB, /* REP STOSD */ + + /* Load DWORD [0x4000] with 0xDEADBEEF to retrieve later */ + 0xBF, 0x00, 0x40, 0x00, 0x00, /* MOV EDI, 0x4000 */ + 0xB8, 0xEF, 0xBE, 0x00, 0x00, /* MOV EAX, 0xBEEF */ + 0x89, 0x07, /* MOV [EDI], EAX */ + + /* Identity map the first 4MiB of memory */ + 0xB9, 0x00, 0x04, 0x00, 0x00, /* MOV ECX, 0x400 */ + 0xBF, 0x00, 0x20, 0x00, 0x00, /* MOV EDI, 0x2000 */ + 0xB8, 0x03, 0x00, 0x00, 0x00, /* MOV EAX, 3 */ + /* aLoop: */ + 0xAB, /* STOSD */ + 0x05, 0x00, 0x10, 0x00, 0x00, /* ADD EAX, 0x1000 */ + 0xE2, 0xF8, /* LOOP aLoop */ + + /* Map physical address 0x4000 to virtual address 0x7FF000 */ + 0xBF, 0xFC, 0x3F, 0x00, 0x00, /* MOV EDI, 0x3FFC */ + 0xB8, 0x03, 0x40, 0x00, 0x00, /* MOV EAX, 0x4003 */ + 0x89, 0x07, /* MOV [EDI], EAX */ + + /* Add page tables into page directory */ + 0xBF, 0x00, 0x10, 0x00, 0x00, /* MOV EDI, 0x1000 */ + 0xB8, 0x03, 0x20, 0x00, 0x00, /* MOV EAX, 0x2003 */ + 0x89, 0x07, /* MOV [EDI], EAX */ + 0xBF, 0x04, 0x10, 0x00, 0x00, /* MOV EDI, 0x1004 */ + 0xB8, 0x03, 0x30, 0x00, 0x00, /* MOV EAX, 0x3003 */ + 0x89, 0x07, /* MOV [EDI], EAX */ + + /* Load the page directory register */ + 0xB8, 0x00, 0x10, 0x00, 0x00, /* MOV EAX, 0x1000 */ + 0x0F, 0x22, 0xD8, /* MOV CR3, EAX */ + + /* Enable paging */ + 0x0F, 0x20, 0xC0, /* MOV EAX, CR0 */ + 0x0D, 0x00, 0x00, 0x00, 0x80, /* OR EAX, 0x80000000 */ + 0x0F, 0x22, 0xC0, /* MOV CR0, EAX */ + + /* Clear EAX */ + 0x31, 0xC0, /* XOR EAX, EAX */ + + /* Load using virtual memory address; EAX = 0xBEEF */ + 0xBE, 0x00, 0xF0, 0x7F, 0x00, /* MOV ESI, 0x7FF000 */ + 0x8B, 0x06, /* MOV EAX, [ESI] */ + 0xF4, /* HLT */ + }; + + /* Initialise X86-32bit mode */ + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); + uc_assert_success(err); + + /* Map 8MB of memory at base address 0 */ + err = uc_mem_map(uc, 0, (8 * 1024 * 1024), UC_PROT_ALL); + uc_assert_success(err); + + /* Write code into memory at address 0 */ + err = uc_mem_write(uc, 0, code, sizeof(code)); + uc_assert_success(err); + + /* Start emulation */ + err = uc_emu_start(uc, 0, sizeof(code), 0, 0); + uc_assert_success(err); + + /* The code should have loaded 0xBEEF into EAX */ + uc_reg_read(uc, UC_X86_REG_EAX, &r_eax); + assert_int_equal(r_eax, 0xBEEF); + + uc_close(uc); +} + + +/****************************************************************************/ + + +static void test_high_paging(void **state) { + uc_engine *uc; + uc_err err; + int r_eax; + + /* The following x86 code will map emulated physical memory + to virtual memory using pages and attempt + to read/write from virtual memory + + Specifically, the virtual memory address range + has not been mapped by UC (0xFFFFF000 - 0xFFFFFFFF) + + Memory area purposes: + 0x1000 = page directory + 0x2000 = page table (identity map first 4 MiB) + 0x3000 = page table (0xFFFFF000 -> 0x00004000) + 0x4000 = data area (0xDEADBEEF) + */ + const uint8_t code[] = { + /* Zero memory for page directories and page tables */ + 0xBF, 0x00, 0x10, 0x00, 0x00, /* MOV EDI, 0x1000 */ + 0xB9, 0x00, 0x10, 0x00, 0x00, /* MOV ECX, 0x1000 */ + 0x31, 0xC0, /* XOR EAX, EAX */ + 0xF3, 0xAB, /* REP STOSD */ + + /* Load DWORD [0x4000] with 0xDEADBEEF to retrieve later */ + 0xBF, 0x00, 0x40, 0x00, 0x00, /* MOV EDI, 0x4000 */ + 0xB8, 0xEF, 0xBE, 0x00, 0x00, /* MOV EAX, 0xBEEF */ + 0x89, 0x07, /* MOV [EDI], EAX */ + + /* Identity map the first 4MiB of memory */ + 0xB9, 0x00, 0x04, 0x00, 0x00, /* MOV ECX, 0x400 */ + 0xBF, 0x00, 0x20, 0x00, 0x00, /* MOV EDI, 0x2000 */ + 0xB8, 0x03, 0x00, 0x00, 0x00, /* MOV EAX, 3 */ + /* aLoop: */ + 0xAB, /* STOSD */ + 0x05, 0x00, 0x10, 0x00, 0x00, /* ADD EAX, 0x1000 */ + 0xE2, 0xF8, /* LOOP aLoop */ + + /* Map physical address 0x4000 to virtual address 0xFFFFF000 */ + 0xBF, 0xFC, 0x3F, 0x00, 0x00, /* MOV EDI, 0x3FFC */ + 0xB8, 0x03, 0x40, 0x00, 0x00, /* MOV EAX, 0x4003 */ + 0x89, 0x07, /* MOV [EDI], EAX */ + + /* Add page tables into page directory */ + 0xBF, 0x00, 0x10, 0x00, 0x00, /* MOV EDI, 0x1000 */ + 0xB8, 0x03, 0x20, 0x00, 0x00, /* MOV EAX, 0x2003 */ + 0x89, 0x07, /* MOV [EDI], EAX */ + 0xBF, 0xFC, 0x1F, 0x00, 0x00, /* MOV EDI, 0x1FFC */ + 0xB8, 0x03, 0x30, 0x00, 0x00, /* MOV EAX, 0x3003 */ + 0x89, 0x07, /* MOV [EDI], EAX */ + + /* Load the page directory register */ + 0xB8, 0x00, 0x10, 0x00, 0x00, /* MOV EAX, 0x1000 */ + 0x0F, 0x22, 0xD8, /* MOV CR3, EAX */ + + /* Enable paging */ + 0x0F, 0x20, 0xC0, /* MOV EAX, CR0 */ + 0x0D, 0x00, 0x00, 0x00, 0x80, /* OR EAX, 0x80000000 */ + 0x0F, 0x22, 0xC0, /* MOV CR0, EAX */ + + /* Clear EAX */ + 0x31, 0xC0, /* XOR EAX, EAX */ + + /* Load using virtual memory address; EAX = 0xBEEF */ + 0xBE, 0x00, 0xF0, 0xFF, 0xFF, /* MOV ESI, 0xFFFFF000 */ + 0x8B, 0x06, /* MOV EAX, [ESI] */ + 0xF4, /* HLT */ + }; + + /* Initialise X86-32bit mode */ + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); + uc_assert_success(err); + + /* Map 4MB of memory at base address 0 */ + err = uc_mem_map(uc, 0, (4 * 1024 * 1024), UC_PROT_ALL); + uc_assert_success(err); + + /* Write code into memory at address 0 */ + err = uc_mem_write(uc, 0, code, sizeof(code)); + uc_assert_success(err); + + /* Start emulation */ + err = uc_emu_start(uc, 0, sizeof(code), 0, 0); + uc_assert_success(err); + + /* The code should have loaded 0xBEEF into EAX */ + uc_reg_read(uc, UC_X86_REG_EAX, &r_eax); + assert_int_equal(r_eax, 0xBEEF); + + uc_close(uc); +} + + +/****************************************************************************/ + + +int main(void) { + const struct CMUnitTests tests[] = { + cmocka_unit_test(test_low_paging), + cmocka_unit_test(test_high_paging), + }; + return cmocka_run_group_tests(tests, NULL, NULL); +} From 2f28f3f210432bdfdd944015699367ab6edfbd0b Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Mon, 22 Feb 2016 14:01:00 +0800 Subject: [PATCH 085/126] unit: make test_x86_soft_paging.c compilable. also update .gitignore for its binary --- .gitignore | 1 + tests/unit/test_x86_soft_paging.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8d291285..ae776b30 100644 --- a/.gitignore +++ b/.gitignore @@ -138,6 +138,7 @@ test_tb_x86 test_multihook test_pc_change mem_fuzz +test_x86_soft_paging ################# diff --git a/tests/unit/test_x86_soft_paging.c b/tests/unit/test_x86_soft_paging.c index b3a931fc..1b3aaeef 100644 --- a/tests/unit/test_x86_soft_paging.c +++ b/tests/unit/test_x86_soft_paging.c @@ -202,7 +202,7 @@ static void test_high_paging(void **state) { int main(void) { - const struct CMUnitTests tests[] = { + const struct CMUnitTest tests[] = { cmocka_unit_test(test_low_paging), cmocka_unit_test(test_high_paging), }; From aabcb95f0120151b47b549eaa50899b6abc3d9ce Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Mon, 22 Feb 2016 14:02:28 +0800 Subject: [PATCH 086/126] unit: remove ^M from test_x86_soft_paging.c --- tests/unit/test_x86_soft_paging.c | 420 +++++++++++++++--------------- 1 file changed, 210 insertions(+), 210 deletions(-) diff --git a/tests/unit/test_x86_soft_paging.c b/tests/unit/test_x86_soft_paging.c index 1b3aaeef..ffba0155 100644 --- a/tests/unit/test_x86_soft_paging.c +++ b/tests/unit/test_x86_soft_paging.c @@ -1,210 +1,210 @@ -#include "unicorn_test.h" -#include - -/* - Two tests here for software paging - Low paging: Test paging using virtual addresses already mapped by Unicorn - High paging: Test paging using virtual addresses not mapped by Unicorn -*/ - -static void test_low_paging(void **state) { - uc_engine *uc; - uc_err err; - int r_eax; - - /* The following x86 code will map emulated physical memory - to virtual memory using pages and attempt - to read/write from virtual memory - - Specifically, the virtual memory address range - has been mapped by Unicorn (0x7FF000 - 0x7FFFFF) - - Memory area purposes: - 0x1000 = page directory - 0x2000 = page table (identity map first 4 MiB) - 0x3000 = page table (0x007FF000 -> 0x00004000) - 0x4000 = data area (0xBEEF) - */ - const uint8_t code[] = { - /* Zero memory for page directories and page tables */ - 0xBF, 0x00, 0x10, 0x00, 0x00, /* MOV EDI, 0x1000 */ - 0xB9, 0x00, 0x10, 0x00, 0x00, /* MOV ECX, 0x1000 */ - 0x31, 0xC0, /* XOR EAX, EAX */ - 0xF3, 0xAB, /* REP STOSD */ - - /* Load DWORD [0x4000] with 0xDEADBEEF to retrieve later */ - 0xBF, 0x00, 0x40, 0x00, 0x00, /* MOV EDI, 0x4000 */ - 0xB8, 0xEF, 0xBE, 0x00, 0x00, /* MOV EAX, 0xBEEF */ - 0x89, 0x07, /* MOV [EDI], EAX */ - - /* Identity map the first 4MiB of memory */ - 0xB9, 0x00, 0x04, 0x00, 0x00, /* MOV ECX, 0x400 */ - 0xBF, 0x00, 0x20, 0x00, 0x00, /* MOV EDI, 0x2000 */ - 0xB8, 0x03, 0x00, 0x00, 0x00, /* MOV EAX, 3 */ - /* aLoop: */ - 0xAB, /* STOSD */ - 0x05, 0x00, 0x10, 0x00, 0x00, /* ADD EAX, 0x1000 */ - 0xE2, 0xF8, /* LOOP aLoop */ - - /* Map physical address 0x4000 to virtual address 0x7FF000 */ - 0xBF, 0xFC, 0x3F, 0x00, 0x00, /* MOV EDI, 0x3FFC */ - 0xB8, 0x03, 0x40, 0x00, 0x00, /* MOV EAX, 0x4003 */ - 0x89, 0x07, /* MOV [EDI], EAX */ - - /* Add page tables into page directory */ - 0xBF, 0x00, 0x10, 0x00, 0x00, /* MOV EDI, 0x1000 */ - 0xB8, 0x03, 0x20, 0x00, 0x00, /* MOV EAX, 0x2003 */ - 0x89, 0x07, /* MOV [EDI], EAX */ - 0xBF, 0x04, 0x10, 0x00, 0x00, /* MOV EDI, 0x1004 */ - 0xB8, 0x03, 0x30, 0x00, 0x00, /* MOV EAX, 0x3003 */ - 0x89, 0x07, /* MOV [EDI], EAX */ - - /* Load the page directory register */ - 0xB8, 0x00, 0x10, 0x00, 0x00, /* MOV EAX, 0x1000 */ - 0x0F, 0x22, 0xD8, /* MOV CR3, EAX */ - - /* Enable paging */ - 0x0F, 0x20, 0xC0, /* MOV EAX, CR0 */ - 0x0D, 0x00, 0x00, 0x00, 0x80, /* OR EAX, 0x80000000 */ - 0x0F, 0x22, 0xC0, /* MOV CR0, EAX */ - - /* Clear EAX */ - 0x31, 0xC0, /* XOR EAX, EAX */ - - /* Load using virtual memory address; EAX = 0xBEEF */ - 0xBE, 0x00, 0xF0, 0x7F, 0x00, /* MOV ESI, 0x7FF000 */ - 0x8B, 0x06, /* MOV EAX, [ESI] */ - 0xF4, /* HLT */ - }; - - /* Initialise X86-32bit mode */ - err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); - uc_assert_success(err); - - /* Map 8MB of memory at base address 0 */ - err = uc_mem_map(uc, 0, (8 * 1024 * 1024), UC_PROT_ALL); - uc_assert_success(err); - - /* Write code into memory at address 0 */ - err = uc_mem_write(uc, 0, code, sizeof(code)); - uc_assert_success(err); - - /* Start emulation */ - err = uc_emu_start(uc, 0, sizeof(code), 0, 0); - uc_assert_success(err); - - /* The code should have loaded 0xBEEF into EAX */ - uc_reg_read(uc, UC_X86_REG_EAX, &r_eax); - assert_int_equal(r_eax, 0xBEEF); - - uc_close(uc); -} - - -/****************************************************************************/ - - -static void test_high_paging(void **state) { - uc_engine *uc; - uc_err err; - int r_eax; - - /* The following x86 code will map emulated physical memory - to virtual memory using pages and attempt - to read/write from virtual memory - - Specifically, the virtual memory address range - has not been mapped by UC (0xFFFFF000 - 0xFFFFFFFF) - - Memory area purposes: - 0x1000 = page directory - 0x2000 = page table (identity map first 4 MiB) - 0x3000 = page table (0xFFFFF000 -> 0x00004000) - 0x4000 = data area (0xDEADBEEF) - */ - const uint8_t code[] = { - /* Zero memory for page directories and page tables */ - 0xBF, 0x00, 0x10, 0x00, 0x00, /* MOV EDI, 0x1000 */ - 0xB9, 0x00, 0x10, 0x00, 0x00, /* MOV ECX, 0x1000 */ - 0x31, 0xC0, /* XOR EAX, EAX */ - 0xF3, 0xAB, /* REP STOSD */ - - /* Load DWORD [0x4000] with 0xDEADBEEF to retrieve later */ - 0xBF, 0x00, 0x40, 0x00, 0x00, /* MOV EDI, 0x4000 */ - 0xB8, 0xEF, 0xBE, 0x00, 0x00, /* MOV EAX, 0xBEEF */ - 0x89, 0x07, /* MOV [EDI], EAX */ - - /* Identity map the first 4MiB of memory */ - 0xB9, 0x00, 0x04, 0x00, 0x00, /* MOV ECX, 0x400 */ - 0xBF, 0x00, 0x20, 0x00, 0x00, /* MOV EDI, 0x2000 */ - 0xB8, 0x03, 0x00, 0x00, 0x00, /* MOV EAX, 3 */ - /* aLoop: */ - 0xAB, /* STOSD */ - 0x05, 0x00, 0x10, 0x00, 0x00, /* ADD EAX, 0x1000 */ - 0xE2, 0xF8, /* LOOP aLoop */ - - /* Map physical address 0x4000 to virtual address 0xFFFFF000 */ - 0xBF, 0xFC, 0x3F, 0x00, 0x00, /* MOV EDI, 0x3FFC */ - 0xB8, 0x03, 0x40, 0x00, 0x00, /* MOV EAX, 0x4003 */ - 0x89, 0x07, /* MOV [EDI], EAX */ - - /* Add page tables into page directory */ - 0xBF, 0x00, 0x10, 0x00, 0x00, /* MOV EDI, 0x1000 */ - 0xB8, 0x03, 0x20, 0x00, 0x00, /* MOV EAX, 0x2003 */ - 0x89, 0x07, /* MOV [EDI], EAX */ - 0xBF, 0xFC, 0x1F, 0x00, 0x00, /* MOV EDI, 0x1FFC */ - 0xB8, 0x03, 0x30, 0x00, 0x00, /* MOV EAX, 0x3003 */ - 0x89, 0x07, /* MOV [EDI], EAX */ - - /* Load the page directory register */ - 0xB8, 0x00, 0x10, 0x00, 0x00, /* MOV EAX, 0x1000 */ - 0x0F, 0x22, 0xD8, /* MOV CR3, EAX */ - - /* Enable paging */ - 0x0F, 0x20, 0xC0, /* MOV EAX, CR0 */ - 0x0D, 0x00, 0x00, 0x00, 0x80, /* OR EAX, 0x80000000 */ - 0x0F, 0x22, 0xC0, /* MOV CR0, EAX */ - - /* Clear EAX */ - 0x31, 0xC0, /* XOR EAX, EAX */ - - /* Load using virtual memory address; EAX = 0xBEEF */ - 0xBE, 0x00, 0xF0, 0xFF, 0xFF, /* MOV ESI, 0xFFFFF000 */ - 0x8B, 0x06, /* MOV EAX, [ESI] */ - 0xF4, /* HLT */ - }; - - /* Initialise X86-32bit mode */ - err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); - uc_assert_success(err); - - /* Map 4MB of memory at base address 0 */ - err = uc_mem_map(uc, 0, (4 * 1024 * 1024), UC_PROT_ALL); - uc_assert_success(err); - - /* Write code into memory at address 0 */ - err = uc_mem_write(uc, 0, code, sizeof(code)); - uc_assert_success(err); - - /* Start emulation */ - err = uc_emu_start(uc, 0, sizeof(code), 0, 0); - uc_assert_success(err); - - /* The code should have loaded 0xBEEF into EAX */ - uc_reg_read(uc, UC_X86_REG_EAX, &r_eax); - assert_int_equal(r_eax, 0xBEEF); - - uc_close(uc); -} - - -/****************************************************************************/ - - -int main(void) { - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_low_paging), - cmocka_unit_test(test_high_paging), - }; - return cmocka_run_group_tests(tests, NULL, NULL); -} +#include "unicorn_test.h" +#include + +/* + Two tests here for software paging + Low paging: Test paging using virtual addresses already mapped by Unicorn + High paging: Test paging using virtual addresses not mapped by Unicorn +*/ + +static void test_low_paging(void **state) { + uc_engine *uc; + uc_err err; + int r_eax; + + /* The following x86 code will map emulated physical memory + to virtual memory using pages and attempt + to read/write from virtual memory + + Specifically, the virtual memory address range + has been mapped by Unicorn (0x7FF000 - 0x7FFFFF) + + Memory area purposes: + 0x1000 = page directory + 0x2000 = page table (identity map first 4 MiB) + 0x3000 = page table (0x007FF000 -> 0x00004000) + 0x4000 = data area (0xBEEF) + */ + const uint8_t code[] = { + /* Zero memory for page directories and page tables */ + 0xBF, 0x00, 0x10, 0x00, 0x00, /* MOV EDI, 0x1000 */ + 0xB9, 0x00, 0x10, 0x00, 0x00, /* MOV ECX, 0x1000 */ + 0x31, 0xC0, /* XOR EAX, EAX */ + 0xF3, 0xAB, /* REP STOSD */ + + /* Load DWORD [0x4000] with 0xDEADBEEF to retrieve later */ + 0xBF, 0x00, 0x40, 0x00, 0x00, /* MOV EDI, 0x4000 */ + 0xB8, 0xEF, 0xBE, 0x00, 0x00, /* MOV EAX, 0xBEEF */ + 0x89, 0x07, /* MOV [EDI], EAX */ + + /* Identity map the first 4MiB of memory */ + 0xB9, 0x00, 0x04, 0x00, 0x00, /* MOV ECX, 0x400 */ + 0xBF, 0x00, 0x20, 0x00, 0x00, /* MOV EDI, 0x2000 */ + 0xB8, 0x03, 0x00, 0x00, 0x00, /* MOV EAX, 3 */ + /* aLoop: */ + 0xAB, /* STOSD */ + 0x05, 0x00, 0x10, 0x00, 0x00, /* ADD EAX, 0x1000 */ + 0xE2, 0xF8, /* LOOP aLoop */ + + /* Map physical address 0x4000 to virtual address 0x7FF000 */ + 0xBF, 0xFC, 0x3F, 0x00, 0x00, /* MOV EDI, 0x3FFC */ + 0xB8, 0x03, 0x40, 0x00, 0x00, /* MOV EAX, 0x4003 */ + 0x89, 0x07, /* MOV [EDI], EAX */ + + /* Add page tables into page directory */ + 0xBF, 0x00, 0x10, 0x00, 0x00, /* MOV EDI, 0x1000 */ + 0xB8, 0x03, 0x20, 0x00, 0x00, /* MOV EAX, 0x2003 */ + 0x89, 0x07, /* MOV [EDI], EAX */ + 0xBF, 0x04, 0x10, 0x00, 0x00, /* MOV EDI, 0x1004 */ + 0xB8, 0x03, 0x30, 0x00, 0x00, /* MOV EAX, 0x3003 */ + 0x89, 0x07, /* MOV [EDI], EAX */ + + /* Load the page directory register */ + 0xB8, 0x00, 0x10, 0x00, 0x00, /* MOV EAX, 0x1000 */ + 0x0F, 0x22, 0xD8, /* MOV CR3, EAX */ + + /* Enable paging */ + 0x0F, 0x20, 0xC0, /* MOV EAX, CR0 */ + 0x0D, 0x00, 0x00, 0x00, 0x80, /* OR EAX, 0x80000000 */ + 0x0F, 0x22, 0xC0, /* MOV CR0, EAX */ + + /* Clear EAX */ + 0x31, 0xC0, /* XOR EAX, EAX */ + + /* Load using virtual memory address; EAX = 0xBEEF */ + 0xBE, 0x00, 0xF0, 0x7F, 0x00, /* MOV ESI, 0x7FF000 */ + 0x8B, 0x06, /* MOV EAX, [ESI] */ + 0xF4, /* HLT */ + }; + + /* Initialise X86-32bit mode */ + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); + uc_assert_success(err); + + /* Map 8MB of memory at base address 0 */ + err = uc_mem_map(uc, 0, (8 * 1024 * 1024), UC_PROT_ALL); + uc_assert_success(err); + + /* Write code into memory at address 0 */ + err = uc_mem_write(uc, 0, code, sizeof(code)); + uc_assert_success(err); + + /* Start emulation */ + err = uc_emu_start(uc, 0, sizeof(code), 0, 0); + uc_assert_success(err); + + /* The code should have loaded 0xBEEF into EAX */ + uc_reg_read(uc, UC_X86_REG_EAX, &r_eax); + assert_int_equal(r_eax, 0xBEEF); + + uc_close(uc); +} + + +/****************************************************************************/ + + +static void test_high_paging(void **state) { + uc_engine *uc; + uc_err err; + int r_eax; + + /* The following x86 code will map emulated physical memory + to virtual memory using pages and attempt + to read/write from virtual memory + + Specifically, the virtual memory address range + has not been mapped by UC (0xFFFFF000 - 0xFFFFFFFF) + + Memory area purposes: + 0x1000 = page directory + 0x2000 = page table (identity map first 4 MiB) + 0x3000 = page table (0xFFFFF000 -> 0x00004000) + 0x4000 = data area (0xDEADBEEF) + */ + const uint8_t code[] = { + /* Zero memory for page directories and page tables */ + 0xBF, 0x00, 0x10, 0x00, 0x00, /* MOV EDI, 0x1000 */ + 0xB9, 0x00, 0x10, 0x00, 0x00, /* MOV ECX, 0x1000 */ + 0x31, 0xC0, /* XOR EAX, EAX */ + 0xF3, 0xAB, /* REP STOSD */ + + /* Load DWORD [0x4000] with 0xDEADBEEF to retrieve later */ + 0xBF, 0x00, 0x40, 0x00, 0x00, /* MOV EDI, 0x4000 */ + 0xB8, 0xEF, 0xBE, 0x00, 0x00, /* MOV EAX, 0xBEEF */ + 0x89, 0x07, /* MOV [EDI], EAX */ + + /* Identity map the first 4MiB of memory */ + 0xB9, 0x00, 0x04, 0x00, 0x00, /* MOV ECX, 0x400 */ + 0xBF, 0x00, 0x20, 0x00, 0x00, /* MOV EDI, 0x2000 */ + 0xB8, 0x03, 0x00, 0x00, 0x00, /* MOV EAX, 3 */ + /* aLoop: */ + 0xAB, /* STOSD */ + 0x05, 0x00, 0x10, 0x00, 0x00, /* ADD EAX, 0x1000 */ + 0xE2, 0xF8, /* LOOP aLoop */ + + /* Map physical address 0x4000 to virtual address 0xFFFFF000 */ + 0xBF, 0xFC, 0x3F, 0x00, 0x00, /* MOV EDI, 0x3FFC */ + 0xB8, 0x03, 0x40, 0x00, 0x00, /* MOV EAX, 0x4003 */ + 0x89, 0x07, /* MOV [EDI], EAX */ + + /* Add page tables into page directory */ + 0xBF, 0x00, 0x10, 0x00, 0x00, /* MOV EDI, 0x1000 */ + 0xB8, 0x03, 0x20, 0x00, 0x00, /* MOV EAX, 0x2003 */ + 0x89, 0x07, /* MOV [EDI], EAX */ + 0xBF, 0xFC, 0x1F, 0x00, 0x00, /* MOV EDI, 0x1FFC */ + 0xB8, 0x03, 0x30, 0x00, 0x00, /* MOV EAX, 0x3003 */ + 0x89, 0x07, /* MOV [EDI], EAX */ + + /* Load the page directory register */ + 0xB8, 0x00, 0x10, 0x00, 0x00, /* MOV EAX, 0x1000 */ + 0x0F, 0x22, 0xD8, /* MOV CR3, EAX */ + + /* Enable paging */ + 0x0F, 0x20, 0xC0, /* MOV EAX, CR0 */ + 0x0D, 0x00, 0x00, 0x00, 0x80, /* OR EAX, 0x80000000 */ + 0x0F, 0x22, 0xC0, /* MOV CR0, EAX */ + + /* Clear EAX */ + 0x31, 0xC0, /* XOR EAX, EAX */ + + /* Load using virtual memory address; EAX = 0xBEEF */ + 0xBE, 0x00, 0xF0, 0xFF, 0xFF, /* MOV ESI, 0xFFFFF000 */ + 0x8B, 0x06, /* MOV EAX, [ESI] */ + 0xF4, /* HLT */ + }; + + /* Initialise X86-32bit mode */ + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); + uc_assert_success(err); + + /* Map 4MB of memory at base address 0 */ + err = uc_mem_map(uc, 0, (4 * 1024 * 1024), UC_PROT_ALL); + uc_assert_success(err); + + /* Write code into memory at address 0 */ + err = uc_mem_write(uc, 0, code, sizeof(code)); + uc_assert_success(err); + + /* Start emulation */ + err = uc_emu_start(uc, 0, sizeof(code), 0, 0); + uc_assert_success(err); + + /* The code should have loaded 0xBEEF into EAX */ + uc_reg_read(uc, UC_X86_REG_EAX, &r_eax); + assert_int_equal(r_eax, 0xBEEF); + + uc_close(uc); +} + + +/****************************************************************************/ + + +int main(void) { + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_low_paging), + cmocka_unit_test(test_high_paging), + }; + return cmocka_run_group_tests(tests, NULL, NULL); +} From 693719e732042469e4f5b745698b765d8af317b3 Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Sat, 27 Feb 2016 10:50:51 -0800 Subject: [PATCH 087/126] Go: update hook interface --- bindings/go/unicorn/hook.c | 12 ++++++++---- bindings/go/unicorn/hook.go | 27 +++++++++------------------ bindings/go/unicorn/hook.h | 4 ++-- bindings/go/unicorn/unicorn.go | 2 +- 4 files changed, 20 insertions(+), 25 deletions(-) diff --git a/bindings/go/unicorn/hook.c b/bindings/go/unicorn/hook.c index 4ed41b51..a2b7dc93 100644 --- a/bindings/go/unicorn/hook.c +++ b/bindings/go/unicorn/hook.c @@ -1,12 +1,16 @@ #include #include "_cgo_export.h" -uc_err uc_hook_add_i1(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, int arg1) { - return uc_hook_add(handle, h2, type, callback, (void *)user, arg1); +uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, + void *user_data, uint64_t begin, uint64_t end, ...); + + +uc_err uc_hook_add_wrap(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, uint64_t begin, uint64_t end) { + return uc_hook_add(handle, h2, type, callback, (void *)user, begin, end); } -uc_err uc_hook_add_u2(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, uint64_t arg1, uint64_t arg2) { - return uc_hook_add(handle, h2, type, callback, (void *)user, arg1, arg2); +uc_err uc_hook_add_insn(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, uint64_t begin, uint64_t end, int insn) { + return uc_hook_add(handle, h2, type, callback, (void *)user, begin, end, insn); } void hookCode_cgo(uc_engine *handle, uint64_t addr, uint32_t size, uintptr_t user) { diff --git a/bindings/go/unicorn/hook.go b/bindings/go/unicorn/hook.go index d5dfc874..6591c46c 100644 --- a/bindings/go/unicorn/hook.go +++ b/bindings/go/unicorn/hook.go @@ -63,23 +63,21 @@ func hookX86Syscall(handle unsafe.Pointer, user unsafe.Pointer) { hook.Callback.(func(Unicorn))(hook.Uc) } -func (u *uc) HookAdd(htype int, cb interface{}, extra ...uint64) (Hook, error) { +func (u *uc) HookAdd(htype int, cb interface{}, begin, end uint64, extra ...int) (Hook, error) { var callback unsafe.Pointer - var iarg1 C.int - var uarg1, uarg2 C.uint64_t - rangeMode := false + var insn C.int + var insnMode bool switch htype { case HOOK_BLOCK, HOOK_CODE: - rangeMode = true callback = C.hookCode_cgo case HOOK_MEM_READ, HOOK_MEM_WRITE, HOOK_MEM_READ | HOOK_MEM_WRITE: - rangeMode = true callback = C.hookMemAccess_cgo case HOOK_INTR: callback = C.hookInterrupt_cgo case HOOK_INSN: - iarg1 = C.int(extra[0]) - switch iarg1 { + insn = C.int(extra[0]) + insnMode = true + switch insn { case X86_INS_IN: callback = C.hookX86In_cgo case X86_INS_OUT: @@ -93,7 +91,6 @@ func (u *uc) HookAdd(htype int, cb interface{}, extra ...uint64) (Hook, error) { // special case for mask if htype&(HOOK_MEM_READ_UNMAPPED|HOOK_MEM_WRITE_UNMAPPED|HOOK_MEM_FETCH_UNMAPPED| 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.") @@ -102,16 +99,10 @@ func (u *uc) HookAdd(htype int, cb interface{}, extra ...uint64) (Hook, error) { var h2 C.uc_hook data := &HookData{u, cb} uptr := uintptr(unsafe.Pointer(data)) - if rangeMode { - if len(extra) == 2 { - uarg1 = C.uint64_t(extra[0]) - uarg2 = C.uint64_t(extra[1]) - } else { - uarg1, uarg2 = 1, 0 - } - C.uc_hook_add_u2(u.handle, &h2, C.uc_hook_type(htype), callback, C.uintptr_t(uptr), uarg1, uarg2) + if insnMode { + C.uc_hook_add_wrap(u.handle, &h2, C.uc_hook_type(htype), callback, C.uintptr_t(uptr), C.uint64_t(begin), C.uint64_t(end)) } else { - C.uc_hook_add_i1(u.handle, &h2, C.uc_hook_type(htype), callback, C.uintptr_t(uptr), iarg1) + C.uc_hook_add_insn(u.handle, &h2, C.uc_hook_type(htype), callback, C.uintptr_t(uptr), C.uint64_t(begin), C.uint64_t(end), insn) } hookDataMap[uptr] = data hookToUintptr[Hook(h2)] = uptr diff --git a/bindings/go/unicorn/hook.h b/bindings/go/unicorn/hook.h index 6c209516..35813a0a 100644 --- a/bindings/go/unicorn/hook.h +++ b/bindings/go/unicorn/hook.h @@ -1,5 +1,5 @@ -uc_err uc_hook_add_i1(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, int arg1); -uc_err uc_hook_add_u2(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, uint64_t arg1, uint64_t arg2); +uc_err uc_hook_add_wrap(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, uint64_t begin, uint64_t end); +uc_err uc_hook_add_insn(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, uint64_t begin, uint64_t end, int insn); void hookCode_cgo(uc_engine *handle, uint64_t addr, uint32_t size, uintptr_t user); bool hookMemInvalid_cgo(uc_engine *handle, uc_mem_type type, uint64_t addr, int size, int64_t value, uintptr_t user); void hookMemAccess_cgo(uc_engine *handle, uc_mem_type type, uint64_t addr, int size, int64_t value, uintptr_t user); diff --git a/bindings/go/unicorn/unicorn.go b/bindings/go/unicorn/unicorn.go index 4f6f1f99..1f3e9094 100644 --- a/bindings/go/unicorn/unicorn.go +++ b/bindings/go/unicorn/unicorn.go @@ -39,7 +39,7 @@ type Unicorn interface { Start(begin, until uint64) error StartWithOptions(begin, until uint64, options *UcOptions) error Stop() error - HookAdd(htype int, cb interface{}, extra ...uint64) (Hook, error) + HookAdd(htype int, cb interface{}, begin, end uint64, extra ...int) (Hook, error) HookDel(hook Hook) error Close() error } From 475c8de3dec65f1d90928e2665d767ee91880bfd Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Sat, 27 Feb 2016 10:55:40 -0800 Subject: [PATCH 088/126] Go: update test hooks --- bindings/go/unicorn/hook.go | 4 ++-- bindings/go/unicorn/x86_test.go | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bindings/go/unicorn/hook.go b/bindings/go/unicorn/hook.go index 6591c46c..0a1a7d6f 100644 --- a/bindings/go/unicorn/hook.go +++ b/bindings/go/unicorn/hook.go @@ -100,9 +100,9 @@ func (u *uc) HookAdd(htype int, cb interface{}, begin, end uint64, extra ...int) data := &HookData{u, cb} uptr := uintptr(unsafe.Pointer(data)) if insnMode { - C.uc_hook_add_wrap(u.handle, &h2, C.uc_hook_type(htype), callback, C.uintptr_t(uptr), C.uint64_t(begin), C.uint64_t(end)) - } else { C.uc_hook_add_insn(u.handle, &h2, C.uc_hook_type(htype), callback, C.uintptr_t(uptr), C.uint64_t(begin), C.uint64_t(end), insn) + } else { + C.uc_hook_add_wrap(u.handle, &h2, C.uc_hook_type(htype), callback, C.uintptr_t(uptr), C.uint64_t(begin), C.uint64_t(end)) } hookDataMap[uptr] = data hookToUintptr[Hook(h2)] = uptr diff --git a/bindings/go/unicorn/x86_test.go b/bindings/go/unicorn/x86_test.go index 67400552..aca1d3be 100644 --- a/bindings/go/unicorn/x86_test.go +++ b/bindings/go/unicorn/x86_test.go @@ -96,7 +96,7 @@ func TestX86InOut(t *testing.T) { default: return 0 } - }, X86_INS_IN) + }, 1, 0, X86_INS_IN) mu.HookAdd(HOOK_INSN, func(_ Unicorn, port, size, value uint32) { outCalled = true var err error @@ -111,7 +111,7 @@ func TestX86InOut(t *testing.T) { if err != nil { t.Fatal(err) } - }, X86_INS_OUT) + }, 1, 0, X86_INS_OUT) if err := mu.Start(ADDRESS, ADDRESS+uint64(len(code))); err != nil { t.Fatal(err) } @@ -132,7 +132,7 @@ func TestX86Syscall(t *testing.T) { mu.HookAdd(HOOK_INSN, func(_ Unicorn) { rax, _ := mu.RegRead(X86_REG_RAX) mu.RegWrite(X86_REG_RAX, rax+1) - }, X86_INS_SYSCALL) + }, 1, 0, X86_INS_SYSCALL) mu.RegWrite(X86_REG_RAX, 0x100) err = mu.Start(ADDRESS, ADDRESS+uint64(len(code))) if err != nil { From 74f783a27419d22da3c4e653aba48466a703929a Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Sat, 27 Feb 2016 10:51:10 -0800 Subject: [PATCH 089/126] Go: add x86 RegWriteMmr method --- bindings/go/unicorn/unicorn.go | 1 + bindings/go/unicorn/x86.go | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 bindings/go/unicorn/x86.go diff --git a/bindings/go/unicorn/unicorn.go b/bindings/go/unicorn/unicorn.go index 1f3e9094..2076fb88 100644 --- a/bindings/go/unicorn/unicorn.go +++ b/bindings/go/unicorn/unicorn.go @@ -36,6 +36,7 @@ type Unicorn interface { MemWrite(addr uint64, data []byte) error RegRead(reg int) (uint64, error) RegWrite(reg int, value uint64) error + RegWriteMmr(reg int, value *X86Mmr) error Start(begin, until uint64) error StartWithOptions(begin, until uint64, options *UcOptions) error Stop() error diff --git a/bindings/go/unicorn/x86.go b/bindings/go/unicorn/x86.go new file mode 100644 index 00000000..490f7dfa --- /dev/null +++ b/bindings/go/unicorn/x86.go @@ -0,0 +1,26 @@ +package unicorn + +import ( + "unsafe" +) + +// #include +// #include +import "C" + +type X86Mmr struct { + Selector uint16 + Base uint64 + Limit uint32 + Flags uint32 +} + +func (u *uc) RegWriteMmr(reg int, value *X86Mmr) error { + var val C.uc_x86_mmr + val.selector = C.uint16_t(value.Selector) + val.base = C.uint64_t(value.Base) + val.limit = C.uint32_t(value.Limit) + val.flags = C.uint32_t(value.Flags) + ucerr := C.uc_reg_write(u.handle, C.int(reg), unsafe.Pointer(&val)) + return errReturn(ucerr) +} From 9f1603c15753016b8636b4be3ae1b40169c0119d Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Sat, 27 Feb 2016 11:10:15 -0800 Subject: [PATCH 090/126] Go: add MemRegions --- bindings/go/unicorn/unicorn.go | 25 +++++++++++++++++++++++++ bindings/go/unicorn/unicorn_test.go | 22 ++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/bindings/go/unicorn/unicorn.go b/bindings/go/unicorn/unicorn.go index 2076fb88..1500627a 100644 --- a/bindings/go/unicorn/unicorn.go +++ b/bindings/go/unicorn/unicorn.go @@ -25,12 +25,18 @@ func errReturn(err C.uc_err) error { return nil } +type MemRegion struct { + Begin, End uint64 + Prot int +} + type Unicorn interface { MemMap(addr, size uint64) error MemMapProt(addr, size uint64, prot int) error MemMapPtr(addr, size uint64, prot int, ptr unsafe.Pointer) error MemProtect(addr, size uint64, prot int) error MemUnmap(addr, size uint64) error + MemRegions() ([]*MemRegion, error) MemRead(addr, size uint64) ([]byte, error) MemReadInto(dst []byte, addr uint64) error MemWrite(addr uint64, data []byte) error @@ -104,6 +110,25 @@ func (u *uc) RegRead(reg int) (uint64, error) { return uint64(val), errReturn(ucerr) } +func (u *uc) MemRegions() ([]*MemRegion, error) { + var regions *C.struct_uc_mem_region + var count C.uint32_t + ucerr := C.uc_mem_regions(u.handle, ®ions, &count) + if ucerr != C.UC_ERR_OK { + return nil, errReturn(ucerr) + } + ret := make([]*MemRegion, count) + tmp := (*[1 << 30]C.struct_uc_mem_region)(unsafe.Pointer(regions))[:count] + for i, v := range tmp { + ret[i] = &MemRegion{ + Begin: uint64(v.begin), + End: uint64(v.end), + Prot: int(v.perms), + } + } + return ret, nil +} + func (u *uc) MemWrite(addr uint64, data []byte) error { if len(data) == 0 { return nil diff --git a/bindings/go/unicorn/unicorn_test.go b/bindings/go/unicorn/unicorn_test.go index caf13126..58e78431 100644 --- a/bindings/go/unicorn/unicorn_test.go +++ b/bindings/go/unicorn/unicorn_test.go @@ -37,3 +37,25 @@ func TestDoubleClose(t *testing.T) { t.Fatal(err) } } + +func TestMemRegions(t *testing.T) { + mu, err := NewUnicorn(ARCH_X86, MODE_32) + if err != nil { + t.Fatal(err) + } + err = mu.MemMap(0x1000, 0x1000) + if err != nil { + t.Fatal(err) + } + regions, err := mu.MemRegions() + if err != nil { + t.Fatal(err) + } + if len(regions) != 1 { + t.Fatalf("returned wrong number of regions: %d != 1", len(regions)) + } + r := regions[0] + if r.Begin != 0x1000 || r.End != 0x1fff || r.Prot != 7 { + t.Fatalf("incorrect region: %#v", r) + } +} From 43eb9ec351c5998be0504fa39e82a8f7882a7a94 Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Sat, 27 Feb 2016 11:15:06 -0800 Subject: [PATCH 091/126] Go: add uc_query api --- bindings/go/unicorn/unicorn.go | 7 +++++++ bindings/go/unicorn/unicorn_test.go | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/bindings/go/unicorn/unicorn.go b/bindings/go/unicorn/unicorn.go index 1500627a..ecaa6336 100644 --- a/bindings/go/unicorn/unicorn.go +++ b/bindings/go/unicorn/unicorn.go @@ -48,6 +48,7 @@ type Unicorn interface { Stop() error HookAdd(htype int, cb interface{}, begin, end uint64, extra ...int) (Hook, error) HookDel(hook Hook) error + Query(queryType int) (uint64, error) Close() error } @@ -167,3 +168,9 @@ func (u *uc) MemProtect(addr, size uint64, prot int) error { func (u *uc) MemUnmap(addr, size uint64) error { return errReturn(C.uc_mem_unmap(u.handle, C.uint64_t(addr), C.size_t(size))) } + +func (u *uc) Query(queryType int) (uint64, error) { + var ret C.size_t + ucerr := C.uc_query(u.handle, C.uc_query_type(queryType), &ret) + return uint64(ret), errReturn(ucerr) +} diff --git a/bindings/go/unicorn/unicorn_test.go b/bindings/go/unicorn/unicorn_test.go index 58e78431..6627528f 100644 --- a/bindings/go/unicorn/unicorn_test.go +++ b/bindings/go/unicorn/unicorn_test.go @@ -59,3 +59,17 @@ func TestMemRegions(t *testing.T) { t.Fatalf("incorrect region: %#v", r) } } + +func TestQuery(t *testing.T) { + mu, err := NewUnicorn(ARCH_ARM, MODE_THUMB) + if err != nil { + t.Fatal(err) + } + mode, err := mu.Query(QUERY_MODE) + if err != nil { + t.Fatal(err) + } + if mode != MODE_THUMB { + t.Fatal("query returned invalid mode: %d != %d", mode, MODE_THUMB) + } +} From 4f1c88e70c23c34e54e96cbdcdd9da08ebcdefbf Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Sun, 28 Feb 2016 12:00:58 -0800 Subject: [PATCH 092/126] Go: add RegReadMmr and test --- bindings/go/unicorn/unicorn.go | 1 + bindings/go/unicorn/x86.go | 12 ++++++++++++ bindings/go/unicorn/x86_test.go | 15 +++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/bindings/go/unicorn/unicorn.go b/bindings/go/unicorn/unicorn.go index ecaa6336..2b0e456c 100644 --- a/bindings/go/unicorn/unicorn.go +++ b/bindings/go/unicorn/unicorn.go @@ -42,6 +42,7 @@ type Unicorn interface { MemWrite(addr uint64, data []byte) error RegRead(reg int) (uint64, error) RegWrite(reg int, value uint64) error + RegReadMmr(reg int) (*X86Mmr, error) RegWriteMmr(reg int, value *X86Mmr) error Start(begin, until uint64) error StartWithOptions(begin, until uint64, options *UcOptions) error diff --git a/bindings/go/unicorn/x86.go b/bindings/go/unicorn/x86.go index 490f7dfa..9097de2a 100644 --- a/bindings/go/unicorn/x86.go +++ b/bindings/go/unicorn/x86.go @@ -24,3 +24,15 @@ func (u *uc) RegWriteMmr(reg int, value *X86Mmr) error { ucerr := C.uc_reg_write(u.handle, C.int(reg), unsafe.Pointer(&val)) return errReturn(ucerr) } + +func (u *uc) RegReadMmr(reg int) (*X86Mmr, error) { + var val C.uc_x86_mmr + ucerr := C.uc_reg_read(u.handle, C.int(reg), unsafe.Pointer(&val)) + ret := &X86Mmr{ + Selector: uint16(val.selector), + Base: uint64(val.base), + Limit: uint32(val.limit), + Flags: uint32(val.flags), + } + return ret, errReturn(ucerr) +} diff --git a/bindings/go/unicorn/x86_test.go b/bindings/go/unicorn/x86_test.go index aca1d3be..c74a0611 100644 --- a/bindings/go/unicorn/x86_test.go +++ b/bindings/go/unicorn/x86_test.go @@ -143,3 +143,18 @@ func TestX86Syscall(t *testing.T) { t.Fatal("Incorrect syscall return value.") } } + +func TestX86Mmr(t *testing.T) { + mu, err := MakeUc(MODE_64, "") + if err != nil { + t.Fatal(err) + } + err = mu.RegWriteMmr(X86_REG_GDTR, &X86Mmr{Selector: 0, Base: 0x1000, Limit: 0x1fff, Flags: 0}) + if err != nil { + t.Fatal(err) + } + mmr, err := mu.RegReadMmr(X86_REG_GDTR) + if mmr.Selector != 0 || mmr.Base != 0x1000 || mmr.Limit != 0x1fff || mmr.Flags != 0 { + t.Fatalf("mmr read failed: %#v", mmr) + } +} From 5fa6705d7af599275193d5eeaad5abf20fcc1fee Mon Sep 17 00:00:00 2001 From: Jonas Zaddach Date: Mon, 29 Feb 2016 22:57:41 +0100 Subject: [PATCH 093/126] Fixed restoring of eflags after helper call --- qemu/target-i386/translate.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/qemu/target-i386/translate.c b/qemu/target-i386/translate.c index d68cb516..76bab2d6 100644 --- a/qemu/target-i386/translate.c +++ b/qemu/target-i386/translate.c @@ -4721,6 +4721,17 @@ static void sync_eflags(DisasContext *s, TCGContext *tcg_ctx) tcg_gen_st_tl(tcg_ctx, *cpu_T[0], cpu_env, offsetof(CPUX86State, eflags)); } +static void restore_eflags(DisasContext *s, TCGContext *tcg_ctx) +{ + TCGv **cpu_T = (TCGv **)tcg_ctx->cpu_T; + TCGv_ptr cpu_env = tcg_ctx->cpu_env; + + tcg_gen_ld_tl(tcg_ctx, *cpu_T[0], cpu_env, offsetof(CPUX86State, eflags)); + gen_helper_write_eflags(tcg_ctx, cpu_env, *cpu_T[0], + tcg_const_i32(tcg_ctx, (TF_MASK | AC_MASK | ID_MASK | NT_MASK) & 0xffff)); + set_cc_op(s, CC_OP_EFLAGS); +} + /* convert one instruction. s->is_jmp is set if the translation must be stopped. Return the next pc value */ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, @@ -4773,6 +4784,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, changed_cc_op = true; } gen_uc_tracecode(tcg_ctx, 0xf1f1f1f1, UC_HOOK_CODE_IDX, env->uc, pc_start); + restore_eflags(s, tcg_ctx); // the callback might want to stop emulation immediately check_exit_request(tcg_ctx); } From 9eb1c57c34cf8ba5c3f59a77087ebf170f46ae25 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 1 Mar 2016 13:49:27 +0800 Subject: [PATCH 094/126] add Travis support for automated tests --- .travis.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..b80f07f3 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,9 @@ +language: c +sudo: false +before_install: + - export LD_LIBRARY_PATH=`pwd`/samples/:$LD_LIBRARY_PATH +script: + - ./make.sh +compiler: + - clang + - gcc From d6fee1fd6a3427d50f8a28ca66df104c9c3783bd Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 1 Mar 2016 13:54:32 +0800 Subject: [PATCH 095/126] add Travis build status to README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 942e1b8e..0d8e7558 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ Unicorn Engine ============== +[![Build Status](https://travis-ci.org/unicorn-engine/unicorn.svg?branch=master)](https://travis-ci.org/unicorn-engine/unicorn) + Unicorn is a lightweight, multi-platform, multi-architecture CPU emulator framework based on [QEMU](http://qemu.org). From 1cd3c3093b0fc152daed76bfd0068a34c922e09c Mon Sep 17 00:00:00 2001 From: Hiroyuki UEKAWA Date: Wed, 2 Mar 2016 09:23:48 +0900 Subject: [PATCH 096/126] fix WRITE_BYTE_H --- qemu/target-arm/unicorn_aarch64.c | 2 +- qemu/target-arm/unicorn_arm.c | 2 +- qemu/target-i386/unicorn.c | 2 +- qemu/target-m68k/unicorn.c | 2 +- qemu/target-mips/unicorn.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/qemu/target-arm/unicorn_aarch64.c b/qemu/target-arm/unicorn_aarch64.c index 1ce9d6eb..fbdfaff7 100644 --- a/qemu/target-arm/unicorn_aarch64.c +++ b/qemu/target-arm/unicorn_aarch64.c @@ -62,7 +62,7 @@ int arm64_reg_read(struct uc_struct *uc, unsigned int regid, void *value) #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_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8)) #define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) int arm64_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) diff --git a/qemu/target-arm/unicorn_arm.c b/qemu/target-arm/unicorn_arm.c index 95ea812d..da51cac4 100644 --- a/qemu/target-arm/unicorn_arm.c +++ b/qemu/target-arm/unicorn_arm.c @@ -69,7 +69,7 @@ int arm_reg_read(struct uc_struct *uc, unsigned int regid, void *value) #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_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8)) #define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) int arm_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index c8436b9b..92b79d32 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -578,7 +578,7 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) #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_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8)) #define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) diff --git a/qemu/target-m68k/unicorn.c b/qemu/target-m68k/unicorn.c index 0055d4a1..bbf5898f 100644 --- a/qemu/target-m68k/unicorn.c +++ b/qemu/target-m68k/unicorn.c @@ -54,7 +54,7 @@ int m68k_reg_read(struct uc_struct *uc, unsigned int regid, void *value) #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_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8)) #define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) int m68k_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) diff --git a/qemu/target-mips/unicorn.c b/qemu/target-mips/unicorn.c index 6af98dce..6085a259 100644 --- a/qemu/target-mips/unicorn.c +++ b/qemu/target-mips/unicorn.c @@ -67,7 +67,7 @@ int mips_reg_read(struct uc_struct *uc, unsigned int regid, void *value) #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_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8)) #define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) int mips_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) From c5888e5670e7608b9e49436962b294fb81fddbe2 Mon Sep 17 00:00:00 2001 From: Hiroyuki UEKAWA Date: Wed, 2 Mar 2016 12:43:02 +0900 Subject: [PATCH 097/126] move macros in `qemu/target-*/unicorn*.c` to `uc_priv.h` --- include/uc_priv.h | 11 +++++++++++ qemu/target-arm/unicorn_aarch64.c | 17 +---------------- qemu/target-arm/unicorn_arm.c | 16 +--------------- qemu/target-i386/unicorn.c | 16 ++-------------- qemu/target-m68k/unicorn.c | 14 +------------- qemu/target-mips/unicorn.c | 15 +-------------- qemu/target-sparc/unicorn.c | 8 +------- qemu/target-sparc/unicorn64.c | 8 +------- 8 files changed, 19 insertions(+), 86 deletions(-) diff --git a/include/uc_priv.h b/include/uc_priv.h index 0ef5a3dd..e36a8c84 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -22,6 +22,17 @@ #define ARR_SIZE(a) (sizeof(a)/sizeof(a[0])) +#define READ_QWORD(x) ((uint64)x) +#define READ_DWORD(x) (x & 0xffffffff) +#define READ_WORD(x) (x & 0xffff) +#define READ_BYTE_H(x) ((x & 0xffff) >> 8) +#define READ_BYTE_L(x) (x & 0xff) +#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) << 8)) +#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) + + QTAILQ_HEAD(CPUTailQ, CPUState); typedef struct ModuleEntry { diff --git a/qemu/target-arm/unicorn_aarch64.c b/qemu/target-arm/unicorn_aarch64.c index fbdfaff7..c1d53a68 100644 --- a/qemu/target-arm/unicorn_aarch64.c +++ b/qemu/target-arm/unicorn_aarch64.c @@ -3,21 +3,11 @@ #include "hw/boards.h" #include "hw/arm/arm.h" - #include "sysemu/cpus.h" - #include "unicorn.h" - #include "cpu.h" - #include "unicorn_common.h" - - -#define READ_QWORD(x) ((uint64)x) -#define READ_DWORD(x) (x & 0xffffffff) -#define READ_WORD(x) (x & 0xffff) -#define READ_BYTE_H(x) ((x & 0xffff) >> 8) -#define READ_BYTE_L(x) (x & 0xff) +#include "uc_priv.h" static void arm64_set_pc(struct uc_struct *uc, uint64_t address) @@ -60,11 +50,6 @@ int arm64_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) << 8)) -#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) - int arm64_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { CPUState *mycpu = first_cpu; diff --git a/qemu/target-arm/unicorn_arm.c b/qemu/target-arm/unicorn_arm.c index da51cac4..9fc2a44c 100644 --- a/qemu/target-arm/unicorn_arm.c +++ b/qemu/target-arm/unicorn_arm.c @@ -3,20 +3,11 @@ #include "hw/boards.h" #include "hw/arm/arm.h" - #include "sysemu/cpus.h" - #include "unicorn.h" - #include "cpu.h" #include "unicorn_common.h" - - -#define READ_QWORD(x) ((uint64)x) -#define READ_DWORD(x) (x & 0xffffffff) -#define READ_WORD(x) (x & 0xffff) -#define READ_BYTE_H(x) ((x & 0xffff) >> 8) -#define READ_BYTE_L(x) (x & 0xff) +#include "uc_priv.h" static void arm_set_pc(struct uc_struct *uc, uint64_t address) @@ -67,11 +58,6 @@ int arm_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) << 8)) -#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) - int arm_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { CPUState *mycpu = first_cpu; diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index 92b79d32..7ec2d140 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -2,20 +2,14 @@ /* By Nguyen Anh Quynh , 2015 */ #include "hw/boards.h" -#include "sysemu/cpus.h" #include "hw/i386/pc.h" +#include "sysemu/cpus.h" #include "unicorn.h" #include "cpu.h" #include "tcg.h" - #include "unicorn_common.h" #include /* needed for uc_x86_mmr */ - -#define READ_QWORD(x) ((uint64)x) -#define READ_DWORD(x) (x & 0xffffffff) -#define READ_WORD(x) (x & 0xffff) -#define READ_BYTE_H(x) ((x & 0xffff) >> 8) -#define READ_BYTE_L(x) (x & 0xff) +#include "uc_priv.h" static void x86_set_pc(struct uc_struct *uc, uint64_t address) @@ -575,12 +569,6 @@ int x86_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) << 8)) -#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) - int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { CPUState *mycpu = first_cpu; diff --git a/qemu/target-m68k/unicorn.c b/qemu/target-m68k/unicorn.c index bbf5898f..0edf04c2 100644 --- a/qemu/target-m68k/unicorn.c +++ b/qemu/target-m68k/unicorn.c @@ -6,14 +6,8 @@ #include "sysemu/cpus.h" #include "unicorn.h" #include "cpu.h" - #include "unicorn_common.h" - -#define READ_QWORD(x) ((uint64)x) -#define READ_DWORD(x) (x & 0xffffffff) -#define READ_WORD(x) (x & 0xffff) -#define READ_BYTE_H(x) ((x & 0xffff) >> 8) -#define READ_BYTE_L(x) (x & 0xff) +#include "uc_priv.h" static void m68k_set_pc(struct uc_struct *uc, uint64_t address) @@ -51,12 +45,6 @@ int m68k_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) << 8)) -#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) - int m68k_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { CPUState *mycpu = first_cpu; diff --git a/qemu/target-mips/unicorn.c b/qemu/target-mips/unicorn.c index 6085a259..7740d0d9 100644 --- a/qemu/target-mips/unicorn.c +++ b/qemu/target-mips/unicorn.c @@ -6,15 +6,8 @@ #include "sysemu/cpus.h" #include "unicorn.h" #include "cpu.h" - #include "unicorn_common.h" - - -#define READ_QWORD(x) ((uint64)x) -#define READ_DWORD(x) (x & 0xffffffff) -#define READ_WORD(x) (x & 0xffff) -#define READ_BYTE_H(x) ((x & 0xffff) >> 8) -#define READ_BYTE_L(x) (x & 0xff) +#include "uc_priv.h" static uint64_t mips_mem_redirect(uint64_t address) @@ -64,12 +57,6 @@ int mips_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) << 8)) -#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) - int mips_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { CPUState *mycpu = first_cpu; diff --git a/qemu/target-sparc/unicorn.c b/qemu/target-sparc/unicorn.c index e612457b..3775776a 100644 --- a/qemu/target-sparc/unicorn.c +++ b/qemu/target-sparc/unicorn.c @@ -7,13 +7,7 @@ #include "unicorn.h" #include "cpu.h" #include "unicorn_common.h" - - -#define READ_QWORD(x) ((uint64)x) -#define READ_DWORD(x) (x & 0xffffffff) -#define READ_WORD(x) (x & 0xffff) -#define READ_BYTE_H(x) ((x & 0xffff) >> 8) -#define READ_BYTE_L(x) (x & 0xff) +#include "uc_priv.h" static bool sparc_stop_interrupt(int intno) diff --git a/qemu/target-sparc/unicorn64.c b/qemu/target-sparc/unicorn64.c index e9257b75..ef99b5ab 100644 --- a/qemu/target-sparc/unicorn64.c +++ b/qemu/target-sparc/unicorn64.c @@ -7,13 +7,7 @@ #include "unicorn.h" #include "cpu.h" #include "unicorn_common.h" - - -#define READ_QWORD(x) ((uint64)x) -#define READ_DWORD(x) (x & 0xffffffff) -#define READ_WORD(x) (x & 0xffff) -#define READ_BYTE_H(x) ((x & 0xffff) >> 8) -#define READ_BYTE_L(x) (x & 0xff) +#include "uc_priv.h" static bool sparc_stop_interrupt(int intno) From feb7b8e1ae56f4290da6c5372c2d6b3d93c8ea3f Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 3 Mar 2016 23:14:25 +0800 Subject: [PATCH 098/126] travis: support OSX & Linux --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index b80f07f3..4d077ff9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,3 +7,6 @@ script: compiler: - clang - gcc +os: + - linux + - osx From cf08670a1c1d16b53637c6bcf0c805a5e29cf180 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 3 Mar 2016 23:25:29 +0800 Subject: [PATCH 099/126] Travis: install dependencies for OSX --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 4d077ff9..9a3ebd3f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,9 @@ language: c sudo: false before_install: - export LD_LIBRARY_PATH=`pwd`/samples/:$LD_LIBRARY_PATH + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew pkg-config glib; fi + script: - ./make.sh compiler: From 3ebb5d3a2e145aa9355e4c1e0349f8a181236281 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 3 Mar 2016 23:33:07 +0800 Subject: [PATCH 100/126] travis: fix brew install --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9a3ebd3f..ffc13784 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ sudo: false before_install: - export LD_LIBRARY_PATH=`pwd`/samples/:$LD_LIBRARY_PATH - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew pkg-config glib; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install pkg-config glib; fi script: - ./make.sh From 1ddebc7304dd4d0a91ad410eedc7e41bae8d46fa Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 3 Mar 2016 23:41:03 +0800 Subject: [PATCH 101/126] travis: do not need to install pkg-config --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ffc13784..39c18b8e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ sudo: false before_install: - export LD_LIBRARY_PATH=`pwd`/samples/:$LD_LIBRARY_PATH - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install pkg-config glib; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install glib; fi script: - ./make.sh From 1087ba9dea62ef0e6c2b2e7e147b1dab9b46c2d2 Mon Sep 17 00:00:00 2001 From: Nicolas PLANEL Date: Fri, 4 Mar 2016 15:26:06 +1100 Subject: [PATCH 102/126] [query] add UC_QUERY_PAGE_SIZE uc_query helper Return the current page size used by the current arch. Useful to call uc_mem_map() with memory/size aligned. Signed-off-by: Nicolas PLANEL --- include/unicorn/unicorn.h | 1 + tests/unit/test_mem_map.c | 10 ++++++++++ uc.c | 5 +++++ 3 files changed, 16 insertions(+) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 35e745ca..23a17a4f 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -262,6 +262,7 @@ typedef struct uc_mem_region { typedef enum uc_query_type { // Dynamically query current hardware mode. UC_QUERY_MODE = 1, + UC_QUERY_PAGE_SIZE, } uc_query_type; /* diff --git a/tests/unit/test_mem_map.c b/tests/unit/test_mem_map.c index 303a370b..9c2b9892 100644 --- a/tests/unit/test_mem_map.c +++ b/tests/unit/test_mem_map.c @@ -158,6 +158,15 @@ static void test_strange_map(void **state) uc_mem_unmap(uc, 0x0,0x1000); } +static void test_query_page_size(void **state) +{ + uc_engine *uc = *state; + + size_t page_size; + uc_assert_success(uc_query(uc, UC_QUERY_PAGE_SIZE, &page_size)); + assert_int_equal(4096, page_size); +} + void write(uc_engine* uc, uint64_t addr, uint64_t len){ uint8_t* buff = alloca(len); memset(buff,0,len); @@ -220,6 +229,7 @@ int main(void) { test(test_unmap_double_map), test(test_overlap_unmap_double_map), test(test_strange_map), + test(test_query_page_size), }; #undef test return cmocka_run_group_tests(tests, NULL, NULL); diff --git a/uc.c b/uc.c index 298d21e0..ce9f121d 100644 --- a/uc.c +++ b/uc.c @@ -1094,6 +1094,11 @@ uint32_t uc_mem_regions(uc_engine *uc, uc_mem_region **regions, uint32_t *count) UNICORN_EXPORT uc_err uc_query(uc_engine *uc, uc_query_type type, size_t *result) { + if (type == UC_QUERY_PAGE_SIZE) { + *result = uc->target_page_size; + return UC_ERR_OK; + } + switch(uc->arch) { case UC_ARCH_ARM: return uc->query(uc, type, result); From 2031f7cbdd64cb5a2bc5e980574710ed1ff2d5b9 Mon Sep 17 00:00:00 2001 From: Nicolas PLANEL Date: Fri, 4 Mar 2016 15:29:32 +1100 Subject: [PATCH 103/126] [query] update bindings UC_QUERY_PAGE_SIZE Signed-off-by: Nicolas PLANEL --- bindings/dotnet/UnicornManaged/Const/Common.fs | 1 + bindings/go/unicorn/unicorn_const.go | 1 + bindings/java/unicorn/UnicornConst.java | 1 + bindings/python/unicorn/unicorn_const.py | 1 + 4 files changed, 4 insertions(+) diff --git a/bindings/dotnet/UnicornManaged/Const/Common.fs b/bindings/dotnet/UnicornManaged/Const/Common.fs index 0f42d3d7..ef9004e6 100644 --- a/bindings/dotnet/UnicornManaged/Const/Common.fs +++ b/bindings/dotnet/UnicornManaged/Const/Common.fs @@ -93,6 +93,7 @@ module Common = let UC_HOOK_MEM_INVALID = 1008 let UC_HOOK_MEM_VALID = 7168 let UC_QUERY_MODE = 1 + let UC_QUERY_PAGE_SIZE = 2 let UC_PROT_NONE = 0 let UC_PROT_READ = 1 diff --git a/bindings/go/unicorn/unicorn_const.go b/bindings/go/unicorn/unicorn_const.go index 1faff075..01b62fca 100644 --- a/bindings/go/unicorn/unicorn_const.go +++ b/bindings/go/unicorn/unicorn_const.go @@ -88,6 +88,7 @@ const ( HOOK_MEM_INVALID = 1008 HOOK_MEM_VALID = 7168 QUERY_MODE = 1 + QUERY_PAGE_SIZE = 2 PROT_NONE = 0 PROT_READ = 1 diff --git a/bindings/java/unicorn/UnicornConst.java b/bindings/java/unicorn/UnicornConst.java index 64b52236..033267ae 100644 --- a/bindings/java/unicorn/UnicornConst.java +++ b/bindings/java/unicorn/UnicornConst.java @@ -90,6 +90,7 @@ public interface UnicornConst { public static final int UC_HOOK_MEM_INVALID = 1008; public static final int UC_HOOK_MEM_VALID = 7168; public static final int UC_QUERY_MODE = 1; + public static final int UC_QUERY_PAGE_SIZE = 2; public static final int UC_PROT_NONE = 0; public static final int UC_PROT_READ = 1; diff --git a/bindings/python/unicorn/unicorn_const.py b/bindings/python/unicorn/unicorn_const.py index bdb8ed01..89ccd919 100644 --- a/bindings/python/unicorn/unicorn_const.py +++ b/bindings/python/unicorn/unicorn_const.py @@ -86,6 +86,7 @@ UC_HOOK_MEM_FETCH_INVALID = 576 UC_HOOK_MEM_INVALID = 1008 UC_HOOK_MEM_VALID = 7168 UC_QUERY_MODE = 1 +UC_QUERY_PAGE_SIZE = 2 UC_PROT_NONE = 0 UC_PROT_READ = 1 From bf7dc4293b7711a89938996c325439255bc89061 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 6 Mar 2016 17:27:50 +0800 Subject: [PATCH 104/126] python: README -> README.md in setup.py --- bindings/python/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/python/setup.py b/bindings/python/setup.py index 66ea8ab0..8c44f470 100755 --- a/bindings/python/setup.py +++ b/bindings/python/setup.py @@ -63,7 +63,7 @@ def copy_sources(): src.extend(glob.glob("../../Makefile")) src.extend(glob.glob("../../LICENSE*")) - src.extend(glob.glob("../../README")) + src.extend(glob.glob("../../README.md")) src.extend(glob.glob("../../*.TXT")) src.extend(glob.glob("../../RELEASE_NOTES")) src.extend(glob.glob("../../make.sh")) From 0950f2e18b54acc20062bbd69e21a0f7e31204ce Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 6 Mar 2016 17:28:32 +0800 Subject: [PATCH 105/126] python: 0.9 -> 1.0 in setup.py --- bindings/python/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/python/setup.py b/bindings/python/setup.py index 8c44f470..6b98bae5 100755 --- a/bindings/python/setup.py +++ b/bindings/python/setup.py @@ -24,7 +24,7 @@ PKG_NAME = 'unicorn' if os.path.exists(PATH_LIB64) and os.path.exists(PATH_LIB32): PKG_NAME = 'unicorn-windows' -VERSION = '0.9' +VERSION = '1.0' SYSTEM = sys.platform # virtualenv breaks import, but get_python_lib() will work. From eb5a7624526cece15e43353e73b67e5f334abefe Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 6 Mar 2016 21:21:39 +0800 Subject: [PATCH 106/126] python: add __version__ --- bindings/python/unicorn/__init__.py | 2 +- bindings/python/unicorn/unicorn.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/bindings/python/unicorn/__init__.py b/bindings/python/unicorn/__init__.py index 3f63904c..9d2b717c 100644 --- a/bindings/python/unicorn/__init__.py +++ b/bindings/python/unicorn/__init__.py @@ -1,4 +1,4 @@ # Unicorn Python bindings, by Nguyen Anh Quynnh from . import arm_const, arm64_const, mips_const, sparc_const, m68k_const, x86_const from .unicorn_const import * -from .unicorn import Uc, uc_version, uc_arch_supported, version_bind, debug, UcError +from .unicorn import Uc, uc_version, uc_arch_supported, version_bind, debug, UcError, __version__ diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index 3d784368..989d985f 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -81,6 +81,8 @@ if _found == False: raise ImportError("ERROR: fail to load the dynamic library.") +__version__ = "%s.%s" %(UC_API_MAJOR, UC_API_MINOR) + # setup all the function prototype def _setup_prototype(lib, fname, restype, *argtypes): getattr(lib, fname).restype = restype From 338fb0e81b18b4909d969207ca4131ddb3ebc9ba Mon Sep 17 00:00:00 2001 From: Spl3en Date: Mon, 7 Mar 2016 17:52:08 +0100 Subject: [PATCH 107/126] Fix a typo in uc_hook_add documentation. --- include/unicorn/unicorn.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 23a17a4f..65d6aa53 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -459,7 +459,7 @@ uc_err uc_emu_stop(uc_engine *uc); @user_data: user-defined data. This will be passed to callback function in its last argument @user_data @begin: start address of the area where the callback is effect (inclusive) - @begin: end address of the area where the callback is effect (inclusive) + @end: end address of the area where the callback is effect (inclusive) NOTE 1: the callback is called only if related address is in range [@begin, @end] NOTE 2: if @begin > @end, callback is called whenever this hook type is triggered @...: variable arguments (depending on @type) From 9d9056c4747c404f6c460e8c779cda407aff1df7 Mon Sep 17 00:00:00 2001 From: Hoang-Vu Dang Date: Mon, 7 Mar 2016 12:22:20 -0600 Subject: [PATCH 108/126] Add a license for regression tests --- tests/regress/LICENSE | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 tests/regress/LICENSE diff --git a/tests/regress/LICENSE b/tests/regress/LICENSE new file mode 100644 index 00000000..dceeb48a --- /dev/null +++ b/tests/regress/LICENSE @@ -0,0 +1,30 @@ +This is the software license for Unicorn regression tests. The regression tests +are written by several Unicorn contributors (See CREDITS.TXT) and maintained by +Hoang-Vu Dang + +Copyright (c) 2015, Unicorn contributers +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the developer(s) nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. From 9c91a6ec28744d5140fd44d6de6af9ab7d190b93 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 8 Mar 2016 08:55:55 +0800 Subject: [PATCH 109/126] fix a typo in tests/regress/LICENSE --- tests/regress/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regress/LICENSE b/tests/regress/LICENSE index dceeb48a..dd85900f 100644 --- a/tests/regress/LICENSE +++ b/tests/regress/LICENSE @@ -2,7 +2,7 @@ This is the software license for Unicorn regression tests. The regression tests are written by several Unicorn contributors (See CREDITS.TXT) and maintained by Hoang-Vu Dang -Copyright (c) 2015, Unicorn contributers +Copyright (c) 2015, Unicorn contributors All rights reserved. Redistribution and use in source and binary forms, with or without From 86e2127af16dd332221d17bf73401ca4800485d5 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 8 Mar 2016 12:52:13 +0800 Subject: [PATCH 110/126] add Appveyor CI --- appveyor.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 appveyor.yml diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000..c854f49e --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,27 @@ +version: 1.0-{build} + +platform: + - x64 + +environment: + global: + MSYS2_BASEVER: 20150512 + MSYS2_ARCH: x86_64 + matrix: + - HOST_ARCH_ARG: --host=x86_64-w64-mingw32 + ADD_PATH: /mingw64/bin + - HOST_ARCH_ARG: --host=i686-w64-mingw32 + ADD_PATH: /mingw32/bin + - HOST_ARCH_ARG: --enable-msvc + ADD_PATH: /mingw64/bin + +install: + - C:\"Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" + - appveyor DownloadFile "http://kent.dl.sourceforge.net/project/msys2/Base/%MSYS2_ARCH%/msys2-base-%MSYS2_ARCH%-%MSYS2_BASEVER%.tar.xz" -FileName "msys2.tar.xz" + - 7z x msys2.tar.xz + - 7z x msys2.tar > NUL + - msys64\usr\bin\bash -lc "" + - msys64\usr\bin\bash -lc "for i in {1..3}; do pacman --noconfirm -Suy python2 make pkg-config mingw-w64-x86_64-glib2 mingw-w64-x86_64-toolchain && break || sleep 15; done" + +build_script: + - ./make.sh cross-win64 From 861d5e1ad83501b83d4c61bc42041a34fb0bf76c Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 8 Mar 2016 13:06:16 +0800 Subject: [PATCH 111/126] fix appveyor.yml --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index c854f49e..db1e0861 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -24,4 +24,4 @@ install: - msys64\usr\bin\bash -lc "for i in {1..3}; do pacman --noconfirm -Suy python2 make pkg-config mingw-w64-x86_64-glib2 mingw-w64-x86_64-toolchain && break || sleep 15; done" build_script: - - ./make.sh cross-win64 + - make.sh cross-win64 From 276775f5cca809f54c90849a6356a350e6431d81 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 8 Mar 2016 13:41:24 +0800 Subject: [PATCH 112/126] more fix for Appveyor CI --- README.md | 1 + appveyor.yml | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 0d8e7558..f57b1df6 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ Unicorn Engine ============== [![Build Status](https://travis-ci.org/unicorn-engine/unicorn.svg?branch=master)](https://travis-ci.org/unicorn-engine/unicorn) +[![Build status](https://ci.appveyor.com/api/projects/status/kojr7bald748ba2x/branch/master?svg=true)](https://ci.appveyor.com/project/aquynh/unicorn/branch/master) Unicorn is a lightweight, multi-platform, multi-architecture CPU emulator framework based on [QEMU](http://qemu.org). diff --git a/appveyor.yml b/appveyor.yml index db1e0861..8d1c61e7 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -12,8 +12,6 @@ environment: ADD_PATH: /mingw64/bin - HOST_ARCH_ARG: --host=i686-w64-mingw32 ADD_PATH: /mingw32/bin - - HOST_ARCH_ARG: --enable-msvc - ADD_PATH: /mingw64/bin install: - C:\"Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" From 26261be2445c7c91917b981736913b76487d5084 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Wed, 9 Mar 2016 09:35:00 +0800 Subject: [PATCH 113/126] improve Appveyor config --- appveyor.yml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 8d1c61e7..790d37c8 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,7 +5,6 @@ platform: environment: global: - MSYS2_BASEVER: 20150512 MSYS2_ARCH: x86_64 matrix: - HOST_ARCH_ARG: --host=x86_64-w64-mingw32 @@ -15,11 +14,7 @@ environment: install: - C:\"Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" - - appveyor DownloadFile "http://kent.dl.sourceforge.net/project/msys2/Base/%MSYS2_ARCH%/msys2-base-%MSYS2_ARCH%-%MSYS2_BASEVER%.tar.xz" -FileName "msys2.tar.xz" - - 7z x msys2.tar.xz - - 7z x msys2.tar > NUL - - msys64\usr\bin\bash -lc "" - - msys64\usr\bin\bash -lc "for i in {1..3}; do pacman --noconfirm -Suy python2 make pkg-config mingw-w64-x86_64-glib2 mingw-w64-x86_64-toolchain && break || sleep 15; done" + - C:\msys64\usr\bin\bash -lc "pacman --noconfirm -Suy python2 make pkg-config mingw-w64-x86_64-glib2 mingw-w64-x86_64-toolchain" build_script: - make.sh cross-win64 From dca32a875e14e35403c62c82c7c15f46c5ef450c Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Wed, 9 Mar 2016 09:54:09 +0800 Subject: [PATCH 114/126] appveyor: try without pacman installs --- appveyor.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 790d37c8..ffa5aa42 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -14,7 +14,6 @@ environment: install: - C:\"Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" - - C:\msys64\usr\bin\bash -lc "pacman --noconfirm -Suy python2 make pkg-config mingw-w64-x86_64-glib2 mingw-w64-x86_64-toolchain" build_script: - make.sh cross-win64 From 2cfe6fb9c0b74fa5e129b20819afbe7e05f4ce8f Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Wed, 9 Mar 2016 11:53:59 +0800 Subject: [PATCH 115/126] appveyor: no need to initialize MSVC env for Msys2 --- appveyor.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index ffa5aa42..cbc1c215 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -12,8 +12,5 @@ environment: - HOST_ARCH_ARG: --host=i686-w64-mingw32 ADD_PATH: /mingw32/bin -install: - - C:\"Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" - build_script: - make.sh cross-win64 From ff66a72d7b19b47c2e609be4bf06349652bc33cb Mon Sep 17 00:00:00 2001 From: feliam Date: Wed, 9 Mar 2016 18:07:38 -0300 Subject: [PATCH 116/126] GDT/LDT/IDT/FPU access from python bingings --- bindings/python/unicorn/unicorn.py | 50 ++++++++++++++++++++++++++++-- qemu/target-i386/unicorn.c | 39 +++++++++++++++++++++++ 2 files changed, 86 insertions(+), 3 deletions(-) diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index 989d985f..28ba7e77 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -156,6 +156,23 @@ def uc_arch_supported(query): return _uc.uc_arch_supported(query) + +class uc_x86_mmr(ctypes.Structure): + '''Memory-Management Register for instructions IDTR, GDTR, LDTR, TR.''' + _fields_ = [ + ("selector", ctypes.c_uint16), # not used by GDTR and IDTR + ("base", ctypes.c_uint64), # handle 32 or 64 bit CPUs + ("limit", ctypes.c_uint32), + ("flags", ctypes.c_uint32), # not used by GDTR and IDTR + ] + +class uc_x86_float80(ctypes.Structure): + '''Float80''' + _fields_ = [ + ("mantissa", ctypes.c_uint64), + ("exponent", ctypes.c_uint16), + ] + class Uc(object): def __init__(self, arch, mode): # verify version compatibility with the core before doing anything @@ -188,7 +205,6 @@ class Uc(object): except: # _uc might be pulled from under our feet pass - # emulate from @begin, and stop when reaching address @until def emu_start(self, begin, until, timeout=0, count=0): status = _uc.uc_emu_start(self._uch, begin, until, timeout, count) @@ -205,6 +221,20 @@ class Uc(object): # return the value of a register def reg_read(self, reg_id): + if self._arch == UC_ARCH_X86: + if reg_id in [ x86_const.UC_X86_REG_IDTR, x86_const.UC_X86_REG_GDTR, x86_const.UC_X86_REG_LDTR, x86_const.UC_X86_REG_TR]: + reg = uc_x86_mmr() + status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg)) + if status != UC_ERR_OK: + raise UcError(status) + return (reg.selector,reg.base, reg.limits, reg.flags) + if reg_id in range(x86_const.UC_X86_REG_FP0,x86_const.UC_X86_REG_FP0+8): + reg = uc_x86_float80() + status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg)) + if status != UC_ERR_OK: + raise UcError(status) + return (reg.mantissa, reg.exponent) + # read to 64bit number to be safe reg = ctypes.c_int64(0) status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg)) @@ -215,8 +245,22 @@ class Uc(object): # write to a register def reg_write(self, reg_id, value): - # convert to 64bit number to be safe - reg = ctypes.c_int64(value) + if self._arch == UC_ARCH_X86: + if reg_id in [ x86_const.UC_X86_REG_IDTR, x86_const.UC_X86_REG_GDTR, x86_const.UC_X86_REG_LDTR, x86_const.UC_X86_REG_TR]: + assert isinstance(value, tuple) and len(value)==4 + reg = uc_x86_mmr() + reg.selector=value[0] + reg.base=value[1] + reg.limits=value[2] + reg.flags=value[3] + if reg_id in range(x86_const.UC_X86_REG_FP0, x86_const.UC_X86_REG_FP0+8): + reg = uc_x86_float80() + reg.mantissa = value[0] + reg.exponent = value[1] + else: + # convert to 64bit number to be safe + reg = ctypes.c_int64(value) + status = _uc.uc_reg_write(self._uch, reg_id, ctypes.byref(reg)) if status != UC_ERR_OK: raise UcError(status) diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index 7ec2d140..3ab525c3 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -140,6 +140,25 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) { CPUState *mycpu = first_cpu; + switch(regid) { + default: + break; + case UC_X86_REG_FP0 ... UC_X86_REG_FP7: + { + floatx80 reg = X86_CPU(uc, mycpu)->env.fpregs[regid - UC_X86_REG_FP0].d; + cpu_get_fp80(value, value+sizeof(uint64_t), reg); + } + break; + case UC_X86_REG_FPSW: + { + uint16_t fpus = X86_CPU(uc, mycpu)->env.fpus; + fpus = fpus & ~(7<<11); + fpus |= (X86_CPU(uc, mycpu)->env.fpstt&7)<<11; + *(uint16_t*) value = fpus; + } + break; + } + switch(uc->mode) { default: break; @@ -573,6 +592,26 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { CPUState *mycpu = first_cpu; + switch(regid) { + default: + break; + case UC_X86_REG_FP0 ... UC_X86_REG_FP7: + { + //floatx80 cpu_set_fp80(uint64_t mant, uint16_t upper); + uint64_t mant = *(uint64_t*) value; + uint16_t upper = *(uint16_t*) (value+sizeof(uint64_t)); + X86_CPU(uc, mycpu)->env.fpregs[regid - UC_X86_REG_FP0].d = cpu_set_fp80(mant, upper); + } + break; + case UC_X86_REG_FPSW: + { + uint16_t fpus = *(uint16_t*) value; + X86_CPU(uc, mycpu)->env.fpus = fpus; + X86_CPU(uc, mycpu)->env.fpstt = (fpus>>11)&7; + } + break; + } + switch(uc->mode) { default: break; From a5f2a64de52dfa1772cd8de0886292964fe32236 Mon Sep 17 00:00:00 2001 From: feliam Date: Wed, 9 Mar 2016 18:27:59 -0300 Subject: [PATCH 117/126] -spaces- --- bindings/python/unicorn/unicorn.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index 28ba7e77..01cbff13 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -156,7 +156,6 @@ def uc_arch_supported(query): return _uc.uc_arch_supported(query) - class uc_x86_mmr(ctypes.Structure): '''Memory-Management Register for instructions IDTR, GDTR, LDTR, TR.''' _fields_ = [ @@ -166,6 +165,7 @@ class uc_x86_mmr(ctypes.Structure): ("flags", ctypes.c_uint32), # not used by GDTR and IDTR ] + class uc_x86_float80(ctypes.Structure): '''Float80''' _fields_ = [ @@ -173,6 +173,7 @@ class uc_x86_float80(ctypes.Structure): ("exponent", ctypes.c_uint16), ] + class Uc(object): def __init__(self, arch, mode): # verify version compatibility with the core before doing anything From 0a3799eadac6ad335551d4fb30328a9e6c802e8e Mon Sep 17 00:00:00 2001 From: feliam Date: Wed, 9 Mar 2016 19:14:33 -0300 Subject: [PATCH 118/126] FPU control word and tags --- bindings/python/unicorn/x86_const.py | 4 ++- include/unicorn/x86.h | 3 +- qemu/target-i386/unicorn.c | 52 +++++++++++++++++++++++++--- 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/bindings/python/unicorn/x86_const.py b/bindings/python/unicorn/x86_const.py index a0cf0abc..8f93c0e0 100644 --- a/bindings/python/unicorn/x86_const.py +++ b/bindings/python/unicorn/x86_const.py @@ -248,7 +248,9 @@ UC_X86_REG_IDTR = 242 UC_X86_REG_GDTR = 243 UC_X86_REG_LDTR = 244 UC_X86_REG_TR = 245 -UC_X86_REG_ENDING = 246 +UC_X86_REG_FPTAGS = 246 +UC_X86_REG_FPCW = 247 +UC_X86_REG_ENDING = 248 # X86 instructions diff --git a/include/unicorn/x86.h b/include/unicorn/x86.h index 51401eba..88559730 100644 --- a/include/unicorn/x86.h +++ b/include/unicorn/x86.h @@ -73,7 +73,8 @@ typedef enum uc_x86_reg { UC_X86_REG_R9D, UC_X86_REG_R10D, UC_X86_REG_R11D, UC_X86_REG_R12D, UC_X86_REG_R13D, UC_X86_REG_R14D, UC_X86_REG_R15D, UC_X86_REG_R8W, UC_X86_REG_R9W, UC_X86_REG_R10W, UC_X86_REG_R11W, UC_X86_REG_R12W, UC_X86_REG_R13W, UC_X86_REG_R14W, UC_X86_REG_R15W, - UC_X86_REG_IDTR, UC_X86_REG_GDTR, UC_X86_REG_LDTR, UC_X86_REG_TR, + UC_X86_REG_IDTR, UC_X86_REG_GDTR, UC_X86_REG_LDTR, UC_X86_REG_TR, UC_X86_REG_FPCW, + UC_X86_REG_FPTAG, UC_X86_REG_ENDING // <-- mark the end of the list of registers } uc_x86_reg; diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index 3ab525c3..4b285f93 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -152,10 +152,42 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) case UC_X86_REG_FPSW: { uint16_t fpus = X86_CPU(uc, mycpu)->env.fpus; - fpus = fpus & ~(7<<11); - fpus |= (X86_CPU(uc, mycpu)->env.fpstt&7)<<11; + fpus = fpus & ~0x3800; + fpus |= ( X86_CPU(uc, mycpu)->env.fpstt & 0x7 ) << 11; *(uint16_t*) value = fpus; } + case UC_X86_REG_FPCW: + *(uint16_t*) value = X86_CPU(uc, mycpu)->env.fpuc; + break; + case UC_X86_REG_FPTAG: + { + #define EXPD(fp) (fp.l.upper & 0x7fff) + #define MANTD(fp) (fp.l.lower) + #define MAXEXPD 0x7fff + int fptag, exp, i; + uint64_t mant; + CPU_LDoubleU tmp; + fptag = 0; + for (i = 7; i >= 0; i--) { + fptag <<= 2; + if (X86_CPU(uc, mycpu)->env.fptags[i]) { + fptag |= 3; + } else { + tmp.d = X86_CPU(uc, mycpu)->env.fpregs[i].d; + exp = EXPD(tmp); + mant = MANTD(tmp); + if (exp == 0 && mant == 0) { + /* zero */ + fptag |= 1; + } else if (exp == 0 || exp == MAXEXPD + || (mant & (1LL << 63)) == 0) { + /* NaNs, infinity, denormal */ + fptag |= 2; + } + } + } + *(uint16_t*) value = fptag; + } break; } @@ -606,10 +638,22 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) case UC_X86_REG_FPSW: { uint16_t fpus = *(uint16_t*) value; - X86_CPU(uc, mycpu)->env.fpus = fpus; - X86_CPU(uc, mycpu)->env.fpstt = (fpus>>11)&7; + X86_CPU(uc, mycpu)->env.fpus = fpus & ~0x3800; + X86_CPU(uc, mycpu)->env.fpstt = (fpus >> 11) & 0x7; } break; + case UC_X86_REG_FPCW: + *(uint16_t*) value = X86_CPU(uc, mycpu)->env.fpuc; + break; + case UC_X86_REG_FPTAG: + { + int i; + uint16_t fptag = *(uint16_t*) value; + for (i = 0; i < 8; i++) { + X86_CPU(uc, mycpu)->env.fptags[i] = ((fptag & 3) == 3); + fptag >>= 2; + } + } } switch(uc->mode) { From 3038726a5b9fef12bb78b6ea5dd593c1fbe853b7 Mon Sep 17 00:00:00 2001 From: feliam Date: Wed, 9 Mar 2016 22:14:51 -0300 Subject: [PATCH 119/126] Fix --- bindings/python/unicorn/unicorn.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index 01cbff13..aef9d996 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -246,6 +246,8 @@ class Uc(object): # write to a register def reg_write(self, reg_id, value): + reg = None + if self._arch == UC_ARCH_X86: if reg_id in [ x86_const.UC_X86_REG_IDTR, x86_const.UC_X86_REG_GDTR, x86_const.UC_X86_REG_LDTR, x86_const.UC_X86_REG_TR]: assert isinstance(value, tuple) and len(value)==4 @@ -258,7 +260,8 @@ class Uc(object): reg = uc_x86_float80() reg.mantissa = value[0] reg.exponent = value[1] - else: + + if reg is None: # convert to 64bit number to be safe reg = ctypes.c_int64(value) From c5b123d2d9d86c5d0ac8ddc936b5b53cd88139d4 Mon Sep 17 00:00:00 2001 From: xorstream Date: Thu, 10 Mar 2016 14:41:11 +1100 Subject: [PATCH 120/126] Updated MSVC bindings for new and changed functions. --- bindings/msvc/unicorn.def | 3 ++ bindings/msvc/unicorn_dynload.c | 56 +++++++++++++++++++++++---------- bindings/msvc/unicorn_dynload.h | 2 +- 3 files changed, 44 insertions(+), 17 deletions(-) diff --git a/bindings/msvc/unicorn.def b/bindings/msvc/unicorn.def index c8d88b3b..d53f96a3 100644 --- a/bindings/msvc/unicorn.def +++ b/bindings/msvc/unicorn.def @@ -3,6 +3,7 @@ uc_version uc_arch_supported uc_open uc_close +uc_query uc_errno uc_strerror uc_reg_write @@ -14,5 +15,7 @@ uc_emu_stop uc_hook_add uc_hook_del uc_mem_map +uc_mem_map_ptr uc_mem_unmap uc_mem_protect +uc_mem_regions diff --git a/bindings/msvc/unicorn_dynload.c b/bindings/msvc/unicorn_dynload.c index ca9b4e2a..5db754f8 100644 --- a/bindings/msvc/unicorn_dynload.c +++ b/bindings/msvc/unicorn_dynload.c @@ -1,6 +1,6 @@ // // Dynamic loader for unicorn shared library in windows and linux. -// This was made for v0.9 of unicorn. +// This was made for v1.0 of unicorn. // Newer versions of unicorn may require changes to these files. // // Windows Notes: @@ -62,6 +62,7 @@ typedef unsigned int (*uc_version_t)(unsigned int *major, unsigned int *minor); typedef bool (*uc_arch_supported_t)(uc_arch arch); typedef uc_err (*uc_open_t)(uc_arch arch, uc_mode mode, uc_engine **uc); typedef uc_err (*uc_close_t)(uc_engine *uc); +typedef uc_err (*uc_query_t)(uc_engine *uc, uc_query_type type, size_t *result); typedef uc_err (*uc_errno_t)(uc_engine *uc); typedef const char* (*uc_strerror_t)(uc_err code); typedef uc_err (*uc_reg_write_t)(uc_engine *uc, int regid, const void *value); @@ -70,17 +71,20 @@ typedef uc_err (*uc_mem_write_t)(uc_engine *uc, uint64_t address, const void *by typedef uc_err (*uc_mem_read_t)(uc_engine *uc, uint64_t address, void *bytes, size_t size); typedef uc_err (*uc_emu_start_t)(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count); typedef uc_err (*uc_emu_stop_t)(uc_engine *uc); -typedef uc_err (*uc_hook_add_t)(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, ...); +typedef uc_err (*uc_hook_add_t)(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, uint64_t begin, uint64_t end, ...); typedef uc_err (*uc_hook_del_t)(uc_engine *uc, uc_hook hh); typedef uc_err (*uc_mem_map_t)(uc_engine *uc, uint64_t address, size_t size, uint32_t perms); +typedef uc_err (*uc_mem_map_ptr_t)(uc_engine *uc, uint64_t address, size_t size, uint32_t perms, void *ptr); typedef uc_err (*uc_mem_unmap_t)(uc_engine *uc, uint64_t address, size_t size); typedef uc_err (*uc_mem_protect_t)(uc_engine *uc, uint64_t address, size_t size, uint32_t perms); +typedef uc_err (*uc_mem_regions_t)(uc_engine *uc, uc_mem_region **regions, uint32_t *count); static uc_version_t gp_uc_version = NULL; static uc_arch_supported_t gp_uc_arch_supported = NULL; static uc_open_t gp_uc_open = NULL; static uc_close_t gp_uc_close = NULL; +static uc_query_t gp_uc_query = NULL; static uc_errno_t gp_uc_errno = NULL; static uc_strerror_t gp_uc_strerror = NULL; static uc_reg_write_t gp_uc_reg_write = NULL; @@ -92,8 +96,10 @@ static uc_emu_stop_t gp_uc_emu_stop = NULL; static uc_hook_add_t gp_uc_hook_add = NULL; static uc_hook_del_t gp_uc_hook_del = NULL; static uc_mem_map_t gp_uc_mem_map = NULL; +static uc_mem_map_ptr_t gp_uc_mem_map_ptr = NULL; static uc_mem_unmap_t gp_uc_mem_unmap = NULL; static uc_mem_protect_t gp_uc_mem_protect = NULL; +static uc_mem_regions_t gp_uc_mem_regions = NULL; bool uc_dyn_load(const char* path, int flags) @@ -118,6 +124,7 @@ bool uc_dyn_load(const char* path, int flags) gp_uc_arch_supported = (uc_arch_supported_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_arch_supported"); gp_uc_open = (uc_open_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_open"); gp_uc_close = (uc_close_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_close"); + gp_uc_query = (uc_query_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_query"); gp_uc_errno = (uc_errno_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_errno"); gp_uc_strerror = (uc_strerror_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_strerror"); gp_uc_reg_write = (uc_reg_write_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_reg_write"); @@ -129,8 +136,10 @@ bool uc_dyn_load(const char* path, int flags) gp_uc_hook_add = (uc_hook_add_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_hook_add"); gp_uc_hook_del = (uc_hook_del_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_hook_del"); gp_uc_mem_map = (uc_mem_map_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_map"); + gp_uc_mem_map_ptr = (uc_mem_map_ptr_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_map_ptr"); gp_uc_mem_unmap = (uc_mem_unmap_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_unmap"); gp_uc_mem_protect = (uc_mem_protect_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_protect"); + gp_uc_mem_regions = (uc_mem_regions_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_regions"); return true; } @@ -146,6 +155,7 @@ bool uc_dyn_free(void) gp_uc_arch_supported = NULL; gp_uc_open = NULL; gp_uc_close = NULL; + gp_uc_query = NULL; gp_uc_errno = NULL; gp_uc_strerror = NULL; gp_uc_reg_write = NULL; @@ -157,8 +167,10 @@ bool uc_dyn_free(void) gp_uc_hook_add = NULL; gp_uc_hook_del = NULL; gp_uc_mem_map = NULL; + gp_uc_mem_map_ptr = NULL; gp_uc_mem_unmap = NULL; gp_uc_mem_protect = NULL; + gp_uc_mem_regions = NULL; return true; } @@ -183,6 +195,11 @@ uc_err uc_close(uc_engine *uc) return gp_uc_close(uc); } +uc_err uc_query(uc_engine *uc, uc_query_type type, size_t *result) +{ + return gp_uc_query(uc, type, result); +} + uc_err uc_errno(uc_engine *uc) { return gp_uc_errno(uc); @@ -223,43 +240,40 @@ uc_err uc_emu_stop(uc_engine *uc) return gp_uc_emu_stop(uc); } -uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, ...) +uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, uint64_t begin, uint64_t end, ...) { va_list valist; uc_err ret = UC_ERR_OK; int id; - uint64_t begin, end; va_start(valist, user_data); switch(type) { // note this default case will capture any combinations of // UC_HOOK_MEM_*_PROT and UC_HOOK_MEM_*_UNMAPPED + // as well as any combination of + // UC_HOOK_MEM_READ, UC_HOOK_MEM_WRITE and UC_HOOK_MEM_FETCH default: case UC_HOOK_INTR: + case UC_HOOK_CODE: + case UC_HOOK_BLOCK: + // all combinations of UC_HOOK_MEM_*_PROT and UC_HOOK_MEM_*_UNMAPPED are caught by 'default' case UC_HOOK_MEM_READ_UNMAPPED: case UC_HOOK_MEM_WRITE_UNMAPPED: case UC_HOOK_MEM_FETCH_UNMAPPED: case UC_HOOK_MEM_READ_PROT: case UC_HOOK_MEM_WRITE_PROT: case UC_HOOK_MEM_FETCH_PROT: + // all combinations of read/write/fetch are caught by 'default' + case UC_HOOK_MEM_READ: + case UC_HOOK_MEM_WRITE: case UC_HOOK_MEM_FETCH: // 0 extra args - ret = gp_uc_hook_add(uc, hh, type, callback, user_data); + ret = gp_uc_hook_add(uc, hh, type, callback, user_data, begin, end); break; case UC_HOOK_INSN: // 1 extra arg id = va_arg(valist, int); - ret = gp_uc_hook_add(uc, hh, type, callback, user_data, id); - break; - case UC_HOOK_CODE: - case UC_HOOK_BLOCK: - case UC_HOOK_MEM_READ: - case UC_HOOK_MEM_WRITE: - case UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE: - // 2 extra args - begin = va_arg(valist, uint64_t); - end = va_arg(valist, uint64_t); - ret = gp_uc_hook_add(uc, hh, type, callback, user_data, begin, end); + ret = gp_uc_hook_add(uc, hh, type, callback, user_data, begin, end, id); break; } @@ -277,6 +291,11 @@ uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms) return gp_uc_mem_map(uc, address, size, perms); } +uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size, uint32_t perms, void *ptr) +{ + return gp_uc_mem_map_ptr(uc, address, size, perms, ptr); +} + uc_err uc_mem_unmap(uc_engine *uc, uint64_t address, size_t size) { return gp_uc_mem_unmap(uc, address, size); @@ -287,4 +306,9 @@ uc_err uc_mem_protect(uc_engine *uc, uint64_t address, size_t size, uint32_t per return gp_uc_mem_protect(uc, address, size, perms); } +uc_err uc_mem_regions(uc_engine *uc, uc_mem_region **regions, uint32_t *count) +{ + return gp_uc_mem_regions(uc, regions, count); +} + #endif // DYNLOAD diff --git a/bindings/msvc/unicorn_dynload.h b/bindings/msvc/unicorn_dynload.h index 638f5250..2618bde5 100644 --- a/bindings/msvc/unicorn_dynload.h +++ b/bindings/msvc/unicorn_dynload.h @@ -1,6 +1,6 @@ // // Dynamic loader for unicorn shared library in windows and linux. -// This was made for v0.9 of unicorn. +// This was made for v1.0 of unicorn. // Newer versions of unicorn may require changes to these files. // // Windows Notes: From 23b3f651f910afb28a68fb1c2810d21aba9082f2 Mon Sep 17 00:00:00 2001 From: feliam Date: Thu, 10 Mar 2016 07:45:36 -0300 Subject: [PATCH 121/126] Indentation --- bindings/python/unicorn/unicorn.py | 1 + include/unicorn/x86.h | 2 +- qemu/target-i386/unicorn.c | 8 ++++---- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index aef9d996..7b592a7c 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -206,6 +206,7 @@ class Uc(object): except: # _uc might be pulled from under our feet pass + # emulate from @begin, and stop when reaching address @until def emu_start(self, begin, until, timeout=0, count=0): status = _uc.uc_emu_start(self._uch, begin, until, timeout, count) diff --git a/include/unicorn/x86.h b/include/unicorn/x86.h index 88559730..fe33c723 100644 --- a/include/unicorn/x86.h +++ b/include/unicorn/x86.h @@ -74,7 +74,7 @@ typedef enum uc_x86_reg { UC_X86_REG_R14D, UC_X86_REG_R15D, UC_X86_REG_R8W, UC_X86_REG_R9W, UC_X86_REG_R10W, UC_X86_REG_R11W, UC_X86_REG_R12W, UC_X86_REG_R13W, UC_X86_REG_R14W, UC_X86_REG_R15W, UC_X86_REG_IDTR, UC_X86_REG_GDTR, UC_X86_REG_LDTR, UC_X86_REG_TR, UC_X86_REG_FPCW, - UC_X86_REG_FPTAG, + UC_X86_REG_FPTAG, UC_X86_REG_ENDING // <-- mark the end of the list of registers } uc_x86_reg; diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index 4b285f93..106266f3 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -152,7 +152,7 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) case UC_X86_REG_FPSW: { uint16_t fpus = X86_CPU(uc, mycpu)->env.fpus; - fpus = fpus & ~0x3800; + fpus = fpus & ~0x3800; fpus |= ( X86_CPU(uc, mycpu)->env.fpstt & 0x7 ) << 11; *(uint16_t*) value = fpus; } @@ -629,9 +629,8 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) break; case UC_X86_REG_FP0 ... UC_X86_REG_FP7: { - //floatx80 cpu_set_fp80(uint64_t mant, uint16_t upper); uint64_t mant = *(uint64_t*) value; - uint16_t upper = *(uint16_t*) (value+sizeof(uint64_t)); + uint16_t upper = *(uint16_t*) (value + sizeof(uint64_t)); X86_CPU(uc, mycpu)->env.fpregs[regid - UC_X86_REG_FP0].d = cpu_set_fp80(mant, upper); } break; @@ -654,7 +653,8 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) fptag >>= 2; } } - } + break; + } switch(uc->mode) { default: From 28b94d10b8ff76a2193a4ae42f6949a7f58fd4a0 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Mon, 14 Mar 2016 09:14:48 +0800 Subject: [PATCH 122/126] bindings: add X86 FPTAGS & FPCW registers after recent change in the core --- bindings/dotnet/UnicornManaged/Const/X86.fs | 4 +++- bindings/go/unicorn/x86_const.go | 4 +++- bindings/java/unicorn/X86Const.java | 4 +++- bindings/python/unicorn/x86_const.py | 4 ++-- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/bindings/dotnet/UnicornManaged/Const/X86.fs b/bindings/dotnet/UnicornManaged/Const/X86.fs index e293d5a1..d0526f87 100644 --- a/bindings/dotnet/UnicornManaged/Const/X86.fs +++ b/bindings/dotnet/UnicornManaged/Const/X86.fs @@ -255,7 +255,9 @@ module X86 = let UC_X86_REG_GDTR = 243 let UC_X86_REG_LDTR = 244 let UC_X86_REG_TR = 245 - let UC_X86_REG_ENDING = 246 + let UC_X86_REG_FPCW = 246 + let UC_X86_REG_FPTAG = 247 + let UC_X86_REG_ENDING = 248 // X86 instructions diff --git a/bindings/go/unicorn/x86_const.go b/bindings/go/unicorn/x86_const.go index 49e2310f..ef18c08e 100644 --- a/bindings/go/unicorn/x86_const.go +++ b/bindings/go/unicorn/x86_const.go @@ -250,7 +250,9 @@ const ( X86_REG_GDTR = 243 X86_REG_LDTR = 244 X86_REG_TR = 245 - X86_REG_ENDING = 246 + X86_REG_FPCW = 246 + X86_REG_FPTAG = 247 + X86_REG_ENDING = 248 // X86 instructions diff --git a/bindings/java/unicorn/X86Const.java b/bindings/java/unicorn/X86Const.java index 9c6d93ee..7afed1f9 100644 --- a/bindings/java/unicorn/X86Const.java +++ b/bindings/java/unicorn/X86Const.java @@ -252,7 +252,9 @@ public interface X86Const { public static final int UC_X86_REG_GDTR = 243; public static final int UC_X86_REG_LDTR = 244; public static final int UC_X86_REG_TR = 245; - public static final int UC_X86_REG_ENDING = 246; + public static final int UC_X86_REG_FPCW = 246; + public static final int UC_X86_REG_FPTAG = 247; + public static final int UC_X86_REG_ENDING = 248; // X86 instructions diff --git a/bindings/python/unicorn/x86_const.py b/bindings/python/unicorn/x86_const.py index 8f93c0e0..ee5ba38f 100644 --- a/bindings/python/unicorn/x86_const.py +++ b/bindings/python/unicorn/x86_const.py @@ -248,8 +248,8 @@ UC_X86_REG_IDTR = 242 UC_X86_REG_GDTR = 243 UC_X86_REG_LDTR = 244 UC_X86_REG_TR = 245 -UC_X86_REG_FPTAGS = 246 -UC_X86_REG_FPCW = 247 +UC_X86_REG_FPCW = 246 +UC_X86_REG_FPTAG = 247 UC_X86_REG_ENDING = 248 # X86 instructions From 75e5fb466c38a0cc83dbc3826af34ee4d34477f7 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Mon, 14 Mar 2016 09:27:46 +0800 Subject: [PATCH 123/126] x86: fix writing to UC_X86_REG_FPCW --- qemu/target-i386/unicorn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index 106266f3..a3ccfe8c 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -642,7 +642,7 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) } break; case UC_X86_REG_FPCW: - *(uint16_t*) value = X86_CPU(uc, mycpu)->env.fpuc; + X86_CPU(uc, mycpu)->env.fpuc = *(uint16_t *)value; break; case UC_X86_REG_FPTAG: { From 0524f34b8201cf37bc2784fcde8db8af11c0e4e5 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Mon, 14 Mar 2016 23:50:58 +0800 Subject: [PATCH 124/126] rename appveyor.yml to .appveyor.yml --- appveyor.yml => .appveyor.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename appveyor.yml => .appveyor.yml (100%) diff --git a/appveyor.yml b/.appveyor.yml similarity index 100% rename from appveyor.yml rename to .appveyor.yml From 2a9a794bffa30402819cd9873577ecc2f424288d Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Mon, 14 Mar 2016 17:44:02 -0700 Subject: [PATCH 125/126] tweak Go bindings for 32-bit --- bindings/go/unicorn/unicorn.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/go/unicorn/unicorn.go b/bindings/go/unicorn/unicorn.go index 2b0e456c..be8a7348 100644 --- a/bindings/go/unicorn/unicorn.go +++ b/bindings/go/unicorn/unicorn.go @@ -120,7 +120,7 @@ func (u *uc) MemRegions() ([]*MemRegion, error) { return nil, errReturn(ucerr) } ret := make([]*MemRegion, count) - tmp := (*[1 << 30]C.struct_uc_mem_region)(unsafe.Pointer(regions))[:count] + tmp := (*[1 << 24]C.struct_uc_mem_region)(unsafe.Pointer(regions))[:count] for i, v := range tmp { ret[i] = &MemRegion{ Begin: uint64(v.begin), From b43f89566f7ec3f209a2e2862089c3d7fa36befa Mon Sep 17 00:00:00 2001 From: feliam Date: Tue, 15 Mar 2016 12:17:40 -0300 Subject: [PATCH 126/126] Bugfix --- qemu/target-i386/unicorn.c | 1 + 1 file changed, 1 insertion(+) diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index a3ccfe8c..6d149ece 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -156,6 +156,7 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) fpus |= ( X86_CPU(uc, mycpu)->env.fpstt & 0x7 ) << 11; *(uint16_t*) value = fpus; } + break; case UC_X86_REG_FPCW: *(uint16_t*) value = X86_CPU(uc, mycpu)->env.fpuc; break;