Merge branch 'mem_map_ex' of https://github.com/cseagle/unicorn into cseagle-mem_map_ex

This commit is contained in:
Nguyen Anh Quynh 2015-08-28 18:11:10 +08:00
commit 96a274c4aa
10 changed files with 353 additions and 51 deletions

View File

@ -15,12 +15,6 @@
QTAILQ_HEAD(CPUTailQ, CPUState);
typedef struct MemoryBlock {
uint64_t begin; //inclusive
uint64_t end; //exclusive
uint32_t perms;
} MemoryBlock;
typedef struct ModuleEntry {
void (*init)(void);
QTAILQ_ENTRY(ModuleEntry) node;
@ -51,7 +45,9 @@ typedef void (*uc_args_uc_long_t)(struct uc_struct*, unsigned long);
typedef void (*uc_args_uc_u64_t)(struct uc_struct *, uint64_t addr);
typedef int (*uc_args_uc_ram_size_t)(struct uc_struct*, ram_addr_t begin, size_t size);
typedef MemoryRegion* (*uc_args_uc_ram_size_t)(struct uc_struct*, ram_addr_t begin, size_t size, uint32_t perms);
typedef void (*uc_readonly_mem_t)(MemoryRegion *mr, bool readonly);
// which interrupt should make emulation stop?
typedef bool (*uc_args_int_t)(int intno);
@ -94,6 +90,7 @@ struct uc_struct {
uc_args_tcg_enable_t tcg_enabled;
uc_args_uc_long_t tcg_exec_init;
uc_args_uc_ram_size_t memory_map;
uc_readonly_mem_t readonly_mem;
// list of cpu
void* cpu;
@ -174,13 +171,13 @@ struct uc_struct {
int thumb; // thumb mode for ARM
// full TCG cache leads to middle-block break in the last translation?
bool block_full;
MemoryBlock *mapped_blocks;
MemoryRegion **mapped_blocks;
uint32_t mapped_block_count;
};
#include "qemu_macro.h"
// check if this address is mapped in (via uc_mem_map())
bool memory_mapping(struct uc_struct* uc, uint64_t address);
MemoryRegion *memory_mapping(struct uc_struct* uc, uint64_t address);
#endif

View File

@ -116,6 +116,7 @@ typedef enum uc_err {
UC_ERR_HOOK, // Invalid hook type: uc_hook_add()
UC_ERR_INSN_INVALID, // Quit emulation due to invalid instruction: uc_emu_start()
UC_ERR_MAP, // Invalid memory mapping: uc_mem_map()
UC_ERR_MEM_WRITE_RO, // Quit emulation due to invalid memory WRITE: uc_emu_start()
} uc_err;
@ -147,6 +148,7 @@ typedef enum uc_mem_type {
UC_MEM_READ = 16, // Memory is read from
UC_MEM_WRITE, // Memory is written to
UC_MEM_READ_WRITE, // Memory is accessed (either READ or WRITE)
UC_MEM_WRITE_RO, // Read only memory is written to
} uc_mem_type;
// All type of hooks for uc_hook_add() API.
@ -387,12 +389,12 @@ uc_err uc_hook_del(uch handle, uch *h2);
typedef enum uc_prot {
UC_PROT_READ = 1,
UC_PROT_WRITE = 2,
UC_PROT_EXEC = 4
} uc_prot;
/*
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. The region is mapped
with permissions UC_PROT_READ | UC_PROT_WRITE.
@handle: handle returned by uc_open()
@address: starting address of the new memory region to be mapped in.
@ -406,6 +408,25 @@ typedef enum uc_prot {
UNICORN_EXPORT
uc_err uc_mem_map(uch handle, uint64_t address, size_t size);
/*
Map memory in for emulation.
This API adds a memory region that can be used by emulation.
@handle: 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_MAP 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_MAP error.
@perms: Permissions for the newly mapped region.
This must be some combination of UC_PROT_READ | UC_PROT_WRITE,
or this will return with UC_ERR_MAP error.
@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_ex(uch handle, uint64_t address, size_t size, uint32_t perms);
#ifdef __cplusplus
}
#endif

6
qemu/include/exec/memory.h Normal file → Executable file
View File

@ -170,6 +170,8 @@ struct MemoryRegion {
MemoryRegionIoeventfd *ioeventfds;
NotifierList iommu_notify;
struct uc_struct *uc;
uint32_t perms; //all perms, partially redundant with readonly
uint64_t end;
};
/**
@ -315,12 +317,14 @@ void memory_region_init_io(struct uc_struct *uc, MemoryRegion *mr,
* @owner: the object that tracks the region's reference count
* @name: the name of the region.
* @size: size of the region.
* @perms: permissions on the region (UC_PROT_READ, UC_PROT_WRITE, UC_PROT_EXEC).
* @errp: pointer to Error*, to store an error if it happens.
*/
void memory_region_init_ram(struct uc_struct *uc, MemoryRegion *mr,
struct Object *owner,
const char *name,
uint64_t size,
uint32_t perms,
Error **errp);
/**
@ -934,7 +938,7 @@ void address_space_unmap(AddressSpace *as, void *buffer, hwaddr len,
void memory_register_types(struct uc_struct *uc);
int memory_map(struct uc_struct *uc, ram_addr_t begin, size_t size);
MemoryRegion *memory_map(struct uc_struct *uc, ram_addr_t begin, size_t size, uint32_t perms);
int memory_free(struct uc_struct *uc);
#endif

27
qemu/memory.c Normal file → Executable file
View File

@ -31,27 +31,28 @@
// Unicorn engine
int memory_map(struct uc_struct *uc, ram_addr_t begin, size_t size)
MemoryRegion *memory_map(struct uc_struct *uc, ram_addr_t begin, size_t size, uint32_t perms)
{
uc->ram = g_new(MemoryRegion, 1);
memory_region_init_ram(uc, uc->ram, NULL, "pc.ram", size, &error_abort);
memory_region_init_ram(uc, uc->ram, NULL, "pc.ram", size, perms, &error_abort);
memory_region_add_subregion(get_system_memory(uc), begin, uc->ram);
if (uc->current_cpu)
tlb_flush(uc->current_cpu, 1);
return 0;
return uc->ram;
}
int memory_free(struct uc_struct *uc)
{
int i;
get_system_memory(uc)->enabled = false;
if (uc->ram) {
uc->ram->enabled = false;
memory_region_del_subregion(get_system_memory(uc), uc->ram);
g_free(uc->ram);
for (i = 0; i < uc->mapped_block_count; i++) {
uc->mapped_blocks[i]->enabled = false;
memory_region_del_subregion(get_system_memory(uc), uc->mapped_blocks[i]);
g_free(uc->mapped_blocks[i]);
}
return 0;
}
@ -1151,10 +1152,15 @@ void memory_region_init_ram(struct uc_struct *uc, MemoryRegion *mr,
Object *owner,
const char *name,
uint64_t size,
uint32_t perms,
Error **errp)
{
memory_region_init(uc, mr, owner, name, size);
mr->ram = true;
if (!(perms & UC_PROT_WRITE)) {
mr->readonly = true;
}
mr->perms = perms;
mr->terminates = true;
mr->destructor = memory_region_destructor_ram;
mr->ram_addr = qemu_ram_alloc(size, mr, errp);
@ -1309,6 +1315,12 @@ void memory_region_set_readonly(MemoryRegion *mr, bool readonly)
if (mr->readonly != readonly) {
memory_region_transaction_begin(mr->uc);
mr->readonly = readonly;
if (readonly) {
mr->perms &= ~UC_PROT_WRITE;
}
else {
mr->perms |= UC_PROT_WRITE;
}
mr->uc->memory_region_update_pending |= mr->enabled;
memory_region_transaction_commit(mr->uc);
}
@ -1528,6 +1540,7 @@ static void memory_region_add_subregion_common(MemoryRegion *mr,
assert(!subregion->container);
subregion->container = mr;
subregion->addr = offset;
subregion->end = offset + int128_get64(subregion->size);
memory_region_update_container_subregions(subregion);
}

View File

@ -460,31 +460,53 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
target_ulong tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
uintptr_t haddr;
struct uc_struct *uc = env->uc;
MemoryRegion *mr = memory_mapping(uc, addr);
// Unicorn: callback on memory write
if (env->uc->hook_mem_write) {
struct hook_struct *trace = hook_find((uch)env->uc, UC_MEM_WRITE, addr);
if (uc->hook_mem_write) {
struct hook_struct *trace = hook_find((uch)uc, UC_MEM_WRITE, addr);
if (trace) {
((uc_cb_hookmem_t)trace->callback)((uch)env->uc, UC_MEM_WRITE,
((uc_cb_hookmem_t)trace->callback)((uch)uc, UC_MEM_WRITE,
(uint64_t)addr, (int)DATA_SIZE, (int64_t)val, trace->user_data);
}
}
// Unicorn: callback on invalid memory
if (env->uc->hook_mem_idx && !memory_mapping(env->uc, addr)) {
if (!((uc_cb_eventmem_t)env->uc->hook_callbacks[env->uc->hook_mem_idx].callback)(
(uch)env->uc, UC_MEM_WRITE, addr, DATA_SIZE, (int64_t)val,
env->uc->hook_callbacks[env->uc->hook_mem_idx].user_data)) {
if (uc->hook_mem_idx && mr == NULL) {
if (!((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)(
(uch)uc, UC_MEM_WRITE, addr, DATA_SIZE, (int64_t)val,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) {
// save error & quit
env->invalid_addr = addr;
env->invalid_error = UC_ERR_MEM_WRITE;
// printf("***** Invalid memory write at " TARGET_FMT_lx "\n", addr);
cpu_exit(env->uc->current_cpu);
cpu_exit(uc->current_cpu);
return;
} else {
env->invalid_error = UC_ERR_OK;
}
}
// Unicorn: callback on read only memory
if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //read only memory
bool result = false;
if (uc->hook_mem_idx) {
result = ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)(
(uch)uc, UC_MEM_WRITE_RO, addr, DATA_SIZE, (int64_t)val,
uc->hook_callbacks[uc->hook_mem_idx].user_data);
}
if (result) {
env->invalid_error = UC_ERR_OK;
}
else {
env->invalid_addr = addr;
env->invalid_error = UC_ERR_MEM_WRITE_RO;
// printf("***** Invalid memory write (ro) at " TARGET_FMT_lx "\n", addr);
cpu_exit(uc->current_cpu);
return;
}
}
/* Adjust the given return address. */
retaddr -= GETPC_ADJ;
@ -546,6 +568,8 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
Undo that for the recursion. */
glue(helper_ret_stb, MMUSUFFIX)(env, addr + i, val8,
mmu_idx, retaddr + GETPC_ADJ);
if (env->invalid_error != UC_ERR_OK)
break;
}
return;
}
@ -574,31 +598,54 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
target_ulong tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
uintptr_t haddr;
struct uc_struct *uc = env->uc;
MemoryRegion *mr = memory_mapping(uc, addr);
// Unicorn: callback on memory write
if (env->uc->hook_mem_write) {
struct hook_struct *trace = hook_find((uch)env->uc, UC_MEM_WRITE, addr);
if (uc->hook_mem_write) {
struct hook_struct *trace = hook_find((uch)uc, UC_MEM_WRITE, addr);
if (trace) {
((uc_cb_hookmem_t)trace->callback)((uch)env->uc, UC_MEM_WRITE,
((uc_cb_hookmem_t)trace->callback)((uch)uc, UC_MEM_WRITE,
(uint64_t)addr, (int)DATA_SIZE, (int64_t)val, trace->user_data);
}
}
// Unicorn: callback on invalid memory
if (env->uc->hook_mem_idx && !memory_mapping(env->uc, addr)) {
if (!((uc_cb_eventmem_t)env->uc->hook_callbacks[env->uc->hook_mem_idx].callback)(
(uch)env->uc, UC_MEM_WRITE, addr, DATA_SIZE, (int64_t)val,
env->uc->hook_callbacks[env->uc->hook_mem_idx].user_data)) {
if (uc->hook_mem_idx && mr == NULL) {
if (!((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)(
(uch)uc, UC_MEM_WRITE, addr, DATA_SIZE, (int64_t)val,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) {
// save error & quit
env->invalid_addr = addr;
env->invalid_error = UC_ERR_MEM_WRITE;
// printf("***** Invalid memory write at " TARGET_FMT_lx "\n", addr);
cpu_exit(env->uc->current_cpu);
cpu_exit(uc->current_cpu);
return;
} else {
env->invalid_error = UC_ERR_OK;
}
}
// Unicorn: callback on read only memory
if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //read only memory
bool result = false;
if (uc->hook_mem_idx) {
result = ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)(
(uch)uc, UC_MEM_WRITE_RO, addr, DATA_SIZE, (int64_t)val,
uc->hook_callbacks[uc->hook_mem_idx].user_data);
}
if (result) {
env->invalid_error = UC_ERR_OK;
}
else {
env->invalid_addr = addr;
env->invalid_error = UC_ERR_MEM_WRITE_RO;
// printf("***** Invalid memory write (ro) at " TARGET_FMT_lx "\n", addr);
cpu_exit(uc->current_cpu);
return;
}
}
/* Adjust the given return address. */
retaddr -= GETPC_ADJ;
@ -659,6 +706,8 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
Undo that for the recursion. */
glue(helper_ret_stb, MMUSUFFIX)(env, addr + i, val8,
mmu_idx, retaddr + GETPC_ADJ);
if (env->invalid_error != UC_ERR_OK)
break;
}
return;
}

1
qemu/unicorn_common.h Normal file → Executable file
View File

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

1
regress/Makefile Normal file → Executable file
View File

@ -4,6 +4,7 @@ LDFLAGS = -L.. -lunicorn
TESTS = map_crash map_write
TESTS += sigill sigill2
TESTS += block_test
TESTS += ro_mem_test
all: $(TESTS)

195
regress/ro_mem_test.c Executable file
View File

@ -0,0 +1,195 @@
#include <inttypes.h>
#include <string.h>
#include <unistd.h>
#include <unicorn/unicorn.h>
const uint8_t PROGRAM[] =
"\xeb\x1a\x58\x83\xc0\x04\x83\xe0\xfc\x83\xc0\x01\xc7\x00\x78\x56"
"\x34\x12\x83\xc0\x07\xc7\x00\x21\x43\x65\x87\x90\xe8\xe1\xff\xff"
"\xff" "xxxxAAAAxxxBBBB";
// total size: 33 bytes
/*
jmp short bottom
top:
pop eax
add eax, 4
and eax, 0xfffffffc
add eax, 1 ; unaligned
mov dword [eax], 0x12345678 ; try to write into code section
add eax, 7 ; aligned
mov dword [eax], 0x87654321 ; try to write into code section
nop
bottom:
call top
*/
// callback for tracing instruction
static void hook_code(uch handle, uint64_t address, uint32_t size, void *user_data)
{
uint32_t esp;
printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size);
uc_reg_read(handle, UC_X86_REG_ESP, &esp);
printf(">>> --- ESP is 0x%x\n", esp);
}
// callback for tracing memory access (READ or WRITE)
static bool hook_mem_invalid(uch handle, uc_mem_type type,
uint64_t address, int size, int64_t value, void *user_data)
{
uint32_t esp;
uc_reg_read(handle, UC_X86_REG_ESP, &esp);
switch(type) {
default:
// return false to indicate we want to stop emulation
return false;
case UC_MEM_WRITE:
//if this is a push, esp has not been adjusted yet
if (esp == (address + size)) {
uint32_t upper;
upper = (esp + 0xfff) & ~0xfff;
printf(">>> Stack appears to be missing at 0x%"PRIx64 ", allocating now\n", address);
// map this memory in with 2MB in size
uc_mem_map_ex(handle, upper - 0x8000, 0x8000, UC_PROT_READ | UC_PROT_WRITE);
// return true to indicate we want to continue
return true;
}
printf(">>> Missing memory is being WRITTEN at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n",
address, size, value);
return false;
case UC_MEM_WRITE_RO:
printf(">>> RO memory is being WRITTEN at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n",
address, size, value);
return false;
}
}
#define STACK 0x500000
#define STACK_SIZE 0x5000
int main(int argc, char **argv, char **envp) {
uch handle, trace1, trace2;
uc_err err;
uint8_t bytes[8];
uint32_t esp;
int result;
int map_stack = 0;
if (argc == 2 && strcmp(argv[1], "--map-stack") == 0) {
map_stack = 1;
}
printf("Memory mapping test\n");
// Initialize emulator in X86-32bit mode
err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle);
if (err) {
printf("Failed on uc_open() with error returned: %u\n", err);
return 1;
}
uc_mem_map(handle, 0x100000, 0x1000);
uc_mem_map(handle, 0x200000, 0x2000);
uc_mem_map(handle, 0x300000, 0x3000);
uc_mem_map_ex(handle, 0x400000, 0x4000, UC_PROT_READ);
if (map_stack) {
printf("Pre-mapping stack\n");
uc_mem_map_ex(handle, STACK, STACK_SIZE, UC_PROT_READ | UC_PROT_WRITE);
}
else {
printf("Mapping stack on first invalid memory access\n");
}
esp = STACK + STACK_SIZE;
uc_reg_write(handle, UC_X86_REG_ESP, &esp);
// write machine code to be emulated to memory
if (uc_mem_write(handle, 0x400000, PROGRAM, sizeof(PROGRAM))) {
printf("Failed to write emulation code to memory, quit!\n");
return 2;
}
else {
printf("Allowed to write to read only memory via uc_mem_write\n");
}
//uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)0x400000, (uint64_t)0x400fff);
// intercept invalid memory events
uc_hook_add(handle, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL);
// emulate machine code in infinite time
printf("BEGIN execution - 1\n");
err = uc_emu_start(handle, 0x400000, 0x400000 + sizeof(PROGRAM), 0, 10);
if (err) {
printf("Expected failue on uc_emu_start() with error returned %u: %s\n",
err, uc_strerror(err));
}
else {
printf("UNEXPECTED uc_emu_start returned UC_ERR_OK\n");
}
printf("END execution - 1\n");
// emulate machine code in infinite time
printf("BEGIN execution - 2\n");
uint32_t eax = 0x40002C;
uc_reg_write(handle, UC_X86_REG_EAX, &eax);
err = uc_emu_start(handle, 0x400015, 0x400000 + sizeof(PROGRAM), 0, 2);
if (err) {
printf("Expected failure on uc_emu_start() with error returned %u: %s\n",
err, uc_strerror(err));
}
else {
printf("UNEXPECTED uc_emu_start returned UC_ERR_OK\n");
}
printf("END execution - 2\n");
printf("Verifying content at 0x400025 is unchanged\n");
if (!uc_mem_read(handle, 0x400025, bytes, 4)) {
printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", (uint32_t)0x400025, *(uint32_t*) bytes);
if (0x41414141 != *(uint32_t*) bytes) {
printf("ERROR content in read only memory changed\n");
}
else {
printf("SUCCESS content in read only memory unchanged\n");
}
}
else {
printf(">>> Failed to read 4 bytes from [0x%x]\n", (uint32_t)(esp - 4));
return 4;
}
printf("Verifying content at 0x40002C is unchanged\n");
if (!uc_mem_read(handle, 0x40002C, bytes, 4)) {
printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", (uint32_t)0x40002C, *(uint32_t*) bytes);
if (0x42424242 != *(uint32_t*) bytes) {
printf("ERROR content in read only memory changed\n");
}
else {
printf("SUCCESS content in read only memory unchanged\n");
}
}
else {
printf(">>> Failed to read 4 bytes from [0x%x]\n", (uint32_t)(esp - 4));
return 4;
}
printf("Verifying content at bottom of stack is readable and correct\n");
if (!uc_mem_read(handle, esp - 4, bytes, 4)) {
printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", (uint32_t)(esp - 4), *(uint32_t*) bytes);
}
else {
printf(">>> Failed to read 4 bytes from [0x%x]\n", (uint32_t)(esp - 4));
return 4;
}
uc_close(&handle);
return 0;
}

0
samples/Makefile Normal file → Executable file
View File

53
uc.c
View File

@ -89,6 +89,8 @@ const char *uc_strerror(uc_err code)
return "Invalid hook type (UC_ERR_HOOK)";
case UC_ERR_MAP:
return "Invalid memory mapping (UC_ERR_MAP)";
case UC_ERR_MEM_WRITE_RO:
return "Invalid memory write (UC_ERR_MEM_WRITE_RO)";
}
}
@ -351,19 +353,32 @@ uc_err uc_mem_read(uch handle, uint64_t address, uint8_t *bytes, size_t size)
return UC_ERR_OK;
}
UNICORN_EXPORT
uc_err uc_mem_write(uch handle, uint64_t address, const uint8_t *bytes, size_t size)
{
struct uc_struct *uc = (struct uc_struct *)(uintptr_t)handle;
uint32_t operms;
if (handle == 0)
// invalid handle
return UC_ERR_UCH;
MemoryRegion *mr = memory_mapping(uc, address);
if (mr == NULL)
return UC_ERR_MEM_WRITE;
operms = mr->perms;
if (!(operms & UC_PROT_WRITE)) //write protected
//but this is not the program accessing memory, so temporarily mark writable
uc->readonly_mem(mr, false);
if (uc->write_mem(&uc->as, address, bytes, size) == false)
return UC_ERR_MEM_WRITE;
if (!(operms & UC_PROT_WRITE)) //write protected
//now write protect it again
uc->readonly_mem(mr, true);
return UC_ERR_OK;
}
@ -529,9 +544,9 @@ static uc_err _hook_mem_access(uch handle, uc_mem_type type,
}
UNICORN_EXPORT
uc_err uc_mem_map(uch handle, uint64_t address, size_t size)
uc_err uc_mem_map_ex(uch handle, uint64_t address, size_t size, uint32_t perms)
{
MemoryBlock *blocks;
MemoryRegion **regions;
struct uc_struct* uc = (struct uc_struct *)handle;
if (handle == 0)
@ -550,34 +565,41 @@ uc_err uc_mem_map(uch handle, uint64_t address, size_t size)
if ((size & (4*1024 - 1)) != 0)
return UC_ERR_MAP;
// check for only valid permissions
if ((perms & ~(UC_PROT_READ | UC_PROT_WRITE)) != 0)
return UC_ERR_MAP;
if ((uc->mapped_block_count & (MEM_BLOCK_INCR - 1)) == 0) { //time to grow
blocks = realloc(uc->mapped_blocks, sizeof(MemoryBlock) * (uc->mapped_block_count + MEM_BLOCK_INCR));
if (blocks == NULL) {
regions = (MemoryRegion**)realloc(uc->mapped_blocks, sizeof(MemoryRegion*) * (uc->mapped_block_count + MEM_BLOCK_INCR));
if (regions == NULL) {
return UC_ERR_OOM;
}
uc->mapped_blocks = blocks;
uc->mapped_blocks = regions;
}
uc->mapped_blocks[uc->mapped_block_count].begin = address;
uc->mapped_blocks[uc->mapped_block_count].end = address + size;
//TODO extend uc_mem_map to accept permissions, figure out how to pass this down to qemu
uc->mapped_blocks[uc->mapped_block_count].perms = UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC;
uc->memory_map(uc, address, size);
uc->mapped_blocks[uc->mapped_block_count] = uc->memory_map(uc, address, size, perms);
uc->mapped_block_count++;
return UC_ERR_OK;
}
bool memory_mapping(struct uc_struct* uc, uint64_t address)
UNICORN_EXPORT
uc_err uc_mem_map(uch handle, uint64_t address, size_t size)
{
//old api, maps RW by default
return uc_mem_map_ex(handle, address, size, UC_PROT_READ | UC_PROT_WRITE);
}
MemoryRegion *memory_mapping(struct uc_struct* uc, uint64_t address)
{
unsigned int i;
for(i = 0; i < uc->mapped_block_count; i++) {
if (address >= uc->mapped_blocks[i].begin && address < uc->mapped_blocks[i].end)
return true;
if (address >= uc->mapped_blocks[i]->addr && address < uc->mapped_blocks[i]->end)
return uc->mapped_blocks[i];
}
// not found
return false;
return NULL;
}
static uc_err _hook_mem_invalid(struct uc_struct* uc, uc_cb_eventmem_t callback,
@ -744,4 +766,3 @@ uc_err uc_hook_del(uch handle, uch *h2)
return hook_del(handle, h2);
}