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:
@ -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():
|
||||||
|
@ -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())
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
18
uc.c
@ -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;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user