ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.79
Committed: 2008-01-12T23:01:40Z (16 years, 8 months ago) by gbeauche
Branch: MAIN
Changes since 1.78: +69 -24 lines
Log Message:
64-bit Windows support

File Contents

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