Skip to content

Commit a977b1e

Browse files
committed
add uc_mem_read_virtual
New api to read from a vaddr. When using the MMU it's useful to direct read from virtual addresses.
1 parent 7fd2aa4 commit a977b1e

File tree

4 files changed

+99
-0
lines changed

4 files changed

+99
-0
lines changed

include/uc_priv.h

+4
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ typedef bool (*uc_write_mem_t)(AddressSpace *as, hwaddr addr,
8080
typedef bool (*uc_read_mem_t)(AddressSpace *as, hwaddr addr, uint8_t *buf,
8181
int len);
8282

83+
typedef bool (*uc_read_mem_virtual_t)(struct uc_struct *uc, vaddr addr, uc_prot prot, uint8_t *buf,
84+
int len);
85+
8386
typedef MemoryRegion *(*uc_mem_cow_t)(struct uc_struct *uc,
8487
MemoryRegion *current, hwaddr begin,
8588
size_t size);
@@ -276,6 +279,7 @@ struct uc_struct {
276279

277280
uc_write_mem_t write_mem;
278281
uc_read_mem_t read_mem;
282+
uc_read_mem_virtual_t read_mem_virtual;
279283
uc_mem_cow_t memory_cow;
280284
uc_args_void_t release; // release resource when uc_close()
281285
uc_args_uc_u64_t set_pc; // set PC for tracecode

include/unicorn/unicorn.h

+20
Original file line numberDiff line numberDiff line change
@@ -933,6 +933,26 @@ uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *bytes,
933933
UNICORN_EXPORT
934934
uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *bytes, size_t size);
935935

936+
/*
937+
Read a range of bytes in memory after mmu translation.
938+
939+
@uc: handle returned by uc_open()
940+
@address: starting virtual memory address of bytes to get.
941+
@prot: The access type for the tlb lookup
942+
@bytes: pointer to a variable containing data copied from memory.
943+
@size: size of memory to read.
944+
945+
NOTE: @bytes must be big enough to contain @size bytes.
946+
947+
This function will translate the address with the mmu. Therefore all
948+
pages needs to be memory mapped with the proper access rights.
949+
950+
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
951+
for detailed error).
952+
*/
953+
UNICORN_EXPORT
954+
uc_err uc_mem_read_virtual(uc_engine *uc, uint64_t address, uc_prot prot, void *bytes, size_t size);
955+
936956
/*
937957
Emulate machine code in a specific duration of time.
938958

qemu/unicorn_common.h

+36
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "tcg/tcg.h"
66
#include "qemu-common.h"
77
#include "exec/memory.h"
8+
#include "exec/cpu_ldst.h"
89

910
// This header define common patterns/codes that will be included in all arch-sepcific
1011
// codes for unicorns purposes.
@@ -28,6 +29,40 @@ static inline bool cpu_physical_mem_write(AddressSpace *as, hwaddr addr,
2829
return cpu_physical_memory_rw(as, addr, (void *)buf, len, 1);
2930
}
3031

32+
static bool cpu_virtual_mem_read(struct uc_struct *uc, vaddr addr, uc_prot prot, uint8_t *buf, int len)
33+
{
34+
MMUAccessType access_type;
35+
void *hostptr;
36+
int mmu_idx = cpu_mmu_index(uc->cpu->env_ptr, false);
37+
38+
/*
39+
* Only page aligned access is allowed,
40+
* because tlb_fill() might change the mappings
41+
*/
42+
assert((addr & TARGET_PAGE_MASK) == ((addr + len) & TARGET_PAGE_MASK));
43+
44+
switch(prot) {
45+
case UC_PROT_READ:
46+
access_type = MMU_DATA_LOAD;
47+
break;
48+
case UC_PROT_WRITE:
49+
access_type = MMU_DATA_STORE;
50+
break;
51+
case UC_PROT_EXEC:
52+
access_type = MMU_INST_FETCH;
53+
break;
54+
default:
55+
return false;
56+
}
57+
58+
hostptr = tlb_vaddr_to_host(uc->cpu->env_ptr, addr, access_type, mmu_idx);
59+
if (!hostptr) {
60+
return false;
61+
}
62+
memcpy(buf, hostptr, len);
63+
return true;
64+
}
65+
3166
void tb_cleanup(struct uc_struct *uc);
3267
void free_code_gen_buffer(struct uc_struct *uc);
3368

@@ -126,6 +161,7 @@ static inline void uc_common_init(struct uc_struct* uc)
126161
{
127162
uc->write_mem = cpu_physical_mem_write;
128163
uc->read_mem = cpu_physical_mem_read;
164+
uc->read_mem_virtual = cpu_virtual_mem_read;
129165
uc->tcg_exec_init = tcg_exec_init;
130166
uc->cpu_exec_init_all = cpu_exec_init_all;
131167
uc->vm_start = vm_start;

uc.c

+39
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,45 @@ static bool check_mem_area(uc_engine *uc, uint64_t address, size_t size)
773773
return (count == size);
774774
}
775775

776+
UNICORN_EXPORT
777+
uc_err uc_mem_read_virtual(uc_engine *uc, uint64_t address, uc_prot prot, void *_bytes, size_t size)
778+
{
779+
size_t count = 0, len;
780+
uint8_t *bytes = _bytes;
781+
uint64_t align;
782+
uint64_t pagesize;
783+
784+
UC_INIT(uc);
785+
786+
// qemu cpu_physical_memory_rw() size is an int
787+
if (size > INT_MAX) {
788+
restore_jit_state(uc);
789+
return UC_ERR_ARG;
790+
}
791+
792+
if (!(UC_PROT_READ == prot || UC_PROT_WRITE == prot || UC_PROT_EXEC == prot)) {
793+
restore_jit_state(uc);
794+
return UC_ERR_ARG;
795+
}
796+
797+
while (count < size) {
798+
align = uc->target_page_align;
799+
pagesize = uc->target_page_size;
800+
len = MIN(size - count, (address & ~align) + pagesize - address);
801+
if (!uc->read_mem_virtual(uc, address, prot, bytes, len)) {
802+
restore_jit_state(uc);
803+
return UC_ERR_READ_UNMAPPED;
804+
}
805+
bytes += len;
806+
address += len;
807+
count += len;
808+
size -= len;
809+
}
810+
assert(count == size);
811+
restore_jit_state(uc);
812+
return UC_ERR_OK;
813+
}
814+
776815
UNICORN_EXPORT
777816
uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *_bytes, size_t size)
778817
{

0 commit comments

Comments
 (0)