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