Merge remote-tracking branch 'upstream/master' into change-handle-based-api

This commit is contained in:
Jonathon Reinhart
2015-08-30 00:02:33 -04:00
84 changed files with 5283 additions and 1274 deletions

133
uc.c
View File

@ -31,11 +31,6 @@
#include "qemu/include/hw/boards.h"
// TODO
static uint64_t map_begin[32], map_end[32];
static int map_count = 0;
UNICORN_EXPORT
unsigned int uc_version(unsigned int *major, unsigned int *minor)
{
@ -85,6 +80,10 @@ 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_NW:
return "Write to non-writable (UC_ERR_MEM_WRITE_NW)";
case UC_ERR_MEM_READ_NR:
return "Read from non-readable (UC_ERR_MEM_READ_NR)";
}
}
@ -269,6 +268,8 @@ uc_err uc_close(struct uc_struct *uc)
uc->root->free(uc->root);
free(uc->hook_callbacks);
free(uc->mapped_blocks);
// finally, free uc itself.
memset(uc, 0, sizeof(*uc));
@ -302,23 +303,90 @@ uc_err uc_reg_write(struct uc_struct *uc, int regid, const void *value)
}
UNICORN_EXPORT
uc_err uc_mem_read(struct uc_struct *uc, uint64_t address, uint8_t *bytes, size_t size)
// check if a memory area is mapped
// this is complicated because an area can overlap adjacent blocks
static bool check_mem_area(struct uc_struct *uc, uint64_t address, size_t size)
{
if (uc->read_mem(&uc->as, address, bytes, size) == false)
return UC_ERR_MEM_READ;
size_t count = 0, len;
return UC_ERR_OK;
while(count < size) {
MemoryRegion *mr = memory_mapping(uc, address);
if (mr) {
len = MIN(size - count, mr->end - address);
count += len;
address += len;
} else // this address is not mapped in yet
break;
}
return (count == size);
}
UNICORN_EXPORT
uc_err uc_mem_read(struct uc_struct *uc, uint64_t address, uint8_t *bytes, size_t size)
{
if (!check_mem_area(uc, address, size))
return UC_ERR_MEM_READ;
size_t count = 0, len;
// memory area can overlap adjacent memory blocks
while(count < size) {
MemoryRegion *mr = memory_mapping(uc, address);
if (mr) {
len = MIN(size - count, mr->end - address);
if (uc->read_mem(&uc->as, address, bytes, len) == false)
break;
count += len;
address += len;
bytes += len;
} else // this address is not mapped in yet
break;
}
if (count == size)
return UC_ERR_OK;
else
return UC_ERR_MEM_READ;
}
UNICORN_EXPORT
uc_err uc_mem_write(struct uc_struct *uc, uint64_t address, const uint8_t *bytes, size_t size)
{
if (uc->write_mem(&uc->as, address, bytes, size) == false)
if (!check_mem_area(uc, address, size))
return UC_ERR_MEM_WRITE;
return UC_ERR_OK;
size_t count = 0, len;
// memory area can overlap adjacent memory blocks
while(count < size) {
MemoryRegion *mr = memory_mapping(uc, address);
if (mr) {
uint32_t 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);
len = MIN(size - count, mr->end - address);
if (uc->write_mem(&uc->as, address, bytes, len) == false)
break;
if (!(operms & UC_PROT_WRITE)) // write protected
// now write protect it again
uc->readonly_mem(mr, true);
count += len;
address += len;
bytes += len;
} else // this address is not mapped in yet
break;
}
if (count == size)
return UC_ERR_OK;
else
return UC_ERR_MEM_WRITE;
}
#define TIMEOUT_STEP 2 // microseconds
@ -358,6 +426,7 @@ uc_err uc_emu_start(struct uc_struct* uc, uint64_t begin, uint64_t until, uint64
uc->stop_request = false;
uc->invalid_error = UC_ERR_OK;
uc->block_full = false;
uc->emulation_done = false;
switch(uc->arch) {
default:
@ -423,6 +492,11 @@ uc_err uc_emu_start(struct uc_struct* uc, uint64_t begin, uint64_t until, uint64
// emulation is done
uc->emulation_done = true;
if (timeout) {
// wait for the timer to finish
qemu_thread_join(&uc->timer);
}
return uc->invalid_error;
}
@ -430,6 +504,9 @@ uc_err uc_emu_start(struct uc_struct* uc, uint64_t begin, uint64_t until, uint64
UNICORN_EXPORT
uc_err uc_emu_stop(struct uc_struct *uc)
{
if (uc->emulation_done)
return UC_ERR_OK;
uc->stop_request = true;
// exit the current TB
cpu_exit(uc->current_cpu);
@ -469,8 +546,10 @@ static uc_err _hook_mem_access(struct uc_struct *uc, uc_mem_type type,
}
UNICORN_EXPORT
uc_err uc_mem_map(struct uc_struct *uc, uint64_t address, size_t size)
uc_err uc_mem_map(struct uc_struct *uc, uint64_t address, size_t size, uint32_t perms)
{
MemoryRegion **regions;
if (size == 0)
// invalid memory mapping
return UC_ERR_MAP;
@ -483,25 +562,34 @@ uc_err uc_mem_map(struct uc_struct *uc, uint64_t address, size_t size)
if ((size & (4*1024 - 1)) != 0)
return UC_ERR_MAP;
map_begin[map_count] = address;
map_end[map_count] = size + map_begin[map_count];
uc->memory_map(uc, map_begin[map_count], size);
map_count++;
// 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
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 = regions;
}
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(uint64_t address)
MemoryRegion *memory_mapping(struct uc_struct* uc, uint64_t address)
{
unsigned int i;
for(i = 0; i < map_count; i++) {
if (address >= map_begin[i] && address <= map_end[i])
return true;
for(i = 0; i < uc->mapped_block_count; i++) {
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,
@ -653,4 +741,3 @@ uc_err uc_hook_del(struct uc_struct *uc, uc_hook_h hh)
{
return hook_del(uc, hh);
}