From 2e0f753e6f9411901dce1e6779b0bcdd57d13c09 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Fri, 5 Jun 2020 20:12:44 +0800 Subject: [PATCH] save cpu->jmp_env in saving context, so uc_emu_start() can be reentrant. also improved Python binding on handling context --- bindings/python/unicorn/unicorn.py | 31 +++++++++++++++--------------- include/uc_priv.h | 6 ++++-- qemu/cpu-exec.c | 8 ++------ qemu/cpus.c | 2 ++ uc.c | 18 ++++++++++------- 5 files changed, 34 insertions(+), 31 deletions(-) diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index 40fccce0..7b8f49be 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -596,15 +596,12 @@ class Uc(object): h = 0 def context_save(self): - size = _uc.uc_context_size(self._uch) - - context = context_factory(size) - - status = _uc.uc_context_save(self._uch, ctypes.byref(context)) + context = UcContext(self._uch) + status = _uc.uc_context_save(self._uch, context.context) if status != uc.UC_ERR_OK: raise UcError(status) - return ctypes.string_at(ctypes.byref(context), ctypes.sizeof(context)) + return context def context_update(self, context): status = _uc.uc_context_save(self._uch, context) @@ -612,7 +609,7 @@ class Uc(object): raise UcError(status) def context_restore(self, context): - status = _uc.uc_context_restore(self._uch, context) + status = _uc.uc_context_restore(self._uch, context.context) if status != uc.UC_ERR_OK: raise UcError(status) @@ -631,15 +628,17 @@ class Uc(object): _uc.uc_free(regions) -def context_factory(size): - class SavedContext(ctypes.Structure): - _fields_ = [ - ('size', ctypes.c_size_t), - ('data', ctypes.c_char*size) - ] - ctxt = SavedContext() - ctxt.size = size - return ctxt +class UcContext(ctypes.Structure): + def __init__(self, h): + self.context = uc_context() + + status = _uc.uc_context_alloc(h, ctypes.byref(self.context)) + if status != uc.UC_ERR_OK: + raise UcError(status) + + def __del__(self): + _uc.uc_free(self.context) + # print out debugging info def debug(): diff --git a/include/uc_priv.h b/include/uc_priv.h index ef8be62c..80288187 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -253,9 +253,11 @@ struct uc_struct { }; // Metadata stub for the variable-size cpu context used with uc_context_*() +// We also save cpu->jmp_env, so emulation can be reentrant struct uc_context { - size_t size; - char data[0]; + size_t context_size; // size of the real internal context structure + unsigned int jmp_env_size; // size of cpu->jmp_env + char data[0]; // context + cpu->jmp_env }; // check if this address is mapped in (via uc_mem_map()) diff --git a/qemu/cpu-exec.c b/qemu/cpu-exec.c index 7da6e3f4..b4aa4bf0 100644 --- a/qemu/cpu-exec.c +++ b/qemu/cpu-exec.c @@ -39,13 +39,9 @@ void cpu_loop_exit(CPUState *cpu) /* exit the current TB from a signal handler. The host registers are restored in a state compatible with the CPU emulator */ -#if defined(CONFIG_SOFTMMU) - void cpu_resume_from_signal(CPUState *cpu, void *puc) { -#endif /* XXX: restore cpu registers saved in host registers */ - cpu->exception_index = -1; siglongjmp(cpu->jmp_env, 1); } @@ -66,7 +62,6 @@ int cpu_exec(struct uc_struct *uc, CPUArchState *env) // qq uintptr_t next_tb; struct hook *hook; - if (cpu->halted) { if (!cpu_has_work(cpu)) { return EXCP_HALTED; @@ -306,7 +301,8 @@ int cpu_exec(struct uc_struct *uc, CPUArchState *env) // qq tb_flush(env); /* fail safe : never use current_cpu outside cpu_exec() */ - uc->current_cpu = NULL; + // uc->current_cpu = NULL; + return ret; } diff --git a/qemu/cpus.c b/qemu/cpus.c index 0035e222..28509d54 100644 --- a/qemu/cpus.c +++ b/qemu/cpus.c @@ -71,6 +71,8 @@ int resume_all_vcpus(struct uc_struct *uc) return -1; } + cpu->exit_request = 0; + //qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true); cpu_resume(cpu); qemu_tcg_cpu_loop(uc); diff --git a/uc.c b/uc.c index 038c7803..3e2f7dc9 100644 --- a/uc.c +++ b/uc.c @@ -1323,9 +1323,10 @@ uc_err uc_context_alloc(uc_engine *uc, uc_context **context) struct uc_context **_context = context; size_t size = cpu_context_size(uc->arch, uc->mode); - *_context = malloc(size + sizeof(uc_context)); + *_context = malloc(size); if (*_context) { - (*_context)->size = size; + (*_context)->jmp_env_size = sizeof(*uc->cpu->jmp_env); + (*_context)->context_size = size - sizeof(uc_context) - (*_context)->jmp_env_size; return UC_ERR_OK; } else { return UC_ERR_NOMEM; @@ -1342,21 +1343,24 @@ uc_err uc_free(void *mem) UNICORN_EXPORT size_t uc_context_size(uc_engine *uc) { - return cpu_context_size(uc->arch, uc->mode); + // return the total size of struct uc_context + return sizeof(uc_context) + cpu_context_size(uc->arch, uc->mode) + sizeof(*uc->cpu->jmp_env); } UNICORN_EXPORT uc_err uc_context_save(uc_engine *uc, uc_context *context) { - struct uc_context *_context = context; - memcpy(_context->data, uc->cpu->env_ptr, _context->size); + memcpy(context->data, uc->cpu->env_ptr, context->context_size); + memcpy(context->data + context->context_size, uc->cpu->jmp_env, context->jmp_env_size); + return UC_ERR_OK; } UNICORN_EXPORT uc_err uc_context_restore(uc_engine *uc, uc_context *context) { - struct uc_context *_context = context; - memcpy(uc->cpu->env_ptr, _context->data, _context->size); + memcpy(uc->cpu->env_ptr, context->data, context->context_size); + memcpy(uc->cpu->jmp_env, context->data + context->context_size, context->jmp_env_size); + return UC_ERR_OK; }