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 word GC_register_map_entries(char *maps)
248 char *buf_ptr = maps;
251 unsigned int maj_dev;
252 ptr_t least_ha, greatest_ha;
254 ptr_t datastart = (ptr_t)(DATASTART);
256 /* Compute heap bounds. FIXME: Should work if heap and roots are */
258 least_ha = (ptr_t)(word)(-1);
260 for (i = 0; i < GC_n_heap_sects; ++i) {
261 ptr_t sect_start = GC_heap_sects[i].hs_start;
262 ptr_t sect_end = sect_start + GC_heap_sects[i].hs_bytes;
263 if (sect_start < least_ha) least_ha = sect_start;
264 if (sect_end > greatest_ha) greatest_ha = sect_end;
266 if (greatest_ha < (ptr_t)GC_scratch_last_end_ptr)
267 greatest_ha = (ptr_t)GC_scratch_last_end_ptr;
270 buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, &prot, &maj_dev, 0);
271 if (buf_ptr == NULL) return 1;
272 if (prot[1] == 'w') {
273 /* This is a writable mapping. Add it to */
274 /* the root set unless it is already otherwise */
276 if (start <= GC_stackbottom && end >= GC_stackbottom) {
277 /* Stack mapping; discard */
281 /* This may fail, since a thread may already be */
282 /* unregistered, but its thread stack may still be there. */
283 /* That can fail because the stack may disappear while */
284 /* we're marking. Thus the marker is, and has to be */
285 /* prepared to recover from segmentation faults. */
286 if (GC_segment_is_thread_stack(start, end)) continue;
287 /* FIXME: REDIRECT_MALLOC actually works with threads on */
288 /* LINUX/IA64 if we omit this check. The problem is that */
289 /* thread stacks contain pointers to dynamic thread */
290 /* vectors, which may be reused due to thread caching. */
291 /* Currently they may not be marked if the thread is */
293 /* For dead threads, we trace the whole stack, which is */
294 /* very suboptimal for performance reasons. */
296 /* We no longer exclude the main data segment. */
297 if (start < least_ha && end > least_ha) {
300 if (start < greatest_ha && end > greatest_ha) {
303 if (start >= least_ha && end <= greatest_ha) continue;
304 GC_add_roots_inner((char *)start, (char *)end, TRUE);
310 void GC_register_dynamic_libraries()
312 if (!GC_register_map_entries(GC_get_maps()))
313 ABORT("Failed to read /proc for library registration.");
316 /* We now take care of the main data segment ourselves: */
317 GC_bool GC_register_main_static_data()
322 # define HAVE_REGISTER_MAIN_STATIC_DATA
324 #endif /* USE_PROC_FOR_LIBRARIES */
326 #if !defined(USE_PROC_FOR_LIBRARIES)
327 /* The following is the preferred way to walk dynamic libraries */
328 /* For glibc 2.2.4+. Unfortunately, it doesn't work for older */
329 /* versions. Thanks to Jakub Jelinek for most of the code. */
331 # if (defined(LINUX) || defined (__GLIBC__)) /* Are others OK here, too? */ \
332 && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) \
333 || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && defined(DT_CONFIG)))
335 /* We have the header files for a glibc that includes dl_iterate_phdr. */
336 /* It may still not be available in the library on the target system. */
337 /* Thus we also treat it as a weak symbol. */
338 #define HAVE_DL_ITERATE_PHDR
340 static int GC_register_dynlib_callback(info, size, ptr)
341 struct dl_phdr_info * info;
345 const ElfW(Phdr) * p;
349 /* Make sure struct dl_phdr_info is at least as big as we need. */
350 if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
351 + sizeof (info->dlpi_phnum))
355 for( i = 0; i < (int)(info->dlpi_phnum); ((i++),(p++)) ) {
356 switch( p->p_type ) {
359 if( !(p->p_flags & PF_W) ) break;
360 start = ((char *)(p->p_vaddr)) + info->dlpi_addr;
362 if (GC_has_static_roots
363 && !GC_has_static_roots(info->dlpi_name, start, p->p_memsz))
366 GC_add_roots_inner(start, start + p->p_memsz, TRUE);
374 * (int *)ptr = 1; /* Signal that we were called */
378 /* Return TRUE if we succeed, FALSE if dl_iterate_phdr wasn't there. */
380 #pragma weak dl_iterate_phdr
382 GC_bool GC_register_dynamic_libraries_dl_iterate_phdr()
384 if (dl_iterate_phdr) {
385 int did_something = 0;
386 dl_iterate_phdr(GC_register_dynlib_callback, &did_something);
387 if (!did_something) {
388 /* dl_iterate_phdr may forget the static data segment in */
389 /* statically linked executables. */
390 GC_add_roots_inner(DATASTART, (char *)(DATAEND), TRUE);
391 # if defined(DATASTART2)
392 GC_add_roots_inner(DATASTART2, (char *)(DATAEND2), TRUE);
402 /* Do we need to separately register the main static data segment? */
403 GC_bool GC_register_main_static_data()
405 return (dl_iterate_phdr == 0);
408 #define HAVE_REGISTER_MAIN_STATIC_DATA
410 # else /* !LINUX || version(glibc) < 2.2.4 */
412 /* Dynamic loading code for Linux running ELF. Somewhat tested on
413 * Linux/x86, untested but hopefully should work on Linux/Alpha.
414 * This code was derived from the Solaris/ELF support. Thanks to
415 * whatever kind soul wrote that. - Patrick Bridges */
417 /* This doesn't necessarily work in all cases, e.g. with preloaded
418 * dynamic libraries. */
421 # include <sys/exec_elf.h>
422 /* for compatibility with 1.4.x */
440 # pragma weak _DYNAMIC
442 extern ElfW(Dyn) _DYNAMIC[];
444 static struct link_map *
445 GC_FirstDLOpenedLinkMap()
448 static struct link_map *cachedResult = 0;
453 if( cachedResult == 0 ) {
455 for( dp = _DYNAMIC; (tag = dp->d_tag) != 0; dp++ ) {
456 if( tag == DT_DEBUG ) {
458 = ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
459 if( lm != 0 ) cachedResult = lm->l_next; /* might be NIL */
468 void GC_register_dynamic_libraries()
473 # ifdef HAVE_DL_ITERATE_PHDR
474 if (GC_register_dynamic_libraries_dl_iterate_phdr()) {
478 lm = GC_FirstDLOpenedLinkMap();
479 for (lm = GC_FirstDLOpenedLinkMap();
480 lm != (struct link_map *) 0; lm = lm->l_next)
484 unsigned long offset;
488 e = (ElfW(Ehdr) *) lm->l_addr;
489 p = ((ElfW(Phdr) *)(((char *)(e)) + e->e_phoff));
490 offset = ((unsigned long)(lm->l_addr));
491 for( i = 0; i < (int)(e->e_phnum); ((i++),(p++)) ) {
492 switch( p->p_type ) {
495 if( !(p->p_flags & PF_W) ) break;
496 start = ((char *)(p->p_vaddr)) + offset;
497 GC_add_roots_inner(start, start + p->p_memsz, TRUE);
507 #endif /* !USE_PROC_FOR_LIBRARIES */
511 #if defined(IRIX5) || (defined(USE_PROC_FOR_LIBRARIES) && !defined(LINUX))
513 #include <sys/procfs.h>
514 #include <sys/stat.h>
518 #include <signal.h> /* Only for the following test. */
523 extern void * GC_roots_present();
524 /* The type is a lie, since the real type doesn't make sense here, */
525 /* and we only test for NULL. */
528 /* We use /proc to track down all parts of the address space that are */
529 /* mapped by the process, and throw out regions we know we shouldn't */
530 /* worry about. This may also work under other SVR4 variants. */
531 void GC_register_dynamic_libraries()
535 static prmap_t * addr_map = 0;
536 static int current_sz = 0; /* Number of records currently in addr_map */
537 static int needed_sz; /* Required size of addr_map */
542 ptr_t heap_start = (ptr_t)HEAP_START;
543 ptr_t heap_end = heap_start;
547 # endif /* SOLARISDL */
550 sprintf(buf, "/proc/%d", getpid());
551 /* The above generates a lint complaint, since pid_t varies. */
552 /* It's unclear how to improve this. */
553 fd = open(buf, O_RDONLY);
555 ABORT("/proc open failed");
558 if (ioctl(fd, PIOCNMAP, &needed_sz) < 0) {
559 GC_err_printf("fd = %d, errno = %d\n", fd, errno);
560 ABORT("/proc PIOCNMAP ioctl failed");
562 if (needed_sz >= current_sz) {
563 current_sz = needed_sz * 2 + 1;
564 /* Expansion, plus room for 0 record */
565 addr_map = (prmap_t *)GC_scratch_alloc((word)
566 (current_sz * sizeof(prmap_t)));
568 if (ioctl(fd, PIOCMAP, addr_map) < 0) {
569 GC_err_printf("fd = %d, errno = %d, needed_sz = %d, addr_map = 0x%X\n",
570 fd, errno, needed_sz, addr_map);
571 ABORT("/proc PIOCMAP ioctl failed");
573 if (GC_n_heap_sects > 0) {
574 heap_end = GC_heap_sects[GC_n_heap_sects-1].hs_start
575 + GC_heap_sects[GC_n_heap_sects-1].hs_bytes;
576 if (heap_end < GC_scratch_last_end_ptr) heap_end = GC_scratch_last_end_ptr;
578 for (i = 0; i < needed_sz; i++) {
579 flags = addr_map[i].pr_mflags;
580 if ((flags & (MA_BREAK | MA_STACK | MA_PHYS
581 | MA_FETCHOP | MA_NOTCACHED)) != 0) goto irrelevant;
582 if ((flags & (MA_READ | MA_WRITE)) != (MA_READ | MA_WRITE))
584 /* The latter test is empirically useless in very old Irix */
585 /* versions. Other than the */
586 /* main data and stack segments, everything appears to be */
587 /* mapped readable, writable, executable, and shared(!!). */
588 /* This makes no sense to me. - HB */
589 start = (ptr_t)(addr_map[i].pr_vaddr);
590 if (GC_roots_present(start)) goto irrelevant;
591 if (start < heap_end && start >= heap_start)
594 if (GC_is_thread_stack(start)) goto irrelevant;
595 # endif /* MMAP_STACKS */
597 limit = start + addr_map[i].pr_size;
598 /* The following seemed to be necessary for very old versions */
599 /* of Irix, but it has been reported to discard relevant */
600 /* segments under Irix 6.5. */
602 if (addr_map[i].pr_off == 0 && strncmp(start, ELFMAG, 4) == 0) {
603 /* Discard text segments, i.e. 0-offset mappings against */
604 /* executable files which appear to have ELF headers. */
607 # define MAP_IRR_SZ 10
608 static ptr_t map_irr[MAP_IRR_SZ];
609 /* Known irrelevant map entries */
610 static int n_irr = 0;
614 for (i = 0; i < n_irr; i++) {
615 if (map_irr[i] == start) goto irrelevant;
617 arg = (caddr_t)start;
618 obj = ioctl(fd, PIOCOPENM, &arg);
622 if ((buf.st_mode & 0111) != 0) {
623 if (n_irr < MAP_IRR_SZ) {
624 map_irr[n_irr++] = start;
631 GC_add_roots_inner(start, limit, TRUE);
634 /* Dont keep cached descriptor, for now. Some kernels don't like us */
635 /* to keep a /proc file descriptor around during kill -9. */
636 if (close(fd) < 0) ABORT("Couldnt close /proc file");
640 # endif /* USE_PROC || IRIX5 */
642 # if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
644 # define WIN32_LEAN_AND_MEAN
646 # include <windows.h>
649 /* We traverse the entire address space and register all segments */
650 /* that could possibly have been written to. */
652 extern GC_bool GC_is_heap_base (ptr_t p);
654 # ifdef GC_WIN32_THREADS
655 extern void GC_get_next_stack(char *start, char **lo, char **hi);
656 void GC_cond_add_roots(char *base, char * limit)
658 char * curr_base = base;
659 char * next_stack_lo;
660 char * next_stack_hi;
662 if (base == limit) return;
664 GC_get_next_stack(curr_base, &next_stack_lo, &next_stack_hi);
665 if (next_stack_lo >= limit) break;
666 GC_add_roots_inner(curr_base, next_stack_lo, TRUE);
667 curr_base = next_stack_hi;
669 if (curr_base < limit) GC_add_roots_inner(curr_base, limit, TRUE);
672 void GC_cond_add_roots(char *base, char * limit)
676 = (char *) ((word)(&dummy) & ~(GC_sysinfo.dwAllocationGranularity-1));
677 if (base == limit) return;
678 if (limit > stack_top && base < GC_stackbottom) {
679 /* Part of the stack; ignore it. */
682 GC_add_roots_inner(base, limit, TRUE);
687 /* Do we need to separately register the main static data segment? */
688 GC_bool GC_register_main_static_data()
693 extern GC_bool GC_no_win32_dlls;
695 GC_bool GC_register_main_static_data()
697 return GC_no_win32_dlls;
701 # define HAVE_REGISTER_MAIN_STATIC_DATA
703 # ifdef DEBUG_VIRTUALQUERY
704 void GC_dump_meminfo(MEMORY_BASIC_INFORMATION *buf)
706 GC_printf("BaseAddress = %lx, AllocationBase = %lx, RegionSize = %lx(%lu)\n",
707 buf -> BaseAddress, buf -> AllocationBase, buf -> RegionSize,
709 GC_printf("\tAllocationProtect = %lx, State = %lx, Protect = %lx, "
711 buf -> AllocationProtect, buf -> State, buf -> Protect,
714 # endif /* DEBUG_VIRTUALQUERY */
716 extern GC_bool GC_wnt; /* Is Windows NT derivative. */
717 /* Defined and set in os_dep.c. */
719 void GC_register_dynamic_libraries()
721 MEMORY_BASIC_INFORMATION buf;
726 char * limit, * new_limit;
729 if (GC_no_win32_dlls) return;
731 base = limit = p = GC_sysinfo.lpMinimumApplicationAddress;
732 # if defined(MSWINCE) && !defined(_WIN32_WCE_EMULATION)
733 /* Only the first 32 MB of address space belongs to the current process */
734 while (p < (LPVOID)0x02000000) {
735 result = VirtualQuery(p, &buf, sizeof(buf));
737 /* Page is free; advance to the next possible allocation base */
739 (((DWORD) p + GC_sysinfo.dwAllocationGranularity)
740 & ~(GC_sysinfo.dwAllocationGranularity-1));
743 while (p < GC_sysinfo.lpMaximumApplicationAddress) {
744 result = VirtualQuery(p, &buf, sizeof(buf));
747 if (result != sizeof(buf)) {
748 ABORT("Weird VirtualQuery result");
750 new_limit = (char *)p + buf.RegionSize;
751 protect = buf.Protect;
752 if (buf.State == MEM_COMMIT
753 && (protect == PAGE_EXECUTE_READWRITE
754 || protect == PAGE_READWRITE)
755 && !GC_is_heap_base(buf.AllocationBase)
756 /* There is some evidence that we cannot always
757 * ignore MEM_PRIVATE sections under Windows ME
758 * and predecessors. Hence we now also check for
760 && (buf.Type == MEM_IMAGE ||
761 !GC_wnt && buf.Type == MEM_PRIVATE)) {
762 # ifdef DEBUG_VIRTUALQUERY
763 GC_dump_meminfo(&buf);
765 if ((char *)p != limit) {
766 GC_cond_add_roots(base, limit);
772 if (p > (LPVOID)new_limit /* overflow */) break;
773 p = (LPVOID)new_limit;
775 GC_cond_add_roots(base, limit);
778 #endif /* MSWIN32 || MSWINCE || CYGWIN32 */
780 #if defined(ALPHA) && defined(OSF1)
784 void GC_register_dynamic_libraries()
790 ldr_module_t moduleid = LDR_NULL_MODULE;
791 ldr_module_info_t moduleinfo;
792 size_t moduleinfosize = sizeof(moduleinfo);
793 size_t modulereturnsize;
797 ldr_region_info_t regioninfo;
798 size_t regioninfosize = sizeof(regioninfo);
799 size_t regionreturnsize;
801 /* Obtain id of this process */
802 mypid = ldr_my_process();
804 /* For each module */
807 /* Get the next (first) module */
808 status = ldr_next_module(mypid, &moduleid);
810 /* Any more modules? */
811 if (moduleid == LDR_NULL_MODULE)
812 break; /* No more modules */
814 /* Check status AFTER checking moduleid because */
815 /* of a bug in the non-shared ldr_next_module stub */
817 GC_printf("dynamic_load: status = %d\n", status);
819 extern char *sys_errlist[];
822 if (errno <= sys_nerr) {
823 GC_printf("dynamic_load: %s\n", sys_errlist[errno]);
825 GC_printf("dynamic_load: %d\n", errno);
828 ABORT("ldr_next_module failed");
831 /* Get the module information */
832 status = ldr_inq_module(mypid, moduleid, &moduleinfo,
833 moduleinfosize, &modulereturnsize);
835 ABORT("ldr_inq_module failed");
837 /* is module for the main program (i.e. nonshared portion)? */
838 if (moduleinfo.lmi_flags & LDR_MAIN)
839 continue; /* skip the main module */
842 GC_printf("---Module---\n");
843 GC_printf("Module ID = %16ld\n", moduleinfo.lmi_modid);
844 GC_printf("Count of regions = %16d\n", moduleinfo.lmi_nregion);
845 GC_printf("flags for module = %16lx\n", moduleinfo.lmi_flags);
846 GC_printf("pathname of module = \"%s\"\n", moduleinfo.lmi_name);
849 /* For each region in this module */
850 for (region = 0; region < moduleinfo.lmi_nregion; region++) {
852 /* Get the region information */
853 status = ldr_inq_region(mypid, moduleid, region, ®ioninfo,
854 regioninfosize, ®ionreturnsize);
856 ABORT("ldr_inq_region failed");
858 /* only process writable (data) regions */
859 if (! (regioninfo.lri_prot & LDR_W))
863 GC_printf("--- Region ---\n");
864 GC_printf("Region number = %16ld\n",
865 regioninfo.lri_region_no);
866 GC_printf("Protection flags = %016x\n", regioninfo.lri_prot);
867 GC_printf("Virtual address = %16p\n", regioninfo.lri_vaddr);
868 GC_printf("Mapped address = %16p\n", regioninfo.lri_mapaddr);
869 GC_printf("Region size = %16ld\n", regioninfo.lri_size);
870 GC_printf("Region name = \"%s\"\n", regioninfo.lri_name);
873 /* register region as a garbage collection root */
875 (char *)regioninfo.lri_mapaddr,
876 (char *)regioninfo.lri_mapaddr + regioninfo.lri_size,
889 extern char *sys_errlist[];
892 void GC_register_dynamic_libraries()
895 int index = 1; /* Ordinal position in shared library search list */
896 struct shl_descriptor *shl_desc; /* Shared library info, see dl.h */
898 /* For each dynamic library loaded */
901 /* Get info about next shared library */
902 status = shl_get(index, &shl_desc);
904 /* Check if this is the end of the list or if some error occured */
906 # ifdef GC_HPUX_THREADS
907 /* I've seen errno values of 0. The man page is not clear */
908 /* as to whether errno should get set on a -1 return. */
911 if (errno == EINVAL) {
912 break; /* Moved past end of shared library list --> finished */
914 if (errno <= sys_nerr) {
915 GC_printf("dynamic_load: %s\n", sys_errlist[errno]);
917 GC_printf("dynamic_load: %d\n", errno);
919 ABORT("shl_get failed");
925 GC_printf("---Shared library---\n");
926 GC_printf("\tfilename = \"%s\"\n", shl_desc->filename);
927 GC_printf("\tindex = %d\n", index);
928 GC_printf("\thandle = %08x\n",
929 (unsigned long) shl_desc->handle);
930 GC_printf("\ttext seg. start = %08x\n", shl_desc->tstart);
931 GC_printf("\ttext seg. end = %08x\n", shl_desc->tend);
932 GC_printf("\tdata seg. start = %08x\n", shl_desc->dstart);
933 GC_printf("\tdata seg. end = %08x\n", shl_desc->dend);
934 GC_printf("\tref. count = %lu\n", shl_desc->ref_count);
937 /* register shared library's data segment as a garbage collection root */
938 GC_add_roots_inner((char *) shl_desc->dstart,
939 (char *) shl_desc->dend, TRUE);
949 #include <sys/errno.h>
950 void GC_register_dynamic_libraries()
957 ldibuf = alloca(ldibuflen = 8192);
959 while ( (len = loadquery(L_GETINFO,ldibuf,ldibuflen)) < 0) {
960 if (errno != ENOMEM) {
961 ABORT("loadquery failed");
963 ldibuf = alloca(ldibuflen *= 2);
966 ldi = (struct ld_info *)ldibuf;
968 len = ldi->ldinfo_next;
971 (ptr_t)(unsigned long)ldi->ldinfo_dataorg
972 + ldi->ldinfo_datasize,
974 ldi = len ? (struct ld_info *)((char *)ldi + len) : 0;
981 /* __private_extern__ hack required for pre-3.4 gcc versions. */
982 #ifndef __private_extern__
983 # define __private_extern__ extern
984 # include <mach-o/dyld.h>
985 # undef __private_extern__
987 # include <mach-o/dyld.h>
989 #include <mach-o/getsect.h>
991 /*#define DARWIN_DEBUG*/
993 const static struct {
996 } GC_dyld_sections[] = {
997 { SEG_DATA, SECT_DATA },
998 { SEG_DATA, SECT_BSS },
999 { SEG_DATA, SECT_COMMON }
1003 static const char *GC_dyld_name_for_hdr(const struct GC_MACH_HEADER *hdr) {
1005 c = _dyld_image_count();
1006 for(i=0;i<c;i++) if(_dyld_get_image_header(i) == hdr)
1007 return _dyld_get_image_name(i);
1012 /* This should never be called by a thread holding the lock */
1013 static void GC_dyld_image_add(const struct GC_MACH_HEADER *hdr, intptr_t slide)
1015 unsigned long start,end,i;
1016 const struct GC_MACH_SECTION *sec;
1017 if (GC_no_dls) return;
1018 for(i=0;i<sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]);i++) {
1019 # if defined (__LP64__)
1020 sec = getsectbynamefromheader_64(
1022 sec = getsectbynamefromheader(
1024 hdr, GC_dyld_sections[i].seg,
1025 GC_dyld_sections[i].sect);
1026 if(sec == NULL || sec->size == 0) continue;
1027 start = slide + sec->addr;
1028 end = start + sec->size;
1029 # ifdef DARWIN_DEBUG
1030 GC_printf("Adding section at %p-%p (%lu bytes) from image %s\n",
1031 start,end,sec->size,GC_dyld_name_for_hdr(hdr));
1033 GC_add_roots((char*)start,(char*)end);
1035 # ifdef DARWIN_DEBUG
1036 GC_print_static_roots();
1040 /* This should never be called by a thread holding the lock */
1041 static void GC_dyld_image_remove(const struct GC_MACH_HEADER *hdr,
1044 unsigned long start,end,i;
1045 const struct GC_MACH_SECTION *sec;
1046 for(i=0;i<sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]);i++) {
1047 # if defined (__LP64__)
1048 sec = getsectbynamefromheader_64(
1050 sec = getsectbynamefromheader(
1052 hdr, GC_dyld_sections[i].seg,
1053 GC_dyld_sections[i].sect);
1054 if(sec == NULL || sec->size == 0) continue;
1055 start = slide + sec->addr;
1056 end = start + sec->size;
1057 # ifdef DARWIN_DEBUG
1058 GC_printf("Removing section at %p-%p (%lu bytes) from image %s\n",
1059 start,end,sec->size,GC_dyld_name_for_hdr(hdr));
1061 GC_remove_roots((char*)start,(char*)end);
1063 # ifdef DARWIN_DEBUG
1064 GC_print_static_roots();
1068 void GC_register_dynamic_libraries() {
1069 /* Currently does nothing. The callbacks are setup by GC_init_dyld()
1070 The dyld library takes it from there. */
1073 /* The _dyld_* functions have an internal lock so no _dyld functions
1074 can be called while the world is stopped without the risk of a deadlock.
1075 Because of this we MUST setup callbacks BEFORE we ever stop the world.
1076 This should be called BEFORE any thread in created and WITHOUT the
1077 allocation lock held. */
1079 void GC_init_dyld() {
1080 static GC_bool initialized = FALSE;
1081 char *bind_fully_env = NULL;
1083 if(initialized) return;
1085 # ifdef DARWIN_DEBUG
1086 GC_printf("Registering dyld callbacks...\n");
1089 /* Apple's Documentation:
1090 When you call _dyld_register_func_for_add_image, the dynamic linker runtime
1091 calls the specified callback (func) once for each of the images that is
1092 currently loaded into the program. When a new image is added to the program,
1093 your callback is called again with the mach_header for the new image, and the
1094 virtual memory slide amount of the new image.
1096 This WILL properly register already linked libraries and libraries
1097 linked in the future
1100 _dyld_register_func_for_add_image(GC_dyld_image_add);
1101 _dyld_register_func_for_remove_image(GC_dyld_image_remove);
1103 /* Set this early to avoid reentrancy issues. */
1106 bind_fully_env = getenv("DYLD_BIND_AT_LAUNCH");
1108 if (bind_fully_env == NULL) {
1109 # ifdef DARWIN_DEBUG
1110 GC_printf("Forcing full bind of GC code...\n");
1113 if(!_dyld_bind_fully_image_containing_address((unsigned long*)GC_malloc))
1114 GC_abort("_dyld_bind_fully_image_containing_address failed");
1119 #define HAVE_REGISTER_MAIN_STATIC_DATA
1120 GC_bool GC_register_main_static_data()
1122 /* Already done through dyld callbacks */
1128 #else /* !DYNAMIC_LOADING */
1132 # include "il/PCR_IL.h"
1133 # include "th/PCR_ThCtl.h"
1134 # include "mm/PCR_MM.h"
1136 void GC_register_dynamic_libraries()
1138 /* Add new static data areas of dynamically loaded modules. */
1140 PCR_IL_LoadedFile * p = PCR_IL_GetLastLoadedFile();
1141 PCR_IL_LoadedSegment * q;
1143 /* Skip uncommited files */
1144 while (p != NIL && !(p -> lf_commitPoint)) {
1145 /* The loading of this file has not yet been committed */
1146 /* Hence its description could be inconsistent. */
1147 /* Furthermore, it hasn't yet been run. Hence its data */
1148 /* segments can't possibly reference heap allocated */
1152 for (; p != NIL; p = p -> lf_prev) {
1153 for (q = p -> lf_ls; q != NIL; q = q -> ls_next) {
1154 if ((q -> ls_flags & PCR_IL_SegFlags_Traced_MASK)
1155 == PCR_IL_SegFlags_Traced_on) {
1157 ((char *)(q -> ls_addr),
1158 (char *)(q -> ls_addr) + q -> ls_bytes,
1169 void GC_register_dynamic_libraries(){}
1171 int GC_no_dynamic_loading;
1175 #endif /* !DYNAMIC_LOADING */
1177 #ifndef HAVE_REGISTER_MAIN_STATIC_DATA
1179 /* Do we need to separately register the main static data segment? */
1180 GC_bool GC_register_main_static_data()
1185 /* Register a routine to filter dynamic library registration. */
1187 GC_register_has_static_roots_callback
1188 (int (*callback)(const char *, void *, size_t)) {
1189 GC_has_static_roots = callback;
1192 #endif /* HAVE_REGISTER_MAIN_STATIC_DATA */