/[emacs]/emacs/gc/os_dep.c
ViewVC logotype

Diff of /emacs/gc/os_dep.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.2.2.1 by fx, Thu Jun 5 18:23:04 2003 UTC revision 1.2.2.1.2.1 by fx, Mon Jun 16 15:19:52 2003 UTC
# Line 132  Line 132 
132  # define jmp_buf sigjmp_buf  # define jmp_buf sigjmp_buf
133  #endif  #endif
134    
135    #ifdef DARWIN
136    /* for get_etext and friends */
137    #include <mach-o/getsect.h>
138    #endif
139    
140  #ifdef DJGPP  #ifdef DJGPP
141    /* Apparently necessary for djgpp 2.01.  May cause problems with      */    /* Apparently necessary for djgpp 2.01.  May cause problems with      */
142    /* other versions.                                                    */    /* other versions.                                                    */
# Line 150  Line 155 
155  # define OPT_PROT_EXEC 0  # define OPT_PROT_EXEC 0
156  #endif  #endif
157    
158    #if defined(LINUX) && \
159        (defined(USE_PROC_FOR_LIBRARIES) || defined(IA64) || !defined(SMALL_CONFIG))
160    
161    /* We need to parse /proc/self/maps, either to find dynamic libraries,  */
162    /* and/or to find the register backing store base (IA64).  Do it once   */
163    /* here.                                                                */
164    
165    #define READ read
166    
167    /* Repeatedly perform a read call until the buffer is filled or */
168    /* we encounter EOF.                                            */
169    ssize_t GC_repeat_read(int fd, char *buf, size_t count)
170    {
171        ssize_t num_read = 0;
172        ssize_t result;
173        
174        while (num_read < count) {
175            result = READ(fd, buf + num_read, count - num_read);
176            if (result < 0) return result;
177            if (result == 0) break;
178            num_read += result;
179        }
180        return num_read;
181    }
182    
183    /*
184     * Apply fn to a buffer containing the contents of /proc/self/maps.
185     * Return the result of fn or, if we failed, 0.
186     */
187    
188    word GC_apply_to_maps(word (*fn)(char *))
189    {
190        int f;
191        int result;
192        int maps_size;
193        char maps_temp[32768];
194        char *maps_buf;
195    
196        /* Read /proc/self/maps     */
197            /* Note that we may not allocate, and thus can't use stdio.     */
198            f = open("/proc/self/maps", O_RDONLY);
199            if (-1 == f) return 0;
200            /* stat() doesn't work for /proc/self/maps, so we have to
201               read it to find out how large it is... */
202            maps_size = 0;
203            do {
204                result = GC_repeat_read(f, maps_temp, sizeof(maps_temp));
205                if (result <= 0) return 0;
206                maps_size += result;
207            } while (result == sizeof(maps_temp));
208    
209            if (maps_size > sizeof(maps_temp)) {
210                /* If larger than our buffer, close and re-read it. */
211                close(f);
212                f = open("/proc/self/maps", O_RDONLY);
213                if (-1 == f) return 0;
214                maps_buf = alloca(maps_size);
215                if (NULL == maps_buf) return 0;
216                result = GC_repeat_read(f, maps_buf, maps_size);
217                if (result <= 0) return 0;
218            } else {
219                /* Otherwise use the fixed size buffer */
220                maps_buf = maps_temp;
221            }
222    
223            close(f);
224            maps_buf[result] = '\0';
225            
226        /* Apply fn to result. */
227            return fn(maps_buf);
228    }
229    
230    #endif /* Need GC_apply_to_maps */
231    
232    #if defined(LINUX) && (defined(USE_PROC_FOR_LIBRARIES) || defined(IA64))
233    //
234    //  GC_parse_map_entry parses an entry from /proc/self/maps so we can
235    //  locate all writable data segments that belong to shared libraries.
236    //  The format of one of these entries and the fields we care about
237    //  is as follows:
238    //  XXXXXXXX-XXXXXXXX r-xp 00000000 30:05 260537     name of mapping...\n
239    //  ^^^^^^^^ ^^^^^^^^ ^^^^          ^^
240    //  start    end      prot          maj_dev
241    //  0        9        18            32
242    //  
243    //  For 64 bit ABIs:
244    //  0        17       34            56
245    //
246    //  The parser is called with a pointer to the entry and the return value
247    //  is either NULL or is advanced to the next entry(the byte after the
248    //  trailing '\n'.)
249    //
250    #if CPP_WORDSZ == 32
251    # define OFFSET_MAP_START   0
252    # define OFFSET_MAP_END     9
253    # define OFFSET_MAP_PROT   18
254    # define OFFSET_MAP_MAJDEV 32
255    # define ADDR_WIDTH         8
256    #endif
257    
258    #if CPP_WORDSZ == 64
259    # define OFFSET_MAP_START   0
260    # define OFFSET_MAP_END    17
261    # define OFFSET_MAP_PROT   34
262    # define OFFSET_MAP_MAJDEV 56
263    # define ADDR_WIDTH        16
264    #endif
265    
266    /*
267     * Assign various fields of the first line in buf_ptr to *start, *end,
268     * *prot_buf and *maj_dev.  Only *prot_buf may be set for unwritable maps.
269     */
270    char *GC_parse_map_entry(char *buf_ptr, word *start, word *end,
271                                    char *prot_buf, unsigned int *maj_dev)
272    {
273        int i;
274        char *tok;
275    
276        if (buf_ptr == NULL || *buf_ptr == '\0') {
277            return NULL;
278        }
279    
280        memcpy(prot_buf, buf_ptr+OFFSET_MAP_PROT, 4);
281                                    /* do the protections first. */
282        prot_buf[4] = '\0';
283    
284        if (prot_buf[1] == 'w') {/* we can skip all of this if it's not writable. */
285    
286            tok = buf_ptr;
287            buf_ptr[OFFSET_MAP_START+ADDR_WIDTH] = '\0';
288            *start = strtoul(tok, NULL, 16);
289    
290            tok = buf_ptr+OFFSET_MAP_END;
291            buf_ptr[OFFSET_MAP_END+ADDR_WIDTH] = '\0';
292            *end = strtoul(tok, NULL, 16);
293    
294            buf_ptr += OFFSET_MAP_MAJDEV;
295            tok = buf_ptr;
296            while (*buf_ptr != ':') buf_ptr++;
297            *buf_ptr++ = '\0';
298            *maj_dev = strtoul(tok, NULL, 16);
299        }
300    
301        while (*buf_ptr && *buf_ptr++ != '\n');
302    
303        return buf_ptr;
304    }
305    
306    #endif /* Need to parse /proc/self/maps. */    
307    
308  #if defined(SEARCH_FOR_DATA_START)  #if defined(SEARCH_FOR_DATA_START)
309    /* The I386 case can be handled without a search.  The Alpha case     */    /* The I386 case can be handled without a search.  The Alpha case     */
310    /* used to be handled differently as well, but the rules changed      */    /* used to be handled differently as well, but the rules changed      */
# Line 679  ptr_t GC_get_stack_base() Line 834  ptr_t GC_get_stack_base()
834    extern ptr_t __libc_stack_end;    extern ptr_t __libc_stack_end;
835    
836  # ifdef IA64  # ifdef IA64
837        /* Try to read the backing store base from /proc/self/maps. */
838        /* We look for the writable mapping with a 0 major device,  */
839        /* which is as close to our frame as possible, but below it.*/
840        static word backing_store_base_from_maps(char *maps)
841        {
842          char prot_buf[5];
843          char *buf_ptr = maps;
844          word start, end;
845          unsigned int maj_dev;
846          word current_best = 0;
847          word dummy;
848      
849          for (;;) {
850            buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, prot_buf, &maj_dev);
851            if (buf_ptr == NULL) return current_best;
852            if (prot_buf[1] == 'w' && maj_dev == 0) {
853                if (end < (word)(&dummy) && start > current_best) current_best = start;
854            }
855          }
856          return current_best;
857        }
858    
859        static word backing_store_base_from_proc(void)
860        {
861            return GC_apply_to_maps(backing_store_base_from_maps);
862        }
863    
864  #   pragma weak __libc_ia64_register_backing_store_base  #   pragma weak __libc_ia64_register_backing_store_base
865      extern ptr_t __libc_ia64_register_backing_store_base;      extern ptr_t __libc_ia64_register_backing_store_base;
866    
# Line 688  ptr_t GC_get_stack_base() Line 870  ptr_t GC_get_stack_base()
870            && 0 != __libc_ia64_register_backing_store_base) {            && 0 != __libc_ia64_register_backing_store_base) {
871          /* Glibc 2.2.4 has a bug such that for dynamically linked       */          /* Glibc 2.2.4 has a bug such that for dynamically linked       */
872          /* executables __libc_ia64_register_backing_store_base is       */          /* executables __libc_ia64_register_backing_store_base is       */
873          /* defined but ininitialized during constructor calls.          */          /* defined but uninitialized during constructor calls.          */
874          /* Hence we check for both nonzero address and value.           */          /* Hence we check for both nonzero address and value.           */
875          return __libc_ia64_register_backing_store_base;          return __libc_ia64_register_backing_store_base;
876        } else {        } else {
877          word result = (word)GC_stackbottom - BACKING_STORE_DISPLACEMENT;          word result = backing_store_base_from_proc();
878          result += BACKING_STORE_ALIGNMENT - 1;          if (0 == result) {
879          result &= ~(BACKING_STORE_ALIGNMENT - 1);            /* Use dumb heuristics.  Works only for default configuration. */
880              result = (word)GC_stackbottom - BACKING_STORE_DISPLACEMENT;
881              result += BACKING_STORE_ALIGNMENT - 1;
882              result &= ~(BACKING_STORE_ALIGNMENT - 1);
883              /* Verify that it's at least readable.  If not, we goofed. */
884              GC_noop1(*(word *)result);
885            }
886          return (ptr_t)result;          return (ptr_t)result;
887        }        }
888      }      }
# Line 706  ptr_t GC_get_stack_base() Line 894  ptr_t GC_get_stack_base()
894      /* using direct I/O system calls in order to avoid calling malloc   */      /* using direct I/O system calls in order to avoid calling malloc   */
895      /* in case REDIRECT_MALLOC is defined.                              */      /* in case REDIRECT_MALLOC is defined.                              */
896  #   define STAT_BUF_SIZE 4096  #   define STAT_BUF_SIZE 4096
897  #   if defined(GC_USE_LD_WRAP)  #   define STAT_READ read
898  #       define STAT_READ __real_read            /* Should probably call the real read, if read is wrapped.    */
 #   else  
 #       define STAT_READ read  
 #   endif      
899      char stat_buf[STAT_BUF_SIZE];      char stat_buf[STAT_BUF_SIZE];
900      int f;      int f;
901      char c;      char c;
# Line 782  ptr_t GC_get_stack_base() Line 967  ptr_t GC_get_stack_base()
967    
968  ptr_t GC_get_stack_base()  ptr_t GC_get_stack_base()
969  {  {
970    #   if defined(HEURISTIC1) || defined(HEURISTIC2) || \
971           defined(LINUX_STACKBOTTOM) || defined(FREEBSD_STACKBOTTOM)
972      word dummy;      word dummy;
973      ptr_t result;      ptr_t result;
974    #   endif
975    
976  #   define STACKBOTTOM_ALIGNMENT_M1 ((word)STACK_GRAN - 1)  #   define STACKBOTTOM_ALIGNMENT_M1 ((word)STACK_GRAN - 1)
977    
# Line 945  void GC_register_data_segments() Line 1133  void GC_register_data_segments()
1133    /* all real work is done by GC_register_dynamic_libraries.  Under     */    /* all real work is done by GC_register_dynamic_libraries.  Under     */
1134    /* win32s, we cannot find the data segments associated with dll's.    */    /* win32s, we cannot find the data segments associated with dll's.    */
1135    /* We register the main data segment here.                            */    /* 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  
1136    GC_bool GC_no_win32_dlls = FALSE;          GC_bool GC_no_win32_dlls = FALSE;      
1137  #  endif          /* This used to be set for gcc, to avoid dealing with           */
1138            /* the structured exception handling issues.  But we now have   */
1139            /* assembly code to do that right.                              */
1140        
1141    void GC_init_win32()    void GC_init_win32()
1142    {    {
# Line 1830  void (*GC_push_other_roots) GC_PROTO((vo Line 2016  void (*GC_push_other_roots) GC_PROTO((vo
2016   *              make sure that other system calls are similarly protected   *              make sure that other system calls are similarly protected
2017   *              or write only to the stack.   *              or write only to the stack.
2018   */   */
   
2019  GC_bool GC_dirty_maintained = FALSE;  GC_bool GC_dirty_maintained = FALSE;
2020    
2021  # ifdef DEFAULT_VDB  # ifdef DEFAULT_VDB
# Line 1844  GC_bool GC_dirty_maintained = FALSE; Line 2029  GC_bool GC_dirty_maintained = FALSE;
2029  /* Initialize virtual dirty bit implementation.                 */  /* Initialize virtual dirty bit implementation.                 */
2030  void GC_dirty_init()  void GC_dirty_init()
2031  {  {
2032    #   ifdef PRINTSTATS
2033          GC_printf0("Initializing DEFAULT_VDB...\n");
2034    #   endif
2035      GC_dirty_maintained = TRUE;      GC_dirty_maintained = TRUE;
2036  }  }
2037    
# Line 1926  GC_bool is_ptrfree; Line 2114  GC_bool is_ptrfree;
2114   * objects only if they are the same.   * objects only if they are the same.
2115   */   */
2116    
2117  # if !defined(MSWIN32) && !defined(MSWINCE)  # if !defined(MSWIN32) && !defined(MSWINCE) && !defined(DARWIN)
2118    
2119  #   include <sys/mman.h>  #   include <sys/mman.h>
2120  #   include <signal.h>  #   include <signal.h>
# Line 1945  GC_bool is_ptrfree; Line 2133  GC_bool is_ptrfree;
2133                        
2134  # else  # else
2135    
2136    # ifdef DARWIN
2137        /* Using vm_protect (mach syscall) over mprotect (BSD syscall) seems to
2138           decrease the likelihood of some of the problems described below. */
2139        #include <mach/vm_map.h>
2140        extern mach_port_t GC_task_self;
2141        #define PROTECT(addr,len) \
2142            if(vm_protect(GC_task_self,(vm_address_t)(addr),(vm_size_t)(len), \
2143                    FALSE,VM_PROT_READ) != KERN_SUCCESS) { \
2144                ABORT("vm_portect failed"); \
2145            }
2146        #define UNPROTECT(addr,len) \
2147            if(vm_protect(GC_task_self,(vm_address_t)(addr),(vm_size_t)(len), \
2148                    FALSE,VM_PROT_READ|VM_PROT_WRITE) != KERN_SUCCESS) { \
2149                ABORT("vm_portect failed"); \
2150            }
2151    # else
2152        
2153  #   ifndef MSWINCE  #   ifndef MSWINCE
2154  #     include <signal.h>  #     include <signal.h>
2155  #   endif  #   endif
# Line 1962  GC_bool is_ptrfree; Line 2167  GC_bool is_ptrfree;
2167                                &protect_junk)) { \                                &protect_junk)) { \
2168              ABORT("un-VirtualProtect failed"); \              ABORT("un-VirtualProtect failed"); \
2169            }            }
2170              # endif /* !DARWIN */
2171  # endif  # endif /* MSWIN32 || MSWINCE || DARWIN */
2172    
2173  #if defined(SUNOS4) || defined(FREEBSD)  #if defined(SUNOS4) || defined(FREEBSD)
2174      typedef void (* SIG_PF)();      typedef void (* SIG_PF)();
2175  #endif  #endif /* SUNOS4 || FREEBSD */
2176    
2177  #if defined(SUNOS5SIGS) || defined(OSF1) || defined(LINUX) \  #if defined(SUNOS5SIGS) || defined(OSF1) || defined(LINUX) \
2178      || defined(MACOSX) || defined(HURD)      || defined(HURD)
2179  # ifdef __STDC__  # ifdef __STDC__
2180      typedef void (* SIG_PF)(int);      typedef void (* SIG_PF)(int);
2181  # else  # else
2182      typedef void (* SIG_PF)();      typedef void (* SIG_PF)();
2183  # endif  # endif
2184  #endif  #endif /* SUNOS5SIGS || OSF1 || LINUX || HURD */
2185    
2186  #if defined(MSWIN32)  #if defined(MSWIN32)
2187      typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_PF;      typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_PF;
2188  #   undef SIG_DFL  #   undef SIG_DFL
# Line 1989  GC_bool is_ptrfree; Line 2196  GC_bool is_ptrfree;
2196    
2197  #if defined(IRIX5) || defined(OSF1) || defined(HURD)  #if defined(IRIX5) || defined(OSF1) || defined(HURD)
2198      typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);      typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);
2199  #endif  #endif /* IRIX5 || OSF1 || HURD */
2200    
2201  #if defined(SUNOS5SIGS)  #if defined(SUNOS5SIGS)
2202  # ifdef HPUX  # ifdef HPUX
2203  #   define SIGINFO __siginfo  #   define SIGINFO __siginfo
# Line 2001  GC_bool is_ptrfree; Line 2209  GC_bool is_ptrfree;
2209  # else  # else
2210      typedef void (* REAL_SIG_PF)();      typedef void (* REAL_SIG_PF)();
2211  # endif  # endif
2212  #endif  #endif /* SUNOS5SIGS */
2213    
2214  #if defined(LINUX)  #if defined(LINUX)
2215  #   if __GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 2  #   if __GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 2
2216        typedef struct sigcontext s_c;        typedef struct sigcontext s_c;
# Line 2035  GC_bool is_ptrfree; Line 2244  GC_bool is_ptrfree;
2244          return (char *)faultaddr;          return (char *)faultaddr;
2245      }      }
2246  #   endif /* !ALPHA */  #   endif /* !ALPHA */
2247  # endif  # endif /* LINUX */
   
 # 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 */  
2248    
2249    #ifndef DARWIN
2250  SIG_PF GC_old_bus_handler;  SIG_PF GC_old_bus_handler;
2251  SIG_PF GC_old_segv_handler;     /* Also old MSWIN32 ACCESS_VIOLATION filter */  SIG_PF GC_old_segv_handler;     /* Also old MSWIN32 ACCESS_VIOLATION filter */
2252    #endif /* !DARWIN */
2253    
2254  #ifdef THREADS  #if defined(THREADS)
2255  /* We need to lock around the bitmap update in the write fault handler  */  /* We need to lock around the bitmap update in the write fault handler  */
2256  /* in order to avoid the risk of losing a bit.  We do this with a       */  /* in order to avoid the risk of losing a bit.  We do this with a       */
2257  /* test-and-set spin lock if we know how to do that.  Otherwise we      */  /* test-and-set spin lock if we know how to do that.  Otherwise we      */
# Line 2216  SIG_PF GC_old_segv_handler;    /* Also old Line 2300  SIG_PF GC_old_segv_handler;    /* Also old
2300  #endif /* !THREADS */  #endif /* !THREADS */
2301    
2302  /*ARGSUSED*/  /*ARGSUSED*/
2303    #if !defined(DARWIN)
2304  # if defined (SUNOS4) || defined(FREEBSD)  # if defined (SUNOS4) || defined(FREEBSD)
2305      void GC_write_fault_handler(sig, code, scp, addr)      void GC_write_fault_handler(sig, code, scp, addr)
2306      int sig, code;      int sig, code;
# Line 2231  SIG_PF GC_old_segv_handler;    /* Also old Line 2316  SIG_PF GC_old_segv_handler;    /* Also old
2316  #     define SIG_OK (sig == SIGBUS)  #     define SIG_OK (sig == SIGBUS)
2317  #     define CODE_OK (code == BUS_PAGE_FAULT)  #     define CODE_OK (code == BUS_PAGE_FAULT)
2318  #   endif  #   endif
2319  # endif  # endif /* SUNOS4 || FREEBSD */
2320    
2321  # if defined(IRIX5) || defined(OSF1) || defined(HURD)  # if defined(IRIX5) || defined(OSF1) || defined(HURD)
2322  #   include <errno.h>  #   include <errno.h>
2323      void GC_write_fault_handler(int sig, int code, struct sigcontext *scp)      void GC_write_fault_handler(int sig, int code, struct sigcontext *scp)
# Line 2247  SIG_PF GC_old_segv_handler;    /* Also old Line 2333  SIG_PF GC_old_segv_handler;    /* Also old
2333  #     define SIG_OK (sig == SIGBUS || sig == SIGSEGV)    #     define SIG_OK (sig == SIGBUS || sig == SIGSEGV)  
2334  #     define CODE_OK  TRUE  #     define CODE_OK  TRUE
2335  #   endif  #   endif
2336  # endif  # endif /* IRIX5 || OSF1 || HURD */
2337    
2338  # if defined(LINUX)  # if defined(LINUX)
2339  #   if defined(ALPHA) || defined(M68K)  #   if defined(ALPHA) || defined(M68K)
2340        void GC_write_fault_handler(int sig, int code, s_c * sc)        void GC_write_fault_handler(int sig, int code, s_c * sc)
# Line 2267  SIG_PF GC_old_segv_handler;    /* Also old Line 2354  SIG_PF GC_old_segv_handler;    /* Also old
2354          /* Empirically c.trapno == 14, on IA32, but is that useful?     */          /* Empirically c.trapno == 14, on IA32, but is that useful?     */
2355          /* Should probably consider alignment issues on other           */          /* Should probably consider alignment issues on other           */
2356          /* architectures.                                               */          /* architectures.                                               */
2357  # endif  # endif /* LINUX */
2358    
2359  # if defined(SUNOS5SIGS)  # if defined(SUNOS5SIGS)
2360  #  ifdef __STDC__  #  ifdef __STDC__
2361      void GC_write_fault_handler(int sig, struct SIGINFO *scp, void * context)      void GC_write_fault_handler(int sig, struct SIGINFO *scp, void * context)
# Line 2288  SIG_PF GC_old_segv_handler;    /* Also old Line 2376  SIG_PF GC_old_segv_handler;    /* Also old
2376  #     define SIG_OK (sig == SIGSEGV)  #     define SIG_OK (sig == SIGSEGV)
2377  #     define CODE_OK (scp -> si_code == SEGV_ACCERR)  #     define CODE_OK (scp -> si_code == SEGV_ACCERR)
2378  #   endif  #   endif
2379  # endif  # endif /* SUNOS5SIGS */
   
 # 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  
2380    
2381  # if defined(MSWIN32) || defined(MSWINCE)  # if defined(MSWIN32) || defined(MSWINCE)
2382      LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info)      LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info)
# Line 2302  SIG_PF GC_old_segv_handler;    /* Also old Line 2384  SIG_PF GC_old_segv_handler;    /* Also old
2384                          STATUS_ACCESS_VIOLATION)                          STATUS_ACCESS_VIOLATION)
2385  #   define CODE_OK (exc_info -> ExceptionRecord -> ExceptionInformation[0] == 1)  #   define CODE_OK (exc_info -> ExceptionRecord -> ExceptionInformation[0] == 1)
2386                          /* Write fault */                          /* Write fault */
2387  # endif  # endif /* MSWIN32 || MSWINCE */
2388  {  {
2389      register unsigned i;      register unsigned i;
2390  #   if defined(HURD)  #   if defined(HURD)
# Line 2373  SIG_PF GC_old_segv_handler;    /* Also old Line 2455  SIG_PF GC_old_segv_handler;    /* Also old
2455  #       endif  #       endif
2456  #     endif  #     endif
2457  #   endif  #   endif
 #   if defined(MACOSX)  
         char * addr = get_fault_addr(scp);  
 #   endif  
2458  #   if defined(MSWIN32) || defined(MSWINCE)  #   if defined(MSWIN32) || defined(MSWINCE)
2459          char * addr = (char *) (exc_info -> ExceptionRecord          char * addr = (char *) (exc_info -> ExceptionRecord
2460                                  -> ExceptionInformation[1]);                                  -> ExceptionInformation[1]);
# Line 2439  SIG_PF GC_old_segv_handler;    /* Also old Line 2518  SIG_PF GC_old_segv_handler;    /* Also old
2518                      (*(REAL_SIG_PF)old_handler) (sig, code, scp);                      (*(REAL_SIG_PF)old_handler) (sig, code, scp);
2519                      return;                      return;
2520  #               endif  #               endif
 #               ifdef MACOSX  
                     (*(REAL_SIG_PF)old_handler) (sig, code, scp);  
 #               endif  
2521  #               ifdef MSWIN32  #               ifdef MSWIN32
2522                      return((*old_handler)(exc_info));                      return((*old_handler)(exc_info));
2523  #               endif  #               endif
# Line 2483  SIG_PF GC_old_segv_handler;    /* Also old Line 2559  SIG_PF GC_old_segv_handler;    /* Also old
2559      ABORT("Unexpected bus error or segmentation fault");      ABORT("Unexpected bus error or segmentation fault");
2560  #endif  #endif
2561  }  }
2562    #endif /* !DARWIN */
2563    
2564  /*  /*
2565   * We hold the allocation lock.  We expect block h to be written   * We hold the allocation lock.  We expect block h to be written
# Line 2515  GC_bool is_ptrfree; Line 2592  GC_bool is_ptrfree;
2592      UNPROTECT(h_trunc, (ptr_t)h_end - (ptr_t)h_trunc);      UNPROTECT(h_trunc, (ptr_t)h_end - (ptr_t)h_trunc);
2593  }  }
2594    
2595    #if !defined(DARWIN)
2596  void GC_dirty_init()  void GC_dirty_init()
2597  {  {
2598  #   if defined(SUNOS5SIGS) || defined(IRIX5) || defined(LINUX) || \  #   if defined(SUNOS5SIGS) || defined(IRIX5) || defined(LINUX) || \
# Line 2537  void GC_dirty_init() Line 2615  void GC_dirty_init()
2615          (void)sigaddset(&act.sa_mask, SIG_SUSPEND);          (void)sigaddset(&act.sa_mask, SIG_SUSPEND);
2616  #     endif /* SIG_SUSPEND */  #     endif /* SIG_SUSPEND */
2617  #    endif  #    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  
2618  #   ifdef PRINTSTATS  #   ifdef PRINTSTATS
2619          GC_printf0("Inititalizing mprotect virtual dirty bit implementation\n");          GC_printf0("Inititalizing mprotect virtual dirty bit implementation\n");
2620  #   endif  #   endif
# Line 2583  void GC_dirty_init() Line 2654  void GC_dirty_init()
2654          sigaction(SIGSEGV, 0, &oldact);          sigaction(SIGSEGV, 0, &oldact);
2655          sigaction(SIGSEGV, &act, 0);          sigaction(SIGSEGV, &act, 0);
2656  #     else  #     else
2657          sigaction(SIGSEGV, &act, &oldact);          {
2658              int res = sigaction(SIGSEGV, &act, &oldact);
2659              if (res != 0) ABORT("Sigaction failed");
2660            }
2661  #     endif  #     endif
2662  #     if defined(_sigargs) || defined(HURD) || !defined(SA_SIGINFO)  #     if defined(_sigargs) || defined(HURD) || !defined(SA_SIGINFO)
2663          /* This is Irix 5.x, not 6.x.  Irix 5.x does not have   */          /* This is Irix 5.x, not 6.x.  Irix 5.x does not have   */
# Line 2606  void GC_dirty_init() Line 2680  void GC_dirty_init()
2680  #       endif  #       endif
2681        }        }
2682  #   endif  #   endif
2683  #   if defined(MACOSX) || defined(HPUX) || defined(LINUX) || defined(HURD)  #   if defined(HPUX) || defined(LINUX) || defined(HURD)
2684        sigaction(SIGBUS, &act, &oldact);        sigaction(SIGBUS, &act, &oldact);
2685        GC_old_bus_handler = oldact.sa_handler;        GC_old_bus_handler = oldact.sa_handler;
2686        if (GC_old_bus_handler == SIG_IGN) {        if (GC_old_bus_handler == SIG_IGN) {
# Line 2618  void GC_dirty_init() Line 2692  void GC_dirty_init()
2692            GC_err_printf0("Replaced other SIGBUS handler\n");            GC_err_printf0("Replaced other SIGBUS handler\n");
2693  #       endif  #       endif
2694        }        }
2695  #   endif /* MACOS || HPUX || LINUX */  #   endif /* HPUX || LINUX || HURD */
2696  #   if defined(MSWIN32)  #   if defined(MSWIN32)
2697        GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler);        GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler);
2698        if (GC_old_segv_handler != NULL) {        if (GC_old_segv_handler != NULL) {
# Line 2630  void GC_dirty_init() Line 2704  void GC_dirty_init()
2704        }        }
2705  #   endif  #   endif
2706  }  }
2707    #endif /* !DARWIN */
2708    
2709  int GC_incremental_protection_needs()  int GC_incremental_protection_needs()
2710  {  {
# Line 2879  word n; Line 2954  word n;
2954  {  {
2955  }  }
2956    
 # 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  
   
2957  # endif /* MPROTECT_VDB */  # endif /* MPROTECT_VDB */
2958    
2959  # ifdef PROC_VDB  # ifdef PROC_VDB
# Line 3204  GC_bool is_ptrfree; Line 3272  GC_bool is_ptrfree;
3272    
3273  # endif /* PCR_VDB */  # endif /* PCR_VDB */
3274    
3275    #if defined(MPROTECT_VDB) && defined(DARWIN)
3276    /* The following sources were used as a *reference* for this exception handling
3277       code:
3278          1. Apple's mach/xnu documentation
3279          2. Timothy J. Wood's "Mach Exception Handlers 101" post to the
3280             omnigroup's macosx-dev list.
3281             www.omnigroup.com/mailman/archive/macosx-dev/2000-June/002030.html
3282          3. macosx-nat.c from Apple's GDB source code.
3283    */
3284      
3285    /* There seem to be numerous problems with darwin's mach exception handling.
3286       I'm pretty sure they are not problems in my code. Search for
3287       BROKEN_EXCEPTION_HANDLING for more information. */
3288    #define BROKEN_EXCEPTION_HANDLING
3289      
3290    #include <mach/mach.h>
3291    #include <mach/mach_error.h>
3292    #include <mach/thread_status.h>
3293    #include <mach/exception.h>
3294    #include <mach/task.h>
3295    #include <pthread.h>
3296    
3297    /* These are not defined in any header, although they are documented */
3298    extern boolean_t exc_server(mach_msg_header_t *,mach_msg_header_t *);
3299    extern kern_return_t exception_raise(
3300        mach_port_t,mach_port_t,mach_port_t,
3301        exception_type_t,exception_data_t,mach_msg_type_number_t);
3302    extern kern_return_t exception_raise_state(
3303        mach_port_t,mach_port_t,mach_port_t,
3304        exception_type_t,exception_data_t,mach_msg_type_number_t,
3305        thread_state_flavor_t*,thread_state_t,mach_msg_type_number_t,
3306        thread_state_t,mach_msg_type_number_t*);
3307    extern kern_return_t exception_raise_state_identity(
3308        mach_port_t,mach_port_t,mach_port_t,
3309        exception_type_t,exception_data_t,mach_msg_type_number_t,
3310        thread_state_flavor_t*,thread_state_t,mach_msg_type_number_t,
3311        thread_state_t,mach_msg_type_number_t*);
3312    
3313    
3314    #define MAX_EXCEPTION_PORTS 16
3315    
3316    static mach_port_t GC_task_self;
3317    
3318    static struct {
3319        mach_msg_type_number_t count;
3320        exception_mask_t      masks[MAX_EXCEPTION_PORTS];
3321        exception_handler_t   ports[MAX_EXCEPTION_PORTS];
3322        exception_behavior_t  behaviors[MAX_EXCEPTION_PORTS];
3323        thread_state_flavor_t flavors[MAX_EXCEPTION_PORTS];
3324    } GC_old_exc_ports;
3325    
3326    static struct {
3327        mach_port_t exception;
3328    #if defined(THREADS)
3329        mach_port_t reply;
3330    #endif
3331    } GC_ports;
3332    
3333    typedef struct {
3334        mach_msg_header_t head;
3335    } GC_msg_t;
3336    
3337    typedef enum {
3338        GC_MP_NORMAL, GC_MP_DISCARDING, GC_MP_STOPPED
3339    } GC_mprotect_state_t;
3340    
3341    /* FIXME: 1 and 2 seem to be safe to use in the msgh_id field,
3342       but it isn't  documented. Use the source and see if they
3343       should be ok. */
3344    #define ID_STOP 1
3345    #define ID_RESUME 2
3346    
3347    /* These values are only used on the reply port */
3348    #define ID_ACK 3
3349    
3350    #if defined(THREADS)
3351    
3352    GC_mprotect_state_t GC_mprotect_state;
3353    
3354    /* The following should ONLY be called when the world is stopped  */
3355    static void GC_mprotect_thread_notify(mach_msg_id_t id) {
3356        struct {
3357            GC_msg_t msg;
3358            mach_msg_trailer_t trailer;
3359        } buf;
3360        mach_msg_return_t r;
3361        /* remote, local */
3362        buf.msg.head.msgh_bits =
3363            MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND,0);
3364        buf.msg.head.msgh_size = sizeof(buf.msg);
3365        buf.msg.head.msgh_remote_port = GC_ports.exception;
3366        buf.msg.head.msgh_local_port = MACH_PORT_NULL;
3367        buf.msg.head.msgh_id = id;
3368                
3369        r = mach_msg(
3370            &buf.msg.head,
3371            MACH_SEND_MSG|MACH_RCV_MSG|MACH_RCV_LARGE,
3372            sizeof(buf.msg),
3373            sizeof(buf),
3374            GC_ports.reply,
3375            MACH_MSG_TIMEOUT_NONE,
3376            MACH_PORT_NULL);
3377        if(r != MACH_MSG_SUCCESS)
3378            ABORT("mach_msg failed in GC_mprotect_thread_notify");
3379        if(buf.msg.head.msgh_id != ID_ACK)
3380            ABORT("invalid ack in GC_mprotect_thread_notify");
3381    }
3382    
3383    /* Should only be called by the mprotect thread */
3384    static void GC_mprotect_thread_reply() {
3385        GC_msg_t msg;
3386        mach_msg_return_t r;
3387        /* remote, local */
3388        msg.head.msgh_bits =
3389            MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND,0);
3390        msg.head.msgh_size = sizeof(msg);
3391        msg.head.msgh_remote_port = GC_ports.reply;
3392        msg.head.msgh_local_port = MACH_PORT_NULL;
3393        msg.head.msgh_id = ID_ACK;
3394                
3395        r = mach_msg(
3396            &msg.head,
3397            MACH_SEND_MSG,
3398            sizeof(msg),
3399            0,
3400            MACH_PORT_NULL,
3401            MACH_MSG_TIMEOUT_NONE,
3402            MACH_PORT_NULL);
3403        if(r != MACH_MSG_SUCCESS)
3404            ABORT("mach_msg failed in GC_mprotect_thread_reply");
3405    }
3406    
3407    void GC_mprotect_stop() {
3408        GC_mprotect_thread_notify(ID_STOP);
3409    }
3410    void GC_mprotect_resume() {
3411        GC_mprotect_thread_notify(ID_RESUME);
3412    }
3413    
3414    #else /* !THREADS */
3415    /* The compiler should optimize away any GC_mprotect_state computations */
3416    #define GC_mprotect_state GC_MP_NORMAL
3417    #endif
3418    
3419    static void *GC_mprotect_thread(void *arg) {
3420        mach_msg_return_t r;
3421        /* These two structures contain some private kernel data. We don't need to
3422           access any of it so we don't bother defining a proper struct. The
3423           correct definitions are in the xnu source code. */
3424        struct {
3425            mach_msg_header_t head;
3426            char data[256];
3427        } reply;
3428        struct {
3429            mach_msg_header_t head;
3430            mach_msg_body_t msgh_body;
3431            char data[1024];
3432        } msg;
3433    
3434        mach_msg_id_t id;
3435        
3436        for(;;) {
3437            r = mach_msg(
3438                &msg.head,
3439                MACH_RCV_MSG|MACH_RCV_LARGE|
3440                    (GC_mprotect_state == GC_MP_DISCARDING ? MACH_RCV_TIMEOUT : 0),
3441                0,
3442                sizeof(msg),
3443                GC_ports.exception,
3444                GC_mprotect_state == GC_MP_DISCARDING ? 0 : MACH_MSG_TIMEOUT_NONE,
3445                MACH_PORT_NULL);
3446            
3447            id = r == MACH_MSG_SUCCESS ? msg.head.msgh_id : -1;
3448            
3449    #if defined(THREADS)
3450            if(GC_mprotect_state == GC_MP_DISCARDING) {
3451                if(r == MACH_RCV_TIMED_OUT) {
3452                    GC_mprotect_state = GC_MP_STOPPED;
3453                    GC_mprotect_thread_reply();
3454                    continue;
3455                }
3456                if(r == MACH_MSG_SUCCESS && (id == ID_STOP || id == ID_RESUME))
3457                    ABORT("out of order mprotect thread request");
3458            }
3459    #endif
3460            
3461            if(r != MACH_MSG_SUCCESS) {
3462                GC_err_printf2("mach_msg failed with %d %s\n",
3463                    (int)r,mach_error_string(r));
3464                ABORT("mach_msg failed");
3465            }
3466            
3467            switch(id) {
3468    #if defined(THREADS)
3469                case ID_STOP:
3470                    if(GC_mprotect_state != GC_MP_NORMAL)
3471                        ABORT("Called mprotect_stop when state wasn't normal");
3472                    GC_mprotect_state = GC_MP_DISCARDING;
3473                    break;
3474                case ID_RESUME:
3475                    if(GC_mprotect_state != GC_MP_STOPPED)
3476                        ABORT("Called mprotect_resume when state wasn't stopped");
3477                    GC_mprotect_state = GC_MP_NORMAL;
3478                    GC_mprotect_thread_reply();
3479                    break;
3480    #endif /* THREADS */
3481                default:
3482                        /* Handle the message (calls catch_exception_raise) */
3483                    if(!exc_server(&msg.head,&reply.head))
3484                        ABORT("exc_server failed");
3485                    /* Send the reply */
3486                    r = mach_msg(
3487                        &reply.head,
3488                        MACH_SEND_MSG,
3489                        reply.head.msgh_size,
3490                        0,
3491                        MACH_PORT_NULL,
3492                        MACH_MSG_TIMEOUT_NONE,
3493                        MACH_PORT_NULL);
3494                    if(r != MACH_MSG_SUCCESS) {
3495                            /* This will fail if the thread dies, but the thread shouldn't
3496                               die... */
3497                            #ifdef BROKEN_EXCEPTION_HANDLING
3498                            GC_err_printf2(
3499                            "mach_msg failed with %d %s while sending exc reply\n",
3500                            (int)r,mach_error_string(r));
3501                    #else
3502                            ABORT("mach_msg failed while sending exception reply");
3503                    #endif
3504                    }
3505            } /* switch */
3506        } /* for(;;) */
3507        /* NOT REACHED */
3508        return NULL;
3509    }
3510    
3511    /* All this SIGBUS code shouldn't be necessary. All protection faults should
3512       be going throught the mach exception handler. However, it seems a SIGBUS is
3513       occasionally sent for some unknown reason. Even more odd, it seems to be
3514       meaningless and safe to ignore. */
3515    #ifdef BROKEN_EXCEPTION_HANDLING
3516    
3517    typedef void (* SIG_PF)();
3518    static SIG_PF GC_old_bus_handler;
3519    
3520    /* Updates to this aren't atomic, but the SIGBUSs seem pretty rare.
3521       Even if this doesn't get updated property, it isn't really a problem */
3522    static int GC_sigbus_count;
3523    
3524    static void GC_darwin_sigbus(int num,siginfo_t *sip,void *context) {
3525        if(num != SIGBUS) ABORT("Got a non-sigbus signal in the sigbus handler");
3526        
3527        /* Ugh... some seem safe to ignore, but too many in a row probably means
3528           trouble. GC_sigbus_count is reset for each mach exception that is
3529           handled */
3530        if(GC_sigbus_count >= 8) {
3531            ABORT("Got more than 8 SIGBUSs in a row!");
3532        } else {
3533            GC_sigbus_count++;
3534            GC_err_printf0("GC: WARNING: Ignoring SIGBUS.\n");
3535        }
3536    }
3537    #endif /* BROKEN_EXCEPTION_HANDLING */
3538    
3539    void GC_dirty_init() {
3540        kern_return_t r;
3541        mach_port_t me;
3542        pthread_t thread;
3543        pthread_attr_t attr;
3544        exception_mask_t mask;
3545        
3546    #   ifdef PRINTSTATS
3547            GC_printf0("Inititalizing mach/darwin mprotect virtual dirty bit "
3548                "implementation\n");
3549    #   endif  
3550    #       ifdef BROKEN_EXCEPTION_HANDLING
3551            GC_err_printf0("GC: WARNING: Enabling workarounds for various darwin "
3552                "exception handling bugs.\n");
3553    #       endif
3554        GC_dirty_maintained = TRUE;
3555        if (GC_page_size % HBLKSIZE != 0) {
3556            GC_err_printf0("Page size not multiple of HBLKSIZE\n");
3557            ABORT("Page size not multiple of HBLKSIZE");
3558        }
3559        
3560        GC_task_self = me = mach_task_self();
3561        
3562        r = mach_port_allocate(me,MACH_PORT_RIGHT_RECEIVE,&GC_ports.exception);
3563        if(r != KERN_SUCCESS) ABORT("mach_port_allocate failed (exception port)");
3564        
3565        r = mach_port_insert_right(me,GC_ports.exception,GC_ports.exception,
3566            MACH_MSG_TYPE_MAKE_SEND);
3567        if(r != KERN_SUCCESS)
3568            ABORT("mach_port_insert_right failed (exception port)");
3569    
3570        #if defined(THREADS)
3571            r = mach_port_allocate(me,MACH_PORT_RIGHT_RECEIVE,&GC_ports.reply);
3572            if(r != KERN_SUCCESS) ABORT("mach_port_allocate failed (reply port)");
3573        #endif
3574    
3575        /* The exceptions we want to catch */  
3576        mask = EXC_MASK_BAD_ACCESS;
3577    
3578        r = task_get_exception_ports(
3579            me,
3580            mask,
3581            GC_old_exc_ports.masks,
3582            &GC_old_exc_ports.count,
3583            GC_old_exc_ports.ports,
3584            GC_old_exc_ports.behaviors,
3585            GC_old_exc_ports.flavors
3586        );
3587        if(r != KERN_SUCCESS) ABORT("task_get_exception_ports failed");
3588            
3589        r = task_set_exception_ports(
3590            me,
3591            mask,
3592            GC_ports.exception,
3593            EXCEPTION_DEFAULT,
3594            MACHINE_THREAD_STATE
3595        );
3596        if(r != KERN_SUCCESS) ABORT("task_set_exception_ports failed");
3597    
3598        if(pthread_attr_init(&attr) != 0) ABORT("pthread_attr_init failed");
3599        if(pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED) != 0)
3600            ABORT("pthread_attr_setdetachedstate failed");
3601    
3602    #       undef pthread_create
3603        /* This will call the real pthread function, not our wrapper */
3604        if(pthread_create(&thread,&attr,GC_mprotect_thread,NULL) != 0)
3605            ABORT("pthread_create failed");
3606        pthread_attr_destroy(&attr);
3607        
3608        /* Setup the sigbus handler for ignoring the meaningless SIGBUSs */
3609        #ifdef BROKEN_EXCEPTION_HANDLING
3610        {
3611            struct sigaction sa, oldsa;
3612            sa.sa_handler = (SIG_PF)GC_darwin_sigbus;
3613            sigemptyset(&sa.sa_mask);
3614            sa.sa_flags = SA_RESTART|SA_SIGINFO;
3615            if(sigaction(SIGBUS,&sa,&oldsa) < 0) ABORT("sigaction");
3616            GC_old_bus_handler = (SIG_PF)oldsa.sa_handler;
3617            if (GC_old_bus_handler != SIG_DFL) {
3618    #               ifdef PRINTSTATS
3619                    GC_err_printf0("Replaced other SIGBUS handler\n");
3620    #               endif
3621            }
3622        }
3623        #endif /* BROKEN_EXCEPTION_HANDLING  */
3624    }
3625    
3626    /* The source code for Apple's GDB was used as a reference for the exception
3627       forwarding code. This code is similar to be GDB code only because there is
3628       only one way to do it. */
3629    static kern_return_t GC_forward_exception(
3630            mach_port_t thread,
3631            mach_port_t task,
3632            exception_type_t exception,
3633            exception_data_t data,
3634            mach_msg_type_number_t data_count
3635    ) {
3636        int i;
3637        kern_return_t r;
3638        mach_port_t port;
3639        exception_behavior_t behavior;
3640        thread_state_flavor_t flavor;
3641        
3642        thread_state_data_t thread_state;
3643        mach_msg_type_number_t thread_state_count = THREAD_STATE_MAX;
3644            
3645        for(i=0;i<GC_old_exc_ports.count;i++)
3646            if(GC_old_exc_ports.masks[i] & (1 << exception))
3647                break;
3648        if(i==GC_old_exc_ports.count) ABORT("No handler for exception!");
3649        
3650        port = GC_old_exc_ports.ports[i];
3651        behavior = GC_old_exc_ports.behaviors[i];
3652        flavor = GC_old_exc_ports.flavors[i];
3653    
3654        if(behavior != EXCEPTION_DEFAULT) {
3655            r = thread_get_state(thread,flavor,thread_state,&thread_state_count);
3656            if(r != KERN_SUCCESS)
3657                ABORT("thread_get_state failed in forward_exception");
3658        }
3659        
3660        switch(behavior) {
3661            case EXCEPTION_DEFAULT:
3662                r = exception_raise(port,thread,task,exception,data,data_count);
3663                break;
3664            case EXCEPTION_STATE:
3665                r = exception_raise_state(port,thread,task,exception,data,
3666                    data_count,&flavor,thread_state,thread_state_count,
3667                    thread_state,&thread_state_count);
3668                break;
3669            case EXCEPTION_STATE_IDENTITY:
3670                r = exception_raise_state_identity(port,thread,task,exception,data,
3671                    data_count,&flavor,thread_state,thread_state_count,
3672                    thread_state,&thread_state_count);
3673                break;
3674            default:
3675                r = KERN_FAILURE; /* make gcc happy */
3676                ABORT("forward_exception: unknown behavior");
3677                break;
3678        }
3679        
3680        if(behavior != EXCEPTION_DEFAULT) {
3681            r = thread_set_state(thread,flavor,thread_state,thread_state_count);
3682            if(r != KERN_SUCCESS)
3683                ABORT("thread_set_state failed in forward_exception");
3684        }
3685        
3686        return r;
3687    }
3688    
3689    #define FWD() GC_forward_exception(thread,task,exception,code,code_count)
3690    
3691    /* This violates the namespace rules but there isn't anything that can be done
3692       about it. The exception handling stuff is hard coded to call this */
3693    kern_return_t
3694    catch_exception_raise(
3695       mach_port_t exception_port,mach_port_t thread,mach_port_t task,
3696       exception_type_t exception,exception_data_t code,
3697       mach_msg_type_number_t code_count
3698    ) {
3699        kern_return_t r;
3700        char *addr;
3701        struct hblk *h;
3702        int i;
3703    #ifdef POWERPC
3704        thread_state_flavor_t flavor = PPC_EXCEPTION_STATE;
3705        mach_msg_type_number_t exc_state_count = PPC_EXCEPTION_STATE_COUNT;
3706        ppc_exception_state_t exc_state;
3707    #else
3708    #       error FIXME for non-ppc darwin
3709    #endif
3710    
3711        
3712        if(exception != EXC_BAD_ACCESS || code[0] != KERN_PROTECTION_FAILURE) {
3713            #ifdef DEBUG_EXCEPTION_HANDLING
3714            /* We aren't interested, pass it on to the old handler */
3715            GC_printf3("Exception: 0x%x Code: 0x%x 0x%x in catch....\n",
3716                exception,
3717                code_count > 0 ? code[0] : -1,
3718                code_count > 1 ? code[1] : -1);
3719            #endif
3720            return FWD();
3721        }
3722    
3723        r = thread_get_state(thread,flavor,
3724            (natural_t*)&exc_state,&exc_state_count);
3725        if(r != KERN_SUCCESS) {
3726            /* The thread is supposed to be suspended while the exception handler
3727               is called. This shouldn't fail. */
3728            #ifdef BROKEN_EXCEPTION_HANDLING
3729                GC_err_printf0("thread_get_state failed in "
3730                    "catch_exception_raise\n");
3731                return KERN_SUCCESS;
3732            #else
3733                ABORT("thread_get_state failed in catch_exception_raise");
3734            #endif
3735        }
3736        
3737        /* This is the address that caused the fault */
3738        addr = (char*) exc_state.dar;
3739            
3740        if((HDR(addr)) == 0) {
3741            /* Ugh... just like the SIGBUS problem above, it seems we get a bogus
3742               KERN_PROTECTION_FAILURE every once and a while. We wait till we get
3743               a bunch in a row before doing anything about it. If a "real" fault
3744               ever occurres it'll just keep faulting over and over and we'll hit
3745               the limit pretty quickly. */
3746            #ifdef BROKEN_EXCEPTION_HANDLING
3747                static char *last_fault;
3748                static int last_fault_count;
3749                
3750                if(addr != last_fault) {
3751                    last_fault = addr;
3752                    last_fault_count = 0;
3753                }
3754                if(++last_fault_count < 32) {
3755                    if(last_fault_count == 1)
3756                        GC_err_printf1(
3757                            "GC: WARNING: Ignoring KERN_PROTECTION_FAILURE at %p\n",
3758                            addr);
3759                    return KERN_SUCCESS;
3760                }
3761                
3762                GC_err_printf1("Unexpected KERN_PROTECTION_FAILURE at %p\n",addr);
3763                /* Can't pass it along to the signal handler because that is
3764                   ignoring SIGBUS signals. We also shouldn't call ABORT here as
3765                   signals don't always work too well from the exception handler. */
3766                GC_err_printf0("Aborting\n");
3767                exit(EXIT_FAILURE);
3768            #else /* BROKEN_EXCEPTION_HANDLING */
3769                /* Pass it along to the next exception handler
3770                   (which should call SIGBUS/SIGSEGV) */
3771                return FWD();
3772            #endif /* !BROKEN_EXCEPTION_HANDLING */
3773        }
3774    
3775        #ifdef BROKEN_EXCEPTION_HANDLING
3776            /* Reset the number of consecutive SIGBUSs */
3777            GC_sigbus_count = 0;
3778        #endif
3779        
3780        if(GC_mprotect_state == GC_MP_NORMAL) { /* common case */
3781            h = (struct hblk*)((word)addr & ~(GC_page_size-1));
3782            UNPROTECT(h, GC_page_size);    
3783            for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
3784                register int index = PHT_HASH(h+i);
3785                async_set_pht_entry_from_index(GC_dirty_pages, index);
3786            }
3787        } else if(GC_mprotect_state == GC_MP_DISCARDING) {
3788            /* Lie to the thread for now. No sense UNPROTECT()ing the memory
3789               when we're just going to PROTECT() it again later. The thread
3790               will just fault again once it resumes */
3791        } else {
3792            /* Shouldn't happen, i don't think */
3793            GC_printf0("KERN_PROTECTION_FAILURE while world is stopped\n");
3794            return FWD();
3795        }
3796        return KERN_SUCCESS;
3797    }
3798    #undef FWD
3799    
3800    /* These should never be called, but just in case...  */
3801    kern_return_t catch_exception_raise_state(mach_port_name_t exception_port,
3802        int exception, exception_data_t code, mach_msg_type_number_t codeCnt,
3803        int flavor, thread_state_t old_state, int old_stateCnt,
3804        thread_state_t new_state, int new_stateCnt)
3805    {
3806        ABORT("catch_exception_raise_state");
3807        return(KERN_INVALID_ARGUMENT);
3808    }
3809    kern_return_t catch_exception_raise_state_identity(
3810        mach_port_name_t exception_port, mach_port_t thread, mach_port_t task,
3811        int exception, exception_data_t code, mach_msg_type_number_t codeCnt,
3812        int flavor, thread_state_t old_state, int old_stateCnt,
3813        thread_state_t new_state, int new_stateCnt)
3814    {
3815        ABORT("catch_exception_raise_state_identity");
3816        return(KERN_INVALID_ARGUMENT);
3817    }
3818    
3819    
3820    #endif /* DARWIN && MPROTECT_VDB */
3821    
3822  # ifndef HAVE_INCREMENTAL_PROTECTION_NEEDS  # ifndef HAVE_INCREMENTAL_PROTECTION_NEEDS
3823    int GC_incremental_protection_needs()    int GC_incremental_protection_needs()
3824    {    {
# Line 3323  struct callinfo info[NFRAMES]; Line 3938  struct callinfo info[NFRAMES];
3938      asm("movl %%ebp,%0" : "=r"(frame));      asm("movl %%ebp,%0" : "=r"(frame));
3939      fp = frame;      fp = frame;
3940  # else  # else
     word GC_save_regs_in_stack();  
   
3941      frame = (struct frame *) GC_save_regs_in_stack ();      frame = (struct frame *) GC_save_regs_in_stack ();
3942      fp = (struct frame *)((long) frame -> FR_SAVFP + BIAS);      fp = (struct frame *)((long) frame -> FR_SAVFP + BIAS);
3943  #endif  #endif
# Line 3465  struct callinfo info[NFRAMES]; Line 4078  struct callinfo info[NFRAMES];
4078                  }                  }
4079                  name = result_buf;                  name = result_buf;
4080                  pclose(pipe);                  pclose(pipe);
4081                  out:                  out:;
4082              }              }
4083  #         endif /* LINUX */  #         endif /* LINUX */
4084            GC_err_printf1("\t\t%s\n", name);            GC_err_printf1("\t\t%s\n", name);
# Line 3481  struct callinfo info[NFRAMES]; Line 4094  struct callinfo info[NFRAMES];
4094    
4095  #endif /* NEED_CALLINFO */  #endif /* NEED_CALLINFO */
4096    
 #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 && ... */  
4097    
4098    
4099  #if defined(LINUX) && defined(__ELF__) && !defined(SMALL_CONFIG)  #if defined(LINUX) && defined(__ELF__) && !defined(SMALL_CONFIG)
# Line 3513  ssize_t GC_repeat_read(int fd, char *buf Line 4101  ssize_t GC_repeat_read(int fd, char *buf
4101  /* Dump /proc/self/maps to GC_stderr, to enable looking up names for  /* Dump /proc/self/maps to GC_stderr, to enable looking up names for
4102     addresses in FIND_LEAK output. */     addresses in FIND_LEAK output. */
4103    
4104    static word dump_maps(char *maps)
4105    {
4106        GC_err_write(maps, strlen(maps));
4107        return 1;
4108    }
4109    
4110  void GC_print_address_map()  void GC_print_address_map()
4111  {  {
     int f;  
     int result;  
     char maps_temp[32768];  
4112      GC_err_printf0("---------- Begin address map ----------\n");      GC_err_printf0("---------- Begin address map ----------\n");
4113          f = open("/proc/self/maps", O_RDONLY);      GC_apply_to_maps(dump_maps);
         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);      
4114      GC_err_printf0("---------- End address map ----------\n");      GC_err_printf0("---------- End address map ----------\n");
4115  }  }
4116    

Legend:
Removed from v.1.2.2.1  
changed lines
  Added in v.1.2.2.1.2.1

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26