ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.49
Committed: 2004-12-02T23:29:52Z (20 years ago) by gbeauche
Branch: MAIN
Changes since 1.48: +20 -6 lines
Log Message:
ppc64 fixes

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