ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.53
Committed: 2005-02-20T11:39:12Z (19 years, 8 months ago) by gbeauche
Branch: MAIN
Changes since 1.52: +7 -0 lines
Log Message:
NetBSD/ppc support

File Contents

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