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