handle snapshots over context_save context_restore
This commit is contained in:
@@ -389,6 +389,7 @@ struct uc_struct {
|
|||||||
uint64_t qemu_real_host_page_size;
|
uint64_t qemu_real_host_page_size;
|
||||||
int qemu_icache_linesize;
|
int qemu_icache_linesize;
|
||||||
/* ARCH_REGS_STORAGE_SIZE */
|
/* ARCH_REGS_STORAGE_SIZE */
|
||||||
|
uc_context_content context_content;
|
||||||
int cpu_context_size;
|
int cpu_context_size;
|
||||||
uint64_t next_pc; // save next PC for some special cases
|
uint64_t next_pc; // save next PC for some special cases
|
||||||
bool hook_insert; // insert new hook at begin of the hook list (append by
|
bool hook_insert; // insert new hook at begin of the hook list (append by
|
||||||
@@ -419,6 +420,7 @@ struct uc_context {
|
|||||||
size_t context_size; // size of the real internal context structure
|
size_t context_size; // size of the real internal context structure
|
||||||
uc_mode mode; // the mode of this context
|
uc_mode mode; // the mode of this context
|
||||||
uc_arch arch; // the arch of this context
|
uc_arch arch; // the arch of this context
|
||||||
|
int snapshot_level; // the memory snapshot level to restore
|
||||||
char data[0]; // context
|
char data[0]; // context
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -581,6 +581,9 @@ typedef enum uc_control_type {
|
|||||||
// Write: @args = (uint32_t)
|
// Write: @args = (uint32_t)
|
||||||
// Read: @args = (uint32_t*)
|
// Read: @args = (uint32_t*)
|
||||||
UC_CTL_TCG_BUFFER_SIZE,
|
UC_CTL_TCG_BUFFER_SIZE,
|
||||||
|
// controle if context_save/restore should work with snapshots
|
||||||
|
// Write: @args = (int)
|
||||||
|
UC_CTL_CONTEXT_MODE,
|
||||||
} uc_control_type;
|
} uc_control_type;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -662,6 +665,7 @@ See sample_ctl.c for a detailed example.
|
|||||||
uc_ctl(uc, UC_CTL_READ(UC_CTL_TCG_BUFFER_SIZE, 1), (size))
|
uc_ctl(uc, UC_CTL_READ(UC_CTL_TCG_BUFFER_SIZE, 1), (size))
|
||||||
#define uc_ctl_set_tcg_buffer_size(uc, size) \
|
#define uc_ctl_set_tcg_buffer_size(uc, size) \
|
||||||
uc_ctl(uc, UC_CTL_WRITE(UC_CTL_TCG_BUFFER_SIZE, 1), (size))
|
uc_ctl(uc, UC_CTL_WRITE(UC_CTL_TCG_BUFFER_SIZE, 1), (size))
|
||||||
|
#define uc_ctl_context_mode(uc, mode) uc_ctl(uc, UC_CTL_WRITE(UC_CTL_CONTEXT_MODE, 1), (mode))
|
||||||
|
|
||||||
// Opaque storage for CPU context, used with uc_context_*()
|
// Opaque storage for CPU context, used with uc_context_*()
|
||||||
struct uc_context;
|
struct uc_context;
|
||||||
@@ -1015,6 +1019,11 @@ struct uc_tlb_entry {
|
|||||||
uc_prot perms;
|
uc_prot perms;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef enum uc_context_content {
|
||||||
|
UC_CTL_CONTEXT_CPU = 1,
|
||||||
|
UC_CTL_CONTEXT_MEMORY = 2,
|
||||||
|
} uc_context_content;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Map memory in for emulation.
|
Map memory in for emulation.
|
||||||
This API adds a memory region that can be used by emulation.
|
This API adds a memory region that can be used by emulation.
|
||||||
@@ -1345,12 +1354,6 @@ size_t uc_context_size(uc_engine *uc);
|
|||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_context_free(uc_context *context);
|
uc_err uc_context_free(uc_context *context);
|
||||||
|
|
||||||
UNICORN_EXPORT
|
|
||||||
uc_err uc_snapshot(uc_engine *uc);
|
|
||||||
|
|
||||||
UNICORN_EXPORT
|
|
||||||
uc_err uc_restore_latest_snapshot(uc_engine *uc);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -278,30 +278,34 @@ static void test_mem_protect_mmio(void)
|
|||||||
static void test_snapshot(void)
|
static void test_snapshot(void)
|
||||||
{
|
{
|
||||||
uc_engine *uc;
|
uc_engine *uc;
|
||||||
|
uc_context *c0, *c1;
|
||||||
uint32_t mem;
|
uint32_t mem;
|
||||||
// mov eax, [0x2020]; inc eax; mov [0x2020], eax
|
// mov eax, [0x2020]; inc eax; mov [0x2020], eax
|
||||||
char code[] = "\xa1\x20\x20\x00\x00\x00\x00\x00\x00\xff\xc0\xa3\x20\x20\x00"
|
char code[] = "\xa1\x20\x20\x00\x00\x00\x00\x00\x00\xff\xc0\xa3\x20\x20\x00"
|
||||||
"\x00\x00\x00\x00\x00";
|
"\x00\x00\x00\x00\x00";
|
||||||
|
|
||||||
OK(uc_open(UC_ARCH_X86, UC_MODE_64, &uc));
|
OK(uc_open(UC_ARCH_X86, UC_MODE_64, &uc));
|
||||||
|
OK(uc_context_alloc(uc, &c0));
|
||||||
|
OK(uc_context_alloc(uc, &c1));
|
||||||
|
OK(uc_ctl_context_mode(uc, UC_CTL_CONTEXT_MEMORY));
|
||||||
OK(uc_mem_map(uc, 0x1000, 0x1000, UC_PROT_ALL));
|
OK(uc_mem_map(uc, 0x1000, 0x1000, UC_PROT_ALL));
|
||||||
OK(uc_mem_write(uc, 0x1000, code, sizeof(code) - 1));
|
OK(uc_mem_write(uc, 0x1000, code, sizeof(code) - 1));
|
||||||
|
|
||||||
OK(uc_mem_map(uc, 0x2000, 0x1000, UC_PROT_ALL));
|
OK(uc_mem_map(uc, 0x2000, 0x1000, UC_PROT_ALL));
|
||||||
OK(uc_snapshot(uc));
|
OK(uc_context_save(uc, c0));
|
||||||
|
|
||||||
OK(uc_emu_start(uc, 0x1000, 0x1000 + sizeof(code) - 1, 0, 0));
|
OK(uc_emu_start(uc, 0x1000, 0x1000 + sizeof(code) - 1, 0, 0));
|
||||||
OK(uc_mem_read(uc, 0x2020, &mem, sizeof(mem)));
|
OK(uc_mem_read(uc, 0x2020, &mem, sizeof(mem)));
|
||||||
TEST_CHECK(mem == 1);
|
TEST_CHECK(mem == 1);
|
||||||
OK(uc_snapshot(uc));
|
OK(uc_context_save(uc, c1));
|
||||||
OK(uc_emu_start(uc, 0x1000, 0x1000 + sizeof(code) - 1, 0, 0));
|
OK(uc_emu_start(uc, 0x1000, 0x1000 + sizeof(code) - 1, 0, 0));
|
||||||
OK(uc_mem_read(uc, 0x2020, &mem, sizeof(mem)));
|
OK(uc_mem_read(uc, 0x2020, &mem, sizeof(mem)));
|
||||||
TEST_CHECK(mem == 2);
|
TEST_CHECK(mem == 2);
|
||||||
OK(uc_restore_latest_snapshot(uc));
|
OK(uc_context_restore(uc, c1));
|
||||||
//TODO check mem
|
//TODO check mem
|
||||||
OK(uc_mem_read(uc, 0x2020, &mem, sizeof(mem)));
|
OK(uc_mem_read(uc, 0x2020, &mem, sizeof(mem)));
|
||||||
TEST_CHECK(mem == 1);
|
TEST_CHECK(mem == 1);
|
||||||
OK(uc_restore_latest_snapshot(uc));
|
OK(uc_context_restore(uc, c0));
|
||||||
OK(uc_mem_read(uc, 0x2020, &mem, sizeof(mem)));
|
OK(uc_mem_read(uc, 0x2020, &mem, sizeof(mem)));
|
||||||
TEST_CHECK(mem == 0);
|
TEST_CHECK(mem == 0);
|
||||||
//TODO check mem
|
//TODO check mem
|
||||||
@@ -318,7 +322,7 @@ static void test_context_snapshot(void)
|
|||||||
uint64_t tmp = 1;
|
uint64_t tmp = 1;
|
||||||
|
|
||||||
OK(uc_open(UC_ARCH_X86, UC_MODE_64, &uc));
|
OK(uc_open(UC_ARCH_X86, UC_MODE_64, &uc));
|
||||||
OK(uc_ctl_context_use_snapshots(uc, 1));
|
OK(uc_ctl_context_mode(uc, UC_CTL_CONTEXT_MEMORY|UC_CTL_CONTEXT_CPU));
|
||||||
OK(uc_mem_map(uc, 0x1000, 0x1000, UC_PROT_ALL));
|
OK(uc_mem_map(uc, 0x1000, 0x1000, UC_PROT_ALL));
|
||||||
OK(uc_context_alloc(uc, &ctx));
|
OK(uc_context_alloc(uc, &ctx));
|
||||||
OK(uc_context_save(uc, ctx));
|
OK(uc_context_save(uc, ctx));
|
||||||
|
|||||||
69
uc.c
69
uc.c
@@ -31,6 +31,8 @@
|
|||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
|
|
||||||
static void clear_deleted_hooks(uc_engine *uc);
|
static void clear_deleted_hooks(uc_engine *uc);
|
||||||
|
static uc_err uc_snapshot(uc_engine *uc);
|
||||||
|
static uc_err uc_restore_latest_snapshot(uc_engine *uc);
|
||||||
|
|
||||||
static void *hook_insert(struct list *l, struct hook *h)
|
static void *hook_insert(struct list *l, struct hook *h)
|
||||||
{
|
{
|
||||||
@@ -256,6 +258,8 @@ static uc_err uc_init_engine(uc_engine *uc)
|
|||||||
uc->reg_reset(uc);
|
uc->reg_reset(uc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uc->context_content = UC_CTL_CONTEXT_CPU;
|
||||||
|
|
||||||
uc->init_done = true;
|
uc->init_done = true;
|
||||||
|
|
||||||
return UC_ERR_OK;
|
return UC_ERR_OK;
|
||||||
@@ -1985,13 +1989,26 @@ UNICORN_EXPORT
|
|||||||
uc_err uc_context_save(uc_engine *uc, uc_context *context)
|
uc_err uc_context_save(uc_engine *uc, uc_context *context)
|
||||||
{
|
{
|
||||||
UC_INIT(uc);
|
UC_INIT(uc);
|
||||||
|
uc_err ret = UC_ERR_OK;
|
||||||
|
|
||||||
if (!uc->context_save) {
|
if (uc->context_content & UC_CTL_CONTEXT_MEMORY) {
|
||||||
memcpy(context->data, uc->cpu->env_ptr, context->context_size);
|
ret = uc_snapshot(uc);
|
||||||
return UC_ERR_OK;
|
if (ret != UC_ERR_OK) {
|
||||||
} else {
|
return ret;
|
||||||
return uc->context_save(uc, context);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context->snapshot_level = uc->snapshot_level;
|
||||||
|
|
||||||
|
if (uc->context_content & UC_CTL_CONTEXT_CPU) {
|
||||||
|
if (!uc->context_save) {
|
||||||
|
memcpy(context->data, uc->cpu->env_ptr, context->context_size);
|
||||||
|
return UC_ERR_OK;
|
||||||
|
} else {
|
||||||
|
return uc->context_save(uc, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep in mind that we don't a uc_engine when r/w the registers of a context.
|
// Keep in mind that we don't a uc_engine when r/w the registers of a context.
|
||||||
@@ -2237,13 +2254,26 @@ UNICORN_EXPORT
|
|||||||
uc_err uc_context_restore(uc_engine *uc, uc_context *context)
|
uc_err uc_context_restore(uc_engine *uc, uc_context *context)
|
||||||
{
|
{
|
||||||
UC_INIT(uc);
|
UC_INIT(uc);
|
||||||
|
uc_err ret;
|
||||||
|
|
||||||
if (!uc->context_restore) {
|
if (uc->context_content & UC_CTL_CONTEXT_MEMORY) {
|
||||||
memcpy(uc->cpu->env_ptr, context->data, context->context_size);
|
uc->snapshot_level = context->snapshot_level;
|
||||||
return UC_ERR_OK;
|
ret = uc_restore_latest_snapshot(uc);
|
||||||
} else {
|
if (ret != UC_ERR_OK) {
|
||||||
return uc->context_restore(uc, context);
|
return ret;
|
||||||
|
}
|
||||||
|
uc_snapshot(uc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (uc->context_content & UC_CTL_CONTEXT_CPU) {
|
||||||
|
if (!uc->context_restore) {
|
||||||
|
memcpy(uc->cpu->env_ptr, context->data, context->context_size);
|
||||||
|
return UC_ERR_OK;
|
||||||
|
} else {
|
||||||
|
return uc->context_restore(uc, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UC_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
@@ -2588,6 +2618,19 @@ uc_err uc_ctl(uc_engine *uc, uc_control_type control, ...)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case UC_CTL_CONTEXT_MODE:
|
||||||
|
|
||||||
|
UC_INIT(uc);
|
||||||
|
|
||||||
|
if (rw == UC_CTL_IO_WRITE) {
|
||||||
|
int mode = va_arg(args, int);
|
||||||
|
uc->context_content = mode;
|
||||||
|
err = UC_ERR_OK;
|
||||||
|
} else {
|
||||||
|
err = UC_ERR_ARG;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
err = UC_ERR_ARG;
|
err = UC_ERR_ARG;
|
||||||
break;
|
break;
|
||||||
@@ -2598,8 +2641,7 @@ uc_err uc_ctl(uc_engine *uc, uc_control_type control, ...)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
UNICORN_EXPORT
|
static uc_err uc_snapshot(struct uc_struct *uc)
|
||||||
uc_err uc_snapshot(struct uc_struct *uc)
|
|
||||||
{
|
{
|
||||||
if (uc->snapshot_level == INT32_MAX) {
|
if (uc->snapshot_level == INT32_MAX) {
|
||||||
return UC_ERR_RESOURCE;
|
return UC_ERR_RESOURCE;
|
||||||
@@ -2608,8 +2650,7 @@ uc_err uc_snapshot(struct uc_struct *uc)
|
|||||||
return UC_ERR_OK;
|
return UC_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
UNICORN_EXPORT
|
static uc_err uc_restore_latest_snapshot(struct uc_struct *uc)
|
||||||
uc_err uc_restore_latest_snapshot(struct uc_struct *uc)
|
|
||||||
{
|
{
|
||||||
MemoryRegion *subregion, *subregion_next;
|
MemoryRegion *subregion, *subregion_next;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user