ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.43
Committed: 2004-01-20T23:49:32Z (20 years, 5 months ago) by nigel
Branch: MAIN
Changes since 1.42: +2 -0 lines
Log Message:
Added missing switch value to eliminate a warning

File Contents

# User Rev Content
1 gbeauche 1.1 /*
2     * sigsegv.cpp - SIGSEGV signals support
3     *
4     * Derived from Bruno Haible's work on his SIGSEGV library for clisp
5     * <http://clisp.sourceforge.net/>
6     *
7 gbeauche 1.27 * MacOS X support derived from the post by Timothy J. Wood to the
8     * omnigroup macosx-dev list:
9     * Mach Exception Handlers 101 (Was Re: ptrace, gdb)
10     * tjw@omnigroup.com Sun, 4 Jun 2000
11     * www.omnigroup.com/mailman/archive/macosx-dev/2000-June/002030.html
12     *
13 cebix 1.41 * Basilisk II (C) 1997-2004 Christian Bauer
14 gbeauche 1.1 *
15     * This program is free software; you can redistribute it and/or modify
16     * it under the terms of the GNU General Public License as published by
17     * the Free Software Foundation; either version 2 of the License, or
18     * (at your option) any later version.
19     *
20     * This program is distributed in the hope that it will be useful,
21     * but WITHOUT ANY WARRANTY; without even the implied warranty of
22     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23     * GNU General Public License for more details.
24     *
25     * You should have received a copy of the GNU General Public License
26     * along with this program; if not, write to the Free Software
27     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28     */
29    
30     #ifdef HAVE_UNISTD_H
31     #include <unistd.h>
32     #endif
33    
34     #ifdef HAVE_CONFIG_H
35     #include "config.h"
36     #endif
37    
38 gbeauche 1.22 #include <list>
39 gbeauche 1.39 #include <stdio.h>
40 gbeauche 1.1 #include <signal.h>
41     #include "sigsegv.h"
42    
43 gbeauche 1.22 #ifndef NO_STD_NAMESPACE
44     using std::list;
45     #endif
46    
47 gbeauche 1.1 // Return value type of a signal handler (standard type if not defined)
48     #ifndef RETSIGTYPE
49     #define RETSIGTYPE void
50     #endif
51    
52     // Type of the system signal handler
53     typedef RETSIGTYPE (*signal_handler)(int);
54    
55     // User's SIGSEGV handler
56 gbeauche 1.12 static sigsegv_fault_handler_t sigsegv_fault_handler = 0;
57 gbeauche 1.1
58 gbeauche 1.10 // Function called to dump state if we can't handle the fault
59 gbeauche 1.12 static sigsegv_state_dumper_t sigsegv_state_dumper = 0;
60 gbeauche 1.10
61 gbeauche 1.1 // Actual SIGSEGV handler installer
62     static bool sigsegv_do_install_handler(int sig);
63    
64    
65     /*
66 gbeauche 1.14 * Instruction decoding aids
67     */
68    
69     // Transfer size
70     enum transfer_size_t {
71     SIZE_UNKNOWN,
72     SIZE_BYTE,
73 gbeauche 1.34 SIZE_WORD, // 2 bytes
74     SIZE_LONG, // 4 bytes
75     SIZE_QUAD, // 8 bytes
76 gbeauche 1.14 };
77    
78 gbeauche 1.23 // Transfer type
79     typedef sigsegv_transfer_type_t transfer_type_t;
80    
81 gbeauche 1.14 #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__))
82     // Addressing mode
83     enum addressing_mode_t {
84     MODE_UNKNOWN,
85     MODE_NORM,
86     MODE_U,
87     MODE_X,
88     MODE_UX
89     };
90    
91     // Decoded instruction
92     struct instruction_t {
93     transfer_type_t transfer_type;
94     transfer_size_t transfer_size;
95     addressing_mode_t addr_mode;
96     unsigned int addr;
97     char ra, rd;
98     };
99    
100     static void powerpc_decode_instruction(instruction_t *instruction, unsigned int nip, unsigned int * gpr)
101     {
102     // Get opcode and divide into fields
103     unsigned int opcode = *((unsigned int *)nip);
104     unsigned int primop = opcode >> 26;
105     unsigned int exop = (opcode >> 1) & 0x3ff;
106     unsigned int ra = (opcode >> 16) & 0x1f;
107     unsigned int rb = (opcode >> 11) & 0x1f;
108     unsigned int rd = (opcode >> 21) & 0x1f;
109     signed int imm = (signed short)(opcode & 0xffff);
110    
111     // Analyze opcode
112 gbeauche 1.22 transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
113 gbeauche 1.14 transfer_size_t transfer_size = SIZE_UNKNOWN;
114     addressing_mode_t addr_mode = MODE_UNKNOWN;
115     switch (primop) {
116     case 31:
117     switch (exop) {
118     case 23: // lwzx
119 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
120 gbeauche 1.14 case 55: // lwzux
121 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
122 gbeauche 1.14 case 87: // lbzx
123 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
124 gbeauche 1.14 case 119: // lbzux
125 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
126 gbeauche 1.14 case 151: // stwx
127 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
128 gbeauche 1.14 case 183: // stwux
129 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
130 gbeauche 1.14 case 215: // stbx
131 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
132 gbeauche 1.14 case 247: // stbux
133 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
134 gbeauche 1.14 case 279: // lhzx
135 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
136 gbeauche 1.14 case 311: // lhzux
137 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
138 gbeauche 1.14 case 343: // lhax
139 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
140 gbeauche 1.14 case 375: // lhaux
141 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
142 gbeauche 1.14 case 407: // sthx
143 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
144 gbeauche 1.14 case 439: // sthux
145 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
146 gbeauche 1.14 }
147     break;
148    
149     case 32: // lwz
150 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
151 gbeauche 1.14 case 33: // lwzu
152 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
153 gbeauche 1.14 case 34: // lbz
154 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
155 gbeauche 1.14 case 35: // lbzu
156 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
157 gbeauche 1.14 case 36: // stw
158 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
159 gbeauche 1.14 case 37: // stwu
160 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
161 gbeauche 1.14 case 38: // stb
162 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
163 gbeauche 1.14 case 39: // stbu
164 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
165 gbeauche 1.14 case 40: // lhz
166 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
167 gbeauche 1.14 case 41: // lhzu
168 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
169 gbeauche 1.14 case 42: // lha
170 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
171 gbeauche 1.14 case 43: // lhau
172 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
173 gbeauche 1.14 case 44: // sth
174 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
175 gbeauche 1.14 case 45: // sthu
176 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
177 gbeauche 1.14 }
178    
179     // Calculate effective address
180     unsigned int addr = 0;
181     switch (addr_mode) {
182     case MODE_X:
183     case MODE_UX:
184     if (ra == 0)
185     addr = gpr[rb];
186     else
187     addr = gpr[ra] + gpr[rb];
188     break;
189     case MODE_NORM:
190     case MODE_U:
191     if (ra == 0)
192     addr = (signed int)(signed short)imm;
193     else
194     addr = gpr[ra] + (signed int)(signed short)imm;
195     break;
196     default:
197     break;
198     }
199    
200     // Commit decoded instruction
201     instruction->addr = addr;
202     instruction->addr_mode = addr_mode;
203     instruction->transfer_type = transfer_type;
204     instruction->transfer_size = transfer_size;
205     instruction->ra = ra;
206     instruction->rd = rd;
207     }
208     #endif
209    
210    
211     /*
212 gbeauche 1.1 * OS-dependant SIGSEGV signals support section
213     */
214    
215     #if HAVE_SIGINFO_T
216     // Generic extended signal handler
217 cebix 1.8 #if defined(__NetBSD__) || defined(__FreeBSD__)
218     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
219     #else
220 gbeauche 1.1 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
221 cebix 1.8 #endif
222 gbeauche 1.5 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, siginfo_t *sip, void *scp
223 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 siginfo_t *sip, void *scp
224     #define SIGSEGV_FAULT_HANDLER_ARGS sip, scp
225 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS sip->si_addr
226 gbeauche 1.37 #if (defined(sgi) || defined(__sgi))
227     #include <ucontext.h>
228     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
229     #define SIGSEGV_FAULT_INSTRUCTION (unsigned long)SIGSEGV_CONTEXT_REGS[CTX_EPC]
230 gbeauche 1.38 #if (defined(mips) || defined(__mips))
231     #define SIGSEGV_REGISTER_FILE SIGSEGV_CONTEXT_REGS
232     #define SIGSEGV_SKIP_INSTRUCTION mips_skip_instruction
233     #endif
234 gbeauche 1.37 #endif
235 gbeauche 1.32 #if defined(__sun__)
236     #if (defined(sparc) || defined(__sparc__))
237 gbeauche 1.40 #include <sys/stack.h>
238     #include <sys/regset.h>
239 gbeauche 1.32 #include <sys/ucontext.h>
240     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
241     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[REG_PC]
242 gbeauche 1.40 #define SIGSEGV_SPARC_GWINDOWS (((ucontext_t *)scp)->uc_mcontext.gwins)
243     #define SIGSEGV_SPARC_RWINDOW (struct rwindow *)((char *)SIGSEGV_CONTEXT_REGS[REG_SP] + STACK_BIAS)
244     #define SIGSEGV_REGISTER_FILE ((unsigned long *)SIGSEGV_CONTEXT_REGS), SIGSEGV_SPARC_GWINDOWS, SIGSEGV_SPARC_RWINDOW
245     #define SIGSEGV_SKIP_INSTRUCTION sparc_skip_instruction
246 gbeauche 1.32 #endif
247     #endif
248 gbeauche 1.33 #if defined(__FreeBSD__)
249 gbeauche 1.17 #if (defined(i386) || defined(__i386__))
250     #define SIGSEGV_FAULT_INSTRUCTION (((struct sigcontext *)scp)->sc_eip)
251 gbeauche 1.34 #define SIGSEGV_REGISTER_FILE ((unsigned long *)&(((struct sigcontext *)scp)->sc_edi)) /* EDI is the first GPR (even below EIP) in sigcontext */
252 gbeauche 1.17 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
253 gbeauche 1.19 #endif
254 gbeauche 1.17 #endif
255 gbeauche 1.5 #if defined(__linux__)
256 gbeauche 1.6 #if (defined(i386) || defined(__i386__))
257     #include <sys/ucontext.h>
258 gbeauche 1.14 #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
259     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[14] /* should use REG_EIP instead */
260 gbeauche 1.34 #define SIGSEGV_REGISTER_FILE (unsigned long *)SIGSEGV_CONTEXT_REGS
261 gbeauche 1.10 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
262 gbeauche 1.6 #endif
263 gbeauche 1.20 #if (defined(x86_64) || defined(__x86_64__))
264     #include <sys/ucontext.h>
265     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
266     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[16] /* should use REG_RIP instead */
267     #define SIGSEGV_REGISTER_FILE (unsigned long *)SIGSEGV_CONTEXT_REGS
268 gbeauche 1.34 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
269 gbeauche 1.20 #endif
270 gbeauche 1.5 #if (defined(ia64) || defined(__ia64__))
271     #define SIGSEGV_FAULT_INSTRUCTION (((struct sigcontext *)scp)->sc_ip & ~0x3ULL) /* slot number is in bits 0 and 1 */
272     #endif
273 gbeauche 1.9 #if (defined(powerpc) || defined(__powerpc__))
274     #include <sys/ucontext.h>
275 gbeauche 1.14 #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.regs)
276     #define SIGSEGV_FAULT_INSTRUCTION (SIGSEGV_CONTEXT_REGS->nip)
277     #define SIGSEGV_REGISTER_FILE (unsigned int *)&SIGSEGV_CONTEXT_REGS->nip, (unsigned int *)(SIGSEGV_CONTEXT_REGS->gpr)
278 gbeauche 1.13 #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
279 gbeauche 1.9 #endif
280 gbeauche 1.39 #if (defined(hppa) || defined(__hppa__))
281     #undef SIGSEGV_FAULT_ADDRESS
282     #define SIGSEGV_FAULT_ADDRESS sip->si_ptr
283     #endif
284 gbeauche 1.42 #if (defined(arm) || defined(__arm__))
285     #include <asm/ucontext.h> /* use kernel structure, glibc may not be in sync */
286     #define SIGSEGV_CONTEXT_REGS (((struct ucontext *)scp)->uc_mcontext)
287     #define SIGSEGV_FAULT_INSTRUCTION (SIGSEGV_CONTEXT_REGS.arm_pc)
288     #endif
289 gbeauche 1.5 #endif
290 gbeauche 1.1 #endif
291    
292     #if HAVE_SIGCONTEXT_SUBTERFUGE
293     // Linux kernels prior to 2.4 ?
294     #if defined(__linux__)
295     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
296     #if (defined(i386) || defined(__i386__))
297     #include <asm/sigcontext.h>
298     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext scs
299 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 struct sigcontext *scp
300     #define SIGSEGV_FAULT_HANDLER_ARGS &scs
301     #define SIGSEGV_FAULT_ADDRESS scp->cr2
302     #define SIGSEGV_FAULT_INSTRUCTION scp->eip
303 gbeauche 1.34 #define SIGSEGV_REGISTER_FILE (unsigned long *)scp
304 gbeauche 1.10 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
305 gbeauche 1.1 #endif
306     #if (defined(sparc) || defined(__sparc__))
307     #include <asm/sigcontext.h>
308 gbeauche 1.5 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp, char *addr
309 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp, addr
310 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS addr
311     #endif
312     #if (defined(powerpc) || defined(__powerpc__))
313     #include <asm/sigcontext.h>
314 gbeauche 1.4 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext *scp
315 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, scp
316 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS scp->regs->dar
317     #define SIGSEGV_FAULT_INSTRUCTION scp->regs->nip
318 gbeauche 1.14 #define SIGSEGV_REGISTER_FILE (unsigned int *)&scp->regs->nip, (unsigned int *)(scp->regs->gpr)
319 gbeauche 1.13 #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
320 gbeauche 1.1 #endif
321 gbeauche 1.4 #if (defined(alpha) || defined(__alpha__))
322     #include <asm/sigcontext.h>
323     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
324 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
325 gbeauche 1.4 #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
326     #define SIGSEGV_FAULT_INSTRUCTION scp->sc_pc
327 gbeauche 1.42 #endif
328     #if (defined(arm) || defined(__arm__))
329     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int r1, int r2, int r3, struct sigcontext sc
330     #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 struct sigcontext *scp
331     #define SIGSEGV_FAULT_HANDLER_ARGS &sc
332     #define SIGSEGV_FAULT_ADDRESS scp->fault_address
333     #define SIGSEGV_FAULT_INSTRUCTION scp->arm_pc
334 gbeauche 1.4 #endif
335 gbeauche 1.1 #endif
336    
337     // Irix 5 or 6 on MIPS
338 gbeauche 1.37 #if (defined(sgi) || defined(__sgi)) && (defined(SYSTYPE_SVR4) || defined(_SYSTYPE_SVR4))
339 gbeauche 1.11 #include <ucontext.h>
340 gbeauche 1.1 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
341 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
342 gbeauche 1.37 #define SIGSEGV_FAULT_ADDRESS (unsigned long)scp->sc_badvaddr
343     #define SIGSEGV_FAULT_INSTRUCTION (unsigned long)scp->sc_pc
344 gbeauche 1.1 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
345     #endif
346    
347 gbeauche 1.11 // HP-UX
348     #if (defined(hpux) || defined(__hpux__))
349     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
350 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
351 gbeauche 1.11 #define SIGSEGV_FAULT_ADDRESS scp->sc_sl.sl_ss.ss_narrow.ss_cr21
352     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV) FAULT_HANDLER(SIGBUS)
353     #endif
354    
355 gbeauche 1.1 // OSF/1 on Alpha
356     #if defined(__osf__)
357 gbeauche 1.11 #include <ucontext.h>
358 gbeauche 1.1 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
359 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
360 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS scp->sc_traparg_a0
361     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
362     #endif
363    
364     // AIX
365     #if defined(_AIX)
366     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
367 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
368 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS scp->sc_jmpbuf.jmp_context.o_vaddr
369     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
370     #endif
371    
372 gbeauche 1.33 // NetBSD
373     #if defined(__NetBSD__)
374 gbeauche 1.1 #if (defined(m68k) || defined(__m68k__))
375     #include <m68k/frame.h>
376     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
377 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
378 gbeauche 1.14 #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
379 gbeauche 1.1 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
380 gbeauche 1.14
381     // Use decoding scheme from BasiliskII/m68k native
382     static sigsegv_address_t get_fault_address(struct sigcontext *scp)
383     {
384     struct sigstate {
385     int ss_flags;
386     struct frame ss_frame;
387     };
388     struct sigstate *state = (struct sigstate *)scp->sc_ap;
389     char *fault_addr;
390     switch (state->ss_frame.f_format) {
391     case 7: /* 68040 access error */
392     /* "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown */
393     fault_addr = state->ss_frame.f_fmt7.f_fa;
394     break;
395     default:
396     fault_addr = (char *)code;
397     break;
398     }
399     return (sigsegv_address_t)fault_addr;
400     }
401 gbeauche 1.33 #endif
402     #if (defined(alpha) || defined(__alpha__))
403     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
404     #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
405     #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
406     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
407     #endif
408     #if (defined(i386) || defined(__i386__))
409     #error "FIXME: need to decode instruction and compute EA"
410     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
411     #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
412     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
413     #endif
414     #endif
415     #if defined(__FreeBSD__)
416 gbeauche 1.39 #if (defined(i386) || defined(__i386__))
417 gbeauche 1.33 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
418     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp, char *addr
419 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp, addr
420 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS addr
421 gbeauche 1.33 #define SIGSEGV_FAULT_INSTRUCTION scp->sc_eip
422 gbeauche 1.34 #define SIGSEGV_REGISTER_FILE ((unsigned long *)&scp->sc_edi)
423 gbeauche 1.33 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
424 gbeauche 1.1 #endif
425 gbeauche 1.39 #if (defined(alpha) || defined(__alpha__))
426     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
427     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, char *addr, struct sigcontext *scp
428     #define SIGSEGV_FAULT_HANDLER_ARGS sig, addr, scp
429     #define SIGSEGV_FAULT_ADDRESS addr
430     #define SIGSEGV_FAULT_INSTRUCTION scp->sc_pc
431     #endif
432 gbeauche 1.1 #endif
433 gbeauche 1.33
434     // Extract fault address out of a sigcontext
435     #if (defined(alpha) || defined(__alpha__))
436     // From Boehm's GC 6.0alpha8
437     static sigsegv_address_t get_fault_address(struct sigcontext *scp)
438     {
439     unsigned int instruction = *((unsigned int *)(scp->sc_pc));
440     unsigned long fault_address = scp->sc_regs[(instruction >> 16) & 0x1f];
441     fault_address += (signed long)(signed short)(instruction & 0xffff);
442     return (sigsegv_address_t)fault_address;
443     }
444     #endif
445    
446 gbeauche 1.4
447 gbeauche 1.27 // MacOS X, not sure which version this works in. Under 10.1
448     // vm_protect does not appear to work from a signal handler. Under
449     // 10.2 signal handlers get siginfo type arguments but the si_addr
450     // field is the address of the faulting instruction and not the
451     // address that caused the SIGBUS. Maybe this works in 10.0? In any
452     // case with Mach exception handlers there is a way to do what this
453     // was meant to do.
454     #ifndef HAVE_MACH_EXCEPTIONS
455 gbeauche 1.4 #if defined(__APPLE__) && defined(__MACH__)
456     #if (defined(ppc) || defined(__ppc__))
457     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
458 gbeauche 1.27 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
459 gbeauche 1.4 #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
460     #define SIGSEGV_FAULT_INSTRUCTION scp->sc_ir
461     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
462 gbeauche 1.14 #define SIGSEGV_REGISTER_FILE (unsigned int *)&scp->sc_ir, &((unsigned int *) scp->sc_regs)[2]
463     #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
464 gbeauche 1.4
465 gbeauche 1.14 // Use decoding scheme from SheepShaver
466 gbeauche 1.4 static sigsegv_address_t get_fault_address(struct sigcontext *scp)
467     {
468 gbeauche 1.14 unsigned int nip = (unsigned int) scp->sc_ir;
469     unsigned int * gpr = &((unsigned int *) scp->sc_regs)[2];
470     instruction_t instr;
471    
472     powerpc_decode_instruction(&instr, nip, gpr);
473     return (sigsegv_address_t)instr.addr;
474 gbeauche 1.4 }
475     #endif
476     #endif
477 gbeauche 1.1 #endif
478 gbeauche 1.27 #endif
479    
480     #if HAVE_MACH_EXCEPTIONS
481    
482     // This can easily be extended to other Mach systems, but really who
483     // uses HURD (oops GNU/HURD), Darwin/x86, NextStep, Rhapsody, or CMU
484     // Mach 2.5/3.0?
485     #if defined(__APPLE__) && defined(__MACH__)
486    
487     #include <sys/types.h>
488     #include <stdlib.h>
489     #include <stdio.h>
490     #include <pthread.h>
491    
492     /*
493     * If you are familiar with MIG then you will understand the frustration
494     * that was necessary to get these embedded into C++ code by hand.
495     */
496     extern "C" {
497     #include <mach/mach.h>
498     #include <mach/mach_error.h>
499    
500     extern boolean_t exc_server(mach_msg_header_t *, mach_msg_header_t *);
501     extern kern_return_t catch_exception_raise(mach_port_t, mach_port_t,
502     mach_port_t, exception_type_t, exception_data_t, mach_msg_type_number_t);
503     extern kern_return_t exception_raise(mach_port_t, mach_port_t, mach_port_t,
504     exception_type_t, exception_data_t, mach_msg_type_number_t);
505     extern kern_return_t exception_raise_state(mach_port_t, exception_type_t,
506     exception_data_t, mach_msg_type_number_t, thread_state_flavor_t *,
507     thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t *);
508     extern kern_return_t exception_raise_state_identity(mach_port_t, mach_port_t, mach_port_t,
509     exception_type_t, exception_data_t, mach_msg_type_number_t, thread_state_flavor_t *,
510     thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t *);
511     }
512    
513     // Could make this dynamic by looking for a result of MIG_ARRAY_TOO_LARGE
514     #define HANDLER_COUNT 64
515    
516     // structure to tuck away existing exception handlers
517     typedef struct _ExceptionPorts {
518     mach_msg_type_number_t maskCount;
519     exception_mask_t masks[HANDLER_COUNT];
520     exception_handler_t handlers[HANDLER_COUNT];
521     exception_behavior_t behaviors[HANDLER_COUNT];
522     thread_state_flavor_t flavors[HANDLER_COUNT];
523     } ExceptionPorts;
524    
525     // exception handler thread
526     static pthread_t exc_thread;
527    
528     // place where old exception handler info is stored
529     static ExceptionPorts ports;
530    
531     // our exception port
532     static mach_port_t _exceptionPort = MACH_PORT_NULL;
533    
534     #define MACH_CHECK_ERROR(name,ret) \
535     if (ret != KERN_SUCCESS) { \
536     mach_error(#name, ret); \
537     exit (1); \
538     }
539    
540     #define SIGSEGV_FAULT_ADDRESS code[1]
541     #define SIGSEGV_FAULT_INSTRUCTION get_fault_instruction(thread, state)
542 gbeauche 1.31 #define SIGSEGV_FAULT_HANDLER_INVOKE(ADDR, IP) ((code[0] == KERN_PROTECTION_FAILURE) ? sigsegv_fault_handler(ADDR, IP) : SIGSEGV_RETURN_FAILURE)
543 gbeauche 1.27 #define SIGSEGV_FAULT_HANDLER_ARGLIST mach_port_t thread, exception_data_t code, ppc_thread_state_t *state
544     #define SIGSEGV_FAULT_HANDLER_ARGS thread, code, &state
545     #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
546     #define SIGSEGV_REGISTER_FILE &state->srr0, &state->r0
547    
548     // Given a suspended thread, stuff the current instruction and
549     // registers into state.
550     //
551     // It would have been nice to have this be ppc/x86 independant which
552     // could have been done easily with a thread_state_t instead of
553     // ppc_thread_state_t, but because of the way this is called it is
554     // easier to do it this way.
555     #if (defined(ppc) || defined(__ppc__))
556     static inline sigsegv_address_t get_fault_instruction(mach_port_t thread, ppc_thread_state_t *state)
557     {
558     kern_return_t krc;
559     mach_msg_type_number_t count;
560    
561     count = MACHINE_THREAD_STATE_COUNT;
562     krc = thread_get_state(thread, MACHINE_THREAD_STATE, (thread_state_t)state, &count);
563     MACH_CHECK_ERROR (thread_get_state, krc);
564    
565     return (sigsegv_address_t)state->srr0;
566     }
567     #endif
568    
569     // Since there can only be one exception thread running at any time
570     // this is not a problem.
571     #define MSG_SIZE 512
572     static char msgbuf[MSG_SIZE];
573     static char replybuf[MSG_SIZE];
574    
575     /*
576     * This is the entry point for the exception handler thread. The job
577     * of this thread is to wait for exception messages on the exception
578     * port that was setup beforehand and to pass them on to exc_server.
579     * exc_server is a MIG generated function that is a part of Mach.
580     * Its job is to decide what to do with the exception message. In our
581     * case exc_server calls catch_exception_raise on our behalf. After
582     * exc_server returns, it is our responsibility to send the reply.
583     */
584     static void *
585     handleExceptions(void *priv)
586     {
587     mach_msg_header_t *msg, *reply;
588     kern_return_t krc;
589    
590     msg = (mach_msg_header_t *)msgbuf;
591     reply = (mach_msg_header_t *)replybuf;
592    
593     for (;;) {
594     krc = mach_msg(msg, MACH_RCV_MSG, MSG_SIZE, MSG_SIZE,
595     _exceptionPort, 0, MACH_PORT_NULL);
596     MACH_CHECK_ERROR(mach_msg, krc);
597    
598     if (!exc_server(msg, reply)) {
599     fprintf(stderr, "exc_server hated the message\n");
600     exit(1);
601     }
602    
603     krc = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0,
604     msg->msgh_local_port, 0, MACH_PORT_NULL);
605     if (krc != KERN_SUCCESS) {
606     fprintf(stderr, "Error sending message to original reply port, krc = %d, %s",
607     krc, mach_error_string(krc));
608     exit(1);
609     }
610     }
611     }
612     #endif
613     #endif
614 gbeauche 1.1
615 gbeauche 1.14
616     /*
617     * Instruction skipping
618     */
619    
620 gbeauche 1.10 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
621     // Decode and skip X86 instruction
622 gbeauche 1.34 #if (defined(i386) || defined(__i386__)) || defined(__x86_64__)
623 gbeauche 1.10 #if defined(__linux__)
624     enum {
625 gbeauche 1.34 #if (defined(i386) || defined(__i386__))
626 gbeauche 1.10 X86_REG_EIP = 14,
627     X86_REG_EAX = 11,
628     X86_REG_ECX = 10,
629     X86_REG_EDX = 9,
630     X86_REG_EBX = 8,
631     X86_REG_ESP = 7,
632     X86_REG_EBP = 6,
633     X86_REG_ESI = 5,
634     X86_REG_EDI = 4
635 gbeauche 1.34 #endif
636     #if defined(__x86_64__)
637     X86_REG_R8 = 0,
638     X86_REG_R9 = 1,
639     X86_REG_R10 = 2,
640     X86_REG_R11 = 3,
641     X86_REG_R12 = 4,
642     X86_REG_R13 = 5,
643     X86_REG_R14 = 6,
644     X86_REG_R15 = 7,
645     X86_REG_EDI = 8,
646     X86_REG_ESI = 9,
647     X86_REG_EBP = 10,
648     X86_REG_EBX = 11,
649     X86_REG_EDX = 12,
650     X86_REG_EAX = 13,
651     X86_REG_ECX = 14,
652     X86_REG_ESP = 15,
653     X86_REG_EIP = 16
654     #endif
655 gbeauche 1.10 };
656     #endif
657 gbeauche 1.17 #if defined(__NetBSD__) || defined(__FreeBSD__)
658     enum {
659 gbeauche 1.34 #if (defined(i386) || defined(__i386__))
660 gbeauche 1.17 X86_REG_EIP = 10,
661     X86_REG_EAX = 7,
662     X86_REG_ECX = 6,
663     X86_REG_EDX = 5,
664     X86_REG_EBX = 4,
665     X86_REG_ESP = 13,
666     X86_REG_EBP = 2,
667     X86_REG_ESI = 1,
668     X86_REG_EDI = 0
669 gbeauche 1.34 #endif
670 gbeauche 1.17 };
671     #endif
672 gbeauche 1.10 // FIXME: this is partly redundant with the instruction decoding phase
673     // to discover transfer type and register number
674     static inline int ix86_step_over_modrm(unsigned char * p)
675     {
676     int mod = (p[0] >> 6) & 3;
677     int rm = p[0] & 7;
678     int offset = 0;
679    
680     // ModR/M Byte
681     switch (mod) {
682     case 0: // [reg]
683     if (rm == 5) return 4; // disp32
684     break;
685     case 1: // disp8[reg]
686     offset = 1;
687     break;
688     case 2: // disp32[reg]
689     offset = 4;
690     break;
691     case 3: // register
692     return 0;
693     }
694    
695     // SIB Byte
696     if (rm == 4) {
697     if (mod == 0 && (p[1] & 7) == 5)
698     offset = 5; // disp32[index]
699     else
700     offset++;
701     }
702    
703     return offset;
704     }
705    
706 gbeauche 1.34 static bool ix86_skip_instruction(unsigned long * regs)
707 gbeauche 1.10 {
708 gbeauche 1.14 unsigned char * eip = (unsigned char *)regs[X86_REG_EIP];
709 gbeauche 1.10
710     if (eip == 0)
711     return false;
712    
713 gbeauche 1.22 transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
714 gbeauche 1.14 transfer_size_t transfer_size = SIZE_LONG;
715 gbeauche 1.10
716     int reg = -1;
717     int len = 0;
718 gbeauche 1.34
719     #if DEBUG
720     printf("IP: %p [%02x %02x %02x %02x...]\n",
721     eip, eip[0], eip[1], eip[2], eip[3]);
722     #endif
723    
724 gbeauche 1.10 // Operand size prefix
725     if (*eip == 0x66) {
726     eip++;
727     len++;
728     transfer_size = SIZE_WORD;
729     }
730    
731 gbeauche 1.34 // REX prefix
732     #if defined(__x86_64__)
733     struct rex_t {
734     unsigned char W;
735     unsigned char R;
736     unsigned char X;
737     unsigned char B;
738     };
739     rex_t rex = { 0, 0, 0, 0 };
740     bool has_rex = false;
741     if ((*eip & 0xf0) == 0x40) {
742     has_rex = true;
743     const unsigned char b = *eip;
744     rex.W = b & (1 << 3);
745     rex.R = b & (1 << 2);
746     rex.X = b & (1 << 1);
747     rex.B = b & (1 << 0);
748     #if DEBUG
749     printf("REX: %c,%c,%c,%c\n",
750     rex.W ? 'W' : '_',
751     rex.R ? 'R' : '_',
752     rex.X ? 'X' : '_',
753     rex.B ? 'B' : '_');
754     #endif
755     eip++;
756     len++;
757     if (rex.W)
758     transfer_size = SIZE_QUAD;
759     }
760     #else
761     const bool has_rex = false;
762     #endif
763    
764 gbeauche 1.10 // Decode instruction
765     switch (eip[0]) {
766 gbeauche 1.17 case 0x0f:
767 gbeauche 1.18 switch (eip[1]) {
768     case 0xb6: // MOVZX r32, r/m8
769     case 0xb7: // MOVZX r32, r/m16
770 gbeauche 1.17 switch (eip[2] & 0xc0) {
771     case 0x80:
772     reg = (eip[2] >> 3) & 7;
773 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
774 gbeauche 1.17 break;
775     case 0x40:
776     reg = (eip[2] >> 3) & 7;
777 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
778 gbeauche 1.17 break;
779     case 0x00:
780     reg = (eip[2] >> 3) & 7;
781 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
782 gbeauche 1.17 break;
783     }
784     len += 3 + ix86_step_over_modrm(eip + 2);
785 gbeauche 1.18 break;
786 gbeauche 1.17 }
787     break;
788 gbeauche 1.10 case 0x8a: // MOV r8, r/m8
789     transfer_size = SIZE_BYTE;
790     case 0x8b: // MOV r32, r/m32 (or 16-bit operation)
791     switch (eip[1] & 0xc0) {
792     case 0x80:
793     reg = (eip[1] >> 3) & 7;
794 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
795 gbeauche 1.10 break;
796     case 0x40:
797     reg = (eip[1] >> 3) & 7;
798 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
799 gbeauche 1.10 break;
800     case 0x00:
801     reg = (eip[1] >> 3) & 7;
802 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
803 gbeauche 1.10 break;
804     }
805     len += 2 + ix86_step_over_modrm(eip + 1);
806     break;
807     case 0x88: // MOV r/m8, r8
808     transfer_size = SIZE_BYTE;
809     case 0x89: // MOV r/m32, r32 (or 16-bit operation)
810     switch (eip[1] & 0xc0) {
811     case 0x80:
812     reg = (eip[1] >> 3) & 7;
813 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
814 gbeauche 1.10 break;
815     case 0x40:
816     reg = (eip[1] >> 3) & 7;
817 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
818 gbeauche 1.10 break;
819     case 0x00:
820     reg = (eip[1] >> 3) & 7;
821 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
822 gbeauche 1.10 break;
823     }
824     len += 2 + ix86_step_over_modrm(eip + 1);
825     break;
826     }
827    
828 gbeauche 1.22 if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
829 gbeauche 1.10 // Unknown machine code, let it crash. Then patch the decoder
830     return false;
831     }
832    
833 gbeauche 1.34 #if defined(__x86_64__)
834     if (rex.R)
835     reg += 8;
836     #endif
837    
838 gbeauche 1.22 if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) {
839 gbeauche 1.34 static const int x86_reg_map[] = {
840 gbeauche 1.10 X86_REG_EAX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBX,
841 gbeauche 1.34 X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI,
842     #if defined(__x86_64__)
843     X86_REG_R8, X86_REG_R9, X86_REG_R10, X86_REG_R11,
844     X86_REG_R12, X86_REG_R13, X86_REG_R14, X86_REG_R15,
845     #endif
846 gbeauche 1.10 };
847    
848 gbeauche 1.34 if (reg < 0 || reg >= (sizeof(x86_reg_map)/sizeof(x86_reg_map[0]) - 1))
849 gbeauche 1.10 return false;
850    
851 gbeauche 1.34 // Set 0 to the relevant register part
852     // NOTE: this is only valid for MOV alike instructions
853 gbeauche 1.10 int rloc = x86_reg_map[reg];
854     switch (transfer_size) {
855     case SIZE_BYTE:
856 gbeauche 1.36 if (has_rex || reg < 4)
857     regs[rloc] = (regs[rloc] & ~0x00ffL);
858     else {
859     rloc = x86_reg_map[reg - 4];
860     regs[rloc] = (regs[rloc] & ~0xff00L);
861     }
862 gbeauche 1.10 break;
863     case SIZE_WORD:
864 gbeauche 1.34 regs[rloc] = (regs[rloc] & ~0xffffL);
865 gbeauche 1.10 break;
866     case SIZE_LONG:
867 gbeauche 1.34 case SIZE_QUAD: // zero-extension
868 gbeauche 1.10 regs[rloc] = 0;
869     break;
870     }
871     }
872    
873     #if DEBUG
874 gbeauche 1.15 printf("%08x: %s %s access", regs[X86_REG_EIP],
875 gbeauche 1.34 transfer_size == SIZE_BYTE ? "byte" :
876     transfer_size == SIZE_WORD ? "word" :
877     transfer_size == SIZE_LONG ? "long" :
878     transfer_size == SIZE_QUAD ? "quad" : "unknown",
879 gbeauche 1.22 transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
880 gbeauche 1.10
881     if (reg != -1) {
882 gbeauche 1.34 static const char * x86_byte_reg_str_map[] = {
883     "al", "cl", "dl", "bl",
884     "spl", "bpl", "sil", "dil",
885     "r8b", "r9b", "r10b", "r11b",
886     "r12b", "r13b", "r14b", "r15b",
887     "ah", "ch", "dh", "bh",
888     };
889     static const char * x86_word_reg_str_map[] = {
890     "ax", "cx", "dx", "bx",
891     "sp", "bp", "si", "di",
892     "r8w", "r9w", "r10w", "r11w",
893     "r12w", "r13w", "r14w", "r15w",
894     };
895     static const char *x86_long_reg_str_map[] = {
896     "eax", "ecx", "edx", "ebx",
897     "esp", "ebp", "esi", "edi",
898     "r8d", "r9d", "r10d", "r11d",
899     "r12d", "r13d", "r14d", "r15d",
900     };
901     static const char *x86_quad_reg_str_map[] = {
902     "rax", "rcx", "rdx", "rbx",
903     "rsp", "rbp", "rsi", "rdi",
904     "r8", "r9", "r10", "r11",
905     "r12", "r13", "r14", "r15",
906 gbeauche 1.10 };
907 gbeauche 1.34 const char * reg_str = NULL;
908     switch (transfer_size) {
909     case SIZE_BYTE:
910     reg_str = x86_byte_reg_str_map[(!has_rex && reg >= 4 ? 12 : 0) + reg];
911     break;
912     case SIZE_WORD: reg_str = x86_word_reg_str_map[reg]; break;
913     case SIZE_LONG: reg_str = x86_long_reg_str_map[reg]; break;
914     case SIZE_QUAD: reg_str = x86_quad_reg_str_map[reg]; break;
915     }
916     if (reg_str)
917     printf(" %s register %%%s",
918     transfer_type == SIGSEGV_TRANSFER_LOAD ? "to" : "from",
919     reg_str);
920 gbeauche 1.10 }
921     printf(", %d bytes instruction\n", len);
922     #endif
923    
924     regs[X86_REG_EIP] += len;
925 gbeauche 1.13 return true;
926     }
927     #endif
928 gbeauche 1.14
929 gbeauche 1.13 // Decode and skip PPC instruction
930 gbeauche 1.14 #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__))
931     static bool powerpc_skip_instruction(unsigned int * nip_p, unsigned int * regs)
932 gbeauche 1.13 {
933 gbeauche 1.14 instruction_t instr;
934     powerpc_decode_instruction(&instr, *nip_p, regs);
935 gbeauche 1.13
936 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
937 gbeauche 1.13 // Unknown machine code, let it crash. Then patch the decoder
938     return false;
939     }
940    
941     #if DEBUG
942 gbeauche 1.14 printf("%08x: %s %s access", *nip_p,
943     instr.transfer_size == SIZE_BYTE ? "byte" : instr.transfer_size == SIZE_WORD ? "word" : "long",
944 gbeauche 1.22 instr.transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
945 gbeauche 1.14
946     if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
947     printf(" r%d (ra = %08x)\n", instr.ra, instr.addr);
948 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
949 gbeauche 1.14 printf(" r%d (rd = 0)\n", instr.rd);
950     #endif
951    
952     if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
953     regs[instr.ra] = instr.addr;
954 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
955 gbeauche 1.14 regs[instr.rd] = 0;
956 gbeauche 1.13
957 gbeauche 1.14 *nip_p += 4;
958 gbeauche 1.10 return true;
959 gbeauche 1.38 }
960     #endif
961    
962     // Decode and skip MIPS instruction
963     #if (defined(mips) || defined(__mips))
964     enum {
965     #if (defined(sgi) || defined(__sgi))
966     MIPS_REG_EPC = 35,
967     #endif
968     };
969     static bool mips_skip_instruction(greg_t * regs)
970     {
971     unsigned int * epc = (unsigned int *)(unsigned long)regs[MIPS_REG_EPC];
972    
973     if (epc == 0)
974     return false;
975    
976     #if DEBUG
977     printf("IP: %p [%08x]\n", epc, epc[0]);
978     #endif
979    
980     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
981     transfer_size_t transfer_size = SIZE_LONG;
982     int direction = 0;
983    
984     const unsigned int opcode = epc[0];
985     switch (opcode >> 26) {
986     case 32: // Load Byte
987     case 36: // Load Byte Unsigned
988     transfer_type = SIGSEGV_TRANSFER_LOAD;
989     transfer_size = SIZE_BYTE;
990     break;
991     case 33: // Load Halfword
992     case 37: // Load Halfword Unsigned
993     transfer_type = SIGSEGV_TRANSFER_LOAD;
994     transfer_size = SIZE_WORD;
995     break;
996     case 35: // Load Word
997     case 39: // Load Word Unsigned
998     transfer_type = SIGSEGV_TRANSFER_LOAD;
999     transfer_size = SIZE_LONG;
1000     break;
1001     case 34: // Load Word Left
1002     transfer_type = SIGSEGV_TRANSFER_LOAD;
1003     transfer_size = SIZE_LONG;
1004     direction = -1;
1005     break;
1006     case 38: // Load Word Right
1007     transfer_type = SIGSEGV_TRANSFER_LOAD;
1008     transfer_size = SIZE_LONG;
1009     direction = 1;
1010     break;
1011     case 55: // Load Doubleword
1012     transfer_type = SIGSEGV_TRANSFER_LOAD;
1013     transfer_size = SIZE_QUAD;
1014     break;
1015     case 26: // Load Doubleword Left
1016     transfer_type = SIGSEGV_TRANSFER_LOAD;
1017     transfer_size = SIZE_QUAD;
1018     direction = -1;
1019     break;
1020     case 27: // Load Doubleword Right
1021     transfer_type = SIGSEGV_TRANSFER_LOAD;
1022     transfer_size = SIZE_QUAD;
1023     direction = 1;
1024     break;
1025     case 40: // Store Byte
1026     transfer_type = SIGSEGV_TRANSFER_STORE;
1027     transfer_size = SIZE_BYTE;
1028     break;
1029     case 41: // Store Halfword
1030     transfer_type = SIGSEGV_TRANSFER_STORE;
1031     transfer_size = SIZE_WORD;
1032     break;
1033     case 43: // Store Word
1034     case 42: // Store Word Left
1035     case 46: // Store Word Right
1036     transfer_type = SIGSEGV_TRANSFER_STORE;
1037     transfer_size = SIZE_LONG;
1038     break;
1039     case 63: // Store Doubleword
1040     case 44: // Store Doubleword Left
1041     case 45: // Store Doubleword Right
1042     transfer_type = SIGSEGV_TRANSFER_STORE;
1043     transfer_size = SIZE_QUAD;
1044     break;
1045     /* Misc instructions unlikely to be used within CPU emulators */
1046     case 48: // Load Linked Word
1047     transfer_type = SIGSEGV_TRANSFER_LOAD;
1048     transfer_size = SIZE_LONG;
1049     break;
1050     case 52: // Load Linked Doubleword
1051     transfer_type = SIGSEGV_TRANSFER_LOAD;
1052     transfer_size = SIZE_QUAD;
1053     break;
1054     case 56: // Store Conditional Word
1055     transfer_type = SIGSEGV_TRANSFER_STORE;
1056     transfer_size = SIZE_LONG;
1057     break;
1058     case 60: // Store Conditional Doubleword
1059     transfer_type = SIGSEGV_TRANSFER_STORE;
1060     transfer_size = SIZE_QUAD;
1061     break;
1062     }
1063    
1064     if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1065     // Unknown machine code, let it crash. Then patch the decoder
1066     return false;
1067     }
1068    
1069     // Zero target register in case of a load operation
1070     const int reg = (opcode >> 16) & 0x1f;
1071     if (transfer_type == SIGSEGV_TRANSFER_LOAD) {
1072     if (direction == 0)
1073     regs[reg] = 0;
1074     else {
1075     // FIXME: untested code
1076     unsigned long ea = regs[(opcode >> 21) & 0x1f];
1077     ea += (signed long)(signed int)(signed short)(opcode & 0xffff);
1078     const int offset = ea & (transfer_size == SIZE_LONG ? 3 : 7);
1079     unsigned long value;
1080     if (direction > 0) {
1081     const unsigned long rmask = ~((1L << ((offset + 1) * 8)) - 1);
1082     value = regs[reg] & rmask;
1083     }
1084     else {
1085     const unsigned long lmask = (1L << (offset * 8)) - 1;
1086     value = regs[reg] & lmask;
1087     }
1088     // restore most significant bits
1089     if (transfer_size == SIZE_LONG)
1090     value = (signed long)(signed int)value;
1091     regs[reg] = value;
1092     }
1093     }
1094    
1095     #if DEBUG
1096     #if (defined(_ABIN32) || defined(_ABI64))
1097     static const char * mips_gpr_names[32] = {
1098     "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
1099     "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
1100     "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
1101     "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
1102     };
1103     #else
1104     static const char * mips_gpr_names[32] = {
1105     "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
1106     "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
1107     "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
1108     "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
1109     };
1110     #endif
1111     printf("%s %s register %s\n",
1112     transfer_size == SIZE_BYTE ? "byte" :
1113     transfer_size == SIZE_WORD ? "word" :
1114     transfer_size == SIZE_LONG ? "long" :
1115     transfer_size == SIZE_QUAD ? "quad" : "unknown",
1116     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1117     mips_gpr_names[reg]);
1118     #endif
1119    
1120     regs[MIPS_REG_EPC] += 4;
1121 gbeauche 1.40 return true;
1122     }
1123     #endif
1124    
1125     // Decode and skip SPARC instruction
1126     #if (defined(sparc) || defined(__sparc__))
1127     enum {
1128     #if (defined(__sun__))
1129     SPARC_REG_G1 = REG_G1,
1130     SPARC_REG_O0 = REG_O0,
1131     SPARC_REG_PC = REG_PC,
1132     #endif
1133     };
1134     static bool sparc_skip_instruction(unsigned long * regs, gwindows_t * gwins, struct rwindow * rwin)
1135     {
1136     unsigned int * pc = (unsigned int *)regs[SPARC_REG_PC];
1137    
1138     if (pc == 0)
1139     return false;
1140    
1141     #if DEBUG
1142     printf("IP: %p [%08x]\n", pc, pc[0]);
1143     #endif
1144    
1145     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1146     transfer_size_t transfer_size = SIZE_LONG;
1147     bool register_pair = false;
1148    
1149     const unsigned int opcode = pc[0];
1150     if ((opcode >> 30) != 3)
1151     return false;
1152     switch ((opcode >> 19) & 0x3f) {
1153     case 9: // Load Signed Byte
1154     case 1: // Load Unsigned Byte
1155     transfer_type = SIGSEGV_TRANSFER_LOAD;
1156     transfer_size = SIZE_BYTE;
1157     break;
1158     case 10:// Load Signed Halfword
1159     case 2: // Load Unsigned Word
1160     transfer_type = SIGSEGV_TRANSFER_LOAD;
1161     transfer_size = SIZE_WORD;
1162     break;
1163     case 8: // Load Word
1164     case 0: // Load Unsigned Word
1165     transfer_type = SIGSEGV_TRANSFER_LOAD;
1166     transfer_size = SIZE_LONG;
1167     break;
1168     case 11:// Load Extended Word
1169     transfer_type = SIGSEGV_TRANSFER_LOAD;
1170     transfer_size = SIZE_QUAD;
1171     break;
1172     case 3: // Load Doubleword
1173     transfer_type = SIGSEGV_TRANSFER_LOAD;
1174     transfer_size = SIZE_LONG;
1175     register_pair = true;
1176     break;
1177     case 5: // Store Byte
1178     transfer_type = SIGSEGV_TRANSFER_STORE;
1179     transfer_size = SIZE_BYTE;
1180     break;
1181     case 6: // Store Halfword
1182     transfer_type = SIGSEGV_TRANSFER_STORE;
1183     transfer_size = SIZE_WORD;
1184     break;
1185     case 4: // Store Word
1186     transfer_type = SIGSEGV_TRANSFER_STORE;
1187     transfer_size = SIZE_LONG;
1188     break;
1189     case 14:// Store Extended Word
1190     transfer_type = SIGSEGV_TRANSFER_STORE;
1191     transfer_size = SIZE_QUAD;
1192     break;
1193     case 7: // Store Doubleword
1194     transfer_type = SIGSEGV_TRANSFER_STORE;
1195     transfer_size = SIZE_WORD;
1196     register_pair = true;
1197     break;
1198     }
1199    
1200     if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1201     // Unknown machine code, let it crash. Then patch the decoder
1202     return false;
1203     }
1204    
1205     // Zero target register in case of a load operation
1206     const int reg = (opcode >> 25) & 0x1f;
1207     if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != 0) {
1208     // FIXME: code to handle local & input registers is not tested
1209     if (reg >= 1 && reg <= 7) {
1210     // global registers
1211     regs[reg - 1 + SPARC_REG_G1] = 0;
1212     }
1213     else if (reg >= 8 && reg <= 15) {
1214     // output registers
1215     regs[reg - 8 + SPARC_REG_O0] = 0;
1216     }
1217     else if (reg >= 16 && reg <= 23) {
1218     // local registers (in register windows)
1219     if (gwins)
1220     gwins->wbuf->rw_local[reg - 16] = 0;
1221     else
1222     rwin->rw_local[reg - 16] = 0;
1223     }
1224     else {
1225     // input registers (in register windows)
1226     if (gwins)
1227     gwins->wbuf->rw_in[reg - 24] = 0;
1228     else
1229     rwin->rw_in[reg - 24] = 0;
1230     }
1231     }
1232    
1233     #if DEBUG
1234     static const char * reg_names[] = {
1235     "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
1236     "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
1237     "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
1238     "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"
1239     };
1240     printf("%s %s register %s\n",
1241     transfer_size == SIZE_BYTE ? "byte" :
1242     transfer_size == SIZE_WORD ? "word" :
1243     transfer_size == SIZE_LONG ? "long" :
1244     transfer_size == SIZE_QUAD ? "quad" : "unknown",
1245     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1246     reg_names[reg]);
1247     #endif
1248    
1249     regs[SPARC_REG_PC] += 4;
1250 gbeauche 1.38 return true;
1251 gbeauche 1.10 }
1252     #endif
1253     #endif
1254    
1255 gbeauche 1.1 // Fallbacks
1256     #ifndef SIGSEGV_FAULT_INSTRUCTION
1257     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_INVALID_PC
1258     #endif
1259 gbeauche 1.30 #ifndef SIGSEGV_FAULT_HANDLER_ARGLIST_1
1260     #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 SIGSEGV_FAULT_HANDLER_ARGLIST
1261     #endif
1262 gbeauche 1.31 #ifndef SIGSEGV_FAULT_HANDLER_INVOKE
1263     #define SIGSEGV_FAULT_HANDLER_INVOKE(ADDR, IP) sigsegv_fault_handler(ADDR, IP)
1264     #endif
1265 gbeauche 1.1
1266 gbeauche 1.2 // SIGSEGV recovery supported ?
1267     #if defined(SIGSEGV_ALL_SIGNALS) && defined(SIGSEGV_FAULT_HANDLER_ARGLIST) && defined(SIGSEGV_FAULT_ADDRESS)
1268     #define HAVE_SIGSEGV_RECOVERY
1269     #endif
1270    
1271 gbeauche 1.1
1272     /*
1273     * SIGSEGV global handler
1274     */
1275    
1276 gbeauche 1.27 #if defined(HAVE_SIGSEGV_RECOVERY) || defined(HAVE_MACH_EXCEPTIONS)
1277     // This function handles the badaccess to memory.
1278     // It is called from the signal handler or the exception handler.
1279 gbeauche 1.30 static bool handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGLIST_1)
1280 gbeauche 1.1 {
1281 gbeauche 1.10 sigsegv_address_t fault_address = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
1282     sigsegv_address_t fault_instruction = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
1283    
1284 gbeauche 1.1 // Call user's handler and reinstall the global handler, if required
1285 gbeauche 1.31 switch (SIGSEGV_FAULT_HANDLER_INVOKE(fault_address, fault_instruction)) {
1286 gbeauche 1.24 case SIGSEGV_RETURN_SUCCESS:
1287 gbeauche 1.27 return true;
1288    
1289 gbeauche 1.10 #if HAVE_SIGSEGV_SKIP_INSTRUCTION
1290 gbeauche 1.24 case SIGSEGV_RETURN_SKIP_INSTRUCTION:
1291 gbeauche 1.27 // Call the instruction skipper with the register file
1292     // available
1293     if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE)) {
1294     #ifdef HAVE_MACH_EXCEPTIONS
1295     // Unlike UNIX signals where the thread state
1296     // is modified off of the stack, in Mach we
1297     // need to actually call thread_set_state to
1298     // have the register values updated.
1299     kern_return_t krc;
1300    
1301     krc = thread_set_state(thread,
1302     MACHINE_THREAD_STATE, (thread_state_t)state,
1303     MACHINE_THREAD_STATE_COUNT);
1304     MACH_CHECK_ERROR (thread_get_state, krc);
1305     #endif
1306     return true;
1307     }
1308 gbeauche 1.24 break;
1309     #endif
1310 nigel 1.43 case SIGSEGV_RETURN_FAILURE:
1311     return false;
1312 gbeauche 1.10 }
1313 gbeauche 1.27
1314     // We can't do anything with the fault_address, dump state?
1315     if (sigsegv_state_dumper != 0)
1316     sigsegv_state_dumper(fault_address, fault_instruction);
1317    
1318     return false;
1319     }
1320     #endif
1321    
1322    
1323     /*
1324     * There are two mechanisms for handling a bad memory access,
1325     * Mach exceptions and UNIX signals. The implementation specific
1326     * code appears below. Its reponsibility is to call handle_badaccess
1327     * which is the routine that handles the fault in an implementation
1328     * agnostic manner. The implementation specific code below is then
1329     * reponsible for checking whether handle_badaccess was able
1330     * to handle the memory access error and perform any implementation
1331     * specific tasks necessary afterwards.
1332     */
1333    
1334     #ifdef HAVE_MACH_EXCEPTIONS
1335     /*
1336     * We need to forward all exceptions that we do not handle.
1337     * This is important, there are many exceptions that may be
1338     * handled by other exception handlers. For example debuggers
1339     * use exceptions and the exception hander is in another
1340     * process in such a case. (Timothy J. Wood states in his
1341     * message to the list that he based this code on that from
1342     * gdb for Darwin.)
1343     */
1344     static inline kern_return_t
1345     forward_exception(mach_port_t thread_port,
1346     mach_port_t task_port,
1347     exception_type_t exception_type,
1348     exception_data_t exception_data,
1349     mach_msg_type_number_t data_count,
1350     ExceptionPorts *oldExceptionPorts)
1351     {
1352     kern_return_t kret;
1353     unsigned int portIndex;
1354     mach_port_t port;
1355     exception_behavior_t behavior;
1356     thread_state_flavor_t flavor;
1357     thread_state_t thread_state;
1358     mach_msg_type_number_t thread_state_count;
1359    
1360     for (portIndex = 0; portIndex < oldExceptionPorts->maskCount; portIndex++) {
1361     if (oldExceptionPorts->masks[portIndex] & (1 << exception_type)) {
1362     // This handler wants the exception
1363     break;
1364     }
1365     }
1366    
1367     if (portIndex >= oldExceptionPorts->maskCount) {
1368     fprintf(stderr, "No handler for exception_type = %d. Not fowarding\n", exception_type);
1369     return KERN_FAILURE;
1370     }
1371    
1372     port = oldExceptionPorts->handlers[portIndex];
1373     behavior = oldExceptionPorts->behaviors[portIndex];
1374     flavor = oldExceptionPorts->flavors[portIndex];
1375    
1376     /*
1377     fprintf(stderr, "forwarding exception, port = 0x%x, behaviour = %d, flavor = %d\n", port, behavior, flavor);
1378     */
1379    
1380     if (behavior != EXCEPTION_DEFAULT) {
1381     thread_state_count = THREAD_STATE_MAX;
1382     kret = thread_get_state (thread_port, flavor, thread_state,
1383     &thread_state_count);
1384     MACH_CHECK_ERROR (thread_get_state, kret);
1385     }
1386    
1387     switch (behavior) {
1388     case EXCEPTION_DEFAULT:
1389     // fprintf(stderr, "forwarding to exception_raise\n");
1390     kret = exception_raise(port, thread_port, task_port, exception_type,
1391     exception_data, data_count);
1392     MACH_CHECK_ERROR (exception_raise, kret);
1393     break;
1394     case EXCEPTION_STATE:
1395     // fprintf(stderr, "forwarding to exception_raise_state\n");
1396     kret = exception_raise_state(port, exception_type, exception_data,
1397     data_count, &flavor,
1398     thread_state, thread_state_count,
1399     thread_state, &thread_state_count);
1400     MACH_CHECK_ERROR (exception_raise_state, kret);
1401     break;
1402     case EXCEPTION_STATE_IDENTITY:
1403     // fprintf(stderr, "forwarding to exception_raise_state_identity\n");
1404     kret = exception_raise_state_identity(port, thread_port, task_port,
1405     exception_type, exception_data,
1406     data_count, &flavor,
1407     thread_state, thread_state_count,
1408     thread_state, &thread_state_count);
1409     MACH_CHECK_ERROR (exception_raise_state_identity, kret);
1410     break;
1411     default:
1412     fprintf(stderr, "forward_exception got unknown behavior\n");
1413     break;
1414     }
1415    
1416     if (behavior != EXCEPTION_DEFAULT) {
1417     kret = thread_set_state (thread_port, flavor, thread_state,
1418     thread_state_count);
1419     MACH_CHECK_ERROR (thread_set_state, kret);
1420     }
1421    
1422     return KERN_SUCCESS;
1423     }
1424    
1425     /*
1426     * This is the code that actually handles the exception.
1427     * It is called by exc_server. For Darwin 5 Apple changed
1428     * this a bit from how this family of functions worked in
1429     * Mach. If you are familiar with that it is a little
1430     * different. The main variation that concerns us here is
1431     * that code is an array of exception specific codes and
1432     * codeCount is a count of the number of codes in the code
1433     * array. In typical Mach all exceptions have a code
1434     * and sub-code. It happens to be the case that for a
1435     * EXC_BAD_ACCESS exception the first entry is the type of
1436     * bad access that occurred and the second entry is the
1437     * faulting address so these entries correspond exactly to
1438     * how the code and sub-code are used on Mach.
1439     *
1440     * This is a MIG interface. No code in Basilisk II should
1441     * call this directley. This has to have external C
1442     * linkage because that is what exc_server expects.
1443     */
1444     kern_return_t
1445     catch_exception_raise(mach_port_t exception_port,
1446     mach_port_t thread,
1447     mach_port_t task,
1448     exception_type_t exception,
1449     exception_data_t code,
1450     mach_msg_type_number_t codeCount)
1451     {
1452     ppc_thread_state_t state;
1453     kern_return_t krc;
1454    
1455     if ((exception == EXC_BAD_ACCESS) && (codeCount >= 2)) {
1456     if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS))
1457     return KERN_SUCCESS;
1458     }
1459    
1460     // In Mach we do not need to remove the exception handler.
1461     // If we forward the exception, eventually some exception handler
1462     // will take care of this exception.
1463     krc = forward_exception(thread, task, exception, code, codeCount, &ports);
1464    
1465     return krc;
1466     }
1467     #endif
1468    
1469     #ifdef HAVE_SIGSEGV_RECOVERY
1470     // Handle bad memory accesses with signal handler
1471     static void sigsegv_handler(SIGSEGV_FAULT_HANDLER_ARGLIST)
1472     {
1473     // Call handler and reinstall the global handler, if required
1474     if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS)) {
1475     #if (defined(HAVE_SIGACTION) ? defined(SIGACTION_NEED_REINSTALL) : defined(SIGNAL_NEED_REINSTALL))
1476     sigsegv_do_install_handler(sig);
1477     #endif
1478     return;
1479     }
1480 gbeauche 1.10
1481 gbeauche 1.27 // Failure: reinstall default handler for "safe" crash
1482 gbeauche 1.1 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
1483 gbeauche 1.27 SIGSEGV_ALL_SIGNALS
1484 gbeauche 1.1 #undef FAULT_HANDLER
1485     }
1486 gbeauche 1.2 #endif
1487 gbeauche 1.1
1488    
1489     /*
1490     * SIGSEGV handler initialization
1491     */
1492    
1493     #if defined(HAVE_SIGINFO_T)
1494     static bool sigsegv_do_install_handler(int sig)
1495     {
1496     // Setup SIGSEGV handler to process writes to frame buffer
1497     #ifdef HAVE_SIGACTION
1498 gbeauche 1.22 struct sigaction sigsegv_sa;
1499     sigemptyset(&sigsegv_sa.sa_mask);
1500     sigsegv_sa.sa_sigaction = sigsegv_handler;
1501     sigsegv_sa.sa_flags = SA_SIGINFO;
1502     return (sigaction(sig, &sigsegv_sa, 0) == 0);
1503 gbeauche 1.1 #else
1504     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
1505     #endif
1506     }
1507 gbeauche 1.2 #endif
1508    
1509     #if defined(HAVE_SIGCONTEXT_SUBTERFUGE)
1510 gbeauche 1.1 static bool sigsegv_do_install_handler(int sig)
1511     {
1512     // Setup SIGSEGV handler to process writes to frame buffer
1513     #ifdef HAVE_SIGACTION
1514 gbeauche 1.22 struct sigaction sigsegv_sa;
1515     sigemptyset(&sigsegv_sa.sa_mask);
1516     sigsegv_sa.sa_handler = (signal_handler)sigsegv_handler;
1517     sigsegv_sa.sa_flags = 0;
1518 gbeauche 1.1 #if !EMULATED_68K && defined(__NetBSD__)
1519 gbeauche 1.22 sigaddset(&sigsegv_sa.sa_mask, SIGALRM);
1520     sigsegv_sa.sa_flags |= SA_ONSTACK;
1521 gbeauche 1.1 #endif
1522 gbeauche 1.22 return (sigaction(sig, &sigsegv_sa, 0) == 0);
1523 gbeauche 1.1 #else
1524     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
1525     #endif
1526     }
1527     #endif
1528    
1529 gbeauche 1.27 #if defined(HAVE_MACH_EXCEPTIONS)
1530     static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
1531     {
1532     /*
1533     * Except for the exception port functions, this should be
1534     * pretty much stock Mach. If later you choose to support
1535     * other Mach's besides Darwin, just check for __MACH__
1536     * here and __APPLE__ where the actual differences are.
1537     */
1538     #if defined(__APPLE__) && defined(__MACH__)
1539     if (sigsegv_fault_handler != NULL) {
1540     sigsegv_fault_handler = handler;
1541     return true;
1542     }
1543    
1544     kern_return_t krc;
1545    
1546     // create the the exception port
1547     krc = mach_port_allocate(mach_task_self(),
1548     MACH_PORT_RIGHT_RECEIVE, &_exceptionPort);
1549     if (krc != KERN_SUCCESS) {
1550     mach_error("mach_port_allocate", krc);
1551     return false;
1552     }
1553    
1554     // add a port send right
1555     krc = mach_port_insert_right(mach_task_self(),
1556     _exceptionPort, _exceptionPort,
1557     MACH_MSG_TYPE_MAKE_SEND);
1558     if (krc != KERN_SUCCESS) {
1559     mach_error("mach_port_insert_right", krc);
1560     return false;
1561     }
1562    
1563     // get the old exception ports
1564     ports.maskCount = sizeof (ports.masks) / sizeof (ports.masks[0]);
1565     krc = thread_get_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, ports.masks,
1566     &ports.maskCount, ports.handlers, ports.behaviors, ports.flavors);
1567     if (krc != KERN_SUCCESS) {
1568     mach_error("thread_get_exception_ports", krc);
1569     return false;
1570     }
1571    
1572     // set the new exception port
1573     //
1574     // We could have used EXCEPTION_STATE_IDENTITY instead of
1575     // EXCEPTION_DEFAULT to get the thread state in the initial
1576     // message, but it turns out that in the common case this is not
1577     // neccessary. If we need it we can later ask for it from the
1578     // suspended thread.
1579     //
1580     // Even with THREAD_STATE_NONE, Darwin provides the program
1581     // counter in the thread state. The comments in the header file
1582     // seem to imply that you can count on the GPR's on an exception
1583     // as well but just to be safe I use MACHINE_THREAD_STATE because
1584     // you have to ask for all of the GPR's anyway just to get the
1585     // program counter. In any case because of update effective
1586     // address from immediate and update address from effective
1587     // addresses of ra and rb modes (as good an name as any for these
1588     // addressing modes) used in PPC instructions, you will need the
1589     // GPR state anyway.
1590     krc = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, _exceptionPort,
1591     EXCEPTION_DEFAULT, MACHINE_THREAD_STATE);
1592     if (krc != KERN_SUCCESS) {
1593     mach_error("thread_set_exception_ports", krc);
1594     return false;
1595     }
1596    
1597     // create the exception handler thread
1598     if (pthread_create(&exc_thread, NULL, &handleExceptions, NULL) != 0) {
1599     (void)fprintf(stderr, "creation of exception thread failed\n");
1600     return false;
1601     }
1602    
1603     // do not care about the exception thread any longer, let is run standalone
1604     (void)pthread_detach(exc_thread);
1605    
1606     sigsegv_fault_handler = handler;
1607     return true;
1608     #else
1609     return false;
1610     #endif
1611     }
1612     #endif
1613    
1614 gbeauche 1.12 bool sigsegv_install_handler(sigsegv_fault_handler_t handler)
1615 gbeauche 1.1 {
1616 gbeauche 1.27 #if defined(HAVE_SIGSEGV_RECOVERY)
1617 gbeauche 1.1 bool success = true;
1618     #define FAULT_HANDLER(sig) success = success && sigsegv_do_install_handler(sig);
1619     SIGSEGV_ALL_SIGNALS
1620     #undef FAULT_HANDLER
1621 gbeauche 1.27 if (success)
1622     sigsegv_fault_handler = handler;
1623 gbeauche 1.1 return success;
1624 gbeauche 1.27 #elif defined(HAVE_MACH_EXCEPTIONS)
1625     return sigsegv_do_install_handler(handler);
1626 gbeauche 1.1 #else
1627     // FAIL: no siginfo_t nor sigcontext subterfuge is available
1628     return false;
1629     #endif
1630     }
1631    
1632    
1633     /*
1634     * SIGSEGV handler deinitialization
1635     */
1636    
1637     void sigsegv_deinstall_handler(void)
1638     {
1639 gbeauche 1.27 // We do nothing for Mach exceptions, the thread would need to be
1640     // suspended if not already so, and we might mess with other
1641     // exception handlers that came after we registered ours. There is
1642     // no need to remove the exception handler, in fact this function is
1643     // not called anywhere in Basilisk II.
1644 gbeauche 1.2 #ifdef HAVE_SIGSEGV_RECOVERY
1645 gbeauche 1.12 sigsegv_fault_handler = 0;
1646 gbeauche 1.1 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
1647     SIGSEGV_ALL_SIGNALS
1648     #undef FAULT_HANDLER
1649 gbeauche 1.2 #endif
1650 gbeauche 1.1 }
1651    
1652 gbeauche 1.10
1653     /*
1654     * Set callback function when we cannot handle the fault
1655     */
1656    
1657 gbeauche 1.12 void sigsegv_set_dump_state(sigsegv_state_dumper_t handler)
1658 gbeauche 1.10 {
1659 gbeauche 1.12 sigsegv_state_dumper = handler;
1660 gbeauche 1.10 }
1661    
1662    
1663 gbeauche 1.1 /*
1664     * Test program used for configure/test
1665     */
1666    
1667 gbeauche 1.4 #ifdef CONFIGURE_TEST_SIGSEGV_RECOVERY
1668 gbeauche 1.1 #include <stdio.h>
1669     #include <stdlib.h>
1670     #include <fcntl.h>
1671     #include <sys/mman.h>
1672 gbeauche 1.4 #include "vm_alloc.h"
1673 gbeauche 1.1
1674 gbeauche 1.32 const int REF_INDEX = 123;
1675     const int REF_VALUE = 45;
1676    
1677 gbeauche 1.1 static int page_size;
1678 gbeauche 1.3 static volatile char * page = 0;
1679     static volatile int handler_called = 0;
1680 gbeauche 1.1
1681 gbeauche 1.32 #ifdef __GNUC__
1682     // Code range where we expect the fault to come from
1683     static void *b_region, *e_region;
1684     #endif
1685    
1686 gbeauche 1.24 static sigsegv_return_t sigsegv_test_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
1687 gbeauche 1.1 {
1688 gbeauche 1.39 #if DEBUG
1689     printf("sigsegv_test_handler(%p, %p)\n", fault_address, instruction_address);
1690     printf("expected fault at %p\n", page + REF_INDEX);
1691     #ifdef __GNUC__
1692     printf("expected instruction address range: %p-%p\n", b_region, e_region);
1693     #endif
1694     #endif
1695 gbeauche 1.1 handler_called++;
1696 gbeauche 1.32 if ((fault_address - REF_INDEX) != page)
1697 gbeauche 1.29 exit(10);
1698 gbeauche 1.32 #ifdef __GNUC__
1699     // Make sure reported fault instruction address falls into
1700     // expected code range
1701     if (instruction_address != SIGSEGV_INVALID_PC
1702     && ((instruction_address < (sigsegv_address_t)b_region) ||
1703     (instruction_address >= (sigsegv_address_t)e_region)))
1704     exit(11);
1705     #endif
1706 gbeauche 1.4 if (vm_protect((char *)((unsigned long)fault_address & -page_size), page_size, VM_PAGE_READ | VM_PAGE_WRITE) != 0)
1707 gbeauche 1.32 exit(12);
1708 gbeauche 1.24 return SIGSEGV_RETURN_SUCCESS;
1709 gbeauche 1.1 }
1710    
1711 gbeauche 1.10 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1712 gbeauche 1.24 static sigsegv_return_t sigsegv_insn_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
1713 gbeauche 1.10 {
1714 gbeauche 1.28 if (((unsigned long)fault_address - (unsigned long)page) < page_size) {
1715     #ifdef __GNUC__
1716     // Make sure reported fault instruction address falls into
1717     // expected code range
1718     if (instruction_address != SIGSEGV_INVALID_PC
1719     && ((instruction_address < (sigsegv_address_t)b_region) ||
1720     (instruction_address >= (sigsegv_address_t)e_region)))
1721     return SIGSEGV_RETURN_FAILURE;
1722     #endif
1723 gbeauche 1.26 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
1724 gbeauche 1.28 }
1725    
1726 gbeauche 1.24 return SIGSEGV_RETURN_FAILURE;
1727 gbeauche 1.10 }
1728 gbeauche 1.34
1729     // More sophisticated tests for instruction skipper
1730     static bool arch_insn_skipper_tests()
1731     {
1732     #if (defined(i386) || defined(__i386__)) || defined(__x86_64__)
1733     static const unsigned char code[] = {
1734     0x8a, 0x00, // mov (%eax),%al
1735     0x8a, 0x2c, 0x18, // mov (%eax,%ebx,1),%ch
1736     0x88, 0x20, // mov %ah,(%eax)
1737     0x88, 0x08, // mov %cl,(%eax)
1738     0x66, 0x8b, 0x00, // mov (%eax),%ax
1739     0x66, 0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%cx
1740     0x66, 0x89, 0x00, // mov %ax,(%eax)
1741     0x66, 0x89, 0x0c, 0x18, // mov %cx,(%eax,%ebx,1)
1742     0x8b, 0x00, // mov (%eax),%eax
1743     0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%ecx
1744     0x89, 0x00, // mov %eax,(%eax)
1745     0x89, 0x0c, 0x18, // mov %ecx,(%eax,%ebx,1)
1746     #if defined(__x86_64__)
1747     0x44, 0x8a, 0x00, // mov (%rax),%r8b
1748     0x44, 0x8a, 0x20, // mov (%rax),%r12b
1749     0x42, 0x8a, 0x3c, 0x10, // mov (%rax,%r10,1),%dil
1750     0x44, 0x88, 0x00, // mov %r8b,(%rax)
1751     0x44, 0x88, 0x20, // mov %r12b,(%rax)
1752     0x42, 0x88, 0x3c, 0x10, // mov %dil,(%rax,%r10,1)
1753     0x66, 0x44, 0x8b, 0x00, // mov (%rax),%r8w
1754     0x66, 0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%cx
1755     0x66, 0x44, 0x89, 0x00, // mov %r8w,(%rax)
1756     0x66, 0x42, 0x89, 0x0c, 0x10, // mov %cx,(%rax,%r10,1)
1757     0x44, 0x8b, 0x00, // mov (%rax),%r8d
1758     0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%ecx
1759     0x44, 0x89, 0x00, // mov %r8d,(%rax)
1760     0x42, 0x89, 0x0c, 0x10, // mov %ecx,(%rax,%r10,1)
1761     0x48, 0x8b, 0x08, // mov (%rax),%rcx
1762     0x4c, 0x8b, 0x18, // mov (%rax),%r11
1763     0x4a, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%rcx
1764     0x4e, 0x8b, 0x1c, 0x10, // mov (%rax,%r10,1),%r11
1765     0x48, 0x89, 0x08, // mov %rcx,(%rax)
1766     0x4c, 0x89, 0x18, // mov %r11,(%rax)
1767     0x4a, 0x89, 0x0c, 0x10, // mov %rcx,(%rax,%r10,1)
1768     0x4e, 0x89, 0x1c, 0x10, // mov %r11,(%rax,%r10,1)
1769     #endif
1770     0 // end
1771     };
1772     const int N_REGS = 20;
1773     unsigned long regs[N_REGS];
1774     for (int i = 0; i < N_REGS; i++)
1775     regs[i] = i;
1776     const unsigned long start_code = (unsigned long)&code;
1777     regs[X86_REG_EIP] = start_code;
1778     while ((regs[X86_REG_EIP] - start_code) < (sizeof(code) - 1)
1779     && ix86_skip_instruction(regs))
1780     ; /* simply iterate */
1781     return (regs[X86_REG_EIP] - start_code) == (sizeof(code) - 1);
1782     #endif
1783     return true;
1784     }
1785 gbeauche 1.10 #endif
1786    
1787 gbeauche 1.1 int main(void)
1788     {
1789 gbeauche 1.4 if (vm_init() < 0)
1790 gbeauche 1.1 return 1;
1791    
1792     page_size = getpagesize();
1793 gbeauche 1.4 if ((page = (char *)vm_acquire(page_size)) == VM_MAP_FAILED)
1794 gbeauche 1.29 return 2;
1795 gbeauche 1.4
1796 gbeauche 1.32 memset((void *)page, 0, page_size);
1797 gbeauche 1.4 if (vm_protect((char *)page, page_size, VM_PAGE_READ) < 0)
1798 gbeauche 1.29 return 3;
1799 gbeauche 1.1
1800     if (!sigsegv_install_handler(sigsegv_test_handler))
1801 gbeauche 1.29 return 4;
1802 gbeauche 1.1
1803 gbeauche 1.32 #ifdef __GNUC__
1804     b_region = &&L_b_region1;
1805     e_region = &&L_e_region1;
1806     #endif
1807     L_b_region1:
1808     page[REF_INDEX] = REF_VALUE;
1809     if (page[REF_INDEX] != REF_VALUE)
1810     exit(20);
1811     page[REF_INDEX] = REF_VALUE;
1812     L_e_region1:
1813    
1814 gbeauche 1.1 if (handler_called != 1)
1815 gbeauche 1.29 return 5;
1816 gbeauche 1.10
1817     #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1818     if (!sigsegv_install_handler(sigsegv_insn_handler))
1819 gbeauche 1.29 return 6;
1820 gbeauche 1.10
1821 gbeauche 1.17 if (vm_protect((char *)page, page_size, VM_PAGE_READ | VM_PAGE_WRITE) < 0)
1822 gbeauche 1.29 return 7;
1823 gbeauche 1.10
1824     for (int i = 0; i < page_size; i++)
1825     page[i] = (i + 1) % page_size;
1826    
1827     if (vm_protect((char *)page, page_size, VM_PAGE_NOACCESS) < 0)
1828 gbeauche 1.29 return 8;
1829 gbeauche 1.10
1830     #define TEST_SKIP_INSTRUCTION(TYPE) do { \
1831 gbeauche 1.34 const unsigned long TAG = 0x12345678 | \
1832     (sizeof(long) == 8 ? 0x9abcdef0UL << 31 : 0); \
1833 gbeauche 1.10 TYPE data = *((TYPE *)(page + sizeof(TYPE))); \
1834 gbeauche 1.34 volatile unsigned long effect = data + TAG; \
1835 gbeauche 1.10 if (effect != TAG) \
1836 gbeauche 1.29 return 9; \
1837 gbeauche 1.10 } while (0)
1838    
1839 gbeauche 1.28 #ifdef __GNUC__
1840 gbeauche 1.32 b_region = &&L_b_region2;
1841     e_region = &&L_e_region2;
1842 gbeauche 1.28 #endif
1843 gbeauche 1.32 L_b_region2:
1844 gbeauche 1.10 TEST_SKIP_INSTRUCTION(unsigned char);
1845     TEST_SKIP_INSTRUCTION(unsigned short);
1846     TEST_SKIP_INSTRUCTION(unsigned int);
1847 gbeauche 1.34 TEST_SKIP_INSTRUCTION(unsigned long);
1848 gbeauche 1.32 L_e_region2:
1849 gbeauche 1.1
1850 gbeauche 1.34 if (!arch_insn_skipper_tests())
1851     return 20;
1852 gbeauche 1.35 #endif
1853 gbeauche 1.34
1854 gbeauche 1.4 vm_exit();
1855 gbeauche 1.1 return 0;
1856     }
1857     #endif