ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.86
Committed: 2009-02-11T19:23:53Z (15 years, 7 months ago) by asvitkine
Branch: MAIN
Changes since 1.85: +14 -5 lines
Log Message:
[Patch from Mike Sliczniak]

This first patch gets B2 and SS to build under Leopard and Tiger.

I tested this on a 32-bit intel 10.5.6 mac like so:

B2
./autogen.sh --disable-standalone-gui --enable-vosf --enable-sdl-video --enable-sdl-audio --enable-addressing=real --without-esd --without-gtk --without-mon --without-x

SS
./autogen.sh --disable-standalone-gui --enable-vosf -enable-sdl-video --disable-sdl-audio --enable-addressing=real --without-esd --without-gtk --without-mon --without-x --enable-jit

There is also a little tweak so that you can use sdl audio in SheepShaver when building for Mac OS X.

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