LCOV - code coverage report
Current view: top level - mm/boehm-gc - dyn_load.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 49 79 62.0 %
Date: 2015-06-10 18:10:59 Functions: 4 6 66.7 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
       3             :  * Copyright (c) 1997 by Silicon Graphics.  All rights reserved.
       4             :  *
       5             :  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
       6             :  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
       7             :  *
       8             :  * Permission is hereby granted to use or copy this program
       9             :  * for any purpose,  provided the above notices are retained on all copies.
      10             :  * Permission to modify the code and to distribute modified code is granted,
      11             :  * provided the above notices are retained, and a notice that the code was
      12             :  * modified is included with the above copyright notice.
      13             :  *
      14             :  * Original author: Bill Janssen
      15             :  * Heavily modified by Hans Boehm and others
      16             :  */
      17             : 
      18             : #include "private/gc_priv.h"
      19             : 
      20             : /*
      21             :  * This is incredibly OS specific code for tracking down data sections in
      22             :  * dynamic libraries.  There appears to be no way of doing this quickly
      23             :  * without groveling through undocumented data structures.  We would argue
      24             :  * that this is a bug in the design of the dlopen interface.  THIS CODE
      25             :  * MAY BREAK IN FUTURE OS RELEASES.  If this matters to you, don't hesitate
      26             :  * to let your vendor know ...
      27             :  *
      28             :  * None of this is safe with dlclose and incremental collection.
      29             :  * But then not much of anything is safe in the presence of dlclose.
      30             :  */
      31             : 
      32             : #if !defined(MACOS) && !defined(_WIN32_WCE) && !defined(__CC_ARM)
      33             : # include <sys/types.h>
      34             : #endif
      35             : 
      36             : /* BTL: avoid circular redefinition of dlopen if GC_SOLARIS_THREADS defined */
      37             : #undef GC_MUST_RESTORE_REDEFINED_DLOPEN
      38             : #if defined(GC_PTHREADS) && !defined(GC_NO_DLOPEN) \
      39             :     && !defined(GC_NO_THREAD_REDIRECTS) && !defined(GC_USE_LD_WRAP)
      40             :   /* To support threads in Solaris, gc.h interposes on dlopen by        */
      41             :   /* defining "dlopen" to be "GC_dlopen", which is implemented below.   */
      42             :   /* However, both GC_FirstDLOpenedLinkMap() and GC_dlopen() use the    */
      43             :   /* real system dlopen() in their implementation. We first remove      */
      44             :   /* gc.h's dlopen definition and restore it later, after GC_dlopen().  */
      45             : # undef dlopen
      46             : # define GC_MUST_RESTORE_REDEFINED_DLOPEN
      47             : #endif /* !GC_NO_DLOPEN */
      48             : 
      49             : /* A user-supplied routine (custom filter) that might be called to      */
      50             : /* determine whether a DSO really needs to be scanned by the GC.        */
      51             : /* 0 means no filter installed.  May be unused on some platforms.       */
      52             : /* FIXME: Add filter support for more platforms.                        */
      53             : STATIC GC_has_static_roots_func GC_has_static_roots = 0;
      54             : 
      55             : #if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE) \
      56             :     || defined(CYGWIN32)) && !defined(PCR)
      57             : 
      58             : #if !defined(SOLARISDL) && !defined(IRIX5) && \
      59             :     !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32) && \
      60             :     !(defined(ALPHA) && defined(OSF1)) && \
      61             :     !defined(HPUX) && !(defined(LINUX) && defined(__ELF__)) && \
      62             :     !defined(AIX) && !defined(SCO_ELF) && !defined(DGUX) && \
      63             :     !(defined(FREEBSD) && defined(__ELF__)) && \
      64             :     !(defined(OPENBSD) && (defined(__ELF__) || defined(M68K))) && \
      65             :     !(defined(NETBSD) && defined(__ELF__)) && !defined(HURD) && \
      66             :     !defined(DARWIN) && !defined(CYGWIN32)
      67             :  --> We only know how to find data segments of dynamic libraries for the
      68             :  --> above.  Additional SVR4 variants might not be too
      69             :  --> hard to add.
      70             : #endif
      71             : 
      72             : #include <stdio.h>
      73             : #ifdef SOLARISDL
      74             : #   include <sys/elf.h>
      75             : #   include <dlfcn.h>
      76             : #   include <link.h>
      77             : #endif
      78             : 
      79             : #if defined(NETBSD)
      80             : #   include <sys/param.h>
      81             : #   include <dlfcn.h>
      82             : #   include <machine/elf_machdep.h>
      83             : #   define ELFSIZE ARCH_ELFSIZE
      84             : #endif
      85             : 
      86             : #if defined(SCO_ELF) || defined(DGUX) || defined(HURD) \
      87             :     || (defined(__ELF__) && (defined(LINUX) || defined(FREEBSD) \
      88             :                              || defined(NETBSD) || defined(OPENBSD)))
      89             : # include <stddef.h>
      90             : # if !defined(OPENBSD) && !defined(PLATFORM_ANDROID)
      91             :     /* FIXME: Why we exclude it for OpenBSD? */
      92             :     /* Exclude Android because linker.h below includes its own version. */
      93             : #   include <elf.h>
      94             : # endif
      95             : # ifdef PLATFORM_ANDROID
      96             :     /* The header file is in "bionic/linker" folder of Android sources. */
      97             :     /* If you don't need the "dynamic loading" feature, you may build   */
      98             :     /* the collector with -D IGNORE_DYNAMIC_LOADING.                    */
      99             : #   include <linker.h>
     100             : # else
     101             : #   include <link.h>
     102             : # endif
     103             : #endif
     104             : 
     105             : /* Newer versions of GNU/Linux define this macro.  We
     106             :  * define it similarly for any ELF systems that don't.  */
     107             : #  ifndef ElfW
     108             : #    if defined(FREEBSD)
     109             : #      if __ELF_WORD_SIZE == 32
     110             : #        define ElfW(type) Elf32_##type
     111             : #      else
     112             : #        define ElfW(type) Elf64_##type
     113             : #      endif
     114             : #    elif defined(NETBSD) || defined(OPENBSD)
     115             : #      if ELFSIZE == 32
     116             : #        define ElfW(type) Elf32_##type
     117             : #      else
     118             : #        define ElfW(type) Elf64_##type
     119             : #      endif
     120             : #    else
     121             : #      if !defined(ELF_CLASS) || ELF_CLASS == ELFCLASS32
     122             : #        define ElfW(type) Elf32_##type
     123             : #      else
     124             : #        define ElfW(type) Elf64_##type
     125             : #      endif
     126             : #    endif
     127             : #  endif
     128             : 
     129             : #if defined(SOLARISDL) && !defined(USE_PROC_FOR_LIBRARIES)
     130             : 
     131             : #ifdef LINT
     132             :     Elf32_Dyn _DYNAMIC;
     133             : #endif
     134             : 
     135             : STATIC struct link_map *
     136             : GC_FirstDLOpenedLinkMap(void)
     137             : {
     138             :     extern ElfW(Dyn) _DYNAMIC;
     139             :     ElfW(Dyn) *dp;
     140             :     static struct link_map * cachedResult = 0;
     141             :     static ElfW(Dyn) *dynStructureAddr = 0;
     142             :                 /* BTL: added to avoid Solaris 5.3 ld.so _DYNAMIC bug   */
     143             : 
     144             : #   ifdef SUNOS53_SHARED_LIB
     145             :         /* BTL: Avoid the Solaris 5.3 bug that _DYNAMIC isn't being set */
     146             :         /* up properly in dynamically linked .so's. This means we have  */
     147             :         /* to use its value in the set of original object files loaded  */
     148             :         /* at program startup.                                          */
     149             :         if( dynStructureAddr == 0 ) {
     150             :           void* startupSyms = dlopen(0, RTLD_LAZY);
     151             :           dynStructureAddr = (ElfW(Dyn)*)dlsym(startupSyms, "_DYNAMIC");
     152             :         }
     153             : #   else
     154             :         dynStructureAddr = &_DYNAMIC;
     155             : #   endif
     156             : 
     157             :     if( dynStructureAddr == 0) {
     158             :         return(0);
     159             :     }
     160             :     if( cachedResult == 0 ) {
     161             :         int tag;
     162             :         for( dp = ((ElfW(Dyn) *)(&_DYNAMIC)); (tag = dp->d_tag) != 0; dp++ ) {
     163             :             if( tag == DT_DEBUG ) {
     164             :                 struct link_map *lm
     165             :                         = ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
     166             :                 if( lm != 0 ) cachedResult = lm->l_next; /* might be NULL */
     167             :                 break;
     168             :             }
     169             :         }
     170             :     }
     171             :     return cachedResult;
     172             : }
     173             : 
     174             : #endif /* SOLARISDL ... */
     175             : 
     176             : /* BTL: added to fix circular dlopen definition if GC_SOLARIS_THREADS defined */
     177             : # ifdef GC_MUST_RESTORE_REDEFINED_DLOPEN
     178             : #   define dlopen GC_dlopen
     179             : # endif
     180             : 
     181             : # if defined(SOLARISDL)
     182             : /* Add dynamic library data sections to the root set.           */
     183             : # if !defined(PCR) && !defined(GC_SOLARIS_THREADS) && defined(THREADS)
     184             :         --> fix mutual exclusion with dlopen
     185             : # endif
     186             : 
     187             : # ifndef USE_PROC_FOR_LIBRARIES
     188             : GC_INNER void GC_register_dynamic_libraries(void)
     189             : {
     190             :   struct link_map *lm;
     191             : 
     192             :   for (lm = GC_FirstDLOpenedLinkMap(); lm != 0; lm = lm->l_next) {
     193             :         ElfW(Ehdr) * e;
     194             :         ElfW(Phdr) * p;
     195             :         unsigned long offset;
     196             :         char * start;
     197             :         int i;
     198             : 
     199             :         e = (ElfW(Ehdr) *) lm->l_addr;
     200             : #       ifdef PLATFORM_ANDROID
     201             :           if (e == NULL)
     202             :             continue;
     203             : #       endif
     204             :         p = ((ElfW(Phdr) *)(((char *)(e)) + e->e_phoff));
     205             :         offset = ((unsigned long)(lm->l_addr));
     206             :         for( i = 0; i < (int)e->e_phnum; i++, p++ ) {
     207             :           switch( p->p_type ) {
     208             :             case PT_LOAD:
     209             :               {
     210             :                 if( !(p->p_flags & PF_W) ) break;
     211             :                 start = ((char *)(p->p_vaddr)) + offset;
     212             :                 GC_add_roots_inner(
     213             :                   start,
     214             :                   start + p->p_memsz,
     215             :                   TRUE
     216             :                 );
     217             :               }
     218             :               break;
     219             :             default:
     220             :               break;
     221             :           }
     222             :         }
     223             :     }
     224             : }
     225             : 
     226             : # endif /* !USE_PROC ... */
     227             : # endif /* SOLARISDL */
     228             : 
     229             : #if defined(SCO_ELF) || defined(DGUX) || defined(HURD) \
     230             :     || (defined(__ELF__) && (defined(LINUX) || defined(FREEBSD) \
     231             :                              || defined(NETBSD) || defined(OPENBSD)))
     232             : 
     233             : #ifdef USE_PROC_FOR_LIBRARIES
     234             : 
     235             : #include <string.h>
     236             : 
     237             : #include <sys/stat.h>
     238             : #include <fcntl.h>
     239             : #include <unistd.h>
     240             : 
     241             : #define MAPS_BUF_SIZE (32*1024)
     242             : 
     243             : /* Sort an array of HeapSects by start address.                         */
     244             : /* Unfortunately at least some versions of                              */
     245             : /* Linux qsort end up calling malloc by way of sysconf, and hence can't */
     246             : /* be used in the collector.  Hence we roll our own.  Should be         */
     247             : /* reasonably fast if the array is already mostly sorted, as we expect  */
     248             : /* it to be.                                                            */
     249             : static void sort_heap_sects(struct HeapSect *base, size_t number_of_elements)
     250             : {
     251             :     signed_word n = (signed_word)number_of_elements;
     252             :     signed_word nsorted = 1;
     253             :     signed_word i;
     254             : 
     255             :     while (nsorted < n) {
     256             :       while (nsorted < n &&
     257             :              base[nsorted-1].hs_start < base[nsorted].hs_start)
     258             :           ++nsorted;
     259             :       if (nsorted == n) break;
     260             :       GC_ASSERT(base[nsorted-1].hs_start > base[nsorted].hs_start);
     261             :       i = nsorted - 1;
     262             :       while (i >= 0 && base[i].hs_start > base[i+1].hs_start) {
     263             :         struct HeapSect tmp = base[i];
     264             :         base[i] = base[i+1];
     265             :         base[i+1] = tmp;
     266             :         --i;
     267             :       }
     268             :       GC_ASSERT(base[nsorted-1].hs_start < base[nsorted].hs_start);
     269             :       ++nsorted;
     270             :     }
     271             : }
     272             : 
     273             : STATIC word GC_register_map_entries(char *maps)
     274             : {
     275             :     char *prot;
     276             :     char *buf_ptr = maps;
     277             :     ptr_t start, end;
     278             :     unsigned int maj_dev;
     279             :     ptr_t least_ha, greatest_ha;
     280             :     unsigned i;
     281             :     ptr_t datastart;
     282             : 
     283             : #   ifdef DATASTART_IS_FUNC
     284             :       static ptr_t datastart_cached = (ptr_t)(word)-1;
     285             : 
     286             :       /* Evaluate DATASTART only once.  */
     287             :       if (datastart_cached == (ptr_t)(word)-1) {
     288             :         datastart_cached = (ptr_t)(DATASTART);
     289             :       }
     290             :       datastart = datastart_cached;
     291             : #   else
     292             :       datastart = (ptr_t)(DATASTART);
     293             : #   endif
     294             : 
     295             :     GC_ASSERT(I_HOLD_LOCK());
     296             :     sort_heap_sects(GC_our_memory, GC_n_memory);
     297             :     least_ha = GC_our_memory[0].hs_start;
     298             :     greatest_ha = GC_our_memory[GC_n_memory-1].hs_start
     299             :                   + GC_our_memory[GC_n_memory-1].hs_bytes;
     300             : 
     301             :     for (;;) {
     302             :         buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, &prot,
     303             :                                      &maj_dev, 0);
     304             :         if (buf_ptr == NULL) return 1;
     305             :         if (prot[1] == 'w') {
     306             :             /* This is a writable mapping.  Add it to           */
     307             :             /* the root set unless it is already otherwise      */
     308             :             /* accounted for.                                   */
     309             :             if (start <= GC_stackbottom && end >= GC_stackbottom) {
     310             :                 /* Stack mapping; discard       */
     311             :                 continue;
     312             :             }
     313             : #           ifdef THREADS
     314             :               /* This may fail, since a thread may already be           */
     315             :               /* unregistered, but its thread stack may still be there. */
     316             :               /* That can fail because the stack may disappear while    */
     317             :               /* we're marking.  Thus the marker is, and has to be      */
     318             :               /* prepared to recover from segmentation faults.          */
     319             : 
     320             :               if (GC_segment_is_thread_stack(start, end)) continue;
     321             : 
     322             :               /* FIXME: NPTL squirrels                                  */
     323             :               /* away pointers in pieces of the stack segment that we   */
     324             :               /* don't scan.  We work around this                       */
     325             :               /* by treating anything allocated by libpthread as        */
     326             :               /* uncollectable, as we do in some other cases.           */
     327             :               /* A specifically identified problem is that              */
     328             :               /* thread stacks contain pointers to dynamic thread       */
     329             :               /* vectors, which may be reused due to thread caching.    */
     330             :               /* They may not be marked if the thread is still live.    */
     331             :               /* This specific instance should be addressed by          */
     332             :               /* INCLUDE_LINUX_THREAD_DESCR, but that doesn't quite     */
     333             :               /* seem to suffice.                                       */
     334             :               /* We currently trace entire thread stacks, if they are   */
     335             :               /* are currently cached but unused.  This is              */
     336             :               /* very suboptimal for performance reasons.               */
     337             : #           endif
     338             :             /* We no longer exclude the main data segment.              */
     339             :             if (end <= least_ha || start >= greatest_ha) {
     340             :               /* The easy case; just trace entire segment */
     341             :               GC_add_roots_inner((char *)start, (char *)end, TRUE);
     342             :               continue;
     343             :             }
     344             :             /* Add sections that don't belong to us. */
     345             :               i = 0;
     346             :               while (GC_our_memory[i].hs_start + GC_our_memory[i].hs_bytes
     347             :                      < start)
     348             :                   ++i;
     349             :               GC_ASSERT(i < GC_n_memory);
     350             :               if (GC_our_memory[i].hs_start <= start) {
     351             :                   start = GC_our_memory[i].hs_start
     352             :                           + GC_our_memory[i].hs_bytes;
     353             :                   ++i;
     354             :               }
     355             :               while (i < GC_n_memory && GC_our_memory[i].hs_start < end
     356             :                      && start < end) {
     357             :                   if ((char *)start < GC_our_memory[i].hs_start)
     358             :                     GC_add_roots_inner((char *)start,
     359             :                                        GC_our_memory[i].hs_start, TRUE);
     360             :                   start = GC_our_memory[i].hs_start
     361             :                           + GC_our_memory[i].hs_bytes;
     362             :                   ++i;
     363             :               }
     364             :               if (start < end)
     365             :                   GC_add_roots_inner((char *)start, (char *)end, TRUE);
     366             :         }
     367             :     }
     368             :     return 1;
     369             : }
     370             : 
     371             : GC_INNER void GC_register_dynamic_libraries(void)
     372             : {
     373             :     if (!GC_register_map_entries(GC_get_maps()))
     374             :         ABORT("Failed to read /proc for library registration");
     375             : }
     376             : 
     377             : /* We now take care of the main data segment ourselves: */
     378             : GC_INNER GC_bool GC_register_main_static_data(void)
     379             : {
     380             :     return FALSE;
     381             : }
     382             : 
     383             : # define HAVE_REGISTER_MAIN_STATIC_DATA
     384             : 
     385             : #else /* !USE_PROC_FOR_LIBRARIES */
     386             : 
     387             : /* The following is the preferred way to walk dynamic libraries */
     388             : /* For glibc 2.2.4+.  Unfortunately, it doesn't work for older  */
     389             : /* versions.  Thanks to Jakub Jelinek for most of the code.     */
     390             : 
     391             : #if (defined(LINUX) || defined (__GLIBC__)) /* Are others OK here, too? */ \
     392             :      && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) \
     393             :          || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && defined(DT_CONFIG)))
     394             : /* We have the header files for a glibc that includes dl_iterate_phdr.  */
     395             : /* It may still not be available in the library on the target system.   */
     396             : /* Thus we also treat it as a weak symbol.                              */
     397             : # define HAVE_DL_ITERATE_PHDR
     398             : # pragma weak dl_iterate_phdr
     399             : #endif
     400             : 
     401             : #if (defined(FREEBSD) && __FreeBSD__ >= 7)
     402             :   /* On the FreeBSD system, any target system at major version 7 shall   */
     403             :   /* have dl_iterate_phdr; therefore, we need not make it weak as above. */
     404             : # define HAVE_DL_ITERATE_PHDR
     405             : # define DL_ITERATE_PHDR_STRONG
     406             : #endif
     407             : 
     408             : #if defined(HAVE_DL_ITERATE_PHDR)
     409             : 
     410             : # ifdef PT_GNU_RELRO
     411             : /* Instead of registering PT_LOAD sections directly, we keep them       */
     412             : /* in a temporary list, and filter them by excluding PT_GNU_RELRO       */
     413             : /* segments.  Processing PT_GNU_RELRO sections with                     */
     414             : /* GC_exclude_static_roots instead would be superficially cleaner.  But */
     415             : /* it runs into trouble if a client registers an overlapping segment,   */
     416             : /* which unfortunately seems quite possible.                            */
     417             : 
     418             : #   define MAX_LOAD_SEGS MAX_ROOT_SETS
     419             : 
     420             :     static struct load_segment {
     421             :       ptr_t start;
     422             :       ptr_t end;
     423             :       /* Room for a second segment if we remove a RELRO segment */
     424             :       /* from the middle.                                       */
     425             :       ptr_t start2;
     426             :       ptr_t end2;
     427             :     } load_segs[MAX_LOAD_SEGS];
     428             : 
     429             :     static int n_load_segs;
     430             : # endif /* PT_GNU_RELRO */
     431             : 
     432        3167 : STATIC int GC_register_dynlib_callback(struct dl_phdr_info * info,
     433             :                                        size_t size, void * ptr)
     434             : {
     435             :   const ElfW(Phdr) * p;
     436             :   ptr_t start, end;
     437             :   int i;
     438             : 
     439             :   /* Make sure struct dl_phdr_info is at least as big as we need.  */
     440        3167 :   if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
     441             :       + sizeof (info->dlpi_phnum))
     442           0 :     return -1;
     443             : 
     444        3167 :   p = info->dlpi_phdr;
     445       26720 :   for( i = 0; i < (int)info->dlpi_phnum; i++, p++ ) {
     446       23553 :     switch( p->p_type ) {
     447             : #     ifdef PT_GNU_RELRO
     448             :         case PT_GNU_RELRO:
     449             :         /* This entry is known to be constant and will eventually be remapped
     450             :            read-only.  However, the address range covered by this entry is
     451             :            typically a subset of a previously encountered `LOAD' segment, so
     452             :            we need to exclude it.  */
     453             :         {
     454             :             int j;
     455             : 
     456        1601 :             start = ((ptr_t)(p->p_vaddr)) + info->dlpi_addr;
     457        1601 :             end = start + p->p_memsz;
     458        3202 :             for (j = n_load_segs; --j >= 0; ) {
     459        1601 :               if (start >= load_segs[j].start && start < load_segs[j].end) {
     460        1601 :                 if (load_segs[j].start2 != 0) {
     461           0 :                   WARN("More than one GNU_RELRO segment per load seg\n",0);
     462             :                 } else {
     463             :                   GC_ASSERT(end <= load_segs[j].end);
     464             :                   /* Remove from the existing load segment */
     465        1601 :                   load_segs[j].end2 = load_segs[j].end;
     466        1601 :                   load_segs[j].end = start;
     467        1601 :                   load_segs[j].start2 = end;
     468             :                 }
     469        1601 :                 break;
     470             :               }
     471           0 :               if (j == 0) WARN("Failed to find PT_GNU_RELRO segment"
     472             :                                " inside PT_LOAD region", 0);
     473             :             }
     474             :         }
     475             : 
     476        1601 :         break;
     477             : #     endif
     478             : 
     479             :       case PT_LOAD:
     480             :         {
     481        6082 :           GC_has_static_roots_func callback = GC_has_static_roots;
     482        6082 :           if( !(p->p_flags & PF_W) ) break;
     483        2915 :           start = ((char *)(p->p_vaddr)) + info->dlpi_addr;
     484        2915 :           end = start + p->p_memsz;
     485             : 
     486        2915 :           if (callback != 0 && !callback(info->dlpi_name, start, p->p_memsz))
     487           0 :             break;
     488             : #         ifdef PT_GNU_RELRO
     489        2915 :             if (n_load_segs >= MAX_LOAD_SEGS) ABORT("Too many PT_LOAD segs");
     490             : #           if CPP_WORDSZ == 64
     491             :               /* FIXME: GC_push_all eventually does the correct         */
     492             :               /* rounding to the next multiple of ALIGNMENT, so, most   */
     493             :               /* probably, we should remove the corresponding assertion */
     494             :               /* check in GC_add_roots_inner along with this code line. */
     495             :               /* start pointer value may require aligning */
     496        2915 :               start = (ptr_t)((word)start & ~(sizeof(word) - 1));
     497             : #           endif
     498        2915 :             load_segs[n_load_segs].start = start;
     499        2915 :             load_segs[n_load_segs].end = end;
     500        2915 :             load_segs[n_load_segs].start2 = 0;
     501        2915 :             load_segs[n_load_segs].end2 = 0;
     502        2915 :             ++n_load_segs;
     503             : #         else
     504             :             GC_add_roots_inner(start, end, TRUE);
     505             : #         endif /* PT_GNU_RELRO */
     506             :         }
     507             :       break;
     508             :       default:
     509             :         break;
     510             :     }
     511             :   }
     512             : 
     513        3167 :   *(int *)ptr = 1;     /* Signal that we were called */
     514        3167 :   return 0;
     515             : }
     516             : 
     517             : /* Do we need to separately register the main static data segment? */
     518         415 : GC_INNER GC_bool GC_register_main_static_data(void)
     519             : {
     520             : # ifdef DL_ITERATE_PHDR_STRONG
     521             :     /* If dl_iterate_phdr is not a weak symbol then don't test against  */
     522             :     /* zero (otherwise a compiler might issue a warning).               */
     523             :     return FALSE;
     524             : # else
     525         415 :     return (dl_iterate_phdr == 0); /* implicit conversion to function ptr */
     526             : # endif
     527             : }
     528             : 
     529             : /* Return TRUE if we succeed, FALSE if dl_iterate_phdr wasn't there. */
     530         252 : STATIC GC_bool GC_register_dynamic_libraries_dl_iterate_phdr(void)
     531             : {
     532             :   int did_something;
     533         252 :   if (GC_register_main_static_data())
     534           0 :     return FALSE;
     535             : 
     536             : # ifdef PT_GNU_RELRO
     537             :     {
     538             :       static GC_bool excluded_segs = FALSE;
     539         252 :       n_load_segs = 0;
     540         252 :       if (!excluded_segs) {
     541         163 :         GC_exclude_static_roots_inner((ptr_t)load_segs,
     542             :                                       (ptr_t)load_segs + sizeof(load_segs));
     543         163 :         excluded_segs = TRUE;
     544             :       }
     545             :     }
     546             : # endif
     547             : 
     548         252 :   did_something = 0;
     549         252 :   dl_iterate_phdr(GC_register_dynlib_callback, &did_something);
     550         252 :   if (did_something) {
     551             : #   ifdef PT_GNU_RELRO
     552             :       int i;
     553             : 
     554        3167 :       for (i = 0; i < n_load_segs; ++i) {
     555        2915 :         if (load_segs[i].end > load_segs[i].start) {
     556        1314 :           GC_add_roots_inner(load_segs[i].start, load_segs[i].end, TRUE);
     557             :         }
     558        2915 :         if (load_segs[i].end2 > load_segs[i].start2) {
     559        1601 :           GC_add_roots_inner(load_segs[i].start2, load_segs[i].end2, TRUE);
     560             :         }
     561             :       }
     562             : #   endif
     563             :   } else {
     564             :       char *datastart;
     565             :       char *dataend;
     566             : #     ifdef DATASTART_IS_FUNC
     567             :         static ptr_t datastart_cached = (ptr_t)(word)-1;
     568             : 
     569             :         /* Evaluate DATASTART only once.  */
     570             :         if (datastart_cached == (ptr_t)(word)-1) {
     571             :           datastart_cached = (ptr_t)(DATASTART);
     572             :         }
     573             :         datastart = (char *)datastart_cached;
     574             : #     else
     575           0 :         datastart = DATASTART;
     576             : #     endif
     577             : #     ifdef DATAEND_IS_FUNC
     578             :         {
     579             :           static ptr_t dataend_cached = 0;
     580             :           /* Evaluate DATAEND only once. */
     581             :           if (dataend_cached == 0) {
     582             :             dataend_cached = (ptr_t)(DATAEND);
     583             :           }
     584             :           dataend = (char *)dataend_cached;
     585             :         }
     586             : #     else
     587           0 :         dataend = DATAEND;
     588             : #     endif
     589             : 
     590             :       /* dl_iterate_phdr may forget the static data segment in  */
     591             :       /* statically linked executables.                         */
     592           0 :       GC_add_roots_inner(datastart, dataend, TRUE);
     593             : #     if defined(DATASTART2)
     594             :         GC_add_roots_inner(DATASTART2, (char *)(DATAEND2), TRUE);
     595             : #     endif
     596             :   }
     597         252 :   return TRUE;
     598             : }
     599             : 
     600             : # define HAVE_REGISTER_MAIN_STATIC_DATA
     601             : 
     602             : #else /* !HAVE_DL_ITERATE_PHDR */
     603             : 
     604             : /* Dynamic loading code for Linux running ELF. Somewhat tested on
     605             :  * Linux/x86, untested but hopefully should work on Linux/Alpha.
     606             :  * This code was derived from the Solaris/ELF support. Thanks to
     607             :  * whatever kind soul wrote that.  - Patrick Bridges */
     608             : 
     609             : /* This doesn't necessarily work in all cases, e.g. with preloaded
     610             :  * dynamic libraries.                                           */
     611             : 
     612             : # if defined(NETBSD) || defined(OPENBSD)
     613             : #   include <sys/exec_elf.h>
     614             :    /* for compatibility with 1.4.x */
     615             : #   ifndef DT_DEBUG
     616             : #     define DT_DEBUG   21
     617             : #   endif
     618             : #   ifndef PT_LOAD
     619             : #     define PT_LOAD    1
     620             : #   endif
     621             : #   ifndef PF_W
     622             : #     define PF_W       2
     623             : #   endif
     624             : # elif !defined(PLATFORM_ANDROID)
     625             : #  include <elf.h>
     626             : # endif
     627             : 
     628             : # ifndef PLATFORM_ANDROID
     629             : #   include <link.h>
     630             : # endif
     631             : 
     632             : #endif /* !HAVE_DL_ITERATE_PHDR */
     633             : 
     634             : #ifdef __GNUC__
     635             : # pragma weak _DYNAMIC
     636             : #endif
     637             : extern ElfW(Dyn) _DYNAMIC[];
     638             : 
     639             : STATIC struct link_map *
     640           0 : GC_FirstDLOpenedLinkMap(void)
     641             : {
     642             :     ElfW(Dyn) *dp;
     643             :     static struct link_map *cachedResult = 0;
     644             : 
     645           0 :     if( _DYNAMIC == 0) {
     646           0 :         return(0);
     647             :     }
     648           0 :     if( cachedResult == 0 ) {
     649             : #     if defined(NETBSD) && defined(RTLD_DI_LINKMAP)
     650             :         struct link_map *lm = NULL;
     651             :         if (!dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &lm))
     652             :             cachedResult = lm;
     653             : #     else
     654             :         int tag;
     655           0 :         for( dp = _DYNAMIC; (tag = dp->d_tag) != 0; dp++ ) {
     656           0 :             if( tag == DT_DEBUG ) {
     657             :                 struct link_map *lm
     658           0 :                         = ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
     659           0 :                 if( lm != 0 ) cachedResult = lm->l_next; /* might be NULL */
     660           0 :                 break;
     661             :             }
     662             :         }
     663             : #     endif /* !NETBSD || !RTLD_DI_LINKMAP */
     664             :     }
     665           0 :     return cachedResult;
     666             : }
     667             : 
     668         252 : GC_INNER void GC_register_dynamic_libraries(void)
     669             : {
     670             :   struct link_map *lm;
     671             : 
     672             : # ifdef HAVE_DL_ITERATE_PHDR
     673         252 :     if (GC_register_dynamic_libraries_dl_iterate_phdr()) {
     674         252 :         return;
     675             :     }
     676             : # endif
     677           0 :   for (lm = GC_FirstDLOpenedLinkMap(); lm != 0; lm = lm->l_next)
     678             :     {
     679             :         ElfW(Ehdr) * e;
     680             :         ElfW(Phdr) * p;
     681             :         unsigned long offset;
     682             :         char * start;
     683             :         int i;
     684             : 
     685           0 :         e = (ElfW(Ehdr) *) lm->l_addr;
     686             : #       ifdef PLATFORM_ANDROID
     687             :           if (e == NULL)
     688             :             continue;
     689             : #       endif
     690           0 :         p = ((ElfW(Phdr) *)(((char *)(e)) + e->e_phoff));
     691           0 :         offset = ((unsigned long)(lm->l_addr));
     692           0 :         for( i = 0; i < (int)e->e_phnum; i++, p++ ) {
     693           0 :           switch( p->p_type ) {
     694             :             case PT_LOAD:
     695             :               {
     696           0 :                 if( !(p->p_flags & PF_W) ) break;
     697           0 :                 start = ((char *)(p->p_vaddr)) + offset;
     698           0 :                 GC_add_roots_inner(start, start + p->p_memsz, TRUE);
     699             :               }
     700             :               break;
     701             :             default:
     702             :               break;
     703             :           }
     704             :         }
     705             :     }
     706             : }
     707             : 
     708             : #endif /* !USE_PROC_FOR_LIBRARIES */
     709             : 
     710             : #endif /* LINUX */
     711             : 
     712             : #if defined(IRIX5) || (defined(USE_PROC_FOR_LIBRARIES) && !defined(LINUX))
     713             : 
     714             : #include <sys/procfs.h>
     715             : #include <sys/stat.h>
     716             : #include <fcntl.h>
     717             : #include <elf.h>
     718             : #include <errno.h>
     719             : #include <signal.h>  /* Only for the following test. */
     720             : #ifndef _sigargs
     721             : # define IRIX6
     722             : #endif
     723             : 
     724             : /* We use /proc to track down all parts of the address space that are   */
     725             : /* mapped by the process, and throw out regions we know we shouldn't    */
     726             : /* worry about.  This may also work under other SVR4 variants.          */
     727             : GC_INNER void GC_register_dynamic_libraries(void)
     728             : {
     729             :     static int fd = -1;
     730             :     char buf[30];
     731             :     static prmap_t * addr_map = 0;
     732             :     static int current_sz = 0;  /* Number of records currently in addr_map */
     733             :     static int needed_sz;       /* Required size of addr_map            */
     734             :     int i;
     735             :     long flags;
     736             :     ptr_t start;
     737             :     ptr_t limit;
     738             :     ptr_t heap_start = HEAP_START;
     739             :     ptr_t heap_end = heap_start;
     740             : 
     741             : #   ifdef SOLARISDL
     742             : #     define MA_PHYS 0
     743             : #   endif /* SOLARISDL */
     744             : 
     745             :     if (fd < 0) {
     746             :       sprintf(buf, "/proc/%ld", (long)getpid());
     747             :         /* The above generates a lint complaint, since pid_t varies.    */
     748             :         /* It's unclear how to improve this.                            */
     749             :       fd = open(buf, O_RDONLY);
     750             :       if (fd < 0) {
     751             :         ABORT("/proc open failed");
     752             :       }
     753             :     }
     754             :     if (ioctl(fd, PIOCNMAP, &needed_sz) < 0) {
     755             :         GC_err_printf("fd = %d, errno = %d\n", fd, errno);
     756             :         ABORT("/proc PIOCNMAP ioctl failed");
     757             :     }
     758             :     if (needed_sz >= current_sz) {
     759             :         current_sz = needed_sz * 2 + 1;
     760             :                         /* Expansion, plus room for 0 record */
     761             :         addr_map = (prmap_t *)GC_scratch_alloc(
     762             :                                 (word)current_sz * sizeof(prmap_t));
     763             :         if (addr_map == NULL)
     764             :           ABORT("Insufficient memory for address map");
     765             :     }
     766             :     if (ioctl(fd, PIOCMAP, addr_map) < 0) {
     767             :         GC_err_printf("fd = %d, errno = %d, needed_sz = %d, addr_map = %p\n",
     768             :                         fd, errno, needed_sz, addr_map);
     769             :         ABORT("/proc PIOCMAP ioctl failed");
     770             :     };
     771             :     if (GC_n_heap_sects > 0) {
     772             :         heap_end = GC_heap_sects[GC_n_heap_sects-1].hs_start
     773             :                         + GC_heap_sects[GC_n_heap_sects-1].hs_bytes;
     774             :         if (heap_end < GC_scratch_last_end_ptr) heap_end = GC_scratch_last_end_ptr;
     775             :     }
     776             :     for (i = 0; i < needed_sz; i++) {
     777             :         flags = addr_map[i].pr_mflags;
     778             :         if ((flags & (MA_BREAK | MA_STACK | MA_PHYS
     779             :                       | MA_FETCHOP | MA_NOTCACHED)) != 0) goto irrelevant;
     780             :         if ((flags & (MA_READ | MA_WRITE)) != (MA_READ | MA_WRITE))
     781             :             goto irrelevant;
     782             :           /* The latter test is empirically useless in very old Irix    */
     783             :           /* versions.  Other than the                                  */
     784             :           /* main data and stack segments, everything appears to be     */
     785             :           /* mapped readable, writable, executable, and shared(!!).     */
     786             :           /* This makes no sense to me. - HB                            */
     787             :         start = (ptr_t)(addr_map[i].pr_vaddr);
     788             :         if (GC_roots_present(start)) goto irrelevant;
     789             :         if (start < heap_end && start >= heap_start)
     790             :                 goto irrelevant;
     791             : #       ifdef MMAP_STACKS
     792             :           if (GC_is_thread_stack(start)) goto irrelevant;
     793             : #       endif /* MMAP_STACKS */
     794             : 
     795             :         limit = start + addr_map[i].pr_size;
     796             :         /* The following seemed to be necessary for very old versions   */
     797             :         /* of Irix, but it has been reported to discard relevant        */
     798             :         /* segments under Irix 6.5.                                     */
     799             : #       ifndef IRIX6
     800             :           if (addr_map[i].pr_off == 0 && strncmp(start, ELFMAG, 4) == 0) {
     801             :             /* Discard text segments, i.e. 0-offset mappings against    */
     802             :             /* executable files which appear to have ELF headers.       */
     803             :             caddr_t arg;
     804             :             int obj;
     805             : #           define MAP_IRR_SZ 10
     806             :             static ptr_t map_irr[MAP_IRR_SZ];
     807             :                                         /* Known irrelevant map entries */
     808             :             static int n_irr = 0;
     809             :             struct stat buf;
     810             :             register int j;
     811             : 
     812             :             for (j = 0; j < n_irr; j++) {
     813             :                 if (map_irr[j] == start) goto irrelevant;
     814             :             }
     815             :             arg = (caddr_t)start;
     816             :             obj = ioctl(fd, PIOCOPENM, &arg);
     817             :             if (obj >= 0) {
     818             :                 fstat(obj, &buf);
     819             :                 close(obj);
     820             :                 if ((buf.st_mode & 0111) != 0) {
     821             :                     if (n_irr < MAP_IRR_SZ) {
     822             :                         map_irr[n_irr++] = start;
     823             :                     }
     824             :                     goto irrelevant;
     825             :                 }
     826             :             }
     827             :           }
     828             : #       endif /* !IRIX6 */
     829             :         GC_add_roots_inner(start, limit, TRUE);
     830             :       irrelevant: ;
     831             :     }
     832             :     /* Don't keep cached descriptor, for now.  Some kernels don't like us */
     833             :     /* to keep a /proc file descriptor around during kill -9.             */
     834             :         if (close(fd) < 0) ABORT("Couldn't close /proc file");
     835             :         fd = -1;
     836             : }
     837             : 
     838             : # endif /* USE_PROC || IRIX5 */
     839             : 
     840             : # if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
     841             : 
     842             : # ifndef WIN32_LEAN_AND_MEAN
     843             : #   define WIN32_LEAN_AND_MEAN 1
     844             : # endif
     845             : # define NOSERVICE
     846             : # include <windows.h>
     847             : # include <stdlib.h>
     848             : 
     849             :   /* We traverse the entire address space and register all segments     */
     850             :   /* that could possibly have been written to.                          */
     851             :   STATIC void GC_cond_add_roots(char *base, char * limit)
     852             :   {
     853             : #   ifdef GC_WIN32_THREADS
     854             :       char * curr_base = base;
     855             :       char * next_stack_lo;
     856             :       char * next_stack_hi;
     857             : 
     858             :       if (base == limit) return;
     859             :       for(;;) {
     860             :           GC_get_next_stack(curr_base, limit, &next_stack_lo, &next_stack_hi);
     861             :           if (next_stack_lo >= limit) break;
     862             :           if (next_stack_lo > curr_base)
     863             :             GC_add_roots_inner(curr_base, next_stack_lo, TRUE);
     864             :           curr_base = next_stack_hi;
     865             :       }
     866             :       if (curr_base < limit) GC_add_roots_inner(curr_base, limit, TRUE);
     867             : #   else
     868             :       char * stack_top
     869             :          = (char *)((word)GC_approx_sp() &
     870             :                         ~(GC_sysinfo.dwAllocationGranularity - 1));
     871             :       if (base == limit) return;
     872             :       if (limit > stack_top && base < GC_stackbottom) {
     873             :           /* Part of the stack; ignore it. */
     874             :           return;
     875             :       }
     876             :       GC_add_roots_inner(base, limit, TRUE);
     877             : #   endif
     878             :   }
     879             : 
     880             : #ifdef DYNAMIC_LOADING
     881             :   /* GC_register_main_static_data is not needed unless DYNAMIC_LOADING. */
     882             :   GC_INNER GC_bool GC_register_main_static_data(void)
     883             :   {
     884             : #   if defined(MSWINCE) || defined(CYGWIN32)
     885             :       /* Do we need to separately register the main static data segment? */
     886             :       return FALSE;
     887             : #   else
     888             :       return GC_no_win32_dlls;
     889             : #   endif
     890             :   }
     891             : # define HAVE_REGISTER_MAIN_STATIC_DATA
     892             : #endif /* DYNAMIC_LOADING */
     893             : 
     894             : # ifdef DEBUG_VIRTUALQUERY
     895             :   void GC_dump_meminfo(MEMORY_BASIC_INFORMATION *buf)
     896             :   {
     897             :     GC_printf("BaseAddress = 0x%lx, AllocationBase = 0x%lx,"
     898             :               " RegionSize = 0x%lx(%lu)\n", buf -> BaseAddress,
     899             :               buf -> AllocationBase, buf -> RegionSize, buf -> RegionSize);
     900             :     GC_printf("\tAllocationProtect = 0x%lx, State = 0x%lx, Protect = 0x%lx, "
     901             :               "Type = 0x%lx\n", buf -> AllocationProtect, buf -> State,
     902             :               buf -> Protect, buf -> Type);
     903             :   }
     904             : # endif /* DEBUG_VIRTUALQUERY */
     905             : 
     906             : # if defined(MSWINCE) || defined(CYGWIN32)
     907             :     /* FIXME: Should we really need to scan MEM_PRIVATE sections?       */
     908             :     /* For now, we don't add MEM_PRIVATE sections to the data roots for */
     909             :     /* WinCE because otherwise SEGV fault sometimes happens to occur in */
     910             :     /* GC_mark_from() (and, even if we use WRAP_MARK_SOME, WinCE prints */
     911             :     /* a "Data Abort" message to the debugging console).                */
     912             :     /* To workaround that, use -DGC_REGISTER_MEM_PRIVATE.               */
     913             : #   define GC_wnt TRUE
     914             : # endif
     915             : 
     916             :   GC_INNER void GC_register_dynamic_libraries(void)
     917             :   {
     918             :     MEMORY_BASIC_INFORMATION buf;
     919             :     size_t result;
     920             :     DWORD protect;
     921             :     LPVOID p;
     922             :     char * base;
     923             :     char * limit, * new_limit;
     924             : 
     925             : #   ifdef MSWIN32
     926             :       if (GC_no_win32_dlls) return;
     927             : #   endif
     928             :     base = limit = p = GC_sysinfo.lpMinimumApplicationAddress;
     929             :     while (p < GC_sysinfo.lpMaximumApplicationAddress) {
     930             :         result = VirtualQuery(p, &buf, sizeof(buf));
     931             : #       ifdef MSWINCE
     932             :           if (result == 0) {
     933             :             /* Page is free; advance to the next possible allocation base */
     934             :             new_limit = (char *)
     935             :                 (((DWORD) p + GC_sysinfo.dwAllocationGranularity)
     936             :                  & ~(GC_sysinfo.dwAllocationGranularity-1));
     937             :           } else
     938             : #       endif
     939             :         /* else */ {
     940             :             if (result != sizeof(buf)) {
     941             :                 ABORT("Weird VirtualQuery result");
     942             :             }
     943             :             new_limit = (char *)p + buf.RegionSize;
     944             :             protect = buf.Protect;
     945             :             if (buf.State == MEM_COMMIT
     946             :                 && (protect == PAGE_EXECUTE_READWRITE
     947             :                     || protect == PAGE_READWRITE)
     948             :                 && (buf.Type == MEM_IMAGE
     949             : #                   ifdef GC_REGISTER_MEM_PRIVATE
     950             :                       || (protect == PAGE_READWRITE && buf.Type == MEM_PRIVATE)
     951             : #                   else
     952             :                       /* There is some evidence that we cannot always   */
     953             :                       /* ignore MEM_PRIVATE sections under Windows ME   */
     954             :                       /* and predecessors.  Hence we now also check for */
     955             :                       /* that case.                                     */
     956             :                       || (!GC_wnt && buf.Type == MEM_PRIVATE)
     957             : #                   endif
     958             :                    )
     959             :                 && !GC_is_heap_base(buf.AllocationBase)) {
     960             : #               ifdef DEBUG_VIRTUALQUERY
     961             :                   GC_dump_meminfo(&buf);
     962             : #               endif
     963             :                 if ((char *)p != limit) {
     964             :                     GC_cond_add_roots(base, limit);
     965             :                     base = p;
     966             :                 }
     967             :                 limit = new_limit;
     968             :             }
     969             :         }
     970             :         if (p > (LPVOID)new_limit /* overflow */) break;
     971             :         p = (LPVOID)new_limit;
     972             :     }
     973             :     GC_cond_add_roots(base, limit);
     974             :   }
     975             : 
     976             : #endif /* MSWIN32 || MSWINCE || CYGWIN32 */
     977             : 
     978             : #if defined(ALPHA) && defined(OSF1)
     979             : 
     980             : #include <loader.h>
     981             : 
     982             : extern char *sys_errlist[];
     983             : extern int sys_nerr;
     984             : extern int errno;
     985             : 
     986             : GC_INNER void GC_register_dynamic_libraries(void)
     987             : {
     988             :   int status;
     989             :   ldr_process_t mypid;
     990             : 
     991             :   /* module */
     992             :     ldr_module_t moduleid = LDR_NULL_MODULE;
     993             :     ldr_module_info_t moduleinfo;
     994             :     size_t moduleinfosize = sizeof(moduleinfo);
     995             :     size_t modulereturnsize;
     996             : 
     997             :   /* region */
     998             :     ldr_region_t region;
     999             :     ldr_region_info_t regioninfo;
    1000             :     size_t regioninfosize = sizeof(regioninfo);
    1001             :     size_t regionreturnsize;
    1002             : 
    1003             :   /* Obtain id of this process */
    1004             :     mypid = ldr_my_process();
    1005             : 
    1006             :   /* For each module */
    1007             :     while (TRUE) {
    1008             : 
    1009             :       /* Get the next (first) module */
    1010             :         status = ldr_next_module(mypid, &moduleid);
    1011             : 
    1012             :       /* Any more modules? */
    1013             :         if (moduleid == LDR_NULL_MODULE)
    1014             :             break;    /* No more modules */
    1015             : 
    1016             :       /* Check status AFTER checking moduleid because */
    1017             :       /* of a bug in the non-shared ldr_next_module stub */
    1018             :         if (status != 0) {
    1019             :           if (GC_print_stats) {
    1020             :             GC_log_printf("dynamic_load: status = %d\n", status);
    1021             :             if (errno < sys_nerr) {
    1022             :               GC_log_printf("dynamic_load: %s\n", sys_errlist[errno]);
    1023             :             } else {
    1024             :               GC_log_printf("dynamic_load: err_code = %d\n", errno);
    1025             :             }
    1026             :           }
    1027             :           ABORT("ldr_next_module failed");
    1028             :         }
    1029             : 
    1030             :       /* Get the module information */
    1031             :         status = ldr_inq_module(mypid, moduleid, &moduleinfo,
    1032             :                                 moduleinfosize, &modulereturnsize);
    1033             :         if (status != 0 )
    1034             :             ABORT("ldr_inq_module failed");
    1035             : 
    1036             :       /* is module for the main program (i.e. nonshared portion)? */
    1037             :           if (moduleinfo.lmi_flags & LDR_MAIN)
    1038             :               continue;    /* skip the main module */
    1039             : 
    1040             : #     ifdef DL_VERBOSE
    1041             :         GC_log_printf("---Module---\n");
    1042             :         GC_log_printf("Module ID\t = %16ld\n", moduleinfo.lmi_modid);
    1043             :         GC_log_printf("Count of regions = %16d\n", moduleinfo.lmi_nregion);
    1044             :         GC_log_printf("flags for module = %16lx\n", moduleinfo.lmi_flags);
    1045             :         GC_log_printf("module pathname\t = \"%s\"\n", moduleinfo.lmi_name);
    1046             : #     endif
    1047             : 
    1048             :       /* For each region in this module */
    1049             :         for (region = 0; region < moduleinfo.lmi_nregion; region++) {
    1050             :           /* Get the region information */
    1051             :             status = ldr_inq_region(mypid, moduleid, region, &regioninfo,
    1052             :                                     regioninfosize, &regionreturnsize);
    1053             :             if (status != 0 )
    1054             :                 ABORT("ldr_inq_region failed");
    1055             : 
    1056             :           /* only process writable (data) regions */
    1057             :             if (! (regioninfo.lri_prot & LDR_W))
    1058             :                 continue;
    1059             : 
    1060             : #         ifdef DL_VERBOSE
    1061             :             GC_log_printf("--- Region ---\n");
    1062             :             GC_log_printf("Region number\t = %16ld\n",
    1063             :                           regioninfo.lri_region_no);
    1064             :             GC_log_printf("Protection flags = %016x\n", regioninfo.lri_prot);
    1065             :             GC_log_printf("Virtual address\t = %16p\n", regioninfo.lri_vaddr);
    1066             :             GC_log_printf("Mapped address\t = %16p\n",
    1067             :                           regioninfo.lri_mapaddr);
    1068             :             GC_log_printf("Region size\t = %16ld\n", regioninfo.lri_size);
    1069             :             GC_log_printf("Region name\t = \"%s\"\n", regioninfo.lri_name);
    1070             : #         endif
    1071             : 
    1072             :           /* register region as a garbage collection root */
    1073             :           GC_add_roots_inner((char *)regioninfo.lri_mapaddr,
    1074             :                         (char *)regioninfo.lri_mapaddr + regioninfo.lri_size,
    1075             :                         TRUE);
    1076             : 
    1077             :         }
    1078             :     }
    1079             : }
    1080             : #endif
    1081             : 
    1082             : #if defined(HPUX)
    1083             : 
    1084             : #include <errno.h>
    1085             : #include <dl.h>
    1086             : 
    1087             : extern char *sys_errlist[];
    1088             : extern int sys_nerr;
    1089             : 
    1090             : GC_INNER void GC_register_dynamic_libraries(void)
    1091             : {
    1092             :   int status;
    1093             :   int index = 1; /* Ordinal position in shared library search list */
    1094             :   struct shl_descriptor *shl_desc; /* Shared library info, see dl.h */
    1095             : 
    1096             :   /* For each dynamic library loaded */
    1097             :     while (TRUE) {
    1098             : 
    1099             :       /* Get info about next shared library */
    1100             :         status = shl_get(index, &shl_desc);
    1101             : 
    1102             :       /* Check if this is the end of the list or if some error occured */
    1103             :         if (status != 0) {
    1104             : #        ifdef GC_HPUX_THREADS
    1105             :            /* I've seen errno values of 0.  The man page is not clear   */
    1106             :            /* as to whether errno should get set on a -1 return.        */
    1107             :            break;
    1108             : #        else
    1109             :           if (errno == EINVAL) {
    1110             :             break; /* Moved past end of shared library list --> finished */
    1111             :           } else {
    1112             :             if (GC_print_stats) {
    1113             :               if (errno < sys_nerr) {
    1114             :                 GC_log_printf("dynamic_load: %s\n", sys_errlist[errno]);
    1115             :               } else {
    1116             :                 GC_log_printf("dynamic_load: err_code = %d\n", errno);
    1117             :               }
    1118             :             }
    1119             :             ABORT("shl_get failed");
    1120             :           }
    1121             : #        endif
    1122             :         }
    1123             : 
    1124             : #     ifdef DL_VERBOSE
    1125             :         GC_log_printf("---Shared library---\n");
    1126             :         GC_log_printf("\tfilename\t= \"%s\"\n", shl_desc->filename);
    1127             :         GC_log_printf("\tindex\t\t= %d\n", index);
    1128             :         GC_log_printf("\thandle\t\t= %08x\n",
    1129             :                       (unsigned long) shl_desc->handle);
    1130             :         GC_log_printf("\ttext seg.start\t= %08x\n", shl_desc->tstart);
    1131             :         GC_log_printf("\ttext seg.end\t= %08x\n", shl_desc->tend);
    1132             :         GC_log_printf("\tdata seg.start\t= %08x\n", shl_desc->dstart);
    1133             :         GC_log_printf("\tdata seg.end\t= %08x\n", shl_desc->dend);
    1134             :         GC_log_printf("\tref.count\t= %lu\n", shl_desc->ref_count);
    1135             : #     endif
    1136             : 
    1137             :       /* register shared library's data segment as a garbage collection root */
    1138             :         GC_add_roots_inner((char *) shl_desc->dstart,
    1139             :                            (char *) shl_desc->dend, TRUE);
    1140             : 
    1141             :         index++;
    1142             :     }
    1143             : }
    1144             : #endif /* HPUX */
    1145             : 
    1146             : #ifdef AIX
    1147             : # pragma alloca
    1148             : # include <sys/ldr.h>
    1149             : # include <sys/errno.h>
    1150             :   GC_INNER void GC_register_dynamic_libraries(void)
    1151             :   {
    1152             :         int len;
    1153             :         char *ldibuf;
    1154             :         int ldibuflen;
    1155             :         struct ld_info *ldi;
    1156             : 
    1157             :         ldibuf = alloca(ldibuflen = 8192);
    1158             : 
    1159             :         while ( (len = loadquery(L_GETINFO,ldibuf,ldibuflen)) < 0) {
    1160             :                 if (errno != ENOMEM) {
    1161             :                         ABORT("loadquery failed");
    1162             :                 }
    1163             :                 ldibuf = alloca(ldibuflen *= 2);
    1164             :         }
    1165             : 
    1166             :         ldi = (struct ld_info *)ldibuf;
    1167             :         while (ldi) {
    1168             :                 len = ldi->ldinfo_next;
    1169             :                 GC_add_roots_inner(
    1170             :                                 ldi->ldinfo_dataorg,
    1171             :                                 (ptr_t)(unsigned long)ldi->ldinfo_dataorg
    1172             :                                 + ldi->ldinfo_datasize,
    1173             :                                 TRUE);
    1174             :                 ldi = len ? (struct ld_info *)((char *)ldi + len) : 0;
    1175             :         }
    1176             :   }
    1177             : #endif /* AIX */
    1178             : 
    1179             : #ifdef DARWIN
    1180             : 
    1181             : /* __private_extern__ hack required for pre-3.4 gcc versions.   */
    1182             : #ifndef __private_extern__
    1183             : # define __private_extern__ extern
    1184             : # include <mach-o/dyld.h>
    1185             : # undef __private_extern__
    1186             : #else
    1187             : # include <mach-o/dyld.h>
    1188             : #endif
    1189             : #include <mach-o/getsect.h>
    1190             : 
    1191             : /*#define DARWIN_DEBUG*/
    1192             : 
    1193             : /* Writable sections generally available on Darwin.     */
    1194             : STATIC const struct {
    1195             :     const char *seg;
    1196             :     const char *sect;
    1197             : } GC_dyld_sections[] = {
    1198             :     { SEG_DATA, SECT_DATA },
    1199             :     /* Used by FSF GCC, but not by OS X system tools, so far.   */
    1200             :     { SEG_DATA, "__static_data" },
    1201             :     { SEG_DATA, SECT_BSS },
    1202             :     { SEG_DATA, SECT_COMMON },
    1203             :     /* FSF GCC - zero-sized object sections for targets         */
    1204             :     /*supporting section anchors.                               */
    1205             :     { SEG_DATA, "__zobj_data" },
    1206             :     { SEG_DATA, "__zobj_bss" }
    1207             : };
    1208             : 
    1209             : /* Additional writable sections:                                */
    1210             : /* GCC on Darwin constructs aligned sections "on demand", where */
    1211             : /* the alignment size is embedded in the section name.          */
    1212             : /* Furthermore, there are distinctions between sections         */
    1213             : /* containing private vs. public symbols.  It also constructs   */
    1214             : /* sections specifically for zero-sized objects, when the       */
    1215             : /* target supports section anchors.                             */
    1216             : STATIC const char * GC_dyld_add_sect_fmts[] =
    1217             : {
    1218             :   "__bss%u",
    1219             :   "__pu_bss%u",
    1220             :   "__zo_bss%u",
    1221             :   "__zo_pu_bss%u",
    1222             :   NULL
    1223             : };
    1224             : 
    1225             : /* Currently, mach-o will allow up to the max of 2^15 alignment */
    1226             : /* in an object file.                                           */
    1227             : #ifndef L2_MAX_OFILE_ALIGNMENT
    1228             : # define L2_MAX_OFILE_ALIGNMENT 15
    1229             : #endif
    1230             : 
    1231             : STATIC const char *GC_dyld_name_for_hdr(const struct GC_MACH_HEADER *hdr)
    1232             : {
    1233             :     unsigned long i, c;
    1234             :     c = _dyld_image_count();
    1235             :     for (i = 0; i < c; i++)
    1236             :       if ((const struct GC_MACH_HEADER *)_dyld_get_image_header(i) == hdr)
    1237             :         return _dyld_get_image_name(i);
    1238             :     return NULL;
    1239             : }
    1240             : 
    1241             : /* This should never be called by a thread holding the lock.    */
    1242             : STATIC void GC_dyld_image_add(const struct GC_MACH_HEADER *hdr,
    1243             :                               intptr_t slide)
    1244             : {
    1245             :   unsigned long start, end;
    1246             :   unsigned i, j;
    1247             :   const struct GC_MACH_SECTION *sec;
    1248             :   const char *name;
    1249             :   GC_has_static_roots_func callback = GC_has_static_roots;
    1250             :   char secnam[16];
    1251             :   const char *fmt;
    1252             :   DCL_LOCK_STATE;
    1253             : 
    1254             :   if (GC_no_dls) return;
    1255             : # ifdef DARWIN_DEBUG
    1256             :     name = GC_dyld_name_for_hdr(hdr);
    1257             : # else
    1258             :     name = callback != 0 ? GC_dyld_name_for_hdr(hdr) : NULL;
    1259             : # endif
    1260             :   for (i = 0; i < sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]); i++) {
    1261             :     sec = GC_GETSECTBYNAME(hdr, GC_dyld_sections[i].seg,
    1262             :                            GC_dyld_sections[i].sect);
    1263             :     if (sec == NULL || sec->size < sizeof(word))
    1264             :       continue;
    1265             :     start = slide + sec->addr;
    1266             :     end = start + sec->size;
    1267             :     LOCK();
    1268             :     /* The user callback is called holding the lock.    */
    1269             :     if (callback == 0 || callback(name, (void*)start, (size_t)sec->size)) {
    1270             : #     ifdef DARWIN_DEBUG
    1271             :         GC_log_printf(
    1272             :               "Adding section __DATA,%s at %p-%p (%lu bytes) from image %s\n",
    1273             :                GC_dyld_sections[i].sect, (void*)start, (void*)end,
    1274             :                (unsigned long)sec->size, name);
    1275             : #     endif
    1276             :       GC_add_roots_inner((ptr_t)start, (ptr_t)end, FALSE);
    1277             :     }
    1278             :     UNLOCK();
    1279             :   }
    1280             : 
    1281             :   /* Sections constructed on demand.    */
    1282             :   for (j = 0; (fmt = GC_dyld_add_sect_fmts[j]) != NULL; j++) {
    1283             :     /* Add our manufactured aligned BSS sections.       */
    1284             :     for (i = 0; i <= L2_MAX_OFILE_ALIGNMENT; i++) {
    1285             :       snprintf(secnam, sizeof(secnam), fmt, (unsigned)i);
    1286             :       sec = GC_GETSECTBYNAME(hdr, SEG_DATA, secnam);
    1287             :       if (sec == NULL || sec->size == 0)
    1288             :         continue;
    1289             :       start = slide + sec->addr;
    1290             :       end = start + sec->size;
    1291             : #     ifdef DARWIN_DEBUG
    1292             :         GC_log_printf("Adding on-demand section __DATA,%s at"
    1293             :                       " %p-%p (%lu bytes) from image %s\n",
    1294             :                       secnam, (void*)start, (void*)end,
    1295             :                       (unsigned long)sec->size, name);
    1296             : #     endif
    1297             :       GC_add_roots((char*)start, (char*)end);
    1298             :     }
    1299             :   }
    1300             : 
    1301             : # ifdef DARWIN_DEBUG
    1302             :     GC_print_static_roots();
    1303             : # endif
    1304             : }
    1305             : 
    1306             : /* This should never be called by a thread holding the lock.    */
    1307             : STATIC void GC_dyld_image_remove(const struct GC_MACH_HEADER *hdr,
    1308             :                                  intptr_t slide)
    1309             : {
    1310             :   unsigned long start, end;
    1311             :   unsigned i, j;
    1312             :   const struct GC_MACH_SECTION *sec;
    1313             :   char secnam[16];
    1314             :   const char *fmt;
    1315             : 
    1316             :   for (i = 0; i < sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]); i++) {
    1317             :     sec = GC_GETSECTBYNAME(hdr, GC_dyld_sections[i].seg,
    1318             :                            GC_dyld_sections[i].sect);
    1319             :     if (sec == NULL || sec->size == 0)
    1320             :       continue;
    1321             :     start = slide + sec->addr;
    1322             :     end = start + sec->size;
    1323             : #   ifdef DARWIN_DEBUG
    1324             :       GC_log_printf(
    1325             :             "Removing section __DATA,%s at %p-%p (%lu bytes) from image %s\n",
    1326             :             GC_dyld_sections[i].sect, (void*)start, (void*)end,
    1327             :             (unsigned long)sec->size, GC_dyld_name_for_hdr(hdr));
    1328             : #   endif
    1329             :     GC_remove_roots((char*)start, (char*)end);
    1330             :   }
    1331             : 
    1332             :   /* Remove our on-demand sections.     */
    1333             :   for (j = 0; (fmt = GC_dyld_add_sect_fmts[j]) != NULL; j++) {
    1334             :     for (i = 0; i <= L2_MAX_OFILE_ALIGNMENT; i++) {
    1335             :       snprintf(secnam, sizeof(secnam), fmt, (unsigned)i);
    1336             :       sec = GC_GETSECTBYNAME(hdr, SEG_DATA, secnam);
    1337             :       if (sec == NULL || sec->size == 0)
    1338             :         continue;
    1339             :       start = slide + sec->addr;
    1340             :       end = start + sec->size;
    1341             : #     ifdef DARWIN_DEBUG
    1342             :         GC_log_printf("Removing on-demand section __DATA,%s at"
    1343             :                       " %p-%p (%lu bytes) from image %s\n", secnam,
    1344             :                       (void*)start, (void*)end, (unsigned long)sec->size,
    1345             :                       GC_dyld_name_for_hdr(hdr));
    1346             : #     endif
    1347             :       GC_remove_roots((char*)start, (char*)end);
    1348             :     }
    1349             :   }
    1350             : 
    1351             : # ifdef DARWIN_DEBUG
    1352             :     GC_print_static_roots();
    1353             : # endif
    1354             : }
    1355             : 
    1356             : GC_INNER void GC_register_dynamic_libraries(void)
    1357             : {
    1358             :     /* Currently does nothing. The callbacks are setup by GC_init_dyld()
    1359             :     The dyld library takes it from there. */
    1360             : }
    1361             : 
    1362             : /* The _dyld_* functions have an internal lock so no _dyld functions
    1363             :    can be called while the world is stopped without the risk of a deadlock.
    1364             :    Because of this we MUST setup callbacks BEFORE we ever stop the world.
    1365             :    This should be called BEFORE any thread in created and WITHOUT the
    1366             :    allocation lock held. */
    1367             : 
    1368             : GC_INNER void GC_init_dyld(void)
    1369             : {
    1370             :   static GC_bool initialized = FALSE;
    1371             : 
    1372             :   if (initialized) return;
    1373             : 
    1374             : # ifdef DARWIN_DEBUG
    1375             :     GC_log_printf("Registering dyld callbacks...\n");
    1376             : # endif
    1377             : 
    1378             :   /* Apple's Documentation:
    1379             :      When you call _dyld_register_func_for_add_image, the dynamic linker
    1380             :      runtime calls the specified callback (func) once for each of the images
    1381             :      that is currently loaded into the program. When a new image is added to
    1382             :      the program, your callback is called again with the mach_header for the
    1383             :      new image, and the virtual memory slide amount of the new image.
    1384             : 
    1385             :      This WILL properly register already linked libraries and libraries
    1386             :      linked in the future.
    1387             :   */
    1388             : 
    1389             :   _dyld_register_func_for_add_image(GC_dyld_image_add);
    1390             :   _dyld_register_func_for_remove_image(GC_dyld_image_remove);
    1391             :       /* Ignore 2 compiler warnings here: passing argument 1 of       */
    1392             :       /* '_dyld_register_func_for_add/remove_image' from incompatible */
    1393             :       /* pointer type.                                                */
    1394             : 
    1395             :   /* Set this early to avoid reentrancy issues. */
    1396             :   initialized = TRUE;
    1397             : 
    1398             : # ifdef NO_DYLD_BIND_FULLY_IMAGE
    1399             :     /* FIXME: What should we do in this case?   */
    1400             : # else
    1401             :     if (GC_no_dls) return; /* skip main data segment registration */
    1402             : 
    1403             :     /* When the environment variable is set, the dynamic linker binds   */
    1404             :     /* all undefined symbols the application needs at launch time.      */
    1405             :     /* This includes function symbols that are normally bound lazily at */
    1406             :     /* the time of their first invocation.                              */
    1407             :     if (GETENV("DYLD_BIND_AT_LAUNCH") == 0) {
    1408             :       /* The environment variable is unset, so we should bind manually. */
    1409             : #     ifdef DARWIN_DEBUG
    1410             :         GC_log_printf("Forcing full bind of GC code...\n");
    1411             : #     endif
    1412             :       /* FIXME: '_dyld_bind_fully_image_containing_address' is deprecated. */
    1413             :       if (!_dyld_bind_fully_image_containing_address(
    1414             :                                                   (unsigned long *)GC_malloc))
    1415             :         ABORT("_dyld_bind_fully_image_containing_address failed");
    1416             :     }
    1417             : # endif
    1418             : }
    1419             : 
    1420             : #define HAVE_REGISTER_MAIN_STATIC_DATA
    1421             : GC_INNER GC_bool GC_register_main_static_data(void)
    1422             : {
    1423             :   /* Already done through dyld callbacks */
    1424             :   return FALSE;
    1425             : }
    1426             : 
    1427             : #endif /* DARWIN */
    1428             : 
    1429             : #elif defined(PCR)
    1430             : 
    1431             : # include "il/PCR_IL.h"
    1432             : # include "th/PCR_ThCtl.h"
    1433             : # include "mm/PCR_MM.h"
    1434             : 
    1435             :   GC_INNER void GC_register_dynamic_libraries(void)
    1436             :   {
    1437             :     /* Add new static data areas of dynamically loaded modules. */
    1438             :     PCR_IL_LoadedFile * p = PCR_IL_GetLastLoadedFile();
    1439             :     PCR_IL_LoadedSegment * q;
    1440             : 
    1441             :     /* Skip uncommitted files */
    1442             :     while (p != NIL && !(p -> lf_commitPoint)) {
    1443             :         /* The loading of this file has not yet been committed    */
    1444             :         /* Hence its description could be inconsistent.           */
    1445             :         /* Furthermore, it hasn't yet been run.  Hence its data   */
    1446             :         /* segments can't possibly reference heap allocated       */
    1447             :         /* objects.                                               */
    1448             :         p = p -> lf_prev;
    1449             :     }
    1450             :     for (; p != NIL; p = p -> lf_prev) {
    1451             :       for (q = p -> lf_ls; q != NIL; q = q -> ls_next) {
    1452             :         if ((q -> ls_flags & PCR_IL_SegFlags_Traced_MASK)
    1453             :             == PCR_IL_SegFlags_Traced_on) {
    1454             :           GC_add_roots_inner((char *)(q -> ls_addr),
    1455             :                              (char *)(q -> ls_addr) + q -> ls_bytes, TRUE);
    1456             :         }
    1457             :       }
    1458             :     }
    1459             :   }
    1460             : #endif /* PCR && !DYNAMIC_LOADING && !MSWIN32 */
    1461             : 
    1462             : #if !defined(HAVE_REGISTER_MAIN_STATIC_DATA) && defined(DYNAMIC_LOADING)
    1463             :   /* Do we need to separately register the main static data segment? */
    1464             :   GC_INNER GC_bool GC_register_main_static_data(void)
    1465             :   {
    1466             :     return TRUE;
    1467             :   }
    1468             : #endif /* HAVE_REGISTER_MAIN_STATIC_DATA */
    1469             : 
    1470             : /* Register a routine to filter dynamic library registration.  */
    1471           0 : GC_API void GC_CALL GC_register_has_static_roots_callback(
    1472             :                                         GC_has_static_roots_func callback)
    1473             : {
    1474           0 :     GC_has_static_roots = callback;
    1475           0 : }

Generated by: LCOV version 1.11