ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.58
Committed: 2006-01-22T23:14:48Z (18 years, 10 months ago) by gbeauche
Branch: MAIN
Changes since 1.57: +41 -21 lines
Log Message:
- Fix SPARC Store Doubleword transfer_size in decoder.
- In the instruction skipper code, add a huge kludge (trampoline) to forcibly
  zero out %global registers when requested. Otherwise, Solaris/SPARC turned
  out to use %g1 during signal handling, and the zero we could have written
  to there vanished. This assumes [%sp-8] is valid to use (ABI states data
  below %sp is undefined though)

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