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