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

Generated by: LCOV version 1.11