2021-10-03 17:14:44 +03:00
|
|
|
/* Unicorn Emulator Engine */
|
|
|
|
|
|
|
|
/* Sample code to demonstrate how to emulate RISCV code */
|
|
|
|
|
|
|
|
#include <unicorn/unicorn.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
// code to be emulated
|
|
|
|
#if 0
|
|
|
|
$ cstool riscv64 1305100093850502
|
|
|
|
0 13 05 10 00 addi a0, zero, 1
|
|
|
|
4 93 85 05 02 addi a1, a1, 0x20
|
|
|
|
#endif
|
2023-05-11 22:42:20 +03:00
|
|
|
// #define RISCV_CODE "\x13\x05\x10\x00\x93\x85\x05\x02\x93\x85\x05\x02"
|
2021-10-03 17:14:44 +03:00
|
|
|
#define RISCV_CODE "\x13\x05\x10\x00\x93\x85\x05\x02"
|
|
|
|
|
|
|
|
// memory address where emulation starts
|
|
|
|
#define ADDRESS 0x10000
|
|
|
|
|
2021-10-29 13:44:49 +03:00
|
|
|
static void hook_block(uc_engine *uc, uint64_t address, uint32_t size,
|
|
|
|
void *user_data)
|
2021-10-03 17:14:44 +03:00
|
|
|
{
|
2021-10-29 13:44:49 +03:00
|
|
|
printf(">>> Tracing basic block at 0x%" PRIx64 ", block size = 0x%x\n",
|
|
|
|
address, size);
|
2021-10-03 17:14:44 +03:00
|
|
|
}
|
|
|
|
|
2021-10-29 13:44:49 +03:00
|
|
|
static void hook_code(uc_engine *uc, uint64_t address, uint32_t size,
|
|
|
|
void *user_data)
|
2021-10-03 17:14:44 +03:00
|
|
|
{
|
2021-10-29 13:44:49 +03:00
|
|
|
printf(">>> Tracing instruction at 0x%" PRIx64
|
|
|
|
", instruction size = 0x%x\n",
|
|
|
|
address, size);
|
2021-10-03 17:14:44 +03:00
|
|
|
}
|
|
|
|
|
2021-10-29 13:44:49 +03:00
|
|
|
static void hook_code3(uc_engine *uc, uint64_t address, uint32_t size,
|
|
|
|
void *user_data)
|
2021-10-03 17:14:44 +03:00
|
|
|
{
|
2021-10-29 13:44:49 +03:00
|
|
|
printf(">>> Tracing instruction at 0x%" PRIx64
|
|
|
|
", instruction size = 0x%x\n",
|
|
|
|
address, size);
|
2021-10-03 17:14:44 +03:00
|
|
|
if (address == ADDRESS) {
|
|
|
|
printf("stop emulation\n");
|
|
|
|
uc_emu_stop(uc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_riscv(void)
|
|
|
|
{
|
|
|
|
uc_engine *uc;
|
|
|
|
uc_hook trace1, trace2;
|
|
|
|
uc_err err;
|
|
|
|
|
|
|
|
uint32_t a0 = 0x1234;
|
|
|
|
uint32_t a1 = 0x7890;
|
|
|
|
|
|
|
|
printf("Emulate RISCV code\n");
|
|
|
|
|
|
|
|
// Initialize emulator in RISCV64 mode
|
|
|
|
err = uc_open(UC_ARCH_RISCV, UC_MODE_RISCV32, &uc);
|
|
|
|
if (err) {
|
2021-10-29 13:44:49 +03:00
|
|
|
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
|
|
|
uc_strerror(err));
|
2021-10-03 17:14:44 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// map 2MB memory for this emulation
|
|
|
|
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
|
|
|
|
|
|
|
// write machine code to be emulated to memory
|
|
|
|
uc_mem_write(uc, ADDRESS, RISCV_CODE, sizeof(RISCV_CODE) - 1);
|
|
|
|
|
|
|
|
// initialize machine registers
|
|
|
|
uc_reg_write(uc, UC_RISCV_REG_A0, &a0);
|
|
|
|
uc_reg_write(uc, UC_RISCV_REG_A1, &a1);
|
|
|
|
|
|
|
|
// tracing all basic blocks with customized callback
|
|
|
|
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
|
|
|
|
|
|
|
// tracing all instruction
|
|
|
|
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0);
|
|
|
|
|
|
|
|
// emulate machine code in infinite time (last param = 0), or when
|
|
|
|
// finishing all the code.
|
|
|
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(RISCV_CODE) - 1, 0, 0);
|
|
|
|
if (err) {
|
|
|
|
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
|
|
|
}
|
|
|
|
|
|
|
|
// now print out some registers
|
|
|
|
printf(">>> Emulation done. Below is the CPU context\n");
|
|
|
|
|
|
|
|
uc_reg_read(uc, UC_RISCV_REG_A0, &a0);
|
|
|
|
uc_reg_read(uc, UC_RISCV_REG_A1, &a1);
|
|
|
|
|
|
|
|
printf(">>> A0 = 0x%x\n", a0);
|
|
|
|
printf(">>> A1 = 0x%x\n", a1);
|
|
|
|
|
|
|
|
uc_close(uc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_riscv2(void)
|
|
|
|
{
|
|
|
|
uc_engine *uc;
|
|
|
|
uc_hook trace1, trace2;
|
|
|
|
uc_err err;
|
|
|
|
|
|
|
|
uint32_t a0 = 0x1234;
|
|
|
|
uint32_t a1 = 0x7890;
|
|
|
|
|
|
|
|
printf("Emulate RISCV code: split emulation\n");
|
|
|
|
|
|
|
|
// Initialize emulator in RISCV64 mode
|
|
|
|
err = uc_open(UC_ARCH_RISCV, UC_MODE_RISCV32, &uc);
|
|
|
|
if (err) {
|
2021-10-29 13:44:49 +03:00
|
|
|
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
|
|
|
uc_strerror(err));
|
2021-10-03 17:14:44 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// map 2MB memory for this emulation
|
|
|
|
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
|
|
|
|
|
|
|
// write machine code to be emulated to memory
|
|
|
|
uc_mem_write(uc, ADDRESS, RISCV_CODE, sizeof(RISCV_CODE) - 1);
|
|
|
|
|
|
|
|
// initialize machine registers
|
|
|
|
uc_reg_write(uc, UC_RISCV_REG_A0, &a0);
|
|
|
|
uc_reg_write(uc, UC_RISCV_REG_A1, &a1);
|
|
|
|
|
|
|
|
// tracing all basic blocks with customized callback
|
|
|
|
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
|
|
|
|
|
|
|
// tracing all instruction
|
|
|
|
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0);
|
|
|
|
|
|
|
|
// emulate 1 instruction
|
|
|
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + 4, 0, 0);
|
|
|
|
if (err) {
|
|
|
|
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
|
|
|
}
|
|
|
|
|
|
|
|
uc_reg_read(uc, UC_RISCV_REG_A0, &a0);
|
|
|
|
uc_reg_read(uc, UC_RISCV_REG_A1, &a1);
|
|
|
|
|
|
|
|
printf(">>> A0 = 0x%x\n", a0);
|
|
|
|
printf(">>> A1 = 0x%x\n", a1);
|
|
|
|
|
|
|
|
// emulate one more instruction
|
|
|
|
err = uc_emu_start(uc, ADDRESS + 4, ADDRESS + 8, 0, 0);
|
|
|
|
if (err) {
|
|
|
|
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
|
|
|
}
|
|
|
|
|
|
|
|
// now print out some registers
|
|
|
|
printf(">>> Emulation done. Below is the CPU context\n");
|
|
|
|
|
|
|
|
uc_reg_read(uc, UC_RISCV_REG_A0, &a0);
|
|
|
|
uc_reg_read(uc, UC_RISCV_REG_A1, &a1);
|
|
|
|
|
|
|
|
printf(">>> A0 = 0x%x\n", a0);
|
|
|
|
printf(">>> A1 = 0x%x\n", a1);
|
|
|
|
|
|
|
|
uc_close(uc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_riscv3(void)
|
|
|
|
{
|
|
|
|
uc_engine *uc;
|
|
|
|
uc_hook trace1, trace2;
|
|
|
|
uc_err err;
|
|
|
|
|
|
|
|
uint32_t a0 = 0x1234;
|
|
|
|
uint32_t a1 = 0x7890;
|
|
|
|
|
|
|
|
printf("Emulate RISCV code: early stop\n");
|
|
|
|
|
|
|
|
// Initialize emulator in RISCV64 mode
|
|
|
|
err = uc_open(UC_ARCH_RISCV, UC_MODE_RISCV32, &uc);
|
|
|
|
if (err) {
|
2021-10-29 13:44:49 +03:00
|
|
|
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
|
|
|
uc_strerror(err));
|
2021-10-03 17:14:44 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// map 2MB memory for this emulation
|
|
|
|
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
|
|
|
|
|
|
|
// write machine code to be emulated to memory
|
|
|
|
uc_mem_write(uc, ADDRESS, RISCV_CODE, sizeof(RISCV_CODE) - 1);
|
|
|
|
|
|
|
|
// initialize machine registers
|
|
|
|
uc_reg_write(uc, UC_RISCV_REG_A0, &a0);
|
|
|
|
uc_reg_write(uc, UC_RISCV_REG_A1, &a1);
|
|
|
|
|
|
|
|
// tracing all basic blocks with customized callback
|
|
|
|
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
|
|
|
|
|
|
|
// tracing all instruction
|
|
|
|
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code3, NULL, 1, 0);
|
|
|
|
|
|
|
|
// emulate machine code in infinite time (last param = 0), or when
|
|
|
|
// finishing all the code.
|
|
|
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(RISCV_CODE) - 1, 0, 0);
|
|
|
|
if (err) {
|
|
|
|
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
|
|
|
}
|
|
|
|
|
|
|
|
// now print out some registers
|
|
|
|
printf(">>> Emulation done. Below is the CPU context\n");
|
|
|
|
|
|
|
|
uc_reg_read(uc, UC_RISCV_REG_A0, &a0);
|
|
|
|
uc_reg_read(uc, UC_RISCV_REG_A1, &a1);
|
|
|
|
|
|
|
|
printf(">>> A0 = 0x%x\n", a0);
|
|
|
|
printf(">>> A1 = 0x%x\n", a1);
|
|
|
|
|
|
|
|
uc_close(uc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_riscv_step(void)
|
|
|
|
{
|
|
|
|
uc_engine *uc;
|
|
|
|
uc_hook trace1, trace2;
|
|
|
|
uc_err err;
|
|
|
|
|
|
|
|
uint32_t a0 = 0x1234;
|
|
|
|
uint32_t a1 = 0x7890;
|
|
|
|
uint32_t pc = 0x0000;
|
|
|
|
|
|
|
|
printf("Emulate RISCV code: step\n");
|
|
|
|
|
|
|
|
// Initialize emulator in RISCV64 mode
|
|
|
|
err = uc_open(UC_ARCH_RISCV, UC_MODE_RISCV32, &uc);
|
|
|
|
if (err) {
|
2021-10-29 13:44:49 +03:00
|
|
|
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
|
|
|
uc_strerror(err));
|
2021-10-03 17:14:44 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// map 2MB memory for this emulation
|
|
|
|
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
|
|
|
|
|
|
|
// write machine code to be emulated to memory
|
|
|
|
uc_mem_write(uc, ADDRESS, RISCV_CODE, sizeof(RISCV_CODE) - 1);
|
|
|
|
|
|
|
|
// initialize machine registers
|
|
|
|
uc_reg_write(uc, UC_RISCV_REG_A0, &a0);
|
|
|
|
uc_reg_write(uc, UC_RISCV_REG_A1, &a1);
|
|
|
|
|
|
|
|
// tracing all basic blocks with customized callback
|
|
|
|
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
|
|
|
|
|
|
|
// tracing all instruction
|
|
|
|
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0);
|
|
|
|
|
|
|
|
// emulate 1 instruction
|
|
|
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + 12, 0, 1);
|
|
|
|
if (err) {
|
|
|
|
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
|
|
|
}
|
|
|
|
|
|
|
|
uc_reg_read(uc, UC_RISCV_REG_A0, &a0);
|
|
|
|
uc_reg_read(uc, UC_RISCV_REG_A1, &a1);
|
|
|
|
uc_reg_read(uc, UC_RISCV_REG_PC, &pc);
|
|
|
|
|
|
|
|
printf(">>> A0 = 0x%x\n", a0);
|
|
|
|
printf(">>> A1 = 0x%x\n", a1);
|
|
|
|
|
|
|
|
if (pc != 0x10004) {
|
|
|
|
printf("Error after step: PC is: 0x%x, expected was 0x10004\n", pc);
|
|
|
|
}
|
|
|
|
|
|
|
|
// emulate one more instruction
|
|
|
|
err = uc_emu_start(uc, ADDRESS + 4, ADDRESS + 8, 0, 0);
|
|
|
|
if (err) {
|
|
|
|
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
|
|
|
}
|
|
|
|
|
|
|
|
// now print out some registers
|
|
|
|
printf(">>> Emulation done. Below is the CPU context\n");
|
|
|
|
|
|
|
|
uc_reg_read(uc, UC_RISCV_REG_A0, &a0);
|
|
|
|
uc_reg_read(uc, UC_RISCV_REG_A1, &a1);
|
|
|
|
|
|
|
|
printf(">>> A0 = 0x%x\n", a0);
|
|
|
|
printf(">>> A1 = 0x%x\n", a1);
|
|
|
|
|
|
|
|
uc_close(uc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_riscv_timeout(void)
|
|
|
|
{
|
|
|
|
uc_engine *uc;
|
|
|
|
uc_hook trace1, trace2;
|
|
|
|
uc_err err;
|
|
|
|
|
|
|
|
uint32_t a0 = 0x1234;
|
|
|
|
uint32_t a1 = 0x7890;
|
|
|
|
uint32_t pc = 0x0000;
|
|
|
|
|
|
|
|
printf("Emulate RISCV code: timeout\n");
|
|
|
|
|
|
|
|
// Initialize emulator in RISCV64 mode
|
|
|
|
err = uc_open(UC_ARCH_RISCV, UC_MODE_RISCV32, &uc);
|
|
|
|
if (err) {
|
2021-10-29 13:44:49 +03:00
|
|
|
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
|
|
|
uc_strerror(err));
|
2021-10-03 17:14:44 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// map 2MB memory for this emulation
|
|
|
|
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
|
|
|
|
|
|
|
// write machine code to be emulated to memory
|
|
|
|
uc_mem_write(uc, ADDRESS, "\x00\x00\x00\x00\x00\x00\x00\x00", 8);
|
|
|
|
|
|
|
|
// initialize machine registers
|
|
|
|
uc_reg_write(uc, UC_RISCV_REG_A0, &a0);
|
|
|
|
uc_reg_write(uc, UC_RISCV_REG_A1, &a1);
|
|
|
|
|
|
|
|
// tracing all basic blocks with customized callback
|
|
|
|
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
|
|
|
|
|
|
|
// tracing all instruction
|
|
|
|
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0);
|
|
|
|
|
|
|
|
// emulate 1 instruction with timeout
|
|
|
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + 4, 1000, 1);
|
|
|
|
if (err) {
|
|
|
|
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
|
|
|
}
|
|
|
|
uc_reg_read(uc, UC_RISCV_REG_PC, &pc);
|
|
|
|
|
|
|
|
if (pc != 0x10000) {
|
|
|
|
printf("Error after step: PC is: 0x%x, expected was 0x10004\n", pc);
|
|
|
|
}
|
|
|
|
|
|
|
|
// emulate 1 instruction with timeout
|
|
|
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + 4, 1000, 1);
|
|
|
|
if (err) {
|
|
|
|
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
|
|
|
}
|
|
|
|
uc_reg_read(uc, UC_RISCV_REG_PC, &pc);
|
|
|
|
|
|
|
|
if (pc != 0x10000) {
|
|
|
|
printf("Error after step: PC is: 0x%x, expected was 0x10004\n", pc);
|
|
|
|
}
|
|
|
|
|
|
|
|
// now print out some registers
|
|
|
|
printf(">>> Emulation done\n");
|
|
|
|
|
|
|
|
uc_close(uc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_riscv_sd64(void)
|
|
|
|
{
|
|
|
|
uc_engine *uc;
|
|
|
|
uc_hook trace1, trace2;
|
|
|
|
uc_err err;
|
|
|
|
|
|
|
|
uint64_t reg;
|
|
|
|
|
|
|
|
/*
|
|
|
|
00813823 sd s0,16(sp)
|
|
|
|
00000013 nop
|
|
|
|
*/
|
|
|
|
#define CODE64 "\x23\x38\x81\x00\x13\x00\x00\x00"
|
|
|
|
|
|
|
|
printf("Emulate RISCV code: sd64 instruction\n");
|
|
|
|
|
|
|
|
// Initialize emulator in RISCV64 mode
|
|
|
|
err = uc_open(UC_ARCH_RISCV, UC_MODE_RISCV64, &uc);
|
|
|
|
if (err) {
|
2021-10-29 13:44:49 +03:00
|
|
|
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
|
|
|
uc_strerror(err));
|
2021-10-03 17:14:44 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// map 2MB memory for this emulation
|
|
|
|
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
|
|
|
|
|
|
|
// write machine code to be emulated to memory
|
|
|
|
uc_mem_write(uc, ADDRESS, CODE64, sizeof(CODE64) - 1);
|
|
|
|
|
|
|
|
// tracing all basic blocks with customized callback
|
|
|
|
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
|
|
|
|
|
|
|
// tracing all instruction
|
|
|
|
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0);
|
|
|
|
|
|
|
|
reg = ADDRESS + 0x100;
|
|
|
|
uc_reg_write(uc, UC_RISCV_REG_SP, ®);
|
|
|
|
|
|
|
|
reg = 0x11223344;
|
|
|
|
uc_reg_write(uc, UC_RISCV_REG_S0, ®);
|
|
|
|
|
|
|
|
// execute instruction
|
|
|
|
err = uc_emu_start(uc, 0x10000, -1, 0, 1);
|
|
|
|
if (err) {
|
|
|
|
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
|
|
|
}
|
|
|
|
|
|
|
|
// now print out some registers
|
|
|
|
printf(">>> Emulation done.\n");
|
|
|
|
|
|
|
|
uc_close(uc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool hook_memalloc(uc_engine *uc, uc_mem_type type, uint64_t address,
|
2021-10-29 13:44:49 +03:00
|
|
|
int size, int64_t value, void *user_data)
|
2021-10-03 17:14:44 +03:00
|
|
|
{
|
|
|
|
uint64_t algined_address = address & 0xFFFFFFFFFFFFF000ULL;
|
|
|
|
int aligned_size = ((int)(size / 0x1000) + 1) * 0x1000;
|
|
|
|
|
2021-10-29 13:44:49 +03:00
|
|
|
printf(">>> Allocating block at 0x%" PRIx64 " (0x%" PRIx64
|
|
|
|
"), block size = 0x%x (0x%x)\n",
|
|
|
|
address, algined_address, size, aligned_size);
|
2021-10-03 17:14:44 +03:00
|
|
|
|
|
|
|
uc_mem_map(uc, algined_address, aligned_size, UC_PROT_ALL);
|
|
|
|
|
|
|
|
// this recovers from missing memory, so we return true
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_recover_from_illegal(void)
|
|
|
|
{
|
|
|
|
uc_engine *uc;
|
|
|
|
uc_hook trace1, trace2, mem_alloc;
|
|
|
|
uc_err err;
|
|
|
|
uint64_t a0 = 0x1234;
|
|
|
|
uint64_t a1 = 0x7890;
|
|
|
|
|
|
|
|
printf("Emulate RISCV code: recover_from_illegal\n");
|
|
|
|
|
|
|
|
// Initialize emulator in RISCV64 mode
|
|
|
|
err = uc_open(UC_ARCH_RISCV, UC_MODE_RISCV64, &uc);
|
|
|
|
if (err) {
|
|
|
|
printf("Failed on uc_open() with error returned: %u\n", err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
uc_reg_write(uc, UC_RISCV_REG_A0, &a0);
|
|
|
|
uc_reg_write(uc, UC_RISCV_REG_A1, &a1);
|
|
|
|
|
|
|
|
// map 2MB memory for this emulation
|
|
|
|
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
|
|
|
|
|
|
|
// auto-allocate memory on access
|
2021-10-29 13:44:49 +03:00
|
|
|
uc_hook_add(uc, &mem_alloc, UC_HOOK_MEM_UNMAPPED, hook_memalloc, NULL, 1,
|
|
|
|
0);
|
2021-10-03 17:14:44 +03:00
|
|
|
|
|
|
|
// tracing all basic blocks with customized callback
|
|
|
|
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
|
|
|
|
|
|
|
// tracing all instruction
|
|
|
|
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0);
|
|
|
|
|
|
|
|
// write machine code to be emulated to memory
|
|
|
|
uc_mem_write(uc, ADDRESS, RISCV_CODE, sizeof(RISCV_CODE) - 1);
|
|
|
|
|
|
|
|
// emulate 1 instruction, wrong address, illegal code
|
|
|
|
err = uc_emu_start(uc, 0x1000, -1, 0, 1);
|
|
|
|
if (err != UC_ERR_INSN_INVALID) {
|
|
|
|
printf("Expected Illegal Instruction error, got: %u\n", err);
|
|
|
|
}
|
|
|
|
|
|
|
|
// emulate 1 instruction, correct address, valid code
|
|
|
|
err = uc_emu_start(uc, ADDRESS, -1, 0, 1);
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
|
|
|
}
|
|
|
|
|
|
|
|
// now print out some registers
|
|
|
|
printf(">>> Emulation done. Below is the CPU context\n");
|
|
|
|
|
|
|
|
uc_reg_read(uc, UC_RISCV_REG_A0, &a0);
|
|
|
|
uc_reg_read(uc, UC_RISCV_REG_A1, &a1);
|
|
|
|
|
2021-10-29 13:44:49 +03:00
|
|
|
printf(">>> A0 = 0x%" PRIx64 "\n", a0);
|
|
|
|
printf(">>> A1 = 0x%" PRIx64 "\n", a1);
|
2021-10-03 17:14:44 +03:00
|
|
|
|
|
|
|
uc_close(uc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_riscv_func_return(void)
|
|
|
|
{
|
|
|
|
uc_engine *uc;
|
|
|
|
uc_hook trace1, trace2;
|
|
|
|
uc_err err;
|
|
|
|
|
|
|
|
uint64_t pc = 0, ra = 0;
|
|
|
|
|
|
|
|
// 10000: 00008067 ret
|
|
|
|
// 10004: 8082 c.ret
|
|
|
|
// 10006: 0001 nop
|
|
|
|
// 10008: 0001 nop
|
|
|
|
|
|
|
|
#define CODE "\x67\x80\x00\x00\x82\x80\x01\x00\x01\x00"
|
|
|
|
|
|
|
|
printf("Emulate RISCV code: return from func\n");
|
|
|
|
|
|
|
|
// Initialize emulator in RISCV64 mode
|
|
|
|
err = uc_open(UC_ARCH_RISCV, UC_MODE_RISCV64, &uc);
|
|
|
|
if (err) {
|
2021-10-29 13:44:49 +03:00
|
|
|
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
|
|
|
uc_strerror(err));
|
2021-10-03 17:14:44 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// map 2MB memory for this emulation
|
|
|
|
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
|
|
|
|
|
|
|
// write machine code to be emulated to memory
|
|
|
|
uc_mem_write(uc, ADDRESS, CODE, sizeof(CODE) - 1);
|
|
|
|
|
|
|
|
// tracing all basic blocks with customized callback
|
|
|
|
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
|
|
|
|
|
|
|
// tracing all instruction
|
|
|
|
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0);
|
|
|
|
|
|
|
|
#if 1
|
|
|
|
// set return address register
|
|
|
|
// RET instruction will return to address in RA
|
|
|
|
// so after RET, PC == RA
|
|
|
|
ra = 0x10006;
|
|
|
|
uc_reg_write(uc, UC_RISCV_REG_RA, &ra);
|
|
|
|
|
|
|
|
// execute ret instruction
|
|
|
|
err = uc_emu_start(uc, 0x10000, -1, 0, 1);
|
|
|
|
if (err) {
|
|
|
|
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
|
|
|
}
|
|
|
|
|
|
|
|
uc_reg_read(uc, UC_RISCV_REG_PC, &pc);
|
|
|
|
if (pc != ra) {
|
2021-10-29 13:44:49 +03:00
|
|
|
printf("Error after execution: PC is: 0x%" PRIx64
|
|
|
|
", expected was 0x%" PRIx64 "\n",
|
|
|
|
pc, ra);
|
2021-10-03 17:14:44 +03:00
|
|
|
if (pc == 0x10000) {
|
|
|
|
printf(" PC did not change during execution\n");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
printf("Good, PC == RA\n");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// set return address register
|
|
|
|
// C.RET instruction will return to address in RA
|
|
|
|
// so after C.RET, PC == RA
|
|
|
|
ra = 0x10006;
|
|
|
|
uc_reg_write(uc, UC_RISCV_REG_RA, &ra);
|
|
|
|
|
|
|
|
printf("========\n");
|
|
|
|
// execute c.ret instruction
|
|
|
|
err = uc_emu_start(uc, 0x10004, -1, 0, 1);
|
|
|
|
if (err) {
|
|
|
|
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
|
|
|
}
|
|
|
|
|
|
|
|
uc_reg_read(uc, UC_RISCV_REG_PC, &pc);
|
|
|
|
if (pc != ra) {
|
2021-10-29 13:44:49 +03:00
|
|
|
printf("Error after execution: PC is: 0x%" PRIx64
|
|
|
|
", expected was 0x%" PRIx64 "\n",
|
|
|
|
pc, ra);
|
2021-10-03 17:14:44 +03:00
|
|
|
if (pc == 0x10004) {
|
|
|
|
printf(" PC did not change during execution\n");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
printf("Good, PC == RA\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
// now print out some registers
|
|
|
|
printf(">>> Emulation done.\n");
|
|
|
|
|
|
|
|
uc_close(uc);
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv, char **envp)
|
|
|
|
{
|
|
|
|
test_recover_from_illegal();
|
|
|
|
|
|
|
|
printf("------------------\n");
|
|
|
|
test_riscv();
|
|
|
|
|
|
|
|
printf("------------------\n");
|
|
|
|
test_riscv2();
|
|
|
|
|
|
|
|
printf("------------------\n");
|
|
|
|
test_riscv3();
|
|
|
|
|
|
|
|
printf("------------------\n");
|
|
|
|
test_riscv_step();
|
|
|
|
|
|
|
|
printf("------------------\n");
|
|
|
|
test_riscv_timeout();
|
|
|
|
|
|
|
|
printf("------------------\n");
|
|
|
|
test_riscv_sd64();
|
|
|
|
|
|
|
|
printf("------------------\n");
|
|
|
|
test_riscv_func_return();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|