[BACK]Return to os_dep.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib2 / asir2000 / gc

Diff for /OpenXM_contrib2/asir2000/gc/os_dep.c between version 1.6 and 1.7

version 1.6, 2002/07/24 08:00:11 version 1.7, 2003/06/24 05:11:33
Line 80 
Line 80 
 #   define NEED_FIND_LIMIT  #   define NEED_FIND_LIMIT
 # endif  # endif
   
 #ifdef NEED_FIND_LIMIT  
 #   include <setjmp.h>  
 #endif  
   
 #if defined(FREEBSD) && defined(I386)  #if defined(FREEBSD) && defined(I386)
 #  include <machine/trap.h>  #  include <machine/trap.h>
   #  if !defined(PCR)
   #    define NEED_FIND_LIMIT
   #  endif
 #endif  #endif
   
   #ifdef NEED_FIND_LIMIT
   #   include <setjmp.h>
   #endif
   
 #ifdef AMIGA  #ifdef AMIGA
 # define GC_AMIGA_DEF  # define GC_AMIGA_DEF
 # include "AmigaOS.c"  # include "AmigaOS.c"
Line 129 
Line 132 
 # define jmp_buf sigjmp_buf  # define jmp_buf sigjmp_buf
 #endif  #endif
   
   #ifdef DARWIN
   /* for get_etext and friends */
   #include <mach-o/getsect.h>
   #endif
   
 #ifdef DJGPP  #ifdef DJGPP
   /* Apparently necessary for djgpp 2.01.  May cause problems with      */    /* Apparently necessary for djgpp 2.01.  May cause problems with      */
   /* other versions.                                                    */    /* other versions.                                                    */
Line 147 
Line 155 
 # define OPT_PROT_EXEC 0  # define OPT_PROT_EXEC 0
 #endif  #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)  #if defined(SEARCH_FOR_DATA_START)
   /* The I386 case can be handled without a search.  The Alpha case     */    /* The I386 case can be handled without a search.  The Alpha case     */
   /* used to be handled differently as well, but the rules changed      */    /* used to be handled differently as well, but the rules changed      */
Line 154 
Line 312 
   /* cover all versions.                                                */    /* cover all versions.                                                */
   
 # ifdef LINUX  # ifdef LINUX
       /* Some Linux distributions arrange to define __data_start.  Some   */
       /* define data_start as a weak symbol.  The latter is technically   */
       /* broken, since the user program may define data_start, in which   */
       /* case we lose.  Nonetheless, we try both, prefering __data_start. */
       /* We assume gcc-compatible pragmas.        */
 #   pragma weak __data_start  #   pragma weak __data_start
     extern int __data_start[];      extern int __data_start[];
 #   pragma weak data_start  #   pragma weak data_start
Line 617  ptr_t GC_get_stack_base()
Line 780  ptr_t GC_get_stack_base()
     }      }
   
     /* Return the first nonaddressible location > p (up) or     */      /* Return the first nonaddressible location > p (up) or     */
     /* the smallest location q s.t. [q,p] is addressible (!up). */      /* the smallest location q s.t. [q,p) is addressable (!up). */
       /* We assume that p (up) or p-1 (!up) is addressable.       */
     ptr_t GC_find_limit(p, up)      ptr_t GC_find_limit(p, up)
     ptr_t p;      ptr_t p;
     GC_bool up;      GC_bool up;
Line 661  ptr_t GC_get_stack_base()
Line 825  ptr_t GC_get_stack_base()
   
 #include <sys/types.h>  #include <sys/types.h>
 #include <sys/stat.h>  #include <sys/stat.h>
   #include <ctype.h>
   
 # define STAT_SKIP 27   /* Number of fields preceding startstack        */  # define STAT_SKIP 27   /* Number of fields preceding startstack        */
                         /* field in /proc/self/stat                     */                          /* field in /proc/self/stat                     */
Line 669  ptr_t GC_get_stack_base()
Line 834  ptr_t GC_get_stack_base()
   extern ptr_t __libc_stack_end;    extern ptr_t __libc_stack_end;
   
 # ifdef IA64  # 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  #   pragma weak __libc_ia64_register_backing_store_base
     extern ptr_t __libc_ia64_register_backing_store_base;      extern ptr_t __libc_ia64_register_backing_store_base;
   
Line 678  ptr_t GC_get_stack_base()
Line 870  ptr_t GC_get_stack_base()
           && 0 != __libc_ia64_register_backing_store_base) {            && 0 != __libc_ia64_register_backing_store_base) {
         /* Glibc 2.2.4 has a bug such that for dynamically linked       */          /* Glibc 2.2.4 has a bug such that for dynamically linked       */
         /* executables __libc_ia64_register_backing_store_base is       */          /* executables __libc_ia64_register_backing_store_base is       */
         /* defined but ininitialized during constructor calls.          */          /* defined but uninitialized during constructor calls.          */
         /* Hence we check for both nonzero address and value.           */          /* Hence we check for both nonzero address and value.           */
         return __libc_ia64_register_backing_store_base;          return __libc_ia64_register_backing_store_base;
       } else {        } else {
         word result = (word)GC_stackbottom - BACKING_STORE_DISPLACEMENT;          word result = backing_store_base_from_proc();
         result += BACKING_STORE_ALIGNMENT - 1;          if (0 == result) {
         result &= ~(BACKING_STORE_ALIGNMENT - 1);            /* 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;          return (ptr_t)result;
       }        }
     }      }
Line 696  ptr_t GC_get_stack_base()
Line 894  ptr_t GC_get_stack_base()
     /* using direct I/O system calls in order to avoid calling malloc   */      /* using direct I/O system calls in order to avoid calling malloc   */
     /* in case REDIRECT_MALLOC is defined.                              */      /* in case REDIRECT_MALLOC is defined.                              */
 #   define STAT_BUF_SIZE 4096  #   define STAT_BUF_SIZE 4096
 #   if defined(GC_USE_LD_WRAP)  #   define STAT_READ read
 #       define STAT_READ __real_read            /* Should probably call the real read, if read is wrapped.    */
 #   else  
 #       define STAT_READ read  
 #   endif  
     char stat_buf[STAT_BUF_SIZE];      char stat_buf[STAT_BUF_SIZE];
     int f;      int f;
     char c;      char c;
Line 772  ptr_t GC_get_stack_base()
Line 967  ptr_t GC_get_stack_base()
   
 ptr_t GC_get_stack_base()  ptr_t GC_get_stack_base()
 {  {
   #   if defined(HEURISTIC1) || defined(HEURISTIC2) || \
          defined(LINUX_STACKBOTTOM) || defined(FREEBSD_STACKBOTTOM)
     word dummy;      word dummy;
     ptr_t result;      ptr_t result;
   #   endif
   
 #   define STACKBOTTOM_ALIGNMENT_M1 ((word)STACK_GRAN - 1)  #   define STACKBOTTOM_ALIGNMENT_M1 ((word)STACK_GRAN - 1)
   
Line 934  void GC_register_data_segments()
Line 1132  void GC_register_data_segments()
   /* invalid result.  Under NT, GC_register_data_segments is a noop and */    /* invalid result.  Under NT, GC_register_data_segments is a noop and */
   /* all real work is done by GC_register_dynamic_libraries.  Under     */    /* all real work is done by GC_register_dynamic_libraries.  Under     */
   /* win32s, we cannot find the data segments associated with dll's.    */    /* win32s, we cannot find the data segments associated with dll's.    */
   /* We rgister 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  
   GC_bool GC_no_win32_dlls = FALSE;    GC_bool GC_no_win32_dlls = FALSE;
 #  endif          /* 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()    void GC_init_win32()
   {    {
Line 971  void GC_register_data_segments()
Line 1168  void GC_register_data_segments()
     return(p);      return(p);
   }    }
 # endif  # endif
   
   # ifndef REDIRECT_MALLOC
     /* We maintain a linked list of AllocationBase values that we know    */
     /* correspond to malloc heap sections.  Currently this is only called */
     /* during a GC.  But there is some hope that for long running         */
     /* programs we will eventually see most heap sections.                */
   
     /* In the long run, it would be more reliable to occasionally walk    */
     /* the malloc heap with HeapWalk on the default heap.  But that       */
     /* apparently works only for NT-based Windows.                        */
   
     /* In the long run, a better data structure would also be nice ...    */
     struct GC_malloc_heap_list {
       void * allocation_base;
       struct GC_malloc_heap_list *next;
     } *GC_malloc_heap_l = 0;
   
     /* Is p the base of one of the malloc heap sections we already know   */
     /* about?                                                             */
     GC_bool GC_is_malloc_heap_base(ptr_t p)
     {
       struct GC_malloc_heap_list *q = GC_malloc_heap_l;
   
       while (0 != q) {
         if (q -> allocation_base == p) return TRUE;
         q = q -> next;
       }
       return FALSE;
     }
   
     void *GC_get_allocation_base(void *p)
     {
       MEMORY_BASIC_INFORMATION buf;
       DWORD result = VirtualQuery(p, &buf, sizeof(buf));
       if (result != sizeof(buf)) {
         ABORT("Weird VirtualQuery result");
       }
       return buf.AllocationBase;
     }
   
     size_t GC_max_root_size = 100000;     /* Appr. largest root size.     */
   
     void GC_add_current_malloc_heap()
     {
       struct GC_malloc_heap_list *new_l =
                    malloc(sizeof(struct GC_malloc_heap_list));
       void * candidate = GC_get_allocation_base(new_l);
   
       if (new_l == 0) return;
       if (GC_is_malloc_heap_base(candidate)) {
         /* Try a little harder to find malloc heap.                       */
           size_t req_size = 10000;
           do {
             void *p = malloc(req_size);
             if (0 == p) { free(new_l); return; }
             candidate = GC_get_allocation_base(p);
             free(p);
             req_size *= 2;
           } while (GC_is_malloc_heap_base(candidate)
                    && req_size < GC_max_root_size/10 && req_size < 500000);
           if (GC_is_malloc_heap_base(candidate)) {
             free(new_l); return;
           }
       }
   #   ifdef CONDPRINT
         if (GC_print_stats)
             GC_printf1("Found new system malloc AllocationBase at 0x%lx\n",
                        candidate);
   #   endif
       new_l -> allocation_base = candidate;
       new_l -> next = GC_malloc_heap_l;
       GC_malloc_heap_l = new_l;
     }
   # endif /* REDIRECT_MALLOC */
   
   /* Is p the start of either the malloc heap, or of one of our */    /* Is p the start of either the malloc heap, or of one of our */
   /* heap sections?                                             */    /* heap sections?                                             */
   GC_bool GC_is_heap_base (ptr_t p)    GC_bool GC_is_heap_base (ptr_t p)
   {    {
   
      register unsigned i;       unsigned i;
   
 #    ifndef REDIRECT_MALLOC  #    ifndef REDIRECT_MALLOC
        static ptr_t malloc_heap_pointer = 0;         static word last_gc_no = -1;
   
        if (0 == malloc_heap_pointer) {         if (last_gc_no != GC_gc_no) {
          MEMORY_BASIC_INFORMATION buf;           GC_add_current_malloc_heap();
          void *pTemp = malloc( 1 );           last_gc_no = GC_gc_no;
          register DWORD result = VirtualQuery(pTemp, &buf, sizeof(buf));  
   
          free( pTemp );  
   
   
          if (result != sizeof(buf)) {  
              ABORT("Weird VirtualQuery result");  
          }  
          malloc_heap_pointer = (ptr_t)(buf.AllocationBase);  
        }         }
        if (p == malloc_heap_pointer) return(TRUE);         if (GC_root_size > GC_max_root_size) GC_max_root_size = GC_root_size;
          if (GC_is_malloc_heap_base(p)) return TRUE;
 #    endif  #    endif
      for (i = 0; i < GC_n_heap_bases; i++) {       for (i = 0; i < GC_n_heap_bases; i++) {
          if (GC_heap_bases[i] == p) return(TRUE);           if (GC_heap_bases[i] == p) return TRUE;
      }       }
      return(FALSE);       return FALSE ;
   }    }
   
 # ifdef MSWIN32  # ifdef MSWIN32
Line 1050  void GC_register_data_segments()
Line 1313  void GC_register_data_segments()
   
 # if (defined(SVR4) || defined(AUX) || defined(DGUX) \  # if (defined(SVR4) || defined(AUX) || defined(DGUX) \
       || (defined(LINUX) && defined(SPARC))) && !defined(PCR)        || (defined(LINUX) && defined(SPARC))) && !defined(PCR)
 char * GC_SysVGetDataStart(max_page_size, etext_addr)  ptr_t GC_SysVGetDataStart(max_page_size, etext_addr)
 int max_page_size;  int max_page_size;
 int * etext_addr;  int * etext_addr;
 {  {
Line 1076  int * etext_addr;
Line 1339  int * etext_addr;
         /* string constants in the text segment, but after etext.       */          /* string constants in the text segment, but after etext.       */
         /* Use plan B.  Note that we now know there is a gap between    */          /* Use plan B.  Note that we now know there is a gap between    */
         /* text and data segments, so plan A bought us something.       */          /* text and data segments, so plan A bought us something.       */
         result = (char *)GC_find_limit((ptr_t)(DATAEND) - MIN_PAGE_SIZE, FALSE);          result = (char *)GC_find_limit((ptr_t)(DATAEND), FALSE);
     }      }
     return((char *)result);      return((ptr_t)result);
 }  }
 # endif  # endif
   
   # if defined(FREEBSD) && defined(I386) && !defined(PCR)
   /* Its unclear whether this should be identical to the above, or        */
   /* whether it should apply to non-X86 architectures.                    */
   /* For now we don't assume that there is always an empty page after     */
   /* etext.  But in some cases there actually seems to be slightly more.  */
   /* This also deals with holes between read-only data and writable data. */
   ptr_t GC_FreeBSDGetDataStart(max_page_size, etext_addr)
   int max_page_size;
   int * etext_addr;
   {
       word text_end = ((word)(etext_addr) + sizeof(word) - 1)
                        & ~(sizeof(word) - 1);
           /* etext rounded to word boundary       */
       VOLATILE word next_page = (text_end + (word)max_page_size - 1)
                                 & ~((word)max_page_size - 1);
       VOLATILE ptr_t result = (ptr_t)text_end;
       GC_setup_temporary_fault_handler();
       if (setjmp(GC_jmp_buf) == 0) {
           /* Try reading at the address.                          */
           /* This should happen before there is another thread.   */
           for (; next_page < (word)(DATAEND); next_page += (word)max_page_size)
               *(VOLATILE char *)next_page;
           GC_reset_fault_handler();
       } else {
           GC_reset_fault_handler();
           /* As above, we go to plan B    */
           result = GC_find_limit((ptr_t)(DATAEND), FALSE);
       }
       return(result);
   }
   
   # endif
   
   
 #ifdef AMIGA  #ifdef AMIGA
   
 #  define GC_AMIGA_DS  #  define GC_AMIGA_DS
Line 1093  int * etext_addr;
Line 1389  int * etext_addr;
   
 void GC_register_data_segments()  void GC_register_data_segments()
 {  {
 #   if !defined(PCR) && !defined(SRC_M3) && !defined(NEXT) && !defined(MACOS) \  #   if !defined(PCR) && !defined(SRC_M3) && !defined(MACOS)
        && !defined(MACOSX)  
 #     if defined(REDIRECT_MALLOC) && defined(GC_SOLARIS_THREADS)  #     if defined(REDIRECT_MALLOC) && defined(GC_SOLARIS_THREADS)
         /* As of Solaris 2.3, the Solaris threads implementation        */          /* As of Solaris 2.3, the Solaris threads implementation        */
         /* allocates the data structure for the initial thread with     */          /* allocates the data structure for the initial thread with     */
Line 1111  void GC_register_data_segments()
Line 1406  void GC_register_data_segments()
 #       endif  #       endif
 #     endif  #     endif
 #   endif  #   endif
 #   if !defined(PCR) && (defined(NEXT) || defined(MACOSX))  
       GC_add_roots_inner(DATASTART, (char *) get_end(), FALSE);  
 #   endif  
 #   if defined(MACOS)  #   if defined(MACOS)
     {      {
 #   if defined(THINK_C)  #   if defined(THINK_C)
Line 1223  word bytes;
Line 1515  word bytes;
 ptr_t GC_unix_get_mem(bytes)  ptr_t GC_unix_get_mem(bytes)
 word bytes;  word bytes;
 {  {
     static GC_bool initialized = FALSE;  
     static int fd;  
     void *result;      void *result;
     static ptr_t last_addr = HEAP_START;      static ptr_t last_addr = HEAP_START;
   
     if (!initialized) {  #   ifndef USE_MMAP_ANON
         fd = open("/dev/zero", O_RDONLY);        static GC_bool initialized = FALSE;
         initialized = TRUE;        static int fd;
     }  
         if (!initialized) {
             fd = open("/dev/zero", O_RDONLY);
             fcntl(fd, F_SETFD, FD_CLOEXEC);
             initialized = TRUE;
         }
   #   endif
   
     if (bytes & (GC_page_size -1)) ABORT("Bad GET_MEM arg");      if (bytes & (GC_page_size -1)) ABORT("Bad GET_MEM arg");
     result = mmap(last_addr, bytes, PROT_READ | PROT_WRITE | OPT_PROT_EXEC,  #   ifdef USE_MMAP_ANON
                   GC_MMAP_FLAGS, fd, 0/* offset */);        result = mmap(last_addr, bytes, PROT_READ | PROT_WRITE | OPT_PROT_EXEC,
                       GC_MMAP_FLAGS | MAP_ANON, -1, 0/* offset */);
   #   else
         result = mmap(last_addr, bytes, PROT_READ | PROT_WRITE | OPT_PROT_EXEC,
                       GC_MMAP_FLAGS, fd, 0/* offset */);
   #   endif
     if (result == MAP_FAILED) return(0);      if (result == MAP_FAILED) return(0);
     last_addr = (ptr_t)result + bytes + GC_page_size - 1;      last_addr = (ptr_t)result + bytes + GC_page_size - 1;
     last_addr = (ptr_t)((word)last_addr & ~(GC_page_size - 1));      last_addr = (ptr_t)((word)last_addr & ~(GC_page_size - 1));
Line 1527  void GC_remap(ptr_t start, word bytes)
Line 1829  void GC_remap(ptr_t start, word bytes)
       }        }
 #   else  #   else
       if (-1 == zero_descr) zero_descr = open("/dev/zero", O_RDWR);        if (-1 == zero_descr) zero_descr = open("/dev/zero", O_RDWR);
         fcntl(zero_descr, F_SETFD, FD_CLOEXEC);
       if (0 == start_addr) return;        if (0 == start_addr) return;
       result = mmap(start_addr, len, PROT_READ | PROT_WRITE | OPT_PROT_EXEC,        result = mmap(start_addr, len, PROT_READ | PROT_WRITE | OPT_PROT_EXEC,
                     MAP_FIXED | MAP_PRIVATE, zero_descr, 0);                      MAP_FIXED | MAP_PRIVATE, zero_descr, 0);
Line 1713  void (*GC_push_other_roots) GC_PROTO((void)) = GC_defa
Line 2016  void (*GC_push_other_roots) GC_PROTO((void)) = GC_defa
  *              make sure that other system calls are similarly protected   *              make sure that other system calls are similarly protected
  *              or write only to the stack.   *              or write only to the stack.
  */   */
   
 GC_bool GC_dirty_maintained = FALSE;  GC_bool GC_dirty_maintained = FALSE;
   
 # ifdef DEFAULT_VDB  # ifdef DEFAULT_VDB
Line 1727  GC_bool GC_dirty_maintained = FALSE;
Line 2029  GC_bool GC_dirty_maintained = FALSE;
 /* Initialize virtual dirty bit implementation.                 */  /* Initialize virtual dirty bit implementation.                 */
 void GC_dirty_init()  void GC_dirty_init()
 {  {
   #   ifdef PRINTSTATS
         GC_printf0("Initializing DEFAULT_VDB...\n");
   #   endif
     GC_dirty_maintained = TRUE;      GC_dirty_maintained = TRUE;
 }  }
   
Line 1809  GC_bool is_ptrfree;
Line 2114  GC_bool is_ptrfree;
  * objects only if they are the same.   * objects only if they are the same.
  */   */
   
 # if !defined(MSWIN32) && !defined(MSWINCE)  # if !defined(MSWIN32) && !defined(MSWINCE) && !defined(DARWIN)
   
 #   include <sys/mman.h>  #   include <sys/mman.h>
 #   include <signal.h>  #   include <signal.h>
Line 1828  GC_bool is_ptrfree;
Line 2133  GC_bool is_ptrfree;
   
 # else  # 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  #   ifndef MSWINCE
 #     include <signal.h>  #     include <signal.h>
 #   endif  #   endif
Line 1845  GC_bool is_ptrfree;
Line 2167  GC_bool is_ptrfree;
                               &protect_junk)) { \                                &protect_junk)) { \
             ABORT("un-VirtualProtect failed"); \              ABORT("un-VirtualProtect failed"); \
           }            }
   # endif /* !DARWIN */
 # endif  # endif /* MSWIN32 || MSWINCE || DARWIN */
   
 #if defined(SUNOS4) || defined(FREEBSD)  #if defined(SUNOS4) || defined(FREEBSD)
     typedef void (* SIG_PF)();      typedef void (* SIG_PF)();
 #endif  #endif /* SUNOS4 || FREEBSD */
   
 #if defined(SUNOS5SIGS) || defined(OSF1) || defined(LINUX) \  #if defined(SUNOS5SIGS) || defined(OSF1) || defined(LINUX) \
     || defined(MACOSX) || defined(HURD)      || defined(HURD)
 # ifdef __STDC__  # ifdef __STDC__
     typedef void (* SIG_PF)(int);      typedef void (* SIG_PF)(int);
 # else  # else
     typedef void (* SIG_PF)();      typedef void (* SIG_PF)();
 # endif  # endif
 #endif  #endif /* SUNOS5SIGS || OSF1 || LINUX || HURD */
   
 #if defined(MSWIN32)  #if defined(MSWIN32)
     typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_PF;      typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_PF;
 #   undef SIG_DFL  #   undef SIG_DFL
Line 1872  GC_bool is_ptrfree;
Line 2196  GC_bool is_ptrfree;
   
 #if defined(IRIX5) || defined(OSF1) || defined(HURD)  #if defined(IRIX5) || defined(OSF1) || defined(HURD)
     typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);      typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);
 #endif  #endif /* IRIX5 || OSF1 || HURD */
   
 #if defined(SUNOS5SIGS)  #if defined(SUNOS5SIGS)
 # ifdef HPUX  # ifdef HPUX
 #   define SIGINFO __siginfo  #   define SIGINFO __siginfo
Line 1884  GC_bool is_ptrfree;
Line 2209  GC_bool is_ptrfree;
 # else  # else
     typedef void (* REAL_SIG_PF)();      typedef void (* REAL_SIG_PF)();
 # endif  # endif
 #endif  #endif /* SUNOS5SIGS */
   
 #if defined(LINUX)  #if defined(LINUX)
 #   if __GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 2  #   if __GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 2
       typedef struct sigcontext s_c;        typedef struct sigcontext s_c;
Line 1918  GC_bool is_ptrfree;
Line 2244  GC_bool is_ptrfree;
         return (char *)faultaddr;          return (char *)faultaddr;
     }      }
 #   endif /* !ALPHA */  #   endif /* !ALPHA */
 # endif  # endif /* LINUX */
   
 # if defined(MACOSX) /* Should also test for PowerPC? */  #ifndef DARWIN
     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_bus_handler;
 SIG_PF GC_old_segv_handler;     /* Also old MSWIN32 ACCESS_VIOLATION filter */  SIG_PF GC_old_segv_handler;     /* Also old MSWIN32 ACCESS_VIOLATION filter */
   #endif /* !DARWIN */
   
 #ifdef THREADS  #if defined(THREADS)
 /* 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  */
 /* 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       */
 /* 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 2099  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2300  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
 #endif /* !THREADS */  #endif /* !THREADS */
   
 /*ARGSUSED*/  /*ARGSUSED*/
   #if !defined(DARWIN)
 # if defined (SUNOS4) || defined(FREEBSD)  # if defined (SUNOS4) || defined(FREEBSD)
     void GC_write_fault_handler(sig, code, scp, addr)      void GC_write_fault_handler(sig, code, scp, addr)
     int sig, code;      int sig, code;
Line 2114  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2316  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
 #     define SIG_OK (sig == SIGBUS)  #     define SIG_OK (sig == SIGBUS)
 #     define CODE_OK (code == BUS_PAGE_FAULT)  #     define CODE_OK (code == BUS_PAGE_FAULT)
 #   endif  #   endif
 # endif  # endif /* SUNOS4 || FREEBSD */
   
 # if defined(IRIX5) || defined(OSF1) || defined(HURD)  # if defined(IRIX5) || defined(OSF1) || defined(HURD)
 #   include <errno.h>  #   include <errno.h>
     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 2130  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2333  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
 #     define SIG_OK (sig == SIGBUS || sig == SIGSEGV)  #     define SIG_OK (sig == SIGBUS || sig == SIGSEGV)
 #     define CODE_OK  TRUE  #     define CODE_OK  TRUE
 #   endif  #   endif
 # endif  # endif /* IRIX5 || OSF1 || HURD */
   
 # if defined(LINUX)  # if defined(LINUX)
 #   if defined(ALPHA) || defined(M68K)  #   if defined(ALPHA) || defined(M68K)
       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 2150  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2354  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
         /* Empirically c.trapno == 14, on IA32, but is that useful?     */          /* Empirically c.trapno == 14, on IA32, but is that useful?     */
         /* Should probably consider alignment issues on other           */          /* Should probably consider alignment issues on other           */
         /* architectures.                                               */          /* architectures.                                               */
 # endif  # endif /* LINUX */
   
 # if defined(SUNOS5SIGS)  # if defined(SUNOS5SIGS)
 #  ifdef __STDC__  #  ifdef __STDC__
     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 2171  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2376  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
 #     define SIG_OK (sig == SIGSEGV)  #     define SIG_OK (sig == SIGSEGV)
 #     define CODE_OK (scp -> si_code == SEGV_ACCERR)  #     define CODE_OK (scp -> si_code == SEGV_ACCERR)
 #   endif  #   endif
 # 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  
   
 # if defined(MSWIN32) || defined(MSWINCE)  # if defined(MSWIN32) || defined(MSWINCE)
     LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info)      LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info)
 #   define SIG_OK (exc_info -> ExceptionRecord -> ExceptionCode == \  #   define SIG_OK (exc_info -> ExceptionRecord -> ExceptionCode == \
                         STATUS_ACCESS_VIOLATION)                          STATUS_ACCESS_VIOLATION)
 #   define CODE_OK (exc_info -> ExceptionRecord -> ExceptionInformation[0] == 1)  #   define CODE_OK (exc_info -> ExceptionRecord -> ExceptionInformation[0] == 1)
                         /* Write fault */                          /* Write fault */
 # endif  # endif /* MSWIN32 || MSWINCE */
 {  {
     register unsigned i;      register unsigned i;
 #   if defined(HURD)  #   if defined(HURD)
Line 2201  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2400  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
         char * addr = (char *) (scp -> si_addr);          char * addr = (char *) (scp -> si_addr);
 #   endif  #   endif
 #   ifdef LINUX  #   ifdef LINUX
 #     ifdef I386  #     if defined(I386) || defined (X86_64)
         char * addr = (char *) (sc.cr2);          char * addr = (char *) (sc.cr2);
 #     else  #     else
 #       if defined(M68K)  #       if defined(M68K)
Line 2256  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2455  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
 #       endif  #       endif
 #     endif  #     endif
 #   endif  #   endif
 #   if defined(MACOSX)  
         char * addr = get_fault_addr(scp);  
 #   endif  
 #   if defined(MSWIN32) || defined(MSWINCE)  #   if defined(MSWIN32) || defined(MSWINCE)
         char * addr = (char *) (exc_info -> ExceptionRecord          char * addr = (char *) (exc_info -> ExceptionRecord
                                 -> ExceptionInformation[1]);                                  -> ExceptionInformation[1]);
Line 2322  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2518  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
                     (*(REAL_SIG_PF)old_handler) (sig, code, scp);                      (*(REAL_SIG_PF)old_handler) (sig, code, scp);
                     return;                      return;
 #               endif  #               endif
 #               ifdef MACOSX  
                     (*(REAL_SIG_PF)old_handler) (sig, code, scp);  
 #               endif  
 #               ifdef MSWIN32  #               ifdef MSWIN32
                     return((*old_handler)(exc_info));                      return((*old_handler)(exc_info));
 #               endif  #               endif
Line 2366  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2559  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
     ABORT("Unexpected bus error or segmentation fault");      ABORT("Unexpected bus error or segmentation fault");
 #endif  #endif
 }  }
   #endif /* !DARWIN */
   
 /*  /*
  * 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 2398  GC_bool is_ptrfree;
Line 2592  GC_bool is_ptrfree;
     UNPROTECT(h_trunc, (ptr_t)h_end - (ptr_t)h_trunc);      UNPROTECT(h_trunc, (ptr_t)h_end - (ptr_t)h_trunc);
 }  }
   
   #if !defined(DARWIN)
 void GC_dirty_init()  void GC_dirty_init()
 {  {
 #   if defined(SUNOS5SIGS) || defined(IRIX5) || defined(LINUX) || \  #   if defined(SUNOS5SIGS) || defined(IRIX5) || defined(LINUX) || \
Line 2420  void GC_dirty_init()
Line 2615  void GC_dirty_init()
         (void)sigaddset(&act.sa_mask, SIG_SUSPEND);          (void)sigaddset(&act.sa_mask, SIG_SUSPEND);
 #     endif /* SIG_SUSPEND */  #     endif /* SIG_SUSPEND */
 #    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  
 #   ifdef PRINTSTATS  #   ifdef PRINTSTATS
         GC_printf0("Inititalizing mprotect virtual dirty bit implementation\n");          GC_printf0("Inititalizing mprotect virtual dirty bit implementation\n");
 #   endif  #   endif
Line 2466  void GC_dirty_init()
Line 2654  void GC_dirty_init()
         sigaction(SIGSEGV, 0, &oldact);          sigaction(SIGSEGV, 0, &oldact);
         sigaction(SIGSEGV, &act, 0);          sigaction(SIGSEGV, &act, 0);
 #     else  #     else
         sigaction(SIGSEGV, &act, &oldact);          {
             int res = sigaction(SIGSEGV, &act, &oldact);
             if (res != 0) ABORT("Sigaction failed");
           }
 #     endif  #     endif
 #     if defined(_sigargs) || defined(HURD) || !defined(SA_SIGINFO)  #     if defined(_sigargs) || defined(HURD) || !defined(SA_SIGINFO)
         /* 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 2489  void GC_dirty_init()
Line 2680  void GC_dirty_init()
 #       endif  #       endif
       }        }
 #   endif  #   endif
 #   if defined(MACOSX) || defined(HPUX) || defined(LINUX) || defined(HURD)  #   if defined(HPUX) || defined(LINUX) || defined(HURD)
       sigaction(SIGBUS, &act, &oldact);        sigaction(SIGBUS, &act, &oldact);
       GC_old_bus_handler = oldact.sa_handler;        GC_old_bus_handler = oldact.sa_handler;
       if (GC_old_bus_handler == SIG_IGN) {        if (GC_old_bus_handler == SIG_IGN) {
Line 2501  void GC_dirty_init()
Line 2692  void GC_dirty_init()
           GC_err_printf0("Replaced other SIGBUS handler\n");            GC_err_printf0("Replaced other SIGBUS handler\n");
 #       endif  #       endif
       }        }
 #   endif /* MACOS || HPUX || LINUX */  #   endif /* HPUX || LINUX || HURD */
 #   if defined(MSWIN32)  #   if defined(MSWIN32)
       GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler);        GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler);
       if (GC_old_segv_handler != NULL) {        if (GC_old_segv_handler != NULL) {
Line 2513  void GC_dirty_init()
Line 2704  void GC_dirty_init()
       }        }
 #   endif  #   endif
 }  }
   #endif /* !DARWIN */
   
 int GC_incremental_protection_needs()  int GC_incremental_protection_needs()
 {  {
Line 2762  word n;
Line 2954  word n;
 {  {
 }  }
   
 # 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 */  # endif /* MPROTECT_VDB */
   
 # ifdef PROC_VDB  # ifdef PROC_VDB
Line 2847  void GC_dirty_init()
Line 3032  void GC_dirty_init()
     }      }
     GC_proc_fd = syscall(SYS_ioctl, fd, PIOCOPENPD, 0);      GC_proc_fd = syscall(SYS_ioctl, fd, PIOCOPENPD, 0);
     close(fd);      close(fd);
       syscall(SYS_fcntl, GC_proc_fd, F_SETFD, FD_CLOEXEC);
     if (GC_proc_fd < 0) {      if (GC_proc_fd < 0) {
         ABORT("/proc ioctl failed");          ABORT("/proc ioctl failed");
     }      }
Line 3086  GC_bool is_ptrfree;
Line 3272  GC_bool is_ptrfree;
   
 # endif /* PCR_VDB */  # 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  # ifndef HAVE_INCREMENTAL_PROTECTION_NEEDS
   int GC_incremental_protection_needs()    int GC_incremental_protection_needs()
   {    {
Line 3151  GC_bool is_ptrfree;
Line 3884  GC_bool is_ptrfree;
 /* callers.  Ignore my frame and my callers frame.                      */  /* callers.  Ignore my frame and my callers frame.                      */
   
 #ifdef LINUX  #ifdef LINUX
 # include <features.h>  
 # if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2  
 #   define HAVE_BUILTIN_BACKTRACE  
 #   ifdef IA64  
 #     define BUILTIN_BACKTRACE_BROKEN  
 #   endif  
 # endif  
 #endif  
   
 #include <execinfo.h>  
 #ifdef LINUX  
 #   include <unistd.h>  #   include <unistd.h>
 #endif  #endif
   
Line 3170  GC_bool is_ptrfree;
Line 3892  GC_bool is_ptrfree;
 #ifdef SAVE_CALL_CHAIN  #ifdef SAVE_CALL_CHAIN
   
 #if NARGS == 0 && NFRAMES % 2 == 0 /* No padding */ \  #if NARGS == 0 && NFRAMES % 2 == 0 /* No padding */ \
     && defined(HAVE_BUILTIN_BACKTRACE)      && defined(GC_HAVE_BUILTIN_BACKTRACE)
   
   #include <execinfo.h>
   
 void GC_save_callers (info)  void GC_save_callers (info)
 struct callinfo info[NFRAMES];  struct callinfo info[NFRAMES];
 {  {
Line 3214  struct callinfo info[NFRAMES];
Line 3938  struct callinfo info[NFRAMES];
     asm("movl %%ebp,%0" : "=r"(frame));      asm("movl %%ebp,%0" : "=r"(frame));
     fp = frame;      fp = frame;
 # else  # else
     word GC_save_regs_in_stack();  
   
     frame = (struct frame *) GC_save_regs_in_stack ();      frame = (struct frame *) GC_save_regs_in_stack ();
     fp = (struct frame *)((long) frame -> FR_SAVFP + BIAS);      fp = (struct frame *)((long) frame -> FR_SAVFP + BIAS);
 #endif  #endif
Line 3247  struct callinfo info[NFRAMES];
Line 3969  struct callinfo info[NFRAMES];
 {  {
     register int i;      register int i;
     static int reentry_count = 0;      static int reentry_count = 0;
       GC_bool stop = FALSE;
   
     LOCK();      LOCK();
       ++reentry_count;        ++reentry_count;
Line 3257  struct callinfo info[NFRAMES];
Line 3980  struct callinfo info[NFRAMES];
 #   else  #   else
       GC_err_printf0("\tCall chain at allocation:\n");        GC_err_printf0("\tCall chain at allocation:\n");
 #   endif  #   endif
     for (i = 0; i < NFRAMES; i++) {      for (i = 0; i < NFRAMES && !stop ; i++) {
         if (info[i].ci_pc == 0) break;          if (info[i].ci_pc == 0) break;
 #       if NARGS > 0  #       if NARGS > 0
         {          {
Line 3282  struct callinfo info[NFRAMES];
Line 4005  struct callinfo info[NFRAMES];
 #         ifdef LINUX  #         ifdef LINUX
             FILE *pipe;              FILE *pipe;
 #         endif  #         endif
 #         if defined(HAVE_BUILTIN_BACKTRACE) && \  #         if defined(GC_HAVE_BUILTIN_BACKTRACE)
              !defined(BUILTIN_BACKTRACE_BROKEN)  
             char **sym_name =              char **sym_name =
               backtrace_symbols((void **)(&(info[i].ci_pc)), 1);                backtrace_symbols((void **)(&(info[i].ci_pc)), 1);
             char *name = sym_name[0];              char *name = sym_name[0];
             GC_bool found_it = (strchr(name, '(') != 0);  
 #         else  #         else
             char buf[40];              char buf[40];
             char *name = buf;              char *name = buf;
             GC_bool fount_it = FALSE:  
             sprintf(buf, "##PC##= 0x%lx", info[i].ci_pc);              sprintf(buf, "##PC##= 0x%lx", info[i].ci_pc);
 #         endif  #         endif
 #         ifdef LINUX  #         if defined(LINUX) && !defined(SMALL_CONFIG)
             if (!found_it) {              /* Try for a line number. */
               {
 #               define EXE_SZ 100  #               define EXE_SZ 100
                 static char exe_name[EXE_SZ];                  static char exe_name[EXE_SZ];
 #               define CMD_SZ 200  #               define CMD_SZ 200
Line 3306  struct callinfo info[NFRAMES];
Line 4027  struct callinfo info[NFRAMES];
                 static GC_bool found_exe_name = FALSE;                  static GC_bool found_exe_name = FALSE;
                 static GC_bool will_fail = FALSE;                  static GC_bool will_fail = FALSE;
                 int ret_code;                  int ret_code;
                 /* Unfortunately, this is the common case for the       */  
                 /* main executable.                                     */  
                 /* Try to get it via a hairy and expensive scheme.      */                  /* Try to get it via a hairy and expensive scheme.      */
                 /* First we get the name of the executable:             */                  /* First we get the name of the executable:             */
                 if (will_fail) goto out;                  if (will_fail) goto out;
Line 3324  struct callinfo info[NFRAMES];
Line 4043  struct callinfo info[NFRAMES];
                 /* Then we use popen to start addr2line -e <exe> <addr> */                  /* Then we use popen to start addr2line -e <exe> <addr> */
                 /* There are faster ways to do this, but hopefully this */                  /* There are faster ways to do this, but hopefully this */
                 /* isn't time critical.                                 */                  /* isn't time critical.                                 */
                 sprintf(cmd_buf, "/usr/bin/addr2line -e %s 0x%lx", exe_name,                  sprintf(cmd_buf, "/usr/bin/addr2line -f -e %s 0x%lx", exe_name,
                                  (unsigned long)info[i].ci_pc);                                   (unsigned long)info[i].ci_pc);
                 pipe = popen(cmd_buf, "r");                  pipe = popen(cmd_buf, "r");
                 if (pipe < 0 || fgets(result_buf, RESULT_SZ, pipe) == 0) {                  if (pipe == NULL
                       || (result_len = fread(result_buf, 1, RESULT_SZ - 1, pipe))
                          == 0) {
                     if (pipe != NULL) pclose(pipe);
                   will_fail = TRUE;                    will_fail = TRUE;
                   goto out;                    goto out;
                 }                  }
                 result_len = strlen(result_buf);  
                 if (result_buf[result_len - 1] == '\n') --result_len;                  if (result_buf[result_len - 1] == '\n') --result_len;
                   result_buf[result_len] = 0;
                 if (result_buf[0] == '?'                  if (result_buf[0] == '?'
                     || result_buf[result_len-2] == ':'                      || result_buf[result_len-2] == ':'
                        && result_buf[result_len-1] == '0')                         && result_buf[result_len-1] == '0') {
                       pclose(pipe);
                     goto out;                      goto out;
                   }
                   /* Get rid of embedded newline, if any.  Test for "main" */
                   {
                      char * nl = strchr(result_buf, '\n');
                      if (nl != NULL && nl < result_buf + result_len) {
                        *nl = ':';
                      }
                      if (strncmp(result_buf, "main", nl - result_buf) == 0) {
                        stop = TRUE;
                      }
                   }
                 if (result_len < RESULT_SZ - 25) {                  if (result_len < RESULT_SZ - 25) {
                   /* Add in hex address */                    /* Add in hex address */
                     sprintf(result_buf + result_len, " [0x%lx]",                      sprintf(result_buf + result_len, " [0x%lx]",
Line 3344  struct callinfo info[NFRAMES];
Line 4078  struct callinfo info[NFRAMES];
                 }                  }
                 name = result_buf;                  name = result_buf;
                 pclose(pipe);                  pclose(pipe);
                 out:                  out:;
             }              }
 #         endif /* LINUX */  #         endif /* LINUX */
           GC_err_printf1("\t\t%s\n", name);            GC_err_printf1("\t\t%s\n", name);
           free(sym_name);  /* May call GC_free; that's OK */  #         if defined(GC_HAVE_BUILTIN_BACKTRACE)
               free(sym_name);  /* May call GC_free; that's OK */
   #         endif
         }          }
     }      }
     LOCK();      LOCK();
Line 3358  struct callinfo info[NFRAMES];
Line 4094  struct callinfo info[NFRAMES];
   
 #endif /* NEED_CALLINFO */  #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)  #if defined(LINUX) && defined(__ELF__) && !defined(SMALL_CONFIG)
   
 /* 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
    addresses in FIND_LEAK output. */     addresses in FIND_LEAK output. */
   
   static word dump_maps(char *maps)
   {
       GC_err_write(maps, strlen(maps));
       return 1;
   }
   
 void GC_print_address_map()  void GC_print_address_map()
 {  {
     int f;  
     int result;  
     char maps_temp[32768];  
     GC_err_printf0("---------- Begin address map ----------\n");      GC_err_printf0("---------- Begin address map ----------\n");
         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));  
   
     GC_err_printf0("---------- End address map ----------\n");      GC_err_printf0("---------- End address map ----------\n");
 }  }
   

Legend:
Removed from v.1.6  
changed lines
  Added in v.1.7

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>