ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.77
Committed: 2008-01-06T17:22:19Z (16 years, 9 months ago) by gbeauche
Branch: MAIN
Changes since 1.76: +39 -41 lines
Log Message:
The Linux kernel actually allows to restart execution from the specified slot
in the bundle. This is faster and more accurate as this avoids emulation.

Also clean-up code so that to prepare the use of lib uaccess on hpux/ia64.
XXX: this will need explicit use of uint64_t to define registers because
HP/UX is ILP32 capable and all registers are 64-bit capable so "unsigned long"
won't fit.

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     if (use_fast_path < 0)
2441 gbeauche 1.72 use_fast_path = addr == SIP->addr;
2442     SIP->addr = addr;
2443 gbeauche 1.68 }
2444     #endif
2445 gbeauche 1.72 return SIP->addr;
2446 gbeauche 1.67 }
2447    
2448     // Return the address of the instruction that caused the fault, or
2449     // SIGSEGV_INVALID_ADDRESS if we could not retrieve this information
2450 gbeauche 1.72 sigsegv_address_t sigsegv_get_fault_instruction_address(sigsegv_info_t *SIP)
2451 gbeauche 1.67 {
2452 gbeauche 1.68 #ifdef HAVE_MACH_EXCEPTIONS
2453 gbeauche 1.72 if (!SIP->has_thr_state) {
2454     mach_get_thread_state(SIP);
2455 gbeauche 1.68
2456 gbeauche 1.72 SIP->pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
2457 gbeauche 1.68 }
2458     #endif
2459 gbeauche 1.72 return SIP->pc;
2460 gbeauche 1.67 }
2461    
2462 gbeauche 1.27 // This function handles the badaccess to memory.
2463     // It is called from the signal handler or the exception handler.
2464 gbeauche 1.30 static bool handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGLIST_1)
2465 gbeauche 1.1 {
2466 gbeauche 1.72 sigsegv_info_t SI;
2467     SI.addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS_FAST;
2468     SI.pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION_FAST;
2469 gbeauche 1.56 #ifdef HAVE_MACH_EXCEPTIONS
2470 gbeauche 1.72 SI.thread = thread;
2471     SI.has_exc_state = false;
2472     SI.has_thr_state = false;
2473 gbeauche 1.56 #endif
2474 gbeauche 1.72 sigsegv_info_t * const SIP = &SI;
2475 gbeauche 1.56
2476 gbeauche 1.1 // Call user's handler and reinstall the global handler, if required
2477 gbeauche 1.72 switch (SIGSEGV_FAULT_HANDLER_INVOKE(SIP)) {
2478 gbeauche 1.24 case SIGSEGV_RETURN_SUCCESS:
2479 gbeauche 1.27 return true;
2480    
2481 gbeauche 1.10 #if HAVE_SIGSEGV_SKIP_INSTRUCTION
2482 gbeauche 1.24 case SIGSEGV_RETURN_SKIP_INSTRUCTION:
2483 gbeauche 1.27 // Call the instruction skipper with the register file
2484     // available
2485 gbeauche 1.70 #ifdef HAVE_MACH_EXCEPTIONS
2486 gbeauche 1.72 if (!SIP->has_thr_state)
2487     mach_get_thread_state(SIP);
2488 gbeauche 1.70 #endif
2489 gbeauche 1.27 if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE)) {
2490     #ifdef HAVE_MACH_EXCEPTIONS
2491     // Unlike UNIX signals where the thread state
2492     // is modified off of the stack, in Mach we
2493     // need to actually call thread_set_state to
2494     // have the register values updated.
2495 gbeauche 1.72 mach_set_thread_state(SIP);
2496 gbeauche 1.27 #endif
2497     return true;
2498     }
2499 gbeauche 1.24 break;
2500     #endif
2501 nigel 1.43 case SIGSEGV_RETURN_FAILURE:
2502 gbeauche 1.50 // We can't do anything with the fault_address, dump state?
2503     if (sigsegv_state_dumper != 0)
2504 gbeauche 1.72 sigsegv_state_dumper(SIP);
2505 gbeauche 1.50 break;
2506 gbeauche 1.10 }
2507 gbeauche 1.27
2508     return false;
2509     }
2510    
2511    
2512     /*
2513     * There are two mechanisms for handling a bad memory access,
2514     * Mach exceptions and UNIX signals. The implementation specific
2515     * code appears below. Its reponsibility is to call handle_badaccess
2516     * which is the routine that handles the fault in an implementation
2517     * agnostic manner. The implementation specific code below is then
2518     * reponsible for checking whether handle_badaccess was able
2519     * to handle the memory access error and perform any implementation
2520     * specific tasks necessary afterwards.
2521     */
2522    
2523     #ifdef HAVE_MACH_EXCEPTIONS
2524     /*
2525     * We need to forward all exceptions that we do not handle.
2526     * This is important, there are many exceptions that may be
2527     * handled by other exception handlers. For example debuggers
2528     * use exceptions and the exception hander is in another
2529     * process in such a case. (Timothy J. Wood states in his
2530     * message to the list that he based this code on that from
2531     * gdb for Darwin.)
2532     */
2533     static inline kern_return_t
2534     forward_exception(mach_port_t thread_port,
2535     mach_port_t task_port,
2536     exception_type_t exception_type,
2537     exception_data_t exception_data,
2538     mach_msg_type_number_t data_count,
2539     ExceptionPorts *oldExceptionPorts)
2540     {
2541     kern_return_t kret;
2542     unsigned int portIndex;
2543     mach_port_t port;
2544     exception_behavior_t behavior;
2545     thread_state_flavor_t flavor;
2546 gbeauche 1.57 thread_state_data_t thread_state;
2547 gbeauche 1.27 mach_msg_type_number_t thread_state_count;
2548    
2549     for (portIndex = 0; portIndex < oldExceptionPorts->maskCount; portIndex++) {
2550     if (oldExceptionPorts->masks[portIndex] & (1 << exception_type)) {
2551     // This handler wants the exception
2552     break;
2553     }
2554     }
2555    
2556     if (portIndex >= oldExceptionPorts->maskCount) {
2557     fprintf(stderr, "No handler for exception_type = %d. Not fowarding\n", exception_type);
2558     return KERN_FAILURE;
2559     }
2560    
2561     port = oldExceptionPorts->handlers[portIndex];
2562     behavior = oldExceptionPorts->behaviors[portIndex];
2563     flavor = oldExceptionPorts->flavors[portIndex];
2564    
2565 gbeauche 1.63 if (!VALID_THREAD_STATE_FLAVOR(flavor)) {
2566     fprintf(stderr, "Invalid thread_state flavor = %d. Not forwarding\n", flavor);
2567     return KERN_FAILURE;
2568     }
2569    
2570 gbeauche 1.27 /*
2571     fprintf(stderr, "forwarding exception, port = 0x%x, behaviour = %d, flavor = %d\n", port, behavior, flavor);
2572     */
2573    
2574     if (behavior != EXCEPTION_DEFAULT) {
2575     thread_state_count = THREAD_STATE_MAX;
2576 gbeauche 1.60 kret = thread_get_state (thread_port, flavor, (natural_t *)&thread_state,
2577 gbeauche 1.27 &thread_state_count);
2578     MACH_CHECK_ERROR (thread_get_state, kret);
2579     }
2580    
2581     switch (behavior) {
2582     case EXCEPTION_DEFAULT:
2583     // fprintf(stderr, "forwarding to exception_raise\n");
2584     kret = exception_raise(port, thread_port, task_port, exception_type,
2585     exception_data, data_count);
2586     MACH_CHECK_ERROR (exception_raise, kret);
2587     break;
2588     case EXCEPTION_STATE:
2589     // fprintf(stderr, "forwarding to exception_raise_state\n");
2590     kret = exception_raise_state(port, exception_type, exception_data,
2591     data_count, &flavor,
2592 gbeauche 1.60 (natural_t *)&thread_state, thread_state_count,
2593     (natural_t *)&thread_state, &thread_state_count);
2594 gbeauche 1.27 MACH_CHECK_ERROR (exception_raise_state, kret);
2595     break;
2596     case EXCEPTION_STATE_IDENTITY:
2597     // fprintf(stderr, "forwarding to exception_raise_state_identity\n");
2598     kret = exception_raise_state_identity(port, thread_port, task_port,
2599     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_identity, kret);
2604     break;
2605     default:
2606     fprintf(stderr, "forward_exception got unknown behavior\n");
2607 gbeauche 1.63 kret = KERN_FAILURE;
2608 gbeauche 1.27 break;
2609     }
2610    
2611     if (behavior != EXCEPTION_DEFAULT) {
2612 gbeauche 1.60 kret = thread_set_state (thread_port, flavor, (natural_t *)&thread_state,
2613 gbeauche 1.27 thread_state_count);
2614     MACH_CHECK_ERROR (thread_set_state, kret);
2615     }
2616    
2617 gbeauche 1.63 return kret;
2618 gbeauche 1.27 }
2619    
2620     /*
2621     * This is the code that actually handles the exception.
2622     * It is called by exc_server. For Darwin 5 Apple changed
2623     * this a bit from how this family of functions worked in
2624     * Mach. If you are familiar with that it is a little
2625     * different. The main variation that concerns us here is
2626     * that code is an array of exception specific codes and
2627     * codeCount is a count of the number of codes in the code
2628     * array. In typical Mach all exceptions have a code
2629     * and sub-code. It happens to be the case that for a
2630     * EXC_BAD_ACCESS exception the first entry is the type of
2631     * bad access that occurred and the second entry is the
2632     * faulting address so these entries correspond exactly to
2633     * how the code and sub-code are used on Mach.
2634     *
2635     * This is a MIG interface. No code in Basilisk II should
2636     * call this directley. This has to have external C
2637     * linkage because that is what exc_server expects.
2638     */
2639     kern_return_t
2640     catch_exception_raise(mach_port_t exception_port,
2641     mach_port_t thread,
2642     mach_port_t task,
2643     exception_type_t exception,
2644     exception_data_t code,
2645 gbeauche 1.66 mach_msg_type_number_t code_count)
2646 gbeauche 1.27 {
2647     kern_return_t krc;
2648    
2649 gbeauche 1.66 if (exception == EXC_BAD_ACCESS) {
2650     switch (code[0]) {
2651     case KERN_PROTECTION_FAILURE:
2652     case KERN_INVALID_ADDRESS:
2653     if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS))
2654     return KERN_SUCCESS;
2655     break;
2656     }
2657 gbeauche 1.27 }
2658    
2659     // In Mach we do not need to remove the exception handler.
2660     // If we forward the exception, eventually some exception handler
2661     // will take care of this exception.
2662 gbeauche 1.66 krc = forward_exception(thread, task, exception, code, code_count, &ports);
2663 gbeauche 1.27
2664     return krc;
2665     }
2666     #endif
2667    
2668     #ifdef HAVE_SIGSEGV_RECOVERY
2669     // Handle bad memory accesses with signal handler
2670     static void sigsegv_handler(SIGSEGV_FAULT_HANDLER_ARGLIST)
2671     {
2672     // Call handler and reinstall the global handler, if required
2673     if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS)) {
2674     #if (defined(HAVE_SIGACTION) ? defined(SIGACTION_NEED_REINSTALL) : defined(SIGNAL_NEED_REINSTALL))
2675     sigsegv_do_install_handler(sig);
2676     #endif
2677     return;
2678     }
2679 gbeauche 1.10
2680 gbeauche 1.27 // Failure: reinstall default handler for "safe" crash
2681 gbeauche 1.1 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
2682 gbeauche 1.27 SIGSEGV_ALL_SIGNALS
2683 gbeauche 1.1 #undef FAULT_HANDLER
2684     }
2685 gbeauche 1.2 #endif
2686 gbeauche 1.1
2687    
2688     /*
2689     * SIGSEGV handler initialization
2690     */
2691    
2692     #if defined(HAVE_SIGINFO_T)
2693     static bool sigsegv_do_install_handler(int sig)
2694     {
2695     // Setup SIGSEGV handler to process writes to frame buffer
2696     #ifdef HAVE_SIGACTION
2697 gbeauche 1.22 struct sigaction sigsegv_sa;
2698     sigemptyset(&sigsegv_sa.sa_mask);
2699     sigsegv_sa.sa_sigaction = sigsegv_handler;
2700     sigsegv_sa.sa_flags = SA_SIGINFO;
2701     return (sigaction(sig, &sigsegv_sa, 0) == 0);
2702 gbeauche 1.1 #else
2703     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
2704     #endif
2705     }
2706 gbeauche 1.2 #endif
2707    
2708     #if defined(HAVE_SIGCONTEXT_SUBTERFUGE)
2709 gbeauche 1.1 static bool sigsegv_do_install_handler(int sig)
2710     {
2711     // Setup SIGSEGV handler to process writes to frame buffer
2712     #ifdef HAVE_SIGACTION
2713 gbeauche 1.22 struct sigaction sigsegv_sa;
2714     sigemptyset(&sigsegv_sa.sa_mask);
2715     sigsegv_sa.sa_handler = (signal_handler)sigsegv_handler;
2716     sigsegv_sa.sa_flags = 0;
2717 gbeauche 1.1 #if !EMULATED_68K && defined(__NetBSD__)
2718 gbeauche 1.22 sigaddset(&sigsegv_sa.sa_mask, SIGALRM);
2719     sigsegv_sa.sa_flags |= SA_ONSTACK;
2720 gbeauche 1.1 #endif
2721 gbeauche 1.22 return (sigaction(sig, &sigsegv_sa, 0) == 0);
2722 gbeauche 1.1 #else
2723     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
2724     #endif
2725     }
2726     #endif
2727    
2728 gbeauche 1.27 #if defined(HAVE_MACH_EXCEPTIONS)
2729     static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
2730     {
2731     /*
2732     * Except for the exception port functions, this should be
2733     * pretty much stock Mach. If later you choose to support
2734     * other Mach's besides Darwin, just check for __MACH__
2735     * here and __APPLE__ where the actual differences are.
2736     */
2737     #if defined(__APPLE__) && defined(__MACH__)
2738     if (sigsegv_fault_handler != NULL) {
2739     sigsegv_fault_handler = handler;
2740     return true;
2741     }
2742    
2743     kern_return_t krc;
2744    
2745     // create the the exception port
2746     krc = mach_port_allocate(mach_task_self(),
2747     MACH_PORT_RIGHT_RECEIVE, &_exceptionPort);
2748     if (krc != KERN_SUCCESS) {
2749     mach_error("mach_port_allocate", krc);
2750     return false;
2751     }
2752    
2753     // add a port send right
2754     krc = mach_port_insert_right(mach_task_self(),
2755     _exceptionPort, _exceptionPort,
2756     MACH_MSG_TYPE_MAKE_SEND);
2757     if (krc != KERN_SUCCESS) {
2758     mach_error("mach_port_insert_right", krc);
2759     return false;
2760     }
2761    
2762     // get the old exception ports
2763     ports.maskCount = sizeof (ports.masks) / sizeof (ports.masks[0]);
2764     krc = thread_get_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, ports.masks,
2765     &ports.maskCount, ports.handlers, ports.behaviors, ports.flavors);
2766     if (krc != KERN_SUCCESS) {
2767     mach_error("thread_get_exception_ports", krc);
2768     return false;
2769     }
2770    
2771     // set the new exception port
2772     //
2773     // We could have used EXCEPTION_STATE_IDENTITY instead of
2774     // EXCEPTION_DEFAULT to get the thread state in the initial
2775     // message, but it turns out that in the common case this is not
2776     // neccessary. If we need it we can later ask for it from the
2777     // suspended thread.
2778     //
2779     // Even with THREAD_STATE_NONE, Darwin provides the program
2780     // counter in the thread state. The comments in the header file
2781     // seem to imply that you can count on the GPR's on an exception
2782     // as well but just to be safe I use MACHINE_THREAD_STATE because
2783     // you have to ask for all of the GPR's anyway just to get the
2784     // program counter. In any case because of update effective
2785     // address from immediate and update address from effective
2786     // addresses of ra and rb modes (as good an name as any for these
2787     // addressing modes) used in PPC instructions, you will need the
2788     // GPR state anyway.
2789     krc = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, _exceptionPort,
2790 gbeauche 1.56 EXCEPTION_DEFAULT, SIGSEGV_THREAD_STATE_FLAVOR);
2791 gbeauche 1.27 if (krc != KERN_SUCCESS) {
2792     mach_error("thread_set_exception_ports", krc);
2793     return false;
2794     }
2795    
2796     // create the exception handler thread
2797     if (pthread_create(&exc_thread, NULL, &handleExceptions, NULL) != 0) {
2798     (void)fprintf(stderr, "creation of exception thread failed\n");
2799     return false;
2800     }
2801    
2802     // do not care about the exception thread any longer, let is run standalone
2803     (void)pthread_detach(exc_thread);
2804    
2805     sigsegv_fault_handler = handler;
2806     return true;
2807     #else
2808     return false;
2809     #endif
2810     }
2811     #endif
2812    
2813 gbeauche 1.48 #ifdef HAVE_WIN32_EXCEPTIONS
2814     static LONG WINAPI main_exception_filter(EXCEPTION_POINTERS *ExceptionInfo)
2815     {
2816     if (sigsegv_fault_handler != NULL
2817     && ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION
2818     && ExceptionInfo->ExceptionRecord->NumberParameters == 2
2819     && handle_badaccess(ExceptionInfo))
2820     return EXCEPTION_CONTINUE_EXECUTION;
2821    
2822     return EXCEPTION_CONTINUE_SEARCH;
2823     }
2824    
2825     #if defined __CYGWIN__ && defined __i386__
2826     /* In Cygwin programs, SetUnhandledExceptionFilter has no effect because Cygwin
2827     installs a global exception handler. We have to dig deep in order to install
2828     our main_exception_filter. */
2829    
2830     /* Data structures for the current thread's exception handler chain.
2831     On the x86 Windows uses register fs, offset 0 to point to the current
2832     exception handler; Cygwin mucks with it, so we must do the same... :-/ */
2833    
2834     /* Magic taken from winsup/cygwin/include/exceptions.h. */
2835    
2836     struct exception_list {
2837     struct exception_list *prev;
2838     int (*handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
2839     };
2840     typedef struct exception_list exception_list;
2841    
2842     /* Magic taken from winsup/cygwin/exceptions.cc. */
2843    
2844     __asm__ (".equ __except_list,0");
2845    
2846     extern exception_list *_except_list __asm__ ("%fs:__except_list");
2847    
2848     /* For debugging. _except_list is not otherwise accessible from gdb. */
2849     static exception_list *
2850     debug_get_except_list ()
2851     {
2852     return _except_list;
2853     }
2854    
2855     /* Cygwin's original exception handler. */
2856     static int (*cygwin_exception_handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
2857    
2858     /* Our exception handler. */
2859     static int
2860     libsigsegv_exception_handler (EXCEPTION_RECORD *exception, void *frame, CONTEXT *context, void *dispatch)
2861     {
2862     EXCEPTION_POINTERS ExceptionInfo;
2863     ExceptionInfo.ExceptionRecord = exception;
2864     ExceptionInfo.ContextRecord = context;
2865     if (main_exception_filter (&ExceptionInfo) == EXCEPTION_CONTINUE_SEARCH)
2866     return cygwin_exception_handler (exception, frame, context, dispatch);
2867     else
2868     return 0;
2869     }
2870    
2871     static void
2872     do_install_main_exception_filter ()
2873     {
2874     /* We cannot insert any handler into the chain, because such handlers
2875     must lie on the stack (?). Instead, we have to replace(!) Cygwin's
2876     global exception handler. */
2877     cygwin_exception_handler = _except_list->handler;
2878     _except_list->handler = libsigsegv_exception_handler;
2879     }
2880    
2881     #else
2882    
2883     static void
2884     do_install_main_exception_filter ()
2885     {
2886     SetUnhandledExceptionFilter ((LPTOP_LEVEL_EXCEPTION_FILTER) &main_exception_filter);
2887     }
2888     #endif
2889    
2890     static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
2891     {
2892     static bool main_exception_filter_installed = false;
2893     if (!main_exception_filter_installed) {
2894     do_install_main_exception_filter();
2895     main_exception_filter_installed = true;
2896     }
2897     sigsegv_fault_handler = handler;
2898     return true;
2899     }
2900     #endif
2901    
2902 gbeauche 1.12 bool sigsegv_install_handler(sigsegv_fault_handler_t handler)
2903 gbeauche 1.1 {
2904 gbeauche 1.27 #if defined(HAVE_SIGSEGV_RECOVERY)
2905 gbeauche 1.1 bool success = true;
2906     #define FAULT_HANDLER(sig) success = success && sigsegv_do_install_handler(sig);
2907     SIGSEGV_ALL_SIGNALS
2908     #undef FAULT_HANDLER
2909 gbeauche 1.27 if (success)
2910     sigsegv_fault_handler = handler;
2911 gbeauche 1.1 return success;
2912 gbeauche 1.48 #elif defined(HAVE_MACH_EXCEPTIONS) || defined(HAVE_WIN32_EXCEPTIONS)
2913 gbeauche 1.27 return sigsegv_do_install_handler(handler);
2914 gbeauche 1.1 #else
2915     // FAIL: no siginfo_t nor sigcontext subterfuge is available
2916     return false;
2917     #endif
2918     }
2919    
2920    
2921     /*
2922     * SIGSEGV handler deinitialization
2923     */
2924    
2925     void sigsegv_deinstall_handler(void)
2926     {
2927 gbeauche 1.27 // We do nothing for Mach exceptions, the thread would need to be
2928     // suspended if not already so, and we might mess with other
2929     // exception handlers that came after we registered ours. There is
2930     // no need to remove the exception handler, in fact this function is
2931     // not called anywhere in Basilisk II.
2932 gbeauche 1.2 #ifdef HAVE_SIGSEGV_RECOVERY
2933 gbeauche 1.12 sigsegv_fault_handler = 0;
2934 gbeauche 1.1 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
2935     SIGSEGV_ALL_SIGNALS
2936     #undef FAULT_HANDLER
2937 gbeauche 1.2 #endif
2938 gbeauche 1.48 #ifdef HAVE_WIN32_EXCEPTIONS
2939     sigsegv_fault_handler = NULL;
2940     #endif
2941 gbeauche 1.1 }
2942    
2943 gbeauche 1.10
2944     /*
2945     * Set callback function when we cannot handle the fault
2946     */
2947    
2948 gbeauche 1.12 void sigsegv_set_dump_state(sigsegv_state_dumper_t handler)
2949 gbeauche 1.10 {
2950 gbeauche 1.12 sigsegv_state_dumper = handler;
2951 gbeauche 1.10 }
2952    
2953    
2954 gbeauche 1.1 /*
2955     * Test program used for configure/test
2956     */
2957    
2958 gbeauche 1.4 #ifdef CONFIGURE_TEST_SIGSEGV_RECOVERY
2959 gbeauche 1.1 #include <stdio.h>
2960     #include <stdlib.h>
2961     #include <fcntl.h>
2962 gbeauche 1.48 #ifdef HAVE_SYS_MMAN_H
2963 gbeauche 1.1 #include <sys/mman.h>
2964 gbeauche 1.48 #endif
2965 gbeauche 1.4 #include "vm_alloc.h"
2966 gbeauche 1.1
2967 gbeauche 1.32 const int REF_INDEX = 123;
2968     const int REF_VALUE = 45;
2969    
2970 gbeauche 1.1 static int page_size;
2971 gbeauche 1.3 static volatile char * page = 0;
2972     static volatile int handler_called = 0;
2973 gbeauche 1.1
2974 gbeauche 1.61 /* Barriers */
2975     #ifdef __GNUC__
2976     #define BARRIER() asm volatile ("" : : : "memory")
2977     #else
2978     #define BARRIER() /* nothing */
2979     #endif
2980    
2981 gbeauche 1.32 #ifdef __GNUC__
2982     // Code range where we expect the fault to come from
2983     static void *b_region, *e_region;
2984     #endif
2985    
2986 gbeauche 1.67 static sigsegv_return_t sigsegv_test_handler(sigsegv_info_t *sip)
2987 gbeauche 1.1 {
2988 gbeauche 1.67 const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
2989     const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip);
2990 gbeauche 1.39 #if DEBUG
2991     printf("sigsegv_test_handler(%p, %p)\n", fault_address, instruction_address);
2992     printf("expected fault at %p\n", page + REF_INDEX);
2993     #ifdef __GNUC__
2994     printf("expected instruction address range: %p-%p\n", b_region, e_region);
2995     #endif
2996     #endif
2997 gbeauche 1.1 handler_called++;
2998 gbeauche 1.32 if ((fault_address - REF_INDEX) != page)
2999 gbeauche 1.29 exit(10);
3000 gbeauche 1.32 #ifdef __GNUC__
3001     // Make sure reported fault instruction address falls into
3002     // expected code range
3003 gbeauche 1.67 if (instruction_address != SIGSEGV_INVALID_ADDRESS
3004 gbeauche 1.32 && ((instruction_address < (sigsegv_address_t)b_region) ||
3005     (instruction_address >= (sigsegv_address_t)e_region)))
3006     exit(11);
3007     #endif
3008 gbeauche 1.4 if (vm_protect((char *)((unsigned long)fault_address & -page_size), page_size, VM_PAGE_READ | VM_PAGE_WRITE) != 0)
3009 gbeauche 1.32 exit(12);
3010 gbeauche 1.24 return SIGSEGV_RETURN_SUCCESS;
3011 gbeauche 1.1 }
3012    
3013 gbeauche 1.10 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
3014 gbeauche 1.67 static sigsegv_return_t sigsegv_insn_handler(sigsegv_info_t *sip)
3015 gbeauche 1.10 {
3016 gbeauche 1.67 const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
3017     const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip);
3018 gbeauche 1.44 #if DEBUG
3019     printf("sigsegv_insn_handler(%p, %p)\n", fault_address, instruction_address);
3020     #endif
3021 gbeauche 1.28 if (((unsigned long)fault_address - (unsigned long)page) < page_size) {
3022     #ifdef __GNUC__
3023     // Make sure reported fault instruction address falls into
3024     // expected code range
3025 gbeauche 1.67 if (instruction_address != SIGSEGV_INVALID_ADDRESS
3026 gbeauche 1.28 && ((instruction_address < (sigsegv_address_t)b_region) ||
3027     (instruction_address >= (sigsegv_address_t)e_region)))
3028     return SIGSEGV_RETURN_FAILURE;
3029     #endif
3030 gbeauche 1.26 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
3031 gbeauche 1.28 }
3032    
3033 gbeauche 1.24 return SIGSEGV_RETURN_FAILURE;
3034 gbeauche 1.10 }
3035 gbeauche 1.34
3036     // More sophisticated tests for instruction skipper
3037     static bool arch_insn_skipper_tests()
3038     {
3039     #if (defined(i386) || defined(__i386__)) || defined(__x86_64__)
3040     static const unsigned char code[] = {
3041     0x8a, 0x00, // mov (%eax),%al
3042     0x8a, 0x2c, 0x18, // mov (%eax,%ebx,1),%ch
3043     0x88, 0x20, // mov %ah,(%eax)
3044     0x88, 0x08, // mov %cl,(%eax)
3045     0x66, 0x8b, 0x00, // mov (%eax),%ax
3046     0x66, 0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%cx
3047     0x66, 0x89, 0x00, // mov %ax,(%eax)
3048     0x66, 0x89, 0x0c, 0x18, // mov %cx,(%eax,%ebx,1)
3049     0x8b, 0x00, // mov (%eax),%eax
3050     0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%ecx
3051     0x89, 0x00, // mov %eax,(%eax)
3052     0x89, 0x0c, 0x18, // mov %ecx,(%eax,%ebx,1)
3053     #if defined(__x86_64__)
3054     0x44, 0x8a, 0x00, // mov (%rax),%r8b
3055     0x44, 0x8a, 0x20, // mov (%rax),%r12b
3056     0x42, 0x8a, 0x3c, 0x10, // mov (%rax,%r10,1),%dil
3057     0x44, 0x88, 0x00, // mov %r8b,(%rax)
3058     0x44, 0x88, 0x20, // mov %r12b,(%rax)
3059     0x42, 0x88, 0x3c, 0x10, // mov %dil,(%rax,%r10,1)
3060     0x66, 0x44, 0x8b, 0x00, // mov (%rax),%r8w
3061     0x66, 0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%cx
3062     0x66, 0x44, 0x89, 0x00, // mov %r8w,(%rax)
3063     0x66, 0x42, 0x89, 0x0c, 0x10, // mov %cx,(%rax,%r10,1)
3064     0x44, 0x8b, 0x00, // mov (%rax),%r8d
3065     0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%ecx
3066     0x44, 0x89, 0x00, // mov %r8d,(%rax)
3067     0x42, 0x89, 0x0c, 0x10, // mov %ecx,(%rax,%r10,1)
3068     0x48, 0x8b, 0x08, // mov (%rax),%rcx
3069     0x4c, 0x8b, 0x18, // mov (%rax),%r11
3070     0x4a, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%rcx
3071     0x4e, 0x8b, 0x1c, 0x10, // mov (%rax,%r10,1),%r11
3072     0x48, 0x89, 0x08, // mov %rcx,(%rax)
3073     0x4c, 0x89, 0x18, // mov %r11,(%rax)
3074     0x4a, 0x89, 0x0c, 0x10, // mov %rcx,(%rax,%r10,1)
3075     0x4e, 0x89, 0x1c, 0x10, // mov %r11,(%rax,%r10,1)
3076 gbeauche 1.62 0x63, 0x47, 0x04, // movslq 4(%rdi),%eax
3077     0x48, 0x63, 0x47, 0x04, // movslq 4(%rdi),%rax
3078 gbeauche 1.34 #endif
3079     0 // end
3080     };
3081     const int N_REGS = 20;
3082     unsigned long regs[N_REGS];
3083     for (int i = 0; i < N_REGS; i++)
3084     regs[i] = i;
3085     const unsigned long start_code = (unsigned long)&code;
3086     regs[X86_REG_EIP] = start_code;
3087     while ((regs[X86_REG_EIP] - start_code) < (sizeof(code) - 1)
3088     && ix86_skip_instruction(regs))
3089     ; /* simply iterate */
3090     return (regs[X86_REG_EIP] - start_code) == (sizeof(code) - 1);
3091     #endif
3092     return true;
3093     }
3094 gbeauche 1.10 #endif
3095    
3096 gbeauche 1.1 int main(void)
3097     {
3098 gbeauche 1.4 if (vm_init() < 0)
3099 gbeauche 1.1 return 1;
3100    
3101 gbeauche 1.54 page_size = vm_get_page_size();
3102 gbeauche 1.4 if ((page = (char *)vm_acquire(page_size)) == VM_MAP_FAILED)
3103 gbeauche 1.29 return 2;
3104 gbeauche 1.4
3105 gbeauche 1.32 memset((void *)page, 0, page_size);
3106 gbeauche 1.4 if (vm_protect((char *)page, page_size, VM_PAGE_READ) < 0)
3107 gbeauche 1.29 return 3;
3108 gbeauche 1.1
3109     if (!sigsegv_install_handler(sigsegv_test_handler))
3110 gbeauche 1.29 return 4;
3111 gbeauche 1.74
3112 gbeauche 1.32 #ifdef __GNUC__
3113     b_region = &&L_b_region1;
3114     e_region = &&L_e_region1;
3115     #endif
3116 gbeauche 1.74 /* This is a really awful hack but otherwise gcc is smart enough
3117     * (or bug'ous enough?) to optimize the labels and place them
3118     * e.g. at the "main" entry point, which is wrong.
3119     */
3120     volatile int label_hack = 1;
3121     switch (label_hack) {
3122     case 1:
3123     L_b_region1:
3124     page[REF_INDEX] = REF_VALUE;
3125     if (page[REF_INDEX] != REF_VALUE)
3126     exit(20);
3127     page[REF_INDEX] = REF_VALUE;
3128     BARRIER();
3129     // fall-through
3130     case 2:
3131     L_e_region1:
3132     BARRIER();
3133     break;
3134     }
3135 gbeauche 1.32
3136 gbeauche 1.1 if (handler_called != 1)
3137 gbeauche 1.29 return 5;
3138 gbeauche 1.10
3139     #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
3140     if (!sigsegv_install_handler(sigsegv_insn_handler))
3141 gbeauche 1.29 return 6;
3142 gbeauche 1.10
3143 gbeauche 1.17 if (vm_protect((char *)page, page_size, VM_PAGE_READ | VM_PAGE_WRITE) < 0)
3144 gbeauche 1.29 return 7;
3145 gbeauche 1.10
3146     for (int i = 0; i < page_size; i++)
3147     page[i] = (i + 1) % page_size;
3148    
3149     if (vm_protect((char *)page, page_size, VM_PAGE_NOACCESS) < 0)
3150 gbeauche 1.29 return 8;
3151 gbeauche 1.10
3152     #define TEST_SKIP_INSTRUCTION(TYPE) do { \
3153 gbeauche 1.34 const unsigned long TAG = 0x12345678 | \
3154     (sizeof(long) == 8 ? 0x9abcdef0UL << 31 : 0); \
3155 gbeauche 1.10 TYPE data = *((TYPE *)(page + sizeof(TYPE))); \
3156 gbeauche 1.34 volatile unsigned long effect = data + TAG; \
3157 gbeauche 1.10 if (effect != TAG) \
3158 gbeauche 1.29 return 9; \
3159 gbeauche 1.10 } while (0)
3160    
3161 gbeauche 1.28 #ifdef __GNUC__
3162 gbeauche 1.32 b_region = &&L_b_region2;
3163     e_region = &&L_e_region2;
3164 gbeauche 1.28 #endif
3165 gbeauche 1.74 switch (label_hack) {
3166     case 1:
3167     L_b_region2:
3168     TEST_SKIP_INSTRUCTION(unsigned char);
3169     TEST_SKIP_INSTRUCTION(unsigned short);
3170     TEST_SKIP_INSTRUCTION(unsigned int);
3171     TEST_SKIP_INSTRUCTION(unsigned long);
3172     TEST_SKIP_INSTRUCTION(signed char);
3173     TEST_SKIP_INSTRUCTION(signed short);
3174     TEST_SKIP_INSTRUCTION(signed int);
3175     TEST_SKIP_INSTRUCTION(signed long);
3176     BARRIER();
3177     // fall-through
3178     case 2:
3179     L_e_region2:
3180     BARRIER();
3181     break;
3182     }
3183 gbeauche 1.34 if (!arch_insn_skipper_tests())
3184     return 20;
3185 gbeauche 1.35 #endif
3186 gbeauche 1.34
3187 gbeauche 1.4 vm_exit();
3188 gbeauche 1.1 return 0;
3189     }
3190     #endif