ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.55
Committed: 2005-03-23T22:00:06Z (19 years, 5 months ago) by gbeauche
Branch: MAIN
Changes since 1.54: +21 -1 lines
Log Message:
Enable instruction skipping for OpenBSD 3.4 on i386

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