ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.88
Committed: 2009-04-13T19:57:08Z (15 years, 4 months ago) by asvitkine
Branch: MAIN
Changes since 1.87: +1 -1 lines
Log Message:
make sigsegv work better with cygwin

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