Back to index

lightning-sunbird  0.9+nobinonly
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 #ifndef MACOS
00030 #  include <sys/types.h>
00031 #endif
00032 #include "gc_priv.h"
00033 
00034 /* BTL: avoid circular redefinition of dlopen if SOLARIS_THREADS defined */
00035 # if defined(SOLARIS_THREADS) && defined(dlopen)
00036     /* To support threads in Solaris, gc.h interposes on dlopen by       */
00037     /* defining "dlopen" to be "GC_dlopen", which is implemented below.  */
00038     /* However, both GC_FirstDLOpenedLinkMap() and GC_dlopen() use the   */
00039     /* real system dlopen() in their implementation. We first remove     */
00040     /* gc.h's dlopen definition and restore it later, after GC_dlopen(). */
00041 #   undef dlopen
00042 #   define GC_must_restore_redefined_dlopen
00043 # else
00044 #   undef GC_must_restore_redefined_dlopen
00045 # endif
00046 
00047 #if (defined(DYNAMIC_LOADING) || defined(MSWIN32)) && !defined(PCR)
00048 #if !defined(SUNOS4) && !defined(SUNOS5DL) && !defined(IRIX5) && \
00049     !defined(MSWIN32) && !(defined(ALPHA) && defined(OSF1)) && \
00050     !defined(HP_PA) && !(defined(LINUX) && defined(__ELF__)) && \
00051     !defined(RS6000) && !defined(SCO_ELF)
00052  --> We only know how to find data segments of dynamic libraries for the
00053  --> above.  Additional SVR4 variants might not be too
00054  --> hard to add.
00055 #endif
00056 
00057 #include <stdio.h>
00058 #ifdef SUNOS5DL
00059 #   include <sys/elf.h>
00060 #   include <dlfcn.h>
00061 #   include <link.h>
00062 #endif
00063 #ifdef SUNOS4
00064 #   include <dlfcn.h>
00065 #   include <link.h>
00066 #   include <a.out.h>
00067   /* struct link_map field overrides */
00068 #   define l_next    lm_next
00069 #   define l_addr    lm_addr
00070 #   define l_name    lm_name
00071 #endif
00072 
00073 
00074 #if defined(SUNOS5DL) && !defined(USE_PROC_FOR_LIBRARIES)
00075 
00076 #ifdef LINT
00077     Elf32_Dyn _DYNAMIC;
00078 #endif
00079 
00080 static struct link_map *
00081 GC_FirstDLOpenedLinkMap()
00082 {
00083     extern Elf32_Dyn _DYNAMIC;
00084     Elf32_Dyn *dp;
00085     struct r_debug *r;
00086     static struct link_map * cachedResult = 0;
00087     static Elf32_Dyn *dynStructureAddr = 0;
00088                      /* BTL: added to avoid Solaris 5.3 ld.so _DYNAMIC bug */
00089 
00090 #   ifdef SUNOS53_SHARED_LIB
00091        /* BTL: Avoid the Solaris 5.3 bug that _DYNAMIC isn't being set       */
00092        /* up properly in dynamically linked .so's. This means we have */
00093        /* to use its value in the set of original object files loaded */
00094        /* at program startup.                                         */
00095        if( dynStructureAddr == 0 ) {
00096          void* startupSyms = dlopen(0, RTLD_LAZY);
00097          dynStructureAddr = (Elf32_Dyn*)dlsym(startupSyms, "_DYNAMIC");
00098               }
00099 #   else
00100        dynStructureAddr = &_DYNAMIC;
00101 #   endif
00102 
00103     if( dynStructureAddr == 0) {
00104         return(0);
00105     }
00106     if( cachedResult == 0 ) {
00107         int tag;
00108         for( dp = ((Elf32_Dyn *)(&_DYNAMIC)); (tag = dp->d_tag) != 0; dp++ ) {
00109             if( tag == DT_DEBUG ) {
00110                 struct link_map *lm
00111                         = ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
00112                 if( lm != 0 ) cachedResult = lm->l_next; /* might be NIL */
00113                 break;
00114             }
00115         }
00116     }
00117     return cachedResult;
00118 }
00119 
00120 #endif /* SUNOS5DL ... */
00121 
00122 #if defined(SUNOS4) && !defined(USE_PROC_FOR_LIBRARIES)
00123 
00124 #ifdef LINT
00125     struct link_dynamic _DYNAMIC;
00126 #endif
00127 
00128 static struct link_map *
00129 GC_FirstDLOpenedLinkMap()
00130 {
00131     extern struct link_dynamic _DYNAMIC;
00132 
00133     if( &_DYNAMIC == 0) {
00134         return(0);
00135     }
00136     return(_DYNAMIC.ld_un.ld_1->ld_loaded);
00137 }
00138 
00139 /* Return the address of the ld.so allocated common symbol     */
00140 /* with the least address, or 0 if none.                */
00141 static ptr_t GC_first_common()
00142 {
00143     ptr_t result = 0;
00144     extern struct link_dynamic _DYNAMIC;
00145     struct rtc_symb * curr_symbol;
00146     
00147     if( &_DYNAMIC == 0) {
00148         return(0);
00149     }
00150     curr_symbol = _DYNAMIC.ldd -> ldd_cp;
00151     for (; curr_symbol != 0; curr_symbol = curr_symbol -> rtc_next) {
00152         if (result == 0
00153             || (ptr_t)(curr_symbol -> rtc_sp -> n_value) < result) {
00154             result = (ptr_t)(curr_symbol -> rtc_sp -> n_value);
00155         }
00156     }
00157     return(result);
00158 }
00159 
00160 #endif  /* SUNOS4 ... */
00161 
00162 # if defined(SUNOS4) || defined(SUNOS5DL)
00163 /* Add dynamic library data sections to the root set.          */
00164 # if !defined(PCR) && !defined(SOLARIS_THREADS) && defined(THREADS)
00165 #   ifndef SRC_M3
00166        --> fix mutual exclusion with dlopen
00167 #   endif  /* We assume M3 programs don't call dlopen for now */
00168 # endif
00169 
00170 # ifdef SOLARIS_THREADS
00171   /* Redefine dlopen to guarantee mutual exclusion with */
00172   /* GC_register_dynamic_libraries.                     */
00173   /* assumes that dlopen doesn't need to call GC_malloc */
00174   /* and friends.                                */
00175 # include <thread.h>
00176 # include <synch.h>
00177 
00178 void * GC_dlopen(const char *path, int mode)
00179 {
00180     void * result;
00181     
00182 #   ifndef USE_PROC_FOR_LIBRARIES
00183       mutex_lock(&GC_allocate_ml);
00184 #   endif
00185     result = dlopen(path, mode);
00186 #   ifndef USE_PROC_FOR_LIBRARIES
00187       mutex_unlock(&GC_allocate_ml);
00188 #   endif
00189     return(result);
00190 }
00191 # endif  /* SOLARIS_THREADS */
00192 
00193 /* BTL: added to fix circular dlopen definition if SOLARIS_THREADS defined */
00194 # if defined(GC_must_restore_redefined_dlopen)
00195 #   define dlopen GC_dlopen
00196 # endif
00197 
00198 # ifndef USE_PROC_FOR_LIBRARIES
00199 void GC_register_dynamic_libraries()
00200 {
00201   struct link_map *lm = GC_FirstDLOpenedLinkMap();
00202   
00203 
00204   for (lm = GC_FirstDLOpenedLinkMap();
00205        lm != (struct link_map *) 0;  lm = lm->l_next)
00206     {
00207 #     ifdef SUNOS4
00208        struct exec *e;
00209         
00210         e = (struct exec *) lm->lm_addr;
00211         GC_add_roots_inner(
00212                   ((char *) (N_DATOFF(*e) + lm->lm_addr)),
00213                   ((char *) (N_BSSADDR(*e) + e->a_bss + lm->lm_addr)),
00214                   TRUE);
00215 #     endif
00216 #     ifdef SUNOS5DL
00217        Elf32_Ehdr * e;
00218         Elf32_Phdr * p;
00219         unsigned long offset;
00220         char * start;
00221         register int i;
00222         
00223        e = (Elf32_Ehdr *) lm->l_addr;
00224         p = ((Elf32_Phdr *)(((char *)(e)) + e->e_phoff));
00225         offset = ((unsigned long)(lm->l_addr));
00226         for( i = 0; i < (int)(e->e_phnum); ((i++),(p++)) ) {
00227           switch( p->p_type ) {
00228             case PT_LOAD:
00229               {
00230                 if( !(p->p_flags & PF_W) ) break;
00231                 start = ((char *)(p->p_vaddr)) + offset;
00232                 GC_add_roots_inner(
00233                   start,
00234                   start + p->p_memsz,
00235                   TRUE
00236                 );
00237               }
00238               break;
00239             default:
00240               break;
00241           }
00242        }
00243 #     endif
00244     }
00245 #   ifdef SUNOS4
00246       {
00247        static ptr_t common_start = 0;
00248        ptr_t common_end;
00249        extern ptr_t GC_find_limit();
00250        
00251        if (common_start == 0) common_start = GC_first_common();
00252        if (common_start != 0) {
00253            common_end = GC_find_limit(common_start, TRUE);
00254            GC_add_roots_inner((char *)common_start, (char *)common_end, TRUE);
00255        }
00256       }
00257 #   endif
00258 }
00259 
00260 # endif /* !USE_PROC ... */
00261 # endif /* SUNOS */
00262 
00263 #if defined(LINUX) && defined(USE_PROC)
00264 
00265 #include <fcntl.h>
00266 #include <unistd.h>
00267 #define BUFSIZE 32000
00268 
00269 /* Register all possible root segments using kernel proces info read
00270    from /proc. This adds every read/write piece of the virtual address
00271    space to the root set, so it does more than register dynamic
00272    libraries */
00273 void GC_register_dynamic_libraries()
00274 {
00275   int mapfile;
00276   char *fname = "/proc/self/maps";
00277   unsigned int start, end, offset, inode;
00278   char perms[10], path[512];
00279   static char buffer[BUFSIZE];
00280   int e;
00281   
00282 
00283   GC_printf0("[[register mmap data start.]]\n");
00284   memset(buffer,0,BUFSIZE);
00285   mapfile = open(fname, O_RDONLY); /* Don't use fopen - it mallocs */
00286   offset = 0;
00287   do {
00288     e = read(mapfile, buffer + offset, BUFSIZE - offset - 1);
00289     offset = offset + e;
00290   } while (e > 0);
00291 
00292   if (offset >= (BUFSIZE - 1)) {
00293     ABORT("map buffer too small\n");
00294   } else {
00295     int result, count;
00296 
00297     char *next = buffer;
00298     
00299     close(mapfile);
00300     buffer[offset] = '\0';
00301     do {
00302       result = sscanf(next,
00303                     "%x-%x %s %x %*s %d %n",
00304                     &start, &end, perms, &offset, &inode, &count);
00305       next = next + count;
00306       if (result > 0) {
00307        char *c = strstr(perms, "rw");
00308        int isroot = (c != 0);
00309        /* GC_printf6("%8x-%8x %s %8x device %8d %d",
00310           start, end, perms, offset, inode, isroot); */
00311        if (inode != 0) {
00312          result = sscanf(next, "%s\n%n", path, &count);
00313          next = next + count;
00314        } else {
00315          strcpy(path, "mmap zero"); /* dumb... */
00316        }
00317        GC_printf3("[[registering roots %8x-%8x for mmap: %s]]\n",
00318                  start, end, path);
00319        if (isroot) {
00320          GC_add_roots_inner((char *)start, (char *)end, TRUE);
00321        }
00322       }
00323     } while (result > 0);
00324   }
00325   GC_printf0("[[register mmap data finish.]]\n");
00326 }
00327 #endif
00328 
00329 
00330 #if defined(LINUX) && !defined(USE_PROC)
00331 
00332 /* This code shouldn't be used anymore - the /proc version is more complete */
00333 
00334 /* Dynamic loading code for Linux running ELF. Somewhat tested on
00335  * Linux/x86, untested but hopefully should work on Linux/Alpha. 
00336  * This code was derived from the Solaris/ELF support. Thanks to
00337  * whatever kind soul wrote that.  - Patrick Bridges */
00338 
00339 #include <elf.h>
00340 #include <link.h>
00341 
00342 /* Newer versions of Linux/Alpha and Linux/x86 define this macro.  We
00343  * define it for those older versions that don't.  */
00344 #  ifndef ElfW
00345 #    if !defined(ELF_CLASS) || ELF_CLASS == ELFCLASS32
00346 #      define ElfW(type) Elf32_##type
00347 #    else
00348 #      define ElfW(type) Elf64_##type
00349 #    endif
00350 #  endif
00351 
00352 static struct link_map *
00353 GC_FirstDLOpenedLinkMap()
00354 {
00355     extern ElfW(Dyn) _DYNAMIC[];
00356     ElfW(Dyn) *dp;
00357     struct r_debug *r;
00358     static struct link_map *cachedResult = 0;
00359 
00360     if( _DYNAMIC == 0) {
00361         return(0);
00362     }
00363     if( cachedResult == 0 ) {
00364         int tag;
00365         for( dp = _DYNAMIC; (tag = dp->d_tag) != 0; dp++ ) {
00366             if( tag == DT_DEBUG ) {
00367                 struct link_map *lm
00368                         = ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
00369                 if( lm != 0 ) cachedResult = lm->l_next; /* might be NIL */
00370                 break;
00371             }
00372         }
00373     }
00374     return cachedResult;
00375 }
00376 
00377 
00378 void GC_register_dynamic_libraries()
00379 {
00380   struct link_map *lm = GC_FirstDLOpenedLinkMap();
00381   
00382 
00383   GC_printf0("[[register dynamic libraries start.]]\n");
00384 
00385   for (lm = GC_FirstDLOpenedLinkMap();
00386        lm != (struct link_map *) 0;  lm = lm->l_next)
00387     {
00388        ElfW(Ehdr) * e;
00389         ElfW(Phdr) * p;
00390         unsigned long offset;
00391         char * start;
00392         register int i;
00393         
00394        GC_printf1("[[registering roots for library: %s]]\n", lm->l_name);
00395 
00396        e = (ElfW(Ehdr) *) lm->l_addr;
00397         p = ((ElfW(Phdr) *)(((char *)(e)) + e->e_phoff));
00398         offset = ((unsigned long)(lm->l_addr));
00399         for( i = 0; i < (int)(e->e_phnum); ((i++),(p++)) ) {
00400           switch( p->p_type ) {
00401             case PT_LOAD:
00402               {
00403                 if( !(p->p_flags & PF_W) ) break;
00404                 start = ((char *)(p->p_vaddr)) + offset;
00405                 GC_add_roots_inner(start, start + p->p_memsz, TRUE);
00406               }
00407               break;
00408             default:
00409               break;
00410           }
00411        }
00412 
00413        /* as a hack, register the link_map itself as a root. */
00414        GC_add_roots_inner(lm, lm + 1, TRUE);
00415     }
00416 
00417   GC_printf0("[[register dynamic libraries finish.]]\n");
00418 }
00419 
00420 #endif
00421 
00422 #if defined(IRIX5) || defined(USE_PROC_FOR_LIBRARIES)
00423 
00424 #include <sys/procfs.h>
00425 #include <sys/stat.h>
00426 #include <fcntl.h>
00427 #include <elf.h>
00428 #include <errno.h>
00429 
00430 extern void * GC_roots_present();
00431        /* The type is a lie, since the real type doesn't make sense here, */
00432        /* and we only test for NULL.                                     */
00433 
00434 extern ptr_t GC_scratch_last_end_ptr; /* End of GC_scratch_alloc arena       */
00435 
00436 /* We use /proc to track down all parts of the address space that are */
00437 /* mapped by the process, and throw out regions we know we shouldn't  */
00438 /* worry about.  This may also work under other SVR4 variants.        */
00439 void GC_register_dynamic_libraries()
00440 {
00441     static int fd = -1;
00442     char buf[30];
00443     static prmap_t * addr_map = 0;
00444     static int current_sz = 0;     /* Number of records currently in addr_map */
00445     static int needed_sz;   /* Required size of addr_map              */
00446     register int i;
00447     register long flags;
00448     register ptr_t start;
00449     register ptr_t limit;
00450     ptr_t heap_start = (ptr_t)HEAP_START;
00451     ptr_t heap_end = heap_start;
00452 
00453 #   ifdef SUNOS5DL
00454 #     define MA_PHYS 0
00455 #   endif /* SUNOS5DL */
00456 
00457     if (fd < 0) {
00458       sprintf(buf, "/proc/%d", getpid());
00459        /* The above generates a lint complaint, since pid_t varies.   */
00460        /* It's unclear how to improve this.                           */
00461       fd = open(buf, O_RDONLY);
00462       if (fd < 0) {
00463        ABORT("/proc open failed");
00464       }
00465     }
00466     if (ioctl(fd, PIOCNMAP, &needed_sz) < 0) {
00467        GC_err_printf2("fd = %d, errno = %d\n", fd, errno);
00468        ABORT("/proc PIOCNMAP ioctl failed");
00469     }
00470     if (needed_sz >= current_sz) {
00471         current_sz = needed_sz * 2 + 1;
00472                      /* Expansion, plus room for 0 record */
00473         addr_map = (prmap_t *)GC_scratch_alloc((word)
00474                                           (current_sz * sizeof(prmap_t)));
00475     }
00476     if (ioctl(fd, PIOCMAP, addr_map) < 0) {
00477         GC_err_printf4("fd = %d, errno = %d, needed_sz = %d, addr_map = 0x%X\n",
00478                         fd, errno, needed_sz, addr_map);
00479        ABORT("/proc PIOCMAP ioctl failed");
00480     };
00481     if (GC_n_heap_sects > 0) {
00482        heap_end = GC_heap_sects[GC_n_heap_sects-1].hs_start
00483                      + GC_heap_sects[GC_n_heap_sects-1].hs_bytes;
00484        if (heap_end < GC_scratch_last_end_ptr) heap_end = GC_scratch_last_end_ptr; 
00485     }
00486     for (i = 0; i < needed_sz; i++) {
00487         flags = addr_map[i].pr_mflags;
00488         if ((flags & (MA_BREAK | MA_STACK | MA_PHYS)) != 0) goto irrelevant;
00489         if ((flags & (MA_READ | MA_WRITE)) != (MA_READ | MA_WRITE))
00490             goto irrelevant;
00491           /* The latter test is empirically useless.  Other than the  */
00492           /* main data and stack segments, everything appears to be   */
00493           /* mapped readable, writable, executable, and shared(!!).   */
00494           /* This makes no sense to me.   - HB                        */
00495         start = (ptr_t)(addr_map[i].pr_vaddr);
00496         if (GC_roots_present(start)) goto irrelevant;
00497         if (start < heap_end && start >= heap_start)
00498               goto irrelevant;
00499 #      ifdef MMAP_STACKS
00500          if (GC_is_thread_stack(start)) goto irrelevant;
00501 #      endif /* MMAP_STACKS */
00502 
00503         limit = start + addr_map[i].pr_size;
00504        if (addr_map[i].pr_off == 0 && strncmp(start, ELFMAG, 4) == 0) {
00505            /* Discard text segments, i.e. 0-offset mappings against   */
00506            /* executable files which appear to have ELF headers.      */
00507            caddr_t arg;
00508            int obj;
00509 #          define MAP_IRR_SZ 10
00510            static ptr_t map_irr[MAP_IRR_SZ];
00511                                    /* Known irrelevant map entries    */
00512            static int n_irr = 0;
00513            struct stat buf;
00514            register int i;
00515            
00516            for (i = 0; i < n_irr; i++) {
00517                if (map_irr[i] == start) goto irrelevant;
00518            }
00519            arg = (caddr_t)start;
00520            obj = ioctl(fd, PIOCOPENM, &arg);
00521            if (obj >= 0) {
00522                fstat(obj, &buf);
00523                close(obj);
00524                if ((buf.st_mode & 0111) != 0) {
00525                    if (n_irr < MAP_IRR_SZ) {
00526                        map_irr[n_irr++] = start;
00527                    }
00528                    goto irrelevant;
00529                }
00530            }
00531        }
00532         GC_add_roots_inner(start, limit, TRUE);
00533       irrelevant: ;
00534     }
00535     /* Dont keep cached descriptor, for now.  Some kernels don't like us */
00536     /* to keep a /proc file descriptor around during kill -9.          */
00537        if (close(fd) < 0) ABORT("Couldnt close /proc file");
00538        fd = -1;
00539 }
00540 
00541 # endif /* USE_PROC || IRIX5 */
00542 
00543 # ifdef MSWIN32
00544 
00545 # define WIN32_LEAN_AND_MEAN
00546 # define NOSERVICE
00547 # include <windows.h>
00548 # include <stdlib.h>
00549 
00550   /* We traverse the entire address space and register all segments   */
00551   /* that could possibly have been written to.                        */
00552   DWORD GC_allocation_granularity;
00553   
00554   extern GC_bool GC_is_heap_base (ptr_t p);
00555 
00556 # ifdef WIN32_THREADS
00557     extern void GC_get_next_stack(char *start, char **lo, char **hi);
00558 # endif
00559   
00560   void GC_cond_add_roots(char *base, char * limit)
00561   {
00562     char dummy;
00563     char * stack_top
00564            = (char *) ((word)(&dummy) & ~(GC_allocation_granularity-1));
00565     if (base == limit) return;
00566 #   ifdef WIN32_THREADS
00567     {
00568         char * curr_base = base;
00569        char * next_stack_lo;
00570        char * next_stack_hi;
00571        
00572        for(;;) {
00573            GC_get_next_stack(curr_base, &next_stack_lo, &next_stack_hi);
00574            if (next_stack_lo >= limit) break;
00575            GC_add_roots_inner(curr_base, next_stack_lo, TRUE);
00576            curr_base = next_stack_hi;
00577        }
00578        if (curr_base < limit) GC_add_roots_inner(curr_base, limit, TRUE);
00579     }
00580 #   else
00581         if (limit > stack_top && base < GC_stackbottom) {
00582            /* Part of the stack; ignore it. */
00583            return;
00584         }
00585         GC_add_roots_inner(base, limit, TRUE);
00586 #   endif
00587   }
00588   
00589   extern GC_bool GC_win32s;
00590   
00591   void GC_register_dynamic_libraries()
00592   {
00593     MEMORY_BASIC_INFORMATION buf;
00594     SYSTEM_INFO sysinfo;
00595     DWORD result;
00596     DWORD protect;
00597     LPVOID p;
00598     char * base;
00599     char * limit, * new_limit;
00600     
00601     if (GC_win32s) return;
00602     GetSystemInfo(&sysinfo);
00603     base = limit = p = sysinfo.lpMinimumApplicationAddress;
00604     GC_allocation_granularity = sysinfo.dwAllocationGranularity;
00605     while (p < sysinfo.lpMaximumApplicationAddress) {
00606         result = VirtualQuery(p, &buf, sizeof(buf));
00607         if (result != sizeof(buf)) {
00608             ABORT("Weird VirtualQuery result");
00609         }
00610         new_limit = (char *)p + buf.RegionSize;
00611         protect = buf.Protect;
00612         if (buf.State == MEM_COMMIT
00613             && (protect == PAGE_EXECUTE_READWRITE
00614                 || protect == PAGE_READWRITE)
00615             && !GC_is_heap_base(buf.AllocationBase)) {
00616             if ((char *)p == limit) {
00617                 limit = new_limit;
00618             } else {
00619                 GC_cond_add_roots(base, limit);
00620                 base = p;
00621                 limit = new_limit;
00622             }
00623         }
00624         if (p > (LPVOID)new_limit /* overflow */) break;
00625         p = (LPVOID)new_limit;
00626     }
00627     GC_cond_add_roots(base, limit);
00628   }
00629 
00630 #endif /* MSWIN32 */
00631 
00632 #if defined(ALPHA) && defined(OSF1)
00633 
00634 #include <loader.h>
00635 
00636 void GC_register_dynamic_libraries()
00637 {
00638   int status;
00639   ldr_process_t mypid;
00640 
00641   /* module */
00642     ldr_module_t moduleid = LDR_NULL_MODULE;
00643     ldr_module_info_t moduleinfo;
00644     size_t moduleinfosize = sizeof(moduleinfo);
00645     size_t modulereturnsize;    
00646 
00647   /* region */
00648     ldr_region_t region; 
00649     ldr_region_info_t regioninfo;
00650     size_t regioninfosize = sizeof(regioninfo);
00651     size_t regionreturnsize;
00652 
00653   /* Obtain id of this process */
00654     mypid = ldr_my_process();
00655   
00656   /* For each module */
00657     while (TRUE) {
00658 
00659       /* Get the next (first) module */
00660         status = ldr_next_module(mypid, &moduleid);
00661 
00662       /* Any more modules? */
00663         if (moduleid == LDR_NULL_MODULE)
00664             break;    /* No more modules */
00665 
00666       /* Check status AFTER checking moduleid because */
00667       /* of a bug in the non-shared ldr_next_module stub */
00668         if (status != 0 ) {
00669             GC_printf1("dynamic_load: status = %ld\n", (long)status);
00670             {
00671                 extern char *sys_errlist[];
00672                 extern int sys_nerr;
00673                 extern int errno;
00674                 if (errno <= sys_nerr) {
00675                     GC_printf1("dynamic_load: %s\n", (long)sys_errlist[errno]);
00676                } else {
00677                     GC_printf1("dynamic_load: %d\n", (long)errno);
00678                 }
00679         }
00680             ABORT("ldr_next_module failed");
00681          }
00682 
00683       /* Get the module information */
00684         status = ldr_inq_module(mypid, moduleid, &moduleinfo,
00685                                 moduleinfosize, &modulereturnsize); 
00686         if (status != 0 )
00687             ABORT("ldr_inq_module failed");
00688 
00689       /* is module for the main program (i.e. nonshared portion)? */
00690           if (moduleinfo.lmi_flags & LDR_MAIN)
00691               continue;    /* skip the main module */
00692 
00693 #     ifdef VERBOSE
00694           GC_printf("---Module---\n");
00695           GC_printf("Module ID            = %16ld\n", moduleinfo.lmi_modid);
00696           GC_printf("Count of regions     = %16d\n", moduleinfo.lmi_nregion);
00697           GC_printf("flags for module     = %16lx\n", moduleinfo.lmi_flags); 
00698           GC_printf("pathname of module   = \"%s\"\n", moduleinfo.lmi_name);
00699 #     endif
00700 
00701       /* For each region in this module */
00702         for (region = 0; region < moduleinfo.lmi_nregion; region++) {
00703 
00704           /* Get the region information */
00705             status = ldr_inq_region(mypid, moduleid, region, &regioninfo,
00706                                     regioninfosize, &regionreturnsize);
00707             if (status != 0 )
00708                 ABORT("ldr_inq_region failed");
00709 
00710           /* only process writable (data) regions */
00711             if (! (regioninfo.lri_prot & LDR_W))
00712                 continue;
00713 
00714 #         ifdef VERBOSE
00715               GC_printf("--- Region ---\n");
00716               GC_printf("Region number    = %16ld\n",
00717                              regioninfo.lri_region_no);
00718               GC_printf("Protection flags = %016x\n",  regioninfo.lri_prot);
00719               GC_printf("Virtual address  = %16p\n",   regioninfo.lri_vaddr);
00720               GC_printf("Mapped address   = %16p\n",   regioninfo.lri_mapaddr);
00721               GC_printf("Region size      = %16ld\n",  regioninfo.lri_size);
00722               GC_printf("Region name      = \"%s\"\n", regioninfo.lri_name);
00723 #         endif
00724 
00725           /* register region as a garbage collection root */
00726             GC_add_roots_inner (
00727                 (char *)regioninfo.lri_mapaddr,
00728                 (char *)regioninfo.lri_mapaddr + regioninfo.lri_size,
00729                 TRUE);
00730 
00731         }
00732     }
00733 }
00734 #endif
00735 
00736 #if defined(HP_PA)
00737 
00738 #include <errno.h>
00739 #include <dl.h>
00740 
00741 extern int errno;
00742 extern char *sys_errlist[];
00743 extern int sys_nerr;
00744 
00745 void GC_register_dynamic_libraries()
00746 {
00747   int status;
00748   int index = 1; /* Ordinal position in shared library search list */
00749   struct shl_descriptor *shl_desc; /* Shared library info, see dl.h */
00750 
00751   /* For each dynamic library loaded */
00752     while (TRUE) {
00753 
00754       /* Get info about next shared library */
00755         status = shl_get(index, &shl_desc);
00756 
00757       /* Check if this is the end of the list or if some error occured */
00758         if (status != 0) {
00759           if (errno == EINVAL) {
00760               break; /* Moved past end of shared library list --> finished */
00761           } else {
00762               if (errno <= sys_nerr) {
00763                     GC_printf1("dynamic_load: %s\n", (long) sys_errlist[errno]);
00764               } else {
00765                     GC_printf1("dynamic_load: %d\n", (long) errno);
00766              }
00767               ABORT("shl_get failed");
00768           }
00769         }
00770 
00771 #     ifdef VERBOSE
00772           GC_printf0("---Shared library---\n");
00773           GC_printf1("\tfilename        = \"%s\"\n", shl_desc->filename);
00774           GC_printf1("\tindex           = %d\n", index);
00775           GC_printf1("\thandle          = %08x\n",
00776                                    (unsigned long) shl_desc->handle);
00777           GC_printf1("\ttext seg. start = %08x\n", shl_desc->tstart);
00778           GC_printf1("\ttext seg. end   = %08x\n", shl_desc->tend);
00779           GC_printf1("\tdata seg. start = %08x\n", shl_desc->dstart);
00780           GC_printf1("\tdata seg. end   = %08x\n", shl_desc->dend);
00781           GC_printf1("\tref. count      = %lu\n", shl_desc->ref_count);
00782 #     endif
00783 
00784       /* register shared library's data segment as a garbage collection root */
00785         GC_add_roots_inner((char *) shl_desc->dstart,
00786                         (char *) shl_desc->dend, TRUE);
00787 
00788         index++;
00789     }
00790 }
00791 #endif /* HP_PA */
00792 
00793 #ifdef RS6000
00794 #pragma alloca
00795 #include <sys/ldr.h>
00796 #include <sys/errno.h>
00797 void GC_register_dynamic_libraries()
00798 {
00799        int len;
00800        char *ldibuf;
00801        int ldibuflen;
00802        struct ld_info *ldi;
00803 
00804        ldibuf = alloca(ldibuflen = 8192);
00805 
00806        while ( (len = loadquery(L_GETINFO,ldibuf,ldibuflen)) < 0) {
00807               if (errno != ENOMEM) {
00808                      ABORT("loadquery failed");
00809               }
00810               ldibuf = alloca(ldibuflen *= 2);
00811        }
00812 
00813        ldi = (struct ld_info *)ldibuf;
00814        while (ldi) {
00815               len = ldi->ldinfo_next;
00816               GC_add_roots_inner(
00817                             ldi->ldinfo_dataorg,
00818                             (unsigned long)ldi->ldinfo_dataorg
00819                              + ldi->ldinfo_datasize,
00820                             TRUE);
00821               ldi = len ? (struct ld_info *)((char *)ldi + len) : 0;
00822        }
00823 }
00824 #endif /* RS6000 */
00825 
00826 
00827 
00828 #else /* !DYNAMIC_LOADING */
00829 
00830 #ifdef PCR
00831 
00832 #   include "il/PCR_IL.h"
00833 #   include "th/PCR_ThCtl.h"
00834 #   include "mm/PCR_MM.h"
00835 
00836 void GC_register_dynamic_libraries()
00837 {
00838     /* Add new static data areas of dynamically loaded modules.       */
00839         {
00840           PCR_IL_LoadedFile * p = PCR_IL_GetLastLoadedFile();
00841           PCR_IL_LoadedSegment * q;
00842           
00843           /* Skip uncommited files */
00844           while (p != NIL && !(p -> lf_commitPoint)) {
00845               /* The loading of this file has not yet been committed  */
00846               /* Hence its description could be inconsistent.                */
00847               /* Furthermore, it hasn't yet been run.  Hence its data */
00848               /* segments can't possibly reference heap allocated     */
00849               /* objects.                                      */
00850               p = p -> lf_prev;
00851           }
00852           for (; p != NIL; p = p -> lf_prev) {
00853             for (q = p -> lf_ls; q != NIL; q = q -> ls_next) {
00854               if ((q -> ls_flags & PCR_IL_SegFlags_Traced_MASK)
00855                   == PCR_IL_SegFlags_Traced_on) {
00856                 GC_add_roots_inner
00857                      ((char *)(q -> ls_addr), 
00858                       (char *)(q -> ls_addr) + q -> ls_bytes,
00859                       TRUE);
00860               }
00861             }
00862           }
00863         }
00864 }
00865 
00866 
00867 #else /* !PCR */
00868 
00869 void GC_register_dynamic_libraries(){}
00870 
00871 int GC_no_dynamic_loading;
00872 
00873 #endif /* !PCR */
00874 #endif /* !DYNAMIC_LOADING */