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.
14 * Original author: Bill Janssen
15 * Heavily modified by Hans Boehm and others
19 * This is incredibly OS specific code for tracking down data sections in
20 * dynamic libraries. There appears to be no way of doing this quickly
21 * without groveling through undocumented data structures. We would argue
22 * that this is a bug in the design of the dlopen interface. THIS CODE
23 * MAY BREAK IN FUTURE OS RELEASES. If this matters to you, don't hesitate
24 * to let your vendor know ...
26 * None of this is safe with dlclose and incremental collection.
27 * But then not much of anything is safe in the presence of dlclose.
29 #if defined(__linux__) && !defined(_GNU_SOURCE)
30 /* Can't test LINUX, since this must be define before other includes */
33 #if !defined(MACOS) && !defined(_WIN32_WCE)
34 # include <sys/types.h>
36 #include "private/gc_priv.h"
38 /* BTL: avoid circular redefinition of dlopen if GC_SOLARIS_THREADS defined */
39 # if (defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS)) \
40 && defined(dlopen) && !defined(GC_USE_LD_WRAP)
41 /* To support threads in Solaris, gc.h interposes on dlopen by */
42 /* defining "dlopen" to be "GC_dlopen", which is implemented below. */
43 /* However, both GC_FirstDLOpenedLinkMap() and GC_dlopen() use the */
44 /* real system dlopen() in their implementation. We first remove */
45 /* gc.h's dlopen definition and restore it later, after GC_dlopen(). */
47 # define GC_must_restore_redefined_dlopen
49 # undef GC_must_restore_redefined_dlopen
52 #if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE)) \
54 #if !defined(SUNOS4) && !defined(SUNOS5DL) && !defined(IRIX5) && \
55 !defined(MSWIN32) && !defined(MSWINCE) && \
56 !(defined(ALPHA) && defined(OSF1)) && \
57 !defined(HPUX) && !(defined(LINUX) && defined(__ELF__)) && \
58 !defined(RS6000) && !defined(SCO_ELF) && !defined(DGUX) && \
59 !(defined(FREEBSD) && defined(__ELF__)) && \
60 !(defined(NETBSD) && defined(__ELF__)) && !defined(HURD) && \
62 --> We only know how to find data segments of dynamic libraries
for the
63 --> above
. Additional SVR4 variants might
not be too
77 /* struct link_map field overrides */
78 # define l_next lm_next
79 # define l_addr lm_addr
80 # define l_name lm_name
84 # include <machine/elf_machdep.h>
85 # define ELFSIZE ARCH_ELFSIZE
88 #if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
89 (defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \
90 (defined(NETBSD) && defined(__ELF__)) || defined(HURD)
96 /* Newer versions of GNU/Linux define this macro. We
97 * define it similarly for any ELF systems that don't. */
101 # define ElfW(type) Elf32_##type
103 # define ElfW(type) Elf64_##type
106 # if !defined(ELF_CLASS) || ELF_CLASS == ELFCLASS32
107 # define ElfW(type) Elf32_##type
109 # define ElfW(type) Elf64_##type
114 #if defined(SUNOS5DL) && !defined(USE_PROC_FOR_LIBRARIES)
120 static struct link_map
*
121 GC_FirstDLOpenedLinkMap()
123 extern ElfW(Dyn
) _DYNAMIC
;
126 static struct link_map
* cachedResult
= 0;
127 static ElfW(Dyn
) *dynStructureAddr
= 0;
128 /* BTL: added to avoid Solaris 5.3 ld.so _DYNAMIC bug */
130 # ifdef SUNOS53_SHARED_LIB
131 /* BTL: Avoid the Solaris 5.3 bug that _DYNAMIC isn't being set */
132 /* up properly in dynamically linked .so's. This means we have */
133 /* to use its value in the set of original object files loaded */
134 /* at program startup. */
135 if( dynStructureAddr
== 0 ) {
136 void* startupSyms
= dlopen(0, RTLD_LAZY
);
137 dynStructureAddr
= (ElfW(Dyn
)*)dlsym(startupSyms
, "_DYNAMIC");
140 dynStructureAddr
= &_DYNAMIC
;
143 if( dynStructureAddr
== 0) {
146 if( cachedResult
== 0 ) {
148 for( dp
= ((ElfW(Dyn
) *)(&_DYNAMIC
)); (tag
= dp
->d_tag
) != 0; dp
++ ) {
149 if( tag
== DT_DEBUG
) {
151 = ((struct r_debug
*)(dp
->d_un
.d_ptr
))->r_map
;
152 if( lm
!= 0 ) cachedResult
= lm
->l_next
; /* might be NIL */
160 #endif /* SUNOS5DL ... */
162 /* BTL: added to fix circular dlopen definition if GC_SOLARIS_THREADS defined */
163 # if defined(GC_must_restore_redefined_dlopen)
164 # define dlopen GC_dlopen
167 #if defined(SUNOS4) && !defined(USE_PROC_FOR_LIBRARIES)
170 struct link_dynamic _DYNAMIC
;
173 static struct link_map
*
174 GC_FirstDLOpenedLinkMap()
176 extern struct link_dynamic _DYNAMIC
;
178 if( &_DYNAMIC
== 0) {
181 return(_DYNAMIC
.ld_un
.ld_1
->ld_loaded
);
184 /* Return the address of the ld.so allocated common symbol */
185 /* with the least address, or 0 if none. */
186 static ptr_t
GC_first_common()
189 extern struct link_dynamic _DYNAMIC
;
190 struct rtc_symb
* curr_symbol
;
192 if( &_DYNAMIC
== 0) {
195 curr_symbol
= _DYNAMIC
.ldd
-> ldd_cp
;
196 for (; curr_symbol
!= 0; curr_symbol
= curr_symbol
-> rtc_next
) {
198 || (ptr_t
)(curr_symbol
-> rtc_sp
-> n_value
) < result
) {
199 result
= (ptr_t
)(curr_symbol
-> rtc_sp
-> n_value
);
205 #endif /* SUNOS4 ... */
207 # if defined(SUNOS4) || defined(SUNOS5DL)
208 /* Add dynamic library data sections to the root set. */
209 # if !defined(PCR) && !defined(GC_SOLARIS_THREADS) && defined(THREADS)
211 --> fix mutual exclusion with dlopen
212 # endif /* We assume M3 programs don't call dlopen for now */
215 # ifndef USE_PROC_FOR_LIBRARIES
216 void GC_register_dynamic_libraries()
218 struct link_map
*lm
= GC_FirstDLOpenedLinkMap();
221 for (lm
= GC_FirstDLOpenedLinkMap();
222 lm
!= (struct link_map
*) 0; lm
= lm
->l_next
)
227 e
= (struct exec
*) lm
->lm_addr
;
229 ((char *) (N_DATOFF(*e
) + lm
->lm_addr
)),
230 ((char *) (N_BSSADDR(*e
) + e
->a_bss
+ lm
->lm_addr
)),
236 unsigned long offset
;
240 e
= (ElfW(Ehdr
) *) lm
->l_addr
;
241 p
= ((ElfW(Phdr
) *)(((char *)(e
)) + e
->e_phoff
));
242 offset
= ((unsigned long)(lm
->l_addr
));
243 for( i
= 0; i
< (int)(e
->e_phnum
); ((i
++),(p
++)) ) {
244 switch( p
->p_type
) {
247 if( !(p
->p_flags
& PF_W
) ) break;
248 start
= ((char *)(p
->p_vaddr
)) + offset
;
264 static ptr_t common_start
= 0;
266 extern ptr_t
GC_find_limit();
268 if (common_start
== 0) common_start
= GC_first_common();
269 if (common_start
!= 0) {
270 common_end
= GC_find_limit(common_start
, TRUE
);
271 GC_add_roots_inner((char *)common_start
, (char *)common_end
, TRUE
);
277 # endif /* !USE_PROC ... */
280 #if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
281 (defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \
282 (defined(NETBSD) && defined(__ELF__)) || defined(HURD)
285 #ifdef USE_PROC_FOR_LIBRARIES
289 #include <sys/stat.h>
293 #define MAPS_BUF_SIZE (32*1024)
295 extern ssize_t
GC_repeat_read(int fd
, char *buf
, size_t count
);
296 /* Repeatedly read until buffer is filled, or EOF is encountered */
297 /* Defined in os_dep.c. */
299 char *GC_parse_map_entry(char *buf_ptr
, word
*start
, word
*end
,
300 char *prot_buf
, unsigned int *maj_dev
);
301 word
GC_apply_to_maps(word (*fn
)(char *));
304 word
GC_register_map_entries(char *maps
)
307 char *buf_ptr
= maps
;
310 unsigned int maj_dev
;
311 word least_ha
, greatest_ha
;
313 word datastart
= (word
)(DATASTART
);
315 /* Compute heap bounds. FIXME: Should be done by add_to_heap? */
316 least_ha
= (word
)(-1);
318 for (i
= 0; i
< GC_n_heap_sects
; ++i
) {
319 word sect_start
= (word
)GC_heap_sects
[i
].hs_start
;
320 word sect_end
= sect_start
+ GC_heap_sects
[i
].hs_bytes
;
321 if (sect_start
< least_ha
) least_ha
= sect_start
;
322 if (sect_end
> greatest_ha
) greatest_ha
= sect_end
;
324 if (greatest_ha
< (word
)GC_scratch_last_end_ptr
)
325 greatest_ha
= (word
)GC_scratch_last_end_ptr
;
328 buf_ptr
= GC_parse_map_entry(buf_ptr
, &start
, &end
, prot_buf
, &maj_dev
);
329 if (buf_ptr
== NULL
) return 1;
330 if (prot_buf
[1] == 'w') {
331 /* This is a writable mapping. Add it to */
332 /* the root set unless it is already otherwise */
334 if (start
<= (word
)GC_stackbottom
&& end
>= (word
)GC_stackbottom
) {
335 /* Stack mapping; discard */
339 if (GC_segment_is_thread_stack(start
, end
)) continue;
341 /* We no longer exclude the main data segment. */
342 if (start
< least_ha
&& end
> least_ha
) {
345 if (start
< greatest_ha
&& end
> greatest_ha
) {
348 if (start
>= least_ha
&& end
<= greatest_ha
) continue;
349 GC_add_roots_inner((char *)start
, (char *)end
, TRUE
);
355 void GC_register_dynamic_libraries()
357 if (!GC_apply_to_maps(GC_register_map_entries
))
358 ABORT("Failed to read /proc for library registration.");
361 /* We now take care of the main data segment ourselves: */
362 GC_bool
GC_register_main_static_data()
367 # define HAVE_REGISTER_MAIN_STATIC_DATA
369 #endif /* USE_PROC_FOR_LIBRARIES */
371 #if !defined(USE_PROC_FOR_LIBRARIES)
372 /* The following is the preferred way to walk dynamic libraries */
373 /* For glibc 2.2.4+. Unfortunately, it doesn't work for older */
374 /* versions. Thanks to Jakub Jelinek for most of the code. */
376 # if defined(LINUX) /* Are others OK here, too? */ \
377 && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) \
378 || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && defined(DT_CONFIG)))
380 /* We have the header files for a glibc that includes dl_iterate_phdr. */
381 /* It may still not be available in the library on the target system. */
382 /* Thus we also treat it as a weak symbol. */
383 #define HAVE_DL_ITERATE_PHDR
385 static int GC_register_dynlib_callback(info
, size
, ptr
)
386 struct dl_phdr_info
* info
;
390 const ElfW(Phdr
) * p
;
394 /* Make sure struct dl_phdr_info is at least as big as we need. */
395 if (size
< offsetof (struct dl_phdr_info
, dlpi_phnum
)
396 + sizeof (info
->dlpi_phnum
))
400 for( i
= 0; i
< (int)(info
->dlpi_phnum
); ((i
++),(p
++)) ) {
401 switch( p
->p_type
) {
404 if( !(p
->p_flags
& PF_W
) ) break;
405 start
= ((char *)(p
->p_vaddr
)) + info
->dlpi_addr
;
406 GC_add_roots_inner(start
, start
+ p
->p_memsz
, TRUE
);
414 * (int *)ptr
= 1; /* Signal that we were called */
418 /* Return TRUE if we succeed, FALSE if dl_iterate_phdr wasn't there. */
420 #pragma weak dl_iterate_phdr
422 GC_bool
GC_register_dynamic_libraries_dl_iterate_phdr()
424 if (dl_iterate_phdr
) {
425 int did_something
= 0;
426 dl_iterate_phdr(GC_register_dynlib_callback
, &did_something
);
427 if (!did_something
) {
428 /* dl_iterate_phdr may forget the static data segment in */
429 /* statically linked executables. */
430 GC_add_roots_inner(DATASTART
, (char *)(DATAEND
), TRUE
);
431 # if defined(DATASTART2)
432 GC_add_roots_inner(DATASTART2
, (char *)(DATAEND2
), TRUE
);
442 /* Do we need to separately register the main static data segment? */
443 GC_bool
GC_register_main_static_data()
445 return (dl_iterate_phdr
== 0);
448 #define HAVE_REGISTER_MAIN_STATIC_DATA
450 # else /* !LINUX || version(glibc) < 2.2.4 */
452 /* Dynamic loading code for Linux running ELF. Somewhat tested on
453 * Linux/x86, untested but hopefully should work on Linux/Alpha.
454 * This code was derived from the Solaris/ELF support. Thanks to
455 * whatever kind soul wrote that. - Patrick Bridges */
457 /* This doesn't necessarily work in all cases, e.g. with preloaded
458 * dynamic libraries. */
461 # include <sys/exec_elf.h>
462 /* for compatibility with 1.4.x */
480 # pragma weak _DYNAMIC
482 extern ElfW(Dyn
) _DYNAMIC
[];
484 static struct link_map
*
485 GC_FirstDLOpenedLinkMap()
489 static struct link_map
*cachedResult
= 0;
494 if( cachedResult
== 0 ) {
496 for( dp
= _DYNAMIC
; (tag
= dp
->d_tag
) != 0; dp
++ ) {
497 if( tag
== DT_DEBUG
) {
499 = ((struct r_debug
*)(dp
->d_un
.d_ptr
))->r_map
;
500 if( lm
!= 0 ) cachedResult
= lm
->l_next
; /* might be NIL */
509 void GC_register_dynamic_libraries()
514 # ifdef HAVE_DL_ITERATE_PHDR
515 if (GC_register_dynamic_libraries_dl_iterate_phdr()) {
519 lm
= GC_FirstDLOpenedLinkMap();
520 for (lm
= GC_FirstDLOpenedLinkMap();
521 lm
!= (struct link_map
*) 0; lm
= lm
->l_next
)
525 unsigned long offset
;
529 e
= (ElfW(Ehdr
) *) lm
->l_addr
;
530 p
= ((ElfW(Phdr
) *)(((char *)(e
)) + e
->e_phoff
));
531 offset
= ((unsigned long)(lm
->l_addr
));
532 for( i
= 0; i
< (int)(e
->e_phnum
); ((i
++),(p
++)) ) {
533 switch( p
->p_type
) {
536 if( !(p
->p_flags
& PF_W
) ) break;
537 start
= ((char *)(p
->p_vaddr
)) + offset
;
538 GC_add_roots_inner(start
, start
+ p
->p_memsz
, TRUE
);
548 #endif /* !USE_PROC_FOR_LIBRARIES */
552 #if defined(IRIX5) || (defined(USE_PROC_FOR_LIBRARIES) && !defined(LINUX))
554 #include <sys/procfs.h>
555 #include <sys/stat.h>
559 #include <signal.h> /* Only for the following test. */
564 extern void * GC_roots_present();
565 /* The type is a lie, since the real type doesn't make sense here, */
566 /* and we only test for NULL. */
569 /* We use /proc to track down all parts of the address space that are */
570 /* mapped by the process, and throw out regions we know we shouldn't */
571 /* worry about. This may also work under other SVR4 variants. */
572 void GC_register_dynamic_libraries()
576 static prmap_t
* addr_map
= 0;
577 static int current_sz
= 0; /* Number of records currently in addr_map */
578 static int needed_sz
; /* Required size of addr_map */
581 register ptr_t start
;
582 register ptr_t limit
;
583 ptr_t heap_start
= (ptr_t
)HEAP_START
;
584 ptr_t heap_end
= heap_start
;
588 # endif /* SUNOS5DL */
591 sprintf(buf
, "/proc/%d", getpid());
592 /* The above generates a lint complaint, since pid_t varies. */
593 /* It's unclear how to improve this. */
594 fd
= open(buf
, O_RDONLY
);
596 ABORT("/proc open failed");
599 if (ioctl(fd
, PIOCNMAP
, &needed_sz
) < 0) {
600 GC_err_printf2("fd = %d, errno = %d\n", fd
, errno
);
601 ABORT("/proc PIOCNMAP ioctl failed");
603 if (needed_sz
>= current_sz
) {
604 current_sz
= needed_sz
* 2 + 1;
605 /* Expansion, plus room for 0 record */
606 addr_map
= (prmap_t
*)GC_scratch_alloc((word
)
607 (current_sz
* sizeof(prmap_t
)));
609 if (ioctl(fd
, PIOCMAP
, addr_map
) < 0) {
610 GC_err_printf4("fd = %d, errno = %d, needed_sz = %d, addr_map = 0x%X\n",
611 fd
, errno
, needed_sz
, addr_map
);
612 ABORT("/proc PIOCMAP ioctl failed");
614 if (GC_n_heap_sects
> 0) {
615 heap_end
= GC_heap_sects
[GC_n_heap_sects
-1].hs_start
616 + GC_heap_sects
[GC_n_heap_sects
-1].hs_bytes
;
617 if (heap_end
< GC_scratch_last_end_ptr
) heap_end
= GC_scratch_last_end_ptr
;
619 for (i
= 0; i
< needed_sz
; i
++) {
620 flags
= addr_map
[i
].pr_mflags
;
621 if ((flags
& (MA_BREAK
| MA_STACK
| MA_PHYS
)) != 0) goto irrelevant
;
622 if ((flags
& (MA_READ
| MA_WRITE
)) != (MA_READ
| MA_WRITE
))
624 /* The latter test is empirically useless in very old Irix */
625 /* versions. Other than the */
626 /* main data and stack segments, everything appears to be */
627 /* mapped readable, writable, executable, and shared(!!). */
628 /* This makes no sense to me. - HB */
629 start
= (ptr_t
)(addr_map
[i
].pr_vaddr
);
630 if (GC_roots_present(start
)) goto irrelevant
;
631 if (start
< heap_end
&& start
>= heap_start
)
634 if (GC_is_thread_stack(start
)) goto irrelevant
;
635 # endif /* MMAP_STACKS */
637 limit
= start
+ addr_map
[i
].pr_size
;
638 /* The following seemed to be necessary for very old versions */
639 /* of Irix, but it has been reported to discard relevant */
640 /* segments under Irix 6.5. */
642 if (addr_map
[i
].pr_off
== 0 && strncmp(start
, ELFMAG
, 4) == 0) {
643 /* Discard text segments, i.e. 0-offset mappings against */
644 /* executable files which appear to have ELF headers. */
647 # define MAP_IRR_SZ 10
648 static ptr_t map_irr
[MAP_IRR_SZ
];
649 /* Known irrelevant map entries */
650 static int n_irr
= 0;
654 for (i
= 0; i
< n_irr
; i
++) {
655 if (map_irr
[i
] == start
) goto irrelevant
;
657 arg
= (caddr_t
)start
;
658 obj
= ioctl(fd
, PIOCOPENM
, &arg
);
662 if ((buf
.st_mode
& 0111) != 0) {
663 if (n_irr
< MAP_IRR_SZ
) {
664 map_irr
[n_irr
++] = start
;
671 GC_add_roots_inner(start
, limit
, TRUE
);
674 /* Dont keep cached descriptor, for now. Some kernels don't like us */
675 /* to keep a /proc file descriptor around during kill -9. */
676 if (close(fd
) < 0) ABORT("Couldnt close /proc file");
680 # endif /* USE_PROC || IRIX5 */
682 # if defined(MSWIN32) || defined(MSWINCE)
684 # define WIN32_LEAN_AND_MEAN
686 # include <windows.h>
689 /* We traverse the entire address space and register all segments */
690 /* that could possibly have been written to. */
692 extern GC_bool
GC_is_heap_base (ptr_t p
);
694 # ifdef GC_WIN32_THREADS
695 extern void GC_get_next_stack(char *start
, char **lo
, char **hi
);
696 void GC_cond_add_roots(char *base
, char * limit
)
698 char * curr_base
= base
;
699 char * next_stack_lo
;
700 char * next_stack_hi
;
702 if (base
== limit
) return;
704 GC_get_next_stack(curr_base
, &next_stack_lo
, &next_stack_hi
);
705 if (next_stack_lo
>= limit
) break;
706 GC_add_roots_inner(curr_base
, next_stack_lo
, TRUE
);
707 curr_base
= next_stack_hi
;
709 if (curr_base
< limit
) GC_add_roots_inner(curr_base
, limit
, TRUE
);
712 void GC_cond_add_roots(char *base
, char * limit
)
716 = (char *) ((word
)(&dummy
) & ~(GC_sysinfo
.dwAllocationGranularity
-1));
717 if (base
== limit
) return;
718 if (limit
> stack_top
&& base
< GC_stackbottom
) {
719 /* Part of the stack; ignore it. */
722 GC_add_roots_inner(base
, limit
, TRUE
);
727 /* Do we need to separately register the main static data segment? */
728 GC_bool
GC_register_main_static_data()
733 extern GC_bool GC_no_win32_dlls
;
735 GC_bool
GC_register_main_static_data()
737 return GC_no_win32_dlls
;
741 # define HAVE_REGISTER_MAIN_STATIC_DATA
743 /* The frame buffer testing code is dead in this version. */
744 /* We leave it here temporarily in case the switch to just */
745 /* testing for MEM_IMAGE sections causes un expected */
747 GC_bool GC_warn_fb
= TRUE
; /* Warn about traced likely */
748 /* graphics memory. */
749 GC_bool GC_disallow_ignore_fb
= FALSE
;
750 int GC_ignore_fb_mb
; /* Ignore mappings bigger than the */
751 /* specified number of MB. */
752 GC_bool GC_ignore_fb
= FALSE
; /* Enable frame buffer */
755 /* Issue warning if tracing apparent framebuffer. */
756 /* This limits us to one warning, and it's a back door to */
759 /* Should [start, start+len) be treated as a frame buffer */
761 /* Unfortunately, we currently have no real way to tell */
762 /* automatically, and rely largely on user input. */
763 /* FIXME: If we had more data on this phenomenon (e.g. */
764 /* is start aligned to a MB multiple?) we should be able to */
766 /* Based on a very limited sample, it appears that: */
767 /* - Frame buffer mappings appear as mappings of length */
768 /* 2**n MB - 192K. (We guess the 192K can vary a bit.) */
769 /* - Have a stating address at best 64K aligned. */
770 /* I'd love more information about the mapping, since I */
771 /* can't reproduce the problem. */
772 static GC_bool
is_frame_buffer(ptr_t start
, size_t len
)
774 static GC_bool initialized
= FALSE
;
775 # define MB (1024*1024)
776 # define DEFAULT_FB_MB 15
779 if (GC_disallow_ignore_fb
) return FALSE
;
781 char * ignore_fb_string
= GETENV("GC_IGNORE_FB");
783 if (0 != ignore_fb_string
) {
784 while (*ignore_fb_string
== ' ' || *ignore_fb_string
== '\t')
786 if (*ignore_fb_string
== '\0') {
787 GC_ignore_fb_mb
= DEFAULT_FB_MB
;
789 GC_ignore_fb_mb
= atoi(ignore_fb_string
);
790 if (GC_ignore_fb_mb
< MIN_FB_MB
) {
791 WARN("Bad GC_IGNORE_FB value. Using %ld\n", DEFAULT_FB_MB
);
792 GC_ignore_fb_mb
= DEFAULT_FB_MB
;
797 GC_ignore_fb_mb
= DEFAULT_FB_MB
; /* For warning */
801 if (len
>= ((size_t)GC_ignore_fb_mb
<< 20)) {
806 WARN("Possible frame buffer mapping at 0x%lx: \n"
807 "\tConsider setting GC_IGNORE_FB to improve performance.\n",
818 # ifdef DEBUG_VIRTUALQUERY
819 void GC_dump_meminfo(MEMORY_BASIC_INFORMATION
*buf
)
821 GC_printf4("BaseAddress = %lx, AllocationBase = %lx, RegionSize = %lx(%lu)\n",
822 buf
-> BaseAddress
, buf
-> AllocationBase
, buf
-> RegionSize
,
824 GC_printf4("\tAllocationProtect = %lx, State = %lx, Protect = %lx, "
826 buf
-> AllocationProtect
, buf
-> State
, buf
-> Protect
,
829 # endif /* DEBUG_VIRTUALQUERY */
831 void GC_register_dynamic_libraries()
833 MEMORY_BASIC_INFORMATION buf
;
838 char * limit
, * new_limit
;
841 if (GC_no_win32_dlls
) return;
843 base
= limit
= p
= GC_sysinfo
.lpMinimumApplicationAddress
;
844 # if defined(MSWINCE) && !defined(_WIN32_WCE_EMULATION)
845 /* Only the first 32 MB of address space belongs to the current process */
846 while (p
< (LPVOID
)0x02000000) {
847 result
= VirtualQuery(p
, &buf
, sizeof(buf
));
849 /* Page is free; advance to the next possible allocation base */
851 (((DWORD
) p
+ GC_sysinfo
.dwAllocationGranularity
)
852 & ~(GC_sysinfo
.dwAllocationGranularity
-1));
855 while (p
< GC_sysinfo
.lpMaximumApplicationAddress
) {
856 result
= VirtualQuery(p
, &buf
, sizeof(buf
));
859 if (result
!= sizeof(buf
)) {
860 ABORT("Weird VirtualQuery result");
862 new_limit
= (char *)p
+ buf
.RegionSize
;
863 protect
= buf
.Protect
;
864 if (buf
.State
== MEM_COMMIT
865 && (protect
== PAGE_EXECUTE_READWRITE
866 || protect
== PAGE_READWRITE
)
867 && !GC_is_heap_base(buf
.AllocationBase
)
868 /* This used to check for
869 * !is_frame_buffer(p, buf.RegionSize, buf.Type)
870 * instead of just checking for MEM_IMAGE.
871 * If something breaks, change it back. */
872 && buf
.Type
== MEM_IMAGE
) {
873 # ifdef DEBUG_VIRTUALQUERY
874 GC_dump_meminfo(&buf
);
876 if ((char *)p
!= limit
) {
877 GC_cond_add_roots(base
, limit
);
883 if (p
> (LPVOID
)new_limit
/* overflow */) break;
884 p
= (LPVOID
)new_limit
;
886 GC_cond_add_roots(base
, limit
);
889 #endif /* MSWIN32 || MSWINCE */
891 #if defined(ALPHA) && defined(OSF1)
895 void GC_register_dynamic_libraries()
901 ldr_module_t moduleid
= LDR_NULL_MODULE
;
902 ldr_module_info_t moduleinfo
;
903 size_t moduleinfosize
= sizeof(moduleinfo
);
904 size_t modulereturnsize
;
908 ldr_region_info_t regioninfo
;
909 size_t regioninfosize
= sizeof(regioninfo
);
910 size_t regionreturnsize
;
912 /* Obtain id of this process */
913 mypid
= ldr_my_process();
915 /* For each module */
918 /* Get the next (first) module */
919 status
= ldr_next_module(mypid
, &moduleid
);
921 /* Any more modules? */
922 if (moduleid
== LDR_NULL_MODULE
)
923 break; /* No more modules */
925 /* Check status AFTER checking moduleid because */
926 /* of a bug in the non-shared ldr_next_module stub */
928 GC_printf1("dynamic_load: status = %ld\n", (long)status
);
930 extern char *sys_errlist
[];
933 if (errno
<= sys_nerr
) {
934 GC_printf1("dynamic_load: %s\n", (long)sys_errlist
[errno
]);
936 GC_printf1("dynamic_load: %d\n", (long)errno
);
939 ABORT("ldr_next_module failed");
942 /* Get the module information */
943 status
= ldr_inq_module(mypid
, moduleid
, &moduleinfo
,
944 moduleinfosize
, &modulereturnsize
);
946 ABORT("ldr_inq_module failed");
948 /* is module for the main program (i.e. nonshared portion)? */
949 if (moduleinfo
.lmi_flags
& LDR_MAIN
)
950 continue; /* skip the main module */
953 GC_printf("---Module---\n");
954 GC_printf("Module ID = %16ld\n", moduleinfo
.lmi_modid
);
955 GC_printf("Count of regions = %16d\n", moduleinfo
.lmi_nregion
);
956 GC_printf("flags for module = %16lx\n", moduleinfo
.lmi_flags
);
957 GC_printf("pathname of module = \"%s\"\n", moduleinfo
.lmi_name
);
960 /* For each region in this module */
961 for (region
= 0; region
< moduleinfo
.lmi_nregion
; region
++) {
963 /* Get the region information */
964 status
= ldr_inq_region(mypid
, moduleid
, region
, ®ioninfo
,
965 regioninfosize
, ®ionreturnsize
);
967 ABORT("ldr_inq_region failed");
969 /* only process writable (data) regions */
970 if (! (regioninfo
.lri_prot
& LDR_W
))
974 GC_printf("--- Region ---\n");
975 GC_printf("Region number = %16ld\n",
976 regioninfo
.lri_region_no
);
977 GC_printf("Protection flags = %016x\n", regioninfo
.lri_prot
);
978 GC_printf("Virtual address = %16p\n", regioninfo
.lri_vaddr
);
979 GC_printf("Mapped address = %16p\n", regioninfo
.lri_mapaddr
);
980 GC_printf("Region size = %16ld\n", regioninfo
.lri_size
);
981 GC_printf("Region name = \"%s\"\n", regioninfo
.lri_name
);
984 /* register region as a garbage collection root */
986 (char *)regioninfo
.lri_mapaddr
,
987 (char *)regioninfo
.lri_mapaddr
+ regioninfo
.lri_size
,
1001 extern char *sys_errlist
[];
1002 extern int sys_nerr
;
1004 void GC_register_dynamic_libraries()
1007 int index
= 1; /* Ordinal position in shared library search list */
1008 struct shl_descriptor
*shl_desc
; /* Shared library info, see dl.h */
1010 /* For each dynamic library loaded */
1013 /* Get info about next shared library */
1014 status
= shl_get(index
, &shl_desc
);
1016 /* Check if this is the end of the list or if some error occured */
1018 # ifdef GC_HPUX_THREADS
1019 /* I've seen errno values of 0. The man page is not clear */
1020 /* as to whether errno should get set on a -1 return. */
1023 if (errno
== EINVAL
) {
1024 break; /* Moved past end of shared library list --> finished */
1026 if (errno
<= sys_nerr
) {
1027 GC_printf1("dynamic_load: %s\n", (long) sys_errlist
[errno
]);
1029 GC_printf1("dynamic_load: %d\n", (long) errno
);
1031 ABORT("shl_get failed");
1037 GC_printf0("---Shared library---\n");
1038 GC_printf1("\tfilename = \"%s\"\n", shl_desc
->filename
);
1039 GC_printf1("\tindex = %d\n", index
);
1040 GC_printf1("\thandle = %08x\n",
1041 (unsigned long) shl_desc
->handle
);
1042 GC_printf1("\ttext seg. start = %08x\n", shl_desc
->tstart
);
1043 GC_printf1("\ttext seg. end = %08x\n", shl_desc
->tend
);
1044 GC_printf1("\tdata seg. start = %08x\n", shl_desc
->dstart
);
1045 GC_printf1("\tdata seg. end = %08x\n", shl_desc
->dend
);
1046 GC_printf1("\tref. count = %lu\n", shl_desc
->ref_count
);
1049 /* register shared library's data segment as a garbage collection root */
1050 GC_add_roots_inner((char *) shl_desc
->dstart
,
1051 (char *) shl_desc
->dend
, TRUE
);
1060 #include <sys/ldr.h>
1061 #include <sys/errno.h>
1062 void GC_register_dynamic_libraries()
1067 struct ld_info
*ldi
;
1069 ldibuf
= alloca(ldibuflen
= 8192);
1071 while ( (len
= loadquery(L_GETINFO
,ldibuf
,ldibuflen
)) < 0) {
1072 if (errno
!= ENOMEM
) {
1073 ABORT("loadquery failed");
1075 ldibuf
= alloca(ldibuflen
*= 2);
1078 ldi
= (struct ld_info
*)ldibuf
;
1080 len
= ldi
->ldinfo_next
;
1082 ldi
->ldinfo_dataorg
,
1083 (ptr_t
)(unsigned long)ldi
->ldinfo_dataorg
1084 + ldi
->ldinfo_datasize
,
1086 ldi
= len
? (struct ld_info
*)((char *)ldi
+ len
) : 0;
1093 /* __private_extern__ hack required for pre-3.4 gcc versions. */
1094 #ifndef __private_extern__
1095 # define __private_extern__ extern
1096 # include <mach-o/dyld.h>
1097 # undef __private_extern__
1099 # include <mach-o/dyld.h>
1101 #include <mach-o/getsect.h>
1103 /*#define DARWIN_DEBUG*/
1105 const static struct {
1108 } GC_dyld_sections
[] = {
1109 { SEG_DATA
, SECT_DATA
},
1110 { SEG_DATA
, SECT_BSS
},
1111 { SEG_DATA
, SECT_COMMON
}
1115 static const char *GC_dyld_name_for_hdr(struct mach_header
*hdr
) {
1117 c
= _dyld_image_count();
1118 for(i
=0;i
<c
;i
++) if(_dyld_get_image_header(i
) == hdr
)
1119 return _dyld_get_image_name(i
);
1124 /* This should never be called by a thread holding the lock */
1125 static void GC_dyld_image_add(struct mach_header
* hdr
, unsigned long slide
) {
1126 unsigned long start
,end
,i
;
1127 const struct section
*sec
;
1128 for(i
=0;i
<sizeof(GC_dyld_sections
)/sizeof(GC_dyld_sections
[0]);i
++) {
1129 sec
= getsectbynamefromheader(
1130 hdr
,GC_dyld_sections
[i
].seg
,GC_dyld_sections
[i
].sect
);
1131 if(sec
== NULL
|| sec
->size
== 0) continue;
1132 start
= slide
+ sec
->addr
;
1133 end
= start
+ sec
->size
;
1134 # ifdef DARWIN_DEBUG
1135 GC_printf4("Adding section at %p-%p (%lu bytes) from image %s\n",
1136 start
,end
,sec
->size
,GC_dyld_name_for_hdr(hdr
));
1138 GC_add_roots((char*)start
,(char*)end
);
1140 # ifdef DARWIN_DEBUG
1141 GC_print_static_roots();
1145 /* This should never be called by a thread holding the lock */
1146 static void GC_dyld_image_remove(struct mach_header
* hdr
, unsigned long slide
) {
1147 unsigned long start
,end
,i
;
1148 const struct section
*sec
;
1149 for(i
=0;i
<sizeof(GC_dyld_sections
)/sizeof(GC_dyld_sections
[0]);i
++) {
1150 sec
= getsectbynamefromheader(
1151 hdr
,GC_dyld_sections
[i
].seg
,GC_dyld_sections
[i
].sect
);
1152 if(sec
== NULL
|| sec
->size
== 0) continue;
1153 start
= slide
+ sec
->addr
;
1154 end
= start
+ sec
->size
;
1155 # ifdef DARWIN_DEBUG
1156 GC_printf4("Removing section at %p-%p (%lu bytes) from image %s\n",
1157 start
,end
,sec
->size
,GC_dyld_name_for_hdr(hdr
));
1159 GC_remove_roots((char*)start
,(char*)end
);
1161 # ifdef DARWIN_DEBUG
1162 GC_print_static_roots();
1166 void GC_register_dynamic_libraries() {
1167 /* Currently does nothing. The callbacks are setup by GC_init_dyld()
1168 The dyld library takes it from there. */
1171 /* The _dyld_* functions have an internal lock so no _dyld functions
1172 can be called while the world is stopped without the risk of a deadlock.
1173 Because of this we MUST setup callbacks BEFORE we ever stop the world.
1174 This should be called BEFORE any thread in created and WITHOUT the
1175 allocation lock held. */
1177 void GC_init_dyld() {
1178 static GC_bool initialized
= FALSE
;
1179 char *bind_fully_env
= NULL
;
1181 if(initialized
) return;
1183 # ifdef DARWIN_DEBUG
1184 GC_printf0("Registering dyld callbacks...\n");
1187 /* Apple's Documentation:
1188 When you call _dyld_register_func_for_add_image, the dynamic linker runtime
1189 calls the specified callback (func) once for each of the images that is
1190 currently loaded into the program. When a new image is added to the program,
1191 your callback is called again with the mach_header for the new image, and the
1192 virtual memory slide amount of the new image.
1194 This WILL properly register already linked libraries and libraries
1195 linked in the future
1198 _dyld_register_func_for_add_image(GC_dyld_image_add
);
1199 _dyld_register_func_for_remove_image(GC_dyld_image_remove
);
1201 /* Set this early to avoid reentrancy issues. */
1204 bind_fully_env
= getenv("DYLD_BIND_AT_LAUNCH");
1206 if (bind_fully_env
== NULL
) {
1207 # ifdef DARWIN_DEBUG
1208 GC_printf0("Forcing full bind of GC code...\n");
1211 if(!_dyld_bind_fully_image_containing_address((unsigned long*)GC_malloc
))
1212 GC_abort("_dyld_bind_fully_image_containing_address failed");
1217 #define HAVE_REGISTER_MAIN_STATIC_DATA
1218 GC_bool
GC_register_main_static_data()
1220 /* Already done through dyld callbacks */
1226 #else /* !DYNAMIC_LOADING */
1230 # include "il/PCR_IL.h"
1231 # include "th/PCR_ThCtl.h"
1232 # include "mm/PCR_MM.h"
1234 void GC_register_dynamic_libraries()
1236 /* Add new static data areas of dynamically loaded modules. */
1238 PCR_IL_LoadedFile
* p
= PCR_IL_GetLastLoadedFile();
1239 PCR_IL_LoadedSegment
* q
;
1241 /* Skip uncommited files */
1242 while (p
!= NIL
&& !(p
-> lf_commitPoint
)) {
1243 /* The loading of this file has not yet been committed */
1244 /* Hence its description could be inconsistent. */
1245 /* Furthermore, it hasn't yet been run. Hence its data */
1246 /* segments can't possibly reference heap allocated */
1250 for (; p
!= NIL
; p
= p
-> lf_prev
) {
1251 for (q
= p
-> lf_ls
; q
!= NIL
; q
= q
-> ls_next
) {
1252 if ((q
-> ls_flags
& PCR_IL_SegFlags_Traced_MASK
)
1253 == PCR_IL_SegFlags_Traced_on
) {
1255 ((char *)(q
-> ls_addr
),
1256 (char *)(q
-> ls_addr
) + q
-> ls_bytes
,
1267 void GC_register_dynamic_libraries(){}
1269 int GC_no_dynamic_loading
;
1273 #endif /* !DYNAMIC_LOADING */
1275 #ifndef HAVE_REGISTER_MAIN_STATIC_DATA
1277 /* Do we need to separately register the main static data segment? */
1278 GC_bool
GC_register_main_static_data()
1282 #endif /* HAVE_REGISTER_MAIN_STATIC_DATA */