Home | History | Annotate | Line # | Download | only in kernel
t_signal_and_sp.c revision 1.7
      1  1.7  riastrad /*	$NetBSD: t_signal_and_sp.c,v 1.7 2025/04/21 02:33:44 riastradh Exp $	*/
      2  1.1       pho 
      3  1.1       pho /*
      4  1.1       pho  * Copyright (c) 2024 The NetBSD Foundation, Inc.
      5  1.1       pho  * All rights reserved.
      6  1.1       pho  *
      7  1.1       pho  * Redistribution and use in source and binary forms, with or without
      8  1.1       pho  * modification, are permitted provided that the following conditions
      9  1.1       pho  * are met:
     10  1.1       pho  * 1. Redistributions of source code must retain the above copyright
     11  1.1       pho  *    notice, this list of conditions and the following disclaimer.
     12  1.1       pho  * 2. Redistributions in binary form must reproduce the above copyright
     13  1.1       pho  *    notice, this list of conditions and the following disclaimer in the
     14  1.1       pho  *    documentation and/or other materials provided with the distribution.
     15  1.1       pho  *
     16  1.1       pho  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  1.1       pho  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  1.1       pho  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  1.1       pho  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  1.1       pho  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  1.1       pho  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  1.1       pho  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  1.1       pho  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  1.1       pho  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  1.1       pho  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  1.1       pho  * POSSIBILITY OF SUCH DAMAGE.
     27  1.1       pho  */
     28  1.1       pho 
     29  1.2  riastrad #include <sys/cdefs.h>
     30  1.7  riastrad __RCSID("$NetBSD: t_signal_and_sp.c,v 1.7 2025/04/21 02:33:44 riastradh Exp $");
     31  1.2  riastrad 
     32  1.2  riastrad #include <sys/wait.h>
     33  1.2  riastrad 
     34  1.2  riastrad #include <machine/param.h>
     35  1.2  riastrad 
     36  1.1       pho #include <atf-c.h>
     37  1.2  riastrad #include <limits.h>
     38  1.2  riastrad #include <poll.h>
     39  1.7  riastrad #include <pthread.h>
     40  1.2  riastrad #include <signal.h>
     41  1.2  riastrad #include <stdint.h>
     42  1.2  riastrad #include <stdio.h>
     43  1.2  riastrad #include <string.h>
     44  1.2  riastrad #include <time.h>
     45  1.7  riastrad #include <ucontext.h>
     46  1.2  riastrad #include <unistd.h>
     47  1.1       pho 
     48  1.2  riastrad #include "h_execsp.h"
     49  1.2  riastrad #include "h_macros.h"
     50  1.2  riastrad 
     51  1.2  riastrad #ifdef HAVE_STACK_POINTER_H
     52  1.1       pho #  include "stack_pointer.h"
     53  1.2  riastrad #endif
     54  1.1       pho 
     55  1.2  riastrad #ifdef HAVE_SIGNALSPHANDLER
     56  1.2  riastrad void signalsphandler(int);	/* signalsphandler.S assembly routine */
     57  1.2  riastrad #endif
     58  1.2  riastrad 
     59  1.2  riastrad void *volatile signalsp;
     60  1.2  riastrad 
     61  1.2  riastrad static void
     62  1.2  riastrad test_execsp(const struct atf_tc *tc, const char *prog)
     63  1.1       pho {
     64  1.2  riastrad #ifdef STACK_ALIGNBYTES
     65  1.2  riastrad 	char h_execsp[PATH_MAX];
     66  1.2  riastrad 	struct execsp execsp;
     67  1.2  riastrad 	int fd[2];
     68  1.2  riastrad 	pid_t pid;
     69  1.2  riastrad 	struct pollfd pollfd;
     70  1.2  riastrad 	int nfds;
     71  1.2  riastrad 	ssize_t nread;
     72  1.2  riastrad 	int status;
     73  1.2  riastrad 
     74  1.1       pho 	/*
     75  1.2  riastrad 	 * Determine the full path to the helper program.
     76  1.1       pho 	 */
     77  1.2  riastrad 	RL(snprintf(h_execsp, sizeof(h_execsp), "%s/%s",
     78  1.2  riastrad 		atf_tc_get_config_var(tc, "srcdir"), prog));
     79  1.2  riastrad 
     80  1.2  riastrad 	/*
     81  1.2  riastrad 	 * Create a pipe to read a bundle of stack pointer samples from
     82  1.2  riastrad 	 * the child, and fork the child.
     83  1.2  riastrad 	 */
     84  1.2  riastrad 	RL(pipe(fd));
     85  1.2  riastrad 	RL(pid = vfork());
     86  1.2  riastrad 	if (pid == 0) {		/* child */
     87  1.2  riastrad 		char *const argv[] = {h_execsp, NULL};
     88  1.2  riastrad 
     89  1.2  riastrad 		if (dup2(fd[1], STDOUT_FILENO) == -1)
     90  1.2  riastrad 			_exit(1);
     91  1.2  riastrad 		if (closefrom(STDERR_FILENO + 1) == -1)
     92  1.2  riastrad 			_exit(2);
     93  1.2  riastrad 		if (execve(argv[0], argv, NULL) == -1)
     94  1.2  riastrad 			_exit(3);
     95  1.2  riastrad 		_exit(4);
     96  1.2  riastrad 	}
     97  1.2  riastrad 
     98  1.2  riastrad 	/*
     99  1.2  riastrad 	 * Close the writing end so, if something goes wrong in the
    100  1.2  riastrad 	 * child, we don't hang indefinitely waiting for output.
    101  1.2  riastrad 	 */
    102  1.2  riastrad 	RL(close(fd[1]));
    103  1.2  riastrad 
    104  1.2  riastrad 	/*
    105  1.2  riastrad 	 * Wait up to 5sec for the child to return an answer.  Any more
    106  1.2  riastrad 	 * than that, and we kill it.  The child is mostly hand-written
    107  1.2  riastrad 	 * assembly routines where lots can go wrong, so don't bother
    108  1.2  riastrad 	 * waiting if it gets stuck in a loop.
    109  1.2  riastrad 	 */
    110  1.2  riastrad 	pollfd.fd = fd[0];
    111  1.2  riastrad 	pollfd.events = POLLIN;
    112  1.2  riastrad 	RL(nfds = poll(&pollfd, 1, 5*1000/*ms*/));
    113  1.2  riastrad 	if (nfds == 0) {
    114  1.2  riastrad 		fprintf(stderr, "child hung, killing\n");
    115  1.2  riastrad 		RL(kill(pid, SIGKILL));
    116  1.2  riastrad 	}
    117  1.1       pho 
    118  1.1       pho 	/*
    119  1.2  riastrad 	 * Read a bundle of stack pointer samples from the child.
    120  1.1       pho 	 */
    121  1.2  riastrad 	RL(nread = read(fd[0], &execsp, sizeof(execsp)));
    122  1.2  riastrad 	ATF_CHECK_MSG((size_t)nread == sizeof(execsp),
    123  1.2  riastrad 	    "nread=%zu sizeof(execsp)=%zu",
    124  1.2  riastrad 	    (size_t)nread, sizeof(execsp));
    125  1.2  riastrad 
    126  1.2  riastrad 	/*
    127  1.2  riastrad 	 * Wait for the child to terminate and report failure if it
    128  1.2  riastrad 	 * didn't exit cleanly.
    129  1.2  riastrad 	 */
    130  1.2  riastrad 	RL(waitpid(pid, &status, 0));
    131  1.2  riastrad 	if (WIFSIGNALED(status)) {
    132  1.2  riastrad 		atf_tc_fail_nonfatal("child exited on signal %d (%s)",
    133  1.2  riastrad 		    WTERMSIG(status), strsignal(WTERMSIG(status)));
    134  1.2  riastrad 	} else if (!WIFEXITED(status)) {
    135  1.2  riastrad 		atf_tc_fail_nonfatal("child exited status=0x%x", status);
    136  1.2  riastrad 	} else {
    137  1.2  riastrad 		ATF_CHECK_MSG(WEXITSTATUS(status) == 0,
    138  1.2  riastrad 		    "child exited with code %d",
    139  1.2  riastrad 		    WEXITSTATUS(status));
    140  1.2  riastrad 	}
    141  1.2  riastrad 
    142  1.2  riastrad 	/*
    143  1.2  riastrad 	 * Now that we have reaped the child, stop here if the stack
    144  1.2  riastrad 	 * pointer samples are bogus; otherwise verify they are all
    145  1.2  riastrad 	 * aligned.
    146  1.2  riastrad 	 */
    147  1.2  riastrad 	if ((size_t)nread != sizeof(execsp))
    148  1.2  riastrad 		return;		/* failed already */
    149  1.2  riastrad 
    150  1.2  riastrad 	printf("start sp @ %p\n", execsp.startsp);
    151  1.3  riastrad 	printf("ctor sp @ %p\n", execsp.ctorsp);
    152  1.2  riastrad 	printf("main sp @ %p\n", execsp.mainsp);
    153  1.3  riastrad 	printf("dtor sp @ %p\n", execsp.dtorsp);
    154  1.2  riastrad 
    155  1.2  riastrad 	ATF_CHECK_MSG(((uintptr_t)execsp.startsp & STACK_ALIGNBYTES) == 0,
    156  1.2  riastrad 	    "elf entry point was called with misaligned sp: %p",
    157  1.2  riastrad 	    execsp.startsp);
    158  1.2  riastrad 
    159  1.3  riastrad 	ATF_CHECK_MSG(((uintptr_t)execsp.ctorsp & STACK_ALIGNBYTES) == 0,
    160  1.3  riastrad 	    "elf constructor was called with misaligned sp: %p",
    161  1.3  riastrad 	    execsp.ctorsp);
    162  1.3  riastrad 
    163  1.2  riastrad 	ATF_CHECK_MSG(((uintptr_t)execsp.mainsp & STACK_ALIGNBYTES) == 0,
    164  1.2  riastrad 	    "main function was called with misaligned sp: %p",
    165  1.2  riastrad 	    execsp.mainsp);
    166  1.2  riastrad 
    167  1.3  riastrad 	ATF_CHECK_MSG(((uintptr_t)execsp.dtorsp & STACK_ALIGNBYTES) == 0,
    168  1.3  riastrad 	    "elf destructor was called with misaligned sp: %p",
    169  1.3  riastrad 	    execsp.dtorsp);
    170  1.3  riastrad 
    171  1.2  riastrad 	/*
    172  1.2  riastrad 	 * Leave a reminder on architectures for which we haven't
    173  1.2  riastrad 	 * implemented execsp_start.S.
    174  1.2  riastrad 	 */
    175  1.3  riastrad 	if (execsp.startsp == NULL ||
    176  1.3  riastrad 	    execsp.ctorsp == NULL ||
    177  1.3  riastrad 	    execsp.mainsp == NULL ||
    178  1.3  riastrad 	    execsp.dtorsp == NULL)
    179  1.2  riastrad 		atf_tc_skip("Not fully supported on this architecture");
    180  1.2  riastrad #else
    181  1.2  riastrad 	atf_tc_skip("Unknown STACK_ALIGNBYTES on this architecture");
    182  1.2  riastrad #endif
    183  1.2  riastrad }
    184  1.2  riastrad 
    185  1.2  riastrad ATF_TC(execsp_dynamic);
    186  1.2  riastrad ATF_TC_HEAD(execsp_dynamic, tc)
    187  1.2  riastrad {
    188  1.2  riastrad 	atf_tc_set_md_var(tc, "descr",
    189  1.2  riastrad 	    "Verify stack pointer is aligned on dynamic program start");
    190  1.2  riastrad }
    191  1.2  riastrad ATF_TC_BODY(execsp_dynamic, tc)
    192  1.2  riastrad {
    193  1.2  riastrad 	test_execsp(tc, "h_execsp_dynamic");
    194  1.1       pho }
    195  1.2  riastrad 
    196  1.2  riastrad ATF_TC(execsp_static);
    197  1.2  riastrad ATF_TC_HEAD(execsp_static, tc)
    198  1.2  riastrad {
    199  1.2  riastrad 	atf_tc_set_md_var(tc, "descr",
    200  1.2  riastrad 	    "Verify stack pointer is aligned on static program start");
    201  1.2  riastrad }
    202  1.2  riastrad ATF_TC_BODY(execsp_static, tc)
    203  1.2  riastrad {
    204  1.2  riastrad 	test_execsp(tc, "h_execsp_static");
    205  1.2  riastrad }
    206  1.2  riastrad 
    207  1.7  riastrad #if defined STACK_ALIGNBYTES && defined HAVE_CONTEXTSPFUNC
    208  1.7  riastrad void *volatile contextsp;	/* set by contextspfunc.S */
    209  1.7  riastrad static ucontext_t test_context, return_context;
    210  1.7  riastrad static volatile bool test_context_done;
    211  1.7  riastrad 
    212  1.7  riastrad void contextspfunc(void);	/* contextspfunc.S assembly routine */
    213  1.7  riastrad 
    214  1.7  riastrad void contextdone(void);		/* called by contextspfunc.S */
    215  1.7  riastrad void
    216  1.7  riastrad contextdone(void)
    217  1.7  riastrad {
    218  1.7  riastrad 
    219  1.7  riastrad 	fprintf(stderr, "contextdone\n");
    220  1.7  riastrad 	ATF_REQUIRE(!test_context_done);
    221  1.7  riastrad 	test_context_done = true;
    222  1.7  riastrad 	RL(setcontext(&return_context));
    223  1.7  riastrad 	atf_tc_fail("setcontext returned");
    224  1.7  riastrad }
    225  1.7  riastrad #endif
    226  1.7  riastrad 
    227  1.7  riastrad ATF_TC(contextsp);
    228  1.7  riastrad ATF_TC_HEAD(contextsp, tc)
    229  1.7  riastrad {
    230  1.7  riastrad 	atf_tc_set_md_var(tc, "descr",
    231  1.7  riastrad 	    "Verify stack pointer is aligned on makecontext entry");
    232  1.7  riastrad }
    233  1.7  riastrad ATF_TC_BODY(contextsp, tc)
    234  1.7  riastrad {
    235  1.7  riastrad #if defined STACK_ALIGNBYTES && defined HAVE_CONTEXTSPFUNC
    236  1.7  riastrad 	char *stack;
    237  1.7  riastrad 	unsigned i;
    238  1.7  riastrad 
    239  1.7  riastrad 	REQUIRE_LIBC(stack = malloc(SIGSTKSZ + STACK_ALIGNBYTES), NULL);
    240  1.7  riastrad 	fprintf(stderr, "stack @ [%p,%p)\n", stack, stack + STACK_ALIGNBYTES);
    241  1.7  riastrad 
    242  1.7  riastrad 	for (i = 0; i <= STACK_ALIGNBYTES; i++) {
    243  1.7  riastrad 		contextsp = NULL;
    244  1.7  riastrad 		test_context_done = false;
    245  1.7  riastrad 		RL(getcontext(&test_context));
    246  1.7  riastrad 		test_context.uc_stack.ss_sp = stack;
    247  1.7  riastrad 		test_context.uc_stack.ss_size = SIGSTKSZ + i;
    248  1.7  riastrad 		makecontext(&test_context, &contextspfunc, 0);
    249  1.7  riastrad 		fprintf(stderr, "[%u] swapcontext\n", i);
    250  1.7  riastrad 		RL(swapcontext(&return_context, &test_context));
    251  1.7  riastrad 		ATF_CHECK(contextsp != NULL);
    252  1.7  riastrad 		ATF_CHECK_MSG(((uintptr_t)contextsp & STACK_ALIGNBYTES) == 0,
    253  1.7  riastrad 		    "[%u] makecontext function called with misaligned sp %p",
    254  1.7  riastrad 		    i, contextsp);
    255  1.7  riastrad 	}
    256  1.7  riastrad 
    257  1.7  riastrad 	for (i = 0; i <= STACK_ALIGNBYTES; i++) {
    258  1.7  riastrad 		contextsp = NULL;
    259  1.7  riastrad 		test_context_done = false;
    260  1.7  riastrad 		RL(getcontext(&test_context));
    261  1.7  riastrad 		test_context.uc_stack.ss_sp = stack + i;
    262  1.7  riastrad 		test_context.uc_stack.ss_size = SIGSTKSZ;
    263  1.7  riastrad 		makecontext(&test_context, &contextspfunc, 0);
    264  1.7  riastrad 		fprintf(stderr, "[%u] swapcontext\n", i);
    265  1.7  riastrad 		RL(swapcontext(&return_context, &test_context));
    266  1.7  riastrad 		ATF_CHECK(contextsp != NULL);
    267  1.7  riastrad 		ATF_CHECK_MSG(((uintptr_t)contextsp & STACK_ALIGNBYTES) == 0,
    268  1.7  riastrad 		    "[%u] makecontext function called with misaligned sp %p",
    269  1.7  riastrad 		    i, contextsp);
    270  1.7  riastrad 	}
    271  1.7  riastrad #else
    272  1.7  riastrad 	atf_tc_skip("Not implemented on this platform");
    273  1.7  riastrad #endif
    274  1.7  riastrad }
    275  1.7  riastrad 
    276  1.2  riastrad ATF_TC(signalsp);
    277  1.2  riastrad ATF_TC_HEAD(signalsp, tc)
    278  1.2  riastrad {
    279  1.2  riastrad 	atf_tc_set_md_var(tc, "descr",
    280  1.2  riastrad 	    "Verify stack pointer is aligned on entry to signal handler");
    281  1.2  riastrad }
    282  1.2  riastrad ATF_TC_BODY(signalsp, tc)
    283  1.2  riastrad {
    284  1.2  riastrad #if defined STACK_ALIGNBYTES && defined HAVE_SIGNALSPHANDLER
    285  1.2  riastrad 	struct sigaction sa;
    286  1.2  riastrad 
    287  1.2  riastrad 	memset(&sa, 0, sizeof(sa));
    288  1.2  riastrad 	sa.sa_handler = &signalsphandler;
    289  1.2  riastrad 	RL(sigaction(SIGUSR1, &sa, NULL));
    290  1.2  riastrad 	RL(raise(SIGUSR1));
    291  1.2  riastrad 
    292  1.2  riastrad 	ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0,
    293  1.2  riastrad 	    "signal handler was called with a misaligned sp: %p",
    294  1.2  riastrad 	    signalsp);
    295  1.2  riastrad #else
    296  1.2  riastrad 	atf_tc_skip("Not implemented on this platform");
    297  1.2  riastrad #endif
    298  1.2  riastrad }
    299  1.2  riastrad 
    300  1.2  riastrad ATF_TC(signalsp_sigaltstack);
    301  1.2  riastrad ATF_TC_HEAD(signalsp_sigaltstack, tc)
    302  1.2  riastrad {
    303  1.2  riastrad 	atf_tc_set_md_var(tc, "descr",
    304  1.2  riastrad 	    "Verify stack pointer is aligned on entry to signal handler"
    305  1.2  riastrad 	    " with maximally misaligned sigaltstack");
    306  1.2  riastrad }
    307  1.2  riastrad ATF_TC_BODY(signalsp_sigaltstack, tc)
    308  1.2  riastrad {
    309  1.2  riastrad #if defined STACK_ALIGNBYTES && HAVE_SIGNALSPHANDLER
    310  1.2  riastrad 	char *stack;
    311  1.2  riastrad 	struct sigaction sa;
    312  1.2  riastrad 	struct sigaltstack ss;
    313  1.2  riastrad 	unsigned i;
    314  1.2  riastrad 
    315  1.2  riastrad 	memset(&sa, 0, sizeof(sa));
    316  1.2  riastrad 	sa.sa_handler = &signalsphandler;
    317  1.2  riastrad 	sa.sa_flags = SA_ONSTACK;
    318  1.2  riastrad 	RL(sigaction(SIGUSR1, &sa, NULL));
    319  1.2  riastrad 
    320  1.2  riastrad 	/*
    321  1.2  riastrad 	 * Allocate a signal stack with enough slop to try all possible
    322  1.2  riastrad 	 * misalignments of the stack pointer.  Print it to stderr so
    323  1.2  riastrad 	 * it always appears in atf output before shenanigans happen.
    324  1.2  riastrad 	 */
    325  1.2  riastrad 	REQUIRE_LIBC(stack = malloc(SIGSTKSZ + STACK_ALIGNBYTES), NULL);
    326  1.7  riastrad 	fprintf(stderr, "stack @ [%p, %p)\n",
    327  1.2  riastrad 	    stack, stack + SIGSTKSZ + STACK_ALIGNBYTES);
    328  1.2  riastrad 
    329  1.6  riastrad #if defined __alpha__ || defined __i386__ || defined __mips__
    330  1.4  riastrad 	atf_tc_expect_fail("PR kern/59327:"
    331  1.4  riastrad 	    " user stack pointer is not aligned properly");
    332  1.4  riastrad #endif
    333  1.4  riastrad 
    334  1.2  riastrad 	/*
    335  1.2  riastrad 	 * Try with all alignments of high addresses.
    336  1.2  riastrad 	 */
    337  1.2  riastrad 	for (i = 0; i <= STACK_ALIGNBYTES; i++) {
    338  1.2  riastrad 		ss.ss_sp = stack;
    339  1.2  riastrad 		ss.ss_size = SIGSTKSZ + i;
    340  1.2  riastrad 		ss.ss_flags = 0;
    341  1.2  riastrad 		RL(sigaltstack(&ss, NULL));
    342  1.2  riastrad 
    343  1.2  riastrad 		signalsp = NULL;
    344  1.2  riastrad 		RL(raise(SIGUSR1));
    345  1.2  riastrad 		ATF_CHECK(signalsp != NULL);
    346  1.2  riastrad 		ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0,
    347  1.2  riastrad 		    "[%u] signal handler was called with a misaligned sp: %p",
    348  1.2  riastrad 		    i, signalsp);
    349  1.2  riastrad 	}
    350  1.2  riastrad 
    351  1.2  riastrad 	/*
    352  1.2  riastrad 	 * Try with all alignments of low addresses.
    353  1.2  riastrad 	 */
    354  1.2  riastrad 	for (i = 0; i <= STACK_ALIGNBYTES; i++) {
    355  1.2  riastrad 		ss.ss_sp = stack + i;
    356  1.2  riastrad 		ss.ss_size = SIGSTKSZ;
    357  1.2  riastrad 		ss.ss_flags = 0;
    358  1.2  riastrad 		RL(sigaltstack(&ss, NULL));
    359  1.2  riastrad 
    360  1.2  riastrad 		signalsp = NULL;
    361  1.2  riastrad 		RL(raise(SIGUSR1));
    362  1.2  riastrad 		ATF_CHECK(signalsp != NULL);
    363  1.2  riastrad 		ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0,
    364  1.2  riastrad 		    "[%u] signal handler was called with a misaligned sp: %p",
    365  1.2  riastrad 		    i, signalsp);
    366  1.2  riastrad 	}
    367  1.2  riastrad #else
    368  1.2  riastrad 	atf_tc_skip("Not implemented on this platform");
    369  1.1       pho #endif
    370  1.2  riastrad }
    371  1.1       pho 
    372  1.7  riastrad #if defined STACK_ALIGNBYTES && defined HAVE_THREADSPFUNC
    373  1.7  riastrad void *threadspfunc(void *);	/* threadspfunc.S assembly routine */
    374  1.7  riastrad #endif
    375  1.7  riastrad 
    376  1.7  riastrad ATF_TC(threadsp);
    377  1.7  riastrad ATF_TC_HEAD(threadsp, tc)
    378  1.7  riastrad {
    379  1.7  riastrad 	atf_tc_set_md_var(tc, "descr",
    380  1.7  riastrad 	    "Verify stack pointer is aligned on thread start");
    381  1.7  riastrad }
    382  1.7  riastrad ATF_TC_BODY(threadsp, tc)
    383  1.7  riastrad {
    384  1.7  riastrad #if defined STACK_ALIGNBYTES && defined HAVE_THREADSPFUNC
    385  1.7  riastrad 	char *stack;
    386  1.7  riastrad 	unsigned i;
    387  1.7  riastrad 
    388  1.7  riastrad 	REQUIRE_LIBC(stack = malloc(SIGSTKSZ + STACK_ALIGNBYTES), NULL);
    389  1.7  riastrad 	fprintf(stderr, "stack @ [%p,%p)\n", stack, stack + STACK_ALIGNBYTES);
    390  1.7  riastrad 
    391  1.7  riastrad #ifdef __mips__
    392  1.7  riastrad 	atf_tc_expect_fail("PR kern/59327:"
    393  1.7  riastrad 	    " user stack pointer is not aligned properly");
    394  1.7  riastrad #endif
    395  1.7  riastrad 
    396  1.7  riastrad 	for (i = 0; i <= STACK_ALIGNBYTES; i++) {
    397  1.7  riastrad 		pthread_t t;
    398  1.7  riastrad 		pthread_attr_t attr;
    399  1.7  riastrad 		void *sp;
    400  1.7  riastrad 
    401  1.7  riastrad 		RZ(pthread_attr_init(&attr));
    402  1.7  riastrad 		RZ(pthread_attr_setstack(&attr, stack, SIGSTKSZ + i));
    403  1.7  riastrad 		RZ(pthread_create(&t, &attr, &threadspfunc, NULL));
    404  1.7  riastrad 		RZ(pthread_attr_destroy(&attr));
    405  1.7  riastrad 
    406  1.7  riastrad 		alarm(1);
    407  1.7  riastrad 		RZ(pthread_join(t, &sp));
    408  1.7  riastrad 		alarm(0);
    409  1.7  riastrad 
    410  1.7  riastrad 		ATF_CHECK(sp != NULL);
    411  1.7  riastrad 		ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0,
    412  1.7  riastrad 		    "[%u] thread called with misaligned sp: %p", i, signalsp);
    413  1.7  riastrad 	}
    414  1.7  riastrad 
    415  1.7  riastrad 	for (i = 0; i <= STACK_ALIGNBYTES; i++) {
    416  1.7  riastrad 		pthread_t t;
    417  1.7  riastrad 		pthread_attr_t attr;
    418  1.7  riastrad 		void *sp;
    419  1.7  riastrad 
    420  1.7  riastrad 		RZ(pthread_attr_init(&attr));
    421  1.7  riastrad 		RZ(pthread_attr_setstack(&attr, stack + i, SIGSTKSZ));
    422  1.7  riastrad 		RZ(pthread_create(&t, &attr, &threadspfunc, NULL));
    423  1.7  riastrad 		RZ(pthread_attr_destroy(&attr));
    424  1.7  riastrad 
    425  1.7  riastrad 		alarm(1);
    426  1.7  riastrad 		RZ(pthread_join(t, &sp));
    427  1.7  riastrad 		alarm(0);
    428  1.7  riastrad 
    429  1.7  riastrad 		ATF_CHECK(sp != NULL);
    430  1.7  riastrad 		ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0,
    431  1.7  riastrad 		    "[%u] thread called with misaligned sp: %p", i, signalsp);
    432  1.7  riastrad 	}
    433  1.7  riastrad #else
    434  1.7  riastrad 	atf_tc_skip("Not implemented on this platform");
    435  1.7  riastrad #endif
    436  1.7  riastrad }
    437  1.7  riastrad 
    438  1.1       pho ATF_TC(misaligned_sp_and_signal);
    439  1.1       pho ATF_TC_HEAD(misaligned_sp_and_signal, tc)
    440  1.1       pho {
    441  1.1       pho 	atf_tc_set_md_var(tc, "descr", "process can return from a signal"
    442  1.1       pho 	    " handler even if the stack pointer is misaligned when a signal"
    443  1.1       pho 	    " arrives");
    444  1.1       pho }
    445  1.1       pho ATF_TC_BODY(misaligned_sp_and_signal, tc)
    446  1.1       pho {
    447  1.2  riastrad #if defined STACK_ALIGNBYTES && defined HAVE_STACK_POINTER_H
    448  1.1       pho 	/*
    449  1.1       pho 	 * Set up a handler for SIGALRM.
    450  1.1       pho 	 */
    451  1.1       pho 	struct sigaction sa;
    452  1.1       pho 	memset(&sa, 0, sizeof(sa));
    453  1.2  riastrad 	sa.sa_handler = &signalsphandler;
    454  1.2  riastrad 	RL(sigaction(SIGALRM, &sa, NULL));
    455  1.1       pho 
    456  1.6  riastrad #if defined __alpha__ || defined __i386__ || defined __mips__
    457  1.4  riastrad 	atf_tc_expect_fail("PR kern/58149:"
    458  1.4  riastrad 	    " Cannot return from a signal handler"
    459  1.4  riastrad 	    " if SP was misaligned when the signal arrived");
    460  1.4  riastrad #endif
    461  1.4  riastrad 
    462  1.1       pho 	/*
    463  1.1       pho 	 * Set up an interval timer so that we receive SIGALRM after 50 ms.
    464  1.1       pho 	 */
    465  1.1       pho 	struct itimerval itv;
    466  1.1       pho 	memset(&itv, 0, sizeof(itv));
    467  1.1       pho 	itv.it_value.tv_usec = 1000 * 50;
    468  1.2  riastrad 	RL(setitimer(ITIMER_MONOTONIC, &itv, NULL));
    469  1.1       pho 
    470  1.1       pho 	/*
    471  1.1       pho 	 * Now misalign the SP. Wait for the signal to arrive and see what
    472  1.1       pho 	 * happens. This should be fine as long as we don't use it to
    473  1.1       pho 	 * access memory.
    474  1.1       pho 	 */
    475  1.1       pho 	MISALIGN_SP;
    476  1.2  riastrad 	while (signalsp == NULL) {
    477  1.1       pho 		/*
    478  1.1       pho 		 * Make sure the compiler does not optimize this busy loop
    479  1.1       pho 		 * away.
    480  1.1       pho 		 */
    481  1.2  riastrad 		__asm__("" ::: "memory");
    482  1.1       pho 	}
    483  1.1       pho 	/*
    484  1.1       pho 	 * We could successfully return from a signal handler. Now we
    485  1.1       pho 	 * should fix the SP before calling any functions.
    486  1.1       pho 	 */
    487  1.1       pho 	FIX_SP;
    488  1.1       pho 
    489  1.1       pho 	/*
    490  1.1       pho 	 * But was the stack pointer aligned when we were on the signal
    491  1.1       pho 	 * handler?
    492  1.1       pho 	 */
    493  1.2  riastrad 	ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0,
    494  1.1       pho 	    "signal handler was called with a misaligned sp: %p",
    495  1.2  riastrad 	    signalsp);
    496  1.1       pho #else
    497  1.1       pho 	atf_tc_skip("Not implemented for this platform");
    498  1.1       pho #endif
    499  1.1       pho }
    500  1.1       pho 
    501  1.1       pho ATF_TP_ADD_TCS(tp)
    502  1.1       pho {
    503  1.2  riastrad 
    504  1.7  riastrad 	ATF_TP_ADD_TC(tp, contextsp);
    505  1.2  riastrad 	ATF_TP_ADD_TC(tp, execsp_dynamic);
    506  1.2  riastrad 	ATF_TP_ADD_TC(tp, execsp_static);
    507  1.1       pho 	ATF_TP_ADD_TC(tp, misaligned_sp_and_signal);
    508  1.2  riastrad 	ATF_TP_ADD_TC(tp, signalsp);
    509  1.2  riastrad 	ATF_TP_ADD_TC(tp, signalsp_sigaltstack);
    510  1.7  riastrad 	ATF_TP_ADD_TC(tp, threadsp);
    511  1.1       pho 	return atf_no_error();
    512  1.1       pho }
    513