save cpu->jmp_env in saving context, so uc_emu_start() can be reentrant. also improved Python binding on handling context

This commit is contained in:
Nguyen Anh Quynh
2020-06-05 20:12:44 +08:00
parent a4784cc96c
commit 2e0f753e6f
5 changed files with 34 additions and 31 deletions

View File

@ -596,15 +596,12 @@ class Uc(object):
h = 0 h = 0
def context_save(self): def context_save(self):
size = _uc.uc_context_size(self._uch) context = UcContext(self._uch)
status = _uc.uc_context_save(self._uch, context.context)
context = context_factory(size)
status = _uc.uc_context_save(self._uch, ctypes.byref(context))
if status != uc.UC_ERR_OK: if status != uc.UC_ERR_OK:
raise UcError(status) raise UcError(status)
return ctypes.string_at(ctypes.byref(context), ctypes.sizeof(context)) return context
def context_update(self, context): def context_update(self, context):
status = _uc.uc_context_save(self._uch, context) status = _uc.uc_context_save(self._uch, context)
@ -612,7 +609,7 @@ class Uc(object):
raise UcError(status) raise UcError(status)
def context_restore(self, context): 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: if status != uc.UC_ERR_OK:
raise UcError(status) raise UcError(status)
@ -631,15 +628,17 @@ class Uc(object):
_uc.uc_free(regions) _uc.uc_free(regions)
def context_factory(size): class UcContext(ctypes.Structure):
class SavedContext(ctypes.Structure): def __init__(self, h):
_fields_ = [ self.context = uc_context()
('size', ctypes.c_size_t),
('data', ctypes.c_char*size) status = _uc.uc_context_alloc(h, ctypes.byref(self.context))
] if status != uc.UC_ERR_OK:
ctxt = SavedContext() raise UcError(status)
ctxt.size = size
return ctxt def __del__(self):
_uc.uc_free(self.context)
# print out debugging info # print out debugging info
def debug(): def debug():

View File

@ -253,9 +253,11 @@ struct uc_struct {
}; };
// Metadata stub for the variable-size cpu context used with uc_context_*() // 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 { struct uc_context {
size_t size; size_t context_size; // size of the real internal context structure
char data[0]; 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()) // check if this address is mapped in (via uc_mem_map())

View File

@ -39,13 +39,9 @@ void cpu_loop_exit(CPUState *cpu)
/* exit the current TB from a signal handler. The host registers are /* exit the current TB from a signal handler. The host registers are
restored in a state compatible with the CPU emulator restored in a state compatible with the CPU emulator
*/ */
#if defined(CONFIG_SOFTMMU)
void cpu_resume_from_signal(CPUState *cpu, void *puc) void cpu_resume_from_signal(CPUState *cpu, void *puc)
{ {
#endif
/* XXX: restore cpu registers saved in host registers */ /* XXX: restore cpu registers saved in host registers */
cpu->exception_index = -1; cpu->exception_index = -1;
siglongjmp(cpu->jmp_env, 1); siglongjmp(cpu->jmp_env, 1);
} }
@ -66,7 +62,6 @@ int cpu_exec(struct uc_struct *uc, CPUArchState *env) // qq
uintptr_t next_tb; uintptr_t next_tb;
struct hook *hook; struct hook *hook;
if (cpu->halted) { if (cpu->halted) {
if (!cpu_has_work(cpu)) { if (!cpu_has_work(cpu)) {
return EXCP_HALTED; return EXCP_HALTED;
@ -306,7 +301,8 @@ int cpu_exec(struct uc_struct *uc, CPUArchState *env) // qq
tb_flush(env); tb_flush(env);
/* fail safe : never use current_cpu outside cpu_exec() */ /* fail safe : never use current_cpu outside cpu_exec() */
uc->current_cpu = NULL; // uc->current_cpu = NULL;
return ret; return ret;
} }

View File

@ -71,6 +71,8 @@ int resume_all_vcpus(struct uc_struct *uc)
return -1; return -1;
} }
cpu->exit_request = 0;
//qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true); //qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true);
cpu_resume(cpu); cpu_resume(cpu);
qemu_tcg_cpu_loop(uc); qemu_tcg_cpu_loop(uc);

18
uc.c
View File

@ -1323,9 +1323,10 @@ uc_err uc_context_alloc(uc_engine *uc, uc_context **context)
struct uc_context **_context = context; struct uc_context **_context = context;
size_t size = cpu_context_size(uc->arch, uc->mode); size_t size = cpu_context_size(uc->arch, uc->mode);
*_context = malloc(size + sizeof(uc_context)); *_context = malloc(size);
if (*_context) { 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; return UC_ERR_OK;
} else { } else {
return UC_ERR_NOMEM; return UC_ERR_NOMEM;
@ -1342,21 +1343,24 @@ uc_err uc_free(void *mem)
UNICORN_EXPORT UNICORN_EXPORT
size_t uc_context_size(uc_engine *uc) 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 UNICORN_EXPORT
uc_err uc_context_save(uc_engine *uc, uc_context *context) uc_err uc_context_save(uc_engine *uc, uc_context *context)
{ {
struct uc_context *_context = context; memcpy(context->data, uc->cpu->env_ptr, context->context_size);
memcpy(_context->data, uc->cpu->env_ptr, _context->size); memcpy(context->data + context->context_size, uc->cpu->jmp_env, context->jmp_env_size);
return UC_ERR_OK; return UC_ERR_OK;
} }
UNICORN_EXPORT UNICORN_EXPORT
uc_err uc_context_restore(uc_engine *uc, uc_context *context) uc_err uc_context_restore(uc_engine *uc, uc_context *context)
{ {
struct uc_context *_context = context; memcpy(uc->cpu->env_ptr, context->data, context->context_size);
memcpy(uc->cpu->env_ptr, _context->data, _context->size); memcpy(uc->cpu->jmp_env, context->data + context->context_size, context->jmp_env_size);
return UC_ERR_OK; return UC_ERR_OK;
} }