2 * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
3 * Copyright (c) 1997 by Silicon Graphics. All rights reserved.
5 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
6 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
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.
15 #include "private/gc_priv.h"
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 ...
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.
29 #if !defined(MACOS) && !defined(SN_TARGET_ORBIS) && !defined(SN_TARGET_PSP2) \
30 && !defined(_WIN32_WCE) && !defined(__CC_ARM)
31 # include <sys/types.h>
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(). */
44 # define GC_MUST_RESTORE_REDEFINED_DLOPEN
45 #endif /* !GC_NO_DLOPEN */
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;
53 #if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE) \
54 || defined(CYGWIN32)) && !defined(PCR)
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) \
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.
78 # include <sys/param.h>
80 # include <machine/elf_machdep.h>
81 # define ELFSIZE ARCH_ELFSIZE
85 # include <sys/param.h>
86 # if (OpenBSD >= 200519) && !defined(HAVE_DL_ITERATE_PHDR)
87 # define HAVE_DL_ITERATE_PHDR
91 #if defined(SCO_ELF) || defined(DGUX) || defined(HURD) || defined(NACL) \
92 || (defined(__ELF__) && (defined(LINUX) || defined(FREEBSD) \
93 || defined(NETBSD) || defined(OPENBSD)))
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. */
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>
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. */
121 struct link_map* l_next;
122 struct link_map* l_prev;
126 struct link_map* r_map;
133 EXTERN_C_BEGIN /* Workaround missing extern "C" around _DYNAMIC */
134 /* symbol in link.h of some Linux hosts. */
140 /* Newer versions of GNU/Linux define this macro. We
141 * define it similarly for any ELF systems that don't. */
143 # if defined(FREEBSD)
144 # if __ELF_WORD_SIZE == 32
145 # define ElfW(type) Elf32_##type
147 # define ElfW(type) Elf64_##type
149 # elif defined(NETBSD) || defined(OPENBSD)
151 # define ElfW(type) Elf32_##type
153 # define ElfW(type) Elf64_##type
156 # if !defined(ELF_CLASS) || ELF_CLASS == ELFCLASS32
157 # define ElfW(type) Elf32_##type
159 # define ElfW(type) Elf64_##type
164 #if defined(SOLARISDL) && !defined(USE_PROC_FOR_LIBRARIES)
167 extern ElfW(Dyn) _DYNAMIC;
170 STATIC struct link_map *
171 GC_FirstDLOpenedLinkMap(void)
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 */
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");
188 dynStructureAddr = &_DYNAMIC;
191 if (0 == COVERT_DATAFLOW(dynStructureAddr)) {
192 /* _DYNAMIC symbol not resolved. */
195 if (cachedResult == 0) {
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;
201 struct link_map *lm = rd->r_map;
203 cachedResult = lm->l_next; /* might be NULL */
212 #endif /* SOLARISDL ... */
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
219 # if defined(SOLARISDL)
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
227 # ifndef USE_PROC_FOR_LIBRARIES
228 GC_INNER void GC_register_dynamic_libraries(void)
232 for (lm = GC_FirstDLOpenedLinkMap(); lm != 0; lm = lm->l_next) {
235 unsigned long offset;
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 ) {
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);
258 # endif /* !USE_PROC ... */
259 # endif /* SOLARISDL */
261 #if defined(SCO_ELF) || defined(DGUX) || defined(HURD) || defined(NACL) \
262 || (defined(__ELF__) && (defined(LINUX) || defined(FREEBSD) \
263 || defined(NETBSD) || defined(OPENBSD)))
265 #ifdef USE_PROC_FOR_LIBRARIES
269 #include <sys/stat.h>
273 #define MAPS_BUF_SIZE (32*1024)
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 */
281 static void sort_heap_sects(struct HeapSect *base, size_t number_of_elements)
283 signed_word n = (signed_word)number_of_elements;
284 signed_word nsorted = 1;
286 while (nsorted < n) {
289 while (nsorted < n &&
290 (word)base[nsorted-1].hs_start < (word)base[nsorted].hs_start)
292 if (nsorted == n) break;
293 GC_ASSERT((word)base[nsorted-1].hs_start > (word)base[nsorted].hs_start);
295 while (i >= 0 && (word)base[i].hs_start > (word)base[i+1].hs_start) {
296 struct HeapSect tmp = base[i];
301 GC_ASSERT((word)base[nsorted-1].hs_start < (word)base[nsorted].hs_start);
306 STATIC void GC_register_map_entries(char *maps)
309 char *buf_ptr = maps;
311 unsigned int maj_dev;
312 ptr_t least_ha, greatest_ha;
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;
322 buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, &prot,
326 if (prot[1] == 'w') {
327 /* This is a writable mapping. Add it to */
328 /* the root set unless it is already otherwise */
330 if ((word)start <= (word)GC_stackbottom
331 && (word)end >= (word)GC_stackbottom) {
332 /* Stack mapping; discard */
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. */
342 if (GC_segment_is_thread_stack(start, end)) continue;
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. */
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);
367 /* Add sections that don't belong to us. */
369 while ((word)(GC_our_memory[i].hs_start
370 + GC_our_memory[i].hs_bytes) < (word)start)
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;
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;
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);
398 GC_INNER void GC_register_dynamic_libraries(void)
400 char *maps = GC_get_maps();
403 ABORT("Failed to read /proc for library registration");
404 GC_register_map_entries(maps);
407 /* We now take care of the main data segment ourselves: */
408 GC_INNER GC_bool GC_register_main_static_data(void)
413 # define HAVE_REGISTER_MAIN_STATIC_DATA
415 #else /* !USE_PROC_FOR_LIBRARIES */
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. */
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
428 /* Android headers might have no such definition for some targets. */
430 extern int dl_iterate_phdr(int (*cb)(struct dl_phdr_info *,
435 #endif /* __GLIBC__ >= 2 || HOST_ANDROID */
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
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. */
450 # pragma weak dl_iterate_phdr
454 #if defined(HAVE_DL_ITERATE_PHDR)
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. */
464 # define MAX_LOAD_SEGS MAX_ROOT_SETS
466 static struct load_segment {
469 /* Room for a second segment if we remove a RELRO segment */
470 /* from the middle. */
473 } load_segs[MAX_LOAD_SEGS];
475 static int n_load_segs;
476 static GC_bool load_segs_overflow;
477 # endif /* PT_GNU_RELRO */
479 STATIC int GC_register_dynlib_callback(struct dl_phdr_info * info,
480 size_t size, void * ptr)
482 const ElfW(Phdr) * p;
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))
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;
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))
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));
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;
516 GC_add_roots_inner(start, end, TRUE);
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;
525 GC_add_roots_inner(start, end, TRUE);
526 # endif /* !PT_GNU_RELRO */
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. */
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);
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;
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. */
566 *(int *)ptr = 1; /* Signal that we were called */
570 /* Do we need to separately register the main static data segment? */
571 GC_INNER GC_bool GC_register_main_static_data(void)
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). */
578 return 0 == COVERT_DATAFLOW(dl_iterate_phdr);
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)
586 if (GC_register_main_static_data())
591 static GC_bool excluded_segs = FALSE;
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;
603 dl_iterate_phdr(GC_register_dynlib_callback, &did_something);
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);
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);
618 ptr_t datastart, dataend;
619 # ifdef DATASTART_IS_FUNC
620 static ptr_t datastart_cached = (ptr_t)GC_WORD_MAX;
622 /* Evaluate DATASTART only once. */
623 if (datastart_cached == (ptr_t)GC_WORD_MAX) {
624 datastart_cached = DATASTART;
626 datastart = datastart_cached;
628 datastart = DATASTART;
630 # ifdef DATAEND_IS_FUNC
632 static ptr_t dataend_cached = 0;
633 /* Evaluate DATAEND only once. */
634 if (dataend_cached == 0) {
635 dataend_cached = DATAEND;
637 dataend = dataend_cached;
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);
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);
657 GC_add_roots_inner(DATASTART2, DATAEND2, TRUE);
663 # define HAVE_REGISTER_MAIN_STATIC_DATA
665 #else /* !HAVE_DL_ITERATE_PHDR */
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 */
672 /* This doesn't necessarily work in all cases, e.g. with preloaded
673 * dynamic libraries. */
675 # if defined(NETBSD) || defined(OPENBSD)
676 # include <sys/exec_elf.h>
677 /* for compatibility with 1.4.x */
687 # elif !defined(HOST_ANDROID)
691 # ifndef HOST_ANDROID
695 #endif /* !HAVE_DL_ITERATE_PHDR */
699 # pragma weak _DYNAMIC
701 extern ElfW(Dyn) _DYNAMIC[];
704 STATIC struct link_map *
705 GC_FirstDLOpenedLinkMap(void)
707 static struct link_map *cachedResult = 0;
709 if (0 == COVERT_DATAFLOW(_DYNAMIC)) {
710 /* _DYNAMIC symbol not resolved. */
713 if( cachedResult == 0 ) {
714 # if defined(NETBSD) && defined(RTLD_DI_LINKMAP)
715 # if defined(CPPCHECK)
716 # define GC_RTLD_DI_LINKMAP 2
718 # define GC_RTLD_DI_LINKMAP RTLD_DI_LINKMAP
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) {
728 cachedResult = lm->l_next;
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. */
739 struct link_map *lm = rd->r_map;
741 cachedResult = lm->l_next; /* might be NULL */
746 # endif /* !NETBSD || !RTLD_DI_LINKMAP */
751 GC_INNER void GC_register_dynamic_libraries(void)
755 # ifdef HAVE_DL_ITERATE_PHDR
756 if (GC_register_dynamic_libraries_dl_iterate_phdr()) {
760 for (lm = GC_FirstDLOpenedLinkMap(); lm != 0; lm = lm->l_next)
764 unsigned long offset;
768 e = (ElfW(Ehdr) *) lm->l_addr;
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 ) {
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);
791 #endif /* !USE_PROC_FOR_LIBRARIES */
795 #if defined(IRIX5) || (defined(USE_PROC_FOR_LIBRARIES) && !defined(LINUX))
797 #include <sys/procfs.h>
798 #include <sys/stat.h>
802 #include <signal.h> /* Only for the following test. */
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)
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 */
821 ptr_t heap_start = HEAP_START;
822 ptr_t heap_end = heap_start;
826 # endif /* SOLARISDL */
829 (void)snprintf(buf, sizeof(buf), "/proc/%ld", (long)getpid());
830 buf[sizeof(buf) - 1] = '\0';
831 fd = open(buf, O_RDONLY);
833 ABORT("/proc open failed");
836 if (ioctl(fd, PIOCNMAP, &needed_sz) < 0) {
837 ABORT_ARG2("/proc PIOCNMAP ioctl failed",
838 ": fd = %d, errno = %d", fd, errno);
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");
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);
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;
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))
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)
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. */
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. */
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;
894 for (j = 0; j < n_irr; j++) {
895 if (map_irr[j] == start) goto irrelevant;
897 arg = (caddr_t)start;
898 obj = ioctl(fd, PIOCOPENM, &arg);
902 if ((buf.st_mode & 0111) != 0) {
903 if (n_irr < MAP_IRR_SZ) {
904 map_irr[n_irr++] = start;
911 GC_add_roots_inner(start, limit, TRUE);
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");
920 # endif /* USE_PROC || IRIX5 */
922 # if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
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)
930 # ifdef GC_WIN32_THREADS
931 char * curr_base = base;
932 char * next_stack_lo;
933 char * next_stack_hi;
935 if (base == limit) return;
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;
943 if ((word)curr_base < (word)limit)
944 GC_add_roots_inner(curr_base, limit, TRUE);
947 = (char *)((word)GC_approx_sp() &
948 ~(word)(GC_sysinfo.dwAllocationGranularity - 1));
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. */
956 GC_add_roots_inner(base, limit, TRUE);
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)
964 # if defined(MSWINCE) || defined(CYGWIN32)
965 /* Do we need to separately register the main static data segment? */
968 return GC_no_win32_dlls;
971 # define HAVE_REGISTER_MAIN_STATIC_DATA
972 #endif /* DYNAMIC_LOADING */
974 # ifdef DEBUG_VIRTUALQUERY
975 void GC_dump_meminfo(MEMORY_BASIC_INFORMATION *buf)
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);
984 # endif /* DEBUG_VIRTUALQUERY */
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. */
996 GC_INNER void GC_register_dynamic_libraries(void)
998 MEMORY_BASIC_INFORMATION buf;
1002 char * limit, * new_limit;
1005 if (GC_no_win32_dlls) return;
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));
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));
1021 if (result != sizeof(buf)) {
1022 ABORT("Weird VirtualQuery result");
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)
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 */
1039 || (!GC_wnt && buf.Type == MEM_PRIVATE)
1042 && !GC_is_heap_base(buf.AllocationBase)) {
1043 # ifdef DEBUG_VIRTUALQUERY
1044 GC_dump_meminfo(&buf);
1046 if ((char *)p != limit) {
1047 GC_cond_add_roots(base, limit);
1053 if ((word)p > (word)new_limit /* overflow */) break;
1054 p = (LPVOID)new_limit;
1056 GC_cond_add_roots(base, limit);
1059 #endif /* MSWIN32 || MSWINCE || CYGWIN32 */
1061 #if defined(ALPHA) && defined(OSF1)
1066 extern char *sys_errlist[];
1067 extern int sys_nerr;
1071 GC_INNER void GC_register_dynamic_libraries(void)
1073 ldr_module_t moduleid = LDR_NULL_MODULE;
1074 ldr_process_t mypid = ldr_my_process(); /* obtain id of this process */
1076 /* For each module */
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 */
1086 /* Any more modules? */
1087 if (moduleid == LDR_NULL_MODULE)
1088 break; /* No more modules */
1090 /* Check status AFTER checking moduleid because */
1091 /* of a bug in the non-shared ldr_next_module stub. */
1093 ABORT_ARG3("ldr_next_module failed",
1094 ": status= %d, errcode= %d (%s)", status, errno,
1095 errno < sys_nerr ? sys_errlist[errno] : "");
1098 /* Get the module information */
1099 status = ldr_inq_module(mypid, moduleid, &moduleinfo,
1100 sizeof(moduleinfo), &modulereturnsize);
1102 ABORT("ldr_inq_module failed");
1104 /* is module for the main program (i.e. nonshared portion)? */
1105 if (moduleinfo.lmi_flags & LDR_MAIN)
1106 continue; /* skip the main module */
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);
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, ®ioninfo,
1120 sizeof(regioninfo), ®ionreturnsize);
1122 ABORT("ldr_inq_region failed");
1124 /* only process writable (data) regions */
1125 if (! (regioninfo.lri_prot & LDR_W))
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);
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,
1156 extern char *sys_errlist[];
1157 extern int sys_nerr;
1160 GC_INNER void GC_register_dynamic_libraries(void)
1162 int index = 1; /* Ordinal position in shared library search list */
1164 /* For each dynamic library loaded */
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 */
1170 /* Check if this is the end of the list or if some error occurred */
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. */
1177 if (errno == EINVAL) {
1178 break; /* Moved past end of shared library list --> finished */
1180 ABORT_ARG3("shl_get failed",
1181 ": status= %d, errcode= %d (%s)", status, errno,
1182 errno < sys_nerr ? sys_errlist[errno] : "");
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);
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);
1211 # include <sys/ldr.h>
1212 # include <sys/errno.h>
1213 GC_INNER void GC_register_dynamic_libraries(void)
1215 int ldibuflen = 8192;
1219 struct ld_info *ldi;
1220 # if defined(CPPCHECK)
1221 char ldibuf[ldibuflen];
1223 char *ldibuf = alloca(ldibuflen);
1226 len = loadquery(L_GETINFO, ldibuf, ldibuflen);
1228 if (errno != ENOMEM) {
1229 ABORT("loadquery failed");
1235 ldi = (struct ld_info *)ldibuf;
1237 len = ldi->ldinfo_next;
1239 ldi->ldinfo_dataorg,
1240 (ptr_t)(unsigned long)ldi->ldinfo_dataorg
1241 + ldi->ldinfo_datasize,
1243 ldi = len ? (struct ld_info *)((char *)ldi + len) : 0;
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__
1258 # include <mach-o/dyld.h>
1260 #include <mach-o/getsect.h>
1262 /*#define DARWIN_DEBUG*/
1264 /* Writable sections generally available on Darwin. */
1265 STATIC const struct dyld_sections_s {
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" }
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[] = {
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
1300 STATIC const char *GC_dyld_name_for_hdr(const struct GC_MACH_HEADER *hdr)
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);
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,
1314 unsigned long start, end;
1316 const struct GC_MACH_SECTION *sec;
1318 GC_has_static_roots_func callback = GC_has_static_roots;
1321 if (GC_no_dls) return;
1322 # ifdef DARWIN_DEBUG
1323 name = GC_dyld_name_for_hdr(hdr);
1325 name = callback != 0 ? GC_dyld_name_for_hdr(hdr) : NULL;
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))
1332 start = slide + sec->addr;
1333 end = start + sec->size;
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
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);
1343 GC_add_roots_inner((ptr_t)start, (ptr_t)end, FALSE);
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];
1352 /* Add our manufactured aligned BSS sections. */
1353 for (i = 0; i <= L2_MAX_OFILE_ALIGNMENT; i++) {
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)
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);
1369 GC_add_roots((char*)start, (char*)end);
1373 # if defined(DARWIN_DEBUG) && !defined(NO_DEBUGGING)
1375 GC_print_static_roots();
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,
1384 unsigned long start, end;
1386 const struct GC_MACH_SECTION *sec;
1387 # if defined(DARWIN_DEBUG) && !defined(NO_DEBUGGING)
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)
1396 start = slide + sec->addr;
1397 end = start + sec->size;
1398 # ifdef DARWIN_DEBUG
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));
1404 GC_remove_roots((char*)start, (char*)end);
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];
1411 for (i = 0; i <= L2_MAX_OFILE_ALIGNMENT; i++) {
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)
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));
1427 GC_remove_roots((char*)start, (char*)end);
1431 # if defined(DARWIN_DEBUG) && !defined(NO_DEBUGGING)
1433 GC_print_static_roots();
1438 GC_INNER void GC_register_dynamic_libraries(void)
1440 /* Currently does nothing. The callbacks are setup by GC_init_dyld()
1441 The dyld library takes it from there. */
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. */
1450 GC_INNER void GC_init_dyld(void)
1452 static GC_bool initialized = FALSE;
1454 if (initialized) return;
1456 # ifdef DARWIN_DEBUG
1457 GC_log_printf("Registering dyld callbacks...\n");
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.
1467 This WILL properly register already linked libraries and libraries
1468 linked in the future.
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. */
1478 /* Set this early to avoid reentrancy issues. */
1481 # ifdef NO_DYLD_BIND_FULLY_IMAGE
1482 /* FIXME: What should we do in this case? */
1484 if (GC_no_dls) return; /* skip main data segment registration */
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");
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");
1503 #define HAVE_REGISTER_MAIN_STATIC_DATA
1504 GC_INNER GC_bool GC_register_main_static_data(void)
1506 /* Already done through dyld callbacks */
1513 # include <kernel/image.h>
1515 GC_INNER void GC_register_dynamic_libraries(void)
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);
1529 # include "il/PCR_IL.h"
1530 # include "th/PCR_ThCtl.h"
1531 # include "mm/PCR_MM.h"
1533 GC_INNER void GC_register_dynamic_libraries(void)
1535 /* Add new static data areas of dynamically loaded modules. */
1536 PCR_IL_LoadedFile * p = PCR_IL_GetLastLoadedFile();
1537 PCR_IL_LoadedSegment * q;
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 */
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);
1558 #endif /* PCR && !DYNAMIC_LOADING && !MSWIN32 */
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)
1566 #endif /* HAVE_REGISTER_MAIN_STATIC_DATA */
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)
1572 GC_has_static_roots = callback;