ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.38
Committed: 2003-12-20T10:06:18Z (20 years, 11 months ago) by gbeauche
Branch: MAIN
Changes since 1.37: +167 -0 lines
Log Message:
MIPS instruction skipper. TODO: check LWL/LWR semantics.

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.7 * Basilisk II (C) 1997-2002 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.1 #include <signal.h>
40     #include "sigsegv.h"
41    
42 gbeauche 1.22 #ifndef NO_STD_NAMESPACE
43     using std::list;
44     #endif
45    
46 gbeauche 1.1 // Return value type of a signal handler (standard type if not defined)
47     #ifndef RETSIGTYPE
48     #define RETSIGTYPE void
49     #endif
50    
51     // Type of the system signal handler
52     typedef RETSIGTYPE (*signal_handler)(int);
53    
54     // User's SIGSEGV handler
55 gbeauche 1.12 static sigsegv_fault_handler_t sigsegv_fault_handler = 0;
56 gbeauche 1.1
57 gbeauche 1.10 // Function called to dump state if we can't handle the fault
58 gbeauche 1.12 static sigsegv_state_dumper_t sigsegv_state_dumper = 0;
59 gbeauche 1.10
60 gbeauche 1.1 // Actual SIGSEGV handler installer
61     static bool sigsegv_do_install_handler(int sig);
62    
63    
64     /*
65 gbeauche 1.14 * Instruction decoding aids
66     */
67    
68     // Transfer size
69     enum transfer_size_t {
70     SIZE_UNKNOWN,
71     SIZE_BYTE,
72 gbeauche 1.34 SIZE_WORD, // 2 bytes
73     SIZE_LONG, // 4 bytes
74     SIZE_QUAD, // 8 bytes
75 gbeauche 1.14 };
76    
77 gbeauche 1.23 // Transfer type
78     typedef sigsegv_transfer_type_t transfer_type_t;
79    
80 gbeauche 1.14 #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__))
81     // Addressing mode
82     enum addressing_mode_t {
83     MODE_UNKNOWN,
84     MODE_NORM,
85     MODE_U,
86     MODE_X,
87     MODE_UX
88     };
89    
90     // Decoded instruction
91     struct instruction_t {
92     transfer_type_t transfer_type;
93     transfer_size_t transfer_size;
94     addressing_mode_t addr_mode;
95     unsigned int addr;
96     char ra, rd;
97     };
98    
99     static void powerpc_decode_instruction(instruction_t *instruction, unsigned int nip, unsigned int * gpr)
100     {
101     // Get opcode and divide into fields
102     unsigned int opcode = *((unsigned int *)nip);
103     unsigned int primop = opcode >> 26;
104     unsigned int exop = (opcode >> 1) & 0x3ff;
105     unsigned int ra = (opcode >> 16) & 0x1f;
106     unsigned int rb = (opcode >> 11) & 0x1f;
107     unsigned int rd = (opcode >> 21) & 0x1f;
108     signed int imm = (signed short)(opcode & 0xffff);
109    
110     // Analyze opcode
111 gbeauche 1.22 transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
112 gbeauche 1.14 transfer_size_t transfer_size = SIZE_UNKNOWN;
113     addressing_mode_t addr_mode = MODE_UNKNOWN;
114     switch (primop) {
115     case 31:
116     switch (exop) {
117     case 23: // lwzx
118 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
119 gbeauche 1.14 case 55: // lwzux
120 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
121 gbeauche 1.14 case 87: // lbzx
122 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
123 gbeauche 1.14 case 119: // lbzux
124 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
125 gbeauche 1.14 case 151: // stwx
126 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
127 gbeauche 1.14 case 183: // stwux
128 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
129 gbeauche 1.14 case 215: // stbx
130 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
131 gbeauche 1.14 case 247: // stbux
132 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
133 gbeauche 1.14 case 279: // lhzx
134 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
135 gbeauche 1.14 case 311: // lhzux
136 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
137 gbeauche 1.14 case 343: // lhax
138 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
139 gbeauche 1.14 case 375: // lhaux
140 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
141 gbeauche 1.14 case 407: // sthx
142 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
143 gbeauche 1.14 case 439: // sthux
144 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
145 gbeauche 1.14 }
146     break;
147    
148     case 32: // lwz
149 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
150 gbeauche 1.14 case 33: // lwzu
151 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
152 gbeauche 1.14 case 34: // lbz
153 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
154 gbeauche 1.14 case 35: // lbzu
155 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
156 gbeauche 1.14 case 36: // stw
157 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
158 gbeauche 1.14 case 37: // stwu
159 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
160 gbeauche 1.14 case 38: // stb
161 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
162 gbeauche 1.14 case 39: // stbu
163 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
164 gbeauche 1.14 case 40: // lhz
165 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
166 gbeauche 1.14 case 41: // lhzu
167 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
168 gbeauche 1.14 case 42: // lha
169 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
170 gbeauche 1.14 case 43: // lhau
171 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
172 gbeauche 1.14 case 44: // sth
173 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
174 gbeauche 1.14 case 45: // sthu
175 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
176 gbeauche 1.14 }
177    
178     // Calculate effective address
179     unsigned int addr = 0;
180     switch (addr_mode) {
181     case MODE_X:
182     case MODE_UX:
183     if (ra == 0)
184     addr = gpr[rb];
185     else
186     addr = gpr[ra] + gpr[rb];
187     break;
188     case MODE_NORM:
189     case MODE_U:
190     if (ra == 0)
191     addr = (signed int)(signed short)imm;
192     else
193     addr = gpr[ra] + (signed int)(signed short)imm;
194     break;
195     default:
196     break;
197     }
198    
199     // Commit decoded instruction
200     instruction->addr = addr;
201     instruction->addr_mode = addr_mode;
202     instruction->transfer_type = transfer_type;
203     instruction->transfer_size = transfer_size;
204     instruction->ra = ra;
205     instruction->rd = rd;
206     }
207     #endif
208    
209    
210     /*
211 gbeauche 1.1 * OS-dependant SIGSEGV signals support section
212     */
213    
214     #if HAVE_SIGINFO_T
215     // Generic extended signal handler
216 cebix 1.8 #if defined(__NetBSD__) || defined(__FreeBSD__)
217     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
218     #else
219 gbeauche 1.1 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
220 cebix 1.8 #endif
221 gbeauche 1.5 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, siginfo_t *sip, void *scp
222 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 siginfo_t *sip, void *scp
223     #define SIGSEGV_FAULT_HANDLER_ARGS sip, scp
224 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS sip->si_addr
225 gbeauche 1.37 #if (defined(sgi) || defined(__sgi))
226     #include <ucontext.h>
227     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
228     #define SIGSEGV_FAULT_INSTRUCTION (unsigned long)SIGSEGV_CONTEXT_REGS[CTX_EPC]
229 gbeauche 1.38 #if (defined(mips) || defined(__mips))
230     #define SIGSEGV_REGISTER_FILE SIGSEGV_CONTEXT_REGS
231     #define SIGSEGV_SKIP_INSTRUCTION mips_skip_instruction
232     #endif
233 gbeauche 1.37 #endif
234 gbeauche 1.32 #if defined(__sun__)
235     #if (defined(sparc) || defined(__sparc__))
236     #include <sys/ucontext.h>
237     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
238     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[REG_PC]
239     #endif
240     #endif
241 gbeauche 1.33 #if defined(__FreeBSD__)
242 gbeauche 1.17 #if (defined(i386) || defined(__i386__))
243     #define SIGSEGV_FAULT_INSTRUCTION (((struct sigcontext *)scp)->sc_eip)
244 gbeauche 1.34 #define SIGSEGV_REGISTER_FILE ((unsigned long *)&(((struct sigcontext *)scp)->sc_edi)) /* EDI is the first GPR (even below EIP) in sigcontext */
245 gbeauche 1.17 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
246 gbeauche 1.19 #endif
247 gbeauche 1.17 #endif
248 gbeauche 1.5 #if defined(__linux__)
249 gbeauche 1.6 #if (defined(i386) || defined(__i386__))
250     #include <sys/ucontext.h>
251 gbeauche 1.14 #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
252     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[14] /* should use REG_EIP instead */
253 gbeauche 1.34 #define SIGSEGV_REGISTER_FILE (unsigned long *)SIGSEGV_CONTEXT_REGS
254 gbeauche 1.10 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
255 gbeauche 1.6 #endif
256 gbeauche 1.20 #if (defined(x86_64) || defined(__x86_64__))
257     #include <sys/ucontext.h>
258     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
259     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[16] /* should use REG_RIP instead */
260     #define SIGSEGV_REGISTER_FILE (unsigned long *)SIGSEGV_CONTEXT_REGS
261 gbeauche 1.34 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
262 gbeauche 1.20 #endif
263 gbeauche 1.5 #if (defined(ia64) || defined(__ia64__))
264     #define SIGSEGV_FAULT_INSTRUCTION (((struct sigcontext *)scp)->sc_ip & ~0x3ULL) /* slot number is in bits 0 and 1 */
265     #endif
266 gbeauche 1.9 #if (defined(powerpc) || defined(__powerpc__))
267     #include <sys/ucontext.h>
268 gbeauche 1.14 #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.regs)
269     #define SIGSEGV_FAULT_INSTRUCTION (SIGSEGV_CONTEXT_REGS->nip)
270     #define SIGSEGV_REGISTER_FILE (unsigned int *)&SIGSEGV_CONTEXT_REGS->nip, (unsigned int *)(SIGSEGV_CONTEXT_REGS->gpr)
271 gbeauche 1.13 #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
272 gbeauche 1.9 #endif
273 gbeauche 1.5 #endif
274 gbeauche 1.1 #endif
275    
276     #if HAVE_SIGCONTEXT_SUBTERFUGE
277     // Linux kernels prior to 2.4 ?
278     #if defined(__linux__)
279     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
280     #if (defined(i386) || defined(__i386__))
281     #include <asm/sigcontext.h>
282     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext scs
283 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 struct sigcontext *scp
284     #define SIGSEGV_FAULT_HANDLER_ARGS &scs
285     #define SIGSEGV_FAULT_ADDRESS scp->cr2
286     #define SIGSEGV_FAULT_INSTRUCTION scp->eip
287 gbeauche 1.34 #define SIGSEGV_REGISTER_FILE (unsigned long *)scp
288 gbeauche 1.10 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
289 gbeauche 1.1 #endif
290     #if (defined(sparc) || defined(__sparc__))
291     #include <asm/sigcontext.h>
292 gbeauche 1.5 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp, char *addr
293 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp, addr
294 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS addr
295     #endif
296     #if (defined(powerpc) || defined(__powerpc__))
297     #include <asm/sigcontext.h>
298 gbeauche 1.4 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext *scp
299 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, scp
300 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS scp->regs->dar
301     #define SIGSEGV_FAULT_INSTRUCTION scp->regs->nip
302 gbeauche 1.14 #define SIGSEGV_REGISTER_FILE (unsigned int *)&scp->regs->nip, (unsigned int *)(scp->regs->gpr)
303 gbeauche 1.13 #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
304 gbeauche 1.1 #endif
305 gbeauche 1.4 #if (defined(alpha) || defined(__alpha__))
306     #include <asm/sigcontext.h>
307     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
308 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
309 gbeauche 1.4 #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
310     #define SIGSEGV_FAULT_INSTRUCTION scp->sc_pc
311     #endif
312 gbeauche 1.1 #endif
313    
314     // Irix 5 or 6 on MIPS
315 gbeauche 1.37 #if (defined(sgi) || defined(__sgi)) && (defined(SYSTYPE_SVR4) || defined(_SYSTYPE_SVR4))
316 gbeauche 1.11 #include <ucontext.h>
317 gbeauche 1.1 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
318 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
319 gbeauche 1.37 #define SIGSEGV_FAULT_ADDRESS (unsigned long)scp->sc_badvaddr
320     #define SIGSEGV_FAULT_INSTRUCTION (unsigned long)scp->sc_pc
321 gbeauche 1.1 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
322     #endif
323    
324 gbeauche 1.11 // HP-UX
325     #if (defined(hpux) || defined(__hpux__))
326     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
327 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
328 gbeauche 1.11 #define SIGSEGV_FAULT_ADDRESS scp->sc_sl.sl_ss.ss_narrow.ss_cr21
329     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV) FAULT_HANDLER(SIGBUS)
330     #endif
331    
332 gbeauche 1.1 // OSF/1 on Alpha
333     #if defined(__osf__)
334 gbeauche 1.11 #include <ucontext.h>
335 gbeauche 1.1 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
336 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
337 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS scp->sc_traparg_a0
338     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
339     #endif
340    
341     // AIX
342     #if defined(_AIX)
343     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
344 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
345 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS scp->sc_jmpbuf.jmp_context.o_vaddr
346     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
347     #endif
348    
349 gbeauche 1.33 // NetBSD
350     #if defined(__NetBSD__)
351 gbeauche 1.1 #if (defined(m68k) || defined(__m68k__))
352     #include <m68k/frame.h>
353     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
354 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
355 gbeauche 1.14 #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
356 gbeauche 1.1 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
357 gbeauche 1.14
358     // Use decoding scheme from BasiliskII/m68k native
359     static sigsegv_address_t get_fault_address(struct sigcontext *scp)
360     {
361     struct sigstate {
362     int ss_flags;
363     struct frame ss_frame;
364     };
365     struct sigstate *state = (struct sigstate *)scp->sc_ap;
366     char *fault_addr;
367     switch (state->ss_frame.f_format) {
368     case 7: /* 68040 access error */
369     /* "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown */
370     fault_addr = state->ss_frame.f_fmt7.f_fa;
371     break;
372     default:
373     fault_addr = (char *)code;
374     break;
375     }
376     return (sigsegv_address_t)fault_addr;
377     }
378 gbeauche 1.33 #endif
379     #if (defined(alpha) || defined(__alpha__))
380     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
381     #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
382     #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
383     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
384     #endif
385     #if (defined(i386) || defined(__i386__))
386     #error "FIXME: need to decode instruction and compute EA"
387     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
388     #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
389     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
390     #endif
391     #endif
392     #if defined(__FreeBSD__)
393     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
394     #if (defined(i386) || defined(__i386__))
395     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp, char *addr
396 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp, addr
397 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS addr
398 gbeauche 1.33 #define SIGSEGV_FAULT_INSTRUCTION scp->sc_eip
399 gbeauche 1.34 #define SIGSEGV_REGISTER_FILE ((unsigned long *)&scp->sc_edi)
400 gbeauche 1.33 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
401 gbeauche 1.1 #endif
402     #endif
403 gbeauche 1.33
404     // Extract fault address out of a sigcontext
405     #if (defined(alpha) || defined(__alpha__))
406     // From Boehm's GC 6.0alpha8
407     static sigsegv_address_t get_fault_address(struct sigcontext *scp)
408     {
409     unsigned int instruction = *((unsigned int *)(scp->sc_pc));
410     unsigned long fault_address = scp->sc_regs[(instruction >> 16) & 0x1f];
411     fault_address += (signed long)(signed short)(instruction & 0xffff);
412     return (sigsegv_address_t)fault_address;
413     }
414     #endif
415    
416 gbeauche 1.4
417 gbeauche 1.27 // MacOS X, not sure which version this works in. Under 10.1
418     // vm_protect does not appear to work from a signal handler. Under
419     // 10.2 signal handlers get siginfo type arguments but the si_addr
420     // field is the address of the faulting instruction and not the
421     // address that caused the SIGBUS. Maybe this works in 10.0? In any
422     // case with Mach exception handlers there is a way to do what this
423     // was meant to do.
424     #ifndef HAVE_MACH_EXCEPTIONS
425 gbeauche 1.4 #if defined(__APPLE__) && defined(__MACH__)
426     #if (defined(ppc) || defined(__ppc__))
427     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
428 gbeauche 1.27 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
429 gbeauche 1.4 #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
430     #define SIGSEGV_FAULT_INSTRUCTION scp->sc_ir
431     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
432 gbeauche 1.14 #define SIGSEGV_REGISTER_FILE (unsigned int *)&scp->sc_ir, &((unsigned int *) scp->sc_regs)[2]
433     #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
434 gbeauche 1.4
435 gbeauche 1.14 // Use decoding scheme from SheepShaver
436 gbeauche 1.4 static sigsegv_address_t get_fault_address(struct sigcontext *scp)
437     {
438 gbeauche 1.14 unsigned int nip = (unsigned int) scp->sc_ir;
439     unsigned int * gpr = &((unsigned int *) scp->sc_regs)[2];
440     instruction_t instr;
441    
442     powerpc_decode_instruction(&instr, nip, gpr);
443     return (sigsegv_address_t)instr.addr;
444 gbeauche 1.4 }
445     #endif
446     #endif
447 gbeauche 1.1 #endif
448 gbeauche 1.27 #endif
449    
450     #if HAVE_MACH_EXCEPTIONS
451    
452     // This can easily be extended to other Mach systems, but really who
453     // uses HURD (oops GNU/HURD), Darwin/x86, NextStep, Rhapsody, or CMU
454     // Mach 2.5/3.0?
455     #if defined(__APPLE__) && defined(__MACH__)
456    
457     #include <sys/types.h>
458     #include <stdlib.h>
459     #include <stdio.h>
460     #include <pthread.h>
461    
462     /*
463     * If you are familiar with MIG then you will understand the frustration
464     * that was necessary to get these embedded into C++ code by hand.
465     */
466     extern "C" {
467     #include <mach/mach.h>
468     #include <mach/mach_error.h>
469    
470     extern boolean_t exc_server(mach_msg_header_t *, mach_msg_header_t *);
471     extern kern_return_t catch_exception_raise(mach_port_t, mach_port_t,
472     mach_port_t, exception_type_t, exception_data_t, mach_msg_type_number_t);
473     extern kern_return_t exception_raise(mach_port_t, mach_port_t, mach_port_t,
474     exception_type_t, exception_data_t, mach_msg_type_number_t);
475     extern kern_return_t exception_raise_state(mach_port_t, exception_type_t,
476     exception_data_t, mach_msg_type_number_t, thread_state_flavor_t *,
477     thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t *);
478     extern kern_return_t exception_raise_state_identity(mach_port_t, mach_port_t, mach_port_t,
479     exception_type_t, exception_data_t, mach_msg_type_number_t, thread_state_flavor_t *,
480     thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t *);
481     }
482    
483     // Could make this dynamic by looking for a result of MIG_ARRAY_TOO_LARGE
484     #define HANDLER_COUNT 64
485    
486     // structure to tuck away existing exception handlers
487     typedef struct _ExceptionPorts {
488     mach_msg_type_number_t maskCount;
489     exception_mask_t masks[HANDLER_COUNT];
490     exception_handler_t handlers[HANDLER_COUNT];
491     exception_behavior_t behaviors[HANDLER_COUNT];
492     thread_state_flavor_t flavors[HANDLER_COUNT];
493     } ExceptionPorts;
494    
495     // exception handler thread
496     static pthread_t exc_thread;
497    
498     // place where old exception handler info is stored
499     static ExceptionPorts ports;
500    
501     // our exception port
502     static mach_port_t _exceptionPort = MACH_PORT_NULL;
503    
504     #define MACH_CHECK_ERROR(name,ret) \
505     if (ret != KERN_SUCCESS) { \
506     mach_error(#name, ret); \
507     exit (1); \
508     }
509    
510     #define SIGSEGV_FAULT_ADDRESS code[1]
511     #define SIGSEGV_FAULT_INSTRUCTION get_fault_instruction(thread, state)
512 gbeauche 1.31 #define SIGSEGV_FAULT_HANDLER_INVOKE(ADDR, IP) ((code[0] == KERN_PROTECTION_FAILURE) ? sigsegv_fault_handler(ADDR, IP) : SIGSEGV_RETURN_FAILURE)
513 gbeauche 1.27 #define SIGSEGV_FAULT_HANDLER_ARGLIST mach_port_t thread, exception_data_t code, ppc_thread_state_t *state
514     #define SIGSEGV_FAULT_HANDLER_ARGS thread, code, &state
515     #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
516     #define SIGSEGV_REGISTER_FILE &state->srr0, &state->r0
517    
518     // Given a suspended thread, stuff the current instruction and
519     // registers into state.
520     //
521     // It would have been nice to have this be ppc/x86 independant which
522     // could have been done easily with a thread_state_t instead of
523     // ppc_thread_state_t, but because of the way this is called it is
524     // easier to do it this way.
525     #if (defined(ppc) || defined(__ppc__))
526     static inline sigsegv_address_t get_fault_instruction(mach_port_t thread, ppc_thread_state_t *state)
527     {
528     kern_return_t krc;
529     mach_msg_type_number_t count;
530    
531     count = MACHINE_THREAD_STATE_COUNT;
532     krc = thread_get_state(thread, MACHINE_THREAD_STATE, (thread_state_t)state, &count);
533     MACH_CHECK_ERROR (thread_get_state, krc);
534    
535     return (sigsegv_address_t)state->srr0;
536     }
537     #endif
538    
539     // Since there can only be one exception thread running at any time
540     // this is not a problem.
541     #define MSG_SIZE 512
542     static char msgbuf[MSG_SIZE];
543     static char replybuf[MSG_SIZE];
544    
545     /*
546     * This is the entry point for the exception handler thread. The job
547     * of this thread is to wait for exception messages on the exception
548     * port that was setup beforehand and to pass them on to exc_server.
549     * exc_server is a MIG generated function that is a part of Mach.
550     * Its job is to decide what to do with the exception message. In our
551     * case exc_server calls catch_exception_raise on our behalf. After
552     * exc_server returns, it is our responsibility to send the reply.
553     */
554     static void *
555     handleExceptions(void *priv)
556     {
557     mach_msg_header_t *msg, *reply;
558     kern_return_t krc;
559    
560     msg = (mach_msg_header_t *)msgbuf;
561     reply = (mach_msg_header_t *)replybuf;
562    
563     for (;;) {
564     krc = mach_msg(msg, MACH_RCV_MSG, MSG_SIZE, MSG_SIZE,
565     _exceptionPort, 0, MACH_PORT_NULL);
566     MACH_CHECK_ERROR(mach_msg, krc);
567    
568     if (!exc_server(msg, reply)) {
569     fprintf(stderr, "exc_server hated the message\n");
570     exit(1);
571     }
572    
573     krc = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0,
574     msg->msgh_local_port, 0, MACH_PORT_NULL);
575     if (krc != KERN_SUCCESS) {
576     fprintf(stderr, "Error sending message to original reply port, krc = %d, %s",
577     krc, mach_error_string(krc));
578     exit(1);
579     }
580     }
581     }
582     #endif
583     #endif
584 gbeauche 1.1
585 gbeauche 1.14
586     /*
587     * Instruction skipping
588     */
589    
590 gbeauche 1.10 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
591     // Decode and skip X86 instruction
592 gbeauche 1.34 #if (defined(i386) || defined(__i386__)) || defined(__x86_64__)
593 gbeauche 1.10 #if defined(__linux__)
594     enum {
595 gbeauche 1.34 #if (defined(i386) || defined(__i386__))
596 gbeauche 1.10 X86_REG_EIP = 14,
597     X86_REG_EAX = 11,
598     X86_REG_ECX = 10,
599     X86_REG_EDX = 9,
600     X86_REG_EBX = 8,
601     X86_REG_ESP = 7,
602     X86_REG_EBP = 6,
603     X86_REG_ESI = 5,
604     X86_REG_EDI = 4
605 gbeauche 1.34 #endif
606     #if defined(__x86_64__)
607     X86_REG_R8 = 0,
608     X86_REG_R9 = 1,
609     X86_REG_R10 = 2,
610     X86_REG_R11 = 3,
611     X86_REG_R12 = 4,
612     X86_REG_R13 = 5,
613     X86_REG_R14 = 6,
614     X86_REG_R15 = 7,
615     X86_REG_EDI = 8,
616     X86_REG_ESI = 9,
617     X86_REG_EBP = 10,
618     X86_REG_EBX = 11,
619     X86_REG_EDX = 12,
620     X86_REG_EAX = 13,
621     X86_REG_ECX = 14,
622     X86_REG_ESP = 15,
623     X86_REG_EIP = 16
624     #endif
625 gbeauche 1.10 };
626     #endif
627 gbeauche 1.17 #if defined(__NetBSD__) || defined(__FreeBSD__)
628     enum {
629 gbeauche 1.34 #if (defined(i386) || defined(__i386__))
630 gbeauche 1.17 X86_REG_EIP = 10,
631     X86_REG_EAX = 7,
632     X86_REG_ECX = 6,
633     X86_REG_EDX = 5,
634     X86_REG_EBX = 4,
635     X86_REG_ESP = 13,
636     X86_REG_EBP = 2,
637     X86_REG_ESI = 1,
638     X86_REG_EDI = 0
639 gbeauche 1.34 #endif
640 gbeauche 1.17 };
641     #endif
642 gbeauche 1.10 // FIXME: this is partly redundant with the instruction decoding phase
643     // to discover transfer type and register number
644     static inline int ix86_step_over_modrm(unsigned char * p)
645     {
646     int mod = (p[0] >> 6) & 3;
647     int rm = p[0] & 7;
648     int offset = 0;
649    
650     // ModR/M Byte
651     switch (mod) {
652     case 0: // [reg]
653     if (rm == 5) return 4; // disp32
654     break;
655     case 1: // disp8[reg]
656     offset = 1;
657     break;
658     case 2: // disp32[reg]
659     offset = 4;
660     break;
661     case 3: // register
662     return 0;
663     }
664    
665     // SIB Byte
666     if (rm == 4) {
667     if (mod == 0 && (p[1] & 7) == 5)
668     offset = 5; // disp32[index]
669     else
670     offset++;
671     }
672    
673     return offset;
674     }
675    
676 gbeauche 1.34 static bool ix86_skip_instruction(unsigned long * regs)
677 gbeauche 1.10 {
678 gbeauche 1.14 unsigned char * eip = (unsigned char *)regs[X86_REG_EIP];
679 gbeauche 1.10
680     if (eip == 0)
681     return false;
682    
683 gbeauche 1.22 transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
684 gbeauche 1.14 transfer_size_t transfer_size = SIZE_LONG;
685 gbeauche 1.10
686     int reg = -1;
687     int len = 0;
688 gbeauche 1.34
689     #if DEBUG
690     printf("IP: %p [%02x %02x %02x %02x...]\n",
691     eip, eip[0], eip[1], eip[2], eip[3]);
692     #endif
693    
694 gbeauche 1.10 // Operand size prefix
695     if (*eip == 0x66) {
696     eip++;
697     len++;
698     transfer_size = SIZE_WORD;
699     }
700    
701 gbeauche 1.34 // REX prefix
702     #if defined(__x86_64__)
703     struct rex_t {
704     unsigned char W;
705     unsigned char R;
706     unsigned char X;
707     unsigned char B;
708     };
709     rex_t rex = { 0, 0, 0, 0 };
710     bool has_rex = false;
711     if ((*eip & 0xf0) == 0x40) {
712     has_rex = true;
713     const unsigned char b = *eip;
714     rex.W = b & (1 << 3);
715     rex.R = b & (1 << 2);
716     rex.X = b & (1 << 1);
717     rex.B = b & (1 << 0);
718     #if DEBUG
719     printf("REX: %c,%c,%c,%c\n",
720     rex.W ? 'W' : '_',
721     rex.R ? 'R' : '_',
722     rex.X ? 'X' : '_',
723     rex.B ? 'B' : '_');
724     #endif
725     eip++;
726     len++;
727     if (rex.W)
728     transfer_size = SIZE_QUAD;
729     }
730     #else
731     const bool has_rex = false;
732     #endif
733    
734 gbeauche 1.10 // Decode instruction
735     switch (eip[0]) {
736 gbeauche 1.17 case 0x0f:
737 gbeauche 1.18 switch (eip[1]) {
738     case 0xb6: // MOVZX r32, r/m8
739     case 0xb7: // MOVZX r32, r/m16
740 gbeauche 1.17 switch (eip[2] & 0xc0) {
741     case 0x80:
742     reg = (eip[2] >> 3) & 7;
743 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
744 gbeauche 1.17 break;
745     case 0x40:
746     reg = (eip[2] >> 3) & 7;
747 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
748 gbeauche 1.17 break;
749     case 0x00:
750     reg = (eip[2] >> 3) & 7;
751 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
752 gbeauche 1.17 break;
753     }
754     len += 3 + ix86_step_over_modrm(eip + 2);
755 gbeauche 1.18 break;
756 gbeauche 1.17 }
757     break;
758 gbeauche 1.10 case 0x8a: // MOV r8, r/m8
759     transfer_size = SIZE_BYTE;
760     case 0x8b: // MOV r32, r/m32 (or 16-bit operation)
761     switch (eip[1] & 0xc0) {
762     case 0x80:
763     reg = (eip[1] >> 3) & 7;
764 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
765 gbeauche 1.10 break;
766     case 0x40:
767     reg = (eip[1] >> 3) & 7;
768 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
769 gbeauche 1.10 break;
770     case 0x00:
771     reg = (eip[1] >> 3) & 7;
772 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
773 gbeauche 1.10 break;
774     }
775     len += 2 + ix86_step_over_modrm(eip + 1);
776     break;
777     case 0x88: // MOV r/m8, r8
778     transfer_size = SIZE_BYTE;
779     case 0x89: // MOV r/m32, r32 (or 16-bit operation)
780     switch (eip[1] & 0xc0) {
781     case 0x80:
782     reg = (eip[1] >> 3) & 7;
783 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
784 gbeauche 1.10 break;
785     case 0x40:
786     reg = (eip[1] >> 3) & 7;
787 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
788 gbeauche 1.10 break;
789     case 0x00:
790     reg = (eip[1] >> 3) & 7;
791 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
792 gbeauche 1.10 break;
793     }
794     len += 2 + ix86_step_over_modrm(eip + 1);
795     break;
796     }
797    
798 gbeauche 1.22 if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
799 gbeauche 1.10 // Unknown machine code, let it crash. Then patch the decoder
800     return false;
801     }
802    
803 gbeauche 1.34 #if defined(__x86_64__)
804     if (rex.R)
805     reg += 8;
806     #endif
807    
808 gbeauche 1.22 if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) {
809 gbeauche 1.34 static const int x86_reg_map[] = {
810 gbeauche 1.10 X86_REG_EAX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBX,
811 gbeauche 1.34 X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI,
812     #if defined(__x86_64__)
813     X86_REG_R8, X86_REG_R9, X86_REG_R10, X86_REG_R11,
814     X86_REG_R12, X86_REG_R13, X86_REG_R14, X86_REG_R15,
815     #endif
816 gbeauche 1.10 };
817    
818 gbeauche 1.34 if (reg < 0 || reg >= (sizeof(x86_reg_map)/sizeof(x86_reg_map[0]) - 1))
819 gbeauche 1.10 return false;
820    
821 gbeauche 1.34 // Set 0 to the relevant register part
822     // NOTE: this is only valid for MOV alike instructions
823 gbeauche 1.10 int rloc = x86_reg_map[reg];
824     switch (transfer_size) {
825     case SIZE_BYTE:
826 gbeauche 1.36 if (has_rex || reg < 4)
827     regs[rloc] = (regs[rloc] & ~0x00ffL);
828     else {
829     rloc = x86_reg_map[reg - 4];
830     regs[rloc] = (regs[rloc] & ~0xff00L);
831     }
832 gbeauche 1.10 break;
833     case SIZE_WORD:
834 gbeauche 1.34 regs[rloc] = (regs[rloc] & ~0xffffL);
835 gbeauche 1.10 break;
836     case SIZE_LONG:
837 gbeauche 1.34 case SIZE_QUAD: // zero-extension
838 gbeauche 1.10 regs[rloc] = 0;
839     break;
840     }
841     }
842    
843     #if DEBUG
844 gbeauche 1.15 printf("%08x: %s %s access", regs[X86_REG_EIP],
845 gbeauche 1.34 transfer_size == SIZE_BYTE ? "byte" :
846     transfer_size == SIZE_WORD ? "word" :
847     transfer_size == SIZE_LONG ? "long" :
848     transfer_size == SIZE_QUAD ? "quad" : "unknown",
849 gbeauche 1.22 transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
850 gbeauche 1.10
851     if (reg != -1) {
852 gbeauche 1.34 static const char * x86_byte_reg_str_map[] = {
853     "al", "cl", "dl", "bl",
854     "spl", "bpl", "sil", "dil",
855     "r8b", "r9b", "r10b", "r11b",
856     "r12b", "r13b", "r14b", "r15b",
857     "ah", "ch", "dh", "bh",
858     };
859     static const char * x86_word_reg_str_map[] = {
860     "ax", "cx", "dx", "bx",
861     "sp", "bp", "si", "di",
862     "r8w", "r9w", "r10w", "r11w",
863     "r12w", "r13w", "r14w", "r15w",
864     };
865     static const char *x86_long_reg_str_map[] = {
866     "eax", "ecx", "edx", "ebx",
867     "esp", "ebp", "esi", "edi",
868     "r8d", "r9d", "r10d", "r11d",
869     "r12d", "r13d", "r14d", "r15d",
870     };
871     static const char *x86_quad_reg_str_map[] = {
872     "rax", "rcx", "rdx", "rbx",
873     "rsp", "rbp", "rsi", "rdi",
874     "r8", "r9", "r10", "r11",
875     "r12", "r13", "r14", "r15",
876 gbeauche 1.10 };
877 gbeauche 1.34 const char * reg_str = NULL;
878     switch (transfer_size) {
879     case SIZE_BYTE:
880     reg_str = x86_byte_reg_str_map[(!has_rex && reg >= 4 ? 12 : 0) + reg];
881     break;
882     case SIZE_WORD: reg_str = x86_word_reg_str_map[reg]; break;
883     case SIZE_LONG: reg_str = x86_long_reg_str_map[reg]; break;
884     case SIZE_QUAD: reg_str = x86_quad_reg_str_map[reg]; break;
885     }
886     if (reg_str)
887     printf(" %s register %%%s",
888     transfer_type == SIGSEGV_TRANSFER_LOAD ? "to" : "from",
889     reg_str);
890 gbeauche 1.10 }
891     printf(", %d bytes instruction\n", len);
892     #endif
893    
894     regs[X86_REG_EIP] += len;
895 gbeauche 1.13 return true;
896     }
897     #endif
898 gbeauche 1.14
899 gbeauche 1.13 // Decode and skip PPC instruction
900 gbeauche 1.14 #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__))
901     static bool powerpc_skip_instruction(unsigned int * nip_p, unsigned int * regs)
902 gbeauche 1.13 {
903 gbeauche 1.14 instruction_t instr;
904     powerpc_decode_instruction(&instr, *nip_p, regs);
905 gbeauche 1.13
906 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
907 gbeauche 1.13 // Unknown machine code, let it crash. Then patch the decoder
908     return false;
909     }
910    
911     #if DEBUG
912 gbeauche 1.14 printf("%08x: %s %s access", *nip_p,
913     instr.transfer_size == SIZE_BYTE ? "byte" : instr.transfer_size == SIZE_WORD ? "word" : "long",
914 gbeauche 1.22 instr.transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
915 gbeauche 1.14
916     if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
917     printf(" r%d (ra = %08x)\n", instr.ra, instr.addr);
918 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
919 gbeauche 1.14 printf(" r%d (rd = 0)\n", instr.rd);
920     #endif
921    
922     if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
923     regs[instr.ra] = instr.addr;
924 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
925 gbeauche 1.14 regs[instr.rd] = 0;
926 gbeauche 1.13
927 gbeauche 1.14 *nip_p += 4;
928 gbeauche 1.10 return true;
929 gbeauche 1.38 }
930     #endif
931    
932     // Decode and skip MIPS instruction
933     #if (defined(mips) || defined(__mips))
934     enum {
935     #if (defined(sgi) || defined(__sgi))
936     MIPS_REG_EPC = 35,
937     #endif
938     };
939     static bool mips_skip_instruction(greg_t * regs)
940     {
941     unsigned int * epc = (unsigned int *)(unsigned long)regs[MIPS_REG_EPC];
942    
943     if (epc == 0)
944     return false;
945    
946     #if DEBUG
947     printf("IP: %p [%08x]\n", epc, epc[0]);
948     #endif
949    
950     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
951     transfer_size_t transfer_size = SIZE_LONG;
952     int direction = 0;
953    
954     const unsigned int opcode = epc[0];
955     switch (opcode >> 26) {
956     case 32: // Load Byte
957     case 36: // Load Byte Unsigned
958     transfer_type = SIGSEGV_TRANSFER_LOAD;
959     transfer_size = SIZE_BYTE;
960     break;
961     case 33: // Load Halfword
962     case 37: // Load Halfword Unsigned
963     transfer_type = SIGSEGV_TRANSFER_LOAD;
964     transfer_size = SIZE_WORD;
965     break;
966     case 35: // Load Word
967     case 39: // Load Word Unsigned
968     transfer_type = SIGSEGV_TRANSFER_LOAD;
969     transfer_size = SIZE_LONG;
970     break;
971     case 34: // Load Word Left
972     transfer_type = SIGSEGV_TRANSFER_LOAD;
973     transfer_size = SIZE_LONG;
974     direction = -1;
975     break;
976     case 38: // Load Word Right
977     transfer_type = SIGSEGV_TRANSFER_LOAD;
978     transfer_size = SIZE_LONG;
979     direction = 1;
980     break;
981     case 55: // Load Doubleword
982     transfer_type = SIGSEGV_TRANSFER_LOAD;
983     transfer_size = SIZE_QUAD;
984     break;
985     case 26: // Load Doubleword Left
986     transfer_type = SIGSEGV_TRANSFER_LOAD;
987     transfer_size = SIZE_QUAD;
988     direction = -1;
989     break;
990     case 27: // Load Doubleword Right
991     transfer_type = SIGSEGV_TRANSFER_LOAD;
992     transfer_size = SIZE_QUAD;
993     direction = 1;
994     break;
995     case 40: // Store Byte
996     transfer_type = SIGSEGV_TRANSFER_STORE;
997     transfer_size = SIZE_BYTE;
998     break;
999     case 41: // Store Halfword
1000     transfer_type = SIGSEGV_TRANSFER_STORE;
1001     transfer_size = SIZE_WORD;
1002     break;
1003     case 43: // Store Word
1004     case 42: // Store Word Left
1005     case 46: // Store Word Right
1006     transfer_type = SIGSEGV_TRANSFER_STORE;
1007     transfer_size = SIZE_LONG;
1008     break;
1009     case 63: // Store Doubleword
1010     case 44: // Store Doubleword Left
1011     case 45: // Store Doubleword Right
1012     transfer_type = SIGSEGV_TRANSFER_STORE;
1013     transfer_size = SIZE_QUAD;
1014     break;
1015     /* Misc instructions unlikely to be used within CPU emulators */
1016     case 48: // Load Linked Word
1017     transfer_type = SIGSEGV_TRANSFER_LOAD;
1018     transfer_size = SIZE_LONG;
1019     break;
1020     case 52: // Load Linked Doubleword
1021     transfer_type = SIGSEGV_TRANSFER_LOAD;
1022     transfer_size = SIZE_QUAD;
1023     break;
1024     case 56: // Store Conditional Word
1025     transfer_type = SIGSEGV_TRANSFER_STORE;
1026     transfer_size = SIZE_LONG;
1027     break;
1028     case 60: // Store Conditional Doubleword
1029     transfer_type = SIGSEGV_TRANSFER_STORE;
1030     transfer_size = SIZE_QUAD;
1031     break;
1032     }
1033    
1034     if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1035     // Unknown machine code, let it crash. Then patch the decoder
1036     return false;
1037     }
1038    
1039     // Zero target register in case of a load operation
1040     const int reg = (opcode >> 16) & 0x1f;
1041     if (transfer_type == SIGSEGV_TRANSFER_LOAD) {
1042     if (direction == 0)
1043     regs[reg] = 0;
1044     else {
1045     // FIXME: untested code
1046     unsigned long ea = regs[(opcode >> 21) & 0x1f];
1047     ea += (signed long)(signed int)(signed short)(opcode & 0xffff);
1048     const int offset = ea & (transfer_size == SIZE_LONG ? 3 : 7);
1049     unsigned long value;
1050     if (direction > 0) {
1051     const unsigned long rmask = ~((1L << ((offset + 1) * 8)) - 1);
1052     value = regs[reg] & rmask;
1053     }
1054     else {
1055     const unsigned long lmask = (1L << (offset * 8)) - 1;
1056     value = regs[reg] & lmask;
1057     }
1058     // restore most significant bits
1059     if (transfer_size == SIZE_LONG)
1060     value = (signed long)(signed int)value;
1061     regs[reg] = value;
1062     }
1063     }
1064    
1065     #if DEBUG
1066     #if (defined(_ABIN32) || defined(_ABI64))
1067     static const char * mips_gpr_names[32] = {
1068     "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
1069     "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
1070     "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
1071     "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
1072     };
1073     #else
1074     static const char * mips_gpr_names[32] = {
1075     "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
1076     "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
1077     "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
1078     "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
1079     };
1080     #endif
1081     printf("%s %s register %s\n",
1082     transfer_size == SIZE_BYTE ? "byte" :
1083     transfer_size == SIZE_WORD ? "word" :
1084     transfer_size == SIZE_LONG ? "long" :
1085     transfer_size == SIZE_QUAD ? "quad" : "unknown",
1086     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1087     mips_gpr_names[reg]);
1088     #endif
1089    
1090     regs[MIPS_REG_EPC] += 4;
1091     return true;
1092 gbeauche 1.10 }
1093     #endif
1094     #endif
1095    
1096 gbeauche 1.1 // Fallbacks
1097     #ifndef SIGSEGV_FAULT_INSTRUCTION
1098     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_INVALID_PC
1099     #endif
1100 gbeauche 1.30 #ifndef SIGSEGV_FAULT_HANDLER_ARGLIST_1
1101     #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 SIGSEGV_FAULT_HANDLER_ARGLIST
1102     #endif
1103 gbeauche 1.31 #ifndef SIGSEGV_FAULT_HANDLER_INVOKE
1104     #define SIGSEGV_FAULT_HANDLER_INVOKE(ADDR, IP) sigsegv_fault_handler(ADDR, IP)
1105     #endif
1106 gbeauche 1.1
1107 gbeauche 1.2 // SIGSEGV recovery supported ?
1108     #if defined(SIGSEGV_ALL_SIGNALS) && defined(SIGSEGV_FAULT_HANDLER_ARGLIST) && defined(SIGSEGV_FAULT_ADDRESS)
1109     #define HAVE_SIGSEGV_RECOVERY
1110     #endif
1111    
1112 gbeauche 1.1
1113     /*
1114     * SIGSEGV global handler
1115     */
1116    
1117 gbeauche 1.27 #if defined(HAVE_SIGSEGV_RECOVERY) || defined(HAVE_MACH_EXCEPTIONS)
1118     // This function handles the badaccess to memory.
1119     // It is called from the signal handler or the exception handler.
1120 gbeauche 1.30 static bool handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGLIST_1)
1121 gbeauche 1.1 {
1122 gbeauche 1.10 sigsegv_address_t fault_address = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
1123     sigsegv_address_t fault_instruction = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
1124    
1125 gbeauche 1.1 // Call user's handler and reinstall the global handler, if required
1126 gbeauche 1.31 switch (SIGSEGV_FAULT_HANDLER_INVOKE(fault_address, fault_instruction)) {
1127 gbeauche 1.24 case SIGSEGV_RETURN_SUCCESS:
1128 gbeauche 1.27 return true;
1129    
1130 gbeauche 1.10 #if HAVE_SIGSEGV_SKIP_INSTRUCTION
1131 gbeauche 1.24 case SIGSEGV_RETURN_SKIP_INSTRUCTION:
1132 gbeauche 1.27 // Call the instruction skipper with the register file
1133     // available
1134     if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE)) {
1135     #ifdef HAVE_MACH_EXCEPTIONS
1136     // Unlike UNIX signals where the thread state
1137     // is modified off of the stack, in Mach we
1138     // need to actually call thread_set_state to
1139     // have the register values updated.
1140     kern_return_t krc;
1141    
1142     krc = thread_set_state(thread,
1143     MACHINE_THREAD_STATE, (thread_state_t)state,
1144     MACHINE_THREAD_STATE_COUNT);
1145     MACH_CHECK_ERROR (thread_get_state, krc);
1146     #endif
1147     return true;
1148     }
1149 gbeauche 1.24 break;
1150     #endif
1151 gbeauche 1.10 }
1152 gbeauche 1.27
1153     // We can't do anything with the fault_address, dump state?
1154     if (sigsegv_state_dumper != 0)
1155     sigsegv_state_dumper(fault_address, fault_instruction);
1156    
1157     return false;
1158     }
1159     #endif
1160    
1161    
1162     /*
1163     * There are two mechanisms for handling a bad memory access,
1164     * Mach exceptions and UNIX signals. The implementation specific
1165     * code appears below. Its reponsibility is to call handle_badaccess
1166     * which is the routine that handles the fault in an implementation
1167     * agnostic manner. The implementation specific code below is then
1168     * reponsible for checking whether handle_badaccess was able
1169     * to handle the memory access error and perform any implementation
1170     * specific tasks necessary afterwards.
1171     */
1172    
1173     #ifdef HAVE_MACH_EXCEPTIONS
1174     /*
1175     * We need to forward all exceptions that we do not handle.
1176     * This is important, there are many exceptions that may be
1177     * handled by other exception handlers. For example debuggers
1178     * use exceptions and the exception hander is in another
1179     * process in such a case. (Timothy J. Wood states in his
1180     * message to the list that he based this code on that from
1181     * gdb for Darwin.)
1182     */
1183     static inline kern_return_t
1184     forward_exception(mach_port_t thread_port,
1185     mach_port_t task_port,
1186     exception_type_t exception_type,
1187     exception_data_t exception_data,
1188     mach_msg_type_number_t data_count,
1189     ExceptionPorts *oldExceptionPorts)
1190     {
1191     kern_return_t kret;
1192     unsigned int portIndex;
1193     mach_port_t port;
1194     exception_behavior_t behavior;
1195     thread_state_flavor_t flavor;
1196     thread_state_t thread_state;
1197     mach_msg_type_number_t thread_state_count;
1198    
1199     for (portIndex = 0; portIndex < oldExceptionPorts->maskCount; portIndex++) {
1200     if (oldExceptionPorts->masks[portIndex] & (1 << exception_type)) {
1201     // This handler wants the exception
1202     break;
1203     }
1204     }
1205    
1206     if (portIndex >= oldExceptionPorts->maskCount) {
1207     fprintf(stderr, "No handler for exception_type = %d. Not fowarding\n", exception_type);
1208     return KERN_FAILURE;
1209     }
1210    
1211     port = oldExceptionPorts->handlers[portIndex];
1212     behavior = oldExceptionPorts->behaviors[portIndex];
1213     flavor = oldExceptionPorts->flavors[portIndex];
1214    
1215     /*
1216     fprintf(stderr, "forwarding exception, port = 0x%x, behaviour = %d, flavor = %d\n", port, behavior, flavor);
1217     */
1218    
1219     if (behavior != EXCEPTION_DEFAULT) {
1220     thread_state_count = THREAD_STATE_MAX;
1221     kret = thread_get_state (thread_port, flavor, thread_state,
1222     &thread_state_count);
1223     MACH_CHECK_ERROR (thread_get_state, kret);
1224     }
1225    
1226     switch (behavior) {
1227     case EXCEPTION_DEFAULT:
1228     // fprintf(stderr, "forwarding to exception_raise\n");
1229     kret = exception_raise(port, thread_port, task_port, exception_type,
1230     exception_data, data_count);
1231     MACH_CHECK_ERROR (exception_raise, kret);
1232     break;
1233     case EXCEPTION_STATE:
1234     // fprintf(stderr, "forwarding to exception_raise_state\n");
1235     kret = exception_raise_state(port, exception_type, exception_data,
1236     data_count, &flavor,
1237     thread_state, thread_state_count,
1238     thread_state, &thread_state_count);
1239     MACH_CHECK_ERROR (exception_raise_state, kret);
1240     break;
1241     case EXCEPTION_STATE_IDENTITY:
1242     // fprintf(stderr, "forwarding to exception_raise_state_identity\n");
1243     kret = exception_raise_state_identity(port, thread_port, task_port,
1244     exception_type, exception_data,
1245     data_count, &flavor,
1246     thread_state, thread_state_count,
1247     thread_state, &thread_state_count);
1248     MACH_CHECK_ERROR (exception_raise_state_identity, kret);
1249     break;
1250     default:
1251     fprintf(stderr, "forward_exception got unknown behavior\n");
1252     break;
1253     }
1254    
1255     if (behavior != EXCEPTION_DEFAULT) {
1256     kret = thread_set_state (thread_port, flavor, thread_state,
1257     thread_state_count);
1258     MACH_CHECK_ERROR (thread_set_state, kret);
1259     }
1260    
1261     return KERN_SUCCESS;
1262     }
1263    
1264     /*
1265     * This is the code that actually handles the exception.
1266     * It is called by exc_server. For Darwin 5 Apple changed
1267     * this a bit from how this family of functions worked in
1268     * Mach. If you are familiar with that it is a little
1269     * different. The main variation that concerns us here is
1270     * that code is an array of exception specific codes and
1271     * codeCount is a count of the number of codes in the code
1272     * array. In typical Mach all exceptions have a code
1273     * and sub-code. It happens to be the case that for a
1274     * EXC_BAD_ACCESS exception the first entry is the type of
1275     * bad access that occurred and the second entry is the
1276     * faulting address so these entries correspond exactly to
1277     * how the code and sub-code are used on Mach.
1278     *
1279     * This is a MIG interface. No code in Basilisk II should
1280     * call this directley. This has to have external C
1281     * linkage because that is what exc_server expects.
1282     */
1283     kern_return_t
1284     catch_exception_raise(mach_port_t exception_port,
1285     mach_port_t thread,
1286     mach_port_t task,
1287     exception_type_t exception,
1288     exception_data_t code,
1289     mach_msg_type_number_t codeCount)
1290     {
1291     ppc_thread_state_t state;
1292     kern_return_t krc;
1293    
1294     if ((exception == EXC_BAD_ACCESS) && (codeCount >= 2)) {
1295     if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS))
1296     return KERN_SUCCESS;
1297     }
1298    
1299     // In Mach we do not need to remove the exception handler.
1300     // If we forward the exception, eventually some exception handler
1301     // will take care of this exception.
1302     krc = forward_exception(thread, task, exception, code, codeCount, &ports);
1303    
1304     return krc;
1305     }
1306     #endif
1307    
1308     #ifdef HAVE_SIGSEGV_RECOVERY
1309     // Handle bad memory accesses with signal handler
1310     static void sigsegv_handler(SIGSEGV_FAULT_HANDLER_ARGLIST)
1311     {
1312     // Call handler and reinstall the global handler, if required
1313     if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS)) {
1314     #if (defined(HAVE_SIGACTION) ? defined(SIGACTION_NEED_REINSTALL) : defined(SIGNAL_NEED_REINSTALL))
1315     sigsegv_do_install_handler(sig);
1316     #endif
1317     return;
1318     }
1319 gbeauche 1.10
1320 gbeauche 1.27 // Failure: reinstall default handler for "safe" crash
1321 gbeauche 1.1 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
1322 gbeauche 1.27 SIGSEGV_ALL_SIGNALS
1323 gbeauche 1.1 #undef FAULT_HANDLER
1324     }
1325 gbeauche 1.2 #endif
1326 gbeauche 1.1
1327    
1328     /*
1329     * SIGSEGV handler initialization
1330     */
1331    
1332     #if defined(HAVE_SIGINFO_T)
1333     static bool sigsegv_do_install_handler(int sig)
1334     {
1335     // Setup SIGSEGV handler to process writes to frame buffer
1336     #ifdef HAVE_SIGACTION
1337 gbeauche 1.22 struct sigaction sigsegv_sa;
1338     sigemptyset(&sigsegv_sa.sa_mask);
1339     sigsegv_sa.sa_sigaction = sigsegv_handler;
1340     sigsegv_sa.sa_flags = SA_SIGINFO;
1341     return (sigaction(sig, &sigsegv_sa, 0) == 0);
1342 gbeauche 1.1 #else
1343     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
1344     #endif
1345     }
1346 gbeauche 1.2 #endif
1347    
1348     #if defined(HAVE_SIGCONTEXT_SUBTERFUGE)
1349 gbeauche 1.1 static bool sigsegv_do_install_handler(int sig)
1350     {
1351     // Setup SIGSEGV handler to process writes to frame buffer
1352     #ifdef HAVE_SIGACTION
1353 gbeauche 1.22 struct sigaction sigsegv_sa;
1354     sigemptyset(&sigsegv_sa.sa_mask);
1355     sigsegv_sa.sa_handler = (signal_handler)sigsegv_handler;
1356     sigsegv_sa.sa_flags = 0;
1357 gbeauche 1.1 #if !EMULATED_68K && defined(__NetBSD__)
1358 gbeauche 1.22 sigaddset(&sigsegv_sa.sa_mask, SIGALRM);
1359     sigsegv_sa.sa_flags |= SA_ONSTACK;
1360 gbeauche 1.1 #endif
1361 gbeauche 1.22 return (sigaction(sig, &sigsegv_sa, 0) == 0);
1362 gbeauche 1.1 #else
1363     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
1364     #endif
1365     }
1366     #endif
1367    
1368 gbeauche 1.27 #if defined(HAVE_MACH_EXCEPTIONS)
1369     static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
1370     {
1371     /*
1372     * Except for the exception port functions, this should be
1373     * pretty much stock Mach. If later you choose to support
1374     * other Mach's besides Darwin, just check for __MACH__
1375     * here and __APPLE__ where the actual differences are.
1376     */
1377     #if defined(__APPLE__) && defined(__MACH__)
1378     if (sigsegv_fault_handler != NULL) {
1379     sigsegv_fault_handler = handler;
1380     return true;
1381     }
1382    
1383     kern_return_t krc;
1384    
1385     // create the the exception port
1386     krc = mach_port_allocate(mach_task_self(),
1387     MACH_PORT_RIGHT_RECEIVE, &_exceptionPort);
1388     if (krc != KERN_SUCCESS) {
1389     mach_error("mach_port_allocate", krc);
1390     return false;
1391     }
1392    
1393     // add a port send right
1394     krc = mach_port_insert_right(mach_task_self(),
1395     _exceptionPort, _exceptionPort,
1396     MACH_MSG_TYPE_MAKE_SEND);
1397     if (krc != KERN_SUCCESS) {
1398     mach_error("mach_port_insert_right", krc);
1399     return false;
1400     }
1401    
1402     // get the old exception ports
1403     ports.maskCount = sizeof (ports.masks) / sizeof (ports.masks[0]);
1404     krc = thread_get_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, ports.masks,
1405     &ports.maskCount, ports.handlers, ports.behaviors, ports.flavors);
1406     if (krc != KERN_SUCCESS) {
1407     mach_error("thread_get_exception_ports", krc);
1408     return false;
1409     }
1410    
1411     // set the new exception port
1412     //
1413     // We could have used EXCEPTION_STATE_IDENTITY instead of
1414     // EXCEPTION_DEFAULT to get the thread state in the initial
1415     // message, but it turns out that in the common case this is not
1416     // neccessary. If we need it we can later ask for it from the
1417     // suspended thread.
1418     //
1419     // Even with THREAD_STATE_NONE, Darwin provides the program
1420     // counter in the thread state. The comments in the header file
1421     // seem to imply that you can count on the GPR's on an exception
1422     // as well but just to be safe I use MACHINE_THREAD_STATE because
1423     // you have to ask for all of the GPR's anyway just to get the
1424     // program counter. In any case because of update effective
1425     // address from immediate and update address from effective
1426     // addresses of ra and rb modes (as good an name as any for these
1427     // addressing modes) used in PPC instructions, you will need the
1428     // GPR state anyway.
1429     krc = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, _exceptionPort,
1430     EXCEPTION_DEFAULT, MACHINE_THREAD_STATE);
1431     if (krc != KERN_SUCCESS) {
1432     mach_error("thread_set_exception_ports", krc);
1433     return false;
1434     }
1435    
1436     // create the exception handler thread
1437     if (pthread_create(&exc_thread, NULL, &handleExceptions, NULL) != 0) {
1438     (void)fprintf(stderr, "creation of exception thread failed\n");
1439     return false;
1440     }
1441    
1442     // do not care about the exception thread any longer, let is run standalone
1443     (void)pthread_detach(exc_thread);
1444    
1445     sigsegv_fault_handler = handler;
1446     return true;
1447     #else
1448     return false;
1449     #endif
1450     }
1451     #endif
1452    
1453 gbeauche 1.12 bool sigsegv_install_handler(sigsegv_fault_handler_t handler)
1454 gbeauche 1.1 {
1455 gbeauche 1.27 #if defined(HAVE_SIGSEGV_RECOVERY)
1456 gbeauche 1.1 bool success = true;
1457     #define FAULT_HANDLER(sig) success = success && sigsegv_do_install_handler(sig);
1458     SIGSEGV_ALL_SIGNALS
1459     #undef FAULT_HANDLER
1460 gbeauche 1.27 if (success)
1461     sigsegv_fault_handler = handler;
1462 gbeauche 1.1 return success;
1463 gbeauche 1.27 #elif defined(HAVE_MACH_EXCEPTIONS)
1464     return sigsegv_do_install_handler(handler);
1465 gbeauche 1.1 #else
1466     // FAIL: no siginfo_t nor sigcontext subterfuge is available
1467     return false;
1468     #endif
1469     }
1470    
1471    
1472     /*
1473     * SIGSEGV handler deinitialization
1474     */
1475    
1476     void sigsegv_deinstall_handler(void)
1477     {
1478 gbeauche 1.27 // We do nothing for Mach exceptions, the thread would need to be
1479     // suspended if not already so, and we might mess with other
1480     // exception handlers that came after we registered ours. There is
1481     // no need to remove the exception handler, in fact this function is
1482     // not called anywhere in Basilisk II.
1483 gbeauche 1.2 #ifdef HAVE_SIGSEGV_RECOVERY
1484 gbeauche 1.12 sigsegv_fault_handler = 0;
1485 gbeauche 1.1 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
1486     SIGSEGV_ALL_SIGNALS
1487     #undef FAULT_HANDLER
1488 gbeauche 1.2 #endif
1489 gbeauche 1.1 }
1490    
1491 gbeauche 1.10
1492     /*
1493     * Set callback function when we cannot handle the fault
1494     */
1495    
1496 gbeauche 1.12 void sigsegv_set_dump_state(sigsegv_state_dumper_t handler)
1497 gbeauche 1.10 {
1498 gbeauche 1.12 sigsegv_state_dumper = handler;
1499 gbeauche 1.10 }
1500    
1501    
1502 gbeauche 1.1 /*
1503     * Test program used for configure/test
1504     */
1505    
1506 gbeauche 1.4 #ifdef CONFIGURE_TEST_SIGSEGV_RECOVERY
1507 gbeauche 1.1 #include <stdio.h>
1508     #include <stdlib.h>
1509     #include <fcntl.h>
1510     #include <sys/mman.h>
1511 gbeauche 1.4 #include "vm_alloc.h"
1512 gbeauche 1.1
1513 gbeauche 1.32 const int REF_INDEX = 123;
1514     const int REF_VALUE = 45;
1515    
1516 gbeauche 1.1 static int page_size;
1517 gbeauche 1.3 static volatile char * page = 0;
1518     static volatile int handler_called = 0;
1519 gbeauche 1.1
1520 gbeauche 1.32 #ifdef __GNUC__
1521     // Code range where we expect the fault to come from
1522     static void *b_region, *e_region;
1523     #endif
1524    
1525 gbeauche 1.24 static sigsegv_return_t sigsegv_test_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
1526 gbeauche 1.1 {
1527     handler_called++;
1528 gbeauche 1.32 if ((fault_address - REF_INDEX) != page)
1529 gbeauche 1.29 exit(10);
1530 gbeauche 1.32 #ifdef __GNUC__
1531     // Make sure reported fault instruction address falls into
1532     // expected code range
1533     if (instruction_address != SIGSEGV_INVALID_PC
1534     && ((instruction_address < (sigsegv_address_t)b_region) ||
1535     (instruction_address >= (sigsegv_address_t)e_region)))
1536     exit(11);
1537     #endif
1538 gbeauche 1.4 if (vm_protect((char *)((unsigned long)fault_address & -page_size), page_size, VM_PAGE_READ | VM_PAGE_WRITE) != 0)
1539 gbeauche 1.32 exit(12);
1540 gbeauche 1.24 return SIGSEGV_RETURN_SUCCESS;
1541 gbeauche 1.1 }
1542    
1543 gbeauche 1.10 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1544 gbeauche 1.24 static sigsegv_return_t sigsegv_insn_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
1545 gbeauche 1.10 {
1546 gbeauche 1.28 if (((unsigned long)fault_address - (unsigned long)page) < page_size) {
1547     #ifdef __GNUC__
1548     // Make sure reported fault instruction address falls into
1549     // expected code range
1550     if (instruction_address != SIGSEGV_INVALID_PC
1551     && ((instruction_address < (sigsegv_address_t)b_region) ||
1552     (instruction_address >= (sigsegv_address_t)e_region)))
1553     return SIGSEGV_RETURN_FAILURE;
1554     #endif
1555 gbeauche 1.26 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
1556 gbeauche 1.28 }
1557    
1558 gbeauche 1.24 return SIGSEGV_RETURN_FAILURE;
1559 gbeauche 1.10 }
1560 gbeauche 1.34
1561     // More sophisticated tests for instruction skipper
1562     static bool arch_insn_skipper_tests()
1563     {
1564     #if (defined(i386) || defined(__i386__)) || defined(__x86_64__)
1565     static const unsigned char code[] = {
1566     0x8a, 0x00, // mov (%eax),%al
1567     0x8a, 0x2c, 0x18, // mov (%eax,%ebx,1),%ch
1568     0x88, 0x20, // mov %ah,(%eax)
1569     0x88, 0x08, // mov %cl,(%eax)
1570     0x66, 0x8b, 0x00, // mov (%eax),%ax
1571     0x66, 0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%cx
1572     0x66, 0x89, 0x00, // mov %ax,(%eax)
1573     0x66, 0x89, 0x0c, 0x18, // mov %cx,(%eax,%ebx,1)
1574     0x8b, 0x00, // mov (%eax),%eax
1575     0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%ecx
1576     0x89, 0x00, // mov %eax,(%eax)
1577     0x89, 0x0c, 0x18, // mov %ecx,(%eax,%ebx,1)
1578     #if defined(__x86_64__)
1579     0x44, 0x8a, 0x00, // mov (%rax),%r8b
1580     0x44, 0x8a, 0x20, // mov (%rax),%r12b
1581     0x42, 0x8a, 0x3c, 0x10, // mov (%rax,%r10,1),%dil
1582     0x44, 0x88, 0x00, // mov %r8b,(%rax)
1583     0x44, 0x88, 0x20, // mov %r12b,(%rax)
1584     0x42, 0x88, 0x3c, 0x10, // mov %dil,(%rax,%r10,1)
1585     0x66, 0x44, 0x8b, 0x00, // mov (%rax),%r8w
1586     0x66, 0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%cx
1587     0x66, 0x44, 0x89, 0x00, // mov %r8w,(%rax)
1588     0x66, 0x42, 0x89, 0x0c, 0x10, // mov %cx,(%rax,%r10,1)
1589     0x44, 0x8b, 0x00, // mov (%rax),%r8d
1590     0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%ecx
1591     0x44, 0x89, 0x00, // mov %r8d,(%rax)
1592     0x42, 0x89, 0x0c, 0x10, // mov %ecx,(%rax,%r10,1)
1593     0x48, 0x8b, 0x08, // mov (%rax),%rcx
1594     0x4c, 0x8b, 0x18, // mov (%rax),%r11
1595     0x4a, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%rcx
1596     0x4e, 0x8b, 0x1c, 0x10, // mov (%rax,%r10,1),%r11
1597     0x48, 0x89, 0x08, // mov %rcx,(%rax)
1598     0x4c, 0x89, 0x18, // mov %r11,(%rax)
1599     0x4a, 0x89, 0x0c, 0x10, // mov %rcx,(%rax,%r10,1)
1600     0x4e, 0x89, 0x1c, 0x10, // mov %r11,(%rax,%r10,1)
1601     #endif
1602     0 // end
1603     };
1604     const int N_REGS = 20;
1605     unsigned long regs[N_REGS];
1606     for (int i = 0; i < N_REGS; i++)
1607     regs[i] = i;
1608     const unsigned long start_code = (unsigned long)&code;
1609     regs[X86_REG_EIP] = start_code;
1610     while ((regs[X86_REG_EIP] - start_code) < (sizeof(code) - 1)
1611     && ix86_skip_instruction(regs))
1612     ; /* simply iterate */
1613     return (regs[X86_REG_EIP] - start_code) == (sizeof(code) - 1);
1614     #endif
1615     return true;
1616     }
1617 gbeauche 1.10 #endif
1618    
1619 gbeauche 1.1 int main(void)
1620     {
1621 gbeauche 1.4 if (vm_init() < 0)
1622 gbeauche 1.1 return 1;
1623    
1624     page_size = getpagesize();
1625 gbeauche 1.4 if ((page = (char *)vm_acquire(page_size)) == VM_MAP_FAILED)
1626 gbeauche 1.29 return 2;
1627 gbeauche 1.4
1628 gbeauche 1.32 memset((void *)page, 0, page_size);
1629 gbeauche 1.4 if (vm_protect((char *)page, page_size, VM_PAGE_READ) < 0)
1630 gbeauche 1.29 return 3;
1631 gbeauche 1.1
1632     if (!sigsegv_install_handler(sigsegv_test_handler))
1633 gbeauche 1.29 return 4;
1634 gbeauche 1.1
1635 gbeauche 1.32 #ifdef __GNUC__
1636     b_region = &&L_b_region1;
1637     e_region = &&L_e_region1;
1638     #endif
1639     L_b_region1:
1640     page[REF_INDEX] = REF_VALUE;
1641     if (page[REF_INDEX] != REF_VALUE)
1642     exit(20);
1643     page[REF_INDEX] = REF_VALUE;
1644     L_e_region1:
1645    
1646 gbeauche 1.1 if (handler_called != 1)
1647 gbeauche 1.29 return 5;
1648 gbeauche 1.10
1649     #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1650     if (!sigsegv_install_handler(sigsegv_insn_handler))
1651 gbeauche 1.29 return 6;
1652 gbeauche 1.10
1653 gbeauche 1.17 if (vm_protect((char *)page, page_size, VM_PAGE_READ | VM_PAGE_WRITE) < 0)
1654 gbeauche 1.29 return 7;
1655 gbeauche 1.10
1656     for (int i = 0; i < page_size; i++)
1657     page[i] = (i + 1) % page_size;
1658    
1659     if (vm_protect((char *)page, page_size, VM_PAGE_NOACCESS) < 0)
1660 gbeauche 1.29 return 8;
1661 gbeauche 1.10
1662     #define TEST_SKIP_INSTRUCTION(TYPE) do { \
1663 gbeauche 1.34 const unsigned long TAG = 0x12345678 | \
1664     (sizeof(long) == 8 ? 0x9abcdef0UL << 31 : 0); \
1665 gbeauche 1.10 TYPE data = *((TYPE *)(page + sizeof(TYPE))); \
1666 gbeauche 1.34 volatile unsigned long effect = data + TAG; \
1667 gbeauche 1.10 if (effect != TAG) \
1668 gbeauche 1.29 return 9; \
1669 gbeauche 1.10 } while (0)
1670    
1671 gbeauche 1.28 #ifdef __GNUC__
1672 gbeauche 1.32 b_region = &&L_b_region2;
1673     e_region = &&L_e_region2;
1674 gbeauche 1.28 #endif
1675 gbeauche 1.32 L_b_region2:
1676 gbeauche 1.10 TEST_SKIP_INSTRUCTION(unsigned char);
1677     TEST_SKIP_INSTRUCTION(unsigned short);
1678     TEST_SKIP_INSTRUCTION(unsigned int);
1679 gbeauche 1.34 TEST_SKIP_INSTRUCTION(unsigned long);
1680 gbeauche 1.32 L_e_region2:
1681 gbeauche 1.1
1682 gbeauche 1.34 if (!arch_insn_skipper_tests())
1683     return 20;
1684 gbeauche 1.35 #endif
1685 gbeauche 1.34
1686 gbeauche 1.4 vm_exit();
1687 gbeauche 1.1 return 0;
1688     }
1689     #endif