Back to index

glibc  2.9
hurdfault.c
Go to the documentation of this file.
00001 /* Handle faults in the signal thread.
00002    Copyright (C) 1994,1995,1996,1997,2002,2005
00003        Free Software Foundation, Inc.
00004    This file is part of the GNU C Library.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <hurd.h>
00022 #include <hurd/signal.h>
00023 #include "hurdfault.h"
00024 #include <errno.h>
00025 #include <string.h>
00026 #include <setjmp.h>
00027 #include <stdio.h>
00028 #include <thread_state.h>
00029 #include "faultexc_server.h"       /* mig-generated header for our exc server.  */
00030 #include <assert.h>
00031 
00032 jmp_buf _hurdsig_fault_env;
00033 struct hurd_signal_preemptor _hurdsig_fault_preemptor = {0};
00034 
00035 /* XXX temporary to deal with spelling fix */
00036 weak_alias (_hurdsig_fault_preemptor, _hurdsig_fault_preempter)
00037 
00038 static mach_port_t forward_sigexc;
00039 
00040 kern_return_t
00041 _hurdsig_fault_catch_exception_raise (mach_port_t port,
00042                                   thread_t thread,
00043                                   task_t task,
00044 #ifdef EXC_MASK_ALL         /* New interface flavor.  */
00045                                   exception_type_t exception,
00046                                   exception_data_t code,
00047                                   mach_msg_type_number_t codeCnt
00048 #else                       /* Vanilla Mach 3.0 interface.  */
00049                                   integer_t exception,
00050                                   integer_t code, integer_t subcode
00051 #endif
00052                                   )
00053 {
00054   int signo;
00055   struct hurd_signal_detail d;
00056 
00057   if (port != forward_sigexc ||
00058       thread != _hurd_msgport_thread || task != __mach_task_self ())
00059     return EPERM;           /* Strange bogosity.  */
00060 
00061   d.exc = exception;
00062 #ifdef EXC_MASK_ALL
00063   assert (codeCnt >= 2);
00064   d.exc_code = code[0];
00065   d.exc_subcode = code[1];
00066 #else
00067   d.exc_code = code;
00068   d.exc_subcode = subcode;
00069 #endif
00070 
00071   /* Call the machine-dependent function to translate the Mach exception
00072      codes into a signal number and subcode.  */
00073   _hurd_exception2signal (&d, &signo);
00074 
00075   return HURD_PREEMPT_SIGNAL_P (&_hurdsig_fault_preemptor, signo, d.code)
00076     ? 0 : EGREGIOUS;
00077 }
00078 
00079 #ifdef EXC_MASK_ALL
00080 /* XXX New interface flavor has additional RPCs that we could be using
00081    instead.  These RPCs roll a thread_get_state/thread_set_state into
00082    the message, so the signal thread ought to use these to save some calls.
00083  */
00084 kern_return_t
00085 _hurdsig_fault_catch_exception_raise_state
00086 (mach_port_t port,
00087  exception_type_t exception,
00088  exception_data_t code,
00089  mach_msg_type_number_t codeCnt,
00090  int *flavor,
00091  thread_state_t old_state,
00092  mach_msg_type_number_t old_stateCnt,
00093  thread_state_t new_state,
00094  mach_msg_type_number_t *new_stateCnt)
00095 {
00096   abort ();
00097   return KERN_FAILURE;
00098 }
00099 
00100 kern_return_t
00101 _hurdsig_fault_catch_exception_raise_state_identity
00102 (mach_port_t exception_port,
00103  thread_t thread,
00104  task_t task,
00105  exception_type_t exception,
00106  exception_data_t code,
00107  mach_msg_type_number_t codeCnt,
00108  int *flavor,
00109  thread_state_t old_state,
00110  mach_msg_type_number_t old_stateCnt,
00111  thread_state_t new_state,
00112  mach_msg_type_number_t *new_stateCnt)
00113 {
00114   abort ();
00115   return KERN_FAILURE;
00116 }
00117 #endif
00118 
00119 
00120 #ifdef NDR_CHAR_ASCII              /* OSF Mach flavors have different names.  */
00121 # define mig_reply_header_t mig_reply_error_t
00122 #endif
00123 
00124 static void
00125 faulted (void)
00126 {
00127   struct
00128     {
00129       mach_msg_header_t head;
00130       char buf[64];
00131     } request;
00132   mig_reply_header_t reply;
00133   extern int _hurdsig_fault_exc_server (mach_msg_header_t *,
00134                                    mach_msg_header_t *);
00135 
00136  /* Wait for the exception_raise message forwarded by the proc server.  */
00137 
00138  if (__mach_msg (&request.head, MACH_RCV_MSG, 0,
00139                 sizeof request, forward_sigexc,
00140                 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL)
00141       != MACH_MSG_SUCCESS)
00142     __libc_fatal ("msg receive failed on signal thread exc\n");
00143 
00144   /* Run the exc demuxer which should call the server function above.
00145      That function returns 0 if the exception was expected.  */
00146   _hurdsig_fault_exc_server (&request.head, &reply.Head);
00147   if (reply.Head.msgh_remote_port != MACH_PORT_NULL)
00148     __mach_msg (&reply.Head, MACH_SEND_MSG, reply.Head.msgh_size,
00149               0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
00150   if (reply.RetCode == MIG_BAD_ID)
00151     __mach_msg_destroy (&request.head);
00152 
00153   if (reply.RetCode)
00154     __libc_fatal ("BUG: unexpected fault in signal thread\n");
00155 
00156   _hurdsig_fault_preemptor.signals = 0;
00157   longjmp (_hurdsig_fault_env, 1);
00158 }
00159 
00160 static char faultstack[1024];
00161 
00162 /* Send exceptions for the signal thread to the proc server.
00163    It will forward the message on to our message port,
00164    and then restore the thread's state to code which
00165    does `longjmp (_hurd_sigthread_fault_env, 1)'.  */
00166 
00167 void
00168 _hurdsig_fault_init (void)
00169 {
00170   error_t err;
00171   struct machine_thread_state state;
00172   mach_port_t sigexc;
00173 
00174   /* Allocate a port to receive signal thread exceptions.
00175      We will move this receive right to the proc server.  */
00176   err = __mach_port_allocate (__mach_task_self (),
00177                            MACH_PORT_RIGHT_RECEIVE, &sigexc);
00178   assert_perror (err);
00179   err = __mach_port_allocate (__mach_task_self (),
00180                            MACH_PORT_RIGHT_RECEIVE, &forward_sigexc);
00181   assert_perror (err);
00182 
00183   /* Allocate a port to receive the exception msgs forwarded
00184      from the proc server.  */
00185   err = __mach_port_insert_right (__mach_task_self (), sigexc,
00186                               sigexc, MACH_MSG_TYPE_MAKE_SEND);
00187   assert_perror (err);
00188 
00189   /* Set the queue limit for this port to just one.  The proc server will
00190      notice if we ever get a second exception while one remains queued and
00191      unreceived, and decide we are hopelessly buggy.  */
00192 #ifdef MACH_PORT_RECEIVE_STATUS_COUNT
00193   {
00194     const mach_port_limits_t lim = { mpl_qlimit: 1 };
00195     assert (MACH_PORT_RECEIVE_STATUS_COUNT == sizeof lim / sizeof (natural_t));
00196     err = __mach_port_set_attributes (__mach_task_self (), forward_sigexc,
00197                                   MACH_PORT_RECEIVE_STATUS,
00198                                   (mach_port_info_t) &lim,
00199                                   MACH_PORT_RECEIVE_STATUS_COUNT);
00200   }
00201 #else
00202   err = __mach_port_set_qlimit (__mach_task_self (), forward_sigexc, 1);
00203 #endif
00204   assert_perror (err);
00205 
00206   /* This state will be restored when we fault.
00207      It runs the function above.  */
00208   memset (&state, 0, sizeof state);
00209   MACHINE_THREAD_STATE_SET_PC (&state, faulted);
00210   MACHINE_THREAD_STATE_SET_SP (&state, faultstack, sizeof faultstack);
00211 
00212   err = __USEPORT
00213     (PROC,
00214      __proc_handle_exceptions (port,
00215                             sigexc,
00216                             forward_sigexc, MACH_MSG_TYPE_MAKE_SEND,
00217                             MACHINE_THREAD_STATE_FLAVOR,
00218                             (natural_t *) &state,
00219                             MACHINE_THREAD_STATE_COUNT));
00220   assert_perror (err);
00221 
00222   /* Direct signal thread exceptions to the proc server.  */
00223 #ifdef THREAD_EXCEPTION_PORT
00224   err = __thread_set_special_port (_hurd_msgport_thread,
00225                                THREAD_EXCEPTION_PORT, sigexc);
00226 #elif defined (EXC_MASK_ALL)
00227   __thread_set_exception_ports (_hurd_msgport_thread,
00228                             EXC_MASK_ALL & ~(EXC_MASK_SYSCALL
00229                                            | EXC_MASK_MACH_SYSCALL
00230                                            | EXC_MASK_RPC_ALERT),
00231                             sigexc,
00232                             EXCEPTION_STATE_IDENTITY,
00233                             MACHINE_THREAD_STATE);
00234 #else
00235 # error thread_set_exception_ports?
00236 #endif
00237   __mach_port_deallocate (__mach_task_self (), sigexc);
00238   assert_perror (err);
00239 }