148fb7bfaSmrg /* Thread library support for -fsplit-stack. */
2*b1e83836Smrg /* Copyright (C) 2009-2022 Free Software Foundation, Inc.
348fb7bfaSmrg Contributed by Ian Lance Taylor <iant@google.com>.
448fb7bfaSmrg
548fb7bfaSmrg This file is part of GCC.
648fb7bfaSmrg
748fb7bfaSmrg GCC is free software; you can redistribute it and/or modify it under
848fb7bfaSmrg the terms of the GNU General Public License as published by the Free
948fb7bfaSmrg Software Foundation; either version 3, or (at your option) any later
1048fb7bfaSmrg version.
1148fb7bfaSmrg
1248fb7bfaSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1348fb7bfaSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
1448fb7bfaSmrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1548fb7bfaSmrg for more details.
1648fb7bfaSmrg
1748fb7bfaSmrg Under Section 7 of GPL version 3, you are granted additional
1848fb7bfaSmrg permissions described in the GCC Runtime Library Exception, version
1948fb7bfaSmrg 3.1, as published by the Free Software Foundation.
2048fb7bfaSmrg
2148fb7bfaSmrg You should have received a copy of the GNU General Public License and
2248fb7bfaSmrg a copy of the GCC Runtime Library Exception along with this program;
2348fb7bfaSmrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
2448fb7bfaSmrg <http://www.gnu.org/licenses/>. */
2548fb7bfaSmrg
2648fb7bfaSmrg #include "tconfig.h"
2748fb7bfaSmrg #include "tsystem.h"
2848fb7bfaSmrg #include "coretypes.h"
2948fb7bfaSmrg #include "tm.h"
3048fb7bfaSmrg #include "libgcc_tm.h"
3148fb7bfaSmrg
3248fb7bfaSmrg /* If inhibit_libc is defined, we cannot compile this file. The
3348fb7bfaSmrg effect is that people will not be able to use -fsplit-stack. That
3448fb7bfaSmrg is much better than failing the build particularly since people
3548fb7bfaSmrg will want to define inhibit_libc while building a compiler which
3648fb7bfaSmrg can build glibc. */
3748fb7bfaSmrg
3848fb7bfaSmrg #ifndef inhibit_libc
3948fb7bfaSmrg
4048fb7bfaSmrg #include <errno.h>
41*b1e83836Smrg #include <signal.h>
4248fb7bfaSmrg #include <pthread.h>
4348fb7bfaSmrg
4448fb7bfaSmrg #include "generic-morestack.h"
4548fb7bfaSmrg
4648fb7bfaSmrg /* We declare the pthread functions we need as weak, so that
4748fb7bfaSmrg libgcc_s.so does not need to be linked against -lpthread. */
4848fb7bfaSmrg
4948fb7bfaSmrg extern int pthread_once (pthread_once_t *, void (*) (void))
5048fb7bfaSmrg __attribute__ ((weak));
5148fb7bfaSmrg
5248fb7bfaSmrg extern int pthread_key_create (pthread_key_t *, void (*) (void *))
5348fb7bfaSmrg __attribute__ ((weak));
5448fb7bfaSmrg
5548fb7bfaSmrg extern int pthread_setspecific (pthread_key_t, const void *)
5648fb7bfaSmrg __attribute__ ((weak));
5748fb7bfaSmrg
58*b1e83836Smrg extern int pthread_sigmask (int, const sigset_t *, sigset_t *)
59*b1e83836Smrg __attribute__ ((weak));
60*b1e83836Smrg
6148fb7bfaSmrg /* The key for the list of stack segments to free when the thread
6248fb7bfaSmrg exits. This is created by pthread_key_create. */
6348fb7bfaSmrg
6448fb7bfaSmrg static pthread_key_t segment_list_key;
6548fb7bfaSmrg
6648fb7bfaSmrg /* Used to only run create_key once. */
6748fb7bfaSmrg
6848fb7bfaSmrg static pthread_once_t create_key_once = PTHREAD_ONCE_INIT;
6948fb7bfaSmrg
7048fb7bfaSmrg /* Release all the segments for a thread. This is the destructor
7148fb7bfaSmrg function used by pthread_key_create, and is called when a thread
7248fb7bfaSmrg exits. */
7348fb7bfaSmrg
7448fb7bfaSmrg static void
free_segments(void * arg)7548fb7bfaSmrg free_segments (void* arg)
7648fb7bfaSmrg {
77*b1e83836Smrg /* We must block signals in case the signal handler tries to split
78*b1e83836Smrg the stack. We leave them blocked while the thread exits. */
79*b1e83836Smrg if (pthread_sigmask)
80*b1e83836Smrg {
81*b1e83836Smrg sigset_t mask;
82*b1e83836Smrg
83*b1e83836Smrg sigfillset (&mask);
84*b1e83836Smrg pthread_sigmask (SIG_BLOCK, &mask, NULL);
85*b1e83836Smrg }
86*b1e83836Smrg
8748fb7bfaSmrg __morestack_release_segments ((struct stack_segment **) arg, 1);
8848fb7bfaSmrg }
8948fb7bfaSmrg
9048fb7bfaSmrg /* Set up the key for the list of segments. This is called via
9148fb7bfaSmrg pthread_once. */
9248fb7bfaSmrg
9348fb7bfaSmrg static void
create_key(void)9448fb7bfaSmrg create_key (void)
9548fb7bfaSmrg {
9648fb7bfaSmrg int err;
9748fb7bfaSmrg
9848fb7bfaSmrg err = pthread_key_create (&segment_list_key, free_segments);
9948fb7bfaSmrg if (err != 0)
10048fb7bfaSmrg {
10148fb7bfaSmrg static const char msg[] = "pthread_key_create failed: errno ";
10248fb7bfaSmrg __morestack_fail (msg, sizeof msg - 1, err);
10348fb7bfaSmrg }
10448fb7bfaSmrg }
10548fb7bfaSmrg
10648fb7bfaSmrg /* Pass information from the pthread_create wrapper to
10748fb7bfaSmrg stack_split_initialize_thread. */
10848fb7bfaSmrg
10948fb7bfaSmrg struct pthread_create_args
11048fb7bfaSmrg {
11148fb7bfaSmrg void *(*start_routine) (void *);
11248fb7bfaSmrg void *arg;
11348fb7bfaSmrg };
11448fb7bfaSmrg
11548fb7bfaSmrg /* Initialize a thread. This is called via pthread_create. It calls
11648fb7bfaSmrg a target dependent function to set up any required stack guard. */
11748fb7bfaSmrg
11848fb7bfaSmrg static void* stack_split_initialize_thread (void *)
11948fb7bfaSmrg __attribute__ ((no_split_stack));
12048fb7bfaSmrg
12148fb7bfaSmrg static void *
stack_split_initialize_thread(void * varg)12248fb7bfaSmrg stack_split_initialize_thread (void *varg)
12348fb7bfaSmrg {
12448fb7bfaSmrg struct pthread_create_args *args = (struct pthread_create_args *) varg;
12548fb7bfaSmrg int err;
12648fb7bfaSmrg void *(*start_routine) (void *);
12748fb7bfaSmrg void *arg;
12848fb7bfaSmrg
12948fb7bfaSmrg __stack_split_initialize ();
13048fb7bfaSmrg
13148fb7bfaSmrg err = pthread_setspecific (segment_list_key, (void *) &__morestack_segments);
13248fb7bfaSmrg if (err != 0)
13348fb7bfaSmrg {
13448fb7bfaSmrg static const char msg[] = "pthread_setspecific failed: errno ";
13548fb7bfaSmrg __morestack_fail (msg, sizeof msg - 1, err);
13648fb7bfaSmrg }
13748fb7bfaSmrg
13848fb7bfaSmrg start_routine = args->start_routine;
13948fb7bfaSmrg arg = args->arg;
14048fb7bfaSmrg free (args);
14148fb7bfaSmrg return (*start_routine) (arg);
14248fb7bfaSmrg }
14348fb7bfaSmrg
14448fb7bfaSmrg /* This function wraps calls to pthread_create to make sure that the
14548fb7bfaSmrg stack guard is initialized for new threads. FIXME: This hack will
14648fb7bfaSmrg not be necessary if glibc supports -fsplit-stack directly. */
14748fb7bfaSmrg
14848fb7bfaSmrg int __wrap_pthread_create (pthread_t *, const pthread_attr_t *,
14948fb7bfaSmrg void *(*start_routine) (void *), void *)
15048fb7bfaSmrg __attribute__ ((visibility ("hidden")));
15148fb7bfaSmrg
15248fb7bfaSmrg extern int __real_pthread_create (pthread_t *, const pthread_attr_t *,
15348fb7bfaSmrg void *(*start_routine) (void *), void *)
15448fb7bfaSmrg __attribute__ ((weak));
15548fb7bfaSmrg
15648fb7bfaSmrg int
__wrap_pthread_create(pthread_t * tid,const pthread_attr_t * attr,void * (* start_routine)(void *),void * arg)15748fb7bfaSmrg __wrap_pthread_create (pthread_t *tid, const pthread_attr_t *attr,
15848fb7bfaSmrg void *(*start_routine) (void *), void *arg)
15948fb7bfaSmrg {
16048fb7bfaSmrg int err;
16148fb7bfaSmrg struct pthread_create_args* args;
16248fb7bfaSmrg
16348fb7bfaSmrg err = pthread_once (&create_key_once, create_key);
16448fb7bfaSmrg if (err != 0)
16548fb7bfaSmrg {
16648fb7bfaSmrg static const char msg[] = "pthread_once failed: errno ";
16748fb7bfaSmrg __morestack_fail (msg, sizeof msg - 1, err);
16848fb7bfaSmrg }
16948fb7bfaSmrg
17048fb7bfaSmrg args = malloc (sizeof (struct pthread_create_args));
17148fb7bfaSmrg if (args == NULL)
17248fb7bfaSmrg return EAGAIN;
17348fb7bfaSmrg args->start_routine = start_routine;
17448fb7bfaSmrg args->arg = arg;
17548fb7bfaSmrg return __real_pthread_create (tid, attr, stack_split_initialize_thread, args);
17648fb7bfaSmrg }
17748fb7bfaSmrg
17848fb7bfaSmrg #endif /* !defined (inhibit_libc) */
179