ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.80
Committed: 2008-01-14T19:29:29Z (16 years, 9 months ago) by gbeauche
Branch: MAIN
Changes since 1.79: +32 -16 lines
Log Message:
Fix build on MacOS X Leopard.

Leopard kernel faster? This is pure marketing hype. For 32-bit applications,
Mach exception recovery is 60% slower. For 64-bit applications, this is up
to 40% faster though. In any case, MacOS X remains pretty slow wrt. Linux...

File Contents

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