ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.75
Committed: 2008-01-06T16:25:03Z (16 years, 8 months ago) by gbeauche
Branch: MAIN
Changes since 1.74: +717 -1 lines
Log Message:
Add initial support for instruction skipping on Linux/ia64. It was more
complex than expected but it was fun to play with. Who designed this ISA?
I'd love to see how the decoder is implemented in HW, by all means it is
not "simplified" unless I missed some pattern...

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     unsigned char commit;
1230     unsigned char valid;
1231     signed char index;
1232     unsigned char nat;
1233     unsigned long value;
1234     };
1235    
1236     // Decoded instruction type
1237     struct ia64_instruction_t {
1238     unsigned char mnemo;
1239     unsigned char pred;
1240     unsigned char no_memory;
1241     unsigned long inst;
1242     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     if (inst->mnemo == IA64_INST_UNKNOWN)
1618     return false;
1619     if (inst->pred && !IA64_GET_PR(inst->pred))
1620     return true;
1621    
1622     unsigned char nat, nat2;
1623     unsigned long dst, dst2, src1, src2, src3;
1624    
1625     switch (inst->mnemo) {
1626     case IA64_INST_NOP:
1627     break;
1628     case IA64_INST_ADD:
1629     case IA64_INST_SUB:
1630     case IA64_INST_SHLADD:
1631     src3 = inst->operands[3].value;
1632     // fall-through
1633     case IA64_INST_AND:
1634     case IA64_INST_ANDCM:
1635     case IA64_INST_OR:
1636     case IA64_INST_XOR:
1637     src1 = inst->operands[1].value;
1638     src2 = inst->operands[2].value;
1639     switch (inst->mnemo) {
1640     case IA64_INST_ADD: dst = src1 + src2 + src3; break;
1641     case IA64_INST_SUB: dst = src1 - src2 - src3; break;
1642     case IA64_INST_SHLADD: dst = (src1 << src3) + src2; break;
1643     case IA64_INST_AND: dst = src1 & src2; break;
1644     case IA64_INST_ANDCM: dst = src1 &~ src2; break;
1645     case IA64_INST_OR: dst = src1 | src2; break;
1646     case IA64_INST_XOR: dst = src1 ^ src2; break;
1647     }
1648     inst->operands[0].commit = true;
1649     inst->operands[0].value = dst;
1650     inst->operands[0].nat = inst->operands[1].nat | inst->operands[2].nat;
1651     break;
1652     case IA64_INST_SXT1:
1653     case IA64_INST_SXT2:
1654     case IA64_INST_SXT4:
1655     case IA64_INST_ZXT1:
1656     case IA64_INST_ZXT2:
1657     case IA64_INST_ZXT4:
1658     src1 = inst->operands[1].value;
1659     switch (inst->mnemo) {
1660     case IA64_INST_SXT1: dst = (signed long)(signed char)src1; break;
1661     case IA64_INST_SXT2: dst = (signed long)(signed short)src1; break;
1662     case IA64_INST_SXT4: dst = (signed long)(signed int)src1; break;
1663     case IA64_INST_ZXT1: dst = (unsigned char)src1; break;
1664     case IA64_INST_ZXT2: dst = (unsigned short)src1; break;
1665     case IA64_INST_ZXT4: dst = (unsigned int)src1; break;
1666     }
1667     inst->operands[0].commit = true;
1668     inst->operands[0].value = dst;
1669     inst->operands[0].nat = inst->operands[1].nat;
1670     break;
1671     case IA64_INST_LD1_UPDATE:
1672     case IA64_INST_LD2_UPDATE:
1673     case IA64_INST_LD4_UPDATE:
1674     case IA64_INST_LD8_UPDATE:
1675     inst->operands[1].commit = true;
1676     dst2 = inst->operands[1].value + inst->operands[2].value;
1677     nat2 = inst->operands[2].nat ? inst->operands[2].nat : 0;
1678     // fall-through
1679     case IA64_INST_LD1:
1680     case IA64_INST_LD2:
1681     case IA64_INST_LD4:
1682     case IA64_INST_LD8:
1683     src1 = inst->operands[1].value;
1684     if (inst->no_memory)
1685     dst = 0;
1686     else {
1687     switch (inst->mnemo) {
1688     case IA64_INST_LD1: case IA64_INST_LD1_UPDATE: dst = *((unsigned char *)src1); break;
1689     case IA64_INST_LD2: case IA64_INST_LD2_UPDATE: dst = *((unsigned short *)src1); break;
1690     case IA64_INST_LD4: case IA64_INST_LD4_UPDATE: dst = *((unsigned int *)src1); break;
1691     case IA64_INST_LD8: case IA64_INST_LD8_UPDATE: dst = *((unsigned long *)src1); break;
1692     }
1693     }
1694     inst->operands[0].commit = true;
1695     inst->operands[0].value = dst;
1696     inst->operands[0].nat = 0;
1697     inst->operands[1].value = dst2;
1698     inst->operands[1].nat = nat2;
1699     break;
1700     case IA64_INST_ST1_UPDATE:
1701     case IA64_INST_ST2_UPDATE:
1702     case IA64_INST_ST4_UPDATE:
1703     case IA64_INST_ST8_UPDATE:
1704     inst->operands[0].commit = 0;
1705     dst2 = inst->operands[0].value + inst->operands[2].value;
1706     nat2 = inst->operands[2].nat ? inst->operands[2].nat : 0;
1707     // fall-through
1708     case IA64_INST_ST1:
1709     case IA64_INST_ST2:
1710     case IA64_INST_ST4:
1711     case IA64_INST_ST8:
1712     dst = inst->operands[0].value;
1713     src1 = inst->operands[1].value;
1714     if (!inst->no_memory) {
1715     switch (inst->mnemo) {
1716     case IA64_INST_ST1: case IA64_INST_ST1_UPDATE: *((unsigned char *)dst) = src1; break;
1717     case IA64_INST_ST2: case IA64_INST_ST2_UPDATE: *((unsigned short *)dst) = src1; break;
1718     case IA64_INST_ST4: case IA64_INST_ST4_UPDATE: *((unsigned int *)dst) = src1; break;
1719     case IA64_INST_ST8: case IA64_INST_ST8_UPDATE: *((unsigned long *)dst) = src1; break;
1720     }
1721     }
1722     inst->operands[0].value = dst2;
1723     inst->operands[0].nat = nat2;
1724     break;
1725     default:
1726     return false;
1727     }
1728    
1729     for (int i = 0; i < IA64_N_OPERANDS; i++) {
1730     ia64_operand_t const & op = inst->operands[i];
1731     if (!op.commit)
1732     continue;
1733     if (op.index == -1)
1734     return false; // XXX: internal error
1735     IA64_SET_GR(op.index, op.value);
1736     IA64_SET_NAT(op.index, op.nat);
1737     }
1738     return true;
1739     }
1740    
1741     static bool ia64_emulate_instruction(unsigned long raw_inst, unsigned long *ctx)
1742     {
1743     ia64_instruction_t inst;
1744     memset(&inst, 0, sizeof(inst));
1745     inst.inst = raw_inst;
1746     if (!ia64_decode_instruction(&inst, ctx))
1747     return false;
1748     return ia64_emulate_instruction(&inst, ctx);
1749     }
1750    
1751     static bool ia64_skip_instruction(unsigned long *ctx)
1752     {
1753     unsigned long ip = ctx[IA64_REG_IP];
1754     #if DEBUG
1755     printf("IP: 0x%016lx\n", ip);
1756     #if 0
1757     printf(" Template 0x%02x\n", ia64_get_template(ip));
1758     ia64_get_instruction(ip, 0);
1759     ia64_get_instruction(ip, 1);
1760     ia64_get_instruction(ip, 2);
1761     #endif
1762     #endif
1763    
1764     // Select which decode switch to use
1765     ia64_instruction_t inst;
1766     inst.inst = ia64_get_instruction(ip, ip & 3);
1767     if (!ia64_decode_instruction(&inst, ctx)) {
1768     fprintf(stderr, "ERROR: ia64_skip_instruction(): could not decode instruction\n");
1769     return false;
1770     }
1771    
1772     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1773     transfer_size_t transfer_size = SIZE_UNKNOWN;
1774    
1775     switch (inst.mnemo) {
1776     case IA64_INST_LD1:
1777     case IA64_INST_LD2:
1778     case IA64_INST_LD4:
1779     case IA64_INST_LD8:
1780     case IA64_INST_LD1_UPDATE:
1781     case IA64_INST_LD2_UPDATE:
1782     case IA64_INST_LD4_UPDATE:
1783     case IA64_INST_LD8_UPDATE:
1784     transfer_type = SIGSEGV_TRANSFER_LOAD;
1785     break;
1786     case IA64_INST_ST1:
1787     case IA64_INST_ST2:
1788     case IA64_INST_ST4:
1789     case IA64_INST_ST8:
1790     case IA64_INST_ST1_UPDATE:
1791     case IA64_INST_ST2_UPDATE:
1792     case IA64_INST_ST4_UPDATE:
1793     case IA64_INST_ST8_UPDATE:
1794     transfer_type = SIGSEGV_TRANSFER_STORE;
1795     break;
1796     }
1797    
1798     if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1799     // Unknown machine code, let it crash. Then patch the decoder
1800     fprintf(stderr, "ERROR: ia64_skip_instruction(): not a load/store instruction\n");
1801     return false;
1802     }
1803    
1804     switch (inst.mnemo) {
1805     case IA64_INST_LD1:
1806     case IA64_INST_LD1_UPDATE:
1807     case IA64_INST_ST1:
1808     case IA64_INST_ST1_UPDATE:
1809     transfer_size = SIZE_BYTE;
1810     break;
1811     case IA64_INST_LD2:
1812     case IA64_INST_LD2_UPDATE:
1813     case IA64_INST_ST2:
1814     case IA64_INST_ST2_UPDATE:
1815     transfer_size = SIZE_WORD;
1816     break;
1817     case IA64_INST_LD4:
1818     case IA64_INST_LD4_UPDATE:
1819     case IA64_INST_ST4:
1820     case IA64_INST_ST4_UPDATE:
1821     transfer_size = SIZE_LONG;
1822     break;
1823     case IA64_INST_LD8:
1824     case IA64_INST_LD8_UPDATE:
1825     case IA64_INST_ST8:
1826     case IA64_INST_ST8_UPDATE:
1827     transfer_size = SIZE_QUAD;
1828     break;
1829     }
1830    
1831     if (transfer_size == SIZE_UNKNOWN) {
1832     // Unknown machine code, let it crash. Then patch the decoder
1833     fprintf(stderr, "ERROR: ia64_skip_instruction(): unknown transfer size\n");
1834     return false;
1835     }
1836    
1837     inst.no_memory = true;
1838     if (!ia64_emulate_instruction(&inst, ctx)) {
1839     fprintf(stderr, "ERROR: ia64_skip_instruction(): could not emulate fault instruction\n");
1840     return false;
1841     }
1842    
1843     int slot = ip & 3;
1844     bool emulate_next = false;
1845     switch (slot) {
1846     case 0:
1847     switch (ia64_get_template(ip)) {
1848     case 0x2: // MI;I
1849     case 0x3: // MI;I;
1850     emulate_next = true;
1851     slot = 2;
1852     break;
1853     case 0xa: // M;MI
1854     case 0xb: // M;MI;
1855     emulate_next = true;
1856     slot = 1;
1857     break;
1858     }
1859     break;
1860     }
1861     if (emulate_next) {
1862     while (slot < 3) {
1863     if (!ia64_emulate_instruction(ia64_get_instruction(ip, slot), ctx)) {
1864     fprintf(stderr, "ERROR: ia64_skip_instruction(): could not emulate instruction\n");
1865     return false;
1866     }
1867     ++slot;
1868     }
1869     }
1870    
1871     ctx[IA64_REG_IP] = (ip & ~3ul) + 16;
1872     #if DEBUG
1873     printf("IP: 0x%016lx\n", ctx[IA64_REG_IP]);
1874     #endif
1875     return true;
1876     }
1877     #endif
1878    
1879 gbeauche 1.13 // Decode and skip PPC instruction
1880 gbeauche 1.69 #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__))
1881 gbeauche 1.49 static bool powerpc_skip_instruction(unsigned long * nip_p, unsigned long * regs)
1882 gbeauche 1.13 {
1883 gbeauche 1.14 instruction_t instr;
1884     powerpc_decode_instruction(&instr, *nip_p, regs);
1885 gbeauche 1.13
1886 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1887 gbeauche 1.13 // Unknown machine code, let it crash. Then patch the decoder
1888     return false;
1889     }
1890    
1891     #if DEBUG
1892 gbeauche 1.14 printf("%08x: %s %s access", *nip_p,
1893 gbeauche 1.49 instr.transfer_size == SIZE_BYTE ? "byte" :
1894     instr.transfer_size == SIZE_WORD ? "word" :
1895     instr.transfer_size == SIZE_LONG ? "long" : "quad",
1896 gbeauche 1.22 instr.transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
1897 gbeauche 1.14
1898     if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
1899     printf(" r%d (ra = %08x)\n", instr.ra, instr.addr);
1900 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
1901 gbeauche 1.14 printf(" r%d (rd = 0)\n", instr.rd);
1902     #endif
1903    
1904     if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
1905     regs[instr.ra] = instr.addr;
1906 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
1907 gbeauche 1.14 regs[instr.rd] = 0;
1908 gbeauche 1.13
1909 gbeauche 1.14 *nip_p += 4;
1910 gbeauche 1.10 return true;
1911 gbeauche 1.38 }
1912     #endif
1913    
1914     // Decode and skip MIPS instruction
1915     #if (defined(mips) || defined(__mips))
1916 gbeauche 1.65 static bool mips_skip_instruction(greg_t * pc_p, greg_t * regs)
1917 gbeauche 1.38 {
1918 gbeauche 1.65 unsigned int * epc = (unsigned int *)(unsigned long)*pc_p;
1919 gbeauche 1.38
1920     if (epc == 0)
1921     return false;
1922    
1923     #if DEBUG
1924     printf("IP: %p [%08x]\n", epc, epc[0]);
1925     #endif
1926    
1927     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1928     transfer_size_t transfer_size = SIZE_LONG;
1929     int direction = 0;
1930    
1931     const unsigned int opcode = epc[0];
1932     switch (opcode >> 26) {
1933     case 32: // Load Byte
1934     case 36: // Load Byte Unsigned
1935     transfer_type = SIGSEGV_TRANSFER_LOAD;
1936     transfer_size = SIZE_BYTE;
1937     break;
1938     case 33: // Load Halfword
1939     case 37: // Load Halfword Unsigned
1940     transfer_type = SIGSEGV_TRANSFER_LOAD;
1941     transfer_size = SIZE_WORD;
1942     break;
1943     case 35: // Load Word
1944     case 39: // Load Word Unsigned
1945     transfer_type = SIGSEGV_TRANSFER_LOAD;
1946     transfer_size = SIZE_LONG;
1947     break;
1948     case 34: // Load Word Left
1949     transfer_type = SIGSEGV_TRANSFER_LOAD;
1950     transfer_size = SIZE_LONG;
1951     direction = -1;
1952     break;
1953     case 38: // Load Word Right
1954     transfer_type = SIGSEGV_TRANSFER_LOAD;
1955     transfer_size = SIZE_LONG;
1956     direction = 1;
1957     break;
1958     case 55: // Load Doubleword
1959     transfer_type = SIGSEGV_TRANSFER_LOAD;
1960     transfer_size = SIZE_QUAD;
1961     break;
1962     case 26: // Load Doubleword Left
1963     transfer_type = SIGSEGV_TRANSFER_LOAD;
1964     transfer_size = SIZE_QUAD;
1965     direction = -1;
1966     break;
1967     case 27: // Load Doubleword Right
1968     transfer_type = SIGSEGV_TRANSFER_LOAD;
1969     transfer_size = SIZE_QUAD;
1970     direction = 1;
1971     break;
1972     case 40: // Store Byte
1973     transfer_type = SIGSEGV_TRANSFER_STORE;
1974     transfer_size = SIZE_BYTE;
1975     break;
1976     case 41: // Store Halfword
1977     transfer_type = SIGSEGV_TRANSFER_STORE;
1978     transfer_size = SIZE_WORD;
1979     break;
1980     case 43: // Store Word
1981     case 42: // Store Word Left
1982     case 46: // Store Word Right
1983     transfer_type = SIGSEGV_TRANSFER_STORE;
1984     transfer_size = SIZE_LONG;
1985     break;
1986     case 63: // Store Doubleword
1987     case 44: // Store Doubleword Left
1988     case 45: // Store Doubleword Right
1989     transfer_type = SIGSEGV_TRANSFER_STORE;
1990     transfer_size = SIZE_QUAD;
1991     break;
1992     /* Misc instructions unlikely to be used within CPU emulators */
1993     case 48: // Load Linked Word
1994     transfer_type = SIGSEGV_TRANSFER_LOAD;
1995     transfer_size = SIZE_LONG;
1996     break;
1997     case 52: // Load Linked Doubleword
1998     transfer_type = SIGSEGV_TRANSFER_LOAD;
1999     transfer_size = SIZE_QUAD;
2000     break;
2001     case 56: // Store Conditional Word
2002     transfer_type = SIGSEGV_TRANSFER_STORE;
2003     transfer_size = SIZE_LONG;
2004     break;
2005     case 60: // Store Conditional Doubleword
2006     transfer_type = SIGSEGV_TRANSFER_STORE;
2007     transfer_size = SIZE_QUAD;
2008     break;
2009     }
2010    
2011     if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
2012     // Unknown machine code, let it crash. Then patch the decoder
2013     return false;
2014     }
2015    
2016     // Zero target register in case of a load operation
2017     const int reg = (opcode >> 16) & 0x1f;
2018     if (transfer_type == SIGSEGV_TRANSFER_LOAD) {
2019     if (direction == 0)
2020     regs[reg] = 0;
2021     else {
2022     // FIXME: untested code
2023     unsigned long ea = regs[(opcode >> 21) & 0x1f];
2024     ea += (signed long)(signed int)(signed short)(opcode & 0xffff);
2025     const int offset = ea & (transfer_size == SIZE_LONG ? 3 : 7);
2026     unsigned long value;
2027     if (direction > 0) {
2028     const unsigned long rmask = ~((1L << ((offset + 1) * 8)) - 1);
2029     value = regs[reg] & rmask;
2030     }
2031     else {
2032     const unsigned long lmask = (1L << (offset * 8)) - 1;
2033     value = regs[reg] & lmask;
2034     }
2035     // restore most significant bits
2036     if (transfer_size == SIZE_LONG)
2037     value = (signed long)(signed int)value;
2038     regs[reg] = value;
2039     }
2040     }
2041    
2042     #if DEBUG
2043     #if (defined(_ABIN32) || defined(_ABI64))
2044     static const char * mips_gpr_names[32] = {
2045     "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
2046     "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
2047     "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
2048     "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
2049     };
2050     #else
2051     static const char * mips_gpr_names[32] = {
2052     "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
2053     "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
2054     "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
2055     "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
2056     };
2057     #endif
2058     printf("%s %s register %s\n",
2059     transfer_size == SIZE_BYTE ? "byte" :
2060     transfer_size == SIZE_WORD ? "word" :
2061     transfer_size == SIZE_LONG ? "long" :
2062     transfer_size == SIZE_QUAD ? "quad" : "unknown",
2063     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
2064     mips_gpr_names[reg]);
2065     #endif
2066    
2067 gbeauche 1.65 *pc_p += 4;
2068 gbeauche 1.40 return true;
2069     }
2070     #endif
2071    
2072     // Decode and skip SPARC instruction
2073     #if (defined(sparc) || defined(__sparc__))
2074     enum {
2075     #if (defined(__sun__))
2076     SPARC_REG_G1 = REG_G1,
2077     SPARC_REG_O0 = REG_O0,
2078     SPARC_REG_PC = REG_PC,
2079 gbeauche 1.59 SPARC_REG_nPC = REG_nPC
2080 gbeauche 1.40 #endif
2081     };
2082     static bool sparc_skip_instruction(unsigned long * regs, gwindows_t * gwins, struct rwindow * rwin)
2083     {
2084     unsigned int * pc = (unsigned int *)regs[SPARC_REG_PC];
2085    
2086     if (pc == 0)
2087     return false;
2088    
2089     #if DEBUG
2090     printf("IP: %p [%08x]\n", pc, pc[0]);
2091     #endif
2092    
2093     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
2094     transfer_size_t transfer_size = SIZE_LONG;
2095     bool register_pair = false;
2096    
2097     const unsigned int opcode = pc[0];
2098     if ((opcode >> 30) != 3)
2099     return false;
2100     switch ((opcode >> 19) & 0x3f) {
2101     case 9: // Load Signed Byte
2102     case 1: // Load Unsigned Byte
2103     transfer_type = SIGSEGV_TRANSFER_LOAD;
2104     transfer_size = SIZE_BYTE;
2105     break;
2106     case 10:// Load Signed Halfword
2107     case 2: // Load Unsigned Word
2108     transfer_type = SIGSEGV_TRANSFER_LOAD;
2109     transfer_size = SIZE_WORD;
2110     break;
2111     case 8: // Load Word
2112     case 0: // Load Unsigned Word
2113     transfer_type = SIGSEGV_TRANSFER_LOAD;
2114     transfer_size = SIZE_LONG;
2115     break;
2116     case 11:// Load Extended Word
2117     transfer_type = SIGSEGV_TRANSFER_LOAD;
2118     transfer_size = SIZE_QUAD;
2119     break;
2120     case 3: // Load Doubleword
2121     transfer_type = SIGSEGV_TRANSFER_LOAD;
2122     transfer_size = SIZE_LONG;
2123     register_pair = true;
2124     break;
2125     case 5: // Store Byte
2126     transfer_type = SIGSEGV_TRANSFER_STORE;
2127     transfer_size = SIZE_BYTE;
2128     break;
2129     case 6: // Store Halfword
2130     transfer_type = SIGSEGV_TRANSFER_STORE;
2131     transfer_size = SIZE_WORD;
2132     break;
2133     case 4: // Store Word
2134     transfer_type = SIGSEGV_TRANSFER_STORE;
2135     transfer_size = SIZE_LONG;
2136     break;
2137     case 14:// Store Extended Word
2138     transfer_type = SIGSEGV_TRANSFER_STORE;
2139     transfer_size = SIZE_QUAD;
2140     break;
2141     case 7: // Store Doubleword
2142     transfer_type = SIGSEGV_TRANSFER_STORE;
2143 gbeauche 1.58 transfer_size = SIZE_LONG;
2144 gbeauche 1.40 register_pair = true;
2145     break;
2146     }
2147    
2148     if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
2149     // Unknown machine code, let it crash. Then patch the decoder
2150     return false;
2151     }
2152    
2153 gbeauche 1.58 const int reg = (opcode >> 25) & 0x1f;
2154    
2155     #if DEBUG
2156     static const char * reg_names[] = {
2157     "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
2158     "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
2159     "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
2160     "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"
2161     };
2162     printf("%s %s register %s\n",
2163     transfer_size == SIZE_BYTE ? "byte" :
2164     transfer_size == SIZE_WORD ? "word" :
2165     transfer_size == SIZE_LONG ? "long" :
2166     transfer_size == SIZE_QUAD ? "quad" : "unknown",
2167     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
2168     reg_names[reg]);
2169     #endif
2170    
2171 gbeauche 1.40 // Zero target register in case of a load operation
2172     if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != 0) {
2173     // FIXME: code to handle local & input registers is not tested
2174 gbeauche 1.58 if (reg >= 1 && reg < 8) {
2175 gbeauche 1.40 // global registers
2176     regs[reg - 1 + SPARC_REG_G1] = 0;
2177     }
2178 gbeauche 1.58 else if (reg >= 8 && reg < 16) {
2179 gbeauche 1.40 // output registers
2180     regs[reg - 8 + SPARC_REG_O0] = 0;
2181     }
2182 gbeauche 1.58 else if (reg >= 16 && reg < 24) {
2183 gbeauche 1.40 // local registers (in register windows)
2184     if (gwins)
2185     gwins->wbuf->rw_local[reg - 16] = 0;
2186     else
2187     rwin->rw_local[reg - 16] = 0;
2188     }
2189     else {
2190     // input registers (in register windows)
2191     if (gwins)
2192     gwins->wbuf->rw_in[reg - 24] = 0;
2193     else
2194     rwin->rw_in[reg - 24] = 0;
2195     }
2196     }
2197    
2198     regs[SPARC_REG_PC] += 4;
2199 gbeauche 1.59 regs[SPARC_REG_nPC] += 4;
2200 gbeauche 1.38 return true;
2201 gbeauche 1.10 }
2202     #endif
2203     #endif
2204    
2205 gbeauche 1.44 // Decode and skip ARM instruction
2206     #if (defined(arm) || defined(__arm__))
2207     enum {
2208     #if (defined(__linux__))
2209     ARM_REG_PC = 15,
2210     ARM_REG_CPSR = 16
2211     #endif
2212     };
2213     static bool arm_skip_instruction(unsigned long * regs)
2214     {
2215     unsigned int * pc = (unsigned int *)regs[ARM_REG_PC];
2216    
2217     if (pc == 0)
2218     return false;
2219    
2220     #if DEBUG
2221     printf("IP: %p [%08x]\n", pc, pc[0]);
2222     #endif
2223    
2224     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
2225     transfer_size_t transfer_size = SIZE_UNKNOWN;
2226     enum { op_sdt = 1, op_sdth = 2 };
2227     int op = 0;
2228    
2229     // Handle load/store instructions only
2230     const unsigned int opcode = pc[0];
2231     switch ((opcode >> 25) & 7) {
2232     case 0: // Halfword and Signed Data Transfer (LDRH, STRH, LDRSB, LDRSH)
2233     op = op_sdth;
2234     // Determine transfer size (S/H bits)
2235     switch ((opcode >> 5) & 3) {
2236     case 0: // SWP instruction
2237     break;
2238     case 1: // Unsigned halfwords
2239     case 3: // Signed halfwords
2240     transfer_size = SIZE_WORD;
2241     break;
2242     case 2: // Signed byte
2243     transfer_size = SIZE_BYTE;
2244     break;
2245     }
2246     break;
2247     case 2:
2248     case 3: // Single Data Transfer (LDR, STR)
2249     op = op_sdt;
2250     // Determine transfer size (B bit)
2251     if (((opcode >> 22) & 1) == 1)
2252     transfer_size = SIZE_BYTE;
2253     else
2254     transfer_size = SIZE_LONG;
2255     break;
2256     default:
2257     // FIXME: support load/store mutliple?
2258     return false;
2259     }
2260    
2261     // Check for invalid transfer size (SWP instruction?)
2262     if (transfer_size == SIZE_UNKNOWN)
2263     return false;
2264    
2265     // Determine transfer type (L bit)
2266     if (((opcode >> 20) & 1) == 1)
2267     transfer_type = SIGSEGV_TRANSFER_LOAD;
2268     else
2269     transfer_type = SIGSEGV_TRANSFER_STORE;
2270    
2271     // Compute offset
2272     int offset;
2273     if (((opcode >> 25) & 1) == 0) {
2274     if (op == op_sdt)
2275     offset = opcode & 0xfff;
2276     else if (op == op_sdth) {
2277     int rm = opcode & 0xf;
2278     if (((opcode >> 22) & 1) == 0) {
2279     // register offset
2280     offset = regs[rm];
2281     }
2282     else {
2283     // immediate offset
2284     offset = ((opcode >> 4) & 0xf0) | (opcode & 0x0f);
2285     }
2286     }
2287     }
2288     else {
2289     const int rm = opcode & 0xf;
2290     const int sh = (opcode >> 7) & 0x1f;
2291     if (((opcode >> 4) & 1) == 1) {
2292     // we expect only legal load/store instructions
2293     printf("FATAL: invalid shift operand\n");
2294     return false;
2295     }
2296     const unsigned int v = regs[rm];
2297     switch ((opcode >> 5) & 3) {
2298     case 0: // logical shift left
2299     offset = sh ? v << sh : v;
2300     break;
2301     case 1: // logical shift right
2302     offset = sh ? v >> sh : 0;
2303     break;
2304     case 2: // arithmetic shift right
2305     if (sh)
2306     offset = ((signed int)v) >> sh;
2307     else
2308     offset = (v & 0x80000000) ? 0xffffffff : 0;
2309     break;
2310     case 3: // rotate right
2311     if (sh)
2312     offset = (v >> sh) | (v << (32 - sh));
2313     else
2314     offset = (v >> 1) | ((regs[ARM_REG_CPSR] << 2) & 0x80000000);
2315     break;
2316     }
2317     }
2318     if (((opcode >> 23) & 1) == 0)
2319     offset = -offset;
2320    
2321     int rd = (opcode >> 12) & 0xf;
2322     int rn = (opcode >> 16) & 0xf;
2323     #if DEBUG
2324     static const char * reg_names[] = {
2325     "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2326     "r9", "r9", "sl", "fp", "ip", "sp", "lr", "pc"
2327     };
2328     printf("%s %s register %s\n",
2329     transfer_size == SIZE_BYTE ? "byte" :
2330     transfer_size == SIZE_WORD ? "word" :
2331     transfer_size == SIZE_LONG ? "long" : "unknown",
2332     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
2333     reg_names[rd]);
2334     #endif
2335    
2336     unsigned int base = regs[rn];
2337     if (((opcode >> 24) & 1) == 1)
2338     base += offset;
2339    
2340     if (transfer_type == SIGSEGV_TRANSFER_LOAD)
2341     regs[rd] = 0;
2342    
2343     if (((opcode >> 24) & 1) == 0) // post-index addressing
2344     regs[rn] += offset;
2345     else if (((opcode >> 21) & 1) == 1) // write-back address into base
2346     regs[rn] = base;
2347    
2348     regs[ARM_REG_PC] += 4;
2349     return true;
2350     }
2351     #endif
2352    
2353    
2354 gbeauche 1.1 // Fallbacks
2355 gbeauche 1.68 #ifndef SIGSEGV_FAULT_ADDRESS_FAST
2356     #define SIGSEGV_FAULT_ADDRESS_FAST SIGSEGV_FAULT_ADDRESS
2357     #endif
2358     #ifndef SIGSEGV_FAULT_INSTRUCTION_FAST
2359     #define SIGSEGV_FAULT_INSTRUCTION_FAST SIGSEGV_FAULT_INSTRUCTION
2360     #endif
2361 gbeauche 1.1 #ifndef SIGSEGV_FAULT_INSTRUCTION
2362 gbeauche 1.67 #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_INVALID_ADDRESS
2363 gbeauche 1.1 #endif
2364 gbeauche 1.30 #ifndef SIGSEGV_FAULT_HANDLER_ARGLIST_1
2365     #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 SIGSEGV_FAULT_HANDLER_ARGLIST
2366     #endif
2367 gbeauche 1.31 #ifndef SIGSEGV_FAULT_HANDLER_INVOKE
2368 gbeauche 1.67 #define SIGSEGV_FAULT_HANDLER_INVOKE(P) sigsegv_fault_handler(P)
2369 gbeauche 1.31 #endif
2370 gbeauche 1.1
2371 gbeauche 1.2 // SIGSEGV recovery supported ?
2372     #if defined(SIGSEGV_ALL_SIGNALS) && defined(SIGSEGV_FAULT_HANDLER_ARGLIST) && defined(SIGSEGV_FAULT_ADDRESS)
2373     #define HAVE_SIGSEGV_RECOVERY
2374     #endif
2375    
2376 gbeauche 1.1
2377     /*
2378     * SIGSEGV global handler
2379     */
2380    
2381 gbeauche 1.67 struct sigsegv_info_t {
2382     sigsegv_address_t addr;
2383     sigsegv_address_t pc;
2384 gbeauche 1.68 #ifdef HAVE_MACH_EXCEPTIONS
2385     mach_port_t thread;
2386     bool has_exc_state;
2387     SIGSEGV_EXCEPTION_STATE_TYPE exc_state;
2388     mach_msg_type_number_t exc_state_count;
2389     bool has_thr_state;
2390     SIGSEGV_THREAD_STATE_TYPE thr_state;
2391     mach_msg_type_number_t thr_state_count;
2392     #endif
2393 gbeauche 1.67 };
2394    
2395 gbeauche 1.70 #ifdef HAVE_MACH_EXCEPTIONS
2396 gbeauche 1.72 static void mach_get_exception_state(sigsegv_info_t *SIP)
2397 gbeauche 1.70 {
2398 gbeauche 1.72 SIP->exc_state_count = SIGSEGV_EXCEPTION_STATE_COUNT;
2399     kern_return_t krc = thread_get_state(SIP->thread,
2400 gbeauche 1.70 SIGSEGV_EXCEPTION_STATE_FLAVOR,
2401 gbeauche 1.72 (natural_t *)&SIP->exc_state,
2402     &SIP->exc_state_count);
2403 gbeauche 1.70 MACH_CHECK_ERROR(thread_get_state, krc);
2404 gbeauche 1.72 SIP->has_exc_state = true;
2405 gbeauche 1.70 }
2406    
2407 gbeauche 1.72 static void mach_get_thread_state(sigsegv_info_t *SIP)
2408 gbeauche 1.70 {
2409 gbeauche 1.72 SIP->thr_state_count = SIGSEGV_THREAD_STATE_COUNT;
2410     kern_return_t krc = thread_get_state(SIP->thread,
2411 gbeauche 1.70 SIGSEGV_THREAD_STATE_FLAVOR,
2412 gbeauche 1.72 (natural_t *)&SIP->thr_state,
2413     &SIP->thr_state_count);
2414 gbeauche 1.70 MACH_CHECK_ERROR(thread_get_state, krc);
2415 gbeauche 1.72 SIP->has_thr_state = true;
2416 gbeauche 1.70 }
2417    
2418 gbeauche 1.72 static void mach_set_thread_state(sigsegv_info_t *SIP)
2419 gbeauche 1.70 {
2420 gbeauche 1.72 kern_return_t krc = thread_set_state(SIP->thread,
2421 gbeauche 1.70 SIGSEGV_THREAD_STATE_FLAVOR,
2422 gbeauche 1.72 (natural_t *)&SIP->thr_state,
2423     SIP->thr_state_count);
2424 gbeauche 1.70 MACH_CHECK_ERROR(thread_set_state, krc);
2425     }
2426     #endif
2427    
2428 gbeauche 1.67 // Return the address of the invalid memory reference
2429 gbeauche 1.72 sigsegv_address_t sigsegv_get_fault_address(sigsegv_info_t *SIP)
2430 gbeauche 1.67 {
2431 gbeauche 1.68 #ifdef HAVE_MACH_EXCEPTIONS
2432     static int use_fast_path = -1;
2433 gbeauche 1.72 if (use_fast_path != 1 && !SIP->has_exc_state) {
2434     mach_get_exception_state(SIP);
2435 gbeauche 1.68
2436     sigsegv_address_t addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
2437     if (use_fast_path < 0)
2438 gbeauche 1.72 use_fast_path = addr == SIP->addr;
2439     SIP->addr = addr;
2440 gbeauche 1.68 }
2441     #endif
2442 gbeauche 1.72 return SIP->addr;
2443 gbeauche 1.67 }
2444    
2445     // Return the address of the instruction that caused the fault, or
2446     // SIGSEGV_INVALID_ADDRESS if we could not retrieve this information
2447 gbeauche 1.72 sigsegv_address_t sigsegv_get_fault_instruction_address(sigsegv_info_t *SIP)
2448 gbeauche 1.67 {
2449 gbeauche 1.68 #ifdef HAVE_MACH_EXCEPTIONS
2450 gbeauche 1.72 if (!SIP->has_thr_state) {
2451     mach_get_thread_state(SIP);
2452 gbeauche 1.68
2453 gbeauche 1.72 SIP->pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
2454 gbeauche 1.68 }
2455     #endif
2456 gbeauche 1.72 return SIP->pc;
2457 gbeauche 1.67 }
2458    
2459 gbeauche 1.27 // This function handles the badaccess to memory.
2460     // It is called from the signal handler or the exception handler.
2461 gbeauche 1.30 static bool handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGLIST_1)
2462 gbeauche 1.1 {
2463 gbeauche 1.72 sigsegv_info_t SI;
2464     SI.addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS_FAST;
2465     SI.pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION_FAST;
2466 gbeauche 1.56 #ifdef HAVE_MACH_EXCEPTIONS
2467 gbeauche 1.72 SI.thread = thread;
2468     SI.has_exc_state = false;
2469     SI.has_thr_state = false;
2470 gbeauche 1.56 #endif
2471 gbeauche 1.72 sigsegv_info_t * const SIP = &SI;
2472 gbeauche 1.56
2473 gbeauche 1.1 // Call user's handler and reinstall the global handler, if required
2474 gbeauche 1.72 switch (SIGSEGV_FAULT_HANDLER_INVOKE(SIP)) {
2475 gbeauche 1.24 case SIGSEGV_RETURN_SUCCESS:
2476 gbeauche 1.27 return true;
2477    
2478 gbeauche 1.10 #if HAVE_SIGSEGV_SKIP_INSTRUCTION
2479 gbeauche 1.24 case SIGSEGV_RETURN_SKIP_INSTRUCTION:
2480 gbeauche 1.27 // Call the instruction skipper with the register file
2481     // available
2482 gbeauche 1.70 #ifdef HAVE_MACH_EXCEPTIONS
2483 gbeauche 1.72 if (!SIP->has_thr_state)
2484     mach_get_thread_state(SIP);
2485 gbeauche 1.70 #endif
2486 gbeauche 1.27 if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE)) {
2487     #ifdef HAVE_MACH_EXCEPTIONS
2488     // Unlike UNIX signals where the thread state
2489     // is modified off of the stack, in Mach we
2490     // need to actually call thread_set_state to
2491     // have the register values updated.
2492 gbeauche 1.72 mach_set_thread_state(SIP);
2493 gbeauche 1.27 #endif
2494     return true;
2495     }
2496 gbeauche 1.24 break;
2497     #endif
2498 nigel 1.43 case SIGSEGV_RETURN_FAILURE:
2499 gbeauche 1.50 // We can't do anything with the fault_address, dump state?
2500     if (sigsegv_state_dumper != 0)
2501 gbeauche 1.72 sigsegv_state_dumper(SIP);
2502 gbeauche 1.50 break;
2503 gbeauche 1.10 }
2504 gbeauche 1.27
2505     return false;
2506     }
2507    
2508    
2509     /*
2510     * There are two mechanisms for handling a bad memory access,
2511     * Mach exceptions and UNIX signals. The implementation specific
2512     * code appears below. Its reponsibility is to call handle_badaccess
2513     * which is the routine that handles the fault in an implementation
2514     * agnostic manner. The implementation specific code below is then
2515     * reponsible for checking whether handle_badaccess was able
2516     * to handle the memory access error and perform any implementation
2517     * specific tasks necessary afterwards.
2518     */
2519    
2520     #ifdef HAVE_MACH_EXCEPTIONS
2521     /*
2522     * We need to forward all exceptions that we do not handle.
2523     * This is important, there are many exceptions that may be
2524     * handled by other exception handlers. For example debuggers
2525     * use exceptions and the exception hander is in another
2526     * process in such a case. (Timothy J. Wood states in his
2527     * message to the list that he based this code on that from
2528     * gdb for Darwin.)
2529     */
2530     static inline kern_return_t
2531     forward_exception(mach_port_t thread_port,
2532     mach_port_t task_port,
2533     exception_type_t exception_type,
2534     exception_data_t exception_data,
2535     mach_msg_type_number_t data_count,
2536     ExceptionPorts *oldExceptionPorts)
2537     {
2538     kern_return_t kret;
2539     unsigned int portIndex;
2540     mach_port_t port;
2541     exception_behavior_t behavior;
2542     thread_state_flavor_t flavor;
2543 gbeauche 1.57 thread_state_data_t thread_state;
2544 gbeauche 1.27 mach_msg_type_number_t thread_state_count;
2545    
2546     for (portIndex = 0; portIndex < oldExceptionPorts->maskCount; portIndex++) {
2547     if (oldExceptionPorts->masks[portIndex] & (1 << exception_type)) {
2548     // This handler wants the exception
2549     break;
2550     }
2551     }
2552    
2553     if (portIndex >= oldExceptionPorts->maskCount) {
2554     fprintf(stderr, "No handler for exception_type = %d. Not fowarding\n", exception_type);
2555     return KERN_FAILURE;
2556     }
2557    
2558     port = oldExceptionPorts->handlers[portIndex];
2559     behavior = oldExceptionPorts->behaviors[portIndex];
2560     flavor = oldExceptionPorts->flavors[portIndex];
2561    
2562 gbeauche 1.63 if (!VALID_THREAD_STATE_FLAVOR(flavor)) {
2563     fprintf(stderr, "Invalid thread_state flavor = %d. Not forwarding\n", flavor);
2564     return KERN_FAILURE;
2565     }
2566    
2567 gbeauche 1.27 /*
2568     fprintf(stderr, "forwarding exception, port = 0x%x, behaviour = %d, flavor = %d\n", port, behavior, flavor);
2569     */
2570    
2571     if (behavior != EXCEPTION_DEFAULT) {
2572     thread_state_count = THREAD_STATE_MAX;
2573 gbeauche 1.60 kret = thread_get_state (thread_port, flavor, (natural_t *)&thread_state,
2574 gbeauche 1.27 &thread_state_count);
2575     MACH_CHECK_ERROR (thread_get_state, kret);
2576     }
2577    
2578     switch (behavior) {
2579     case EXCEPTION_DEFAULT:
2580     // fprintf(stderr, "forwarding to exception_raise\n");
2581     kret = exception_raise(port, thread_port, task_port, exception_type,
2582     exception_data, data_count);
2583     MACH_CHECK_ERROR (exception_raise, kret);
2584     break;
2585     case EXCEPTION_STATE:
2586     // fprintf(stderr, "forwarding to exception_raise_state\n");
2587     kret = exception_raise_state(port, exception_type, exception_data,
2588     data_count, &flavor,
2589 gbeauche 1.60 (natural_t *)&thread_state, thread_state_count,
2590     (natural_t *)&thread_state, &thread_state_count);
2591 gbeauche 1.27 MACH_CHECK_ERROR (exception_raise_state, kret);
2592     break;
2593     case EXCEPTION_STATE_IDENTITY:
2594     // fprintf(stderr, "forwarding to exception_raise_state_identity\n");
2595     kret = exception_raise_state_identity(port, thread_port, task_port,
2596     exception_type, exception_data,
2597     data_count, &flavor,
2598 gbeauche 1.60 (natural_t *)&thread_state, thread_state_count,
2599     (natural_t *)&thread_state, &thread_state_count);
2600 gbeauche 1.27 MACH_CHECK_ERROR (exception_raise_state_identity, kret);
2601     break;
2602     default:
2603     fprintf(stderr, "forward_exception got unknown behavior\n");
2604 gbeauche 1.63 kret = KERN_FAILURE;
2605 gbeauche 1.27 break;
2606     }
2607    
2608     if (behavior != EXCEPTION_DEFAULT) {
2609 gbeauche 1.60 kret = thread_set_state (thread_port, flavor, (natural_t *)&thread_state,
2610 gbeauche 1.27 thread_state_count);
2611     MACH_CHECK_ERROR (thread_set_state, kret);
2612     }
2613    
2614 gbeauche 1.63 return kret;
2615 gbeauche 1.27 }
2616    
2617     /*
2618     * This is the code that actually handles the exception.
2619     * It is called by exc_server. For Darwin 5 Apple changed
2620     * this a bit from how this family of functions worked in
2621     * Mach. If you are familiar with that it is a little
2622     * different. The main variation that concerns us here is
2623     * that code is an array of exception specific codes and
2624     * codeCount is a count of the number of codes in the code
2625     * array. In typical Mach all exceptions have a code
2626     * and sub-code. It happens to be the case that for a
2627     * EXC_BAD_ACCESS exception the first entry is the type of
2628     * bad access that occurred and the second entry is the
2629     * faulting address so these entries correspond exactly to
2630     * how the code and sub-code are used on Mach.
2631     *
2632     * This is a MIG interface. No code in Basilisk II should
2633     * call this directley. This has to have external C
2634     * linkage because that is what exc_server expects.
2635     */
2636     kern_return_t
2637     catch_exception_raise(mach_port_t exception_port,
2638     mach_port_t thread,
2639     mach_port_t task,
2640     exception_type_t exception,
2641     exception_data_t code,
2642 gbeauche 1.66 mach_msg_type_number_t code_count)
2643 gbeauche 1.27 {
2644     kern_return_t krc;
2645    
2646 gbeauche 1.66 if (exception == EXC_BAD_ACCESS) {
2647     switch (code[0]) {
2648     case KERN_PROTECTION_FAILURE:
2649     case KERN_INVALID_ADDRESS:
2650     if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS))
2651     return KERN_SUCCESS;
2652     break;
2653     }
2654 gbeauche 1.27 }
2655    
2656     // In Mach we do not need to remove the exception handler.
2657     // If we forward the exception, eventually some exception handler
2658     // will take care of this exception.
2659 gbeauche 1.66 krc = forward_exception(thread, task, exception, code, code_count, &ports);
2660 gbeauche 1.27
2661     return krc;
2662     }
2663     #endif
2664    
2665     #ifdef HAVE_SIGSEGV_RECOVERY
2666     // Handle bad memory accesses with signal handler
2667     static void sigsegv_handler(SIGSEGV_FAULT_HANDLER_ARGLIST)
2668     {
2669     // Call handler and reinstall the global handler, if required
2670     if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS)) {
2671     #if (defined(HAVE_SIGACTION) ? defined(SIGACTION_NEED_REINSTALL) : defined(SIGNAL_NEED_REINSTALL))
2672     sigsegv_do_install_handler(sig);
2673     #endif
2674     return;
2675     }
2676 gbeauche 1.10
2677 gbeauche 1.27 // Failure: reinstall default handler for "safe" crash
2678 gbeauche 1.1 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
2679 gbeauche 1.27 SIGSEGV_ALL_SIGNALS
2680 gbeauche 1.1 #undef FAULT_HANDLER
2681     }
2682 gbeauche 1.2 #endif
2683 gbeauche 1.1
2684    
2685     /*
2686     * SIGSEGV handler initialization
2687     */
2688    
2689     #if defined(HAVE_SIGINFO_T)
2690     static bool sigsegv_do_install_handler(int sig)
2691     {
2692     // Setup SIGSEGV handler to process writes to frame buffer
2693     #ifdef HAVE_SIGACTION
2694 gbeauche 1.22 struct sigaction sigsegv_sa;
2695     sigemptyset(&sigsegv_sa.sa_mask);
2696     sigsegv_sa.sa_sigaction = sigsegv_handler;
2697     sigsegv_sa.sa_flags = SA_SIGINFO;
2698     return (sigaction(sig, &sigsegv_sa, 0) == 0);
2699 gbeauche 1.1 #else
2700     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
2701     #endif
2702     }
2703 gbeauche 1.2 #endif
2704    
2705     #if defined(HAVE_SIGCONTEXT_SUBTERFUGE)
2706 gbeauche 1.1 static bool sigsegv_do_install_handler(int sig)
2707     {
2708     // Setup SIGSEGV handler to process writes to frame buffer
2709     #ifdef HAVE_SIGACTION
2710 gbeauche 1.22 struct sigaction sigsegv_sa;
2711     sigemptyset(&sigsegv_sa.sa_mask);
2712     sigsegv_sa.sa_handler = (signal_handler)sigsegv_handler;
2713     sigsegv_sa.sa_flags = 0;
2714 gbeauche 1.1 #if !EMULATED_68K && defined(__NetBSD__)
2715 gbeauche 1.22 sigaddset(&sigsegv_sa.sa_mask, SIGALRM);
2716     sigsegv_sa.sa_flags |= SA_ONSTACK;
2717 gbeauche 1.1 #endif
2718 gbeauche 1.22 return (sigaction(sig, &sigsegv_sa, 0) == 0);
2719 gbeauche 1.1 #else
2720     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
2721     #endif
2722     }
2723     #endif
2724    
2725 gbeauche 1.27 #if defined(HAVE_MACH_EXCEPTIONS)
2726     static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
2727     {
2728     /*
2729     * Except for the exception port functions, this should be
2730     * pretty much stock Mach. If later you choose to support
2731     * other Mach's besides Darwin, just check for __MACH__
2732     * here and __APPLE__ where the actual differences are.
2733     */
2734     #if defined(__APPLE__) && defined(__MACH__)
2735     if (sigsegv_fault_handler != NULL) {
2736     sigsegv_fault_handler = handler;
2737     return true;
2738     }
2739    
2740     kern_return_t krc;
2741    
2742     // create the the exception port
2743     krc = mach_port_allocate(mach_task_self(),
2744     MACH_PORT_RIGHT_RECEIVE, &_exceptionPort);
2745     if (krc != KERN_SUCCESS) {
2746     mach_error("mach_port_allocate", krc);
2747     return false;
2748     }
2749    
2750     // add a port send right
2751     krc = mach_port_insert_right(mach_task_self(),
2752     _exceptionPort, _exceptionPort,
2753     MACH_MSG_TYPE_MAKE_SEND);
2754     if (krc != KERN_SUCCESS) {
2755     mach_error("mach_port_insert_right", krc);
2756     return false;
2757     }
2758    
2759     // get the old exception ports
2760     ports.maskCount = sizeof (ports.masks) / sizeof (ports.masks[0]);
2761     krc = thread_get_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, ports.masks,
2762     &ports.maskCount, ports.handlers, ports.behaviors, ports.flavors);
2763     if (krc != KERN_SUCCESS) {
2764     mach_error("thread_get_exception_ports", krc);
2765     return false;
2766     }
2767    
2768     // set the new exception port
2769     //
2770     // We could have used EXCEPTION_STATE_IDENTITY instead of
2771     // EXCEPTION_DEFAULT to get the thread state in the initial
2772     // message, but it turns out that in the common case this is not
2773     // neccessary. If we need it we can later ask for it from the
2774     // suspended thread.
2775     //
2776     // Even with THREAD_STATE_NONE, Darwin provides the program
2777     // counter in the thread state. The comments in the header file
2778     // seem to imply that you can count on the GPR's on an exception
2779     // as well but just to be safe I use MACHINE_THREAD_STATE because
2780     // you have to ask for all of the GPR's anyway just to get the
2781     // program counter. In any case because of update effective
2782     // address from immediate and update address from effective
2783     // addresses of ra and rb modes (as good an name as any for these
2784     // addressing modes) used in PPC instructions, you will need the
2785     // GPR state anyway.
2786     krc = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, _exceptionPort,
2787 gbeauche 1.56 EXCEPTION_DEFAULT, SIGSEGV_THREAD_STATE_FLAVOR);
2788 gbeauche 1.27 if (krc != KERN_SUCCESS) {
2789     mach_error("thread_set_exception_ports", krc);
2790     return false;
2791     }
2792    
2793     // create the exception handler thread
2794     if (pthread_create(&exc_thread, NULL, &handleExceptions, NULL) != 0) {
2795     (void)fprintf(stderr, "creation of exception thread failed\n");
2796     return false;
2797     }
2798    
2799     // do not care about the exception thread any longer, let is run standalone
2800     (void)pthread_detach(exc_thread);
2801    
2802     sigsegv_fault_handler = handler;
2803     return true;
2804     #else
2805     return false;
2806     #endif
2807     }
2808     #endif
2809    
2810 gbeauche 1.48 #ifdef HAVE_WIN32_EXCEPTIONS
2811     static LONG WINAPI main_exception_filter(EXCEPTION_POINTERS *ExceptionInfo)
2812     {
2813     if (sigsegv_fault_handler != NULL
2814     && ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION
2815     && ExceptionInfo->ExceptionRecord->NumberParameters == 2
2816     && handle_badaccess(ExceptionInfo))
2817     return EXCEPTION_CONTINUE_EXECUTION;
2818    
2819     return EXCEPTION_CONTINUE_SEARCH;
2820     }
2821    
2822     #if defined __CYGWIN__ && defined __i386__
2823     /* In Cygwin programs, SetUnhandledExceptionFilter has no effect because Cygwin
2824     installs a global exception handler. We have to dig deep in order to install
2825     our main_exception_filter. */
2826    
2827     /* Data structures for the current thread's exception handler chain.
2828     On the x86 Windows uses register fs, offset 0 to point to the current
2829     exception handler; Cygwin mucks with it, so we must do the same... :-/ */
2830    
2831     /* Magic taken from winsup/cygwin/include/exceptions.h. */
2832    
2833     struct exception_list {
2834     struct exception_list *prev;
2835     int (*handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
2836     };
2837     typedef struct exception_list exception_list;
2838    
2839     /* Magic taken from winsup/cygwin/exceptions.cc. */
2840    
2841     __asm__ (".equ __except_list,0");
2842    
2843     extern exception_list *_except_list __asm__ ("%fs:__except_list");
2844    
2845     /* For debugging. _except_list is not otherwise accessible from gdb. */
2846     static exception_list *
2847     debug_get_except_list ()
2848     {
2849     return _except_list;
2850     }
2851    
2852     /* Cygwin's original exception handler. */
2853     static int (*cygwin_exception_handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
2854    
2855     /* Our exception handler. */
2856     static int
2857     libsigsegv_exception_handler (EXCEPTION_RECORD *exception, void *frame, CONTEXT *context, void *dispatch)
2858     {
2859     EXCEPTION_POINTERS ExceptionInfo;
2860     ExceptionInfo.ExceptionRecord = exception;
2861     ExceptionInfo.ContextRecord = context;
2862     if (main_exception_filter (&ExceptionInfo) == EXCEPTION_CONTINUE_SEARCH)
2863     return cygwin_exception_handler (exception, frame, context, dispatch);
2864     else
2865     return 0;
2866     }
2867    
2868     static void
2869     do_install_main_exception_filter ()
2870     {
2871     /* We cannot insert any handler into the chain, because such handlers
2872     must lie on the stack (?). Instead, we have to replace(!) Cygwin's
2873     global exception handler. */
2874     cygwin_exception_handler = _except_list->handler;
2875     _except_list->handler = libsigsegv_exception_handler;
2876     }
2877    
2878     #else
2879    
2880     static void
2881     do_install_main_exception_filter ()
2882     {
2883     SetUnhandledExceptionFilter ((LPTOP_LEVEL_EXCEPTION_FILTER) &main_exception_filter);
2884     }
2885     #endif
2886    
2887     static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
2888     {
2889     static bool main_exception_filter_installed = false;
2890     if (!main_exception_filter_installed) {
2891     do_install_main_exception_filter();
2892     main_exception_filter_installed = true;
2893     }
2894     sigsegv_fault_handler = handler;
2895     return true;
2896     }
2897     #endif
2898    
2899 gbeauche 1.12 bool sigsegv_install_handler(sigsegv_fault_handler_t handler)
2900 gbeauche 1.1 {
2901 gbeauche 1.27 #if defined(HAVE_SIGSEGV_RECOVERY)
2902 gbeauche 1.1 bool success = true;
2903     #define FAULT_HANDLER(sig) success = success && sigsegv_do_install_handler(sig);
2904     SIGSEGV_ALL_SIGNALS
2905     #undef FAULT_HANDLER
2906 gbeauche 1.27 if (success)
2907     sigsegv_fault_handler = handler;
2908 gbeauche 1.1 return success;
2909 gbeauche 1.48 #elif defined(HAVE_MACH_EXCEPTIONS) || defined(HAVE_WIN32_EXCEPTIONS)
2910 gbeauche 1.27 return sigsegv_do_install_handler(handler);
2911 gbeauche 1.1 #else
2912     // FAIL: no siginfo_t nor sigcontext subterfuge is available
2913     return false;
2914     #endif
2915     }
2916    
2917    
2918     /*
2919     * SIGSEGV handler deinitialization
2920     */
2921    
2922     void sigsegv_deinstall_handler(void)
2923     {
2924 gbeauche 1.27 // We do nothing for Mach exceptions, the thread would need to be
2925     // suspended if not already so, and we might mess with other
2926     // exception handlers that came after we registered ours. There is
2927     // no need to remove the exception handler, in fact this function is
2928     // not called anywhere in Basilisk II.
2929 gbeauche 1.2 #ifdef HAVE_SIGSEGV_RECOVERY
2930 gbeauche 1.12 sigsegv_fault_handler = 0;
2931 gbeauche 1.1 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
2932     SIGSEGV_ALL_SIGNALS
2933     #undef FAULT_HANDLER
2934 gbeauche 1.2 #endif
2935 gbeauche 1.48 #ifdef HAVE_WIN32_EXCEPTIONS
2936     sigsegv_fault_handler = NULL;
2937     #endif
2938 gbeauche 1.1 }
2939    
2940 gbeauche 1.10
2941     /*
2942     * Set callback function when we cannot handle the fault
2943     */
2944    
2945 gbeauche 1.12 void sigsegv_set_dump_state(sigsegv_state_dumper_t handler)
2946 gbeauche 1.10 {
2947 gbeauche 1.12 sigsegv_state_dumper = handler;
2948 gbeauche 1.10 }
2949    
2950    
2951 gbeauche 1.1 /*
2952     * Test program used for configure/test
2953     */
2954    
2955 gbeauche 1.4 #ifdef CONFIGURE_TEST_SIGSEGV_RECOVERY
2956 gbeauche 1.1 #include <stdio.h>
2957     #include <stdlib.h>
2958     #include <fcntl.h>
2959 gbeauche 1.48 #ifdef HAVE_SYS_MMAN_H
2960 gbeauche 1.1 #include <sys/mman.h>
2961 gbeauche 1.48 #endif
2962 gbeauche 1.4 #include "vm_alloc.h"
2963 gbeauche 1.1
2964 gbeauche 1.32 const int REF_INDEX = 123;
2965     const int REF_VALUE = 45;
2966    
2967 gbeauche 1.1 static int page_size;
2968 gbeauche 1.3 static volatile char * page = 0;
2969     static volatile int handler_called = 0;
2970 gbeauche 1.1
2971 gbeauche 1.61 /* Barriers */
2972     #ifdef __GNUC__
2973     #define BARRIER() asm volatile ("" : : : "memory")
2974     #else
2975     #define BARRIER() /* nothing */
2976     #endif
2977    
2978 gbeauche 1.32 #ifdef __GNUC__
2979     // Code range where we expect the fault to come from
2980     static void *b_region, *e_region;
2981     #endif
2982    
2983 gbeauche 1.67 static sigsegv_return_t sigsegv_test_handler(sigsegv_info_t *sip)
2984 gbeauche 1.1 {
2985 gbeauche 1.67 const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
2986     const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip);
2987 gbeauche 1.39 #if DEBUG
2988     printf("sigsegv_test_handler(%p, %p)\n", fault_address, instruction_address);
2989     printf("expected fault at %p\n", page + REF_INDEX);
2990     #ifdef __GNUC__
2991     printf("expected instruction address range: %p-%p\n", b_region, e_region);
2992     #endif
2993     #endif
2994 gbeauche 1.1 handler_called++;
2995 gbeauche 1.32 if ((fault_address - REF_INDEX) != page)
2996 gbeauche 1.29 exit(10);
2997 gbeauche 1.32 #ifdef __GNUC__
2998     // Make sure reported fault instruction address falls into
2999     // expected code range
3000 gbeauche 1.67 if (instruction_address != SIGSEGV_INVALID_ADDRESS
3001 gbeauche 1.32 && ((instruction_address < (sigsegv_address_t)b_region) ||
3002     (instruction_address >= (sigsegv_address_t)e_region)))
3003     exit(11);
3004     #endif
3005 gbeauche 1.4 if (vm_protect((char *)((unsigned long)fault_address & -page_size), page_size, VM_PAGE_READ | VM_PAGE_WRITE) != 0)
3006 gbeauche 1.32 exit(12);
3007 gbeauche 1.24 return SIGSEGV_RETURN_SUCCESS;
3008 gbeauche 1.1 }
3009    
3010 gbeauche 1.10 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
3011 gbeauche 1.67 static sigsegv_return_t sigsegv_insn_handler(sigsegv_info_t *sip)
3012 gbeauche 1.10 {
3013 gbeauche 1.67 const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
3014     const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip);
3015 gbeauche 1.44 #if DEBUG
3016     printf("sigsegv_insn_handler(%p, %p)\n", fault_address, instruction_address);
3017     #endif
3018 gbeauche 1.28 if (((unsigned long)fault_address - (unsigned long)page) < page_size) {
3019     #ifdef __GNUC__
3020     // Make sure reported fault instruction address falls into
3021     // expected code range
3022 gbeauche 1.67 if (instruction_address != SIGSEGV_INVALID_ADDRESS
3023 gbeauche 1.28 && ((instruction_address < (sigsegv_address_t)b_region) ||
3024     (instruction_address >= (sigsegv_address_t)e_region)))
3025     return SIGSEGV_RETURN_FAILURE;
3026     #endif
3027 gbeauche 1.26 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
3028 gbeauche 1.28 }
3029    
3030 gbeauche 1.24 return SIGSEGV_RETURN_FAILURE;
3031 gbeauche 1.10 }
3032 gbeauche 1.34
3033     // More sophisticated tests for instruction skipper
3034     static bool arch_insn_skipper_tests()
3035     {
3036     #if (defined(i386) || defined(__i386__)) || defined(__x86_64__)
3037     static const unsigned char code[] = {
3038     0x8a, 0x00, // mov (%eax),%al
3039     0x8a, 0x2c, 0x18, // mov (%eax,%ebx,1),%ch
3040     0x88, 0x20, // mov %ah,(%eax)
3041     0x88, 0x08, // mov %cl,(%eax)
3042     0x66, 0x8b, 0x00, // mov (%eax),%ax
3043     0x66, 0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%cx
3044     0x66, 0x89, 0x00, // mov %ax,(%eax)
3045     0x66, 0x89, 0x0c, 0x18, // mov %cx,(%eax,%ebx,1)
3046     0x8b, 0x00, // mov (%eax),%eax
3047     0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%ecx
3048     0x89, 0x00, // mov %eax,(%eax)
3049     0x89, 0x0c, 0x18, // mov %ecx,(%eax,%ebx,1)
3050     #if defined(__x86_64__)
3051     0x44, 0x8a, 0x00, // mov (%rax),%r8b
3052     0x44, 0x8a, 0x20, // mov (%rax),%r12b
3053     0x42, 0x8a, 0x3c, 0x10, // mov (%rax,%r10,1),%dil
3054     0x44, 0x88, 0x00, // mov %r8b,(%rax)
3055     0x44, 0x88, 0x20, // mov %r12b,(%rax)
3056     0x42, 0x88, 0x3c, 0x10, // mov %dil,(%rax,%r10,1)
3057     0x66, 0x44, 0x8b, 0x00, // mov (%rax),%r8w
3058     0x66, 0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%cx
3059     0x66, 0x44, 0x89, 0x00, // mov %r8w,(%rax)
3060     0x66, 0x42, 0x89, 0x0c, 0x10, // mov %cx,(%rax,%r10,1)
3061     0x44, 0x8b, 0x00, // mov (%rax),%r8d
3062     0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%ecx
3063     0x44, 0x89, 0x00, // mov %r8d,(%rax)
3064     0x42, 0x89, 0x0c, 0x10, // mov %ecx,(%rax,%r10,1)
3065     0x48, 0x8b, 0x08, // mov (%rax),%rcx
3066     0x4c, 0x8b, 0x18, // mov (%rax),%r11
3067     0x4a, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%rcx
3068     0x4e, 0x8b, 0x1c, 0x10, // mov (%rax,%r10,1),%r11
3069     0x48, 0x89, 0x08, // mov %rcx,(%rax)
3070     0x4c, 0x89, 0x18, // mov %r11,(%rax)
3071     0x4a, 0x89, 0x0c, 0x10, // mov %rcx,(%rax,%r10,1)
3072     0x4e, 0x89, 0x1c, 0x10, // mov %r11,(%rax,%r10,1)
3073 gbeauche 1.62 0x63, 0x47, 0x04, // movslq 4(%rdi),%eax
3074     0x48, 0x63, 0x47, 0x04, // movslq 4(%rdi),%rax
3075 gbeauche 1.34 #endif
3076     0 // end
3077     };
3078     const int N_REGS = 20;
3079     unsigned long regs[N_REGS];
3080     for (int i = 0; i < N_REGS; i++)
3081     regs[i] = i;
3082     const unsigned long start_code = (unsigned long)&code;
3083     regs[X86_REG_EIP] = start_code;
3084     while ((regs[X86_REG_EIP] - start_code) < (sizeof(code) - 1)
3085     && ix86_skip_instruction(regs))
3086     ; /* simply iterate */
3087     return (regs[X86_REG_EIP] - start_code) == (sizeof(code) - 1);
3088     #endif
3089     return true;
3090     }
3091 gbeauche 1.10 #endif
3092    
3093 gbeauche 1.1 int main(void)
3094     {
3095 gbeauche 1.4 if (vm_init() < 0)
3096 gbeauche 1.1 return 1;
3097    
3098 gbeauche 1.54 page_size = vm_get_page_size();
3099 gbeauche 1.4 if ((page = (char *)vm_acquire(page_size)) == VM_MAP_FAILED)
3100 gbeauche 1.29 return 2;
3101 gbeauche 1.4
3102 gbeauche 1.32 memset((void *)page, 0, page_size);
3103 gbeauche 1.4 if (vm_protect((char *)page, page_size, VM_PAGE_READ) < 0)
3104 gbeauche 1.29 return 3;
3105 gbeauche 1.1
3106     if (!sigsegv_install_handler(sigsegv_test_handler))
3107 gbeauche 1.29 return 4;
3108 gbeauche 1.74
3109 gbeauche 1.32 #ifdef __GNUC__
3110     b_region = &&L_b_region1;
3111     e_region = &&L_e_region1;
3112     #endif
3113 gbeauche 1.74 /* This is a really awful hack but otherwise gcc is smart enough
3114     * (or bug'ous enough?) to optimize the labels and place them
3115     * e.g. at the "main" entry point, which is wrong.
3116     */
3117     volatile int label_hack = 1;
3118     switch (label_hack) {
3119     case 1:
3120     L_b_region1:
3121     page[REF_INDEX] = REF_VALUE;
3122     if (page[REF_INDEX] != REF_VALUE)
3123     exit(20);
3124     page[REF_INDEX] = REF_VALUE;
3125     BARRIER();
3126     // fall-through
3127     case 2:
3128     L_e_region1:
3129     BARRIER();
3130     break;
3131     }
3132 gbeauche 1.32
3133 gbeauche 1.1 if (handler_called != 1)
3134 gbeauche 1.29 return 5;
3135 gbeauche 1.10
3136     #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
3137     if (!sigsegv_install_handler(sigsegv_insn_handler))
3138 gbeauche 1.29 return 6;
3139 gbeauche 1.10
3140 gbeauche 1.17 if (vm_protect((char *)page, page_size, VM_PAGE_READ | VM_PAGE_WRITE) < 0)
3141 gbeauche 1.29 return 7;
3142 gbeauche 1.10
3143     for (int i = 0; i < page_size; i++)
3144     page[i] = (i + 1) % page_size;
3145    
3146     if (vm_protect((char *)page, page_size, VM_PAGE_NOACCESS) < 0)
3147 gbeauche 1.29 return 8;
3148 gbeauche 1.10
3149     #define TEST_SKIP_INSTRUCTION(TYPE) do { \
3150 gbeauche 1.34 const unsigned long TAG = 0x12345678 | \
3151     (sizeof(long) == 8 ? 0x9abcdef0UL << 31 : 0); \
3152 gbeauche 1.10 TYPE data = *((TYPE *)(page + sizeof(TYPE))); \
3153 gbeauche 1.34 volatile unsigned long effect = data + TAG; \
3154 gbeauche 1.10 if (effect != TAG) \
3155 gbeauche 1.29 return 9; \
3156 gbeauche 1.10 } while (0)
3157    
3158 gbeauche 1.28 #ifdef __GNUC__
3159 gbeauche 1.32 b_region = &&L_b_region2;
3160     e_region = &&L_e_region2;
3161 gbeauche 1.28 #endif
3162 gbeauche 1.74 switch (label_hack) {
3163     case 1:
3164     L_b_region2:
3165     TEST_SKIP_INSTRUCTION(unsigned char);
3166     TEST_SKIP_INSTRUCTION(unsigned short);
3167     TEST_SKIP_INSTRUCTION(unsigned int);
3168     TEST_SKIP_INSTRUCTION(unsigned long);
3169     TEST_SKIP_INSTRUCTION(signed char);
3170     TEST_SKIP_INSTRUCTION(signed short);
3171     TEST_SKIP_INSTRUCTION(signed int);
3172     TEST_SKIP_INSTRUCTION(signed long);
3173     BARRIER();
3174     // fall-through
3175     case 2:
3176     L_e_region2:
3177     BARRIER();
3178     break;
3179     }
3180 gbeauche 1.34 if (!arch_insn_skipper_tests())
3181     return 20;
3182 gbeauche 1.35 #endif
3183 gbeauche 1.34
3184 gbeauche 1.4 vm_exit();
3185 gbeauche 1.1 return 0;
3186     }
3187     #endif