ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.63
Committed: 2006-05-09T06:24:05Z (18 years, 5 months ago) by gbeauche
Branch: MAIN
Changes since 1.62: +8 -2 lines
Log Message:
MacOS X exception handling updates:
- Call user handler for KERN_INVALID_ADDRESS too (SIGBUS)
- Check for VALID_THREAD_STATE_FLAVOR in forward_exception()
- Return KERN_FAILURE if forward_exception() got an unknown behavior code

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 gbeauche 1.52 * Basilisk II (C) 1997-2005 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 gbeauche 1.49 static void powerpc_decode_instruction(instruction_t *instruction, unsigned int nip, unsigned long * gpr)
101 gbeauche 1.14 {
102     // Get opcode and divide into fields
103 gbeauche 1.49 unsigned int opcode = *((unsigned int *)(unsigned long)nip);
104 gbeauche 1.14 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.49 case 58: // ld, ldu, lwa
178     transfer_type = SIGSEGV_TRANSFER_LOAD;
179     transfer_size = SIZE_QUAD;
180     addr_mode = ((opcode & 3) == 1) ? MODE_U : MODE_NORM;
181     imm &= ~3;
182     break;
183     case 62: // std, stdu, stq
184     transfer_type = SIGSEGV_TRANSFER_STORE;
185     transfer_size = SIZE_QUAD;
186     addr_mode = ((opcode & 3) == 1) ? MODE_U : MODE_NORM;
187     imm &= ~3;
188     break;
189 gbeauche 1.14 }
190    
191     // Calculate effective address
192     unsigned int addr = 0;
193     switch (addr_mode) {
194     case MODE_X:
195     case MODE_UX:
196     if (ra == 0)
197     addr = gpr[rb];
198     else
199     addr = gpr[ra] + gpr[rb];
200     break;
201     case MODE_NORM:
202     case MODE_U:
203     if (ra == 0)
204     addr = (signed int)(signed short)imm;
205     else
206     addr = gpr[ra] + (signed int)(signed short)imm;
207     break;
208     default:
209     break;
210     }
211    
212     // Commit decoded instruction
213     instruction->addr = addr;
214     instruction->addr_mode = addr_mode;
215     instruction->transfer_type = transfer_type;
216     instruction->transfer_size = transfer_size;
217     instruction->ra = ra;
218     instruction->rd = rd;
219     }
220     #endif
221    
222    
223     /*
224 gbeauche 1.1 * OS-dependant SIGSEGV signals support section
225     */
226    
227     #if HAVE_SIGINFO_T
228     // Generic extended signal handler
229 gbeauche 1.51 #if defined(__FreeBSD__)
230 cebix 1.8 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
231     #else
232 gbeauche 1.1 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
233 cebix 1.8 #endif
234 gbeauche 1.5 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, siginfo_t *sip, void *scp
235 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 siginfo_t *sip, void *scp
236     #define SIGSEGV_FAULT_HANDLER_ARGS sip, scp
237 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS sip->si_addr
238 gbeauche 1.37 #if (defined(sgi) || defined(__sgi))
239     #include <ucontext.h>
240     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
241     #define SIGSEGV_FAULT_INSTRUCTION (unsigned long)SIGSEGV_CONTEXT_REGS[CTX_EPC]
242 gbeauche 1.38 #if (defined(mips) || defined(__mips))
243     #define SIGSEGV_REGISTER_FILE SIGSEGV_CONTEXT_REGS
244     #define SIGSEGV_SKIP_INSTRUCTION mips_skip_instruction
245     #endif
246 gbeauche 1.37 #endif
247 gbeauche 1.32 #if defined(__sun__)
248     #if (defined(sparc) || defined(__sparc__))
249 gbeauche 1.40 #include <sys/stack.h>
250     #include <sys/regset.h>
251 gbeauche 1.32 #include <sys/ucontext.h>
252     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
253     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[REG_PC]
254 gbeauche 1.40 #define SIGSEGV_SPARC_GWINDOWS (((ucontext_t *)scp)->uc_mcontext.gwins)
255     #define SIGSEGV_SPARC_RWINDOW (struct rwindow *)((char *)SIGSEGV_CONTEXT_REGS[REG_SP] + STACK_BIAS)
256     #define SIGSEGV_REGISTER_FILE ((unsigned long *)SIGSEGV_CONTEXT_REGS), SIGSEGV_SPARC_GWINDOWS, SIGSEGV_SPARC_RWINDOW
257     #define SIGSEGV_SKIP_INSTRUCTION sparc_skip_instruction
258 gbeauche 1.32 #endif
259 gbeauche 1.54 #if defined(__i386__)
260     #include <sys/regset.h>
261     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
262     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[EIP]
263     #define SIGSEGV_REGISTER_FILE (unsigned long *)SIGSEGV_CONTEXT_REGS
264     #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
265     #endif
266 gbeauche 1.32 #endif
267 gbeauche 1.55 #if defined(__FreeBSD__) || defined(__OpenBSD__)
268 gbeauche 1.17 #if (defined(i386) || defined(__i386__))
269     #define SIGSEGV_FAULT_INSTRUCTION (((struct sigcontext *)scp)->sc_eip)
270 gbeauche 1.34 #define SIGSEGV_REGISTER_FILE ((unsigned long *)&(((struct sigcontext *)scp)->sc_edi)) /* EDI is the first GPR (even below EIP) in sigcontext */
271 gbeauche 1.17 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
272 gbeauche 1.19 #endif
273 gbeauche 1.17 #endif
274 gbeauche 1.51 #if defined(__NetBSD__)
275     #if (defined(i386) || defined(__i386__))
276     #include <sys/ucontext.h>
277     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.__gregs)
278     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[_REG_EIP]
279     #define SIGSEGV_REGISTER_FILE (unsigned long *)SIGSEGV_CONTEXT_REGS
280     #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
281     #endif
282 gbeauche 1.53 #if (defined(powerpc) || defined(__powerpc__))
283     #include <sys/ucontext.h>
284     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.__gregs)
285     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[_REG_PC]
286     #define SIGSEGV_REGISTER_FILE (unsigned long *)&SIGSEGV_CONTEXT_REGS[_REG_PC], (unsigned long *)&SIGSEGV_CONTEXT_REGS[_REG_R0]
287     #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
288     #endif
289 gbeauche 1.51 #endif
290 gbeauche 1.5 #if defined(__linux__)
291 gbeauche 1.6 #if (defined(i386) || defined(__i386__))
292     #include <sys/ucontext.h>
293 gbeauche 1.14 #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
294     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[14] /* should use REG_EIP instead */
295 gbeauche 1.34 #define SIGSEGV_REGISTER_FILE (unsigned long *)SIGSEGV_CONTEXT_REGS
296 gbeauche 1.10 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
297 gbeauche 1.6 #endif
298 gbeauche 1.20 #if (defined(x86_64) || defined(__x86_64__))
299     #include <sys/ucontext.h>
300     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
301     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[16] /* should use REG_RIP instead */
302     #define SIGSEGV_REGISTER_FILE (unsigned long *)SIGSEGV_CONTEXT_REGS
303 gbeauche 1.34 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
304 gbeauche 1.20 #endif
305 gbeauche 1.5 #if (defined(ia64) || defined(__ia64__))
306     #define SIGSEGV_FAULT_INSTRUCTION (((struct sigcontext *)scp)->sc_ip & ~0x3ULL) /* slot number is in bits 0 and 1 */
307     #endif
308 gbeauche 1.9 #if (defined(powerpc) || defined(__powerpc__))
309     #include <sys/ucontext.h>
310 gbeauche 1.14 #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.regs)
311     #define SIGSEGV_FAULT_INSTRUCTION (SIGSEGV_CONTEXT_REGS->nip)
312 gbeauche 1.49 #define SIGSEGV_REGISTER_FILE (unsigned long *)&SIGSEGV_CONTEXT_REGS->nip, (unsigned long *)(SIGSEGV_CONTEXT_REGS->gpr)
313 gbeauche 1.13 #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
314 gbeauche 1.9 #endif
315 gbeauche 1.39 #if (defined(hppa) || defined(__hppa__))
316     #undef SIGSEGV_FAULT_ADDRESS
317     #define SIGSEGV_FAULT_ADDRESS sip->si_ptr
318     #endif
319 gbeauche 1.42 #if (defined(arm) || defined(__arm__))
320     #include <asm/ucontext.h> /* use kernel structure, glibc may not be in sync */
321     #define SIGSEGV_CONTEXT_REGS (((struct ucontext *)scp)->uc_mcontext)
322     #define SIGSEGV_FAULT_INSTRUCTION (SIGSEGV_CONTEXT_REGS.arm_pc)
323 gbeauche 1.44 #define SIGSEGV_REGISTER_FILE (&SIGSEGV_CONTEXT_REGS.arm_r0)
324     #define SIGSEGV_SKIP_INSTRUCTION arm_skip_instruction
325 gbeauche 1.42 #endif
326 gbeauche 1.5 #endif
327 gbeauche 1.1 #endif
328    
329     #if HAVE_SIGCONTEXT_SUBTERFUGE
330     // Linux kernels prior to 2.4 ?
331     #if defined(__linux__)
332     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
333     #if (defined(i386) || defined(__i386__))
334     #include <asm/sigcontext.h>
335     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext scs
336 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 struct sigcontext *scp
337     #define SIGSEGV_FAULT_HANDLER_ARGS &scs
338     #define SIGSEGV_FAULT_ADDRESS scp->cr2
339     #define SIGSEGV_FAULT_INSTRUCTION scp->eip
340 gbeauche 1.34 #define SIGSEGV_REGISTER_FILE (unsigned long *)scp
341 gbeauche 1.10 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
342 gbeauche 1.1 #endif
343     #if (defined(sparc) || defined(__sparc__))
344     #include <asm/sigcontext.h>
345 gbeauche 1.5 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp, char *addr
346 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp, addr
347 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS addr
348     #endif
349     #if (defined(powerpc) || defined(__powerpc__))
350     #include <asm/sigcontext.h>
351 gbeauche 1.4 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext *scp
352 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, scp
353 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS scp->regs->dar
354     #define SIGSEGV_FAULT_INSTRUCTION scp->regs->nip
355 gbeauche 1.49 #define SIGSEGV_REGISTER_FILE (unsigned long *)&scp->regs->nip, (unsigned long *)(scp->regs->gpr)
356 gbeauche 1.13 #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
357 gbeauche 1.1 #endif
358 gbeauche 1.4 #if (defined(alpha) || defined(__alpha__))
359     #include <asm/sigcontext.h>
360     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
361 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
362 gbeauche 1.4 #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
363     #define SIGSEGV_FAULT_INSTRUCTION scp->sc_pc
364 gbeauche 1.42 #endif
365     #if (defined(arm) || defined(__arm__))
366     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int r1, int r2, int r3, struct sigcontext sc
367     #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 struct sigcontext *scp
368     #define SIGSEGV_FAULT_HANDLER_ARGS &sc
369     #define SIGSEGV_FAULT_ADDRESS scp->fault_address
370     #define SIGSEGV_FAULT_INSTRUCTION scp->arm_pc
371 gbeauche 1.44 #define SIGSEGV_REGISTER_FILE &scp->arm_r0
372     #define SIGSEGV_SKIP_INSTRUCTION arm_skip_instruction
373 gbeauche 1.4 #endif
374 gbeauche 1.1 #endif
375    
376     // Irix 5 or 6 on MIPS
377 gbeauche 1.37 #if (defined(sgi) || defined(__sgi)) && (defined(SYSTYPE_SVR4) || defined(_SYSTYPE_SVR4))
378 gbeauche 1.11 #include <ucontext.h>
379 gbeauche 1.1 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
380 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
381 gbeauche 1.37 #define SIGSEGV_FAULT_ADDRESS (unsigned long)scp->sc_badvaddr
382     #define SIGSEGV_FAULT_INSTRUCTION (unsigned long)scp->sc_pc
383 gbeauche 1.1 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
384     #endif
385    
386 gbeauche 1.11 // HP-UX
387     #if (defined(hpux) || defined(__hpux__))
388     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
389 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
390 gbeauche 1.11 #define SIGSEGV_FAULT_ADDRESS scp->sc_sl.sl_ss.ss_narrow.ss_cr21
391     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV) FAULT_HANDLER(SIGBUS)
392     #endif
393    
394 gbeauche 1.1 // OSF/1 on Alpha
395     #if defined(__osf__)
396 gbeauche 1.11 #include <ucontext.h>
397 gbeauche 1.1 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
398 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
399 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS scp->sc_traparg_a0
400     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
401     #endif
402    
403     // AIX
404     #if defined(_AIX)
405     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
406 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
407 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS scp->sc_jmpbuf.jmp_context.o_vaddr
408     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
409     #endif
410    
411 gbeauche 1.33 // NetBSD
412     #if defined(__NetBSD__)
413 gbeauche 1.1 #if (defined(m68k) || defined(__m68k__))
414     #include <m68k/frame.h>
415     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
416 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
417 gbeauche 1.14 #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
418 gbeauche 1.1 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
419 gbeauche 1.14
420     // Use decoding scheme from BasiliskII/m68k native
421     static sigsegv_address_t get_fault_address(struct sigcontext *scp)
422     {
423     struct sigstate {
424     int ss_flags;
425     struct frame ss_frame;
426     };
427     struct sigstate *state = (struct sigstate *)scp->sc_ap;
428     char *fault_addr;
429     switch (state->ss_frame.f_format) {
430     case 7: /* 68040 access error */
431     /* "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown */
432     fault_addr = state->ss_frame.f_fmt7.f_fa;
433     break;
434     default:
435     fault_addr = (char *)code;
436     break;
437     }
438     return (sigsegv_address_t)fault_addr;
439     }
440 gbeauche 1.33 #endif
441     #if (defined(alpha) || defined(__alpha__))
442     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
443     #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
444     #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
445     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
446     #endif
447     #if (defined(i386) || defined(__i386__))
448     #error "FIXME: need to decode instruction and compute EA"
449     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
450     #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
451     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
452     #endif
453     #endif
454     #if defined(__FreeBSD__)
455 gbeauche 1.39 #if (defined(i386) || defined(__i386__))
456 gbeauche 1.33 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
457     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp, char *addr
458 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp, addr
459 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS addr
460 gbeauche 1.33 #define SIGSEGV_FAULT_INSTRUCTION scp->sc_eip
461 gbeauche 1.34 #define SIGSEGV_REGISTER_FILE ((unsigned long *)&scp->sc_edi)
462 gbeauche 1.33 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
463 gbeauche 1.1 #endif
464 gbeauche 1.39 #if (defined(alpha) || defined(__alpha__))
465     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
466     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, char *addr, struct sigcontext *scp
467     #define SIGSEGV_FAULT_HANDLER_ARGS sig, addr, scp
468     #define SIGSEGV_FAULT_ADDRESS addr
469     #define SIGSEGV_FAULT_INSTRUCTION scp->sc_pc
470     #endif
471 gbeauche 1.1 #endif
472 gbeauche 1.33
473     // Extract fault address out of a sigcontext
474     #if (defined(alpha) || defined(__alpha__))
475     // From Boehm's GC 6.0alpha8
476     static sigsegv_address_t get_fault_address(struct sigcontext *scp)
477     {
478     unsigned int instruction = *((unsigned int *)(scp->sc_pc));
479     unsigned long fault_address = scp->sc_regs[(instruction >> 16) & 0x1f];
480     fault_address += (signed long)(signed short)(instruction & 0xffff);
481     return (sigsegv_address_t)fault_address;
482     }
483     #endif
484    
485 gbeauche 1.4
486 gbeauche 1.27 // MacOS X, not sure which version this works in. Under 10.1
487     // vm_protect does not appear to work from a signal handler. Under
488     // 10.2 signal handlers get siginfo type arguments but the si_addr
489     // field is the address of the faulting instruction and not the
490     // address that caused the SIGBUS. Maybe this works in 10.0? In any
491     // case with Mach exception handlers there is a way to do what this
492     // was meant to do.
493     #ifndef HAVE_MACH_EXCEPTIONS
494 gbeauche 1.4 #if defined(__APPLE__) && defined(__MACH__)
495     #if (defined(ppc) || defined(__ppc__))
496     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
497 gbeauche 1.27 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
498 gbeauche 1.4 #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
499     #define SIGSEGV_FAULT_INSTRUCTION scp->sc_ir
500     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
501 gbeauche 1.14 #define SIGSEGV_REGISTER_FILE (unsigned int *)&scp->sc_ir, &((unsigned int *) scp->sc_regs)[2]
502     #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
503 gbeauche 1.4
504 gbeauche 1.14 // Use decoding scheme from SheepShaver
505 gbeauche 1.4 static sigsegv_address_t get_fault_address(struct sigcontext *scp)
506     {
507 gbeauche 1.14 unsigned int nip = (unsigned int) scp->sc_ir;
508     unsigned int * gpr = &((unsigned int *) scp->sc_regs)[2];
509     instruction_t instr;
510    
511     powerpc_decode_instruction(&instr, nip, gpr);
512     return (sigsegv_address_t)instr.addr;
513 gbeauche 1.4 }
514     #endif
515     #endif
516 gbeauche 1.1 #endif
517 gbeauche 1.27 #endif
518    
519 gbeauche 1.48 #if HAVE_WIN32_EXCEPTIONS
520     #define WIN32_LEAN_AND_MEAN /* avoid including junk */
521     #include <windows.h>
522     #include <winerror.h>
523    
524     #define SIGSEGV_FAULT_HANDLER_ARGLIST EXCEPTION_POINTERS *ExceptionInfo
525     #define SIGSEGV_FAULT_HANDLER_ARGS ExceptionInfo
526     #define SIGSEGV_FAULT_ADDRESS ExceptionInfo->ExceptionRecord->ExceptionInformation[1]
527     #define SIGSEGV_CONTEXT_REGS ExceptionInfo->ContextRecord
528     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS->Eip
529     #define SIGSEGV_REGISTER_FILE ((unsigned long *)&SIGSEGV_CONTEXT_REGS->Edi)
530     #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
531     #endif
532    
533 gbeauche 1.27 #if HAVE_MACH_EXCEPTIONS
534    
535     // This can easily be extended to other Mach systems, but really who
536     // uses HURD (oops GNU/HURD), Darwin/x86, NextStep, Rhapsody, or CMU
537     // Mach 2.5/3.0?
538     #if defined(__APPLE__) && defined(__MACH__)
539    
540     #include <sys/types.h>
541     #include <stdlib.h>
542     #include <stdio.h>
543     #include <pthread.h>
544    
545     /*
546     * If you are familiar with MIG then you will understand the frustration
547     * that was necessary to get these embedded into C++ code by hand.
548     */
549     extern "C" {
550     #include <mach/mach.h>
551     #include <mach/mach_error.h>
552    
553     extern boolean_t exc_server(mach_msg_header_t *, mach_msg_header_t *);
554     extern kern_return_t catch_exception_raise(mach_port_t, mach_port_t,
555     mach_port_t, exception_type_t, exception_data_t, mach_msg_type_number_t);
556     extern kern_return_t exception_raise(mach_port_t, mach_port_t, mach_port_t,
557     exception_type_t, exception_data_t, mach_msg_type_number_t);
558     extern kern_return_t exception_raise_state(mach_port_t, exception_type_t,
559     exception_data_t, mach_msg_type_number_t, thread_state_flavor_t *,
560     thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t *);
561     extern kern_return_t exception_raise_state_identity(mach_port_t, mach_port_t, mach_port_t,
562     exception_type_t, exception_data_t, mach_msg_type_number_t, thread_state_flavor_t *,
563     thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t *);
564     }
565    
566     // Could make this dynamic by looking for a result of MIG_ARRAY_TOO_LARGE
567     #define HANDLER_COUNT 64
568    
569     // structure to tuck away existing exception handlers
570     typedef struct _ExceptionPorts {
571     mach_msg_type_number_t maskCount;
572     exception_mask_t masks[HANDLER_COUNT];
573     exception_handler_t handlers[HANDLER_COUNT];
574     exception_behavior_t behaviors[HANDLER_COUNT];
575     thread_state_flavor_t flavors[HANDLER_COUNT];
576     } ExceptionPorts;
577    
578     // exception handler thread
579     static pthread_t exc_thread;
580    
581     // place where old exception handler info is stored
582     static ExceptionPorts ports;
583    
584     // our exception port
585     static mach_port_t _exceptionPort = MACH_PORT_NULL;
586    
587     #define MACH_CHECK_ERROR(name,ret) \
588     if (ret != KERN_SUCCESS) { \
589     mach_error(#name, ret); \
590     exit (1); \
591     }
592    
593 gbeauche 1.56 #ifdef __ppc__
594     #define SIGSEGV_THREAD_STATE_TYPE ppc_thread_state_t
595     #define SIGSEGV_THREAD_STATE_FLAVOR PPC_THREAD_STATE
596     #define SIGSEGV_THREAD_STATE_COUNT PPC_THREAD_STATE_COUNT
597     #define SIGSEGV_FAULT_INSTRUCTION state->srr0
598     #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
599     #define SIGSEGV_REGISTER_FILE (unsigned long *)&state->srr0, (unsigned long *)&state->r0
600     #endif
601     #ifdef __i386__
602 gbeauche 1.57 #ifdef i386_SAVED_STATE
603 gbeauche 1.56 #define SIGSEGV_THREAD_STATE_TYPE struct i386_saved_state
604     #define SIGSEGV_THREAD_STATE_FLAVOR i386_SAVED_STATE
605     #define SIGSEGV_THREAD_STATE_COUNT i386_SAVED_STATE_COUNT
606 gbeauche 1.57 #define SIGSEGV_REGISTER_FILE ((unsigned long *)&state->edi) /* EDI is the first GPR we consider */
607     #else
608     #define SIGSEGV_THREAD_STATE_TYPE struct i386_thread_state
609     #define SIGSEGV_THREAD_STATE_FLAVOR i386_THREAD_STATE
610     #define SIGSEGV_THREAD_STATE_COUNT i386_THREAD_STATE_COUNT
611     #define SIGSEGV_REGISTER_FILE ((unsigned long *)&state->eax) /* EAX is the first GPR we consider */
612     #endif
613 gbeauche 1.56 #define SIGSEGV_FAULT_INSTRUCTION state->eip
614     #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
615     #endif
616 gbeauche 1.27 #define SIGSEGV_FAULT_ADDRESS code[1]
617 gbeauche 1.63 #define SIGSEGV_FAULT_HANDLER_INVOKE(ADDR, IP) ((code[0] == KERN_PROTECTION_FAILURE || code[0] == KERN_INVALID_ADDRESS) ? sigsegv_fault_handler(ADDR, IP) : SIGSEGV_RETURN_FAILURE)
618 gbeauche 1.56 #define SIGSEGV_FAULT_HANDLER_ARGLIST mach_port_t thread, exception_data_t code, SIGSEGV_THREAD_STATE_TYPE *state
619 gbeauche 1.27 #define SIGSEGV_FAULT_HANDLER_ARGS thread, code, &state
620    
621     // Since there can only be one exception thread running at any time
622     // this is not a problem.
623     #define MSG_SIZE 512
624     static char msgbuf[MSG_SIZE];
625     static char replybuf[MSG_SIZE];
626    
627     /*
628     * This is the entry point for the exception handler thread. The job
629     * of this thread is to wait for exception messages on the exception
630     * port that was setup beforehand and to pass them on to exc_server.
631     * exc_server is a MIG generated function that is a part of Mach.
632     * Its job is to decide what to do with the exception message. In our
633     * case exc_server calls catch_exception_raise on our behalf. After
634     * exc_server returns, it is our responsibility to send the reply.
635     */
636     static void *
637     handleExceptions(void *priv)
638     {
639     mach_msg_header_t *msg, *reply;
640     kern_return_t krc;
641    
642     msg = (mach_msg_header_t *)msgbuf;
643     reply = (mach_msg_header_t *)replybuf;
644    
645     for (;;) {
646     krc = mach_msg(msg, MACH_RCV_MSG, MSG_SIZE, MSG_SIZE,
647     _exceptionPort, 0, MACH_PORT_NULL);
648     MACH_CHECK_ERROR(mach_msg, krc);
649    
650     if (!exc_server(msg, reply)) {
651     fprintf(stderr, "exc_server hated the message\n");
652     exit(1);
653     }
654    
655     krc = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0,
656     msg->msgh_local_port, 0, MACH_PORT_NULL);
657     if (krc != KERN_SUCCESS) {
658     fprintf(stderr, "Error sending message to original reply port, krc = %d, %s",
659     krc, mach_error_string(krc));
660     exit(1);
661     }
662     }
663     }
664     #endif
665     #endif
666 gbeauche 1.1
667 gbeauche 1.14
668     /*
669     * Instruction skipping
670     */
671    
672 gbeauche 1.10 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
673     // Decode and skip X86 instruction
674 gbeauche 1.34 #if (defined(i386) || defined(__i386__)) || defined(__x86_64__)
675 gbeauche 1.10 #if defined(__linux__)
676     enum {
677 gbeauche 1.34 #if (defined(i386) || defined(__i386__))
678 gbeauche 1.10 X86_REG_EIP = 14,
679     X86_REG_EAX = 11,
680     X86_REG_ECX = 10,
681     X86_REG_EDX = 9,
682     X86_REG_EBX = 8,
683     X86_REG_ESP = 7,
684     X86_REG_EBP = 6,
685     X86_REG_ESI = 5,
686     X86_REG_EDI = 4
687 gbeauche 1.34 #endif
688     #if defined(__x86_64__)
689     X86_REG_R8 = 0,
690     X86_REG_R9 = 1,
691     X86_REG_R10 = 2,
692     X86_REG_R11 = 3,
693     X86_REG_R12 = 4,
694     X86_REG_R13 = 5,
695     X86_REG_R14 = 6,
696     X86_REG_R15 = 7,
697     X86_REG_EDI = 8,
698     X86_REG_ESI = 9,
699     X86_REG_EBP = 10,
700     X86_REG_EBX = 11,
701     X86_REG_EDX = 12,
702     X86_REG_EAX = 13,
703     X86_REG_ECX = 14,
704     X86_REG_ESP = 15,
705     X86_REG_EIP = 16
706     #endif
707 gbeauche 1.10 };
708     #endif
709 gbeauche 1.51 #if defined(__NetBSD__)
710     enum {
711     #if (defined(i386) || defined(__i386__))
712     X86_REG_EIP = _REG_EIP,
713     X86_REG_EAX = _REG_EAX,
714     X86_REG_ECX = _REG_ECX,
715     X86_REG_EDX = _REG_EDX,
716     X86_REG_EBX = _REG_EBX,
717     X86_REG_ESP = _REG_ESP,
718     X86_REG_EBP = _REG_EBP,
719     X86_REG_ESI = _REG_ESI,
720     X86_REG_EDI = _REG_EDI
721     #endif
722     };
723     #endif
724     #if defined(__FreeBSD__)
725 gbeauche 1.17 enum {
726 gbeauche 1.34 #if (defined(i386) || defined(__i386__))
727 gbeauche 1.17 X86_REG_EIP = 10,
728     X86_REG_EAX = 7,
729     X86_REG_ECX = 6,
730     X86_REG_EDX = 5,
731     X86_REG_EBX = 4,
732     X86_REG_ESP = 13,
733     X86_REG_EBP = 2,
734     X86_REG_ESI = 1,
735     X86_REG_EDI = 0
736 gbeauche 1.34 #endif
737 gbeauche 1.17 };
738     #endif
739 gbeauche 1.55 #if defined(__OpenBSD__)
740     enum {
741     #if defined(__i386__)
742     // EDI is the first register we consider
743     #define OREG(REG) offsetof(struct sigcontext, sc_##REG)
744     #define DREG(REG) ((OREG(REG) - OREG(edi)) / 4)
745     X86_REG_EIP = DREG(eip), // 7
746     X86_REG_EAX = DREG(eax), // 6
747     X86_REG_ECX = DREG(ecx), // 5
748     X86_REG_EDX = DREG(edx), // 4
749     X86_REG_EBX = DREG(ebx), // 3
750     X86_REG_ESP = DREG(esp), // 10
751     X86_REG_EBP = DREG(ebp), // 2
752     X86_REG_ESI = DREG(esi), // 1
753     X86_REG_EDI = DREG(edi) // 0
754     #undef DREG
755     #undef OREG
756     #endif
757     };
758     #endif
759 gbeauche 1.54 #if defined(__sun__)
760     // Same as for Linux, need to check for x86-64
761     enum {
762     #if defined(__i386__)
763     X86_REG_EIP = EIP,
764     X86_REG_EAX = EAX,
765     X86_REG_ECX = ECX,
766     X86_REG_EDX = EDX,
767     X86_REG_EBX = EBX,
768     X86_REG_ESP = ESP,
769     X86_REG_EBP = EBP,
770     X86_REG_ESI = ESI,
771     X86_REG_EDI = EDI
772     #endif
773     };
774     #endif
775 gbeauche 1.56 #if defined(__APPLE__) && defined(__MACH__)
776     enum {
777 gbeauche 1.57 #ifdef i386_SAVED_STATE
778     // same as FreeBSD (in Open Darwin 8.0.1)
779 gbeauche 1.56 X86_REG_EIP = 10,
780     X86_REG_EAX = 7,
781     X86_REG_ECX = 6,
782     X86_REG_EDX = 5,
783     X86_REG_EBX = 4,
784     X86_REG_ESP = 13,
785     X86_REG_EBP = 2,
786     X86_REG_ESI = 1,
787     X86_REG_EDI = 0
788 gbeauche 1.57 #else
789     // new layout (MacOS X 10.4.4 for x86)
790     X86_REG_EIP = 10,
791     X86_REG_EAX = 0,
792     X86_REG_ECX = 2,
793     X86_REG_EDX = 4,
794     X86_REG_EBX = 1,
795     X86_REG_ESP = 7,
796     X86_REG_EBP = 6,
797     X86_REG_ESI = 5,
798     X86_REG_EDI = 4
799     #endif
800 gbeauche 1.56 };
801     #endif
802 gbeauche 1.48 #if defined(_WIN32)
803     enum {
804     #if (defined(i386) || defined(__i386__))
805     X86_REG_EIP = 7,
806     X86_REG_EAX = 5,
807     X86_REG_ECX = 4,
808     X86_REG_EDX = 3,
809     X86_REG_EBX = 2,
810     X86_REG_ESP = 10,
811     X86_REG_EBP = 6,
812     X86_REG_ESI = 1,
813     X86_REG_EDI = 0
814     #endif
815     };
816     #endif
817 gbeauche 1.10 // FIXME: this is partly redundant with the instruction decoding phase
818     // to discover transfer type and register number
819     static inline int ix86_step_over_modrm(unsigned char * p)
820     {
821     int mod = (p[0] >> 6) & 3;
822     int rm = p[0] & 7;
823     int offset = 0;
824    
825     // ModR/M Byte
826     switch (mod) {
827     case 0: // [reg]
828     if (rm == 5) return 4; // disp32
829     break;
830     case 1: // disp8[reg]
831     offset = 1;
832     break;
833     case 2: // disp32[reg]
834     offset = 4;
835     break;
836     case 3: // register
837     return 0;
838     }
839    
840     // SIB Byte
841     if (rm == 4) {
842     if (mod == 0 && (p[1] & 7) == 5)
843     offset = 5; // disp32[index]
844     else
845     offset++;
846     }
847    
848     return offset;
849     }
850    
851 gbeauche 1.34 static bool ix86_skip_instruction(unsigned long * regs)
852 gbeauche 1.10 {
853 gbeauche 1.14 unsigned char * eip = (unsigned char *)regs[X86_REG_EIP];
854 gbeauche 1.10
855     if (eip == 0)
856     return false;
857 gbeauche 1.50 #ifdef _WIN32
858     if (IsBadCodePtr((FARPROC)eip))
859     return false;
860     #endif
861 gbeauche 1.10
862 gbeauche 1.22 transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
863 gbeauche 1.14 transfer_size_t transfer_size = SIZE_LONG;
864 gbeauche 1.10
865     int reg = -1;
866     int len = 0;
867 gbeauche 1.34
868     #if DEBUG
869     printf("IP: %p [%02x %02x %02x %02x...]\n",
870     eip, eip[0], eip[1], eip[2], eip[3]);
871     #endif
872    
873 gbeauche 1.10 // Operand size prefix
874     if (*eip == 0x66) {
875     eip++;
876     len++;
877     transfer_size = SIZE_WORD;
878     }
879    
880 gbeauche 1.34 // REX prefix
881     #if defined(__x86_64__)
882     struct rex_t {
883     unsigned char W;
884     unsigned char R;
885     unsigned char X;
886     unsigned char B;
887     };
888     rex_t rex = { 0, 0, 0, 0 };
889     bool has_rex = false;
890     if ((*eip & 0xf0) == 0x40) {
891     has_rex = true;
892     const unsigned char b = *eip;
893     rex.W = b & (1 << 3);
894     rex.R = b & (1 << 2);
895     rex.X = b & (1 << 1);
896     rex.B = b & (1 << 0);
897     #if DEBUG
898     printf("REX: %c,%c,%c,%c\n",
899     rex.W ? 'W' : '_',
900     rex.R ? 'R' : '_',
901     rex.X ? 'X' : '_',
902     rex.B ? 'B' : '_');
903     #endif
904     eip++;
905     len++;
906     if (rex.W)
907     transfer_size = SIZE_QUAD;
908     }
909     #else
910     const bool has_rex = false;
911     #endif
912    
913 gbeauche 1.10 // Decode instruction
914 gbeauche 1.45 int target_size = SIZE_UNKNOWN;
915 gbeauche 1.10 switch (eip[0]) {
916 gbeauche 1.17 case 0x0f:
917 gbeauche 1.45 target_size = transfer_size;
918 gbeauche 1.18 switch (eip[1]) {
919 gbeauche 1.45 case 0xbe: // MOVSX r32, r/m8
920 gbeauche 1.18 case 0xb6: // MOVZX r32, r/m8
921 gbeauche 1.45 transfer_size = SIZE_BYTE;
922     goto do_mov_extend;
923 gbeauche 1.47 case 0xbf: // MOVSX r32, r/m16
924 gbeauche 1.18 case 0xb7: // MOVZX r32, r/m16
925 gbeauche 1.45 transfer_size = SIZE_WORD;
926     goto do_mov_extend;
927     do_mov_extend:
928     switch (eip[2] & 0xc0) {
929     case 0x80:
930     reg = (eip[2] >> 3) & 7;
931     transfer_type = SIGSEGV_TRANSFER_LOAD;
932     break;
933     case 0x40:
934     reg = (eip[2] >> 3) & 7;
935     transfer_type = SIGSEGV_TRANSFER_LOAD;
936     break;
937     case 0x00:
938     reg = (eip[2] >> 3) & 7;
939     transfer_type = SIGSEGV_TRANSFER_LOAD;
940     break;
941     }
942     len += 3 + ix86_step_over_modrm(eip + 2);
943     break;
944 gbeauche 1.17 }
945     break;
946 gbeauche 1.62 #if defined(__x86_64__)
947     case 0x63: // MOVSXD r64, r/m32
948     if (has_rex && rex.W) {
949     transfer_size = SIZE_LONG;
950     target_size = SIZE_QUAD;
951     }
952     else if (transfer_size != SIZE_WORD) {
953     transfer_size = SIZE_LONG;
954     target_size = SIZE_QUAD;
955     }
956     switch (eip[1] & 0xc0) {
957     case 0x80:
958     reg = (eip[1] >> 3) & 7;
959     transfer_type = SIGSEGV_TRANSFER_LOAD;
960     break;
961     case 0x40:
962     reg = (eip[1] >> 3) & 7;
963     transfer_type = SIGSEGV_TRANSFER_LOAD;
964     break;
965     case 0x00:
966     reg = (eip[1] >> 3) & 7;
967     transfer_type = SIGSEGV_TRANSFER_LOAD;
968     break;
969     }
970     len += 2 + ix86_step_over_modrm(eip + 1);
971     break;
972     #endif
973 gbeauche 1.10 case 0x8a: // MOV r8, r/m8
974     transfer_size = SIZE_BYTE;
975     case 0x8b: // MOV r32, r/m32 (or 16-bit operation)
976     switch (eip[1] & 0xc0) {
977     case 0x80:
978     reg = (eip[1] >> 3) & 7;
979 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
980 gbeauche 1.10 break;
981     case 0x40:
982     reg = (eip[1] >> 3) & 7;
983 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
984 gbeauche 1.10 break;
985     case 0x00:
986     reg = (eip[1] >> 3) & 7;
987 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
988 gbeauche 1.10 break;
989     }
990     len += 2 + ix86_step_over_modrm(eip + 1);
991     break;
992     case 0x88: // MOV r/m8, r8
993     transfer_size = SIZE_BYTE;
994     case 0x89: // MOV r/m32, r32 (or 16-bit operation)
995     switch (eip[1] & 0xc0) {
996     case 0x80:
997     reg = (eip[1] >> 3) & 7;
998 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
999 gbeauche 1.10 break;
1000     case 0x40:
1001     reg = (eip[1] >> 3) & 7;
1002 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
1003 gbeauche 1.10 break;
1004     case 0x00:
1005     reg = (eip[1] >> 3) & 7;
1006 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
1007 gbeauche 1.10 break;
1008     }
1009     len += 2 + ix86_step_over_modrm(eip + 1);
1010     break;
1011     }
1012 gbeauche 1.45 if (target_size == SIZE_UNKNOWN)
1013     target_size = transfer_size;
1014 gbeauche 1.10
1015 gbeauche 1.22 if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1016 gbeauche 1.10 // Unknown machine code, let it crash. Then patch the decoder
1017     return false;
1018     }
1019    
1020 gbeauche 1.34 #if defined(__x86_64__)
1021     if (rex.R)
1022     reg += 8;
1023     #endif
1024    
1025 gbeauche 1.22 if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) {
1026 gbeauche 1.34 static const int x86_reg_map[] = {
1027 gbeauche 1.10 X86_REG_EAX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBX,
1028 gbeauche 1.34 X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI,
1029     #if defined(__x86_64__)
1030     X86_REG_R8, X86_REG_R9, X86_REG_R10, X86_REG_R11,
1031     X86_REG_R12, X86_REG_R13, X86_REG_R14, X86_REG_R15,
1032     #endif
1033 gbeauche 1.10 };
1034    
1035 gbeauche 1.34 if (reg < 0 || reg >= (sizeof(x86_reg_map)/sizeof(x86_reg_map[0]) - 1))
1036 gbeauche 1.10 return false;
1037    
1038 gbeauche 1.34 // Set 0 to the relevant register part
1039     // NOTE: this is only valid for MOV alike instructions
1040 gbeauche 1.10 int rloc = x86_reg_map[reg];
1041 gbeauche 1.45 switch (target_size) {
1042 gbeauche 1.10 case SIZE_BYTE:
1043 gbeauche 1.36 if (has_rex || reg < 4)
1044     regs[rloc] = (regs[rloc] & ~0x00ffL);
1045     else {
1046     rloc = x86_reg_map[reg - 4];
1047     regs[rloc] = (regs[rloc] & ~0xff00L);
1048     }
1049 gbeauche 1.10 break;
1050     case SIZE_WORD:
1051 gbeauche 1.34 regs[rloc] = (regs[rloc] & ~0xffffL);
1052 gbeauche 1.10 break;
1053     case SIZE_LONG:
1054 gbeauche 1.34 case SIZE_QUAD: // zero-extension
1055 gbeauche 1.10 regs[rloc] = 0;
1056     break;
1057     }
1058     }
1059    
1060     #if DEBUG
1061 gbeauche 1.15 printf("%08x: %s %s access", regs[X86_REG_EIP],
1062 gbeauche 1.34 transfer_size == SIZE_BYTE ? "byte" :
1063     transfer_size == SIZE_WORD ? "word" :
1064     transfer_size == SIZE_LONG ? "long" :
1065     transfer_size == SIZE_QUAD ? "quad" : "unknown",
1066 gbeauche 1.22 transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
1067 gbeauche 1.10
1068     if (reg != -1) {
1069 gbeauche 1.34 static const char * x86_byte_reg_str_map[] = {
1070     "al", "cl", "dl", "bl",
1071     "spl", "bpl", "sil", "dil",
1072     "r8b", "r9b", "r10b", "r11b",
1073     "r12b", "r13b", "r14b", "r15b",
1074     "ah", "ch", "dh", "bh",
1075     };
1076     static const char * x86_word_reg_str_map[] = {
1077     "ax", "cx", "dx", "bx",
1078     "sp", "bp", "si", "di",
1079     "r8w", "r9w", "r10w", "r11w",
1080     "r12w", "r13w", "r14w", "r15w",
1081     };
1082     static const char *x86_long_reg_str_map[] = {
1083     "eax", "ecx", "edx", "ebx",
1084     "esp", "ebp", "esi", "edi",
1085     "r8d", "r9d", "r10d", "r11d",
1086     "r12d", "r13d", "r14d", "r15d",
1087     };
1088     static const char *x86_quad_reg_str_map[] = {
1089     "rax", "rcx", "rdx", "rbx",
1090     "rsp", "rbp", "rsi", "rdi",
1091     "r8", "r9", "r10", "r11",
1092     "r12", "r13", "r14", "r15",
1093 gbeauche 1.10 };
1094 gbeauche 1.34 const char * reg_str = NULL;
1095 gbeauche 1.46 switch (target_size) {
1096 gbeauche 1.34 case SIZE_BYTE:
1097     reg_str = x86_byte_reg_str_map[(!has_rex && reg >= 4 ? 12 : 0) + reg];
1098     break;
1099     case SIZE_WORD: reg_str = x86_word_reg_str_map[reg]; break;
1100     case SIZE_LONG: reg_str = x86_long_reg_str_map[reg]; break;
1101     case SIZE_QUAD: reg_str = x86_quad_reg_str_map[reg]; break;
1102     }
1103     if (reg_str)
1104     printf(" %s register %%%s",
1105     transfer_type == SIGSEGV_TRANSFER_LOAD ? "to" : "from",
1106     reg_str);
1107 gbeauche 1.10 }
1108     printf(", %d bytes instruction\n", len);
1109     #endif
1110    
1111     regs[X86_REG_EIP] += len;
1112 gbeauche 1.13 return true;
1113     }
1114     #endif
1115 gbeauche 1.14
1116 gbeauche 1.13 // Decode and skip PPC instruction
1117 gbeauche 1.14 #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__))
1118 gbeauche 1.49 static bool powerpc_skip_instruction(unsigned long * nip_p, unsigned long * regs)
1119 gbeauche 1.13 {
1120 gbeauche 1.14 instruction_t instr;
1121     powerpc_decode_instruction(&instr, *nip_p, regs);
1122 gbeauche 1.13
1123 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1124 gbeauche 1.13 // Unknown machine code, let it crash. Then patch the decoder
1125     return false;
1126     }
1127    
1128     #if DEBUG
1129 gbeauche 1.14 printf("%08x: %s %s access", *nip_p,
1130 gbeauche 1.49 instr.transfer_size == SIZE_BYTE ? "byte" :
1131     instr.transfer_size == SIZE_WORD ? "word" :
1132     instr.transfer_size == SIZE_LONG ? "long" : "quad",
1133 gbeauche 1.22 instr.transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
1134 gbeauche 1.14
1135     if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
1136     printf(" r%d (ra = %08x)\n", instr.ra, instr.addr);
1137 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
1138 gbeauche 1.14 printf(" r%d (rd = 0)\n", instr.rd);
1139     #endif
1140    
1141     if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
1142     regs[instr.ra] = instr.addr;
1143 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
1144 gbeauche 1.14 regs[instr.rd] = 0;
1145 gbeauche 1.13
1146 gbeauche 1.14 *nip_p += 4;
1147 gbeauche 1.10 return true;
1148 gbeauche 1.38 }
1149     #endif
1150    
1151     // Decode and skip MIPS instruction
1152     #if (defined(mips) || defined(__mips))
1153     enum {
1154     #if (defined(sgi) || defined(__sgi))
1155     MIPS_REG_EPC = 35,
1156     #endif
1157     };
1158     static bool mips_skip_instruction(greg_t * regs)
1159     {
1160     unsigned int * epc = (unsigned int *)(unsigned long)regs[MIPS_REG_EPC];
1161    
1162     if (epc == 0)
1163     return false;
1164    
1165     #if DEBUG
1166     printf("IP: %p [%08x]\n", epc, epc[0]);
1167     #endif
1168    
1169     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1170     transfer_size_t transfer_size = SIZE_LONG;
1171     int direction = 0;
1172    
1173     const unsigned int opcode = epc[0];
1174     switch (opcode >> 26) {
1175     case 32: // Load Byte
1176     case 36: // Load Byte Unsigned
1177     transfer_type = SIGSEGV_TRANSFER_LOAD;
1178     transfer_size = SIZE_BYTE;
1179     break;
1180     case 33: // Load Halfword
1181     case 37: // Load Halfword Unsigned
1182     transfer_type = SIGSEGV_TRANSFER_LOAD;
1183     transfer_size = SIZE_WORD;
1184     break;
1185     case 35: // Load Word
1186     case 39: // Load Word Unsigned
1187     transfer_type = SIGSEGV_TRANSFER_LOAD;
1188     transfer_size = SIZE_LONG;
1189     break;
1190     case 34: // Load Word Left
1191     transfer_type = SIGSEGV_TRANSFER_LOAD;
1192     transfer_size = SIZE_LONG;
1193     direction = -1;
1194     break;
1195     case 38: // Load Word Right
1196     transfer_type = SIGSEGV_TRANSFER_LOAD;
1197     transfer_size = SIZE_LONG;
1198     direction = 1;
1199     break;
1200     case 55: // Load Doubleword
1201     transfer_type = SIGSEGV_TRANSFER_LOAD;
1202     transfer_size = SIZE_QUAD;
1203     break;
1204     case 26: // Load Doubleword Left
1205     transfer_type = SIGSEGV_TRANSFER_LOAD;
1206     transfer_size = SIZE_QUAD;
1207     direction = -1;
1208     break;
1209     case 27: // Load Doubleword Right
1210     transfer_type = SIGSEGV_TRANSFER_LOAD;
1211     transfer_size = SIZE_QUAD;
1212     direction = 1;
1213     break;
1214     case 40: // Store Byte
1215     transfer_type = SIGSEGV_TRANSFER_STORE;
1216     transfer_size = SIZE_BYTE;
1217     break;
1218     case 41: // Store Halfword
1219     transfer_type = SIGSEGV_TRANSFER_STORE;
1220     transfer_size = SIZE_WORD;
1221     break;
1222     case 43: // Store Word
1223     case 42: // Store Word Left
1224     case 46: // Store Word Right
1225     transfer_type = SIGSEGV_TRANSFER_STORE;
1226     transfer_size = SIZE_LONG;
1227     break;
1228     case 63: // Store Doubleword
1229     case 44: // Store Doubleword Left
1230     case 45: // Store Doubleword Right
1231     transfer_type = SIGSEGV_TRANSFER_STORE;
1232     transfer_size = SIZE_QUAD;
1233     break;
1234     /* Misc instructions unlikely to be used within CPU emulators */
1235     case 48: // Load Linked Word
1236     transfer_type = SIGSEGV_TRANSFER_LOAD;
1237     transfer_size = SIZE_LONG;
1238     break;
1239     case 52: // Load Linked Doubleword
1240     transfer_type = SIGSEGV_TRANSFER_LOAD;
1241     transfer_size = SIZE_QUAD;
1242     break;
1243     case 56: // Store Conditional Word
1244     transfer_type = SIGSEGV_TRANSFER_STORE;
1245     transfer_size = SIZE_LONG;
1246     break;
1247     case 60: // Store Conditional Doubleword
1248     transfer_type = SIGSEGV_TRANSFER_STORE;
1249     transfer_size = SIZE_QUAD;
1250     break;
1251     }
1252    
1253     if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1254     // Unknown machine code, let it crash. Then patch the decoder
1255     return false;
1256     }
1257    
1258     // Zero target register in case of a load operation
1259     const int reg = (opcode >> 16) & 0x1f;
1260     if (transfer_type == SIGSEGV_TRANSFER_LOAD) {
1261     if (direction == 0)
1262     regs[reg] = 0;
1263     else {
1264     // FIXME: untested code
1265     unsigned long ea = regs[(opcode >> 21) & 0x1f];
1266     ea += (signed long)(signed int)(signed short)(opcode & 0xffff);
1267     const int offset = ea & (transfer_size == SIZE_LONG ? 3 : 7);
1268     unsigned long value;
1269     if (direction > 0) {
1270     const unsigned long rmask = ~((1L << ((offset + 1) * 8)) - 1);
1271     value = regs[reg] & rmask;
1272     }
1273     else {
1274     const unsigned long lmask = (1L << (offset * 8)) - 1;
1275     value = regs[reg] & lmask;
1276     }
1277     // restore most significant bits
1278     if (transfer_size == SIZE_LONG)
1279     value = (signed long)(signed int)value;
1280     regs[reg] = value;
1281     }
1282     }
1283    
1284     #if DEBUG
1285     #if (defined(_ABIN32) || defined(_ABI64))
1286     static const char * mips_gpr_names[32] = {
1287     "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
1288     "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
1289     "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
1290     "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
1291     };
1292     #else
1293     static const char * mips_gpr_names[32] = {
1294     "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
1295     "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
1296     "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
1297     "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
1298     };
1299     #endif
1300     printf("%s %s register %s\n",
1301     transfer_size == SIZE_BYTE ? "byte" :
1302     transfer_size == SIZE_WORD ? "word" :
1303     transfer_size == SIZE_LONG ? "long" :
1304     transfer_size == SIZE_QUAD ? "quad" : "unknown",
1305     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1306     mips_gpr_names[reg]);
1307     #endif
1308    
1309     regs[MIPS_REG_EPC] += 4;
1310 gbeauche 1.40 return true;
1311     }
1312     #endif
1313    
1314     // Decode and skip SPARC instruction
1315     #if (defined(sparc) || defined(__sparc__))
1316     enum {
1317     #if (defined(__sun__))
1318     SPARC_REG_G1 = REG_G1,
1319     SPARC_REG_O0 = REG_O0,
1320     SPARC_REG_PC = REG_PC,
1321 gbeauche 1.59 SPARC_REG_nPC = REG_nPC
1322 gbeauche 1.40 #endif
1323     };
1324     static bool sparc_skip_instruction(unsigned long * regs, gwindows_t * gwins, struct rwindow * rwin)
1325     {
1326     unsigned int * pc = (unsigned int *)regs[SPARC_REG_PC];
1327    
1328     if (pc == 0)
1329     return false;
1330    
1331     #if DEBUG
1332     printf("IP: %p [%08x]\n", pc, pc[0]);
1333     #endif
1334    
1335     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1336     transfer_size_t transfer_size = SIZE_LONG;
1337     bool register_pair = false;
1338    
1339     const unsigned int opcode = pc[0];
1340     if ((opcode >> 30) != 3)
1341     return false;
1342     switch ((opcode >> 19) & 0x3f) {
1343     case 9: // Load Signed Byte
1344     case 1: // Load Unsigned Byte
1345     transfer_type = SIGSEGV_TRANSFER_LOAD;
1346     transfer_size = SIZE_BYTE;
1347     break;
1348     case 10:// Load Signed Halfword
1349     case 2: // Load Unsigned Word
1350     transfer_type = SIGSEGV_TRANSFER_LOAD;
1351     transfer_size = SIZE_WORD;
1352     break;
1353     case 8: // Load Word
1354     case 0: // Load Unsigned Word
1355     transfer_type = SIGSEGV_TRANSFER_LOAD;
1356     transfer_size = SIZE_LONG;
1357     break;
1358     case 11:// Load Extended Word
1359     transfer_type = SIGSEGV_TRANSFER_LOAD;
1360     transfer_size = SIZE_QUAD;
1361     break;
1362     case 3: // Load Doubleword
1363     transfer_type = SIGSEGV_TRANSFER_LOAD;
1364     transfer_size = SIZE_LONG;
1365     register_pair = true;
1366     break;
1367     case 5: // Store Byte
1368     transfer_type = SIGSEGV_TRANSFER_STORE;
1369     transfer_size = SIZE_BYTE;
1370     break;
1371     case 6: // Store Halfword
1372     transfer_type = SIGSEGV_TRANSFER_STORE;
1373     transfer_size = SIZE_WORD;
1374     break;
1375     case 4: // Store Word
1376     transfer_type = SIGSEGV_TRANSFER_STORE;
1377     transfer_size = SIZE_LONG;
1378     break;
1379     case 14:// Store Extended Word
1380     transfer_type = SIGSEGV_TRANSFER_STORE;
1381     transfer_size = SIZE_QUAD;
1382     break;
1383     case 7: // Store Doubleword
1384     transfer_type = SIGSEGV_TRANSFER_STORE;
1385 gbeauche 1.58 transfer_size = SIZE_LONG;
1386 gbeauche 1.40 register_pair = true;
1387     break;
1388     }
1389    
1390     if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1391     // Unknown machine code, let it crash. Then patch the decoder
1392     return false;
1393     }
1394    
1395 gbeauche 1.58 const int reg = (opcode >> 25) & 0x1f;
1396    
1397     #if DEBUG
1398     static const char * reg_names[] = {
1399     "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
1400     "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
1401     "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
1402     "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"
1403     };
1404     printf("%s %s register %s\n",
1405     transfer_size == SIZE_BYTE ? "byte" :
1406     transfer_size == SIZE_WORD ? "word" :
1407     transfer_size == SIZE_LONG ? "long" :
1408     transfer_size == SIZE_QUAD ? "quad" : "unknown",
1409     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1410     reg_names[reg]);
1411     #endif
1412    
1413 gbeauche 1.40 // Zero target register in case of a load operation
1414     if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != 0) {
1415     // FIXME: code to handle local & input registers is not tested
1416 gbeauche 1.58 if (reg >= 1 && reg < 8) {
1417 gbeauche 1.40 // global registers
1418     regs[reg - 1 + SPARC_REG_G1] = 0;
1419     }
1420 gbeauche 1.58 else if (reg >= 8 && reg < 16) {
1421 gbeauche 1.40 // output registers
1422     regs[reg - 8 + SPARC_REG_O0] = 0;
1423     }
1424 gbeauche 1.58 else if (reg >= 16 && reg < 24) {
1425 gbeauche 1.40 // local registers (in register windows)
1426     if (gwins)
1427     gwins->wbuf->rw_local[reg - 16] = 0;
1428     else
1429     rwin->rw_local[reg - 16] = 0;
1430     }
1431     else {
1432     // input registers (in register windows)
1433     if (gwins)
1434     gwins->wbuf->rw_in[reg - 24] = 0;
1435     else
1436     rwin->rw_in[reg - 24] = 0;
1437     }
1438     }
1439    
1440     regs[SPARC_REG_PC] += 4;
1441 gbeauche 1.59 regs[SPARC_REG_nPC] += 4;
1442 gbeauche 1.38 return true;
1443 gbeauche 1.10 }
1444     #endif
1445     #endif
1446    
1447 gbeauche 1.44 // Decode and skip ARM instruction
1448     #if (defined(arm) || defined(__arm__))
1449     enum {
1450     #if (defined(__linux__))
1451     ARM_REG_PC = 15,
1452     ARM_REG_CPSR = 16
1453     #endif
1454     };
1455     static bool arm_skip_instruction(unsigned long * regs)
1456     {
1457     unsigned int * pc = (unsigned int *)regs[ARM_REG_PC];
1458    
1459     if (pc == 0)
1460     return false;
1461    
1462     #if DEBUG
1463     printf("IP: %p [%08x]\n", pc, pc[0]);
1464     #endif
1465    
1466     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1467     transfer_size_t transfer_size = SIZE_UNKNOWN;
1468     enum { op_sdt = 1, op_sdth = 2 };
1469     int op = 0;
1470    
1471     // Handle load/store instructions only
1472     const unsigned int opcode = pc[0];
1473     switch ((opcode >> 25) & 7) {
1474     case 0: // Halfword and Signed Data Transfer (LDRH, STRH, LDRSB, LDRSH)
1475     op = op_sdth;
1476     // Determine transfer size (S/H bits)
1477     switch ((opcode >> 5) & 3) {
1478     case 0: // SWP instruction
1479     break;
1480     case 1: // Unsigned halfwords
1481     case 3: // Signed halfwords
1482     transfer_size = SIZE_WORD;
1483     break;
1484     case 2: // Signed byte
1485     transfer_size = SIZE_BYTE;
1486     break;
1487     }
1488     break;
1489     case 2:
1490     case 3: // Single Data Transfer (LDR, STR)
1491     op = op_sdt;
1492     // Determine transfer size (B bit)
1493     if (((opcode >> 22) & 1) == 1)
1494     transfer_size = SIZE_BYTE;
1495     else
1496     transfer_size = SIZE_LONG;
1497     break;
1498     default:
1499     // FIXME: support load/store mutliple?
1500     return false;
1501     }
1502    
1503     // Check for invalid transfer size (SWP instruction?)
1504     if (transfer_size == SIZE_UNKNOWN)
1505     return false;
1506    
1507     // Determine transfer type (L bit)
1508     if (((opcode >> 20) & 1) == 1)
1509     transfer_type = SIGSEGV_TRANSFER_LOAD;
1510     else
1511     transfer_type = SIGSEGV_TRANSFER_STORE;
1512    
1513     // Compute offset
1514     int offset;
1515     if (((opcode >> 25) & 1) == 0) {
1516     if (op == op_sdt)
1517     offset = opcode & 0xfff;
1518     else if (op == op_sdth) {
1519     int rm = opcode & 0xf;
1520     if (((opcode >> 22) & 1) == 0) {
1521     // register offset
1522     offset = regs[rm];
1523     }
1524     else {
1525     // immediate offset
1526     offset = ((opcode >> 4) & 0xf0) | (opcode & 0x0f);
1527     }
1528     }
1529     }
1530     else {
1531     const int rm = opcode & 0xf;
1532     const int sh = (opcode >> 7) & 0x1f;
1533     if (((opcode >> 4) & 1) == 1) {
1534     // we expect only legal load/store instructions
1535     printf("FATAL: invalid shift operand\n");
1536     return false;
1537     }
1538     const unsigned int v = regs[rm];
1539     switch ((opcode >> 5) & 3) {
1540     case 0: // logical shift left
1541     offset = sh ? v << sh : v;
1542     break;
1543     case 1: // logical shift right
1544     offset = sh ? v >> sh : 0;
1545     break;
1546     case 2: // arithmetic shift right
1547     if (sh)
1548     offset = ((signed int)v) >> sh;
1549     else
1550     offset = (v & 0x80000000) ? 0xffffffff : 0;
1551     break;
1552     case 3: // rotate right
1553     if (sh)
1554     offset = (v >> sh) | (v << (32 - sh));
1555     else
1556     offset = (v >> 1) | ((regs[ARM_REG_CPSR] << 2) & 0x80000000);
1557     break;
1558     }
1559     }
1560     if (((opcode >> 23) & 1) == 0)
1561     offset = -offset;
1562    
1563     int rd = (opcode >> 12) & 0xf;
1564     int rn = (opcode >> 16) & 0xf;
1565     #if DEBUG
1566     static const char * reg_names[] = {
1567     "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
1568     "r9", "r9", "sl", "fp", "ip", "sp", "lr", "pc"
1569     };
1570     printf("%s %s register %s\n",
1571     transfer_size == SIZE_BYTE ? "byte" :
1572     transfer_size == SIZE_WORD ? "word" :
1573     transfer_size == SIZE_LONG ? "long" : "unknown",
1574     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1575     reg_names[rd]);
1576     #endif
1577    
1578     unsigned int base = regs[rn];
1579     if (((opcode >> 24) & 1) == 1)
1580     base += offset;
1581    
1582     if (transfer_type == SIGSEGV_TRANSFER_LOAD)
1583     regs[rd] = 0;
1584    
1585     if (((opcode >> 24) & 1) == 0) // post-index addressing
1586     regs[rn] += offset;
1587     else if (((opcode >> 21) & 1) == 1) // write-back address into base
1588     regs[rn] = base;
1589    
1590     regs[ARM_REG_PC] += 4;
1591     return true;
1592     }
1593     #endif
1594    
1595    
1596 gbeauche 1.1 // Fallbacks
1597     #ifndef SIGSEGV_FAULT_INSTRUCTION
1598     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_INVALID_PC
1599     #endif
1600 gbeauche 1.30 #ifndef SIGSEGV_FAULT_HANDLER_ARGLIST_1
1601     #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 SIGSEGV_FAULT_HANDLER_ARGLIST
1602     #endif
1603 gbeauche 1.31 #ifndef SIGSEGV_FAULT_HANDLER_INVOKE
1604     #define SIGSEGV_FAULT_HANDLER_INVOKE(ADDR, IP) sigsegv_fault_handler(ADDR, IP)
1605     #endif
1606 gbeauche 1.1
1607 gbeauche 1.2 // SIGSEGV recovery supported ?
1608     #if defined(SIGSEGV_ALL_SIGNALS) && defined(SIGSEGV_FAULT_HANDLER_ARGLIST) && defined(SIGSEGV_FAULT_ADDRESS)
1609     #define HAVE_SIGSEGV_RECOVERY
1610     #endif
1611    
1612 gbeauche 1.1
1613     /*
1614     * SIGSEGV global handler
1615     */
1616    
1617 gbeauche 1.27 // This function handles the badaccess to memory.
1618     // It is called from the signal handler or the exception handler.
1619 gbeauche 1.30 static bool handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGLIST_1)
1620 gbeauche 1.1 {
1621 gbeauche 1.56 #ifdef HAVE_MACH_EXCEPTIONS
1622     // We must match the initial count when writing back the CPU state registers
1623     kern_return_t krc;
1624     mach_msg_type_number_t count;
1625    
1626     count = SIGSEGV_THREAD_STATE_COUNT;
1627     krc = thread_get_state(thread, SIGSEGV_THREAD_STATE_FLAVOR, (thread_state_t)state, &count);
1628     MACH_CHECK_ERROR (thread_get_state, krc);
1629     #endif
1630    
1631 gbeauche 1.10 sigsegv_address_t fault_address = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
1632     sigsegv_address_t fault_instruction = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
1633    
1634 gbeauche 1.1 // Call user's handler and reinstall the global handler, if required
1635 gbeauche 1.31 switch (SIGSEGV_FAULT_HANDLER_INVOKE(fault_address, fault_instruction)) {
1636 gbeauche 1.24 case SIGSEGV_RETURN_SUCCESS:
1637 gbeauche 1.27 return true;
1638    
1639 gbeauche 1.10 #if HAVE_SIGSEGV_SKIP_INSTRUCTION
1640 gbeauche 1.24 case SIGSEGV_RETURN_SKIP_INSTRUCTION:
1641 gbeauche 1.27 // Call the instruction skipper with the register file
1642     // available
1643     if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE)) {
1644     #ifdef HAVE_MACH_EXCEPTIONS
1645     // Unlike UNIX signals where the thread state
1646     // is modified off of the stack, in Mach we
1647     // need to actually call thread_set_state to
1648     // have the register values updated.
1649     krc = thread_set_state(thread,
1650 gbeauche 1.56 SIGSEGV_THREAD_STATE_FLAVOR, (thread_state_t)state,
1651     count);
1652     MACH_CHECK_ERROR (thread_set_state, krc);
1653 gbeauche 1.27 #endif
1654     return true;
1655     }
1656 gbeauche 1.24 break;
1657     #endif
1658 nigel 1.43 case SIGSEGV_RETURN_FAILURE:
1659 gbeauche 1.50 // We can't do anything with the fault_address, dump state?
1660     if (sigsegv_state_dumper != 0)
1661     sigsegv_state_dumper(fault_address, fault_instruction);
1662     break;
1663 gbeauche 1.10 }
1664 gbeauche 1.27
1665     return false;
1666     }
1667    
1668    
1669     /*
1670     * There are two mechanisms for handling a bad memory access,
1671     * Mach exceptions and UNIX signals. The implementation specific
1672     * code appears below. Its reponsibility is to call handle_badaccess
1673     * which is the routine that handles the fault in an implementation
1674     * agnostic manner. The implementation specific code below is then
1675     * reponsible for checking whether handle_badaccess was able
1676     * to handle the memory access error and perform any implementation
1677     * specific tasks necessary afterwards.
1678     */
1679    
1680     #ifdef HAVE_MACH_EXCEPTIONS
1681     /*
1682     * We need to forward all exceptions that we do not handle.
1683     * This is important, there are many exceptions that may be
1684     * handled by other exception handlers. For example debuggers
1685     * use exceptions and the exception hander is in another
1686     * process in such a case. (Timothy J. Wood states in his
1687     * message to the list that he based this code on that from
1688     * gdb for Darwin.)
1689     */
1690     static inline kern_return_t
1691     forward_exception(mach_port_t thread_port,
1692     mach_port_t task_port,
1693     exception_type_t exception_type,
1694     exception_data_t exception_data,
1695     mach_msg_type_number_t data_count,
1696     ExceptionPorts *oldExceptionPorts)
1697     {
1698     kern_return_t kret;
1699     unsigned int portIndex;
1700     mach_port_t port;
1701     exception_behavior_t behavior;
1702     thread_state_flavor_t flavor;
1703 gbeauche 1.57 thread_state_data_t thread_state;
1704 gbeauche 1.27 mach_msg_type_number_t thread_state_count;
1705    
1706     for (portIndex = 0; portIndex < oldExceptionPorts->maskCount; portIndex++) {
1707     if (oldExceptionPorts->masks[portIndex] & (1 << exception_type)) {
1708     // This handler wants the exception
1709     break;
1710     }
1711     }
1712    
1713     if (portIndex >= oldExceptionPorts->maskCount) {
1714     fprintf(stderr, "No handler for exception_type = %d. Not fowarding\n", exception_type);
1715     return KERN_FAILURE;
1716     }
1717    
1718     port = oldExceptionPorts->handlers[portIndex];
1719     behavior = oldExceptionPorts->behaviors[portIndex];
1720     flavor = oldExceptionPorts->flavors[portIndex];
1721    
1722 gbeauche 1.63 if (!VALID_THREAD_STATE_FLAVOR(flavor)) {
1723     fprintf(stderr, "Invalid thread_state flavor = %d. Not forwarding\n", flavor);
1724     return KERN_FAILURE;
1725     }
1726    
1727 gbeauche 1.27 /*
1728     fprintf(stderr, "forwarding exception, port = 0x%x, behaviour = %d, flavor = %d\n", port, behavior, flavor);
1729     */
1730    
1731     if (behavior != EXCEPTION_DEFAULT) {
1732     thread_state_count = THREAD_STATE_MAX;
1733 gbeauche 1.60 kret = thread_get_state (thread_port, flavor, (natural_t *)&thread_state,
1734 gbeauche 1.27 &thread_state_count);
1735     MACH_CHECK_ERROR (thread_get_state, kret);
1736     }
1737    
1738     switch (behavior) {
1739     case EXCEPTION_DEFAULT:
1740     // fprintf(stderr, "forwarding to exception_raise\n");
1741     kret = exception_raise(port, thread_port, task_port, exception_type,
1742     exception_data, data_count);
1743     MACH_CHECK_ERROR (exception_raise, kret);
1744     break;
1745     case EXCEPTION_STATE:
1746     // fprintf(stderr, "forwarding to exception_raise_state\n");
1747     kret = exception_raise_state(port, exception_type, exception_data,
1748     data_count, &flavor,
1749 gbeauche 1.60 (natural_t *)&thread_state, thread_state_count,
1750     (natural_t *)&thread_state, &thread_state_count);
1751 gbeauche 1.27 MACH_CHECK_ERROR (exception_raise_state, kret);
1752     break;
1753     case EXCEPTION_STATE_IDENTITY:
1754     // fprintf(stderr, "forwarding to exception_raise_state_identity\n");
1755     kret = exception_raise_state_identity(port, thread_port, task_port,
1756     exception_type, exception_data,
1757     data_count, &flavor,
1758 gbeauche 1.60 (natural_t *)&thread_state, thread_state_count,
1759     (natural_t *)&thread_state, &thread_state_count);
1760 gbeauche 1.27 MACH_CHECK_ERROR (exception_raise_state_identity, kret);
1761     break;
1762     default:
1763     fprintf(stderr, "forward_exception got unknown behavior\n");
1764 gbeauche 1.63 kret = KERN_FAILURE;
1765 gbeauche 1.27 break;
1766     }
1767    
1768     if (behavior != EXCEPTION_DEFAULT) {
1769 gbeauche 1.60 kret = thread_set_state (thread_port, flavor, (natural_t *)&thread_state,
1770 gbeauche 1.27 thread_state_count);
1771     MACH_CHECK_ERROR (thread_set_state, kret);
1772     }
1773    
1774 gbeauche 1.63 return kret;
1775 gbeauche 1.27 }
1776    
1777     /*
1778     * This is the code that actually handles the exception.
1779     * It is called by exc_server. For Darwin 5 Apple changed
1780     * this a bit from how this family of functions worked in
1781     * Mach. If you are familiar with that it is a little
1782     * different. The main variation that concerns us here is
1783     * that code is an array of exception specific codes and
1784     * codeCount is a count of the number of codes in the code
1785     * array. In typical Mach all exceptions have a code
1786     * and sub-code. It happens to be the case that for a
1787     * EXC_BAD_ACCESS exception the first entry is the type of
1788     * bad access that occurred and the second entry is the
1789     * faulting address so these entries correspond exactly to
1790     * how the code and sub-code are used on Mach.
1791     *
1792     * This is a MIG interface. No code in Basilisk II should
1793     * call this directley. This has to have external C
1794     * linkage because that is what exc_server expects.
1795     */
1796     kern_return_t
1797     catch_exception_raise(mach_port_t exception_port,
1798     mach_port_t thread,
1799     mach_port_t task,
1800     exception_type_t exception,
1801     exception_data_t code,
1802     mach_msg_type_number_t codeCount)
1803     {
1804 gbeauche 1.56 SIGSEGV_THREAD_STATE_TYPE state;
1805 gbeauche 1.27 kern_return_t krc;
1806    
1807     if ((exception == EXC_BAD_ACCESS) && (codeCount >= 2)) {
1808     if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS))
1809     return KERN_SUCCESS;
1810     }
1811    
1812     // In Mach we do not need to remove the exception handler.
1813     // If we forward the exception, eventually some exception handler
1814     // will take care of this exception.
1815     krc = forward_exception(thread, task, exception, code, codeCount, &ports);
1816    
1817     return krc;
1818     }
1819     #endif
1820    
1821     #ifdef HAVE_SIGSEGV_RECOVERY
1822     // Handle bad memory accesses with signal handler
1823     static void sigsegv_handler(SIGSEGV_FAULT_HANDLER_ARGLIST)
1824     {
1825     // Call handler and reinstall the global handler, if required
1826     if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS)) {
1827     #if (defined(HAVE_SIGACTION) ? defined(SIGACTION_NEED_REINSTALL) : defined(SIGNAL_NEED_REINSTALL))
1828     sigsegv_do_install_handler(sig);
1829     #endif
1830     return;
1831     }
1832 gbeauche 1.10
1833 gbeauche 1.27 // Failure: reinstall default handler for "safe" crash
1834 gbeauche 1.1 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
1835 gbeauche 1.27 SIGSEGV_ALL_SIGNALS
1836 gbeauche 1.1 #undef FAULT_HANDLER
1837     }
1838 gbeauche 1.2 #endif
1839 gbeauche 1.1
1840    
1841     /*
1842     * SIGSEGV handler initialization
1843     */
1844    
1845     #if defined(HAVE_SIGINFO_T)
1846     static bool sigsegv_do_install_handler(int sig)
1847     {
1848     // Setup SIGSEGV handler to process writes to frame buffer
1849     #ifdef HAVE_SIGACTION
1850 gbeauche 1.22 struct sigaction sigsegv_sa;
1851     sigemptyset(&sigsegv_sa.sa_mask);
1852     sigsegv_sa.sa_sigaction = sigsegv_handler;
1853     sigsegv_sa.sa_flags = SA_SIGINFO;
1854     return (sigaction(sig, &sigsegv_sa, 0) == 0);
1855 gbeauche 1.1 #else
1856     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
1857     #endif
1858     }
1859 gbeauche 1.2 #endif
1860    
1861     #if defined(HAVE_SIGCONTEXT_SUBTERFUGE)
1862 gbeauche 1.1 static bool sigsegv_do_install_handler(int sig)
1863     {
1864     // Setup SIGSEGV handler to process writes to frame buffer
1865     #ifdef HAVE_SIGACTION
1866 gbeauche 1.22 struct sigaction sigsegv_sa;
1867     sigemptyset(&sigsegv_sa.sa_mask);
1868     sigsegv_sa.sa_handler = (signal_handler)sigsegv_handler;
1869     sigsegv_sa.sa_flags = 0;
1870 gbeauche 1.1 #if !EMULATED_68K && defined(__NetBSD__)
1871 gbeauche 1.22 sigaddset(&sigsegv_sa.sa_mask, SIGALRM);
1872     sigsegv_sa.sa_flags |= SA_ONSTACK;
1873 gbeauche 1.1 #endif
1874 gbeauche 1.22 return (sigaction(sig, &sigsegv_sa, 0) == 0);
1875 gbeauche 1.1 #else
1876     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
1877     #endif
1878     }
1879     #endif
1880    
1881 gbeauche 1.27 #if defined(HAVE_MACH_EXCEPTIONS)
1882     static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
1883     {
1884     /*
1885     * Except for the exception port functions, this should be
1886     * pretty much stock Mach. If later you choose to support
1887     * other Mach's besides Darwin, just check for __MACH__
1888     * here and __APPLE__ where the actual differences are.
1889     */
1890     #if defined(__APPLE__) && defined(__MACH__)
1891     if (sigsegv_fault_handler != NULL) {
1892     sigsegv_fault_handler = handler;
1893     return true;
1894     }
1895    
1896     kern_return_t krc;
1897    
1898     // create the the exception port
1899     krc = mach_port_allocate(mach_task_self(),
1900     MACH_PORT_RIGHT_RECEIVE, &_exceptionPort);
1901     if (krc != KERN_SUCCESS) {
1902     mach_error("mach_port_allocate", krc);
1903     return false;
1904     }
1905    
1906     // add a port send right
1907     krc = mach_port_insert_right(mach_task_self(),
1908     _exceptionPort, _exceptionPort,
1909     MACH_MSG_TYPE_MAKE_SEND);
1910     if (krc != KERN_SUCCESS) {
1911     mach_error("mach_port_insert_right", krc);
1912     return false;
1913     }
1914    
1915     // get the old exception ports
1916     ports.maskCount = sizeof (ports.masks) / sizeof (ports.masks[0]);
1917     krc = thread_get_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, ports.masks,
1918     &ports.maskCount, ports.handlers, ports.behaviors, ports.flavors);
1919     if (krc != KERN_SUCCESS) {
1920     mach_error("thread_get_exception_ports", krc);
1921     return false;
1922     }
1923    
1924     // set the new exception port
1925     //
1926     // We could have used EXCEPTION_STATE_IDENTITY instead of
1927     // EXCEPTION_DEFAULT to get the thread state in the initial
1928     // message, but it turns out that in the common case this is not
1929     // neccessary. If we need it we can later ask for it from the
1930     // suspended thread.
1931     //
1932     // Even with THREAD_STATE_NONE, Darwin provides the program
1933     // counter in the thread state. The comments in the header file
1934     // seem to imply that you can count on the GPR's on an exception
1935     // as well but just to be safe I use MACHINE_THREAD_STATE because
1936     // you have to ask for all of the GPR's anyway just to get the
1937     // program counter. In any case because of update effective
1938     // address from immediate and update address from effective
1939     // addresses of ra and rb modes (as good an name as any for these
1940     // addressing modes) used in PPC instructions, you will need the
1941     // GPR state anyway.
1942     krc = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, _exceptionPort,
1943 gbeauche 1.56 EXCEPTION_DEFAULT, SIGSEGV_THREAD_STATE_FLAVOR);
1944 gbeauche 1.27 if (krc != KERN_SUCCESS) {
1945     mach_error("thread_set_exception_ports", krc);
1946     return false;
1947     }
1948    
1949     // create the exception handler thread
1950     if (pthread_create(&exc_thread, NULL, &handleExceptions, NULL) != 0) {
1951     (void)fprintf(stderr, "creation of exception thread failed\n");
1952     return false;
1953     }
1954    
1955     // do not care about the exception thread any longer, let is run standalone
1956     (void)pthread_detach(exc_thread);
1957    
1958     sigsegv_fault_handler = handler;
1959     return true;
1960     #else
1961     return false;
1962     #endif
1963     }
1964     #endif
1965    
1966 gbeauche 1.48 #ifdef HAVE_WIN32_EXCEPTIONS
1967     static LONG WINAPI main_exception_filter(EXCEPTION_POINTERS *ExceptionInfo)
1968     {
1969     if (sigsegv_fault_handler != NULL
1970     && ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION
1971     && ExceptionInfo->ExceptionRecord->NumberParameters == 2
1972     && handle_badaccess(ExceptionInfo))
1973     return EXCEPTION_CONTINUE_EXECUTION;
1974    
1975     return EXCEPTION_CONTINUE_SEARCH;
1976     }
1977    
1978     #if defined __CYGWIN__ && defined __i386__
1979     /* In Cygwin programs, SetUnhandledExceptionFilter has no effect because Cygwin
1980     installs a global exception handler. We have to dig deep in order to install
1981     our main_exception_filter. */
1982    
1983     /* Data structures for the current thread's exception handler chain.
1984     On the x86 Windows uses register fs, offset 0 to point to the current
1985     exception handler; Cygwin mucks with it, so we must do the same... :-/ */
1986    
1987     /* Magic taken from winsup/cygwin/include/exceptions.h. */
1988    
1989     struct exception_list {
1990     struct exception_list *prev;
1991     int (*handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
1992     };
1993     typedef struct exception_list exception_list;
1994    
1995     /* Magic taken from winsup/cygwin/exceptions.cc. */
1996    
1997     __asm__ (".equ __except_list,0");
1998    
1999     extern exception_list *_except_list __asm__ ("%fs:__except_list");
2000    
2001     /* For debugging. _except_list is not otherwise accessible from gdb. */
2002     static exception_list *
2003     debug_get_except_list ()
2004     {
2005     return _except_list;
2006     }
2007    
2008     /* Cygwin's original exception handler. */
2009     static int (*cygwin_exception_handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
2010    
2011     /* Our exception handler. */
2012     static int
2013     libsigsegv_exception_handler (EXCEPTION_RECORD *exception, void *frame, CONTEXT *context, void *dispatch)
2014     {
2015     EXCEPTION_POINTERS ExceptionInfo;
2016     ExceptionInfo.ExceptionRecord = exception;
2017     ExceptionInfo.ContextRecord = context;
2018     if (main_exception_filter (&ExceptionInfo) == EXCEPTION_CONTINUE_SEARCH)
2019     return cygwin_exception_handler (exception, frame, context, dispatch);
2020     else
2021     return 0;
2022     }
2023    
2024     static void
2025     do_install_main_exception_filter ()
2026     {
2027     /* We cannot insert any handler into the chain, because such handlers
2028     must lie on the stack (?). Instead, we have to replace(!) Cygwin's
2029     global exception handler. */
2030     cygwin_exception_handler = _except_list->handler;
2031     _except_list->handler = libsigsegv_exception_handler;
2032     }
2033    
2034     #else
2035    
2036     static void
2037     do_install_main_exception_filter ()
2038     {
2039     SetUnhandledExceptionFilter ((LPTOP_LEVEL_EXCEPTION_FILTER) &main_exception_filter);
2040     }
2041     #endif
2042    
2043     static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
2044     {
2045     static bool main_exception_filter_installed = false;
2046     if (!main_exception_filter_installed) {
2047     do_install_main_exception_filter();
2048     main_exception_filter_installed = true;
2049     }
2050     sigsegv_fault_handler = handler;
2051     return true;
2052     }
2053     #endif
2054    
2055 gbeauche 1.12 bool sigsegv_install_handler(sigsegv_fault_handler_t handler)
2056 gbeauche 1.1 {
2057 gbeauche 1.27 #if defined(HAVE_SIGSEGV_RECOVERY)
2058 gbeauche 1.1 bool success = true;
2059     #define FAULT_HANDLER(sig) success = success && sigsegv_do_install_handler(sig);
2060     SIGSEGV_ALL_SIGNALS
2061     #undef FAULT_HANDLER
2062 gbeauche 1.27 if (success)
2063     sigsegv_fault_handler = handler;
2064 gbeauche 1.1 return success;
2065 gbeauche 1.48 #elif defined(HAVE_MACH_EXCEPTIONS) || defined(HAVE_WIN32_EXCEPTIONS)
2066 gbeauche 1.27 return sigsegv_do_install_handler(handler);
2067 gbeauche 1.1 #else
2068     // FAIL: no siginfo_t nor sigcontext subterfuge is available
2069     return false;
2070     #endif
2071     }
2072    
2073    
2074     /*
2075     * SIGSEGV handler deinitialization
2076     */
2077    
2078     void sigsegv_deinstall_handler(void)
2079     {
2080 gbeauche 1.27 // We do nothing for Mach exceptions, the thread would need to be
2081     // suspended if not already so, and we might mess with other
2082     // exception handlers that came after we registered ours. There is
2083     // no need to remove the exception handler, in fact this function is
2084     // not called anywhere in Basilisk II.
2085 gbeauche 1.2 #ifdef HAVE_SIGSEGV_RECOVERY
2086 gbeauche 1.12 sigsegv_fault_handler = 0;
2087 gbeauche 1.1 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
2088     SIGSEGV_ALL_SIGNALS
2089     #undef FAULT_HANDLER
2090 gbeauche 1.2 #endif
2091 gbeauche 1.48 #ifdef HAVE_WIN32_EXCEPTIONS
2092     sigsegv_fault_handler = NULL;
2093     #endif
2094 gbeauche 1.1 }
2095    
2096 gbeauche 1.10
2097     /*
2098     * Set callback function when we cannot handle the fault
2099     */
2100    
2101 gbeauche 1.12 void sigsegv_set_dump_state(sigsegv_state_dumper_t handler)
2102 gbeauche 1.10 {
2103 gbeauche 1.12 sigsegv_state_dumper = handler;
2104 gbeauche 1.10 }
2105    
2106    
2107 gbeauche 1.1 /*
2108     * Test program used for configure/test
2109     */
2110    
2111 gbeauche 1.4 #ifdef CONFIGURE_TEST_SIGSEGV_RECOVERY
2112 gbeauche 1.1 #include <stdio.h>
2113     #include <stdlib.h>
2114     #include <fcntl.h>
2115 gbeauche 1.48 #ifdef HAVE_SYS_MMAN_H
2116 gbeauche 1.1 #include <sys/mman.h>
2117 gbeauche 1.48 #endif
2118 gbeauche 1.4 #include "vm_alloc.h"
2119 gbeauche 1.1
2120 gbeauche 1.32 const int REF_INDEX = 123;
2121     const int REF_VALUE = 45;
2122    
2123 gbeauche 1.1 static int page_size;
2124 gbeauche 1.3 static volatile char * page = 0;
2125     static volatile int handler_called = 0;
2126 gbeauche 1.1
2127 gbeauche 1.61 /* Barriers */
2128     #ifdef __GNUC__
2129     #define BARRIER() asm volatile ("" : : : "memory")
2130     #else
2131     #define BARRIER() /* nothing */
2132     #endif
2133    
2134 gbeauche 1.32 #ifdef __GNUC__
2135     // Code range where we expect the fault to come from
2136     static void *b_region, *e_region;
2137     #endif
2138    
2139 gbeauche 1.24 static sigsegv_return_t sigsegv_test_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
2140 gbeauche 1.1 {
2141 gbeauche 1.39 #if DEBUG
2142     printf("sigsegv_test_handler(%p, %p)\n", fault_address, instruction_address);
2143     printf("expected fault at %p\n", page + REF_INDEX);
2144     #ifdef __GNUC__
2145     printf("expected instruction address range: %p-%p\n", b_region, e_region);
2146     #endif
2147     #endif
2148 gbeauche 1.1 handler_called++;
2149 gbeauche 1.32 if ((fault_address - REF_INDEX) != page)
2150 gbeauche 1.29 exit(10);
2151 gbeauche 1.32 #ifdef __GNUC__
2152     // Make sure reported fault instruction address falls into
2153     // expected code range
2154     if (instruction_address != SIGSEGV_INVALID_PC
2155     && ((instruction_address < (sigsegv_address_t)b_region) ||
2156     (instruction_address >= (sigsegv_address_t)e_region)))
2157     exit(11);
2158     #endif
2159 gbeauche 1.4 if (vm_protect((char *)((unsigned long)fault_address & -page_size), page_size, VM_PAGE_READ | VM_PAGE_WRITE) != 0)
2160 gbeauche 1.32 exit(12);
2161 gbeauche 1.24 return SIGSEGV_RETURN_SUCCESS;
2162 gbeauche 1.1 }
2163    
2164 gbeauche 1.10 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
2165 gbeauche 1.24 static sigsegv_return_t sigsegv_insn_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
2166 gbeauche 1.10 {
2167 gbeauche 1.44 #if DEBUG
2168     printf("sigsegv_insn_handler(%p, %p)\n", fault_address, instruction_address);
2169     #endif
2170 gbeauche 1.28 if (((unsigned long)fault_address - (unsigned long)page) < page_size) {
2171     #ifdef __GNUC__
2172     // Make sure reported fault instruction address falls into
2173     // expected code range
2174     if (instruction_address != SIGSEGV_INVALID_PC
2175     && ((instruction_address < (sigsegv_address_t)b_region) ||
2176     (instruction_address >= (sigsegv_address_t)e_region)))
2177     return SIGSEGV_RETURN_FAILURE;
2178     #endif
2179 gbeauche 1.26 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
2180 gbeauche 1.28 }
2181    
2182 gbeauche 1.24 return SIGSEGV_RETURN_FAILURE;
2183 gbeauche 1.10 }
2184 gbeauche 1.34
2185     // More sophisticated tests for instruction skipper
2186     static bool arch_insn_skipper_tests()
2187     {
2188     #if (defined(i386) || defined(__i386__)) || defined(__x86_64__)
2189     static const unsigned char code[] = {
2190     0x8a, 0x00, // mov (%eax),%al
2191     0x8a, 0x2c, 0x18, // mov (%eax,%ebx,1),%ch
2192     0x88, 0x20, // mov %ah,(%eax)
2193     0x88, 0x08, // mov %cl,(%eax)
2194     0x66, 0x8b, 0x00, // mov (%eax),%ax
2195     0x66, 0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%cx
2196     0x66, 0x89, 0x00, // mov %ax,(%eax)
2197     0x66, 0x89, 0x0c, 0x18, // mov %cx,(%eax,%ebx,1)
2198     0x8b, 0x00, // mov (%eax),%eax
2199     0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%ecx
2200     0x89, 0x00, // mov %eax,(%eax)
2201     0x89, 0x0c, 0x18, // mov %ecx,(%eax,%ebx,1)
2202     #if defined(__x86_64__)
2203     0x44, 0x8a, 0x00, // mov (%rax),%r8b
2204     0x44, 0x8a, 0x20, // mov (%rax),%r12b
2205     0x42, 0x8a, 0x3c, 0x10, // mov (%rax,%r10,1),%dil
2206     0x44, 0x88, 0x00, // mov %r8b,(%rax)
2207     0x44, 0x88, 0x20, // mov %r12b,(%rax)
2208     0x42, 0x88, 0x3c, 0x10, // mov %dil,(%rax,%r10,1)
2209     0x66, 0x44, 0x8b, 0x00, // mov (%rax),%r8w
2210     0x66, 0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%cx
2211     0x66, 0x44, 0x89, 0x00, // mov %r8w,(%rax)
2212     0x66, 0x42, 0x89, 0x0c, 0x10, // mov %cx,(%rax,%r10,1)
2213     0x44, 0x8b, 0x00, // mov (%rax),%r8d
2214     0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%ecx
2215     0x44, 0x89, 0x00, // mov %r8d,(%rax)
2216     0x42, 0x89, 0x0c, 0x10, // mov %ecx,(%rax,%r10,1)
2217     0x48, 0x8b, 0x08, // mov (%rax),%rcx
2218     0x4c, 0x8b, 0x18, // mov (%rax),%r11
2219     0x4a, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%rcx
2220     0x4e, 0x8b, 0x1c, 0x10, // mov (%rax,%r10,1),%r11
2221     0x48, 0x89, 0x08, // mov %rcx,(%rax)
2222     0x4c, 0x89, 0x18, // mov %r11,(%rax)
2223     0x4a, 0x89, 0x0c, 0x10, // mov %rcx,(%rax,%r10,1)
2224     0x4e, 0x89, 0x1c, 0x10, // mov %r11,(%rax,%r10,1)
2225 gbeauche 1.62 0x63, 0x47, 0x04, // movslq 4(%rdi),%eax
2226     0x48, 0x63, 0x47, 0x04, // movslq 4(%rdi),%rax
2227 gbeauche 1.34 #endif
2228     0 // end
2229     };
2230     const int N_REGS = 20;
2231     unsigned long regs[N_REGS];
2232     for (int i = 0; i < N_REGS; i++)
2233     regs[i] = i;
2234     const unsigned long start_code = (unsigned long)&code;
2235     regs[X86_REG_EIP] = start_code;
2236     while ((regs[X86_REG_EIP] - start_code) < (sizeof(code) - 1)
2237     && ix86_skip_instruction(regs))
2238     ; /* simply iterate */
2239     return (regs[X86_REG_EIP] - start_code) == (sizeof(code) - 1);
2240     #endif
2241     return true;
2242     }
2243 gbeauche 1.10 #endif
2244    
2245 gbeauche 1.1 int main(void)
2246     {
2247 gbeauche 1.4 if (vm_init() < 0)
2248 gbeauche 1.1 return 1;
2249    
2250 gbeauche 1.54 page_size = vm_get_page_size();
2251 gbeauche 1.4 if ((page = (char *)vm_acquire(page_size)) == VM_MAP_FAILED)
2252 gbeauche 1.29 return 2;
2253 gbeauche 1.4
2254 gbeauche 1.32 memset((void *)page, 0, page_size);
2255 gbeauche 1.4 if (vm_protect((char *)page, page_size, VM_PAGE_READ) < 0)
2256 gbeauche 1.29 return 3;
2257 gbeauche 1.1
2258     if (!sigsegv_install_handler(sigsegv_test_handler))
2259 gbeauche 1.29 return 4;
2260 gbeauche 1.1
2261 gbeauche 1.32 #ifdef __GNUC__
2262     b_region = &&L_b_region1;
2263     e_region = &&L_e_region1;
2264     #endif
2265     L_b_region1:
2266     page[REF_INDEX] = REF_VALUE;
2267     if (page[REF_INDEX] != REF_VALUE)
2268     exit(20);
2269     page[REF_INDEX] = REF_VALUE;
2270 gbeauche 1.61 BARRIER();
2271 gbeauche 1.32 L_e_region1:
2272    
2273 gbeauche 1.1 if (handler_called != 1)
2274 gbeauche 1.29 return 5;
2275 gbeauche 1.10
2276     #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
2277     if (!sigsegv_install_handler(sigsegv_insn_handler))
2278 gbeauche 1.29 return 6;
2279 gbeauche 1.10
2280 gbeauche 1.17 if (vm_protect((char *)page, page_size, VM_PAGE_READ | VM_PAGE_WRITE) < 0)
2281 gbeauche 1.29 return 7;
2282 gbeauche 1.10
2283     for (int i = 0; i < page_size; i++)
2284     page[i] = (i + 1) % page_size;
2285    
2286     if (vm_protect((char *)page, page_size, VM_PAGE_NOACCESS) < 0)
2287 gbeauche 1.29 return 8;
2288 gbeauche 1.10
2289     #define TEST_SKIP_INSTRUCTION(TYPE) do { \
2290 gbeauche 1.34 const unsigned long TAG = 0x12345678 | \
2291     (sizeof(long) == 8 ? 0x9abcdef0UL << 31 : 0); \
2292 gbeauche 1.10 TYPE data = *((TYPE *)(page + sizeof(TYPE))); \
2293 gbeauche 1.34 volatile unsigned long effect = data + TAG; \
2294 gbeauche 1.10 if (effect != TAG) \
2295 gbeauche 1.29 return 9; \
2296 gbeauche 1.10 } while (0)
2297    
2298 gbeauche 1.28 #ifdef __GNUC__
2299 gbeauche 1.32 b_region = &&L_b_region2;
2300     e_region = &&L_e_region2;
2301 gbeauche 1.28 #endif
2302 gbeauche 1.32 L_b_region2:
2303 gbeauche 1.10 TEST_SKIP_INSTRUCTION(unsigned char);
2304     TEST_SKIP_INSTRUCTION(unsigned short);
2305     TEST_SKIP_INSTRUCTION(unsigned int);
2306 gbeauche 1.34 TEST_SKIP_INSTRUCTION(unsigned long);
2307 gbeauche 1.44 TEST_SKIP_INSTRUCTION(signed char);
2308     TEST_SKIP_INSTRUCTION(signed short);
2309     TEST_SKIP_INSTRUCTION(signed int);
2310     TEST_SKIP_INSTRUCTION(signed long);
2311 gbeauche 1.61 BARRIER();
2312 gbeauche 1.32 L_e_region2:
2313 gbeauche 1.1
2314 gbeauche 1.34 if (!arch_insn_skipper_tests())
2315     return 20;
2316 gbeauche 1.35 #endif
2317 gbeauche 1.34
2318 gbeauche 1.4 vm_exit();
2319 gbeauche 1.1 return 0;
2320     }
2321     #endif