ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.65
Committed: 2007-06-05T13:15:57Z (17 years, 3 months ago) by gbeauche
Branch: MAIN
Changes since 1.64: +11 -9 lines
Log Message:
Arrangements for Linux/mips.

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