xref: /freebsd/lib/libc/amd64/gen/signalcontext.c (revision 559a218c9b257775fb249b67945fe4a05b7a6b9f)
1d915a14eSPedro F. Giffuni /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3d915a14eSPedro F. Giffuni  *
44adc354cSDaniel Eischen  * Copyright (c) 2003 Marcel Moolenaar
54adc354cSDaniel Eischen  * All rights reserved.
64adc354cSDaniel Eischen  *
74adc354cSDaniel Eischen  * Redistribution and use in source and binary forms, with or without
84adc354cSDaniel Eischen  * modification, are permitted provided that the following conditions
94adc354cSDaniel Eischen  * are met:
104adc354cSDaniel Eischen  *
114adc354cSDaniel Eischen  * 1. Redistributions of source code must retain the above copyright
124adc354cSDaniel Eischen  *    notice, this list of conditions and the following disclaimer.
134adc354cSDaniel Eischen  * 2. Redistributions in binary form must reproduce the above copyright
144adc354cSDaniel Eischen  *    notice, this list of conditions and the following disclaimer in the
154adc354cSDaniel Eischen  *    documentation and/or other materials provided with the distribution.
164adc354cSDaniel Eischen  *
174adc354cSDaniel Eischen  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
184adc354cSDaniel Eischen  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
194adc354cSDaniel Eischen  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
204adc354cSDaniel Eischen  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
214adc354cSDaniel Eischen  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
224adc354cSDaniel Eischen  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
234adc354cSDaniel Eischen  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
244adc354cSDaniel Eischen  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
254adc354cSDaniel Eischen  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
264adc354cSDaniel Eischen  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
274adc354cSDaniel Eischen  */
284adc354cSDaniel Eischen 
294adc354cSDaniel Eischen #include <sys/types.h>
304adc354cSDaniel Eischen #include <sys/ucontext.h>
314adc354cSDaniel Eischen #include <signal.h>
324adc354cSDaniel Eischen #include <stdlib.h>
334adc354cSDaniel Eischen #include <strings.h>
344adc354cSDaniel Eischen 
354adc354cSDaniel Eischen typedef void (*handler_t)(uint64_t, uint64_t, uint64_t);
364adc354cSDaniel Eischen 
374adc354cSDaniel Eischen /* Prototypes */
3837260333SPeter Wemm static void sigctx_wrapper(ucontext_t *ucp, handler_t func, uint64_t *args);
394adc354cSDaniel Eischen 
404adc354cSDaniel Eischen __weak_reference(__signalcontext, signalcontext);
414adc354cSDaniel Eischen 
424adc354cSDaniel Eischen int
__signalcontext(ucontext_t * ucp,int sig,__sighandler_t * func)434adc354cSDaniel Eischen __signalcontext(ucontext_t *ucp, int sig, __sighandler_t *func)
444adc354cSDaniel Eischen {
454adc354cSDaniel Eischen 	uint64_t *args;
464adc354cSDaniel Eischen 	siginfo_t *sig_si;
474adc354cSDaniel Eischen 	ucontext_t *sig_uc;
484adc354cSDaniel Eischen 	uint64_t sp;
494adc354cSDaniel Eischen 
504adc354cSDaniel Eischen 	/* Bail out if we don't have a valid ucontext pointer. */
514adc354cSDaniel Eischen 	if (ucp == NULL)
524adc354cSDaniel Eischen 		abort();
534adc354cSDaniel Eischen 
544adc354cSDaniel Eischen 	/*
554adc354cSDaniel Eischen 	 * Build a signal frame and copy the arguments of signal handler
5637260333SPeter Wemm 	 * 'func' onto the stack and do the funky stack alignment.
5737260333SPeter Wemm 	 * This means that we need an 8-byte-odd alignment since the ABI expects
5837260333SPeter Wemm 	 * the return address to be pushed, thus breaking the 16 byte alignment.
594adc354cSDaniel Eischen 	 */
602ff285bfSDavid Xu 	sp = (ucp->uc_mcontext.mc_rsp - 128 - sizeof(ucontext_t)) & ~15UL;
614adc354cSDaniel Eischen 	sig_uc = (ucontext_t *)sp;
624adc354cSDaniel Eischen 	bcopy(ucp, sig_uc, sizeof(*sig_uc));
634adc354cSDaniel Eischen 	sp = (sp - sizeof(siginfo_t)) & ~15UL;
644adc354cSDaniel Eischen 	sig_si = (siginfo_t *)sp;
654adc354cSDaniel Eischen 	bzero(sig_si, sizeof(*sig_si));
664adc354cSDaniel Eischen 	sig_si->si_signo = sig;
6737260333SPeter Wemm 	sp -= 3 * sizeof(uint64_t);
684adc354cSDaniel Eischen 	args = (uint64_t *)sp;
694adc354cSDaniel Eischen 	args[0] = sig;
704adc354cSDaniel Eischen 	args[1] = (intptr_t)sig_si;
714adc354cSDaniel Eischen 	args[2] = (intptr_t)sig_uc;
724adc354cSDaniel Eischen 	sp -= 16;
734adc354cSDaniel Eischen 
744adc354cSDaniel Eischen 	/*
754adc354cSDaniel Eischen 	 * Setup the ucontext of the signal handler.
764adc354cSDaniel Eischen 	 */
774adc354cSDaniel Eischen 	bzero(&ucp->uc_mcontext, sizeof(ucp->uc_mcontext));
780187c8ffSDavid Xu 	ucp->uc_mcontext.mc_fpformat = _MC_FPFMT_NODEV;
790187c8ffSDavid Xu 	ucp->uc_mcontext.mc_ownedfp = _MC_FPOWNED_NONE;
804adc354cSDaniel Eischen 	ucp->uc_link = sig_uc;
814adc354cSDaniel Eischen 	sigdelset(&ucp->uc_sigmask, sig);
824adc354cSDaniel Eischen 
834160fed5SDavid Xu 	ucp->uc_mcontext.mc_len = sizeof(mcontext_t);
844adc354cSDaniel Eischen 	ucp->uc_mcontext.mc_rdi = (register_t)ucp;
854adc354cSDaniel Eischen 	ucp->uc_mcontext.mc_rsi = (register_t)func;
864adc354cSDaniel Eischen 	ucp->uc_mcontext.mc_rdx = (register_t)args;
874adc354cSDaniel Eischen 	ucp->uc_mcontext.mc_rbp = (register_t)sp;
884adc354cSDaniel Eischen 	ucp->uc_mcontext.mc_rbx = (register_t)sp;
894adc354cSDaniel Eischen 	ucp->uc_mcontext.mc_rsp = (register_t)sp;
9037260333SPeter Wemm 	ucp->uc_mcontext.mc_rip = (register_t)sigctx_wrapper;
914adc354cSDaniel Eischen 	return (0);
924adc354cSDaniel Eischen }
934adc354cSDaniel Eischen 
944adc354cSDaniel Eischen static void
sigctx_wrapper(ucontext_t * ucp,handler_t func,uint64_t * args)9537260333SPeter Wemm sigctx_wrapper(ucontext_t *ucp, handler_t func, uint64_t *args)
964adc354cSDaniel Eischen {
974adc354cSDaniel Eischen 
984adc354cSDaniel Eischen 	(*func)(args[0], args[1], args[2]);
994adc354cSDaniel Eischen 	if (ucp->uc_link == NULL)
1004adc354cSDaniel Eischen 		exit(0);
1014adc354cSDaniel Eischen 	setcontext((const ucontext_t *)ucp->uc_link);
1024adc354cSDaniel Eischen 	/* should never get here */
1034adc354cSDaniel Eischen 	abort();
1044adc354cSDaniel Eischen 	/* NOTREACHED */
1054adc354cSDaniel Eischen }
106