ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
(Generate patch)

Comparing BasiliskII/src/Unix/sigsegv.cpp (file contents):
Revision 1.17 by gbeauche, 2002-05-20T17:49:04Z vs.
Revision 1.83 by gbeauche, 2008-01-20T00:39:51Z

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines