ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.67
Committed: 2007-12-30T08:45:18Z (16 years, 8 months ago) by gbeauche
Branch: MAIN
Changes since 1.66: +33 -10 lines
Log Message:
Improve API for systems that require explicit calls to functions to retrieve
the memory addresses that triggered a SIGSEGV (e.g. MacOS X).

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 gbeauche 1.66 #define SIGSEGV_EXCEPTION_STATE_TYPE ppc_exception_state_t
606     #define SIGSEGV_EXCEPTION_STATE_FLAVOR PPC_EXCEPTION_STATE
607     #define SIGSEGV_EXCEPTION_STATE_COUNT PPC_EXCEPTION_STATE_COUNT
608     #define SIGSEGV_FAULT_ADDRESS exc_state->dar
609 gbeauche 1.56 #define SIGSEGV_THREAD_STATE_TYPE ppc_thread_state_t
610     #define SIGSEGV_THREAD_STATE_FLAVOR PPC_THREAD_STATE
611     #define SIGSEGV_THREAD_STATE_COUNT PPC_THREAD_STATE_COUNT
612 gbeauche 1.66 #define SIGSEGV_FAULT_INSTRUCTION state.srr0
613 gbeauche 1.56 #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
614 gbeauche 1.66 #define SIGSEGV_REGISTER_FILE (unsigned long *)&state.srr0, (unsigned long *)&state.r0
615 gbeauche 1.56 #endif
616     #ifdef __i386__
617 gbeauche 1.57 #ifdef i386_SAVED_STATE
618 gbeauche 1.56 #define SIGSEGV_THREAD_STATE_TYPE struct i386_saved_state
619     #define SIGSEGV_THREAD_STATE_FLAVOR i386_SAVED_STATE
620     #define SIGSEGV_THREAD_STATE_COUNT i386_SAVED_STATE_COUNT
621 gbeauche 1.66 #define SIGSEGV_REGISTER_FILE ((unsigned long *)&state.edi) /* EDI is the first GPR we consider */
622 gbeauche 1.57 #else
623 gbeauche 1.66 #define SIGSEGV_EXCEPTION_STATE_TYPE struct i386_exception_state
624     #define SIGSEGV_EXCEPTION_STATE_FLAVOR i386_EXCEPTION_STATE
625     #define SIGSEGV_EXCEPTION_STATE_COUNT i386_EXCEPTION_STATE_COUNT
626     #define SIGSEGV_FAULT_ADDRESS exc_state->faultvaddr
627 gbeauche 1.57 #define SIGSEGV_THREAD_STATE_TYPE struct i386_thread_state
628     #define SIGSEGV_THREAD_STATE_FLAVOR i386_THREAD_STATE
629     #define SIGSEGV_THREAD_STATE_COUNT i386_THREAD_STATE_COUNT
630 gbeauche 1.66 #define SIGSEGV_REGISTER_FILE ((unsigned long *)&state.eax) /* EAX is the first GPR we consider */
631 gbeauche 1.57 #endif
632 gbeauche 1.66 #define SIGSEGV_FAULT_INSTRUCTION state.eip
633 gbeauche 1.56 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
634     #endif
635 gbeauche 1.66 #ifdef __x86_64__
636     #define SIGSEGV_EXCEPTION_STATE_TYPE struct x86_exception_state64
637     #define SIGSEGV_EXCEPTION_STATE_FLAVOR x86_EXCEPTION_STATE64
638     #define SIGSEGV_EXCEPTION_STATE_COUNT x86_EXCEPTION_STATE64_COUNT
639     #define SIGSEGV_FAULT_ADDRESS exc_state->faultvaddr
640     #define SIGSEGV_THREAD_STATE_TYPE struct x86_thread_state64
641     #define SIGSEGV_THREAD_STATE_FLAVOR x86_THREAD_STATE64
642     #define SIGSEGV_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT
643     #define SIGSEGV_REGISTER_FILE ((unsigned long *)&state.rax) /* RAX is the first GPR we consider */
644     #define SIGSEGV_FAULT_INSTRUCTION state.rip
645     #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
646     #endif
647     #ifdef SIGSEGV_EXCEPTION_STATE_TYPE
648     #define SIGSEGV_FAULT_HANDLER_ARGLIST mach_port_t thread, SIGSEGV_EXCEPTION_STATE_TYPE *exc_state
649     #define SIGSEGV_FAULT_HANDLER_ARGS thread, &exc_state
650     #else
651 gbeauche 1.27 #define SIGSEGV_FAULT_ADDRESS code[1]
652 gbeauche 1.66 #define SIGSEGV_FAULT_HANDLER_ARGLIST mach_port_t thread, exception_data_t code
653     #define SIGSEGV_FAULT_HANDLER_ARGS thread, code
654     #endif
655 gbeauche 1.27
656     // Since there can only be one exception thread running at any time
657     // this is not a problem.
658     #define MSG_SIZE 512
659     static char msgbuf[MSG_SIZE];
660     static char replybuf[MSG_SIZE];
661    
662     /*
663     * This is the entry point for the exception handler thread. The job
664     * of this thread is to wait for exception messages on the exception
665     * port that was setup beforehand and to pass them on to exc_server.
666     * exc_server is a MIG generated function that is a part of Mach.
667     * Its job is to decide what to do with the exception message. In our
668     * case exc_server calls catch_exception_raise on our behalf. After
669     * exc_server returns, it is our responsibility to send the reply.
670     */
671     static void *
672     handleExceptions(void *priv)
673     {
674     mach_msg_header_t *msg, *reply;
675     kern_return_t krc;
676    
677     msg = (mach_msg_header_t *)msgbuf;
678     reply = (mach_msg_header_t *)replybuf;
679    
680     for (;;) {
681     krc = mach_msg(msg, MACH_RCV_MSG, MSG_SIZE, MSG_SIZE,
682     _exceptionPort, 0, MACH_PORT_NULL);
683     MACH_CHECK_ERROR(mach_msg, krc);
684    
685     if (!exc_server(msg, reply)) {
686     fprintf(stderr, "exc_server hated the message\n");
687     exit(1);
688     }
689    
690     krc = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0,
691     msg->msgh_local_port, 0, MACH_PORT_NULL);
692     if (krc != KERN_SUCCESS) {
693     fprintf(stderr, "Error sending message to original reply port, krc = %d, %s",
694     krc, mach_error_string(krc));
695     exit(1);
696     }
697     }
698     }
699     #endif
700     #endif
701 gbeauche 1.1
702 gbeauche 1.14
703     /*
704     * Instruction skipping
705     */
706    
707 gbeauche 1.10 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
708     // Decode and skip X86 instruction
709 gbeauche 1.34 #if (defined(i386) || defined(__i386__)) || defined(__x86_64__)
710 gbeauche 1.10 #if defined(__linux__)
711     enum {
712 gbeauche 1.34 #if (defined(i386) || defined(__i386__))
713 gbeauche 1.10 X86_REG_EIP = 14,
714     X86_REG_EAX = 11,
715     X86_REG_ECX = 10,
716     X86_REG_EDX = 9,
717     X86_REG_EBX = 8,
718     X86_REG_ESP = 7,
719     X86_REG_EBP = 6,
720     X86_REG_ESI = 5,
721     X86_REG_EDI = 4
722 gbeauche 1.34 #endif
723     #if defined(__x86_64__)
724     X86_REG_R8 = 0,
725     X86_REG_R9 = 1,
726     X86_REG_R10 = 2,
727     X86_REG_R11 = 3,
728     X86_REG_R12 = 4,
729     X86_REG_R13 = 5,
730     X86_REG_R14 = 6,
731     X86_REG_R15 = 7,
732     X86_REG_EDI = 8,
733     X86_REG_ESI = 9,
734     X86_REG_EBP = 10,
735     X86_REG_EBX = 11,
736     X86_REG_EDX = 12,
737     X86_REG_EAX = 13,
738     X86_REG_ECX = 14,
739     X86_REG_ESP = 15,
740     X86_REG_EIP = 16
741     #endif
742 gbeauche 1.10 };
743     #endif
744 gbeauche 1.51 #if defined(__NetBSD__)
745     enum {
746     #if (defined(i386) || defined(__i386__))
747     X86_REG_EIP = _REG_EIP,
748     X86_REG_EAX = _REG_EAX,
749     X86_REG_ECX = _REG_ECX,
750     X86_REG_EDX = _REG_EDX,
751     X86_REG_EBX = _REG_EBX,
752     X86_REG_ESP = _REG_ESP,
753     X86_REG_EBP = _REG_EBP,
754     X86_REG_ESI = _REG_ESI,
755     X86_REG_EDI = _REG_EDI
756     #endif
757     };
758     #endif
759     #if defined(__FreeBSD__)
760 gbeauche 1.17 enum {
761 gbeauche 1.34 #if (defined(i386) || defined(__i386__))
762 gbeauche 1.17 X86_REG_EIP = 10,
763     X86_REG_EAX = 7,
764     X86_REG_ECX = 6,
765     X86_REG_EDX = 5,
766     X86_REG_EBX = 4,
767     X86_REG_ESP = 13,
768     X86_REG_EBP = 2,
769     X86_REG_ESI = 1,
770     X86_REG_EDI = 0
771 gbeauche 1.34 #endif
772 gbeauche 1.17 };
773     #endif
774 gbeauche 1.55 #if defined(__OpenBSD__)
775     enum {
776     #if defined(__i386__)
777     // EDI is the first register we consider
778     #define OREG(REG) offsetof(struct sigcontext, sc_##REG)
779     #define DREG(REG) ((OREG(REG) - OREG(edi)) / 4)
780     X86_REG_EIP = DREG(eip), // 7
781     X86_REG_EAX = DREG(eax), // 6
782     X86_REG_ECX = DREG(ecx), // 5
783     X86_REG_EDX = DREG(edx), // 4
784     X86_REG_EBX = DREG(ebx), // 3
785     X86_REG_ESP = DREG(esp), // 10
786     X86_REG_EBP = DREG(ebp), // 2
787     X86_REG_ESI = DREG(esi), // 1
788     X86_REG_EDI = DREG(edi) // 0
789     #undef DREG
790     #undef OREG
791     #endif
792     };
793     #endif
794 gbeauche 1.54 #if defined(__sun__)
795     // Same as for Linux, need to check for x86-64
796     enum {
797     #if defined(__i386__)
798     X86_REG_EIP = EIP,
799     X86_REG_EAX = EAX,
800     X86_REG_ECX = ECX,
801     X86_REG_EDX = EDX,
802     X86_REG_EBX = EBX,
803     X86_REG_ESP = ESP,
804     X86_REG_EBP = EBP,
805     X86_REG_ESI = ESI,
806     X86_REG_EDI = EDI
807     #endif
808     };
809     #endif
810 gbeauche 1.56 #if defined(__APPLE__) && defined(__MACH__)
811     enum {
812 gbeauche 1.66 #if (defined(i386) || defined(__i386__))
813 gbeauche 1.57 #ifdef i386_SAVED_STATE
814     // same as FreeBSD (in Open Darwin 8.0.1)
815 gbeauche 1.56 X86_REG_EIP = 10,
816     X86_REG_EAX = 7,
817     X86_REG_ECX = 6,
818     X86_REG_EDX = 5,
819     X86_REG_EBX = 4,
820     X86_REG_ESP = 13,
821     X86_REG_EBP = 2,
822     X86_REG_ESI = 1,
823     X86_REG_EDI = 0
824 gbeauche 1.57 #else
825     // new layout (MacOS X 10.4.4 for x86)
826     X86_REG_EIP = 10,
827     X86_REG_EAX = 0,
828     X86_REG_ECX = 2,
829 gbeauche 1.66 X86_REG_EDX = 3,
830 gbeauche 1.57 X86_REG_EBX = 1,
831     X86_REG_ESP = 7,
832     X86_REG_EBP = 6,
833     X86_REG_ESI = 5,
834     X86_REG_EDI = 4
835     #endif
836 gbeauche 1.66 #endif
837     #if defined(__x86_64__)
838     X86_REG_R8 = 8,
839     X86_REG_R9 = 9,
840     X86_REG_R10 = 10,
841     X86_REG_R11 = 11,
842     X86_REG_R12 = 12,
843     X86_REG_R13 = 13,
844     X86_REG_R14 = 14,
845     X86_REG_R15 = 15,
846     X86_REG_EDI = 4,
847     X86_REG_ESI = 5,
848     X86_REG_EBP = 6,
849     X86_REG_EBX = 1,
850     X86_REG_EDX = 3,
851     X86_REG_EAX = 0,
852     X86_REG_ECX = 2,
853     X86_REG_ESP = 7,
854     X86_REG_EIP = 16
855     #endif
856 gbeauche 1.56 };
857     #endif
858 gbeauche 1.48 #if defined(_WIN32)
859     enum {
860     #if (defined(i386) || defined(__i386__))
861     X86_REG_EIP = 7,
862     X86_REG_EAX = 5,
863     X86_REG_ECX = 4,
864     X86_REG_EDX = 3,
865     X86_REG_EBX = 2,
866     X86_REG_ESP = 10,
867     X86_REG_EBP = 6,
868     X86_REG_ESI = 1,
869     X86_REG_EDI = 0
870     #endif
871     };
872     #endif
873 gbeauche 1.10 // FIXME: this is partly redundant with the instruction decoding phase
874     // to discover transfer type and register number
875     static inline int ix86_step_over_modrm(unsigned char * p)
876     {
877     int mod = (p[0] >> 6) & 3;
878     int rm = p[0] & 7;
879     int offset = 0;
880    
881     // ModR/M Byte
882     switch (mod) {
883     case 0: // [reg]
884     if (rm == 5) return 4; // disp32
885     break;
886     case 1: // disp8[reg]
887     offset = 1;
888     break;
889     case 2: // disp32[reg]
890     offset = 4;
891     break;
892     case 3: // register
893     return 0;
894     }
895    
896     // SIB Byte
897     if (rm == 4) {
898     if (mod == 0 && (p[1] & 7) == 5)
899     offset = 5; // disp32[index]
900     else
901     offset++;
902     }
903    
904     return offset;
905     }
906    
907 gbeauche 1.34 static bool ix86_skip_instruction(unsigned long * regs)
908 gbeauche 1.10 {
909 gbeauche 1.14 unsigned char * eip = (unsigned char *)regs[X86_REG_EIP];
910 gbeauche 1.10
911     if (eip == 0)
912     return false;
913 gbeauche 1.50 #ifdef _WIN32
914     if (IsBadCodePtr((FARPROC)eip))
915     return false;
916     #endif
917 gbeauche 1.10
918 gbeauche 1.64 enum instruction_type_t {
919     i_MOV,
920     i_ADD
921     };
922    
923 gbeauche 1.22 transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
924 gbeauche 1.14 transfer_size_t transfer_size = SIZE_LONG;
925 gbeauche 1.64 instruction_type_t instruction_type = i_MOV;
926 gbeauche 1.10
927     int reg = -1;
928     int len = 0;
929 gbeauche 1.34
930     #if DEBUG
931     printf("IP: %p [%02x %02x %02x %02x...]\n",
932     eip, eip[0], eip[1], eip[2], eip[3]);
933     #endif
934    
935 gbeauche 1.10 // Operand size prefix
936     if (*eip == 0x66) {
937     eip++;
938     len++;
939     transfer_size = SIZE_WORD;
940     }
941    
942 gbeauche 1.34 // REX prefix
943     #if defined(__x86_64__)
944     struct rex_t {
945     unsigned char W;
946     unsigned char R;
947     unsigned char X;
948     unsigned char B;
949     };
950     rex_t rex = { 0, 0, 0, 0 };
951     bool has_rex = false;
952     if ((*eip & 0xf0) == 0x40) {
953     has_rex = true;
954     const unsigned char b = *eip;
955     rex.W = b & (1 << 3);
956     rex.R = b & (1 << 2);
957     rex.X = b & (1 << 1);
958     rex.B = b & (1 << 0);
959     #if DEBUG
960     printf("REX: %c,%c,%c,%c\n",
961     rex.W ? 'W' : '_',
962     rex.R ? 'R' : '_',
963     rex.X ? 'X' : '_',
964     rex.B ? 'B' : '_');
965     #endif
966     eip++;
967     len++;
968     if (rex.W)
969     transfer_size = SIZE_QUAD;
970     }
971     #else
972     const bool has_rex = false;
973     #endif
974    
975 gbeauche 1.10 // Decode instruction
976 gbeauche 1.64 int op_len = 1;
977 gbeauche 1.45 int target_size = SIZE_UNKNOWN;
978 gbeauche 1.10 switch (eip[0]) {
979 gbeauche 1.17 case 0x0f:
980 gbeauche 1.45 target_size = transfer_size;
981 gbeauche 1.18 switch (eip[1]) {
982 gbeauche 1.45 case 0xbe: // MOVSX r32, r/m8
983 gbeauche 1.18 case 0xb6: // MOVZX r32, r/m8
984 gbeauche 1.45 transfer_size = SIZE_BYTE;
985     goto do_mov_extend;
986 gbeauche 1.47 case 0xbf: // MOVSX r32, r/m16
987 gbeauche 1.18 case 0xb7: // MOVZX r32, r/m16
988 gbeauche 1.45 transfer_size = SIZE_WORD;
989     goto do_mov_extend;
990     do_mov_extend:
991 gbeauche 1.64 op_len = 2;
992     goto do_transfer_load;
993     }
994     break;
995 gbeauche 1.62 #if defined(__x86_64__)
996     case 0x63: // MOVSXD r64, r/m32
997     if (has_rex && rex.W) {
998     transfer_size = SIZE_LONG;
999     target_size = SIZE_QUAD;
1000     }
1001     else if (transfer_size != SIZE_WORD) {
1002     transfer_size = SIZE_LONG;
1003     target_size = SIZE_QUAD;
1004     }
1005 gbeauche 1.64 goto do_transfer_load;
1006 gbeauche 1.62 #endif
1007 gbeauche 1.64 case 0x02: // ADD r8, r/m8
1008     transfer_size = SIZE_BYTE;
1009     case 0x03: // ADD r32, r/m32
1010     instruction_type = i_ADD;
1011     goto do_transfer_load;
1012 gbeauche 1.10 case 0x8a: // MOV r8, r/m8
1013     transfer_size = SIZE_BYTE;
1014     case 0x8b: // MOV r32, r/m32 (or 16-bit operation)
1015 gbeauche 1.64 do_transfer_load:
1016     switch (eip[op_len] & 0xc0) {
1017 gbeauche 1.10 case 0x80:
1018 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
1019 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
1020 gbeauche 1.10 break;
1021     case 0x40:
1022 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
1023 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
1024 gbeauche 1.10 break;
1025     case 0x00:
1026 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
1027 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
1028 gbeauche 1.10 break;
1029     }
1030 gbeauche 1.64 len += 1 + op_len + ix86_step_over_modrm(eip + op_len);
1031 gbeauche 1.10 break;
1032 gbeauche 1.64 case 0x00: // ADD r/m8, r8
1033     transfer_size = SIZE_BYTE;
1034     case 0x01: // ADD r/m32, r32
1035     instruction_type = i_ADD;
1036     goto do_transfer_store;
1037 gbeauche 1.10 case 0x88: // MOV r/m8, r8
1038     transfer_size = SIZE_BYTE;
1039     case 0x89: // MOV r/m32, r32 (or 16-bit operation)
1040 gbeauche 1.64 do_transfer_store:
1041     switch (eip[op_len] & 0xc0) {
1042 gbeauche 1.10 case 0x80:
1043 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
1044 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
1045 gbeauche 1.10 break;
1046     case 0x40:
1047 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
1048 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
1049 gbeauche 1.10 break;
1050     case 0x00:
1051 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
1052 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
1053 gbeauche 1.10 break;
1054     }
1055 gbeauche 1.64 len += 1 + op_len + ix86_step_over_modrm(eip + op_len);
1056 gbeauche 1.10 break;
1057     }
1058 gbeauche 1.45 if (target_size == SIZE_UNKNOWN)
1059     target_size = transfer_size;
1060 gbeauche 1.10
1061 gbeauche 1.22 if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1062 gbeauche 1.10 // Unknown machine code, let it crash. Then patch the decoder
1063     return false;
1064     }
1065    
1066 gbeauche 1.34 #if defined(__x86_64__)
1067     if (rex.R)
1068     reg += 8;
1069     #endif
1070    
1071 gbeauche 1.64 if (instruction_type == i_MOV && transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) {
1072 gbeauche 1.34 static const int x86_reg_map[] = {
1073 gbeauche 1.10 X86_REG_EAX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBX,
1074 gbeauche 1.34 X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI,
1075     #if defined(__x86_64__)
1076     X86_REG_R8, X86_REG_R9, X86_REG_R10, X86_REG_R11,
1077     X86_REG_R12, X86_REG_R13, X86_REG_R14, X86_REG_R15,
1078     #endif
1079 gbeauche 1.10 };
1080    
1081 gbeauche 1.34 if (reg < 0 || reg >= (sizeof(x86_reg_map)/sizeof(x86_reg_map[0]) - 1))
1082 gbeauche 1.10 return false;
1083    
1084 gbeauche 1.34 // Set 0 to the relevant register part
1085     // NOTE: this is only valid for MOV alike instructions
1086 gbeauche 1.10 int rloc = x86_reg_map[reg];
1087 gbeauche 1.45 switch (target_size) {
1088 gbeauche 1.10 case SIZE_BYTE:
1089 gbeauche 1.36 if (has_rex || reg < 4)
1090     regs[rloc] = (regs[rloc] & ~0x00ffL);
1091     else {
1092     rloc = x86_reg_map[reg - 4];
1093     regs[rloc] = (regs[rloc] & ~0xff00L);
1094     }
1095 gbeauche 1.10 break;
1096     case SIZE_WORD:
1097 gbeauche 1.34 regs[rloc] = (regs[rloc] & ~0xffffL);
1098 gbeauche 1.10 break;
1099     case SIZE_LONG:
1100 gbeauche 1.34 case SIZE_QUAD: // zero-extension
1101 gbeauche 1.10 regs[rloc] = 0;
1102     break;
1103     }
1104     }
1105    
1106     #if DEBUG
1107 gbeauche 1.64 printf("%p: %s %s access", (void *)regs[X86_REG_EIP],
1108 gbeauche 1.34 transfer_size == SIZE_BYTE ? "byte" :
1109     transfer_size == SIZE_WORD ? "word" :
1110     transfer_size == SIZE_LONG ? "long" :
1111     transfer_size == SIZE_QUAD ? "quad" : "unknown",
1112 gbeauche 1.22 transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
1113 gbeauche 1.10
1114     if (reg != -1) {
1115 gbeauche 1.34 static const char * x86_byte_reg_str_map[] = {
1116     "al", "cl", "dl", "bl",
1117     "spl", "bpl", "sil", "dil",
1118     "r8b", "r9b", "r10b", "r11b",
1119     "r12b", "r13b", "r14b", "r15b",
1120     "ah", "ch", "dh", "bh",
1121     };
1122     static const char * x86_word_reg_str_map[] = {
1123     "ax", "cx", "dx", "bx",
1124     "sp", "bp", "si", "di",
1125     "r8w", "r9w", "r10w", "r11w",
1126     "r12w", "r13w", "r14w", "r15w",
1127     };
1128     static const char *x86_long_reg_str_map[] = {
1129     "eax", "ecx", "edx", "ebx",
1130     "esp", "ebp", "esi", "edi",
1131     "r8d", "r9d", "r10d", "r11d",
1132     "r12d", "r13d", "r14d", "r15d",
1133     };
1134     static const char *x86_quad_reg_str_map[] = {
1135     "rax", "rcx", "rdx", "rbx",
1136     "rsp", "rbp", "rsi", "rdi",
1137     "r8", "r9", "r10", "r11",
1138     "r12", "r13", "r14", "r15",
1139 gbeauche 1.10 };
1140 gbeauche 1.34 const char * reg_str = NULL;
1141 gbeauche 1.46 switch (target_size) {
1142 gbeauche 1.34 case SIZE_BYTE:
1143     reg_str = x86_byte_reg_str_map[(!has_rex && reg >= 4 ? 12 : 0) + reg];
1144     break;
1145     case SIZE_WORD: reg_str = x86_word_reg_str_map[reg]; break;
1146     case SIZE_LONG: reg_str = x86_long_reg_str_map[reg]; break;
1147     case SIZE_QUAD: reg_str = x86_quad_reg_str_map[reg]; break;
1148     }
1149     if (reg_str)
1150     printf(" %s register %%%s",
1151     transfer_type == SIGSEGV_TRANSFER_LOAD ? "to" : "from",
1152     reg_str);
1153 gbeauche 1.10 }
1154     printf(", %d bytes instruction\n", len);
1155     #endif
1156    
1157     regs[X86_REG_EIP] += len;
1158 gbeauche 1.13 return true;
1159     }
1160     #endif
1161 gbeauche 1.14
1162 gbeauche 1.13 // Decode and skip PPC instruction
1163 gbeauche 1.14 #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__))
1164 gbeauche 1.49 static bool powerpc_skip_instruction(unsigned long * nip_p, unsigned long * regs)
1165 gbeauche 1.13 {
1166 gbeauche 1.14 instruction_t instr;
1167     powerpc_decode_instruction(&instr, *nip_p, regs);
1168 gbeauche 1.13
1169 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1170 gbeauche 1.13 // Unknown machine code, let it crash. Then patch the decoder
1171     return false;
1172     }
1173    
1174     #if DEBUG
1175 gbeauche 1.14 printf("%08x: %s %s access", *nip_p,
1176 gbeauche 1.49 instr.transfer_size == SIZE_BYTE ? "byte" :
1177     instr.transfer_size == SIZE_WORD ? "word" :
1178     instr.transfer_size == SIZE_LONG ? "long" : "quad",
1179 gbeauche 1.22 instr.transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
1180 gbeauche 1.14
1181     if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
1182     printf(" r%d (ra = %08x)\n", instr.ra, instr.addr);
1183 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
1184 gbeauche 1.14 printf(" r%d (rd = 0)\n", instr.rd);
1185     #endif
1186    
1187     if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
1188     regs[instr.ra] = instr.addr;
1189 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
1190 gbeauche 1.14 regs[instr.rd] = 0;
1191 gbeauche 1.13
1192 gbeauche 1.14 *nip_p += 4;
1193 gbeauche 1.10 return true;
1194 gbeauche 1.38 }
1195     #endif
1196    
1197     // Decode and skip MIPS instruction
1198     #if (defined(mips) || defined(__mips))
1199 gbeauche 1.65 static bool mips_skip_instruction(greg_t * pc_p, greg_t * regs)
1200 gbeauche 1.38 {
1201 gbeauche 1.65 unsigned int * epc = (unsigned int *)(unsigned long)*pc_p;
1202 gbeauche 1.38
1203     if (epc == 0)
1204     return false;
1205    
1206     #if DEBUG
1207     printf("IP: %p [%08x]\n", epc, epc[0]);
1208     #endif
1209    
1210     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1211     transfer_size_t transfer_size = SIZE_LONG;
1212     int direction = 0;
1213    
1214     const unsigned int opcode = epc[0];
1215     switch (opcode >> 26) {
1216     case 32: // Load Byte
1217     case 36: // Load Byte Unsigned
1218     transfer_type = SIGSEGV_TRANSFER_LOAD;
1219     transfer_size = SIZE_BYTE;
1220     break;
1221     case 33: // Load Halfword
1222     case 37: // Load Halfword Unsigned
1223     transfer_type = SIGSEGV_TRANSFER_LOAD;
1224     transfer_size = SIZE_WORD;
1225     break;
1226     case 35: // Load Word
1227     case 39: // Load Word Unsigned
1228     transfer_type = SIGSEGV_TRANSFER_LOAD;
1229     transfer_size = SIZE_LONG;
1230     break;
1231     case 34: // Load Word Left
1232     transfer_type = SIGSEGV_TRANSFER_LOAD;
1233     transfer_size = SIZE_LONG;
1234     direction = -1;
1235     break;
1236     case 38: // Load Word Right
1237     transfer_type = SIGSEGV_TRANSFER_LOAD;
1238     transfer_size = SIZE_LONG;
1239     direction = 1;
1240     break;
1241     case 55: // Load Doubleword
1242     transfer_type = SIGSEGV_TRANSFER_LOAD;
1243     transfer_size = SIZE_QUAD;
1244     break;
1245     case 26: // Load Doubleword Left
1246     transfer_type = SIGSEGV_TRANSFER_LOAD;
1247     transfer_size = SIZE_QUAD;
1248     direction = -1;
1249     break;
1250     case 27: // Load Doubleword Right
1251     transfer_type = SIGSEGV_TRANSFER_LOAD;
1252     transfer_size = SIZE_QUAD;
1253     direction = 1;
1254     break;
1255     case 40: // Store Byte
1256     transfer_type = SIGSEGV_TRANSFER_STORE;
1257     transfer_size = SIZE_BYTE;
1258     break;
1259     case 41: // Store Halfword
1260     transfer_type = SIGSEGV_TRANSFER_STORE;
1261     transfer_size = SIZE_WORD;
1262     break;
1263     case 43: // Store Word
1264     case 42: // Store Word Left
1265     case 46: // Store Word Right
1266     transfer_type = SIGSEGV_TRANSFER_STORE;
1267     transfer_size = SIZE_LONG;
1268     break;
1269     case 63: // Store Doubleword
1270     case 44: // Store Doubleword Left
1271     case 45: // Store Doubleword Right
1272     transfer_type = SIGSEGV_TRANSFER_STORE;
1273     transfer_size = SIZE_QUAD;
1274     break;
1275     /* Misc instructions unlikely to be used within CPU emulators */
1276     case 48: // Load Linked Word
1277     transfer_type = SIGSEGV_TRANSFER_LOAD;
1278     transfer_size = SIZE_LONG;
1279     break;
1280     case 52: // Load Linked Doubleword
1281     transfer_type = SIGSEGV_TRANSFER_LOAD;
1282     transfer_size = SIZE_QUAD;
1283     break;
1284     case 56: // Store Conditional Word
1285     transfer_type = SIGSEGV_TRANSFER_STORE;
1286     transfer_size = SIZE_LONG;
1287     break;
1288     case 60: // Store Conditional Doubleword
1289     transfer_type = SIGSEGV_TRANSFER_STORE;
1290     transfer_size = SIZE_QUAD;
1291     break;
1292     }
1293    
1294     if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1295     // Unknown machine code, let it crash. Then patch the decoder
1296     return false;
1297     }
1298    
1299     // Zero target register in case of a load operation
1300     const int reg = (opcode >> 16) & 0x1f;
1301     if (transfer_type == SIGSEGV_TRANSFER_LOAD) {
1302     if (direction == 0)
1303     regs[reg] = 0;
1304     else {
1305     // FIXME: untested code
1306     unsigned long ea = regs[(opcode >> 21) & 0x1f];
1307     ea += (signed long)(signed int)(signed short)(opcode & 0xffff);
1308     const int offset = ea & (transfer_size == SIZE_LONG ? 3 : 7);
1309     unsigned long value;
1310     if (direction > 0) {
1311     const unsigned long rmask = ~((1L << ((offset + 1) * 8)) - 1);
1312     value = regs[reg] & rmask;
1313     }
1314     else {
1315     const unsigned long lmask = (1L << (offset * 8)) - 1;
1316     value = regs[reg] & lmask;
1317     }
1318     // restore most significant bits
1319     if (transfer_size == SIZE_LONG)
1320     value = (signed long)(signed int)value;
1321     regs[reg] = value;
1322     }
1323     }
1324    
1325     #if DEBUG
1326     #if (defined(_ABIN32) || defined(_ABI64))
1327     static const char * mips_gpr_names[32] = {
1328     "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
1329     "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
1330     "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
1331     "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
1332     };
1333     #else
1334     static const char * mips_gpr_names[32] = {
1335     "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
1336     "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
1337     "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
1338     "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
1339     };
1340     #endif
1341     printf("%s %s register %s\n",
1342     transfer_size == SIZE_BYTE ? "byte" :
1343     transfer_size == SIZE_WORD ? "word" :
1344     transfer_size == SIZE_LONG ? "long" :
1345     transfer_size == SIZE_QUAD ? "quad" : "unknown",
1346     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1347     mips_gpr_names[reg]);
1348     #endif
1349    
1350 gbeauche 1.65 *pc_p += 4;
1351 gbeauche 1.40 return true;
1352     }
1353     #endif
1354    
1355     // Decode and skip SPARC instruction
1356     #if (defined(sparc) || defined(__sparc__))
1357     enum {
1358     #if (defined(__sun__))
1359     SPARC_REG_G1 = REG_G1,
1360     SPARC_REG_O0 = REG_O0,
1361     SPARC_REG_PC = REG_PC,
1362 gbeauche 1.59 SPARC_REG_nPC = REG_nPC
1363 gbeauche 1.40 #endif
1364     };
1365     static bool sparc_skip_instruction(unsigned long * regs, gwindows_t * gwins, struct rwindow * rwin)
1366     {
1367     unsigned int * pc = (unsigned int *)regs[SPARC_REG_PC];
1368    
1369     if (pc == 0)
1370     return false;
1371    
1372     #if DEBUG
1373     printf("IP: %p [%08x]\n", pc, pc[0]);
1374     #endif
1375    
1376     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1377     transfer_size_t transfer_size = SIZE_LONG;
1378     bool register_pair = false;
1379    
1380     const unsigned int opcode = pc[0];
1381     if ((opcode >> 30) != 3)
1382     return false;
1383     switch ((opcode >> 19) & 0x3f) {
1384     case 9: // Load Signed Byte
1385     case 1: // Load Unsigned Byte
1386     transfer_type = SIGSEGV_TRANSFER_LOAD;
1387     transfer_size = SIZE_BYTE;
1388     break;
1389     case 10:// Load Signed Halfword
1390     case 2: // Load Unsigned Word
1391     transfer_type = SIGSEGV_TRANSFER_LOAD;
1392     transfer_size = SIZE_WORD;
1393     break;
1394     case 8: // Load Word
1395     case 0: // Load Unsigned Word
1396     transfer_type = SIGSEGV_TRANSFER_LOAD;
1397     transfer_size = SIZE_LONG;
1398     break;
1399     case 11:// Load Extended Word
1400     transfer_type = SIGSEGV_TRANSFER_LOAD;
1401     transfer_size = SIZE_QUAD;
1402     break;
1403     case 3: // Load Doubleword
1404     transfer_type = SIGSEGV_TRANSFER_LOAD;
1405     transfer_size = SIZE_LONG;
1406     register_pair = true;
1407     break;
1408     case 5: // Store Byte
1409     transfer_type = SIGSEGV_TRANSFER_STORE;
1410     transfer_size = SIZE_BYTE;
1411     break;
1412     case 6: // Store Halfword
1413     transfer_type = SIGSEGV_TRANSFER_STORE;
1414     transfer_size = SIZE_WORD;
1415     break;
1416     case 4: // Store Word
1417     transfer_type = SIGSEGV_TRANSFER_STORE;
1418     transfer_size = SIZE_LONG;
1419     break;
1420     case 14:// Store Extended Word
1421     transfer_type = SIGSEGV_TRANSFER_STORE;
1422     transfer_size = SIZE_QUAD;
1423     break;
1424     case 7: // Store Doubleword
1425     transfer_type = SIGSEGV_TRANSFER_STORE;
1426 gbeauche 1.58 transfer_size = SIZE_LONG;
1427 gbeauche 1.40 register_pair = true;
1428     break;
1429     }
1430    
1431     if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1432     // Unknown machine code, let it crash. Then patch the decoder
1433     return false;
1434     }
1435    
1436 gbeauche 1.58 const int reg = (opcode >> 25) & 0x1f;
1437    
1438     #if DEBUG
1439     static const char * reg_names[] = {
1440     "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
1441     "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
1442     "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
1443     "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"
1444     };
1445     printf("%s %s register %s\n",
1446     transfer_size == SIZE_BYTE ? "byte" :
1447     transfer_size == SIZE_WORD ? "word" :
1448     transfer_size == SIZE_LONG ? "long" :
1449     transfer_size == SIZE_QUAD ? "quad" : "unknown",
1450     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1451     reg_names[reg]);
1452     #endif
1453    
1454 gbeauche 1.40 // Zero target register in case of a load operation
1455     if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != 0) {
1456     // FIXME: code to handle local & input registers is not tested
1457 gbeauche 1.58 if (reg >= 1 && reg < 8) {
1458 gbeauche 1.40 // global registers
1459     regs[reg - 1 + SPARC_REG_G1] = 0;
1460     }
1461 gbeauche 1.58 else if (reg >= 8 && reg < 16) {
1462 gbeauche 1.40 // output registers
1463     regs[reg - 8 + SPARC_REG_O0] = 0;
1464     }
1465 gbeauche 1.58 else if (reg >= 16 && reg < 24) {
1466 gbeauche 1.40 // local registers (in register windows)
1467     if (gwins)
1468     gwins->wbuf->rw_local[reg - 16] = 0;
1469     else
1470     rwin->rw_local[reg - 16] = 0;
1471     }
1472     else {
1473     // input registers (in register windows)
1474     if (gwins)
1475     gwins->wbuf->rw_in[reg - 24] = 0;
1476     else
1477     rwin->rw_in[reg - 24] = 0;
1478     }
1479     }
1480    
1481     regs[SPARC_REG_PC] += 4;
1482 gbeauche 1.59 regs[SPARC_REG_nPC] += 4;
1483 gbeauche 1.38 return true;
1484 gbeauche 1.10 }
1485     #endif
1486     #endif
1487    
1488 gbeauche 1.44 // Decode and skip ARM instruction
1489     #if (defined(arm) || defined(__arm__))
1490     enum {
1491     #if (defined(__linux__))
1492     ARM_REG_PC = 15,
1493     ARM_REG_CPSR = 16
1494     #endif
1495     };
1496     static bool arm_skip_instruction(unsigned long * regs)
1497     {
1498     unsigned int * pc = (unsigned int *)regs[ARM_REG_PC];
1499    
1500     if (pc == 0)
1501     return false;
1502    
1503     #if DEBUG
1504     printf("IP: %p [%08x]\n", pc, pc[0]);
1505     #endif
1506    
1507     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1508     transfer_size_t transfer_size = SIZE_UNKNOWN;
1509     enum { op_sdt = 1, op_sdth = 2 };
1510     int op = 0;
1511    
1512     // Handle load/store instructions only
1513     const unsigned int opcode = pc[0];
1514     switch ((opcode >> 25) & 7) {
1515     case 0: // Halfword and Signed Data Transfer (LDRH, STRH, LDRSB, LDRSH)
1516     op = op_sdth;
1517     // Determine transfer size (S/H bits)
1518     switch ((opcode >> 5) & 3) {
1519     case 0: // SWP instruction
1520     break;
1521     case 1: // Unsigned halfwords
1522     case 3: // Signed halfwords
1523     transfer_size = SIZE_WORD;
1524     break;
1525     case 2: // Signed byte
1526     transfer_size = SIZE_BYTE;
1527     break;
1528     }
1529     break;
1530     case 2:
1531     case 3: // Single Data Transfer (LDR, STR)
1532     op = op_sdt;
1533     // Determine transfer size (B bit)
1534     if (((opcode >> 22) & 1) == 1)
1535     transfer_size = SIZE_BYTE;
1536     else
1537     transfer_size = SIZE_LONG;
1538     break;
1539     default:
1540     // FIXME: support load/store mutliple?
1541     return false;
1542     }
1543    
1544     // Check for invalid transfer size (SWP instruction?)
1545     if (transfer_size == SIZE_UNKNOWN)
1546     return false;
1547    
1548     // Determine transfer type (L bit)
1549     if (((opcode >> 20) & 1) == 1)
1550     transfer_type = SIGSEGV_TRANSFER_LOAD;
1551     else
1552     transfer_type = SIGSEGV_TRANSFER_STORE;
1553    
1554     // Compute offset
1555     int offset;
1556     if (((opcode >> 25) & 1) == 0) {
1557     if (op == op_sdt)
1558     offset = opcode & 0xfff;
1559     else if (op == op_sdth) {
1560     int rm = opcode & 0xf;
1561     if (((opcode >> 22) & 1) == 0) {
1562     // register offset
1563     offset = regs[rm];
1564     }
1565     else {
1566     // immediate offset
1567     offset = ((opcode >> 4) & 0xf0) | (opcode & 0x0f);
1568     }
1569     }
1570     }
1571     else {
1572     const int rm = opcode & 0xf;
1573     const int sh = (opcode >> 7) & 0x1f;
1574     if (((opcode >> 4) & 1) == 1) {
1575     // we expect only legal load/store instructions
1576     printf("FATAL: invalid shift operand\n");
1577     return false;
1578     }
1579     const unsigned int v = regs[rm];
1580     switch ((opcode >> 5) & 3) {
1581     case 0: // logical shift left
1582     offset = sh ? v << sh : v;
1583     break;
1584     case 1: // logical shift right
1585     offset = sh ? v >> sh : 0;
1586     break;
1587     case 2: // arithmetic shift right
1588     if (sh)
1589     offset = ((signed int)v) >> sh;
1590     else
1591     offset = (v & 0x80000000) ? 0xffffffff : 0;
1592     break;
1593     case 3: // rotate right
1594     if (sh)
1595     offset = (v >> sh) | (v << (32 - sh));
1596     else
1597     offset = (v >> 1) | ((regs[ARM_REG_CPSR] << 2) & 0x80000000);
1598     break;
1599     }
1600     }
1601     if (((opcode >> 23) & 1) == 0)
1602     offset = -offset;
1603    
1604     int rd = (opcode >> 12) & 0xf;
1605     int rn = (opcode >> 16) & 0xf;
1606     #if DEBUG
1607     static const char * reg_names[] = {
1608     "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
1609     "r9", "r9", "sl", "fp", "ip", "sp", "lr", "pc"
1610     };
1611     printf("%s %s register %s\n",
1612     transfer_size == SIZE_BYTE ? "byte" :
1613     transfer_size == SIZE_WORD ? "word" :
1614     transfer_size == SIZE_LONG ? "long" : "unknown",
1615     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1616     reg_names[rd]);
1617     #endif
1618    
1619     unsigned int base = regs[rn];
1620     if (((opcode >> 24) & 1) == 1)
1621     base += offset;
1622    
1623     if (transfer_type == SIGSEGV_TRANSFER_LOAD)
1624     regs[rd] = 0;
1625    
1626     if (((opcode >> 24) & 1) == 0) // post-index addressing
1627     regs[rn] += offset;
1628     else if (((opcode >> 21) & 1) == 1) // write-back address into base
1629     regs[rn] = base;
1630    
1631     regs[ARM_REG_PC] += 4;
1632     return true;
1633     }
1634     #endif
1635    
1636    
1637 gbeauche 1.1 // Fallbacks
1638     #ifndef SIGSEGV_FAULT_INSTRUCTION
1639 gbeauche 1.67 #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_INVALID_ADDRESS
1640 gbeauche 1.1 #endif
1641 gbeauche 1.30 #ifndef SIGSEGV_FAULT_HANDLER_ARGLIST_1
1642     #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 SIGSEGV_FAULT_HANDLER_ARGLIST
1643     #endif
1644 gbeauche 1.31 #ifndef SIGSEGV_FAULT_HANDLER_INVOKE
1645 gbeauche 1.67 #define SIGSEGV_FAULT_HANDLER_INVOKE(P) sigsegv_fault_handler(P)
1646 gbeauche 1.31 #endif
1647 gbeauche 1.1
1648 gbeauche 1.2 // SIGSEGV recovery supported ?
1649     #if defined(SIGSEGV_ALL_SIGNALS) && defined(SIGSEGV_FAULT_HANDLER_ARGLIST) && defined(SIGSEGV_FAULT_ADDRESS)
1650     #define HAVE_SIGSEGV_RECOVERY
1651     #endif
1652    
1653 gbeauche 1.1
1654     /*
1655     * SIGSEGV global handler
1656     */
1657    
1658 gbeauche 1.67 struct sigsegv_info_t {
1659     sigsegv_address_t addr;
1660     sigsegv_address_t pc;
1661     };
1662    
1663     // Return the address of the invalid memory reference
1664     sigsegv_address_t sigsegv_get_fault_address(sigsegv_info_t *sip)
1665     {
1666     return sip->addr;
1667     }
1668    
1669     // Return the address of the instruction that caused the fault, or
1670     // SIGSEGV_INVALID_ADDRESS if we could not retrieve this information
1671     sigsegv_address_t sigsegv_get_fault_instruction_address(sigsegv_info_t *sip)
1672     {
1673     return sip->pc;
1674     }
1675    
1676 gbeauche 1.27 // This function handles the badaccess to memory.
1677     // It is called from the signal handler or the exception handler.
1678 gbeauche 1.30 static bool handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGLIST_1)
1679 gbeauche 1.1 {
1680 gbeauche 1.56 #ifdef HAVE_MACH_EXCEPTIONS
1681     // We must match the initial count when writing back the CPU state registers
1682     kern_return_t krc;
1683     mach_msg_type_number_t count;
1684 gbeauche 1.66 SIGSEGV_THREAD_STATE_TYPE state;
1685 gbeauche 1.56
1686     count = SIGSEGV_THREAD_STATE_COUNT;
1687 gbeauche 1.66 krc = thread_get_state(thread, SIGSEGV_THREAD_STATE_FLAVOR, (thread_state_t)&state, &count);
1688 gbeauche 1.56 MACH_CHECK_ERROR (thread_get_state, krc);
1689     #endif
1690    
1691 gbeauche 1.67 sigsegv_info_t si;
1692     si.addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
1693     si.pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
1694 gbeauche 1.10
1695 gbeauche 1.1 // Call user's handler and reinstall the global handler, if required
1696 gbeauche 1.67 switch (SIGSEGV_FAULT_HANDLER_INVOKE(&si)) {
1697 gbeauche 1.24 case SIGSEGV_RETURN_SUCCESS:
1698 gbeauche 1.27 return true;
1699    
1700 gbeauche 1.10 #if HAVE_SIGSEGV_SKIP_INSTRUCTION
1701 gbeauche 1.24 case SIGSEGV_RETURN_SKIP_INSTRUCTION:
1702 gbeauche 1.27 // Call the instruction skipper with the register file
1703     // available
1704     if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE)) {
1705     #ifdef HAVE_MACH_EXCEPTIONS
1706     // Unlike UNIX signals where the thread state
1707     // is modified off of the stack, in Mach we
1708     // need to actually call thread_set_state to
1709     // have the register values updated.
1710     krc = thread_set_state(thread,
1711 gbeauche 1.66 SIGSEGV_THREAD_STATE_FLAVOR, (thread_state_t)&state,
1712 gbeauche 1.56 count);
1713     MACH_CHECK_ERROR (thread_set_state, krc);
1714 gbeauche 1.27 #endif
1715     return true;
1716     }
1717 gbeauche 1.24 break;
1718     #endif
1719 nigel 1.43 case SIGSEGV_RETURN_FAILURE:
1720 gbeauche 1.50 // We can't do anything with the fault_address, dump state?
1721     if (sigsegv_state_dumper != 0)
1722 gbeauche 1.67 sigsegv_state_dumper(&si);
1723 gbeauche 1.50 break;
1724 gbeauche 1.10 }
1725 gbeauche 1.27
1726     return false;
1727     }
1728    
1729    
1730     /*
1731     * There are two mechanisms for handling a bad memory access,
1732     * Mach exceptions and UNIX signals. The implementation specific
1733     * code appears below. Its reponsibility is to call handle_badaccess
1734     * which is the routine that handles the fault in an implementation
1735     * agnostic manner. The implementation specific code below is then
1736     * reponsible for checking whether handle_badaccess was able
1737     * to handle the memory access error and perform any implementation
1738     * specific tasks necessary afterwards.
1739     */
1740    
1741     #ifdef HAVE_MACH_EXCEPTIONS
1742     /*
1743     * We need to forward all exceptions that we do not handle.
1744     * This is important, there are many exceptions that may be
1745     * handled by other exception handlers. For example debuggers
1746     * use exceptions and the exception hander is in another
1747     * process in such a case. (Timothy J. Wood states in his
1748     * message to the list that he based this code on that from
1749     * gdb for Darwin.)
1750     */
1751     static inline kern_return_t
1752     forward_exception(mach_port_t thread_port,
1753     mach_port_t task_port,
1754     exception_type_t exception_type,
1755     exception_data_t exception_data,
1756     mach_msg_type_number_t data_count,
1757     ExceptionPorts *oldExceptionPorts)
1758     {
1759     kern_return_t kret;
1760     unsigned int portIndex;
1761     mach_port_t port;
1762     exception_behavior_t behavior;
1763     thread_state_flavor_t flavor;
1764 gbeauche 1.57 thread_state_data_t thread_state;
1765 gbeauche 1.27 mach_msg_type_number_t thread_state_count;
1766    
1767     for (portIndex = 0; portIndex < oldExceptionPorts->maskCount; portIndex++) {
1768     if (oldExceptionPorts->masks[portIndex] & (1 << exception_type)) {
1769     // This handler wants the exception
1770     break;
1771     }
1772     }
1773    
1774     if (portIndex >= oldExceptionPorts->maskCount) {
1775     fprintf(stderr, "No handler for exception_type = %d. Not fowarding\n", exception_type);
1776     return KERN_FAILURE;
1777     }
1778    
1779     port = oldExceptionPorts->handlers[portIndex];
1780     behavior = oldExceptionPorts->behaviors[portIndex];
1781     flavor = oldExceptionPorts->flavors[portIndex];
1782    
1783 gbeauche 1.63 if (!VALID_THREAD_STATE_FLAVOR(flavor)) {
1784     fprintf(stderr, "Invalid thread_state flavor = %d. Not forwarding\n", flavor);
1785     return KERN_FAILURE;
1786     }
1787    
1788 gbeauche 1.27 /*
1789     fprintf(stderr, "forwarding exception, port = 0x%x, behaviour = %d, flavor = %d\n", port, behavior, flavor);
1790     */
1791    
1792     if (behavior != EXCEPTION_DEFAULT) {
1793     thread_state_count = THREAD_STATE_MAX;
1794 gbeauche 1.60 kret = thread_get_state (thread_port, flavor, (natural_t *)&thread_state,
1795 gbeauche 1.27 &thread_state_count);
1796     MACH_CHECK_ERROR (thread_get_state, kret);
1797     }
1798    
1799     switch (behavior) {
1800     case EXCEPTION_DEFAULT:
1801     // fprintf(stderr, "forwarding to exception_raise\n");
1802     kret = exception_raise(port, thread_port, task_port, exception_type,
1803     exception_data, data_count);
1804     MACH_CHECK_ERROR (exception_raise, kret);
1805     break;
1806     case EXCEPTION_STATE:
1807     // fprintf(stderr, "forwarding to exception_raise_state\n");
1808     kret = exception_raise_state(port, exception_type, exception_data,
1809     data_count, &flavor,
1810 gbeauche 1.60 (natural_t *)&thread_state, thread_state_count,
1811     (natural_t *)&thread_state, &thread_state_count);
1812 gbeauche 1.27 MACH_CHECK_ERROR (exception_raise_state, kret);
1813     break;
1814     case EXCEPTION_STATE_IDENTITY:
1815     // fprintf(stderr, "forwarding to exception_raise_state_identity\n");
1816     kret = exception_raise_state_identity(port, thread_port, task_port,
1817     exception_type, exception_data,
1818     data_count, &flavor,
1819 gbeauche 1.60 (natural_t *)&thread_state, thread_state_count,
1820     (natural_t *)&thread_state, &thread_state_count);
1821 gbeauche 1.27 MACH_CHECK_ERROR (exception_raise_state_identity, kret);
1822     break;
1823     default:
1824     fprintf(stderr, "forward_exception got unknown behavior\n");
1825 gbeauche 1.63 kret = KERN_FAILURE;
1826 gbeauche 1.27 break;
1827     }
1828    
1829     if (behavior != EXCEPTION_DEFAULT) {
1830 gbeauche 1.60 kret = thread_set_state (thread_port, flavor, (natural_t *)&thread_state,
1831 gbeauche 1.27 thread_state_count);
1832     MACH_CHECK_ERROR (thread_set_state, kret);
1833     }
1834    
1835 gbeauche 1.63 return kret;
1836 gbeauche 1.27 }
1837    
1838     /*
1839     * This is the code that actually handles the exception.
1840     * It is called by exc_server. For Darwin 5 Apple changed
1841     * this a bit from how this family of functions worked in
1842     * Mach. If you are familiar with that it is a little
1843     * different. The main variation that concerns us here is
1844     * that code is an array of exception specific codes and
1845     * codeCount is a count of the number of codes in the code
1846     * array. In typical Mach all exceptions have a code
1847     * and sub-code. It happens to be the case that for a
1848     * EXC_BAD_ACCESS exception the first entry is the type of
1849     * bad access that occurred and the second entry is the
1850     * faulting address so these entries correspond exactly to
1851     * how the code and sub-code are used on Mach.
1852     *
1853     * This is a MIG interface. No code in Basilisk II should
1854     * call this directley. This has to have external C
1855     * linkage because that is what exc_server expects.
1856     */
1857     kern_return_t
1858     catch_exception_raise(mach_port_t exception_port,
1859     mach_port_t thread,
1860     mach_port_t task,
1861     exception_type_t exception,
1862     exception_data_t code,
1863 gbeauche 1.66 mach_msg_type_number_t code_count)
1864 gbeauche 1.27 {
1865     kern_return_t krc;
1866    
1867 gbeauche 1.66 if (exception == EXC_BAD_ACCESS) {
1868     switch (code[0]) {
1869     case KERN_PROTECTION_FAILURE:
1870     case KERN_INVALID_ADDRESS:
1871     {
1872     #ifdef SIGSEGV_EXCEPTION_STATE_TYPE
1873     SIGSEGV_EXCEPTION_STATE_TYPE exc_state;
1874     mach_msg_type_number_t exc_state_count;
1875     exc_state_count = SIGSEGV_EXCEPTION_STATE_COUNT;
1876     krc = thread_get_state(thread, SIGSEGV_EXCEPTION_STATE_FLAVOR, (natural_t *)&exc_state, &exc_state_count);
1877     MACH_CHECK_ERROR (thread_get_state, krc);
1878     #endif
1879    
1880     if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS))
1881     return KERN_SUCCESS;
1882     break;
1883     }
1884     }
1885 gbeauche 1.27 }
1886    
1887     // In Mach we do not need to remove the exception handler.
1888     // If we forward the exception, eventually some exception handler
1889     // will take care of this exception.
1890 gbeauche 1.66 krc = forward_exception(thread, task, exception, code, code_count, &ports);
1891 gbeauche 1.27
1892     return krc;
1893     }
1894     #endif
1895    
1896     #ifdef HAVE_SIGSEGV_RECOVERY
1897     // Handle bad memory accesses with signal handler
1898     static void sigsegv_handler(SIGSEGV_FAULT_HANDLER_ARGLIST)
1899     {
1900     // Call handler and reinstall the global handler, if required
1901     if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS)) {
1902     #if (defined(HAVE_SIGACTION) ? defined(SIGACTION_NEED_REINSTALL) : defined(SIGNAL_NEED_REINSTALL))
1903     sigsegv_do_install_handler(sig);
1904     #endif
1905     return;
1906     }
1907 gbeauche 1.10
1908 gbeauche 1.27 // Failure: reinstall default handler for "safe" crash
1909 gbeauche 1.1 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
1910 gbeauche 1.27 SIGSEGV_ALL_SIGNALS
1911 gbeauche 1.1 #undef FAULT_HANDLER
1912     }
1913 gbeauche 1.2 #endif
1914 gbeauche 1.1
1915    
1916     /*
1917     * SIGSEGV handler initialization
1918     */
1919    
1920     #if defined(HAVE_SIGINFO_T)
1921     static bool sigsegv_do_install_handler(int sig)
1922     {
1923     // Setup SIGSEGV handler to process writes to frame buffer
1924     #ifdef HAVE_SIGACTION
1925 gbeauche 1.22 struct sigaction sigsegv_sa;
1926     sigemptyset(&sigsegv_sa.sa_mask);
1927     sigsegv_sa.sa_sigaction = sigsegv_handler;
1928     sigsegv_sa.sa_flags = SA_SIGINFO;
1929     return (sigaction(sig, &sigsegv_sa, 0) == 0);
1930 gbeauche 1.1 #else
1931     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
1932     #endif
1933     }
1934 gbeauche 1.2 #endif
1935    
1936     #if defined(HAVE_SIGCONTEXT_SUBTERFUGE)
1937 gbeauche 1.1 static bool sigsegv_do_install_handler(int sig)
1938     {
1939     // Setup SIGSEGV handler to process writes to frame buffer
1940     #ifdef HAVE_SIGACTION
1941 gbeauche 1.22 struct sigaction sigsegv_sa;
1942     sigemptyset(&sigsegv_sa.sa_mask);
1943     sigsegv_sa.sa_handler = (signal_handler)sigsegv_handler;
1944     sigsegv_sa.sa_flags = 0;
1945 gbeauche 1.1 #if !EMULATED_68K && defined(__NetBSD__)
1946 gbeauche 1.22 sigaddset(&sigsegv_sa.sa_mask, SIGALRM);
1947     sigsegv_sa.sa_flags |= SA_ONSTACK;
1948 gbeauche 1.1 #endif
1949 gbeauche 1.22 return (sigaction(sig, &sigsegv_sa, 0) == 0);
1950 gbeauche 1.1 #else
1951     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
1952     #endif
1953     }
1954     #endif
1955    
1956 gbeauche 1.27 #if defined(HAVE_MACH_EXCEPTIONS)
1957     static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
1958     {
1959     /*
1960     * Except for the exception port functions, this should be
1961     * pretty much stock Mach. If later you choose to support
1962     * other Mach's besides Darwin, just check for __MACH__
1963     * here and __APPLE__ where the actual differences are.
1964     */
1965     #if defined(__APPLE__) && defined(__MACH__)
1966     if (sigsegv_fault_handler != NULL) {
1967     sigsegv_fault_handler = handler;
1968     return true;
1969     }
1970    
1971     kern_return_t krc;
1972    
1973     // create the the exception port
1974     krc = mach_port_allocate(mach_task_self(),
1975     MACH_PORT_RIGHT_RECEIVE, &_exceptionPort);
1976     if (krc != KERN_SUCCESS) {
1977     mach_error("mach_port_allocate", krc);
1978     return false;
1979     }
1980    
1981     // add a port send right
1982     krc = mach_port_insert_right(mach_task_self(),
1983     _exceptionPort, _exceptionPort,
1984     MACH_MSG_TYPE_MAKE_SEND);
1985     if (krc != KERN_SUCCESS) {
1986     mach_error("mach_port_insert_right", krc);
1987     return false;
1988     }
1989    
1990     // get the old exception ports
1991     ports.maskCount = sizeof (ports.masks) / sizeof (ports.masks[0]);
1992     krc = thread_get_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, ports.masks,
1993     &ports.maskCount, ports.handlers, ports.behaviors, ports.flavors);
1994     if (krc != KERN_SUCCESS) {
1995     mach_error("thread_get_exception_ports", krc);
1996     return false;
1997     }
1998    
1999     // set the new exception port
2000     //
2001     // We could have used EXCEPTION_STATE_IDENTITY instead of
2002     // EXCEPTION_DEFAULT to get the thread state in the initial
2003     // message, but it turns out that in the common case this is not
2004     // neccessary. If we need it we can later ask for it from the
2005     // suspended thread.
2006     //
2007     // Even with THREAD_STATE_NONE, Darwin provides the program
2008     // counter in the thread state. The comments in the header file
2009     // seem to imply that you can count on the GPR's on an exception
2010     // as well but just to be safe I use MACHINE_THREAD_STATE because
2011     // you have to ask for all of the GPR's anyway just to get the
2012     // program counter. In any case because of update effective
2013     // address from immediate and update address from effective
2014     // addresses of ra and rb modes (as good an name as any for these
2015     // addressing modes) used in PPC instructions, you will need the
2016     // GPR state anyway.
2017     krc = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, _exceptionPort,
2018 gbeauche 1.56 EXCEPTION_DEFAULT, SIGSEGV_THREAD_STATE_FLAVOR);
2019 gbeauche 1.27 if (krc != KERN_SUCCESS) {
2020     mach_error("thread_set_exception_ports", krc);
2021     return false;
2022     }
2023    
2024     // create the exception handler thread
2025     if (pthread_create(&exc_thread, NULL, &handleExceptions, NULL) != 0) {
2026     (void)fprintf(stderr, "creation of exception thread failed\n");
2027     return false;
2028     }
2029    
2030     // do not care about the exception thread any longer, let is run standalone
2031     (void)pthread_detach(exc_thread);
2032    
2033     sigsegv_fault_handler = handler;
2034     return true;
2035     #else
2036     return false;
2037     #endif
2038     }
2039     #endif
2040    
2041 gbeauche 1.48 #ifdef HAVE_WIN32_EXCEPTIONS
2042     static LONG WINAPI main_exception_filter(EXCEPTION_POINTERS *ExceptionInfo)
2043     {
2044     if (sigsegv_fault_handler != NULL
2045     && ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION
2046     && ExceptionInfo->ExceptionRecord->NumberParameters == 2
2047     && handle_badaccess(ExceptionInfo))
2048     return EXCEPTION_CONTINUE_EXECUTION;
2049    
2050     return EXCEPTION_CONTINUE_SEARCH;
2051     }
2052    
2053     #if defined __CYGWIN__ && defined __i386__
2054     /* In Cygwin programs, SetUnhandledExceptionFilter has no effect because Cygwin
2055     installs a global exception handler. We have to dig deep in order to install
2056     our main_exception_filter. */
2057    
2058     /* Data structures for the current thread's exception handler chain.
2059     On the x86 Windows uses register fs, offset 0 to point to the current
2060     exception handler; Cygwin mucks with it, so we must do the same... :-/ */
2061    
2062     /* Magic taken from winsup/cygwin/include/exceptions.h. */
2063    
2064     struct exception_list {
2065     struct exception_list *prev;
2066     int (*handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
2067     };
2068     typedef struct exception_list exception_list;
2069    
2070     /* Magic taken from winsup/cygwin/exceptions.cc. */
2071    
2072     __asm__ (".equ __except_list,0");
2073    
2074     extern exception_list *_except_list __asm__ ("%fs:__except_list");
2075    
2076     /* For debugging. _except_list is not otherwise accessible from gdb. */
2077     static exception_list *
2078     debug_get_except_list ()
2079     {
2080     return _except_list;
2081     }
2082    
2083     /* Cygwin's original exception handler. */
2084     static int (*cygwin_exception_handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
2085    
2086     /* Our exception handler. */
2087     static int
2088     libsigsegv_exception_handler (EXCEPTION_RECORD *exception, void *frame, CONTEXT *context, void *dispatch)
2089     {
2090     EXCEPTION_POINTERS ExceptionInfo;
2091     ExceptionInfo.ExceptionRecord = exception;
2092     ExceptionInfo.ContextRecord = context;
2093     if (main_exception_filter (&ExceptionInfo) == EXCEPTION_CONTINUE_SEARCH)
2094     return cygwin_exception_handler (exception, frame, context, dispatch);
2095     else
2096     return 0;
2097     }
2098    
2099     static void
2100     do_install_main_exception_filter ()
2101     {
2102     /* We cannot insert any handler into the chain, because such handlers
2103     must lie on the stack (?). Instead, we have to replace(!) Cygwin's
2104     global exception handler. */
2105     cygwin_exception_handler = _except_list->handler;
2106     _except_list->handler = libsigsegv_exception_handler;
2107     }
2108    
2109     #else
2110    
2111     static void
2112     do_install_main_exception_filter ()
2113     {
2114     SetUnhandledExceptionFilter ((LPTOP_LEVEL_EXCEPTION_FILTER) &main_exception_filter);
2115     }
2116     #endif
2117    
2118     static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
2119     {
2120     static bool main_exception_filter_installed = false;
2121     if (!main_exception_filter_installed) {
2122     do_install_main_exception_filter();
2123     main_exception_filter_installed = true;
2124     }
2125     sigsegv_fault_handler = handler;
2126     return true;
2127     }
2128     #endif
2129    
2130 gbeauche 1.12 bool sigsegv_install_handler(sigsegv_fault_handler_t handler)
2131 gbeauche 1.1 {
2132 gbeauche 1.27 #if defined(HAVE_SIGSEGV_RECOVERY)
2133 gbeauche 1.1 bool success = true;
2134     #define FAULT_HANDLER(sig) success = success && sigsegv_do_install_handler(sig);
2135     SIGSEGV_ALL_SIGNALS
2136     #undef FAULT_HANDLER
2137 gbeauche 1.27 if (success)
2138     sigsegv_fault_handler = handler;
2139 gbeauche 1.1 return success;
2140 gbeauche 1.48 #elif defined(HAVE_MACH_EXCEPTIONS) || defined(HAVE_WIN32_EXCEPTIONS)
2141 gbeauche 1.27 return sigsegv_do_install_handler(handler);
2142 gbeauche 1.1 #else
2143     // FAIL: no siginfo_t nor sigcontext subterfuge is available
2144     return false;
2145     #endif
2146     }
2147    
2148    
2149     /*
2150     * SIGSEGV handler deinitialization
2151     */
2152    
2153     void sigsegv_deinstall_handler(void)
2154     {
2155 gbeauche 1.27 // We do nothing for Mach exceptions, the thread would need to be
2156     // suspended if not already so, and we might mess with other
2157     // exception handlers that came after we registered ours. There is
2158     // no need to remove the exception handler, in fact this function is
2159     // not called anywhere in Basilisk II.
2160 gbeauche 1.2 #ifdef HAVE_SIGSEGV_RECOVERY
2161 gbeauche 1.12 sigsegv_fault_handler = 0;
2162 gbeauche 1.1 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
2163     SIGSEGV_ALL_SIGNALS
2164     #undef FAULT_HANDLER
2165 gbeauche 1.2 #endif
2166 gbeauche 1.48 #ifdef HAVE_WIN32_EXCEPTIONS
2167     sigsegv_fault_handler = NULL;
2168     #endif
2169 gbeauche 1.1 }
2170    
2171 gbeauche 1.10
2172     /*
2173     * Set callback function when we cannot handle the fault
2174     */
2175    
2176 gbeauche 1.12 void sigsegv_set_dump_state(sigsegv_state_dumper_t handler)
2177 gbeauche 1.10 {
2178 gbeauche 1.12 sigsegv_state_dumper = handler;
2179 gbeauche 1.10 }
2180    
2181    
2182 gbeauche 1.1 /*
2183     * Test program used for configure/test
2184     */
2185    
2186 gbeauche 1.4 #ifdef CONFIGURE_TEST_SIGSEGV_RECOVERY
2187 gbeauche 1.1 #include <stdio.h>
2188     #include <stdlib.h>
2189     #include <fcntl.h>
2190 gbeauche 1.48 #ifdef HAVE_SYS_MMAN_H
2191 gbeauche 1.1 #include <sys/mman.h>
2192 gbeauche 1.48 #endif
2193 gbeauche 1.4 #include "vm_alloc.h"
2194 gbeauche 1.1
2195 gbeauche 1.32 const int REF_INDEX = 123;
2196     const int REF_VALUE = 45;
2197    
2198 gbeauche 1.1 static int page_size;
2199 gbeauche 1.3 static volatile char * page = 0;
2200     static volatile int handler_called = 0;
2201 gbeauche 1.1
2202 gbeauche 1.61 /* Barriers */
2203     #ifdef __GNUC__
2204     #define BARRIER() asm volatile ("" : : : "memory")
2205     #else
2206     #define BARRIER() /* nothing */
2207     #endif
2208    
2209 gbeauche 1.32 #ifdef __GNUC__
2210     // Code range where we expect the fault to come from
2211     static void *b_region, *e_region;
2212     #endif
2213    
2214 gbeauche 1.67 static sigsegv_return_t sigsegv_test_handler(sigsegv_info_t *sip)
2215 gbeauche 1.1 {
2216 gbeauche 1.67 const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
2217     const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip);
2218 gbeauche 1.39 #if DEBUG
2219     printf("sigsegv_test_handler(%p, %p)\n", fault_address, instruction_address);
2220     printf("expected fault at %p\n", page + REF_INDEX);
2221     #ifdef __GNUC__
2222     printf("expected instruction address range: %p-%p\n", b_region, e_region);
2223     #endif
2224     #endif
2225 gbeauche 1.1 handler_called++;
2226 gbeauche 1.32 if ((fault_address - REF_INDEX) != page)
2227 gbeauche 1.29 exit(10);
2228 gbeauche 1.32 #ifdef __GNUC__
2229     // Make sure reported fault instruction address falls into
2230     // expected code range
2231 gbeauche 1.67 if (instruction_address != SIGSEGV_INVALID_ADDRESS
2232 gbeauche 1.32 && ((instruction_address < (sigsegv_address_t)b_region) ||
2233     (instruction_address >= (sigsegv_address_t)e_region)))
2234     exit(11);
2235     #endif
2236 gbeauche 1.4 if (vm_protect((char *)((unsigned long)fault_address & -page_size), page_size, VM_PAGE_READ | VM_PAGE_WRITE) != 0)
2237 gbeauche 1.32 exit(12);
2238 gbeauche 1.24 return SIGSEGV_RETURN_SUCCESS;
2239 gbeauche 1.1 }
2240    
2241 gbeauche 1.10 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
2242 gbeauche 1.67 static sigsegv_return_t sigsegv_insn_handler(sigsegv_info_t *sip)
2243 gbeauche 1.10 {
2244 gbeauche 1.67 const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
2245     const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip);
2246 gbeauche 1.44 #if DEBUG
2247     printf("sigsegv_insn_handler(%p, %p)\n", fault_address, instruction_address);
2248     #endif
2249 gbeauche 1.28 if (((unsigned long)fault_address - (unsigned long)page) < page_size) {
2250     #ifdef __GNUC__
2251     // Make sure reported fault instruction address falls into
2252     // expected code range
2253 gbeauche 1.67 if (instruction_address != SIGSEGV_INVALID_ADDRESS
2254 gbeauche 1.28 && ((instruction_address < (sigsegv_address_t)b_region) ||
2255     (instruction_address >= (sigsegv_address_t)e_region)))
2256     return SIGSEGV_RETURN_FAILURE;
2257     #endif
2258 gbeauche 1.26 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
2259 gbeauche 1.28 }
2260    
2261 gbeauche 1.24 return SIGSEGV_RETURN_FAILURE;
2262 gbeauche 1.10 }
2263 gbeauche 1.34
2264     // More sophisticated tests for instruction skipper
2265     static bool arch_insn_skipper_tests()
2266     {
2267     #if (defined(i386) || defined(__i386__)) || defined(__x86_64__)
2268     static const unsigned char code[] = {
2269     0x8a, 0x00, // mov (%eax),%al
2270     0x8a, 0x2c, 0x18, // mov (%eax,%ebx,1),%ch
2271     0x88, 0x20, // mov %ah,(%eax)
2272     0x88, 0x08, // mov %cl,(%eax)
2273     0x66, 0x8b, 0x00, // mov (%eax),%ax
2274     0x66, 0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%cx
2275     0x66, 0x89, 0x00, // mov %ax,(%eax)
2276     0x66, 0x89, 0x0c, 0x18, // mov %cx,(%eax,%ebx,1)
2277     0x8b, 0x00, // mov (%eax),%eax
2278     0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%ecx
2279     0x89, 0x00, // mov %eax,(%eax)
2280     0x89, 0x0c, 0x18, // mov %ecx,(%eax,%ebx,1)
2281     #if defined(__x86_64__)
2282     0x44, 0x8a, 0x00, // mov (%rax),%r8b
2283     0x44, 0x8a, 0x20, // mov (%rax),%r12b
2284     0x42, 0x8a, 0x3c, 0x10, // mov (%rax,%r10,1),%dil
2285     0x44, 0x88, 0x00, // mov %r8b,(%rax)
2286     0x44, 0x88, 0x20, // mov %r12b,(%rax)
2287     0x42, 0x88, 0x3c, 0x10, // mov %dil,(%rax,%r10,1)
2288     0x66, 0x44, 0x8b, 0x00, // mov (%rax),%r8w
2289     0x66, 0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%cx
2290     0x66, 0x44, 0x89, 0x00, // mov %r8w,(%rax)
2291     0x66, 0x42, 0x89, 0x0c, 0x10, // mov %cx,(%rax,%r10,1)
2292     0x44, 0x8b, 0x00, // mov (%rax),%r8d
2293     0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%ecx
2294     0x44, 0x89, 0x00, // mov %r8d,(%rax)
2295     0x42, 0x89, 0x0c, 0x10, // mov %ecx,(%rax,%r10,1)
2296     0x48, 0x8b, 0x08, // mov (%rax),%rcx
2297     0x4c, 0x8b, 0x18, // mov (%rax),%r11
2298     0x4a, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%rcx
2299     0x4e, 0x8b, 0x1c, 0x10, // mov (%rax,%r10,1),%r11
2300     0x48, 0x89, 0x08, // mov %rcx,(%rax)
2301     0x4c, 0x89, 0x18, // mov %r11,(%rax)
2302     0x4a, 0x89, 0x0c, 0x10, // mov %rcx,(%rax,%r10,1)
2303     0x4e, 0x89, 0x1c, 0x10, // mov %r11,(%rax,%r10,1)
2304 gbeauche 1.62 0x63, 0x47, 0x04, // movslq 4(%rdi),%eax
2305     0x48, 0x63, 0x47, 0x04, // movslq 4(%rdi),%rax
2306 gbeauche 1.34 #endif
2307     0 // end
2308     };
2309     const int N_REGS = 20;
2310     unsigned long regs[N_REGS];
2311     for (int i = 0; i < N_REGS; i++)
2312     regs[i] = i;
2313     const unsigned long start_code = (unsigned long)&code;
2314     regs[X86_REG_EIP] = start_code;
2315     while ((regs[X86_REG_EIP] - start_code) < (sizeof(code) - 1)
2316     && ix86_skip_instruction(regs))
2317     ; /* simply iterate */
2318     return (regs[X86_REG_EIP] - start_code) == (sizeof(code) - 1);
2319     #endif
2320     return true;
2321     }
2322 gbeauche 1.10 #endif
2323    
2324 gbeauche 1.1 int main(void)
2325     {
2326 gbeauche 1.4 if (vm_init() < 0)
2327 gbeauche 1.1 return 1;
2328    
2329 gbeauche 1.54 page_size = vm_get_page_size();
2330 gbeauche 1.4 if ((page = (char *)vm_acquire(page_size)) == VM_MAP_FAILED)
2331 gbeauche 1.29 return 2;
2332 gbeauche 1.4
2333 gbeauche 1.32 memset((void *)page, 0, page_size);
2334 gbeauche 1.4 if (vm_protect((char *)page, page_size, VM_PAGE_READ) < 0)
2335 gbeauche 1.29 return 3;
2336 gbeauche 1.1
2337     if (!sigsegv_install_handler(sigsegv_test_handler))
2338 gbeauche 1.29 return 4;
2339 gbeauche 1.1
2340 gbeauche 1.32 #ifdef __GNUC__
2341     b_region = &&L_b_region1;
2342     e_region = &&L_e_region1;
2343     #endif
2344     L_b_region1:
2345     page[REF_INDEX] = REF_VALUE;
2346     if (page[REF_INDEX] != REF_VALUE)
2347     exit(20);
2348     page[REF_INDEX] = REF_VALUE;
2349 gbeauche 1.61 BARRIER();
2350 gbeauche 1.32 L_e_region1:
2351    
2352 gbeauche 1.1 if (handler_called != 1)
2353 gbeauche 1.29 return 5;
2354 gbeauche 1.10
2355     #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
2356     if (!sigsegv_install_handler(sigsegv_insn_handler))
2357 gbeauche 1.29 return 6;
2358 gbeauche 1.10
2359 gbeauche 1.17 if (vm_protect((char *)page, page_size, VM_PAGE_READ | VM_PAGE_WRITE) < 0)
2360 gbeauche 1.29 return 7;
2361 gbeauche 1.10
2362     for (int i = 0; i < page_size; i++)
2363     page[i] = (i + 1) % page_size;
2364    
2365     if (vm_protect((char *)page, page_size, VM_PAGE_NOACCESS) < 0)
2366 gbeauche 1.29 return 8;
2367 gbeauche 1.10
2368     #define TEST_SKIP_INSTRUCTION(TYPE) do { \
2369 gbeauche 1.34 const unsigned long TAG = 0x12345678 | \
2370     (sizeof(long) == 8 ? 0x9abcdef0UL << 31 : 0); \
2371 gbeauche 1.10 TYPE data = *((TYPE *)(page + sizeof(TYPE))); \
2372 gbeauche 1.34 volatile unsigned long effect = data + TAG; \
2373 gbeauche 1.10 if (effect != TAG) \
2374 gbeauche 1.29 return 9; \
2375 gbeauche 1.10 } while (0)
2376    
2377 gbeauche 1.28 #ifdef __GNUC__
2378 gbeauche 1.32 b_region = &&L_b_region2;
2379     e_region = &&L_e_region2;
2380 gbeauche 1.28 #endif
2381 gbeauche 1.32 L_b_region2:
2382 gbeauche 1.10 TEST_SKIP_INSTRUCTION(unsigned char);
2383     TEST_SKIP_INSTRUCTION(unsigned short);
2384     TEST_SKIP_INSTRUCTION(unsigned int);
2385 gbeauche 1.34 TEST_SKIP_INSTRUCTION(unsigned long);
2386 gbeauche 1.44 TEST_SKIP_INSTRUCTION(signed char);
2387     TEST_SKIP_INSTRUCTION(signed short);
2388     TEST_SKIP_INSTRUCTION(signed int);
2389     TEST_SKIP_INSTRUCTION(signed long);
2390 gbeauche 1.61 BARRIER();
2391 gbeauche 1.32 L_e_region2:
2392 gbeauche 1.1
2393 gbeauche 1.34 if (!arch_insn_skipper_tests())
2394     return 20;
2395 gbeauche 1.35 #endif
2396 gbeauche 1.34
2397 gbeauche 1.4 vm_exit();
2398 gbeauche 1.1 return 0;
2399     }
2400     #endif