diff --git a/tests/benchmarks/cow/Makefile b/tests/benchmarks/cow/Makefile new file mode 100644 index 00000000..3c4bb8ce --- /dev/null +++ b/tests/benchmarks/cow/Makefile @@ -0,0 +1,24 @@ +CFLAGS += -Wall -Werror -I../../../include +CFLAGS += -D__USE_MINGW_ANSI_STDIO=1 +LDLIBS += -L../../../build -lgsl -lgslcblas -lm -lunicorn + +UNAME_S := $(shell uname -s) +LDLIBS += -pthread +ifeq ($(UNAME_S), Linux) +LDLIBS += -lrt +endif + +#EXECUTE_VARS = LD_LIBRARY_PATH=../../cmocka/src:../../build/ DYLD_LIBRARY_PATH=../../build/ +EXECUTE_VARS = LD_LIBRARY_PATH=../../../build/cmocka/src:../../../build/ DYLD_LIBRARY_PATH=../../../build/ + +TESTS_SOURCE = $(wildcard *.c) +TESTS = $(TESTS_SOURCE:%.c=%) + +.PHONY: all clean test + +test: $(TESTS) + +all: $(TESTS) + +clean: + rm -f $(TESTS) diff --git a/tests/benchmarks/cow/benchmark.c b/tests/benchmarks/cow/benchmark.c new file mode 100644 index 00000000..327886ce --- /dev/null +++ b/tests/benchmarks/cow/benchmark.c @@ -0,0 +1,186 @@ +#include +#include +#include +#include +#include +#include +#include + +struct data { + gsl_rstat_workspace *rstat_p; + struct timespec start; +}; + + +void update_stats(gsl_rstat_workspace *rstat_p, struct timespec *start, struct timespec *end) +{ + double dur = (end->tv_sec - start->tv_sec) * 1000.0; + dur += (end->tv_nsec - start->tv_nsec) / 1000000.0; + gsl_rstat_add(dur, rstat_p); +} + +static uint64_t CODEADDR = 0x1000; +static uint64_t DATABASE = 0x40000000; +static uint64_t BLOCKSIZE = 0x10000; + +/*static void callback_mem(uc_engine *uc, uc_mem_type type, uint64_t addr, uint32_t size, uint64_t value, void *data) +{ + printf("callback mem valid: 0x%lX, value: 0x%lX\n", addr, value); +}*/ +static int callback_mem_prot(uc_engine *uc, uc_mem_type type, uint64_t addr, uint32_t size, int64_t value, void *data) +{ + printf("callback mem prot: 0x%lX, type: %X\n", addr, type); + return false; +} + +static void callback_block(uc_engine *uc, uint64_t addr, uint32_t size, void *data) +{ + struct timespec now; + struct data *d = data; + size_t run; + uint64_t rax = 512; + uint64_t rbx = DATABASE; + uint64_t rsi; + long memblock; + long offset; + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &now); + if (d->rstat_p) { + update_stats(d->rstat_p, &d->start, &now); + } else { + d->rstat_p = gsl_rstat_alloc(); + } + run = gsl_rstat_n(d->rstat_p); + if ((run >> 4) >= 20) { + uc_emu_stop(uc); + return; + } else if (run > 0 && run % 16 == 0) { + uc_snapshot(uc); + } +/* if (run > 0 && run % 16 == 0) { + uc_emu_stop(uc); + return; + }*/ + rsi = random(); + memblock = random() & 15; + offset = random() & (BLOCKSIZE - 1) & (~0xf); +// memblock = 0; +// offset = 0; + if (memblock == 15 && (offset + 0x1000) > BLOCKSIZE) { + offset -= 0x1000; + } + rbx += (memblock * BLOCKSIZE) + offset; + printf("write at 0x%lX\n", rbx); + printf("[%li] callback block: 0x%lX\n", run, addr); + uc_reg_write(uc, UC_X86_REG_RBX, &rbx); + uc_reg_write(uc, UC_X86_REG_RAX, &rax); + uc_reg_write(uc, UC_X86_REG_RSI, &rsi); + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &d->start); +} + +static void prepare_mapping(uc_engine *uc) +{ + for (size_t i = 0; i < 16; i++) { + printf("mem map: 0x%lX\n", DATABASE+i*BLOCKSIZE); + uc_mem_map(uc, DATABASE+i*BLOCKSIZE, BLOCKSIZE, UC_PROT_READ|UC_PROT_WRITE); + } +} + +static void prepare_code(uc_engine *uc, const char *file, void **addr) +{ + uc_err err; + int fd; + fd = open(file, O_RDONLY, 0); + if (fd == -1) { + perror("open"); + exit(1); + } + *addr = mmap(*addr, 0x1000, PROT_READ, MAP_PRIVATE, fd, 0); + if (addr == MAP_FAILED) { + perror("mmap"); + exit(1); + } + err = uc_mem_map_ptr(uc, CODEADDR, 0x1000, UC_PROT_READ|UC_PROT_EXEC, *addr); + close(fd); + if (err != UC_ERR_OK) { + printf("err: %s\n", uc_strerror(err)); + exit(1); + } + printf("mapped %s\n", file); + return; +} + +void print_stats(gsl_rstat_workspace *rstat_p) +{ + double mean, variance, largest, smallest, sd, + rms, sd_mean, median, skew, kurtosis; + size_t n; + + mean = gsl_rstat_mean(rstat_p); + variance = gsl_rstat_variance(rstat_p); + largest = gsl_rstat_max(rstat_p); + smallest = gsl_rstat_min(rstat_p); + median = gsl_rstat_median(rstat_p); + sd = gsl_rstat_sd(rstat_p); + sd_mean = gsl_rstat_sd_mean(rstat_p); + skew = gsl_rstat_skew(rstat_p); + rms = gsl_rstat_rms(rstat_p); + kurtosis = gsl_rstat_kurtosis(rstat_p); + n = gsl_rstat_n(rstat_p); + + printf ("The sample mean is %g\n", mean); + printf ("The estimated variance is %g\n", variance); + printf ("The largest value is %g\n", largest); + printf ("The smallest value is %g\n", smallest); + printf( "The median is %g\n", median); + printf( "The standard deviation is %g\n", sd); + printf( "The root mean square is %g\n", rms); + printf( "The standard devation of the mean is %g\n", sd_mean); + printf( "The skew is %g\n", skew); + printf( "The kurtosis %g\n", kurtosis); + printf( "There are %zu items in the accumulator\n", n); +} +int main(int argc, char *argv[]) +{ + uc_engine *uc; + uc_err err; + uc_hook hook_block; + uc_hook hook_mem; + struct data d; + uint64_t rax = 5; + uint64_t rbx = DATABASE; + void *bin_mmap = NULL; + + if (argc != 2) { + fprintf(stderr, "usage: %s binary\n", argv[0]); + return 1; + } + + d.rstat_p = NULL; + srandom(time(NULL)); + + uc_open(UC_ARCH_X86, UC_MODE_64, &uc); + prepare_code(uc, argv[1], &bin_mmap); + prepare_mapping(uc); + err = uc_hook_add(uc, &hook_block, UC_HOOK_BLOCK, &callback_block, &d, CODEADDR, 0x1000); + if (err != UC_ERR_OK) { + return 1; + } + uc_hook_add(uc, &hook_mem, UC_HOOK_MEM_INVALID, &callback_mem_prot, NULL, CODEADDR, 0x1000); + uc_reg_write(uc, UC_X86_REG_RBX, &rbx); + uc_reg_write(uc, UC_X86_REG_RAX, &rax); +/* err = uc_hook_add(uc, &hook_mem, UC_HOOK_MEM_VALID, &callback_mem, NULL, DATABASE, 16*BLOCKSIZE); + if (err) { + printf("err: %s\n", uc_strerror(err)); + return 1; + }*/ + for (int i = 0; i < 1; i++) { + err = uc_emu_start(uc, CODEADDR, -1, 0, 0); + if (err) { + printf("err: %s\n", uc_strerror(err)); + return 1; + } + uc_snapshot(uc); + } + print_stats(d.rstat_p); + return 0; +} diff --git a/tests/benchmarks/cow/binary.S b/tests/benchmarks/cow/binary.S new file mode 100644 index 00000000..1705535c --- /dev/null +++ b/tests/benchmarks/cow/binary.S @@ -0,0 +1,13 @@ +USE64 +DEFAULT REL + +SECTION .text +loop: + xor rcx, rcx +write: + mov [rbx+rcx*8], rsi + inc rcx + mov rdi, rax + sub rdi, rcx + jnz write + jmp loop