ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.83
Committed: 2008-01-20T00:39:51Z (16 years, 10 months ago) by gbeauche
Branch: MAIN
Changes since 1.82: +15 -1 lines
Log Message:
HPPA support.

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