ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.81
Committed: 2008-01-19T22:25:27Z (16 years, 9 months ago) by gbeauche
Branch: MAIN
Changes since 1.80: +78 -67 lines
Log Message:
Use fixed-size integer types, especially for 64-bit quantities. HP-UX for IPF
is essentially an ILP32 platform but machine registers are 64-bit wide. Make
IA64_SET_GR() set the NaT bit at the same time as the register value.

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 gbeauche 1.81 typedef uint64_t ia64_bundle_t[2];
1230 gbeauche 1.75 #if defined(__linux__)
1231 gbeauche 1.77 // We can directly patch the slot number
1232 gbeauche 1.81 #define IA64_CAN_PATCH_IP_SLOT 1
1233 gbeauche 1.77 // Helper macros to access the machine context
1234     #define IA64_CONTEXT_TYPE struct sigcontext *
1235     #define IA64_CONTEXT scp
1236     #define IA64_GET_IP() (IA64_CONTEXT->sc_ip)
1237     #define IA64_SET_IP(V) (IA64_CONTEXT->sc_ip = (V))
1238     #define IA64_GET_PR(P) ((IA64_CONTEXT->sc_pr >> (P)) & 1)
1239     #define IA64_GET_NAT(I) ((IA64_CONTEXT->sc_nat >> (I)) & 1)
1240     #define IA64_GET_GR(R) (IA64_CONTEXT->sc_gr[(R)])
1241 gbeauche 1.81 #define _IA64_SET_GR(R,V) (IA64_CONTEXT->sc_gr[(R)] = (V))
1242     #define _IA64_SET_NAT(I,V) (IA64_CONTEXT->sc_nat = (IA64_CONTEXT->sc_nat & ~(1ull << (I))) | (((uint64_t)!!(V)) << (I)))
1243     #define IA64_SET_GR(R,V,N) (_IA64_SET_GR(R,V), _IA64_SET_NAT(R,N))
1244    
1245     // Load bundle (in little-endian)
1246     static inline void ia64_load_bundle(ia64_bundle_t bundle, uint64_t raw_ip)
1247     {
1248     uint64_t *ip = (uint64_t *)(raw_ip & ~3ull);
1249     bundle[0] = ip[0];
1250     bundle[1] = ip[1];
1251     }
1252 gbeauche 1.75 #endif
1253    
1254     // Instruction operations
1255     enum {
1256     IA64_INST_UNKNOWN = 0,
1257     IA64_INST_LD1, // ld1 op0=[op1]
1258     IA64_INST_LD1_UPDATE, // ld1 op0=[op1],op2
1259     IA64_INST_LD2, // ld2 op0=[op1]
1260     IA64_INST_LD2_UPDATE, // ld2 op0=[op1],op2
1261     IA64_INST_LD4, // ld4 op0=[op1]
1262     IA64_INST_LD4_UPDATE, // ld4 op0=[op1],op2
1263     IA64_INST_LD8, // ld8 op0=[op1]
1264     IA64_INST_LD8_UPDATE, // ld8 op0=[op1],op2
1265     IA64_INST_ST1, // st1 [op0]=op1
1266     IA64_INST_ST1_UPDATE, // st1 [op0]=op1,op2
1267     IA64_INST_ST2, // st2 [op0]=op1
1268     IA64_INST_ST2_UPDATE, // st2 [op0]=op1,op2
1269     IA64_INST_ST4, // st4 [op0]=op1
1270     IA64_INST_ST4_UPDATE, // st4 [op0]=op1,op2
1271     IA64_INST_ST8, // st8 [op0]=op1
1272     IA64_INST_ST8_UPDATE, // st8 [op0]=op1,op2
1273     IA64_INST_ADD, // add op0=op1,op2,op3
1274     IA64_INST_SUB, // sub op0=op1,op2,op3
1275     IA64_INST_SHLADD, // shladd op0=op1,op3,op2
1276     IA64_INST_AND, // and op0=op1,op2
1277     IA64_INST_ANDCM, // andcm op0=op1,op2
1278     IA64_INST_OR, // or op0=op1,op2
1279     IA64_INST_XOR, // xor op0=op1,op2
1280     IA64_INST_SXT1, // sxt1 op0=op1
1281     IA64_INST_SXT2, // sxt2 op0=op1
1282     IA64_INST_SXT4, // sxt4 op0=op1
1283     IA64_INST_ZXT1, // zxt1 op0=op1
1284     IA64_INST_ZXT2, // zxt2 op0=op1
1285     IA64_INST_ZXT4, // zxt4 op0=op1
1286     IA64_INST_NOP // nop op0
1287     };
1288    
1289     const int IA64_N_OPERANDS = 4;
1290    
1291     // Decoded operand type
1292     struct ia64_operand_t {
1293 gbeauche 1.81 uint8_t commit; // commit result of operation to register file?
1294     uint8_t valid; // XXX: not really used, can be removed (debug)
1295     int8_t index; // index of GPR, or -1 if immediate value
1296     uint8_t nat; // NaT state before operation
1297     uint64_t value; // register contents or immediate value
1298 gbeauche 1.75 };
1299    
1300     // Decoded instruction type
1301     struct ia64_instruction_t {
1302 gbeauche 1.81 uint8_t mnemo; // operation to perform
1303     uint8_t pred; // predicate register to check
1304     uint8_t no_memory; // used to emulated main fault instruction
1305     uint64_t inst; // the raw instruction bits (41-bit wide)
1306 gbeauche 1.75 ia64_operand_t operands[IA64_N_OPERANDS];
1307     };
1308    
1309     // Get immediate sign-bit
1310 gbeauche 1.81 static inline int ia64_inst_get_sbit(uint64_t inst)
1311 gbeauche 1.75 {
1312     return (inst >> 36) & 1;
1313     }
1314    
1315     // Get 8-bit immediate value (A3, A8, I27, M30)
1316 gbeauche 1.81 static inline uint64_t ia64_inst_get_imm8(uint64_t inst)
1317 gbeauche 1.75 {
1318 gbeauche 1.81 uint64_t value = (inst >> 13) & 0x7full;
1319 gbeauche 1.75 if (ia64_inst_get_sbit(inst))
1320 gbeauche 1.81 value |= ~0x7full;
1321 gbeauche 1.75 return value;
1322     }
1323    
1324     // Get 9-bit immediate value (M3)
1325 gbeauche 1.81 static inline uint64_t ia64_inst_get_imm9b(uint64_t inst)
1326 gbeauche 1.75 {
1327 gbeauche 1.81 uint64_t value = (((inst >> 27) & 1) << 7) | ((inst >> 13) & 0x7f);
1328 gbeauche 1.75 if (ia64_inst_get_sbit(inst))
1329 gbeauche 1.81 value |= ~0xffull;
1330 gbeauche 1.75 return value;
1331     }
1332    
1333     // Get 9-bit immediate value (M5)
1334 gbeauche 1.81 static inline uint64_t ia64_inst_get_imm9a(uint64_t inst)
1335 gbeauche 1.75 {
1336 gbeauche 1.81 uint64_t value = (((inst >> 27) & 1) << 7) | ((inst >> 6) & 0x7f);
1337 gbeauche 1.75 if (ia64_inst_get_sbit(inst))
1338 gbeauche 1.81 value |= ~0xffull;
1339 gbeauche 1.75 return value;
1340     }
1341    
1342     // Get 14-bit immediate value (A4)
1343 gbeauche 1.81 static inline uint64_t ia64_inst_get_imm14(uint64_t inst)
1344 gbeauche 1.75 {
1345 gbeauche 1.81 uint64_t value = (((inst >> 27) & 0x3f) << 7) | (inst & 0x7f);
1346 gbeauche 1.75 if (ia64_inst_get_sbit(inst))
1347 gbeauche 1.81 value |= ~0x1ffull;
1348 gbeauche 1.75 return value;
1349     }
1350    
1351     // Get 22-bit immediate value (A5)
1352 gbeauche 1.81 static inline uint64_t ia64_inst_get_imm22(uint64_t inst)
1353 gbeauche 1.75 {
1354 gbeauche 1.81 uint64_t value = ((((inst >> 22) & 0x1f) << 16) |
1355     (((inst >> 27) & 0x1ff) << 7) |
1356     (inst & 0x7f));
1357 gbeauche 1.75 if (ia64_inst_get_sbit(inst))
1358 gbeauche 1.81 value |= ~0x1fffffull;
1359 gbeauche 1.75 return value;
1360     }
1361    
1362     // Get 21-bit immediate value (I19)
1363 gbeauche 1.81 static inline uint64_t ia64_inst_get_imm21(uint64_t inst)
1364 gbeauche 1.75 {
1365     return (((inst >> 36) & 1) << 20) | ((inst >> 6) & 0xfffff);
1366     }
1367    
1368     // Get 2-bit count value (A2)
1369 gbeauche 1.81 static inline int ia64_inst_get_count2(uint64_t inst)
1370 gbeauche 1.75 {
1371     return (inst >> 27) & 0x3;
1372     }
1373    
1374     // Get bundle template
1375 gbeauche 1.81 static inline unsigned int ia64_get_template(uint64_t ip)
1376 gbeauche 1.75 {
1377 gbeauche 1.81 ia64_bundle_t bundle;
1378     ia64_load_bundle(bundle, ip);
1379     return bundle[0] & 0x1f;
1380 gbeauche 1.75 }
1381    
1382     // Get specified instruction in bundle
1383 gbeauche 1.81 static uint64_t ia64_get_instruction(uint64_t ip, int slot)
1384 gbeauche 1.75 {
1385 gbeauche 1.81 uint64_t inst;
1386     ia64_bundle_t bundle;
1387     ia64_load_bundle(bundle, ip);
1388 gbeauche 1.75 #if DEBUG
1389 gbeauche 1.81 printf("Bundle: %016llx%016llx\n", bundle[1], bundle[0]);
1390 gbeauche 1.75 #endif
1391    
1392     switch (slot) {
1393     case 0:
1394 gbeauche 1.81 inst = (bundle[0] >> 5) & 0x1ffffffffffull;
1395 gbeauche 1.75 break;
1396     case 1:
1397 gbeauche 1.81 inst = ((bundle[1] & 0x7fffffull) << 18) | ((bundle[0] >> 46) & 0x3ffffull);
1398 gbeauche 1.75 break;
1399     case 2:
1400 gbeauche 1.81 inst = (bundle[1] >> 23) & 0x1ffffffffffull;
1401 gbeauche 1.75 break;
1402     case 3:
1403     fprintf(stderr, "ERROR: ia64_get_instruction(), invalid slot number %d\n", slot);
1404     abort();
1405     break;
1406     }
1407    
1408     #if DEBUG
1409 gbeauche 1.81 printf(" Instruction %d: 0x%016llx\n", slot, inst);
1410 gbeauche 1.75 #endif
1411     return inst;
1412     }
1413    
1414     // Decode group 0 instructions
1415 gbeauche 1.77 static bool ia64_decode_instruction_0(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1416 gbeauche 1.75 {
1417     const int r1 = (inst->inst >> 6) & 0x7f;
1418     const int r3 = (inst->inst >> 20) & 0x7f;
1419    
1420     const int x3 = (inst->inst >> 33) & 0x07;
1421     const int x6 = (inst->inst >> 27) & 0x3f;
1422     const int x2 = (inst->inst >> 31) & 0x03;
1423     const int x4 = (inst->inst >> 27) & 0x0f;
1424    
1425     if (x3 == 0) {
1426     switch (x6) {
1427     case 0x01: // nop.i (I19)
1428     inst->mnemo = IA64_INST_NOP;
1429     inst->operands[0].valid = true;
1430     inst->operands[0].index = -1;
1431     inst->operands[0].value = ia64_inst_get_imm21(inst->inst);
1432     return true;
1433     case 0x14: // sxt1 (I29)
1434     case 0x15: // sxt2 (I29)
1435     case 0x16: // sxt4 (I29)
1436     case 0x10: // zxt1 (I29)
1437     case 0x11: // zxt2 (I29)
1438     case 0x12: // zxt4 (I29)
1439     switch (x6) {
1440     case 0x14: inst->mnemo = IA64_INST_SXT1; break;
1441     case 0x15: inst->mnemo = IA64_INST_SXT2; break;
1442     case 0x16: inst->mnemo = IA64_INST_SXT4; break;
1443     case 0x10: inst->mnemo = IA64_INST_ZXT1; break;
1444     case 0x11: inst->mnemo = IA64_INST_ZXT2; break;
1445     case 0x12: inst->mnemo = IA64_INST_ZXT4; break;
1446     default: abort();
1447     }
1448     inst->operands[0].valid = true;
1449     inst->operands[0].index = r1;
1450     inst->operands[1].valid = true;
1451     inst->operands[1].index = r3;
1452     inst->operands[1].value = IA64_GET_GR(r3);
1453     inst->operands[1].nat = IA64_GET_NAT(r3);
1454     return true;
1455     }
1456     }
1457     return false;
1458     }
1459    
1460     // Decode group 4 instructions (load/store instructions)
1461 gbeauche 1.77 static bool ia64_decode_instruction_4(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1462 gbeauche 1.75 {
1463     const int r1 = (inst->inst >> 6) & 0x7f;
1464     const int r2 = (inst->inst >> 13) & 0x7f;
1465     const int r3 = (inst->inst >> 20) & 0x7f;
1466    
1467     const int m = (inst->inst >> 36) & 1;
1468     const int x = (inst->inst >> 27) & 1;
1469     const int x6 = (inst->inst >> 30) & 0x3f;
1470    
1471     switch (x6) {
1472     case 0x00:
1473     case 0x01:
1474     case 0x02:
1475     case 0x03:
1476     if (x == 0) {
1477     inst->operands[0].valid = true;
1478     inst->operands[0].index = r1;
1479     inst->operands[1].valid = true;
1480     inst->operands[1].index = r3;
1481     inst->operands[1].value = IA64_GET_GR(r3);
1482     inst->operands[1].nat = IA64_GET_NAT(r3);
1483     if (m == 0) {
1484     switch (x6) {
1485     case 0x00: inst->mnemo = IA64_INST_LD1; break;
1486     case 0x01: inst->mnemo = IA64_INST_LD2; break;
1487     case 0x02: inst->mnemo = IA64_INST_LD4; break;
1488     case 0x03: inst->mnemo = IA64_INST_LD8; break;
1489     }
1490     }
1491     else {
1492     inst->operands[2].valid = true;
1493     inst->operands[2].index = r2;
1494     inst->operands[2].value = IA64_GET_GR(r2);
1495     inst->operands[2].nat = IA64_GET_NAT(r2);
1496     switch (x6) {
1497     case 0x00: inst->mnemo = IA64_INST_LD1_UPDATE; break;
1498     case 0x01: inst->mnemo = IA64_INST_LD2_UPDATE; break;
1499     case 0x02: inst->mnemo = IA64_INST_LD4_UPDATE; break;
1500     case 0x03: inst->mnemo = IA64_INST_LD8_UPDATE; break;
1501     }
1502     }
1503     return true;
1504     }
1505     break;
1506     case 0x30:
1507     case 0x31:
1508     case 0x32:
1509     case 0x33:
1510     if (m == 0 && x == 0) {
1511     inst->operands[0].valid = true;
1512     inst->operands[0].index = r3;
1513     inst->operands[0].value = IA64_GET_GR(r3);
1514     inst->operands[0].nat = IA64_GET_NAT(r3);
1515     inst->operands[1].valid = true;
1516     inst->operands[1].index = r2;
1517     inst->operands[1].value = IA64_GET_GR(r2);
1518     inst->operands[1].nat = IA64_GET_NAT(r2);
1519     switch (x6) {
1520     case 0x30: inst->mnemo = IA64_INST_ST1; break;
1521     case 0x31: inst->mnemo = IA64_INST_ST2; break;
1522     case 0x32: inst->mnemo = IA64_INST_ST4; break;
1523     case 0x33: inst->mnemo = IA64_INST_ST8; break;
1524     }
1525     return true;
1526     }
1527     break;
1528     }
1529     return false;
1530     }
1531    
1532     // Decode group 5 instructions (load/store instructions)
1533 gbeauche 1.77 static bool ia64_decode_instruction_5(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1534 gbeauche 1.75 {
1535     const int r1 = (inst->inst >> 6) & 0x7f;
1536     const int r2 = (inst->inst >> 13) & 0x7f;
1537     const int r3 = (inst->inst >> 20) & 0x7f;
1538    
1539     const int x6 = (inst->inst >> 30) & 0x3f;
1540    
1541     switch (x6) {
1542     case 0x00:
1543     case 0x01:
1544     case 0x02:
1545     case 0x03:
1546     inst->operands[0].valid = true;
1547     inst->operands[0].index = r1;
1548     inst->operands[1].valid = true;
1549     inst->operands[1].index = r3;
1550     inst->operands[1].value = IA64_GET_GR(r3);
1551     inst->operands[1].nat = IA64_GET_NAT(r3);
1552     inst->operands[2].valid = true;
1553     inst->operands[2].index = -1;
1554     inst->operands[2].value = ia64_inst_get_imm9b(inst->inst);
1555     inst->operands[2].nat = 0;
1556     switch (x6) {
1557     case 0x00: inst->mnemo = IA64_INST_LD1_UPDATE; break;
1558     case 0x01: inst->mnemo = IA64_INST_LD2_UPDATE; break;
1559     case 0x02: inst->mnemo = IA64_INST_LD4_UPDATE; break;
1560     case 0x03: inst->mnemo = IA64_INST_LD8_UPDATE; break;
1561     }
1562     return true;
1563     case 0x30:
1564     case 0x31:
1565     case 0x32:
1566     case 0x33:
1567     inst->operands[0].valid = true;
1568     inst->operands[0].index = r3;
1569     inst->operands[0].value = IA64_GET_GR(r3);
1570     inst->operands[0].nat = IA64_GET_NAT(r3);
1571     inst->operands[1].valid = true;
1572     inst->operands[1].index = r2;
1573     inst->operands[1].value = IA64_GET_GR(r2);
1574     inst->operands[1].nat = IA64_GET_NAT(r2);
1575     inst->operands[2].valid = true;
1576     inst->operands[2].index = -1;
1577     inst->operands[2].value = ia64_inst_get_imm9a(inst->inst);
1578     inst->operands[2].nat = 0;
1579     switch (x6) {
1580     case 0x30: inst->mnemo = IA64_INST_ST1_UPDATE; break;
1581     case 0x31: inst->mnemo = IA64_INST_ST2_UPDATE; break;
1582     case 0x32: inst->mnemo = IA64_INST_ST4_UPDATE; break;
1583     case 0x33: inst->mnemo = IA64_INST_ST8_UPDATE; break;
1584     }
1585     return true;
1586     }
1587     return false;
1588     }
1589    
1590     // Decode group 8 instructions (ALU integer)
1591 gbeauche 1.77 static bool ia64_decode_instruction_8(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1592 gbeauche 1.75 {
1593     const int r1 = (inst->inst >> 6) & 0x7f;
1594     const int r2 = (inst->inst >> 13) & 0x7f;
1595     const int r3 = (inst->inst >> 20) & 0x7f;
1596    
1597     const int x2a = (inst->inst >> 34) & 0x3;
1598     const int x2b = (inst->inst >> 27) & 0x3;
1599     const int x4 = (inst->inst >> 29) & 0xf;
1600     const int ve = (inst->inst >> 33) & 0x1;
1601    
1602     // destination register (r1) is always valid in this group
1603     inst->operands[0].valid = true;
1604     inst->operands[0].index = r1;
1605    
1606     // source register (r3) is always valid in this group
1607     inst->operands[2].valid = true;
1608     inst->operands[2].index = r3;
1609     inst->operands[2].value = IA64_GET_GR(r3);
1610     inst->operands[2].nat = IA64_GET_NAT(r3);
1611    
1612     if (x2a == 0 && ve == 0) {
1613     inst->operands[1].valid = true;
1614     inst->operands[1].index = r2;
1615     inst->operands[1].value = IA64_GET_GR(r2);
1616     inst->operands[1].nat = IA64_GET_NAT(r2);
1617     switch (x4) {
1618     case 0x0: // add (A1)
1619     inst->mnemo = IA64_INST_ADD;
1620     inst->operands[3].valid = true;
1621     inst->operands[3].index = -1;
1622     inst->operands[3].value = x2b == 1;
1623     return true;
1624     case 0x1: // add (A1)
1625     inst->mnemo = IA64_INST_SUB;
1626     inst->operands[3].valid = true;
1627     inst->operands[3].index = -1;
1628     inst->operands[3].value = x2b == 0;
1629     return true;
1630     case 0x4: // shladd (A2)
1631     inst->mnemo = IA64_INST_SHLADD;
1632     inst->operands[3].valid = true;
1633     inst->operands[3].index = -1;
1634     inst->operands[3].value = ia64_inst_get_count2(inst->inst);
1635     return true;
1636     case 0x9:
1637     if (x2b == 1) {
1638     inst->mnemo = IA64_INST_SUB;
1639     inst->operands[1].index = -1;
1640     inst->operands[1].value = ia64_inst_get_imm8(inst->inst);
1641     inst->operands[1].nat = 0;
1642     return true;
1643     }
1644     break;
1645     case 0xb:
1646     inst->operands[1].index = -1;
1647     inst->operands[1].value = ia64_inst_get_imm8(inst->inst);
1648     inst->operands[1].nat = 0;
1649     // fall-through
1650     case 0x3:
1651     switch (x2b) {
1652     case 0: inst->mnemo = IA64_INST_AND; break;
1653     case 1: inst->mnemo = IA64_INST_ANDCM; break;
1654     case 2: inst->mnemo = IA64_INST_OR; break;
1655     case 3: inst->mnemo = IA64_INST_XOR; break;
1656     }
1657     return true;
1658     }
1659     }
1660     return false;
1661     }
1662    
1663     // Decode instruction
1664 gbeauche 1.77 static bool ia64_decode_instruction(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1665 gbeauche 1.75 {
1666     const int major = (inst->inst >> 37) & 0xf;
1667    
1668     inst->mnemo = IA64_INST_UNKNOWN;
1669     inst->pred = inst->inst & 0x3f;
1670     memset(&inst->operands[0], 0, sizeof(inst->operands));
1671    
1672     switch (major) {
1673 gbeauche 1.77 case 0x0: return ia64_decode_instruction_0(inst, IA64_CONTEXT);
1674     case 0x4: return ia64_decode_instruction_4(inst, IA64_CONTEXT);
1675     case 0x5: return ia64_decode_instruction_5(inst, IA64_CONTEXT);
1676     case 0x8: return ia64_decode_instruction_8(inst, IA64_CONTEXT);
1677 gbeauche 1.75 }
1678     return false;
1679     }
1680    
1681 gbeauche 1.77 static bool ia64_emulate_instruction(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1682 gbeauche 1.75 {
1683 gbeauche 1.76 // XXX: handle Register NaT Consumption fault?
1684     // XXX: this simple emulator assumes instructions in a bundle
1685     // don't depend on effects of other instructions in the same
1686     // bundle. It probably would be simpler to JIT-generate code to be
1687     // executed natively but probably more costly (inject/extract CPU state)
1688 gbeauche 1.75 if (inst->mnemo == IA64_INST_UNKNOWN)
1689     return false;
1690     if (inst->pred && !IA64_GET_PR(inst->pred))
1691     return true;
1692    
1693 gbeauche 1.81 uint8_t nat, nat2;
1694     uint64_t dst, dst2, src1, src2, src3;
1695 gbeauche 1.75
1696     switch (inst->mnemo) {
1697     case IA64_INST_NOP:
1698     break;
1699     case IA64_INST_ADD:
1700     case IA64_INST_SUB:
1701     case IA64_INST_SHLADD:
1702     src3 = inst->operands[3].value;
1703     // fall-through
1704     case IA64_INST_AND:
1705     case IA64_INST_ANDCM:
1706     case IA64_INST_OR:
1707     case IA64_INST_XOR:
1708     src1 = inst->operands[1].value;
1709     src2 = inst->operands[2].value;
1710     switch (inst->mnemo) {
1711     case IA64_INST_ADD: dst = src1 + src2 + src3; break;
1712     case IA64_INST_SUB: dst = src1 - src2 - src3; break;
1713     case IA64_INST_SHLADD: dst = (src1 << src3) + src2; break;
1714     case IA64_INST_AND: dst = src1 & src2; break;
1715     case IA64_INST_ANDCM: dst = src1 &~ src2; break;
1716     case IA64_INST_OR: dst = src1 | src2; break;
1717     case IA64_INST_XOR: dst = src1 ^ src2; break;
1718     }
1719     inst->operands[0].commit = true;
1720     inst->operands[0].value = dst;
1721     inst->operands[0].nat = inst->operands[1].nat | inst->operands[2].nat;
1722     break;
1723     case IA64_INST_SXT1:
1724     case IA64_INST_SXT2:
1725     case IA64_INST_SXT4:
1726     case IA64_INST_ZXT1:
1727     case IA64_INST_ZXT2:
1728     case IA64_INST_ZXT4:
1729     src1 = inst->operands[1].value;
1730     switch (inst->mnemo) {
1731 gbeauche 1.81 case IA64_INST_SXT1: dst = (int64_t)(int8_t)src1; break;
1732     case IA64_INST_SXT2: dst = (int64_t)(int16_t)src1; break;
1733     case IA64_INST_SXT4: dst = (int64_t)(int32_t)src1; break;
1734     case IA64_INST_ZXT1: dst = (uint8_t)src1; break;
1735     case IA64_INST_ZXT2: dst = (uint16_t)src1; break;
1736     case IA64_INST_ZXT4: dst = (uint32_t)src1; break;
1737 gbeauche 1.75 }
1738     inst->operands[0].commit = true;
1739     inst->operands[0].value = dst;
1740     inst->operands[0].nat = inst->operands[1].nat;
1741     break;
1742     case IA64_INST_LD1_UPDATE:
1743     case IA64_INST_LD2_UPDATE:
1744     case IA64_INST_LD4_UPDATE:
1745     case IA64_INST_LD8_UPDATE:
1746     inst->operands[1].commit = true;
1747     dst2 = inst->operands[1].value + inst->operands[2].value;
1748     nat2 = inst->operands[2].nat ? inst->operands[2].nat : 0;
1749     // fall-through
1750     case IA64_INST_LD1:
1751     case IA64_INST_LD2:
1752     case IA64_INST_LD4:
1753     case IA64_INST_LD8:
1754     src1 = inst->operands[1].value;
1755     if (inst->no_memory)
1756     dst = 0;
1757     else {
1758     switch (inst->mnemo) {
1759 gbeauche 1.81 case IA64_INST_LD1: case IA64_INST_LD1_UPDATE: dst = *((uint8_t *)src1); break;
1760     case IA64_INST_LD2: case IA64_INST_LD2_UPDATE: dst = *((uint16_t *)src1); break;
1761     case IA64_INST_LD4: case IA64_INST_LD4_UPDATE: dst = *((uint32_t *)src1); break;
1762     case IA64_INST_LD8: case IA64_INST_LD8_UPDATE: dst = *((uint64_t *)src1); break;
1763 gbeauche 1.75 }
1764     }
1765     inst->operands[0].commit = true;
1766     inst->operands[0].value = dst;
1767     inst->operands[0].nat = 0;
1768     inst->operands[1].value = dst2;
1769     inst->operands[1].nat = nat2;
1770     break;
1771     case IA64_INST_ST1_UPDATE:
1772     case IA64_INST_ST2_UPDATE:
1773     case IA64_INST_ST4_UPDATE:
1774     case IA64_INST_ST8_UPDATE:
1775     inst->operands[0].commit = 0;
1776     dst2 = inst->operands[0].value + inst->operands[2].value;
1777     nat2 = inst->operands[2].nat ? inst->operands[2].nat : 0;
1778     // fall-through
1779     case IA64_INST_ST1:
1780     case IA64_INST_ST2:
1781     case IA64_INST_ST4:
1782     case IA64_INST_ST8:
1783     dst = inst->operands[0].value;
1784     src1 = inst->operands[1].value;
1785     if (!inst->no_memory) {
1786     switch (inst->mnemo) {
1787 gbeauche 1.81 case IA64_INST_ST1: case IA64_INST_ST1_UPDATE: *((uint8_t *)dst) = src1; break;
1788     case IA64_INST_ST2: case IA64_INST_ST2_UPDATE: *((uint16_t *)dst) = src1; break;
1789     case IA64_INST_ST4: case IA64_INST_ST4_UPDATE: *((uint32_t *)dst) = src1; break;
1790     case IA64_INST_ST8: case IA64_INST_ST8_UPDATE: *((uint64_t *)dst) = src1; break;
1791 gbeauche 1.75 }
1792     }
1793     inst->operands[0].value = dst2;
1794     inst->operands[0].nat = nat2;
1795     break;
1796     default:
1797     return false;
1798     }
1799    
1800     for (int i = 0; i < IA64_N_OPERANDS; i++) {
1801     ia64_operand_t const & op = inst->operands[i];
1802     if (!op.commit)
1803     continue;
1804     if (op.index == -1)
1805     return false; // XXX: internal error
1806 gbeauche 1.81 IA64_SET_GR(op.index, op.value, op.nat);
1807 gbeauche 1.75 }
1808     return true;
1809     }
1810    
1811 gbeauche 1.81 static bool ia64_emulate_instruction(uint64_t raw_inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1812 gbeauche 1.75 {
1813     ia64_instruction_t inst;
1814     memset(&inst, 0, sizeof(inst));
1815     inst.inst = raw_inst;
1816 gbeauche 1.77 if (!ia64_decode_instruction(&inst, IA64_CONTEXT))
1817 gbeauche 1.75 return false;
1818 gbeauche 1.77 return ia64_emulate_instruction(&inst, IA64_CONTEXT);
1819 gbeauche 1.75 }
1820    
1821 gbeauche 1.77 static bool ia64_skip_instruction(IA64_CONTEXT_TYPE IA64_CONTEXT)
1822 gbeauche 1.75 {
1823 gbeauche 1.81 uint64_t ip = IA64_GET_IP();
1824 gbeauche 1.75 #if DEBUG
1825 gbeauche 1.81 printf("IP: 0x%016llx\n", ip);
1826 gbeauche 1.75 #if 0
1827     printf(" Template 0x%02x\n", ia64_get_template(ip));
1828     ia64_get_instruction(ip, 0);
1829     ia64_get_instruction(ip, 1);
1830     ia64_get_instruction(ip, 2);
1831     #endif
1832     #endif
1833    
1834     // Select which decode switch to use
1835     ia64_instruction_t inst;
1836     inst.inst = ia64_get_instruction(ip, ip & 3);
1837 gbeauche 1.77 if (!ia64_decode_instruction(&inst, IA64_CONTEXT)) {
1838 gbeauche 1.75 fprintf(stderr, "ERROR: ia64_skip_instruction(): could not decode instruction\n");
1839     return false;
1840     }
1841    
1842     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1843     transfer_size_t transfer_size = SIZE_UNKNOWN;
1844    
1845     switch (inst.mnemo) {
1846     case IA64_INST_LD1:
1847     case IA64_INST_LD2:
1848     case IA64_INST_LD4:
1849     case IA64_INST_LD8:
1850     case IA64_INST_LD1_UPDATE:
1851     case IA64_INST_LD2_UPDATE:
1852     case IA64_INST_LD4_UPDATE:
1853     case IA64_INST_LD8_UPDATE:
1854     transfer_type = SIGSEGV_TRANSFER_LOAD;
1855     break;
1856     case IA64_INST_ST1:
1857     case IA64_INST_ST2:
1858     case IA64_INST_ST4:
1859     case IA64_INST_ST8:
1860     case IA64_INST_ST1_UPDATE:
1861     case IA64_INST_ST2_UPDATE:
1862     case IA64_INST_ST4_UPDATE:
1863     case IA64_INST_ST8_UPDATE:
1864     transfer_type = SIGSEGV_TRANSFER_STORE;
1865     break;
1866     }
1867    
1868     if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1869     // Unknown machine code, let it crash. Then patch the decoder
1870     fprintf(stderr, "ERROR: ia64_skip_instruction(): not a load/store instruction\n");
1871     return false;
1872     }
1873    
1874     switch (inst.mnemo) {
1875     case IA64_INST_LD1:
1876     case IA64_INST_LD1_UPDATE:
1877     case IA64_INST_ST1:
1878     case IA64_INST_ST1_UPDATE:
1879     transfer_size = SIZE_BYTE;
1880     break;
1881     case IA64_INST_LD2:
1882     case IA64_INST_LD2_UPDATE:
1883     case IA64_INST_ST2:
1884     case IA64_INST_ST2_UPDATE:
1885     transfer_size = SIZE_WORD;
1886     break;
1887     case IA64_INST_LD4:
1888     case IA64_INST_LD4_UPDATE:
1889     case IA64_INST_ST4:
1890     case IA64_INST_ST4_UPDATE:
1891     transfer_size = SIZE_LONG;
1892     break;
1893     case IA64_INST_LD8:
1894     case IA64_INST_LD8_UPDATE:
1895     case IA64_INST_ST8:
1896     case IA64_INST_ST8_UPDATE:
1897     transfer_size = SIZE_QUAD;
1898     break;
1899     }
1900    
1901     if (transfer_size == SIZE_UNKNOWN) {
1902     // Unknown machine code, let it crash. Then patch the decoder
1903     fprintf(stderr, "ERROR: ia64_skip_instruction(): unknown transfer size\n");
1904     return false;
1905     }
1906    
1907     inst.no_memory = true;
1908 gbeauche 1.77 if (!ia64_emulate_instruction(&inst, IA64_CONTEXT)) {
1909 gbeauche 1.75 fprintf(stderr, "ERROR: ia64_skip_instruction(): could not emulate fault instruction\n");
1910     return false;
1911     }
1912    
1913     int slot = ip & 3;
1914     bool emulate_next = false;
1915     switch (slot) {
1916     case 0:
1917     switch (ia64_get_template(ip)) {
1918     case 0x2: // MI;I
1919     case 0x3: // MI;I;
1920     emulate_next = true;
1921     slot = 2;
1922     break;
1923     case 0xa: // M;MI
1924     case 0xb: // M;MI;
1925     emulate_next = true;
1926     slot = 1;
1927     break;
1928     }
1929     break;
1930     }
1931 gbeauche 1.77 if (emulate_next && !IA64_CAN_PATCH_IP_SLOT) {
1932 gbeauche 1.75 while (slot < 3) {
1933 gbeauche 1.77 if (!ia64_emulate_instruction(ia64_get_instruction(ip, slot), IA64_CONTEXT)) {
1934 gbeauche 1.75 fprintf(stderr, "ERROR: ia64_skip_instruction(): could not emulate instruction\n");
1935     return false;
1936     }
1937     ++slot;
1938     }
1939     }
1940    
1941 gbeauche 1.77 #if IA64_CAN_PATCH_IP_SLOT
1942     if ((slot = ip & 3) < 2)
1943 gbeauche 1.81 IA64_SET_IP((ip & ~3ull) + (slot + 1));
1944 gbeauche 1.77 else
1945     #endif
1946 gbeauche 1.81 IA64_SET_IP((ip & ~3ull) + 16);
1947 gbeauche 1.75 #if DEBUG
1948 gbeauche 1.81 printf("IP: 0x%016llx\n", IA64_GET_IP());
1949 gbeauche 1.75 #endif
1950     return true;
1951     }
1952     #endif
1953    
1954 gbeauche 1.13 // Decode and skip PPC instruction
1955 gbeauche 1.69 #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__))
1956 gbeauche 1.49 static bool powerpc_skip_instruction(unsigned long * nip_p, unsigned long * regs)
1957 gbeauche 1.13 {
1958 gbeauche 1.14 instruction_t instr;
1959     powerpc_decode_instruction(&instr, *nip_p, regs);
1960 gbeauche 1.13
1961 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1962 gbeauche 1.13 // Unknown machine code, let it crash. Then patch the decoder
1963     return false;
1964     }
1965    
1966     #if DEBUG
1967 gbeauche 1.14 printf("%08x: %s %s access", *nip_p,
1968 gbeauche 1.49 instr.transfer_size == SIZE_BYTE ? "byte" :
1969     instr.transfer_size == SIZE_WORD ? "word" :
1970     instr.transfer_size == SIZE_LONG ? "long" : "quad",
1971 gbeauche 1.22 instr.transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
1972 gbeauche 1.14
1973     if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
1974     printf(" r%d (ra = %08x)\n", instr.ra, instr.addr);
1975 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
1976 gbeauche 1.14 printf(" r%d (rd = 0)\n", instr.rd);
1977     #endif
1978    
1979     if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
1980     regs[instr.ra] = instr.addr;
1981 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
1982 gbeauche 1.14 regs[instr.rd] = 0;
1983 gbeauche 1.13
1984 gbeauche 1.14 *nip_p += 4;
1985 gbeauche 1.10 return true;
1986 gbeauche 1.38 }
1987     #endif
1988    
1989     // Decode and skip MIPS instruction
1990     #if (defined(mips) || defined(__mips))
1991 gbeauche 1.65 static bool mips_skip_instruction(greg_t * pc_p, greg_t * regs)
1992 gbeauche 1.38 {
1993 gbeauche 1.65 unsigned int * epc = (unsigned int *)(unsigned long)*pc_p;
1994 gbeauche 1.38
1995     if (epc == 0)
1996     return false;
1997    
1998     #if DEBUG
1999     printf("IP: %p [%08x]\n", epc, epc[0]);
2000     #endif
2001    
2002     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
2003     transfer_size_t transfer_size = SIZE_LONG;
2004     int direction = 0;
2005    
2006     const unsigned int opcode = epc[0];
2007     switch (opcode >> 26) {
2008     case 32: // Load Byte
2009     case 36: // Load Byte Unsigned
2010     transfer_type = SIGSEGV_TRANSFER_LOAD;
2011     transfer_size = SIZE_BYTE;
2012     break;
2013     case 33: // Load Halfword
2014     case 37: // Load Halfword Unsigned
2015     transfer_type = SIGSEGV_TRANSFER_LOAD;
2016     transfer_size = SIZE_WORD;
2017     break;
2018     case 35: // Load Word
2019     case 39: // Load Word Unsigned
2020     transfer_type = SIGSEGV_TRANSFER_LOAD;
2021     transfer_size = SIZE_LONG;
2022     break;
2023     case 34: // Load Word Left
2024     transfer_type = SIGSEGV_TRANSFER_LOAD;
2025     transfer_size = SIZE_LONG;
2026     direction = -1;
2027     break;
2028     case 38: // Load Word Right
2029     transfer_type = SIGSEGV_TRANSFER_LOAD;
2030     transfer_size = SIZE_LONG;
2031     direction = 1;
2032     break;
2033     case 55: // Load Doubleword
2034     transfer_type = SIGSEGV_TRANSFER_LOAD;
2035     transfer_size = SIZE_QUAD;
2036     break;
2037     case 26: // Load Doubleword Left
2038     transfer_type = SIGSEGV_TRANSFER_LOAD;
2039     transfer_size = SIZE_QUAD;
2040     direction = -1;
2041     break;
2042     case 27: // Load Doubleword Right
2043     transfer_type = SIGSEGV_TRANSFER_LOAD;
2044     transfer_size = SIZE_QUAD;
2045     direction = 1;
2046     break;
2047     case 40: // Store Byte
2048     transfer_type = SIGSEGV_TRANSFER_STORE;
2049     transfer_size = SIZE_BYTE;
2050     break;
2051     case 41: // Store Halfword
2052     transfer_type = SIGSEGV_TRANSFER_STORE;
2053     transfer_size = SIZE_WORD;
2054     break;
2055     case 43: // Store Word
2056     case 42: // Store Word Left
2057     case 46: // Store Word Right
2058     transfer_type = SIGSEGV_TRANSFER_STORE;
2059     transfer_size = SIZE_LONG;
2060     break;
2061     case 63: // Store Doubleword
2062     case 44: // Store Doubleword Left
2063     case 45: // Store Doubleword Right
2064     transfer_type = SIGSEGV_TRANSFER_STORE;
2065     transfer_size = SIZE_QUAD;
2066     break;
2067     /* Misc instructions unlikely to be used within CPU emulators */
2068     case 48: // Load Linked Word
2069     transfer_type = SIGSEGV_TRANSFER_LOAD;
2070     transfer_size = SIZE_LONG;
2071     break;
2072     case 52: // Load Linked Doubleword
2073     transfer_type = SIGSEGV_TRANSFER_LOAD;
2074     transfer_size = SIZE_QUAD;
2075     break;
2076     case 56: // Store Conditional Word
2077     transfer_type = SIGSEGV_TRANSFER_STORE;
2078     transfer_size = SIZE_LONG;
2079     break;
2080     case 60: // Store Conditional Doubleword
2081     transfer_type = SIGSEGV_TRANSFER_STORE;
2082     transfer_size = SIZE_QUAD;
2083     break;
2084     }
2085    
2086     if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
2087     // Unknown machine code, let it crash. Then patch the decoder
2088     return false;
2089     }
2090    
2091     // Zero target register in case of a load operation
2092     const int reg = (opcode >> 16) & 0x1f;
2093     if (transfer_type == SIGSEGV_TRANSFER_LOAD) {
2094     if (direction == 0)
2095     regs[reg] = 0;
2096     else {
2097     // FIXME: untested code
2098     unsigned long ea = regs[(opcode >> 21) & 0x1f];
2099     ea += (signed long)(signed int)(signed short)(opcode & 0xffff);
2100     const int offset = ea & (transfer_size == SIZE_LONG ? 3 : 7);
2101     unsigned long value;
2102     if (direction > 0) {
2103     const unsigned long rmask = ~((1L << ((offset + 1) * 8)) - 1);
2104     value = regs[reg] & rmask;
2105     }
2106     else {
2107     const unsigned long lmask = (1L << (offset * 8)) - 1;
2108     value = regs[reg] & lmask;
2109     }
2110     // restore most significant bits
2111     if (transfer_size == SIZE_LONG)
2112     value = (signed long)(signed int)value;
2113     regs[reg] = value;
2114     }
2115     }
2116    
2117     #if DEBUG
2118     #if (defined(_ABIN32) || defined(_ABI64))
2119     static const char * mips_gpr_names[32] = {
2120     "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
2121     "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
2122     "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
2123     "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
2124     };
2125     #else
2126     static const char * mips_gpr_names[32] = {
2127     "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
2128     "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
2129     "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
2130     "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
2131     };
2132     #endif
2133     printf("%s %s register %s\n",
2134     transfer_size == SIZE_BYTE ? "byte" :
2135     transfer_size == SIZE_WORD ? "word" :
2136     transfer_size == SIZE_LONG ? "long" :
2137     transfer_size == SIZE_QUAD ? "quad" : "unknown",
2138     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
2139     mips_gpr_names[reg]);
2140     #endif
2141    
2142 gbeauche 1.65 *pc_p += 4;
2143 gbeauche 1.40 return true;
2144     }
2145     #endif
2146    
2147     // Decode and skip SPARC instruction
2148     #if (defined(sparc) || defined(__sparc__))
2149     enum {
2150     #if (defined(__sun__))
2151     SPARC_REG_G1 = REG_G1,
2152     SPARC_REG_O0 = REG_O0,
2153     SPARC_REG_PC = REG_PC,
2154 gbeauche 1.59 SPARC_REG_nPC = REG_nPC
2155 gbeauche 1.40 #endif
2156     };
2157     static bool sparc_skip_instruction(unsigned long * regs, gwindows_t * gwins, struct rwindow * rwin)
2158     {
2159     unsigned int * pc = (unsigned int *)regs[SPARC_REG_PC];
2160    
2161     if (pc == 0)
2162     return false;
2163    
2164     #if DEBUG
2165     printf("IP: %p [%08x]\n", pc, pc[0]);
2166     #endif
2167    
2168     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
2169     transfer_size_t transfer_size = SIZE_LONG;
2170     bool register_pair = false;
2171    
2172     const unsigned int opcode = pc[0];
2173     if ((opcode >> 30) != 3)
2174     return false;
2175     switch ((opcode >> 19) & 0x3f) {
2176     case 9: // Load Signed Byte
2177     case 1: // Load Unsigned Byte
2178     transfer_type = SIGSEGV_TRANSFER_LOAD;
2179     transfer_size = SIZE_BYTE;
2180     break;
2181     case 10:// Load Signed Halfword
2182     case 2: // Load Unsigned Word
2183     transfer_type = SIGSEGV_TRANSFER_LOAD;
2184     transfer_size = SIZE_WORD;
2185     break;
2186     case 8: // Load Word
2187     case 0: // Load Unsigned Word
2188     transfer_type = SIGSEGV_TRANSFER_LOAD;
2189     transfer_size = SIZE_LONG;
2190     break;
2191     case 11:// Load Extended Word
2192     transfer_type = SIGSEGV_TRANSFER_LOAD;
2193     transfer_size = SIZE_QUAD;
2194     break;
2195     case 3: // Load Doubleword
2196     transfer_type = SIGSEGV_TRANSFER_LOAD;
2197     transfer_size = SIZE_LONG;
2198     register_pair = true;
2199     break;
2200     case 5: // Store Byte
2201     transfer_type = SIGSEGV_TRANSFER_STORE;
2202     transfer_size = SIZE_BYTE;
2203     break;
2204     case 6: // Store Halfword
2205     transfer_type = SIGSEGV_TRANSFER_STORE;
2206     transfer_size = SIZE_WORD;
2207     break;
2208     case 4: // Store Word
2209     transfer_type = SIGSEGV_TRANSFER_STORE;
2210     transfer_size = SIZE_LONG;
2211     break;
2212     case 14:// Store Extended Word
2213     transfer_type = SIGSEGV_TRANSFER_STORE;
2214     transfer_size = SIZE_QUAD;
2215     break;
2216     case 7: // Store Doubleword
2217     transfer_type = SIGSEGV_TRANSFER_STORE;
2218 gbeauche 1.58 transfer_size = SIZE_LONG;
2219 gbeauche 1.40 register_pair = true;
2220     break;
2221     }
2222    
2223     if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
2224     // Unknown machine code, let it crash. Then patch the decoder
2225     return false;
2226     }
2227    
2228 gbeauche 1.58 const int reg = (opcode >> 25) & 0x1f;
2229    
2230     #if DEBUG
2231     static const char * reg_names[] = {
2232     "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
2233     "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
2234     "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
2235     "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"
2236     };
2237     printf("%s %s register %s\n",
2238     transfer_size == SIZE_BYTE ? "byte" :
2239     transfer_size == SIZE_WORD ? "word" :
2240     transfer_size == SIZE_LONG ? "long" :
2241     transfer_size == SIZE_QUAD ? "quad" : "unknown",
2242     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
2243     reg_names[reg]);
2244     #endif
2245    
2246 gbeauche 1.40 // Zero target register in case of a load operation
2247     if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != 0) {
2248     // FIXME: code to handle local & input registers is not tested
2249 gbeauche 1.58 if (reg >= 1 && reg < 8) {
2250 gbeauche 1.40 // global registers
2251     regs[reg - 1 + SPARC_REG_G1] = 0;
2252     }
2253 gbeauche 1.58 else if (reg >= 8 && reg < 16) {
2254 gbeauche 1.40 // output registers
2255     regs[reg - 8 + SPARC_REG_O0] = 0;
2256     }
2257 gbeauche 1.58 else if (reg >= 16 && reg < 24) {
2258 gbeauche 1.40 // local registers (in register windows)
2259     if (gwins)
2260     gwins->wbuf->rw_local[reg - 16] = 0;
2261     else
2262     rwin->rw_local[reg - 16] = 0;
2263     }
2264     else {
2265     // input registers (in register windows)
2266     if (gwins)
2267     gwins->wbuf->rw_in[reg - 24] = 0;
2268     else
2269     rwin->rw_in[reg - 24] = 0;
2270     }
2271     }
2272    
2273     regs[SPARC_REG_PC] += 4;
2274 gbeauche 1.59 regs[SPARC_REG_nPC] += 4;
2275 gbeauche 1.38 return true;
2276 gbeauche 1.10 }
2277     #endif
2278     #endif
2279    
2280 gbeauche 1.44 // Decode and skip ARM instruction
2281     #if (defined(arm) || defined(__arm__))
2282     enum {
2283     #if (defined(__linux__))
2284     ARM_REG_PC = 15,
2285     ARM_REG_CPSR = 16
2286     #endif
2287     };
2288     static bool arm_skip_instruction(unsigned long * regs)
2289     {
2290     unsigned int * pc = (unsigned int *)regs[ARM_REG_PC];
2291    
2292     if (pc == 0)
2293     return false;
2294    
2295     #if DEBUG
2296     printf("IP: %p [%08x]\n", pc, pc[0]);
2297     #endif
2298    
2299     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
2300     transfer_size_t transfer_size = SIZE_UNKNOWN;
2301     enum { op_sdt = 1, op_sdth = 2 };
2302     int op = 0;
2303    
2304     // Handle load/store instructions only
2305     const unsigned int opcode = pc[0];
2306     switch ((opcode >> 25) & 7) {
2307     case 0: // Halfword and Signed Data Transfer (LDRH, STRH, LDRSB, LDRSH)
2308     op = op_sdth;
2309     // Determine transfer size (S/H bits)
2310     switch ((opcode >> 5) & 3) {
2311     case 0: // SWP instruction
2312     break;
2313     case 1: // Unsigned halfwords
2314     case 3: // Signed halfwords
2315     transfer_size = SIZE_WORD;
2316     break;
2317     case 2: // Signed byte
2318     transfer_size = SIZE_BYTE;
2319     break;
2320     }
2321     break;
2322     case 2:
2323     case 3: // Single Data Transfer (LDR, STR)
2324     op = op_sdt;
2325     // Determine transfer size (B bit)
2326     if (((opcode >> 22) & 1) == 1)
2327     transfer_size = SIZE_BYTE;
2328     else
2329     transfer_size = SIZE_LONG;
2330     break;
2331     default:
2332     // FIXME: support load/store mutliple?
2333     return false;
2334     }
2335    
2336     // Check for invalid transfer size (SWP instruction?)
2337     if (transfer_size == SIZE_UNKNOWN)
2338     return false;
2339    
2340     // Determine transfer type (L bit)
2341     if (((opcode >> 20) & 1) == 1)
2342     transfer_type = SIGSEGV_TRANSFER_LOAD;
2343     else
2344     transfer_type = SIGSEGV_TRANSFER_STORE;
2345    
2346     // Compute offset
2347     int offset;
2348     if (((opcode >> 25) & 1) == 0) {
2349     if (op == op_sdt)
2350     offset = opcode & 0xfff;
2351     else if (op == op_sdth) {
2352     int rm = opcode & 0xf;
2353     if (((opcode >> 22) & 1) == 0) {
2354     // register offset
2355     offset = regs[rm];
2356     }
2357     else {
2358     // immediate offset
2359     offset = ((opcode >> 4) & 0xf0) | (opcode & 0x0f);
2360     }
2361     }
2362     }
2363     else {
2364     const int rm = opcode & 0xf;
2365     const int sh = (opcode >> 7) & 0x1f;
2366     if (((opcode >> 4) & 1) == 1) {
2367     // we expect only legal load/store instructions
2368     printf("FATAL: invalid shift operand\n");
2369     return false;
2370     }
2371     const unsigned int v = regs[rm];
2372     switch ((opcode >> 5) & 3) {
2373     case 0: // logical shift left
2374     offset = sh ? v << sh : v;
2375     break;
2376     case 1: // logical shift right
2377     offset = sh ? v >> sh : 0;
2378     break;
2379     case 2: // arithmetic shift right
2380     if (sh)
2381     offset = ((signed int)v) >> sh;
2382     else
2383     offset = (v & 0x80000000) ? 0xffffffff : 0;
2384     break;
2385     case 3: // rotate right
2386     if (sh)
2387     offset = (v >> sh) | (v << (32 - sh));
2388     else
2389     offset = (v >> 1) | ((regs[ARM_REG_CPSR] << 2) & 0x80000000);
2390     break;
2391     }
2392     }
2393     if (((opcode >> 23) & 1) == 0)
2394     offset = -offset;
2395    
2396     int rd = (opcode >> 12) & 0xf;
2397     int rn = (opcode >> 16) & 0xf;
2398     #if DEBUG
2399     static const char * reg_names[] = {
2400     "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2401     "r9", "r9", "sl", "fp", "ip", "sp", "lr", "pc"
2402     };
2403     printf("%s %s register %s\n",
2404     transfer_size == SIZE_BYTE ? "byte" :
2405     transfer_size == SIZE_WORD ? "word" :
2406     transfer_size == SIZE_LONG ? "long" : "unknown",
2407     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
2408     reg_names[rd]);
2409     #endif
2410    
2411     unsigned int base = regs[rn];
2412     if (((opcode >> 24) & 1) == 1)
2413     base += offset;
2414    
2415     if (transfer_type == SIGSEGV_TRANSFER_LOAD)
2416     regs[rd] = 0;
2417    
2418     if (((opcode >> 24) & 1) == 0) // post-index addressing
2419     regs[rn] += offset;
2420     else if (((opcode >> 21) & 1) == 1) // write-back address into base
2421     regs[rn] = base;
2422    
2423     regs[ARM_REG_PC] += 4;
2424     return true;
2425     }
2426     #endif
2427    
2428    
2429 gbeauche 1.1 // Fallbacks
2430 gbeauche 1.68 #ifndef SIGSEGV_FAULT_ADDRESS_FAST
2431     #define SIGSEGV_FAULT_ADDRESS_FAST SIGSEGV_FAULT_ADDRESS
2432     #endif
2433     #ifndef SIGSEGV_FAULT_INSTRUCTION_FAST
2434     #define SIGSEGV_FAULT_INSTRUCTION_FAST SIGSEGV_FAULT_INSTRUCTION
2435     #endif
2436 gbeauche 1.1 #ifndef SIGSEGV_FAULT_INSTRUCTION
2437 gbeauche 1.67 #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_INVALID_ADDRESS
2438 gbeauche 1.1 #endif
2439 gbeauche 1.30 #ifndef SIGSEGV_FAULT_HANDLER_ARGLIST_1
2440     #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 SIGSEGV_FAULT_HANDLER_ARGLIST
2441     #endif
2442 gbeauche 1.31 #ifndef SIGSEGV_FAULT_HANDLER_INVOKE
2443 gbeauche 1.67 #define SIGSEGV_FAULT_HANDLER_INVOKE(P) sigsegv_fault_handler(P)
2444 gbeauche 1.31 #endif
2445 gbeauche 1.1
2446 gbeauche 1.2 // SIGSEGV recovery supported ?
2447     #if defined(SIGSEGV_ALL_SIGNALS) && defined(SIGSEGV_FAULT_HANDLER_ARGLIST) && defined(SIGSEGV_FAULT_ADDRESS)
2448     #define HAVE_SIGSEGV_RECOVERY
2449     #endif
2450    
2451 gbeauche 1.1
2452     /*
2453     * SIGSEGV global handler
2454     */
2455    
2456 gbeauche 1.67 struct sigsegv_info_t {
2457     sigsegv_address_t addr;
2458     sigsegv_address_t pc;
2459 gbeauche 1.68 #ifdef HAVE_MACH_EXCEPTIONS
2460     mach_port_t thread;
2461     bool has_exc_state;
2462     SIGSEGV_EXCEPTION_STATE_TYPE exc_state;
2463     mach_msg_type_number_t exc_state_count;
2464     bool has_thr_state;
2465     SIGSEGV_THREAD_STATE_TYPE thr_state;
2466     mach_msg_type_number_t thr_state_count;
2467     #endif
2468 gbeauche 1.67 };
2469    
2470 gbeauche 1.70 #ifdef HAVE_MACH_EXCEPTIONS
2471 gbeauche 1.72 static void mach_get_exception_state(sigsegv_info_t *SIP)
2472 gbeauche 1.70 {
2473 gbeauche 1.72 SIP->exc_state_count = SIGSEGV_EXCEPTION_STATE_COUNT;
2474     kern_return_t krc = thread_get_state(SIP->thread,
2475 gbeauche 1.70 SIGSEGV_EXCEPTION_STATE_FLAVOR,
2476 gbeauche 1.72 (natural_t *)&SIP->exc_state,
2477     &SIP->exc_state_count);
2478 gbeauche 1.70 MACH_CHECK_ERROR(thread_get_state, krc);
2479 gbeauche 1.72 SIP->has_exc_state = true;
2480 gbeauche 1.70 }
2481    
2482 gbeauche 1.72 static void mach_get_thread_state(sigsegv_info_t *SIP)
2483 gbeauche 1.70 {
2484 gbeauche 1.72 SIP->thr_state_count = SIGSEGV_THREAD_STATE_COUNT;
2485     kern_return_t krc = thread_get_state(SIP->thread,
2486 gbeauche 1.70 SIGSEGV_THREAD_STATE_FLAVOR,
2487 gbeauche 1.72 (natural_t *)&SIP->thr_state,
2488     &SIP->thr_state_count);
2489 gbeauche 1.70 MACH_CHECK_ERROR(thread_get_state, krc);
2490 gbeauche 1.72 SIP->has_thr_state = true;
2491 gbeauche 1.70 }
2492    
2493 gbeauche 1.72 static void mach_set_thread_state(sigsegv_info_t *SIP)
2494 gbeauche 1.70 {
2495 gbeauche 1.72 kern_return_t krc = thread_set_state(SIP->thread,
2496 gbeauche 1.70 SIGSEGV_THREAD_STATE_FLAVOR,
2497 gbeauche 1.72 (natural_t *)&SIP->thr_state,
2498     SIP->thr_state_count);
2499 gbeauche 1.70 MACH_CHECK_ERROR(thread_set_state, krc);
2500     }
2501     #endif
2502    
2503 gbeauche 1.67 // Return the address of the invalid memory reference
2504 gbeauche 1.72 sigsegv_address_t sigsegv_get_fault_address(sigsegv_info_t *SIP)
2505 gbeauche 1.67 {
2506 gbeauche 1.68 #ifdef HAVE_MACH_EXCEPTIONS
2507     static int use_fast_path = -1;
2508 gbeauche 1.72 if (use_fast_path != 1 && !SIP->has_exc_state) {
2509     mach_get_exception_state(SIP);
2510 gbeauche 1.68
2511     sigsegv_address_t addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
2512 gbeauche 1.78 if (use_fast_path < 0) {
2513     const char *machfault = getenv("SIGSEGV_MACH_FAULT");
2514     if (machfault) {
2515     if (strcmp(machfault, "fast") == 0)
2516     use_fast_path = 1;
2517     else if (strcmp(machfault, "slow") == 0)
2518     use_fast_path = 0;
2519     }
2520     if (use_fast_path < 0)
2521     use_fast_path = addr == SIP->addr;
2522     }
2523 gbeauche 1.72 SIP->addr = addr;
2524 gbeauche 1.68 }
2525     #endif
2526 gbeauche 1.72 return SIP->addr;
2527 gbeauche 1.67 }
2528    
2529     // Return the address of the instruction that caused the fault, or
2530     // SIGSEGV_INVALID_ADDRESS if we could not retrieve this information
2531 gbeauche 1.72 sigsegv_address_t sigsegv_get_fault_instruction_address(sigsegv_info_t *SIP)
2532 gbeauche 1.67 {
2533 gbeauche 1.68 #ifdef HAVE_MACH_EXCEPTIONS
2534 gbeauche 1.72 if (!SIP->has_thr_state) {
2535     mach_get_thread_state(SIP);
2536 gbeauche 1.68
2537 gbeauche 1.72 SIP->pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
2538 gbeauche 1.68 }
2539     #endif
2540 gbeauche 1.72 return SIP->pc;
2541 gbeauche 1.67 }
2542    
2543 gbeauche 1.27 // This function handles the badaccess to memory.
2544     // It is called from the signal handler or the exception handler.
2545 gbeauche 1.30 static bool handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGLIST_1)
2546 gbeauche 1.1 {
2547 gbeauche 1.72 sigsegv_info_t SI;
2548     SI.addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS_FAST;
2549     SI.pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION_FAST;
2550 gbeauche 1.56 #ifdef HAVE_MACH_EXCEPTIONS
2551 gbeauche 1.72 SI.thread = thread;
2552     SI.has_exc_state = false;
2553     SI.has_thr_state = false;
2554 gbeauche 1.56 #endif
2555 gbeauche 1.72 sigsegv_info_t * const SIP = &SI;
2556 gbeauche 1.56
2557 gbeauche 1.1 // Call user's handler and reinstall the global handler, if required
2558 gbeauche 1.72 switch (SIGSEGV_FAULT_HANDLER_INVOKE(SIP)) {
2559 gbeauche 1.24 case SIGSEGV_RETURN_SUCCESS:
2560 gbeauche 1.27 return true;
2561    
2562 gbeauche 1.10 #if HAVE_SIGSEGV_SKIP_INSTRUCTION
2563 gbeauche 1.24 case SIGSEGV_RETURN_SKIP_INSTRUCTION:
2564 gbeauche 1.27 // Call the instruction skipper with the register file
2565     // available
2566 gbeauche 1.70 #ifdef HAVE_MACH_EXCEPTIONS
2567 gbeauche 1.72 if (!SIP->has_thr_state)
2568     mach_get_thread_state(SIP);
2569 gbeauche 1.70 #endif
2570 gbeauche 1.27 if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE)) {
2571     #ifdef HAVE_MACH_EXCEPTIONS
2572     // Unlike UNIX signals where the thread state
2573     // is modified off of the stack, in Mach we
2574     // need to actually call thread_set_state to
2575     // have the register values updated.
2576 gbeauche 1.72 mach_set_thread_state(SIP);
2577 gbeauche 1.27 #endif
2578     return true;
2579     }
2580 gbeauche 1.24 break;
2581     #endif
2582 nigel 1.43 case SIGSEGV_RETURN_FAILURE:
2583 gbeauche 1.50 // We can't do anything with the fault_address, dump state?
2584     if (sigsegv_state_dumper != 0)
2585 gbeauche 1.72 sigsegv_state_dumper(SIP);
2586 gbeauche 1.50 break;
2587 gbeauche 1.10 }
2588 gbeauche 1.27
2589     return false;
2590     }
2591    
2592    
2593     /*
2594     * There are two mechanisms for handling a bad memory access,
2595     * Mach exceptions and UNIX signals. The implementation specific
2596     * code appears below. Its reponsibility is to call handle_badaccess
2597     * which is the routine that handles the fault in an implementation
2598     * agnostic manner. The implementation specific code below is then
2599     * reponsible for checking whether handle_badaccess was able
2600     * to handle the memory access error and perform any implementation
2601     * specific tasks necessary afterwards.
2602     */
2603    
2604     #ifdef HAVE_MACH_EXCEPTIONS
2605     /*
2606     * We need to forward all exceptions that we do not handle.
2607     * This is important, there are many exceptions that may be
2608     * handled by other exception handlers. For example debuggers
2609     * use exceptions and the exception hander is in another
2610     * process in such a case. (Timothy J. Wood states in his
2611     * message to the list that he based this code on that from
2612     * gdb for Darwin.)
2613     */
2614     static inline kern_return_t
2615     forward_exception(mach_port_t thread_port,
2616     mach_port_t task_port,
2617     exception_type_t exception_type,
2618     exception_data_t exception_data,
2619     mach_msg_type_number_t data_count,
2620     ExceptionPorts *oldExceptionPorts)
2621     {
2622     kern_return_t kret;
2623     unsigned int portIndex;
2624     mach_port_t port;
2625     exception_behavior_t behavior;
2626     thread_state_flavor_t flavor;
2627 gbeauche 1.57 thread_state_data_t thread_state;
2628 gbeauche 1.27 mach_msg_type_number_t thread_state_count;
2629    
2630     for (portIndex = 0; portIndex < oldExceptionPorts->maskCount; portIndex++) {
2631     if (oldExceptionPorts->masks[portIndex] & (1 << exception_type)) {
2632     // This handler wants the exception
2633     break;
2634     }
2635     }
2636    
2637     if (portIndex >= oldExceptionPorts->maskCount) {
2638     fprintf(stderr, "No handler for exception_type = %d. Not fowarding\n", exception_type);
2639     return KERN_FAILURE;
2640     }
2641    
2642     port = oldExceptionPorts->handlers[portIndex];
2643     behavior = oldExceptionPorts->behaviors[portIndex];
2644     flavor = oldExceptionPorts->flavors[portIndex];
2645    
2646 gbeauche 1.63 if (!VALID_THREAD_STATE_FLAVOR(flavor)) {
2647     fprintf(stderr, "Invalid thread_state flavor = %d. Not forwarding\n", flavor);
2648     return KERN_FAILURE;
2649     }
2650    
2651 gbeauche 1.27 /*
2652     fprintf(stderr, "forwarding exception, port = 0x%x, behaviour = %d, flavor = %d\n", port, behavior, flavor);
2653     */
2654    
2655     if (behavior != EXCEPTION_DEFAULT) {
2656     thread_state_count = THREAD_STATE_MAX;
2657 gbeauche 1.60 kret = thread_get_state (thread_port, flavor, (natural_t *)&thread_state,
2658 gbeauche 1.27 &thread_state_count);
2659     MACH_CHECK_ERROR (thread_get_state, kret);
2660     }
2661    
2662     switch (behavior) {
2663     case EXCEPTION_DEFAULT:
2664     // fprintf(stderr, "forwarding to exception_raise\n");
2665     kret = exception_raise(port, thread_port, task_port, exception_type,
2666     exception_data, data_count);
2667     MACH_CHECK_ERROR (exception_raise, kret);
2668     break;
2669     case EXCEPTION_STATE:
2670     // fprintf(stderr, "forwarding to exception_raise_state\n");
2671     kret = exception_raise_state(port, exception_type, exception_data,
2672     data_count, &flavor,
2673 gbeauche 1.60 (natural_t *)&thread_state, thread_state_count,
2674     (natural_t *)&thread_state, &thread_state_count);
2675 gbeauche 1.27 MACH_CHECK_ERROR (exception_raise_state, kret);
2676     break;
2677     case EXCEPTION_STATE_IDENTITY:
2678     // fprintf(stderr, "forwarding to exception_raise_state_identity\n");
2679     kret = exception_raise_state_identity(port, thread_port, task_port,
2680     exception_type, exception_data,
2681     data_count, &flavor,
2682 gbeauche 1.60 (natural_t *)&thread_state, thread_state_count,
2683     (natural_t *)&thread_state, &thread_state_count);
2684 gbeauche 1.27 MACH_CHECK_ERROR (exception_raise_state_identity, kret);
2685     break;
2686     default:
2687     fprintf(stderr, "forward_exception got unknown behavior\n");
2688 gbeauche 1.63 kret = KERN_FAILURE;
2689 gbeauche 1.27 break;
2690     }
2691    
2692     if (behavior != EXCEPTION_DEFAULT) {
2693 gbeauche 1.60 kret = thread_set_state (thread_port, flavor, (natural_t *)&thread_state,
2694 gbeauche 1.27 thread_state_count);
2695     MACH_CHECK_ERROR (thread_set_state, kret);
2696     }
2697    
2698 gbeauche 1.63 return kret;
2699 gbeauche 1.27 }
2700    
2701     /*
2702     * This is the code that actually handles the exception.
2703     * It is called by exc_server. For Darwin 5 Apple changed
2704     * this a bit from how this family of functions worked in
2705     * Mach. If you are familiar with that it is a little
2706     * different. The main variation that concerns us here is
2707     * that code is an array of exception specific codes and
2708     * codeCount is a count of the number of codes in the code
2709     * array. In typical Mach all exceptions have a code
2710     * and sub-code. It happens to be the case that for a
2711     * EXC_BAD_ACCESS exception the first entry is the type of
2712     * bad access that occurred and the second entry is the
2713     * faulting address so these entries correspond exactly to
2714     * how the code and sub-code are used on Mach.
2715     *
2716     * This is a MIG interface. No code in Basilisk II should
2717     * call this directley. This has to have external C
2718     * linkage because that is what exc_server expects.
2719     */
2720     kern_return_t
2721     catch_exception_raise(mach_port_t exception_port,
2722     mach_port_t thread,
2723     mach_port_t task,
2724     exception_type_t exception,
2725     exception_data_t code,
2726 gbeauche 1.66 mach_msg_type_number_t code_count)
2727 gbeauche 1.27 {
2728     kern_return_t krc;
2729    
2730 gbeauche 1.66 if (exception == EXC_BAD_ACCESS) {
2731     switch (code[0]) {
2732     case KERN_PROTECTION_FAILURE:
2733     case KERN_INVALID_ADDRESS:
2734     if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS))
2735     return KERN_SUCCESS;
2736     break;
2737     }
2738 gbeauche 1.27 }
2739    
2740     // In Mach we do not need to remove the exception handler.
2741     // If we forward the exception, eventually some exception handler
2742     // will take care of this exception.
2743 gbeauche 1.66 krc = forward_exception(thread, task, exception, code, code_count, &ports);
2744 gbeauche 1.27
2745     return krc;
2746     }
2747     #endif
2748    
2749     #ifdef HAVE_SIGSEGV_RECOVERY
2750     // Handle bad memory accesses with signal handler
2751     static void sigsegv_handler(SIGSEGV_FAULT_HANDLER_ARGLIST)
2752     {
2753     // Call handler and reinstall the global handler, if required
2754     if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS)) {
2755     #if (defined(HAVE_SIGACTION) ? defined(SIGACTION_NEED_REINSTALL) : defined(SIGNAL_NEED_REINSTALL))
2756     sigsegv_do_install_handler(sig);
2757     #endif
2758     return;
2759     }
2760 gbeauche 1.10
2761 gbeauche 1.27 // Failure: reinstall default handler for "safe" crash
2762 gbeauche 1.1 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
2763 gbeauche 1.27 SIGSEGV_ALL_SIGNALS
2764 gbeauche 1.1 #undef FAULT_HANDLER
2765     }
2766 gbeauche 1.2 #endif
2767 gbeauche 1.1
2768    
2769     /*
2770     * SIGSEGV handler initialization
2771     */
2772    
2773     #if defined(HAVE_SIGINFO_T)
2774     static bool sigsegv_do_install_handler(int sig)
2775     {
2776     // Setup SIGSEGV handler to process writes to frame buffer
2777     #ifdef HAVE_SIGACTION
2778 gbeauche 1.22 struct sigaction sigsegv_sa;
2779     sigemptyset(&sigsegv_sa.sa_mask);
2780     sigsegv_sa.sa_sigaction = sigsegv_handler;
2781     sigsegv_sa.sa_flags = SA_SIGINFO;
2782     return (sigaction(sig, &sigsegv_sa, 0) == 0);
2783 gbeauche 1.1 #else
2784     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
2785     #endif
2786     }
2787 gbeauche 1.2 #endif
2788    
2789     #if defined(HAVE_SIGCONTEXT_SUBTERFUGE)
2790 gbeauche 1.1 static bool sigsegv_do_install_handler(int sig)
2791     {
2792     // Setup SIGSEGV handler to process writes to frame buffer
2793     #ifdef HAVE_SIGACTION
2794 gbeauche 1.22 struct sigaction sigsegv_sa;
2795     sigemptyset(&sigsegv_sa.sa_mask);
2796     sigsegv_sa.sa_handler = (signal_handler)sigsegv_handler;
2797     sigsegv_sa.sa_flags = 0;
2798 gbeauche 1.1 #if !EMULATED_68K && defined(__NetBSD__)
2799 gbeauche 1.22 sigaddset(&sigsegv_sa.sa_mask, SIGALRM);
2800     sigsegv_sa.sa_flags |= SA_ONSTACK;
2801 gbeauche 1.1 #endif
2802 gbeauche 1.22 return (sigaction(sig, &sigsegv_sa, 0) == 0);
2803 gbeauche 1.1 #else
2804     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
2805     #endif
2806     }
2807     #endif
2808    
2809 gbeauche 1.27 #if defined(HAVE_MACH_EXCEPTIONS)
2810     static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
2811     {
2812     /*
2813     * Except for the exception port functions, this should be
2814     * pretty much stock Mach. If later you choose to support
2815     * other Mach's besides Darwin, just check for __MACH__
2816     * here and __APPLE__ where the actual differences are.
2817     */
2818     #if defined(__APPLE__) && defined(__MACH__)
2819     if (sigsegv_fault_handler != NULL) {
2820     sigsegv_fault_handler = handler;
2821     return true;
2822     }
2823    
2824     kern_return_t krc;
2825    
2826     // create the the exception port
2827     krc = mach_port_allocate(mach_task_self(),
2828     MACH_PORT_RIGHT_RECEIVE, &_exceptionPort);
2829     if (krc != KERN_SUCCESS) {
2830     mach_error("mach_port_allocate", krc);
2831     return false;
2832     }
2833    
2834     // add a port send right
2835     krc = mach_port_insert_right(mach_task_self(),
2836     _exceptionPort, _exceptionPort,
2837     MACH_MSG_TYPE_MAKE_SEND);
2838     if (krc != KERN_SUCCESS) {
2839     mach_error("mach_port_insert_right", krc);
2840     return false;
2841     }
2842    
2843     // get the old exception ports
2844     ports.maskCount = sizeof (ports.masks) / sizeof (ports.masks[0]);
2845     krc = thread_get_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, ports.masks,
2846     &ports.maskCount, ports.handlers, ports.behaviors, ports.flavors);
2847     if (krc != KERN_SUCCESS) {
2848     mach_error("thread_get_exception_ports", krc);
2849     return false;
2850     }
2851    
2852     // set the new exception port
2853     //
2854     // We could have used EXCEPTION_STATE_IDENTITY instead of
2855     // EXCEPTION_DEFAULT to get the thread state in the initial
2856     // message, but it turns out that in the common case this is not
2857     // neccessary. If we need it we can later ask for it from the
2858     // suspended thread.
2859     //
2860     // Even with THREAD_STATE_NONE, Darwin provides the program
2861     // counter in the thread state. The comments in the header file
2862     // seem to imply that you can count on the GPR's on an exception
2863     // as well but just to be safe I use MACHINE_THREAD_STATE because
2864     // you have to ask for all of the GPR's anyway just to get the
2865     // program counter. In any case because of update effective
2866     // address from immediate and update address from effective
2867     // addresses of ra and rb modes (as good an name as any for these
2868     // addressing modes) used in PPC instructions, you will need the
2869     // GPR state anyway.
2870     krc = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, _exceptionPort,
2871 gbeauche 1.56 EXCEPTION_DEFAULT, SIGSEGV_THREAD_STATE_FLAVOR);
2872 gbeauche 1.27 if (krc != KERN_SUCCESS) {
2873     mach_error("thread_set_exception_ports", krc);
2874     return false;
2875     }
2876    
2877     // create the exception handler thread
2878     if (pthread_create(&exc_thread, NULL, &handleExceptions, NULL) != 0) {
2879     (void)fprintf(stderr, "creation of exception thread failed\n");
2880     return false;
2881     }
2882    
2883     // do not care about the exception thread any longer, let is run standalone
2884     (void)pthread_detach(exc_thread);
2885    
2886     sigsegv_fault_handler = handler;
2887     return true;
2888     #else
2889     return false;
2890     #endif
2891     }
2892     #endif
2893    
2894 gbeauche 1.48 #ifdef HAVE_WIN32_EXCEPTIONS
2895     static LONG WINAPI main_exception_filter(EXCEPTION_POINTERS *ExceptionInfo)
2896     {
2897     if (sigsegv_fault_handler != NULL
2898     && ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION
2899     && ExceptionInfo->ExceptionRecord->NumberParameters == 2
2900     && handle_badaccess(ExceptionInfo))
2901     return EXCEPTION_CONTINUE_EXECUTION;
2902    
2903     return EXCEPTION_CONTINUE_SEARCH;
2904     }
2905    
2906     #if defined __CYGWIN__ && defined __i386__
2907     /* In Cygwin programs, SetUnhandledExceptionFilter has no effect because Cygwin
2908     installs a global exception handler. We have to dig deep in order to install
2909     our main_exception_filter. */
2910    
2911     /* Data structures for the current thread's exception handler chain.
2912     On the x86 Windows uses register fs, offset 0 to point to the current
2913     exception handler; Cygwin mucks with it, so we must do the same... :-/ */
2914    
2915     /* Magic taken from winsup/cygwin/include/exceptions.h. */
2916    
2917     struct exception_list {
2918     struct exception_list *prev;
2919     int (*handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
2920     };
2921     typedef struct exception_list exception_list;
2922    
2923     /* Magic taken from winsup/cygwin/exceptions.cc. */
2924    
2925     __asm__ (".equ __except_list,0");
2926    
2927     extern exception_list *_except_list __asm__ ("%fs:__except_list");
2928    
2929     /* For debugging. _except_list is not otherwise accessible from gdb. */
2930     static exception_list *
2931     debug_get_except_list ()
2932     {
2933     return _except_list;
2934     }
2935    
2936     /* Cygwin's original exception handler. */
2937     static int (*cygwin_exception_handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
2938    
2939     /* Our exception handler. */
2940     static int
2941     libsigsegv_exception_handler (EXCEPTION_RECORD *exception, void *frame, CONTEXT *context, void *dispatch)
2942     {
2943     EXCEPTION_POINTERS ExceptionInfo;
2944     ExceptionInfo.ExceptionRecord = exception;
2945     ExceptionInfo.ContextRecord = context;
2946     if (main_exception_filter (&ExceptionInfo) == EXCEPTION_CONTINUE_SEARCH)
2947     return cygwin_exception_handler (exception, frame, context, dispatch);
2948     else
2949     return 0;
2950     }
2951    
2952     static void
2953     do_install_main_exception_filter ()
2954     {
2955     /* We cannot insert any handler into the chain, because such handlers
2956     must lie on the stack (?). Instead, we have to replace(!) Cygwin's
2957     global exception handler. */
2958     cygwin_exception_handler = _except_list->handler;
2959     _except_list->handler = libsigsegv_exception_handler;
2960     }
2961    
2962     #else
2963    
2964     static void
2965     do_install_main_exception_filter ()
2966     {
2967     SetUnhandledExceptionFilter ((LPTOP_LEVEL_EXCEPTION_FILTER) &main_exception_filter);
2968     }
2969     #endif
2970    
2971     static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
2972     {
2973     static bool main_exception_filter_installed = false;
2974     if (!main_exception_filter_installed) {
2975     do_install_main_exception_filter();
2976     main_exception_filter_installed = true;
2977     }
2978     sigsegv_fault_handler = handler;
2979     return true;
2980     }
2981     #endif
2982    
2983 gbeauche 1.12 bool sigsegv_install_handler(sigsegv_fault_handler_t handler)
2984 gbeauche 1.1 {
2985 gbeauche 1.27 #if defined(HAVE_SIGSEGV_RECOVERY)
2986 gbeauche 1.1 bool success = true;
2987     #define FAULT_HANDLER(sig) success = success && sigsegv_do_install_handler(sig);
2988     SIGSEGV_ALL_SIGNALS
2989     #undef FAULT_HANDLER
2990 gbeauche 1.27 if (success)
2991     sigsegv_fault_handler = handler;
2992 gbeauche 1.1 return success;
2993 gbeauche 1.48 #elif defined(HAVE_MACH_EXCEPTIONS) || defined(HAVE_WIN32_EXCEPTIONS)
2994 gbeauche 1.27 return sigsegv_do_install_handler(handler);
2995 gbeauche 1.1 #else
2996     // FAIL: no siginfo_t nor sigcontext subterfuge is available
2997     return false;
2998     #endif
2999     }
3000    
3001    
3002     /*
3003     * SIGSEGV handler deinitialization
3004     */
3005    
3006     void sigsegv_deinstall_handler(void)
3007     {
3008 gbeauche 1.27 // We do nothing for Mach exceptions, the thread would need to be
3009     // suspended if not already so, and we might mess with other
3010     // exception handlers that came after we registered ours. There is
3011     // no need to remove the exception handler, in fact this function is
3012     // not called anywhere in Basilisk II.
3013 gbeauche 1.2 #ifdef HAVE_SIGSEGV_RECOVERY
3014 gbeauche 1.12 sigsegv_fault_handler = 0;
3015 gbeauche 1.1 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
3016     SIGSEGV_ALL_SIGNALS
3017     #undef FAULT_HANDLER
3018 gbeauche 1.2 #endif
3019 gbeauche 1.48 #ifdef HAVE_WIN32_EXCEPTIONS
3020     sigsegv_fault_handler = NULL;
3021     #endif
3022 gbeauche 1.1 }
3023    
3024 gbeauche 1.10
3025     /*
3026     * Set callback function when we cannot handle the fault
3027     */
3028    
3029 gbeauche 1.12 void sigsegv_set_dump_state(sigsegv_state_dumper_t handler)
3030 gbeauche 1.10 {
3031 gbeauche 1.12 sigsegv_state_dumper = handler;
3032 gbeauche 1.10 }
3033    
3034    
3035 gbeauche 1.1 /*
3036     * Test program used for configure/test
3037     */
3038    
3039 gbeauche 1.4 #ifdef CONFIGURE_TEST_SIGSEGV_RECOVERY
3040 gbeauche 1.1 #include <stdio.h>
3041     #include <stdlib.h>
3042     #include <fcntl.h>
3043 gbeauche 1.48 #ifdef HAVE_SYS_MMAN_H
3044 gbeauche 1.1 #include <sys/mman.h>
3045 gbeauche 1.48 #endif
3046 gbeauche 1.4 #include "vm_alloc.h"
3047 gbeauche 1.1
3048 gbeauche 1.32 const int REF_INDEX = 123;
3049     const int REF_VALUE = 45;
3050    
3051 gbeauche 1.79 static sigsegv_uintptr_t page_size;
3052 gbeauche 1.3 static volatile char * page = 0;
3053     static volatile int handler_called = 0;
3054 gbeauche 1.1
3055 gbeauche 1.61 /* Barriers */
3056     #ifdef __GNUC__
3057     #define BARRIER() asm volatile ("" : : : "memory")
3058     #else
3059     #define BARRIER() /* nothing */
3060     #endif
3061    
3062 gbeauche 1.32 #ifdef __GNUC__
3063     // Code range where we expect the fault to come from
3064     static void *b_region, *e_region;
3065     #endif
3066    
3067 gbeauche 1.67 static sigsegv_return_t sigsegv_test_handler(sigsegv_info_t *sip)
3068 gbeauche 1.1 {
3069 gbeauche 1.67 const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
3070     const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip);
3071 gbeauche 1.39 #if DEBUG
3072     printf("sigsegv_test_handler(%p, %p)\n", fault_address, instruction_address);
3073     printf("expected fault at %p\n", page + REF_INDEX);
3074     #ifdef __GNUC__
3075     printf("expected instruction address range: %p-%p\n", b_region, e_region);
3076     #endif
3077     #endif
3078 gbeauche 1.1 handler_called++;
3079 gbeauche 1.32 if ((fault_address - REF_INDEX) != page)
3080 gbeauche 1.29 exit(10);
3081 gbeauche 1.32 #ifdef __GNUC__
3082     // Make sure reported fault instruction address falls into
3083     // expected code range
3084 gbeauche 1.67 if (instruction_address != SIGSEGV_INVALID_ADDRESS
3085 gbeauche 1.32 && ((instruction_address < (sigsegv_address_t)b_region) ||
3086     (instruction_address >= (sigsegv_address_t)e_region)))
3087     exit(11);
3088     #endif
3089 gbeauche 1.79 if (vm_protect((char *)((sigsegv_uintptr_t)fault_address & -page_size), page_size, VM_PAGE_READ | VM_PAGE_WRITE) != 0)
3090 gbeauche 1.32 exit(12);
3091 gbeauche 1.24 return SIGSEGV_RETURN_SUCCESS;
3092 gbeauche 1.1 }
3093    
3094 gbeauche 1.10 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
3095 gbeauche 1.67 static sigsegv_return_t sigsegv_insn_handler(sigsegv_info_t *sip)
3096 gbeauche 1.10 {
3097 gbeauche 1.67 const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
3098     const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip);
3099 gbeauche 1.44 #if DEBUG
3100     printf("sigsegv_insn_handler(%p, %p)\n", fault_address, instruction_address);
3101     #endif
3102 gbeauche 1.79 if (((sigsegv_uintptr_t)fault_address - (sigsegv_uintptr_t)page) < page_size) {
3103 gbeauche 1.28 #ifdef __GNUC__
3104     // Make sure reported fault instruction address falls into
3105     // expected code range
3106 gbeauche 1.67 if (instruction_address != SIGSEGV_INVALID_ADDRESS
3107 gbeauche 1.28 && ((instruction_address < (sigsegv_address_t)b_region) ||
3108     (instruction_address >= (sigsegv_address_t)e_region)))
3109     return SIGSEGV_RETURN_FAILURE;
3110     #endif
3111 gbeauche 1.26 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
3112 gbeauche 1.28 }
3113    
3114 gbeauche 1.24 return SIGSEGV_RETURN_FAILURE;
3115 gbeauche 1.10 }
3116 gbeauche 1.34
3117     // More sophisticated tests for instruction skipper
3118     static bool arch_insn_skipper_tests()
3119     {
3120 gbeauche 1.79 #if (defined(i386) || defined(__i386__)) || (defined(__x86_64__) || defined(_M_X64))
3121 gbeauche 1.34 static const unsigned char code[] = {
3122     0x8a, 0x00, // mov (%eax),%al
3123     0x8a, 0x2c, 0x18, // mov (%eax,%ebx,1),%ch
3124     0x88, 0x20, // mov %ah,(%eax)
3125     0x88, 0x08, // mov %cl,(%eax)
3126     0x66, 0x8b, 0x00, // mov (%eax),%ax
3127     0x66, 0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%cx
3128     0x66, 0x89, 0x00, // mov %ax,(%eax)
3129     0x66, 0x89, 0x0c, 0x18, // mov %cx,(%eax,%ebx,1)
3130     0x8b, 0x00, // mov (%eax),%eax
3131     0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%ecx
3132     0x89, 0x00, // mov %eax,(%eax)
3133     0x89, 0x0c, 0x18, // mov %ecx,(%eax,%ebx,1)
3134 gbeauche 1.79 #if defined(__x86_64__) || defined(_M_X64)
3135 gbeauche 1.34 0x44, 0x8a, 0x00, // mov (%rax),%r8b
3136     0x44, 0x8a, 0x20, // mov (%rax),%r12b
3137     0x42, 0x8a, 0x3c, 0x10, // mov (%rax,%r10,1),%dil
3138     0x44, 0x88, 0x00, // mov %r8b,(%rax)
3139     0x44, 0x88, 0x20, // mov %r12b,(%rax)
3140     0x42, 0x88, 0x3c, 0x10, // mov %dil,(%rax,%r10,1)
3141     0x66, 0x44, 0x8b, 0x00, // mov (%rax),%r8w
3142     0x66, 0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%cx
3143     0x66, 0x44, 0x89, 0x00, // mov %r8w,(%rax)
3144     0x66, 0x42, 0x89, 0x0c, 0x10, // mov %cx,(%rax,%r10,1)
3145     0x44, 0x8b, 0x00, // mov (%rax),%r8d
3146     0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%ecx
3147     0x44, 0x89, 0x00, // mov %r8d,(%rax)
3148     0x42, 0x89, 0x0c, 0x10, // mov %ecx,(%rax,%r10,1)
3149     0x48, 0x8b, 0x08, // mov (%rax),%rcx
3150     0x4c, 0x8b, 0x18, // mov (%rax),%r11
3151     0x4a, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%rcx
3152     0x4e, 0x8b, 0x1c, 0x10, // mov (%rax,%r10,1),%r11
3153     0x48, 0x89, 0x08, // mov %rcx,(%rax)
3154     0x4c, 0x89, 0x18, // mov %r11,(%rax)
3155     0x4a, 0x89, 0x0c, 0x10, // mov %rcx,(%rax,%r10,1)
3156     0x4e, 0x89, 0x1c, 0x10, // mov %r11,(%rax,%r10,1)
3157 gbeauche 1.62 0x63, 0x47, 0x04, // movslq 4(%rdi),%eax
3158     0x48, 0x63, 0x47, 0x04, // movslq 4(%rdi),%rax
3159 gbeauche 1.34 #endif
3160     0 // end
3161     };
3162     const int N_REGS = 20;
3163 gbeauche 1.79 SIGSEGV_REGISTER_TYPE regs[N_REGS];
3164 gbeauche 1.34 for (int i = 0; i < N_REGS; i++)
3165     regs[i] = i;
3166 gbeauche 1.79 const sigsegv_uintptr_t start_code = (sigsegv_uintptr_t)&code;
3167 gbeauche 1.34 regs[X86_REG_EIP] = start_code;
3168     while ((regs[X86_REG_EIP] - start_code) < (sizeof(code) - 1)
3169     && ix86_skip_instruction(regs))
3170     ; /* simply iterate */
3171     return (regs[X86_REG_EIP] - start_code) == (sizeof(code) - 1);
3172     #endif
3173     return true;
3174     }
3175 gbeauche 1.10 #endif
3176    
3177 gbeauche 1.1 int main(void)
3178     {
3179 gbeauche 1.4 if (vm_init() < 0)
3180 gbeauche 1.1 return 1;
3181    
3182 gbeauche 1.54 page_size = vm_get_page_size();
3183 gbeauche 1.4 if ((page = (char *)vm_acquire(page_size)) == VM_MAP_FAILED)
3184 gbeauche 1.29 return 2;
3185 gbeauche 1.4
3186 gbeauche 1.32 memset((void *)page, 0, page_size);
3187 gbeauche 1.4 if (vm_protect((char *)page, page_size, VM_PAGE_READ) < 0)
3188 gbeauche 1.29 return 3;
3189 gbeauche 1.1
3190     if (!sigsegv_install_handler(sigsegv_test_handler))
3191 gbeauche 1.29 return 4;
3192 gbeauche 1.74
3193 gbeauche 1.32 #ifdef __GNUC__
3194     b_region = &&L_b_region1;
3195     e_region = &&L_e_region1;
3196     #endif
3197 gbeauche 1.74 /* This is a really awful hack but otherwise gcc is smart enough
3198     * (or bug'ous enough?) to optimize the labels and place them
3199     * e.g. at the "main" entry point, which is wrong.
3200     */
3201     volatile int label_hack = 1;
3202     switch (label_hack) {
3203     case 1:
3204     L_b_region1:
3205     page[REF_INDEX] = REF_VALUE;
3206     if (page[REF_INDEX] != REF_VALUE)
3207     exit(20);
3208     page[REF_INDEX] = REF_VALUE;
3209     BARRIER();
3210     // fall-through
3211     case 2:
3212     L_e_region1:
3213     BARRIER();
3214     break;
3215     }
3216 gbeauche 1.32
3217 gbeauche 1.1 if (handler_called != 1)
3218 gbeauche 1.29 return 5;
3219 gbeauche 1.10
3220     #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
3221     if (!sigsegv_install_handler(sigsegv_insn_handler))
3222 gbeauche 1.29 return 6;
3223 gbeauche 1.10
3224 gbeauche 1.17 if (vm_protect((char *)page, page_size, VM_PAGE_READ | VM_PAGE_WRITE) < 0)
3225 gbeauche 1.29 return 7;
3226 gbeauche 1.10
3227     for (int i = 0; i < page_size; i++)
3228     page[i] = (i + 1) % page_size;
3229    
3230     if (vm_protect((char *)page, page_size, VM_PAGE_NOACCESS) < 0)
3231 gbeauche 1.29 return 8;
3232 gbeauche 1.10
3233     #define TEST_SKIP_INSTRUCTION(TYPE) do { \
3234 gbeauche 1.34 const unsigned long TAG = 0x12345678 | \
3235     (sizeof(long) == 8 ? 0x9abcdef0UL << 31 : 0); \
3236 gbeauche 1.10 TYPE data = *((TYPE *)(page + sizeof(TYPE))); \
3237 gbeauche 1.34 volatile unsigned long effect = data + TAG; \
3238 gbeauche 1.10 if (effect != TAG) \
3239 gbeauche 1.29 return 9; \
3240 gbeauche 1.10 } while (0)
3241    
3242 gbeauche 1.28 #ifdef __GNUC__
3243 gbeauche 1.32 b_region = &&L_b_region2;
3244     e_region = &&L_e_region2;
3245 gbeauche 1.28 #endif
3246 gbeauche 1.74 switch (label_hack) {
3247     case 1:
3248     L_b_region2:
3249     TEST_SKIP_INSTRUCTION(unsigned char);
3250     TEST_SKIP_INSTRUCTION(unsigned short);
3251     TEST_SKIP_INSTRUCTION(unsigned int);
3252     TEST_SKIP_INSTRUCTION(unsigned long);
3253     TEST_SKIP_INSTRUCTION(signed char);
3254     TEST_SKIP_INSTRUCTION(signed short);
3255     TEST_SKIP_INSTRUCTION(signed int);
3256     TEST_SKIP_INSTRUCTION(signed long);
3257     BARRIER();
3258     // fall-through
3259     case 2:
3260     L_e_region2:
3261     BARRIER();
3262     break;
3263     }
3264 gbeauche 1.34 if (!arch_insn_skipper_tests())
3265     return 20;
3266 gbeauche 1.35 #endif
3267 gbeauche 1.34
3268 gbeauche 1.4 vm_exit();
3269 gbeauche 1.1 return 0;
3270     }
3271     #endif