Module Name: src Committed By: kamil Date: Thu Dec 1 20:11:17 UTC 2016
Modified Files: src/tests/kernel: Makefile t_ptrace_wait.c Added Files: src/tests/kernel: t_ptrace_amd64_wait.c t_ptrace_amd64_wait3.c t_ptrace_amd64_wait4.c t_ptrace_amd64_wait6.c t_ptrace_amd64_waitid.c t_ptrace_amd64_waitpid.c t_ptrace_wait.h Log Message: Add new test file t_ptrace_amd64_wait.c and refactor t_ptrace_*wait* tests Clone t_ptrace_wait.c to t_ptrace_amd64_wait.c and put common parts to t_ptrace_wait.h. The t_ptrace_amd64_wait.c file is dedicated to hold amd64-specific tests for the ptrace(2) interface. Add new basic test dbreg1 in t_ptrace_amd64_wait{,3,4,6,id,pid}: Verify plain PT_GETDBREGS with printing Debug Registers Fix evbarm64-aarch64 issue pointed by <christos>, kill1 and kill2 tests must be defined without PT_STEP guards. Sponsored by <The NetBSD Foundation> To generate a diff of this commit: cvs rdiff -u -r1.41 -r1.42 src/tests/kernel/Makefile cvs rdiff -u -r0 -r1.1 src/tests/kernel/t_ptrace_amd64_wait.c \ src/tests/kernel/t_ptrace_amd64_wait3.c \ src/tests/kernel/t_ptrace_amd64_wait4.c \ src/tests/kernel/t_ptrace_amd64_wait6.c \ src/tests/kernel/t_ptrace_amd64_waitid.c \ src/tests/kernel/t_ptrace_amd64_waitpid.c \ src/tests/kernel/t_ptrace_wait.h cvs rdiff -u -r1.36 -r1.37 src/tests/kernel/t_ptrace_wait.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/tests/kernel/Makefile diff -u src/tests/kernel/Makefile:1.41 src/tests/kernel/Makefile:1.42 --- src/tests/kernel/Makefile:1.41 Mon Nov 7 21:09:03 2016 +++ src/tests/kernel/Makefile Thu Dec 1 20:11:17 2016 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.41 2016/11/07 21:09:03 kamil Exp $ +# $NetBSD: Makefile,v 1.42 2016/12/01 20:11:17 kamil Exp $ NOMAN= # defined @@ -23,6 +23,15 @@ TESTS_C+= t_subr_prf TESTS_C+= t_kauth_pr_47598 TESTS_C+= t_sysctl +.if (${MACHINE} == "amd64") +TESTS_C+= t_ptrace_amd64_wait +TESTS_C+= t_ptrace_amd64_wait3 +TESTS_C+= t_ptrace_amd64_wait4 +TESTS_C+= t_ptrace_amd64_wait6 +TESTS_C+= t_ptrace_amd64_waitid +TESTS_C+= t_ptrace_amd64_waitpid +.endif + TESTS_SH= t_umount TESTS_SH+= t_umountstress TESTS_SH+= t_ps_strings Index: src/tests/kernel/t_ptrace_wait.c diff -u src/tests/kernel/t_ptrace_wait.c:1.36 src/tests/kernel/t_ptrace_wait.c:1.37 --- src/tests/kernel/t_ptrace_wait.c:1.36 Wed Nov 30 21:12:53 2016 +++ src/tests/kernel/t_ptrace_wait.c Thu Dec 1 20:11:17 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: t_ptrace_wait.c,v 1.36 2016/11/30 21:12:53 kamil Exp $ */ +/* $NetBSD: t_ptrace_wait.c,v 1.37 2016/12/01 20:11:17 kamil Exp $ */ /*- * Copyright (c) 2016 The NetBSD Foundation, Inc. @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: t_ptrace_wait.c,v 1.36 2016/11/30 21:12:53 kamil Exp $"); +__RCSID("$NetBSD: t_ptrace_wait.c,v 1.37 2016/12/01 20:11:17 kamil Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -50,358 +50,7 @@ __RCSID("$NetBSD: t_ptrace_wait.c,v 1.36 #include "../h_macros.h" -/* Detect plain wait(2) use-case */ -#if !defined(TWAIT_WAITPID) && \ - !defined(TWAIT_WAITID) && \ - !defined(TWAIT_WAIT3) && \ - !defined(TWAIT_WAIT4) && \ - !defined(TWAIT_WAIT6) -#define TWAIT_WAIT -#endif - -/* - * There are two classes of wait(2)-like functions: - * - wait4(2)-like accepting pid_t, optional options parameter, struct rusage* - * - wait6(2)-like accepting idtype_t, id_t, struct wrusage, mandatory options - * - * The TWAIT_FNAME value is to be used for convenience in debug messages. - * - * The TWAIT_GENERIC() macro is designed to reuse the same unmodified - * code with as many wait(2)-like functions as possible. - * - * In a common use-case wait4(2) and wait6(2)-like function can work the almost - * the same way, however there are few important differences: - * wait6(2) must specify P_PID for idtype to match wpid from wait4(2). - * To behave like wait4(2), wait6(2) the 'options' to wait must include - * WEXITED|WTRUNCATED. - * - * There are two helper macros (they purpose it to mach more than one - * wait(2)-like function): - * The TWAIT_HAVE_STATUS - specifies whether a function can retrieve - * status (as integer value). - * The TWAIT_HAVE_PID - specifies whether a function can request - * exact process identifier - * The TWAIT_HAVE_RUSAGE - specifies whether a function can request - * the struct rusage value - * - */ - -#if defined(TWAIT_WAIT) -# define TWAIT_FNAME "wait" -# define TWAIT_WAIT4TYPE(a,b,c,d) wait((b)) -# define TWAIT_GENERIC(a,b,c) wait((b)) -# define TWAIT_HAVE_STATUS 1 -#elif defined(TWAIT_WAITPID) -# define TWAIT_FNAME "waitpid" -# define TWAIT_WAIT4TYPE(a,b,c,d) waitpid((a),(b),(c)) -# define TWAIT_GENERIC(a,b,c) waitpid((a),(b),(c)) -# define TWAIT_HAVE_PID 1 -# define TWAIT_HAVE_STATUS 1 -#elif defined(TWAIT_WAITID) -# define TWAIT_FNAME "waitid" -# define TWAIT_GENERIC(a,b,c) \ - waitid(P_PID,(a),NULL,(c)|WEXITED|WTRAPPED) -# define TWAIT_WAIT6TYPE(a,b,c,d,e,f) waitid((a),(b),(f),(d)) -# define TWAIT_HAVE_PID 1 -#elif defined(TWAIT_WAIT3) -# define TWAIT_FNAME "wait3" -# define TWAIT_WAIT4TYPE(a,b,c,d) wait3((b),(c),(d)) -# define TWAIT_GENERIC(a,b,c) wait3((b),(c),NULL) -# define TWAIT_HAVE_STATUS 1 -# define TWAIT_HAVE_RUSAGE 1 -#elif defined(TWAIT_WAIT4) -# define TWAIT_FNAME "wait4" -# define TWAIT_WAIT4TYPE(a,b,c,d) wait4((a),(b),(c),(d)) -# define TWAIT_GENERIC(a,b,c) wait4((a),(b),(c),NULL) -# define TWAIT_HAVE_PID 1 -# define TWAIT_HAVE_STATUS 1 -# define TWAIT_HAVE_RUSAGE 1 -#elif defined(TWAIT_WAIT6) -# define TWAIT_FNAME "wait6" -# define TWAIT_WAIT6TYPE(a,b,c,d,e,f) wait6((a),(b),(c),(d),(e),(f)) -# define TWAIT_GENERIC(a,b,c) \ - wait6(P_PID,(a),(b),(c)|WEXITED|WTRAPPED,NULL,NULL) -# define TWAIT_HAVE_PID 1 -# define TWAIT_HAVE_STATUS 1 -#endif - -/* - * There are 3 groups of tests: - * - TWAIT_GENERIC() (wait, wait2, waitpid, wait3, wait4, wait6) - * - TWAIT_WAIT4TYPE() (wait2, waitpid, wait3, wait4) - * - TWAIT_WAIT6TYPE() (waitid, wait6) - * - * Tests only in the above categories are allowed. However some tests are not - * possible in the context requested functionality to be verified, therefore - * there are helper macros: - * - TWAIT_HAVE_PID (wait2, waitpid, waitid, wait4, wait6) - * - TWAIT_HAVE_STATUS (wait, wait2, waitpid, wait3, wait4, wait6) - * - TWAIT_HAVE_RUSAGE (wait3, wait4) - * - TWAIT_HAVE_RETPID (wait, wait2, waitpid, wait3, wait4, wait6) - * - * If there is an intention to test e.g. wait6(2) specific features in the - * ptrace(2) context, find the most matching group and with #ifdefs reduce - * functionality of less featured than wait6(2) interface (TWAIT_WAIT6TYPE). - * - * For clarity never use negative preprocessor checks, like: - * #if !defined(TWAIT_WAIT4) - * always refer to checks for positive values. - */ - -/* - * A child process cannot call atf functions and expect them to magically - * work like in the parent. - * The printf(3) messaging from a child will not work out of the box as well - * without estabilishing a communication protocol with its parent. To not - * overcomplicate the tests - do not log from a child and use err(3)/errx(3) - * wrapped with FORKEE_ASSERT()/FORKEE_ASSERTX() as that is guaranteed to work. - */ -#define FORKEE_ASSERT_EQ(x, y) \ -do { \ - int ret = (x) == (y); \ - if (!ret) \ - errx(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: " \ - "%s(%d) == %s(%d)", __FILE__, __LINE__, __func__, \ - #x, (int)x, #y, (int)y); \ -} while (/*CONSTCOND*/0) - -#define FORKEE_ASSERTX(x) \ -do { \ - int ret = (x); \ - if (!ret) \ - errx(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: %s",\ - __FILE__, __LINE__, __func__, #x); \ -} while (/*CONSTCOND*/0) - -#define FORKEE_ASSERT(x) \ -do { \ - int ret = (x); \ - if (!ret) \ - err(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: %s",\ - __FILE__, __LINE__, __func__, #x); \ -} while (/*CONSTCOND*/0) - -/* - * Simplify logic for functions using general purpose registers add HAVE_GPREGS - * - * For platforms that do not implement all needed calls for simplicity assume - * that they are unsupported at all. - */ -#if defined(PT_GETREGS) \ - && defined(PT_SETREGS) \ - && defined(PTRACE_REG_PC) \ - && defined(PTRACE_REG_SET_PC) \ - && defined(PTRACE_REG_SP) \ - && defined(PTRACE_REG_INTRV) -#define HAVE_GPREGS -#endif - -/* Add guards for floating point registers */ -#if defined(PT_GETFPREGS) \ - && defined(PT_SETFPREGS) -#define HAVE_FPREGS -#endif - -/* Add guards for cpu debug registers */ -#if defined(PT_GETDBREGS) \ - && defined(PT_SETDBREGS) -#define HAVE_DBREGS -#endif - -/* - * If waitid(2) returns because one or more processes have a state change to - * report, 0 is returned. If an error is detected, a value of -1 is returned - * and errno is set to indicate the error. If WNOHANG is specified and there - * are no stopped, continued or exited children, 0 is returned. - */ -#if defined(TWAIT_WAITID) -#define TWAIT_REQUIRE_SUCCESS(a,b) ATF_REQUIRE((a) == 0) -#define TWAIT_REQUIRE_FAILURE(a,b) ATF_REQUIRE_ERRNO((a),(b) == -1) -#define FORKEE_REQUIRE_SUCCESS(a,b) FORKEE_ASSERTX((a) == 0) -#define FORKEE_REQUIRE_FAILURE(a,b) \ - FORKEE_ASSERTX(((a) == errno) && ((b) == -1)) -#else -#define TWAIT_REQUIRE_SUCCESS(a,b) ATF_REQUIRE((a) == (b)) -#define TWAIT_REQUIRE_FAILURE(a,b) ATF_REQUIRE_ERRNO((a),(b) == -1) -#define FORKEE_REQUIRE_SUCCESS(a,b) FORKEE_ASSERTX((a) == (b)) -#define FORKEE_REQUIRE_FAILURE(a,b) \ - FORKEE_ASSERTX(((a) == errno) && ((b) == -1)) -#endif - -/* - * Helper tools to verify whether status reports exited value - */ -#if TWAIT_HAVE_STATUS -static void __used -validate_status_exited(int status, int expected) -{ - ATF_REQUIRE_MSG(WIFEXITED(status), "Reported exited process"); - ATF_REQUIRE_MSG(!WIFCONTINUED(status), "Reported continued process"); - ATF_REQUIRE_MSG(!WIFSIGNALED(status), "Reported signaled process"); - ATF_REQUIRE_MSG(!WIFSTOPPED(status), "Reported stopped process"); - - ATF_REQUIRE_EQ_MSG(WEXITSTATUS(status), expected, - "The process has exited with invalid value %d != %d", - WEXITSTATUS(status), expected); -} - -static void __used -forkee_status_exited(int status, int expected) -{ - FORKEE_ASSERTX(WIFEXITED(status)); - FORKEE_ASSERTX(!WIFCONTINUED(status)); - FORKEE_ASSERTX(!WIFSIGNALED(status)); - FORKEE_ASSERTX(!WIFSTOPPED(status)); - - FORKEE_ASSERT_EQ(WEXITSTATUS(status), expected); -} - -static void __used -validate_status_continued(int status) -{ - ATF_REQUIRE_MSG(!WIFEXITED(status), "Reported exited process"); - ATF_REQUIRE_MSG(WIFCONTINUED(status), "Reported continued process"); - ATF_REQUIRE_MSG(!WIFSIGNALED(status), "Reported signaled process"); - ATF_REQUIRE_MSG(!WIFSTOPPED(status), "Reported stopped process"); -} - -static void __used -forkee_status_continued(int status) -{ - FORKEE_ASSERTX(!WIFEXITED(status)); - FORKEE_ASSERTX(WIFCONTINUED(status)); - FORKEE_ASSERTX(!WIFSIGNALED(status)); - FORKEE_ASSERTX(!WIFSTOPPED(status)); -} - -static void __used -validate_status_signaled(int status, int expected_termsig, int expected_core) -{ - ATF_REQUIRE_MSG(!WIFEXITED(status), "Reported exited process"); - ATF_REQUIRE_MSG(!WIFCONTINUED(status), "Reported continued process"); - ATF_REQUIRE_MSG(WIFSIGNALED(status), "Reported signaled process"); - ATF_REQUIRE_MSG(!WIFSTOPPED(status), "Reported stopped process"); - - ATF_REQUIRE_EQ_MSG(WTERMSIG(status), expected_termsig, - "Unexpected signal received"); - - ATF_REQUIRE_EQ_MSG(WCOREDUMP(status), expected_core, - "Unexpectedly core file %s generated", expected_core ? "not" : ""); -} - -static void __used -forkee_status_signaled(int status, int expected_termsig, int expected_core) -{ - FORKEE_ASSERTX(!WIFEXITED(status)); - FORKEE_ASSERTX(!WIFCONTINUED(status)); - FORKEE_ASSERTX(WIFSIGNALED(status)); - FORKEE_ASSERTX(!WIFSTOPPED(status)); - - FORKEE_ASSERT_EQ(WTERMSIG(status), expected_termsig); - FORKEE_ASSERT_EQ(WCOREDUMP(status), expected_core); -} - -static void __used -validate_status_stopped(int status, int expected) -{ - ATF_REQUIRE_MSG(!WIFEXITED(status), "Reported exited process"); - ATF_REQUIRE_MSG(!WIFCONTINUED(status), "Reported continued process"); - ATF_REQUIRE_MSG(!WIFSIGNALED(status), "Reported signaled process"); - ATF_REQUIRE_MSG(WIFSTOPPED(status), "Reported stopped process"); - - char st[128], ex[128]; - strlcpy(st, strsignal(WSTOPSIG(status)), sizeof(st)); - strlcpy(ex, strsignal(expected), sizeof(ex)); - - ATF_REQUIRE_EQ_MSG(WSTOPSIG(status), expected, - "Unexpected stop signal received [%s] != [%s]", st, ex); -} - -static void __used -forkee_status_stopped(int status, int expected) -{ - FORKEE_ASSERTX(!WIFEXITED(status)); - FORKEE_ASSERTX(!WIFCONTINUED(status)); - FORKEE_ASSERTX(!WIFSIGNALED(status)); - FORKEE_ASSERTX(WIFSTOPPED(status)); - - FORKEE_ASSERT_EQ(WSTOPSIG(status), expected); -} -#else -#define validate_status_exited(a,b) -#define forkee_status_exited(a,b) -#define validate_status_continued(a,b) -#define forkee_status_continued(a,b) -#define validate_status_signaled(a,b,c) -#define forkee_status_signaled(a,b,c) -#define validate_status_stopped(a,b) -#define forkee_status_stopped(a,b) -#endif - -#if defined(TWAIT_HAVE_PID) -/* This function is currently designed to be run in the main/parent process */ -static void -await_zombie(pid_t process) -{ - struct kinfo_proc2 p; - size_t len = sizeof(p); - - const int name[] = { - [0] = CTL_KERN, - [1] = KERN_PROC2, - [2] = KERN_PROC_PID, - [3] = process, - [4] = sizeof(p), - [5] = 1 - }; - - const size_t namelen = __arraycount(name); - - /* Await the process becoming a zombie */ - while(1) { - ATF_REQUIRE(sysctl(name, namelen, &p, &len, NULL, 0) == 0); - - if (p.p_stat == LSZOMB) - break; - - ATF_REQUIRE(usleep(1000) == 0); - } -} -#endif - -/* Happy number sequence -- this function is used to just consume cpu cycles */ -#define HAPPY_NUMBER 1 - -/* If n is not happy then its sequence ends in the cycle: - * 4, 16, 37, 58, 89, 145, 42, 20, 4, ... */ -#define SAD_NUMBER 4 - -/* Calculate the sum of the squares of the digits of n */ -static unsigned __used -dsum(unsigned n) -{ - unsigned sum, x; - for (sum = 0; n; n /= 10) { - x = n % 10; - sum += x * x; - } - return sum; -} - -static int __used -check_happy(unsigned n) -{ - for (;;) { - unsigned total = dsum(n); - - if (total == HAPPY_NUMBER) - return 1; - if (total == SAD_NUMBER) - return 0; - - n = total; - } -} +#include "t_ptrace_wait.h" ATF_TC(traceme1); ATF_TC_HEAD(traceme1, tc) @@ -4971,36 +4620,6 @@ ATF_TC_BODY(kill2, tc) TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); } -#if defined(TWAIT_HAVE_PID) -#define ATF_TP_ADD_TC_HAVE_PID(a,b) ATF_TP_ADD_TC(a,b) -#else -#define ATF_TP_ADD_TC_HAVE_PID(a,b) -#endif - -#if defined(HAVE_GPREGS) -#define ATF_TP_ADD_TC_HAVE_GPREGS(a,b) ATF_TP_ADD_TC(a,b) -#else -#define ATF_TP_ADD_TC_HAVE_GPREGS(a,b) -#endif - -#if defined(HAVE_FPREGS) -#define ATF_TP_ADD_TC_HAVE_FPREGS(a,b) ATF_TP_ADD_TC(a,b) -#else -#define ATF_TP_ADD_TC_HAVE_FPREGS(a,b) -#endif - -#if defined(HAVE_DBREGS) -#define ATF_TP_ADD_TC_HAVE_DBREGS(a,b) ATF_TP_ADD_TC(a,b) -#else -#define ATF_TP_ADD_TC_HAVE_DBREGS(a,b) -#endif - -#if defined(PT_STEP) -#define ATF_TP_ADD_TC_PT_STEP(a,b) ATF_TP_ADD_TC(a,b) -#else -#define ATF_TP_ADD_TC_PT_STEP(a,b) -#endif - ATF_TP_ADD_TCS(tp) { setvbuf(stdout, NULL, _IONBF, 0); @@ -5080,8 +4699,8 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC_PT_STEP(tp, step3); ATF_TP_ADD_TC_PT_STEP(tp, step4); - ATF_TP_ADD_TC_PT_STEP(tp, kill1); - ATF_TP_ADD_TC_PT_STEP(tp, kill2); + ATF_TP_ADD_TC(tp, kill1); + ATF_TP_ADD_TC(tp, kill2); return atf_no_error(); } Added files: Index: src/tests/kernel/t_ptrace_amd64_wait.c diff -u /dev/null src/tests/kernel/t_ptrace_amd64_wait.c:1.1 --- /dev/null Thu Dec 1 20:11:17 2016 +++ src/tests/kernel/t_ptrace_amd64_wait.c Thu Dec 1 20:11:17 2016 @@ -0,0 +1,122 @@ +/* $NetBSD: t_ptrace_amd64_wait.c,v 1.1 2016/12/01 20:11:17 kamil Exp $ */ + +/*- + * Copyright (c) 2016 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_ptrace_amd64_wait.c,v 1.1 2016/12/01 20:11:17 kamil Exp $"); + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/ptrace.h> +#include <sys/resource.h> +#include <sys/stat.h> +#include <sys/sysctl.h> +#include <sys/wait.h> +#include <machine/reg.h> +#include <err.h> +#include <errno.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <strings.h> +#include <unistd.h> + +#include <atf-c.h> + +#include "../h_macros.h" + +#include "t_ptrace_wait.h" + +#if defined(HAVE_DBREGS) +ATF_TC(dbregs1); +ATF_TC_HEAD(dbregs1, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify plain PT_GETDBREGS with printing Debug Registers"); +} + +ATF_TC_BODY(dbregs1, tc) +{ + const int exitval = 5; + const int sigval = SIGSTOP; + pid_t child, wpid; +#if defined(TWAIT_HAVE_STATUS) + int status; +#endif + struct dbreg r; + size_t i; + + printf("Before forking process PID=%d\n", getpid()); + child = atf_utils_fork(); + if (child == 0) { + printf("Before calling PT_TRACE_ME from child %d\n", getpid()); + FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); + + printf("Before raising %s from child\n", strsignal(sigval)); + FORKEE_ASSERT(raise(sigval) == 0); + + printf("Before exiting of the child process\n"); + _exit(exitval); + } + printf("Parent process PID=%d, child's PID=%d\n", getpid(), child); + + printf("Before calling %s() for the child\n", TWAIT_FNAME); + TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); + + validate_status_stopped(status, sigval); + + printf("Call GETDBREGS for the child process\n"); + ATF_REQUIRE(ptrace(PT_GETDBREGS, child, &r, 0) != -1); + + printf("State of the debug registers:\n"); + for (i = 0; i < __arraycount(r.dbregs); i++) + printf("r[%zu]=%#lx\n", i, r.dbregs[i]); + + printf("Before resuming the child process where it left off and " + "without signal to be sent\n"); + ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); + + printf("Before calling %s() for the child\n", TWAIT_FNAME); + TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); + + validate_status_exited(status, exitval); + + printf("Before calling %s() for the child\n", TWAIT_FNAME); + TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); +} +#endif + +ATF_TP_ADD_TCS(tp) +{ + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); + + ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs1); + + return atf_no_error(); +} Index: src/tests/kernel/t_ptrace_amd64_wait3.c diff -u /dev/null src/tests/kernel/t_ptrace_amd64_wait3.c:1.1 --- /dev/null Thu Dec 1 20:11:17 2016 +++ src/tests/kernel/t_ptrace_amd64_wait3.c Thu Dec 1 20:11:17 2016 @@ -0,0 +1,30 @@ +/* $NetBSD: t_ptrace_amd64_wait3.c,v 1.1 2016/12/01 20:11:17 kamil Exp $ */ + +/*- + * Copyright (c) 2016 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define TWAIT_WAIT3 +#include "t_ptrace_amd64_wait.c" Index: src/tests/kernel/t_ptrace_amd64_wait4.c diff -u /dev/null src/tests/kernel/t_ptrace_amd64_wait4.c:1.1 --- /dev/null Thu Dec 1 20:11:17 2016 +++ src/tests/kernel/t_ptrace_amd64_wait4.c Thu Dec 1 20:11:17 2016 @@ -0,0 +1,30 @@ +/* $NetBSD: t_ptrace_amd64_wait4.c,v 1.1 2016/12/01 20:11:17 kamil Exp $ */ + +/*- + * Copyright (c) 2016 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define TWAIT_WAIT4 +#include "t_ptrace_amd64_wait.c" Index: src/tests/kernel/t_ptrace_amd64_wait6.c diff -u /dev/null src/tests/kernel/t_ptrace_amd64_wait6.c:1.1 --- /dev/null Thu Dec 1 20:11:17 2016 +++ src/tests/kernel/t_ptrace_amd64_wait6.c Thu Dec 1 20:11:17 2016 @@ -0,0 +1,30 @@ +/* $NetBSD: t_ptrace_amd64_wait6.c,v 1.1 2016/12/01 20:11:17 kamil Exp $ */ + +/*- + * Copyright (c) 2016 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define TWAIT_WAIT6 +#include "t_ptrace_amd64_wait.c" Index: src/tests/kernel/t_ptrace_amd64_waitid.c diff -u /dev/null src/tests/kernel/t_ptrace_amd64_waitid.c:1.1 --- /dev/null Thu Dec 1 20:11:17 2016 +++ src/tests/kernel/t_ptrace_amd64_waitid.c Thu Dec 1 20:11:17 2016 @@ -0,0 +1,30 @@ +/* $NetBSD: t_ptrace_amd64_waitid.c,v 1.1 2016/12/01 20:11:17 kamil Exp $ */ + +/*- + * Copyright (c) 2016 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define TWAIT_WAITID +#include "t_ptrace_amd64_wait.c" Index: src/tests/kernel/t_ptrace_amd64_waitpid.c diff -u /dev/null src/tests/kernel/t_ptrace_amd64_waitpid.c:1.1 --- /dev/null Thu Dec 1 20:11:17 2016 +++ src/tests/kernel/t_ptrace_amd64_waitpid.c Thu Dec 1 20:11:17 2016 @@ -0,0 +1,30 @@ +/* $NetBSD: t_ptrace_amd64_waitpid.c,v 1.1 2016/12/01 20:11:17 kamil Exp $ */ + +/*- + * Copyright (c) 2016 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define TWAIT_WAITPID +#include "t_ptrace_amd64_wait.c" Index: src/tests/kernel/t_ptrace_wait.h diff -u /dev/null src/tests/kernel/t_ptrace_wait.h:1.1 --- /dev/null Thu Dec 1 20:11:17 2016 +++ src/tests/kernel/t_ptrace_wait.h Thu Dec 1 20:11:17 2016 @@ -0,0 +1,408 @@ +/* $NetBSD: t_ptrace_wait.h,v 1.1 2016/12/01 20:11:17 kamil Exp $ */ + +/*- + * Copyright (c) 2016 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* Detect plain wait(2) use-case */ +#if !defined(TWAIT_WAITPID) && \ + !defined(TWAIT_WAITID) && \ + !defined(TWAIT_WAIT3) && \ + !defined(TWAIT_WAIT4) && \ + !defined(TWAIT_WAIT6) +#define TWAIT_WAIT +#endif + +/* + * There are two classes of wait(2)-like functions: + * - wait4(2)-like accepting pid_t, optional options parameter, struct rusage* + * - wait6(2)-like accepting idtype_t, id_t, struct wrusage, mandatory options + * + * The TWAIT_FNAME value is to be used for convenience in debug messages. + * + * The TWAIT_GENERIC() macro is designed to reuse the same unmodified + * code with as many wait(2)-like functions as possible. + * + * In a common use-case wait4(2) and wait6(2)-like function can work the almost + * the same way, however there are few important differences: + * wait6(2) must specify P_PID for idtype to match wpid from wait4(2). + * To behave like wait4(2), wait6(2) the 'options' to wait must include + * WEXITED|WTRUNCATED. + * + * There are two helper macros (they purpose it to mach more than one + * wait(2)-like function): + * The TWAIT_HAVE_STATUS - specifies whether a function can retrieve + * status (as integer value). + * The TWAIT_HAVE_PID - specifies whether a function can request + * exact process identifier + * The TWAIT_HAVE_RUSAGE - specifies whether a function can request + * the struct rusage value + * + */ + +#if defined(TWAIT_WAIT) +# define TWAIT_FNAME "wait" +# define TWAIT_WAIT4TYPE(a,b,c,d) wait((b)) +# define TWAIT_GENERIC(a,b,c) wait((b)) +# define TWAIT_HAVE_STATUS 1 +#elif defined(TWAIT_WAITPID) +# define TWAIT_FNAME "waitpid" +# define TWAIT_WAIT4TYPE(a,b,c,d) waitpid((a),(b),(c)) +# define TWAIT_GENERIC(a,b,c) waitpid((a),(b),(c)) +# define TWAIT_HAVE_PID 1 +# define TWAIT_HAVE_STATUS 1 +#elif defined(TWAIT_WAITID) +# define TWAIT_FNAME "waitid" +# define TWAIT_GENERIC(a,b,c) \ + waitid(P_PID,(a),NULL,(c)|WEXITED|WTRAPPED) +# define TWAIT_WAIT6TYPE(a,b,c,d,e,f) waitid((a),(b),(f),(d)) +# define TWAIT_HAVE_PID 1 +#elif defined(TWAIT_WAIT3) +# define TWAIT_FNAME "wait3" +# define TWAIT_WAIT4TYPE(a,b,c,d) wait3((b),(c),(d)) +# define TWAIT_GENERIC(a,b,c) wait3((b),(c),NULL) +# define TWAIT_HAVE_STATUS 1 +# define TWAIT_HAVE_RUSAGE 1 +#elif defined(TWAIT_WAIT4) +# define TWAIT_FNAME "wait4" +# define TWAIT_WAIT4TYPE(a,b,c,d) wait4((a),(b),(c),(d)) +# define TWAIT_GENERIC(a,b,c) wait4((a),(b),(c),NULL) +# define TWAIT_HAVE_PID 1 +# define TWAIT_HAVE_STATUS 1 +# define TWAIT_HAVE_RUSAGE 1 +#elif defined(TWAIT_WAIT6) +# define TWAIT_FNAME "wait6" +# define TWAIT_WAIT6TYPE(a,b,c,d,e,f) wait6((a),(b),(c),(d),(e),(f)) +# define TWAIT_GENERIC(a,b,c) \ + wait6(P_PID,(a),(b),(c)|WEXITED|WTRAPPED,NULL,NULL) +# define TWAIT_HAVE_PID 1 +# define TWAIT_HAVE_STATUS 1 +#endif + +/* + * There are 3 groups of tests: + * - TWAIT_GENERIC() (wait, wait2, waitpid, wait3, wait4, wait6) + * - TWAIT_WAIT4TYPE() (wait2, waitpid, wait3, wait4) + * - TWAIT_WAIT6TYPE() (waitid, wait6) + * + * Tests only in the above categories are allowed. However some tests are not + * possible in the context requested functionality to be verified, therefore + * there are helper macros: + * - TWAIT_HAVE_PID (wait2, waitpid, waitid, wait4, wait6) + * - TWAIT_HAVE_STATUS (wait, wait2, waitpid, wait3, wait4, wait6) + * - TWAIT_HAVE_RUSAGE (wait3, wait4) + * - TWAIT_HAVE_RETPID (wait, wait2, waitpid, wait3, wait4, wait6) + * + * If there is an intention to test e.g. wait6(2) specific features in the + * ptrace(2) context, find the most matching group and with #ifdefs reduce + * functionality of less featured than wait6(2) interface (TWAIT_WAIT6TYPE). + * + * For clarity never use negative preprocessor checks, like: + * #if !defined(TWAIT_WAIT4) + * always refer to checks for positive values. + */ + +/* + * A child process cannot call atf functions and expect them to magically + * work like in the parent. + * The printf(3) messaging from a child will not work out of the box as well + * without estabilishing a communication protocol with its parent. To not + * overcomplicate the tests - do not log from a child and use err(3)/errx(3) + * wrapped with FORKEE_ASSERT()/FORKEE_ASSERTX() as that is guaranteed to work. + */ +#define FORKEE_ASSERT_EQ(x, y) \ +do { \ + int ret = (x) == (y); \ + if (!ret) \ + errx(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: " \ + "%s(%d) == %s(%d)", __FILE__, __LINE__, __func__, \ + #x, (int)x, #y, (int)y); \ +} while (/*CONSTCOND*/0) + +#define FORKEE_ASSERTX(x) \ +do { \ + int ret = (x); \ + if (!ret) \ + errx(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: %s",\ + __FILE__, __LINE__, __func__, #x); \ +} while (/*CONSTCOND*/0) + +#define FORKEE_ASSERT(x) \ +do { \ + int ret = (x); \ + if (!ret) \ + err(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: %s",\ + __FILE__, __LINE__, __func__, #x); \ +} while (/*CONSTCOND*/0) + +/* + * Simplify logic for functions using general purpose registers add HAVE_GPREGS + * + * For platforms that do not implement all needed calls for simplicity assume + * that they are unsupported at all. + */ +#if defined(PT_GETREGS) \ + && defined(PT_SETREGS) \ + && defined(PTRACE_REG_PC) \ + && defined(PTRACE_REG_SET_PC) \ + && defined(PTRACE_REG_SP) \ + && defined(PTRACE_REG_INTRV) +#define HAVE_GPREGS +#endif + +/* Add guards for floating point registers */ +#if defined(PT_GETFPREGS) \ + && defined(PT_SETFPREGS) +#define HAVE_FPREGS +#endif + +/* Add guards for cpu debug registers */ +#if defined(PT_GETDBREGS) \ + && defined(PT_SETDBREGS) +#define HAVE_DBREGS +#endif + +/* + * If waitid(2) returns because one or more processes have a state change to + * report, 0 is returned. If an error is detected, a value of -1 is returned + * and errno is set to indicate the error. If WNOHANG is specified and there + * are no stopped, continued or exited children, 0 is returned. + */ +#if defined(TWAIT_WAITID) +#define TWAIT_REQUIRE_SUCCESS(a,b) ATF_REQUIRE((a) == 0) +#define TWAIT_REQUIRE_FAILURE(a,b) ATF_REQUIRE_ERRNO((a),(b) == -1) +#define FORKEE_REQUIRE_SUCCESS(a,b) FORKEE_ASSERTX((a) == 0) +#define FORKEE_REQUIRE_FAILURE(a,b) \ + FORKEE_ASSERTX(((a) == errno) && ((b) == -1)) +#else +#define TWAIT_REQUIRE_SUCCESS(a,b) ATF_REQUIRE((a) == (b)) +#define TWAIT_REQUIRE_FAILURE(a,b) ATF_REQUIRE_ERRNO((a),(b) == -1) +#define FORKEE_REQUIRE_SUCCESS(a,b) FORKEE_ASSERTX((a) == (b)) +#define FORKEE_REQUIRE_FAILURE(a,b) \ + FORKEE_ASSERTX(((a) == errno) && ((b) == -1)) +#endif + +/* + * Helper tools to verify whether status reports exited value + */ +#if TWAIT_HAVE_STATUS +static void __used +validate_status_exited(int status, int expected) +{ + ATF_REQUIRE_MSG(WIFEXITED(status), "Reported !exited process"); + ATF_REQUIRE_MSG(!WIFCONTINUED(status), "Reported continued process"); + ATF_REQUIRE_MSG(!WIFSIGNALED(status), "Reported signaled process"); + ATF_REQUIRE_MSG(!WIFSTOPPED(status), "Reported stopped process"); + + ATF_REQUIRE_EQ_MSG(WEXITSTATUS(status), expected, + "The process has exited with invalid value %d != %d", + WEXITSTATUS(status), expected); +} + +static void __used +forkee_status_exited(int status, int expected) +{ + FORKEE_ASSERTX(WIFEXITED(status)); + FORKEE_ASSERTX(!WIFCONTINUED(status)); + FORKEE_ASSERTX(!WIFSIGNALED(status)); + FORKEE_ASSERTX(!WIFSTOPPED(status)); + + FORKEE_ASSERT_EQ(WEXITSTATUS(status), expected); +} + +static void __used +validate_status_continued(int status) +{ + ATF_REQUIRE_MSG(!WIFEXITED(status), "Reported exited process"); + ATF_REQUIRE_MSG(WIFCONTINUED(status), "Reported !continued process"); + ATF_REQUIRE_MSG(!WIFSIGNALED(status), "Reported signaled process"); + ATF_REQUIRE_MSG(!WIFSTOPPED(status), "Reported stopped process"); +} + +static void __used +forkee_status_continued(int status) +{ + FORKEE_ASSERTX(!WIFEXITED(status)); + FORKEE_ASSERTX(WIFCONTINUED(status)); + FORKEE_ASSERTX(!WIFSIGNALED(status)); + FORKEE_ASSERTX(!WIFSTOPPED(status)); +} + +static void __used +validate_status_signaled(int status, int expected_termsig, int expected_core) +{ + ATF_REQUIRE_MSG(!WIFEXITED(status), "Reported exited process"); + ATF_REQUIRE_MSG(!WIFCONTINUED(status), "Reported continued process"); + ATF_REQUIRE_MSG(WIFSIGNALED(status), "Reported !signaled process"); + ATF_REQUIRE_MSG(!WIFSTOPPED(status), "Reported stopped process"); + + ATF_REQUIRE_EQ_MSG(WTERMSIG(status), expected_termsig, + "Unexpected signal received"); + + ATF_REQUIRE_EQ_MSG(WCOREDUMP(status), expected_core, + "Unexpectedly core file %s generated", expected_core ? "not" : ""); +} + +static void __used +forkee_status_signaled(int status, int expected_termsig, int expected_core) +{ + FORKEE_ASSERTX(!WIFEXITED(status)); + FORKEE_ASSERTX(!WIFCONTINUED(status)); + FORKEE_ASSERTX(WIFSIGNALED(status)); + FORKEE_ASSERTX(!WIFSTOPPED(status)); + + FORKEE_ASSERT_EQ(WTERMSIG(status), expected_termsig); + FORKEE_ASSERT_EQ(WCOREDUMP(status), expected_core); +} + +static void __used +validate_status_stopped(int status, int expected) +{ + ATF_REQUIRE_MSG(!WIFEXITED(status), "Reported exited process"); + ATF_REQUIRE_MSG(!WIFCONTINUED(status), "Reported continued process"); + ATF_REQUIRE_MSG(!WIFSIGNALED(status), "Reported signaled process"); + ATF_REQUIRE_MSG(WIFSTOPPED(status), "Reported !stopped process"); + + char st[128], ex[128]; + strlcpy(st, strsignal(WSTOPSIG(status)), sizeof(st)); + strlcpy(ex, strsignal(expected), sizeof(ex)); + + ATF_REQUIRE_EQ_MSG(WSTOPSIG(status), expected, + "Unexpected stop signal received [%s] != [%s]", st, ex); +} + +static void __used +forkee_status_stopped(int status, int expected) +{ + FORKEE_ASSERTX(!WIFEXITED(status)); + FORKEE_ASSERTX(!WIFCONTINUED(status)); + FORKEE_ASSERTX(!WIFSIGNALED(status)); + FORKEE_ASSERTX(WIFSTOPPED(status)); + + FORKEE_ASSERT_EQ(WSTOPSIG(status), expected); +} +#else +#define validate_status_exited(a,b) +#define forkee_status_exited(a,b) +#define validate_status_continued(a,b) +#define forkee_status_continued(a,b) +#define validate_status_signaled(a,b,c) +#define forkee_status_signaled(a,b,c) +#define validate_status_stopped(a,b) +#define forkee_status_stopped(a,b) +#endif + +/* This function is currently designed to be run in the main/parent process */ +static void __used +await_zombie(pid_t process) +{ + struct kinfo_proc2 p; + size_t len = sizeof(p); + + const int name[] = { + [0] = CTL_KERN, + [1] = KERN_PROC2, + [2] = KERN_PROC_PID, + [3] = process, + [4] = sizeof(p), + [5] = 1 + }; + + const size_t namelen = __arraycount(name); + + /* Await the process becoming a zombie */ + while(1) { + ATF_REQUIRE(sysctl(name, namelen, &p, &len, NULL, 0) == 0); + + if (p.p_stat == LSZOMB) + break; + + ATF_REQUIRE(usleep(1000) == 0); + } +} + +/* Happy number sequence -- this function is used to just consume cpu cycles */ +#define HAPPY_NUMBER 1 + +/* If n is not happy then its sequence ends in the cycle: + * 4, 16, 37, 58, 89, 145, 42, 20, 4, ... */ +#define SAD_NUMBER 4 + +/* Calculate the sum of the squares of the digits of n */ +static unsigned __used +dsum(unsigned n) +{ + unsigned sum, x; + for (sum = 0; n; n /= 10) { + x = n % 10; + sum += x * x; + } + return sum; +} + +static int __used +check_happy(unsigned n) +{ + for (;;) { + unsigned total = dsum(n); + + if (total == HAPPY_NUMBER) + return 1; + if (total == SAD_NUMBER) + return 0; + + n = total; + } +} + +#if defined(TWAIT_HAVE_PID) +#define ATF_TP_ADD_TC_HAVE_PID(a,b) ATF_TP_ADD_TC(a,b) +#else +#define ATF_TP_ADD_TC_HAVE_PID(a,b) +#endif + +#if defined(HAVE_GPREGS) +#define ATF_TP_ADD_TC_HAVE_GPREGS(a,b) ATF_TP_ADD_TC(a,b) +#else +#define ATF_TP_ADD_TC_HAVE_GPREGS(a,b) +#endif + +#if defined(HAVE_FPREGS) +#define ATF_TP_ADD_TC_HAVE_FPREGS(a,b) ATF_TP_ADD_TC(a,b) +#else +#define ATF_TP_ADD_TC_HAVE_FPREGS(a,b) +#endif + +#if defined(HAVE_DBREGS) +#define ATF_TP_ADD_TC_HAVE_DBREGS(a,b) ATF_TP_ADD_TC(a,b) +#else +#define ATF_TP_ADD_TC_HAVE_DBREGS(a,b) +#endif + +#if defined(PT_STEP) +#define ATF_TP_ADD_TC_PT_STEP(a,b) ATF_TP_ADD_TC(a,b) +#else +#define ATF_TP_ADD_TC_PT_STEP(a,b) +#endif