ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.41
Committed: 2004-01-12T15:29:25Z (20 years, 8 months ago) by cebix
Branch: MAIN
Changes since 1.40: +1 -1 lines
Log Message:
Happy New Year! :)

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