From 07ca60a749653eb550eb4a286a11a2c17facc8e7 Mon Sep 17 00:00:00 2001 From: Ivan Baravy Date: Wed, 29 Jan 2020 13:53:13 +0300 Subject: [PATCH] Implement line coverage collection and reporting! --- .gitignore | 2 + covpreproc.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++ kofu.c | 2 +- makefile | 7 +++- trace_lbr.c | 8 ++-- 5 files changed, 124 insertions(+), 6 deletions(-) create mode 100644 covpreproc.c diff --git a/.gitignore b/.gitignore index 4e8ca83..2bbd3a0 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,5 @@ kolibri.lst kolibri.prp tags *.out +coverage.* +covpreproc diff --git a/covpreproc.c b/covpreproc.c new file mode 100644 index 0000000..0c63708 --- /dev/null +++ b/covpreproc.c @@ -0,0 +1,111 @@ +#include +#include +#include +#include + +#define MAX_COVERED_CODE_SIZE (128*1024) + +typedef struct { + uint64_t to_cnt, from_cnt; +} branch; + +branch branches[MAX_COVERED_CODE_SIZE]; + +uint32_t coverage_offset, coverage_begin, coverage_end; + +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); + size_t branch_cnt = fsize/(2*sizeof(uint32_t)); + 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 /*&& to < 0x80000000u*/) { + from = from - coverage_begin + coverage_offset; + branches[from].from_cnt++; + } + if (to >= coverage_begin && to < coverage_end /*&& from < 0x80000000u*/) { + to = to - coverage_begin + coverage_offset; + branches[to].to_cnt++; + } + } + fclose(f); +} + +size_t count_line_bytes(const char *s) { + size_t cnt = 0; + for (size_t i = 10; i <= 58; i += 3) { + if (s[i] == ' ') break; + cnt++; + } + return cnt; +} + +size_t count_block_bytes(FILE *f) { + char tmp[1024]; + size_t cnt = 0; + if (fgets(tmp, 1024, f) && strspn(tmp, "0123456789ABCDEF") == 8) { + cnt = count_line_bytes(tmp); + while (fgets(tmp, 1024, f) && tmp[0] == ' ' && tmp[10] != ' ') { + cnt += count_line_bytes(tmp); + } + } + return cnt; +} + +int main(int argc, char **argv) { + if (argc < 6) { + fprintf(stderr, "usage: covpreproc \n"); + exit(1); + } + sscanf(argv[2], "%" SCNx32, &coverage_offset); + sscanf(argv[3], "%" SCNx32, &coverage_begin); + sscanf(argv[4], "%" SCNx32, &coverage_end); + + for (int i = 5; i < argc; i++) { + read_coverage_file(argv[i]); + } + + FILE *f = fopen(argv[1], "r"); + char tmp[1024]; + uint64_t cur = 0; + while (1) { + off_t fpos_before = ftello(f); + if (!fgets(tmp, 1024, f)) { + break; + } + off_t fpos_after = ftello(f); + if (strspn(tmp, "0123456789ABCDEF") == 8) { + fseeko(f, fpos_before, SEEK_SET); + size_t inst_len = count_block_bytes(f); + fseeko(f, fpos_after, SEEK_SET); + unsigned long pos = strtoul(tmp, NULL, 16); + size_t total_to = 0, total_from = 0; + for (size_t i = 0; i < inst_len; i++) { + total_to += branches[pos + i].to_cnt; + total_from += branches[pos + i].from_cnt; + } + cur += total_to; + if (cur) { + putchar(' '); + } else { + putchar('-'); + } + if (total_from || total_to || cur) { + printf("%8" PRIu64 " %8" PRIu64 " %8" PRIu64, total_from, total_to, cur); + } else { + printf(" - - -"); + } + cur -= total_from; + } else { + printf(" "); + } + printf(" : %s", tmp + 64); + } + fclose(f); + + return 0; +} diff --git a/kofu.c b/kofu.c index 4d4507f..fa7f62c 100644 --- a/kofu.c +++ b/kofu.c @@ -47,7 +47,7 @@ const char *last_dir = cur_dir; bool cur_dir_changed = true; char cmd_buf[FGETS_BUF_LEN]; -int trace = false; +int trace = true; const char *f70_status_name[] = { "success", diff --git a/makefile b/makefile index 389d176..963099b 100644 --- a/makefile +++ b/makefile @@ -6,10 +6,13 @@ CFLAGS_32=-m32 LDFLAGS= LDFLAGS_32=-m32 -all: kofu kofuse kolibri.sym kolibri.prp kolibri.lst tags tools/mkdirrange tools/mkfilepattern +all: kofu kofuse kolibri.sym kolibri.prp kolibri.lst tags tools/mkdirrange tools/mkfilepattern covpreproc + +covpreproc: covpreproc.c + $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ kofu: kofu.o kolibri.o trace.o trace_lbr.o trace_lwp.o cio.o - $(CC) $(LDFLAGS) $(LDFLAGS_32) $^ -o $@ + $(CC) $(LDFLAGS) $(LDFLAGS_32) $^ -o $@ -static kofuse: kofuse.o kolibri.o cio.o $(CC) $(LDFLAGS) $(LDFLAGS_32) $^ -o $@ `pkg-config fuse3 --libs` diff --git a/trace_lbr.c b/trace_lbr.c index e6c98dd..e7bb8b1 100644 --- a/trace_lbr.c +++ b/trace_lbr.c @@ -48,8 +48,8 @@ void handle_sigtrap() { if ((from >= (uintptr_t)coverage_begin && from < (uintptr_t)coverage_end) || (to >= (uintptr_t)coverage_begin && to < (uintptr_t)coverage_end)) { - write(covfd, &from, 8); - write(covfd, &to, 8); + write(covfd, &from, 4); + write(covfd, &to, 4); } wrmsr(0x1d9, 3); @@ -72,7 +72,9 @@ void trace_lbr_begin() { perror("rdmsr: open"); exit(1); } - covfd = open("coverage", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + 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); set_eflags_tf(1); }