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,57 +23,67 @@ 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;
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 {
switch(regid) {
default: break;
case UC_ARM64_REG_X29:
*(int64_t *)value = ARM_CPU(uc, mycpu)->env.xregs[29];
break;
case UC_ARM64_REG_X30:
*(int64_t *)value = ARM_CPU(uc, mycpu)->env.xregs[30];
break;
case UC_ARM64_REG_PC:
*(uint64_t *)value = ARM_CPU(uc, mycpu)->env.pc;
break;
case UC_ARM64_REG_SP:
*(int64_t *)value = ARM_CPU(uc, mycpu)->env.xregs[31];
break;
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 {
switch(regid) {
default: break;
case UC_ARM64_REG_X29:
*(int64_t *)value = ARM_CPU(uc, mycpu)->env.xregs[29];
break;
case UC_ARM64_REG_X30:
*(int64_t *)value = ARM_CPU(uc, mycpu)->env.xregs[30];
break;
case UC_ARM64_REG_PC:
*(uint64_t *)value = ARM_CPU(uc, mycpu)->env.pc;
break;
case UC_ARM64_REG_SP:
*(int64_t *)value = ARM_CPU(uc, mycpu)->env.xregs[31];
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;
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 {
switch(regid) {
default: break;
case UC_ARM64_REG_X29:
ARM_CPU(uc, mycpu)->env.xregs[29] = *(uint64_t *)value;
break;
case UC_ARM64_REG_X30:
ARM_CPU(uc, mycpu)->env.xregs[30] = *(uint64_t *)value;
break;
case UC_ARM64_REG_PC:
ARM_CPU(uc, mycpu)->env.pc = *(uint64_t *)value;
// force to quit execution and flush TB
uc->quit_request = true;
uc_emu_stop(uc);
break;
case UC_ARM64_REG_SP:
ARM_CPU(uc, mycpu)->env.xregs[31] = *(uint64_t *)value;
break;
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 {
switch(regid) {
default: break;
case UC_ARM64_REG_X29:
ARM_CPU(uc, mycpu)->env.xregs[29] = *(uint64_t *)value;
break;
case UC_ARM64_REG_X30:
ARM_CPU(uc, mycpu)->env.xregs[30] = *(uint64_t *)value;
break;
case UC_ARM64_REG_PC:
ARM_CPU(uc, mycpu)->env.pc = *(uint64_t *)value;
// force to quit execution and flush TB
uc->quit_request = true;
uc_emu_stop(uc);
break;
case UC_ARM64_REG_SP:
ARM_CPU(uc, mycpu)->env.xregs[31] = *(uint64_t *)value;
break;
}
}
}

View File

@ -27,62 +27,72 @@ 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;
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 {
switch(regid) {
case UC_ARM_REG_CPSR:
*(int32_t *)value = cpsr_read(&ARM_CPU(uc, mycpu)->env);
break;
//case UC_ARM_REG_SP:
case UC_ARM_REG_R13:
*(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[13];
break;
//case UC_ARM_REG_LR:
case UC_ARM_REG_R14:
*(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[14];
break;
//case UC_ARM_REG_PC:
case UC_ARM_REG_R15:
*(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[15];
break;
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 {
switch(regid) {
case UC_ARM_REG_CPSR:
*(int32_t *)value = cpsr_read(&ARM_CPU(uc, mycpu)->env);
break;
//case UC_ARM_REG_SP:
case UC_ARM_REG_R13:
*(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[13];
break;
//case UC_ARM_REG_LR:
case UC_ARM_REG_R14:
*(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[14];
break;
//case UC_ARM_REG_PC:
case UC_ARM_REG_R15:
*(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[15];
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;
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 {
switch(regid) {
//case UC_ARM_REG_SP:
case UC_ARM_REG_R13:
ARM_CPU(uc, mycpu)->env.regs[13] = *(uint32_t *)value;
break;
//case UC_ARM_REG_LR:
case UC_ARM_REG_R14:
ARM_CPU(uc, mycpu)->env.regs[14] = *(uint32_t *)value;
break;
//case UC_ARM_REG_PC:
case UC_ARM_REG_R15:
ARM_CPU(uc, mycpu)->env.pc = *(uint32_t *)value;
ARM_CPU(uc, mycpu)->env.regs[15] = *(uint32_t *)value;
// force to quit execution and flush TB
uc->quit_request = true;
uc_emu_stop(uc);
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 {
switch(regid) {
//case UC_ARM_REG_SP:
case UC_ARM_REG_R13:
ARM_CPU(uc, mycpu)->env.regs[13] = *(uint32_t *)value;
break;
//case UC_ARM_REG_LR:
case UC_ARM_REG_R14:
ARM_CPU(uc, mycpu)->env.regs[14] = *(uint32_t *)value;
break;
//case UC_ARM_REG_PC:
case UC_ARM_REG_R15:
ARM_CPU(uc, mycpu)->env.pc = *(uint32_t *)value;
ARM_CPU(uc, mycpu)->env.regs[15] = *(uint32_t *)value;
// force to quit execution and flush TB
uc->quit_request = true;
uc_emu_stop(uc);
break;
break;
}
}
}

File diff suppressed because it is too large Load Diff

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,47 +25,56 @@ 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;
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)
*(int32_t *)value = M68K_CPU(uc, mycpu)->env.dregs[regid - UC_M68K_REG_D0];
else {
switch(regid) {
default: break;
case UC_M68K_REG_PC:
*(int32_t *)value = M68K_CPU(uc, mycpu)->env.pc;
break;
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)
*(int32_t *)value = M68K_CPU(uc, mycpu)->env.dregs[regid - UC_M68K_REG_D0];
else {
switch(regid) {
default: break;
case UC_M68K_REG_PC:
*(int32_t *)value = M68K_CPU(uc, mycpu)->env.pc;
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;
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)
M68K_CPU(uc, mycpu)->env.dregs[regid - UC_M68K_REG_D0] = *(uint32_t *)value;
else {
switch(regid) {
default: break;
case UC_M68K_REG_PC:
M68K_CPU(uc, mycpu)->env.pc = *(uint32_t *)value;
// force to quit execution and flush TB
uc->quit_request = true;
uc_emu_stop(uc);
break;
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)
M68K_CPU(uc, mycpu)->env.dregs[regid - UC_M68K_REG_D0] = *(uint32_t *)value;
else {
switch(regid) {
default: break;
case UC_M68K_REG_PC:
M68K_CPU(uc, mycpu)->env.pc = *(uint32_t *)value;
// force to quit execution and flush TB
uc->quit_request = true;
uc_emu_stop(uc);
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,43 +39,52 @@ 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;
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 {
switch(regid) {
default: break;
case UC_MIPS_REG_PC:
*(int32_t *)value = MIPS_CPU(uc, mycpu)->env.active_tc.PC;
break;
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 {
switch(regid) {
default: break;
case UC_MIPS_REG_PC:
*(int32_t *)value = MIPS_CPU(uc, mycpu)->env.active_tc.PC;
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;
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 {
switch(regid) {
default: break;
case UC_MIPS_REG_PC:
MIPS_CPU(uc, mycpu)->env.active_tc.PC = *(uint32_t *)value;
// force to quit execution and flush TB
uc->quit_request = true;
uc_emu_stop(uc);
break;
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 {
switch(regid) {
default: break;
case UC_MIPS_REG_PC:
MIPS_CPU(uc, mycpu)->env.active_tc.PC = *(uint32_t *)value;
// force to quit execution and flush TB
uc->quit_request = true;
uc_emu_stop(uc);
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,52 +39,62 @@ 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;
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)
*(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0];
else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7)
*(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0];
else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7)
*(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0];
else {
switch(regid) {
default: break;
case UC_SPARC_REG_PC:
*(int32_t *)value = SPARC_CPU(uc, mycpu)->env.pc;
break;
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)
*(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0];
else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7)
*(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0];
else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7)
*(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0];
else {
switch(regid) {
default: break;
case UC_SPARC_REG_PC:
*(int32_t *)value = SPARC_CPU(uc, mycpu)->env.pc;
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;
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)
SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0] = *(uint32_t *)value;
else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7)
SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0] = *(uint32_t *)value;
else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7)
SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0] = *(uint32_t *)value;
else {
switch(regid) {
default: break;
case UC_SPARC_REG_PC:
SPARC_CPU(uc, mycpu)->env.pc = *(uint32_t *)value;
SPARC_CPU(uc, mycpu)->env.npc = *(uint32_t *)value + 4;
// force to quit execution and flush TB
uc->quit_request = true;
uc_emu_stop(uc);
break;
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)
SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0] = *(uint32_t *)value;
else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7)
SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0] = *(uint32_t *)value;
else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7)
SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0] = *(uint32_t *)value;
else {
switch(regid) {
default: break;
case UC_SPARC_REG_PC:
SPARC_CPU(uc, mycpu)->env.pc = *(uint32_t *)value;
SPARC_CPU(uc, mycpu)->env.npc = *(uint32_t *)value + 4;
// force to quit execution and flush TB
uc->quit_request = true;
uc_emu_stop(uc);
break;
}
}
}

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,53 +39,62 @@ 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;
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)
*(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0];
else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7)
*(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0];
else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7)
*(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0];
else {
switch(regid) {
default: break;
case UC_SPARC_REG_PC:
*(int64_t *)value = SPARC_CPU(uc, mycpu)->env.pc;
break;
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)
*(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0];
else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7)
*(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0];
else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7)
*(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0];
else {
switch(regid) {
default: break;
case UC_SPARC_REG_PC:
*(int64_t *)value = SPARC_CPU(uc, mycpu)->env.pc;
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;
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)
SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0] = *(uint64_t *)value;
else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7)
SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0] = *(uint64_t *)value;
else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7)
SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0] = *(uint64_t *)value;
else {
switch(regid) {
default: break;
case UC_SPARC_REG_PC:
SPARC_CPU(uc, mycpu)->env.pc = *(uint64_t *)value;
SPARC_CPU(uc, mycpu)->env.npc = *(uint64_t *)value + 4;
break;
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)
SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0] = *(uint64_t *)value;
else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7)
SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0] = *(uint64_t *)value;
else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7)
SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0] = *(uint64_t *)value;
else {
switch(regid) {
default: break;
case UC_SPARC_REG_PC:
SPARC_CPU(uc, mycpu)->env.pc = *(uint64_t *)value;
SPARC_CPU(uc, mycpu)->env.npc = *(uint64_t *)value + 4;
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)