ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.50
Committed: 2004-12-11T13:07:38Z (19 years, 10 months ago) by gbeauche
Branch: MAIN
Changes since 1.49: +8 -5 lines
Log Message:
Check that we can really read at the faulty eip in Windows prior to decoding
the instruction. Also fix the unrecoverable fault dump to really be useful.

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