(root)/
glibc-2.38/
hurd/
hurdfault.c
       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.
       4  
       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.
       9  
      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.
      14  
      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/>.  */
      18  
      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>
      29  
      30  jmp_buf _hurdsig_fault_env;
      31  struct hurd_signal_preemptor _hurdsig_fault_preemptor = {0};
      32  
      33  /* XXX temporary to deal with spelling fix */
      34  weak_alias (_hurdsig_fault_preemptor, _hurdsig_fault_preempter)
      35  
      36  static mach_port_t forward_sigexc;
      37  
      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
      50  				      )
      51  {
      52    int signo;
      53    struct hurd_signal_detail d;
      54  
      55    if (port != forward_sigexc
      56        || thread != _hurd_msgport_thread || task != __mach_task_self ())
      57      return EPERM;		/* Strange bogosity.  */
      58  
      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
      68  
      69    /* Call the machine-dependent function to translate the Mach exception
      70       codes into a signal number and subcode.  */
      71    _hurd_exception2signal (&d, &signo);
      72  
      73    return HURD_PREEMPT_SIGNAL_P (&_hurdsig_fault_preemptor, signo, d.exc_subcode)
      74      ? 0 : EGREGIOUS;
      75  }
      76  
      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.
      81   */
      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)
      93  {
      94    abort ();
      95    return KERN_FAILURE;
      96  }
      97  
      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)
     111  {
     112    abort ();
     113    return KERN_FAILURE;
     114  }
     115  #endif
     116  
     117  
     118  #ifdef NDR_CHAR_ASCII		/* OSF Mach flavors have different names.  */
     119  # define mig_reply_header_t	mig_reply_error_t
     120  #endif
     121  
     122  static void
     123  faulted (void)
     124  {
     125    struct
     126      {
     127        mach_msg_header_t head;
     128        char buf[64];
     129      } request;
     130    mig_reply_header_t reply;
     131    extern int _hurdsig_fault_exc_server (mach_msg_header_t *,
     132  					mach_msg_header_t *);
     133  
     134   /* Wait for the exception_raise message forwarded by the proc server.  */
     135  
     136   if (__mach_msg (&request.head, MACH_RCV_MSG, 0,
     137  		  sizeof request, forward_sigexc,
     138  		  MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL)
     139        != MACH_MSG_SUCCESS)
     140      __libc_fatal ("msg receive failed on signal thread exc\n");
     141  
     142    /* Run the exc demuxer which should call the server function above.
     143       That function returns 0 if the exception was expected.  */
     144    _hurdsig_fault_exc_server (&request.head, &reply.Head);
     145    if (reply.Head.msgh_remote_port != MACH_PORT_NULL)
     146      __mach_msg (&reply.Head, MACH_SEND_MSG, reply.Head.msgh_size,
     147  		0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
     148    if (reply.RetCode == MIG_BAD_ID)
     149      __mach_msg_destroy (&request.head);
     150  
     151    if (reply.RetCode)
     152      __libc_fatal ("BUG: unexpected fault in signal thread\n");
     153  
     154    _hurdsig_fault_preemptor.signals = 0;
     155    longjmp (_hurdsig_fault_env, 1);
     156  }
     157  
     158  static char faultstack[1024];
     159  
     160  /* Send exceptions for the signal thread to the proc server.
     161     It will forward the message on to our message port,
     162     and then restore the thread's state to code which
     163     does `longjmp (_hurd_sigthread_fault_env, 1)'.  */
     164  
     165  void
     166  _hurdsig_fault_init (void)
     167  {
     168    error_t err;
     169    struct machine_thread_state state;
     170    mach_port_t sigexc;
     171  
     172    /* Allocate a port to receive signal thread exceptions.
     173       We will move this receive right to the proc server.  */
     174    err = __mach_port_allocate (__mach_task_self (),
     175  			      MACH_PORT_RIGHT_RECEIVE, &sigexc);
     176    assert_perror (err);
     177    err = __mach_port_insert_right (__mach_task_self (), sigexc,
     178  				  sigexc, MACH_MSG_TYPE_MAKE_SEND);
     179    assert_perror (err);
     180  
     181    /* Allocate a port to receive the exception msgs forwarded
     182       from the proc server.  */
     183    err = __mach_port_allocate (__mach_task_self (),
     184  			      MACH_PORT_RIGHT_RECEIVE, &forward_sigexc);
     185    assert_perror (err);
     186  
     187    /* Set the queue limit for this port to just one.  The proc server will
     188       notice if we ever get a second exception while one remains queued and
     189       unreceived, and decide we are hopelessly buggy.  */
     190  #ifdef MACH_PORT_RECEIVE_STATUS_COUNT
     191    {
     192      const mach_port_limits_t lim = { mpl_qlimit: 1 };
     193      assert (MACH_PORT_RECEIVE_STATUS_COUNT == sizeof lim / sizeof (natural_t));
     194      err = __mach_port_set_attributes (__mach_task_self (), forward_sigexc,
     195  				      MACH_PORT_RECEIVE_STATUS,
     196  				      (mach_port_info_t) &lim,
     197  				      MACH_PORT_RECEIVE_STATUS_COUNT);
     198    }
     199  #else
     200    err = __mach_port_set_qlimit (__mach_task_self (), forward_sigexc, 1);
     201  #endif
     202    assert_perror (err);
     203  
     204    /* This state will be restored when we fault.
     205       It runs the function above.  */
     206    memset (&state, 0, sizeof state);
     207    MACHINE_THREAD_STATE_FIX_NEW (&state);
     208    MACHINE_THREAD_STATE_SETUP_CALL (&state, faultstack,
     209  				   sizeof faultstack, faulted);
     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  }