diff options
author | anton <anton@cvs.openbsd.org> | 2020-08-01 08:44:58 +0000 |
---|---|---|
committer | anton <anton@cvs.openbsd.org> | 2020-08-01 08:44:58 +0000 |
commit | 3dae3500265a39b2698eaaf3c7a9eeca75ceb567 (patch) | |
tree | 5685cfefdfd7c0887da17276ea56adeed1160943 /regress/sys | |
parent | 3b7e4141b065f7e691d6b1beb58e1741ad972486 (diff) |
add kcov remote coverage tests
Diffstat (limited to 'regress/sys')
-rw-r--r-- | regress/sys/dev/kcov/Makefile | 4 | ||||
-rw-r--r-- | regress/sys/dev/kcov/kcov.c | 132 |
2 files changed, 107 insertions, 29 deletions
diff --git a/regress/sys/dev/kcov/Makefile b/regress/sys/dev/kcov/Makefile index a6c2a72bee3..623afe51258 100644 --- a/regress/sys/dev/kcov/Makefile +++ b/regress/sys/dev/kcov/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.10 2019/05/14 20:48:45 anton Exp $ +# $OpenBSD: Makefile,v 1.11 2020/08/01 08:44:57 anton Exp $ PROG= kcov WARNINGS= yes @@ -18,6 +18,8 @@ TESTS+= dying TESTS+= exec TESTS+= fork TESTS+= open +TESTS+= remote +TESTS+= remote-close TESTS+= state REGRESS_SETUP_ONCE= setup diff --git a/regress/sys/dev/kcov/kcov.c b/regress/sys/dev/kcov/kcov.c index 87b3e6e17d1..d210d57651d 100644 --- a/regress/sys/dev/kcov/kcov.c +++ b/regress/sys/dev/kcov/kcov.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kcov.c,v 1.12 2019/05/19 09:34:59 anton Exp $ */ +/* $OpenBSD: kcov.c,v 1.13 2020/08/01 08:44:57 anton Exp $ */ /* * Copyright (c) 2018 Anton Lindqvist <anton@openbsd.org> @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <sys/types.h> +#include <sys/event.h> #include <sys/ioctl.h> #include <sys/kcov.h> #include <sys/mman.h> @@ -36,13 +38,15 @@ struct context { unsigned long c_bufsize; }; -static int test_close(const struct context *); -static int test_coverage(const struct context *); -static int test_dying(const struct context *); -static int test_exec(const struct context *); -static int test_fork(const struct context *); -static int test_open(const struct context *); -static int test_state(const struct context *); +static int test_close(struct context *); +static int test_coverage(struct context *); +static int test_dying(struct context *); +static int test_exec(struct context *); +static int test_fork(struct context *); +static int test_open(struct context *); +static int test_remote(struct context *); +static int test_remote_close(struct context *); +static int test_state(struct context *); static int check_coverage(const unsigned long *, int, unsigned long, int); static void do_syscall(void); @@ -59,17 +63,19 @@ main(int argc, char *argv[]) { struct { const char *name; - int (*fn)(const struct context *); + int (*fn)(struct context *); int coverage; /* test must produce coverage */ } tests[] = { - { "close", test_close, 0 }, - { "coverage", test_coverage, 1 }, - { "dying", test_dying, 1 }, - { "exec", test_exec, 1 }, - { "fork", test_fork, 1 }, - { "open", test_open, 0 }, - { "state", test_state, 1 }, - { NULL, NULL, 0 }, + { "close", test_close, 0 }, + { "coverage", test_coverage, 1 }, + { "dying", test_dying, 1 }, + { "exec", test_exec, 1 }, + { "fork", test_fork, 1 }, + { "open", test_open, 0 }, + { "remote", test_remote, 1 }, + { "remote-close", test_remote_close, 0 }, + { "state", test_state, 1 }, + { NULL, NULL, 0 }, }; struct context ctx; const char *errstr; @@ -154,7 +160,10 @@ main(int argc, char *argv[]) if (munmap(cover, ctx.c_bufsize * sizeof(unsigned long)) == -1) err(1, "munmap"); - close(ctx.c_fd); + if (ctx.c_fd != -1) { + if (close(ctx.c_fd) == -1) + err(1, "close"); + } return error; } @@ -260,7 +269,7 @@ kcov_disable(int fd) * Close before mmap. */ static int -test_close(const struct context *ctx) +test_close(struct context *ctx) { int fd; @@ -273,7 +282,7 @@ test_close(const struct context *ctx) * Coverage of current thread. */ static int -test_coverage(const struct context *ctx) +test_coverage(struct context *ctx) { kcov_enable(ctx->c_fd, ctx->c_mode); do_syscall(); @@ -284,7 +293,7 @@ test_coverage(const struct context *ctx) static void * closer(void *arg) { - const struct context *ctx = arg; + struct context *ctx = arg; close(ctx->c_fd); return NULL; @@ -294,7 +303,7 @@ closer(void *arg) * Close kcov descriptor in another thread during tracing. */ static int -test_dying(const struct context *ctx) +test_dying(struct context *ctx) { pthread_t th; int error; @@ -306,22 +315,24 @@ test_dying(const struct context *ctx) if ((error = pthread_join(th, NULL))) errc(1, error, "pthread_join"); + error = 0; if (close(ctx->c_fd) == -1) { if (errno != EBADF) err(1, "close"); } else { warnx("expected kcov descriptor to be closed"); - return 1; + error = 1; } + ctx->c_fd = -1; - return 0; + return error; } /* * Coverage of thread after exec. */ static int -test_exec(const struct context *ctx) +test_exec(struct context *ctx) { pid_t pid; int status; @@ -356,7 +367,7 @@ test_exec(const struct context *ctx) * Coverage of thread after fork. */ static int -test_fork(const struct context *ctx) +test_fork(struct context *ctx) { pid_t pid; int status; @@ -391,7 +402,7 @@ test_fork(const struct context *ctx) * Open /dev/kcov more than once. */ static int -test_open(const struct context *ctx) +test_open(struct context *ctx) { unsigned long *cover; int fd; @@ -419,10 +430,75 @@ test_open(const struct context *ctx) } /* + * Remote taskq coverage. One reliable way to trigger a task on behalf of the + * running process is to monitor a kqueue file descriptor using kqueue. + */ +static int +test_remote(struct context *ctx) +{ + struct kio_remote_attach remote = { + .subsystem = KCOV_REMOTE_COMMON, + .id = 0, + }; + struct kevent kev; + int kq1, kq2, pip[2]; + int x = 0; + + if (ioctl(ctx->c_fd, KIOREMOTEATTACH, &remote) == -1) + err(1, "ioctl: KIOREMOTEATTACH"); + kcov_enable(ctx->c_fd, ctx->c_mode); + + kq1 = kqueue(); + if (kq1 == -1) + err(1, "kqueue"); + kq2 = kqueue(); + if (kq1 == -1) + err(1, "kqueue"); + EV_SET(&kev, kq2, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL); + if (kevent(kq1, &kev, 1, NULL, 0, NULL) == -1) + err(1, "kqueue"); + + if (pipe(pip) == -1) + err(1, "pipe"); + + EV_SET(&kev, pip[0], EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL); + if (kevent(kq2, &kev, 1, NULL, 0, NULL) == -1) + err(1, "kqueue"); + (void)write(pip[1], &x, sizeof(x)); + + if (kevent(kq1, NULL, 0, &kev, 1, NULL) == -1) + err(1, "kevent"); + + kcov_disable(ctx->c_fd); + + return 0; +} + +/* + * Close with remote coverage enabled. + */ +static int +test_remote_close(struct context *ctx) +{ + struct kio_remote_attach remote = { + .subsystem = KCOV_REMOTE_COMMON, + .id = 0, + }; + + if (ioctl(ctx->c_fd, KIOREMOTEATTACH, &remote) == -1) + err(1, "ioctl: KIOREMOTEATTACH"); + kcov_enable(ctx->c_fd, ctx->c_mode); + if (close(ctx->c_fd) == -1) + err(1, "close"); + ctx->c_fd = kcov_open(); + return 0; +} + +/* * State transitions. */ static int -test_state(const struct context *ctx) +test_state(struct context *ctx) { if (ioctl(ctx->c_fd, KIOENABLE, &ctx->c_mode) == -1) { warn("KIOSETBUFSIZE -> KIOENABLE"); |