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) && !(__ANDROID_API__ >= 21)
113       /* link_map and r_debug are defined in link.h of NDK r10+.        */
114       /* bionic/linker/linker.h defines them too 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 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   if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
478       + sizeof (info->dlpi_phnum))
479     return -1;
480 
481   p = info->dlpi_phdr;
482   for( i = 0; i < (int)info->dlpi_phnum; i++, p++ ) {
483     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             start = ((ptr_t)(p->p_vaddr)) + info->dlpi_addr;
494             end = start + p->p_memsz;
495             for (j = n_load_segs; --j >= 0; ) {
496               if ((word)start >= (word)load_segs[j].start
497                   && (word)start < (word)load_segs[j].end) {
498                 if (load_segs[j].start2 != 0) {
499                   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                   load_segs[j].end2 = load_segs[j].end;
504                   load_segs[j].end = start;
505                   load_segs[j].start2 = end;
506                 }
507                 break;
508               }
509               if (j == 0) WARN("Failed to find PT_GNU_RELRO segment"
510                                " inside PT_LOAD region", 0);
511             }
512         }
513 
514         break;
515 #     endif
516 
517       case PT_LOAD:
518         {
519           GC_has_static_roots_func callback = GC_has_static_roots;
520           if( !(p->p_flags & PF_W) ) break;
521           start = ((char *)(p->p_vaddr)) + info->dlpi_addr;
522           end = start + p->p_memsz;
523 
524           if (callback != 0 && !callback(info->dlpi_name, start, p->p_memsz))
525             break;
526 #         ifdef PT_GNU_RELRO
527             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               start = (ptr_t)((word)start & ~(sizeof(word) - 1));
535 #           endif
536             load_segs[n_load_segs].start = start;
537             load_segs[n_load_segs].end = end;
538             load_segs[n_load_segs].start2 = 0;
539             load_segs[n_load_segs].end2 = 0;
540             ++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   *(int *)ptr = 1;     /* Signal that we were called */
552   return 0;
553 }
554 
555 /* Do we need to separately register the main static data segment? */
556 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     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 STATIC GC_bool GC_register_dynamic_libraries_dl_iterate_phdr(void)
569 {
570   int did_something;
571   if (GC_register_main_static_data())
572     return FALSE;
573 
574 # ifdef PT_GNU_RELRO
575     {
576       static GC_bool excluded_segs = FALSE;
577       n_load_segs = 0;
578       if (!EXPECT(excluded_segs, TRUE)) {
579         GC_exclude_static_roots_inner((ptr_t)load_segs,
580                                       (ptr_t)load_segs + sizeof(load_segs));
581         excluded_segs = TRUE;
582       }
583     }
584 # endif
585 
586   did_something = 0;
587   dl_iterate_phdr(GC_register_dynlib_callback, &did_something);
588   if (did_something) {
589 #   ifdef PT_GNU_RELRO
590       int i;
591 
592       for (i = 0; i < n_load_segs; ++i) {
593         if ((word)load_segs[i].end > (word)load_segs[i].start) {
594           GC_add_roots_inner(load_segs[i].start, load_segs[i].end, TRUE);
595         }
596         if ((word)load_segs[i].end2 > (word)load_segs[i].start2) {
597           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         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         dataend = DATAEND;
626 #     endif
627 
628       /* dl_iterate_phdr may forget the static data segment in  */
629       /* statically linked executables.                         */
630       GC_add_roots_inner(datastart, dataend, TRUE);
631 #     if defined(DATASTART2)
632         GC_add_roots_inner(DATASTART2, (char *)(DATAEND2), TRUE);
633 #     endif
634   }
635   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 GC_FirstDLOpenedLinkMap(void)
679 {
680     ElfW(Dyn) *dp;
681     static struct link_map *cachedResult = 0;
682 
683     if (0 == (ptr_t)_DYNAMIC) {
684         /* _DYNAMIC symbol not resolved. */
685         return(0);
686     }
687     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) && lm != NULL) {
691             /* Now lm points link_map object of libgc.  Since it    */
692             /* might not be the first dynamically linked object,    */
693             /* try to find it (object next to the main object).     */
694             while (lm->l_prev != NULL) {
695                 lm = lm->l_prev;
696             }
697             cachedResult = lm->l_next;
698         }
699 #     else
700         int tag;
701         for( dp = _DYNAMIC; (tag = dp->d_tag) != 0; dp++ ) {
702             if( tag == DT_DEBUG ) {
703                 struct link_map *lm
704                         = ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
705                 if( lm != 0 ) cachedResult = lm->l_next; /* might be NULL */
706                 break;
707             }
708         }
709 #     endif /* !NETBSD || !RTLD_DI_LINKMAP */
710     }
711     return cachedResult;
712 }
713 
714 GC_INNER void GC_register_dynamic_libraries(void)
715 {
716   struct link_map *lm;
717 
718 # ifdef HAVE_DL_ITERATE_PHDR
719     if (GC_register_dynamic_libraries_dl_iterate_phdr()) {
720         return;
721     }
722 # endif
723   for (lm = GC_FirstDLOpenedLinkMap(); lm != 0; lm = lm->l_next)
724     {
725         ElfW(Ehdr) * e;
726         ElfW(Phdr) * p;
727         unsigned long offset;
728         char * start;
729         int i;
730 
731         e = (ElfW(Ehdr) *) lm->l_addr;
732 #       ifdef PLATFORM_ANDROID
733           if (e == NULL)
734             continue;
735 #       endif
736         p = ((ElfW(Phdr) *)(((char *)(e)) + e->e_phoff));
737         offset = ((unsigned long)(lm->l_addr));
738         for( i = 0; i < (int)e->e_phnum; i++, p++ ) {
739           switch( p->p_type ) {
740             case PT_LOAD:
741               {
742                 if( !(p->p_flags & PF_W) ) break;
743                 start = ((char *)(p->p_vaddr)) + offset;
744                 GC_add_roots_inner(start, start + p->p_memsz, TRUE);
745               }
746               break;
747             default:
748               break;
749           }
750         }
751     }
752 }
753 
754 #endif /* !USE_PROC_FOR_LIBRARIES */
755 
756 #endif /* LINUX */
757 
758 #if defined(IRIX5) || (defined(USE_PROC_FOR_LIBRARIES) && !defined(LINUX))
759 
760 #include <sys/procfs.h>
761 #include <sys/stat.h>
762 #include <fcntl.h>
763 #include <elf.h>
764 #include <errno.h>
765 #include <signal.h>  /* Only for the following test. */
766 #ifndef _sigargs
767 # define IRIX6
768 #endif
769 
770 /* We use /proc to track down all parts of the address space that are   */
771 /* mapped by the process, and throw out regions we know we shouldn't    */
772 /* worry about.  This may also work under other SVR4 variants.          */
773 GC_INNER void GC_register_dynamic_libraries(void)
774 {
775     static int fd = -1;
776     char buf[30];
777     static prmap_t * addr_map = 0;
778     static int current_sz = 0;  /* Number of records currently in addr_map */
779     static int needed_sz;       /* Required size of addr_map            */
780     int i;
781     long flags;
782     ptr_t start;
783     ptr_t limit;
784     ptr_t heap_start = HEAP_START;
785     ptr_t heap_end = heap_start;
786 
787 #   ifdef SOLARISDL
788 #     define MA_PHYS 0
789 #   endif /* SOLARISDL */
790 
791     if (fd < 0) {
792       (void)snprintf(buf, sizeof(buf), "/proc/%ld", (long)getpid());
793       buf[sizeof(buf) - 1] = '\0';
794         /* The above generates a lint complaint, since pid_t varies.    */
795         /* It's unclear how to improve this.                            */
796       fd = open(buf, O_RDONLY);
797       if (fd < 0) {
798         ABORT("/proc open failed");
799       }
800     }
801     if (ioctl(fd, PIOCNMAP, &needed_sz) < 0) {
802         ABORT_ARG2("/proc PIOCNMAP ioctl failed",
803                    ": fd = %d, errno = %d", fd, errno);
804     }
805     if (needed_sz >= current_sz) {
806         current_sz = needed_sz * 2 + 1;
807                         /* Expansion, plus room for 0 record */
808         addr_map = (prmap_t *)GC_scratch_alloc(
809                                 (word)current_sz * sizeof(prmap_t));
810         if (addr_map == NULL)
811           ABORT("Insufficient memory for address map");
812     }
813     if (ioctl(fd, PIOCMAP, addr_map) < 0) {
814         ABORT_ARG3("/proc PIOCMAP ioctl failed",
815                    ": errcode= %d, needed_sz= %d, addr_map= %p",
816                    errno, needed_sz, addr_map);
817     };
818     if (GC_n_heap_sects > 0) {
819         heap_end = GC_heap_sects[GC_n_heap_sects-1].hs_start
820                         + GC_heap_sects[GC_n_heap_sects-1].hs_bytes;
821         if ((word)heap_end < (word)GC_scratch_last_end_ptr)
822           heap_end = GC_scratch_last_end_ptr;
823     }
824     for (i = 0; i < needed_sz; i++) {
825         flags = addr_map[i].pr_mflags;
826         if ((flags & (MA_BREAK | MA_STACK | MA_PHYS
827                       | MA_FETCHOP | MA_NOTCACHED)) != 0) goto irrelevant;
828         if ((flags & (MA_READ | MA_WRITE)) != (MA_READ | MA_WRITE))
829             goto irrelevant;
830           /* The latter test is empirically useless in very old Irix    */
831           /* versions.  Other than the                                  */
832           /* main data and stack segments, everything appears to be     */
833           /* mapped readable, writable, executable, and shared(!!).     */
834           /* This makes no sense to me. - HB                            */
835         start = (ptr_t)(addr_map[i].pr_vaddr);
836         if (GC_roots_present(start)) goto irrelevant;
837         if ((word)start < (word)heap_end && (word)start >= (word)heap_start)
838                 goto irrelevant;
839 
840         limit = start + addr_map[i].pr_size;
841         /* The following seemed to be necessary for very old versions   */
842         /* of Irix, but it has been reported to discard relevant        */
843         /* segments under Irix 6.5.                                     */
844 #       ifndef IRIX6
845           if (addr_map[i].pr_off == 0 && strncmp(start, ELFMAG, 4) == 0) {
846             /* Discard text segments, i.e. 0-offset mappings against    */
847             /* executable files which appear to have ELF headers.       */
848             caddr_t arg;
849             int obj;
850 #           define MAP_IRR_SZ 10
851             static ptr_t map_irr[MAP_IRR_SZ];
852                                         /* Known irrelevant map entries */
853             static int n_irr = 0;
854             struct stat buf;
855             register int j;
856 
857             for (j = 0; j < n_irr; j++) {
858                 if (map_irr[j] == start) goto irrelevant;
859             }
860             arg = (caddr_t)start;
861             obj = ioctl(fd, PIOCOPENM, &arg);
862             if (obj >= 0) {
863                 fstat(obj, &buf);
864                 close(obj);
865                 if ((buf.st_mode & 0111) != 0) {
866                     if (n_irr < MAP_IRR_SZ) {
867                         map_irr[n_irr++] = start;
868                     }
869                     goto irrelevant;
870                 }
871             }
872           }
873 #       endif /* !IRIX6 */
874         GC_add_roots_inner(start, limit, TRUE);
875       irrelevant: ;
876     }
877     /* Don't keep cached descriptor, for now.  Some kernels don't like us */
878     /* to keep a /proc file descriptor around during kill -9.             */
879         if (close(fd) < 0) ABORT("Couldn't close /proc file");
880         fd = -1;
881 }
882 
883 # endif /* USE_PROC || IRIX5 */
884 
885 # if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
886 
887 # ifndef WIN32_LEAN_AND_MEAN
888 #   define WIN32_LEAN_AND_MEAN 1
889 # endif
890 # define NOSERVICE
891 # include <windows.h>
892 # include <stdlib.h>
893 
894   /* We traverse the entire address space and register all segments     */
895   /* that could possibly have been written to.                          */
896   STATIC void GC_cond_add_roots(char *base, char * limit)
897   {
898 #   ifdef GC_WIN32_THREADS
899       char * curr_base = base;
900       char * next_stack_lo;
901       char * next_stack_hi;
902 
903       if (base == limit) return;
904       for(;;) {
905           GC_get_next_stack(curr_base, limit, &next_stack_lo, &next_stack_hi);
906           if ((word)next_stack_lo >= (word)limit) break;
907           if ((word)next_stack_lo > (word)curr_base)
908             GC_add_roots_inner(curr_base, next_stack_lo, TRUE);
909           curr_base = next_stack_hi;
910       }
911       if ((word)curr_base < (word)limit)
912         GC_add_roots_inner(curr_base, limit, TRUE);
913 #   else
914       char * stack_top
915          = (char *)((word)GC_approx_sp() &
916                         ~(GC_sysinfo.dwAllocationGranularity - 1));
917 
918       if (base == limit) return;
919       if ((word)limit > (word)stack_top
920           && (word)base < (word)GC_stackbottom) {
921           /* Part of the stack; ignore it. */
922           return;
923       }
924       GC_add_roots_inner(base, limit, TRUE);
925 #   endif
926   }
927 
928 #ifdef DYNAMIC_LOADING
929   /* GC_register_main_static_data is not needed unless DYNAMIC_LOADING. */
930   GC_INNER GC_bool GC_register_main_static_data(void)
931   {
932 #   if defined(MSWINCE) || defined(CYGWIN32)
933       /* Do we need to separately register the main static data segment? */
934       return FALSE;
935 #   else
936       return GC_no_win32_dlls;
937 #   endif
938   }
939 # define HAVE_REGISTER_MAIN_STATIC_DATA
940 #endif /* DYNAMIC_LOADING */
941 
942 # ifdef DEBUG_VIRTUALQUERY
943   void GC_dump_meminfo(MEMORY_BASIC_INFORMATION *buf)
944   {
945     GC_printf("BaseAddress = 0x%lx, AllocationBase = 0x%lx,"
946               " RegionSize = 0x%lx(%lu)\n", buf -> BaseAddress,
947               buf -> AllocationBase, buf -> RegionSize, buf -> RegionSize);
948     GC_printf("\tAllocationProtect = 0x%lx, State = 0x%lx, Protect = 0x%lx, "
949               "Type = 0x%lx\n", buf -> AllocationProtect, buf -> State,
950               buf -> Protect, buf -> Type);
951   }
952 # endif /* DEBUG_VIRTUALQUERY */
953 
954 # if defined(MSWINCE) || defined(CYGWIN32)
955     /* FIXME: Should we really need to scan MEM_PRIVATE sections?       */
956     /* For now, we don't add MEM_PRIVATE sections to the data roots for */
957     /* WinCE because otherwise SEGV fault sometimes happens to occur in */
958     /* GC_mark_from() (and, even if we use WRAP_MARK_SOME, WinCE prints */
959     /* a "Data Abort" message to the debugging console).                */
960     /* To workaround that, use -DGC_REGISTER_MEM_PRIVATE.               */
961 #   define GC_wnt TRUE
962 # endif
963 
964   GC_INNER void GC_register_dynamic_libraries(void)
965   {
966     MEMORY_BASIC_INFORMATION buf;
967     size_t result;
968     DWORD protect;
969     LPVOID p;
970     char * base;
971     char * limit, * new_limit;
972 
973 #   ifdef MSWIN32
974       if (GC_no_win32_dlls) return;
975 #   endif
976     base = limit = p = GC_sysinfo.lpMinimumApplicationAddress;
977     while ((word)p < (word)GC_sysinfo.lpMaximumApplicationAddress) {
978         result = VirtualQuery(p, &buf, sizeof(buf));
979 #       ifdef MSWINCE
980           if (result == 0) {
981             /* Page is free; advance to the next possible allocation base */
982             new_limit = (char *)
983                 (((DWORD) p + GC_sysinfo.dwAllocationGranularity)
984                  & ~(GC_sysinfo.dwAllocationGranularity-1));
985           } else
986 #       endif
987         /* else */ {
988             if (result != sizeof(buf)) {
989                 ABORT("Weird VirtualQuery result");
990             }
991             new_limit = (char *)p + buf.RegionSize;
992             protect = buf.Protect;
993             if (buf.State == MEM_COMMIT
994                 && (protect == PAGE_EXECUTE_READWRITE
995                     || protect == PAGE_READWRITE)
996                 && (buf.Type == MEM_IMAGE
997 #                   ifdef GC_REGISTER_MEM_PRIVATE
998                       || (protect == PAGE_READWRITE && buf.Type == MEM_PRIVATE)
999 #                   else
1000                       /* There is some evidence that we cannot always   */
1001                       /* ignore MEM_PRIVATE sections under Windows ME   */
1002                       /* and predecessors.  Hence we now also check for */
1003                       /* that case.                                     */
1004                       || (!GC_wnt && buf.Type == MEM_PRIVATE)
1005 #                   endif
1006                    )
1007                 && !GC_is_heap_base(buf.AllocationBase)) {
1008 #               ifdef DEBUG_VIRTUALQUERY
1009                   GC_dump_meminfo(&buf);
1010 #               endif
1011                 if ((char *)p != limit) {
1012                     GC_cond_add_roots(base, limit);
1013                     base = p;
1014                 }
1015                 limit = new_limit;
1016             }
1017         }
1018         if ((word)p > (word)new_limit /* overflow */) break;
1019         p = (LPVOID)new_limit;
1020     }
1021     GC_cond_add_roots(base, limit);
1022   }
1023 
1024 #endif /* MSWIN32 || MSWINCE || CYGWIN32 */
1025 
1026 #if defined(ALPHA) && defined(OSF1)
1027 
1028 #include <loader.h>
1029 
1030 extern char *sys_errlist[];
1031 extern int sys_nerr;
1032 extern int errno;
1033 
1034 GC_INNER void GC_register_dynamic_libraries(void)
1035 {
1036   int status;
1037   ldr_process_t mypid;
1038 
1039   /* module */
1040     ldr_module_t moduleid = LDR_NULL_MODULE;
1041     ldr_module_info_t moduleinfo;
1042     size_t moduleinfosize = sizeof(moduleinfo);
1043     size_t modulereturnsize;
1044 
1045   /* region */
1046     ldr_region_t region;
1047     ldr_region_info_t regioninfo;
1048     size_t regioninfosize = sizeof(regioninfo);
1049     size_t regionreturnsize;
1050 
1051   /* Obtain id of this process */
1052     mypid = ldr_my_process();
1053 
1054   /* For each module */
1055     while (TRUE) {
1056 
1057       /* Get the next (first) module */
1058         status = ldr_next_module(mypid, &moduleid);
1059 
1060       /* Any more modules? */
1061         if (moduleid == LDR_NULL_MODULE)
1062             break;    /* No more modules */
1063 
1064       /* Check status AFTER checking moduleid because       */
1065       /* of a bug in the non-shared ldr_next_module stub.   */
1066         if (status != 0) {
1067           ABORT_ARG3("ldr_next_module failed",
1068                      ": status= %d, errcode= %d (%s)", status, errno,
1069                      errno < sys_nerr ? sys_errlist[errno] : "");
1070         }
1071 
1072       /* Get the module information */
1073         status = ldr_inq_module(mypid, moduleid, &moduleinfo,
1074                                 moduleinfosize, &modulereturnsize);
1075         if (status != 0 )
1076             ABORT("ldr_inq_module failed");
1077 
1078       /* is module for the main program (i.e. nonshared portion)? */
1079           if (moduleinfo.lmi_flags & LDR_MAIN)
1080               continue;    /* skip the main module */
1081 
1082 #     ifdef DL_VERBOSE
1083         GC_log_printf("---Module---\n");
1084         GC_log_printf("Module ID\t = %16ld\n", moduleinfo.lmi_modid);
1085         GC_log_printf("Count of regions = %16d\n", moduleinfo.lmi_nregion);
1086         GC_log_printf("flags for module = %16lx\n", moduleinfo.lmi_flags);
1087         GC_log_printf("module pathname\t = \"%s\"\n", moduleinfo.lmi_name);
1088 #     endif
1089 
1090       /* For each region in this module */
1091         for (region = 0; region < moduleinfo.lmi_nregion; region++) {
1092           /* Get the region information */
1093             status = ldr_inq_region(mypid, moduleid, region, &regioninfo,
1094                                     regioninfosize, &regionreturnsize);
1095             if (status != 0 )
1096                 ABORT("ldr_inq_region failed");
1097 
1098           /* only process writable (data) regions */
1099             if (! (regioninfo.lri_prot & LDR_W))
1100                 continue;
1101 
1102 #         ifdef DL_VERBOSE
1103             GC_log_printf("--- Region ---\n");
1104             GC_log_printf("Region number\t = %16ld\n",
1105                           regioninfo.lri_region_no);
1106             GC_log_printf("Protection flags = %016x\n", regioninfo.lri_prot);
1107             GC_log_printf("Virtual address\t = %16p\n", regioninfo.lri_vaddr);
1108             GC_log_printf("Mapped address\t = %16p\n",
1109                           regioninfo.lri_mapaddr);
1110             GC_log_printf("Region size\t = %16ld\n", regioninfo.lri_size);
1111             GC_log_printf("Region name\t = \"%s\"\n", regioninfo.lri_name);
1112 #         endif
1113 
1114           /* register region as a garbage collection root */
1115           GC_add_roots_inner((char *)regioninfo.lri_mapaddr,
1116                         (char *)regioninfo.lri_mapaddr + regioninfo.lri_size,
1117                         TRUE);
1118 
1119         }
1120     }
1121 }
1122 #endif
1123 
1124 #if defined(HPUX)
1125 
1126 #include <errno.h>
1127 #include <dl.h>
1128 
1129 extern char *sys_errlist[];
1130 extern int sys_nerr;
1131 
1132 GC_INNER void GC_register_dynamic_libraries(void)
1133 {
1134   int status;
1135   int index = 1; /* Ordinal position in shared library search list */
1136   struct shl_descriptor *shl_desc; /* Shared library info, see dl.h */
1137 
1138   /* For each dynamic library loaded */
1139     while (TRUE) {
1140 
1141       /* Get info about next shared library */
1142         status = shl_get(index, &shl_desc);
1143 
1144       /* Check if this is the end of the list or if some error occurred */
1145         if (status != 0) {
1146 #        ifdef GC_HPUX_THREADS
1147            /* I've seen errno values of 0.  The man page is not clear   */
1148            /* as to whether errno should get set on a -1 return.        */
1149            break;
1150 #        else
1151           if (errno == EINVAL) {
1152             break; /* Moved past end of shared library list --> finished */
1153           } else {
1154             ABORT_ARG3("shl_get failed",
1155                        ": status= %d, errcode= %d (%s)", status, errno,
1156                        errno < sys_nerr ? sys_errlist[errno] : "");
1157           }
1158 #        endif
1159         }
1160 
1161 #     ifdef DL_VERBOSE
1162         GC_log_printf("---Shared library---\n");
1163         GC_log_printf("\tfilename\t= \"%s\"\n", shl_desc->filename);
1164         GC_log_printf("\tindex\t\t= %d\n", index);
1165         GC_log_printf("\thandle\t\t= %08x\n",
1166                       (unsigned long) shl_desc->handle);
1167         GC_log_printf("\ttext seg.start\t= %08x\n", shl_desc->tstart);
1168         GC_log_printf("\ttext seg.end\t= %08x\n", shl_desc->tend);
1169         GC_log_printf("\tdata seg.start\t= %08x\n", shl_desc->dstart);
1170         GC_log_printf("\tdata seg.end\t= %08x\n", shl_desc->dend);
1171         GC_log_printf("\tref.count\t= %lu\n", shl_desc->ref_count);
1172 #     endif
1173 
1174       /* register shared library's data segment as a garbage collection root */
1175         GC_add_roots_inner((char *) shl_desc->dstart,
1176                            (char *) shl_desc->dend, TRUE);
1177 
1178         index++;
1179     }
1180 }
1181 #endif /* HPUX */
1182 
1183 #ifdef AIX
1184 # pragma alloca
1185 # include <sys/ldr.h>
1186 # include <sys/errno.h>
1187   GC_INNER void GC_register_dynamic_libraries(void)
1188   {
1189         int len;
1190         char *ldibuf;
1191         int ldibuflen;
1192         struct ld_info *ldi;
1193 
1194         ldibuf = alloca(ldibuflen = 8192);
1195 
1196         while ( (len = loadquery(L_GETINFO,ldibuf,ldibuflen)) < 0) {
1197                 if (errno != ENOMEM) {
1198                         ABORT("loadquery failed");
1199                 }
1200                 ldibuf = alloca(ldibuflen *= 2);
1201         }
1202 
1203         ldi = (struct ld_info *)ldibuf;
1204         while (ldi) {
1205                 len = ldi->ldinfo_next;
1206                 GC_add_roots_inner(
1207                                 ldi->ldinfo_dataorg,
1208                                 (ptr_t)(unsigned long)ldi->ldinfo_dataorg
1209                                 + ldi->ldinfo_datasize,
1210                                 TRUE);
1211                 ldi = len ? (struct ld_info *)((char *)ldi + len) : 0;
1212         }
1213   }
1214 #endif /* AIX */
1215 
1216 #ifdef DARWIN
1217 
1218 /* __private_extern__ hack required for pre-3.4 gcc versions.   */
1219 #ifndef __private_extern__
1220 # define __private_extern__ extern
1221 # include <mach-o/dyld.h>
1222 # undef __private_extern__
1223 #else
1224 # include <mach-o/dyld.h>
1225 #endif
1226 #include <mach-o/getsect.h>
1227 
1228 /*#define DARWIN_DEBUG*/
1229 
1230 /* Writable sections generally available on Darwin.     */
1231 STATIC const struct {
1232     const char *seg;
1233     const char *sect;
1234 } GC_dyld_sections[] = {
1235     { SEG_DATA, SECT_DATA },
1236     /* Used by FSF GCC, but not by OS X system tools, so far.   */
1237     { SEG_DATA, "__static_data" },
1238     { SEG_DATA, SECT_BSS },
1239     { SEG_DATA, SECT_COMMON },
1240     /* FSF GCC - zero-sized object sections for targets         */
1241     /*supporting section anchors.                               */
1242     { SEG_DATA, "__zobj_data" },
1243     { SEG_DATA, "__zobj_bss" }
1244 };
1245 
1246 /* Additional writable sections:                                */
1247 /* GCC on Darwin constructs aligned sections "on demand", where */
1248 /* the alignment size is embedded in the section name.          */
1249 /* Furthermore, there are distinctions between sections         */
1250 /* containing private vs. public symbols.  It also constructs   */
1251 /* sections specifically for zero-sized objects, when the       */
1252 /* target supports section anchors.                             */
1253 STATIC const char * const GC_dyld_add_sect_fmts[] = {
1254   "__bss%u",
1255   "__pu_bss%u",
1256   "__zo_bss%u",
1257   "__zo_pu_bss%u"
1258 };
1259 
1260 /* Currently, mach-o will allow up to the max of 2^15 alignment */
1261 /* in an object file.                                           */
1262 #ifndef L2_MAX_OFILE_ALIGNMENT
1263 # define L2_MAX_OFILE_ALIGNMENT 15
1264 #endif
1265 
1266 STATIC const char *GC_dyld_name_for_hdr(const struct GC_MACH_HEADER *hdr)
1267 {
1268     unsigned long i, c;
1269     c = _dyld_image_count();
1270     for (i = 0; i < c; i++)
1271       if ((const struct GC_MACH_HEADER *)_dyld_get_image_header(i) == hdr)
1272         return _dyld_get_image_name(i);
1273     return NULL;
1274 }
1275 
1276 /* This should never be called by a thread holding the lock.    */
1277 STATIC void GC_dyld_image_add(const struct GC_MACH_HEADER *hdr,
1278                               intptr_t slide)
1279 {
1280   unsigned long start, end;
1281   unsigned i, j;
1282   const struct GC_MACH_SECTION *sec;
1283   const char *name;
1284   GC_has_static_roots_func callback = GC_has_static_roots;
1285   char secnam[16];
1286   const char *fmt;
1287   DCL_LOCK_STATE;
1288 
1289   if (GC_no_dls) return;
1290 # ifdef DARWIN_DEBUG
1291     name = GC_dyld_name_for_hdr(hdr);
1292 # else
1293     name = callback != 0 ? GC_dyld_name_for_hdr(hdr) : NULL;
1294 # endif
1295   for (i = 0; i < sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]); i++) {
1296     sec = GC_GETSECTBYNAME(hdr, GC_dyld_sections[i].seg,
1297                            GC_dyld_sections[i].sect);
1298     if (sec == NULL || sec->size < sizeof(word))
1299       continue;
1300     start = slide + sec->addr;
1301     end = start + sec->size;
1302     LOCK();
1303     /* The user callback is called holding the lock.    */
1304     if (callback == 0 || callback(name, (void*)start, (size_t)sec->size)) {
1305 #     ifdef DARWIN_DEBUG
1306         GC_log_printf(
1307               "Adding section __DATA,%s at %p-%p (%lu bytes) from image %s\n",
1308                GC_dyld_sections[i].sect, (void*)start, (void*)end,
1309                (unsigned long)sec->size, name);
1310 #     endif
1311       GC_add_roots_inner((ptr_t)start, (ptr_t)end, FALSE);
1312     }
1313     UNLOCK();
1314   }
1315 
1316   /* Sections constructed on demand.    */
1317   for (j = 0; j < sizeof(GC_dyld_add_sect_fmts) / sizeof(char *); j++) {
1318     fmt = GC_dyld_add_sect_fmts[j];
1319     /* Add our manufactured aligned BSS sections.       */
1320     for (i = 0; i <= L2_MAX_OFILE_ALIGNMENT; i++) {
1321       (void)snprintf(secnam, sizeof(secnam), fmt, (unsigned)i);
1322       secnam[sizeof(secnam) - 1] = '\0';
1323       sec = GC_GETSECTBYNAME(hdr, SEG_DATA, secnam);
1324       if (sec == NULL || sec->size == 0)
1325         continue;
1326       start = slide + sec->addr;
1327       end = start + sec->size;
1328 #     ifdef DARWIN_DEBUG
1329         GC_log_printf("Adding on-demand section __DATA,%s at"
1330                       " %p-%p (%lu bytes) from image %s\n",
1331                       secnam, (void*)start, (void*)end,
1332                       (unsigned long)sec->size, name);
1333 #     endif
1334       GC_add_roots((char*)start, (char*)end);
1335     }
1336   }
1337 
1338 # ifdef DARWIN_DEBUG
1339     GC_print_static_roots();
1340 # endif
1341 }
1342 
1343 /* This should never be called by a thread holding the lock.    */
1344 STATIC void GC_dyld_image_remove(const struct GC_MACH_HEADER *hdr,
1345                                  intptr_t slide)
1346 {
1347   unsigned long start, end;
1348   unsigned i, j;
1349   const struct GC_MACH_SECTION *sec;
1350   char secnam[16];
1351   const char *fmt;
1352 
1353   for (i = 0; i < sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]); i++) {
1354     sec = GC_GETSECTBYNAME(hdr, GC_dyld_sections[i].seg,
1355                            GC_dyld_sections[i].sect);
1356     if (sec == NULL || sec->size == 0)
1357       continue;
1358     start = slide + sec->addr;
1359     end = start + sec->size;
1360 #   ifdef DARWIN_DEBUG
1361       GC_log_printf(
1362             "Removing section __DATA,%s at %p-%p (%lu bytes) from image %s\n",
1363             GC_dyld_sections[i].sect, (void*)start, (void*)end,
1364             (unsigned long)sec->size, GC_dyld_name_for_hdr(hdr));
1365 #   endif
1366     GC_remove_roots((char*)start, (char*)end);
1367   }
1368 
1369   /* Remove our on-demand sections.     */
1370   for (j = 0; j < sizeof(GC_dyld_add_sect_fmts) / sizeof(char *); j++) {
1371     fmt = GC_dyld_add_sect_fmts[j];
1372     for (i = 0; i <= L2_MAX_OFILE_ALIGNMENT; i++) {
1373       (void)snprintf(secnam, sizeof(secnam), fmt, (unsigned)i);
1374       secnam[sizeof(secnam) - 1] = '\0';
1375       sec = GC_GETSECTBYNAME(hdr, SEG_DATA, secnam);
1376       if (sec == NULL || sec->size == 0)
1377         continue;
1378       start = slide + sec->addr;
1379       end = start + sec->size;
1380 #     ifdef DARWIN_DEBUG
1381         GC_log_printf("Removing on-demand section __DATA,%s at"
1382                       " %p-%p (%lu bytes) from image %s\n", secnam,
1383                       (void*)start, (void*)end, (unsigned long)sec->size,
1384                       GC_dyld_name_for_hdr(hdr));
1385 #     endif
1386       GC_remove_roots((char*)start, (char*)end);
1387     }
1388   }
1389 
1390 # ifdef DARWIN_DEBUG
1391     GC_print_static_roots();
1392 # endif
1393 }
1394 
1395 GC_INNER void GC_register_dynamic_libraries(void)
1396 {
1397     /* Currently does nothing. The callbacks are setup by GC_init_dyld()
1398     The dyld library takes it from there. */
1399 }
1400 
1401 /* The _dyld_* functions have an internal lock so no _dyld functions
1402    can be called while the world is stopped without the risk of a deadlock.
1403    Because of this we MUST setup callbacks BEFORE we ever stop the world.
1404    This should be called BEFORE any thread in created and WITHOUT the
1405    allocation lock held. */
1406 
1407 GC_INNER void GC_init_dyld(void)
1408 {
1409   static GC_bool initialized = FALSE;
1410 
1411   if (initialized) return;
1412 
1413 # ifdef DARWIN_DEBUG
1414     GC_log_printf("Registering dyld callbacks...\n");
1415 # endif
1416 
1417   /* Apple's Documentation:
1418      When you call _dyld_register_func_for_add_image, the dynamic linker
1419      runtime calls the specified callback (func) once for each of the images
1420      that is currently loaded into the program. When a new image is added to
1421      the program, your callback is called again with the mach_header for the
1422      new image, and the virtual memory slide amount of the new image.
1423 
1424      This WILL properly register already linked libraries and libraries
1425      linked in the future.
1426   */
1427 
1428   _dyld_register_func_for_add_image(GC_dyld_image_add);
1429   _dyld_register_func_for_remove_image(GC_dyld_image_remove);
1430       /* Ignore 2 compiler warnings here: passing argument 1 of       */
1431       /* '_dyld_register_func_for_add/remove_image' from incompatible */
1432       /* pointer type.                                                */
1433 
1434   /* Set this early to avoid reentrancy issues. */
1435   initialized = TRUE;
1436 
1437 # ifdef NO_DYLD_BIND_FULLY_IMAGE
1438     /* FIXME: What should we do in this case?   */
1439 # else
1440     if (GC_no_dls) return; /* skip main data segment registration */
1441 
1442     /* When the environment variable is set, the dynamic linker binds   */
1443     /* all undefined symbols the application needs at launch time.      */
1444     /* This includes function symbols that are normally bound lazily at */
1445     /* the time of their first invocation.                              */
1446     if (GETENV("DYLD_BIND_AT_LAUNCH") == 0) {
1447       /* The environment variable is unset, so we should bind manually. */
1448 #     ifdef DARWIN_DEBUG
1449         GC_log_printf("Forcing full bind of GC code...\n");
1450 #     endif
1451       /* FIXME: '_dyld_bind_fully_image_containing_address' is deprecated. */
1452       if (!_dyld_bind_fully_image_containing_address(
1453                                                   (unsigned long *)GC_malloc))
1454         ABORT("_dyld_bind_fully_image_containing_address failed");
1455     }
1456 # endif
1457 }
1458 
1459 #define HAVE_REGISTER_MAIN_STATIC_DATA
1460 GC_INNER GC_bool GC_register_main_static_data(void)
1461 {
1462   /* Already done through dyld callbacks */
1463   return FALSE;
1464 }
1465 
1466 #endif /* DARWIN */
1467 
1468 #elif defined(PCR)
1469 
1470 # include "il/PCR_IL.h"
1471 # include "th/PCR_ThCtl.h"
1472 # include "mm/PCR_MM.h"
1473 
1474   GC_INNER void GC_register_dynamic_libraries(void)
1475   {
1476     /* Add new static data areas of dynamically loaded modules. */
1477     PCR_IL_LoadedFile * p = PCR_IL_GetLastLoadedFile();
1478     PCR_IL_LoadedSegment * q;
1479 
1480     /* Skip uncommitted files */
1481     while (p != NIL && !(p -> lf_commitPoint)) {
1482         /* The loading of this file has not yet been committed    */
1483         /* Hence its description could be inconsistent.           */
1484         /* Furthermore, it hasn't yet been run.  Hence its data   */
1485         /* segments can't possibly reference heap allocated       */
1486         /* objects.                                               */
1487         p = p -> lf_prev;
1488     }
1489     for (; p != NIL; p = p -> lf_prev) {
1490       for (q = p -> lf_ls; q != NIL; q = q -> ls_next) {
1491         if ((q -> ls_flags & PCR_IL_SegFlags_Traced_MASK)
1492             == PCR_IL_SegFlags_Traced_on) {
1493           GC_add_roots_inner((char *)(q -> ls_addr),
1494                              (char *)(q -> ls_addr) + q -> ls_bytes, TRUE);
1495         }
1496       }
1497     }
1498   }
1499 #endif /* PCR && !DYNAMIC_LOADING && !MSWIN32 */
1500 
1501 #if !defined(HAVE_REGISTER_MAIN_STATIC_DATA) && defined(DYNAMIC_LOADING)
1502   /* Do we need to separately register the main static data segment? */
1503   GC_INNER GC_bool GC_register_main_static_data(void)
1504   {
1505     return TRUE;
1506   }
1507 #endif /* HAVE_REGISTER_MAIN_STATIC_DATA */
1508 
1509 /* Register a routine to filter dynamic library registration.  */
1510 GC_API void GC_CALL GC_register_has_static_roots_callback(
1511                                         GC_has_static_roots_func callback)
1512 {
1513     GC_has_static_roots = callback;
1514 }
1515