diff --git a/bindings/dotnet/UnicornEngine/Const/Arm.fs b/bindings/dotnet/UnicornEngine/Const/Arm.fs index 8a275261..1d7f218a 100644 --- a/bindings/dotnet/UnicornEngine/Const/Arm.fs +++ b/bindings/dotnet/UnicornEngine/Const/Arm.fs @@ -187,7 +187,8 @@ module Arm = let UC_ARM_REG_XPSR_G = 137 let UC_ARM_REG_XPSR_NZCVQG = 138 let UC_ARM_REG_CP_REG = 139 - let UC_ARM_REG_ENDING = 140 + let UC_ARM_REG_ESR = 140 + let UC_ARM_REG_ENDING = 141 // alias registers let UC_ARM_REG_R13 = 12 diff --git a/bindings/go/unicorn/arm_const.go b/bindings/go/unicorn/arm_const.go index 554d5754..1008f204 100644 --- a/bindings/go/unicorn/arm_const.go +++ b/bindings/go/unicorn/arm_const.go @@ -182,7 +182,8 @@ const ( ARM_REG_XPSR_G = 137 ARM_REG_XPSR_NZCVQG = 138 ARM_REG_CP_REG = 139 - ARM_REG_ENDING = 140 + ARM_REG_ESR = 140 + ARM_REG_ENDING = 141 // alias registers ARM_REG_R13 = 12 @@ -192,4 +193,4 @@ const ( ARM_REG_SL = 76 ARM_REG_FP = 77 ARM_REG_IP = 78 -) \ No newline at end of file +) diff --git a/bindings/java/src/main/java/unicorn/ArmConst.java b/bindings/java/src/main/java/unicorn/ArmConst.java index 300a8fda..9e2e590a 100644 --- a/bindings/java/src/main/java/unicorn/ArmConst.java +++ b/bindings/java/src/main/java/unicorn/ArmConst.java @@ -184,7 +184,8 @@ public interface ArmConst { public static final int UC_ARM_REG_XPSR_G = 137; public static final int UC_ARM_REG_XPSR_NZCVQG = 138; public static final int UC_ARM_REG_CP_REG = 139; - public static final int UC_ARM_REG_ENDING = 140; + public static final int UC_ARM_REG_ESR = 140; + public static final int UC_ARM_REG_ENDING = 141; // alias registers public static final int UC_ARM_REG_R13 = 12; diff --git a/bindings/pascal/unicorn/ArmConst.pas b/bindings/pascal/unicorn/ArmConst.pas index 8974f494..39a7262c 100644 --- a/bindings/pascal/unicorn/ArmConst.pas +++ b/bindings/pascal/unicorn/ArmConst.pas @@ -185,7 +185,8 @@ const UC_ARM_REG_XPSR_G = 137; UC_ARM_REG_XPSR_NZCVQG = 138; UC_ARM_REG_CP_REG = 139; - UC_ARM_REG_ENDING = 140; + UC_ARM_REG_ESR = 140; + UC_ARM_REG_ENDING = 141; // alias registers UC_ARM_REG_R13 = 12; @@ -197,4 +198,4 @@ const UC_ARM_REG_IP = 78; implementation -end. \ No newline at end of file +end. diff --git a/bindings/python/unicorn/arm_const.py b/bindings/python/unicorn/arm_const.py index e48825b0..54d29272 100644 --- a/bindings/python/unicorn/arm_const.py +++ b/bindings/python/unicorn/arm_const.py @@ -180,7 +180,8 @@ UC_ARM_REG_XPSR_NZCVQ = 136 UC_ARM_REG_XPSR_G = 137 UC_ARM_REG_XPSR_NZCVQG = 138 UC_ARM_REG_CP_REG = 139 -UC_ARM_REG_ENDING = 140 +UC_ARM_REG_ESR = 140 +UC_ARM_REG_ENDING = 141 # alias registers UC_ARM_REG_R13 = 12 diff --git a/bindings/ruby/unicorn_gem/lib/unicorn_engine/arm_const.rb b/bindings/ruby/unicorn_gem/lib/unicorn_engine/arm_const.rb index 181b4349..f2f96fc0 100644 --- a/bindings/ruby/unicorn_gem/lib/unicorn_engine/arm_const.rb +++ b/bindings/ruby/unicorn_gem/lib/unicorn_engine/arm_const.rb @@ -182,7 +182,8 @@ module UnicornEngine UC_ARM_REG_XPSR_G = 137 UC_ARM_REG_XPSR_NZCVQG = 138 UC_ARM_REG_CP_REG = 139 - UC_ARM_REG_ENDING = 140 + UC_ARM_REG_ESR = 140 + UC_ARM_REG_ENDING = 141 # alias registers UC_ARM_REG_R13 = 12 @@ -192,4 +193,4 @@ module UnicornEngine UC_ARM_REG_SL = 76 UC_ARM_REG_FP = 77 UC_ARM_REG_IP = 78 -end \ No newline at end of file +end diff --git a/bindings/rust/src/arm.rs b/bindings/rust/src/arm.rs index df43245d..8e453a09 100644 --- a/bindings/rust/src/arm.rs +++ b/bindings/rust/src/arm.rs @@ -145,7 +145,8 @@ pub enum RegisterARM { XPSR_G = 137, XPSR_NZCVQG = 138, CP_REG = 139, - ENDING = 140, + ESR = 140, + ENDING = 141, } impl RegisterARM { diff --git a/bindings/zig/unicorn/arm_const.zig b/bindings/zig/unicorn/arm_const.zig index 2403e9a7..811cef6d 100644 --- a/bindings/zig/unicorn/arm_const.zig +++ b/bindings/zig/unicorn/arm_const.zig @@ -182,7 +182,8 @@ pub const armConst = enum(c_int) { ARM_REG_XPSR_G = 137, ARM_REG_XPSR_NZCVQG = 138, ARM_REG_CP_REG = 139, - ARM_REG_ENDING = 140, + ARM_REG_ESR = 140, + ARM_REG_ENDING = 141, // alias registers ARM_REG_R13 = 12, diff --git a/include/unicorn/arm.h b/include/unicorn/arm.h index 7b3686ad..ea77a44d 100644 --- a/include/unicorn/arm.h +++ b/include/unicorn/arm.h @@ -212,6 +212,9 @@ typedef enum uc_arm_reg { UC_ARM_REG_XPSR_G, UC_ARM_REG_XPSR_NZCVQG, UC_ARM_REG_CP_REG, + // A pseudo-register for fetching the exception syndrome + // from the CPU state. This is not a real register. + UC_ARM_REG_ESR, UC_ARM_REG_ENDING, // <-- mark the end of the list or registers //> alias registers diff --git a/qemu/target/arm/unicorn_arm.c b/qemu/target/arm/unicorn_arm.c index a1a73186..31d94472 100644 --- a/qemu/target/arm/unicorn_arm.c +++ b/qemu/target/arm/unicorn_arm.c @@ -352,6 +352,10 @@ uc_err reg_read(void *_env, int mode, unsigned int regid, void *value, CHECK_REG_TYPE(uc_arm_cp_reg); ret = read_cp_reg(env, (uc_arm_cp_reg *)value); break; + case UC_ARM_REG_ESR: + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->exception.syndrome; + break; } } @@ -556,6 +560,10 @@ uc_err reg_write(void *_env, int mode, unsigned int regid, const void *value, ret = write_cp_reg(env, (uc_arm_cp_reg *)value); arm_rebuild_hflags_arm(env); break; + case UC_ARM_REG_ESR: + CHECK_REG_TYPE(uint32_t); + env->exception.syndrome = *(uint32_t *)value; + break; } } diff --git a/tests/unit/test_arm.c b/tests/unit/test_arm.c index 309b5ccb..ec57465b 100644 --- a/tests/unit/test_arm.c +++ b/tests/unit/test_arm.c @@ -966,8 +966,8 @@ static bool test_arm_v7_lpae_hook_tlb(uc_engine *uc, uint64_t addr, } static void test_arm_v7_lpae_hook_read(uc_engine *uc, uc_mem_type type, - uint64_t address, int size, uint64_t value, - void *user_data) + uint64_t address, int size, + uint64_t value, void *user_data) { TEST_CHECK(address == 0x100001000); } @@ -981,10 +981,11 @@ static void test_arm_v7_lpae(void) OK(uc_open(UC_ARCH_ARM, UC_MODE_ARM, &uc)); OK(uc_ctl_set_cpu_model(uc, UC_CPU_ARM_CORTEX_A7)); - OK(uc_ctl_tlb_mode(uc, UC_TLB_VIRTUAL)); - OK(uc_hook_add(uc, &hook_tlb, UC_HOOK_TLB_FILL, test_arm_v7_lpae_hook_tlb, NULL, 1, 0)); - OK(uc_hook_add(uc, &hook_read, UC_HOOK_MEM_READ, test_arm_v7_lpae_hook_read, NULL, 1, 0)); + OK(uc_hook_add(uc, &hook_tlb, UC_HOOK_TLB_FILL, test_arm_v7_lpae_hook_tlb, + NULL, 1, 0)); + OK(uc_hook_add(uc, &hook_read, UC_HOOK_MEM_READ, test_arm_v7_lpae_hook_read, + NULL, 1, 0)); reg = 0x1000; OK(uc_reg_write(uc, UC_ARM_REG_R0, ®)); @@ -997,6 +998,42 @@ static void test_arm_v7_lpae(void) OK(uc_close(uc)); } +static void test_arm_svc_interrupt(uc_engine *uc, int intno, void *user_data) +{ + uint32_t esr; + OK(uc_reg_read(uc, UC_ARM_REG_ESR, &esr)); + switch (intno) { + // SVC + case 2: + TEST_CHECK((esr & 0xff) == 0x42); + break; + // HVC + case 3: + TEST_CHECK((esr & 0xff) == 0x33); + break; + } +} + +static void test_arm_svc_hvc_syndrome(void) +{ + uc_engine *uc; + uint8_t code[] = { + 0x42, 0x00, 0x00, 0xef, // svc #0x42 + 0x73, 0x03, 0x40, 0xe1, // hvc #0x33 + }; + + uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_ARM, (char *)code, sizeof(code), + UC_CPU_ARM_CORTEX_A15); + + uc_hook hook; + OK(uc_hook_add(uc, &hook, UC_HOOK_INTR, test_arm_svc_interrupt, NULL, 1, + 0)); + + OK(uc_emu_start(uc, code_start, code_start + 4, 0, 0)); + + OK(uc_close(uc)); +} + TEST_LIST = {{"test_arm_nop", test_arm_nop}, {"test_arm_thumb_sub", test_arm_thumb_sub}, {"test_armeb_sub", test_armeb_sub}, @@ -1027,4 +1064,5 @@ TEST_LIST = {{"test_arm_nop", test_arm_nop}, {"test_arm_thumb_tcg_opcode_cmn", test_arm_thumb_tcg_opcode_cmn}, {"test_arm_cp15_c1_c0_2", test_arm_cp15_c1_c0_2}, {"test_arm_v7_lpae", test_arm_v7_lpae}, + {"test_arm_svc_hvc_syndrome", test_arm_svc_hvc_syndrome}, {NULL, NULL}};