Implement line coverage collection and reporting!
This commit is contained in:
parent
0ea4945923
commit
07ca60a749
2
.gitignore
vendored
2
.gitignore
vendored
@ -19,3 +19,5 @@ kolibri.lst
|
||||
kolibri.prp
|
||||
tags
|
||||
*.out
|
||||
coverage.*
|
||||
covpreproc
|
||||
|
111
covpreproc.c
Normal file
111
covpreproc.c
Normal 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
2
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",
|
||||
|
7
makefile
7
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`
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user