ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.87
Committed: 2009-02-11T20:44:10Z (15 years, 9 months ago) by asvitkine
Branch: MAIN
Changes since 1.86: +0 -79 lines
Log Message:
move sigsegv_info_t declaration to header

File Contents

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