ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.78
Committed: 2008-01-07T22:44:39Z (16 years, 8 months ago) by gbeauche
Branch: MAIN
Changes since 1.77: +11 -2 lines
Log Message:
Make it possible to override the Mach fault recovery scheme through an
environment variable: SIGSEGV_MACH_FAULT. It can be set to "direct" to
assume the fault address comes from code[1] argument, or "slow" to use
the slow path through thread_get_status(EXCEPTION_STATE)->faultvaddr.

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.71 * Basilisk II (C) 1997-2008 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 gbeauche 1.64 // Transfer type
70     enum transfer_type_t {
71     SIGSEGV_TRANSFER_UNKNOWN = 0,
72     SIGSEGV_TRANSFER_LOAD = 1,
73 gbeauche 1.73 SIGSEGV_TRANSFER_STORE = 2
74 gbeauche 1.64 };
75    
76 gbeauche 1.14 // Transfer size
77     enum transfer_size_t {
78     SIZE_UNKNOWN,
79     SIZE_BYTE,
80 gbeauche 1.34 SIZE_WORD, // 2 bytes
81     SIZE_LONG, // 4 bytes
82 gbeauche 1.73 SIZE_QUAD // 8 bytes
83 gbeauche 1.14 };
84    
85 gbeauche 1.69 #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__))
86 gbeauche 1.14 // Addressing mode
87     enum addressing_mode_t {
88     MODE_UNKNOWN,
89     MODE_NORM,
90     MODE_U,
91     MODE_X,
92     MODE_UX
93     };
94    
95     // Decoded instruction
96     struct instruction_t {
97     transfer_type_t transfer_type;
98     transfer_size_t transfer_size;
99     addressing_mode_t addr_mode;
100     unsigned int addr;
101     char ra, rd;
102     };
103    
104 gbeauche 1.49 static void powerpc_decode_instruction(instruction_t *instruction, unsigned int nip, unsigned long * gpr)
105 gbeauche 1.14 {
106     // Get opcode and divide into fields
107 gbeauche 1.49 unsigned int opcode = *((unsigned int *)(unsigned long)nip);
108 gbeauche 1.14 unsigned int primop = opcode >> 26;
109     unsigned int exop = (opcode >> 1) & 0x3ff;
110     unsigned int ra = (opcode >> 16) & 0x1f;
111     unsigned int rb = (opcode >> 11) & 0x1f;
112     unsigned int rd = (opcode >> 21) & 0x1f;
113     signed int imm = (signed short)(opcode & 0xffff);
114    
115     // Analyze opcode
116 gbeauche 1.22 transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
117 gbeauche 1.14 transfer_size_t transfer_size = SIZE_UNKNOWN;
118     addressing_mode_t addr_mode = MODE_UNKNOWN;
119     switch (primop) {
120     case 31:
121     switch (exop) {
122     case 23: // lwzx
123 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
124 gbeauche 1.14 case 55: // lwzux
125 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
126 gbeauche 1.14 case 87: // lbzx
127 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
128 gbeauche 1.14 case 119: // lbzux
129 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
130 gbeauche 1.14 case 151: // stwx
131 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
132 gbeauche 1.14 case 183: // stwux
133 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
134 gbeauche 1.14 case 215: // stbx
135 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
136 gbeauche 1.14 case 247: // stbux
137 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
138 gbeauche 1.14 case 279: // lhzx
139 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
140 gbeauche 1.14 case 311: // lhzux
141 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
142 gbeauche 1.14 case 343: // lhax
143 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
144 gbeauche 1.14 case 375: // lhaux
145 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
146 gbeauche 1.14 case 407: // sthx
147 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
148 gbeauche 1.14 case 439: // sthux
149 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
150 gbeauche 1.14 }
151     break;
152    
153     case 32: // lwz
154 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
155 gbeauche 1.14 case 33: // lwzu
156 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
157 gbeauche 1.14 case 34: // lbz
158 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
159 gbeauche 1.14 case 35: // lbzu
160 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
161 gbeauche 1.14 case 36: // stw
162 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
163 gbeauche 1.14 case 37: // stwu
164 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
165 gbeauche 1.14 case 38: // stb
166 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
167 gbeauche 1.14 case 39: // stbu
168 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
169 gbeauche 1.14 case 40: // lhz
170 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
171 gbeauche 1.14 case 41: // lhzu
172 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
173 gbeauche 1.14 case 42: // lha
174 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
175 gbeauche 1.14 case 43: // lhau
176 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
177 gbeauche 1.14 case 44: // sth
178 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
179 gbeauche 1.14 case 45: // sthu
180 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
181 gbeauche 1.49 case 58: // ld, ldu, lwa
182     transfer_type = SIGSEGV_TRANSFER_LOAD;
183     transfer_size = SIZE_QUAD;
184     addr_mode = ((opcode & 3) == 1) ? MODE_U : MODE_NORM;
185     imm &= ~3;
186     break;
187     case 62: // std, stdu, stq
188     transfer_type = SIGSEGV_TRANSFER_STORE;
189     transfer_size = SIZE_QUAD;
190     addr_mode = ((opcode & 3) == 1) ? MODE_U : MODE_NORM;
191     imm &= ~3;
192     break;
193 gbeauche 1.14 }
194    
195     // Calculate effective address
196     unsigned int addr = 0;
197     switch (addr_mode) {
198     case MODE_X:
199     case MODE_UX:
200     if (ra == 0)
201     addr = gpr[rb];
202     else
203     addr = gpr[ra] + gpr[rb];
204     break;
205     case MODE_NORM:
206     case MODE_U:
207     if (ra == 0)
208     addr = (signed int)(signed short)imm;
209     else
210     addr = gpr[ra] + (signed int)(signed short)imm;
211     break;
212     default:
213     break;
214     }
215    
216     // Commit decoded instruction
217     instruction->addr = addr;
218     instruction->addr_mode = addr_mode;
219     instruction->transfer_type = transfer_type;
220     instruction->transfer_size = transfer_size;
221     instruction->ra = ra;
222     instruction->rd = rd;
223     }
224     #endif
225    
226    
227     /*
228 gbeauche 1.1 * OS-dependant SIGSEGV signals support section
229     */
230    
231     #if HAVE_SIGINFO_T
232     // Generic extended signal handler
233 gbeauche 1.51 #if defined(__FreeBSD__)
234 cebix 1.8 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
235     #else
236 gbeauche 1.1 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
237 cebix 1.8 #endif
238 gbeauche 1.5 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, siginfo_t *sip, void *scp
239 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 siginfo_t *sip, void *scp
240     #define SIGSEGV_FAULT_HANDLER_ARGS sip, scp
241 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS sip->si_addr
242 gbeauche 1.37 #if (defined(sgi) || defined(__sgi))
243     #include <ucontext.h>
244     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
245     #define SIGSEGV_FAULT_INSTRUCTION (unsigned long)SIGSEGV_CONTEXT_REGS[CTX_EPC]
246 gbeauche 1.38 #if (defined(mips) || defined(__mips))
247 gbeauche 1.65 #define SIGSEGV_REGISTER_FILE &SIGSEGV_CONTEXT_REGS[CTX_EPC], &SIGSEGV_CONTEXT_REGS[CTX_R0]
248 gbeauche 1.38 #define SIGSEGV_SKIP_INSTRUCTION mips_skip_instruction
249     #endif
250 gbeauche 1.37 #endif
251 gbeauche 1.32 #if defined(__sun__)
252     #if (defined(sparc) || defined(__sparc__))
253 gbeauche 1.40 #include <sys/stack.h>
254     #include <sys/regset.h>
255 gbeauche 1.32 #include <sys/ucontext.h>
256     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
257     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[REG_PC]
258 gbeauche 1.40 #define SIGSEGV_SPARC_GWINDOWS (((ucontext_t *)scp)->uc_mcontext.gwins)
259     #define SIGSEGV_SPARC_RWINDOW (struct rwindow *)((char *)SIGSEGV_CONTEXT_REGS[REG_SP] + STACK_BIAS)
260     #define SIGSEGV_REGISTER_FILE ((unsigned long *)SIGSEGV_CONTEXT_REGS), SIGSEGV_SPARC_GWINDOWS, SIGSEGV_SPARC_RWINDOW
261     #define SIGSEGV_SKIP_INSTRUCTION sparc_skip_instruction
262 gbeauche 1.32 #endif
263 gbeauche 1.54 #if defined(__i386__)
264     #include <sys/regset.h>
265     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
266     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[EIP]
267     #define SIGSEGV_REGISTER_FILE (unsigned long *)SIGSEGV_CONTEXT_REGS
268     #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
269     #endif
270 gbeauche 1.32 #endif
271 gbeauche 1.55 #if defined(__FreeBSD__) || defined(__OpenBSD__)
272 gbeauche 1.17 #if (defined(i386) || defined(__i386__))
273     #define SIGSEGV_FAULT_INSTRUCTION (((struct sigcontext *)scp)->sc_eip)
274 gbeauche 1.34 #define SIGSEGV_REGISTER_FILE ((unsigned long *)&(((struct sigcontext *)scp)->sc_edi)) /* EDI is the first GPR (even below EIP) in sigcontext */
275 gbeauche 1.17 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
276 gbeauche 1.19 #endif
277 gbeauche 1.17 #endif
278 gbeauche 1.51 #if defined(__NetBSD__)
279     #if (defined(i386) || defined(__i386__))
280     #include <sys/ucontext.h>
281     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.__gregs)
282     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[_REG_EIP]
283     #define SIGSEGV_REGISTER_FILE (unsigned long *)SIGSEGV_CONTEXT_REGS
284     #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
285     #endif
286 gbeauche 1.53 #if (defined(powerpc) || defined(__powerpc__))
287     #include <sys/ucontext.h>
288     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.__gregs)
289     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[_REG_PC]
290     #define SIGSEGV_REGISTER_FILE (unsigned long *)&SIGSEGV_CONTEXT_REGS[_REG_PC], (unsigned long *)&SIGSEGV_CONTEXT_REGS[_REG_R0]
291     #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
292     #endif
293 gbeauche 1.51 #endif
294 gbeauche 1.5 #if defined(__linux__)
295 gbeauche 1.6 #if (defined(i386) || defined(__i386__))
296     #include <sys/ucontext.h>
297 gbeauche 1.14 #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
298     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[14] /* should use REG_EIP instead */
299 gbeauche 1.34 #define SIGSEGV_REGISTER_FILE (unsigned long *)SIGSEGV_CONTEXT_REGS
300 gbeauche 1.10 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
301 gbeauche 1.6 #endif
302 gbeauche 1.20 #if (defined(x86_64) || defined(__x86_64__))
303     #include <sys/ucontext.h>
304     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
305     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[16] /* should use REG_RIP instead */
306     #define SIGSEGV_REGISTER_FILE (unsigned long *)SIGSEGV_CONTEXT_REGS
307 gbeauche 1.34 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
308 gbeauche 1.20 #endif
309 gbeauche 1.5 #if (defined(ia64) || defined(__ia64__))
310 gbeauche 1.75 #define SIGSEGV_CONTEXT_REGS ((struct sigcontext *)scp)
311     #define SIGSEGV_FAULT_INSTRUCTION (SIGSEGV_CONTEXT_REGS->sc_ip & ~0x3ULL) /* slot number is in bits 0 and 1 */
312 gbeauche 1.77 #define SIGSEGV_REGISTER_FILE SIGSEGV_CONTEXT_REGS
313 gbeauche 1.75 #define SIGSEGV_SKIP_INSTRUCTION ia64_skip_instruction
314 gbeauche 1.5 #endif
315 gbeauche 1.9 #if (defined(powerpc) || defined(__powerpc__))
316     #include <sys/ucontext.h>
317 gbeauche 1.14 #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.regs)
318     #define SIGSEGV_FAULT_INSTRUCTION (SIGSEGV_CONTEXT_REGS->nip)
319 gbeauche 1.49 #define SIGSEGV_REGISTER_FILE (unsigned long *)&SIGSEGV_CONTEXT_REGS->nip, (unsigned long *)(SIGSEGV_CONTEXT_REGS->gpr)
320 gbeauche 1.13 #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
321 gbeauche 1.9 #endif
322 gbeauche 1.39 #if (defined(hppa) || defined(__hppa__))
323     #undef SIGSEGV_FAULT_ADDRESS
324     #define SIGSEGV_FAULT_ADDRESS sip->si_ptr
325     #endif
326 gbeauche 1.42 #if (defined(arm) || defined(__arm__))
327     #include <asm/ucontext.h> /* use kernel structure, glibc may not be in sync */
328     #define SIGSEGV_CONTEXT_REGS (((struct ucontext *)scp)->uc_mcontext)
329     #define SIGSEGV_FAULT_INSTRUCTION (SIGSEGV_CONTEXT_REGS.arm_pc)
330 gbeauche 1.44 #define SIGSEGV_REGISTER_FILE (&SIGSEGV_CONTEXT_REGS.arm_r0)
331     #define SIGSEGV_SKIP_INSTRUCTION arm_skip_instruction
332 gbeauche 1.42 #endif
333 gbeauche 1.65 #if (defined(mips) || defined(__mips__))
334     #include <sys/ucontext.h>
335     #define SIGSEGV_CONTEXT_REGS (((struct ucontext *)scp)->uc_mcontext)
336     #define SIGSEGV_FAULT_INSTRUCTION (SIGSEGV_CONTEXT_REGS.pc)
337     #define SIGSEGV_REGISTER_FILE &SIGSEGV_CONTEXT_REGS.pc, &SIGSEGV_CONTEXT_REGS.gregs[0]
338     #define SIGSEGV_SKIP_INSTRUCTION mips_skip_instruction
339     #endif
340 gbeauche 1.5 #endif
341 gbeauche 1.1 #endif
342    
343     #if HAVE_SIGCONTEXT_SUBTERFUGE
344     // Linux kernels prior to 2.4 ?
345     #if defined(__linux__)
346     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
347     #if (defined(i386) || defined(__i386__))
348     #include <asm/sigcontext.h>
349     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext scs
350 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 struct sigcontext *scp
351     #define SIGSEGV_FAULT_HANDLER_ARGS &scs
352     #define SIGSEGV_FAULT_ADDRESS scp->cr2
353     #define SIGSEGV_FAULT_INSTRUCTION scp->eip
354 gbeauche 1.34 #define SIGSEGV_REGISTER_FILE (unsigned long *)scp
355 gbeauche 1.10 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
356 gbeauche 1.1 #endif
357     #if (defined(sparc) || defined(__sparc__))
358     #include <asm/sigcontext.h>
359 gbeauche 1.5 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp, char *addr
360 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp, addr
361 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS addr
362     #endif
363     #if (defined(powerpc) || defined(__powerpc__))
364     #include <asm/sigcontext.h>
365 gbeauche 1.4 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext *scp
366 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, scp
367 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS scp->regs->dar
368     #define SIGSEGV_FAULT_INSTRUCTION scp->regs->nip
369 gbeauche 1.49 #define SIGSEGV_REGISTER_FILE (unsigned long *)&scp->regs->nip, (unsigned long *)(scp->regs->gpr)
370 gbeauche 1.13 #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
371 gbeauche 1.1 #endif
372 gbeauche 1.4 #if (defined(alpha) || defined(__alpha__))
373     #include <asm/sigcontext.h>
374     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
375 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
376 gbeauche 1.4 #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
377     #define SIGSEGV_FAULT_INSTRUCTION scp->sc_pc
378 gbeauche 1.42 #endif
379     #if (defined(arm) || defined(__arm__))
380     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int r1, int r2, int r3, struct sigcontext sc
381     #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 struct sigcontext *scp
382     #define SIGSEGV_FAULT_HANDLER_ARGS &sc
383     #define SIGSEGV_FAULT_ADDRESS scp->fault_address
384     #define SIGSEGV_FAULT_INSTRUCTION scp->arm_pc
385 gbeauche 1.44 #define SIGSEGV_REGISTER_FILE &scp->arm_r0
386     #define SIGSEGV_SKIP_INSTRUCTION arm_skip_instruction
387 gbeauche 1.4 #endif
388 gbeauche 1.1 #endif
389    
390     // Irix 5 or 6 on MIPS
391 gbeauche 1.37 #if (defined(sgi) || defined(__sgi)) && (defined(SYSTYPE_SVR4) || defined(_SYSTYPE_SVR4))
392 gbeauche 1.11 #include <ucontext.h>
393 gbeauche 1.1 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
394 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
395 gbeauche 1.37 #define SIGSEGV_FAULT_ADDRESS (unsigned long)scp->sc_badvaddr
396     #define SIGSEGV_FAULT_INSTRUCTION (unsigned long)scp->sc_pc
397 gbeauche 1.1 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
398     #endif
399    
400 gbeauche 1.11 // HP-UX
401     #if (defined(hpux) || defined(__hpux__))
402     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
403 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
404 gbeauche 1.11 #define SIGSEGV_FAULT_ADDRESS scp->sc_sl.sl_ss.ss_narrow.ss_cr21
405     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV) FAULT_HANDLER(SIGBUS)
406     #endif
407    
408 gbeauche 1.1 // OSF/1 on Alpha
409     #if defined(__osf__)
410 gbeauche 1.11 #include <ucontext.h>
411 gbeauche 1.1 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
412 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
413 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS scp->sc_traparg_a0
414     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
415     #endif
416    
417     // AIX
418     #if defined(_AIX)
419     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
420 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
421 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS scp->sc_jmpbuf.jmp_context.o_vaddr
422     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
423     #endif
424    
425 gbeauche 1.33 // NetBSD
426     #if defined(__NetBSD__)
427 gbeauche 1.1 #if (defined(m68k) || defined(__m68k__))
428     #include <m68k/frame.h>
429     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
430 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
431 gbeauche 1.14 #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
432 gbeauche 1.1 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
433 gbeauche 1.14
434     // Use decoding scheme from BasiliskII/m68k native
435     static sigsegv_address_t get_fault_address(struct sigcontext *scp)
436     {
437     struct sigstate {
438     int ss_flags;
439     struct frame ss_frame;
440     };
441     struct sigstate *state = (struct sigstate *)scp->sc_ap;
442     char *fault_addr;
443     switch (state->ss_frame.f_format) {
444     case 7: /* 68040 access error */
445     /* "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown */
446     fault_addr = state->ss_frame.f_fmt7.f_fa;
447     break;
448     default:
449     fault_addr = (char *)code;
450     break;
451     }
452     return (sigsegv_address_t)fault_addr;
453     }
454 gbeauche 1.33 #endif
455     #if (defined(alpha) || defined(__alpha__))
456     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
457     #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
458     #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
459     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
460     #endif
461     #if (defined(i386) || defined(__i386__))
462     #error "FIXME: need to decode instruction and compute EA"
463     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
464     #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
465     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
466     #endif
467     #endif
468     #if defined(__FreeBSD__)
469 gbeauche 1.39 #if (defined(i386) || defined(__i386__))
470 gbeauche 1.33 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
471     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp, char *addr
472 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp, addr
473 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS addr
474 gbeauche 1.33 #define SIGSEGV_FAULT_INSTRUCTION scp->sc_eip
475 gbeauche 1.34 #define SIGSEGV_REGISTER_FILE ((unsigned long *)&scp->sc_edi)
476 gbeauche 1.33 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
477 gbeauche 1.1 #endif
478 gbeauche 1.39 #if (defined(alpha) || defined(__alpha__))
479     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
480     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, char *addr, struct sigcontext *scp
481     #define SIGSEGV_FAULT_HANDLER_ARGS sig, addr, scp
482     #define SIGSEGV_FAULT_ADDRESS addr
483     #define SIGSEGV_FAULT_INSTRUCTION scp->sc_pc
484     #endif
485 gbeauche 1.1 #endif
486 gbeauche 1.33
487     // Extract fault address out of a sigcontext
488     #if (defined(alpha) || defined(__alpha__))
489     // From Boehm's GC 6.0alpha8
490     static sigsegv_address_t get_fault_address(struct sigcontext *scp)
491     {
492     unsigned int instruction = *((unsigned int *)(scp->sc_pc));
493     unsigned long fault_address = scp->sc_regs[(instruction >> 16) & 0x1f];
494     fault_address += (signed long)(signed short)(instruction & 0xffff);
495     return (sigsegv_address_t)fault_address;
496     }
497     #endif
498    
499 gbeauche 1.4
500 gbeauche 1.27 // MacOS X, not sure which version this works in. Under 10.1
501     // vm_protect does not appear to work from a signal handler. Under
502     // 10.2 signal handlers get siginfo type arguments but the si_addr
503     // field is the address of the faulting instruction and not the
504     // address that caused the SIGBUS. Maybe this works in 10.0? In any
505     // case with Mach exception handlers there is a way to do what this
506     // was meant to do.
507     #ifndef HAVE_MACH_EXCEPTIONS
508 gbeauche 1.4 #if defined(__APPLE__) && defined(__MACH__)
509     #if (defined(ppc) || defined(__ppc__))
510     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
511 gbeauche 1.27 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
512 gbeauche 1.4 #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
513     #define SIGSEGV_FAULT_INSTRUCTION scp->sc_ir
514     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
515 gbeauche 1.14 #define SIGSEGV_REGISTER_FILE (unsigned int *)&scp->sc_ir, &((unsigned int *) scp->sc_regs)[2]
516     #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
517 gbeauche 1.4
518 gbeauche 1.14 // Use decoding scheme from SheepShaver
519 gbeauche 1.4 static sigsegv_address_t get_fault_address(struct sigcontext *scp)
520     {
521 gbeauche 1.14 unsigned int nip = (unsigned int) scp->sc_ir;
522     unsigned int * gpr = &((unsigned int *) scp->sc_regs)[2];
523     instruction_t instr;
524    
525     powerpc_decode_instruction(&instr, nip, gpr);
526     return (sigsegv_address_t)instr.addr;
527 gbeauche 1.4 }
528     #endif
529     #endif
530 gbeauche 1.1 #endif
531 gbeauche 1.27 #endif
532    
533 gbeauche 1.48 #if HAVE_WIN32_EXCEPTIONS
534     #define WIN32_LEAN_AND_MEAN /* avoid including junk */
535     #include <windows.h>
536     #include <winerror.h>
537    
538     #define SIGSEGV_FAULT_HANDLER_ARGLIST EXCEPTION_POINTERS *ExceptionInfo
539     #define SIGSEGV_FAULT_HANDLER_ARGS ExceptionInfo
540     #define SIGSEGV_FAULT_ADDRESS ExceptionInfo->ExceptionRecord->ExceptionInformation[1]
541     #define SIGSEGV_CONTEXT_REGS ExceptionInfo->ContextRecord
542     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS->Eip
543     #define SIGSEGV_REGISTER_FILE ((unsigned long *)&SIGSEGV_CONTEXT_REGS->Edi)
544     #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
545     #endif
546    
547 gbeauche 1.27 #if HAVE_MACH_EXCEPTIONS
548    
549     // This can easily be extended to other Mach systems, but really who
550     // uses HURD (oops GNU/HURD), Darwin/x86, NextStep, Rhapsody, or CMU
551     // Mach 2.5/3.0?
552     #if defined(__APPLE__) && defined(__MACH__)
553    
554     #include <sys/types.h>
555     #include <stdlib.h>
556     #include <stdio.h>
557     #include <pthread.h>
558    
559     /*
560     * If you are familiar with MIG then you will understand the frustration
561     * that was necessary to get these embedded into C++ code by hand.
562     */
563     extern "C" {
564     #include <mach/mach.h>
565     #include <mach/mach_error.h>
566    
567     extern boolean_t exc_server(mach_msg_header_t *, mach_msg_header_t *);
568     extern kern_return_t catch_exception_raise(mach_port_t, mach_port_t,
569     mach_port_t, exception_type_t, exception_data_t, mach_msg_type_number_t);
570     extern kern_return_t exception_raise(mach_port_t, mach_port_t, mach_port_t,
571     exception_type_t, exception_data_t, mach_msg_type_number_t);
572     extern kern_return_t exception_raise_state(mach_port_t, exception_type_t,
573     exception_data_t, mach_msg_type_number_t, thread_state_flavor_t *,
574     thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t *);
575     extern kern_return_t exception_raise_state_identity(mach_port_t, mach_port_t, mach_port_t,
576     exception_type_t, exception_data_t, mach_msg_type_number_t, thread_state_flavor_t *,
577     thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t *);
578     }
579    
580     // Could make this dynamic by looking for a result of MIG_ARRAY_TOO_LARGE
581     #define HANDLER_COUNT 64
582    
583     // structure to tuck away existing exception handlers
584     typedef struct _ExceptionPorts {
585     mach_msg_type_number_t maskCount;
586     exception_mask_t masks[HANDLER_COUNT];
587     exception_handler_t handlers[HANDLER_COUNT];
588     exception_behavior_t behaviors[HANDLER_COUNT];
589     thread_state_flavor_t flavors[HANDLER_COUNT];
590     } ExceptionPorts;
591    
592     // exception handler thread
593     static pthread_t exc_thread;
594    
595     // place where old exception handler info is stored
596     static ExceptionPorts ports;
597    
598     // our exception port
599     static mach_port_t _exceptionPort = MACH_PORT_NULL;
600    
601     #define MACH_CHECK_ERROR(name,ret) \
602     if (ret != KERN_SUCCESS) { \
603     mach_error(#name, ret); \
604     exit (1); \
605     }
606    
607 gbeauche 1.56 #ifdef __ppc__
608 gbeauche 1.66 #define SIGSEGV_EXCEPTION_STATE_TYPE ppc_exception_state_t
609     #define SIGSEGV_EXCEPTION_STATE_FLAVOR PPC_EXCEPTION_STATE
610     #define SIGSEGV_EXCEPTION_STATE_COUNT PPC_EXCEPTION_STATE_COUNT
611 gbeauche 1.72 #define SIGSEGV_FAULT_ADDRESS SIP->exc_state.dar
612 gbeauche 1.56 #define SIGSEGV_THREAD_STATE_TYPE ppc_thread_state_t
613     #define SIGSEGV_THREAD_STATE_FLAVOR PPC_THREAD_STATE
614     #define SIGSEGV_THREAD_STATE_COUNT PPC_THREAD_STATE_COUNT
615 gbeauche 1.72 #define SIGSEGV_FAULT_INSTRUCTION SIP->thr_state.srr0
616 gbeauche 1.56 #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
617 gbeauche 1.72 #define SIGSEGV_REGISTER_FILE (unsigned long *)&SIP->thr_state.srr0, (unsigned long *)&SIP->thr_state.r0
618 gbeauche 1.56 #endif
619 gbeauche 1.69 #ifdef __ppc64__
620     #define SIGSEGV_EXCEPTION_STATE_TYPE ppc_exception_state64_t
621     #define SIGSEGV_EXCEPTION_STATE_FLAVOR PPC_EXCEPTION_STATE64
622     #define SIGSEGV_EXCEPTION_STATE_COUNT PPC_EXCEPTION_STATE64_COUNT
623 gbeauche 1.72 #define SIGSEGV_FAULT_ADDRESS SIP->exc_state.dar
624 gbeauche 1.69 #define SIGSEGV_THREAD_STATE_TYPE ppc_thread_state64_t
625     #define SIGSEGV_THREAD_STATE_FLAVOR PPC_THREAD_STATE64
626     #define SIGSEGV_THREAD_STATE_COUNT PPC_THREAD_STATE64_COUNT
627 gbeauche 1.72 #define SIGSEGV_FAULT_INSTRUCTION SIP->thr_state.srr0
628 gbeauche 1.69 #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
629 gbeauche 1.72 #define SIGSEGV_REGISTER_FILE (unsigned long *)&SIP->thr_state.srr0, (unsigned long *)&SIP->thr_state.r0
630 gbeauche 1.69 #endif
631 gbeauche 1.56 #ifdef __i386__
632 gbeauche 1.66 #define SIGSEGV_EXCEPTION_STATE_TYPE struct i386_exception_state
633     #define SIGSEGV_EXCEPTION_STATE_FLAVOR i386_EXCEPTION_STATE
634     #define SIGSEGV_EXCEPTION_STATE_COUNT i386_EXCEPTION_STATE_COUNT
635 gbeauche 1.72 #define SIGSEGV_FAULT_ADDRESS SIP->exc_state.faultvaddr
636 gbeauche 1.57 #define SIGSEGV_THREAD_STATE_TYPE struct i386_thread_state
637     #define SIGSEGV_THREAD_STATE_FLAVOR i386_THREAD_STATE
638     #define SIGSEGV_THREAD_STATE_COUNT i386_THREAD_STATE_COUNT
639 gbeauche 1.72 #define SIGSEGV_FAULT_INSTRUCTION SIP->thr_state.eip
640 gbeauche 1.56 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
641 gbeauche 1.72 #define SIGSEGV_REGISTER_FILE ((unsigned long *)&SIP->thr_state.eax) /* EAX is the first GPR we consider */
642 gbeauche 1.56 #endif
643 gbeauche 1.66 #ifdef __x86_64__
644     #define SIGSEGV_EXCEPTION_STATE_TYPE struct x86_exception_state64
645     #define SIGSEGV_EXCEPTION_STATE_FLAVOR x86_EXCEPTION_STATE64
646     #define SIGSEGV_EXCEPTION_STATE_COUNT x86_EXCEPTION_STATE64_COUNT
647 gbeauche 1.72 #define SIGSEGV_FAULT_ADDRESS SIP->exc_state.faultvaddr
648 gbeauche 1.66 #define SIGSEGV_THREAD_STATE_TYPE struct x86_thread_state64
649     #define SIGSEGV_THREAD_STATE_FLAVOR x86_THREAD_STATE64
650     #define SIGSEGV_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT
651 gbeauche 1.72 #define SIGSEGV_FAULT_INSTRUCTION SIP->thr_state.rip
652 gbeauche 1.66 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
653 gbeauche 1.72 #define SIGSEGV_REGISTER_FILE ((unsigned long *)&SIP->thr_state.rax) /* RAX is the first GPR we consider */
654 gbeauche 1.66 #endif
655 gbeauche 1.68 #define SIGSEGV_FAULT_ADDRESS_FAST code[1]
656     #define SIGSEGV_FAULT_INSTRUCTION_FAST SIGSEGV_INVALID_ADDRESS
657 gbeauche 1.66 #define SIGSEGV_FAULT_HANDLER_ARGLIST mach_port_t thread, exception_data_t code
658     #define SIGSEGV_FAULT_HANDLER_ARGS thread, code
659 gbeauche 1.27
660     // Since there can only be one exception thread running at any time
661     // this is not a problem.
662     #define MSG_SIZE 512
663     static char msgbuf[MSG_SIZE];
664     static char replybuf[MSG_SIZE];
665    
666     /*
667     * This is the entry point for the exception handler thread. The job
668     * of this thread is to wait for exception messages on the exception
669     * port that was setup beforehand and to pass them on to exc_server.
670     * exc_server is a MIG generated function that is a part of Mach.
671     * Its job is to decide what to do with the exception message. In our
672     * case exc_server calls catch_exception_raise on our behalf. After
673     * exc_server returns, it is our responsibility to send the reply.
674     */
675     static void *
676     handleExceptions(void *priv)
677     {
678     mach_msg_header_t *msg, *reply;
679     kern_return_t krc;
680    
681     msg = (mach_msg_header_t *)msgbuf;
682     reply = (mach_msg_header_t *)replybuf;
683    
684     for (;;) {
685     krc = mach_msg(msg, MACH_RCV_MSG, MSG_SIZE, MSG_SIZE,
686     _exceptionPort, 0, MACH_PORT_NULL);
687     MACH_CHECK_ERROR(mach_msg, krc);
688    
689     if (!exc_server(msg, reply)) {
690     fprintf(stderr, "exc_server hated the message\n");
691     exit(1);
692     }
693    
694     krc = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0,
695     msg->msgh_local_port, 0, MACH_PORT_NULL);
696     if (krc != KERN_SUCCESS) {
697     fprintf(stderr, "Error sending message to original reply port, krc = %d, %s",
698     krc, mach_error_string(krc));
699     exit(1);
700     }
701     }
702     }
703     #endif
704     #endif
705 gbeauche 1.1
706 gbeauche 1.14
707     /*
708     * Instruction skipping
709     */
710    
711 gbeauche 1.10 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
712     // Decode and skip X86 instruction
713 gbeauche 1.34 #if (defined(i386) || defined(__i386__)) || defined(__x86_64__)
714 gbeauche 1.10 #if defined(__linux__)
715     enum {
716 gbeauche 1.34 #if (defined(i386) || defined(__i386__))
717 gbeauche 1.10 X86_REG_EIP = 14,
718     X86_REG_EAX = 11,
719     X86_REG_ECX = 10,
720     X86_REG_EDX = 9,
721     X86_REG_EBX = 8,
722     X86_REG_ESP = 7,
723     X86_REG_EBP = 6,
724     X86_REG_ESI = 5,
725     X86_REG_EDI = 4
726 gbeauche 1.34 #endif
727     #if defined(__x86_64__)
728     X86_REG_R8 = 0,
729     X86_REG_R9 = 1,
730     X86_REG_R10 = 2,
731     X86_REG_R11 = 3,
732     X86_REG_R12 = 4,
733     X86_REG_R13 = 5,
734     X86_REG_R14 = 6,
735     X86_REG_R15 = 7,
736     X86_REG_EDI = 8,
737     X86_REG_ESI = 9,
738     X86_REG_EBP = 10,
739     X86_REG_EBX = 11,
740     X86_REG_EDX = 12,
741     X86_REG_EAX = 13,
742     X86_REG_ECX = 14,
743     X86_REG_ESP = 15,
744     X86_REG_EIP = 16
745     #endif
746 gbeauche 1.10 };
747     #endif
748 gbeauche 1.51 #if defined(__NetBSD__)
749     enum {
750     #if (defined(i386) || defined(__i386__))
751     X86_REG_EIP = _REG_EIP,
752     X86_REG_EAX = _REG_EAX,
753     X86_REG_ECX = _REG_ECX,
754     X86_REG_EDX = _REG_EDX,
755     X86_REG_EBX = _REG_EBX,
756     X86_REG_ESP = _REG_ESP,
757     X86_REG_EBP = _REG_EBP,
758     X86_REG_ESI = _REG_ESI,
759     X86_REG_EDI = _REG_EDI
760     #endif
761     };
762     #endif
763     #if defined(__FreeBSD__)
764 gbeauche 1.17 enum {
765 gbeauche 1.34 #if (defined(i386) || defined(__i386__))
766 gbeauche 1.17 X86_REG_EIP = 10,
767     X86_REG_EAX = 7,
768     X86_REG_ECX = 6,
769     X86_REG_EDX = 5,
770     X86_REG_EBX = 4,
771     X86_REG_ESP = 13,
772     X86_REG_EBP = 2,
773     X86_REG_ESI = 1,
774     X86_REG_EDI = 0
775 gbeauche 1.34 #endif
776 gbeauche 1.17 };
777     #endif
778 gbeauche 1.55 #if defined(__OpenBSD__)
779     enum {
780     #if defined(__i386__)
781     // EDI is the first register we consider
782     #define OREG(REG) offsetof(struct sigcontext, sc_##REG)
783     #define DREG(REG) ((OREG(REG) - OREG(edi)) / 4)
784     X86_REG_EIP = DREG(eip), // 7
785     X86_REG_EAX = DREG(eax), // 6
786     X86_REG_ECX = DREG(ecx), // 5
787     X86_REG_EDX = DREG(edx), // 4
788     X86_REG_EBX = DREG(ebx), // 3
789     X86_REG_ESP = DREG(esp), // 10
790     X86_REG_EBP = DREG(ebp), // 2
791     X86_REG_ESI = DREG(esi), // 1
792     X86_REG_EDI = DREG(edi) // 0
793     #undef DREG
794     #undef OREG
795     #endif
796     };
797     #endif
798 gbeauche 1.54 #if defined(__sun__)
799     // Same as for Linux, need to check for x86-64
800     enum {
801     #if defined(__i386__)
802     X86_REG_EIP = EIP,
803     X86_REG_EAX = EAX,
804     X86_REG_ECX = ECX,
805     X86_REG_EDX = EDX,
806     X86_REG_EBX = EBX,
807     X86_REG_ESP = ESP,
808     X86_REG_EBP = EBP,
809     X86_REG_ESI = ESI,
810     X86_REG_EDI = EDI
811     #endif
812     };
813     #endif
814 gbeauche 1.56 #if defined(__APPLE__) && defined(__MACH__)
815     enum {
816 gbeauche 1.66 #if (defined(i386) || defined(__i386__))
817 gbeauche 1.57 #ifdef i386_SAVED_STATE
818     // same as FreeBSD (in Open Darwin 8.0.1)
819 gbeauche 1.56 X86_REG_EIP = 10,
820     X86_REG_EAX = 7,
821     X86_REG_ECX = 6,
822     X86_REG_EDX = 5,
823     X86_REG_EBX = 4,
824     X86_REG_ESP = 13,
825     X86_REG_EBP = 2,
826     X86_REG_ESI = 1,
827     X86_REG_EDI = 0
828 gbeauche 1.57 #else
829     // new layout (MacOS X 10.4.4 for x86)
830     X86_REG_EIP = 10,
831     X86_REG_EAX = 0,
832     X86_REG_ECX = 2,
833 gbeauche 1.66 X86_REG_EDX = 3,
834 gbeauche 1.57 X86_REG_EBX = 1,
835     X86_REG_ESP = 7,
836     X86_REG_EBP = 6,
837     X86_REG_ESI = 5,
838     X86_REG_EDI = 4
839     #endif
840 gbeauche 1.66 #endif
841     #if defined(__x86_64__)
842     X86_REG_R8 = 8,
843     X86_REG_R9 = 9,
844     X86_REG_R10 = 10,
845     X86_REG_R11 = 11,
846     X86_REG_R12 = 12,
847     X86_REG_R13 = 13,
848     X86_REG_R14 = 14,
849     X86_REG_R15 = 15,
850     X86_REG_EDI = 4,
851     X86_REG_ESI = 5,
852     X86_REG_EBP = 6,
853     X86_REG_EBX = 1,
854     X86_REG_EDX = 3,
855     X86_REG_EAX = 0,
856     X86_REG_ECX = 2,
857     X86_REG_ESP = 7,
858     X86_REG_EIP = 16
859     #endif
860 gbeauche 1.56 };
861     #endif
862 gbeauche 1.48 #if defined(_WIN32)
863     enum {
864     #if (defined(i386) || defined(__i386__))
865     X86_REG_EIP = 7,
866     X86_REG_EAX = 5,
867     X86_REG_ECX = 4,
868     X86_REG_EDX = 3,
869     X86_REG_EBX = 2,
870     X86_REG_ESP = 10,
871     X86_REG_EBP = 6,
872     X86_REG_ESI = 1,
873     X86_REG_EDI = 0
874     #endif
875     };
876     #endif
877 gbeauche 1.10 // FIXME: this is partly redundant with the instruction decoding phase
878     // to discover transfer type and register number
879     static inline int ix86_step_over_modrm(unsigned char * p)
880     {
881     int mod = (p[0] >> 6) & 3;
882     int rm = p[0] & 7;
883     int offset = 0;
884    
885     // ModR/M Byte
886     switch (mod) {
887     case 0: // [reg]
888     if (rm == 5) return 4; // disp32
889     break;
890     case 1: // disp8[reg]
891     offset = 1;
892     break;
893     case 2: // disp32[reg]
894     offset = 4;
895     break;
896     case 3: // register
897     return 0;
898     }
899    
900     // SIB Byte
901     if (rm == 4) {
902     if (mod == 0 && (p[1] & 7) == 5)
903     offset = 5; // disp32[index]
904     else
905     offset++;
906     }
907    
908     return offset;
909     }
910    
911 gbeauche 1.34 static bool ix86_skip_instruction(unsigned long * regs)
912 gbeauche 1.10 {
913 gbeauche 1.14 unsigned char * eip = (unsigned char *)regs[X86_REG_EIP];
914 gbeauche 1.10
915     if (eip == 0)
916     return false;
917 gbeauche 1.50 #ifdef _WIN32
918     if (IsBadCodePtr((FARPROC)eip))
919     return false;
920     #endif
921 gbeauche 1.10
922 gbeauche 1.64 enum instruction_type_t {
923     i_MOV,
924     i_ADD
925     };
926    
927 gbeauche 1.22 transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
928 gbeauche 1.14 transfer_size_t transfer_size = SIZE_LONG;
929 gbeauche 1.64 instruction_type_t instruction_type = i_MOV;
930 gbeauche 1.10
931     int reg = -1;
932     int len = 0;
933 gbeauche 1.34
934     #if DEBUG
935     printf("IP: %p [%02x %02x %02x %02x...]\n",
936     eip, eip[0], eip[1], eip[2], eip[3]);
937     #endif
938    
939 gbeauche 1.10 // Operand size prefix
940     if (*eip == 0x66) {
941     eip++;
942     len++;
943     transfer_size = SIZE_WORD;
944     }
945    
946 gbeauche 1.34 // REX prefix
947     #if defined(__x86_64__)
948     struct rex_t {
949     unsigned char W;
950     unsigned char R;
951     unsigned char X;
952     unsigned char B;
953     };
954     rex_t rex = { 0, 0, 0, 0 };
955     bool has_rex = false;
956     if ((*eip & 0xf0) == 0x40) {
957     has_rex = true;
958     const unsigned char b = *eip;
959     rex.W = b & (1 << 3);
960     rex.R = b & (1 << 2);
961     rex.X = b & (1 << 1);
962     rex.B = b & (1 << 0);
963     #if DEBUG
964     printf("REX: %c,%c,%c,%c\n",
965     rex.W ? 'W' : '_',
966     rex.R ? 'R' : '_',
967     rex.X ? 'X' : '_',
968     rex.B ? 'B' : '_');
969     #endif
970     eip++;
971     len++;
972     if (rex.W)
973     transfer_size = SIZE_QUAD;
974     }
975     #else
976     const bool has_rex = false;
977     #endif
978    
979 gbeauche 1.10 // Decode instruction
980 gbeauche 1.64 int op_len = 1;
981 gbeauche 1.45 int target_size = SIZE_UNKNOWN;
982 gbeauche 1.10 switch (eip[0]) {
983 gbeauche 1.17 case 0x0f:
984 gbeauche 1.45 target_size = transfer_size;
985 gbeauche 1.18 switch (eip[1]) {
986 gbeauche 1.45 case 0xbe: // MOVSX r32, r/m8
987 gbeauche 1.18 case 0xb6: // MOVZX r32, r/m8
988 gbeauche 1.45 transfer_size = SIZE_BYTE;
989     goto do_mov_extend;
990 gbeauche 1.47 case 0xbf: // MOVSX r32, r/m16
991 gbeauche 1.18 case 0xb7: // MOVZX r32, r/m16
992 gbeauche 1.45 transfer_size = SIZE_WORD;
993     goto do_mov_extend;
994     do_mov_extend:
995 gbeauche 1.64 op_len = 2;
996     goto do_transfer_load;
997     }
998     break;
999 gbeauche 1.62 #if defined(__x86_64__)
1000     case 0x63: // MOVSXD r64, r/m32
1001     if (has_rex && rex.W) {
1002     transfer_size = SIZE_LONG;
1003     target_size = SIZE_QUAD;
1004     }
1005     else if (transfer_size != SIZE_WORD) {
1006     transfer_size = SIZE_LONG;
1007     target_size = SIZE_QUAD;
1008     }
1009 gbeauche 1.64 goto do_transfer_load;
1010 gbeauche 1.62 #endif
1011 gbeauche 1.64 case 0x02: // ADD r8, r/m8
1012     transfer_size = SIZE_BYTE;
1013     case 0x03: // ADD r32, r/m32
1014     instruction_type = i_ADD;
1015     goto do_transfer_load;
1016 gbeauche 1.10 case 0x8a: // MOV r8, r/m8
1017     transfer_size = SIZE_BYTE;
1018     case 0x8b: // MOV r32, r/m32 (or 16-bit operation)
1019 gbeauche 1.64 do_transfer_load:
1020     switch (eip[op_len] & 0xc0) {
1021 gbeauche 1.10 case 0x80:
1022 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
1023 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
1024 gbeauche 1.10 break;
1025     case 0x40:
1026 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
1027 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
1028 gbeauche 1.10 break;
1029     case 0x00:
1030 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
1031 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
1032 gbeauche 1.10 break;
1033     }
1034 gbeauche 1.64 len += 1 + op_len + ix86_step_over_modrm(eip + op_len);
1035 gbeauche 1.10 break;
1036 gbeauche 1.64 case 0x00: // ADD r/m8, r8
1037     transfer_size = SIZE_BYTE;
1038     case 0x01: // ADD r/m32, r32
1039     instruction_type = i_ADD;
1040     goto do_transfer_store;
1041 gbeauche 1.10 case 0x88: // MOV r/m8, r8
1042     transfer_size = SIZE_BYTE;
1043     case 0x89: // MOV r/m32, r32 (or 16-bit operation)
1044 gbeauche 1.64 do_transfer_store:
1045     switch (eip[op_len] & 0xc0) {
1046 gbeauche 1.10 case 0x80:
1047 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
1048 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
1049 gbeauche 1.10 break;
1050     case 0x40:
1051 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
1052 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
1053 gbeauche 1.10 break;
1054     case 0x00:
1055 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
1056 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
1057 gbeauche 1.10 break;
1058     }
1059 gbeauche 1.64 len += 1 + op_len + ix86_step_over_modrm(eip + op_len);
1060 gbeauche 1.10 break;
1061     }
1062 gbeauche 1.45 if (target_size == SIZE_UNKNOWN)
1063     target_size = transfer_size;
1064 gbeauche 1.10
1065 gbeauche 1.22 if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1066 gbeauche 1.10 // Unknown machine code, let it crash. Then patch the decoder
1067     return false;
1068     }
1069    
1070 gbeauche 1.34 #if defined(__x86_64__)
1071     if (rex.R)
1072     reg += 8;
1073     #endif
1074    
1075 gbeauche 1.64 if (instruction_type == i_MOV && transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) {
1076 gbeauche 1.34 static const int x86_reg_map[] = {
1077 gbeauche 1.10 X86_REG_EAX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBX,
1078 gbeauche 1.34 X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI,
1079     #if defined(__x86_64__)
1080     X86_REG_R8, X86_REG_R9, X86_REG_R10, X86_REG_R11,
1081     X86_REG_R12, X86_REG_R13, X86_REG_R14, X86_REG_R15,
1082     #endif
1083 gbeauche 1.10 };
1084    
1085 gbeauche 1.34 if (reg < 0 || reg >= (sizeof(x86_reg_map)/sizeof(x86_reg_map[0]) - 1))
1086 gbeauche 1.10 return false;
1087    
1088 gbeauche 1.34 // Set 0 to the relevant register part
1089     // NOTE: this is only valid for MOV alike instructions
1090 gbeauche 1.10 int rloc = x86_reg_map[reg];
1091 gbeauche 1.45 switch (target_size) {
1092 gbeauche 1.10 case SIZE_BYTE:
1093 gbeauche 1.36 if (has_rex || reg < 4)
1094     regs[rloc] = (regs[rloc] & ~0x00ffL);
1095     else {
1096     rloc = x86_reg_map[reg - 4];
1097     regs[rloc] = (regs[rloc] & ~0xff00L);
1098     }
1099 gbeauche 1.10 break;
1100     case SIZE_WORD:
1101 gbeauche 1.34 regs[rloc] = (regs[rloc] & ~0xffffL);
1102 gbeauche 1.10 break;
1103     case SIZE_LONG:
1104 gbeauche 1.34 case SIZE_QUAD: // zero-extension
1105 gbeauche 1.10 regs[rloc] = 0;
1106     break;
1107     }
1108     }
1109    
1110     #if DEBUG
1111 gbeauche 1.64 printf("%p: %s %s access", (void *)regs[X86_REG_EIP],
1112 gbeauche 1.34 transfer_size == SIZE_BYTE ? "byte" :
1113     transfer_size == SIZE_WORD ? "word" :
1114     transfer_size == SIZE_LONG ? "long" :
1115     transfer_size == SIZE_QUAD ? "quad" : "unknown",
1116 gbeauche 1.22 transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
1117 gbeauche 1.10
1118     if (reg != -1) {
1119 gbeauche 1.34 static const char * x86_byte_reg_str_map[] = {
1120     "al", "cl", "dl", "bl",
1121     "spl", "bpl", "sil", "dil",
1122     "r8b", "r9b", "r10b", "r11b",
1123     "r12b", "r13b", "r14b", "r15b",
1124     "ah", "ch", "dh", "bh",
1125     };
1126     static const char * x86_word_reg_str_map[] = {
1127     "ax", "cx", "dx", "bx",
1128     "sp", "bp", "si", "di",
1129     "r8w", "r9w", "r10w", "r11w",
1130     "r12w", "r13w", "r14w", "r15w",
1131     };
1132     static const char *x86_long_reg_str_map[] = {
1133     "eax", "ecx", "edx", "ebx",
1134     "esp", "ebp", "esi", "edi",
1135     "r8d", "r9d", "r10d", "r11d",
1136     "r12d", "r13d", "r14d", "r15d",
1137     };
1138     static const char *x86_quad_reg_str_map[] = {
1139     "rax", "rcx", "rdx", "rbx",
1140     "rsp", "rbp", "rsi", "rdi",
1141     "r8", "r9", "r10", "r11",
1142     "r12", "r13", "r14", "r15",
1143 gbeauche 1.10 };
1144 gbeauche 1.34 const char * reg_str = NULL;
1145 gbeauche 1.46 switch (target_size) {
1146 gbeauche 1.34 case SIZE_BYTE:
1147     reg_str = x86_byte_reg_str_map[(!has_rex && reg >= 4 ? 12 : 0) + reg];
1148     break;
1149     case SIZE_WORD: reg_str = x86_word_reg_str_map[reg]; break;
1150     case SIZE_LONG: reg_str = x86_long_reg_str_map[reg]; break;
1151     case SIZE_QUAD: reg_str = x86_quad_reg_str_map[reg]; break;
1152     }
1153     if (reg_str)
1154     printf(" %s register %%%s",
1155     transfer_type == SIGSEGV_TRANSFER_LOAD ? "to" : "from",
1156     reg_str);
1157 gbeauche 1.10 }
1158     printf(", %d bytes instruction\n", len);
1159     #endif
1160    
1161     regs[X86_REG_EIP] += len;
1162 gbeauche 1.13 return true;
1163     }
1164     #endif
1165 gbeauche 1.14
1166 gbeauche 1.75 // Decode and skip IA-64 instruction
1167     #if defined(__ia64__)
1168     #if defined(__linux__)
1169 gbeauche 1.77 // We can directly patch the slot number
1170     #define IA64_CAN_PATCH_IP_SLOT 1
1171     // Helper macros to access the machine context
1172     #define IA64_CONTEXT_TYPE struct sigcontext *
1173     #define IA64_CONTEXT scp
1174     #define IA64_GET_IP() (IA64_CONTEXT->sc_ip)
1175     #define IA64_SET_IP(V) (IA64_CONTEXT->sc_ip = (V))
1176     #define IA64_GET_PR(P) ((IA64_CONTEXT->sc_pr >> (P)) & 1)
1177     #define IA64_GET_NAT(I) ((IA64_CONTEXT->sc_nat >> (I)) & 1)
1178     #define IA64_SET_NAT(I,V) (IA64_CONTEXT->sc_nat= (IA64_CONTEXT->sc_nat & ~(1ul << (I))) | (((unsigned long)!!(V)) << (I)))
1179     #define IA64_GET_GR(R) (IA64_CONTEXT->sc_gr[(R)])
1180     #define IA64_SET_GR(R,V) (IA64_CONTEXT->sc_gr[(R)] = (V))
1181 gbeauche 1.75 #endif
1182    
1183     // Instruction operations
1184     enum {
1185     IA64_INST_UNKNOWN = 0,
1186     IA64_INST_LD1, // ld1 op0=[op1]
1187     IA64_INST_LD1_UPDATE, // ld1 op0=[op1],op2
1188     IA64_INST_LD2, // ld2 op0=[op1]
1189     IA64_INST_LD2_UPDATE, // ld2 op0=[op1],op2
1190     IA64_INST_LD4, // ld4 op0=[op1]
1191     IA64_INST_LD4_UPDATE, // ld4 op0=[op1],op2
1192     IA64_INST_LD8, // ld8 op0=[op1]
1193     IA64_INST_LD8_UPDATE, // ld8 op0=[op1],op2
1194     IA64_INST_ST1, // st1 [op0]=op1
1195     IA64_INST_ST1_UPDATE, // st1 [op0]=op1,op2
1196     IA64_INST_ST2, // st2 [op0]=op1
1197     IA64_INST_ST2_UPDATE, // st2 [op0]=op1,op2
1198     IA64_INST_ST4, // st4 [op0]=op1
1199     IA64_INST_ST4_UPDATE, // st4 [op0]=op1,op2
1200     IA64_INST_ST8, // st8 [op0]=op1
1201     IA64_INST_ST8_UPDATE, // st8 [op0]=op1,op2
1202     IA64_INST_ADD, // add op0=op1,op2,op3
1203     IA64_INST_SUB, // sub op0=op1,op2,op3
1204     IA64_INST_SHLADD, // shladd op0=op1,op3,op2
1205     IA64_INST_AND, // and op0=op1,op2
1206     IA64_INST_ANDCM, // andcm op0=op1,op2
1207     IA64_INST_OR, // or op0=op1,op2
1208     IA64_INST_XOR, // xor op0=op1,op2
1209     IA64_INST_SXT1, // sxt1 op0=op1
1210     IA64_INST_SXT2, // sxt2 op0=op1
1211     IA64_INST_SXT4, // sxt4 op0=op1
1212     IA64_INST_ZXT1, // zxt1 op0=op1
1213     IA64_INST_ZXT2, // zxt2 op0=op1
1214     IA64_INST_ZXT4, // zxt4 op0=op1
1215     IA64_INST_NOP // nop op0
1216     };
1217    
1218     const int IA64_N_OPERANDS = 4;
1219    
1220     // Decoded operand type
1221     struct ia64_operand_t {
1222 gbeauche 1.76 unsigned char commit; // commit result of operation to register file?
1223     unsigned char valid; // XXX: not really used, can be removed (debug)
1224     signed char index; // index of GPR, or -1 if immediate value
1225     unsigned char nat; // NaT state before operation
1226     unsigned long value; // register contents or immediate value
1227 gbeauche 1.75 };
1228    
1229     // Decoded instruction type
1230     struct ia64_instruction_t {
1231 gbeauche 1.76 unsigned char mnemo; // operation to perform
1232     unsigned char pred; // predicate register to check
1233     unsigned char no_memory; // used to emulated main fault instruction
1234     unsigned long inst; // the raw instruction bits (41-bit wide)
1235 gbeauche 1.75 ia64_operand_t operands[IA64_N_OPERANDS];
1236     };
1237    
1238     // Get immediate sign-bit
1239     static inline int ia64_inst_get_sbit(unsigned long inst)
1240     {
1241     return (inst >> 36) & 1;
1242     }
1243    
1244     // Get 8-bit immediate value (A3, A8, I27, M30)
1245     static inline unsigned long ia64_inst_get_imm8(unsigned long inst)
1246     {
1247     unsigned long value = (inst >> 13) & 0x7ful;
1248     if (ia64_inst_get_sbit(inst))
1249     value |= ~0x7ful;
1250     return value;
1251     }
1252    
1253     // Get 9-bit immediate value (M3)
1254     static inline unsigned long ia64_inst_get_imm9b(unsigned long inst)
1255     {
1256     unsigned long value = (((inst >> 27) & 1) << 7) | ((inst >> 13) & 0x7f);
1257     if (ia64_inst_get_sbit(inst))
1258     value |= ~0xfful;
1259     return value;
1260     }
1261    
1262     // Get 9-bit immediate value (M5)
1263     static inline unsigned long ia64_inst_get_imm9a(unsigned long inst)
1264     {
1265     unsigned long value = (((inst >> 27) & 1) << 7) | ((inst >> 6) & 0x7f);
1266     if (ia64_inst_get_sbit(inst))
1267     value |= ~0xfful;
1268     return value;
1269     }
1270    
1271     // Get 14-bit immediate value (A4)
1272     static inline unsigned long ia64_inst_get_imm14(unsigned long inst)
1273     {
1274     unsigned long value = (((inst >> 27) & 0x3f) << 7) | (inst & 0x7f);
1275     if (ia64_inst_get_sbit(inst))
1276     value |= ~0x1fful;
1277     return value;
1278     }
1279    
1280     // Get 22-bit immediate value (A5)
1281     static inline unsigned long ia64_inst_get_imm22(unsigned long inst)
1282     {
1283     unsigned long value = ((((inst >> 22) & 0x1f) << 16) |
1284     (((inst >> 27) & 0x1ff) << 7) |
1285     (inst & 0x7f));
1286     if (ia64_inst_get_sbit(inst))
1287     value |= ~0x1ffffful;
1288     return value;
1289     }
1290    
1291     // Get 21-bit immediate value (I19)
1292     static inline unsigned long ia64_inst_get_imm21(unsigned long inst)
1293     {
1294     return (((inst >> 36) & 1) << 20) | ((inst >> 6) & 0xfffff);
1295     }
1296    
1297     // Get 2-bit count value (A2)
1298     static inline int ia64_inst_get_count2(unsigned long inst)
1299     {
1300     return (inst >> 27) & 0x3;
1301     }
1302    
1303     // Get bundle template
1304     static inline unsigned int ia64_get_template(unsigned long raw_ip)
1305     {
1306     unsigned long *ip = (unsigned long *)(raw_ip & ~3ul);
1307     return ip[0] & 0x1f;
1308     }
1309    
1310     // Get specified instruction in bundle
1311     static unsigned long ia64_get_instruction(unsigned long raw_ip, int slot)
1312     {
1313     unsigned long inst;
1314     unsigned long *ip = (unsigned long *)(raw_ip & ~3ul);
1315     #if DEBUG
1316     printf("Bundle: %016lx%016lx\n", ip[1], ip[0]);
1317     #endif
1318    
1319     switch (slot) {
1320     case 0:
1321     inst = (ip[0] >> 5) & 0x1fffffffffful;
1322     break;
1323     case 1:
1324     inst = ((ip[1] & 0x7ffffful) << 18) | ((ip[0] >> 46) & 0x3fffful);
1325     break;
1326     case 2:
1327     inst = (ip[1] >> 23) & 0x1fffffffffful;
1328     break;
1329     case 3:
1330     fprintf(stderr, "ERROR: ia64_get_instruction(), invalid slot number %d\n", slot);
1331     abort();
1332     break;
1333     }
1334    
1335     #if DEBUG
1336     printf(" Instruction %d: 0x%016lx\n", slot, inst);
1337     #endif
1338     return inst;
1339     }
1340    
1341     // Decode group 0 instructions
1342 gbeauche 1.77 static bool ia64_decode_instruction_0(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1343 gbeauche 1.75 {
1344     const int r1 = (inst->inst >> 6) & 0x7f;
1345     const int r3 = (inst->inst >> 20) & 0x7f;
1346    
1347     const int x3 = (inst->inst >> 33) & 0x07;
1348     const int x6 = (inst->inst >> 27) & 0x3f;
1349     const int x2 = (inst->inst >> 31) & 0x03;
1350     const int x4 = (inst->inst >> 27) & 0x0f;
1351    
1352     if (x3 == 0) {
1353     switch (x6) {
1354     case 0x01: // nop.i (I19)
1355     inst->mnemo = IA64_INST_NOP;
1356     inst->operands[0].valid = true;
1357     inst->operands[0].index = -1;
1358     inst->operands[0].value = ia64_inst_get_imm21(inst->inst);
1359     return true;
1360     case 0x14: // sxt1 (I29)
1361     case 0x15: // sxt2 (I29)
1362     case 0x16: // sxt4 (I29)
1363     case 0x10: // zxt1 (I29)
1364     case 0x11: // zxt2 (I29)
1365     case 0x12: // zxt4 (I29)
1366     switch (x6) {
1367     case 0x14: inst->mnemo = IA64_INST_SXT1; break;
1368     case 0x15: inst->mnemo = IA64_INST_SXT2; break;
1369     case 0x16: inst->mnemo = IA64_INST_SXT4; break;
1370     case 0x10: inst->mnemo = IA64_INST_ZXT1; break;
1371     case 0x11: inst->mnemo = IA64_INST_ZXT2; break;
1372     case 0x12: inst->mnemo = IA64_INST_ZXT4; break;
1373     default: abort();
1374     }
1375     inst->operands[0].valid = true;
1376     inst->operands[0].index = r1;
1377     inst->operands[1].valid = true;
1378     inst->operands[1].index = r3;
1379     inst->operands[1].value = IA64_GET_GR(r3);
1380     inst->operands[1].nat = IA64_GET_NAT(r3);
1381     return true;
1382     }
1383     }
1384     return false;
1385     }
1386    
1387     // Decode group 4 instructions (load/store instructions)
1388 gbeauche 1.77 static bool ia64_decode_instruction_4(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1389 gbeauche 1.75 {
1390     const int r1 = (inst->inst >> 6) & 0x7f;
1391     const int r2 = (inst->inst >> 13) & 0x7f;
1392     const int r3 = (inst->inst >> 20) & 0x7f;
1393    
1394     const int m = (inst->inst >> 36) & 1;
1395     const int x = (inst->inst >> 27) & 1;
1396     const int x6 = (inst->inst >> 30) & 0x3f;
1397    
1398     switch (x6) {
1399     case 0x00:
1400     case 0x01:
1401     case 0x02:
1402     case 0x03:
1403     if (x == 0) {
1404     inst->operands[0].valid = true;
1405     inst->operands[0].index = r1;
1406     inst->operands[1].valid = true;
1407     inst->operands[1].index = r3;
1408     inst->operands[1].value = IA64_GET_GR(r3);
1409     inst->operands[1].nat = IA64_GET_NAT(r3);
1410     if (m == 0) {
1411     switch (x6) {
1412     case 0x00: inst->mnemo = IA64_INST_LD1; break;
1413     case 0x01: inst->mnemo = IA64_INST_LD2; break;
1414     case 0x02: inst->mnemo = IA64_INST_LD4; break;
1415     case 0x03: inst->mnemo = IA64_INST_LD8; break;
1416     }
1417     }
1418     else {
1419     inst->operands[2].valid = true;
1420     inst->operands[2].index = r2;
1421     inst->operands[2].value = IA64_GET_GR(r2);
1422     inst->operands[2].nat = IA64_GET_NAT(r2);
1423     switch (x6) {
1424     case 0x00: inst->mnemo = IA64_INST_LD1_UPDATE; break;
1425     case 0x01: inst->mnemo = IA64_INST_LD2_UPDATE; break;
1426     case 0x02: inst->mnemo = IA64_INST_LD4_UPDATE; break;
1427     case 0x03: inst->mnemo = IA64_INST_LD8_UPDATE; break;
1428     }
1429     }
1430     return true;
1431     }
1432     break;
1433     case 0x30:
1434     case 0x31:
1435     case 0x32:
1436     case 0x33:
1437     if (m == 0 && x == 0) {
1438     inst->operands[0].valid = true;
1439     inst->operands[0].index = r3;
1440     inst->operands[0].value = IA64_GET_GR(r3);
1441     inst->operands[0].nat = IA64_GET_NAT(r3);
1442     inst->operands[1].valid = true;
1443     inst->operands[1].index = r2;
1444     inst->operands[1].value = IA64_GET_GR(r2);
1445     inst->operands[1].nat = IA64_GET_NAT(r2);
1446     switch (x6) {
1447     case 0x30: inst->mnemo = IA64_INST_ST1; break;
1448     case 0x31: inst->mnemo = IA64_INST_ST2; break;
1449     case 0x32: inst->mnemo = IA64_INST_ST4; break;
1450     case 0x33: inst->mnemo = IA64_INST_ST8; break;
1451     }
1452     return true;
1453     }
1454     break;
1455     }
1456     return false;
1457     }
1458    
1459     // Decode group 5 instructions (load/store instructions)
1460 gbeauche 1.77 static bool ia64_decode_instruction_5(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1461 gbeauche 1.75 {
1462     const int r1 = (inst->inst >> 6) & 0x7f;
1463     const int r2 = (inst->inst >> 13) & 0x7f;
1464     const int r3 = (inst->inst >> 20) & 0x7f;
1465    
1466     const int x6 = (inst->inst >> 30) & 0x3f;
1467    
1468     switch (x6) {
1469     case 0x00:
1470     case 0x01:
1471     case 0x02:
1472     case 0x03:
1473     inst->operands[0].valid = true;
1474     inst->operands[0].index = r1;
1475     inst->operands[1].valid = true;
1476     inst->operands[1].index = r3;
1477     inst->operands[1].value = IA64_GET_GR(r3);
1478     inst->operands[1].nat = IA64_GET_NAT(r3);
1479     inst->operands[2].valid = true;
1480     inst->operands[2].index = -1;
1481     inst->operands[2].value = ia64_inst_get_imm9b(inst->inst);
1482     inst->operands[2].nat = 0;
1483     switch (x6) {
1484     case 0x00: inst->mnemo = IA64_INST_LD1_UPDATE; break;
1485     case 0x01: inst->mnemo = IA64_INST_LD2_UPDATE; break;
1486     case 0x02: inst->mnemo = IA64_INST_LD4_UPDATE; break;
1487     case 0x03: inst->mnemo = IA64_INST_LD8_UPDATE; break;
1488     }
1489     return true;
1490     case 0x30:
1491     case 0x31:
1492     case 0x32:
1493     case 0x33:
1494     inst->operands[0].valid = true;
1495     inst->operands[0].index = r3;
1496     inst->operands[0].value = IA64_GET_GR(r3);
1497     inst->operands[0].nat = IA64_GET_NAT(r3);
1498     inst->operands[1].valid = true;
1499     inst->operands[1].index = r2;
1500     inst->operands[1].value = IA64_GET_GR(r2);
1501     inst->operands[1].nat = IA64_GET_NAT(r2);
1502     inst->operands[2].valid = true;
1503     inst->operands[2].index = -1;
1504     inst->operands[2].value = ia64_inst_get_imm9a(inst->inst);
1505     inst->operands[2].nat = 0;
1506     switch (x6) {
1507     case 0x30: inst->mnemo = IA64_INST_ST1_UPDATE; break;
1508     case 0x31: inst->mnemo = IA64_INST_ST2_UPDATE; break;
1509     case 0x32: inst->mnemo = IA64_INST_ST4_UPDATE; break;
1510     case 0x33: inst->mnemo = IA64_INST_ST8_UPDATE; break;
1511     }
1512     return true;
1513     }
1514     return false;
1515     }
1516    
1517     // Decode group 8 instructions (ALU integer)
1518 gbeauche 1.77 static bool ia64_decode_instruction_8(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1519 gbeauche 1.75 {
1520     const int r1 = (inst->inst >> 6) & 0x7f;
1521     const int r2 = (inst->inst >> 13) & 0x7f;
1522     const int r3 = (inst->inst >> 20) & 0x7f;
1523    
1524     const int x2a = (inst->inst >> 34) & 0x3;
1525     const int x2b = (inst->inst >> 27) & 0x3;
1526     const int x4 = (inst->inst >> 29) & 0xf;
1527     const int ve = (inst->inst >> 33) & 0x1;
1528    
1529     // destination register (r1) is always valid in this group
1530     inst->operands[0].valid = true;
1531     inst->operands[0].index = r1;
1532    
1533     // source register (r3) is always valid in this group
1534     inst->operands[2].valid = true;
1535     inst->operands[2].index = r3;
1536     inst->operands[2].value = IA64_GET_GR(r3);
1537     inst->operands[2].nat = IA64_GET_NAT(r3);
1538    
1539     if (x2a == 0 && ve == 0) {
1540     inst->operands[1].valid = true;
1541     inst->operands[1].index = r2;
1542     inst->operands[1].value = IA64_GET_GR(r2);
1543     inst->operands[1].nat = IA64_GET_NAT(r2);
1544     switch (x4) {
1545     case 0x0: // add (A1)
1546     inst->mnemo = IA64_INST_ADD;
1547     inst->operands[3].valid = true;
1548     inst->operands[3].index = -1;
1549     inst->operands[3].value = x2b == 1;
1550     return true;
1551     case 0x1: // add (A1)
1552     inst->mnemo = IA64_INST_SUB;
1553     inst->operands[3].valid = true;
1554     inst->operands[3].index = -1;
1555     inst->operands[3].value = x2b == 0;
1556     return true;
1557     case 0x4: // shladd (A2)
1558     inst->mnemo = IA64_INST_SHLADD;
1559     inst->operands[3].valid = true;
1560     inst->operands[3].index = -1;
1561     inst->operands[3].value = ia64_inst_get_count2(inst->inst);
1562     return true;
1563     case 0x9:
1564     if (x2b == 1) {
1565     inst->mnemo = IA64_INST_SUB;
1566     inst->operands[1].index = -1;
1567     inst->operands[1].value = ia64_inst_get_imm8(inst->inst);
1568     inst->operands[1].nat = 0;
1569     return true;
1570     }
1571     break;
1572     case 0xb:
1573     inst->operands[1].index = -1;
1574     inst->operands[1].value = ia64_inst_get_imm8(inst->inst);
1575     inst->operands[1].nat = 0;
1576     // fall-through
1577     case 0x3:
1578     switch (x2b) {
1579     case 0: inst->mnemo = IA64_INST_AND; break;
1580     case 1: inst->mnemo = IA64_INST_ANDCM; break;
1581     case 2: inst->mnemo = IA64_INST_OR; break;
1582     case 3: inst->mnemo = IA64_INST_XOR; break;
1583     }
1584     return true;
1585     }
1586     }
1587     return false;
1588     }
1589    
1590     // Decode instruction
1591 gbeauche 1.77 static bool ia64_decode_instruction(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1592 gbeauche 1.75 {
1593     const int major = (inst->inst >> 37) & 0xf;
1594    
1595     inst->mnemo = IA64_INST_UNKNOWN;
1596     inst->pred = inst->inst & 0x3f;
1597     memset(&inst->operands[0], 0, sizeof(inst->operands));
1598    
1599     switch (major) {
1600 gbeauche 1.77 case 0x0: return ia64_decode_instruction_0(inst, IA64_CONTEXT);
1601     case 0x4: return ia64_decode_instruction_4(inst, IA64_CONTEXT);
1602     case 0x5: return ia64_decode_instruction_5(inst, IA64_CONTEXT);
1603     case 0x8: return ia64_decode_instruction_8(inst, IA64_CONTEXT);
1604 gbeauche 1.75 }
1605     return false;
1606     }
1607    
1608 gbeauche 1.77 static bool ia64_emulate_instruction(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1609 gbeauche 1.75 {
1610 gbeauche 1.76 // XXX: handle Register NaT Consumption fault?
1611     // XXX: this simple emulator assumes instructions in a bundle
1612     // don't depend on effects of other instructions in the same
1613     // bundle. It probably would be simpler to JIT-generate code to be
1614     // executed natively but probably more costly (inject/extract CPU state)
1615 gbeauche 1.75 if (inst->mnemo == IA64_INST_UNKNOWN)
1616     return false;
1617     if (inst->pred && !IA64_GET_PR(inst->pred))
1618     return true;
1619    
1620     unsigned char nat, nat2;
1621     unsigned long dst, dst2, src1, src2, src3;
1622    
1623     switch (inst->mnemo) {
1624     case IA64_INST_NOP:
1625     break;
1626     case IA64_INST_ADD:
1627     case IA64_INST_SUB:
1628     case IA64_INST_SHLADD:
1629     src3 = inst->operands[3].value;
1630     // fall-through
1631     case IA64_INST_AND:
1632     case IA64_INST_ANDCM:
1633     case IA64_INST_OR:
1634     case IA64_INST_XOR:
1635     src1 = inst->operands[1].value;
1636     src2 = inst->operands[2].value;
1637     switch (inst->mnemo) {
1638     case IA64_INST_ADD: dst = src1 + src2 + src3; break;
1639     case IA64_INST_SUB: dst = src1 - src2 - src3; break;
1640     case IA64_INST_SHLADD: dst = (src1 << src3) + src2; break;
1641     case IA64_INST_AND: dst = src1 & src2; break;
1642     case IA64_INST_ANDCM: dst = src1 &~ src2; break;
1643     case IA64_INST_OR: dst = src1 | src2; break;
1644     case IA64_INST_XOR: dst = src1 ^ src2; break;
1645     }
1646     inst->operands[0].commit = true;
1647     inst->operands[0].value = dst;
1648     inst->operands[0].nat = inst->operands[1].nat | inst->operands[2].nat;
1649     break;
1650     case IA64_INST_SXT1:
1651     case IA64_INST_SXT2:
1652     case IA64_INST_SXT4:
1653     case IA64_INST_ZXT1:
1654     case IA64_INST_ZXT2:
1655     case IA64_INST_ZXT4:
1656     src1 = inst->operands[1].value;
1657     switch (inst->mnemo) {
1658     case IA64_INST_SXT1: dst = (signed long)(signed char)src1; break;
1659     case IA64_INST_SXT2: dst = (signed long)(signed short)src1; break;
1660     case IA64_INST_SXT4: dst = (signed long)(signed int)src1; break;
1661     case IA64_INST_ZXT1: dst = (unsigned char)src1; break;
1662     case IA64_INST_ZXT2: dst = (unsigned short)src1; break;
1663     case IA64_INST_ZXT4: dst = (unsigned int)src1; break;
1664     }
1665     inst->operands[0].commit = true;
1666     inst->operands[0].value = dst;
1667     inst->operands[0].nat = inst->operands[1].nat;
1668     break;
1669     case IA64_INST_LD1_UPDATE:
1670     case IA64_INST_LD2_UPDATE:
1671     case IA64_INST_LD4_UPDATE:
1672     case IA64_INST_LD8_UPDATE:
1673     inst->operands[1].commit = true;
1674     dst2 = inst->operands[1].value + inst->operands[2].value;
1675     nat2 = inst->operands[2].nat ? inst->operands[2].nat : 0;
1676     // fall-through
1677     case IA64_INST_LD1:
1678     case IA64_INST_LD2:
1679     case IA64_INST_LD4:
1680     case IA64_INST_LD8:
1681     src1 = inst->operands[1].value;
1682     if (inst->no_memory)
1683     dst = 0;
1684     else {
1685     switch (inst->mnemo) {
1686     case IA64_INST_LD1: case IA64_INST_LD1_UPDATE: dst = *((unsigned char *)src1); break;
1687     case IA64_INST_LD2: case IA64_INST_LD2_UPDATE: dst = *((unsigned short *)src1); break;
1688     case IA64_INST_LD4: case IA64_INST_LD4_UPDATE: dst = *((unsigned int *)src1); break;
1689     case IA64_INST_LD8: case IA64_INST_LD8_UPDATE: dst = *((unsigned long *)src1); break;
1690     }
1691     }
1692     inst->operands[0].commit = true;
1693     inst->operands[0].value = dst;
1694     inst->operands[0].nat = 0;
1695     inst->operands[1].value = dst2;
1696     inst->operands[1].nat = nat2;
1697     break;
1698     case IA64_INST_ST1_UPDATE:
1699     case IA64_INST_ST2_UPDATE:
1700     case IA64_INST_ST4_UPDATE:
1701     case IA64_INST_ST8_UPDATE:
1702     inst->operands[0].commit = 0;
1703     dst2 = inst->operands[0].value + inst->operands[2].value;
1704     nat2 = inst->operands[2].nat ? inst->operands[2].nat : 0;
1705     // fall-through
1706     case IA64_INST_ST1:
1707     case IA64_INST_ST2:
1708     case IA64_INST_ST4:
1709     case IA64_INST_ST8:
1710     dst = inst->operands[0].value;
1711     src1 = inst->operands[1].value;
1712     if (!inst->no_memory) {
1713     switch (inst->mnemo) {
1714     case IA64_INST_ST1: case IA64_INST_ST1_UPDATE: *((unsigned char *)dst) = src1; break;
1715     case IA64_INST_ST2: case IA64_INST_ST2_UPDATE: *((unsigned short *)dst) = src1; break;
1716     case IA64_INST_ST4: case IA64_INST_ST4_UPDATE: *((unsigned int *)dst) = src1; break;
1717     case IA64_INST_ST8: case IA64_INST_ST8_UPDATE: *((unsigned long *)dst) = src1; break;
1718     }
1719     }
1720     inst->operands[0].value = dst2;
1721     inst->operands[0].nat = nat2;
1722     break;
1723     default:
1724     return false;
1725     }
1726    
1727     for (int i = 0; i < IA64_N_OPERANDS; i++) {
1728     ia64_operand_t const & op = inst->operands[i];
1729     if (!op.commit)
1730     continue;
1731     if (op.index == -1)
1732     return false; // XXX: internal error
1733     IA64_SET_GR(op.index, op.value);
1734     IA64_SET_NAT(op.index, op.nat);
1735     }
1736     return true;
1737     }
1738    
1739 gbeauche 1.77 static bool ia64_emulate_instruction(unsigned long raw_inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1740 gbeauche 1.75 {
1741     ia64_instruction_t inst;
1742     memset(&inst, 0, sizeof(inst));
1743     inst.inst = raw_inst;
1744 gbeauche 1.77 if (!ia64_decode_instruction(&inst, IA64_CONTEXT))
1745 gbeauche 1.75 return false;
1746 gbeauche 1.77 return ia64_emulate_instruction(&inst, IA64_CONTEXT);
1747 gbeauche 1.75 }
1748    
1749 gbeauche 1.77 static bool ia64_skip_instruction(IA64_CONTEXT_TYPE IA64_CONTEXT)
1750 gbeauche 1.75 {
1751 gbeauche 1.77 unsigned long ip = IA64_GET_IP();
1752 gbeauche 1.75 #if DEBUG
1753     printf("IP: 0x%016lx\n", ip);
1754     #if 0
1755     printf(" Template 0x%02x\n", ia64_get_template(ip));
1756     ia64_get_instruction(ip, 0);
1757     ia64_get_instruction(ip, 1);
1758     ia64_get_instruction(ip, 2);
1759     #endif
1760     #endif
1761    
1762     // Select which decode switch to use
1763     ia64_instruction_t inst;
1764     inst.inst = ia64_get_instruction(ip, ip & 3);
1765 gbeauche 1.77 if (!ia64_decode_instruction(&inst, IA64_CONTEXT)) {
1766 gbeauche 1.75 fprintf(stderr, "ERROR: ia64_skip_instruction(): could not decode instruction\n");
1767     return false;
1768     }
1769    
1770     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1771     transfer_size_t transfer_size = SIZE_UNKNOWN;
1772    
1773     switch (inst.mnemo) {
1774     case IA64_INST_LD1:
1775     case IA64_INST_LD2:
1776     case IA64_INST_LD4:
1777     case IA64_INST_LD8:
1778     case IA64_INST_LD1_UPDATE:
1779     case IA64_INST_LD2_UPDATE:
1780     case IA64_INST_LD4_UPDATE:
1781     case IA64_INST_LD8_UPDATE:
1782     transfer_type = SIGSEGV_TRANSFER_LOAD;
1783     break;
1784     case IA64_INST_ST1:
1785     case IA64_INST_ST2:
1786     case IA64_INST_ST4:
1787     case IA64_INST_ST8:
1788     case IA64_INST_ST1_UPDATE:
1789     case IA64_INST_ST2_UPDATE:
1790     case IA64_INST_ST4_UPDATE:
1791     case IA64_INST_ST8_UPDATE:
1792     transfer_type = SIGSEGV_TRANSFER_STORE;
1793     break;
1794     }
1795    
1796     if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1797     // Unknown machine code, let it crash. Then patch the decoder
1798     fprintf(stderr, "ERROR: ia64_skip_instruction(): not a load/store instruction\n");
1799     return false;
1800     }
1801    
1802     switch (inst.mnemo) {
1803     case IA64_INST_LD1:
1804     case IA64_INST_LD1_UPDATE:
1805     case IA64_INST_ST1:
1806     case IA64_INST_ST1_UPDATE:
1807     transfer_size = SIZE_BYTE;
1808     break;
1809     case IA64_INST_LD2:
1810     case IA64_INST_LD2_UPDATE:
1811     case IA64_INST_ST2:
1812     case IA64_INST_ST2_UPDATE:
1813     transfer_size = SIZE_WORD;
1814     break;
1815     case IA64_INST_LD4:
1816     case IA64_INST_LD4_UPDATE:
1817     case IA64_INST_ST4:
1818     case IA64_INST_ST4_UPDATE:
1819     transfer_size = SIZE_LONG;
1820     break;
1821     case IA64_INST_LD8:
1822     case IA64_INST_LD8_UPDATE:
1823     case IA64_INST_ST8:
1824     case IA64_INST_ST8_UPDATE:
1825     transfer_size = SIZE_QUAD;
1826     break;
1827     }
1828    
1829     if (transfer_size == SIZE_UNKNOWN) {
1830     // Unknown machine code, let it crash. Then patch the decoder
1831     fprintf(stderr, "ERROR: ia64_skip_instruction(): unknown transfer size\n");
1832     return false;
1833     }
1834    
1835     inst.no_memory = true;
1836 gbeauche 1.77 if (!ia64_emulate_instruction(&inst, IA64_CONTEXT)) {
1837 gbeauche 1.75 fprintf(stderr, "ERROR: ia64_skip_instruction(): could not emulate fault instruction\n");
1838     return false;
1839     }
1840    
1841     int slot = ip & 3;
1842     bool emulate_next = false;
1843     switch (slot) {
1844     case 0:
1845     switch (ia64_get_template(ip)) {
1846     case 0x2: // MI;I
1847     case 0x3: // MI;I;
1848     emulate_next = true;
1849     slot = 2;
1850     break;
1851     case 0xa: // M;MI
1852     case 0xb: // M;MI;
1853     emulate_next = true;
1854     slot = 1;
1855     break;
1856     }
1857     break;
1858     }
1859 gbeauche 1.77 if (emulate_next && !IA64_CAN_PATCH_IP_SLOT) {
1860 gbeauche 1.75 while (slot < 3) {
1861 gbeauche 1.77 if (!ia64_emulate_instruction(ia64_get_instruction(ip, slot), IA64_CONTEXT)) {
1862 gbeauche 1.75 fprintf(stderr, "ERROR: ia64_skip_instruction(): could not emulate instruction\n");
1863     return false;
1864     }
1865     ++slot;
1866     }
1867     }
1868    
1869 gbeauche 1.77 #if IA64_CAN_PATCH_IP_SLOT
1870     if ((slot = ip & 3) < 2)
1871     IA64_SET_IP((ip & ~3ul) + (slot + 1));
1872     else
1873     #endif
1874     IA64_SET_IP((ip & ~3ul) + 16);
1875 gbeauche 1.75 #if DEBUG
1876 gbeauche 1.77 printf("IP: 0x%016lx\n", IA64_GET_IP());
1877 gbeauche 1.75 #endif
1878     return true;
1879     }
1880     #endif
1881    
1882 gbeauche 1.13 // Decode and skip PPC instruction
1883 gbeauche 1.69 #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__))
1884 gbeauche 1.49 static bool powerpc_skip_instruction(unsigned long * nip_p, unsigned long * regs)
1885 gbeauche 1.13 {
1886 gbeauche 1.14 instruction_t instr;
1887     powerpc_decode_instruction(&instr, *nip_p, regs);
1888 gbeauche 1.13
1889 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1890 gbeauche 1.13 // Unknown machine code, let it crash. Then patch the decoder
1891     return false;
1892     }
1893    
1894     #if DEBUG
1895 gbeauche 1.14 printf("%08x: %s %s access", *nip_p,
1896 gbeauche 1.49 instr.transfer_size == SIZE_BYTE ? "byte" :
1897     instr.transfer_size == SIZE_WORD ? "word" :
1898     instr.transfer_size == SIZE_LONG ? "long" : "quad",
1899 gbeauche 1.22 instr.transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
1900 gbeauche 1.14
1901     if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
1902     printf(" r%d (ra = %08x)\n", instr.ra, instr.addr);
1903 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
1904 gbeauche 1.14 printf(" r%d (rd = 0)\n", instr.rd);
1905     #endif
1906    
1907     if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
1908     regs[instr.ra] = instr.addr;
1909 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
1910 gbeauche 1.14 regs[instr.rd] = 0;
1911 gbeauche 1.13
1912 gbeauche 1.14 *nip_p += 4;
1913 gbeauche 1.10 return true;
1914 gbeauche 1.38 }
1915     #endif
1916    
1917     // Decode and skip MIPS instruction
1918     #if (defined(mips) || defined(__mips))
1919 gbeauche 1.65 static bool mips_skip_instruction(greg_t * pc_p, greg_t * regs)
1920 gbeauche 1.38 {
1921 gbeauche 1.65 unsigned int * epc = (unsigned int *)(unsigned long)*pc_p;
1922 gbeauche 1.38
1923     if (epc == 0)
1924     return false;
1925    
1926     #if DEBUG
1927     printf("IP: %p [%08x]\n", epc, epc[0]);
1928     #endif
1929    
1930     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1931     transfer_size_t transfer_size = SIZE_LONG;
1932     int direction = 0;
1933    
1934     const unsigned int opcode = epc[0];
1935     switch (opcode >> 26) {
1936     case 32: // Load Byte
1937     case 36: // Load Byte Unsigned
1938     transfer_type = SIGSEGV_TRANSFER_LOAD;
1939     transfer_size = SIZE_BYTE;
1940     break;
1941     case 33: // Load Halfword
1942     case 37: // Load Halfword Unsigned
1943     transfer_type = SIGSEGV_TRANSFER_LOAD;
1944     transfer_size = SIZE_WORD;
1945     break;
1946     case 35: // Load Word
1947     case 39: // Load Word Unsigned
1948     transfer_type = SIGSEGV_TRANSFER_LOAD;
1949     transfer_size = SIZE_LONG;
1950     break;
1951     case 34: // Load Word Left
1952     transfer_type = SIGSEGV_TRANSFER_LOAD;
1953     transfer_size = SIZE_LONG;
1954     direction = -1;
1955     break;
1956     case 38: // Load Word Right
1957     transfer_type = SIGSEGV_TRANSFER_LOAD;
1958     transfer_size = SIZE_LONG;
1959     direction = 1;
1960     break;
1961     case 55: // Load Doubleword
1962     transfer_type = SIGSEGV_TRANSFER_LOAD;
1963     transfer_size = SIZE_QUAD;
1964     break;
1965     case 26: // Load Doubleword Left
1966     transfer_type = SIGSEGV_TRANSFER_LOAD;
1967     transfer_size = SIZE_QUAD;
1968     direction = -1;
1969     break;
1970     case 27: // Load Doubleword Right
1971     transfer_type = SIGSEGV_TRANSFER_LOAD;
1972     transfer_size = SIZE_QUAD;
1973     direction = 1;
1974     break;
1975     case 40: // Store Byte
1976     transfer_type = SIGSEGV_TRANSFER_STORE;
1977     transfer_size = SIZE_BYTE;
1978     break;
1979     case 41: // Store Halfword
1980     transfer_type = SIGSEGV_TRANSFER_STORE;
1981     transfer_size = SIZE_WORD;
1982     break;
1983     case 43: // Store Word
1984     case 42: // Store Word Left
1985     case 46: // Store Word Right
1986     transfer_type = SIGSEGV_TRANSFER_STORE;
1987     transfer_size = SIZE_LONG;
1988     break;
1989     case 63: // Store Doubleword
1990     case 44: // Store Doubleword Left
1991     case 45: // Store Doubleword Right
1992     transfer_type = SIGSEGV_TRANSFER_STORE;
1993     transfer_size = SIZE_QUAD;
1994     break;
1995     /* Misc instructions unlikely to be used within CPU emulators */
1996     case 48: // Load Linked Word
1997     transfer_type = SIGSEGV_TRANSFER_LOAD;
1998     transfer_size = SIZE_LONG;
1999     break;
2000     case 52: // Load Linked Doubleword
2001     transfer_type = SIGSEGV_TRANSFER_LOAD;
2002     transfer_size = SIZE_QUAD;
2003     break;
2004     case 56: // Store Conditional Word
2005     transfer_type = SIGSEGV_TRANSFER_STORE;
2006     transfer_size = SIZE_LONG;
2007     break;
2008     case 60: // Store Conditional Doubleword
2009     transfer_type = SIGSEGV_TRANSFER_STORE;
2010     transfer_size = SIZE_QUAD;
2011     break;
2012     }
2013    
2014     if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
2015     // Unknown machine code, let it crash. Then patch the decoder
2016     return false;
2017     }
2018    
2019     // Zero target register in case of a load operation
2020     const int reg = (opcode >> 16) & 0x1f;
2021     if (transfer_type == SIGSEGV_TRANSFER_LOAD) {
2022     if (direction == 0)
2023     regs[reg] = 0;
2024     else {
2025     // FIXME: untested code
2026     unsigned long ea = regs[(opcode >> 21) & 0x1f];
2027     ea += (signed long)(signed int)(signed short)(opcode & 0xffff);
2028     const int offset = ea & (transfer_size == SIZE_LONG ? 3 : 7);
2029     unsigned long value;
2030     if (direction > 0) {
2031     const unsigned long rmask = ~((1L << ((offset + 1) * 8)) - 1);
2032     value = regs[reg] & rmask;
2033     }
2034     else {
2035     const unsigned long lmask = (1L << (offset * 8)) - 1;
2036     value = regs[reg] & lmask;
2037     }
2038     // restore most significant bits
2039     if (transfer_size == SIZE_LONG)
2040     value = (signed long)(signed int)value;
2041     regs[reg] = value;
2042     }
2043     }
2044    
2045     #if DEBUG
2046     #if (defined(_ABIN32) || defined(_ABI64))
2047     static const char * mips_gpr_names[32] = {
2048     "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
2049     "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
2050     "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
2051     "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
2052     };
2053     #else
2054     static const char * mips_gpr_names[32] = {
2055     "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
2056     "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
2057     "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
2058     "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
2059     };
2060     #endif
2061     printf("%s %s register %s\n",
2062     transfer_size == SIZE_BYTE ? "byte" :
2063     transfer_size == SIZE_WORD ? "word" :
2064     transfer_size == SIZE_LONG ? "long" :
2065     transfer_size == SIZE_QUAD ? "quad" : "unknown",
2066     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
2067     mips_gpr_names[reg]);
2068     #endif
2069    
2070 gbeauche 1.65 *pc_p += 4;
2071 gbeauche 1.40 return true;
2072     }
2073     #endif
2074    
2075     // Decode and skip SPARC instruction
2076     #if (defined(sparc) || defined(__sparc__))
2077     enum {
2078     #if (defined(__sun__))
2079     SPARC_REG_G1 = REG_G1,
2080     SPARC_REG_O0 = REG_O0,
2081     SPARC_REG_PC = REG_PC,
2082 gbeauche 1.59 SPARC_REG_nPC = REG_nPC
2083 gbeauche 1.40 #endif
2084     };
2085     static bool sparc_skip_instruction(unsigned long * regs, gwindows_t * gwins, struct rwindow * rwin)
2086     {
2087     unsigned int * pc = (unsigned int *)regs[SPARC_REG_PC];
2088    
2089     if (pc == 0)
2090     return false;
2091    
2092     #if DEBUG
2093     printf("IP: %p [%08x]\n", pc, pc[0]);
2094     #endif
2095    
2096     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
2097     transfer_size_t transfer_size = SIZE_LONG;
2098     bool register_pair = false;
2099    
2100     const unsigned int opcode = pc[0];
2101     if ((opcode >> 30) != 3)
2102     return false;
2103     switch ((opcode >> 19) & 0x3f) {
2104     case 9: // Load Signed Byte
2105     case 1: // Load Unsigned Byte
2106     transfer_type = SIGSEGV_TRANSFER_LOAD;
2107     transfer_size = SIZE_BYTE;
2108     break;
2109     case 10:// Load Signed Halfword
2110     case 2: // Load Unsigned Word
2111     transfer_type = SIGSEGV_TRANSFER_LOAD;
2112     transfer_size = SIZE_WORD;
2113     break;
2114     case 8: // Load Word
2115     case 0: // Load Unsigned Word
2116     transfer_type = SIGSEGV_TRANSFER_LOAD;
2117     transfer_size = SIZE_LONG;
2118     break;
2119     case 11:// Load Extended Word
2120     transfer_type = SIGSEGV_TRANSFER_LOAD;
2121     transfer_size = SIZE_QUAD;
2122     break;
2123     case 3: // Load Doubleword
2124     transfer_type = SIGSEGV_TRANSFER_LOAD;
2125     transfer_size = SIZE_LONG;
2126     register_pair = true;
2127     break;
2128     case 5: // Store Byte
2129     transfer_type = SIGSEGV_TRANSFER_STORE;
2130     transfer_size = SIZE_BYTE;
2131     break;
2132     case 6: // Store Halfword
2133     transfer_type = SIGSEGV_TRANSFER_STORE;
2134     transfer_size = SIZE_WORD;
2135     break;
2136     case 4: // Store Word
2137     transfer_type = SIGSEGV_TRANSFER_STORE;
2138     transfer_size = SIZE_LONG;
2139     break;
2140     case 14:// Store Extended Word
2141     transfer_type = SIGSEGV_TRANSFER_STORE;
2142     transfer_size = SIZE_QUAD;
2143     break;
2144     case 7: // Store Doubleword
2145     transfer_type = SIGSEGV_TRANSFER_STORE;
2146 gbeauche 1.58 transfer_size = SIZE_LONG;
2147 gbeauche 1.40 register_pair = true;
2148     break;
2149     }
2150    
2151     if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
2152     // Unknown machine code, let it crash. Then patch the decoder
2153     return false;
2154     }
2155    
2156 gbeauche 1.58 const int reg = (opcode >> 25) & 0x1f;
2157    
2158     #if DEBUG
2159     static const char * reg_names[] = {
2160     "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
2161     "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
2162     "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
2163     "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"
2164     };
2165     printf("%s %s register %s\n",
2166     transfer_size == SIZE_BYTE ? "byte" :
2167     transfer_size == SIZE_WORD ? "word" :
2168     transfer_size == SIZE_LONG ? "long" :
2169     transfer_size == SIZE_QUAD ? "quad" : "unknown",
2170     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
2171     reg_names[reg]);
2172     #endif
2173    
2174 gbeauche 1.40 // Zero target register in case of a load operation
2175     if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != 0) {
2176     // FIXME: code to handle local & input registers is not tested
2177 gbeauche 1.58 if (reg >= 1 && reg < 8) {
2178 gbeauche 1.40 // global registers
2179     regs[reg - 1 + SPARC_REG_G1] = 0;
2180     }
2181 gbeauche 1.58 else if (reg >= 8 && reg < 16) {
2182 gbeauche 1.40 // output registers
2183     regs[reg - 8 + SPARC_REG_O0] = 0;
2184     }
2185 gbeauche 1.58 else if (reg >= 16 && reg < 24) {
2186 gbeauche 1.40 // local registers (in register windows)
2187     if (gwins)
2188     gwins->wbuf->rw_local[reg - 16] = 0;
2189     else
2190     rwin->rw_local[reg - 16] = 0;
2191     }
2192     else {
2193     // input registers (in register windows)
2194     if (gwins)
2195     gwins->wbuf->rw_in[reg - 24] = 0;
2196     else
2197     rwin->rw_in[reg - 24] = 0;
2198     }
2199     }
2200    
2201     regs[SPARC_REG_PC] += 4;
2202 gbeauche 1.59 regs[SPARC_REG_nPC] += 4;
2203 gbeauche 1.38 return true;
2204 gbeauche 1.10 }
2205     #endif
2206     #endif
2207    
2208 gbeauche 1.44 // Decode and skip ARM instruction
2209     #if (defined(arm) || defined(__arm__))
2210     enum {
2211     #if (defined(__linux__))
2212     ARM_REG_PC = 15,
2213     ARM_REG_CPSR = 16
2214     #endif
2215     };
2216     static bool arm_skip_instruction(unsigned long * regs)
2217     {
2218     unsigned int * pc = (unsigned int *)regs[ARM_REG_PC];
2219    
2220     if (pc == 0)
2221     return false;
2222    
2223     #if DEBUG
2224     printf("IP: %p [%08x]\n", pc, pc[0]);
2225     #endif
2226    
2227     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
2228     transfer_size_t transfer_size = SIZE_UNKNOWN;
2229     enum { op_sdt = 1, op_sdth = 2 };
2230     int op = 0;
2231    
2232     // Handle load/store instructions only
2233     const unsigned int opcode = pc[0];
2234     switch ((opcode >> 25) & 7) {
2235     case 0: // Halfword and Signed Data Transfer (LDRH, STRH, LDRSB, LDRSH)
2236     op = op_sdth;
2237     // Determine transfer size (S/H bits)
2238     switch ((opcode >> 5) & 3) {
2239     case 0: // SWP instruction
2240     break;
2241     case 1: // Unsigned halfwords
2242     case 3: // Signed halfwords
2243     transfer_size = SIZE_WORD;
2244     break;
2245     case 2: // Signed byte
2246     transfer_size = SIZE_BYTE;
2247     break;
2248     }
2249     break;
2250     case 2:
2251     case 3: // Single Data Transfer (LDR, STR)
2252     op = op_sdt;
2253     // Determine transfer size (B bit)
2254     if (((opcode >> 22) & 1) == 1)
2255     transfer_size = SIZE_BYTE;
2256     else
2257     transfer_size = SIZE_LONG;
2258     break;
2259     default:
2260     // FIXME: support load/store mutliple?
2261     return false;
2262     }
2263    
2264     // Check for invalid transfer size (SWP instruction?)
2265     if (transfer_size == SIZE_UNKNOWN)
2266     return false;
2267    
2268     // Determine transfer type (L bit)
2269     if (((opcode >> 20) & 1) == 1)
2270     transfer_type = SIGSEGV_TRANSFER_LOAD;
2271     else
2272     transfer_type = SIGSEGV_TRANSFER_STORE;
2273    
2274     // Compute offset
2275     int offset;
2276     if (((opcode >> 25) & 1) == 0) {
2277     if (op == op_sdt)
2278     offset = opcode & 0xfff;
2279     else if (op == op_sdth) {
2280     int rm = opcode & 0xf;
2281     if (((opcode >> 22) & 1) == 0) {
2282     // register offset
2283     offset = regs[rm];
2284     }
2285     else {
2286     // immediate offset
2287     offset = ((opcode >> 4) & 0xf0) | (opcode & 0x0f);
2288     }
2289     }
2290     }
2291     else {
2292     const int rm = opcode & 0xf;
2293     const int sh = (opcode >> 7) & 0x1f;
2294     if (((opcode >> 4) & 1) == 1) {
2295     // we expect only legal load/store instructions
2296     printf("FATAL: invalid shift operand\n");
2297     return false;
2298     }
2299     const unsigned int v = regs[rm];
2300     switch ((opcode >> 5) & 3) {
2301     case 0: // logical shift left
2302     offset = sh ? v << sh : v;
2303     break;
2304     case 1: // logical shift right
2305     offset = sh ? v >> sh : 0;
2306     break;
2307     case 2: // arithmetic shift right
2308     if (sh)
2309     offset = ((signed int)v) >> sh;
2310     else
2311     offset = (v & 0x80000000) ? 0xffffffff : 0;
2312     break;
2313     case 3: // rotate right
2314     if (sh)
2315     offset = (v >> sh) | (v << (32 - sh));
2316     else
2317     offset = (v >> 1) | ((regs[ARM_REG_CPSR] << 2) & 0x80000000);
2318     break;
2319     }
2320     }
2321     if (((opcode >> 23) & 1) == 0)
2322     offset = -offset;
2323    
2324     int rd = (opcode >> 12) & 0xf;
2325     int rn = (opcode >> 16) & 0xf;
2326     #if DEBUG
2327     static const char * reg_names[] = {
2328     "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2329     "r9", "r9", "sl", "fp", "ip", "sp", "lr", "pc"
2330     };
2331     printf("%s %s register %s\n",
2332     transfer_size == SIZE_BYTE ? "byte" :
2333     transfer_size == SIZE_WORD ? "word" :
2334     transfer_size == SIZE_LONG ? "long" : "unknown",
2335     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
2336     reg_names[rd]);
2337     #endif
2338    
2339     unsigned int base = regs[rn];
2340     if (((opcode >> 24) & 1) == 1)
2341     base += offset;
2342    
2343     if (transfer_type == SIGSEGV_TRANSFER_LOAD)
2344     regs[rd] = 0;
2345    
2346     if (((opcode >> 24) & 1) == 0) // post-index addressing
2347     regs[rn] += offset;
2348     else if (((opcode >> 21) & 1) == 1) // write-back address into base
2349     regs[rn] = base;
2350    
2351     regs[ARM_REG_PC] += 4;
2352     return true;
2353     }
2354     #endif
2355    
2356    
2357 gbeauche 1.1 // Fallbacks
2358 gbeauche 1.68 #ifndef SIGSEGV_FAULT_ADDRESS_FAST
2359     #define SIGSEGV_FAULT_ADDRESS_FAST SIGSEGV_FAULT_ADDRESS
2360     #endif
2361     #ifndef SIGSEGV_FAULT_INSTRUCTION_FAST
2362     #define SIGSEGV_FAULT_INSTRUCTION_FAST SIGSEGV_FAULT_INSTRUCTION
2363     #endif
2364 gbeauche 1.1 #ifndef SIGSEGV_FAULT_INSTRUCTION
2365 gbeauche 1.67 #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_INVALID_ADDRESS
2366 gbeauche 1.1 #endif
2367 gbeauche 1.30 #ifndef SIGSEGV_FAULT_HANDLER_ARGLIST_1
2368     #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 SIGSEGV_FAULT_HANDLER_ARGLIST
2369     #endif
2370 gbeauche 1.31 #ifndef SIGSEGV_FAULT_HANDLER_INVOKE
2371 gbeauche 1.67 #define SIGSEGV_FAULT_HANDLER_INVOKE(P) sigsegv_fault_handler(P)
2372 gbeauche 1.31 #endif
2373 gbeauche 1.1
2374 gbeauche 1.2 // SIGSEGV recovery supported ?
2375     #if defined(SIGSEGV_ALL_SIGNALS) && defined(SIGSEGV_FAULT_HANDLER_ARGLIST) && defined(SIGSEGV_FAULT_ADDRESS)
2376     #define HAVE_SIGSEGV_RECOVERY
2377     #endif
2378    
2379 gbeauche 1.1
2380     /*
2381     * SIGSEGV global handler
2382     */
2383    
2384 gbeauche 1.67 struct sigsegv_info_t {
2385     sigsegv_address_t addr;
2386     sigsegv_address_t pc;
2387 gbeauche 1.68 #ifdef HAVE_MACH_EXCEPTIONS
2388     mach_port_t thread;
2389     bool has_exc_state;
2390     SIGSEGV_EXCEPTION_STATE_TYPE exc_state;
2391     mach_msg_type_number_t exc_state_count;
2392     bool has_thr_state;
2393     SIGSEGV_THREAD_STATE_TYPE thr_state;
2394     mach_msg_type_number_t thr_state_count;
2395     #endif
2396 gbeauche 1.67 };
2397    
2398 gbeauche 1.70 #ifdef HAVE_MACH_EXCEPTIONS
2399 gbeauche 1.72 static void mach_get_exception_state(sigsegv_info_t *SIP)
2400 gbeauche 1.70 {
2401 gbeauche 1.72 SIP->exc_state_count = SIGSEGV_EXCEPTION_STATE_COUNT;
2402     kern_return_t krc = thread_get_state(SIP->thread,
2403 gbeauche 1.70 SIGSEGV_EXCEPTION_STATE_FLAVOR,
2404 gbeauche 1.72 (natural_t *)&SIP->exc_state,
2405     &SIP->exc_state_count);
2406 gbeauche 1.70 MACH_CHECK_ERROR(thread_get_state, krc);
2407 gbeauche 1.72 SIP->has_exc_state = true;
2408 gbeauche 1.70 }
2409    
2410 gbeauche 1.72 static void mach_get_thread_state(sigsegv_info_t *SIP)
2411 gbeauche 1.70 {
2412 gbeauche 1.72 SIP->thr_state_count = SIGSEGV_THREAD_STATE_COUNT;
2413     kern_return_t krc = thread_get_state(SIP->thread,
2414 gbeauche 1.70 SIGSEGV_THREAD_STATE_FLAVOR,
2415 gbeauche 1.72 (natural_t *)&SIP->thr_state,
2416     &SIP->thr_state_count);
2417 gbeauche 1.70 MACH_CHECK_ERROR(thread_get_state, krc);
2418 gbeauche 1.72 SIP->has_thr_state = true;
2419 gbeauche 1.70 }
2420    
2421 gbeauche 1.72 static void mach_set_thread_state(sigsegv_info_t *SIP)
2422 gbeauche 1.70 {
2423 gbeauche 1.72 kern_return_t krc = thread_set_state(SIP->thread,
2424 gbeauche 1.70 SIGSEGV_THREAD_STATE_FLAVOR,
2425 gbeauche 1.72 (natural_t *)&SIP->thr_state,
2426     SIP->thr_state_count);
2427 gbeauche 1.70 MACH_CHECK_ERROR(thread_set_state, krc);
2428     }
2429     #endif
2430    
2431 gbeauche 1.67 // Return the address of the invalid memory reference
2432 gbeauche 1.72 sigsegv_address_t sigsegv_get_fault_address(sigsegv_info_t *SIP)
2433 gbeauche 1.67 {
2434 gbeauche 1.68 #ifdef HAVE_MACH_EXCEPTIONS
2435     static int use_fast_path = -1;
2436 gbeauche 1.72 if (use_fast_path != 1 && !SIP->has_exc_state) {
2437     mach_get_exception_state(SIP);
2438 gbeauche 1.68
2439     sigsegv_address_t addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
2440 gbeauche 1.78 if (use_fast_path < 0) {
2441     const char *machfault = getenv("SIGSEGV_MACH_FAULT");
2442     if (machfault) {
2443     if (strcmp(machfault, "fast") == 0)
2444     use_fast_path = 1;
2445     else if (strcmp(machfault, "slow") == 0)
2446     use_fast_path = 0;
2447     }
2448     if (use_fast_path < 0)
2449     use_fast_path = addr == SIP->addr;
2450     }
2451 gbeauche 1.72 SIP->addr = addr;
2452 gbeauche 1.68 }
2453     #endif
2454 gbeauche 1.72 return SIP->addr;
2455 gbeauche 1.67 }
2456    
2457     // Return the address of the instruction that caused the fault, or
2458     // SIGSEGV_INVALID_ADDRESS if we could not retrieve this information
2459 gbeauche 1.72 sigsegv_address_t sigsegv_get_fault_instruction_address(sigsegv_info_t *SIP)
2460 gbeauche 1.67 {
2461 gbeauche 1.68 #ifdef HAVE_MACH_EXCEPTIONS
2462 gbeauche 1.72 if (!SIP->has_thr_state) {
2463     mach_get_thread_state(SIP);
2464 gbeauche 1.68
2465 gbeauche 1.72 SIP->pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
2466 gbeauche 1.68 }
2467     #endif
2468 gbeauche 1.72 return SIP->pc;
2469 gbeauche 1.67 }
2470    
2471 gbeauche 1.27 // This function handles the badaccess to memory.
2472     // It is called from the signal handler or the exception handler.
2473 gbeauche 1.30 static bool handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGLIST_1)
2474 gbeauche 1.1 {
2475 gbeauche 1.72 sigsegv_info_t SI;
2476     SI.addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS_FAST;
2477     SI.pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION_FAST;
2478 gbeauche 1.56 #ifdef HAVE_MACH_EXCEPTIONS
2479 gbeauche 1.72 SI.thread = thread;
2480     SI.has_exc_state = false;
2481     SI.has_thr_state = false;
2482 gbeauche 1.56 #endif
2483 gbeauche 1.72 sigsegv_info_t * const SIP = &SI;
2484 gbeauche 1.56
2485 gbeauche 1.1 // Call user's handler and reinstall the global handler, if required
2486 gbeauche 1.72 switch (SIGSEGV_FAULT_HANDLER_INVOKE(SIP)) {
2487 gbeauche 1.24 case SIGSEGV_RETURN_SUCCESS:
2488 gbeauche 1.27 return true;
2489    
2490 gbeauche 1.10 #if HAVE_SIGSEGV_SKIP_INSTRUCTION
2491 gbeauche 1.24 case SIGSEGV_RETURN_SKIP_INSTRUCTION:
2492 gbeauche 1.27 // Call the instruction skipper with the register file
2493     // available
2494 gbeauche 1.70 #ifdef HAVE_MACH_EXCEPTIONS
2495 gbeauche 1.72 if (!SIP->has_thr_state)
2496     mach_get_thread_state(SIP);
2497 gbeauche 1.70 #endif
2498 gbeauche 1.27 if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE)) {
2499     #ifdef HAVE_MACH_EXCEPTIONS
2500     // Unlike UNIX signals where the thread state
2501     // is modified off of the stack, in Mach we
2502     // need to actually call thread_set_state to
2503     // have the register values updated.
2504 gbeauche 1.72 mach_set_thread_state(SIP);
2505 gbeauche 1.27 #endif
2506     return true;
2507     }
2508 gbeauche 1.24 break;
2509     #endif
2510 nigel 1.43 case SIGSEGV_RETURN_FAILURE:
2511 gbeauche 1.50 // We can't do anything with the fault_address, dump state?
2512     if (sigsegv_state_dumper != 0)
2513 gbeauche 1.72 sigsegv_state_dumper(SIP);
2514 gbeauche 1.50 break;
2515 gbeauche 1.10 }
2516 gbeauche 1.27
2517     return false;
2518     }
2519    
2520    
2521     /*
2522     * There are two mechanisms for handling a bad memory access,
2523     * Mach exceptions and UNIX signals. The implementation specific
2524     * code appears below. Its reponsibility is to call handle_badaccess
2525     * which is the routine that handles the fault in an implementation
2526     * agnostic manner. The implementation specific code below is then
2527     * reponsible for checking whether handle_badaccess was able
2528     * to handle the memory access error and perform any implementation
2529     * specific tasks necessary afterwards.
2530     */
2531    
2532     #ifdef HAVE_MACH_EXCEPTIONS
2533     /*
2534     * We need to forward all exceptions that we do not handle.
2535     * This is important, there are many exceptions that may be
2536     * handled by other exception handlers. For example debuggers
2537     * use exceptions and the exception hander is in another
2538     * process in such a case. (Timothy J. Wood states in his
2539     * message to the list that he based this code on that from
2540     * gdb for Darwin.)
2541     */
2542     static inline kern_return_t
2543     forward_exception(mach_port_t thread_port,
2544     mach_port_t task_port,
2545     exception_type_t exception_type,
2546     exception_data_t exception_data,
2547     mach_msg_type_number_t data_count,
2548     ExceptionPorts *oldExceptionPorts)
2549     {
2550     kern_return_t kret;
2551     unsigned int portIndex;
2552     mach_port_t port;
2553     exception_behavior_t behavior;
2554     thread_state_flavor_t flavor;
2555 gbeauche 1.57 thread_state_data_t thread_state;
2556 gbeauche 1.27 mach_msg_type_number_t thread_state_count;
2557    
2558     for (portIndex = 0; portIndex < oldExceptionPorts->maskCount; portIndex++) {
2559     if (oldExceptionPorts->masks[portIndex] & (1 << exception_type)) {
2560     // This handler wants the exception
2561     break;
2562     }
2563     }
2564    
2565     if (portIndex >= oldExceptionPorts->maskCount) {
2566     fprintf(stderr, "No handler for exception_type = %d. Not fowarding\n", exception_type);
2567     return KERN_FAILURE;
2568     }
2569    
2570     port = oldExceptionPorts->handlers[portIndex];
2571     behavior = oldExceptionPorts->behaviors[portIndex];
2572     flavor = oldExceptionPorts->flavors[portIndex];
2573    
2574 gbeauche 1.63 if (!VALID_THREAD_STATE_FLAVOR(flavor)) {
2575     fprintf(stderr, "Invalid thread_state flavor = %d. Not forwarding\n", flavor);
2576     return KERN_FAILURE;
2577     }
2578    
2579 gbeauche 1.27 /*
2580     fprintf(stderr, "forwarding exception, port = 0x%x, behaviour = %d, flavor = %d\n", port, behavior, flavor);
2581     */
2582    
2583     if (behavior != EXCEPTION_DEFAULT) {
2584     thread_state_count = THREAD_STATE_MAX;
2585 gbeauche 1.60 kret = thread_get_state (thread_port, flavor, (natural_t *)&thread_state,
2586 gbeauche 1.27 &thread_state_count);
2587     MACH_CHECK_ERROR (thread_get_state, kret);
2588     }
2589    
2590     switch (behavior) {
2591     case EXCEPTION_DEFAULT:
2592     // fprintf(stderr, "forwarding to exception_raise\n");
2593     kret = exception_raise(port, thread_port, task_port, exception_type,
2594     exception_data, data_count);
2595     MACH_CHECK_ERROR (exception_raise, kret);
2596     break;
2597     case EXCEPTION_STATE:
2598     // fprintf(stderr, "forwarding to exception_raise_state\n");
2599     kret = exception_raise_state(port, exception_type, exception_data,
2600     data_count, &flavor,
2601 gbeauche 1.60 (natural_t *)&thread_state, thread_state_count,
2602     (natural_t *)&thread_state, &thread_state_count);
2603 gbeauche 1.27 MACH_CHECK_ERROR (exception_raise_state, kret);
2604     break;
2605     case EXCEPTION_STATE_IDENTITY:
2606     // fprintf(stderr, "forwarding to exception_raise_state_identity\n");
2607     kret = exception_raise_state_identity(port, thread_port, task_port,
2608     exception_type, exception_data,
2609     data_count, &flavor,
2610 gbeauche 1.60 (natural_t *)&thread_state, thread_state_count,
2611     (natural_t *)&thread_state, &thread_state_count);
2612 gbeauche 1.27 MACH_CHECK_ERROR (exception_raise_state_identity, kret);
2613     break;
2614     default:
2615     fprintf(stderr, "forward_exception got unknown behavior\n");
2616 gbeauche 1.63 kret = KERN_FAILURE;
2617 gbeauche 1.27 break;
2618     }
2619    
2620     if (behavior != EXCEPTION_DEFAULT) {
2621 gbeauche 1.60 kret = thread_set_state (thread_port, flavor, (natural_t *)&thread_state,
2622 gbeauche 1.27 thread_state_count);
2623     MACH_CHECK_ERROR (thread_set_state, kret);
2624     }
2625    
2626 gbeauche 1.63 return kret;
2627 gbeauche 1.27 }
2628    
2629     /*
2630     * This is the code that actually handles the exception.
2631     * It is called by exc_server. For Darwin 5 Apple changed
2632     * this a bit from how this family of functions worked in
2633     * Mach. If you are familiar with that it is a little
2634     * different. The main variation that concerns us here is
2635     * that code is an array of exception specific codes and
2636     * codeCount is a count of the number of codes in the code
2637     * array. In typical Mach all exceptions have a code
2638     * and sub-code. It happens to be the case that for a
2639     * EXC_BAD_ACCESS exception the first entry is the type of
2640     * bad access that occurred and the second entry is the
2641     * faulting address so these entries correspond exactly to
2642     * how the code and sub-code are used on Mach.
2643     *
2644     * This is a MIG interface. No code in Basilisk II should
2645     * call this directley. This has to have external C
2646     * linkage because that is what exc_server expects.
2647     */
2648     kern_return_t
2649     catch_exception_raise(mach_port_t exception_port,
2650     mach_port_t thread,
2651     mach_port_t task,
2652     exception_type_t exception,
2653     exception_data_t code,
2654 gbeauche 1.66 mach_msg_type_number_t code_count)
2655 gbeauche 1.27 {
2656     kern_return_t krc;
2657    
2658 gbeauche 1.66 if (exception == EXC_BAD_ACCESS) {
2659     switch (code[0]) {
2660     case KERN_PROTECTION_FAILURE:
2661     case KERN_INVALID_ADDRESS:
2662     if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS))
2663     return KERN_SUCCESS;
2664     break;
2665     }
2666 gbeauche 1.27 }
2667    
2668     // In Mach we do not need to remove the exception handler.
2669     // If we forward the exception, eventually some exception handler
2670     // will take care of this exception.
2671 gbeauche 1.66 krc = forward_exception(thread, task, exception, code, code_count, &ports);
2672 gbeauche 1.27
2673     return krc;
2674     }
2675     #endif
2676    
2677     #ifdef HAVE_SIGSEGV_RECOVERY
2678     // Handle bad memory accesses with signal handler
2679     static void sigsegv_handler(SIGSEGV_FAULT_HANDLER_ARGLIST)
2680     {
2681     // Call handler and reinstall the global handler, if required
2682     if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS)) {
2683     #if (defined(HAVE_SIGACTION) ? defined(SIGACTION_NEED_REINSTALL) : defined(SIGNAL_NEED_REINSTALL))
2684     sigsegv_do_install_handler(sig);
2685     #endif
2686     return;
2687     }
2688 gbeauche 1.10
2689 gbeauche 1.27 // Failure: reinstall default handler for "safe" crash
2690 gbeauche 1.1 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
2691 gbeauche 1.27 SIGSEGV_ALL_SIGNALS
2692 gbeauche 1.1 #undef FAULT_HANDLER
2693     }
2694 gbeauche 1.2 #endif
2695 gbeauche 1.1
2696    
2697     /*
2698     * SIGSEGV handler initialization
2699     */
2700    
2701     #if defined(HAVE_SIGINFO_T)
2702     static bool sigsegv_do_install_handler(int sig)
2703     {
2704     // Setup SIGSEGV handler to process writes to frame buffer
2705     #ifdef HAVE_SIGACTION
2706 gbeauche 1.22 struct sigaction sigsegv_sa;
2707     sigemptyset(&sigsegv_sa.sa_mask);
2708     sigsegv_sa.sa_sigaction = sigsegv_handler;
2709     sigsegv_sa.sa_flags = SA_SIGINFO;
2710     return (sigaction(sig, &sigsegv_sa, 0) == 0);
2711 gbeauche 1.1 #else
2712     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
2713     #endif
2714     }
2715 gbeauche 1.2 #endif
2716    
2717     #if defined(HAVE_SIGCONTEXT_SUBTERFUGE)
2718 gbeauche 1.1 static bool sigsegv_do_install_handler(int sig)
2719     {
2720     // Setup SIGSEGV handler to process writes to frame buffer
2721     #ifdef HAVE_SIGACTION
2722 gbeauche 1.22 struct sigaction sigsegv_sa;
2723     sigemptyset(&sigsegv_sa.sa_mask);
2724     sigsegv_sa.sa_handler = (signal_handler)sigsegv_handler;
2725     sigsegv_sa.sa_flags = 0;
2726 gbeauche 1.1 #if !EMULATED_68K && defined(__NetBSD__)
2727 gbeauche 1.22 sigaddset(&sigsegv_sa.sa_mask, SIGALRM);
2728     sigsegv_sa.sa_flags |= SA_ONSTACK;
2729 gbeauche 1.1 #endif
2730 gbeauche 1.22 return (sigaction(sig, &sigsegv_sa, 0) == 0);
2731 gbeauche 1.1 #else
2732     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
2733     #endif
2734     }
2735     #endif
2736    
2737 gbeauche 1.27 #if defined(HAVE_MACH_EXCEPTIONS)
2738     static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
2739     {
2740     /*
2741     * Except for the exception port functions, this should be
2742     * pretty much stock Mach. If later you choose to support
2743     * other Mach's besides Darwin, just check for __MACH__
2744     * here and __APPLE__ where the actual differences are.
2745     */
2746     #if defined(__APPLE__) && defined(__MACH__)
2747     if (sigsegv_fault_handler != NULL) {
2748     sigsegv_fault_handler = handler;
2749     return true;
2750     }
2751    
2752     kern_return_t krc;
2753    
2754     // create the the exception port
2755     krc = mach_port_allocate(mach_task_self(),
2756     MACH_PORT_RIGHT_RECEIVE, &_exceptionPort);
2757     if (krc != KERN_SUCCESS) {
2758     mach_error("mach_port_allocate", krc);
2759     return false;
2760     }
2761    
2762     // add a port send right
2763     krc = mach_port_insert_right(mach_task_self(),
2764     _exceptionPort, _exceptionPort,
2765     MACH_MSG_TYPE_MAKE_SEND);
2766     if (krc != KERN_SUCCESS) {
2767     mach_error("mach_port_insert_right", krc);
2768     return false;
2769     }
2770    
2771     // get the old exception ports
2772     ports.maskCount = sizeof (ports.masks) / sizeof (ports.masks[0]);
2773     krc = thread_get_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, ports.masks,
2774     &ports.maskCount, ports.handlers, ports.behaviors, ports.flavors);
2775     if (krc != KERN_SUCCESS) {
2776     mach_error("thread_get_exception_ports", krc);
2777     return false;
2778     }
2779    
2780     // set the new exception port
2781     //
2782     // We could have used EXCEPTION_STATE_IDENTITY instead of
2783     // EXCEPTION_DEFAULT to get the thread state in the initial
2784     // message, but it turns out that in the common case this is not
2785     // neccessary. If we need it we can later ask for it from the
2786     // suspended thread.
2787     //
2788     // Even with THREAD_STATE_NONE, Darwin provides the program
2789     // counter in the thread state. The comments in the header file
2790     // seem to imply that you can count on the GPR's on an exception
2791     // as well but just to be safe I use MACHINE_THREAD_STATE because
2792     // you have to ask for all of the GPR's anyway just to get the
2793     // program counter. In any case because of update effective
2794     // address from immediate and update address from effective
2795     // addresses of ra and rb modes (as good an name as any for these
2796     // addressing modes) used in PPC instructions, you will need the
2797     // GPR state anyway.
2798     krc = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, _exceptionPort,
2799 gbeauche 1.56 EXCEPTION_DEFAULT, SIGSEGV_THREAD_STATE_FLAVOR);
2800 gbeauche 1.27 if (krc != KERN_SUCCESS) {
2801     mach_error("thread_set_exception_ports", krc);
2802     return false;
2803     }
2804    
2805     // create the exception handler thread
2806     if (pthread_create(&exc_thread, NULL, &handleExceptions, NULL) != 0) {
2807     (void)fprintf(stderr, "creation of exception thread failed\n");
2808     return false;
2809     }
2810    
2811     // do not care about the exception thread any longer, let is run standalone
2812     (void)pthread_detach(exc_thread);
2813    
2814     sigsegv_fault_handler = handler;
2815     return true;
2816     #else
2817     return false;
2818     #endif
2819     }
2820     #endif
2821    
2822 gbeauche 1.48 #ifdef HAVE_WIN32_EXCEPTIONS
2823     static LONG WINAPI main_exception_filter(EXCEPTION_POINTERS *ExceptionInfo)
2824     {
2825     if (sigsegv_fault_handler != NULL
2826     && ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION
2827     && ExceptionInfo->ExceptionRecord->NumberParameters == 2
2828     && handle_badaccess(ExceptionInfo))
2829     return EXCEPTION_CONTINUE_EXECUTION;
2830    
2831     return EXCEPTION_CONTINUE_SEARCH;
2832     }
2833    
2834     #if defined __CYGWIN__ && defined __i386__
2835     /* In Cygwin programs, SetUnhandledExceptionFilter has no effect because Cygwin
2836     installs a global exception handler. We have to dig deep in order to install
2837     our main_exception_filter. */
2838    
2839     /* Data structures for the current thread's exception handler chain.
2840     On the x86 Windows uses register fs, offset 0 to point to the current
2841     exception handler; Cygwin mucks with it, so we must do the same... :-/ */
2842    
2843     /* Magic taken from winsup/cygwin/include/exceptions.h. */
2844    
2845     struct exception_list {
2846     struct exception_list *prev;
2847     int (*handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
2848     };
2849     typedef struct exception_list exception_list;
2850    
2851     /* Magic taken from winsup/cygwin/exceptions.cc. */
2852    
2853     __asm__ (".equ __except_list,0");
2854    
2855     extern exception_list *_except_list __asm__ ("%fs:__except_list");
2856    
2857     /* For debugging. _except_list is not otherwise accessible from gdb. */
2858     static exception_list *
2859     debug_get_except_list ()
2860     {
2861     return _except_list;
2862     }
2863    
2864     /* Cygwin's original exception handler. */
2865     static int (*cygwin_exception_handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
2866    
2867     /* Our exception handler. */
2868     static int
2869     libsigsegv_exception_handler (EXCEPTION_RECORD *exception, void *frame, CONTEXT *context, void *dispatch)
2870     {
2871     EXCEPTION_POINTERS ExceptionInfo;
2872     ExceptionInfo.ExceptionRecord = exception;
2873     ExceptionInfo.ContextRecord = context;
2874     if (main_exception_filter (&ExceptionInfo) == EXCEPTION_CONTINUE_SEARCH)
2875     return cygwin_exception_handler (exception, frame, context, dispatch);
2876     else
2877     return 0;
2878     }
2879    
2880     static void
2881     do_install_main_exception_filter ()
2882     {
2883     /* We cannot insert any handler into the chain, because such handlers
2884     must lie on the stack (?). Instead, we have to replace(!) Cygwin's
2885     global exception handler. */
2886     cygwin_exception_handler = _except_list->handler;
2887     _except_list->handler = libsigsegv_exception_handler;
2888     }
2889    
2890     #else
2891    
2892     static void
2893     do_install_main_exception_filter ()
2894     {
2895     SetUnhandledExceptionFilter ((LPTOP_LEVEL_EXCEPTION_FILTER) &main_exception_filter);
2896     }
2897     #endif
2898    
2899     static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
2900     {
2901     static bool main_exception_filter_installed = false;
2902     if (!main_exception_filter_installed) {
2903     do_install_main_exception_filter();
2904     main_exception_filter_installed = true;
2905     }
2906     sigsegv_fault_handler = handler;
2907     return true;
2908     }
2909     #endif
2910    
2911 gbeauche 1.12 bool sigsegv_install_handler(sigsegv_fault_handler_t handler)
2912 gbeauche 1.1 {
2913 gbeauche 1.27 #if defined(HAVE_SIGSEGV_RECOVERY)
2914 gbeauche 1.1 bool success = true;
2915     #define FAULT_HANDLER(sig) success = success && sigsegv_do_install_handler(sig);
2916     SIGSEGV_ALL_SIGNALS
2917     #undef FAULT_HANDLER
2918 gbeauche 1.27 if (success)
2919     sigsegv_fault_handler = handler;
2920 gbeauche 1.1 return success;
2921 gbeauche 1.48 #elif defined(HAVE_MACH_EXCEPTIONS) || defined(HAVE_WIN32_EXCEPTIONS)
2922 gbeauche 1.27 return sigsegv_do_install_handler(handler);
2923 gbeauche 1.1 #else
2924     // FAIL: no siginfo_t nor sigcontext subterfuge is available
2925     return false;
2926     #endif
2927     }
2928    
2929    
2930     /*
2931     * SIGSEGV handler deinitialization
2932     */
2933    
2934     void sigsegv_deinstall_handler(void)
2935     {
2936 gbeauche 1.27 // We do nothing for Mach exceptions, the thread would need to be
2937     // suspended if not already so, and we might mess with other
2938     // exception handlers that came after we registered ours. There is
2939     // no need to remove the exception handler, in fact this function is
2940     // not called anywhere in Basilisk II.
2941 gbeauche 1.2 #ifdef HAVE_SIGSEGV_RECOVERY
2942 gbeauche 1.12 sigsegv_fault_handler = 0;
2943 gbeauche 1.1 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
2944     SIGSEGV_ALL_SIGNALS
2945     #undef FAULT_HANDLER
2946 gbeauche 1.2 #endif
2947 gbeauche 1.48 #ifdef HAVE_WIN32_EXCEPTIONS
2948     sigsegv_fault_handler = NULL;
2949     #endif
2950 gbeauche 1.1 }
2951    
2952 gbeauche 1.10
2953     /*
2954     * Set callback function when we cannot handle the fault
2955     */
2956    
2957 gbeauche 1.12 void sigsegv_set_dump_state(sigsegv_state_dumper_t handler)
2958 gbeauche 1.10 {
2959 gbeauche 1.12 sigsegv_state_dumper = handler;
2960 gbeauche 1.10 }
2961    
2962    
2963 gbeauche 1.1 /*
2964     * Test program used for configure/test
2965     */
2966    
2967 gbeauche 1.4 #ifdef CONFIGURE_TEST_SIGSEGV_RECOVERY
2968 gbeauche 1.1 #include <stdio.h>
2969     #include <stdlib.h>
2970     #include <fcntl.h>
2971 gbeauche 1.48 #ifdef HAVE_SYS_MMAN_H
2972 gbeauche 1.1 #include <sys/mman.h>
2973 gbeauche 1.48 #endif
2974 gbeauche 1.4 #include "vm_alloc.h"
2975 gbeauche 1.1
2976 gbeauche 1.32 const int REF_INDEX = 123;
2977     const int REF_VALUE = 45;
2978    
2979 gbeauche 1.1 static int page_size;
2980 gbeauche 1.3 static volatile char * page = 0;
2981     static volatile int handler_called = 0;
2982 gbeauche 1.1
2983 gbeauche 1.61 /* Barriers */
2984     #ifdef __GNUC__
2985     #define BARRIER() asm volatile ("" : : : "memory")
2986     #else
2987     #define BARRIER() /* nothing */
2988     #endif
2989    
2990 gbeauche 1.32 #ifdef __GNUC__
2991     // Code range where we expect the fault to come from
2992     static void *b_region, *e_region;
2993     #endif
2994    
2995 gbeauche 1.67 static sigsegv_return_t sigsegv_test_handler(sigsegv_info_t *sip)
2996 gbeauche 1.1 {
2997 gbeauche 1.67 const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
2998     const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip);
2999 gbeauche 1.39 #if DEBUG
3000     printf("sigsegv_test_handler(%p, %p)\n", fault_address, instruction_address);
3001     printf("expected fault at %p\n", page + REF_INDEX);
3002     #ifdef __GNUC__
3003     printf("expected instruction address range: %p-%p\n", b_region, e_region);
3004     #endif
3005     #endif
3006 gbeauche 1.1 handler_called++;
3007 gbeauche 1.32 if ((fault_address - REF_INDEX) != page)
3008 gbeauche 1.29 exit(10);
3009 gbeauche 1.32 #ifdef __GNUC__
3010     // Make sure reported fault instruction address falls into
3011     // expected code range
3012 gbeauche 1.67 if (instruction_address != SIGSEGV_INVALID_ADDRESS
3013 gbeauche 1.32 && ((instruction_address < (sigsegv_address_t)b_region) ||
3014     (instruction_address >= (sigsegv_address_t)e_region)))
3015     exit(11);
3016     #endif
3017 gbeauche 1.4 if (vm_protect((char *)((unsigned long)fault_address & -page_size), page_size, VM_PAGE_READ | VM_PAGE_WRITE) != 0)
3018 gbeauche 1.32 exit(12);
3019 gbeauche 1.24 return SIGSEGV_RETURN_SUCCESS;
3020 gbeauche 1.1 }
3021    
3022 gbeauche 1.10 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
3023 gbeauche 1.67 static sigsegv_return_t sigsegv_insn_handler(sigsegv_info_t *sip)
3024 gbeauche 1.10 {
3025 gbeauche 1.67 const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
3026     const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip);
3027 gbeauche 1.44 #if DEBUG
3028     printf("sigsegv_insn_handler(%p, %p)\n", fault_address, instruction_address);
3029     #endif
3030 gbeauche 1.28 if (((unsigned long)fault_address - (unsigned long)page) < page_size) {
3031     #ifdef __GNUC__
3032     // Make sure reported fault instruction address falls into
3033     // expected code range
3034 gbeauche 1.67 if (instruction_address != SIGSEGV_INVALID_ADDRESS
3035 gbeauche 1.28 && ((instruction_address < (sigsegv_address_t)b_region) ||
3036     (instruction_address >= (sigsegv_address_t)e_region)))
3037     return SIGSEGV_RETURN_FAILURE;
3038     #endif
3039 gbeauche 1.26 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
3040 gbeauche 1.28 }
3041    
3042 gbeauche 1.24 return SIGSEGV_RETURN_FAILURE;
3043 gbeauche 1.10 }
3044 gbeauche 1.34
3045     // More sophisticated tests for instruction skipper
3046     static bool arch_insn_skipper_tests()
3047     {
3048     #if (defined(i386) || defined(__i386__)) || defined(__x86_64__)
3049     static const unsigned char code[] = {
3050     0x8a, 0x00, // mov (%eax),%al
3051     0x8a, 0x2c, 0x18, // mov (%eax,%ebx,1),%ch
3052     0x88, 0x20, // mov %ah,(%eax)
3053     0x88, 0x08, // mov %cl,(%eax)
3054     0x66, 0x8b, 0x00, // mov (%eax),%ax
3055     0x66, 0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%cx
3056     0x66, 0x89, 0x00, // mov %ax,(%eax)
3057     0x66, 0x89, 0x0c, 0x18, // mov %cx,(%eax,%ebx,1)
3058     0x8b, 0x00, // mov (%eax),%eax
3059     0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%ecx
3060     0x89, 0x00, // mov %eax,(%eax)
3061     0x89, 0x0c, 0x18, // mov %ecx,(%eax,%ebx,1)
3062     #if defined(__x86_64__)
3063     0x44, 0x8a, 0x00, // mov (%rax),%r8b
3064     0x44, 0x8a, 0x20, // mov (%rax),%r12b
3065     0x42, 0x8a, 0x3c, 0x10, // mov (%rax,%r10,1),%dil
3066     0x44, 0x88, 0x00, // mov %r8b,(%rax)
3067     0x44, 0x88, 0x20, // mov %r12b,(%rax)
3068     0x42, 0x88, 0x3c, 0x10, // mov %dil,(%rax,%r10,1)
3069     0x66, 0x44, 0x8b, 0x00, // mov (%rax),%r8w
3070     0x66, 0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%cx
3071     0x66, 0x44, 0x89, 0x00, // mov %r8w,(%rax)
3072     0x66, 0x42, 0x89, 0x0c, 0x10, // mov %cx,(%rax,%r10,1)
3073     0x44, 0x8b, 0x00, // mov (%rax),%r8d
3074     0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%ecx
3075     0x44, 0x89, 0x00, // mov %r8d,(%rax)
3076     0x42, 0x89, 0x0c, 0x10, // mov %ecx,(%rax,%r10,1)
3077     0x48, 0x8b, 0x08, // mov (%rax),%rcx
3078     0x4c, 0x8b, 0x18, // mov (%rax),%r11
3079     0x4a, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%rcx
3080     0x4e, 0x8b, 0x1c, 0x10, // mov (%rax,%r10,1),%r11
3081     0x48, 0x89, 0x08, // mov %rcx,(%rax)
3082     0x4c, 0x89, 0x18, // mov %r11,(%rax)
3083     0x4a, 0x89, 0x0c, 0x10, // mov %rcx,(%rax,%r10,1)
3084     0x4e, 0x89, 0x1c, 0x10, // mov %r11,(%rax,%r10,1)
3085 gbeauche 1.62 0x63, 0x47, 0x04, // movslq 4(%rdi),%eax
3086     0x48, 0x63, 0x47, 0x04, // movslq 4(%rdi),%rax
3087 gbeauche 1.34 #endif
3088     0 // end
3089     };
3090     const int N_REGS = 20;
3091     unsigned long regs[N_REGS];
3092     for (int i = 0; i < N_REGS; i++)
3093     regs[i] = i;
3094     const unsigned long start_code = (unsigned long)&code;
3095     regs[X86_REG_EIP] = start_code;
3096     while ((regs[X86_REG_EIP] - start_code) < (sizeof(code) - 1)
3097     && ix86_skip_instruction(regs))
3098     ; /* simply iterate */
3099     return (regs[X86_REG_EIP] - start_code) == (sizeof(code) - 1);
3100     #endif
3101     return true;
3102     }
3103 gbeauche 1.10 #endif
3104    
3105 gbeauche 1.1 int main(void)
3106     {
3107 gbeauche 1.4 if (vm_init() < 0)
3108 gbeauche 1.1 return 1;
3109    
3110 gbeauche 1.54 page_size = vm_get_page_size();
3111 gbeauche 1.4 if ((page = (char *)vm_acquire(page_size)) == VM_MAP_FAILED)
3112 gbeauche 1.29 return 2;
3113 gbeauche 1.4
3114 gbeauche 1.32 memset((void *)page, 0, page_size);
3115 gbeauche 1.4 if (vm_protect((char *)page, page_size, VM_PAGE_READ) < 0)
3116 gbeauche 1.29 return 3;
3117 gbeauche 1.1
3118     if (!sigsegv_install_handler(sigsegv_test_handler))
3119 gbeauche 1.29 return 4;
3120 gbeauche 1.74
3121 gbeauche 1.32 #ifdef __GNUC__
3122     b_region = &&L_b_region1;
3123     e_region = &&L_e_region1;
3124     #endif
3125 gbeauche 1.74 /* This is a really awful hack but otherwise gcc is smart enough
3126     * (or bug'ous enough?) to optimize the labels and place them
3127     * e.g. at the "main" entry point, which is wrong.
3128     */
3129     volatile int label_hack = 1;
3130     switch (label_hack) {
3131     case 1:
3132     L_b_region1:
3133     page[REF_INDEX] = REF_VALUE;
3134     if (page[REF_INDEX] != REF_VALUE)
3135     exit(20);
3136     page[REF_INDEX] = REF_VALUE;
3137     BARRIER();
3138     // fall-through
3139     case 2:
3140     L_e_region1:
3141     BARRIER();
3142     break;
3143     }
3144 gbeauche 1.32
3145 gbeauche 1.1 if (handler_called != 1)
3146 gbeauche 1.29 return 5;
3147 gbeauche 1.10
3148     #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
3149     if (!sigsegv_install_handler(sigsegv_insn_handler))
3150 gbeauche 1.29 return 6;
3151 gbeauche 1.10
3152 gbeauche 1.17 if (vm_protect((char *)page, page_size, VM_PAGE_READ | VM_PAGE_WRITE) < 0)
3153 gbeauche 1.29 return 7;
3154 gbeauche 1.10
3155     for (int i = 0; i < page_size; i++)
3156     page[i] = (i + 1) % page_size;
3157    
3158     if (vm_protect((char *)page, page_size, VM_PAGE_NOACCESS) < 0)
3159 gbeauche 1.29 return 8;
3160 gbeauche 1.10
3161     #define TEST_SKIP_INSTRUCTION(TYPE) do { \
3162 gbeauche 1.34 const unsigned long TAG = 0x12345678 | \
3163     (sizeof(long) == 8 ? 0x9abcdef0UL << 31 : 0); \
3164 gbeauche 1.10 TYPE data = *((TYPE *)(page + sizeof(TYPE))); \
3165 gbeauche 1.34 volatile unsigned long effect = data + TAG; \
3166 gbeauche 1.10 if (effect != TAG) \
3167 gbeauche 1.29 return 9; \
3168 gbeauche 1.10 } while (0)
3169    
3170 gbeauche 1.28 #ifdef __GNUC__
3171 gbeauche 1.32 b_region = &&L_b_region2;
3172     e_region = &&L_e_region2;
3173 gbeauche 1.28 #endif
3174 gbeauche 1.74 switch (label_hack) {
3175     case 1:
3176     L_b_region2:
3177     TEST_SKIP_INSTRUCTION(unsigned char);
3178     TEST_SKIP_INSTRUCTION(unsigned short);
3179     TEST_SKIP_INSTRUCTION(unsigned int);
3180     TEST_SKIP_INSTRUCTION(unsigned long);
3181     TEST_SKIP_INSTRUCTION(signed char);
3182     TEST_SKIP_INSTRUCTION(signed short);
3183     TEST_SKIP_INSTRUCTION(signed int);
3184     TEST_SKIP_INSTRUCTION(signed long);
3185     BARRIER();
3186     // fall-through
3187     case 2:
3188     L_e_region2:
3189     BARRIER();
3190     break;
3191     }
3192 gbeauche 1.34 if (!arch_insn_skipper_tests())
3193     return 20;
3194 gbeauche 1.35 #endif
3195 gbeauche 1.34
3196 gbeauche 1.4 vm_exit();
3197 gbeauche 1.1 return 0;
3198     }
3199     #endif