ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.82
Committed: 2008-01-19T22:27:29Z (16 years, 10 months ago) by gbeauche
Branch: MAIN
Changes since 1.81: +75 -1 lines
Log Message:
Add support for HP-UX/ia64. It would be best to use libunwind so that to
handle stacked registers access with ease...

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