ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.57
Committed: 2006-01-22T00:05:05Z (18 years, 8 months ago) by gbeauche
Branch: MAIN
Changes since 1.56: +23 -3 lines
Log Message:
Adapt for MacOS X for Intel, also fix thread_state type in forward_exception()

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.31 #define SIGSEGV_FAULT_HANDLER_INVOKE(ADDR, IP) ((code[0] == KERN_PROTECTION_FAILURE) ? 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.10 case 0x8a: // MOV r8, r/m8
947     transfer_size = SIZE_BYTE;
948     case 0x8b: // MOV r32, r/m32 (or 16-bit operation)
949     switch (eip[1] & 0xc0) {
950     case 0x80:
951     reg = (eip[1] >> 3) & 7;
952 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
953 gbeauche 1.10 break;
954     case 0x40:
955     reg = (eip[1] >> 3) & 7;
956 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
957 gbeauche 1.10 break;
958     case 0x00:
959     reg = (eip[1] >> 3) & 7;
960 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
961 gbeauche 1.10 break;
962     }
963     len += 2 + ix86_step_over_modrm(eip + 1);
964     break;
965     case 0x88: // MOV r/m8, r8
966     transfer_size = SIZE_BYTE;
967     case 0x89: // MOV r/m32, r32 (or 16-bit operation)
968     switch (eip[1] & 0xc0) {
969     case 0x80:
970     reg = (eip[1] >> 3) & 7;
971 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
972 gbeauche 1.10 break;
973     case 0x40:
974     reg = (eip[1] >> 3) & 7;
975 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
976 gbeauche 1.10 break;
977     case 0x00:
978     reg = (eip[1] >> 3) & 7;
979 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
980 gbeauche 1.10 break;
981     }
982     len += 2 + ix86_step_over_modrm(eip + 1);
983     break;
984     }
985 gbeauche 1.45 if (target_size == SIZE_UNKNOWN)
986     target_size = transfer_size;
987 gbeauche 1.10
988 gbeauche 1.22 if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
989 gbeauche 1.10 // Unknown machine code, let it crash. Then patch the decoder
990     return false;
991     }
992    
993 gbeauche 1.34 #if defined(__x86_64__)
994     if (rex.R)
995     reg += 8;
996     #endif
997    
998 gbeauche 1.22 if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) {
999 gbeauche 1.34 static const int x86_reg_map[] = {
1000 gbeauche 1.10 X86_REG_EAX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBX,
1001 gbeauche 1.34 X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI,
1002     #if defined(__x86_64__)
1003     X86_REG_R8, X86_REG_R9, X86_REG_R10, X86_REG_R11,
1004     X86_REG_R12, X86_REG_R13, X86_REG_R14, X86_REG_R15,
1005     #endif
1006 gbeauche 1.10 };
1007    
1008 gbeauche 1.34 if (reg < 0 || reg >= (sizeof(x86_reg_map)/sizeof(x86_reg_map[0]) - 1))
1009 gbeauche 1.10 return false;
1010    
1011 gbeauche 1.34 // Set 0 to the relevant register part
1012     // NOTE: this is only valid for MOV alike instructions
1013 gbeauche 1.10 int rloc = x86_reg_map[reg];
1014 gbeauche 1.45 switch (target_size) {
1015 gbeauche 1.10 case SIZE_BYTE:
1016 gbeauche 1.36 if (has_rex || reg < 4)
1017     regs[rloc] = (regs[rloc] & ~0x00ffL);
1018     else {
1019     rloc = x86_reg_map[reg - 4];
1020     regs[rloc] = (regs[rloc] & ~0xff00L);
1021     }
1022 gbeauche 1.10 break;
1023     case SIZE_WORD:
1024 gbeauche 1.34 regs[rloc] = (regs[rloc] & ~0xffffL);
1025 gbeauche 1.10 break;
1026     case SIZE_LONG:
1027 gbeauche 1.34 case SIZE_QUAD: // zero-extension
1028 gbeauche 1.10 regs[rloc] = 0;
1029     break;
1030     }
1031     }
1032    
1033     #if DEBUG
1034 gbeauche 1.15 printf("%08x: %s %s access", regs[X86_REG_EIP],
1035 gbeauche 1.34 transfer_size == SIZE_BYTE ? "byte" :
1036     transfer_size == SIZE_WORD ? "word" :
1037     transfer_size == SIZE_LONG ? "long" :
1038     transfer_size == SIZE_QUAD ? "quad" : "unknown",
1039 gbeauche 1.22 transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
1040 gbeauche 1.10
1041     if (reg != -1) {
1042 gbeauche 1.34 static const char * x86_byte_reg_str_map[] = {
1043     "al", "cl", "dl", "bl",
1044     "spl", "bpl", "sil", "dil",
1045     "r8b", "r9b", "r10b", "r11b",
1046     "r12b", "r13b", "r14b", "r15b",
1047     "ah", "ch", "dh", "bh",
1048     };
1049     static const char * x86_word_reg_str_map[] = {
1050     "ax", "cx", "dx", "bx",
1051     "sp", "bp", "si", "di",
1052     "r8w", "r9w", "r10w", "r11w",
1053     "r12w", "r13w", "r14w", "r15w",
1054     };
1055     static const char *x86_long_reg_str_map[] = {
1056     "eax", "ecx", "edx", "ebx",
1057     "esp", "ebp", "esi", "edi",
1058     "r8d", "r9d", "r10d", "r11d",
1059     "r12d", "r13d", "r14d", "r15d",
1060     };
1061     static const char *x86_quad_reg_str_map[] = {
1062     "rax", "rcx", "rdx", "rbx",
1063     "rsp", "rbp", "rsi", "rdi",
1064     "r8", "r9", "r10", "r11",
1065     "r12", "r13", "r14", "r15",
1066 gbeauche 1.10 };
1067 gbeauche 1.34 const char * reg_str = NULL;
1068 gbeauche 1.46 switch (target_size) {
1069 gbeauche 1.34 case SIZE_BYTE:
1070     reg_str = x86_byte_reg_str_map[(!has_rex && reg >= 4 ? 12 : 0) + reg];
1071     break;
1072     case SIZE_WORD: reg_str = x86_word_reg_str_map[reg]; break;
1073     case SIZE_LONG: reg_str = x86_long_reg_str_map[reg]; break;
1074     case SIZE_QUAD: reg_str = x86_quad_reg_str_map[reg]; break;
1075     }
1076     if (reg_str)
1077     printf(" %s register %%%s",
1078     transfer_type == SIGSEGV_TRANSFER_LOAD ? "to" : "from",
1079     reg_str);
1080 gbeauche 1.10 }
1081     printf(", %d bytes instruction\n", len);
1082     #endif
1083    
1084     regs[X86_REG_EIP] += len;
1085 gbeauche 1.13 return true;
1086     }
1087     #endif
1088 gbeauche 1.14
1089 gbeauche 1.13 // Decode and skip PPC instruction
1090 gbeauche 1.14 #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__))
1091 gbeauche 1.49 static bool powerpc_skip_instruction(unsigned long * nip_p, unsigned long * regs)
1092 gbeauche 1.13 {
1093 gbeauche 1.14 instruction_t instr;
1094     powerpc_decode_instruction(&instr, *nip_p, regs);
1095 gbeauche 1.13
1096 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1097 gbeauche 1.13 // Unknown machine code, let it crash. Then patch the decoder
1098     return false;
1099     }
1100    
1101     #if DEBUG
1102 gbeauche 1.14 printf("%08x: %s %s access", *nip_p,
1103 gbeauche 1.49 instr.transfer_size == SIZE_BYTE ? "byte" :
1104     instr.transfer_size == SIZE_WORD ? "word" :
1105     instr.transfer_size == SIZE_LONG ? "long" : "quad",
1106 gbeauche 1.22 instr.transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
1107 gbeauche 1.14
1108     if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
1109     printf(" r%d (ra = %08x)\n", instr.ra, instr.addr);
1110 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
1111 gbeauche 1.14 printf(" r%d (rd = 0)\n", instr.rd);
1112     #endif
1113    
1114     if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
1115     regs[instr.ra] = instr.addr;
1116 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
1117 gbeauche 1.14 regs[instr.rd] = 0;
1118 gbeauche 1.13
1119 gbeauche 1.14 *nip_p += 4;
1120 gbeauche 1.10 return true;
1121 gbeauche 1.38 }
1122     #endif
1123    
1124     // Decode and skip MIPS instruction
1125     #if (defined(mips) || defined(__mips))
1126     enum {
1127     #if (defined(sgi) || defined(__sgi))
1128     MIPS_REG_EPC = 35,
1129     #endif
1130     };
1131     static bool mips_skip_instruction(greg_t * regs)
1132     {
1133     unsigned int * epc = (unsigned int *)(unsigned long)regs[MIPS_REG_EPC];
1134    
1135     if (epc == 0)
1136     return false;
1137    
1138     #if DEBUG
1139     printf("IP: %p [%08x]\n", epc, epc[0]);
1140     #endif
1141    
1142     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1143     transfer_size_t transfer_size = SIZE_LONG;
1144     int direction = 0;
1145    
1146     const unsigned int opcode = epc[0];
1147     switch (opcode >> 26) {
1148     case 32: // Load Byte
1149     case 36: // Load Byte Unsigned
1150     transfer_type = SIGSEGV_TRANSFER_LOAD;
1151     transfer_size = SIZE_BYTE;
1152     break;
1153     case 33: // Load Halfword
1154     case 37: // Load Halfword Unsigned
1155     transfer_type = SIGSEGV_TRANSFER_LOAD;
1156     transfer_size = SIZE_WORD;
1157     break;
1158     case 35: // Load Word
1159     case 39: // Load Word Unsigned
1160     transfer_type = SIGSEGV_TRANSFER_LOAD;
1161     transfer_size = SIZE_LONG;
1162     break;
1163     case 34: // Load Word Left
1164     transfer_type = SIGSEGV_TRANSFER_LOAD;
1165     transfer_size = SIZE_LONG;
1166     direction = -1;
1167     break;
1168     case 38: // Load Word Right
1169     transfer_type = SIGSEGV_TRANSFER_LOAD;
1170     transfer_size = SIZE_LONG;
1171     direction = 1;
1172     break;
1173     case 55: // Load Doubleword
1174     transfer_type = SIGSEGV_TRANSFER_LOAD;
1175     transfer_size = SIZE_QUAD;
1176     break;
1177     case 26: // Load Doubleword Left
1178     transfer_type = SIGSEGV_TRANSFER_LOAD;
1179     transfer_size = SIZE_QUAD;
1180     direction = -1;
1181     break;
1182     case 27: // Load Doubleword Right
1183     transfer_type = SIGSEGV_TRANSFER_LOAD;
1184     transfer_size = SIZE_QUAD;
1185     direction = 1;
1186     break;
1187     case 40: // Store Byte
1188     transfer_type = SIGSEGV_TRANSFER_STORE;
1189     transfer_size = SIZE_BYTE;
1190     break;
1191     case 41: // Store Halfword
1192     transfer_type = SIGSEGV_TRANSFER_STORE;
1193     transfer_size = SIZE_WORD;
1194     break;
1195     case 43: // Store Word
1196     case 42: // Store Word Left
1197     case 46: // Store Word Right
1198     transfer_type = SIGSEGV_TRANSFER_STORE;
1199     transfer_size = SIZE_LONG;
1200     break;
1201     case 63: // Store Doubleword
1202     case 44: // Store Doubleword Left
1203     case 45: // Store Doubleword Right
1204     transfer_type = SIGSEGV_TRANSFER_STORE;
1205     transfer_size = SIZE_QUAD;
1206     break;
1207     /* Misc instructions unlikely to be used within CPU emulators */
1208     case 48: // Load Linked Word
1209     transfer_type = SIGSEGV_TRANSFER_LOAD;
1210     transfer_size = SIZE_LONG;
1211     break;
1212     case 52: // Load Linked Doubleword
1213     transfer_type = SIGSEGV_TRANSFER_LOAD;
1214     transfer_size = SIZE_QUAD;
1215     break;
1216     case 56: // Store Conditional Word
1217     transfer_type = SIGSEGV_TRANSFER_STORE;
1218     transfer_size = SIZE_LONG;
1219     break;
1220     case 60: // Store Conditional Doubleword
1221     transfer_type = SIGSEGV_TRANSFER_STORE;
1222     transfer_size = SIZE_QUAD;
1223     break;
1224     }
1225    
1226     if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1227     // Unknown machine code, let it crash. Then patch the decoder
1228     return false;
1229     }
1230    
1231     // Zero target register in case of a load operation
1232     const int reg = (opcode >> 16) & 0x1f;
1233     if (transfer_type == SIGSEGV_TRANSFER_LOAD) {
1234     if (direction == 0)
1235     regs[reg] = 0;
1236     else {
1237     // FIXME: untested code
1238     unsigned long ea = regs[(opcode >> 21) & 0x1f];
1239     ea += (signed long)(signed int)(signed short)(opcode & 0xffff);
1240     const int offset = ea & (transfer_size == SIZE_LONG ? 3 : 7);
1241     unsigned long value;
1242     if (direction > 0) {
1243     const unsigned long rmask = ~((1L << ((offset + 1) * 8)) - 1);
1244     value = regs[reg] & rmask;
1245     }
1246     else {
1247     const unsigned long lmask = (1L << (offset * 8)) - 1;
1248     value = regs[reg] & lmask;
1249     }
1250     // restore most significant bits
1251     if (transfer_size == SIZE_LONG)
1252     value = (signed long)(signed int)value;
1253     regs[reg] = value;
1254     }
1255     }
1256    
1257     #if DEBUG
1258     #if (defined(_ABIN32) || defined(_ABI64))
1259     static const char * mips_gpr_names[32] = {
1260     "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
1261     "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
1262     "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
1263     "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
1264     };
1265     #else
1266     static const char * mips_gpr_names[32] = {
1267     "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
1268     "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
1269     "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
1270     "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
1271     };
1272     #endif
1273     printf("%s %s register %s\n",
1274     transfer_size == SIZE_BYTE ? "byte" :
1275     transfer_size == SIZE_WORD ? "word" :
1276     transfer_size == SIZE_LONG ? "long" :
1277     transfer_size == SIZE_QUAD ? "quad" : "unknown",
1278     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1279     mips_gpr_names[reg]);
1280     #endif
1281    
1282     regs[MIPS_REG_EPC] += 4;
1283 gbeauche 1.40 return true;
1284     }
1285     #endif
1286    
1287     // Decode and skip SPARC instruction
1288     #if (defined(sparc) || defined(__sparc__))
1289     enum {
1290     #if (defined(__sun__))
1291     SPARC_REG_G1 = REG_G1,
1292     SPARC_REG_O0 = REG_O0,
1293     SPARC_REG_PC = REG_PC,
1294     #endif
1295     };
1296     static bool sparc_skip_instruction(unsigned long * regs, gwindows_t * gwins, struct rwindow * rwin)
1297     {
1298     unsigned int * pc = (unsigned int *)regs[SPARC_REG_PC];
1299    
1300     if (pc == 0)
1301     return false;
1302    
1303     #if DEBUG
1304     printf("IP: %p [%08x]\n", pc, pc[0]);
1305     #endif
1306    
1307     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1308     transfer_size_t transfer_size = SIZE_LONG;
1309     bool register_pair = false;
1310    
1311     const unsigned int opcode = pc[0];
1312     if ((opcode >> 30) != 3)
1313     return false;
1314     switch ((opcode >> 19) & 0x3f) {
1315     case 9: // Load Signed Byte
1316     case 1: // Load Unsigned Byte
1317     transfer_type = SIGSEGV_TRANSFER_LOAD;
1318     transfer_size = SIZE_BYTE;
1319     break;
1320     case 10:// Load Signed Halfword
1321     case 2: // Load Unsigned Word
1322     transfer_type = SIGSEGV_TRANSFER_LOAD;
1323     transfer_size = SIZE_WORD;
1324     break;
1325     case 8: // Load Word
1326     case 0: // Load Unsigned Word
1327     transfer_type = SIGSEGV_TRANSFER_LOAD;
1328     transfer_size = SIZE_LONG;
1329     break;
1330     case 11:// Load Extended Word
1331     transfer_type = SIGSEGV_TRANSFER_LOAD;
1332     transfer_size = SIZE_QUAD;
1333     break;
1334     case 3: // Load Doubleword
1335     transfer_type = SIGSEGV_TRANSFER_LOAD;
1336     transfer_size = SIZE_LONG;
1337     register_pair = true;
1338     break;
1339     case 5: // Store Byte
1340     transfer_type = SIGSEGV_TRANSFER_STORE;
1341     transfer_size = SIZE_BYTE;
1342     break;
1343     case 6: // Store Halfword
1344     transfer_type = SIGSEGV_TRANSFER_STORE;
1345     transfer_size = SIZE_WORD;
1346     break;
1347     case 4: // Store Word
1348     transfer_type = SIGSEGV_TRANSFER_STORE;
1349     transfer_size = SIZE_LONG;
1350     break;
1351     case 14:// Store Extended Word
1352     transfer_type = SIGSEGV_TRANSFER_STORE;
1353     transfer_size = SIZE_QUAD;
1354     break;
1355     case 7: // Store Doubleword
1356     transfer_type = SIGSEGV_TRANSFER_STORE;
1357     transfer_size = SIZE_WORD;
1358     register_pair = true;
1359     break;
1360     }
1361    
1362     if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1363     // Unknown machine code, let it crash. Then patch the decoder
1364     return false;
1365     }
1366    
1367     // Zero target register in case of a load operation
1368     const int reg = (opcode >> 25) & 0x1f;
1369     if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != 0) {
1370     // FIXME: code to handle local & input registers is not tested
1371     if (reg >= 1 && reg <= 7) {
1372     // global registers
1373     regs[reg - 1 + SPARC_REG_G1] = 0;
1374     }
1375     else if (reg >= 8 && reg <= 15) {
1376     // output registers
1377     regs[reg - 8 + SPARC_REG_O0] = 0;
1378     }
1379     else if (reg >= 16 && reg <= 23) {
1380     // local registers (in register windows)
1381     if (gwins)
1382     gwins->wbuf->rw_local[reg - 16] = 0;
1383     else
1384     rwin->rw_local[reg - 16] = 0;
1385     }
1386     else {
1387     // input registers (in register windows)
1388     if (gwins)
1389     gwins->wbuf->rw_in[reg - 24] = 0;
1390     else
1391     rwin->rw_in[reg - 24] = 0;
1392     }
1393     }
1394    
1395     #if DEBUG
1396     static const char * reg_names[] = {
1397     "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
1398     "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
1399     "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
1400     "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"
1401     };
1402     printf("%s %s register %s\n",
1403     transfer_size == SIZE_BYTE ? "byte" :
1404     transfer_size == SIZE_WORD ? "word" :
1405     transfer_size == SIZE_LONG ? "long" :
1406     transfer_size == SIZE_QUAD ? "quad" : "unknown",
1407     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1408     reg_names[reg]);
1409     #endif
1410    
1411     regs[SPARC_REG_PC] += 4;
1412 gbeauche 1.38 return true;
1413 gbeauche 1.10 }
1414     #endif
1415     #endif
1416    
1417 gbeauche 1.44 // Decode and skip ARM instruction
1418     #if (defined(arm) || defined(__arm__))
1419     enum {
1420     #if (defined(__linux__))
1421     ARM_REG_PC = 15,
1422     ARM_REG_CPSR = 16
1423     #endif
1424     };
1425     static bool arm_skip_instruction(unsigned long * regs)
1426     {
1427     unsigned int * pc = (unsigned int *)regs[ARM_REG_PC];
1428    
1429     if (pc == 0)
1430     return false;
1431    
1432     #if DEBUG
1433     printf("IP: %p [%08x]\n", pc, pc[0]);
1434     #endif
1435    
1436     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1437     transfer_size_t transfer_size = SIZE_UNKNOWN;
1438     enum { op_sdt = 1, op_sdth = 2 };
1439     int op = 0;
1440    
1441     // Handle load/store instructions only
1442     const unsigned int opcode = pc[0];
1443     switch ((opcode >> 25) & 7) {
1444     case 0: // Halfword and Signed Data Transfer (LDRH, STRH, LDRSB, LDRSH)
1445     op = op_sdth;
1446     // Determine transfer size (S/H bits)
1447     switch ((opcode >> 5) & 3) {
1448     case 0: // SWP instruction
1449     break;
1450     case 1: // Unsigned halfwords
1451     case 3: // Signed halfwords
1452     transfer_size = SIZE_WORD;
1453     break;
1454     case 2: // Signed byte
1455     transfer_size = SIZE_BYTE;
1456     break;
1457     }
1458     break;
1459     case 2:
1460     case 3: // Single Data Transfer (LDR, STR)
1461     op = op_sdt;
1462     // Determine transfer size (B bit)
1463     if (((opcode >> 22) & 1) == 1)
1464     transfer_size = SIZE_BYTE;
1465     else
1466     transfer_size = SIZE_LONG;
1467     break;
1468     default:
1469     // FIXME: support load/store mutliple?
1470     return false;
1471     }
1472    
1473     // Check for invalid transfer size (SWP instruction?)
1474     if (transfer_size == SIZE_UNKNOWN)
1475     return false;
1476    
1477     // Determine transfer type (L bit)
1478     if (((opcode >> 20) & 1) == 1)
1479     transfer_type = SIGSEGV_TRANSFER_LOAD;
1480     else
1481     transfer_type = SIGSEGV_TRANSFER_STORE;
1482    
1483     // Compute offset
1484     int offset;
1485     if (((opcode >> 25) & 1) == 0) {
1486     if (op == op_sdt)
1487     offset = opcode & 0xfff;
1488     else if (op == op_sdth) {
1489     int rm = opcode & 0xf;
1490     if (((opcode >> 22) & 1) == 0) {
1491     // register offset
1492     offset = regs[rm];
1493     }
1494     else {
1495     // immediate offset
1496     offset = ((opcode >> 4) & 0xf0) | (opcode & 0x0f);
1497     }
1498     }
1499     }
1500     else {
1501     const int rm = opcode & 0xf;
1502     const int sh = (opcode >> 7) & 0x1f;
1503     if (((opcode >> 4) & 1) == 1) {
1504     // we expect only legal load/store instructions
1505     printf("FATAL: invalid shift operand\n");
1506     return false;
1507     }
1508     const unsigned int v = regs[rm];
1509     switch ((opcode >> 5) & 3) {
1510     case 0: // logical shift left
1511     offset = sh ? v << sh : v;
1512     break;
1513     case 1: // logical shift right
1514     offset = sh ? v >> sh : 0;
1515     break;
1516     case 2: // arithmetic shift right
1517     if (sh)
1518     offset = ((signed int)v) >> sh;
1519     else
1520     offset = (v & 0x80000000) ? 0xffffffff : 0;
1521     break;
1522     case 3: // rotate right
1523     if (sh)
1524     offset = (v >> sh) | (v << (32 - sh));
1525     else
1526     offset = (v >> 1) | ((regs[ARM_REG_CPSR] << 2) & 0x80000000);
1527     break;
1528     }
1529     }
1530     if (((opcode >> 23) & 1) == 0)
1531     offset = -offset;
1532    
1533     int rd = (opcode >> 12) & 0xf;
1534     int rn = (opcode >> 16) & 0xf;
1535     #if DEBUG
1536     static const char * reg_names[] = {
1537     "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
1538     "r9", "r9", "sl", "fp", "ip", "sp", "lr", "pc"
1539     };
1540     printf("%s %s register %s\n",
1541     transfer_size == SIZE_BYTE ? "byte" :
1542     transfer_size == SIZE_WORD ? "word" :
1543     transfer_size == SIZE_LONG ? "long" : "unknown",
1544     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1545     reg_names[rd]);
1546     #endif
1547    
1548     unsigned int base = regs[rn];
1549     if (((opcode >> 24) & 1) == 1)
1550     base += offset;
1551    
1552     if (transfer_type == SIGSEGV_TRANSFER_LOAD)
1553     regs[rd] = 0;
1554    
1555     if (((opcode >> 24) & 1) == 0) // post-index addressing
1556     regs[rn] += offset;
1557     else if (((opcode >> 21) & 1) == 1) // write-back address into base
1558     regs[rn] = base;
1559    
1560     regs[ARM_REG_PC] += 4;
1561     return true;
1562     }
1563     #endif
1564    
1565    
1566 gbeauche 1.1 // Fallbacks
1567     #ifndef SIGSEGV_FAULT_INSTRUCTION
1568     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_INVALID_PC
1569     #endif
1570 gbeauche 1.30 #ifndef SIGSEGV_FAULT_HANDLER_ARGLIST_1
1571     #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 SIGSEGV_FAULT_HANDLER_ARGLIST
1572     #endif
1573 gbeauche 1.31 #ifndef SIGSEGV_FAULT_HANDLER_INVOKE
1574     #define SIGSEGV_FAULT_HANDLER_INVOKE(ADDR, IP) sigsegv_fault_handler(ADDR, IP)
1575     #endif
1576 gbeauche 1.1
1577 gbeauche 1.2 // SIGSEGV recovery supported ?
1578     #if defined(SIGSEGV_ALL_SIGNALS) && defined(SIGSEGV_FAULT_HANDLER_ARGLIST) && defined(SIGSEGV_FAULT_ADDRESS)
1579     #define HAVE_SIGSEGV_RECOVERY
1580     #endif
1581    
1582 gbeauche 1.1
1583     /*
1584     * SIGSEGV global handler
1585     */
1586    
1587 gbeauche 1.27 // This function handles the badaccess to memory.
1588     // It is called from the signal handler or the exception handler.
1589 gbeauche 1.30 static bool handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGLIST_1)
1590 gbeauche 1.1 {
1591 gbeauche 1.56 #ifdef HAVE_MACH_EXCEPTIONS
1592     // We must match the initial count when writing back the CPU state registers
1593     kern_return_t krc;
1594     mach_msg_type_number_t count;
1595    
1596     count = SIGSEGV_THREAD_STATE_COUNT;
1597     krc = thread_get_state(thread, SIGSEGV_THREAD_STATE_FLAVOR, (thread_state_t)state, &count);
1598     MACH_CHECK_ERROR (thread_get_state, krc);
1599     #endif
1600    
1601 gbeauche 1.10 sigsegv_address_t fault_address = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
1602     sigsegv_address_t fault_instruction = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
1603    
1604 gbeauche 1.1 // Call user's handler and reinstall the global handler, if required
1605 gbeauche 1.31 switch (SIGSEGV_FAULT_HANDLER_INVOKE(fault_address, fault_instruction)) {
1606 gbeauche 1.24 case SIGSEGV_RETURN_SUCCESS:
1607 gbeauche 1.27 return true;
1608    
1609 gbeauche 1.10 #if HAVE_SIGSEGV_SKIP_INSTRUCTION
1610 gbeauche 1.24 case SIGSEGV_RETURN_SKIP_INSTRUCTION:
1611 gbeauche 1.27 // Call the instruction skipper with the register file
1612     // available
1613     if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE)) {
1614     #ifdef HAVE_MACH_EXCEPTIONS
1615     // Unlike UNIX signals where the thread state
1616     // is modified off of the stack, in Mach we
1617     // need to actually call thread_set_state to
1618     // have the register values updated.
1619     krc = thread_set_state(thread,
1620 gbeauche 1.56 SIGSEGV_THREAD_STATE_FLAVOR, (thread_state_t)state,
1621     count);
1622     MACH_CHECK_ERROR (thread_set_state, krc);
1623 gbeauche 1.27 #endif
1624     return true;
1625     }
1626 gbeauche 1.24 break;
1627     #endif
1628 nigel 1.43 case SIGSEGV_RETURN_FAILURE:
1629 gbeauche 1.50 // We can't do anything with the fault_address, dump state?
1630     if (sigsegv_state_dumper != 0)
1631     sigsegv_state_dumper(fault_address, fault_instruction);
1632     break;
1633 gbeauche 1.10 }
1634 gbeauche 1.27
1635     return false;
1636     }
1637    
1638    
1639     /*
1640     * There are two mechanisms for handling a bad memory access,
1641     * Mach exceptions and UNIX signals. The implementation specific
1642     * code appears below. Its reponsibility is to call handle_badaccess
1643     * which is the routine that handles the fault in an implementation
1644     * agnostic manner. The implementation specific code below is then
1645     * reponsible for checking whether handle_badaccess was able
1646     * to handle the memory access error and perform any implementation
1647     * specific tasks necessary afterwards.
1648     */
1649    
1650     #ifdef HAVE_MACH_EXCEPTIONS
1651     /*
1652     * We need to forward all exceptions that we do not handle.
1653     * This is important, there are many exceptions that may be
1654     * handled by other exception handlers. For example debuggers
1655     * use exceptions and the exception hander is in another
1656     * process in such a case. (Timothy J. Wood states in his
1657     * message to the list that he based this code on that from
1658     * gdb for Darwin.)
1659     */
1660     static inline kern_return_t
1661     forward_exception(mach_port_t thread_port,
1662     mach_port_t task_port,
1663     exception_type_t exception_type,
1664     exception_data_t exception_data,
1665     mach_msg_type_number_t data_count,
1666     ExceptionPorts *oldExceptionPorts)
1667     {
1668     kern_return_t kret;
1669     unsigned int portIndex;
1670     mach_port_t port;
1671     exception_behavior_t behavior;
1672     thread_state_flavor_t flavor;
1673 gbeauche 1.57 thread_state_data_t thread_state;
1674 gbeauche 1.27 mach_msg_type_number_t thread_state_count;
1675    
1676     for (portIndex = 0; portIndex < oldExceptionPorts->maskCount; portIndex++) {
1677     if (oldExceptionPorts->masks[portIndex] & (1 << exception_type)) {
1678     // This handler wants the exception
1679     break;
1680     }
1681     }
1682    
1683     if (portIndex >= oldExceptionPorts->maskCount) {
1684     fprintf(stderr, "No handler for exception_type = %d. Not fowarding\n", exception_type);
1685     return KERN_FAILURE;
1686     }
1687    
1688     port = oldExceptionPorts->handlers[portIndex];
1689     behavior = oldExceptionPorts->behaviors[portIndex];
1690     flavor = oldExceptionPorts->flavors[portIndex];
1691    
1692     /*
1693     fprintf(stderr, "forwarding exception, port = 0x%x, behaviour = %d, flavor = %d\n", port, behavior, flavor);
1694     */
1695    
1696     if (behavior != EXCEPTION_DEFAULT) {
1697     thread_state_count = THREAD_STATE_MAX;
1698     kret = thread_get_state (thread_port, flavor, thread_state,
1699     &thread_state_count);
1700     MACH_CHECK_ERROR (thread_get_state, kret);
1701     }
1702    
1703     switch (behavior) {
1704     case EXCEPTION_DEFAULT:
1705     // fprintf(stderr, "forwarding to exception_raise\n");
1706     kret = exception_raise(port, thread_port, task_port, exception_type,
1707     exception_data, data_count);
1708     MACH_CHECK_ERROR (exception_raise, kret);
1709     break;
1710     case EXCEPTION_STATE:
1711     // fprintf(stderr, "forwarding to exception_raise_state\n");
1712     kret = exception_raise_state(port, exception_type, exception_data,
1713     data_count, &flavor,
1714     thread_state, thread_state_count,
1715     thread_state, &thread_state_count);
1716     MACH_CHECK_ERROR (exception_raise_state, kret);
1717     break;
1718     case EXCEPTION_STATE_IDENTITY:
1719     // fprintf(stderr, "forwarding to exception_raise_state_identity\n");
1720     kret = exception_raise_state_identity(port, thread_port, task_port,
1721     exception_type, exception_data,
1722     data_count, &flavor,
1723     thread_state, thread_state_count,
1724     thread_state, &thread_state_count);
1725     MACH_CHECK_ERROR (exception_raise_state_identity, kret);
1726     break;
1727     default:
1728     fprintf(stderr, "forward_exception got unknown behavior\n");
1729     break;
1730     }
1731    
1732     if (behavior != EXCEPTION_DEFAULT) {
1733     kret = thread_set_state (thread_port, flavor, thread_state,
1734     thread_state_count);
1735     MACH_CHECK_ERROR (thread_set_state, kret);
1736     }
1737    
1738     return KERN_SUCCESS;
1739     }
1740    
1741     /*
1742     * This is the code that actually handles the exception.
1743     * It is called by exc_server. For Darwin 5 Apple changed
1744     * this a bit from how this family of functions worked in
1745     * Mach. If you are familiar with that it is a little
1746     * different. The main variation that concerns us here is
1747     * that code is an array of exception specific codes and
1748     * codeCount is a count of the number of codes in the code
1749     * array. In typical Mach all exceptions have a code
1750     * and sub-code. It happens to be the case that for a
1751     * EXC_BAD_ACCESS exception the first entry is the type of
1752     * bad access that occurred and the second entry is the
1753     * faulting address so these entries correspond exactly to
1754     * how the code and sub-code are used on Mach.
1755     *
1756     * This is a MIG interface. No code in Basilisk II should
1757     * call this directley. This has to have external C
1758     * linkage because that is what exc_server expects.
1759     */
1760     kern_return_t
1761     catch_exception_raise(mach_port_t exception_port,
1762     mach_port_t thread,
1763     mach_port_t task,
1764     exception_type_t exception,
1765     exception_data_t code,
1766     mach_msg_type_number_t codeCount)
1767     {
1768 gbeauche 1.56 SIGSEGV_THREAD_STATE_TYPE state;
1769 gbeauche 1.27 kern_return_t krc;
1770    
1771     if ((exception == EXC_BAD_ACCESS) && (codeCount >= 2)) {
1772     if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS))
1773     return KERN_SUCCESS;
1774     }
1775    
1776     // In Mach we do not need to remove the exception handler.
1777     // If we forward the exception, eventually some exception handler
1778     // will take care of this exception.
1779     krc = forward_exception(thread, task, exception, code, codeCount, &ports);
1780    
1781     return krc;
1782     }
1783     #endif
1784    
1785     #ifdef HAVE_SIGSEGV_RECOVERY
1786     // Handle bad memory accesses with signal handler
1787     static void sigsegv_handler(SIGSEGV_FAULT_HANDLER_ARGLIST)
1788     {
1789     // Call handler and reinstall the global handler, if required
1790     if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS)) {
1791     #if (defined(HAVE_SIGACTION) ? defined(SIGACTION_NEED_REINSTALL) : defined(SIGNAL_NEED_REINSTALL))
1792     sigsegv_do_install_handler(sig);
1793     #endif
1794     return;
1795     }
1796 gbeauche 1.10
1797 gbeauche 1.27 // Failure: reinstall default handler for "safe" crash
1798 gbeauche 1.1 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
1799 gbeauche 1.27 SIGSEGV_ALL_SIGNALS
1800 gbeauche 1.1 #undef FAULT_HANDLER
1801     }
1802 gbeauche 1.2 #endif
1803 gbeauche 1.1
1804    
1805     /*
1806     * SIGSEGV handler initialization
1807     */
1808    
1809     #if defined(HAVE_SIGINFO_T)
1810     static bool sigsegv_do_install_handler(int sig)
1811     {
1812     // Setup SIGSEGV handler to process writes to frame buffer
1813     #ifdef HAVE_SIGACTION
1814 gbeauche 1.22 struct sigaction sigsegv_sa;
1815     sigemptyset(&sigsegv_sa.sa_mask);
1816     sigsegv_sa.sa_sigaction = sigsegv_handler;
1817     sigsegv_sa.sa_flags = SA_SIGINFO;
1818     return (sigaction(sig, &sigsegv_sa, 0) == 0);
1819 gbeauche 1.1 #else
1820     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
1821     #endif
1822     }
1823 gbeauche 1.2 #endif
1824    
1825     #if defined(HAVE_SIGCONTEXT_SUBTERFUGE)
1826 gbeauche 1.1 static bool sigsegv_do_install_handler(int sig)
1827     {
1828     // Setup SIGSEGV handler to process writes to frame buffer
1829     #ifdef HAVE_SIGACTION
1830 gbeauche 1.22 struct sigaction sigsegv_sa;
1831     sigemptyset(&sigsegv_sa.sa_mask);
1832     sigsegv_sa.sa_handler = (signal_handler)sigsegv_handler;
1833     sigsegv_sa.sa_flags = 0;
1834 gbeauche 1.1 #if !EMULATED_68K && defined(__NetBSD__)
1835 gbeauche 1.22 sigaddset(&sigsegv_sa.sa_mask, SIGALRM);
1836     sigsegv_sa.sa_flags |= SA_ONSTACK;
1837 gbeauche 1.1 #endif
1838 gbeauche 1.22 return (sigaction(sig, &sigsegv_sa, 0) == 0);
1839 gbeauche 1.1 #else
1840     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
1841     #endif
1842     }
1843     #endif
1844    
1845 gbeauche 1.27 #if defined(HAVE_MACH_EXCEPTIONS)
1846     static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
1847     {
1848     /*
1849     * Except for the exception port functions, this should be
1850     * pretty much stock Mach. If later you choose to support
1851     * other Mach's besides Darwin, just check for __MACH__
1852     * here and __APPLE__ where the actual differences are.
1853     */
1854     #if defined(__APPLE__) && defined(__MACH__)
1855     if (sigsegv_fault_handler != NULL) {
1856     sigsegv_fault_handler = handler;
1857     return true;
1858     }
1859    
1860     kern_return_t krc;
1861    
1862     // create the the exception port
1863     krc = mach_port_allocate(mach_task_self(),
1864     MACH_PORT_RIGHT_RECEIVE, &_exceptionPort);
1865     if (krc != KERN_SUCCESS) {
1866     mach_error("mach_port_allocate", krc);
1867     return false;
1868     }
1869    
1870     // add a port send right
1871     krc = mach_port_insert_right(mach_task_self(),
1872     _exceptionPort, _exceptionPort,
1873     MACH_MSG_TYPE_MAKE_SEND);
1874     if (krc != KERN_SUCCESS) {
1875     mach_error("mach_port_insert_right", krc);
1876     return false;
1877     }
1878    
1879     // get the old exception ports
1880     ports.maskCount = sizeof (ports.masks) / sizeof (ports.masks[0]);
1881     krc = thread_get_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, ports.masks,
1882     &ports.maskCount, ports.handlers, ports.behaviors, ports.flavors);
1883     if (krc != KERN_SUCCESS) {
1884     mach_error("thread_get_exception_ports", krc);
1885     return false;
1886     }
1887    
1888     // set the new exception port
1889     //
1890     // We could have used EXCEPTION_STATE_IDENTITY instead of
1891     // EXCEPTION_DEFAULT to get the thread state in the initial
1892     // message, but it turns out that in the common case this is not
1893     // neccessary. If we need it we can later ask for it from the
1894     // suspended thread.
1895     //
1896     // Even with THREAD_STATE_NONE, Darwin provides the program
1897     // counter in the thread state. The comments in the header file
1898     // seem to imply that you can count on the GPR's on an exception
1899     // as well but just to be safe I use MACHINE_THREAD_STATE because
1900     // you have to ask for all of the GPR's anyway just to get the
1901     // program counter. In any case because of update effective
1902     // address from immediate and update address from effective
1903     // addresses of ra and rb modes (as good an name as any for these
1904     // addressing modes) used in PPC instructions, you will need the
1905     // GPR state anyway.
1906     krc = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, _exceptionPort,
1907 gbeauche 1.56 EXCEPTION_DEFAULT, SIGSEGV_THREAD_STATE_FLAVOR);
1908 gbeauche 1.27 if (krc != KERN_SUCCESS) {
1909     mach_error("thread_set_exception_ports", krc);
1910     return false;
1911     }
1912    
1913     // create the exception handler thread
1914     if (pthread_create(&exc_thread, NULL, &handleExceptions, NULL) != 0) {
1915     (void)fprintf(stderr, "creation of exception thread failed\n");
1916     return false;
1917     }
1918    
1919     // do not care about the exception thread any longer, let is run standalone
1920     (void)pthread_detach(exc_thread);
1921    
1922     sigsegv_fault_handler = handler;
1923     return true;
1924     #else
1925     return false;
1926     #endif
1927     }
1928     #endif
1929    
1930 gbeauche 1.48 #ifdef HAVE_WIN32_EXCEPTIONS
1931     static LONG WINAPI main_exception_filter(EXCEPTION_POINTERS *ExceptionInfo)
1932     {
1933     if (sigsegv_fault_handler != NULL
1934     && ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION
1935     && ExceptionInfo->ExceptionRecord->NumberParameters == 2
1936     && handle_badaccess(ExceptionInfo))
1937     return EXCEPTION_CONTINUE_EXECUTION;
1938    
1939     return EXCEPTION_CONTINUE_SEARCH;
1940     }
1941    
1942     #if defined __CYGWIN__ && defined __i386__
1943     /* In Cygwin programs, SetUnhandledExceptionFilter has no effect because Cygwin
1944     installs a global exception handler. We have to dig deep in order to install
1945     our main_exception_filter. */
1946    
1947     /* Data structures for the current thread's exception handler chain.
1948     On the x86 Windows uses register fs, offset 0 to point to the current
1949     exception handler; Cygwin mucks with it, so we must do the same... :-/ */
1950    
1951     /* Magic taken from winsup/cygwin/include/exceptions.h. */
1952    
1953     struct exception_list {
1954     struct exception_list *prev;
1955     int (*handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
1956     };
1957     typedef struct exception_list exception_list;
1958    
1959     /* Magic taken from winsup/cygwin/exceptions.cc. */
1960    
1961     __asm__ (".equ __except_list,0");
1962    
1963     extern exception_list *_except_list __asm__ ("%fs:__except_list");
1964    
1965     /* For debugging. _except_list is not otherwise accessible from gdb. */
1966     static exception_list *
1967     debug_get_except_list ()
1968     {
1969     return _except_list;
1970     }
1971    
1972     /* Cygwin's original exception handler. */
1973     static int (*cygwin_exception_handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
1974    
1975     /* Our exception handler. */
1976     static int
1977     libsigsegv_exception_handler (EXCEPTION_RECORD *exception, void *frame, CONTEXT *context, void *dispatch)
1978     {
1979     EXCEPTION_POINTERS ExceptionInfo;
1980     ExceptionInfo.ExceptionRecord = exception;
1981     ExceptionInfo.ContextRecord = context;
1982     if (main_exception_filter (&ExceptionInfo) == EXCEPTION_CONTINUE_SEARCH)
1983     return cygwin_exception_handler (exception, frame, context, dispatch);
1984     else
1985     return 0;
1986     }
1987    
1988     static void
1989     do_install_main_exception_filter ()
1990     {
1991     /* We cannot insert any handler into the chain, because such handlers
1992     must lie on the stack (?). Instead, we have to replace(!) Cygwin's
1993     global exception handler. */
1994     cygwin_exception_handler = _except_list->handler;
1995     _except_list->handler = libsigsegv_exception_handler;
1996     }
1997    
1998     #else
1999    
2000     static void
2001     do_install_main_exception_filter ()
2002     {
2003     SetUnhandledExceptionFilter ((LPTOP_LEVEL_EXCEPTION_FILTER) &main_exception_filter);
2004     }
2005     #endif
2006    
2007     static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
2008     {
2009     static bool main_exception_filter_installed = false;
2010     if (!main_exception_filter_installed) {
2011     do_install_main_exception_filter();
2012     main_exception_filter_installed = true;
2013     }
2014     sigsegv_fault_handler = handler;
2015     return true;
2016     }
2017     #endif
2018    
2019 gbeauche 1.12 bool sigsegv_install_handler(sigsegv_fault_handler_t handler)
2020 gbeauche 1.1 {
2021 gbeauche 1.27 #if defined(HAVE_SIGSEGV_RECOVERY)
2022 gbeauche 1.1 bool success = true;
2023     #define FAULT_HANDLER(sig) success = success && sigsegv_do_install_handler(sig);
2024     SIGSEGV_ALL_SIGNALS
2025     #undef FAULT_HANDLER
2026 gbeauche 1.27 if (success)
2027     sigsegv_fault_handler = handler;
2028 gbeauche 1.1 return success;
2029 gbeauche 1.48 #elif defined(HAVE_MACH_EXCEPTIONS) || defined(HAVE_WIN32_EXCEPTIONS)
2030 gbeauche 1.27 return sigsegv_do_install_handler(handler);
2031 gbeauche 1.1 #else
2032     // FAIL: no siginfo_t nor sigcontext subterfuge is available
2033     return false;
2034     #endif
2035     }
2036    
2037    
2038     /*
2039     * SIGSEGV handler deinitialization
2040     */
2041    
2042     void sigsegv_deinstall_handler(void)
2043     {
2044 gbeauche 1.27 // We do nothing for Mach exceptions, the thread would need to be
2045     // suspended if not already so, and we might mess with other
2046     // exception handlers that came after we registered ours. There is
2047     // no need to remove the exception handler, in fact this function is
2048     // not called anywhere in Basilisk II.
2049 gbeauche 1.2 #ifdef HAVE_SIGSEGV_RECOVERY
2050 gbeauche 1.12 sigsegv_fault_handler = 0;
2051 gbeauche 1.1 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
2052     SIGSEGV_ALL_SIGNALS
2053     #undef FAULT_HANDLER
2054 gbeauche 1.2 #endif
2055 gbeauche 1.48 #ifdef HAVE_WIN32_EXCEPTIONS
2056     sigsegv_fault_handler = NULL;
2057     #endif
2058 gbeauche 1.1 }
2059    
2060 gbeauche 1.10
2061     /*
2062     * Set callback function when we cannot handle the fault
2063     */
2064    
2065 gbeauche 1.12 void sigsegv_set_dump_state(sigsegv_state_dumper_t handler)
2066 gbeauche 1.10 {
2067 gbeauche 1.12 sigsegv_state_dumper = handler;
2068 gbeauche 1.10 }
2069    
2070    
2071 gbeauche 1.1 /*
2072     * Test program used for configure/test
2073     */
2074    
2075 gbeauche 1.4 #ifdef CONFIGURE_TEST_SIGSEGV_RECOVERY
2076 gbeauche 1.1 #include <stdio.h>
2077     #include <stdlib.h>
2078     #include <fcntl.h>
2079 gbeauche 1.48 #ifdef HAVE_SYS_MMAN_H
2080 gbeauche 1.1 #include <sys/mman.h>
2081 gbeauche 1.48 #endif
2082 gbeauche 1.4 #include "vm_alloc.h"
2083 gbeauche 1.1
2084 gbeauche 1.32 const int REF_INDEX = 123;
2085     const int REF_VALUE = 45;
2086    
2087 gbeauche 1.1 static int page_size;
2088 gbeauche 1.3 static volatile char * page = 0;
2089     static volatile int handler_called = 0;
2090 gbeauche 1.1
2091 gbeauche 1.32 #ifdef __GNUC__
2092     // Code range where we expect the fault to come from
2093     static void *b_region, *e_region;
2094     #endif
2095    
2096 gbeauche 1.24 static sigsegv_return_t sigsegv_test_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
2097 gbeauche 1.1 {
2098 gbeauche 1.39 #if DEBUG
2099     printf("sigsegv_test_handler(%p, %p)\n", fault_address, instruction_address);
2100     printf("expected fault at %p\n", page + REF_INDEX);
2101     #ifdef __GNUC__
2102     printf("expected instruction address range: %p-%p\n", b_region, e_region);
2103     #endif
2104     #endif
2105 gbeauche 1.1 handler_called++;
2106 gbeauche 1.32 if ((fault_address - REF_INDEX) != page)
2107 gbeauche 1.29 exit(10);
2108 gbeauche 1.32 #ifdef __GNUC__
2109     // Make sure reported fault instruction address falls into
2110     // expected code range
2111     if (instruction_address != SIGSEGV_INVALID_PC
2112     && ((instruction_address < (sigsegv_address_t)b_region) ||
2113     (instruction_address >= (sigsegv_address_t)e_region)))
2114     exit(11);
2115     #endif
2116 gbeauche 1.4 if (vm_protect((char *)((unsigned long)fault_address & -page_size), page_size, VM_PAGE_READ | VM_PAGE_WRITE) != 0)
2117 gbeauche 1.32 exit(12);
2118 gbeauche 1.24 return SIGSEGV_RETURN_SUCCESS;
2119 gbeauche 1.1 }
2120    
2121 gbeauche 1.10 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
2122 gbeauche 1.24 static sigsegv_return_t sigsegv_insn_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
2123 gbeauche 1.10 {
2124 gbeauche 1.44 #if DEBUG
2125     printf("sigsegv_insn_handler(%p, %p)\n", fault_address, instruction_address);
2126     #endif
2127 gbeauche 1.28 if (((unsigned long)fault_address - (unsigned long)page) < page_size) {
2128     #ifdef __GNUC__
2129     // Make sure reported fault instruction address falls into
2130     // expected code range
2131     if (instruction_address != SIGSEGV_INVALID_PC
2132     && ((instruction_address < (sigsegv_address_t)b_region) ||
2133     (instruction_address >= (sigsegv_address_t)e_region)))
2134     return SIGSEGV_RETURN_FAILURE;
2135     #endif
2136 gbeauche 1.26 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
2137 gbeauche 1.28 }
2138    
2139 gbeauche 1.24 return SIGSEGV_RETURN_FAILURE;
2140 gbeauche 1.10 }
2141 gbeauche 1.34
2142     // More sophisticated tests for instruction skipper
2143     static bool arch_insn_skipper_tests()
2144     {
2145     #if (defined(i386) || defined(__i386__)) || defined(__x86_64__)
2146     static const unsigned char code[] = {
2147     0x8a, 0x00, // mov (%eax),%al
2148     0x8a, 0x2c, 0x18, // mov (%eax,%ebx,1),%ch
2149     0x88, 0x20, // mov %ah,(%eax)
2150     0x88, 0x08, // mov %cl,(%eax)
2151     0x66, 0x8b, 0x00, // mov (%eax),%ax
2152     0x66, 0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%cx
2153     0x66, 0x89, 0x00, // mov %ax,(%eax)
2154     0x66, 0x89, 0x0c, 0x18, // mov %cx,(%eax,%ebx,1)
2155     0x8b, 0x00, // mov (%eax),%eax
2156     0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%ecx
2157     0x89, 0x00, // mov %eax,(%eax)
2158     0x89, 0x0c, 0x18, // mov %ecx,(%eax,%ebx,1)
2159     #if defined(__x86_64__)
2160     0x44, 0x8a, 0x00, // mov (%rax),%r8b
2161     0x44, 0x8a, 0x20, // mov (%rax),%r12b
2162     0x42, 0x8a, 0x3c, 0x10, // mov (%rax,%r10,1),%dil
2163     0x44, 0x88, 0x00, // mov %r8b,(%rax)
2164     0x44, 0x88, 0x20, // mov %r12b,(%rax)
2165     0x42, 0x88, 0x3c, 0x10, // mov %dil,(%rax,%r10,1)
2166     0x66, 0x44, 0x8b, 0x00, // mov (%rax),%r8w
2167     0x66, 0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%cx
2168     0x66, 0x44, 0x89, 0x00, // mov %r8w,(%rax)
2169     0x66, 0x42, 0x89, 0x0c, 0x10, // mov %cx,(%rax,%r10,1)
2170     0x44, 0x8b, 0x00, // mov (%rax),%r8d
2171     0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%ecx
2172     0x44, 0x89, 0x00, // mov %r8d,(%rax)
2173     0x42, 0x89, 0x0c, 0x10, // mov %ecx,(%rax,%r10,1)
2174     0x48, 0x8b, 0x08, // mov (%rax),%rcx
2175     0x4c, 0x8b, 0x18, // mov (%rax),%r11
2176     0x4a, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%rcx
2177     0x4e, 0x8b, 0x1c, 0x10, // mov (%rax,%r10,1),%r11
2178     0x48, 0x89, 0x08, // mov %rcx,(%rax)
2179     0x4c, 0x89, 0x18, // mov %r11,(%rax)
2180     0x4a, 0x89, 0x0c, 0x10, // mov %rcx,(%rax,%r10,1)
2181     0x4e, 0x89, 0x1c, 0x10, // mov %r11,(%rax,%r10,1)
2182     #endif
2183     0 // end
2184     };
2185     const int N_REGS = 20;
2186     unsigned long regs[N_REGS];
2187     for (int i = 0; i < N_REGS; i++)
2188     regs[i] = i;
2189     const unsigned long start_code = (unsigned long)&code;
2190     regs[X86_REG_EIP] = start_code;
2191     while ((regs[X86_REG_EIP] - start_code) < (sizeof(code) - 1)
2192     && ix86_skip_instruction(regs))
2193     ; /* simply iterate */
2194     return (regs[X86_REG_EIP] - start_code) == (sizeof(code) - 1);
2195     #endif
2196     return true;
2197     }
2198 gbeauche 1.10 #endif
2199    
2200 gbeauche 1.1 int main(void)
2201     {
2202 gbeauche 1.4 if (vm_init() < 0)
2203 gbeauche 1.1 return 1;
2204    
2205 gbeauche 1.54 page_size = vm_get_page_size();
2206 gbeauche 1.4 if ((page = (char *)vm_acquire(page_size)) == VM_MAP_FAILED)
2207 gbeauche 1.29 return 2;
2208 gbeauche 1.4
2209 gbeauche 1.32 memset((void *)page, 0, page_size);
2210 gbeauche 1.4 if (vm_protect((char *)page, page_size, VM_PAGE_READ) < 0)
2211 gbeauche 1.29 return 3;
2212 gbeauche 1.1
2213     if (!sigsegv_install_handler(sigsegv_test_handler))
2214 gbeauche 1.29 return 4;
2215 gbeauche 1.1
2216 gbeauche 1.32 #ifdef __GNUC__
2217     b_region = &&L_b_region1;
2218     e_region = &&L_e_region1;
2219     #endif
2220     L_b_region1:
2221     page[REF_INDEX] = REF_VALUE;
2222     if (page[REF_INDEX] != REF_VALUE)
2223     exit(20);
2224     page[REF_INDEX] = REF_VALUE;
2225     L_e_region1:
2226    
2227 gbeauche 1.1 if (handler_called != 1)
2228 gbeauche 1.29 return 5;
2229 gbeauche 1.10
2230     #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
2231     if (!sigsegv_install_handler(sigsegv_insn_handler))
2232 gbeauche 1.29 return 6;
2233 gbeauche 1.10
2234 gbeauche 1.17 if (vm_protect((char *)page, page_size, VM_PAGE_READ | VM_PAGE_WRITE) < 0)
2235 gbeauche 1.29 return 7;
2236 gbeauche 1.10
2237     for (int i = 0; i < page_size; i++)
2238     page[i] = (i + 1) % page_size;
2239    
2240     if (vm_protect((char *)page, page_size, VM_PAGE_NOACCESS) < 0)
2241 gbeauche 1.29 return 8;
2242 gbeauche 1.10
2243     #define TEST_SKIP_INSTRUCTION(TYPE) do { \
2244 gbeauche 1.34 const unsigned long TAG = 0x12345678 | \
2245     (sizeof(long) == 8 ? 0x9abcdef0UL << 31 : 0); \
2246 gbeauche 1.10 TYPE data = *((TYPE *)(page + sizeof(TYPE))); \
2247 gbeauche 1.34 volatile unsigned long effect = data + TAG; \
2248 gbeauche 1.10 if (effect != TAG) \
2249 gbeauche 1.29 return 9; \
2250 gbeauche 1.10 } while (0)
2251    
2252 gbeauche 1.28 #ifdef __GNUC__
2253 gbeauche 1.32 b_region = &&L_b_region2;
2254     e_region = &&L_e_region2;
2255 gbeauche 1.28 #endif
2256 gbeauche 1.32 L_b_region2:
2257 gbeauche 1.10 TEST_SKIP_INSTRUCTION(unsigned char);
2258     TEST_SKIP_INSTRUCTION(unsigned short);
2259     TEST_SKIP_INSTRUCTION(unsigned int);
2260 gbeauche 1.34 TEST_SKIP_INSTRUCTION(unsigned long);
2261 gbeauche 1.44 TEST_SKIP_INSTRUCTION(signed char);
2262     TEST_SKIP_INSTRUCTION(signed short);
2263     TEST_SKIP_INSTRUCTION(signed int);
2264     TEST_SKIP_INSTRUCTION(signed long);
2265 gbeauche 1.32 L_e_region2:
2266 gbeauche 1.1
2267 gbeauche 1.34 if (!arch_insn_skipper_tests())
2268     return 20;
2269 gbeauche 1.35 #endif
2270 gbeauche 1.34
2271 gbeauche 1.4 vm_exit();
2272 gbeauche 1.1 return 0;
2273     }
2274     #endif