ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.54
Committed: 2005-03-23T21:37:24Z (19 years, 5 months ago) by gbeauche
Branch: MAIN
Changes since 1.53: +24 -5 lines
Log Message:
instruction skipper for Solaris/i386 (Solaris 9)

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