Home | History | Annotate | Line # | Download | only in kernel
t_signal_and_sp.c revision 1.9
      1  1.9  riastrad /*	$NetBSD: t_signal_and_sp.c,v 1.9 2025/04/21 03:48:07 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.9  riastrad __RCSID("$NetBSD: t_signal_and_sp.c,v 1.9 2025/04/21 03:48:07 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.9  riastrad static ucontext_t 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.9  riastrad static void
    215  1.9  riastrad contextnoop(void)
    216  1.9  riastrad {
    217  1.9  riastrad 
    218  1.9  riastrad 	fprintf(stderr, "contextnoop\n");
    219  1.9  riastrad 	/* control will return to contextspfunc via uc_link */
    220  1.9  riastrad }
    221  1.9  riastrad 
    222  1.7  riastrad void contextdone(void);		/* called by contextspfunc.S */
    223  1.7  riastrad void
    224  1.7  riastrad contextdone(void)
    225  1.7  riastrad {
    226  1.7  riastrad 
    227  1.7  riastrad 	fprintf(stderr, "contextdone\n");
    228  1.7  riastrad 	ATF_REQUIRE(!test_context_done);
    229  1.7  riastrad 	test_context_done = true;
    230  1.7  riastrad 	RL(setcontext(&return_context));
    231  1.7  riastrad 	atf_tc_fail("setcontext returned");
    232  1.7  riastrad }
    233  1.7  riastrad #endif
    234  1.7  riastrad 
    235  1.7  riastrad ATF_TC(contextsp);
    236  1.7  riastrad ATF_TC_HEAD(contextsp, tc)
    237  1.7  riastrad {
    238  1.7  riastrad 	atf_tc_set_md_var(tc, "descr",
    239  1.7  riastrad 	    "Verify stack pointer is aligned on makecontext entry");
    240  1.7  riastrad }
    241  1.7  riastrad ATF_TC_BODY(contextsp, tc)
    242  1.7  riastrad {
    243  1.7  riastrad #if defined STACK_ALIGNBYTES && defined HAVE_CONTEXTSPFUNC
    244  1.9  riastrad 	ucontext_t uc;
    245  1.7  riastrad 	char *stack;
    246  1.7  riastrad 	unsigned i;
    247  1.7  riastrad 
    248  1.9  riastrad #ifdef __hppa__
    249  1.9  riastrad 	/*
    250  1.9  riastrad 	 * Not sure what the deal is but I probably wrote contextspfunc
    251  1.9  riastrad 	 * wrong.
    252  1.9  riastrad 	 */
    253  1.9  riastrad 	atf_tc_expect_signal(SIGILL, "PR kern/59327:"
    254  1.9  riastrad 	    " user stack pointer is not aligned properly");
    255  1.9  riastrad #endif
    256  1.9  riastrad 
    257  1.7  riastrad 	REQUIRE_LIBC(stack = malloc(SIGSTKSZ + STACK_ALIGNBYTES), NULL);
    258  1.9  riastrad 	fprintf(stderr, "stack @ [%p,%p)\n", stack,
    259  1.9  riastrad 	    stack + SIGSTKSZ + STACK_ALIGNBYTES);
    260  1.9  riastrad 
    261  1.9  riastrad 	for (i = 0; i <= STACK_ALIGNBYTES; i++) {
    262  1.9  riastrad 		contextsp = NULL;
    263  1.9  riastrad 		test_context_done = false;
    264  1.9  riastrad 
    265  1.9  riastrad 		RL(getcontext(&uc));
    266  1.9  riastrad 		uc.uc_stack.ss_sp = stack;
    267  1.9  riastrad 		uc.uc_stack.ss_size = SIGSTKSZ + i;
    268  1.9  riastrad 		makecontext(&uc, &contextspfunc, 0);
    269  1.9  riastrad 
    270  1.9  riastrad 		fprintf(stderr, "[%u] swapcontext\n", i);
    271  1.9  riastrad 		RL(swapcontext(&return_context, &uc));
    272  1.9  riastrad 
    273  1.9  riastrad 		ATF_CHECK(contextsp != NULL);
    274  1.9  riastrad 		ATF_CHECK_MSG((uintptr_t)stack <= (uintptr_t)contextsp &&
    275  1.9  riastrad 		    (uintptr_t)contextsp <= (uintptr_t)stack + SIGSTKSZ + i,
    276  1.9  riastrad 		    "contextsp=%p", contextsp);
    277  1.9  riastrad 		ATF_CHECK_MSG(((uintptr_t)contextsp & STACK_ALIGNBYTES) == 0,
    278  1.9  riastrad 		    "[%u] makecontext function called with misaligned sp %p",
    279  1.9  riastrad 		    i, contextsp);
    280  1.9  riastrad 	}
    281  1.9  riastrad 
    282  1.9  riastrad 	for (i = 0; i <= STACK_ALIGNBYTES; i++) {
    283  1.9  riastrad 		contextsp = NULL;
    284  1.9  riastrad 		test_context_done = false;
    285  1.9  riastrad 
    286  1.9  riastrad 		RL(getcontext(&uc));
    287  1.9  riastrad 		uc.uc_stack.ss_sp = stack + i;
    288  1.9  riastrad 		uc.uc_stack.ss_size = SIGSTKSZ;
    289  1.9  riastrad 		makecontext(&uc, &contextspfunc, 0);
    290  1.9  riastrad 
    291  1.9  riastrad 		fprintf(stderr, "[%u] swapcontext\n", i);
    292  1.9  riastrad 		RL(swapcontext(&return_context, &uc));
    293  1.9  riastrad 
    294  1.9  riastrad 		ATF_CHECK(contextsp != NULL);
    295  1.9  riastrad 		ATF_CHECK_MSG((uintptr_t)stack + i <= (uintptr_t)contextsp &&
    296  1.9  riastrad 		    (uintptr_t)contextsp <= (uintptr_t)stack + i + SIGSTKSZ,
    297  1.9  riastrad 		    "contextsp=%p", contextsp);
    298  1.9  riastrad 		ATF_CHECK_MSG(((uintptr_t)contextsp & STACK_ALIGNBYTES) == 0,
    299  1.9  riastrad 		    "[%u] makecontext function called with misaligned sp %p",
    300  1.9  riastrad 		    i, contextsp);
    301  1.9  riastrad 	}
    302  1.9  riastrad #else
    303  1.9  riastrad 	atf_tc_skip("Not implemented on this platform");
    304  1.9  riastrad #endif
    305  1.9  riastrad }
    306  1.9  riastrad 
    307  1.9  riastrad ATF_TC(contextsplink);
    308  1.9  riastrad ATF_TC_HEAD(contextsplink, tc)
    309  1.9  riastrad {
    310  1.9  riastrad 	atf_tc_set_md_var(tc, "descr",
    311  1.9  riastrad 	    "Verify stack pointer is aligned on makecontext link entry");
    312  1.9  riastrad }
    313  1.9  riastrad ATF_TC_BODY(contextsplink, tc)
    314  1.9  riastrad {
    315  1.9  riastrad #if defined STACK_ALIGNBYTES && defined HAVE_CONTEXTSPFUNC
    316  1.9  riastrad 	ucontext_t uc1, uc2;
    317  1.9  riastrad 	char *stack1, *stack2;
    318  1.9  riastrad 	unsigned i;
    319  1.9  riastrad 
    320  1.9  riastrad 	REQUIRE_LIBC(stack1 = malloc(SIGSTKSZ), NULL);
    321  1.9  riastrad 	fprintf(stderr, "stack1 @ [%p,%p)\n", stack1, stack1 + SIGSTKSZ);
    322  1.9  riastrad 	REQUIRE_LIBC(stack2 = malloc(SIGSTKSZ + STACK_ALIGNBYTES), NULL);
    323  1.9  riastrad 	fprintf(stderr, "stack2 @ [%p,%p)\n",
    324  1.9  riastrad 	    stack2, stack2 + SIGSTKSZ + STACK_ALIGNBYTES);
    325  1.9  riastrad 
    326  1.9  riastrad #ifdef __hppa__
    327  1.9  riastrad 	/*
    328  1.9  riastrad 	 * Not sure what the deal is but I probably wrote contextspfunc
    329  1.9  riastrad 	 * wrong.
    330  1.9  riastrad 	 */
    331  1.9  riastrad 	atf_tc_expect_signal(SIGILL, "PR kern/59327:"
    332  1.9  riastrad 	    " user stack pointer is not aligned properly");
    333  1.9  riastrad #endif
    334  1.9  riastrad #ifdef __mips_n64
    335  1.9  riastrad 	atf_tc_expect_fail("PR kern/59327:"
    336  1.9  riastrad 	    " user stack pointer is not aligned properly");
    337  1.9  riastrad #endif
    338  1.7  riastrad 
    339  1.7  riastrad 	for (i = 0; i <= STACK_ALIGNBYTES; i++) {
    340  1.7  riastrad 		contextsp = NULL;
    341  1.7  riastrad 		test_context_done = false;
    342  1.9  riastrad 
    343  1.9  riastrad 		RL(getcontext(&uc1));
    344  1.9  riastrad 		uc1.uc_stack.ss_sp = stack1;
    345  1.9  riastrad 		uc1.uc_stack.ss_size = SIGSTKSZ;
    346  1.9  riastrad 		uc1.uc_link = &uc2;
    347  1.9  riastrad 		makecontext(&uc1, &contextnoop, 0);
    348  1.9  riastrad 
    349  1.9  riastrad 		RL(getcontext(&uc2));
    350  1.9  riastrad 		uc2.uc_stack.ss_sp = stack2;
    351  1.9  riastrad 		uc2.uc_stack.ss_size = SIGSTKSZ + i;
    352  1.9  riastrad 		makecontext(&uc2, &contextspfunc, 0);
    353  1.9  riastrad 
    354  1.7  riastrad 		fprintf(stderr, "[%u] swapcontext\n", i);
    355  1.9  riastrad 		RL(swapcontext(&return_context, &uc1));
    356  1.9  riastrad 
    357  1.7  riastrad 		ATF_CHECK(contextsp != NULL);
    358  1.9  riastrad 		ATF_CHECK_MSG((uintptr_t)stack2 <= (uintptr_t)contextsp &&
    359  1.9  riastrad 		    (uintptr_t)contextsp <= (uintptr_t)stack2 + SIGSTKSZ + i,
    360  1.9  riastrad 		    "contextsp=%p", contextsp);
    361  1.7  riastrad 		ATF_CHECK_MSG(((uintptr_t)contextsp & STACK_ALIGNBYTES) == 0,
    362  1.7  riastrad 		    "[%u] makecontext function called with misaligned sp %p",
    363  1.7  riastrad 		    i, contextsp);
    364  1.7  riastrad 	}
    365  1.7  riastrad 
    366  1.7  riastrad 	for (i = 0; i <= STACK_ALIGNBYTES; i++) {
    367  1.7  riastrad 		contextsp = NULL;
    368  1.7  riastrad 		test_context_done = false;
    369  1.9  riastrad 
    370  1.9  riastrad 		RL(getcontext(&uc1));
    371  1.9  riastrad 		uc1.uc_stack.ss_sp = stack1;
    372  1.9  riastrad 		uc1.uc_stack.ss_size = SIGSTKSZ;
    373  1.9  riastrad 		uc1.uc_link = &uc2;
    374  1.9  riastrad 		makecontext(&uc1, &contextnoop, 0);
    375  1.9  riastrad 
    376  1.9  riastrad 		RL(getcontext(&uc2));
    377  1.9  riastrad 		uc2.uc_stack.ss_sp = stack2 + i;
    378  1.9  riastrad 		uc2.uc_stack.ss_size = SIGSTKSZ;
    379  1.9  riastrad 		makecontext(&uc2, &contextspfunc, 0);
    380  1.9  riastrad 
    381  1.7  riastrad 		fprintf(stderr, "[%u] swapcontext\n", i);
    382  1.9  riastrad 		RL(swapcontext(&return_context, &uc1));
    383  1.9  riastrad 
    384  1.7  riastrad 		ATF_CHECK(contextsp != NULL);
    385  1.9  riastrad 		ATF_CHECK_MSG((uintptr_t)stack2 + i <= (uintptr_t)contextsp &&
    386  1.9  riastrad 		    (uintptr_t)contextsp <= (uintptr_t)stack2 + SIGSTKSZ + i,
    387  1.9  riastrad 		    "contextsp=%p", contextsp);
    388  1.7  riastrad 		ATF_CHECK_MSG(((uintptr_t)contextsp & STACK_ALIGNBYTES) == 0,
    389  1.7  riastrad 		    "[%u] makecontext function called with misaligned sp %p",
    390  1.7  riastrad 		    i, contextsp);
    391  1.7  riastrad 	}
    392  1.7  riastrad #else
    393  1.7  riastrad 	atf_tc_skip("Not implemented on this platform");
    394  1.7  riastrad #endif
    395  1.7  riastrad }
    396  1.7  riastrad 
    397  1.2  riastrad ATF_TC(signalsp);
    398  1.2  riastrad ATF_TC_HEAD(signalsp, tc)
    399  1.2  riastrad {
    400  1.2  riastrad 	atf_tc_set_md_var(tc, "descr",
    401  1.2  riastrad 	    "Verify stack pointer is aligned on entry to signal handler");
    402  1.2  riastrad }
    403  1.2  riastrad ATF_TC_BODY(signalsp, tc)
    404  1.2  riastrad {
    405  1.2  riastrad #if defined STACK_ALIGNBYTES && defined HAVE_SIGNALSPHANDLER
    406  1.2  riastrad 	struct sigaction sa;
    407  1.2  riastrad 
    408  1.2  riastrad 	memset(&sa, 0, sizeof(sa));
    409  1.2  riastrad 	sa.sa_handler = &signalsphandler;
    410  1.2  riastrad 	RL(sigaction(SIGUSR1, &sa, NULL));
    411  1.2  riastrad 	RL(raise(SIGUSR1));
    412  1.2  riastrad 
    413  1.2  riastrad 	ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0,
    414  1.2  riastrad 	    "signal handler was called with a misaligned sp: %p",
    415  1.2  riastrad 	    signalsp);
    416  1.2  riastrad #else
    417  1.2  riastrad 	atf_tc_skip("Not implemented on this platform");
    418  1.2  riastrad #endif
    419  1.2  riastrad }
    420  1.2  riastrad 
    421  1.2  riastrad ATF_TC(signalsp_sigaltstack);
    422  1.2  riastrad ATF_TC_HEAD(signalsp_sigaltstack, tc)
    423  1.2  riastrad {
    424  1.2  riastrad 	atf_tc_set_md_var(tc, "descr",
    425  1.2  riastrad 	    "Verify stack pointer is aligned on entry to signal handler"
    426  1.2  riastrad 	    " with maximally misaligned sigaltstack");
    427  1.2  riastrad }
    428  1.2  riastrad ATF_TC_BODY(signalsp_sigaltstack, tc)
    429  1.2  riastrad {
    430  1.2  riastrad #if defined STACK_ALIGNBYTES && HAVE_SIGNALSPHANDLER
    431  1.2  riastrad 	char *stack;
    432  1.2  riastrad 	struct sigaction sa;
    433  1.2  riastrad 	struct sigaltstack ss;
    434  1.2  riastrad 	unsigned i;
    435  1.2  riastrad 
    436  1.2  riastrad 	memset(&sa, 0, sizeof(sa));
    437  1.2  riastrad 	sa.sa_handler = &signalsphandler;
    438  1.2  riastrad 	sa.sa_flags = SA_ONSTACK;
    439  1.2  riastrad 	RL(sigaction(SIGUSR1, &sa, NULL));
    440  1.2  riastrad 
    441  1.2  riastrad 	/*
    442  1.2  riastrad 	 * Allocate a signal stack with enough slop to try all possible
    443  1.2  riastrad 	 * misalignments of the stack pointer.  Print it to stderr so
    444  1.2  riastrad 	 * it always appears in atf output before shenanigans happen.
    445  1.2  riastrad 	 */
    446  1.2  riastrad 	REQUIRE_LIBC(stack = malloc(SIGSTKSZ + STACK_ALIGNBYTES), NULL);
    447  1.7  riastrad 	fprintf(stderr, "stack @ [%p, %p)\n",
    448  1.2  riastrad 	    stack, stack + SIGSTKSZ + STACK_ALIGNBYTES);
    449  1.2  riastrad 
    450  1.6  riastrad #if defined __alpha__ || defined __i386__ || defined __mips__
    451  1.4  riastrad 	atf_tc_expect_fail("PR kern/59327:"
    452  1.4  riastrad 	    " user stack pointer is not aligned properly");
    453  1.4  riastrad #endif
    454  1.4  riastrad 
    455  1.2  riastrad 	/*
    456  1.2  riastrad 	 * Try with all alignments of high addresses.
    457  1.2  riastrad 	 */
    458  1.2  riastrad 	for (i = 0; i <= STACK_ALIGNBYTES; i++) {
    459  1.2  riastrad 		ss.ss_sp = stack;
    460  1.2  riastrad 		ss.ss_size = SIGSTKSZ + i;
    461  1.2  riastrad 		ss.ss_flags = 0;
    462  1.2  riastrad 		RL(sigaltstack(&ss, NULL));
    463  1.2  riastrad 
    464  1.2  riastrad 		signalsp = NULL;
    465  1.2  riastrad 		RL(raise(SIGUSR1));
    466  1.2  riastrad 		ATF_CHECK(signalsp != NULL);
    467  1.9  riastrad 		ATF_CHECK_MSG((uintptr_t)stack <= (uintptr_t)signalsp &&
    468  1.9  riastrad 		    (uintptr_t)signalsp <= (uintptr_t)stack + SIGSTKSZ + i,
    469  1.9  riastrad 		    "signalsp=%p", signalsp);
    470  1.2  riastrad 		ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0,
    471  1.2  riastrad 		    "[%u] signal handler was called with a misaligned sp: %p",
    472  1.2  riastrad 		    i, signalsp);
    473  1.2  riastrad 	}
    474  1.2  riastrad 
    475  1.2  riastrad 	/*
    476  1.2  riastrad 	 * Try with all alignments of low addresses.
    477  1.2  riastrad 	 */
    478  1.2  riastrad 	for (i = 0; i <= STACK_ALIGNBYTES; i++) {
    479  1.2  riastrad 		ss.ss_sp = stack + i;
    480  1.2  riastrad 		ss.ss_size = SIGSTKSZ;
    481  1.2  riastrad 		ss.ss_flags = 0;
    482  1.2  riastrad 		RL(sigaltstack(&ss, NULL));
    483  1.2  riastrad 
    484  1.2  riastrad 		signalsp = NULL;
    485  1.2  riastrad 		RL(raise(SIGUSR1));
    486  1.2  riastrad 		ATF_CHECK(signalsp != NULL);
    487  1.9  riastrad 		ATF_CHECK_MSG((uintptr_t)stack + i <= (uintptr_t)signalsp &&
    488  1.9  riastrad 		    (uintptr_t)signalsp <= (uintptr_t)stack + i + SIGSTKSZ,
    489  1.9  riastrad 		    "signalsp=%p", signalsp);
    490  1.2  riastrad 		ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0,
    491  1.2  riastrad 		    "[%u] signal handler was called with a misaligned sp: %p",
    492  1.2  riastrad 		    i, signalsp);
    493  1.2  riastrad 	}
    494  1.2  riastrad #else
    495  1.2  riastrad 	atf_tc_skip("Not implemented on this platform");
    496  1.1       pho #endif
    497  1.2  riastrad }
    498  1.1       pho 
    499  1.7  riastrad #if defined STACK_ALIGNBYTES && defined HAVE_THREADSPFUNC
    500  1.7  riastrad void *threadspfunc(void *);	/* threadspfunc.S assembly routine */
    501  1.7  riastrad #endif
    502  1.7  riastrad 
    503  1.7  riastrad ATF_TC(threadsp);
    504  1.7  riastrad ATF_TC_HEAD(threadsp, tc)
    505  1.7  riastrad {
    506  1.7  riastrad 	atf_tc_set_md_var(tc, "descr",
    507  1.7  riastrad 	    "Verify stack pointer is aligned on thread start");
    508  1.7  riastrad }
    509  1.7  riastrad ATF_TC_BODY(threadsp, tc)
    510  1.7  riastrad {
    511  1.7  riastrad #if defined STACK_ALIGNBYTES && defined HAVE_THREADSPFUNC
    512  1.7  riastrad 	char *stack;
    513  1.7  riastrad 	unsigned i;
    514  1.7  riastrad 
    515  1.7  riastrad 	REQUIRE_LIBC(stack = malloc(SIGSTKSZ + STACK_ALIGNBYTES), NULL);
    516  1.9  riastrad 	fprintf(stderr, "stack @ [%p,%p)\n", stack,
    517  1.9  riastrad 	    stack + SIGSTKSZ + STACK_ALIGNBYTES);
    518  1.9  riastrad 
    519  1.9  riastrad #ifdef __hppa__
    520  1.9  riastrad 	/*
    521  1.9  riastrad 	 * Not sure what the deal is but I probably wrote threadspfunc
    522  1.9  riastrad 	 * wrong.
    523  1.9  riastrad 	 */
    524  1.9  riastrad 	atf_tc_expect_signal(SIGBUS, "PR kern/59327:"
    525  1.9  riastrad 	    " user stack pointer is not aligned properly");
    526  1.9  riastrad #endif
    527  1.9  riastrad #ifdef __riscv__
    528  1.9  riastrad 	atf_tc_expect_fail("sp inexplicably lies outside stack range");
    529  1.9  riastrad #endif
    530  1.7  riastrad 
    531  1.7  riastrad 	for (i = 0; i <= STACK_ALIGNBYTES; i++) {
    532  1.7  riastrad 		pthread_t t;
    533  1.7  riastrad 		pthread_attr_t attr;
    534  1.7  riastrad 		void *sp;
    535  1.7  riastrad 
    536  1.7  riastrad 		RZ(pthread_attr_init(&attr));
    537  1.7  riastrad 		RZ(pthread_attr_setstack(&attr, stack, SIGSTKSZ + i));
    538  1.7  riastrad 		RZ(pthread_create(&t, &attr, &threadspfunc, NULL));
    539  1.7  riastrad 		RZ(pthread_attr_destroy(&attr));
    540  1.7  riastrad 
    541  1.7  riastrad 		alarm(1);
    542  1.7  riastrad 		RZ(pthread_join(t, &sp));
    543  1.7  riastrad 		alarm(0);
    544  1.7  riastrad 
    545  1.7  riastrad 		ATF_CHECK(sp != NULL);
    546  1.9  riastrad 		ATF_CHECK_MSG((uintptr_t)stack <= (uintptr_t)sp &&
    547  1.9  riastrad 		    (uintptr_t)sp <= (uintptr_t)stack + SIGSTKSZ + i,
    548  1.9  riastrad 		    "sp=%p", sp);
    549  1.7  riastrad 		ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0,
    550  1.7  riastrad 		    "[%u] thread called with misaligned sp: %p", i, signalsp);
    551  1.7  riastrad 	}
    552  1.7  riastrad 
    553  1.7  riastrad 	for (i = 0; i <= STACK_ALIGNBYTES; i++) {
    554  1.7  riastrad 		pthread_t t;
    555  1.7  riastrad 		pthread_attr_t attr;
    556  1.7  riastrad 		void *sp;
    557  1.7  riastrad 
    558  1.7  riastrad 		RZ(pthread_attr_init(&attr));
    559  1.7  riastrad 		RZ(pthread_attr_setstack(&attr, stack + i, SIGSTKSZ));
    560  1.7  riastrad 		RZ(pthread_create(&t, &attr, &threadspfunc, NULL));
    561  1.7  riastrad 		RZ(pthread_attr_destroy(&attr));
    562  1.7  riastrad 
    563  1.7  riastrad 		alarm(1);
    564  1.7  riastrad 		RZ(pthread_join(t, &sp));
    565  1.7  riastrad 		alarm(0);
    566  1.7  riastrad 
    567  1.7  riastrad 		ATF_CHECK(sp != NULL);
    568  1.9  riastrad 		ATF_CHECK_MSG((uintptr_t)stack + i <= (uintptr_t)sp &&
    569  1.9  riastrad 		    (uintptr_t)sp <= (uintptr_t)stack + i + SIGSTKSZ,
    570  1.9  riastrad 		    "sp=%p", sp);
    571  1.7  riastrad 		ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0,
    572  1.7  riastrad 		    "[%u] thread called with misaligned sp: %p", i, signalsp);
    573  1.7  riastrad 	}
    574  1.7  riastrad #else
    575  1.7  riastrad 	atf_tc_skip("Not implemented on this platform");
    576  1.7  riastrad #endif
    577  1.7  riastrad }
    578  1.7  riastrad 
    579  1.1       pho ATF_TC(misaligned_sp_and_signal);
    580  1.1       pho ATF_TC_HEAD(misaligned_sp_and_signal, tc)
    581  1.1       pho {
    582  1.1       pho 	atf_tc_set_md_var(tc, "descr", "process can return from a signal"
    583  1.1       pho 	    " handler even if the stack pointer is misaligned when a signal"
    584  1.1       pho 	    " arrives");
    585  1.1       pho }
    586  1.1       pho ATF_TC_BODY(misaligned_sp_and_signal, tc)
    587  1.1       pho {
    588  1.2  riastrad #if defined STACK_ALIGNBYTES && defined HAVE_STACK_POINTER_H
    589  1.1       pho 	/*
    590  1.1       pho 	 * Set up a handler for SIGALRM.
    591  1.1       pho 	 */
    592  1.1       pho 	struct sigaction sa;
    593  1.1       pho 	memset(&sa, 0, sizeof(sa));
    594  1.2  riastrad 	sa.sa_handler = &signalsphandler;
    595  1.2  riastrad 	RL(sigaction(SIGALRM, &sa, NULL));
    596  1.1       pho 
    597  1.6  riastrad #if defined __alpha__ || defined __i386__ || defined __mips__
    598  1.4  riastrad 	atf_tc_expect_fail("PR kern/58149:"
    599  1.4  riastrad 	    " Cannot return from a signal handler"
    600  1.4  riastrad 	    " if SP was misaligned when the signal arrived");
    601  1.4  riastrad #endif
    602  1.4  riastrad 
    603  1.1       pho 	/*
    604  1.1       pho 	 * Set up an interval timer so that we receive SIGALRM after 50 ms.
    605  1.1       pho 	 */
    606  1.1       pho 	struct itimerval itv;
    607  1.1       pho 	memset(&itv, 0, sizeof(itv));
    608  1.1       pho 	itv.it_value.tv_usec = 1000 * 50;
    609  1.2  riastrad 	RL(setitimer(ITIMER_MONOTONIC, &itv, NULL));
    610  1.1       pho 
    611  1.1       pho 	/*
    612  1.1       pho 	 * Now misalign the SP. Wait for the signal to arrive and see what
    613  1.1       pho 	 * happens. This should be fine as long as we don't use it to
    614  1.1       pho 	 * access memory.
    615  1.1       pho 	 */
    616  1.1       pho 	MISALIGN_SP;
    617  1.2  riastrad 	while (signalsp == NULL) {
    618  1.1       pho 		/*
    619  1.1       pho 		 * Make sure the compiler does not optimize this busy loop
    620  1.1       pho 		 * away.
    621  1.1       pho 		 */
    622  1.2  riastrad 		__asm__("" ::: "memory");
    623  1.1       pho 	}
    624  1.1       pho 	/*
    625  1.1       pho 	 * We could successfully return from a signal handler. Now we
    626  1.1       pho 	 * should fix the SP before calling any functions.
    627  1.1       pho 	 */
    628  1.1       pho 	FIX_SP;
    629  1.1       pho 
    630  1.1       pho 	/*
    631  1.1       pho 	 * But was the stack pointer aligned when we were on the signal
    632  1.1       pho 	 * handler?
    633  1.1       pho 	 */
    634  1.2  riastrad 	ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0,
    635  1.1       pho 	    "signal handler was called with a misaligned sp: %p",
    636  1.2  riastrad 	    signalsp);
    637  1.1       pho #else
    638  1.1       pho 	atf_tc_skip("Not implemented for this platform");
    639  1.1       pho #endif
    640  1.1       pho }
    641  1.1       pho 
    642  1.1       pho ATF_TP_ADD_TCS(tp)
    643  1.1       pho {
    644  1.2  riastrad 
    645  1.7  riastrad 	ATF_TP_ADD_TC(tp, contextsp);
    646  1.9  riastrad 	ATF_TP_ADD_TC(tp, contextsplink);
    647  1.2  riastrad 	ATF_TP_ADD_TC(tp, execsp_dynamic);
    648  1.2  riastrad 	ATF_TP_ADD_TC(tp, execsp_static);
    649  1.1       pho 	ATF_TP_ADD_TC(tp, misaligned_sp_and_signal);
    650  1.2  riastrad 	ATF_TP_ADD_TC(tp, signalsp);
    651  1.2  riastrad 	ATF_TP_ADD_TC(tp, signalsp_sigaltstack);
    652  1.7  riastrad 	ATF_TP_ADD_TC(tp, threadsp);
    653  1.1       pho 	return atf_no_error();
    654  1.1       pho }
    655