ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.56
Committed: 2005-06-12T21:47:46Z (19 years, 3 months ago) by gbeauche
Branch: MAIN
CVS Tags: nigel-build-17
Changes since 1.55: +46 -32 lines
Log Message:
Mach exception recovery and instruction skipping for Darwin/x86.

File Contents

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