Merge branch 'elf-move'
[platform/upstream/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, see
18    <http://www.gnu.org/licenses/>.  */
19
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>
30
31 jmp_buf _hurdsig_fault_env;
32 struct hurd_signal_preemptor _hurdsig_fault_preemptor = {0};
33
34 /* XXX temporary to deal with spelling fix */
35 weak_alias (_hurdsig_fault_preemptor, _hurdsig_fault_preempter)
36
37 static mach_port_t forward_sigexc;
38
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
51                                       )
52 {
53   int signo;
54   struct hurd_signal_detail d;
55
56   if (port != forward_sigexc ||
57       thread != _hurd_msgport_thread || task != __mach_task_self ())
58     return EPERM;               /* Strange bogosity.  */
59
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
69
70   /* Call the machine-dependent function to translate the Mach exception
71      codes into a signal number and subcode.  */
72   _hurd_exception2signal (&d, &signo);
73
74   return HURD_PREEMPT_SIGNAL_P (&_hurdsig_fault_preemptor, signo, d.code)
75     ? 0 : EGREGIOUS;
76 }
77
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.
82  */
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)
94 {
95   abort ();
96   return KERN_FAILURE;
97 }
98
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)
112 {
113   abort ();
114   return KERN_FAILURE;
115 }
116 #endif
117
118
119 #ifdef NDR_CHAR_ASCII           /* OSF Mach flavors have different names.  */
120 # define mig_reply_header_t     mig_reply_error_t
121 #endif
122
123 static void
124 faulted (void)
125 {
126   struct
127     {
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 *);
134
135  /* Wait for the exception_raise message forwarded by the proc server.  */
136
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");
142
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);
151
152   if (reply.RetCode)
153     __libc_fatal ("BUG: unexpected fault in signal thread\n");
154
155   _hurdsig_fault_preemptor.signals = 0;
156   longjmp (_hurdsig_fault_env, 1);
157 }
158
159 static char faultstack[1024];
160
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)'.  */
165
166 void
167 _hurdsig_fault_init (void)
168 {
169   error_t err;
170   struct machine_thread_state state;
171   mach_port_t sigexc;
172
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);
181
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);
187
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
192   {
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);
199   }
200 #else
201   err = __mach_port_set_qlimit (__mach_task_self (), forward_sigexc, 1);
202 #endif
203   assert_perror (err);
204
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);
210
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);
220
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);
238 }