Merge from the pain train
[official-gcc.git] / boehm-gc / dyn_load.c
blobc5139aa80a8fdee315af53616e78cd3c21bfb569
1 /*
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 */
31 # define _GNU_SOURCE
32 #endif
33 #if !defined(MACOS) && !defined(_WIN32_WCE)
34 # include <sys/types.h>
35 #endif
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(). */
46 # undef dlopen
47 # define GC_must_restore_redefined_dlopen
48 # else
49 # undef GC_must_restore_redefined_dlopen
50 # endif
52 #if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE)) \
53 && !defined(PCR)
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) && \
61 !defined(DARWIN)
62 --> We only know how to find data segments of dynamic libraries for the
63 --> above. Additional SVR4 variants might not be too
64 --> hard to add.
65 #endif
67 #include <stdio.h>
68 #ifdef SUNOS5DL
69 # include <sys/elf.h>
70 # include <dlfcn.h>
71 # include <link.h>
72 #endif
73 #ifdef SUNOS4
74 # include <dlfcn.h>
75 # include <link.h>
76 # include <a.out.h>
77 /* struct link_map field overrides */
78 # define l_next lm_next
79 # define l_addr lm_addr
80 # define l_name lm_name
81 #endif
83 #if defined(NETBSD)
84 # include <machine/elf_machdep.h>
85 # define ELFSIZE ARCH_ELFSIZE
86 #endif
88 #if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
89 (defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \
90 (defined(NETBSD) && defined(__ELF__)) || defined(HURD)
91 # include <stddef.h>
92 # include <elf.h>
93 # include <link.h>
94 #endif
96 /* Newer versions of GNU/Linux define this macro. We
97 * define it similarly for any ELF systems that don't. */
98 # ifndef ElfW
99 # ifdef __NetBSD__
100 # if ELFSIZE == 32
101 # define ElfW(type) Elf32_##type
102 # else
103 # define ElfW(type) Elf64_##type
104 # endif
105 # else
106 # if !defined(ELF_CLASS) || ELF_CLASS == ELFCLASS32
107 # define ElfW(type) Elf32_##type
108 # else
109 # define ElfW(type) Elf64_##type
110 # endif
111 # endif
112 # endif
114 #if defined(SUNOS5DL) && !defined(USE_PROC_FOR_LIBRARIES)
116 #ifdef LINT
117 Elf32_Dyn _DYNAMIC;
118 #endif
120 static struct link_map *
121 GC_FirstDLOpenedLinkMap()
123 extern ElfW(Dyn) _DYNAMIC;
124 ElfW(Dyn) *dp;
125 struct r_debug *r;
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");
139 # else
140 dynStructureAddr = &_DYNAMIC;
141 # endif
143 if( dynStructureAddr == 0) {
144 return(0);
146 if( cachedResult == 0 ) {
147 int tag;
148 for( dp = ((ElfW(Dyn) *)(&_DYNAMIC)); (tag = dp->d_tag) != 0; dp++ ) {
149 if( tag == DT_DEBUG ) {
150 struct link_map *lm
151 = ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
152 if( lm != 0 ) cachedResult = lm->l_next; /* might be NIL */
153 break;
157 return cachedResult;
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
165 # endif
167 #if defined(SUNOS4) && !defined(USE_PROC_FOR_LIBRARIES)
169 #ifdef LINT
170 struct link_dynamic _DYNAMIC;
171 #endif
173 static struct link_map *
174 GC_FirstDLOpenedLinkMap()
176 extern struct link_dynamic _DYNAMIC;
178 if( &_DYNAMIC == 0) {
179 return(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()
188 ptr_t result = 0;
189 extern struct link_dynamic _DYNAMIC;
190 struct rtc_symb * curr_symbol;
192 if( &_DYNAMIC == 0) {
193 return(0);
195 curr_symbol = _DYNAMIC.ldd -> ldd_cp;
196 for (; curr_symbol != 0; curr_symbol = curr_symbol -> rtc_next) {
197 if (result == 0
198 || (ptr_t)(curr_symbol -> rtc_sp -> n_value) < result) {
199 result = (ptr_t)(curr_symbol -> rtc_sp -> n_value);
202 return(result);
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)
210 # ifndef SRC_M3
211 --> fix mutual exclusion with dlopen
212 # endif /* We assume M3 programs don't call dlopen for now */
213 # endif
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)
224 # ifdef SUNOS4
225 struct exec *e;
227 e = (struct exec *) lm->lm_addr;
228 GC_add_roots_inner(
229 ((char *) (N_DATOFF(*e) + lm->lm_addr)),
230 ((char *) (N_BSSADDR(*e) + e->a_bss + lm->lm_addr)),
231 TRUE);
232 # endif
233 # ifdef SUNOS5DL
234 ElfW(Ehdr) * e;
235 ElfW(Phdr) * p;
236 unsigned long offset;
237 char * start;
238 register int i;
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 ) {
245 case PT_LOAD:
247 if( !(p->p_flags & PF_W) ) break;
248 start = ((char *)(p->p_vaddr)) + offset;
249 GC_add_roots_inner(
250 start,
251 start + p->p_memsz,
252 TRUE
255 break;
256 default:
257 break;
260 # endif
262 # ifdef SUNOS4
264 static ptr_t common_start = 0;
265 ptr_t common_end;
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);
274 # endif
277 # endif /* !USE_PROC ... */
278 # endif /* SUNOS */
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
287 #include <string.h>
289 #include <sys/stat.h>
290 #include <fcntl.h>
291 #include <unistd.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 *));
302 /* From os_dep.c */
304 word GC_register_map_entries(char *maps)
306 char prot_buf[5];
307 char *buf_ptr = maps;
308 int count;
309 word start, end;
310 unsigned int maj_dev;
311 word least_ha, greatest_ha;
312 unsigned i;
313 word datastart = (word)(DATASTART);
315 /* Compute heap bounds. FIXME: Should be done by add_to_heap? */
316 least_ha = (word)(-1);
317 greatest_ha = 0;
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;
327 for (;;) {
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 */
333 /* accounted for. */
334 if (start <= (word)GC_stackbottom && end >= (word)GC_stackbottom) {
335 /* Stack mapping; discard */
336 continue;
338 # ifdef THREADS
339 if (GC_segment_is_thread_stack(start, end)) continue;
340 # endif
341 /* We no longer exclude the main data segment. */
342 if (start < least_ha && end > least_ha) {
343 end = least_ha;
345 if (start < greatest_ha && end > greatest_ha) {
346 start = greatest_ha;
348 if (start >= least_ha && end <= greatest_ha) continue;
349 GC_add_roots_inner((char *)start, (char *)end, TRUE);
352 return 1;
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()
364 return FALSE;
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;
387 size_t size;
388 void * ptr;
390 const ElfW(Phdr) * p;
391 char * start;
392 register int i;
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))
397 return -1;
399 p = info->dlpi_phdr;
400 for( i = 0; i < (int)(info->dlpi_phnum); ((i++),(p++)) ) {
401 switch( p->p_type ) {
402 case PT_LOAD:
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);
408 break;
409 default:
410 break;
414 * (int *)ptr = 1; /* Signal that we were called */
415 return 0;
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);
433 # endif
436 return TRUE;
437 } else {
438 return FALSE;
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. */
460 #if defined(NETBSD)
461 # include <sys/exec_elf.h>
462 /* for compatibility with 1.4.x */
463 # ifndef DT_DEBUG
464 # define DT_DEBUG 21
465 # endif
466 # ifndef PT_LOAD
467 # define PT_LOAD 1
468 # endif
469 # ifndef PF_W
470 # define PF_W 2
471 # endif
472 #else
473 # include <elf.h>
474 #endif
475 #include <link.h>
477 # endif
479 #ifdef __GNUC__
480 # pragma weak _DYNAMIC
481 #endif
482 extern ElfW(Dyn) _DYNAMIC[];
484 static struct link_map *
485 GC_FirstDLOpenedLinkMap()
487 ElfW(Dyn) *dp;
488 struct r_debug *r;
489 static struct link_map *cachedResult = 0;
491 if( _DYNAMIC == 0) {
492 return(0);
494 if( cachedResult == 0 ) {
495 int tag;
496 for( dp = _DYNAMIC; (tag = dp->d_tag) != 0; dp++ ) {
497 if( tag == DT_DEBUG ) {
498 struct link_map *lm
499 = ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
500 if( lm != 0 ) cachedResult = lm->l_next; /* might be NIL */
501 break;
505 return cachedResult;
509 void GC_register_dynamic_libraries()
511 struct link_map *lm;
514 # ifdef HAVE_DL_ITERATE_PHDR
515 if (GC_register_dynamic_libraries_dl_iterate_phdr()) {
516 return;
518 # endif
519 lm = GC_FirstDLOpenedLinkMap();
520 for (lm = GC_FirstDLOpenedLinkMap();
521 lm != (struct link_map *) 0; lm = lm->l_next)
523 ElfW(Ehdr) * e;
524 ElfW(Phdr) * p;
525 unsigned long offset;
526 char * start;
527 register int i;
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 ) {
534 case PT_LOAD:
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);
540 break;
541 default:
542 break;
548 #endif /* !USE_PROC_FOR_LIBRARIES */
550 #endif /* LINUX */
552 #if defined(IRIX5) || (defined(USE_PROC_FOR_LIBRARIES) && !defined(LINUX))
554 #include <sys/procfs.h>
555 #include <sys/stat.h>
556 #include <fcntl.h>
557 #include <elf.h>
558 #include <errno.h>
559 #include <signal.h> /* Only for the following test. */
560 #ifndef _sigargs
561 # define IRIX6
562 #endif
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()
574 static int fd = -1;
575 char buf[30];
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 */
579 register int i;
580 register long flags;
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;
586 # ifdef SUNOS5DL
587 # define MA_PHYS 0
588 # endif /* SUNOS5DL */
590 if (fd < 0) {
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);
595 if (fd < 0) {
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))
623 goto irrelevant;
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)
632 goto irrelevant;
633 # ifdef MMAP_STACKS
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. */
641 # ifndef IRIX6
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. */
645 caddr_t arg;
646 int obj;
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;
651 struct stat buf;
652 register int i;
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);
659 if (obj >= 0) {
660 fstat(obj, &buf);
661 close(obj);
662 if ((buf.st_mode & 0111) != 0) {
663 if (n_irr < MAP_IRR_SZ) {
664 map_irr[n_irr++] = start;
666 goto irrelevant;
670 # endif /* !IRIX6 */
671 GC_add_roots_inner(start, limit, TRUE);
672 irrelevant: ;
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");
677 fd = -1;
680 # endif /* USE_PROC || IRIX5 */
682 # if defined(MSWIN32) || defined(MSWINCE)
684 # define WIN32_LEAN_AND_MEAN
685 # define NOSERVICE
686 # include <windows.h>
687 # include <stdlib.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;
703 for(;;) {
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);
711 # else
712 void GC_cond_add_roots(char *base, char * limit)
714 char dummy;
715 char * stack_top
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. */
720 return;
722 GC_add_roots_inner(base, limit, TRUE);
724 # endif
726 # ifdef MSWINCE
727 /* Do we need to separately register the main static data segment? */
728 GC_bool GC_register_main_static_data()
730 return FALSE;
732 # else /* win32 */
733 extern GC_bool GC_no_win32_dlls;
735 GC_bool GC_register_main_static_data()
737 return GC_no_win32_dlls;
739 # endif /* win32 */
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 */
746 /* problems. */
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 */
753 /* checking. */
755 /* Issue warning if tracing apparent framebuffer. */
756 /* This limits us to one warning, and it's a back door to */
757 /* disable that. */
759 /* Should [start, start+len) be treated as a frame buffer */
760 /* and ignored? */
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 */
765 /* do better. */
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
777 # define MIN_FB_MB 3
779 if (GC_disallow_ignore_fb) return FALSE;
780 if (!initialized) {
781 char * ignore_fb_string = GETENV("GC_IGNORE_FB");
783 if (0 != ignore_fb_string) {
784 while (*ignore_fb_string == ' ' || *ignore_fb_string == '\t')
785 ++ignore_fb_string;
786 if (*ignore_fb_string == '\0') {
787 GC_ignore_fb_mb = DEFAULT_FB_MB;
788 } else {
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;
795 GC_ignore_fb = TRUE;
796 } else {
797 GC_ignore_fb_mb = DEFAULT_FB_MB; /* For warning */
799 initialized = TRUE;
801 if (len >= ((size_t)GC_ignore_fb_mb << 20)) {
802 if (GC_ignore_fb) {
803 return TRUE;
804 } else {
805 if (GC_warn_fb) {
806 WARN("Possible frame buffer mapping at 0x%lx: \n"
807 "\tConsider setting GC_IGNORE_FB to improve performance.\n",
808 start);
809 GC_warn_fb = FALSE;
811 return FALSE;
813 } else {
814 return FALSE;
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,
823 buf -> RegionSize);
824 GC_printf4("\tAllocationProtect = %lx, State = %lx, Protect = %lx, "
825 "Type = %lx\n",
826 buf -> AllocationProtect, buf -> State, buf -> Protect,
827 buf -> Type);
829 # endif /* DEBUG_VIRTUALQUERY */
831 void GC_register_dynamic_libraries()
833 MEMORY_BASIC_INFORMATION buf;
834 DWORD result;
835 DWORD protect;
836 LPVOID p;
837 char * base;
838 char * limit, * new_limit;
840 # ifdef MSWIN32
841 if (GC_no_win32_dlls) return;
842 # endif
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));
848 if (result == 0) {
849 /* Page is free; advance to the next possible allocation base */
850 new_limit = (char *)
851 (((DWORD) p + GC_sysinfo.dwAllocationGranularity)
852 & ~(GC_sysinfo.dwAllocationGranularity-1));
853 } else
854 # else
855 while (p < GC_sysinfo.lpMaximumApplicationAddress) {
856 result = VirtualQuery(p, &buf, sizeof(buf));
857 # endif
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);
875 # endif
876 if ((char *)p != limit) {
877 GC_cond_add_roots(base, limit);
878 base = p;
880 limit = new_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)
893 #include <loader.h>
895 void GC_register_dynamic_libraries()
897 int status;
898 ldr_process_t mypid;
900 /* module */
901 ldr_module_t moduleid = LDR_NULL_MODULE;
902 ldr_module_info_t moduleinfo;
903 size_t moduleinfosize = sizeof(moduleinfo);
904 size_t modulereturnsize;
906 /* region */
907 ldr_region_t region;
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 */
916 while (TRUE) {
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 */
927 if (status != 0 ) {
928 GC_printf1("dynamic_load: status = %ld\n", (long)status);
930 extern char *sys_errlist[];
931 extern int sys_nerr;
932 extern int errno;
933 if (errno <= sys_nerr) {
934 GC_printf1("dynamic_load: %s\n", (long)sys_errlist[errno]);
935 } else {
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);
945 if (status != 0 )
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 */
952 # ifdef VERBOSE
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);
958 # endif
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, &regioninfo,
965 regioninfosize, &regionreturnsize);
966 if (status != 0 )
967 ABORT("ldr_inq_region failed");
969 /* only process writable (data) regions */
970 if (! (regioninfo.lri_prot & LDR_W))
971 continue;
973 # ifdef VERBOSE
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);
982 # endif
984 /* register region as a garbage collection root */
985 GC_add_roots_inner (
986 (char *)regioninfo.lri_mapaddr,
987 (char *)regioninfo.lri_mapaddr + regioninfo.lri_size,
988 TRUE);
993 #endif
995 #if defined(HPUX)
997 #include <errno.h>
998 #include <dl.h>
1000 extern int errno;
1001 extern char *sys_errlist[];
1002 extern int sys_nerr;
1004 void GC_register_dynamic_libraries()
1006 int status;
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 */
1011 while (TRUE) {
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 */
1017 if (status != 0) {
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. */
1021 break;
1022 # else
1023 if (errno == EINVAL) {
1024 break; /* Moved past end of shared library list --> finished */
1025 } else {
1026 if (errno <= sys_nerr) {
1027 GC_printf1("dynamic_load: %s\n", (long) sys_errlist[errno]);
1028 } else {
1029 GC_printf1("dynamic_load: %d\n", (long) errno);
1031 ABORT("shl_get failed");
1033 # endif
1036 # ifdef VERBOSE
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);
1047 # endif
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);
1053 index++;
1056 #endif /* HPUX */
1058 #ifdef RS6000
1059 #pragma alloca
1060 #include <sys/ldr.h>
1061 #include <sys/errno.h>
1062 void GC_register_dynamic_libraries()
1064 int len;
1065 char *ldibuf;
1066 int ldibuflen;
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;
1079 while (ldi) {
1080 len = ldi->ldinfo_next;
1081 GC_add_roots_inner(
1082 ldi->ldinfo_dataorg,
1083 (ptr_t)(unsigned long)ldi->ldinfo_dataorg
1084 + ldi->ldinfo_datasize,
1085 TRUE);
1086 ldi = len ? (struct ld_info *)((char *)ldi + len) : 0;
1089 #endif /* RS6000 */
1091 #ifdef DARWIN
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__
1098 #else
1099 # include <mach-o/dyld.h>
1100 #endif
1101 #include <mach-o/getsect.h>
1103 /*#define DARWIN_DEBUG*/
1105 const static struct {
1106 const char *seg;
1107 const char *sect;
1108 } GC_dyld_sections[] = {
1109 { SEG_DATA, SECT_DATA },
1110 { SEG_DATA, SECT_BSS },
1111 { SEG_DATA, SECT_COMMON }
1114 #ifdef DARWIN_DEBUG
1115 static const char *GC_dyld_name_for_hdr(struct mach_header *hdr) {
1116 unsigned long i,c;
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);
1120 return NULL;
1122 #endif
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));
1137 # endif
1138 GC_add_roots((char*)start,(char*)end);
1140 # ifdef DARWIN_DEBUG
1141 GC_print_static_roots();
1142 # endif
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));
1158 # endif
1159 GC_remove_roots((char*)start,(char*)end);
1161 # ifdef DARWIN_DEBUG
1162 GC_print_static_roots();
1163 # endif
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");
1185 # endif
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. */
1202 initialized = TRUE;
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");
1209 # endif
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 */
1221 return FALSE;
1224 #endif /* DARWIN */
1226 #else /* !DYNAMIC_LOADING */
1228 #ifdef PCR
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 */
1247 /* objects. */
1248 p = p -> lf_prev;
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) {
1254 GC_add_roots_inner
1255 ((char *)(q -> ls_addr),
1256 (char *)(q -> ls_addr) + q -> ls_bytes,
1257 TRUE);
1265 #else /* !PCR */
1267 void GC_register_dynamic_libraries(){}
1269 int GC_no_dynamic_loading;
1271 #endif /* !PCR */
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()
1280 return TRUE;
1282 #endif /* HAVE_REGISTER_MAIN_STATIC_DATA */