ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.61
Committed: 2006-02-27T13:38:52Z (18 years, 8 months ago) by gbeauche
Branch: MAIN
Changes since 1.60: +9 -0 lines
Log Message:
add some barriers to make sure L_e_region* really come after the test insns

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 gbeauche 1.59 SPARC_REG_nPC = REG_nPC
1295 gbeauche 1.40 #endif
1296     };
1297     static bool sparc_skip_instruction(unsigned long * regs, gwindows_t * gwins, struct rwindow * rwin)
1298     {
1299     unsigned int * pc = (unsigned int *)regs[SPARC_REG_PC];
1300    
1301     if (pc == 0)
1302     return false;
1303    
1304     #if DEBUG
1305     printf("IP: %p [%08x]\n", pc, pc[0]);
1306     #endif
1307    
1308     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1309     transfer_size_t transfer_size = SIZE_LONG;
1310     bool register_pair = false;
1311    
1312     const unsigned int opcode = pc[0];
1313     if ((opcode >> 30) != 3)
1314     return false;
1315     switch ((opcode >> 19) & 0x3f) {
1316     case 9: // Load Signed Byte
1317     case 1: // Load Unsigned Byte
1318     transfer_type = SIGSEGV_TRANSFER_LOAD;
1319     transfer_size = SIZE_BYTE;
1320     break;
1321     case 10:// Load Signed Halfword
1322     case 2: // Load Unsigned Word
1323     transfer_type = SIGSEGV_TRANSFER_LOAD;
1324     transfer_size = SIZE_WORD;
1325     break;
1326     case 8: // Load Word
1327     case 0: // Load Unsigned Word
1328     transfer_type = SIGSEGV_TRANSFER_LOAD;
1329     transfer_size = SIZE_LONG;
1330     break;
1331     case 11:// Load Extended Word
1332     transfer_type = SIGSEGV_TRANSFER_LOAD;
1333     transfer_size = SIZE_QUAD;
1334     break;
1335     case 3: // Load Doubleword
1336     transfer_type = SIGSEGV_TRANSFER_LOAD;
1337     transfer_size = SIZE_LONG;
1338     register_pair = true;
1339     break;
1340     case 5: // Store Byte
1341     transfer_type = SIGSEGV_TRANSFER_STORE;
1342     transfer_size = SIZE_BYTE;
1343     break;
1344     case 6: // Store Halfword
1345     transfer_type = SIGSEGV_TRANSFER_STORE;
1346     transfer_size = SIZE_WORD;
1347     break;
1348     case 4: // Store Word
1349     transfer_type = SIGSEGV_TRANSFER_STORE;
1350     transfer_size = SIZE_LONG;
1351     break;
1352     case 14:// Store Extended Word
1353     transfer_type = SIGSEGV_TRANSFER_STORE;
1354     transfer_size = SIZE_QUAD;
1355     break;
1356     case 7: // Store Doubleword
1357     transfer_type = SIGSEGV_TRANSFER_STORE;
1358 gbeauche 1.58 transfer_size = SIZE_LONG;
1359 gbeauche 1.40 register_pair = true;
1360     break;
1361     }
1362    
1363     if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1364     // Unknown machine code, let it crash. Then patch the decoder
1365     return false;
1366     }
1367    
1368 gbeauche 1.58 const int reg = (opcode >> 25) & 0x1f;
1369    
1370     #if DEBUG
1371     static const char * reg_names[] = {
1372     "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
1373     "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
1374     "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
1375     "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"
1376     };
1377     printf("%s %s register %s\n",
1378     transfer_size == SIZE_BYTE ? "byte" :
1379     transfer_size == SIZE_WORD ? "word" :
1380     transfer_size == SIZE_LONG ? "long" :
1381     transfer_size == SIZE_QUAD ? "quad" : "unknown",
1382     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1383     reg_names[reg]);
1384     #endif
1385    
1386 gbeauche 1.40 // Zero target register in case of a load operation
1387     if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != 0) {
1388     // FIXME: code to handle local & input registers is not tested
1389 gbeauche 1.58 if (reg >= 1 && reg < 8) {
1390 gbeauche 1.40 // global registers
1391     regs[reg - 1 + SPARC_REG_G1] = 0;
1392     }
1393 gbeauche 1.58 else if (reg >= 8 && reg < 16) {
1394 gbeauche 1.40 // output registers
1395     regs[reg - 8 + SPARC_REG_O0] = 0;
1396     }
1397 gbeauche 1.58 else if (reg >= 16 && reg < 24) {
1398 gbeauche 1.40 // local registers (in register windows)
1399     if (gwins)
1400     gwins->wbuf->rw_local[reg - 16] = 0;
1401     else
1402     rwin->rw_local[reg - 16] = 0;
1403     }
1404     else {
1405     // input registers (in register windows)
1406     if (gwins)
1407     gwins->wbuf->rw_in[reg - 24] = 0;
1408     else
1409     rwin->rw_in[reg - 24] = 0;
1410     }
1411     }
1412    
1413     regs[SPARC_REG_PC] += 4;
1414 gbeauche 1.59 regs[SPARC_REG_nPC] += 4;
1415 gbeauche 1.38 return true;
1416 gbeauche 1.10 }
1417     #endif
1418     #endif
1419    
1420 gbeauche 1.44 // Decode and skip ARM instruction
1421     #if (defined(arm) || defined(__arm__))
1422     enum {
1423     #if (defined(__linux__))
1424     ARM_REG_PC = 15,
1425     ARM_REG_CPSR = 16
1426     #endif
1427     };
1428     static bool arm_skip_instruction(unsigned long * regs)
1429     {
1430     unsigned int * pc = (unsigned int *)regs[ARM_REG_PC];
1431    
1432     if (pc == 0)
1433     return false;
1434    
1435     #if DEBUG
1436     printf("IP: %p [%08x]\n", pc, pc[0]);
1437     #endif
1438    
1439     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1440     transfer_size_t transfer_size = SIZE_UNKNOWN;
1441     enum { op_sdt = 1, op_sdth = 2 };
1442     int op = 0;
1443    
1444     // Handle load/store instructions only
1445     const unsigned int opcode = pc[0];
1446     switch ((opcode >> 25) & 7) {
1447     case 0: // Halfword and Signed Data Transfer (LDRH, STRH, LDRSB, LDRSH)
1448     op = op_sdth;
1449     // Determine transfer size (S/H bits)
1450     switch ((opcode >> 5) & 3) {
1451     case 0: // SWP instruction
1452     break;
1453     case 1: // Unsigned halfwords
1454     case 3: // Signed halfwords
1455     transfer_size = SIZE_WORD;
1456     break;
1457     case 2: // Signed byte
1458     transfer_size = SIZE_BYTE;
1459     break;
1460     }
1461     break;
1462     case 2:
1463     case 3: // Single Data Transfer (LDR, STR)
1464     op = op_sdt;
1465     // Determine transfer size (B bit)
1466     if (((opcode >> 22) & 1) == 1)
1467     transfer_size = SIZE_BYTE;
1468     else
1469     transfer_size = SIZE_LONG;
1470     break;
1471     default:
1472     // FIXME: support load/store mutliple?
1473     return false;
1474     }
1475    
1476     // Check for invalid transfer size (SWP instruction?)
1477     if (transfer_size == SIZE_UNKNOWN)
1478     return false;
1479    
1480     // Determine transfer type (L bit)
1481     if (((opcode >> 20) & 1) == 1)
1482     transfer_type = SIGSEGV_TRANSFER_LOAD;
1483     else
1484     transfer_type = SIGSEGV_TRANSFER_STORE;
1485    
1486     // Compute offset
1487     int offset;
1488     if (((opcode >> 25) & 1) == 0) {
1489     if (op == op_sdt)
1490     offset = opcode & 0xfff;
1491     else if (op == op_sdth) {
1492     int rm = opcode & 0xf;
1493     if (((opcode >> 22) & 1) == 0) {
1494     // register offset
1495     offset = regs[rm];
1496     }
1497     else {
1498     // immediate offset
1499     offset = ((opcode >> 4) & 0xf0) | (opcode & 0x0f);
1500     }
1501     }
1502     }
1503     else {
1504     const int rm = opcode & 0xf;
1505     const int sh = (opcode >> 7) & 0x1f;
1506     if (((opcode >> 4) & 1) == 1) {
1507     // we expect only legal load/store instructions
1508     printf("FATAL: invalid shift operand\n");
1509     return false;
1510     }
1511     const unsigned int v = regs[rm];
1512     switch ((opcode >> 5) & 3) {
1513     case 0: // logical shift left
1514     offset = sh ? v << sh : v;
1515     break;
1516     case 1: // logical shift right
1517     offset = sh ? v >> sh : 0;
1518     break;
1519     case 2: // arithmetic shift right
1520     if (sh)
1521     offset = ((signed int)v) >> sh;
1522     else
1523     offset = (v & 0x80000000) ? 0xffffffff : 0;
1524     break;
1525     case 3: // rotate right
1526     if (sh)
1527     offset = (v >> sh) | (v << (32 - sh));
1528     else
1529     offset = (v >> 1) | ((regs[ARM_REG_CPSR] << 2) & 0x80000000);
1530     break;
1531     }
1532     }
1533     if (((opcode >> 23) & 1) == 0)
1534     offset = -offset;
1535    
1536     int rd = (opcode >> 12) & 0xf;
1537     int rn = (opcode >> 16) & 0xf;
1538     #if DEBUG
1539     static const char * reg_names[] = {
1540     "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
1541     "r9", "r9", "sl", "fp", "ip", "sp", "lr", "pc"
1542     };
1543     printf("%s %s register %s\n",
1544     transfer_size == SIZE_BYTE ? "byte" :
1545     transfer_size == SIZE_WORD ? "word" :
1546     transfer_size == SIZE_LONG ? "long" : "unknown",
1547     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1548     reg_names[rd]);
1549     #endif
1550    
1551     unsigned int base = regs[rn];
1552     if (((opcode >> 24) & 1) == 1)
1553     base += offset;
1554    
1555     if (transfer_type == SIGSEGV_TRANSFER_LOAD)
1556     regs[rd] = 0;
1557    
1558     if (((opcode >> 24) & 1) == 0) // post-index addressing
1559     regs[rn] += offset;
1560     else if (((opcode >> 21) & 1) == 1) // write-back address into base
1561     regs[rn] = base;
1562    
1563     regs[ARM_REG_PC] += 4;
1564     return true;
1565     }
1566     #endif
1567    
1568    
1569 gbeauche 1.1 // Fallbacks
1570     #ifndef SIGSEGV_FAULT_INSTRUCTION
1571     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_INVALID_PC
1572     #endif
1573 gbeauche 1.30 #ifndef SIGSEGV_FAULT_HANDLER_ARGLIST_1
1574     #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 SIGSEGV_FAULT_HANDLER_ARGLIST
1575     #endif
1576 gbeauche 1.31 #ifndef SIGSEGV_FAULT_HANDLER_INVOKE
1577     #define SIGSEGV_FAULT_HANDLER_INVOKE(ADDR, IP) sigsegv_fault_handler(ADDR, IP)
1578     #endif
1579 gbeauche 1.1
1580 gbeauche 1.2 // SIGSEGV recovery supported ?
1581     #if defined(SIGSEGV_ALL_SIGNALS) && defined(SIGSEGV_FAULT_HANDLER_ARGLIST) && defined(SIGSEGV_FAULT_ADDRESS)
1582     #define HAVE_SIGSEGV_RECOVERY
1583     #endif
1584    
1585 gbeauche 1.1
1586     /*
1587     * SIGSEGV global handler
1588     */
1589    
1590 gbeauche 1.27 // This function handles the badaccess to memory.
1591     // It is called from the signal handler or the exception handler.
1592 gbeauche 1.30 static bool handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGLIST_1)
1593 gbeauche 1.1 {
1594 gbeauche 1.56 #ifdef HAVE_MACH_EXCEPTIONS
1595     // We must match the initial count when writing back the CPU state registers
1596     kern_return_t krc;
1597     mach_msg_type_number_t count;
1598    
1599     count = SIGSEGV_THREAD_STATE_COUNT;
1600     krc = thread_get_state(thread, SIGSEGV_THREAD_STATE_FLAVOR, (thread_state_t)state, &count);
1601     MACH_CHECK_ERROR (thread_get_state, krc);
1602     #endif
1603    
1604 gbeauche 1.10 sigsegv_address_t fault_address = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
1605     sigsegv_address_t fault_instruction = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
1606    
1607 gbeauche 1.1 // Call user's handler and reinstall the global handler, if required
1608 gbeauche 1.31 switch (SIGSEGV_FAULT_HANDLER_INVOKE(fault_address, fault_instruction)) {
1609 gbeauche 1.24 case SIGSEGV_RETURN_SUCCESS:
1610 gbeauche 1.27 return true;
1611    
1612 gbeauche 1.10 #if HAVE_SIGSEGV_SKIP_INSTRUCTION
1613 gbeauche 1.24 case SIGSEGV_RETURN_SKIP_INSTRUCTION:
1614 gbeauche 1.27 // Call the instruction skipper with the register file
1615     // available
1616     if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE)) {
1617     #ifdef HAVE_MACH_EXCEPTIONS
1618     // Unlike UNIX signals where the thread state
1619     // is modified off of the stack, in Mach we
1620     // need to actually call thread_set_state to
1621     // have the register values updated.
1622     krc = thread_set_state(thread,
1623 gbeauche 1.56 SIGSEGV_THREAD_STATE_FLAVOR, (thread_state_t)state,
1624     count);
1625     MACH_CHECK_ERROR (thread_set_state, krc);
1626 gbeauche 1.27 #endif
1627     return true;
1628     }
1629 gbeauche 1.24 break;
1630     #endif
1631 nigel 1.43 case SIGSEGV_RETURN_FAILURE:
1632 gbeauche 1.50 // We can't do anything with the fault_address, dump state?
1633     if (sigsegv_state_dumper != 0)
1634     sigsegv_state_dumper(fault_address, fault_instruction);
1635     break;
1636 gbeauche 1.10 }
1637 gbeauche 1.27
1638     return false;
1639     }
1640    
1641    
1642     /*
1643     * There are two mechanisms for handling a bad memory access,
1644     * Mach exceptions and UNIX signals. The implementation specific
1645     * code appears below. Its reponsibility is to call handle_badaccess
1646     * which is the routine that handles the fault in an implementation
1647     * agnostic manner. The implementation specific code below is then
1648     * reponsible for checking whether handle_badaccess was able
1649     * to handle the memory access error and perform any implementation
1650     * specific tasks necessary afterwards.
1651     */
1652    
1653     #ifdef HAVE_MACH_EXCEPTIONS
1654     /*
1655     * We need to forward all exceptions that we do not handle.
1656     * This is important, there are many exceptions that may be
1657     * handled by other exception handlers. For example debuggers
1658     * use exceptions and the exception hander is in another
1659     * process in such a case. (Timothy J. Wood states in his
1660     * message to the list that he based this code on that from
1661     * gdb for Darwin.)
1662     */
1663     static inline kern_return_t
1664     forward_exception(mach_port_t thread_port,
1665     mach_port_t task_port,
1666     exception_type_t exception_type,
1667     exception_data_t exception_data,
1668     mach_msg_type_number_t data_count,
1669     ExceptionPorts *oldExceptionPorts)
1670     {
1671     kern_return_t kret;
1672     unsigned int portIndex;
1673     mach_port_t port;
1674     exception_behavior_t behavior;
1675     thread_state_flavor_t flavor;
1676 gbeauche 1.57 thread_state_data_t thread_state;
1677 gbeauche 1.27 mach_msg_type_number_t thread_state_count;
1678    
1679     for (portIndex = 0; portIndex < oldExceptionPorts->maskCount; portIndex++) {
1680     if (oldExceptionPorts->masks[portIndex] & (1 << exception_type)) {
1681     // This handler wants the exception
1682     break;
1683     }
1684     }
1685    
1686     if (portIndex >= oldExceptionPorts->maskCount) {
1687     fprintf(stderr, "No handler for exception_type = %d. Not fowarding\n", exception_type);
1688     return KERN_FAILURE;
1689     }
1690    
1691     port = oldExceptionPorts->handlers[portIndex];
1692     behavior = oldExceptionPorts->behaviors[portIndex];
1693     flavor = oldExceptionPorts->flavors[portIndex];
1694    
1695     /*
1696     fprintf(stderr, "forwarding exception, port = 0x%x, behaviour = %d, flavor = %d\n", port, behavior, flavor);
1697     */
1698    
1699     if (behavior != EXCEPTION_DEFAULT) {
1700     thread_state_count = THREAD_STATE_MAX;
1701 gbeauche 1.60 kret = thread_get_state (thread_port, flavor, (natural_t *)&thread_state,
1702 gbeauche 1.27 &thread_state_count);
1703     MACH_CHECK_ERROR (thread_get_state, kret);
1704     }
1705    
1706     switch (behavior) {
1707     case EXCEPTION_DEFAULT:
1708     // fprintf(stderr, "forwarding to exception_raise\n");
1709     kret = exception_raise(port, thread_port, task_port, exception_type,
1710     exception_data, data_count);
1711     MACH_CHECK_ERROR (exception_raise, kret);
1712     break;
1713     case EXCEPTION_STATE:
1714     // fprintf(stderr, "forwarding to exception_raise_state\n");
1715     kret = exception_raise_state(port, exception_type, exception_data,
1716     data_count, &flavor,
1717 gbeauche 1.60 (natural_t *)&thread_state, thread_state_count,
1718     (natural_t *)&thread_state, &thread_state_count);
1719 gbeauche 1.27 MACH_CHECK_ERROR (exception_raise_state, kret);
1720     break;
1721     case EXCEPTION_STATE_IDENTITY:
1722     // fprintf(stderr, "forwarding to exception_raise_state_identity\n");
1723     kret = exception_raise_state_identity(port, thread_port, task_port,
1724     exception_type, exception_data,
1725     data_count, &flavor,
1726 gbeauche 1.60 (natural_t *)&thread_state, thread_state_count,
1727     (natural_t *)&thread_state, &thread_state_count);
1728 gbeauche 1.27 MACH_CHECK_ERROR (exception_raise_state_identity, kret);
1729     break;
1730     default:
1731     fprintf(stderr, "forward_exception got unknown behavior\n");
1732     break;
1733     }
1734    
1735     if (behavior != EXCEPTION_DEFAULT) {
1736 gbeauche 1.60 kret = thread_set_state (thread_port, flavor, (natural_t *)&thread_state,
1737 gbeauche 1.27 thread_state_count);
1738     MACH_CHECK_ERROR (thread_set_state, kret);
1739     }
1740    
1741     return KERN_SUCCESS;
1742     }
1743    
1744     /*
1745     * This is the code that actually handles the exception.
1746     * It is called by exc_server. For Darwin 5 Apple changed
1747     * this a bit from how this family of functions worked in
1748     * Mach. If you are familiar with that it is a little
1749     * different. The main variation that concerns us here is
1750     * that code is an array of exception specific codes and
1751     * codeCount is a count of the number of codes in the code
1752     * array. In typical Mach all exceptions have a code
1753     * and sub-code. It happens to be the case that for a
1754     * EXC_BAD_ACCESS exception the first entry is the type of
1755     * bad access that occurred and the second entry is the
1756     * faulting address so these entries correspond exactly to
1757     * how the code and sub-code are used on Mach.
1758     *
1759     * This is a MIG interface. No code in Basilisk II should
1760     * call this directley. This has to have external C
1761     * linkage because that is what exc_server expects.
1762     */
1763     kern_return_t
1764     catch_exception_raise(mach_port_t exception_port,
1765     mach_port_t thread,
1766     mach_port_t task,
1767     exception_type_t exception,
1768     exception_data_t code,
1769     mach_msg_type_number_t codeCount)
1770     {
1771 gbeauche 1.56 SIGSEGV_THREAD_STATE_TYPE state;
1772 gbeauche 1.27 kern_return_t krc;
1773    
1774     if ((exception == EXC_BAD_ACCESS) && (codeCount >= 2)) {
1775     if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS))
1776     return KERN_SUCCESS;
1777     }
1778    
1779     // In Mach we do not need to remove the exception handler.
1780     // If we forward the exception, eventually some exception handler
1781     // will take care of this exception.
1782     krc = forward_exception(thread, task, exception, code, codeCount, &ports);
1783    
1784     return krc;
1785     }
1786     #endif
1787    
1788     #ifdef HAVE_SIGSEGV_RECOVERY
1789     // Handle bad memory accesses with signal handler
1790     static void sigsegv_handler(SIGSEGV_FAULT_HANDLER_ARGLIST)
1791     {
1792     // Call handler and reinstall the global handler, if required
1793     if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS)) {
1794     #if (defined(HAVE_SIGACTION) ? defined(SIGACTION_NEED_REINSTALL) : defined(SIGNAL_NEED_REINSTALL))
1795     sigsegv_do_install_handler(sig);
1796     #endif
1797     return;
1798     }
1799 gbeauche 1.10
1800 gbeauche 1.27 // Failure: reinstall default handler for "safe" crash
1801 gbeauche 1.1 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
1802 gbeauche 1.27 SIGSEGV_ALL_SIGNALS
1803 gbeauche 1.1 #undef FAULT_HANDLER
1804     }
1805 gbeauche 1.2 #endif
1806 gbeauche 1.1
1807    
1808     /*
1809     * SIGSEGV handler initialization
1810     */
1811    
1812     #if defined(HAVE_SIGINFO_T)
1813     static bool sigsegv_do_install_handler(int sig)
1814     {
1815     // Setup SIGSEGV handler to process writes to frame buffer
1816     #ifdef HAVE_SIGACTION
1817 gbeauche 1.22 struct sigaction sigsegv_sa;
1818     sigemptyset(&sigsegv_sa.sa_mask);
1819     sigsegv_sa.sa_sigaction = sigsegv_handler;
1820     sigsegv_sa.sa_flags = SA_SIGINFO;
1821     return (sigaction(sig, &sigsegv_sa, 0) == 0);
1822 gbeauche 1.1 #else
1823     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
1824     #endif
1825     }
1826 gbeauche 1.2 #endif
1827    
1828     #if defined(HAVE_SIGCONTEXT_SUBTERFUGE)
1829 gbeauche 1.1 static bool sigsegv_do_install_handler(int sig)
1830     {
1831     // Setup SIGSEGV handler to process writes to frame buffer
1832     #ifdef HAVE_SIGACTION
1833 gbeauche 1.22 struct sigaction sigsegv_sa;
1834     sigemptyset(&sigsegv_sa.sa_mask);
1835     sigsegv_sa.sa_handler = (signal_handler)sigsegv_handler;
1836     sigsegv_sa.sa_flags = 0;
1837 gbeauche 1.1 #if !EMULATED_68K && defined(__NetBSD__)
1838 gbeauche 1.22 sigaddset(&sigsegv_sa.sa_mask, SIGALRM);
1839     sigsegv_sa.sa_flags |= SA_ONSTACK;
1840 gbeauche 1.1 #endif
1841 gbeauche 1.22 return (sigaction(sig, &sigsegv_sa, 0) == 0);
1842 gbeauche 1.1 #else
1843     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
1844     #endif
1845     }
1846     #endif
1847    
1848 gbeauche 1.27 #if defined(HAVE_MACH_EXCEPTIONS)
1849     static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
1850     {
1851     /*
1852     * Except for the exception port functions, this should be
1853     * pretty much stock Mach. If later you choose to support
1854     * other Mach's besides Darwin, just check for __MACH__
1855     * here and __APPLE__ where the actual differences are.
1856     */
1857     #if defined(__APPLE__) && defined(__MACH__)
1858     if (sigsegv_fault_handler != NULL) {
1859     sigsegv_fault_handler = handler;
1860     return true;
1861     }
1862    
1863     kern_return_t krc;
1864    
1865     // create the the exception port
1866     krc = mach_port_allocate(mach_task_self(),
1867     MACH_PORT_RIGHT_RECEIVE, &_exceptionPort);
1868     if (krc != KERN_SUCCESS) {
1869     mach_error("mach_port_allocate", krc);
1870     return false;
1871     }
1872    
1873     // add a port send right
1874     krc = mach_port_insert_right(mach_task_self(),
1875     _exceptionPort, _exceptionPort,
1876     MACH_MSG_TYPE_MAKE_SEND);
1877     if (krc != KERN_SUCCESS) {
1878     mach_error("mach_port_insert_right", krc);
1879     return false;
1880     }
1881    
1882     // get the old exception ports
1883     ports.maskCount = sizeof (ports.masks) / sizeof (ports.masks[0]);
1884     krc = thread_get_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, ports.masks,
1885     &ports.maskCount, ports.handlers, ports.behaviors, ports.flavors);
1886     if (krc != KERN_SUCCESS) {
1887     mach_error("thread_get_exception_ports", krc);
1888     return false;
1889     }
1890    
1891     // set the new exception port
1892     //
1893     // We could have used EXCEPTION_STATE_IDENTITY instead of
1894     // EXCEPTION_DEFAULT to get the thread state in the initial
1895     // message, but it turns out that in the common case this is not
1896     // neccessary. If we need it we can later ask for it from the
1897     // suspended thread.
1898     //
1899     // Even with THREAD_STATE_NONE, Darwin provides the program
1900     // counter in the thread state. The comments in the header file
1901     // seem to imply that you can count on the GPR's on an exception
1902     // as well but just to be safe I use MACHINE_THREAD_STATE because
1903     // you have to ask for all of the GPR's anyway just to get the
1904     // program counter. In any case because of update effective
1905     // address from immediate and update address from effective
1906     // addresses of ra and rb modes (as good an name as any for these
1907     // addressing modes) used in PPC instructions, you will need the
1908     // GPR state anyway.
1909     krc = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, _exceptionPort,
1910 gbeauche 1.56 EXCEPTION_DEFAULT, SIGSEGV_THREAD_STATE_FLAVOR);
1911 gbeauche 1.27 if (krc != KERN_SUCCESS) {
1912     mach_error("thread_set_exception_ports", krc);
1913     return false;
1914     }
1915    
1916     // create the exception handler thread
1917     if (pthread_create(&exc_thread, NULL, &handleExceptions, NULL) != 0) {
1918     (void)fprintf(stderr, "creation of exception thread failed\n");
1919     return false;
1920     }
1921    
1922     // do not care about the exception thread any longer, let is run standalone
1923     (void)pthread_detach(exc_thread);
1924    
1925     sigsegv_fault_handler = handler;
1926     return true;
1927     #else
1928     return false;
1929     #endif
1930     }
1931     #endif
1932    
1933 gbeauche 1.48 #ifdef HAVE_WIN32_EXCEPTIONS
1934     static LONG WINAPI main_exception_filter(EXCEPTION_POINTERS *ExceptionInfo)
1935     {
1936     if (sigsegv_fault_handler != NULL
1937     && ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION
1938     && ExceptionInfo->ExceptionRecord->NumberParameters == 2
1939     && handle_badaccess(ExceptionInfo))
1940     return EXCEPTION_CONTINUE_EXECUTION;
1941    
1942     return EXCEPTION_CONTINUE_SEARCH;
1943     }
1944    
1945     #if defined __CYGWIN__ && defined __i386__
1946     /* In Cygwin programs, SetUnhandledExceptionFilter has no effect because Cygwin
1947     installs a global exception handler. We have to dig deep in order to install
1948     our main_exception_filter. */
1949    
1950     /* Data structures for the current thread's exception handler chain.
1951     On the x86 Windows uses register fs, offset 0 to point to the current
1952     exception handler; Cygwin mucks with it, so we must do the same... :-/ */
1953    
1954     /* Magic taken from winsup/cygwin/include/exceptions.h. */
1955    
1956     struct exception_list {
1957     struct exception_list *prev;
1958     int (*handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
1959     };
1960     typedef struct exception_list exception_list;
1961    
1962     /* Magic taken from winsup/cygwin/exceptions.cc. */
1963    
1964     __asm__ (".equ __except_list,0");
1965    
1966     extern exception_list *_except_list __asm__ ("%fs:__except_list");
1967    
1968     /* For debugging. _except_list is not otherwise accessible from gdb. */
1969     static exception_list *
1970     debug_get_except_list ()
1971     {
1972     return _except_list;
1973     }
1974    
1975     /* Cygwin's original exception handler. */
1976     static int (*cygwin_exception_handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
1977    
1978     /* Our exception handler. */
1979     static int
1980     libsigsegv_exception_handler (EXCEPTION_RECORD *exception, void *frame, CONTEXT *context, void *dispatch)
1981     {
1982     EXCEPTION_POINTERS ExceptionInfo;
1983     ExceptionInfo.ExceptionRecord = exception;
1984     ExceptionInfo.ContextRecord = context;
1985     if (main_exception_filter (&ExceptionInfo) == EXCEPTION_CONTINUE_SEARCH)
1986     return cygwin_exception_handler (exception, frame, context, dispatch);
1987     else
1988     return 0;
1989     }
1990    
1991     static void
1992     do_install_main_exception_filter ()
1993     {
1994     /* We cannot insert any handler into the chain, because such handlers
1995     must lie on the stack (?). Instead, we have to replace(!) Cygwin's
1996     global exception handler. */
1997     cygwin_exception_handler = _except_list->handler;
1998     _except_list->handler = libsigsegv_exception_handler;
1999     }
2000    
2001     #else
2002    
2003     static void
2004     do_install_main_exception_filter ()
2005     {
2006     SetUnhandledExceptionFilter ((LPTOP_LEVEL_EXCEPTION_FILTER) &main_exception_filter);
2007     }
2008     #endif
2009    
2010     static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
2011     {
2012     static bool main_exception_filter_installed = false;
2013     if (!main_exception_filter_installed) {
2014     do_install_main_exception_filter();
2015     main_exception_filter_installed = true;
2016     }
2017     sigsegv_fault_handler = handler;
2018     return true;
2019     }
2020     #endif
2021    
2022 gbeauche 1.12 bool sigsegv_install_handler(sigsegv_fault_handler_t handler)
2023 gbeauche 1.1 {
2024 gbeauche 1.27 #if defined(HAVE_SIGSEGV_RECOVERY)
2025 gbeauche 1.1 bool success = true;
2026     #define FAULT_HANDLER(sig) success = success && sigsegv_do_install_handler(sig);
2027     SIGSEGV_ALL_SIGNALS
2028     #undef FAULT_HANDLER
2029 gbeauche 1.27 if (success)
2030     sigsegv_fault_handler = handler;
2031 gbeauche 1.1 return success;
2032 gbeauche 1.48 #elif defined(HAVE_MACH_EXCEPTIONS) || defined(HAVE_WIN32_EXCEPTIONS)
2033 gbeauche 1.27 return sigsegv_do_install_handler(handler);
2034 gbeauche 1.1 #else
2035     // FAIL: no siginfo_t nor sigcontext subterfuge is available
2036     return false;
2037     #endif
2038     }
2039    
2040    
2041     /*
2042     * SIGSEGV handler deinitialization
2043     */
2044    
2045     void sigsegv_deinstall_handler(void)
2046     {
2047 gbeauche 1.27 // We do nothing for Mach exceptions, the thread would need to be
2048     // suspended if not already so, and we might mess with other
2049     // exception handlers that came after we registered ours. There is
2050     // no need to remove the exception handler, in fact this function is
2051     // not called anywhere in Basilisk II.
2052 gbeauche 1.2 #ifdef HAVE_SIGSEGV_RECOVERY
2053 gbeauche 1.12 sigsegv_fault_handler = 0;
2054 gbeauche 1.1 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
2055     SIGSEGV_ALL_SIGNALS
2056     #undef FAULT_HANDLER
2057 gbeauche 1.2 #endif
2058 gbeauche 1.48 #ifdef HAVE_WIN32_EXCEPTIONS
2059     sigsegv_fault_handler = NULL;
2060     #endif
2061 gbeauche 1.1 }
2062    
2063 gbeauche 1.10
2064     /*
2065     * Set callback function when we cannot handle the fault
2066     */
2067    
2068 gbeauche 1.12 void sigsegv_set_dump_state(sigsegv_state_dumper_t handler)
2069 gbeauche 1.10 {
2070 gbeauche 1.12 sigsegv_state_dumper = handler;
2071 gbeauche 1.10 }
2072    
2073    
2074 gbeauche 1.1 /*
2075     * Test program used for configure/test
2076     */
2077    
2078 gbeauche 1.4 #ifdef CONFIGURE_TEST_SIGSEGV_RECOVERY
2079 gbeauche 1.1 #include <stdio.h>
2080     #include <stdlib.h>
2081     #include <fcntl.h>
2082 gbeauche 1.48 #ifdef HAVE_SYS_MMAN_H
2083 gbeauche 1.1 #include <sys/mman.h>
2084 gbeauche 1.48 #endif
2085 gbeauche 1.4 #include "vm_alloc.h"
2086 gbeauche 1.1
2087 gbeauche 1.32 const int REF_INDEX = 123;
2088     const int REF_VALUE = 45;
2089    
2090 gbeauche 1.1 static int page_size;
2091 gbeauche 1.3 static volatile char * page = 0;
2092     static volatile int handler_called = 0;
2093 gbeauche 1.1
2094 gbeauche 1.61 /* Barriers */
2095     #ifdef __GNUC__
2096     #define BARRIER() asm volatile ("" : : : "memory")
2097     #else
2098     #define BARRIER() /* nothing */
2099     #endif
2100    
2101 gbeauche 1.32 #ifdef __GNUC__
2102     // Code range where we expect the fault to come from
2103     static void *b_region, *e_region;
2104     #endif
2105    
2106 gbeauche 1.24 static sigsegv_return_t sigsegv_test_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
2107 gbeauche 1.1 {
2108 gbeauche 1.39 #if DEBUG
2109     printf("sigsegv_test_handler(%p, %p)\n", fault_address, instruction_address);
2110     printf("expected fault at %p\n", page + REF_INDEX);
2111     #ifdef __GNUC__
2112     printf("expected instruction address range: %p-%p\n", b_region, e_region);
2113     #endif
2114     #endif
2115 gbeauche 1.1 handler_called++;
2116 gbeauche 1.32 if ((fault_address - REF_INDEX) != page)
2117 gbeauche 1.29 exit(10);
2118 gbeauche 1.32 #ifdef __GNUC__
2119     // Make sure reported fault instruction address falls into
2120     // expected code range
2121     if (instruction_address != SIGSEGV_INVALID_PC
2122     && ((instruction_address < (sigsegv_address_t)b_region) ||
2123     (instruction_address >= (sigsegv_address_t)e_region)))
2124     exit(11);
2125     #endif
2126 gbeauche 1.4 if (vm_protect((char *)((unsigned long)fault_address & -page_size), page_size, VM_PAGE_READ | VM_PAGE_WRITE) != 0)
2127 gbeauche 1.32 exit(12);
2128 gbeauche 1.24 return SIGSEGV_RETURN_SUCCESS;
2129 gbeauche 1.1 }
2130    
2131 gbeauche 1.10 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
2132 gbeauche 1.24 static sigsegv_return_t sigsegv_insn_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
2133 gbeauche 1.10 {
2134 gbeauche 1.44 #if DEBUG
2135     printf("sigsegv_insn_handler(%p, %p)\n", fault_address, instruction_address);
2136     #endif
2137 gbeauche 1.28 if (((unsigned long)fault_address - (unsigned long)page) < page_size) {
2138     #ifdef __GNUC__
2139     // Make sure reported fault instruction address falls into
2140     // expected code range
2141     if (instruction_address != SIGSEGV_INVALID_PC
2142     && ((instruction_address < (sigsegv_address_t)b_region) ||
2143     (instruction_address >= (sigsegv_address_t)e_region)))
2144     return SIGSEGV_RETURN_FAILURE;
2145     #endif
2146 gbeauche 1.26 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
2147 gbeauche 1.28 }
2148    
2149 gbeauche 1.24 return SIGSEGV_RETURN_FAILURE;
2150 gbeauche 1.10 }
2151 gbeauche 1.34
2152     // More sophisticated tests for instruction skipper
2153     static bool arch_insn_skipper_tests()
2154     {
2155     #if (defined(i386) || defined(__i386__)) || defined(__x86_64__)
2156     static const unsigned char code[] = {
2157     0x8a, 0x00, // mov (%eax),%al
2158     0x8a, 0x2c, 0x18, // mov (%eax,%ebx,1),%ch
2159     0x88, 0x20, // mov %ah,(%eax)
2160     0x88, 0x08, // mov %cl,(%eax)
2161     0x66, 0x8b, 0x00, // mov (%eax),%ax
2162     0x66, 0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%cx
2163     0x66, 0x89, 0x00, // mov %ax,(%eax)
2164     0x66, 0x89, 0x0c, 0x18, // mov %cx,(%eax,%ebx,1)
2165     0x8b, 0x00, // mov (%eax),%eax
2166     0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%ecx
2167     0x89, 0x00, // mov %eax,(%eax)
2168     0x89, 0x0c, 0x18, // mov %ecx,(%eax,%ebx,1)
2169     #if defined(__x86_64__)
2170     0x44, 0x8a, 0x00, // mov (%rax),%r8b
2171     0x44, 0x8a, 0x20, // mov (%rax),%r12b
2172     0x42, 0x8a, 0x3c, 0x10, // mov (%rax,%r10,1),%dil
2173     0x44, 0x88, 0x00, // mov %r8b,(%rax)
2174     0x44, 0x88, 0x20, // mov %r12b,(%rax)
2175     0x42, 0x88, 0x3c, 0x10, // mov %dil,(%rax,%r10,1)
2176     0x66, 0x44, 0x8b, 0x00, // mov (%rax),%r8w
2177     0x66, 0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%cx
2178     0x66, 0x44, 0x89, 0x00, // mov %r8w,(%rax)
2179     0x66, 0x42, 0x89, 0x0c, 0x10, // mov %cx,(%rax,%r10,1)
2180     0x44, 0x8b, 0x00, // mov (%rax),%r8d
2181     0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%ecx
2182     0x44, 0x89, 0x00, // mov %r8d,(%rax)
2183     0x42, 0x89, 0x0c, 0x10, // mov %ecx,(%rax,%r10,1)
2184     0x48, 0x8b, 0x08, // mov (%rax),%rcx
2185     0x4c, 0x8b, 0x18, // mov (%rax),%r11
2186     0x4a, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%rcx
2187     0x4e, 0x8b, 0x1c, 0x10, // mov (%rax,%r10,1),%r11
2188     0x48, 0x89, 0x08, // mov %rcx,(%rax)
2189     0x4c, 0x89, 0x18, // mov %r11,(%rax)
2190     0x4a, 0x89, 0x0c, 0x10, // mov %rcx,(%rax,%r10,1)
2191     0x4e, 0x89, 0x1c, 0x10, // mov %r11,(%rax,%r10,1)
2192     #endif
2193     0 // end
2194     };
2195     const int N_REGS = 20;
2196     unsigned long regs[N_REGS];
2197     for (int i = 0; i < N_REGS; i++)
2198     regs[i] = i;
2199     const unsigned long start_code = (unsigned long)&code;
2200     regs[X86_REG_EIP] = start_code;
2201     while ((regs[X86_REG_EIP] - start_code) < (sizeof(code) - 1)
2202     && ix86_skip_instruction(regs))
2203     ; /* simply iterate */
2204     return (regs[X86_REG_EIP] - start_code) == (sizeof(code) - 1);
2205     #endif
2206     return true;
2207     }
2208 gbeauche 1.10 #endif
2209    
2210 gbeauche 1.1 int main(void)
2211     {
2212 gbeauche 1.4 if (vm_init() < 0)
2213 gbeauche 1.1 return 1;
2214    
2215 gbeauche 1.54 page_size = vm_get_page_size();
2216 gbeauche 1.4 if ((page = (char *)vm_acquire(page_size)) == VM_MAP_FAILED)
2217 gbeauche 1.29 return 2;
2218 gbeauche 1.4
2219 gbeauche 1.32 memset((void *)page, 0, page_size);
2220 gbeauche 1.4 if (vm_protect((char *)page, page_size, VM_PAGE_READ) < 0)
2221 gbeauche 1.29 return 3;
2222 gbeauche 1.1
2223     if (!sigsegv_install_handler(sigsegv_test_handler))
2224 gbeauche 1.29 return 4;
2225 gbeauche 1.1
2226 gbeauche 1.32 #ifdef __GNUC__
2227     b_region = &&L_b_region1;
2228     e_region = &&L_e_region1;
2229     #endif
2230     L_b_region1:
2231     page[REF_INDEX] = REF_VALUE;
2232     if (page[REF_INDEX] != REF_VALUE)
2233     exit(20);
2234     page[REF_INDEX] = REF_VALUE;
2235 gbeauche 1.61 BARRIER();
2236 gbeauche 1.32 L_e_region1:
2237    
2238 gbeauche 1.1 if (handler_called != 1)
2239 gbeauche 1.29 return 5;
2240 gbeauche 1.10
2241     #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
2242     if (!sigsegv_install_handler(sigsegv_insn_handler))
2243 gbeauche 1.29 return 6;
2244 gbeauche 1.10
2245 gbeauche 1.17 if (vm_protect((char *)page, page_size, VM_PAGE_READ | VM_PAGE_WRITE) < 0)
2246 gbeauche 1.29 return 7;
2247 gbeauche 1.10
2248     for (int i = 0; i < page_size; i++)
2249     page[i] = (i + 1) % page_size;
2250    
2251     if (vm_protect((char *)page, page_size, VM_PAGE_NOACCESS) < 0)
2252 gbeauche 1.29 return 8;
2253 gbeauche 1.10
2254     #define TEST_SKIP_INSTRUCTION(TYPE) do { \
2255 gbeauche 1.34 const unsigned long TAG = 0x12345678 | \
2256     (sizeof(long) == 8 ? 0x9abcdef0UL << 31 : 0); \
2257 gbeauche 1.10 TYPE data = *((TYPE *)(page + sizeof(TYPE))); \
2258 gbeauche 1.34 volatile unsigned long effect = data + TAG; \
2259 gbeauche 1.10 if (effect != TAG) \
2260 gbeauche 1.29 return 9; \
2261 gbeauche 1.10 } while (0)
2262    
2263 gbeauche 1.28 #ifdef __GNUC__
2264 gbeauche 1.32 b_region = &&L_b_region2;
2265     e_region = &&L_e_region2;
2266 gbeauche 1.28 #endif
2267 gbeauche 1.32 L_b_region2:
2268 gbeauche 1.10 TEST_SKIP_INSTRUCTION(unsigned char);
2269     TEST_SKIP_INSTRUCTION(unsigned short);
2270     TEST_SKIP_INSTRUCTION(unsigned int);
2271 gbeauche 1.34 TEST_SKIP_INSTRUCTION(unsigned long);
2272 gbeauche 1.44 TEST_SKIP_INSTRUCTION(signed char);
2273     TEST_SKIP_INSTRUCTION(signed short);
2274     TEST_SKIP_INSTRUCTION(signed int);
2275     TEST_SKIP_INSTRUCTION(signed long);
2276 gbeauche 1.61 BARRIER();
2277 gbeauche 1.32 L_e_region2:
2278 gbeauche 1.1
2279 gbeauche 1.34 if (!arch_insn_skipper_tests())
2280     return 20;
2281 gbeauche 1.35 #endif
2282 gbeauche 1.34
2283 gbeauche 1.4 vm_exit();
2284 gbeauche 1.1 return 0;
2285     }
2286     #endif