emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] Changes to emacs/gc/os_dep.c [Boehm-GC]


From: Dave Love
Subject: [Emacs-diffs] Changes to emacs/gc/os_dep.c [Boehm-GC]
Date: Mon, 16 Jun 2003 11:41:53 -0400

Index: emacs/gc/os_dep.c
diff -c emacs/gc/os_dep.c:1.2.2.2 emacs/gc/os_dep.c:1.2.2.3
*** emacs/gc/os_dep.c:1.2.2.2   Fri Jun  6 05:44:19 2003
--- emacs/gc/os_dep.c   Mon Jun 16 11:41:51 2003
***************
*** 132,137 ****
--- 132,142 ----
  # define jmp_buf sigjmp_buf
  #endif
  
+ #ifdef DARWIN
+ /* for get_etext and friends */
+ #include <mach-o/getsect.h>
+ #endif
+ 
  #ifdef DJGPP
    /* Apparently necessary for djgpp 2.01.  May cause problems with    */
    /* other versions.                                                  */
***************
*** 150,155 ****
--- 155,310 ----
  # define OPT_PROT_EXEC 0
  #endif
  
+ #if defined(LINUX) && \
+     (defined(USE_PROC_FOR_LIBRARIES) || defined(IA64) || 
!defined(SMALL_CONFIG))
+ 
+ /* We need to parse /proc/self/maps, either to find dynamic libraries,        
*/
+ /* and/or to find the register backing store base (IA64).  Do it once */
+ /* here.                                                              */
+ 
+ #define READ read
+ 
+ /* Repeatedly perform a read call until the buffer is filled or       */
+ /* we encounter EOF.                                          */
+ ssize_t GC_repeat_read(int fd, char *buf, size_t count)
+ {
+     ssize_t num_read = 0;
+     ssize_t result;
+     
+     while (num_read < count) {
+       result = READ(fd, buf + num_read, count - num_read);
+       if (result < 0) return result;
+       if (result == 0) break;
+       num_read += result;
+     }
+     return num_read;
+ }
+ 
+ /*
+  * Apply fn to a buffer containing the contents of /proc/self/maps.
+  * Return the result of fn or, if we failed, 0.
+  */
+ 
+ word GC_apply_to_maps(word (*fn)(char *))
+ {
+     int f;
+     int result;
+     int maps_size;
+     char maps_temp[32768];
+     char *maps_buf;
+ 
+     /* Read /proc/self/maps   */
+         /* Note that we may not allocate, and thus can't use stdio.   */
+         f = open("/proc/self/maps", O_RDONLY);
+         if (-1 == f) return 0;
+       /* stat() doesn't work for /proc/self/maps, so we have to
+          read it to find out how large it is... */
+       maps_size = 0;
+       do {
+           result = GC_repeat_read(f, maps_temp, sizeof(maps_temp));
+           if (result <= 0) return 0;
+           maps_size += result;
+       } while (result == sizeof(maps_temp));
+ 
+       if (maps_size > sizeof(maps_temp)) {
+           /* If larger than our buffer, close and re-read it. */
+           close(f);
+           f = open("/proc/self/maps", O_RDONLY);
+           if (-1 == f) return 0;
+           maps_buf = alloca(maps_size);
+           if (NULL == maps_buf) return 0;
+           result = GC_repeat_read(f, maps_buf, maps_size);
+           if (result <= 0) return 0;
+       } else {
+           /* Otherwise use the fixed size buffer */
+           maps_buf = maps_temp;
+       }
+ 
+       close(f);
+         maps_buf[result] = '\0';
+       
+     /* Apply fn to result. */
+       return fn(maps_buf);
+ }
+ 
+ #endif /* Need GC_apply_to_maps */
+ 
+ #if defined(LINUX) && (defined(USE_PROC_FOR_LIBRARIES) || defined(IA64))
+ //
+ //  GC_parse_map_entry parses an entry from /proc/self/maps so we can
+ //  locate all writable data segments that belong to shared libraries.
+ //  The format of one of these entries and the fields we care about
+ //  is as follows:
+ //  XXXXXXXX-XXXXXXXX r-xp 00000000 30:05 260537     name of mapping...\n
+ //  ^^^^^^^^ ^^^^^^^^ ^^^^          ^^
+ //  start    end      prot          maj_dev
+ //  0        9        18            32
+ //  
+ //  For 64 bit ABIs:
+ //  0      17       34            56
+ //
+ //  The parser is called with a pointer to the entry and the return value
+ //  is either NULL or is advanced to the next entry(the byte after the
+ //  trailing '\n'.)
+ //
+ #if CPP_WORDSZ == 32
+ # define OFFSET_MAP_START   0
+ # define OFFSET_MAP_END     9
+ # define OFFSET_MAP_PROT   18
+ # define OFFSET_MAP_MAJDEV 32
+ # define ADDR_WIDTH       8
+ #endif
+ 
+ #if CPP_WORDSZ == 64
+ # define OFFSET_MAP_START   0
+ # define OFFSET_MAP_END    17
+ # define OFFSET_MAP_PROT   34
+ # define OFFSET_MAP_MAJDEV 56
+ # define ADDR_WIDTH      16
+ #endif
+ 
+ /*
+  * Assign various fields of the first line in buf_ptr to *start, *end,
+  * *prot_buf and *maj_dev.  Only *prot_buf may be set for unwritable maps.
+  */
+ char *GC_parse_map_entry(char *buf_ptr, word *start, word *end,
+                                 char *prot_buf, unsigned int *maj_dev)
+ {
+     int i;
+     char *tok;
+ 
+     if (buf_ptr == NULL || *buf_ptr == '\0') {
+         return NULL;
+     }
+ 
+     memcpy(prot_buf, buf_ptr+OFFSET_MAP_PROT, 4);
+                               /* do the protections first. */
+     prot_buf[4] = '\0';
+ 
+     if (prot_buf[1] == 'w') {/* we can skip all of this if it's not writable. 
*/
+ 
+         tok = buf_ptr;
+         buf_ptr[OFFSET_MAP_START+ADDR_WIDTH] = '\0';
+         *start = strtoul(tok, NULL, 16);
+ 
+         tok = buf_ptr+OFFSET_MAP_END;
+         buf_ptr[OFFSET_MAP_END+ADDR_WIDTH] = '\0';
+         *end = strtoul(tok, NULL, 16);
+ 
+         buf_ptr += OFFSET_MAP_MAJDEV;
+         tok = buf_ptr;
+         while (*buf_ptr != ':') buf_ptr++;
+         *buf_ptr++ = '\0';
+         *maj_dev = strtoul(tok, NULL, 16);
+     }
+ 
+     while (*buf_ptr && *buf_ptr++ != '\n');
+ 
+     return buf_ptr;
+ }
+ 
+ #endif /* Need to parse /proc/self/maps. */   
+ 
  #if defined(SEARCH_FOR_DATA_START)
    /* The I386 case can be handled without a search.  The Alpha case   */
    /* used to be handled differently as well, but the rules changed    */
***************
*** 679,684 ****
--- 834,866 ----
    extern ptr_t __libc_stack_end;
  
  # ifdef IA64
+     /* Try to read the backing store base from /proc/self/maps.       */
+     /* We look for the writable mapping with a 0 major device,  */
+     /* which is       as close to our frame as possible, but below it.*/
+     static word backing_store_base_from_maps(char *maps)
+     {
+       char prot_buf[5];
+       char *buf_ptr = maps;
+       word start, end;
+       unsigned int maj_dev;
+       word current_best = 0;
+       word dummy;
+   
+       for (;;) {
+         buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, prot_buf, 
&maj_dev);
+       if (buf_ptr == NULL) return current_best;
+       if (prot_buf[1] == 'w' && maj_dev == 0) {
+           if (end < (word)(&dummy) && start > current_best) current_best = 
start;
+       }
+       }
+       return current_best;
+     }
+ 
+     static word backing_store_base_from_proc(void)
+     {
+         return GC_apply_to_maps(backing_store_base_from_maps);
+     }
+ 
  #   pragma weak __libc_ia64_register_backing_store_base
      extern ptr_t __libc_ia64_register_backing_store_base;
  
***************
*** 688,700 ****
          && 0 != __libc_ia64_register_backing_store_base) {
        /* Glibc 2.2.4 has a bug such that for dynamically linked       */
        /* executables __libc_ia64_register_backing_store_base is       */
!       /* defined but ininitialized during constructor calls.          */
        /* Hence we check for both nonzero address and value.           */
        return __libc_ia64_register_backing_store_base;
        } else {
!       word result = (word)GC_stackbottom - BACKING_STORE_DISPLACEMENT;
!       result += BACKING_STORE_ALIGNMENT - 1;
!       result &= ~(BACKING_STORE_ALIGNMENT - 1);
        return (ptr_t)result;
        }
      }
--- 870,888 ----
          && 0 != __libc_ia64_register_backing_store_base) {
        /* Glibc 2.2.4 has a bug such that for dynamically linked       */
        /* executables __libc_ia64_register_backing_store_base is       */
!       /* defined but uninitialized during constructor calls.          */
        /* Hence we check for both nonzero address and value.           */
        return __libc_ia64_register_backing_store_base;
        } else {
!       word result = backing_store_base_from_proc();
!       if (0 == result) {
!         /* Use dumb heuristics.  Works only for default configuration. */
!         result = (word)GC_stackbottom - BACKING_STORE_DISPLACEMENT;
!         result += BACKING_STORE_ALIGNMENT - 1;
!         result &= ~(BACKING_STORE_ALIGNMENT - 1);
!         /* Verify that it's at least readable.  If not, we goofed. */
!         GC_noop1(*(word *)result); 
!       }
        return (ptr_t)result;
        }
      }
***************
*** 706,716 ****
      /* using direct I/O system calls in order to avoid calling malloc   */
      /* in case REDIRECT_MALLOC is defined.                            */ 
  #   define STAT_BUF_SIZE 4096
! #   if defined(GC_USE_LD_WRAP)
! #     define STAT_READ __real_read
! #   else
! #     define STAT_READ read
! #   endif    
      char stat_buf[STAT_BUF_SIZE];
      int f;
      char c;
--- 894,901 ----
      /* using direct I/O system calls in order to avoid calling malloc   */
      /* in case REDIRECT_MALLOC is defined.                            */ 
  #   define STAT_BUF_SIZE 4096
! #   define STAT_READ read
!         /* Should probably call the real read, if read is wrapped.    */
      char stat_buf[STAT_BUF_SIZE];
      int f;
      char c;
***************
*** 782,789 ****
--- 967,977 ----
  
  ptr_t GC_get_stack_base()
  {
+ #   if defined(HEURISTIC1) || defined(HEURISTIC2) || \
+        defined(LINUX_STACKBOTTOM) || defined(FREEBSD_STACKBOTTOM)
      word dummy;
      ptr_t result;
+ #   endif
  
  #   define STACKBOTTOM_ALIGNMENT_M1 ((word)STACK_GRAN - 1)
  
***************
*** 945,956 ****
    /* all real work is done by GC_register_dynamic_libraries.  Under   */
    /* win32s, we cannot find the data segments associated with dll's.  */
    /* We register the main data segment here.                          */
- #  ifdef __GCC__
-   GC_bool GC_no_win32_dlls = TRUE;
-                        /* GCC can't do SEH, so we can't use VirtualQuery */
- #  else
    GC_bool GC_no_win32_dlls = FALSE;    
! #  endif
    
    void GC_init_win32()
    {
--- 1133,1142 ----
    /* all real work is done by GC_register_dynamic_libraries.  Under   */
    /* win32s, we cannot find the data segments associated with dll's.  */
    /* We register the main data segment here.                          */
    GC_bool GC_no_win32_dlls = FALSE;    
!       /* This used to be set for gcc, to avoid dealing with           */
!       /* the structured exception handling issues.  But we now have   */
!       /* assembly code to do that right.                              */
    
    void GC_init_win32()
    {
***************
*** 1830,1836 ****
   *            make sure that other system calls are similarly protected
   *            or write only to the stack.
   */
-  
  GC_bool GC_dirty_maintained = FALSE;
  
  # ifdef DEFAULT_VDB
--- 2016,2021 ----
***************
*** 1844,1849 ****
--- 2029,2037 ----
  /* Initialize virtual dirty bit implementation.                       */
  void GC_dirty_init()
  {
+ #   ifdef PRINTSTATS
+       GC_printf0("Initializing DEFAULT_VDB...\n");
+ #   endif
      GC_dirty_maintained = TRUE;
  }
  
***************
*** 1926,1932 ****
   * objects only if they are the same.
   */
  
! # if !defined(MSWIN32) && !defined(MSWINCE)
  
  #   include <sys/mman.h>
  #   include <signal.h>
--- 2114,2120 ----
   * objects only if they are the same.
   */
  
! # if !defined(MSWIN32) && !defined(MSWINCE) && !defined(DARWIN)
  
  #   include <sys/mman.h>
  #   include <signal.h>
***************
*** 1945,1950 ****
--- 2133,2155 ----
          
  # else
  
+ # ifdef DARWIN
+     /* Using vm_protect (mach syscall) over mprotect (BSD syscall) seems to
+        decrease the likelihood of some of the problems described below. */
+     #include <mach/vm_map.h>
+     extern mach_port_t GC_task_self;
+     #define PROTECT(addr,len) \
+         if(vm_protect(GC_task_self,(vm_address_t)(addr),(vm_size_t)(len), \
+                 FALSE,VM_PROT_READ) != KERN_SUCCESS) { \
+             ABORT("vm_portect failed"); \
+         }
+     #define UNPROTECT(addr,len) \
+         if(vm_protect(GC_task_self,(vm_address_t)(addr),(vm_size_t)(len), \
+                 FALSE,VM_PROT_READ|VM_PROT_WRITE) != KERN_SUCCESS) { \
+             ABORT("vm_portect failed"); \
+         }
+ # else
+     
  #   ifndef MSWINCE
  #     include <signal.h>
  #   endif
***************
*** 1962,1981 ****
                              &protect_junk)) { \
            ABORT("un-VirtualProtect failed"); \
          }
!         
! # endif
  
  #if defined(SUNOS4) || defined(FREEBSD)
      typedef void (* SIG_PF)();
! #endif
  #if defined(SUNOS5SIGS) || defined(OSF1) || defined(LINUX) \
!     || defined(MACOSX) || defined(HURD)
  # ifdef __STDC__
      typedef void (* SIG_PF)(int);
  # else
      typedef void (* SIG_PF)();
  # endif
! #endif
  #if defined(MSWIN32)
      typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_PF;
  #   undef SIG_DFL
--- 2167,2188 ----
                              &protect_junk)) { \
            ABORT("un-VirtualProtect failed"); \
          }
! # endif /* !DARWIN */
! # endif /* MSWIN32 || MSWINCE || DARWIN */
  
  #if defined(SUNOS4) || defined(FREEBSD)
      typedef void (* SIG_PF)();
! #endif /* SUNOS4 || FREEBSD */
! 
  #if defined(SUNOS5SIGS) || defined(OSF1) || defined(LINUX) \
!     || defined(HURD)
  # ifdef __STDC__
      typedef void (* SIG_PF)(int);
  # else
      typedef void (* SIG_PF)();
  # endif
! #endif /* SUNOS5SIGS || OSF1 || LINUX || HURD */
! 
  #if defined(MSWIN32)
      typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_PF;
  #   undef SIG_DFL
***************
*** 1989,1995 ****
  
  #if defined(IRIX5) || defined(OSF1) || defined(HURD)
      typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);
! #endif
  #if defined(SUNOS5SIGS)
  # ifdef HPUX
  #   define SIGINFO __siginfo
--- 2196,2203 ----
  
  #if defined(IRIX5) || defined(OSF1) || defined(HURD)
      typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);
! #endif /* IRIX5 || OSF1 || HURD */
! 
  #if defined(SUNOS5SIGS)
  # ifdef HPUX
  #   define SIGINFO __siginfo
***************
*** 2001,2007 ****
  # else
      typedef void (* REAL_SIG_PF)();
  # endif
! #endif
  #if defined(LINUX)
  #   if __GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 2
        typedef struct sigcontext s_c;
--- 2209,2216 ----
  # else
      typedef void (* REAL_SIG_PF)();
  # endif
! #endif /* SUNOS5SIGS */
! 
  #if defined(LINUX)
  #   if __GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 2
        typedef struct sigcontext s_c;
***************
*** 2035,2173 ****
        return (char *)faultaddr;
      }
  #   endif /* !ALPHA */
! # endif
! 
! # if defined(MACOSX) /* Should also test for PowerPC? */
!     typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);
! 
! /* Decodes the machine instruction which was responsible for the sending of 
the
!    SIGBUS signal. Sadly this is the only way to find the faulting address 
because
!    the signal handler doesn't get it directly from the kernel (although it is
!    available on the Mach level, but droppped by the BSD personality before it
!    calls our signal handler...)
!    This code should be able to deal correctly with all PPCs starting from the
!    601 up to and including the G4s (including Velocity Engine). */
! #define EXTRACT_OP1(iw)     (((iw) & 0xFC000000) >> 26)
! #define EXTRACT_OP2(iw)     (((iw) & 0x000007FE) >> 1)
! #define EXTRACT_REGA(iw)    (((iw) & 0x001F0000) >> 16)
! #define EXTRACT_REGB(iw)    (((iw) & 0x03E00000) >> 21)
! #define EXTRACT_REGC(iw)    (((iw) & 0x0000F800) >> 11)
! #define EXTRACT_DISP(iw)    ((short *) &(iw))[1]
! 
! static char *get_fault_addr(struct sigcontext *scp)
! {
!    unsigned int   instr = *((unsigned int *) scp->sc_ir);
!    unsigned int * regs = &((unsigned int *) scp->sc_regs)[2];
!    int            disp = 0, tmp;
!    unsigned int   baseA = 0, baseB = 0;
!    unsigned int   addr, alignmask = 0xFFFFFFFF;
! 
! #ifdef GC_DEBUG_DECODER
!    GC_err_printf1("Instruction: 0x%lx\n", instr);
!    GC_err_printf1("Opcode 1: d\n", (int)EXTRACT_OP1(instr));
! #endif
!    switch(EXTRACT_OP1(instr)) {
!       case 38:   /* stb */
!       case 39:   /* stbu */
!       case 54:   /* stfd */
!       case 55:   /* stfdu */
!       case 52:   /* stfs */
!       case 53:   /* stfsu */
!       case 44:   /* sth */
!       case 45:   /* sthu */
!       case 47:   /* stmw */
!       case 36:   /* stw */
!       case 37:   /* stwu */
!             tmp = EXTRACT_REGA(instr);
!             if(tmp > 0)
!                baseA = regs[tmp];
!             disp = EXTRACT_DISP(instr);
!             break;
!       case 31:
! #ifdef GC_DEBUG_DECODER
!             GC_err_printf1("Opcode 2: %d\n", (int)EXTRACT_OP2(instr));
! #endif
!             switch(EXTRACT_OP2(instr)) {
!                case 86:    /* dcbf */
!                case 54:    /* dcbst */
!                case 1014:  /* dcbz */
!                case 247:   /* stbux */
!                case 215:   /* stbx */
!                case 759:   /* stfdux */
!                case 727:   /* stfdx */
!                case 983:   /* stfiwx */
!                case 695:   /* stfsux */
!                case 663:   /* stfsx */
!                case 918:   /* sthbrx */
!                case 439:   /* sthux */
!                case 407:   /* sthx */
!                case 661:   /* stswx */
!                case 662:   /* stwbrx */
!                case 150:   /* stwcx. */
!                case 183:   /* stwux */
!                case 151:   /* stwx */
!                case 135:   /* stvebx */
!                case 167:   /* stvehx */
!                case 199:   /* stvewx */
!                case 231:   /* stvx */
!                case 487:   /* stvxl */
!                      tmp = EXTRACT_REGA(instr);
!                      if(tmp > 0)
!                         baseA = regs[tmp];
!                         baseB = regs[EXTRACT_REGC(instr)];
!                         /* determine Altivec alignment mask */
!                         switch(EXTRACT_OP2(instr)) {
!                            case 167:   /* stvehx */
!                                  alignmask = 0xFFFFFFFE;
!                                  break;
!                            case 199:   /* stvewx */
!                                  alignmask = 0xFFFFFFFC;
!                                  break;
!                            case 231:   /* stvx */
!                                  alignmask = 0xFFFFFFF0;
!                                  break;
!                            case 487:  /* stvxl */
!                                  alignmask = 0xFFFFFFF0;
!                                  break;
!                         }
!                         break;
!                case 725:   /* stswi */
!                      tmp = EXTRACT_REGA(instr);
!                      if(tmp > 0)
!                         baseA = regs[tmp];
!                         break;
!                default:   /* ignore instruction */
! #ifdef GC_DEBUG_DECODER
!                      GC_err_printf("Ignored by inner handler\n");
! #endif
!                      return NULL;
!                     break;
!             }
!             break;
!       default:   /* ignore instruction */
! #ifdef GC_DEBUG_DECODER
!             GC_err_printf("Ignored by main handler\n");
! #endif
!             return NULL;
!             break;
!    }
!       
!    addr = (baseA + baseB) + disp;
!   addr &= alignmask;
! #ifdef GC_DEBUG_DECODER
!    GC_err_printf1("BaseA: %d\n", baseA);
!    GC_err_printf1("BaseB: %d\n", baseB);
!    GC_err_printf1("Disp:  %d\n", disp);
!    GC_err_printf1("Address: %d\n", addr);
! #endif
!    return (char *)addr;
! }
! #endif /* MACOSX */
  
  SIG_PF GC_old_bus_handler;
  SIG_PF GC_old_segv_handler;   /* Also old MSWIN32 ACCESS_VIOLATION filter */
  
! #ifdef THREADS
  /* We need to lock around the bitmap update in the write fault handler        
*/
  /* in order to avoid the risk of losing a bit.  We do this with a     */
  /* test-and-set spin lock if we know how to do that.  Otherwise we    */
--- 2244,2257 ----
        return (char *)faultaddr;
      }
  #   endif /* !ALPHA */
! # endif /* LINUX */
  
+ #ifndef DARWIN
  SIG_PF GC_old_bus_handler;
  SIG_PF GC_old_segv_handler;   /* Also old MSWIN32 ACCESS_VIOLATION filter */
+ #endif /* !DARWIN */
  
! #if defined(THREADS)
  /* We need to lock around the bitmap update in the write fault handler        
*/
  /* in order to avoid the risk of losing a bit.  We do this with a     */
  /* test-and-set spin lock if we know how to do that.  Otherwise we    */
***************
*** 2216,2221 ****
--- 2300,2306 ----
  #endif /* !THREADS */
  
  /*ARGSUSED*/
+ #if !defined(DARWIN)
  # if defined (SUNOS4) || defined(FREEBSD)
      void GC_write_fault_handler(sig, code, scp, addr)
      int sig, code;
***************
*** 2231,2237 ****
  #     define SIG_OK (sig == SIGBUS)
  #     define CODE_OK (code == BUS_PAGE_FAULT)
  #   endif
! # endif
  # if defined(IRIX5) || defined(OSF1) || defined(HURD)
  #   include <errno.h>
      void GC_write_fault_handler(int sig, int code, struct sigcontext *scp)
--- 2316,2323 ----
  #     define SIG_OK (sig == SIGBUS)
  #     define CODE_OK (code == BUS_PAGE_FAULT)
  #   endif
! # endif /* SUNOS4 || FREEBSD */
! 
  # if defined(IRIX5) || defined(OSF1) || defined(HURD)
  #   include <errno.h>
      void GC_write_fault_handler(int sig, int code, struct sigcontext *scp)
***************
*** 2247,2253 ****
  #     define SIG_OK (sig == SIGBUS || sig == SIGSEGV)         
  #     define CODE_OK  TRUE
  #   endif
! # endif
  # if defined(LINUX)
  #   if defined(ALPHA) || defined(M68K)
        void GC_write_fault_handler(int sig, int code, s_c * sc)
--- 2333,2340 ----
  #     define SIG_OK (sig == SIGBUS || sig == SIGSEGV)         
  #     define CODE_OK  TRUE
  #   endif
! # endif /* IRIX5 || OSF1 || HURD */
! 
  # if defined(LINUX)
  #   if defined(ALPHA) || defined(M68K)
        void GC_write_fault_handler(int sig, int code, s_c * sc)
***************
*** 2267,2273 ****
        /* Empirically c.trapno == 14, on IA32, but is that useful?     */
        /* Should probably consider alignment issues on other           */
        /* architectures.                                               */
! # endif
  # if defined(SUNOS5SIGS)
  #  ifdef __STDC__
      void GC_write_fault_handler(int sig, struct SIGINFO *scp, void * context)
--- 2354,2361 ----
        /* Empirically c.trapno == 14, on IA32, but is that useful?     */
        /* Should probably consider alignment issues on other           */
        /* architectures.                                               */
! # endif /* LINUX */
! 
  # if defined(SUNOS5SIGS)
  #  ifdef __STDC__
      void GC_write_fault_handler(int sig, struct SIGINFO *scp, void * context)
***************
*** 2288,2300 ****
  #     define SIG_OK (sig == SIGSEGV)
  #     define CODE_OK (scp -> si_code == SEGV_ACCERR)
  #   endif
! # endif
! 
! # if defined(MACOSX)
!     void GC_write_fault_handler(int sig, int code, struct sigcontext *scp)
! #   define SIG_OK (sig == SIGBUS)
! #   define CODE_OK (code == 0 /* experimentally determined */)
! # endif
  
  # if defined(MSWIN32) || defined(MSWINCE)
      LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info)
--- 2376,2382 ----
  #     define SIG_OK (sig == SIGSEGV)
  #     define CODE_OK (scp -> si_code == SEGV_ACCERR)
  #   endif
! # endif /* SUNOS5SIGS */
  
  # if defined(MSWIN32) || defined(MSWINCE)
      LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info)
***************
*** 2302,2308 ****
                        STATUS_ACCESS_VIOLATION)
  #   define CODE_OK (exc_info -> ExceptionRecord -> ExceptionInformation[0] == 
1)
                        /* Write fault */
! # endif
  {
      register unsigned i;
  #   if defined(HURD) 
--- 2384,2390 ----
                        STATUS_ACCESS_VIOLATION)
  #   define CODE_OK (exc_info -> ExceptionRecord -> ExceptionInformation[0] == 
1)
                        /* Write fault */
! # endif /* MSWIN32 || MSWINCE */
  {
      register unsigned i;
  #   if defined(HURD) 
***************
*** 2373,2381 ****
  #     endif
  #     endif
  #   endif
- #   if defined(MACOSX)
-         char * addr = get_fault_addr(scp);
- #   endif
  #   if defined(MSWIN32) || defined(MSWINCE)
        char * addr = (char *) (exc_info -> ExceptionRecord
                                -> ExceptionInformation[1]);
--- 2455,2460 ----
***************
*** 2439,2447 ****
                    (*(REAL_SIG_PF)old_handler) (sig, code, scp);
                    return;
  #             endif
- #             ifdef MACOSX
-                   (*(REAL_SIG_PF)old_handler) (sig, code, scp);
- #             endif
  #             ifdef MSWIN32
                    return((*old_handler)(exc_info));
  #             endif
--- 2518,2523 ----
***************
*** 2483,2488 ****
--- 2559,2565 ----
      ABORT("Unexpected bus error or segmentation fault");
  #endif
  }
+ #endif /* !DARWIN */
  
  /*
   * We hold the allocation lock.  We expect block h to be written
***************
*** 2515,2520 ****
--- 2592,2598 ----
      UNPROTECT(h_trunc, (ptr_t)h_end - (ptr_t)h_trunc);
  }
  
+ #if !defined(DARWIN)
  void GC_dirty_init()
  {
  #   if defined(SUNOS5SIGS) || defined(IRIX5) || defined(LINUX) || \
***************
*** 2537,2549 ****
          (void)sigaddset(&act.sa_mask, SIG_SUSPEND);
  #     endif /* SIG_SUSPEND */
  #    endif
- #   if defined(MACOSX)
-       struct sigaction act, oldact;
- 
-       act.sa_flags = SA_RESTART;
-       act.sa_handler = GC_write_fault_handler;
-       sigemptyset(&act.sa_mask);
- #   endif
  #   ifdef PRINTSTATS
        GC_printf0("Inititalizing mprotect virtual dirty bit implementation\n");
  #   endif
--- 2615,2620 ----
***************
*** 2583,2589 ****
                sigaction(SIGSEGV, 0, &oldact);
                sigaction(SIGSEGV, &act, 0);
  #     else
!               sigaction(SIGSEGV, &act, &oldact);
  #     endif
  #     if defined(_sigargs) || defined(HURD) || !defined(SA_SIGINFO)
        /* This is Irix 5.x, not 6.x.  Irix 5.x does not have   */
--- 2654,2663 ----
                sigaction(SIGSEGV, 0, &oldact);
                sigaction(SIGSEGV, &act, 0);
  #     else
!       {
!         int res = sigaction(SIGSEGV, &act, &oldact);
!         if (res != 0) ABORT("Sigaction failed");
!       }
  #     endif
  #     if defined(_sigargs) || defined(HURD) || !defined(SA_SIGINFO)
        /* This is Irix 5.x, not 6.x.  Irix 5.x does not have   */
***************
*** 2606,2612 ****
  #       endif
        }
  #   endif
! #   if defined(MACOSX) || defined(HPUX) || defined(LINUX) || defined(HURD)
        sigaction(SIGBUS, &act, &oldact);
        GC_old_bus_handler = oldact.sa_handler;
        if (GC_old_bus_handler == SIG_IGN) {
--- 2680,2686 ----
  #       endif
        }
  #   endif
! #   if defined(HPUX) || defined(LINUX) || defined(HURD)
        sigaction(SIGBUS, &act, &oldact);
        GC_old_bus_handler = oldact.sa_handler;
        if (GC_old_bus_handler == SIG_IGN) {
***************
*** 2618,2624 ****
          GC_err_printf0("Replaced other SIGBUS handler\n");
  #       endif
        }
! #   endif /* MACOS || HPUX || LINUX */
  #   if defined(MSWIN32)
        GC_old_segv_handler = 
SetUnhandledExceptionFilter(GC_write_fault_handler);
        if (GC_old_segv_handler != NULL) {
--- 2692,2698 ----
          GC_err_printf0("Replaced other SIGBUS handler\n");
  #       endif
        }
! #   endif /* HPUX || LINUX || HURD */
  #   if defined(MSWIN32)
        GC_old_segv_handler = 
SetUnhandledExceptionFilter(GC_write_fault_handler);
        if (GC_old_segv_handler != NULL) {
***************
*** 2630,2635 ****
--- 2704,2710 ----
        }
  #   endif
  }
+ #endif /* !DARWIN */
  
  int GC_incremental_protection_needs()
  {
***************
*** 2879,2891 ****
  {
  }
  
- # else /* !MPROTECT_VDB */
- 
- #   ifdef GC_USE_LD_WRAP
-       ssize_t __wrap_read(int fd, void *buf, size_t nbyte)
-       { return __real_read(fd, buf, nbyte); }
- #   endif
- 
  # endif /* MPROTECT_VDB */
  
  # ifdef PROC_VDB
--- 2954,2959 ----
***************
*** 3204,3209 ****
--- 3272,3824 ----
  
  # endif /* PCR_VDB */
  
+ #if defined(MPROTECT_VDB) && defined(DARWIN)
+ /* The following sources were used as a *reference* for this exception 
handling
+    code:
+       1. Apple's mach/xnu documentation
+       2. Timothy J. Wood's "Mach Exception Handlers 101" post to the
+          omnigroup's macosx-dev list. 
+          www.omnigroup.com/mailman/archive/macosx-dev/2000-June/002030.html
+       3. macosx-nat.c from Apple's GDB source code.
+ */
+    
+ /* There seem to be numerous problems with darwin's mach exception handling.
+    I'm pretty sure they are not problems in my code. Search for 
+    BROKEN_EXCEPTION_HANDLING for more information. */
+ #define BROKEN_EXCEPTION_HANDLING
+    
+ #include <mach/mach.h>
+ #include <mach/mach_error.h>
+ #include <mach/thread_status.h>
+ #include <mach/exception.h>
+ #include <mach/task.h>
+ #include <pthread.h>
+ 
+ /* These are not defined in any header, although they are documented */
+ extern boolean_t exc_server(mach_msg_header_t *,mach_msg_header_t *);
+ extern kern_return_t exception_raise(
+     mach_port_t,mach_port_t,mach_port_t,
+     exception_type_t,exception_data_t,mach_msg_type_number_t);
+ extern kern_return_t exception_raise_state(
+     mach_port_t,mach_port_t,mach_port_t,
+     exception_type_t,exception_data_t,mach_msg_type_number_t,
+     thread_state_flavor_t*,thread_state_t,mach_msg_type_number_t,
+     thread_state_t,mach_msg_type_number_t*);
+ extern kern_return_t exception_raise_state_identity(
+     mach_port_t,mach_port_t,mach_port_t,
+     exception_type_t,exception_data_t,mach_msg_type_number_t,
+     thread_state_flavor_t*,thread_state_t,mach_msg_type_number_t,
+     thread_state_t,mach_msg_type_number_t*);
+ 
+ 
+ #define MAX_EXCEPTION_PORTS 16
+ 
+ static mach_port_t GC_task_self;
+ 
+ static struct {
+     mach_msg_type_number_t count;
+     exception_mask_t      masks[MAX_EXCEPTION_PORTS];
+     exception_handler_t   ports[MAX_EXCEPTION_PORTS];
+     exception_behavior_t  behaviors[MAX_EXCEPTION_PORTS];
+     thread_state_flavor_t flavors[MAX_EXCEPTION_PORTS];
+ } GC_old_exc_ports;
+ 
+ static struct {
+     mach_port_t exception;
+ #if defined(THREADS)
+     mach_port_t reply;
+ #endif
+ } GC_ports;
+ 
+ typedef struct {
+     mach_msg_header_t head;
+ } GC_msg_t;
+ 
+ typedef enum {
+     GC_MP_NORMAL, GC_MP_DISCARDING, GC_MP_STOPPED
+ } GC_mprotect_state_t;
+ 
+ /* FIXME: 1 and 2 seem to be safe to use in the msgh_id field,
+    but it isn't  documented. Use the source and see if they
+    should be ok. */
+ #define ID_STOP 1
+ #define ID_RESUME 2
+ 
+ /* These values are only used on the reply port */
+ #define ID_ACK 3
+ 
+ #if defined(THREADS)
+ 
+ GC_mprotect_state_t GC_mprotect_state;
+ 
+ /* The following should ONLY be called when the world is stopped  */
+ static void GC_mprotect_thread_notify(mach_msg_id_t id) {
+     struct {
+         GC_msg_t msg;
+         mach_msg_trailer_t trailer;
+     } buf;
+     mach_msg_return_t r;
+     /* remote, local */
+     buf.msg.head.msgh_bits = 
+         MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND,0);
+     buf.msg.head.msgh_size = sizeof(buf.msg);
+     buf.msg.head.msgh_remote_port = GC_ports.exception;
+     buf.msg.head.msgh_local_port = MACH_PORT_NULL;
+     buf.msg.head.msgh_id = id;
+             
+     r = mach_msg(
+         &buf.msg.head,
+         MACH_SEND_MSG|MACH_RCV_MSG|MACH_RCV_LARGE,
+         sizeof(buf.msg),
+         sizeof(buf),
+         GC_ports.reply,
+         MACH_MSG_TIMEOUT_NONE,
+         MACH_PORT_NULL);
+     if(r != MACH_MSG_SUCCESS)
+       ABORT("mach_msg failed in GC_mprotect_thread_notify");
+     if(buf.msg.head.msgh_id != ID_ACK)
+         ABORT("invalid ack in GC_mprotect_thread_notify");
+ }
+ 
+ /* Should only be called by the mprotect thread */
+ static void GC_mprotect_thread_reply() {
+     GC_msg_t msg;
+     mach_msg_return_t r;
+     /* remote, local */
+     msg.head.msgh_bits = 
+         MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND,0);
+     msg.head.msgh_size = sizeof(msg);
+     msg.head.msgh_remote_port = GC_ports.reply;
+     msg.head.msgh_local_port = MACH_PORT_NULL;
+     msg.head.msgh_id = ID_ACK;
+             
+     r = mach_msg(
+         &msg.head,
+         MACH_SEND_MSG,
+         sizeof(msg),
+         0,
+         MACH_PORT_NULL,
+         MACH_MSG_TIMEOUT_NONE,
+         MACH_PORT_NULL);
+     if(r != MACH_MSG_SUCCESS)
+       ABORT("mach_msg failed in GC_mprotect_thread_reply");
+ }
+ 
+ void GC_mprotect_stop() {
+     GC_mprotect_thread_notify(ID_STOP);
+ }
+ void GC_mprotect_resume() {
+     GC_mprotect_thread_notify(ID_RESUME);
+ }
+ 
+ #else /* !THREADS */
+ /* The compiler should optimize away any GC_mprotect_state computations */
+ #define GC_mprotect_state GC_MP_NORMAL
+ #endif
+ 
+ static void *GC_mprotect_thread(void *arg) {
+     mach_msg_return_t r;
+     /* These two structures contain some private kernel data. We don't need to
+        access any of it so we don't bother defining a proper struct. The
+        correct definitions are in the xnu source code. */
+     struct {
+         mach_msg_header_t head;
+         char data[256];
+     } reply;
+     struct {
+         mach_msg_header_t head;
+         mach_msg_body_t msgh_body;
+         char data[1024];
+     } msg;
+ 
+     mach_msg_id_t id;
+     
+     for(;;) {
+         r = mach_msg(
+             &msg.head,
+             MACH_RCV_MSG|MACH_RCV_LARGE|
+                 (GC_mprotect_state == GC_MP_DISCARDING ? MACH_RCV_TIMEOUT : 
0),
+             0,
+             sizeof(msg),
+             GC_ports.exception,
+             GC_mprotect_state == GC_MP_DISCARDING ? 0 : MACH_MSG_TIMEOUT_NONE,
+             MACH_PORT_NULL);
+         
+         id = r == MACH_MSG_SUCCESS ? msg.head.msgh_id : -1;
+         
+ #if defined(THREADS)
+         if(GC_mprotect_state == GC_MP_DISCARDING) {
+             if(r == MACH_RCV_TIMED_OUT) {
+                 GC_mprotect_state = GC_MP_STOPPED;
+                 GC_mprotect_thread_reply();
+                 continue;
+             }
+             if(r == MACH_MSG_SUCCESS && (id == ID_STOP || id == ID_RESUME))
+                 ABORT("out of order mprotect thread request");
+         }
+ #endif
+         
+         if(r != MACH_MSG_SUCCESS) {
+             GC_err_printf2("mach_msg failed with %d %s\n", 
+                 (int)r,mach_error_string(r));
+             ABORT("mach_msg failed");
+         }
+         
+         switch(id) {
+ #if defined(THREADS)
+             case ID_STOP:
+                 if(GC_mprotect_state != GC_MP_NORMAL)
+                     ABORT("Called mprotect_stop when state wasn't normal");
+                 GC_mprotect_state = GC_MP_DISCARDING;
+                 break;
+             case ID_RESUME:
+                 if(GC_mprotect_state != GC_MP_STOPPED)
+                     ABORT("Called mprotect_resume when state wasn't stopped");
+                 GC_mprotect_state = GC_MP_NORMAL;
+                 GC_mprotect_thread_reply();
+                 break;
+ #endif /* THREADS */
+             default:
+                   /* Handle the message (calls catch_exception_raise) */
+               if(!exc_server(&msg.head,&reply.head))
+                     ABORT("exc_server failed");
+                 /* Send the reply */
+                 r = mach_msg(
+                     &reply.head,
+                     MACH_SEND_MSG,
+                     reply.head.msgh_size,
+                     0,
+                     MACH_PORT_NULL,
+                     MACH_MSG_TIMEOUT_NONE,
+                     MACH_PORT_NULL);
+               if(r != MACH_MSG_SUCCESS) {
+                       /* This will fail if the thread dies, but the thread 
shouldn't
+                          die... */
+                       #ifdef BROKEN_EXCEPTION_HANDLING
+                       GC_err_printf2(
+                         "mach_msg failed with %d %s while sending exc 
reply\n",
+                         (int)r,mach_error_string(r));
+               #else
+                       ABORT("mach_msg failed while sending exception reply");
+               #endif
+               }
+         } /* switch */
+     } /* for(;;) */
+     /* NOT REACHED */
+     return NULL;
+ }
+ 
+ /* All this SIGBUS code shouldn't be necessary. All protection faults should
+    be going throught the mach exception handler. However, it seems a SIGBUS is
+    occasionally sent for some unknown reason. Even more odd, it seems to be
+    meaningless and safe to ignore. */
+ #ifdef BROKEN_EXCEPTION_HANDLING
+ 
+ typedef void (* SIG_PF)();
+ static SIG_PF GC_old_bus_handler;
+ 
+ /* Updates to this aren't atomic, but the SIGBUSs seem pretty rare.
+    Even if this doesn't get updated property, it isn't really a problem */
+ static int GC_sigbus_count;
+ 
+ static void GC_darwin_sigbus(int num,siginfo_t *sip,void *context) {
+     if(num != SIGBUS) ABORT("Got a non-sigbus signal in the sigbus handler");
+     
+     /* Ugh... some seem safe to ignore, but too many in a row probably means
+        trouble. GC_sigbus_count is reset for each mach exception that is
+        handled */
+     if(GC_sigbus_count >= 8) {
+         ABORT("Got more than 8 SIGBUSs in a row!");
+     } else {
+         GC_sigbus_count++;
+         GC_err_printf0("GC: WARNING: Ignoring SIGBUS.\n");
+     }
+ }
+ #endif /* BROKEN_EXCEPTION_HANDLING */
+ 
+ void GC_dirty_init() {
+     kern_return_t r;
+     mach_port_t me;
+     pthread_t thread;
+     pthread_attr_t attr;
+     exception_mask_t mask;
+     
+ #   ifdef PRINTSTATS
+         GC_printf0("Inititalizing mach/darwin mprotect virtual dirty bit "
+             "implementation\n");
+ #   endif  
+ #     ifdef BROKEN_EXCEPTION_HANDLING
+         GC_err_printf0("GC: WARNING: Enabling workarounds for various darwin "
+             "exception handling bugs.\n");
+ #     endif
+     GC_dirty_maintained = TRUE;
+     if (GC_page_size % HBLKSIZE != 0) {
+         GC_err_printf0("Page size not multiple of HBLKSIZE\n");
+         ABORT("Page size not multiple of HBLKSIZE");
+     }
+     
+     GC_task_self = me = mach_task_self();
+     
+     r = mach_port_allocate(me,MACH_PORT_RIGHT_RECEIVE,&GC_ports.exception);
+     if(r != KERN_SUCCESS) ABORT("mach_port_allocate failed (exception port)");
+     
+     r = mach_port_insert_right(me,GC_ports.exception,GC_ports.exception,
+       MACH_MSG_TYPE_MAKE_SEND);
+     if(r != KERN_SUCCESS)
+       ABORT("mach_port_insert_right failed (exception port)");
+ 
+     #if defined(THREADS)
+         r = mach_port_allocate(me,MACH_PORT_RIGHT_RECEIVE,&GC_ports.reply);
+         if(r != KERN_SUCCESS) ABORT("mach_port_allocate failed (reply port)");
+     #endif
+ 
+     /* The exceptions we want to catch */  
+     mask = EXC_MASK_BAD_ACCESS;
+ 
+     r = task_get_exception_ports(
+         me,
+         mask,
+         GC_old_exc_ports.masks,
+         &GC_old_exc_ports.count,
+         GC_old_exc_ports.ports,
+         GC_old_exc_ports.behaviors,
+         GC_old_exc_ports.flavors
+     );
+     if(r != KERN_SUCCESS) ABORT("task_get_exception_ports failed");
+         
+     r = task_set_exception_ports(
+         me,
+         mask,
+         GC_ports.exception,
+         EXCEPTION_DEFAULT,
+         MACHINE_THREAD_STATE
+     );
+     if(r != KERN_SUCCESS) ABORT("task_set_exception_ports failed");
+ 
+     if(pthread_attr_init(&attr) != 0) ABORT("pthread_attr_init failed");
+     if(pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED) != 0) 
+         ABORT("pthread_attr_setdetachedstate failed");
+ 
+ #     undef pthread_create
+     /* This will call the real pthread function, not our wrapper */
+     if(pthread_create(&thread,&attr,GC_mprotect_thread,NULL) != 0)
+         ABORT("pthread_create failed");
+     pthread_attr_destroy(&attr);
+     
+     /* Setup the sigbus handler for ignoring the meaningless SIGBUSs */
+     #ifdef BROKEN_EXCEPTION_HANDLING 
+     {
+         struct sigaction sa, oldsa;
+         sa.sa_handler = (SIG_PF)GC_darwin_sigbus;
+         sigemptyset(&sa.sa_mask);
+         sa.sa_flags = SA_RESTART|SA_SIGINFO;
+         if(sigaction(SIGBUS,&sa,&oldsa) < 0) ABORT("sigaction");
+         GC_old_bus_handler = (SIG_PF)oldsa.sa_handler;
+         if (GC_old_bus_handler != SIG_DFL) {
+ #             ifdef PRINTSTATS
+                 GC_err_printf0("Replaced other SIGBUS handler\n");
+ #             endif
+         }
+     }
+     #endif /* BROKEN_EXCEPTION_HANDLING  */
+ }
+  
+ /* The source code for Apple's GDB was used as a reference for the exception
+    forwarding code. This code is similar to be GDB code only because there is 
+    only one way to do it. */
+ static kern_return_t GC_forward_exception(
+         mach_port_t thread,
+         mach_port_t task,
+         exception_type_t exception,
+         exception_data_t data,
+         mach_msg_type_number_t data_count
+ ) {
+     int i;
+     kern_return_t r;
+     mach_port_t port;
+     exception_behavior_t behavior;
+     thread_state_flavor_t flavor;
+     
+     thread_state_data_t thread_state;
+     mach_msg_type_number_t thread_state_count = THREAD_STATE_MAX;
+         
+     for(i=0;i<GC_old_exc_ports.count;i++)
+         if(GC_old_exc_ports.masks[i] & (1 << exception))
+             break;
+     if(i==GC_old_exc_ports.count) ABORT("No handler for exception!");
+     
+     port = GC_old_exc_ports.ports[i];
+     behavior = GC_old_exc_ports.behaviors[i];
+     flavor = GC_old_exc_ports.flavors[i];
+ 
+     if(behavior != EXCEPTION_DEFAULT) {
+         r = thread_get_state(thread,flavor,thread_state,&thread_state_count);
+         if(r != KERN_SUCCESS)
+             ABORT("thread_get_state failed in forward_exception");
+     }
+     
+     switch(behavior) {
+         case EXCEPTION_DEFAULT:
+             r = exception_raise(port,thread,task,exception,data,data_count);
+             break;
+         case EXCEPTION_STATE:
+             r = exception_raise_state(port,thread,task,exception,data,
+                 data_count,&flavor,thread_state,thread_state_count,
+                 thread_state,&thread_state_count);
+             break;
+         case EXCEPTION_STATE_IDENTITY:
+             r = 
exception_raise_state_identity(port,thread,task,exception,data,
+                 data_count,&flavor,thread_state,thread_state_count,
+                 thread_state,&thread_state_count);
+             break;
+         default:
+             r = KERN_FAILURE; /* make gcc happy */
+             ABORT("forward_exception: unknown behavior");
+             break;
+     }
+     
+     if(behavior != EXCEPTION_DEFAULT) {
+         r = thread_set_state(thread,flavor,thread_state,thread_state_count);
+         if(r != KERN_SUCCESS)
+             ABORT("thread_set_state failed in forward_exception");
+     }
+     
+     return r;
+ }
+ 
+ #define FWD() GC_forward_exception(thread,task,exception,code,code_count)
+ 
+ /* This violates the namespace rules but there isn't anything that can be done
+    about it. The exception handling stuff is hard coded to call this */
+ kern_return_t
+ catch_exception_raise(
+    mach_port_t exception_port,mach_port_t thread,mach_port_t task,
+    exception_type_t exception,exception_data_t code,
+    mach_msg_type_number_t code_count
+ ) {
+     kern_return_t r;
+     char *addr;
+     struct hblk *h;
+     int i;
+ #ifdef POWERPC
+     thread_state_flavor_t flavor = PPC_EXCEPTION_STATE;
+     mach_msg_type_number_t exc_state_count = PPC_EXCEPTION_STATE_COUNT;
+     ppc_exception_state_t exc_state;
+ #else
+ #     error FIXME for non-ppc darwin
+ #endif
+ 
+     
+     if(exception != EXC_BAD_ACCESS || code[0] != KERN_PROTECTION_FAILURE) {
+         #ifdef DEBUG_EXCEPTION_HANDLING
+         /* We aren't interested, pass it on to the old handler */
+         GC_printf3("Exception: 0x%x Code: 0x%x 0x%x in catch....\n",
+             exception,
+             code_count > 0 ? code[0] : -1,
+             code_count > 1 ? code[1] : -1); 
+         #endif
+         return FWD();
+     }
+ 
+     r = thread_get_state(thread,flavor,
+         (natural_t*)&exc_state,&exc_state_count);
+     if(r != KERN_SUCCESS) {
+         /* The thread is supposed to be suspended while the exception handler
+            is called. This shouldn't fail. */
+         #ifdef BROKEN_EXCEPTION_HANDLING
+             GC_err_printf0("thread_get_state failed in "
+                 "catch_exception_raise\n");
+             return KERN_SUCCESS;
+         #else
+             ABORT("thread_get_state failed in catch_exception_raise");
+         #endif
+     }
+     
+     /* This is the address that caused the fault */
+     addr = (char*) exc_state.dar;
+         
+     if((HDR(addr)) == 0) {
+         /* Ugh... just like the SIGBUS problem above, it seems we get a bogus 
+            KERN_PROTECTION_FAILURE every once and a while. We wait till we get
+            a bunch in a row before doing anything about it. If a "real" fault 
+            ever occurres it'll just keep faulting over and over and we'll hit
+            the limit pretty quickly. */
+         #ifdef BROKEN_EXCEPTION_HANDLING
+             static char *last_fault;
+             static int last_fault_count;
+             
+             if(addr != last_fault) {
+                 last_fault = addr;
+                 last_fault_count = 0;
+             }
+             if(++last_fault_count < 32) {
+                 if(last_fault_count == 1)
+                     GC_err_printf1(
+                         "GC: WARNING: Ignoring KERN_PROTECTION_FAILURE at 
%p\n",
+                         addr);
+                 return KERN_SUCCESS;
+             }
+             
+             GC_err_printf1("Unexpected KERN_PROTECTION_FAILURE at %p\n",addr);
+             /* Can't pass it along to the signal handler because that is
+                ignoring SIGBUS signals. We also shouldn't call ABORT here as
+                signals don't always work too well from the exception handler. 
*/
+             GC_err_printf0("Aborting\n");
+             exit(EXIT_FAILURE);
+         #else /* BROKEN_EXCEPTION_HANDLING */
+             /* Pass it along to the next exception handler 
+                (which should call SIGBUS/SIGSEGV) */
+             return FWD();
+         #endif /* !BROKEN_EXCEPTION_HANDLING */
+     }
+ 
+     #ifdef BROKEN_EXCEPTION_HANDLING
+         /* Reset the number of consecutive SIGBUSs */
+         GC_sigbus_count = 0;
+     #endif
+     
+     if(GC_mprotect_state == GC_MP_NORMAL) { /* common case */
+         h = (struct hblk*)((word)addr & ~(GC_page_size-1));
+         UNPROTECT(h, GC_page_size);   
+         for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
+             register int index = PHT_HASH(h+i);
+             async_set_pht_entry_from_index(GC_dirty_pages, index);
+         }
+     } else if(GC_mprotect_state == GC_MP_DISCARDING) {
+         /* Lie to the thread for now. No sense UNPROTECT()ing the memory
+            when we're just going to PROTECT() it again later. The thread
+            will just fault again once it resumes */
+     } else {
+         /* Shouldn't happen, i don't think */
+         GC_printf0("KERN_PROTECTION_FAILURE while world is stopped\n");
+         return FWD();
+     }
+     return KERN_SUCCESS;
+ }
+ #undef FWD
+ 
+ /* These should never be called, but just in case...  */
+ kern_return_t catch_exception_raise_state(mach_port_name_t exception_port,
+     int exception, exception_data_t code, mach_msg_type_number_t codeCnt,
+     int flavor, thread_state_t old_state, int old_stateCnt,
+     thread_state_t new_state, int new_stateCnt)
+ {
+     ABORT("catch_exception_raise_state");
+     return(KERN_INVALID_ARGUMENT);
+ }
+ kern_return_t catch_exception_raise_state_identity(
+     mach_port_name_t exception_port, mach_port_t thread, mach_port_t task,
+     int exception, exception_data_t code, mach_msg_type_number_t codeCnt,
+     int flavor, thread_state_t old_state, int old_stateCnt, 
+     thread_state_t new_state, int new_stateCnt)
+ {
+     ABORT("catch_exception_raise_state_identity");
+     return(KERN_INVALID_ARGUMENT);
+ }
+ 
+ 
+ #endif /* DARWIN && MPROTECT_VDB */
+ 
  # ifndef HAVE_INCREMENTAL_PROTECTION_NEEDS
    int GC_incremental_protection_needs()
    {
***************
*** 3323,3330 ****
      asm("movl %%ebp,%0" : "=r"(frame));
      fp = frame;
  # else
-     word GC_save_regs_in_stack();
- 
      frame = (struct frame *) GC_save_regs_in_stack ();
      fp = (struct frame *)((long) frame -> FR_SAVFP + BIAS);
  #endif
--- 3938,3943 ----
***************
*** 3465,3471 ****
                }
                name = result_buf;
                pclose(pipe);
!               out:
            }
  #       endif /* LINUX */
          GC_err_printf1("\t\t%s\n", name);
--- 4078,4084 ----
                }
                name = result_buf;
                pclose(pipe);
!               out:;
            }
  #       endif /* LINUX */
          GC_err_printf1("\t\t%s\n", name);
***************
*** 3481,3511 ****
  
  #endif /* NEED_CALLINFO */
  
- #if defined(LINUX) && defined(__ELF__) && \
-     (!defined(SMALL_CONFIG) || defined(USE_PROC_FOR_LIBRARIES))
- #ifdef GC_USE_LD_WRAP
- #   define READ __real_read
- #else
- #   define READ read
- #endif
- 
- 
- /* Repeatedly perform a read call until the buffer is filled or       */
- /* we encounter EOF.                                          */
- ssize_t GC_repeat_read(int fd, char *buf, size_t count)
- {
-     ssize_t num_read = 0;
-     ssize_t result;
-     
-     while (num_read < count) {
-       result = READ(fd, buf + num_read, count - num_read);
-       if (result < 0) return result;
-       if (result == 0) break;
-       num_read += result;
-     }
-     return num_read;
- }
- #endif /* LINUX && ... */
  
  
  #if defined(LINUX) && defined(__ELF__) && !defined(SMALL_CONFIG)
--- 4094,4099 ----
***************
*** 3513,3532 ****
  /* Dump /proc/self/maps to GC_stderr, to enable looking up names for
     addresses in FIND_LEAK output. */
  
  void GC_print_address_map()
  {
-     int f;
-     int result;
-     char maps_temp[32768];
      GC_err_printf0("---------- Begin address map ----------\n");
!         f = open("/proc/self/maps", O_RDONLY);
!         if (-1 == f) ABORT("Couldn't open /proc/self/maps");
!       do {
!           result = GC_repeat_read(f, maps_temp, sizeof(maps_temp));
!           if (result <= 0) ABORT("Couldn't read /proc/self/maps");
!           GC_err_write(maps_temp, result);
!       } while (result == sizeof(maps_temp));
!       close(f);     
      GC_err_printf0("---------- End address map ----------\n");
  }
  
--- 4101,4116 ----
  /* Dump /proc/self/maps to GC_stderr, to enable looking up names for
     addresses in FIND_LEAK output. */
  
+ static word dump_maps(char *maps)
+ {
+     GC_err_write(maps, strlen(maps));
+     return 1;
+ }
+ 
  void GC_print_address_map()
  {
      GC_err_printf0("---------- Begin address map ----------\n");
!     GC_apply_to_maps(dump_maps);
      GC_err_printf0("---------- End address map ----------\n");
  }
  




reply via email to

[Prev in Thread] Current Thread [Next in Thread]