Blame hurd/hurdfault.c

Packit 6c4009
/* Handle faults in the signal thread.
Packit 6c4009
   Copyright (C) 1994-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <hurd.h>
Packit 6c4009
#include <hurd/signal.h>
Packit 6c4009
#include "hurdfault.h"
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <setjmp.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <thread_state.h>
Packit 6c4009
#include "faultexc_server.h"	/* mig-generated header for our exc server.  */
Packit 6c4009
#include <assert.h>
Packit 6c4009
Packit 6c4009
jmp_buf _hurdsig_fault_env;
Packit 6c4009
struct hurd_signal_preemptor _hurdsig_fault_preemptor = {0};
Packit 6c4009
Packit 6c4009
/* XXX temporary to deal with spelling fix */
Packit 6c4009
weak_alias (_hurdsig_fault_preemptor, _hurdsig_fault_preempter)
Packit 6c4009
Packit 6c4009
static mach_port_t forward_sigexc;
Packit 6c4009
Packit 6c4009
kern_return_t
Packit 6c4009
_hurdsig_fault_catch_exception_raise (mach_port_t port,
Packit 6c4009
				      thread_t thread,
Packit 6c4009
				      task_t task,
Packit 6c4009
#ifdef EXC_MASK_ALL		/* New interface flavor.  */
Packit 6c4009
				      exception_type_t exception,
Packit 6c4009
				      exception_data_t code,
Packit 6c4009
				      mach_msg_type_number_t codeCnt
Packit 6c4009
#else				/* Vanilla Mach 3.0 interface.  */
Packit 6c4009
				      integer_t exception,
Packit 6c4009
				      integer_t code, integer_t subcode
Packit 6c4009
#endif
Packit 6c4009
				      )
Packit 6c4009
{
Packit 6c4009
  int signo;
Packit 6c4009
  struct hurd_signal_detail d;
Packit 6c4009
Packit 6c4009
  if (port != forward_sigexc ||
Packit 6c4009
      thread != _hurd_msgport_thread || task != __mach_task_self ())
Packit 6c4009
    return EPERM;		/* Strange bogosity.  */
Packit 6c4009
Packit 6c4009
  d.exc = exception;
Packit 6c4009
#ifdef EXC_MASK_ALL
Packit 6c4009
  assert (codeCnt >= 2);
Packit 6c4009
  d.exc_code = code[0];
Packit 6c4009
  d.exc_subcode = code[1];
Packit 6c4009
#else
Packit 6c4009
  d.exc_code = code;
Packit 6c4009
  d.exc_subcode = subcode;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  /* Call the machine-dependent function to translate the Mach exception
Packit 6c4009
     codes into a signal number and subcode.  */
Packit 6c4009
  _hurd_exception2signal (&d, &signo);
Packit 6c4009
Packit 6c4009
  return HURD_PREEMPT_SIGNAL_P (&_hurdsig_fault_preemptor, signo, d.code)
Packit 6c4009
    ? 0 : EGREGIOUS;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#ifdef EXC_MASK_ALL
Packit 6c4009
/* XXX New interface flavor has additional RPCs that we could be using
Packit 6c4009
   instead.  These RPCs roll a thread_get_state/thread_set_state into
Packit 6c4009
   the message, so the signal thread ought to use these to save some calls.
Packit 6c4009
 */
Packit 6c4009
kern_return_t
Packit 6c4009
_hurdsig_fault_catch_exception_raise_state
Packit 6c4009
(mach_port_t port,
Packit 6c4009
 exception_type_t exception,
Packit 6c4009
 exception_data_t code,
Packit 6c4009
 mach_msg_type_number_t codeCnt,
Packit 6c4009
 int *flavor,
Packit 6c4009
 thread_state_t old_state,
Packit 6c4009
 mach_msg_type_number_t old_stateCnt,
Packit 6c4009
 thread_state_t new_state,
Packit 6c4009
 mach_msg_type_number_t *new_stateCnt)
Packit 6c4009
{
Packit 6c4009
  abort ();
Packit 6c4009
  return KERN_FAILURE;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
kern_return_t
Packit 6c4009
_hurdsig_fault_catch_exception_raise_state_identity
Packit 6c4009
(mach_port_t exception_port,
Packit 6c4009
 thread_t thread,
Packit 6c4009
 task_t task,
Packit 6c4009
 exception_type_t exception,
Packit 6c4009
 exception_data_t code,
Packit 6c4009
 mach_msg_type_number_t codeCnt,
Packit 6c4009
 int *flavor,
Packit 6c4009
 thread_state_t old_state,
Packit 6c4009
 mach_msg_type_number_t old_stateCnt,
Packit 6c4009
 thread_state_t new_state,
Packit 6c4009
 mach_msg_type_number_t *new_stateCnt)
Packit 6c4009
{
Packit 6c4009
  abort ();
Packit 6c4009
  return KERN_FAILURE;
Packit 6c4009
}
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
#ifdef NDR_CHAR_ASCII		/* OSF Mach flavors have different names.  */
Packit 6c4009
# define mig_reply_header_t	mig_reply_error_t
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
faulted (void)
Packit 6c4009
{
Packit 6c4009
  struct
Packit 6c4009
    {
Packit 6c4009
      mach_msg_header_t head;
Packit 6c4009
      char buf[64];
Packit 6c4009
    } request;
Packit 6c4009
  mig_reply_header_t reply;
Packit 6c4009
  extern int _hurdsig_fault_exc_server (mach_msg_header_t *,
Packit 6c4009
					mach_msg_header_t *);
Packit 6c4009
Packit 6c4009
 /* Wait for the exception_raise message forwarded by the proc server.  */
Packit 6c4009
Packit 6c4009
 if (__mach_msg (&request.head, MACH_RCV_MSG, 0,
Packit 6c4009
		  sizeof request, forward_sigexc,
Packit 6c4009
		  MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL)
Packit 6c4009
      != MACH_MSG_SUCCESS)
Packit 6c4009
    __libc_fatal ("msg receive failed on signal thread exc\n");
Packit 6c4009
Packit 6c4009
  /* Run the exc demuxer which should call the server function above.
Packit 6c4009
     That function returns 0 if the exception was expected.  */
Packit 6c4009
  _hurdsig_fault_exc_server (&request.head, &reply.Head);
Packit 6c4009
  if (reply.Head.msgh_remote_port != MACH_PORT_NULL)
Packit 6c4009
    __mach_msg (&reply.Head, MACH_SEND_MSG, reply.Head.msgh_size,
Packit 6c4009
		0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
Packit 6c4009
  if (reply.RetCode == MIG_BAD_ID)
Packit 6c4009
    __mach_msg_destroy (&request.head);
Packit 6c4009
Packit 6c4009
  if (reply.RetCode)
Packit 6c4009
    __libc_fatal ("BUG: unexpected fault in signal thread\n");
Packit 6c4009
Packit 6c4009
  _hurdsig_fault_preemptor.signals = 0;
Packit 6c4009
  longjmp (_hurdsig_fault_env, 1);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static char faultstack[1024];
Packit 6c4009
Packit 6c4009
/* Send exceptions for the signal thread to the proc server.
Packit 6c4009
   It will forward the message on to our message port,
Packit 6c4009
   and then restore the thread's state to code which
Packit 6c4009
   does `longjmp (_hurd_sigthread_fault_env, 1)'.  */
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
_hurdsig_fault_init (void)
Packit 6c4009
{
Packit 6c4009
  error_t err;
Packit 6c4009
  struct machine_thread_state state;
Packit 6c4009
  mach_port_t sigexc;
Packit 6c4009
Packit 6c4009
  /* Allocate a port to receive signal thread exceptions.
Packit 6c4009
     We will move this receive right to the proc server.  */
Packit 6c4009
  err = __mach_port_allocate (__mach_task_self (),
Packit 6c4009
			      MACH_PORT_RIGHT_RECEIVE, &sigexc);
Packit 6c4009
  assert_perror (err);
Packit 6c4009
  err = __mach_port_allocate (__mach_task_self (),
Packit 6c4009
			      MACH_PORT_RIGHT_RECEIVE, &forward_sigexc);
Packit 6c4009
  assert_perror (err);
Packit 6c4009
Packit 6c4009
  /* Allocate a port to receive the exception msgs forwarded
Packit 6c4009
     from the proc server.  */
Packit 6c4009
  err = __mach_port_insert_right (__mach_task_self (), sigexc,
Packit 6c4009
				  sigexc, MACH_MSG_TYPE_MAKE_SEND);
Packit 6c4009
  assert_perror (err);
Packit 6c4009
Packit 6c4009
  /* Set the queue limit for this port to just one.  The proc server will
Packit 6c4009
     notice if we ever get a second exception while one remains queued and
Packit 6c4009
     unreceived, and decide we are hopelessly buggy.  */
Packit 6c4009
#ifdef MACH_PORT_RECEIVE_STATUS_COUNT
Packit 6c4009
  {
Packit 6c4009
    const mach_port_limits_t lim = { mpl_qlimit: 1 };
Packit 6c4009
    assert (MACH_PORT_RECEIVE_STATUS_COUNT == sizeof lim / sizeof (natural_t));
Packit 6c4009
    err = __mach_port_set_attributes (__mach_task_self (), forward_sigexc,
Packit 6c4009
				      MACH_PORT_RECEIVE_STATUS,
Packit 6c4009
				      (mach_port_info_t) &lim,
Packit 6c4009
				      MACH_PORT_RECEIVE_STATUS_COUNT);
Packit 6c4009
  }
Packit 6c4009
#else
Packit 6c4009
  err = __mach_port_set_qlimit (__mach_task_self (), forward_sigexc, 1);
Packit 6c4009
#endif
Packit 6c4009
  assert_perror (err);
Packit 6c4009
Packit 6c4009
  /* This state will be restored when we fault.
Packit 6c4009
     It runs the function above.  */
Packit 6c4009
  memset (&state, 0, sizeof state);
Packit 6c4009
  MACHINE_THREAD_STATE_FIX_NEW (&state);
Packit 6c4009
  MACHINE_THREAD_STATE_SET_PC (&state, faulted);
Packit 6c4009
  MACHINE_THREAD_STATE_SET_SP (&state, faultstack, sizeof faultstack);
Packit 6c4009
Packit 6c4009
  err = __USEPORT
Packit 6c4009
    (PROC,
Packit 6c4009
     __proc_handle_exceptions (port,
Packit 6c4009
			       sigexc,
Packit 6c4009
			       forward_sigexc, MACH_MSG_TYPE_MAKE_SEND,
Packit 6c4009
			       MACHINE_THREAD_STATE_FLAVOR,
Packit 6c4009
			       (natural_t *) &state,
Packit 6c4009
			       MACHINE_THREAD_STATE_COUNT));
Packit 6c4009
  assert_perror (err);
Packit 6c4009
Packit 6c4009
  /* Direct signal thread exceptions to the proc server.  */
Packit 6c4009
#ifdef THREAD_EXCEPTION_PORT
Packit 6c4009
  err = __thread_set_special_port (_hurd_msgport_thread,
Packit 6c4009
				   THREAD_EXCEPTION_PORT, sigexc);
Packit 6c4009
#elif defined (EXC_MASK_ALL)
Packit 6c4009
  __thread_set_exception_ports (_hurd_msgport_thread,
Packit 6c4009
				EXC_MASK_ALL & ~(EXC_MASK_SYSCALL
Packit 6c4009
						 | EXC_MASK_MACH_SYSCALL
Packit 6c4009
						 | EXC_MASK_RPC_ALERT),
Packit 6c4009
				sigexc,
Packit 6c4009
				EXCEPTION_STATE_IDENTITY,
Packit 6c4009
				MACHINE_THREAD_STATE);
Packit 6c4009
#else
Packit 6c4009
# error thread_set_exception_ports?
Packit 6c4009
#endif
Packit 6c4009
  __mach_port_deallocate (__mach_task_self (), sigexc);
Packit 6c4009
  assert_perror (err);
Packit 6c4009
}