Fix exits wrongly cleared in nested uc_emu_start

This commit is contained in:
2022-03-06 23:40:34 +01:00
parent 12fa73f2b6
commit 09b15e9071
3 changed files with 20 additions and 13 deletions

View File

@@ -341,7 +341,8 @@ struct uc_struct {
int invalid_error; // invalid memory code: 1 = READ, 2 = WRITE, 3 = CODE int invalid_error; // invalid memory code: 1 = READ, 2 = WRITE, 3 = CODE
int use_exits; int use_exits;
GTree *exits; // addresses where emulation stops (@until param of uint64_t exits[UC_MAX_NESTED_LEVEL]; // When multiple exits is not enabled.
GTree *ctl_exits; // addresses where emulation stops (@until param of
// uc_emu_start()) Also see UC_CTL_USE_EXITS for more details. // uc_emu_start()) Also see UC_CTL_USE_EXITS for more details.
int thumb; // thumb mode for ARM int thumb; // thumb mode for ARM
@@ -390,14 +391,18 @@ static inline void uc_add_exit(uc_engine *uc, uint64_t addr)
{ {
uint64_t *new_exit = g_malloc(sizeof(uint64_t)); uint64_t *new_exit = g_malloc(sizeof(uint64_t));
*new_exit = addr; *new_exit = addr;
g_tree_insert(uc->exits, (gpointer)new_exit, (gpointer)1); g_tree_insert(uc->ctl_exits, (gpointer)new_exit, (gpointer)1);
} }
// This function has to exist since we would like to accept uint32_t or // This function has to exist since we would like to accept uint32_t or
// it's complex to achieve so. // it's complex to achieve so.
static inline int uc_addr_is_exit(uc_engine *uc, uint64_t addr) static inline int uc_addr_is_exit(uc_engine *uc, uint64_t addr)
{ {
return g_tree_lookup(uc->exits, (gpointer)(&addr)) == (gpointer)1; if (uc->use_exits) {
return g_tree_lookup(uc->ctl_exits, (gpointer)(&addr)) == (gpointer)1;
} else {
return uc->exits[uc->nested_level - 1] == addr;
}
} }
#ifdef UNICORN_TRACER #ifdef UNICORN_TRACER

View File

@@ -214,8 +214,11 @@ void resume_all_vcpus(struct uc_struct* uc)
// clear the cache of the exits address, since the generated code // clear the cache of the exits address, since the generated code
// at that address is to exit emulation, but not for the instruction there. // at that address is to exit emulation, but not for the instruction there.
// if we dont do this, next time we cannot emulate at that address // if we dont do this, next time we cannot emulate at that address
if (uc->use_exits) {
g_tree_foreach(uc->exits, uc_exit_invalidate_iter, (void*)uc); g_tree_foreach(uc->ctl_exits, uc_exit_invalidate_iter, (void*)uc);
} else {
uc_exit_invalidate_iter((gpointer)&uc->exits[uc->nested_level - 1], NULL, (gpointer)uc);
}
cpu->created = false; cpu->created = false;
} }

15
uc.c
View File

@@ -209,7 +209,7 @@ static uc_err uc_init(uc_engine *uc)
uc->hook[i].delete_fn = hook_delete; uc->hook[i].delete_fn = hook_delete;
} }
uc->exits = g_tree_new_full(uc_exits_cmp, NULL, g_free, NULL); uc->ctl_exits = g_tree_new_full(uc_exits_cmp, NULL, g_free, NULL);
if (machine_initialize(uc)) { if (machine_initialize(uc)) {
return UC_ERR_RESOURCE; return UC_ERR_RESOURCE;
@@ -465,7 +465,7 @@ uc_err uc_close(uc_engine *uc)
free(uc->mapped_blocks); free(uc->mapped_blocks);
g_tree_destroy(uc->exits); g_tree_destroy(uc->ctl_exits);
// finally, free uc itself. // finally, free uc itself.
memset(uc, 0, sizeof(*uc)); memset(uc, 0, sizeof(*uc));
@@ -828,8 +828,7 @@ uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until,
// If UC_CTL_UC_USE_EXITS is set, then the @until param won't have any // If UC_CTL_UC_USE_EXITS is set, then the @until param won't have any
// effect. This is designed for the backward compatibility. // effect. This is designed for the backward compatibility.
if (!uc->use_exits) { if (!uc->use_exits) {
g_tree_remove_all(uc->exits); uc->exits[uc->nested_level - 1] = until;
uc_add_exit(uc, until);
} }
if (timeout) { if (timeout) {
@@ -2127,7 +2126,7 @@ uc_err uc_ctl(uc_engine *uc, uc_control_type control, ...)
err = UC_ERR_ARG; err = UC_ERR_ARG;
} else if (rw == UC_CTL_IO_READ) { } else if (rw == UC_CTL_IO_READ) {
size_t *exits_cnt = va_arg(args, size_t *); size_t *exits_cnt = va_arg(args, size_t *);
*exits_cnt = g_tree_nnodes(uc->exits); *exits_cnt = g_tree_nnodes(uc->ctl_exits);
} else { } else {
err = UC_ERR_ARG; err = UC_ERR_ARG;
} }
@@ -2143,20 +2142,20 @@ uc_err uc_ctl(uc_engine *uc, uc_control_type control, ...)
} else if (rw == UC_CTL_IO_READ) { } else if (rw == UC_CTL_IO_READ) {
uint64_t *exits = va_arg(args, uint64_t *); uint64_t *exits = va_arg(args, uint64_t *);
size_t cnt = va_arg(args, size_t); size_t cnt = va_arg(args, size_t);
if (cnt < g_tree_nnodes(uc->exits)) { if (cnt < g_tree_nnodes(uc->ctl_exits)) {
err = UC_ERR_ARG; err = UC_ERR_ARG;
} else { } else {
uc_ctl_exit_request req; uc_ctl_exit_request req;
req.array = exits; req.array = exits;
req.len = 0; req.len = 0;
g_tree_foreach(uc->exits, uc_read_exit_iter, (void *)&req); g_tree_foreach(uc->ctl_exits, uc_read_exit_iter, (void *)&req);
} }
} else if (rw == UC_CTL_IO_WRITE) { } else if (rw == UC_CTL_IO_WRITE) {
uint64_t *exits = va_arg(args, uint64_t *); uint64_t *exits = va_arg(args, uint64_t *);
size_t cnt = va_arg(args, size_t); size_t cnt = va_arg(args, size_t);
g_tree_remove_all(uc->exits); g_tree_remove_all(uc->ctl_exits);
for (size_t i = 0; i < cnt; i++) { for (size_t i = 0; i < cnt; i++) {
uc_add_exit(uc, exits[i]); uc_add_exit(uc, exits[i]);