2.3.5-3
[glibc.git] / hurd / hurdfault.c
blob6ab5a9787691bdcb737883b533e651325a15d749
1 /* Handle faults in the signal thread.
2 Copyright (C) 1994,95,96,97,2002 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, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
20 #include <hurd.h>
21 #include <hurd/signal.h>
22 #include "hurdfault.h"
23 #include <errno.h>
24 #include <string.h>
25 #include <setjmp.h>
26 #include <stdio.h>
27 #include "thread_state.h"
28 #include "faultexc_server.h" /* mig-generated header for our exc server. */
29 #include <assert.h>
31 jmp_buf _hurdsig_fault_env;
32 struct hurd_signal_preemptor _hurdsig_fault_preemptor = {0};
34 /* XXX temporary to deal with spelling fix */
35 weak_alias (_hurdsig_fault_preemptor, _hurdsig_fault_preempter)
37 static mach_port_t forward_sigexc;
39 kern_return_t
40 _hurdsig_fault_catch_exception_raise (mach_port_t port,
41 thread_t thread,
42 task_t task,
43 #ifdef EXC_MASK_ALL /* New interface flavor. */
44 exception_type_t exception,
45 exception_data_t code,
46 mach_msg_type_number_t codeCnt
47 #else /* Vanilla Mach 3.0 interface. */
48 integer_t exception,
49 integer_t code, integer_t subcode
50 #endif
53 int signo;
54 struct hurd_signal_detail d;
56 if (port != forward_sigexc ||
57 thread != _hurd_msgport_thread || task != __mach_task_self ())
58 return EPERM; /* Strange bogosity. */
60 d.exc = exception;
61 #ifdef EXC_MASK_ALL
62 assert (codeCnt >= 2);
63 d.exc_code = code[0];
64 d.exc_subcode = code[1];
65 #else
66 d.exc_code = code;
67 d.exc_subcode = subcode;
68 #endif
70 /* Call the machine-dependent function to translate the Mach exception
71 codes into a signal number and subcode. */
72 _hurd_exception2signal (&d, &signo);
74 return HURD_PREEMPT_SIGNAL_P (&_hurdsig_fault_preemptor, signo, d.code)
75 ? 0 : EGREGIOUS;
78 #ifdef EXC_MASK_ALL
79 /* XXX New interface flavor has additional RPCs that we could be using
80 instead. These RPCs roll a thread_get_state/thread_set_state into
81 the message, so the signal thread ought to use these to save some calls.
83 kern_return_t
84 _hurdsig_fault_catch_exception_raise_state
85 (mach_port_t port,
86 exception_type_t exception,
87 exception_data_t code,
88 mach_msg_type_number_t codeCnt,
89 int *flavor,
90 thread_state_t old_state,
91 mach_msg_type_number_t old_stateCnt,
92 thread_state_t new_state,
93 mach_msg_type_number_t *new_stateCnt)
95 abort ();
96 return KERN_FAILURE;
99 kern_return_t
100 _hurdsig_fault_catch_exception_raise_state_identity
101 (mach_port_t exception_port,
102 thread_t thread,
103 task_t task,
104 exception_type_t exception,
105 exception_data_t code,
106 mach_msg_type_number_t codeCnt,
107 int *flavor,
108 thread_state_t old_state,
109 mach_msg_type_number_t old_stateCnt,
110 thread_state_t new_state,
111 mach_msg_type_number_t *new_stateCnt)
113 abort ();
114 return KERN_FAILURE;
116 #endif
119 #ifdef NDR_CHAR_ASCII /* OSF Mach flavors have different names. */
120 # define mig_reply_header_t mig_reply_error_t
121 #endif
123 static void
124 faulted (void)
126 struct
128 mach_msg_header_t head;
129 char buf[64];
130 } request;
131 mig_reply_header_t reply;
132 extern int _hurdsig_fault_exc_server (mach_msg_header_t *,
133 mach_msg_header_t *);
135 /* Wait for the exception_raise message forwarded by the proc server. */
137 if (__mach_msg (&request.head, MACH_RCV_MSG, 0,
138 sizeof request, forward_sigexc,
139 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL)
140 != MACH_MSG_SUCCESS)
141 __libc_fatal ("msg receive failed on signal thread exc\n");
143 /* Run the exc demuxer which should call the server function above.
144 That function returns 0 if the exception was expected. */
145 _hurdsig_fault_exc_server (&request.head, &reply.Head);
146 if (reply.Head.msgh_remote_port != MACH_PORT_NULL)
147 __mach_msg (&reply.Head, MACH_SEND_MSG, reply.Head.msgh_size,
148 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
149 if (reply.RetCode == MIG_BAD_ID)
150 __mach_msg_destroy (&request.head);
152 if (reply.RetCode)
153 __libc_fatal ("BUG: unexpected fault in signal thread\n");
155 _hurdsig_fault_preemptor.signals = 0;
156 longjmp (_hurdsig_fault_env, 1);
159 static char faultstack[1024];
161 /* Send exceptions for the signal thread to the proc server.
162 It will forward the message on to our message port,
163 and then restore the thread's state to code which
164 does `longjmp (_hurd_sigthread_fault_env, 1)'. */
166 void
167 _hurdsig_fault_init (void)
169 error_t err;
170 struct machine_thread_state state;
171 mach_port_t sigexc;
173 /* Allocate a port to receive signal thread exceptions.
174 We will move this receive right to the proc server. */
175 err = __mach_port_allocate (__mach_task_self (),
176 MACH_PORT_RIGHT_RECEIVE, &sigexc);
177 assert_perror (err);
178 err = __mach_port_allocate (__mach_task_self (),
179 MACH_PORT_RIGHT_RECEIVE, &forward_sigexc);
180 assert_perror (err);
182 /* Allocate a port to receive the exception msgs forwarded
183 from the proc server. */
184 err = __mach_port_insert_right (__mach_task_self (), sigexc,
185 sigexc, MACH_MSG_TYPE_MAKE_SEND);
186 assert_perror (err);
188 /* Set the queue limit for this port to just one. The proc server will
189 notice if we ever get a second exception while one remains queued and
190 unreceived, and decide we are hopelessly buggy. */
191 #ifdef MACH_PORT_RECEIVE_STATUS_COUNT
193 const mach_port_limits_t lim = { mpl_qlimit: 1 };
194 assert (MACH_PORT_RECEIVE_STATUS_COUNT == sizeof lim / sizeof (natural_t));
195 err = __mach_port_set_attributes (__mach_task_self (), forward_sigexc,
196 MACH_PORT_RECEIVE_STATUS,
197 (mach_port_info_t) &lim,
198 MACH_PORT_RECEIVE_STATUS_COUNT);
200 #else
201 err = __mach_port_set_qlimit (__mach_task_self (), forward_sigexc, 1);
202 #endif
203 assert_perror (err);
205 /* This state will be restored when we fault.
206 It runs the function above. */
207 memset (&state, 0, sizeof state);
208 MACHINE_THREAD_STATE_SET_PC (&state, faulted);
209 MACHINE_THREAD_STATE_SET_SP (&state, faultstack, sizeof faultstack);
211 err = __USEPORT
212 (PROC,
213 __proc_handle_exceptions (port,
214 sigexc,
215 forward_sigexc, MACH_MSG_TYPE_MAKE_SEND,
216 MACHINE_THREAD_STATE_FLAVOR,
217 (natural_t *) &state,
218 MACHINE_THREAD_STATE_COUNT));
219 assert_perror (err);
221 /* Direct signal thread exceptions to the proc server. */
222 #ifdef THREAD_EXCEPTION_PORT
223 err = __thread_set_special_port (_hurd_msgport_thread,
224 THREAD_EXCEPTION_PORT, sigexc);
225 #elif defined (EXC_MASK_ALL)
226 __thread_set_exception_ports (_hurd_msgport_thread,
227 EXC_MASK_ALL & ~(EXC_MASK_SYSCALL
228 | EXC_MASK_MACH_SYSCALL
229 | EXC_MASK_RPC_ALERT),
230 sigexc,
231 EXCEPTION_STATE_IDENTITY,
232 MACHINE_THREAD_STATE);
233 #else
234 # error thread_set_exception_ports?
235 #endif
236 __mach_port_deallocate (__mach_task_self (), sigexc);
237 assert_perror (err);