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