ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.42
Committed: 2004-01-19T16:59:13Z (20 years, 9 months ago) by gbeauche
Branch: MAIN
Changes since 1.41: +12 -0 lines
Log Message:
ARM/linux sigsegv handler. Instruction skipper yet to be written for
happy Zaurus owners.

File Contents

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