Merge remote-tracking branch 'h33p/master' into dev

This is for binary search optmization on memory blocks.
This commit is contained in:
lazymio 2021-10-26 11:23:42 +02:00
commit 489b072fc3
No known key found for this signature in database
GPG Key ID: DFF27E34A47CB873
2 changed files with 72 additions and 23 deletions

View File

@ -1,5 +1,25 @@
#include "unicorn_test.h" #include "unicorn_test.h"
static void test_map_correct() {
uc_engine* uc;
OK(uc_open (UC_ARCH_X86, UC_MODE_64, &uc));
OK(uc_mem_map (uc, 0x40000, 0x1000 * 16, UC_PROT_ALL));
OK(uc_close(uc));
}
static void test_map_wrapping() {
uc_engine* uc;
OK(uc_open (UC_ARCH_X86, UC_MODE_64, &uc));
uc_assert_err(UC_ERR_ARG, uc_mem_map (uc, (~0ll - 0x4000) & ~0xfff, 0x8000, UC_PROT_ALL));
OK(uc_close(uc));
}
TEST_LIST = { TEST_LIST = {
{ "test_map_correct", test_map_correct },
{ "test_map_wrapping", test_map_wrapping },
{ NULL, NULL } { NULL, NULL }
}; };

73
uc.c
View File

@ -765,26 +765,52 @@ uc_err uc_emu_stop(uc_engine *uc)
return UC_ERR_OK; return UC_ERR_OK;
} }
// return target index where a memory region at the address exists, or could be inserted
//
// address either is inside the mapping at the returned index, or is in free space before
// the next mapping.
//
// if there is overlap, between regions, ending address will be higher than the starting
// address of the mapping at returned index
static int bsearch_mapped_blocks(const uc_engine *uc, uint64_t address) {
int left, right, mid;
MemoryRegion *mapping;
left = 0;
right = uc->mapped_block_count;
while (left < right) {
mid = left + (right - left) / 2;
mapping = uc->mapped_blocks[mid];
if (mapping->end - 1 < address) {
left = mid + 1;
} else if (mapping->addr > address) {
right = mid;
} else {
return mid;
}
}
return left;
}
// find if a memory range overlaps with existing mapped regions // find if a memory range overlaps with existing mapped regions
static bool memory_overlap(struct uc_struct *uc, uint64_t begin, size_t size) static bool memory_overlap(struct uc_struct *uc, uint64_t begin, size_t size)
{ {
unsigned int i; unsigned int i;
uint64_t end = begin + size - 1; uint64_t end = begin + size - 1;
for(i = 0; i < uc->mapped_block_count; i++) { i = bsearch_mapped_blocks(uc, begin);
// begin address falls inside this region?
if (begin >= uc->mapped_blocks[i]->addr && begin <= uc->mapped_blocks[i]->end - 1) { // is this the highest region with no possible overlap?
return true; if (i >= uc->mapped_block_count)
} return false;
// end address falls inside this region?
if (end >= uc->mapped_blocks[i]->addr && end <= uc->mapped_blocks[i]->end - 1) { // end address overlaps this region?
return true; if (end >= uc->mapped_blocks[i]->addr)
} return true;
// this region falls totally inside this range?
if (begin < uc->mapped_blocks[i]->addr && end > uc->mapped_blocks[i]->end - 1) {
return true;
}
}
// not found // not found
return false; return false;
@ -794,6 +820,7 @@ static bool memory_overlap(struct uc_struct *uc, uint64_t begin, size_t size)
static uc_err mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms, MemoryRegion *block) static uc_err mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms, MemoryRegion *block)
{ {
MemoryRegion **regions; MemoryRegion **regions;
int pos;
if (block == NULL) { if (block == NULL) {
return UC_ERR_NOMEM; return UC_ERR_NOMEM;
@ -808,7 +835,12 @@ static uc_err mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t per
uc->mapped_blocks = regions; uc->mapped_blocks = regions;
} }
uc->mapped_blocks[uc->mapped_block_count] = block; pos = bsearch_mapped_blocks(uc, block->addr);
// shift the array right to give space for the new pointer
memmove(&uc->mapped_blocks[pos + 1], &uc->mapped_blocks[pos], sizeof(MemoryRegion*) * (uc->mapped_block_count - pos));
uc->mapped_blocks[pos] = block;
uc->mapped_block_count++; uc->mapped_block_count++;
return UC_ERR_OK; return UC_ERR_OK;
@ -1225,13 +1257,10 @@ MemoryRegion *memory_mapping(struct uc_struct* uc, uint64_t address)
return uc->mapped_blocks[i]; return uc->mapped_blocks[i];
} }
for(i = 0; i < uc->mapped_block_count; i++) { i = bsearch_mapped_blocks(uc, address);
if (address >= uc->mapped_blocks[i]->addr && address <= uc->mapped_blocks[i]->end - 1) {
// cache this index for the next query if (i < uc->mapped_block_count && address >= uc->mapped_blocks[i]->addr && address <= uc->mapped_blocks[i]->end - 1)
uc->mapped_block_cache_index = i; return uc->mapped_blocks[i];
return uc->mapped_blocks[i];
}
}
// not found // not found
return NULL; return NULL;