ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.39
Committed: 2003-12-20T21:50:08Z (20 years, 11 months ago) by gbeauche
Branch: MAIN
Changes since 1.38: +20 -1 lines
Log Message:
Add support for Linux/hppa, FreeBSD/alpha. Misc debugging output.

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