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.
32 #if (defined(__linux__) || defined(__GLIBC__) || defined(__GNU__)) \
33 && !defined(_GNU_SOURCE)
34 /* Can't test LINUX, since this must be defined before other includes */
37 #if !defined(MACOS) && !defined(_WIN32_WCE)
38 # include <sys/types.h>
40 #include "private/gc_priv.h"
42 /* BTL: avoid circular redefinition of dlopen if GC_SOLARIS_THREADS defined */
43 # if (defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS)) \
44 && defined(dlopen) && !defined(GC_USE_LD_WRAP)
45 /* To support threads in Solaris, gc.h interposes on dlopen by */
46 /* defining "dlopen" to be "GC_dlopen", which is implemented below. */
47 /* However, both GC_FirstDLOpenedLinkMap() and GC_dlopen() use the */
48 /* real system dlopen() in their implementation. We first remove */
49 /* gc.h's dlopen definition and restore it later, after GC_dlopen(). */
51 # define GC_must_restore_redefined_dlopen
53 # undef GC_must_restore_redefined_dlopen
56 /* A user-supplied routine that is called to determine if a DSO must
57 be scanned by the gc. */
58 static int (*GC_has_static_roots)(const char *, void *, size_t);
61 #if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE)) \
63 #if !defined(SOLARISDL) && !defined(IRIX5) && \
64 !defined(MSWIN32) && !defined(MSWINCE) && \
65 !(defined(ALPHA) && defined(OSF1)) && \
66 !defined(HPUX) && !(defined(LINUX) && defined(__ELF__)) && \
67 !defined(AIX) && !defined(SCO_ELF) && !defined(DGUX) && \
68 !(defined(FREEBSD) && defined(__ELF__)) && \
69 !(defined(NETBSD) && defined(__ELF__)) && !defined(HURD) && \
70 !defined(DARWIN) && !defined(CYGWIN32)
71 --> We only know how to find data segments of dynamic libraries for the
72 --> above. Additional SVR4 variants might not be too
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. */
100 # if __ELF_WORD_SIZE == 32
101 # define ElfW(type) Elf32_##type
103 # define ElfW(type) Elf64_##type
105 # elif defined(NETBSD)
107 # define ElfW(type) Elf32_##type
109 # define ElfW(type) Elf64_##type
112 # if !defined(ELF_CLASS) || ELF_CLASS == ELFCLASS32
113 # define ElfW(type) Elf32_##type
115 # define ElfW(type) Elf64_##type
120 #if defined(SOLARISDL) && !defined(USE_PROC_FOR_LIBRARIES)
126 static struct link_map *
127 GC_FirstDLOpenedLinkMap()
129 extern ElfW(Dyn) _DYNAMIC;
132 static struct link_map * cachedResult = 0;
133 static ElfW(Dyn) *dynStructureAddr = 0;
134 /* BTL: added to avoid Solaris 5.3 ld.so _DYNAMIC bug */
136 # ifdef SUNOS53_SHARED_LIB
137 /* BTL: Avoid the Solaris 5.3 bug that _DYNAMIC isn't being set */
138 /* up properly in dynamically linked .so's. This means we have */
139 /* to use its value in the set of original object files loaded */
140 /* at program startup. */
141 if( dynStructureAddr == 0 ) {
142 void* startupSyms = dlopen(0, RTLD_LAZY);
143 dynStructureAddr = (ElfW(Dyn)*)dlsym(startupSyms, "_DYNAMIC");
146 dynStructureAddr = &_DYNAMIC;
149 if( dynStructureAddr == 0) {
152 if( cachedResult == 0 ) {
154 for( dp = ((ElfW(Dyn) *)(&_DYNAMIC)); (tag = dp->d_tag) != 0; dp++ ) {
155 if( tag == DT_DEBUG ) {
157 = ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
158 if( lm != 0 ) cachedResult = lm->l_next; /* might be NIL */
166 #endif /* SOLARISDL ... */
168 /* BTL: added to fix circular dlopen definition if GC_SOLARIS_THREADS defined */
169 # if defined(GC_must_restore_redefined_dlopen)
170 # define dlopen GC_dlopen
173 # if defined(SOLARISDL)
174 /* Add dynamic library data sections to the root set. */
175 # if !defined(PCR) && !defined(GC_SOLARIS_THREADS) && defined(THREADS)
176 --> fix mutual exclusion with dlopen
179 # ifndef USE_PROC_FOR_LIBRARIES
180 void GC_register_dynamic_libraries()
182 struct link_map *lm = GC_FirstDLOpenedLinkMap();
185 for (lm = GC_FirstDLOpenedLinkMap();
186 lm != (struct link_map *) 0; lm = lm->l_next)
190 unsigned long offset;
194 e = (ElfW(Ehdr) *) lm->l_addr;
195 p = ((ElfW(Phdr) *)(((char *)(e)) + e->e_phoff));
196 offset = ((unsigned long)(lm->l_addr));
197 for( i = 0; i < (int)(e->e_phnum); ((i++),(p++)) ) {
198 switch( p->p_type ) {
201 if( !(p->p_flags & PF_W) ) break;
202 start = ((char *)(p->p_vaddr)) + offset;
217 # endif /* !USE_PROC ... */
218 # endif /* SOLARISDL */
220 #if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
221 (defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \
222 (defined(NETBSD) && defined(__ELF__)) || defined(HURD)
225 #ifdef USE_PROC_FOR_LIBRARIES
229 #include <sys/stat.h>
233 #define MAPS_BUF_SIZE (32*1024)
235 extern ssize_t GC_repeat_read(int fd, char *buf, size_t count);
236 /* Repeatedly read until buffer is filled, or EOF is encountered */
237 /* Defined in os_dep.c. */
239 char *GC_parse_map_entry(char *buf_ptr, ptr_t *start, ptr_t *end,
240 char **prot, unsigned int *maj_dev,
241 char **mapping_name);
242 char *GC_get_maps(void);
245 /* Sort an array of HeapSects by start address. */
246 /* Unfortunately at least some versions of */
247 /* Linux qsort end up calling malloc by way of sysconf, and hence can't */
248 /* be used in the colector. Hence we roll our own. Should be */
249 /* reasonably fast if the array is already mostly sorted, as we expect */
251 void sort_heap_sects(struct HeapSect *base, size_t number_of_elements)
253 signed_word n = (signed_word)number_of_elements;
254 signed_word nsorted = 1;
257 while (nsorted < n) {
258 while (nsorted < n &&
259 base[nsorted-1].hs_start < base[nsorted].hs_start)
261 if (nsorted == n) break;
262 GC_ASSERT(base[nsorted-1].hs_start > base[nsorted].hs_start);
264 while (i >= 0 && base[i].hs_start > base[i+1].hs_start) {
265 struct HeapSect tmp = base[i];
270 GC_ASSERT(base[nsorted-1].hs_start < base[nsorted].hs_start);
275 word GC_register_map_entries(char *maps)
278 char *buf_ptr = maps;
281 unsigned int maj_dev;
282 ptr_t least_ha, greatest_ha;
284 ptr_t datastart = (ptr_t)(DATASTART);
286 GC_ASSERT(I_HOLD_LOCK());
287 sort_heap_sects(GC_our_memory, GC_n_memory);
288 least_ha = GC_our_memory[0].hs_start;
289 greatest_ha = GC_our_memory[GC_n_memory-1].hs_start
290 + GC_our_memory[GC_n_memory-1].hs_bytes;
293 buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, &prot, &maj_dev, 0);
294 if (buf_ptr == NULL) return 1;
295 if (prot[1] == 'w') {
296 /* This is a writable mapping. Add it to */
297 /* the root set unless it is already otherwise */
299 if (start <= GC_stackbottom && end >= GC_stackbottom) {
300 /* Stack mapping; discard */
304 /* This may fail, since a thread may already be */
305 /* unregistered, but its thread stack may still be there. */
306 /* That can fail because the stack may disappear while */
307 /* we're marking. Thus the marker is, and has to be */
308 /* prepared to recover from segmentation faults. */
310 if (GC_segment_is_thread_stack(start, end)) continue;
312 /* FIXME: NPTL squirrels */
313 /* away pointers in pieces of the stack segment that we */
314 /* don't scan. We work around this */
315 /* by treating anything allocated by libpthread as */
316 /* uncollectable, as we do in some other cases. */
317 /* A specifically identified problem is that */
318 /* thread stacks contain pointers to dynamic thread */
319 /* vectors, which may be reused due to thread caching. */
320 /* They may not be marked if the thread is still live. */
321 /* This specific instance should be addressed by */
322 /* INCLUDE_LINUX_THREAD_DESCR, but that doesn't quite */
323 /* seem to suffice. */
324 /* We currently trace entire thread stacks, if they are */
325 /* are currently cached but unused. This is */
326 /* very suboptimal for performance reasons. */
328 /* We no longer exclude the main data segment. */
329 if (end <= least_ha || start >= greatest_ha) {
330 /* The easy case; just trace entire segment */
331 GC_add_roots_inner((char *)start, (char *)end, TRUE);
334 /* Add sections that dont belong to us. */
336 while (GC_our_memory[i].hs_start + GC_our_memory[i].hs_bytes
339 GC_ASSERT(i < GC_n_memory);
340 if (GC_our_memory[i].hs_start <= start) {
341 start = GC_our_memory[i].hs_start
342 + GC_our_memory[i].hs_bytes;
345 while (i < GC_n_memory && GC_our_memory[i].hs_start < end
347 if ((char *)start < GC_our_memory[i].hs_start)
348 GC_add_roots_inner((char *)start,
349 GC_our_memory[i].hs_start, TRUE);
350 start = GC_our_memory[i].hs_start
351 + GC_our_memory[i].hs_bytes;
355 GC_add_roots_inner((char *)start, (char *)end, TRUE);
361 void GC_register_dynamic_libraries()
363 if (!GC_register_map_entries(GC_get_maps()))
364 ABORT("Failed to read /proc for library registration.");
367 /* We now take care of the main data segment ourselves: */
368 GC_bool GC_register_main_static_data()
373 # define HAVE_REGISTER_MAIN_STATIC_DATA
375 #endif /* USE_PROC_FOR_LIBRARIES */
377 #if !defined(USE_PROC_FOR_LIBRARIES)
378 /* The following is the preferred way to walk dynamic libraries */
379 /* For glibc 2.2.4+. Unfortunately, it doesn't work for older */
380 /* versions. Thanks to Jakub Jelinek for most of the code. */
382 # if (defined(LINUX) || defined (__GLIBC__)) /* Are others OK here, too? */ \
383 && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) \
384 || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && defined(DT_CONFIG)))
386 /* We have the header files for a glibc that includes dl_iterate_phdr. */
387 /* It may still not be available in the library on the target system. */
388 /* Thus we also treat it as a weak symbol. */
389 #define HAVE_DL_ITERATE_PHDR
391 static int GC_register_dynlib_callback(info, size, ptr)
392 struct dl_phdr_info * info;
396 const ElfW(Phdr) * p;
400 /* Make sure struct dl_phdr_info is at least as big as we need. */
401 if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
402 + sizeof (info->dlpi_phnum))
406 for( i = 0; i < (int)(info->dlpi_phnum); ((i++),(p++)) ) {
407 switch( p->p_type ) {
410 if( !(p->p_flags & PF_W) ) break;
411 start = ((char *)(p->p_vaddr)) + info->dlpi_addr;
413 if (GC_has_static_roots
414 && !GC_has_static_roots(info->dlpi_name, start, p->p_memsz))
417 GC_add_roots_inner(start, start + p->p_memsz, TRUE);
425 * (int *)ptr = 1; /* Signal that we were called */
429 /* Return TRUE if we succeed, FALSE if dl_iterate_phdr wasn't there. */
431 #pragma weak dl_iterate_phdr
433 GC_bool GC_register_dynamic_libraries_dl_iterate_phdr()
435 if (dl_iterate_phdr) {
436 int did_something = 0;
437 dl_iterate_phdr(GC_register_dynlib_callback, &did_something);
438 if (!did_something) {
439 /* dl_iterate_phdr may forget the static data segment in */
440 /* statically linked executables. */
441 GC_add_roots_inner(DATASTART, (char *)(DATAEND), TRUE);
442 # if defined(DATASTART2)
443 GC_add_roots_inner(DATASTART2, (char *)(DATAEND2), TRUE);
453 /* Do we need to separately register the main static data segment? */
454 GC_bool GC_register_main_static_data()
456 return (dl_iterate_phdr == 0);
459 #define HAVE_REGISTER_MAIN_STATIC_DATA
461 # else /* !LINUX || version(glibc) < 2.2.4 */
463 /* Dynamic loading code for Linux running ELF. Somewhat tested on
464 * Linux/x86, untested but hopefully should work on Linux/Alpha.
465 * This code was derived from the Solaris/ELF support. Thanks to
466 * whatever kind soul wrote that. - Patrick Bridges */
468 /* This doesn't necessarily work in all cases, e.g. with preloaded
469 * dynamic libraries. */
472 # include <sys/exec_elf.h>
473 /* for compatibility with 1.4.x */
491 # pragma weak _DYNAMIC
493 extern ElfW(Dyn) _DYNAMIC[];
495 static struct link_map *
496 GC_FirstDLOpenedLinkMap()
499 static struct link_map *cachedResult = 0;
504 if( cachedResult == 0 ) {
506 for( dp = _DYNAMIC; (tag = dp->d_tag) != 0; dp++ ) {
507 if( tag == DT_DEBUG ) {
509 = ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
510 if( lm != 0 ) cachedResult = lm->l_next; /* might be NIL */
519 void GC_register_dynamic_libraries()
524 # ifdef HAVE_DL_ITERATE_PHDR
525 if (GC_register_dynamic_libraries_dl_iterate_phdr()) {
529 lm = GC_FirstDLOpenedLinkMap();
530 for (lm = GC_FirstDLOpenedLinkMap();
531 lm != (struct link_map *) 0; lm = lm->l_next)
535 unsigned long offset;
539 e = (ElfW(Ehdr) *) lm->l_addr;
540 p = ((ElfW(Phdr) *)(((char *)(e)) + e->e_phoff));
541 offset = ((unsigned long)(lm->l_addr));
542 for( i = 0; i < (int)(e->e_phnum); ((i++),(p++)) ) {
543 switch( p->p_type ) {
546 if( !(p->p_flags & PF_W) ) break;
547 start = ((char *)(p->p_vaddr)) + offset;
548 GC_add_roots_inner(start, start + p->p_memsz, TRUE);
558 #endif /* !USE_PROC_FOR_LIBRARIES */
562 #if defined(IRIX5) || (defined(USE_PROC_FOR_LIBRARIES) && !defined(LINUX))
564 #include <sys/procfs.h>
565 #include <sys/stat.h>
569 #include <signal.h> /* Only for the following test. */
574 extern void * GC_roots_present();
575 /* The type is a lie, since the real type doesn't make sense here, */
576 /* and we only test for NULL. */
579 /* We use /proc to track down all parts of the address space that are */
580 /* mapped by the process, and throw out regions we know we shouldn't */
581 /* worry about. This may also work under other SVR4 variants. */
582 void GC_register_dynamic_libraries()
586 static prmap_t * addr_map = 0;
587 static int current_sz = 0; /* Number of records currently in addr_map */
588 static int needed_sz; /* Required size of addr_map */
593 ptr_t heap_start = (ptr_t)HEAP_START;
594 ptr_t heap_end = heap_start;
598 # endif /* SOLARISDL */
601 sprintf(buf, "/proc/%d", getpid());
602 /* The above generates a lint complaint, since pid_t varies. */
603 /* It's unclear how to improve this. */
604 fd = open(buf, O_RDONLY);
606 ABORT("/proc open failed");
609 if (ioctl(fd, PIOCNMAP, &needed_sz) < 0) {
610 GC_err_printf("fd = %d, errno = %d\n", fd, errno);
611 ABORT("/proc PIOCNMAP ioctl failed");
613 if (needed_sz >= current_sz) {
614 current_sz = needed_sz * 2 + 1;
615 /* Expansion, plus room for 0 record */
616 addr_map = (prmap_t *)GC_scratch_alloc((word)
617 (current_sz * sizeof(prmap_t)));
619 if (ioctl(fd, PIOCMAP, addr_map) < 0) {
620 GC_err_printf("fd = %d, errno = %d, needed_sz = %d, addr_map = 0x%X\n",
621 fd, errno, needed_sz, addr_map);
622 ABORT("/proc PIOCMAP ioctl failed");
624 if (GC_n_heap_sects > 0) {
625 heap_end = GC_heap_sects[GC_n_heap_sects-1].hs_start
626 + GC_heap_sects[GC_n_heap_sects-1].hs_bytes;
627 if (heap_end < GC_scratch_last_end_ptr) heap_end = GC_scratch_last_end_ptr;
629 for (i = 0; i < needed_sz; i++) {
630 flags = addr_map[i].pr_mflags;
631 if ((flags & (MA_BREAK | MA_STACK | MA_PHYS
632 | MA_FETCHOP | MA_NOTCACHED)) != 0) goto irrelevant;
633 if ((flags & (MA_READ | MA_WRITE)) != (MA_READ | MA_WRITE))
635 /* The latter test is empirically useless in very old Irix */
636 /* versions. Other than the */
637 /* main data and stack segments, everything appears to be */
638 /* mapped readable, writable, executable, and shared(!!). */
639 /* This makes no sense to me. - HB */
640 start = (ptr_t)(addr_map[i].pr_vaddr);
641 if (GC_roots_present(start)) goto irrelevant;
642 if (start < heap_end && start >= heap_start)
645 if (GC_is_thread_stack(start)) goto irrelevant;
646 # endif /* MMAP_STACKS */
648 limit = start + addr_map[i].pr_size;
649 /* The following seemed to be necessary for very old versions */
650 /* of Irix, but it has been reported to discard relevant */
651 /* segments under Irix 6.5. */
653 if (addr_map[i].pr_off == 0 && strncmp(start, ELFMAG, 4) == 0) {
654 /* Discard text segments, i.e. 0-offset mappings against */
655 /* executable files which appear to have ELF headers. */
658 # define MAP_IRR_SZ 10
659 static ptr_t map_irr[MAP_IRR_SZ];
660 /* Known irrelevant map entries */
661 static int n_irr = 0;
665 for (i = 0; i < n_irr; i++) {
666 if (map_irr[i] == start) goto irrelevant;
668 arg = (caddr_t)start;
669 obj = ioctl(fd, PIOCOPENM, &arg);
673 if ((buf.st_mode & 0111) != 0) {
674 if (n_irr < MAP_IRR_SZ) {
675 map_irr[n_irr++] = start;
682 GC_add_roots_inner(start, limit, TRUE);
685 /* Dont keep cached descriptor, for now. Some kernels don't like us */
686 /* to keep a /proc file descriptor around during kill -9. */
687 if (close(fd) < 0) ABORT("Couldnt close /proc file");
691 # endif /* USE_PROC || IRIX5 */
693 # if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
695 # define WIN32_LEAN_AND_MEAN
697 # include <windows.h>
700 /* We traverse the entire address space and register all segments */
701 /* that could possibly have been written to. */
703 extern GC_bool GC_is_heap_base (ptr_t p);
705 # ifdef GC_WIN32_THREADS
706 extern void GC_get_next_stack(char *start, char **lo, char **hi);
707 void GC_cond_add_roots(char *base, char * limit)
709 char * curr_base = base;
710 char * next_stack_lo;
711 char * next_stack_hi;
713 if (base == limit) return;
715 GC_get_next_stack(curr_base, &next_stack_lo, &next_stack_hi);
716 if (next_stack_lo >= limit) break;
717 GC_add_roots_inner(curr_base, next_stack_lo, TRUE);
718 curr_base = next_stack_hi;
720 if (curr_base < limit) GC_add_roots_inner(curr_base, limit, TRUE);
723 void GC_cond_add_roots(char *base, char * limit)
727 = (char *) ((word)(&dummy) & ~(GC_sysinfo.dwAllocationGranularity-1));
728 if (base == limit) return;
729 if (limit > stack_top && base < GC_stackbottom) {
730 /* Part of the stack; ignore it. */
733 GC_add_roots_inner(base, limit, TRUE);
738 /* Do we need to separately register the main static data segment? */
739 GC_bool GC_register_main_static_data()
744 extern GC_bool GC_no_win32_dlls;
746 GC_bool GC_register_main_static_data()
748 return GC_no_win32_dlls;
752 # define HAVE_REGISTER_MAIN_STATIC_DATA
754 # ifdef DEBUG_VIRTUALQUERY
755 void GC_dump_meminfo(MEMORY_BASIC_INFORMATION *buf)
757 GC_printf("BaseAddress = %lx, AllocationBase = %lx, RegionSize = %lx(%lu)\n",
758 buf -> BaseAddress, buf -> AllocationBase, buf -> RegionSize,
760 GC_printf("\tAllocationProtect = %lx, State = %lx, Protect = %lx, "
762 buf -> AllocationProtect, buf -> State, buf -> Protect,
765 # endif /* DEBUG_VIRTUALQUERY */
767 extern GC_bool GC_wnt; /* Is Windows NT derivative. */
768 /* Defined and set in os_dep.c. */
770 void GC_register_dynamic_libraries()
772 MEMORY_BASIC_INFORMATION buf;
777 char * limit, * new_limit;
780 if (GC_no_win32_dlls) return;
782 base = limit = p = GC_sysinfo.lpMinimumApplicationAddress;
783 # if defined(MSWINCE) && !defined(_WIN32_WCE_EMULATION)
784 /* Only the first 32 MB of address space belongs to the current process */
785 while (p < (LPVOID)0x02000000) {
786 result = VirtualQuery(p, &buf, sizeof(buf));
788 /* Page is free; advance to the next possible allocation base */
790 (((DWORD) p + GC_sysinfo.dwAllocationGranularity)
791 & ~(GC_sysinfo.dwAllocationGranularity-1));
794 while (p < GC_sysinfo.lpMaximumApplicationAddress) {
795 result = VirtualQuery(p, &buf, sizeof(buf));
798 if (result != sizeof(buf)) {
799 ABORT("Weird VirtualQuery result");
801 new_limit = (char *)p + buf.RegionSize;
802 protect = buf.Protect;
803 if (buf.State == MEM_COMMIT
804 && (protect == PAGE_EXECUTE_READWRITE
805 || protect == PAGE_READWRITE)
806 && !GC_is_heap_base(buf.AllocationBase)
807 /* There is some evidence that we cannot always
808 * ignore MEM_PRIVATE sections under Windows ME
809 * and predecessors. Hence we now also check for
811 && (buf.Type == MEM_IMAGE ||
812 !GC_wnt && buf.Type == MEM_PRIVATE)) {
813 # ifdef DEBUG_VIRTUALQUERY
814 GC_dump_meminfo(&buf);
816 if ((char *)p != limit) {
817 GC_cond_add_roots(base, limit);
823 if (p > (LPVOID)new_limit /* overflow */) break;
824 p = (LPVOID)new_limit;
826 GC_cond_add_roots(base, limit);
829 #endif /* MSWIN32 || MSWINCE || CYGWIN32 */
831 #if defined(ALPHA) && defined(OSF1)
835 void GC_register_dynamic_libraries()
841 ldr_module_t moduleid = LDR_NULL_MODULE;
842 ldr_module_info_t moduleinfo;
843 size_t moduleinfosize = sizeof(moduleinfo);
844 size_t modulereturnsize;
848 ldr_region_info_t regioninfo;
849 size_t regioninfosize = sizeof(regioninfo);
850 size_t regionreturnsize;
852 /* Obtain id of this process */
853 mypid = ldr_my_process();
855 /* For each module */
858 /* Get the next (first) module */
859 status = ldr_next_module(mypid, &moduleid);
861 /* Any more modules? */
862 if (moduleid == LDR_NULL_MODULE)
863 break; /* No more modules */
865 /* Check status AFTER checking moduleid because */
866 /* of a bug in the non-shared ldr_next_module stub */
868 GC_printf("dynamic_load: status = %d\n", status);
870 extern char *sys_errlist[];
873 if (errno <= sys_nerr) {
874 GC_printf("dynamic_load: %s\n", sys_errlist[errno]);
876 GC_printf("dynamic_load: %d\n", errno);
879 ABORT("ldr_next_module failed");
882 /* Get the module information */
883 status = ldr_inq_module(mypid, moduleid, &moduleinfo,
884 moduleinfosize, &modulereturnsize);
886 ABORT("ldr_inq_module failed");
888 /* is module for the main program (i.e. nonshared portion)? */
889 if (moduleinfo.lmi_flags & LDR_MAIN)
890 continue; /* skip the main module */
893 GC_printf("---Module---\n");
894 GC_printf("Module ID = %16ld\n", moduleinfo.lmi_modid);
895 GC_printf("Count of regions = %16d\n", moduleinfo.lmi_nregion);
896 GC_printf("flags for module = %16lx\n", moduleinfo.lmi_flags);
897 GC_printf("pathname of module = \"%s\"\n", moduleinfo.lmi_name);
900 /* For each region in this module */
901 for (region = 0; region < moduleinfo.lmi_nregion; region++) {
903 /* Get the region information */
904 status = ldr_inq_region(mypid, moduleid, region, ®ioninfo,
905 regioninfosize, ®ionreturnsize);
907 ABORT("ldr_inq_region failed");
909 /* only process writable (data) regions */
910 if (! (regioninfo.lri_prot & LDR_W))
914 GC_printf("--- Region ---\n");
915 GC_printf("Region number = %16ld\n",
916 regioninfo.lri_region_no);
917 GC_printf("Protection flags = %016x\n", regioninfo.lri_prot);
918 GC_printf("Virtual address = %16p\n", regioninfo.lri_vaddr);
919 GC_printf("Mapped address = %16p\n", regioninfo.lri_mapaddr);
920 GC_printf("Region size = %16ld\n", regioninfo.lri_size);
921 GC_printf("Region name = \"%s\"\n", regioninfo.lri_name);
924 /* register region as a garbage collection root */
926 (char *)regioninfo.lri_mapaddr,
927 (char *)regioninfo.lri_mapaddr + regioninfo.lri_size,
940 extern char *sys_errlist[];
943 void GC_register_dynamic_libraries()
946 int index = 1; /* Ordinal position in shared library search list */
947 struct shl_descriptor *shl_desc; /* Shared library info, see dl.h */
949 /* For each dynamic library loaded */
952 /* Get info about next shared library */
953 status = shl_get(index, &shl_desc);
955 /* Check if this is the end of the list or if some error occured */
957 # ifdef GC_HPUX_THREADS
958 /* I've seen errno values of 0. The man page is not clear */
959 /* as to whether errno should get set on a -1 return. */
962 if (errno == EINVAL) {
963 break; /* Moved past end of shared library list --> finished */
965 if (errno <= sys_nerr) {
966 GC_printf("dynamic_load: %s\n", sys_errlist[errno]);
968 GC_printf("dynamic_load: %d\n", errno);
970 ABORT("shl_get failed");
976 GC_printf("---Shared library---\n");
977 GC_printf("\tfilename = \"%s\"\n", shl_desc->filename);
978 GC_printf("\tindex = %d\n", index);
979 GC_printf("\thandle = %08x\n",
980 (unsigned long) shl_desc->handle);
981 GC_printf("\ttext seg. start = %08x\n", shl_desc->tstart);
982 GC_printf("\ttext seg. end = %08x\n", shl_desc->tend);
983 GC_printf("\tdata seg. start = %08x\n", shl_desc->dstart);
984 GC_printf("\tdata seg. end = %08x\n", shl_desc->dend);
985 GC_printf("\tref. count = %lu\n", shl_desc->ref_count);
988 /* register shared library's data segment as a garbage collection root */
989 GC_add_roots_inner((char *) shl_desc->dstart,
990 (char *) shl_desc->dend, TRUE);
1000 #include <sys/errno.h>
1001 void GC_register_dynamic_libraries()
1006 struct ld_info *ldi;
1008 ldibuf = alloca(ldibuflen = 8192);
1010 while ( (len = loadquery(L_GETINFO,ldibuf,ldibuflen)) < 0) {
1011 if (errno != ENOMEM) {
1012 ABORT("loadquery failed");
1014 ldibuf = alloca(ldibuflen *= 2);
1017 ldi = (struct ld_info *)ldibuf;
1019 len = ldi->ldinfo_next;
1021 ldi->ldinfo_dataorg,
1022 (ptr_t)(unsigned long)ldi->ldinfo_dataorg
1023 + ldi->ldinfo_datasize,
1025 ldi = len ? (struct ld_info *)((char *)ldi + len) : 0;
1032 /* __private_extern__ hack required for pre-3.4 gcc versions. */
1033 #ifndef __private_extern__
1034 # define __private_extern__ extern
1035 # include <mach-o/dyld.h>
1036 # undef __private_extern__
1038 # include <mach-o/dyld.h>
1040 #include <mach-o/getsect.h>
1042 /*#define DARWIN_DEBUG*/
1044 const static struct {
1047 } GC_dyld_sections[] = {
1048 { SEG_DATA, SECT_DATA },
1049 { SEG_DATA, SECT_BSS },
1050 { SEG_DATA, SECT_COMMON }
1054 static const char *GC_dyld_name_for_hdr(const struct GC_MACH_HEADER *hdr) {
1056 c = _dyld_image_count();
1057 for(i=0;i<c;i++) if(_dyld_get_image_header(i) == hdr)
1058 return _dyld_get_image_name(i);
1063 /* This should never be called by a thread holding the lock */
1064 static void GC_dyld_image_add(const struct GC_MACH_HEADER *hdr, intptr_t slide)
1066 unsigned long start,end,i;
1067 const struct GC_MACH_SECTION *sec;
1068 if (GC_no_dls) return;
1069 for(i=0;i<sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]);i++) {
1070 sec = GC_GETSECTBYNAME(hdr, GC_dyld_sections[i].seg,
1071 GC_dyld_sections[i].sect);
1072 if(sec == NULL || sec->size == 0) continue;
1073 start = slide + sec->addr;
1074 end = start + sec->size;
1075 # ifdef DARWIN_DEBUG
1076 GC_printf("Adding section at %p-%p (%lu bytes) from image %s\n",
1077 start,end,sec->size,GC_dyld_name_for_hdr(hdr));
1079 GC_add_roots((char*)start,(char*)end);
1081 # ifdef DARWIN_DEBUG
1082 GC_print_static_roots();
1086 /* This should never be called by a thread holding the lock */
1087 static void GC_dyld_image_remove(const struct GC_MACH_HEADER *hdr,
1090 unsigned long start,end,i;
1091 const struct GC_MACH_SECTION *sec;
1092 for(i=0;i<sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]);i++) {
1093 sec = GC_GETSECTBYNAME(hdr, GC_dyld_sections[i].seg,
1094 GC_dyld_sections[i].sect);
1095 if(sec == NULL || sec->size == 0) continue;
1096 start = slide + sec->addr;
1097 end = start + sec->size;
1098 # ifdef DARWIN_DEBUG
1099 GC_printf("Removing section at %p-%p (%lu bytes) from image %s\n",
1100 start,end,sec->size,GC_dyld_name_for_hdr(hdr));
1102 GC_remove_roots((char*)start,(char*)end);
1104 # ifdef DARWIN_DEBUG
1105 GC_print_static_roots();
1109 void GC_register_dynamic_libraries() {
1110 /* Currently does nothing. The callbacks are setup by GC_init_dyld()
1111 The dyld library takes it from there. */
1114 /* The _dyld_* functions have an internal lock so no _dyld functions
1115 can be called while the world is stopped without the risk of a deadlock.
1116 Because of this we MUST setup callbacks BEFORE we ever stop the world.
1117 This should be called BEFORE any thread in created and WITHOUT the
1118 allocation lock held. */
1120 void GC_init_dyld() {
1121 static GC_bool initialized = FALSE;
1122 char *bind_fully_env = NULL;
1124 if(initialized) return;
1126 # ifdef DARWIN_DEBUG
1127 GC_printf("Registering dyld callbacks...\n");
1130 /* Apple's Documentation:
1131 When you call _dyld_register_func_for_add_image, the dynamic linker runtime
1132 calls the specified callback (func) once for each of the images that is
1133 currently loaded into the program. When a new image is added to the program,
1134 your callback is called again with the mach_header for the new image, and the
1135 virtual memory slide amount of the new image.
1137 This WILL properly register already linked libraries and libraries
1138 linked in the future
1141 _dyld_register_func_for_add_image(GC_dyld_image_add);
1142 _dyld_register_func_for_remove_image(GC_dyld_image_remove);
1144 /* Set this early to avoid reentrancy issues. */
1147 bind_fully_env = getenv("DYLD_BIND_AT_LAUNCH");
1149 if (bind_fully_env == NULL) {
1150 # ifdef DARWIN_DEBUG
1151 GC_printf("Forcing full bind of GC code...\n");
1154 if(!_dyld_bind_fully_image_containing_address((unsigned long*)GC_malloc))
1155 GC_abort("_dyld_bind_fully_image_containing_address failed");
1160 #define HAVE_REGISTER_MAIN_STATIC_DATA
1161 GC_bool GC_register_main_static_data()
1163 /* Already done through dyld callbacks */
1169 #else /* !DYNAMIC_LOADING */
1173 # include "il/PCR_IL.h"
1174 # include "th/PCR_ThCtl.h"
1175 # include "mm/PCR_MM.h"
1177 void GC_register_dynamic_libraries()
1179 /* Add new static data areas of dynamically loaded modules. */
1181 PCR_IL_LoadedFile * p = PCR_IL_GetLastLoadedFile();
1182 PCR_IL_LoadedSegment * q;
1184 /* Skip uncommited files */
1185 while (p != NIL && !(p -> lf_commitPoint)) {
1186 /* The loading of this file has not yet been committed */
1187 /* Hence its description could be inconsistent. */
1188 /* Furthermore, it hasn't yet been run. Hence its data */
1189 /* segments can't possibly reference heap allocated */
1193 for (; p != NIL; p = p -> lf_prev) {
1194 for (q = p -> lf_ls; q != NIL; q = q -> ls_next) {
1195 if ((q -> ls_flags & PCR_IL_SegFlags_Traced_MASK)
1196 == PCR_IL_SegFlags_Traced_on) {
1198 ((char *)(q -> ls_addr),
1199 (char *)(q -> ls_addr) + q -> ls_bytes,
1210 void GC_register_dynamic_libraries(){}
1212 int GC_no_dynamic_loading;
1216 #endif /* !DYNAMIC_LOADING */
1218 #ifndef HAVE_REGISTER_MAIN_STATIC_DATA
1220 /* Do we need to separately register the main static data segment? */
1221 GC_bool GC_register_main_static_data()
1226 /* Register a routine to filter dynamic library registration. */
1228 GC_register_has_static_roots_callback
1229 (int (*callback)(const char *, void *, size_t)) {
1230 GC_has_static_roots = callback;
1233 #endif /* HAVE_REGISTER_MAIN_STATIC_DATA */