ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.84
Committed: 2008-01-20T17:09:34Z (16 years, 8 months ago) by gbeauche
Branch: MAIN
Changes since 1.83: +5 -6 lines
Log Message:
Add support for Windows/ia64.

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