ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.64
Committed: 2006-07-19T21:31:10Z (18 years, 1 month ago) by gbeauche
Branch: MAIN
CVS Tags: nigel-build-19
Changes since 1.63: +43 -49 lines
Log Message:
A few fixlets to the SIGSEGV library:
- Don't export transfer types definitions (formerly used by older API)
- Handle ADD instructions in ix86_skip_instruction() (generated by icc 9.1)
- Use "%p" format for EIP/RIP addresses

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.52 * Basilisk II (C) 1997-2005 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     // Type of the system signal handler
53     typedef RETSIGTYPE (*signal_handler)(int);
54    
55     // User's SIGSEGV handler
56 gbeauche 1.12 static sigsegv_fault_handler_t sigsegv_fault_handler = 0;
57 gbeauche 1.1
58 gbeauche 1.10 // Function called to dump state if we can't handle the fault
59 gbeauche 1.12 static sigsegv_state_dumper_t sigsegv_state_dumper = 0;
60 gbeauche 1.10
61 gbeauche 1.1 // Actual SIGSEGV handler installer
62     static bool sigsegv_do_install_handler(int sig);
63    
64    
65     /*
66 gbeauche 1.14 * Instruction decoding aids
67     */
68    
69 gbeauche 1.64 // Transfer type
70     enum transfer_type_t {
71     SIGSEGV_TRANSFER_UNKNOWN = 0,
72     SIGSEGV_TRANSFER_LOAD = 1,
73     SIGSEGV_TRANSFER_STORE = 2,
74     };
75    
76 gbeauche 1.14 // Transfer size
77     enum transfer_size_t {
78     SIZE_UNKNOWN,
79     SIZE_BYTE,
80 gbeauche 1.34 SIZE_WORD, // 2 bytes
81     SIZE_LONG, // 4 bytes
82     SIZE_QUAD, // 8 bytes
83 gbeauche 1.14 };
84    
85     #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__))
86     // Addressing mode
87     enum addressing_mode_t {
88     MODE_UNKNOWN,
89     MODE_NORM,
90     MODE_U,
91     MODE_X,
92     MODE_UX
93     };
94    
95     // Decoded instruction
96     struct instruction_t {
97     transfer_type_t transfer_type;
98     transfer_size_t transfer_size;
99     addressing_mode_t addr_mode;
100     unsigned int addr;
101     char ra, rd;
102     };
103    
104 gbeauche 1.49 static void powerpc_decode_instruction(instruction_t *instruction, unsigned int nip, unsigned long * gpr)
105 gbeauche 1.14 {
106     // Get opcode and divide into fields
107 gbeauche 1.49 unsigned int opcode = *((unsigned int *)(unsigned long)nip);
108 gbeauche 1.14 unsigned int primop = opcode >> 26;
109     unsigned int exop = (opcode >> 1) & 0x3ff;
110     unsigned int ra = (opcode >> 16) & 0x1f;
111     unsigned int rb = (opcode >> 11) & 0x1f;
112     unsigned int rd = (opcode >> 21) & 0x1f;
113     signed int imm = (signed short)(opcode & 0xffff);
114    
115     // Analyze opcode
116 gbeauche 1.22 transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
117 gbeauche 1.14 transfer_size_t transfer_size = SIZE_UNKNOWN;
118     addressing_mode_t addr_mode = MODE_UNKNOWN;
119     switch (primop) {
120     case 31:
121     switch (exop) {
122     case 23: // lwzx
123 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
124 gbeauche 1.14 case 55: // lwzux
125 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
126 gbeauche 1.14 case 87: // lbzx
127 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
128 gbeauche 1.14 case 119: // lbzux
129 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
130 gbeauche 1.14 case 151: // stwx
131 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
132 gbeauche 1.14 case 183: // stwux
133 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
134 gbeauche 1.14 case 215: // stbx
135 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
136 gbeauche 1.14 case 247: // stbux
137 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
138 gbeauche 1.14 case 279: // lhzx
139 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
140 gbeauche 1.14 case 311: // lhzux
141 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
142 gbeauche 1.14 case 343: // lhax
143 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
144 gbeauche 1.14 case 375: // lhaux
145 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
146 gbeauche 1.14 case 407: // sthx
147 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
148 gbeauche 1.14 case 439: // sthux
149 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
150 gbeauche 1.14 }
151     break;
152    
153     case 32: // lwz
154 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
155 gbeauche 1.14 case 33: // lwzu
156 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
157 gbeauche 1.14 case 34: // lbz
158 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
159 gbeauche 1.14 case 35: // lbzu
160 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
161 gbeauche 1.14 case 36: // stw
162 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
163 gbeauche 1.14 case 37: // stwu
164 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
165 gbeauche 1.14 case 38: // stb
166 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
167 gbeauche 1.14 case 39: // stbu
168 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
169 gbeauche 1.14 case 40: // lhz
170 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
171 gbeauche 1.14 case 41: // lhzu
172 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
173 gbeauche 1.14 case 42: // lha
174 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
175 gbeauche 1.14 case 43: // lhau
176 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
177 gbeauche 1.14 case 44: // sth
178 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
179 gbeauche 1.14 case 45: // sthu
180 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
181 gbeauche 1.49 case 58: // ld, ldu, lwa
182     transfer_type = SIGSEGV_TRANSFER_LOAD;
183     transfer_size = SIZE_QUAD;
184     addr_mode = ((opcode & 3) == 1) ? MODE_U : MODE_NORM;
185     imm &= ~3;
186     break;
187     case 62: // std, stdu, stq
188     transfer_type = SIGSEGV_TRANSFER_STORE;
189     transfer_size = SIZE_QUAD;
190     addr_mode = ((opcode & 3) == 1) ? MODE_U : MODE_NORM;
191     imm &= ~3;
192     break;
193 gbeauche 1.14 }
194    
195     // Calculate effective address
196     unsigned int addr = 0;
197     switch (addr_mode) {
198     case MODE_X:
199     case MODE_UX:
200     if (ra == 0)
201     addr = gpr[rb];
202     else
203     addr = gpr[ra] + gpr[rb];
204     break;
205     case MODE_NORM:
206     case MODE_U:
207     if (ra == 0)
208     addr = (signed int)(signed short)imm;
209     else
210     addr = gpr[ra] + (signed int)(signed short)imm;
211     break;
212     default:
213     break;
214     }
215    
216     // Commit decoded instruction
217     instruction->addr = addr;
218     instruction->addr_mode = addr_mode;
219     instruction->transfer_type = transfer_type;
220     instruction->transfer_size = transfer_size;
221     instruction->ra = ra;
222     instruction->rd = rd;
223     }
224     #endif
225    
226    
227     /*
228 gbeauche 1.1 * OS-dependant SIGSEGV signals support section
229     */
230    
231     #if HAVE_SIGINFO_T
232     // Generic extended signal handler
233 gbeauche 1.51 #if defined(__FreeBSD__)
234 cebix 1.8 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
235     #else
236 gbeauche 1.1 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
237 cebix 1.8 #endif
238 gbeauche 1.5 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, siginfo_t *sip, void *scp
239 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 siginfo_t *sip, void *scp
240     #define SIGSEGV_FAULT_HANDLER_ARGS sip, scp
241 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS sip->si_addr
242 gbeauche 1.37 #if (defined(sgi) || defined(__sgi))
243     #include <ucontext.h>
244     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
245     #define SIGSEGV_FAULT_INSTRUCTION (unsigned long)SIGSEGV_CONTEXT_REGS[CTX_EPC]
246 gbeauche 1.38 #if (defined(mips) || defined(__mips))
247     #define SIGSEGV_REGISTER_FILE SIGSEGV_CONTEXT_REGS
248     #define SIGSEGV_SKIP_INSTRUCTION mips_skip_instruction
249     #endif
250 gbeauche 1.37 #endif
251 gbeauche 1.32 #if defined(__sun__)
252     #if (defined(sparc) || defined(__sparc__))
253 gbeauche 1.40 #include <sys/stack.h>
254     #include <sys/regset.h>
255 gbeauche 1.32 #include <sys/ucontext.h>
256     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
257     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[REG_PC]
258 gbeauche 1.40 #define SIGSEGV_SPARC_GWINDOWS (((ucontext_t *)scp)->uc_mcontext.gwins)
259     #define SIGSEGV_SPARC_RWINDOW (struct rwindow *)((char *)SIGSEGV_CONTEXT_REGS[REG_SP] + STACK_BIAS)
260     #define SIGSEGV_REGISTER_FILE ((unsigned long *)SIGSEGV_CONTEXT_REGS), SIGSEGV_SPARC_GWINDOWS, SIGSEGV_SPARC_RWINDOW
261     #define SIGSEGV_SKIP_INSTRUCTION sparc_skip_instruction
262 gbeauche 1.32 #endif
263 gbeauche 1.54 #if defined(__i386__)
264     #include <sys/regset.h>
265     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
266     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[EIP]
267     #define SIGSEGV_REGISTER_FILE (unsigned long *)SIGSEGV_CONTEXT_REGS
268     #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
269     #endif
270 gbeauche 1.32 #endif
271 gbeauche 1.55 #if defined(__FreeBSD__) || defined(__OpenBSD__)
272 gbeauche 1.17 #if (defined(i386) || defined(__i386__))
273     #define SIGSEGV_FAULT_INSTRUCTION (((struct sigcontext *)scp)->sc_eip)
274 gbeauche 1.34 #define SIGSEGV_REGISTER_FILE ((unsigned long *)&(((struct sigcontext *)scp)->sc_edi)) /* EDI is the first GPR (even below EIP) in sigcontext */
275 gbeauche 1.17 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
276 gbeauche 1.19 #endif
277 gbeauche 1.17 #endif
278 gbeauche 1.51 #if defined(__NetBSD__)
279     #if (defined(i386) || defined(__i386__))
280     #include <sys/ucontext.h>
281     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.__gregs)
282     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[_REG_EIP]
283     #define SIGSEGV_REGISTER_FILE (unsigned long *)SIGSEGV_CONTEXT_REGS
284     #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
285     #endif
286 gbeauche 1.53 #if (defined(powerpc) || defined(__powerpc__))
287     #include <sys/ucontext.h>
288     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.__gregs)
289     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[_REG_PC]
290     #define SIGSEGV_REGISTER_FILE (unsigned long *)&SIGSEGV_CONTEXT_REGS[_REG_PC], (unsigned long *)&SIGSEGV_CONTEXT_REGS[_REG_R0]
291     #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
292     #endif
293 gbeauche 1.51 #endif
294 gbeauche 1.5 #if defined(__linux__)
295 gbeauche 1.6 #if (defined(i386) || defined(__i386__))
296     #include <sys/ucontext.h>
297 gbeauche 1.14 #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
298     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[14] /* should use REG_EIP instead */
299 gbeauche 1.34 #define SIGSEGV_REGISTER_FILE (unsigned long *)SIGSEGV_CONTEXT_REGS
300 gbeauche 1.10 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
301 gbeauche 1.6 #endif
302 gbeauche 1.20 #if (defined(x86_64) || defined(__x86_64__))
303     #include <sys/ucontext.h>
304     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
305     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[16] /* should use REG_RIP instead */
306     #define SIGSEGV_REGISTER_FILE (unsigned long *)SIGSEGV_CONTEXT_REGS
307 gbeauche 1.34 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
308 gbeauche 1.20 #endif
309 gbeauche 1.5 #if (defined(ia64) || defined(__ia64__))
310     #define SIGSEGV_FAULT_INSTRUCTION (((struct sigcontext *)scp)->sc_ip & ~0x3ULL) /* slot number is in bits 0 and 1 */
311     #endif
312 gbeauche 1.9 #if (defined(powerpc) || defined(__powerpc__))
313     #include <sys/ucontext.h>
314 gbeauche 1.14 #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.regs)
315     #define SIGSEGV_FAULT_INSTRUCTION (SIGSEGV_CONTEXT_REGS->nip)
316 gbeauche 1.49 #define SIGSEGV_REGISTER_FILE (unsigned long *)&SIGSEGV_CONTEXT_REGS->nip, (unsigned long *)(SIGSEGV_CONTEXT_REGS->gpr)
317 gbeauche 1.13 #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
318 gbeauche 1.9 #endif
319 gbeauche 1.39 #if (defined(hppa) || defined(__hppa__))
320     #undef SIGSEGV_FAULT_ADDRESS
321     #define SIGSEGV_FAULT_ADDRESS sip->si_ptr
322     #endif
323 gbeauche 1.42 #if (defined(arm) || defined(__arm__))
324     #include <asm/ucontext.h> /* use kernel structure, glibc may not be in sync */
325     #define SIGSEGV_CONTEXT_REGS (((struct ucontext *)scp)->uc_mcontext)
326     #define SIGSEGV_FAULT_INSTRUCTION (SIGSEGV_CONTEXT_REGS.arm_pc)
327 gbeauche 1.44 #define SIGSEGV_REGISTER_FILE (&SIGSEGV_CONTEXT_REGS.arm_r0)
328     #define SIGSEGV_SKIP_INSTRUCTION arm_skip_instruction
329 gbeauche 1.42 #endif
330 gbeauche 1.5 #endif
331 gbeauche 1.1 #endif
332    
333     #if HAVE_SIGCONTEXT_SUBTERFUGE
334     // Linux kernels prior to 2.4 ?
335     #if defined(__linux__)
336     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
337     #if (defined(i386) || defined(__i386__))
338     #include <asm/sigcontext.h>
339     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext scs
340 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 struct sigcontext *scp
341     #define SIGSEGV_FAULT_HANDLER_ARGS &scs
342     #define SIGSEGV_FAULT_ADDRESS scp->cr2
343     #define SIGSEGV_FAULT_INSTRUCTION scp->eip
344 gbeauche 1.34 #define SIGSEGV_REGISTER_FILE (unsigned long *)scp
345 gbeauche 1.10 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
346 gbeauche 1.1 #endif
347     #if (defined(sparc) || defined(__sparc__))
348     #include <asm/sigcontext.h>
349 gbeauche 1.5 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp, char *addr
350 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp, addr
351 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS addr
352     #endif
353     #if (defined(powerpc) || defined(__powerpc__))
354     #include <asm/sigcontext.h>
355 gbeauche 1.4 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext *scp
356 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, scp
357 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS scp->regs->dar
358     #define SIGSEGV_FAULT_INSTRUCTION scp->regs->nip
359 gbeauche 1.49 #define SIGSEGV_REGISTER_FILE (unsigned long *)&scp->regs->nip, (unsigned long *)(scp->regs->gpr)
360 gbeauche 1.13 #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
361 gbeauche 1.1 #endif
362 gbeauche 1.4 #if (defined(alpha) || defined(__alpha__))
363     #include <asm/sigcontext.h>
364     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
365 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
366 gbeauche 1.4 #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
367     #define SIGSEGV_FAULT_INSTRUCTION scp->sc_pc
368 gbeauche 1.42 #endif
369     #if (defined(arm) || defined(__arm__))
370     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int r1, int r2, int r3, struct sigcontext sc
371     #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 struct sigcontext *scp
372     #define SIGSEGV_FAULT_HANDLER_ARGS &sc
373     #define SIGSEGV_FAULT_ADDRESS scp->fault_address
374     #define SIGSEGV_FAULT_INSTRUCTION scp->arm_pc
375 gbeauche 1.44 #define SIGSEGV_REGISTER_FILE &scp->arm_r0
376     #define SIGSEGV_SKIP_INSTRUCTION arm_skip_instruction
377 gbeauche 1.4 #endif
378 gbeauche 1.1 #endif
379    
380     // Irix 5 or 6 on MIPS
381 gbeauche 1.37 #if (defined(sgi) || defined(__sgi)) && (defined(SYSTYPE_SVR4) || defined(_SYSTYPE_SVR4))
382 gbeauche 1.11 #include <ucontext.h>
383 gbeauche 1.1 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
384 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
385 gbeauche 1.37 #define SIGSEGV_FAULT_ADDRESS (unsigned long)scp->sc_badvaddr
386     #define SIGSEGV_FAULT_INSTRUCTION (unsigned long)scp->sc_pc
387 gbeauche 1.1 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
388     #endif
389    
390 gbeauche 1.11 // HP-UX
391     #if (defined(hpux) || defined(__hpux__))
392     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
393 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
394 gbeauche 1.11 #define SIGSEGV_FAULT_ADDRESS scp->sc_sl.sl_ss.ss_narrow.ss_cr21
395     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV) FAULT_HANDLER(SIGBUS)
396     #endif
397    
398 gbeauche 1.1 // OSF/1 on Alpha
399     #if defined(__osf__)
400 gbeauche 1.11 #include <ucontext.h>
401 gbeauche 1.1 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
402 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
403 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS scp->sc_traparg_a0
404     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
405     #endif
406    
407     // AIX
408     #if defined(_AIX)
409     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
410 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
411 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS scp->sc_jmpbuf.jmp_context.o_vaddr
412     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
413     #endif
414    
415 gbeauche 1.33 // NetBSD
416     #if defined(__NetBSD__)
417 gbeauche 1.1 #if (defined(m68k) || defined(__m68k__))
418     #include <m68k/frame.h>
419     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
420 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
421 gbeauche 1.14 #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
422 gbeauche 1.1 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
423 gbeauche 1.14
424     // Use decoding scheme from BasiliskII/m68k native
425     static sigsegv_address_t get_fault_address(struct sigcontext *scp)
426     {
427     struct sigstate {
428     int ss_flags;
429     struct frame ss_frame;
430     };
431     struct sigstate *state = (struct sigstate *)scp->sc_ap;
432     char *fault_addr;
433     switch (state->ss_frame.f_format) {
434     case 7: /* 68040 access error */
435     /* "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown */
436     fault_addr = state->ss_frame.f_fmt7.f_fa;
437     break;
438     default:
439     fault_addr = (char *)code;
440     break;
441     }
442     return (sigsegv_address_t)fault_addr;
443     }
444 gbeauche 1.33 #endif
445     #if (defined(alpha) || defined(__alpha__))
446     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
447     #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
448     #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
449     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
450     #endif
451     #if (defined(i386) || defined(__i386__))
452     #error "FIXME: need to decode instruction and compute EA"
453     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
454     #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
455     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
456     #endif
457     #endif
458     #if defined(__FreeBSD__)
459 gbeauche 1.39 #if (defined(i386) || defined(__i386__))
460 gbeauche 1.33 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
461     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp, char *addr
462 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp, addr
463 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS addr
464 gbeauche 1.33 #define SIGSEGV_FAULT_INSTRUCTION scp->sc_eip
465 gbeauche 1.34 #define SIGSEGV_REGISTER_FILE ((unsigned long *)&scp->sc_edi)
466 gbeauche 1.33 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
467 gbeauche 1.1 #endif
468 gbeauche 1.39 #if (defined(alpha) || defined(__alpha__))
469     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
470     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, char *addr, struct sigcontext *scp
471     #define SIGSEGV_FAULT_HANDLER_ARGS sig, addr, scp
472     #define SIGSEGV_FAULT_ADDRESS addr
473     #define SIGSEGV_FAULT_INSTRUCTION scp->sc_pc
474     #endif
475 gbeauche 1.1 #endif
476 gbeauche 1.33
477     // Extract fault address out of a sigcontext
478     #if (defined(alpha) || defined(__alpha__))
479     // From Boehm's GC 6.0alpha8
480     static sigsegv_address_t get_fault_address(struct sigcontext *scp)
481     {
482     unsigned int instruction = *((unsigned int *)(scp->sc_pc));
483     unsigned long fault_address = scp->sc_regs[(instruction >> 16) & 0x1f];
484     fault_address += (signed long)(signed short)(instruction & 0xffff);
485     return (sigsegv_address_t)fault_address;
486     }
487     #endif
488    
489 gbeauche 1.4
490 gbeauche 1.27 // MacOS X, not sure which version this works in. Under 10.1
491     // vm_protect does not appear to work from a signal handler. Under
492     // 10.2 signal handlers get siginfo type arguments but the si_addr
493     // field is the address of the faulting instruction and not the
494     // address that caused the SIGBUS. Maybe this works in 10.0? In any
495     // case with Mach exception handlers there is a way to do what this
496     // was meant to do.
497     #ifndef HAVE_MACH_EXCEPTIONS
498 gbeauche 1.4 #if defined(__APPLE__) && defined(__MACH__)
499     #if (defined(ppc) || defined(__ppc__))
500     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
501 gbeauche 1.27 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
502 gbeauche 1.4 #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
503     #define SIGSEGV_FAULT_INSTRUCTION scp->sc_ir
504     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
505 gbeauche 1.14 #define SIGSEGV_REGISTER_FILE (unsigned int *)&scp->sc_ir, &((unsigned int *) scp->sc_regs)[2]
506     #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
507 gbeauche 1.4
508 gbeauche 1.14 // Use decoding scheme from SheepShaver
509 gbeauche 1.4 static sigsegv_address_t get_fault_address(struct sigcontext *scp)
510     {
511 gbeauche 1.14 unsigned int nip = (unsigned int) scp->sc_ir;
512     unsigned int * gpr = &((unsigned int *) scp->sc_regs)[2];
513     instruction_t instr;
514    
515     powerpc_decode_instruction(&instr, nip, gpr);
516     return (sigsegv_address_t)instr.addr;
517 gbeauche 1.4 }
518     #endif
519     #endif
520 gbeauche 1.1 #endif
521 gbeauche 1.27 #endif
522    
523 gbeauche 1.48 #if HAVE_WIN32_EXCEPTIONS
524     #define WIN32_LEAN_AND_MEAN /* avoid including junk */
525     #include <windows.h>
526     #include <winerror.h>
527    
528     #define SIGSEGV_FAULT_HANDLER_ARGLIST EXCEPTION_POINTERS *ExceptionInfo
529     #define SIGSEGV_FAULT_HANDLER_ARGS ExceptionInfo
530     #define SIGSEGV_FAULT_ADDRESS ExceptionInfo->ExceptionRecord->ExceptionInformation[1]
531     #define SIGSEGV_CONTEXT_REGS ExceptionInfo->ContextRecord
532     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS->Eip
533     #define SIGSEGV_REGISTER_FILE ((unsigned long *)&SIGSEGV_CONTEXT_REGS->Edi)
534     #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
535     #endif
536    
537 gbeauche 1.27 #if HAVE_MACH_EXCEPTIONS
538    
539     // This can easily be extended to other Mach systems, but really who
540     // uses HURD (oops GNU/HURD), Darwin/x86, NextStep, Rhapsody, or CMU
541     // Mach 2.5/3.0?
542     #if defined(__APPLE__) && defined(__MACH__)
543    
544     #include <sys/types.h>
545     #include <stdlib.h>
546     #include <stdio.h>
547     #include <pthread.h>
548    
549     /*
550     * If you are familiar with MIG then you will understand the frustration
551     * that was necessary to get these embedded into C++ code by hand.
552     */
553     extern "C" {
554     #include <mach/mach.h>
555     #include <mach/mach_error.h>
556    
557     extern boolean_t exc_server(mach_msg_header_t *, mach_msg_header_t *);
558     extern kern_return_t catch_exception_raise(mach_port_t, mach_port_t,
559     mach_port_t, exception_type_t, exception_data_t, mach_msg_type_number_t);
560     extern kern_return_t exception_raise(mach_port_t, mach_port_t, mach_port_t,
561     exception_type_t, exception_data_t, mach_msg_type_number_t);
562     extern kern_return_t exception_raise_state(mach_port_t, exception_type_t,
563     exception_data_t, mach_msg_type_number_t, thread_state_flavor_t *,
564     thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t *);
565     extern kern_return_t exception_raise_state_identity(mach_port_t, mach_port_t, mach_port_t,
566     exception_type_t, exception_data_t, mach_msg_type_number_t, thread_state_flavor_t *,
567     thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t *);
568     }
569    
570     // Could make this dynamic by looking for a result of MIG_ARRAY_TOO_LARGE
571     #define HANDLER_COUNT 64
572    
573     // structure to tuck away existing exception handlers
574     typedef struct _ExceptionPorts {
575     mach_msg_type_number_t maskCount;
576     exception_mask_t masks[HANDLER_COUNT];
577     exception_handler_t handlers[HANDLER_COUNT];
578     exception_behavior_t behaviors[HANDLER_COUNT];
579     thread_state_flavor_t flavors[HANDLER_COUNT];
580     } ExceptionPorts;
581    
582     // exception handler thread
583     static pthread_t exc_thread;
584    
585     // place where old exception handler info is stored
586     static ExceptionPorts ports;
587    
588     // our exception port
589     static mach_port_t _exceptionPort = MACH_PORT_NULL;
590    
591     #define MACH_CHECK_ERROR(name,ret) \
592     if (ret != KERN_SUCCESS) { \
593     mach_error(#name, ret); \
594     exit (1); \
595     }
596    
597 gbeauche 1.56 #ifdef __ppc__
598     #define SIGSEGV_THREAD_STATE_TYPE ppc_thread_state_t
599     #define SIGSEGV_THREAD_STATE_FLAVOR PPC_THREAD_STATE
600     #define SIGSEGV_THREAD_STATE_COUNT PPC_THREAD_STATE_COUNT
601     #define SIGSEGV_FAULT_INSTRUCTION state->srr0
602     #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
603     #define SIGSEGV_REGISTER_FILE (unsigned long *)&state->srr0, (unsigned long *)&state->r0
604     #endif
605     #ifdef __i386__
606 gbeauche 1.57 #ifdef i386_SAVED_STATE
607 gbeauche 1.56 #define SIGSEGV_THREAD_STATE_TYPE struct i386_saved_state
608     #define SIGSEGV_THREAD_STATE_FLAVOR i386_SAVED_STATE
609     #define SIGSEGV_THREAD_STATE_COUNT i386_SAVED_STATE_COUNT
610 gbeauche 1.57 #define SIGSEGV_REGISTER_FILE ((unsigned long *)&state->edi) /* EDI is the first GPR we consider */
611     #else
612     #define SIGSEGV_THREAD_STATE_TYPE struct i386_thread_state
613     #define SIGSEGV_THREAD_STATE_FLAVOR i386_THREAD_STATE
614     #define SIGSEGV_THREAD_STATE_COUNT i386_THREAD_STATE_COUNT
615     #define SIGSEGV_REGISTER_FILE ((unsigned long *)&state->eax) /* EAX is the first GPR we consider */
616     #endif
617 gbeauche 1.56 #define SIGSEGV_FAULT_INSTRUCTION state->eip
618     #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
619     #endif
620 gbeauche 1.27 #define SIGSEGV_FAULT_ADDRESS code[1]
621 gbeauche 1.63 #define SIGSEGV_FAULT_HANDLER_INVOKE(ADDR, IP) ((code[0] == KERN_PROTECTION_FAILURE || code[0] == KERN_INVALID_ADDRESS) ? sigsegv_fault_handler(ADDR, IP) : SIGSEGV_RETURN_FAILURE)
622 gbeauche 1.56 #define SIGSEGV_FAULT_HANDLER_ARGLIST mach_port_t thread, exception_data_t code, SIGSEGV_THREAD_STATE_TYPE *state
623 gbeauche 1.27 #define SIGSEGV_FAULT_HANDLER_ARGS thread, code, &state
624    
625     // Since there can only be one exception thread running at any time
626     // this is not a problem.
627     #define MSG_SIZE 512
628     static char msgbuf[MSG_SIZE];
629     static char replybuf[MSG_SIZE];
630    
631     /*
632     * This is the entry point for the exception handler thread. The job
633     * of this thread is to wait for exception messages on the exception
634     * port that was setup beforehand and to pass them on to exc_server.
635     * exc_server is a MIG generated function that is a part of Mach.
636     * Its job is to decide what to do with the exception message. In our
637     * case exc_server calls catch_exception_raise on our behalf. After
638     * exc_server returns, it is our responsibility to send the reply.
639     */
640     static void *
641     handleExceptions(void *priv)
642     {
643     mach_msg_header_t *msg, *reply;
644     kern_return_t krc;
645    
646     msg = (mach_msg_header_t *)msgbuf;
647     reply = (mach_msg_header_t *)replybuf;
648    
649     for (;;) {
650     krc = mach_msg(msg, MACH_RCV_MSG, MSG_SIZE, MSG_SIZE,
651     _exceptionPort, 0, MACH_PORT_NULL);
652     MACH_CHECK_ERROR(mach_msg, krc);
653    
654     if (!exc_server(msg, reply)) {
655     fprintf(stderr, "exc_server hated the message\n");
656     exit(1);
657     }
658    
659     krc = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0,
660     msg->msgh_local_port, 0, MACH_PORT_NULL);
661     if (krc != KERN_SUCCESS) {
662     fprintf(stderr, "Error sending message to original reply port, krc = %d, %s",
663     krc, mach_error_string(krc));
664     exit(1);
665     }
666     }
667     }
668     #endif
669     #endif
670 gbeauche 1.1
671 gbeauche 1.14
672     /*
673     * Instruction skipping
674     */
675    
676 gbeauche 1.10 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
677     // Decode and skip X86 instruction
678 gbeauche 1.34 #if (defined(i386) || defined(__i386__)) || defined(__x86_64__)
679 gbeauche 1.10 #if defined(__linux__)
680     enum {
681 gbeauche 1.34 #if (defined(i386) || defined(__i386__))
682 gbeauche 1.10 X86_REG_EIP = 14,
683     X86_REG_EAX = 11,
684     X86_REG_ECX = 10,
685     X86_REG_EDX = 9,
686     X86_REG_EBX = 8,
687     X86_REG_ESP = 7,
688     X86_REG_EBP = 6,
689     X86_REG_ESI = 5,
690     X86_REG_EDI = 4
691 gbeauche 1.34 #endif
692     #if defined(__x86_64__)
693     X86_REG_R8 = 0,
694     X86_REG_R9 = 1,
695     X86_REG_R10 = 2,
696     X86_REG_R11 = 3,
697     X86_REG_R12 = 4,
698     X86_REG_R13 = 5,
699     X86_REG_R14 = 6,
700     X86_REG_R15 = 7,
701     X86_REG_EDI = 8,
702     X86_REG_ESI = 9,
703     X86_REG_EBP = 10,
704     X86_REG_EBX = 11,
705     X86_REG_EDX = 12,
706     X86_REG_EAX = 13,
707     X86_REG_ECX = 14,
708     X86_REG_ESP = 15,
709     X86_REG_EIP = 16
710     #endif
711 gbeauche 1.10 };
712     #endif
713 gbeauche 1.51 #if defined(__NetBSD__)
714     enum {
715     #if (defined(i386) || defined(__i386__))
716     X86_REG_EIP = _REG_EIP,
717     X86_REG_EAX = _REG_EAX,
718     X86_REG_ECX = _REG_ECX,
719     X86_REG_EDX = _REG_EDX,
720     X86_REG_EBX = _REG_EBX,
721     X86_REG_ESP = _REG_ESP,
722     X86_REG_EBP = _REG_EBP,
723     X86_REG_ESI = _REG_ESI,
724     X86_REG_EDI = _REG_EDI
725     #endif
726     };
727     #endif
728     #if defined(__FreeBSD__)
729 gbeauche 1.17 enum {
730 gbeauche 1.34 #if (defined(i386) || defined(__i386__))
731 gbeauche 1.17 X86_REG_EIP = 10,
732     X86_REG_EAX = 7,
733     X86_REG_ECX = 6,
734     X86_REG_EDX = 5,
735     X86_REG_EBX = 4,
736     X86_REG_ESP = 13,
737     X86_REG_EBP = 2,
738     X86_REG_ESI = 1,
739     X86_REG_EDI = 0
740 gbeauche 1.34 #endif
741 gbeauche 1.17 };
742     #endif
743 gbeauche 1.55 #if defined(__OpenBSD__)
744     enum {
745     #if defined(__i386__)
746     // EDI is the first register we consider
747     #define OREG(REG) offsetof(struct sigcontext, sc_##REG)
748     #define DREG(REG) ((OREG(REG) - OREG(edi)) / 4)
749     X86_REG_EIP = DREG(eip), // 7
750     X86_REG_EAX = DREG(eax), // 6
751     X86_REG_ECX = DREG(ecx), // 5
752     X86_REG_EDX = DREG(edx), // 4
753     X86_REG_EBX = DREG(ebx), // 3
754     X86_REG_ESP = DREG(esp), // 10
755     X86_REG_EBP = DREG(ebp), // 2
756     X86_REG_ESI = DREG(esi), // 1
757     X86_REG_EDI = DREG(edi) // 0
758     #undef DREG
759     #undef OREG
760     #endif
761     };
762     #endif
763 gbeauche 1.54 #if defined(__sun__)
764     // Same as for Linux, need to check for x86-64
765     enum {
766     #if defined(__i386__)
767     X86_REG_EIP = EIP,
768     X86_REG_EAX = EAX,
769     X86_REG_ECX = ECX,
770     X86_REG_EDX = EDX,
771     X86_REG_EBX = EBX,
772     X86_REG_ESP = ESP,
773     X86_REG_EBP = EBP,
774     X86_REG_ESI = ESI,
775     X86_REG_EDI = EDI
776     #endif
777     };
778     #endif
779 gbeauche 1.56 #if defined(__APPLE__) && defined(__MACH__)
780     enum {
781 gbeauche 1.57 #ifdef i386_SAVED_STATE
782     // same as FreeBSD (in Open Darwin 8.0.1)
783 gbeauche 1.56 X86_REG_EIP = 10,
784     X86_REG_EAX = 7,
785     X86_REG_ECX = 6,
786     X86_REG_EDX = 5,
787     X86_REG_EBX = 4,
788     X86_REG_ESP = 13,
789     X86_REG_EBP = 2,
790     X86_REG_ESI = 1,
791     X86_REG_EDI = 0
792 gbeauche 1.57 #else
793     // new layout (MacOS X 10.4.4 for x86)
794     X86_REG_EIP = 10,
795     X86_REG_EAX = 0,
796     X86_REG_ECX = 2,
797     X86_REG_EDX = 4,
798     X86_REG_EBX = 1,
799     X86_REG_ESP = 7,
800     X86_REG_EBP = 6,
801     X86_REG_ESI = 5,
802     X86_REG_EDI = 4
803     #endif
804 gbeauche 1.56 };
805     #endif
806 gbeauche 1.48 #if defined(_WIN32)
807     enum {
808     #if (defined(i386) || defined(__i386__))
809     X86_REG_EIP = 7,
810     X86_REG_EAX = 5,
811     X86_REG_ECX = 4,
812     X86_REG_EDX = 3,
813     X86_REG_EBX = 2,
814     X86_REG_ESP = 10,
815     X86_REG_EBP = 6,
816     X86_REG_ESI = 1,
817     X86_REG_EDI = 0
818     #endif
819     };
820     #endif
821 gbeauche 1.10 // FIXME: this is partly redundant with the instruction decoding phase
822     // to discover transfer type and register number
823     static inline int ix86_step_over_modrm(unsigned char * p)
824     {
825     int mod = (p[0] >> 6) & 3;
826     int rm = p[0] & 7;
827     int offset = 0;
828    
829     // ModR/M Byte
830     switch (mod) {
831     case 0: // [reg]
832     if (rm == 5) return 4; // disp32
833     break;
834     case 1: // disp8[reg]
835     offset = 1;
836     break;
837     case 2: // disp32[reg]
838     offset = 4;
839     break;
840     case 3: // register
841     return 0;
842     }
843    
844     // SIB Byte
845     if (rm == 4) {
846     if (mod == 0 && (p[1] & 7) == 5)
847     offset = 5; // disp32[index]
848     else
849     offset++;
850     }
851    
852     return offset;
853     }
854    
855 gbeauche 1.34 static bool ix86_skip_instruction(unsigned long * regs)
856 gbeauche 1.10 {
857 gbeauche 1.14 unsigned char * eip = (unsigned char *)regs[X86_REG_EIP];
858 gbeauche 1.10
859     if (eip == 0)
860     return false;
861 gbeauche 1.50 #ifdef _WIN32
862     if (IsBadCodePtr((FARPROC)eip))
863     return false;
864     #endif
865 gbeauche 1.10
866 gbeauche 1.64 enum instruction_type_t {
867     i_MOV,
868     i_ADD
869     };
870    
871 gbeauche 1.22 transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
872 gbeauche 1.14 transfer_size_t transfer_size = SIZE_LONG;
873 gbeauche 1.64 instruction_type_t instruction_type = i_MOV;
874 gbeauche 1.10
875     int reg = -1;
876     int len = 0;
877 gbeauche 1.34
878     #if DEBUG
879     printf("IP: %p [%02x %02x %02x %02x...]\n",
880     eip, eip[0], eip[1], eip[2], eip[3]);
881     #endif
882    
883 gbeauche 1.10 // Operand size prefix
884     if (*eip == 0x66) {
885     eip++;
886     len++;
887     transfer_size = SIZE_WORD;
888     }
889    
890 gbeauche 1.34 // REX prefix
891     #if defined(__x86_64__)
892     struct rex_t {
893     unsigned char W;
894     unsigned char R;
895     unsigned char X;
896     unsigned char B;
897     };
898     rex_t rex = { 0, 0, 0, 0 };
899     bool has_rex = false;
900     if ((*eip & 0xf0) == 0x40) {
901     has_rex = true;
902     const unsigned char b = *eip;
903     rex.W = b & (1 << 3);
904     rex.R = b & (1 << 2);
905     rex.X = b & (1 << 1);
906     rex.B = b & (1 << 0);
907     #if DEBUG
908     printf("REX: %c,%c,%c,%c\n",
909     rex.W ? 'W' : '_',
910     rex.R ? 'R' : '_',
911     rex.X ? 'X' : '_',
912     rex.B ? 'B' : '_');
913     #endif
914     eip++;
915     len++;
916     if (rex.W)
917     transfer_size = SIZE_QUAD;
918     }
919     #else
920     const bool has_rex = false;
921     #endif
922    
923 gbeauche 1.10 // Decode instruction
924 gbeauche 1.64 int op_len = 1;
925 gbeauche 1.45 int target_size = SIZE_UNKNOWN;
926 gbeauche 1.10 switch (eip[0]) {
927 gbeauche 1.17 case 0x0f:
928 gbeauche 1.45 target_size = transfer_size;
929 gbeauche 1.18 switch (eip[1]) {
930 gbeauche 1.45 case 0xbe: // MOVSX r32, r/m8
931 gbeauche 1.18 case 0xb6: // MOVZX r32, r/m8
932 gbeauche 1.45 transfer_size = SIZE_BYTE;
933     goto do_mov_extend;
934 gbeauche 1.47 case 0xbf: // MOVSX r32, r/m16
935 gbeauche 1.18 case 0xb7: // MOVZX r32, r/m16
936 gbeauche 1.45 transfer_size = SIZE_WORD;
937     goto do_mov_extend;
938     do_mov_extend:
939 gbeauche 1.64 op_len = 2;
940     goto do_transfer_load;
941     }
942     break;
943 gbeauche 1.62 #if defined(__x86_64__)
944     case 0x63: // MOVSXD r64, r/m32
945     if (has_rex && rex.W) {
946     transfer_size = SIZE_LONG;
947     target_size = SIZE_QUAD;
948     }
949     else if (transfer_size != SIZE_WORD) {
950     transfer_size = SIZE_LONG;
951     target_size = SIZE_QUAD;
952     }
953 gbeauche 1.64 goto do_transfer_load;
954 gbeauche 1.62 #endif
955 gbeauche 1.64 case 0x02: // ADD r8, r/m8
956     transfer_size = SIZE_BYTE;
957     case 0x03: // ADD r32, r/m32
958     instruction_type = i_ADD;
959     goto do_transfer_load;
960 gbeauche 1.10 case 0x8a: // MOV r8, r/m8
961     transfer_size = SIZE_BYTE;
962     case 0x8b: // MOV r32, r/m32 (or 16-bit operation)
963 gbeauche 1.64 do_transfer_load:
964     switch (eip[op_len] & 0xc0) {
965 gbeauche 1.10 case 0x80:
966 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
967 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
968 gbeauche 1.10 break;
969     case 0x40:
970 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
971 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
972 gbeauche 1.10 break;
973     case 0x00:
974 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
975 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
976 gbeauche 1.10 break;
977     }
978 gbeauche 1.64 len += 1 + op_len + ix86_step_over_modrm(eip + op_len);
979 gbeauche 1.10 break;
980 gbeauche 1.64 case 0x00: // ADD r/m8, r8
981     transfer_size = SIZE_BYTE;
982     case 0x01: // ADD r/m32, r32
983     instruction_type = i_ADD;
984     goto do_transfer_store;
985 gbeauche 1.10 case 0x88: // MOV r/m8, r8
986     transfer_size = SIZE_BYTE;
987     case 0x89: // MOV r/m32, r32 (or 16-bit operation)
988 gbeauche 1.64 do_transfer_store:
989     switch (eip[op_len] & 0xc0) {
990 gbeauche 1.10 case 0x80:
991 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
992 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
993 gbeauche 1.10 break;
994     case 0x40:
995 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
996 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
997 gbeauche 1.10 break;
998     case 0x00:
999 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
1000 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
1001 gbeauche 1.10 break;
1002     }
1003 gbeauche 1.64 len += 1 + op_len + ix86_step_over_modrm(eip + op_len);
1004 gbeauche 1.10 break;
1005     }
1006 gbeauche 1.45 if (target_size == SIZE_UNKNOWN)
1007     target_size = transfer_size;
1008 gbeauche 1.10
1009 gbeauche 1.22 if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1010 gbeauche 1.10 // Unknown machine code, let it crash. Then patch the decoder
1011     return false;
1012     }
1013    
1014 gbeauche 1.34 #if defined(__x86_64__)
1015     if (rex.R)
1016     reg += 8;
1017     #endif
1018    
1019 gbeauche 1.64 if (instruction_type == i_MOV && transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) {
1020 gbeauche 1.34 static const int x86_reg_map[] = {
1021 gbeauche 1.10 X86_REG_EAX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBX,
1022 gbeauche 1.34 X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI,
1023     #if defined(__x86_64__)
1024     X86_REG_R8, X86_REG_R9, X86_REG_R10, X86_REG_R11,
1025     X86_REG_R12, X86_REG_R13, X86_REG_R14, X86_REG_R15,
1026     #endif
1027 gbeauche 1.10 };
1028    
1029 gbeauche 1.34 if (reg < 0 || reg >= (sizeof(x86_reg_map)/sizeof(x86_reg_map[0]) - 1))
1030 gbeauche 1.10 return false;
1031    
1032 gbeauche 1.34 // Set 0 to the relevant register part
1033     // NOTE: this is only valid for MOV alike instructions
1034 gbeauche 1.10 int rloc = x86_reg_map[reg];
1035 gbeauche 1.45 switch (target_size) {
1036 gbeauche 1.10 case SIZE_BYTE:
1037 gbeauche 1.36 if (has_rex || reg < 4)
1038     regs[rloc] = (regs[rloc] & ~0x00ffL);
1039     else {
1040     rloc = x86_reg_map[reg - 4];
1041     regs[rloc] = (regs[rloc] & ~0xff00L);
1042     }
1043 gbeauche 1.10 break;
1044     case SIZE_WORD:
1045 gbeauche 1.34 regs[rloc] = (regs[rloc] & ~0xffffL);
1046 gbeauche 1.10 break;
1047     case SIZE_LONG:
1048 gbeauche 1.34 case SIZE_QUAD: // zero-extension
1049 gbeauche 1.10 regs[rloc] = 0;
1050     break;
1051     }
1052     }
1053    
1054     #if DEBUG
1055 gbeauche 1.64 printf("%p: %s %s access", (void *)regs[X86_REG_EIP],
1056 gbeauche 1.34 transfer_size == SIZE_BYTE ? "byte" :
1057     transfer_size == SIZE_WORD ? "word" :
1058     transfer_size == SIZE_LONG ? "long" :
1059     transfer_size == SIZE_QUAD ? "quad" : "unknown",
1060 gbeauche 1.22 transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
1061 gbeauche 1.10
1062     if (reg != -1) {
1063 gbeauche 1.34 static const char * x86_byte_reg_str_map[] = {
1064     "al", "cl", "dl", "bl",
1065     "spl", "bpl", "sil", "dil",
1066     "r8b", "r9b", "r10b", "r11b",
1067     "r12b", "r13b", "r14b", "r15b",
1068     "ah", "ch", "dh", "bh",
1069     };
1070     static const char * x86_word_reg_str_map[] = {
1071     "ax", "cx", "dx", "bx",
1072     "sp", "bp", "si", "di",
1073     "r8w", "r9w", "r10w", "r11w",
1074     "r12w", "r13w", "r14w", "r15w",
1075     };
1076     static const char *x86_long_reg_str_map[] = {
1077     "eax", "ecx", "edx", "ebx",
1078     "esp", "ebp", "esi", "edi",
1079     "r8d", "r9d", "r10d", "r11d",
1080     "r12d", "r13d", "r14d", "r15d",
1081     };
1082     static const char *x86_quad_reg_str_map[] = {
1083     "rax", "rcx", "rdx", "rbx",
1084     "rsp", "rbp", "rsi", "rdi",
1085     "r8", "r9", "r10", "r11",
1086     "r12", "r13", "r14", "r15",
1087 gbeauche 1.10 };
1088 gbeauche 1.34 const char * reg_str = NULL;
1089 gbeauche 1.46 switch (target_size) {
1090 gbeauche 1.34 case SIZE_BYTE:
1091     reg_str = x86_byte_reg_str_map[(!has_rex && reg >= 4 ? 12 : 0) + reg];
1092     break;
1093     case SIZE_WORD: reg_str = x86_word_reg_str_map[reg]; break;
1094     case SIZE_LONG: reg_str = x86_long_reg_str_map[reg]; break;
1095     case SIZE_QUAD: reg_str = x86_quad_reg_str_map[reg]; break;
1096     }
1097     if (reg_str)
1098     printf(" %s register %%%s",
1099     transfer_type == SIGSEGV_TRANSFER_LOAD ? "to" : "from",
1100     reg_str);
1101 gbeauche 1.10 }
1102     printf(", %d bytes instruction\n", len);
1103     #endif
1104    
1105     regs[X86_REG_EIP] += len;
1106 gbeauche 1.13 return true;
1107     }
1108     #endif
1109 gbeauche 1.14
1110 gbeauche 1.13 // Decode and skip PPC instruction
1111 gbeauche 1.14 #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__))
1112 gbeauche 1.49 static bool powerpc_skip_instruction(unsigned long * nip_p, unsigned long * regs)
1113 gbeauche 1.13 {
1114 gbeauche 1.14 instruction_t instr;
1115     powerpc_decode_instruction(&instr, *nip_p, regs);
1116 gbeauche 1.13
1117 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1118 gbeauche 1.13 // Unknown machine code, let it crash. Then patch the decoder
1119     return false;
1120     }
1121    
1122     #if DEBUG
1123 gbeauche 1.14 printf("%08x: %s %s access", *nip_p,
1124 gbeauche 1.49 instr.transfer_size == SIZE_BYTE ? "byte" :
1125     instr.transfer_size == SIZE_WORD ? "word" :
1126     instr.transfer_size == SIZE_LONG ? "long" : "quad",
1127 gbeauche 1.22 instr.transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
1128 gbeauche 1.14
1129     if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
1130     printf(" r%d (ra = %08x)\n", instr.ra, instr.addr);
1131 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
1132 gbeauche 1.14 printf(" r%d (rd = 0)\n", instr.rd);
1133     #endif
1134    
1135     if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
1136     regs[instr.ra] = instr.addr;
1137 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
1138 gbeauche 1.14 regs[instr.rd] = 0;
1139 gbeauche 1.13
1140 gbeauche 1.14 *nip_p += 4;
1141 gbeauche 1.10 return true;
1142 gbeauche 1.38 }
1143     #endif
1144    
1145     // Decode and skip MIPS instruction
1146     #if (defined(mips) || defined(__mips))
1147     enum {
1148     #if (defined(sgi) || defined(__sgi))
1149     MIPS_REG_EPC = 35,
1150     #endif
1151     };
1152     static bool mips_skip_instruction(greg_t * regs)
1153     {
1154     unsigned int * epc = (unsigned int *)(unsigned long)regs[MIPS_REG_EPC];
1155    
1156     if (epc == 0)
1157     return false;
1158    
1159     #if DEBUG
1160     printf("IP: %p [%08x]\n", epc, epc[0]);
1161     #endif
1162    
1163     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1164     transfer_size_t transfer_size = SIZE_LONG;
1165     int direction = 0;
1166    
1167     const unsigned int opcode = epc[0];
1168     switch (opcode >> 26) {
1169     case 32: // Load Byte
1170     case 36: // Load Byte Unsigned
1171     transfer_type = SIGSEGV_TRANSFER_LOAD;
1172     transfer_size = SIZE_BYTE;
1173     break;
1174     case 33: // Load Halfword
1175     case 37: // Load Halfword Unsigned
1176     transfer_type = SIGSEGV_TRANSFER_LOAD;
1177     transfer_size = SIZE_WORD;
1178     break;
1179     case 35: // Load Word
1180     case 39: // Load Word Unsigned
1181     transfer_type = SIGSEGV_TRANSFER_LOAD;
1182     transfer_size = SIZE_LONG;
1183     break;
1184     case 34: // Load Word Left
1185     transfer_type = SIGSEGV_TRANSFER_LOAD;
1186     transfer_size = SIZE_LONG;
1187     direction = -1;
1188     break;
1189     case 38: // Load Word Right
1190     transfer_type = SIGSEGV_TRANSFER_LOAD;
1191     transfer_size = SIZE_LONG;
1192     direction = 1;
1193     break;
1194     case 55: // Load Doubleword
1195     transfer_type = SIGSEGV_TRANSFER_LOAD;
1196     transfer_size = SIZE_QUAD;
1197     break;
1198     case 26: // Load Doubleword Left
1199     transfer_type = SIGSEGV_TRANSFER_LOAD;
1200     transfer_size = SIZE_QUAD;
1201     direction = -1;
1202     break;
1203     case 27: // Load Doubleword Right
1204     transfer_type = SIGSEGV_TRANSFER_LOAD;
1205     transfer_size = SIZE_QUAD;
1206     direction = 1;
1207     break;
1208     case 40: // Store Byte
1209     transfer_type = SIGSEGV_TRANSFER_STORE;
1210     transfer_size = SIZE_BYTE;
1211     break;
1212     case 41: // Store Halfword
1213     transfer_type = SIGSEGV_TRANSFER_STORE;
1214     transfer_size = SIZE_WORD;
1215     break;
1216     case 43: // Store Word
1217     case 42: // Store Word Left
1218     case 46: // Store Word Right
1219     transfer_type = SIGSEGV_TRANSFER_STORE;
1220     transfer_size = SIZE_LONG;
1221     break;
1222     case 63: // Store Doubleword
1223     case 44: // Store Doubleword Left
1224     case 45: // Store Doubleword Right
1225     transfer_type = SIGSEGV_TRANSFER_STORE;
1226     transfer_size = SIZE_QUAD;
1227     break;
1228     /* Misc instructions unlikely to be used within CPU emulators */
1229     case 48: // Load Linked Word
1230     transfer_type = SIGSEGV_TRANSFER_LOAD;
1231     transfer_size = SIZE_LONG;
1232     break;
1233     case 52: // Load Linked Doubleword
1234     transfer_type = SIGSEGV_TRANSFER_LOAD;
1235     transfer_size = SIZE_QUAD;
1236     break;
1237     case 56: // Store Conditional Word
1238     transfer_type = SIGSEGV_TRANSFER_STORE;
1239     transfer_size = SIZE_LONG;
1240     break;
1241     case 60: // Store Conditional Doubleword
1242     transfer_type = SIGSEGV_TRANSFER_STORE;
1243     transfer_size = SIZE_QUAD;
1244     break;
1245     }
1246    
1247     if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1248     // Unknown machine code, let it crash. Then patch the decoder
1249     return false;
1250     }
1251    
1252     // Zero target register in case of a load operation
1253     const int reg = (opcode >> 16) & 0x1f;
1254     if (transfer_type == SIGSEGV_TRANSFER_LOAD) {
1255     if (direction == 0)
1256     regs[reg] = 0;
1257     else {
1258     // FIXME: untested code
1259     unsigned long ea = regs[(opcode >> 21) & 0x1f];
1260     ea += (signed long)(signed int)(signed short)(opcode & 0xffff);
1261     const int offset = ea & (transfer_size == SIZE_LONG ? 3 : 7);
1262     unsigned long value;
1263     if (direction > 0) {
1264     const unsigned long rmask = ~((1L << ((offset + 1) * 8)) - 1);
1265     value = regs[reg] & rmask;
1266     }
1267     else {
1268     const unsigned long lmask = (1L << (offset * 8)) - 1;
1269     value = regs[reg] & lmask;
1270     }
1271     // restore most significant bits
1272     if (transfer_size == SIZE_LONG)
1273     value = (signed long)(signed int)value;
1274     regs[reg] = value;
1275     }
1276     }
1277    
1278     #if DEBUG
1279     #if (defined(_ABIN32) || defined(_ABI64))
1280     static const char * mips_gpr_names[32] = {
1281     "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
1282     "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
1283     "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
1284     "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
1285     };
1286     #else
1287     static const char * mips_gpr_names[32] = {
1288     "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
1289     "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
1290     "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
1291     "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
1292     };
1293     #endif
1294     printf("%s %s register %s\n",
1295     transfer_size == SIZE_BYTE ? "byte" :
1296     transfer_size == SIZE_WORD ? "word" :
1297     transfer_size == SIZE_LONG ? "long" :
1298     transfer_size == SIZE_QUAD ? "quad" : "unknown",
1299     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1300     mips_gpr_names[reg]);
1301     #endif
1302    
1303     regs[MIPS_REG_EPC] += 4;
1304 gbeauche 1.40 return true;
1305     }
1306     #endif
1307    
1308     // Decode and skip SPARC instruction
1309     #if (defined(sparc) || defined(__sparc__))
1310     enum {
1311     #if (defined(__sun__))
1312     SPARC_REG_G1 = REG_G1,
1313     SPARC_REG_O0 = REG_O0,
1314     SPARC_REG_PC = REG_PC,
1315 gbeauche 1.59 SPARC_REG_nPC = REG_nPC
1316 gbeauche 1.40 #endif
1317     };
1318     static bool sparc_skip_instruction(unsigned long * regs, gwindows_t * gwins, struct rwindow * rwin)
1319     {
1320     unsigned int * pc = (unsigned int *)regs[SPARC_REG_PC];
1321    
1322     if (pc == 0)
1323     return false;
1324    
1325     #if DEBUG
1326     printf("IP: %p [%08x]\n", pc, pc[0]);
1327     #endif
1328    
1329     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1330     transfer_size_t transfer_size = SIZE_LONG;
1331     bool register_pair = false;
1332    
1333     const unsigned int opcode = pc[0];
1334     if ((opcode >> 30) != 3)
1335     return false;
1336     switch ((opcode >> 19) & 0x3f) {
1337     case 9: // Load Signed Byte
1338     case 1: // Load Unsigned Byte
1339     transfer_type = SIGSEGV_TRANSFER_LOAD;
1340     transfer_size = SIZE_BYTE;
1341     break;
1342     case 10:// Load Signed Halfword
1343     case 2: // Load Unsigned Word
1344     transfer_type = SIGSEGV_TRANSFER_LOAD;
1345     transfer_size = SIZE_WORD;
1346     break;
1347     case 8: // Load Word
1348     case 0: // Load Unsigned Word
1349     transfer_type = SIGSEGV_TRANSFER_LOAD;
1350     transfer_size = SIZE_LONG;
1351     break;
1352     case 11:// Load Extended Word
1353     transfer_type = SIGSEGV_TRANSFER_LOAD;
1354     transfer_size = SIZE_QUAD;
1355     break;
1356     case 3: // Load Doubleword
1357     transfer_type = SIGSEGV_TRANSFER_LOAD;
1358     transfer_size = SIZE_LONG;
1359     register_pair = true;
1360     break;
1361     case 5: // Store Byte
1362     transfer_type = SIGSEGV_TRANSFER_STORE;
1363     transfer_size = SIZE_BYTE;
1364     break;
1365     case 6: // Store Halfword
1366     transfer_type = SIGSEGV_TRANSFER_STORE;
1367     transfer_size = SIZE_WORD;
1368     break;
1369     case 4: // Store Word
1370     transfer_type = SIGSEGV_TRANSFER_STORE;
1371     transfer_size = SIZE_LONG;
1372     break;
1373     case 14:// Store Extended Word
1374     transfer_type = SIGSEGV_TRANSFER_STORE;
1375     transfer_size = SIZE_QUAD;
1376     break;
1377     case 7: // Store Doubleword
1378     transfer_type = SIGSEGV_TRANSFER_STORE;
1379 gbeauche 1.58 transfer_size = SIZE_LONG;
1380 gbeauche 1.40 register_pair = true;
1381     break;
1382     }
1383    
1384     if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1385     // Unknown machine code, let it crash. Then patch the decoder
1386     return false;
1387     }
1388    
1389 gbeauche 1.58 const int reg = (opcode >> 25) & 0x1f;
1390    
1391     #if DEBUG
1392     static const char * reg_names[] = {
1393     "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
1394     "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
1395     "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
1396     "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"
1397     };
1398     printf("%s %s register %s\n",
1399     transfer_size == SIZE_BYTE ? "byte" :
1400     transfer_size == SIZE_WORD ? "word" :
1401     transfer_size == SIZE_LONG ? "long" :
1402     transfer_size == SIZE_QUAD ? "quad" : "unknown",
1403     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1404     reg_names[reg]);
1405     #endif
1406    
1407 gbeauche 1.40 // Zero target register in case of a load operation
1408     if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != 0) {
1409     // FIXME: code to handle local & input registers is not tested
1410 gbeauche 1.58 if (reg >= 1 && reg < 8) {
1411 gbeauche 1.40 // global registers
1412     regs[reg - 1 + SPARC_REG_G1] = 0;
1413     }
1414 gbeauche 1.58 else if (reg >= 8 && reg < 16) {
1415 gbeauche 1.40 // output registers
1416     regs[reg - 8 + SPARC_REG_O0] = 0;
1417     }
1418 gbeauche 1.58 else if (reg >= 16 && reg < 24) {
1419 gbeauche 1.40 // local registers (in register windows)
1420     if (gwins)
1421     gwins->wbuf->rw_local[reg - 16] = 0;
1422     else
1423     rwin->rw_local[reg - 16] = 0;
1424     }
1425     else {
1426     // input registers (in register windows)
1427     if (gwins)
1428     gwins->wbuf->rw_in[reg - 24] = 0;
1429     else
1430     rwin->rw_in[reg - 24] = 0;
1431     }
1432     }
1433    
1434     regs[SPARC_REG_PC] += 4;
1435 gbeauche 1.59 regs[SPARC_REG_nPC] += 4;
1436 gbeauche 1.38 return true;
1437 gbeauche 1.10 }
1438     #endif
1439     #endif
1440    
1441 gbeauche 1.44 // Decode and skip ARM instruction
1442     #if (defined(arm) || defined(__arm__))
1443     enum {
1444     #if (defined(__linux__))
1445     ARM_REG_PC = 15,
1446     ARM_REG_CPSR = 16
1447     #endif
1448     };
1449     static bool arm_skip_instruction(unsigned long * regs)
1450     {
1451     unsigned int * pc = (unsigned int *)regs[ARM_REG_PC];
1452    
1453     if (pc == 0)
1454     return false;
1455    
1456     #if DEBUG
1457     printf("IP: %p [%08x]\n", pc, pc[0]);
1458     #endif
1459    
1460     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1461     transfer_size_t transfer_size = SIZE_UNKNOWN;
1462     enum { op_sdt = 1, op_sdth = 2 };
1463     int op = 0;
1464    
1465     // Handle load/store instructions only
1466     const unsigned int opcode = pc[0];
1467     switch ((opcode >> 25) & 7) {
1468     case 0: // Halfword and Signed Data Transfer (LDRH, STRH, LDRSB, LDRSH)
1469     op = op_sdth;
1470     // Determine transfer size (S/H bits)
1471     switch ((opcode >> 5) & 3) {
1472     case 0: // SWP instruction
1473     break;
1474     case 1: // Unsigned halfwords
1475     case 3: // Signed halfwords
1476     transfer_size = SIZE_WORD;
1477     break;
1478     case 2: // Signed byte
1479     transfer_size = SIZE_BYTE;
1480     break;
1481     }
1482     break;
1483     case 2:
1484     case 3: // Single Data Transfer (LDR, STR)
1485     op = op_sdt;
1486     // Determine transfer size (B bit)
1487     if (((opcode >> 22) & 1) == 1)
1488     transfer_size = SIZE_BYTE;
1489     else
1490     transfer_size = SIZE_LONG;
1491     break;
1492     default:
1493     // FIXME: support load/store mutliple?
1494     return false;
1495     }
1496    
1497     // Check for invalid transfer size (SWP instruction?)
1498     if (transfer_size == SIZE_UNKNOWN)
1499     return false;
1500    
1501     // Determine transfer type (L bit)
1502     if (((opcode >> 20) & 1) == 1)
1503     transfer_type = SIGSEGV_TRANSFER_LOAD;
1504     else
1505     transfer_type = SIGSEGV_TRANSFER_STORE;
1506    
1507     // Compute offset
1508     int offset;
1509     if (((opcode >> 25) & 1) == 0) {
1510     if (op == op_sdt)
1511     offset = opcode & 0xfff;
1512     else if (op == op_sdth) {
1513     int rm = opcode & 0xf;
1514     if (((opcode >> 22) & 1) == 0) {
1515     // register offset
1516     offset = regs[rm];
1517     }
1518     else {
1519     // immediate offset
1520     offset = ((opcode >> 4) & 0xf0) | (opcode & 0x0f);
1521     }
1522     }
1523     }
1524     else {
1525     const int rm = opcode & 0xf;
1526     const int sh = (opcode >> 7) & 0x1f;
1527     if (((opcode >> 4) & 1) == 1) {
1528     // we expect only legal load/store instructions
1529     printf("FATAL: invalid shift operand\n");
1530     return false;
1531     }
1532     const unsigned int v = regs[rm];
1533     switch ((opcode >> 5) & 3) {
1534     case 0: // logical shift left
1535     offset = sh ? v << sh : v;
1536     break;
1537     case 1: // logical shift right
1538     offset = sh ? v >> sh : 0;
1539     break;
1540     case 2: // arithmetic shift right
1541     if (sh)
1542     offset = ((signed int)v) >> sh;
1543     else
1544     offset = (v & 0x80000000) ? 0xffffffff : 0;
1545     break;
1546     case 3: // rotate right
1547     if (sh)
1548     offset = (v >> sh) | (v << (32 - sh));
1549     else
1550     offset = (v >> 1) | ((regs[ARM_REG_CPSR] << 2) & 0x80000000);
1551     break;
1552     }
1553     }
1554     if (((opcode >> 23) & 1) == 0)
1555     offset = -offset;
1556    
1557     int rd = (opcode >> 12) & 0xf;
1558     int rn = (opcode >> 16) & 0xf;
1559     #if DEBUG
1560     static const char * reg_names[] = {
1561     "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
1562     "r9", "r9", "sl", "fp", "ip", "sp", "lr", "pc"
1563     };
1564     printf("%s %s register %s\n",
1565     transfer_size == SIZE_BYTE ? "byte" :
1566     transfer_size == SIZE_WORD ? "word" :
1567     transfer_size == SIZE_LONG ? "long" : "unknown",
1568     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1569     reg_names[rd]);
1570     #endif
1571    
1572     unsigned int base = regs[rn];
1573     if (((opcode >> 24) & 1) == 1)
1574     base += offset;
1575    
1576     if (transfer_type == SIGSEGV_TRANSFER_LOAD)
1577     regs[rd] = 0;
1578    
1579     if (((opcode >> 24) & 1) == 0) // post-index addressing
1580     regs[rn] += offset;
1581     else if (((opcode >> 21) & 1) == 1) // write-back address into base
1582     regs[rn] = base;
1583    
1584     regs[ARM_REG_PC] += 4;
1585     return true;
1586     }
1587     #endif
1588    
1589    
1590 gbeauche 1.1 // Fallbacks
1591     #ifndef SIGSEGV_FAULT_INSTRUCTION
1592     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_INVALID_PC
1593     #endif
1594 gbeauche 1.30 #ifndef SIGSEGV_FAULT_HANDLER_ARGLIST_1
1595     #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 SIGSEGV_FAULT_HANDLER_ARGLIST
1596     #endif
1597 gbeauche 1.31 #ifndef SIGSEGV_FAULT_HANDLER_INVOKE
1598     #define SIGSEGV_FAULT_HANDLER_INVOKE(ADDR, IP) sigsegv_fault_handler(ADDR, IP)
1599     #endif
1600 gbeauche 1.1
1601 gbeauche 1.2 // SIGSEGV recovery supported ?
1602     #if defined(SIGSEGV_ALL_SIGNALS) && defined(SIGSEGV_FAULT_HANDLER_ARGLIST) && defined(SIGSEGV_FAULT_ADDRESS)
1603     #define HAVE_SIGSEGV_RECOVERY
1604     #endif
1605    
1606 gbeauche 1.1
1607     /*
1608     * SIGSEGV global handler
1609     */
1610    
1611 gbeauche 1.27 // This function handles the badaccess to memory.
1612     // It is called from the signal handler or the exception handler.
1613 gbeauche 1.30 static bool handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGLIST_1)
1614 gbeauche 1.1 {
1615 gbeauche 1.56 #ifdef HAVE_MACH_EXCEPTIONS
1616     // We must match the initial count when writing back the CPU state registers
1617     kern_return_t krc;
1618     mach_msg_type_number_t count;
1619    
1620     count = SIGSEGV_THREAD_STATE_COUNT;
1621     krc = thread_get_state(thread, SIGSEGV_THREAD_STATE_FLAVOR, (thread_state_t)state, &count);
1622     MACH_CHECK_ERROR (thread_get_state, krc);
1623     #endif
1624    
1625 gbeauche 1.10 sigsegv_address_t fault_address = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
1626     sigsegv_address_t fault_instruction = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
1627    
1628 gbeauche 1.1 // Call user's handler and reinstall the global handler, if required
1629 gbeauche 1.31 switch (SIGSEGV_FAULT_HANDLER_INVOKE(fault_address, fault_instruction)) {
1630 gbeauche 1.24 case SIGSEGV_RETURN_SUCCESS:
1631 gbeauche 1.27 return true;
1632    
1633 gbeauche 1.10 #if HAVE_SIGSEGV_SKIP_INSTRUCTION
1634 gbeauche 1.24 case SIGSEGV_RETURN_SKIP_INSTRUCTION:
1635 gbeauche 1.27 // Call the instruction skipper with the register file
1636     // available
1637     if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE)) {
1638     #ifdef HAVE_MACH_EXCEPTIONS
1639     // Unlike UNIX signals where the thread state
1640     // is modified off of the stack, in Mach we
1641     // need to actually call thread_set_state to
1642     // have the register values updated.
1643     krc = thread_set_state(thread,
1644 gbeauche 1.56 SIGSEGV_THREAD_STATE_FLAVOR, (thread_state_t)state,
1645     count);
1646     MACH_CHECK_ERROR (thread_set_state, krc);
1647 gbeauche 1.27 #endif
1648     return true;
1649     }
1650 gbeauche 1.24 break;
1651     #endif
1652 nigel 1.43 case SIGSEGV_RETURN_FAILURE:
1653 gbeauche 1.50 // We can't do anything with the fault_address, dump state?
1654     if (sigsegv_state_dumper != 0)
1655     sigsegv_state_dumper(fault_address, fault_instruction);
1656     break;
1657 gbeauche 1.10 }
1658 gbeauche 1.27
1659     return false;
1660     }
1661    
1662    
1663     /*
1664     * There are two mechanisms for handling a bad memory access,
1665     * Mach exceptions and UNIX signals. The implementation specific
1666     * code appears below. Its reponsibility is to call handle_badaccess
1667     * which is the routine that handles the fault in an implementation
1668     * agnostic manner. The implementation specific code below is then
1669     * reponsible for checking whether handle_badaccess was able
1670     * to handle the memory access error and perform any implementation
1671     * specific tasks necessary afterwards.
1672     */
1673    
1674     #ifdef HAVE_MACH_EXCEPTIONS
1675     /*
1676     * We need to forward all exceptions that we do not handle.
1677     * This is important, there are many exceptions that may be
1678     * handled by other exception handlers. For example debuggers
1679     * use exceptions and the exception hander is in another
1680     * process in such a case. (Timothy J. Wood states in his
1681     * message to the list that he based this code on that from
1682     * gdb for Darwin.)
1683     */
1684     static inline kern_return_t
1685     forward_exception(mach_port_t thread_port,
1686     mach_port_t task_port,
1687     exception_type_t exception_type,
1688     exception_data_t exception_data,
1689     mach_msg_type_number_t data_count,
1690     ExceptionPorts *oldExceptionPorts)
1691     {
1692     kern_return_t kret;
1693     unsigned int portIndex;
1694     mach_port_t port;
1695     exception_behavior_t behavior;
1696     thread_state_flavor_t flavor;
1697 gbeauche 1.57 thread_state_data_t thread_state;
1698 gbeauche 1.27 mach_msg_type_number_t thread_state_count;
1699    
1700     for (portIndex = 0; portIndex < oldExceptionPorts->maskCount; portIndex++) {
1701     if (oldExceptionPorts->masks[portIndex] & (1 << exception_type)) {
1702     // This handler wants the exception
1703     break;
1704     }
1705     }
1706    
1707     if (portIndex >= oldExceptionPorts->maskCount) {
1708     fprintf(stderr, "No handler for exception_type = %d. Not fowarding\n", exception_type);
1709     return KERN_FAILURE;
1710     }
1711    
1712     port = oldExceptionPorts->handlers[portIndex];
1713     behavior = oldExceptionPorts->behaviors[portIndex];
1714     flavor = oldExceptionPorts->flavors[portIndex];
1715    
1716 gbeauche 1.63 if (!VALID_THREAD_STATE_FLAVOR(flavor)) {
1717     fprintf(stderr, "Invalid thread_state flavor = %d. Not forwarding\n", flavor);
1718     return KERN_FAILURE;
1719     }
1720    
1721 gbeauche 1.27 /*
1722     fprintf(stderr, "forwarding exception, port = 0x%x, behaviour = %d, flavor = %d\n", port, behavior, flavor);
1723     */
1724    
1725     if (behavior != EXCEPTION_DEFAULT) {
1726     thread_state_count = THREAD_STATE_MAX;
1727 gbeauche 1.60 kret = thread_get_state (thread_port, flavor, (natural_t *)&thread_state,
1728 gbeauche 1.27 &thread_state_count);
1729     MACH_CHECK_ERROR (thread_get_state, kret);
1730     }
1731    
1732     switch (behavior) {
1733     case EXCEPTION_DEFAULT:
1734     // fprintf(stderr, "forwarding to exception_raise\n");
1735     kret = exception_raise(port, thread_port, task_port, exception_type,
1736     exception_data, data_count);
1737     MACH_CHECK_ERROR (exception_raise, kret);
1738     break;
1739     case EXCEPTION_STATE:
1740     // fprintf(stderr, "forwarding to exception_raise_state\n");
1741     kret = exception_raise_state(port, exception_type, exception_data,
1742     data_count, &flavor,
1743 gbeauche 1.60 (natural_t *)&thread_state, thread_state_count,
1744     (natural_t *)&thread_state, &thread_state_count);
1745 gbeauche 1.27 MACH_CHECK_ERROR (exception_raise_state, kret);
1746     break;
1747     case EXCEPTION_STATE_IDENTITY:
1748     // fprintf(stderr, "forwarding to exception_raise_state_identity\n");
1749     kret = exception_raise_state_identity(port, thread_port, task_port,
1750     exception_type, exception_data,
1751     data_count, &flavor,
1752 gbeauche 1.60 (natural_t *)&thread_state, thread_state_count,
1753     (natural_t *)&thread_state, &thread_state_count);
1754 gbeauche 1.27 MACH_CHECK_ERROR (exception_raise_state_identity, kret);
1755     break;
1756     default:
1757     fprintf(stderr, "forward_exception got unknown behavior\n");
1758 gbeauche 1.63 kret = KERN_FAILURE;
1759 gbeauche 1.27 break;
1760     }
1761    
1762     if (behavior != EXCEPTION_DEFAULT) {
1763 gbeauche 1.60 kret = thread_set_state (thread_port, flavor, (natural_t *)&thread_state,
1764 gbeauche 1.27 thread_state_count);
1765     MACH_CHECK_ERROR (thread_set_state, kret);
1766     }
1767    
1768 gbeauche 1.63 return kret;
1769 gbeauche 1.27 }
1770    
1771     /*
1772     * This is the code that actually handles the exception.
1773     * It is called by exc_server. For Darwin 5 Apple changed
1774     * this a bit from how this family of functions worked in
1775     * Mach. If you are familiar with that it is a little
1776     * different. The main variation that concerns us here is
1777     * that code is an array of exception specific codes and
1778     * codeCount is a count of the number of codes in the code
1779     * array. In typical Mach all exceptions have a code
1780     * and sub-code. It happens to be the case that for a
1781     * EXC_BAD_ACCESS exception the first entry is the type of
1782     * bad access that occurred and the second entry is the
1783     * faulting address so these entries correspond exactly to
1784     * how the code and sub-code are used on Mach.
1785     *
1786     * This is a MIG interface. No code in Basilisk II should
1787     * call this directley. This has to have external C
1788     * linkage because that is what exc_server expects.
1789     */
1790     kern_return_t
1791     catch_exception_raise(mach_port_t exception_port,
1792     mach_port_t thread,
1793     mach_port_t task,
1794     exception_type_t exception,
1795     exception_data_t code,
1796     mach_msg_type_number_t codeCount)
1797     {
1798 gbeauche 1.56 SIGSEGV_THREAD_STATE_TYPE state;
1799 gbeauche 1.27 kern_return_t krc;
1800    
1801     if ((exception == EXC_BAD_ACCESS) && (codeCount >= 2)) {
1802     if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS))
1803     return KERN_SUCCESS;
1804     }
1805    
1806     // In Mach we do not need to remove the exception handler.
1807     // If we forward the exception, eventually some exception handler
1808     // will take care of this exception.
1809     krc = forward_exception(thread, task, exception, code, codeCount, &ports);
1810    
1811     return krc;
1812     }
1813     #endif
1814    
1815     #ifdef HAVE_SIGSEGV_RECOVERY
1816     // Handle bad memory accesses with signal handler
1817     static void sigsegv_handler(SIGSEGV_FAULT_HANDLER_ARGLIST)
1818     {
1819     // Call handler and reinstall the global handler, if required
1820     if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS)) {
1821     #if (defined(HAVE_SIGACTION) ? defined(SIGACTION_NEED_REINSTALL) : defined(SIGNAL_NEED_REINSTALL))
1822     sigsegv_do_install_handler(sig);
1823     #endif
1824     return;
1825     }
1826 gbeauche 1.10
1827 gbeauche 1.27 // Failure: reinstall default handler for "safe" crash
1828 gbeauche 1.1 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
1829 gbeauche 1.27 SIGSEGV_ALL_SIGNALS
1830 gbeauche 1.1 #undef FAULT_HANDLER
1831     }
1832 gbeauche 1.2 #endif
1833 gbeauche 1.1
1834    
1835     /*
1836     * SIGSEGV handler initialization
1837     */
1838    
1839     #if defined(HAVE_SIGINFO_T)
1840     static bool sigsegv_do_install_handler(int sig)
1841     {
1842     // Setup SIGSEGV handler to process writes to frame buffer
1843     #ifdef HAVE_SIGACTION
1844 gbeauche 1.22 struct sigaction sigsegv_sa;
1845     sigemptyset(&sigsegv_sa.sa_mask);
1846     sigsegv_sa.sa_sigaction = sigsegv_handler;
1847     sigsegv_sa.sa_flags = SA_SIGINFO;
1848     return (sigaction(sig, &sigsegv_sa, 0) == 0);
1849 gbeauche 1.1 #else
1850     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
1851     #endif
1852     }
1853 gbeauche 1.2 #endif
1854    
1855     #if defined(HAVE_SIGCONTEXT_SUBTERFUGE)
1856 gbeauche 1.1 static bool sigsegv_do_install_handler(int sig)
1857     {
1858     // Setup SIGSEGV handler to process writes to frame buffer
1859     #ifdef HAVE_SIGACTION
1860 gbeauche 1.22 struct sigaction sigsegv_sa;
1861     sigemptyset(&sigsegv_sa.sa_mask);
1862     sigsegv_sa.sa_handler = (signal_handler)sigsegv_handler;
1863     sigsegv_sa.sa_flags = 0;
1864 gbeauche 1.1 #if !EMULATED_68K && defined(__NetBSD__)
1865 gbeauche 1.22 sigaddset(&sigsegv_sa.sa_mask, SIGALRM);
1866     sigsegv_sa.sa_flags |= SA_ONSTACK;
1867 gbeauche 1.1 #endif
1868 gbeauche 1.22 return (sigaction(sig, &sigsegv_sa, 0) == 0);
1869 gbeauche 1.1 #else
1870     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
1871     #endif
1872     }
1873     #endif
1874    
1875 gbeauche 1.27 #if defined(HAVE_MACH_EXCEPTIONS)
1876     static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
1877     {
1878     /*
1879     * Except for the exception port functions, this should be
1880     * pretty much stock Mach. If later you choose to support
1881     * other Mach's besides Darwin, just check for __MACH__
1882     * here and __APPLE__ where the actual differences are.
1883     */
1884     #if defined(__APPLE__) && defined(__MACH__)
1885     if (sigsegv_fault_handler != NULL) {
1886     sigsegv_fault_handler = handler;
1887     return true;
1888     }
1889    
1890     kern_return_t krc;
1891    
1892     // create the the exception port
1893     krc = mach_port_allocate(mach_task_self(),
1894     MACH_PORT_RIGHT_RECEIVE, &_exceptionPort);
1895     if (krc != KERN_SUCCESS) {
1896     mach_error("mach_port_allocate", krc);
1897     return false;
1898     }
1899    
1900     // add a port send right
1901     krc = mach_port_insert_right(mach_task_self(),
1902     _exceptionPort, _exceptionPort,
1903     MACH_MSG_TYPE_MAKE_SEND);
1904     if (krc != KERN_SUCCESS) {
1905     mach_error("mach_port_insert_right", krc);
1906     return false;
1907     }
1908    
1909     // get the old exception ports
1910     ports.maskCount = sizeof (ports.masks) / sizeof (ports.masks[0]);
1911     krc = thread_get_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, ports.masks,
1912     &ports.maskCount, ports.handlers, ports.behaviors, ports.flavors);
1913     if (krc != KERN_SUCCESS) {
1914     mach_error("thread_get_exception_ports", krc);
1915     return false;
1916     }
1917    
1918     // set the new exception port
1919     //
1920     // We could have used EXCEPTION_STATE_IDENTITY instead of
1921     // EXCEPTION_DEFAULT to get the thread state in the initial
1922     // message, but it turns out that in the common case this is not
1923     // neccessary. If we need it we can later ask for it from the
1924     // suspended thread.
1925     //
1926     // Even with THREAD_STATE_NONE, Darwin provides the program
1927     // counter in the thread state. The comments in the header file
1928     // seem to imply that you can count on the GPR's on an exception
1929     // as well but just to be safe I use MACHINE_THREAD_STATE because
1930     // you have to ask for all of the GPR's anyway just to get the
1931     // program counter. In any case because of update effective
1932     // address from immediate and update address from effective
1933     // addresses of ra and rb modes (as good an name as any for these
1934     // addressing modes) used in PPC instructions, you will need the
1935     // GPR state anyway.
1936     krc = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, _exceptionPort,
1937 gbeauche 1.56 EXCEPTION_DEFAULT, SIGSEGV_THREAD_STATE_FLAVOR);
1938 gbeauche 1.27 if (krc != KERN_SUCCESS) {
1939     mach_error("thread_set_exception_ports", krc);
1940     return false;
1941     }
1942    
1943     // create the exception handler thread
1944     if (pthread_create(&exc_thread, NULL, &handleExceptions, NULL) != 0) {
1945     (void)fprintf(stderr, "creation of exception thread failed\n");
1946     return false;
1947     }
1948    
1949     // do not care about the exception thread any longer, let is run standalone
1950     (void)pthread_detach(exc_thread);
1951    
1952     sigsegv_fault_handler = handler;
1953     return true;
1954     #else
1955     return false;
1956     #endif
1957     }
1958     #endif
1959    
1960 gbeauche 1.48 #ifdef HAVE_WIN32_EXCEPTIONS
1961     static LONG WINAPI main_exception_filter(EXCEPTION_POINTERS *ExceptionInfo)
1962     {
1963     if (sigsegv_fault_handler != NULL
1964     && ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION
1965     && ExceptionInfo->ExceptionRecord->NumberParameters == 2
1966     && handle_badaccess(ExceptionInfo))
1967     return EXCEPTION_CONTINUE_EXECUTION;
1968    
1969     return EXCEPTION_CONTINUE_SEARCH;
1970     }
1971    
1972     #if defined __CYGWIN__ && defined __i386__
1973     /* In Cygwin programs, SetUnhandledExceptionFilter has no effect because Cygwin
1974     installs a global exception handler. We have to dig deep in order to install
1975     our main_exception_filter. */
1976    
1977     /* Data structures for the current thread's exception handler chain.
1978     On the x86 Windows uses register fs, offset 0 to point to the current
1979     exception handler; Cygwin mucks with it, so we must do the same... :-/ */
1980    
1981     /* Magic taken from winsup/cygwin/include/exceptions.h. */
1982    
1983     struct exception_list {
1984     struct exception_list *prev;
1985     int (*handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
1986     };
1987     typedef struct exception_list exception_list;
1988    
1989     /* Magic taken from winsup/cygwin/exceptions.cc. */
1990    
1991     __asm__ (".equ __except_list,0");
1992    
1993     extern exception_list *_except_list __asm__ ("%fs:__except_list");
1994    
1995     /* For debugging. _except_list is not otherwise accessible from gdb. */
1996     static exception_list *
1997     debug_get_except_list ()
1998     {
1999     return _except_list;
2000     }
2001    
2002     /* Cygwin's original exception handler. */
2003     static int (*cygwin_exception_handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
2004    
2005     /* Our exception handler. */
2006     static int
2007     libsigsegv_exception_handler (EXCEPTION_RECORD *exception, void *frame, CONTEXT *context, void *dispatch)
2008     {
2009     EXCEPTION_POINTERS ExceptionInfo;
2010     ExceptionInfo.ExceptionRecord = exception;
2011     ExceptionInfo.ContextRecord = context;
2012     if (main_exception_filter (&ExceptionInfo) == EXCEPTION_CONTINUE_SEARCH)
2013     return cygwin_exception_handler (exception, frame, context, dispatch);
2014     else
2015     return 0;
2016     }
2017    
2018     static void
2019     do_install_main_exception_filter ()
2020     {
2021     /* We cannot insert any handler into the chain, because such handlers
2022     must lie on the stack (?). Instead, we have to replace(!) Cygwin's
2023     global exception handler. */
2024     cygwin_exception_handler = _except_list->handler;
2025     _except_list->handler = libsigsegv_exception_handler;
2026     }
2027    
2028     #else
2029    
2030     static void
2031     do_install_main_exception_filter ()
2032     {
2033     SetUnhandledExceptionFilter ((LPTOP_LEVEL_EXCEPTION_FILTER) &main_exception_filter);
2034     }
2035     #endif
2036    
2037     static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
2038     {
2039     static bool main_exception_filter_installed = false;
2040     if (!main_exception_filter_installed) {
2041     do_install_main_exception_filter();
2042     main_exception_filter_installed = true;
2043     }
2044     sigsegv_fault_handler = handler;
2045     return true;
2046     }
2047     #endif
2048    
2049 gbeauche 1.12 bool sigsegv_install_handler(sigsegv_fault_handler_t handler)
2050 gbeauche 1.1 {
2051 gbeauche 1.27 #if defined(HAVE_SIGSEGV_RECOVERY)
2052 gbeauche 1.1 bool success = true;
2053     #define FAULT_HANDLER(sig) success = success && sigsegv_do_install_handler(sig);
2054     SIGSEGV_ALL_SIGNALS
2055     #undef FAULT_HANDLER
2056 gbeauche 1.27 if (success)
2057     sigsegv_fault_handler = handler;
2058 gbeauche 1.1 return success;
2059 gbeauche 1.48 #elif defined(HAVE_MACH_EXCEPTIONS) || defined(HAVE_WIN32_EXCEPTIONS)
2060 gbeauche 1.27 return sigsegv_do_install_handler(handler);
2061 gbeauche 1.1 #else
2062     // FAIL: no siginfo_t nor sigcontext subterfuge is available
2063     return false;
2064     #endif
2065     }
2066    
2067    
2068     /*
2069     * SIGSEGV handler deinitialization
2070     */
2071    
2072     void sigsegv_deinstall_handler(void)
2073     {
2074 gbeauche 1.27 // We do nothing for Mach exceptions, the thread would need to be
2075     // suspended if not already so, and we might mess with other
2076     // exception handlers that came after we registered ours. There is
2077     // no need to remove the exception handler, in fact this function is
2078     // not called anywhere in Basilisk II.
2079 gbeauche 1.2 #ifdef HAVE_SIGSEGV_RECOVERY
2080 gbeauche 1.12 sigsegv_fault_handler = 0;
2081 gbeauche 1.1 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
2082     SIGSEGV_ALL_SIGNALS
2083     #undef FAULT_HANDLER
2084 gbeauche 1.2 #endif
2085 gbeauche 1.48 #ifdef HAVE_WIN32_EXCEPTIONS
2086     sigsegv_fault_handler = NULL;
2087     #endif
2088 gbeauche 1.1 }
2089    
2090 gbeauche 1.10
2091     /*
2092     * Set callback function when we cannot handle the fault
2093     */
2094    
2095 gbeauche 1.12 void sigsegv_set_dump_state(sigsegv_state_dumper_t handler)
2096 gbeauche 1.10 {
2097 gbeauche 1.12 sigsegv_state_dumper = handler;
2098 gbeauche 1.10 }
2099    
2100    
2101 gbeauche 1.1 /*
2102     * Test program used for configure/test
2103     */
2104    
2105 gbeauche 1.4 #ifdef CONFIGURE_TEST_SIGSEGV_RECOVERY
2106 gbeauche 1.1 #include <stdio.h>
2107     #include <stdlib.h>
2108     #include <fcntl.h>
2109 gbeauche 1.48 #ifdef HAVE_SYS_MMAN_H
2110 gbeauche 1.1 #include <sys/mman.h>
2111 gbeauche 1.48 #endif
2112 gbeauche 1.4 #include "vm_alloc.h"
2113 gbeauche 1.1
2114 gbeauche 1.32 const int REF_INDEX = 123;
2115     const int REF_VALUE = 45;
2116    
2117 gbeauche 1.1 static int page_size;
2118 gbeauche 1.3 static volatile char * page = 0;
2119     static volatile int handler_called = 0;
2120 gbeauche 1.1
2121 gbeauche 1.61 /* Barriers */
2122     #ifdef __GNUC__
2123     #define BARRIER() asm volatile ("" : : : "memory")
2124     #else
2125     #define BARRIER() /* nothing */
2126     #endif
2127    
2128 gbeauche 1.32 #ifdef __GNUC__
2129     // Code range where we expect the fault to come from
2130     static void *b_region, *e_region;
2131     #endif
2132    
2133 gbeauche 1.24 static sigsegv_return_t sigsegv_test_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
2134 gbeauche 1.1 {
2135 gbeauche 1.39 #if DEBUG
2136     printf("sigsegv_test_handler(%p, %p)\n", fault_address, instruction_address);
2137     printf("expected fault at %p\n", page + REF_INDEX);
2138     #ifdef __GNUC__
2139     printf("expected instruction address range: %p-%p\n", b_region, e_region);
2140     #endif
2141     #endif
2142 gbeauche 1.1 handler_called++;
2143 gbeauche 1.32 if ((fault_address - REF_INDEX) != page)
2144 gbeauche 1.29 exit(10);
2145 gbeauche 1.32 #ifdef __GNUC__
2146     // Make sure reported fault instruction address falls into
2147     // expected code range
2148     if (instruction_address != SIGSEGV_INVALID_PC
2149     && ((instruction_address < (sigsegv_address_t)b_region) ||
2150     (instruction_address >= (sigsegv_address_t)e_region)))
2151     exit(11);
2152     #endif
2153 gbeauche 1.4 if (vm_protect((char *)((unsigned long)fault_address & -page_size), page_size, VM_PAGE_READ | VM_PAGE_WRITE) != 0)
2154 gbeauche 1.32 exit(12);
2155 gbeauche 1.24 return SIGSEGV_RETURN_SUCCESS;
2156 gbeauche 1.1 }
2157    
2158 gbeauche 1.10 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
2159 gbeauche 1.24 static sigsegv_return_t sigsegv_insn_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
2160 gbeauche 1.10 {
2161 gbeauche 1.44 #if DEBUG
2162     printf("sigsegv_insn_handler(%p, %p)\n", fault_address, instruction_address);
2163     #endif
2164 gbeauche 1.28 if (((unsigned long)fault_address - (unsigned long)page) < page_size) {
2165     #ifdef __GNUC__
2166     // Make sure reported fault instruction address falls into
2167     // expected code range
2168     if (instruction_address != SIGSEGV_INVALID_PC
2169     && ((instruction_address < (sigsegv_address_t)b_region) ||
2170     (instruction_address >= (sigsegv_address_t)e_region)))
2171     return SIGSEGV_RETURN_FAILURE;
2172     #endif
2173 gbeauche 1.26 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
2174 gbeauche 1.28 }
2175    
2176 gbeauche 1.24 return SIGSEGV_RETURN_FAILURE;
2177 gbeauche 1.10 }
2178 gbeauche 1.34
2179     // More sophisticated tests for instruction skipper
2180     static bool arch_insn_skipper_tests()
2181     {
2182     #if (defined(i386) || defined(__i386__)) || defined(__x86_64__)
2183     static const unsigned char code[] = {
2184     0x8a, 0x00, // mov (%eax),%al
2185     0x8a, 0x2c, 0x18, // mov (%eax,%ebx,1),%ch
2186     0x88, 0x20, // mov %ah,(%eax)
2187     0x88, 0x08, // mov %cl,(%eax)
2188     0x66, 0x8b, 0x00, // mov (%eax),%ax
2189     0x66, 0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%cx
2190     0x66, 0x89, 0x00, // mov %ax,(%eax)
2191     0x66, 0x89, 0x0c, 0x18, // mov %cx,(%eax,%ebx,1)
2192     0x8b, 0x00, // mov (%eax),%eax
2193     0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%ecx
2194     0x89, 0x00, // mov %eax,(%eax)
2195     0x89, 0x0c, 0x18, // mov %ecx,(%eax,%ebx,1)
2196     #if defined(__x86_64__)
2197     0x44, 0x8a, 0x00, // mov (%rax),%r8b
2198     0x44, 0x8a, 0x20, // mov (%rax),%r12b
2199     0x42, 0x8a, 0x3c, 0x10, // mov (%rax,%r10,1),%dil
2200     0x44, 0x88, 0x00, // mov %r8b,(%rax)
2201     0x44, 0x88, 0x20, // mov %r12b,(%rax)
2202     0x42, 0x88, 0x3c, 0x10, // mov %dil,(%rax,%r10,1)
2203     0x66, 0x44, 0x8b, 0x00, // mov (%rax),%r8w
2204     0x66, 0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%cx
2205     0x66, 0x44, 0x89, 0x00, // mov %r8w,(%rax)
2206     0x66, 0x42, 0x89, 0x0c, 0x10, // mov %cx,(%rax,%r10,1)
2207     0x44, 0x8b, 0x00, // mov (%rax),%r8d
2208     0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%ecx
2209     0x44, 0x89, 0x00, // mov %r8d,(%rax)
2210     0x42, 0x89, 0x0c, 0x10, // mov %ecx,(%rax,%r10,1)
2211     0x48, 0x8b, 0x08, // mov (%rax),%rcx
2212     0x4c, 0x8b, 0x18, // mov (%rax),%r11
2213     0x4a, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%rcx
2214     0x4e, 0x8b, 0x1c, 0x10, // mov (%rax,%r10,1),%r11
2215     0x48, 0x89, 0x08, // mov %rcx,(%rax)
2216     0x4c, 0x89, 0x18, // mov %r11,(%rax)
2217     0x4a, 0x89, 0x0c, 0x10, // mov %rcx,(%rax,%r10,1)
2218     0x4e, 0x89, 0x1c, 0x10, // mov %r11,(%rax,%r10,1)
2219 gbeauche 1.62 0x63, 0x47, 0x04, // movslq 4(%rdi),%eax
2220     0x48, 0x63, 0x47, 0x04, // movslq 4(%rdi),%rax
2221 gbeauche 1.34 #endif
2222     0 // end
2223     };
2224     const int N_REGS = 20;
2225     unsigned long regs[N_REGS];
2226     for (int i = 0; i < N_REGS; i++)
2227     regs[i] = i;
2228     const unsigned long start_code = (unsigned long)&code;
2229     regs[X86_REG_EIP] = start_code;
2230     while ((regs[X86_REG_EIP] - start_code) < (sizeof(code) - 1)
2231     && ix86_skip_instruction(regs))
2232     ; /* simply iterate */
2233     return (regs[X86_REG_EIP] - start_code) == (sizeof(code) - 1);
2234     #endif
2235     return true;
2236     }
2237 gbeauche 1.10 #endif
2238    
2239 gbeauche 1.1 int main(void)
2240     {
2241 gbeauche 1.4 if (vm_init() < 0)
2242 gbeauche 1.1 return 1;
2243    
2244 gbeauche 1.54 page_size = vm_get_page_size();
2245 gbeauche 1.4 if ((page = (char *)vm_acquire(page_size)) == VM_MAP_FAILED)
2246 gbeauche 1.29 return 2;
2247 gbeauche 1.4
2248 gbeauche 1.32 memset((void *)page, 0, page_size);
2249 gbeauche 1.4 if (vm_protect((char *)page, page_size, VM_PAGE_READ) < 0)
2250 gbeauche 1.29 return 3;
2251 gbeauche 1.1
2252     if (!sigsegv_install_handler(sigsegv_test_handler))
2253 gbeauche 1.29 return 4;
2254 gbeauche 1.1
2255 gbeauche 1.32 #ifdef __GNUC__
2256     b_region = &&L_b_region1;
2257     e_region = &&L_e_region1;
2258     #endif
2259     L_b_region1:
2260     page[REF_INDEX] = REF_VALUE;
2261     if (page[REF_INDEX] != REF_VALUE)
2262     exit(20);
2263     page[REF_INDEX] = REF_VALUE;
2264 gbeauche 1.61 BARRIER();
2265 gbeauche 1.32 L_e_region1:
2266    
2267 gbeauche 1.1 if (handler_called != 1)
2268 gbeauche 1.29 return 5;
2269 gbeauche 1.10
2270     #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
2271     if (!sigsegv_install_handler(sigsegv_insn_handler))
2272 gbeauche 1.29 return 6;
2273 gbeauche 1.10
2274 gbeauche 1.17 if (vm_protect((char *)page, page_size, VM_PAGE_READ | VM_PAGE_WRITE) < 0)
2275 gbeauche 1.29 return 7;
2276 gbeauche 1.10
2277     for (int i = 0; i < page_size; i++)
2278     page[i] = (i + 1) % page_size;
2279    
2280     if (vm_protect((char *)page, page_size, VM_PAGE_NOACCESS) < 0)
2281 gbeauche 1.29 return 8;
2282 gbeauche 1.10
2283     #define TEST_SKIP_INSTRUCTION(TYPE) do { \
2284 gbeauche 1.34 const unsigned long TAG = 0x12345678 | \
2285     (sizeof(long) == 8 ? 0x9abcdef0UL << 31 : 0); \
2286 gbeauche 1.10 TYPE data = *((TYPE *)(page + sizeof(TYPE))); \
2287 gbeauche 1.34 volatile unsigned long effect = data + TAG; \
2288 gbeauche 1.10 if (effect != TAG) \
2289 gbeauche 1.29 return 9; \
2290 gbeauche 1.10 } while (0)
2291    
2292 gbeauche 1.28 #ifdef __GNUC__
2293 gbeauche 1.32 b_region = &&L_b_region2;
2294     e_region = &&L_e_region2;
2295 gbeauche 1.28 #endif
2296 gbeauche 1.32 L_b_region2:
2297 gbeauche 1.10 TEST_SKIP_INSTRUCTION(unsigned char);
2298     TEST_SKIP_INSTRUCTION(unsigned short);
2299     TEST_SKIP_INSTRUCTION(unsigned int);
2300 gbeauche 1.34 TEST_SKIP_INSTRUCTION(unsigned long);
2301 gbeauche 1.44 TEST_SKIP_INSTRUCTION(signed char);
2302     TEST_SKIP_INSTRUCTION(signed short);
2303     TEST_SKIP_INSTRUCTION(signed int);
2304     TEST_SKIP_INSTRUCTION(signed long);
2305 gbeauche 1.61 BARRIER();
2306 gbeauche 1.32 L_e_region2:
2307 gbeauche 1.1
2308 gbeauche 1.34 if (!arch_insn_skipper_tests())
2309     return 20;
2310 gbeauche 1.35 #endif
2311 gbeauche 1.34
2312 gbeauche 1.4 vm_exit();
2313 gbeauche 1.1 return 0;
2314     }
2315     #endif