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.23 by gbeauche, 2003-08-17T10:52:52Z vs.
Revision 1.38 by gbeauche, 2003-12-20T10:06:18Z

# Line 4 | Line 4
4   *  Derived from Bruno Haible's work on his SIGSEGV library for clisp
5   *  <http://clisp.sourceforge.net/>
6   *
7 + *  MacOS X support derived from the post by Timothy J. Wood to the
8 + *  omnigroup macosx-dev list:
9 + *    Mach Exception Handlers 101 (Was Re: ptrace, gdb)
10 + *    tjw@omnigroup.com Sun, 4 Jun 2000
11 + *    www.omnigroup.com/mailman/archive/macosx-dev/2000-June/002030.html
12 + *
13   *  Basilisk II (C) 1997-2002 Christian Bauer
14   *
15   *  This program is free software; you can redistribute it and/or modify
# Line 45 | Line 51 | using std::list;
51   // Type of the system signal handler
52   typedef RETSIGTYPE (*signal_handler)(int);
53  
48 // Ignore range chain
49 struct ignore_range_t {
50        sigsegv_address_t       start;
51        unsigned long           length;
52        int                                     transfer_type;
53 };
54
55 typedef list<ignore_range_t> ignore_range_list_t;
56 ignore_range_list_t sigsegv_ignore_ranges;
57
54   // User's SIGSEGV handler
55   static sigsegv_fault_handler_t sigsegv_fault_handler = 0;
56  
# Line 64 | Line 60 | static sigsegv_state_dumper_t sigsegv_st
60   // Actual SIGSEGV handler installer
61   static bool sigsegv_do_install_handler(int sig);
62  
67 // Find ignore range matching address
68 static inline ignore_range_list_t::iterator sigsegv_find_ignore_range(sigsegv_address_t address)
69 {
70        ignore_range_list_t::iterator it;
71        for (it = sigsegv_ignore_ranges.begin(); it != sigsegv_ignore_ranges.end(); it++)
72                if (address >= it->start && address < it->start + it->length)
73                        break;
74        return it;
75 }
76
63  
64   /*
65   *  Instruction decoding aids
# Line 83 | Line 69 | static inline ignore_range_list_t::itera
69   enum transfer_size_t {
70          SIZE_UNKNOWN,
71          SIZE_BYTE,
72 <        SIZE_WORD,
73 <        SIZE_LONG
72 >        SIZE_WORD, // 2 bytes
73 >        SIZE_LONG, // 4 bytes
74 >        SIZE_QUAD, // 8 bytes
75   };
76  
77   // Transfer type
# Line 232 | Line 219 | static void powerpc_decode_instruction(i
219   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV)
220   #endif
221   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, siginfo_t *sip, void *scp
222 + #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 siginfo_t *sip, void *scp
223 + #define SIGSEGV_FAULT_HANDLER_ARGS              sip, scp
224   #define SIGSEGV_FAULT_ADDRESS                   sip->si_addr
225 < #if defined(__NetBSD__) || defined(__FreeBSD__)
225 > #if (defined(sgi) || defined(__sgi))
226 > #include <ucontext.h>
227 > #define SIGSEGV_CONTEXT_REGS                    (((ucontext_t *)scp)->uc_mcontext.gregs)
228 > #define SIGSEGV_FAULT_INSTRUCTION               (unsigned long)SIGSEGV_CONTEXT_REGS[CTX_EPC]
229 > #if (defined(mips) || defined(__mips))
230 > #define SIGSEGV_REGISTER_FILE                   SIGSEGV_CONTEXT_REGS
231 > #define SIGSEGV_SKIP_INSTRUCTION                mips_skip_instruction
232 > #endif
233 > #endif
234 > #if defined(__sun__)
235 > #if (defined(sparc) || defined(__sparc__))
236 > #include <sys/ucontext.h>
237 > #define SIGSEGV_CONTEXT_REGS                    (((ucontext_t *)scp)->uc_mcontext.gregs)
238 > #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_CONTEXT_REGS[REG_PC]
239 > #endif
240 > #endif
241 > #if defined(__FreeBSD__)
242   #if (defined(i386) || defined(__i386__))
243   #define SIGSEGV_FAULT_INSTRUCTION               (((struct sigcontext *)scp)->sc_eip)
244 < #define SIGSEGV_REGISTER_FILE                   ((unsigned int *)&(((struct sigcontext *)scp)->sc_edi)) /* EDI is the first GPR (even below EIP) in sigcontext */
244 > #define SIGSEGV_REGISTER_FILE                   ((unsigned long *)&(((struct sigcontext *)scp)->sc_edi)) /* EDI is the first GPR (even below EIP) in sigcontext */
245   #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
246   #endif
247   #endif
# Line 245 | Line 250 | static void powerpc_decode_instruction(i
250   #include <sys/ucontext.h>
251   #define SIGSEGV_CONTEXT_REGS                    (((ucontext_t *)scp)->uc_mcontext.gregs)
252   #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_CONTEXT_REGS[14] /* should use REG_EIP instead */
253 < #define SIGSEGV_REGISTER_FILE                   (unsigned int *)SIGSEGV_CONTEXT_REGS
253 > #define SIGSEGV_REGISTER_FILE                   (unsigned long *)SIGSEGV_CONTEXT_REGS
254   #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
255   #endif
256   #if (defined(x86_64) || defined(__x86_64__))
# Line 253 | Line 258 | static void powerpc_decode_instruction(i
258   #define SIGSEGV_CONTEXT_REGS                    (((ucontext_t *)scp)->uc_mcontext.gregs)
259   #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_CONTEXT_REGS[16] /* should use REG_RIP instead */
260   #define SIGSEGV_REGISTER_FILE                   (unsigned long *)SIGSEGV_CONTEXT_REGS
261 + #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
262   #endif
263   #if (defined(ia64) || defined(__ia64__))
264   #define SIGSEGV_FAULT_INSTRUCTION               (((struct sigcontext *)scp)->sc_ip & ~0x3ULL) /* slot number is in bits 0 and 1 */
# Line 274 | Line 280 | static void powerpc_decode_instruction(i
280   #if (defined(i386) || defined(__i386__))
281   #include <asm/sigcontext.h>
282   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, struct sigcontext scs
283 < #define SIGSEGV_FAULT_ADDRESS                   scs.cr2
284 < #define SIGSEGV_FAULT_INSTRUCTION               scs.eip
285 < #define SIGSEGV_REGISTER_FILE                   (unsigned int *)(&scs)
283 > #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 struct sigcontext *scp
284 > #define SIGSEGV_FAULT_HANDLER_ARGS              &scs
285 > #define SIGSEGV_FAULT_ADDRESS                   scp->cr2
286 > #define SIGSEGV_FAULT_INSTRUCTION               scp->eip
287 > #define SIGSEGV_REGISTER_FILE                   (unsigned long *)scp
288   #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
289   #endif
290   #if (defined(sparc) || defined(__sparc__))
291   #include <asm/sigcontext.h>
292   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp, char *addr
293 + #define SIGSEGV_FAULT_HANDLER_ARGS              sig, code, scp, addr
294   #define SIGSEGV_FAULT_ADDRESS                   addr
295   #endif
296   #if (defined(powerpc) || defined(__powerpc__))
297   #include <asm/sigcontext.h>
298   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, struct sigcontext *scp
299 + #define SIGSEGV_FAULT_HANDLER_ARGS              sig, scp
300   #define SIGSEGV_FAULT_ADDRESS                   scp->regs->dar
301   #define SIGSEGV_FAULT_INSTRUCTION               scp->regs->nip
302   #define SIGSEGV_REGISTER_FILE                   (unsigned int *)&scp->regs->nip, (unsigned int *)(scp->regs->gpr)
# Line 295 | Line 305 | static void powerpc_decode_instruction(i
305   #if (defined(alpha) || defined(__alpha__))
306   #include <asm/sigcontext.h>
307   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
308 + #define SIGSEGV_FAULT_HANDLER_ARGS              sig, code, scp
309   #define SIGSEGV_FAULT_ADDRESS                   get_fault_address(scp)
310   #define SIGSEGV_FAULT_INSTRUCTION               scp->sc_pc
300
301 // From Boehm's GC 6.0alpha8
302 static sigsegv_address_t get_fault_address(struct sigcontext *scp)
303 {
304        unsigned int instruction = *((unsigned int *)(scp->sc_pc));
305        unsigned long fault_address = scp->sc_regs[(instruction >> 16) & 0x1f];
306        fault_address += (signed long)(signed short)(instruction & 0xffff);
307        return (sigsegv_address_t)fault_address;
308 }
311   #endif
312   #endif
313  
314   // Irix 5 or 6 on MIPS
315 < #if (defined(sgi) || defined(__sgi)) && (defined(SYSTYPE_SVR4) || defined(__SYSTYPE_SVR4))
315 > #if (defined(sgi) || defined(__sgi)) && (defined(SYSTYPE_SVR4) || defined(_SYSTYPE_SVR4))
316   #include <ucontext.h>
317   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
318 < #define SIGSEGV_FAULT_ADDRESS                   scp->sc_badvaddr
318 > #define SIGSEGV_FAULT_HANDLER_ARGS              sig, code, scp
319 > #define SIGSEGV_FAULT_ADDRESS                   (unsigned long)scp->sc_badvaddr
320 > #define SIGSEGV_FAULT_INSTRUCTION               (unsigned long)scp->sc_pc
321   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV)
322   #endif
323  
324   // HP-UX
325   #if (defined(hpux) || defined(__hpux__))
326   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
327 + #define SIGSEGV_FAULT_HANDLER_ARGS              sig, code, scp
328   #define SIGSEGV_FAULT_ADDRESS                   scp->sc_sl.sl_ss.ss_narrow.ss_cr21
329   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV) FAULT_HANDLER(SIGBUS)
330   #endif
# Line 328 | Line 333 | static sigsegv_address_t get_fault_addre
333   #if defined(__osf__)
334   #include <ucontext.h>
335   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
336 + #define SIGSEGV_FAULT_HANDLER_ARGS              sig, code, scp
337   #define SIGSEGV_FAULT_ADDRESS                   scp->sc_traparg_a0
338   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV)
339   #endif
# Line 335 | Line 341 | static sigsegv_address_t get_fault_addre
341   // AIX
342   #if defined(_AIX)
343   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
344 + #define SIGSEGV_FAULT_HANDLER_ARGS              sig, code, scp
345   #define SIGSEGV_FAULT_ADDRESS                   scp->sc_jmpbuf.jmp_context.o_vaddr
346   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV)
347   #endif
348  
349 < // NetBSD or FreeBSD
350 < #if defined(__NetBSD__) || defined(__FreeBSD__)
349 > // NetBSD
350 > #if defined(__NetBSD__)
351   #if (defined(m68k) || defined(__m68k__))
352   #include <m68k/frame.h>
353   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
354 + #define SIGSEGV_FAULT_HANDLER_ARGS              sig, code, scp
355   #define SIGSEGV_FAULT_ADDRESS                   get_fault_address(scp)
356   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV)
357  
# Line 367 | Line 375 | static sigsegv_address_t get_fault_addre
375          }
376          return (sigsegv_address_t)fault_addr;
377   }
378 < #else
379 < #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, void *scp, char *addr
380 < #define SIGSEGV_FAULT_ADDRESS                   addr
378 > #endif
379 > #if (defined(alpha) || defined(__alpha__))
380 > #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
381 > #define SIGSEGV_FAULT_HANDLER_ARGS              sig, code, scp
382 > #define SIGSEGV_FAULT_ADDRESS                   get_fault_address(scp)
383 > #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGBUS)
384 > #endif
385 > #if (defined(i386) || defined(__i386__))
386 > #error "FIXME: need to decode instruction and compute EA"
387 > #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
388 > #define SIGSEGV_FAULT_HANDLER_ARGS              sig, code, scp
389 > #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV)
390 > #endif
391 > #endif
392 > #if defined(__FreeBSD__)
393   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGBUS)
394 + #if (defined(i386) || defined(__i386__))
395 + #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp, char *addr
396 + #define SIGSEGV_FAULT_HANDLER_ARGS              sig, code, scp, addr
397 + #define SIGSEGV_FAULT_ADDRESS                   addr
398 + #define SIGSEGV_FAULT_INSTRUCTION               scp->sc_eip
399 + #define SIGSEGV_REGISTER_FILE                   ((unsigned long *)&scp->sc_edi)
400 + #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
401   #endif
402   #endif
403  
404 < // MacOS X
404 > // Extract fault address out of a sigcontext
405 > #if (defined(alpha) || defined(__alpha__))
406 > // From Boehm's GC 6.0alpha8
407 > static sigsegv_address_t get_fault_address(struct sigcontext *scp)
408 > {
409 >        unsigned int instruction = *((unsigned int *)(scp->sc_pc));
410 >        unsigned long fault_address = scp->sc_regs[(instruction >> 16) & 0x1f];
411 >        fault_address += (signed long)(signed short)(instruction & 0xffff);
412 >        return (sigsegv_address_t)fault_address;
413 > }
414 > #endif
415 >
416 >
417 > // MacOS X, not sure which version this works in. Under 10.1
418 > // vm_protect does not appear to work from a signal handler. Under
419 > // 10.2 signal handlers get siginfo type arguments but the si_addr
420 > // field is the address of the faulting instruction and not the
421 > // address that caused the SIGBUS. Maybe this works in 10.0? In any
422 > // case with Mach exception handlers there is a way to do what this
423 > // was meant to do.
424 > #ifndef HAVE_MACH_EXCEPTIONS
425   #if defined(__APPLE__) && defined(__MACH__)
426   #if (defined(ppc) || defined(__ppc__))
427   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
428 + #define SIGSEGV_FAULT_HANDLER_ARGS              sig, code, scp
429   #define SIGSEGV_FAULT_ADDRESS                   get_fault_address(scp)
430   #define SIGSEGV_FAULT_INSTRUCTION               scp->sc_ir
431   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGBUS)
# Line 397 | Line 445 | static sigsegv_address_t get_fault_addre
445   #endif
446   #endif
447   #endif
448 + #endif
449 +
450 + #if HAVE_MACH_EXCEPTIONS
451 +
452 + // This can easily be extended to other Mach systems, but really who
453 + // uses HURD (oops GNU/HURD), Darwin/x86, NextStep, Rhapsody, or CMU
454 + // Mach 2.5/3.0?
455 + #if defined(__APPLE__) && defined(__MACH__)
456 +
457 + #include <sys/types.h>
458 + #include <stdlib.h>
459 + #include <stdio.h>
460 + #include <pthread.h>
461 +
462 + /*
463 + * If you are familiar with MIG then you will understand the frustration
464 + * that was necessary to get these embedded into C++ code by hand.
465 + */
466 + extern "C" {
467 + #include <mach/mach.h>
468 + #include <mach/mach_error.h>
469 +
470 + extern boolean_t exc_server(mach_msg_header_t *, mach_msg_header_t *);
471 + extern kern_return_t catch_exception_raise(mach_port_t, mach_port_t,
472 +        mach_port_t, exception_type_t, exception_data_t, mach_msg_type_number_t);
473 + extern kern_return_t exception_raise(mach_port_t, mach_port_t, mach_port_t,
474 +        exception_type_t, exception_data_t, mach_msg_type_number_t);
475 + extern kern_return_t exception_raise_state(mach_port_t, exception_type_t,
476 +        exception_data_t, mach_msg_type_number_t, thread_state_flavor_t *,
477 +        thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t *);
478 + extern kern_return_t exception_raise_state_identity(mach_port_t, mach_port_t, mach_port_t,
479 +        exception_type_t, exception_data_t, mach_msg_type_number_t, thread_state_flavor_t *,
480 +        thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t *);
481 + }
482 +
483 + // Could make this dynamic by looking for a result of MIG_ARRAY_TOO_LARGE
484 + #define HANDLER_COUNT 64
485 +
486 + // structure to tuck away existing exception handlers
487 + typedef struct _ExceptionPorts {
488 +        mach_msg_type_number_t maskCount;
489 +        exception_mask_t masks[HANDLER_COUNT];
490 +        exception_handler_t handlers[HANDLER_COUNT];
491 +        exception_behavior_t behaviors[HANDLER_COUNT];
492 +        thread_state_flavor_t flavors[HANDLER_COUNT];
493 + } ExceptionPorts;
494 +
495 + // exception handler thread
496 + static pthread_t exc_thread;
497 +
498 + // place where old exception handler info is stored
499 + static ExceptionPorts ports;
500 +
501 + // our exception port
502 + static mach_port_t _exceptionPort = MACH_PORT_NULL;
503 +
504 + #define MACH_CHECK_ERROR(name,ret) \
505 + if (ret != KERN_SUCCESS) { \
506 +        mach_error(#name, ret); \
507 +        exit (1); \
508 + }
509 +
510 + #define SIGSEGV_FAULT_ADDRESS                   code[1]
511 + #define SIGSEGV_FAULT_INSTRUCTION               get_fault_instruction(thread, state)
512 + #define SIGSEGV_FAULT_HANDLER_INVOKE(ADDR, IP)  ((code[0] == KERN_PROTECTION_FAILURE) ? sigsegv_fault_handler(ADDR, IP) : SIGSEGV_RETURN_FAILURE)
513 + #define SIGSEGV_FAULT_HANDLER_ARGLIST   mach_port_t thread, exception_data_t code, ppc_thread_state_t *state
514 + #define SIGSEGV_FAULT_HANDLER_ARGS              thread, code, &state
515 + #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
516 + #define SIGSEGV_REGISTER_FILE                   &state->srr0, &state->r0
517 +
518 + // Given a suspended thread, stuff the current instruction and
519 + // registers into state.
520 + //
521 + // It would have been nice to have this be ppc/x86 independant which
522 + // could have been done easily with a thread_state_t instead of
523 + // ppc_thread_state_t, but because of the way this is called it is
524 + // easier to do it this way.
525 + #if (defined(ppc) || defined(__ppc__))
526 + static inline sigsegv_address_t get_fault_instruction(mach_port_t thread, ppc_thread_state_t *state)
527 + {
528 +        kern_return_t krc;
529 +        mach_msg_type_number_t count;
530 +
531 +        count = MACHINE_THREAD_STATE_COUNT;
532 +        krc = thread_get_state(thread, MACHINE_THREAD_STATE, (thread_state_t)state, &count);
533 +        MACH_CHECK_ERROR (thread_get_state, krc);
534 +
535 +        return (sigsegv_address_t)state->srr0;
536 + }
537 + #endif
538 +
539 + // Since there can only be one exception thread running at any time
540 + // this is not a problem.
541 + #define MSG_SIZE 512
542 + static char msgbuf[MSG_SIZE];
543 + static char replybuf[MSG_SIZE];
544 +
545 + /*
546 + * This is the entry point for the exception handler thread. The job
547 + * of this thread is to wait for exception messages on the exception
548 + * port that was setup beforehand and to pass them on to exc_server.
549 + * exc_server is a MIG generated function that is a part of Mach.
550 + * Its job is to decide what to do with the exception message. In our
551 + * case exc_server calls catch_exception_raise on our behalf. After
552 + * exc_server returns, it is our responsibility to send the reply.
553 + */
554 + static void *
555 + handleExceptions(void *priv)
556 + {
557 +        mach_msg_header_t *msg, *reply;
558 +        kern_return_t krc;
559 +
560 +        msg = (mach_msg_header_t *)msgbuf;
561 +        reply = (mach_msg_header_t *)replybuf;
562 +
563 +        for (;;) {
564 +                krc = mach_msg(msg, MACH_RCV_MSG, MSG_SIZE, MSG_SIZE,
565 +                                _exceptionPort, 0, MACH_PORT_NULL);
566 +                MACH_CHECK_ERROR(mach_msg, krc);
567 +
568 +                if (!exc_server(msg, reply)) {
569 +                        fprintf(stderr, "exc_server hated the message\n");
570 +                        exit(1);
571 +                }
572 +
573 +                krc = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0,
574 +                                 msg->msgh_local_port, 0, MACH_PORT_NULL);
575 +                if (krc != KERN_SUCCESS) {
576 +                        fprintf(stderr, "Error sending message to original reply port, krc = %d, %s",
577 +                                krc, mach_error_string(krc));
578 +                        exit(1);
579 +                }
580 +        }
581 + }
582 + #endif
583 + #endif
584  
585  
586   /*
# Line 405 | Line 589 | static sigsegv_address_t get_fault_addre
589  
590   #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
591   // Decode and skip X86 instruction
592 < #if (defined(i386) || defined(__i386__))
592 > #if (defined(i386) || defined(__i386__)) || defined(__x86_64__)
593   #if defined(__linux__)
594   enum {
595 + #if (defined(i386) || defined(__i386__))
596          X86_REG_EIP = 14,
597          X86_REG_EAX = 11,
598          X86_REG_ECX = 10,
# Line 417 | Line 602 | enum {
602          X86_REG_EBP = 6,
603          X86_REG_ESI = 5,
604          X86_REG_EDI = 4
605 + #endif
606 + #if defined(__x86_64__)
607 +        X86_REG_R8  = 0,
608 +        X86_REG_R9  = 1,
609 +        X86_REG_R10 = 2,
610 +        X86_REG_R11 = 3,
611 +        X86_REG_R12 = 4,
612 +        X86_REG_R13 = 5,
613 +        X86_REG_R14 = 6,
614 +        X86_REG_R15 = 7,
615 +        X86_REG_EDI = 8,
616 +        X86_REG_ESI = 9,
617 +        X86_REG_EBP = 10,
618 +        X86_REG_EBX = 11,
619 +        X86_REG_EDX = 12,
620 +        X86_REG_EAX = 13,
621 +        X86_REG_ECX = 14,
622 +        X86_REG_ESP = 15,
623 +        X86_REG_EIP = 16
624 + #endif
625   };
626   #endif
627   #if defined(__NetBSD__) || defined(__FreeBSD__)
628   enum {
629 + #if (defined(i386) || defined(__i386__))
630          X86_REG_EIP = 10,
631          X86_REG_EAX = 7,
632          X86_REG_ECX = 6,
# Line 430 | Line 636 | enum {
636          X86_REG_EBP = 2,
637          X86_REG_ESI = 1,
638          X86_REG_EDI = 0
639 + #endif
640   };
641   #endif
642   // FIXME: this is partly redundant with the instruction decoding phase
# Line 466 | Line 673 | static inline int ix86_step_over_modrm(u
673          return offset;
674   }
675  
676 < static bool ix86_skip_instruction(unsigned int * regs)
676 > static bool ix86_skip_instruction(unsigned long * regs)
677   {
678          unsigned char * eip = (unsigned char *)regs[X86_REG_EIP];
679  
# Line 478 | Line 685 | static bool ix86_skip_instruction(unsign
685          
686          int reg = -1;
687          int len = 0;
688 <        
688 >
689 > #if DEBUG
690 >        printf("IP: %p [%02x %02x %02x %02x...]\n",
691 >                   eip, eip[0], eip[1], eip[2], eip[3]);
692 > #endif
693 >
694          // Operand size prefix
695          if (*eip == 0x66) {
696                  eip++;
# Line 486 | Line 698 | static bool ix86_skip_instruction(unsign
698                  transfer_size = SIZE_WORD;
699          }
700  
701 +        // REX prefix
702 + #if defined(__x86_64__)
703 +        struct rex_t {
704 +                unsigned char W;
705 +                unsigned char R;
706 +                unsigned char X;
707 +                unsigned char B;
708 +        };
709 +        rex_t rex = { 0, 0, 0, 0 };
710 +        bool has_rex = false;
711 +        if ((*eip & 0xf0) == 0x40) {
712 +                has_rex = true;
713 +                const unsigned char b = *eip;
714 +                rex.W = b & (1 << 3);
715 +                rex.R = b & (1 << 2);
716 +                rex.X = b & (1 << 1);
717 +                rex.B = b & (1 << 0);
718 + #if DEBUG
719 +                printf("REX: %c,%c,%c,%c\n",
720 +                           rex.W ? 'W' : '_',
721 +                           rex.R ? 'R' : '_',
722 +                           rex.X ? 'X' : '_',
723 +                           rex.B ? 'B' : '_');
724 + #endif
725 +                eip++;
726 +                len++;
727 +                if (rex.W)
728 +                        transfer_size = SIZE_QUAD;
729 +        }
730 + #else
731 +        const bool has_rex = false;
732 + #endif
733 +
734          // Decode instruction
735          switch (eip[0]) {
736          case 0x0f:
# Line 555 | Line 800 | static bool ix86_skip_instruction(unsign
800                  return false;
801          }
802  
803 + #if defined(__x86_64__)
804 +        if (rex.R)
805 +                reg += 8;
806 + #endif
807 +
808          if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) {
809 <                static const int x86_reg_map[8] = {
809 >                static const int x86_reg_map[] = {
810                          X86_REG_EAX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBX,
811 <                        X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI
811 >                        X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI,
812 > #if defined(__x86_64__)
813 >                        X86_REG_R8,  X86_REG_R9,  X86_REG_R10, X86_REG_R11,
814 >                        X86_REG_R12, X86_REG_R13, X86_REG_R14, X86_REG_R15,
815 > #endif
816                  };
817                  
818 <                if (reg < 0 || reg >= 8)
818 >                if (reg < 0 || reg >= (sizeof(x86_reg_map)/sizeof(x86_reg_map[0]) - 1))
819                          return false;
820  
821 +                // Set 0 to the relevant register part
822 +                // NOTE: this is only valid for MOV alike instructions
823                  int rloc = x86_reg_map[reg];
824                  switch (transfer_size) {
825                  case SIZE_BYTE:
826 <                        regs[rloc] = (regs[rloc] & ~0xff);
826 >                        if (has_rex || reg < 4)
827 >                                regs[rloc] = (regs[rloc] & ~0x00ffL);
828 >                        else {
829 >                                rloc = x86_reg_map[reg - 4];
830 >                                regs[rloc] = (regs[rloc] & ~0xff00L);
831 >                        }
832                          break;
833                  case SIZE_WORD:
834 <                        regs[rloc] = (regs[rloc] & ~0xffff);
834 >                        regs[rloc] = (regs[rloc] & ~0xffffL);
835                          break;
836                  case SIZE_LONG:
837 +                case SIZE_QUAD: // zero-extension
838                          regs[rloc] = 0;
839                          break;
840                  }
# Line 580 | Line 842 | static bool ix86_skip_instruction(unsign
842  
843   #if DEBUG
844          printf("%08x: %s %s access", regs[X86_REG_EIP],
845 <                   transfer_size == SIZE_BYTE ? "byte" : transfer_size == SIZE_WORD ? "word" : "long",
845 >                   transfer_size == SIZE_BYTE ? "byte" :
846 >                   transfer_size == SIZE_WORD ? "word" :
847 >                   transfer_size == SIZE_LONG ? "long" :
848 >                   transfer_size == SIZE_QUAD ? "quad" : "unknown",
849                     transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
850          
851          if (reg != -1) {
852 <                static const char * x86_reg_str_map[8] = {
853 <                        "eax", "ecx", "edx", "ebx",
854 <                        "esp", "ebp", "esi", "edi"
852 >                static const char * x86_byte_reg_str_map[] = {
853 >                        "al",   "cl",   "dl",   "bl",
854 >                        "spl",  "bpl",  "sil",  "dil",
855 >                        "r8b",  "r9b",  "r10b", "r11b",
856 >                        "r12b", "r13b", "r14b", "r15b",
857 >                        "ah",   "ch",   "dh",   "bh",
858 >                };
859 >                static const char * x86_word_reg_str_map[] = {
860 >                        "ax",   "cx",   "dx",   "bx",
861 >                        "sp",   "bp",   "si",   "di",
862 >                        "r8w",  "r9w",  "r10w", "r11w",
863 >                        "r12w", "r13w", "r14w", "r15w",
864                  };
865 <                printf(" %s register %%%s", transfer_type == SIGSEGV_TRANSFER_LOAD ? "to" : "from", x86_reg_str_map[reg]);
865 >                static const char *x86_long_reg_str_map[] = {
866 >                        "eax",  "ecx",  "edx",  "ebx",
867 >                        "esp",  "ebp",  "esi",  "edi",
868 >                        "r8d",  "r9d",  "r10d", "r11d",
869 >                        "r12d", "r13d", "r14d", "r15d",
870 >                };
871 >                static const char *x86_quad_reg_str_map[] = {
872 >                        "rax", "rcx", "rdx", "rbx",
873 >                        "rsp", "rbp", "rsi", "rdi",
874 >                        "r8",  "r9",  "r10", "r11",
875 >                        "r12", "r13", "r14", "r15",
876 >                };
877 >                const char * reg_str = NULL;
878 >                switch (transfer_size) {
879 >                case SIZE_BYTE:
880 >                        reg_str = x86_byte_reg_str_map[(!has_rex && reg >= 4 ? 12 : 0) + reg];
881 >                        break;
882 >                case SIZE_WORD: reg_str = x86_word_reg_str_map[reg]; break;
883 >                case SIZE_LONG: reg_str = x86_long_reg_str_map[reg]; break;
884 >                case SIZE_QUAD: reg_str = x86_quad_reg_str_map[reg]; break;
885 >                }
886 >                if (reg_str)
887 >                        printf(" %s register %%%s",
888 >                                   transfer_type == SIGSEGV_TRANSFER_LOAD ? "to" : "from",
889 >                                   reg_str);
890          }
891          printf(", %d bytes instruction\n", len);
892   #endif
# Line 610 | Line 908 | static bool powerpc_skip_instruction(uns
908                  return false;
909          }
910  
613        ignore_range_list_t::iterator it = sigsegv_find_ignore_range((sigsegv_address_t)instr.addr);
614        if (it == sigsegv_ignore_ranges.end() || ((it->transfer_type & instr.transfer_type) != instr.transfer_type)) {
615                // Address doesn't fall into ignore ranges list, let it crash.
616                return false;
617        }
618
911   #if DEBUG
912          printf("%08x: %s %s access", *nip_p,
913                     instr.transfer_size == SIZE_BYTE ? "byte" : instr.transfer_size == SIZE_WORD ? "word" : "long",
# Line 636 | Line 928 | static bool powerpc_skip_instruction(uns
928          return true;
929   }
930   #endif
931 +
932 + // Decode and skip MIPS instruction
933 + #if (defined(mips) || defined(__mips))
934 + enum {
935 + #if (defined(sgi) || defined(__sgi))
936 +  MIPS_REG_EPC = 35,
937 + #endif
938 + };
939 + static bool mips_skip_instruction(greg_t * regs)
940 + {
941 +  unsigned int * epc = (unsigned int *)(unsigned long)regs[MIPS_REG_EPC];
942 +
943 +  if (epc == 0)
944 +        return false;
945 +
946 + #if DEBUG
947 +  printf("IP: %p [%08x]\n", epc, epc[0]);
948 + #endif
949 +
950 +  transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
951 +  transfer_size_t transfer_size = SIZE_LONG;
952 +  int direction = 0;
953 +
954 +  const unsigned int opcode = epc[0];
955 +  switch (opcode >> 26) {
956 +  case 32: // Load Byte
957 +  case 36: // Load Byte Unsigned
958 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
959 +        transfer_size = SIZE_BYTE;
960 +        break;
961 +  case 33: // Load Halfword
962 +  case 37: // Load Halfword Unsigned
963 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
964 +        transfer_size = SIZE_WORD;
965 +        break;
966 +  case 35: // Load Word
967 +  case 39: // Load Word Unsigned
968 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
969 +        transfer_size = SIZE_LONG;
970 +        break;
971 +  case 34: // Load Word Left
972 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
973 +        transfer_size = SIZE_LONG;
974 +        direction = -1;
975 +        break;
976 +  case 38: // Load Word Right
977 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
978 +        transfer_size = SIZE_LONG;
979 +        direction = 1;
980 +        break;
981 +  case 55: // Load Doubleword
982 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
983 +        transfer_size = SIZE_QUAD;
984 +        break;
985 +  case 26: // Load Doubleword Left
986 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
987 +        transfer_size = SIZE_QUAD;
988 +        direction = -1;
989 +        break;
990 +  case 27: // Load Doubleword Right
991 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
992 +        transfer_size = SIZE_QUAD;
993 +        direction = 1;
994 +        break;
995 +  case 40: // Store Byte
996 +        transfer_type = SIGSEGV_TRANSFER_STORE;
997 +        transfer_size = SIZE_BYTE;
998 +        break;
999 +  case 41: // Store Halfword
1000 +        transfer_type = SIGSEGV_TRANSFER_STORE;
1001 +        transfer_size = SIZE_WORD;
1002 +        break;
1003 +  case 43: // Store Word
1004 +  case 42: // Store Word Left
1005 +  case 46: // Store Word Right
1006 +        transfer_type = SIGSEGV_TRANSFER_STORE;
1007 +        transfer_size = SIZE_LONG;
1008 +        break;
1009 +  case 63: // Store Doubleword
1010 +  case 44: // Store Doubleword Left
1011 +  case 45: // Store Doubleword Right
1012 +        transfer_type = SIGSEGV_TRANSFER_STORE;
1013 +        transfer_size = SIZE_QUAD;
1014 +        break;
1015 +  /* Misc instructions unlikely to be used within CPU emulators */
1016 +  case 48: // Load Linked Word
1017 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
1018 +        transfer_size = SIZE_LONG;
1019 +        break;
1020 +  case 52: // Load Linked Doubleword
1021 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
1022 +        transfer_size = SIZE_QUAD;
1023 +        break;
1024 +  case 56: // Store Conditional Word
1025 +        transfer_type = SIGSEGV_TRANSFER_STORE;
1026 +        transfer_size = SIZE_LONG;
1027 +        break;
1028 +  case 60: // Store Conditional Doubleword
1029 +        transfer_type = SIGSEGV_TRANSFER_STORE;
1030 +        transfer_size = SIZE_QUAD;
1031 +        break;
1032 +  }
1033 +
1034 +  if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1035 +        // Unknown machine code, let it crash. Then patch the decoder
1036 +        return false;
1037 +  }
1038 +
1039 +  // Zero target register in case of a load operation
1040 +  const int reg = (opcode >> 16) & 0x1f;
1041 +  if (transfer_type == SIGSEGV_TRANSFER_LOAD) {
1042 +        if (direction == 0)
1043 +          regs[reg] = 0;
1044 +        else {
1045 +          // FIXME: untested code
1046 +          unsigned long ea = regs[(opcode >> 21) & 0x1f];
1047 +          ea += (signed long)(signed int)(signed short)(opcode & 0xffff);
1048 +          const int offset = ea & (transfer_size == SIZE_LONG ? 3 : 7);
1049 +          unsigned long value;
1050 +          if (direction > 0) {
1051 +                const unsigned long rmask = ~((1L << ((offset + 1) * 8)) - 1);
1052 +                value = regs[reg] & rmask;
1053 +          }
1054 +          else {
1055 +                const unsigned long lmask = (1L << (offset * 8)) - 1;
1056 +                value = regs[reg] & lmask;
1057 +          }
1058 +          // restore most significant bits
1059 +          if (transfer_size == SIZE_LONG)
1060 +                value = (signed long)(signed int)value;
1061 +          regs[reg] = value;
1062 +        }
1063 +  }
1064 +
1065 + #if DEBUG
1066 + #if (defined(_ABIN32) || defined(_ABI64))
1067 +  static const char * mips_gpr_names[32] = {
1068 +        "zero", "at",   "v0",   "v1",   "a0",   "a1",   "a2",   "a3",
1069 +        "t0",   "t1",   "t2",   "t3",   "t4",   "t5",   "t6",   "t7",
1070 +        "s0",   "s1",   "s2",   "s3",   "s4",   "s5",   "s6",   "s7",
1071 +        "t8",   "t9",   "k0",   "k1",   "gp",   "sp",   "s8",   "ra"
1072 +  };
1073 + #else
1074 +  static const char * mips_gpr_names[32] = {
1075 +        "zero", "at",   "v0",   "v1",   "a0",   "a1",   "a2",   "a3",
1076 +        "a4",   "a5",   "a6",   "a7",   "t0",   "t1",   "t2",   "t3",
1077 +        "s0",   "s1",   "s2",   "s3",   "s4",   "s5",   "s6",   "s7",
1078 +        "t8",   "t9",   "k0",   "k1",   "gp",   "sp",   "s8",   "ra"
1079 +  };
1080 + #endif
1081 +  printf("%s %s register %s\n",
1082 +                 transfer_size == SIZE_BYTE ? "byte" :
1083 +                 transfer_size == SIZE_WORD ? "word" :
1084 +                 transfer_size == SIZE_LONG ? "long" :
1085 +                 transfer_size == SIZE_QUAD ? "quad" : "unknown",
1086 +                 transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1087 +                 mips_gpr_names[reg]);
1088 + #endif
1089 +
1090 +  regs[MIPS_REG_EPC] += 4;
1091 +  return true;
1092 + }
1093 + #endif
1094   #endif
1095  
1096   // Fallbacks
1097   #ifndef SIGSEGV_FAULT_INSTRUCTION
1098   #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_INVALID_PC
1099   #endif
1100 + #ifndef SIGSEGV_FAULT_HANDLER_ARGLIST_1
1101 + #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 SIGSEGV_FAULT_HANDLER_ARGLIST
1102 + #endif
1103 + #ifndef SIGSEGV_FAULT_HANDLER_INVOKE
1104 + #define SIGSEGV_FAULT_HANDLER_INVOKE(ADDR, IP)  sigsegv_fault_handler(ADDR, IP)
1105 + #endif
1106  
1107   // SIGSEGV recovery supported ?
1108   #if defined(SIGSEGV_ALL_SIGNALS) && defined(SIGSEGV_FAULT_HANDLER_ARGLIST) && defined(SIGSEGV_FAULT_ADDRESS)
# Line 653 | Line 1114 | static bool powerpc_skip_instruction(uns
1114   *  SIGSEGV global handler
1115   */
1116  
1117 < #ifdef HAVE_SIGSEGV_RECOVERY
1118 < static void sigsegv_handler(SIGSEGV_FAULT_HANDLER_ARGLIST)
1117 > #if defined(HAVE_SIGSEGV_RECOVERY) || defined(HAVE_MACH_EXCEPTIONS)
1118 > // This function handles the badaccess to memory.
1119 > // It is called from the signal handler or the exception handler.
1120 > static bool handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGLIST_1)
1121   {
1122          sigsegv_address_t fault_address = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
1123          sigsegv_address_t fault_instruction = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
661        bool fault_recovered = false;
1124          
1125          // Call user's handler and reinstall the global handler, if required
1126 <        if (sigsegv_fault_handler(fault_address, fault_instruction)) {
1127 < #if (defined(HAVE_SIGACTION) ? defined(SIGACTION_NEED_REINSTALL) : defined(SIGNAL_NEED_REINSTALL))
1128 <                sigsegv_do_install_handler(sig);
1126 >        switch (SIGSEGV_FAULT_HANDLER_INVOKE(fault_address, fault_instruction)) {
1127 >        case SIGSEGV_RETURN_SUCCESS:
1128 >                return true;
1129 >
1130 > #if HAVE_SIGSEGV_SKIP_INSTRUCTION
1131 >        case SIGSEGV_RETURN_SKIP_INSTRUCTION:
1132 >                // Call the instruction skipper with the register file
1133 >                // available
1134 >                if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE)) {
1135 > #ifdef HAVE_MACH_EXCEPTIONS
1136 >                        // Unlike UNIX signals where the thread state
1137 >                        // is modified off of the stack, in Mach we
1138 >                        // need to actually call thread_set_state to
1139 >                        // have the register values updated.
1140 >                        kern_return_t krc;
1141 >
1142 >                        krc = thread_set_state(thread,
1143 >                                                                   MACHINE_THREAD_STATE, (thread_state_t)state,
1144 >                                                                   MACHINE_THREAD_STATE_COUNT);
1145 >                        MACH_CHECK_ERROR (thread_get_state, krc);
1146 > #endif
1147 >                        return true;
1148 >                }
1149 >                break;
1150   #endif
668                fault_recovered = true;
1151          }
1152 < #if HAVE_SIGSEGV_SKIP_INSTRUCTION
1153 <        else if (sigsegv_ignore_ranges.size() > 0) {
1154 <                // Call the instruction skipper with the register file available
1155 <                if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE))
1156 <                        fault_recovered = true;
1152 >        
1153 >        // We can't do anything with the fault_address, dump state?
1154 >        if (sigsegv_state_dumper != 0)
1155 >                sigsegv_state_dumper(fault_address, fault_instruction);
1156 >
1157 >        return false;
1158 > }
1159 > #endif
1160 >
1161 >
1162 > /*
1163 > * There are two mechanisms for handling a bad memory access,
1164 > * Mach exceptions and UNIX signals. The implementation specific
1165 > * code appears below. Its reponsibility is to call handle_badaccess
1166 > * which is the routine that handles the fault in an implementation
1167 > * agnostic manner. The implementation specific code below is then
1168 > * reponsible for checking whether handle_badaccess was able
1169 > * to handle the memory access error and perform any implementation
1170 > * specific tasks necessary afterwards.
1171 > */
1172 >
1173 > #ifdef HAVE_MACH_EXCEPTIONS
1174 > /*
1175 > * We need to forward all exceptions that we do not handle.
1176 > * This is important, there are many exceptions that may be
1177 > * handled by other exception handlers. For example debuggers
1178 > * use exceptions and the exception hander is in another
1179 > * process in such a case. (Timothy J. Wood states in his
1180 > * message to the list that he based this code on that from
1181 > * gdb for Darwin.)
1182 > */
1183 > static inline kern_return_t
1184 > forward_exception(mach_port_t thread_port,
1185 >                                  mach_port_t task_port,
1186 >                                  exception_type_t exception_type,
1187 >                                  exception_data_t exception_data,
1188 >                                  mach_msg_type_number_t data_count,
1189 >                                  ExceptionPorts *oldExceptionPorts)
1190 > {
1191 >        kern_return_t kret;
1192 >        unsigned int portIndex;
1193 >        mach_port_t port;
1194 >        exception_behavior_t behavior;
1195 >        thread_state_flavor_t flavor;
1196 >        thread_state_t thread_state;
1197 >        mach_msg_type_number_t thread_state_count;
1198 >
1199 >        for (portIndex = 0; portIndex < oldExceptionPorts->maskCount; portIndex++) {
1200 >                if (oldExceptionPorts->masks[portIndex] & (1 << exception_type)) {
1201 >                        // This handler wants the exception
1202 >                        break;
1203 >                }
1204          }
1205 +
1206 +        if (portIndex >= oldExceptionPorts->maskCount) {
1207 +                fprintf(stderr, "No handler for exception_type = %d. Not fowarding\n", exception_type);
1208 +                return KERN_FAILURE;
1209 +        }
1210 +
1211 +        port = oldExceptionPorts->handlers[portIndex];
1212 +        behavior = oldExceptionPorts->behaviors[portIndex];
1213 +        flavor = oldExceptionPorts->flavors[portIndex];
1214 +
1215 +        /*
1216 +         fprintf(stderr, "forwarding exception, port = 0x%x, behaviour = %d, flavor = %d\n", port, behavior, flavor);
1217 +         */
1218 +
1219 +        if (behavior != EXCEPTION_DEFAULT) {
1220 +                thread_state_count = THREAD_STATE_MAX;
1221 +                kret = thread_get_state (thread_port, flavor, thread_state,
1222 +                                                                 &thread_state_count);
1223 +                MACH_CHECK_ERROR (thread_get_state, kret);
1224 +        }
1225 +
1226 +        switch (behavior) {
1227 +        case EXCEPTION_DEFAULT:
1228 +          // fprintf(stderr, "forwarding to exception_raise\n");
1229 +          kret = exception_raise(port, thread_port, task_port, exception_type,
1230 +                                                         exception_data, data_count);
1231 +          MACH_CHECK_ERROR (exception_raise, kret);
1232 +          break;
1233 +        case EXCEPTION_STATE:
1234 +          // fprintf(stderr, "forwarding to exception_raise_state\n");
1235 +          kret = exception_raise_state(port, exception_type, exception_data,
1236 +                                                                   data_count, &flavor,
1237 +                                                                   thread_state, thread_state_count,
1238 +                                                                   thread_state, &thread_state_count);
1239 +          MACH_CHECK_ERROR (exception_raise_state, kret);
1240 +          break;
1241 +        case EXCEPTION_STATE_IDENTITY:
1242 +          // fprintf(stderr, "forwarding to exception_raise_state_identity\n");
1243 +          kret = exception_raise_state_identity(port, thread_port, task_port,
1244 +                                                                                        exception_type, exception_data,
1245 +                                                                                        data_count, &flavor,
1246 +                                                                                        thread_state, thread_state_count,
1247 +                                                                                        thread_state, &thread_state_count);
1248 +          MACH_CHECK_ERROR (exception_raise_state_identity, kret);
1249 +          break;
1250 +        default:
1251 +          fprintf(stderr, "forward_exception got unknown behavior\n");
1252 +          break;
1253 +        }
1254 +
1255 +        if (behavior != EXCEPTION_DEFAULT) {
1256 +                kret = thread_set_state (thread_port, flavor, thread_state,
1257 +                                                                 thread_state_count);
1258 +                MACH_CHECK_ERROR (thread_set_state, kret);
1259 +        }
1260 +
1261 +        return KERN_SUCCESS;
1262 + }
1263 +
1264 + /*
1265 + * This is the code that actually handles the exception.
1266 + * It is called by exc_server. For Darwin 5 Apple changed
1267 + * this a bit from how this family of functions worked in
1268 + * Mach. If you are familiar with that it is a little
1269 + * different. The main variation that concerns us here is
1270 + * that code is an array of exception specific codes and
1271 + * codeCount is a count of the number of codes in the code
1272 + * array. In typical Mach all exceptions have a code
1273 + * and sub-code. It happens to be the case that for a
1274 + * EXC_BAD_ACCESS exception the first entry is the type of
1275 + * bad access that occurred and the second entry is the
1276 + * faulting address so these entries correspond exactly to
1277 + * how the code and sub-code are used on Mach.
1278 + *
1279 + * This is a MIG interface. No code in Basilisk II should
1280 + * call this directley. This has to have external C
1281 + * linkage because that is what exc_server expects.
1282 + */
1283 + kern_return_t
1284 + catch_exception_raise(mach_port_t exception_port,
1285 +                                          mach_port_t thread,
1286 +                                          mach_port_t task,
1287 +                                          exception_type_t exception,
1288 +                                          exception_data_t code,
1289 +                                          mach_msg_type_number_t codeCount)
1290 + {
1291 +        ppc_thread_state_t state;
1292 +        kern_return_t krc;
1293 +
1294 +        if ((exception == EXC_BAD_ACCESS)  && (codeCount >= 2)) {
1295 +                if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS))
1296 +                        return KERN_SUCCESS;
1297 +        }
1298 +
1299 +        // In Mach we do not need to remove the exception handler.
1300 +        // If we forward the exception, eventually some exception handler
1301 +        // will take care of this exception.
1302 +        krc = forward_exception(thread, task, exception, code, codeCount, &ports);
1303 +
1304 +        return krc;
1305 + }
1306 + #endif
1307 +
1308 + #ifdef HAVE_SIGSEGV_RECOVERY
1309 + // Handle bad memory accesses with signal handler
1310 + static void sigsegv_handler(SIGSEGV_FAULT_HANDLER_ARGLIST)
1311 + {
1312 +        // Call handler and reinstall the global handler, if required
1313 +        if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS)) {
1314 + #if (defined(HAVE_SIGACTION) ? defined(SIGACTION_NEED_REINSTALL) : defined(SIGNAL_NEED_REINSTALL))
1315 +                sigsegv_do_install_handler(sig);
1316   #endif
1317 +                return;
1318 +        }
1319  
1320 <        if (!fault_recovered) {
679 <                // FAIL: reinstall default handler for "safe" crash
1320 >        // Failure: reinstall default handler for "safe" crash
1321   #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
1322 <                SIGSEGV_ALL_SIGNALS
1322 >        SIGSEGV_ALL_SIGNALS
1323   #undef FAULT_HANDLER
683                
684                // We can't do anything with the fault_address, dump state?
685                if (sigsegv_state_dumper != 0)
686                        sigsegv_state_dumper(fault_address, fault_instruction);
687        }
1324   }
1325   #endif
1326  
# Line 729 | Line 1365 | static bool sigsegv_do_install_handler(i
1365   }
1366   #endif
1367  
1368 < bool sigsegv_install_handler(sigsegv_fault_handler_t handler)
1368 > #if defined(HAVE_MACH_EXCEPTIONS)
1369 > static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
1370   {
1371 < #ifdef HAVE_SIGSEGV_RECOVERY
1371 >        /*
1372 >         * Except for the exception port functions, this should be
1373 >         * pretty much stock Mach. If later you choose to support
1374 >         * other Mach's besides Darwin, just check for __MACH__
1375 >         * here and __APPLE__ where the actual differences are.
1376 >         */
1377 > #if defined(__APPLE__) && defined(__MACH__)
1378 >        if (sigsegv_fault_handler != NULL) {
1379 >                sigsegv_fault_handler = handler;
1380 >                return true;
1381 >        }
1382 >
1383 >        kern_return_t krc;
1384 >
1385 >        // create the the exception port
1386 >        krc = mach_port_allocate(mach_task_self(),
1387 >                          MACH_PORT_RIGHT_RECEIVE, &_exceptionPort);
1388 >        if (krc != KERN_SUCCESS) {
1389 >                mach_error("mach_port_allocate", krc);
1390 >                return false;
1391 >        }
1392 >
1393 >        // add a port send right
1394 >        krc = mach_port_insert_right(mach_task_self(),
1395 >                              _exceptionPort, _exceptionPort,
1396 >                              MACH_MSG_TYPE_MAKE_SEND);
1397 >        if (krc != KERN_SUCCESS) {
1398 >                mach_error("mach_port_insert_right", krc);
1399 >                return false;
1400 >        }
1401 >
1402 >        // get the old exception ports
1403 >        ports.maskCount = sizeof (ports.masks) / sizeof (ports.masks[0]);
1404 >        krc = thread_get_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, ports.masks,
1405 >                                &ports.maskCount, ports.handlers, ports.behaviors, ports.flavors);
1406 >        if (krc != KERN_SUCCESS) {
1407 >                mach_error("thread_get_exception_ports", krc);
1408 >                return false;
1409 >        }
1410 >
1411 >        // set the new exception port
1412 >        //
1413 >        // We could have used EXCEPTION_STATE_IDENTITY instead of
1414 >        // EXCEPTION_DEFAULT to get the thread state in the initial
1415 >        // message, but it turns out that in the common case this is not
1416 >        // neccessary. If we need it we can later ask for it from the
1417 >        // suspended thread.
1418 >        //
1419 >        // Even with THREAD_STATE_NONE, Darwin provides the program
1420 >        // counter in the thread state.  The comments in the header file
1421 >        // seem to imply that you can count on the GPR's on an exception
1422 >        // as well but just to be safe I use MACHINE_THREAD_STATE because
1423 >        // you have to ask for all of the GPR's anyway just to get the
1424 >        // program counter. In any case because of update effective
1425 >        // address from immediate and update address from effective
1426 >        // addresses of ra and rb modes (as good an name as any for these
1427 >        // addressing modes) used in PPC instructions, you will need the
1428 >        // GPR state anyway.
1429 >        krc = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, _exceptionPort,
1430 >                                EXCEPTION_DEFAULT, MACHINE_THREAD_STATE);
1431 >        if (krc != KERN_SUCCESS) {
1432 >                mach_error("thread_set_exception_ports", krc);
1433 >                return false;
1434 >        }
1435 >
1436 >        // create the exception handler thread
1437 >        if (pthread_create(&exc_thread, NULL, &handleExceptions, NULL) != 0) {
1438 >                (void)fprintf(stderr, "creation of exception thread failed\n");
1439 >                return false;
1440 >        }
1441 >
1442 >        // do not care about the exception thread any longer, let is run standalone
1443 >        (void)pthread_detach(exc_thread);
1444 >
1445          sigsegv_fault_handler = handler;
1446 +        return true;
1447 + #else
1448 +        return false;
1449 + #endif
1450 + }
1451 + #endif
1452 +
1453 + bool sigsegv_install_handler(sigsegv_fault_handler_t handler)
1454 + {
1455 + #if defined(HAVE_SIGSEGV_RECOVERY)
1456          bool success = true;
1457   #define FAULT_HANDLER(sig) success = success && sigsegv_do_install_handler(sig);
1458          SIGSEGV_ALL_SIGNALS
1459   #undef FAULT_HANDLER
1460 +        if (success)
1461 +            sigsegv_fault_handler = handler;
1462          return success;
1463 + #elif defined(HAVE_MACH_EXCEPTIONS)
1464 +        return sigsegv_do_install_handler(handler);
1465   #else
1466          // FAIL: no siginfo_t nor sigcontext subterfuge is available
1467          return false;
# Line 751 | Line 1475 | bool sigsegv_install_handler(sigsegv_fau
1475  
1476   void sigsegv_deinstall_handler(void)
1477   {
1478 +  // We do nothing for Mach exceptions, the thread would need to be
1479 +  // suspended if not already so, and we might mess with other
1480 +  // exception handlers that came after we registered ours. There is
1481 +  // no need to remove the exception handler, in fact this function is
1482 +  // not called anywhere in Basilisk II.
1483   #ifdef HAVE_SIGSEGV_RECOVERY
1484          sigsegv_fault_handler = 0;
1485   #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
# Line 761 | Line 1490 | void sigsegv_deinstall_handler(void)
1490  
1491  
1492   /*
764 *  Add SIGSEGV ignore range
765 */
766
767 void sigsegv_add_ignore_range(sigsegv_address_t address, unsigned long length, int transfer_type)
768 {
769        ignore_range_t ignore_range;
770        ignore_range.start = address;
771        ignore_range.length = length;
772        ignore_range.transfer_type = transfer_type;
773        sigsegv_ignore_ranges.push_front(ignore_range);
774 }
775
776
777 /*
778 *  Remove SIGSEGV ignore range. Range must match installed one, otherwise FALSE is returned.
779 */
780
781 bool sigsegv_remove_ignore_range(sigsegv_address_t address, unsigned long length, int transfer_type)
782 {
783        ignore_range_list_t::iterator it;
784        for (it = sigsegv_ignore_ranges.begin(); it != sigsegv_ignore_ranges.end(); it++)
785                if (it->start == address && it->length == length && ((it->transfer_type & transfer_type) == transfer_type))
786                        break;
787
788        if (it != sigsegv_ignore_ranges.end()) {
789                if (it->transfer_type != transfer_type)
790                        it->transfer_type &= ~transfer_type;
791                else
792                        sigsegv_ignore_ranges.erase(it);
793                return true;
794        }
795
796        return false;
797 }
798
799
800 /*
1493   *  Set callback function when we cannot handle the fault
1494   */
1495  
# Line 818 | Line 1510 | void sigsegv_set_dump_state(sigsegv_stat
1510   #include <sys/mman.h>
1511   #include "vm_alloc.h"
1512  
1513 + const int REF_INDEX = 123;
1514 + const int REF_VALUE = 45;
1515 +
1516   static int page_size;
1517   static volatile char * page = 0;
1518   static volatile int handler_called = 0;
1519  
1520 < static bool sigsegv_test_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
1520 > #ifdef __GNUC__
1521 > // Code range where we expect the fault to come from
1522 > static void *b_region, *e_region;
1523 > #endif
1524 >
1525 > static sigsegv_return_t sigsegv_test_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
1526   {
1527          handler_called++;
1528 <        if ((fault_address - 123) != page)
1529 <                exit(1);
1528 >        if ((fault_address - REF_INDEX) != page)
1529 >                exit(10);
1530 > #ifdef __GNUC__
1531 >        // Make sure reported fault instruction address falls into
1532 >        // expected code range
1533 >        if (instruction_address != SIGSEGV_INVALID_PC
1534 >                && ((instruction_address <  (sigsegv_address_t)b_region) ||
1535 >                        (instruction_address >= (sigsegv_address_t)e_region)))
1536 >                exit(11);
1537 > #endif
1538          if (vm_protect((char *)((unsigned long)fault_address & -page_size), page_size, VM_PAGE_READ | VM_PAGE_WRITE) != 0)
1539 <                exit(1);
1540 <        return true;
1539 >                exit(12);
1540 >        return SIGSEGV_RETURN_SUCCESS;
1541   }
1542  
1543   #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1544 < static bool sigsegv_insn_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
1544 > static sigsegv_return_t sigsegv_insn_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
1545   {
1546 <        return false;
1546 >        if (((unsigned long)fault_address - (unsigned long)page) < page_size) {
1547 > #ifdef __GNUC__
1548 >                // Make sure reported fault instruction address falls into
1549 >                // expected code range
1550 >                if (instruction_address != SIGSEGV_INVALID_PC
1551 >                        && ((instruction_address <  (sigsegv_address_t)b_region) ||
1552 >                                (instruction_address >= (sigsegv_address_t)e_region)))
1553 >                        return SIGSEGV_RETURN_FAILURE;
1554 > #endif
1555 >                return SIGSEGV_RETURN_SKIP_INSTRUCTION;
1556 >        }
1557 >
1558 >        return SIGSEGV_RETURN_FAILURE;
1559 > }
1560 >
1561 > // More sophisticated tests for instruction skipper
1562 > static bool arch_insn_skipper_tests()
1563 > {
1564 > #if (defined(i386) || defined(__i386__)) || defined(__x86_64__)
1565 >        static const unsigned char code[] = {
1566 >                0x8a, 0x00,                    // mov    (%eax),%al
1567 >                0x8a, 0x2c, 0x18,              // mov    (%eax,%ebx,1),%ch
1568 >                0x88, 0x20,                    // mov    %ah,(%eax)
1569 >                0x88, 0x08,                    // mov    %cl,(%eax)
1570 >                0x66, 0x8b, 0x00,              // mov    (%eax),%ax
1571 >                0x66, 0x8b, 0x0c, 0x18,        // mov    (%eax,%ebx,1),%cx
1572 >                0x66, 0x89, 0x00,              // mov    %ax,(%eax)
1573 >                0x66, 0x89, 0x0c, 0x18,        // mov    %cx,(%eax,%ebx,1)
1574 >                0x8b, 0x00,                    // mov    (%eax),%eax
1575 >                0x8b, 0x0c, 0x18,              // mov    (%eax,%ebx,1),%ecx
1576 >                0x89, 0x00,                    // mov    %eax,(%eax)
1577 >                0x89, 0x0c, 0x18,              // mov    %ecx,(%eax,%ebx,1)
1578 > #if defined(__x86_64__)
1579 >                0x44, 0x8a, 0x00,              // mov    (%rax),%r8b
1580 >                0x44, 0x8a, 0x20,              // mov    (%rax),%r12b
1581 >                0x42, 0x8a, 0x3c, 0x10,        // mov    (%rax,%r10,1),%dil
1582 >                0x44, 0x88, 0x00,              // mov    %r8b,(%rax)
1583 >                0x44, 0x88, 0x20,              // mov    %r12b,(%rax)
1584 >                0x42, 0x88, 0x3c, 0x10,        // mov    %dil,(%rax,%r10,1)
1585 >                0x66, 0x44, 0x8b, 0x00,        // mov    (%rax),%r8w
1586 >                0x66, 0x42, 0x8b, 0x0c, 0x10,  // mov    (%rax,%r10,1),%cx
1587 >                0x66, 0x44, 0x89, 0x00,        // mov    %r8w,(%rax)
1588 >                0x66, 0x42, 0x89, 0x0c, 0x10,  // mov    %cx,(%rax,%r10,1)
1589 >                0x44, 0x8b, 0x00,              // mov    (%rax),%r8d
1590 >                0x42, 0x8b, 0x0c, 0x10,        // mov    (%rax,%r10,1),%ecx
1591 >                0x44, 0x89, 0x00,              // mov    %r8d,(%rax)
1592 >                0x42, 0x89, 0x0c, 0x10,        // mov    %ecx,(%rax,%r10,1)
1593 >                0x48, 0x8b, 0x08,              // mov    (%rax),%rcx
1594 >                0x4c, 0x8b, 0x18,              // mov    (%rax),%r11
1595 >                0x4a, 0x8b, 0x0c, 0x10,        // mov    (%rax,%r10,1),%rcx
1596 >                0x4e, 0x8b, 0x1c, 0x10,        // mov    (%rax,%r10,1),%r11
1597 >                0x48, 0x89, 0x08,              // mov    %rcx,(%rax)
1598 >                0x4c, 0x89, 0x18,              // mov    %r11,(%rax)
1599 >                0x4a, 0x89, 0x0c, 0x10,        // mov    %rcx,(%rax,%r10,1)
1600 >                0x4e, 0x89, 0x1c, 0x10,        // mov    %r11,(%rax,%r10,1)
1601 > #endif
1602 >                0                              // end
1603 >        };
1604 >        const int N_REGS = 20;
1605 >        unsigned long regs[N_REGS];
1606 >        for (int i = 0; i < N_REGS; i++)
1607 >                regs[i] = i;
1608 >        const unsigned long start_code = (unsigned long)&code;
1609 >        regs[X86_REG_EIP] = start_code;
1610 >        while ((regs[X86_REG_EIP] - start_code) < (sizeof(code) - 1)
1611 >                   && ix86_skip_instruction(regs))
1612 >                ; /* simply iterate */
1613 >        return (regs[X86_REG_EIP] - start_code) == (sizeof(code) - 1);
1614 > #endif
1615 >        return true;
1616   }
1617   #endif
1618  
# Line 846 | Line 1623 | int main(void)
1623  
1624          page_size = getpagesize();
1625          if ((page = (char *)vm_acquire(page_size)) == VM_MAP_FAILED)
1626 <                return 1;
1626 >                return 2;
1627          
1628 +        memset((void *)page, 0, page_size);
1629          if (vm_protect((char *)page, page_size, VM_PAGE_READ) < 0)
1630 <                return 1;
1630 >                return 3;
1631          
1632          if (!sigsegv_install_handler(sigsegv_test_handler))
1633 <                return 1;
856 <        
857 <        page[123] = 45;
858 <        page[123] = 45;
1633 >                return 4;
1634          
1635 + #ifdef __GNUC__
1636 +        b_region = &&L_b_region1;
1637 +        e_region = &&L_e_region1;
1638 + #endif
1639 + L_b_region1:
1640 +        page[REF_INDEX] = REF_VALUE;
1641 +        if (page[REF_INDEX] != REF_VALUE)
1642 +          exit(20);
1643 +        page[REF_INDEX] = REF_VALUE;
1644 + L_e_region1:
1645 +
1646          if (handler_called != 1)
1647 <                return 1;
1647 >                return 5;
1648  
1649   #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1650          if (!sigsegv_install_handler(sigsegv_insn_handler))
1651 <                return 1;
1651 >                return 6;
1652          
1653          if (vm_protect((char *)page, page_size, VM_PAGE_READ | VM_PAGE_WRITE) < 0)
1654 <                return 1;
1654 >                return 7;
1655          
1656          for (int i = 0; i < page_size; i++)
1657                  page[i] = (i + 1) % page_size;
1658          
1659          if (vm_protect((char *)page, page_size, VM_PAGE_NOACCESS) < 0)
1660 <                return 1;
1660 >                return 8;
1661          
876        sigsegv_add_ignore_range((char *)page, page_size, SIGSEGV_TRANSFER_LOAD | SIGSEGV_TRANSFER_STORE);
877
1662   #define TEST_SKIP_INSTRUCTION(TYPE) do {                                \
1663 <                const unsigned int TAG = 0x12345678;                    \
1663 >                const unsigned long TAG = 0x12345678 |                  \
1664 >                (sizeof(long) == 8 ? 0x9abcdef0UL << 31 : 0);   \
1665                  TYPE data = *((TYPE *)(page + sizeof(TYPE)));   \
1666 <                volatile unsigned int effect = data + TAG;              \
1666 >                volatile unsigned long effect = data + TAG;             \
1667                  if (effect != TAG)                                                              \
1668 <                        return 1;                                                                       \
1668 >                        return 9;                                                                       \
1669          } while (0)
1670          
1671 + #ifdef __GNUC__
1672 +        b_region = &&L_b_region2;
1673 +        e_region = &&L_e_region2;
1674 + #endif
1675 + L_b_region2:
1676          TEST_SKIP_INSTRUCTION(unsigned char);
1677          TEST_SKIP_INSTRUCTION(unsigned short);
1678          TEST_SKIP_INSTRUCTION(unsigned int);
1679 +        TEST_SKIP_INSTRUCTION(unsigned long);
1680 + L_e_region2:
1681 +
1682 +        if (!arch_insn_skipper_tests())
1683 +                return 20;
1684   #endif
1685  
1686          vm_exit();

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines