Fix coverage collection
This commit is contained in:
parent
0073eb0cc9
commit
78db00fef9
4
README
4
README
@ -117,6 +117,10 @@ Allow reading process_vm_readv syscall.
|
|||||||
|
|
||||||
# sysctl -w kernel.yama.ptrace_scope=0
|
# sysctl -w kernel.yama.ptrace_scope=0
|
||||||
|
|
||||||
|
Insert msr linux kernel module to collect coverage.
|
||||||
|
|
||||||
|
# modprobe msr
|
||||||
|
|
||||||
|
|
||||||
Links & Acknowledgements
|
Links & Acknowledgements
|
||||||
------------------------
|
------------------------
|
||||||
|
3
makefile
3
makefile
@ -28,7 +28,8 @@ else
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
CFLAGS=$(WARNINGS) $(NOWARNINGS) -std=c11 -g -O0 -DNDEBUG -masm=intel \
|
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
|
CFLAGS_32=$(CFLAGS) -m32 -D_FILE_OFFSET_BITS=64 -D__USE_TIME_BITS64
|
||||||
LDFLAGS=-no-pie
|
LDFLAGS=-no-pie
|
||||||
LDFLAGS_32=$(LDFLAGS) -m32
|
LDFLAGS_32=$(LDFLAGS) -m32
|
||||||
|
34
runtests.c
34
runtests.c
@ -37,6 +37,7 @@ _Thread_local char reffname[PATH_MAX];
|
|||||||
_Thread_local char outfname[PATH_MAX];
|
_Thread_local char outfname[PATH_MAX];
|
||||||
|
|
||||||
int coverage = 0;
|
int coverage = 0;
|
||||||
|
int no_timeout = 0;
|
||||||
int silent_success = 1;
|
int silent_success = 1;
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -125,7 +126,7 @@ struct test_wait_arg {
|
|||||||
pthread_cond_t *cond;
|
pthread_cond_t *cond;
|
||||||
};
|
};
|
||||||
|
|
||||||
static unsigned
|
static time_t
|
||||||
get_test_timeout(const char *testname) {
|
get_test_timeout(const char *testname) {
|
||||||
sprintf(timeoutfname, "%s/%s", testname, TIMEOUT_FILENAME);
|
sprintf(timeoutfname, "%s/%s", testname, TIMEOUT_FILENAME);
|
||||||
FILE *f = fopen(timeoutfname, "rb");
|
FILE *f = fopen(timeoutfname, "rb");
|
||||||
@ -178,21 +179,33 @@ run_test(const void *arg) {
|
|||||||
int child;
|
int child;
|
||||||
if (!(child = fork())) {
|
if (!(child = fork())) {
|
||||||
chdir(test_name);
|
chdir(test_name);
|
||||||
execl("../../umka_shell", "../../umka_shell", "-ri", "run.us", "-o",
|
if (coverage) {
|
||||||
"out.log", NULL);
|
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));
|
fprintf(stderr, "Can't run test command: %s\n", strerror(errno));
|
||||||
return (void *)-1;
|
return (void *)-1;
|
||||||
}
|
}
|
||||||
pthread_t t;
|
pthread_t t;
|
||||||
struct test_wait_arg wa = {.pid = child, .cond = &cond};
|
struct test_wait_arg wa = {.pid = child, .cond = &cond};
|
||||||
pthread_create(&t, NULL, thread_wait, &wa);
|
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;
|
struct timespec ts;
|
||||||
clock_gettime(CLOCK_REALTIME, &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;
|
int status;
|
||||||
if ((status = pthread_cond_timedwait(&cond, &mutex, &ts))) {
|
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);
|
tout/60, tout % 60);
|
||||||
kill(child, SIGKILL);
|
kill(child, SIGKILL);
|
||||||
result = (void *)(intptr_t)status;
|
result = (void *)(intptr_t)status;
|
||||||
@ -270,19 +283,24 @@ main(int argc, char *argv[]) {
|
|||||||
(void)argc;
|
(void)argc;
|
||||||
// int action = ACTION_RUN;
|
// int action = ACTION_RUN;
|
||||||
size_t nthreads = 1;
|
size_t nthreads = 1;
|
||||||
|
|
||||||
struct optparse opts;
|
struct optparse opts;
|
||||||
optparse_init(&opts, argv);
|
optparse_init(&opts, argv);
|
||||||
int opt;
|
int opt;
|
||||||
|
|
||||||
while ((opt = optparse(&opts, "j:s")) != -1) {
|
while ((opt = optparse(&opts, "cj:st")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
|
case 'c':
|
||||||
|
coverage = 1;
|
||||||
|
break;
|
||||||
case 'j':
|
case 'j':
|
||||||
nthreads = strtoul(opts.optarg, NULL, 0);
|
nthreads = strtoul(opts.optarg, NULL, 0);
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
silent_success = 0;
|
silent_success = 0;
|
||||||
break;
|
break;
|
||||||
|
case 't':
|
||||||
|
no_timeout = 1;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "[!] Unknown option: '%c'\n", opt);
|
fprintf(stderr, "[!] Unknown option: '%c'\n", opt);
|
||||||
exit(1);
|
exit(1);
|
||||||
|
2
shell.c
2
shell.c
@ -4368,7 +4368,9 @@ shell_run_cmd_sync(struct shell_ctx *ctx) {
|
|||||||
}
|
}
|
||||||
case UMKA_CMD_SYS_LFN: {
|
case UMKA_CMD_SYS_LFN: {
|
||||||
struct cmd_sys_lfn_arg *c = &cmd->sys_lfn.arg;
|
struct cmd_sys_lfn_arg *c = &cmd->sys_lfn.arg;
|
||||||
|
COVERAGE_ON();
|
||||||
umka_sys_lfn(c->bufptr, c->r, c->f70or80);
|
umka_sys_lfn(c->bufptr, c->r, c->f70or80);
|
||||||
|
COVERAGE_OFF();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
24
trace.c
24
trace.c
@ -8,24 +8,22 @@
|
|||||||
|
|
||||||
#include "trace_lbr.h"
|
#include "trace_lbr.h"
|
||||||
|
|
||||||
uint32_t coverage;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
trace_begin(void) {
|
trace_enable(void) {
|
||||||
trace_lbr_begin();
|
trace_lbr_enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
trace_end(void) {
|
trace_disable(void) {
|
||||||
trace_lbr_end();
|
trace_lbr_disable();
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t
|
|
||||||
trace_pause(void) {
|
|
||||||
return trace_lbr_pause();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
trace_resume(uint32_t value) {
|
trace_on(void) {
|
||||||
trace_lbr_resume(value);
|
trace_lbr_on();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
trace_off(void) {
|
||||||
|
trace_lbr_off();
|
||||||
}
|
}
|
||||||
|
16
trace.h
16
trace.h
@ -9,17 +9,13 @@
|
|||||||
#ifndef TRACE_H_INCLUDED
|
#ifndef TRACE_H_INCLUDED
|
||||||
#define TRACE_H_INCLUDED
|
#define TRACE_H_INCLUDED
|
||||||
|
|
||||||
#include <inttypes.h>
|
#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)
|
void trace_enable(void);
|
||||||
|
void trace_disable(void);
|
||||||
#define COVERAGE_OFF() do { coverage = trace_pause(); } while (0)
|
void trace_on(void);
|
||||||
|
void trace_off(void);
|
||||||
void trace_begin(void);
|
|
||||||
void trace_end(void);
|
|
||||||
uint32_t trace_pause(void);
|
|
||||||
void trace_resume(uint32_t value);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
31
trace_lbr.c
31
trace_lbr.c
@ -24,10 +24,11 @@
|
|||||||
#define MSR_IA32_LASTBRANCHFROMIP 0x1db
|
#define MSR_IA32_LASTBRANCHFROMIP 0x1db
|
||||||
#define MSR_IA32_LASTBRANCHTOIP 0x1dc
|
#define MSR_IA32_LASTBRANCHTOIP 0x1dc
|
||||||
|
|
||||||
|
int coverage = 0;
|
||||||
int msrfd;
|
int msrfd;
|
||||||
|
|
||||||
uint64_t rdmsr(uint32_t reg)
|
static uint64_t
|
||||||
{
|
rdmsr(uint32_t reg) {
|
||||||
uint64_t data = 0;
|
uint64_t data = 0;
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
@ -43,8 +44,8 @@ uint64_t rdmsr(uint32_t reg)
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wrmsr(uint32_t reg, uint64_t data)
|
static void
|
||||||
{
|
wrmsr(uint32_t reg, uint64_t data) {
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
int fd;
|
int fd;
|
||||||
fd = open("/dev/cpu/0/msr", O_WRONLY);
|
fd = open("/dev/cpu/0/msr", O_WRONLY);
|
||||||
@ -66,7 +67,8 @@ void wrmsr(uint32_t reg, uint64_t data)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_sigtrap(int signo) {
|
static void
|
||||||
|
handle_sigtrap(int signo) {
|
||||||
(void)signo;
|
(void)signo;
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
uint64_t from = rdmsr(MSR_IA32_LASTBRANCHFROMIP);
|
uint64_t from = rdmsr(MSR_IA32_LASTBRANCHFROMIP);
|
||||||
@ -86,13 +88,13 @@ void handle_sigtrap(int signo) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t set_eflags_tf(uint32_t tf);
|
void
|
||||||
|
trace_lbr_enable(void) {
|
||||||
void trace_lbr_begin(void) {
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
struct sigaction action;
|
struct sigaction action;
|
||||||
action.sa_handler = &handle_sigtrap;
|
action.sa_handler = &handle_sigtrap;
|
||||||
action.sa_flags = 0;
|
action.sa_flags = 0;
|
||||||
|
coverage = 1;
|
||||||
sigaction(SIGTRAP, &action, NULL);
|
sigaction(SIGTRAP, &action, NULL);
|
||||||
|
|
||||||
wrmsr(MSR_IA32_DEBUGCTL, MSR_IA32_DEBUGCTL_LBR + MSR_IA32_DEBUGCTL_BTF);
|
wrmsr(MSR_IA32_DEBUGCTL, MSR_IA32_DEBUGCTL_LBR + MSR_IA32_DEBUGCTL_BTF);
|
||||||
@ -106,7 +108,8 @@ void trace_lbr_begin(void) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void trace_lbr_end(void) {
|
void
|
||||||
|
trace_lbr_disable(void) {
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
wrmsr(MSR_IA32_DEBUGCTL, 0);
|
wrmsr(MSR_IA32_DEBUGCTL, 0);
|
||||||
close(msrfd);
|
close(msrfd);
|
||||||
@ -115,10 +118,12 @@ void trace_lbr_end(void) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t trace_lbr_pause(void) {
|
void
|
||||||
return set_eflags_tf(0u);
|
trace_lbr_on(void) {
|
||||||
|
set_eflags_tf(coverage);
|
||||||
}
|
}
|
||||||
|
|
||||||
void trace_lbr_resume(uint32_t value) {
|
void
|
||||||
set_eflags_tf(value);
|
trace_lbr_off(void) {
|
||||||
|
set_eflags_tf(0u);
|
||||||
}
|
}
|
||||||
|
10
trace_lbr.h
10
trace_lbr.h
@ -9,11 +9,9 @@
|
|||||||
#ifndef TRACE_LBR_H_INCLUDED
|
#ifndef TRACE_LBR_H_INCLUDED
|
||||||
#define TRACE_LBR_H_INCLUDED
|
#define TRACE_LBR_H_INCLUDED
|
||||||
|
|
||||||
#include <inttypes.h>
|
void trace_lbr_enable(void);
|
||||||
|
void trace_lbr_disable(void);
|
||||||
void trace_lbr_begin(void);
|
void trace_lbr_on(void);
|
||||||
void trace_lbr_end(void);
|
void trace_lbr_off(void);
|
||||||
uint32_t trace_lbr_pause(void);
|
|
||||||
void trace_lbr_resume(uint32_t value);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
1
umka.asm
1
umka.asm
@ -638,7 +638,6 @@ proc set_eflags_tf c uses ebx esi edi ebp, tf
|
|||||||
rol eax, 8
|
rol eax, 8
|
||||||
push eax
|
push eax
|
||||||
popfd
|
popfd
|
||||||
mov eax, edx
|
|
||||||
ret
|
ret
|
||||||
endp
|
endp
|
||||||
|
|
||||||
|
3
umka.h
3
umka.h
@ -862,6 +862,9 @@ umka_cli(void);
|
|||||||
void
|
void
|
||||||
umka_sti(void);
|
umka_sti(void);
|
||||||
|
|
||||||
|
void
|
||||||
|
set_eflags_tf(uint32_t tf);
|
||||||
|
|
||||||
#define COVERAGE_TABLE_SIZE (512*1024)
|
#define COVERAGE_TABLE_SIZE (512*1024)
|
||||||
|
|
||||||
struct coverage_branch {
|
struct coverage_branch {
|
||||||
|
21
umka_os.c
21
umka_os.c
@ -233,11 +233,9 @@ int
|
|||||||
main(int argc, char *argv[]) {
|
main(int argc, char *argv[]) {
|
||||||
(void)argc;
|
(void)argc;
|
||||||
const char *usage = "umka_os [-i <infile>] [-o <outfile>]"
|
const char *usage = "umka_os [-i <infile>] [-o <outfile>]"
|
||||||
" [-b <boardlog>] [-s <startupfile>]\n";
|
" [-b <boardlog>] [-s <startupfile>] [-c covfile]\n";
|
||||||
if (coverage) {
|
|
||||||
trace_begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
int coverage = 0;
|
||||||
int show_display = 0;
|
int show_display = 0;
|
||||||
|
|
||||||
umka_sti();
|
umka_sti();
|
||||||
@ -248,6 +246,7 @@ main(int argc, char *argv[]) {
|
|||||||
const char *infile = NULL;
|
const char *infile = NULL;
|
||||||
const char *outfile = NULL;
|
const char *outfile = NULL;
|
||||||
const char *boardlogfile = NULL;
|
const char *boardlogfile = NULL;
|
||||||
|
const char *covfile = NULL;
|
||||||
FILE *fstartup = NULL;
|
FILE *fstartup = NULL;
|
||||||
FILE *fin = stdin;
|
FILE *fin = stdin;
|
||||||
FILE *fout = stdout;
|
FILE *fout = stdout;
|
||||||
@ -257,11 +256,15 @@ main(int argc, char *argv[]) {
|
|||||||
int opt;
|
int opt;
|
||||||
optparse_init(&options, argv);
|
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) {
|
switch (opt) {
|
||||||
case 'b':
|
case 'b':
|
||||||
boardlogfile = options.optarg;
|
boardlogfile = options.optarg;
|
||||||
break;
|
break;
|
||||||
|
case 'c':
|
||||||
|
coverage = 1;
|
||||||
|
covfile = options.optarg;
|
||||||
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
show_display = 1;
|
show_display = 1;
|
||||||
break;
|
break;
|
||||||
@ -281,6 +284,10 @@ main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (coverage) {
|
||||||
|
trace_enable();
|
||||||
|
}
|
||||||
|
|
||||||
if (startupfile) {
|
if (startupfile) {
|
||||||
fstartup = fopen(startupfile, "rb");
|
fstartup = fopen(startupfile, "rb");
|
||||||
if (!fstartup) {
|
if (!fstartup) {
|
||||||
@ -429,7 +436,9 @@ main(int argc, char *argv[]) {
|
|||||||
umka_osloop(); // doesn't return
|
umka_osloop(); // doesn't return
|
||||||
|
|
||||||
if (coverage)
|
if (coverage)
|
||||||
trace_end();
|
trace_disable();
|
||||||
|
|
||||||
|
(void)covfile;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
16
umka_shell.c
16
umka_shell.c
@ -63,7 +63,9 @@ main(int argc, char **argv) {
|
|||||||
" -i infile file with commands\n"
|
" -i infile file with commands\n"
|
||||||
" -o outfile file for logs\n"
|
" -o outfile file for logs\n"
|
||||||
" -r reproducible logs (without pointers and datetime)\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;
|
const char *infile = NULL, *outfile = NULL;
|
||||||
FILE *fin = stdin;
|
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[1] = (e820entry_t){(uintptr_t)mem1, 128*1024*1024, 1};
|
||||||
kos_boot.memmap_blocks[2] = (e820entry_t){(uintptr_t)mem2, 256*1024*1024, 1};
|
kos_boot.memmap_blocks[2] = (e820entry_t){(uintptr_t)mem2, 256*1024*1024, 1};
|
||||||
*/
|
*/
|
||||||
|
int coverage = 0;
|
||||||
int reproducible = 0;
|
int reproducible = 0;
|
||||||
|
|
||||||
struct optparse options;
|
struct optparse options;
|
||||||
optparse_init(&options, argv);
|
optparse_init(&options, argv);
|
||||||
int opt;
|
int opt;
|
||||||
|
|
||||||
while ((opt = optparse(&options, "i:o:rc")) != -1) {
|
while ((opt = optparse(&options, "i:o:rc:")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'i':
|
case 'i':
|
||||||
infile = options.optarg;
|
infile = options.optarg;
|
||||||
@ -94,6 +97,7 @@ main(int argc, char **argv) {
|
|||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
coverage = 1;
|
coverage = 1;
|
||||||
|
sprintf(covfile, "%s.%i", options.optarg, getpid());
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
fputs(usage, stderr);
|
fputs(usage, stderr);
|
||||||
@ -123,15 +127,13 @@ main(int argc, char **argv) {
|
|||||||
struct umka_shell_ctx *ctx = umka_shell_init(reproducible, fin);
|
struct umka_shell_ctx *ctx = umka_shell_init(reproducible, fin);
|
||||||
|
|
||||||
if (coverage)
|
if (coverage)
|
||||||
trace_begin();
|
trace_enable();
|
||||||
|
|
||||||
run_test(ctx->shell);
|
run_test(ctx->shell);
|
||||||
|
|
||||||
if (coverage) {
|
if (coverage) {
|
||||||
trace_end();
|
trace_disable();
|
||||||
char coverage_filename[32];
|
FILE *f = fopen(covfile, "w");
|
||||||
sprintf(coverage_filename, "coverage.%i", getpid());
|
|
||||||
FILE *f = fopen(coverage_filename, "w");
|
|
||||||
fwrite(coverage_table,
|
fwrite(coverage_table,
|
||||||
COVERAGE_TABLE_SIZE * sizeof(struct coverage_branch), 1, f);
|
COVERAGE_TABLE_SIZE * sizeof(struct coverage_branch), 1, f);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
Loading…
Reference in New Issue
Block a user