Back to index

plt-scheme  4.2.1
dyn_load.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
00003  * Copyright (c) 1997 by Silicon Graphics.  All rights reserved.
00004  *
00005  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
00006  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
00007  *
00008  * Permission is hereby granted to use or copy this program
00009  * for any purpose,  provided the above notices are retained on all copies.
00010  * Permission to modify the code and to distribute modified code is granted,
00011  * provided the above notices are retained, and a notice that the code was
00012  * modified is included with the above copyright notice.
00013  *
00014  * Original author: Bill Janssen
00015  * Heavily modified by Hans Boehm and others
00016  */
00017 
00018 /*
00019  * This is incredibly OS specific code for tracking down data sections in
00020  * dynamic libraries.  There appears to be no way of doing this quickly
00021  * without groveling through undocumented data structures.  We would argue
00022  * that this is a bug in the design of the dlopen interface.  THIS CODE
00023  * MAY BREAK IN FUTURE OS RELEASES.  If this matters to you, don't hesitate
00024  * to let your vendor know ...
00025  *
00026  * None of this is safe with dlclose and incremental collection.
00027  * But then not much of anything is safe in the presence of dlclose.
00028  */
00029 #if defined(__linux__) && !defined(_GNU_SOURCE)
00030     /* Can't test LINUX, since this must be define before other includes */
00031 #   define _GNU_SOURCE
00032 #endif
00033 #if !defined(MACOS) && !defined(_WIN32_WCE)
00034 #  include <sys/types.h>
00035 #endif
00036 #include "private/gc_priv.h"
00037 
00038 /* BTL: avoid circular redefinition of dlopen if GC_SOLARIS_THREADS defined */
00039 # if (defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS)) \
00040       && defined(dlopen) && !defined(GC_USE_LD_WRAP)
00041     /* To support threads in Solaris, gc.h interposes on dlopen by       */
00042     /* defining "dlopen" to be "GC_dlopen", which is implemented below.  */
00043     /* However, both GC_FirstDLOpenedLinkMap() and GC_dlopen() use the   */
00044     /* real system dlopen() in their implementation. We first remove     */
00045     /* gc.h's dlopen definition and restore it later, after GC_dlopen(). */
00046 #   undef dlopen
00047 #   define GC_must_restore_redefined_dlopen
00048 # else
00049 #   undef GC_must_restore_redefined_dlopen
00050 # endif
00051 
00052 /* PLTSCHEME: added OPENBSD: */
00053 #if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE)) \
00054     && !defined(PCR)
00055 #if !defined(SUNOS4) && !defined(SUNOS5DL) && !defined(IRIX5) && \
00056     !defined(MSWIN32) && !defined(MSWINCE) && \
00057     !(defined(ALPHA) && defined(OSF1)) && \
00058     !defined(HPUX) && !(defined(LINUX) && defined(__ELF__)) && \
00059     !defined(RS6000) && !defined(SCO_ELF) && !defined(DGUX) && \
00060     !(defined(FREEBSD) && defined(__ELF__)) && \
00061     !(defined(OPENBSD) && defined(__ELF__)) && \
00062     !(defined(NETBSD) && defined(__ELF__)) && !defined(HURD) && \
00063     !defined(DARWIN)
00064  --> We only know how to find data segments of dynamic libraries for the
00065  --> above.  Additional SVR4 variants might not be too
00066  --> hard to add.
00067 #endif
00068 
00069 #include <stdio.h>
00070 #ifdef SUNOS5DL
00071 #   include <sys/elf.h>
00072 #   include <dlfcn.h>
00073 #   include <link.h>
00074 #endif
00075 #ifdef SUNOS4
00076 #   include <dlfcn.h>
00077 #   include <link.h>
00078 #   include <a.out.h>
00079   /* struct link_map field overrides */
00080 #   define l_next    lm_next
00081 #   define l_addr    lm_addr
00082 #   define l_name    lm_name
00083 #endif
00084 
00085 #if defined(NETBSD)
00086 #   include <machine/elf_machdep.h>
00087 #   define ELFSIZE ARCH_ELFSIZE
00088 #endif
00089 
00090 #if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
00091     (defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \
00092     (defined(NETBSD) && defined(__ELF__)) || defined(HURD)
00093 #   include <stddef.h>
00094 #   include <elf.h>
00095 #   include <link.h>
00096 #endif
00097 
00098 /* Newer versions of GNU/Linux define this macro.  We
00099  * define it similarly for any ELF systems that don't.  */
00100 #  ifndef ElfW
00101 #    if defined(FREEBSD)
00102 #      if __ELF_WORD_SIZE == 32
00103 #        define ElfW(type) Elf32_##type
00104 #      else
00105 #        define ElfW(type) Elf64_##type
00106 #      endif
00107 #    else
00108 #      ifdef NETBSD
00109 #        if ELFSIZE == 32
00110 #          define ElfW(type) Elf32_##type
00111 #        else
00112 #          define ElfW(type) Elf64_##type
00113 #        endif
00114 #      else
00115 #        if !defined(ELF_CLASS) || ELF_CLASS == ELFCLASS32
00116 #          define ElfW(type) Elf32_##type
00117 #        else
00118 #          define ElfW(type) Elf64_##type
00119 #       endif
00120 #      endif
00121 #    endif
00122 #  endif
00123 
00124 #if defined(SUNOS5DL) && !defined(USE_PROC_FOR_LIBRARIES)
00125 
00126 #ifdef LINT
00127     Elf32_Dyn _DYNAMIC;
00128 #endif
00129 
00130 static struct link_map *
00131 GC_FirstDLOpenedLinkMap()
00132 {
00133     extern ElfW(Dyn) _DYNAMIC;
00134     ElfW(Dyn) *dp;
00135     struct r_debug *r;
00136     static struct link_map * cachedResult = 0;
00137     static ElfW(Dyn) *dynStructureAddr = 0;
00138                      /* BTL: added to avoid Solaris 5.3 ld.so _DYNAMIC bug */
00139 
00140 #   ifdef SUNOS53_SHARED_LIB
00141        /* BTL: Avoid the Solaris 5.3 bug that _DYNAMIC isn't being set       */
00142        /* up properly in dynamically linked .so's. This means we have */
00143        /* to use its value in the set of original object files loaded */
00144        /* at program startup.                                         */
00145        if( dynStructureAddr == 0 ) {
00146          void* startupSyms = dlopen(0, RTLD_LAZY);
00147          dynStructureAddr = (ElfW(Dyn)*)dlsym(startupSyms, "_DYNAMIC");
00148               }
00149 #   else
00150        dynStructureAddr = &_DYNAMIC;
00151 #   endif
00152 
00153     if( dynStructureAddr == 0) {
00154         return(0);
00155     }
00156     if( cachedResult == 0 ) {
00157         int tag;
00158         for( dp = ((ElfW(Dyn) *)(&_DYNAMIC)); (tag = dp->d_tag) != 0; dp++ ) {
00159             if( tag == DT_DEBUG ) {
00160                 struct link_map *lm
00161                         = ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
00162                 if( lm != 0 ) cachedResult = lm->l_next; /* might be NIL */
00163                 break;
00164             }
00165         }
00166     }
00167     return cachedResult;
00168 }
00169 
00170 #endif /* SUNOS5DL ... */
00171 
00172 /* BTL: added to fix circular dlopen definition if GC_SOLARIS_THREADS defined */
00173 # if defined(GC_must_restore_redefined_dlopen)
00174 #   define dlopen GC_dlopen
00175 # endif
00176 
00177 #if defined(SUNOS4) && !defined(USE_PROC_FOR_LIBRARIES)
00178 
00179 #ifdef LINT
00180     struct link_dynamic _DYNAMIC;
00181 #endif
00182 
00183 static struct link_map *
00184 GC_FirstDLOpenedLinkMap()
00185 {
00186     extern struct link_dynamic _DYNAMIC;
00187 
00188     if( &_DYNAMIC == 0) {
00189         return(0);
00190     }
00191     return(_DYNAMIC.ld_un.ld_1->ld_loaded);
00192 }
00193 
00194 /* Return the address of the ld.so allocated common symbol     */
00195 /* with the least address, or 0 if none.                */
00196 static ptr_t GC_first_common()
00197 {
00198     ptr_t result = 0;
00199     extern struct link_dynamic _DYNAMIC;
00200     struct rtc_symb * curr_symbol;
00201     
00202     if( &_DYNAMIC == 0) {
00203         return(0);
00204     }
00205     curr_symbol = _DYNAMIC.ldd -> ldd_cp;
00206     for (; curr_symbol != 0; curr_symbol = curr_symbol -> rtc_next) {
00207         if (result == 0
00208             || (ptr_t)(curr_symbol -> rtc_sp -> n_value) < result) {
00209             result = (ptr_t)(curr_symbol -> rtc_sp -> n_value);
00210         }
00211     }
00212     return(result);
00213 }
00214 
00215 #endif  /* SUNOS4 ... */
00216 
00217 # if defined(SUNOS4) || defined(SUNOS5DL)
00218 /* Add dynamic library data sections to the root set.          */
00219 # if !defined(PCR) && !defined(GC_SOLARIS_THREADS) && defined(THREADS)
00220 #   ifndef SRC_M3
00221        --> fix mutual exclusion with dlopen
00222 #   endif  /* We assume M3 programs don't call dlopen for now */
00223 # endif
00224 
00225 # ifndef USE_PROC_FOR_LIBRARIES
00226 void GC_register_dynamic_libraries()
00227 {
00228   struct link_map *lm = GC_FirstDLOpenedLinkMap();
00229   
00230 
00231   for (lm = GC_FirstDLOpenedLinkMap();
00232        lm != (struct link_map *) 0;  lm = lm->l_next)
00233     {
00234 #     ifdef SUNOS4
00235        struct exec *e;
00236         
00237         e = (struct exec *) lm->lm_addr;
00238         GC_add_roots_inner(
00239                   ((char *) (N_DATOFF(*e) + lm->lm_addr)),
00240                   ((char *) (N_BSSADDR(*e) + e->a_bss + lm->lm_addr)),
00241                   TRUE);
00242 #     endif
00243 #     ifdef SUNOS5DL
00244        ElfW(Ehdr) * e;
00245         ElfW(Phdr) * p;
00246         unsigned long offset;
00247         char * start;
00248         register int i;
00249         
00250        e = (ElfW(Ehdr) *) lm->l_addr;
00251         p = ((ElfW(Phdr) *)(((char *)(e)) + e->e_phoff));
00252         offset = ((unsigned long)(lm->l_addr));
00253         for( i = 0; i < (int)(e->e_phnum); ((i++),(p++)) ) {
00254           switch( p->p_type ) {
00255             case PT_LOAD:
00256               {
00257                 if( !(p->p_flags & PF_W) ) break;
00258                 start = ((char *)(p->p_vaddr)) + offset;
00259                 GC_add_roots_inner(
00260                   start,
00261                   start + p->p_memsz,
00262                   TRUE
00263                 );
00264               }
00265               break;
00266             default:
00267               break;
00268           }
00269        }
00270 #     endif
00271     }
00272 #   ifdef SUNOS4
00273       {
00274        static ptr_t common_start = 0;
00275        ptr_t common_end;
00276        extern ptr_t GC_find_limit();
00277        
00278        if (common_start == 0) common_start = GC_first_common();
00279        if (common_start != 0) {
00280            common_end = GC_find_limit(common_start, TRUE);
00281            GC_add_roots_inner((char *)common_start, (char *)common_end, TRUE);
00282        }
00283       }
00284 #   endif
00285 }
00286 
00287 # endif /* !USE_PROC ... */
00288 # endif /* SUNOS */
00289 
00290 /* PLTSCHEME: added OPENBSD: */
00291 #if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
00292     (defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \
00293     (defined(OPENBSD) && defined(__ELF__)) || \
00294     (defined(NETBSD) && defined(__ELF__)) || defined(HURD)
00295 
00296 
00297 #ifdef USE_PROC_FOR_LIBRARIES
00298 
00299 #include <string.h>
00300 
00301 #include <sys/stat.h>
00302 #include <fcntl.h>
00303 #include <unistd.h>
00304 
00305 #define MAPS_BUF_SIZE (32*1024)
00306 
00307 extern ssize_t GC_repeat_read(int fd, char *buf, size_t count);
00308        /* Repeatedly read until buffer is filled, or EOF is encountered */
00309        /* Defined in os_dep.c.                                  */
00310 
00311 char *GC_parse_map_entry(char *buf_ptr, word *start, word *end,
00312                          char *prot_buf, unsigned int *maj_dev);
00313 word GC_apply_to_maps(word (*fn)(char *));
00314        /* From os_dep.c     */
00315 
00316 word GC_register_map_entries(char *maps)
00317 {
00318     char prot_buf[5];
00319     char *buf_ptr = maps;
00320     int count;
00321     word start, end;
00322     unsigned int maj_dev;
00323     word least_ha, greatest_ha;
00324     unsigned i;
00325     word datastart = (word)(DATASTART);
00326 
00327     /* Compute heap bounds. FIXME: Should be done by add_to_heap?     */
00328        least_ha = (word)(-1);
00329        greatest_ha = 0;
00330        for (i = 0; i < GC_n_heap_sects; ++i) {
00331            word sect_start = (word)GC_heap_sects[i].hs_start;
00332            word sect_end = sect_start + GC_heap_sects[i].hs_bytes;
00333            if (sect_start < least_ha) least_ha = sect_start;
00334            if (sect_end > greatest_ha) greatest_ha = sect_end;
00335         }
00336        if (greatest_ha < (word)GC_scratch_last_end_ptr)
00337            greatest_ha = (word)GC_scratch_last_end_ptr; 
00338 
00339     for (;;) {
00340         buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, prot_buf, &maj_dev);
00341        if (buf_ptr == NULL) return 1;
00342        if (prot_buf[1] == 'w') {
00343            /* This is a writable mapping.  Add it to           */
00344            /* the root set unless it is already otherwise      */
00345            /* accounted for.                                   */
00346            if (start <= (word)GC_stackbottom && end >= (word)GC_stackbottom) {
00347               /* Stack mapping; discard   */
00348               continue;
00349            }
00350 #          ifdef THREADS
00351              if (GC_segment_is_thread_stack(start, end)) continue;
00352 #          endif
00353            /* We no longer exclude the main data segment.             */
00354            if (start < least_ha && end > least_ha) {
00355               end = least_ha;
00356            }
00357            if (start < greatest_ha && end > greatest_ha) {
00358               start = greatest_ha;
00359            }
00360            if (start >= least_ha && end <= greatest_ha) continue;
00361            GC_add_roots_inner((char *)start, (char *)end, TRUE);
00362        }
00363     }
00364     return 1;
00365 }
00366 
00367 void GC_register_dynamic_libraries()
00368 {
00369    if (!GC_apply_to_maps(GC_register_map_entries))
00370        ABORT("Failed to read /proc for library registration.");
00371 }
00372 
00373 /* We now take care of the main data segment ourselves: */
00374 GC_bool GC_register_main_static_data()
00375 {
00376   return FALSE;
00377 }
00378   
00379 # define HAVE_REGISTER_MAIN_STATIC_DATA
00380 
00381 #endif /* USE_PROC_FOR_LIBRARIES */
00382 
00383 #if !defined(USE_PROC_FOR_LIBRARIES)
00384 /* The following is the preferred way to walk dynamic libraries       */
00385 /* For glibc 2.2.4+.  Unfortunately, it doesn't work for older */
00386 /* versions.  Thanks to Jakub Jelinek for most of the code.    */
00387 
00388 # if defined(LINUX) /* Are others OK here, too? */ \
00389      && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) \
00390          || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && defined(DT_CONFIG))) 
00391 
00392 /* We have the header files for a glibc that includes dl_iterate_phdr.       */
00393 /* It may still not be available in the library on the target system.   */
00394 /* Thus we also treat it as a weak symbol.                            */
00395 #define HAVE_DL_ITERATE_PHDR
00396 
00397 static int GC_register_dynlib_callback(info, size, ptr)
00398      struct dl_phdr_info * info;
00399      size_t size;
00400      void * ptr;
00401 {
00402   const ElfW(Phdr) * p;
00403   char * start;
00404   register int i;
00405 
00406   /* Make sure struct dl_phdr_info is at least as big as we need.  */
00407   if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
00408       + sizeof (info->dlpi_phnum))
00409     return -1;
00410 
00411   p = info->dlpi_phdr;
00412   for( i = 0; i < (int)(info->dlpi_phnum); ((i++),(p++)) ) {
00413     switch( p->p_type ) {
00414       case PT_LOAD:
00415        {
00416          if( !(p->p_flags & PF_W) ) break;
00417          start = ((char *)(p->p_vaddr)) + info->dlpi_addr;
00418          GC_add_roots_inner(start, start + p->p_memsz, TRUE);
00419        }
00420       break;
00421       default:
00422        break;
00423     }
00424   }
00425 
00426   * (int *)ptr = 1;  /* Signal that we were called */
00427   return 0;
00428 }     
00429 
00430 /* Return TRUE if we succeed, FALSE if dl_iterate_phdr wasn't there. */
00431 
00432 #pragma weak dl_iterate_phdr
00433 
00434 GC_bool GC_register_dynamic_libraries_dl_iterate_phdr()
00435 {
00436   if (dl_iterate_phdr) {
00437     int did_something = 0;
00438     dl_iterate_phdr(GC_register_dynlib_callback, &did_something);
00439     if (!did_something) {
00440        /* dl_iterate_phdr may forget the static data segment in       */
00441        /* statically linked executables.                       */
00442        GC_add_roots_inner(DATASTART, (char *)(DATAEND), TRUE);
00443 #       if defined(DATASTART2)
00444           GC_add_roots_inner(DATASTART2, (char *)(DATAEND2), TRUE);
00445 #       endif
00446     }
00447 
00448     return TRUE;
00449   } else {
00450     return FALSE;
00451   }
00452 }
00453 
00454 /* Do we need to separately register the main static data segment? */
00455 GC_bool GC_register_main_static_data()
00456 {
00457   return (dl_iterate_phdr == 0);
00458 }
00459 
00460 #define HAVE_REGISTER_MAIN_STATIC_DATA
00461 
00462 # else /* !LINUX || version(glibc) < 2.2.4 */
00463 
00464 /* Dynamic loading code for Linux running ELF. Somewhat tested on
00465  * Linux/x86, untested but hopefully should work on Linux/Alpha. 
00466  * This code was derived from the Solaris/ELF support. Thanks to
00467  * whatever kind soul wrote that.  - Patrick Bridges */
00468 
00469 /* This doesn't necessarily work in all cases, e.g. with preloaded
00470  * dynamic libraries.                                          */
00471 
00472 #if defined(NETBSD)
00473 #  include <sys/exec_elf.h>
00474 /* for compatibility with 1.4.x */
00475 #  ifndef DT_DEBUG
00476 #  define DT_DEBUG     21
00477 #  endif
00478 #  ifndef PT_LOAD
00479 #  define PT_LOAD      1
00480 #  endif
00481 #  ifndef PF_W
00482 #  define PF_W         2
00483 #  endif
00484 /* PLTSCHEME: OPENBSD */
00485 #elif defined(OPENBSD)
00486 #   include <link_elf.h>
00487 #else
00488 #  include <elf.h>
00489 #endif
00490 #include <link.h>
00491 
00492 # endif
00493 
00494 #ifdef __GNUC__
00495 # pragma weak _DYNAMIC
00496 #endif
00497 
00498 /* PLTSCHEME: ifndef OPENBSD */
00499 #ifndef OPENBSD
00500 extern ElfW(Dyn) _DYNAMIC[];
00501 #endif
00502 
00503 static struct link_map *
00504 GC_FirstDLOpenedLinkMap()
00505 {
00506     ElfW(Dyn) *dp;
00507     static struct link_map *cachedResult = 0;
00508 
00509     if( _DYNAMIC == 0) {
00510         return(0);
00511     }
00512     if( cachedResult == 0 ) {
00513         int tag;
00514         for( dp = _DYNAMIC; (tag = dp->d_tag) != 0; dp++ ) {
00515            /* FIXME: The DT_DEBUG header is not mandated by the       */
00516            /* ELF spec.  This code appears to be dependent on         */
00517            /* idiosynchracies of older GNU tool chains.  If this code */
00518            /* fails for you, the real problem is probably that it is  */
00519            /* being used at all.  You should be getting the           */
00520            /* dl_iterate_phdr version.                                */
00521             if( tag == DT_DEBUG ) {
00522                 struct link_map *lm
00523                         = ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
00524                 if( lm != 0 ) cachedResult = lm->l_next; /* might be NIL */
00525                 break;
00526             }
00527         }
00528     }
00529     return cachedResult;
00530 }
00531 
00532 
00533 void GC_register_dynamic_libraries()
00534 {
00535   struct link_map *lm;
00536   
00537 
00538 # ifdef HAVE_DL_ITERATE_PHDR
00539     if (GC_register_dynamic_libraries_dl_iterate_phdr()) {
00540        return;
00541     }
00542 # endif
00543   lm = GC_FirstDLOpenedLinkMap();
00544   for (lm = GC_FirstDLOpenedLinkMap();
00545        lm != (struct link_map *) 0;  lm = lm->l_next)
00546     {
00547        ElfW(Ehdr) * e;
00548         ElfW(Phdr) * p;
00549         unsigned long offset;
00550         char * start;
00551         register int i;
00552         
00553        e = (ElfW(Ehdr) *) lm->l_addr;
00554         p = ((ElfW(Phdr) *)(((char *)(e)) + e->e_phoff));
00555         offset = ((unsigned long)(lm->l_addr));
00556         for( i = 0; i < (int)(e->e_phnum); ((i++),(p++)) ) {
00557           switch( p->p_type ) {
00558             case PT_LOAD:
00559               {
00560                 if( !(p->p_flags & PF_W) ) break;
00561                 start = ((char *)(p->p_vaddr)) + offset;
00562                 GC_add_roots_inner(start, start + p->p_memsz, TRUE);
00563               }
00564               break;
00565             default:
00566               break;
00567           }
00568        }
00569     }
00570 }
00571 
00572 #endif /* !USE_PROC_FOR_LIBRARIES */
00573 
00574 #endif /* LINUX */
00575 
00576 #if defined(IRIX5) || (defined(USE_PROC_FOR_LIBRARIES) && !defined(LINUX))
00577 
00578 #include <sys/procfs.h>
00579 #include <sys/stat.h>
00580 #include <fcntl.h>
00581 #include <elf.h>
00582 #include <errno.h>
00583 #include <signal.h>  /* Only for the following test. */
00584 #ifndef _sigargs
00585 # define IRIX6
00586 #endif
00587 
00588 extern void * GC_roots_present();
00589        /* The type is a lie, since the real type doesn't make sense here, */
00590        /* and we only test for NULL.                                     */
00591 
00592 
00593 /* We use /proc to track down all parts of the address space that are */
00594 /* mapped by the process, and throw out regions we know we shouldn't  */
00595 /* worry about.  This may also work under other SVR4 variants.        */
00596 void GC_register_dynamic_libraries()
00597 {
00598     static int fd = -1;
00599     char buf[30];
00600     static prmap_t * addr_map = 0;
00601     static int current_sz = 0;     /* Number of records currently in addr_map */
00602     static int needed_sz;   /* Required size of addr_map              */
00603     register int i;
00604     register long flags;
00605     register ptr_t start;
00606     register ptr_t limit;
00607     ptr_t heap_start = (ptr_t)HEAP_START;
00608     ptr_t heap_end = heap_start;
00609 
00610 #   ifdef SUNOS5DL
00611 #     define MA_PHYS 0
00612 #   endif /* SUNOS5DL */
00613 
00614     if (fd < 0) {
00615       sprintf(buf, "/proc/%d", getpid());
00616        /* The above generates a lint complaint, since pid_t varies.   */
00617        /* It's unclear how to improve this.                           */
00618       fd = open(buf, O_RDONLY);
00619       if (fd < 0) {
00620        ABORT("/proc open failed");
00621       }
00622     }
00623     if (ioctl(fd, PIOCNMAP, &needed_sz) < 0) {
00624        GC_err_printf2("fd = %d, errno = %d\n", fd, errno);
00625        ABORT("/proc PIOCNMAP ioctl failed");
00626     }
00627     if (needed_sz >= current_sz) {
00628         current_sz = needed_sz * 2 + 1;
00629                      /* Expansion, plus room for 0 record */
00630         addr_map = (prmap_t *)GC_scratch_alloc((word)
00631                                           (current_sz * sizeof(prmap_t)));
00632     }
00633     if (ioctl(fd, PIOCMAP, addr_map) < 0) {
00634         GC_err_printf4("fd = %d, errno = %d, needed_sz = %d, addr_map = 0x%X\n",
00635                         fd, errno, needed_sz, addr_map);
00636        ABORT("/proc PIOCMAP ioctl failed");
00637     };
00638     if (GC_n_heap_sects > 0) {
00639        heap_end = GC_heap_sects[GC_n_heap_sects-1].hs_start
00640                      + GC_heap_sects[GC_n_heap_sects-1].hs_bytes;
00641        if (heap_end < GC_scratch_last_end_ptr) heap_end = GC_scratch_last_end_ptr; 
00642     }
00643     for (i = 0; i < needed_sz; i++) {
00644         flags = addr_map[i].pr_mflags;
00645         if ((flags & (MA_BREAK | MA_STACK | MA_PHYS
00646                     | MA_FETCHOP | MA_NOTCACHED)) != 0) goto irrelevant;
00647         if ((flags & (MA_READ | MA_WRITE)) != (MA_READ | MA_WRITE))
00648             goto irrelevant;
00649           /* The latter test is empirically useless in very old Irix  */
00650          /* versions.  Other than the                                 */
00651           /* main data and stack segments, everything appears to be   */
00652           /* mapped readable, writable, executable, and shared(!!).   */
00653           /* This makes no sense to me.   - HB                        */
00654         start = (ptr_t)(addr_map[i].pr_vaddr);
00655         if (GC_roots_present(start)) goto irrelevant;
00656         if (start < heap_end && start >= heap_start)
00657               goto irrelevant;
00658 #      ifdef MMAP_STACKS
00659          if (GC_is_thread_stack(start)) goto irrelevant;
00660 #      endif /* MMAP_STACKS */
00661 
00662         limit = start + addr_map[i].pr_size;
00663        /* The following seemed to be necessary for very old versions  */
00664        /* of Irix, but it has been reported to discard relevant       */
00665        /* segments under Irix 6.5.                                    */
00666 #      ifndef IRIX6
00667          if (addr_map[i].pr_off == 0 && strncmp(start, ELFMAG, 4) == 0) {
00668            /* Discard text segments, i.e. 0-offset mappings against   */
00669            /* executable files which appear to have ELF headers.      */
00670            caddr_t arg;
00671            int obj;
00672 #          define MAP_IRR_SZ 10
00673            static ptr_t map_irr[MAP_IRR_SZ];
00674                                    /* Known irrelevant map entries    */
00675            static int n_irr = 0;
00676            struct stat buf;
00677            register int i;
00678            
00679            for (i = 0; i < n_irr; i++) {
00680                if (map_irr[i] == start) goto irrelevant;
00681            }
00682            arg = (caddr_t)start;
00683            obj = ioctl(fd, PIOCOPENM, &arg);
00684            if (obj >= 0) {
00685                fstat(obj, &buf);
00686                close(obj);
00687                if ((buf.st_mode & 0111) != 0) {
00688                    if (n_irr < MAP_IRR_SZ) {
00689                        map_irr[n_irr++] = start;
00690                    }
00691                    goto irrelevant;
00692                }
00693            }
00694          }
00695 #      endif /* !IRIX6 */
00696         GC_add_roots_inner(start, limit, TRUE);
00697       irrelevant: ;
00698     }
00699     /* Dont keep cached descriptor, for now.  Some kernels don't like us */
00700     /* to keep a /proc file descriptor around during kill -9.          */
00701        if (close(fd) < 0) ABORT("Couldnt close /proc file");
00702        fd = -1;
00703 }
00704 
00705 # endif /* USE_PROC || IRIX5 */
00706 
00707 # if defined(MSWIN32) || defined(MSWINCE)
00708 
00709 # define WIN32_LEAN_AND_MEAN
00710 # define NOSERVICE
00711 # include <windows.h>
00712 # include <stdlib.h>
00713 
00714   /* We traverse the entire address space and register all segments   */
00715   /* that could possibly have been written to.                        */
00716   
00717   extern GC_bool GC_is_heap_base (ptr_t p);
00718 
00719 # ifdef GC_WIN32_THREADS
00720     extern void GC_get_next_stack(char *start, char **lo, char **hi);
00721     void GC_cond_add_roots(char *base, char * limit)
00722     {
00723       char * curr_base = base;
00724       char * next_stack_lo;
00725       char * next_stack_hi;
00726    
00727       if (base == limit) return;
00728       for(;;) {
00729          GC_get_next_stack(curr_base, &next_stack_lo, &next_stack_hi);
00730          if (next_stack_lo >= limit) break;
00731          GC_add_roots_inner(curr_base, next_stack_lo, TRUE);
00732          curr_base = next_stack_hi;
00733       }
00734       if (curr_base < limit) GC_add_roots_inner(curr_base, limit, TRUE);
00735     }
00736 # else
00737     void GC_cond_add_roots(char *base, char * limit)
00738     {
00739       char dummy;
00740       char * stack_top
00741         = (char *) ((word)(&dummy) & ~(GC_sysinfo.dwAllocationGranularity-1));
00742       if (base == limit) return;
00743       if (limit > stack_top && base < GC_stackbottom) {
00744          /* Part of the stack; ignore it. */
00745          return;
00746       }
00747       GC_add_roots_inner(base, limit, TRUE);
00748     }
00749 # endif
00750 
00751 # ifdef MSWINCE
00752   /* Do we need to separately register the main static data segment? */
00753   GC_bool GC_register_main_static_data()
00754   {
00755     return FALSE;
00756   }
00757 # else /* win32 */
00758   extern GC_bool GC_no_win32_dlls;
00759 
00760   GC_bool GC_register_main_static_data()
00761   {
00762     return GC_no_win32_dlls;
00763   }
00764 # endif /* win32 */
00765   
00766 # define HAVE_REGISTER_MAIN_STATIC_DATA
00767 
00768   /* The frame buffer testing code is dead in this version.    */
00769   /* We leave it here temporarily in case the switch to just   */
00770   /* testing for MEM_IMAGE sections causes un expected         */
00771   /* problems.                                                 */
00772   GC_bool GC_warn_fb = TRUE;       /* Warn about traced likely        */
00773                             /* graphics memory.         */
00774   GC_bool GC_disallow_ignore_fb = FALSE;
00775   int GC_ignore_fb_mb;      /* Ignore mappings bigger than the        */
00776                      /* specified number of MB.         */
00777   GC_bool GC_ignore_fb = FALSE; /* Enable frame buffer  */
00778                             /* checking.         */
00779   
00780   /* Issue warning if tracing apparent framebuffer.            */
00781   /* This limits us to one warning, and it's a back door to    */
00782   /* disable that.                                      */
00783  
00784   /* Should [start, start+len) be treated as a frame buffer    */
00785   /* and ignored?                                       */
00786   /* Unfortunately, we currently are not quite sure how to tell       */
00787   /* this automatically, and rely largely on user input.       */
00788   /* We expect that any mapping with type MEM_MAPPED (which    */
00789   /* apparently excludes library data sections) can be safely  */
00790   /* ignored.  But we're too completely remove this code in    */
00791   /* this version.                                      */
00792   /* Based on a very limited sample, it appears that:          */
00793   /*   - Frame buffer mappings appear as mappings of large     */
00794   /*     length, usually a bit less than a power of two.       */
00795   /*   - The definition of "a bit less" in the above cannot    */
00796   /*     be made more precise.                                 */
00797   /*   - Have a starting address at best 64K aligned.          */
00798   /*   - Have type == MEM_MAPPED.                       */
00799   static GC_bool is_frame_buffer(ptr_t start, size_t len, DWORD tp)
00800   {
00801     static GC_bool initialized = FALSE;
00802 #   define MB (1024*1024)
00803 #   define DEFAULT_FB_MB 15
00804 #   define MIN_FB_MB 3
00805 
00806     if (GC_disallow_ignore_fb || tp != MEM_MAPPED) return FALSE;
00807     if (!initialized) {
00808       char * ignore_fb_string =  GETENV("GC_IGNORE_FB");
00809 
00810       if (0 != ignore_fb_string) {
00811        while (*ignore_fb_string == ' ' || *ignore_fb_string == '\t')
00812          ++ignore_fb_string;
00813        if (*ignore_fb_string == '\0') {
00814          GC_ignore_fb_mb = DEFAULT_FB_MB;
00815        } else {
00816          GC_ignore_fb_mb = atoi(ignore_fb_string);
00817          if (GC_ignore_fb_mb < MIN_FB_MB) {
00818            WARN("Bad GC_IGNORE_FB value.  Using %ld\n", DEFAULT_FB_MB);
00819            GC_ignore_fb_mb = DEFAULT_FB_MB;
00820          }
00821        }
00822        GC_ignore_fb = TRUE;
00823       } else {
00824        GC_ignore_fb_mb = DEFAULT_FB_MB;  /* For warning */
00825       }
00826       initialized = TRUE;
00827     }
00828     if (len >= ((size_t)GC_ignore_fb_mb << 20)) {
00829       if (GC_ignore_fb) {
00830        return TRUE;
00831       } else {
00832        if (GC_warn_fb) {
00833          WARN("Possible frame buffer mapping at 0x%lx: \n"
00834               "\tConsider setting GC_IGNORE_FB to improve performance.\n",
00835               start);
00836          GC_warn_fb = FALSE;
00837        }
00838        return FALSE;
00839       }
00840     } else {
00841       return FALSE;
00842     }
00843   }
00844 
00845 # ifdef DEBUG_VIRTUALQUERY
00846   void GC_dump_meminfo(MEMORY_BASIC_INFORMATION *buf)
00847   {
00848     GC_printf4("BaseAddress = %lx, AllocationBase = %lx, RegionSize = %lx(%lu)\n",
00849               buf -> BaseAddress, buf -> AllocationBase, buf -> RegionSize,
00850               buf -> RegionSize);
00851     GC_printf4("\tAllocationProtect = %lx, State = %lx, Protect = %lx, "
00852               "Type = %lx\n",
00853               buf -> AllocationProtect, buf -> State, buf -> Protect,
00854               buf -> Type);
00855   }
00856 # endif /* DEBUG_VIRTUALQUERY */
00857 
00858   extern GC_bool GC_wnt;  /* Is Windows NT derivative.         */
00859                        /* Defined and set in os_dep.c.  */
00860 
00861   void GC_register_dynamic_libraries()
00862   {
00863     MEMORY_BASIC_INFORMATION buf;
00864     DWORD result;
00865     DWORD protect;
00866     LPVOID p;
00867     char * base;
00868     char * limit, * new_limit;
00869 
00870 #   ifdef MSWIN32
00871       if (GC_no_win32_dlls) return;
00872 #   endif
00873     base = limit = p = GC_sysinfo.lpMinimumApplicationAddress;
00874 #   if defined(MSWINCE) && !defined(_WIN32_WCE_EMULATION)
00875     /* Only the first 32 MB of address space belongs to the current process */
00876     while (p < (LPVOID)0x02000000) {
00877         result = VirtualQuery(p, &buf, sizeof(buf));
00878        if (result == 0) {
00879            /* Page is free; advance to the next possible allocation base */
00880            new_limit = (char *)
00881               (((DWORD) p + GC_sysinfo.dwAllocationGranularity)
00882                & ~(GC_sysinfo.dwAllocationGranularity-1));
00883        } else
00884 #   else
00885     while (p < GC_sysinfo.lpMaximumApplicationAddress) {
00886         result = VirtualQuery(p, &buf, sizeof(buf));
00887 #   endif
00888        {
00889            if (result != sizeof(buf)) {
00890               ABORT("Weird VirtualQuery result");
00891            }
00892            new_limit = (char *)p + buf.RegionSize;
00893            protect = buf.Protect;
00894            if (buf.State == MEM_COMMIT
00895               && (protect == PAGE_EXECUTE_READWRITE
00896                   || protect == PAGE_READWRITE)
00897               && !GC_is_heap_base(buf.AllocationBase)
00898               /* This used to check for
00899                * !is_frame_buffer(p, buf.RegionSize, buf.Type)
00900                * instead of just checking for MEM_IMAGE.
00901                * If something breaks, change it back. */
00902               /* There is some evidence that we cannot always
00903                * ignore MEM_PRIVATE sections under Windows ME
00904                * and predecessors.  Hence we now also check for
00905                * that case. */
00906               && (buf.Type == MEM_IMAGE ||
00907                   !GC_wnt && buf.Type == MEM_PRIVATE)) {  
00908 #              ifdef DEBUG_VIRTUALQUERY
00909                  GC_dump_meminfo(&buf);
00910 #              endif
00911               if ((char *)p != limit) {
00912                   GC_cond_add_roots(base, limit);
00913                   base = p;
00914               }
00915               limit = new_limit;
00916            }
00917        }
00918         if (p > (LPVOID)new_limit /* overflow */) break;
00919         p = (LPVOID)new_limit;
00920     }
00921     GC_cond_add_roots(base, limit);
00922   }
00923 
00924 #endif /* MSWIN32 || MSWINCE */
00925   
00926 #if defined(ALPHA) && defined(OSF1)
00927 
00928 #include <loader.h>
00929 
00930 void GC_register_dynamic_libraries()
00931 {
00932   int status;
00933   ldr_process_t mypid;
00934 
00935   /* module */
00936     ldr_module_t moduleid = LDR_NULL_MODULE;
00937     ldr_module_info_t moduleinfo;
00938     size_t moduleinfosize = sizeof(moduleinfo);
00939     size_t modulereturnsize;    
00940 
00941   /* region */
00942     ldr_region_t region; 
00943     ldr_region_info_t regioninfo;
00944     size_t regioninfosize = sizeof(regioninfo);
00945     size_t regionreturnsize;
00946 
00947   /* Obtain id of this process */
00948     mypid = ldr_my_process();
00949   
00950   /* For each module */
00951     while (TRUE) {
00952 
00953       /* Get the next (first) module */
00954         status = ldr_next_module(mypid, &moduleid);
00955 
00956       /* Any more modules? */
00957         if (moduleid == LDR_NULL_MODULE)
00958             break;    /* No more modules */
00959 
00960       /* Check status AFTER checking moduleid because */
00961       /* of a bug in the non-shared ldr_next_module stub */
00962         if (status != 0 ) {
00963             GC_printf1("dynamic_load: status = %ld\n", (long)status);
00964             {
00965                 extern char *sys_errlist[];
00966                 extern int sys_nerr;
00967                 extern int errno;
00968                 if (errno <= sys_nerr) {
00969                     GC_printf1("dynamic_load: %s\n", (long)sys_errlist[errno]);
00970                } else {
00971                     GC_printf1("dynamic_load: %d\n", (long)errno);
00972                 }
00973         }
00974             ABORT("ldr_next_module failed");
00975          }
00976 
00977       /* Get the module information */
00978         status = ldr_inq_module(mypid, moduleid, &moduleinfo,
00979                                 moduleinfosize, &modulereturnsize); 
00980         if (status != 0 )
00981             ABORT("ldr_inq_module failed");
00982 
00983       /* is module for the main program (i.e. nonshared portion)? */
00984           if (moduleinfo.lmi_flags & LDR_MAIN)
00985               continue;    /* skip the main module */
00986 
00987 #     ifdef VERBOSE
00988           GC_printf("---Module---\n");
00989           GC_printf("Module ID            = %16ld\n", moduleinfo.lmi_modid);
00990           GC_printf("Count of regions     = %16d\n", moduleinfo.lmi_nregion);
00991           GC_printf("flags for module     = %16lx\n", moduleinfo.lmi_flags); 
00992           GC_printf("pathname of module   = \"%s\"\n", moduleinfo.lmi_name);
00993 #     endif
00994 
00995       /* For each region in this module */
00996         for (region = 0; region < moduleinfo.lmi_nregion; region++) {
00997 
00998           /* Get the region information */
00999             status = ldr_inq_region(mypid, moduleid, region, &regioninfo,
01000                                     regioninfosize, &regionreturnsize);
01001             if (status != 0 )
01002                 ABORT("ldr_inq_region failed");
01003 
01004           /* only process writable (data) regions */
01005             if (! (regioninfo.lri_prot & LDR_W))
01006                 continue;
01007 
01008 #         ifdef VERBOSE
01009               GC_printf("--- Region ---\n");
01010               GC_printf("Region number    = %16ld\n",
01011                              regioninfo.lri_region_no);
01012               GC_printf("Protection flags = %016x\n",  regioninfo.lri_prot);
01013               GC_printf("Virtual address  = %16p\n",   regioninfo.lri_vaddr);
01014               GC_printf("Mapped address   = %16p\n",   regioninfo.lri_mapaddr);
01015               GC_printf("Region size      = %16ld\n",  regioninfo.lri_size);
01016               GC_printf("Region name      = \"%s\"\n", regioninfo.lri_name);
01017 #         endif
01018 
01019           /* register region as a garbage collection root */
01020             GC_add_roots_inner (
01021                 (char *)regioninfo.lri_mapaddr,
01022                 (char *)regioninfo.lri_mapaddr + regioninfo.lri_size,
01023                 TRUE);
01024 
01025         }
01026     }
01027 }
01028 #endif
01029 
01030 #if defined(HPUX)
01031 
01032 #include <errno.h>
01033 #include <dl.h>
01034 
01035 extern int errno;
01036 extern char *sys_errlist[];
01037 extern int sys_nerr;
01038 
01039 void GC_register_dynamic_libraries()
01040 {
01041   int status;
01042   int index = 1; /* Ordinal position in shared library search list */
01043   struct shl_descriptor *shl_desc; /* Shared library info, see dl.h */
01044 
01045   /* For each dynamic library loaded */
01046     while (TRUE) {
01047 
01048       /* Get info about next shared library */
01049         status = shl_get(index, &shl_desc);
01050 
01051       /* Check if this is the end of the list or if some error occured */
01052         if (status != 0) {
01053 #       ifdef GC_HPUX_THREADS
01054           /* I've seen errno values of 0.  The man page is not clear  */
01055           /* as to whether errno should get set on a -1 return.       */
01056           break;
01057 #       else
01058           if (errno == EINVAL) {
01059               break; /* Moved past end of shared library list --> finished */
01060           } else {
01061               if (errno <= sys_nerr) {
01062                     GC_printf1("dynamic_load: %s\n", (long) sys_errlist[errno]);
01063               } else {
01064                     GC_printf1("dynamic_load: %d\n", (long) errno);
01065              }
01066               ABORT("shl_get failed");
01067           }
01068 #       endif
01069         }
01070 
01071 #     ifdef VERBOSE
01072           GC_printf0("---Shared library---\n");
01073           GC_printf1("\tfilename        = \"%s\"\n", shl_desc->filename);
01074           GC_printf1("\tindex           = %d\n", index);
01075           GC_printf1("\thandle          = %08x\n",
01076                                    (unsigned long) shl_desc->handle);
01077           GC_printf1("\ttext seg. start = %08x\n", shl_desc->tstart);
01078           GC_printf1("\ttext seg. end   = %08x\n", shl_desc->tend);
01079           GC_printf1("\tdata seg. start = %08x\n", shl_desc->dstart);
01080           GC_printf1("\tdata seg. end   = %08x\n", shl_desc->dend);
01081           GC_printf1("\tref. count      = %lu\n", shl_desc->ref_count);
01082 #     endif
01083 
01084       /* register shared library's data segment as a garbage collection root */
01085         GC_add_roots_inner((char *) shl_desc->dstart,
01086                         (char *) shl_desc->dend, TRUE);
01087 
01088         index++;
01089     }
01090 }
01091 #endif /* HPUX */
01092 
01093 #ifdef RS6000
01094 #pragma alloca
01095 #include <sys/ldr.h>
01096 #include <sys/errno.h>
01097 void GC_register_dynamic_libraries()
01098 {
01099        int len;
01100        char *ldibuf;
01101        int ldibuflen;
01102        struct ld_info *ldi;
01103 
01104        ldibuf = alloca(ldibuflen = 8192);
01105 
01106        while ( (len = loadquery(L_GETINFO,ldibuf,ldibuflen)) < 0) {
01107               if (errno != ENOMEM) {
01108                      ABORT("loadquery failed");
01109               }
01110               ldibuf = alloca(ldibuflen *= 2);
01111        }
01112 
01113        ldi = (struct ld_info *)ldibuf;
01114        while (ldi) {
01115               len = ldi->ldinfo_next;
01116               GC_add_roots_inner(
01117                             ldi->ldinfo_dataorg,
01118                             (ptr_t)(unsigned long)ldi->ldinfo_dataorg
01119                              + ldi->ldinfo_datasize,
01120                             TRUE);
01121               ldi = len ? (struct ld_info *)((char *)ldi + len) : 0;
01122        }
01123 }
01124 #endif /* RS6000 */
01125 
01126 #ifdef DARWIN
01127 
01128 /* __private_extern__ hack required for pre-3.4 gcc versions.  */
01129 #ifndef __private_extern__
01130 # define __private_extern__ extern
01131 # include <mach-o/dyld.h>
01132 # undef __private_extern__
01133 #else
01134 # include <mach-o/dyld.h>
01135 #endif
01136 #include <mach-o/getsect.h>
01137 
01138 /*#define DARWIN_DEBUG*/
01139 
01140 const static struct { 
01141         const char *seg;
01142         const char *sect;
01143 } GC_dyld_sections[] = {
01144         { SEG_DATA, SECT_DATA },
01145         { SEG_DATA, SECT_BSS },
01146         { SEG_DATA, SECT_COMMON }
01147 };
01148     
01149 #ifdef DARWIN_DEBUG
01150 static const char *GC_dyld_name_for_hdr(struct mach_header *hdr) {
01151     unsigned long i,c;
01152     c = _dyld_image_count();
01153     for(i=0;i<c;i++) if(_dyld_get_image_header(i) == hdr)
01154         return _dyld_get_image_name(i);
01155     return NULL;
01156 }
01157 #endif
01158         
01159 /* This should never be called by a thread holding the lock */
01160 static void GC_dyld_image_add(struct mach_header* hdr, unsigned long slide) {
01161     unsigned long start,end,i;
01162     const struct section *sec;
01163     if (GC_no_dls) return;
01164     for(i=0;i<sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]);i++) {
01165         sec = getsectbynamefromheader(
01166             hdr,GC_dyld_sections[i].seg,GC_dyld_sections[i].sect);
01167         if(sec == NULL || sec->size == 0) continue;
01168         start = slide + sec->addr;
01169         end = start + sec->size;
01170 #      ifdef DARWIN_DEBUG
01171             GC_printf4("Adding section at %p-%p (%lu bytes) from image %s\n",
01172                 start,end,sec->size,GC_dyld_name_for_hdr(hdr));
01173 #       endif
01174         GC_add_roots((char*)start,(char*)end);
01175     }
01176 #   ifdef DARWIN_DEBUG
01177         GC_print_static_roots();
01178 #   endif
01179 }
01180 
01181 /* This should never be called by a thread holding the lock */
01182 static void GC_dyld_image_remove(struct mach_header* hdr, unsigned long slide) {
01183     unsigned long start,end,i;
01184     const struct section *sec;
01185     for(i=0;i<sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]);i++) {
01186         sec = getsectbynamefromheader(
01187             hdr,GC_dyld_sections[i].seg,GC_dyld_sections[i].sect);
01188         if(sec == NULL || sec->size == 0) continue;
01189         start = slide + sec->addr;
01190         end = start + sec->size;
01191 #      ifdef DARWIN_DEBUG
01192             GC_printf4("Removing section at %p-%p (%lu bytes) from image %s\n",
01193                 start,end,sec->size,GC_dyld_name_for_hdr(hdr));
01194 #             endif
01195         GC_remove_roots((char*)start,(char*)end);
01196     }
01197 #   ifdef DARWIN_DEBUG
01198         GC_print_static_roots();
01199 #   endif
01200 }
01201 
01202 void GC_register_dynamic_libraries() {
01203     /* Currently does nothing. The callbacks are setup by GC_init_dyld() 
01204     The dyld library takes it from there. */
01205 }
01206 
01207 /* The _dyld_* functions have an internal lock so no _dyld functions
01208    can be called while the world is stopped without the risk of a deadlock.
01209    Because of this we MUST setup callbacks BEFORE we ever stop the world.
01210    This should be called BEFORE any thread in created and WITHOUT the
01211    allocation lock held. */
01212    
01213 void GC_init_dyld() {
01214   static GC_bool initialized = FALSE;
01215   char *bind_fully_env = NULL;
01216   
01217   if(initialized) return;
01218   
01219   /* PLTSCHEME: not if dls are disabled */
01220   if (GC_no_dls) {
01221     initialized = TRUE;
01222     return;
01223   }
01224   
01225 #   ifdef DARWIN_DEBUG
01226   GC_printf0("Registering dyld callbacks...\n");
01227 #   endif
01228   
01229   /* Apple's Documentation:
01230      When you call _dyld_register_func_for_add_image, the dynamic linker runtime
01231      calls the specified callback (func) once for each of the images that is
01232      currently loaded into the program. When a new image is added to the program,
01233      your callback is called again with the mach_header for the new image, and the  
01234      virtual memory slide amount of the new image. 
01235      
01236      This WILL properly register already linked libraries and libraries 
01237      linked in the future
01238   */
01239   
01240     _dyld_register_func_for_add_image(GC_dyld_image_add);
01241     _dyld_register_func_for_remove_image(GC_dyld_image_remove);
01242 
01243     /* Set this early to avoid reentrancy issues. */
01244     initialized = TRUE;
01245 
01246     bind_fully_env = getenv("DYLD_BIND_AT_LAUNCH");
01247     
01248     if (bind_fully_env == NULL) {
01249 #   ifdef DARWIN_DEBUG
01250       GC_printf0("Forcing full bind of GC code...\n");
01251 #   endif
01252       
01253       if(!_dyld_bind_fully_image_containing_address((unsigned long*)GC_malloc))
01254         GC_abort("_dyld_bind_fully_image_containing_address failed");
01255     }
01256 
01257 }
01258 
01259 #define HAVE_REGISTER_MAIN_STATIC_DATA
01260 GC_bool GC_register_main_static_data()
01261 {
01262   /* Already done through dyld callbacks */
01263   return FALSE;
01264 }
01265 
01266 #endif /* DARWIN */
01267 
01268 #else /* !DYNAMIC_LOADING */
01269 
01270 #ifdef PCR
01271 
01272 #   include "il/PCR_IL.h"
01273 #   include "th/PCR_ThCtl.h"
01274 #   include "mm/PCR_MM.h"
01275 
01276 void GC_register_dynamic_libraries()
01277 {
01278     /* Add new static data areas of dynamically loaded modules.       */
01279         {
01280           PCR_IL_LoadedFile * p = PCR_IL_GetLastLoadedFile();
01281           PCR_IL_LoadedSegment * q;
01282           
01283           /* Skip uncommited files */
01284           while (p != NIL && !(p -> lf_commitPoint)) {
01285               /* The loading of this file has not yet been committed  */
01286               /* Hence its description could be inconsistent.                */
01287               /* Furthermore, it hasn't yet been run.  Hence its data */
01288               /* segments can't possibly reference heap allocated     */
01289               /* objects.                                      */
01290               p = p -> lf_prev;
01291           }
01292           for (; p != NIL; p = p -> lf_prev) {
01293             for (q = p -> lf_ls; q != NIL; q = q -> ls_next) {
01294               if ((q -> ls_flags & PCR_IL_SegFlags_Traced_MASK)
01295                   == PCR_IL_SegFlags_Traced_on) {
01296                 GC_add_roots_inner
01297                      ((char *)(q -> ls_addr), 
01298                       (char *)(q -> ls_addr) + q -> ls_bytes,
01299                       TRUE);
01300               }
01301             }
01302           }
01303         }
01304 }
01305 
01306 
01307 #else /* !PCR */
01308 
01309 void GC_register_dynamic_libraries(){}
01310 
01311 int GC_no_dynamic_loading;
01312 
01313 #endif /* !PCR */
01314 
01315 #endif /* !DYNAMIC_LOADING */
01316 
01317 #ifndef HAVE_REGISTER_MAIN_STATIC_DATA
01318 
01319 /* Do we need to separately register the main static data segment? */
01320 GC_bool GC_register_main_static_data()
01321 {
01322   return TRUE;
01323 }
01324 #endif /* HAVE_REGISTER_MAIN_STATIC_DATA */
01325