From 78db00fef99805fe58c5f9a5e8fba8ff4554c944 Mon Sep 17 00:00:00 2001 From: Ivan Baravy Date: Sat, 2 Mar 2024 14:28:47 +0000 Subject: [PATCH] Fix coverage collection --- README | 4 ++++ makefile | 3 ++- runtests.c | 34 ++++++++++++++++++++++++++-------- shell.c | 2 ++ trace.c | 24 +++++++++++------------- trace.h | 16 ++++++---------- trace_lbr.c | 31 ++++++++++++++++++------------- trace_lbr.h | 10 ++++------ umka.asm | 1 - umka.h | 3 +++ umka_os.c | 21 +++++++++++++++------ umka_shell.c | 16 +++++++++------- 12 files changed, 100 insertions(+), 65 deletions(-) diff --git a/README b/README index b086d34..bdeb8cd 100644 --- a/README +++ b/README @@ -117,6 +117,10 @@ Allow reading process_vm_readv syscall. # sysctl -w kernel.yama.ptrace_scope=0 +Insert msr linux kernel module to collect coverage. + + # modprobe msr + Links & Acknowledgements ------------------------ diff --git a/makefile b/makefile index 2e5ab43..ebc8462 100644 --- a/makefile +++ b/makefile @@ -28,7 +28,8 @@ else endif CFLAGS=$(WARNINGS) $(NOWARNINGS) -std=c11 -g -O0 -DNDEBUG -masm=intel \ - -D_POSIX_C_SOURCE=200809L -I$(HOST) -Ideps -I. -fno-pie -D_POSIX + -D_POSIX_C_SOURCE=200809L -I$(HOST) -Ideps -I. -fno-pie -D_POSIX \ + -fno-common CFLAGS_32=$(CFLAGS) -m32 -D_FILE_OFFSET_BITS=64 -D__USE_TIME_BITS64 LDFLAGS=-no-pie LDFLAGS_32=$(LDFLAGS) -m32 diff --git a/runtests.c b/runtests.c index b571b47..5ba6b71 100644 --- a/runtests.c +++ b/runtests.c @@ -37,6 +37,7 @@ _Thread_local char reffname[PATH_MAX]; _Thread_local char outfname[PATH_MAX]; int coverage = 0; +int no_timeout = 0; int silent_success = 1; static int @@ -125,7 +126,7 @@ struct test_wait_arg { pthread_cond_t *cond; }; -static unsigned +static time_t get_test_timeout(const char *testname) { sprintf(timeoutfname, "%s/%s", testname, TIMEOUT_FILENAME); FILE *f = fopen(timeoutfname, "rb"); @@ -178,21 +179,33 @@ run_test(const void *arg) { int child; if (!(child = fork())) { chdir(test_name); - execl("../../umka_shell", "../../umka_shell", "-ri", "run.us", "-o", - "out.log", NULL); + if (coverage) { + char covfile[64]; + sprintf(covfile, "../cov_%s", test_name); + execl("/usr/bin/taskset", "taskset", "1", "sudo", + "../../umka_shell", "-ri", "run.us", "-o", "out.log", "-c", + covfile, NULL); + } else { + execl("../../umka_shell", "../../umka_shell", "-ri", "run.us", "-o", + "out.log", NULL); + } fprintf(stderr, "Can't run test command: %s\n", strerror(errno)); return (void *)-1; } pthread_t t; struct test_wait_arg wa = {.pid = child, .cond = &cond}; pthread_create(&t, NULL, thread_wait, &wa); - unsigned tout = get_test_timeout(test_name); + time_t tout = get_test_timeout(test_name); struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); - ts.tv_sec += tout; + if (no_timeout) { + ts.tv_sec += 60*60*24*7; // a week + } else { + ts.tv_sec += tout; + } int status; if ((status = pthread_cond_timedwait(&cond, &mutex, &ts))) { - fprintf(stderr, "[!] %s: timeout (%um%us)\n", test_name, + fprintf(stderr, "[!] %s: timeout (%llim%llis)\n", test_name, tout/60, tout % 60); kill(child, SIGKILL); result = (void *)(intptr_t)status; @@ -270,19 +283,24 @@ main(int argc, char *argv[]) { (void)argc; // int action = ACTION_RUN; size_t nthreads = 1; - struct optparse opts; optparse_init(&opts, argv); int opt; - while ((opt = optparse(&opts, "j:s")) != -1) { + while ((opt = optparse(&opts, "cj:st")) != -1) { switch (opt) { + case 'c': + coverage = 1; + break; case 'j': nthreads = strtoul(opts.optarg, NULL, 0); break; case 's': silent_success = 0; break; + case 't': + no_timeout = 1; + break; default: fprintf(stderr, "[!] Unknown option: '%c'\n", opt); exit(1); diff --git a/shell.c b/shell.c index 6929094..c54542c 100644 --- a/shell.c +++ b/shell.c @@ -4368,7 +4368,9 @@ shell_run_cmd_sync(struct shell_ctx *ctx) { } case UMKA_CMD_SYS_LFN: { struct cmd_sys_lfn_arg *c = &cmd->sys_lfn.arg; + COVERAGE_ON(); umka_sys_lfn(c->bufptr, c->r, c->f70or80); + COVERAGE_OFF(); break; } default: diff --git a/trace.c b/trace.c index e0f15c2..34f5640 100644 --- a/trace.c +++ b/trace.c @@ -8,24 +8,22 @@ #include "trace_lbr.h" -uint32_t coverage; - void -trace_begin(void) { - trace_lbr_begin(); +trace_enable(void) { + trace_lbr_enable(); } void -trace_end(void) { - trace_lbr_end(); -} - -uint32_t -trace_pause(void) { - return trace_lbr_pause(); +trace_disable(void) { + trace_lbr_disable(); } void -trace_resume(uint32_t value) { - trace_lbr_resume(value); +trace_on(void) { + trace_lbr_on(); +} + +void +trace_off(void) { + trace_lbr_off(); } diff --git a/trace.h b/trace.h index ea5a74e..5ee3130 100644 --- a/trace.h +++ b/trace.h @@ -9,17 +9,13 @@ #ifndef TRACE_H_INCLUDED #define TRACE_H_INCLUDED -#include +#define COVERAGE_ON() do { trace_on(); } while (0) -extern uint32_t coverage; +#define COVERAGE_OFF() do { trace_off(); } while (0) -#define COVERAGE_ON() do { trace_resume(coverage); } while (0) - -#define COVERAGE_OFF() do { coverage = trace_pause(); } while (0) - -void trace_begin(void); -void trace_end(void); -uint32_t trace_pause(void); -void trace_resume(uint32_t value); +void trace_enable(void); +void trace_disable(void); +void trace_on(void); +void trace_off(void); #endif diff --git a/trace_lbr.c b/trace_lbr.c index f94c7a0..a5306bf 100644 --- a/trace_lbr.c +++ b/trace_lbr.c @@ -24,10 +24,11 @@ #define MSR_IA32_LASTBRANCHFROMIP 0x1db #define MSR_IA32_LASTBRANCHTOIP 0x1dc +int coverage = 0; int msrfd; -uint64_t rdmsr(uint32_t reg) -{ +static uint64_t +rdmsr(uint32_t reg) { uint64_t data = 0; #ifndef _WIN32 @@ -43,8 +44,8 @@ uint64_t rdmsr(uint32_t reg) return data; } -void wrmsr(uint32_t reg, uint64_t data) -{ +static void +wrmsr(uint32_t reg, uint64_t data) { #ifndef _WIN32 int fd; fd = open("/dev/cpu/0/msr", O_WRONLY); @@ -66,7 +67,8 @@ void wrmsr(uint32_t reg, uint64_t data) #endif } -void handle_sigtrap(int signo) { +static void +handle_sigtrap(int signo) { (void)signo; #ifndef _WIN32 uint64_t from = rdmsr(MSR_IA32_LASTBRANCHFROMIP); @@ -86,13 +88,13 @@ void handle_sigtrap(int signo) { #endif } -uint32_t set_eflags_tf(uint32_t tf); - -void trace_lbr_begin(void) { +void +trace_lbr_enable(void) { #ifndef _WIN32 struct sigaction action; action.sa_handler = &handle_sigtrap; action.sa_flags = 0; + coverage = 1; sigaction(SIGTRAP, &action, NULL); wrmsr(MSR_IA32_DEBUGCTL, MSR_IA32_DEBUGCTL_LBR + MSR_IA32_DEBUGCTL_BTF); @@ -106,7 +108,8 @@ void trace_lbr_begin(void) { #endif } -void trace_lbr_end(void) { +void +trace_lbr_disable(void) { #ifndef _WIN32 wrmsr(MSR_IA32_DEBUGCTL, 0); close(msrfd); @@ -115,10 +118,12 @@ void trace_lbr_end(void) { #endif } -uint32_t trace_lbr_pause(void) { - return set_eflags_tf(0u); +void +trace_lbr_on(void) { + set_eflags_tf(coverage); } -void trace_lbr_resume(uint32_t value) { - set_eflags_tf(value); +void +trace_lbr_off(void) { + set_eflags_tf(0u); } diff --git a/trace_lbr.h b/trace_lbr.h index 12e6789..d52436e 100644 --- a/trace_lbr.h +++ b/trace_lbr.h @@ -9,11 +9,9 @@ #ifndef TRACE_LBR_H_INCLUDED #define TRACE_LBR_H_INCLUDED -#include - -void trace_lbr_begin(void); -void trace_lbr_end(void); -uint32_t trace_lbr_pause(void); -void trace_lbr_resume(uint32_t value); +void trace_lbr_enable(void); +void trace_lbr_disable(void); +void trace_lbr_on(void); +void trace_lbr_off(void); #endif diff --git a/umka.asm b/umka.asm index 9511be1..3d33510 100644 --- a/umka.asm +++ b/umka.asm @@ -638,7 +638,6 @@ proc set_eflags_tf c uses ebx esi edi ebp, tf rol eax, 8 push eax popfd - mov eax, edx ret endp diff --git a/umka.h b/umka.h index e91e125..25bb53a 100644 --- a/umka.h +++ b/umka.h @@ -862,6 +862,9 @@ umka_cli(void); void umka_sti(void); +void +set_eflags_tf(uint32_t tf); + #define COVERAGE_TABLE_SIZE (512*1024) struct coverage_branch { diff --git a/umka_os.c b/umka_os.c index d6fc88e..72a7c26 100644 --- a/umka_os.c +++ b/umka_os.c @@ -233,11 +233,9 @@ int main(int argc, char *argv[]) { (void)argc; const char *usage = "umka_os [-i ] [-o ]" - " [-b ] [-s ]\n"; - if (coverage) { - trace_begin(); - } + " [-b ] [-s ] [-c covfile]\n"; + int coverage = 0; int show_display = 0; umka_sti(); @@ -248,6 +246,7 @@ main(int argc, char *argv[]) { const char *infile = NULL; const char *outfile = NULL; const char *boardlogfile = NULL; + const char *covfile = NULL; FILE *fstartup = NULL; FILE *fin = stdin; FILE *fout = stdout; @@ -257,11 +256,15 @@ main(int argc, char *argv[]) { int opt; optparse_init(&options, argv); - while ((opt = optparse(&options, "b:di:o:s:")) != -1) { + while ((opt = optparse(&options, "b:c:di:o:s:")) != -1) { switch (opt) { case 'b': boardlogfile = options.optarg; break; + case 'c': + coverage = 1; + covfile = options.optarg; + break; case 'd': show_display = 1; break; @@ -281,6 +284,10 @@ main(int argc, char *argv[]) { } } + if (coverage) { + trace_enable(); + } + if (startupfile) { fstartup = fopen(startupfile, "rb"); if (!fstartup) { @@ -429,7 +436,9 @@ main(int argc, char *argv[]) { umka_osloop(); // doesn't return if (coverage) - trace_end(); + trace_disable(); + + (void)covfile; return 0; } diff --git a/umka_shell.c b/umka_shell.c index aae7c1f..24deb56 100644 --- a/umka_shell.c +++ b/umka_shell.c @@ -63,7 +63,9 @@ main(int argc, char **argv) { " -i infile file with commands\n" " -o outfile file for logs\n" " -r reproducible logs (without pointers and datetime)\n" - " -c collect coverage\n"; + " -c covfile collect coverage to the file\n"; + + char covfile[64]; const char *infile = NULL, *outfile = NULL; FILE *fin = stdin; @@ -75,13 +77,14 @@ main(int argc, char **argv) { kos_boot.memmap_blocks[1] = (e820entry_t){(uintptr_t)mem1, 128*1024*1024, 1}; kos_boot.memmap_blocks[2] = (e820entry_t){(uintptr_t)mem2, 256*1024*1024, 1}; */ + int coverage = 0; int reproducible = 0; struct optparse options; optparse_init(&options, argv); int opt; - while ((opt = optparse(&options, "i:o:rc")) != -1) { + while ((opt = optparse(&options, "i:o:rc:")) != -1) { switch (opt) { case 'i': infile = options.optarg; @@ -94,6 +97,7 @@ main(int argc, char **argv) { break; case 'c': coverage = 1; + sprintf(covfile, "%s.%i", options.optarg, getpid()); break; case 'h': fputs(usage, stderr); @@ -123,15 +127,13 @@ main(int argc, char **argv) { struct umka_shell_ctx *ctx = umka_shell_init(reproducible, fin); if (coverage) - trace_begin(); + trace_enable(); run_test(ctx->shell); if (coverage) { - trace_end(); - char coverage_filename[32]; - sprintf(coverage_filename, "coverage.%i", getpid()); - FILE *f = fopen(coverage_filename, "w"); + trace_disable(); + FILE *f = fopen(covfile, "w"); fwrite(coverage_table, COVERAGE_TABLE_SIZE * sizeof(struct coverage_branch), 1, f); fclose(f);