s390: Use dl-symbol-redir-ifunc.h on cpu-tunables
[glibc.git] / hurd / hurdfault.c
blob1578b88ea603edf5a98f9514d55d08b4e5d908af
1 /* Handle faults in the signal thread.
2 Copyright (C) 1994-2023 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 #include <hurd.h>
20 #include <hurd/signal.h>
21 #include "hurdfault.h"
22 #include <errno.h>
23 #include <string.h>
24 #include <setjmp.h>
25 #include <stdio.h>
26 #include <thread_state.h>
27 #include "faultexc_server.h" /* mig-generated header for our exc server. */
28 #include <assert.h>
30 jmp_buf _hurdsig_fault_env;
31 struct hurd_signal_preemptor _hurdsig_fault_preemptor = {0};
33 /* XXX temporary to deal with spelling fix */
34 weak_alias (_hurdsig_fault_preemptor, _hurdsig_fault_preempter)
36 static mach_port_t forward_sigexc;
38 kern_return_t
39 _hurdsig_fault_catch_exception_raise (mach_port_t port,
40 thread_t thread,
41 task_t task,
42 #ifdef EXC_MASK_ALL /* New interface flavor. */
43 exception_type_t exception,
44 exception_data_t code,
45 mach_msg_type_number_t codeCnt
46 #else /* Vanilla Mach 3.0 interface. */
47 integer_t exception,
48 integer_t code, long_integer_t subcode
49 #endif
52 int signo;
53 struct hurd_signal_detail d;
55 if (port != forward_sigexc
56 || thread != _hurd_msgport_thread || task != __mach_task_self ())
57 return EPERM; /* Strange bogosity. */
59 d.exc = exception;
60 #ifdef EXC_MASK_ALL
61 assert (codeCnt >= 2);
62 d.exc_code = code[0];
63 d.exc_subcode = code[1];
64 #else
65 d.exc_code = code;
66 d.exc_subcode = subcode;
67 #endif
69 /* Call the machine-dependent function to translate the Mach exception
70 codes into a signal number and subcode. */
71 _hurd_exception2signal (&d, &signo);
73 return HURD_PREEMPT_SIGNAL_P (&_hurdsig_fault_preemptor, signo, d.exc_subcode)
74 ? 0 : EGREGIOUS;
77 #ifdef EXC_MASK_ALL
78 /* XXX New interface flavor has additional RPCs that we could be using
79 instead. These RPCs roll a thread_get_state/thread_set_state into
80 the message, so the signal thread ought to use these to save some calls.
82 kern_return_t
83 _hurdsig_fault_catch_exception_raise_state
84 (mach_port_t port,
85 exception_type_t exception,
86 exception_data_t code,
87 mach_msg_type_number_t codeCnt,
88 int *flavor,
89 thread_state_t old_state,
90 mach_msg_type_number_t old_stateCnt,
91 thread_state_t new_state,
92 mach_msg_type_number_t *new_stateCnt)
94 abort ();
95 return KERN_FAILURE;
98 kern_return_t
99 _hurdsig_fault_catch_exception_raise_state_identity
100 (mach_port_t exception_port,
101 thread_t thread,
102 task_t task,
103 exception_type_t exception,
104 exception_data_t code,
105 mach_msg_type_number_t codeCnt,
106 int *flavor,
107 thread_state_t old_state,
108 mach_msg_type_number_t old_stateCnt,
109 thread_state_t new_state,
110 mach_msg_type_number_t *new_stateCnt)
112 abort ();
113 return KERN_FAILURE;
115 #endif
118 static void
119 faulted (void)
121 struct
123 mach_msg_header_t head;
124 char buf[64];
125 } request;
126 mig_reply_header_t reply;
127 extern int _hurdsig_fault_exc_server (mach_msg_header_t *,
128 mach_msg_header_t *);
130 /* Wait for the exception_raise message forwarded by the proc server. */
132 if (__mach_msg (&request.head, MACH_RCV_MSG, 0,
133 sizeof request, forward_sigexc,
134 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL)
135 != MACH_MSG_SUCCESS)
136 __libc_fatal ("msg receive failed on signal thread exc\n");
138 /* Run the exc demuxer which should call the server function above.
139 That function returns 0 if the exception was expected. */
140 _hurdsig_fault_exc_server (&request.head, &reply.Head);
141 if (reply.Head.msgh_remote_port != MACH_PORT_NULL)
142 __mach_msg (&reply.Head, MACH_SEND_MSG, reply.Head.msgh_size,
143 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
144 if (reply.RetCode == MIG_BAD_ID)
145 __mach_msg_destroy (&request.head);
147 if (reply.RetCode)
148 __libc_fatal ("BUG: unexpected fault in signal thread\n");
150 _hurdsig_fault_preemptor.signals = 0;
151 longjmp (_hurdsig_fault_env, 1);
154 static char faultstack[1024];
156 /* Send exceptions for the signal thread to the proc server.
157 It will forward the message on to our message port,
158 and then restore the thread's state to code which
159 does `longjmp (_hurd_sigthread_fault_env, 1)'. */
161 void
162 _hurdsig_fault_init (void)
164 error_t err;
165 struct machine_thread_state state;
166 mach_port_t sigexc;
168 /* Allocate a port to receive signal thread exceptions.
169 We will move this receive right to the proc server. */
170 err = __mach_port_allocate (__mach_task_self (),
171 MACH_PORT_RIGHT_RECEIVE, &sigexc);
172 assert_perror (err);
173 err = __mach_port_insert_right (__mach_task_self (), sigexc,
174 sigexc, MACH_MSG_TYPE_MAKE_SEND);
175 assert_perror (err);
177 /* Allocate a port to receive the exception msgs forwarded
178 from the proc server. */
179 err = __mach_port_allocate (__mach_task_self (),
180 MACH_PORT_RIGHT_RECEIVE, &forward_sigexc);
181 assert_perror (err);
183 /* Set the queue limit for this port to just one. The proc server will
184 notice if we ever get a second exception while one remains queued and
185 unreceived, and decide we are hopelessly buggy. */
186 #ifdef MACH_PORT_RECEIVE_STATUS_COUNT
188 const mach_port_limits_t lim = { mpl_qlimit: 1 };
189 assert (MACH_PORT_RECEIVE_STATUS_COUNT == sizeof lim / sizeof (natural_t));
190 err = __mach_port_set_attributes (__mach_task_self (), forward_sigexc,
191 MACH_PORT_RECEIVE_STATUS,
192 (mach_port_info_t) &lim,
193 MACH_PORT_RECEIVE_STATUS_COUNT);
195 #else
196 err = __mach_port_set_qlimit (__mach_task_self (), forward_sigexc, 1);
197 #endif
198 assert_perror (err);
200 /* This state will be restored when we fault.
201 It runs the function above. */
202 memset (&state, 0, sizeof state);
203 MACHINE_THREAD_STATE_FIX_NEW (&state);
204 MACHINE_THREAD_STATE_SETUP_CALL (&state, faultstack,
205 sizeof faultstack, faulted);
207 err = __USEPORT
208 (PROC,
209 __proc_handle_exceptions (port,
210 sigexc,
211 forward_sigexc, MACH_MSG_TYPE_MAKE_SEND,
212 MACHINE_THREAD_STATE_FLAVOR,
213 (natural_t *) &state,
214 MACHINE_THREAD_STATE_COUNT));
215 assert_perror (err);
217 /* Direct signal thread exceptions to the proc server. */
218 #ifdef THREAD_EXCEPTION_PORT
219 err = __thread_set_special_port (_hurd_msgport_thread,
220 THREAD_EXCEPTION_PORT, sigexc);
221 #elif defined (EXC_MASK_ALL)
222 __thread_set_exception_ports (_hurd_msgport_thread,
223 EXC_MASK_ALL & ~(EXC_MASK_SYSCALL
224 | EXC_MASK_MACH_SYSCALL
225 | EXC_MASK_RPC_ALERT),
226 sigexc,
227 EXCEPTION_STATE_IDENTITY,
228 MACHINE_THREAD_STATE);
229 #else
230 # error thread_set_exception_ports?
231 #endif
232 __mach_port_deallocate (__mach_task_self (), sigexc);
233 assert_perror (err);