ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.91
Committed: 2010-04-08T03:53:27Z (14 years, 1 month ago) by asvitkine
Branch: MAIN
CVS Tags: HEAD
Changes since 1.90: +32 -0 lines
Log Message:
[Joel Mauras]
GCC has become too smart - we need to slice the binary created to be sure the
address of the trap is within the test addresses. This is why each trap occurs
between two case labels and a new section of assembly code is set in between.

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