.
[kopensolaris-gnu/glibc.git] / hurd / hurdfault.c
1 /* Handle faults in the signal thread.
2    Copyright (C) 1994, 1995, 1996, 1997 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 Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    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    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
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                                       int exception,
44                                       int code,
45                                       int subcode)
46 {
47   int signo;
48   struct hurd_signal_detail d;
49
50   if (port != forward_sigexc ||
51       thread != _hurd_msgport_thread || task != __mach_task_self ())
52     return EPERM;               /* Strange bogosity.  */
53
54   d.exc = exception;
55   d.exc_code = code;
56   d.exc_subcode = subcode;
57
58   /* Call the machine-dependent function to translate the Mach exception
59      codes into a signal number and subcode.  */
60   _hurd_exception2signal (&d, &signo);
61
62   return HURD_PREEMPT_SIGNAL_P (&_hurdsig_fault_preemptor, signo, d.code)
63     ? 0 : EGREGIOUS;
64 }
65
66 static void
67 faulted (void)
68 {
69   struct
70     {
71       mach_msg_header_t head;
72       char buf[64];
73     } request;
74   struct
75     {
76       mach_msg_header_t head;
77       mach_msg_type_t type;
78       int result;
79     } reply;
80   extern int _hurdsig_fault_exc_server (mach_msg_header_t *,
81                                         mach_msg_header_t *);
82
83  /* Wait for the exception_raise message forwarded by the proc server.  */
84
85  if (__mach_msg (&request.head, MACH_RCV_MSG, 0,
86                   sizeof request, forward_sigexc,
87                   MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL)
88       != MACH_MSG_SUCCESS)
89     __libc_fatal ("msg receive failed on signal thread exc\n");
90
91   /* Run the exc demuxer which should call the server function above.
92      That function returns 0 if the exception was expected.  */
93   _hurdsig_fault_exc_server (&request.head, &reply.head);
94   if (reply.head.msgh_remote_port != MACH_PORT_NULL)
95     __mach_msg (&reply.head, MACH_SEND_MSG, reply.head.msgh_size,
96                 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
97   if (reply.result == MIG_BAD_ID)
98     __mach_msg_destroy (&request.head);
99
100   if (reply.result)
101     __libc_fatal ("BUG: unexpected fault in signal thread\n");
102
103   _hurdsig_fault_preemptor.signals = 0;
104   longjmp (_hurdsig_fault_env, 1);
105 }
106
107 static char faultstack[1024];
108
109 /* Send exceptions for the signal thread to the proc server.
110    It will forward the message on to our message port,
111    and then restore the thread's state to code which
112    does `longjmp (_hurd_sigthread_fault_env, 1)'.  */
113
114 void
115 _hurdsig_fault_init (void)
116 {
117   error_t err;
118   struct machine_thread_state state;
119   mach_port_t sigexc;
120
121   /* Allocate a port to receive signal thread exceptions.
122      We will move this receive right to the proc server.  */
123   err = __mach_port_allocate (__mach_task_self (),
124                               MACH_PORT_RIGHT_RECEIVE, &sigexc);
125   assert_perror (err);
126   err = __mach_port_allocate (__mach_task_self (),
127                               MACH_PORT_RIGHT_RECEIVE, &forward_sigexc);
128   assert_perror (err);
129
130   /* Allocate a port to receive the exception msgs forwarded
131      from the proc server.  */
132   err = __mach_port_insert_right (__mach_task_self (), sigexc,
133                                   sigexc, MACH_MSG_TYPE_MAKE_SEND);
134   assert_perror (err);
135
136   /* Set the queue limit for this port to just one.  The proc server will
137      notice if we ever get a second exception while one remains queued and
138      unreceived, and decide we are hopelessly buggy.  */
139   err = __mach_port_set_qlimit (__mach_task_self (), forward_sigexc, 1);
140   assert_perror (err);
141
142   /* This state will be restored when we fault.
143      It runs the function above.  */
144   memset (&state, 0, sizeof state);
145   MACHINE_THREAD_STATE_SET_PC (&state, faulted);
146   MACHINE_THREAD_STATE_SET_SP (&state, faultstack, sizeof faultstack);
147
148   err = __USEPORT
149     (PROC,
150      __proc_handle_exceptions (port,
151                                sigexc,
152                                forward_sigexc, MACH_MSG_TYPE_MAKE_SEND,
153                                MACHINE_THREAD_STATE_FLAVOR,
154                                (natural_t *) &state,
155                                MACHINE_THREAD_STATE_COUNT));
156   assert_perror (err);
157
158   /* Direct signal thread exceptions to the proc server.  */
159   err = __thread_set_special_port (_hurd_msgport_thread,
160                                    THREAD_EXCEPTION_PORT, sigexc);
161   __mach_port_deallocate (__mach_task_self (), sigexc);
162   assert_perror (err);
163 }