add batched reg access

This commit is contained in:
Ryan Hileman 2016-04-04 08:25:30 -07:00
parent 1486ccce70
commit acd88856e1
18 changed files with 1320 additions and 1151 deletions

23
bindings/go/unicorn/uc.c Normal file
View file

@ -0,0 +1,23 @@
#include <stdlib.h>
#include <unicorn/unicorn.h>
#include "_cgo_export.h"
uc_err uc_reg_read_batch_helper(uc_engine *handle, int *regs, uint64_t *val_out, int count) {
void **val_ref = malloc(sizeof(void *) * count);
for (int i = 0; i < count; i++) {
val_ref[i] = (void *)&val_out[i];
}
uc_err ret = uc_reg_read_batch(handle, regs, val_ref, count);
free(val_ref);
return ret;
}
uc_err uc_reg_write_batch_helper(uc_engine *handle, int *regs, uint64_t *val_in, int count) {
const void **val_ref = malloc(sizeof(void *) * count);
for (int i = 0; i < count; i++) {
val_ref[i] = (void *)&val_in[i];
}
uc_err ret = uc_reg_write_batch(handle, regs, val_ref, count);
free(val_ref);
return ret;
}

2
bindings/go/unicorn/uc.h Normal file
View file

@ -0,0 +1,2 @@
uc_err uc_reg_read_batch_helper(uc_engine *handle, int *regs, uint64_t *val_out, int count);
uc_err uc_reg_write_batch_helper(uc_engine *handle, int *regs, uint64_t *val_in, int count);

View file

@ -7,8 +7,10 @@ import (
)
/*
#cgo CFLAGS: -O3
#cgo LDFLAGS: -lunicorn
#include <unicorn/unicorn.h>
#include "uc.h"
*/
import "C"
@ -41,7 +43,9 @@ type Unicorn interface {
MemReadInto(dst []byte, addr uint64) error
MemWrite(addr uint64, data []byte) error
RegRead(reg int) (uint64, error)
RegReadBatch(regs []int) ([]uint64, error)
RegWrite(reg int, value uint64) error
RegWriteBatch(regs []int, vals []uint64) error
RegReadMmr(reg int) (*X86Mmr, error)
RegWriteMmr(reg int, value *X86Mmr) error
Start(begin, until uint64) error
@ -117,6 +121,38 @@ func (u *uc) RegRead(reg int) (uint64, error) {
return uint64(val), errReturn(ucerr)
}
func (u *uc) RegWriteBatch(regs []int, vals []uint64) error {
if len(regs) == 0 {
return nil
}
if len(vals) < len(regs) {
regs = regs[:len(vals)]
}
cregs := make([]C.int, len(regs))
for i, v := range regs {
cregs[i] = C.int(v)
}
cregs2 := (*C.int)(unsafe.Pointer(&cregs[0]))
cvals := (*C.uint64_t)(unsafe.Pointer(&vals[0]))
ucerr := C.uc_reg_write_batch_helper(u.handle, cregs2, cvals, C.int(len(regs)))
return errReturn(ucerr)
}
func (u *uc) RegReadBatch(regs []int) ([]uint64, error) {
if len(regs) == 0 {
return nil, nil
}
cregs := make([]C.int, len(regs))
for i, v := range regs {
cregs[i] = C.int(v)
}
cregs2 := (*C.int)(unsafe.Pointer(&cregs[0]))
vals := make([]uint64, len(regs))
cvals := (*C.uint64_t)(unsafe.Pointer(&vals[0]))
ucerr := C.uc_reg_read_batch_helper(u.handle, cregs2, cvals, C.int(len(regs)))
return vals, errReturn(ucerr)
}
func (u *uc) MemRegions() ([]*MemRegion, error) {
var regions *C.struct_uc_mem_region
var count C.uint32_t

View file

@ -46,8 +46,8 @@ typedef QTAILQ_HEAD(, ModuleEntry) ModuleTypeList;
typedef uc_err (*query_t)(struct uc_struct *uc, uc_query_type type, size_t *result);
// return 0 on success, -1 on failure
typedef int (*reg_read_t)(struct uc_struct *uc, unsigned int regid, void *value);
typedef int (*reg_write_t)(struct uc_struct *uc, unsigned int regid, const void *value);
typedef int (*reg_read_t)(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
typedef int (*reg_write_t)(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
typedef void (*reg_reset_t)(struct uc_struct *uc);

View file

@ -386,6 +386,34 @@ uc_err uc_reg_write(uc_engine *uc, int regid, const void *value);
UNICORN_EXPORT
uc_err uc_reg_read(uc_engine *uc, int regid, void *value);
/*
Write multiple register values.
@uc: handle returned by uc_open()
@rges: array of register IDs to store
@value: pointer to array of register values
@count: length of both *regs and *vals
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
for detailed error).
*/
UNICORN_EXPORT
uc_err uc_reg_write_batch(uc_engine *uc, int *regs, void *const *vals, int count);
/*
Read multiple register values.
@uc: handle returned by uc_open()
@rges: array of register IDs to retrieve
@value: pointer to array of values to hold registers
@count: length of both *regs and *vals
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
for detailed error).
*/
UNICORN_EXPORT
uc_err uc_reg_read_batch(uc_engine *uc, int *regs, void **vals, int count);
/*
Write to a range of bytes in memory.

View file

@ -5,10 +5,10 @@
#define UC_QEMU_TARGET_ARM_H
// functions to read & write registers
int arm_reg_read(struct uc_struct *uc, unsigned int regid, void *value);
int arm_reg_write(struct uc_struct *uc, unsigned int regid, const void *value);
int arm64_reg_read(struct uc_struct *uc, unsigned int regid, void *value);
int arm64_reg_write(struct uc_struct *uc, unsigned int regid, const void *value);
int arm_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
int arm_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
int arm64_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
int arm64_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
void arm_reg_reset(struct uc_struct *uc);
void arm64_reg_reset(struct uc_struct *uc);

View file

@ -23,10 +23,14 @@ void arm64_reg_reset(struct uc_struct *uc)
env->pc = 0;
}
int arm64_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
int arm64_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count)
{
CPUState *mycpu = first_cpu;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
void *value = vals[i];
if (regid >= UC_ARM64_REG_X0 && regid <= UC_ARM64_REG_X28)
*(int64_t *)value = ARM_CPU(uc, mycpu)->env.xregs[regid - UC_ARM64_REG_X0];
else {
@ -46,14 +50,19 @@ int arm64_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
break;
}
}
}
return 0;
}
int arm64_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
int arm64_reg_write(struct uc_struct *uc, unsigned int *regs, void* const* vals, int count)
{
CPUState *mycpu = first_cpu;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
const void *value = vals[i];
if (regid >= UC_ARM64_REG_X0 && regid <= UC_ARM64_REG_X28)
ARM_CPU(uc, mycpu)->env.xregs[regid - UC_ARM64_REG_X0] = *(uint64_t *)value;
else {
@ -76,6 +85,7 @@ int arm64_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
break;
}
}
}
return 0;
}

View file

@ -27,12 +27,16 @@ void arm_reg_reset(struct uc_struct *uc)
env->pc = 0;
}
int arm_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
int arm_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count)
{
CPUState *mycpu;
int i;
mycpu = first_cpu;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
void *value = vals[i];
if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12)
*(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0];
else {
@ -54,14 +58,19 @@ int arm_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
break;
}
}
}
return 0;
}
int arm_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
int arm_reg_write(struct uc_struct *uc, unsigned int *regs, void* const* vals, int count)
{
CPUState *mycpu = first_cpu;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
const void *value = vals[i];
if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12)
ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0] = *(uint32_t *)value;
else {
@ -85,6 +94,7 @@ int arm_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
break;
}
}
}
return 0;
}

View file

@ -136,10 +136,14 @@ void x86_reg_reset(struct uc_struct *uc)
}
}
int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count)
{
CPUState *mycpu = first_cpu;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
void *value = vals[i];
switch(regid) {
default:
break;
@ -148,7 +152,7 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
floatx80 reg = X86_CPU(uc, mycpu)->env.fpregs[regid - UC_X86_REG_FP0].d;
cpu_get_fp80(value, value+sizeof(uint64_t), reg);
}
return 0;
continue;
case UC_X86_REG_FPSW:
{
uint16_t fpus = X86_CPU(uc, mycpu)->env.fpus;
@ -156,10 +160,10 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
fpus |= ( X86_CPU(uc, mycpu)->env.fpstt & 0x7 ) << 11;
*(uint16_t*) value = fpus;
}
return 0;
continue;
case UC_X86_REG_FPCW:
*(uint16_t*) value = X86_CPU(uc, mycpu)->env.fpuc;
return 0;
continue;
case UC_X86_REG_FPTAG:
{
#define EXPD(fp) (fp.l.upper & 0x7fff)
@ -189,7 +193,7 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
}
*(uint16_t*) value = fptag;
}
return 0;
continue;
}
switch(uc->mode) {
@ -200,19 +204,19 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
default: break;
case UC_X86_REG_ES:
*(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_ES].selector;
return 0;
continue;
case UC_X86_REG_SS:
*(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_SS].selector;
return 0;
continue;
case UC_X86_REG_DS:
*(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_DS].selector;
return 0;
continue;
case UC_X86_REG_FS:
*(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_FS].selector;
return 0;
continue;
case UC_X86_REG_GS:
*(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_GS].selector;
return 0;
continue;
}
// fall-thru
case UC_MODE_32:
@ -616,15 +620,19 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
break;
#endif
}
}
return 0;
}
int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count)
{
CPUState *mycpu = first_cpu;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
const void *value = vals[i];
switch(regid) {
default:
break;
@ -634,17 +642,17 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
uint16_t upper = *(uint16_t*) (value + sizeof(uint64_t));
X86_CPU(uc, mycpu)->env.fpregs[regid - UC_X86_REG_FP0].d = cpu_set_fp80(mant, upper);
}
return 0;
continue;
case UC_X86_REG_FPSW:
{
uint16_t fpus = *(uint16_t*) value;
X86_CPU(uc, mycpu)->env.fpus = fpus & ~0x3800;
X86_CPU(uc, mycpu)->env.fpstt = (fpus >> 11) & 0x7;
}
return 0;
continue;
case UC_X86_REG_FPCW:
X86_CPU(uc, mycpu)->env.fpuc = *(uint16_t *)value;
return 0;
continue;
case UC_X86_REG_FPTAG:
{
int i;
@ -654,7 +662,7 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
fptag >>= 2;
}
return 0;
continue;
}
break;
}
@ -668,19 +676,19 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
default: break;
case UC_X86_REG_ES:
X86_CPU(uc, mycpu)->env.segs[R_ES].selector = *(uint16_t *)value;
return 0;
continue;
case UC_X86_REG_SS:
X86_CPU(uc, mycpu)->env.segs[R_SS].selector = *(uint16_t *)value;
return 0;
continue;
case UC_X86_REG_DS:
X86_CPU(uc, mycpu)->env.segs[R_DS].selector = *(uint16_t *)value;
return 0;
continue;
case UC_X86_REG_FS:
X86_CPU(uc, mycpu)->env.segs[R_FS].selector = *(uint16_t *)value;
return 0;
continue;
case UC_X86_REG_GS:
X86_CPU(uc, mycpu)->env.segs[R_GS].selector = *(uint16_t *)value;
return 0;
continue;
}
// fall-thru
case UC_MODE_32:
@ -1101,6 +1109,7 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
break;
#endif
}
}
return 0;
}

View file

@ -5,8 +5,8 @@
#define UC_QEMU_TARGET_I386_H
// functions to read & write registers
int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value);
int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value);
int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
void x86_reg_reset(struct uc_struct *uc);

View file

@ -25,10 +25,14 @@ void m68k_reg_reset(struct uc_struct *uc)
env->pc = 0;
}
int m68k_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
int m68k_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count)
{
CPUState *mycpu = first_cpu;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
void *value = vals[i];
if (regid >= UC_M68K_REG_A0 && regid <= UC_M68K_REG_A7)
*(int32_t *)value = M68K_CPU(uc, mycpu)->env.aregs[regid - UC_M68K_REG_A0];
else if (regid >= UC_M68K_REG_D0 && regid <= UC_M68K_REG_D7)
@ -41,14 +45,19 @@ int m68k_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
break;
}
}
}
return 0;
}
int m68k_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
int m68k_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count)
{
CPUState *mycpu = first_cpu;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
const void *value = vals[i];
if (regid >= UC_M68K_REG_A0 && regid <= UC_M68K_REG_A7)
M68K_CPU(uc, mycpu)->env.aregs[regid - UC_M68K_REG_A0] = *(uint32_t *)value;
else if (regid >= UC_M68K_REG_D0 && regid <= UC_M68K_REG_D7)
@ -64,7 +73,7 @@ int m68k_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
break;
}
}
}
return 0;
}

View file

@ -5,8 +5,8 @@
#define UC_QEMU_TARGET_M68K_H
// functions to read & write registers
int m68k_reg_read(struct uc_struct *uc, unsigned int regid, void *value);
int m68k_reg_write(struct uc_struct *uc, unsigned int regid, const void *value);
int m68k_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
int m68k_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
void m68k_reg_reset(struct uc_struct *uc);

View file

@ -39,10 +39,14 @@ void mips_reg_reset(struct uc_struct *uc)
env->active_tc.PC = 0;
}
int mips_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
int mips_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count)
{
CPUState *mycpu = first_cpu;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
void *value = vals[i];
if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31)
*(int32_t *)value = MIPS_CPU(uc, mycpu)->env.active_tc.gpr[regid - UC_MIPS_REG_0];
else {
@ -53,14 +57,19 @@ int mips_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
break;
}
}
}
return 0;
}
int mips_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
int mips_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count)
{
CPUState *mycpu = first_cpu;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
const void *value = vals[i];
if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31)
MIPS_CPU(uc, mycpu)->env.active_tc.gpr[regid - UC_MIPS_REG_0] = *(uint32_t *)value;
else {
@ -74,7 +83,7 @@ int mips_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
break;
}
}
}
return 0;
}

View file

@ -5,8 +5,8 @@
#define UC_QEMU_TARGET_MIPS_H
// functions to read & write registers
int mips_reg_read(struct uc_struct *uc, unsigned int regid, void *value);
int mips_reg_write(struct uc_struct *uc, unsigned int regid, const void *value);
int mips_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
int mips_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
void mips_reg_reset(struct uc_struct *uc);

View file

@ -39,10 +39,14 @@ void sparc_reg_reset(struct uc_struct *uc)
env->regwptr = env->regbase;
}
int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count)
{
CPUState *mycpu = first_cpu;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
void *value = vals[i];
if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7)
*(int32_t *)value = SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0];
else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7)
@ -59,14 +63,19 @@ int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
break;
}
}
}
return 0;
}
int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count)
{
CPUState *mycpu = first_cpu;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
const void *value = vals[i];
if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7)
SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0] = *(uint32_t *)value;
else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7)
@ -87,6 +96,7 @@ int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
break;
}
}
}
return 0;
}

View file

@ -5,8 +5,8 @@
#define UC_QEMU_TARGET_SPARC_H
// functions to read & write registers
int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value);
int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value);
int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
void sparc_reg_reset(struct uc_struct *uc);

View file

@ -39,10 +39,14 @@ void sparc_reg_reset(struct uc_struct *uc)
env->regwptr = env->regbase;
}
int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count)
{
CPUState *mycpu = first_cpu;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
void *value = vals[i];
if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7)
*(int64_t *)value = SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0];
else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7)
@ -59,14 +63,19 @@ int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
break;
}
}
}
return 0;
}
int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, void* const* vals, int count)
{
CPUState *mycpu = first_cpu;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
const void *value = vals[i];
if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7)
SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0] = *(uint64_t *)value;
else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7)
@ -84,7 +93,7 @@ int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
break;
}
}
}
return 0;
}

22
uc.c
View file

@ -332,10 +332,10 @@ uc_err uc_close(uc_engine *uc)
UNICORN_EXPORT
uc_err uc_reg_read(uc_engine *uc, int regid, void *value)
uc_err uc_reg_read_batch(uc_engine *uc, int *ids, void **vals, int count)
{
if (uc->reg_read)
uc->reg_read(uc, regid, value);
uc->reg_read(uc, (unsigned int *)ids, vals, count);
else
return -1; // FIXME: need a proper uc_err
@ -344,10 +344,10 @@ uc_err uc_reg_read(uc_engine *uc, int regid, void *value)
UNICORN_EXPORT
uc_err uc_reg_write(uc_engine *uc, int regid, const void *value)
uc_err uc_reg_write_batch(uc_engine *uc, int *ids, void *const *vals, int count)
{
if (uc->reg_write)
uc->reg_write(uc, regid, value);
uc->reg_write(uc, (unsigned int *)ids, vals, count);
else
return -1; // FIXME: need a proper uc_err
@ -355,6 +355,20 @@ uc_err uc_reg_write(uc_engine *uc, int regid, const void *value)
}
UNICORN_EXPORT
uc_err uc_reg_read(uc_engine *uc, int regid, void *value)
{
return uc_reg_read_batch(uc, &regid, &value, 1);
}
UNICORN_EXPORT
uc_err uc_reg_write(uc_engine *uc, int regid, const void *value)
{
return uc_reg_write_batch(uc, &regid, (void *const *)&value, 1);
}
// check if a memory area is mapped
// this is complicated because an area can overlap adjacent blocks
static bool check_mem_area(uc_engine *uc, uint64_t address, size_t size)