1 /* Translate Mach exception codes into signal numbers.  i386 version.
2    Copyright (C) 1991-2022 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 <mach/exception.h>
22 
23 /* Translate the Mach exception codes, as received in an `exception_raise' RPC,
24    into a signal number and signal subcode.  */
25 
26 static void
exception2signal(struct hurd_signal_detail * detail,int * signo,int posix)27 exception2signal (struct hurd_signal_detail *detail, int *signo, int posix)
28 {
29   detail->error = 0;
30 
31   switch (detail->exc)
32     {
33     default:
34       *signo = SIGIOT;
35       detail->code = detail->exc;
36       break;
37 
38     case EXC_BAD_ACCESS:
39       switch (detail->exc_code)
40         {
41 	case KERN_INVALID_ADDRESS:
42 	case KERN_MEMORY_FAILURE:
43 	  *signo = SIGSEGV;
44 	  detail->code = posix ? SEGV_MAPERR : detail->exc_subcode;
45 	  break;
46 
47 	case KERN_PROTECTION_FAILURE:
48 	case KERN_WRITE_PROTECTION_FAILURE:
49 	  *signo = SIGSEGV;
50 	  detail->code = posix ? SEGV_ACCERR : detail->exc_subcode;
51 	  break;
52 
53 	default:
54 	  *signo = SIGBUS;
55 	  detail->code = posix ? BUS_ADRERR : detail->exc_subcode;
56 	  break;
57 	}
58       detail->error = detail->exc_code;
59       break;
60 
61     case EXC_BAD_INSTRUCTION:
62       *signo = SIGILL;
63       switch (detail->exc_code)
64         {
65 	case EXC_I386_INVOP:
66 	  detail->code = posix ? ILL_ILLOPC : ILL_INVOPR_FAULT;
67 	  break;
68 
69 	case EXC_I386_STKFLT:
70 	  detail->code = posix ? ILL_BADSTK : ILL_STACK_FAULT;
71 	  break;
72 
73 	default:
74 	  detail->code = 0;
75 	  break;
76 	}
77       break;
78 
79     case EXC_ARITHMETIC:
80       *signo = SIGFPE;
81       switch (detail->exc_code)
82 	{
83 	case EXC_I386_DIV:	/* integer divide by zero */
84 	  detail->code = posix ? FPE_INTDIV : FPE_INTDIV_FAULT;
85 	  break;
86 
87 	case EXC_I386_INTO:	/* integer overflow */
88 	  detail->code = posix ? FPE_INTOVF : FPE_INTOVF_TRAP;
89 	  break;
90 
91 	  /* These aren't anywhere documented or used in Mach 3.0.  */
92 	case EXC_I386_NOEXT:
93 	case EXC_I386_EXTOVR:
94 	default:
95 	  detail->code = 0;
96 	  break;
97 
98 	case EXC_I386_EXTERR:
99 	  /* Subcode is the fp_status word saved by the hardware.
100 	     Give an error code corresponding to the first bit set.  */
101 	  if (detail->exc_subcode & FPS_IE)
102 	    {
103 	      /* NB: We used to send SIGILL here but we can't distinguish
104 		 POSIX vs. legacy with respect to what signal we send.  */
105 	      detail->code = posix ? FPE_FLTINV : 0 /*ILL_FPEOPR_FAULT*/;
106 	    }
107 	  else if (detail->exc_subcode & FPS_DE)
108 	    {
109 	      detail->code = posix ? FPE_FLTUND : FPE_FLTDNR_FAULT;
110 	    }
111 	  else if (detail->exc_subcode & FPS_ZE)
112 	    {
113 	      detail->code = posix ? FPE_FLTDIV : FPE_FLTDIV_FAULT;
114 	    }
115 	  else if (detail->exc_subcode & FPS_OE)
116 	    {
117 	      detail->code = posix ? FPE_FLTOVF : FPE_FLTOVF_FAULT;
118 	    }
119 	  else if (detail->exc_subcode & FPS_UE)
120 	    {
121 	      detail->code = posix ? FPE_FLTUND : FPE_FLTUND_FAULT;
122 	    }
123 	  else if (detail->exc_subcode & FPS_PE)
124 	    {
125 	      detail->code = posix ? FPE_FLTRES : FPE_FLTINX_FAULT;
126 	    }
127 	  else
128 	    {
129 	      detail->code = 0;
130 	    }
131 	  break;
132 
133 	  /* These two can only be arithmetic exceptions if we
134 	     are in V86 mode.  (See Mach 3.0 i386/trap.c.)  */
135 	case EXC_I386_EMERR:
136 	  detail->code = posix ? 0 : FPE_EMERR_FAULT;
137 	  break;
138 	case EXC_I386_BOUND:
139 	  detail->code = posix ? FPE_FLTSUB : FPE_EMBND_FAULT;
140 	  break;
141 	}
142       break;
143 
144     case EXC_EMULATION:
145       /* 3.0 doesn't give this one, why, I don't know.  */
146       *signo = SIGEMT;
147       detail->code = 0;
148       break;
149 
150     case EXC_SOFTWARE:
151       /* The only time we get this in Mach 3.0
152 	 is for an out of bounds trap.  */
153       if (detail->exc_code == EXC_I386_BOUND)
154 	{
155 	  *signo = SIGFPE;
156 	  detail->code = posix ? FPE_FLTSUB : FPE_SUBRNG_FAULT;
157 	}
158       else
159 	{
160 	  *signo = SIGEMT;
161 	  detail->code = 0;
162 	}
163       break;
164 
165     case EXC_BREAKPOINT:
166       *signo = SIGTRAP;
167       switch (detail->exc_code)
168         {
169 	case EXC_I386_SGL:
170 	  detail->code = posix ? TRAP_BRKPT : DBG_SINGLE_TRAP;
171 	  break;
172 
173 	case EXC_I386_BPT:
174 	  detail->code = posix ? TRAP_BRKPT : DBG_BRKPNT_FAULT;
175 	  break;
176 
177 	default:
178 	  detail->code = 0;
179 	  break;
180 	}
181       break;
182     }
183 }
libc_hidden_def(_hurd_exception2signal)184 libc_hidden_def (_hurd_exception2signal)
185 
186 void
187 _hurd_exception2signal (struct hurd_signal_detail *detail, int *signo)
188 {
189   exception2signal (detail, signo, 1);
190 }
191 
192 void
_hurd_exception2signal_legacy(struct hurd_signal_detail * detail,int * signo)193 _hurd_exception2signal_legacy (struct hurd_signal_detail *detail, int *signo)
194 {
195   exception2signal (detail, signo, 0);
196 }
197