From 0ef2b5fd719e2f65f43333c68d0b60f48fb2bc70 Mon Sep 17 00:00:00 2001 From: Andrew Dutcher Date: Sat, 20 Aug 2016 04:14:07 -0700 Subject: [PATCH 1/6] New feature: registers can be bulk saved/restored in an opaque blob --- include/unicorn/unicorn.h | 29 +++++++++++++++++++++++++++ qemu/target-arm/unicorn.h | 3 +++ qemu/target-arm/unicorn_aarch64.c | 2 ++ qemu/target-arm/unicorn_arm.c | 2 ++ qemu/target-i386/unicorn.c | 2 ++ qemu/target-i386/unicorn.h | 2 ++ qemu/target-m68k/unicorn.c | 2 ++ qemu/target-m68k/unicorn.h | 1 + qemu/target-mips/unicorn.c | 8 ++++++++ qemu/target-mips/unicorn.h | 3 +++ qemu/target-sparc/unicorn.c | 2 ++ qemu/target-sparc/unicorn.h | 3 +++ qemu/target-sparc/unicorn64.c | 2 ++ uc.c | 33 +++++++++++++++++++++++++++++++ 14 files changed, 94 insertions(+) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 4619c7c3..5f04ec10 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -624,6 +624,35 @@ uc_err uc_mem_protect(uc_engine *uc, uint64_t address, size_t size, uint32_t per UNICORN_EXPORT uc_err uc_mem_regions(uc_engine *uc, uc_mem_region **regions, uint32_t *count); +/* + Save a copy of the current state's registers + This API should be used to efficiently make or update a saved copy of the + state's registers. + + @uc: handle returned by uc_open() + @buffer: pointer to the region to store the registers in. The first call to + this function should pass NULL in this parameter, so a region of the + appropriate size for the current architecure can be allocated. Further calls + to this function may pass in the return value of previous calls. + + @return a pointer to the region the registers were saved in. If buffer was + NULL, this is a newly allocated region, otherwise it is the same as buffer. + Any allocation performed by this function must be freed by the user. +*/ +UNICORN_EXPORT +void *uc_save_regstate(uc_engine *uc, void *buffer); + +/* + Restore the current state's registers from a saved copy + This API should be used to roll the CPU register state back to a previous + state saved by uc_save_regstate(). + + @uc: handle returned by uc_open() + @buffer: pointer returned by uc_save_regstate() +*/ +UNICORN_EXPORT +void uc_restore_regstate(uc_engine *uc, void *buffer); + #ifdef __cplusplus } #endif diff --git a/qemu/target-arm/unicorn.h b/qemu/target-arm/unicorn.h index 0b3fb93d..d8a02505 100644 --- a/qemu/target-arm/unicorn.h +++ b/qemu/target-arm/unicorn.h @@ -19,4 +19,7 @@ void arm_uc_init(struct uc_struct* uc); __attribute__ ((visibility ("default"))) void arm64_uc_init(struct uc_struct* uc); +extern const int ARM_REGS_STORAGE_SIZE; +extern const int ARM64_REGS_STORAGE_SIZE; + #endif diff --git a/qemu/target-arm/unicorn_aarch64.c b/qemu/target-arm/unicorn_aarch64.c index e2c593a6..bb2610fd 100644 --- a/qemu/target-arm/unicorn_aarch64.c +++ b/qemu/target-arm/unicorn_aarch64.c @@ -10,6 +10,8 @@ #include "uc_priv.h" +const int ARM64_REGS_STORAGE_SIZE = offsetof(CPUARMState, tlb_table); + static void arm64_set_pc(struct uc_struct *uc, uint64_t address) { ((CPUARMState *)uc->current_cpu->env_ptr)->pc = address; diff --git a/qemu/target-arm/unicorn_arm.c b/qemu/target-arm/unicorn_arm.c index bdf2222c..706cf7bb 100644 --- a/qemu/target-arm/unicorn_arm.c +++ b/qemu/target-arm/unicorn_arm.c @@ -10,6 +10,8 @@ #include "uc_priv.h" +const int ARM_REGS_STORAGE_SIZE = offsetof(CPUARMState, tlb_table); + static void arm_set_pc(struct uc_struct *uc, uint64_t address) { ((CPUARMState *)uc->current_cpu->env_ptr)->pc = address; diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index 004e2a4a..a4d7a640 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -12,6 +12,8 @@ #include "uc_priv.h" +const int X86_REGS_STORAGE_SIZE = offsetof(CPUX86State, tlb_table); + static void x86_set_pc(struct uc_struct *uc, uint64_t address) { ((CPUX86State *)uc->current_cpu->env_ptr)->eip = address; diff --git a/qemu/target-i386/unicorn.h b/qemu/target-i386/unicorn.h index 37e38b4f..cb292001 100644 --- a/qemu/target-i386/unicorn.h +++ b/qemu/target-i386/unicorn.h @@ -12,4 +12,6 @@ void x86_reg_reset(struct uc_struct *uc); void x86_uc_init(struct uc_struct* uc); int x86_uc_machine_init(struct uc_struct *uc); + +extern const int X86_REGS_STORAGE_SIZE; #endif diff --git a/qemu/target-m68k/unicorn.c b/qemu/target-m68k/unicorn.c index d2818cfe..849eb08f 100644 --- a/qemu/target-m68k/unicorn.c +++ b/qemu/target-m68k/unicorn.c @@ -10,6 +10,8 @@ #include "uc_priv.h" +const int M68K_REGS_STORAGE_SIZE = offsetof(CPUM68KState, tlb_table); + static void m68k_set_pc(struct uc_struct *uc, uint64_t address) { ((CPUM68KState *)uc->current_cpu->env_ptr)->pc = address; diff --git a/qemu/target-m68k/unicorn.h b/qemu/target-m68k/unicorn.h index 7cf8e21a..59471865 100644 --- a/qemu/target-m68k/unicorn.h +++ b/qemu/target-m68k/unicorn.h @@ -12,4 +12,5 @@ void m68k_reg_reset(struct uc_struct *uc); void m68k_uc_init(struct uc_struct* uc); +extern const int M68K_REGS_STORAGE_SIZE; #endif diff --git a/qemu/target-mips/unicorn.c b/qemu/target-mips/unicorn.c index 94c1819f..6d84a97b 100644 --- a/qemu/target-mips/unicorn.c +++ b/qemu/target-mips/unicorn.c @@ -9,6 +9,14 @@ #include "unicorn_common.h" #include "uc_priv.h" +// prevent the lines from being compiled twice +#ifdef TARGET_WORDS_BIGENDIAN +#ifdef TARGET_MIPS64 +const int MIPS64_REGS_STORAGE_SIZE = offsetof(CPUMIPSState, tlb_table); +#else // MIPS32 +const int MIPS_REGS_STORAGE_SIZE = offsetof(CPUMIPSState, tlb_table); +#endif +#endif static uint64_t mips_mem_redirect(uint64_t address) { diff --git a/qemu/target-mips/unicorn.h b/qemu/target-mips/unicorn.h index c9639eb8..53b5c32a 100644 --- a/qemu/target-mips/unicorn.h +++ b/qemu/target-mips/unicorn.h @@ -15,4 +15,7 @@ void mipsel_uc_init(struct uc_struct* uc); void mips64_uc_init(struct uc_struct* uc); void mips64el_uc_init(struct uc_struct* uc); +extern const int MIPS_REGS_STORAGE_SIZE; +extern const int MIPS64_REGS_STORAGE_SIZE; + #endif diff --git a/qemu/target-sparc/unicorn.c b/qemu/target-sparc/unicorn.c index a2a3dcaa..5cfb8d2a 100644 --- a/qemu/target-sparc/unicorn.c +++ b/qemu/target-sparc/unicorn.c @@ -10,6 +10,8 @@ #include "uc_priv.h" +const int SPARC_REGS_STORAGE_SIZE = offsetof(CPUSPARCState, tlb_table); + static bool sparc_stop_interrupt(int intno) { switch(intno) { diff --git a/qemu/target-sparc/unicorn.h b/qemu/target-sparc/unicorn.h index 53bf1303..2140f286 100644 --- a/qemu/target-sparc/unicorn.h +++ b/qemu/target-sparc/unicorn.h @@ -13,4 +13,7 @@ void sparc_reg_reset(struct uc_struct *uc); void sparc_uc_init(struct uc_struct* uc); void sparc64_uc_init(struct uc_struct* uc); +extern const int SPARC_REGS_STORAGE_SIZE; +extern const int SPARC64_REGS_STORAGE_SIZE; + #endif diff --git a/qemu/target-sparc/unicorn64.c b/qemu/target-sparc/unicorn64.c index 9a748936..b8a96dda 100644 --- a/qemu/target-sparc/unicorn64.c +++ b/qemu/target-sparc/unicorn64.c @@ -10,6 +10,8 @@ #include "uc_priv.h" +const int SPARC64_REGS_STORAGE_SIZE = offsetof(CPUSPARCState, tlb_table); + static bool sparc_stop_interrupt(int intno) { switch(intno) { diff --git a/uc.c b/uc.c index d6f26ba4..d9a9282d 100644 --- a/uc.c +++ b/uc.c @@ -1160,3 +1160,36 @@ uc_err uc_query(uc_engine *uc, uc_query_type type, size_t *result) return UC_ERR_OK; } + +size_t cpu_regs_size(uc_arch arch, uc_mode mode); +size_t cpu_regs_size(uc_arch arch, uc_mode mode) { + // each of these constants is defined by offsetof(CPUXYZState, tlb_table) + // tbl_table is the first entry in the CPU_COMMON macro, so it marks the end + // of the interesting CPU registers + switch (arch) { + case UC_ARCH_M68K: return M68K_REGS_STORAGE_SIZE; + case UC_ARCH_X86: return X86_REGS_STORAGE_SIZE; + case UC_ARCH_ARM: return ARM_REGS_STORAGE_SIZE; + case UC_ARCH_ARM64: return ARM64_REGS_STORAGE_SIZE; + case UC_ARCH_MIPS: return mode & UC_MODE_MIPS64 ? MIPS64_REGS_STORAGE_SIZE : MIPS_REGS_STORAGE_SIZE; + case UC_ARCH_SPARC: return mode & UC_MODE_SPARC64 ? SPARC64_REGS_STORAGE_SIZE : SPARC_REGS_STORAGE_SIZE; + default: return 0; + } +} + +UNICORN_EXPORT +void *uc_save_regstate(uc_engine *uc, void *buffer) { + size_t sz = cpu_regs_size(uc->arch, uc->mode); + if (!buffer) { + buffer = malloc(sz); + } + + memcpy(buffer, uc->current_cpu->env_ptr, sz); + return buffer; +} + +UNICORN_EXPORT +void uc_restore_regstate(uc_engine *uc, void *buffer) { + size_t sz = cpu_regs_size(uc->arch, uc->mode); + memcpy(uc->current_cpu->env_ptr, buffer, sz); +} From f2af98942b02561183966d0afd36c8455c09b81e Mon Sep 17 00:00:00 2001 From: Andrew Dutcher Date: Wed, 31 Aug 2016 20:25:28 -0500 Subject: [PATCH 2/6] Added (failing?) test for reg save/restore --- tests/unit/test_x86.c | 63 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/tests/unit/test_x86.c b/tests/unit/test_x86.c index 348cd5cd..ec1aa6f1 100644 --- a/tests/unit/test_x86.c +++ b/tests/unit/test_x86.c @@ -729,6 +729,68 @@ static void test_x86_16(void **state) /******************************************************************************/ +static void test_i386_reg_save(void **state) +{ + uc_engine *uc; + + static const uint64_t address = 0; + static const uint8_t code[] = { + 0x40 // inc eax + }; + int32_t eax = 1; + + // Initialize emulator + uc_assert_success(uc_open(UC_ARCH_X86, UC_MODE_16, &uc)); + + // map 8KB memory for this emulation + uc_assert_success(uc_mem_map(uc, address, 8 * 1024, UC_PROT_ALL)); + + // write machine code to be emulated to memory + uc_assert_success(uc_mem_write(uc, address, code, sizeof(code))); + + // set eax to 1 + uc_assert_success(uc_reg_write(uc, UC_X86_REG_EAX, &eax)); + + // step one instruction + uc_assert_success(uc_emu_start(uc, address, address+1, 0, 0)); + + // save the state + void *saved_regs = uc_save_regstate(uc, NULL); + + // step one instruction + uc_assert_success(uc_emu_start(uc, address, address+1, 0, 0)); + + // check that eax == 3 + uc_assert_success(uc_reg_read(uc, UC_X86_REG_EAX, &eax)); + assert_int_equal(eax, 3); + + // restore the state + uc_restore_regstate(uc, saved_regs); + + // check that eax == 2 + uc_assert_success(uc_reg_read(uc, UC_X86_REG_EAX, &eax)); + assert_int_equal(eax, 2); + + // step one instruction + uc_assert_success(uc_emu_start(uc, address, address+1, 0, 0)); + + // check that eax == 3 + uc_assert_success(uc_reg_read(uc, UC_X86_REG_EAX, &eax)); + assert_int_equal(eax, 3); + + // restore the state + uc_restore_regstate(uc, saved_regs); + + // check that eax == 2 + uc_assert_success(uc_reg_read(uc, UC_X86_REG_EAX, &eax)); + assert_int_equal(eax, 2); + + // clean up; + free(saved_regs); + uc_assert_success(uc_close(uc)); +} +/******************************************************************************/ + int main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(test_i386), @@ -738,6 +800,7 @@ int main(void) { cmocka_unit_test(test_i386_invalid_mem_read), cmocka_unit_test(test_i386_invalid_mem_write), cmocka_unit_test(test_i386_jump_invalid), + cmocka_unit_test(test_i386_reg_save), cmocka_unit_test(test_x86_64), cmocka_unit_test(test_x86_64_syscall), From 885b809004385eedbf786e9911ca76283e45d90c Mon Sep 17 00:00:00 2001 From: Andrew Dutcher Date: Thu, 8 Sep 2016 14:40:39 -0700 Subject: [PATCH 3/6] Add python bindings for reg save/restore --- bindings/python/sample_x86.py | 52 ++++++++++++++++++++++++++++++ bindings/python/unicorn/unicorn.py | 24 ++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/bindings/python/sample_x86.py b/bindings/python/sample_x86.py index 7010327f..e213a774 100755 --- a/bindings/python/sample_x86.py +++ b/bindings/python/sample_x86.py @@ -308,6 +308,56 @@ def test_i386_inout(): print("ERROR: %s" % e) +def test_i386_reg_save(): + print("Save/restore registers in opaque blob") + address = 0 + code = '\x40' # inc eax + try: + # Initialize emulator + mu = Uc(UC_ARCH_X86, UC_MODE_32) + + # map 8KB memory for this emulation + mu.mem_map(address, 8 * 1024, UC_PROT_ALL) + + # write machine code to be emulated to memory + mu.mem_write(address, code) + + print(">>> set eax to 1") + mu.reg_write(UC_X86_REG_EAX, 1) + + print(">>> execute 'inc eax'") + mu.emu_start(address, address+1) + + print(">>> save the register state") + saved_regs = mu.save_regs() + + print(">>> execute 'inc eax'") + mu.emu_start(address, address+1) + + print(">>> assert eax == 3") + assert mu.reg_read(UC_X86_REG_EAX) == 3 + + print(">>> restore the register state") + mu.restore_regs(saved_regs) + + print(">>> assert eax == 2") + assert mu.reg_read(UC_X86_REG_EAX) == 2 + + print(">>> execute 'inc eax'") + mu.emu_start(address, address+1) + + print(">>> assert eax == 3") + assert mu.reg_read(UC_X86_REG_EAX) == 3 + + print(">>> restore the register state") + mu.restore_regs(saved_regs) + + print(">>> assert eax == 2") + assert mu.reg_read(UC_X86_REG_EAX) == 2 + + except UcError as e: + print("ERROR: %s" % e) + def test_x86_64(): print("Emulate x86_64 code") try: @@ -479,6 +529,8 @@ if __name__ == '__main__': print("=" * 20) test_i386_inout() print("=" * 20) + test_i386_reg_save() + print("=" * 20) test_x86_64() print("=" * 20) test_x86_64_syscall() diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index a1083f70..cf541e9c 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -127,6 +127,9 @@ _setup_prototype(_uc, "uc_mem_map_ptr", ucerr, uc_engine, ctypes.c_uint64, ctype _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)) +_setup_prototype(_uc, "uc_save_regstate", ctypes.c_voidp, uc_engine, ctypes.c_voidp) +_setup_prototype(_uc, "uc_restore_regstate", None, uc_engine, ctypes.c_voidp) +_setup_prototype(_uc, "free", None, ctypes.c_voidp) # uc_hook_add is special due to variable number of arguments _uc.uc_hook_add = _uc.uc_hook_add @@ -449,6 +452,27 @@ class Uc(object): raise UcError(status) h = 0 + def save_regs(self, store=None): + if store is None: + ptr = ctypes.cast(0, ctypes.c_voidp) + return _ActivePointer(_uc.uc_save_regstate(self._uch, ptr)) + elif type(store) is _ActivePointer: + _uc.uc_save_regstate(self._uch, store.pointer) + return store + else: + raise TypeError("Bad register store %s" % repr(store)) + + def restore_regs(self, store): + if type(store) is not _ActivePointer: + raise TYpeError("Bad register store %s" % repr(store)) + _uc.uc_restore_regstate(self._uch, store.pointer) + +class _ActivePointer(object): + def __init__(self, pointer): + self.pointer = pointer + + def __del__(self): + _uc.free(self.pointer) # print out debugging info def debug(): From 3deb9fdcad0904c0a0c0509ba116e56a2ebf5730 Mon Sep 17 00:00:00 2001 From: Andrew Dutcher Date: Thu, 8 Sep 2016 14:41:34 -0700 Subject: [PATCH 4/6] Fix save/restore to work while emulation is not active --- tests/unit/test_x86.c | 2 +- uc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/unit/test_x86.c b/tests/unit/test_x86.c index ec1aa6f1..6daa1322 100644 --- a/tests/unit/test_x86.c +++ b/tests/unit/test_x86.c @@ -740,7 +740,7 @@ static void test_i386_reg_save(void **state) int32_t eax = 1; // Initialize emulator - uc_assert_success(uc_open(UC_ARCH_X86, UC_MODE_16, &uc)); + uc_assert_success(uc_open(UC_ARCH_X86, UC_MODE_32, &uc)); // map 8KB memory for this emulation uc_assert_success(uc_mem_map(uc, address, 8 * 1024, UC_PROT_ALL)); diff --git a/uc.c b/uc.c index d9a9282d..5694dd81 100644 --- a/uc.c +++ b/uc.c @@ -1184,12 +1184,12 @@ void *uc_save_regstate(uc_engine *uc, void *buffer) { buffer = malloc(sz); } - memcpy(buffer, uc->current_cpu->env_ptr, sz); + memcpy(buffer, first_cpu->env_ptr, sz); return buffer; } UNICORN_EXPORT void uc_restore_regstate(uc_engine *uc, void *buffer) { size_t sz = cpu_regs_size(uc->arch, uc->mode); - memcpy(uc->current_cpu->env_ptr, buffer, sz); + memcpy(first_cpu->env_ptr, buffer, sz); } From 20ce432dbc5ceced3f087b0416c1343fd94522cd Mon Sep 17 00:00:00 2001 From: Andrew Dutcher Date: Fri, 9 Sep 2016 11:55:20 -0700 Subject: [PATCH 5/6] Fix bracket style --- uc.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/uc.c b/uc.c index 5694dd81..132003d2 100644 --- a/uc.c +++ b/uc.c @@ -1162,7 +1162,8 @@ uc_err uc_query(uc_engine *uc, uc_query_type type, size_t *result) } size_t cpu_regs_size(uc_arch arch, uc_mode mode); -size_t cpu_regs_size(uc_arch arch, uc_mode mode) { +size_t cpu_regs_size(uc_arch arch, uc_mode mode) +{ // each of these constants is defined by offsetof(CPUXYZState, tlb_table) // tbl_table is the first entry in the CPU_COMMON macro, so it marks the end // of the interesting CPU registers @@ -1178,7 +1179,8 @@ size_t cpu_regs_size(uc_arch arch, uc_mode mode) { } UNICORN_EXPORT -void *uc_save_regstate(uc_engine *uc, void *buffer) { +void *uc_save_regstate(uc_engine *uc, void *buffer) +{ size_t sz = cpu_regs_size(uc->arch, uc->mode); if (!buffer) { buffer = malloc(sz); @@ -1189,7 +1191,8 @@ void *uc_save_regstate(uc_engine *uc, void *buffer) { } UNICORN_EXPORT -void uc_restore_regstate(uc_engine *uc, void *buffer) { +void uc_restore_regstate(uc_engine *uc, void *buffer) +{ size_t sz = cpu_regs_size(uc->arch, uc->mode); memcpy(first_cpu->env_ptr, buffer, sz); } From e3b0e520132e4019e6f509bb651fda75f96e1645 Mon Sep 17 00:00:00 2001 From: Andrew Dutcher Date: Mon, 26 Sep 2016 14:38:32 -0700 Subject: [PATCH 6/6] Rename save/restore functions to match the style of the rest of the API --- bindings/python/sample_x86.py | 6 +++--- bindings/python/unicorn/unicorn.py | 14 +++++++------- include/unicorn/unicorn.h | 8 ++++---- tests/unit/test_x86.c | 6 +++--- uc.c | 4 ++-- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/bindings/python/sample_x86.py b/bindings/python/sample_x86.py index e213a774..22111503 100755 --- a/bindings/python/sample_x86.py +++ b/bindings/python/sample_x86.py @@ -329,7 +329,7 @@ def test_i386_reg_save(): mu.emu_start(address, address+1) print(">>> save the register state") - saved_regs = mu.save_regs() + saved_regs = mu.regstate_save() print(">>> execute 'inc eax'") mu.emu_start(address, address+1) @@ -338,7 +338,7 @@ def test_i386_reg_save(): assert mu.reg_read(UC_X86_REG_EAX) == 3 print(">>> restore the register state") - mu.restore_regs(saved_regs) + mu.regstate_restore(saved_regs) print(">>> assert eax == 2") assert mu.reg_read(UC_X86_REG_EAX) == 2 @@ -350,7 +350,7 @@ def test_i386_reg_save(): assert mu.reg_read(UC_X86_REG_EAX) == 3 print(">>> restore the register state") - mu.restore_regs(saved_regs) + mu.regstate_restore(saved_regs) print(">>> assert eax == 2") assert mu.reg_read(UC_X86_REG_EAX) == 2 diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index cf541e9c..4995d1af 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -127,8 +127,8 @@ _setup_prototype(_uc, "uc_mem_map_ptr", ucerr, uc_engine, ctypes.c_uint64, ctype _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)) -_setup_prototype(_uc, "uc_save_regstate", ctypes.c_voidp, uc_engine, ctypes.c_voidp) -_setup_prototype(_uc, "uc_restore_regstate", None, uc_engine, ctypes.c_voidp) +_setup_prototype(_uc, "uc_regstate_save", ctypes.c_voidp, uc_engine, ctypes.c_voidp) +_setup_prototype(_uc, "uc_regstate_restore", None, uc_engine, ctypes.c_voidp) _setup_prototype(_uc, "free", None, ctypes.c_voidp) # uc_hook_add is special due to variable number of arguments @@ -452,20 +452,20 @@ class Uc(object): raise UcError(status) h = 0 - def save_regs(self, store=None): + def regstate_save(self, store=None): if store is None: ptr = ctypes.cast(0, ctypes.c_voidp) - return _ActivePointer(_uc.uc_save_regstate(self._uch, ptr)) + return _ActivePointer(_uc.uc_regstate_save(self._uch, ptr)) elif type(store) is _ActivePointer: - _uc.uc_save_regstate(self._uch, store.pointer) + _uc.uc_regstate_save(self._uch, store.pointer) return store else: raise TypeError("Bad register store %s" % repr(store)) - def restore_regs(self, store): + def regstate_restore(self, store): if type(store) is not _ActivePointer: raise TYpeError("Bad register store %s" % repr(store)) - _uc.uc_restore_regstate(self._uch, store.pointer) + _uc.uc_regstate_restore(self._uch, store.pointer) class _ActivePointer(object): def __init__(self, pointer): diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 5f04ec10..0de7598f 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -640,18 +640,18 @@ uc_err uc_mem_regions(uc_engine *uc, uc_mem_region **regions, uint32_t *count); Any allocation performed by this function must be freed by the user. */ UNICORN_EXPORT -void *uc_save_regstate(uc_engine *uc, void *buffer); +void *uc_regstate_save(uc_engine *uc, void *buffer); /* Restore the current state's registers from a saved copy This API should be used to roll the CPU register state back to a previous - state saved by uc_save_regstate(). + state saved by uc_regstate_save(). @uc: handle returned by uc_open() - @buffer: pointer returned by uc_save_regstate() + @buffer: pointer returned by uc_regstate_save() */ UNICORN_EXPORT -void uc_restore_regstate(uc_engine *uc, void *buffer); +void uc_regstate_restore(uc_engine *uc, void *buffer); #ifdef __cplusplus } diff --git a/tests/unit/test_x86.c b/tests/unit/test_x86.c index 6daa1322..08a416b1 100644 --- a/tests/unit/test_x86.c +++ b/tests/unit/test_x86.c @@ -755,7 +755,7 @@ static void test_i386_reg_save(void **state) uc_assert_success(uc_emu_start(uc, address, address+1, 0, 0)); // save the state - void *saved_regs = uc_save_regstate(uc, NULL); + void *saved_regs = uc_regstate_save(uc, NULL); // step one instruction uc_assert_success(uc_emu_start(uc, address, address+1, 0, 0)); @@ -765,7 +765,7 @@ static void test_i386_reg_save(void **state) assert_int_equal(eax, 3); // restore the state - uc_restore_regstate(uc, saved_regs); + uc_regstate_restore(uc, saved_regs); // check that eax == 2 uc_assert_success(uc_reg_read(uc, UC_X86_REG_EAX, &eax)); @@ -779,7 +779,7 @@ static void test_i386_reg_save(void **state) assert_int_equal(eax, 3); // restore the state - uc_restore_regstate(uc, saved_regs); + uc_regstate_restore(uc, saved_regs); // check that eax == 2 uc_assert_success(uc_reg_read(uc, UC_X86_REG_EAX, &eax)); diff --git a/uc.c b/uc.c index 132003d2..9ed157e0 100644 --- a/uc.c +++ b/uc.c @@ -1179,7 +1179,7 @@ size_t cpu_regs_size(uc_arch arch, uc_mode mode) } UNICORN_EXPORT -void *uc_save_regstate(uc_engine *uc, void *buffer) +void *uc_regstate_save(uc_engine *uc, void *buffer) { size_t sz = cpu_regs_size(uc->arch, uc->mode); if (!buffer) { @@ -1191,7 +1191,7 @@ void *uc_save_regstate(uc_engine *uc, void *buffer) } UNICORN_EXPORT -void uc_restore_regstate(uc_engine *uc, void *buffer) +void uc_regstate_restore(uc_engine *uc, void *buffer) { size_t sz = cpu_regs_size(uc->arch, uc->mode); memcpy(first_cpu->env_ptr, buffer, sz);