diff --git a/makefile b/makefile index 5130253..4350473 100644 --- a/makefile +++ b/makefile @@ -44,7 +44,7 @@ endif ifeq ($(HOST),linux) all: umka_shell umka_fuse umka_os umka_gen_devices_dat umka.sym umka.prp \ - umka.lst tags covpreproc default.skn skin.skn + umka.lst tags default.skn skin.skn else ifeq ($(HOST),windows) all: umka_shell umka.sym umka.prp \ umka.lst default.skn skin.skn @@ -57,9 +57,6 @@ endif test: umka_shell @cd test && make clean all && cd ../ -covpreproc: covpreproc.c - $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ - umka_shell: umka_shell.o umka.o shell.o trace.o trace_lbr.o vdisk.o vnet.o \ lodepng.o pci.o thread.o util.o optparse.o bestline.o $(CC) $(LDFLAGS_32) $^ -o $@ -T umka.ld diff --git a/test/makefile b/test/makefile index f4c69e9..6a681b9 100644 --- a/test/makefile +++ b/test/makefile @@ -67,7 +67,7 @@ else endif collect_coverage: - ../covpreproc ../umka.lst 0x34 coverage.* > ../umka.cov + ../tools/covpreproc ../umka.lst coverage.* > ../umka.cov clean: rm -f *.out.log *.out.png coverage.* diff --git a/covpreproc.c b/tools/covpreproc.c similarity index 74% rename from covpreproc.c rename to tools/covpreproc.c index 7cacc8c..a715003 100644 --- a/covpreproc.c +++ b/tools/covpreproc.c @@ -3,44 +3,33 @@ UMKa - User-Mode KolibriOS developer tools - Copyright (C) 2020 Ivan Baravy + Copyright (C) 2020,2022 Ivan Baravy */ +#include #include #include #include -#include -#define MAX_COVERED_CODE_SIZE (256*1024) +#define COVERAGE_TABLE_SIZE (512*1024) -typedef struct { - uint64_t to_cnt, from_cnt; -} branch; +struct coverage_branch { + uint64_t to_cnt; + uint64_t from_cnt; +}; -branch branches[MAX_COVERED_CODE_SIZE]; +struct coverage_branch branches[COVERAGE_TABLE_SIZE]; -uint32_t coverage_offset, coverage_begin, coverage_end; +uint32_t coverage_begin = 0x34; // TODD: detect in runtime void read_coverage_file(const char *fname) { FILE *f = fopen(fname, "r"); - fseeko(f, 0, SEEK_END); - off_t fsize = ftello(f); - fseeko(f, 0, SEEK_SET); - fread(&coverage_begin, sizeof(uint32_t), 1, f); - fread(&coverage_end, sizeof(uint32_t), 1, f); - size_t branch_cnt = (fsize-4*2)/(2*4); - for (size_t i = 0; i < branch_cnt; i++) { - uint32_t from, to; - fread(&from, sizeof(uint32_t), 1, f); - fread(&to, sizeof(uint32_t), 1, f); - if (from >= coverage_begin && from < coverage_end) { - from = from - coverage_begin + coverage_offset; - branches[from].from_cnt++; - } - if (to >= coverage_begin && to < coverage_end) { - to = to - coverage_begin + coverage_offset; - branches[to].to_cnt++; - } + for (size_t i = 0; i < COVERAGE_TABLE_SIZE; i++) { + uint64_t from, to; + fread(&to, 1, sizeof(uint64_t), f); + fread(&from, 1, sizeof(uint64_t), f); + branches[i].to_cnt += to; + branches[i].from_cnt += from; } fclose(f); } @@ -98,19 +87,19 @@ int is_cond_jump(const char *s) { || !strncmp(s, "jpe", 3) || !strncmp(s, "jnp", 3) || !strncmp(s, "jpo", 3) + || !strncmp(s, "loop", 4) || !strncmp(s, "jcxz", 4) || !strncmp(s, "jecxz", 5); return found; } int main(int argc, char **argv) { - if (argc < 4) { - fprintf(stderr, "usage: covpreproc \n"); + if (argc < 3) { + fprintf(stderr, "usage: covpreproc \n"); exit(1); } - sscanf(argv[2], "%" SCNx32, &coverage_offset); - for (int i = 3; i < argc; i++) { + for (int i = 2; i < argc; i++) { read_coverage_file(argv[i]); } @@ -131,9 +120,10 @@ int main(int argc, char **argv) { unsigned long pos = strtoul(tmp, NULL, 16); size_t total_to = 0, total_from = 0; for (size_t i = 0; i < inst_len; i++) { - if (pos + i < coverage_end - coverage_begin + coverage_offset) { - total_to += branches[pos + i].to_cnt; - total_from += branches[pos + i].from_cnt; + if (pos + i >= coverage_begin + && pos + i < coverage_begin + COVERAGE_TABLE_SIZE) { + total_to += branches[pos + i - coverage_begin].to_cnt; + total_from += branches[pos + i - coverage_begin].from_cnt; } } cur += total_to; @@ -154,7 +144,8 @@ int main(int argc, char **argv) { putchar('-'); } if (is_cond) { - int spaces = 19 - printf("%10" PRIu64 "/%" PRIu64, taken, not_taken); + int spaces = 19 - printf("%10" PRIu64 "/%" PRIu64, taken, + not_taken); while (spaces-- > 0) putchar(' '); } else { diff --git a/tools/makefile b/tools/makefile index 79a4224..3ad32ab 100644 --- a/tools/makefile +++ b/tools/makefile @@ -7,7 +7,7 @@ CFLAGS=$(WARNINGS) $(NOWARNINGS) -std=c11 -O2 \ -DNDEBUG -D_POSIX_C_SOURCE=200809L -fno-pie LDFLAGS=-no-pie -all: mkdirrange mkfilepattern lfbviewx randdir +all: mkdirrange mkfilepattern lfbviewx randdir covpreproc mkdirrange: mkdirrange.c $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ @@ -21,7 +21,10 @@ lfbviewx: lfbviewx.c randdir: randdir.c $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ +covpreproc: covpreproc.c + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ + .PHONY: all clean clean: - rm -f *.o mkdirrange mkfilepattern lfbviewx + rm -f *.o mkdirrange mkfilepattern lfbviewx randdir covpreproc diff --git a/trace_lbr.c b/trace_lbr.c index 73c990b..ebfbede 100644 --- a/trace_lbr.c +++ b/trace_lbr.c @@ -3,7 +3,7 @@ UMKa - User-Mode KolibriOS developer tools - Copyright (C) 2019-2020 Ivan Baravy + Copyright (C) 2019-2020,2022 Ivan Baravy Copyright (C) 2021 Magomed Kostoev */ @@ -18,11 +18,13 @@ #include "umka.h" -#define MSR_IA32_DEBUGCTLMSR 0x1d9 +#define MSR_IA32_DEBUGCTL 0x1d9 +#define MSR_IA32_DEBUGCTL_LBR 0x1 // enable profiling +#define MSR_IA32_DEBUGCTL_BTF 0x2 // profile only branches if EFLAGS.TF #define MSR_IA32_LASTBRANCHFROMIP 0x1db #define MSR_IA32_LASTBRANCHTOIP 0x1dc -int covfd, msrfd; +int msrfd; uint64_t rdmsr(uint32_t reg) { @@ -66,13 +68,15 @@ void handle_sigtrap() { uint64_t from = rdmsr(MSR_IA32_LASTBRANCHFROMIP); uint64_t to = rdmsr(MSR_IA32_LASTBRANCHTOIP); - if ((from >= (uintptr_t)coverage_begin && from < (uintptr_t)coverage_end) || - (to >= (uintptr_t)coverage_begin && to < (uintptr_t)coverage_end)) { - write(covfd, &from, 4); - write(covfd, &to, 4); + if (from >= (uintptr_t)coverage_begin && from < (uintptr_t)coverage_end) { + coverage_table[from - (uintptr_t)coverage_begin].from_cnt++; } - wrmsr(MSR_IA32_DEBUGCTLMSR, 3); + if (to >= (uintptr_t)coverage_begin && to < (uintptr_t)coverage_end) { + coverage_table[to - (uintptr_t)coverage_begin].to_cnt++; + } + + wrmsr(MSR_IA32_DEBUGCTL, MSR_IA32_DEBUGCTL_LBR + MSR_IA32_DEBUGCTL_BTF); #else printf("STUB: %s:%d", __FILE__, __LINE__); #endif @@ -87,19 +91,12 @@ void trace_lbr_begin() { action.sa_flags = SA_SIGINFO; sigaction(SIGTRAP, &action, NULL); - wrmsr(MSR_IA32_DEBUGCTLMSR, 3); + wrmsr(MSR_IA32_DEBUGCTL, MSR_IA32_DEBUGCTL_LBR + MSR_IA32_DEBUGCTL_BTF); msrfd = open("/dev/cpu/0/msr", O_RDONLY); if (msrfd < 0) { perror("rdmsr: open"); exit(1); } - char coverage_filename[32]; - sprintf(coverage_filename, "coverage.%i", getpid()); - covfd = open(coverage_filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH | S_IWOTH); - void *coverage_begin_addr = coverage_begin; - void *coverage_end_addr = coverage_end; - write(covfd, &coverage_begin_addr, 4); - write(covfd, &coverage_end_addr, 4); #else printf("STUB: %s:%d", __FILE__, __LINE__); #endif @@ -107,9 +104,8 @@ void trace_lbr_begin() { void trace_lbr_end() { #ifndef _WIN32 - wrmsr(MSR_IA32_DEBUGCTLMSR, 0); + wrmsr(MSR_IA32_DEBUGCTL, 0); close(msrfd); - close(covfd); #else printf("STUB: %s:%d", __FILE__, __LINE__); #endif diff --git a/umka.asm b/umka.asm index 50b58fe..19fe658 100644 --- a/umka.asm +++ b/umka.asm @@ -88,12 +88,12 @@ pubsym irq_serv.irq_10, 'kos_irq_serv_irq10' pubsym attach_int_handler, 'kos_attach_int_handler', 12 pubsym fs_execute, 'kos_fs_execute', 4 pubsym set_keyboard_data, 'kos_set_keyboard_data' -pubsym KEY_COUNT as 'kos_key_count' -pubsym KEY_BUFF as 'kos_key_buff' -pubsym keyboard_mode as 'kos_keyboard_mode' -pubsym sys_getkey as 'kos_get_key' -pubsym syslang as 'kos_syslang' -pubsym keyboard as 'kos_keyboard' +pubsym KEY_COUNT, 'kos_key_count' +pubsym KEY_BUFF, 'kos_key_buff' +pubsym keyboard_mode, 'kos_keyboard_mode' +pubsym sys_getkey, 'kos_get_key' +pubsym syslang, 'kos_syslang' +pubsym keyboard, 'kos_keyboard' pubsym disk_add, 16 pubsym disk_del, 4 @@ -991,6 +991,18 @@ restore org,sys_msg_board,delay_ms coverage_end: +section '.bss.coverage' executable writable align 64 +struct coverage_branch + to_cnt DQ ? + from_cnt DQ ? +ends + +COVERAGE_TABLE_SIZE = 512*1024 ; 512k should be enough for the kernel + +coverage_table rb COVERAGE_TABLE_SIZE * sizeof.coverage_branch +pubsym coverage_table + + section '.data.boot' writeable align 0x1000 BOOT boot_data virtual at BOOT diff --git a/umka.h b/umka.h index fbfa201..0e73a34 100644 --- a/umka.h +++ b/umka.h @@ -833,6 +833,14 @@ umka_cli(void); void umka_sti(void); +#define COVERAGE_TABLE_SIZE (512*1024) + +struct coverage_branch { + uint64_t to_cnt; + uint64_t from_cnt; +}; + +extern struct coverage_branch coverage_table[]; extern uint8_t coverage_begin[]; extern uint8_t coverage_end[]; diff --git a/umka_shell.c b/umka_shell.c index 920fc71..5b7b78a 100644 --- a/umka_shell.c +++ b/umka_shell.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "optparse.h" #include "shell.h" #include "umka.h" @@ -104,8 +105,15 @@ main(int argc, char **argv) { run_test(&ctx); - if (coverage) + if (coverage) { trace_end(); + char coverage_filename[32]; + sprintf(coverage_filename, "coverage.%i", getpid()); + FILE *f = fopen(coverage_filename, "w"); + fwrite(coverage_table, + COVERAGE_TABLE_SIZE * sizeof(struct coverage_branch), 1, f); + fclose(f); + } return 0; }