Implement line coverage collection and reporting!

This commit is contained in:
Ivan Baravy 2020-01-29 13:53:13 +03:00
parent 0ea4945923
commit 07ca60a749
5 changed files with 124 additions and 6 deletions

2
.gitignore vendored
View File

@ -19,3 +19,5 @@ kolibri.lst
kolibri.prp
tags
*.out
coverage.*
covpreproc

111
covpreproc.c Normal file
View File

@ -0,0 +1,111 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#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 <listing file> <coverage_begin offset> <coverage_begin address> <coverage_end address> <coverage files ...>\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;
}

2
kofu.c
View File

@ -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",

View File

@ -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`

View File

@ -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);
}