ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.76
Committed: 2008-01-06T16:36:00Z (16 years, 10 months ago) by gbeauche
Branch: MAIN
Changes since 1.75: +14 -9 lines
Log Message:
Further comment the ia64 decoder and (minimal) emulator.

File Contents

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