ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.85
Committed: 2008-01-20T22:24:53Z (16 years, 8 months ago) by gbeauche
Branch: MAIN
Changes since 1.84: +99 -33 lines
Log Message:
64-bit Mach exceptions support. Note that mach_exc_server() et al. must be
explicitly generated from mig. The advantage of that is to provide a "fast"
path for x86_64 on Leopard too (fault address in code[1]).

By "fast", this means +33% faster wrt. explicitly thread_get_state() but
still pretty slow (40 usec/fault). This is on par with the i386 code path though.

File Contents

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