ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.52
Committed: 2005-01-30T21:42:14Z (19 years, 10 months ago) by gbeauche
Branch: MAIN
Changes since 1.51: +1 -1 lines
Log Message:
Happy New Year!

File Contents

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