New feature: registers can be bulk saved/restored in an opaque blob

This commit is contained in:
Andrew Dutcher 2016-08-20 04:14:07 -07:00
parent 236b6e9085
commit 0ef2b5fd71
14 changed files with 94 additions and 0 deletions

View file

@ -624,6 +624,35 @@ uc_err uc_mem_protect(uc_engine *uc, uint64_t address, size_t size, uint32_t per
UNICORN_EXPORT
uc_err uc_mem_regions(uc_engine *uc, uc_mem_region **regions, uint32_t *count);
/*
Save a copy of the current state's registers
This API should be used to efficiently make or update a saved copy of the
state's registers.
@uc: handle returned by uc_open()
@buffer: pointer to the region to store the registers in. The first call to
this function should pass NULL in this parameter, so a region of the
appropriate size for the current architecure can be allocated. Further calls
to this function may pass in the return value of previous calls.
@return a pointer to the region the registers were saved in. If buffer was
NULL, this is a newly allocated region, otherwise it is the same as buffer.
Any allocation performed by this function must be freed by the user.
*/
UNICORN_EXPORT
void *uc_save_regstate(uc_engine *uc, void *buffer);
/*
Restore the current state's registers from a saved copy
This API should be used to roll the CPU register state back to a previous
state saved by uc_save_regstate().
@uc: handle returned by uc_open()
@buffer: pointer returned by uc_save_regstate()
*/
UNICORN_EXPORT
void uc_restore_regstate(uc_engine *uc, void *buffer);
#ifdef __cplusplus
}
#endif

View file

@ -19,4 +19,7 @@ void arm_uc_init(struct uc_struct* uc);
__attribute__ ((visibility ("default")))
void arm64_uc_init(struct uc_struct* uc);
extern const int ARM_REGS_STORAGE_SIZE;
extern const int ARM64_REGS_STORAGE_SIZE;
#endif

View file

@ -10,6 +10,8 @@
#include "uc_priv.h"
const int ARM64_REGS_STORAGE_SIZE = offsetof(CPUARMState, tlb_table);
static void arm64_set_pc(struct uc_struct *uc, uint64_t address)
{
((CPUARMState *)uc->current_cpu->env_ptr)->pc = address;

View file

@ -10,6 +10,8 @@
#include "uc_priv.h"
const int ARM_REGS_STORAGE_SIZE = offsetof(CPUARMState, tlb_table);
static void arm_set_pc(struct uc_struct *uc, uint64_t address)
{
((CPUARMState *)uc->current_cpu->env_ptr)->pc = address;

View file

@ -12,6 +12,8 @@
#include "uc_priv.h"
const int X86_REGS_STORAGE_SIZE = offsetof(CPUX86State, tlb_table);
static void x86_set_pc(struct uc_struct *uc, uint64_t address)
{
((CPUX86State *)uc->current_cpu->env_ptr)->eip = address;

View file

@ -12,4 +12,6 @@ void x86_reg_reset(struct uc_struct *uc);
void x86_uc_init(struct uc_struct* uc);
int x86_uc_machine_init(struct uc_struct *uc);
extern const int X86_REGS_STORAGE_SIZE;
#endif

View file

@ -10,6 +10,8 @@
#include "uc_priv.h"
const int M68K_REGS_STORAGE_SIZE = offsetof(CPUM68KState, tlb_table);
static void m68k_set_pc(struct uc_struct *uc, uint64_t address)
{
((CPUM68KState *)uc->current_cpu->env_ptr)->pc = address;

View file

@ -12,4 +12,5 @@ void m68k_reg_reset(struct uc_struct *uc);
void m68k_uc_init(struct uc_struct* uc);
extern const int M68K_REGS_STORAGE_SIZE;
#endif

View file

@ -9,6 +9,14 @@
#include "unicorn_common.h"
#include "uc_priv.h"
// prevent the lines from being compiled twice
#ifdef TARGET_WORDS_BIGENDIAN
#ifdef TARGET_MIPS64
const int MIPS64_REGS_STORAGE_SIZE = offsetof(CPUMIPSState, tlb_table);
#else // MIPS32
const int MIPS_REGS_STORAGE_SIZE = offsetof(CPUMIPSState, tlb_table);
#endif
#endif
static uint64_t mips_mem_redirect(uint64_t address)
{

View file

@ -15,4 +15,7 @@ void mipsel_uc_init(struct uc_struct* uc);
void mips64_uc_init(struct uc_struct* uc);
void mips64el_uc_init(struct uc_struct* uc);
extern const int MIPS_REGS_STORAGE_SIZE;
extern const int MIPS64_REGS_STORAGE_SIZE;
#endif

View file

@ -10,6 +10,8 @@
#include "uc_priv.h"
const int SPARC_REGS_STORAGE_SIZE = offsetof(CPUSPARCState, tlb_table);
static bool sparc_stop_interrupt(int intno)
{
switch(intno) {

View file

@ -13,4 +13,7 @@ void sparc_reg_reset(struct uc_struct *uc);
void sparc_uc_init(struct uc_struct* uc);
void sparc64_uc_init(struct uc_struct* uc);
extern const int SPARC_REGS_STORAGE_SIZE;
extern const int SPARC64_REGS_STORAGE_SIZE;
#endif

View file

@ -10,6 +10,8 @@
#include "uc_priv.h"
const int SPARC64_REGS_STORAGE_SIZE = offsetof(CPUSPARCState, tlb_table);
static bool sparc_stop_interrupt(int intno)
{
switch(intno) {

33
uc.c
View file

@ -1160,3 +1160,36 @@ uc_err uc_query(uc_engine *uc, uc_query_type type, size_t *result)
return UC_ERR_OK;
}
size_t cpu_regs_size(uc_arch arch, uc_mode mode);
size_t cpu_regs_size(uc_arch arch, uc_mode mode) {
// each of these constants is defined by offsetof(CPUXYZState, tlb_table)
// tbl_table is the first entry in the CPU_COMMON macro, so it marks the end
// of the interesting CPU registers
switch (arch) {
case UC_ARCH_M68K: return M68K_REGS_STORAGE_SIZE;
case UC_ARCH_X86: return X86_REGS_STORAGE_SIZE;
case UC_ARCH_ARM: return ARM_REGS_STORAGE_SIZE;
case UC_ARCH_ARM64: return ARM64_REGS_STORAGE_SIZE;
case UC_ARCH_MIPS: return mode & UC_MODE_MIPS64 ? MIPS64_REGS_STORAGE_SIZE : MIPS_REGS_STORAGE_SIZE;
case UC_ARCH_SPARC: return mode & UC_MODE_SPARC64 ? SPARC64_REGS_STORAGE_SIZE : SPARC_REGS_STORAGE_SIZE;
default: return 0;
}
}
UNICORN_EXPORT
void *uc_save_regstate(uc_engine *uc, void *buffer) {
size_t sz = cpu_regs_size(uc->arch, uc->mode);
if (!buffer) {
buffer = malloc(sz);
}
memcpy(buffer, uc->current_cpu->env_ptr, sz);
return buffer;
}
UNICORN_EXPORT
void uc_restore_regstate(uc_engine *uc, void *buffer) {
size_t sz = cpu_regs_size(uc->arch, uc->mode);
memcpy(uc->current_cpu->env_ptr, buffer, sz);
}