Module Name:    src
Committed By:   kamil
Date:           Sun Feb 12 06:09:53 UTC 2017

Modified Files:
        src/lib/libc/sys: ptrace.2
        src/sys/kern: sys_ptrace_common.c
        src/sys/sys: ptrace.h
        src/tests/kernel: t_ptrace_wait.c

Log Message:
Introduce new interface in ptrace(2) - PT_GET_SIGMASK and PT_SET_SIGMASK

Add new interface to add ability to get/set signal mask of a tracee.
It has been inspired by Linux PTRACE_GETSIGMASK and PTRACE_SETSIGMASK, but
adapted for NetBSD API.

This interface is used for checkpointing software to set/restore context
of a process including signal mask like criu or just to track this property
in reverse-execution software like Record and Replay Framework (rr).

Add new ATF tests for this interface
====================================
getsigmask1:
    Verify that plain PT_SET_SIGMASK can be called

getsigmask2:
    Verify that PT_SET_SIGMASK reports correct mask from tracee

setsigmask1:
    Verify that plain PT_SET_SIGMASK can be called with empty mask

setsigmask2:
    Verify that sigmask is preserved between PT_GET_SIGMASK and
    PT_SET_SIGMASK

setsigmask3:
    Verify that sigmask is preserved between PT_GET_SIGMASK, process
    resumed and PT_SET_SIGMASK

setsigmask4:
    Verify that new sigmask is visible in tracee

Kernel ABI bump delayed as there are more interfaces to come in ptrace(2).

Sponsored by <The NetBSD Foundation>


To generate a diff of this commit:
cvs rdiff -u -r1.58 -r1.59 src/lib/libc/sys/ptrace.2
cvs rdiff -u -r1.13 -r1.14 src/sys/kern/sys_ptrace_common.c
cvs rdiff -u -r1.55 -r1.56 src/sys/sys/ptrace.h
cvs rdiff -u -r1.69 -r1.70 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/lib/libc/sys/ptrace.2
diff -u src/lib/libc/sys/ptrace.2:1.58 src/lib/libc/sys/ptrace.2:1.59
--- src/lib/libc/sys/ptrace.2:1.58	Fri Jan 27 12:52:39 2017
+++ src/lib/libc/sys/ptrace.2	Sun Feb 12 06:09:53 2017
@@ -1,7 +1,7 @@
-.\"	$NetBSD: ptrace.2,v 1.58 2017/01/27 12:52:39 wiz Exp $
+.\"	$NetBSD: ptrace.2,v 1.59 2017/02/12 06:09:53 kamil Exp $
 .\"
 .\" This file is in the public domain.
-.Dd January 25, 2016
+.Dd February 12, 2016
 .Dt PTRACE 2
 .Os
 .Sh NAME
@@ -514,6 +514,31 @@ The
 .Fa data
 argument should be set to
 .Li sizeof(struct ptrace_siginfo) .
+.It Dv PT_SET_SIGMASK
+This request loads the traced process' signal mask from
+.Dq Li "sigset_t"
+(defined in
+.In sys/sigtypes.h )
+pointed to by
+.Fa addr .
+The
+.Fa data
+argument contains the LWP ID of the thread whose registers are to
+be written.
+If zero is supplied, the first thread of the process is written.
+.It Dv PT_GET_SIGMASK
+This request is the converse of
+.Dv PT_SET_SIGMASK ;
+it reads the traced process' signal mask into
+.Dq Li "sigset_t"
+(defined in
+.In sys/sigtypes.h )
+pointed to by
+.Fa addr .
+The
+.Fa data
+argument contains the LWP ID of the thread whose mask is to be read.
+If zero is supplied, the first thread of the process is read.
 .El
 .Pp
 Additionally, the following requests exist but are

Index: src/sys/kern/sys_ptrace_common.c
diff -u src/sys/kern/sys_ptrace_common.c:1.13 src/sys/kern/sys_ptrace_common.c:1.14
--- src/sys/kern/sys_ptrace_common.c:1.13	Sat Feb 11 19:32:41 2017
+++ src/sys/kern/sys_ptrace_common.c	Sun Feb 12 06:09:52 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: sys_ptrace_common.c,v 1.13 2017/02/11 19:32:41 kamil Exp $	*/
+/*	$NetBSD: sys_ptrace_common.c,v 1.14 2017/02/12 06:09:52 kamil Exp $	*/
 
 /*-
  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -118,7 +118,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sys_ptrace_common.c,v 1.13 2017/02/11 19:32:41 kamil Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sys_ptrace_common.c,v 1.14 2017/02/12 06:09:52 kamil Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ptrace.h"
@@ -212,6 +212,8 @@ ptrace_listener_cb(kauth_cred_t cred, ka
 	case PT_GET_PROCESS_STATE:
 	case PT_SET_SIGINFO:
 	case PT_GET_SIGINFO:
+	case PT_SET_SIGMASK:
+	case PT_GET_SIGMASK:
 #ifdef __HAVE_PTRACE_MACHDEP
 	PTRACE_MACHDEP_REQUEST_CASES
 #endif
@@ -406,6 +408,8 @@ do_ptrace(struct ptrace_methods *ptm, st
 	case  PT_IO:
 	case  PT_SET_SIGINFO:
 	case  PT_GET_SIGINFO:
+	case  PT_SET_SIGMASK:
+	case  PT_GET_SIGMASK:
 #ifdef PT_GETREGS
 	case  PT_GETREGS:
 #endif
@@ -1039,6 +1043,35 @@ do_ptrace(struct ptrace_methods *ptm, st
 
 		break;
 
+	case  PT_SET_SIGMASK:
+		write = 1;
+
+	case  PT_GET_SIGMASK:
+		/* write = 0 done above. */
+
+		tmp = data;
+		if (tmp != 0 && t->p_nlwps > 1) {
+			lwp_delref(lt);
+			mutex_enter(t->p_lock);
+			lt = lwp_find(t, tmp);
+			if (lt == NULL) {
+				mutex_exit(t->p_lock);
+				error = ESRCH;
+				break;
+			}
+			lwp_addref(lt);
+			mutex_exit(t->p_lock);
+		}
+
+		if (!process_validregs(lt))
+			error = EINVAL;
+		else if (write == 1)
+			error = copyin(addr, &lt->l_sigmask, sizeof(sigset_t));
+		else
+			error = copyout(&lt->l_sigmask, addr, sizeof(sigset_t));
+			
+		break;
+
 #ifdef PT_SETREGS
 	case  PT_SETREGS:
 		write = 1;

Index: src/sys/sys/ptrace.h
diff -u src/sys/sys/ptrace.h:1.55 src/sys/sys/ptrace.h:1.56
--- src/sys/sys/ptrace.h:1.55	Mon Jan 16 21:35:59 2017
+++ src/sys/sys/ptrace.h	Sun Feb 12 06:09:52 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: ptrace.h,v 1.55 2017/01/16 21:35:59 kamil Exp $	*/
+/*	$NetBSD: ptrace.h,v 1.56 2017/02/12 06:09:52 kamil Exp $	*/
 
 /*-
  * Copyright (c) 1984, 1993
@@ -55,6 +55,8 @@
 #define	PT_GET_PROCESS_STATE	18	/* get process state, defined below */
 #define	PT_SET_SIGINFO		19	/* set signal state, defined below */
 #define	PT_GET_SIGINFO		20	/* get signal state, defined below */
+#define	PT_SET_SIGMASK		21	/* set signal mask */
+#define	PT_GET_SIGMASK		22	/* get signal mask */
 
 #define	PT_FIRSTMACH		32	/* for machine-specific requests */
 #include <machine/ptrace.h>		/* machine-specific requests, if any */
@@ -80,7 +82,9 @@
 /* 17 */    "PT_GET_EVENT_MASK", \
 /* 18 */    "PT_GET_PROCESS_STATE", \
 /* 19 */    "PT_SET_SIGINFO", \
-/* 20 */    "PT_GET_SIGINFO",
+/* 20 */    "PT_GET_SIGINFO", \
+/* 20 */    "PT_GET_SIGMASK", \
+/* 20 */    "PT_GET_SIGMASK",
 
 /* PT_{G,S}EVENT_MASK */
 typedef struct ptrace_event {

Index: src/tests/kernel/t_ptrace_wait.c
diff -u src/tests/kernel/t_ptrace_wait.c:1.69 src/tests/kernel/t_ptrace_wait.c:1.70
--- src/tests/kernel/t_ptrace_wait.c:1.69	Fri Jan 27 16:43:07 2017
+++ src/tests/kernel/t_ptrace_wait.c	Sun Feb 12 06:09:52 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: t_ptrace_wait.c,v 1.69 2017/01/27 16:43:07 kamil Exp $	*/
+/*	$NetBSD: t_ptrace_wait.c,v 1.70 2017/02/12 06:09:52 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.69 2017/01/27 16:43:07 kamil Exp $");
+__RCSID("$NetBSD: t_ptrace_wait.c,v 1.70 2017/02/12 06:09:52 kamil Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -6583,6 +6583,370 @@ ATF_TC_BODY(signal10, tc)
 	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
 }
 
+ATF_TC(getsigmask1);
+ATF_TC_HEAD(getsigmask1, tc)
+{
+	atf_tc_set_md_var(tc, "descr",
+	    "Verify that plain PT_SET_SIGMASK can be called");
+}
+
+ATF_TC_BODY(getsigmask1, tc)
+{
+	const int exitval = 5;
+	const int sigval = SIGSTOP;
+	pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+	int status;
+#endif
+	sigset_t mask;
+
+	printf("Before forking process PID=%d\n", getpid());
+	ATF_REQUIRE((child = fork()) != -1);
+	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("Before calling PT_GET_SIGMASK\n");
+	ATF_REQUIRE(ptrace(PT_GET_SIGMASK, child, &mask, 0) != -1);
+
+	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));
+}
+
+ATF_TC(getsigmask2);
+ATF_TC_HEAD(getsigmask2, tc)
+{
+	atf_tc_set_md_var(tc, "descr",
+	    "Verify that PT_SET_SIGMASK reports correct mask from tracee");
+}
+
+ATF_TC_BODY(getsigmask2, tc)
+{
+	const int exitval = 5;
+	const int sigval = SIGSTOP;
+	const int sigmasked = SIGTRAP;
+	pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+	int status;
+#endif
+	sigset_t mask;
+	sigset_t expected_mask;
+	ATF_REQUIRE(sigemptyset(&mask) == 0);
+	ATF_REQUIRE(sigemptyset(&expected_mask) == 0);
+	ATF_REQUIRE(sigaddset(&expected_mask, sigmasked) == 0);
+
+	printf("Before forking process PID=%d\n", getpid());
+	ATF_REQUIRE((child = fork()) != -1);
+	if (child == 0) {
+		printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+		sigaddset(&mask, sigmasked);
+		sigprocmask(SIG_BLOCK, &mask, NULL);
+
+		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("Before calling PT_GET_SIGMASK\n");
+	ATF_REQUIRE(ptrace(PT_GET_SIGMASK, child, &mask, 0) != -1);
+
+	ATF_REQUIRE(memcmp(&mask, &expected_mask, sizeof(sigset_t)) == 0);
+
+	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));
+}
+
+ATF_TC(setsigmask1);
+ATF_TC_HEAD(setsigmask1, tc)
+{
+	atf_tc_set_md_var(tc, "descr",
+	    "Verify that plain PT_SET_SIGMASK can be called with empty mask");
+}
+
+ATF_TC_BODY(setsigmask1, tc)
+{
+	const int exitval = 5;
+	const int sigval = SIGSTOP;
+	pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+	int status;
+#endif
+	sigset_t mask;
+	ATF_REQUIRE(sigemptyset(&mask) == 0);
+
+	printf("Before forking process PID=%d\n", getpid());
+	ATF_REQUIRE((child = fork()) != -1);
+	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("Before calling PT_SET_SIGMASK for empty mask\n");
+	ATF_REQUIRE(ptrace(PT_SET_SIGMASK, child, &mask, 0) != -1);
+
+	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));
+}
+
+ATF_TC(setsigmask2);
+ATF_TC_HEAD(setsigmask2, tc)
+{
+	atf_tc_set_md_var(tc, "descr",
+	    "Verify that sigmask is preserved between PT_GET_SIGMASK and "
+	    "PT_SET_SIGMASK");
+}
+
+ATF_TC_BODY(setsigmask2, tc)
+{
+	const int exitval = 5;
+	const int sigval = SIGSTOP;
+	pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+	int status;
+#endif
+	sigset_t new_mask;
+	sigset_t mask;
+	ATF_REQUIRE(sigemptyset(&new_mask) == 0);
+	ATF_REQUIRE(sigemptyset(&mask) == 0);
+	ATF_REQUIRE(sigaddset(&mask, SIGINT) == 0);
+
+	printf("Before forking process PID=%d\n", getpid());
+	ATF_REQUIRE((child = fork()) != -1);
+	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("Before calling PT_SET_SIGMASK for new mask with SIGINT\n");
+	ATF_REQUIRE(ptrace(PT_SET_SIGMASK, child, &mask, 0) != -1);
+
+	printf("Before calling PT_GET_SIGMASK to store it in new_mask\n");
+	ATF_REQUIRE(ptrace(PT_GET_SIGMASK, child, &new_mask, 0) != -1);
+
+	ATF_REQUIRE(memcmp(&mask, &new_mask, sizeof(sigset_t)) == 0);
+
+	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));
+}
+
+ATF_TC(setsigmask3);
+ATF_TC_HEAD(setsigmask3, tc)
+{
+	atf_tc_set_md_var(tc, "descr",
+	    "Verify that sigmask is preserved between PT_GET_SIGMASK, process "
+	    "resumed and PT_SET_SIGMASK");
+}
+
+ATF_TC_BODY(setsigmask3, tc)
+{
+	const int exitval = 5;
+	const int sigval = SIGSTOP;
+	pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+	int status;
+#endif
+	sigset_t new_mask;
+	sigset_t mask;
+	ATF_REQUIRE(sigemptyset(&new_mask) == 0);
+	ATF_REQUIRE(sigemptyset(&mask) == 0);
+	ATF_REQUIRE(sigaddset(&mask, SIGINT) == 0);
+
+	printf("Before forking process PID=%d\n", getpid());
+	ATF_REQUIRE((child = fork()) != -1);
+	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 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("Before calling PT_SET_SIGMASK for new mask with SIGINT\n");
+	ATF_REQUIRE(ptrace(PT_SET_SIGMASK, child, &mask, 0) != -1);
+
+	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_stopped(status, sigval);
+
+	printf("Before calling PT_GET_SIGMASK to store it in new_mask\n");
+	ATF_REQUIRE(ptrace(PT_GET_SIGMASK, child, &new_mask, 0) != -1);
+
+	ATF_REQUIRE(memcmp(&mask, &new_mask, sizeof(sigset_t)) == 0);
+
+	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));
+}
+
+ATF_TC(setsigmask4);
+ATF_TC_HEAD(setsigmask4, tc)
+{
+	atf_tc_set_md_var(tc, "descr",
+	    "Verify that new sigmask is visible in tracee");
+}
+
+ATF_TC_BODY(setsigmask4, tc)
+{
+	const int exitval = 5;
+	const int sigval = SIGSTOP;
+	pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+	int status;
+#endif
+	sigset_t mask;
+	sigset_t expected_mask;
+	ATF_REQUIRE(sigemptyset(&mask) == 0);
+	ATF_REQUIRE(sigemptyset(&expected_mask) == 0);
+	ATF_REQUIRE(sigaddset(&expected_mask, SIGINT) == 0);
+
+	printf("Before forking process PID=%d\n", getpid());
+	ATF_REQUIRE((child = fork()) != -1);
+	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);
+
+		sigprocmask(0, NULL, &mask);
+
+		FORKEE_ASSERT
+		    (memcmp(&mask, &expected_mask, sizeof(sigset_t)) == 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("Before calling PT_SET_SIGMASK for new mask with SIGINT\n");
+	ATF_REQUIRE(ptrace(PT_SET_SIGMASK, child, &expected_mask, 0) != -1);
+
+	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));
+}
+
 ATF_TP_ADD_TCS(tp)
 {
 	setvbuf(stdout, NULL, _IONBF, 0);
@@ -6696,5 +7060,13 @@ ATF_TP_ADD_TCS(tp)
 	ATF_TP_ADD_TC(tp, signal9);
 	ATF_TP_ADD_TC(tp, signal10);
 
+	ATF_TP_ADD_TC(tp, getsigmask1);
+	ATF_TP_ADD_TC(tp, getsigmask2);
+
+	ATF_TP_ADD_TC(tp, setsigmask1);
+	ATF_TP_ADD_TC(tp, setsigmask2);
+	ATF_TP_ADD_TC(tp, setsigmask3);
+	ATF_TP_ADD_TC(tp, setsigmask4);
+
 	return atf_no_error();
 }

Reply via email to