Merge branch 'map-ptr' of https://github.com/lunixbochs/unicorn into lunixbochs-map-ptr

This commit is contained in:
Nguyen Anh Quynh 2015-11-28 15:50:53 +08:00
commit 6b599314e1
21 changed files with 173 additions and 7 deletions

View file

@ -28,6 +28,7 @@ func errReturn(err C.uc_err) error {
type Unicorn interface { type Unicorn interface {
MemMap(addr, size uint64) error MemMap(addr, size uint64) error
MemMapProt(addr, size uint64, prot int) error MemMapProt(addr, size uint64, prot int) error
MemMapPtr(addr, size uint64, ptr unsafe.Pointer) error
MemUnmap(addr, size uint64) error MemUnmap(addr, size uint64) error
MemRead(addr, size uint64) ([]byte, error) MemRead(addr, size uint64) ([]byte, error)
MemReadInto(dst []byte, addr uint64) error MemReadInto(dst []byte, addr uint64) error
@ -128,6 +129,10 @@ func (u *uc) MemMap(addr, size uint64) error {
return u.MemMapProt(addr, size, PROT_ALL) return u.MemMapProt(addr, size, PROT_ALL)
} }
func (u *uc) MemMapPtr(addr, size uint64, ptr unsafe.Pointer) error {
return errReturn(C.uc_mem_map_ptr(u.handle, C.uint64_t(addr), C.size_t(size), ptr))
}
func (u *uc) MemUnmap(addr, size uint64) error { func (u *uc) MemUnmap(addr, size uint64) error {
return errReturn(C.uc_mem_unmap(u.handle, C.uint64_t(addr), C.size_t(size))) return errReturn(C.uc_mem_unmap(u.handle, C.uint64_t(addr), C.size_t(size)))
} }

View file

@ -104,6 +104,7 @@ _setup_prototype(_uc, "uc_emu_start", ucerr, uc_engine, ctypes.c_uint64, ctypes.
_setup_prototype(_uc, "uc_emu_stop", ucerr, uc_engine) _setup_prototype(_uc, "uc_emu_stop", ucerr, uc_engine)
_setup_prototype(_uc, "uc_hook_del", ucerr, uc_engine, uc_hook_h) _setup_prototype(_uc, "uc_hook_del", ucerr, uc_engine, uc_hook_h)
_setup_prototype(_uc, "uc_mem_map", ucerr, uc_engine, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_uint32) _setup_prototype(_uc, "uc_mem_map", ucerr, uc_engine, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_uint32)
_setup_prototype(_uc, "uc_mem_map_ptr", ucerr, uc_engine, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_void_p)
_setup_prototype(_uc, "uc_mem_unmap", ucerr, uc_engine, ctypes.c_uint64, ctypes.c_size_t) _setup_prototype(_uc, "uc_mem_unmap", ucerr, uc_engine, ctypes.c_uint64, ctypes.c_size_t)
_setup_prototype(_uc, "uc_mem_protect", ucerr, uc_engine, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_uint32) _setup_prototype(_uc, "uc_mem_protect", ucerr, uc_engine, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_uint32)
@ -241,6 +242,13 @@ class Uc(object):
raise UcError(status) raise UcError(status)
# map a range of memory from a raw host memory address
def mem_map_ptr(self, address, size, ptr):
status = _uc.uc_mem_map_ptr(self._uch, address, size, ptr)
if status != UC_ERR_OK:
raise UcError(status)
# unmap a range of memory # unmap a range of memory
def mem_unmap(self, address, size): def mem_unmap(self, address, size):
status = _uc.uc_mem_unmap(self._uch, address, size) status = _uc.uc_mem_unmap(self._uch, address, size)

View file

@ -48,6 +48,8 @@ typedef void (*uc_args_uc_u64_t)(struct uc_struct *, uint64_t addr);
typedef MemoryRegion* (*uc_args_uc_ram_size_t)(struct uc_struct*, ram_addr_t begin, size_t size, uint32_t perms); typedef MemoryRegion* (*uc_args_uc_ram_size_t)(struct uc_struct*, ram_addr_t begin, size_t size, uint32_t perms);
typedef MemoryRegion* (*uc_args_uc_ram_size_ptr_t)(struct uc_struct*, ram_addr_t begin, size_t size, void *ptr);
typedef void (*uc_mem_unmap_t)(struct uc_struct*, MemoryRegion *mr); typedef void (*uc_mem_unmap_t)(struct uc_struct*, MemoryRegion *mr);
typedef void (*uc_readonly_mem_t)(MemoryRegion *mr, bool readonly); typedef void (*uc_readonly_mem_t)(MemoryRegion *mr, bool readonly);
@ -97,6 +99,7 @@ struct uc_struct {
uc_args_tcg_enable_t tcg_enabled; uc_args_tcg_enable_t tcg_enabled;
uc_args_uc_long_t tcg_exec_init; uc_args_uc_long_t tcg_exec_init;
uc_args_uc_ram_size_t memory_map; uc_args_uc_ram_size_t memory_map;
uc_args_uc_ram_size_ptr_t memory_map_ptr;
uc_mem_unmap_t memory_unmap; uc_mem_unmap_t memory_unmap;
uc_readonly_mem_t readonly_mem; uc_readonly_mem_t readonly_mem;
uc_mem_redirect_t mem_redirect; uc_mem_redirect_t mem_redirect;

View file

@ -446,6 +446,24 @@ typedef enum uc_prot {
UNICORN_EXPORT UNICORN_EXPORT
uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms); uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms);
/*
Map existing host memory in for emulation.
This API adds a memory region that can be used by emulation.
@uc: handle returned by uc_open()
@address: starting address of the new memory region to be mapped in.
This address must be aligned to 4KB, or this will return with UC_ERR_ARG error.
@size: size of the new memory region to be mapped in.
This size must be multiple of 4KB, or this will return with UC_ERR_ARG error.
@ptr: pointer to host memory backing the newly mapped memory. Existing host
memory permissions are preserved.
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
for detailed error).
*/
UNICORN_EXPORT
uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size, void *ptr);
/* /*
Unmap a region of emulation memory. Unmap a region of emulation memory.
This API deletes a memory mapping from the emulation memory space. This API deletes a memory mapping from the emulation memory space.

View file

@ -8,6 +8,7 @@
#define phys_mem_clean phys_mem_clean_aarch64 #define phys_mem_clean phys_mem_clean_aarch64
#define tb_cleanup tb_cleanup_aarch64 #define tb_cleanup tb_cleanup_aarch64
#define memory_map memory_map_aarch64 #define memory_map memory_map_aarch64
#define memory_map_ptr memory_map_ptr_aarch64
#define memory_unmap memory_unmap_aarch64 #define memory_unmap memory_unmap_aarch64
#define memory_free memory_free_aarch64 #define memory_free memory_free_aarch64
#define helper_raise_exception helper_raise_exception_aarch64 #define helper_raise_exception helper_raise_exception_aarch64

View file

@ -8,6 +8,7 @@
#define phys_mem_clean phys_mem_clean_arm #define phys_mem_clean phys_mem_clean_arm
#define tb_cleanup tb_cleanup_arm #define tb_cleanup tb_cleanup_arm
#define memory_map memory_map_arm #define memory_map memory_map_arm
#define memory_map_ptr memory_map_ptr_arm
#define memory_unmap memory_unmap_arm #define memory_unmap memory_unmap_arm
#define memory_free memory_free_arm #define memory_free memory_free_arm
#define helper_raise_exception helper_raise_exception_arm #define helper_raise_exception helper_raise_exception_arm

View file

@ -14,6 +14,7 @@ symbols = (
'phys_mem_clean', 'phys_mem_clean',
'tb_cleanup', 'tb_cleanup',
'memory_map', 'memory_map',
'memory_map_ptr',
'memory_unmap', 'memory_unmap',
'memory_free', 'memory_free',
'helper_raise_exception', 'helper_raise_exception',

View file

@ -939,6 +939,7 @@ void address_space_unmap(AddressSpace *as, void *buffer, hwaddr len,
void memory_register_types(struct uc_struct *uc); void memory_register_types(struct uc_struct *uc);
MemoryRegion *memory_map(struct uc_struct *uc, ram_addr_t begin, size_t size, uint32_t perms); MemoryRegion *memory_map(struct uc_struct *uc, ram_addr_t begin, size_t size, uint32_t perms);
MemoryRegion *memory_map_ptr(struct uc_struct *uc, ram_addr_t begin, size_t size, void *ptr);
void memory_unmap(struct uc_struct *uc, MemoryRegion *mr); void memory_unmap(struct uc_struct *uc, MemoryRegion *mr);
int memory_free(struct uc_struct *uc); int memory_free(struct uc_struct *uc);

View file

@ -8,6 +8,7 @@
#define phys_mem_clean phys_mem_clean_m68k #define phys_mem_clean phys_mem_clean_m68k
#define tb_cleanup tb_cleanup_m68k #define tb_cleanup tb_cleanup_m68k
#define memory_map memory_map_m68k #define memory_map memory_map_m68k
#define memory_map_ptr memory_map_ptr_m68k
#define memory_unmap memory_unmap_m68k #define memory_unmap memory_unmap_m68k
#define memory_free memory_free_m68k #define memory_free memory_free_m68k
#define helper_raise_exception helper_raise_exception_m68k #define helper_raise_exception helper_raise_exception_m68k

View file

@ -48,6 +48,23 @@ MemoryRegion *memory_map(struct uc_struct *uc, ram_addr_t begin, size_t size, ui
return ram; return ram;
} }
MemoryRegion *memory_map_ptr(struct uc_struct *uc, ram_addr_t begin, size_t size, void *ptr)
{
MemoryRegion *ram = g_new(MemoryRegion, 1);
memory_region_init_ram_ptr(uc, ram, NULL, "pc.ram", size, ptr);
if (ram->ram_addr == -1)
// out of memory
return NULL;
memory_region_add_subregion(get_system_memory(uc), begin, ram);
if (uc->current_cpu)
tlb_flush(uc->current_cpu, 1);
return ram;
}
void memory_unmap(struct uc_struct *uc, MemoryRegion *mr) void memory_unmap(struct uc_struct *uc, MemoryRegion *mr)
{ {
int i; int i;

View file

@ -8,6 +8,7 @@
#define phys_mem_clean phys_mem_clean_mips #define phys_mem_clean phys_mem_clean_mips
#define tb_cleanup tb_cleanup_mips #define tb_cleanup tb_cleanup_mips
#define memory_map memory_map_mips #define memory_map memory_map_mips
#define memory_map_ptr memory_map_ptr_mips
#define memory_unmap memory_unmap_mips #define memory_unmap memory_unmap_mips
#define memory_free memory_free_mips #define memory_free memory_free_mips
#define helper_raise_exception helper_raise_exception_mips #define helper_raise_exception helper_raise_exception_mips

View file

@ -8,6 +8,7 @@
#define phys_mem_clean phys_mem_clean_mips64 #define phys_mem_clean phys_mem_clean_mips64
#define tb_cleanup tb_cleanup_mips64 #define tb_cleanup tb_cleanup_mips64
#define memory_map memory_map_mips64 #define memory_map memory_map_mips64
#define memory_map_ptr memory_map_ptr_mips64
#define memory_unmap memory_unmap_mips64 #define memory_unmap memory_unmap_mips64
#define memory_free memory_free_mips64 #define memory_free memory_free_mips64
#define helper_raise_exception helper_raise_exception_mips64 #define helper_raise_exception helper_raise_exception_mips64

View file

@ -8,6 +8,7 @@
#define phys_mem_clean phys_mem_clean_mips64el #define phys_mem_clean phys_mem_clean_mips64el
#define tb_cleanup tb_cleanup_mips64el #define tb_cleanup tb_cleanup_mips64el
#define memory_map memory_map_mips64el #define memory_map memory_map_mips64el
#define memory_map_ptr memory_map_ptr_mips64el
#define memory_unmap memory_unmap_mips64el #define memory_unmap memory_unmap_mips64el
#define memory_free memory_free_mips64el #define memory_free memory_free_mips64el
#define helper_raise_exception helper_raise_exception_mips64el #define helper_raise_exception helper_raise_exception_mips64el

View file

@ -8,6 +8,7 @@
#define phys_mem_clean phys_mem_clean_mipsel #define phys_mem_clean phys_mem_clean_mipsel
#define tb_cleanup tb_cleanup_mipsel #define tb_cleanup tb_cleanup_mipsel
#define memory_map memory_map_mipsel #define memory_map memory_map_mipsel
#define memory_map_ptr memory_map_ptr_mipsel
#define memory_unmap memory_unmap_mipsel #define memory_unmap memory_unmap_mipsel
#define memory_free memory_free_mipsel #define memory_free memory_free_mipsel
#define helper_raise_exception helper_raise_exception_mipsel #define helper_raise_exception helper_raise_exception_mipsel

View file

@ -8,6 +8,7 @@
#define phys_mem_clean phys_mem_clean_sparc #define phys_mem_clean phys_mem_clean_sparc
#define tb_cleanup tb_cleanup_sparc #define tb_cleanup tb_cleanup_sparc
#define memory_map memory_map_sparc #define memory_map memory_map_sparc
#define memory_map_ptr memory_map_ptr_sparc
#define memory_unmap memory_unmap_sparc #define memory_unmap memory_unmap_sparc
#define memory_free memory_free_sparc #define memory_free memory_free_sparc
#define helper_raise_exception helper_raise_exception_sparc #define helper_raise_exception helper_raise_exception_sparc

View file

@ -8,6 +8,7 @@
#define phys_mem_clean phys_mem_clean_sparc64 #define phys_mem_clean phys_mem_clean_sparc64
#define tb_cleanup tb_cleanup_sparc64 #define tb_cleanup tb_cleanup_sparc64
#define memory_map memory_map_sparc64 #define memory_map memory_map_sparc64
#define memory_map_ptr memory_map_ptr_sparc64
#define memory_unmap memory_unmap_sparc64 #define memory_unmap memory_unmap_sparc64
#define memory_free memory_free_sparc64 #define memory_free memory_free_sparc64
#define helper_raise_exception helper_raise_exception_sparc64 #define helper_raise_exception helper_raise_exception_sparc64

View file

@ -73,6 +73,7 @@ static inline void uc_common_init(struct uc_struct* uc)
uc->pause_all_vcpus = pause_all_vcpus; uc->pause_all_vcpus = pause_all_vcpus;
uc->vm_start = vm_start; uc->vm_start = vm_start;
uc->memory_map = memory_map; uc->memory_map = memory_map;
uc->memory_map_ptr = memory_map_ptr;
uc->memory_unmap = memory_unmap; uc->memory_unmap = memory_unmap;
uc->readonly_mem = memory_region_set_readonly; uc->readonly_mem = memory_region_set_readonly;

View file

@ -8,6 +8,7 @@
#define phys_mem_clean phys_mem_clean_x86_64 #define phys_mem_clean phys_mem_clean_x86_64
#define tb_cleanup tb_cleanup_x86_64 #define tb_cleanup tb_cleanup_x86_64
#define memory_map memory_map_x86_64 #define memory_map memory_map_x86_64
#define memory_map_ptr memory_map_ptr_x86_64
#define memory_unmap memory_unmap_x86_64 #define memory_unmap memory_unmap_x86_64
#define memory_free memory_free_x86_64 #define memory_free memory_free_x86_64
#define helper_raise_exception helper_raise_exception_x86_64 #define helper_raise_exception helper_raise_exception_x86_64

View file

@ -4,7 +4,7 @@ CFLAGS += -L ../../
CFLAGS += -lcmocka -lunicorn CFLAGS += -lcmocka -lunicorn
CFLAGS += -I ../../include CFLAGS += -I ../../include
ALL_TESTS = test_sanity test_x86 test_mem_map ALL_TESTS = test_sanity test_x86 test_mem_map test_mem_map_ptr
.PHONY: all .PHONY: all
all: ${ALL_TESTS} all: ${ALL_TESTS}
@ -23,9 +23,7 @@ test: ${ALL_TESTS}
test_sanity: test_sanity.c test_sanity: test_sanity.c
test_x86: test_x86.c test_x86: test_x86.c
test_mem_map: test_mem_map.c test_mem_map: test_mem_map.c
test_mem_map_ptr: test_mem_map_ptr.c
${ALL_TESTS}: ${ALL_TESTS}:
gcc ${CFLAGS} -o $@ $^ gcc ${CFLAGS} -o $@ $^

View file

@ -0,0 +1,75 @@
/**
* Unicorn memory API tests
*
* This tests manual pointer-backed memory.
*/
#include "unicorn_test.h"
#include <stdio.h>
#include <string.h>
/* Called before every test to set up a new instance */
static int setup(void **state)
{
uc_engine *uc;
uc_assert_success(uc_open(UC_ARCH_X86, UC_MODE_32, &uc));
*state = uc;
return 0;
}
/* Called after every test to clean up */
static int teardown(void **state)
{
uc_engine *uc = *state;
uc_assert_success(uc_close(uc));
*state = NULL;
return 0;
}
/******************************************************************************/
/**
* A basic test showing mapping of memory, and reading/writing it
*/
static void test_basic(void **state)
{
uc_engine *uc = *state;
const uint64_t mem_start = 0x1000;
const uint64_t mem_len = 0x1000;
const uint64_t test_addr = mem_start;
void *host_mem = calloc(1, mem_len);
/* Map a region */
uc_assert_success(uc_mem_map_ptr(uc, mem_start, mem_len, host_mem));
/* Write some data to it */
uc_assert_success(uc_mem_write(uc, test_addr, "test", 4));
uint8_t buf[4];
memset(buf, 0xCC, sizeof(buf));
/* Read it back */
uc_assert_success(uc_mem_read(uc, test_addr, buf, sizeof(buf)));
/* And make sure it matches what we expect */
assert_memory_equal(buf, "test", 4);
/* Unmap the region */
uc_assert_success(uc_mem_unmap(uc, mem_start, mem_len));
assert_memory_equal(buf, host_mem, 4);
}
int main(void) {
#define test(x) cmocka_unit_test_setup_teardown(x, setup, teardown)
const struct CMUnitTest tests[] = {
test(test_basic),
};
#undef test
return cmocka_run_group_tests(tests, NULL, NULL);
}

35
uc.c
View file

@ -570,8 +570,8 @@ static uc_err _hook_mem_access(uc_engine *uc, uc_hook_type type,
return UC_ERR_OK; return UC_ERR_OK;
} }
UNICORN_EXPORT // common setup/error checking shared between uc_mem_map and uc_mem_map_ptr
uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms) static uc_err mem_map_start(uc_engine *uc, uint64_t address, size_t size, uint32_t perms)
{ {
MemoryRegion **regions; MemoryRegion **regions;
@ -600,7 +600,13 @@ uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms)
uc->mapped_blocks = regions; uc->mapped_blocks = regions;
} }
uc->mapped_blocks[uc->mapped_block_count] = uc->memory_map(uc, address, size, perms); return UC_ERR_OK;
}
// common final step shared by uc_mem_map and uc_mem_map_ptr
static uc_err mem_map_finish(uc_engine *uc, MemoryRegion *block)
{
uc->mapped_blocks[uc->mapped_block_count] = block;
if (uc->mapped_blocks[uc->mapped_block_count] == NULL) if (uc->mapped_blocks[uc->mapped_block_count] == NULL)
return UC_ERR_NOMEM; return UC_ERR_NOMEM;
@ -609,6 +615,29 @@ uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms)
return UC_ERR_OK; return UC_ERR_OK;
} }
UNICORN_EXPORT
uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms)
{
uc_err err;
if ((err = mem_map_start(uc, address, size, perms)) != UC_ERR_OK)
return err;
return mem_map_finish(uc, uc->memory_map(uc, address, size, perms));
}
UNICORN_EXPORT
uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size, void *ptr)
{
if (ptr == NULL)
return UC_ERR_ARG;
uc_err err;
if ((err = mem_map_start(uc, address, size, UC_PROT_ALL)) != UC_ERR_OK)
return err;
return mem_map_finish(uc, uc->memory_map_ptr(uc, address, size, ptr));
}
// Create a backup copy of the indicated MemoryRegion. // Create a backup copy of the indicated MemoryRegion.
// Generally used in prepartion for splitting a MemoryRegion. // Generally used in prepartion for splitting a MemoryRegion.
static uint8_t *copy_region(struct uc_struct *uc, MemoryRegion *mr) static uint8_t *copy_region(struct uc_struct *uc, MemoryRegion *mr)